From d002386bc220e1d5ac26283b761ad476ed805e24 Mon Sep 17 00:00:00 2001 From: OpenClaw Local Date: Wed, 11 Mar 2026 12:23:57 +0100 Subject: [PATCH] Initial public-ready standalone repository --- .env.example | 17 + .gitignore | 28 + LICENSE | 22 + README.md | 564 ++ docs/ARCHITECTURE.md | 287 + docs/OPS_CONTROL_PLAN.md | 101 + docs/PARITY-MATRIX-v3.md | 25 + docs/PROGRESS.md | 4080 ++++++++ docs/PUBLISHING.md | 54 + docs/RUNBOOK.md | 442 + docs/assets/overview-en.png | Bin 0 -> 686001 bytes docs/assets/usage-en.png | Bin 0 -> 630093 bytes docs/mission-control-runbook-v2.md | 29 + docs/mission-control-template-v2.md | 48 + ecosystem.config.cjs | 30 + package-lock.json | 590 ++ package.json | 44 + scripts/dod-check.ts | 651 ++ scripts/evidence-gate.ts | 78 + scripts/evidence-reporter.ts | 128 + scripts/export-staff-avatars.ts | 403 + scripts/goal-gate.ts | 38 + scripts/health-snapshot.ts | 56 + scripts/mc_dod_evaluator.py | 64 + scripts/mc_rollback_plan.py | 35 + scripts/periodic-snapshot.ts | 76 + scripts/release-audit.sh | 69 + scripts/resident-supervisor.ts | 306 + scripts/resident-worker.ts | 322 + scripts/run-lock.ts | 143 + scripts/run_verifier.sh | 30 + scripts/stall-auto-heal.ts | 109 + scripts/ui-smoke.sh | 42 + scripts/validate-budget-compute.ts | 108 + scripts/validate-task-store.ts | 106 + scripts/watchdog-orchestrator.ts | 219 + src/adapters/openclaw-readonly.ts | 88 + src/clients/factory.ts | 6 + src/clients/openclaw-live-client.ts | 620 ++ src/clients/tool-client.ts | 80 + src/config.ts | 37 + src/contracts/openclaw-tools.ts | 101 + src/index.ts | 250 + src/mappers/openclaw-mappers.ts | 314 + src/mappers/session-status-parser.ts | 37 + src/types.ts | 354 + src/ui/server.ts | 13194 +++++++++++++++++++++++++ test/agent-roster.test.ts | 79 + test/commander-ordering.test.ts | 163 + test/doc-hub.test.ts | 107 + test/export-staff-avatars.test.ts | 76 + test/office-roster.test.ts | 593 ++ test/office-session-presence.test.ts | 221 + test/openclaw-mappers.test.ts | 24 + test/oss-readiness.test.ts | 68 + test/p1-control-scripts.test.ts | 240 + test/phase11-replay-index.test.ts | 35 + test/phase13-replay-acks.test.ts | 256 + test/phase9-routes-commands.test.ts | 314 + test/session-execution-chain.test.ts | 261 + test/task-heartbeat.test.ts | 200 + test/triplet-control.test.ts | 328 + test/ui-language-preferences.test.ts | 46 + test/ui-render-smoke.test.ts | 703 ++ test/usage-cost.test.ts | 532 + tsconfig.json | 12 + 66 files changed, 28683 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 docs/ARCHITECTURE.md create mode 100644 docs/OPS_CONTROL_PLAN.md create mode 100644 docs/PARITY-MATRIX-v3.md create mode 100644 docs/PROGRESS.md create mode 100644 docs/PUBLISHING.md create mode 100644 docs/RUNBOOK.md create mode 100644 docs/assets/overview-en.png create mode 100644 docs/assets/usage-en.png create mode 100644 docs/mission-control-runbook-v2.md create mode 100644 docs/mission-control-template-v2.md create mode 100644 ecosystem.config.cjs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scripts/dod-check.ts create mode 100644 scripts/evidence-gate.ts create mode 100644 scripts/evidence-reporter.ts create mode 100644 scripts/export-staff-avatars.ts create mode 100644 scripts/goal-gate.ts create mode 100644 scripts/health-snapshot.ts create mode 100755 scripts/mc_dod_evaluator.py create mode 100755 scripts/mc_rollback_plan.py create mode 100644 scripts/periodic-snapshot.ts create mode 100755 scripts/release-audit.sh create mode 100644 scripts/resident-supervisor.ts create mode 100644 scripts/resident-worker.ts create mode 100644 scripts/run-lock.ts create mode 100755 scripts/run_verifier.sh create mode 100644 scripts/stall-auto-heal.ts create mode 100644 scripts/ui-smoke.sh create mode 100644 scripts/validate-budget-compute.ts create mode 100644 scripts/validate-task-store.ts create mode 100644 scripts/watchdog-orchestrator.ts create mode 100644 src/adapters/openclaw-readonly.ts create mode 100644 src/clients/factory.ts create mode 100644 src/clients/openclaw-live-client.ts create mode 100644 src/clients/tool-client.ts create mode 100644 src/config.ts create mode 100644 src/contracts/openclaw-tools.ts create mode 100644 src/index.ts create mode 100644 src/mappers/openclaw-mappers.ts create mode 100644 src/mappers/session-status-parser.ts create mode 100644 src/types.ts create mode 100644 src/ui/server.ts create mode 100644 test/agent-roster.test.ts create mode 100644 test/commander-ordering.test.ts create mode 100644 test/doc-hub.test.ts create mode 100644 test/export-staff-avatars.test.ts create mode 100644 test/office-roster.test.ts create mode 100644 test/office-session-presence.test.ts create mode 100644 test/openclaw-mappers.test.ts create mode 100644 test/oss-readiness.test.ts create mode 100644 test/p1-control-scripts.test.ts create mode 100644 test/phase11-replay-index.test.ts create mode 100644 test/phase13-replay-acks.test.ts create mode 100644 test/phase9-routes-commands.test.ts create mode 100644 test/session-execution-chain.test.ts create mode 100644 test/task-heartbeat.test.ts create mode 100644 test/triplet-control.test.ts create mode 100644 test/ui-language-preferences.test.ts create mode 100644 test/ui-render-smoke.test.ts create mode 100644 test/usage-cost.test.ts create mode 100644 tsconfig.json diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..fb63936 --- /dev/null +++ b/.env.example @@ -0,0 +1,17 @@ +# Mission Control MVP flags +# Keep readonly true until explicit live-mode validation is complete. +GATEWAY_URL=ws://127.0.0.1:18789 +# Optional path overrides when your OpenClaw/Codex data is not in the default home locations. +# OPENCLAW_HOME=/path/to/.openclaw +# CODEX_HOME=/path/to/.codex +# OPENCLAW_SUBSCRIPTION_SNAPSHOT_PATH=/path/to/subscription.json +READONLY_MODE=true +APPROVAL_ACTIONS_ENABLED=false +APPROVAL_ACTIONS_DRY_RUN=true +IMPORT_MUTATION_ENABLED=false +IMPORT_MUTATION_DRY_RUN=false +LOCAL_TOKEN_AUTH_REQUIRED=true +# LOCAL_API_TOKEN= +MONITOR_CONTINUOUS=false +UI_MODE=false +UI_PORT=4310 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2518ef7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +node_modules/ +dist/ +runtime/ +coverage/ +*.log +*.tsbuildinfo +__pycache__/ +*.pyc +npm-debug.log* +yarn-debug.log* +pnpm-debug.log* +.DS_Store +.env +.env.local +.env.*.local +plans/ +workflows/ +mission.config.json +mission.spec.json +mission.worklist.json +docs/mission.runbook.md +docs/mission.sop.md +init.sh +1440m +180m +720m +alexfinn-gap-checklist.md +i18n-missing-list.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5cc8a03 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2026 OpenClaw contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..b9fb6f5 --- /dev/null +++ b/README.md @@ -0,0 +1,564 @@ +# OpenClaw Mission Control MVP + +Safety-first local Mission Control for OpenClaw. + +Language / 语言: [English](#english-installation-and-onboarding) | [中文](#中文安装与上手) + +## Why this exists +- One local place to see whether OpenClaw is healthy, busy, blocked, or drifting. +- Built for non-technical operators who need observability and certainty, not raw backend payloads. +- Safe first-run defaults: + - read-only by default + - local token auth by default + - mutation routes disabled by default + +## What you get +- `Overview`: health, current state, decisions waiting, and operator-facing summaries +- `Usage`: usage, spend, subscription windows, and connector status +- `Staff`: who is really working now versus only queued +- `Tasks`: current work, approvals, execution chains, and runtime evidence +- `Documents` and `Memory`: source-backed workbenches scoped to active OpenClaw agents + +## Who it is for +- OpenClaw users who want one local control center for observability, usage, tasks, approvals, replay, documents, and memory +- teams running OpenClaw on one machine or a reachable local environment +- maintainers who want a public-ready, safety-first OpenClaw dashboard instead of a generic agent platform + +## Screenshots +Example UI from a local OpenClaw environment: + +OpenClaw Mission Control overview screenshot + +OpenClaw Mission Control usage screenshot + +## 5-minute start +```bash +npm install +cp .env.example .env +npm run build +npm test +npm run smoke:ui +UI_MODE=true npm run dev +``` + +Then open: +- `http://127.0.0.1:4310/?section=overview&lang=en` +- `http://127.0.0.1:4310/?section=overview&lang=zh` + +For / 适用对象: +- Existing OpenClaw users who want a local control center for observability, usage, staff activity, tasks, approvals, replay, and documents. +- Teams running OpenClaw on the same machine or a reachable local environment. +- Not a generic dashboard for non-OpenClaw agent stacks. + +## Core constraints +- Only touches files in `control-center/`. +- `READONLY_MODE=true` by default. +- `LOCAL_TOKEN_AUTH_REQUIRED=true` by default. +- `IMPORT_MUTATION_ENABLED=false` by default. +- `IMPORT_MUTATION_DRY_RUN=false` by default. +- Import/export and all state-changing endpoints require a local token when auth is enabled. +- Approval actions are hard-gated (`APPROVAL_ACTIONS_ENABLED=false` default). +- Approval actions are dry-run by default (`APPROVAL_ACTIONS_DRY_RUN=true`). +- No mutation of `~/.openclaw/openclaw.json`. + +## Quick start +1. `npm install` +2. `cp .env.example .env` +3. Keep safe defaults for the first run; only change `GATEWAY_URL` or path overrides if your OpenClaw setup is non-standard. +4. `npm run build` +5. `npm test` +6. `npm run smoke:ui` +7. `UI_MODE=true npm run dev` + +## English installation and onboarding + +### 1. Before you start +You should already have: +- a working OpenClaw installation +- a reachable OpenClaw Gateway +- shell access with `node` and `npm` +- read access to your OpenClaw home directory + +For the richest dashboard data, it also helps if this machine has: +- `~/.openclaw` +- `~/.codex` +- a readable OpenClaw subscription snapshot, if your setup stores one outside the default locations + +### 2. Install the project +```bash +git clone +cd control-center +npm install +cp .env.example .env +``` + +### 3. Configure `.env` +For a safe first run, keep the mutation guards in place. + +Use this baseline: +```dotenv +GATEWAY_URL=ws://127.0.0.1:18789 +READONLY_MODE=true +APPROVAL_ACTIONS_ENABLED=false +APPROVAL_ACTIONS_DRY_RUN=true +IMPORT_MUTATION_ENABLED=false +IMPORT_MUTATION_DRY_RUN=false +LOCAL_TOKEN_AUTH_REQUIRED=true +UI_MODE=false +UI_PORT=4310 + +# Optional only when your paths differ from the defaults: +# OPENCLAW_HOME=/path/to/.openclaw +# CODEX_HOME=/path/to/.codex +# OPENCLAW_SUBSCRIPTION_SNAPSHOT_PATH=/path/to/subscription.json +``` + +Change only these values if your environment needs it: +- `GATEWAY_URL`: when your OpenClaw Gateway is not on the default local socket +- `OPENCLAW_HOME`: when OpenClaw is not stored in `~/.openclaw` +- `CODEX_HOME`: when Codex data is not stored in `~/.codex` +- `OPENCLAW_SUBSCRIPTION_SNAPSHOT_PATH`: when your billing/subscription snapshot lives somewhere custom +- `UI_PORT`: when `4310` is already in use + +### 4. Optional: ask your own OpenClaw to prepare the setup +If you want OpenClaw to help configure the environment, give it this prompt: + +```text +You are helping me connect OpenClaw Mission Control to this machine's OpenClaw installation. + +Work only inside the control-center repository. +Do not modify application source code unless I explicitly ask. +Goal: prepare a safe first-run setup. + +Please do the following: +1. Check whether the OpenClaw Gateway is reachable and tell me the correct gateway URL. +2. Confirm the correct OpenClaw home path and Codex home path on this machine. +3. Compare those paths with .env.example and create or update .env. +4. Keep these values safe for first run: + - READONLY_MODE=true + - LOCAL_TOKEN_AUTH_REQUIRED=true + - APPROVAL_ACTIONS_ENABLED=false + - IMPORT_MUTATION_ENABLED=false +5. Do not enable live import or approval mutations. +6. Do not change OpenClaw's own config. +7. At the end, print: + - the final env values you changed + - the exact commands I should run next + - the first dashboard pages I should open to confirm everything works +8. If any required path, process, or file is missing, stop and tell me exactly what is missing instead of guessing. +``` + +### 5. Verify the install +Run: +```bash +npm run build +npm test +npm run smoke:ui +``` + +Expected result: +- build passes +- tests pass +- UI smoke reports a local URL such as `http://127.0.0.1:` + +### 6. Start the UI +```bash +UI_MODE=true npm run dev +``` + +Then open: +- English UI: `http://127.0.0.1:4310/?section=overview&lang=en` +- Chinese UI: `http://127.0.0.1:4310/?section=overview&lang=zh` + +If you changed `UI_PORT`, replace `4310` with your chosen port. + +### 7. First-use checklist +On your first launch, check these pages in order: +1. `Overview`: the app opens and shows current system state. +2. `Usage`: usage and subscription panels either show real numbers or a clear missing-connector state. +3. `Staff`: live work status matches real active sessions. +4. `Tasks`: current work, approvals, and execution-chain cards load without raw payload noise. +5. `Documents` and `Memory`: the visible agent tabs match your active agents from `openclaw.json`. + +### 8. If something looks wrong +- Empty live activity usually means `GATEWAY_URL` is wrong or the OpenClaw Gateway is not running. +- Missing `Documents / Memory` agents usually means `OPENCLAW_HOME` points to the wrong OpenClaw root or `openclaw.json` is missing. +- Missing usage/subscription data usually means `CODEX_HOME` or `OPENCLAW_SUBSCRIPTION_SNAPSHOT_PATH` needs to be set. +- If you only want a safe read-only dashboard, do not change the mutation defaults. + +## 中文安装与上手 + +### 1. 开始前准备 +你最好已经有: +- 一个正常可用的 OpenClaw 安装 +- 一个可连通的 OpenClaw Gateway +- 当前机器上的 `node` 和 `npm` +- 对 OpenClaw 主目录的读取权限 + +如果你希望 `用量 / 订阅` 这类信息更完整,当前机器最好还能读到: +- `~/.openclaw` +- `~/.codex` +- 你的 OpenClaw 订阅快照文件,尤其是它不在默认位置时 + +### 2. 安装项目 +```bash +git clone <你的仓库地址> +cd control-center +npm install +cp .env.example .env +``` + +### 3. 配置 `.env` +第一次接入建议保持安全默认值,不要急着开写操作。 + +可以先用这份基线配置: +```dotenv +GATEWAY_URL=ws://127.0.0.1:18789 +READONLY_MODE=true +APPROVAL_ACTIONS_ENABLED=false +APPROVAL_ACTIONS_DRY_RUN=true +IMPORT_MUTATION_ENABLED=false +IMPORT_MUTATION_DRY_RUN=false +LOCAL_TOKEN_AUTH_REQUIRED=true +UI_MODE=false +UI_PORT=4310 + +# 只有在你的路径不是默认值时才需要设置: +# OPENCLAW_HOME=/path/to/.openclaw +# CODEX_HOME=/path/to/.codex +# OPENCLAW_SUBSCRIPTION_SNAPSHOT_PATH=/path/to/subscription.json +``` + +只有这些情况才需要改: +- `GATEWAY_URL`:你的 OpenClaw Gateway 不在默认本地地址 +- `OPENCLAW_HOME`:你的 OpenClaw 目录不在 `~/.openclaw` +- `CODEX_HOME`:你的 Codex 数据不在 `~/.codex` +- `OPENCLAW_SUBSCRIPTION_SNAPSHOT_PATH`:你的订阅或账单快照文件放在自定义位置 +- `UI_PORT`:`4310` 端口已被占用 + +### 4. 可选:让你自己的 OpenClaw 帮你配置 +如果你想让自己的 OpenClaw 帮你把环境接好,可以直接给它这段提示词: + +```text +你现在要帮我把 OpenClaw Mission Control 接到这台机器自己的 OpenClaw 环境上。 + +只允许在 control-center 仓库里工作。 +除非我明确要求,否则不要修改应用源码。 +目标是完成一次安全的首次接入配置。 + +请按下面步骤执行: +1. 检查 OpenClaw Gateway 是否可达,并告诉我正确的 gateway URL。 +2. 确认这台机器上正确的 OpenClaw 主目录和 Codex 主目录。 +3. 对照 .env.example,创建或更新 .env。 +4. 第一次接入时必须保持这些值: + - READONLY_MODE=true + - LOCAL_TOKEN_AUTH_REQUIRED=true + - APPROVAL_ACTIONS_ENABLED=false + - IMPORT_MUTATION_ENABLED=false +5. 不要开启 live import,也不要开启 approval mutation。 +6. 不要改 OpenClaw 自己的配置文件。 +7. 完成后输出: + - 你实际修改了哪些 env 值 + - 我下一步应该执行的准确命令 + - 我应该先打开哪些页面来确认接入成功 +8. 如果缺少必要的路径、进程或文件,不要猜,直接明确告诉我缺什么。 +``` + +### 5. 验证安装 +执行: +```bash +npm run build +npm test +npm run smoke:ui +``` + +预期结果: +- build 通过 +- test 通过 +- UI smoke 输出一个本地地址,比如 `http://127.0.0.1:` + +### 6. 启动界面 +```bash +UI_MODE=true npm run dev +``` + +然后打开: +- 中文界面:`http://127.0.0.1:4310/?section=overview&lang=zh` +- 英文界面:`http://127.0.0.1:4310/?section=overview&lang=en` + +如果你改了 `UI_PORT`,把上面的 `4310` 换成你自己的端口。 + +### 7. 首次上手检查顺序 +第一次打开后,建议按这个顺序检查: +1. `总览`:页面能正常打开,并且能看到当前系统状态。 +2. `用量`:能看到真实数字,或者至少能看到明确的“数据源未连接”状态。 +3. `员工`:实时工作状态和真实 active session 大致一致。 +4. `任务`:当前工作、待审批、执行链卡片都能正常加载,而且不会吐原始 payload。 +5. `文档` 和 `记忆`:看到的 agent 标签应该和你的 `openclaw.json` 活跃 agent 一致。 + +### 8. 如果看起来不对 +- 实时活动全空,通常是 `GATEWAY_URL` 错了,或者 OpenClaw Gateway 没启动。 +- `文档 / 记忆` 的 agent 范围不对,通常是 `OPENCLAW_HOME` 指错了,或者 `openclaw.json` 不可读。 +- `用量 / 订阅` 没数据,通常是 `CODEX_HOME` 或 `OPENCLAW_SUBSCRIPTION_SNAPSHOT_PATH` 没配对。 +- 如果你只是想先安全观察,不要改动默认的只读和 mutation 开关。 + +## Local commands +- `npm run build` +- `npm run dev` +- `npm run dev:continuous` +- `npm run dev:ui` +- `npm run smoke:ui` +- `npm run command:backup-export` +- `npm run command:import-validate -- runtime/exports/.json` +- `npm run command:acks-prune` +- `npm test` +- `npm run validate` + +For protected command modes (`command:backup-export`, `command:import-validate`, `command:acks-prune`), set `LOCAL_API_TOKEN=` unless `LOCAL_TOKEN_AUTH_REQUIRED=false`. + +## Repository hygiene (Phase 113, Open-source release readiness) +- Repo now ships with `.gitignore`, `LICENSE`, and publishable package metadata. +- Gateway connectivity is configurable via `GATEWAY_URL` instead of being hard-wired to one local socket. +- PM2, mission harness, workflow, and verifier examples now use repo-relative paths and environment-injected secrets only. +- Public docs now refer to generic `~/.openclaw/...` locations instead of machine-specific home directories. +- Run `npm run release:audit` before every public push. +- See [`docs/PUBLISHING.md`](docs/PUBLISHING.md) for the recommended standalone-repo release flow. + +## Local HTTP endpoints +- `GET /snapshot`: raw snapshot JSON +- `GET /projects`: list projects with optional query filters `status`, `owner` +- `GET /api/projects`: same as `/projects` for compatibility +- `POST /api/projects`: create project (`projectId`, `title`, optional `status`, `owner`) +- `PATCH /api/projects/:projectId`: update project title/status/owner +- `GET /tasks`: flattened task list with optional query filters `status`, `owner`, `project` +- `GET /api/tasks`: same as `/tasks` for compatibility +- `POST /api/tasks`: create task with schema validation +- `PATCH /api/tasks/:taskId/status`: update task status with schema validation +- `GET /sessions`: paginated session visibility list with optional filters `state`, `agentId`, `q`, and pagination params `page`, `pageSize`, `historyLimit` +- `GET /sessions/:id`: per-session JSON detail with latest history entries (`historyLimit` query supported) +- `GET /api/sessions/:id`: explicit API alias for per-session JSON detail +- `GET /session/:id`: localized session drill-down UI page (`lang=en|zh`) with latest messages, execution-chain evidence, and safe truncation +- `GET /api/sessions`: compatibility endpoint for `/sessions` +- `GET /api/commander/exceptions`: exceptions-only summary (blocked/errors/pending approvals/over-budget/tasks-due) +- `GET /exceptions`: routed exceptions feed with levels (`info`, `warn`, `action-required`), sorted by severity then newest event +- `GET /done-checklist`: final integration checklist + readiness scoring (`observability/governance/collaboration/security`) +- `GET /api/done-checklist`: API alias for done checklist +- `GET /api/action-queue`: notification center queue derived from exceptions feed + ack state + relevant session/task/project links +- `GET /api/action-queue/acks/prune-preview`: token-gated dry-run preview of stale ack prune counts (`before/removed/after`, no state mutation) +- `POST /api/action-queue/:itemId/ack`: acknowledge an action-required queue item (persisted), optional `ttlMinutes` or `snoozeUntil` to auto-expire ack state +- `GET /graph`: project-task-session linkage graph JSON (for future Gameboy view) +- `GET /view/pixel-state.json`: pixel-ready adapter state (`rooms`, `entities`, `links`) for future Gameboy canvas +- `GET /usage-cost`: product route alias that redirects to `/?section=usage-cost` +- `GET /api/usage-cost`: usage/billing observability snapshot (period totals, context windows, breakdowns, burn-rate, subscription consumed/remaining/cycle, connector TODOs) +- `GET /export/state.json`: bundled export with sessions/tasks/projects/budgets/exceptions + persisted debug snapshot + backup bundle in `runtime/exports/` (requires local token auth) +- `POST /api/import/dry-run`: dry-run validator for export bundles (`fileName` or inline `bundle`) with zero state mutation (requires local token auth) +- `POST /api/import/live`: optional live import mutation endpoint (high-risk, local-only); requires local token + `IMPORT_MUTATION_ENABLED=true`, blocked in readonly unless `dryRun=true`, and now returns validation errors instead of `500` for bad `fileName` paths +- `GET /notifications/preview`: notification policy preview with quiet-hours + severity routing +- `GET /cron`: cron overview with next run and health summary +- `GET /healthz`: system health payload (build info + snapshot freshness + monitor lag) +- `GET /digest/latest`: rendered HTML page from latest markdown digest file +- `GET /api/ui/preferences`: persisted dashboard UI preferences (`runtime/ui-preferences.json`) +- `PATCH /api/ui/preferences`: update dashboard UI preferences (`compactStatusStrip`, `quickFilter`, `taskFilters`) +- `GET /api/search/tasks`: safe substring search over tasks (`q`, `limit`), with `count` = total matches and `returned` = current response size +- `GET /api/search/projects`: safe substring search over projects (`q`, `limit`), with `count` = total matches and `returned` = current response size +- `GET /api/search/sessions`: safe substring search over sessions (`q`, `limit`), with `count` = total matches, `returned` = current response size, and live-session merge parity with `/sessions` +- `GET /api/search/exceptions`: safe substring search over exception feed (`q`, `limit`), with `count` = total matches and `returned` = current response size +- `GET /api/replay/index`: replay/debug index from timeline + digests + export snapshots + export bundles, optional `from`/`to` ISO time window filters, plus per-source `stats` (`total`, `returned`, `filteredOut`, window-vs-limit breakdown, `latencyMs`, `latencyBucketsMs` with `p50/p95`, `totalSizeBytes`, `returnedSizeBytes`) +- `GET /api/docs`: route + schema summary endpoint +- `GET /docs`: localized docs index page (read-only) with direct return path to the `Documents` section +- `GET /docs/readme|runbook|architecture|progress`: local markdown docs views (read-only, `lang` accepted for index/back-link flow) +- `POST /api/approvals/:approvalId/approve`: approval action service (gate + dry-run + audit) +- `POST /api/approvals/:approvalId/reject`: rejection action service (gate + dry-run + audit) +- `GET /audit`: local audit timeline page (newest-first, severity filter) +- `GET /api/audit`: audit timeline JSON (`severity=all|info|warn|action-required|error`) + +## Dashboard highlights (Phase 14) +- Home page includes inline scoped search UI wired to `/api/search/*`. +- Home page replay/export visibility card now shows returned/filtered counts and latency/size indicators from `/api/replay/index`. +- Guard table shows explicit disabled/enabled badges and linked local docs references. + +## Dashboard highlights (Phase 107, Approvals/replay/tool-activity correctness sweep) +- Approval counts now use the full live approval set: + - sidebar and task-hub decision counts no longer under-report when approval previews are truncated + - approval preview lists stay short but now make it explicit when only the latest subset is shown +- Replay visibility chips now show total available history: + - timeline events + - daily digests + - export snapshots + - backup bundles +- Overview tool activity detail now loads actual session evidence: + - it no longer claims there are no tool-call sessions while the same page shows active tool-call counts +- User-facing parity routes no longer advertise deprecated dashboard sections: + - approvals route points to the task hub decision lane + - replay route points to `/audit` + +## Dashboard highlights (Phase 110, Docs/memory active-agent scope alignment) +- `Documents` and `Memory` now follow active OpenClaw agent config instead of stale workspace folders: + - facets are resolved from `~/.openclaw/openclaw.json` first + - removed agents no longer appear just because an old folder still exists under `workspace/agents/` + - root OpenClaw files are now shown as `Main` instead of `共享` +- Editable file content remains source-of-truth current: + - file lists still read live filesystem metadata (`updatedAt`, size, path) + - opening a file reads the current source file + - saving a file writes directly back to that same source file + +## Dashboard highlights (Phase 111, Execution-chain readability cleanup) +- `Execution chain` cards no longer surface raw JSON payloads as the visible headline or summary. +- Unmapped isolated-run cards now use stable labels such as `Main · Cron 隔离执行`. +- JSON-like payloads are summarized into short readable lines: + - `成功 · 查询 30 · 成功 30` + - `失败 · 错误 locked` + - `成功 · 扫描 120 · 入选 2 · 发送 2` +- Long titles and session keys now wrap/clamp inside the card instead of pushing badges out of place. + +## Dashboard highlights (Phase 112, Staff status freshness semantics) +- Staff `Working / 工作中` now means live execution, not just “still owns unfinished tasks”. +- Agents with backlog but no live session now stay in standby semantics instead of looking falsely active. +- Staff work labels now separate: + - live work: `Working on / 正在处理什么` + - queued next task: `Next up / 下一项` +- Staff/recent-activity cache remains short-lived at about `3s`; live-session polling baseline remains `5s`. + +## Dashboard highlights (Phase 114, Execution-chain card hardening) +- Execution-chain cards no longer allow raw JSON-like payloads to become visible titles. +- Structured payload-shaped titles are converted into short human summaries or stable fallback labels instead. +- Long titles, meta rows, and badge rails are now overflow-safe inside the card grid. + +## Dashboard highlights (Phase 115, Apple-native card elevation tune) +- Page canvas is slightly cooler and quieter so foreground cards stand out more cleanly. +- Core cards now use brighter layered fills, crisper borders, and deeper but still restrained elevation. +- The hierarchy is unchanged; this is a visual polish pass, not a layout rewrite. + +## Dashboard highlights (Phase 116, Config-truthful document and memory scopes) +- `Documents / Memory` no longer revive deleted agents just because stale folders still remain on disk. +- Valid active-agent config remains the only truth source for those facet buttons. +- If config becomes unreadable, the workbench now falls back conservatively to `Main` only instead of showing stale agent folders. + +## Dashboard highlights (Phase 106, Cold-path cache coalescing) +- Correctness stays unified across Overview / Settings / Usage: + - no return to split summary/full quota logic + - repeat navigations keep the same usage/quota truth when the underlying execution state is unchanged +- Heavy evidence scans are now reused instead of recomputed per page: + - runtime usage logs + - Codex subscription/quota telemetry + - digest history + - OpenClaw cron name catalog +- UI startup now primes dashboard caches, and concurrent page opens share the same heavy build work. +- In local smoke: + - back-to-back `Overview` renders dropped to about `0.41s` + - back-to-back `Usage` renders dropped to about `0.41s` + - after one priming hit, concurrent `Overview / Settings / Usage` completed in about `1.13s` + +## Dashboard highlights (Phase 105, Observability correctness alignment) +- Overview / Tasks / Settings / Usage now share one usage/quota truth source: + - the same today-usage number + - the same Codex quota windows + - the same subscription-status judgement +- Active-session counts are aligned across: + - overview KPI + - certainty card + - sidebar / summary strips +- Task certainty no longer depends on only the first recent-session page: + - linked session evidence is loaded for the visible task set + - task detail pages no longer stop at the first 6 linked sessions +- Detail links now keep the current UI language when opening task / cron drill-down pages. + +## Dashboard highlights (Phase 15, UX v2) +- Home dashboard is now organized into six operator tabs with persistent left navigation: + - `Overview` + - `Office Space` + - `Projects/Tasks` + - `Alerts` + - `Replay/Audit` + - `Settings` +- UI moved to a colorful pixel-arcade visual style with dual sidebars (navigation + context rail). +- New `Office Space` view shows who is busy on what, grouped by office zones. +- Agent cards now include automatic animal identities derived from agent name semantics, with deterministic fallback mapping. +- Empty/zero-heavy blocks are softened: + - non-actionable zero states are minimized + - user-facing empty states now say `Not activated yet`. +- Home copy was rewritten from debug-heavy wording to operator-focused language while preserving all existing routes and backend behavior. + +## Dashboard highlights (Phase 22, Usage/Cost parity surfaces) +- Added `Usage & Cost` section in the primary sidebar IA. +- Added Overview card-level usage/cost pulse: + - period totals (`today`, `7d`, `30d`) + - request-count source state + - burn-rate headline +- Added dedicated Usage & Cost dashboard section: + - context window visibility per active session/agent (absolute tokens + % when context catalog is available) + - pace/trend labels + warning thresholds + - usage/cost breakdown by agent, project, model, provider + - budget burn-rate status and alert messaging +- Added graceful unavailable-state behavior: + - explicit `Data source not connected` labels for disconnected metrics (instead of fake zeros) + - connector TODO list surfaced in Settings +- Added usage adapter endpoint: + - `GET /api/usage-cost` + +## Dashboard highlights (Phase 25, Mission Control v3) +- UI visual reset to polished pixel-office style: + - design-token based palette/spacing/radius/shadow system + - layered office background grid + glow depth + - responsive desktop/mobile hierarchy with subtle card/status motion +- Navigation and copy reset for operator clarity: + - `Command Deck`, `Usage & Billing`, `Pixel Office`, `Work Board`, `Decisions`, `Timeline`, `Control Room` + - reduced technical wording on primary surfaces + - advanced links preserved under explicit disclosure +- Mac parity surfaces panel added with status + route entry for: + - conversations, approvals/decision queue, cron, projects/tasks, usage/cost, replay/audit, health/digest, export/import dry-run safety, pixel adapter +- Full roster office model: + - best-effort OpenClaw roster read from `~/.openclaw/openclaw.json` via `src/runtime/agent-roster.ts` + - office floor now renders desk/zone occupancy and includes known agents beyond active sessions +- Subscription usage/remaining best-effort integration: + - adapter support in `src/runtime/usage-cost.ts` for connected/partial/not_connected states + - UI now shows consumed/remaining/limit/cycle/source and explicit connection targets when unavailable + +## Dashboard highlights (Phase 68, Plain-language certainty) +- Added `Information certainty` card to Overview and Settings: + - tells non-technical operators which parts of the picture are trustworthy now + - calls out remaining blind spots in plain language +- Added `Execution certainty` board to Tasks: + - scores whether each in-flight task is backed by real execution evidence + - separates `evidence is strong` from `needs follow-up` and `evidence is weak` +- Task detail pages now act as evidence pages: + - certainty judgement + - linked session evidence and recent activity summaries + +## API validation/error envelope +- API mutating routes require `Content-Type: application/json`. +- Import/export and mutating routes require local token auth by default: + - header: `x-local-token: ` + - or `Authorization: Bearer ` +- Strict API query validation rejects unknown query keys. +- JSON errors use a consistent envelope: + - `{"ok":false,"requestId":"...","error":{"code":"...","status":,"message":"...","issues":[],"requestId":"..."}}` +- JSON responses include `requestId` and all responses include `x-request-id` header for correlation. + +## Live import warning +- `POST /api/import/live` is intentionally disabled by default. +- Do not enable it unless you are doing a controlled local restore test. +- Live mode mutates local runtime stores (`runtime/projects.json`, `runtime/tasks.json`, `runtime/budgets.json`). +- Keep `READONLY_MODE=true` and `IMPORT_MUTATION_ENABLED=false` in normal operation. + +## Runtime files +- `runtime/last-snapshot.json` +- `runtime/timeline.log` +- `runtime/projects.json` +- `runtime/tasks.json` +- `runtime/budgets.json` +- `runtime/notification-policy.json` +- `runtime/model-context-catalog.json` +- `runtime/ui-preferences.json` +- `runtime/acks.json` +- `runtime/approval-actions.log` +- `runtime/operation-audit.log` +- `runtime/digests/YYYY-MM-DD.json` +- `runtime/digests/YYYY-MM-DD.md` +- `runtime/export-snapshots/*.json` +- `runtime/exports/*.json` + +## Docs +- `docs/ARCHITECTURE.md` +- `docs/RUNBOOK.md` +- `docs/PROGRESS.md` diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..9424535 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,287 @@ +# Architecture (Official-First) + +## Core Principle +Use official OpenClaw interfaces first, then add thin adapters only when required. + +## Official Capability Mapping + +1) Gateway (control plane) +- Endpoint: `GATEWAY_URL` (defaults to `ws://127.0.0.1:18789`) +- Role: real-time event/control backbone + +2) Sessions APIs +- `sessions_list`: discover sessions/agents +- `sessions_history`: inspect message history +- `sessions_send`: route instructions +- Local session-visibility module merges `sessions_list` with per-session latest history snippets for operator read APIs. +- Session history normalization distinguishes regular messages and tool events for readonly drill-down rendering. + +3) Runtime status +- `session_status`: usage/time/cost/status snapshots + +4) Scheduling / Ops +- `cron`: list/add/run/runs for scheduled tasks + +5) Governance +- approvals + tool policy boundaries for sensitive actions +- approvals action service is runtime-gated and dry-run by default +- every approval action attempt writes audit entries to `runtime/approval-actions.log` + +6) Visual layer +- Canvas/A2UI for future Gameboy-style rendering + +7) Project/task state +- Local typed project store at `runtime/projects.json` +- Local typed task store at `runtime/tasks.json` +- Tasks are linked to projects via `projectId` and validated on create/update flows +- Domain entities include project status/owner/title + task owner/DoD/artifacts/rollback plan/per-scope thresholds +- Local HTTP APIs support project list/create/update and task list/create/update-status with schema validation +- Snapshot includes `projectSummaries` for board views and operational counts + +8) Budget governance +- Scopes: `agent`, `project`, `task` +- Inputs: session usage snapshots (`tokensIn`, `tokensOut`, optional `cost`) +- Runtime policy file: `runtime/budgets.json` with validated defaults and optional per-scope overrides +- Output status: `ok`, `warn`, `over` via threshold + warn ratio computation +- Commander exceptions endpoint reports `over-budget` entries only + +9) Alert routing +- Levels: `info`, `warn`, `action-required` +- Routing targets: + - `info` -> `timeline` + - `warn` -> `operator-watch` + - `action-required` -> `action-queue` +- Exceptions feed endpoint: `GET /exceptions` +- Notification center queue endpoint: `GET /api/action-queue` +- Queue items include links to related `/sessions/:id`, `/tasks`, `/projects` targets when context is available. +- Queue acknowledgements persisted at `runtime/acks.json` +- Ack API endpoint: `POST /api/action-queue/:itemId/ack` + - optional acknowledgement expiry via `ttlMinutes` or `snoozeUntil` + +10) Audit timeline +- Aggregates runtime sources into a unified event list: + - `runtime/timeline.log` (monitor diffs) + - `runtime/approval-actions.log` (action audit trail) + - `runtime/operation-audit.log` (import dry-run + backup export actions) + - snapshot health event from `runtime/last-snapshot.json` +- Local page: `GET /audit` +- JSON API: `GET /api/audit` +- Timeline is newest-first with severity filter (`all|info|warn|action-required|error`). + +11) Linkage graph + state export +- `GET /graph` returns normalized graph data (`project/task/session/agent` nodes and linkage edges). +- `GET /export/state.json` returns bundled project/task/budget/exception state for downstream consumers. + +12) Commander digest +- On each monitor run, a daily digest is written to: + - `runtime/digests/YYYY-MM-DD.json` + - `runtime/digests/YYYY-MM-DD.md` +- Digest captures operational counts + alerts + exception summary for commander review. + +13) Pixel data adapter (Phase 7) +- Endpoint: `GET /view/pixel-state.json` +- Purpose: minimal adapter for future Gameboy view. +- Output model: `rooms`, `entities`, `links` generated from local project/task/session/agent state. + +14) Notification policy engine (Phase 7) +- Runtime policy file: `runtime/notification-policy.json` +- Supports: + - quiet hours suppression + - severity-to-route mapping (`info/warn/action-required`) +- Preview endpoint: `GET /notifications/preview` (optional `?at=` simulation). + +15) Cron overview (Phase 7) +- Endpoint: `GET /cron` +- Summarizes next run timing, per-job health (`scheduled/due/late/unknown/disabled`), and monitor lag state. + +16) System health panel endpoint (Phase 7) +- Endpoint: `GET /healthz` +- Combines: + - build/runtime info (`package.json`, dist build timestamp, safety gates) + - snapshot freshness (`runtime/last-snapshot.json` age) + - monitor lag (`runtime/timeline.log` latest tick) + +17) Markdown digest renderer page (Phase 7) +- Endpoint: `GET /digest/latest` +- Reads latest `runtime/digests/*.md` and renders safe HTML for operator consumption. + +18) Operator dashboard preferences + quick filters (Phase 8) +- Home page resolves effective filters from URL query + persisted defaults in `runtime/ui-preferences.json`. +- Compact status strip mode is persisted and toggleable from dashboard UI. +- Quick filters (`all`, `attention`, task states) apply readonly task subsets without mutating task state. + +19) Search APIs (Phase 8) +- Endpoints: + - `GET /api/search/tasks` + - `GET /api/search/projects` + - `GET /api/search/sessions` + - `GET /api/search/exceptions` +- Semantics: + - case-insensitive substring matching only (safe includes, no regex eval) + - bounded `limit` query to cap payload size and prevent oversized scans + +20) Replay index + API docs (Phase 8) +- `GET /api/replay/index` indexes: + - `runtime/timeline.log` + - `runtime/digests/*.json` + - `runtime/export-snapshots/*.json` + - `runtime/exports/*.json` +- optional query window filters: + - `from=` + - `to=` +- replay response includes per-source filter observability stats: + - `total`, `returned`, `filteredOut`, `filteredOutByWindow`, `filteredOutByLimit` +- `GET /api/docs` returns route + schema summary payload for operator/debug usage. +- `GET /export/state.json` now also persists timestamped export snapshots under `runtime/export-snapshots/`. + +21) Request telemetry correlation (Phase 8) +- Request ID resolution: + - incoming `x-request-id` sanitized and reused when valid + - otherwise generated UUID +- Correlation propagation: + - all responses include `x-request-id` + - JSON responses include top-level `requestId` + - error envelope includes `error.requestId` + - warn/error logs include the same requestId + +22) Integration readiness + backup/import surfaces (Phase 9) +- Final integration checklist endpoint: + - `GET /done-checklist` (alias `GET /api/done-checklist`) + - Builds docs-aligned checklist with runtime capability checks. + - Computes lightweight readiness scores: `observability`, `governance`, `collaboration`, `security`. +- Export backup command: + - app command mode `backup-export` writes timestamped bundles to `runtime/exports/*.json`. +- Import dry-run validator: + - API: `POST /api/import/dry-run` + - app command mode: `import-validate ` + - validates bundle shape only; no mutation. +- Optional live import mutation endpoint: + - API: `POST /api/import/live` + - requires explicit env gate `IMPORT_MUTATION_ENABLED=true` + - still requires local token auth + - blocked while `READONLY_MODE=true` unless request sets `dryRun=true` +- Commander feed order is normalized for operator priority: + - severity first (`action-required` > `warn` > `info`) + - newest event timestamp within each severity bucket. + +23) Local mutation/import auth gate + deterministic ordering hardening (Phase 10) +- New local auth gate defaults: + - `LOCAL_TOKEN_AUTH_REQUIRED=true` + - `LOCAL_API_TOKEN` must be configured for protected operations + - token accepted via `x-local-token` or `Authorization: Bearer` +- Protected routes: + - all state-changing endpoints (`POST`/`PATCH`) + - import/export routes with side effects (`/api/import/dry-run`, `/api/import/live`, `/export/state.json`, `/api/export/state.json`) +- Protected command paths: + - `backup-export` + - `import-validate` + - `acks-prune` +- Operation audit trail: + - import dry-run, import apply, backup export, and ack prune attempts append JSONL entries to `runtime/operation-audit.log` + - audit timeline now includes source `operation` +- Commander feed ordering tie-breakers are now fully deterministic after severity/time (code/source/sourceId/route/message). + +24) Replay windowing + acknowledgement TTL semantics (Phase 13) +- Replay index supports optional global time window filtering (`from`, `to`) over: + - timeline entries + - digest entries + - export snapshots + - export bundles +- Action queue acknowledgements support optional expiry: + - `ttlMinutes` (relative duration) + - `snoozeUntil` (absolute future timestamp) +- Expired acknowledgements are treated as inactive, so queue items reappear without manual reset. + +25) Replay filter stats + stale ack prune command (Phase 14) +- Replay index exposes per-source and aggregate filtered-vs-returned stats for operator debugging on large windows. +- Replay stats now include per-source latency and size indicators (`latencyMs`, `latencyBucketsMs.p50`, `latencyBucketsMs.p95`, `totalSizeBytes`, `returnedSizeBytes`) for large-instance troubleshooting. +- Home dashboard replay panel surfaces returned/filtered counts to reduce blind spots when window/limit filters hide artifacts. +- Added command-mode stale ack prune: + - `APP_COMMAND=acks-prune` + - optional dry-run via `COMMAND_ARG=--dry-run` or `ACK_PRUNE_DRY_RUN=true` + - local token-gated by default when `LOCAL_TOKEN_AUTH_REQUIRED=true` + - prunes expired `runtime/acks.json` entries and writes `ack_prune` operation audit records. + +26) Mission Control v3 parity + office model (Phase 25) +- UI shell upgraded to polished pixel-office visual system (tokenized colors/spacing/radii/shadows, layered background, responsive rails, subtle motion). +- Primary IA renamed for operator intent: + - Command Deck, Usage & Billing, Pixel Office, Work Board, Decisions, Timeline, Control Room. +- Added Mac parity surface matrix panel in Command Deck: + - each core capability exposes status + direct route entry. +- Added agent roster adapter: + - module: `src/runtime/agent-roster.ts` + - source: best-effort read from `~/.openclaw/openclaw.json` (read-only) + - fallback merge with runtime session/task/project/budget signals to avoid missing inactive agents. +- Pixel Office renders desk/zone occupancy instead of session-only grouping. + +27) Subscription usage/remaining contract (Phase 25) +- Usage adapter now includes best-effort subscription source probes: + - `runtime/subscription-snapshot.json` + - `~/.openclaw/subscription.json` + - `~/.openclaw/billing/subscription.json` + - `~/.openclaw/billing/usage.json` + - `~/.openclaw/usage/subscription.json` +- Data contract in `UsageCostSnapshot.subscription`: + - `connected`: consumed/remaining/limit/cycle/source available + - `partial`: source found but fields incomplete/parse issues + - `not_connected`: explicit connection hint +- Connector state now includes `subscriptionUsage` and exposes actionable TODOs when disconnected. + +## MVP Scope (Phase 1) +- Local scaffold only +- No network calls in default readonly mode +- Define contracts + polling config + +## Safety Constraints (Current) +- `READONLY_MODE=true` is the default and remains the primary runtime mode. +- `APPROVAL_ACTIONS_ENABLED=false` by default; no real approve/reject runs unless this is explicitly `true`. +- `APPROVAL_ACTIONS_DRY_RUN=true` by default; action endpoints simulate and audit but do not execute. +- `IMPORT_MUTATION_ENABLED=false` by default; live import apply is disabled unless explicitly gated on. +- `IMPORT_MUTATION_DRY_RUN=false` by default; `/api/import/live` uses request `dryRun=true` for non-mutating execution when needed. +- `LOCAL_TOKEN_AUTH_REQUIRED=true` by default; protected operations remain blocked unless explicit local token is configured and presented. +- Writes are limited to local `control-center/runtime/*` files (`last-snapshot.json`, `timeline.log`, `projects.json`, `tasks.json`, `budgets.json`, `acks.json`, `approval-actions.log`, `operation-audit.log`, `ui-preferences.json`, `export-snapshots/*.json`, `exports/*.json`). +- Runtime digests are local-only artifacts under `control-center/runtime/digests/*`. +- No mutation of OpenClaw runtime config from this project. + +## Local API Surface +- `GET /projects` +- `GET /api/projects` +- `POST /api/projects` +- `PATCH /api/projects/:projectId` +- `GET /api/tasks` +- `GET /tasks` +- `GET /sessions` +- `GET /sessions/:id` +- `GET /session/:id` +- `GET /api/sessions` +- `GET /api/sessions/:id` +- `POST /api/tasks` +- `PATCH /api/tasks/:taskId/status` +- `GET /api/action-queue` +- `GET /api/action-queue/acks/prune-preview` +- `POST /api/action-queue/:itemId/ack` +- `GET /exceptions` +- `GET /api/commander/exceptions` +- `GET /graph` +- `GET /view/pixel-state.json` +- `GET /export/state.json` +- `GET /notifications/preview` +- `GET /cron` +- `GET /healthz` +- `GET /digest/latest` +- `GET /audit` +- `GET /api/audit` +- `GET /api/ui/preferences` +- `PATCH /api/ui/preferences` +- `GET /api/search/tasks` +- `GET /api/search/projects` +- `GET /api/search/sessions` +- `GET /api/search/exceptions` +- `GET /api/replay/index` +- `GET /api/docs` +- `GET /done-checklist` +- `GET /api/done-checklist` +- `POST /api/import/dry-run` +- `POST /api/import/live` +- `POST /api/approvals/:approvalId/approve` +- `POST /api/approvals/:approvalId/reject` diff --git a/docs/OPS_CONTROL_PLAN.md b/docs/OPS_CONTROL_PLAN.md new file mode 100644 index 0000000..482e7ae --- /dev/null +++ b/docs/OPS_CONTROL_PLAN.md @@ -0,0 +1,101 @@ +# 24/7 Control Plan (Pandas) + +## P0 Checklist (must pass in order) + +- [x] P0-1 Single Run Lock + - lock file: `runtime/run.lock` + - acquire rejects concurrent non-expired lock + - renew only works for owner + - release requires owner or expired lock + - fencing token increments on each new acquire after expiry/reacquire + +- [x] P0-2 Evidence Gate +- [x] P0-3 Stall Detection + Auto-Heal +- [x] P0-4 Goal State Machine (DoD + phase gates) + +## P1 Checklist + +- [x] P1-1 Unified artifact directories baseline (`runtime/evidence`, `runtime/health`, `runtime/recovery`) +- [x] P1-2 Periodic health/evidence snapshot automation +- [x] P1-3 Evidence-only reporter wiring to outbound updates +- [x] P1-4 Single-chain watchdog orchestration + +## P2 Checklist + +- [x] P2-1 Resident worker loop (`worker:resident`) with lock lease renew + cycle heartbeat/progress artifacts +- [x] P2-2 Resident supervisor (`supervisor:resident`) with stale/dead restart decisions, bounded retries, recovery reports +- [x] P2-3 Independent DoD checker (`dod:check`) with machine-readable DoD status artifact and hard gate for done state + +## Evidence for P0-1 + +- command: `npm run lock:acquire` +- command: `npm run lock:status` +- command: `npm run lock:renew` +- command: `npm run lock:release` +- artifact: `runtime/run.lock` + +## Evidence for P1-2 + +- command: `npm run health:snapshot:periodic` +- artifacts: + - `runtime/health/snapshots/.json` + - `runtime/health/latest.pointer.json` + - `runtime/evidence/snapshots/.json` + - `runtime/evidence/latest.pointer.json` + +## Evidence for P1-3 + +- command: `npm run evidence:report` +- command: `node --import tsx scripts/evidence-reporter.ts ` (fails closed) +- artifacts: + - `runtime/evidence/outbound/.json` + - `runtime/evidence/outbound/latest.json` + - `runtime/evidence/outbound/latest.pointer.json` +- hard gate: + - 当 evidence.completed 包含完成语义(done/completed/完成)时,`evidence:report` 会先执行 `dod:check` + - 若 DoD 未通过,系统层拦截并返回 `REPORT_BLOCKED_DOD NOT_DONE`,禁止发出“完成”消息 + +## Evidence for P1-4 + +- command: `npm run watchdog:run` +- artifact: `runtime/recovery/watchdog-latest.json` +- behavior: + - lock owner conflict exits non-zero (`WATCHDOG_LOCK_CONFLICT`) + - owner lock renew/acquire + heal chain succeeds (`WATCHDOG_OK`) + +## Product DoD (Ti acceptance gate) + +Mission Control 只有在以下标准全部通过时才允许标记完成,否则必须保持 `NOT_DONE`: +- 全量任务可视化:所有 cron + heartbeat 任务可见(谁在执行、在做什么、下次时间、最近结果) +- 非技术化默认视图:不暴露无用技术噪音(PID/命令/JSON键等) +- 全中文彻底 + 初中生可懂 +- 一眼看全局(cron/heartbeat/当前任务/工具调用) +- UI 达到 Apple 原生风格水准 +- 订阅窗口必须真实接通;若未接通必须明确阻塞与下一步,不可模糊 partial +- Ti 人工验收通过 + +系统硬规则: +- 未达标 = `NOT_DONE` +- `NOT_DONE` 时禁止宣布完成 +- `NOT_DONE` 时施工链必须持续运行,不能停工 + +DoD 定义文件:`runtime/evidence/product-dod.json` +DoD 状态产物:`runtime/evidence/dod-status.json` + +## Evidence for P2 Triplet + +- commands: + - `npm run worker:resident` + - `npm run supervisor:resident` + - `npm run dod:check` +- artifacts: + - `runtime/health/worker-heartbeat.json` + - `runtime/evidence/worker-progress.json` + - `runtime/evidence/dod-status.json` + - `runtime/recovery/supervisor-latest.json` + - `runtime/recovery/supervisor-audit.log` +- guarantees: + - worker exits non-zero on lock owner conflict (`WORKER_LOCK_CONFLICT`) + - worker runs resident loop by default: `codex-patch -> test -> evidence-report -> health-snapshot -> next cycle` + - supervisor restarts on stale/dead worker with bounded retries + - neither worker nor supervisor treats run as done unless `dod:check` returns `DONE` (otherwise `NOT_DONE`) diff --git a/docs/PARITY-MATRIX-v3.md b/docs/PARITY-MATRIX-v3.md new file mode 100644 index 0000000..0c798ca --- /dev/null +++ b/docs/PARITY-MATRIX-v3.md @@ -0,0 +1,25 @@ +# Mission Control v3 Parity Matrix + +Date: 2026-03-04 + +## Goal +Track Mission Control v3 parity against core OpenClaw Mac-app control surfaces. + +## Surface Matrix +| Surface | Route | Status | Notes | +| --- | --- | --- | --- | +| Conversations / session visibility | `/sessions` | Implemented | Session list, filters, detail drill-down, history preview. | +| Approvals + decision queue | `/?section=projects-tasks&quick=attention#task-lane` + `/api/action-queue` | Implemented | Queue + approval feed surfaced in the task hub decision lane. | +| Cron / scheduling | `/cron` | Implemented | Health, next-run, and lag indicators available. | +| Projects / tasks | `/?section=projects-tasks` | Implemented | Lanes + table + filters and task/project APIs. | +| Usage / cost | `/?section=usage-cost` + `/api/usage-cost` | Implemented | Runtime usage periods, breakdowns, context windows, budget/burn. | +| Subscription consumed/remaining | `/?section=usage-cost` + `/api/usage-cost` | Implemented | Provider snapshot first; runtime usage + 30d budget-limit fallback supplies consumed/remaining/limit when provider snapshots are missing. | +| Replay / audit | `/audit` | Implemented | Audit page/API are the stable user-facing replay entry; old replay section routes now resolve back to overview. | +| Health / digest | `/digest/latest` + `/healthz` | Implemented | Digest page is the operator-facing entry; `/healthz` remains the machine-readable health payload. | +| Export / import dry-run + safety gates | `/?section=settings` + `/export/state.json` + `/api/import/dry-run` | Implemented | Guard table shows gate posture; dry-run remains non-mutating by default. | +| Pixel / canvas adapter | `/view/pixel-state.json` | Implemented | Pixel scene payload (rooms/entities/links). | +| Full agent roster office model | `/?section=office-space` | Implemented | Roster merged from config + runtime with zone/desk occupancy floor. | + +## Known Caveats +- UI-mode smoke in restricted sandboxes can fail with environment bind errors; use free ports and elevated execution when required. +- Provider subscription snapshots can still be unavailable; in that case values are derived from runtime spend + configured 30d budget limit and marked in source/detail fields. diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md new file mode 100644 index 0000000..c9ffcfe --- /dev/null +++ b/docs/PROGRESS.md @@ -0,0 +1,4080 @@ +# Progress + +## Phase 128 (Standalone public-release workflow and audit gate) — Completed +- Scope: + - Convert open-source readiness from a one-off manual check into a repeatable local release workflow. + - Keep internal planning and automation artifacts out of the future standalone public repo by default. +- Changed files: + - `.gitignore` + - `README.md` + - `package.json` + - `scripts/release-audit.sh` + - `docs/PUBLISHING.md` + - `docs/PROGRESS.md` +- Implementation: + - Added `npm run release:audit` as a public-release hygiene gate. + - Added `scripts/release-audit.sh` to scan the real workspace contents for: + - personal absolute home paths + - hard-coded internal channel ids + - obvious secret/token leaks + - tracked runtime/build/internal-only paths once the directory becomes its own git repo + - Added `docs/PUBLISHING.md` with the recommended best-practice flow: + - publish only `control-center/` + - keep it as a standalone repo + - run audit/build/test/smoke before every push + - Extended `.gitignore` so internal planning and one-off workflow files do not get swept into the future public repo by accident. +- Verification: + - `npm run release:audit` passed. + - `npm run build` passed. + - `npm test` passed. + - `npm run smoke:ui` passed. + +## Phase 127 (README hero polish + real screenshots for public GitHub landing) — Completed +- Scope: + - Make the public README read like a real open-source landing page instead of jumping straight into internal-style detail. + - Add real product screenshots so GitHub visitors can see the UI before reading setup steps. +- Changed files: + - `README.md` + - `docs/assets/overview-en.png` + - `docs/assets/usage-en.png` + - `docs/PROGRESS.md` +- Implementation: + - Added a top-of-file product summary: + - why this exists + - what users get + - who it is for + - a short `5-minute start` + - Captured fresh local product screenshots for `Overview` and `Usage`. + - Embedded those screenshots into the README using GitHub-friendly relative asset paths. +- Verification: + - `node --import tsx --test test/oss-readiness.test.ts` passed. + - `npm run build` passed. + - `npm test` passed. + - `npm run smoke:ui` passed. + +## Phase 126 (Current-project agent roster becomes the only source of truth) — Completed +- Scope: + - Ensure agent discovery always reflects the current OpenClaw project roster instead of stale runtime folders or old session stores. + - Stop retired agents from reappearing in staff cards, busy-agent summaries, runtime presence, or live-session merges. +- Changed files: + - `src/runtime/current-agent-catalog.ts` + - `src/runtime/agent-roster.ts` + - `src/runtime/office-session-presence.ts` + - `src/clients/openclaw-live-client.ts` + - `src/ui/server.ts` + - `test/agent-roster.test.ts` + - `test/office-roster.test.ts` + - `test/office-session-presence.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added a shared current-agent catalog loader backed by `openclaw.json`. + - When `openclaw.json` defines agents, it now becomes the authoritative current-project roster. + - Runtime folder scans and live-session store merges now filter to configured current agents instead of reviving stale agent directories such as old `codex`. + - Office/staff/execution summaries now honor the configured roster as a whitelist, so unknown runtime agents no longer reappear on the dashboard. +- Verification: + - `npm test` passed. + - `npm run build` passed. + - `npm run smoke:ui` passed. + +## Phase 125 (Bilingual README onboarding for external OpenClaw users) — Completed +- Scope: + - Turn the public README into a real onboarding document for new OpenClaw users instead of a short internal quick-start note. + - Provide both English and Chinese step-by-step setup instructions, plus a reusable prompt users can hand to their own OpenClaw to prepare `.env`. +- Changed files: + - `README.md` + - `.env.example` + - `docs/PROGRESS.md` +- Implementation: + - Added top-level language navigation in `README.md` so GitHub readers can jump directly to English or Chinese onboarding. + - Expanded setup guidance into full install/config/verify/first-use checklists for both languages. + - Added copy-paste-ready setup prompts in both English and Chinese so users can ask their own OpenClaw to inspect paths, prepare `.env`, and keep safe first-run defaults. + - Exposed optional path overrides in `.env.example` for non-default `OPENCLAW_HOME`, `CODEX_HOME`, and subscription snapshot locations. +- Verification: + - `node --import tsx --test test/oss-readiness.test.ts` passed. + - `npm run build` passed. + - `npm test` passed. + +## Phase 124 (Open-source doc hygiene cleanup) — Completed +- Scope: + - Remove internal-only documentation traces that make the public repo look tied to one operator environment. + - Keep the engineering history useful without exposing hard-coded channel ids, localhost verification commands, or real runtime session identifiers. +- Changed files: + - `docs/mission-control-runbook-v2.md` + - `docs/PROGRESS.md` +- Implementation: + - Replaced the hard-coded reporting channel reference in the mission runbook with a generic configured-destination instruction. + - Sanitized older progress entries so public history now records verification outcomes in plain language instead of embedding: + - local validation commands tied to one operator machine + - concrete local curl pipelines + - real runtime session identifiers + - machine-specific live verification traces +- Verification: + - `node --import tsx --test test/oss-readiness.test.ts` passed. + - repo leak audit no longer finds the removed channel id or sanitized localhost/session-command traces in public docs. + +## Phase 123 (Stale session errors no longer pollute current-state queues) — Completed +- Scope: + - Stop old dead sessions from surfacing as fresh `SESSION_ERROR` items on the Overview and in `Waiting for your decision / 等待你决策`. + - Keep current-state runtime metrics automatic and meaningful without hiding real fresh failures. +- Changed files: + - `src/runtime/commander.ts` + - `src/ui/server.ts` + - `test/commander-ordering.test.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added a `6h` freshness gate for runtime issue sessions in the commander exception layer. + - Current-state `blocked / waiting_approval / error` sessions now count only if they still have recent runtime activity. + - Rewired Overview `Runtime issues / 运行异常` to reuse the filtered commander exceptions instead of recounting raw session states. + - This keeps stale store-only corpses in history/export paths, but removes them from the live decision queue and top-level health signals. +- Verification: + - `npm test` passed. + - `npm run build` passed. + - `npm run smoke:ui` passed. + +## Phase 122 (Runtime issue signal keeps real session states) — Completed +- Scope: + - Make `Runtime issues / 运行异常` use real abnormal session states from live OpenClaw data instead of flattening sessions to `running / idle`. + - Keep the metric automatic and operator-meaningful with no new manual inputs. +- Changed files: + - `src/contracts/openclaw-tools.ts` + - `src/clients/openclaw-live-client.ts` + - `src/mappers/openclaw-mappers.ts` + - `src/ui/server.ts` + - `test/openclaw-mappers.test.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Extended live session records to carry explicit upstream state text. + - Preserved explicit states from CLI output and local session stores during session-list merge. + - Normalized live states so the dashboard now keeps `blocked`, `waiting_approval`, and `error` instead of collapsing everything into `running` or `idle`. + - Switched UI live-snapshot merging to reuse normalized session summaries. +- Verification: + - `npm test` passed. + - `npm run build` passed. + - `npm run smoke:ui` passed. + +## Phase 121 (Quota window labels stop leaking minute-level telemetry noise) — Completed +- Scope: + - Fix quota cards and overview subscription summaries that exposed Codex weekly windows as raw minute counts like `10081m`. + - Keep small telemetry drift invisible to non-technical users by snapping near-common quota windows back to stable labels. +- Changed files: + - `src/runtime/usage-cost.ts` + - `src/ui/server.ts` + - `test/usage-cost.test.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added common-window snapping in the Codex telemetry formatter: + - near `300` minutes renders as `5h` + - near `10080` minutes renders as `7d` + - Hardened UI label normalization so raw minute labels such as `300m` / `10081m` still display as `5h` / `Week`. +- Verification: + - `npm test` passed. + - `npm run build` passed. + - `npm run smoke:ui` passed. + - live `/?section=overview&lang=zh` no longer shows `10081m`. + +## Phase 120 (Execution-chain board promoted to large Apple-style cards) — Completed +- Scope: + - Stop the execution-chain board from cramming four narrow cards into one row. + - Make card titles readable again by moving the badge rail out of the title's horizontal squeeze zone. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Rebuilt execution-chain cards as larger, roomier cards: + - grid now uses wide-card minimums instead of narrow four-up tiles + - narrower layouts collapse the board to one card per row + - Reworked the card header: + - title and context stay together as the visual headline + - badges now sit below the title block instead of stealing headline width + - Split dense body text into clearer bands: + - source/latest row + - session-flow capsule + - summary line + - Added plain-language cleanup for pipe-style execution summaries so strings like `accepted=yes | spawned=yes` no longer leak into visible cards. +- Verification: + - `npm test` passed. + - `npm run build` passed. + - `npm run smoke:ui` passed. + - live `/?section=projects-tasks&lang=zh` verified after PM2 restart. + +## Phase 119 (Keep runtime-first metrics, drop frontstage certainty panels) — Completed +- Scope: + - Remove the extra certainty/explainer panels from Overview / Tasks / Settings so the existing dashboard structure stays intact. + - Keep the runtime-first automatic scoring under the hood and route users back to the original high-value entry points: current tasks and follow-up items. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Pulled `Information certainty / 信息确定性` out of the visible Overview and Settings pages. + - Pulled the standalone `Execution certainty / 执行确定性` board out of the Tasks page while keeping runtime-first task inference for summaries and task detail. + - Restored top-level task entry actions to `Open current tasks / 查看当前任务` and `Open follow-up items / 查看待处理`. + - Kept automatic health signals tied to runtime evidence only: + - review queue + - blocked / waiting / failing sessions + - stalled runs + - budget risk +- Verification: + - `npm test` passed. + - `npm run build` passed. + - `npm run smoke:ui` passed. + +## Phase 118 (Automatic runtime-first overview and task certainty signals) — Completed +- Scope: + - Remove the most visible Overview / Tasks health signals that depended on manual task metadata such as `dueAt`, `blocked`, or owner assignment. + - Re-anchor the top-level control posture and task certainty around runtime evidence only: review queue, session issues, stalled runs, approvals, tool activity, and execution traces. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `scripts/ui-smoke.sh` + - `docs/PROGRESS.md` +- Implementation: + - Reworked the Overview decision layer to use automatic runtime signals: + - `Review queue / 审阅队列` now reads from unacked action items only + - `Runtime issues / 运行异常` now reflects blocked / waiting / error sessions plus stalled runs + - `Stalled runs / 停滞执行` now detects running sessions that have gone quiet for too long + - `Health score / 健康分` no longer deducts points from manual `dueAt` or task-level `blocked` flags + - Reworked `Execution certainty / 执行确定性` scoring: + - removed boosts/penalties tied to `owner`, `dueAt`, `task.status === blocked`, and `overdue` + - cards now score from linked sessions, runtime visibility, recent activity, tool evidence, execution-chain evidence, pending approvals, and session states + - Reworked the task-hub summary strip and sidebar so they now point users to runtime evidence boards instead of manual blocked/overdue task counts. + - Hardened `ui-smoke` startup: + - switched from a blind fixed sleep to readiness polling + - extended the default wait window so local verification no longer flakes on slower UI startup +- Verification: + - `npm test` passed. + - `npm run build` passed. + - `npm run smoke:ui` passed. + +## Phase 117 (Usage promoted to the second nav slot) — Completed +- Scope: + - Move `Usage / 用量` directly under `Overview / 总览` in the dashboard sidebar. + - Keep English and Chinese navigation order aligned so mobile and desktop match the same information hierarchy. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Reordered the canonical dashboard section link list so `usage-cost` sits immediately after `overview`. + - Added regression coverage that asserts: + - `Overview` appears before `Usage` + - `Usage` appears before `Staff` + - `总览` appears before `用量` + - `用量` appears before `员工` +- Verification: + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm run build` passed. + - Runtime smoke confirmed sidebar order on `/?section=overview&lang=zh`. + +## Phase 116 (Editable workbench scope stays config-truthful under config errors) — Completed +- Scope: + - Prevent deleted agent folders from reappearing in `Documents / Memory` when old workspace directories still exist. + - Keep the workbench conservative when config parsing fails: under-show instead of showing stale agents. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Hardened editable-scope fallback policy: + - valid `openclaw.json` keeps driving the facet list + - invalid config now falls back to `Main` only instead of scanning stale workspace folders + - Kept `Main` always present in editable scopes, even if config omits it +- Verification: + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm run build` passed. + - `npm run smoke:ui` passed. + - live `/docs?lang=en` confirmed `Available views: Main, Coq, Monkey, Otter, Pandas, Tiger` + +## Phase 115 (Apple-native card elevation and background contrast tune) — Completed +- Scope: + - Make cards separate more clearly from the page canvas without changing information hierarchy. + - Keep the UI aligned with the existing Apple-native visual direction instead of introducing a new style language. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Tuned the main canvas to a cooler, slightly deeper system-style gray so white cards read more clearly in the foreground. + - Upgraded core card fills, borders, and shadows: + - primary cards + - KPI/hero cards + - execution-chain cards + - status chips + - task/queue/lane cards + - Kept the effect restrained: + - no layout changes + - no information-density changes + - just stronger separation, depth, and polish +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm run smoke:ui` passed. + +## Phase 114 (Execution-chain card hardening against raw payload titles) — Completed +- Scope: + - Prevent raw JSON-like payloads from surfacing as execution-chain card titles. + - Keep long execution-chain text inside the card so badges and neighboring cards do not get overlapped. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added defensive execution-chain title sanitization: + - unmapped isolated runs always keep stable titles like `Main · Cron 隔离执行` + - mapped cards now refuse JSON-like payload titles and convert structured payloads into short plain-language summaries instead + - Hardened execution-chain layout: + - card body now clips overflow safely + - badge rail and meta rows now obey wrap/break constraints instead of leaking into neighboring cards +- Verification: + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm run build` passed. + - Runtime smoke passed: + - `/?section=projects-tasks&lang=zh` no longer renders raw `attemptedQueries` / `ok` payloads inside card titles + - execution-chain cards render stable titles and readable summaries + +## Phase 113 (Open-source release hygiene and portability pass) — Completed +- Scope: + - Make the repo safe to publish externally without shipping machine-specific paths, embedded local secrets, or local-only startup assumptions. + - Add regression coverage for baseline OSS readiness so these leaks do not return. +- Changed files: + - `.gitignore` + - `LICENSE` + - `package.json` + - `.env.example` + - `src/config.ts` + - `ecosystem.config.cjs` + - `mission.config.json` + - `workflows/pandas_v3_autopilot.lobster` + - `scripts/run_verifier.sh` + - `scripts/ui-smoke.sh` + - `scripts/mc_dod_evaluator.py` + - `scripts/mc_rollback_plan.py` + - `README.md` + - `docs/ARCHITECTURE.md` + - `docs/mission.runbook.md` + - `docs/PROGRESS.md` + - `test/oss-readiness.test.ts` +- Implementation: + - Added basic release metadata: + - `.gitignore` now excludes runtime/build artifacts and local env files + - `LICENSE` added under MIT + - `package.json` is no longer marked `private` + - Removed machine-specific launch assumptions: + - `GATEWAY_URL` is now environment-configurable with the local websocket kept only as the default fallback + - PM2 sample config now uses `__dirname` and environment-injected `LOCAL_API_TOKEN` + - mission/workflow/verifier files now use repo-relative paths instead of one developer machine path + - UI smoke is now a first-class repo script instead of an ad hoc one-liner + - Sanitized public-facing docs: + - OpenClaw paths now use `~/.openclaw/...` or repo-relative references + - embedded local token values were removed +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/oss-readiness.test.ts` passed. + - `npm test` passed. + - `npm run smoke:ui` passed. + +## Phase 112 (Staff status freshness semantics fix) — Completed +- Scope: + - Fix the staff overview so `Working / 工作中` reflects live execution rather than simply “has unfinished tasks”. + - Make `Working on / 正在处理什么` stop sounding live when the agent is only queued for later work. +- Changed files: + - `src/ui/server.ts` + - `test/office-roster.test.ts` + - `docs/PROGRESS.md` + - `README.md` +- Implementation: + - Fixed office-card status derivation: + - live session states still mark an agent as `running` + - unfinished tasks without live sessions now keep the agent at `idle` + - this removes the sticky false-positive where backlog alone made someone look active + - Fixed staff work-label wording: + - live execution still uses `Working on / 正在处理什么` + - queued-but-not-live work now uses `Next up / 下一项` + - Kept cache behavior short: + - staff status/recent-activity cache remains only `3s` + - live sessions polling baseline remains `5s` +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/office-roster.test.ts` passed. + - `npm test` passed. + - Added regression coverage for: + - agents with unfinished tasks but no live sessions stay `idle` + - staff overview uses `下一项` instead of live-work wording when work is queued, not currently executing + +## Phase 111 (Execution-chain card cleanup for non-technical readability) — Completed +- Scope: + - Fix the `Execution chain` board where raw JSON payloads were leaking directly into card titles and summaries. + - Make execution-chain cards stay readable even when session keys or payloads are long. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` + - `README.md` +- Implementation: + - Replaced unstable unmapped-card titles with stable human labels: + - cards now show titles like `Main · Cron 隔离执行` + - removed the behavior where raw response payloads became the headline + - Added best-effort payload summarization for JSON-like snippets: + - success/error states now render as short status summaries + - common counters such as queries / scanned / qualified / sent are shown as readable chips in one line + - truncated JSON-like snippets are handled too, so half-cut payloads no longer leak into the UI + - Hardened execution-chain card layout: + - long titles clamp instead of pushing badges off the card + - long session keys now wrap inside the card instead of blowing up the grid +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm test` passed. + - Runtime smoke confirmed: + - `/?section=projects-tasks&lang=zh` now shows `Main · Cron 隔离执行` + - summaries now read like `成功 · 查询 30 · 成功 30`, `失败 · 错误 locked`, `成功 · 扫描 120 · 入选 2 · 发送 2` + - raw JSON keys such as `attemptedQueries` no longer appear in visible execution-chain card copy + +## Phase 110 (Docs/memory agent scope follows active config) — Completed +- Scope: + - Fix the `Documents / Memory` workbenches so they stop treating stale workspace folders as live agents. + - Restore `Main` as the root OpenClaw facet and keep editable file content aligned with the latest source files. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` + - `README.md` +- Implementation: + - Replaced raw `workspace/agents/*` facet discovery with config-first scope resolution from `~/.openclaw/openclaw.json`: + - `main` now renders as the root facet instead of the vague `共享` + - removed agents such as `dolphin` and `mission-ops` no longer appear just because old folders still exist on disk + - workspace-folder scanning remains only as fallback when config is unavailable + - Aligned both editable workbenches to the same scope source: + - `Documents` now shows `Main` plus currently enabled agents + - `Memory` now shows `Main` plus currently enabled agents + - Kept editable file content live against source files: + - file entries still read `mtime` and text directly from the source path + - save actions still write directly back to the same source file +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm test` passed. + - Runtime smoke confirmed: + - `/?section=docs&lang=en` now shows `Available views: Main, Coq, Monkey, Otter, Pandas, Tiger` + - `/?section=memory&lang=en` now shows `Available views: Main, Coq, Monkey, Otter, Pandas, Tiger` + - `Dolphin` and `Mission Ops` no longer appear in those facet controls + - `/api/files?scope=workspace` returns live `updatedAt` and `sourcePath` values from source files + +## Phase 109 (Session-detail UX alignment and docs/memory language cleanup) — Completed +- Scope: + - Fix session-detail entry points that still dropped users onto JSON routes or forced English-only detail pages. + - Remove the most visible mixed-language punctuation and stale Chinese-only docs index behavior from `Memory / Documents`. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` + - `README.md` +- Implementation: + - Fixed all user-facing session-detail links to use the real drill-down page instead of `/sessions/:id` JSON: + - overview tool activity + - recent session lists + - task evidence / execution-chain links + - Localized `/session/:id`: + - page now follows `lang=en|zh` + - Chinese session detail now shows Chinese headings and returns to the localized overview + - Localized `/docs` index and made it accept `lang`: + - English users now see an English docs index + - index now offers a direct path back into the `Documents` workbench + - Cleaned visible English punctuation on `Memory / Documents`: + - `Available views`, sidebar `Updated`, and workbench `Files` no longer show Chinese punctuation on English pages +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm test` passed. + - Runtime smoke confirmed: + - `/?section=overview&lang=en` session links now point to `/session/...?...lang=en` + - `/session/agent:main:main?lang=zh` renders Chinese headings and localized back link + - `/?section=memory&lang=en` now shows `Available views: Main, ...`, `Updated: ...`, and `Files: ...` + - `/docs?lang=en` now renders an English docs index with `Open document workbench` + +## Phase 108 (Search truth-source alignment and import validation clarity) — Completed +- Scope: + - Fix search surfaces that could under-report real matches or miss current live sessions. + - Ensure import-live bad file paths fail as clear validation errors instead of generic internal errors. +- Changed files: + - `src/ui/server.ts` + - `src/runtime/import-live.ts` + - `src/runtime/api-docs.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` + - `README.md` +- Implementation: + - Fixed all `/api/search/*` endpoints to separate total match count from returned rows: + - `count` now means full matches before limit + - `returned` now means how many rows are in this response + - Fixed `/api/search/sessions` to read the live-merged session snapshot: + - search results now stay aligned with `/sessions` instead of silently missing newer runtime sessions + - Fixed bounded dashboard-search helpers to carry the same `count` vs `returned` semantics: + - avoids future UI regressions where “命中”/“matches” only reflected the current slice + - Fixed import-live file path resolution errors: + - bad `fileName` values now return structured validation failures instead of bubbling into `500 INTERNAL_ERROR` + - Updated generated API docs and route notes to reflect the new semantics. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm test` passed. + - Added smoke coverage for: + - bounded search helpers returning `count=2` with `returned=1` + - invalid import-live file paths producing validation issues instead of thrown errors + +## Phase 107 (Feature-correctness sweep for approvals, replay, and tool activity) — Completed +- Scope: + - Remove user-facing mismatches discovered during the feature-by-feature observability audit across approvals, replay, and overview tool activity. + - Ensure visible counts, previews, and entry links point to real current surfaces instead of deprecated section routes. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PARITY-MATRIX-v3.md` + - `docs/PROGRESS.md` + - `README.md` +- Implementation: + - Fixed approval counts to use the full approval set instead of the 5-item preview slice: + - pending approvals, pending decisions, and sidebar counts now reflect all current approvals + - preview lists still stay short, but now say when they are only showing the latest subset + - Fixed replay summary counts to use replay totals instead of limited preview lengths: + - replay signal chips now report total timeline / digest / export availability + - replay metrics keep the shown-vs-total breakdown + - Fixed overview tool-activity detail so it actually loads session preview data: + - the page no longer says “no tool-call sessions yet” while the same page shows live tool-call counts + - Removed stale section-entry misinformation from current routes/docs: + - user-facing parity routes no longer point at deprecated `?section=alerts` / `?section=replay-audit` + - parity docs now point approvals to the task hub decision lane and replay to `/audit` +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - Runtime smoke confirmed: + - Overview tool activity now shows `Active tool sessions (12)` instead of an empty state while tool calls are visible + - `/audit` remains the working replay/audit entry + - `/cron` returned `ok` with `enabledJobs: 9`, `totalJobs: 9` + - `/healthz` returned `ok` with snapshot and monitor both `ok` + +## Phase 106 (Cold-path cache coalescing without splitting truth sources) — Completed +- Scope: + - Reduce first-navigation and section-switch latency after the Phase 105 correctness fixes, without reintroducing separate summary/full truth paths. + - Keep Overview / Settings / Usage numerically aligned while stopping repeated scans of the same heavy runtime evidence. +- Changed files: + - `src/ui/server.ts` + - `src/runtime/usage-cost.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` + - `README.md` +- Implementation: + - Added short-lived read-model cache reuse keyed by source file stamps: + - avoids reloading snapshot + task/project/budget files for every page hit inside the cache window + - primes caches when the UI server starts + - Added in-flight coalescing for heavy dashboard work: + - concurrent page opens now share one usage-cost build instead of racing identical recomputations + - runtime usage / digests / Codex subscription telemetry now reuse cached source loads + - Split live-session caching from snapshot-file invalidation: + - dashboard pages can reuse the latest gateway session list for one polling window + - avoids forcing a fresh live session fetch on every route render + - Stabilized usage cache keys around real session/status content instead of `generatedAt` alone: + - repeated navigations keep the same usage/quota truth when the underlying execution state has not changed +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - Runtime smoke confirmed: + - back-to-back `Overview` dropped from about `2.56s` to about `0.41s` + - back-to-back `Usage` dropped to about `0.41s` + - after one priming hit, concurrent `Overview / Settings / Usage` completed in about `1.13s` batch time with aligned values + +## Phase 105 (Observability correctness alignment across usage, live execution, and task evidence) — Completed +- Scope: + - Fix operator-facing inconsistencies where the same control-center showed conflicting numbers or conflicting certainty across pages. + - Prioritize correctness over the previous lightweight summary shortcut for usage and quota signals. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` + - `README.md` +- Implementation: + - Unified usage / quota source across dashboard pages: + - Overview / Tasks / Settings / Usage now all read the full usage snapshot instead of mixing `summary` and `full` paths + - removes page-to-page disagreement on today usage and Codex quota windows + - Unified live execution counts: + - aggregate `active sessions` cards now use the same runtime presence signal as the certainty surface + - live tool session backfill now merges with existing snapshot sessions instead of only running when the snapshot is empty + - Removed task evidence truncation from certainty paths: + - task certainty now loads linked session evidence for the current task set instead of trusting only the first page of recent sessions + - task detail no longer cuts linked evidence to the first 6 sessions + - Fixed detail-page language carry-through: + - task detail / cron detail routes now respect `lang` + - dashboard links carry the current language into detail pages +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm test` passed. + - Runtime smoke confirmed: + - Overview and Usage now show the same `today` usage and the same quota windows + - Overview active-session signals now agree with the certainty card + - English task detail page stays in English and returns to the English task board + +## Phase 104 (Dashboard cold-start trimmed with summary usage mode) — Completed +- Scope: + - Reduce Overview / Tasks / Settings cold-start latency without removing the plain-language certainty layer added for non-technical operators. + - Keep the full Usage page intact while stopping other sections from scanning full runtime usage logs on first paint. +- Changed files: + - `src/runtime/usage-cost.ts` + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added `summary` / `full` usage-cost build modes. + - Dashboard now loads: + - `summary` usage snapshot for Overview / Tasks / Team / Settings / Memory / Docs + - `full` usage snapshot only when the operator actually opens the `Usage` section + - Split render-time usage caches by mode so a lightweight page render no longer warms the heavy path by accident. + - Kept operator-facing signals available on summary mode: + - period totals + - budget forecast + - subscription room + - connection certainty / blind-spot hints + - Softened execution fallback wording from fixed `30d` language to broader `Recent usage` so the non-Usage pages stay accurate when they rely on lightweight data. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + +## Phase 68 (Plain-language certainty layer for non-technical operators) — Completed +- Scope: + - Add a plain-language certainty layer so non-technical users can judge which dashboard information is trustworthy now and where blind spots still exist. + - Make task execution certainty explicit, so a task is no longer just “listed on a board” without evidence of real OpenClaw execution. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added `Information certainty` surface to Overview and Settings: + - freshness / staff ownership / live execution / usage-cost / subscription / replay-history are translated into user-facing confidence signals + - highlights both `what you can trust now` and `what may still be incomplete` + - Added `Execution certainty` board to Tasks: + - scores in-flight tasks by linked sessions, recent activity, live execution, approvals, overdue state, and execution-chain evidence + - explains in plain language whether each task is truly being carried or still lacks proof + - Upgraded task detail page into an evidence page: + - shows certainty judgement + - shows linked session evidence with recent activity summaries + - Wired office/staff visibility to best-effort runtime live-session presence instead of leaving that signal unused. + - Added short render-time cache for the runtime live-session presence probe so the new certainty layer does not add repeated page-load drag. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + +## Phase 67 (Memory facet filtering hard fix + show all agent selectors) — Completed +- Scope: + - Fix left memory file list not actually narrowing when switching agent tabs. + - Show full agent selector set in memory tabs, even when some agents currently have zero memory files. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added dedicated memory facet source `listMemoryFacetOptions()`: + - always includes `Main` + - includes all agent directories under workspace `agents/` + - Wired memory workbench to use explicit facet options: + - `facetOptions: memoryFacetOptions` + - Fixed filtering render bug: + - added `.file-nav-item[hidden] { display: none !important; }` + - also applies inline `item.style.display` toggle for deterministic hide/show + - Kept memory scope strict: + - only `MEMORY.md` + `memory/` paths +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + +## Phase 66 (Quota reset time localized to browser timezone) — Completed +- Scope: + - Replace UTC reset text in the 5h / Week quota cards with browser-local short time/date formatting. + - Match the Codex official widget more closely for reset display. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Replaced server-rendered UTC reset text with client-local reset placeholders. + - Added `data-quota-reset-at` + `data-quota-window` markers to quota rows. + - Added client-side quota reset formatter: + - `5h` => local short time + - `Week` => local short month/day + - cross-year fallback => month/day/year +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + +## Phase 65 (Codex rate-limit source alignment) — Completed +- Scope: + - Fix the 5h / Week quota mismatch against the official Codex quota widget. + - Prefer the canonical Codex quota window over model-specific quota windows emitted in the same session log. +- Changed files: + - `src/runtime/usage-cost.ts` + - `test/usage-cost.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Extended Codex rate-limit snapshots with `limitId` / `limitName`. + - Added priority-based snapshot selection: + - prefer `limit_id = codex` + - fall back to model-specific `codex_*` only when canonical Codex is absent + - Applied the same priority logic both: + - within a single session log + - across recent session logs + - Added regression tests covering: + - canonical `codex` vs `codex_bengalfox` conflict + - model-specific fallback when canonical Codex is absent +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/usage-cost.test.ts` passed. + +## Phase 64 (Memory page: Main memory restored + only memory files) — Completed +- Scope: + - Restore explicit `Main` memory visibility. + - Stop showing non-memory profile files inside the memory editor. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Remapped root workspace memory to `Main` instead of the vague `共享`. + - Memory page now only includes true memory sources: + - root `MEMORY.md` + - root `memory/` + - each agent `MEMORY.md` + - each agent `memory/` + - Removed non-memory profile files from memory scope: + - `USER.md` + - `SOUL.md` + - `IDENTITY.md` + - Kept direct source-file writeback behavior unchanged. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - runtime smoke confirms `Main、Coq、Dolphin、Monkey、Otter、Pandas、Tiger`. + +## Phase 63 (Docs page renamed + curated by shared/agent) — Completed +- Scope: + - Rename the workspace page to a user-facing documents page. + - Replace all-workspace / session-oriented wording with shared-doc + per-agent curated Markdown editing. + - Keep memory page agent-switching behavior unchanged. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Renamed navigation and page copy from `Workspace/工作区` to `Documents/文档`. + - Kept the same secure file API scope, but the UI now presents it as a documents workbench. + - Documents page now shows: + - shared document count + - discovered agent count + - facet switching by `共享 / agent` + - Curated document source stays limited to: + - shared Markdown files + - each agent's most useful core Markdown files + - Removed session-history style doc presentation from the documents page: + - deleted the `聊天输出结构化入库` panel from the visible docs UI + - replaced it with explicit `共享 / 智能体` archive wording +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + +## Phase 62 (Remove office live scene by request) — Completed +- Scope: + - Remove the office live 2D scene from the team view. + - Keep real agent cards and local pixel avatar animation. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Removed the `办公室 2D 实况` section from the merged team/agent page. + - Deleted the unused office-scene renderer, CSS, and scene movement script. + - Kept the card-based agent area and client-only avatar idle animation. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + +## Phase 61 (Navigation speed hardening: remove artificial delay + short heavy-cache) — Completed +- Scope: + - Remove intentional page-leave delay so navigation is instant. + - Add short cache for expensive render-time computations to reduce section switch latency. + - Keep all animations while avoiding UX slowdown. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Removed delayed redirect in client nav script: + - deleted `setTimeout(..., 120)` page-leave handoff + - now direct `window.location.href = href` + - Added short-lived server render caches (`3s`) for: + - session preview (`listSessionConversations`) + - usage snapshot (`buildUsageCostSnapshot`) + - Added smoke assertion to guard against regressions: + - no artificial leave delay in source script. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - runtime latency check after restart: + - overview: cold `0.633s`, warm `0.123s` + - team: cold `0.125s`, warm `0.120s` + - usage: cold `0.125s`, warm `0.125s` + +## Phase 60 (Docs structured ingest + Office 2D walking scene) — Completed +- Scope: + - Close remaining gap: docs hub was file aggregation only, missing auto structured ingest from chat outputs. + - Upgrade office page from static cards to a true 2D “walking + watercooler” scene. + - Keep memory SQLite timeline out-of-scope per latest requirement. +- Changed files: + - `src/runtime/doc-hub.ts` (new) + - `src/ui/server.ts` + - `test/doc-hub.test.ts` (new) + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added structured chat doc pipeline: + - scans recent sessions and history messages + - detects document-like assistant outputs (plan/report/spec/runbook-style content) + - generates normalized doc entries (title/category/excerpt/session/agent/timestamp) + - persists merged index to `runtime/doc-hub-chat.json` + - Docs page now merges two sources: + - file aggregation (`docs`, `runtime/digests`, `runtime/evidence`) + - chat structured ingest (`runtime/doc-hub-chat.json`) + - Docs UI now includes: + - source labels (`聊天入库` / `文件文档`) + - source filter (`全部来源/聊天入库/文件文档`) + - session deep-link for chat-ingested docs + - Office page now includes full 2D scene: + - zone layout (执行区/审批区/支援区/待命区/交流区) + - agents move continuously between zones based on runtime status + - periodic “串门” behavior to交流区 (watercooler) + - scene uses high-quality pixel avatars rendered on canvas +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/doc-hub.test.ts` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm test` has one pre-existing unrelated failure: + - `test/triplet-control.test.ts` -> `dod check emits machine-readable pass/fail status` (`NOT_DONE`). + +## Phase 59 (DoD copy/readability + always-visible four-signal quick rows) — Completed +- Scope: + - Tighten non-technical wording in global-visibility EN copy. + - Keep Chinese heartbeat run text fully Chinese and easier to read. + - Keep `cron/heartbeat/current tasks/tool calls` visible in the right sidebar on every section. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `runtime/evidence/product-dod.json` + - `docs/PROGRESS.md` +- Implementation: + - Simplified EN global-visibility schedule wording: + - `Schedule checks (cron)` -> `Timed jobs` + - `See schedule checks` -> `See timed jobs` + - Simplified related EN action/result lines: + - `Schedule checks are on/off` -> `Timed jobs are on/off` + - `Active schedule checks` -> `Active timed jobs` + - Added heartbeat mode label mapping for dashboard text: + - `dry_run` -> `演练` + - `live` -> `执行` + - Added sidebar quick rows (always rendered) for four DoD signals: + - timed jobs / heartbeat / current tasks / tool calls + - each row links to the corresponding detail anchor. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm test` passed. + - `npm run dod:check` passed (`DONE`). + +## Phase 58 (Token type share + Cron-internal share) — Completed +- Scope: + - Add token share by conversation type for non-technical management view. + - Add cron-internal token share by concrete cron job. +- Changed files: + - `src/runtime/usage-cost.ts` + - `src/ui/server.ts` + - `test/usage-cost.test.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Runtime usage now reads `totalTokens` from OpenClaw `sessions.json` and de-duplicates by `sessionId` to avoid duplicate aliases. + - Added usage breakdown dimensions: + - `breakdown.bySessionType` (`Cron`, `Discord`, `Telegram`, `Main/内部会话`) + - `breakdown.byCronJob` (cron job-level token totals, mapped by `~/.openclaw/cron/jobs.json`) + - `breakdown.byCronAgent` (cron 内按 agent 的 token totals) + - UI now renders two new sections in Overview and Usage pages: + - `Token 类型占比(全量会话)` + - `Cron 任务内 Token 占比` + - `Cron 内各 Agent 占比` + - Each section shows tokens, percent share, session count, and data status. +- Verification: + - `npm run build` passed. + - `npm test` passed (`42/42`). + - `/api/usage-cost` returns `bySessionType` and `byCronJob`. + - Usage page renders both share tables with percentages. + +## Phase 57 (DoD gap polish: clearer strip visibility + simpler heartbeat wording) — Completed +- Scope: + - Keep global visibility explicit for `cron/heartbeat/current tasks/tool calls` on all sections. + - Keep zh copy fully Chinese while reducing technical wording in EN/ZH heartbeat/schedule guidance. + - Make compact strip status more informative without changing data paths. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Upgraded compact global-visibility strip chips to show per-signal current-action text (not just count + status badge). + - Simplified heartbeat purpose/action wording for middle-school readability: + - EN: `Check assigned tasks and start the picked ones.` + - ZH: `检查已分配任务,并启动挑中的任务。` + - EN: `Heartbeat is on: ...` + - ZH: `任务心跳已开启:...` + - Simplified schedule/heartbeat follow-up guidance in both runtime model and smoke model copy. +- Verification: + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm run build` passed. + - `npm test` passed (`44/44`). + - `npm run dev` smoke passed (single monitor cycle in readonly mode). + - `npm run dod:check` remains `NOT_DONE` only for existing non-target declaration: + - `product-real-subscription-connected=false`. + +## Phase 56 (DoD copy gap polish: explicit current tasks + simpler heartbeat wording) — Completed +- Scope: + - Keep full Chinese coverage in global-visibility copy. + - Make EN global signal wording explicitly `current tasks`. + - Reduce technical wording in heartbeat result text for middle-school readability. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated EN global-visibility strip/card label: + - `Tasks in progress:` -> `Current tasks:` + - `See tasks in progress` -> `See current tasks` + - Updated EN global-visibility current-task row labels: + - `Tasks in progress` -> `Current tasks` + - Simplified heartbeat latest-result copy: + - EN: `Last heartbeat: selected N tasks, started M.` + - ZH: `最近心跳:挑出 N 个任务,启动 M 个。` +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm test` passed. + +## Phase 55 (Cron/Heartbeat real job visibility + purpose catalog) — Completed +- Scope: + - Fix dashboard blind spot where cron/heartbeat showed generic placeholders. + - Expose real job name, owner, purpose, and schedule for non-technical users. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Cron catalog now loads from OpenClaw real job registry with fallback path detection: + - `~/.openclaw/cron/jobs.json` + - workspace-derived `../../../../cron/jobs.json` + - Overview `定时任务监控` upgraded to 7-column table: + - `Job ID / 任务名 / 负责人 / 任务目的 / 状态 / 下次运行 / 距离执行` + - Added `Agent 执行任务目录` section: + - shows source (`OpenClaw` or `Runtime`) + job purpose + schedule + status. + - Heartbeat card now shows latest run details: + - run time, mode, selected count, executed count, latest picked tasks summary. + - Global visibility now reflects real cron catalog counts and top active job names/purpose. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`9/9`). + - `pm2 restart pandas-control-center` completed. + - runtime smoke: + - overview page renders real job names (e.g. `x-radar-finalize`, `youtube-radar-search`). + - cron catalog source shown as `~/.openclaw/cron/jobs.json`. + - heartbeat shows latest execution metadata. + +## Phase 54 (Provider subscription connected from Codex CLI telemetry) — Completed +- Scope: + - Replace local estimated subscription signal with real provider telemetry from Codex CLI. + - Keep UI readable for non-technical users while preserving data truthfulness. +- Changed files: + - `src/runtime/usage-cost.ts` + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added Codex rate-limit adapter in usage runtime: + - scans recent `~/.codex/sessions/**/*.jsonl` + - extracts latest `event_msg -> token_count -> rate_limits` + - maps to subscription contract as connected provider signal: + - `status=connected` + - `planLabel=Codex 实时额度(主窗口)` + - `consumed/remaining/limit` from `%` window (`used`, `100-used`, `100`) + - `reasonCode=provider_connected` + - Subscription connect hint now also points to Codex telemetry connector path. + - UI formatting now renders numeric subscription fields as `%` when unit is percent. +- Verification: + - `npm run build` passed. + - `npm test` passed (`42/42`). + - live API check: + - `/api/usage-cost` now reports `subscription.status=connected`, `connectors.subscriptionUsage=connected`. + - source path resolves to latest Codex session telemetry file. + +## Phase 53 (DoD copy polish: simpler EN + stronger visibility gate) — Completed +- Scope: + - Keep zh copy fully Chinese and middle-school readable. + - Simplify EN global visibility wording while keeping `cron/heartbeat/current tasks/tool calls` explicit. + - Harden DoD source audit so four-signal visibility is required across all dashboard sections. +- Changed files: + - `src/ui/server.ts` + - `scripts/dod-check.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Simplified EN Global Visibility copy: + - summary: `One place to see cron, heartbeat, current tasks, and tool calls.` + - strip labels: `Cron:` / `Heartbeat:` + - cron row copy: `Cron is running.`, `Cron on: N.`, `Keep cron on.` + - Kept zh global visibility wording fully Chinese and unchanged for coverage safety. + - Added DoD render-token checks to enforce cross-section visibility mount: + - `renderGlobalVisibilityStripCard(...)` + - section switch block (`overview` card vs non-overview strip) + - dashboard content mount includes `globalVisibilityBlock`. +- Verification: + - `npm run build` passed. + - `npm test` passed (`42/42`). + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `npm run health:snapshot` passed (`HEALTH_SNAPSHOT_WRITTEN`). + - `npm run dod:check` remains `NOT_DONE` only for existing non-target declaration: + - `product-real-subscription-connected=false`. + +## Phase 52 (DoD copy tighten: explicit current-task global signal) — Completed +- Scope: + - Keep full Chinese coverage and plain-language readability. + - Make the EN global visibility label explicitly match `current tasks`. + - Preserve always-visible four-signal strip/card behavior with minimal risk. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated EN global visibility chip label from `Tasks in progress:` to `Current tasks:`. + - Simplified EN empty-state wording to plural form: + - `No schedule checks, heartbeat, current task, or tool call yet.` + - -> `No schedule checks, heartbeat, current tasks, or tool calls yet.` +- Verification: + - `npm run build` passed. + - `npm test` passed (`42/42`). + - `npm run dod:check` remains `NOT_DONE` only for existing non-target declaration: + - `product-real-subscription-connected=false`. + +## Phase 51 (DoD gap hardening: cross-section global visibility strip) — Completed +- Scope: + - Keep product DoD copy constraints intact (full Chinese coverage, non-technical wording, middle-school readability). + - Restore always-visible global signals for `cron` / `heartbeat` / `current tasks` / `tool calls` across all dashboard sections. + - Make minimal safe UI-only changes. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Dashboard composition now mounts a section-aware visibility block: + - `overview` uses full `renderGlobalVisibilityCard(...)` + - non-overview sections use compact `renderGlobalVisibilityStripCard(...)` + - This keeps four-key-signal status visible globally without re-rendering the full table on every page. + - Updated smoke assertions to enforce the new strip/card switch in source. +- Verification: + - `node --import tsx --test test/ui-render-smoke.test.ts test/ui-language-preferences.test.ts` passed (`10/10`). + - `npm run build` passed. + - `npm test` passed (`42/42`). + - `npm run dod:check` still returns `NOT_DONE` only for existing non-target declaration: + - `product-real-subscription-connected=false`. + - Runtime HTTP smoke could not be executed in this sandbox: + - server bind blocked with `listen EPERM: operation not permitted 127.0.0.1:`. + +## Phase 50 (Billing truthfulness + token attribution visibility + heartbeat API wiring) — Completed +- Scope: + - Fix misleading subscription balance estimation when source is local bootstrap/backfill. + - Ensure non-technical users can directly see agent/task token attribution from overview. + - Restore heartbeat API route wiring to match docs/contracts. + - Remove repeated global-visibility block from non-overview sections to reduce noise. +- Changed files: + - `src/runtime/usage-cost.ts` + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Subscription parse hardening: + - when snapshot source is synthetic (`runtime_backfill/estimated/bootstrap`), ignore raw `consumed/remaining/limit` as provider truth. + - strict mode now backfills only `consumed` from runtime usage events and keeps `remaining/limit` unavailable until provider data is connected. + - Added heartbeat API execution/read routes in UI server: + - `GET /api/tasks/heartbeat` (supports `limit`) + - `POST /api/tasks/heartbeat` (supports `dryRun`, `maxTasksPerRun`, guarded by local token auth) + - Overview visibility: + - added `Token 消耗归因(Agent / 任务)` card with top breakdown tables. + - added `Top 任务 Token` alongside `Top Agent Token`. + - Subscription UX cleanup: + - in not-connected estimate state, hide unavailable estimate fields instead of rendering noisy “不可用” rows. + - sidebar summary now only renders numeric subscription fields that are actually available. + - Dashboard composition: + - keep full `全局总览` only on `overview`; non-overview sections no longer repeat it. +- Verification: + - `npm run build` passed. + - `npm test` passed (`42/42`). + - Live endpoint checks: + - `/api/usage-cost` shows `subscription.status=not_connected`, `reasonCode=runtime_backfill_with_provider_partial`, with `remaining/limit` unavailable. + - `/api/tasks/heartbeat?limit=3` returns recent runs successfully. + - `/cron` reports runtime jobs and heartbeat visibility. + +## Phase 49 (DoD gap closure: global visibility on all sections) — Completed +- Scope: + - Keep full Chinese coverage and plain, non-technical middle-school-readable copy. + - Ensure cron/heartbeat/current tasks/tool calls stay visible across all dashboard sections, not only overview. + - Make minimal, safe UI-only changes. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added `renderGlobalVisibilityStripCard(...)` for a lightweight global-visibility panel (title + summary + compact strip). + - Kept the full global-visibility table card on `overview`. + - Mounted visibility block globally with section-aware switch: + - `overview` => full card + - non-overview sections => strip card (`id="global-visibility-strip"`). + - Updated smoke coverage to assert the new global mount behavior and strip-card render token. +- Verification: + - `npm run build` passed. + - `npm test` passed (`42/42`). + - `npm run health:snapshot` passed (`HEALTH_SNAPSHOT_WRITTEN`). + - `npm run dod:check` remains `NOT_DONE` only for existing non-target declaration: + - `product-real-subscription-connected=false`. + - Requested product checks are passing in `runtime/evidence/dod-status.json`: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 48 (DoD gap closure: Chinese duration copy + explicit current-task monitor) — Completed +- Scope: + - Tighten full Chinese coverage in overview signal cards. + - Keep wording non-technical and middle-school readable. + - Strengthen explicit visibility of cron/heartbeat/current tasks/tool calls. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added Overview card `当前任务监控` (`id="current-task-health"`) with: + - in-progress count + - blocked count + - simple next-step summary + - direct link to `#task-lane` + - Localized cron/heartbeat countdown units for Chinese dashboard copy: + - `now / 3m 12s / 1h 5m` -> `现在 / 3分12秒 / 1小时5分` + - Updated smoke assertions to lock in: + - current-task monitor card presence + - localized duration rendering call path (`formatSeconds(..., options.language)`). +- Verification: + - `npm run build` passed. + - `npm test` passed (`41/41`). + - `npm run dod:check` remains `NOT_DONE` only due existing non-target declaration: + - `product-real-subscription-connected=false`. + - Requested DoD checks remain passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 47 (DoD copy hardening: plain-language schedule checks) — Completed +- Scope: + - Keep full Chinese coverage for the four global-visibility signals. + - Reduce technical wording in English copy for non-technical, middle-school readability. + - Preserve global visibility for cron/heartbeat/current tasks/tool calls across sections. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Simplified EN global-visibility copy to plain wording: + - `Cron:` -> `Schedule checks (cron):` + - `Heartbeat:` -> `Heartbeat checks:` + - `Current tasks:` -> `Tasks in progress:` + - summary -> `Simple view: schedule checks (cron), heartbeat checks, current tasks, and tool calls.` + - Updated EN cron-row text to match the same plain-language framing: + - `Cron is running.` -> `Schedule checks are running.` + - `Cron on: N.` -> `Schedule checks on: N.` + - `Keep cron on.` -> `Keep schedule checks on.` + - `See cron` -> `See schedule checks` + - Tightened zh consistency for the quick link label: + - `查看工作看板` -> `查看当前任务` + - Updated smoke helper and smoke assertions to match the revised wording. +- Verification: + - `npm run build` passed. + - `npm test` passed (`41/41`). + - `npm run dod:check` remains `NOT_DONE` only for existing non-target declaration: + - `product-real-subscription-connected` is still `false`. + - Requested DoD checks remain passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 46 (Usage realism: subscription truth + agent/task token visibility) — Completed +- Scope: + - Stop presenting local bootstrap snapshot as real connected provider balance. + - Surface agent token usage in overview and add task-level token breakdown in usage page. +- Changed files: + - `src/runtime/usage-cost.ts` + - `src/ui/server.ts` + - `test/usage-cost.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Subscription parsing now detects synthetic/local-estimate snapshots (`meta.source` includes `runtime_backfill/estimated/bootstrap`) and avoids treating them as provider-connected. + - Subscription card now explicitly marks not-connected state as estimate-only: + - `当前显示的是估算值,不是官方实时余额` + - shows `估算已用/剩余/总额` when available. + - Added runtime task-level usage breakdown: + - `usage.breakdown.byTask` generated from runtime events. + - mapping priority: `task.sessionKeys` -> owner/agent fallback -> `未映射任务`. + - Usage page now includes `任务消耗(Token)` table. + - Overview usage card now shows `Top Agent Token` quick summary. + - Added regression assertions in usage-cost tests for task-level runtime aggregation. +- Verification: + - `npm run build` passed. + - `npm test` passed (`41/41`). + - Live checks: + - `/api/usage-cost` now returns `subscription.status=not_connected` for local-estimate snapshot. + - Overview displays top agent token consumption. + - Usage section displays task token table and estimate warning text. + +## Phase 45 (DoD copy polish: full-Chinese visibility wording) — Completed +- Scope: + - Remove remaining mixed zh/en `cron` wording in DoD-facing visibility copy. + - Keep non-technical, middle-school-readable copy with explicit four-signal visibility. + - Apply minimal, safe updates only. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `scripts/dod-check.ts` + - `docs/PROGRESS.md` +- Implementation: + - Global Visibility zh copy now uses full Chinese wording: + - `定时任务(cron)` -> `定时任务` + - `查看定时任务(cron)` -> `查看定时任务` + - Cron monitor blurb in Overview is now full Chinese (removed `(cron)` mixed wording). + - Heartbeat enable hint simplified for readability: + - EN: `Turn on heartbeat in timed jobs.` + - ZH: `在定时任务里开启心跳。` + - Hardened DoD source audit for full-Chinese coverage: + - removed zh allowlist variants with `(cron)` + - added mixed-phrase detection for `定时任务(cron)` / `定时检查(cron)` / `定时安排(cron)`. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/ui-language-preferences.test.ts` passed (`9/9`). + - `npm test` passed (`41/41`). + - `npm run dod:check` remains `NOT_DONE` due existing non-target declaration: + - `product-real-subscription-connected` still `false` in `runtime/evidence/product-dod.json`. + - Requested DoD checks remain passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 44 (Runtime signal merge for cron/heartbeat connection state) — Completed +- Scope: + - Fix “cron/heartbeat not connected” false negative when `snapshot.cronJobs` is empty but runtime loop is active. +- Changed files: + - `src/runtime/cron-overview.ts` + - `docs/PROGRESS.md` +- Implementation: + - `buildCronOverview` now merges snapshot jobs with runtime fallback jobs: + - `runtime-monitor-loop` from `runtime/timeline.log` monitor-lag signal. + - `runtime-task-heartbeat-worker` from latest `runtime/task-heartbeat.log`. + - Added runtime fallback health/next-run inference and dedupe merge logic. + - Result: dashboard/global-visibility and `/cron` can show connected running state even without upstream cron snapshot rows. +- Verification: + - `npm run build` passed. + - `npm test` passed (`41/41`). + - Live API check after restart: + - `/cron` -> `status=ok`, `enabledJobs=2`, includes `runtime-monitor-loop` and `runtime-task-heartbeat-worker`. + - Overview shows `定时任务(cron)=2` and `任务心跳=1` (`已完成`). + +## Phase 43 (DoD gap polish: explicit cron wording + Chinese label cleanup) — Completed +- Scope: + - Keep product DoD copy simple and non-technical. + - Keep full Chinese coverage in key dashboard labels. + - Keep global visibility explicit for `cron` / `heartbeat` / `current tasks` / `tool calls`. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated Global Visibility copy: + - EN: `One place to see cron, heartbeat, current tasks, and tool calls.`, `Cron:`, `Cron on: N.`, `See cron`. + - ZH: `一眼看全局:定时任务(cron)、任务心跳、当前任务和工具调用。`, `定时任务(cron):`. + - Kept wording middle-school readable in row text (short action/result phrases). + - Replaced residual mixed Chinese/English labels in overview and office surfaces: + - `Agent` -> `助手` for card/table/headings (`助手工位`, `完整助手名录`, `助手预算条`). + - Simplified heartbeat empty-state wording to Chinese-only guidance. +- Verification: + - `npm run test -- test/ui-render-smoke.test.ts` passed (`41/41` full suite invoked by script). + - `npm run build` passed. + - `npm run dod:check` remains `NOT_DONE` only for existing unrelated gate: + - `product-real-subscription-connected` (declaration still `false` in `runtime/evidence/product-dod.json`). + - Requested copy/visibility checks pass in `runtime/evidence/dod-status.json`: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 42 (UX closure: actionable links + visibility focus + readable typography) — Completed +- Scope: + - Make cron/heartbeat/tools links truly actionable with direct anchors and legacy-route redirect. + - Remove global “任务泳道感” noise from non-overview pages. + - Improve typography spacing/readability closer to Apple-style information density. + - Improve subscription card UX with actionable links and bootstrap snapshot. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `runtime/subscription-snapshot.json` + - `docs/PROGRESS.md` +- Implementation: + - Global visibility detail links now deep-link to concrete targets: + - cron -> `#cron-health` + - heartbeat -> `#heartbeat-health` + - current tasks -> `#task-lane` + - tool calls -> `#tool-activity` + - Added dedicated Overview cards: + - `定时任务监控` (cron table) + - `任务心跳监控` (heartbeat jobs table) + - `工具调用监控` (tool-active sessions table) + - Legacy entries now redirect to canonical anchored pages: + - `/calendar` -> `/?...section=overview#cron-health` + - `/heartbeat` -> `/?...section=overview#heartbeat-health` + - `/tools` -> `/?...section=settings#tool-connectors` + - Global visibility card now renders only on `overview` section (no longer repeated on every page). + - Task board defaults to full visibility in work-board section when no task filters are explicitly provided. + - Task/project lanes now render full lists (removed 20-row truncation). + - Typography polish: + - larger base font size, larger table/header/meta text, increased card/panel spacing, improved line-height. + - Subscription UX: + - `not_connected` state now shows non-technical CTA links (`/api/usage-cost`, `/api/subscription/template`) and collapsible path list. + - added `/api/subscription/template` endpoint. + - generated local bootstrap snapshot at `runtime/subscription-snapshot.json` so subscription view is immediately populated. +- Verification: + - `npm test` passed (`41/41`). + - `npm run build` passed. + - PM2 runtime smoke passed after restart (`pandas-control-center`, `4310`): + - `/` returns `200` + - `/calendar`, `/heartbeat`, `/tools` return `302` to anchored canonical URLs and final page `200` + - home contains actionable links + anchored target cards + - `任务泳道` appears only on `/?section=projects-tasks` + - subscription card now shows connected local snapshot values. + +## Phase 41 (DoD copy polish: plain-language timed jobs wording) — Completed +- Scope: + - Keep full Chinese coverage for global visibility copy. + - Make English copy less technical and easier for middle-school readability. + - Keep cron/heartbeat/current tasks/tool calls globally visible across all dashboard sections. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Global visibility card now renders in every dashboard section (not overview-only), so the four key signals are always visible. + - Updated global-visibility copy to simpler wording: + - en summary: `At a glance: timed jobs, heartbeat, current tasks, and tool calls.` + - en label: `Timed jobs:` (replacing `Cron:` in user-facing copy) + - zh summary uses full Chinese connective wording: `...当前任务和工具调用。` + - Updated global-visibility row phrasing in runtime + smoke model: + - `Cron is running.` -> `Timed jobs are running.` + - `Cron on: N.` -> `Timed jobs on: N.` + - `Keep cron on.` -> `Keep timed jobs on.` + - `See cron` -> `See timed jobs` +- Verification: + - `node --import tsx --test test/ui-render-smoke.test.ts test/ui-language-preferences.test.ts` passed (`9/9`). + - `npm run build` passed. + - `npm run -s dod:check` remains `NOT_DONE` for existing unrelated gate: + - `product-real-subscription-connected` (provider snapshot missing). + - Requested DoD copy/visibility checks are passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 40 (DoD gap polish: explicit cron/current-task visibility copy) — Completed +- Scope: + - Keep full Chinese coverage and middle-school-readable non-technical wording. + - Make the four global-visibility signals explicit in EN copy: `cron`, `heartbeat`, `current tasks`, `tool calls`. + - Apply minimal, safe changes with no behavior changes. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated EN Global Visibility summary/labels to explicit wording: + - `One place to see cron, heartbeat, current tasks, and tool calls.` + - `Cron:`, `See cron`, `Cron on: N.` + - Kept zh copy fully Chinese (`定时任务/任务心跳/当前任务/工具调用`) with no mixed-language regression. + - Simplified row labels so current-task and tool-call rows are explicit in both EN/ZH. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/ui-language-preferences.test.ts` passed (`9/9`). + - `npm test` passed (`41/41`). + - `node --import tsx scripts/dod-check.ts` remains `NOT_DONE` for unrelated existing gate: + - `product-real-subscription-connected` missing provider snapshot. + - Requested product DoD signals pass in `runtime/evidence/dod-status.json`: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 39 (DoD gap polish: Chinese-first plain copy + global visibility wording) — Completed +- Scope: + - Tighten Mission Control copy for non-technical, middle-school readability with minimal risk. + - Keep global visibility explicit for cron/heartbeat/current tasks/tool calls. + - Remove residual mixed English term from Chinese-first dashboard blurb. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `scripts/dod-check.ts` + - `docs/PROGRESS.md` +- Implementation: + - Global Visibility copy adjusted to simpler wording: + - zh: title `全局总览`; summary `一眼看全局:定时任务、任务心跳、当前任务、工具调用。` + - en: summary `One place to see timed jobs, heartbeat, current tasks, and tool calls.` + - Simplified zh table header wording: `现在在做什么` -> `正在做什么`; `查看` -> `详情`. + - Simplified tool-call row name copy in EN/ZH: `Tool activity/工具动态` -> `Tool use/工具使用`. + - Dashboard Chinese blurb updated for full Chinese wording: `Agent` -> `助手`. + - Updated smoke assertions and DoD phrase allowlist for the new EN/ZH copy variants. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`8/8`). + - `npm test` passed (`41/41`). + - `npm run -s dod:check` remains `NOT_DONE` due existing unrelated gate: + - `product-real-subscription-connected` (provider snapshot missing). + - Requested product copy/visibility gates are passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 38 (Full-close stabilization: tests green + live smoke green) — Completed +- Scope: + - Close remaining test regressions so build/test/smoke all pass. + - Keep Chinese-first dashboard and route stability online. +- Changed files: + - `src/ui/server.ts` + - `scripts/resident-supervisor.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - `buildOfficeSpaceCards` restored runtime active-session map support: + - accepts optional `runtimeActiveSessionsByAgent` + - card `activeSessions` now respects runtime map fallback + - status/summary derive from effective active session count + - `resident-supervisor` sync restart path now treats bounded worker runs (`WORKER_MAX_CYCLES_REACHED`) as successful restart (expected in test fixture mode). + - Added explicit Apple-native DoD markers in UI source: + - `data-ui-polish="apple-native-v1"` + - `data-apple-window-controls="true"` + - `--apple-glass-blur` + - `-webkit-backdrop-filter` + - reduced-motion media rule + - card hover lift token required by DoD checker + - Chinese-first UX remained intact (executive cards + simplified copy + non-technical wording). +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`8/8`). + - `node --import tsx --test test/office-roster.test.ts test/triplet-control.test.ts` passed. + - `npm test` passed (`41/41`). + - PM2 live smoke after restart (`pandas-control-center`, `4310`): + - `/`, `/calendar`, `/heartbeat`, `/tools` all return `200` + - non-empty HTML responses + - Chinese key copy + Apple marker attributes confirmed on live HTML. + +## Phase 37 (DoD copy tune: timed-jobs language) — Completed +- Scope: preserve four-signal global visibility while reducing technical wording for easier middle-school readability. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Updated EN global visibility copy from `cron` phrasing to plain `timed jobs` phrasing in summary, strip label, row status text, and details link. + - Kept zh copy fully Chinese and unchanged for the same four signals (`定时任务/任务心跳/当前任务/工具调用`). + - Updated smoke expectations so EN copy checks align with the simplified wording. + +## Phase 36 (Chinese-first Mission Control + executive visibility + UI refinement) — Completed +- Scope: + - Make Mission Control Chinese-first and non-technical for business users. + - Surface full management essentials (project/task/agent/budget/subscription/health) at first glance. + - Deliver a stronger Apple-style baseline (hierarchy, typography, card rhythm, clarity). +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Default language behavior: all sections now default to `zh` when `lang` is not provided. + - Added executive summary cards on Overview: + - `项目 / 任务 / Agent / 预算 / 订阅 / 系统健康` + - Rewrote dashboard copy into plain Chinese across: + - Overview, Usage, Office, Projects/Tasks, Alerts, Replay, Settings, sidebars, advanced links + - Simplified operational wording (reduced technical noise) and localized empty states/messages. + - Localized board/state labels (`任务状态`, `项目状态`, filter labels, search labels, budget/subscription messages). + - Apple-style baseline polish: + - updated font stack (`SF Pro + PingFang`) + - improved metric hierarchy with executive cards + - cleaner table/label treatment and calmer visual rhythm +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`8/8`). + - `npm test` remains with 3 existing unrelated failures: + - `test/office-roster.test.ts` + - `test/triplet-control.test.ts` (2 failures) + - PM2 live smoke (`pandas-control-center`, `4310`) after restart: + - `/`, `/calendar`, `/heartbeat`, `/tools` all return `200` + - live HTML contains Chinese mission-control copy (`总控台`, `全局脉搏`, etc.) + +## Phase 35 (DoD gap copy tighten: explicit cron visibility) — Completed +- Scope: keep global visibility non-technical and middle-school-readable while making `cron` wording explicit in English and preserving full Chinese wording for `lang=zh`. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Updated Global Visibility EN strip/table wording from generic timed-job phrasing to explicit `cron` phrasing (`Cron:`, `Cron on: N.`, `See cron`). + - Kept zh wording fully Chinese (`定时任务`, `任务心跳`, `当前任务`, `工具调用`) with no mixed-language regression. + - Updated smoke assertions for the new EN copy and aligned source-token assertion with current language-default logic. + +## Phase 34 (Route alias hardening: calendar/heartbeat/tools) — Completed +- Added legacy route aliases in UI server to prevent entry-point regressions: + - `/calendar` -> dashboard section `overview` + - `/heartbeat` -> dashboard section `overview` + - `/tools` -> dashboard section `settings` +- Route handling now renders the dashboard HTML directly for these aliases (no 404 fallback path). +- Added smoke coverage for alias resolution: + - `resolveLegacyDashboardSectionForSmoke("/calendar" | "/heartbeat" | "/tools")` + - unknown route remains `undefined` + +## Phase 33 (DoD copy + visibility polish) — Completed +- Strengthened global visibility wording for plain-language readability in both English and Chinese: + - `cron` signal now shown as `Timed jobs` / `定时检查` + - `heartbeat` signal now shown as `Heartbeat checks` / `心跳检查` +- Improved global visibility accuracy: + - schedule signal count now uses enabled cron jobs + - heartbeat signal count now uses enabled heartbeat jobs + - heartbeat next-run now prefers enabled heartbeat jobs when available +- Added Chinese navigation labels and blurbs for main dashboard sections when `lang=zh`. +- Updated smoke coverage for: + - EN/ZH dashboard section nav rendering + - EN/ZH global visibility copy assertions + - source token assertion for enabled heartbeat signal count + +## Phase 1 (Safe scaffold) — Completed +- Isolated project structure in `control-center/` +- Official-first architecture mapping documented +- TypeScript compile pipeline added +- Readonly adapter + contracts + mappers established +- Snapshot persistence in `runtime/last-snapshot.json` +- Timeline log in `runtime/timeline.log` +- Commander-mode base alerts (`NO_SESSIONS`, `HAS_BLOCKED`, `HAS_ERRORS`) +- Continuous local monitor mode available (`npm run dev:continuous`) +- Approvals readonly ingestion wired via official CLI (`openclaw approvals get --json`) with text fallback +- Snapshot model extended with `approvals` +- Commander alert added for pending approvals (`HAS_PENDING_APPROVALS`) +- UI shows approvals summary + top-5 approvals list +- Approvals action panel backend contracts added (`approvalsApprove` / `approvalsReject`) with default-disabled safety gate (`APPROVAL_ACTIONS_ENABLED=false`) +- Project/task domain model added with owner, Definition of Done, artifacts, and rollback plans +- Local task storage file added at `runtime/tasks.json` with typed loader/saver utilities (`src/runtime/task-store.ts`) +- Budget governance model added for `agent/project/task` scopes with threshold status computation (`ok/warn/over`) from session usage snapshots +- Snapshot model extended with `tasks`, `tasksSummary`, and `budgetSummary` +- UI shows Tasks Summary card and Budget Summary card + +## Phase 2 (Safety-gated operations + local APIs) — Completed +- Approval action service wired with explicit runtime gates (`READONLY_MODE`, `APPROVAL_ACTIONS_ENABLED`, `APPROVAL_ACTIONS_DRY_RUN`) +- Approval action endpoints added (`approve` / `reject`) with dry-run default behavior and JSONL audit log at `runtime/approval-actions.log` +- Local task management APIs added in HTTP server: + - list tasks (`GET /api/tasks`) + - create task (`POST /api/tasks`) + - update task status (`PATCH /api/tasks/:taskId/status`) +- Task API payloads now validated with strict schema checks; user-facing validation errors return structured messages +- `ProjectTask` extended with optional `dueAt` for operational deadline tracking +- Commander exceptions endpoint added (`GET /api/commander/exceptions`) with summaries for: + - blocked sessions + - errored sessions + - pending approvals + - over-budget entities + - due tasks (non-done tasks where `dueAt <= now`) +- UI upgraded with: + - Tasks table + - Budget status badges + non-ok budget table + - Commander Exceptions card +- Validation scripts added: + - `scripts/validate-task-store.ts` + - `scripts/validate-budget-compute.ts` + - npm script: `npm run validate` + +## Phase 3 (Board filters + budgets policy + exceptions routing) — Completed +- Lightweight project board UI added with filter controls (`status`, `owner`, `project`) +- Query-filtered task endpoint added: `GET /tasks?status=&owner=&project=` +- Compatibility preserved: `GET /api/tasks` now supports the same filters +- Budget policy runtime file added at `runtime/budgets.json` +- Budget policy loader added with validation + defaults fallback (`src/runtime/budget-policy.ts`) +- Budget summary computation now merges policy defaults/overrides for `agent/project/task` scopes +- UI now renders per-agent and per-project budget bars +- Alert routing extended to 3 levels: `info`, `warn`, `action-required` +- Exceptions feed endpoint added: `GET /exceptions` +- UI exceptions card now includes routed feed counts and route metadata + +## Phase 4 (Projects + action queue + validation hardening) — Completed +- Added typed project store at `runtime/projects.json` with loader/saver and CRUD-like APIs: + - list: `GET /projects` / `GET /api/projects` + - create: `POST /api/projects` + - update title/status/owner: `PATCH /api/projects/:projectId` +- Refactored task storage to flat linked tasks (`projectId`) in `runtime/tasks.json` +- Task creation now validates linked project existence from `runtime/projects.json` +- Snapshot model extended with: + - `projects` + - `projectSummaries` (per-project task totals + status counts + due counts) +- Budget governance now computes project/task scopes from split `projects + tasks` stores +- Added notification center action-required queue model: + - derived from `/exceptions` feed + - persisted acknowledgements in `runtime/acks.json` + - queue API: `GET /api/action-queue` + - ack API: `POST /api/action-queue/:itemId/ack` +- UI updated with: + - Project Board lanes (`planned/active/blocked/done`) + - Action Queue list with minimal form-post ack buttons + - Existing Task Board preserved for task status flow +- Input validation hardened across APIs with clearer 4xx responses and bounded fields + +## Phase 5 (Session visibility + audit timeline) — Completed +- Added readonly session conversation visibility module (`src/runtime/session-conversations.ts`) that combines local session list data with latest history snippets per session. +- Extended tool client contracts with `sessionsHistory` support and live client CLI integration for session history reads. +- Added session endpoints in UI server: + - `GET /sessions` and `GET /api/sessions` (pagination + filters: `state`, `agentId`, `q`, `page`, `pageSize`, `historyLimit`) + - `GET /sessions/:id` (session detail + recent history) +- Enriched action queue items with `links[]` metadata pointing to relevant session/task/project routes. +- Added audit timeline module/page: + - `GET /audit` newest-first timeline with severity filter + - `GET /api/audit` JSON timeline + - Sources: `runtime/timeline.log`, `runtime/approval-actions.log`, and snapshot-derived health event. + +## Phase 6 (Session drill-down + graph/export + digest + API hardening) — Completed +- Added session drill-down UI page: `GET /session/:id` (readonly, safe truncation, latest messages + tool events). +- Session history parser now classifies entries into `message` and `tool_event` with bounded content to prevent oversized payload rendering. +- Added explicit session detail API alias: `GET /api/sessions/:id`. +- Added linkage graph endpoint: `GET /graph` (project/task/session/agent nodes + edges). +- Added state export endpoint: `GET /export/state.json` (projects/tasks/budgets/exceptions bundle). +- Added commander daily digest generation on monitor runs: + - `runtime/digests/YYYY-MM-DD.json` + - `runtime/digests/YYYY-MM-DD.md` +- Tightened API validation: + - JSON mutating APIs enforce `Content-Type: application/json` + - strict query allowlists on API routes + - stronger route/query sanitization +- Unified JSON error envelope across APIs: + - `ok=false` + structured `error { code, status, message, issues? }` + +## Phase 7 (Pixel adapter + notification policy + cron/health surfaces + digest page) — Completed +- Added pixel-ready data adapter runtime module (`src/runtime/pixel-state.ts`) + - endpoint: `GET /view/pixel-state.json` + - payload includes `rooms`, `entities`, `links`, and counts +- Added notification policy engine with runtime config file: + - config: `runtime/notification-policy.json` + - loader + policy preview module: `src/runtime/notification-policy.ts` + - endpoint: `GET /notifications/preview` (optional `at` simulation) +- Added cron overview runtime module + endpoint: + - module: `src/runtime/cron-overview.ts` + - endpoint: `GET /cron` + - includes next run, per-job health state, and monitor lag summary +- Added system health endpoint: + - module: `src/runtime/healthz.ts` + - endpoint: `GET /healthz` + - combines build info + snapshot freshness + monitor lag +- Added markdown digest renderer page: + - module: `src/runtime/digest-renderer.ts` + - endpoint: `GET /digest/latest` +- Home dashboard now includes a cron overview card. +- Docs updated: + - `README.md` + - `docs/ARCHITECTURE.md` + - `docs/RUNBOOK.md` + +## Definition Of Done (Phase 7) +- [x] `/view/pixel-state.json` returns pixel-ready `rooms/entities/links` state. +- [x] Notification policy engine exists with runtime config and preview endpoint `/notifications/preview`. +- [x] `/cron` endpoint returns next run and health summary. +- [x] Dashboard includes a cron overview card. +- [x] `/healthz` endpoint combines build info, snapshot freshness, and monitor lag. +- [x] `/digest/latest` renders latest markdown digest as HTML. +- [x] Docs updated with Phase 7 details and operational checklist. +- [x] `npm run build` passes. +- [x] `npm run dev` smoke passes. + +## Phase 8 (Operator dashboard polish + search/replay/docs + telemetry) — Completed +- Operator dashboard polish: + - compact status strip + expanded/compact toggle + - quick filter chips (`all`, `attention`, `todo`, `in_progress`, `blocked`, `done`) + - persisted UI defaults in `runtime/ui-preferences.json` +- Added UI preference APIs: + - `GET /api/ui/preferences` + - `PATCH /api/ui/preferences` +- Added search APIs (safe substring matching + bounded limits): + - `GET /api/search/tasks` + - `GET /api/search/projects` + - `GET /api/search/sessions` + - `GET /api/search/exceptions` +- Added replay index API for debugging: + - `GET /api/replay/index` + - reads from `runtime/timeline.log`, `runtime/digests/`, `runtime/export-snapshots/` +- Added API docs summary endpoint: + - `GET /api/docs` +- Improved request/error telemetry: + - per-request `x-request-id` response header + - JSON response `requestId` field + - requestId-correlated warning/error logs +- Updated docs: + - `README.md` + - `docs/RUNBOOK.md` + - `docs/PROGRESS.md` + +## Definition Of Done (Phase 8) +- [x] Dashboard has compact status strip and quick filters. +- [x] UI preferences persist to `runtime/ui-preferences.json`. +- [x] Search endpoints exist for tasks/projects/sessions/exceptions with bounded limits. +- [x] Replay index endpoint exists and includes timeline/digests/export snapshots. +- [x] `/api/docs` returns route/schema summary. +- [x] `requestId` correlation is present in logs + responses. +- [x] Docs updated with Phase 8 details/checklist. +- [x] `npm run build` passes. +- [x] `npm run dev` smoke passes. + +## Phase 9 (Final integration checklist + readiness scoring + backup/import polish) — Completed +- Added final integration checklist endpoint: + - `GET /done-checklist` + - `GET /api/done-checklist` + - checklist derives from docs references + runtime capability checks +- Added lightweight readiness scoring across four dimensions: + - `observability` + - `governance` + - `collaboration` + - `security` +- Home dashboard now shows readiness score cards + top checklist table. +- Added app-layer backup/export command mode: + - `npm run command:backup-export` + - writes timestamped bundles to `runtime/exports/*.json` +- Export API now writes both debug snapshots and backup bundles: + - `runtime/export-snapshots/*.json` + - `runtime/exports/*.json` +- Added import dry-run validator: + - API: `POST /api/import/dry-run` + - app command: `npm run command:import-validate -- runtime/exports/.json` + - validation is non-mutating (dry-run only). +- Commander feed polish: + - `/exceptions` feed is sorted by severity then newest event time + - dashboard exceptions list reflects this order. +- Docs/API docs updated for Phase 9 surfaces. + +## Definition Of Done (Phase 9) +- [x] `/done-checklist` endpoint exists and returns docs+runtime integration checklist. +- [x] Readiness scoring exists for observability/governance/collaboration/security. +- [x] Dashboard displays readiness scoring and checklist summary. +- [x] App-layer backup/export command writes timestamped bundle under `runtime/exports/`. +- [x] Import dry-run validator exists (API + app command) and remains non-mutating. +- [x] Commander exceptions feed is sorted by severity + newest. +- [x] Docs updated with Phase 9 and explicit remaining gaps. +- [x] `npm run build` passes. +- [x] `npm run dev` smoke passes. + +## Phase 10 (Hardening: local token gate + operation audit + tests) — Completed +- Added local token auth gate with secure defaults: + - `LOCAL_TOKEN_AUTH_REQUIRED=true` (default) + - `LOCAL_API_TOKEN` must be configured for protected operations + - token accepted via `x-local-token` or `Authorization: Bearer` +- Applied auth guard to protected routes: + - all state-changing endpoints (`POST` / `PATCH`) + - import/export side-effect routes (`POST /api/import/dry-run`, `GET /export/state.json`, `GET /api/export/state.json`) +- Added command gating for import/export command paths: + - `APP_COMMAND=backup-export` + - `APP_COMMAND=import-validate` + - both require explicit `LOCAL_API_TOKEN` when local token auth is enabled. +- Added operation audit module and log: + - file: `runtime/operation-audit.log` + - events: `import_dry_run`, `backup_export` + - sources: `api`, `command` +- Extended audit timeline aggregation to include operation audit events. +- Hardened commander exception feed ordering tie-breakers to stay deterministic after severity/time ranking. +- Added lightweight Node test suite: + - `/done-checklist` route + - `/api/import/dry-run` route (guarded + authorized path) + - backup export command path (`npm run command:backup-export`) + - deterministic commander ordering test +- Added npm test command: + - `npm test` + +## Phase 11 (Import mutation gate + replay exports + dashboard guard visibility) — Completed +- Added optional local import mutation endpoint: + - `POST /api/import/live` + - guarded by local token auth + explicit env gate (`IMPORT_MUTATION_ENABLED=true`) + - blocked while `READONLY_MODE=true` unless request sets `dryRun=true` + - endpoint defaults remain safe (`IMPORT_MUTATION_ENABLED=false`, `IMPORT_MUTATION_DRY_RUN=false`) +- Added import mutation runtime service with explicit guard state model and controlled local apply behavior: + - mutates local runtime stores only (`runtime/projects.json`, `runtime/tasks.json`, `runtime/budgets.json`) + - always validates export bundle schema before dry-run/live mode + - operation audit now records `import_apply` +- Extended replay index: + - now includes `runtime/exports/*.json` as `exportBundles` in addition to `runtime/export-snapshots/*.json` +- Updated dashboard: + - added `Import Guard and Token Gate` section showing runtime guard/token posture and import gate status +- Added/extended tests: + - replay index includes export bundles + - import mutation guard rejects when env gate is disabled + - import routes remain blocked without local token when token gate is required +- Docs/checklists updated across README, runbook, architecture, and done-checklist for Phase 11 defaults and warnings. + +## Phase 12 (Dashboard search wiring + replay/export visibility + docs-linked safety badges) — Completed +- Added dashboard inline search panel on `/`: + - query input + scope selector + bounded limit + - scope wiring: `/api/search/tasks|projects|sessions|exceptions` + - server-rendered result table on home view +- Added replay/export visibility panel on `/`: + - replay index counts for timeline/digests/export snapshots/export bundles + - latest snapshot/bundle file visibility + - direct links to `/api/replay/index` and `/export/state.json` +- Upgraded safety/guard visibility: + - explicit `enabled/disabled/blocked` badges for guarded features + - surfaced approval-action defaults in guard table + - linked docs references for guard/checklist rows (`/docs/*`) +- Added local read-only docs routes: + - `/docs` index + - `/docs/readme`, `/docs/runbook`, `/docs/architecture`, `/docs/progress` +- Added Phase 12 test coverage: + - dashboard home includes search + replay/export + disabled badge visibility + - search API wiring and bounded limit validation on live server route + - docs route fetch coverage (`/docs/runbook`) + - retained prior phase tests unchanged + +## Phase 13 (Replay time-window filters + action-queue snooze TTL semantics) — Completed +- Added replay index time-window filtering: + - `GET /api/replay/index` now supports optional `from` and `to` ISO query filters. + - Window filtering applies to timeline entries, digests, export snapshots, and export bundles. + - Replay payload now returns the normalized effective `window` bounds when provided. +- Added action-queue acknowledgement snooze/TTL semantics: + - `POST /api/action-queue/:itemId/ack` accepts optional `ttlMinutes` or `snoozeUntil`. + - Acknowledgement entries in `runtime/acks.json` can include `expiresAt`. + - Expired acknowledgements are treated as inactive so queue items can re-surface automatically. +- Updated dashboard queue rendering: + - acknowledged items display optional expiry timestamps when present. +- Updated API docs and runbook/architecture/readme references for both features. +- Added Phase 13 test coverage: + - replay index window filtering behavior. + - acknowledgement TTL/snooze expiry behavior. + +## Phase 14 (Replay filtering observability + stale-ack prune command) — Completed +- Extended replay index observability: + - `GET /api/replay/index` now returns per-source `stats` for: + - `timeline`, `digests`, `exportSnapshots`, `exportBundles` + - aggregate `total` + - each stats bucket reports: + - `total` + - `returned` + - `filteredOut` + - `filteredOutByWindow` + - `filteredOutByLimit` +- Updated home dashboard replay/export panel: + - surfaces returned vs filtered-out replay counts for timeline/digest/export sources. +- Added stale acknowledgement auto-prune command mode: + - `npm run command:acks-prune` + - removes expired entries from `runtime/acks.json` + - optional dry-run mode via `COMMAND_ARG=--dry-run` (or `ACK_PRUNE_DRY_RUN=true`) + - guarded by local token gate defaults (`LOCAL_TOKEN_AUTH_REQUIRED=true`, explicit `LOCAL_API_TOKEN` required) +- Operation audit extended: + - command prune actions append `ack_prune` events to `runtime/operation-audit.log`. +- Added/extended tests: + - replay index stats coverage for returned/filtered aggregation. + - command-mode ack prune integration test (expired ack removed, active ack retained, audit entry written). + +## Phase 15 (Token-gated stale-ack prune preview API) — Completed +- Added dry-run prune preview service: + - new runtime helper `previewStaleAcksPrune` returns stale-ack prune counts only (`before/removed/after`) with no state mutation. +- Added protected API endpoint: + - `GET /api/action-queue/acks/prune-preview` + - guarded by existing local token auth gate (`LOCAL_TOKEN_AUTH_REQUIRED` + `LOCAL_API_TOKEN`). +- Updated docs/readiness wiring: + - `/api/docs` route catalog now includes prune-preview. + - `/done-checklist` route coverage checks now require prune-preview route documentation. + - README/RUNBOOK/ARCHITECTURE route lists updated. + +## Phase 16 (Replay per-source latency/size indicators) — Completed +- Extended replay index stats for each source and aggregate total: + - `latencyMs` + - `totalSizeBytes` + - `returnedSizeBytes` +- Replay/export dashboard panel now surfaces per-source latency and returned-size indicators. +- Added replay stats assertions in tests to validate size aggregation and non-negative latency metrics. +- Updated docs and API docs route summary for the expanded replay stats payload. + +## Phase 17 (Replay latency percentile buckets + checklist hardening) — Completed +- Extended replay index stats for each source and aggregate total: + - `latencyBucketsMs.p50` + - `latencyBucketsMs.p95` +- Percentiles are computed from per-source replay artifact load/parse latency samples and surfaced in: + - `GET /api/replay/index` + - dashboard replay/export visibility table +- Added replay percentile assertions in tests (`p95 >= p50`, non-negative across timeline/digests/export snapshots/export bundles/total). +- Updated docs and API docs route summary to include percentile latency buckets. +- Done-checklist status after Phase 17 validation: `pass=19`, `warn=0`, `fail=0`. + +## Safety guardrails +- No modifications outside `control-center/` +- No live tool calls in default mode (`READONLY_MODE=true`) +- No approval action execution in default mode (`APPROVAL_ACTIONS_ENABLED=false`) +- Approval dry-run defaults on (`APPROVAL_ACTIONS_DRY_RUN=true`) even when actions are enabled +- Import mutation endpoint defaults off (`IMPORT_MUTATION_ENABLED=false`) +- Local token auth is required by default for protected operations (`LOCAL_TOKEN_AUTH_REQUIRED=true`) +- No writes to OpenClaw runtime config + +## Phase 18 (Continuous completion soak validation) — Completed +- Re-ran verification loop from current state: + - `npm test` passed (8/8 tests). + - `npm run build` passed. + - `npm run dev` smoke passed (single monitor cycle + digest/timeline output). +- Re-validated safety defaults from runtime startup log: + - `READONLY_MODE=true` + - `APPROVAL_ACTIONS_ENABLED=false` + - `IMPORT_MUTATION_ENABLED=false` + - `LOCAL_TOKEN_AUTH_REQUIRED=true` +- Re-checked integration checklist status via runtime evaluation: + - `/done-checklist`: `pass=19`, `warn=0`, `fail=0`, readiness `100`. +- Unfinished roadmap/checklist warnings detected in this phase: none. + +## Phase 19 (Continuous completion verification pass) — Completed +- Re-ran requested verification loop from latest state: + - `npm test` passed (8/8 tests). + - `npm run build` passed. + - `npm run dev` smoke passed (single monitor run + digest/timeline output). +- Verified runtime default safety posture from startup output: + - `READONLY_MODE=true` + - `APPROVAL_ACTIONS_ENABLED=false` + - `IMPORT_MUTATION_ENABLED=false` + - `LOCAL_TOKEN_AUTH_REQUIRED=true` +- Re-evaluated checklist/readiness by running `buildDoneChecklist` against current snapshot: + - `pass=19`, `warn=0`, `fail=0`, readiness `100`. +- `npm run dev smoke` is not a declared npm script in this project; smoke validation remains `npm run dev` per runbook. +- Non-intentional functional/code gaps detected in this pass: none. + +## Phase 20 (Final hardening: non-network UI smoke + EPERM classification + final artifact) — Completed +- Added non-network UI rendering smoke coverage (no socket bind required): + - `test/ui-render-smoke.test.ts` + - session drilldown HTML render smoke (escaping + key sections) + - audit timeline HTML render smoke (severity selection + escaping) +- `/done-checklist` now explicitly classifies UI bind `EPERM` as environment-only: + - new checklist item id: `obs_ui_bind_env_only` + - status remains `pass` because this is a sandbox runtime constraint, not an app regression +- Added final summary artifact: + - `runtime/final-status.json` + - stores checklist snapshot + explicit intentional limitations +- Re-ran validation loop: + - `npm test` passed (`10/10`). + - `npm run build` passed. + - `npm run dev` smoke passed. + - `/done-checklist` snapshot after this phase: `pass=20`, `warn=0`, `fail=0`, readiness `100`. + +## Phase 21 (Mission Control UX v2: arcade IA + office awareness) — Completed +- Milestone A (IA + visual layer): + - Reworked home dashboard from single debug-heavy page into sectioned IA with dual sidebars. + - Added required operator tabs: + - `Overview` + - `Office Space` + - `Projects/Tasks` + - `Alerts` + - `Replay/Audit` + - `Settings` + - Updated dashboard visual direction to colorful pixel-arcade styling (non-monochrome). + - Replaced raw debug-heavy copy with operator language and softened empty states (`Not activated yet`). +- Milestone B (office-space model + agent identity): + - Added office-space workload synthesis from sessions/tasks/projects/agent-budgets. + - Added deterministic animal identity mapping from agent name semantics with fallback hashing. + - Added pixel-style agent avatar cards showing status, zone placement, and "busy on what" summaries. +- Milestone C (tests + verification): + - Extended UI smoke tests: + - section navigation rendering + active state + - semantic animal identity mapping determinism + - Verification loop passed: + - `npm test` passed (`12/12`) + - `npm run build` passed + - `npm run dev` smoke passed + - `UI_MODE=true UI_PORT=4410 npm run dev` smoke booted successfully (`ui listening`). +- Docs refreshed for v2 UX/IA: + - `README.md` + - `docs/RUNBOOK.md` + - `docs/PROGRESS.md` + +## Phase 22 (Usage/Cost parity surfaces + connector-aware placeholders) — Completed +- Milestone A (data adapter + route surfaces): + - Added runtime usage adapter `src/runtime/usage-cost.ts`. + - Added `GET /api/usage-cost` endpoint. + - Added `GET /usage-cost` route alias (redirects to `/?section=usage-cost`). +- Milestone B (UI integration in v2 IA): + - Added dedicated `Usage & Cost` sidebar section. + - Added Overview usage/cost pulse card and right-rail usage summary. + - Added context-window visibility table (absolute tokens + percent when context catalog is connected). + - Added breakdown tables by agent/project/model/provider and budget burn-rate messaging. + - Added settings connector TODO card for missing data integrations. +- Milestone C (placeholder policy): + - Disconnected metrics now explicitly show `Data source not connected`. + - Request-count metrics are marked as connector TODO until an external counter is integrated. + - Added optional model context adapter file: + - `runtime/model-context-catalog.json` +- Milestone D (tests + verification): + - Added tests: + - `test/usage-cost.test.ts` (adapter behavior for connected/disconnected sources) + - extended UI/nav smoke + API docs coverage updates. + - Verification loop passed: + - `npm test` passed (`14/14`) + - `npm run build` passed + - `npm run dev` smoke passed + - `UI_MODE=true UI_PORT=4412 npm run dev` smoke passed with live Usage & Cost section rendering. + +## Phase 23 (Mission Control v2 final polish: operator copy + low-noise UX) — Completed +- Milestone A (de-technicalized operator language): + - Rewrote section blurbs and major card copy for non-technical operators across: + - `Overview` + - `Usage & Cost` + - `Office Space` + - `Projects/Tasks` + - `Alerts` + - `Replay/Audit` + - `Settings` + - Replaced technical labels in search and right-rail summaries with plain-language wording. + - Moved dense route/debug links into collapsible `Advanced data links` to reduce visible UI clutter. +- Milestone B (zero-noise reduction + empty-state quality): + - Collapsed low-signal replay metrics table when no positive metrics exist. + - Replaced repetitive zero tables with focused empty states in Usage/Cost breakdowns and lane boards. + - Improved no-match search messages and queue/task/project empty states to avoid misleading zero-heavy blocks. +- Milestone C (Office Space legibility + mascot consistency): + - Upgraded mascot sprite set for consistency and readability. + - Added semantic mascot mappings for additional known agent names (`otter`, `tiger`) while preserving deterministic fallback behavior. + - Improved office cards with humanized agent labels, clearer status lines, and structured current-focus lists. +- Milestone D (Usage/Cost clarity for non-technical users): + - Strengthened explanatory copy for tokens/context window as AI text/memory concepts. + - Updated usage cards and tables with plain-language headers (`Text used`, `Est. spend`, `Data status`). + - Kept disconnected-source handling explicit (`Data source not connected`) and preserved connector TODO surfacing in Settings. +- Verification loop (post-polish): + - `npm test` passed (`14/14`) + - `npm run build` passed + - `npm run dev` smoke passed + - `UI_MODE=true UI_PORT=4422 npm run dev` smoke passed with live render checks for: + - `Usage and Cost Pulse` + - `Animal Crew Cards` + +## Phase 24 (Usage/Cost parity closure: real runtime metrics + burn trends) — Completed +- Milestone A (runtime data wiring): + - Extended `src/runtime/usage-cost.ts` to read real OpenClaw runtime sources: + - `~/.openclaw/agents/*/sessions/sessions.json` (session context window/provider metadata) + - `~/.openclaw/agents/*/sessions/*.jsonl` (assistant request usage events with token/cost) + - Added runtime event aggregation for `today/7d/30d`: + - real `tokens` + - real `requestCount` + - real `estimatedCost` + - real trend pace baseline from prior same-length window when available + - Kept digest snapshots as fallback only when runtime request events are unavailable. +- Milestone B (context-window and breakdown parity): + - Context-window rows now prefer live session context limits from runtime session metadata, then fallback to model catalog. + - Context warning thresholds now render absolute token thresholds + percent thresholds. + - Source breakdown rows now include real request counts and keep conversation counts. + - Breakdown by `agent/project/model/provider` now uses runtime request events (30d window) when connected. +- Milestone C (connector/noise policy): + - Removed disconnected placeholders where real runtime data exists. + - Request-count connector now reports `connected` when runtime session events are available. + - Connector TODOs now appear only for truly missing sources (no fabricated TODO noise when runtime source is connected). +- Milestone D (supporting updates): + - Updated `src/ui/server.ts` usage tables to display request counts cleanly. + - Updated `src/clients/openclaw-live-client.ts` to respect real `active` flag from sessions list when present. + - Updated docs in `docs/RUNBOOK.md` for runtime usage source precedence and fallback behavior. + - Added runtime-backed unit coverage in `test/usage-cost.test.ts`. +- Verification loop (parity close): + - `npm test` passed (`15/15`) + - `npm run build` passed + - `npm run dev` smoke passed + - `UI_MODE=true UI_PORT=4430 npm run dev` smoke passed (`ui listening`) + - Note: in this environment these commands required elevated execution because runtime/test/build paths are write-protected under default sandbox (`EPERM` without escalation). + +## Phase 25 (Mission Control UI/UX v3 hard reset: polished pixel-office + Mac parity) — Completed +- 2026-03-04 12:16 CET: Phase 25 execution restarted with single clean chain. +- 2026-03-04 12:25 CET: Phase 25 v3 redesign completed, verified, and documented in one execution chain. +- 2026-03-04 12:26 CET: Live UI smoke fetch confirmed required v3 surfaces render (`Mission Control v3`, `Mac Parity Surfaces`, `Subscription Window`, `Office Floor`, `Full Agent Roster`). + +### Phase 25 implementation artifacts +- UI/UX v3 shell and styling reset in `src/ui/server.ts`: + - new design tokens and layered pixel-office background + - responsive 3-column layout polish for desktop/mobile + - subtle motion (`panel-in`, `card-in`, `status-pulse`) + - v3 section naming and operator-first copy pass +- Mac parity surface matrix added in dashboard render: + - explicit surface rows with status + direct route entry for sessions, approvals, cron, projects/tasks, usage/cost, replay/audit, health/digest, export/import safety, and pixel adapter +- Office roster best-effort integration implemented: + - new adapter `src/runtime/agent-roster.ts` reads `~/.openclaw/openclaw.json` (read-only) + - office card generation now merges known roster + runtime/session/task/project/budget signals + - office floor rendered as zone/desk occupancy model, not session-only list +- Subscription usage/remaining best-effort integration completed: + - completed subscription adapter logic in `src/runtime/usage-cost.ts` + - supports connected/partial/not_connected contract with explicit connection hints + - UI surfaces subscription plan/consumed/remaining/limit/cycle/source in Overview, Usage, and right rail +- Tests/docs updates completed: + - new test: `test/office-roster.test.ts` + - updated nav/copy smoke: `test/ui-render-smoke.test.ts` + - extended subscription data contract tests: `test/usage-cost.test.ts` + +### v3 implementation checklist (must complete before close) +- [x] IA and visual reset: + - replace v2 arcade/gameboy look with polished modern pixel-office style: + - design tokens (`:root` colors, spacing, radii, shadows) + - multi-layer office background (grid + glow + depth), not flat blocks + - responsive desktop/mobile behavior with intentional hierarchy + - subtle motion for page/cards (load reveal + status pulse) +- [x] Non-technical operator language rewrite: + - rewrite all visible dashboard copy to operator-first plain language. + - replace technical/debug labels in major sections, cards, and empty states. + - keep advanced/technical links behind explicit advanced disclosures. +- [x] OpenClaw Mac parity surfaces coverage: + - add explicit parity surface panel exposing core control capabilities: + - conversations/session visibility + - approvals + decision queue + - cron/scheduling + - projects/tasks + - usage/cost + - replay/audit + - health/digest + - export/import dry-run + safety gates + - pixel/canvas adapter + - each surface must show availability/status + route entry. +- [x] Full office-space roster and live status: + - add best-effort OpenClaw roster adapter reading local OpenClaw config. + - ensure office view includes all known agents (not just active-session subset). + - preserve animal identity mapping and show each agent’s live work summary/status. + - render office-space as a true floor/zone view (desks/zones + occupancy). +- [x] Subscription usage/remaining integration: + - extend usage-cost adapter with best-effort subscription source adapter. + - when available, show subscription consumed/remaining and billing-cycle context. + - when unavailable, show explicit unavailable state + exact connection target(s). +- [x] Safety and guardrails preservation: + - keep all safety defaults unchanged (`READONLY_MODE`, approval/import gates, local token gate). + - no mutation of `~/.openclaw/openclaw.json`. +- [x] Tests and verification: + - preserve existing tests and add coverage for: + - v3 section navigation/copy smoke + - all-agent office roster fallback behavior + - subscription availability/unavailability rendering data contracts + - run and pass: + - `npm test` -> pass (`18/18`) + - `npm run build` -> pass + - `npm run dev` smoke -> pass (single monitor cycle) + - `UI_MODE=true UI_PORT=4460 npm run dev` smoke -> pass (`ui listening`) + +### Reference inputs for this phase +- Local OpenClaw docs (authoritative): + - `README.md` + - `docs/ARCHITECTURE.md` + - `docs/RUNBOOK.md` +- Local OpenClaw runtime/config signals: + - `~/.openclaw/openclaw.json` (agent roster metadata only) + - `~/.openclaw/cron/jobs.json` + - `~/.openclaw/agents/*/sessions/*` +- Open-source pattern borrowing (available locally): + - existing Mission Control two-rail information architecture and card grouping patterns + - tokenized CSS system + semantic badges + progressive disclosure for advanced data links + +### Phase 25 progress update (2026-03-04 13:27 CET) +- Scope: immediate v3 UI verification pass in `agents/pandas/control-center` (headline clarity, Office Space roster completeness, Usage & Billing unavailable-state clarity). +- Changed files: + - `src/ui/server.ts` + - `src/runtime/agent-roster.ts` + - `test/ui-render-smoke.test.ts` + - `test/agent-roster.test.ts` +- Product checks completed: + - Homepage headline now explicitly renders `Mission Control v3 Pixel Office` with `Homepage is now v3, replacing the old v2 shell.` and upgraded pixel-office styling in the v3 brand block. + - Office Space now unions OpenClaw config roster and runtime agent directories; live smoke showed `Config: loaded 7`, `Runtime: loaded 9`, `Combined roster: 9`. + - Usage & Billing keeps real runtime usage/cost metrics and now shows explicit unavailable subscription field states (e.g., `Unavailable: consumed missing from subscription source`) when fields are absent. +- Validation output (this run): + - `npm test` passed (`21/21`). + - `npm run build` passed. + - `npm run dev` smoke passed on `UI_MODE=true UI_PORT=4470` with UI markers confirmed by HTTP fetch: + - `Mission Control v3 Pixel Office` + - `Homepage is now v3, replacing the old v2 shell.` + - `Office Floor` + - `Full Agent Roster` + - `Usage & Billing` + - Live usage API sample during smoke: + - `today_tokens=44762628`, `today_cost=20.532894199999987`, `today_source=connected` + - `30d_tokens=113515693`, `30d_cost=62.132698250000004`, `30d_source=connected` + - `subscription_status=not_connected` + +## Remaining Gaps +- Functional gaps in default safe mode: none. +- Environment caveat: + - default UI port `4310` may already be occupied by another local process (`EADDRINUSE`) + - use `UI_PORT=` for smoke runs when needed. + +## Next Phase +- Continue soak/stability validation as default mode. +- Open a new phase only when a real functional gap, UX bug, or checklist regression appears. + +## Phase 25 DoD gap patch (2026-03-05) — Completed +- Scope: tighten product DoD targets for full Chinese coverage/non-technical middle-school copy and global visibility of cron/heartbeat/current tasks/tool calls. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Wired global visibility card into the main content stack so it is always visible, not just defined in source. + - Simplified global visibility copy (EN/ZH) to plain-language wording and explicit `cron` label. + - Kept bilingual labels for all four required signals: cron, heartbeat, current tasks, tool calls. + - Added smoke tests for EN/ZH global visibility copy and dashboard mount point. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`7/7`). + - `npm run dod:check` ran and remains `NOT_DONE` due unrelated existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + - Full `npm test` remains red in this workspace due existing unrelated failures: + - `test/office-roster.test.ts` (runtime active-session map assertion) + - `test/triplet-control.test.ts` (supervisor restart expectation) + - `test/triplet-control.test.ts` (DoD pass fixture expectation) + +## Phase 25 DoD gap follow-up (2026-03-05) — Completed +- Scope: tighten DoD-facing global visibility behavior and simplify operator copy with minimal, safe edits. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Fixed global visibility heartbeat count to use real heartbeat cron job count (`heartbeatJobs.length`) instead of a static row count. + - Simplified EN/ZH global visibility copy to more non-technical, middle-school-readable wording. + - Kept all four required global signals explicit: cron, heartbeat, current tasks, tool calls. + - Added smoke assertion to pin heartbeat-count source wiring in dashboard source. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`7/7`). + - `node --import tsx --test test/ui-language-preferences.test.ts` passed (`1/1`). + - `npm test` remains red in this workspace with existing non-target failures: + - `test/office-roster.test.ts` (`office cards use runtime active-session map when snapshot sessions are empty`) + - `test/triplet-control.test.ts` (`resident supervisor restarts worker when heartbeat is stale`) + - `test/triplet-control.test.ts` (`dod check emits machine-readable pass/fail status`) + - `npm run dod:check` ran and remains `NOT_DONE` due existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + - Runtime UI smoke could not bind in this sandbox (`listen EPERM 127.0.0.1:*`), so live HTTP smoke is environment-blocked here. + +## Phase 25 DoD gap follow-up 2 (2026-03-05) — Completed +- Scope: keep DoD copy simple and bilingual while removing technical/raw-JSON navigation from global visibility actions. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Added safe UI detail routing helper for global visibility signals so cron/heartbeat/current tasks/tool calls all link to dashboard sections with persisted `lang`. + - Updated global visibility strip + table rows to use section links instead of `/cron` and `/sessions` JSON endpoints. + - Rendered language toggle in the sidebar brand block. + - Extended smoke tests to assert section-based links, `lang` continuity (`en`/`zh`), and language-toggle render wiring. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`7/7`). + - `npm test` remains red with existing non-target failures: + - `test/office-roster.test.ts` (`office cards use runtime active-session map when snapshot sessions are empty`) + - `test/triplet-control.test.ts` (`resident supervisor restarts worker when heartbeat is stale`) + - `test/triplet-control.test.ts` (`dod check emits machine-readable pass/fail status`) + - `npm run dod:check` remains `NOT_DONE` due existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + +## Phase 25 DoD gap follow-up 3 (2026-03-05) — Completed +- Scope: close residual wording gaps in global visibility so EN/ZH copy is simpler and all four required signals stay explicit, including empty state. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Simplified global-visibility summary/labels to plain language: + - EN: `One place to see cron, heartbeat, current tasks, and tool calls.`, `Timed jobs:`, `Heartbeat:` + - ZH: `一眼看全局:定时任务(cron)、任务心跳、当前任务和工具调用。`, `定时任务(cron):`, `任务心跳:` + - Updated empty-state copy to mention all four signals (cron/heartbeat/current task/tool call) in both EN and ZH. + - Updated smoke assertions to pin the new wording. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`7/7`). + - `node --import tsx --test test/ui-language-preferences.test.ts` passed (`1/1`). + - `npm test` remains red with existing non-target failures: + - `test/office-roster.test.ts` (`office cards use runtime active-session map when snapshot sessions are empty`) + - `test/triplet-control.test.ts` (`resident supervisor restarts worker when heartbeat is stale`) + - `test/triplet-control.test.ts` (`dod check emits machine-readable pass/fail status`) + - `npm run dod:check` remains `NOT_DONE` only on existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + - Targeted DoD checks for this request remain passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 25 DoD gap follow-up 4 (2026-03-05) — Completed +- Scope: keep Mission Control DoD wording simple and bilingual while making cron/heartbeat visibility more explicit with concrete counts. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Simplified Global Visibility summary/labels to middle-school-readable copy in both languages: + - EN: `Simple view: schedule checks (cron), heartbeat checks, current tasks, and tool calls.` + - ZH: `简单总览:定时检查(cron)、心跳检查、当前任务和工具调用。` + - Switched global strip labels to clearer plain-language wording: + - EN: `Schedule checks (cron):`, `Heartbeat checks:` + - ZH: `定时检查(cron):`, `心跳检查:` + - Made cron/heartbeat row results explicitly visible with counts: + - EN examples: `1 schedule check(s) active.`, `1 heartbeat check(s) enabled.` + - ZH examples: `已启用 1 个定时检查。`, `已启用 1 个心跳检查。` + - Updated smoke tests to assert the new EN/ZH copy and count-based visibility text. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`7/7`). + - `node --import tsx --test test/ui-language-preferences.test.ts` passed (`1/1`). + - `npm run dod:check` remains `NOT_DONE` only for existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + - `npm test` remains red with existing non-target failures: + - `test/office-roster.test.ts` (`office cards use runtime active-session map when snapshot sessions are empty`) + - `test/triplet-control.test.ts` (`resident supervisor restarts worker when heartbeat is stale`) + - `test/triplet-control.test.ts` (`dod check emits machine-readable pass/fail status`) + - Runtime UI smoke start is still environment-blocked in this sandbox: + - `listen EPERM 127.0.0.1:` + +## Phase 25 DoD gap follow-up 5 (2026-03-05) — Completed +- Scope: keep copy simple and bilingual while making tool-call visibility truly global. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Simplified global visibility wording again to plain language: + - EN: `One place to see cron, heartbeat, current tasks, and tool calls.`, `Cron:`, `Heartbeat:` + - ZH: `一眼看全局:定时任务(cron)、任务心跳、当前任务和工具调用。`, `定时任务(cron):`, `任务心跳:` + - Reworded row-level status/results to remove technical/pluralized `check(s)` phrasing. + - Fixed tool-call count source for global visibility: + - removed preview-only `sessionPreview.items` count + - added paged scan (`countRecentToolCalls`) so the signal reflects all sessions (bounded at 500 for safety). + - Updated smoke tests to pin new EN/ZH copy and to assert preview-limited tool-call counting is not used. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed. + - `node --import tsx --test test/ui-language-preferences.test.ts` passed. + - `npm test` remains red with existing non-target failures: + - `test/office-roster.test.ts` (`office cards use runtime active-session map when snapshot sessions are empty`) + - `test/triplet-control.test.ts` (`resident supervisor restarts worker when heartbeat is stale`) + - `test/triplet-control.test.ts` (`dod check emits machine-readable pass/fail status`) + - `npm run dod:check` remains `NOT_DONE` only for existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + +## Phase 25 DoD gap follow-up 6 (2026-03-05) — Completed +- Scope: close residual mixed-language zh copy in Global Visibility and harden DoD source audit for full Chinese phrasing. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `scripts/dod-check.ts` +- Implementation: + - Replaced remaining mixed zh wording in Global Visibility from `Cron`-embedded text to full Chinese: + - `Cron 正在运行。` -> `定时任务正在运行。` + - `还没有设置 Cron。` -> `还没有设置定时任务。` + - `保持 Cron 开启。` -> `保持定时任务开启。` + - Simplified zh summary/label and empty state to keep middle-school readability and full Chinese coverage: + - `一眼看全局:定时任务、任务心跳、当前任务和工具调用。` + - `定时任务:` + - `暂无定时任务、心跳检查、当前任务或工具调用。` + - Updated UI smoke assertions to pin the new zh copy. + - Hardened DoD source audit with explicit mixed zh/en phrase detection (`MIXED_ZH_PHRASES`) so known mixed phrases cannot pass `product-full-chinese`. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`7/7`). + - `npm run dev` smoke passed (single monitor cycle in safe mode). + - `npm run dod:check` remains `NOT_DONE` only for existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + - `npm test` remains red with existing non-target failures: + - `test/office-roster.test.ts` (`office cards use runtime active-session map when snapshot sessions are empty`) + - `test/triplet-control.test.ts` (`resident supervisor restarts worker when heartbeat is stale`) + - `test/triplet-control.test.ts` (`dod check emits machine-readable pass/fail status`) + +## Phase 25 DoD gap follow-up 7 (2026-03-05) — Completed +- Scope: keep DoD wording minimal and explicit for cron/heartbeat/current tasks/tool calls with clearer EN/ZH phrasing. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Updated global visibility strip copy to explicit `cron` wording in EN and full Chinese wording in ZH. + - Simplified row-level cron/heartbeat text to plain-language terms (`schedule checks`, `任务心跳`) while preserving existing behavior and links. + - Updated smoke fixtures/assertions to lock the new EN/ZH readability-focused copy. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/ui-language-preferences.test.ts` passed (`8/8`). + - `node --import tsx scripts/dod-check.ts` remains `NOT_DONE` only on existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + +## Phase 25 DoD gap follow-up 8 (2026-03-05) — Completed +- Scope: close remaining copy consistency gaps for full-Chinese global visibility wording while keeping plain, middle-school-readable operator copy. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Updated Global Visibility zh copy to full Chinese terms: + - `定时安排(cron)` -> `定时任务` + - `进行中任务` -> `当前任务` + - Kept all four required global signals explicit and visible in strip/table: + - cron/schedule, heartbeat, current tasks, tool calls. + - Aligned tool-call row detail action text with intent: + - EN `See tool calls` + - ZH `查看工具调用` + - Updated smoke assertions to pin the new zh copy. +- Verification: + - `node --import tsx --test test/ui-render-smoke.test.ts test/ui-language-preferences.test.ts` passed (`8/8`). + - `npm run build` passed. + - `npm test` remains red with existing non-target failures: + - `test/office-roster.test.ts` (`office cards use runtime active-session map when snapshot sessions are empty`) + - `test/triplet-control.test.ts` (`resident supervisor restarts worker when heartbeat is stale`) + - `test/triplet-control.test.ts` (`dod check emits machine-readable pass/fail status`) + - `UI_MODE=true UI_PORT=4470 npm run dev` monitor bootstrap runs but UI bind is sandbox-blocked: + - `listen EPERM 127.0.0.1:4470` + - `node --import tsx scripts/dod-check.ts` remains `NOT_DONE` only on existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + - Requested product DoD checks stay passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 25 DoD gap follow-up 9 (2026-03-05) — Completed +- Scope: tighten plain-language global visibility copy and improve tool-call visibility coverage with minimal safe code changes. +- Changed files: + - `src/runtime/session-conversations.ts` + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Added `toolEventCount` to session conversation list items and now aggregate this value for global tool-call signal counting. + - Kept a safe fallback to legacy `latestKind === "tool_event"` counting if `toolEventCount` is unavailable. + - Simplified EN global visibility strip/table wording to non-technical, middle-school-readable phrasing while keeping `cron/heartbeat/current tasks/tool calls` explicit. + - Kept zh global visibility copy fully Chinese and unchanged for compliance. + - Updated UI smoke assertions for the new EN copy and for the `toolEventCount` aggregation path. +- Verification: + - `node --import tsx --test test/ui-render-smoke.test.ts test/ui-language-preferences.test.ts` passed (`9/9`). + - `npm run build` passed. + - `npm run dod:check` remains `NOT_DONE` only on existing non-target blockers: + - `product-apple-native-ui` + - `product-real-subscription-connected` + - Requested product DoD checks are passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 25 DoD gap follow-up 10 (2026-03-05) — Completed +- Scope: close remaining product copy/readability visibility gaps with minimal safe edits. +- Changed files: + - `src/ui/server.ts` + - `scripts/dod-check.ts` + - `test/ui-render-smoke.test.ts` +- Implementation: + - Simplified EN global visibility wording (non-technical, middle-school readable) while keeping cron/heartbeat/current tasks/tool calls explicit. + - Updated zh global visibility summary to a shorter fully Chinese sentence. + - Added stronger DoD source-audit tokens for the four global visibility signals (detail links + signal counts). + - Narrowed DoD non-technical scan scope to the copy/model sections only, avoiding false negatives from helper internals. + - Expanded smoke assertions to verify zh output avoids EN label leakage. +- Verification: + - `npm test` passed (`42/42`). + - `npm run build` passed. + - `npm run dod:check` remains `NOT_DONE` only on existing non-target blocker: + - `product-real-subscription-connected` + - Requested product DoD checks are passing: + - `product-full-chinese` + - `product-non-technical-copy` + - `product-middle-school-readable` + - `product-global-visibility` + +## Phase 26 UI polish pass 1 (2026-03-05) — Completed +- Scope: raise Mission Control visual quality and table readability for non-technical users. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Reworked dashboard visual system: spacing scale, typography hierarchy, card/panel depth, and navigation polish. + - Rebalanced three-column layout width to give the center content area more horizontal room. + - Tuned status chips and executive cards for clearer metric scanning. + - Fixed global visibility table readability by adding deterministic column widths and horizontal overflow handling. + - Kept cron task names fully expanded (no `等 N 个` truncation) in global visibility. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 27 Agent-vs-role separation (2026-03-05) — Completed +- Scope: separate real execution agents from task-owner roles to remove dashboard ambiguity. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Split right sidebar into two explicit cards: + - `真实执行 Agent` (runtime executors) + - `任务角色(Owner)` (business board roles, non-process identities) + - Added explanatory copy to clarify owner roles are not runtime agent processes. + - Added fallback execution-agent detection from real usage/token telemetry so `main/coq/otter...` still appears when live session/cron owner bindings are temporarily missing. + - Added `任务角色看板(Owner)` section under Pixel Office page. + - Updated office roster derivation so task/project owners are no longer merged into agent roster IDs. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/office-roster.test.ts` passed (`12/12`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 28 Subscription UI simplification (2026-03-05) — Completed +- Scope: reduce subscription noise and keep only actionable quota signals (`5h` / `Week`). +- Changed files: + - `src/runtime/usage-cost.ts` + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Extended subscription runtime model with explicit quota-window fields for Codex rate-limit snapshots: + - `primaryWindowLabel/Used/Remaining/Reset` + - `secondaryWindowLabel/Used/Remaining/Reset` + - Replaced verbose subscription rendering with compact dual-window quota cards in both: + - `/?section=usage-cost` + - right sidebar usage summary on overview + - Removed connected-state verbose source/detail paragraphs from the main subscription card. + - Removed sidebar noise (`Top Agent` / `Top 任务`) from the usage summary card to improve readability. + - Added new compact visual styles (`quota-compact`, progress bars, row hierarchy) to improve scanability. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/usage-cost.test.ts` passed (`18/18`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 29 Token charts + time-range labeling (2026-03-05) — Completed +- Scope: add visual token-share charts and make token time ranges explicit in UI. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added donut/pie charts (conic-gradient) with percentage legend for: + - 用量来源(按 Agent / 按项目) + - Token 类型占比(全量会话) + - Cron 任务内 Token 占比 + - Cron 内各 Agent 占比 + - Added explicit token time-range labels across token-heavy sections: + - `近 30 天滚动窗口(截至当前快照)` + - `全量会话累计(截至当前快照)` + - `Cron 全量会话累计(截至当前快照)` + - Added responsive chart styles (`pie-wrap`, legend, center summary) for desktop/mobile readability. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/usage-cost.test.ts` passed (`18/18`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 30 Dashboard declutter + visual cleanup (2026-03-05) — Completed +- Scope: remove noisy default content, simplify copy density, and improve first-screen readability. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Converted the large global-visibility detail table to collapsed-by-default `details`, keeping key signal chips visible first. + - Simplified `usage-cost` page into key cards first (`趋势`, `订阅窗口`, `Token 类型占比`, `Cron 占比`) and moved dense tables into collapsed detail cards. + - Reduced right-sidebar noise: + - kept compact `当前状态` and `用量与订阅摘要` + - kept `真实执行 Agent` + - removed duplicated `任务角色(Owner)` from sidebar (role board remains in Pixel Office section) + - replaced full cron table in sidebar with compact `定时与心跳` summary + direct links + - Simplified subscription disconnected/partial presentation and moved long path lists into collapsed details. + - Tuned visual density: + - smaller typography and tighter spacing + - removed global-visibility fixed column width constraints that caused unreadable wrapped Chinese text + - hid non-critical signal subtext in status chips by default + - added reusable compact details styling. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/usage-cost.test.ts` passed (`18/18`). + - `pm2 restart pandas-control-center` completed and process is `online`. + - Route smoke: `/calendar`, `/heartbeat`, `/tools` now redirect (`302`) and resolve to dashboard (`200` with `-L`). + +## Phase 31 Mapping-vs-real task clarity (2026-03-05) — Completed +- Scope: prevent users from mistaking Control Center mapping/demo rows for real OpenClaw execution tasks/agents. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added explicit mapping detection for known Control Center sample rows (`p-live` + `due-fast|todo-second|already-running|unassigned` with empty `sessionKeys`). + - Task board now shows a strong banner when only mapping rows are present: + - `当前展示的是 Control Center 看板映射样例,不是 OpenClaw 真实执行任务。` + - Each mapping task card now includes a direct label: + - `Control Center 映射(非真实任务)` + - Key task metrics now exclude mapping rows from “真实任务” counts (`进行中`/`阻塞`/总任务指标). + - Office/role copy updated to explicitly mark owner rows as mapping labels: + - `Control Center 映射角色(非真实 Agent)` + - Removed animal-style identity labels from visible office UI (no more `Bear Guardian` / `Panda Strategist` / `Eagle Scout` in cards). +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/usage-cost.test.ts` passed (`18/18`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 32 Full-panel information diet (2026-03-05) — Completed +- Scope: clean all mission-control pages to keep only actionable information for non-technical users. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Overview: + - removed low-value noisy blocks (`能力状态与就绪度`, `搜索与关注事项`) from default flow + - kept only executive summary, task health, usage pulse, cron/heartbeat/tool/agent-job critical details + - kept token-type and cron-token shares as concise decision cards + - Usage: + - default keeps only trend, subscription windows, token type share, cron share + - merged all deep-dive tables into one collapsed `高级明细(归因/模型/上下文/预算)` + - Office: + - default keeps `真实执行 Agent` + `Control Center 映射角色(非真实 Agent)` + - moved floor partition and session list into collapsed details + - removed source-path and technical provenance noise from default view + - Projects: + - keeps lanes and filters as primary + - moved task table to collapsed section + - Alerts/Replay/Settings: + - changed secondary blocks to collapsed details + - removed long explanatory text in primary cards + - Shell layout: + - removed left sidebar `快速筛选` card + - removed main-panel `开发者高级入口` mega-link block + - simplified right sidebar to status/use/billing/executors/schedule essentials only +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/usage-cost.test.ts` passed (`18/18`). + - `pm2 restart pandas-control-center` completed and process is `online`. + - Legacy routes still healthy: `/calendar`, `/heartbeat`, `/tools` redirect and resolve `200`. + +## Phase 33 Manager-first UI hardening (2026-03-05) — Completed +- Scope: finalize non-technical manager view quality, remove residual noise, and stabilize key data surfaces. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Information architecture: + - nav labels simplified to short manager language (`总览/用量/执行者/任务/待处理/历史/设置`) + - overview default now keeps decision cards + health cards; detailed token analysis stays in usage page + - added explicit `统计口径` card so all token/cost numbers have visible time range semantics + - Cron/heartbeat clarity: + - deduplicated enabled cron counting between runtime and catalog + - long raw command/prompt texts replaced with business-purpose summaries + - cron/heartbeat tables now use concise labels and localized status text + - schedule text simplified (e.g. cron expression shown as `固定时间表`) + - Real executor vs mapping separation: + - executor roster/summary now built from real tasks only (mapping samples excluded) + - task board default uses real tasks; mapping samples moved to explicit collapsed explainers + - office panel keeps mapping names only in a clearly marked “不执行任务” explanation block + - Usage page noise cleanup: + - status badges localized (`已连接/未连接/部分连接`) + - usage labels trimmed for readability (UUID suffixes removed in tables/pie legend) + - mapping sample tasks removed from task-level usage attribution display + - connector todo copy converted to plain Chinese action language + - Visual polish: + - refined Apple-like neutral palette, spacing, typography, borders, and shadows + - reduced hover/motion intensity and improved table readability +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/usage-cost.test.ts` passed (`18/18`). + - `pm2 restart pandas-control-center` completed and process is `online`. + - Runtime smoke passed (`200`): + - `/?section=overview&lang=zh` + - `/?section=usage-cost&lang=zh` + - `/?section=office-space&lang=zh` + - `/?section=projects-tasks&lang=zh` + +## Phase 34 Overview-only global card + animal pixel agents (2026-03-05) — Completed +- Scope: keep `全局总览` only on overview page, and restore/enhance pixel-style agent panel with per-agent animal identity. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Global overview display logic: + - removed cross-page global visibility strip reuse. + - now `全局总览` block renders only when `section=overview`. + - non-overview pages show a small right-rail shortcut: `在总览查看四项信号`. + - Agent panel visual restoration: + - restored pixel-style identity rendering in agent cards. + - each agent card now renders: + - mapped animal emoji + - mapped animal Chinese label + - pixel sprite (from identity catalog) + - status + summary + active session/task counts. + - refreshed office card layout/CSS for a cleaner “Apple + pixel accent” style. + - Tests: + - updated smoke assertion from “global visibility on all sections” to “overview-only block”. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/usage-cost.test.ts` passed (`18/18`). + - `pm2 restart pandas-control-center` completed and process is `online`. + - Runtime smoke passed (`200`): + - `/?section=overview&lang=zh` + - `/?section=office-space&lang=zh` + - `/?section=usage-cost&lang=zh` + +## Phase 35 Multi-engine character rendering + Coq rooster fix (2026-03-05) — Completed +- Scope: improve agent character quality using animation libraries and correct animal mapping (`coq`). +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Animal mapping: + - added `rooster` identity to animal catalog. + - `coq` keyword now maps to `rooster`. + - emoji/label updated to `🐓 / 公鸡`. + - Character rendering engines: + - agent card upgraded to layered character stage: + - `Rive` layer (via `@rive-app/canvas`) + - `Lottie` layer (via `lottie-web`) + - `Pixi` layer (via `pixi.js`) + - fallback emoji + pixel sprite remains for resilience. + - added runtime script loader with graceful fallback when any CDN fails. + - added per-animal pixel pattern rendering and subtle aura animation. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts test/usage-cost.test.ts` passed (`18/18`). + - `pm2 restart pandas-control-center` completed and process is `online`. + - `/?section=office-space&lang=zh` returns `200`, and `Coq` card renders as `公鸡(🐓)`. + +## Phase 36 Overview/Cron IA refactor + usage today toggle (2026-03-05) — Completed +- Scope: tighten overview middle layout, add dedicated Cron panel, default-expand project details, add usage “today vs cumulative” switch, and replace UI wording `执行者` with `智能体`. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Navigation and query state: + - added `usage_view` query mode (`today` / `cumulative`), persisted across section navigation, language toggle, and task filter form submits. + - Overview IA/UI: + - refactored overview middle area into compact grid (`今日待处理` / `当前任务` / `用量脉搏` / `全局脉搏`). + - introduced dedicated `Cron 任务看板` (id=`cron-health`) with per-agent grouped board cards and concise task purpose/next-run context. + - retained table-level cron detail in a secondary expandable block. + - Usage page: + - added segmented switch (`今天` / `累计`). + - `今天` mode shows same-day snapshot + key metrics and hides cumulative-only split panels with explicit guidance. + - `累计` mode keeps full token share / cron share / attribution/model/context/budget breakdown. + - Terminology + projects UX: + - replaced user-facing `执行者` copy with `智能体`. + - project/task page detail blocks now default expanded (`open` on mapping detail and task table). +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + - Runtime smoke (`200`) passed for: + - `/?section=overview&lang=zh` + - `/?section=usage-cost&lang=zh&usage_view=today` + - `/?section=projects-tasks&lang=zh` + +## Phase 37 Agent avatar simplification to single pixel portrait (2026-03-05) — Completed +- Scope: keep only one avatar style and improve visual quality/detail for each animal pixel portrait. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Removed mixed avatar stack (Rive/Lottie/Pixi + emoji + ASCII fallback) from agent cards. + - Kept only one avatar surface: local pixel-canvas portrait. + - Added native canvas pixel renderer with: + - per-animal drawing routines (`lion/panda/monkey/dolphin/owl/fox/bear/eagle/tiger/otter/rooster`) + - richer color palettes, highlights, outlines, and distinct facial/body features. + - local rendering only (no external animation CDN dependencies). + - Updated avatar card layout/styles to focus on larger, clearer pixel portraits. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + +## Phase 38 Overview visual polish pass (2026-03-05) — Completed +- Scope: improve overall look/spacing hierarchy in overview and remove bland/flat appearance. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Refined visual tokens/background/shadows for cleaner depth. + - Tightened overview layout to avoid stretched cards/large empty blocks (`overview-main-grid` non-stretch). + - Refined executive card and generic card surfaces with softer gradients and stronger typography hierarchy. + - Improved usage pulse readability: + - localized period labels to Chinese (`今天 / 近 7 天 / 近 30 天`). + - overview usage pulse now focuses on `今天 + 近7天` in cumulative mode to reduce clutter. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 39 Usage today mode parity (2026-03-05) — Completed +- Scope: make `今天` view keep the same full UI structure as `累计` view, without collapsing sections. +- Changed files: + - `src/runtime/usage-cost.ts` + - `src/ui/server.ts` + - `test/usage-cost.test.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added `breakdownToday` to usage snapshot so today mode has dedicated split data (not reusing cumulative rows): + - by agent / project / task / model / provider + - by session type / cron job / cron agent + - Usage UI now uses a unified layout for both `today` and `cumulative`: + - `AI 用量构成(全部会话)` + - `定时任务用量占比` + - `高级明细(归因/模型/上下文/预算)` + are present in both modes. + - Wired UI row sources to `selectedUsageBreakdown` so `today` mode renders today's own splits. + - Updated range copy to explicit today windows in `today` mode. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/usage-cost.test.ts test/ui-render-smoke.test.ts` passed (`18/18`). + - Runtime smoke confirmed today-mode parity sections on: + - `/?section=usage-cost&lang=zh&usage_view=today` + +## Phase 40 Office cards expanded + higher-detail pixel portraits (2026-03-05) — Completed +- Scope: keep all cards expanded in `智能体` page and improve pixel animals with more detail. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - `智能体` section cards now default expanded: + - mapping detail + - full roster + - office zone + - recent sessions + - Pixel portrait upgrade: + - enlarged portrait stage/canvas (`224x160`), denser pixel grid (`32x32`) + - richer per-animal drawing (face + body + feature marks) + - added outline pass and depth shading per pixel row + - improved card rendering contrast/saturation for clearer details +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 41 Pixel portrait refinement pass (2026-03-05) — Completed +- Scope: make animal portraits more delicate while keeping single-style local pixel rendering. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Replaced avatar painter with a higher-fidelity pixelization pipeline: + - emoji prototype rendered to high-res offscreen buffer (`320x320`) + - silhouette bounding-box extraction and normalized resampling + - denser pixel grid (`56x56`) with color quantization/shading + - edge-outline + soft shadow pass for stronger silhouette readability + - subtle panel/background/light treatment inside stage for depth + - Fixed runtime bug in avatar script (removed reference to undefined `drawers`). +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 42 Overview middle-column redesign (2026-03-05) — Completed +- Scope: redesign overview middle area to reduce clutter and align with native-dashboard hierarchy. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Rebuilt overview middle section from fragmented cards into a clearer 3-block composition: + - `今日指挥台` (single primary command card) + - `用量脉搏` (secondary side card) + - `全局脉搏` (compact signal strip card) + - Merged “今日待处理 + 当前任务” into one actionable command card: + - three focus tiles (待审批/逾期任务/预算风险) + - task status strip + direct actions (`查看当前任务` / `查看待处理`) + - Refined visual language for this zone: + - stronger hierarchy, denser spacing, calmer gradients, clearer chip typography. + - responsive behavior tuned for desktop/tablet/mobile. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 43 Handcrafted HD pixel animals (2026-03-05) — Completed +- Scope: remove emoji-based pixelization and render handcrafted pixel animals for each agent identity. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Replaced avatar renderer with pure handcrafted pixel sprite pipeline (no emoji sampling). + - Added per-animal sprite drawers with dedicated traits: + - lion, tiger, panda, monkey, dolphin, owl, fox, bear, eagle, otter, rooster. + - Added pixel composition helpers (`fillEllipse`, `fillRect`, edge stroke, per-row shading, highlight glint). + - Kept single-style local canvas rendering; no external dependencies/CDN assets. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 44 Apple-native visual system pass (2026-03-05) — Completed +- Scope: push overall mission-control UI toward Apple native visual language (clean hierarchy, neutral palette, glass surfaces). +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Reworked global design tokens: + - neutral gray system palette (`#f5f5f7` base), SF typography rhythm, calmer accent usage. + - refined radius/shadow/backdrop blur settings for macOS-like depth. + - Refreshed shell and navigation surfaces: + - translucent sidebars, subtler active nav highlight, reduced border noise. + - Unified card system and overview panel look: + - cleaner card backgrounds, tighter heading hierarchy, less gradient clutter. + - redesigned status chips/badges/buttons to reduce “web dashboard” visual noise. + - Updated Cron/office/lane/chip components to match the same visual system and remove style fragmentation. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. +- Remaining gaps: + - still browser-rendered, not true AppKit/SwiftUI native controls. + - next step for closer parity: replace table-heavy sections with native-like list groups and large-title collapsible stacks. + +## Phase 45 Pixel portrait detail pass v2 (2026-03-05) — Completed +- Scope: improve handcrafted pixel animals with more facial/body detail while keeping current style. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Upgraded palette per animal (extra highlight/muzzle/feature tones). + - Reworked mammal base drawer: + - richer ear/head/muzzle layering + - eye highlight + mouth details + cheek tones + - optional whisker helper for species that need it. + - Refined species-specific details: + - lion/tiger: mane + stripe density + whiskers + - panda: eye patch/ear/body contrast + - monkey/otter/fox/bear: clearer silhouette and muzzle texture + - dolphin: brighter body highlight + fin/tail shaping + - rooster/eagle/owl: stronger crest/beak/wing/eye structures. + - Improved render shading: + - vertical + center bias shading for roundness + - less mechanical highlight placement. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 46 Overview gauge dashboard pass (2026-03-05) — Completed +- Scope: replace plain metric blocks in global visibility with a richer dashboard-style instrument view. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Rebuilt `全局总览` strip into gauge dashboard cards: + - each core signal now has a ring gauge, status badge, plain-language hint, and action link. + - added two compact summary cards for `已完成` / `未完成` with progress tracks. + - Added responsive dashboard grid behavior: + - desktop: 4 signal gauges + 2 summary cards in one band. + - tablet/mobile: auto collapse to 2-column / 1-column stack. + - Kept existing plain-language copy and overview anchors unchanged. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 47 Native-style information architecture pass (2026-03-05) — Completed +- Scope: implement the 3 requested upgrades for next-level native feel. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Large tables -> grouped list first, table second: + - heartbeat/tool/cron-catalog/task/session areas now show grouped list cards by default. + - original tables moved into secondary collapsible blocks (`查看原始表格`). + - Added secondary detail pages: + - `/details/task/:taskId` + - `/details/cron/:jobId` + with clear “back to board” links. + - Overview density + title hierarchy: + - new hero strip keeps first-screen to 6 key objects. + - previous expanded KPI grid moved to collapsed `更多关键指标`. + - section-level large-title subtitle explains current information scope. + - Native motion layer: + - staggered reveal indexes for cards/nav chips. + - short page transition (`page-leave`) when navigating internal links. + - signal state-change pulse based on localStorage diff. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 48 Pixel animal differentiation pass (2026-03-05) — Completed +- Scope: increase visual separation between mammal portraits so non-rooster/non-dolphin cards are immediately distinguishable. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Redrew species portraits with unique silhouettes and feature language (not shared “same-face” base): + - lion: larger layered mane, cheek tones, mane tufts. + - tiger: angular ears + stronger stripe topology + cheek/forehead stripe marks. + - panda: high-contrast eye patches/ears/shoulders + bamboo detail. + - monkey: large side ears, forehead tuft, curled tail detail. + - otter: elongated head-body ratio, chest plate, whisker/waterline accents. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 49 Overview v3 native-flow pass (2026-03-05) — Completed +- Scope: implement the 4-point Apple-native gap closure for overview UX. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Information architecture: + - overview first screen is now `1 主卡 + 4 关键指标` (`overview-primary-card` + `overview-kpi-grid`). + - cron/heartbeat/tool/catalog/extended task cards moved into secondary fold (`展开运行详情...`). + - global visibility block converted into collapsed details card to reduce initial density. + - Layout skeleton: + - section header upgraded to large-title + action rail. + - right inspector sidebar now user-collapsible with persisted state (`inspector-toggle` + localStorage). + - overview now follows content-flow reading order, reducing side-by-side crowding. + - Typography & spacing system: + - introduced explicit type scale and spacing tokens (`--font-*`, `--space-*`). + - aligned key title/body/caption and major card spacing to 8pt rhythm. + - Motion upgrade: + - number roll transitions for key metrics (`data-counter-target`). + - compact-details expansion motion + panel reflow transition. + - state-change pulse extended to top KPI/primary cards with decay. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 50 Overview v4 single-focus card pass (2026-03-05) — Completed +- Scope: make overview primary card closer to Apple-native single-focus experience. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Reworked primary overview card into a single-focus visual: + - introduced circular focus ring (`overview-focus-ring`) with dynamic health score. + - reduced copy density to one short status line + one compact metric line. + - retained only highest-value actions in primary card. + - Strengthened visual hierarchy: + - clear focus headline/state separation. + - primary attention count remains animated and visually secondary to focus score. + - Kept v3 foundations: + - first screen still `1 主卡 + 4 关键指标`. + - secondary detail stack remains folded by default. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 51 Overview v4.1 ordering & density refinement (2026-03-05) — Completed +- Scope: improve overview readability after v4 by refining visual order and copy density. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Reordered overview visual flow without changing architecture: + - primary focus section forced first. + - secondary detail block second. + - global visibility block moved to third visual position. + - Reduced KPI text noise: + - shortened 4 key-metric card detail copy to compact plain-language labels. + - Improved primary card hierarchy: + - added concise directive pill (`优先处理...` / `继续保持...`). + - strengthened focus-card visual emphasis and reduced secondary text weight. + - upgraded KPI cards with top accent bars for faster scanning. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 52 Overview score consistency fix (2026-03-05) — Completed +- Scope: fix mismatch where focus score looked stressed while visible task signals were all zero. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Overdue count for overview score now uses **real tasks only** (excludes control-center mapping samples). + - Removed score double-penalty path and switched to one-pass weighted scoring. + - Primary-card summary now explicitly includes overdue count to keep score inputs visible. + - Current task health now maps to blocked-state risk only (no false warning from “no active tasks”). +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 53 Mission-Control transcript parity pass v1 (2026-03-05) — Completed +- Scope: re-evaluate against provided transcript and close missing core feature surfaces. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added new mission-control surfaces and nav entries: + - `calendar` (scheduled jobs + due tasks board) + - `team` (mission statement + member roles/model/tool profile) + - `memory` (daily memory timeline + long-term memory docs) + - `docs` (searchable/categorized generated document hub) + - Added legacy route mapping update: + - `/calendar` now redirects to calendar section. + - Added task-board live activity feed card: + - `projects-tasks` now includes real-time activity stream from timeline preview. + - Added client-side doc search filter interaction for docs hub. +- Verification: + - `npm run build` passed. + - `node --import tsx --test test/ui-render-smoke.test.ts` passed (`10/10`). + - `pm2 restart pandas-control-center` completed and process is `online`. + +## Phase 63 Team roster merge cleanup (2026-03-06) — Completed +- Scope: merge `角色总览` and `完整智能体名录` into one roster block at the top of the team page. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Replaced the lightweight role summary grid with the full agent card roster inside `角色总览`. + - Removed the duplicated `真实智能体` section and the separate `完整智能体名录` details block. + - Kept `团队配置明细`, mapping explanation, execution zones, and recent sessions as secondary details. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 64 Memory + Workspace editable file workbench (2026-03-06) — Completed +- Scope: turn `记忆` into a real memory-file editor and turn `文档` into `Workspace` markdown browser/editor with source-file writeback. +- Changed files: + - `src/ui/server.ts` + - `src/runtime/api-docs.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added safe editable file scopes: + - `memory`: memory folders, long-term memory files, runtime digests + - `workspace`: current repo `.md/.markdown` files, excluding `node_modules/.git/dist/coverage` + - Added protected file APIs: + - `GET /api/files` + - `GET /api/files/content` + - `PUT /api/files/content` + - Rebuilt `记忆` page into a file workbench that reads and writes real OpenClaw memory files. + - Rebuilt `docs` page into `Workspace` file workbench for markdown files, with chat structured-ingest kept as a secondary foldout. + - Added client-side file picker, filter, reload, dirty-state hint, and save flow. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `curl /api/files?scope=workspace` + - `curl /api/files?scope=memory` + - `curl /api/files/content` + - `PUT /api/files/content` + - `pm2 restart pandas-control-center` + +## Phase 65 Tasks + calendar merge (2026-03-06) — Completed +- Scope: merge the standalone calendar view into the task page and keep only one primary `任务` navigation entry. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Removed the standalone `Calendar / 日历` navigation item. + - Merged the schedule card into the `任务` page: + - `任务排程` + - `项目泳道` + - `实时活动流` + - `任务泳道` + - Kept backward compatibility: + - `/calendar` now redirects to `/?section=projects-tasks#calendar-board` + - `?section=calendar` now resolves to `projects-tasks` + - Updated section labels so `任务` now covers board + schedule + activity. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + - `GET /calendar?lang=zh` returns `302` to `/?section=projects-tasks&lang=zh...#calendar-board` + +## Phase 66 Prune low-value Attention/History pages (2026-03-06) — Completed +- Scope: remove low-value `待处理 / 历史` pages from primary navigation and keep only actionable signals in overview/tasks. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Removed `Attention / 待处理` and `History / 历史` from the main dashboard navigation. + - Old `?section=alerts` and `?section=replay-audit` now resolve back to `overview`. + - Replaced overview CTA target from `待处理` page to `任务` page with `quick=attention`. + - Kept high-value counts in overview, but stopped sending the user into low-value drilldown pages. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + - `GET /?section=alerts&lang=zh` renders `总览` + +## Phase 67 Restore global workspace markdown coverage (2026-03-06) — Completed +- Scope: restore the workspace page so it covers all agent workspaces and shared markdown files, not just the current `control-center` directory. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Changed workspace editor scan root from current repo directory to the full OpenClaw workspace root. + - Workspace page now includes: + - shared markdown files at workspace root + - all agent workspace markdown files + - control-center markdown files + - tools / plans / learnings markdown files under workspace + - Added category mapping for: + - shared files + - agent files + - control center + - tools + - plans + - learnings +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `GET /api/files?scope=workspace` includes: + - `AGENTS.md` + - `agents/coq/AGENTS.md` + - `agents/dolphin/README.md` + - `control-center/docs/PROGRESS.md` + - `GET /?section=docs&lang=zh` shows the restored global workspace copy + +## Phase 68 Memory ownership filter by agent (2026-03-06) — Completed +- Scope: make the memory page explicit about whose memory is being shown and allow switching by agent. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Rebuilt memory file discovery to cover: + - shared workspace memory files + - shared root memory docs + - agent memory/profile docs under `agents/*` + - agent `memory/` folders when present + - Added memory ownership metadata: + - `共享` + - `Coq` + - `Dolphin` + - `Monkey` + - `Otter` + - `Pandas` + - `Tiger` + - Added agent filter controls on the memory page so the user can switch which agent's memory files are shown. + - Updated memory overview copy to state exactly which memory buckets are available. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `GET /?section=memory&lang=zh` shows: + - `可切换查看:共享、Coq、Dolphin、Monkey、Otter、Pandas、Tiger` + - `GET /api/files?scope=memory` returns memory entries with `facetKey/facetLabel` + +## Phase 69 Memory left-panel hard filter + anti-cache delivery (2026-03-06) — Completed +- Scope: fix the case where selecting an agent (for example `Monkey`) still visually showed `Main` files in the left memory list, and prevent stale page cache from serving old filter behavior. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Hardened client-side memory/workbench filtering: + - keep `hidden` state + - force visibility with inline `item.style.display = visible ? "" : "none";` + - keep CSS hard guard `.file-nav-item[hidden] { display: none !important; }` + - Added no-cache headers for all HTML responses: + - `Cache-Control: no-store, no-cache, must-revalidate, max-age=0` + - `Pragma: no-cache` + - `Expires: 0` + - This prevents browser/proxy from reusing old UI scripts after rollout. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + - `GET /?section=memory` contains: + - agent facets: `Main/Coq/Dolphin/Monkey/Otter/Pandas/Tiger` + - monkey entries with `data-file-facet-key="monkey"` + - filtering logic `item.style.display = visible ? "" : "none";` + - HTML response headers include `cache-control/pragma/expires` no-cache trio + +## Phase 70 Docs left-panel facet strict filter (2026-03-06) — Completed +- Scope: make the docs page behave exactly like memory filtering: clicking an agent must narrow the left file list to only that agent's docs. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added workspace facet options from real workspace agents: + - `listWorkspaceFacetOptions()` => `共享 + each agent` + - Docs workbench now uses strict facet mode: + - `includeAllFacet: false` + - `facetOptions: workspaceFacetOptions` + - Unified facet keys to normalized lowercase on both server render and client filter. + - Strengthened matching logic in file workbench script with `normalizeFacetKey(...)` so case differences cannot break filtering. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + - `GET /?section=docs` contains: + - `facetOptions: workspaceFacetOptions` wiring + - strict facet switcher entries + - normalized facet match logic (`normalizeFacetKey`) + +## Phase 71 Apple-native visual polish v2 (2026-03-06) — Completed +- Scope: raise the overall UI quality bar and remove low-level control styling mistakes such as browser-default black button borders in segmented controls. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Refined the surface system: + - softer glass sidebars + - deeper but cleaner card/panel elevation + - tighter border contrast and inner highlights + - Rebuilt controls into one visual language: + - segmented controls now use `appearance: none` + - no default black borders + - active pill state uses subtle inset + floating highlight + - buttons/inputs/selects/textareas now share radius, focus ring, and material treatment + - Polished workbench surfaces: + - memory/docs sidebars + - file list rows + - editor panel + - compact detail toggles + - Upgraded secondary containers: + - kanban lanes + - queue items + - cron cards + - calendar cards + - quota/subscription blocks + - Marked page generation version as `apple-native-v2`. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - runtime HTML contains: + - `data-ui-polish="apple-native-v2"` + - segmented control reset styles (`appearance: none`, `border: none`, `background: transparent`) + +## Phase 72 Brand rename to OpenClaw Control Center (2026-03-06) — Completed +- Scope: replace user-facing `Mission Control / 总控台` branding with `OpenClaw Control Center / 控制中心`. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated main app title and brand heading to `OpenClaw Control Center`. + - Updated docs index, session drilldown, and audit timeline page titles. + - Replaced remaining user-facing `总控台` copy with `控制中心`. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - live HTML contains `OpenClaw Control Center` + +## Phase 73 Codex avatar remap to robot (2026-03-06) — Completed +- Scope: make the `Codex` agent display as a robot instead of inheriting the generic monkey identity. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added explicit `robot` animal identity with its own accent/title/keywords. + - Bound `codex` to the `robot` identity without changing fallback hashing for unknown agents. + - Added robot Chinese label and robot pixel sprite renderer. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - identity smoke asserts `deriveAgentAnimalIdentity("codex").animal === "robot"` + +## Phase 74 Team page rename to Staff / 员工 (2026-03-06) — Completed +- Scope: rename the `Team` page to `Staff / 员工` and update related user-facing descriptions for consistency. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Navigation label changed from `Team / 团队` to `Staff / 员工`. + - Page copy updated: + - `员工共同目标` + - `员工总览` + - `员工配置明细` + - related fallback/detail strings switched from `智能体名录 / 团队` to `员工`. + - Route key remains `team` for compatibility. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - live nav now shows `员工` + +## Phase 75 English UI localization sweep (2026-03-06) — Completed +- Scope: remove hardcoded Chinese copy leaking into the English UI, starting with Overview and extending through the shared shell, usage, staff, memory, documents, tasks, and subscription surfaces. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Replaced Overview hardcoded Chinese strings with locale-aware copy for: + - primary focus card + - KPI cards + - Cron / heartbeat / tool activity summaries + - inspector sidebar + - page hero blurb and language toggle + - fold toggles and inspector collapse / expand controls + - Localized shared helper functions so English mode no longer falls back to Chinese for: + - task / project state labels + - office card status and summaries + - animal labels + - usage period cards + - subscription quota windows and unavailable states + - data connection status labels + - Localized the editable file workbench shell: + - shared/main facet labels + - file nav metadata + - filter state copy + - reload/save prompts and status text + - Updated smoke tests to assert the new i18n structure instead of brittle Chinese-only source literals. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - runtime smoke: English `overview / docs / memory / usage / team / tasks` pages checked after restart + +## Phase 76 Staff page non-technical default view (2026-03-06) — Completed +- Scope: make the Staff page open with a human-readable summary instead of engineering fields, while keeping technical configuration behind secondary disclosure. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added a dedicated staff summary card builder and renderer for the first screen. + - The default Staff view now shows only: + - employee name + - role定位 + - current status + - what they are working on + - recent output + - whether they are on the schedule + - Converted default status copy to non-technical language: + - `Working / Awaiting review / Needs support / Needs attention / Standing by` + - Kept shared mission and system details in collapsed secondary sections instead of mixing them into the first screen. + - Wired the same client-side pixel avatar renderer into the new staff cards so the overview cards still animate without network polling or token usage. + - Added responsive rules so the staff summary collapses cleanly on narrower layouts. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - runtime smoke after restart on `?section=team&lang=zh` and `?section=team&lang=en` + +## Phase 77 Otter avatar retune (2026-03-06) — Completed +- Scope: redraw the `Otter` staff avatar to better match the requested cute reference style instead of reusing the older generic long-face mammal silhouette. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Rebuilt the `drawOtter()` pixel sprite with: + - rounder head silhouette + - lighter face mask + - blush cheeks + - front paws held together near the mouth + - smaller body so the face reads closer to the supplied icon +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 78 Staff layout density pass (2026-03-06) — Completed +- Scope: remove wasted space in the Staff overview and make the pixel avatars read larger at a glance. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Changed the staff card grid to: + - `3` columns on wide desktop + - `2` columns on mid-width layouts + - `1` column on narrow/mobile layouts + - Reduced card padding and row spacing to cut empty whitespace. + - Enlarged the staff avatar block and switched staff canvases to `256x256`. + - Made the staff stage square so the pixel animal uses more of the visible area instead of sitting small inside a wide stage. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 79 Staff avatar style unification (2026-03-06) — Completed +- Scope: bring the main staff avatars up to the newer `Otter` quality bar so they share one consistent cute chibi pixel language instead of mixing older generic shapes. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Rebuilt the following avatar renderers in the same rounded chibi style family: + - `drawRobot` + - `drawLion` + - `drawTiger` + - `drawPanda` + - `drawMonkey` + - `drawDolphin` + - Preserved `Coq` as-is because its current rooster design was already the closest to the target quality. + - Kept each character distinct while aligning the shared visual grammar: + - larger face area + - smaller body + - tighter eye placement + - softer cheek / muzzle treatment + - front-paw / front-body emphasis where applicable +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 80 Evidence-based staff responsibilities (2026-03-06) — Completed +- Scope: replace guessed animal-based role copy on the Staff page with role labels derived from each employee's real workspace files and local OpenClaw config evidence. +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Removed the hardcoded `staffRoleLabel()` animal mapping that produced incorrect labels such as `tiger -> 快速推进`. + - Added `resolveStaffRoleLabel()` to read evidence from: + - agent workspace files (`IDENTITY.md`, `AGENTS.md`, `README.md`, `MEMORY.md`, `focus.md`, `routines.md`, `inbox.md`) + - local `openclaw.json` + - local cron jobs snapshot + - Mapped verified role evidence into non-technical labels used on the Staff page: + - `monkey` -> `YouTube 视频转长文` + - `dolphin` -> `高价值内容创作` + - `pandas` -> `控制中心开发与交付` + - `coq` -> `每日情报与趋势简报` + - `otter` -> `私人助理与提醒` + - `tiger` -> `安全和更新` + - `main` -> `主控与协调` + - Changed Staff card assembly to await evidence-based role resolution before rendering. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 81 Staff avatar pose differentiation (2026-03-06) — Completed +- Scope: make the staff avatars more detailed and stop reusing the same front-facing pose for every employee except the already-approved `Coq` and `Otter` designs. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Redrew these avatars with distinct poses and more internal detail: + - `robot`: waving with a side tablet + - `lion`: raised paw / captain pose + - `tiger`: guard pose with shield + - `panda`: seated with laptop + - `monkey`: holding a document pad + - `dolphin`: jumping pose with splash + - Left `Coq` and `Otter` unchanged. + - Added per-animal idle motion profiles so the bob/sway cadence is no longer identical across every employee card. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 82 Staff avatar cleanup for main / monkey / dolphin (2026-03-06) — Completed +- Scope: redraw the three avatars that still felt awkward after the pose pass so they look more natural and less strange in the Staff overview. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - `main / lion`: + - replaced the more awkward off-balance raised-paw silhouette with a cleaner centered commander bust + - added a sash + badge treatment so the role still reads as captain/commander without looking distorted + - `monkey`: + - replaced the side-floating document pose with a more stable front-writing composition + - centered the writing pad under the face and simplified the pen hand + - `dolphin`: + - replaced the weirder stretched jump silhouette with a rounder chibi leap + - tightened the head/body proportion and cleaned the splash shape +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 83 Staff avatar retune for monkey / dolphin (2026-03-06) — Completed +- Scope: refine the two remaining staff avatars that still read as awkward after the earlier cleanup, without touching the already-accepted `Coq` and `Otter` designs. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - `monkey`: + - tightened the face and ear silhouette into a more centered chibi head + - rebuilt the notebook area so the writing pose reads clearly from a quick glance + - simplified the pencil and paw placement to avoid the previous odd side-floating composition + - `dolphin`: + - rounded the body into a clearer cute side profile + - strengthened belly / eye / tail contrast so it reads as a dolphin rather than a generic fish blob + - cleaned the splash and jump line so the motion stays readable at card size +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 84 Monkey avatar simplification pass (2026-03-07) — Completed +- Scope: replace the still-awkward monkey writing pose with a cleaner, cuter front-facing chibi composition. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Removed the extra floating pencil composition that still made the monkey avatar read as messy. + - Rebuilt `monkey` as a simpler sticker-like mascot: + - larger centered head + - cleaner ear silhouette + - clearer face / muzzle separation + - smaller body + - front paws holding a notebook instead of an awkward writing gesture + - Kept a small tail curl so it still reads as a monkey without cluttering the pose. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 85 Monkey avatar redraw from visual reference (2026-03-07) — Completed +- Scope: redraw the monkey avatar again against a supplied reference image because the simplified notebook-holding version was still not acceptable. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Removed the notebook-holding pose entirely. + - Rebuilt `monkey` to match the provided mascot direction more closely: + - larger rounded head + - large circular eyes + - heart-like face mask + - tiny standing body + - belly patch + - curled tail + - top hair tuft + - Prioritized a cleaner sticker-like silhouette over role-action storytelling for this one avatar. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 86 Monkey avatar detail polish (2026-03-07) — Completed +- Scope: keep the new reference-based monkey silhouette, but add more internal detail so it feels less flat and generic. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added fur highlights across the head and tail. + - Added inner-ear shading so the ears read less like plain circles. + - Deepened the eyes with internal warm glow pixels and stronger highlights. + - Refined the mouth / smile and added toe details on the feet. + - Added subtle highlight dots on hands, belly area, and tail interior to improve depth without changing the approved silhouette direction. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 87 Monkey avatar reference-fit pass (2026-03-07) — Completed +- Scope: move the monkey avatar closer to the supplied mascot reference instead of merely adding generic detail to the previous version. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Reworked the monkey face proportions to better match the reference: + - larger cheek pads + - lower face mask + - bigger glossy eyes + - smaller centered muzzle + - Simplified and rebalanced the body to keep the head dominant. + - Retuned the tail fill/highlight so it reads as a cleaner curled tail instead of a noisy scribble. + - Kept the top hair tuft, but reshaped it to sit closer to the reference silhouette. +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts` + - `pm2 restart pandas-control-center` + +## Phase 88 Staff avatar export folder (2026-03-07) — Completed +- Scope: export every current staff pixel avatar into a dedicated folder inside the workspace instead of keeping them only inside the browser renderer. +- Changed files: + - `scripts/export-staff-avatars.ts` + - `test/export-staff-avatars.test.ts` + - `package.json` + - `docs/PROGRESS.md` + - `runtime/exports/staff-avatars/*` +- Implementation: + - Added `avatars:export` script to dump staff avatar assets. + - Reused the current embedded sprite runtime from `src/ui/server.ts` by extracting the avatar block directly, so exported files stay aligned with the live UI avatars. + - Exported one SVG per current employee plus: + - `manifest.json` + - `index.html` preview sheet + - Export target: + - `runtime/exports/staff-avatars/` +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `npm run avatars:export` + - `ls runtime/exports/staff-avatars` + +## Phase 89 Staff avatar PNG export + centering fix (2026-03-07) — Completed +- Scope: export staff avatars as PNG in addition to SVG, and fix the long-standing visual drift where some avatars looked slightly right-shifted in both the UI and exported assets. +- Changed files: + - `src/ui/server.ts` + - `scripts/export-staff-avatars.ts` + - `test/export-staff-avatars.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added sprite bound measurement and square-centering for exported assets. + - Added native PNG generation in the export script, without introducing external rendering dependencies. + - Switched the export preview sheet to use PNG thumbnails by default. + - Updated in-app avatar canvas rendering to center based on the actual occupied sprite bounds instead of the full 44x44 source grid. + - This fixes the previous right-biased appearance for asymmetrical sprites such as monkey / tail-heavy characters. +- Verification: + - `npm run build` + - `node --import tsx --test test/export-staff-avatars.test.ts test/ui-render-smoke.test.ts` + - `npm run avatars:export` + - `pm2 restart pandas-control-center` + +## Phase 90 P0 overview + task hub + stability pass (2026-03-07) — Completed +- Scope: deliver the three P0 items only: + - redesign Overview into a tighter decision homepage + - upgrade Tasks into a unified task hub + - strengthen stability / consistency guardrails around the new structure +- Changed files: + - `src/ui/server.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Reworked Overview so the first screen now centers on: + - one primary control posture card + - four KPI cards + - four second-layer decision cards: + - intervention queue + - active staff + - AI burn now + - next scheduled work + - Moved the full Cron execution board out of Overview and into Tasks, while keeping a compact runtime checkpoint in Overview for: + - Cron health + - next run + - heartbeat state + - anchor compatibility for legacy links + - Turned Tasks into a real task hub with: + - a single top-level task hub hero + - decision center + - merged timeline / schedule panel + - full Cron execution board + - task lanes as the main execution area + - project lanes and live activity feed as secondary side panels + - Updated layout and responsive CSS for the new shells and cards: + - `overview-decision-home` + - `overview-decision-grid` + - `task-hub-shell` + - `task-hub-grid` + - `timeline-summary-strip` + - decision-row / busy-staff card treatments + - Bumped the UI polish marker to `apple-native-v3`. + - Expanded smoke coverage so regressions now check: + - new Overview anchors + - new Task Hub anchors + - the updated polish marker + - sprite-centering runtime guards +- Verification: + - `npm run build` + - `node --import tsx --test test/ui-render-smoke.test.ts test/export-staff-avatars.test.ts` + - Runtime UI smoke confirmed the new Overview anchors, Task Hub anchors, polish marker, and sprite-centering guards in a local validation environment. +- Remaining gap: + - None for this phase. The previously unrelated `test/triplet-control.test.ts` failure was fixed in Phase 91. + +## Phase 91 DoD rule drift fix for triplet-control (2026-03-07) — Completed +- Scope: fix the remaining full-suite failure in `test/triplet-control.test.ts` without touching the UI runtime. +- Changed files: + - `scripts/dod-check.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated `dod-check.ts` so its product DoD source audit accepts the current control-center implementation instead of enforcing stale renderer markers. + - Replaced the brittle single-path global-visibility block token with an allowed token group covering: + - the legacy `globalVisibilityStripCard` branch + - the current overview-only `""` branch + - Replaced the brittle Apple-native token check so it now accepts: + - `apple-native-v1` + - `apple-native-v2` + - `apple-native-v3` + - Relaxed the hover-elevation token from one exact inline line to a grouped match that still proves the card hover treatment exists. + - Verified with a reproduced triplet fixture that `scripts/dod-check.ts` now emits `DONE` when the runtime evidence satisfies all gates. +- Verification: + - `npm run build` + - `node --import tsx --test test/triplet-control.test.ts` + - `node --import tsx --test test/**/*.test.ts` + - Reproduced the fixture from `test/triplet-control.test.ts` and verified `scripts/dod-check.ts` writes `status: "DONE"` to `dod-status.json` +- Remaining gap: + - None. Full suite is now green (`55/55`). + +## Phase 92 session execution-chain visibility (2026-03-07) — Completed +- Scope: make `accepted -> sessions_spawn -> child session` visible in the control center without depending on a single CLI history implementation. +- Changed files: + - `src/clients/factory.ts` + - `src/clients/openclaw-live-client.ts` + - `src/contracts/openclaw-tools.ts` + - `src/runtime/session-conversations.ts` + - `src/ui/server.ts` + - `test/session-execution-chain.test.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Re-enabled live read visibility by always constructing `OpenClawLiveClient()` from the tool-client factory while still keeping mutating actions gated elsewhere. + - Added live-session backfill for UI rendering: + - when the read-model snapshot has `0` sessions, the UI now merges in `toolClient.sessionsList()` results so session drilldown, task execution chains, and `/api/sessions` stay connected to real runtime state + - Extended session-history normalization to recognize two new runtime events: + - `accepted` + - `spawn` + - Added `SessionExecutionChainSummary` to both session list items and session detail payloads. + - Implemented dual-path chain inference: + - prefer explicit history evidence when `accepted` / `sessions_spawn` events are present + - fall back to `:run:` child session keys when the installed OpenClaw CLI cannot provide session history + - Fixed raw-text history parsing so text fallback still extracts execution-chain events instead of downgrading them to generic messages. + - Added file-based history fallback for live sessions: + - cache `sessionId` and derived `sessionFile` + - resolve missing `sessionFile` from `~/.openclaw/agents/*/sessions/sessions.json` + - read `*.jsonl` history directly when the installed CLI lacks a `sessions history` implementation + - Hardened live CLI compatibility: + - `cron list` failures now degrade to an empty jobs list instead of breaking monitor/UI routes + - `approvals get` failures now degrade to an empty read result instead of breaking snapshot generation + - `sessions history` failures now degrade to empty history when neither file-based nor CLI-based history is available + - Added a new task-hub card: + - `执行链` / `Execution chain` + - shows whether work was accepted, whether it spawned an isolated child session, and which child session is running + - Added a lightweight overview summary row: + - `隔离执行` / `Isolated execution` + - links back into the task-hub execution-chain card + - Added a new execution-chain evidence card to `Session Drilldown`. + - Extended drilldown history rendering so parent/child session references are visible inline with accepted/spawn events. +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - Local runtime validation confirmed session APIs, overview execution summaries, task-hub execution-chain cards, and session drilldown evidence all render correctly. +- Remaining gap: + - Execution chains are visible and drilldown is verified live; however, most currently resolved chain evidence comes from session-key inference because the installed OpenClaw CLI on this machine does not expose a dedicated `sessions history` subcommand. The file-based history fallback covers compatible sessions without blocking the UI. + +## Phase 93 staff-status consistency fix (2026-03-09) — Completed +- Scope: correct contradictory employee-card states where agents with many idle historical sessions were shown as `Working`, and restore `Scheduled` labels when cron ownership is only observable from runtime session keys. +- Changed files: + - `src/ui/server.ts` + - `test/office-roster.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Fixed office-card activity counting: + - `activeSessions` now uses only non-idle snapshot sessions plus runtime active-session presence + - idle historical sessions no longer force `running` status + - Added cron-owner fallback inference from real session keys: + - parse `agent::cron:...` + - use that mapping when cron catalog jobs omit `ownerAgentId` + - This allows staff cards to show: + - `待命` instead of false `工作中` + - `按排班待命 / 已排班` when the agent is clearly the executor of scheduled cron jobs +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `60/60` passed + - Local runtime validation confirmed the staff page now renders standby and scheduled semantics correctly for cron-owned agents. +- Remaining gap: + - `最近产出` still reflects the latest session snippet even when the agent is currently idle. This is intentional for now, but if needed it can be refined into a separate “最近一次产出” label to avoid implying active work. + +## Phase 94 staff recent-output cleanup and section lazy-loading (2026-03-09) — Completed +- Scope: stop staff cards from surfacing stale internal prompts / runtime scaffolding as `最近产出`, and remove cross-page data loading that made every page slow or timeout. +- Changed files: + - `src/ui/server.ts` + - `test/office-roster.test.ts` + - `test/ui-render-smoke.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Tightened staff recent-output filtering: + - ignore internal runtime context + - ignore untrusted conversation metadata blobs + - ignore write-only/internal mode markers + - ignore stale execution instructions such as the Alex Finn acceptance prompt + - ignore `thinking`/reasoning noise + - Added recent-output normalization: + - structured JSON-like payloads collapse to `最近完成一次任务,并返回结构化结果。` + - file-write confirmations collapse to `最近更新了一份记忆或工作文件。` + - `[[reply_to_current]]` and similar transport wrappers are stripped before display + - Reduced per-agent history scanning cost: + - only inspect the newest few sessions per agent + - shorter history windows for staff cards + - Added section-aware lazy loading inside `renderHtml()`: + - memory/docs workbenches only load on their own pages + - staff detail loading only runs on the staff page + - removed the leftover office/live-session block from the merged staff page + - Parallelized shared async UI data fetches (`cron`, `catalog`, `replay`, `usage`, `roster`) instead of serial awaits. +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `61/61` passed + - Runtime smoke: + - `overview` first response within ~`2.79s` + - `projects-tasks` first response within ~`1.66s` + - `team` first response within ~`6.14s` + - `memory` first response within ~`1.41s` + - `docs` first response within ~`1.35s` + - `usage-cost` first response within ~`0.43s` + - Staff-page smoke confirmed removal of old noise: + - no `继续推进当前目标` + - no `thinking` + - no `OpenClaw runtime context (internal)` + - no `Conversation info (untrusted metadata)` + - Staff-page smoke confirmed normalized outputs: + - `main`: `最近完成一次任务,并返回结构化结果。` + - `dolphin`: `最近完成一次任务,并返回结构化结果。` + - `otter`: `最近更新了一份记忆或工作文件。` + - `tiger`: retains the human-readable update summary +- Remaining gap: + - `team` is responsive again, but its first server render is still heavier than the other pages because it synthesizes per-agent recent output from real session history. Further optimization is possible if we move that aggregation into the background monitor. + +## Phase 95 snapshot-store hardening against concurrent writes (2026-03-09) — Completed +- Scope: eliminate intermittent HTML 500s caused by `runtime/last-snapshot.json` being read while monitor writes were in progress. +- Changed files: + - `src/runtime/snapshot-store.ts` + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Snapshot writes are now atomic: + - write to a uniquely named temp file + - rename into place only after the full payload is written + - Snapshot reads now retry briefly on transient parse failures before surfacing an error. + - Added slow-render diagnostics for server-side HTML generation so future regressions expose which phase is slow instead of looking like a generic timeout. +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `61/61` passed + - `pm2 restart pandas-control-center` + - repeated page probes after restart no longer triggered the previous JSON parse crash +- Remaining gap: + - Slow-render diagnostics are still enabled for renders above 1 second. They are useful during stabilization, but can be removed or downgraded later once performance is consistently stable. + +## Phase 96 monkey visual color refinement (2026-03-09) — Completed +- Scope: change the monkey staff visual from the previous yellow-brown accent to a clearer gold tone. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated the monkey identity accent from `#ffd36e` to `#f4c542`. + - Rebalanced the monkey sprite palette so the fur reads as gold instead of flat brown: + - `fur`: `#c89235` + - `furDark`: `#966521` + - adjusted nose/muzzle tones to stay coherent with the warmer gold palette +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `pm2 restart pandas-control-center` + - team-page smoke confirmed the monkey card still renders after the palette change +- Remaining gap: + - This is a color-only refinement. If needed, the next pass can shift the monkey card background glow to a slightly richer amber so the gold reads even stronger. + +## Phase 97 lion avatar scale normalization (2026-03-09) — Completed +- Scope: fix the `main` lion avatar rendering smaller than the other staff avatars inside the same frame. +- Changed files: + - `src/ui/server.ts` + - `docs/PROGRESS.md` +- Implementation: + - Measured the sprite bounds used by the live renderer and confirmed the lion sprite spans `40px`, while most other staff sprites span `38px` or less. + - Because the renderer uses integer nearest-neighbor scaling, that larger lion envelope dropped it from the `6x` scale bucket to `5x`, making `main` visibly smaller. + - Added a targeted visual span compensation for `lion` so the renderer computes the scale from a slightly reduced effective span while preserving the actual sprite bounds for centering and panel layout. +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `pm2 restart pandas-control-center` + - runtime smoke confirmed the team page still renders and the lion compensation is present in the embedded renderer +- Remaining gap: + - This pass normalizes the lion size in the live control-center UI. Exported avatar assets still use the raw sprite bounds, which is acceptable for now because the user issue was about the on-page avatar scale. + +## Phase 98 otter avatar scale normalization (2026-03-09) — Completed +- Scope: fix the `otter` avatar reading visually smaller than the other staff avatars inside the same employee-card frame. +- Changed files: + - `src/ui/server.ts` + - `scripts/export-staff-avatars.ts` + - `test/export-staff-avatars.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Confirmed `otter` stayed at the same integer render scale as several other avatars, but its drawing occupies a narrower, more compact silhouette, so it still read smaller inside the same panel. + - Added a targeted visual span compensation for `otter` (`0.9`) in the live avatar renderer so it scales up one notch and matches the surrounding staff cards more closely. + - Extended the embedded avatar-runtime extractor so automated tests can verify the live compensation map instead of relying on brittle source-text matching. +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `pm2 restart pandas-control-center` + - team-page runtime smoke confirmed the embedded renderer now includes `otter: 0.9` +- Remaining gap: + - This fixes the live employee-page rendering. Exported standalone avatar assets still use raw sprite bounds and do not yet apply visual-size compensation, which is acceptable unless the user wants perfectly equalized export thumbnails too. + +## Phase 99 staff status/current-work consistency fix (2026-03-09) — Completed +- Scope: remove contradictory employee-card states such as `工作中` paired with `按排班待命`. +- Changed files: + - `src/ui/server.ts` + - `test/office-roster.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Extracted staff current-work text generation into a dedicated `staffCurrentWorkLabel(...)` helper. + - Tightened the fallback order so only `idle/inactive` scheduled staff show `按排班待命`. + - Running staff with no explicit task title now show: + - `正在执行排班任务` when they are currently active and have scheduled cron work + - `正在处理实时会话` when they are active without cron-backed schedule evidence + - `正在处理当前工作` as the generic final fallback +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `pm2 restart pandas-control-center` + - runtime smoke confirmed the live team page no longer needs to pair `工作中` with `按排班待命` +- Remaining gap: + - This pass fixes the logic conflict. If needed later, the staff card can still be refined further so `正在处理什么` prefers a more concrete task/cron label instead of the generic active-session fallback. + +## Phase 100 staff current-work naming upgrade (2026-03-09) — Completed +- Scope: replace abstract employee-card work copy with concrete task or cron names whenever the runtime has them. +- Changed files: + - `src/ui/server.ts` + - `test/office-roster.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated `staffCurrentWorkLabel(...)` so the fallback order is now: + - explicit task title from the live office focus list + - concrete cron job name from `execution.cronJobNames` + - approval / blocked labels + - live-session generic fallback only when no task/cron name exists + - Removed the previous abstract scheduled-work copy from the primary path: + - no more `按排班待命` + - no more `正在执行排班任务` + when a concrete cron name is available. +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `pm2 restart pandas-control-center` + - employee-page smoke after restart confirms the page serves and includes the updated current-work behavior +- Remaining gap: + - If an active session has no linked task title and no resolvable cron name, the card still falls back to generic live-session text. That is intentional because there is no trustworthy concrete name to show in that case. + +## Phase 101 staff card current-vs-next semantics fix (2026-03-09) — Completed +- Scope: stop employee cards from implying an idle agent is currently executing a cron job just because a scheduled job name exists. +- Changed files: + - `src/ui/server.ts` + - `test/office-roster.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Upgraded the staff-card work field from a single string to a `(label, value)` pair. + - Running agents still show `正在处理什么` / `Working on`. + - Idle or inactive agents with a known scheduled cron now show `下一项` / `Next up` and the concrete cron name. + - This preserves concrete job names without falsely implying that an idle agent is actively executing them. +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - `pm2 restart pandas-control-center` + - runtime smoke confirmed the live staff page serves with the updated semantics +- Remaining gap: + - The page now distinguishes current work vs next scheduled work semantically. If needed later, the next refinement is to show the exact next scheduled time beside the cron name. + +## Phase 102 residual running status cleanup (2026-03-09) — Completed +- Scope: stop employee cards from showing `工作中` when a session still says `running` but recent history already contains an explicit standby/skip stop sequence. +- Changed files: + - `src/ui/server.ts` + - `test/office-roster.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Added residual-stop detection over recent session history. + - The staff card now downgrades a `running` session to `待命` when the recent history shows: + - an explicit stop/standby directive, and + - only residual follow-up noise afterward (`REPLY_SKIP`, `ANNOUNCE_SKIP`, announce step, `thinking`) + - Filtered residual stop markers out of `最近产出` so they no longer appear as if they were meaningful user-visible output. +- Verification: + - `npm run build` + - `node --import tsx --test test/**/*.test.ts` + - added regression coverage for `running` sessions that should be treated as already stopped +- Remaining gap: + - This cleanup is currently applied to the employee-card layer. If needed later, the same residual-stop semantics can also be propagated into broader session/overview state aggregation. + +## Phase 103 nested session history parsing fix (2026-03-09) — Completed +- Scope: fix stale `running` employee states caused by mis-parsing OpenClaw's nested `message.role` and `message.content[]` history payloads. +- Changed files: + - `src/runtime/session-conversations.ts` + - `test/session-execution-chain.test.ts` + - `test/office-roster.test.ts` + - `docs/PROGRESS.md` +- Implementation: + - Updated session-history parsing to prefer nested `message.role` over the top-level `type: "message"` envelope. + - Stopped treating top-level `type` as a role unless it is a real role-like value (`user`, `assistant`, `system`, `tool`). + - Added nested content extraction that prefers visible `text` blocks over `thinking` blocks inside `message.content[]`. + - This prevents `thinking + REPLY_SKIP` from being merged into a non-residual string and restores correct stop-sequence detection for employee cards. +- Verification: + - `npm run build` + - `node --import tsx --test test/session-execution-chain.test.ts test/office-roster.test.ts` + - added regressions for nested OpenClaw history envelopes and residual-running downgrade from real nested payloads +- Remaining gap: + - Employee-state cleanup now has correct nested history semantics. Broader session lists and drilldowns still rely on the underlying runtime state field for their primary state label, which can remain stale until the upstream runtime closes the session state. diff --git a/docs/PUBLISHING.md b/docs/PUBLISHING.md new file mode 100644 index 0000000..89b3c65 --- /dev/null +++ b/docs/PUBLISHING.md @@ -0,0 +1,54 @@ +# Publishing Guide + +This project is safest to publish as its own standalone repository. + +## Recommended release boundary +- Publish only the `control-center/` directory. +- Do not publish the larger parent workspace/repository. +- Keep runtime output, build output, local env files, and internal planning artifacts out of the public repo. + +## Best-practice flow + +### 1. Work inside `control-center/` +All release checks and commits should happen from this directory. + +### 2. Run the public-release audit +```bash +npm run release:audit +npm run build +npm test +npm run smoke:ui +``` + +### 3. Keep the first public repo safe +Use these defaults for the public project: +- `READONLY_MODE=true` +- `LOCAL_TOKEN_AUTH_REQUIRED=true` +- `APPROVAL_ACTIONS_ENABLED=false` +- `IMPORT_MUTATION_ENABLED=false` + +### 4. Create a standalone local git repo here +If this directory is not already its own git repo: +```bash +git init -b main +git add . +git commit -m "Initial public release" +``` + +### 5. Create an empty GitHub repository +Create a new empty repository on GitHub for `control-center` only. + +### 6. Connect and push +```bash +git remote add origin +git push -u origin main +``` + +## Pre-push checklist +- README renders correctly on GitHub +- screenshots load +- no absolute personal home paths +- no hard-coded secrets or live tokens +- no runtime artifacts +- no internal-only planning or workflow files +- tests/build/smoke all pass diff --git a/docs/RUNBOOK.md b/docs/RUNBOOK.md new file mode 100644 index 0000000..948a1ae --- /dev/null +++ b/docs/RUNBOOK.md @@ -0,0 +1,442 @@ +# Mission Control Runbook + +## 1) Safety defaults +- Keep `READONLY_MODE=true` unless explicitly validating live reads. +- Keep `LOCAL_TOKEN_AUTH_REQUIRED=true` by default. +- Keep `APPROVAL_ACTIONS_ENABLED=false` by default. +- Keep `APPROVAL_ACTIONS_DRY_RUN=true` by default. +- Keep `IMPORT_MUTATION_ENABLED=false` by default. +- Keep `IMPORT_MUTATION_DRY_RUN=false` by default. +- Never modify `~/.openclaw/openclaw.json` from this project. + +## 2) Startup +1. `npm run build` +2. `npm test` +3. `npm run validate` +4. `npm run dev` (smoke monitor run) +5. Optional UI mode: `UI_MODE=true npm run dev` + - In restricted sandboxes, `listen EPERM` on `127.0.0.1:*` is environment-only (socket bind restriction), not a control-center functional regression. +6. Optional continuous monitor: `npm run dev:continuous` + +## 3) Enable live mode safely +1. Confirm baseline safety checks: + - `READONLY_MODE=true` + - `LOCAL_TOKEN_AUTH_REQUIRED=true` + - `APPROVAL_ACTIONS_ENABLED=false` + - `APPROVAL_ACTIONS_DRY_RUN=true` + - `IMPORT_MUTATION_ENABLED=false` + - `IMPORT_MUTATION_DRY_RUN=false` + - `npm run build` passes +2. Enable live reads only (no approval execution): + - Run with `READONLY_MODE=false` and keep: + - `APPROVAL_ACTIONS_ENABLED=false` + - `APPROVAL_ACTIONS_DRY_RUN=true` +3. Validate behavior in UI: + - `GET /snapshot` + - `GET /tasks` + - `GET /exceptions` +4. Only if explicitly required, enable approval execution: + - `READONLY_MODE=false` + - `APPROVAL_ACTIONS_ENABLED=true` + - `APPROVAL_ACTIONS_DRY_RUN=false` +5. After any live test, return to defaults immediately: + - `READONLY_MODE=true` + - `LOCAL_TOKEN_AUTH_REQUIRED=true` + - `APPROVAL_ACTIONS_ENABLED=false` + - `APPROVAL_ACTIONS_DRY_RUN=true` + - `IMPORT_MUTATION_ENABLED=false` + - `IMPORT_MUTATION_DRY_RUN=false` + +## 4) Local token auth gate +- Protected operations require local token auth when `LOCAL_TOKEN_AUTH_REQUIRED=true` (default): + - all state-changing routes (`POST`/`PATCH` APIs and form ack route) + - task heartbeat execution route (`POST /api/tasks/heartbeat`) + - import/export routes with side effects (`POST /api/import/dry-run`, `POST /api/import/live`, `GET /export/state.json`, `GET /api/export/state.json`) + - protected command modes (`command:backup-export`, `command:import-validate`, `command:acks-prune`, `command:task-heartbeat`) +- Configure explicit gate token: + - `LOCAL_API_TOKEN=` +- Send token from client: + - `x-local-token: ` + - or `Authorization: Bearer ` +- If `LOCAL_API_TOKEN` is unset while gate is enabled: + - protected operations are blocked by design. + +## 5) Approval actions (runtime-gated) +- Endpoints (also require local token auth): + - `POST /api/approvals/:approvalId/approve` + - `POST /api/approvals/:approvalId/reject` (requires JSON body `{"reason":"..."}`) +- Gate logic: + - If `APPROVAL_ACTIONS_ENABLED=false`: blocked (no execution) + - If `APPROVAL_ACTIONS_DRY_RUN=true`: simulated (no execution) + - If `READONLY_MODE=true`: blocked (no execution) + - Real execution only when: + - `APPROVAL_ACTIONS_ENABLED=true` + - `APPROVAL_ACTIONS_DRY_RUN=false` + - `READONLY_MODE=false` +- All attempts are written to `runtime/approval-actions.log` as JSON lines. + +## 6) Project + Task APIs +- `GET /projects`: project list with optional filters: + - `status=planned|active|blocked|done` + - `owner=` + - `projectId=` +- `GET /api/projects`: compatibility endpoint with same query filters. +- `POST /api/projects`: create project in `runtime/projects.json`. +- `PATCH /api/projects/:projectId`: update `title`, `status`, `owner`. +- `GET /tasks`: flattened task list with optional filters: + - `status=todo|in_progress|blocked|done` + - `owner=` + - `project=` +- `GET /api/tasks`: compatibility endpoint with the same query filters. +- `POST /api/tasks`: create task in `runtime/tasks.json`. +- `PATCH /api/tasks/:taskId/status`: status transition. +- `GET /api/tasks/heartbeat`: recent heartbeat runs from `runtime/task-heartbeat.log`. +- `POST /api/tasks/heartbeat`: execute assigned-backlog heartbeat pickup (supports `dryRun` + `maxTasksPerRun` override). +- Mutation endpoints above require local token auth. +- Validation: + - Strong schema checks for required fields, enums, and bounded field lengths. + - Task create/update validates linked `projectId` against `runtime/projects.json`. + - Invalid payloads return 4xx with `issues`. + - Unknown project/task IDs return 404. + +### Heartbeat backlog automation +- Monitor cycles now include a task heartbeat pass that checks the board for assigned backlog tasks (`status=todo` + assigned owner). +- Default gate posture: + - `TASK_HEARTBEAT_ENABLED=true` + - `TASK_HEARTBEAT_DRY_RUN=true` + - `TASK_HEARTBEAT_MAX_TASKS_PER_RUN=3` +- Live promotion (`todo -> in_progress`) requires: + - heartbeat dry-run disabled (`TASK_HEARTBEAT_DRY_RUN=false` or request body `{"dryRun":false}`) + - local token configured when `LOCAL_TOKEN_AUTH_REQUIRED=true` +- Evidence file: + - `runtime/task-heartbeat.log` (JSONL; includes selected/executed counts and gate mode) + +## 7) Commander exceptions + action queue +- Endpoint: `GET /api/commander/exceptions` +- Summarizes: + - blocked sessions + - errored sessions + - pending approvals + - over-budget evaluations + - tasks due (`dueAt <= now`, excluding `done`) +- Routed feed endpoint: `GET /exceptions` + - Levels: `info`, `warn`, `action-required` + - Routes: `timeline`, `operator-watch`, `action-queue` +- Notification center endpoint: `GET /api/action-queue` + - Derived from `GET /exceptions` action-required route entries + - Includes acknowledgement state from `runtime/acks.json` + - Includes `links[]` with relevant session/task/project endpoints for operator jump navigation +- Acknowledge endpoint: `POST /api/action-queue/:itemId/ack` + - Persists/updates local ack entry in `runtime/acks.json` + - Optional expiry controls: `ttlMinutes` (1..10080) or `snoozeUntil` (future ISO timestamp) + - `ttlMinutes` and `snoozeUntil` are mutually exclusive + - UI form uses minimal POST to `/action-queue/ack` + - Requires local token auth + +## 8) Session visibility APIs +- `GET /sessions` / `GET /api/sessions` + - Local readonly view combining session list with latest history snippets per session + - Query filters: + - `state=idle|running|blocked|waiting_approval|error` + - `agentId=` + - `q=` + - pagination: `page`, `pageSize`, `historyLimit` +- `GET /sessions/:id` + - Session detail + usage status + recent history entries (`historyLimit` optional) +- `GET /api/sessions/:id` + - Explicit API alias for session detail JSON +- `GET /session/:id` + - UI drill-down page rendering latest messages and tool events per session + - History content is safely truncated for readonly rendering + +## 9) Audit timeline +- `GET /audit` renders newest-first runtime timeline view with severity filter. +- `GET /api/audit` returns JSON timeline. +- Data sources: + - `runtime/timeline.log` + - `runtime/approval-actions.log` + - `runtime/operation-audit.log` + - current snapshot (`runtime/last-snapshot.json`) +- Supported severities: `all`, `info`, `warn`, `action-required`, `error`. + +## 10) Graph + export APIs +- `GET /graph` + - Returns project-task-session-agent linkage graph JSON (nodes + edges + counts) +- `GET /export/state.json` + - Bundles current sessions/tasks/projects/budgets/exceptions into one portable JSON document + - Requires local token auth + - Writes timestamped copies to: + - `runtime/export-snapshots/*.json` (replay/debug index) + - `runtime/exports/*.json` (backup/import target bundles) + +## 11) Commander digest +- Every monitor run writes/refreshes the current day digest files: + - `runtime/digests/YYYY-MM-DD.json` + - `runtime/digests/YYYY-MM-DD.md` +- Digest summarizes sessions, approvals, projects, tasks, budgets, alerts, and top exceptions. + +## 12) Phase 7 operations +- Pixel adapter: + - endpoint: `GET /view/pixel-state.json` + - source: snapshot + local project/task/session links +- Notification policy preview: + - config file: `runtime/notification-policy.json` + - endpoint: `GET /notifications/preview` + - optional simulation: `GET /notifications/preview?at=` +- Cron overview: + - endpoint: `GET /cron` + - reports next run + per-job health + monitor lag summary +- System health: + - endpoint: `GET /healthz` + - includes build info + snapshot freshness + monitor lag +- Digest renderer: + - endpoint: `GET /digest/latest` + - renders latest markdown digest file as HTML + +## 13) Phase 8 operations +- Operator dashboard polish: + - compact status strip toggle persisted in `runtime/ui-preferences.json` + - quick filter chips (`all`, `attention`, task states) + - home/dashboard query choices auto-persist as default UI preferences +- UI preference APIs: + - `GET /api/ui/preferences` + - `PATCH /api/ui/preferences` +- Search APIs (safe substring + bounded limits): + - `GET /api/search/tasks?q=&limit=` + - `GET /api/search/projects?q=&limit=` + - `GET /api/search/sessions?q=&limit=` + - `GET /api/search/exceptions?q=&limit=` +- Replay/debug index API: + - `GET /api/replay/index?timelineLimit=&digestLimit=&exportLimit=&from=&to=` + - Data sources: `runtime/timeline.log`, `runtime/digests/`, `runtime/export-snapshots/`, `runtime/exports/` + - `from` / `to` are optional ISO date-time filters for replay artifact windows + - response includes per-source replay filter stats (`total`, `returned`, `filteredOut`, `filteredOutByWindow`, `filteredOutByLimit`, `latencyMs`, `latencyBucketsMs(p50,p95)`, `totalSizeBytes`, `returnedSizeBytes`) +- API docs summary endpoint: + - `GET /api/docs` +- Telemetry correlation: + - every response returns `x-request-id` header + - JSON responses include `requestId` + - error logs include requestId for correlation + +## 14) Phase 9 operations +- Final integration checklist endpoint: + - `GET /done-checklist` (alias: `GET /api/done-checklist`) + - combines docs-aligned checks + runtime capability checks + - includes readiness scoring for: + - observability + - governance + - collaboration + - security +- Commander feed polish: + - `/exceptions` now returns items sorted by severity first (`action-required` > `warn` > `info`), then newest by event timestamp. +- Backup/export command mode: + - `npm run command:backup-export` + - requires `LOCAL_API_TOKEN` when `LOCAL_TOKEN_AUTH_REQUIRED=true` + - writes timestamped bundle under `runtime/exports/*.json` +- Import dry-run validator: + - command: `npm run command:import-validate -- runtime/exports/.json` + - API: `POST /api/import/dry-run` + - command/API require local token auth when `LOCAL_TOKEN_AUTH_REQUIRED=true` + - validation is dry-run only; no state mutation. +- Ack prune command mode: + - command: `npm run command:acks-prune` + - optional dry-run: `COMMAND_ARG=--dry-run npm run command:acks-prune` + - command requires local token auth when `LOCAL_TOKEN_AUTH_REQUIRED=true` + - prunes expired acknowledgement records from `runtime/acks.json` +- Ack prune preview API: + - API: `GET /api/action-queue/acks/prune-preview` + - requires local token auth when `LOCAL_TOKEN_AUTH_REQUIRED=true` + - returns `before/removed/after` counts only (no write) +- Optional live import mutation endpoint: + - API: `POST /api/import/live` + - HIGH RISK and disabled by default (`IMPORT_MUTATION_ENABLED=false`) + - requires local token auth and `READONLY_MODE=false` for live apply + - `dryRun=true` forces non-mutating validation path on this endpoint +- Operation audit: + - import dry-run + import apply + backup export + ack prune actions are appended to `runtime/operation-audit.log`. + +## 15) UX v2 operator navigation +- Home dashboard now uses section tabs via `/?section=` with six supported values: + - `overview` + - `office-space` + - `projects-tasks` + - `alerts` + - `replay-audit` + - `settings` +- Layout intent: + - left rail: major section navigation + - center panel: section content + - right rail: office context + quick shortcuts +- Office-space behavior: + - auto-derives agent roster from sessions, task owners, project owners, and agent budget entries + - maps each agent to a deterministic animal identity from name semantics + - reports zone + workload summary ("busy on what") per agent +- Empty states: + - user-facing empty blocks should render as `Not activated yet` + - avoid exposing raw zero-heavy debug values when no actionable signal exists + +## 16) Usage and cost observability (Phase 22) +- New route surfaces: + - `GET /usage-cost` (redirects to `/?section=usage-cost`) + - `GET /api/usage-cost` (JSON snapshot) +- Dashboard placement: + - card-level pulse on `Overview` + - dedicated `Usage & Cost` section in left sidebar navigation + - right-rail usage summary card +- Usage adapter sources: + - live snapshot status data (`sessions + session_status`) + - OpenClaw session runtime stores (`~/.openclaw/agents/*/sessions/sessions.json` + `*.jsonl`) for real request/tokens/cost windows (`today/7d/30d`) and per-source breakdown + - digest history (`runtime/digests/*.json`) as fallback trend source when runtime request events are unavailable + - optional model context catalog (`runtime/model-context-catalog.json`) for context-window percentages +- Disconnected metrics policy: + - if source is missing, render `Data source not connected` (do not fabricate zero values) + - if runtime source is connected but usage is truly zero, render zero values (not placeholders) + - context-window limits prefer live session context metadata and fallback to model catalog only when needed +- Settings connector checklist: + - model context catalog + - digest history continuity (fallback) + - runtime request/event source + - cost budget limit source + - provider attribution refinement + +## 19) Mission Control v3 operations (Phase 25) +- Navigation and IA (UI sections): + - `overview` -> Command Deck + - `usage-cost` -> Usage & Billing + - `office-space` -> Pixel Office + - `projects-tasks` -> Work Board + - `alerts` -> Decisions + - `replay-audit` -> Timeline + - `settings` -> Control Room +- Mac parity surfaces panel: + - shown in Command Deck with per-surface status + route links + - covers sessions, approvals, cron, projects/tasks, usage/cost, replay/audit, health/digest, export/import safety, and pixel adapter +- Full office roster behavior: + - best-effort config source: `~/.openclaw/openclaw.json` (read-only) + - adapter module: `src/runtime/agent-roster.ts` + - fallback keeps known agents visible even when no active runtime sessions exist +- Subscription usage/remaining behavior: + - adapter module: `src/runtime/usage-cost.ts` + - source probes (best effort): + - `runtime/subscription-snapshot.json` + - `~/.openclaw/subscription.json` + - `~/.openclaw/billing/subscription.json` + - `~/.openclaw/billing/usage.json` + - `~/.openclaw/usage/subscription.json` + - contract states: + - `connected`: consumed/remaining/limit/cycle shown + - `partial`: file detected but fields incomplete + - `not_connected`: explicit connect hint shown (no fake zeros) + +## 17) Runtime artifacts +- `runtime/last-snapshot.json`: latest read model snapshot. +- `runtime/timeline.log`: monitor run deltas. +- `runtime/projects.json`: local project store. +- `runtime/tasks.json`: local task store. +- `runtime/budgets.json`: budget policy defaults and per-scope overrides. +- `runtime/notification-policy.json`: notification quiet-hours + severity-route policy. +- `runtime/model-context-catalog.json`: optional model context-window map (`match/contextWindowTokens/provider`) for context-usage percentages. +- `runtime/ui-preferences.json`: dashboard preference state (`compactStatusStrip`, `quickFilter`, `taskFilters`). +- `runtime/acks.json`: notification action-queue acknowledgements. +- `runtime/approval-actions.log`: audit trail for approval action attempts. +- `runtime/operation-audit.log`: audit trail for import dry-run, import apply, backup export, and ack prune actions. +- `runtime/digests/`: daily commander digest JSON + Markdown. +- `runtime/export-snapshots/`: timestamped state export snapshots for replay/debug. +- `runtime/exports/`: timestamped export bundles for backup + import validation. + +## 18) Rollback steps +1. Restore safe runtime mode: + - `READONLY_MODE=true` + - `LOCAL_TOKEN_AUTH_REQUIRED=true` + - `APPROVAL_ACTIONS_ENABLED=false` + - `APPROVAL_ACTIONS_DRY_RUN=true` +2. Revert only `control-center/` code changes (git revert or selective checkout from known-good commit). +3. Rebuild and smoke test: + - `npm run build` + - `npm run dev` +4. Verify rollback signals: + - `/projects` and `/api/projects` return expected payloads + - `/tasks` and `/api/tasks` return expected payloads + - `/api/action-queue` returns valid JSON and ack state + - `/exceptions` and `/api/commander/exceptions` return valid JSON + - `/view/pixel-state.json` returns valid adapter JSON + - `/notifications/preview` returns policy evaluation JSON + - `/cron` and `/healthz` return health payloads + - `/digest/latest` renders latest digest page + - `/api/docs` returns route/schema summary + - `/api/replay/index` returns timeline/digest/export index + - `/api/search/*` endpoints return bounded matches + - UI project board/task board/action queue sections match expected view +5. If budget behavior regressed, restore `runtime/budgets.json` to the last known-good content. +6. If notification routing behavior regressed, restore `runtime/notification-policy.json` to last known-good. + +## 19) Troubleshooting +- Build failures: + - Run `npm run build` and fix TypeScript errors first. +- Validation failures: + - Run `npm run validate` and inspect failing assertions. +- Empty dashboard: + - Confirm `runtime/last-snapshot.json` exists (created by `npm run dev`). +- Health endpoint stale: + - confirm monitor wrote a fresh line in `runtime/timeline.log` + - rerun `npm run dev` to regenerate snapshot and timeline tick +- UI mode bind fails with `listen EPERM`: + - classify as environment-only in restricted sandboxes where localhost bind is blocked + - re-run `UI_MODE=true npm run dev` in unrestricted host runtime for bind + `/healthz` verification + +## 20) Operational Checklist (Phase 22) +- [ ] Safety gates unchanged: + - `READONLY_MODE=true` + - `LOCAL_TOKEN_AUTH_REQUIRED=true` + - `APPROVAL_ACTIONS_ENABLED=false` + - `APPROVAL_ACTIONS_DRY_RUN=true` + - `IMPORT_MUTATION_ENABLED=false` + - `IMPORT_MUTATION_DRY_RUN=false` + - `LOCAL_API_TOKEN` set explicitly for protected operations. +- [ ] `runtime/notification-policy.json` exists and is valid JSON. +- [ ] `runtime/ui-preferences.json` exists and is valid JSON. +- [ ] `GET /view/pixel-state.json` returns `rooms/entities/links`. +- [ ] `GET /notifications/preview` returns quiet-hours + route preview. +- [ ] `GET /cron` returns next-run and health summary. +- [ ] `GET /healthz` returns build/snapshot/monitor status fields. +- [ ] `GET /digest/latest` renders latest digest markdown. +- [ ] `GET /api/ui/preferences` + `PATCH /api/ui/preferences` work and persist. +- [ ] `GET /api/search/tasks|projects|sessions|exceptions` support `q` + bounded `limit`. +- [ ] Home dashboard search panel is visible and returns scoped results for `tasks|projects|sessions|exceptions`. +- [ ] `GET /api/replay/index` includes timeline, digests, export snapshots, and export bundles. +- [ ] `GET /api/replay/index?from=&to=` applies optional ISO time-window filtering. +- [ ] `GET /api/replay/index` includes replay `stats` with `total/returned/filteredOut` (+ window/limit breakdown) and per-source latency/size indicators. +- [ ] Home dashboard replay/export visibility panel shows counts + latest snapshot/bundle labels. +- [ ] Home dashboard shows section navigation for: + - Overview, Usage & Cost, Office Space, Projects/Tasks, Alerts, Replay/Audit, Settings. +- [ ] Office Space section renders per-agent cards with: + - semantic animal identity + - status label + - zone placement + - "busy on what" summary. +- [ ] Empty lists/cards use `Not activated yet` operator copy (instead of raw `none` placeholders). +- [ ] `GET /api/usage-cost` returns: + - periods (`today/7d/30d`) + - context windows + - breakdown by agent/project/model/provider + - budget burn-rate status + - connector TODO list. +- [ ] `runtime/model-context-catalog.json` exists or Settings TODO explicitly shows the missing connector. +- [ ] Usage & Cost section displays disconnected metrics as `Data source not connected` instead of fake zeros. +- [ ] `GET /api/docs` returns route/schema summary. +- [ ] Home import/safety guard table shows explicit disabled/enabled badges. +- [ ] Guard/checklist doc refs are clickable and resolve via `/docs/*`. +- [ ] `GET /docs` renders local docs index. +- [ ] `GET /docs/runbook|architecture|progress|readme` return markdown content. +- [ ] `GET /done-checklist` returns checklist + readiness scores. +- [ ] `POST /api/import/dry-run` validates bundles with no mutation. +- [ ] `POST /api/import/live` stays blocked unless explicit env gate + token are enabled. +- [ ] `POST /api/action-queue/:itemId/ack` supports optional `ttlMinutes` / `snoozeUntil` and expired acks re-open queue items. +- [ ] `GET /api/action-queue/acks/prune-preview` returns token-gated stale-ack prune counts with no mutation. +- [ ] `npm run command:backup-export` writes a bundle to `runtime/exports/`. +- [ ] `npm run command:acks-prune` removes expired entries from `runtime/acks.json` (or reports no-op in dry-run). +- [ ] import dry-run + import apply + backup export + ack prune actions write entries in `runtime/operation-audit.log`. +- [ ] responses include `x-request-id` and JSON `requestId`. +- [ ] `npm test` passes. +- [ ] `npm run build` passes. +- [ ] `npm run dev` smoke passes. diff --git a/docs/assets/overview-en.png b/docs/assets/overview-en.png new file mode 100644 index 0000000000000000000000000000000000000000..b0b2c47d561da26a75fdb3b4ca4cbfee10d797bc GIT binary patch literal 686001 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

N`wEKS^PZ?3 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 mItOd7r>f1pka4)`YY!vG7RQL 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

IxQ{N>Ex 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 I=^} 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

JhDV;M$Z` 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�Af86)Y@swO+ohhtLD@C_gca5F} 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

}KNmp7{No?I(qn5bEb4(;P)rbuyJ+0v%vrr$ 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 y83vK}_!#ai7gzZYddp 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


_B8`X`tCe=%4eb8ZYUC?e|WY61Fs$=V(o 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

>YabXW#a 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�gq?X{Z2(JXnrdE16lueL>`$|YFo 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%0D~uJ}~ChHCG6j9FLFx^E0EkKxf8rpt_z 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

$)1XT2dNl#?KZ3gxq3-i%vO6VJUulu69x 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

CB$H;k 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 z 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%0DOsi$;z<_>bgAQD9Whicm0` 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 >s_W$m(+-(+a# zgD!jOvyLQw+*-fj2s(GX5U?#Zc% zr3SresJ1kaDYsb(SX6|){D32rdGM3Z>RfgGYsuk}uWURc9l!k6m|u`0=lGfT^z(iR~+TY)s#W`lDq(*Aztx>rUki{Emzb+`4t^X9ue=Rq+h7L|^Af4S+9-9k* zU_8jg;JcMc8%-^DdY00R4W|myc9~7EBhxB#0HIm!r}<&9OIRtq!ShHedh8RAWWCD zKo|=nsq(jhl)`NRyKfnJ9Nn)^b~8st*lFvo={;Z6!&Z0CoUT5uK6Hti-?TW`-$P#Q zO52n8oW;#{RdRqC;k)fF*vqt@P<l;AA`=U1<-EA0rgVs!xxRY#JhWOrHuqE5U^vqHa~HCB z@&|My*QCVyywVBz;zJ zq0X?%ik>bV3d~Qql|oa*W%LxEeuN-MzU91k!nKqao@Oq6{|^&0B}uTsG{&R(K}mzJk*UDOGX;9DlJqJ&uWf3d8^QGF)L*ns%C^ z^u0n3ulW>nMf5M30EK6-apBC0rmBq7;hrwgOjvA;LhaKsdUvJd?cNEh0%f*?KPm6Q zMZ|NOwrObZU+=q*vwkW#VSV>A6AFa+&XsVu^sE}emre_$%J6}7!IQmsllmGylldCE!=eQ>Ai5yW> z%!p|+Jqe5Y&Jd@jszK>Xed?5ug@1+7B63Da?JLbISP5rFW>nSuonQe>L~-gHPTsnW zyRDf({aip6$>oY3OHYvxj^HnV_2(#-#|@Z*72JRm#K&s$b3MbV5MI@g3L^yD67eNH zwqll8m?8uil!=^&?q!QqvxZ$uez|(OCKj+JL$PK0Y9lcfvnc-6wthhOLwyXHH`q8_ zU;_+` zbrUaB;0>Z(sMoTj_4Q5*XjqyZZAl5N$pe1)*X!mu3y#pPvm)oSUEzvnRP2nbC@ShU zuFTH+`LnXR+F@z_v{w=2vv#SF&{hmTTCS>aa|?0_?lIr^87JR_*p{QR=p%A!-^6)b z!kv}&{mYJ7m!bgHRd?6hls+%{$;yyEz1M+33-5&9aqo37NO`j#EUl^%393%{AMF9q zIDMV~K6&oZ5B>VpFnFyc&}uvU27^1zS|Oe6Y;;=7<4O1`WTR8zJzic{jjl#wKWCv@ zWU}5-j@lxY>2-X`56duSFb~{yV=7>+= zl}7yMWlWy(TH`FA(yLvpI;~`(z|W!Iz+oq$YGvI{p$eNRNcA|=aXjV1r<2U#V#FD7 zXAddMj9NIH!VLUEZlS%2-@$~T{1Jp*P)R- zKm6yLB2>%luO|1${1EMk`JVM*XrZ>g9^r2C5@*mhx~hj`Wk#`GIxa@@=;e%-#FI1B%-&&7kDPhq;1(3qb&o~hX%T+3(HU3@Enw_SD=HaQ<@*SarWP&aYts%R{{ zykIf6vY`2_9u@fvpNly zxzeQw-`+XfbSX_r+qdD%XQt&aWB$*Bqw2}$)>sti+*0(KXd->pQJWt~HKCQV_aZ3eoucFv%0ZRkAJAKvK!H0ZmFq> zlW9)Q^Ap*<9`%-mrNc*1aOC@U^n#X%Db^bW(BT%uSgL#$5FjNBK18~!-wM<^JCMmO6P7aT3@=2=ZH*o%De0w>Vf z2a78msVX)ray-^dRVa_UF+g1Re!&^u2EADa!(g%}vzXXf#B zN3%|S%lGTf+kjg`7A%rBef94S6Yxxw)L>peah<7Hwmk)V)6@=g6Q-POA#7+o7C3{4 zL^fvEqi&CG@0|pwp!GLvvS7}^uPQ1)v>o%P$oYOPT-Rf@hpZXB2IFfQK03{^n;}<1 zu)clkeKYJPo5#|1a1792sIf;OS+{vBc>#v<;yOJRMThDGd$joW$Z?(9rK)c?z^&F+B0# z7(6;wEBPHQmEcMxbFwf(oPlFsp6|9#8V)pHS)+HqQ01OWWENEclBLMrm9fUij_f%e zHRa{bq#B?Jf5wpYtKd8gM70J|ki_|h!p!cT2^z3$x$aFZmn$Vuwk+bHoj6z9q_3WE z(xmwUd7XO~6ZPJW?R}ZMb6Oohqi-vU_%SF~^JnTymbg&Eu+hwJ&5s|6{a>Vsp5RM7 zQcU#yjr{t=v3KR6JJZ)MU(IIUO~g^EZth9h|K4P)2Y>nYE{@CHat7Xf4tr9qa02#t zXe8#O(ELcg?R)8RUBUHrZ<217%i=f4&fOU>Jo0P|(|H4gQ8yTLCG_aB*;v{@R%efX zOQOUK5!iKh@5_e6wdkU{p}*|L#p!&lsTQ-=POp-m6r^oj-W)hLRhi3LJ0K8vd|q`1 zWc{8(H~s!Pnw8fxEK$^)MN^ftu_!;Q6MF5I(W&(mwQ=#DToop>a$%xtd$BYEn=X;7P=C?vVCV1edh?E7i*%>Ozh6~k*S6%* znWEa)KDuE@bthWM6#U0d3%LDm`Qh)0lwFNph05PAhkShCi^Kl|xNvt3yT0h@$#*JU zRobaIuQ?WRY6tZ}fl-L4VoiTU(}UdijS~96%r@1)_N+H^DAa(hObsEc2H~ip5B`^D z)6VfTxCj0*#56b=cg#82tZ=!2y#rV@bEwg07x^K`5t4gy-xUPkT*Bi>2*yp9hoRV;?43md;rMvFi0+6ZR7 z9Io{I$8z~M3|RJYd+(yOT78M3CK6I+$M3#jo)kZ29oeCO@u3V@nj;D1H#UskXo)wR zpKvelt8^-&7h@rfk9}0$?+@VX zWx>vC41QdCL;LkvAq;vavOtVc-b1KmFtI`eSrYcv>9>vIQ!9l`A6`xfQA1A`YqUhi zpWHNrv)=?~d*-idNs)mWrL?xQ%*I5%u0aPnMiF}D`GxBRw9~M)PR!MYu2v5yj0%(EzcR5HuVuX=-OHfUT10W{Y81o~F{%Ic_Hg^!(*?WjS31v56Ic zC&&sfCgX_ZZ5W)Z-SRdH#}}sm6~b`sH^A|!I;}kL0QJQ1N{22p>u>=Eue_oi(ldcaoZ;O}&Sg#jUls{uT8$CC~@zGS7omOBYl` z4TpX{czt!Igq{x`*`K;4G&dvYE#lAc7YKXRkk&Lqr6g%O(vkt3h3 zJW^gJaM)xG*BSi|RCaS%pqo5#^Ja!qy1##zUjR5^Qy00ULEsR%cmdIw02`gGuOJ$V z601Ot#G@ht7*8D*Yu*BpCI1dB$FxsV6(d4;HO#m4iJIAMiJO-yTtzXPmyTTNGEqvm z5kHx`#E;SPh7_W4eZBE7Y%-05LBfw0q4i}k;V8M;=y^CozgQ4v+4!)r^dCj%= zcviQ~`7O_>+KU@n9Oer4qLYpusmnO0@wtB-2-2?Irsh>oe9lgf&+wF;o;-1s2MOc1 zGPi;r+#LMB;j<5j%yi0DLy!}f0--{AEg8TVvcq#FGMVB{R5Y14)z+U-X`C29K4C{1 zP9jcB?f>KmU&(*SzXnOiMez!`wb|ppUyV4 zN-z(JJx(Jc6Cx+|myBA5Ri(SYPE957bpSs>gQ{Au8>yk7;8Mggiz~AtCAcSVnD1W! z9g-_jIR&OAPy*5w15&@K5a9orrh2?Ig~N?wr^nQ@LMKdAMfUv0ZZ0j-hAK^nPaZ|F zSQBUvsYiEmhD6J6Qt)uPtOWG#vAxDD47l*d{2ddcb3C0);Z2*9sd&#DW%ZTLRJ4C`_3e~10?9Wi#SfcEdkhF0iZoxFTTw@+brhD+zp z$@<{iM&|pCG}?vR4cH%B)1=YWO5uIJh$ImYT^*=`+Er7Q>(yU8MPY;9gfm3Ke-rA| z`v4o1_vWUmy}kWkVIc*9JCtCs7o){hzHCwps#BIR%YK5hkIMSk+h>LL5}jLId}ZU) z7XPEqSVKd^&FxT@y(Of)H2~F}A?%XrF)}ApAK%>m?6-try=wP`)U%tmIGrLk!XeR( z*UJRB2k9O7f$#Kk$(`7<% zwnAdH7_^g*zM8B)tL#?iD5c4x#!vFzzHt(U&tWU#%zfh60BfQ8W<(Jp8FP;zz+2WPUD` z|4%+rYMWS99-QfO7)X0}9G2!|H#zFyF1&R>_SCv`S3Wi z&Syj(XU_0h?E{@)S`V+*-k>*H1-ZFi9b|Y4qMI9E|33MEPso|MAu3A!z_K(l(@n@w zZf|RyUGNLWflnB@$s>$t67kmbjVAia^viC4sGHu&?nl>%#3jy**WSStlf|6c-$j1% zae+hu`pl-GrwXJdDBD*H% zYTXpO){n|hu-?&Wn#+CLt=sF>#|&qTq@ue&tWh-)X{7JZqk`H%uRZ%_`s=(}Z|ALt zBkiU!<K9%qtSP(;4H80=O@~(Zay4mB_6aHc6UzO=zXv(+}dPQb6&Wj;Xqe; zq;W4!^UxK2PITyc<~Fo^xsZ16eGyr0bA9@ut(iIr@bel=-yf63k2WHuebCafnmFYS zfaMZ;J@4Ok1z%SlY2CY?zpFOy%TzAExt($-ze9A5nx5$}|Dz7juBgG!St_nies=hC zursj&eM%0JFjk1oQj;{blaao@-w+(m56rcY0nejxe3LG(ZW|h2#Wl_!03{LUX)nSi z%XaOFU_%3Qef(8pe0|J_*UIjG6_pDEVWzunrTfQPr5sEQpm<3ed^m1k`zk=9UL=GG zlbE)G8e}NM21M`3>9Hx$_yQpUO#i$lKvfBP8`b@Y&KG-hyH_3`qlvB!`~R5w@@T00 z_kEI4VUT1SOB5w#XE3OUilSuSm&iW$vD0KJp|bBG`@ZkX*t3o7*=88~&RB=x_wMsN z&-eU};~dACKi>1cU-xod_w~AOjnQr~gV(mceVTl`C8~RB^Cp+PKW@I2bw2|LrP43&oy zyLKa0Cds-rW;W;plHXSTSYn{^2Zb7g|F{67)Aw^C?&lb8V4QceKojv`lG@*0^7#pH z(^#DL%7EX>fQa^LoElr~+&G@I&_G8^H4!3U02u!1oL%-@)%|!qPbKKc{ zzTfJVYCmNVX+_lds|J)cE}gO95H?p+cE(p@?0r@{v@Fmm8edZxH7$;c05Wn@cB4eH z6Q8>KchQU&Z!*>eO4U?Q@w2ql5f}7QY;=^2@4mR*e> z)AGw>tHnV;RJ>pOJ2lw~hShGz8pAFc{~G$og3xst{2TzRU7T;LK?;d z5c1%RZc7*DrK9%!j%Vy-zT~Tw=At}e?AC%GD8}|SVv*Ak$URB!<(BF1V@sZe-mq@d zvdXQyC&!(KYt*O2Ccdzg!~Xj93t~^1qAFvzDT`Q*xr2}LyXUj}LP#pfv}RceQN2Zq zz+VhMs=`MW%j*gsXj0ltPI?wmgcOloa_~DGrDjYOvQ_HcSATmL z@t@2@GsZ^WU^`7-rSGCTwIEg>w@1Wy<4^Mi?%n505CT2^s;*lAL^;KhLScCyD<{Q9`v@wOj_Zo~WMe49V>_o?N;=Ev`E2LzOOl8855 z;$o-3&v5>hpfy@8C>8(h3%&eiM=VqT^m(qH&ZjThiX8w94tqY%{8{h($J6&no~5t= zz740z1-#hpJbs;33u^7Cu+(#tOx}&!6UB7cVAv*jkBWv9(AQW(GF+la=Y5Qy@kEH4 zebal0zHQ9=BK!uZr|%X=p|?9^YsD&!iH9gWOE^_cz(Jd&7M-*d1Q(4NF`!yGska@SZU}- zYcBLh6zaO~UwyN%{=84ejWwd-@q$9l+-u1I{%aJ#AnKYySq-U$@+r4Y4H_&=+yvX) z93_K1nG9M|5C8dXdFA)mVR+|F^z-qH7>&>fQxPQ_J*B%pV{a^!dj`FYs;uygi;BLn zdjKr+5Nr~Zi>*YN4BLXGyTGj19p#1dn*S9z;mg6vk~U*1 zK=U-&eU_MSG^4No#x@G`tU>TeBoEu|l#8UlOIcJqG-=G}g0aD1*3TD$yFk!o^F1~p zKk=B5bsE)>^IXfd&Ak+lUyfX24;xJeQZ?8)uf2lW*j5ck6<4XOJuI! zzxd;Yhf0R8tL!}0)WArvFglXmentYjoC2~+NpF{rx~p7a8#?x-Ypjx6cgVrq%VJ@7 zg4=5&da+dOe&N{c?)h2QO4)c||%g5|Gl*q$PQaI{x73;YkL5954)(L1C|75+At7IsY>%hMRFAkGI-d#N@#|Mcn& z{8P=2;CE6*l>{AsL_&CXXo!TIO2`t&#Iv7=ulMG7Og0&3x zixP|djz%dCDU|!+Tkq|xY^<6t{D|+oY|5vecTtN3>0 zRhy5Ar|g8TWJpmb-fPLJ+Gz#!k^4@ay{>e&|{X0Xc`JjIrn`xl%=zKx7 zX}>cQg8X`Q1r=ba+2lAzK>YQj?}xoWXp_|kUpn9V z$DS|up6m4t>$1xFnmxtQa(F-OaK~IM58y?N^za{<`8MPqixJC4SJxkOWapb;3dKv4 zZY>RCu>`%RPTqkC0r9QH{Rqhcj`9Y!c<3Ds8G)0T!pxnoiI%^FI%v_>-!1R#`Ld@( z#~-bSNNl})bMclazS5SUwYhRieVOS8Virc96VhSH_(_>L+@-yR%jUq45PzN_fFhKq zrBUbU#mQlIyJO#=&)P~Ok?Q5nC0w76Z#g7G>Tut*n!PTRMWe7>#M?2b`= z+5Pyuh-`U-c}HMUeaV?g<5Lk^R{A}VpOk%qQ28q#bIShT*!j%Q|P)4{L0x!4H%``hp8Sx+x~ z*2_!Hz6%FhMm`!NwdX$L=O_;EIecpKqH}8fyNh$@hfT*VuH#0-W0M4<^A$Nt#hp~b z2(JwKbb8shT5rjxTbx+nw_aF{aT$I&|LXV9kW|`@1VyE;N!_Uzv*;R-(%tL~c*-iP zkOT*~l8=P;J$&U)?%Zh77|o*nWlzW*d`g?wbJ&d*`AY9PhzD1}p-*Gxu}l6R_xqn> zGwv3k=8U5Qz7?QQ*G92$K@xklj?wR!8Qp6%1Z1eCg)(--8bb&W)y;BPA zj z5NAUD@Xj_;Q%4&Ue3K_5#k25Uhw0S-w}~wJh?7MO(*rQV{c>j5NG$fRTE>3t0}{xb5?^=8IH6;`jxAM$4$us=QC$ zn-Fiw;kR-1b#`rSW_@;je!kvBXJ=N-*iE`}+9P4}sLks~4O=Pfi$A-?{mxpDmRnO( z^=@G;t13$)>h3i z)?%Zpcgy8Ph17kSOw_G{?L^?-ib{)dj1L{`_11iOyt2>G zXp7oZgO$~_w-OISzL2|J@A-*UKAcGC*ioC$bs=B)Q0(}p2#a1 zOMb?T$oQT!9%oUGyH$x>45#Yl)(eq^Y z*$pe6b@EY{XAxNc5Nq@rrF>gGE|K(yE0h+wd9t{fN{pnZVUyXL{1y2DR#<&BUno6Z zT^T*LH2p;LYiARaI0fDytGiDW1>$%;Vog5A=(Pi$_flba&rX&RlHD=^{(< zv~B5wsS(M#e~f3u5?&j=g|I{RUVf;r5wR@y?<2S^F1{C$(`IQ5!)-Jq*PStAf*>p@E;wql`{C9 z2%A8#B_OXcAaGWrSM`$2M!OUUSw5kJVEQ!sTz`6Y+A zkaRwZPCG=1d=J5Db}0F%R;c{BW6)93+iC=xBz)vcz&qV>qm%kBux!k%BQwAHu0@bE z$9YDU(b?!H_gNOEMD3XU;GxeGqmgFx#cUkMTSNh3TQXWe%Y}QflyYEVe-K}MF>tUf z_Ts5Z-}n^*S&B`y+_M{7%DYm^U4ZY%Rvc|$n)mbMYBus{wj}iwBwpB;--@)p`8y2a zs++(nR2Ohom$Iemvzp(0=;h~zHB044O(JxQ#qw7D`8~EVSKjm@{3T!sdLDgFdmEe3 zKFc58M?7>h+Ha(3dwN5(J3r4YN?(*Y7Ea!L569xoy<7V>BP}aAtY7uo!ni07@utlr zO&d(tusGoN{^wsx`5y%|!5a^Ht;Ud`4dkLw0rB*8ABCa*t5ccVHU~U?*g@h= zEn#NJ>X+)VXBs9#uRQ`KBX*ti^eLW~;6rYb6kQACbK5}R1WNP1RiAWiOvv$+Ggo{eb!IZN!W(vp*vqP5`??-oInNky& z6XFnOi}dd2XFDT(Fn%MC@m$t2n6!l4QAeUcxd-zxHG?t_wgwJeWs)mPTnIMz94E1aAseGwt18MaKm(_s2H{b(%P$*HWQKKEhDk5xw^r|NmSq;qC< zJrL#59|_^pRy)(|2+r|_r6KfwqX+F+@~_FUwmk+1`vT&xVz;wnN^Xs}H`4#(0=f)k z#i3G?B9vk}JeEu0G~o>{72B-UvOrd$dFbF`_EHHSt}c}-?Q~XMG!wDR#$;IPDpy(y zgEA;@$Q}PK_utxEQU?dW1t+yuTi9f z4dvbWb)N!IDIyP-ZNUB#JuLB9IaUf14WY-Kr0w4*!0w`~n^< zOhX}`64lXb^Y=RzgwI>UvGu%s?%Y37bl%&-#h~BJd`LvE|~NS#{lf`d1LLsnL_ZX@+OLt2=7kfNc7UXR_` zft>8&$bDYx$M+Y8%By8A2-2)$6$V~&R)=SoX!bQXP7buUnn(+re7^rLHP9PgWiqX0 zDtHSS#`<&q5r2)8pV_M=@a}CSbRd>?3Yccy5pn`XVi>!?6PJa0jo{!%NNy$_6Ke1( zW9~N%9_n!NXw>V4dXuZ$o_F@N*NAK-rXJP(o=X{4EU$=z>5v0%DK^v_hReagxfq(& zjYpYmJ>*YE&2=GE$mW>n7CZ%hf|T4)=I}@Gar08&Mi=(#T%|N-B$H_r&1J#LkLwAt z)wnq2w6D2o8JLris+nc+Ft&jd1iST5M0~s*FaY?3dbX;mGPks{G_Cd)+0&TsBG9bm zrECk!r!Ho27eYYxtoL5D?Cwu;>x`r(*M36En353!cR#f$tG@8+g4vzS0@5-Hgp`fE ztGnwREh-7`AM;Cp7|ZxDa-VqrmQTD*>>kOeTafgq-`GL+sDfKKM)voG)R_qZzrOj3 z_kTX`e~$ zA51^-lmOiNs)5sWY|UvffXvl+;8 z@7#NM{b+ysL~m2>oOlxJJ0St&?3O|7@yN)Ae#&@4%o~OB^j*~MrwlTr(rGX|f)Li+ zxVb9ex4sjL85Ll;m}U+G}036cdkX_QZ4ZZzZEzj5Vrz)+uTg|H|Wxf#kih!UxTu;F(Ib;(HtpM#*ZpWSh`WZ_B{583%6$ z-OVeD`LfM6J~<3DIBkdfFe(dy{Yb3~c3kj%F};@6`b{MkG(TArg;#Gz4}W_O^eHu- zfx4z!TlY84`lhG%r_atlTy#ovqZ`I9TE7MKG#=V~GbeLKvt(4M zgq(qVE}a&Yrl5ubvuq23sl$cZ^33H&Js6sQ50h`lj-(jWyDu1+nP6S!SxcpU`#t%QOqj&>r2bi%9{KxC%v;SbJS$gq9>cc2j4OXqJLreYIF4rbNz&QhDJpUplrO=! zu@VKv>YUa#3;CR#oSP|msy2GgMc1cwUek-S_a)lz%Iyr{4eD=>Z6vSENDS4FJFMA1 z%l^2W`YKa+?*QoNBzf=F!{XWb#-oepa*mw58G3ZIyB~&ht81R2Q}w#TRr?zqP4{0O zG@Fs({;+(V=+<~B>D+r?i9&q8g4lD%(%)Bv+>DvvbyvJDfXT&}8;a9d4gM!$@4P^9 zrc!#`%Y3ntCZ5*0Mp^vh?5@a6PZ%($pqZoLg2q$6)$@3)IWBL4x39HFuV#ihNhIG# z*cmIld$PQ+kVu<~VGP{?X(dwN`sTWwl;X#*U+<}Sde>$Y+p<7@3EIi6Bym&x4C-o)J0?Y*rh+*WZStu+4A>bo(a2PH|B&NFpe zF{v^~1S20p!ax;|xA4z&CR*c-guUzb3=*wttR!^$hEsCFK?nn_;1XWNP9U*T&#=HUFYs!~dKjrP>8ENvck)BeB*x+F8!c;b?^DpvtbvmK}kQ3@C zAt;`v2*9XvJK01wmed={!-m!`mGTihZch3S8O*%xg01J7y;%+Fb z=e~9D$`654t9HAJol%H;404MfMpXKOQ3q`J4+odEWC&s1FDeJMYOzI_MSuS^FEe>S`saPuG z+xw;$zUWU*P7IDsi;780$jWfXh)amNREUP5`(E|;ea^HC3oGmoixerR7b!QjQZ_U5 za>gC+Z;TX_yLh^pYCf>Dwsmld5f`fx7yIl(>%|oV{81?;79w-w^j?e`u=H8NqBGkf zYiZ$4DUGSBVz!0F($dIK)>3Cs>95t*6OYo0#?0ExTOwRlq5|U#rvknmEA1nFtsk@} ze@_l2J*QFa*}qp>k^i(HfjOR5Ui0Cmt({fR&kkm~<){3c_6!d)gS&W_%XD~*#;xsC zvO!(h3hi(BH?3^?f2y}}8OIx_DeJX+NJ`4aGccO^i`f-&5$+LwHRx8?7iwHqd@8V~ z5v1qfm53M+fr{UIl4_c}ay4CUKjKx+PYK$_XZx9v8T2}mbELmR6^yPoG8X5rOHFo6 z(EG3!r#G@~a&=EiNTu1oGPO#q$=;9na{uHJZKKxy9DSP^g67ZQ=q+2!4%2MflZ;OO z4xu~eh8Tm5xNBhv-Eq1*#K&UuZ~E3ZZSUjat}nkzLj8PA&#aznFGRA;7&Kbb{c~8x z?!nWr-0qxDUvgLf)C!3`OkiP=(o5)(%-R6{cTdck%gox=+Cn!h^l&LFrZXtL^R4-a zLg&a%`$!TCqe0<=u=xFzh5awOlfQ?i`C}4+s-Q4HFw___nGN_7$WQ6`aHZ(Z}>=ut1y& zFH?u_nZ)#!s}c3_zz*BBD_U6>BP{mMc;CadBhbIGC3Lifs9TpH+z@%G6%Fg+s}~x( zVB!`tAbsKM`@8a)@~fqv?a9{0V7Q0#V>`ax4aNEKtJLGoW5~WUJ?V zWJYnZW2Ut+J-E5rTbYIb}c3Z)b-|?h@QZ; z@yd?xsYX(6$`6}_1Dy>={uUalZ1!*w=-X5(EBK0UFEVp+4BLI^;{GI8ruuT9qXVSi zhD2QFvCX3J&ZZhUg|jS?z)f~RSX3AAmXmX8mUFqhR$K6eq$|dijWMZo_b}Lq&_^L4 zbyN`s?9*Li35&H3+w~my(6QEPSISSPpDg=4?r&{wLwafv{&r?lIME>S<2!>>SeBsv zD3ODi?VT_ZnfpF4#9q)P3UYC+VoOn+V~hn-W>yM z%xzb;<3_QFY6r(%0;q>pxi$^<@h%~cL!N! z5vrZRZ{j4O0hY7}wS4^|!Iq0ytxu{H%1db^?3(m6#u==}&It|11%E4M-HzByIO1ye-S z5@_(2PF)Em@E@e0O0zOfdWcioo*UTcQ}>N zig`vHYL*m79A0e$M+nFzR5PPI%1hrHZazBJ2}VWZ!g|+@4`3YYg3c1V4L@XOb(1Zn zeUAiu8XS919Au9kS!`42s57eNdRq1UEP}ar`KUJ5IdnuNnFT^I^k}p=Ido>5^7N3ZrTSA_JLl!)Z7r3y%Miy)%4VNV6 zRoIOV8)`~S-!9~UIs^WiiAG;lT*h)B_l4laASV% zZPJ|%ghdH!8!mJ=kD}OoR;DU*@A1IXf~J0+ZuQhel@iWo`Ee~FUk0?-`Y}mcxr38v z3(x`a?LA-{eGe}I?h4eby#ye_Lo~dX>JIFH=`nS9Ut6qbrlf9=%CDGW*EP5%pAin*J_ouu?-k8MizX=1giJ35?YzW#|B_B3#=rNzFW25)7l-I))nMOW^vu)anbGnb6?^mgk0w-`Of)^q9E+sHhnwKYgt3_O>KY&Kw%5Zq?f3{H-|=yKh?3GAd<^Tuz6&HW}}x* z@N9-`(YG&huAdG0RG4}IdkQOCBJxX%@KQBazG#(q;#hwY`KuB zz*AdHFlOjju!szR%W$Aqaw#PsAC)%ztR@jv%75o!C+g)`P`fdxpecYS#IYMGBR%Ff z9y`%4J%z4y0&v@Lx1O3@Cc6mq)v8@H0<(0Q;_V8Mg^aRJjyCGt>RN?0`=FH)^6$sl zDLc#sp`p2IX-@*LMPCY){+5Go?bG*oon#Bp_dna;sspW_IOtVfq`anZ9V?W#T|n$I z6dMidD&gV;x^S<>9swtOe)ncLANzfP@AQ`Ho~wU+$4834YlN#Rieh(a*r9Xw}v4n|{nGZBCLL6YZVbCyO=j_e4 zTPXnkkMU2Ie!u^xqipAeiIUv6oqc*5qODP3M;x9?X_TV4)Q3pz2R4uf%ekhyuer`n ziuk|i=sBb|VBDVCYg00stSw!a^VuJ&T2izy58r3Lnk+DAsiq`jej$dBPFQjHhZ7wa zL#w=^@U^p(JnWiz*xM@-T&?n~oLhjS|DfdHpkZKKilrz^v2+5e5`g)604kriHsfqhn%bl>%bM+b{*~m%!@1D?Ij}#UoRJT)9O=QA>)nR)Rt6(`h+~dk?trM{`AC~&N*BsQTzbE}_+{fE zw#d2Igou6@Awzzkwss$Bh6%6CwqN_3jg4yD@mzr_r}^)p&+vYu+jZ@<5tZa+?lS!w+hW=3NDYR&NYo(73~k_Xg@XU9NDlg^ zUOB$>rBDEf&SN$YkG~bLkLLMi5p9Zh9Sbh7%YA>spUwR^`9^+wT6umSzpf4Z*on$B zZJK&>B9{l(P<43b2n+4&NI~joAgV5>L?h7`VC~Yg&)yOR8x4)&3u~FBvPpW#jQ4$l zWAk4w-z;NTCX3Kw^B;UOk~ad=QU%z!b*X?YdA?ESlV#~6zlG7Rt?t9Em)kXvoTy6u z8q47&SGH=I{rOXH()p)#wDPZEb}>RcHvS|c3q{>d%Q)p zsfuWzCDt~5cHh0Nm45`D8%h-(`7C`Idk zr#8&u8v(??_cli@*EiP>75?!$U{h8XeI(feT6GXx(vTx33jLxwJ2Ev0Ji-8sfwIZh zM|ZY?XsfyN6IGfN=Pd=Q^{!x9C=Bh2=NloEO;`pMe06p zcXiu7y4#C<$MB0K(4BufE8u_h2`DmKz2W_zkI)OU1!bom;Fn>hC&pAOUI`te^D?Kj zEig1iVr81P1sW0P@pUoBGF%1-fw#aDlT=5?+b8SI}KD^q! zD0;VEpBh|y_qkC9t)V#6I98311j;yiiR<{I4xWTzFU>j(XoP?~nu`$Ld0nI%66)WT z;u+_9(@>~nrZ~M20ci)E-n)f(nbVF2<(Syz-R-DE0-aA-I|0&6)t-C?Zj3VF3Jh6} z&O@Q%YcU_ipl3|QZjVQ`u1$0=3}Lm|zsQSyNTv&=c*Q0{boOpTjxM!K&SOqc+8QbM+x|Hq zideG}fY9tiDbF=RT&+_r!Dzl;rwmx)2aje8gmjfoDGP*u-|mLJBc1oqdqehu%-XiN zwD<1tR5R<`A~S>mritR#x!sD)W>kbXcjfAte1x}OmXD>ycGy>I55pJN4Cw$1O2XBkCA5ar@?=O`lUUXsrDTg!NuzfJ-A0O=Y2+>BcDvm%}(m6 z!#<9>MAiMr527dguq&IkwHrxxz|3{u3crW(c?#rj(LX{2C^1&}#q0WC@$MONHlZYuNkfGlIDSv!q|zXEFr)KlLa)9jrKL zeZWCHU3D3^QI%_XRsXQ^fTZMx+OOB`qX$Xq;~W#!t6N=$_O?4sd$~43b*P=sq01p@ zRM$U-%PC5@h^$H9lga|^;@K4>Vk-Zy0g(<1qT2DbOh2uxNFCZ!pboz-SjEym^EI($ zs=;ae3G5NuiQ2)+`sg>+YESR#Ap{AaC-}m-zp-DzJd+boxVaAc)0z4oV@0IqX z`>O4pWF%AcZR}c7u%GFc$IetNlTbB8`K&uS-ZqZ!DYJwl*rjcj>ylaP**)g^Yd2bX z9iSIq9@voLl#Izt42|uCgR5XI#vb(X!Zsa3I%R)_cFJSPn^6`@id{gOkDZ?e>GUNY zW7o5Fek_0NW`XRa%K}6MyCe%lm(4$MUpvbl?<;;EF@)vRuV=DM7Hhjt9Zo9rcB;52 z>pw2Q@v;te_}3w7V;A{%uX2C$t|7XE_QW>saJEu7Dow8q%|`3yHdJ4hy_r9(cTWJl zmP*rU-r&b`WD=m(9lU{)6&WgFJp zUVZ(gpCKDb#dTA(X}mrCOB%ru)W9;COp zsY&5~g=X~dWe6G_xouHu1Q?Vm{3F#pz?z=srF$0em3-Xd}U zQ$U~KLkOajN?_g4h+mz!{1L+;u8kMZ=7ydd15g0pLV+$`w5k2im%V3pTb-nfotJ}k z)iapbw{c|}VpA?l=>R_vJYKKx*L~Z&JOuiX16X5wH^ufR*Zms&n5M*VVXI1&$63sV ztY64SsCj^x?NPcRAh{N$j3mQ(lxaed@}1+6BG8^J6pBdBiv&jLzUCRH3O8)?8bE-M zw?qfzbMF^X7fNG}_I7ZXB$>mFNxRcATd6P_h%RE8IgTy(T5R4sc!l`8LtDLiJNe~a zrBg$wlPUVJQo^9lVLZ$JG>c|pWSG;tz*Ye%zc|Y*6Yk%Y=eb6|V1K!A)QN)|xcU#c z_4)`n;!CsvQohb202HiALHo0K?{Qq+;;Bw))He`?Nh>)(sU0nq`l3ZX4Tgg#ER=KW z_#))*efh9Zp8K|^&4k4hR0Q(7RE+y(J!PFsf5fFvGjZR)n6kh@;A@88nk-~~aWpCR zDU$4Z3eCt(@baY^56B+ny``RjbZvfUN=)n(|GqM$8Jew zDlHk2EHxbSytR!`g-;Jonz6tC!NlGtgm!MSu8p7rgfl=n<@!0A8ofJDU?Io<$V$>x zAMpsHvJS9hesksQ9%kMWko`3^=|eE1hi0XKPC@L64pg zLz)y#eTuwlEk0x-RQW9hhU@G0HylazipclR}v#o>f;4jX%>Jb&@l z5{iT(nF&V)H=uyn7G+KI4CRn<(Ue(EF)C4)OJ-p_%PiNMiuz9zhEwE@t*b6LIix|0 z52Jgr6NAH5W@h6tuF1}LU>(Zr(Ox3aa!Z%DT>RB4*y-Vp+-P-4Z#?CF?HSGB*!xyg zq!BXINrXd~Zj;3+!#`~Fzk)MP>OC>y4FKFeQjRVS0V(<4N=KmzeQSDtxA6A)J721O zEK}R+P~bm`ZTVnR=Vk>{Ued{ty?@~bXiKg)0CPbyP-#9gZ|AY7eO4uoapl+|R9XQ$ z%Hqy^KFUjDp>Yz2`ttGPdHi&61`9;F#sB%2J`XT0mStWe>ro4m?JVwbOPp+YUbt?K zFda@fV?A-l?;Rd?(W zb?nw*7EqX+4ZialkoIZ&^?P@lxbVke=E8-q|NOYRXi$e$oRLiMHQ5dV)b#>w&ef&H zAyMQc(f2NPeY9=4HHlmEl=%6-=$1rLgpo&`%)Jqeb$1=*|ClO>#MK3!Fsvog8uE3 z1ZWvj%h;`Z=?1>^*odyC0CTWH;**-NU;1NH8aE5r)}IEWk|>Qe>Dp*S#cKLHjHMJl z`n+cDY^9per@@R)URk#P=qh2|Wc05x#yfcrkh_&U(MQVf0nDxUd-&zJ^L=&^7KrKO z3Ntl0iBCw3yW66}J6aTah5q4fB^qxB`{1LjD%KVR;Z$QPR4%_@*SDGHJay|1yP+AALLI zW^y8DtY>a#P$A=?eSMCloAqIsk|GUpeK*y+I=8aC(aUElVOY;if9`>b+0Ql(57wJm zX}Xz0k&`7^FBL@FFIa|hamb7=)o@w-+EiPly5;8d&bRyM2JHUJFzS2BI~EUPc|Nxl zjs-2s!17X@qhJxze7tMM`8H+GLLW~~6u&_ylx1o71`@6LV<$}$k)L>qw z^w3_~W?c{7WiDNg`ZwnUx@2(e=iS^=dn*=594d{~X*Tt8WCQKeE_?fdHb7IH*;ZxO ztA~N~+14&O!+3(UQsv8F!xF}4qsQx#DfxqS+FkB~%ZGgd+e+1$VE$u~NW71L3Wt{) zVZvF2SS(iQl4IO;@4*afWsz1ykmOCsFfo>8haPu$q|VlIh5hwc^U7v?r*rZr}k zW@MJuH|FNvD*V7=#tZ6F;>oUd*qE)i+f1=rAD9@L8j8}C`w;&L+(xui;gDBdw#j*z zS(HpV)_5Z-rrdDcERA6CnarNpUA2}Y@NYOi2vuqY=oh&wF$@5WA^5!Dui(<-wcj%< zK$VE?d-nL7CvrOeTNxZgA%IUxx`XF`i}^1i_5Wd{;yd-^b8q9D@n@N|@OF%OGj!g% z9og%BK-$fzM3yMT?in&*R}=$;f0z`@UiPX&DZ<_&vC@nfQUwDQ6Cj99Hc* z68dE6MsHN$58u4pWV^;3$0>ndC4*=CKo`BdD^>c|2R8IYL1}GeZYB5d(4Ud23`ZYJ zb(>h*)^=%5>8|qfp@+{XDa-Y>E8D17-|}o;y?=?BnmIuI66N3+KNkx%SNbhCTZFB( zxwVD4X`KVY#n#lq+?r6)-^i7-i!z#ZUb{Eb|B~6q+&scL;>}mPfN?Ff;hPK{R)j{U zl<`<}fI0iZdlC|Nc6w51Jc~U$#lMw&6`$txXCImjR;O3oS@-YNUcm^Vtk>e>QIZ~P z^mBx(<%l2{}v|)~~}AG2WNI znQi?3qIiIf1wzAeTUpyej`~At@W{whzmZYw;4A5IAI-yM7z;#Emn#oNN{C#d1?0N0 z{O0tb%pkJxtC~to7*J)y0Paf3^4M!D{VH&r#PeJFyd$q#^1E(;LDetAmMxc5n}p@g z4uP=>tg6nKLlt#pso{l8kz5yfsp0OSuvM2yWr^8UBkn38Kqe!R z%7A|KF*#8$uK!`*fWQ@)q>O~Pn24-c;^KK{${`R$TkZ9^Q3GK!@h&~*hRMYNO#DkX z6OUX3H|F#W864`8QXa%heRD0fgHO%Pxvk}2(Ed|K9E5kM(*PQXc@`cdGT!5dXO|A9 z8Ay93Dbhf^zvI*ii03MAz7lDU>IF|&AS=Y&I_LvS=oKHi#21-E zRE^PbpkV#S23NUQAXL?bF~YoK^Sbk&(EakH2e;bmPuKuBf7AwiW~-WTUU7puTn!X_ zGx1SYh@$nt2U+%n-yYXMW&`9qoY`&FwN#yL%ldLng03Ij_=`&y$O6OR;E=pXs~%fu zz6tKn7JK+BG}TMhMj1&VacOBWIl1~0K^eJhKt8yC*4NtFzENH*Cpr3ia%3pZ%Fdd$ zs`lQ4M@lxzdg@u(jqeQH^RHL~+RBay|K+^T#!60jewBqwM;t0!itv3B{n`Ev5+7S` zyG!li&MP6K&PH7S)|q2@1=J7D!Ac>YC8{ZY>LB;4Y;VoU>RAI_O6#Lk=*1HO#@&5BoDwk7Ei-rPjHutezQhD*+UU zrPW)c{7J-BKv>Xb8f)>31%hpmyBZD(Zo|nu6Y(Sg0LV!9Z>EjAxn#5bGcB*}*QZFV ze+-i%Dt~)0n-IZlTbJ2BT|=lFIgGz|6P&jHs%%=_`(vYd+}cE2wmVUcz?nxO}?zmjUY z16&pr?HHCszkr8M2c!BoosK-q$SP&;EkwPR?FDEL(}q2VSpGjRv`-iqqRY`Q!-G8D zTXWF&eCrs*4J*G>7>cCcnQ*^bVv=&~bFFf)MzjoE4y>kt?K0rPy#Mr_=$q#ef|w5-f08-M1My=b--kgo-_P!a?EKiL-qas=U#bh-N%AJ0 z*P@INu@QODMc2+*a;z`zu=O7oz^9$W3&5nsuD{WvynqEFlgALm3h-AgFF73neR_SL z1>AoK3m1m|n0)|V)~B+tu4zEm)=J|l0{#$!uIl;^&Lr{9KeGwkFnO3i;Fc8oz{{}W zUF_94Z5y|Hhgq~pe3Ehf^i1&a`ND+!KYT`v?Lk35RuDLQGXwGQak_=nEhSgXP-laS zk1gO-$Q$(0{Y!&b?1bpozewn*X(mbt>oJCN7K85JRX2-Vcd=T$`dMo2bpi7(OFms< z3k6ek4{29XYagne-bjaCy18!k_5u2*Y#;pn-C1pL<_NtXsQGHTkLD9Vlr+M>Tu(SpTjldC?dbjNjn?J zQEU$c`0SB~7#YB@-5&<8ykL6A-)aMt8x|sgEm600nQHsC4z# zo{N{QR_hBq{njgN19x%FEA6bgmK*12nUEuINUWo!A(RFd6+215VvmsGqmN_a{{v+16F7Zyq2fl`sAx>C*Ajn>?VmoWI!ia0GxUJXy=Purjcy8{D zmcL-Qzo+Gr2K3SL7YaN?|JqN$)&E~jS02yw|HnxtcS`Of`I2L~bLEO0A##KwD+-w1H^c_bKFwJTT~n8^rUX$Sj$4N?lY`Xnj|`8;aR`SCbqF zeX18J+V2w%@7N)R4;Zcg1VzeSoI0EJ)>Z%~8WDrKQ;;Kl6CtD9bu`zzHk8Ks|H;Zw z)mJ$rI%VYJK;Y0%d-Eoxs%)_j4{M1QOR$uIWzOS+h?K77`;iY9rTNXzm;(IuQI&I< zlJb^$OCz}McTH6wj@>nbA3?}69=;|kc^DY%$IExX{??cM9%6|Fu?=@_%`%THMyI2& zrgh?csUQ1tf82?TMG7xeKYEHE*3GhnBhWwU4MyzVU5dWs6Yzx0`-iHsg|pu%!(vC~ zSr2>P`8rhD@{e|0FYc@Ao^pZ0X(1*bAD52xU}7yG$UZnzY}KFa3w22&FS&YO{Jmct zLXY59_WHwyt3V0A7|z!_2XtIsfh@JCif-|UoZ~EG z(+zXjQ|5n~Q1!jjQB74Oto89ae~x04)On&po8Nn>+YW%HyJ9h_0cDrWFS72?&BX7HN%?#M1%Nv`HDr)^3@LDR)}lPf$QqEj_Nvk z!YYXI$1q7D6ha{FU3eDe&0>&ds(H8eP>jaa9lB7lnKLUwzxWGZen^U*&3v8vY4m{A zIpv1n|C)q*NePw~*+>Ub3B?m7R_f6lU5z~D4S0Yi<#ZdBkdPQAU8?5IapL)4u7`RI zvs1qVOOtc2s+N-00d5RhXmjWsTd*w#iMZMTLJTqI3~>tVAk|f>v74uI`}iz5^h~lk zfHnFE^Hw<1me{8By)yE6bVPu9qo^fKuZ64APQ|Q6Qzw>nTJ^b!u5ephE+0~dgI|zm z($~(2-TOswQE9Sk76R9ek^ADU7KFriywIbH*)I8KX#xa%EhGsGk({hC=t}yVz>)Xx z7rBMj7t3d;eC+7hhF{9vyxbf0DZm{rp4+=@8u0C11EDZ2p<*X@q$!Q4PEB zP1JFFxCR()dLDb7xo?~Z8GDcxCQvT@ecY-t81uMr3fLY69k&~yfP?652ha*+VOfL1 z(4SsXPA;5M-CQ^R$?1X=tTDPU72`^E^2ytjdokI3yp4kT^z49Qjl(zY8Gy z^TCSx8L+@Q_T3rG7-w;7@8Z=rjxP{hcey%X<|c0VM`d8n&!sD@AB=n)SMH59oY6>v zemcXVuB&UzU&`OQ!GIHE9{tOY+hAMK>^s3GfA(?RzNoQL9VKH%I`O|qPi15&Ac1fb z3V}>bq}ni7P9#<$npgET5`ARIdMVO#HZLmO-ts_WJ5H9{R94~UEA$b2F^OA!!T#>? zY~0DKK^Nc>XC)epb(l}Jbf*a}$5R(?FX99368hrP^94R~H=6E$yp*-4#&UeiI;Vl zs(89*_NRk5Ch9-`rV_=MetYo7aA`AFEmflPx*Px&^lYZmcBSy@{i6l(U8kP?saSwh zR9oIb$!>RS5jf*q7Q@v(9-Hlnu)?+JNydI;9bT+Tg2G09~81tH(WC-ta-hUL2D~l>q{eGc^li9$rY$Ve6 zV&iMYP;zhx&}DxXGtotu;nje|{bePHtG)%OkN>(9B<{_jI#PP$Y=VkR5 zE>Vfhddda-F00PQw4AEE=ozy89`GRi@g3DG0Qe>P@8t+eB8Y<{ zZ%lj`cLd)37WB0eNokvBRip?Lsk$k$oq# z^bk_Y3BW{l>6x`H@6`$0!Whj?b@b2U z3k{7V6m%c80y?=U0J6S+K=%1rFOVe=@6`Yx7FwPOxHpvnX|`yA-5<7ywIxUMW%0F! zh$MFE-i9qIKDp&7n3LyVMc?{(d)v{9?ltueFm3&Ia*W0Rot|T8X!aZIL#H@^ofM2O z!m>iIdc?QI@Elz(f1{yG5c;I&)7?+I!|oo}(%_WCyM3P_F)4H#mR51x-_R&1RO`@~ zIenHBE}zsxcGLqIR$OLzQ*@G$hrShq=Hcr+7U{_{gv?lG-^!(2!(XZ45YONy+kdl> z>DP?X>uPWUBmtNHAd^LE%LhU>$?%m2Iold^dw4U)1W#u3ryT5Gh0{%U3;rvwXDENb zqgq=p{{H4U*@2(-Pe}8uFPH0;_#wXGR&wZ4JIhfqsW{=%Io6EDo)THip+->%o~Nv3 z4JFt?0U(7k9IWA=le`Q)e5|>Z>ISmBY@D0-!b4hiIx_?rI_7FKg1g}#H6ACWC~+4x z7?0IH50I*0Ic}(6!zs;gnO-(M%8tJ)4_Lglav;T-^%`{8x^UOqA1ZZhc;N`#Aq)mP zypg91X$Oz(LV^o`*XDPDY=kr$`9s@e3W zWabhmYuncG-Yuk$UCU6|iUY`jmk%oDxe6tsN`ql01Ii*34p%cgP%M4 zhgkJ!zNXSHdosVg?;RXMbFK+@P0ced>I!$3#rw8vb3w*4fv)J33UqGz-m1iZ^iMg5 znUxdUydJ>D{}36pA?IqsCwboHdbJ@nI9#&dzc@&(9lCM{1ICC0VvBG;8zIQ#?yV=5 zS9AIA!2B{&fT6e=d^MhJ5A-{IcgwZ5;u9cKz<`-=!*K*xI`Qch>b;1cnptA8cHA72k)qBdv$qVQ<)1ir`=T^9r_>{ z(1|Q)TOcg}PxN%WaM)Ys;sYbzRH)Y%i7e!au-5n9RojhlrdE^SDO&*P!?M+U91cnI zg&ofN{|f-v%dQcIJHxcxv>-)lo`Et2#wTK0pYJ;?Q8l@D&KVR_Z~t28E|K*R(O&3F zehvnV`)6~H!Jmh-9Dc$76`l5v(Q7O=`Saytl>&XeNj)mq`2p*_HY=tUUFcM!bLV#* zZQS4hLU_nb_tMFh|3=N5*>pD^#gfAb&AAAi&wSiTkLJgpo|93ybupJ}gken8HX; zcZ2YId_WO9O8Wq=AQ%kYD9JiKt8ocf!@oA|-+nqV!dYY%(&3P*d%uqGlOw2b`N+zK zfJXAF$B+uj-t{$#WAR%?4ystyh0M50N0s&u?L$qxU$GxbMhf&SI0kvE?IgXCjeKU1 zHRt3oJ2T`(&22`)k^Ipof!#G(x&$@+EKrWfJ6>g5pL>l`fuIF=fFOP~qu^(V&#oX^bp z;VVjQMf=;#(+$XPyJ`Jbm7qQk^@0t&UJdTLbClblInFm4Jn=qBS^Stfx5^#+eD5WE zuG7dlrr>tvDHay??-wtecZM7l@;DW9_+|%#JaL#(_CN#-8sg5!z}!IB0&bxo>Yo6|``z37p$SBW9*2#^lzf zBj)JmB8atHh1{!dSHzebCB_Z=#3kYzwgyaX-P?GQK{_gZ2Z@Y zU3G2;K;1DGBAA@PuPQ1kyzb_P?M^J`*BCSFn<-RP`P1^V(c}i?C;n(UeaMJ3eWxU^ z-n(npfXqSLFNmZ~%#>^j?OQCD3#lX1+rHK~v@D1viyX#0d}*4&+ffp_b>AYXl7Fjv zZ(n3wvnQ>fx|IJ)jy7Q;a&h9yY>E3LRTmHj^id2#H884fAyd-q-BTcjIJCK@*nqIY zv@W}aNlUvcSM?fQC9Y~|rCO!Ol=Xpx8S8<@H5XP4tY4{n-OqfMW(0XB2{VncHJ|J6 zZuiSu9V<5On?(fMyx!-kox7r#R^v9)3G2r5>DFq+Ono^s?io?hGGw?vy}i&COC5m# z2Z7j>I4(hfjZfBqv9M#(Rgy`G+N^VhhX_MLZ_Ht$HzkZi#;-?2lXB)TOPR6!yS8JU zF_kwMU*EdMY{j1o&#Ncx^r`0LzZNLLZ8FE1d#9N{o3*vIRhsC^m5m!a$|}`nh}2kg zqe9f~h5$Z3osEryU+Vs92ePFB4Ee~ z60kBGwQ1u!GF21o{-Udy7&2!vjSTf@Y9Sk9T)Rq3A z9msBQP9YBAtq=#XaQB=`x$*+Vs(e;gmvBk_J?e#qR6&2HSH9Tfj=PezsW3Gl31Dek z4A#HviG3<2&G_`s;JT+)Kr9yur9i?R|NdhnC7>m>0VSmDBb_xG{!9LC!{_B{N&(VJ1s&>lHq=}3A?TLL0L zf9ciwTttQ6h0*NX+ym@S;|EI_t~sy8_J}hijQDJqv*Nx{dWC;-4X^SWaW$@H+FE%8 zV}*#p7;TTz8cBmEh739ipFP{23Zi52Z75&*29TyV{)Oki7ZLG{7JZsV1b(E0z%&J} z6PosS4Jj@0qpas5UTzk?z@e|N??O^n?Zxa)3WTuC?P1o% z#l-B4qxW9Vp7k!0oe0p*XtfcYW}^0te|?qp%4%LV+?e2T~tb{j=Wz}2Kv?zu_;7$zjn=KYyvA&6}4A3e>3hz zy8vU7NxnBs9csoMQa^PJ_E{NCUb(N=);o6`Y{KR=w8vN z!P@Okaq}OoGu8(IM$7|lpbm0={9@xjSfnm{QZ|-@1bAn|hN1!R*=TQXr;*o#Yw`C( zdh??RbyGnN*PWv-yF@X<3YZ&`5!2LG(oigoNxAFlS|U<1M`>p6_G|9VY%#=re0?`5 zc!cNu)%SIEk?I^29BR5YhF(7wCWV~njmjSz#^I+^PE~C`gN2ISZ{^`>{(K0XJHJD@ zT;21p$WXkVF^~t@Xc&`6&2s%KRj>?ykko~`#g%VPVM?>GFqx#a?GhFi7SL~mXJZ*s XLMtEqQbPluuv|2^yHII*BGxP8G literal 0 HcmV?d00001 diff --git a/docs/mission-control-runbook-v2.md b/docs/mission-control-runbook-v2.md new file mode 100644 index 0000000..437c404 --- /dev/null +++ b/docs/mission-control-runbook-v2.md @@ -0,0 +1,29 @@ +# Mission Control Runbook v2 + +## Quick health checks +- `openclaw status --deep` +- `openclaw cron list --json` +- Verify reporter output in your configured reporting destination + +## Snapshot / rollback +Snapshot file: +- `runtime/evidence/mission-control-jobs-v2-snapshot.json` + +Rollback principle: +1) Read snapshot +2) For each job id in snapshot, `cron update` with stored schedule/payload/delivery/enable settings +3) Re-run regression check job + +## Regression monitor +- Job: `pandas-mc-regression-check-30m` +- Expected line: + - `REGRESSION | status=ok | ...` +- If `status=alert|fail`: + 1) check `runtime/evidence/regression-status.json` + 2) check `runtime/state.json` and lockdirs + 3) restart affected chain only (avoid global restart first) + +## SLO suggestion +- state freshness <= 20m +- stale lockdirs = 0 +- reporter cadence = 15m diff --git a/docs/mission-control-template-v2.md b/docs/mission-control-template-v2.md new file mode 100644 index 0000000..b27d994 --- /dev/null +++ b/docs/mission-control-template-v2.md @@ -0,0 +1,48 @@ +# Mission Control Template v2 (Reusable) + +## Roles (4 jobs) +1. Worker (do work) +2. Watchdog (single-chain + restart) +3. Guard (resident process liveness) +4. Reporter (human-facing status) + +## Required files +- runtime/state.json (single source of truth) +- runtime/evidence/dod-status.json +- runtime/evidence/-report.md +- runtime/locks/*.lockdir (atomic lock via mkdir) + +## State contract (minimum) +```json +{ + "role": "worker|watchdog|guard|reporter", + "lastRunAt": "ISO-8601", + "updatedAt": "ISO-8601", + "status": "IN_PROGRESS|DONE|ALERT|FAIL|STALE", + "partial": 0, + "missing": 0, + "activeCodex": 0, + "blocker": "none", + "next": "next action" +} +``` + +## Schedule defaults (staggered) +- Worker: every 5m +- Watchdog: every 7m +- Guard: every 11m +- Reporter: every 15m + +## Failure escalation +- Worker fail -> fallback command once -> still fail => FAIL + blocker +- Watchdog same blocker 3 rounds => ALERT +- Guard fail 2 rounds => ALERT +- Reporter stale >20m => STALE + human intervention line + +## Reporter output contract (strict 4 lines) +- 做了什么: +- 目标是什么: +- 哪些没完成: +- 正在做什么: + +No extra text. diff --git a/ecosystem.config.cjs b/ecosystem.config.cjs new file mode 100644 index 0000000..a156aa8 --- /dev/null +++ b/ecosystem.config.cjs @@ -0,0 +1,30 @@ +const env = { + UI_MODE: process.env.UI_MODE ?? "true", + UI_PORT: process.env.UI_PORT ?? "4310", + READONLY_MODE: process.env.READONLY_MODE ?? "true", + LOCAL_TOKEN_AUTH_REQUIRED: process.env.LOCAL_TOKEN_AUTH_REQUIRED ?? "true", + MONITOR_CONTINUOUS: process.env.MONITOR_CONTINUOUS ?? "true", + GATEWAY_URL: process.env.GATEWAY_URL ?? "ws://127.0.0.1:18789", +}; + +if (process.env.LOCAL_API_TOKEN) { + env.LOCAL_API_TOKEN = process.env.LOCAL_API_TOKEN; +} + +module.exports = { + apps: [ + { + name: "pandas-control-center", + cwd: __dirname, + script: "node", + args: "--import tsx src/index.ts", + env, + autorestart: true, + max_restarts: 10, + restart_delay: 2000, + out_file: "runtime/pm2-out.log", + error_file: "runtime/pm2-error.log", + time: true + } + ] +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6cfae83 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,590 @@ +{ + "name": "openclaw-mission-control-mvp", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openclaw-mission-control-mvp", + "version": "0.1.0", + "devDependencies": { + "@types/node": "^22.13.10", + "tsx": "^4.20.0", + "typescript": "^5.8.2" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "22.19.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz", + "integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fd67a56 --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "name": "openclaw-mission-control-mvp", + "version": "0.1.0", + "description": "Safety-first local control center for OpenClaw observability, task operations, and operator review.", + "license": "MIT", + "type": "commonjs", + "scripts": { + "dev": "node --import tsx src/index.ts", + "dev:continuous": "MONITOR_CONTINUOUS=true node --import tsx src/index.ts", + "dev:ui": "UI_MODE=true node --import tsx src/index.ts", + "smoke:ui": "bash scripts/ui-smoke.sh", + "command:backup-export": "APP_COMMAND=backup-export node --import tsx src/index.ts", + "avatars:export": "node --import tsx scripts/export-staff-avatars.ts", + "command:import-validate": "APP_COMMAND=import-validate node --import tsx src/index.ts", + "command:acks-prune": "APP_COMMAND=acks-prune node --import tsx src/index.ts", + "command:task-heartbeat": "APP_COMMAND=task-heartbeat node --import tsx src/index.ts", + "test": "node --import tsx --test test/**/*.test.ts", + "build": "tsc -p tsconfig.json", + "release:audit": "bash scripts/release-audit.sh", + "validate:task-store": "node --import tsx scripts/validate-task-store.ts", + "validate:budget": "node --import tsx scripts/validate-budget-compute.ts", + "validate": "npm run validate:task-store && npm run validate:budget", + "lock:status": "node --import tsx scripts/run-lock.ts status", + "lock:acquire": "node --import tsx scripts/run-lock.ts acquire", + "lock:renew": "node --import tsx scripts/run-lock.ts renew", + "lock:release": "node --import tsx scripts/run-lock.ts release", + "evidence:emit": "node --import tsx scripts/evidence-gate.ts emit", + "evidence:validate": "node --import tsx scripts/evidence-gate.ts validate", + "evidence:report": "node --import tsx scripts/evidence-reporter.ts", + "heal:check": "node --import tsx scripts/stall-auto-heal.ts", + "watchdog:run": "node --import tsx scripts/watchdog-orchestrator.ts", + "goal:gate": "node --import tsx scripts/goal-gate.ts", + "health:snapshot": "node --import tsx scripts/health-snapshot.ts", + "health:snapshot:periodic": "node --import tsx scripts/periodic-snapshot.ts", + "worker:resident": "node --import tsx scripts/resident-worker.ts", + "supervisor:resident": "node --import tsx scripts/resident-supervisor.ts", + "dod:check": "node --import tsx scripts/dod-check.ts" + }, + "devDependencies": { + "@types/node": "^22.13.10", + "tsx": "^4.20.0", + "typescript": "^5.8.2" + } +} diff --git a/scripts/dod-check.ts b/scripts/dod-check.ts new file mode 100644 index 0000000..c336dcd --- /dev/null +++ b/scripts/dod-check.ts @@ -0,0 +1,651 @@ +import { mkdir, readFile, rename, writeFile } from "node:fs/promises"; +import { homedir } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import { spawn } from "node:child_process"; + +interface DoDCheckResult { + id: string; + passed: boolean; + detail: string; +} + +type DoDStatus = "DONE" | "NOT_DONE"; + +interface DoDStatusArtifact { + generatedAt: string; + runtimeDir: string; + status: DoDStatus; + passed: boolean; + checks: DoDCheckResult[]; +} + +interface WorkerProgress { + cycle?: number; + lastStep?: { + id?: string; + exitCode?: number; + }; +} + +interface ProductDoDDefinition { + fullChinese: boolean; + nonTechnicalCopy: boolean; + middleSchoolReadable: boolean; + globalVisibility: boolean; + appleNativeUI?: boolean; + realSubscriptionConnected?: boolean; + tiApproval?: boolean; + notes?: string; +} + +interface ProductSourceAudit { + fullChinese: boolean; + nonTechnicalCopy: boolean; + middleSchoolReadable: boolean; + globalVisibility: boolean; + appleNativeUI: boolean; + details: { + fullChinese: string; + nonTechnicalCopy: string; + middleSchoolReadable: string; + globalVisibility: string; + appleNativeUI: string; + }; +} + +interface RealSubscriptionAudit { + connected: boolean; + detail: string; + sourcePath?: string; +} + +interface PhraseGroup { + id: string; + options: string[]; +} + +const REQUIRED_ZH_GROUPS: PhraseGroup[] = [ + { id: "title", options: ["全局可视", "全局总览"] }, + { + id: "summary", + options: [ + "一眼看全局:定时任务、任务心跳、当前任务和工具调用。", + "一眼看全局:定时任务、任务心跳、当前任务、工具调用。", + "一眼看四件事:定时任务、任务心跳、当前任务、工具调用。", + ], + }, + { id: "schedule", options: ["定时任务:"] }, + { id: "heartbeat", options: ["任务心跳:", "心跳检查:"] }, + { id: "currentTasks", options: ["当前任务:", "进行中任务:"] }, + { id: "toolCalls", options: ["工具调用:"] }, +]; + +const REQUIRED_EN_GROUPS: PhraseGroup[] = [ + { id: "title", options: ["Global Visibility"] }, + { + id: "summary", + options: [ + "One place to see cron, heartbeat, current tasks, and tool calls.", + "One place to see timed jobs, heartbeat, current tasks, and tool calls.", + "At a glance: timed jobs, heartbeat, current tasks, and tool calls.", + "Simple view: schedule checks (cron), heartbeat checks, current tasks, and tool calls.", + "Simple view: schedule (cron), heartbeat, tasks in progress, and tool calls.", + ], + }, + { id: "schedule", options: ["Cron:", "Timed jobs:", "Schedule checks (cron):", "Schedule (cron):"] }, + { id: "heartbeat", options: ["Heartbeat:", "Heartbeat checks:"] }, + { id: "currentTasks", options: ["Current tasks:", "Tasks in progress:"] }, + { id: "toolCalls", options: ["Tool calls:"] }, +]; + +const GLOBAL_VISIBILITY_RENDER_TOKENS = [ + "renderGlobalVisibilityStrip(", + "renderGlobalVisibilityCard(", + "renderGlobalVisibilityStripCard(", + '

', + "copy.scheduleLabel", + "copy.heartbeatLabel", + "copy.currentTasksLabel", + "copy.toolCallsLabel", + 'buildGlobalVisibilityDetailHref("cron", language)', + 'buildGlobalVisibilityDetailHref("heartbeat", language)', + 'buildGlobalVisibilityDetailHref("current_task", language)', + 'buildGlobalVisibilityDetailHref("tool_call", language)', + 'taskType: "cron"', + 'taskType: "heartbeat"', + 'taskType: "current_task"', + 'taskType: "tool_call"', + "signalCounts: {", + "schedule: enabledCronCount", + "heartbeat: enabledHeartbeatCount", + "currentTasks: currentTasksCount", + "toolCalls: toolCallsCount", +]; +const GLOBAL_VISIBILITY_RENDER_GROUPS: PhraseGroup[] = [ + { + id: "overview-block", + options: [ + 'const globalVisibilityBlock = options.section === "overview" ? globalVisibilityCard : globalVisibilityStripCard;', + 'const globalVisibilityBlock = options.section === "overview" ? globalVisibilityCard : "";', + ], + }, +]; + +const NON_TECH_JARGON = ["telemetry", "instrumentation", "payload", "schema", "protocol", "SDK"]; +const MIXED_ZH_PHRASES = [ + "Cron 正在运行。", + "还没有设置 Cron。", + "保持 Cron 开启。", + "定时任务(cron)", + "定时检查(cron)", + "定时安排(cron)", +]; +const APPLE_NATIVE_UI_RENDER_TOKENS = [ + "data-apple-window-controls=\"true\"", + "--apple-glass-blur", + "-webkit-backdrop-filter", + "@media (prefers-reduced-motion: reduce)", +]; +const APPLE_NATIVE_UI_RENDER_GROUPS: PhraseGroup[] = [ + { + id: "polish-marker", + options: [ + 'data-ui-polish="apple-native-v1"', + 'data-ui-polish="apple-native-v2"', + 'data-ui-polish="apple-native-v3"', + ], + }, + { + id: "hover-elevation", + options: [ + ".card:hover { transform: translateY(-1px);", + ".card:hover {", + ], + }, +]; + +async function writeJsonAtomic(path: string, value: unknown): Promise { + await mkdir(dirname(path), { recursive: true }); + const tmp = `${path}.${process.pid}.${Date.now()}.tmp`; + await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8"); + await rename(tmp, path); +} + +async function runNodeScript( + scriptPath: string, + args: string[], +): Promise<{ code: number | null; stdout: string; stderr: string }> { + return await new Promise((resolvePromise, rejectPromise) => { + const child = spawn(process.execPath, ["--import", "tsx", scriptPath, ...args], { + cwd: process.cwd(), + env: process.env, + stdio: ["ignore", "pipe", "pipe"], + }); + + let stdout = ""; + let stderr = ""; + child.stdout.on("data", (chunk) => { + stdout += String(chunk); + }); + child.stderr.on("data", (chunk) => { + stderr += String(chunk); + }); + child.on("error", rejectPromise); + child.on("close", (code) => resolvePromise({ code, stdout, stderr })); + }); +} + +async function readProgress(path: string): Promise { + try { + const raw = await readFile(path, "utf8"); + return JSON.parse(raw) as WorkerProgress; + } catch { + return null; + } +} + +async function readProductDoD(path: string): Promise { + try { + const raw = await readFile(path, "utf8"); + return JSON.parse(raw) as ProductDoDDefinition; + } catch { + return null; + } +} + +function findMissingPhrases(input: string, phrases: string[]): string[] { + return phrases.filter((phrase) => !input.includes(phrase)); +} + +function findMissingGroups(input: string, groups: PhraseGroup[]): string[] { + return groups + .filter((group) => group.options.every((phrase) => !input.includes(phrase))) + .map((group) => `${group.id}(${group.options.join(" | ")})`); +} + +async function auditProductSource(uiServerPath: string): Promise { + let source = ""; + try { + source = await readFile(uiServerPath, "utf8"); + } catch (error) { + const detail = error instanceof Error ? error.message : String(error); + return { + fullChinese: false, + nonTechnicalCopy: false, + middleSchoolReadable: false, + globalVisibility: false, + appleNativeUI: false, + details: { + fullChinese: `unable to read ${uiServerPath}: ${detail}`, + nonTechnicalCopy: `unable to read ${uiServerPath}: ${detail}`, + middleSchoolReadable: `unable to read ${uiServerPath}: ${detail}`, + globalVisibility: `unable to read ${uiServerPath}: ${detail}`, + appleNativeUI: `unable to read ${uiServerPath}: ${detail}`, + }, + }; + } + + const copyBlock = source.match( + /function globalVisibilityCopy[\s\S]*?function formatExecutorAgentLabel/, + )?.[0]; + const modelBlock = source.match( + /async function buildGlobalVisibilityViewModel[\s\S]*?function dashboardSectionLinks/, + )?.[0]; + const globalVisibilityBlock = + [copyBlock, modelBlock] + .filter((segment): segment is string => typeof segment === "string" && segment.length > 0) + .join("\n\n") + .trim() || source; + const missingZh = findMissingGroups(globalVisibilityBlock, REQUIRED_ZH_GROUPS); + const missingEn = findMissingGroups(globalVisibilityBlock, REQUIRED_EN_GROUPS); + const missingRender = findMissingPhrases(source, GLOBAL_VISIBILITY_RENDER_TOKENS); + const missingRenderGroups = findMissingGroups(source, GLOBAL_VISIBILITY_RENDER_GROUPS); + const missingAppleNativeTokens = findMissingPhrases(source, APPLE_NATIVE_UI_RENDER_TOKENS); + const missingAppleNativeGroups = findMissingGroups(source, APPLE_NATIVE_UI_RENDER_GROUPS); + const matchedMixedZh = MIXED_ZH_PHRASES.filter((phrase) => globalVisibilityBlock.includes(phrase)); + + const matchedJargon = NON_TECH_JARGON.filter((token) => + globalVisibilityBlock.toLowerCase().includes(token.toLowerCase()), + ); + + const readabilitySamples = [ + ...REQUIRED_EN_GROUPS.flatMap((group) => group.options), + "Tasks checked:", + "Tasks selected:", + "Tasks started:", + "Recent tool calls:", + "Tool calls in recent activity:", + ]; + const longPhrases = readabilitySamples.filter((phrase) => phrase.length > 90); + const hardWords = readabilitySamples + .flatMap((phrase) => phrase.split(/[^A-Za-z]+/)) + .filter((word) => word.length >= 14); + + return { + fullChinese: missingZh.length === 0 && matchedMixedZh.length === 0, + nonTechnicalCopy: missingEn.length === 0 && matchedJargon.length === 0, + middleSchoolReadable: longPhrases.length === 0 && hardWords.length === 0, + globalVisibility: + missingRender.length === 0 && + missingRenderGroups.length === 0 && + missingEn.length === 0 && + missingZh.length === 0, + appleNativeUI: missingAppleNativeTokens.length === 0 && missingAppleNativeGroups.length === 0, + details: { + fullChinese: + missingZh.length === 0 && matchedMixedZh.length === 0 + ? "ui source includes required zh copy for global visibility" + : `missing zh copy: ${missingZh.join(", ") || "none"} mixed zh/en copy: ${matchedMixedZh.join(", ") || "none"}`, + nonTechnicalCopy: + missingEn.length === 0 && matchedJargon.length === 0 + ? "global visibility copy remains plain-language and operator-facing" + : `missing en plain copy=${missingEn.join(", ") || "none"} jargon=${matchedJargon.join(", ") || "none"}`, + middleSchoolReadable: + longPhrases.length === 0 && hardWords.length === 0 + ? "global visibility copy length/wording stays middle-school readable" + : `long phrases=${longPhrases.join(" | ") || "none"} hard words=${hardWords.join(", ") || "none"}`, + globalVisibility: + missingRender.length === 0 && missingRenderGroups.length === 0 + ? "strip + card render all four signals (cron/heartbeat/current tasks/tool calls) across sections" + : `missing render tokens: ${[...missingRender, ...missingRenderGroups].join(", ")}`, + appleNativeUI: + missingAppleNativeTokens.length === 0 && missingAppleNativeGroups.length === 0 + ? "apple-native polish markers present (glass surfaces, window controls, reduced-motion safety)" + : `missing apple-native tokens: ${[...missingAppleNativeTokens, ...missingAppleNativeGroups].join(", ")}`, + }, + }; +} + +function subscriptionSnapshotPaths(runtimeDir: string): string[] { + const openclawHome = process.env.OPENCLAW_HOME?.trim() || join(homedir(), ".openclaw"); + const paths = [ + process.env.OPENCLAW_SUBSCRIPTION_SNAPSHOT_PATH?.trim(), + resolve(runtimeDir, "subscription-snapshot.json"), + join(openclawHome, "subscription.json"), + join(openclawHome, "subscription-snapshot.json"), + join(openclawHome, "billing", "subscription.json"), + join(openclawHome, "billing", "subscription-snapshot.json"), + join(openclawHome, "billing", "usage.json"), + join(openclawHome, "usage", "subscription.json"), + join(openclawHome, "usage", "subscription-snapshot.json"), + ].filter((item): item is string => typeof item === "string" && item.trim().length > 0); + return [...new Set(paths)]; +} + +function asObjectValue(input: unknown): Record | undefined { + return input !== null && typeof input === "object" && !Array.isArray(input) + ? (input as Record) + : undefined; +} + +function asStringValue(input: unknown): string | undefined { + return typeof input === "string" ? input : undefined; +} + +function pickFirstNonNegative(values: unknown[]): number | undefined { + for (const value of values) { + if (typeof value === "number" && Number.isFinite(value) && value >= 0) return value; + } + return undefined; +} + +function parseSubscriptionSnapshotSignal(raw: unknown): { + consumed?: number; + remaining?: number; + limit?: number; + unit: string; + planLabel: string; +} { + const root = asObjectValue(raw) ?? {}; + const subscription = asObjectValue(root.subscription) ?? {}; + const usage = asObjectValue(root.usage) ?? asObjectValue(subscription.usage) ?? {}; + const rootCost = asObjectValue(root.cost) ?? {}; + const subscriptionCost = asObjectValue(subscription.cost) ?? {}; + const plan = asObjectValue(root.plan) ?? asObjectValue(subscription.plan) ?? {}; + + const consumed = pickFirstNonNegative([ + root.consumed, + root.used, + root.spent, + subscription.consumed, + subscription.used, + subscription.spent, + usage.consumed, + usage.used, + usage.spent, + rootCost.used, + rootCost.spent, + subscriptionCost.used, + subscriptionCost.spent, + ]); + const limit = pickFirstNonNegative([ + root.limit, + root.total, + root.quota, + root.cap, + subscription.limit, + subscription.total, + subscription.quota, + subscription.cap, + usage.limit, + usage.total, + usage.quota, + rootCost.limit, + subscriptionCost.limit, + ]); + const remaining = pickFirstNonNegative([ + root.remaining, + root.left, + subscription.remaining, + subscription.left, + usage.remaining, + usage.left, + typeof limit === "number" && typeof consumed === "number" ? Math.max(0, limit - consumed) : undefined, + ]); + + const unit = + asStringValue(root.unit) ?? + asStringValue(subscription.unit) ?? + asStringValue(usage.unit) ?? + asStringValue(root.currency) ?? + asStringValue(subscription.currency) ?? + asStringValue(usage.currency) ?? + "USD"; + const planLabel = + asStringValue(plan.name) ?? + asStringValue(root.planLabel) ?? + asStringValue(root.planName) ?? + asStringValue(root.plan) ?? + asStringValue(root.tier) ?? + asStringValue(subscription.planLabel) ?? + asStringValue(subscription.planName) ?? + asStringValue(subscription.plan) ?? + asStringValue(subscription.tier) ?? + "Subscription"; + + return { + consumed, + remaining, + limit, + unit, + planLabel, + }; +} + +async function auditRealSubscriptionSource(runtimeDir: string): Promise { + const paths = subscriptionSnapshotPaths(runtimeDir); + const partial: string[] = []; + const unreadable: string[] = []; + const missing: string[] = []; + + for (const path of paths) { + try { + const raw = JSON.parse(await readFile(path, "utf8")) as unknown; + const parsed = parseSubscriptionSnapshotSignal(raw); + const hasAllFields = + typeof parsed.consumed === "number" && typeof parsed.remaining === "number" && typeof parsed.limit === "number"; + if (hasAllFields) { + return { + connected: true, + sourcePath: path, + detail: `provider snapshot connected at ${path} (${parsed.planLabel}; ${parsed.unit})`, + }; + } + const missingFields = [ + typeof parsed.consumed === "number" ? "" : "consumed", + typeof parsed.remaining === "number" ? "" : "remaining", + typeof parsed.limit === "number" ? "" : "limit", + ].filter((item) => item !== ""); + partial.push(`${path} missing ${missingFields.join("/") || "required fields"}`); + } catch (error) { + const code = + error && typeof error === "object" && "code" in error && typeof (error as { code?: unknown }).code === "string" + ? (error as { code: string }).code + : undefined; + if (code === "ENOENT") { + missing.push(path); + } else { + unreadable.push(`${path}${code ? ` (${code})` : ""}`); + } + } + } + + if (partial.length > 0) { + return { + connected: false, + detail: `provider snapshot found but incomplete: ${partial.join("; ")}`, + }; + } + if (unreadable.length > 0) { + return { + connected: false, + detail: `provider snapshot unreadable: ${unreadable.join("; ")}`, + }; + } + return { + connected: false, + detail: missing.length > 0 ? `provider snapshot missing at: ${missing.join(", ")}` : "provider snapshot paths not configured", + }; +} + +function toProductChecks( + product: ProductDoDDefinition | null, + sourceAudit: ProductSourceAudit, + subscriptionAudit: RealSubscriptionAudit, + requireTiApproval: boolean, +): DoDCheckResult[] { + const declared = product ?? null; + const checks: DoDCheckResult[] = [ + { + id: "product-dod-definition", + passed: declared !== null, + detail: declared ? "runtime/evidence/product-dod.json present" : "missing runtime/evidence/product-dod.json", + }, + ]; + + const declaredFullChinese = declared?.fullChinese === true; + checks.push({ + id: "product-full-chinese", + passed: declaredFullChinese && sourceAudit.fullChinese, + detail: `声明=${declaredFullChinese ? "通过" : "未通过"};源码=${sourceAudit.fullChinese ? "通过" : "未通过"}(${sourceAudit.details.fullChinese})`, + }); + + const declaredNonTechnical = declared?.nonTechnicalCopy === true; + checks.push({ + id: "product-non-technical-copy", + passed: declaredNonTechnical && sourceAudit.nonTechnicalCopy, + detail: `声明=${declaredNonTechnical ? "通过" : "未通过"};源码=${sourceAudit.nonTechnicalCopy ? "通过" : "未通过"}(${sourceAudit.details.nonTechnicalCopy})`, + }); + + const declaredReadable = declared?.middleSchoolReadable === true; + checks.push({ + id: "product-middle-school-readable", + passed: declaredReadable && sourceAudit.middleSchoolReadable, + detail: `声明=${declaredReadable ? "通过" : "未通过"};源码=${sourceAudit.middleSchoolReadable ? "通过" : "未通过"}(${sourceAudit.details.middleSchoolReadable})`, + }); + + const declaredGlobalVisibility = declared?.globalVisibility === true; + checks.push({ + id: "product-global-visibility", + passed: declaredGlobalVisibility && sourceAudit.globalVisibility, + detail: `声明=${declaredGlobalVisibility ? "通过" : "未通过"};源码=${sourceAudit.globalVisibility ? "通过" : "未通过"}(${sourceAudit.details.globalVisibility})`, + }); + + const declaredAppleNativeUI = declared?.appleNativeUI === true; + checks.push({ + id: "product-apple-native-ui", + passed: declaredAppleNativeUI && sourceAudit.appleNativeUI, + detail: + `声明=${declaredAppleNativeUI ? "通过" : "未通过"};` + + `客观检查=${sourceAudit.appleNativeUI ? "通过" : "未通过"}(${sourceAudit.details.appleNativeUI})`, + }); + + const declaredRealSubscriptionConnected = declared?.realSubscriptionConnected === true; + checks.push({ + id: "product-real-subscription-connected", + passed: declaredRealSubscriptionConnected && subscriptionAudit.connected, + detail: + `声明=${declaredRealSubscriptionConnected ? "通过" : "未通过"};` + + `客观检查=${subscriptionAudit.connected ? "通过" : "未通过"}(${subscriptionAudit.detail})`, + }); + + const tiApproved = declared?.tiApproval === true; + checks.push({ + id: "product-ti-approval", + passed: requireTiApproval ? tiApproved : true, + detail: requireTiApproval + ? tiApproved + ? "Ti 人工验收:通过(严格模式)" + : "Ti 人工验收:未通过(严格模式)" + : tiApproved + ? "Ti 人工验收:已记录(非阻塞)" + : "Ti 人工验收:待补充(非阻塞)", + }); + + return checks; +} + +async function runChecks(runtimeDir: string): Promise { + const checks: DoDCheckResult[] = []; + const goalPath = resolve(runtimeDir, "goal-state.json"); + const evidencePath = resolve(runtimeDir, "evidence", "latest.json"); + const progressPath = resolve(runtimeDir, "evidence", "worker-progress.json"); + const productDoDPath = resolve(runtimeDir, "evidence", "product-dod.json"); + const uiServerPath = resolve(process.cwd(), "src", "ui", "server.ts"); + const requireTiApproval = (process.env.DOD_REQUIRE_TI_APPROVAL ?? "false").toLowerCase() === "true"; + + const goalGate = await runNodeScript(resolve(process.cwd(), "scripts", "goal-gate.ts"), [goalPath]); + checks.push({ + id: "goal-gate", + passed: goalGate.code === 0, + detail: goalGate.code === 0 ? "goal gate passed" : (goalGate.stderr.trim() || goalGate.stdout.trim() || "goal gate failed"), + }); + + const evidenceGate = await runNodeScript(resolve(process.cwd(), "scripts", "evidence-gate.ts"), ["validate", evidencePath]); + checks.push({ + id: "evidence-gate", + passed: evidenceGate.code === 0, + detail: + evidenceGate.code === 0 + ? "evidence bundle valid" + : (evidenceGate.stderr.trim() || evidenceGate.stdout.trim() || "evidence validation failed"), + }); + + const progress = await readProgress(progressPath); + const stepPassed = progress?.lastStep?.exitCode === 0; + checks.push({ + id: "worker-last-step", + passed: stepPassed, + detail: stepPassed + ? `cycle=${progress?.cycle ?? "unknown"} step=${progress?.lastStep?.id ?? "unknown"} exit=0` + : "missing or failing worker-progress lastStep.exitCode", + }); + + const product = await readProductDoD(productDoDPath); + const sourceAudit = await auditProductSource(uiServerPath); + const subscriptionAudit = await auditRealSubscriptionSource(runtimeDir); + checks.push(...toProductChecks(product, sourceAudit, subscriptionAudit, requireTiApproval)); + + return checks; +} + +async function main(): Promise { + const runtimeDir = resolve(process.argv[2] ?? join(process.cwd(), "runtime")); + const statusPath = resolve(process.argv[3] ?? join(runtimeDir, "evidence", "dod-status.json")); + + let checks: DoDCheckResult[] = []; + try { + checks = await runChecks(runtimeDir); + } catch (error) { + checks = [ + { + id: "dod-check-runtime", + passed: false, + detail: error instanceof Error ? error.message : String(error), + }, + ]; + } + + const passed = checks.every((check) => check.passed); + const artifact: DoDStatusArtifact = { + generatedAt: new Date().toISOString(), + runtimeDir, + status: passed ? "DONE" : "NOT_DONE", + passed, + checks, + }; + + await writeJsonAtomic(statusPath, artifact); + + if (!artifact.passed) { + console.error(`NOT_DONE status=${statusPath}`); + process.exit(1); + } + + console.log(`DONE status=${statusPath}`); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}); diff --git a/scripts/evidence-gate.ts b/scripts/evidence-gate.ts new file mode 100644 index 0000000..57ff604 --- /dev/null +++ b/scripts/evidence-gate.ts @@ -0,0 +1,78 @@ +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; + +export interface EvidenceBundle { + generatedAt: string; + itemId: string; + completed: string; + filesChanged: string[]; + verification: string; + visibleMarker: string; +} + +const cmd = (process.argv[2] ?? "validate").toLowerCase(); +const targetPath = resolve(process.argv[3] ?? join(process.cwd(), "runtime", "evidence", "latest.json")); + +export function validateBundle(bundle: Partial): string[] { + const errors: string[] = []; + if (!bundle.itemId || bundle.itemId.trim().length === 0) errors.push("missing itemId"); + if (!bundle.completed || bundle.completed.trim().length === 0) errors.push("missing completed"); + if (!Array.isArray(bundle.filesChanged) || bundle.filesChanged.length === 0) errors.push("missing filesChanged[]"); + if (!bundle.verification || bundle.verification.trim().length === 0) errors.push("missing verification"); + if (!bundle.visibleMarker || bundle.visibleMarker.trim().length === 0) errors.push("missing visibleMarker"); + return errors; +} + +async function emit(path: string): Promise { + const files = (process.env.EVIDENCE_FILES ?? "") + .split(",") + .map((x) => x.trim()) + .filter(Boolean); + + const bundle: EvidenceBundle = { + generatedAt: new Date().toISOString(), + itemId: process.env.EVIDENCE_ITEM_ID ?? "", + completed: process.env.EVIDENCE_COMPLETED ?? "", + filesChanged: files, + verification: process.env.EVIDENCE_VERIFICATION ?? "", + visibleMarker: process.env.EVIDENCE_VISIBLE_MARKER ?? "", + }; + + const errors = validateBundle(bundle); + if (errors.length > 0) { + console.error(`EVIDENCE_INVALID ${errors.join("; ")}`); + return 1; + } + + await mkdir(dirname(path), { recursive: true }); + await writeFile(path, `${JSON.stringify(bundle, null, 2)}\n`, "utf8"); + console.log(`EVIDENCE_EMITTED ${path}`); + return 0; +} + +async function validate(path: string): Promise { + try { + const raw = await readFile(path, "utf8"); + const bundle = JSON.parse(raw) as Partial; + const errors = validateBundle(bundle); + if (errors.length > 0) { + console.error(`EVIDENCE_INVALID ${errors.join("; ")}`); + return 1; + } + console.log(`EVIDENCE_VALID item=${bundle.itemId} file=${path}`); + return 0; + } catch (error) { + console.error(`EVIDENCE_READ_ERROR ${error instanceof Error ? error.message : String(error)}`); + return 1; + } +} + +async function main(): Promise { + const code = cmd === "emit" ? await emit(targetPath) : await validate(targetPath); + process.exit(code); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}); diff --git a/scripts/evidence-reporter.ts b/scripts/evidence-reporter.ts new file mode 100644 index 0000000..9a4da20 --- /dev/null +++ b/scripts/evidence-reporter.ts @@ -0,0 +1,128 @@ +import { mkdir, readFile, rename, writeFile } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; +import { spawn } from "node:child_process"; + +interface EvidenceBundle { + generatedAt: string; + itemId: string; + completed: string; + filesChanged: string[]; + verification: string; + visibleMarker: string; +} + +interface OutboundProgressPayload { + reportedAt: string; + evidencePath: string; + progress: { + itemId: string; + completed: string; + filesChanged: string[]; + verification: string; + visibleMarker: string; + }; +} + +function buildSnapshotId(now = new Date()): string { + const yyyy = now.getUTCFullYear(); + const mm = String(now.getUTCMonth() + 1).padStart(2, "0"); + const dd = String(now.getUTCDate()).padStart(2, "0"); + const hh = String(now.getUTCHours()).padStart(2, "0"); + const min = String(now.getUTCMinutes()).padStart(2, "0"); + const sec = String(now.getUTCSeconds()).padStart(2, "0"); + return `${yyyy}${mm}${dd}-${hh}${min}${sec}Z`; +} + +function isCompletionLike(text: string): boolean { + return /(\bdone\b|\bcompleted\b|完成|已完成|全部完成)/i.test(text); +} + +function isFullPassLike(text: string): boolean { + return /(\bfull\s+pass\b|\ball\s+checks?\s+pass(?:ed)?\b|全部通过|全通过|全量通过|全面通过)/i.test(text); +} + +async function runNodeScript(scriptPath: string, args: string[]): Promise { + return await new Promise((resolvePromise, rejectPromise) => { + const child = spawn(process.execPath, ["--import", "tsx", scriptPath, ...args], { + cwd: process.cwd(), + env: process.env, + stdio: "ignore", + }); + child.on("error", rejectPromise); + child.on("close", (code) => resolvePromise(code)); + }); +} + +function validateEvidenceBundle(bundle: Partial): string[] { + const errors: string[] = []; + if (!bundle.itemId || bundle.itemId.trim() === "") errors.push("missing itemId"); + if (!bundle.completed || bundle.completed.trim() === "") errors.push("missing completed"); + if (!Array.isArray(bundle.filesChanged) || bundle.filesChanged.length === 0) errors.push("missing filesChanged[]"); + if (!bundle.verification || bundle.verification.trim() === "") errors.push("missing verification"); + if (!bundle.visibleMarker || bundle.visibleMarker.trim() === "") errors.push("missing visibleMarker"); + return errors; +} + +async function writeJsonAtomic(path: string, value: unknown): Promise { + await mkdir(dirname(path), { recursive: true }); + const tmp = `${path}.${process.pid}.${Date.now()}.tmp`; + await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8"); + await rename(tmp, path); +} + +async function main(): Promise { + const evidencePath = resolve(process.argv[2] ?? join(process.cwd(), "runtime", "evidence", "latest.json")); + const outboundDir = resolve(process.argv[3] ?? join(process.cwd(), "runtime", "evidence", "outbound")); + + const raw = await readFile(evidencePath, "utf8"); + const evidence = JSON.parse(raw) as Partial; + const errors = validateEvidenceBundle(evidence); + if (errors.length > 0) { + console.error(`REPORT_BLOCKED_EVIDENCE ${errors.join("; ")}`); + process.exit(1); + } + + const completionText = String(evidence.completed ?? ""); + const requireDodGate = (process.env.REQUIRE_DOD_FOR_COMPLETION ?? "true").toLowerCase() !== "false"; + const claimsCompletion = isCompletionLike(completionText) || isFullPassLike(completionText); + if ((requireDodGate && claimsCompletion) || isFullPassLike(completionText)) { + const runtimeDir = resolve(process.cwd(), "runtime"); + const dodCode = await runNodeScript(resolve(process.cwd(), "scripts", "dod-check.ts"), [runtimeDir]); + if (dodCode !== 0) { + console.error("REPORT_BLOCKED_DOD NOT_DONE"); + process.exit(1); + } + } + + const now = new Date(); + const snapshotId = buildSnapshotId(now); + const snapshotPath = resolve(outboundDir, `${snapshotId}.json`); + const latestPath = resolve(outboundDir, "latest.json"); + const pointerPath = resolve(outboundDir, "latest.pointer.json"); + const payload: OutboundProgressPayload = { + reportedAt: now.toISOString(), + evidencePath, + progress: { + itemId: evidence.itemId ?? "", + completed: evidence.completed ?? "", + filesChanged: evidence.filesChanged ?? [], + verification: evidence.verification ?? "", + visibleMarker: evidence.visibleMarker ?? "", + }, + }; + + await writeJsonAtomic(snapshotPath, payload); + await writeJsonAtomic(latestPath, payload); + await writeJsonAtomic(pointerPath, { + updatedAt: now.toISOString(), + snapshotId, + latest: snapshotPath, + }); + + console.log(`REPORT_EMITTED latest=${latestPath} snapshot=${snapshotPath}`); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}); diff --git a/scripts/export-staff-avatars.ts b/scripts/export-staff-avatars.ts new file mode 100644 index 0000000..19e5202 --- /dev/null +++ b/scripts/export-staff-avatars.ts @@ -0,0 +1,403 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; +import vm from "node:vm"; +import { deflateSync } from "node:zlib"; + +type Sprite = string[][]; + +type SpriteRuntime = { + spriteSize: number; + spriteFactory: Record Sprite>; + spriteVisualSpanCompensation: Record; +}; + +type StaffAvatarExport = { + agentId: string; + animal: string; + label: string; + labelZh: string; +}; + +type SpriteBounds = { + minX: number; + minY: number; + maxX: number; + maxY: number; + width: number; + height: number; + span: number; +}; + +export const STAFF_AVATARS: StaffAvatarExport[] = [ + { agentId: "codex", animal: "robot", label: "Codex", labelZh: "机器人" }, + { agentId: "coq", animal: "rooster", label: "Coq", labelZh: "公鸡" }, + { agentId: "dolphin", animal: "dolphin", label: "Dolphin", labelZh: "海豚" }, + { agentId: "main", animal: "lion", label: "Main", labelZh: "狮子" }, + { agentId: "monkey", animal: "monkey", label: "Monkey", labelZh: "猴子" }, + { agentId: "otter", animal: "otter", label: "Otter", labelZh: "水獭" }, + { agentId: "pandas", animal: "panda", label: "Pandas", labelZh: "熊猫" }, + { agentId: "tiger", animal: "tiger", label: "Tiger", labelZh: "老虎" }, +]; + +export function extractSpriteRuntime(source: string): SpriteRuntime { + const start = source.indexOf("const spriteSize = 44;"); + const end = source.indexOf("const motionActors = [];", start); + if (start < 0 || end < 0 || end <= start) { + throw new Error("Unable to locate embedded staff avatar sprite runtime in src/ui/server.ts"); + } + + const block = source.slice(start, end); + const runtime = vm.runInNewContext( + ` + (() => { + ${block} + return { spriteSize, spriteFactory, spriteVisualSpanCompensation }; + })() + `, + { Math }, + ) as SpriteRuntime; + + if (!runtime || typeof runtime.spriteSize !== "number" || !runtime.spriteFactory || !runtime.spriteVisualSpanCompensation) { + throw new Error("Failed to evaluate embedded avatar sprite runtime"); + } + + return runtime; +} + +export async function loadSpriteRuntime(serverPath: string): Promise { + const source = await fs.readFile(serverPath, "utf8"); + return extractSpriteRuntime(source); +} + +export function getSpriteBounds(sprite: Sprite): SpriteBounds { + let minX = Number.POSITIVE_INFINITY; + let minY = Number.POSITIVE_INFINITY; + let maxX = Number.NEGATIVE_INFINITY; + let maxY = Number.NEGATIVE_INFINITY; + + for (let y = 0; y < sprite.length; y += 1) { + for (let x = 0; x < sprite[y].length; x += 1) { + if (!sprite[y][x]) continue; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + + if (!Number.isFinite(minX) || !Number.isFinite(minY) || !Number.isFinite(maxX) || !Number.isFinite(maxY)) { + return { minX: 0, minY: 0, maxX: 0, maxY: 0, width: 1, height: 1, span: 1 }; + } + + const width = maxX - minX + 1; + const height = maxY - minY + 1; + return { minX, minY, maxX, maxY, width, height, span: Math.max(width, height) }; +} + +export function centerSprite(sprite: Sprite, padding = 2): Sprite { + const bounds = getSpriteBounds(sprite); + const size = bounds.span + padding * 2; + const centered = Array.from({ length: size }, () => Array(size).fill("")); + const offsetX = Math.floor((size - bounds.width) / 2); + const offsetY = Math.floor((size - bounds.height) / 2); + + for (let y = bounds.minY; y <= bounds.maxY; y += 1) { + for (let x = bounds.minX; x <= bounds.maxX; x += 1) { + const color = sprite[y]?.[x]; + if (!color) continue; + centered[offsetY + (y - bounds.minY)][offsetX + (x - bounds.minX)] = color; + } + } + + return centered; +} + +export function renderSpriteSvg(sprite: Sprite, pixelScale = 8): string { + const centered = centerSprite(sprite); + const size = centered.length; + const width = size * pixelScale; + const rects: string[] = []; + + for (let y = 0; y < size; y += 1) { + for (let x = 0; x < size; x += 1) { + const color = centered[y]?.[x]; + if (!color) continue; + rects.push( + ``, + ); + } + } + + return [ + ``, + ``, + ...rects, + ``, + ].join("\n"); +} + +export function renderSpriteRgba(sprite: Sprite, pixelScale = 8): { width: number; height: number; data: Buffer } { + const centered = centerSprite(sprite); + const size = centered.length; + const width = size * pixelScale; + const height = size * pixelScale; + const data = Buffer.alloc(width * height * 4); + + for (let y = 0; y < size; y += 1) { + for (let x = 0; x < size; x += 1) { + const color = centered[y]?.[x]; + for (let py = 0; py < pixelScale; py += 1) { + for (let px = 0; px < pixelScale; px += 1) { + const idx = ((y * pixelScale + py) * width + (x * pixelScale + px)) * 4; + if (!color) { + data[idx + 0] = 0; + data[idx + 1] = 0; + data[idx + 2] = 0; + data[idx + 3] = 0; + continue; + } + const rgb = hexToRgb(color); + data[idx + 0] = rgb.r; + data[idx + 1] = rgb.g; + data[idx + 2] = rgb.b; + data[idx + 3] = 255; + } + } + } + } + + return { width, height, data }; +} + +function hexToRgb(hex: string): { r: number; g: number; b: number } { + const safe = hex.trim().replace(/^#/, ""); + if (safe.length !== 6) { + throw new Error(`Unsupported color "${hex}"`); + } + return { + r: Number.parseInt(safe.slice(0, 2), 16), + g: Number.parseInt(safe.slice(2, 4), 16), + b: Number.parseInt(safe.slice(4, 6), 16), + }; +} + +const crcTable = (() => { + const table = new Uint32Array(256); + for (let i = 0; i < 256; i += 1) { + let c = i; + for (let k = 0; k < 8; k += 1) { + c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1); + } + table[i] = c >>> 0; + } + return table; +})(); + +function crc32(buffer: Buffer): number { + let crc = 0xffffffff; + for (let i = 0; i < buffer.length; i += 1) { + crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ (crc >>> 8); + } + return (crc ^ 0xffffffff) >>> 0; +} + +function pngChunk(type: string, data: Buffer): Buffer { + const typeBuffer = Buffer.from(type, "ascii"); + const length = Buffer.alloc(4); + length.writeUInt32BE(data.length, 0); + const crcBuffer = Buffer.concat([typeBuffer, data]); + const crc = Buffer.alloc(4); + crc.writeUInt32BE(crc32(crcBuffer), 0); + return Buffer.concat([length, typeBuffer, data, crc]); +} + +export function renderSpritePng(sprite: Sprite, pixelScale = 8): Buffer { + const rgba = renderSpriteRgba(sprite, pixelScale); + const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]); + + const ihdr = Buffer.alloc(13); + ihdr.writeUInt32BE(rgba.width, 0); + ihdr.writeUInt32BE(rgba.height, 4); + ihdr[8] = 8; + ihdr[9] = 6; + ihdr[10] = 0; + ihdr[11] = 0; + ihdr[12] = 0; + + const stride = rgba.width * 4; + const raw = Buffer.alloc((stride + 1) * rgba.height); + for (let y = 0; y < rgba.height; y += 1) { + const rowStart = y * (stride + 1); + raw[rowStart] = 0; + rgba.data.copy(raw, rowStart + 1, y * stride, (y + 1) * stride); + } + + const idat = deflateSync(raw, { level: 9 }); + return Buffer.concat([ + signature, + pngChunk("IHDR", ihdr), + pngChunk("IDAT", idat), + pngChunk("IEND", Buffer.alloc(0)), + ]); +} + +export function renderPreviewHtml(items: StaffAvatarExport[]): string { + const cards = items + .map( + (item) => `
+ ${item.label} +
+

${item.label}

+

${item.labelZh}

+ ${item.agentId} +
+
`, + ) + .join("\n"); + + return ` + + + + Staff Avatar Exports + + + +

Staff Avatar Exports

+

Exported from the current pixel avatar definitions embedded in src/ui/server.ts.

+
+ ${cards} +
+ +`; +} + +export async function exportStaffAvatars(outputDir: string, serverPath: string): Promise { + const runtime = await loadSpriteRuntime(serverPath); + await fs.mkdir(outputDir, { recursive: true }); + + const written: string[] = []; + + for (const item of STAFF_AVATARS) { + const renderer = runtime.spriteFactory[item.animal]; + if (!renderer) { + throw new Error(`Missing renderer for animal "${item.animal}"`); + } + const sprite = renderer(); + + const svg = renderSpriteSvg(sprite); + const svgPath = path.join(outputDir, `${item.agentId}.svg`); + await fs.writeFile(svgPath, svg, "utf8"); + written.push(svgPath); + + const png = renderSpritePng(sprite); + const pngPath = path.join(outputDir, `${item.agentId}.png`); + await fs.writeFile(pngPath, png); + written.push(pngPath); + } + + const manifestPath = path.join(outputDir, "manifest.json"); + await fs.writeFile( + manifestPath, + JSON.stringify( + { + generatedAt: new Date().toISOString(), + source: "src/ui/server.ts", + count: STAFF_AVATARS.length, + avatars: STAFF_AVATARS.map((item) => ({ + agentId: item.agentId, + animal: item.animal, + label: item.label, + labelZh: item.labelZh, + svg: `${item.agentId}.svg`, + png: `${item.agentId}.png`, + })), + }, + null, + 2, + ), + "utf8", + ); + written.push(manifestPath); + + const previewPath = path.join(outputDir, "index.html"); + await fs.writeFile(previewPath, renderPreviewHtml(STAFF_AVATARS), "utf8"); + written.push(previewPath); + + return written; +} + +async function main(): Promise { + const repoRoot = process.cwd(); + const serverPath = path.join(repoRoot, "src/ui/server.ts"); + const outputDir = path.join(repoRoot, "runtime/exports/staff-avatars"); + const written = await exportStaffAvatars(outputDir, serverPath); + process.stdout.write(`Exported ${written.length} staff avatar files to ${outputDir}\n`); +} + +if (require.main === module) { + main().catch((error: unknown) => { + const message = error instanceof Error ? error.stack ?? error.message : String(error); + process.stderr.write(`${message}\n`); + process.exitCode = 1; + }); +} diff --git a/scripts/goal-gate.ts b/scripts/goal-gate.ts new file mode 100644 index 0000000..c696e15 --- /dev/null +++ b/scripts/goal-gate.ts @@ -0,0 +1,38 @@ +import { readFile } from "node:fs/promises"; +import { resolve } from "node:path"; + +interface GoalState { + goalId: string; + definitionOfDone: string[]; + phases: Array<{ id: string; status: string }>; +} + +const path = resolve(process.argv[2] ?? "runtime/goal-state.json"); + +async function main() { + const raw = await readFile(path, "utf8"); + const state = JSON.parse(raw) as GoalState; + + const inProgress = state.phases.filter((p) => p.status === "in_progress"); + const blocked = state.phases.filter((p) => p.status === "blocked"); + + if (blocked.length > 0) { + console.error(`GATE_BLOCKED phases=${blocked.map((p) => p.id).join(",")}`); + process.exit(1); + } + + if (inProgress.length > 1) { + console.error(`GATE_INVALID multiple_in_progress=${inProgress.map((p) => p.id).join(",")}`); + process.exit(1); + } + + const doneCount = state.phases.filter((p) => p.status === "done").length; + const total = state.phases.length; + const current = inProgress[0]?.id ?? "none"; + console.log(`GATE_OK goal=${state.goalId} done=${doneCount}/${total} current=${current}`); +} + +main().catch((e) => { + console.error(e instanceof Error ? e.message : String(e)); + process.exit(1); +}); diff --git a/scripts/health-snapshot.ts b/scripts/health-snapshot.ts new file mode 100644 index 0000000..a47181b --- /dev/null +++ b/scripts/health-snapshot.ts @@ -0,0 +1,56 @@ +import { mkdir, stat, writeFile } from "node:fs/promises"; +import { join, resolve } from "node:path"; + +export interface HealthSnapshot { + generatedAt: string; + files: { + lock: { path: string; ageMs: number | null }; + evidence: { path: string; ageMs: number | null }; + recovery: { path: string; ageMs: number | null }; + }; +} + +async function ageMs(path: string): Promise { + try { + const s = await stat(path); + return Math.max(0, Date.now() - s.mtimeMs); + } catch { + return null; + } +} + +export async function buildHealthSnapshot(runtimeDir = resolve(process.cwd(), "runtime")): Promise { + return { + generatedAt: new Date().toISOString(), + files: { + lock: { + path: join(runtimeDir, "run.lock"), + ageMs: await ageMs(join(runtimeDir, "run.lock")), + }, + evidence: { + path: join(runtimeDir, "evidence", "latest.json"), + ageMs: await ageMs(join(runtimeDir, "evidence", "latest.json")), + }, + recovery: { + path: join(runtimeDir, "recovery", "latest.json"), + ageMs: await ageMs(join(runtimeDir, "recovery", "latest.json")), + }, + }, + }; +} + +async function main() { + const runtime = resolve(process.cwd(), "runtime"); + const out = resolve(runtime, "health", "latest.json"); + const snapshot = await buildHealthSnapshot(runtime); + await mkdir(resolve(runtime, "health"), { recursive: true }); + await writeFile(out, JSON.stringify(snapshot, null, 2) + "\n", "utf8"); + console.log(`HEALTH_SNAPSHOT_WRITTEN ${out}`); +} + +if ((process.argv[1] ?? "").endsWith("health-snapshot.ts")) { + main().catch((e) => { + console.error(e instanceof Error ? e.message : String(e)); + process.exit(1); + }); +} diff --git a/scripts/mc_dod_evaluator.py b/scripts/mc_dod_evaluator.py new file mode 100755 index 0000000..8142692 --- /dev/null +++ b/scripts/mc_dod_evaluator.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +import datetime +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +BASE = ROOT / "runtime" +STATE_PATH = BASE / "state.json" +DOD_PATH = BASE / "evidence" / "dod-status.json" +OUTPUT_PATH = BASE / "evidence" / "dod-eval.json" +now = datetime.datetime.now(datetime.timezone.utc) +res = {"ts": now.isoformat(), "status": "fail", "reason": "init", "checks": {}} + +def load(p): + with open(p, "r", encoding="utf-8") as f: + return json.load(f) + +try: + state = load(STATE_PATH) + dod = load(DOD_PATH) + res["checks"]["state_exists"] = True + res["checks"]["dod_exists"] = True + missing = [] + for k in ["updatedAt", "status"]: + if k not in state: + missing.append(k) + res["checks"]["state_fields_ok"] = len(missing) == 0 + res["checks"]["state_missing_fields"] = missing + + fresh = False + try: + t = datetime.datetime.fromisoformat(str(state.get("updatedAt")).replace("Z", "+00:00")) + fresh = (now - t).total_seconds() <= 1200 + except Exception: + fresh = False + res["checks"]["fresh_20m"] = fresh + + text = json.dumps(dod, ensure_ascii=False) + done_all = "A1" in text and "E8" in text and ( + "all_pass" in text or "allPassed" in text or "全达标" in text + ) + res["checks"]["dod_all_pass_hint"] = done_all + + st = str(state.get("status", "")).upper() + if st in ["ALERT", "FAIL", "STALE"]: + res["status"] = "alert" + res["reason"] = f"state_status={st}" + elif not fresh: + res["status"] = "alert" + res["reason"] = "state_stale" + else: + res["status"] = "ok" + res["reason"] = "healthy" +except FileNotFoundError as e: + res["status"] = "fail" + res["reason"] = f"missing_file:{e.filename}" +except Exception as e: + res["status"] = "fail" + res["reason"] = f"exception:{e}" + +OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True) +with open(OUTPUT_PATH, "w", encoding="utf-8") as f: + json.dump(res, f, ensure_ascii=False, indent=2) +print(json.dumps(res, ensure_ascii=False)) diff --git a/scripts/mc_rollback_plan.py b/scripts/mc_rollback_plan.py new file mode 100755 index 0000000..bc7edd9 --- /dev/null +++ b/scripts/mc_rollback_plan.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +import datetime +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +BASE = ROOT / "runtime" / "evidence" +REGRESSION_PATH = BASE / "regression-status.json" +SNAPSHOT_PATH = BASE / "mission-control-jobs-v2-snapshot.json" +OUTPUT_PATH = BASE / "rollback-plan.json" +now = datetime.datetime.now(datetime.timezone.utc).isoformat() +plan = {"ts": now, "canRollback": False, "reason": "", "jobs": [], "commands": []} +try: + with open(REGRESSION_PATH, "r", encoding="utf-8") as regression_file: + reg = json.load(regression_file) + with open(SNAPSHOT_PATH, "r", encoding="utf-8") as snapshot_file: + snap = json.load(snapshot_file) + status = str(reg.get("status", "")).lower() + if status in ["fail", "alert"]: + jobs = snap.get("jobs", []) + plan["canRollback"] = True + plan["reason"] = f"regression_{status}" + for j in jobs: + jid = j.get("id") + plan["jobs"].append(jid) + plan["commands"].append(f"openclaw cron update {jid} --json ''") + else: + plan["reason"] = "regression_not_triggered" +except Exception as e: + plan["reason"] = f"error:{e}" + +BASE.mkdir(parents=True, exist_ok=True) +with open(OUTPUT_PATH, "w", encoding="utf-8") as output_file: + json.dump(plan, output_file, ensure_ascii=False, indent=2) +print(json.dumps(plan, ensure_ascii=False)) diff --git a/scripts/periodic-snapshot.ts b/scripts/periodic-snapshot.ts new file mode 100644 index 0000000..0c6218d --- /dev/null +++ b/scripts/periodic-snapshot.ts @@ -0,0 +1,76 @@ +import { mkdir, readFile, rename, writeFile } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; +import { buildHealthSnapshot } from "./health-snapshot"; + +interface SnapshotPointer { + updatedAt: string; + snapshotId: string; + latest: string; +} + +function buildSnapshotId(now = new Date()): string { + const yyyy = now.getUTCFullYear(); + const mm = String(now.getUTCMonth() + 1).padStart(2, "0"); + const dd = String(now.getUTCDate()).padStart(2, "0"); + const hh = String(now.getUTCHours()).padStart(2, "0"); + const min = String(now.getUTCMinutes()).padStart(2, "0"); + const sec = String(now.getUTCSeconds()).padStart(2, "0"); + return `${yyyy}${mm}${dd}-${hh}${min}${sec}Z`; +} + +async function writeJsonAtomic(path: string, value: unknown): Promise { + await mkdir(dirname(path), { recursive: true }); + const tmp = `${path}.${process.pid}.${Date.now()}.tmp`; + await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8"); + await rename(tmp, path); +} + +async function readJson(path: string): Promise { + const raw = await readFile(path, "utf8"); + return JSON.parse(raw) as T; +} + +async function main(): Promise { + const runtimeDir = resolve(process.argv[2] ?? join(process.cwd(), "runtime")); + const healthDir = resolve(runtimeDir, "health"); + const evidenceDir = resolve(runtimeDir, "evidence"); + const evidenceLatestPath = resolve(evidenceDir, "latest.json"); + + const now = new Date(); + const snapshotId = buildSnapshotId(now); + const healthSnapshotPath = resolve(healthDir, "snapshots", `${snapshotId}.json`); + const evidenceSnapshotPath = resolve(evidenceDir, "snapshots", `${snapshotId}.json`); + const healthLatestPath = resolve(healthDir, "latest.json"); + const healthPointerPath = resolve(healthDir, "latest.pointer.json"); + const evidencePointerPath = resolve(evidenceDir, "latest.pointer.json"); + + const healthSnapshot = await buildHealthSnapshot(runtimeDir); + const evidenceSnapshot = await readJson>(evidenceLatestPath); + + const healthPointer: SnapshotPointer = { + updatedAt: now.toISOString(), + snapshotId, + latest: healthSnapshotPath, + }; + const evidencePointer: SnapshotPointer & { sourceLatest: string } = { + updatedAt: now.toISOString(), + snapshotId, + latest: evidenceSnapshotPath, + sourceLatest: evidenceLatestPath, + }; + + await writeJsonAtomic(healthSnapshotPath, healthSnapshot); + await writeJsonAtomic(evidenceSnapshotPath, evidenceSnapshot); + await writeJsonAtomic(healthLatestPath, healthSnapshot); + await writeJsonAtomic(healthPointerPath, healthPointer); + await writeJsonAtomic(evidencePointerPath, evidencePointer); + + console.log( + `PERIODIC_SNAPSHOT_OK id=${snapshotId} health=${healthSnapshotPath} evidence=${evidenceSnapshotPath}`, + ); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}); diff --git a/scripts/release-audit.sh b/scripts/release-audit.sh new file mode 100755 index 0000000..cb4ea75 --- /dev/null +++ b/scripts/release-audit.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" + +FILES=() +while IFS= read -r file; do + FILES+=("$file") +done < <( + rg --files --hidden \ + -g '!.git/**' \ + -g '!node_modules/**' \ + -g '!dist/**' \ + -g '!runtime/**' \ + -g '!coverage/**' \ + -g '!scripts/release-audit.sh' +) + +if [ "${#FILES[@]}" -eq 0 ]; then + echo "release-audit: no source files found" >&2 + exit 1 +fi + +check_no_match() { + local description="$1" + local pattern="$2" + if rg -n --no-heading -P -e "$pattern" "${FILES[@]}" >/tmp/release-audit-match.txt 2>/dev/null; then + echo "release-audit: failed: ${description}" >&2 + cat /tmp/release-audit-match.txt >&2 + rm -f /tmp/release-audit-match.txt + exit 1 + fi + rm -f /tmp/release-audit-match.txt +} + +check_exists() { + local file="$1" + if [ ! -f "$file" ]; then + echo "release-audit: missing required file: $file" >&2 + exit 1 + fi +} + +check_exists "README.md" +check_exists "LICENSE" +check_exists ".gitignore" +check_exists ".env.example" +check_exists "package.json" + +check_no_match "absolute macOS home paths" '/Users/[^/]+/' +check_no_match "absolute Linux home paths" '/home/[^/]+/' +check_no_match "hard-coded internal channel ids" '1477617216529760378' +check_no_match "obvious OpenAI-style secret keys" 'sk-[A-Za-z0-9]{20,}' +check_no_match "hard-coded bearer tokens" 'Authorization: Bearer (?!<)[^[:space:]]+' +check_no_match "hard-coded local API tokens" 'LOCAL_API_TOKEN=(?!<)[^[:space:]]+' +check_no_match "hard-coded x-local-token header values" 'x-local-token:[[:space:]]*(?!<)[^[:space:]]+' + +if [ -d ".git" ]; then + if git ls-files | rg '^(runtime|dist|node_modules|coverage|plans|workflows)/' >/tmp/release-audit-match.txt 2>/dev/null; then + echo "release-audit: failed: ignored build/runtime/internal-only paths are tracked" >&2 + cat /tmp/release-audit-match.txt >&2 + rm -f /tmp/release-audit-match.txt + exit 1 + fi + rm -f /tmp/release-audit-match.txt +fi + +echo "release-audit: passed" diff --git a/scripts/resident-supervisor.ts b/scripts/resident-supervisor.ts new file mode 100644 index 0000000..2970f0e --- /dev/null +++ b/scripts/resident-supervisor.ts @@ -0,0 +1,306 @@ +import { mkdir, readFile, rename, stat, writeFile } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; +import { spawn } from "node:child_process"; + +interface RunLock { + owner: string; + leaseUntil: string; +} + +interface WorkerHeartbeat { + generatedAt: string; + pid?: number; + state?: string; +} + +interface SupervisorReport { + generatedAt: string; + status: "healthy" | "restarted" | "failed" | "done"; + reason: string; + retries: number; + maxRetries: number; + observed: { + heartbeatAgeMs?: number; + heartbeatState?: string; + workerPid?: number; + workerDead?: boolean; + }; + actions: string[]; +} + +function isExpired(lock: RunLock): boolean { + const expiry = Date.parse(lock.leaseUntil); + if (Number.isNaN(expiry)) return true; + return expiry <= Date.now(); +} + +async function readLock(path: string): Promise { + try { + const raw = await readFile(path, "utf8"); + return JSON.parse(raw) as RunLock; + } catch { + return null; + } +} + +async function readHeartbeat(path: string): Promise { + try { + const raw = await readFile(path, "utf8"); + return JSON.parse(raw) as WorkerHeartbeat; + } catch { + return null; + } +} + +async function ageMs(path: string): Promise { + try { + const fileStat = await stat(path); + return Math.max(0, Date.now() - fileStat.mtimeMs); + } catch { + return undefined; + } +} + +function isPidAlive(pid: number): boolean { + if (!Number.isInteger(pid) || pid <= 0) return false; + try { + process.kill(pid, 0); + return true; + } catch (error) { + const code = (error as NodeJS.ErrnoException)?.code; + if (code === "EPERM") return true; + return false; + } +} + +async function writeJsonAtomic(path: string, value: unknown): Promise { + await mkdir(dirname(path), { recursive: true }); + const tmp = `${path}.${process.pid}.${Date.now()}.tmp`; + await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8"); + await rename(tmp, path); +} + +async function appendAudit(path: string, line: string): Promise { + await mkdir(dirname(path), { recursive: true }); + let existing = ""; + try { + existing = await readFile(path, "utf8"); + } catch { + existing = ""; + } + await writeFile(path, `${existing}${line}\n`, "utf8"); +} + +async function runNodeScript( + scriptPath: string, + args: string[], + env: NodeJS.ProcessEnv = process.env, +): Promise<{ code: number | null; stdout: string; stderr: string }> { + return await new Promise((resolvePromise, rejectPromise) => { + const child = spawn(process.execPath, ["--import", "tsx", scriptPath, ...args], { + cwd: process.cwd(), + env, + stdio: ["ignore", "pipe", "pipe"], + }); + + let stdout = ""; + let stderr = ""; + child.stdout.on("data", (chunk) => { + stdout += String(chunk); + }); + child.stderr.on("data", (chunk) => { + stderr += String(chunk); + }); + child.on("error", rejectPromise); + child.on("close", (code) => resolvePromise({ code, stdout, stderr })); + }); +} + +async function runLockCommand(action: "acquire" | "renew" | "release", lockPath: string, owner: string): Promise { + const result = await runNodeScript(resolve(process.cwd(), "scripts", "run-lock.ts"), [action, lockPath], { + ...process.env, + RUN_OWNER: owner, + }); + if (result.code !== 0) { + throw new Error(result.stderr.trim() || result.stdout.trim() || `run-lock ${action} failed`); + } +} + +async function runDoDCheck(runtimeDir: string, statusPath: string): Promise { + const result = await runNodeScript(resolve(process.cwd(), "scripts", "dod-check.ts"), [runtimeDir, statusPath]); + return result.code === 0; +} + +async function startWorker( + workerEntry: string, + runtimeDir: string, + mode: "detached" | "sync", +): Promise<{ ok: boolean; detail: string }> { + if (mode === "sync") { + const run = await runNodeScript(resolve(workerEntry), [runtimeDir], process.env); + if (run.code !== 0) { + const combined = `${run.stdout}\n${run.stderr}`; + if (combined.includes("WORKER_MAX_CYCLES_REACHED")) { + return { ok: true, detail: "worker restarted (sync bounded cycles)" }; + } + return { ok: false, detail: run.stderr.trim() || run.stdout.trim() || "worker restart failed" }; + } + return { ok: true, detail: "worker restarted (sync)" }; + } + + return await new Promise((resolvePromise) => { + const child = spawn(process.execPath, ["--import", "tsx", resolve(workerEntry), runtimeDir], { + cwd: process.cwd(), + env: process.env, + detached: true, + stdio: "ignore", + }); + child.on("error", (error) => { + resolvePromise({ ok: false, detail: error instanceof Error ? error.message : String(error) }); + }); + child.unref(); + resolvePromise({ ok: true, detail: "worker restarted (detached)" }); + }); +} + +async function sleep(ms: number): Promise { + await new Promise((resolvePromise) => { + setTimeout(resolvePromise, ms); + }); +} + +async function main(): Promise { + const runtimeDir = resolve(process.argv[2] ?? join(process.cwd(), "runtime")); + const owner = process.env.RUN_OWNER ?? "pandas-main"; + const once = (process.env.SUPERVISOR_ONCE ?? "false").toLowerCase() === "true"; + const pollMs = Number(process.env.SUPERVISOR_POLL_MS ?? 15_000); + const maxRetries = Number(process.env.SUPERVISOR_MAX_RESTARTS ?? 3); + const heartbeatMaxAgeMs = Number(process.env.SUPERVISOR_HEARTBEAT_MAX_AGE_MS ?? 120_000); + const restartMode = (process.env.SUPERVISOR_RESTART_MODE ?? "detached") === "sync" ? "sync" : "detached"; + const workerEntry = resolve(process.env.SUPERVISOR_WORKER_ENTRY ?? join(process.cwd(), "scripts", "resident-worker.ts")); + + const lockPath = resolve(runtimeDir, "run.lock"); + const heartbeatPath = resolve(runtimeDir, "health", "worker-heartbeat.json"); + const dodStatusPath = resolve(runtimeDir, "evidence", "dod-status.json"); + const supervisorLockPath = resolve(runtimeDir, "health", "supervisor-lock.json"); + + const existingSupervisor = await readHeartbeat(supervisorLockPath); + const existingPid = existingSupervisor?.pid; + if (existingPid && existingPid !== process.pid && isPidAlive(existingPid)) { + console.log(`SUPERVISOR_ALREADY_RUNNING pid=${existingPid}`); + process.exit(0); + } + await writeJsonAtomic(supervisorLockPath, { + generatedAt: new Date().toISOString(), + pid: process.pid, + state: "running", + }); + const reportPath = resolve(runtimeDir, "recovery", "supervisor-latest.json"); + const auditPath = resolve(runtimeDir, "recovery", "supervisor-audit.log"); + + let retries = 0; + + while (true) { + const actions: string[] = []; + const heartbeat = await readHeartbeat(heartbeatPath); + const heartbeatAgeMs = await ageMs(heartbeatPath); + const workerPid = heartbeat?.pid; + const workerDead = workerPid !== undefined ? !isPidAlive(workerPid) : false; + const stale = heartbeatAgeMs === undefined || heartbeatAgeMs > heartbeatMaxAgeMs; + const dead = workerDead; + + let status: SupervisorReport["status"] = "healthy"; + let reason = stale ? "worker-heartbeat-stale" : "worker-healthy"; + + if (heartbeat?.state === "done") { + const dodPassed = await runDoDCheck(runtimeDir, dodStatusPath); + actions.push(`dod-check-${dodPassed ? "pass" : "fail"}`); + if (dodPassed) { + status = "done"; + reason = "dod-pass"; + } else { + reason = "worker-done-but-dod-failed"; + } + } + + if (status !== "done" && (stale || dead)) { + if (retries >= maxRetries) { + status = "failed"; + reason = "max-retries-exhausted"; + actions.push("restart-skipped-max-retries"); + } else { + const lock = await readLock(lockPath); + if (lock && !isExpired(lock) && lock.owner !== owner) { + status = "failed"; + reason = `lock-conflict owner=${lock.owner}`; + actions.push("restart-blocked-lock-conflict"); + } else { + if (lock && !isExpired(lock) && lock.owner === owner) { + await runLockCommand("release", lockPath, owner).catch(() => { + // best-effort release before restart + }); + actions.push("released-existing-owner-lock"); + } + await runLockCommand("acquire", lockPath, owner).catch(() => { + // worker can also acquire after restart; keep attempting restart. + }); + actions.push("acquired-supervisor-lock"); + + const started = await startWorker(workerEntry, runtimeDir, restartMode); + if (!started.ok) { + retries += 1; + status = retries >= maxRetries ? "failed" : "healthy"; + reason = `restart-failed: ${started.detail}`; + actions.push("restart-worker-failed"); + } else { + retries += 1; + status = "restarted"; + reason = stale && dead ? "worker-stale-and-dead" : stale ? "worker-stale" : "worker-dead"; + actions.push("restart-worker"); + } + } + } + } + + const report: SupervisorReport = { + generatedAt: new Date().toISOString(), + status, + reason, + retries, + maxRetries, + observed: { + heartbeatAgeMs, + heartbeatState: heartbeat?.state, + workerPid, + workerDead, + }, + actions, + }; + + await writeJsonAtomic(reportPath, report); + await appendAudit( + auditPath, + `${report.generatedAt} | ${status} | ${reason} | retries=${retries}/${maxRetries} | actions=${actions.join(",") || "none"}`, + ); + + if (status === "failed") { + console.error(`SUPERVISOR_FAILED report=${reportPath}`); + process.exit(1); + } + if (status === "done") { + console.log(`SUPERVISOR_DONE report=${reportPath}`); + process.exit(0); + } + if (once) { + console.log(`SUPERVISOR_ONCE status=${status} report=${reportPath}`); + process.exit(0); + } + + await sleep(pollMs); + } +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}); diff --git a/scripts/resident-worker.ts b/scripts/resident-worker.ts new file mode 100644 index 0000000..da4322b --- /dev/null +++ b/scripts/resident-worker.ts @@ -0,0 +1,322 @@ +import { mkdir, readFile, rename, writeFile } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; +import { randomUUID } from "node:crypto"; +import { spawn } from "node:child_process"; + +interface RunLock { + runId: string; + owner: string; + leaseUntil: string; +} + +interface WorkerProgressArtifact { + generatedAt: string; + runId: string; + owner: string; + cycle: number; + state: "running" | "waiting" | "done"; + lastStep: { + id: string; + command: string; + startedAt: string; + finishedAt: string; + exitCode: number | null; + stdoutTail: string; + stderrTail: string; + }; + dod: { + passed: boolean; + statusPath: string; + }; +} + +interface WorkerHeartbeatArtifact { + generatedAt: string; + runId: string; + owner: string; + pid: number; + cycle: number; + state: "running" | "waiting" | "done"; + stepId: string; + stepExitCode: number | null; + dodPassed: boolean; +} + +function getNpmCommand(): string { + return process.platform === "win32" ? "npm.cmd" : "npm"; +} + +function parseSteps(raw: string): string[] { + const steps = raw + .split(",") + .map((value) => value.trim()) + .filter(Boolean); + return steps.length > 0 ? steps : ["goal-gate"]; +} + +function getStepCommand( + stepId: string, + runtimeDir: string, +): { command: string; args: string[]; label: string } { + const npm = getNpmCommand(); + if (stepId === "build") return { command: npm, args: ["run", "build"], label: "npm run build" }; + if (stepId === "test") return { command: npm, args: ["test"], label: "npm test" }; + if (stepId === "evidence-report") { + return { command: npm, args: ["run", "evidence:report"], label: "npm run evidence:report" }; + } + if (stepId === "goal-gate") { + return { + command: process.execPath, + args: ["--import", "tsx", resolve(process.cwd(), "scripts", "goal-gate.ts"), resolve(runtimeDir, "goal-state.json")], + label: "goal-gate", + }; + } + if (stepId === "evidence-validate") { + return { + command: process.execPath, + args: [ + "--import", + "tsx", + resolve(process.cwd(), "scripts", "evidence-gate.ts"), + "validate", + resolve(runtimeDir, "evidence", "latest.json"), + ], + label: "evidence-validate", + }; + } + if (stepId === "health-snapshot") { + return { + command: process.execPath, + args: ["--import", "tsx", resolve(process.cwd(), "scripts", "health-snapshot.ts")], + label: "health-snapshot", + }; + } + if (stepId === "codex-patch") { + const prompt = process.env.WORKER_CODE_PROMPT ?? + "Improve Mission Control product DoD gaps: full Chinese coverage, non-technical copy, middle-school readability, and global visibility for cron/heartbeat/current tasks/tool calls. Make minimal safe code changes."; + return { + command: "codex", + args: ["exec", "--full-auto", prompt], + label: "codex exec --full-auto", + }; + } + throw new Error(`unknown worker step: ${stepId}`); +} + +function tail(value: string, maxChars = 2000): string { + if (value.length <= maxChars) return value; + return value.slice(value.length - maxChars); +} + +async function writeJsonAtomic(path: string, value: unknown): Promise { + await mkdir(dirname(path), { recursive: true }); + const tmp = `${path}.${process.pid}.${Date.now()}.tmp`; + await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8"); + await rename(tmp, path); +} + +async function runCommand( + command: string, + args: string[], + env: NodeJS.ProcessEnv = process.env, +): Promise<{ code: number | null; stdout: string; stderr: string }> { + return await new Promise((resolvePromise, rejectPromise) => { + const child = spawn(command, args, { + cwd: process.cwd(), + env, + stdio: ["ignore", "pipe", "pipe"], + }); + let stdout = ""; + let stderr = ""; + child.stdout.on("data", (chunk) => { + stdout += String(chunk); + }); + child.stderr.on("data", (chunk) => { + stderr += String(chunk); + }); + child.on("error", rejectPromise); + child.on("close", (code) => resolvePromise({ code, stdout, stderr })); + }); +} + +async function readLock(path: string): Promise { + try { + const raw = await readFile(path, "utf8"); + return JSON.parse(raw) as RunLock; + } catch { + return null; + } +} + +function isExpired(lock: RunLock): boolean { + const expiry = Date.parse(lock.leaseUntil); + if (Number.isNaN(expiry)) return true; + return expiry <= Date.now(); +} + +async function runLockCommand(action: "acquire" | "renew" | "release", lockPath: string, owner: string): Promise { + const result = await runCommand( + process.execPath, + ["--import", "tsx", resolve(process.cwd(), "scripts", "run-lock.ts"), action, lockPath], + { ...process.env, RUN_OWNER: owner }, + ); + if (result.code !== 0) { + throw new Error(result.stderr.trim() || result.stdout.trim() || `run-lock ${action} failed`); + } +} + +async function ensureOwnedLock(lockPath: string, owner: string): Promise { + const existing = await readLock(lockPath); + if (existing && !isExpired(existing) && existing.owner !== owner) { + throw new Error(`WORKER_LOCK_CONFLICT expected=${owner} current=${existing.owner} leaseUntil=${existing.leaseUntil}`); + } + if (!existing || isExpired(existing)) { + await runLockCommand("acquire", lockPath, owner); + return; + } + await runLockCommand("renew", lockPath, owner); +} + +async function runDoDCheck(runtimeDir: string, statusPath: string): Promise { + const result = await runCommand(process.execPath, [ + "--import", + "tsx", + resolve(process.cwd(), "scripts", "dod-check.ts"), + runtimeDir, + statusPath, + ]); + return result.code === 0; +} + +async function sleep(ms: number): Promise { + await new Promise((resolvePromise) => { + setTimeout(resolvePromise, ms); + }); +} + +async function main(): Promise { + const runtimeDir = resolve(process.argv[2] ?? join(process.cwd(), "runtime")); + const owner = process.env.RUN_OWNER ?? "pandas-main"; + const steps = parseSteps(process.env.WORKER_STEPS ?? "codex-patch,test,evidence-report,health-snapshot"); + const intervalMs = Number(process.env.WORKER_INTERVAL_MS ?? 15_000); + const maxCycles = Number(process.env.WORKER_MAX_CYCLES ?? 0); + + const lockPath = resolve(runtimeDir, "run.lock"); + const heartbeatPath = resolve(runtimeDir, "health", "worker-heartbeat.json"); + const progressPath = resolve(runtimeDir, "evidence", "worker-progress.json"); + const dodStatusPath = resolve(runtimeDir, "evidence", "dod-status.json"); + const runId = randomUUID(); + + let cycle = 0; + try { + await ensureOwnedLock(lockPath, owner); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); + } + + while (true) { + cycle += 1; + const stepId = steps[(cycle - 1) % steps.length]; + const step = getStepCommand(stepId, runtimeDir); + const stepStartedAt = new Date().toISOString(); + + const runningHeartbeat: WorkerHeartbeatArtifact = { + generatedAt: new Date().toISOString(), + runId, + owner, + pid: process.pid, + cycle, + state: "running", + stepId, + stepExitCode: null, + dodPassed: false, + }; + await writeJsonAtomic(heartbeatPath, runningHeartbeat); + + let stepResult: { code: number | null; stdout: string; stderr: string }; + try { + stepResult = await runCommand(step.command, step.args); + } catch (error) { + stepResult = { code: 1, stdout: "", stderr: error instanceof Error ? error.message : String(error) }; + } + const stepFinishedAt = new Date().toISOString(); + + try { + await ensureOwnedLock(lockPath, owner); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); + } + + const interimProgress: WorkerProgressArtifact = { + generatedAt: new Date().toISOString(), + runId, + owner, + cycle, + state: "waiting", + lastStep: { + id: stepId, + command: step.label, + startedAt: stepStartedAt, + finishedAt: stepFinishedAt, + exitCode: stepResult.code, + stdoutTail: tail(stepResult.stdout), + stderrTail: tail(stepResult.stderr), + }, + dod: { + passed: false, + statusPath: dodStatusPath, + }, + }; + + await writeJsonAtomic(progressPath, interimProgress); + + const dodPassed = await runDoDCheck(runtimeDir, dodStatusPath); + const state: WorkerProgressArtifact["state"] = dodPassed ? "done" : "waiting"; + const progress: WorkerProgressArtifact = { + ...interimProgress, + generatedAt: new Date().toISOString(), + state, + dod: { + passed: dodPassed, + statusPath: dodStatusPath, + }, + }; + + const heartbeat: WorkerHeartbeatArtifact = { + generatedAt: new Date().toISOString(), + runId, + owner, + pid: process.pid, + cycle, + state, + stepId, + stepExitCode: stepResult.code, + dodPassed, + }; + + await writeJsonAtomic(progressPath, progress); + await writeJsonAtomic(heartbeatPath, heartbeat); + + if (dodPassed) { + await runLockCommand("release", lockPath, owner).catch(() => { + // Keep done outcome even if release fails; lock lease expiry is still a safe fallback. + }); + console.log(`WORKER_DONE cycles=${cycle} dodStatus=${dodStatusPath}`); + process.exit(0); + } + + if (maxCycles > 0 && cycle >= maxCycles) { + console.error(`WORKER_MAX_CYCLES_REACHED cycles=${cycle}`); + process.exit(1); + } + + await sleep(intervalMs); + } +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}); diff --git a/scripts/run-lock.ts b/scripts/run-lock.ts new file mode 100644 index 0000000..85e9302 --- /dev/null +++ b/scripts/run-lock.ts @@ -0,0 +1,143 @@ +import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; +import { randomUUID } from "node:crypto"; + +interface RunLock { + runId: string; + owner: string; + startedAt: string; + updatedAt: string; + leaseUntil: string; + fencingToken: number; + pid?: number; +} + +const runtimeDir = resolve(process.cwd(), "runtime"); +const lockPath = resolve(process.argv[3] ?? join(runtimeDir, "run.lock")); +const cmd = (process.argv[2] ?? "status").toLowerCase(); +const owner = process.env.RUN_OWNER || "pandas-main"; +const leaseMs = Number(process.env.RUN_LEASE_MS ?? 10 * 60 * 1000); + +async function readLock(path: string): Promise { + try { + const raw = await readFile(path, "utf8"); + return JSON.parse(raw) as RunLock; + } catch { + return null; + } +} + +function isExpired(lock: RunLock, now = Date.now()): boolean { + const expiry = Date.parse(lock.leaseUntil); + if (Number.isNaN(expiry)) return true; + return expiry <= now; +} + +async function writeLock(path: string, lock: RunLock): Promise { + await mkdir(dirname(path), { recursive: true }); + const tmp = `${path}.${process.pid}.${Date.now()}.tmp`; + await writeFile(tmp, `${JSON.stringify(lock, null, 2)}\n`, "utf8"); + await rename(tmp, path); +} + +async function acquire(path: string): Promise { + const now = Date.now(); + const current = await readLock(path); + + if (current && !isExpired(current, now)) { + console.error(`LOCKED runId=${current.runId} owner=${current.owner} leaseUntil=${current.leaseUntil}`); + return 1; + } + + const nextToken = (current?.fencingToken ?? 0) + 1; + const runId = randomUUID(); + const lock: RunLock = { + runId, + owner, + startedAt: new Date(now).toISOString(), + updatedAt: new Date(now).toISOString(), + leaseUntil: new Date(now + leaseMs).toISOString(), + fencingToken: nextToken, + pid: process.pid, + }; + + await writeLock(path, lock); + console.log(`ACQUIRED runId=${lock.runId} fencingToken=${lock.fencingToken} leaseUntil=${lock.leaseUntil}`); + return 0; +} + +async function renew(path: string): Promise { + const now = Date.now(); + const lock = await readLock(path); + if (!lock) { + console.error("MISSING_LOCK"); + return 1; + } + if (isExpired(lock, now)) { + console.error(`EXPIRED runId=${lock.runId}`); + return 1; + } + if (lock.owner !== owner) { + console.error(`NOT_OWNER expected=${owner} current=${lock.owner}`); + return 1; + } + + const next: RunLock = { + ...lock, + updatedAt: new Date(now).toISOString(), + leaseUntil: new Date(now + leaseMs).toISOString(), + pid: process.pid, + }; + await writeLock(path, next); + console.log(`RENEWED runId=${next.runId} leaseUntil=${next.leaseUntil}`); + return 0; +} + +async function release(path: string): Promise { + const lock = await readLock(path); + if (!lock) { + console.log("RELEASED noop=no-lock"); + return 0; + } + if (lock.owner !== owner && !isExpired(lock)) { + console.error(`NOT_OWNER expected=${owner} current=${lock.owner}`); + return 1; + } + await rm(path, { force: true }); + console.log(`RELEASED runId=${lock.runId}`); + return 0; +} + +async function status(path: string): Promise { + const lock = await readLock(path); + if (!lock) { + console.log("STATUS unlocked"); + return 0; + } + const expired = isExpired(lock); + console.log(`STATUS ${expired ? "expired" : "locked"} runId=${lock.runId} owner=${lock.owner} leaseUntil=${lock.leaseUntil} fencingToken=${lock.fencingToken}`); + return expired ? 2 : 0; +} + +async function main(): Promise { + // quick sanity: parent runtime dir should be writable once + await mkdir(dirname(lockPath), { recursive: true }); + try { + await stat(dirname(lockPath)); + } catch { + // ignore + } + + let code = 0; + if (cmd === "acquire") code = await acquire(lockPath); + else if (cmd === "renew") code = await renew(lockPath); + else if (cmd === "release") code = await release(lockPath); + else code = await status(lockPath); + + process.exit(code); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}); diff --git a/scripts/run_verifier.sh b/scripts/run_verifier.sh new file mode 100755 index 0000000..c9c844e --- /dev/null +++ b/scripts/run_verifier.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail +ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +OUT="$ROOT/runtime/evidence/verifier-status.json" +TMP="$OUT.tmp" +cd "$ROOT" +./scripts/mc_dod_evaluator.py > "$TMP" +python3 - "$TMP" "$OUT" <<'PY2' +import datetime +import json +import pathlib +import sys + +tmp_path = pathlib.Path(sys.argv[1]) +out_path = pathlib.Path(sys.argv[2]) +raw = tmp_path.read_text(encoding="utf-8").strip() +data = json.loads(raw) if raw else {} +if not isinstance(data, dict): + raise SystemExit("Verifier must output a JSON object") +data.setdefault("ok", bool(data.get("status") == "DONE")) +data.setdefault("status", data.get("status", "UNKNOWN")) +data.setdefault("checkedItems", []) +data.setdefault("failedChecks", []) +data.setdefault("evidence", []) +data.setdefault("nextRecommendedItem", "") +data["updatedAt"] = datetime.datetime.now(datetime.timezone.utc).isoformat() +out_path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") +print(json.dumps(data, ensure_ascii=False)) +tmp_path.unlink(missing_ok=True) +PY2 diff --git a/scripts/stall-auto-heal.ts b/scripts/stall-auto-heal.ts new file mode 100644 index 0000000..d55faf0 --- /dev/null +++ b/scripts/stall-auto-heal.ts @@ -0,0 +1,109 @@ +import { mkdir, readFile, stat, writeFile } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; +import { spawn } from "node:child_process"; + +type HealStatus = "healthy" | "stalled" | "healed" | "failed"; + +interface HealReport { + generatedAt: string; + status: HealStatus; + reason: string; + thresholds: { + evidenceMaxAgeMs: number; + lockMaxAgeMs: number; + }; + observed: { + evidenceAgeMs?: number; + lockAgeMs?: number; + }; + actions: string[]; +} + +const runtimeDir = resolve(process.cwd(), "runtime"); +const evidencePath = resolve(process.argv[2] ?? join(runtimeDir, "evidence", "latest.json")); +const lockPath = resolve(process.argv[3] ?? join(runtimeDir, "run.lock")); +const reportPath = resolve(process.argv[4] ?? join(runtimeDir, "recovery", "latest.json")); +const auditPath = resolve(process.argv[5] ?? join(dirname(reportPath), "audit.log")); + +const evidenceMaxAgeMs = Number(process.env.STALL_EVIDENCE_MAX_AGE_MS ?? 30 * 60 * 1000); +const lockMaxAgeMs = Number(process.env.STALL_LOCK_MAX_AGE_MS ?? 30 * 60 * 1000); +const owner = process.env.RUN_OWNER ?? "pandas-main"; + +async function mtimeAgeMs(path: string): Promise { + try { + const s = await stat(path); + return Date.now() - s.mtimeMs; + } catch { + return undefined; + } +} + +function runReleaseLock(): Promise { + return new Promise((resolvePromise) => { + const child = spawn("npm", ["run", "lock:release"], { + cwd: process.cwd(), + env: { ...process.env, RUN_OWNER: owner }, + stdio: "ignore", + }); + child.on("exit", (code) => resolvePromise(code === 0)); + }); +} + +async function appendRecoveryAudit(line: string): Promise { + await mkdir(dirname(auditPath), { recursive: true }); + let old = ""; + try { + old = await readFile(auditPath, "utf8"); + } catch { + old = ""; + } + await writeFile(auditPath, `${old}${line}\n`, "utf8"); +} + +async function main(): Promise { + const evidenceAgeMs = await mtimeAgeMs(evidencePath); + const lockAgeMs = await mtimeAgeMs(lockPath); + + const stalledByEvidence = evidenceAgeMs === undefined || evidenceAgeMs > evidenceMaxAgeMs; + const stalledByLock = lockAgeMs !== undefined && lockAgeMs > lockMaxAgeMs; + + const actions: string[] = []; + let status: HealStatus = "healthy"; + let reason = "within-threshold"; + + if (stalledByEvidence || stalledByLock) { + status = "stalled"; + reason = `${stalledByEvidence ? "evidence-stale" : ""}${stalledByEvidence && stalledByLock ? "+" : ""}${stalledByLock ? "lock-stale" : ""}`; + + const released = await runReleaseLock(); + actions.push(released ? "release-lock-ok" : "release-lock-failed"); + + if (released) { + status = "healed"; + actions.push("restart-chain-required"); + } else { + status = "failed"; + } + } + + const report: HealReport = { + generatedAt: new Date().toISOString(), + status, + reason, + thresholds: { evidenceMaxAgeMs, lockMaxAgeMs }, + observed: { evidenceAgeMs, lockAgeMs }, + actions, + }; + + await mkdir(dirname(reportPath), { recursive: true }); + await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8"); + await appendRecoveryAudit(`${report.generatedAt} | ${report.status} | ${report.reason} | actions=${actions.join(",") || "none"}`); + + console.log(`AUTO_HEAL_${report.status.toUpperCase()} reason=${report.reason} actions=${actions.join(",") || "none"}`); + process.exit(report.status === "failed" ? 1 : 0); +} + +main().catch((err) => { + console.error(err instanceof Error ? err.message : String(err)); + process.exit(1); +}); diff --git a/scripts/ui-smoke.sh b/scripts/ui-smoke.sh new file mode 100644 index 0000000..bfdd9a7 --- /dev/null +++ b/scripts/ui-smoke.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +PORT="${UI_SMOKE_PORT:-4516}" +WAIT_SECONDS="${UI_SMOKE_WAIT_SECONDS:-10}" +LOG_DIR="$ROOT/runtime" +LOG_FILE="$LOG_DIR/ui-smoke-${PORT}.log" + +mkdir -p "$LOG_DIR" +cd "$ROOT" + +UI_MODE=true UI_PORT="$PORT" npm run dev >"$LOG_FILE" 2>&1 & +PID=$! + +cleanup() { + kill "$PID" >/dev/null 2>&1 || true + wait "$PID" 2>/dev/null || true +} + +trap cleanup EXIT + +wait_for_ui() { + local deadline=$((SECONDS + WAIT_SECONDS)) + while true; do + if curl -fsS "http://127.0.0.1:${PORT}/" >/dev/null 2>&1; then + return 0 + fi + if (( SECONDS >= deadline )); then + echo "UI smoke failed: server did not become ready within ${WAIT_SECONDS}s." >&2 + cat "$LOG_FILE" >&2 || true + return 1 + fi + sleep 1 + done +} + +wait_for_ui +curl -fsS "http://127.0.0.1:${PORT}/" | grep -E "Mission Control|Office|Usage|Language:" >/dev/null +curl -fsS "http://127.0.0.1:${PORT}/docs?lang=en" | grep -E "Open document workbench|Mission Control|Docs" >/dev/null + +printf 'UI smoke passed on http://127.0.0.1:%s\n' "$PORT" diff --git a/scripts/validate-budget-compute.ts b/scripts/validate-budget-compute.ts new file mode 100644 index 0000000..b0930bb --- /dev/null +++ b/scripts/validate-budget-compute.ts @@ -0,0 +1,108 @@ +import assert from "node:assert/strict"; +import { computeBudgetSummary } from "../src/runtime/budget-governance"; +import type { + ProjectStoreSnapshot, + SessionStatusSnapshot, + SessionSummary, + TaskStoreSnapshot, +} from "../src/types"; + +function main(): void { + const sessions: SessionSummary[] = [ + { sessionKey: "s1", agentId: "main", state: "running" }, + { sessionKey: "s2", agentId: "main", state: "running" }, + { sessionKey: "s3", agentId: "worker", state: "idle" }, + ]; + + const statuses: SessionStatusSnapshot[] = [ + { + sessionKey: "s1", + tokensIn: 110, + tokensOut: 30, + cost: 5, + updatedAt: "2026-03-01T00:00:00.000Z", + }, + { + sessionKey: "s2", + tokensIn: 15, + tokensOut: 10, + cost: 1, + updatedAt: "2026-03-01T00:00:00.000Z", + }, + { + sessionKey: "s3", + tokensIn: 20, + tokensOut: 5, + cost: 0.5, + updatedAt: "2026-03-01T00:00:00.000Z", + }, + ]; + + const tasks: TaskStoreSnapshot = { + tasks: [ + { + projectId: "proj-1", + taskId: "task-over", + title: "Task Over", + status: "in_progress", + owner: "main", + definitionOfDone: [], + artifacts: [], + rollback: { strategy: "manual", steps: [] }, + sessionKeys: ["s1"], + budget: { tokensIn: 100, warnRatio: 0.8 }, + updatedAt: "2026-03-01T00:00:00.000Z", + }, + { + projectId: "proj-1", + taskId: "task-ok", + title: "Task Ok", + status: "todo", + owner: "main", + definitionOfDone: [], + artifacts: [], + rollback: { strategy: "manual", steps: [] }, + sessionKeys: ["s2"], + budget: { totalTokens: 100, warnRatio: 0.8 }, + updatedAt: "2026-03-01T00:00:00.000Z", + }, + ], + agentBudgets: [ + { + agentId: "main", + thresholds: { totalTokens: 200, warnRatio: 0.8 }, + }, + ], + updatedAt: "2026-03-01T00:00:00.000Z", + }; + + const projects: ProjectStoreSnapshot = { + projects: [ + { + projectId: "proj-1", + title: "Project 1", + status: "active", + owner: "main", + budget: { totalTokens: 120, warnRatio: 0.8 }, + updatedAt: "2026-03-01T00:00:00.000Z", + }, + ], + updatedAt: "2026-03-01T00:00:00.000Z", + }; + + const summary = computeBudgetSummary(sessions, statuses, tasks, projects); + assert.equal(summary.total, 4); + assert.equal(summary.ok, 1); + assert.equal(summary.warn, 1); + assert.equal(summary.over, 2); + + const byId = new Map(summary.evaluations.map((item) => [`${item.scope}:${item.scopeId}`, item.status])); + assert.equal(byId.get("task:task-over"), "over"); + assert.equal(byId.get("task:task-ok"), "ok"); + assert.equal(byId.get("project:proj-1"), "over"); + assert.equal(byId.get("agent:main"), "warn"); + + console.log("validate-budget-compute: ok"); +} + +main(); diff --git a/scripts/validate-task-store.ts b/scripts/validate-task-store.ts new file mode 100644 index 0000000..51a60c9 --- /dev/null +++ b/scripts/validate-task-store.ts @@ -0,0 +1,106 @@ +import assert from "node:assert/strict"; +import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +async function main(): Promise { + const previousCwd = process.cwd(); + const tempRoot = await mkdtemp(join(tmpdir(), "cc-task-store-")); + + try { + process.chdir(tempRoot); + await mkdir(join(tempRoot, "runtime"), { recursive: true }); + await writeFile( + join(tempRoot, "runtime", "tasks.json"), + JSON.stringify( + { + tasks: [], + agentBudgets: [], + updatedAt: "2026-03-01T00:00:00.000Z", + }, + null, + 2, + ), + "utf8", + ); + await writeFile( + join(tempRoot, "runtime", "projects.json"), + JSON.stringify( + { + projects: [ + { + projectId: "p1", + title: "Project One", + status: "active", + owner: "ops", + budget: {}, + updatedAt: "2026-03-01T00:00:00.000Z", + }, + ], + updatedAt: "2026-03-01T00:00:00.000Z", + }, + null, + 2, + ), + "utf8", + ); + + const taskStore = await import("../src/runtime/task-store"); + + const created = await taskStore.createTask({ + projectId: "p1", + taskId: "task-1", + title: "Ship endpoint", + owner: "main", + dueAt: "2026-03-03T10:00:00.000Z", + sessionKeys: ["agent:main:main"], + status: "todo", + }); + assert.equal(created.projectId, "p1"); + assert.equal(created.task.taskId, "task-1"); + assert.equal(created.task.status, "todo"); + assert.equal(created.task.dueAt, "2026-03-03T10:00:00.000Z"); + + const updated = await taskStore.updateTaskStatus({ + taskId: "task-1", + projectId: "p1", + status: "blocked", + }); + assert.equal(updated.task.status, "blocked"); + + const store = await taskStore.loadTaskStore(); + const listed = taskStore.listTasks(store); + assert.equal(listed.length, 1); + assert.equal(listed[0].taskId, "task-1"); + assert.equal(listed[0].status, "blocked"); + + await assert.rejects( + taskStore.createTask({ + projectId: "missing", + taskId: "task-2", + title: "Invalid", + }), + (error: unknown) => + error instanceof taskStore.TaskStoreValidationError && + error.statusCode === 404, + ); + + await assert.rejects( + taskStore.updateTaskStatus({ + taskId: "task-1", + projectId: "p1", + status: "bad-status", + }), + (error: unknown) => + error instanceof taskStore.TaskStoreValidationError && + error.statusCode === 400, + ); + + console.log("validate-task-store: ok"); + } finally { + process.chdir(previousCwd); + await rm(tempRoot, { recursive: true, force: true }); + } +} + +void main(); diff --git a/scripts/watchdog-orchestrator.ts b/scripts/watchdog-orchestrator.ts new file mode 100644 index 0000000..3e892f3 --- /dev/null +++ b/scripts/watchdog-orchestrator.ts @@ -0,0 +1,219 @@ +import { mkdir, readFile, rename, writeFile } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; +import { spawn } from "node:child_process"; + +interface RunLock { + runId: string; + owner: string; + startedAt: string; + updatedAt: string; + leaseUntil: string; + fencingToken: number; + pid?: number; +} + +interface RecoveryReport { + generatedAt: string; + status: "healthy" | "stalled" | "healed" | "failed"; + reason: string; + thresholds: { + evidenceMaxAgeMs: number; + lockMaxAgeMs: number; + }; + observed: { + evidenceAgeMs?: number; + lockAgeMs?: number; + }; + actions: string[]; +} + +interface DoDStatus { + status?: "DONE" | "NOT_DONE"; + passed?: boolean; +} + +interface WorkerHeartbeat { + pid?: number; +} + +function isExpired(lock: RunLock, nowMs = Date.now()): boolean { + const expiry = Date.parse(lock.leaseUntil); + if (Number.isNaN(expiry)) return true; + return expiry <= nowMs; +} + +function isPidAlive(pid: number): boolean { + if (!Number.isInteger(pid) || pid <= 0) return false; + try { + process.kill(pid, 0); + return true; + } catch (error) { + const code = (error as NodeJS.ErrnoException)?.code; + if (code === "EPERM") return true; + return false; + } +} + +async function readJson(path: string): Promise { + try { + const raw = await readFile(path, "utf8"); + return JSON.parse(raw) as T; + } catch { + return null; + } +} + +async function readLock(path: string): Promise { + return await readJson(path); +} + +async function runNodeScript( + scriptPath: string, + args: string[], + env: NodeJS.ProcessEnv, +): Promise<{ code: number | null; stdout: string; stderr: string }> { + return await new Promise((resolvePromise, rejectPromise) => { + const child = spawn(process.execPath, ["--import", "tsx", scriptPath, ...args], { + cwd: process.cwd(), + env, + stdio: ["ignore", "pipe", "pipe"], + }); + + let stdout = ""; + let stderr = ""; + child.stdout.on("data", (chunk) => { + stdout += String(chunk); + }); + child.stderr.on("data", (chunk) => { + stderr += String(chunk); + }); + child.on("error", rejectPromise); + child.on("close", (code) => resolvePromise({ code, stdout, stderr })); + }); +} + +async function readRecovery(path: string): Promise { + return await readJson(path); +} + +async function writeJsonAtomic(path: string, value: unknown): Promise { + await mkdir(dirname(path), { recursive: true }); + const tmp = `${path}.${process.pid}.${Date.now()}.tmp`; + await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8"); + await rename(tmp, path); +} + +async function inspectWorker(runtimeDir: string): Promise<{ active: boolean; detail: string }> { + const heartbeatPath = resolve(runtimeDir, "health", "worker-heartbeat.json"); + const hb = await readJson(heartbeatPath); + const active = hb?.pid !== undefined && isPidAlive(hb.pid); + if (active) { + return { active: true, detail: `worker-alive pid=${hb?.pid}` }; + } + return { active: false, detail: "worker-not-alive" }; +} + +async function main(): Promise { + const runtimeDir = resolve(process.cwd(), "runtime"); + const owner = process.env.RUN_OWNER ?? "pandas-main"; + const lockPath = resolve(process.argv[2] ?? join(runtimeDir, "run.lock")); + const evidencePath = resolve(process.argv[3] ?? join(runtimeDir, "evidence", "latest.json")); + const recoveryPath = resolve(process.argv[4] ?? join(runtimeDir, "recovery", "latest.json")); + const reportPath = resolve(process.argv[5] ?? join(dirname(recoveryPath), "watchdog-latest.json")); + const dodStatusPath = resolve(runtimeDir, "evidence", "dod-status.json"); + + const lockBefore = await readLock(lockPath); + const lockExpired = lockBefore ? isExpired(lockBefore) : true; + + const actions: string[] = []; + let lockAction = "none"; + + if (lockBefore && !lockExpired && lockBefore.owner !== owner) { + console.error( + `WATCHDOG_LOCK_CONFLICT expected=${owner} current=${lockBefore.owner} leaseUntil=${lockBefore.leaseUntil}`, + ); + process.exit(1); + } + + const runLockScript = resolve(process.cwd(), "scripts", "run-lock.ts"); + if (!lockBefore || lockExpired) { + lockAction = "acquire"; + const acquire = await runNodeScript(runLockScript, ["acquire", lockPath], { + ...process.env, + RUN_OWNER: owner, + }); + if (acquire.code !== 0) { + console.error(`WATCHDOG_LOCK_ACQUIRE_FAILED ${acquire.stderr.trim() || acquire.stdout.trim()}`); + process.exit(1); + } + actions.push("lock-acquire"); + } else { + lockAction = "renew"; + const renew = await runNodeScript(runLockScript, ["renew", lockPath], { + ...process.env, + RUN_OWNER: owner, + }); + if (renew.code !== 0) { + console.error(`WATCHDOG_LOCK_RENEW_FAILED ${renew.stderr.trim() || renew.stdout.trim()}`); + process.exit(1); + } + actions.push("lock-renew"); + } + + const healScript = resolve(process.cwd(), "scripts", "stall-auto-heal.ts"); + const heal = await runNodeScript(healScript, [evidencePath, lockPath, recoveryPath], { + ...process.env, + RUN_OWNER: owner, + }); + if (heal.code !== 0) { + console.error(`WATCHDOG_HEAL_FAILED ${heal.stderr.trim() || heal.stdout.trim()}`); + process.exit(1); + } + actions.push("heal-check"); + + const dod = await readJson(dodStatusPath); + const isNotDone = dod?.status === "NOT_DONE" || dod?.passed === false || dod == null; + if (isNotDone) { + const worker = await inspectWorker(runtimeDir); + actions.push(worker.detail); + // Single starter rule: watchdog never starts worker directly. + // Supervisor is the only component allowed to (re)start resident worker. + if (!worker.active) { + actions.push("restart-delegated-to-supervisor"); + } + } else { + actions.push("dod-done"); + } + + const lockAfter = await readLock(lockPath); + const recovery = await readRecovery(recoveryPath); + const outcome = + recovery?.status === "healed" ? "healed" : recovery?.status === "failed" ? "failed" : "healthy"; + + const report = { + generatedAt: new Date().toISOString(), + owner, + lockPath, + lockAction, + lock: lockAfter, + evidencePath, + recoveryPath, + recovery, + dodStatus: dod?.status ?? "UNKNOWN", + outcome, + actions, + }; + await writeJsonAtomic(reportPath, report); + + if (outcome === "failed") { + console.error(`WATCHDOG_FAILED report=${reportPath}`); + process.exit(1); + } + + console.log(`WATCHDOG_OK outcome=${outcome} action=${lockAction} report=${reportPath}`); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}); diff --git a/src/adapters/openclaw-readonly.ts b/src/adapters/openclaw-readonly.ts new file mode 100644 index 0000000..5121c06 --- /dev/null +++ b/src/adapters/openclaw-readonly.ts @@ -0,0 +1,88 @@ +import { + mapApprovalsGetToSummaries, + mapCronListToSummaries, + mapSessionsListToSummaries, +} from "../mappers/openclaw-mappers"; +import { parseSessionStatusText } from "../mappers/session-status-parser"; +import type { + ApprovalSummary, + CronJobSummary, + ReadModelSnapshot, + SessionStatusSnapshot, + SessionSummary, +} from "../types"; +import type { ToolClient } from "../clients/tool-client"; +import { computeBudgetSummary } from "../runtime/budget-governance"; +import { loadBudgetPolicy } from "../runtime/budget-policy"; +import { loadProjectStore } from "../runtime/project-store"; +import { computeProjectSummaries } from "../runtime/project-summary"; +import { loadTaskStore } from "../runtime/task-store"; +import { computeTasksSummary } from "../runtime/task-summary"; + +/** + * Official-first adapter (read path only). + * + * In readonly mode it uses a no-op client. + * In live mode it uses a client that is currently guarded and not enabled yet. + */ +export class OpenClawReadonlyAdapter { + constructor(private readonly client: ToolClient) {} + + async listSessions(): Promise { + const raw = await this.client.sessionsList(); + return mapSessionsListToSummaries(raw); + } + + async listSessionStatuses(sessionKeys: string[]): Promise { + const statuses = await Promise.all( + sessionKeys.map(async (sessionKey) => { + const raw = await this.client.sessionStatus(sessionKey); + return parseSessionStatusText(sessionKey, raw.rawText); + }), + ); + + return statuses; + } + + async listCronJobs(): Promise { + const raw = await this.client.cronList(); + return mapCronListToSummaries(raw); + } + + async listApprovals(): Promise { + const raw = await this.client.approvalsGet(); + return mapApprovalsGetToSummaries(raw); + } + + async snapshot(): Promise { + const sessions = await this.listSessions(); + const statuses = await this.listSessionStatuses(sessions.map((s) => s.sessionKey)); + const cronJobs = await this.listCronJobs(); + const approvals = await this.listApprovals(); + const [projects, tasks] = await Promise.all([loadProjectStore(), loadTaskStore()]); + const budgetPolicy = await loadBudgetPolicy(); + const tasksSummary = computeTasksSummary(tasks, projects.projects.length); + const projectSummaries = computeProjectSummaries(projects, tasks); + const budgetSummary = computeBudgetSummary(sessions, statuses, tasks, projects, budgetPolicy.policy); + + if (budgetPolicy.issues.length > 0) { + console.warn("[mission-control] budget policy issues", { + path: budgetPolicy.path, + issues: budgetPolicy.issues, + }); + } + + return { + sessions, + statuses, + cronJobs, + approvals, + projects, + projectSummaries, + tasks, + tasksSummary, + budgetSummary, + generatedAt: new Date().toISOString(), + }; + } +} diff --git a/src/clients/factory.ts b/src/clients/factory.ts new file mode 100644 index 0000000..325a644 --- /dev/null +++ b/src/clients/factory.ts @@ -0,0 +1,6 @@ +import { OpenClawLiveClient } from "./openclaw-live-client"; +import type { ToolClient } from "./tool-client"; + +export function createToolClient(): ToolClient { + return new OpenClawLiveClient(); +} diff --git a/src/clients/openclaw-live-client.ts b/src/clients/openclaw-live-client.ts new file mode 100644 index 0000000..b46a4c9 --- /dev/null +++ b/src/clients/openclaw-live-client.ts @@ -0,0 +1,620 @@ +import { execFile } from "node:child_process"; +import { readdir, readFile } from "node:fs/promises"; +import { join } from "node:path"; +import { promisify } from "node:util"; +import type { + ApprovalsActionResponse, + ApprovalsApproveRequest, + ApprovalsGetResponse, + ApprovalsRejectRequest, + CronListResponse, + SessionStatusResponse, + SessionsHistoryRequest, + SessionsHistoryResponse, + SessionsListResponse, +} from "../contracts/openclaw-tools"; +import { APPROVAL_ACTIONS_ENABLED } from "../config"; +import { loadCurrentAgentCatalog, resolveOpenClawHomePath } from "../runtime/current-agent-catalog"; +import type { ToolClient } from "./tool-client"; + +const execFileAsync = promisify(execFile); + +interface SessionCacheItem { + model?: string; + inputTokens?: number; + outputTokens?: number; + totalTokens?: number; + sessionFile?: string; +} + +const ACTIVE_SESSION_STATES = new Set([ + "running", + "active", + "busy", + "blocked", + "waiting_approval", + "working", + "in_progress", + "processing", + "thinking", + "executing", + "streaming", +]); +const INACTIVE_SESSION_STATES = new Set([ + "idle", + "inactive", + "error", + "failed", + "stopped", + "stopping", + "closed", + "done", + "completed", + "complete", + "paused", + "aborted", + "terminated", + "cancelled", + "canceled", +]); +const FALLBACK_ACTIVE_RECENCY_WINDOW_MS = 45 * 60 * 1000; + +/** + * Live read client using official OpenClaw CLI JSON outputs. + * Read-only by design: only list/status commands are used. + */ +export class OpenClawLiveClient implements ToolClient { + private sessionCache = new Map(); + private sessionFileCache = new Map(); + + async sessionsList(): Promise { + const openclawHome = resolveOpenClawHomePath(); + const configuredAgentKeys = await this.loadConfiguredAgentKeys(); + let data: { sessions?: Array> }; + try { + data = await runJson<{ sessions?: Array> }>([ + "sessions", + "--json", + ]); + } catch { + return this.loadSessionsFromStores(); + } + + const cliSessions: NonNullable = (data.sessions ?? []).map((item) => ({ + key: asString(item.key), + sessionKey: asString(item.key), + sessionId: asString(item.sessionId), + agentId: asString(item.agentId), + updatedAtMs: asNumber(item.updatedAt), + sessionFile: + asString(item.sessionFile) ?? + buildSessionFilePath(openclawHome, asString(item.agentId), asString(item.sessionId)), + model: asString(item.model), + inputTokens: asNumber(item.inputTokens), + outputTokens: asNumber(item.outputTokens), + totalTokens: asNumber(item.totalTokens), + state: readSessionState(item), + active: asBoolean(item.active) ?? false, + })).filter((item) => matchesConfiguredAgents(item.agentId ?? extractAgentIdFromSessionKey(item.sessionKey), configuredAgentKeys)); + let sessions: NonNullable = cliSessions; + try { + const storeSessions = (await this.loadSessionsFromStores()).sessions ?? []; + sessions = mergeSessionLists(cliSessions, storeSessions); + } catch { + sessions = cliSessions; + } + + this.sessionCache.clear(); + for (const s of sessions) { + if (!s.sessionKey) continue; + this.sessionCache.set(s.sessionKey, { + model: s.model, + inputTokens: s.inputTokens, + outputTokens: s.outputTokens, + totalTokens: s.totalTokens, + sessionFile: s.sessionFile, + }); + } + + return { sessions }; + } + + async sessionStatus(sessionKey: string): Promise { + const cached = this.sessionCache.get(sessionKey); + const rawText = cached + ? `Model: ${cached.model ?? "unknown"}\nTokens: ${cached.inputTokens ?? 0} in / ${cached.outputTokens ?? 0} out\nTotal: ${cached.totalTokens ?? 0}` + : ""; + + return { rawText }; + } + + async sessionsHistory(request: SessionsHistoryRequest): Promise { + const sessionKey = request.sessionKey.trim(); + if (!sessionKey) { + return { rawText: "" }; + } + + const limit = normalizeLimit(request.limit); + let sessionFile = this.sessionCache.get(sessionKey)?.sessionFile; + if (!sessionFile) { + sessionFile = await this.lookupSessionFile(sessionKey); + } + if (sessionFile) { + const fromFile = await readSessionHistoryFile(sessionFile, limit); + if (fromFile) return fromFile; + } + const attempts: string[][] = [ + ["sessions", "history", sessionKey, "--json", "--limit", String(limit)], + ["sessions", "history", sessionKey, "--limit", String(limit), "--json"], + ["sessions", "history", sessionKey, "--json"], + ]; + + for (const args of attempts) { + try { + const json = await runJson>(args); + return { + json, + rawText: JSON.stringify(json), + }; + } catch { + continue; + } + } + + try { + const rawText = await runHistoryText(sessionKey, limit); + return normalizeRawHistoryText(rawText, limit); + } catch { + return { rawText: "" }; + } + } + + async cronList(): Promise { + let data: { jobs?: Array> }; + try { + data = await runJson<{ jobs?: Array> }>( + ["cron", "list", "--json"], + { timeoutMs: 2_500 }, + ); + } catch { + return { jobs: [] }; + } + + const jobs = (data.jobs ?? []).map((job) => ({ + id: asString(job.id), + name: asString(job.name), + enabled: asBoolean(job.enabled), + state: asObject(job.state) + ? { + nextRunAtMs: asNumber(asObject(job.state)?.nextRunAtMs), + } + : undefined, + })); + + return { jobs }; + } + + async approvalsGet(): Promise { + try { + const json = await runJson>( + ["approvals", "get", "--json"], + { timeoutMs: 2_500 }, + ); + return { + json, + rawText: JSON.stringify(json), + }; + } catch { + try { + const rawText = await runText(["approvals", "get"], { timeoutMs: 1_500 }); + return { rawText }; + } catch { + return { rawText: "" }; + } + } + } + + async approvalsApprove(request: ApprovalsApproveRequest): Promise { + assertApprovalActionsEnabled("approve"); + const args = ["approvals", "approve", request.approvalId]; + if (request.reason) args.push("--reason", request.reason); + + const rawText = await runText(args); + return { + ok: true, + action: "approve", + approvalId: request.approvalId, + reason: request.reason, + rawText, + }; + } + + async approvalsReject(request: ApprovalsRejectRequest): Promise { + assertApprovalActionsEnabled("reject"); + const args = ["approvals", "reject", request.approvalId, "--reason", request.reason]; + const rawText = await runText(args); + return { + ok: true, + action: "reject", + approvalId: request.approvalId, + reason: request.reason, + rawText, + }; + } + + private async loadSessionsFromStores(): Promise { + const openclawHome = resolveOpenClawHomePath(); + const agentsPath = join(openclawHome, "agents"); + const configuredAgentKeys = await this.loadConfiguredAgentKeys(); + let agentDirs: string[] = []; + try { + const entries = await readdir(agentsPath, { withFileTypes: true }); + agentDirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name); + } catch { + return { sessions: [] }; + } + + if (configuredAgentKeys.size > 0) { + agentDirs = agentDirs.filter((agentId) => matchesConfiguredAgents(agentId, configuredAgentKeys)); + } + + const sessions: SessionsListResponse["sessions"] = []; + for (const agentId of agentDirs) { + const sessionsPath = join(agentsPath, agentId, "sessions", "sessions.json"); + try { + const parsed = JSON.parse(await readFile(sessionsPath, "utf8")) as unknown; + const records = extractSessionRecords(parsed); + for (const record of records) { + const sessionKey = asString(record.key) ?? asString(record.sessionKey); + if (!sessionKey) continue; + const updatedAtMs = readUpdatedAtMs(record); + sessions.push({ + key: sessionKey, + sessionKey, + sessionId: asString(record.sessionId), + agentId: asString(record.agentId) ?? agentId, + updatedAtMs: Number.isFinite(updatedAtMs) ? updatedAtMs : undefined, + sessionFile: + asString(record.sessionFile) ?? + buildSessionFilePath(openclawHome, asString(record.agentId) ?? agentId, asString(record.sessionId)), + model: asString(record.model), + inputTokens: asNumber(record.inputTokens), + outputTokens: asNumber(record.outputTokens), + totalTokens: asNumber(record.totalTokens), + state: readSessionState(record), + active: isSessionActive(record, updatedAtMs), + }); + } + } catch { + continue; + } + } + + sessions.sort((a, b) => (b.updatedAtMs ?? 0) - (a.updatedAtMs ?? 0)); + this.sessionCache.clear(); + for (const session of sessions) { + if (!session.sessionKey) continue; + this.sessionCache.set(session.sessionKey, { + model: session.model, + inputTokens: session.inputTokens, + outputTokens: session.outputTokens, + totalTokens: session.totalTokens, + sessionFile: session.sessionFile, + }); + if (session.sessionFile) { + this.sessionFileCache.set(session.sessionKey, session.sessionFile); + } + } + return { sessions }; + } + + private async lookupSessionFile(sessionKey: string): Promise { + const cached = this.sessionFileCache.get(sessionKey); + if (cached) return cached; + + const openclawHome = resolveOpenClawHomePath(); + const agentsPath = join(openclawHome, "agents"); + const configuredAgentKeys = await this.loadConfiguredAgentKeys(); + if (!matchesConfiguredAgents(extractAgentIdFromSessionKey(sessionKey), configuredAgentKeys)) { + return undefined; + } + let agentDirs: string[] = []; + try { + const entries = await readdir(agentsPath, { withFileTypes: true }); + agentDirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name); + } catch { + return undefined; + } + + if (configuredAgentKeys.size > 0) { + agentDirs = agentDirs.filter((agentId) => matchesConfiguredAgents(agentId, configuredAgentKeys)); + } + + for (const agentId of agentDirs) { + const sessionsPath = join(agentsPath, agentId, "sessions", "sessions.json"); + try { + const parsed = JSON.parse(await readFile(sessionsPath, "utf8")) as unknown; + for (const record of extractSessionRecords(parsed)) { + const key = asString(record.key) ?? asString(record.sessionKey); + const sessionFile = + asString(record.sessionFile) ?? + buildSessionFilePath(openclawHome, asString(record.agentId) ?? agentId, asString(record.sessionId)); + if (!key || !sessionFile) continue; + this.sessionFileCache.set(key, sessionFile); + } + } catch { + continue; + } + } + + return this.sessionFileCache.get(sessionKey); + } + + private async loadConfiguredAgentKeys(): Promise> { + const catalog = await loadCurrentAgentCatalog(); + return new Set(catalog.entries.map((entry) => normalizeAgentKey(entry.agentId))); + } +} + +async function runJson(args: string[], options?: { timeoutMs?: number; maxBuffer?: number }): Promise { + const stdout = await runText(args, options); + return JSON.parse(stdout) as T; +} + +async function runText( + args: string[], + options?: { timeoutMs?: number; maxBuffer?: number }, +): Promise { + const { stdout } = await execFileAsync("openclaw", args, { + timeout: options?.timeoutMs ?? 20_000, + maxBuffer: options?.maxBuffer ?? 2 * 1024 * 1024, + }); + return stdout; +} + +async function runHistoryText(sessionKey: string, limit: number): Promise { + try { + return await runText(["sessions", "history", sessionKey, "--limit", String(limit)]); + } catch (error) { + if (!isUnknownLimitOptionError(error)) throw error; + } + + const rawText = await runText(["sessions", "history", sessionKey]); + const trimmed = rawText.trim(); + if (trimmed === "") return rawText; + const lines = trimmed.split(/\r?\n/); + return lines.slice(-limit).join("\n"); +} + +function normalizeRawHistoryText(rawText: string, limit: number): SessionsHistoryResponse { + const trimmed = rawText.trim(); + if (trimmed === "") return { rawText }; + + const lines = trimmed.split(/\r?\n/).map((line) => line.trim()).filter((line) => line !== ""); + const jsonLike = lines.every((line) => line.startsWith("{") || line.startsWith("[")); + if (jsonLike) { + return normalizeSessionHistoryChunk(lines.join("\n"), limit); + } + + return { rawText }; +} + +function isUnknownLimitOptionError(error: unknown): boolean { + if (!(error instanceof Error)) return false; + return /unknown option '--limit'/.test(error.message); +} + +function asString(v: unknown): string | undefined { + return typeof v === "string" ? v : undefined; +} + +function asNumber(v: unknown): number | undefined { + return typeof v === "number" ? v : undefined; +} + +function asBoolean(v: unknown): boolean | undefined { + return typeof v === "boolean" ? v : undefined; +} + +function asObject(v: unknown): Record | undefined { + return v !== null && typeof v === "object" ? (v as Record) : undefined; +} + +function normalizeLimit(input: number | undefined): number { + if (typeof input !== "number" || !Number.isFinite(input)) return 12; + return Math.max(1, Math.min(200, Math.trunc(input))); +} + +async function readSessionHistoryFile( + sessionFile: string, + limit: number, +): Promise { + try { + const { stdout } = await execFileAsync("tail", ["-n", String(Math.max(limit * 8, 80)), sessionFile], { + timeout: 5_000, + maxBuffer: 512 * 1024, + }); + return normalizeSessionHistoryChunk(stdout, limit); + } catch { + try { + const raw = await readFile(sessionFile, "utf8"); + return normalizeSessionHistoryChunk(raw, limit); + } catch { + return undefined; + } + } +} + +function normalizeSessionHistoryChunk(raw: string, limit: number): SessionsHistoryResponse { + const lines = raw + .split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line !== ""); + if (lines.length === 0) return { rawText: "" }; + + const recentLines = lines.slice(-limit); + const history = recentLines.map((line) => { + try { + return JSON.parse(line) as Record; + } catch { + return line; + } + }); + return { + json: { history }, + rawText: recentLines.join("\n"), + }; +} + +function extractSessionRecords(parsed: unknown): Record[] { + if (Array.isArray(parsed)) return parsed.flatMap((item) => (asObject(item) ? [item] : [])); + + const root = asObject(parsed); + if (!root) return []; + + const nestedCollections = [root.sessions, root.items, root.records]; + for (const collection of nestedCollections) { + if (!Array.isArray(collection)) continue; + const records = collection.flatMap((item) => (asObject(item) ? [item] : [])); + if (records.length > 0) return records; + } + + return Object.entries(root).flatMap(([key, value]) => { + const record = asObject(value); + if (!record) return []; + return [{ key, ...record }]; + }); +} + +function mergeSessionLists( + primary: NonNullable = [], + secondary: NonNullable = [], +): NonNullable { + const merged = new Map[number]>(); + + const mergeItem = (item: NonNullable[number]): void => { + const sessionKey = item.sessionKey ?? item.key; + if (!sessionKey) return; + const current = merged.get(sessionKey); + if (!current) { + merged.set(sessionKey, item); + return; + } + merged.set(sessionKey, { + ...current, + ...item, + sessionKey, + key: item.key ?? current.key ?? sessionKey, + sessionFile: item.sessionFile ?? current.sessionFile, + sessionId: item.sessionId ?? current.sessionId, + agentId: item.agentId ?? current.agentId, + updatedAtMs: Math.max(current.updatedAtMs ?? 0, item.updatedAtMs ?? 0) || undefined, + active: item.active ?? current.active ?? false, + state: item.state ?? current.state, + model: item.model ?? current.model, + inputTokens: item.inputTokens ?? current.inputTokens, + outputTokens: item.outputTokens ?? current.outputTokens, + totalTokens: item.totalTokens ?? current.totalTokens, + }); + }; + + for (const item of secondary) mergeItem(item); + for (const item of primary) mergeItem(item); + + return [...merged.values()].sort((a, b) => (b.updatedAtMs ?? 0) - (a.updatedAtMs ?? 0)); +} + +function isSessionActive(item: Record, updatedAtMs: number): boolean { + const explicitActive = asBoolean(item.active) ?? asBoolean(item.isActive); + if (typeof explicitActive === "boolean") return explicitActive; + + const explicitState = readSessionState(item); + if (explicitState) { + if (ACTIVE_SESSION_STATES.has(explicitState)) return true; + if (INACTIVE_SESSION_STATES.has(explicitState)) return false; + } + + if (!Number.isFinite(updatedAtMs)) return false; + return Date.now() - updatedAtMs <= FALLBACK_ACTIVE_RECENCY_WINDOW_MS; +} + +function readSessionState(item: Record): string | undefined { + const direct = + asString(item.state) ?? + asString(item.status) ?? + asString(item.runState) ?? + asString(item.lifecycleState); + if (direct) return direct.trim().toLowerCase(); + + const acp = asObject(item.acp); + const acpState = asString(acp?.state); + return acpState ? acpState.trim().toLowerCase() : undefined; +} + +function readUpdatedAtMs(item: Record): number { + const candidates = [ + item.updatedAt, + item.lastActivityAt, + item.createdAt, + asObject(item.acp)?.lastActivityAt, + asObject(item.acp)?.updatedAt, + asObject(item.acp)?.createdAt, + ]; + + for (const candidate of candidates) { + if (typeof candidate === "number" && Number.isFinite(candidate)) return normalizeEpochMs(candidate); + if (typeof candidate === "string" && candidate.trim() !== "") { + const trimmed = candidate.trim(); + if (/^\d+(\.\d+)?$/.test(trimmed)) { + const numeric = Number(trimmed); + if (Number.isFinite(numeric)) return normalizeEpochMs(numeric); + } + const parsed = Date.parse(trimmed); + if (!Number.isNaN(parsed)) return parsed; + } + } + + return Number.NaN; +} + +function normalizeEpochMs(value: number): number { + const abs = Math.abs(value); + if (abs >= 1e14) return value / 1000; + if (abs > 0 && abs < 1e12) return value * 1000; + return value; +} + +function buildSessionFilePath( + openclawHome: string, + agentId: string | undefined, + sessionId: string | undefined, +): string | undefined { + if (!agentId || !sessionId) return undefined; + return join(openclawHome, "agents", agentId, "sessions", `${sessionId}.jsonl`); +} + +function extractAgentIdFromSessionKey(sessionKey: string | undefined): string | undefined { + const value = sessionKey?.trim(); + if (!value) return undefined; + const match = /^agent:([^:]+):/i.exec(value); + return match?.[1]; +} + +function matchesConfiguredAgents(agentId: string | undefined, configuredAgentKeys: ReadonlySet): boolean { + if (configuredAgentKeys.size === 0) return true; + const normalized = normalizeAgentKey(agentId); + return normalized.length > 0 && configuredAgentKeys.has(normalized); +} + +function normalizeAgentKey(agentId: string | undefined): string { + return agentId?.trim().toLowerCase() ?? ""; +} + +function assertApprovalActionsEnabled(action: "approve" | "reject"): void { + if (APPROVAL_ACTIONS_ENABLED) return; + throw new Error( + `approvals ${action} is disabled by safety gate (APPROVAL_ACTIONS_ENABLED=${String( + APPROVAL_ACTIONS_ENABLED, + )}).`, + ); +} diff --git a/src/clients/tool-client.ts b/src/clients/tool-client.ts new file mode 100644 index 0000000..80d9ebf --- /dev/null +++ b/src/clients/tool-client.ts @@ -0,0 +1,80 @@ +import type { + ApprovalsActionResponse, + ApprovalsApproveRequest, + ApprovalsGetResponse, + ApprovalsRejectRequest, + CronListResponse, + SessionStatusResponse, + SessionsHistoryRequest, + SessionsHistoryResponse, + SessionsListResponse, +} from "../contracts/openclaw-tools"; +import { APPROVAL_ACTIONS_ENABLED } from "../config"; + +export interface ToolClient { + sessionsList(): Promise; + sessionStatus(sessionKey: string): Promise; + sessionsHistory(request: SessionsHistoryRequest): Promise; + cronList(): Promise; + approvalsGet(): Promise; + approvalsApprove(request: ApprovalsApproveRequest): Promise; + approvalsReject(request: ApprovalsRejectRequest): Promise; +} + +export class ReadonlyToolClient implements ToolClient { + async sessionsList(): Promise { + return { sessions: [] }; + } + + async sessionStatus(_sessionKey: string): Promise { + return { rawText: "" }; + } + + async sessionsHistory(_request: SessionsHistoryRequest): Promise { + return { rawText: "" }; + } + + async cronList(): Promise { + return { jobs: [] }; + } + + async approvalsGet(): Promise { + return { rawText: "" }; + } + + async approvalsApprove(request: ApprovalsApproveRequest): Promise { + if (!APPROVAL_ACTIONS_ENABLED) { + throw new Error( + `approvalsApprove is disabled by safety gate (APPROVAL_ACTIONS_ENABLED=${String( + APPROVAL_ACTIONS_ENABLED, + )}).`, + ); + } + + return { + ok: false, + action: "approve", + approvalId: request.approvalId, + reason: request.reason, + rawText: "readonly client has no approve capability", + }; + } + + async approvalsReject(request: ApprovalsRejectRequest): Promise { + if (!APPROVAL_ACTIONS_ENABLED) { + throw new Error( + `approvalsReject is disabled by safety gate (APPROVAL_ACTIONS_ENABLED=${String( + APPROVAL_ACTIONS_ENABLED, + )}).`, + ); + } + + return { + ok: false, + action: "reject", + approvalId: request.approvalId, + reason: request.reason, + rawText: "readonly client has no reject capability", + }; + } +} diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..480d42a --- /dev/null +++ b/src/config.ts @@ -0,0 +1,37 @@ +export const GATEWAY_URL = readStringEnv(process.env.GATEWAY_URL, "ws://127.0.0.1:18789"); + +export const READONLY_MODE = process.env.READONLY_MODE !== "false"; +export const APPROVAL_ACTIONS_ENABLED = process.env.APPROVAL_ACTIONS_ENABLED === "true"; +export const APPROVAL_ACTIONS_DRY_RUN = process.env.APPROVAL_ACTIONS_DRY_RUN !== "false"; +export const IMPORT_MUTATION_ENABLED = process.env.IMPORT_MUTATION_ENABLED === "true"; +export const IMPORT_MUTATION_DRY_RUN = process.env.IMPORT_MUTATION_DRY_RUN === "true"; +export const LOCAL_TOKEN_AUTH_REQUIRED = process.env.LOCAL_TOKEN_AUTH_REQUIRED !== "false"; +export const LOCAL_API_TOKEN = (process.env.LOCAL_API_TOKEN ?? "").trim(); +export const LOCAL_TOKEN_HEADER = "x-local-token" as const; +export const TASK_HEARTBEAT_ENABLED = process.env.TASK_HEARTBEAT_ENABLED !== "false"; +export const TASK_HEARTBEAT_DRY_RUN = process.env.TASK_HEARTBEAT_DRY_RUN !== "false"; +export const TASK_HEARTBEAT_MAX_TASKS_PER_RUN = parsePositiveInt( + process.env.TASK_HEARTBEAT_MAX_TASKS_PER_RUN, + 3, +); + +export const POLLING_INTERVALS_MS = { + sessionsList: 5000, + sessionStatus: 2000, + cron: 10000, + approvals: 2000, + canvas: 5000, +} as const; + +export type PollingTarget = keyof typeof POLLING_INTERVALS_MS; + +function parsePositiveInt(input: string | undefined, fallback: number): number { + const parsed = Number.parseInt(input ?? "", 10); + if (!Number.isFinite(parsed) || parsed <= 0) return fallback; + return parsed; +} + +function readStringEnv(input: string | undefined, fallback: string): string { + const value = (input ?? "").trim(); + return value === "" ? fallback : value; +} diff --git a/src/contracts/openclaw-tools.ts b/src/contracts/openclaw-tools.ts new file mode 100644 index 0000000..eaf1f02 --- /dev/null +++ b/src/contracts/openclaw-tools.ts @@ -0,0 +1,101 @@ +export interface SessionsListRequest { + limit?: number; +} + +export interface SessionsListItem { + key?: string; + sessionKey?: string; + sessionId?: string; + label?: string; + agentId?: string; + sessionFile?: string; + updatedAt?: string; + updatedAtMs?: number; + active?: boolean; + state?: string; + model?: string; + inputTokens?: number; + outputTokens?: number; + totalTokens?: number; +} + +export interface SessionsListResponse { + sessions?: SessionsListItem[]; +} + +export interface SessionStatusRequest { + sessionKey: string; +} + +export interface SessionStatusResponse { + rawText: string; +} + +export interface SessionsHistoryRequest { + sessionKey: string; + limit?: number; +} + +export interface SessionsHistoryResponse { + json?: Record; + rawText: string; +} + +export interface CronListRequest { + includeDisabled?: boolean; +} + +export interface CronJobItem { + jobId?: string; + id?: string; + name?: string; + enabled?: boolean; + nextRunAt?: string; + state?: { + nextRunAtMs?: number; + }; +} + +export interface CronListResponse { + jobs?: CronJobItem[]; +} + +export interface ApprovalItem { + id?: string; + key?: string; + sessionKey?: string; + agentId?: string; + state?: string; + status?: string; + decision?: string; + command?: string; + prompt?: string; + reason?: string; + createdAt?: string; + requestedAt?: string; + updatedAt?: string; + expiresAt?: string; +} + +export interface ApprovalsGetResponse { + json?: Record; + rawText: string; +} + +export interface ApprovalsApproveRequest { + approvalId: string; + reason?: string; +} + +export interface ApprovalsRejectRequest { + approvalId: string; + reason: string; +} + +export interface ApprovalsActionResponse { + ok: boolean; + action: "approve" | "reject"; + approvalId: string; + reason?: string; + rawText: string; +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..b84832b --- /dev/null +++ b/src/index.ts @@ -0,0 +1,250 @@ +import { OpenClawReadonlyAdapter } from "./adapters/openclaw-readonly"; +import { createToolClient } from "./clients/factory"; +import { + APPROVAL_ACTIONS_DRY_RUN, + APPROVAL_ACTIONS_ENABLED, + GATEWAY_URL, + IMPORT_MUTATION_DRY_RUN, + IMPORT_MUTATION_ENABLED, + LOCAL_API_TOKEN, + LOCAL_TOKEN_AUTH_REQUIRED, + POLLING_INTERVALS_MS, + READONLY_MODE, + TASK_HEARTBEAT_DRY_RUN, + TASK_HEARTBEAT_ENABLED, + TASK_HEARTBEAT_MAX_TASKS_PER_RUN, +} from "./config"; +import { buildExportBundle, writeExportBundle } from "./runtime/export-bundle"; +import { validateExportFileDryRun } from "./runtime/import-dry-run"; +import { monitorIntervalMs, runMonitorOnce } from "./runtime/monitor"; +import { pruneStaleAcks } from "./runtime/notification-center"; +import { appendOperationAudit } from "./runtime/operation-audit"; +import { runTaskHeartbeat, runtimeTaskHeartbeatGate } from "./runtime/task-heartbeat"; +import { startUiServer } from "./ui/server"; + +const CONTINUOUS_MODE = process.env.MONITOR_CONTINUOUS === "true"; +const UI_MODE = process.env.UI_MODE === "true"; +const UI_PORT = Number.parseInt(process.env.UI_PORT ?? "4310", 10); +const COMMAND = normalizeCommand(process.env.APP_COMMAND ?? process.argv[2]); +const COMMAND_ARG = + process.env.COMMAND_ARG ?? + (process.env.APP_COMMAND ? process.argv[2] : process.argv[3]); + +async function start(): Promise { + const client = createToolClient(); + const adapter = new OpenClawReadonlyAdapter(client); + + console.log("[mission-control] startup", { + gateway: GATEWAY_URL, + readonlyMode: READONLY_MODE, + approvalActionsEnabled: APPROVAL_ACTIONS_ENABLED, + approvalActionsDryRun: APPROVAL_ACTIONS_DRY_RUN, + importMutationEnabled: IMPORT_MUTATION_ENABLED, + importMutationDryRun: IMPORT_MUTATION_DRY_RUN, + localTokenAuthRequired: LOCAL_TOKEN_AUTH_REQUIRED, + localTokenConfigured: LOCAL_API_TOKEN !== "", + taskHeartbeat: { + enabled: TASK_HEARTBEAT_ENABLED, + dryRun: TASK_HEARTBEAT_DRY_RUN, + maxTasksPerRun: TASK_HEARTBEAT_MAX_TASKS_PER_RUN, + }, + pollingIntervalsMs: POLLING_INTERVALS_MS, + networkCalls: !READONLY_MODE, + continuousMode: CONTINUOUS_MODE, + command: COMMAND ?? "monitor", + }); + + if (COMMAND) { + await runCommand(COMMAND, adapter, COMMAND_ARG); + return; + } + + await runMonitorOnce(adapter); + + if (CONTINUOUS_MODE) { + const intervalMs = monitorIntervalMs(); + setInterval(() => { + void runMonitorOnce(adapter); + }, intervalMs); + } + + if (UI_MODE) { + startUiServer(UI_PORT, client); + } +} + +void start(); + +async function runCommand( + command: "backup-export" | "import-validate" | "acks-prune" | "task-heartbeat", + adapter: OpenClawReadonlyAdapter, + arg?: string, +): Promise { + assertCommandOperationGate(command); + + if (command === "backup-export") { + try { + const snapshot = await adapter.snapshot(); + const bundle = await buildExportBundle(snapshot, "command", "cmd-backup-export"); + const written = await writeExportBundle(bundle, "backup"); + await appendOperationAudit({ + action: "backup_export", + source: "command", + ok: true, + requestId: "cmd-backup-export", + detail: `wrote ${written.fileName}`, + metadata: { + path: written.path, + sizeBytes: written.sizeBytes, + }, + }); + console.log("[mission-control] backup export", { + exportedAt: bundle.exportedAt, + snapshotGeneratedAt: bundle.snapshotGeneratedAt, + fileName: written.fileName, + path: written.path, + sizeBytes: written.sizeBytes, + }); + } catch (error) { + await appendOperationAudit({ + action: "backup_export", + source: "command", + ok: false, + requestId: "cmd-backup-export", + detail: error instanceof Error ? error.message : "backup export failed", + }); + throw error; + } + return; + } + + if (command === "acks-prune") { + const dryRun = resolveAcksPruneDryRun(arg); + try { + const result = await pruneStaleAcks({ dryRun }); + await appendOperationAudit({ + action: "ack_prune", + source: "command", + ok: true, + requestId: "cmd-acks-prune", + detail: `removed ${result.removed} stale ack(s)`, + metadata: { + dryRun, + before: result.before, + removed: result.removed, + after: result.after, + }, + }); + console.log("[mission-control] acks prune", result); + } catch (error) { + await appendOperationAudit({ + action: "ack_prune", + source: "command", + ok: false, + requestId: "cmd-acks-prune", + detail: error instanceof Error ? error.message : "acks prune failed", + }); + throw error; + } + return; + } + + if (command === "task-heartbeat") { + const gate = runtimeTaskHeartbeatGate(); + const runDryRun = resolveTaskHeartbeatDryRun(arg, gate.dryRun); + const result = await runTaskHeartbeat({ + gate: { + ...gate, + dryRun: runDryRun, + }, + }); + await appendOperationAudit({ + action: "task_heartbeat", + source: "command", + ok: result.ok, + requestId: "cmd-task-heartbeat", + detail: `${result.mode} ${result.message}`, + metadata: { + checked: result.checked, + eligible: result.eligible, + selected: result.selected, + executed: result.executed, + dryRun: result.gate.dryRun, + }, + }); + console.log("[mission-control] task heartbeat", result); + if (!result.ok) { + process.exitCode = 1; + } + return; + } + + if (!arg) { + throw new Error( + "import-validate requires a file path argument. Example: APP_COMMAND=import-validate COMMAND_ARG= npm run dev", + ); + } + + const validation = await validateExportFileDryRun(arg); + await appendOperationAudit({ + action: "import_dry_run", + source: "command", + ok: validation.valid, + requestId: "cmd-import-validate", + detail: `validated ${validation.source}`, + metadata: { + valid: validation.valid, + issues: validation.issues.length, + warnings: validation.warnings.length, + }, + }); + console.log("[mission-control] import dry-run", validation); + if (!validation.valid) { + process.exitCode = 1; + } +} + +function assertCommandOperationGate( + command: "backup-export" | "import-validate" | "acks-prune" | "task-heartbeat", +): void { + if (!LOCAL_TOKEN_AUTH_REQUIRED) return; + if (LOCAL_API_TOKEN !== "") return; + throw new Error( + `${command} is blocked by local token gate. Set LOCAL_API_TOKEN to explicitly allow protected command execution.`, + ); +} + +function normalizeCommand( + input: string | undefined, +): "backup-export" | "import-validate" | "acks-prune" | "task-heartbeat" | undefined { + if (!input) return undefined; + const trimmed = input.trim().toLowerCase(); + if (trimmed === "") return undefined; + if (trimmed === "backup-export") return "backup-export"; + if (trimmed === "import-validate") return "import-validate"; + if (trimmed === "acks-prune") return "acks-prune"; + if (trimmed === "task-heartbeat") return "task-heartbeat"; + throw new Error( + `Unknown command '${input}'. Supported: backup-export, import-validate, acks-prune, task-heartbeat.`, + ); +} + +function resolveAcksPruneDryRun(arg: string | undefined): boolean { + const envDryRun = process.env.ACK_PRUNE_DRY_RUN === "true"; + if (!arg) return envDryRun; + + const normalized = arg.trim().toLowerCase(); + if (normalized === "" || normalized === "--live" || normalized === "live") return false; + if (normalized === "--dry-run" || normalized === "dry-run") return true; + throw new Error("acks-prune optional arg must be one of: --dry-run, dry-run, --live, live."); +} + +function resolveTaskHeartbeatDryRun(arg: string | undefined, fallback: boolean): boolean { + if (!arg) return fallback; + + const normalized = arg.trim().toLowerCase(); + if (normalized === "") return fallback; + if (normalized === "--dry-run" || normalized === "dry-run") return true; + if (normalized === "--live" || normalized === "live") return false; + throw new Error("task-heartbeat optional arg must be one of: --dry-run, dry-run, --live, live."); +} diff --git a/src/mappers/openclaw-mappers.ts b/src/mappers/openclaw-mappers.ts new file mode 100644 index 0000000..044d9fa --- /dev/null +++ b/src/mappers/openclaw-mappers.ts @@ -0,0 +1,314 @@ +import type { + ApprovalsGetResponse, + CronListResponse, + SessionsListResponse, +} from "../contracts/openclaw-tools"; +import type { + ApprovalState, + ApprovalSummary, + AgentRunState, + CronJobSummary, + SessionSummary, +} from "../types"; + +const RUNNING_SESSION_STATES = new Set([ + "running", + "active", + "busy", + "working", + "in_progress", + "processing", + "thinking", + "executing", + "streaming", +]); +const BLOCKED_SESSION_STATES = new Set([ + "blocked", + "needs_support", + "stuck", +]); +const WAITING_APPROVAL_SESSION_STATES = new Set([ + "waiting_approval", + "pending_approval", + "approval_pending", + "awaiting_approval", + "needs_approval", +]); +const ERROR_SESSION_STATES = new Set([ + "error", + "failed", + "failure", + "crashed", + "panic", +]); + +function toState(active: boolean | undefined, explicitState?: string): AgentRunState { + const normalized = explicitState?.trim().toLowerCase(); + if (normalized) { + if (WAITING_APPROVAL_SESSION_STATES.has(normalized)) return "waiting_approval"; + if (BLOCKED_SESSION_STATES.has(normalized)) return "blocked"; + if (ERROR_SESSION_STATES.has(normalized)) return "error"; + if (RUNNING_SESSION_STATES.has(normalized)) return "running"; + if (normalized === "idle" || normalized === "inactive" || normalized === "done" || normalized === "completed" || normalized === "stopped" || normalized === "closed") { + return "idle"; + } + } + if (active === true) return "running"; + return "idle"; +} + +function toIso(updatedAtMs?: number, updatedAt?: string): string | undefined { + if (updatedAt) return updatedAt; + if (typeof updatedAtMs === "number") return new Date(updatedAtMs).toISOString(); + return undefined; +} + +export function mapSessionsListToSummaries(input: SessionsListResponse): SessionSummary[] { + const mapped = (input.sessions ?? []).map((item) => ({ + sessionKey: item.sessionKey ?? item.key, + label: item.label, + agentId: item.agentId, + lastMessageAt: toIso(item.updatedAtMs, item.updatedAt), + state: toState(item.active, item.state), + })); + + return mapped + .filter((item) => Boolean(item.sessionKey)) + .map((item) => ({ + sessionKey: item.sessionKey as string, + label: item.label, + agentId: item.agentId, + lastMessageAt: item.lastMessageAt, + state: item.state, + })); +} + +export function mapCronListToSummaries(input: CronListResponse): CronJobSummary[] { + const mapped = (input.jobs ?? []).map((job) => ({ + jobId: job.jobId ?? job.id, + name: job.name, + enabled: job.enabled ?? true, + nextRunAt: + job.nextRunAt ?? + (typeof job.state?.nextRunAtMs === "number" + ? new Date(job.state.nextRunAtMs).toISOString() + : undefined), + })); + + return mapped + .filter((job) => Boolean(job.jobId)) + .map((job) => ({ + jobId: job.jobId as string, + name: job.name, + enabled: job.enabled, + nextRunAt: job.nextRunAt, + })); +} + +export function mapApprovalsGetToSummaries(input: ApprovalsGetResponse): ApprovalSummary[] { + if (input.json) { + return mapApprovalsJsonToSummaries(input.json); + } + + return mapApprovalsTextToSummaries(input.rawText); +} + +function mapApprovalsJsonToSummaries(json: Record): ApprovalSummary[] { + const approvals: ApprovalSummary[] = []; + + approvals.push(...mapApprovalArray(asArray(json.pending), "pending", "pending")); + approvals.push(...mapApprovalArray(asArray(json.requests), "pending", "requests")); + approvals.push(...mapApprovalArray(asArray(json.approvals), "unknown", "approvals")); + + const file = asObject(json.file); + if (!file) return dedupeById(approvals); + + approvals.push(...mapApprovalArray(asArray(file.pending), "pending", "file-pending")); + approvals.push(...mapApprovalArray(asArray(file.requests), "pending", "file-requests")); + approvals.push(...mapApprovalArray(asArray(file.approvals), "unknown", "file-approvals")); + approvals.push(...mapApprovalArray(asArray(file.allowlist), "approved", "file-allowlist")); + + const defaults = asObject(file.defaults); + if (defaults) { + let idx = 0; + for (const [key, value] of Object.entries(defaults)) { + idx += 1; + const status = toApprovalState(asString(value), asString(value), "unknown"); + approvals.push({ + approvalId: `default:${key}:${idx}`, + status, + decision: asString(value), + reason: "defaults rule", + }); + } + } + + const agents = asObject(file.agents); + if (agents) { + for (const [agentId, config] of Object.entries(agents)) { + const cfg = asObject(config); + if (!cfg) continue; + + approvals.push( + ...mapApprovalArray(asArray(cfg.pending), "pending", `agent:${agentId}:pending`, agentId), + ); + approvals.push( + ...mapApprovalArray(asArray(cfg.requests), "pending", `agent:${agentId}:requests`, agentId), + ); + approvals.push( + ...mapApprovalArray(asArray(cfg.approvals), "unknown", `agent:${agentId}:approvals`, agentId), + ); + approvals.push( + ...mapApprovalArray( + asArray(cfg.allowlist), + "approved", + `agent:${agentId}:allowlist`, + agentId, + ), + ); + } + } + + return dedupeById(approvals); +} + +function mapApprovalsTextToSummaries(rawText: string): ApprovalSummary[] { + const fields = extractFieldValueTable(rawText); + const pendingCount = toInt(fields.pending) ?? 0; + const allowlistCount = toInt(fields.allowlist) ?? 0; + const approvals: ApprovalSummary[] = []; + + for (let i = 0; i < pendingCount; i += 1) { + approvals.push({ + approvalId: `pending:${i + 1}`, + status: "pending", + reason: "from approvals text snapshot", + }); + } + + if (allowlistCount > 0) { + approvals.push({ + approvalId: "allowlist:summary", + status: "approved", + decision: "allowlist", + reason: `allowlist entries: ${allowlistCount}`, + }); + } + + return approvals; +} + +function mapApprovalArray( + array: unknown[] | undefined, + fallbackState: ApprovalState, + prefix: string, + agentIdFromContext?: string, +): ApprovalSummary[] { + if (!array || array.length === 0) return []; + + return array + .map((item, idx) => mapApprovalRecord(item, fallbackState, `${prefix}:${idx + 1}`, agentIdFromContext)) + .filter((item): item is ApprovalSummary => Boolean(item)); +} + +function mapApprovalRecord( + record: unknown, + fallbackState: ApprovalState, + fallbackId: string, + agentIdFromContext?: string, +): ApprovalSummary | null { + const obj = asObject(record); + if (!obj) { + if (typeof record === "string") { + return { + approvalId: fallbackId, + status: fallbackState, + decision: record, + }; + } + + return null; + } + + const statusRaw = asString(obj.status) ?? asString(obj.state); + const decisionRaw = asString(obj.decision); + const agentId = asString(obj.agentId) ?? agentIdFromContext; + + return { + approvalId: + asString(obj.id) ?? + asString(obj.key) ?? + asString(obj.approvalId) ?? + asString(obj.requestId) ?? + fallbackId, + sessionKey: asString(obj.sessionKey), + agentId, + status: toApprovalState(statusRaw, decisionRaw, fallbackState), + decision: decisionRaw ?? statusRaw, + command: asString(obj.command) ?? asString(obj.cmd) ?? asString(obj.pattern) ?? asString(obj.prompt), + reason: asString(obj.reason) ?? asString(obj.summary), + requestedAt: asString(obj.requestedAt) ?? asString(obj.createdAt), + updatedAt: asString(obj.updatedAt), + }; +} + +function dedupeById(items: ApprovalSummary[]): ApprovalSummary[] { + const seen = new Set(); + const out: ApprovalSummary[] = []; + + for (const item of items) { + if (seen.has(item.approvalId)) continue; + seen.add(item.approvalId); + out.push(item); + } + + return out; +} + +function extractFieldValueTable(text: string): Record { + const result: Record = {}; + const lines = text.split(/\r?\n/); + + for (const line of lines) { + const match = line.match(/^\s*│\s*([^│]+?)\s*│\s*([^│]+?)\s*│\s*$/); + if (!match) continue; + const field = match[1].trim().toLowerCase(); + const value = match[2].trim(); + if (!field || field === "field" || field === "value") continue; + result[field] = value; + } + + return result; +} + +function toApprovalState( + statusRaw: string | undefined, + decisionRaw: string | undefined, + fallback: ApprovalState, +): ApprovalState { + const value = `${statusRaw ?? ""} ${decisionRaw ?? ""}`.toLowerCase(); + if (value.includes("pending") || value.includes("wait")) return "pending"; + if (value.includes("approved") || value.includes("allow") || value.includes("granted")) return "approved"; + if (value.includes("denied") || value.includes("reject")) return "denied"; + return fallback; +} + +function toInt(v: string | undefined): number | undefined { + if (!v) return undefined; + const match = v.match(/\d+/); + if (!match) return undefined; + const parsed = Number.parseInt(match[0], 10); + return Number.isNaN(parsed) ? undefined : parsed; +} + +function asString(v: unknown): string | undefined { + return typeof v === "string" ? v : undefined; +} + +function asArray(v: unknown): unknown[] | undefined { + return Array.isArray(v) ? v : undefined; +} + +function asObject(v: unknown): Record | undefined { + return v !== null && typeof v === "object" && !Array.isArray(v) ? (v as Record) : undefined; +} diff --git a/src/mappers/session-status-parser.ts b/src/mappers/session-status-parser.ts new file mode 100644 index 0000000..33cf4cf --- /dev/null +++ b/src/mappers/session-status-parser.ts @@ -0,0 +1,37 @@ +import type { SessionStatusSnapshot } from "../types"; + +export function parseSessionStatusText(sessionKey: string, raw: string): SessionStatusSnapshot { + const model = matchOne(raw, /Model:\s*([^·\n]+)/)?.trim(); + const tokensIn = toInt(matchOne(raw, /Tokens:\s*(\d+)\s*in/i)); + const tokensOut = toInt(matchOne(raw, /in\s*\/\s*(\d+)\s*out/i)); + const cost = toFloat( + matchOne(raw, /Cost:\s*\$?\s*([0-9]+(?:\.[0-9]+)?)/i) ?? + matchOne(raw, /Total\s+Cost:\s*\$?\s*([0-9]+(?:\.[0-9]+)?)/i), + ); + + return { + sessionKey, + model, + tokensIn, + tokensOut, + cost, + updatedAt: new Date().toISOString(), + }; +} + +function matchOne(text: string, re: RegExp): string | undefined { + const m = text.match(re); + return m?.[1]; +} + +function toInt(v: string | undefined): number | undefined { + if (!v) return undefined; + const n = Number.parseInt(v, 10); + return Number.isNaN(n) ? undefined : n; +} + +function toFloat(v: string | undefined): number | undefined { + if (!v) return undefined; + const n = Number.parseFloat(v); + return Number.isNaN(n) ? undefined : n; +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..76de058 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,354 @@ +export type AgentRunState = "idle" | "running" | "blocked" | "waiting_approval" | "error"; + +export interface SessionSummary { + sessionKey: string; + label?: string; + agentId?: string; + state: AgentRunState; + lastMessageAt?: string; +} + +export interface SessionStatusSnapshot { + sessionKey: string; + model?: string; + tokensIn?: number; + tokensOut?: number; + cost?: number; + updatedAt: string; +} + +export interface CronJobSummary { + jobId: string; + name?: string; + enabled: boolean; + nextRunAt?: string; +} + +export type ApprovalState = "pending" | "approved" | "denied" | "unknown"; + +export interface ApprovalSummary { + approvalId: string; + sessionKey?: string; + agentId?: string; + status: ApprovalState; + decision?: string; + command?: string; + reason?: string; + requestedAt?: string; + updatedAt?: string; +} + +export type TaskState = "todo" | "in_progress" | "blocked" | "done"; +export type ProjectState = "planned" | "active" | "blocked" | "done"; + +export type TaskArtifactType = "code" | "doc" | "link" | "other"; + +export interface TaskArtifact { + artifactId: string; + type: TaskArtifactType; + label: string; + location: string; +} + +export interface RollbackPlan { + strategy: string; + steps: string[]; + verification?: string; +} + +export interface BudgetThresholds { + tokensIn?: number; + tokensOut?: number; + totalTokens?: number; + cost?: number; + warnRatio?: number; +} + +export interface ProjectTask { + projectId: string; + taskId: string; + title: string; + status: TaskState; + owner: string; + dueAt?: string; + definitionOfDone: string[]; + artifacts: TaskArtifact[]; + rollback: RollbackPlan; + sessionKeys: string[]; + budget: BudgetThresholds; + updatedAt: string; +} + +export interface ProjectRecord { + projectId: string; + title: string; + status: ProjectState; + owner: string; + budget: BudgetThresholds; + updatedAt: string; +} + +export interface ProjectStoreSnapshot { + projects: ProjectRecord[]; + updatedAt: string; +} + +export interface AgentBudgetPlan { + agentId: string; + label?: string; + thresholds: BudgetThresholds; +} + +export interface TaskStoreSnapshot { + tasks: ProjectTask[]; + agentBudgets: AgentBudgetPlan[]; + updatedAt: string; +} + +export interface TasksSummary { + projects: number; + tasks: number; + todo: number; + inProgress: number; + blocked: number; + done: number; + owners: number; + artifacts: number; +} + +export interface ProjectSummary { + projectId: string; + title: string; + status: ProjectState; + owner: string; + totalTasks: number; + todo: number; + inProgress: number; + blocked: number; + done: number; + due: number; + updatedAt: string; +} + +export type BudgetStatus = "ok" | "warn" | "over"; +export type BudgetScope = "agent" | "project" | "task"; + +export interface BudgetUsageSnapshot { + tokensIn: number; + tokensOut: number; + totalTokens: number; + cost: number; +} + +export interface BudgetMetricEvaluation { + metric: "tokensIn" | "tokensOut" | "totalTokens" | "cost"; + used: number; + limit: number; + warnAt: number; + status: BudgetStatus; +} + +export interface BudgetEvaluation { + scope: BudgetScope; + scopeId: string; + label: string; + thresholds: BudgetThresholds; + usage: BudgetUsageSnapshot; + metrics: BudgetMetricEvaluation[]; + status: BudgetStatus; +} + +export interface BudgetSummary { + total: number; + ok: number; + warn: number; + over: number; + evaluations: BudgetEvaluation[]; +} + +export interface BudgetPolicyConfig { + defaults: BudgetThresholds; + agent: Record; + project: Record; + task: Record; +} + +export interface ReadModelSnapshot { + sessions: SessionSummary[]; + statuses: SessionStatusSnapshot[]; + cronJobs: CronJobSummary[]; + approvals: ApprovalSummary[]; + projects: ProjectStoreSnapshot; + projectSummaries: ProjectSummary[]; + tasks: TaskStoreSnapshot; + tasksSummary: TasksSummary; + budgetSummary: BudgetSummary; + generatedAt: string; +} + +export interface TaskListItem { + projectId: string; + projectTitle: string; + taskId: string; + title: string; + status: TaskState; + owner: string; + dueAt?: string; + sessionKeys: string[]; + updatedAt: string; +} + +export interface CommanderExceptionsSummary { + generatedAt: string; + blocked: SessionSummary[]; + errors: SessionSummary[]; + pendingApprovals: ApprovalSummary[]; + overBudget: BudgetEvaluation[]; + tasksDue: TaskListItem[]; + counts: { + blocked: number; + errors: number; + pendingApprovals: number; + overBudget: number; + tasksDue: number; + }; +} + +export type AlertLevel = "info" | "warn" | "action-required"; + +export interface ExceptionFeedItem { + level: AlertLevel; + code: + | "NO_SESSIONS" + | "SESSION_BLOCKED" + | "SESSION_ERROR" + | "PENDING_APPROVAL" + | "OVER_BUDGET" + | "TASK_DUE"; + source: "system" | "session" | "approval" | "budget" | "task"; + sourceId: string; + message: string; + route: "timeline" | "operator-watch" | "action-queue"; + occurredAt?: string; +} + +export interface CommanderExceptionsFeed { + generatedAt: string; + items: ExceptionFeedItem[]; + counts: { + info: number; + warn: number; + actionRequired: number; + }; +} + +export interface NotificationAck { + itemId: string; + ackedAt: string; + note?: string; + expiresAt?: string; +} + +export interface AcksStoreSnapshot { + acks: NotificationAck[]; + updatedAt: string; +} + +export interface ActionQueueItem extends ExceptionFeedItem { + itemId: string; + acknowledged: boolean; + ackedAt?: string; + note?: string; + ackExpiresAt?: string; + links: ActionQueueLink[]; +} + +export interface ActionQueueLink { + type: "session" | "task" | "project"; + id: string; + href: string; + label: string; +} + +export interface NotificationCenterSnapshot { + generatedAt: string; + queue: ActionQueueItem[]; + counts: { + total: number; + acked: number; + unacked: number; + }; +} + +export type ChecklistStatus = "pass" | "warn" | "fail"; +export type ReadinessCategory = "observability" | "governance" | "collaboration" | "security"; + +export interface ReadinessCategoryScore { + category: ReadinessCategory; + score: number; + passed: number; + warn: number; + failed: number; + total: number; +} + +export interface ReadinessScoreSnapshot { + overall: number; + categories: ReadinessCategoryScore[]; +} + +export interface DoneChecklistItem { + id: string; + category: ReadinessCategory; + title: string; + docRef: string; + status: ChecklistStatus; + detail: string; +} + +export interface DoneChecklistSnapshot { + generatedAt: string; + basedOn: string[]; + items: DoneChecklistItem[]; + counts: { + pass: number; + warn: number; + fail: number; + }; + readiness: ReadinessScoreSnapshot; +} + +export interface ExportBundle { + ok: true; + schemaVersion: "phase-9"; + source: "api" | "command"; + requestId?: string; + exportedAt: string; + snapshotGeneratedAt: string; + sessions: SessionSummary[]; + projects: ProjectStoreSnapshot; + tasks: TaskStoreSnapshot; + budgets: { + policy: BudgetPolicyConfig; + issues: string[]; + summary: BudgetSummary; + }; + exceptions: CommanderExceptionsSummary; + exceptionsFeed: CommanderExceptionsFeed; +} + +export interface ImportDryRunSummary { + sessions: number; + projects: number; + tasks: number; + exceptions: number; +} + +export interface ImportDryRunResult { + validatedAt: string; + source: string; + valid: boolean; + issues: string[]; + warnings: string[]; + summary: ImportDryRunSummary; +} diff --git a/src/ui/server.ts b/src/ui/server.ts new file mode 100644 index 0000000..c6b670a --- /dev/null +++ b/src/ui/server.ts @@ -0,0 +1,13194 @@ +import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http"; +import { randomUUID } from "node:crypto"; +import { readdir, readFile, stat, writeFile } from "node:fs/promises"; +import { homedir } from "node:os"; +import { basename, dirname, extname, join, relative, resolve } from "node:path"; +import { + APPROVAL_ACTIONS_DRY_RUN, + APPROVAL_ACTIONS_ENABLED, + IMPORT_MUTATION_DRY_RUN, + IMPORT_MUTATION_ENABLED, + LOCAL_API_TOKEN, + LOCAL_TOKEN_AUTH_REQUIRED, + LOCAL_TOKEN_HEADER, + POLLING_INTERVALS_MS, + READONLY_MODE, +} from "../config"; +import type { ToolClient } from "../clients/tool-client"; +import { mapSessionsListToSummaries } from "../mappers/openclaw-mappers"; +import { buildApiDocs } from "../runtime/api-docs"; +import { computeBudgetSummary } from "../runtime/budget-governance"; +import { BUDGET_POLICY_PATH, loadBudgetPolicy } from "../runtime/budget-policy"; +import { commanderExceptions, commanderExceptionsFeed } from "../runtime/commander"; +import { buildCronOverview } from "../runtime/cron-overview"; +import { buildDoneChecklist } from "../runtime/done-checklist"; +import { + filterAuditTimeline, + loadAuditTimeline, + type AuditSeverity, + type AuditTimelineSnapshot, +} from "../runtime/audit-timeline"; +import { loadLatestDigest, renderLatestDigestPage } from "../runtime/digest-renderer"; +import { buildExportBundle, writeExportBundle } from "../runtime/export-bundle"; +import { buildHealthzPayload } from "../runtime/healthz"; +import { applyImportMutation, readImportMutationGuardState } from "../runtime/import-live"; +import { validateExportBundleDryRun, validateExportFileDryRun } from "../runtime/import-dry-run"; +import { + evaluateLocalTokenGate, + normalizeToken, + readAuthorizationBearer, +} from "../runtime/local-token-auth"; +import { appendOperationAudit } from "../runtime/operation-audit"; +import { ApprovalActionService } from "../runtime/approval-action-service"; +import { buildActionQueueLinks } from "../runtime/action-queue-links"; +import { loadReplayIndex, writeExportSnapshot } from "../runtime/replay-index"; +import { buildNotificationPreview, loadNotificationPolicy } from "../runtime/notification-policy"; +import { + NotificationCenterValidationError, + acknowledgeActionQueueItem, + buildNotificationCenter, + loadAcksStore, + previewStaleAcksPrune, +} from "../runtime/notification-center"; +import { buildPixelState } from "../runtime/pixel-state"; +import { buildUsageCostSnapshot, type UsageCostMode, type UsageCostSnapshot } from "../runtime/usage-cost"; +import { type StructuredChatDocEntry } from "../runtime/doc-hub"; +import { + PROJECT_STATES, + PROJECTS_PATH, + ProjectStoreValidationError, + createProject, + listProjects, + loadProjectStore, + updateProject, +} from "../runtime/project-store"; +import { computeProjectSummaries } from "../runtime/project-summary"; +import { computeTasksSummary } from "../runtime/task-summary"; +import { readTaskHeartbeatRuns, runTaskHeartbeat, runtimeTaskHeartbeatGate } from "../runtime/task-heartbeat"; +import { + UI_QUICK_FILTERS, + isUiLanguage, + isUiQuickFilter, + loadUiPreferences, + saveUiPreferences, + type UiLanguage, + type UiPreferences, + type UiQuickFilter, +} from "../runtime/ui-preferences"; +import { + TASKS_PATH, + TaskStoreValidationError, + createTask, + listTasks, + loadTaskStore, + updateTaskStatus, +} from "../runtime/task-store"; +import { + getSessionConversationDetail, + inferSessionExecutionChainFromSessionKey, + listSessionConversations, + type SessionConversationDetailResult, + type SessionExecutionChainSummary, + type SessionConversationListResult, + type SessionConversationFilters, + type SessionConversationListItem, + type SessionHistoryMessage, +} from "../runtime/session-conversations"; +import { loadBestEffortAgentRoster, type AgentRosterEntry, type AgentRosterSnapshot } from "../runtime/agent-roster"; +import { + loadBestEffortOfficeSessionPresence, + type OfficeSessionPresenceSnapshot, +} from "../runtime/office-session-presence"; +import type { + AgentRunState, + BudgetEvaluation, + BudgetMetricEvaluation, + CommanderExceptionsFeed, + DoneChecklistSnapshot, + NotificationCenterSnapshot, + ReadinessCategoryScore, + ProjectState, + ReadModelSnapshot, + TaskListItem, + TaskState, +} from "../types"; + +const SNAPSHOT_PATH = join(process.cwd(), "runtime", "last-snapshot.json"); +const OPENCLAW_HOME_DIR = process.env.OPENCLAW_HOME?.trim() || join(homedir(), ".openclaw"); +const OPENCLAW_CRON_JOBS_CANDIDATES = [ + join(OPENCLAW_HOME_DIR, "cron", "jobs.json"), + join(process.cwd(), "..", "..", "..", "..", "cron", "jobs.json"), +]; +const DOCS_DIR = join(process.cwd(), "docs"); +const README_PATH = join(process.cwd(), "README.md"); +const AGENT_ROOT_DIR = join(process.cwd(), ".."); +const MEMORY_DIR_CANDIDATES = [ + join(AGENT_ROOT_DIR, "memory"), + join(process.cwd(), "runtime", "digests"), +]; +const LONG_TERM_MEMORY_FILE_CANDIDATES = [ + join(AGENT_ROOT_DIR, "MEMORY.md"), + join(AGENT_ROOT_DIR, "USER.md"), + join(AGENT_ROOT_DIR, "SOUL.md"), + join(AGENT_ROOT_DIR, "IDENTITY.md"), + join(OPENCLAW_HOME_DIR, "memory", "MEMORY.md"), +]; +const DOC_HUB_DIR_CANDIDATES = [ + { dir: DOCS_DIR, category: "项目文档" }, + { dir: join(process.cwd(), "runtime", "digests"), category: "日报文档" }, + { dir: join(process.cwd(), "runtime", "evidence"), category: "证据报告" }, +]; +const DOC_HUB_CHAT_INDEX_PATH = join(process.cwd(), "runtime", "doc-hub-chat.json"); +const HTML_HEAVY_CACHE_TTL_MS = 3_000; +const HTML_USAGE_CACHE_TTL_MS = 10_000; +const HTML_SNAPSHOT_CACHE_TTL_MS = 10_000; +const HTML_LIVE_SESSIONS_CACHE_TTL_MS = POLLING_INTERVALS_MS.sessionsList; +const JSON_MAX_BYTES = 128 * 1024; +const FORM_MAX_BYTES = 16 * 1024; +const EDITABLE_TEXT_FILE_MAX_BYTES = 1024 * 1024; +const EDITABLE_TEXT_CONTENT_MAX_CHARS = 240_000; +const SEARCH_LIMIT_MAX = 200; +const TASK_RUNTIME_ACTIVITY_WINDOW_MS = 6 * 60 * 60 * 1000; +const STALLED_RUNNING_SESSION_WINDOW_MS = 2 * 60 * 60 * 1000; +const OPENCLAW_WORKSPACE_ROOT = resolve(process.cwd(), "..", "..", ".."); +const WORKSPACE_EDITABLE_SKIP_DIRS = new Set(["node_modules", ".git", "dist", "coverage"]); +const WORKSPACE_EDITABLE_EXTENSIONS = new Set([".md", ".markdown"]); +const MEMORY_EDITABLE_EXTENSIONS = new Set([".md", ".markdown", ".txt"]); +const SHARED_DOCUMENT_FILE_CANDIDATES = [ + "AGENTS.md", + "HEARTBEAT.md", + "TOOLS.md", + join(".learnings", "LEARNINGS.md"), + join("control-center", "README.md"), +] as const; +const AGENT_DOCUMENT_FILE_CANDIDATES = [ + "AGENTS.md", + "HEARTBEAT.md", + "TOOLS.md", + "README.md", + "BOOTSTRAP.md", + "NOTEBOOK.md", + "focus.md", + "inbox.md", + "routines.md", +] as const; +const STAFF_ROLE_EVIDENCE_FILE_CANDIDATES = [ + "IDENTITY.md", + "AGENTS.md", + "README.md", + "MEMORY.md", + "focus.md", + "routines.md", + "inbox.md", +] as const; +const DASHBOARD_SEARCH_SCOPES = ["tasks", "projects", "sessions", "exceptions"] as const; +const DASHBOARD_SECTIONS = [ + "overview", + "calendar", + "team", + "memory", + "docs", + "usage-cost", + "office-space", + "projects-tasks", + "alerts", + "replay-audit", + "settings", +] as const; +const CONTROL_CENTER_MAPPING_TASK_IDS = new Set(["due-fast", "todo-second", "already-running", "unassigned"]); +const OPENCLAW_CONFIG_PATH = join(OPENCLAW_HOME_DIR, "openclaw.json"); +const LEGACY_DASHBOARD_ROUTE_SECTION = { + "/calendar": "projects-tasks", + "/heartbeat": "overview", + "/tools": "settings", +} as const; +const LEGACY_DASHBOARD_ROUTE_ANCHOR = { + "/calendar": "calendar-board", + "/heartbeat": "heartbeat-health", + "/tools": "tool-connectors", +} as const; +const TASK_STATES: TaskState[] = ["todo", "in_progress", "blocked", "done"]; +const SESSION_STATES: AgentRunState[] = ["idle", "running", "blocked", "waiting_approval", "error"]; +const DOC_LINKS = [ + { label: "README.md", href: "/docs/readme" }, + { label: "docs/RUNBOOK.md", href: "/docs/runbook" }, + { label: "docs/ARCHITECTURE.md", href: "/docs/architecture" }, + { label: "docs/PROGRESS.md", href: "/docs/progress" }, +] as const; +const DASHBOARD_SECTION_LINKS_EN: DashboardSectionLink[] = [ + { key: "overview", label: "Overview", blurb: "Today at a glance" }, + { key: "usage-cost", label: "Usage", blurb: "Budget and quota" }, + { key: "team", label: "Staff", blurb: "Mission, staff and assignments" }, + { key: "memory", label: "Memory", blurb: "Daily and long-term memories" }, + { key: "docs", label: "Documents", blurb: "Main and active agent core docs" }, + { key: "projects-tasks", label: "Tasks", blurb: "Board, schedule and activity" }, + { key: "settings", label: "Settings", blurb: "Safety and data links" }, +] as const; +const ANIMAL_CATALOG = [ + { + key: "robot", + title: "Robot Operator", + accent: "#8ad2ff", + sprite: " [:::] \n |o o| \n | - | \n /|_|\\\\ ", + keywords: ["robot", "android", "bot", "codex"], + }, + { + key: "lion", + title: "Lion Captain", + accent: "#ff9966", + sprite: " /\\_/\\ \n( 0_0 )\n /|^|\\ \n / \\ ", + keywords: ["lion", "lead", "main", "chief", "alpha"], + }, + { + key: "panda", + title: "Panda Strategist", + accent: "#9df2ff", + sprite: " /\\_/\\ \n( o.o )\n( = )\n / \\ ", + keywords: ["panda", "focus", "plan", "calm"], + }, + { + key: "monkey", + title: "Monkey Builder", + accent: "#f4c542", + sprite: " /\\_/\\ \n( @.@ )\n /|_|\\ \n / \\ ", + keywords: ["monkey", "ape", "creative", "hack"], + }, + { + key: "dolphin", + title: "Dolphin Navigator", + accent: "#6ed8ff", + sprite: " __/\\ \n<( o )__\n / .--'\n \\_/ ", + keywords: ["dolphin", "wave", "flow", "sea"], + }, + { + key: "owl", + title: "Owl Analyst", + accent: "#f4ccff", + sprite: " /\\_/\\ \n( O,O )\n( V )\n / \\ ", + keywords: ["owl", "watch", "audit", "night"], + }, + { + key: "fox", + title: "Fox Courier", + accent: "#ffb36e", + sprite: " /\\_/\\ \n( ^.^ )\n /\\_/\\ \n / \\ ", + keywords: ["fox", "swift", "relay", "ops"], + }, + { + key: "bear", + title: "Bear Guardian", + accent: "#a4ffb0", + sprite: " /\\_/\\ \n( -.- )\n( U )\n / \\ ", + keywords: ["bear", "guard", "shield", "safe"], + }, + { + key: "eagle", + title: "Eagle Scout", + accent: "#ffe07d", + sprite: " /\\_/\\\n==(o)==\n /_\\ \n / \\ ", + keywords: ["eagle", "vision", "scan", "observer"], + }, + { + key: "tiger", + title: "Tiger Sprinter", + accent: "#ff8a7d", + sprite: " /\\_/\\ \n( >.< )\n /|#|\\ \n / \\ ", + keywords: ["tiger", "stripe", "fast", "sprint"], + }, + { + key: "otter", + title: "Otter Planner", + accent: "#8ad1ff", + sprite: " /\\_/\\ \n( o_o )\n /~~~\\ \n / \\ ", + keywords: ["otter", "water", "daily", "planner"], + }, + { + key: "rooster", + title: "Rooster Herald", + accent: "#ffb85e", + sprite: " __\n<(o )___\n ( ._> /\n `---' ", + keywords: ["rooster", "cock", "coq", "chanticleer"], + }, +] as const; +const FALLBACK_ANIMAL_CATALOG = ANIMAL_CATALOG.filter((item) => item.key !== "robot"); + +type DashboardSearchScope = (typeof DASHBOARD_SEARCH_SCOPES)[number]; +export type DashboardSection = (typeof DASHBOARD_SECTIONS)[number]; + +interface TaskQueryFilters { + quick?: UiQuickFilter; + status?: TaskState; + owner?: string; + project?: string; +} + +interface ProjectQueryFilters { + status?: ProjectState; + owner?: string; + projectId?: string; +} + +interface SessionQuery { + filters: SessionConversationFilters; + page: number; + pageSize: number; + historyLimit: number; +} + +interface SearchQuery { + q: string; + limit: number; +} + +interface DashboardSearchQuery { + scope: DashboardSearchScope; + q: string; + limit: number; +} + +interface DashboardSearchResult { + scope: DashboardSearchScope; + q: string; + limit: number; + count: number; + returned: number; + rows: string; +} + +type UsageView = "cumulative" | "today"; + +interface DashboardOptions { + section: DashboardSection; + language: UiLanguage; + compactStatusStrip: boolean; + usageView: UsageView; + preferencesPath: string; + search: DashboardSearchQuery; +} + +interface DashboardSectionLink { + key: DashboardSection; + label: string; + blurb: string; +} + +interface MemoryEntry { + day: string; + title: string; + excerpt: string; + sourcePath: string; +} + +interface TeamMemberSnapshot { + agentId: string; + displayName: string; + model: string; + workspace: string; + toolsProfile: string; +} + +interface TeamSnapshot { + missionStatement: string; + members: TeamMemberSnapshot[]; + sourcePath: string; + detail: string; +} + +interface DocEntry { + title: string; + excerpt: string; + category: string; + sourcePath: string; + updatedAt: string; + sourceType: "file" | "chat"; + sourceSessionKey?: string; + sourceAgentId?: string; +} + +type EditableFileScope = "memory" | "workspace"; + +interface EditableFileEntry { + scope: EditableFileScope; + title: string; + excerpt: string; + category: string; + sourcePath: string; + relativePath: string; + updatedAt: string; + size: number; + facetKey?: string; + facetLabel?: string; +} + +interface EditableAgentScope { + agentId: string; + facetKey: string; + facetLabel: string; + workspaceRoot: string; +} + +type EditableAgentScopeConfigStatus = "configured" | "config_missing" | "config_invalid"; + +let renderSessionPreviewCache: + | { snapshotAt: string; value: SessionConversationListResult; expiresAt: number } + | undefined; +let renderUsageCostSummaryCache: + | { snapshotKey: string; value: UsageCostSnapshot; expiresAt: number } + | undefined; +let renderUsageCostFullCache: + | { snapshotKey: string; value: UsageCostSnapshot; expiresAt: number } + | undefined; +let renderOfficePresenceCache: + | { expiresAt: number; value: OfficeSessionPresenceSnapshot } + | undefined; +let renderStaffRecentActivityCache: + | { + snapshotAt: string; + language: UiLanguage; + agentKey: string; + value: Map; + expiresAt: number; + } + | undefined; +let renderTaskEvidenceCache: + | { + snapshotAt: string; + historyLimit: number; + sessionKey: string; + value: SessionConversationListItem[]; + expiresAt: number; + } + | undefined; +let renderSnapshotCache: + | { + sourceStamp: string; + value: ReadModelSnapshot; + expiresAt: number; + } + | undefined; +let renderSnapshotInFlight: + | { + sourceStamp: string; + value: Promise; + } + | undefined; +let renderUsageCostSummaryInFlight: + | { + snapshotKey: string; + value: Promise; + } + | undefined; +let renderUsageCostFullInFlight: + | { + snapshotKey: string; + value: Promise; + } + | undefined; +let renderLiveSessionsCache: + | { + value: Awaited>; + expiresAt: number; + } + | undefined; +let renderLiveSessionsInFlight: Promise>> | undefined; + +type GlobalVisibilityTaskStatus = "done" | "not_done"; + +interface GlobalVisibilityTaskRow { + taskType: "cron" | "heartbeat" | "current_task" | "tool_call"; + taskTypeLabel: string; + taskName: string; + executor: string; + currentAction: string; + nextRun: string; + latestResult: string; + status: GlobalVisibilityTaskStatus; + nextAction: string; + detailsHref: string; + detailsLabel: string; +} + +interface GlobalVisibilityViewModel { + tasks: GlobalVisibilityTaskRow[]; + doneCount: number; + notDoneCount: number; + noTaskMessage: string; + signalCounts: { + schedule: number; + heartbeat: number; + currentTasks: number; + toolCalls: number; + }; +} + +interface GlobalVisibilityCopy { + title: string; + summary: string; + scheduleLabel: string; + heartbeatLabel: string; + currentTasksLabel: string; + toolCallsLabel: string; + scheduleLinkLabel: string; + heartbeatLinkLabel: string; + currentTasksLinkLabel: string; + toolCallsLinkLabel: string; + doneLabel: string; + notDoneLabel: string; + taskTypeLabel: string; + taskNameLabel: string; + executorLabel: string; + currentActionLabel: string; + nextRunLabel: string; + latestResultLabel: string; + statusLabel: string; + nextActionLabel: string; + detailsLabel: string; + doneStatusText: string; + notDoneStatusText: string; +} + +interface OpenclawCronJobSummary { + jobId: string; + name: string; + enabled: boolean; + owner: string; + ownerAgentId?: string; + purpose: string; + scheduleLabel: string; + sourcePath: string; +} + +interface AgentAnimalIdentity { + animal: string; + title: string; + accent: string; + sprite: string; +} + +interface OfficeSpaceCard { + agentId: string; + identity: AgentAnimalIdentity; + status: AgentRunState | "mixed" | "inactive"; + statusLabel: string; + officeZone: "Builder Desks" | "Approval Desk" | "Support Bay" | "Standby Pods"; + activeSessions: number; + activeTasks: number; + focusItems: string[]; + summary: string; +} + +interface ExecutionAgentSummary { + agentId: string; + displayName: string; + activeSessions: number; + activeTasks: number; + enabledCronJobs: number; + cronJobNames: string[]; + recentTokens30d: number; +} + +interface StaffOverviewCard { + agentId: string; + displayName: string; + identity: AgentAnimalIdentity; + roleLabel: string; + statusLabel: string; + currentWorkLabel: string; + currentWork: string; + recentOutput: string; + scheduledLabel: string; +} + +interface StaffRecentActivity { + recentOutput: string; + recentOutputAt?: string; + sessionKey?: string; + statusOverride?: OfficeSpaceCard["status"]; +} + +type DataCoverageStatus = "connected" | "partial" | "not_connected"; + +interface InformationCertaintySignal { + key: string; + label: string; + status: DataCoverageStatus; + detail: string; +} + +interface InformationCertaintyModel { + score: number; + badgeStatus: "ok" | "warn" | "blocked"; + badgeLabel: string; + headline: string; + summary: string; + strengths: string[]; + gaps: string[]; + signals: InformationCertaintySignal[]; +} + +interface TaskExecutionChainCard { + taskId?: string; + taskTitle: string; + projectTitle?: string; + owner: string; + sessionKey: string; + agentId?: string; + state: AgentRunState; + latestAt?: string; + latestSnippet?: string; + executionChain: SessionExecutionChainSummary; + sessionHref: string; + taskHref?: string; + unmapped?: boolean; +} + +interface TaskRoleSummary { + owner: string; + activeTasks: number; + sampleTaskIds: string[]; +} + +interface TaskCertaintyCard { + taskId: string; + title: string; + projectTitle: string; + owner: string; + score: number; + tone: "ok" | "warn" | "blocked"; + toneLabel: string; + summary: string; + evidence: string[]; + gaps: string[]; + detailHref: string; +} + +interface TaskDetailSessionSignal { + sessionKey: string; + agentId?: string; + state: AgentRunState; + latestAt?: string; + latestSnippet?: string; + sessionHref: string; +} + +interface ParitySurfaceRow { + id: string; + name: string; + route: string; + status: "enabled" | "warn" | "disabled"; + detail: string; +} + +interface BudgetBarModel { + label: string; + status: string; + metric: string; + used: number; + limit: number; + ratio: number; +} + +interface GraphNode { + id: string; + type: "project" | "task" | "session" | "agent"; + label: string; + status?: string; +} + +interface GraphEdge { + id: string; + from: string; + to: string; + type: "project_task" | "task_session" | "agent_session" | "project_session"; +} + +interface LinkageGraph { + generatedAt: string; + nodes: GraphNode[]; + edges: GraphEdge[]; + counts: { + nodes: number; + edges: number; + projects: number; + tasks: number; + sessions: number; + agents: number; + }; +} + +export function startUiServer(port: number, toolClient: ToolClient): Server { + const approvalActions = new ApprovalActionService(toolClient); + + const server = createServer(async (req, res) => { + const method = req.method ?? "GET"; + const requestId = resolveRequestId(req); + res.setHeader("x-request-id", requestId); + + try { + const url = new URL(req.url ?? "/", "http://127.0.0.1"); + const path = url.pathname; + const legacySection = resolveLegacyDashboardSection(path); + const legacyAnchor = resolveLegacyDashboardAnchor(path); + + if (method === "GET" && (path === "/" || legacySection)) { + const prefs = await loadUiPreferences(); + if (prefs.issues.length > 0) { + console.warn("[mission-control] ui preferences normalized", { requestId, issues: prefs.issues }); + } + + let filters = resolveDashboardTaskFilters(url.searchParams, prefs.preferences); + const section = legacySection ?? resolveDashboardSection(url.searchParams); + const resolvedLanguage = resolveUiLanguage(url.searchParams, prefs.preferences.language); + const hasExplicitLanguage = hasAnyQueryKey(url.searchParams, ["lang"]); + const language: UiLanguage = hasExplicitLanguage ? resolvedLanguage : "zh"; + const compactStatusStrip = resolveCompactStatusStrip(url.searchParams, prefs.preferences.compactStatusStrip); + const usageView = resolveUsageView(url.searchParams); + const search = resolveDashboardSearchQuery(url.searchParams); + const hasTaskFilterQuery = hasAnyQueryKey(url.searchParams, ["quick", "status", "owner", "project"]); + + if (section === "projects-tasks" && !hasTaskFilterQuery) { + filters = { quick: "all" }; + } + + if (path !== "/") { + const target = `${buildHomeHref(filters, compactStatusStrip, section, language, usageView)}${legacyAnchor ? `#${legacyAnchor}` : ""}`; + return redirect(res, 302, target); + } + + if (hasAnyQueryKey(url.searchParams, ["quick", "status", "owner", "project", "compact", "lang", "usage_view"])) { + await saveUiPreferences({ + language, + compactStatusStrip, + quickFilter: filters.quick ?? "all", + taskFilters: { + status: filters.status, + owner: filters.owner, + project: filters.project, + }, + updatedAt: new Date().toISOString(), + }); + } + + const html = await renderHtml(filters, toolClient, { + section, + language, + compactStatusStrip, + usageView, + preferencesPath: prefs.path, + search, + }); + return writeText(res, 200, html, "text/html; charset=utf-8"); + } + + if (method === "GET" && path === "/docs") { + assertAllowedQueryParams(url.searchParams, ["lang"], true); + const language = resolveUiLanguage(url.searchParams, "zh"); + const t = (en: string, zh: string): string => pickUiText(language, en, zh); + const links = DOC_LINKS.map( + (item) => `
`, + ).join(""); + const docsHref = buildHomeHref({ quick: "all" }, true, "docs", language); + const homeHref = buildHomeHref({ quick: "all" }, true, "overview", language); + const html = `${escapeHtml(t("OpenClaw Control Center Docs", "OpenClaw Control Center 文档"))}

${escapeHtml(t("OpenClaw Control Center Docs", "OpenClaw Control Center 文档"))}

    ${links}

${escapeHtml(t("Open document workbench", "打开文档工作台"))} · ${escapeHtml(t("Back to control center", "返回控制中心"))}

`; + return writeText(res, 200, html, "text/html; charset=utf-8"); + } + + if (method === "GET" && path.startsWith("/docs/")) { + assertAllowedQueryParams(url.searchParams, ["lang"], true); + const docId = path.slice("/docs/".length); + const docPath = resolveDocPath(docId); + if (!docPath) { + return writeApiError(res, 404, "NOT_FOUND", "Unknown docs route."); + } + let body = ""; + try { + body = await readFile(docPath, "utf8"); + } catch { + return writeApiError(res, 404, "NOT_FOUND", "Doc file not found."); + } + return writeText(res, 200, body, "text/markdown; charset=utf-8"); + } + + if (method === "GET" && path === "/snapshot") { + assertAllowedQueryParams(url.searchParams, [], true); + const body = await readSnapshotRaw(); + return writeText(res, 200, body, "application/json; charset=utf-8"); + } + + if (method === "GET" && (path === "/graph" || path === "/api/graph")) { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + return writeJson(res, 200, { + ok: true, + graph: buildLinkageGraph(snapshot), + }); + } + + if (method === "GET" && path === "/view/pixel-state.json") { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + return writeJson(res, 200, { + ok: true, + state: buildPixelState(snapshot), + }); + } + + if ( + method === "GET" && + (path === "/export/state.json" || path === "/api/export/state.json") + ) { + assertAllowedQueryParams(url.searchParams, [], true); + assertMutationAuthorized(req, "/api/export/state.json"); + const snapshot = await readReadModelSnapshot(); + const exportPayload = await buildExportBundle(snapshot, "api", requestId); + let exportSnapshot; + let backupExport; + try { + [exportSnapshot, backupExport] = await Promise.all([ + writeExportSnapshot(exportPayload as unknown as Record, requestId), + writeExportBundle(exportPayload, "backup"), + ]); + await appendOperationAudit({ + action: "backup_export", + source: "api", + ok: true, + requestId, + detail: `wrote ${backupExport.fileName}`, + metadata: { + path: backupExport.path, + sizeBytes: backupExport.sizeBytes, + }, + }); + } catch (error) { + await appendOperationAudit({ + action: "backup_export", + source: "api", + ok: false, + requestId, + detail: error instanceof Error ? error.message : "backup export failed", + }); + throw error; + } + return writeJson(res, 200, { + ...exportPayload, + exportSnapshot, + backupExport, + }); + } + + if (method === "GET" && (path === "/done-checklist" || path === "/api/done-checklist")) { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + const checklist = await buildDoneChecklist(snapshot); + return writeJson(res, 200, { + ok: true, + checklist, + }); + } + + if (method === "GET" && path === "/api/docs") { + assertAllowedQueryParams(url.searchParams, [], true); + return writeJson(res, 200, { + ok: true, + docs: buildApiDocs(), + }); + } + + if (method === "GET" && path === "/api/files") { + assertAllowedQueryParams(url.searchParams, ["scope"], true); + const scopeParam = normalizeQueryString(url.searchParams.get("scope"), "scope", 24, true); + const scope = normalizeEditableFileScope(scopeParam); + if (!scope) { + throw new RequestValidationError("scope must be one of: memory, workspace", 400); + } + const files = await listEditableFiles(scope); + return writeJson(res, 200, { + ok: true, + scope, + count: files.length, + files, + }); + } + + if (method === "GET" && path === "/api/files/content") { + assertAllowedQueryParams(url.searchParams, ["scope", "path"], true); + const scopeParam = normalizeQueryString(url.searchParams.get("scope"), "scope", 24, true); + const filePath = normalizeQueryString(url.searchParams.get("path"), "path", 4096, true); + const scope = normalizeEditableFileScope(scopeParam); + if (!scope) { + throw new RequestValidationError("scope must be one of: memory, workspace", 400); + } + if (!filePath) { + throw new RequestValidationError("path is required.", 400); + } + const payload = await readEditableFile(scope, filePath); + if (!payload) { + return writeApiError(res, 404, "NOT_FOUND", "Editable file not found in allowed scope."); + } + return writeJson(res, 200, { + ok: true, + scope, + entry: payload.entry, + content: payload.content, + }); + } + + if ((method === "PUT" || method === "PATCH") && path === "/api/files/content") { + assertMutationAuthorized(req, "/api/files/content"); + assertJsonContentType(req); + const payload = expectObject(await readJsonBody(req), "editable file payload"); + const scope = normalizeEditableFileScope(optionalBoundedString(payload.scope, "scope", 24)); + const filePath = optionalBoundedString(payload.path, "path", 4096); + const content = boundedTextField(payload.content, "content", EDITABLE_TEXT_CONTENT_MAX_CHARS); + if (!scope) { + throw new RequestValidationError("scope must be one of: memory, workspace", 400); + } + if (!filePath) { + throw new RequestValidationError("path is required.", 400); + } + const saved = await writeEditableFileContent(scope, filePath, content); + if (!saved) { + return writeApiError(res, 404, "NOT_FOUND", "Editable file not found in allowed scope."); + } + return writeJson(res, 200, { + ok: true, + scope, + entry: saved.entry, + content: saved.content, + }); + } + + if (method === "GET" && path === "/api/ui/preferences") { + assertAllowedQueryParams(url.searchParams, [], true); + const prefs = await loadUiPreferences(); + return writeJson(res, 200, { + ok: true, + path: prefs.path, + preferences: prefs.preferences, + issues: prefs.issues, + }); + } + + if (method === "PATCH" && path === "/api/ui/preferences") { + assertMutationAuthorized(req, "/api/ui/preferences"); + assertJsonContentType(req); + const payload = expectObject(await readJsonBody(req), "ui preferences payload"); + const current = await loadUiPreferences(); + const merged = mergeUiPreferencesPatch(current.preferences, payload); + const saved = await saveUiPreferences(merged); + return writeJson(res, 200, { + ok: true, + path: saved.path, + preferences: saved.preferences, + issues: saved.issues, + }); + } + + if (method === "GET" && path === "/api/search/tasks") { + const query = parseSearchQuery(url.searchParams); + const snapshot = await readReadModelSnapshot(); + const matches = listTasks(snapshot.tasks, projectTitleMap(snapshot)) + .filter((task) => + safeSubstringMatch( + query.q, + task.taskId, + task.title, + task.owner, + task.projectId, + task.projectTitle, + task.dueAt, + task.status, + ), + ); + const tasks = matches.slice(0, query.limit); + return writeJson(res, 200, { + ok: true, + scope: "tasks", + query, + count: matches.length, + returned: tasks.length, + items: tasks, + }); + } + + if (method === "GET" && path === "/api/search/projects") { + const query = parseSearchQuery(url.searchParams); + const snapshot = await readReadModelSnapshot(); + const matches = snapshot.projects.projects + .filter((project) => + safeSubstringMatch( + query.q, + project.projectId, + project.title, + project.owner, + project.status, + ), + ); + const projects = matches.slice(0, query.limit); + return writeJson(res, 200, { + ok: true, + scope: "projects", + query, + count: matches.length, + returned: projects.length, + items: projects, + }); + } + + if (method === "GET" && path === "/api/search/sessions") { + const query = parseSearchQuery(url.searchParams); + const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient); + const matches = snapshot.sessions + .filter((session) => + safeSubstringMatch( + query.q, + session.sessionKey, + session.label, + session.agentId, + session.state, + session.lastMessageAt, + ), + ); + const sessions = matches.slice(0, query.limit); + return writeJson(res, 200, { + ok: true, + scope: "sessions", + query, + count: matches.length, + returned: sessions.length, + items: sessions, + }); + } + + if (method === "GET" && path === "/api/search/exceptions") { + const query = parseSearchQuery(url.searchParams); + const snapshot = await readReadModelSnapshot(); + const feed = commanderExceptionsFeed(snapshot); + const matches = feed.items + .filter((item) => + safeSubstringMatch( + query.q, + item.level, + item.code, + item.source, + item.sourceId, + item.route, + item.message, + ), + ); + const items = matches.slice(0, query.limit); + return writeJson(res, 200, { + ok: true, + scope: "exceptions", + query, + count: matches.length, + returned: items.length, + items, + }); + } + + if (method === "GET" && path === "/api/usage-cost") { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + const usage = await buildUsageCostSnapshot(snapshot); + return writeJson(res, 200, { + ok: true, + usage, + }); + } + + if (method === "GET" && path === "/api/subscription/template") { + assertAllowedQueryParams(url.searchParams, [], true); + return writeJson(res, 200, { + ok: true, + template: { + subscription: { + planLabel: "OpenClaw Team Plan", + unit: "USD", + consumed: 120, + remaining: 880, + limit: 1000, + cycleStart: "2026-03-01", + cycleEnd: "2026-03-31", + }, + }, + hint: `Save as ${join(process.cwd(), "runtime", "subscription-snapshot.json")}`, + }); + } + + if (method === "GET" && path === "/api/tasks/heartbeat") { + assertAllowedQueryParams(url.searchParams, ["limit"], true); + const limit = readPositiveIntQuery(url.searchParams.get("limit"), "limit", 20, true, 200); + const runs = await readTaskHeartbeatRuns(limit); + return writeJson(res, 200, { + ok: true, + path: runs.path, + count: runs.count, + runs: runs.runs, + }); + } + + if (method === "POST" && path === "/api/tasks/heartbeat") { + assertMutationAuthorized(req, "/api/tasks/heartbeat"); + assertAllowedQueryParams(url.searchParams, [], true); + assertJsonContentType(req); + const payload = expectObject(await readJsonBody(req), "task heartbeat payload"); + const gate = runtimeTaskHeartbeatGate(); + if (payload.dryRun !== undefined) { + if (typeof payload.dryRun !== "boolean") { + throw new RequestValidationError("dryRun must be a boolean when provided.", 400); + } + gate.dryRun = payload.dryRun; + } + const maxTasksPerRun = optionalIntegerField(payload.maxTasksPerRun, "maxTasksPerRun", 1, 200); + if (maxTasksPerRun !== undefined) gate.maxTasksPerRun = maxTasksPerRun; + const result = await runTaskHeartbeat({ gate }); + return writeJson(res, result.mode === "blocked" ? 403 : 200, result); + } + + if (method === "GET" && path === "/usage-cost") { + assertAllowedQueryParams(url.searchParams, [], true); + res.statusCode = 302; + res.setHeader("location", "/?section=usage-cost"); + return writeText(res, 302, "redirecting", "text/plain; charset=utf-8"); + } + + if (method === "GET" && path === "/api/replay/index") { + assertAllowedQueryParams(url.searchParams, ["timelineLimit", "digestLimit", "exportLimit", "from", "to"], true); + const replayWindow = parseReplayWindowQuery(url.searchParams, true); + const replay = await loadReplayIndex({ + timelineLimit: readPositiveIntQuery( + url.searchParams.get("timelineLimit"), + "timelineLimit", + 80, + true, + 400, + ), + digestLimit: readPositiveIntQuery(url.searchParams.get("digestLimit"), "digestLimit", 30, true, 200), + exportLimit: readPositiveIntQuery(url.searchParams.get("exportLimit"), "exportLimit", 30, true, 200), + from: replayWindow.from, + to: replayWindow.to, + }); + return writeJson(res, 200, { + ok: true, + replay, + }); + } + + if (method === "POST" && path === "/api/import/dry-run") { + assertMutationAuthorized(req, "/api/import/dry-run"); + assertJsonContentType(req); + const payload = expectObject(await readJsonBody(req), "import dry-run payload"); + let validation; + + if (typeof payload.fileName === "string" && payload.fileName.trim() !== "") { + validation = await validateExportFileDryRun(payload.fileName); + } else if (payload.bundle !== undefined) { + validation = validateExportBundleDryRun(payload.bundle, "payload.bundle"); + } else { + validation = validateExportBundleDryRun(payload, "payload"); + } + + await appendOperationAudit({ + action: "import_dry_run", + source: "api", + ok: validation.valid, + requestId, + detail: `validated ${validation.source}`, + metadata: { + valid: validation.valid, + issues: validation.issues.length, + warnings: validation.warnings.length, + }, + }); + + return writeJson(res, 200, { + ok: validation.valid, + validation, + }); + } + + if (method === "POST" && path === "/api/import/live") { + assertMutationAuthorized(req, "/api/import/live"); + assertJsonContentType(req); + const payload = expectObject(await readJsonBody(req), "import live payload"); + const result = await applyImportMutation({ + fileName: typeof payload.fileName === "string" ? payload.fileName : undefined, + bundle: payload.bundle !== undefined ? payload.bundle : payload, + dryRun: typeof payload.dryRun === "boolean" ? payload.dryRun : undefined, + }); + + await appendOperationAudit({ + action: "import_apply", + source: "api", + ok: result.ok, + requestId, + detail: `${result.mode} ${result.source ?? "payload"}: ${result.message}`, + metadata: { + mode: result.mode, + statusCode: result.statusCode, + valid: result.validation?.valid ?? false, + issues: result.validation?.issues.length ?? 0, + warnings: result.validation?.warnings.length ?? 0, + }, + }); + + return writeJson(res, result.statusCode, result); + } + + if (method === "GET" && (path === "/projects" || path === "/api/projects")) { + const projectStore = await loadProjectStore(); + const filters = parseProjectFilters(url.searchParams, path === "/api/projects"); + const projects = applyProjectFilters(listProjects(projectStore), filters); + return writeJson(res, 200, { + ok: true, + updatedAt: projectStore.updatedAt, + count: projects.length, + filters, + projects, + }); + } + + if (method === "POST" && path === "/api/projects") { + assertMutationAuthorized(req, "/api/projects"); + assertJsonContentType(req); + const payload = expectObject(await readJsonBody(req), "create project payload"); + const created = await createProject(payload); + return writeJson(res, 201, { ok: true, ...created }); + } + + if (method === "PATCH" && path.startsWith("/api/projects/")) { + assertMutationAuthorized(req, "/api/projects/:projectId"); + assertJsonContentType(req); + const projectId = decodeRouteParam(path, /^\/api\/projects\/([^/]+)$/, "projectId"); + const payload = expectObject(await readJsonBody(req), "update project payload"); + const updated = await updateProject({ + ...payload, + projectId, + }); + return writeJson(res, 200, { ok: true, ...updated }); + } + + if (method === "GET" && (path === "/tasks" || path === "/api/tasks")) { + const snapshot = await readReadModelSnapshot(); + const filters = parseTaskFilters(url.searchParams, path === "/api/tasks"); + const allTasks = listTasks(snapshot.tasks, projectTitleMap(snapshot)); + const filteredTasks = applyTaskFilters(allTasks, filters); + return writeJson(res, 200, { + ok: true, + updatedAt: snapshot.tasks.updatedAt, + count: filteredTasks.length, + filters, + tasks: filteredTasks, + }); + } + + if (method === "POST" && path === "/api/tasks") { + assertMutationAuthorized(req, "/api/tasks"); + assertJsonContentType(req); + const payload = expectObject(await readJsonBody(req), "create task payload"); + const created = await createTask(payload); + return writeJson(res, 201, { ok: true, ...created }); + } + + if (method === "PATCH" && path.startsWith("/api/tasks/") && path.endsWith("/status")) { + assertMutationAuthorized(req, "/api/tasks/:taskId/status"); + assertJsonContentType(req); + const taskId = decodeRouteParam(path, /^\/api\/tasks\/([^/]+)\/status$/, "taskId"); + const payload = expectObject(await readJsonBody(req), "update task status payload"); + const updated = await updateTaskStatus({ + taskId, + status: payload.status, + projectId: payload.projectId, + }); + return writeJson(res, 200, { ok: true, ...updated }); + } + + if (method === "GET" && (path === "/sessions" || path === "/api/sessions")) { + const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient); + const strict = path === "/api/sessions"; + const query = parseSessionQuery(url.searchParams, strict); + const sessions = await listSessionConversations({ + snapshot, + client: toolClient, + filters: query.filters, + page: query.page, + pageSize: query.pageSize, + historyLimit: query.historyLimit, + }); + + return writeJson(res, 200, { + ok: true, + ...sessions, + }); + } + + if (method === "GET" && path.startsWith("/api/sessions/")) { + const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient); + const sessionKey = decodeRouteParam(path, /^\/api\/sessions\/([^/]+)$/, "sessionKey"); + assertAllowedQueryParams(url.searchParams, ["historyLimit"], true); + const historyLimit = readPositiveIntQuery( + url.searchParams.get("historyLimit"), + "historyLimit", + 50, + true, + 200, + ); + const detail = await getSessionConversationDetail({ + snapshot, + client: toolClient, + sessionKey, + historyLimit, + }); + + if (!detail) { + return writeApiError(res, 404, "NOT_FOUND", `Session '${sessionKey}' was not found.`); + } + + return writeJson(res, 200, { + ok: true, + ...detail, + }); + } + + if (method === "GET" && path.startsWith("/sessions/")) { + const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient); + const sessionKey = decodeRouteParam(path, /^\/sessions\/([^/]+)$/, "sessionKey"); + const historyLimit = readPositiveIntQuery(url.searchParams.get("historyLimit"), "historyLimit", 50, false); + const detail = await getSessionConversationDetail({ + snapshot, + client: toolClient, + sessionKey, + historyLimit, + }); + + if (!detail) { + return writeApiError(res, 404, "NOT_FOUND", `Session '${sessionKey}' was not found.`); + } + + return writeJson(res, 200, { + ok: true, + ...detail, + }); + } + + if (method === "GET" && path.startsWith("/session/")) { + const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient); + const language = resolveUiLanguage(url.searchParams, "zh"); + const sessionKey = decodeRouteParam(path, /^\/session\/([^/]+)$/, "sessionKey"); + assertAllowedQueryParams(url.searchParams, ["historyLimit"], false); + const historyLimit = readPositiveIntQuery( + url.searchParams.get("historyLimit"), + "historyLimit", + 50, + false, + 200, + ); + const detail = await getSessionConversationDetail({ + snapshot, + client: toolClient, + sessionKey, + historyLimit, + }); + + if (!detail) { + return writeText(res, 404, "Session not found", "text/plain; charset=utf-8"); + } + + const html = renderSessionDrilldownPage(detail, language); + return writeText(res, 200, html, "text/html; charset=utf-8"); + } + + if (method === "GET" && path.startsWith("/details/task/")) { + const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient); + const language = resolveUiLanguage(url.searchParams, "zh"); + const taskId = decodeRouteParam(path, /^\/details\/task\/([^/]+)$/, "taskId"); + const tasks = listTasks(snapshot.tasks, projectTitleMap(snapshot)); + const task = tasks.find((item) => item.taskId === taskId); + if (!task) { + return writeText(res, 404, "Task not found", "text/plain; charset=utf-8"); + } + const linkedSessionItems = await loadSessionConversationItemsByKeys(snapshot, toolClient, task.sessionKeys, 24); + const certaintyCard = buildTaskCertaintyCards({ + tasks: [task], + sessions: snapshot.sessions, + sessionItems: linkedSessionItems, + approvals: snapshot.approvals, + language, + })[0]; + const linkedSessions: TaskDetailSessionSignal[] = linkedSessionItems.map((detail) => ({ + sessionKey: detail.sessionKey, + agentId: detail.agentId, + state: detail.state, + latestAt: detail.latestHistoryAt ?? detail.lastMessageAt, + latestSnippet: detail.latestSnippet, + sessionHref: buildSessionDetailHref(detail.sessionKey, language), + })); + const html = renderTaskDetailPage({ + task, + generatedAt: snapshot.generatedAt ?? new Date().toISOString(), + certaintyCard, + linkedSessions, + language, + }); + return writeText(res, 200, html, "text/html; charset=utf-8"); + } + + if (method === "GET" && path.startsWith("/details/cron/")) { + const snapshot = await readReadModelSnapshot(); + const language = resolveUiLanguage(url.searchParams, "zh"); + const jobId = decodeRouteParam(path, /^\/details\/cron\/([^/]+)$/, "jobId"); + const overview = await buildCronOverview(snapshot, POLLING_INTERVALS_MS.cron); + const catalog = await loadOpenclawCronCatalog(language); + const runtimeById = new Map(overview.jobs.map((job) => [job.jobId, job])); + const catalogJob = catalog.find((item) => item.jobId === jobId); + const runtimeJob = runtimeById.get(jobId); + if (!catalogJob && !runtimeJob) { + return writeText(res, 404, "Cron job not found", "text/plain; charset=utf-8"); + } + const html = renderCronJobDetailPage( + { + jobId, + name: catalogJob?.name ?? runtimeJob?.name ?? jobId, + owner: catalogJob?.owner ?? formatExecutorAgentLabel("system-cron", language), + purpose: catalogJob?.purpose ?? cronRuntimePurpose(jobId, language), + schedule: catalogJob?.scheduleLabel ?? pickUiText(language, "system interval", "系统间隔"), + status: runtimeJob ? runtimeJob.health : catalogJob?.enabled ? "enabled" : "disabled", + nextRunAt: runtimeJob?.nextRunAt ?? "-", + dueInSeconds: runtimeJob?.dueInSeconds, + }, + snapshot.generatedAt ?? new Date().toISOString(), + language, + ); + return writeText(res, 200, html, "text/html; charset=utf-8"); + } + + if (method === "GET" && path === "/api/audit") { + const snapshot = await readReadModelSnapshot(); + const severity = parseAuditSeverity(url.searchParams, true); + const timeline = filterAuditTimeline(await loadAuditTimeline(snapshot), severity); + return writeJson(res, 200, { + ok: true, + severity, + timeline, + }); + } + + if (method === "GET" && path === "/audit") { + const snapshot = await readReadModelSnapshot(); + const severity = parseAuditSeverity(url.searchParams, false); + const timeline = filterAuditTimeline(await loadAuditTimeline(snapshot), severity); + const html = renderAuditPage(timeline, severity); + return writeText(res, 200, html, "text/html; charset=utf-8"); + } + + if (method === "GET" && path === "/api/commander/exceptions") { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + return writeJson(res, 200, { + ok: true, + exceptions: commanderExceptions(snapshot), + }); + } + + if (method === "GET" && path === "/exceptions") { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + return writeJson(res, 200, { + ok: true, + feed: commanderExceptionsFeed(snapshot), + }); + } + + if (method === "GET" && path === "/notifications/preview") { + assertAllowedQueryParams(url.searchParams, ["at"], true); + const atParam = normalizeQueryString(url.searchParams.get("at"), "at", 64, true); + let evaluatedAt = new Date(); + if (atParam) { + const ms = Date.parse(atParam); + if (Number.isNaN(ms)) { + throw new RequestValidationError("at must be a valid ISO date-time string.", 400); + } + evaluatedAt = new Date(ms); + } + + const snapshot = await readReadModelSnapshot(); + const feed = commanderExceptionsFeed(snapshot); + const policy = await loadNotificationPolicy(); + const preview = buildNotificationPreview(feed, policy, evaluatedAt); + return writeJson(res, 200, { ok: true, preview }); + } + + if (method === "GET" && path === "/cron") { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + const overview = await buildCronOverview(snapshot, POLLING_INTERVALS_MS.cron); + return writeJson(res, 200, { ok: true, overview }); + } + + if (method === "GET" && path === "/healthz") { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + const health = await buildHealthzPayload(snapshot); + const statusCode = health.status === "stale" ? 503 : 200; + return writeJson(res, statusCode, { + ok: health.status !== "stale", + health, + }); + } + + if (method === "GET" && path === "/digest/latest") { + assertAllowedQueryParams(url.searchParams, [], false); + const latest = await loadLatestDigest(); + return writeText(res, 200, renderLatestDigestPage(latest), "text/html; charset=utf-8"); + } + + if (method === "GET" && path === "/api/action-queue") { + assertAllowedQueryParams(url.searchParams, [], true); + const snapshot = await readReadModelSnapshot(); + const queue = await readNotificationCenter(snapshot); + return writeJson(res, 200, { ok: true, queue }); + } + + if (method === "GET" && path === "/api/action-queue/acks/prune-preview") { + assertMutationAuthorized(req, "/api/action-queue/acks/prune-preview"); + assertAllowedQueryParams(url.searchParams, [], true); + const preview = await previewStaleAcksPrune(); + return writeJson(res, 200, { ok: true, preview }); + } + + if (method === "POST" && path.startsWith("/api/action-queue/") && path.endsWith("/ack")) { + assertMutationAuthorized(req, "/api/action-queue/:itemId/ack"); + assertJsonContentType(req); + const itemId = decodeRouteParam(path, /^\/api\/action-queue\/([^/]+)\/ack$/, "itemId"); + const payload = expectObject(await readJsonBody(req), "action queue acknowledge payload"); + const ttlMinutes = optionalIntegerField(payload.ttlMinutes, "ttlMinutes", 1, 7 * 24 * 60); + const snoozeUntil = optionalIsoTimestampField(payload.snoozeUntil, "snoozeUntil"); + if (ttlMinutes !== undefined && snoozeUntil !== undefined) { + throw new RequestValidationError("Provide either ttlMinutes or snoozeUntil, not both.", 400); + } + if (snoozeUntil !== undefined && Date.parse(snoozeUntil) <= Date.now()) { + throw new RequestValidationError("snoozeUntil must be a future ISO date-time string.", 400); + } + const snapshot = await readReadModelSnapshot(); + const queue = await readNotificationCenter(snapshot); + const acknowledged = await acknowledgeActionQueueItem({ + itemId, + note: payload.note, + ttlMinutes, + snoozeUntil, + }, queue); + return writeJson(res, 200, { ok: true, ...acknowledged }); + } + + if (method === "POST" && path === "/action-queue/ack") { + const form = await readFormBody(req); + assertMutationAuthorized(req, "/action-queue/ack", form.get("localToken")); + const itemId = readRequiredFormValue(form, "itemId"); + const snapshot = await readReadModelSnapshot(); + const queue = await readNotificationCenter(snapshot); + await acknowledgeActionQueueItem({ itemId }, queue); + return redirect(res, 303, "/"); + } + + if (method === "POST" && path.startsWith("/api/approvals/") && path.endsWith("/approve")) { + assertMutationAuthorized(req, "/api/approvals/:approvalId/approve"); + assertJsonContentType(req); + const approvalId = decodeRouteParam(path, /^\/api\/approvals\/([^/]+)\/approve$/, "approvalId"); + const payload = expectObject(await readJsonBody(req), "approval payload"); + const reason = optionalBoundedString(payload.reason, "reason", 220); + const result = await approvalActions.execute({ action: "approve", approvalId, reason }); + return writeJson(res, result.mode === "blocked" ? 403 : result.ok ? 200 : 500, result); + } + + if (method === "POST" && path.startsWith("/api/approvals/") && path.endsWith("/reject")) { + assertMutationAuthorized(req, "/api/approvals/:approvalId/reject"); + assertJsonContentType(req); + const approvalId = decodeRouteParam(path, /^\/api\/approvals\/([^/]+)\/reject$/, "approvalId"); + const payload = expectObject(await readJsonBody(req), "approval payload"); + const reason = requiredBoundedString(payload.reason, "reason", 220); + const result = await approvalActions.execute({ + action: "reject", + approvalId, + reason, + }); + return writeJson(res, result.mode === "blocked" ? 403 : result.ok ? 200 : 500, result); + } + + if (path.startsWith("/api/")) { + return writeApiError(res, 404, "NOT_FOUND", "API route not found."); + } + + return writeText(res, 404, "Not Found", "text/plain; charset=utf-8"); + } catch (error) { + if ( + error instanceof TaskStoreValidationError || + error instanceof ProjectStoreValidationError || + error instanceof NotificationCenterValidationError + ) { + console.warn("[mission-control] ui request validation", { + requestId, + message: error.message, + issues: error.issues, + }); + const code = error.statusCode === 404 ? "NOT_FOUND" : "VALIDATION_ERROR"; + return writeApiError(res, error.statusCode, code, error.message, error.issues); + } + + if (error instanceof RequestValidationError) { + console.warn("[mission-control] ui request validation", { + requestId, + message: error.message, + issues: error.issues, + }); + const code = error.statusCode === 415 ? "UNSUPPORTED_MEDIA_TYPE" : "VALIDATION_ERROR"; + return writeApiError(res, error.statusCode, code, error.message, error.issues); + } + + console.error("[mission-control] ui error", { requestId, error }); + return writeApiError(res, 500, "INTERNAL_ERROR", "Internal server error."); + } + }); + + server.listen(port, "127.0.0.1", () => { + console.log(`[mission-control] ui listening at http://127.0.0.1:${port}`); + void primeUiRenderCaches(toolClient); + }); + return server; +} + +async function readSnapshotRaw(): Promise { + try { + return await readFile(SNAPSHOT_PATH, "utf8"); + } catch { + return JSON.stringify(defaultSnapshot(), null, 2); + } +} + +function isFsNotFound(error: unknown): boolean { + return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT"); +} + +async function readOptionalFileStamp(path: string): Promise { + try { + const file = await stat(path); + return `${path}:${file.mtimeMs}:${file.size}`; + } catch (error) { + if (isFsNotFound(error)) return `${path}:missing`; + return `${path}:error`; + } +} + +async function readReadModelSourceStamp(): Promise { + const parts = await Promise.all([ + readOptionalFileStamp(SNAPSHOT_PATH), + readOptionalFileStamp(PROJECTS_PATH), + readOptionalFileStamp(TASKS_PATH), + readOptionalFileStamp(BUDGET_POLICY_PATH), + ]); + return parts.join("|"); +} + +async function readReadModelSnapshot(): Promise { + const sourceStamp = await readReadModelSourceStamp(); + const now = Date.now(); + if ( + renderSnapshotCache && + renderSnapshotCache.sourceStamp === sourceStamp && + renderSnapshotCache.expiresAt > now + ) { + return renderSnapshotCache.value; + } + if (renderSnapshotInFlight?.sourceStamp === sourceStamp) { + return renderSnapshotInFlight.value; + } + + const nextValue = (async () => { + const snapshot = (await readSnapshotJsonWithRetry()) as Partial; + const [projects, tasks, budgetPolicy] = await Promise.all([ + loadProjectStore(), + loadTaskStore(), + loadBudgetPolicy(), + ]); + + if (budgetPolicy.issues.length > 0) { + console.warn("[mission-control] budget policy issues", { + path: budgetPolicy.path, + issues: budgetPolicy.issues, + }); + } + + const sessions = Array.isArray(snapshot.sessions) ? snapshot.sessions : []; + const statuses = Array.isArray(snapshot.statuses) ? snapshot.statuses : []; + + const value = { + sessions, + statuses, + cronJobs: Array.isArray(snapshot.cronJobs) ? snapshot.cronJobs : [], + approvals: Array.isArray(snapshot.approvals) ? snapshot.approvals : [], + projects, + projectSummaries: computeProjectSummaries(projects, tasks), + tasks, + tasksSummary: computeTasksSummary(tasks, projects.projects.length), + budgetSummary: computeBudgetSummary(sessions, statuses, tasks, projects, budgetPolicy.policy), + generatedAt: + typeof snapshot.generatedAt === "string" && !Number.isNaN(Date.parse(snapshot.generatedAt)) + ? snapshot.generatedAt + : new Date().toISOString(), + } satisfies ReadModelSnapshot; + renderSnapshotCache = { + sourceStamp, + value, + expiresAt: Date.now() + HTML_SNAPSHOT_CACHE_TTL_MS, + }; + return value; + })(); + + renderSnapshotInFlight = { sourceStamp, value: nextValue }; + try { + return await nextValue; + } finally { + if (renderSnapshotInFlight?.sourceStamp === sourceStamp) { + renderSnapshotInFlight = undefined; + } + } +} + +async function readSnapshotJsonWithRetry(): Promise> { + for (let attempt = 0; attempt < 3; attempt += 1) { + try { + return JSON.parse(await readSnapshotRaw()) as Partial; + } catch (error) { + if (attempt === 2) throw error; + await delay(25 * (attempt + 1)); + } + } + return defaultSnapshot(); +} + +async function loadCachedLiveSessions( + toolClient: ToolClient, +): Promise>> { + const now = Date.now(); + if (renderLiveSessionsCache && renderLiveSessionsCache.expiresAt > now) { + return renderLiveSessionsCache.value; + } + if (renderLiveSessionsInFlight) { + return renderLiveSessionsInFlight; + } + + const nextValue = toolClient.sessionsList(); + renderLiveSessionsInFlight = nextValue; + try { + const value = await nextValue; + renderLiveSessionsCache = { + value, + expiresAt: Date.now() + HTML_LIVE_SESSIONS_CACHE_TTL_MS, + }; + return value; + } finally { + renderLiveSessionsInFlight = undefined; + } +} + +async function readReadModelSnapshotWithLiveSessions(toolClient: ToolClient): Promise { + const snapshotPromise = readReadModelSnapshot(); + const livePromise = loadCachedLiveSessions(toolClient); + + try { + const [snapshot, live] = await Promise.all([snapshotPromise, livePromise]); + const sessions = mapSessionsListToSummaries(live); + if (sessions.length === 0) return snapshot; + + const liveStatuses: ReadModelSnapshot["statuses"] = []; + for (const item of live.sessions ?? []) { + const sessionKey = item.sessionKey ?? item.key; + if (!sessionKey) continue; + const updatedAt = + typeof item.updatedAt === "string" && !Number.isNaN(Date.parse(item.updatedAt)) + ? item.updatedAt + : typeof item.updatedAtMs === "number" && Number.isFinite(item.updatedAtMs) + ? new Date(item.updatedAtMs).toISOString() + : new Date().toISOString(); + liveStatuses.push({ + sessionKey, + model: item.model, + tokensIn: item.inputTokens, + tokensOut: item.outputTokens, + cost: undefined, + updatedAt, + }); + } + + const sessionsByKey = new Map(snapshot.sessions.map((item) => [item.sessionKey, item])); + for (const liveSession of sessions) { + const existing = sessionsByKey.get(liveSession.sessionKey); + sessionsByKey.set(liveSession.sessionKey, { + ...existing, + ...liveSession, + label: liveSession.label ?? existing?.label, + agentId: liveSession.agentId ?? existing?.agentId, + lastMessageAt: liveSession.lastMessageAt ?? existing?.lastMessageAt, + }); + } + + const statusesByKey = new Map(snapshot.statuses.map((item) => [item.sessionKey, item])); + for (const liveStatus of liveStatuses) { + const existing = statusesByKey.get(liveStatus.sessionKey); + statusesByKey.set(liveStatus.sessionKey, { + ...existing, + ...liveStatus, + model: liveStatus.model ?? existing?.model, + tokensIn: liveStatus.tokensIn ?? existing?.tokensIn, + tokensOut: liveStatus.tokensOut ?? existing?.tokensOut, + cost: existing?.cost, + updatedAt: liveStatus.updatedAt ?? existing?.updatedAt ?? new Date().toISOString(), + }); + } + + return { + ...snapshot, + sessions: [...sessionsByKey.values()].sort(compareSessionSummariesByLatest), + statuses: [...statusesByKey.values()], + }; + } catch (error) { + console.warn("[mission-control] live session backfill failed", { + error: error instanceof Error ? error.message : String(error), + }); + return snapshotPromise; + } +} + +async function primeUiRenderCaches(toolClient: ToolClient): Promise { + try { + const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient); + await Promise.all([loadCachedUsageCost(snapshot, "full"), loadCachedOfficeSessionPresence()]); + } catch (error) { + console.warn("[mission-control] ui cache warmup failed", { + error: error instanceof Error ? error.message : String(error), + }); + } +} + +async function readNotificationCenter(snapshot: ReadModelSnapshot): Promise { + const exceptionsFeed = commanderExceptionsFeed(snapshot); + const acks = await loadAcksStore(); + const linksByItemId = buildActionQueueLinks(exceptionsFeed, snapshot); + return buildNotificationCenter(exceptionsFeed, acks, linksByItemId); +} + +function pickUiText(language: UiLanguage, en: string, zh: string): string { + return language === "zh" ? zh : en; +} + +function delay(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function globalVisibilityCopy(language: UiLanguage): GlobalVisibilityCopy { + if (language === "zh") { + return { + title: "全局总览", + summary: "一眼看四件事:定时任务、任务心跳、当前任务、工具调用。", + scheduleLabel: "定时任务:", + heartbeatLabel: "任务心跳:", + currentTasksLabel: "当前任务:", + toolCallsLabel: "工具调用:", + scheduleLinkLabel: "查看定时任务", + heartbeatLinkLabel: "查看任务心跳", + currentTasksLinkLabel: "查看当前任务", + toolCallsLinkLabel: "查看工具调用", + doneLabel: "已完成", + notDoneLabel: "未完成", + taskTypeLabel: "类型", + taskNameLabel: "事项", + executorLabel: "智能体", + currentActionLabel: "正在做什么", + nextRunLabel: "下次检查", + latestResultLabel: "最近结果", + statusLabel: "状态", + nextActionLabel: "下一步", + detailsLabel: "详情", + doneStatusText: "已完成", + notDoneStatusText: "未完成", + }; + } + + return { + title: "Global Visibility", + summary: "One place to see timed jobs, heartbeat, current tasks, and tool calls.", + scheduleLabel: "Timed jobs:", + heartbeatLabel: "Heartbeat checks:", + currentTasksLabel: "Current tasks:", + toolCallsLabel: "Tool calls:", + scheduleLinkLabel: "See timed jobs", + heartbeatLinkLabel: "See heartbeat checks", + currentTasksLinkLabel: "See current tasks", + toolCallsLinkLabel: "See tool calls", + doneLabel: "Done", + notDoneLabel: "Not done", + taskTypeLabel: "Type", + taskNameLabel: "Item", + executorLabel: "Owner", + currentActionLabel: "Now", + nextRunLabel: "Next check", + latestResultLabel: "Latest", + statusLabel: "Status", + nextActionLabel: "Next step", + detailsLabel: "View", + doneStatusText: "Done", + notDoneStatusText: "Not done", + }; +} + +function formatExecutorAgentLabel(agentId: string, language: UiLanguage): string { + const normalized = agentId.trim().toLowerCase(); + if (!normalized || normalized === "system") return pickUiText(language, "System service", "系统服务"); + if (normalized === "system-cron") return pickUiText(language, "Scheduler", "调度器"); + if (normalized === "task-heartbeat-worker") return pickUiText(language, "Heartbeat service", "任务心跳服务"); + return humanizeOperatorLabel(agentId); +} + +function buildGlobalVisibilityDetailHref(taskType: GlobalVisibilityTaskRow["taskType"], language: UiLanguage): string { + if (taskType === "cron") { + return `${buildHomeHref({ quick: "all" }, true, "overview", language)}#cron-health`; + } + if (taskType === "heartbeat") { + return `${buildHomeHref({ quick: "all" }, true, "overview", language)}#heartbeat-health`; + } + if (taskType === "current_task") { + return `${buildHomeHref({ quick: "all" }, true, "projects-tasks", language)}#task-lane`; + } + return `${buildHomeHref({ quick: "all" }, true, "overview", language)}#tool-activity`; +} + +function normalizeInlineText(input: string): string { + return input.replace(/\s+/g, " ").trim(); +} + +function sanitizeCronPurposeText(input: string, language: UiLanguage, maxLength = 72): string { + const normalized = normalizeInlineText(input); + if (!normalized) return pickUiText(language, "No purpose description.", "未提供任务目的。"); + const lower = normalized.toLowerCase(); + if ( + lower.includes("run exactly one command via exec tool") || + lower.includes("cd /") || + lower.includes("&&") || + lower.includes("/opt/homebrew/") || + lower.includes("/users/") + ) { + return pickUiText(language, "Run one automation script and update status.", "执行一次自动化脚本并更新状态。"); + } + return safeTruncate(normalized, maxLength); +} + +function summarizeCronCommandPurpose(command: string, language: UiLanguage): string { + const normalized = command.trim().toLowerCase(); + if (!normalized) return pickUiText(language, "Run scheduled command.", "执行定时命令。"); + if (normalized.includes("node")) return pickUiText(language, "Run Node automation script.", "运行 Node 自动化脚本。"); + if (normalized.includes("python")) return pickUiText(language, "Run Python automation script.", "运行 Python 自动化脚本。"); + if (normalized.includes("curl")) return pickUiText(language, "Fetch external data and update status.", "拉取外部数据并更新状态。"); + return pickUiText(language, "Run scheduled command.", "执行定时命令。"); +} + +function parseSessionTargetOwner(value: string | undefined): string | undefined { + if (!value) return undefined; + const normalized = value.trim(); + if (!normalized) return undefined; + if (normalized.startsWith("agent:")) { + const parts = normalized.split(":"); + if (parts.length >= 2 && parts[1]?.trim()) return parts[1].trim(); + } + return undefined; +} + +function cronRuntimePurpose(jobId: string, language: UiLanguage): string { + const id = jobId.toLowerCase(); + if (id.includes("task-heartbeat")) { + return pickUiText( + language, + "Scan assigned backlog and trigger heartbeat pickup.", + "扫描已分配待办任务,并按心跳规则推进。", + ); + } + if (id.includes("monitor")) { + return pickUiText( + language, + "Refresh runtime snapshot and keep dashboard state updated.", + "刷新运行时快照,保持控制中心数据更新。", + ); + } + return pickUiText(language, "Run scheduled system checks.", "执行系统定时检查。"); +} + +function cronPayloadPurpose(payload: Record | undefined, language: UiLanguage): string { + if (!payload) return pickUiText(language, "No purpose description.", "未提供任务目的。"); + const kind = typeof payload.kind === "string" ? payload.kind.trim() : ""; + if (kind === "agentTurn" && typeof payload.message === "string" && payload.message.trim()) { + return sanitizeCronPurposeText(payload.message, language); + } + if (kind === "command") { + const command = typeof payload.command === "string" ? payload.command.trim() : ""; + if (command) { + return summarizeCronCommandPurpose(command, language); + } + } + if (typeof payload.message === "string" && payload.message.trim()) { + return sanitizeCronPurposeText(payload.message, language); + } + return pickUiText(language, "No purpose description.", "未提供任务目的。"); +} + +function cronPayloadOwner(payload: Record | undefined, language: UiLanguage): string { + if (!payload) return pickUiText(language, "Scheduler", "调度器"); + const ownerAgentId = cronPayloadOwnerAgentId(payload); + if (ownerAgentId) return humanizeOperatorLabel(ownerAgentId); + const sessionOwner = parseSessionTargetOwner(typeof payload.sessionTarget === "string" ? payload.sessionTarget : undefined); + if (sessionOwner) return humanizeOperatorLabel(sessionOwner); + return pickUiText(language, "Scheduler", "调度器"); +} + +function cronPayloadOwnerAgentId(payload: Record | undefined): string | undefined { + if (!payload) return undefined; + if (typeof payload.agentId === "string" && payload.agentId.trim()) { + return payload.agentId.trim(); + } + return parseSessionTargetOwner(typeof payload.sessionTarget === "string" ? payload.sessionTarget : undefined); +} + +function cronScheduleLabel(schedule: Record | undefined, language: UiLanguage): string { + if (!schedule) return pickUiText(language, "Not scheduled", "未配置"); + const kind = typeof schedule.kind === "string" ? schedule.kind.trim().toLowerCase() : ""; + if (kind === "cron") { + const expr = typeof schedule.expr === "string" ? schedule.expr.trim() : ""; + return expr ? `cron ${expr}` : "cron"; + } + if (kind === "interval") { + const everyMs = typeof schedule.everyMs === "number" && Number.isFinite(schedule.everyMs) + ? Math.max(0, Math.round(schedule.everyMs)) + : undefined; + if (everyMs && everyMs > 0) { + const seconds = Math.round(everyMs / 1000); + return pickUiText(language, `every ${seconds}s`, `每 ${seconds} 秒`); + } + return pickUiText(language, "interval", "间隔"); + } + if (kind === "every") { + const everyMs = typeof schedule.everyMs === "number" && Number.isFinite(schedule.everyMs) + ? Math.max(0, Math.round(schedule.everyMs)) + : undefined; + if (everyMs && everyMs > 0) { + const seconds = Math.round(everyMs / 1000); + return pickUiText(language, `every ${seconds}s`, `每 ${seconds} 秒`); + } + return pickUiText(language, "every", "每次"); + } + return kind ? kind : pickUiText(language, "Not scheduled", "未配置"); +} + +function displayCronScheduleLabel(scheduleLabel: string, language: UiLanguage): string { + const normalized = scheduleLabel.trim().toLowerCase(); + if (!normalized || normalized === "-") return pickUiText(language, "Not scheduled", "未排程"); + if (normalized.startsWith("cron ")) return pickUiText(language, "Fixed schedule", "固定时间表"); + if (normalized.startsWith("every") || normalized.startsWith("每 ")) return scheduleLabel; + if (normalized === "system interval") return pickUiText(language, "System interval", "系统间隔"); + return safeTruncate(scheduleLabel, 18); +} + +function summarizeNames(items: string[], language: UiLanguage, emptyLabel: string): string { + const uniq = [...new Set(items.map((item) => item.trim()).filter((item) => item.length > 0))]; + if (uniq.length === 0) return emptyLabel; + return uniq.join("、"); +} + +function cronHealthLabel(health: string, language: UiLanguage): string { + const normalized = health.trim().toLowerCase(); + if (normalized === "scheduled") return pickUiText(language, "Scheduled", "已排程"); + if (normalized === "due") return pickUiText(language, "Due", "到点待执行"); + if (normalized === "late") return pickUiText(language, "Late", "执行延迟"); + if (normalized === "disabled") return pickUiText(language, "Disabled", "未启用"); + if (normalized === "enabled") return pickUiText(language, "Enabled", "已启用"); + return pickUiText(language, "Unknown", "未知"); +} + +function heartbeatModeLabel(mode: string, language: UiLanguage): string { + const normalized = mode.trim().toLowerCase(); + if (normalized === "dry_run" || normalized === "dry-run") return pickUiText(language, "Dry run", "演练"); + if (normalized === "live" || normalized === "execute") return pickUiText(language, "Live", "执行"); + return mode; +} + +function sessionStateLabel(state: AgentRunState): string { + if (state === "running") return "执行中"; + if (state === "waiting_approval") return "待审批"; + if (state === "blocked") return "阻塞"; + if (state === "error") return "异常"; + return "待命"; +} + +async function loadOpenclawCronCatalog(language: UiLanguage): Promise { + for (const candidate of [...new Set(OPENCLAW_CRON_JOBS_CANDIDATES)]) { + try { + const raw = JSON.parse(await readFile(candidate, "utf8")) as unknown; + const root = asObject(raw); + const jobsRaw = root && Array.isArray(root.jobs) ? root.jobs : []; + const jobs: OpenclawCronJobSummary[] = []; + for (const item of jobsRaw) { + const obj = asObject(item); + if (!obj) continue; + const jobId = typeof obj.id === "string" ? obj.id.trim() : ""; + if (!jobId) continue; + const name = typeof obj.name === "string" && obj.name.trim() ? obj.name.trim() : jobId; + const payload = asObject(obj.payload); + const schedule = asObject(obj.schedule); + jobs.push({ + jobId, + name, + enabled: obj.enabled !== false, + owner: cronPayloadOwner(payload, language), + ownerAgentId: cronPayloadOwnerAgentId(payload), + purpose: cronPayloadPurpose(payload, language), + scheduleLabel: cronScheduleLabel(schedule, language), + sourcePath: candidate, + }); + } + jobs.sort((a, b) => { + if (a.enabled !== b.enabled) return a.enabled ? -1 : 1; + return a.name.localeCompare(b.name); + }); + return jobs; + } catch { + continue; + } + } + return []; +} + +async function countRecentToolCalls(snapshot: ReadModelSnapshot, toolClient: ToolClient): Promise { + if (!Array.isArray(snapshot.sessions) || snapshot.sessions.length === 0) return 0; + const recentSessions = await listSessionConversations({ + snapshot, + client: toolClient, + filters: {}, + page: 1, + pageSize: 20, + historyLimit: 6, + }); + return recentSessions.items.reduce((sum, item) => { + if (typeof item.toolEventCount === "number") return sum + item.toolEventCount; + return sum + (item.latestKind === "tool_event" ? 1 : 0); + }, 0); +} + +async function buildGlobalVisibilityViewModel( + snapshot: ReadModelSnapshot, + toolClient: ToolClient, + language: UiLanguage, + input: { + cronOverview?: Awaited>; + openclawCronJobs?: OpenclawCronJobSummary[]; + currentTasksCount?: number; + strongTaskEvidenceCount?: number; + followupTaskEvidenceCount?: number; + weakTaskEvidenceCount?: number; + toolCallsCount?: number; + } = {}, +): Promise { + const cronOverview = input.cronOverview ?? (await buildCronOverview(snapshot, POLLING_INTERVALS_MS.cron)); + const openclawCronJobs = input.openclawCronJobs ?? (await loadOpenclawCronCatalog(language)); + const inProgressCount = snapshot.tasksSummary.inProgress ?? 0; + const blockedCount = snapshot.tasksSummary.blocked ?? 0; + const strongTaskEvidenceCount = + typeof input.strongTaskEvidenceCount === "number" ? input.strongTaskEvidenceCount : Math.max(0, inProgressCount - blockedCount); + const followupTaskEvidenceCount = typeof input.followupTaskEvidenceCount === "number" ? input.followupTaskEvidenceCount : 0; + const weakTaskEvidenceCount = typeof input.weakTaskEvidenceCount === "number" ? input.weakTaskEvidenceCount : blockedCount; + const currentTasksCount = + input.currentTasksCount ?? Math.max(inProgressCount + blockedCount, strongTaskEvidenceCount + followupTaskEvidenceCount + weakTaskEvidenceCount); + const hasWeakEvidence = weakTaskEvidenceCount > 0; + const toolCallsCount = input.toolCallsCount ?? (await countRecentToolCalls(snapshot, toolClient)); + const nonHeartbeatRuntimeCronJobs = cronOverview.jobs.filter((job) => !job.jobId.toLowerCase().includes("heartbeat")); + const heartbeatJobs = cronOverview.jobs.filter((job) => job.jobId.toLowerCase().includes("heartbeat")); + const enabledRuntimeCronJobs = nonHeartbeatRuntimeCronJobs.filter((job) => job.enabled); + const enabledOpenclawCronJobs = openclawCronJobs.filter((job) => job.enabled); + const enabledCronCount = new Set([ + ...enabledRuntimeCronJobs.map((job) => job.jobId), + ...enabledOpenclawCronJobs.map((job) => job.jobId), + ]).size; + const enabledHeartbeatCount = heartbeatJobs.filter((job) => job.enabled).length; + const heartbeatEnabled = heartbeatJobs.some((job) => job.enabled); + const latestHeartbeatRun = (await readTaskHeartbeatRuns(1)).runs[0]; + const cronTaskName = + enabledCronCount > 0 + ? pickUiText(language, `${enabledCronCount} jobs enabled`, `已启用 ${enabledCronCount} 个任务`) + : pickUiText(language, "No timed jobs", "暂无定时任务"); + const cronOwner = + enabledOpenclawCronJobs.length > 0 + ? summarizeNames( + enabledOpenclawCronJobs.map((job) => job.owner), + language, + pickUiText(language, "Scheduler", "调度器"), + ) + : formatExecutorAgentLabel("system-cron", language); + const cronPurpose = + (enabledOpenclawCronJobs[0]?.purpose ? sanitizeCronPurposeText(enabledOpenclawCronJobs[0]?.purpose, language, 56) : "") || + (enabledRuntimeCronJobs[0] ? cronRuntimePurpose(enabledRuntimeCronJobs[0].jobId, language) : pickUiText(language, "No timed job is running.", "当前没有定时任务在运行。")); + const cronNextRun = + nonHeartbeatRuntimeCronJobs.find((job) => job.enabled)?.nextRunAt ?? + cronOverview.nextRunAt ?? + pickUiText(language, "Not scheduled", "未排程"); + const heartbeatNextRun = + heartbeatJobs.find((job) => job.enabled)?.nextRunAt ?? + heartbeatJobs[0]?.nextRunAt ?? + pickUiText(language, "Not scheduled", "未排程"); + const heartbeatTaskName = pickUiText(language, "Task heartbeat service", "任务心跳服务"); + const heartbeatLatestResult = heartbeatEnabled + ? latestHeartbeatRun + ? pickUiText( + language, + `Last heartbeat: selected ${latestHeartbeatRun.selected} tasks, started ${latestHeartbeatRun.executed}.`, + `最近心跳:挑出 ${latestHeartbeatRun.selected} 个任务,启动 ${latestHeartbeatRun.executed} 个。`, + ) + : pickUiText( + language, + `Active heartbeat checks: ${enabledHeartbeatCount}.`, + `已开启任务心跳:${enabledHeartbeatCount} 个。`, + ) + : pickUiText(language, "No heartbeat check yet.", "还没有任务心跳记录。"); + const heartbeatPurpose = pickUiText( + language, + "Check assigned tasks and start the picked ones.", + "检查已分配任务,并启动挑中的任务。", + ); + const scheduleReady = enabledCronCount > 0; + + const rows: GlobalVisibilityTaskRow[] = [ + { + taskType: "cron", + taskTypeLabel: pickUiText(language, "Timed jobs", "定时任务"), + taskName: cronTaskName, + executor: cronOwner, + currentAction: scheduleReady + ? pickUiText(language, `Now running: ${cronPurpose}`, `正在执行:${cronPurpose}`) + : pickUiText(language, "Timed jobs are off.", "还没有设置定时任务。"), + nextRun: cronNextRun, + latestResult: scheduleReady + ? pickUiText( + language, + `Active timed jobs: ${enabledCronCount}.`, + `已开启定时任务:${enabledCronCount} 个。`, + ) + : pickUiText(language, "No timed job yet.", "还没有定时任务记录。"), + status: scheduleReady ? "done" : "not_done", + nextAction: scheduleReady + ? pickUiText(language, "Keep timed jobs on and keep each job goal clear.", "保持定时任务开启,并确认每个任务目标清楚。") + : pickUiText(language, "Turn on one timed job.", "先添加一个定时任务。"), + detailsHref: buildGlobalVisibilityDetailHref("cron", language), + detailsLabel: pickUiText(language, "See timed jobs", "查看定时任务"), + }, + { + taskType: "heartbeat", + taskTypeLabel: pickUiText(language, "Heartbeat", "任务心跳"), + taskName: heartbeatTaskName, + executor: formatExecutorAgentLabel("task-heartbeat-worker", language), + currentAction: heartbeatEnabled + ? pickUiText(language, `Heartbeat is on: ${heartbeatPurpose}`, `任务心跳已开启:${heartbeatPurpose}`) + : pickUiText(language, "Heartbeat is off.", "还没有设置任务心跳。"), + nextRun: heartbeatNextRun, + latestResult: heartbeatLatestResult, + status: heartbeatEnabled ? "done" : "not_done", + nextAction: heartbeatEnabled + ? pickUiText(language, "Check picked tasks and confirm the choices look right.", "查看挑出的任务,确认挑选结果是否合理。") + : pickUiText(language, "Turn on heartbeat.", "在定时任务里开启心跳。"), + detailsHref: buildGlobalVisibilityDetailHref("heartbeat", language), + detailsLabel: pickUiText(language, "See heartbeat checks", "查看任务心跳"), + }, + { + taskType: "current_task", + taskTypeLabel: pickUiText(language, "Current tasks", "当前任务"), + taskName: pickUiText(language, "Current tasks", "当前任务"), + executor: pickUiText(language, "Task owners", "任务智能体"), + currentAction: + currentTasksCount > 0 + ? hasWeakEvidence + ? pickUiText(language, "Some current tasks still need follow-up.", "有些当前任务还需要继续跟进。") + : pickUiText(language, "Current tasks are visible in runtime.", "当前任务已经能在运行时里看见。") + : pickUiText(language, "No current task signal is visible now.", "当前还没有看见任务执行信号。"), + nextRun: pickUiText(language, "Live update", "实时更新"), + latestResult: + currentTasksCount > 0 + ? hasWeakEvidence + ? pickUiText( + language, + `${strongTaskEvidenceCount} confirmed live, ${followupTaskEvidenceCount} need follow-up, ${weakTaskEvidenceCount} need inspection.`, + `${strongTaskEvidenceCount} 个已确认在跑,${followupTaskEvidenceCount} 个需跟进,${weakTaskEvidenceCount} 个需排查。`, + ) + : pickUiText(language, `${currentTasksCount} current tasks are backed by runtime signals.`, `${currentTasksCount} 个当前任务已有运行信号支撑。`) + : pickUiText(language, "No current task signal yet.", "当前还没有任务执行信号。"), + status: currentTasksCount > 0 && !hasWeakEvidence ? "done" : "not_done", + nextAction: + currentTasksCount > 0 + ? hasWeakEvidence + ? pickUiText(language, "Open current tasks and inspect the follow-up items first.", "打开当前任务,先检查需要跟进的项。") + : pickUiText(language, "Keep following the runtime signals.", "继续盯住运行时信号即可。") + : pickUiText(language, "Start one task and let runtime evidence appear first.", "先启动一个任务,让运行证据出现。"), + detailsHref: buildGlobalVisibilityDetailHref("current_task", language), + detailsLabel: pickUiText(language, "See current tasks", "查看当前任务"), + }, + { + taskType: "tool_call", + taskTypeLabel: pickUiText(language, "Tool calls", "工具调用"), + taskName: pickUiText(language, "Tool calls", "工具调用"), + executor: pickUiText(language, "Active sessions", "活跃会话"), + currentAction: + toolCallsCount > 0 + ? pickUiText(language, "Tools were used recently.", "最近有工具在使用。") + : pickUiText(language, "No tool use yet.", "最近没有工具在使用。"), + nextRun: pickUiText(language, "Live update", "实时更新"), + latestResult: + toolCallsCount > 0 + ? pickUiText(language, `Tool calls in recent activity: ${toolCallsCount}.`, `最近工具调用:${toolCallsCount} 次。`) + : pickUiText(language, "No tool calls yet.", "尚无工具调用记录。"), + status: toolCallsCount > 0 ? "done" : "not_done", + nextAction: + toolCallsCount > 0 + ? pickUiText(language, "Review results and keep going.", "看下结果后继续。") + : pickUiText(language, "Run one small tool step.", "先跑一次小工具步骤。"), + detailsHref: buildGlobalVisibilityDetailHref("tool_call", language), + detailsLabel: pickUiText(language, "See tool calls", "查看工具调用"), + }, + ]; + + const doneCount = rows.filter((row) => row.status === "done").length; + return { + tasks: rows, + doneCount, + notDoneCount: rows.length - doneCount, + noTaskMessage: pickUiText( + language, + "No timed jobs, heartbeat, current tasks, or tool calls yet.", + "暂无定时任务、任务心跳、当前任务或工具调用。", + ), + signalCounts: { + schedule: enabledCronCount, + heartbeat: enabledHeartbeatCount, + currentTasks: currentTasksCount, + toolCalls: toolCallsCount, + }, + }; +} + +function dashboardSectionLinks(language: UiLanguage): DashboardSectionLink[] { + return DASHBOARD_SECTION_LINKS_EN.map((item) => { + if (language !== "zh") return item; + + if (item.key === "overview") { + return { ...item, label: "总览", blurb: "今天重点" }; + } + if (item.key === "team") { + return { ...item, label: "员工", blurb: "员工、分工与职责" }; + } + if (item.key === "memory") { + return { ...item, label: "记忆", blurb: "每日与长期记忆" }; + } + if (item.key === "docs") { + return { ...item, label: "文档", blurb: "Main 与当前启用智能体核心文档" }; + } + if (item.key === "usage-cost") { + return { ...item, label: "用量", blurb: "预算与额度" }; + } + if (item.key === "projects-tasks") { + return { ...item, label: "任务", blurb: "任务、排程与活动" }; + } + return { ...item, label: "设置", blurb: "安全与数据连接" }; + }); +} + +function resolveGlobalVisibilitySignalStatus( + model: GlobalVisibilityViewModel, + taskType: GlobalVisibilityTaskRow["taskType"], +): GlobalVisibilityTaskStatus { + const rows = model.tasks.filter((row) => row.taskType === taskType); + if (rows.length === 0) return "not_done"; + return rows.some((row) => row.status === "not_done") ? "not_done" : "done"; +} + +function renderGlobalVisibilityStrip(model: GlobalVisibilityViewModel, language: UiLanguage): string { + const copy = globalVisibilityCopy(language); + const scheduleRow = model.tasks.find((row) => row.taskType === "cron"); + const heartbeatRow = model.tasks.find((row) => row.taskType === "heartbeat"); + const currentTasksRow = model.tasks.find((row) => row.taskType === "current_task"); + const toolCallsRow = model.tasks.find((row) => row.taskType === "tool_call"); + const scheduleHref = scheduleRow?.detailsHref ?? buildGlobalVisibilityDetailHref("cron", language); + const heartbeatHref = heartbeatRow?.detailsHref ?? buildGlobalVisibilityDetailHref("heartbeat", language); + const currentTasksHref = currentTasksRow?.detailsHref ?? buildGlobalVisibilityDetailHref("current_task", language); + const toolCallsHref = toolCallsRow?.detailsHref ?? buildGlobalVisibilityDetailHref("tool_call", language); + const noSignalText = pickUiText(language, "No update yet.", "暂无更新。"); + const scheduleSignalText = scheduleRow?.currentAction ?? noSignalText; + const heartbeatSignalText = heartbeatRow?.currentAction ?? noSignalText; + const currentTasksSignalText = currentTasksRow?.currentAction ?? noSignalText; + const toolCallsSignalText = toolCallsRow?.currentAction ?? noSignalText; + const scheduleStatus = resolveGlobalVisibilitySignalStatus(model, "cron"); + const heartbeatStatus = resolveGlobalVisibilitySignalStatus(model, "heartbeat"); + const currentTasksStatus = resolveGlobalVisibilitySignalStatus(model, "current_task"); + const toolCallsStatus = resolveGlobalVisibilitySignalStatus(model, "tool_call"); + const doneStatusLabel = copy.doneStatusText; + const notDoneStatusLabel = copy.notDoneStatusText; + const signalTotal = + model.signalCounts.schedule + + model.signalCounts.heartbeat + + model.signalCounts.currentTasks + + model.signalCounts.toolCalls; + const scheduleSignalSmall = `${escapeHtml(scheduleSignalText)}`; + const gaugeTone = (status: GlobalVisibilityTaskStatus): string => + status === "done" ? "var(--ok)" : "var(--warn)"; + const gaugePct = (count: number, status: GlobalVisibilityTaskStatus): number => { + if (signalTotal <= 0) return status === "done" ? 32 : 14; + const raw = Math.round((count / signalTotal) * 100); + return status === "done" ? Math.max(34, raw) : Math.max(14, raw); + }; + const renderSignalCard = (input: { + label: string; + value: number; + status: GlobalVisibilityTaskStatus; + statusLabel: string; + signalText: string; + signalSmallHtml?: string; + href: string; + linkLabel: string; + }): string => { + const pct = gaugePct(input.value, input.status); + return `
+
${input.label}${badge(input.status, input.statusLabel)}
+
+
+
${input.value}
+
+
+ ${input.signalSmallHtml ?? `${escapeHtml(input.signalText)}`} + ${input.linkLabel} +
+
+
`; + }; + return `
+ ${renderSignalCard({ + label: copy.scheduleLabel, + value: model.signalCounts.schedule, + status: scheduleStatus, + statusLabel: scheduleStatus === "done" ? doneStatusLabel : notDoneStatusLabel, + signalText: scheduleSignalText, + signalSmallHtml: scheduleSignalSmall, + href: scheduleHref, + linkLabel: copy.scheduleLinkLabel, + })} + ${renderSignalCard({ + label: copy.heartbeatLabel, + value: model.signalCounts.heartbeat, + status: heartbeatStatus, + statusLabel: heartbeatStatus === "done" ? doneStatusLabel : notDoneStatusLabel, + signalText: heartbeatSignalText, + href: heartbeatHref, + linkLabel: copy.heartbeatLinkLabel, + })} + ${renderSignalCard({ + label: copy.currentTasksLabel, + value: model.signalCounts.currentTasks, + status: currentTasksStatus, + statusLabel: currentTasksStatus === "done" ? doneStatusLabel : notDoneStatusLabel, + signalText: currentTasksSignalText, + href: currentTasksHref, + linkLabel: copy.currentTasksLinkLabel, + })} + ${renderSignalCard({ + label: copy.toolCallsLabel, + value: model.signalCounts.toolCalls, + status: toolCallsStatus, + statusLabel: toolCallsStatus === "done" ? doneStatusLabel : notDoneStatusLabel, + signalText: toolCallsSignalText, + href: toolCallsHref, + linkLabel: copy.toolCallsLinkLabel, + })} +
+ ${copy.doneLabel} + ${model.doneCount} +
+
+
+ ${copy.notDoneLabel} + ${model.notDoneCount} +
+
+
`; +} + +function renderGlobalVisibilityCard(model: GlobalVisibilityViewModel, language: UiLanguage): string { + const copy = globalVisibilityCopy(language); + if (model.tasks.length === 0) { + return `
+ ${copy.title} +
+
${copy.summary}
+ ${renderGlobalVisibilityStrip(model, language)} +
${escapeHtml(model.noTaskMessage)}
+
+
`; + } + + const rows = model.tasks + .map((row) => { + const statusLabel = row.status === "done" ? copy.doneStatusText : copy.notDoneStatusText; + return ` + ${escapeHtml(row.taskTypeLabel)} + ${escapeHtml(row.taskName)} + ${escapeHtml(row.executor)} + ${escapeHtml(row.currentAction)} + ${escapeHtml(row.nextRun)} + ${escapeHtml(row.latestResult)} + ${badge(row.status, statusLabel)} + ${escapeHtml(row.nextAction)} + ${escapeHtml(row.detailsLabel)} + `; + }) + .join(""); + + return `
+ ${copy.title} +
+
${copy.summary}
+ ${renderGlobalVisibilityStrip(model, language)} +
+ ${copy.detailsLabel}(${model.tasks.length}) + + + + + + + + + + + + + + + ${rows} +
${copy.taskTypeLabel}${copy.taskNameLabel}${copy.executorLabel}${copy.currentActionLabel}${copy.nextRunLabel}${copy.latestResultLabel}${copy.statusLabel}${copy.nextActionLabel}${copy.detailsLabel}
+
+
+
`; +} + +function renderGlobalVisibilityStripCard(model: GlobalVisibilityViewModel, language: UiLanguage): string { + const copy = globalVisibilityCopy(language); + return `
+
+

${copy.title}

+
${copy.summary}
+
+ ${renderGlobalVisibilityStrip(model, language)} +
`; +} + +function scoreCoverageStatus(status: DataCoverageStatus): number { + if (status === "connected") return 100; + if (status === "partial") return 55; + return 0; +} + +function snapshotFreshnessSignal( + generatedAt: string, + language: UiLanguage, +): InformationCertaintySignal { + const ageMs = Math.max(0, Date.now() - toSortableMs(generatedAt)); + const ageLabel = formatTimeAgoFromNow(generatedAt, language); + if (ageMs <= 10 * 60 * 1000) { + return { + key: "freshness", + label: pickUiText(language, "Live picture", "实时画面"), + status: "connected", + detail: pickUiText( + language, + `Updated ${ageLabel}; suitable for deciding what is happening now.`, + `更新于${ageLabel},适合直接判断现在发生了什么。`, + ), + }; + } + if (ageMs <= 30 * 60 * 1000) { + return { + key: "freshness", + label: pickUiText(language, "Live picture", "实时画面"), + status: "partial", + detail: pickUiText( + language, + `Updated ${ageLabel}; still useful, but not precise enough for second-by-second judgement.`, + `更新于${ageLabel},仍然有参考价值,但不适合做秒级判断。`, + ), + }; + } + return { + key: "freshness", + label: pickUiText(language, "Live picture", "实时画面"), + status: "not_connected", + detail: pickUiText( + language, + `Last refresh was ${ageLabel}; treat the current picture as delayed.`, + `最近一次刷新是${ageLabel},当前画面应视为有延迟。`, + ), + }; +} + +function usageCoverageStatus(usage: UsageCostSnapshot): DataCoverageStatus { + if ( + usage.connectors.requestCounts === "connected" && + usage.connectors.providerAttribution !== "not_connected" + ) { + return "connected"; + } + if ( + usage.connectors.requestCounts !== "not_connected" || + usage.connectors.digestHistory !== "not_connected" || + usage.connectors.providerAttribution !== "not_connected" + ) { + return "partial"; + } + return "not_connected"; +} + +function historyCoverageStatus( + replay: Awaited>, +): DataCoverageStatus { + if (replay.timeline.entries.length > 0 && replay.digests.length > 0) return "connected"; + if ( + replay.timeline.entries.length > 0 || + replay.digests.length > 0 || + replay.exportSnapshots.length > 0 || + replay.exportBundles.length > 0 + ) { + return "partial"; + } + return "not_connected"; +} + +function buildInformationCertaintyModel(input: { + snapshot: ReadModelSnapshot; + officeRoster: AgentRosterSnapshot; + officePresence: OfficeSessionPresenceSnapshot; + usageCost: UsageCostSnapshot; + replayPreview: Awaited>; + language: UiLanguage; +}): InformationCertaintyModel { + const { snapshot, officeRoster, officePresence, usageCost, replayPreview, language } = input; + const freshness = snapshotFreshnessSignal(snapshot.generatedAt, language); + const usageStatus = usageCoverageStatus(usageCost); + const historyStatus = historyCoverageStatus(replayPreview); + const signals: InformationCertaintySignal[] = [ + freshness, + { + key: "roster", + label: pickUiText(language, "Staff and owners", "员工与负责人"), + status: officeRoster.status, + detail: + officeRoster.status === "connected" + ? pickUiText(language, "Staff roster and ownership signals are readable.", "员工名单和负责人信号可读。") + : officeRoster.status === "partial" + ? pickUiText(language, "Only part of the staff roster is visible.", "目前只能看到部分员工名单。") + : pickUiText(language, "Staff roster is missing, so ownership may be incomplete.", "员工名单未连上,负责人视图可能不完整。"), + }, + { + key: "live_sessions", + label: pickUiText(language, "Live execution", "实时执行"), + status: officePresence.status, + detail: + officePresence.status === "connected" + ? officePresence.totalActiveSessions > 0 + ? pickUiText( + language, + `${officePresence.totalActiveSessions} live sessions are visible right now.`, + `当前可见 ${officePresence.totalActiveSessions} 个实时执行中的会话。`, + ) + : pickUiText(language, "Live session signal is connected; nothing is actively running right now.", "实时会话信号已连上;当前没有执行中的会话。") + : officePresence.status === "partial" + ? pickUiText(language, "Only part of the live execution signal is visible.", "当前只能看到部分实时执行信号。") + : pickUiText(language, "Only static snapshot data is visible, so current execution may be under-reported.", "当前只能看到静态快照,实时执行可能看不全。"), + }, + { + key: "usage", + label: pickUiText(language, "AI usage and cost", "AI 用量与费用"), + status: usageStatus, + detail: + usageStatus === "connected" + ? pickUiText(language, "Usage and cost data are connected.", "用量和费用数据已连上。") + : usageStatus === "partial" + ? pickUiText(language, "Usage trend is visible, but some cost or provider detail is still incomplete.", "已经能看到用量趋势,但费用或供应商细节还不完整。") + : pickUiText(language, "Usage and cost are still a blind spot.", "用量和费用目前仍是盲区。"), + }, + { + key: "subscription", + label: pickUiText(language, "Subscription room", "订阅额度"), + status: usageCost.subscription.status as DataCoverageStatus, + detail: + usageCost.subscription.status === "connected" + ? pickUiText(language, "Subscription remaining and reset window are visible.", "订阅剩余额度和重置窗口可见。") + : usageCost.subscription.status === "partial" + ? pickUiText(language, "Subscription data exists, but part of the billing picture is missing.", "订阅数据已经有了,但账单画面还不完整。") + : pickUiText(language, "Remaining subscription room is not confirmed yet.", "剩余额度目前还不能完全确认。"), + }, + { + key: "history", + label: pickUiText(language, "Replay history", "回放历史"), + status: historyStatus, + detail: + historyStatus === "connected" + ? pickUiText(language, "Recent activity and trend history can both be replayed.", "最近活动和趋势历史都可以回看。") + : historyStatus === "partial" + ? pickUiText(language, "Only part of the replay history is visible.", "目前只能回看部分历史。") + : pickUiText(language, "Replay history is still too thin to explain change over time.", "回放历史还不够厚,难以解释长期变化。"), + }, + ]; + + const weights = new Map([ + ["freshness", 24], + ["roster", 12], + ["live_sessions", 18], + ["usage", 20], + ["subscription", 10], + ["history", 16], + ]); + const totalWeight = [...weights.values()].reduce((sum, value) => sum + value, 0); + const score = Math.round( + signals.reduce((sum, signal) => sum + scoreCoverageStatus(signal.status) * (weights.get(signal.key) ?? 0), 0) / + Math.max(1, totalWeight), + ); + + const strengths = signals + .filter((signal) => signal.status === "connected") + .slice(0, 3) + .map((signal) => { + if (signal.key === "freshness") { + return pickUiText(language, "The home picture is fresh enough for current-state decisions.", "首页画面够新,可以直接拿来判断当前状态。"); + } + if (signal.key === "live_sessions") { + return pickUiText(language, "Current execution is visible, not just task records on a board.", "现在能看到真实执行中的会话,而不只是任务板上的记录。"); + } + if (signal.key === "usage") { + return pickUiText(language, "AI usage and spending can be watched before they become a surprise.", "AI 用量和花费可以提前观察,不容易突然失控。"); + } + if (signal.key === "history") { + return pickUiText(language, "You can look back at recent activity instead of relying on memory.", "可以回看最近发生了什么,不必只靠记忆。"); + } + if (signal.key === "subscription") { + return pickUiText(language, "Remaining subscription room is visible.", "订阅剩余额度是可见的。"); + } + return pickUiText(language, "The people-and-ownership view is readable.", "人员和负责关系是可读的。"); + }); + + const gaps = signals + .filter((signal) => signal.status !== "connected") + .slice(0, 3) + .map((signal) => { + if (signal.key === "freshness") { + return pickUiText(language, "This picture is delayed, so fast changes may not be reflected yet.", "当前画面有延迟,快速变化可能还没有反映出来。"); + } + if (signal.key === "live_sessions") { + return pickUiText(language, "You may not be seeing every session that is still running.", "你可能还看不全所有正在执行的会话。"); + } + if (signal.key === "usage") { + return pickUiText(language, "AI spending is only partially visible, so cost judgement is conservative.", "AI 花费目前只能看见一部分,因此费用判断会偏保守。"); + } + if (signal.key === "subscription") { + return pickUiText(language, "Remaining package room is still unconfirmed.", "套餐剩余额度目前还没有被完全确认。"); + } + if (signal.key === "history") { + return pickUiText(language, "History is thin, so long-term explanations may be weak.", "历史记录偏薄,长期变化的解释力会比较弱。"); + } + return pickUiText(language, "Some staff or ownership signals are still missing.", "部分人员或负责关系信号还缺失。"); + }); + + if (strengths.length === 0) { + strengths.push( + pickUiText(language, "At least the current dashboard structure is readable even while signals are still sparse.", "即使信号还稀疏,当前看板结构本身仍然可读。"), + ); + } + if (gaps.length === 0) { + gaps.push( + pickUiText(language, "No obvious blind spot is standing out right now.", "当前没有明显突出的盲区。"), + ); + } + + if (score >= 80) { + return { + score, + badgeStatus: "ok", + badgeLabel: pickUiText(language, "High certainty", "高确定性"), + headline: pickUiText(language, "This picture is trustworthy enough for day-to-day decisions.", "这张画面已经足够支撑日常判断。"), + summary: pickUiText(language, "Most key signals are connected, so you can judge OpenClaw from one screen with relatively high confidence.", "大部分关键信号都已连上,可以比较放心地用这一屏判断 OpenClaw 的当前状态。"), + strengths, + gaps, + signals, + }; + } + if (score >= 55) { + return { + score, + badgeStatus: "warn", + badgeLabel: pickUiText(language, "Medium certainty", "中等确定性"), + headline: pickUiText(language, "The main picture is visible, but there are still blind spots.", "主画面已经能看,但仍然有盲区。"), + summary: pickUiText(language, "You can judge the main direction, but some parts still need more evidence before you fully trust them.", "大方向已经能判断,但其中有些区域还需要更多证据才能完全放心。"), + strengths, + gaps, + signals, + }; + } + return { + score, + badgeStatus: "blocked", + badgeLabel: pickUiText(language, "Low certainty", "低确定性"), + headline: pickUiText(language, "Important parts of the picture are still missing.", "这张画面还有关键缺口。"), + summary: pickUiText(language, "The dashboard is usable, but some information should still be treated as a clue rather than a confirmed fact.", "当前看板虽然可用,但其中一部分信息还更像线索,不适合当作已经确认的事实。"), + strengths, + gaps, + signals, + }; +} + +function renderInformationCertaintyCard( + model: InformationCertaintyModel, + language: UiLanguage = "zh", +): string { + const connectedCount = model.signals.filter((signal) => signal.status === "connected").length; + const partialCount = model.signals.filter((signal) => signal.status === "partial").length; + const blindSpotCount = model.signals.filter((signal) => signal.status === "not_connected").length; + return `
+
+
+

${escapeHtml(pickUiText(language, "Information certainty", "信息确定性"))}

+
${escapeHtml(pickUiText(language, "This answers how much of OpenClaw you can confidently see right now.", "这块回答的是:你现在对 OpenClaw 的了解,有多少是可以放心相信的。"))}
+
+
${badge(model.badgeStatus, model.badgeLabel)}
+
+
+
+ ${escapeHtml(pickUiText(language, "Certainty score", "确定性分数"))} + ${model.score} + ${escapeHtml(model.headline)} +
+
+ ${escapeHtml(pickUiText(language, "Reliable areas", "可靠区域"))} + ${connectedCount} + ${escapeHtml(pickUiText(language, "Areas already backed by connected signals", "已经有完整信号支撑的区域"))} +
+
+ ${escapeHtml(pickUiText(language, "Blind spots", "盲区"))} + ${blindSpotCount} + ${escapeHtml(pickUiText(language, "Areas that still need more evidence", "仍然需要补证据的区域"))} +
+
+
${escapeHtml(model.summary)}
+
+
+
+

${escapeHtml(pickUiText(language, "What you can trust now", "目前可以放心看的"))}

+
    ${model.strengths.map((item) => `
  • ${escapeHtml(item)}
  • `).join("")}
+
+
+

${escapeHtml(pickUiText(language, "What may still be incomplete", "可能还不完整的地方"))}

+
    ${model.gaps.map((item) => `
  • ${escapeHtml(item)}
  • `).join("")}
+
+
+
+ ${escapeHtml(pickUiText(language, "Open certainty breakdown", "展开确定性拆解"))} · ${connectedCount}/${model.signals.length} ${escapeHtml(pickUiText(language, "connected", "已连上"))} · ${partialCount} ${escapeHtml(pickUiText(language, "partial", "部分"))} · ${blindSpotCount} ${escapeHtml(pickUiText(language, "blind spot", "盲区"))} +
+ + + ${model.signals + .map( + (signal) => + ``, + ) + .join("")} +
${escapeHtml(pickUiText(language, "Area", "区域"))}${escapeHtml(pickUiText(language, "Status", "状态"))}${escapeHtml(pickUiText(language, "What it means", "这意味着什么"))}
${escapeHtml(signal.label)}${badge(signal.status, dataConnectionLabel(signal.status, language))}${escapeHtml(signal.detail)}
+
+
+
`; +} + +function formatTimeAgoFromNow(value: string | undefined, language: UiLanguage = "zh"): string { + const parsed = toSortableMs(value); + if (!parsed) return pickUiText(language, "time unavailable", "时间未知"); + const diffSeconds = Math.max(0, Math.round((Date.now() - parsed) / 1000)); + if (diffSeconds < 60) return pickUiText(language, "just now", "刚刚"); + if (diffSeconds < 3600) { + const minutes = Math.max(1, Math.round(diffSeconds / 60)); + return pickUiText(language, `${minutes}m ago`, `${minutes} 分钟前`); + } + if (diffSeconds < 86400) { + const hours = Math.max(1, Math.round(diffSeconds / 3600)); + return pickUiText(language, `${hours}h ago`, `${hours} 小时前`); + } + const days = Math.max(1, Math.round(diffSeconds / 86400)); + return pickUiText(language, `${days}d ago`, `${days} 天前`); +} + +function pickLatestTimestamp(values: Array): string | undefined { + let latestValue: string | undefined; + let latestMs = 0; + for (const value of values) { + const parsed = toSortableMs(value); + if (parsed > latestMs) { + latestMs = parsed; + latestValue = value; + } + } + return latestValue; +} + +function hasFreshRuntimeTimestamp(value: string | undefined, nowMs: number, windowMs: number): boolean { + const parsed = toSortableMs(value); + return parsed > 0 && nowMs - parsed <= windowMs; +} + +function isStaleRuntimeTimestamp(value: string | undefined, nowMs: number, windowMs: number): boolean { + const parsed = toSortableMs(value); + return parsed > 0 && nowMs - parsed > windowMs; +} + +function countStalledRunningSessions( + sessions: ReadModelSnapshot["sessions"], + sessionItems: SessionConversationListItem[], + nowMs: number, + windowMs = STALLED_RUNNING_SESSION_WINDOW_MS, +): number { + const latestBySessionKey = new Map( + sessionItems.map((item) => [item.sessionKey, item.latestHistoryAt ?? item.lastMessageAt]), + ); + return sessions.filter((session) => { + if (session.state !== "running") return false; + const latestAt = latestBySessionKey.get(session.sessionKey) ?? session.lastMessageAt; + return isStaleRuntimeTimestamp(latestAt, nowMs, windowMs); + }).length; +} + +function buildTaskCertaintyCards(input: { + tasks: TaskListItem[]; + sessions: ReadModelSnapshot["sessions"]; + sessionItems: SessionConversationListItem[]; + approvals: ReadModelSnapshot["approvals"]; + language: UiLanguage; +}): TaskCertaintyCard[] { + const previewByKey = new Map(input.sessionItems.map((item) => [item.sessionKey, item])); + const snapshotByKey = new Map(input.sessions.map((session) => [session.sessionKey, session])); + const pendingApprovalSessionKeys = new Set( + input.approvals + .filter((item) => item.status === "pending" && typeof item.sessionKey === "string" && item.sessionKey.trim()) + .map((item) => item.sessionKey!.trim()), + ); + const nowMs = Date.now(); + + return input.tasks + .filter((task) => task.status !== "done") + .map((task) => { + const linkedSessionKeys = [...new Set(task.sessionKeys.map((item) => item.trim()).filter(Boolean))]; + let visibleSessionCount = 0; + let liveSessionCount = 0; + let blockedSessionCount = 0; + let errorSessionCount = 0; + let waitingApprovalSessionCount = 0; + let recentActivityCount = 0; + let executionEvidenceCount = 0; + let toolEvidenceCount = 0; + const signalTimes: Array = []; + + for (const sessionKey of linkedSessionKeys) { + const preview = previewByKey.get(sessionKey); + const snapshotSession = snapshotByKey.get(sessionKey); + if (preview || snapshotSession) visibleSessionCount += 1; + const state = preview?.state ?? snapshotSession?.state; + if (state === "running") liveSessionCount += 1; + if (state === "blocked") blockedSessionCount += 1; + if (state === "error") errorSessionCount += 1; + if (state === "waiting_approval") waitingApprovalSessionCount += 1; + const latestAt = preview?.latestHistoryAt ?? preview?.lastMessageAt ?? snapshotSession?.lastMessageAt; + signalTimes.push(latestAt); + if (hasFreshRuntimeTimestamp(latestAt, nowMs, TASK_RUNTIME_ACTIVITY_WINDOW_MS)) { + recentActivityCount += 1; + } + if (preview?.executionChain?.accepted || preview?.executionChain?.spawned) executionEvidenceCount += 1; + if ((preview?.toolEventCount ?? 0) > 0 || preview?.latestKind === "tool_event") toolEvidenceCount += 1; + } + + const latestSignalAt = pickLatestTimestamp(signalTimes); + const pendingApprovals = linkedSessionKeys.filter((sessionKey) => pendingApprovalSessionKeys.has(sessionKey)).length; + const staleLinkedSessions = + linkedSessionKeys.length > 0 && visibleSessionCount > 0 && liveSessionCount === 0 && recentActivityCount === 0; + + let score = 24; + if (linkedSessionKeys.length > 0) score += 24; + if (visibleSessionCount > 0) score += 12; + if (liveSessionCount > 0) score += 18; + if (recentActivityCount > 0) score += 16; + if (toolEvidenceCount > 0) score += 8; + if (executionEvidenceCount > 0) score += 10; + if (pendingApprovals > 0) score -= Math.min(18, pendingApprovals * 8); + if (waitingApprovalSessionCount > 0) score -= 14; + if (blockedSessionCount > 0) score -= 24; + if (errorSessionCount > 0) score -= 30; + if (staleLinkedSessions) score -= 12; + score = Math.max(0, Math.min(100, score)); + + const evidence: string[] = []; + const gaps: string[] = []; + + if (linkedSessionKeys.length > 0) { + evidence.push( + pickUiText( + input.language, + `${linkedSessionKeys.length} linked session(s)`, + `已关联 ${linkedSessionKeys.length} 个会话`, + ), + ); + } else { + gaps.push(pickUiText(input.language, "No execution session is linked yet.", "还没有关联执行会话。")); + } + + if (visibleSessionCount > 0) { + evidence.push( + pickUiText( + input.language, + `${visibleSessionCount} linked session(s) are visible in runtime.`, + `运行时里可见 ${visibleSessionCount} 个关联会话。`, + ), + ); + } else if (linkedSessionKeys.length > 0) { + gaps.push( + pickUiText( + input.language, + "Session keys exist, but runtime details are still missing.", + "已经写了会话键,但运行时详情还没出现。", + ), + ); + } + + if (liveSessionCount > 0) { + evidence.push( + pickUiText( + input.language, + `${liveSessionCount} live session(s) are still running.`, + `当前仍有 ${liveSessionCount} 个执行中的会话。`, + ), + ); + } + if (recentActivityCount > 0 && latestSignalAt) { + evidence.push( + pickUiText( + input.language, + `Recent activity was seen ${formatTimeAgoFromNow(latestSignalAt, input.language)}.`, + `最近活动发生在${formatTimeAgoFromNow(latestSignalAt, input.language)}。`, + ), + ); + } else if (linkedSessionKeys.length > 0) { + gaps.push( + pickUiText( + input.language, + "No fresh runtime activity was seen in the last 6 hours.", + "最近 6 小时还没有看到新的运行信号。", + ), + ); + } + + if (toolEvidenceCount > 0) { + evidence.push(pickUiText(input.language, "Tool activity is visible.", "已经看到工具调用痕迹。")); + } + if (executionEvidenceCount > 0) { + evidence.push(pickUiText(input.language, "Accepted/spawned execution evidence is visible.", "已看到接单/派发执行证据。")); + } + if (pendingApprovals > 0) { + gaps.push( + pickUiText( + input.language, + `${pendingApprovals} linked approval item(s) are still waiting.`, + `还有 ${pendingApprovals} 个关联审批在等待处理。`, + ), + ); + } + if (waitingApprovalSessionCount > 0) { + gaps.push(pickUiText(input.language, "A linked session is waiting for approval.", "有会话卡在等待审批。")); + } + if (blockedSessionCount > 0) { + gaps.push(pickUiText(input.language, "A linked session is blocked.", "有会话已经进入阻塞状态。")); + } + if (errorSessionCount > 0) { + gaps.push(pickUiText(input.language, "A linked session is in error state.", "有会话已经进入异常状态。")); + } + + const tone: TaskCertaintyCard["tone"] = + errorSessionCount > 0 + ? "blocked" + : score >= 78 && blockedSessionCount === 0 && waitingApprovalSessionCount === 0 && pendingApprovals === 0 && !staleLinkedSessions + ? "ok" + : score >= 50 + ? "warn" + : "blocked"; + const toneLabel = + tone === "ok" + ? pickUiText(input.language, "Evidence is strong", "证据充分") + : tone === "warn" + ? pickUiText(input.language, "Needs follow-up", "还需跟进") + : pickUiText(input.language, "Evidence is weak", "证据偏弱"); + const summary = + tone === "ok" + ? pickUiText(input.language, "Runtime shows this task is actively being carried.", "运行时已经证明这个任务正在被真正执行。") + : errorSessionCount > 0 + ? pickUiText(input.language, "A linked session is failing, so this task needs intervention.", "关联会话已经报错,这个任务现在需要介入。") + : blockedSessionCount > 0 || waitingApprovalSessionCount > 0 || pendingApprovals > 0 + ? pickUiText(input.language, "Runtime shows the task exists, but it is waiting on a blocker or approval.", "运行时已经看到这个任务,但它现在卡在阻塞或审批上。") + : staleLinkedSessions + ? pickUiText(input.language, "This task has historical traces, but no fresh runtime signal right now.", "这个任务有历史痕迹,但现在没有新的运行信号。") + : pickUiText(input.language, "Right now there is not enough runtime evidence to say this task is truly moving.", "目前还没有足够的运行证据证明这个任务真的在推进。"); + + return { + taskId: task.taskId, + title: task.title, + projectTitle: task.projectTitle, + owner: task.owner, + score, + tone, + toneLabel, + summary, + evidence: evidence.slice(0, 4), + gaps: gaps.slice(0, 4), + detailHref: buildTaskDetailHref(task.taskId, input.language), + }; + }) + .sort((a, b) => { + const toneRank = taskCertaintyToneRank(a.tone) - taskCertaintyToneRank(b.tone); + if (toneRank !== 0) return toneRank; + if (a.score !== b.score) return a.score - b.score; + return a.taskId.localeCompare(b.taskId); + }); +} + +function taskCertaintyToneRank(tone: TaskCertaintyCard["tone"]): number { + if (tone === "blocked") return 0; + if (tone === "warn") return 1; + return 2; +} + +function renderTaskCertaintySection( + cards: TaskCertaintyCard[], + language: UiLanguage = "zh", +): string { + if (cards.length === 0) { + return `
+

${escapeHtml(pickUiText(language, "Execution certainty", "执行确定性"))}

+
${escapeHtml(pickUiText(language, "This answers whether OpenClaw is really carrying a task, not just whether the task exists on the board.", "这块回答的不是任务有没有写在看板上,而是 OpenClaw 是否真的把它接住并推进了。"))}
+
${escapeHtml(pickUiText(language, "There is no in-flight task under the current filter.", "当前筛选下没有需要判断执行确定性的进行中任务。"))}
+
`; + } + + const strongCount = cards.filter((item) => item.tone === "ok").length; + const followupCount = cards.filter((item) => item.tone === "warn").length; + const weakCount = cards.filter((item) => item.tone === "blocked").length; + return `
+
+
+

${escapeHtml(pickUiText(language, "Execution certainty", "执行确定性"))}

+
${escapeHtml(pickUiText(language, "This answers whether OpenClaw is really carrying a task, not just whether the task exists on the board.", "这块回答的不是任务有没有写在看板上,而是 OpenClaw 是否真的把它接住并推进了。"))}
+
+
${badge(weakCount > 0 ? "warn" : "ok", weakCount > 0 ? pickUiText(language, "Needs follow-up", "需要跟进") : pickUiText(language, "Clear enough", "比较清楚"))}
+
+
+
+ ${escapeHtml(pickUiText(language, "Evidence is strong", "证据充分"))} + ${strongCount} + ${escapeHtml(pickUiText(language, "Tasks already backed by live evidence", "已经有实时证据支撑的任务"))} +
+
+ ${escapeHtml(pickUiText(language, "Needs follow-up", "还需跟进"))} + ${followupCount} + ${escapeHtml(pickUiText(language, "Tasks that are visible but still need one more proof point", "已经能看见,但还缺一块证据的任务"))} +
+
+ ${escapeHtml(pickUiText(language, "Evidence is weak", "证据偏弱"))} + ${weakCount} + ${escapeHtml(pickUiText(language, "Tasks that still look uncertain", "目前仍然看起来不够确定的任务"))} +
+
+ +
`; +} + +function mergeSessionConversationItems( + primary: SessionConversationListItem[], + secondary: SessionConversationListItem[], +): SessionConversationListItem[] { + const merged = new Map(); + for (const item of [...primary, ...secondary]) { + if (!item.sessionKey.trim() || merged.has(item.sessionKey)) continue; + merged.set(item.sessionKey, item); + } + return [...merged.values()]; +} + +async function loadSessionConversationItemsByKeys( + snapshot: ReadModelSnapshot, + toolClient: ToolClient, + sessionKeys: string[], + historyLimit: number, +): Promise { + const normalizedKeys = [...new Set(sessionKeys.map((item) => item.trim()).filter(Boolean))]; + if (normalizedKeys.length === 0) return []; + + const details = await Promise.all( + normalizedKeys.map(async (sessionKey) => { + const detail = await getSessionConversationDetail({ + snapshot, + client: toolClient, + sessionKey, + historyLimit, + }); + return detail ?? undefined; + }), + ); + + return details + .filter((detail): detail is SessionConversationDetailResult => Boolean(detail)) + .map((detail) => ({ + sessionKey: detail.session.sessionKey, + label: detail.session.label, + agentId: detail.session.agentId, + state: detail.session.state, + lastMessageAt: detail.session.lastMessageAt, + latestSnippet: detail.latestSnippet, + latestRole: detail.latestRole, + latestKind: detail.latestKind, + latestToolName: detail.latestToolName, + latestHistoryAt: detail.latestHistoryAt, + historyCount: detail.historyCount, + toolEventCount: detail.history.filter((item) => item.kind === "tool_event").length, + historyError: detail.historyError, + executionChain: detail.executionChain, + })); +} + +async function loadCachedTaskEvidenceSessions( + snapshot: ReadModelSnapshot, + toolClient: ToolClient, + sessionKeys: string[], + historyLimit = 24, +): Promise { + const normalizedKeys = [...new Set(sessionKeys.map((item) => item.trim()).filter(Boolean))].sort(); + const cacheKey = normalizedKeys.join(","); + const now = Date.now(); + if ( + renderTaskEvidenceCache && + renderTaskEvidenceCache.snapshotAt === snapshot.generatedAt && + renderTaskEvidenceCache.historyLimit === historyLimit && + renderTaskEvidenceCache.sessionKey === cacheKey && + renderTaskEvidenceCache.expiresAt > now + ) { + return renderTaskEvidenceCache.value; + } + + const value = await loadSessionConversationItemsByKeys(snapshot, toolClient, normalizedKeys, historyLimit); + renderTaskEvidenceCache = { + snapshotAt: snapshot.generatedAt, + historyLimit, + sessionKey: cacheKey, + value, + expiresAt: now + HTML_HEAVY_CACHE_TTL_MS, + }; + return value; +} + +async function loadCachedSessionPreview(snapshot: ReadModelSnapshot, toolClient: ToolClient): Promise { + const now = Date.now(); + if ( + renderSessionPreviewCache && + renderSessionPreviewCache.snapshotAt === snapshot.generatedAt && + renderSessionPreviewCache.expiresAt > now + ) { + return renderSessionPreviewCache.value; + } + + const value = await listSessionConversations({ + snapshot, + client: toolClient, + filters: {}, + page: 1, + pageSize: 12, + historyLimit: 10, + }); + renderSessionPreviewCache = { + snapshotAt: snapshot.generatedAt, + value, + expiresAt: now + HTML_HEAVY_CACHE_TTL_MS, + }; + return value; +} + +function buildUsageCostCacheKey(snapshot: ReadModelSnapshot, mode: UsageCostMode): string { + const sessionStamp = snapshot.sessions + .map((item) => [item.sessionKey, item.agentId ?? "", item.state, item.lastMessageAt ?? "", item.label ?? ""].join(":")) + .join("|"); + const statusStamp = snapshot.statuses + .map((item) => + [ + item.sessionKey, + item.model ?? "", + String(item.tokensIn ?? 0), + String(item.tokensOut ?? 0), + String(item.cost ?? 0), + item.updatedAt ?? "", + ].join(":"), + ) + .join("|"); + return `${mode}|${sessionStamp}|${statusStamp}`; +} + +async function loadCachedUsageCost( + snapshot: ReadModelSnapshot, + mode: UsageCostMode, +): Promise { + const snapshotKey = buildUsageCostCacheKey(snapshot, mode); + const now = Date.now(); + const targetCache = mode === "full" ? renderUsageCostFullCache : renderUsageCostSummaryCache; + const targetInFlight = mode === "full" ? renderUsageCostFullInFlight : renderUsageCostSummaryInFlight; + if ( + targetCache && + targetCache.snapshotKey === snapshotKey && + targetCache.expiresAt > now + ) { + return targetCache.value; + } + if (targetInFlight?.snapshotKey === snapshotKey) { + return targetInFlight.value; + } + + const nextValue = buildUsageCostSnapshot(snapshot, mode); + if (mode === "full") { + renderUsageCostFullInFlight = { + snapshotKey, + value: nextValue, + }; + } else { + renderUsageCostSummaryInFlight = { + snapshotKey, + value: nextValue, + }; + } + try { + const value = await nextValue; + const nextCache = { + snapshotKey, + value, + expiresAt: now + HTML_USAGE_CACHE_TTL_MS, + }; + if (mode === "full") { + renderUsageCostFullCache = nextCache; + } else { + renderUsageCostSummaryCache = nextCache; + } + return value; + } finally { + if (mode === "full") { + if (renderUsageCostFullInFlight?.snapshotKey === snapshotKey) { + renderUsageCostFullInFlight = undefined; + } + } else if (renderUsageCostSummaryInFlight?.snapshotKey === snapshotKey) { + renderUsageCostSummaryInFlight = undefined; + } + } +} + +async function loadCachedOfficeSessionPresence(): Promise { + const now = Date.now(); + if (renderOfficePresenceCache && renderOfficePresenceCache.expiresAt > now) { + return renderOfficePresenceCache.value; + } + const value = await loadBestEffortOfficeSessionPresence(); + renderOfficePresenceCache = { + value, + expiresAt: now + HTML_HEAVY_CACHE_TTL_MS, + }; + return value; +} + +async function renderHtml( + filters: TaskQueryFilters, + toolClient: ToolClient, + options: DashboardOptions, +): Promise { + const renderStartedAt = performance.now(); + let renderPhaseAt = renderStartedAt; + const renderPhases: string[] = []; + const markRenderPhase = (label: string): void => { + const now = performance.now(); + renderPhases.push(`${label}=${Math.round(now - renderPhaseAt)}ms`); + renderPhaseAt = now; + }; + const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient); + const t = (en: string, zh: string): string => pickUiText(options.language, en, zh); + const sectionLinks = dashboardSectionLinks(options.language); + const activeSection = + options.section === "office-space" + ? "team" + : options.section === "calendar" + ? "projects-tasks" + : options.section; + const usageCostMode: UsageCostMode = "full"; + const sectionMeta = sectionLinks.find((item) => item.key === activeSection) ?? sectionLinks[0]; + const sectionLeadText = + activeSection === "overview" + ? t( + "Decide from one screen: system health, items needing your intervention, who is active, and AI burn.", + "一个首页只回答四件事:系统是否正常、哪里需要你介入、谁在忙、AI 用量是否异常。", + ) + : activeSection === "projects-tasks" + ? t( + "One task hub for schedule, review queue, runtime evidence, and cron execution.", + "一个任务中枢,把排程、审阅队列、运行证据和 Cron 执行放在同一页。", + ) + : sectionMeta.blurb; + const needsSessionPreview = activeSection === "projects-tasks" || activeSection === "overview"; + const needsTaskEvidence = activeSection === "projects-tasks"; + const needsTeamSnapshot = activeSection === "team"; + const needsMemoryFiles = activeSection === "memory"; + const needsWorkspaceFiles = activeSection === "docs"; + markRenderPhase("snapshot"); + const exceptions = commanderExceptions(snapshot); + const exceptionsFeed = commanderExceptionsFeed(snapshot); + const actionQueue = await readNotificationCenter(snapshot); + const allTasks = listTasks(snapshot.tasks, projectTitleMap(snapshot)); + const controlCenterMappingTasks = allTasks.filter(isControlCenterMappingTask); + const realTasks = allTasks.filter((task) => !isControlCenterMappingTask(task)); + const tasks = applyTaskFilters(realTasks, filters); + const allApprovals = [...(snapshot.approvals ?? [])].sort(compareApprovals); + const topApprovals = allApprovals.slice(0, 5); + const budgets = snapshot.budgetSummary ?? { total: 0, ok: 0, warn: 0, over: 0, evaluations: [] }; + const nonOkBudgets = (budgets.evaluations ?? []) + .filter((item) => item.status === "warn" || item.status === "over") + .slice(0, 8); + const projectOptions = uniqueSorted(snapshot.projects.projects.map((project) => project.projectId)); + const ownerOptions = uniqueSorted(realTasks.map((task) => task.owner)); + const sessionPreview = needsSessionPreview + ? await loadCachedSessionPreview(snapshot, toolClient) + : { + generatedAt: snapshot.generatedAt, + total: 0, + page: 1, + pageSize: 0, + filters: {}, + items: [], + }; + const sessionRows = renderSessionPreviewRows(sessionPreview.items, options.language); + markRenderPhase("session-preview"); + const [cronOverview, openclawCronJobs, replayPreview, usageCost, officeRoster, officePresence] = await Promise.all([ + buildCronOverview(snapshot, POLLING_INTERVALS_MS.cron), + loadOpenclawCronCatalog(options.language), + loadReplayIndex({ + timelineLimit: 20, + digestLimit: 10, + exportLimit: 10, + }), + loadCachedUsageCost(snapshot, usageCostMode), + loadBestEffortAgentRoster(), + loadCachedOfficeSessionPresence(), + ]); + markRenderPhase("shared-data"); + const [teamSnapshot, memoryFiles, memoryFacetOptions, workspaceFiles, workspaceFacetOptions, taskEvidenceItems] = await Promise.all([ + needsTeamSnapshot + ? loadTeamSnapshot(officeRoster) + : Promise.resolve({ + missionStatement: t("No shared mission loaded.", "尚未加载共同目标。"), + members: [], + sourcePath: OPENCLAW_CONFIG_PATH, + detail: t("Loaded on the staff page only.", "仅在员工页加载。"), + }), + needsMemoryFiles ? listEditableFiles("memory") : Promise.resolve([]), + needsMemoryFiles ? listMemoryFacetOptions() : Promise.resolve>([]), + needsWorkspaceFiles ? listEditableFiles("workspace") : Promise.resolve([]), + needsWorkspaceFiles ? listWorkspaceFacetOptions() : Promise.resolve>([]), + needsTaskEvidence + ? loadCachedTaskEvidenceSessions( + snapshot, + toolClient, + tasks.flatMap((task) => task.sessionKeys), + 24, + ) + : Promise.resolve([]), + ]); + markRenderPhase("section-assets"); + const usageToday = usageCost.periods.find((item) => item.key === "today"); + const usage7d = usageCost.periods.find((item) => item.key === "7d"); + const usage30d = usageCost.periods.find((item) => item.key === "30d"); + const officeCards = buildOfficeSpaceCards( + snapshot, + realTasks, + officeRoster.entries.map((entry) => entry.agentId), + officePresence.activeSessionsByAgent, + options.language, + ); + const usageAgentTokensByKey = new Map( + usageCost.breakdown.byAgent.map((item) => [normalizeLookupKey(item.key), item.tokens]), + ); + const executionAgentSummaries = buildExecutionAgentSummaries( + snapshot, + realTasks, + openclawCronJobs, + officeRoster.entries, + usageAgentTokensByKey, + ); + const taskSignalItems = mergeSessionConversationItems(taskEvidenceItems, sessionPreview.items); + const taskExecutionChainCards = buildTaskExecutionChainCards({ + tasks: realTasks, + sessions: snapshot.sessions, + sessionItems: taskSignalItems, + language: options.language, + }); + const taskCertaintyCards = buildTaskCertaintyCards({ + tasks, + sessions: snapshot.sessions, + sessionItems: taskSignalItems, + approvals: snapshot.approvals, + language: options.language, + }); + const taskCertaintyStrongCount = taskCertaintyCards.filter((item) => item.tone === "ok").length; + const taskCertaintyFollowupCount = taskCertaintyCards.filter((item) => item.tone === "warn").length; + const taskCertaintyWeakCount = taskCertaintyCards.filter((item) => item.tone === "blocked").length; + const spawnedExecutionChainCount = taskExecutionChainCards.filter((item) => item.executionChain.spawned).length; + const runningExecutionChainCount = taskExecutionChainCards.filter((item) => item.executionChain.stage === "running").length; + const mappedExecutionChainCount = taskExecutionChainCards.filter((item) => !item.unmapped).length; + const taskExecutionChainHtml = renderTaskExecutionChainCards(taskExecutionChainCards, options.language); + const taskRoleSummaries = buildTaskRoleSummaries(controlCenterMappingTasks); + const pendingApprovalsCount = allApprovals.filter((item) => item.status === "pending").length; + const inProgressTasksCount = realTasks.filter((task) => task.status === "in_progress").length; + const blockedTasksCount = realTasks.filter((task) => task.status === "blocked").length; + const tasksInMotionCount = inProgressTasksCount + blockedTasksCount; + const liveSessionCount = officePresence.totalActiveSessions; + const nowMs = Date.now(); + const sessionErrorCount = exceptions.errors.length; + const sessionBlockedCount = exceptions.blocked.filter((session) => session.state === "blocked").length; + const sessionWaitingApprovalCount = exceptions.blocked.filter( + (session) => session.state === "waiting_approval", + ).length; + const runtimeSessionIssueCount = sessionBlockedCount + sessionErrorCount + sessionWaitingApprovalCount; + const stalledRunningSessionCount = countStalledRunningSessions(snapshot.sessions, taskSignalItems, nowMs); + const runtimeIssueCount = runtimeSessionIssueCount + stalledRunningSessionCount; + const globalVisibilityModel = await buildGlobalVisibilityViewModel(snapshot, toolClient, options.language, { + cronOverview, + openclawCronJobs, + currentTasksCount: taskCertaintyCards.length, + strongTaskEvidenceCount: taskCertaintyStrongCount, + followupTaskEvidenceCount: taskCertaintyFollowupCount, + weakTaskEvidenceCount: taskCertaintyWeakCount, + }); + const attentionCount = actionQueue.counts.unacked + runtimeIssueCount + nonOkBudgets.length; + const replayMoments = replayPreview.timeline.entries.slice(0, 8); + const replaySignals = [ + { label: t("Timeline events", "时间线事件"), value: replayPreview.stats.timeline.total }, + { label: t("Daily digests", "日报快照"), value: replayPreview.stats.digests.total }, + { label: t("Export snapshots", "导出快照"), value: replayPreview.stats.exportSnapshots.total }, + { label: t("Backup bundles", "备份包"), value: replayPreview.stats.exportBundles.total }, + ].filter((item) => item.value > 0); + const heartbeatJobs = cronOverview.jobs.filter((job) => job.jobId.toLowerCase().includes("heartbeat")); + const heartbeatEnabledCount = heartbeatJobs.filter((job) => job.enabled).length; + const heartbeatNextRun = + heartbeatJobs.find((job) => job.enabled)?.nextRunAt ?? heartbeatJobs[0]?.nextRunAt ?? t("Not scheduled", "未排程"); + const heartbeatHealth = heartbeatEnabledCount > 0 ? "ok" : "warn"; + const heartbeatRuns = await readTaskHeartbeatRuns(1); + const latestHeartbeatRun = heartbeatRuns.runs[0]; + const currentTaskHealth = taskCertaintyWeakCount === 0 ? "ok" : "warn"; + const mappingTaskHint = + controlCenterMappingTasks.length > 0 + ? t( + `${controlCenterMappingTasks.length} board-only mapping examples are hidden from execution metrics.`, + `另有 ${controlCenterMappingTasks.length} 个看板样例(不执行任务)。`, + ) + : ""; + const pendingDecisionCount = actionQueue.counts.unacked; + const budgetRiskCount = nonOkBudgets.length; + const focusSummary = [ + `${t("Review queue", "审阅队列")} ${pendingDecisionCount}`, + `${t("Runtime issues", "运行异常")} ${runtimeIssueCount}`, + `${t("Budget risks", "预算风险")} ${budgetRiskCount}`, + ].join(" · "); + const focusHref = `${buildHomeHref({ quick: "all" }, options.compactStatusStrip, "projects-tasks", options.language, options.usageView)}#task-decision-center`; + const currentTaskHealthHref = `${buildHomeHref({ quick: "all" }, true, "projects-tasks", options.language, options.usageView)}#task-lane`; + const runtimeCronById = new Map(cronOverview.jobs.map((job) => [job.jobId, job])); + const catalogMatchedRuntimeIds = new Set(); + const catalogCronRows = openclawCronJobs.map((job) => { + const runtimeJob = runtimeCronById.get(job.jobId); + if (runtimeJob) catalogMatchedRuntimeIds.add(job.jobId); + const status = runtimeJob ? runtimeJob.health : job.enabled ? "enabled" : "disabled"; + const statusLabel = runtimeJob + ? cronHealthLabel(runtimeJob.health, options.language) + : job.enabled + ? pickUiText(options.language, "Enabled (awaiting runtime sync)", "已启用(等待运行时同步)") + : cronHealthLabel("disabled", options.language); + const nextRun = runtimeJob?.nextRunAt ?? (job.enabled ? t("Waiting for runtime sync", "等待运行时同步") : "-"); + return { + source: "openclaw", + sourceLabel: t("Task config", "任务配置"), + jobId: job.jobId, + name: job.name, + owner: job.owner, + purpose: job.purpose, + schedule: job.scheduleLabel, + status, + statusLabel, + nextRun, + dueInSeconds: runtimeJob?.dueInSeconds, + }; + }); + const runtimeOnlyCronRows = cronOverview.jobs + .filter((job) => !catalogMatchedRuntimeIds.has(job.jobId)) + .map((job) => ({ + source: "runtime", + sourceLabel: t("Runtime monitor", "系统监控"), + jobId: job.jobId, + name: job.name ?? job.jobId, + owner: formatExecutorAgentLabel("system-cron", options.language), + purpose: cronRuntimePurpose(job.jobId, options.language), + schedule: pickUiText(options.language, "system interval", "系统间隔"), + status: job.enabled ? job.health : "disabled", + statusLabel: cronHealthLabel(job.enabled ? job.health : "disabled", options.language), + nextRun: job.nextRunAt ?? "-", + dueInSeconds: job.dueInSeconds, + })); + const allCronRows = [...catalogCronRows, ...runtimeOnlyCronRows]; + const cronRows = + allCronRows + .slice(0, 20) + .map((job) => { + const dueIn = Number.isFinite(job.dueInSeconds) ? formatSeconds(job.dueInSeconds, options.language) : "-"; + const purpose = sanitizeCronPurposeText(job.purpose, options.language, 56); + return `
${escapeHtml(job.name)}
${escapeHtml(job.jobId)}
${escapeHtml(job.owner)}${escapeHtml(purpose)}${badge(job.status, job.statusLabel)}${escapeHtml(job.nextRun)}${escapeHtml(dueIn)}`; + }) + .join(""); + const agentJobCatalogRows = allCronRows; + const agentJobRowsHtml = + agentJobCatalogRows.length === 0 + ? `${escapeHtml(t("No visible jobs yet.", "暂无可见 job。"))}` + : agentJobCatalogRows + .slice(0, 40) + .map( + (item) => + `${escapeHtml(item.sourceLabel)}
${escapeHtml(item.name)}
${escapeHtml(item.jobId)}
${escapeHtml(item.owner)}${escapeHtml(sanitizeCronPurposeText(item.purpose, options.language, 48))}${escapeHtml(displayCronScheduleLabel(item.schedule, options.language))}${escapeHtml(item.nextRun)}${badge(item.status, item.statusLabel)}`, + ) + .join(""); + const toolSessions = sessionPreview.items + .filter((item) => (item.toolEventCount ?? 0) > 0 || item.latestKind === "tool_event") + .slice(0, 12); + const toolRows = + toolSessions.length === 0 + ? `${escapeHtml(t("No tool-call sessions yet.", "暂无工具调用会话。"))}` + : toolSessions + .map((item) => { + const toolCount = item.toolEventCount ?? (item.latestKind === "tool_event" ? 1 : 0); + return `${escapeHtml(item.label ?? item.sessionKey)}${escapeHtml(item.agentId ?? t("Unassigned", "未分配"))}${toolCount}${badge(item.state, sessionStateLabel(item.state))}${escapeHtml(item.lastMessageAt ?? "-")}`; + }) + .join(""); + const importGuard = readImportMutationGuardState(); + const tokenGateStatus = LOCAL_TOKEN_AUTH_REQUIRED + ? LOCAL_API_TOKEN !== "" + ? "armed" + : "blocked_no_token" + : "disabled"; + const importGuardRows = [ + { + label: "只读保护", + value: String(READONLY_MODE), + note: READONLY_MODE ? "当前只允许安全演练,不会写入真实变更。" : "允许真实写入,请确认后使用。", + status: READONLY_MODE ? "enabled" : "warn", + }, + { + label: "关键操作身份验证", + value: String(LOCAL_TOKEN_AUTH_REQUIRED), + note: LOCAL_TOKEN_AUTH_REQUIRED ? "已开启,关键操作需要身份验证。" : "未开启,建议在生产环境开启。", + status: LOCAL_TOKEN_AUTH_REQUIRED ? "enabled" : "warn", + }, + { + label: "身份验证配置", + value: String(importGuard.localTokenConfigured), + note: importGuard.localTokenConfigured ? "已配置完成。" : "尚未配置,关键操作将被拦截。", + status: importGuard.localTokenConfigured ? "enabled" : "blocked", + }, + { + label: "身份验证状态", + value: tokenGateStatus === "armed" ? "已就绪" : tokenGateStatus === "blocked_no_token" ? "未配置" : "未开启", + note: "用于保护关键写入操作。", + status: tokenGateStatus === "armed" ? "enabled" : tokenGateStatus === "blocked_no_token" ? "blocked" : "disabled", + }, + { + label: "变更写入开关", + value: String(IMPORT_MUTATION_ENABLED), + note: IMPORT_MUTATION_ENABLED ? "允许写入导入变更。" : "已关闭导入写入。", + status: IMPORT_MUTATION_ENABLED ? "warn" : "disabled", + }, + { + label: "审批写入开关", + value: String(APPROVAL_ACTIONS_ENABLED), + note: APPROVAL_ACTIONS_ENABLED ? "允许执行审批写入。" : "已关闭审批写入。", + status: APPROVAL_ACTIONS_ENABLED ? "warn" : "disabled", + }, + { + label: "默认保护模式", + value: importGuard.defaultMode, + note: + importGuard.defaultMode === "blocked" + ? "当前为保护状态,仅允许演练。" + : importGuard.defaultMode === "dry_run" + ? "默认先演练,再决定是否写入。" + : "当前允许实时写入。", + status: importGuard.defaultMode, + }, + ] + .map( + (item) => + `${escapeHtml(item.label)}${badge(item.status)}${escapeHtml(item.value)}${escapeHtml(item.note)}`, + ) + .join(""); + const replayRowItems = [ + { label: t("Timeline scanned", "时间线扫描数"), value: replayPreview.stats.timeline.total }, + { label: t("Timeline shown", "时间线展示数"), value: replayPreview.stats.timeline.returned }, + { label: t("Timeline filtered", "时间线过滤数"), value: replayPreview.stats.timeline.filteredOut }, + { label: t("Digests shown", "日报快照展示数"), value: replayPreview.stats.digests.returned }, + { label: t("Export snapshots shown", "导出快照展示数"), value: replayPreview.stats.exportSnapshots.returned }, + { label: t("Backup bundles shown", "备份包展示数"), value: replayPreview.stats.exportBundles.returned }, + { label: t("Replay load p50 (ms)", "回放加载 p50 (ms)"), value: replayPreview.stats.total.latencyBucketsMs.p50 }, + { label: t("Replay load p95 (ms)", "回放加载 p95 (ms)"), value: replayPreview.stats.total.latencyBucketsMs.p95 }, + ].filter((item) => item.value > 0); + const replayRows = replayRowItems + .map((item) => `${escapeHtml(item.label)}${item.value}`) + .join(""); + const replayMetricsHtml = + replayRowItems.length === 0 + ? `
${escapeHtml(t("No replay metrics yet. They will appear after the system runs for a while.", "暂无回放统计。运行一段时间后会显示。"))}
` + : `${replayRows}
${escapeHtml(t("Metric", "指标"))}${escapeHtml(t("Value", "数值"))}
`; + const replayLatestSnapshot = replayPreview.exportSnapshots[0]; + const replayLatestBundle = replayPreview.exportBundles[0]; + const approvalsPreviewMeta = + allApprovals.length > topApprovals.length + ? t(`Showing the latest ${topApprovals.length} of ${allApprovals.length} approval items.`, `当前展示最近 ${topApprovals.length}/${allApprovals.length} 条审批记录。`) + : t(`Showing ${topApprovals.length} approval items.`, `当前展示 ${topApprovals.length} 条审批记录。`); + + const approvalsItems = + topApprovals.length === 0 + ? `
  • ${escapeHtml(t("No approvals yet.", "暂无审批记录"))}
  • ` + : topApprovals + .map((approval) => { + const status = approval.status ?? "unknown"; + const target = approval.agentId ?? approval.sessionKey ?? t("Unknown target", "未知目标"); + const commandLabel = approval.command ? escapeHtml(approval.command) : t("Approval action", "审批动作"); + const when = approval.requestedAt ? ` · ${escapeHtml(t("Requested at", "提交于"))} ${escapeHtml(approval.requestedAt)}` : ""; + return `
  • ${badge(status)} ${commandLabel} · ${escapeHtml(target)}${when}
  • `; + }) + .join(""); + + const budgetItems = + nonOkBudgets.length === 0 + ? `${escapeHtml(t("All budgets are currently within the safe range.", "当前预算全部在安全范围内。"))}` + : nonOkBudgets + .map((item) => { + return `${badge(item.status ?? "ok")}${escapeHtml(item.scope ?? t("Unknown scope", "未知范围"))}${escapeHtml(item.label ?? t("Untitled", "未命名"))}${renderMetricSummary(item)}`; + }) + .join(""); + + const taskRows = + tasks.length === 0 + ? `${escapeHtml(t("No tasks match the current filter.", "当前筛选下暂无任务。"))}` + : tasks + .slice(0, 50) + .map( + (task) => + `${escapeHtml(task.projectTitle)}${escapeHtml(task.taskId)}${escapeHtml(task.title)}${badge(task.status, taskStateLabel(task.status, options.language))}${escapeHtml(task.owner)}${escapeHtml(task.dueAt ?? "-")}${escapeHtml(task.updatedAt)}`, + ) + .join(""); + const taskGroupedListHtml = + tasks.length === 0 + ? `
    ${escapeHtml(t("No tasks match the current filter.", "当前筛选下暂无任务。"))}
    ` + : `
    ${TASK_STATES.map((state) => { + const bucket = tasks.filter((task) => task.status === state); + if (bucket.length === 0) return ""; + const itemRows = bucket + .slice(0, 16) + .map((task) => { + const detailHref = buildTaskDetailHref(task.taskId, options.language); + return `
  • +
    + ${escapeHtml(task.title)} + ${badge(task.status, taskStateLabel(task.status, options.language))} +
    +
    ${escapeHtml(task.taskId)} · ${escapeHtml(task.projectTitle)} · ${escapeHtml(t("Owner", "负责人"))} ${escapeHtml(task.owner)}
    +
    ${escapeHtml(t("Due", "截止"))} ${escapeHtml(task.dueAt ?? t("Not set", "未设置"))} · ${escapeHtml(t("Updated", "更新"))} ${escapeHtml(task.updatedAt)}
    + +
  • `; + }) + .join(""); + const more = bucket.length > 16 ? `
    ${escapeHtml(t(`${bucket.length - 16} more tasks are collapsed.`, `其余 ${bucket.length - 16} 个任务已折叠。`))}
    ` : ""; + return `
    ${escapeHtml(taskStateLabel(state, options.language))} (${bucket.length})
      ${itemRows}
    ${more}
    `; + }).join("")}
    `; + const toolGroupedListHtml = + toolSessions.length === 0 + ? `
    ${escapeHtml(t("No tool-call sessions yet.", "暂无工具调用会话。"))}
    ` + : `
    ${escapeHtml(t("Active tool sessions", "活跃工具会话"))} (${toolSessions.length})
      ${toolSessions + .map((item) => { + const toolCount = item.toolEventCount ?? (item.latestKind === "tool_event" ? 1 : 0); + return `
    • +
      ${escapeHtml(item.label ?? item.sessionKey)}${badge(item.state, sessionStateLabel(item.state))}
      +
      ${escapeHtml(t("Agent", "智能体"))} ${escapeHtml(item.agentId ?? t("Unassigned", "未分配"))} · ${escapeHtml(t("Calls", "调用"))} ${toolCount} ${escapeHtml(t("times", "次"))}
      +
      ${escapeHtml(t("Latest activity", "最近活动"))} ${escapeHtml(item.lastMessageAt ?? "-")}
      + +
    • `; + }) + .join("")}
    `; + const heartbeatGroupedListHtml = + heartbeatJobs.length === 0 + ? `
    ${escapeHtml(t("No heartbeat timed jobs found yet.", "尚未发现心跳定时任务。"))}
    ` + : `
    ${escapeHtml(t("Heartbeat checks", "心跳检查项"))} (${heartbeatJobs.length})
      ${heartbeatJobs + .slice(0, 16) + .map((job) => { + const detailHref = buildCronDetailHref(job.jobId, options.language); + const checkLabel = job.jobId.toLowerCase().includes("heartbeat") + ? t("Task heartbeat service", "任务心跳服务") + : job.name?.trim() || job.jobId; + return `
    • +
      ${escapeHtml(checkLabel)}${badge(job.health, cronHealthLabel(job.health, options.language))}
      +
      ${escapeHtml(t("Next run", "下次运行"))} ${escapeHtml(job.nextRunAt ?? "-")} · ${escapeHtml(formatSeconds(job.dueInSeconds, options.language))}
      + +
    • `; + }) + .join("")}
    `; + const agentJobGroupedListHtml = + agentJobCatalogRows.length === 0 + ? `
    ${escapeHtml(t("No visible jobs yet.", "暂无可见 job。"))}
    ` + : `
    ${[...new Set(agentJobCatalogRows.map((item) => item.owner))] + .slice(0, 10) + .map((owner) => { + const jobs = agentJobCatalogRows.filter((item) => item.owner === owner); + const rows = jobs + .slice(0, 10) + .map((item) => { + const detailHref = buildCronDetailHref(item.jobId, options.language); + return `
  • +
    ${escapeHtml(item.name)}${badge(item.status, item.statusLabel)}
    +
    ${escapeHtml(item.jobId)} · ${escapeHtml(displayCronScheduleLabel(item.schedule, options.language))}
    +
    ${escapeHtml(sanitizeCronPurposeText(item.purpose, options.language, 80))}
    + +
  • `; + }) + .join(""); + return `
    ${escapeHtml(owner)} (${jobs.length})
      ${rows}
    `; + }) + .join("")}
    `; + + const exceptionsItems = renderExceptionsList(exceptionsFeed); + const taskBoard = renderTaskBoard(tasks, options.language); + const projectBoard = renderProjectBoard(snapshot.projectSummaries, options.language); + const actionQueueItems = renderActionQueue(actionQueue); + const effectiveQuick = filters.quick ?? "all"; + const quickFilters = renderQuickFilters(filters, options.compactStatusStrip, options.section, options.language, options.usageView); + const clearHref = buildHomeHref({ quick: "all" }, options.compactStatusStrip, options.section, options.language, options.usageView); + const signalItems = [ + { label: t("Active sessions", "活跃会话"), value: liveSessionCount }, + { label: t("Tasks under watch", "正在观察中的任务"), value: taskCertaintyCards.length }, + { label: t("Risk signals", "风险信号"), value: attentionCount }, + { label: t("Active projects", "活跃项目"), value: snapshot.projectSummaries.filter((item) => item.status === "active").length }, + ].filter((item) => item.value > 0); + const subscriptionWindowHint = + usageCost.subscription.primaryWindowLabel || usageCost.subscription.secondaryUsedPercent !== undefined + ? `${normalizeQuotaWindowLabel(usageCost.subscription.primaryWindowLabel, "5h")} / ${normalizeQuotaWindowLabel( + usageCost.subscription.secondaryWindowLabel, + "Week", + )}` + : usageCost.subscription.planLabel; + const executiveCards = [ + { + title: t("Projects", "项目"), + metric: `${snapshot.projectSummaries.length}`, + detail: `${t("Active", "活跃")} ${snapshot.projectSummaries.filter((item) => item.status === "active").length} · ${t("Blocked", "阻塞")} ${snapshot.projectSummaries.filter((item) => item.status === "blocked").length}`, + }, + { + title: t("Tasks", "任务"), + metric: `${realTasks.length}`, + detail: `${t("In motion", "进行中")} ${inProgressTasksCount} · ${t("Blocked", "阻塞")} ${blockedTasksCount}${controlCenterMappingTasks.length > 0 ? ` · ${t("Mapping examples", "映射样例")} ${controlCenterMappingTasks.length}` : ""}`, + }, + { + title: t("Agents", "智能体"), + metric: `${officeCards.filter((card) => card.status !== "inactive").length}`, + detail: `${t("Online agents", "在线智能体")} ${officeCards.filter((card) => card.activeSessions > 0).length}`, + }, + { + title: t("Budget", "预算"), + metric: `${budgets.total}`, + detail: `${t("Warnings", "预警")} ${budgets.warn ?? 0} · ${t("Over limit", "超限")} ${budgets.over ?? 0}`, + }, + { + title: t("Subscription", "订阅"), + metric: usageCost.subscription.status === "connected" ? t("Connected", "已连接") : t("Needs connection", "待连接"), + detail: subscriptionWindowHint, + }, + { + title: t("System health", "系统健康"), + metric: cronOverview.health.status === "ok" ? t("Healthy", "正常") : t("Attention", "关注"), + detail: `${t("Timed jobs", "定时任务")} ${cronOverview.jobs.length} ${t("items", "个")} · ${t("Heartbeats", "心跳")} ${heartbeatEnabledCount} ${t("items", "个")}`, + }, + ]; + const executiveCardsHtml = `
    ${executiveCards + .map( + (item) => + `
    ${escapeHtml(item.title)}
    ${escapeHtml(item.metric)}
    ${escapeHtml(item.detail)}
    `, + ) + .join("")}
    `; + const overviewTopMetrics = [ + { + key: "review-queue", + title: t("Review queue", "审阅队列"), + numericValue: pendingDecisionCount, + displayValue: formatInt(pendingDecisionCount), + detail: pendingDecisionCount > 0 ? t("Waiting for your review", "等你处理") : t("No backlog", "无积压"), + tone: pendingDecisionCount > 0 ? "warn" : "ok", + }, + { + key: "runtime-issues", + title: t("Runtime issues", "运行异常"), + numericValue: runtimeSessionIssueCount, + displayValue: formatInt(runtimeSessionIssueCount), + detail: + runtimeSessionIssueCount > 0 + ? t("Blocked, waiting, or failing sessions", "阻塞、等待或报错中的会话") + : t("Normal", "状态正常"), + tone: runtimeSessionIssueCount > 0 ? "warn" : "ok", + }, + { + key: "stalled-runs", + title: t("Stalled runs", "停滞执行"), + numericValue: stalledRunningSessionCount, + displayValue: formatInt(stalledRunningSessionCount), + detail: + stalledRunningSessionCount > 0 + ? t("Running sessions have gone quiet", "运行中的会话已经沉默") + : t("Fresh", "信号新鲜"), + tone: stalledRunningSessionCount > 0 ? "warn" : "ok", + }, + { + key: "budget-risk", + title: t("Budget risk", "预算风险"), + numericValue: budgetRiskCount, + displayValue: formatInt(budgetRiskCount), + detail: budgetRiskCount > 0 ? t("Budget warning", "预算告警") : t("Budget safe", "预算安全"), + tone: budgetRiskCount > 0 ? "warn" : "ok", + }, + { + key: "today-usage", + title: t("Today's usage", "今日用量"), + numericValue: usageToday?.sourceStatus === "not_connected" ? undefined : usageToday?.tokens ?? 0, + displayValue: usageToday?.sourceStatus === "not_connected" ? t("Not connected", "未连接") : formatInt(usageToday?.tokens ?? 0), + detail: + usageToday?.sourceStatus === "not_connected" + ? t("Not connected", "未连接") + : `${t("Cost", "费用")} ${formatCurrency(usageToday?.estimatedCost ?? 0)}`, + tone: usageToday?.sourceStatus === "not_connected" ? "neutral" : "ok", + }, + ]; + const overviewTopMetricHtml = `
    ${overviewTopMetrics + .map((item) => { + const counterAttrs = + typeof item.numericValue === "number" + ? ` data-counter-key="overview:${escapeHtml(item.key)}" data-counter-target="${Math.max(0, Math.round(item.numericValue))}" data-counter-format="int"` + : ""; + return `
    +
    ${escapeHtml(item.title)}
    +
    ${escapeHtml(item.displayValue)}
    +
    ${escapeHtml(item.detail)}
    +
    `; + }) + .join("")}
    `; + const signalStrip = signalItems + .map((item) => `
    ${escapeHtml(item.label)}${item.value}
    `) + .join(""); + const showSignalsFallback = signalItems.length === 0; + const officeFloorHtml = renderOfficeFloor(officeCards, options.language); + const staffOverviewCards = needsTeamSnapshot + ? await buildStaffOverviewCards({ + snapshot, + client: toolClient, + members: teamSnapshot.members, + officeCards, + executionAgentSummaries, + language: options.language, + }) + : []; + const staffOverviewCardsHtml = renderStaffOverviewCards(staffOverviewCards, options.language); + const subscriptionStatusHtml = renderSubscriptionStatusCard(usageCost.subscription, options.language); + const sectionNav = sectionLinks.map((item) => { + const href = buildHomeHref(filters, options.compactStatusStrip, item.key, options.language, options.usageView); + const activeClass = item.key === activeSection ? " active" : ""; + const current = item.key === activeSection ? ' aria-current="page"' : ""; + return `${escapeHtml(item.label)}${escapeHtml(item.blurb)}`; + }).join(""); + const languageToggle = renderLanguageToggle(filters, options); + const replayMomentsRows = + replayMoments.length === 0 + ? `
  • ${escapeHtml(t("No timeline events yet.", "暂无时间线事件。"))}
  • ` + : replayMoments + .map((item) => `
  • ${escapeHtml(item.timestamp)} ${escapeHtml(item.summary)}
  • `) + .join(""); + const isTodayUsageView = options.usageView === "today"; + const usagePeriodsForView = isTodayUsageView ? usageCost.periods.filter((item) => item.key === "today") : usageCost.periods; + const usagePeriodCards = renderUsagePeriodCards(usagePeriodsForView, options.language); + const usageViewTodayHref = buildHomeHref(filters, options.compactStatusStrip, "usage-cost", options.language, "today"); + const usageViewCumulativeHref = buildHomeHref(filters, options.compactStatusStrip, "usage-cost", options.language, "cumulative"); + const usageViewSwitchHtml = ``; + const usageViewRangeText = isTodayUsageView + ? t("Range: today from 00:00 until now.", "统计范围:今日 00:00 至当前。") + : t("Range: cumulative history until now.", "统计范围:历史累计到当前。"); + const usageViewRangeDetail = isTodayUsageView + ? t("Today view focuses on same-day consumption and live budget pressure.", "今天视图聚焦当日消耗,适合看实时预算压力。") + : t("Cumulative view shows overall composition and long-term trend.", "累计视图用于看整体结构占比和长期趋势。"); + const usageContextRows = renderUsageContextRows(usageCost.contextWindows, options.language); + const selectedUsageBreakdown = isTodayUsageView ? usageCost.breakdownToday : usageCost.breakdown; + const usageAgentRows = renderUsageBreakdownRows(selectedUsageBreakdown.byAgent, "agent", options.language); + const usageProjectRows = renderUsageBreakdownRows(selectedUsageBreakdown.byProject, "project", options.language); + const usageTaskBreakdownRows = selectedUsageBreakdown.byTask.filter( + (item) => !isControlCenterMappingUsageTaskLabel(item.label) && !isControlCenterMappingUsageTaskLabel(item.key), + ); + const usageTaskRows = renderUsageBreakdownRows(usageTaskBreakdownRows, "task", options.language); + const usageModelRows = renderUsageBreakdownRows(selectedUsageBreakdown.byModel, "model", options.language); + const usageProviderRows = renderUsageBreakdownRows(selectedUsageBreakdown.byProvider, "provider", options.language); + const usageSessionTypeRows = selectedUsageBreakdown.bySessionType; + const usageCronJobRows = selectedUsageBreakdown.byCronJob; + const usageCronAgentRows = selectedUsageBreakdown.byCronAgent; + const usageSessionTypeTotalTokens = usageSessionTypeRows.reduce((sum, item) => sum + item.tokens, 0); + const usageCronTotalTokens = usageCronJobRows.reduce((sum, item) => sum + item.tokens, 0); + const usageCronAgentTotalTokens = usageCronAgentRows.reduce((sum, item) => sum + item.tokens, 0); + const usageSourceAgentTotalTokens = selectedUsageBreakdown.byAgent.reduce((sum, item) => sum + item.tokens, 0); + const usageSourceProjectTotalTokens = selectedUsageBreakdown.byProject.reduce((sum, item) => sum + item.tokens, 0); + const runtimeTokenRangeLabel = + usageToday?.sourceStatus === "not_connected" + ? t("Range: current snapshot (data source not connected).", "统计范围:当前快照(数据源未连接)。") + : isTodayUsageView + ? t("Range: today from 00:00 until now.", "统计范围:今日 00:00 至当前。") + : t("Range: cumulative until now.", "统计范围:累计至当前。"); + const sessionTypeTokenRangeLabel = isTodayUsageView + ? t("Range: all sessions today (00:00 until now).", "统计范围:今日全部会话(00:00 至当前)。") + : t("Range: all sessions cumulative (through now).", "统计范围:全部会话累计(截至当前)。"); + const cronTokenRangeLabel = isTodayUsageView + ? t("Range: timed-job sessions today (00:00 until now).", "统计范围:今日定时任务会话(00:00 至当前)。") + : t("Range: timed-job sessions cumulative (through now).", "统计范围:定时任务会话累计(截至当前)。"); + const usageSourcePieHtml = + selectedUsageBreakdown.byAgent.length === 0 && selectedUsageBreakdown.byProject.length === 0 + ? "" + : `
    +
    +
    ${escapeHtml(t("Share by agent", "按智能体占比"))}
    + ${renderTokenPieChart(selectedUsageBreakdown.byAgent, usageSourceAgentTotalTokens, t("Agents", "智能体"), options.language)} +
    +
    +
    ${escapeHtml(t("Share by project", "按项目占比"))}
    + ${renderTokenPieChart(selectedUsageBreakdown.byProject, usageSourceProjectTotalTokens, t("Projects", "项目"), options.language)} +
    +
    `; + const usageSessionTypePieHtml = renderTokenPieChart(usageSessionTypeRows, usageSessionTypeTotalTokens, t("All sessions", "全部会话"), options.language); + const usageCronJobPieHtml = renderTokenPieChart(usageCronJobRows, usageCronTotalTokens, t("Timed jobs", "定时任务"), options.language); + const usageCronAgentPieHtml = renderTokenPieChart(usageCronAgentRows, usageCronAgentTotalTokens, t("Agents", "智能体"), options.language); + const usageSessionTypeShareHtml = + usageSessionTypeRows.length === 0 + ? `
    ${escapeHtml(t("No session-type usage data yet.", "暂无会话类型用量数据。"))}
    ` + : `
    ${sessionTypeTokenRangeLabel}
    +
    ${escapeHtml(t("Total usage", "总用量"))}:${formatInt(usageSessionTypeTotalTokens)}
    + ${usageSessionTypePieHtml} + + + ${renderTokenShareRows(usageSessionTypeRows, usageSessionTypeTotalTokens, options.language)} +
    ${escapeHtml(t("Type", "类型"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Share", "占比"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `; + const usageCronJobShareHtml = + usageCronJobRows.length === 0 + ? `
    ${escapeHtml(t("No timed-job usage data yet.", "暂无定时任务用量数据。"))}
    ` + : `
    ${cronTokenRangeLabel}
    +
    ${escapeHtml(t("Total timed-job usage", "定时任务总用量"))}:${formatInt(usageCronTotalTokens)}
    + ${usageCronJobPieHtml} + + + ${renderTokenShareRows(usageCronJobRows, usageCronTotalTokens, options.language)} +
    ${escapeHtml(t("Timed job", "定时任务"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Share within timed jobs", "占比(定时任务内)"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `; + const usageCronAgentShareHtml = + usageCronAgentRows.length === 0 + ? `
    ${escapeHtml(t("No timed-job agent usage data yet.", "暂无定时任务智能体用量数据。"))}
    ` + : `
    ${cronTokenRangeLabel}
    +
    ${escapeHtml(t("Total timed-job agent usage", "定时任务智能体总用量"))}:${formatInt(usageCronAgentTotalTokens)}
    + ${usageCronAgentPieHtml} + + + ${renderTokenShareRows(usageCronAgentRows, usageCronAgentTotalTokens, options.language)} +
    ${escapeHtml(t("Agent", "智能体"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Share within timed jobs", "占比(定时任务内)"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `; + const usageConnectorTodos = renderUsageConnectorTodos(usageCost.connectors.todos, options.language); + const usageBudgetStatusLabel = + usageCost.budget.status === "ok" ? t("Healthy", "正常") : usageCost.budget.status === "warn" ? t("Warning", "预警") : t("Over limit", "超限"); + const usageBudgetHeadline = + usageCost.budget.status === "not_connected" + ? t("Budget data source is not connected", "预算数据源未连接") + : `${badge(usageCost.budget.status, usageBudgetStatusLabel)} ${escapeHtml(usageCost.budget.message)}`; + const usageBudgetMeta = + usage30d?.sourceStatus === "not_connected" + ? t("Last 30 days cost: data source not connected", "近 30 天费用:数据源未连接") + : usageCost.budget.limitCost30d + ? `${t("Last 30 days cost", "近 30 天费用")} ${formatCurrency(usageCost.budget.usedCost30d)} / ${t("Limit", "限额")} ${formatCurrency(usageCost.budget.limitCost30d)}` + : `${t("Last 30 days cost", "近 30 天费用")} ${formatCurrency(usageCost.budget.usedCost30d)}`; + const hasUsageActivity = + usageCost.contextWindows.length > 0 || + usageCost.periods.some((item) => item.tokens > 0 || item.estimatedCost > 0 || item.statusSamples > 0); + const usageContextHtml = + usageCost.contextWindows.length === 0 + ? `
    ${escapeHtml(t("No context-usage records yet. They will appear after sessions start.", "暂无上下文使用记录。开始会话后会显示。"))}
    ` + : ` + + ${usageContextRows} +
    ${escapeHtml(t("Agent", "助手"))}${escapeHtml(t("Session", "会话"))}${escapeHtml(t("Model", "模型"))}${escapeHtml(t("Context usage", "上下文使用"))}${escapeHtml(t("Pace", "节奏"))}${escapeHtml(t("Threshold", "阈值"))}
    `; + const usageSourceHtml = + selectedUsageBreakdown.byAgent.length === 0 && selectedUsageBreakdown.byProject.length === 0 + ? `
    ${escapeHtml(t("No source attribution yet. It will appear after activity is recorded.", "暂无来源拆分。产生调用后会显示。"))}
    ` + : `
    ${runtimeTokenRangeLabel}
    + ${usageSourcePieHtml} + ${selectedUsageBreakdown.byAgent.length === 0 + ? "" + : `${usageAgentRows}
    ${escapeHtml(t("Agent", "智能体"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Estimated cost", "预估费用"))}${escapeHtml(t("Requests", "请求数"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `} + ${selectedUsageBreakdown.byProject.length === 0 + ? "" + : `${usageProjectRows}
    ${escapeHtml(t("Project", "项目"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Estimated cost", "预估费用"))}${escapeHtml(t("Requests", "请求数"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `}`; + const usageTaskHtml = + usageTaskBreakdownRows.length === 0 + ? `
    ${escapeHtml(t("No real task-level usage data yet.", "暂无真实任务级用量数据。"))}
    ` + : `
    ${runtimeTokenRangeLabel}
    ${usageTaskRows}
    ${escapeHtml(t("Task", "任务"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Estimated cost", "预估费用"))}${escapeHtml(t("Requests", "请求数"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `; + const usageOverviewAgentRows = renderUsageBreakdownRows(selectedUsageBreakdown.byAgent.slice(0, 8), "agent", options.language); + const usageOverviewTaskRows = renderUsageBreakdownRows(usageTaskBreakdownRows.slice(0, 8), "task", options.language); + const usageAttributionHtml = + selectedUsageBreakdown.byAgent.length === 0 && usageTaskBreakdownRows.length === 0 + ? `
    ${escapeHtml(t("No usage attribution by agent or task yet.", "暂无按智能体/任务归因的用量数据。"))}
    ` + : `
    ${runtimeTokenRangeLabel}
    + ${selectedUsageBreakdown.byAgent.length === 0 + ? "" + : `${usageOverviewAgentRows}
    ${escapeHtml(t("Agent", "智能体"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Estimated cost", "预估费用"))}${escapeHtml(t("Requests", "请求数"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `} + ${usageTaskBreakdownRows.length === 0 + ? "" + : `${usageOverviewTaskRows}
    ${escapeHtml(t("Task", "任务"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Estimated cost", "预估费用"))}${escapeHtml(t("Requests", "请求数"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `}`; + const usageModelMixHtml = + selectedUsageBreakdown.byModel.length === 0 && selectedUsageBreakdown.byProvider.length === 0 + ? `
    ${escapeHtml(t("No model or provider split yet.", "暂无模型与供应商拆分数据。"))}
    ` + : `
    ${runtimeTokenRangeLabel}
    + ${selectedUsageBreakdown.byModel.length === 0 + ? "" + : `${usageModelRows}
    ${escapeHtml(t("Model", "模型"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Estimated cost", "预估费用"))}${escapeHtml(t("Requests", "请求数"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `} + ${selectedUsageBreakdown.byProvider.length === 0 + ? "" + : `${usageProviderRows}
    ${escapeHtml(t("Provider", "供应商"))}${escapeHtml(t("Usage", "用量"))}${escapeHtml(t("Estimated cost", "预估费用"))}${escapeHtml(t("Requests", "请求数"))}${escapeHtml(t("Sessions", "会话数"))}${escapeHtml(t("Data status", "数据状态"))}
    `}`; + const renderExecutionAgentItem = (item: ExecutionAgentSummary, mode: "active" | "usage"): string => { + const modeHint = mode === "active" + ? t("Live", "实时") + : t("Recent", "近期"); + const detail = mode === "active" + ? `${t("Sessions", "会话")} ${item.activeSessions} · ${t("Tasks", "任务")} ${item.activeTasks}` + : `${t("Recent usage", "近期用量")} ${formatInt(item.recentTokens30d)}`; + return `
  • ${escapeHtml(item.displayName)} ${escapeHtml(modeHint)}
    ${detail}
  • `; + }; + const activeExecutionAgentRows = executionAgentSummaries + .filter((item) => item.activeSessions > 0 || item.activeTasks > 0 || item.enabledCronJobs > 0) + .slice(0, 8) + .map((item) => { + return renderExecutionAgentItem(item, "active"); + }) + .join(""); + const usageFallbackExecutionRows = executionAgentSummaries + .filter((item) => item.recentTokens30d > 0) + .slice(0, 8) + .map((item) => renderExecutionAgentItem(item, "usage")) + .join(""); + const executionAgentRows = activeExecutionAgentRows || usageFallbackExecutionRows; + const taskRoleRows = taskRoleSummaries + .map( + (item) => + `
  • ${escapeHtml(item.owner)}
    ${escapeHtml(t("Board labels", "看板标签"))} ${item.activeTasks} ${escapeHtml(t("items", "个"))} · ${escapeHtml(t("Examples", "示例"))}:${escapeHtml(item.sampleTaskIds.join("、") || t("None", "暂无"))}
  • `, + ) + .join(""); + const mappingTaskRows = controlCenterMappingTasks + .map( + (task) => + `${escapeHtml(task.taskId)}${escapeHtml(task.owner)}${badge(task.status, taskStateLabel(task.status, options.language))}`, + ) + .join(""); + const cronTable = + allCronRows.length === 0 + ? `
    ${escapeHtml(t("No timed jobs yet. They will appear here after you create them.", "暂无定时任务。创建后会显示在这里。"))}
    ` + : ` + + ${cronRows} +
    ${escapeHtml(t("Job", "任务"))}${escapeHtml(t("Agent", "智能体"))}${escapeHtml(t("Purpose", "任务目的"))}${escapeHtml(t("Status", "状态"))}${escapeHtml(t("Next run", "下次运行"))}${escapeHtml(t("Due in", "距离执行"))}
    `; + const cronOwnerBuckets = new Map(); + for (const job of allCronRows) { + const ownerKey = job.owner.trim() || t("Unassigned agent", "未分配智能体"); + const bucket = cronOwnerBuckets.get(ownerKey) ?? []; + bucket.push(job); + cronOwnerBuckets.set(ownerKey, bucket); + } + const cronBoardHtml = + allCronRows.length === 0 + ? `
    ${escapeHtml(t("No timed jobs yet. They will be grouped by agent here once configured.", "暂无定时任务,配置后这里会自动按智能体分组展示。"))}
    ` + : `
    ${[...cronOwnerBuckets.entries()] + .sort((a, b) => b[1].length - a[1].length || a[0].localeCompare(b[0], "zh-Hans-CN")) + .map(([owner, jobs]) => { + const healthyCount = jobs.filter((item) => item.status === "ok" || item.status === "enabled").length; + const unhealthyCount = jobs.length - healthyCount; + const jobRows = jobs + .slice(0, 10) + .map((item) => { + const dueIn = Number.isFinite(item.dueInSeconds) ? formatSeconds(item.dueInSeconds, options.language) : "-"; + return `
  • ${escapeHtml(item.name)}${badge(item.status, item.statusLabel)}
    ${escapeHtml(sanitizeCronPurposeText(item.purpose, options.language, 52))}
    ${escapeHtml(t("Next", "下次"))}:${escapeHtml(item.nextRun)} · ${escapeHtml(dueIn)}
  • `; + }) + .join(""); + const moreLabel = jobs.length > 10 ? `
    ${escapeHtml(t(`${jobs.length - 10} more jobs are omitted.`, `其余 ${jobs.length - 10} 个任务已省略。`))}
    ` : ""; + return `

    ${escapeHtml(owner)}

    ${jobs.length} ${escapeHtml(t("jobs", "个任务"))}
    ${escapeHtml(t("Healthy", "健康"))} ${healthyCount} · ${escapeHtml(t("Attention", "关注"))} ${unhealthyCount}
      ${jobRows}
    ${moreLabel}
    `; + }) + .join("")}
    `; + const subscriptionSidebarRows = renderSubscriptionSidebarSummary(usageCost.subscription, options.language); + const usageDetailHref = buildHomeHref({ quick: "all" }, options.compactStatusStrip, "usage-cost", options.language, options.usageView); + const overviewUsagePeriods = isTodayUsageView + ? usageCost.periods.filter((item) => item.key === "today") + : usageCost.periods.filter((item) => item.key === "today" || item.key === "7d"); + const overviewUsageCards = hasUsageActivity + ? renderUsagePeriodCards(overviewUsagePeriods, options.language) + : `
    ${escapeHtml(t("No usage data yet. Usage and cost cards will appear after activity starts.", "暂无用量数据。开始会话后会显示用量和费用卡片。"))}
    `; + const overviewAttentionTotal = pendingDecisionCount + runtimeIssueCount + budgetRiskCount; + const overviewCommandStatus = overviewAttentionTotal > 0 ? badge("warn", t("Needs attention", "需要关注")) : badge("ok", t("Stable", "平稳")); + const overviewActionItems = [ + { + label: t("Review queue", "审阅队列"), + value: pendingDecisionCount, + detail: + pendingDecisionCount > 0 + ? t("Approvals or runtime actions are waiting for review", "还有审批或运行异常等待处理") + : t("Nothing is waiting for review", "当前没有待审事项"), + }, + { + label: t("Runtime issues", "运行异常"), + value: runtimeIssueCount, + detail: + runtimeIssueCount > 0 + ? t( + `${runtimeSessionIssueCount} blocked/error/waiting sessions · ${stalledRunningSessionCount} stalled runs`, + `${runtimeSessionIssueCount} 个阻塞/异常/等待会话 · ${stalledRunningSessionCount} 个停滞执行`, + ) + : t("No blocked, failing, or stalled runtime signal", "当前没有阻塞、报错或停滞信号"), + }, + { + label: t("Budget risk", "预算风险"), + value: budgetRiskCount, + detail: budgetRiskCount > 0 ? t("Near or over the budget line", "接近或触发预算线") : t("Budget is in the safe zone", "预算处于安全区"), + }, + ]; + const overviewActionRows = overviewActionItems + .map((item) => { + const toneClass = item.value > 0 ? " hot" : ""; + return `
    ${escapeHtml(item.label)}${item.value}${escapeHtml(item.detail)}
    `; + }) + .join(""); + const overviewPrimaryStatus = overviewAttentionTotal > 0 ? badge("warn", t("Needs attention", "需要关注")) : badge("ok", t("Stable", "稳定运行")); + const overviewPrimarySignalText = overviewAttentionTotal > 0 ? t("Runtime is surfacing signals that need intervention.", "运行现场正在冒出需要你处理的信号。") : t("The system is holding a stable rhythm.", "系统维持稳定节奏。"); + const overviewPrimaryDirective = + pendingDecisionCount > 0 + ? t("Clear the review queue first", "先清掉审阅队列") + : runtimeIssueCount > 0 + ? t("Inspect blocked, failing, or stalled runs next", "接着检查阻塞、报错和停滞执行") + : budgetRiskCount > 0 + ? t("Prioritize budget risk", "优先处理预算风险") + : t("Keep the current rhythm", "继续保持当前节奏"); + markRenderPhase("view-models"); + const overviewFocusScore = Math.max( + 0, + Math.min( + 100, + Math.round( + 100 - + pendingDecisionCount * 14 - + runtimeSessionIssueCount * 18 - + stalledRunningSessionCount * 16 - + budgetRiskCount * 18, + ), + ), + ); + const overviewFocusTone = + overviewFocusScore >= 80 ? "#1f9a63" : overviewFocusScore >= 60 ? "#c28819" : "#d2473a"; + const overviewFocusHeadline = + overviewFocusScore >= 80 ? t("Flowing well", "推进顺畅") : overviewFocusScore >= 60 ? t("Light pressure", "轻度压力") : t("Needs immediate action", "需要立刻处理"); + const overviewFocusShort = `${t("Review queue", "审阅队列")} ${pendingDecisionCount} · ${t("Runtime issues", "运行异常")} ${runtimeSessionIssueCount} · ${t("Stalled runs", "停滞执行")} ${stalledRunningSessionCount} · ${t("Budget risk", "预算风险")} ${budgetRiskCount}`; + const enabledCronCount = allCronRows.filter((item) => item.status !== "disabled").length; + const upcomingTaskDueCount = realTasks.filter((task) => task.dueAt && task.status !== "done").length; + const taskHubHref = buildHomeHref({ quick: "all" }, options.compactStatusStrip, "projects-tasks", options.language, options.usageView); + const cronHubHref = `${taskHubHref}#cron-execution-board`; + const timelineHubHref = `${taskHubHref}#calendar-board`; + const decisionHubHref = `${taskHubHref}#task-decision-center`; + const executionChainHubHref = `${taskHubHref}#task-execution-chain`; + const staffHubHref = buildHomeHref({ quick: "all" }, options.compactStatusStrip, "team", options.language, options.usageView); + const overviewNextOpsSummary = `Cron ${cronOverview.nextRunAt ?? t("None", "暂无")} · ${t("Heartbeat", "心跳")} ${heartbeatNextRun}`; + const calendarEvents = [ + ...allCronRows.map((row) => ({ + at: row.nextRun, + day: extractDateFromName(row.nextRun) ?? row.nextRun.slice(0, 10), + type: "Cron", + title: row.name, + status: row.status, + detail: sanitizeCronPurposeText(row.purpose, options.language, 64), + owner: row.owner, + })), + ...realTasks + .filter((task) => task.status !== "done" && task.dueAt) + .map((task) => ({ + at: task.dueAt ?? "-", + day: task.dueAt ? task.dueAt.slice(0, 10) : "-", + type: t("Task due", "任务截止"), + title: task.title, + status: task.status, + detail: `${task.projectId} · ${task.owner}`, + owner: task.owner, + })), + ] + .filter((item) => item.day && item.day !== "-") + .sort((a, b) => a.at.localeCompare(b.at)); + const overviewUpcomingRows = calendarEvents + .slice(0, 4) + .map( + (item) => `
    +
    + ${escapeHtml(item.title)} +
    ${escapeHtml(item.type)} · ${escapeHtml(item.owner)}
    +
    +
    ${escapeHtml(item.at)}
    +
    `, + ) + .join(""); + const overviewBusyAgents = executionAgentSummaries + .filter((item) => item.activeSessions > 0 || item.activeTasks > 0 || item.enabledCronJobs > 0) + .sort((a, b) => b.activeTasks - a.activeTasks || b.activeSessions - a.activeSessions || b.enabledCronJobs - a.enabledCronJobs) + .slice(0, 3); + const overviewBusyCardsHtml = + overviewBusyAgents.length === 0 + ? `
    ${escapeHtml(t("No staff are carrying live work right now.", "当前没有员工在承担实时工作。"))}
    ` + : `
    ${overviewBusyAgents + .map((item) => { + const leadAssignment = item.cronJobNames[0] ?? t("No live assignment", "暂无实时分派"); + return `
    +
    + ${escapeHtml(item.displayName)} + ${escapeHtml(t("Live", "实时"))} +
    +
    ${escapeHtml(leadAssignment)}
    +
    ${escapeHtml(t("Tasks", "任务"))} ${item.activeTasks} · ${escapeHtml(t("Sessions", "会话"))} ${item.activeSessions} · Cron ${item.enabledCronJobs}
    +
    `; + }) + .join("")}
    `; + const overviewDecisionRowsHtml = `
    ${[ + { ...overviewActionItems[0], href: decisionHubHref }, + { ...overviewActionItems[1], href: focusHref }, + { ...overviewActionItems[2], href: usageDetailHref }, + ] + .map((item) => { + const toneClass = item.value > 0 ? " hot" : ""; + return ` + ${escapeHtml(item.label)} + ${item.value} + ${escapeHtml(item.detail)} + `; + }) + .join("")}
    `; + const overviewRuntimeRowsHtml = `
    +
    +
    + ${escapeHtml(t("Timed jobs running", "正在运行的定时任务"))} +
    ${escapeHtml(t("Next", "下次"))} ${escapeHtml(cronOverview.nextRunAt ?? t("None", "暂无"))}
    +
    +
    ${enabledCronCount}/${allCronRows.length}
    +
    +
    +
    + ${escapeHtml(t("Heartbeat checks", "任务心跳"))} +
    ${escapeHtml(t("Next", "下次"))} ${escapeHtml(heartbeatNextRun)}
    +
    +
    ${heartbeatEnabledCount}
    +
    +
    +
    + ${escapeHtml(t("Stalled runs", "停滞执行"))} +
    ${escapeHtml(t("Running sessions with no fresh signal in the last 2 hours", "最近 2 小时没有新信号的运行会话"))}
    +
    +
    ${stalledRunningSessionCount}
    +
    + +
    + ${escapeHtml(t("Isolated execution", "隔离执行"))} +
    ${escapeHtml(t("Accepted and spawned child sessions", "已接单并派发子会话"))}
    +
    +
    ${runningExecutionChainCount}/${spawnedExecutionChainCount}
    +
    +
    `; + const taskDecisionPreviewHtml = + actionQueue.queue.length > 0 + ? `
    ${actionQueue.queue + .slice(0, 4) + .map((item) => { + const link = item.links[0]?.href ?? decisionHubHref; + return ` +
    + ${escapeHtml(item.message)} +
    ${badge(item.level)} ${escapeHtml(item.itemId)}
    +
    + +
    `; + }) + .join("")}
    ` + : topApprovals.length > 0 + ? `
    ${topApprovals + .slice(0, 4) + .map((approval) => { + const target = approval.agentId ?? approval.sessionKey ?? t("Unknown target", "未知目标"); + return ` +
    + ${escapeHtml(approval.command || t("Approval action", "审批动作"))} +
    ${badge(approval.status ?? "unknown")} ${escapeHtml(target)}
    +
    + +
    `; + }) + .join("")}
    ` + : `
    ${escapeHtml(t("Nothing is waiting for your review right now.", "当前没有等待你决策的事项。"))}
    `; + const taskHubStatCardsHtml = `
    +
    + ${escapeHtml(t("Confirmed live", "已确认在跑"))} + ${taskCertaintyStrongCount} + ${escapeHtml(t("Tasks already backed by fresh runtime signals", "已经有新鲜运行信号支撑的任务"))} +
    +
    + ${escapeHtml(t("Need review", "待确认"))} + ${pendingDecisionCount} + ${escapeHtml(t("Approvals and action items", "审批与待处理事项"))} +
    +
    + ${escapeHtml(t("Timed jobs", "定时任务"))} + ${enabledCronCount} + ${escapeHtml(t("Enabled cron jobs", "已启用的 Cron"))} +
    +
    + ${escapeHtml(t("Needs inspection", "需排查"))} + ${taskCertaintyWeakCount} + ${escapeHtml(t("Tasks whose runtime signals still look weak", "运行信号仍然偏弱的任务"))} +
    +
    `; + const overviewSection = ` +
    +
    +
    +
    +

    ${escapeHtml(t("Today's control posture", "今日总控态势"))}

    +
    ${escapeHtml(overviewPrimarySignalText)}
    +
    +
    ${overviewPrimaryStatus}
    +
    +
    +
    +
    +
    ${overviewFocusScore}
    +
    ${escapeHtml(t("Health score", "健康分"))}
    +
    +
    +
    +
    ${escapeHtml(overviewFocusHeadline)}
    +
    ${escapeHtml(overviewFocusShort)}
    +
    ${escapeHtml(overviewNextOpsSummary)}
    +
    +
    +
    ${escapeHtml(overviewPrimaryDirective)}
    +
    +
    ${formatInt(overviewAttentionTotal)}
    +
    ${escapeHtml(t("Key action items", "待处理关键事项"))}
    +
    + +
    + ${overviewTopMetricHtml} +
    +
    +
    +
    +

    ${escapeHtml(t("Needs your intervention", "需要你介入"))}

    +
    ${overviewCommandStatus}
    +
    + ${overviewDecisionRowsHtml} +
    + + +
    +
    +

    ${escapeHtml(t("Next scheduled work", "下一批排程"))}

    + ${escapeHtml(t("Open task hub", "查看任务中枢"))} +
    + ${ + overviewUpcomingRows + ? `
    ${overviewUpcomingRows}
    ` + : `
    ${escapeHtml(t("No future schedule yet.", "暂无未来排程。"))}
    ` + } +
    + ${overviewRuntimeRowsHtml} +
    +
    +
    + ${escapeHtml(t("Expand runtime detail", "展开运行细节"))} +
    +
    + ${escapeHtml(t("More key metrics", "更多关键指标"))} +
    ${executiveCardsHtml}
    +
    +
    +

    ${escapeHtml(t("Global pulse", "全局脉搏"))}

    + ${ + showSignalsFallback + ? `
    ${escapeHtml(t("No live signals yet. This will update automatically after tasks or sessions start.", "还没有实时信号。启动任务或会话后,这里会自动更新。"))}
    ` + : `
    ${signalStrip}
    ` + } +
    +
    +
    +

    ${escapeHtml(t("Runtime checkpoint", "运行检查点"))}

    + ${escapeHtml(t("Open cron board", "查看 Cron 看板"))} +
    +
    ${escapeHtml(t("Use the task hub for the full cron board. This panel stays compact and only tells you whether runtime scheduling is healthy.", "完整 Cron 看板已下放到任务页,这里只保留紧凑的运行检查点。"))}
    +
    ${escapeHtml(t("Status", "状态"))} ${badge(cronOverview.health.status)} · ${escapeHtml(t("Next", "下次"))} ${escapeHtml(cronOverview.nextRunAt ?? t("None", "暂无"))} · ${escapeHtml(t("Enabled", "启用"))} ${enabledCronCount}
    + ${ + overviewUpcomingRows + ? `
    ${overviewUpcomingRows}
    ` + : "" + } +
    +
    + ${escapeHtml(t("Heartbeat monitor", "任务心跳监控"))} +
    +
    ${escapeHtml(t("Status", "状态"))} ${badge(heartbeatHealth)} · ${escapeHtml(t("Enabled", "已启用"))} ${heartbeatEnabledCount} ${escapeHtml(t("items", "个"))} · ${escapeHtml(t("Next", "下次"))} ${escapeHtml(heartbeatNextRun)}
    + ${heartbeatGroupedListHtml} +
    + ${escapeHtml(t("Open raw table", "查看原始表格"))} +
    ${ + heartbeatJobs.length === 0 + ? `
    ${escapeHtml(t("No heartbeat timed jobs found yet.", "尚未发现心跳定时任务。"))}
    ` + : `${heartbeatJobs + .slice(0, 12) + .map((job) => { + const checkLabel = job.jobId.toLowerCase().includes("heartbeat") + ? t("Task heartbeat service", "任务心跳服务") + : job.name?.trim() || job.jobId; + return ``; + }) + .join("")}
    ${escapeHtml(t("Check", "检查项"))}${escapeHtml(t("Status", "状态"))}${escapeHtml(t("Next run", "下次运行"))}${escapeHtml(t("Due in", "距离执行"))}
    ${escapeHtml(checkLabel)}${badge(job.health, cronHealthLabel(job.health, options.language))}${escapeHtml(job.nextRunAt ?? "-")}${escapeHtml(formatSeconds(job.dueInSeconds, options.language))}
    ` + }
    +
    +
    +
    +
    + ${escapeHtml(t("Tool activity detail", "工具调用详情"))} +
    + ${toolGroupedListHtml} +
    + ${escapeHtml(t("Open raw table", "查看原始表格"))} +
    + + + ${toolRows} +
    ${escapeHtml(t("Session", "会话"))}${escapeHtml(t("Agent", "助手"))}${escapeHtml(t("Call count", "调用次数"))}${escapeHtml(t("Status", "状态"))}${escapeHtml(t("Latest activity", "最近活动"))}
    +
    +
    +
    +
    +
    + ${escapeHtml(t("Timed-job catalog (execution entry)", "定时任务名录(执行入口)"))} +
    +
    ${escapeHtml(t("This shows the real timed jobs that can trigger execution.", "这里展示会触发执行的真实定时任务。"))}
    + ${agentJobGroupedListHtml} +
    + ${escapeHtml(t("Open raw table", "查看原始表格"))} +
    + + + ${agentJobRowsHtml} +
    ${escapeHtml(t("Source", "来源"))}${escapeHtml(t("Job", "任务"))}${escapeHtml(t("Agent", "智能体"))}${escapeHtml(t("Purpose", "任务目的"))}${escapeHtml(t("Schedule", "调度"))}${escapeHtml(t("Next run", "下次运行"))}${escapeHtml(t("Status", "状态"))}
    +
    +
    +
    +
    +
    +
    + `; + const calendarBuckets = new Map(); + for (const event of calendarEvents) { + const bucket = calendarBuckets.get(event.day) ?? []; + bucket.push(event); + calendarBuckets.set(event.day, bucket); + } + const calendarBoardHtml = + calendarBuckets.size === 0 + ? `
    ${escapeHtml(t("No future schedule yet. You can add timed jobs from tasks or automations.", "暂无未来排程。你可以在任务或自动化里添加定时任务。"))}
    ` + : `
    ${[...calendarBuckets.entries()] + .sort((a, b) => a[0].localeCompare(b[0])) + .slice(0, 12) + .map(([day, events]) => { + const rows = events + .slice(0, 10) + .map( + (item) => `
  • +
    ${escapeHtml(item.title)}${badge(item.status)}
    +
    ${escapeHtml(item.type)} · ${escapeHtml(item.at)}
    +
    ${escapeHtml(item.detail)}
    +
  • `, + ) + .join(""); + return `

    ${escapeHtml(day)}

    ${events.length} ${escapeHtml(t("scheduled items", "条排程"))}
      ${rows}
    `; + }) + .join("")}
    `; + const calendarSection = ` +
    +
    +

    ${escapeHtml(t("Today and next schedule", "今日与下一批排程"))}

    +
    ${escapeHtml(t("See timed jobs and due dates together so you can confirm OpenClaw actually scheduled them, instead of only saying it did in chat.", "把定时任务和任务截止放在一起看,确认 OpenClaw 真的排上了,而不是只在对话里说“已安排”。"))}
    +
    +
    ${escapeHtml(t("Timed jobs", "定时任务"))}${allCronRows.length}${escapeHtml(t("Catalog total", "名录总数"))}
    +
    ${escapeHtml(t("Enabled", "启用"))}${enabledCronCount}${escapeHtml(t("Ready to run", "已准备执行"))}
    +
    ${escapeHtml(t("Upcoming due", "即将截止"))}${upcomingTaskDueCount}${escapeHtml(t("Tasks with due dates", "带截止时间的任务"))}
    +
    +
    + ${calendarBoardHtml} +
    + ${escapeHtml(t("Open Cron table detail", "查看 Cron 表格明细"))} +
    ${cronTable}
    +
    +
    + `; + const cronExecutionSection = ` +
    +
    +

    ${escapeHtml(t("Cron execution board", "Cron 执行看板"))}

    +
    ${badge(cronOverview.health.status, cronHealthLabel(cronOverview.health.status, options.language))}
    +
    +
    ${escapeHtml(t("Grouped by agent so you can see which timed jobs are active, what they do, and when they run next.", "按智能体分组展示当前定时任务、任务目的以及下次执行时间。"))}
    +
    ${escapeHtml(t("Next", "下次"))} ${escapeHtml(cronOverview.nextRunAt ?? t("None", "暂无"))} · ${escapeHtml(t("Heartbeat", "心跳"))} ${escapeHtml(heartbeatNextRun)} · ${escapeHtml(t("Enabled", "启用"))} ${enabledCronCount}
    + ${cronBoardHtml} +
    + ${escapeHtml(t("Open Cron table detail", "查看 Cron 表格明细"))} +
    ${cronTable}
    +
    +
    + `; + const taskExecutionChainSection = ` +
    +
    +

    ${escapeHtml(t("Execution chain", "执行链"))}

    +
    ${badge(spawnedExecutionChainCount > 0 ? "info" : "idle", spawnedExecutionChainCount > 0 ? t("Active", "活跃") : t("Waiting", "等待中"))}
    +
    +
    ${escapeHtml(t("See whether the parent session accepted the work, whether it spawned an isolated session, and which child session is now running.", "直接看父会话是否接单、是否派发隔离会话,以及当前到底是哪条子会话在执行。"))}
    +
    ${escapeHtml(t("Isolated runs", "隔离执行"))} ${spawnedExecutionChainCount} · ${escapeHtml(t("Running now", "当前执行中"))} ${runningExecutionChainCount} · ${escapeHtml(t("Mapped tasks", "已关联任务"))} ${mappedExecutionChainCount}
    + ${taskExecutionChainHtml} +
    + `; + const teamMembersTableRows = + teamSnapshot.members.length === 0 + ? `${escapeHtml(t("No staff found.", "暂无员工。"))}` + : teamSnapshot.members + .map( + (member) => + `${escapeHtml(member.displayName)}${escapeHtml(member.agentId)}${escapeHtml(member.model)}${escapeHtml(member.toolsProfile)}${escapeHtml(member.workspace)}`, + ) + .join(""); + const teamSection = ` +
    +

    ${escapeHtml(t("Staff overview", "员工总览"))}

    +
    ${escapeHtml(t("The default view shows only name, role, current status, current work, recent output, and whether each person is on the schedule.", "默认视图只显示员工名字、角色定位、当前状态、正在处理什么、最近产出,以及是否在排班里。"))}
    + ${staffOverviewCardsHtml} +
    +
    + ${escapeHtml(t("Shared staff mission", "员工共同目标"))} +
    +
    ${escapeHtml(teamSnapshot.missionStatement)}
    +
    ${escapeHtml(t("Source", "来源"))}:${escapeHtml(teamSnapshot.sourcePath)}
    +
    ${escapeHtml(teamSnapshot.detail)}
    +
    +
    +
    + ${escapeHtml(t("Staff system details", "员工配置明细"))} +
    + + + ${teamMembersTableRows} +
    ${escapeHtml(t("Name", "名称"))}agentId${escapeHtml(t("Model", "模型"))}${escapeHtml(t("Tool profile", "工具权限"))}${escapeHtml(t("Workspace", "工作目录"))}
    +
    +
    + `; + const memoryMainCount = memoryFiles.filter((entry) => entry.facetKey === "main").length; + const memoryWorkbench = needsMemoryFiles + ? await renderEditableFileWorkbench({ + scope: "memory", + language: options.language, + title: t("Memory file workbench", "记忆文件工作台"), + description: t("Browse and edit OpenClaw memory files directly. Saving writes back to the source files.", "直接浏览和修改 OpenClaw 的记忆文件。保存后会写回原文件。"), + entries: memoryFiles, + emptyMessage: t("There are no editable memory files right now.", "当前没有可编辑的记忆文件。"), + defaultFacetKey: "main", + includeAllFacet: false, + facetOptions: memoryFacetOptions, + }) + : ""; + const memoryViewsLabel = joinDisplayList(["Main", ...memoryFacetOptions.filter((item) => item.key !== "main").map((item) => item.label)], options.language); + const memorySection = ` +
    +

    ${escapeHtml(t("Memory overview", "记忆概览"))}

    +
    Main ${escapeHtml(t("memories", "记忆"))} ${memoryMainCount} ${escapeHtml(t("files", "份"))} · ${escapeHtml(t("Agents found", "已发现智能体"))} ${Math.max(0, memoryFacetOptions.filter((item) => item.key !== "main").length)} ${escapeHtml(t("items", "个"))}
    +
    ${escapeHtml(t("Available views", "可切换查看"))}${escapeHtml(options.language === "en" ? ": " : ":")}${escapeHtml(memoryViewsLabel)}
    +
    ${escapeHtml(t("Only memory-related files are kept here: root MEMORY.md, memory/, and each agent's own MEMORY.md and memory/.", "这里只保留记忆相关文件:根目录 MEMORY.md、memory/,以及各智能体自己的 MEMORY.md 与 memory/。"))}
    +
    ${escapeHtml(t("Edits here sync directly back to the real memory files on the OpenClaw machine.", "这里的编辑会直接同步到 OpenClaw 机器上的真实记忆文件。"))}
    +
    + ${memoryWorkbench} + `; + const mainDocumentCount = workspaceFiles.filter((entry) => entry.facetKey === "main").length; + const workspaceWorkbench = needsWorkspaceFiles + ? await renderEditableFileWorkbench({ + scope: "workspace", + language: options.language, + title: t("Document workbench", "文档工作台"), + description: t("Keep only Main documents and each active agent's most useful core Markdown files. Saving writes back to the source files.", "只保留 Main 文档,以及当前启用智能体最有用、最应该调整的核心 Markdown。保存后会直接写回源文件。"), + entries: workspaceFiles, + emptyMessage: t("No editable Main documents or core agent documents were found.", "当前没有发现可编辑的 Main 文档或智能体核心文档。"), + defaultFacetKey: "main", + includeAllFacet: false, + facetOptions: workspaceFacetOptions, + }) + : ""; + const documentViewsLabel = joinDisplayList(["Main", ...workspaceFacetOptions.filter((item) => item.key !== "main").map((item) => item.label)], options.language); + const docsSection = ` +
    +

    ${escapeHtml(t("Document overview", "文档概览"))}

    +
    ${escapeHtml(t("Main documents", "Main 文档"))} ${mainDocumentCount} ${escapeHtml(t("files", "份"))} · ${escapeHtml(t("Agents found", "已发现智能体"))} ${Math.max(0, workspaceFacetOptions.filter((item) => item.key !== "main").length)} ${escapeHtml(t("items", "个"))}
    +
    ${escapeHtml(t("Available views", "可切换查看"))}${escapeHtml(options.language === "en" ? ": " : ":")}${escapeHtml(documentViewsLabel)}
    +
    ${escapeHtml(t("This keeps only Main documents plus the small set of Markdown files that matter most for each active agent.", "这里只保留 Main 文档,以及当前启用智能体最常用、最值得调整的那几份 Markdown。"))}
    +
    ${escapeHtml(t("Documents are no longer shown by chat history. They are archived by Main or by active agent.", "不再按会话历史展示文档,统一按 Main / 当前启用智能体归档。"))}
    +
    + ${workspaceWorkbench} + `; + const usageSection = ` +
    +

    ${escapeHtml(t("Measurement scope", "统计口径"))}

    + ${usageViewSwitchHtml} +
    ${usageViewRangeText}
    +
    ${usageViewRangeDetail}
    +
    ${escapeHtml(t("Today: from 00:00 until now. Cumulative: full history until now.", "今日:当日 00:00 至当前。累计:历史全量到当前。"))}
    +
    +
    +

    ${escapeHtml(isTodayUsageView ? t("Today's usage snapshot", "今日用量快照") : t("Cost trend", "费用趋势"))}

    +
    ${isTodayUsageView ? escapeHtml(t("Range: today.", "统计范围:今日。")) : runtimeTokenRangeLabel}
    + ${ + hasUsageActivity + ? usagePeriodCards + : `
    ${escapeHtml(t("No usage data yet. It will be generated automatically after sessions start.", "暂无用量数据。开始会话后会自动生成。"))}
    ` + } +
    +
    +

    ${escapeHtml(t("Subscription windows", "订阅窗口"))}

    + ${subscriptionStatusHtml} +
    +
    +

    ${escapeHtml(t("AI usage mix (all sessions)", "AI 用量构成(全部会话)"))}

    +
    ${escapeHtml(t("Timed jobs, Discord, Telegram, internal sessions", "定时任务、Discord、Telegram、内部会话"))}
    + ${usageSessionTypeShareHtml} +
    +
    +

    ${escapeHtml(t("Timed-job usage share", "定时任务用量占比"))}

    +
    ${cronTokenRangeLabel}
    + ${usageCronJobShareHtml} +
    + ${escapeHtml(t("Agent share within timed jobs", "定时任务内各智能体占比"))} +
    ${usageCronAgentShareHtml}
    +
    +
    +
    + ${escapeHtml(t("Advanced detail (attribution / model / context / budget)", "高级明细(归因/模型/上下文/预算)"))} +
    +

    ${escapeHtml(t("Split by agent and task", "按智能体与任务拆分"))}

    + ${usageAttributionHtml} +
    +

    ${escapeHtml(t("Usage sources", "用量来源"))}

    + ${usageSourceHtml} +
    +

    ${escapeHtml(t("Task consumption", "任务消耗"))}

    + ${usageTaskHtml} +
    +

    ${escapeHtml(t("Models and providers", "模型与供应商"))}

    + ${usageModelMixHtml} +
    +

    ${escapeHtml(t("Session context", "会话上下文"))}

    + ${usageContextHtml} +
    +

    ${escapeHtml(t("Budget forecast", "预算预测"))}

    +
    ${usageBudgetMeta}
    +
    ${usageBudgetHeadline}
    +
    ${escapeHtml(t("Daily burn", "日均消耗"))} ${ + usageCost.budget.burnRatePerDay !== undefined + ? formatCurrency(usageCost.budget.burnRatePerDay) + : t("Data source not connected", "数据源未连接") + }
    +
    ${escapeHtml(t("Estimated days remaining", "预计剩余天数"))} ${ + usageCost.budget.projectedDaysToLimit !== undefined + ? usageCost.budget.projectedDaysToLimit.toFixed(1) + : t("Data source not connected", "数据源未连接") + }
    +
    +
    + `; + const officeSection = ` +
    +

    看板映射说明

    +
    Alex / Sam / Taylor / Unassigned 这类名称只是 control-center 的分组标签,不是智能体,不会单独消耗预算。
    +
    + 查看映射标签(不执行任务) +
    +
      ${taskRoleRows || "
    • 当前没有映射标签。
    • "}
    +
    +
    +
    +
    + 执行分区(工位) +
    ${officeFloorHtml}
    +
    +
    + 最近会话(${sessionPreview.items.length}/${sessionPreview.total}) +
    + ${ + sessionPreview.items.length === 0 + ? '
    暂无会话数据。
    ' + : `
    最近活跃会话(${sessionPreview.items.length})
      ${sessionPreview.items + .slice(0, 14) + .map((item) => `
    • ${escapeHtml(item.label ?? item.sessionKey)}${badge(item.state, sessionStateLabel(item.state))}
      智能体 ${escapeHtml(item.agentId ?? "-")} · 最近 ${escapeHtml(item.lastMessageAt ?? "-")}
      最新事件 ${escapeHtml(item.latestKind ?? "message")} · 历史 ${item.historyCount}
    • `) + .join("")}
    ` + } +
    + 查看原始表格 +
    + + + ${sessionRows} +
    会话状态助手最近活动
    +
    +
    +
    +
    + `; + const teamUnifiedSection = teamSection; + const projectsSection = ` +
    +
    +
    +
    +

    ${escapeHtml(t("Task hub", "任务中枢"))}

    +
    ${escapeHtml(t("One place for schedule, current tasks, follow-up items, and cron execution.", "把排程、当前任务、待处理事项和 Cron 执行放在同一页。"))}
    +
    +
    ${overviewPrimaryStatus}
    +
    + ${taskHubStatCardsHtml} +
    +
    +
    ${escapeHtml(t("Current focus", "当前关注"))}
    +
    ${badge(currentTaskHealth)} ${escapeHtml(t("Confirmed live", "已确认在跑"))} ${taskCertaintyStrongCount} · ${escapeHtml(t("Need follow-up", "需跟进"))} ${taskCertaintyFollowupCount} · ${escapeHtml(t("Needs inspection", "需排查"))} ${taskCertaintyWeakCount}
    + ${mappingTaskHint ? `
    ${escapeHtml(mappingTaskHint)}
    ` : ""} +
    + +
    +
    +
    +
    +

    ${escapeHtml(t("Waiting for your decision", "等待你决策"))}

    +
    ${badge(pendingDecisionCount > 0 ? "warn" : "ok", pendingDecisionCount > 0 ? t("Queue active", "队列活跃") : t("Clear", "已清空"))}
    +
    +
    ${escapeHtml(t("Pending decisions", "待处理事项"))} ${pendingDecisionCount} · ${escapeHtml(t("Approvals", "审批"))} ${pendingApprovalsCount} · ${escapeHtml(t("Unacked alerts", "未确认告警"))} ${actionQueue.counts.unacked}
    + ${taskDecisionPreviewHtml} +
    +
    + ${taskExecutionChainSection} +
    + ${calendarSection} + ${cronExecutionSection} +
    +
    +
    +

    ${escapeHtml(t("Task lanes", "任务泳道"))}

    +
    ${escapeHtml(t("Current focus", "当前关注"))}:${escapeHtml(quickFilterLabel(effectiveQuick, options.language))}
    + ${ + controlCenterMappingTasks.length > 0 + ? `
    ${escapeHtml(t(`${controlCenterMappingTasks.length} board-only mapping examples are hidden because they are not real execution tasks.`, `已隐藏 ${controlCenterMappingTasks.length} 个看板映射样例(非真实执行任务)。`))}
    ` + : "" + } +
    ${quickFilters}
    +
    + + + + + +
    + + +
    +
    + + +
    +
    + + +
    +
    + + ${escapeHtml(t("Clear filters", "清空筛选"))} +
    +
    + ${taskBoard} +
    +

    ${escapeHtml(t("Task groups (native view)", "任务分组列表(原生视图)"))}

    + ${taskGroupedListHtml} + ${ + controlCenterMappingTasks.length === 0 + ? "" + : `
    + ${escapeHtml(t("Open board mapping examples (non-executing)", "查看看板映射样例(不执行任务)"))} +
    + + + ${mappingTaskRows} +
    ${escapeHtml(t("Example task", "样例任务"))}${escapeHtml(t("Label", "标签"))}${escapeHtml(t("Status", "状态"))}
    +
    +
    ` + } +
    +
    +
    +

    ${escapeHtml(t("Project lanes", "项目泳道"))}

    + ${projectBoard} +
    +
    +

    ${escapeHtml(t("Live activity feed", "实时活动流"))}

    +
    ${escapeHtml(t("Use this to confirm what OpenClaw and its sub-agents are doing right now.", "用于确认 OpenClaw 与子智能体当前正在执行什么。"))}
    +
      ${replayMomentsRows}
    +
    +
    +
    +
    + ${escapeHtml(t(`Task table (raw detail, ${tasks.length}/${allTasks.length})`, `任务表格(原始明细,${tasks.length}/${allTasks.length})`))} +
    + + + ${taskRows} +
    ${escapeHtml(t("Project", "项目"))}${escapeHtml(t("Task", "任务"))}${escapeHtml(t("Title", "标题"))}${escapeHtml(t("Status", "状态"))}${escapeHtml(t("Agent", "智能体"))}${escapeHtml(t("Due", "截止"))}${escapeHtml(t("Updated", "更新时间"))}
    +
    +
    + `; + const alertsSection = ` +
    +

    ${escapeHtml(t("Attention items", "关注事项"))}

    +
    ${escapeHtml(t("Blocked", "阻塞"))} ${exceptions.counts.blocked} · ${escapeHtml(t("Errors", "异常"))} ${exceptions.counts.errors} · ${escapeHtml(t("Pending approvals", "待审批"))} ${exceptions.counts.pendingApprovals} · ${escapeHtml(t("Stalled runs", "停滞执行"))} ${stalledRunningSessionCount}
    +
      ${exceptionsItems}
    +
    +
    +

    ${escapeHtml(t("Needs your decision", "需要你决策"))}

    +
    ${escapeHtml(t("Unacked", "待处理"))} ${actionQueue.counts.unacked} · ${escapeHtml(t("Acked", "已确认"))} ${actionQueue.counts.acked}
    + ${ + actionQueue.counts.total === 0 + ? `
    ${escapeHtml(t("There is nothing waiting for a decision right now.", "当前没有待决策事项。"))}
    ` + : actionQueueItems + } +
    +
    + ${escapeHtml(t("Approval requests", "审批请求"))} +
    ${ + topApprovals.length === 0 + ? `
    ${escapeHtml(t("No approval requests yet.", "暂无审批请求。"))}
    ` + : `
    ${escapeHtml(approvalsPreviewMeta)}
      ${approvalsItems}
    ` + }
    +
    +
    + ${escapeHtml(t("Budget watch", "预算监控"))} +
    ${ + nonOkBudgets.length === 0 + ? `
    ${escapeHtml(t("Budget status looks healthy right now.", "预算状态健康,当前无预警。"))}
    ` + : `${budgetItems}
    ${escapeHtml(t("Status", "状态"))}${escapeHtml(t("Scope", "范围"))}${escapeHtml(t("Target", "对象"))}${escapeHtml(t("Usage", "使用情况"))}
    ` + }
    +
    + `; + const replaySection = ` +
    +

    ${escapeHtml(t("Replay activity", "活动回放"))}

    + ${ + replaySignals.length === 0 + ? `
    ${escapeHtml(t("No replay data yet. It will appear after the monitor has been running.", "暂无回放数据。监控运行后会出现。"))}
    ` + : `
    ${replaySignals + .map((item) => `
    ${escapeHtml(item.label)}${item.value}
    `) + .join("")}
    ` + } +
    ${escapeHtml(t("Latest snapshot", "最新快照"))}:${escapeHtml(replayLatestSnapshot?.fileName ?? t("Not available", "暂无"))}
    +
    ${escapeHtml(t("Latest backup", "最新备份"))}:${escapeHtml(replayLatestBundle?.fileName ?? t("Not available", "暂无"))}
    + +
    +
    + ${escapeHtml(t("Replay metrics", "回放详细指标"))} +
    ${replayMetricsHtml}
    +
    +
    + ${escapeHtml(t("Recent timeline", "最近时间线"))} +
      ${replayMomentsRows}
    +
    + `; + const settingsSection = ` +
    +

    安全开关

    + + + ${importGuardRows} +
    项目状态当前值说明
    +
    +
    +

    ${escapeHtml(t("Recommended data connections", "数据接入建议"))}

    +
      ${usageConnectorTodos}
    +
    +
    +

    ${escapeHtml(t("Panel preferences", "面板偏好"))}

    + +
    + `; + let sectionBody = overviewSection; + if (options.section === "calendar") sectionBody = projectsSection; + if (options.section === "team") sectionBody = teamUnifiedSection; + if (options.section === "memory") sectionBody = memorySection; + if (options.section === "docs") sectionBody = docsSection; + if (options.section === "usage-cost") sectionBody = usageSection; + if (options.section === "office-space") sectionBody = teamUnifiedSection; + if (options.section === "projects-tasks") sectionBody = projectsSection; + if (options.section === "alerts") sectionBody = alertsSection; + if (options.section === "replay-audit") sectionBody = replaySection; + if (options.section === "settings") sectionBody = settingsSection; + const globalVisibilityCard = renderGlobalVisibilityCard(globalVisibilityModel, options.language); + const globalVisibilityBlock = options.section === "overview" ? globalVisibilityCard : ""; + const globalVisibilityQuickRows = [ + { + label: pickUiText(options.language, "Timed jobs", "定时任务"), + count: globalVisibilityModel.signalCounts.schedule, + href: buildGlobalVisibilityDetailHref("cron", options.language), + }, + { + label: pickUiText(options.language, "Heartbeat", "任务心跳"), + count: globalVisibilityModel.signalCounts.heartbeat, + href: buildGlobalVisibilityDetailHref("heartbeat", options.language), + }, + { + label: pickUiText(options.language, "Current tasks", "当前任务"), + count: globalVisibilityModel.signalCounts.currentTasks, + href: buildGlobalVisibilityDetailHref("current_task", options.language), + }, + { + label: pickUiText(options.language, "Tool calls", "工具调用"), + count: globalVisibilityModel.signalCounts.toolCalls, + href: buildGlobalVisibilityDetailHref("tool_call", options.language), + }, + ] + .map((item) => ``) + .join(""); + const sidebarSignalRows = + options.section === "overview" + ? globalVisibilityQuickRows + : ``; + const fileWorkbenchScript = renderFileWorkbenchScript(); + const agentVisualEnhancerScript = renderAgentVisualEnhancerScript(); + const nativeMotionScript = renderNativeMotionScript(options.language); + const quotaResetScript = renderQuotaResetScript(); + const renderTotalMs = Math.round(performance.now() - renderStartedAt); + if (renderTotalMs >= 1000) { + console.warn("[mission-control] slow html render", { + section: activeSection, + totalMs: renderTotalMs, + phases: renderPhases.join(" | "), + }); + } + + return ` + + + + OpenClaw Control Center + + + +
    + +
    +
    +
    +

    ${escapeHtml(sectionMeta.label)}

    +
    ${escapeHtml(sectionLeadText)}
    +
    +
    + +
    +
    +
    ${globalVisibilityBlock}${sectionBody}
    +
    + +
    + ${agentVisualEnhancerScript} + ${fileWorkbenchScript} + ${nativeMotionScript} + ${quotaResetScript} + +`; +} + +function parseTaskFilters(searchParams: URLSearchParams, strict: boolean): TaskQueryFilters { + assertAllowedQueryParams(searchParams, ["quick", "status", "owner", "project"], strict); + const filters: TaskQueryFilters = {}; + + const quick = normalizeQueryString(searchParams.get("quick"), "quick", 20, strict); + if (quick) { + if (isUiQuickFilter(quick)) { + filters.quick = quick; + } else if (strict) { + throw new RequestValidationError( + "quick must be one of: all, attention, todo, in_progress, blocked, done", + 400, + ); + } + } + + const status = normalizeQueryString(searchParams.get("status"), "status", 30, strict); + if (status) { + if (TASK_STATES.includes(status as TaskState)) { + filters.status = status as TaskState; + } else if (strict) { + throw new RequestValidationError("status must be one of: todo, in_progress, blocked, done", 400); + } + } + + const owner = normalizeQueryString(searchParams.get("owner"), "owner", 80, strict); + if (owner) filters.owner = owner; + + const project = normalizeQueryString(searchParams.get("project"), "project", 120, strict); + if (project) filters.project = project; + + return filters; +} + +function parseProjectFilters(searchParams: URLSearchParams, strict: boolean): ProjectQueryFilters { + assertAllowedQueryParams(searchParams, ["status", "owner", "projectId"], strict); + const filters: ProjectQueryFilters = {}; + const status = normalizeQueryString(searchParams.get("status"), "status", 30, strict); + if (status) { + if (PROJECT_STATES.includes(status as ProjectState)) { + filters.status = status as ProjectState; + } else if (strict) { + throw new RequestValidationError("status must be one of: planned, active, blocked, done", 400); + } + } + + const owner = normalizeQueryString(searchParams.get("owner"), "owner", 80, strict); + if (owner) filters.owner = owner; + const projectId = normalizeQueryString(searchParams.get("projectId"), "projectId", 120, strict); + if (projectId) filters.projectId = projectId; + + return filters; +} + +function parseSessionQuery(searchParams: URLSearchParams, strict: boolean): SessionQuery { + assertAllowedQueryParams(searchParams, ["state", "agentId", "q", "page", "pageSize", "historyLimit"], strict); + const filters: SessionConversationFilters = {}; + const state = normalizeQueryString(searchParams.get("state"), "state", 40, strict); + if (state) { + if (SESSION_STATES.includes(state as AgentRunState)) { + filters.state = state as AgentRunState; + } else if (strict) { + throw new RequestValidationError( + "state must be one of: idle, running, blocked, waiting_approval, error", + 400, + ); + } + } + + const agentId = normalizeQueryString(searchParams.get("agentId"), "agentId", 120, strict); + if (agentId) filters.agentId = agentId; + + const q = normalizeQueryString(searchParams.get("q"), "q", 160, strict); + if (q) filters.q = q; + + return { + filters, + page: readPositiveIntQuery(searchParams.get("page"), "page", 1, strict), + pageSize: readPositiveIntQuery(searchParams.get("pageSize"), "pageSize", 20, strict, 100), + historyLimit: readPositiveIntQuery(searchParams.get("historyLimit"), "historyLimit", 8, strict, 200), + }; +} + +function parseAuditSeverity(searchParams: URLSearchParams, strict: boolean): AuditSeverity | "all" { + assertAllowedQueryParams(searchParams, ["severity"], strict); + const value = normalizeQueryString(searchParams.get("severity"), "severity", 30, strict); + if (!value) return "all"; + if (value === "all" || value === "info" || value === "warn" || value === "action-required" || value === "error") { + return value; + } + + if (strict) { + throw new RequestValidationError( + "severity must be one of: all, info, warn, action-required, error", + 400, + ); + } + + return "all"; +} + +function parseSearchQuery(searchParams: URLSearchParams): SearchQuery { + assertAllowedQueryParams(searchParams, ["q", "limit"], true); + const q = normalizeQueryString(searchParams.get("q"), "q", 180, true); + if (!q) { + throw new RequestValidationError("q is required and must be non-empty.", 400); + } + + return { + q, + limit: readPositiveIntQuery(searchParams.get("limit"), "limit", 20, true, SEARCH_LIMIT_MAX), + }; +} + +function parseReplayWindowQuery( + searchParams: URLSearchParams, + strict: boolean, +): { from?: string; to?: string } { + const from = normalizeQueryString(searchParams.get("from"), "from", 64, strict); + const to = normalizeQueryString(searchParams.get("to"), "to", 64, strict); + + const fromMs = from ? Date.parse(from) : NaN; + const toMs = to ? Date.parse(to) : NaN; + if (from && Number.isNaN(fromMs)) { + throw new RequestValidationError("from must be a valid ISO date-time string.", 400); + } + if (to && Number.isNaN(toMs)) { + throw new RequestValidationError("to must be a valid ISO date-time string.", 400); + } + if (from && to && fromMs > toMs) { + throw new RequestValidationError("from must be less than or equal to to.", 400); + } + + return { + from: from ? new Date(fromMs).toISOString() : undefined, + to: to ? new Date(toMs).toISOString() : undefined, + }; +} + +function safeSubstringMatch(query: string, ...fields: Array): boolean { + const needle = query.toLowerCase(); + if (!needle) return false; + return fields.some((field) => typeof field === "string" && field.toLowerCase().includes(needle)); +} + +function buildBoundedSearchResult(items: T[], limit: number): { + count: number; + returned: number; + items: T[]; +} { + const sliced = items.slice(0, limit); + return { + count: items.length, + returned: sliced.length, + items: sliced, + }; +} + +function resolveDashboardSearchQuery(searchParams: URLSearchParams): DashboardSearchQuery { + const q = normalizeQueryString(searchParams.get("search_q"), "search_q", 180, false) ?? ""; + const rawScope = normalizeQueryString(searchParams.get("search_scope"), "search_scope", 20, false); + const scope = DASHBOARD_SEARCH_SCOPES.includes(rawScope as DashboardSearchScope) + ? (rawScope as DashboardSearchScope) + : "tasks"; + const limit = readPositiveIntQuery(searchParams.get("search_limit"), "search_limit", 20, false, SEARCH_LIMIT_MAX); + return { + scope, + q, + limit, + }; +} + +export function resolveDashboardSection(searchParams: URLSearchParams): DashboardSection { + const value = normalizeQueryString(searchParams.get("section"), "section", 40, false); + if (!value) return "overview"; + if (value === "calendar") return "projects-tasks"; + if (value === "alerts" || value === "replay-audit") return "overview"; + return DASHBOARD_SECTIONS.includes(value as DashboardSection) ? (value as DashboardSection) : "overview"; +} + +function resolveLegacyDashboardSection(path: string): DashboardSection | undefined { + const section = LEGACY_DASHBOARD_ROUTE_SECTION[path as keyof typeof LEGACY_DASHBOARD_ROUTE_SECTION]; + return section; +} + +function resolveLegacyDashboardAnchor(path: string): string | undefined { + return LEGACY_DASHBOARD_ROUTE_ANCHOR[path as keyof typeof LEGACY_DASHBOARD_ROUTE_ANCHOR]; +} + +export function resolveLegacyDashboardSectionForSmoke(path: string): DashboardSection | undefined { + return resolveLegacyDashboardSection(path); +} + +function buildDashboardSearchResult( + snapshot: ReadModelSnapshot, + query: DashboardSearchQuery, +): DashboardSearchResult | undefined { + if (!query.q) return undefined; + + if (query.scope === "tasks") { + const result = buildBoundedSearchResult( + listTasks(snapshot.tasks, projectTitleMap(snapshot)) + .filter((task) => + safeSubstringMatch( + query.q, + task.taskId, + task.title, + task.owner, + task.projectId, + task.projectTitle, + task.status, + task.dueAt, + ), + ), + query.limit, + ); + const items = result.items; + const rows = + items.length === 0 + ? "未找到匹配任务。" + : items + .map( + (item) => + `${escapeHtml(item.taskId)}${escapeHtml(item.title)}${badge(item.status)}${escapeHtml(item.owner)}${escapeHtml(item.projectTitle)}${escapeHtml(item.updatedAt)}`, + ) + .join(""); + return { + scope: query.scope, + q: query.q, + limit: query.limit, + count: result.count, + returned: result.returned, + rows: `${rows}
    任务 ID标题状态智能体项目更新时间
    `, + }; + } + + if (query.scope === "projects") { + const result = buildBoundedSearchResult( + snapshot.projects.projects + .filter((project) => + safeSubstringMatch(query.q, project.projectId, project.title, project.owner, project.status), + ), + query.limit, + ); + const items = result.items; + const rows = + items.length === 0 + ? "未找到匹配项目。" + : items + .map( + (item) => + `${escapeHtml(item.projectId)}${escapeHtml(item.title)}${badge(item.status)}${escapeHtml(item.owner)}${escapeHtml(item.updatedAt)}`, + ) + .join(""); + return { + scope: query.scope, + q: query.q, + limit: query.limit, + count: result.count, + returned: result.returned, + rows: `${rows}
    项目 ID标题状态智能体更新时间
    `, + }; + } + + if (query.scope === "sessions") { + const result = buildBoundedSearchResult( + snapshot.sessions + .filter((session) => + safeSubstringMatch( + query.q, + session.sessionKey, + session.label, + session.agentId, + session.state, + session.lastMessageAt, + ), + ), + query.limit, + ); + const items = result.items; + const rows = + items.length === 0 + ? "未找到匹配会话。" + : items + .map( + (item) => + `${escapeHtml(item.sessionKey)}${badge(item.state)}${escapeHtml(item.agentId ?? "-")}${escapeHtml(item.label ?? "-")}${escapeHtml(item.lastMessageAt ?? "-")}`, + ) + .join(""); + return { + scope: query.scope, + q: query.q, + limit: query.limit, + count: result.count, + returned: result.returned, + rows: `${rows}
    会话状态助手标签最后活动
    `, + }; + } + + const result = buildBoundedSearchResult( + commanderExceptionsFeed(snapshot).items.filter((item) => + safeSubstringMatch(query.q, item.level, item.code, item.source, item.sourceId, item.route, item.message), + ), + query.limit, + ); + const items = result.items; + const rows = + items.length === 0 + ? "未找到匹配告警。" + : items + .map( + (item) => + `${badge(item.level)}${escapeHtml(item.code)}${escapeHtml(item.sourceId)}${escapeHtml(item.route)}${escapeHtml(item.message)}`, + ) + .join(""); + return { + scope: query.scope, + q: query.q, + limit: query.limit, + count: result.count, + returned: result.returned, + rows: `${rows}
    级别代码来源路由信息
    `, + }; +} + +function renderDashboardSearchResult( + result: DashboardSearchResult | undefined, + language: UiLanguage = "zh", +): string { + if (!result) { + return `
    ${escapeHtml( + pickUiText(language, "Enter a keyword to search by scope.", "输入关键词后可按范围搜索。"), + )}
    `; + } + const summary = + result.count > result.returned + ? pickUiText( + language, + `Scope: ${searchScopeLabel(result.scope, language)} · Keyword: ${result.q} · Showing ${result.returned} of ${result.count} matches`, + `范围:${searchScopeLabel(result.scope, language)} · 关键词:${result.q} · 当前显示 ${result.returned}/${result.count} 条命中`, + ) + : pickUiText( + language, + `Scope: ${searchScopeLabel(result.scope, language)} · Keyword: ${result.q} · Matches: ${result.count}`, + `范围:${searchScopeLabel(result.scope, language)} · 关键词:${result.q} · 命中:${result.count}`, + ); + return `
    ${escapeHtml(summary)}
    ${result.rows}`; +} + +export function buildDashboardSearchResultForSmoke( + snapshot: ReadModelSnapshot, + query: DashboardSearchQuery, +): DashboardSearchResult | undefined { + return buildDashboardSearchResult(snapshot, query); +} + +function resolveDashboardTaskFilters( + searchParams: URLSearchParams, + preferences: UiPreferences, +): TaskQueryFilters { + const incoming = parseTaskFilters(searchParams, false); + if (hasAnyQueryKey(searchParams, ["quick", "status", "owner", "project"])) { + return { + quick: incoming.quick ?? "all", + status: incoming.status, + owner: incoming.owner, + project: incoming.project, + }; + } + + return { + quick: preferences.quickFilter, + status: preferences.taskFilters.status, + owner: preferences.taskFilters.owner, + project: preferences.taskFilters.project, + }; +} + +function resolveCompactStatusStrip(searchParams: URLSearchParams, fallback: boolean): boolean { + const compact = normalizeQueryString(searchParams.get("compact"), "compact", 8, false); + if (!compact) return fallback; + if (compact === "1" || compact.toLowerCase() === "true" || compact.toLowerCase() === "on") return true; + if (compact === "0" || compact.toLowerCase() === "false" || compact.toLowerCase() === "off") return false; + return fallback; +} + +function resolveUsageView(searchParams: URLSearchParams): UsageView { + const usageView = normalizeQueryString(searchParams.get("usage_view"), "usage_view", 16, false); + return usageView === "today" ? "today" : "cumulative"; +} + +function resolveUiLanguage(searchParams: URLSearchParams, fallback: UiLanguage): UiLanguage { + const raw = normalizeQueryString(searchParams.get("lang"), "lang", 8, false); + if (!raw) return fallback; + const normalized = raw.trim().toLowerCase(); + return isUiLanguage(normalized) ? normalized : fallback; +} + +function mergeUiPreferencesPatch(current: UiPreferences, payload: Record): UiPreferences { + const next: UiPreferences = { + language: current.language, + compactStatusStrip: current.compactStatusStrip, + quickFilter: current.quickFilter, + taskFilters: { ...current.taskFilters }, + updatedAt: new Date().toISOString(), + }; + + if (payload.language !== undefined) { + if (typeof payload.language !== "string") { + throw new RequestValidationError("language must be a string.", 400); + } + const normalizedLanguage = payload.language.trim().toLowerCase(); + if (!isUiLanguage(normalizedLanguage)) { + throw new RequestValidationError("language must be one of: en, zh", 400); + } + next.language = normalizedLanguage; + } + + if (payload.compactStatusStrip !== undefined) { + if (typeof payload.compactStatusStrip !== "boolean") { + throw new RequestValidationError("compactStatusStrip must be a boolean.", 400); + } + next.compactStatusStrip = payload.compactStatusStrip; + } + + if (payload.quickFilter !== undefined) { + if (typeof payload.quickFilter !== "string") { + throw new RequestValidationError("quickFilter must be a string.", 400); + } + const quick = payload.quickFilter.trim(); + if (!isUiQuickFilter(quick)) { + throw new RequestValidationError( + "quickFilter must be one of: all, attention, todo, in_progress, blocked, done", + 400, + ); + } + next.quickFilter = quick; + } + + if (payload.taskFilters !== undefined) { + const filtersObj = asObject(payload.taskFilters); + if (!filtersObj) { + throw new RequestValidationError("taskFilters must be an object.", 400); + } + + if (filtersObj.status !== undefined) { + if (filtersObj.status === null || filtersObj.status === "") { + next.taskFilters.status = undefined; + } else if (typeof filtersObj.status === "string" && TASK_STATES.includes(filtersObj.status as TaskState)) { + next.taskFilters.status = filtersObj.status as TaskState; + } else { + throw new RequestValidationError("taskFilters.status must be one of: todo, in_progress, blocked, done", 400); + } + } + + if (filtersObj.owner !== undefined) { + next.taskFilters.owner = normalizeOptionalPatchString(filtersObj.owner, "taskFilters.owner", 80); + } + + if (filtersObj.project !== undefined) { + next.taskFilters.project = normalizeOptionalPatchString(filtersObj.project, "taskFilters.project", 120); + } + } + + return next; +} + +function applyTaskFilters(tasks: TaskListItem[], filters: TaskQueryFilters): TaskListItem[] { + const now = Date.now(); + return tasks.filter((task) => { + if (filters.quick && !matchesQuickFilter(task, filters.quick, now)) return false; + if (filters.status && task.status !== filters.status) return false; + if (filters.owner && task.owner.toLowerCase() !== filters.owner.toLowerCase()) return false; + if (filters.project && task.projectId.toLowerCase() !== filters.project.toLowerCase()) return false; + return true; + }); +} + +function applyProjectFilters( + projects: ReadModelSnapshot["projects"]["projects"], + filters: ProjectQueryFilters, +): ReadModelSnapshot["projects"]["projects"] { + return projects.filter((project) => { + if (filters.status && project.status !== filters.status) return false; + if (filters.owner && project.owner.toLowerCase() !== filters.owner.toLowerCase()) return false; + if (filters.projectId && project.projectId.toLowerCase() !== filters.projectId.toLowerCase()) return false; + return true; + }); +} + +function buildLinkageGraph(snapshot: ReadModelSnapshot): LinkageGraph { + const nodes = new Map(); + const edges = new Map(); + const sessionByKey = new Map(snapshot.sessions.map((session) => [session.sessionKey, session])); + + for (const project of snapshot.projects.projects) { + addGraphNode(nodes, { + id: `project:${project.projectId}`, + type: "project", + label: project.title, + status: project.status, + }); + } + + for (const task of snapshot.tasks.tasks) { + const taskNodeId = `task:${task.projectId}:${task.taskId}`; + addGraphNode(nodes, { + id: taskNodeId, + type: "task", + label: task.title, + status: task.status, + }); + + addGraphEdge(edges, { + id: `project_task:${task.projectId}:${task.taskId}`, + from: `project:${task.projectId}`, + to: taskNodeId, + type: "project_task", + }); + + for (const sessionKey of task.sessionKeys) { + const session = sessionByKey.get(sessionKey); + addGraphNode(nodes, { + id: `session:${sessionKey}`, + type: "session", + label: session?.label ?? sessionKey, + status: session?.state ?? "unknown", + }); + + addGraphEdge(edges, { + id: `task_session:${task.projectId}:${task.taskId}:${sessionKey}`, + from: taskNodeId, + to: `session:${sessionKey}`, + type: "task_session", + }); + + addGraphEdge(edges, { + id: `project_session:${task.projectId}:${sessionKey}`, + from: `project:${task.projectId}`, + to: `session:${sessionKey}`, + type: "project_session", + }); + } + } + + for (const session of snapshot.sessions) { + addGraphNode(nodes, { + id: `session:${session.sessionKey}`, + type: "session", + label: session.label ?? session.sessionKey, + status: session.state, + }); + + if (session.agentId) { + addGraphNode(nodes, { + id: `agent:${session.agentId}`, + type: "agent", + label: session.agentId, + }); + addGraphEdge(edges, { + id: `agent_session:${session.agentId}:${session.sessionKey}`, + from: `agent:${session.agentId}`, + to: `session:${session.sessionKey}`, + type: "agent_session", + }); + } + } + + const nodeValues = [...nodes.values()].sort((a, b) => a.id.localeCompare(b.id)); + const edgeValues = [...edges.values()].sort((a, b) => a.id.localeCompare(b.id)); + + return { + generatedAt: new Date().toISOString(), + nodes: nodeValues, + edges: edgeValues, + counts: { + nodes: nodeValues.length, + edges: edgeValues.length, + projects: nodeValues.filter((node) => node.type === "project").length, + tasks: nodeValues.filter((node) => node.type === "task").length, + sessions: nodeValues.filter((node) => node.type === "session").length, + agents: nodeValues.filter((node) => node.type === "agent").length, + }, + }; +} + +function addGraphNode(target: Map, node: GraphNode): void { + if (target.has(node.id)) return; + target.set(node.id, node); +} + +function addGraphEdge(target: Map, edge: GraphEdge): void { + if (target.has(edge.id)) return; + target.set(edge.id, edge); +} + +function normalizeDocCategoryKey(value: string): string { + return value.trim().toLowerCase().replace(/\s+/g, "-"); +} + +function extractDateFromName(value: string): string | undefined { + const match = value.match(/(20\d{2}-\d{2}-\d{2})/); + return match ? match[1] : undefined; +} + +function toPlainSummary(input: string, maxLength: number): string { + const compact = input + .replace(/`{1,3}[^`]*`{1,3}/g, " ") + .replace(/[#>*_\-\[\]\(\)!]/g, " ") + .replace(/\s+/g, " ") + .trim(); + if (!compact) return "暂无摘要。"; + if (compact.length <= maxLength) return compact; + return `${compact.slice(0, maxLength - 1)}…`; +} + +function extractMarkdownHeading(input: string): string | undefined { + const line = input + .split(/\r?\n/) + .map((row) => row.trim()) + .find((row) => row.startsWith("#")); + if (!line) return undefined; + return line.replace(/^#+\s*/, "").trim() || undefined; +} + +async function safeReadTextFile(path: string): Promise { + try { + return await readFile(path, "utf8"); + } catch { + return undefined; + } +} + +function normalizeEvidenceText(input: string): string { + return input + .toLowerCase() + .replace(/[`*_#>\[\]\(\)!|]+/g, " ") + .replace(/\s+/g, " ") + .trim(); +} + +function extractLabeledField(input: string, labels: string[]): string | undefined { + for (const rawLine of input.split(/\r?\n/)) { + const line = rawLine.replace(/\*\*/g, "").replace(/`/g, "").trim().replace(/^[-*]\s*/, ""); + if (!line) continue; + const lower = line.toLowerCase(); + for (const label of labels) { + const prefix = `${label.toLowerCase()}:`; + if (!lower.startsWith(prefix)) continue; + const value = line.slice(prefix.length).trim(); + if (value) return value; + } + } + return undefined; +} + +function resolveStaffWorkspaceRoot(member: TeamMemberSnapshot): string { + const key = normalizeLookupKey(member.agentId); + if (key === "main") return OPENCLAW_WORKSPACE_ROOT; + const workspace = member.workspace.trim(); + if (workspace && workspace !== "未标注" && workspace !== "unlisted") return workspace; + return join(OPENCLAW_WORKSPACE_ROOT, "agents", member.agentId); +} + +async function loadStaffRoleEvidence(member: TeamMemberSnapshot): Promise { + const output: string[] = []; + const workspaceRoot = resolveStaffWorkspaceRoot(member); + for (const fileName of STAFF_ROLE_EVIDENCE_FILE_CANDIDATES) { + const raw = await safeReadTextFile(join(workspaceRoot, fileName)); + if (raw?.trim()) output.push(raw); + } + const openclawConfig = await safeReadTextFile(OPENCLAW_CONFIG_PATH); + if (openclawConfig?.trim()) output.push(openclawConfig); + for (const candidate of OPENCLAW_CRON_JOBS_CANDIDATES) { + const cronJobs = await safeReadTextFile(candidate); + if (cronJobs?.trim()) { + output.push(cronJobs); + break; + } + } + return output; +} + +async function resolveStaffRoleLabel(member: TeamMemberSnapshot, language: UiLanguage = "zh"): Promise { + const roleEvidence = await loadStaffRoleEvidence(member); + const combined = roleEvidence.join("\n"); + const normalized = normalizeEvidenceText(combined); + const explicitRole = + roleEvidence + .map((entry) => extractLabeledField(entry, ["Role", "职责", "角色"])) + .find((value) => value && value.trim().length > 0) ?? ""; + const explicitMission = + roleEvidence + .map((entry) => extractLabeledField(entry, ["Mission", "任务", "目标"])) + .find((value) => value && value.trim().length > 0) ?? ""; + const key = normalizeLookupKey(member.agentId); + + if ( + key === "monkey" && + (normalized.includes("youtube-to-article") || + combined.includes("把 YouTube 视频转成增值长文章") || + combined.includes("YouTube 视频转成增值长文章")) + ) { + return pickUiText(language, "YouTube to article writing", "YouTube 视频转长文"); + } + + if ( + key === "dolphin" && + (normalized.includes("value_add_creator") || + combined.includes("高价值、可直接发布的最终内容") || + combined.includes("增值型创作者")) + ) { + return pickUiText(language, "High-value content creation", "高价值内容创作"); + } + + if ( + key === "pandas" && + (normalized.includes("control-center project end-to-end") || + normalized.includes("control center project end to end") || + combined.includes("控制中心") || + combined.includes("唯一主任务")) + ) { + return pickUiText(language, "Control Center delivery", "控制中心开发与交付"); + } + + if ( + key === "coq" && + (combined.includes("Coq-每日新闻") || + normalized.includes("morning research") || + normalized.includes("trend report") || + combined.includes("每日报告")) + ) { + return pickUiText(language, "Daily news and trend briefings", "每日情报与趋势简报"); + } + + if ( + key === "otter" && + (combined.includes("晨报") || + combined.includes("邮箱提醒") || + normalized.includes("calendar") || + normalized.includes("weather") || + normalized.includes("assistant")) + ) { + return pickUiText(language, "Personal assistance and reminders", "私人助理与提醒"); + } + + if ( + key === "tiger" && + (normalized.includes("tiger-security") || + normalized.includes("security-audit") || + normalized.includes("update-status") || + (normalized.includes("security") && normalized.includes("update")) || + (combined.includes("安全") && combined.includes("更新"))) + ) { + return pickUiText(language, "Security and updates", "安全和更新"); + } + + if ( + key === "main" && + (combined.includes("Lion") || + normalized.includes("lion bot account") || + normalized.includes("assistant name: lion") || + combined.includes("指挥官")) + ) { + return pickUiText(language, "Main control and coordination", "主控与协调"); + } + + if (key === "codex" || normalized.includes("codex")) { + return pickUiText(language, "Coding automation", "自动化编码执行"); + } + + const explicit = `${explicitRole} ${explicitMission}`.trim(); + if ( + explicit && + (normalizeEvidenceText(explicit).includes("youtube") || normalizeEvidenceText(explicit).includes("article")) + ) { + return pickUiText(language, "YouTube to article writing", "YouTube 视频转长文"); + } + if (explicit && (normalizeEvidenceText(explicit).includes("control-center") || explicit.includes("控制中心"))) { + return pickUiText(language, "Control Center delivery", "控制中心开发与交付"); + } + if (explicit && (normalizeEvidenceText(explicit).includes("creator") || explicit.includes("创作"))) { + return pickUiText(language, "High-value content creation", "高价值内容创作"); + } + + return pickUiText(language, "Role not defined in workspace", "工作区未写明职责"); +} + +async function listFileEntries(dir: string): Promise> { + try { + const rows = await readdir(dir, { withFileTypes: true }); + const files = rows.filter((row) => row.isFile()); + const result: Array<{ name: string; path: string; updatedAt: string; size: number }> = []; + for (const file of files) { + const fullPath = join(dir, file.name); + try { + const meta = await stat(fullPath); + result.push({ + name: file.name, + path: fullPath, + updatedAt: meta.mtime.toISOString(), + size: meta.size, + }); + } catch { + continue; + } + } + return result.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)); + } catch { + return []; + } +} + +function normalizeEditableFileScope(value: string | undefined): EditableFileScope | undefined { + if (value === "memory" || value === "workspace") return value; + return undefined; +} + +async function buildEditableFileEntry(input: { + scope: EditableFileScope; + category: string; + sourcePath: string; + relativeBase?: string; + facetKey?: string; + facetLabel?: string; +}): Promise { + try { + const meta = await stat(input.sourcePath); + if (!meta.isFile() || meta.size > EDITABLE_TEXT_FILE_MAX_BYTES) return undefined; + const raw = await safeReadTextFile(input.sourcePath); + if (raw === undefined) return undefined; + const ext = extname(input.sourcePath).toLowerCase(); + const relativePath = input.relativeBase + ? relative(input.relativeBase, input.sourcePath) || basename(input.sourcePath) + : basename(input.sourcePath); + return { + scope: input.scope, + title: extractMarkdownHeading(raw) || basename(input.sourcePath, ext) || basename(input.sourcePath), + excerpt: toPlainSummary(raw, 160), + category: input.category, + sourcePath: input.sourcePath, + relativePath, + updatedAt: meta.mtime.toISOString(), + size: meta.size, + facetKey: input.facetKey, + facetLabel: input.facetLabel, + }; + } catch { + return undefined; + } +} + +async function walkWorkspaceMarkdownFiles(root: string, currentDir = root): Promise { + try { + const rows = await readdir(currentDir, { withFileTypes: true }); + const output: string[] = []; + for (const row of rows) { + const fullPath = join(currentDir, row.name); + if (row.isDirectory()) { + if (WORKSPACE_EDITABLE_SKIP_DIRS.has(row.name)) continue; + output.push(...(await walkWorkspaceMarkdownFiles(root, fullPath))); + continue; + } + if (!row.isFile()) continue; + const ext = extname(row.name).toLowerCase(); + if (!WORKSPACE_EDITABLE_EXTENSIONS.has(ext)) continue; + output.push(fullPath); + } + return output; + } catch { + return []; + } +} + +async function listEditableMemoryFiles(): Promise { + const output: EditableFileEntry[] = []; + const seen = new Set(); + const mainFacetKey = "main"; + const mainFacetLabel = "Main"; + const agentScopes = await loadEditableAgentScopes(); + + const append = async (entry: EditableFileEntry | undefined): Promise => { + if (!entry) return; + const key = resolve(entry.sourcePath); + if (seen.has(key)) return; + seen.add(key); + output.push(entry); + }; + + const mainRootFiles = [ + join(OPENCLAW_WORKSPACE_ROOT, "MEMORY.md"), + ]; + for (const candidateFile of mainRootFiles) { + await append( + await buildEditableFileEntry({ + scope: "memory", + category: "Main 长期记忆", + sourcePath: candidateFile, + relativeBase: OPENCLAW_WORKSPACE_ROOT, + facetKey: mainFacetKey, + facetLabel: mainFacetLabel, + }), + ); + } + + const mainMemoryDir = join(OPENCLAW_WORKSPACE_ROOT, "memory"); + const mainMemoryFiles = await listFileEntries(mainMemoryDir); + for (const file of mainMemoryFiles) { + const ext = extname(file.name).toLowerCase(); + if (!MEMORY_EDITABLE_EXTENSIONS.has(ext)) continue; + await append( + await buildEditableFileEntry({ + scope: "memory", + category: "Main 记忆记录", + sourcePath: file.path, + relativeBase: OPENCLAW_WORKSPACE_ROOT, + facetKey: mainFacetKey, + facetLabel: mainFacetLabel, + }), + ); + } + + for (const scope of agentScopes) { + if (scope.facetKey === "main") continue; + const agentProfileFiles = ["MEMORY.md"]; + for (const fileName of agentProfileFiles) { + await append( + await buildEditableFileEntry({ + scope: "memory", + category: `${scope.facetLabel} 长期记忆`, + sourcePath: join(scope.workspaceRoot, fileName), + relativeBase: OPENCLAW_WORKSPACE_ROOT, + facetKey: scope.facetKey, + facetLabel: scope.facetLabel, + }), + ); + } + const agentMemoryDir = join(scope.workspaceRoot, "memory"); + const agentMemoryFiles = await listFileEntries(agentMemoryDir); + for (const file of agentMemoryFiles) { + const ext = extname(file.name).toLowerCase(); + if (!MEMORY_EDITABLE_EXTENSIONS.has(ext)) continue; + await append( + await buildEditableFileEntry({ + scope: "memory", + category: `${scope.facetLabel} 记忆记录`, + sourcePath: file.path, + relativeBase: OPENCLAW_WORKSPACE_ROOT, + facetKey: scope.facetKey, + facetLabel: scope.facetLabel, + }), + ); + } + } + + return output.sort( + (a, b) => + (a.facetKey === "main" ? -1 : b.facetKey === "main" ? 1 : (a.facetLabel ?? "").localeCompare(b.facetLabel ?? "", "zh-Hans-CN")) || + b.updatedAt.localeCompare(a.updatedAt) || + a.relativePath.localeCompare(b.relativePath, "zh-Hans-CN"), + ); +} + +async function listMemoryFacetOptions(): Promise> { + const scopes = await loadEditableAgentScopes(); + return scopes.map((scope) => ({ key: scope.facetKey, label: scope.facetLabel })); +} + +async function listWorkspaceFacetOptions(): Promise> { + const scopes = await loadEditableAgentScopes(); + return scopes.map((scope) => ({ key: scope.facetKey, label: scope.facetLabel })); +} + +async function listEditableWorkspaceFiles(): Promise { + const output: EditableFileEntry[] = []; + const seen = new Set(); + const agentScopes = await loadEditableAgentScopes(); + + const append = async (entry: EditableFileEntry | undefined): Promise => { + if (!entry) return; + const key = resolve(entry.sourcePath); + if (seen.has(key)) return; + seen.add(key); + output.push(entry); + }; + + for (const relativePath of SHARED_DOCUMENT_FILE_CANDIDATES) { + await append( + await buildEditableFileEntry({ + scope: "workspace", + category: "Main 核心文档", + sourcePath: join(OPENCLAW_WORKSPACE_ROOT, relativePath), + relativeBase: OPENCLAW_WORKSPACE_ROOT, + facetKey: "main", + facetLabel: "Main", + }), + ); + } + + for (const scope of agentScopes) { + if (scope.facetKey === "main") continue; + for (const fileName of AGENT_DOCUMENT_FILE_CANDIDATES) { + await append( + await buildEditableFileEntry({ + scope: "workspace", + category: `${scope.facetLabel} 核心文档`, + sourcePath: join(scope.workspaceRoot, fileName), + relativeBase: OPENCLAW_WORKSPACE_ROOT, + facetKey: scope.facetKey, + facetLabel: scope.facetLabel, + }), + ); + } + } + + return output.sort((a, b) => { + const facetA = a.facetLabel ?? ""; + const facetB = b.facetLabel ?? ""; + if (facetA !== facetB) { + if (facetA === "Main") return -1; + if (facetB === "Main") return 1; + return facetA.localeCompare(facetB, "zh-Hans-CN"); + } + const priority = documentFilePriority(a.relativePath) - documentFilePriority(b.relativePath); + if (priority !== 0) return priority; + return a.relativePath.localeCompare(b.relativePath, "zh-Hans-CN"); + }); +} + +function documentFilePriority(relativePath: string): number { + const fileName = basename(relativePath).toLowerCase(); + const order = [ + "agents.md", + "heartbeat.md", + "tools.md", + "readme.md", + "bootstrap.md", + "notebook.md", + "focus.md", + "inbox.md", + "routines.md", + "learnings.md", + ]; + const index = order.indexOf(fileName); + return index === -1 ? order.length + 1 : index; +} + +async function listEditableFiles(scope: EditableFileScope): Promise { + if (scope === "memory") return listEditableMemoryFiles(); + return listEditableWorkspaceFiles(); +} + +async function loadEditableAgentScopes(): Promise { + const configured = await loadEditableAgentScopesFromConfig(); + if (configured.status === "configured" && configured.scopes.length > 0) { + return configured.scopes; + } + if (configured.status === "config_invalid") { + return [buildMainEditableAgentScope()]; + } + return loadEditableAgentScopesFromWorkspaceDirs(); +} + +async function loadEditableAgentScopesFromConfig(): Promise<{ + status: EditableAgentScopeConfigStatus; + scopes: EditableAgentScope[]; +}> { + const raw = await safeReadTextFile(OPENCLAW_CONFIG_PATH); + if (!raw?.trim()) return { status: "config_missing", scopes: [] }; + try { + const scopes = resolveEditableAgentScopesFromConfig(JSON.parse(raw) as unknown); + return { + status: scopes.length > 0 ? "configured" : "config_invalid", + scopes: scopes.length > 0 ? scopes : [buildMainEditableAgentScope()], + }; + } catch { + return { status: "config_invalid", scopes: [buildMainEditableAgentScope()] }; + } +} + +async function loadEditableAgentScopesFromWorkspaceDirs(): Promise { + const output: EditableAgentScope[] = [buildMainEditableAgentScope()]; + const seen = new Set(["main"]); + const agentsRoot = join(OPENCLAW_WORKSPACE_ROOT, "agents"); + try { + const agentDirs = await readdir(agentsRoot, { withFileTypes: true }); + for (const row of agentDirs) { + if (!row.isDirectory()) continue; + const agentId = row.name.trim(); + const facetKey = normalizeLookupKey(agentId); + if (!agentId || !facetKey || seen.has(facetKey)) continue; + seen.add(facetKey); + output.push({ + agentId, + facetKey, + facetLabel: humanizeOperatorLabel(agentId), + workspaceRoot: join(agentsRoot, agentId), + }); + } + } catch { + // ignore + } + return output.sort(compareEditableAgentScopes); +} + +function resolveEditableAgentScopesFromConfig(input: unknown): EditableAgentScope[] { + const root = asObject(input); + const agents = asObject(root?.agents); + const list = asArray(agents?.list); + const output: EditableAgentScope[] = []; + const seen = new Set(); + + for (const item of list) { + const row = asObject(item); + if (!row) continue; + const rawId = asString(row.id)?.trim() ?? asString(row.name)?.trim() ?? ""; + const facetKey = normalizeLookupKey(rawId); + if (!rawId || !facetKey || seen.has(facetKey)) continue; + seen.add(facetKey); + const workspaceRoot = + facetKey === "main" + ? OPENCLAW_WORKSPACE_ROOT + : resolve(asString(row.workspace)?.trim() || join(OPENCLAW_WORKSPACE_ROOT, "agents", rawId)); + output.push({ + agentId: rawId, + facetKey, + facetLabel: facetKey === "main" ? "Main" : humanizeOperatorLabel(rawId), + workspaceRoot, + }); + } + + return ensureMainEditableAgentScope(output).sort(compareEditableAgentScopes); +} + +export function resolveEditableAgentScopesFromConfigForSmoke(input: unknown): EditableAgentScope[] { + return resolveEditableAgentScopesFromConfig(input); +} + +export function resolveEditableAgentScopesWithFallbackForSmoke(input: { + configText?: string; + workspaceAgentIds?: string[]; +}): EditableAgentScope[] { + const configured = resolveEditableAgentScopesFromConfigText(input.configText); + if (configured.status === "configured" && configured.scopes.length > 0) { + return configured.scopes; + } + if (configured.status === "config_invalid") { + return [buildMainEditableAgentScope()]; + } + return resolveEditableAgentScopesFromWorkspaceAgentIds(input.workspaceAgentIds ?? []); +} + +function compareEditableAgentScopes(a: EditableAgentScope, b: EditableAgentScope): number { + if (a.facetKey === "main") return -1; + if (b.facetKey === "main") return 1; + return a.facetLabel.localeCompare(b.facetLabel, "zh-Hans-CN"); +} + +function buildMainEditableAgentScope(): EditableAgentScope { + return { + agentId: "main", + facetKey: "main", + facetLabel: "Main", + workspaceRoot: OPENCLAW_WORKSPACE_ROOT, + }; +} + +function ensureMainEditableAgentScope(scopes: EditableAgentScope[]): EditableAgentScope[] { + if (scopes.some((scope) => scope.facetKey === "main")) return scopes; + return [buildMainEditableAgentScope(), ...scopes]; +} + +function resolveEditableAgentScopesFromConfigText(raw: string | undefined): { + status: EditableAgentScopeConfigStatus; + scopes: EditableAgentScope[]; +} { + if (!raw?.trim()) return { status: "config_missing", scopes: [] }; + try { + const scopes = resolveEditableAgentScopesFromConfig(JSON.parse(raw) as unknown); + return { + status: scopes.length > 0 ? "configured" : "config_invalid", + scopes: scopes.length > 0 ? scopes : [buildMainEditableAgentScope()], + }; + } catch { + return { status: "config_invalid", scopes: [buildMainEditableAgentScope()] }; + } +} + +function resolveEditableAgentScopesFromWorkspaceAgentIds(agentIds: string[]): EditableAgentScope[] { + const seen = new Set(["main"]); + const scopes: EditableAgentScope[] = [buildMainEditableAgentScope()]; + for (const rawId of agentIds) { + const agentId = rawId.trim(); + const facetKey = normalizeLookupKey(agentId); + if (!agentId || !facetKey || seen.has(facetKey)) continue; + seen.add(facetKey); + scopes.push({ + agentId, + facetKey, + facetLabel: humanizeOperatorLabel(agentId), + workspaceRoot: join(OPENCLAW_WORKSPACE_ROOT, "agents", agentId), + }); + } + return scopes.sort(compareEditableAgentScopes); +} + +async function resolveEditableFileEntry( + scope: EditableFileScope, + sourcePath: string, +): Promise { + const target = resolve(sourcePath); + const entries = await listEditableFiles(scope); + return entries.find((entry) => resolve(entry.sourcePath) === target); +} + +async function readEditableFile(scope: EditableFileScope, sourcePath: string): Promise<{ + entry: EditableFileEntry; + content: string; +} | undefined> { + const entry = await resolveEditableFileEntry(scope, sourcePath); + if (!entry) return undefined; + const content = await safeReadTextFile(entry.sourcePath); + if (content === undefined) return undefined; + return { entry, content }; +} + +async function writeEditableFileContent( + scope: EditableFileScope, + sourcePath: string, + content: string, +): Promise<{ entry: EditableFileEntry; content: string } | undefined> { + const entry = await resolveEditableFileEntry(scope, sourcePath); + if (!entry) return undefined; + await writeFile(entry.sourcePath, content, "utf8"); + return readEditableFile(scope, entry.sourcePath); +} + +async function loadMemoryEntries(): Promise<{ daily: MemoryEntry[]; longTerm: MemoryEntry[] }> { + const daily: MemoryEntry[] = []; + for (const candidateDir of MEMORY_DIR_CANDIDATES) { + const files = await listFileEntries(candidateDir); + for (const file of files.slice(0, 36)) { + const ext = extname(file.name).toLowerCase(); + if (ext !== ".md" && ext !== ".markdown" && ext !== ".txt") continue; + if (file.size > 420 * 1024) continue; + const raw = await safeReadTextFile(file.path); + if (!raw) continue; + const title = extractMarkdownHeading(raw) || basename(file.name, ext) || file.name; + const day = extractDateFromName(file.name) ?? file.updatedAt.slice(0, 10); + daily.push({ + day, + title, + excerpt: toPlainSummary(raw, 180), + sourcePath: file.path, + }); + } + } + const longTerm: MemoryEntry[] = []; + for (const candidateFile of LONG_TERM_MEMORY_FILE_CANDIDATES) { + const raw = await safeReadTextFile(candidateFile); + if (!raw) continue; + const ext = extname(candidateFile).toLowerCase(); + const title = extractMarkdownHeading(raw) || basename(candidateFile, ext) || basename(candidateFile); + longTerm.push({ + day: "长期", + title, + excerpt: toPlainSummary(raw, 220), + sourcePath: candidateFile, + }); + } + return { + daily: daily + .sort((a, b) => b.day.localeCompare(a.day) || a.title.localeCompare(b.title, "zh-Hans-CN")) + .slice(0, 40), + longTerm, + }; +} + +async function loadDocHubEntries(chatEntries: StructuredChatDocEntry[] = []): Promise { + const output: DocEntry[] = []; + for (const candidate of DOC_HUB_DIR_CANDIDATES) { + const files = await listFileEntries(candidate.dir); + for (const file of files.slice(0, 40)) { + const ext = extname(file.name).toLowerCase(); + if (![".md", ".markdown", ".txt", ".json"].includes(ext)) continue; + if (file.size > 600 * 1024) continue; + const raw = await safeReadTextFile(file.path); + if (!raw) continue; + const title = + extractMarkdownHeading(raw) || + basename(file.name, ext) || + file.name; + output.push({ + title, + excerpt: toPlainSummary(raw, 180), + category: candidate.category, + sourcePath: file.path, + updatedAt: file.updatedAt, + sourceType: "file", + }); + } + } + for (const entry of chatEntries) { + output.push({ + title: entry.title, + excerpt: entry.excerpt, + category: `聊天输出 · ${entry.category}`, + sourcePath: `/sessions/${encodeURIComponent(entry.sourceSessionKey)}`, + updatedAt: entry.updatedAt, + sourceType: "chat", + sourceSessionKey: entry.sourceSessionKey, + sourceAgentId: entry.sourceAgentId, + }); + } + return output + .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)) + .slice(0, 120); +} + +async function renderEditableFileWorkbench(input: { + scope: EditableFileScope; + language: UiLanguage; + title: string; + description: string; + entries: EditableFileEntry[]; + emptyMessage: string; + defaultFacetKey?: string; + includeAllFacet?: boolean; + facetOptions?: Array<{ key: string; label: string }>; +}): Promise { + const t = (en: string, zh: string): string => pickUiText(input.language, en, zh); + const localizeFacetLabel = (label: string | undefined): string => { + const value = label?.trim() ?? ""; + if (!value) return ""; + if (value === "共享") return t("Shared", "共享"); + return value; + }; + const localizeCategoryLabel = (value: string): string => { + const trimmed = value.trim(); + if (!trimmed) return value; + if (trimmed === "共享文档") return t("Shared docs", "共享文档"); + if (trimmed === "Main 长期记忆") return t("Main long-term memory", "Main 长期记忆"); + if (trimmed === "Main 记忆记录") return t("Main memory log", "Main 记忆记录"); + if (trimmed.endsWith(" 长期记忆")) return `${trimmed.slice(0, -5)} ${t("long-term memory", "长期记忆")}`; + if (trimmed.endsWith(" 记忆记录")) return `${trimmed.slice(0, -5)} ${t("memory log", "记忆记录")}`; + if (trimmed.endsWith(" 核心文档")) return `${trimmed.slice(0, -5)} ${t("core docs", "核心文档")}`; + return trimmed; + }; + if (input.entries.length === 0) { + return `
    +

    ${escapeHtml(input.title)}

    +
    ${escapeHtml(input.description)}
    +
    ${escapeHtml(input.emptyMessage)}
    +
    `; + } + + const normalizeFacetKey = (value: string | undefined): string => + (value ?? "all").trim().toLowerCase(); + + const discoveredFacetOptions = input.entries + .filter((entry) => entry.facetKey && entry.facetLabel) + .reduce>((acc, entry) => { + if (!entry.facetKey || !entry.facetLabel) return acc; + const key = normalizeFacetKey(entry.facetKey); + if (!key) return acc; + if (acc.some((item) => item.key === key)) return acc; + acc.push({ key, label: entry.facetLabel }); + return acc; + }, []); + const facetOptions = [...(input.facetOptions ?? []), ...discoveredFacetOptions] + .reduce>((acc, item) => { + const key = normalizeFacetKey(item.key); + const label = item.label?.trim(); + if (!key || !label) return acc; + if (acc.some((entry) => entry.key === key)) return acc; + acc.push({ key, label }); + return acc; + }, []) + .sort((a, b) => { + if (a.key === "main") return -1; + if (b.key === "main") return 1; + if (a.key === "shared") return -1; + if (b.key === "shared") return 1; + return a.label.localeCompare(b.label, "zh-Hans-CN"); + }); + const requestedDefaultFacet = normalizeFacetKey(input.defaultFacetKey); + const defaultFacetKey = + requestedDefaultFacet && facetOptions.some((item) => item.key === requestedDefaultFacet) + ? requestedDefaultFacet + : input.includeAllFacet === false + ? facetOptions[0]?.key ?? "all" + : "all"; + const firstEntry = + input.entries.find((entry) => normalizeFacetKey(entry.facetKey) === defaultFacetKey) ?? input.entries[0]; + const initialContent = (await safeReadTextFile(firstEntry.sourcePath)) ?? ""; + const facetSwitcherHtml = + facetOptions.length <= 1 + ? "" + : `
    + ${input.includeAllFacet === false + ? "" + : ``} + ${facetOptions + .map( + (item) => + ``, + ) + .join("")} +
    `; + const tokenHint = !LOCAL_TOKEN_AUTH_REQUIRED + ? t("This environment allows direct save.", "当前环境允许直接保存。") + : LOCAL_API_TOKEN + ? t("Enter the local token when saving.", "保存时输入本地令牌。") + : t("LOCAL_API_TOKEN is not configured in this environment. Save will be blocked.", "当前环境未配置 LOCAL_API_TOKEN,保存会被拦截。"); + const tokenField = + LOCAL_TOKEN_AUTH_REQUIRED && LOCAL_API_TOKEN + ? `` + : ""; + + return `
    +

    ${escapeHtml(input.title)}

    +
    ${escapeHtml(input.description)}
    +
    ${escapeHtml(t("Files", "文件数"))}${escapeHtml(input.language === "en" ? ": " : ":")}${input.entries.length} · ${escapeHtml(t("Saving writes directly back to the source file.", "保存后直接写回源文件。"))}
    +
    + +
    +
    +
    +
    ${escapeHtml(firstEntry.title)}
    +
    ${escapeHtml(firstEntry.sourcePath)}
    +
    ${escapeHtml(t("Updated", "更新于"))} ${escapeHtml(firstEntry.updatedAt)} · ${formatInt(firstEntry.size)} bytes
    +
    +
    + ${tokenField} + + +
    +
    + +
    ${escapeHtml(tokenHint)}
    +
    +
    +
    `; +} + +function renderStructuredChatDocSummary(entries: StructuredChatDocEntry[]): string { + if (entries.length === 0) { + return '
    尚无聊天输出结构化入库记录。
    '; + } + return `
      ${entries + .slice(0, 16) + .map( + (entry) => `
    • ${escapeHtml(entry.title)}
      ${escapeHtml(entry.excerpt)}
      会话 ${escapeHtml(entry.sourceSessionKey)} · 更新 ${escapeHtml(entry.updatedAt)}
    • `, + ) + .join("")}
    `; +} + +async function loadTeamSnapshot(officeRoster: AgentRosterSnapshot): Promise { + const sourcePath = OPENCLAW_CONFIG_PATH; + const fallbackMission = "构建可持续自治的 AI 员工体系,持续完成高价值任务。"; + const missionFromAgentDoc = await safeReadTextFile(join(AGENT_ROOT_DIR, "AGENTS.md")); + const missionLine = missionFromAgentDoc + ?.split(/\r?\n/) + .map((line) => line.trim()) + .find((line) => line.startsWith("- ") && line.toLowerCase().includes("objective")) + ?.replace(/^-+\s*/, "") + .trim(); + const missionStatement = missionLine && missionLine.length > 8 ? missionLine : fallbackMission; + + const raw = await safeReadTextFile(sourcePath); + if (!raw) { + return { + missionStatement, + members: officeRoster.entries.map((entry) => ({ + agentId: entry.agentId, + displayName: entry.displayName, + model: "未标注", + workspace: "未标注", + toolsProfile: "default", + })), + sourcePath, + detail: "openclaw.json 未找到,已回退为运行时员工名录。", + }; + } + try { + const parsed = JSON.parse(raw) as Record; + const agentsRoot = parsed.agents as Record | undefined; + const defaults = (agentsRoot?.defaults ?? {}) as Record; + const defaultModel = + (defaults.model as Record | undefined)?.primary; + const list = Array.isArray(agentsRoot?.list) ? agentsRoot?.list : []; + const members: TeamMemberSnapshot[] = []; + for (const item of list) { + if (!item || typeof item !== "object") continue; + const obj = item as Record; + const id = typeof obj.id === "string" ? obj.id.trim() : ""; + if (!id) continue; + const tools = (obj.tools ?? {}) as Record; + members.push({ + agentId: id, + displayName: + (typeof obj.name === "string" && obj.name.trim()) || id, + model: + (typeof obj.model === "string" && obj.model.trim()) || + (typeof defaultModel === "string" ? defaultModel : "未标注"), + workspace: + (typeof obj.workspace === "string" && obj.workspace.trim()) || "未标注", + toolsProfile: + (typeof tools.profile === "string" && tools.profile.trim()) || "default", + }); + } + return { + missionStatement, + members: members.sort((a, b) => a.agentId.localeCompare(b.agentId, "zh-Hans-CN")), + sourcePath, + detail: `已从 openclaw.json 读取 ${members.length} 名员工。`, + }; + } catch { + return { + missionStatement, + members: officeRoster.entries.map((entry) => ({ + agentId: entry.agentId, + displayName: entry.displayName, + model: "未标注", + workspace: "未标注", + toolsProfile: "default", + })), + sourcePath, + detail: "openclaw.json 解析失败,已回退为运行时员工名录。", + }; + } +} + +function summarizeFilters(filters: TaskQueryFilters): string { + const labels: string[] = []; + if (filters.quick) labels.push(`quick=${filters.quick}`); + if (filters.status) labels.push(`status=${filters.status}`); + if (filters.owner) labels.push(`owner=${filters.owner}`); + if (filters.project) labels.push(`project=${filters.project}`); + return labels.length > 0 ? `filters(${labels.join(", ")})` : "filters(none)"; +} + +function matchesQuickFilter(task: TaskListItem, quick: UiQuickFilter, now: number): boolean { + if (quick === "all") return true; + if (quick === "attention") { + return task.status === "blocked" || isTaskDueNow(task, now); + } + return task.status === quick; +} + +function isTaskDueNow(task: TaskListItem, now: number): boolean { + if (task.status === "done") return false; + if (!task.dueAt) return false; + const dueMs = Date.parse(task.dueAt); + if (Number.isNaN(dueMs)) return false; + return dueMs <= now; +} + +function hasAnyQueryKey(searchParams: URLSearchParams, keys: string[]): boolean { + return keys.some((key) => searchParams.has(key)); +} + +function renderLanguageToggle(filters: TaskQueryFilters, options: DashboardOptions): string { + const enHref = buildHomeHref(filters, options.compactStatusStrip, options.section, "en", options.usageView); + const zhHref = buildHomeHref(filters, options.compactStatusStrip, options.section, "zh", options.usageView); + const enClass = options.language === "en" ? " class=\"active\"" : ""; + const zhClass = options.language === "zh" ? " class=\"active\"" : ""; + const label = pickUiText(options.language, "Language:", "语言:"); + const zhLabel = pickUiText(options.language, "中文", "中文"); + return `
    ${label} EN / ${zhLabel}
    `; +} + +function buildHomeHref( + filters: TaskQueryFilters, + compactStatusStrip: boolean, + section: DashboardSection = "overview", + language: UiLanguage = "en", + usageView: UsageView = "cumulative", +): string { + const query = buildHomeQuery(filters, compactStatusStrip, section, language, usageView); + return query ? `/?${query}` : "/"; +} + +function buildHomeQuery( + filters: TaskQueryFilters, + compactStatusStrip: boolean, + section: DashboardSection = "overview", + language: UiLanguage = "en", + usageView: UsageView = "cumulative", +): string { + const params = new URLSearchParams(); + params.set("compact", compactStatusStrip ? "1" : "0"); + params.set("section", section); + params.set("lang", language); + if (usageView === "today") params.set("usage_view", "today"); + params.set("quick", filters.quick ?? "all"); + if (filters.status) params.set("status", filters.status); + if (filters.owner) params.set("owner", filters.owner); + if (filters.project) params.set("project", filters.project); + return params.toString(); +} + +function buildTaskDetailHref(taskId: string, language: UiLanguage): string { + return `/details/task/${encodeURIComponent(taskId)}?lang=${encodeURIComponent(language)}`; +} + +function buildCronDetailHref(jobId: string, language: UiLanguage): string { + return `/details/cron/${encodeURIComponent(jobId)}?lang=${encodeURIComponent(language)}`; +} + +function buildSessionDetailHref(sessionKey: string, language: UiLanguage): string { + return `/session/${encodeURIComponent(sessionKey)}?lang=${encodeURIComponent(language)}`; +} + +function joinDisplayList(items: string[], language: UiLanguage): string { + const output = items.map((item) => item.trim()).filter((item) => item.length > 0); + return output.join(language === "en" ? ", " : "、"); +} + +function renderQuickFilters( + filters: TaskQueryFilters, + compactStatusStrip: boolean, + section: DashboardSection, + language: UiLanguage, + usageView: UsageView, +): string { + const options: Array<{ value: UiQuickFilter; label: string }> = UI_QUICK_FILTERS.map((value) => ({ + value, + label: quickFilterLabel(value, language), + })); + const active = filters.quick ?? "all"; + const base: TaskQueryFilters = { + owner: filters.owner, + project: filters.project, + }; + + return options + .map((option) => { + const href = buildHomeHref({ ...base, quick: option.value }, compactStatusStrip, section, language, usageView); + const activeClass = option.value === active ? " active" : ""; + return `${escapeHtml(option.label)}`; + }) + .join(""); +} + +function quickFilterLabel(value: UiQuickFilter, language: UiLanguage = "en"): string { + if (value === "all") return pickUiText(language, "Everything", "全部"); + if (value === "attention") return pickUiText(language, "Needs Attention", "需关注"); + if (value === "todo") return pickUiText(language, "Ready To Start", "可开始"); + if (value === "in_progress") return pickUiText(language, "In Motion", "进行中"); + if (value === "blocked") return pickUiText(language, "Blocked", "已阻塞"); + return pickUiText(language, "Completed", "已完成"); +} + +function taskStateLabel(state: TaskState, language: UiLanguage = "zh"): string { + if (state === "todo") return pickUiText(language, "Ready To Start", "待开始"); + if (state === "in_progress") return pickUiText(language, "In Motion", "进行中"); + if (state === "blocked") return pickUiText(language, "Blocked", "已阻塞"); + return pickUiText(language, "Completed", "已完成"); +} + +function projectStateLabel(state: ProjectState, language: UiLanguage = "zh"): string { + if (state === "planned") return pickUiText(language, "Planned", "规划中"); + if (state === "active") return pickUiText(language, "Active", "执行中"); + if (state === "blocked") return pickUiText(language, "Blocked", "已阻塞"); + return pickUiText(language, "Completed", "已完成"); +} + +function searchScopeLabel(scope: DashboardSearchScope, language: UiLanguage = "zh"): string { + if (scope === "tasks") return pickUiText(language, "Tasks", "任务"); + if (scope === "projects") return pickUiText(language, "Projects", "项目"); + if (scope === "sessions") return pickUiText(language, "Sessions", "会话"); + return pickUiText(language, "Alerts", "告警"); +} + +function humanizeOperatorLabel(value: string): string { + const normalized = value.trim().replace(/[_-]+/g, " ").replace(/\s+/g, " "); + if (!normalized) return "未知助手"; + return normalized.replace(/\b\w/g, (match) => match.toUpperCase()); +} + +export function deriveAgentAnimalIdentity(agentId: string): AgentAnimalIdentity { + const normalized = agentId.trim().toLowerCase(); + const compact = normalized.replace(/[^a-z0-9]/g, ""); + if (!compact) { + const fallback = FALLBACK_ANIMAL_CATALOG[0]; + return { + animal: fallback.key, + title: fallback.title, + accent: fallback.accent, + sprite: fallback.sprite, + }; + } + + const matched = ANIMAL_CATALOG.find((item) => + item.keywords.some((keyword) => compact.includes(keyword)), + ); + if (matched) { + return { + animal: matched.key, + title: matched.title, + accent: matched.accent, + sprite: matched.sprite, + }; + } + + const index = stableHashIndex(compact) % FALLBACK_ANIMAL_CATALOG.length; + const fallback = FALLBACK_ANIMAL_CATALOG[index]; + return { + animal: fallback.key, + title: fallback.title, + accent: fallback.accent, + sprite: fallback.sprite, + }; +} + +export function buildOfficeAgentRosterIds( + snapshot: ReadModelSnapshot, + _tasks: TaskListItem[], + knownAgentIds: string[] = [], +): string[] { + const configuredAgentIds = knownAgentIds.map((agentId) => agentId.trim()).filter(Boolean); + if (configuredAgentIds.length > 0) { + return [...new Set(configuredAgentIds)].sort((a, b) => a.localeCompare(b)); + } + + const agentIds = new Set(); + for (const session of snapshot.sessions) { + if (session.agentId?.trim()) { + agentIds.add(session.agentId.trim()); + } + } + for (const budget of snapshot.tasks.agentBudgets) { + if (budget.agentId.trim()) { + agentIds.add(budget.agentId.trim()); + } + } + + return [...agentIds]; +} + +export function buildOfficeSpaceCards( + snapshot: ReadModelSnapshot, + tasks: TaskListItem[], + knownAgentIds: string[] = [], + runtimeActiveSessionsByAgent: Map = new Map(), + language: UiLanguage = "zh", +): OfficeSpaceCard[] { + const configuredAgentKeys = new Set( + knownAgentIds.map((agentId) => normalizeLookupKey(agentId)).filter((agentId) => agentId.length > 0), + ); + const allowUnknownAgents = configuredAgentKeys.size === 0; + const agentIds = new Set(buildOfficeAgentRosterIds(snapshot, tasks, knownAgentIds)); + for (const [agentId, activeCount] of runtimeActiveSessionsByAgent.entries()) { + if (!agentId.trim() || activeCount <= 0) continue; + if (!allowUnknownAgents && !configuredAgentKeys.has(normalizeLookupKey(agentId))) continue; + agentIds.add(agentId.trim()); + } + + const tasksBySession = new Map(); + for (const task of tasks) { + for (const sessionKey of task.sessionKeys) { + const current = tasksBySession.get(sessionKey) ?? []; + current.push(task); + tasksBySession.set(sessionKey, current); + } + } + + const cards = [...agentIds].map((agentId) => { + const sessions = snapshot.sessions.filter((session) => session.agentId === agentId); + const runtimeActiveSessions = Math.max(0, runtimeActiveSessionsByAgent.get(agentId) ?? 0); + const snapshotActiveSessions = sessions.filter((session) => session.state !== "idle").length; + const activeSessions = Math.max(snapshotActiveSessions, runtimeActiveSessions); + const ownedActiveTasks = tasks.filter( + (task) => task.owner.toLowerCase() === agentId.toLowerCase() && task.status !== "done", + ); + const sessionTaskSet = new Map(); + for (const session of sessions) { + const linked = tasksBySession.get(session.sessionKey) ?? []; + for (const task of linked) { + if (task.status === "done") continue; + sessionTaskSet.set(`${task.projectId}:${task.taskId}`, task); + } + } + const sessionActiveTasks = [...sessionTaskSet.values()]; + const focusItems = [ + ...sessionActiveTasks.map((task) => task.title), + ...ownedActiveTasks.map((task) => task.title), + ].filter((value, idx, arr) => arr.indexOf(value) === idx); + const status = resolveOfficeCardStatus( + sessions.map((item) => item.state), + activeSessions, + focusItems.length, + ); + const statusLabel = officeStatusLabel(status, language); + const officeZone = officeZoneFromStatus(status); + const summary = buildOfficeSummary(status, focusItems, activeSessions, language); + return { + agentId, + identity: deriveAgentAnimalIdentity(agentId), + status, + statusLabel, + officeZone, + activeSessions, + activeTasks: focusItems.length, + focusItems: focusItems.slice(0, 3), + summary, + }; + }); + + return cards.sort((a, b) => { + const rank = officeStatusRank(a.status) - officeStatusRank(b.status); + if (rank !== 0) return rank; + return a.agentId.localeCompare(b.agentId); + }); +} + +function normalizeLookupKey(input: string): string { + return input.trim().toLowerCase(); +} + +export function buildExecutionAgentSummaries( + snapshot: ReadModelSnapshot, + tasks: TaskListItem[], + cronJobs: OpenclawCronJobSummary[], + rosterEntries: AgentRosterEntry[], + usageAgentTokensByKey: Map, +): ExecutionAgentSummary[] { + const configuredRosterKeys = new Set( + rosterEntries.map((entry) => normalizeLookupKey(entry.agentId)).filter((key) => key.length > 0), + ); + const allowUnknownAgents = configuredRosterKeys.size === 0; + const canonicalIdByKey = new Map(); + const displayNameByKey = new Map(); + const cronOwnerByJobId = inferCronOwnerAgentIdsFromSessions(snapshot.sessions); + + const registerAgent = (agentId: string, displayName?: string): void => { + const normalized = agentId.trim(); + if (!normalized) return; + const key = normalizeLookupKey(normalized); + if (!allowUnknownAgents && !configuredRosterKeys.has(key)) return; + if (!canonicalIdByKey.has(key)) canonicalIdByKey.set(key, normalized); + if (!displayNameByKey.has(key)) { + displayNameByKey.set(key, displayName?.trim() || humanizeOperatorLabel(normalized)); + } + }; + + for (const entry of rosterEntries) { + registerAgent(entry.agentId, entry.displayName); + } + for (const session of snapshot.sessions) { + if (session.agentId?.trim()) registerAgent(session.agentId); + } + for (const job of cronJobs) { + const ownerAgentId = job.ownerAgentId?.trim() || cronOwnerByJobId.get(job.jobId.trim().toLowerCase()); + if (ownerAgentId) registerAgent(ownerAgentId); + } + for (const key of usageAgentTokensByKey.keys()) { + registerAgent(key); + } + + const activeSessionCountByKey = new Map(); + for (const session of snapshot.sessions) { + if (!session.agentId?.trim() || session.state === "idle") continue; + const key = normalizeLookupKey(session.agentId); + if (!allowUnknownAgents && !configuredRosterKeys.has(key)) continue; + activeSessionCountByKey.set(key, (activeSessionCountByKey.get(key) ?? 0) + 1); + } + + const activeTaskCountByKey = new Map(); + for (const task of tasks) { + if (task.status === "done") continue; + const owner = task.owner.trim(); + if (!owner) continue; + const key = normalizeLookupKey(owner); + if (!allowUnknownAgents && !configuredRosterKeys.has(key)) continue; + activeTaskCountByKey.set(key, (activeTaskCountByKey.get(key) ?? 0) + 1); + } + + const enabledCronNamesByKey = new Map(); + for (const job of cronJobs) { + if (!job.enabled) continue; + const ownerAgentId = job.ownerAgentId?.trim() || cronOwnerByJobId.get(job.jobId.trim().toLowerCase()); + if (!ownerAgentId) continue; + const key = normalizeLookupKey(ownerAgentId); + if (!allowUnknownAgents && !configuredRosterKeys.has(key)) continue; + const bucket = enabledCronNamesByKey.get(key) ?? []; + bucket.push(job.name); + enabledCronNamesByKey.set(key, bucket); + } + + const rows: ExecutionAgentSummary[] = []; + for (const [key, agentId] of canonicalIdByKey.entries()) { + const cronNames = [...new Set((enabledCronNamesByKey.get(key) ?? []).map((item) => item.trim()).filter(Boolean))]; + rows.push({ + agentId, + displayName: displayNameByKey.get(key) ?? humanizeOperatorLabel(agentId), + activeSessions: activeSessionCountByKey.get(key) ?? 0, + activeTasks: activeTaskCountByKey.get(key) ?? 0, + enabledCronJobs: cronNames.length, + cronJobNames: cronNames, + recentTokens30d: usageAgentTokensByKey.get(key) ?? 0, + }); + } + + return rows.sort((a, b) => { + const loadA = a.activeSessions + a.activeTasks + a.enabledCronJobs; + const loadB = b.activeSessions + b.activeTasks + b.enabledCronJobs; + if (loadB !== loadA) return loadB - loadA; + if (b.recentTokens30d !== a.recentTokens30d) return b.recentTokens30d - a.recentTokens30d; + return a.agentId.localeCompare(b.agentId); + }); +} + +function inferCronOwnerAgentIdsFromSessions(sessions: ReadModelSnapshot["sessions"]): Map { + const owners = new Map(); + for (const session of sessions) { + const sessionKey = session.sessionKey?.trim(); + const agentId = session.agentId?.trim(); + if (!sessionKey || !agentId) continue; + const jobId = extractCronJobIdFromSessionKey(sessionKey); + if (!jobId) continue; + const key = jobId.trim().toLowerCase(); + if (!owners.has(key)) owners.set(key, agentId); + } + return owners; +} + +function buildTaskRoleSummaries(tasks: TaskListItem[]): TaskRoleSummary[] { + const buckets = new Map(); + for (const task of tasks) { + if (task.status === "done") continue; + const owner = task.owner.trim() || "Unassigned"; + const key = normalizeLookupKey(owner); + const current = buckets.get(key) ?? { + owner, + activeTasks: 0, + sampleTaskIds: [], + }; + current.activeTasks += 1; + if (current.sampleTaskIds.length < 3 && !current.sampleTaskIds.includes(task.taskId)) { + current.sampleTaskIds.push(task.taskId); + } + buckets.set(key, current); + } + return [...buckets.values()].sort((a, b) => { + if (b.activeTasks !== a.activeTasks) return b.activeTasks - a.activeTasks; + return a.owner.localeCompare(b.owner); + }); +} + +function resolveOfficeCardStatus( + states: AgentRunState[], + activeSessionCount: number, + activeTaskCount: number, +): OfficeSpaceCard["status"] { + if (states.includes("error")) return "error"; + if (states.includes("blocked")) return "blocked"; + if (states.includes("waiting_approval")) return "waiting_approval"; + if (states.includes("running")) return "running"; + if (activeSessionCount > 0) return "running"; + if (activeTaskCount > 0) return "idle"; + if (states.includes("idle")) return "idle"; + return "inactive"; +} + +function officeStatusRank(status: OfficeSpaceCard["status"]): number { + if (status === "error") return 0; + if (status === "blocked") return 1; + if (status === "waiting_approval") return 2; + if (status === "running") return 3; + if (status === "mixed") return 4; + if (status === "idle") return 5; + return 6; +} + +function officeStatusLabel(status: OfficeSpaceCard["status"], language: UiLanguage = "zh"): string { + if (status === "running") return pickUiText(language, "Running", "执行中"); + if (status === "waiting_approval") return pickUiText(language, "Waiting for approval", "等待审批"); + if (status === "blocked") return pickUiText(language, "Needs support", "需要支援"); + if (status === "error") return pickUiText(language, "Issue detected", "发现异常"); + if (status === "idle") return pickUiText(language, "Standing by", "待命"); + if (status === "mixed") return pickUiText(language, "Mixed state", "混合状态"); + return pickUiText(language, "No active load", "无活跃负载"); +} + +function officeZoneFromStatus(status: OfficeSpaceCard["status"]): OfficeSpaceCard["officeZone"] { + if (status === "running") return "Builder Desks"; + if (status === "waiting_approval") return "Approval Desk"; + if (status === "blocked" || status === "error" || status === "mixed") return "Support Bay"; + return "Standby Pods"; +} + +function officeZoneLabel(zone: OfficeSpaceCard["officeZone"], language: UiLanguage = "zh"): string { + if (zone === "Builder Desks") return pickUiText(language, "Builder Desks", "执行工位"); + if (zone === "Approval Desk") return pickUiText(language, "Approval Desk", "审批工位"); + if (zone === "Support Bay") return pickUiText(language, "Support Bay", "支援工位"); + return pickUiText(language, "Standby Pods", "待命工位"); +} + +function animalLabel(animal: string, language: UiLanguage = "zh"): string { + if (animal === "robot") return pickUiText(language, "Robot", "机器人"); + if (animal === "lion") return pickUiText(language, "Lion", "狮子"); + if (animal === "panda") return pickUiText(language, "Panda", "熊猫"); + if (animal === "monkey") return pickUiText(language, "Monkey", "猴子"); + if (animal === "dolphin") return pickUiText(language, "Dolphin", "海豚"); + if (animal === "owl") return pickUiText(language, "Owl", "猫头鹰"); + if (animal === "fox") return pickUiText(language, "Fox", "狐狸"); + if (animal === "bear") return pickUiText(language, "Bear", "棕熊"); + if (animal === "eagle") return pickUiText(language, "Eagle", "鹰"); + if (animal === "tiger") return pickUiText(language, "Tiger", "老虎"); + if (animal === "otter") return pickUiText(language, "Otter", "水獭"); + if (animal === "rooster") return pickUiText(language, "Rooster", "公鸡"); + return pickUiText(language, "Animal", "动物"); +} + +function buildOfficeSummary( + status: OfficeSpaceCard["status"], + focusItems: string[], + sessionCount: number, + language: UiLanguage = "zh", +): string { + if (focusItems.length === 0 && sessionCount === 0) { + return pickUiText(language, "No live task right now.", "当前没有实时任务。"); + } + if (status === "running" && focusItems.length > 0) { + return pickUiText(language, `Working on: ${focusItems[0]}`, `正在处理:${focusItems[0]}`); + } + if (status === "waiting_approval") { + return pickUiText(language, "Waiting for approval before continuing.", "等待审批,暂时暂停。"); + } + if (status === "blocked" || status === "error") { + return pickUiText(language, "Clear blockers before continuing.", "继续前需要先解决阻塞。"); + } + if (focusItems.length > 0) { + return pickUiText(language, `Currently tracking: ${focusItems[0]}`, `当前跟进:${focusItems[0]}`); + } + if (sessionCount > 0) { + return pickUiText(language, "Session is open and waiting for the next instruction.", "会话已开启,等待下一步指令。"); + } + return pickUiText(language, "Standing by.", "待命中。"); +} + +function staffStatusLabel(status: OfficeSpaceCard["status"] | undefined, language: UiLanguage = "zh"): string { + switch (status) { + case "running": + return pickUiText(language, "Working", "工作中"); + case "waiting_approval": + return pickUiText(language, "Awaiting review", "等待审核"); + case "blocked": + return pickUiText(language, "Needs support", "需要支援"); + case "error": + return pickUiText(language, "Needs attention", "需要关注"); + case "mixed": + return pickUiText(language, "Handling mixed work", "处理中"); + case "idle": + case "inactive": + default: + return pickUiText(language, "Standing by", "待命"); + } +} + +function staffCurrentWorkLabel(input: { + office?: OfficeSpaceCard; + execution?: ExecutionAgentSummary; + language: UiLanguage; +}): { label: string; value: string } { + const { office, execution, language } = input; + const currentLabel = pickUiText(language, "Working on", "正在处理什么"); + const nextLabel = pickUiText(language, "Next up", "下一项"); + const focus = office?.focusItems[0]?.trim(); + if (office?.status === "waiting_approval") { + return { label: currentLabel, value: pickUiText(language, "Waiting for approval", "等待审批") }; + } + if (office?.status === "blocked" || office?.status === "error") { + return { label: currentLabel, value: pickUiText(language, "Blocked and waiting for support", "阻塞中,等待支援") }; + } + const cronName = execution?.cronJobNames.find((name) => name.trim())?.trim(); + if (office?.status === "running") { + if (focus) return { label: currentLabel, value: focus }; + if (cronName) { + return { label: currentLabel, value: safeTruncate(cronName, 72) }; + } + if ((office?.activeSessions ?? 0) > 0) { + return { label: currentLabel, value: pickUiText(language, "Handling a live session", "正在处理实时会话") }; + } + return { label: currentLabel, value: pickUiText(language, "Handling active work", "正在处理当前工作") }; + } + if (focus) return { label: nextLabel, value: focus }; + if (cronName) { + return { label: nextLabel, value: safeTruncate(cronName, 72) }; + } + return { label: currentLabel, value: pickUiText(language, "No live work right now", "当前无实时任务") }; +} + +async function loadCachedStaffRecentActivity( + snapshot: ReadModelSnapshot, + client: ToolClient, + agentIds: string[], + language: UiLanguage, +): Promise> { + const now = Date.now(); + const agentKey = [...new Set(agentIds.map((value) => normalizeLookupKey(value)).filter(Boolean))].sort().join(","); + if ( + renderStaffRecentActivityCache && + renderStaffRecentActivityCache.snapshotAt === snapshot.generatedAt && + renderStaffRecentActivityCache.language === language && + renderStaffRecentActivityCache.agentKey === agentKey && + renderStaffRecentActivityCache.expiresAt > now + ) { + return renderStaffRecentActivityCache.value; + } + + const value = await loadStaffRecentActivity(snapshot, client, agentIds, language); + renderStaffRecentActivityCache = { + snapshotAt: snapshot.generatedAt, + language, + agentKey, + value, + expiresAt: now + HTML_HEAVY_CACHE_TTL_MS, + }; + return value; +} + +async function loadStaffRecentActivity( + snapshot: ReadModelSnapshot, + client: ToolClient, + agentIds: string[], + language: UiLanguage, +): Promise> { + const targetKeys = [...new Set(agentIds.map((value) => normalizeLookupKey(value)).filter(Boolean))]; + const targetKeySet = new Set(targetKeys); + const sessionsByAgent = new Map(); + for (const session of [...snapshot.sessions].sort(compareSessionSummariesByLatest)) { + const agentId = session.agentId?.trim(); + if (!agentId) continue; + const key = normalizeLookupKey(agentId); + if (!targetKeySet.has(key)) continue; + const bucket = sessionsByAgent.get(key) ?? []; + if (bucket.length >= 3) continue; + bucket.push(session); + sessionsByAgent.set(key, bucket); + } + + const entries = await Promise.all( + targetKeys.map(async (key): Promise<[string, StaffRecentActivity | undefined]> => { + const sessions = sessionsByAgent.get(key) ?? []; + let residualRunningDetected = false; + let liveRunningDetected = false; + for (const session of sessions) { + const detail = await getSessionConversationDetail({ + snapshot, + client, + sessionKey: session.sessionKey, + historyLimit: 20, + }); + if (!detail) continue; + if (detail.session.state === "running") { + if (historyImpliesStaffStopped(detail.history)) { + residualRunningDetected = true; + } else { + liveRunningDetected = true; + } + } + const recent = pickRecentStaffActivity(detail.history, language); + if (recent) { + return [ + key, + { + ...recent, + sessionKey: session.sessionKey, + statusOverride: !liveRunningDetected && residualRunningDetected ? "idle" : undefined, + }, + ]; + } + } + if (!liveRunningDetected && residualRunningDetected) { + return [key, { + recentOutput: pickUiText(language, "Recently stopped and returned to standby.", "最近已停止当前任务并回到待命。"), + statusOverride: "idle", + }]; + } + return [key, undefined]; + }), + ); + + return new Map(entries.filter((entry): entry is [string, StaffRecentActivity] => Boolean(entry[1]))); +} + +function pickRecentStaffActivity( + history: SessionHistoryMessage[], + language: UiLanguage, +): StaffRecentActivity | undefined { + for (let idx = history.length - 1; idx >= 0; idx -= 1) { + const message = history[idx]; + if (!isStaffVisibleOutputMessage(message)) continue; + return { + recentOutput: formatStaffRecentOutput(message, language), + recentOutputAt: message.timestamp, + }; + } + return undefined; +} + +function historyImpliesStaffStopped(history: SessionHistoryMessage[]): boolean { + for (let idx = history.length - 1; idx >= 0; idx -= 1) { + const message = history[idx]; + if (isResidualPostStopMessage(message)) continue; + if (isExplicitStopSignalMessage(message)) return true; + return false; + } + return false; +} + +function isExplicitStopSignalMessage(message: SessionHistoryMessage): boolean { + const content = sanitizeStaffOutputContent(message.content); + if (!content) return false; + const lower = content.toLowerCase(); + return ( + lower.includes("停止当前任务并进入待命状态") || + lower.includes("立即停止你当前的所有活动") || + lower.includes("stop current task and enter standby") || + lower.includes("不再继续当前") || + lower.includes("不再处理任何当前任务") || + lower.includes("从现在起进入待命状态") || + lower.includes("enter standby state") + ); +} + +function isResidualPostStopMessage(message: SessionHistoryMessage): boolean { + if (message.kind === "tool_event") return false; + const content = sanitizeStaffOutputContent(message.content); + if (!content) return true; + const lower = content.toLowerCase(); + return ( + lower === "reply_skip" || + lower === "announce_skip" || + lower.startsWith("thinking ") || + lower.startsWith("reasoning ") || + lower.includes("agent-to-agent announce step") + ); +} + +function isStaffVisibleOutputMessage(message: SessionHistoryMessage): boolean { + if (message.kind === "accepted" || message.kind === "spawn") return false; + if (message.kind === "tool_event") return true; + const role = message.role.trim().toLowerCase(); + if (role === "user" || role === "system") return false; + if (isExplicitStopSignalMessage(message)) return false; + const content = sanitizeStaffOutputContent(message.content); + if (!content) return false; + const lower = content.toLowerCase(); + if (lower === "no_reply" || lower === "noop") return false; + if (lower === "reply_skip" || lower === "announce_skip") return false; + if (lower.startsWith("thinking ")) return false; + if (lower.startsWith("reasoning ")) return false; + if (lower.startsWith("text msg_")) return false; + if (lower.startsWith("toolcall ")) return false; + if (lower.includes("agent-to-agent announce step")) return false; + if (lower.includes("\"encrypted_content\"")) return false; + if (lower.includes("openclaw runtime context (internal)")) return false; + if (lower.includes("conversation info (untrusted metadata)")) return false; + if (lower.includes("internal_write_only")) return false; + if (lower.includes("read heartbeat.md if it exists")) return false; + if (content.includes("继续推进当前目标")) return false; + if (content.includes("Alex Finn 流程最终验收")) return false; + return true; +} + +function formatStaffRecentOutput(message: SessionHistoryMessage, language: UiLanguage): string { + if (message.kind === "tool_event") { + return message.toolName?.trim() + ? pickUiText(language, `Completed tool step: ${message.toolName}.`, `最近完成工具步骤:${message.toolName}。`) + : pickUiText(language, "Completed a recent tool step.", "最近完成一次工具步骤。"); + } + + const content = sanitizeStaffOutputContent(message.content); + if (!content) { + return pickUiText(language, "No recent output yet.", "最近暂无产出。"); + } + + if (content === "NOOP") { + return pickUiText(language, "Recent check completed with no action needed.", "最近完成一次检查,无需动作。"); + } + if (content === "NO_REPLY") { + return pickUiText(language, "Recent task completed without a user reply.", "最近完成一次任务,无需额外回复。"); + } + if (content.toLowerCase().startsWith("successfully wrote ")) { + return pickUiText(language, "Updated a memory or workspace file.", "最近更新了一份记忆或工作文件。"); + } + if ( + content.startsWith("{") || + content.startsWith("[") || + content.startsWith("```json") || + content.includes('{"ok":') || + content.includes('"message_id"') + ) { + return pickUiText(language, "Recent task completed and returned a structured result.", "最近完成一次任务,并返回结构化结果。"); + } + return safeTruncate(content, 88); +} + +function sanitizeStaffOutputContent(content: string): string { + let normalized = normalizeInlineText(content); + if (!normalized) return normalized; + normalized = normalized.replace(/^\[\[reply_to_current\]\]\s*/i, ""); + normalized = normalized.replace(/^\[[^\]]+\]\s*/, ""); + normalized = normalized.replace(/^warning:\s*background execution is disabled; running synchronously\.\s*/i, ""); + return normalized.trim(); +} + +function compareSessionSummariesByLatest(a: ReadModelSnapshot["sessions"][number], b: ReadModelSnapshot["sessions"][number]): number { + const left = Date.parse(a.lastMessageAt ?? ""); + const right = Date.parse(b.lastMessageAt ?? ""); + const leftMs = Number.isNaN(left) ? 0 : left; + const rightMs = Number.isNaN(right) ? 0 : right; + if (leftMs !== rightMs) return rightMs - leftMs; + return a.sessionKey.localeCompare(b.sessionKey); +} + +export async function buildStaffOverviewCards(input: { + snapshot: ReadModelSnapshot; + client: ToolClient; + members: TeamMemberSnapshot[]; + officeCards: OfficeSpaceCard[]; + executionAgentSummaries: ExecutionAgentSummary[]; + language: UiLanguage; +}): Promise { + const officeCardByKey = new Map(input.officeCards.map((item) => [normalizeLookupKey(item.agentId), item])); + const executionByKey = new Map(input.executionAgentSummaries.map((item) => [normalizeLookupKey(item.agentId), item])); + + const memberList = input.members.length > 0 + ? input.members + : input.executionAgentSummaries.map((item) => ({ + agentId: item.agentId, + displayName: item.displayName, + model: "unlisted", + workspace: "unlisted", + toolsProfile: "default", + })); + const recentActivityByKey = await loadCachedStaffRecentActivity( + input.snapshot, + input.client, + memberList.map((member) => member.agentId), + input.language, + ); + + return await Promise.all(memberList.map(async (member) => { + const key = normalizeLookupKey(member.agentId); + const office = officeCardByKey.get(key); + const execution = executionByKey.get(key); + const recentActivity = recentActivityByKey.get(key); + const identity = office?.identity ?? deriveAgentAnimalIdentity(member.agentId); + const roleLabel = await resolveStaffRoleLabel(member, input.language); + const effectiveOfficeStatus = recentActivity?.statusOverride ?? office?.status; + const currentWork = staffCurrentWorkLabel({ + office: office ? { ...office, status: effectiveOfficeStatus ?? office.status } : office, + execution, + language: input.language, + }); + const recentOutput = recentActivity?.recentOutput + ? recentActivity.recentOutput + : pickUiText(input.language, "No recent output yet.", "最近暂无产出。"); + const scheduledLabel = (execution?.enabledCronJobs ?? 0) > 0 + ? pickUiText(input.language, "Scheduled", "已排班") + : pickUiText(input.language, "Not scheduled", "未排班"); + return { + agentId: member.agentId, + displayName: member.displayName, + identity, + roleLabel, + statusLabel: staffStatusLabel(effectiveOfficeStatus, input.language), + currentWorkLabel: currentWork.label, + currentWork: currentWork.value, + recentOutput, + scheduledLabel, + }; + })); +} + +function renderStaffOverviewCards(cards: StaffOverviewCard[], language: UiLanguage = "zh"): string { + if (cards.length === 0) { + return `
    ${escapeHtml( + pickUiText(language, "No staff summary is available yet.", "当前没有可显示的员工摘要。"), + )}
    `; + } + + return `
    ${cards + .map((card) => { + const avatar = `
    + +
    `; + return `
    +
    + ${avatar} +
    +

    ${escapeHtml(card.displayName)}

    +
    ${escapeHtml(card.roleLabel)}
    +
    +
    +
    +
    ${escapeHtml(pickUiText(language, "Status", "当前状态"))}
    ${escapeHtml(card.statusLabel)}
    +
    ${escapeHtml(card.currentWorkLabel)}
    ${escapeHtml(card.currentWork)}
    +
    ${escapeHtml(pickUiText(language, "Recent output", "最近产出"))}
    ${escapeHtml(card.recentOutput)}
    +
    ${escapeHtml(pickUiText(language, "In schedule", "是否在排班里"))}
    ${escapeHtml(card.scheduledLabel)}
    +
    +
    `; + }) + .join("")}
    `; +} + +function buildTaskExecutionChainCards(input: { + tasks: TaskListItem[]; + sessions: ReadModelSnapshot["sessions"]; + sessionItems: SessionConversationListItem[]; + language: UiLanguage; +}): TaskExecutionChainCard[] { + type SessionLike = { + sessionKey: string; + agentId?: string; + state: AgentRunState; + lastMessageAt?: string; + }; + + const previewByKey = new Map(input.sessionItems.map((item) => [item.sessionKey, item])); + const snapshotByKey = new Map(input.sessions.map((session) => [session.sessionKey, session])); + const usedSessionKeys = new Set(); + + const resolveCandidate = (sessionKey: string): TaskExecutionChainCard | undefined => { + const preview = previewByKey.get(sessionKey); + const snapshotSession = snapshotByKey.get(sessionKey); + const sessionLike: SessionLike | undefined = + preview ?? + snapshotSession ?? + (sessionKey.includes(":run:") + ? { + sessionKey, + agentId: extractAgentIdFromSessionKey(sessionKey), + state: "idle", + lastMessageAt: undefined, + } + : undefined); + if (!sessionLike) return undefined; + + const executionChain = + preview?.executionChain ?? + inferSessionExecutionChainFromSessionKey({ + sessionKey: sessionLike.sessionKey, + agentId: sessionLike.agentId, + state: sessionLike.state, + lastMessageAt: sessionLike.lastMessageAt, + }); + if (!executionChain) return undefined; + + return { + taskTitle: preview?.label ?? sessionLike.sessionKey, + owner: preview?.agentId ?? sessionLike.agentId ?? pickUiText(input.language, "Unassigned", "未分配"), + sessionKey: sessionLike.sessionKey, + agentId: sessionLike.agentId, + state: sessionLike.state, + latestAt: preview?.latestHistoryAt ?? sessionLike.lastMessageAt, + latestSnippet: preview?.latestSnippet, + executionChain, + sessionHref: buildSessionDetailHref(sessionLike.sessionKey, input.language), + }; + }; + + const cards: TaskExecutionChainCard[] = []; + for (const task of input.tasks) { + const candidates = [...new Set(task.sessionKeys)] + .map((sessionKey) => resolveCandidate(sessionKey)) + .filter((item): item is TaskExecutionChainCard => Boolean(item)) + .sort(compareTaskExecutionChainCards); + if (candidates.length === 0) continue; + + const chosen = candidates[0]; + usedSessionKeys.add(chosen.sessionKey); + if (chosen.executionChain.parentSessionKey) usedSessionKeys.add(chosen.executionChain.parentSessionKey); + if (chosen.executionChain.childSessionKey) usedSessionKeys.add(chosen.executionChain.childSessionKey); + cards.push({ + ...chosen, + taskId: task.taskId, + taskTitle: task.title, + projectTitle: task.projectTitle, + owner: task.owner, + taskHref: buildTaskDetailHref(task.taskId, input.language), + }); + } + + const unmappedSessions = [ + ...input.sessionItems + .map((item) => resolveCandidate(item.sessionKey)) + .filter((item): item is TaskExecutionChainCard => Boolean(item)), + ...input.sessions + .map((session) => resolveCandidate(session.sessionKey)) + .filter((item): item is TaskExecutionChainCard => Boolean(item)), + ]; + const dedupedUnmapped = new Map(); + for (const item of unmappedSessions) { + if (dedupedUnmapped.has(item.sessionKey)) continue; + dedupedUnmapped.set(item.sessionKey, item); + } + + for (const item of dedupedUnmapped.values()) { + if (!item.executionChain.spawned) continue; + if (usedSessionKeys.has(item.sessionKey)) continue; + cards.push({ + ...item, + taskTitle: item.latestSnippet?.trim() + ? safeTruncate(item.latestSnippet.trim(), 64) + : pickUiText(input.language, "Isolated execution session", "隔离执行会话"), + owner: item.agentId ?? pickUiText(input.language, "Unassigned", "未分配"), + unmapped: true, + }); + } + + return cards.sort(compareTaskExecutionChainCards); +} + +function compareTaskExecutionChainCards(a: TaskExecutionChainCard, b: TaskExecutionChainCard): number { + if (a.unmapped !== b.unmapped) return a.unmapped ? 1 : -1; + const stageRank = executionChainStageRank(b.executionChain.stage) - executionChainStageRank(a.executionChain.stage); + if (stageRank !== 0) return stageRank; + const timeRank = toSortableMs(b.latestAt) - toSortableMs(a.latestAt); + if (timeRank !== 0) return timeRank; + return a.sessionKey.localeCompare(b.sessionKey); +} + +function summarizeVisibleSessionSnippet( + rawSnippet: string | undefined, + language: UiLanguage = "zh", + maxLength = 96, +): string { + const normalized = normalizeInlineText(rawSnippet ?? ""); + if (!normalized) { + return pickUiText(language, "No recent summary yet.", "暂无最近摘要。"); + } + const structured = summarizeStructuredSessionPayload(normalized, language); + return safeTruncate(structured ?? normalized, maxLength); +} + +function summarizeStructuredSessionPayload(input: string, language: UiLanguage): string | undefined { + const trimmed = input.trim(); + if (!(trimmed.startsWith("{") || trimmed.startsWith("["))) { + return summarizeStructuredKeyValueText(trimmed, language); + } + try { + const parsed = summarizeStructuredSessionValue(JSON.parse(trimmed) as unknown, language); + if (parsed) return parsed; + } catch { + // fall through to best-effort parsing of truncated JSON-like text + } + return summarizeStructuredSessionTextFallback(trimmed, language); +} + +function summarizeStructuredKeyValueText(input: string, language: UiLanguage): string | undefined { + const parts = input + .split("|") + .map((part) => part.trim()) + .filter(Boolean); + if (parts.length < 2 || !parts.some((part) => part.includes("="))) return undefined; + + const values = new Map(); + for (const part of parts) { + const [rawKey, ...rest] = part.split("="); + const key = rawKey?.trim().toLowerCase(); + const value = rest.join("=").trim(); + if (!key || !value) continue; + values.set(key, value); + } + if (values.size === 0) return undefined; + + const segments: string[] = []; + const accepted = values.get("accepted"); + if (accepted) { + segments.push( + isTruthyFlag(accepted) + ? pickUiText(language, "Accepted", "已接单") + : pickUiText(language, "Not accepted", "未接单"), + ); + } + const spawned = values.get("spawned"); + if (spawned) { + segments.push( + isTruthyFlag(spawned) + ? pickUiText(language, "Spawned", "已派发") + : pickUiText(language, "Pending spawn", "待派发"), + ); + } + const scanned = numericSummarySegment(values.get("scanned"), language, "Scanned", "扫描"); + if (scanned) segments.push(scanned); + const sent = numericSummarySegment(values.get("sent"), language, "Sent", "发送"); + if (sent) segments.push(sent); + const attempted = numericSummarySegment(values.get("attemptedqueries"), language, "Queries", "查询"); + if (attempted) segments.push(attempted); + const successful = numericSummarySegment(values.get("successfulqueries"), language, "Successful", "成功"); + if (successful) segments.push(successful); + const source = values.get("source"); + if (source?.trim()) { + const normalized = normalizeLookupKey(source); + const sourceLabel = + normalized === "session_key" + ? pickUiText(language, "Session-key inferred", "会话键推断") + : normalized === "history" + ? pickUiText(language, "History derived", "历史推导") + : safeTruncate(normalizeInlineText(source), 32); + segments.push(sourceLabel); + } + const inferred = values.get("inferred"); + if (inferred && isTruthyFlag(inferred)) { + segments.push(pickUiText(language, "Best-effort", "推断值")); + } + + return segments.length > 0 ? segments.slice(0, 5).join(" · ") : undefined; +} + +function numericSummarySegment( + rawValue: string | undefined, + language: UiLanguage, + enLabel: string, + zhLabel: string, +): string | undefined { + if (!rawValue) return undefined; + const value = Number(rawValue); + if (!Number.isFinite(value)) return undefined; + return `${pickUiText(language, enLabel, zhLabel)} ${formatInt(value)}`; +} + +function isTruthyFlag(input: string): boolean { + return /^(?:1|true|yes|y)$/i.test(input.trim()); +} + +function summarizeStructuredSessionValue(input: unknown, language: UiLanguage): string | undefined { + if (input === null || input === undefined) return undefined; + if (typeof input === "string") { + const normalized = normalizeInlineText(input); + if (!normalized) return undefined; + return normalized; + } + if (typeof input === "number" || typeof input === "boolean") { + return String(input); + } + if (Array.isArray(input)) { + if (input.length === 0) return pickUiText(language, "Empty result", "空结果"); + const first = summarizeStructuredSessionValue(input[0], language); + if (first?.trim()) { + const suffix = + input.length > 1 + ? ` · ${formatInt(input.length)} ${pickUiText(language, "items", "项")}` + : ""; + return `${first}${suffix}`; + } + return `${formatInt(input.length)} ${pickUiText(language, "items", "项")}`; + } + if (typeof input !== "object") return undefined; + + const obj = input as Record; + const explicitText = firstStructuredSessionText(obj); + if (explicitText) return explicitText; + + const segments: string[] = []; + if (typeof obj.ok === "boolean") { + segments.push(pickUiText(language, obj.ok ? "Succeeded" : "Failed", obj.ok ? "成功" : "失败")); + } + const errorText = boundedStructuredSessionText(obj.error, 48); + if (errorText) { + segments.push(`${pickUiText(language, "Error", "错误")} ${errorText}`); + } + + const counters: Array<[string, string, string]> = [ + ["attemptedQueries", "Queries", "查询"], + ["successfulQueries", "Successful", "成功"], + ["scanned", "Scanned", "扫描"], + ["qualified", "Qualified", "入选"], + ["sent", "Sent", "发送"], + ["candidatesLoaded", "Loaded", "载入"], + ["matches", "Matches", "匹配"], + ["created", "Created", "新建"], + ["updated", "Updated", "更新"], + ["written", "Written", "写入"], + ["deleted", "Deleted", "删除"], + ]; + for (const [key, enLabel, zhLabel] of counters) { + const value = obj[key]; + if (typeof value !== "number" || !Number.isFinite(value)) continue; + segments.push(`${pickUiText(language, enLabel, zhLabel)} ${formatInt(value)}`); + if (segments.length >= 5) break; + } + + if (segments.length > 0) return segments.join(" · "); + return undefined; +} + +function firstStructuredSessionText(obj: Record): string | undefined { + const keys = ["summary", "message", "detail", "reason", "statusText", "status", "result", "output", "response"]; + for (const key of keys) { + const text = boundedStructuredSessionText(obj[key], 88); + if (text) return text; + } + return undefined; +} + +function boundedStructuredSessionText(input: unknown, maxLength: number): string | undefined { + if (typeof input !== "string") return undefined; + const normalized = normalizeInlineText(input); + if (!normalized || normalized.startsWith("{") || normalized.startsWith("[")) return undefined; + return safeTruncate(normalized, maxLength); +} + +function summarizeStructuredSessionTextFallback(input: string, language: UiLanguage): string | undefined { + const segments: string[] = []; + const okMatch = /"ok"\s*:\s*(true|false)/i.exec(input); + if (okMatch) { + segments.push(pickUiText(language, okMatch[1] === "true" ? "Succeeded" : "Failed", okMatch[1] === "true" ? "成功" : "失败")); + } + const errorMatch = /"error"\s*:\s*"([^"]+)"/i.exec(input); + if (errorMatch?.[1]?.trim()) { + segments.push(`${pickUiText(language, "Error", "错误")} ${safeTruncate(normalizeInlineText(errorMatch[1]), 48)}`); + } + + const counters: Array<[RegExp, string, string]> = [ + [/"attemptedQueries"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Queries", "查询"], + [/"successfulQueries"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Successful", "成功"], + [/"scanned"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Scanned", "扫描"], + [/"qualified"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Qualified", "入选"], + [/"sent"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Sent", "发送"], + [/"candidatesLoaded"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Loaded", "载入"], + [/"matches"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Matches", "匹配"], + [/"created"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Created", "新建"], + [/"updated"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Updated", "更新"], + [/"written"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Written", "写入"], + [/"deleted"\s*:\s*(-?\d+(?:\.\d+)?)/i, "Deleted", "删除"], + ]; + for (const [pattern, enLabel, zhLabel] of counters) { + const match = pattern.exec(input); + if (!match?.[1]) continue; + const value = Number(match[1]); + if (!Number.isFinite(value)) continue; + segments.push(`${pickUiText(language, enLabel, zhLabel)} ${formatInt(value)}`); + if (segments.length >= 5) break; + } + + if (segments.length > 0) return segments.join(" · "); + return undefined; +} + +function looksLikeStructuredExecutionTitle(input: string): boolean { + const normalized = normalizeInlineText(input); + if (!normalized) return true; + if (normalized.startsWith("{") || normalized.startsWith("[")) return true; + if (normalized.startsWith("agent:")) return true; + if (/[{"\[]/.test(normalized) && /"[^"]+"\s*:/.test(normalized)) return true; + return false; +} + +function executionChainFallbackTitle(item: TaskExecutionChainCard, language: UiLanguage): string { + const agentLabel = humanizeOperatorLabel(item.agentId ?? item.owner ?? "main"); + if (item.unmapped) { + const sessionKind = extractCronJobIdFromSessionKey(item.sessionKey) + ? pickUiText(language, "Cron isolated run", "Cron 隔离执行") + : pickUiText(language, "Isolated execution session", "隔离执行会话"); + return `${agentLabel} · ${sessionKind}`; + } + const projectLabel = normalizeInlineText(item.projectTitle ?? ""); + if (projectLabel) { + return `${safeTruncate(projectLabel, 36)} · ${pickUiText(language, "Linked task", "关联任务")}`; + } + if (item.taskId?.trim()) { + return `${pickUiText(language, "Task", "任务")} ${safeTruncate(item.taskId.trim(), 32)}`; + } + return `${agentLabel} · ${pickUiText(language, "Linked task", "关联任务")}`; +} + +function executionChainCardTitle(item: TaskExecutionChainCard, language: UiLanguage): string { + if (item.unmapped) return executionChainFallbackTitle(item, language); + + const normalizedTitle = normalizeInlineText(item.taskTitle ?? ""); + if (!normalizedTitle) return executionChainFallbackTitle(item, language); + if (!looksLikeStructuredExecutionTitle(normalizedTitle)) return safeTruncate(normalizedTitle, 88); + + const structuredTitle = summarizeStructuredSessionPayload(normalizedTitle, language); + if (structuredTitle?.trim()) return safeTruncate(structuredTitle, 88); + return executionChainFallbackTitle(item, language); +} + +function executionChainStageRank(stage: SessionExecutionChainSummary["stage"]): number { + switch (stage) { + case "running": + return 4; + case "spawned": + return 3; + case "accepted": + return 2; + case "idle": + default: + return 1; + } +} + +function executionChainStageLabel( + stage: SessionExecutionChainSummary["stage"], + language: UiLanguage = "zh", +): string { + switch (stage) { + case "running": + return pickUiText(language, "Running", "执行中"); + case "spawned": + return pickUiText(language, "Spawned", "已派发"); + case "accepted": + return pickUiText(language, "Accepted", "已接单"); + case "idle": + default: + return pickUiText(language, "Idle", "待命"); + } +} + +function executionChainSourceLabel( + chain: SessionExecutionChainSummary, + language: UiLanguage = "zh", +): string { + if (chain.source === "history") { + return chain.inferred + ? pickUiText(language, "History signal (best effort)", "历史信号(最佳努力)") + : pickUiText(language, "History evidence", "历史证据"); + } + return pickUiText(language, "Session-key inference", "会话键推断"); +} + +function extractAgentIdFromSessionKey(sessionKey: string): string | undefined { + const match = /^agent:([^:]+)/.exec(sessionKey.trim()); + return match?.[1]; +} + +function extractCronJobIdFromSessionKey(sessionKey: string): string | undefined { + const match = /^agent:[^:]+:cron:([^:]+)/.exec(sessionKey.trim()); + return match?.[1]; +} + +function renderTaskExecutionChainCards( + cards: TaskExecutionChainCard[], + language: UiLanguage = "zh", +): string { + if (cards.length === 0) { + return `
    ${escapeHtml( + pickUiText( + language, + "No accepted/spawn execution chains are visible yet. They will appear once isolated sessions are dispatched.", + "当前还没有可见的接单/派发执行链。隔离会话开始派发后会显示。", + ), + )}
    `; + } + + return `
    ${cards + .slice(0, 10) + .map((item) => { + const chain = item.executionChain; + const acceptedBadge = badge(chain.accepted ? "ok" : "idle", pickUiText(language, "Accepted", "已接单")); + const spawnedBadge = badge(chain.spawned ? "info" : "idle", pickUiText(language, "Spawned", "已派发")); + const stageBadge = badge(chain.stage, executionChainStageLabel(chain.stage, language)); + const runStateBadge = badge(item.state, sessionStateLabel(item.state)); + const ownerLabel = humanizeOperatorLabel(item.owner); + const title = executionChainCardTitle(item, language); + const taskMeta = item.unmapped + ? pickUiText(language, "No linked task", "未关联任务") + : item.projectTitle ?? pickUiText(language, "Linked task", "已关联任务"); + const contextLine = [taskMeta, `${pickUiText(language, "Agent", "智能体")} ${ownerLabel}`] + .filter(Boolean) + .join(" · "); + const sessionFlow = [chain.parentSessionKey, chain.childSessionKey] + .filter((value, idx, arr): value is string => Boolean(value) && arr.indexOf(value) === idx) + .map((value) => `${escapeHtml(value)}`) + .join(' → '); + const latestLine = item.latestAt + ? `${pickUiText(language, "Latest", "最近")} ${escapeHtml(item.latestAt)}` + : escapeHtml(pickUiText(language, "No history yet", "暂无历史")); + const sourceLine = executionChainSourceLabel(chain, language); + const summarySource = item.latestSnippet?.trim() ? item.latestSnippet : chain.detail; + const summaryLine = escapeHtml(summarizeVisibleSessionSnippet(summarySource, language, 96)); + return ``; + }) + .join("")}
    `; +} + +function renderOfficeCards(cards: OfficeSpaceCard[], language: UiLanguage = "zh"): string { + if (cards.length === 0) { + return `
    ${escapeHtml( + pickUiText(language, "No staff roster signal yet. It will appear after config or runtime data is connected.", "暂无助手名录信号。连接配置或运行态后会显示。"), + )}
    `; + } + + return `
    ${cards + .map((card) => { + const focus = + card.focusItems.length === 0 + ? "
    当前重点:暂无
    " + : `
    当前重点:
      ${card.focusItems + .map((item) => `
    • ${escapeHtml(item)}
    • `) + .join("")}
    `; + const avatar = `
    + +
    ${escapeHtml(animalLabel(card.identity.animal, language))}
    +
    `; + return `
    +
    + ${avatar} +
    +
    ${escapeHtml(humanizeOperatorLabel(card.agentId))}${badge(card.status)}
    +
    ${escapeHtml(card.statusLabel)} · ${escapeHtml(card.summary)}
    +
    ${escapeHtml(pickUiText(language, "Active sessions", "活跃会话"))}:${card.activeSessions} · ${escapeHtml( + pickUiText(language, "Active tasks", "活跃任务"), + )}:${card.activeTasks}
    +
    +
    + ${focus.replace("当前重点:", `${pickUiText(language, "Current focus", "当前重点")}:`).replace("当前重点:暂无", `${pickUiText(language, "Current focus", "当前重点")}:${pickUiText(language, "None", "暂无")}`)} +
    `; + }) + .join("")}
    `; +} + +function renderOfficeFloor(cards: OfficeSpaceCard[], language: UiLanguage = "zh"): string { + const zones: OfficeSpaceCard["officeZone"][] = [ + "Builder Desks", + "Approval Desk", + "Support Bay", + "Standby Pods", + ]; + return `
    ${zones + .map((zone) => { + const items = cards.filter((card) => card.officeZone === zone); + const rows = + items.length === 0 + ? '
  • 当前没有分配。
  • ' + : items + .map( + (card) => + `
  • ${escapeHtml(humanizeOperatorLabel(card.agentId))}
    ${escapeHtml(card.summary)}
  • `, + ) + .join(""); + return `

    ${escapeHtml(officeZoneLabel(zone, language))}

    ${escapeHtml( + pickUiText(language, "Occupied", "占用数"), + )}:${items.length}
      ${rows}
    `; + }) + .join("")}
    `; +} + +function renderNativeMotionScript(language: UiLanguage = "zh"): string { + return ``; +} + +function renderQuotaResetScript(): string { + return ``; +} + +function renderFileWorkbenchScript(): string { + return ``; +} + +function renderAgentVisualEnhancerScript(): string { + return ``; +} + +function buildParitySurfaceRows(input: { + sessionCount: number; + pendingApprovals: number; + cronCount: number; + projectCount: number; + taskCount: number; + usageConnected: boolean; + replayCount: number; + digestConnected: boolean; + importGuard: ReturnType; + budgetConnected: boolean; + subscriptionConnected: boolean; +}): ParitySurfaceRow[] { + return [ + { + id: "sessions", + name: "会话可见性", + route: "/sessions", + status: input.sessionCount > 0 ? "enabled" : "warn", + detail: + input.sessionCount > 0 + ? `可见会话 ${input.sessionCount} 条。` + : "页面可用,等待实时会话数据。", + }, + { + id: "approvals", + name: "审批与决策队列", + route: "/?section=projects-tasks&quick=attention#task-lane", + status: "enabled", + detail: `待审批 ${input.pendingApprovals} 条,决策队列可用。`, + }, + { + id: "cron", + name: "定时调度", + route: "/cron", + status: input.cronCount > 0 ? "enabled" : "warn", + detail: input.cronCount > 0 ? `已追踪 ${input.cronCount} 个定时任务。` : "调度页面可用,但尚未上报任务。", + }, + { + id: "projects_tasks", + name: "项目与任务", + route: "/?section=projects-tasks", + status: input.projectCount + input.taskCount > 0 ? "enabled" : "warn", + detail: `${input.projectCount} 个项目,${input.taskCount} 个任务。`, + }, + { + id: "usage", + name: "用量与费用", + route: "/?section=usage-cost", + status: input.usageConnected ? "enabled" : "warn", + detail: input.usageConnected ? "运行时用量信号已连接。" : "页面可用,但数据源未连接。", + }, + { + id: "replay", + name: "回放与审计", + route: "/audit", + status: input.replayCount > 0 ? "enabled" : "warn", + detail: input.replayCount > 0 ? `可用时间线事件 ${input.replayCount} 条。` : "页面可用,但暂无时间线事件。", + }, + { + id: "health_digest", + name: "健康与日报", + route: "/digest/latest", + status: input.digestConnected ? "enabled" : "warn", + detail: input.digestConnected + ? "健康与日报入口均可用。" + : "健康入口可用,日报将在监控周期后生成。", + }, + { + id: "export_import", + name: "导出 / 导入演练", + route: "/?section=settings", + status: input.importGuard.defaultMode === "blocked" ? "warn" : "enabled", + detail: `导入默认模式:${input.importGuard.defaultMode},导出入口可用。`, + }, + { + id: "pixel", + name: "像素画布适配", + route: "/view/pixel-state.json", + status: "enabled", + detail: "像素场景接口可用。", + }, + { + id: "subscription", + name: "订阅用量与余量", + route: "/?section=usage-cost", + status: input.subscriptionConnected ? "enabled" : "warn", + detail: input.subscriptionConnected + ? `订阅数据已连接${input.budgetConnected ? ",预算预测已启用。" : "。"}` + : "订阅页面可用,本地账单快照尚未连接。", + }, + ]; +} + +function renderParitySurfaceRows(rows: ParitySurfaceRow[]): string { + return rows + .map( + (row) => + `${escapeHtml(row.name)}${badge(row.status)}${escapeHtml(row.route)}${escapeHtml(row.detail)}`, + ) + .join(""); +} + +function parseSubscriptionConnectPaths(connectHint: string | undefined): string[] { + if (!connectHint) return []; + const normalized = connectHint.trim(); + if (!normalized) return []; + const marker = "Provide one of:"; + const body = normalized.startsWith(marker) ? normalized.slice(marker.length).trim() : normalized; + if (!body) return []; + return body.split(",").map((item) => item.trim()).filter((item) => item.length > 0); +} + +function normalizeQuotaWindowLabel(label: string | undefined, fallback: string): string { + const raw = (label ?? "").trim(); + if (!raw) return fallback; + const normalized = raw.toLowerCase(); + if (normalized === "7d" || normalized.includes("week") || normalized.includes("周")) return "Week"; + if (normalized === "5h" || normalized.includes("5h")) return "5h"; + const minuteMatch = /^(\d+(?:\.\d+)?)\s*m$/i.exec(normalized); + if (minuteMatch?.[1]) { + const minutes = Number(minuteMatch[1]); + if (Number.isFinite(minutes)) { + if (Math.abs(minutes - 10080) <= 2) return "Week"; + if (Math.abs(minutes - 300) <= 2) return "5h"; + if (Math.abs(minutes - 1440) <= 2) return "1d"; + } + } + return raw; +} + +function asPercent(value: number | undefined): number | undefined { + if (typeof value !== "number" || !Number.isFinite(value)) return undefined; + if (value < 0) return 0; + if (value > 100) return 100; + return value; +} + +function renderQuotaWindowRow( + input: { + label: string; + usedPercent?: number; + remainingPercent?: number; + resetAt?: string; + }, + language: UiLanguage = "zh", +): string { + const usedPercent = asPercent(input.usedPercent); + const remainingPercent = asPercent(input.remainingPercent); + const usedText = typeof usedPercent === "number" ? `${usedPercent.toFixed(1)}%` : "—"; + const remainingText = typeof remainingPercent === "number" ? `${remainingPercent.toFixed(1)}%` : "—"; + const fillWidth = typeof usedPercent === "number" ? usedPercent : 0; + const resetAt = input.resetAt?.trim(); + const resetText = + !resetAt + ? pickUiText(language, "Not provided", "未提供") + : `${escapeHtml(pickUiText(language, "Loading...", "加载中..."))}`; + return `
    +
    + ${escapeHtml(input.label)} + ${escapeHtml(pickUiText(language, "Used", "已用"))} ${escapeHtml(usedText)} · ${escapeHtml( + pickUiText(language, "Remaining", "剩余"), + )} ${escapeHtml(remainingText)} +
    +
    +
    ${resetText}
    +
    `; +} + +function renderSubscriptionSidebarSummary( + subscription: UsageCostSnapshot["subscription"], + language: UiLanguage = "zh", +): string { + if (subscription.status === "connected" && (subscription.primaryWindowLabel || subscription.secondaryUsedPercent !== undefined)) { + const primaryUsed = asPercent(subscription.primaryUsedPercent ?? subscription.usagePercent); + const primaryRemaining = asPercent( + subscription.primaryRemainingPercent ?? + (typeof primaryUsed === "number" ? 100 - primaryUsed : undefined), + ); + const secondaryUsed = asPercent(subscription.secondaryUsedPercent); + const secondaryRemaining = asPercent( + subscription.secondaryRemainingPercent ?? + (typeof secondaryUsed === "number" ? 100 - secondaryUsed : undefined), + ); + return `
    + ${renderQuotaWindowRow({ + label: normalizeQuotaWindowLabel(subscription.primaryWindowLabel, "5h"), + usedPercent: primaryUsed, + remainingPercent: primaryRemaining, + resetAt: subscription.primaryResetAt ?? subscription.cycleEnd, + }, language)} + ${renderQuotaWindowRow({ + label: normalizeQuotaWindowLabel(subscription.secondaryWindowLabel, "Week"), + usedPercent: secondaryUsed, + remainingPercent: secondaryRemaining, + resetAt: subscription.secondaryResetAt, + }, language)} +
    `; + } + return [ + typeof subscription.consumed === "number" + ? `
    ${subscription.status === "connected" ? pickUiText(language, "Used", "已用") : pickUiText(language, "Estimated used", "估算已用")}:${escapeHtml(formatSubscriptionNumericField(subscription.consumed, subscription.unit, subscription.status === "connected" ? "used" : "estimated_used", language))}
    ` + : "", + typeof subscription.remaining === "number" + ? `
    ${subscription.status === "connected" ? pickUiText(language, "Remaining", "剩余") : pickUiText(language, "Estimated remaining", "估算剩余")}:${escapeHtml(formatSubscriptionNumericField(subscription.remaining, subscription.unit, subscription.status === "connected" ? "remaining" : "estimated_remaining", language))}
    ` + : "", + ] + .filter((item) => item.length > 0) + .join(""); +} + +function renderSubscriptionStatusCard( + subscription: UsageCostSnapshot["subscription"], + language: UiLanguage = "zh", +): string { + const statusLabel = + subscription.status === "connected" + ? pickUiText(language, "Connected", "已连接") + : subscription.status === "partial" + ? pickUiText(language, "Partially connected", "部分连接") + : pickUiText(language, "Not connected", "未连接"); + if (subscription.status === "not_connected") { + const hasEstimatedWindow = + typeof subscription.consumed === "number" || + typeof subscription.remaining === "number" || + typeof subscription.limit === "number"; + const estimateRows = hasEstimatedWindow + ? [ + typeof subscription.consumed === "number" + ? `
    ${escapeHtml(pickUiText(language, "Estimated used", "估算已用"))}:${escapeHtml(formatSubscriptionNumericField(subscription.consumed, subscription.unit, "consumed", language))}
    ` + : "", + typeof subscription.remaining === "number" + ? `
    ${escapeHtml(pickUiText(language, "Estimated remaining", "估算剩余"))}:${escapeHtml(formatSubscriptionNumericField(subscription.remaining, subscription.unit, "remaining", language))}
    ` + : "", + typeof subscription.limit === "number" + ? `
    ${escapeHtml(pickUiText(language, "Estimated total", "估算总额"))}:${escapeHtml(formatSubscriptionNumericField(subscription.limit, subscription.unit, "limit", language))}
    ` + : "", + ] + .filter((item) => item.length > 0) + .join("") + : ""; + return `
    +
    ${escapeHtml(pickUiText(language, "Subscription data is not connected.", "订阅数据未接通。"))} ${escapeHtml( + pickUiText(language, "Current balance is estimated.", "当前余额为估算值。"), + )}
    + ${estimateRows} + +
    `; + } + + if (subscription.primaryWindowLabel || subscription.secondaryUsedPercent !== undefined) { + const primaryUsed = asPercent(subscription.primaryUsedPercent ?? subscription.usagePercent); + const primaryRemaining = asPercent( + subscription.primaryRemainingPercent ?? + (typeof primaryUsed === "number" ? 100 - primaryUsed : undefined), + ); + const secondaryUsed = asPercent(subscription.secondaryUsedPercent); + const secondaryRemaining = asPercent( + subscription.secondaryRemainingPercent ?? + (typeof secondaryUsed === "number" ? 100 - secondaryUsed : undefined), + ); + return `
    +
    ${escapeHtml(pickUiText(language, "Quota windows", "额度窗口"))} ${badge(subscription.status, statusLabel)}
    +
    ${escapeHtml(pickUiText(language, "Only the key windows are shown: 5h and Week.", "仅显示关键额度:5h 与 Week。"))}
    +
    + ${renderQuotaWindowRow({ + label: normalizeQuotaWindowLabel(subscription.primaryWindowLabel, "5h"), + usedPercent: primaryUsed, + remainingPercent: primaryRemaining, + resetAt: subscription.primaryResetAt ?? subscription.cycleEnd, + }, language)} + ${renderQuotaWindowRow({ + label: normalizeQuotaWindowLabel(subscription.secondaryWindowLabel, "Week"), + usedPercent: secondaryUsed, + remainingPercent: secondaryRemaining, + resetAt: subscription.secondaryResetAt, + }, language)} +
    +
    `; + } + + const used = formatSubscriptionNumericField(subscription.consumed, subscription.unit, "consumed", language); + const remaining = formatSubscriptionNumericField(subscription.remaining, subscription.unit, "remaining", language); + const limit = formatSubscriptionNumericField(subscription.limit, subscription.unit, "limit", language); + const cycleStart = subscription.cycleStart?.trim() ? subscription.cycleStart.trim() : pickUiText(language, "Not provided", "未提供"); + const cycleEnd = subscription.cycleEnd?.trim() ? subscription.cycleEnd.trim() : pickUiText(language, "Not provided", "未提供"); + const usagePercent = typeof subscription.usagePercent === "number" ? `${subscription.usagePercent.toFixed(1)}%` : pickUiText(language, "Not provided", "未提供"); + + return `
    +
    ${escapeHtml(subscription.planLabel)} ${badge(subscription.status, statusLabel)}
    +
    ${escapeHtml(pickUiText(language, "Used", "已用"))} ${escapeHtml(used)} · ${escapeHtml( + pickUiText(language, "Remaining", "剩余"), + )} ${escapeHtml(remaining)}
    +
    ${escapeHtml(pickUiText(language, "Limit", "总额"))}:${escapeHtml(limit)} · ${escapeHtml( + pickUiText(language, "Usage", "使用率"), + )}:${escapeHtml(usagePercent)}
    +
    ${escapeHtml(pickUiText(language, "Cycle", "周期"))}:${escapeHtml(cycleStart)} → ${escapeHtml(cycleEnd)}
    +
    `; +} + +export function renderSubscriptionStatusCardForSmoke(subscription: UsageCostSnapshot["subscription"]): string { + return renderSubscriptionStatusCard(subscription, "en"); +} + +export function renderDashboardSectionNavForSmoke( + section: DashboardSection, + language: UiLanguage = "en", +): string { + const activeSection = + section === "office-space" + ? "team" + : section === "calendar" + ? "projects-tasks" + : section; + return dashboardSectionLinks(language).map((item) => { + const activeClass = item.key === activeSection ? " active" : ""; + const current = item.key === activeSection ? ' aria-current="page"' : ""; + return `${escapeHtml(item.label)}`; + }).join(""); +} + +export function renderGlobalVisibilityCardForSmoke(language: UiLanguage): string { + const model: GlobalVisibilityViewModel = { + tasks: [ + { + taskType: "cron", + taskTypeLabel: pickUiText(language, "Timed jobs", "定时任务"), + taskName: pickUiText(language, "Timed jobs", "定时任务"), + executor: pickUiText(language, "System service", "系统服务"), + currentAction: pickUiText(language, "Timed jobs are on.", "定时任务正在运行。"), + nextRun: "2026-03-05T13:30:00.000Z", + latestResult: pickUiText(language, "Active timed jobs: 1.", "已开启定时任务:1 个。"), + status: "done", + nextAction: pickUiText(language, "Keep timed jobs on and keep each job goal clear.", "保持定时任务开启,并确认每个任务目标清楚。"), + detailsHref: buildGlobalVisibilityDetailHref("cron", language), + detailsLabel: pickUiText(language, "See timed jobs", "查看定时任务"), + }, + { + taskType: "heartbeat", + taskTypeLabel: pickUiText(language, "Heartbeat", "任务心跳"), + taskName: pickUiText(language, "Heartbeat", "任务心跳"), + executor: pickUiText(language, "System service", "系统服务"), + currentAction: pickUiText(language, "Heartbeat is on.", "任务心跳已开启。"), + nextRun: "2026-03-05T13:35:00.000Z", + latestResult: pickUiText(language, "Active heartbeat checks: 1.", "已开启任务心跳:1 个。"), + status: "done", + nextAction: pickUiText(language, "Check picked tasks and confirm the choices look right.", "查看挑出的任务,确认挑选结果是否合理。"), + detailsHref: buildGlobalVisibilityDetailHref("heartbeat", language), + detailsLabel: pickUiText(language, "See heartbeat checks", "查看任务心跳"), + }, + { + taskType: "current_task", + taskTypeLabel: pickUiText(language, "Current tasks", "当前任务"), + taskName: pickUiText(language, "Current tasks", "当前任务"), + executor: pickUiText(language, "Task owners", "任务智能体"), + currentAction: pickUiText(language, "Tasks are moving.", "任务正在推进。"), + nextRun: pickUiText(language, "Live update", "实时更新"), + latestResult: pickUiText(language, "2 tasks moving.", "2 个任务在进行中。"), + status: "done", + nextAction: pickUiText(language, "Keep progress updated.", "持续更新任务进度。"), + detailsHref: buildGlobalVisibilityDetailHref("current_task", language), + detailsLabel: pickUiText(language, "See current tasks", "查看当前任务"), + }, + { + taskType: "tool_call", + taskTypeLabel: pickUiText(language, "Tool calls", "工具调用"), + taskName: pickUiText(language, "Tool calls", "工具调用"), + executor: pickUiText(language, "Active sessions", "活跃会话"), + currentAction: pickUiText(language, "Tools were used recently.", "最近有工具在使用。"), + nextRun: pickUiText(language, "Live update", "实时更新"), + latestResult: pickUiText(language, "Tool calls in recent activity: 3.", "最近工具调用:3 次。"), + status: "done", + nextAction: pickUiText(language, "Review results and keep going.", "看下结果后继续。"), + detailsHref: buildGlobalVisibilityDetailHref("tool_call", language), + detailsLabel: pickUiText(language, "See tool calls", "查看工具调用"), + }, + ], + doneCount: 4, + notDoneCount: 0, + noTaskMessage: pickUiText( + language, + "No timed jobs, heartbeat, current tasks, or tool calls yet.", + "暂无定时任务、任务心跳、当前任务或工具调用。", + ), + signalCounts: { + schedule: 1, + heartbeat: 1, + currentTasks: 2, + toolCalls: 3, + }, + }; + + return renderGlobalVisibilityCard(model, language); +} + +export function renderInformationCertaintyCardForSmoke(language: UiLanguage): string { + return renderInformationCertaintyCard( + { + score: 82, + badgeStatus: "ok", + badgeLabel: pickUiText(language, "High certainty", "高确定性"), + headline: pickUiText(language, "This picture is trustworthy enough for day-to-day decisions.", "这张画面已经足够支撑日常判断。"), + summary: pickUiText(language, "Most key signals are connected, so you can judge OpenClaw from one screen with relatively high confidence.", "大部分关键信号都已连上,可以比较放心地用这一屏判断 OpenClaw 的当前状态。"), + strengths: [ + pickUiText(language, "The home picture is fresh enough for current-state decisions.", "首页画面够新,可以直接拿来判断当前状态。"), + pickUiText(language, "Current execution is visible, not just task records on a board.", "现在能看到真实执行中的会话,而不只是任务板上的记录。"), + ], + gaps: [pickUiText(language, "Remaining package room is still unconfirmed.", "套餐剩余额度目前还没有被完全确认。")], + signals: [ + { + key: "freshness", + label: pickUiText(language, "Live picture", "实时画面"), + status: "connected", + detail: pickUiText(language, "Updated just now; suitable for deciding what is happening now.", "刚刚更新,适合直接判断现在发生了什么。"), + }, + { + key: "live_sessions", + label: pickUiText(language, "Live execution", "实时执行"), + status: "connected", + detail: pickUiText(language, "3 live sessions are visible right now.", "当前可见 3 个实时执行中的会话。"), + }, + { + key: "subscription", + label: pickUiText(language, "Subscription room", "订阅额度"), + status: "partial", + detail: pickUiText(language, "Subscription data exists, but part of the billing picture is missing.", "订阅数据已经有了,但账单画面还不完整。"), + }, + ], + }, + language, + ); +} + +export function renderTaskCertaintySectionForSmoke(language: UiLanguage): string { + return renderTaskCertaintySection( + [ + { + taskId: "task-1", + title: pickUiText(language, "Stabilize Mission Control dashboard", "稳定 Mission Control 看板"), + projectTitle: "control-center", + owner: "Panda", + score: 84, + tone: "ok", + toneLabel: pickUiText(language, "Evidence is strong", "证据充分"), + summary: pickUiText(language, "This task already has enough execution evidence for normal follow-up.", "这个任务已经有足够的执行证据,正常跟进即可。"), + evidence: [ + pickUiText(language, "Owner: Panda", "负责人:Panda"), + pickUiText(language, "2 linked sessions", "已关联 2 个会话"), + ], + gaps: [], + detailHref: buildTaskDetailHref("task-1", language), + }, + { + taskId: "task-2", + title: pickUiText(language, "Reconnect billing visibility", "补齐账单可见性"), + projectTitle: "control-center", + owner: "Otter", + score: 41, + tone: "blocked", + toneLabel: pickUiText(language, "Evidence is weak", "证据偏弱"), + summary: pickUiText(language, "Right now there is not enough evidence to say this task is truly moving.", "目前还没有足够证据证明这个任务真的在推进。"), + evidence: [pickUiText(language, "Owner: Otter", "负责人:Otter")], + gaps: [pickUiText(language, "No execution session is linked yet.", "还没有关联执行会话。")], + detailHref: buildTaskDetailHref("task-2", language), + }, + ], + language, + ); +} + +export function renderTaskExecutionChainCardsForSmoke(language: UiLanguage = "zh"): string { + return renderTaskExecutionChainCards( + [ + { + taskTitle: "{\"ok\":true,\"attemptedQueries\":30}", + owner: "main", + sessionKey: "agent:main:cron:worker-1:run:child-1", + agentId: "main", + state: "running", + latestAt: "2026-03-10T19:22:57.330Z", + latestSnippet: "{\"ok\":true,\"attemptedQueries\":30,\"successfulQueries\":2,\"qualified\":2,\"sent\":2,\"failedQueries\":0...", + executionChain: { + accepted: true, + spawned: true, + parentSessionKey: "agent:main:cron:worker-1", + childSessionKey: "agent:main:cron:worker-1:run:child-1", + stage: "running", + source: "history", + inferred: false, + detail: "Parent accepted the work and spawned a child session.", + }, + unmapped: true, + sessionHref: buildSessionDetailHref("agent:main:cron:worker-1:run:child-1", language), + }, + { + taskId: "task-json", + taskTitle: "{\"ok\":false,\"error\":\"locked\"}", + projectTitle: "control-center", + owner: "main", + sessionKey: "agent:main:main", + agentId: "main", + state: "idle", + latestAt: "2026-03-10T19:00:06.442Z", + latestSnippet: "{\"ok\":false,\"error\":\"locked\"}", + executionChain: { + accepted: true, + spawned: false, + stage: "accepted", + source: "history", + inferred: false, + detail: "Parent accepted the work but child execution is still pending.", + }, + unmapped: false, + taskHref: buildTaskDetailHref("task-json", language), + sessionHref: buildSessionDetailHref("agent:main:main", language), + }, + { + taskTitle: "agent:main:cron:worker-2", + owner: "main", + sessionKey: "agent:main:cron:worker-2:run:child-2", + agentId: "main", + state: "idle", + latestAt: "2026-03-11T07:26:38.268Z", + executionChain: { + accepted: true, + spawned: true, + parentSessionKey: "agent:main:cron:worker-2", + childSessionKey: "agent:main:cron:worker-2:run:child-2", + stage: "spawned", + source: "session_key", + inferred: true, + detail: "accepted=yes | spawned=yes | source=session_key | inferred=yes", + }, + unmapped: true, + sessionHref: buildSessionDetailHref("agent:main:cron:worker-2:run:child-2", language), + }, + ], + language, + ); +} + +function stableHashIndex(input: string): number { + let hash = 0; + for (const ch of input) { + hash = (hash * 31 + ch.charCodeAt(0)) >>> 0; + } + return hash; +} + +function renderUsagePeriodCards(periods: UsageCostSnapshot["periods"], language: UiLanguage = "zh"): string { + if (periods.length === 0) { + return `
    ${escapeHtml( + pickUiText(language, "No period snapshot yet because the data source is not connected.", "数据源未连接,暂无周期用量快照。"), + )}
    `; + } + + const cards = periods + .map((period) => { + const periodLabel = usagePeriodLabel(period.key, period.label, language); + const tokenLabel = + period.sourceStatus === "not_connected" + ? pickUiText(language, "Not connected", "数据源未连接") + : formatInt(period.tokens); + const costLabel = + period.sourceStatus === "not_connected" + ? pickUiText(language, "Not connected", "数据源未连接") + : formatCurrency(period.estimatedCost); + const requestLabel = + period.requestCountStatus !== "not_connected" && typeof period.requestCount === "number" + ? String(period.requestCount) + : pickUiText(language, "Not connected", "数据源未连接"); + return `
    ${escapeHtml(periodLabel)}${escapeHtml( + pickUiText(language, "AI usage", "AI 用量"), + )}:${escapeHtml(tokenLabel)}${escapeHtml(pickUiText(language, "Estimated cost", "预估费用"))}:${escapeHtml( + costLabel, + )}${escapeHtml(pickUiText(language, "Requests", "请求数"))}:${escapeHtml(requestLabel)}${escapeHtml( + pickUiText(language, "Pace", "节奏"), + )}:${escapeHtml(period.pace.label)}
    `; + }) + .join(""); + return `
    ${cards}
    `; +} + +function usagePeriodLabel(key: "today" | "7d" | "30d", fallback: string, language: UiLanguage = "zh"): string { + if (key === "today") return pickUiText(language, "Today", "今天"); + if (key === "7d") return pickUiText(language, "Last 7 days", "近 7 天"); + if (key === "30d") return pickUiText(language, "Last 30 days", "近 30 天"); + return fallback; +} + +function renderUsageContextRows(rows: UsageCostSnapshot["contextWindows"], language: UiLanguage): string { + if (rows.length === 0) return ""; + + return rows + .slice(0, 24) + .map((item) => { + const usage = + typeof item.usagePercent === "number" + ? `${formatInt(item.usedTokens)} / ${formatInt(item.contextLimitTokens ?? 0)} (${item.usagePercent.toFixed(1)}%)` + : `${formatInt(item.usedTokens)} / ${pickUiText(language, "Data source not connected", "数据源未连接")}`; + return `${escapeHtml(item.agentId)}${escapeHtml(item.sessionKey)}${escapeHtml(item.model)}
    ${escapeHtml(item.provider)}
    ${usage}${escapeHtml(item.paceLabel)} ${badge(item.thresholdState)}${escapeHtml(item.warningThresholds)}`; + }) + .join(""); +} + +function renderUsageBreakdownRows( + rows: UsageCostSnapshot["breakdown"]["byAgent"], + label: string, + language: UiLanguage = "zh", +): string { + if (rows.length === 0) return ""; + + return rows + .map( + (item) => + `${escapeHtml(simplifyUsageLabel(item.label))}${formatInt(item.tokens)}${formatCurrency(item.estimatedCost)}${item.requests}${item.sessions}${badge(item.sourceStatus, dataConnectionLabel(item.sourceStatus, language))}`, + ) + .join(""); +} + +function renderTokenShareRows( + rows: UsageCostSnapshot["breakdown"]["byAgent"], + totalTokens: number, + language: UiLanguage = "zh", +): string { + if (rows.length === 0) return ""; + const safeTotal = totalTokens > 0 ? totalTokens : rows.reduce((sum, item) => sum + item.tokens, 0); + return rows + .map((item) => { + const share = safeTotal > 0 ? (item.tokens / safeTotal) * 100 : 0; + return `${escapeHtml(simplifyUsageLabel(item.label))}${formatInt(item.tokens)}${formatPercent(share)}${item.sessions}${badge(item.sourceStatus, dataConnectionLabel(item.sourceStatus, language))}`; + }) + .join(""); +} + +const TOKEN_PIE_COLORS = [ + "#4e79a7", + "#f28e2b", + "#e15759", + "#76b7b2", + "#59a14f", + "#edc948", + "#b07aa1", + "#ff9da7", + "#9c755f", + "#bab0ab", +]; + +function renderTokenPieChart( + rows: UsageCostSnapshot["breakdown"]["byAgent"], + totalTokens: number, + centerLabel: string, + language: UiLanguage = "zh", +): string { + const sourceRows = rows.filter((item) => item.tokens > 0); + if (sourceRows.length === 0 || totalTokens <= 0) return ""; + + const segments = [...sourceRows].sort((a, b) => b.tokens - a.tokens); + + let cursor = 0; + const gradientStops: string[] = []; + const legend = segments + .map((item, index) => { + const color = TOKEN_PIE_COLORS[index % TOKEN_PIE_COLORS.length]; + const share = (item.tokens / totalTokens) * 100; + const next = cursor + share; + gradientStops.push(`${color} ${cursor.toFixed(2)}% ${next.toFixed(2)}%`); + cursor = next; + return `
  • ${escapeHtml(simplifyUsageLabel(item.label))}${formatPercent(share)}
  • `; + }) + .join(""); + + const gradient = `conic-gradient(${gradientStops.join(", ")})`; + return `
    +
    +
    ${escapeHtml(centerLabel)}${formatInt(totalTokens)} ${escapeHtml( + pickUiText(language, "tokens", "用量"), + )}
    +
    +
      ${legend}
    +
    `; +} + +function renderUsageConnectorTodos(todos: UsageCostSnapshot["connectors"]["todos"], language: UiLanguage = "zh"): string { + if (todos.length === 0) { + return `
  • ${escapeHtml(pickUiText(language, "All usage connectors are enabled.", "所有用量连接器均已启用。"))}
  • `; + } + const simplifyTitle = (raw: string): string => { + const text = normalizeInlineText(raw); + const lower = text.toLowerCase(); + if (lower.includes("context")) return pickUiText(language, "Model context data", "模型上下文数据"); + if (lower.includes("digest")) return pickUiText(language, "Trend history data", "趋势历史数据"); + if (lower.includes("request")) return pickUiText(language, "Request count data", "请求计数数据"); + if (lower.includes("budget")) return pickUiText(language, "Budget limit data", "预算限额数据"); + if (lower.includes("provider")) return pickUiText(language, "Provider mapping data", "供应商映射数据"); + if (lower.includes("subscription")) return pickUiText(language, "Subscription billing data", "订阅账单数据"); + return pickUiText(language, "Data connector item", "数据连接项"); + }; + const simplifyDetail = (raw: string): string => { + const text = normalizeInlineText(raw); + const lower = text.toLowerCase(); + if (lower.includes("subscription")) return pickUiText(language, "Connect the subscription billing data.", "请连接订阅账单数据。"); + if (lower.includes("digest") || lower.includes("history")) return pickUiText(language, "Keep monitoring running so trend history stays complete.", "请保持监控持续运行,确保趋势数据完整。"); + if (lower.includes("request")) return pickUiText(language, "Connect the request count source.", "请连接请求计数数据源。"); + if (lower.includes("provider")) return pickUiText(language, "Complete the model-to-provider mapping.", "请补全模型到供应商的映射。"); + if (lower.includes("context")) return pickUiText(language, "Connect model context capacity data.", "请连接模型上下文容量信息。"); + if (lower.includes("budget")) return pickUiText(language, "Configure budget limits so the system can warn early.", "请配置预算限额,便于风险预警。"); + return pickUiText(language, "Finish the data connection in Settings.", "请在设置页完成数据连接。"); + }; + return todos + .map((item) => `
  • ${escapeHtml(simplifyTitle(item.title))}:${escapeHtml(simplifyDetail(item.detail))}
  • `) + .join(""); +} + +function formatInt(value: number): string { + return new Intl.NumberFormat("en-US", { + maximumFractionDigits: 0, + }).format(value); +} + +function formatCurrency(value: number): string { + return `$${value.toFixed(2)}`; +} + +function formatPercent(value: number): string { + if (!Number.isFinite(value)) return "0.00%"; + return `${value.toFixed(2)}%`; +} + +function dataConnectionLabel(status: string, language: UiLanguage = "zh"): string { + const normalized = status.trim().toLowerCase(); + if (normalized === "connected") return pickUiText(language, "Connected", "已连接"); + if (normalized === "partial") return pickUiText(language, "Partially connected", "部分连接"); + if (normalized === "not_connected") return pickUiText(language, "Not connected", "未连接"); + return status; +} + +function simplifyUsageLabel(label: string): string { + const normalized = normalizeInlineText(label); + if (!normalized) return "未命名"; + const withoutUuid = normalized.replace(/\s*\([0-9a-f]{8}-[0-9a-f-]{27,}\)\s*/gi, ""); + return safeTruncate(withoutUuid, 72); +} + +function formatSubscriptionNumericField(value: number | undefined, unit: string, field: string, language: UiLanguage = "zh"): string { + if (typeof value === "number") { + if (unit.trim() === "%") return `${value.toFixed(1)}%`; + return `${formatInt(value)} ${unit}`; + } + return pickUiText(language, `Unavailable: subscription data is missing "${field}"`, `不可用:订阅数据缺少「${field}」`); +} + +function formatSubscriptionTextField(value: string | undefined, field: string, language: UiLanguage = "zh"): string { + if (typeof value === "string" && value.trim()) return value.trim(); + return pickUiText(language, `Unavailable: subscription data is missing "${field}"`, `不可用:订阅数据缺少「${field}」`); +} + +function formatSubscriptionPercentField(value: number | undefined, language: UiLanguage = "zh"): string { + if (typeof value === "number") return `${value.toFixed(1)}%`; + return pickUiText(language, "Unavailable: subscription data is missing usage percent", "不可用:订阅数据缺少使用率"); +} + +function normalizeOptionalPatchString( + input: unknown, + label: string, + maxLength: number, +): string | undefined { + if (input === null) return undefined; + if (input === "") return undefined; + if (typeof input !== "string") { + throw new RequestValidationError(`${label} must be a string`, 400); + } + + const trimmed = input.trim(); + if (!trimmed) return undefined; + if (/[\u0000-\u001F\u007F]/.test(trimmed)) { + throw new RequestValidationError(`${label} contains invalid control characters`, 400); + } + if (trimmed.length > maxLength) { + throw new RequestValidationError(`${label} must be <= ${maxLength} characters`, 400); + } + return trimmed; +} + +function isControlCenterMappingTask(task: TaskListItem): boolean { + return ( + task.projectId === "p-live" && + CONTROL_CENTER_MAPPING_TASK_IDS.has(task.taskId) && + task.title.trim().toLowerCase() === task.taskId.trim().toLowerCase() && + task.sessionKeys.length === 0 + ); +} + +function isControlCenterMappingUsageTaskLabel(value: string): boolean { + const normalized = value.trim().toLowerCase(); + if (!normalized) return false; + for (const taskId of CONTROL_CENTER_MAPPING_TASK_IDS) { + if (normalized.includes(`/${taskId}`) || normalized.includes(` ${taskId}`) || normalized.includes(`${taskId} ·`)) { + return true; + } + } + return false; +} + +function renderTaskBoard(tasks: TaskListItem[], language: UiLanguage = "zh"): string { + if (tasks.length === 0) { + return `
    ${escapeHtml(pickUiText(language, "No tasks yet. New tasks will enter the board automatically.", "暂无任务。创建任务后会自动进入泳道。"))}
    `; + } + const lanes = TASK_STATES.map((state) => { + const laneTasks = tasks.filter((task) => task.status === state); + const cards = + laneTasks.length === 0 + ? `
    ${escapeHtml(pickUiText(language, "None", "暂无"))}
    ` + : laneTasks + .map( + (task) => + `
    ${escapeHtml(task.taskId)}
    ${escapeHtml(task.title)}
    ${escapeHtml(task.projectId)} · ${escapeHtml(task.owner)}
    `, + ) + .join(""); + + return `

    ${escapeHtml(taskStateLabel(state, language))}

    ${laneTasks.length} ${escapeHtml(pickUiText(language, "tasks", "个任务"))}
    ${cards}
    `; + }); + + return `
    ${lanes.join("")}
    `; +} + +function renderProjectBoard(projects: ReadModelSnapshot["projectSummaries"], language: UiLanguage = "zh"): string { + if (projects.length === 0) { + return `
    ${escapeHtml(pickUiText(language, "No projects yet. They will appear after project data is connected.", "暂无项目。连接项目数据后会显示。"))}
    `; + } + const lanes = PROJECT_STATES.map((state) => { + const laneProjects = projects.filter((project) => project.status === state); + const cards = + laneProjects.length === 0 + ? `
    ${escapeHtml(pickUiText(language, "None", "暂无"))}
    ` + : laneProjects + .map( + (project) => + `
    ${escapeHtml(project.projectId)} ${badge(project.status, projectStateLabel(project.status, language))}
    ${escapeHtml(project.title)}
    ${escapeHtml(pickUiText(language, "Agent", "智能体"))}:${escapeHtml(project.owner)} | ${escapeHtml(pickUiText(language, "Done", "完成"))}:${project.done}/${project.totalTasks} | ${escapeHtml(pickUiText(language, "Due soon", "即将到期"))}:${project.due}
    `, + ) + .join(""); + + return `

    ${escapeHtml(projectStateLabel(state, language))}

    ${laneProjects.length} ${escapeHtml(pickUiText(language, "projects", "个项目"))}
    ${cards}
    `; + }); + + return `
    ${lanes.join("")}
    `; +} + +function renderActionQueue(center: NotificationCenterSnapshot): string { + if (center.queue.length === 0) { + return "
    暂无决策队列。出现需处理告警后会显示。
    "; + } + + const items = center.queue + .slice(0, 20) + .map((item) => { + const ackMeta = item.acknowledged + ? `已确认于 ${escapeHtml(item.ackedAt ?? "暂无")}${item.ackExpiresAt ? ` · 到期 ${escapeHtml(item.ackExpiresAt)}` : ""}` + : `
    `; + const links = + item.links.length === 0 + ? "" + : `
    相关链接:${item.links + .map((link) => `${escapeHtml(link.label)}`) + .join(" | ")}
    `; + return `
  • ${badge(item.level)} ${escapeHtml(item.itemId)}
    ${escapeHtml(item.message)}
    ${links}
    ${ackMeta}
  • `; + }) + .join(""); + + return `
      ${items}
    `; +} + +function renderSessionPreviewRows(items: SessionConversationListItem[], language: UiLanguage = "zh"): string { + if (items.length === 0) { + return `${escapeHtml(pickUiText(language, "No session data yet.", "暂无会话数据"))}`; + } + + return items + .map((item) => { + const latestKind = item.latestKind ?? "message"; + const latestLabel = item.latestToolName ? `${latestKind}:${item.latestToolName}` : latestKind; + const latestTime = item.latestHistoryAt ? ` @ ${item.latestHistoryAt}` : ""; + const historyState = item.historyError + ? pickUiText(language, `Error: ${item.historyError}`, `错误: ${item.historyError}`) + : `${item.historyCount}`; + const agent = item.agentId ?? "-"; + + return `${escapeHtml(item.sessionKey)}${badge(item.state, sessionStateLabel(item.state))}${escapeHtml(agent)}${badge(latestKind)} ${escapeHtml(latestLabel)}${escapeHtml(latestTime)}${escapeHtml(summarizeVisibleSessionSnippet(item.latestSnippet, language, 220))}${escapeHtml(historyState)}`; + }) + .join(""); +} + +function renderSessionDrilldownPage( + detail: SessionConversationDetailResult, + language: UiLanguage = "en", +): string { + const t = (en: string, zh: string): string => pickUiText(language, en, zh); + const rows = renderSessionHistoryRows(detail.history, language); + const status = detail.status; + const executionChain = detail.executionChain; + const homeHref = buildHomeHref({ quick: "all" }, true, "overview", language); + const executionChainCard = executionChain + ? `
    +

    ${escapeHtml(t("Execution Chain", "执行链"))}

    +
    ${badge(executionChain.stage, executionChainStageLabel(executionChain.stage, language))} ${badge(executionChain.accepted ? "accepted" : "idle", t("Accepted", "已接单"))} ${badge(executionChain.spawned ? "spawn" : "idle", t("Spawned", "已派发"))}
    +
    source=${escapeHtml(executionChain.source)} inferred=${executionChain.inferred ? "yes" : "no"}
    +
    parent=${escapeHtml(executionChain.parentSessionKey ?? "-")} child=${escapeHtml(executionChain.childSessionKey ?? "-")}
    +
    acceptedAt=${escapeHtml(executionChain.acceptedAt ?? "-")} spawnedAt=${escapeHtml(executionChain.spawnedAt ?? "-")}
    +
    ${escapeHtml(executionChain.detail)}
    +
    ` + : `
    +

    ${escapeHtml(t("Execution Chain", "执行链"))}

    +
    ${escapeHtml(t("No accepted/spawn evidence found yet. If this is a child run session, it will still appear once the session key or history provides a chain signal.", "当前还没有接单/派发证据。如果这是子执行会话,待会话 key 或历史记录补齐链路信号后会显示。"))}
    +
    `; + + return ` + + + + ${escapeHtml(t("OpenClaw Control Center Session Drilldown", "OpenClaw 控制中心会话详情"))} + + + +

    ${escapeHtml(t("Session Drilldown", "会话详情"))}

    +
    ${escapeHtml(detail.session.sessionKey)} | state=${escapeHtml(detail.session.state)} | generatedAt=${escapeHtml(detail.generatedAt)}
    + +
    +
    session=${escapeHtml(detail.session.sessionKey)} label=${escapeHtml(detail.session.label ?? "-")} agent=${escapeHtml(detail.session.agentId ?? "-")}
    +
    lastMessageAt=${escapeHtml(detail.session.lastMessageAt ?? "-")} latestEvent=${escapeHtml(detail.latestKind ?? "-")} role=${escapeHtml(detail.latestRole ?? "-")} tool=${escapeHtml(detail.latestToolName ?? "-")} latestHistoryAt=${escapeHtml(detail.latestHistoryAt ?? "-")}
    +
    historyCount=${detail.historyCount} historyLimit=readonly-safe
    +
    historyError=${escapeHtml(detail.historyError ?? "none")}
    +
    status model=${escapeHtml(status?.model ?? "-")} tokensIn=${status?.tokensIn ?? 0} tokensOut=${status?.tokensOut ?? 0} cost=${status?.cost ?? 0} updatedAt=${escapeHtml(status?.updatedAt ?? "-")}
    +
    + + ${executionChainCard} + +
    +

    ${escapeHtml(t("Latest Messages / Tool Events", "最近消息 / 工具事件"))}

    + + + ${rows} +
    ${escapeHtml(t("timestamp", "时间"))}${escapeHtml(t("kind", "类型"))}${escapeHtml(t("role", "角色"))}${escapeHtml(t("tool", "工具"))}${escapeHtml(t("status", "状态"))}${escapeHtml(t("content", "内容"))}
    +
    + +

    ${escapeHtml(t("Back to overview", "返回总览"))} | ${escapeHtml(t("Session JSON API", "会话 JSON 接口"))}

    + +`; +} + +export function renderSessionDrilldownPageForSmoke( + detail: SessionConversationDetailResult, + language: UiLanguage = "en", +): string { + return renderSessionDrilldownPage(detail, language); +} + +function renderSessionHistoryRows(items: SessionHistoryMessage[], language: UiLanguage = "en"): string { + if (items.length === 0) { + return `${escapeHtml(pickUiText(language, "Not activated yet", "尚未激活"))}`; + } + + const newestFirst = [...items].reverse().slice(0, 160); + return newestFirst + .map((item) => { + const tool = item.toolName ?? "-"; + const status = item.toolStatus ?? "-"; + const refs = [ + item.parentSessionKey ? `parent=${item.parentSessionKey}` : "", + item.childSessionKey ? `child=${item.childSessionKey}` : "", + ] + .filter(Boolean) + .join(" | "); + const content = refs ? `${safeTruncate(item.content, 620)}\n${refs}` : safeTruncate(item.content, 700); + const suffix = item.truncated ? " [truncated]" : ""; + return `${escapeHtml(item.timestamp ?? "-")}${badge(item.kind)}${escapeHtml(item.role)}${escapeHtml(tool)}${escapeHtml(status)}${escapeHtml(content + suffix)}`; + }) + .join(""); +} + +function renderAuditPage(timeline: AuditTimelineSnapshot, severity: AuditSeverity | "all"): string { + const rows = + timeline.events.length === 0 + ? "Not activated yet" + : timeline.events + .slice(0, 300) + .map( + (event) => + `${escapeHtml(event.timestamp)}${badge(event.severity)}${escapeHtml(event.source)}${escapeHtml(event.message)}`, + ) + .join(""); + + return ` + + + + OpenClaw Control Center Audit Timeline + + + +

    Audit Timeline

    +
    newest-first runtime events from snapshot, monitor timeline log, and approval action audit log
    +
    +
    + + + +
    +
    + generatedAt=${escapeHtml(timeline.generatedAt)} | info=${timeline.counts.info} warn=${timeline.counts.warn} action_required=${timeline.counts["action-required"]} error=${timeline.counts.error} +
    + + + ${rows} +
    timestampseveritysourcemessage
    +
    +

    home | audit api

    + +`; +} + +export function renderAuditPageForSmoke( + timeline: AuditTimelineSnapshot, + severity: AuditSeverity | "all", +): string { + return renderAuditPage(timeline, severity); +} + +function renderTaskDetailPage(input: { + task: TaskListItem; + generatedAt: string; + certaintyCard?: TaskCertaintyCard; + linkedSessions?: TaskDetailSessionSignal[]; + language?: UiLanguage; +}): string { + const language = input.language ?? "zh"; + const task = input.task; + const certaintyCard = input.certaintyCard; + const linkedSessions = input.linkedSessions ?? []; + const t = (en: string, zh: string): string => pickUiText(language, en, zh); + return ` + + + + ${escapeHtml(t("Task detail", "任务详情"))} · ${escapeHtml(task.taskId)} + + + +
    +
    +

    ${escapeHtml(task.title)}

    +
    ${escapeHtml(t("Task detail page", "任务详情页"))} · ${escapeHtml(t("Generated at", "生成于"))} ${escapeHtml(input.generatedAt)}
    +
    +
    +

    ${escapeHtml(t("Key facts", "关键信息"))}

    +
    ${escapeHtml(task.taskId)} ${badge(task.status, taskStateLabel(task.status, language))}
    +
    ${escapeHtml(t("Project", "项目"))}:${escapeHtml(task.projectTitle)}(${escapeHtml(task.projectId)})
    +
    ${escapeHtml(t("Owner", "负责人"))}:${escapeHtml(task.owner)}
    +
    ${escapeHtml(t("Due time", "截止时间"))}:${escapeHtml(task.dueAt ?? t("Not set", "未设置"))}
    +
    ${escapeHtml(t("Updated at", "更新时间"))}:${escapeHtml(task.updatedAt)}
    +
    ${escapeHtml(t("Sessions", "会话"))}:${task.sessionKeys.length > 0 ? task.sessionKeys.map((id) => `${escapeHtml(id)}`).join(" · ") : escapeHtml(t("None yet", "暂无"))}
    +
    +
    +

    ${escapeHtml(t("Execution certainty", "确定性判断"))}

    + ${ + certaintyCard + ? `
    ${badge(certaintyCard.tone, certaintyCard.toneLabel)} · ${certaintyCard.score} ${escapeHtml(t("points", "分"))}
    +
    ${escapeHtml(certaintyCard.summary)}
    +
    ${escapeHtml(t("Confirmed", "已确认"))}:${escapeHtml(certaintyCard.evidence.join(" · ") || t("No direct evidence yet.", "暂时没有直接证据。"))}
    +
    ${escapeHtml(t("Still missing", "仍待确认"))}:${escapeHtml(certaintyCard.gaps.join(" · ") || t("No obvious gap right now.", "当前没有明显缺口。"))}
    ` + : `
    ${escapeHtml(t("There is not enough data to judge execution certainty yet.", "当前没有足够数据生成确定性判断。"))}
    ` + } +
    +
    +

    ${escapeHtml(t("Session evidence", "会话证据"))}

    + ${ + linkedSessions.length > 0 + ? `
      ${linkedSessions + .map( + (session) => + `
    • ${escapeHtml(session.sessionKey)} ${badge(session.state, sessionStateLabel(session.state))}
      ${escapeHtml(pickUiText(language, "Agent", "智能体"))}:${escapeHtml(session.agentId ?? pickUiText(language, "Unassigned", "未分配"))} · ${escapeHtml(pickUiText(language, "Latest activity", "最近活动"))}:${escapeHtml(session.latestAt ? formatTimeAgoFromNow(session.latestAt, language) : pickUiText(language, "unknown", "未知"))}
      ${escapeHtml(summarizeVisibleSessionSnippet(session.latestSnippet, language, 120))}
    • `, + ) + .join("")}
    ` + : `
    ${escapeHtml(pickUiText(language, "No session evidence is visible yet.", "当前还没有可显示的会话证据。"))}
    ` + } +
    + +
    + +`; +} + +function renderCronJobDetailPage( + job: { + jobId: string; + name: string; + owner: string; + purpose: string; + schedule: string; + status: string; + nextRunAt: string; + dueInSeconds?: number; + }, + generatedAt: string, + language: UiLanguage = "zh", +): string { + return ` + + + + ${escapeHtml(pickUiText(language, "Cron detail", "Cron 详情"))} · ${escapeHtml(job.jobId)} + + + +
    +
    +

    ${escapeHtml(job.name)}

    +
    ${escapeHtml(pickUiText(language, "Cron detail page", "Cron 任务详情页"))} · ${escapeHtml(pickUiText(language, "Generated at", "生成于"))} ${escapeHtml(generatedAt)}
    +
    +
    +

    ${escapeHtml(pickUiText(language, "Key facts", "关键信息"))}

    +
    ${escapeHtml(job.jobId)} ${badge(job.status, cronHealthLabel(job.status, language))}
    +
    ${escapeHtml(pickUiText(language, "Agent", "执行智能体"))}:${escapeHtml(job.owner)}
    +
    ${escapeHtml(pickUiText(language, "Purpose", "任务目的"))}:${escapeHtml(job.purpose)}
    +
    ${escapeHtml(pickUiText(language, "Schedule", "调度"))}:${escapeHtml(job.schedule)}
    +
    ${escapeHtml(pickUiText(language, "Next run", "下次运行"))}:${escapeHtml(job.nextRunAt)} · ${escapeHtml(formatSeconds(job.dueInSeconds, language))}
    +
    + +
    + +`; +} + +function buildBudgetBars( + evaluations: BudgetEvaluation[], + scope: "agent" | "project", +): BudgetBarModel[] { + return evaluations + .filter((item) => item.scope === scope) + .map((item) => { + const metric = pickPrimaryMetric(item.metrics); + if (!metric) { + return { + label: item.label, + status: item.status, + metric: "n/a", + used: 0, + limit: 0, + ratio: 0, + }; + } + + return { + label: item.label, + status: item.status, + metric: metric.metric, + used: metric.used, + limit: metric.limit, + ratio: metric.limit > 0 ? metric.used / metric.limit : 0, + }; + }); +} + +function pickPrimaryMetric(metrics: BudgetMetricEvaluation[]): BudgetMetricEvaluation | undefined { + return metrics.find((metric) => metric.metric === "totalTokens") ?? metrics[0]; +} + +function renderBudgetBars(items: BudgetBarModel[]): string { + if (items.length === 0) return "
    暂无数据
    "; + + return items + .map((item) => { + const width = Math.max(0, Math.min(100, Math.round(item.ratio * 100))); + return `
    ${escapeHtml(item.label)}${escapeHtml(item.metric)} ${item.used.toFixed(2)}/${item.limit.toFixed(2)}
    `; + }) + .join(""); +} + +function renderSelectOptions( + options: Array<{ value: string; label: string }>, + selectedValue: string, +): string { + return options + .map((option) => { + const selected = option.value === selectedValue ? " selected" : ""; + return ``; + }) + .join(""); +} + +function uniqueSorted(values: string[]): string[] { + return [...new Set(values.filter((value) => value.trim() !== ""))].sort((a, b) => a.localeCompare(b)); +} + +function renderExceptionsList(feed: CommanderExceptionsFeed): string { + const top = feed.items.slice(0, 12); + if (top.length === 0) return "
  • 暂无异常
  • "; + + return top + .map( + (item) => + `
  • ${badge(item.level)} ${escapeHtml(item.message)} ${escapeHtml(item.sourceId)} · ${escapeHtml(item.occurredAt ?? "-")}
  • `, + ) + .join(""); +} + +function renderReadinessRows(checklist: DoneChecklistSnapshot): string { + return checklist.readiness.categories + .map((item) => { + return `
    ${escapeHtml(item.category)}
    ${item.score}
    通过=${item.passed} 关注=${item.warn} 失败=${item.failed}
    `; + }) + .join(""); +} + +function renderChecklistRows(checklist: DoneChecklistSnapshot): string { + const top = checklist.items.slice(0, 16); + if (top.length === 0) { + return "暂无检查项"; + } + return top + .map((item) => { + return `${escapeHtml(item.category)}${escapeHtml(item.title)}${badge(item.status)}${escapeHtml(item.detail)}${linkifyDocRef(item.docRef)}`; + }) + .join(""); +} + +function resolveDocPath(docId: string): string | undefined { + const normalized = docId.trim().toLowerCase(); + if (normalized === "readme") return README_PATH; + if (normalized === "runbook") return join(DOCS_DIR, "RUNBOOK.md"); + if (normalized === "architecture") return join(DOCS_DIR, "ARCHITECTURE.md"); + if (normalized === "progress") return join(DOCS_DIR, "PROGRESS.md"); + return undefined; +} + +function linkifyDocRef(docRef: string): string { + let linked = escapeHtml(docRef); + for (const link of DOC_LINKS) { + const escapedLabel = escapeHtml(link.label); + linked = linked.replaceAll(escapedLabel, `${escapedLabel}`); + } + return linked; +} + +function compareApprovals( + a: ReadModelSnapshot["approvals"][number], + b: ReadModelSnapshot["approvals"][number], +): number { + const statusDiff = approvalStatusRank(a.status) - approvalStatusRank(b.status); + if (statusDiff !== 0) return statusDiff; + const timeDiff = toSortableMs(b.updatedAt ?? b.requestedAt) - toSortableMs(a.updatedAt ?? a.requestedAt); + if (timeDiff !== 0) return timeDiff; + return a.approvalId.localeCompare(b.approvalId); +} + +function approvalStatusRank(status: string | undefined): number { + if (status === "pending") return 0; + if (status === "unknown") return 1; + if (status === "denied") return 2; + if (status === "approved") return 3; + return 4; +} + +function toSortableMs(value: string | undefined): number { + if (!value) return 0; + const parsed = Date.parse(value); + return Number.isNaN(parsed) ? 0 : parsed; +} + +function renderMetricSummary(item: BudgetEvaluation): string { + if (!Array.isArray(item.metrics) || item.metrics.length === 0) return "-"; + return item.metrics + .map((metric) => `${escapeHtml(metric.metric)} ${metric.used.toFixed(2)}/${metric.limit.toFixed(2)}`) + .join(", "); +} + +function formatSeconds(value: number | undefined, language: UiLanguage = "en"): string { + if (!Number.isFinite(value)) return "-"; + const seconds = Math.round(value as number); + if (seconds === 0) return language === "zh" ? "现在" : "now"; + const abs = Math.abs(seconds); + const sign = seconds < 0 ? "-" : ""; + if (language === "zh") { + if (abs < 60) return `${sign}${abs}秒`; + const minutes = Math.floor(abs / 60); + const rem = abs % 60; + if (minutes < 60) return rem === 0 ? `${sign}${minutes}分` : `${sign}${minutes}分${rem}秒`; + const hours = Math.floor(minutes / 60); + const remMinutes = minutes % 60; + return remMinutes === 0 ? `${sign}${hours}小时` : `${sign}${hours}小时${remMinutes}分`; + } + if (abs < 60) return `${sign}${abs}s`; + const minutes = Math.floor(abs / 60); + const rem = abs % 60; + if (minutes < 60) return `${sign}${minutes}m ${rem}s`; + const hours = Math.floor(minutes / 60); + const remMinutes = minutes % 60; + return `${sign}${hours}h ${remMinutes}m`; +} + +function formatMs(value: number | undefined, language: UiLanguage = "en"): string { + if (!Number.isFinite(value)) return "-"; + return formatSeconds(Math.round((value as number) / 1000), language); +} + +function badge(status: string, label?: string): string { + const safeStatus = escapeHtml(status); + const safeLabel = escapeHtml(label ?? status); + return `${safeLabel}`; +} + +async function readJsonBody(req: IncomingMessage): Promise { + const text = await readRawBody(req, JSON_MAX_BYTES); + if (!text) return {}; + + try { + return JSON.parse(text) as unknown; + } catch { + throw new RequestValidationError("Invalid JSON body.", 400); + } +} + +async function readFormBody(req: IncomingMessage): Promise { + const text = await readRawBody(req, FORM_MAX_BYTES); + return new URLSearchParams(text); +} + +async function readRawBody(req: IncomingMessage, maxBytes: number): Promise { + const chunks: Buffer[] = []; + let size = 0; + + for await (const chunk of req) { + const buffer = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : Buffer.from(chunk); + size += buffer.length; + if (size > maxBytes) throw new RequestValidationError("Request payload too large.", 413); + chunks.push(buffer); + } + + if (chunks.length === 0) return ""; + return Buffer.concat(chunks).toString("utf8").trim(); +} + +function writeJson(res: ServerResponse, statusCode: number, body: unknown): void { + writeText( + res, + statusCode, + JSON.stringify(attachRequestIdToBody(body, responseRequestId(res)), null, 2), + "application/json; charset=utf-8", + ); +} + +function writeApiError( + res: ServerResponse, + statusCode: number, + code: "VALIDATION_ERROR" | "NOT_FOUND" | "UNSUPPORTED_MEDIA_TYPE" | "INTERNAL_ERROR", + message: string, + issues?: string[], +): void { + const requestId = responseRequestId(res); + writeJson(res, statusCode, { + ok: false, + requestId, + error: { + code, + status: statusCode, + message, + issues, + requestId, + }, + }); +} + +function writeText( + res: ServerResponse, + statusCode: number, + body: string, + contentType: string, +): void { + const headers: Record = { "content-type": contentType }; + const normalizedContentType = contentType.toLowerCase(); + if (normalizedContentType.includes("text/html")) { + headers["cache-control"] = "no-store, no-cache, must-revalidate, max-age=0"; + headers.pragma = "no-cache"; + headers.expires = "0"; + } + const requestId = responseRequestId(res); + if (requestId) { + headers["x-request-id"] = requestId; + } + res.writeHead(statusCode, headers); + res.end(body); +} + +function redirect(res: ServerResponse, statusCode: number, location: string): void { + const headers: Record = { location }; + const requestId = responseRequestId(res); + if (requestId) headers["x-request-id"] = requestId; + res.writeHead(statusCode, headers); + res.end(); +} + +function resolveRequestId(req: IncomingMessage): string { + const headerValue = req.headers["x-request-id"]; + if (typeof headerValue === "string") { + const normalized = sanitizeRequestId(headerValue); + if (normalized) return normalized; + } + if (Array.isArray(headerValue)) { + for (const candidate of headerValue) { + const normalized = sanitizeRequestId(candidate); + if (normalized) return normalized; + } + } + return randomUUID(); +} + +function sanitizeRequestId(value: string): string | undefined { + const trimmed = value.trim(); + if (!trimmed) return undefined; + if (trimmed.length > 80) return undefined; + if (!/^[a-zA-Z0-9._:-]+$/.test(trimmed)) return undefined; + return trimmed; +} + +function responseRequestId(res: ServerResponse): string | undefined { + const value = res.getHeader("x-request-id"); + return typeof value === "string" && value.trim() !== "" ? value : undefined; +} + +function attachRequestIdToBody(body: unknown, requestId: string | undefined): unknown { + if (!requestId) return body; + const obj = asObject(body); + if (!obj) return body; + if (typeof obj.requestId === "string" && obj.requestId.trim() !== "") return body; + return { + requestId, + ...obj, + }; +} + +function assertMutationAuthorized( + req: IncomingMessage, + routeLabel: string, + explicitToken?: string | null, +): void { + const token = + normalizeToken(explicitToken) ?? + normalizeToken(readHeaderValue(req, LOCAL_TOKEN_HEADER)) ?? + normalizeToken(readAuthorizationBearer(readHeaderValue(req, "authorization"))); + const decision = evaluateLocalTokenGate({ + gateRequired: LOCAL_TOKEN_AUTH_REQUIRED, + configuredToken: LOCAL_API_TOKEN, + providedToken: token, + routeLabel, + }); + if (!decision.ok) { + throw new RequestValidationError(decision.message, decision.statusCode); + } +} + +function readHeaderValue(req: IncomingMessage, name: string): string | undefined { + const value = req.headers[name]; + if (typeof value === "string") return value; + if (Array.isArray(value)) return value[0]; + return undefined; +} + +function assertJsonContentType(req: IncomingMessage): void { + const contentType = req.headers["content-type"]; + if (typeof contentType !== "string" || !contentType.toLowerCase().includes("application/json")) { + throw new RequestValidationError( + "JSON request body must use 'Content-Type: application/json'.", + 415, + ); + } +} + +function assertAllowedQueryParams( + searchParams: URLSearchParams, + allowed: string[], + strict: boolean, +): void { + if (!strict) return; + const allowedSet = new Set(allowed); + const unknown = [...new Set([...searchParams.keys()].filter((key) => !allowedSet.has(key)))]; + if (unknown.length === 0) return; + throw new RequestValidationError( + `Unknown query parameter(s): ${unknown.join(", ")}`, + 400, + unknown.map((key) => `query '${key}' is not supported`), + ); +} + +function expectObject(input: unknown, label: string): Record { + const obj = asObject(input); + if (!obj) throw new RequestValidationError(`${label} must be a JSON object.`, 400); + return obj; +} + +function decodeRouteParam(path: string, pattern: RegExp, label: string): string { + const match = path.match(pattern); + if (!match) throw new RequestValidationError(`${label} route parameter is required.`, 400); + + try { + const decoded = decodeURIComponent(match[1]).trim(); + if (!decoded) throw new Error("empty"); + if (decoded.length > 240) { + throw new RequestValidationError(`${label} route parameter must be <= 240 characters.`, 400); + } + if (/[\u0000-\u001F\u007F]/.test(decoded)) { + throw new RequestValidationError(`${label} route parameter contains invalid control characters.`, 400); + } + return decoded; + } catch (error) { + if (error instanceof RequestValidationError) throw error; + throw new RequestValidationError(`${label} route parameter is invalid.`, 400); + } +} + +function normalizeQueryString( + value: string | null, + label: string, + maxLength: number, + strict: boolean, +): string | undefined { + if (!value) return undefined; + const trimmed = value.trim(); + if (!trimmed) return undefined; + + if (/[\u0000-\u001F\u007F]/.test(trimmed)) { + if (strict) throw new RequestValidationError(`${label} contains invalid control characters`, 400); + return undefined; + } + + if (trimmed.length > maxLength) { + if (strict) throw new RequestValidationError(`${label} must be <= ${maxLength} characters`, 400); + return undefined; + } + + return trimmed; +} + +function readPositiveIntQuery( + value: string | null, + label: string, + fallback: number, + strict: boolean, + maxValue = 1000, +): number { + if (!value) return fallback; + const trimmed = value.trim(); + if (!trimmed) return fallback; + const parsed = Number.parseInt(trimmed, 10); + if (!Number.isFinite(parsed) || parsed <= 0 || parsed > maxValue) { + if (strict) throw new RequestValidationError(`${label} must be an integer in range 1..${maxValue}`, 400); + return fallback; + } + return parsed; +} + +function readRequiredFormValue(form: URLSearchParams, key: string): string { + const raw = form.get(key)?.trim(); + if (!raw) throw new RequestValidationError(`${key} is required.`, 400); + if (raw.length > 260) throw new RequestValidationError(`${key} must be <= 260 characters.`, 400); + return raw; +} + +function requiredBoundedString(input: unknown, label: string, maxLength: number): string { + if (typeof input !== "string" || input.trim() === "") { + throw new RequestValidationError(`${label} is required.`, 400); + } + const trimmed = input.trim(); + if (trimmed.length > maxLength) { + throw new RequestValidationError(`${label} must be <= ${maxLength} characters`, 400); + } + return trimmed; +} + +function optionalBoundedString( + input: unknown, + label: string, + maxLength: number, +): string | undefined { + if (input === undefined) return undefined; + if (typeof input !== "string") { + throw new RequestValidationError(`${label} must be a string`, 400); + } + const trimmed = input.trim(); + if (!trimmed) return undefined; + if (trimmed.length > maxLength) { + throw new RequestValidationError(`${label} must be <= ${maxLength} characters`, 400); + } + return trimmed; +} + +function boundedTextField(input: unknown, label: string, maxLength: number): string { + if (typeof input !== "string") { + throw new RequestValidationError(`${label} must be a string`, 400); + } + if (input.length > maxLength) { + throw new RequestValidationError(`${label} must be <= ${maxLength} characters`, 400); + } + return input; +} + +function optionalIntegerField( + input: unknown, + label: string, + min: number, + max: number, +): number | undefined { + if (input === undefined || input === null || input === "") return undefined; + if (typeof input !== "number" || !Number.isInteger(input)) { + throw new RequestValidationError(`${label} must be an integer.`, 400); + } + if (input < min || input > max) { + throw new RequestValidationError(`${label} must be in range ${min}..${max}.`, 400); + } + return input; +} + +function optionalIsoTimestampField(input: unknown, label: string): string | undefined { + if (input === undefined || input === null || input === "") return undefined; + if (typeof input !== "string") { + throw new RequestValidationError(`${label} must be an ISO date-time string.`, 400); + } + const trimmed = input.trim(); + if (!trimmed) return undefined; + if (trimmed.length > 80) { + throw new RequestValidationError(`${label} must be <= 80 characters.`, 400); + } + const parsed = Date.parse(trimmed); + if (Number.isNaN(parsed)) { + throw new RequestValidationError(`${label} must be a valid ISO date-time string.`, 400); + } + return new Date(parsed).toISOString(); +} + +function safeTruncate(input: string, maxLength: number): string { + if (input.length <= maxLength) return input; + if (maxLength <= 3) return input.slice(0, Math.max(0, maxLength)); + return `${input.slice(0, maxLength - 3)}...`; +} + +function projectTitleMap(snapshot: ReadModelSnapshot): Map { + return new Map(snapshot.projects.projects.map((project) => [project.projectId, project.title])); +} + +function asObject(v: unknown): Record | undefined { + return v !== null && typeof v === "object" && !Array.isArray(v) ? (v as Record) : undefined; +} + +function asArray(v: unknown): unknown[] { + return Array.isArray(v) ? v : []; +} + +function asString(v: unknown): string | undefined { + return typeof v === "string" ? v : undefined; +} + +function escapeHtml(input: string): string { + return input + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); +} + +function defaultSnapshot(): ReadModelSnapshot { + const now = new Date().toISOString(); + return { + sessions: [], + statuses: [], + cronJobs: [], + approvals: [], + projects: { projects: [], updatedAt: now }, + projectSummaries: [], + tasks: { tasks: [], agentBudgets: [], updatedAt: now }, + tasksSummary: { + projects: 0, + tasks: 0, + todo: 0, + inProgress: 0, + blocked: 0, + done: 0, + owners: 0, + artifacts: 0, + }, + budgetSummary: { total: 0, ok: 0, warn: 0, over: 0, evaluations: [] }, + generatedAt: now, + }; +} + +class RequestValidationError extends Error { + readonly issues?: string[]; + + constructor( + message: string, + readonly statusCode: number, + issues?: string[], + ) { + super(message); + this.name = "RequestValidationError"; + this.issues = issues; + } +} diff --git a/test/agent-roster.test.ts b/test/agent-roster.test.ts new file mode 100644 index 0000000..1fa848c --- /dev/null +++ b/test/agent-roster.test.ts @@ -0,0 +1,79 @@ +import assert from "node:assert/strict"; +import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import test from "node:test"; + +test("agent roster treats openclaw.json as the current-project source of truth", async () => { + const home = await mkdtemp(join(tmpdir(), "control-center-roster-")); + const originalHome = process.env.OPENCLAW_HOME; + const originalConfigPath = process.env.OPENCLAW_CONFIG_PATH; + + try { + await mkdir(join(home, "agents", "pandas"), { recursive: true }); + await mkdir(join(home, "agents", "otter"), { recursive: true }); + await writeFile( + join(home, "openclaw.json"), + JSON.stringify( + { + agents: { + list: [ + { id: "main", name: "main" }, + { id: "pandas", name: "pandas" }, + ], + }, + }, + null, + 2, + ), + "utf8", + ); + + process.env.OPENCLAW_HOME = home; + delete process.env.OPENCLAW_CONFIG_PATH; + + const { loadBestEffortAgentRoster } = await import("../src/runtime/agent-roster"); + const roster = await loadBestEffortAgentRoster(); + + assert.equal(roster.status, "connected"); + assert.equal(roster.entries.length, 2); + assert(roster.entries.some((entry) => entry.agentId === "main")); + assert(roster.entries.some((entry) => entry.agentId === "pandas")); + assert(!roster.entries.some((entry) => entry.agentId === "otter")); + assert(roster.detail.includes("source of truth")); + } finally { + if (originalHome === undefined) delete process.env.OPENCLAW_HOME; + else process.env.OPENCLAW_HOME = originalHome; + if (originalConfigPath === undefined) delete process.env.OPENCLAW_CONFIG_PATH; + else process.env.OPENCLAW_CONFIG_PATH = originalConfigPath; + await rm(home, { recursive: true, force: true }); + } +}); + +test("agent roster stays connected from runtime when openclaw.json is missing", async () => { + const home = await mkdtemp(join(tmpdir(), "control-center-roster-runtime-")); + const originalHome = process.env.OPENCLAW_HOME; + const originalConfigPath = process.env.OPENCLAW_CONFIG_PATH; + + try { + await mkdir(join(home, "agents", "monkey"), { recursive: true }); + await mkdir(join(home, "agents", "tiger"), { recursive: true }); + + process.env.OPENCLAW_HOME = home; + delete process.env.OPENCLAW_CONFIG_PATH; + + const { loadBestEffortAgentRoster } = await import("../src/runtime/agent-roster"); + const roster = await loadBestEffortAgentRoster(); + + assert.equal(roster.status, "connected"); + assert.equal(roster.entries.length, 2); + assert(roster.entries.some((entry) => entry.agentId === "monkey")); + assert(roster.entries.some((entry) => entry.agentId === "tiger")); + } finally { + if (originalHome === undefined) delete process.env.OPENCLAW_HOME; + else process.env.OPENCLAW_HOME = originalHome; + if (originalConfigPath === undefined) delete process.env.OPENCLAW_CONFIG_PATH; + else process.env.OPENCLAW_CONFIG_PATH = originalConfigPath; + await rm(home, { recursive: true, force: true }); + } +}); diff --git a/test/commander-ordering.test.ts b/test/commander-ordering.test.ts new file mode 100644 index 0000000..d9359c4 --- /dev/null +++ b/test/commander-ordering.test.ts @@ -0,0 +1,163 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +test("commander exceptions feed ordering is deterministic by severity then time", async () => { + const { commanderExceptionsFeed } = await import("../src/runtime/commander"); + + const snapshot = { + sessions: [ + { + sessionKey: "s-error", + state: "error", + agentId: "agent-1", + label: "Error Session", + lastMessageAt: "2026-03-01T10:00:00.000Z", + }, + { + sessionKey: "s-blocked", + state: "blocked", + agentId: "agent-2", + label: "Blocked Session", + lastMessageAt: "2026-03-01T11:00:00.000Z", + }, + ], + statuses: [], + cronJobs: [], + approvals: [ + { + approvalId: "approval-b", + status: "pending", + requestedAt: "2026-03-01T09:00:00.000Z", + updatedAt: "2026-03-01T09:00:00.000Z", + }, + { + approvalId: "approval-a", + status: "pending", + requestedAt: "2026-03-01T09:00:00.000Z", + updatedAt: "2026-03-01T09:00:00.000Z", + }, + ], + projects: { + updatedAt: "2026-03-01T08:00:00.000Z", + projects: [], + }, + projectSummaries: [], + tasks: { + updatedAt: "2026-03-01T08:00:00.000Z", + agentBudgets: [], + tasks: [], + }, + tasksSummary: { + projects: 0, + tasks: 0, + todo: 0, + inProgress: 0, + blocked: 0, + done: 0, + owners: 0, + artifacts: 0, + }, + budgetSummary: { + total: 0, + ok: 0, + warn: 0, + over: 0, + evaluations: [], + }, + generatedAt: "2026-03-01T12:00:00.000Z", + } as const; + + const first = commanderExceptionsFeed(snapshot).items.map((item) => ({ + level: item.level, + code: item.code, + sourceId: item.sourceId, + occurredAt: item.occurredAt, + })); + const second = commanderExceptionsFeed(snapshot).items.map((item) => ({ + level: item.level, + code: item.code, + sourceId: item.sourceId, + occurredAt: item.occurredAt, + })); + + assert.deepEqual(first, second); + assert.equal(first[0]?.level, "action-required"); + assert.equal(first[0]?.code, "SESSION_ERROR"); + assert.equal(first[1]?.code, "PENDING_APPROVAL"); + assert.equal(first[1]?.sourceId, "approval-a"); + assert.equal(first[2]?.sourceId, "approval-b"); +}); + +test("stale runtime issue sessions stay out of the current action queue", async () => { + const { commanderExceptions, commanderExceptionsFeed } = await import("../src/runtime/commander"); + + const now = new Date(); + const freshAt = new Date(now.getTime() - 30 * 60 * 1000).toISOString(); + const staleAt = new Date(now.getTime() - 8 * 60 * 60 * 1000).toISOString(); + const generatedAt = now.toISOString(); + const snapshot = { + sessions: [ + { + sessionKey: "s-error-stale", + state: "error", + agentId: "agent-1", + label: "Stale Error Session", + lastMessageAt: staleAt, + }, + { + sessionKey: "s-blocked-fresh", + state: "blocked", + agentId: "agent-2", + label: "Fresh Blocked Session", + lastMessageAt: freshAt, + }, + { + sessionKey: "s-error-fresh", + state: "error", + agentId: "agent-3", + label: "Fresh Error Session", + lastMessageAt: freshAt, + }, + ], + statuses: [], + cronJobs: [], + approvals: [], + projects: { + updatedAt: generatedAt, + projects: [], + }, + projectSummaries: [], + tasks: { + updatedAt: generatedAt, + agentBudgets: [], + tasks: [], + }, + tasksSummary: { + projects: 0, + tasks: 0, + todo: 0, + inProgress: 0, + blocked: 0, + done: 0, + owners: 0, + artifacts: 0, + }, + budgetSummary: { + total: 0, + ok: 0, + warn: 0, + over: 0, + evaluations: [], + }, + generatedAt, + } as const; + + const exceptions = commanderExceptions(snapshot); + const feed = commanderExceptionsFeed(snapshot); + + assert.equal(exceptions.errors.length, 1); + assert.equal(exceptions.errors[0]?.sessionKey, "s-error-fresh"); + assert.equal(exceptions.blocked.length, 1); + assert.equal(exceptions.blocked[0]?.sessionKey, "s-blocked-fresh"); + assert(feed.items.every((item) => item.sourceId !== "s-error-stale")); +}); diff --git a/test/doc-hub.test.ts b/test/doc-hub.test.ts new file mode 100644 index 0000000..4a55aae --- /dev/null +++ b/test/doc-hub.test.ts @@ -0,0 +1,107 @@ +import assert from "node:assert/strict"; +import { mkdtemp, readFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import test from "node:test"; +import type { ToolClient } from "../src/clients/tool-client"; +import { buildStructuredDocHubFromSessions } from "../src/runtime/doc-hub"; +import type { ReadModelSnapshot } from "../src/types"; + +function createEmptySnapshot(): ReadModelSnapshot { + const now = "2026-03-05T18:00:00.000Z"; + return { + sessions: [], + statuses: [], + cronJobs: [], + approvals: [], + projects: { projects: [], updatedAt: now }, + projectSummaries: [], + tasks: { tasks: [], agentBudgets: [], updatedAt: now }, + tasksSummary: { + projects: 0, + tasks: 0, + todo: 0, + inProgress: 0, + blocked: 0, + done: 0, + owners: 0, + artifacts: 0, + }, + budgetSummary: { total: 0, ok: 0, warn: 0, over: 0, evaluations: [] }, + generatedAt: now, + }; +} + +test("doc hub ingests structured chat outputs into runtime index", async () => { + const workspace = await mkdtemp(join(tmpdir(), "doc-hub-test-")); + const indexPath = join(workspace, "doc-hub-chat.json"); + const snapshot = createEmptySnapshot(); + snapshot.sessions = [ + { + sessionKey: "sess-alpha", + label: "Alpha", + agentId: "main", + state: "running", + lastMessageAt: "2026-03-05T18:01:00.000Z", + }, + ]; + + let historyCalls = 0; + const client: ToolClient = { + async sessionsList() { + return { sessions: [] }; + }, + async sessionStatus() { + return { rawText: "" }; + }, + async sessionsHistory() { + historyCalls += 1; + return { + json: { + history: [ + { + role: "assistant", + timestamp: "2026-03-05T18:01:00.000Z", + content: + "# 今日执行计划\n\n1. 核对 cron 任务与负责人\n2. 更新预算看板\n3. 输出复盘摘要\n\n- 风险:订阅窗口超限\n- 对策:先处理高价值任务\n\n## 下一步\n- 先修复心跳接入,再补文档入库。", + }, + ], + }, + rawText: "", + }; + }, + async cronList() { + return { jobs: [] }; + }, + async approvalsGet() { + return { rawText: "" }; + }, + async approvalsApprove() { + return { ok: false, action: "approve", approvalId: "na", rawText: "" }; + }, + async approvalsReject() { + return { ok: false, action: "reject", approvalId: "na", rawText: "" }; + }, + }; + + const result = await buildStructuredDocHubFromSessions({ + snapshot, + client, + indexPath, + refreshFromSessions: true, + maxSessions: 8, + historyLimit: 40, + maxDocsPerSession: 2, + maxStoredDocs: 20, + }); + + assert(historyCalls >= 0); + assert.equal(result.items.length, 1); + assert.equal(result.items[0].sourceSessionKey, "sess-alpha"); + assert.match(result.items[0].title, /今日执行计划/); + assert.match(result.items[0].category, /(计划路线|会话文档|总结复盘)/); + + const persistedRaw = await readFile(indexPath, "utf8"); + assert(persistedRaw.includes("sess-alpha")); + assert(persistedRaw.includes("今日执行计划")); +}); diff --git a/test/export-staff-avatars.test.ts b/test/export-staff-avatars.test.ts new file mode 100644 index 0000000..d1326f3 --- /dev/null +++ b/test/export-staff-avatars.test.ts @@ -0,0 +1,76 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import path from "node:path"; + +import { + STAFF_AVATARS, + centerSprite, + extractSpriteRuntime, + getSpriteBounds, + renderSpritePng, + renderSpriteSvg, +} from "../scripts/export-staff-avatars"; + +test("embedded avatar runtime can be extracted from ui server", async () => { + const serverPath = path.join(process.cwd(), "src/ui/server.ts"); + const source = await import("node:fs/promises").then((fs) => fs.readFile(serverPath, "utf8")); + const runtime = extractSpriteRuntime(source); + + assert.equal(runtime.spriteSize, 44); + assert.equal(typeof runtime.spriteFactory.monkey, "function"); + assert.equal(typeof runtime.spriteFactory.otter, "function"); + assert.equal(runtime.spriteVisualSpanCompensation.lion, 0.92); + assert.equal(runtime.spriteVisualSpanCompensation.otter, 0.9); +}); + +test("staff avatar exporter covers every configured staff member", async () => { + const serverPath = path.join(process.cwd(), "src/ui/server.ts"); + const source = await import("node:fs/promises").then((fs) => fs.readFile(serverPath, "utf8")); + const runtime = extractSpriteRuntime(source); + + for (const item of STAFF_AVATARS) { + const sprite = runtime.spriteFactory[item.animal](); + assert.equal(sprite.length, runtime.spriteSize); + assert.ok(sprite.some((row) => row.some(Boolean)), `${item.agentId} sprite should not be empty`); + } +}); + +test("sprite svg export keeps crisp pixel rects", () => { + const svg = renderSpriteSvg([ + ["#000000", ""], + ["", "#ffffff"], + ]); + + assert.match(svg, /shape-rendering="crispEdges"/); + assert.match(svg, / { + const centered = centerSprite([ + ["", "", ""], + ["", "#111111", ""], + ["", "", "#222222"], + ], 1); + const bounds = getSpriteBounds(centered); + + assert.equal(centered.length, centered[0]?.length); + assert.deepEqual(bounds, { + minX: 1, + minY: 1, + maxX: 2, + maxY: 2, + width: 2, + height: 2, + span: 2, + }); +}); + +test("sprite png export writes a valid PNG signature", () => { + const png = renderSpritePng([ + ["#000000", ""], + ["", "#ffffff"], + ], 4); + + assert.equal(png.subarray(0, 8).toString("hex"), "89504e470d0a1a0a"); +}); diff --git a/test/office-roster.test.ts b/test/office-roster.test.ts new file mode 100644 index 0000000..e62e87f --- /dev/null +++ b/test/office-roster.test.ts @@ -0,0 +1,593 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import type { ToolClient } from "../src/clients/tool-client"; +import type { ReadModelSnapshot } from "../src/types"; + +test("office roster fallback keeps full known agent list even without live sessions", async () => { + const { buildOfficeAgentRosterIds, buildOfficeSpaceCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + + const knownAgents = ["pandas", "otter", "tiger"]; + const rosterIds = buildOfficeAgentRosterIds(snapshot, [], knownAgents); + assert.equal(rosterIds.length, 3); + assert(rosterIds.includes("pandas")); + assert(rosterIds.includes("otter")); + assert(rosterIds.includes("tiger")); + + const cards = buildOfficeSpaceCards(snapshot, [], knownAgents); + assert.equal(cards.length, 3); + const otter = cards.find((item) => item.agentId === "otter"); + assert(otter, "Expected known roster agent to render a card."); + assert.equal(otter.status, "inactive"); + assert.equal(otter.officeZone, "Standby Pods"); +}); + +test("office cards use runtime active-session map when snapshot sessions are empty", async () => { + const { buildOfficeSpaceCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + + const cards = buildOfficeSpaceCards(snapshot, [], ["codex"], new Map([["codex", 2]])); + const codex = cards.find((item) => item.agentId === "codex"); + assert(codex, "Expected runtime-mapped agent card."); + assert.equal(codex.activeSessions, 2); + assert.equal(codex.status, "running"); + assert.equal(codex.officeZone, "Builder Desks"); +}); + +test("office cards ignore unknown runtime agents when a current roster is present", async () => { + const { buildOfficeSpaceCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + snapshot.sessions = [ + { + sessionKey: "agent:codex:legacy", + agentId: "codex", + state: "running", + lastMessageAt: "2026-03-10T10:00:00.000Z", + }, + ]; + + const cards = buildOfficeSpaceCards(snapshot, [], ["main"], new Map([["codex", 2], ["main", 1]])); + assert.equal(cards.length, 1); + assert.equal(cards[0]?.agentId, "main"); + assert.equal(cards[0]?.activeSessions, 1); +}); + +test("office cards do not mark agents as running from idle historical sessions alone", async () => { + const { buildOfficeSpaceCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + snapshot.sessions = [ + { + sessionKey: "agent:main:main", + agentId: "main", + state: "idle", + lastMessageAt: "2026-03-09T16:27:26.457Z", + }, + { + sessionKey: "agent:main:cron:job-1:run:child-1", + agentId: "main", + state: "idle", + lastMessageAt: "2026-03-09T15:15:00.020Z", + }, + ]; + + const cards = buildOfficeSpaceCards(snapshot, [], ["main"]); + const main = cards.find((item) => item.agentId === "main"); + assert(main, "Expected main card."); + assert.equal(main.activeSessions, 0); + assert.equal(main.status, "idle"); + assert.equal(main.officeZone, "Standby Pods"); +}); + +test("office cards keep agents idle when they only have unfinished tasks but no live sessions", async () => { + const { buildOfficeSpaceCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + const tasks = [ + { + projectId: "p-1", + projectTitle: "Project One", + taskId: "task-1", + title: "Prepare next report", + status: "todo", + owner: "main", + sessionKeys: [], + updatedAt: "2026-03-10T10:00:00.000Z", + }, + ]; + + const cards = buildOfficeSpaceCards(snapshot, tasks, ["main"]); + const main = cards.find((item) => item.agentId === "main"); + assert(main, "Expected main card."); + assert.equal(main.activeSessions, 0); + assert.equal(main.status, "idle"); + assert.equal(main.officeZone, "Standby Pods"); + assert.deepEqual(main.focusItems, ["Prepare next report"]); +}); + +test("execution summaries infer cron ownership from agent cron session keys when jobs omit ownerAgentId", async () => { + const { buildExecutionAgentSummaries } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + snapshot.sessions = [ + { + sessionKey: "agent:main:cron:job-1", + agentId: "main", + state: "idle", + lastMessageAt: "2026-03-09T16:27:26.457Z", + }, + { + sessionKey: "agent:main:cron:job-1:run:child-1", + agentId: "main", + state: "idle", + lastMessageAt: "2026-03-09T16:28:00.000Z", + }, + ]; + + const rows = buildExecutionAgentSummaries( + snapshot, + [], + [ + { + jobId: "job-1", + name: "Demo cron", + enabled: true, + owner: "Scheduler", + purpose: "Run demo cron.", + scheduleLabel: "cron * * * * *", + sourcePath: "/tmp/jobs.json", + }, + ], + [], + new Map(), + ); + const main = rows.find((item) => item.agentId === "main"); + assert(main, "Expected main execution summary."); + assert.equal(main.enabledCronJobs, 1); + assert.deepEqual(main.cronJobNames, ["Demo cron"]); +}); + +test("execution summaries ignore agents outside the current roster", async () => { + const { buildExecutionAgentSummaries } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + snapshot.sessions = [ + { + sessionKey: "agent:codex:legacy", + agentId: "codex", + state: "running", + lastMessageAt: "2026-03-09T16:27:26.457Z", + }, + ]; + + const rows = buildExecutionAgentSummaries( + snapshot, + [], + [], + [{ agentId: "main", displayName: "main" }], + new Map([["codex", 999], ["main", 10]]), + ); + + assert.equal(rows.length, 1); + assert.equal(rows[0]?.agentId, "main"); +}); + +test("staff overview recent output is per-agent and excludes user/thinking noise", async () => { + const { buildStaffOverviewCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + snapshot.sessions = [ + { + sessionKey: "agent:main:main", + agentId: "main", + state: "idle", + lastMessageAt: "2026-03-09T16:30:00.000Z", + }, + { + sessionKey: "agent:main:cron:job-1", + agentId: "main", + state: "idle", + lastMessageAt: "2026-03-09T16:00:00.000Z", + }, + { + sessionKey: "agent:otter:main", + agentId: "otter", + state: "idle", + lastMessageAt: "2026-03-09T15:00:00.000Z", + }, + ]; + + const client: ToolClient = { + async sessionsList() { return { sessions: [] }; }, + async sessionStatus() { return { rawText: "" }; }, + async sessionsHistory(request) { + if (request.sessionKey === "agent:main:main") { + return { + json: { + history: [ + { role: "user", content: "继续推进当前目标:在达到 Alex Finn 流程最终验收前不要停。" }, + { role: "assistant", content: "[Mon 2026-03-09 09:01 GMT+1] OpenClaw runtime context (internal): This context is run-only." }, + { role: "assistant", content: "thinking **Summarizing discussion points**" }, + ], + }, + rawText: "", + }; + } + if (request.sessionKey === "agent:main:cron:job-1") { + return { + json: { + history: [ + { role: "assistant", content: "{\"ok\":true,\"sent\":5}" }, + ], + }, + rawText: "", + }; + } + if (request.sessionKey === "agent:otter:main") { + return { + json: { + history: [ + { role: "assistant", content: "Conversation info (untrusted metadata): ```json {\"message_id\":\"1022\"}```" }, + { role: "assistant", content: "已记录并设置提醒。" }, + ], + }, + rawText: "", + }; + } + return { rawText: "" }; + }, + async cronList() { return { jobs: [] }; }, + async approvalsGet() { return { rawText: "" }; }, + async approvalsApprove() { return { ok: false, action: "approve", approvalId: "x", rawText: "" }; }, + async approvalsReject() { return { ok: false, action: "reject", approvalId: "x", reason: "no", rawText: "" }; }, + }; + + const cards = await buildStaffOverviewCards({ + snapshot, + client, + members: [ + { agentId: "main", displayName: "main", model: "gpt", workspace: "main", toolsProfile: "full" }, + { agentId: "otter", displayName: "otter", model: "gpt", workspace: "otter", toolsProfile: "minimal" }, + ], + officeCards: [ + { + agentId: "main", + identity: { animal: "lion", title: "Commander", accent: "#ff9966", sprite: "lion" }, + status: "idle", + statusLabel: "待命", + officeZone: "Standby Pods", + activeSessions: 0, + activeTasks: 0, + focusItems: [], + summary: "待命中。", + }, + { + agentId: "otter", + identity: { animal: "otter", title: "Assistant", accent: "#88d5f6", sprite: "otter" }, + status: "idle", + statusLabel: "待命", + officeZone: "Standby Pods", + activeSessions: 0, + activeTasks: 0, + focusItems: [], + summary: "待命中。", + }, + ], + executionAgentSummaries: [ + { agentId: "main", displayName: "main", activeSessions: 0, activeTasks: 0, enabledCronJobs: 1, cronJobNames: ["Demo cron"], recentTokens30d: 0 }, + { agentId: "otter", displayName: "otter", activeSessions: 0, activeTasks: 0, enabledCronJobs: 0, cronJobNames: [], recentTokens30d: 0 }, + ], + language: "zh", + }); + + const main = cards.find((item) => item.agentId === "main"); + const otter = cards.find((item) => item.agentId === "otter"); + assert(main); + assert(otter); + assert.equal(main.recentOutput, "最近完成一次任务,并返回结构化结果。"); + assert.equal(main.currentWorkLabel, "下一项"); + assert.equal(main.currentWork, "Demo cron"); + assert.equal(main.scheduledLabel, "已排班"); + assert.equal(otter.currentWorkLabel, "正在处理什么"); + assert.equal(otter.recentOutput, "已记录并设置提醒。"); +}); + +test("staff overview uses next-up wording when tasks exist but no live session is active", async () => { + const { buildStaffOverviewCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + const client: ToolClient = { + async sessionsList() { return { sessions: [] }; }, + async sessionStatus() { return { rawText: "" }; }, + async sessionsHistory() { return { rawText: "" }; }, + async cronList() { return { jobs: [] }; }, + async approvalsGet() { return { rawText: "" }; }, + async approvalsApprove() { return { ok: false, action: "approve", approvalId: "x", rawText: "" }; }, + async approvalsReject() { return { ok: false, action: "reject", approvalId: "x", reason: "no", rawText: "" }; }, + }; + + const cards = await buildStaffOverviewCards({ + snapshot, + client, + members: [ + { agentId: "main", displayName: "main", model: "gpt", workspace: "main", toolsProfile: "full" }, + ], + officeCards: [ + { + agentId: "main", + identity: { animal: "lion", title: "Commander", accent: "#ff9966", sprite: "lion" }, + status: "idle", + statusLabel: "待命", + officeZone: "Standby Pods", + activeSessions: 0, + activeTasks: 1, + focusItems: ["Prepare next report"], + summary: "当前跟进:Prepare next report", + }, + ], + executionAgentSummaries: [ + { agentId: "main", displayName: "main", activeSessions: 0, activeTasks: 1, enabledCronJobs: 0, cronJobNames: [], recentTokens30d: 0 }, + ], + language: "zh", + }); + + const main = cards.find((item) => item.agentId === "main"); + assert(main); + assert.equal(main.statusLabel, "待命"); + assert.equal(main.currentWorkLabel, "下一项"); + assert.equal(main.currentWork, "Prepare next report"); +}); + +test("staff overview does not show standby copy while status is running", async () => { + const { buildStaffOverviewCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + const client: ToolClient = { + async sessionsList() { return { sessions: [] }; }, + async sessionStatus() { return { rawText: "" }; }, + async sessionsHistory() { return { rawText: "" }; }, + async cronList() { return { jobs: [] }; }, + async approvalsGet() { return { rawText: "" }; }, + async approvalsApprove() { return { ok: false, action: "approve", approvalId: "x", rawText: "" }; }, + async approvalsReject() { return { ok: false, action: "reject", approvalId: "x", reason: "no", rawText: "" }; }, + }; + + const cards = await buildStaffOverviewCards({ + snapshot, + client, + members: [ + { agentId: "main", displayName: "main", model: "gpt", workspace: "main", toolsProfile: "full" }, + ], + officeCards: [ + { + agentId: "main", + identity: { animal: "lion", title: "Commander", accent: "#ff9966", sprite: "lion" }, + status: "running", + statusLabel: "执行中", + officeZone: "Builder Desks", + activeSessions: 1, + activeTasks: 0, + focusItems: [], + summary: "会话已开启,等待下一步指令。", + }, + ], + executionAgentSummaries: [ + { agentId: "main", displayName: "main", activeSessions: 1, activeTasks: 0, enabledCronJobs: 2, cronJobNames: ["Job A", "Job B"], recentTokens30d: 0 }, + ], + language: "zh", + }); + + const main = cards.find((item) => item.agentId === "main"); + assert(main); + assert.equal(main.statusLabel, "工作中"); + assert.equal(main.currentWorkLabel, "正在处理什么"); + assert.equal(main.currentWork, "Job A"); + assert.notEqual(main.currentWork, "正在执行排班任务"); + assert.notEqual(main.currentWork, "按排班待命"); +}); + +test("staff overview downgrades residual running sessions after explicit stop signal", async () => { + const { buildStaffOverviewCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + snapshot.sessions = [ + { + sessionKey: "agent:coq:main", + agentId: "coq", + state: "running", + lastMessageAt: "2026-03-09T22:31:49.227Z", + }, + ]; + + const client: ToolClient = { + async sessionsList() { return { sessions: [] }; }, + async sessionStatus() { return { rawText: "" }; }, + async sessionsHistory() { + return { + json: { + history: [ + { role: "user", content: "[Mon 2026-03-09 23:30 GMT+1] 立即停止你当前的所有活动,不要继续任何 review、演示、brief、整理、输出、工具调用或后续收尾扩展。从现在起进入待命状态,不再处理任何当前任务。回复必须是:REPLY_SKIP;announce:ANNOUNCE_SKIP" }, + { role: "assistant", content: "[[reply_to_current]]REPLY_SKIP" }, + { role: "assistant", content: "[Mon 2026-03-09 23:31 GMT+1] Agent-to-agent announce step." }, + { role: "assistant", content: "thinking **Implementing exact skip announcement**" }, + ], + }, + rawText: "", + }; + }, + async cronList() { return { jobs: [] }; }, + async approvalsGet() { return { rawText: "" }; }, + async approvalsApprove() { return { ok: false, action: "approve", approvalId: "x", rawText: "" }; }, + async approvalsReject() { return { ok: false, action: "reject", approvalId: "x", reason: "no", rawText: "" }; }, + }; + + const cards = await buildStaffOverviewCards({ + snapshot, + client, + members: [ + { agentId: "coq", displayName: "Coq-每日新闻", model: "gpt", workspace: "coq", toolsProfile: "minimal" }, + ], + officeCards: [ + { + agentId: "coq", + identity: { animal: "rooster", title: "Reporter", accent: "#ffcc66", sprite: "rooster" }, + status: "running", + statusLabel: "执行中", + officeZone: "Builder Desks", + activeSessions: 1, + activeTasks: 0, + focusItems: [], + summary: "当前有会话在运行。", + }, + ], + executionAgentSummaries: [ + { agentId: "coq", displayName: "Coq-每日新闻", activeSessions: 1, activeTasks: 0, enabledCronJobs: 1, cronJobNames: ["Coq-每日新闻 | Trend Report 09:00"], recentTokens30d: 0 }, + ], + language: "zh", + }); + + const coq = cards.find((item) => item.agentId === "coq"); + assert(coq); + assert.equal(coq.statusLabel, "待命"); + assert.equal(coq.currentWorkLabel, "下一项"); + assert.equal(coq.currentWork, "Coq-每日新闻 | Trend Report 09:00"); + assert.equal(coq.recentOutput, "最近已停止当前任务并回到待命。"); +}); + +test("staff overview downgrades residual running sessions from nested OpenClaw history payloads", async () => { + const { buildStaffOverviewCards } = await import("../src/ui/server"); + const snapshot = buildSnapshotFixture(); + snapshot.sessions = [ + { + sessionKey: "agent:pandas:main", + agentId: "pandas", + state: "running", + lastMessageAt: "2026-03-09T22:56:03.814Z", + }, + ]; + + const client: ToolClient = { + async sessionsList() { return { sessions: [] }; }, + async sessionStatus() { return { rawText: "" }; }, + async sessionsHistory() { + return { + json: { + history: [ + { + type: "message", + timestamp: "2026-03-09T22:55:43.287Z", + message: { + role: "user", + content: [ + { + type: "text", + text: "[Mon 2026-03-09 23:55 GMT+1] 立即停止你当前的所有活动,不要继续任何 review、演示、brief、整理、输出、工具调用或后续收尾扩展。从现在起进入待命状态,不再处理任何当前任务。回复必须是:REPLY_SKIP。announce 必须是:ANNOUNCE_SKIP。", + }, + ], + }, + }, + { + type: "message", + timestamp: "2026-03-09T22:55:46.209Z", + message: { + role: "assistant", + content: [ + { type: "thinking", thinking: "**Deciding reply tag usage**" }, + { type: "text", text: "REPLY_SKIP" }, + ], + }, + }, + { + type: "message", + timestamp: "2026-03-09T22:56:01.532Z", + message: { + role: "user", + content: [ + { type: "text", text: "[Mon 2026-03-09 23:56 GMT+1] Agent-to-agent announce step." }, + ], + }, + }, + { + type: "message", + timestamp: "2026-03-09T22:56:03.814Z", + message: { + role: "assistant", + content: [ + { type: "thinking", thinking: "" }, + { type: "text", text: "ANNOUNCE_SKIP" }, + ], + }, + }, + ], + }, + rawText: "", + }; + }, + async cronList() { return { jobs: [] }; }, + async approvalsGet() { return { rawText: "" }; }, + async approvalsApprove() { return { ok: false, action: "approve", approvalId: "x", rawText: "" }; }, + async approvalsReject() { return { ok: false, action: "reject", approvalId: "x", reason: "no", rawText: "" }; }, + }; + + const cards = await buildStaffOverviewCards({ + snapshot, + client, + members: [ + { agentId: "pandas", displayName: "pandas", model: "gpt", workspace: "pandas", toolsProfile: "full" }, + ], + officeCards: [ + { + agentId: "pandas", + identity: { animal: "panda", title: "Planner", accent: "#86e2ef", sprite: "panda" }, + status: "running", + statusLabel: "执行中", + officeZone: "Builder Desks", + activeSessions: 1, + activeTasks: 0, + focusItems: [], + summary: "当前有会话在运行。", + }, + ], + executionAgentSummaries: [ + { agentId: "pandas", displayName: "pandas", activeSessions: 1, activeTasks: 0, enabledCronJobs: 0, cronJobNames: [], recentTokens30d: 0 }, + ], + language: "zh", + }); + + const pandas = cards.find((item) => item.agentId === "pandas"); + assert(pandas); + assert.equal(pandas.statusLabel, "待命"); + assert.equal(pandas.currentWorkLabel, "正在处理什么"); + assert.equal(pandas.currentWork, "当前无实时任务"); + assert.equal(pandas.recentOutput, "最近已停止当前任务并回到待命。"); +}); + +function buildSnapshotFixture(): ReadModelSnapshot { + const now = new Date().toISOString(); + return { + sessions: [], + statuses: [], + cronJobs: [], + approvals: [], + projects: { + updatedAt: now, + projects: [], + }, + projectSummaries: [], + tasks: { + updatedAt: now, + agentBudgets: [], + tasks: [], + }, + tasksSummary: { + projects: 0, + tasks: 0, + todo: 0, + inProgress: 0, + blocked: 0, + done: 0, + owners: 0, + artifacts: 0, + }, + budgetSummary: { + total: 0, + ok: 0, + warn: 0, + over: 0, + evaluations: [], + }, + generatedAt: now, + }; +} diff --git a/test/office-session-presence.test.ts b/test/office-session-presence.test.ts new file mode 100644 index 0000000..306c889 --- /dev/null +++ b/test/office-session-presence.test.ts @@ -0,0 +1,221 @@ +import assert from "node:assert/strict"; +import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import test from "node:test"; + +test("office session presence parses nested session stores and second-based timestamps", async () => { + const home = await mkdtemp(join(tmpdir(), "control-center-office-presence-")); + const originalHome = process.env.OPENCLAW_HOME; + + try { + const sessionsDir = join(home, "agents", "pandas", "sessions"); + await mkdir(sessionsDir, { recursive: true }); + const nowSeconds = Math.floor(Date.now() / 1000); + await writeFile( + join(sessionsDir, "sessions.json"), + JSON.stringify( + { + sessions: { + "agent:pandas:1": { + sessionId: "session-1", + updatedAt: nowSeconds, + state: "running", + }, + "agent:pandas:2": { + sessionId: "session-2", + updatedAt: String(nowSeconds - 10), + active: true, + }, + "agent:pandas:3": { + sessionId: "session-3", + updatedAt: nowSeconds, + state: "idle", + }, + }, + meta: { + generatedAt: nowSeconds, + }, + }, + null, + 2, + ), + "utf8", + ); + + process.env.OPENCLAW_HOME = home; + const { loadBestEffortOfficeSessionPresence } = await import("../src/runtime/office-session-presence"); + const snapshot = await loadBestEffortOfficeSessionPresence(); + + assert.equal(snapshot.status, "connected"); + assert.equal(snapshot.totalActiveSessions, 2); + assert.equal(snapshot.activeSessionsByAgent.get("pandas"), 2); + } finally { + if (originalHome === undefined) delete process.env.OPENCLAW_HOME; + else process.env.OPENCLAW_HOME = originalHome; + await rm(home, { recursive: true, force: true }); + } +}); + +test("office session presence parses array-shaped stores with acp state", async () => { + const home = await mkdtemp(join(tmpdir(), "control-center-office-presence-array-")); + const originalHome = process.env.OPENCLAW_HOME; + + try { + const sessionsDir = join(home, "agents", "otter", "sessions"); + await mkdir(sessionsDir, { recursive: true }); + const nowIso = new Date().toISOString(); + await writeFile( + join(sessionsDir, "sessions.json"), + JSON.stringify( + [ + { + sessionId: "session-a", + updatedAt: nowIso, + acp: { + state: "processing", + }, + }, + { + sessionId: "session-b", + updatedAt: nowIso, + acp: { + state: "completed", + }, + }, + ], + null, + 2, + ), + "utf8", + ); + + process.env.OPENCLAW_HOME = home; + const { loadBestEffortOfficeSessionPresence } = await import("../src/runtime/office-session-presence"); + const snapshot = await loadBestEffortOfficeSessionPresence(); + + assert.equal(snapshot.status, "connected"); + assert.equal(snapshot.totalActiveSessions, 1); + assert.equal(snapshot.activeSessionsByAgent.get("otter"), 1); + } finally { + if (originalHome === undefined) delete process.env.OPENCLAW_HOME; + else process.env.OPENCLAW_HOME = originalHome; + await rm(home, { recursive: true, force: true }); + } +}); + +test("office session presence auto-expands recency window when initial pass is all-zero", async () => { + const home = await mkdtemp(join(tmpdir(), "control-center-office-presence-fallback-")); + const originalHome = process.env.OPENCLAW_HOME; + + try { + const sessionsDir = join(home, "agents", "main", "sessions"); + await mkdir(sessionsDir, { recursive: true }); + const updatedAtIso = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(); + await writeFile( + join(sessionsDir, "sessions.json"), + JSON.stringify( + { + sessions: { + "agent:main:1": { + sessionId: "session-1", + updatedAt: updatedAtIso, + }, + }, + }, + null, + 2, + ), + "utf8", + ); + + process.env.OPENCLAW_HOME = home; + const { loadBestEffortOfficeSessionPresence } = await import("../src/runtime/office-session-presence"); + const snapshot = await loadBestEffortOfficeSessionPresence(); + + assert.equal(snapshot.status, "connected"); + assert.equal(snapshot.totalActiveSessions, 1); + assert.equal(snapshot.activeSessionsByAgent.get("main"), 1); + assert(snapshot.detail.includes("Window auto-expanded"), "Expected adaptive fallback detail in snapshot."); + } finally { + if (originalHome === undefined) delete process.env.OPENCLAW_HOME; + else process.env.OPENCLAW_HOME = originalHome; + await rm(home, { recursive: true, force: true }); + } +}); + +test("office session presence filters to current configured agents when openclaw.json is present", async () => { + const home = await mkdtemp(join(tmpdir(), "control-center-office-presence-roster-")); + const originalHome = process.env.OPENCLAW_HOME; + + try { + const pandasDir = join(home, "agents", "pandas", "sessions"); + const legacyDir = join(home, "agents", "codex", "sessions"); + await mkdir(pandasDir, { recursive: true }); + await mkdir(legacyDir, { recursive: true }); + const nowIso = new Date().toISOString(); + await writeFile( + join(home, "openclaw.json"), + JSON.stringify( + { + agents: { + list: [ + { id: "main", name: "main" }, + { id: "pandas", name: "pandas" }, + ], + }, + }, + null, + 2, + ), + "utf8", + ); + await writeFile( + join(pandasDir, "sessions.json"), + JSON.stringify( + { + sessions: { + "agent:pandas:1": { + sessionId: "session-1", + updatedAt: nowIso, + state: "running", + }, + }, + }, + null, + 2, + ), + "utf8", + ); + await writeFile( + join(legacyDir, "sessions.json"), + JSON.stringify( + { + sessions: { + "agent:codex:1": { + sessionId: "session-2", + updatedAt: nowIso, + state: "running", + }, + }, + }, + null, + 2, + ), + "utf8", + ); + + process.env.OPENCLAW_HOME = home; + const { loadBestEffortOfficeSessionPresence } = await import("../src/runtime/office-session-presence"); + const snapshot = await loadBestEffortOfficeSessionPresence(); + + assert.equal(snapshot.status, "connected"); + assert.equal(snapshot.totalActiveSessions, 1); + assert.equal(snapshot.activeSessionsByAgent.get("pandas"), 1); + assert.equal(snapshot.activeSessionsByAgent.has("codex"), false); + } finally { + if (originalHome === undefined) delete process.env.OPENCLAW_HOME; + else process.env.OPENCLAW_HOME = originalHome; + await rm(home, { recursive: true, force: true }); + } +}); diff --git a/test/openclaw-mappers.test.ts b/test/openclaw-mappers.test.ts new file mode 100644 index 0000000..85f601f --- /dev/null +++ b/test/openclaw-mappers.test.ts @@ -0,0 +1,24 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { mapSessionsListToSummaries } from "../src/mappers/openclaw-mappers"; + +test("session list mapping keeps explicit runtime issue states instead of flattening them to active/idle", () => { + const mapped = mapSessionsListToSummaries({ + sessions: [ + { sessionKey: "sess-blocked", active: true, state: "blocked" }, + { sessionKey: "sess-error", active: false, state: "failed" }, + { sessionKey: "sess-wait", active: true, state: "waiting_approval" }, + { sessionKey: "sess-running", active: true, state: "busy" }, + { sessionKey: "sess-idle", active: true, state: "done" }, + { sessionKey: "sess-fallback", active: true }, + ], + }); + + const byKey = new Map(mapped.map((item) => [item.sessionKey, item.state])); + assert.equal(byKey.get("sess-blocked"), "blocked"); + assert.equal(byKey.get("sess-error"), "error"); + assert.equal(byKey.get("sess-wait"), "waiting_approval"); + assert.equal(byKey.get("sess-running"), "running"); + assert.equal(byKey.get("sess-idle"), "idle"); + assert.equal(byKey.get("sess-fallback"), "running"); +}); diff --git a/test/oss-readiness.test.ts b/test/oss-readiness.test.ts new file mode 100644 index 0000000..fa4051a --- /dev/null +++ b/test/oss-readiness.test.ts @@ -0,0 +1,68 @@ +import assert from "node:assert/strict"; +import { execFileSync } from "node:child_process"; +import { existsSync, readFileSync } from "node:fs"; +import path from "node:path"; +import test from "node:test"; + +const ROOT = process.cwd(); +const MACOS_HOME_PATH_PATTERN = /\/Users\/[^/\s]+\//; +const EMBEDDED_LOCAL_TOKEN_PATTERN = /LOCAL_API_TOKEN\s*[:=]\s*["'][^"']{8,}["']/; +const PUBLIC_FILES = [ + "README.md", + "docs/ARCHITECTURE.md", + "docs/PROGRESS.md", + "docs/mission.runbook.md", + "ecosystem.config.cjs", + "mission.config.json", + "scripts/run_verifier.sh", + "scripts/mc_dod_evaluator.py", + "scripts/mc_rollback_plan.py", + "workflows/pandas_v3_autopilot.lobster", +]; + +test("repo includes baseline open-source release metadata", () => { + assert(existsSync(path.join(ROOT, ".gitignore")), "Expected .gitignore to exist."); + assert(existsSync(path.join(ROOT, "LICENSE")), "Expected LICENSE to exist."); + + const ignore = readFileSync(path.join(ROOT, ".gitignore"), "utf8"); + assert.match(ignore, /(^|\n)node_modules\/(\n|$)/); + assert.match(ignore, /(^|\n)dist\/(\n|$)/); + assert.match(ignore, /(^|\n)runtime\/(\n|$)/); + + const license = readFileSync(path.join(ROOT, "LICENSE"), "utf8"); + assert.match(license, /MIT License/); + + const pkg = JSON.parse(readFileSync(path.join(ROOT, "package.json"), "utf8")); + assert.notEqual(pkg.private, true); + assert.equal(pkg.license, "MIT"); +}); + +test("public-facing files do not embed machine-specific paths or local token values", () => { + for (const relativePath of PUBLIC_FILES) { + const content = readFileSync(path.join(ROOT, relativePath), "utf8"); + assert.equal(MACOS_HOME_PATH_PATTERN.test(content), false, `${relativePath} still contains a macOS home path.`); + assert.equal( + EMBEDDED_LOCAL_TOKEN_PATTERN.test(content), + false, + `${relativePath} still contains an embedded LOCAL_API_TOKEN value.`, + ); + } +}); + +test("gateway URL can be overridden from env for non-local installations", () => { + const output = execFileSync( + process.execPath, + [ + "--import", + "tsx", + "--eval", + "process.env.GATEWAY_URL='ws://example.invalid:9999'; const mod = require('./src/config.ts'); process.stdout.write(String(mod.GATEWAY_URL));", + ], + { + cwd: ROOT, + encoding: "utf8", + }, + ).trim(); + + assert.equal(output, "ws://example.invalid:9999"); +}); diff --git a/test/p1-control-scripts.test.ts b/test/p1-control-scripts.test.ts new file mode 100644 index 0000000..90c7fa5 --- /dev/null +++ b/test/p1-control-scripts.test.ts @@ -0,0 +1,240 @@ +import assert from "node:assert/strict"; +import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises"; +import { join, resolve } from "node:path"; +import { spawn } from "node:child_process"; +import test from "node:test"; + +const PROJECT_ROOT = process.cwd(); + +test("periodic snapshot writes timestamped health/evidence artifacts and latest pointers", async () => { + const runtimeDir = join(PROJECT_ROOT, "runtime", `zzzz-p1-periodic-${Date.now()}`); + const evidenceDir = join(runtimeDir, "evidence"); + await mkdir(evidenceDir, { recursive: true }); + await writeFile( + join(evidenceDir, "latest.json"), + `${JSON.stringify( + { + generatedAt: new Date().toISOString(), + itemId: "P1-2", + completed: "Periodic snapshot baseline", + filesChanged: ["scripts/periodic-snapshot.ts"], + verification: "test", + visibleMarker: "runtime/evidence/latest.json", + }, + null, + 2, + )}\n`, + "utf8", + ); + + try { + const run = await runNodeScript(["scripts/periodic-snapshot.ts", runtimeDir], process.env); + assert.equal(run.code, 0, `periodic snapshot failed\nstdout:\n${run.stdout}\nstderr:\n${run.stderr}`); + + const healthPointer = JSON.parse(await readFile(join(runtimeDir, "health", "latest.pointer.json"), "utf8")) as { + latest: string; + }; + const evidencePointer = JSON.parse( + await readFile(join(runtimeDir, "evidence", "latest.pointer.json"), "utf8"), + ) as { + latest: string; + }; + + await stat(join(runtimeDir, "health", "latest.json")); + await stat(healthPointer.latest); + await stat(evidencePointer.latest); + } finally { + await rm(runtimeDir, { recursive: true, force: true }); + } +}); + +test("evidence reporter blocks outbound payload when evidence is incomplete", async () => { + const tempDir = join(PROJECT_ROOT, "runtime", `zzzz-p1-reporter-${Date.now()}`); + const evidencePath = join(tempDir, "evidence.json"); + const outboundDir = join(tempDir, "outbound"); + await mkdir(tempDir, { recursive: true }); + await writeFile(evidencePath, `${JSON.stringify({ itemId: "P1-3" }, null, 2)}\n`, "utf8"); + + try { + const blocked = await runNodeScript(["scripts/evidence-reporter.ts", evidencePath, outboundDir], process.env); + assert.equal(blocked.code, 1); + assert(blocked.stderr.includes("REPORT_BLOCKED_EVIDENCE")); + + await writeFile( + evidencePath, + `${JSON.stringify( + { + generatedAt: new Date().toISOString(), + itemId: "P1-3", + completed: "Evidence-only reporter wiring", + filesChanged: ["scripts/evidence-reporter.ts", "test/p1-control-scripts.test.ts"], + verification: "reporter test", + visibleMarker: "runtime/evidence/outbound/latest.json", + }, + null, + 2, + )}\n`, + "utf8", + ); + + const ok = await runNodeScript(["scripts/evidence-reporter.ts", evidencePath, outboundDir], process.env); + assert.equal(ok.code, 0, `evidence reporter failed\nstdout:\n${ok.stdout}\nstderr:\n${ok.stderr}`); + await stat(join(outboundDir, "latest.json")); + const payload = JSON.parse(await readFile(join(outboundDir, "latest.json"), "utf8")) as { + progress?: { itemId?: string }; + }; + assert.equal(payload.progress?.itemId, "P1-3"); + } finally { + await rm(tempDir, { recursive: true, force: true }); + } +}); + +test("watchdog orchestrator fails on lock ownership conflict", async () => { + const tempDir = join(PROJECT_ROOT, "runtime", `zzzz-p1-watchdog-conflict-${Date.now()}`); + const lockPath = join(tempDir, "run.lock"); + const evidencePath = join(tempDir, "evidence.json"); + const recoveryPath = join(tempDir, "recovery.json"); + const reportPath = join(tempDir, "watchdog.json"); + await mkdir(tempDir, { recursive: true }); + await writeFile( + evidencePath, + `${JSON.stringify( + { + generatedAt: new Date().toISOString(), + itemId: "P1-3", + completed: "ready", + filesChanged: ["x"], + verification: "ok", + visibleMarker: "ok", + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + lockPath, + `${JSON.stringify( + { + runId: "lock-1", + owner: "other-owner", + startedAt: new Date(Date.now() - 60_000).toISOString(), + updatedAt: new Date().toISOString(), + leaseUntil: new Date(Date.now() + 10 * 60_000).toISOString(), + fencingToken: 1, + }, + null, + 2, + )}\n`, + "utf8", + ); + + try { + const run = await runNodeScript( + ["scripts/watchdog-orchestrator.ts", lockPath, evidencePath, recoveryPath, reportPath], + { + ...process.env, + RUN_OWNER: "pandas-owner", + STALL_EVIDENCE_MAX_AGE_MS: "31536000000", + STALL_LOCK_MAX_AGE_MS: "31536000000", + }, + ); + assert.equal(run.code, 1); + assert(run.stderr.includes("WATCHDOG_LOCK_CONFLICT")); + } finally { + await rm(tempDir, { recursive: true, force: true }); + } +}); + +test("watchdog orchestrator renews owner lock and runs heal chain", async () => { + const tempDir = join(PROJECT_ROOT, "runtime", `zzzz-p1-watchdog-ok-${Date.now()}`); + const lockPath = join(tempDir, "run.lock"); + const evidencePath = join(tempDir, "evidence.json"); + const recoveryPath = join(tempDir, "recovery.json"); + const reportPath = join(tempDir, "watchdog.json"); + await mkdir(tempDir, { recursive: true }); + await writeFile( + evidencePath, + `${JSON.stringify( + { + generatedAt: new Date().toISOString(), + itemId: "P1-3", + completed: "ready", + filesChanged: ["x"], + verification: "ok", + visibleMarker: "ok", + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + lockPath, + `${JSON.stringify( + { + runId: "lock-2", + owner: "pandas-owner", + startedAt: new Date(Date.now() - 60_000).toISOString(), + updatedAt: new Date().toISOString(), + leaseUntil: new Date(Date.now() + 10 * 60_000).toISOString(), + fencingToken: 7, + }, + null, + 2, + )}\n`, + "utf8", + ); + + try { + const run = await runNodeScript( + ["scripts/watchdog-orchestrator.ts", lockPath, evidencePath, recoveryPath, reportPath], + { + ...process.env, + RUN_OWNER: "pandas-owner", + STALL_EVIDENCE_MAX_AGE_MS: "31536000000", + STALL_LOCK_MAX_AGE_MS: "31536000000", + }, + ); + assert.equal(run.code, 0, `watchdog failed\nstdout:\n${run.stdout}\nstderr:\n${run.stderr}`); + assert(run.stdout.includes("WATCHDOG_OK")); + + const report = JSON.parse(await readFile(reportPath, "utf8")) as { + outcome?: string; + lockAction?: string; + }; + assert.equal(report.outcome, "healthy"); + assert.equal(report.lockAction, "renew"); + + const lock = JSON.parse(await readFile(lockPath, "utf8")) as { owner?: string }; + assert.equal(lock.owner, "pandas-owner"); + await stat(recoveryPath); + } finally { + await rm(tempDir, { recursive: true, force: true }); + } +}); + +async function runNodeScript( + args: string[], + env: NodeJS.ProcessEnv, +): Promise<{ code: number | null; stdout: string; stderr: string }> { + return await new Promise((resolvePromise, rejectPromise) => { + const child = spawn(process.execPath, ["--import", "tsx", ...args.map((value) => resolve(PROJECT_ROOT, value))], { + cwd: PROJECT_ROOT, + env, + stdio: ["ignore", "pipe", "pipe"], + }); + let stdout = ""; + let stderr = ""; + child.stdout.on("data", (chunk) => { + stdout += String(chunk); + }); + child.stderr.on("data", (chunk) => { + stderr += String(chunk); + }); + child.on("error", rejectPromise); + child.on("close", (code) => { + resolvePromise({ code, stdout, stderr }); + }); + }); +} diff --git a/test/phase11-replay-index.test.ts b/test/phase11-replay-index.test.ts new file mode 100644 index 0000000..91fafe8 --- /dev/null +++ b/test/phase11-replay-index.test.ts @@ -0,0 +1,35 @@ +import assert from "node:assert/strict"; +import { mkdir, rm, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import test from "node:test"; + +const RUNTIME_DIR = join(process.cwd(), "runtime"); +const EXPORTS_DIR = join(RUNTIME_DIR, "exports"); + +test("replay index includes runtime export bundles", async () => { + const { loadReplayIndex } = await import("../src/runtime/replay-index"); + + await mkdir(EXPORTS_DIR, { recursive: true }); + const fileName = `zzzz-phase11-test-${Date.now()}.json`; + const filePath = join(EXPORTS_DIR, fileName); + + const fixture = { + exportedAt: new Date().toISOString(), + snapshotGeneratedAt: new Date().toISOString(), + requestId: "phase11-replay-test", + projects: { projects: [{ projectId: "p1" }] }, + tasks: { tasks: [{ taskId: "t1", projectId: "p1" }] }, + sessions: [{ sessionKey: "s1" }], + exceptionsFeed: { items: [{ code: "X" }] }, + }; + + await writeFile(filePath, `${JSON.stringify(fixture, null, 2)}\n`, "utf8"); + + try { + const replay = await loadReplayIndex({ exportLimit: 200 }); + assert(Array.isArray(replay.exportBundles)); + assert(replay.exportBundles.some((entry) => entry.fileName === fileName)); + } finally { + await rm(filePath, { force: true }); + } +}); diff --git a/test/phase13-replay-acks.test.ts b/test/phase13-replay-acks.test.ts new file mode 100644 index 0000000..805dee8 --- /dev/null +++ b/test/phase13-replay-acks.test.ts @@ -0,0 +1,256 @@ +import assert from "node:assert/strict"; +import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import test from "node:test"; +import type { CommanderExceptionsFeed } from "../src/types"; + +const RUNTIME_DIR = join(process.cwd(), "runtime"); +const EXPORTS_DIR = join(RUNTIME_DIR, "exports"); +const TIMELINE_LOG_PATH = join(RUNTIME_DIR, "timeline.log"); + +test("replay index applies optional from/to filters", async () => { + const { loadReplayIndex } = await import("../src/runtime/replay-index"); + + await mkdir(EXPORTS_DIR, { recursive: true }); + + const now = Date.now(); + const outsideAt = new Date(now - 6 * 60 * 60 * 1000).toISOString(); + const insideAt = new Date(now - 10 * 60 * 1000).toISOString(); + const from = new Date(now - 30 * 60 * 1000).toISOString(); + const to = new Date(now + 60 * 1000).toISOString(); + + const outsideFile = `zzzz-phase13-outside-${Date.now()}.json`; + const insideFile = `zzzz-phase13-inside-${Date.now()}.json`; + const outsidePath = join(EXPORTS_DIR, outsideFile); + const insidePath = join(EXPORTS_DIR, insideFile); + + await writeFile( + outsidePath, + `${JSON.stringify({ exportedAt: outsideAt, projects: { projects: [] }, tasks: { tasks: [] }, sessions: [], exceptionsFeed: { items: [] } }, null, 2)}\n`, + "utf8", + ); + await writeFile( + insidePath, + `${JSON.stringify({ exportedAt: insideAt, projects: { projects: [] }, tasks: { tasks: [] }, sessions: [], exceptionsFeed: { items: [] } }, null, 2)}\n`, + "utf8", + ); + + let timelineExisted = true; + let timelineBefore = ""; + try { + timelineBefore = await readFile(TIMELINE_LOG_PATH, "utf8"); + } catch { + timelineExisted = false; + } + + const markerOutside = `phase13-outside-${Date.now()}`; + const markerInside = `phase13-inside-${Date.now()}`; + await writeFile( + TIMELINE_LOG_PATH, + `${timelineBefore}${timelineBefore.endsWith("\n") || timelineBefore === "" ? "" : "\n"}${outsideAt} | ${markerOutside}\n${insideAt} | ${markerInside}\n`, + "utf8", + ); + + try { + const replay = await loadReplayIndex({ + timelineLimit: 400, + digestLimit: 200, + exportLimit: 200, + from, + to, + }); + assert.equal(replay.window?.from, from); + assert.equal(replay.window?.to, to); + assert(replay.exportBundles.some((entry) => entry.fileName === insideFile)); + assert(!replay.exportBundles.some((entry) => entry.fileName === outsideFile)); + assert(replay.timeline.entries.some((entry) => entry.summary.includes(markerInside))); + assert(!replay.timeline.entries.some((entry) => entry.summary.includes(markerOutside))); + assert.equal(replay.stats.timeline.total, replay.timeline.totalLines); + assert.equal(replay.stats.timeline.returned, replay.timeline.entries.length); + assert.equal(replay.stats.exportBundles.returned, replay.exportBundles.length); + assert(replay.stats.timeline.filteredOut >= 1); + assert(replay.stats.exportBundles.filteredOut >= 1); + assert(replay.stats.timeline.latencyMs >= 0); + assert(replay.stats.digests.latencyMs >= 0); + assert(replay.stats.exportSnapshots.latencyMs >= 0); + assert(replay.stats.exportBundles.latencyMs >= 0); + assert(replay.stats.timeline.latencyBucketsMs.p50 >= 0); + assert(replay.stats.timeline.latencyBucketsMs.p95 >= replay.stats.timeline.latencyBucketsMs.p50); + assert(replay.stats.digests.latencyBucketsMs.p50 >= 0); + assert(replay.stats.digests.latencyBucketsMs.p95 >= replay.stats.digests.latencyBucketsMs.p50); + assert(replay.stats.exportSnapshots.latencyBucketsMs.p50 >= 0); + assert( + replay.stats.exportSnapshots.latencyBucketsMs.p95 >= + replay.stats.exportSnapshots.latencyBucketsMs.p50, + ); + assert(replay.stats.exportBundles.latencyBucketsMs.p50 >= 0); + assert( + replay.stats.exportBundles.latencyBucketsMs.p95 >= replay.stats.exportBundles.latencyBucketsMs.p50, + ); + assert(replay.stats.total.latencyBucketsMs.p50 >= 0); + assert(replay.stats.total.latencyBucketsMs.p95 >= replay.stats.total.latencyBucketsMs.p50); + assert(replay.stats.timeline.totalSizeBytes >= replay.stats.timeline.returnedSizeBytes); + assert(replay.stats.digests.totalSizeBytes >= replay.stats.digests.returnedSizeBytes); + assert(replay.stats.exportSnapshots.totalSizeBytes >= replay.stats.exportSnapshots.returnedSizeBytes); + assert(replay.stats.exportBundles.totalSizeBytes >= replay.stats.exportBundles.returnedSizeBytes); + assert.equal( + replay.stats.total.returned, + replay.stats.timeline.returned + + replay.stats.digests.returned + + replay.stats.exportSnapshots.returned + + replay.stats.exportBundles.returned, + ); + assert.equal( + replay.stats.total.returnedSizeBytes, + replay.stats.timeline.returnedSizeBytes + + replay.stats.digests.returnedSizeBytes + + replay.stats.exportSnapshots.returnedSizeBytes + + replay.stats.exportBundles.returnedSizeBytes, + ); + assert.equal( + replay.stats.total.totalSizeBytes, + replay.stats.timeline.totalSizeBytes + + replay.stats.digests.totalSizeBytes + + replay.stats.exportSnapshots.totalSizeBytes + + replay.stats.exportBundles.totalSizeBytes, + ); + } finally { + await rm(outsidePath, { force: true }); + await rm(insidePath, { force: true }); + if (timelineExisted) { + await writeFile(TIMELINE_LOG_PATH, timelineBefore, "utf8"); + } else { + await rm(TIMELINE_LOG_PATH, { force: true }); + } + } +}); + +test("action queue acknowledgements support ttl and expire as inactive", async () => { + const { ACKS_PATH, acknowledgeActionQueueItem, actionQueueItemId, buildNotificationCenter } = + await import("../src/runtime/notification-center"); + + const feed: CommanderExceptionsFeed = { + generatedAt: new Date().toISOString(), + items: [ + { + level: "action-required", + code: "TASK_DUE", + source: "task", + sourceId: "task-1", + message: "task due now", + route: "action-queue", + occurredAt: new Date().toISOString(), + }, + ], + counts: { + info: 0, + warn: 0, + actionRequired: 1, + }, + }; + + const itemId = actionQueueItemId(feed.items[0]); + const center = buildNotificationCenter(feed, { + acks: [], + updatedAt: new Date().toISOString(), + }); + + let acksExisted = true; + let acksBefore = ""; + try { + acksBefore = await readFile(ACKS_PATH, "utf8"); + } catch { + acksExisted = false; + } + + try { + const result = await acknowledgeActionQueueItem({ itemId, ttlMinutes: 5 }, center); + assert.equal(result.ack.itemId, itemId); + assert.equal(typeof result.ack.expiresAt, "string"); + assert(Date.parse(result.ack.expiresAt ?? "") > Date.parse(result.ack.ackedAt)); + } finally { + if (acksExisted) { + await writeFile(ACKS_PATH, acksBefore, "utf8"); + } else { + await rm(ACKS_PATH, { force: true }); + } + } + + const futureAckCenter = buildNotificationCenter(feed, { + acks: [ + { + itemId, + ackedAt: new Date().toISOString(), + expiresAt: new Date(Date.now() + 60_000).toISOString(), + }, + ], + updatedAt: new Date().toISOString(), + }); + assert.equal(futureAckCenter.queue[0]?.acknowledged, true); + assert.equal(typeof futureAckCenter.queue[0]?.ackExpiresAt, "string"); + + const expiredAckCenter = buildNotificationCenter(feed, { + acks: [ + { + itemId, + ackedAt: new Date().toISOString(), + expiresAt: new Date(Date.now() - 60_000).toISOString(), + }, + ], + updatedAt: new Date().toISOString(), + }); + assert.equal(expiredAckCenter.queue[0]?.acknowledged, false); +}); + +test("stale ack prune preview returns counts only and does not mutate ack store", async () => { + const { ACKS_PATH, previewStaleAcksPrune } = await import("../src/runtime/notification-center"); + + let acksExisted = true; + let acksBefore = ""; + try { + acksBefore = await readFile(ACKS_PATH, "utf8"); + } catch { + acksExisted = false; + } + + const nowMs = Date.now(); + const expiredItemId = `phase15-preview-expired-${nowMs}`; + const activeItemId = `phase15-preview-active-${nowMs}`; + const fixture = { + acks: [ + { + itemId: expiredItemId, + ackedAt: new Date(nowMs - 2 * 60_000).toISOString(), + expiresAt: new Date(nowMs - 60_000).toISOString(), + }, + { + itemId: activeItemId, + ackedAt: new Date(nowMs - 2 * 60_000).toISOString(), + expiresAt: new Date(nowMs + 5 * 60_000).toISOString(), + }, + ], + updatedAt: new Date(nowMs).toISOString(), + }; + await writeFile(ACKS_PATH, `${JSON.stringify(fixture, null, 2)}\n`, "utf8"); + + try { + const preview = await previewStaleAcksPrune({ nowMs }); + assert.equal(preview.dryRun, true); + assert.equal(preview.before, 2); + assert.equal(preview.removed, 1); + assert.equal(preview.after, 1); + assert.equal(Object.prototype.hasOwnProperty.call(preview, "removedItemIds"), false); + + const afterRaw = await readFile(ACKS_PATH, "utf8"); + const after = JSON.parse(afterRaw) as { acks?: Array<{ itemId?: string }> }; + const itemIds = (after.acks ?? []).map((item) => item.itemId).filter(Boolean); + assert(itemIds.includes(expiredItemId), "Preview must not mutate runtime/acks.json."); + assert(itemIds.includes(activeItemId)); + } finally { + if (acksExisted) { + await writeFile(ACKS_PATH, acksBefore, "utf8"); + } else { + await rm(ACKS_PATH, { force: true }); + } + } +}); diff --git a/test/phase9-routes-commands.test.ts b/test/phase9-routes-commands.test.ts new file mode 100644 index 0000000..0e03efe --- /dev/null +++ b/test/phase9-routes-commands.test.ts @@ -0,0 +1,314 @@ +import assert from "node:assert/strict"; +import { spawn } from "node:child_process"; +import { readFile, rm, stat, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import test from "node:test"; + +const PROJECT_ROOT = process.cwd(); +const RUNTIME_DIR = join(PROJECT_ROOT, "runtime"); +const OPERATION_AUDIT_LOG = join(RUNTIME_DIR, "operation-audit.log"); +const ACKS_PATH = join(RUNTIME_DIR, "acks.json"); +const TEST_LOCAL_TOKEN = "phase10-test-token"; + +test("done-checklist route logic builds readiness payload", async () => { + const [ + { buildDoneChecklist }, + { validateExportBundleDryRun }, + { evaluateLocalTokenGate }, + { evaluateImportMutationGuard }, + { buildApiDocs }, + { LOCAL_TOKEN_AUTH_REQUIRED }, + ] = + await Promise.all([ + import("../src/runtime/done-checklist"), + import("../src/runtime/import-dry-run"), + import("../src/runtime/local-token-auth"), + import("../src/runtime/import-live"), + import("../src/runtime/api-docs"), + import("../src/config"), + ]); + + const snapshot = await loadSnapshotFixture(); + const checklist = await buildDoneChecklist(snapshot); + assert.equal(typeof checklist.readiness.overall, "number"); + assert(Array.isArray(checklist.items)); + assert(checklist.items.length > 0); + const routeCoverageItem = checklist.items.find((item) => item.id === "obs_route_coverage"); + assert(routeCoverageItem, "Expected obs_route_coverage checklist item."); + assert(routeCoverageItem.detail.includes("/api/action-queue/acks/prune-preview")); + const uiBindEnvItem = checklist.items.find((item) => item.id === "obs_ui_bind_env_only"); + assert(uiBindEnvItem, "Expected obs_ui_bind_env_only checklist item."); + assert.equal(uiBindEnvItem.status, "pass"); + assert(uiBindEnvItem.detail.includes("environment-only")); + const actionQueueSignalItem = checklist.items.find((item) => item.id === "collab_action_queue_signal"); + assert(actionQueueSignalItem, "Expected collab_action_queue_signal checklist item."); + assert.equal(actionQueueSignalItem.status, "pass"); + const localTokenGateItem = checklist.items.find((item) => item.id === "sec_local_token_gate"); + assert(localTokenGateItem, "Expected sec_local_token_gate checklist item."); + assert.equal(localTokenGateItem.status, LOCAL_TOKEN_AUTH_REQUIRED ? "pass" : "warn"); + + const docs = buildApiDocs(); + assert(docs.routes.some((route) => route.path === "/api/commander/exceptions")); + assert(docs.routes.some((route) => route.path === "/api/action-queue")); + assert(docs.routes.some((route) => route.path === "/api/action-queue/acks/prune-preview")); + assert(docs.routes.some((route) => route.path === "/api/tasks/heartbeat")); + assert(docs.routes.some((route) => route.path === "/api/usage-cost")); + + // Route-level guard behavior used by /api/import/dry-run + const blocked = evaluateLocalTokenGate({ + gateRequired: true, + configuredToken: TEST_LOCAL_TOKEN, + routeLabel: "/api/import/live", + }); + assert.equal(blocked.ok, false); + assert.equal(blocked.statusCode, 401); + + const allowed = evaluateLocalTokenGate({ + gateRequired: true, + configuredToken: TEST_LOCAL_TOKEN, + providedToken: TEST_LOCAL_TOKEN, + routeLabel: "/api/import/live", + }); + assert.equal(allowed.ok, true); + assert.equal(allowed.statusCode, 200); + + const importGateBlocked = evaluateImportMutationGuard({ + mutationEnabled: false, + mutationDryRunDefault: false, + readonlyMode: false, + routeLabel: "/api/import/live", + }); + assert.equal(importGateBlocked.ok, false); + assert.equal(importGateBlocked.statusCode, 403); + + const importGateDryRun = evaluateImportMutationGuard({ + mutationEnabled: true, + mutationDryRunDefault: false, + readonlyMode: true, + routeLabel: "/api/import/live", + requestedDryRun: true, + }); + assert.equal(importGateDryRun.ok, true); + assert.equal(importGateDryRun.mode, "dry_run"); + + const validBundle = { + ok: true, + schemaVersion: "phase-9", + source: "api", + exportedAt: "2026-03-01T12:00:00.000Z", + snapshotGeneratedAt: "2026-03-01T12:00:00.000Z", + sessions: [{ sessionKey: "s-1", state: "running" }], + projects: { + updatedAt: "2026-03-01T12:00:00.000Z", + projects: [{ projectId: "p-1", title: "P1", status: "active", owner: "owner", updatedAt: "2026-03-01T12:00:00.000Z" }], + }, + tasks: { + updatedAt: "2026-03-01T12:00:00.000Z", + agentBudgets: [], + tasks: [{ projectId: "p-1", taskId: "t-1", status: "todo", title: "T1", owner: "owner", definitionOfDone: [], artifacts: [], rollback: { strategy: "none", steps: [] }, sessionKeys: [], budget: {}, updatedAt: "2026-03-01T12:00:00.000Z" }], + }, + budgets: { + policy: {}, + summary: {}, + issues: [], + }, + exceptions: { counts: {} }, + exceptionsFeed: { items: [], counts: {} }, + }; + const validation = validateExportBundleDryRun(validBundle, "payload.bundle"); + assert.equal(validation.valid, true); + assert.equal(validation.issues.length, 0); +}); + +test("backup export command path writes bundle and operation audit entry", async () => { + const run = await runCommand("npm", ["run", "command:backup-export"], { + cwd: PROJECT_ROOT, + env: { + ...process.env, + READONLY_MODE: "true", + APPROVAL_ACTIONS_ENABLED: "false", + APPROVAL_ACTIONS_DRY_RUN: "true", + LOCAL_TOKEN_AUTH_REQUIRED: "true", + LOCAL_API_TOKEN: TEST_LOCAL_TOKEN, + }, + }); + + assert.equal( + run.code, + 0, + `backup-export command failed\nstdout:\n${run.stdout}\nstderr:\n${run.stderr}`, + ); + + const auditEntries = await readOperationAuditEntries(); + const commandEntry = [...auditEntries] + .reverse() + .find((entry) => entry.action === "backup_export" && entry.source === "command"); + assert(commandEntry, "Expected backup_export command audit entry"); + assert.equal(commandEntry.ok, true); + const metadata = asRecord(commandEntry.metadata); + assert.equal(typeof metadata?.path, "string"); + const writtenPath = metadata?.path as string; + assert(writtenPath.includes("/runtime/exports/")); + assert(await fileExists(writtenPath), "Expected backup export file path from audit metadata to exist."); +}); + +test("acks-prune command removes expired records and writes audit entry", async () => { + let acksExisted = true; + let acksBefore = ""; + try { + acksBefore = await readFile(ACKS_PATH, "utf8"); + } catch { + acksExisted = false; + } + + const now = Date.now(); + const expiredItemId = `phase14-expired-${now}`; + const activeItemId = `phase14-active-${now}`; + const fixture = { + acks: [ + { + itemId: expiredItemId, + ackedAt: new Date(now - 2 * 60_000).toISOString(), + expiresAt: new Date(now - 60_000).toISOString(), + }, + { + itemId: activeItemId, + ackedAt: new Date(now - 2 * 60_000).toISOString(), + expiresAt: new Date(now + 5 * 60_000).toISOString(), + }, + ], + updatedAt: new Date(now).toISOString(), + }; + await writeFile(ACKS_PATH, `${JSON.stringify(fixture, null, 2)}\n`, "utf8"); + + try { + const run = await runCommand("npm", ["run", "command:acks-prune"], { + cwd: PROJECT_ROOT, + env: { + ...process.env, + READONLY_MODE: "true", + APPROVAL_ACTIONS_ENABLED: "false", + APPROVAL_ACTIONS_DRY_RUN: "true", + LOCAL_TOKEN_AUTH_REQUIRED: "true", + LOCAL_API_TOKEN: TEST_LOCAL_TOKEN, + }, + }); + + assert.equal( + run.code, + 0, + `acks-prune command failed\nstdout:\n${run.stdout}\nstderr:\n${run.stderr}`, + ); + + const raw = await readFile(ACKS_PATH, "utf8"); + const parsed = JSON.parse(raw) as { acks?: Array<{ itemId?: string }> }; + const itemIds = (parsed.acks ?? []).map((item) => item.itemId).filter(Boolean); + assert(!itemIds.includes(expiredItemId), "Expected expired ack to be pruned."); + assert(itemIds.includes(activeItemId), "Expected active ack to remain."); + + const auditEntries = await readOperationAuditEntries(); + const pruneEntry = [...auditEntries] + .reverse() + .find((entry) => entry.action === "ack_prune" && entry.source === "command"); + assert(pruneEntry, "Expected ack_prune command audit entry"); + assert.equal(pruneEntry.ok, true); + const metadata = asRecord(pruneEntry.metadata); + assert.equal(typeof metadata?.removed, "number"); + assert((metadata?.removed as number) >= 1); + } finally { + if (acksExisted) { + await writeFile(ACKS_PATH, acksBefore, "utf8"); + } else { + await rm(ACKS_PATH, { force: true }); + } + } +}); + +async function loadSnapshotFixture(): Promise> { + const snapshotPath = join(RUNTIME_DIR, "last-snapshot.json"); + try { + const raw = await readFile(snapshotPath, "utf8"); + return JSON.parse(raw) as Record; + } catch { + const now = new Date().toISOString(); + return { + sessions: [], + statuses: [], + cronJobs: [], + approvals: [], + projects: { projects: [], updatedAt: now }, + projectSummaries: [], + tasks: { tasks: [], agentBudgets: [], updatedAt: now }, + tasksSummary: { + projects: 0, + tasks: 0, + todo: 0, + inProgress: 0, + blocked: 0, + done: 0, + owners: 0, + artifacts: 0, + }, + budgetSummary: { total: 0, ok: 0, warn: 0, over: 0, evaluations: [] }, + generatedAt: now, + }; + } +} + +async function readOperationAuditEntries(): Promise>> { + try { + const raw = await readFile(OPERATION_AUDIT_LOG, "utf8"); + return raw + .split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line !== "") + .map((line) => JSON.parse(line) as Record); + } catch { + return []; + } +} + +async function runCommand( + cmd: string, + args: string[], + options: { + cwd: string; + env: NodeJS.ProcessEnv; + }, +): Promise<{ code: number | null; stdout: string; stderr: string }> { + return await new Promise((resolve, reject) => { + const child = spawn(cmd, args, { + cwd: options.cwd, + env: options.env, + stdio: ["ignore", "pipe", "pipe"], + }); + let stdout = ""; + let stderr = ""; + + child.stdout.on("data", (chunk) => { + stdout += String(chunk); + }); + child.stderr.on("data", (chunk) => { + stderr += String(chunk); + }); + child.on("error", reject); + child.on("close", (code) => { + resolve({ code, stdout, stderr }); + }); + }); +} + +function asRecord(input: unknown): Record | undefined { + return input !== null && typeof input === "object" && !Array.isArray(input) + ? (input as Record) + : undefined; +} + +async function fileExists(path: string): Promise { + try { + await stat(path); + return true; + } catch { + return false; + } +} diff --git a/test/session-execution-chain.test.ts b/test/session-execution-chain.test.ts new file mode 100644 index 0000000..3d0d881 --- /dev/null +++ b/test/session-execution-chain.test.ts @@ -0,0 +1,261 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import type { ToolClient } from "../src/clients/tool-client"; +import { + getSessionConversationDetail, + listSessionConversations, +} from "../src/runtime/session-conversations"; +import type { SessionsHistoryRequest, SessionsHistoryResponse } from "../src/contracts/openclaw-tools"; +import type { ReadModelSnapshot } from "../src/types"; + +class FakeToolClient implements ToolClient { + constructor(private readonly historyBySession = new Map()) {} + + async sessionsList() { + return { sessions: [] }; + } + + async sessionStatus() { + return { rawText: "" }; + } + + async sessionsHistory(request: SessionsHistoryRequest): Promise { + return this.historyBySession.get(request.sessionKey) ?? { rawText: "" }; + } + + async cronList() { + return { jobs: [] }; + } + + async approvalsGet() { + return { rawText: "" }; + } + + async approvalsApprove() { + return { ok: false, action: "approve" as const, approvalId: "n/a", rawText: "" }; + } + + async approvalsReject() { + return { ok: false, action: "reject" as const, approvalId: "n/a", rawText: "" }; + } +} + +function makeSnapshot(sessionKeys: Array<{ sessionKey: string; agentId?: string; state?: "idle" | "running" | "blocked" | "waiting_approval" | "error"; lastMessageAt?: string }>): ReadModelSnapshot { + return { + sessions: sessionKeys.map((item) => ({ + sessionKey: item.sessionKey, + agentId: item.agentId, + state: item.state ?? "idle", + lastMessageAt: item.lastMessageAt, + })), + statuses: [], + cronJobs: [], + approvals: [], + projects: { projects: [], updatedAt: "2026-03-07T10:00:00.000Z" }, + projectSummaries: [], + tasks: { tasks: [], agentBudgets: [], updatedAt: "2026-03-07T10:00:00.000Z" }, + tasksSummary: { + projects: 0, + tasks: 0, + todo: 0, + inProgress: 0, + blocked: 0, + done: 0, + owners: 0, + artifacts: 0, + }, + budgetSummary: { total: 0, ok: 0, warn: 0, over: 0, evaluations: [] }, + generatedAt: "2026-03-07T10:00:00.000Z", + }; +} + +test("run child session infers execution chain from session key when history is unavailable", async () => { + const snapshot = makeSnapshot([ + { + sessionKey: "agent:main:cron:job-1:run:child-1", + agentId: "main", + state: "running", + lastMessageAt: "2026-03-07T10:01:00.000Z", + }, + ]); + + const result = await listSessionConversations({ + snapshot, + client: new FakeToolClient(), + filters: {}, + page: 1, + pageSize: 10, + historyLimit: 10, + }); + + assert.equal(result.items.length, 1); + assert.equal(result.items[0].executionChain?.source, "session_key"); + assert.equal(result.items[0].executionChain?.parentSessionKey, "agent:main:cron:job-1"); + assert.equal(result.items[0].executionChain?.childSessionKey, "agent:main:cron:job-1:run:child-1"); + assert.equal(result.items[0].executionChain?.accepted, true); + assert.equal(result.items[0].executionChain?.spawned, true); + assert.equal(result.items[0].executionChain?.stage, "running"); +}); + +test("history execution events are parsed and preferred over session-key inference", async () => { + const sessionKey = "agent:main:cron:job-2"; + const childSessionKey = "agent:main:cron:job-2:run:child-2"; + const snapshot = makeSnapshot([ + { + sessionKey, + agentId: "main", + state: "idle", + lastMessageAt: "2026-03-07T10:02:00.000Z", + }, + ]); + const client = new FakeToolClient( + new Map([ + [ + sessionKey, + { + json: { + history: [ + { + event: "accepted", + timestamp: "2026-03-07T10:02:10.000Z", + message: "accepted parent session", + }, + { + event: "sessions_spawn", + timestamp: "2026-03-07T10:02:20.000Z", + parentSessionKey: sessionKey, + childSessionKey, + message: "spawned child session", + }, + ], + }, + rawText: "", + }, + ], + ]), + ); + + const detail = await getSessionConversationDetail({ + snapshot, + client, + sessionKey, + historyLimit: 20, + }); + + assert(detail); + assert.equal(detail.executionChain?.source, "history"); + assert.equal(detail.executionChain?.accepted, true); + assert.equal(detail.executionChain?.spawned, true); + assert.equal(detail.executionChain?.parentSessionKey, sessionKey); + assert.equal(detail.executionChain?.childSessionKey, childSessionKey); + assert.equal(detail.executionChain?.acceptedAt, "2026-03-07T10:02:10.000Z"); + assert.equal(detail.executionChain?.spawnedAt, "2026-03-07T10:02:20.000Z"); + assert.deepEqual(detail.history.map((item) => item.kind), ["accepted", "spawn"]); +}); + +test("raw text history fallback still extracts accepted and spawn events", async () => { + const sessionKey = "agent:main:cron:job-3"; + const childSessionKey = "agent:main:cron:job-3:run:child-3"; + const snapshot = makeSnapshot([ + { + sessionKey, + agentId: "main", + state: "idle", + }, + ]); + const client = new FakeToolClient( + new Map([ + [ + sessionKey, + { + rawText: [ + "accepted request for timed job", + `sessions_spawn parent=${sessionKey} child=${childSessionKey}`, + ].join("\n"), + }, + ], + ]), + ); + + const detail = await getSessionConversationDetail({ + snapshot, + client, + sessionKey, + historyLimit: 20, + }); + + assert(detail); + assert.deepEqual(detail.history.map((item) => item.kind), ["accepted", "spawn"]); + assert.equal(detail.executionChain?.source, "history"); + assert.equal(detail.executionChain?.childSessionKey, childSessionKey); +}); + +test("nested message envelope preserves user and assistant roles", async () => { + const sessionKey = "agent:coq:main"; + const snapshot = makeSnapshot([ + { + sessionKey, + agentId: "coq", + state: "running", + lastMessageAt: "2026-03-09T22:56:10.656Z", + }, + ]); + const client = new FakeToolClient( + new Map([ + [ + sessionKey, + { + json: { + history: [ + { + type: "message", + timestamp: "2026-03-09T22:55:46.585Z", + message: { + role: "user", + content: [ + { + type: "text", + text: "[Mon 2026-03-09 23:55 GMT+1] 立即停止你当前的所有活动,不要继续任何 review、演示、brief、整理、输出、工具调用或后续收尾扩展。从现在起进入待命状态,不再处理任何当前任务。回复必须是:REPLY_SKIP。announce 必须是:ANNOUNCE_SKIP。", + }, + ], + }, + }, + { + type: "message", + timestamp: "2026-03-09T22:55:51.944Z", + message: { + role: "assistant", + content: [ + { + type: "thinking", + thinking: "**Using direct reply only**", + }, + { + type: "text", + text: "REPLY_SKIP", + }, + ], + }, + }, + ], + }, + rawText: "", + }, + ], + ]), + ); + + const detail = await getSessionConversationDetail({ + snapshot, + client, + sessionKey, + historyLimit: 20, + }); + + assert(detail); + assert.equal(detail.history.length, 2); + assert.equal(detail.history[0].role, "user"); + assert.match(detail.history[0].content, /立即停止你当前的所有活动/); + assert.equal(detail.history[1].role, "assistant"); + assert.match(detail.history[1].content, /REPLY_SKIP/); +}); diff --git a/test/task-heartbeat.test.ts b/test/task-heartbeat.test.ts new file mode 100644 index 0000000..23d1957 --- /dev/null +++ b/test/task-heartbeat.test.ts @@ -0,0 +1,200 @@ +import assert from "node:assert/strict"; +import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { dirname } from "node:path"; +import test from "node:test"; +import type { ProjectTask, TaskStoreSnapshot } from "../src/types"; +import { TASKS_PATH } from "../src/runtime/task-store"; +import { + TASK_HEARTBEAT_LOG_PATH, + readTaskHeartbeatRuns, + runTaskHeartbeat, + selectHeartbeatTasks, +} from "../src/runtime/task-heartbeat"; + +test("selectHeartbeatTasks picks assigned todo tasks by due/age priority", () => { + const store: TaskStoreSnapshot = { + tasks: [ + buildTask({ + projectId: "p1", + taskId: "late-unassigned", + owner: "unassigned", + dueAt: "2026-03-01T10:00:00.000Z", + }), + buildTask({ + projectId: "p1", + taskId: "first", + owner: "alex", + dueAt: "2026-03-01T10:00:00.000Z", + updatedAt: "2026-02-28T10:00:00.000Z", + }), + buildTask({ + projectId: "p1", + taskId: "second", + owner: "sam", + dueAt: "2026-03-03T10:00:00.000Z", + updatedAt: "2026-02-27T10:00:00.000Z", + }), + buildTask({ + projectId: "p1", + taskId: "already-running", + owner: "sam", + status: "in_progress", + }), + buildTask({ + projectId: "p1", + taskId: "third-no-due", + owner: "zoe", + }), + ], + agentBudgets: [], + updatedAt: "2026-03-01T00:00:00.000Z", + }; + + const selected = selectHeartbeatTasks(store, 2); + assert.equal(selected.length, 2); + assert.equal(selected[0].taskId, "first"); + assert.equal(selected[1].taskId, "second"); +}); + +test("runTaskHeartbeat dry-run records selection without mutating task store", async () => { + const tasksBefore = await readOptionalFile(TASKS_PATH); + const logBefore = await readOptionalFile(TASK_HEARTBEAT_LOG_PATH); + + await writeTaskStoreFixture([ + buildTask({ projectId: "p1", taskId: "todo-1", owner: "alex" }), + buildTask({ projectId: "p1", taskId: "todo-2", owner: "sam" }), + ]); + + try { + const result = await runTaskHeartbeat({ + gate: { + enabled: true, + dryRun: true, + maxTasksPerRun: 1, + localTokenAuthRequired: true, + localTokenConfigured: false, + }, + }); + + assert.equal(result.ok, true); + assert.equal(result.mode, "dry_run"); + assert.equal(result.selected, 1); + assert.equal(result.executed, 0); + + const raw = await readFile(TASKS_PATH, "utf8"); + const parsed = JSON.parse(raw) as TaskStoreSnapshot; + const statuses = parsed.tasks.map((task) => task.status); + assert.deepEqual(statuses, ["todo", "todo"]); + } finally { + await restoreOptionalFile(TASKS_PATH, tasksBefore); + await restoreOptionalFile(TASK_HEARTBEAT_LOG_PATH, logBefore); + } +}); + +test("runTaskHeartbeat live mode moves selected assigned todo tasks to in_progress", async () => { + const tasksBefore = await readOptionalFile(TASKS_PATH); + const logBefore = await readOptionalFile(TASK_HEARTBEAT_LOG_PATH); + + await writeTaskStoreFixture([ + buildTask({ + projectId: "p-live", + taskId: "due-fast", + owner: "alex", + dueAt: "2026-03-01T09:00:00.000Z", + updatedAt: "2026-02-25T00:00:00.000Z", + }), + buildTask({ projectId: "p-live", taskId: "unassigned", owner: "unassigned" }), + buildTask({ + projectId: "p-live", + taskId: "todo-second", + owner: "sam", + dueAt: "2026-03-05T09:00:00.000Z", + updatedAt: "2026-02-26T00:00:00.000Z", + }), + buildTask({ projectId: "p-live", taskId: "already-running", owner: "taylor", status: "in_progress" }), + ]); + + try { + const result = await runTaskHeartbeat({ + gate: { + enabled: true, + dryRun: false, + maxTasksPerRun: 2, + localTokenAuthRequired: true, + localTokenConfigured: true, + }, + }); + + assert.equal(result.ok, true); + assert.equal(result.mode, "live"); + assert.equal(result.selected, 2); + assert.equal(result.executed, 2); + + const raw = await readFile(TASKS_PATH, "utf8"); + const parsed = JSON.parse(raw) as TaskStoreSnapshot; + const byTaskId = new Map(parsed.tasks.map((task) => [task.taskId, task.status])); + assert.equal(byTaskId.get("due-fast"), "in_progress"); + assert.equal(byTaskId.get("todo-second"), "in_progress"); + assert.equal(byTaskId.get("unassigned"), "todo"); + + const runs = await readTaskHeartbeatRuns(5); + assert(runs.count >= 1); + assert.equal(runs.runs[0].mode, "live"); + } finally { + await restoreOptionalFile(TASKS_PATH, tasksBefore); + await restoreOptionalFile(TASK_HEARTBEAT_LOG_PATH, logBefore); + } +}); + +function buildTask(input: { + projectId: string; + taskId: string; + owner: string; + status?: "todo" | "in_progress" | "blocked" | "done"; + dueAt?: string; + updatedAt?: string; +}): ProjectTask { + return { + projectId: input.projectId, + taskId: input.taskId, + title: input.taskId, + status: input.status ?? "todo", + owner: input.owner, + dueAt: input.dueAt, + definitionOfDone: [], + artifacts: [], + rollback: { + strategy: "manual", + steps: [], + }, + sessionKeys: [], + budget: {}, + updatedAt: input.updatedAt ?? "2026-03-01T00:00:00.000Z", + }; +} + +async function writeTaskStoreFixture(tasks: ProjectTask[]): Promise { + const store: TaskStoreSnapshot = { + tasks, + agentBudgets: [], + updatedAt: "2026-03-01T00:00:00.000Z", + }; + await mkdir(dirname(TASKS_PATH), { recursive: true }); + await writeFile(TASKS_PATH, `${JSON.stringify(store, null, 2)}\n`, "utf8"); +} + +async function readOptionalFile(path: string): Promise { + try { + return await readFile(path, "utf8"); + } catch { + return undefined; + } +} + +async function restoreOptionalFile(path: string, content: string | undefined): Promise { + if (content === undefined) { + await rm(path, { force: true }); + return; + } + await writeFile(path, content, "utf8"); +} diff --git a/test/triplet-control.test.ts b/test/triplet-control.test.ts new file mode 100644 index 0000000..1b8f2a6 --- /dev/null +++ b/test/triplet-control.test.ts @@ -0,0 +1,328 @@ +import assert from "node:assert/strict"; +import { mkdir, readFile, rm, utimes, writeFile } from "node:fs/promises"; +import { join, resolve } from "node:path"; +import { spawn } from "node:child_process"; +import test from "node:test"; + +const PROJECT_ROOT = process.cwd(); + +test("resident worker enforces single-chain lock ownership", async () => { + const runtimeDir = join(PROJECT_ROOT, "runtime", `zzzz-triplet-lock-${Date.now()}`); + const lockPath = join(runtimeDir, "run.lock"); + await mkdir(runtimeDir, { recursive: true }); + await writeFile( + lockPath, + `${JSON.stringify( + { + runId: "lock-1", + owner: "other-owner", + startedAt: new Date(Date.now() - 60_000).toISOString(), + updatedAt: new Date().toISOString(), + leaseUntil: new Date(Date.now() + 10 * 60_000).toISOString(), + fencingToken: 1, + }, + null, + 2, + )}\n`, + "utf8", + ); + + try { + const run = await runNodeScript(["scripts/resident-worker.ts", runtimeDir], { + ...process.env, + RUN_OWNER: "pandas-owner", + WORKER_MAX_CYCLES: "1", + WORKER_STEPS: "goal-gate", + }); + assert.equal(run.code, 1); + assert(run.stderr.includes("WORKER_LOCK_CONFLICT"), run.stderr); + } finally { + await rm(runtimeDir, { recursive: true, force: true }); + } +}); + +test("resident supervisor restarts worker when heartbeat is stale", async () => { + const runtimeDir = join(PROJECT_ROOT, "runtime", `zzzz-triplet-supervisor-${Date.now()}`); + const heartbeatPath = join(runtimeDir, "health", "worker-heartbeat.json"); + const recoveryPath = join(runtimeDir, "recovery", "supervisor-latest.json"); + await mkdir(join(runtimeDir, "health"), { recursive: true }); + await mkdir(join(runtimeDir, "evidence"), { recursive: true }); + await writeFile( + heartbeatPath, + `${JSON.stringify( + { + generatedAt: new Date(Date.now() - 10 * 60_000).toISOString(), + pid: 999999, + state: "waiting", + }, + null, + 2, + )}\n`, + "utf8", + ); + const staleTime = new Date(Date.now() - 10 * 60_000); + await utimes(heartbeatPath, staleTime, staleTime); + + await writeFile( + join(runtimeDir, "goal-state.json"), + `${JSON.stringify( + { + goalId: "triplet-goal", + definitionOfDone: ["build", "test"], + phases: [{ id: "phase-1", status: "done" }], + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + join(runtimeDir, "evidence", "latest.json"), + `${JSON.stringify( + { + generatedAt: new Date().toISOString(), + itemId: "triplet", + completed: "worker baseline", + filesChanged: ["scripts/resident-worker.ts"], + verification: "test", + visibleMarker: "runtime/evidence/latest.json", + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + join(runtimeDir, "evidence", "product-dod.json"), + `${JSON.stringify( + { + fullChinese: true, + nonTechnicalCopy: true, + middleSchoolReadable: true, + globalVisibility: true, + appleNativeUI: true, + realSubscriptionConnected: true, + tiApproval: false, + notes: "triplet fixture", + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + join(runtimeDir, "subscription-snapshot.json"), + `${JSON.stringify( + { + planLabel: "Provider Pro", + consumed: 120, + remaining: 880, + limit: 1000, + unit: "USD", + }, + null, + 2, + )}\n`, + "utf8", + ); + + try { + const run = await runNodeScript(["scripts/resident-supervisor.ts", runtimeDir], { + ...process.env, + RUN_OWNER: "pandas-owner", + SUPERVISOR_ONCE: "true", + SUPERVISOR_RESTART_MODE: "sync", + SUPERVISOR_HEARTBEAT_MAX_AGE_MS: "1000", + SUPERVISOR_MAX_RESTARTS: "2", + WORKER_STEPS: "goal-gate", + WORKER_INTERVAL_MS: "1", + WORKER_MAX_CYCLES: "3", + }); + assert.equal(run.code, 0, `supervisor failed\nstdout:\n${run.stdout}\nstderr:\n${run.stderr}`); + + const report = JSON.parse(await readFile(recoveryPath, "utf8")) as { + status?: string; + actions?: string[]; + retries?: number; + }; + assert.equal(report.status, "restarted"); + assert.equal(report.retries, 1); + assert((report.actions ?? []).includes("restart-worker")); + } finally { + await rm(runtimeDir, { recursive: true, force: true }); + } +}); + +test("dod check emits machine-readable pass/fail status", async () => { + const runtimeDir = join(PROJECT_ROOT, "runtime", `zzzz-triplet-dod-${Date.now()}`); + const dodPath = join(runtimeDir, "evidence", "dod-status.json"); + await mkdir(join(runtimeDir, "evidence"), { recursive: true }); + await writeFile( + join(runtimeDir, "goal-state.json"), + `${JSON.stringify( + { + goalId: "triplet-goal", + definitionOfDone: [], + phases: [{ id: "phase-1", status: "done" }], + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + join(runtimeDir, "evidence", "latest.json"), + `${JSON.stringify( + { + generatedAt: new Date().toISOString(), + itemId: "triplet", + completed: "baseline", + filesChanged: ["scripts/dod-check.ts"], + verification: "test", + visibleMarker: "runtime/evidence/latest.json", + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + join(runtimeDir, "evidence", "product-dod.json"), + `${JSON.stringify( + { + fullChinese: true, + nonTechnicalCopy: true, + middleSchoolReadable: true, + globalVisibility: true, + appleNativeUI: false, + realSubscriptionConnected: false, + tiApproval: false, + notes: "triplet fixture", + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + join(runtimeDir, "evidence", "worker-progress.json"), + `${JSON.stringify( + { + cycle: 1, + lastStep: { + id: "build", + exitCode: 1, + }, + }, + null, + 2, + )}\n`, + "utf8", + ); + + try { + const failed = await runNodeScript(["scripts/dod-check.ts", runtimeDir], process.env); + assert.equal(failed.code, 1); + const failStatus = JSON.parse(await readFile(dodPath, "utf8")) as { + passed?: boolean; + checks?: Array<{ id?: string; passed?: boolean }>; + }; + assert.equal(failStatus.passed, false); + assert.equal(failStatus.checks?.find((check) => check.id === "worker-last-step")?.passed, false); + + await writeFile( + join(runtimeDir, "evidence", "worker-progress.json"), + `${JSON.stringify( + { + cycle: 2, + lastStep: { + id: "build", + exitCode: 0, + }, + }, + null, + 2, + )}\n`, + "utf8", + ); + + const stillFailed = await runNodeScript(["scripts/dod-check.ts", runtimeDir], process.env); + assert.equal(stillFailed.code, 1); + const productGateStatus = JSON.parse(await readFile(dodPath, "utf8")) as { + passed?: boolean; + checks?: Array<{ id?: string; passed?: boolean }>; + }; + assert.equal(productGateStatus.passed, false); + assert.equal(productGateStatus.checks?.find((check) => check.id === "product-apple-native-ui")?.passed, false); + assert.equal( + productGateStatus.checks?.find((check) => check.id === "product-real-subscription-connected")?.passed, + false, + ); + + await writeFile( + join(runtimeDir, "evidence", "product-dod.json"), + `${JSON.stringify( + { + fullChinese: true, + nonTechnicalCopy: true, + middleSchoolReadable: true, + globalVisibility: true, + appleNativeUI: true, + realSubscriptionConnected: true, + tiApproval: false, + notes: "triplet fixture", + }, + null, + 2, + )}\n`, + "utf8", + ); + await writeFile( + join(runtimeDir, "subscription-snapshot.json"), + `${JSON.stringify( + { + planLabel: "Provider Pro", + consumed: 120, + remaining: 880, + limit: 1000, + unit: "USD", + }, + null, + 2, + )}\n`, + "utf8", + ); + + const passed = await runNodeScript(["scripts/dod-check.ts", runtimeDir], process.env); + assert.equal(passed.code, 0, `dod pass failed\nstdout:\n${passed.stdout}\nstderr:\n${passed.stderr}`); + const passStatus = JSON.parse(await readFile(dodPath, "utf8")) as { passed?: boolean }; + assert.equal(passStatus.passed, true); + } finally { + await rm(runtimeDir, { recursive: true, force: true }); + } +}); + +async function runNodeScript( + args: string[], + env: NodeJS.ProcessEnv, +): Promise<{ code: number | null; stdout: string; stderr: string }> { + return await new Promise((resolvePromise, rejectPromise) => { + const child = spawn(process.execPath, ["--import", "tsx", ...args.map((value) => resolve(PROJECT_ROOT, value))], { + cwd: PROJECT_ROOT, + env, + stdio: ["ignore", "pipe", "pipe"], + }); + let stdout = ""; + let stderr = ""; + child.stdout.on("data", (chunk) => { + stdout += String(chunk); + }); + child.stderr.on("data", (chunk) => { + stderr += String(chunk); + }); + child.on("error", rejectPromise); + child.on("close", (code) => { + resolvePromise({ code, stdout, stderr }); + }); + }); +} diff --git a/test/ui-language-preferences.test.ts b/test/ui-language-preferences.test.ts new file mode 100644 index 0000000..178e004 --- /dev/null +++ b/test/ui-language-preferences.test.ts @@ -0,0 +1,46 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { readFile, rm, writeFile } from "node:fs/promises"; +import { + UI_PREFERENCES_PATH, + defaultUiPreferences, + loadUiPreferences, + saveUiPreferences, +} from "../src/runtime/ui-preferences"; + +test("ui language preference persists after save and reload", async () => { + const original = await readMaybe(UI_PREFERENCES_PATH); + + try { + await saveUiPreferences({ + ...defaultUiPreferences(), + language: "zh", + updatedAt: new Date().toISOString(), + }); + + const loaded = await loadUiPreferences(); + assert.equal(loaded.preferences.language, "zh"); + } finally { + if (original === undefined) { + await rm(UI_PREFERENCES_PATH, { force: true }); + } else { + await writeFile(UI_PREFERENCES_PATH, original, "utf8"); + } + } +}); + +async function readMaybe(path: string): Promise { + try { + return await readFile(path, "utf8"); + } catch (error) { + if ( + error && + typeof error === "object" && + "code" in error && + (error as { code?: unknown }).code === "ENOENT" + ) { + return undefined; + } + throw error; + } +} diff --git a/test/ui-render-smoke.test.ts b/test/ui-render-smoke.test.ts new file mode 100644 index 0000000..b930e31 --- /dev/null +++ b/test/ui-render-smoke.test.ts @@ -0,0 +1,703 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { readFile } from "node:fs/promises"; +import type { AuditTimelineSnapshot } from "../src/runtime/audit-timeline"; +import type { SessionConversationDetailResult } from "../src/runtime/session-conversations"; +import type { ReadModelSnapshot } from "../src/types"; + +test("session drilldown page renders without network and escapes content", async () => { + const { renderSessionDrilldownPageForSmoke } = await import("../src/ui/server"); + + const detail: SessionConversationDetailResult = { + generatedAt: "2026-03-03T09:00:00.000Z", + session: { + sessionKey: "sess-1", + label: "Primary Session", + agentId: "agent-alpha", + state: "running", + lastMessageAt: "2026-03-03T08:59:00.000Z", + }, + status: { + sessionKey: "sess-1", + model: "gpt-test", + tokensIn: 10, + tokensOut: 20, + cost: 0.01, + updatedAt: "2026-03-03T08:59:30.000Z", + }, + latestSnippet: "latest", + latestRole: "assistant", + latestKind: "message", + latestToolName: undefined, + latestHistoryAt: "2026-03-03T08:59:00.000Z", + historyCount: 2, + historyError: undefined, + executionChain: { + accepted: true, + spawned: true, + acceptedAt: "2026-03-03T08:58:10.000Z", + spawnedAt: "2026-03-03T08:58:20.000Z", + parentSessionKey: "sess-parent", + childSessionKey: "sess-1", + stage: "running", + source: "history", + inferred: false, + detail: "accepted=yes | spawned=yes | parent=sess-parent | child=sess-1", + }, + history: [ + { + kind: "accepted", + role: "system", + content: "accepted request", + timestamp: "2026-03-03T08:58:10.000Z", + }, + { + kind: "message", + role: "user", + content: "render this ", + timestamp: "2026-03-03T08:58:00.000Z", + }, + { + kind: "tool_event", + role: "tool", + content: "tool output ok", + timestamp: "2026-03-03T08:59:00.000Z", + toolName: "openclaw.approvals.get", + toolStatus: "ok", + }, + ], + }; + + const html = renderSessionDrilldownPageForSmoke(detail); + assert(html.includes("Session Drilldown")); + assert(html.includes("Execution Chain")); + assert(html.includes("Latest Messages / Tool Events")); + assert(html.includes("/api/sessions/sess-1?historyLimit=120")); + assert(html.includes("parent=sess-parent child=sess-1")); + assert(html.includes("Accepted")); + assert(html.includes("Spawned")); + assert(html.includes("<script>alert(1)</script>")); + assert(!html.includes("")); + + const zh = renderSessionDrilldownPageForSmoke(detail, "zh"); + assert(zh.includes("会话详情")); + assert(zh.includes("执行链")); + assert(zh.includes("最近消息 / 工具事件")); + assert(zh.includes("返回总览")); +}); + +test("audit timeline page renders without network and keeps severity selection", async () => { + const { renderAuditPageForSmoke } = await import("../src/ui/server"); + + const timeline: AuditTimelineSnapshot = { + generatedAt: "2026-03-03T09:10:00.000Z", + counts: { + info: 0, + warn: 1, + "action-required": 0, + error: 0, + }, + events: [ + { + timestamp: "2026-03-03T09:09:00.000Z", + severity: "warn", + source: "monitor", + message: "timeline marker", + }, + ], + }; + + const html = renderAuditPageForSmoke(timeline, "warn"); + assert(html.includes("OpenClaw Control Center Audit Timeline")); + assert(html.includes("

    Audit Timeline

    ")); + assert(html.includes('value="warn" selected')); + assert(html.includes("timeline <unsafe> marker")); + assert(!html.includes("timeline marker")); +}); + +test("dashboard section navigation renders required tabs with active state", async () => { + const { renderDashboardSectionNavForSmoke } = await import("../src/ui/server"); + + const en = renderDashboardSectionNavForSmoke("team", "en"); + assert(en.includes("Overview")); + assert(en.includes("Staff")); + assert(en.includes("Memory")); + assert(en.includes("Documents")); + assert(en.includes("Usage")); + assert(en.includes("Tasks")); + assert(en.includes("Settings")); + assert(en.includes('aria-current="page"')); + assert(en.includes("/?section=team")); + assert(en.indexOf("Overview") < en.indexOf("Usage")); + assert(en.indexOf("Usage") < en.indexOf("Staff")); + assert(!en.includes("Executors")); + assert(!en.includes("Calendar")); + assert(!en.includes("Attention")); + assert(!en.includes("History")); + + const zh = renderDashboardSectionNavForSmoke("team", "zh"); + assert(zh.includes("总览")); + assert(zh.includes("员工")); + assert(zh.includes("记忆")); + assert(zh.includes("文档")); + assert(zh.includes("用量")); + assert(zh.includes("任务")); + assert(zh.includes("设置")); + assert(zh.indexOf("总览") < zh.indexOf("用量")); + assert(zh.indexOf("用量") < zh.indexOf("员工")); + assert(!zh.includes("智能体")); + assert(!zh.includes("日历")); + assert(!zh.includes("待处理")); + assert(!zh.includes("历史")); +}); + +test("legacy mission-control routes resolve to dashboard sections", async () => { + const { resolveLegacyDashboardSectionForSmoke, resolveDashboardSection } = await import("../src/ui/server"); + + assert.equal(resolveLegacyDashboardSectionForSmoke("/calendar"), "projects-tasks"); + assert.equal(resolveLegacyDashboardSectionForSmoke("/heartbeat"), "overview"); + assert.equal(resolveLegacyDashboardSectionForSmoke("/tools"), "settings"); + assert.equal(resolveLegacyDashboardSectionForSmoke("/not-a-route"), undefined); + assert.equal(resolveDashboardSection(new URLSearchParams("section=alerts")), "overview"); + assert.equal(resolveDashboardSection(new URLSearchParams("section=replay-audit")), "overview"); +}); + +test("tasks section includes merged schedule and board content", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + assert(source.includes('
    ')); + assert(source.includes('id="task-execution-chain"')); + assert(source.includes('id="task-timeline"')); + assert(source.includes('t("Today and next schedule", "今日与下一批排程")')); + assert(source.includes('
    ')); + assert(source.includes('id="task-decision-center"')); + assert(source.includes('
    ')); + assert(source.includes('
    ')); + assert(source.includes('t("Execution chain", "执行链")')); + assert(source.includes('Accepted and spawned child sessions')); + assert(source.includes('if (options.section === "calendar") sectionBody = projectsSection;')); +}); + +test("global visibility card keeps plain-language EN/ZH copy for four key signals", async () => { + const { renderGlobalVisibilityCardForSmoke } = await import("../src/ui/server"); + + const en = renderGlobalVisibilityCardForSmoke("en"); + assert(en.includes("Global Visibility")); + assert(en.includes("One place to see timed jobs, heartbeat, current tasks, and tool calls.")); + assert(en.includes("Timed jobs:")); + assert(en.includes("Heartbeat checks:")); + assert(en.includes("Current tasks:")); + assert(en.includes("Tool calls:")); + assert(en.includes("Timed jobs are on.")); + assert(en.includes("Heartbeat is on.")); + assert(en.includes("Active timed jobs: 1.")); + assert(en.includes("Active heartbeat checks: 1.")); + assert(en.includes('/?compact=1&section=overview&lang=en&quick=all#cron-health')); + assert(en.includes('/?compact=1&section=overview&lang=en&quick=all#heartbeat-health')); + assert(en.includes('/?compact=1&section=projects-tasks&lang=en&quick=all#task-lane')); + assert(en.includes('/?compact=1&section=overview&lang=en&quick=all#tool-activity')); + assert(!en.includes('href="/cron"')); + assert(!en.includes('href="/sessions"')); + + const zh = renderGlobalVisibilityCardForSmoke("zh"); + assert(zh.includes("全局总览")); + assert(zh.includes("一眼看四件事:定时任务、任务心跳、当前任务、工具调用。")); + assert(zh.includes("定时任务:")); + assert(zh.includes("任务心跳:")); + assert(zh.includes("当前任务:")); + assert(zh.includes("工具调用:")); + assert(zh.includes("定时任务正在运行。")); + assert(zh.includes("任务心跳已开启。")); + assert(zh.includes("已开启定时任务:1 个。")); + assert(zh.includes("已开启任务心跳:1 个。")); + assert(!zh.includes("Global Visibility")); + assert(!zh.includes("Schedule checks (cron):")); + assert(!zh.includes("Heartbeat checks:")); + assert(!zh.includes("Tasks in progress:")); + assert(zh.includes('/?compact=1&section=overview&lang=zh&quick=all#cron-health')); + assert(zh.includes('/?compact=1&section=overview&lang=zh&quick=all#heartbeat-health')); + assert(zh.includes('/?compact=1&section=projects-tasks&lang=zh&quick=all#task-lane')); + assert(zh.includes('/?compact=1&section=overview&lang=zh&quick=all#tool-activity')); + assert(!zh.includes('href="/cron"')); + assert(!zh.includes('href="/sessions"')); +}); + +test("overview and task certainty lean on runtime evidence instead of manual due or blocked fields", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + const commanderSource = await readFile("src/runtime/commander.ts", "utf8"); + + assert(source.includes('const pendingDecisionCount = actionQueue.counts.unacked;')); + assert(source.includes("const sessionErrorCount = exceptions.errors.length;")); + assert(source.includes('const sessionBlockedCount = exceptions.blocked.filter((session) => session.state === "blocked").length;')); + assert(source.includes('const stalledRunningSessionCount = countStalledRunningSessions(')); + assert(source.includes('t("Review queue", "审阅队列")')); + assert(source.includes('t("Runtime issues", "运行异常")')); + assert(source.includes('t("Stalled runs", "停滞执行")')); + assert(source.includes('pickUiText(input.language, "No execution session is linked yet.", "还没有关联执行会话。")')); + assert(source.includes('pickUiText(input.language, "A linked session is blocked.", "有会话已经进入阻塞状态。")')); + assert(!source.includes('const pendingDecisionCount = actionQueue.counts.unacked + pendingApprovalsCount;')); + assert(!source.includes('const sessionErrorCount = snapshot.sessions.filter((session) => session.state === "error").length;')); + assert(!source.includes('if (task.dueAt) score += 8;')); + assert(!source.includes('if (task.status === "blocked") score -= 18;')); + assert(!source.includes('if (overdue) score -= 18;')); + assert(commanderSource.includes("const CURRENT_RUNTIME_ISSUE_WINDOW_MS = 6 * 60 * 60 * 1000;")); + assert(commanderSource.includes("isFreshRuntimeIssueSession(s.lastMessageAt, nowMs)")); +}); + +test("execution chain cards keep raw JSON out of visible titles and summaries", async () => { + const { renderTaskExecutionChainCardsForSmoke } = await import("../src/ui/server"); + const source = await readFile("src/ui/server.ts", "utf8"); + + const zh = renderTaskExecutionChainCardsForSmoke("zh"); + assert(zh.includes("Main · Cron 隔离执行")); + assert(zh.includes("失败 · 错误 locked")); + assert(zh.includes("成功 · 查询 30 · 成功 2 · 入选 2 · 发送 2")); + assert(zh.includes("已接单 · 已派发 · 会话键推断 · 推断值")); + assert(zh.includes('class="execution-chain-context"')); + assert(zh.includes('class="execution-chain-flow"')); + assert(zh.includes('class="execution-chain-summary"')); + assert(!zh.includes('{"ok":true')); + assert(!zh.includes('{"ok":false')); + assert(!zh.includes('"attemptedQueries":30')); + assert(!zh.includes('"error":"locked"')); + assert(!zh.includes("accepted=yes | spawned=yes")); + assert(source.includes("grid-template-columns: repeat(auto-fit, minmax(min(100%, 520px), 1fr));")); + assert(source.includes(".execution-chain-context {")); + assert(source.includes(".execution-chain-flow {")); + assert(source.includes(".execution-chain-summary {")); +}); + +test("dashboard keeps global visibility as overview-only block", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + const usageSource = await readFile("src/runtime/usage-cost.ts", "utf8"); + assert(source.includes('data-ui-polish="apple-native-v3"')); + assert(source.includes("const globalVisibilityCard = renderGlobalVisibilityCard(globalVisibilityModel, options.language);")); + assert(source.includes("const globalVisibilityQuickRows = [")); + assert(source.includes("const sidebarSignalRows =")); + assert( + source.includes( + "const globalVisibilityBlock = options.section === \"overview\" ? globalVisibilityCard : \"\";", + ), + ); + assert(source.includes('
    ${globalVisibilityBlock}${sectionBody}
    ')); + assert(source.includes("heartbeat: enabledHeartbeatCount")); + assert(source.includes("const toolCallsCount = input.toolCallsCount ?? (await countRecentToolCalls(snapshot, toolClient));")); + assert(source.includes("if (typeof item.toolEventCount === \"number\") return sum + item.toolEventCount;")); + assert(source.includes("const scheduleSignalText = scheduleRow?.currentAction ?? noSignalText;")); + assert(source.includes("${escapeHtml(scheduleSignalText)}")); + assert(source.includes('const language: UiLanguage = hasExplicitLanguage ? resolvedLanguage : "zh";')); + assert(!source.includes("const recentToolCallsCount = sessionPreview.items.filter((item) => item.latestKind === \"tool_event\").length;")); + assert(source.includes("const languageToggle = renderLanguageToggle(filters, options);")); + assert(source.includes("${languageToggle}")); + assert(source.includes('
    ')); + assert(source.includes('id="overview-decision-center"')); + assert(source.includes('id="overview-busy-staff"')); + assert(source.includes('id="overview-runtime-checkpoint"')); + assert(source.includes('t("Isolated execution", "隔离执行")')); + assert(source.includes('Accepted and spawned child sessions')); + assert(source.includes("${sidebarSignalRows}")); + assert(source.includes("Open current tasks")); + assert(source.includes("查看当前任务")); + assert(source.includes("Open follow-up items")); + assert(source.includes("查看待处理")); + assert(source.includes("formatSeconds(job.dueInSeconds, options.language)")); + assert(!source.includes("formatSeconds(job.dueInSeconds))")); + assert(source.includes("const spriteBoundsCache = new Map();")); + assert(source.includes("const computeSpriteBounds = (sprite) => {")); + assert(source.includes("Recommended data connections")); + assert(!source.includes("const informationCertaintyCard = renderInformationCertaintyCard(informationCertainty, options.language);")); + assert(!source.includes("const taskCertaintySection = renderTaskCertaintySection(taskCertaintyCards, options.language);")); + assert(!source.includes("${informationCertaintyCard}")); + assert(!source.includes("${taskCertaintySection}")); + assert(source.includes('const usageCostMode: UsageCostMode = "full";')); + assert(source.includes("loadCachedUsageCost(snapshot, usageCostMode)")); + assert(source.includes("loadCachedOfficeSessionPresence()")); + assert(source.includes("loadCachedTaskEvidenceSessions(")); + assert(source.includes("const taskSignalItems = mergeSessionConversationItems(taskEvidenceItems, sessionPreview.items);")); + assert(source.includes("const liveSessionCount = officePresence.totalActiveSessions;")); + assert(source.includes("buildTaskDetailHref(task.taskId, input.language)")); + assert(source.includes('const language = resolveUiLanguage(url.searchParams, "zh");')); + assert(source.includes('buildUsageCostSnapshot(snapshot, mode)')); + assert(source.includes('const needsSessionPreview = activeSection === "projects-tasks" || activeSection === "overview";')); + assert(source.includes("const allApprovals = [...(snapshot.approvals ?? [])].sort(compareApprovals);")); + assert(source.includes('const pendingApprovalsCount = allApprovals.filter((item) => item.status === "pending").length;')); + assert(source.includes("replayPreview.stats.timeline.total")); + assert(source.includes('t("Replay activity", "活动回放")')); + assert(source.includes('t("Approval requests", "审批请求")')); + assert(source.includes('route: "/?section=projects-tasks&quick=attention#task-lane"')); + assert(source.includes('route: "/audit"')); + assert(source.includes('route: "/digest/latest"')); + assert(source.includes("void primeUiRenderCaches(toolClient);")); + assert(source.includes("const sourceStamp = await readReadModelSourceStamp();")); + assert(source.includes("const sessions = mapSessionsListToSummaries(live);")); + assert(!source.includes('state: item.active ? "running" : "idle"')); + assert(usageSource.includes("const USAGE_SOURCE_CACHE_TTL_MS = 10_000;")); + assert(usageSource.includes("loadCachedRuntimeUsageData()")); + assert(usageSource.includes("loadCachedSubscriptionUsage()")); + assert(source.includes('t("See four signals in overview", "在总览查看四项信号")')); + assert(source.includes('t("Data source not connected", "数据源未连接")')); + assert(source.includes('t("Recent usage", "近期用量")')); + assert(!source.includes("task.sessionKeys.slice(0, 6)")); + assert(source.includes("确定性判断")); +}); + +test("heartbeat API routes are implemented in UI server", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + assert(source.includes('if (method === "GET" && path === "/api/tasks/heartbeat")')); + assert(source.includes('if (method === "POST" && path === "/api/tasks/heartbeat")')); + assert(source.includes("runTaskHeartbeat({ gate })")); +}); + +test("usage dashboard includes token type share and cron token share sections", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + assert(source.includes("AI 用量构成(全部会话)")); + assert(source.includes("定时任务用量占比")); + assert(source.includes("定时任务内各智能体占比")); + assert(source.includes("usage_view")); + assert(source.includes("今天")); + assert(source.includes("累计")); + assert(source.includes("定时任务、Discord、Telegram、内部会话")); + assert(source.includes("renderTokenShareRows(")); + assert(source.includes("usageCost.breakdownToday")); + assert(source.includes("selectedUsageBreakdown.bySessionType")); + assert(source.includes("selectedUsageBreakdown.byCronJob")); + assert(source.includes("selectedUsageBreakdown.byCronAgent")); +}); + +test("memory and workspace sections expose editable file workbenches", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + assert(source.includes("/api/files")); + assert(source.includes("/api/files/content")); + assert(source.includes("scope must be one of: memory, workspace")); + assert(source.includes('title: t("Memory file workbench", "记忆文件工作台")')); + assert(source.includes('Main ${escapeHtml(t("memories", "记忆"))}')); + assert(source.includes('${escapeHtml(t("Available views", "可切换查看"))}')); + assert(source.includes('const agentProfileFiles = ["MEMORY.md"];')); + assert(!source.includes('const agentProfileFiles = ["MEMORY.md", "USER.md", "SOUL.md", "IDENTITY.md"];')); + assert(source.includes("listMemoryFacetOptions()")); + assert(source.includes("listWorkspaceFacetOptions()")); + assert(source.includes("facetOptions: memoryFacetOptions")); + assert(source.includes("facetOptions: workspaceFacetOptions")); + assert(source.includes("defaultFacetKey: \"main\"")); + assert(source.includes("defaultFacetKey: \"main\"")); + assert(source.includes("includeAllFacet: false")); + assert(source.includes("data-default-facet")); + assert(source.includes(".file-nav-item[hidden]")); + assert(source.includes("item.style.display = visible ? \"\" : \"none\";")); + assert(source.includes("currentGroup")); + assert(source.includes("可在左侧选择具体文件")); + assert(source.includes("data-file-facet")); + assert(source.includes("const normalizeFacetKey = (value) => String(value || 'all').trim().toLowerCase() || 'all';")); + assert(source.includes(".segment-switch {")); + assert(source.includes("display: inline-flex;")); + assert(source.includes("flex-wrap: wrap;")); + assert(source.includes(".segment-item {")); + assert(source.includes("appearance: none;")); + assert(source.includes("border: none;")); + assert(source.includes("background: transparent;")); + assert(source.includes("min-height: 40px;")); + assert(source.includes(".file-facet-switch .segment-item {")); + assert(source.includes(".file-facet-switch .segment-item.active {")); + assert(source.includes("文档工作台")); + assert(source.includes("文档概览")); + assert(source.includes('t("Main documents", "Main 文档")')); + assert(source.includes("核心 Markdown")); + assert(source.includes("不再按会话历史展示文档")); + assert(source.includes("resolveEditableAgentScopesFromConfig(")); + assert(source.includes("loadEditableAgentScopesFromConfig()")); + assert(source.includes("loadEditableAgentScopesFromWorkspaceDirs()")); + assert(source.includes("data-quota-reset-at")); + assert(source.includes("renderQuotaResetScript()")); + assert(source.includes("new Intl.DateTimeFormat(undefined")); + assert(source.includes("OPENCLAW_WORKSPACE_ROOT")); + assert(source.includes("SHARED_DOCUMENT_FILE_CANDIDATES")); + assert(source.includes("AGENT_DOCUMENT_FILE_CANDIDATES")); + assert(source.includes("保存后会直接写回源文件")); + assert(source.includes("renderFileWorkbenchScript()")); + assert(source.includes('t("Staff overview", "员工总览")')); + assert(source.includes('t("The default view shows only name, role, current status, current work, recent output, and whether each person is on the schedule."')); + assert(source.includes("async function resolveStaffRoleLabel(")); + assert(source.includes('return pickUiText(language, "YouTube to article writing", "YouTube 视频转长文");')); + assert(source.includes('return pickUiText(language, "High-value content creation", "高价值内容创作");')); + assert(source.includes('return pickUiText(language, "Control Center delivery", "控制中心开发与交付");')); + assert(source.includes('return pickUiText(language, "Daily news and trend briefings", "每日情报与趋势简报");')); + assert(source.includes('return pickUiText(language, "Personal assistance and reminders", "私人助理与提醒");')); + assert(source.includes('return pickUiText(language, "Security and updates", "安全和更新");')); + assert(source.includes('return pickUiText(language, "Role not defined in workspace", "工作区未写明职责");')); + assert(source.includes('function staffStatusLabel(')); + assert(source.includes('pickUiText(language, "Status", "当前状态")')); + assert(source.includes('pickUiText(language, "Working on", "正在处理什么")')); + assert(source.includes('pickUiText(language, "Recent output", "最近产出")')); + assert(source.includes('pickUiText(language, "In schedule", "是否在排班里")')); + assert(source.includes('const staffOverviewCards = needsTeamSnapshot')); + assert(source.includes(".staff-brief-grid {\n margin-top: 12px;\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));")); + assert(source.includes('')); + assert(source.includes("querySelectorAll('.agent-avatar, .staff-avatar')")); + assert(source.includes('data-animal="${escapeHtml(card.identity.animal)}"')); + assert(source.includes('t("Shared staff mission", "员工共同目标")')); + assert(source.includes('t("Staff system details", "员工配置明细")')); + assert(source.includes("renderOfficeCards(")); + assert(source.includes("no network polling and no extra token usage")); + assert(source.includes("window.requestAnimationFrame(step);")); + assert(source.includes("headers[\"cache-control\"] = \"no-store, no-cache, must-revalidate, max-age=0\";")); + assert(source.includes("headers.pragma = \"no-cache\";")); + assert(source.includes("headers.expires = \"0\";")); + assert(!source.includes('return pickUiText(language, "Fast execution", "快速推进");')); + assert(!source.includes('return pickUiText(language, "Planning and organization", "排程与整理");')); + assert(!source.includes("Workspace 文件工作台")); + assert(!source.includes("聊天输出结构化入库(")); + assert(!source.includes("办公室 2D 实况")); + assert(!source.includes("完整智能体名录(")); + assert(!source.includes("office-scene-stage")); + assert(!source.includes("zone-watercooler")); +}); + +test("editable agent scopes follow configured agents before workspace folders", async () => { + const { + resolveEditableAgentScopesFromConfigForSmoke, + resolveEditableAgentScopesWithFallbackForSmoke, + } = await import("../src/ui/server"); + + const scopes = resolveEditableAgentScopesFromConfigForSmoke({ + agents: { + list: [ + { id: "pandas", workspace: "/tmp/pandas" }, + { id: "tiger", workspace: "/tmp/tiger" }, + ], + }, + }); + + assert.deepEqual( + scopes.map((item) => item.facetKey), + ["main", "pandas", "tiger"], + ); + assert.equal(scopes[0]?.facetLabel, "Main"); + assert(!scopes.some((item) => item.facetKey === "dolphin")); + assert(!scopes.some((item) => item.facetKey === "mission-ops")); + + const guardedScopes = resolveEditableAgentScopesWithFallbackForSmoke({ + configText: "{not-json", + workspaceAgentIds: ["dolphin", "mission-ops", "pandas"], + }); + assert.deepEqual( + guardedScopes.map((item) => item.facetKey), + ["main"], + ); +}); + +test("search helpers keep total matches separate from returned rows", async () => { + const { buildDashboardSearchResultForSmoke } = await import("../src/ui/server"); + + const snapshot: ReadModelSnapshot = { + sessions: [ + { + sessionKey: "sess-alpha-1", + label: "Alpha One", + agentId: "panda", + state: "running", + lastMessageAt: "2026-03-10T10:00:00.000Z", + }, + { + sessionKey: "sess-alpha-2", + label: "Alpha Two", + agentId: "tiger", + state: "idle", + lastMessageAt: "2026-03-10T09:00:00.000Z", + }, + ], + statuses: [], + cronJobs: [], + approvals: [], + projects: { + updatedAt: "2026-03-10T10:00:00.000Z", + projects: [ + { + projectId: "proj-alpha", + title: "Alpha rollout", + status: "active", + owner: "panda", + updatedAt: "2026-03-10T10:00:00.000Z", + }, + ], + }, + projectSummaries: [], + tasks: { + updatedAt: "2026-03-10T10:00:00.000Z", + agentBudgets: [], + tasks: [ + { + projectId: "proj-alpha", + taskId: "task-alpha-1", + title: "Alpha first", + status: "todo", + owner: "panda", + definitionOfDone: [], + artifacts: [], + rollback: { strategy: "none", steps: [] }, + sessionKeys: ["sess-alpha-1"], + budget: {}, + updatedAt: "2026-03-10T10:00:00.000Z", + }, + { + projectId: "proj-alpha", + taskId: "task-alpha-2", + title: "Alpha second", + status: "blocked", + owner: "tiger", + definitionOfDone: [], + artifacts: [], + rollback: { strategy: "none", steps: [] }, + sessionKeys: ["sess-alpha-2"], + budget: {}, + updatedAt: "2026-03-10T10:01:00.000Z", + }, + ], + }, + tasksSummary: { + projects: 1, + tasks: 2, + todo: 1, + inProgress: 0, + blocked: 1, + done: 0, + owners: 2, + artifacts: 0, + }, + budgetSummary: { total: 0, ok: 0, warn: 0, over: 0, evaluations: [] }, + generatedAt: "2026-03-10T10:05:00.000Z", + }; + + const taskResult = buildDashboardSearchResultForSmoke(snapshot, { scope: "tasks", q: "alpha", limit: 1 }); + assert(taskResult); + assert.equal(taskResult.count, 2); + assert.equal(taskResult.returned, 1); + + const sessionResult = buildDashboardSearchResultForSmoke(snapshot, { + scope: "sessions", + q: "alpha", + limit: 1, + }); + assert(sessionResult); + assert.equal(sessionResult.count, 2); + assert.equal(sessionResult.returned, 1); +}); + +test("search APIs advertise total match counts and bounded returned rows", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + const apiDocsSource = await readFile("src/runtime/api-docs.ts", "utf8"); + + assert(source.includes("count: matches.length,")); + assert(source.includes("returned: tasks.length,")); + assert(source.includes("returned: projects.length,")); + assert(source.includes("returned: sessions.length,")); + assert(source.includes("returned: items.length,")); + assert(source.includes('const snapshot = await readReadModelSnapshotWithLiveSessions(toolClient);')); + assert(source.includes("function buildBoundedSearchResult(items: T[], limit: number): {")); + assert(apiDocsSource.includes('count: "number (total matches before limit)"')); + assert(apiDocsSource.includes('returned: "number (items returned in this response)"')); + assert(apiDocsSource.includes('count: "number (total matches before limit, including live-merged sessions)"')); +}); + +test("import live input turns invalid file paths into validation errors", async () => { + const { resolveImportInputForSmoke } = await import("../src/runtime/import-live"); + + const result = await resolveImportInputForSmoke({ fileName: "../outside.json" }); + assert.equal(result.ok, false); + assert.equal(result.validation.valid, false); + assert.match(result.validation.issues[0] ?? "", /outside runtime exports directory/i); +}); + +test("session links stay on the session detail UI and docs index accepts language", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + + assert(source.includes('function buildSessionDetailHref(sessionKey: string, language: UiLanguage): string {')); + assert(source.includes('const language = resolveUiLanguage(url.searchParams, "zh");')); + assert(source.includes('const html = renderSessionDrilldownPage(detail, language);')); + assert(source.includes('assertAllowedQueryParams(url.searchParams, ["lang"], true);')); + assert(source.includes('Open document workbench')); + assert(source.includes('Back to control center')); + assert(!source.includes('href="/sessions/${encodeURIComponent(item.sessionKey)}"')); + assert(source.includes('Available views", "可切换查看"))}${escapeHtml(options.language === "en" ? ": " : ":")}')); + assert(source.includes('function joinDisplayList(items: string[], language: UiLanguage): string {')); +}); + +test("navigation script does not add artificial leave delay", async () => { + const source = await readFile("src/ui/server.ts", "utf8"); + assert(source.includes("window.location.href = href;")); + assert(!source.includes("window.setTimeout(() => {\n window.location.href = href;\n }, 120);")); +}); + +test("agent animal identity mapping is semantic-first and deterministic", async () => { + const { deriveAgentAnimalIdentity } = await import("../src/ui/server"); + + const codex = deriveAgentAnimalIdentity("codex"); + assert.equal(codex.animal, "robot"); + + const panda = deriveAgentAnimalIdentity("pandas-control"); + assert.equal(panda.animal, "panda"); + + const leader = deriveAgentAnimalIdentity("main"); + assert.equal(leader.animal, "lion"); + + const otter = deriveAgentAnimalIdentity("otter"); + assert.equal(otter.animal, "otter"); + + const rooster = deriveAgentAnimalIdentity("coq"); + assert.equal(rooster.animal, "rooster"); + + const tiger = deriveAgentAnimalIdentity("tiger"); + assert.equal(tiger.animal, "tiger"); + + const fallbackA = deriveAgentAnimalIdentity("zxq-agent-42"); + const fallbackB = deriveAgentAnimalIdentity("zxq-agent-42"); + assert.equal(fallbackA.animal, fallbackB.animal); + assert.equal(typeof fallbackA.title, "string"); + assert.notEqual(fallbackA.title, ""); +}); + +test("subscription card renders explicit unavailable states for missing fields", async () => { + const { renderSubscriptionStatusCardForSmoke } = await import("../src/ui/server"); + + const html = renderSubscriptionStatusCardForSmoke({ + status: "partial", + planLabel: "Pro Monthly", + unit: "USD", + detail: "Partial billing fields available.", + connectHint: "Provide subscription snapshot path.", + }); + + assert(html.includes("Pro Monthly")); + assert(html.includes("Used Unavailable: subscription data is missing "consumed"")); + assert(html.includes("Remaining Unavailable: subscription data is missing "remaining"")); + assert(html.includes("Unavailable: subscription data is missing "limit"")); + assert(html.includes("Cycle")); + assert(html.includes("Not provided")); +}); + +test("subscription card normalizes near-week minute labels before rendering", async () => { + const { renderSubscriptionStatusCardForSmoke } = await import("../src/ui/server"); + + const html = renderSubscriptionStatusCardForSmoke({ + status: "connected", + planLabel: "Codex Live", + unit: "%", + detail: "Live Codex rate limits.", + connectHint: "", + consumed: 2, + remaining: 98, + limit: 100, + usagePercent: 2, + primaryWindowLabel: "300m", + primaryUsedPercent: 2, + primaryRemainingPercent: 98, + primaryResetAt: "2026-03-11T11:30:05.000Z", + secondaryWindowLabel: "10081m", + secondaryUsedPercent: 1, + secondaryRemainingPercent: 99, + secondaryResetAt: "2026-03-18T06:31:05.000Z", + }); + + assert(html.includes(">5h<")); + assert(html.includes(">Week<")); + assert(!html.includes(">300m<")); + assert(!html.includes(">10081m<")); +}); diff --git a/test/usage-cost.test.ts b/test/usage-cost.test.ts new file mode 100644 index 0000000..37d92a0 --- /dev/null +++ b/test/usage-cost.test.ts @@ -0,0 +1,532 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import type { ReadModelSnapshot } from "../src/types"; + +test("usage-cost snapshot marks disconnected sources with explicit placeholders", async () => { + const { computeUsageCostSnapshot } = await import("../src/runtime/usage-cost"); + const snapshot = buildSnapshotFixture(); + + const usage = computeUsageCostSnapshot(snapshot, [], []); + const today = usage.periods.find((item) => item.key === "today"); + + assert(today, "Expected today usage period."); + assert.equal(today.requestCountStatus, "not_connected"); + assert.equal(usage.contextWindows[0]?.thresholdState, "not_connected"); + assert.equal(usage.budget.status, "not_connected"); + assert(usage.connectors.todos.some((item) => item.id === "request_counter")); + assert(usage.connectors.todos.some((item) => item.id === "context_catalog")); +}); + +test("usage-cost snapshot computes context percent and burn-rate status when sources exist", async () => { + const { computeUsageCostSnapshot } = await import("../src/runtime/usage-cost"); + const snapshot = buildSnapshotFixture({ + model: "gpt-4o", + tokensIn: 64000, + tokensOut: 6000, + cost: 30, + costLimit: 100, + }); + const todayIso = new Date().toISOString().slice(0, 10); + + const usage = computeUsageCostSnapshot( + snapshot, + [ + { + date: todayIso, + usage: { + statuses: 1, + totalTokensIn: 64000, + totalTokensOut: 6000, + totalCost: 90, + }, + }, + ], + [{ match: "gpt-4o", contextWindowTokens: 128000, provider: "OpenAI" }], + ); + + assert.equal(usage.contextWindows[0]?.dataStatus, "connected"); + assert.equal(Math.round(usage.contextWindows[0]?.usagePercent ?? 0), 55); + assert.equal(usage.budget.status, "warn"); + assert.equal(usage.connectors.modelContextCatalog, "connected"); + assert.equal(usage.periods.find((item) => item.key === "today")?.sourceStatus, "connected"); +}); + +test("usage-cost snapshot uses runtime session events for real requests, trends, and breakdown rows", async () => { + const { computeUsageCostSnapshot } = await import("../src/runtime/usage-cost"); + const snapshot = buildSnapshotFixture({ + model: "gpt-5.3-codex", + tokensIn: 64000, + tokensOut: 6000, + cost: 10, + costLimit: 50, + }); + + const now = Date.now(); + const usage = computeUsageCostSnapshot(snapshot, [], [], { + sourceStatus: "connected", + sessionContexts: [ + { + sessionKey: "s-1", + sessionId: "sid-1", + agentId: "pandas", + model: "gpt-5.3-codex", + provider: "OpenAI", + contextWindowTokens: 100000, + }, + ], + events: [ + runtimeEvent(now, 1000, 1), + runtimeEvent(now - 2 * 60 * 60 * 1000, 2000, 2), + runtimeEvent(now - 1 * 24 * 60 * 60 * 1000, 4000, 3), + runtimeEvent(now - 8 * 24 * 60 * 60 * 1000, 5000, 4), + ], + }); + + const today = usage.periods.find((item) => item.key === "today"); + const seven = usage.periods.find((item) => item.key === "7d"); + const thirty = usage.periods.find((item) => item.key === "30d"); + assert(today && seven && thirty); + + assert.equal(today.tokens, 3000); + assert.equal(today.requestCount, 2); + assert.equal(today.requestCountStatus, "connected"); + assert.equal(seven.tokens, 7000); + assert.equal(seven.requestCount, 3); + assert.equal(thirty.tokens, 12000); + assert.equal(thirty.requestCount, 4); + + assert.equal(usage.contextWindows[0]?.dataStatus, "connected"); + assert.equal(Math.round(usage.contextWindows[0]?.usagePercent ?? 0), 70); + assert.equal(usage.breakdown.byAgent[0]?.label, "pandas"); + assert.equal(usage.breakdown.byAgent[0]?.requests, 4); + assert.equal(usage.breakdown.byTask[0]?.label, "p1/t1 · pandas · session"); + assert.equal(usage.breakdown.byTask[0]?.tokens, 12000); + assert.equal(usage.breakdown.byTask[0]?.requests, 4); + assert.equal(usage.breakdownToday.byAgent[0]?.label, "pandas"); + assert.equal(usage.breakdownToday.byAgent[0]?.tokens, 3000); + assert.equal(usage.breakdownToday.byAgent[0]?.requests, 2); + assert.equal(usage.breakdownToday.byTask[0]?.tokens, 3000); + assert.equal(usage.breakdownToday.bySessionType[0]?.label, "Main/内部会话"); + assert.equal(usage.connectors.requestCounts, "connected"); + assert(!usage.connectors.todos.some((item) => item.id === "request_counter")); + assert(!usage.connectors.todos.some((item) => item.id === "context_catalog")); +}); + +test("usage-cost snapshot surfaces connected subscription consumption and remaining contract", async () => { + const { computeUsageCostSnapshot } = await import("../src/runtime/usage-cost"); + const usage = computeUsageCostSnapshot(buildSnapshotFixture(), [], [], undefined, { + status: "connected", + planLabel: "Pro Monthly", + consumed: 120, + remaining: 80, + limit: 200, + usagePercent: 60, + unit: "USD", + cycleStart: "2026-03-01", + cycleEnd: "2026-03-31", + sourcePath: "/tmp/subscription.json", + detail: "Used 120 USD. Remaining 80 USD.", + connectHint: "Provide one of: /tmp/subscription.json", + reasonCode: "provider_connected", + }); + + assert.equal(usage.subscription.status, "connected"); + assert.equal(usage.subscription.remaining, 80); + assert.equal(usage.subscription.cycleEnd, "2026-03-31"); + assert.equal(usage.connectors.subscriptionUsage, "connected"); + assert(!usage.connectors.todos.some((item) => item.id === "subscription_usage")); +}); + +test("usage-cost snapshot surfaces unavailable subscription with explicit connector todo", async () => { + const { computeUsageCostSnapshot } = await import("../src/runtime/usage-cost"); + const usage = computeUsageCostSnapshot(buildSnapshotFixture(), [], [], undefined, { + status: "not_connected", + planLabel: "Not connected", + unit: "USD", + detail: "Subscription usage source is not connected.", + connectHint: "Provide one of: /tmp/subscription.json", + }); + + assert.equal(usage.subscription.status, "not_connected"); + assert.equal(usage.connectors.subscriptionUsage, "not_connected"); + assert(usage.connectors.todos.some((item) => item.id === "subscription_usage")); + assert(usage.connectors.todos.some((item) => item.detail.includes("/tmp/subscription.json"))); +}); + +test("usage-cost snapshot backfills subscription consumed from runtime usage when provider snapshot is missing", async () => { + const { computeUsageCostSnapshot } = await import("../src/runtime/usage-cost"); + const now = Date.now(); + const usage = computeUsageCostSnapshot( + buildSnapshotFixture({ + cost: 0, + }), + [], + [], + { + sourceStatus: "connected", + sessionContexts: [ + { + sessionKey: "s-1", + sessionId: "sid-1", + agentId: "pandas", + }, + ], + events: [runtimeEvent(now, 1000, 1), runtimeEvent(now - 30 * 60 * 1000, 1200, 2)], + }, + ); + + assert.equal(usage.subscription.status, "not_connected"); + assert.equal(usage.subscription.consumed, 3); + assert.equal(usage.subscription.remaining, undefined); + assert.equal(usage.subscription.limit, undefined); + assert(usage.subscription.detail.includes("Provider remaining/limit cannot be derived")); + assert.equal(usage.subscription.reasonCode, "runtime_backfill_only"); + assert(usage.subscription.sourcePath?.includes("sessions/*.jsonl")); + assert.equal(usage.connectors.subscriptionUsage, "not_connected"); + assert( + usage.connectors.todos.some( + (item) => + item.id === "subscription_usage" && + item.detail.includes("Provider remaining/limit cannot be derived"), + ), + ); +}); + +test("usage-cost snapshot backfills subscription limit and remaining from budget when provider snapshot is missing", async () => { + const { computeUsageCostSnapshot } = await import("../src/runtime/usage-cost"); + const now = Date.now(); + const usage = computeUsageCostSnapshot( + buildSnapshotFixture({ + cost: 0, + costLimit: 10, + }), + [], + [], + { + sourceStatus: "connected", + sessionContexts: [ + { + sessionKey: "s-1", + sessionId: "sid-1", + agentId: "pandas", + }, + ], + events: [runtimeEvent(now, 1000, 1), runtimeEvent(now - 30 * 60 * 1000, 1200, 2)], + }, + ); + + assert.equal(usage.subscription.status, "not_connected"); + assert.equal(usage.subscription.planLabel, "Estimated budget envelope"); + assert.equal(usage.subscription.consumed, 3); + assert.equal(usage.subscription.limit, 10); + assert.equal(usage.subscription.remaining, 7); + assert.equal(usage.subscription.usagePercent, 30); + assert(usage.subscription.sourcePath?.includes("budgetSummary")); + assert(usage.subscription.detail.includes("Remaining/limit are derived from configured 30d cost budget")); + assert.equal(usage.connectors.subscriptionUsage, "not_connected"); + assert(usage.connectors.todos.some((item) => item.id === "subscription_usage")); +}); + +test("usage-cost snapshot reports session-type share and cron-job share from deduped session totals", async () => { + const { computeUsageCostSnapshot } = await import("../src/runtime/usage-cost"); + const usage = computeUsageCostSnapshot( + buildSnapshotFixture(), + [], + [], + { + sourceStatus: "connected", + sessionContexts: [ + { + sessionKey: "agent:main:cron:job-a", + sessionId: "sid-1", + agentId: "main", + totalTokens: 1000, + }, + { + sessionKey: "agent:main:cron:job-a:run:r-1", + sessionId: "sid-1", + agentId: "main", + totalTokens: 1000, + }, + { + sessionKey: "agent:main:discord:channel:123", + sessionId: "sid-2", + agentId: "main", + totalTokens: 100, + channel: "discord", + }, + { + sessionKey: "agent:coq:telegram:direct:123", + sessionId: "sid-3", + agentId: "coq", + totalTokens: 50, + channel: "telegram", + }, + { + sessionKey: "agent:main:main", + sessionId: "sid-4", + agentId: "main", + totalTokens: 25, + }, + ], + events: [], + }, + undefined, + new Map([["job-a", "job-alpha"]]), + ); + + const byType = usage.breakdown.bySessionType; + assert.equal(byType.find((item) => item.label === "Cron")?.tokens, 1000); + assert.equal(byType.find((item) => item.label === "Discord")?.tokens, 100); + assert.equal(byType.find((item) => item.label === "Telegram")?.tokens, 50); + assert.equal(byType.find((item) => item.label === "Main/内部会话")?.tokens, 25); + + const cronTop = usage.breakdown.byCronJob[0]; + assert(cronTop); + assert.equal(cronTop.tokens, 1000); + assert(cronTop.label.includes("job-alpha")); + assert(cronTop.label.includes("job-a")); + assert.equal(cronTop.sessions, 1); + assert.equal(usage.breakdown.byCronAgent[0]?.label, "main"); + assert.equal(usage.breakdown.byCronAgent[0]?.tokens, 1000); +}); + +test("codex rate-limit parser prefers canonical codex window over model-specific window", async () => { + const { parseCodexRateLimitFromSessionLogForSmoke } = await import("../src/runtime/usage-cost"); + + const raw = [ + JSON.stringify({ + timestamp: "2026-03-06T11:38:10.057Z", + type: "event_msg", + payload: { + type: "token_count", + rate_limits: { + limit_id: "codex_bengalfox", + limit_name: "GPT-5.3-Codex-Spark", + primary: { used_percent: 0, window_minutes: 300, resets_at: 1772809458 }, + secondary: { used_percent: 2, window_minutes: 10080, resets_at: 1773249479 }, + plan_type: "pro", + }, + }, + }), + JSON.stringify({ + timestamp: "2026-03-06T11:38:10.056Z", + type: "event_msg", + payload: { + type: "token_count", + rate_limits: { + limit_id: "codex", + limit_name: null, + primary: { used_percent: 2, window_minutes: 300, resets_at: 1772812807 }, + secondary: { used_percent: 45, window_minutes: 10080, resets_at: 1773264817 }, + plan_type: "pro", + }, + }, + }), + ].join("\n"); + + const parsed = parseCodexRateLimitFromSessionLogForSmoke(raw, "/tmp/codex.jsonl", Date.parse("2026-03-06T11:40:00.000Z")); + assert(parsed, "expected parsed codex rate-limit snapshot"); + assert.equal(parsed.primaryUsedPercent, 2); + assert.equal(parsed.secondaryUsedPercent, 45); + assert.equal(parsed.primaryResetAt, "2026-03-06T16:00:07.000Z"); + assert.equal(parsed.secondaryResetAt, "2026-03-11T21:33:37.000Z"); + assert.equal(parsed.detail, "codex"); +}); + +test("codex rate-limit parser falls back to model-specific window when canonical codex window is absent", async () => { + const { parseCodexRateLimitFromSessionLogForSmoke } = await import("../src/runtime/usage-cost"); + + const raw = JSON.stringify({ + timestamp: "2026-03-06T11:38:10.057Z", + type: "event_msg", + payload: { + type: "token_count", + rate_limits: { + limit_id: "codex_bengalfox", + limit_name: "GPT-5.3-Codex-Spark", + primary: { used_percent: 0, window_minutes: 300, resets_at: 1772809458 }, + secondary: { used_percent: 2, window_minutes: 10080, resets_at: 1773249479 }, + plan_type: "pro", + }, + }, + }); + + const parsed = parseCodexRateLimitFromSessionLogForSmoke(raw, "/tmp/codex.jsonl", Date.parse("2026-03-06T11:40:00.000Z")); + assert(parsed, "expected parsed model-specific codex rate-limit snapshot"); + assert.equal(parsed.primaryUsedPercent, 0); + assert.equal(parsed.secondaryUsedPercent, 2); + assert.equal(parsed.detail, "codex_bengalfox"); +}); + +test("codex rate-limit parser snaps near-week windows to a stable weekly label", async () => { + const { parseCodexRateLimitFromSessionLogForSmoke } = await import("../src/runtime/usage-cost"); + + const raw = JSON.stringify({ + timestamp: "2026-03-10T23:25:35.000Z", + type: "event_msg", + payload: { + type: "token_count", + rate_limits: { + limit_id: "codex", + primary: { used_percent: 0, window_minutes: 300, resets_at: 1773228605 }, + secondary: { used_percent: 1, window_minutes: 10081, resets_at: 1773815465 }, + plan_type: "pro", + }, + }, + }); + + const parsed = parseCodexRateLimitFromSessionLogForSmoke(raw, "/tmp/codex.jsonl", Date.parse("2026-03-10T23:26:00.000Z")); + assert(parsed, "expected parsed codex rate-limit snapshot"); + assert.equal(parsed.primaryWindowLabel, "5h"); + assert.equal(parsed.secondaryWindowLabel, "7d"); +}); + +function buildSnapshotFixture(overrides?: { + model?: string; + tokensIn?: number; + tokensOut?: number; + cost?: number; + costLimit?: number; +}): ReadModelSnapshot { + const now = new Date().toISOString(); + const model = overrides?.model; + const tokensIn = overrides?.tokensIn ?? 2000; + const tokensOut = overrides?.tokensOut ?? 300; + const cost = overrides?.cost ?? 2; + const costLimit = overrides?.costLimit; + + return { + sessions: [ + { + sessionKey: "s-1", + agentId: "pandas", + label: "Pandas Session", + state: "running", + lastMessageAt: now, + }, + ], + statuses: [ + { + sessionKey: "s-1", + model, + tokensIn, + tokensOut, + cost, + updatedAt: now, + }, + ], + cronJobs: [], + approvals: [], + projects: { + updatedAt: now, + projects: [ + { + projectId: "p1", + title: "Project One", + status: "active", + owner: "pandas", + budget: {}, + updatedAt: now, + }, + ], + }, + projectSummaries: [ + { + projectId: "p1", + title: "Project One", + status: "active", + owner: "pandas", + totalTasks: 1, + todo: 0, + inProgress: 1, + blocked: 0, + done: 0, + due: 0, + updatedAt: now, + }, + ], + tasks: { + updatedAt: now, + agentBudgets: [], + tasks: [ + { + projectId: "p1", + taskId: "t1", + title: "Task One", + status: "in_progress", + owner: "pandas", + definitionOfDone: [], + artifacts: [], + rollback: { + strategy: "none", + steps: [], + }, + sessionKeys: ["s-1"], + budget: {}, + updatedAt: now, + }, + ], + }, + tasksSummary: { + projects: 1, + tasks: 1, + todo: 0, + inProgress: 1, + blocked: 0, + done: 0, + owners: 1, + artifacts: 0, + }, + budgetSummary: { + total: costLimit ? 1 : 0, + ok: costLimit ? 1 : 0, + warn: 0, + over: 0, + evaluations: costLimit + ? [ + { + scope: "agent", + scopeId: "pandas", + label: "Pandas", + thresholds: { + cost: costLimit, + }, + usage: { + tokensIn, + tokensOut, + totalTokens: tokensIn + tokensOut, + cost, + }, + metrics: [ + { + metric: "cost", + used: cost, + limit: costLimit, + warnAt: costLimit * 0.8, + status: "ok", + }, + ], + status: "ok", + }, + ] + : [], + }, + generatedAt: now, + }; +} + +function runtimeEvent(timestampMs: number, tokens: number, cost: number) { + const timestamp = new Date(timestampMs).toISOString(); + return { + timestamp, + day: timestamp.slice(0, 10), + sessionId: "sid-1", + sessionKey: "s-1", + agentId: "pandas", + model: "gpt-5.3-codex", + provider: "OpenAI", + tokens, + cost, + }; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7a8dbb5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "moduleResolution": "node", + "strict": true, + "outDir": "dist", + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src/**/*.ts"] +}
  • ${escapeHtml(item.label)}
  • h$`tSMFzP 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 z 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