diff --git a/docs/project.md b/docs/project.md index 3dc5674..10c6d5a 100644 --- a/docs/project.md +++ b/docs/project.md @@ -55,6 +55,23 @@ curl http://127.0.0.1:18083/api/runtime/threads curl http://127.0.0.1:18083/api/workflow/events ``` +安装并构建前端: + +```bash +cd web +pnpm install +pnpm build +``` + +启动 Phase 4 只读前端工作台: + +```bash +cd web +pnpm dev +``` + +前端开发地址为 `http://127.0.0.1:13083/`。Phase 4 前端仅使用本地静态示例数据,页面文案会标明“示例数据”或“等待连接后端 API”;Phase 5 才接入真实只读 API。 + ## Security Boundaries - 不读取 `.codex/auth.json`。 @@ -66,9 +83,11 @@ curl http://127.0.0.1:18083/api/workflow/events - 当前 `/api/agents` 只读列出 `.codex/agents` 直属 `.toml` 文件,读取前通过 Codex home 边界和 agent TOML 专用 resolver;坏 TOML 以单条 `invalid` 状态返回,不导致服务崩溃。 - 当前 `/api/projects` 只读解析 `.codex/config.toml` 中的 `[projects."..."]`,展示路径、显示名、信任等级和目录存在性。 - 当前 `/api/workflow/events` 从运行线程、spawn edges、goals 和计划文件证据生成事件流/交接边/阶段状态,不写死固定流程。 +- Phase 4 前端不调用真实 API、不保存草稿、不写回 `.codex/agents/*.toml`;所有写回相关控件仅作为只读步骤展示。 ## Known Risks - Codex 内部 SQLite schema 可能变化。 - 运行状态由多来源推断,必须显示置信度。 - Phase 3 真实 SQLite 读取已覆盖临时测试库;如果真实 Codex schema 新增字段或缺少可选字段,应继续走 schema-aware 查询和来源证据,而不是让 API 500。 +- Phase 4 只读工作台是静态壳;如果用户误以为它展示真实状态,应优先检查界面是否仍清楚显示来源、置信度和“等待连接 API”提示。 diff --git a/findings.md b/findings.md index 2a619b5..a4ece28 100644 --- a/findings.md +++ b/findings.md @@ -32,3 +32,4 @@ - Runtime SQLite 读取先检查 `PRAGMA table_info`;缺关键列时对应表返回空列表和 `sqlite_schema_drift`/`low` 证据,可选列缺失、NULL 值和数值类型字段不导致 Snapshot 失败。 - Workflow store 未配置 runtime reader 时返回空视图和 `runtime_missing`/`low` 证据,不 panic、不让 API 500。 - 动态工作流事件从 threads、spawn edges、goals、`task_plan.md` 证据构建,不假设固定角色顺序。 +- Phase 4 前端使用 Vue 3 + Vite 和本地静态示例数据实现中文只读工作台;所有示例状态显示来源和置信度,不调用真实 API,不提供保存或写回按钮。 diff --git a/progress.md b/progress.md index 90d4ea0..f32ffc8 100644 --- a/progress.md +++ b/progress.md @@ -18,6 +18,7 @@ | 2026-05-25 | 3 | coding agent | TDD 实现项目配置、运行线程和动态工作流只读模型 | 完成;新增 `/api/projects`、`/api/runtime/threads`、`/api/workflow/events` | | 2026-05-25 | 3 | spec review | 规格审查未通过:SQLite 依赖提升 Go 下限到 1.25;单侧 DB 缺失来源证据不足 | coding agent 按 blocking 范围修复 | | 2026-05-25 | 3 | quality review | 代码质量审查未通过:SQLite schema drift 可导致 500、`partial` 置信度不在契约内、workflow nil Runtime panic | coding agent 按 blocking 范围修复 | +| 2026-05-25 | 4 | coding agent | 创建 Vue 3 + Vite 中文只读前端工作台,包含五个 tabs、静态示例数据、来源/置信度和空状态 | 完成;未接入真实 API,未提供写回入口 | ## Test Results @@ -95,6 +96,12 @@ | 2026-05-25 | `go vet ./...` | PASS | Phase 3 quality fix vet 通过 | | 2026-05-25 | `gofmt -l internal/runtime internal/workflow internal/server internal/projects internal/app cmd` | PASS | 无需格式化输出 | | 2026-05-25 | `git diff --check` | PASS | Phase 3 quality fix whitespace 检查通过 | +| 2026-05-25 | `pnpm install` | PASS | 在 `web/` 安装 Vue/Vite 依赖,生成 `pnpm-lock.yaml` | +| 2026-05-25 | `pnpm build` | PASS | Vite production build 通过 | +| 2026-05-25 | `pnpm dev` | PASS | Vite dev server 启动于 `http://127.0.0.1:13083/` | +| 2026-05-25 | `curl -I http://127.0.0.1:13083/` | PASS | 本地前端返回 HTTP 200 | +| 2026-05-25 | Browser plugin check | DONE_WITH_CONCERNS | 内置浏览器返回 `Browser is not available: iab`,未完成视觉截图核验 | +| 2026-05-25 | `git diff --check` | PASS | Phase 4 whitespace 检查通过 | ## Bug Loop diff --git a/task_plan.md b/task_plan.md index 28f1b18..71278eb 100644 --- a/task_plan.md +++ b/task_plan.md @@ -21,7 +21,7 @@ | 1 | complete | Go 项目骨架和安全边界 | 后端健康检查可运行;Codex home 路径边界有测试;未读取真实 `.codex` 数据 | | 2 | complete | Agent TOML 只读读取 | 能安全读取 `.codex/agents/*.toml`;坏 TOML 不导致崩溃;提供 `/api/agents` | | 3 | complete | 项目配置、运行线程和工作流模型 | 能读取 projects、threads、spawn edges、goals;状态含来源/置信度;工作流不写死固定流程 | -| 4 | pending | 中文 UI 只读工作台 | 项目/工作流/智能体视图可浏览;空数据可用 | +| 4 | complete | 中文 UI 只读工作台 | 项目/工作流/智能体视图可浏览;空数据可用 | | 5 | pending | API 集成和只读数据显示 | 前端连接只读 API;显示真实 agent 数据和错误状态 | | 6 | pending | 草稿、TOML 校验、diff、备份、写回 | 草稿不覆盖原文件;无效 TOML 阻止写回;备份成功后才能写回 | | 7 | pending | 集成验证与文档 | 测试/构建/浏览器验证通过;文档完整 | diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..9237ae3 --- /dev/null +++ b/web/index.html @@ -0,0 +1,13 @@ + + + + + + + Codex 智能体管理台 + + +
+ + + diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..65115bb --- /dev/null +++ b/web/package.json @@ -0,0 +1,18 @@ +{ + "name": "codex-agent-manager-web", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --host 127.0.0.1 --port 13083", + "build": "vite build", + "preview": "vite preview --host 127.0.0.1 --port 13084" + }, + "dependencies": { + "vue": "^3.5.16" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.2.4", + "vite": "^6.3.5" + } +} diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml new file mode 100644 index 0000000..078a10a --- /dev/null +++ b/web/pnpm-lock.yaml @@ -0,0 +1,830 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + vue: + specifier: ^3.5.16 + version: 3.5.34 + devDependencies: + '@vitejs/plugin-vue': + specifier: ^5.2.4 + version: 5.2.4(vite@6.4.2)(vue@3.5.34) + vite: + specifier: ^6.3.5 + version: 6.4.2 + +packages: + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@rollup/rollup-android-arm-eabi@4.60.4': + resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.4': + resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.4': + resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.4': + resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.4': + resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.4': + resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.60.4': + resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.60.4': + resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.60.4': + resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.60.4': + resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.60.4': + resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.60.4': + resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.60.4': + resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.60.4': + resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.60.4': + resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.60.4': + resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.4': + resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.4': + resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.4': + resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.4': + resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.4': + resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} + cpu: [x64] + os: [win32] + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@vitejs/plugin-vue@5.2.4': + resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.2.25 + + '@vue/compiler-core@3.5.34': + resolution: {integrity: sha512-s9cLyK5mLcvZ4Agva5QgRsQyLKvts9WbU9DB6NqiZkkGEdwmcEiylj5Jbwkp680drF/NNCV8OlAJSe+yMLxaJw==} + + '@vue/compiler-dom@3.5.34': + resolution: {integrity: sha512-EbF/T++k0e2MMZlJsBhzK8Sgwt0HcIPOhzn1CTB/lv6sQcyk+OWf8YeiLxZp3ro7MbbLcAfAJ6sEvjFWuNgUCw==} + + '@vue/compiler-sfc@3.5.34': + resolution: {integrity: sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==} + + '@vue/compiler-ssr@3.5.34': + resolution: {integrity: sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ==} + + '@vue/reactivity@3.5.34': + resolution: {integrity: sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==} + + '@vue/runtime-core@3.5.34': + resolution: {integrity: sha512-mKeBYvu8tcMSLhypAHBmriUFfWXKTCF/23Z4jiCoYK3UtWepkliViNLuR90V9XOyD62mUxs9p1jsrpK3CCGIzw==} + + '@vue/runtime-dom@3.5.34': + resolution: {integrity: sha512-e8kZzERmCwUnBRVsgSQlAfrfU2rGoy0FFKPBXSlfEjc/O3KfA7QP0t1/2ZylrbchjmIKB4dPTd07A6WPr0eOrg==} + + '@vue/server-renderer@3.5.34': + resolution: {integrity: sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==} + peerDependencies: + vue: 3.5.34 + + '@vue/shared@3.5.34': + resolution: {integrity: sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + rollup@4.60.4: + resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + vite@6.4.2: + resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vue@3.5.34: + resolution: {integrity: sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + +snapshots: + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@rollup/rollup-android-arm-eabi@4.60.4': + optional: true + + '@rollup/rollup-android-arm64@4.60.4': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.4': + optional: true + + '@rollup/rollup-darwin-x64@4.60.4': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.4': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.4': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.4': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.4': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.4': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.4': + optional: true + + '@types/estree@1.0.8': {} + + '@vitejs/plugin-vue@5.2.4(vite@6.4.2)(vue@3.5.34)': + dependencies: + vite: 6.4.2 + vue: 3.5.34 + + '@vue/compiler-core@3.5.34': + dependencies: + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.34 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.34': + dependencies: + '@vue/compiler-core': 3.5.34 + '@vue/shared': 3.5.34 + + '@vue/compiler-sfc@3.5.34': + dependencies: + '@babel/parser': 7.29.7 + '@vue/compiler-core': 3.5.34 + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-ssr': 3.5.34 + '@vue/shared': 3.5.34 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.15 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.34': + dependencies: + '@vue/compiler-dom': 3.5.34 + '@vue/shared': 3.5.34 + + '@vue/reactivity@3.5.34': + dependencies: + '@vue/shared': 3.5.34 + + '@vue/runtime-core@3.5.34': + dependencies: + '@vue/reactivity': 3.5.34 + '@vue/shared': 3.5.34 + + '@vue/runtime-dom@3.5.34': + dependencies: + '@vue/reactivity': 3.5.34 + '@vue/runtime-core': 3.5.34 + '@vue/shared': 3.5.34 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.34(vue@3.5.34)': + dependencies: + '@vue/compiler-ssr': 3.5.34 + '@vue/shared': 3.5.34 + vue: 3.5.34 + + '@vue/shared@3.5.34': {} + + csstype@3.2.3: {} + + entities@7.0.1: {} + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + estree-walker@2.0.2: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fsevents@2.3.3: + optional: true + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + nanoid@3.3.12: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + rollup@4.60.4: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.4 + '@rollup/rollup-android-arm64': 4.60.4 + '@rollup/rollup-darwin-arm64': 4.60.4 + '@rollup/rollup-darwin-x64': 4.60.4 + '@rollup/rollup-freebsd-arm64': 4.60.4 + '@rollup/rollup-freebsd-x64': 4.60.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 + '@rollup/rollup-linux-arm-musleabihf': 4.60.4 + '@rollup/rollup-linux-arm64-gnu': 4.60.4 + '@rollup/rollup-linux-arm64-musl': 4.60.4 + '@rollup/rollup-linux-loong64-gnu': 4.60.4 + '@rollup/rollup-linux-loong64-musl': 4.60.4 + '@rollup/rollup-linux-ppc64-gnu': 4.60.4 + '@rollup/rollup-linux-ppc64-musl': 4.60.4 + '@rollup/rollup-linux-riscv64-gnu': 4.60.4 + '@rollup/rollup-linux-riscv64-musl': 4.60.4 + '@rollup/rollup-linux-s390x-gnu': 4.60.4 + '@rollup/rollup-linux-x64-gnu': 4.60.4 + '@rollup/rollup-linux-x64-musl': 4.60.4 + '@rollup/rollup-openbsd-x64': 4.60.4 + '@rollup/rollup-openharmony-arm64': 4.60.4 + '@rollup/rollup-win32-arm64-msvc': 4.60.4 + '@rollup/rollup-win32-ia32-msvc': 4.60.4 + '@rollup/rollup-win32-x64-gnu': 4.60.4 + '@rollup/rollup-win32-x64-msvc': 4.60.4 + fsevents: 2.3.3 + + source-map-js@1.2.1: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + vite@6.4.2: + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.15 + rollup: 4.60.4 + tinyglobby: 0.2.16 + optionalDependencies: + fsevents: 2.3.3 + + vue@3.5.34: + dependencies: + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-sfc': 3.5.34 + '@vue/runtime-dom': 3.5.34 + '@vue/server-renderer': 3.5.34(vue@3.5.34) + '@vue/shared': 3.5.34 diff --git a/web/src/App.vue b/web/src/App.vue new file mode 100644 index 0000000..9d93ae5 --- /dev/null +++ b/web/src/App.vue @@ -0,0 +1,55 @@ + + + diff --git a/web/src/components/HandoffTimeline.vue b/web/src/components/HandoffTimeline.vue new file mode 100644 index 0000000..1c49171 --- /dev/null +++ b/web/src/components/HandoffTimeline.vue @@ -0,0 +1,18 @@ + + + diff --git a/web/src/components/StatusBadge.vue b/web/src/components/StatusBadge.vue new file mode 100644 index 0000000..405f87f --- /dev/null +++ b/web/src/components/StatusBadge.vue @@ -0,0 +1,16 @@ + + + diff --git a/web/src/components/WorkflowGraph.vue b/web/src/components/WorkflowGraph.vue new file mode 100644 index 0000000..a10902f --- /dev/null +++ b/web/src/components/WorkflowGraph.vue @@ -0,0 +1,17 @@ + + + diff --git a/web/src/components/WritebackSteps.vue b/web/src/components/WritebackSteps.vue new file mode 100644 index 0000000..dd089c6 --- /dev/null +++ b/web/src/components/WritebackSteps.vue @@ -0,0 +1,20 @@ + + + diff --git a/web/src/data.js b/web/src/data.js new file mode 100644 index 0000000..5debe6e --- /dev/null +++ b/web/src/data.js @@ -0,0 +1,163 @@ +export const connection = { + label: '等待连接后端 API', + detail: 'Phase 4 仅展示只读工作台外壳;以下内容均为本地示例数据。', + source: 'local_sample', + confidence: 'low', +} + +export const projects = [ + { + id: 'manager', + name: 'codex-agent-manager', + path: '/Users/yoilun/Code/codex-agent-manager', + status: 'recent', + statusZh: '最近活跃', + trust: 'trusted', + activeAgents: 2, + uncertain: true, + drafts: 1, + lastActivity: '示例:18:42', + source: '示例数据', + confidence: 'low', + }, + { + id: 'codex-home', + name: '.codex 本机配置', + path: '/Users/yoilun/.codex', + status: 'unknown', + statusZh: '未知', + trust: 'local', + activeAgents: 0, + uncertain: true, + drafts: 0, + lastActivity: '等待 API', + source: '未连接', + confidence: 'low', + }, + { + id: 'example', + name: '示例项目', + path: '/Users/yoilun/Code/example', + status: 'idle', + statusZh: '空闲', + trust: '示例', + activeAgents: 0, + uncertain: false, + drafts: 0, + lastActivity: '示例:昨天', + source: '示例数据', + confidence: 'low', + }, +] + +export const agentMatrix = [ + { + id: 'lead', + name: '主智能体', + role: '规划与监管', + status: 'recent', + statusZh: '最近活跃', + goal: 'Phase 4 前端工作台', + process: '等待进程表', + source: 'local_sample', + confidence: 'low', + lastActivity: '示例:18:42', + }, + { + id: 'frontend', + name: '前端实现智能体', + role: 'Vue 只读界面', + status: 'running', + statusZh: '运行中', + goal: '搭建中文工作台', + process: '等待 API 连接', + source: 'local_sample', + confidence: 'low', + lastActivity: '示例:刚刚', + }, + { + id: 'reviewer', + name: '审查智能体', + role: '范围与质量审查', + status: 'unknown', + statusZh: '未知', + goal: '等待阶段 5 数据', + process: '未连接', + source: 'api_missing', + confidence: 'low', + lastActivity: '等待连接', + }, +] + +export const workflow = { + phases: [ + { name: 'Phase 0-3', status: 'complete', label: '已完成', gate: 'Go 后端只读模型', evidence: 'task_plan.md / progress.md', confidence: 'medium' }, + { name: 'Phase 4', status: 'running', label: '进行中', gate: '中文只读前端工作台', evidence: '本地示例视图', confidence: 'low' }, + { name: 'Phase 5', status: 'pending', label: '未开始', gate: '连接只读 API', evidence: '等待后续阶段', confidence: 'low' }, + { name: 'Phase 6', status: 'pending', label: '未开始', gate: '草稿校验与写回', evidence: '当前禁用写回', confidence: 'low' }, + ], + handoffs: [ + { from: '主智能体', to: '前端实现智能体', summary: '派发 Phase 4:构建只读工作台外壳', time: '示例:18:45', source: 'local_sample', confidence: 'low' }, + { from: '前端实现智能体', to: '审查智能体', summary: '等待构建和界面验证证据', time: '等待连接', source: 'pending_api', confidence: 'low' }, + { from: '审查智能体', to: '主智能体', summary: '阶段 5 才接入真实 API 和错误态', time: '计划中', source: 'task_plan.md', confidence: 'medium' }, + ], + edges: [ + { parent: '主线程', child: '前端实现', status: '示例运行', source: 'local_sample', confidence: 'low' }, + { parent: '前端实现', child: '界面审查', status: '等待', source: 'pending_api', confidence: 'low' }, + { parent: '界面审查', child: '修复回路', status: '未开始', source: 'task_plan.md', confidence: 'medium' }, + ], +} + +export const agents = [ + { + id: 'frontend-developer', + file: '~/.codex/agents/frontend-developer.toml', + name: '前端开发者', + description: '实现现代 Web 应用、响应式界面和无障碍体验。', + role: 'Vue / Vite / CSS / 可访问性', + status: '示例草稿', + source: 'local_sample', + confidence: 'low', + toml: '[agent]\nname = "前端开发者"\ndescription = "实现现代 Web 应用"\nmode = "readonly-preview"', + }, + { + id: 'code-reviewer', + file: '~/.codex/agents/code-reviewer.toml', + name: '代码审查员', + description: '优先发现行为回归、安全边界和遗漏测试。', + role: '审查 / 风险 / 验证', + status: '等待读取', + source: 'api_missing', + confidence: 'low', + toml: '# 等待 Phase 5 从 /api/agents 读取真实 TOML', + }, +] + +export const drafts = [ + { + file: '~/.codex/agents/frontend-developer.toml', + changedFields: ['描述', '角色设定'], + validation: '示例:未校验', + backup: '等待 Phase 6', + source: 'local_sample', + confidence: 'low', + steps: ['草稿'], + }, + { + file: '~/.codex/agents/code-reviewer.toml', + changedFields: [], + validation: '无草稿', + backup: '无', + source: 'api_missing', + confidence: 'low', + steps: [], + }, +] + +export const settings = [ + { name: 'Codex home', value: '/Users/yoilun/.codex', detail: '阶段 5 后由后端配置返回', enabled: true }, + { name: 'SQLite 状态读取', value: '只读 mode=ro&immutable=1', detail: '当前界面未连接 API', enabled: true }, + { name: '本机进程辅助判断', value: '等待后端聚合', detail: '只显示来源与置信度,不伪装确定状态', enabled: true }, + { name: '写回能力', value: 'Phase 6 才启用', detail: '当前没有保存、写入或批量写回按钮', enabled: false }, + { name: '敏感文件黑名单', value: 'auth.json', detail: '前端只展示规则摘要,不读取内容', enabled: true }, +] diff --git a/web/src/main.js b/web/src/main.js new file mode 100644 index 0000000..fdbdce5 --- /dev/null +++ b/web/src/main.js @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import App from './App.vue' +import './styles.css' + +createApp(App).mount('#app') diff --git a/web/src/styles.css b/web/src/styles.css new file mode 100644 index 0000000..aa2bc1d --- /dev/null +++ b/web/src/styles.css @@ -0,0 +1,814 @@ +:root { + --paper: #f3efe7; + --paper-strong: #e8dfd1; + --panel: #fffdf8; + --panel-muted: #f8f4ec; + --ink: #27312d; + --muted: #6f746c; + --line: #ded6ca; + --green: #2f5d50; + --green-soft: #e4eee9; + --terracotta: #bd6b42; + --terracotta-soft: #f5e1d4; + --amber: #c49a3a; + --blue: #5e718f; + --shadow: 0 18px 45px rgba(62, 52, 39, 0.08); + color: var(--ink); + background: var(--paper); + font-family: "Songti SC", "Noto Serif CJK SC", "Source Han Serif SC", Georgia, serif; + font-size: 16px; + letter-spacing: 0; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + min-width: 320px; + min-height: 100vh; + background: + linear-gradient(90deg, rgba(47, 93, 80, 0.04) 1px, transparent 1px), + linear-gradient(rgba(47, 93, 80, 0.04) 1px, transparent 1px), + var(--paper); + background-size: 28px 28px; +} + +button, +input, +textarea { + font: inherit; + letter-spacing: 0; +} + +button { + cursor: pointer; +} + +.app-shell { + width: min(1440px, 100%); + margin: 0 auto; + padding: 28px; +} + +.workspace-header { + display: grid; + grid-template-columns: minmax(0, 1fr) 340px; + gap: 24px; + align-items: end; + min-height: 160px; +} + +.workspace-header h1 { + margin: 6px 0 10px; + font-size: clamp(2.2rem, 4vw, 4.8rem); + line-height: 0.96; + font-weight: 700; + color: var(--green); +} + +.eyebrow { + margin: 0; + color: var(--terracotta); + font-size: 0.78rem; + font-weight: 700; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +.lede { + max-width: 720px; + margin: 0; + color: var(--muted); + font-size: 1.08rem; + line-height: 1.7; +} + +.connection-card, +.panel { + background: color-mix(in srgb, var(--panel) 92%, white); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: var(--shadow); +} + +.connection-card { + display: grid; + gap: 10px; + padding: 18px; +} + +.connection-card span:last-child { + color: var(--muted); + line-height: 1.6; +} + +.tab-bar { + position: sticky; + top: 0; + z-index: 3; + display: flex; + gap: 8px; + margin: 24px 0; + padding: 10px; + overflow-x: auto; + background: rgba(243, 239, 231, 0.88); + border: 1px solid var(--line); + border-radius: 8px; + backdrop-filter: blur(12px); +} + +.tab-button { + flex: 0 0 auto; + padding: 10px 16px; + color: var(--green); + background: transparent; + border: 1px solid transparent; + border-radius: 6px; +} + +.tab-button.active { + color: var(--panel); + background: var(--green); + border-color: var(--green); +} + +.workspace-main { + min-height: 620px; +} + +.panel { + padding: 20px; +} + +.panel-heading { + display: grid; + gap: 6px; + margin-bottom: 18px; +} + +.panel-heading.horizontal { + grid-template-columns: minmax(0, 1fr) auto; + align-items: start; + gap: 16px; +} + +.panel h2, +.panel h3 { + margin: 0; + color: var(--ink); +} + +.panel h2 { + font-size: 1.28rem; +} + +.panel h3 { + font-size: 0.98rem; +} + +.project-layout { + display: grid; + grid-template-columns: 280px minmax(0, 1fr) 310px; + gap: 16px; + align-items: start; +} + +.project-list, +.detail-panel { + position: sticky; + top: 92px; +} + +.project-item, +.draft-card, +.setting-row, +.graph-edge, +.agent-list-item { + border: 1px solid var(--line); + border-radius: 8px; + background: var(--panel-muted); +} + +.project-item { + display: grid; + gap: 12px; + padding: 14px; + margin-bottom: 10px; +} + +.project-item.selected { + border-color: color-mix(in srgb, var(--green) 52%, var(--line)); + box-shadow: inset 4px 0 0 var(--green); +} + +.project-item strong, +.agent-list-item strong, +.draft-card strong, +.setting-row strong { + display: block; + margin-bottom: 4px; +} + +.project-item span, +.agent-list-item span, +.agent-list-item small, +.draft-card p, +.setting-row p, +.detail-block p, +.empty-state p, +.phase-list p, +.handoff-timeline p, +.graph-edge p { + margin: 0; + color: var(--muted); + line-height: 1.58; +} + +.project-item span, +.agent-list-item small { + word-break: break-all; +} + +.project-item dl, +.detail-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + margin: 0; +} + +.project-item dt, +.detail-grid span { + color: var(--muted); + font-size: 0.82rem; +} + +.project-item dd, +.detail-grid strong { + margin: 0; +} + +.matrix-panel { + overflow: hidden; +} + +.matrix-table { + overflow-x: auto; + border: 1px solid var(--line); + border-radius: 8px; +} + +.matrix-row { + display: grid; + grid-template-columns: minmax(180px, 1.2fr) minmax(220px, 1fr) minmax(170px, 1fr) minmax(150px, 0.8fr) minmax(130px, 0.7fr); + min-width: 920px; + border-top: 1px solid var(--line); +} + +.matrix-row:first-child { + border-top: 0; +} + +.matrix-row.head { + color: var(--muted); + background: var(--paper-strong); + font-size: 0.86rem; + font-weight: 700; +} + +.matrix-row > span { + min-width: 0; + padding: 14px; + border-left: 1px solid var(--line); +} + +.matrix-row > span:first-child { + border-left: 0; +} + +.matrix-row small { + display: block; + color: var(--muted); + margin-top: 4px; +} + +.status-badge { + display: inline-flex; + align-items: center; + flex-wrap: wrap; + gap: 6px; + width: fit-content; + max-width: 100%; + padding: 6px 8px; + color: var(--green); + background: var(--green-soft); + border: 1px solid color-mix(in srgb, var(--green) 24%, transparent); + border-radius: 999px; + font-size: 0.82rem; + line-height: 1.2; +} + +.status-badge small { + color: var(--muted); +} + +.status-dot { + width: 8px; + height: 8px; + flex: 0 0 auto; + border-radius: 50%; + background: var(--green); +} + +.status-badge[data-status="unknown"], +.status-badge[data-status="pending"] { + color: var(--blue); + background: #edf1f5; + border-color: #cbd6df; +} + +.status-badge[data-status="unknown"] .status-dot, +.status-badge[data-status="pending"] .status-dot { + background: var(--blue); +} + +.status-badge[data-status="idle"] { + color: var(--muted); + background: #efebe2; +} + +.status-badge[data-status="complete"] { + color: var(--green); + background: var(--green-soft); +} + +.status-badge[data-status="recent"], +.status-badge[data-status="running"] { + color: var(--terracotta); + background: var(--terracotta-soft); + border-color: #e0b69f; +} + +.status-badge[data-status="recent"] .status-dot, +.status-badge[data-status="running"] .status-dot { + background: var(--terracotta); +} + +.read-only-chip { + display: inline-flex; + align-items: center; + min-height: 32px; + padding: 6px 10px; + color: var(--terracotta); + background: var(--terracotta-soft); + border: 1px solid #e7c2ad; + border-radius: 999px; + font-size: 0.84rem; + font-weight: 700; +} + +.detail-block { + padding: 14px 0; + border-top: 1px solid var(--line); +} + +.detail-grid { + grid-template-columns: auto minmax(0, 1fr); + align-items: center; + padding-top: 14px; + border-top: 1px solid var(--line); +} + +.empty-state { + margin-top: 18px; + padding: 18px; + background: #f7f0e6; + border: 1px dashed #cdbfae; + border-radius: 8px; +} + +.empty-state.compact { + padding: 14px; +} + +.workflow-layout { + display: grid; + grid-template-columns: minmax(0, 1.2fr) minmax(320px, 0.8fr); + gap: 16px; + align-items: start; +} + +.phase-panel, +.graph-panel { + grid-column: 1; +} + +.supervision-panel { + grid-column: 2; + grid-row: 1 / span 2; + position: sticky; + top: 92px; +} + +.phase-list, +.handoff-timeline, +.writeback-steps, +.safety-list { + list-style: none; + padding: 0; + margin: 0; +} + +.phase-list li { + display: grid; + grid-template-columns: 18px minmax(0, 1fr) auto; + gap: 12px; + align-items: start; + padding: 14px 0; + border-top: 1px solid var(--line); +} + +.phase-list li:first-child { + border-top: 0; +} + +.phase-dot { + width: 12px; + height: 12px; + margin-top: 5px; + border-radius: 50%; + background: var(--blue); +} + +.phase-list li[data-status="complete"] .phase-dot { + background: var(--green); +} + +.phase-list li[data-status="running"] .phase-dot { + background: var(--terracotta); +} + +.phase-list span, +.handoff-timeline span, +.graph-edge small { + color: var(--muted); + font-size: 0.82rem; +} + +.handoff-timeline li { + position: relative; + display: grid; + grid-template-columns: 22px minmax(0, 1fr); + gap: 12px; + padding-bottom: 18px; +} + +.handoff-timeline li:not(:last-child)::before { + position: absolute; + left: 6px; + top: 16px; + bottom: 0; + width: 1px; + content: ""; + background: var(--line); +} + +.timeline-marker { + position: relative; + z-index: 1; + width: 13px; + height: 13px; + margin-top: 5px; + border-radius: 50%; + background: var(--panel); + border: 3px solid var(--terracotta); +} + +.timeline-title { + color: var(--ink) !important; + font-weight: 700; +} + +.graph-list { + display: grid; + gap: 12px; +} + +.graph-edge { + display: grid; + grid-template-columns: minmax(120px, 1fr) 52px minmax(120px, 1fr); + gap: 10px; + align-items: center; + padding: 14px; +} + +.graph-edge p, +.graph-edge small { + grid-column: 1 / -1; +} + +.graph-node { + display: grid; + place-items: center; + min-height: 42px; + padding: 8px; + text-align: center; + color: var(--green); + background: var(--green-soft); + border: 1px solid #c8dbd2; + border-radius: 8px; + font-weight: 700; +} + +.graph-node.child { + color: var(--terracotta); + background: var(--terracotta-soft); + border-color: #e5bda6; +} + +.graph-link { + height: 2px; + background: linear-gradient(90deg, var(--green), var(--terracotta)); +} + +.agent-layout { + display: grid; + grid-template-columns: 330px minmax(0, 1fr); + gap: 16px; + align-items: start; +} + +.agent-list { + position: sticky; + top: 92px; +} + +.search-box { + display: grid; + gap: 6px; + margin-bottom: 12px; +} + +.search-box span, +.form-grid span { + color: var(--muted); + font-size: 0.84rem; + font-weight: 700; +} + +.search-box input, +.form-grid input, +.form-grid textarea { + width: 100%; + padding: 11px 12px; + color: var(--ink); + background: var(--panel-muted); + border: 1px solid var(--line); + border-radius: 8px; +} + +.agent-list-item { + display: grid; + width: 100%; + gap: 4px; + margin-bottom: 10px; + padding: 14px; + text-align: left; +} + +.agent-list-item.selected { + border-color: var(--green); + background: var(--green-soft); +} + +.form-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; +} + +.form-grid label { + display: grid; + gap: 6px; +} + +.form-grid .wide { + grid-column: 1 / -1; +} + +.form-grid textarea { + resize: vertical; +} + +.subtabs { + display: flex; + gap: 8px; + margin: 18px 0 12px; + overflow-x: auto; +} + +.subtabs span { + flex: 0 0 auto; + padding: 8px 12px; + color: var(--muted); + border: 1px solid var(--line); + border-radius: 999px; +} + +.subtabs .active { + color: var(--panel); + background: var(--green); + border-color: var(--green); +} + +.readonly-code { + overflow: auto; + padding: 16px; + color: #25322d; + background: #ebe4d8; + border: 1px solid var(--line); + border-radius: 8px; +} + +.readonly-code pre { + margin: 0; + font-family: "SFMono-Regular", Consolas, monospace; + font-size: 0.9rem; + line-height: 1.6; + white-space: pre-wrap; +} + +.drafts-layout, +.settings-layout { + display: grid; + grid-template-columns: minmax(0, 1fr) 340px; + gap: 16px; + align-items: start; +} + +.draft-list, +.settings-list { + display: grid; + gap: 12px; +} + +.draft-card { + display: grid; + gap: 14px; + padding: 16px; +} + +.draft-header { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 12px; + align-items: start; +} + +.writeback-steps { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 8px; +} + +.writeback-steps li { + display: grid; + gap: 6px; + min-width: 0; + color: var(--muted); + font-size: 0.86rem; +} + +.writeback-steps span { + height: 6px; + border-radius: 999px; + background: var(--line); +} + +.writeback-steps li.active { + color: var(--terracotta); + font-weight: 700; +} + +.writeback-steps li.active span { + background: var(--terracotta); +} + +.setting-row { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(150px, auto) 44px; + gap: 14px; + align-items: center; + padding: 16px; +} + +.setting-row > span { + color: var(--green); + font-weight: 700; +} + +.setting-row i { + width: 42px; + height: 24px; + background: var(--green-soft); + border: 1px solid #c4d8d0; + border-radius: 999px; +} + +.setting-row i::after { + display: block; + width: 18px; + height: 18px; + margin: 2px 0 0 19px; + content: ""; + background: var(--green); + border-radius: 50%; +} + +.setting-row i.off { + background: #ece7de; + border-color: var(--line); +} + +.setting-row i.off::after { + margin-left: 2px; + background: var(--muted); +} + +.safety-list { + display: grid; + gap: 10px; +} + +.safety-list li { + padding-left: 14px; + border-left: 3px solid var(--terracotta); + color: var(--muted); + line-height: 1.6; +} + +@media (max-width: 1120px) { + .workspace-header, + .project-layout, + .workflow-layout, + .agent-layout, + .drafts-layout, + .settings-layout { + grid-template-columns: 1fr; + } + + .project-list, + .detail-panel, + .supervision-panel, + .agent-list { + position: static; + } + + .phase-panel, + .graph-panel, + .supervision-panel { + grid-column: auto; + grid-row: auto; + } +} + +@media (max-width: 700px) { + .app-shell { + padding: 16px; + } + + .workspace-header { + min-height: 0; + } + + .panel { + padding: 16px; + } + + .panel-heading.horizontal, + .draft-header, + .setting-row, + .form-grid { + grid-template-columns: 1fr; + } + + .graph-edge { + grid-template-columns: 1fr; + } + + .graph-link { + width: 2px; + height: 28px; + justify-self: center; + } + + .writeback-steps { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .status-badge { + border-radius: 8px; + } +} diff --git a/web/src/views/AgentView.vue b/web/src/views/AgentView.vue new file mode 100644 index 0000000..8add27c --- /dev/null +++ b/web/src/views/AgentView.vue @@ -0,0 +1,80 @@ + + + diff --git a/web/src/views/DraftsView.vue b/web/src/views/DraftsView.vue new file mode 100644 index 0000000..3aaa831 --- /dev/null +++ b/web/src/views/DraftsView.vue @@ -0,0 +1,48 @@ + + + diff --git a/web/src/views/ProjectView.vue b/web/src/views/ProjectView.vue new file mode 100644 index 0000000..6b6e73e --- /dev/null +++ b/web/src/views/ProjectView.vue @@ -0,0 +1,90 @@ + + + diff --git a/web/src/views/SettingsView.vue b/web/src/views/SettingsView.vue new file mode 100644 index 0000000..ab94c81 --- /dev/null +++ b/web/src/views/SettingsView.vue @@ -0,0 +1,42 @@ + + + diff --git a/web/src/views/WorkflowView.vue b/web/src/views/WorkflowView.vue new file mode 100644 index 0000000..afcd835 --- /dev/null +++ b/web/src/views/WorkflowView.vue @@ -0,0 +1,65 @@ + + + diff --git a/web/vite.config.js b/web/vite.config.js new file mode 100644 index 0000000..72fb363 --- /dev/null +++ b/web/vite.config.js @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +export default defineConfig({ + plugins: [vue()], + server: { + host: '127.0.0.1', + port: 13083, + strictPort: false, + proxy: { + '/api': { + target: 'http://127.0.0.1:18083', + changeOrigin: true, + }, + }, + }, +})