@moretea-labs/forge 1.5.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (903) hide show
  1. package/AGENTS.md +120 -0
  2. package/CHANGELOG.md +36 -0
  3. package/CLAUDE.md +120 -0
  4. package/CODE_OF_CONDUCT.md +23 -0
  5. package/CONTRIBUTING.md +77 -0
  6. package/LICENSE +22 -0
  7. package/NOTICE +9 -0
  8. package/README.en.md +5 -0
  9. package/README.es.md +12 -0
  10. package/README.fr.md +12 -0
  11. package/README.ja.md +12 -0
  12. package/README.md +132 -0
  13. package/README.zh-CN.md +84 -0
  14. package/SECURITY.md +50 -0
  15. package/SKILL.md +431 -0
  16. package/SUPPORT.md +31 -0
  17. package/THIRD_PARTY_NOTICES.md +18 -0
  18. package/agents/openai.yaml +4 -0
  19. package/assets/AGENTS.md +68 -0
  20. package/assets/CLAUDE.md +68 -0
  21. package/assets/branding/README.md +10 -0
  22. package/assets/branding/forge-controller-flow.mmd +8 -0
  23. package/assets/hooks/AGENTS.md +75 -0
  24. package/assets/hooks/CLAUDE.md +75 -0
  25. package/assets/hooks/anti-simplification.sh +12 -0
  26. package/assets/hooks/changelog-guard.sh +80 -0
  27. package/assets/hooks/codex.hooks.template.json +60 -0
  28. package/assets/hooks/first-principles-guard.sh +72 -0
  29. package/assets/hooks/hook-input.sh +618 -0
  30. package/assets/hooks/lib/session-state.sh +106 -0
  31. package/assets/hooks/lib/workflow-state.sh +1730 -0
  32. package/assets/hooks/post-bash.sh +215 -0
  33. package/assets/hooks/post-edit-guard.sh +256 -0
  34. package/assets/hooks/post-tool-observer.sh +99 -0
  35. package/assets/hooks/pre-edit-guard.sh +240 -0
  36. package/assets/hooks/prompt-guard.sh +1077 -0
  37. package/assets/hooks/run-hook.sh +67 -0
  38. package/assets/hooks/security-sentinel.sh +115 -0
  39. package/assets/hooks/session-start-context.sh +593 -0
  40. package/assets/hooks/settings.template.json +60 -0
  41. package/assets/hooks/stop-orchestrator.sh +171 -0
  42. package/assets/hooks/subagent-return-channel-guard.sh +107 -0
  43. package/assets/hooks/worktree-guard.sh +39 -0
  44. package/assets/initializer-question-pack.v1.json +132 -0
  45. package/assets/initializer-question-pack.v1.schema.json +46 -0
  46. package/assets/initializer-question-pack.v2.json +174 -0
  47. package/assets/initializer-question-pack.v3.json +206 -0
  48. package/assets/initializer-question-pack.v3.schema.json +92 -0
  49. package/assets/initializer-question-pack.v4.json +557 -0
  50. package/assets/initializer-question-pack.v4.schema.json +169 -0
  51. package/assets/partials/01-header.partial.md +10 -0
  52. package/assets/partials/02-iron-rules.partial.md +30 -0
  53. package/assets/partials/03-philosophy.partial.md +32 -0
  54. package/assets/partials/04-project-structure.partial.md +56 -0
  55. package/assets/partials/05-workflow.partial.md +79 -0
  56. package/assets/partials/06-cloudflare.partial.md +20 -0
  57. package/assets/partials/07-footer.partial.md +38 -0
  58. package/assets/partials/08-orchestration.partial.md +49 -0
  59. package/assets/partials/09-compact-instructions.partial.md +11 -0
  60. package/assets/partials/_assembly-order.md +40 -0
  61. package/assets/partials-agents/01-header.partial.md +8 -0
  62. package/assets/partials-agents/02-operating-mode.partial.md +44 -0
  63. package/assets/partials-agents/03-orchestration.partial.md +45 -0
  64. package/assets/partials-agents/04-task-protocol.partial.md +69 -0
  65. package/assets/partials-agents/05-coding-constraints.partial.md +20 -0
  66. package/assets/partials-agents/06-quality-safety.partial.md +23 -0
  67. package/assets/partials-agents/07-cloudflare.partial.md +9 -0
  68. package/assets/partials-agents/08-deep-docs.partial.md +32 -0
  69. package/assets/plan-map.json +301 -0
  70. package/assets/plugin-registry.v1.json +8 -0
  71. package/assets/project-structures/ai-native-collaborative-editor.txt +25 -0
  72. package/assets/project-structures/ai-native-product-copilot.txt +21 -0
  73. package/assets/project-structures/ai-native-runtime-console.txt +25 -0
  74. package/assets/project-structures/ai-native-sidecar-kernel.txt +19 -0
  75. package/assets/project-structures/astro-ssr.txt +25 -0
  76. package/assets/project-structures/expo-nativewind.txt +52 -0
  77. package/assets/project-structures/monorepo.txt +63 -0
  78. package/assets/project-structures/remix.txt +50 -0
  79. package/assets/project-structures/tanstack-start-workers.txt +51 -0
  80. package/assets/project-structures/vite-tanstack.txt +58 -0
  81. package/assets/reference-configs/AGENTS.md +13 -0
  82. package/assets/reference-configs/CLAUDE.md +13 -0
  83. package/assets/reference-configs/agentic-development-flow.md +94 -0
  84. package/assets/reference-configs/ai-workflows.md +14 -0
  85. package/assets/reference-configs/changelog-versioning.md +13 -0
  86. package/assets/reference-configs/coding-standards.md +14 -0
  87. package/assets/reference-configs/development-protocol.md +21 -0
  88. package/assets/reference-configs/document-generation.md +38 -0
  89. package/assets/reference-configs/evaluator-rubric.md +19 -0
  90. package/assets/reference-configs/external-tooling.md +374 -0
  91. package/assets/reference-configs/git-strategy.md +14 -0
  92. package/assets/reference-configs/global-working-rules.md +64 -0
  93. package/assets/reference-configs/handoff-protocol.md +38 -0
  94. package/assets/reference-configs/harness-overview.md +124 -0
  95. package/assets/reference-configs/heartbeat-triage.md +57 -0
  96. package/assets/reference-configs/hook-operations.md +96 -0
  97. package/assets/reference-configs/release-deploy.md +40 -0
  98. package/assets/reference-configs/spa-day-protocol.md +14 -0
  99. package/assets/reference-configs/sprint-contracts.md +89 -0
  100. package/assets/reference-configs/workflow-orchestration.md +14 -0
  101. package/assets/skill-hooks.json +41 -0
  102. package/assets/skill-version.json +189 -0
  103. package/assets/skills/claude-review/SKILL.md +231 -0
  104. package/assets/skills/codex-review/SKILL.md +103 -0
  105. package/assets/templates/AGENTS.md +13 -0
  106. package/assets/templates/CLAUDE.md +13 -0
  107. package/assets/templates/architecture.template.md +80 -0
  108. package/assets/templates/brief.template.md +38 -0
  109. package/assets/templates/contract.template.md +104 -0
  110. package/assets/templates/decisions.template.md +85 -0
  111. package/assets/templates/factor-factory/factor-backtest-report.template.md +36 -0
  112. package/assets/templates/factor-factory/factor-hypothesis.template.md +30 -0
  113. package/assets/templates/factor-factory/factor-registry.template.json +5 -0
  114. package/assets/templates/gitignore.template +53 -0
  115. package/assets/templates/guides/metro-esm-gotchas.template.md +46 -0
  116. package/assets/templates/helpers/architecture-event.ts +822 -0
  117. package/assets/templates/helpers/architecture-queue.sh +647 -0
  118. package/assets/templates/helpers/archive-architecture-request.sh +244 -0
  119. package/assets/templates/helpers/archive-workflow.sh +295 -0
  120. package/assets/templates/helpers/capability-config.ts +394 -0
  121. package/assets/templates/helpers/capability-resolver.ts +505 -0
  122. package/assets/templates/helpers/capture-plan.sh +335 -0
  123. package/assets/templates/helpers/check-agent-tooling.sh +1533 -0
  124. package/assets/templates/helpers/check-architecture-sync.sh +287 -0
  125. package/assets/templates/helpers/check-brain-manifest.sh +255 -0
  126. package/assets/templates/helpers/check-context-files.sh +49 -0
  127. package/assets/templates/helpers/check-deploy-sql-order.sh +117 -0
  128. package/assets/templates/helpers/check-skill-version.ts +193 -0
  129. package/assets/templates/helpers/check-task-sync.sh +65 -0
  130. package/assets/templates/helpers/check-task-workflow.sh +1002 -0
  131. package/assets/templates/helpers/codex-handoff-resume.sh +269 -0
  132. package/assets/templates/helpers/context-contract-sync.sh +516 -0
  133. package/assets/templates/helpers/contract-run.ts +465 -0
  134. package/assets/templates/helpers/contract-worktree.sh +725 -0
  135. package/assets/templates/helpers/ensure-task-workflow.sh +1218 -0
  136. package/assets/templates/helpers/harness-trace-grade.sh +150 -0
  137. package/assets/templates/helpers/heartbeat-triage.sh +361 -0
  138. package/assets/templates/helpers/inspect-project-state.ts +280 -0
  139. package/assets/templates/helpers/maintenance-triage.sh +167 -0
  140. package/assets/templates/helpers/migrate-project-template.sh +54 -0
  141. package/assets/templates/helpers/migrate-workflow-docs.ts +413 -0
  142. package/assets/templates/helpers/new-plan.sh +183 -0
  143. package/assets/templates/helpers/new-spec.sh +50 -0
  144. package/assets/templates/helpers/new-sprint.sh +49 -0
  145. package/assets/templates/helpers/plan-to-todo.sh +799 -0
  146. package/assets/templates/helpers/prepare-codex-handoff.sh +203 -0
  147. package/assets/templates/helpers/prepare-handoff.sh +81 -0
  148. package/assets/templates/helpers/refresh-current-status.sh +469 -0
  149. package/assets/templates/helpers/select-agent-context-blocks.sh +66 -0
  150. package/assets/templates/helpers/ship-worktrees.sh +561 -0
  151. package/assets/templates/helpers/sprint-backlog.sh +837 -0
  152. package/assets/templates/helpers/summarize-failures.sh +125 -0
  153. package/assets/templates/helpers/switch-plan.sh +153 -0
  154. package/assets/templates/helpers/sync-brain-docs.sh +381 -0
  155. package/assets/templates/helpers/verify-contract.sh +705 -0
  156. package/assets/templates/helpers/verify-sprint.sh +680 -0
  157. package/assets/templates/helpers/workflow-contract.ts +202 -0
  158. package/assets/templates/helpers/workstream-sync.sh +263 -0
  159. package/assets/templates/implementation-notes.template.md +37 -0
  160. package/assets/templates/packages.template.md +45 -0
  161. package/assets/templates/plan.template.md +77 -0
  162. package/assets/templates/prd.template.md +165 -0
  163. package/assets/templates/research.template.md +25 -0
  164. package/assets/templates/review.template.md +78 -0
  165. package/assets/templates/spec.template.md +31 -0
  166. package/assets/templates/sprint.template.md +69 -0
  167. package/assets/templates/tech-stack.template.md +57 -0
  168. package/assets/versions.json +77 -0
  169. package/assets/workflow-contract.v1.json +671 -0
  170. package/bin/forge-desktop-helper.mjs +204 -0
  171. package/bin/forge-hook.mjs +32 -0
  172. package/bin/forge-runtime-service.mjs +34 -0
  173. package/bin/forge-runtime.mjs +30 -0
  174. package/bin/forge.mjs +32 -0
  175. package/docs/CHANGELOG.md +978 -0
  176. package/docs/README.md +72 -0
  177. package/docs/README.zh-CN.md +58 -0
  178. package/docs/architecture/chatgpt-handoff-facade.md +393 -0
  179. package/docs/architecture/current/README.md +158 -0
  180. package/docs/architecture/current/approved-target-architecture.zh-CN.md +1501 -0
  181. package/docs/architecture/current/architecture-invariants.md +331 -0
  182. package/docs/architecture/current/automation-and-schedule-engine.md +453 -0
  183. package/docs/architecture/current/codegraph-context-provider.md +226 -0
  184. package/docs/architecture/current/control-plane-authority-inventory.md +82 -0
  185. package/docs/architecture/current/controller-repository-decoupling.md +148 -0
  186. package/docs/architecture/current/dispatch-and-agent-strategy.md +354 -0
  187. package/docs/architecture/current/entity-model.md +619 -0
  188. package/docs/architecture/current/external-plugin-governance.md +396 -0
  189. package/docs/architecture/current/failure-recovery.md +471 -0
  190. package/docs/architecture/current/governance.md +213 -0
  191. package/docs/architecture/current/human-interaction-plane.md +87 -0
  192. package/docs/architecture/current/implementation-status.md +128 -0
  193. package/docs/architecture/current/job-and-run-lifecycle.md +413 -0
  194. package/docs/architecture/current/local-workspace-target-grants.md +70 -0
  195. package/docs/architecture/current/migration-roadmap.md +105 -0
  196. package/docs/architecture/current/multi-repository-execution.md +371 -0
  197. package/docs/architecture/current/operations-runbook.md +45 -0
  198. package/docs/architecture/current/peer-supercontroller-runtime.md +32 -0
  199. package/docs/architecture/current/personal-assistant-plugin-baseline.md +207 -0
  200. package/docs/architecture/current/repository-access-modes.md +102 -0
  201. package/docs/architecture/current/route-policy.md +15 -0
  202. package/docs/architecture/current/route-session-concurrency.md +85 -0
  203. package/docs/architecture/current/runtime-architecture-simplification.md +214 -0
  204. package/docs/architecture/current/runtime-directory-map.md +49 -0
  205. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +85 -0
  206. package/docs/architecture/current/scheduler-and-resource-claims.md +432 -0
  207. package/docs/architecture/current/session-aware-execution-and-authorization.md +77 -0
  208. package/docs/architecture/current/system-overview.md +144 -0
  209. package/docs/architecture/current/target-requirements-traceability.md +202 -0
  210. package/docs/architecture/current/thin-harness-governance-policy.md +32 -0
  211. package/docs/architecture/current/thin-harness-v1.md +313 -0
  212. package/docs/architecture/current/verification-and-release-gates.md +391 -0
  213. package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +100 -0
  214. package/docs/architecture/decisions/20260803-canonical-skill-surface.md +40 -0
  215. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +53 -0
  216. package/docs/architecture/diagrams/.gitkeep +1 -0
  217. package/docs/architecture/diagrams/agentic-dev-plugin-architecture.html +186 -0
  218. package/docs/architecture/domains/.gitkeep +0 -0
  219. package/docs/architecture/domains/public-surface.md +30 -0
  220. package/docs/architecture/domains/runtime-harness.md +33 -0
  221. package/docs/architecture/domains/verification.md +33 -0
  222. package/docs/architecture/domains/workflow-engine.md +30 -0
  223. package/docs/architecture/global-hook-runtime.md +162 -0
  224. package/docs/architecture/history.md +38 -0
  225. package/docs/architecture/index.md +114 -0
  226. package/docs/architecture/ios-semantic-automation-provider-v2.md +166 -0
  227. package/docs/architecture/modules/.gitkeep +0 -0
  228. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +24 -0
  229. package/docs/architecture/requests/.gitkeep +1 -0
  230. package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +59 -0
  231. package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +59 -0
  232. package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +59 -0
  233. package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +59 -0
  234. package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +59 -0
  235. package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +59 -0
  236. package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +59 -0
  237. package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +59 -0
  238. package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +59 -0
  239. package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +59 -0
  240. package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  241. package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  242. package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +59 -0
  243. package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  244. package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +59 -0
  245. package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  246. package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +59 -0
  247. package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +59 -0
  248. package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +59 -0
  249. package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +59 -0
  250. package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +59 -0
  251. package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +63 -0
  252. package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +60 -0
  253. package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +60 -0
  254. package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +60 -0
  255. package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +60 -0
  256. package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +60 -0
  257. package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +60 -0
  258. package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +68 -0
  259. package/docs/architecture/requests/archive/2026/root.md +68 -0
  260. package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +76 -0
  261. package/docs/architecture/requests/archive/2026/verification-evals-checks.md +68 -0
  262. package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +69 -0
  263. package/docs/architecture/reviews/2026-07-11-access-surface-review.md +99 -0
  264. package/docs/architecture/snapshots/.gitkeep +1 -0
  265. package/docs/forge-autonomous-goal-loop.md +7 -0
  266. package/docs/forge-chatgpt-browser-engine.md +11 -0
  267. package/docs/forge-chatgpt-mcp-setup.md +239 -0
  268. package/docs/forge-chatgpt-supervised-automation.md +11 -0
  269. package/docs/forge-github-issue-launcher.md +7 -0
  270. package/docs/forge-plugin-management.md +95 -0
  271. package/docs/forge-provider-configuration.md +7 -0
  272. package/docs/forge-runtime-self-healing-loop.md +7 -0
  273. package/docs/images/forge-banner-cn.svg +1 -0
  274. package/docs/images/forge-banner.svg +1 -0
  275. package/docs/images/forge-controller-flow.svg +1 -0
  276. package/docs/images/image.png +0 -0
  277. package/docs/images/repo-harness-gptpro-cn.png +0 -0
  278. package/docs/images/repo-harness-gptpro.png +0 -0
  279. package/docs/images/repo-harness-hook-carrot.png +0 -0
  280. package/docs/operations/chatgpt-personal-assistant-runtime.md +83 -0
  281. package/docs/operations/checkout-route-integrity.md +22 -0
  282. package/docs/operations/controller-browser-plugin.md +299 -0
  283. package/docs/operations/controller-desktop-plugin.md +112 -0
  284. package/docs/operations/controller-performance-and-502.md +126 -0
  285. package/docs/operations/controller-reliability-runbook.md +134 -0
  286. package/docs/operations/environment-hardening.md +50 -0
  287. package/docs/operations/features.md +45 -0
  288. package/docs/operations/features.zh-CN.md +45 -0
  289. package/docs/operations/github-repository.md +60 -0
  290. package/docs/operations/gmail-assistant-routines.md +186 -0
  291. package/docs/operations/homebrew.md +26 -0
  292. package/docs/operations/local-system-assistant.md +46 -0
  293. package/docs/operations/local-system-assistant.zh-CN.md +46 -0
  294. package/docs/operations/mcp-tool-exposure.md +58 -0
  295. package/docs/operations/mobile-intents-shortcuts.md +117 -0
  296. package/docs/operations/open-source-release-hygiene.md +31 -0
  297. package/docs/operations/personal-assistant-operator-guide.md +61 -0
  298. package/docs/operations/platform-support.md +62 -0
  299. package/docs/operations/platform-support.zh-CN.md +61 -0
  300. package/docs/operations/provider-configuration.md +31 -0
  301. package/docs/operations/releasing.md +86 -0
  302. package/docs/operations/releasing.zh-CN.md +86 -0
  303. package/docs/operations/route-session-concurrency-baseline.json +893 -0
  304. package/docs/operations/route-session-concurrency-baseline.md +94 -0
  305. package/docs/operations/runtime-performance-diagnostics.md +14 -0
  306. package/docs/operations/sqlite-control-plane-recovery.md +65 -0
  307. package/docs/operations/standalone-disaster-recovery.md +136 -0
  308. package/docs/operations/troubleshooting.md +72 -0
  309. package/docs/operations/troubleshooting.zh-CN.md +70 -0
  310. package/docs/public-usage-guide.md +33 -0
  311. package/docs/public-usage-guide.zh-CN.md +33 -0
  312. package/docs/tutorials/01-install-and-start.md +93 -0
  313. package/docs/tutorials/01-install-and-start.zh-CN.md +93 -0
  314. package/docs/tutorials/02-connect-chatgpt.md +82 -0
  315. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +80 -0
  316. package/docs/tutorials/03-first-repository-task.md +57 -0
  317. package/docs/tutorials/03-first-repository-task.zh-CN.md +57 -0
  318. package/docs/tutorials/README.md +13 -0
  319. package/docs/tutorials/README.zh-CN.md +13 -0
  320. package/docs/wiki/Architecture.md +85 -0
  321. package/docs/wiki/Core-Concepts.md +27 -0
  322. package/docs/wiki/Home.md +36 -0
  323. package/docs/wiki/Implementation.md +172 -0
  324. package/docs/wiki/Installation.md +50 -0
  325. package/docs/wiki/Integrations.md +29 -0
  326. package/docs/wiki/Operations.md +26 -0
  327. package/docs/wiki/Quick-Start.md +46 -0
  328. package/docs/wiki/Releases-and-Upgrades.md +34 -0
  329. package/docs/wiki/Runtime-Architecture.md +50 -0
  330. package/docs/wiki/Security-Model.md +31 -0
  331. package/docs/wiki/Troubleshooting.md +38 -0
  332. package/docs/wiki/Work-Lifecycle.md +31 -0
  333. package/docs/wiki/_Sidebar.md +21 -0
  334. package/install.ps1 +48 -0
  335. package/install.sh +66 -0
  336. package/package.json +156 -0
  337. package/scripts/activate-source-baseline.ts +335 -0
  338. package/scripts/architecture-event.ts +822 -0
  339. package/scripts/architecture-queue.sh +647 -0
  340. package/scripts/archive-architecture-request.sh +244 -0
  341. package/scripts/archive-workflow.sh +295 -0
  342. package/scripts/assemble-template.ts +1172 -0
  343. package/scripts/benchmark-controller-hotpath.ts +212 -0
  344. package/scripts/benchmark-controller-round2.ts +139 -0
  345. package/scripts/benchmark-ios-agent-device.ts +514 -0
  346. package/scripts/benchmark-route-session-concurrency.ts +714 -0
  347. package/scripts/benchmark-thin-harness-gateway-ab.ts +632 -0
  348. package/scripts/benchmark-thin-harness-mcp-e2e.ts +479 -0
  349. package/scripts/benchmark-thin-harness.ts +251 -0
  350. package/scripts/bootstrap-runtime-maintenance-recovery.sh +183 -0
  351. package/scripts/canary-global-hook.sh +263 -0
  352. package/scripts/capability-config.ts +394 -0
  353. package/scripts/capability-resolver.ts +505 -0
  354. package/scripts/capture-plan.sh +335 -0
  355. package/scripts/check-agent-tooling.sh +1549 -0
  356. package/scripts/check-architecture-sync.sh +373 -0
  357. package/scripts/check-brain-manifest.sh +255 -0
  358. package/scripts/check-ci.sh +16 -0
  359. package/scripts/check-context-files.sh +49 -0
  360. package/scripts/check-deploy-sql-order.sh +117 -0
  361. package/scripts/check-mcp-compatibility.ts +93 -0
  362. package/scripts/check-npm-release.sh +32 -0
  363. package/scripts/check-open-source-tracked-surface.sh +146 -0
  364. package/scripts/check-package-identity.mjs +117 -0
  365. package/scripts/check-platform-support.mjs +79 -0
  366. package/scripts/check-public-docs.sh +105 -0
  367. package/scripts/check-public-release-surface.sh +19 -0
  368. package/scripts/check-release-published.sh +57 -0
  369. package/scripts/check-release-readiness.sh +43 -0
  370. package/scripts/check-release-version.mjs +74 -0
  371. package/scripts/check-runtime-architecture.mjs +593 -0
  372. package/scripts/check-runtime-env.mjs +89 -0
  373. package/scripts/check-skill-version.ts +193 -0
  374. package/scripts/check-tarball-install-smoke.sh +66 -0
  375. package/scripts/check-task-sync.sh +65 -0
  376. package/scripts/check-task-workflow.sh +1002 -0
  377. package/scripts/check-third-party-notices.mjs +36 -0
  378. package/scripts/codex-handoff-resume.sh +269 -0
  379. package/scripts/complete-control-plane-cutover.ts +126 -0
  380. package/scripts/context-contract-sync.sh +516 -0
  381. package/scripts/contract-run.ts +465 -0
  382. package/scripts/contract-worktree.sh +725 -0
  383. package/scripts/controller-ngrok-rotation.sh +678 -0
  384. package/scripts/create-project-dirs.sh +282 -0
  385. package/scripts/ensure-codegraph.sh +16 -0
  386. package/scripts/ensure-task-workflow.sh +1218 -0
  387. package/scripts/export-requirement-portfolio.ts +28 -0
  388. package/scripts/factor-lab-check.sh +73 -0
  389. package/scripts/factor-lab-new.sh +96 -0
  390. package/scripts/factor-lab-promote.sh +86 -0
  391. package/scripts/factor-lab-reject.sh +68 -0
  392. package/scripts/harness-trace-grade.sh +150 -0
  393. package/scripts/heartbeat-triage.sh +361 -0
  394. package/scripts/hook-dispatch-diet-report.ts +234 -0
  395. package/scripts/hook-shim.sh +93 -0
  396. package/scripts/init-project.sh +505 -0
  397. package/scripts/initializer-question-pack.ts +200 -0
  398. package/scripts/inspect-project-state.ts +280 -0
  399. package/scripts/install-desktop-operator-registration.ts +45 -0
  400. package/scripts/install-standalone-recovery.ts +74 -0
  401. package/scripts/lib/AGENTS.md +13 -0
  402. package/scripts/lib/CLAUDE.md +13 -0
  403. package/scripts/lib/controller-home-env.sh +69 -0
  404. package/scripts/lib/project-init-lib.sh +2759 -0
  405. package/scripts/load-standalone-recovery.sh +17 -0
  406. package/scripts/loop-engine-cutover-gate.ts +324 -0
  407. package/scripts/maintenance-triage.sh +167 -0
  408. package/scripts/migrate-project-template.sh +1189 -0
  409. package/scripts/migrate-requirement-portfolio.ts +86 -0
  410. package/scripts/migrate-workflow-docs.ts +413 -0
  411. package/scripts/new-plan.sh +183 -0
  412. package/scripts/new-spec.sh +50 -0
  413. package/scripts/new-sprint.sh +49 -0
  414. package/scripts/open-source-audit-allowlist.txt +46 -0
  415. package/scripts/package-source-archive.sh +147 -0
  416. package/scripts/plan-to-todo.sh +799 -0
  417. package/scripts/prepare-codex-handoff.sh +203 -0
  418. package/scripts/prepare-handoff.sh +81 -0
  419. package/scripts/public-release-files.txt +39 -0
  420. package/scripts/public-release.ts +174 -0
  421. package/scripts/publish-release-tarball.sh +27 -0
  422. package/scripts/refresh-current-status.sh +469 -0
  423. package/scripts/refresh-ios-physical-runtime.ts +196 -0
  424. package/scripts/repair-executable-modes.ts +8 -0
  425. package/scripts/rollout-all-registered-repos.sh +7 -0
  426. package/scripts/route-nl-vs-ts-eval.ts +679 -0
  427. package/scripts/run-bun-test-file.ts +182 -0
  428. package/scripts/run-governed-gate.ts +140 -0
  429. package/scripts/run-mobile-monitor-bridge.ts +71 -0
  430. package/scripts/run-skill-evals.ts +1022 -0
  431. package/scripts/run-skill-hook.ts +244 -0
  432. package/scripts/run-supervised-command.ts +24 -0
  433. package/scripts/run-tests-portable.sh +20 -0
  434. package/scripts/select-agent-context-blocks.sh +66 -0
  435. package/scripts/setup-plugins.sh +43 -0
  436. package/scripts/ship-worktrees.sh +561 -0
  437. package/scripts/smoke-browser-cdp-bridge.ts +93 -0
  438. package/scripts/smoke-chatgpt-supervised-automation.ts +208 -0
  439. package/scripts/smoke-ios-physical-device.ts +114 -0
  440. package/scripts/smoke-mcp-http-runtime.ts +216 -0
  441. package/scripts/smoke-mcp-tool-surface.ts +117 -0
  442. package/scripts/smoke-runtime-recovery.ts +220 -0
  443. package/scripts/smoke-schedule-engine.ts +283 -0
  444. package/scripts/sprint-backlog.sh +837 -0
  445. package/scripts/stage-runtime-release.ts +38 -0
  446. package/scripts/summarize-failures.sh +125 -0
  447. package/scripts/switch-plan.sh +153 -0
  448. package/scripts/sync-brain-docs.sh +381 -0
  449. package/scripts/sync-codex-installed-copies.sh +183 -0
  450. package/scripts/test-governance.ts +75 -0
  451. package/scripts/verify-contract.sh +705 -0
  452. package/scripts/verify-forge-runtime.sh +31 -0
  453. package/scripts/verify-sprint.sh +680 -0
  454. package/scripts/windows-paths.d.mts +7 -0
  455. package/scripts/windows-paths.mjs +28 -0
  456. package/scripts/workflow-contract.ts +206 -0
  457. package/scripts/workstream-sync.sh +263 -0
  458. package/src/cli/agent-jobs/executable-resolver.ts +289 -0
  459. package/src/cli/agent-jobs/executor-health.ts +252 -0
  460. package/src/cli/agent-jobs/integration.ts +963 -0
  461. package/src/cli/agent-jobs/job-manager.ts +2030 -0
  462. package/src/cli/agent-jobs/types.ts +219 -0
  463. package/src/cli/agent-jobs/worker-lifecycle.ts +288 -0
  464. package/src/cli/chatgpt-browser/bind-server.ts +504 -0
  465. package/src/cli/chatgpt-browser/binding.ts +140 -0
  466. package/src/cli/chatgpt-browser/bridge-extension.ts +221 -0
  467. package/src/cli/chatgpt-browser/bridge-provider.ts +268 -0
  468. package/src/cli/chatgpt-browser/engine.ts +569 -0
  469. package/src/cli/chatgpt-browser/file-policy.ts +158 -0
  470. package/src/cli/chatgpt-browser/native-provider.ts +553 -0
  471. package/src/cli/chatgpt-browser/oracle-provider.ts +437 -0
  472. package/src/cli/chatgpt-browser/prompt-assembler.ts +29 -0
  473. package/src/cli/chatgpt-browser/session-store.ts +301 -0
  474. package/src/cli/chatgpt-browser/types.ts +172 -0
  475. package/src/cli/commands/adopt-plan.ts +186 -0
  476. package/src/cli/commands/brain-root.ts +132 -0
  477. package/src/cli/commands/brain.ts +609 -0
  478. package/src/cli/commands/capability-context.ts +613 -0
  479. package/src/cli/commands/chatgpt.ts +424 -0
  480. package/src/cli/commands/controller.ts +680 -0
  481. package/src/cli/commands/docs.ts +103 -0
  482. package/src/cli/commands/doctor.ts +476 -0
  483. package/src/cli/commands/global-runtime.ts +323 -0
  484. package/src/cli/commands/hook.ts +34 -0
  485. package/src/cli/commands/init-hook.ts +870 -0
  486. package/src/cli/commands/init.ts +829 -0
  487. package/src/cli/commands/install.ts +86 -0
  488. package/src/cli/commands/mcp.ts +315 -0
  489. package/src/cli/commands/migrate.ts +154 -0
  490. package/src/cli/commands/plugin.ts +74 -0
  491. package/src/cli/commands/prompt-guard-decision.ts +238 -0
  492. package/src/cli/commands/recovery.ts +667 -0
  493. package/src/cli/commands/repository.ts +224 -0
  494. package/src/cli/commands/run.ts +23 -0
  495. package/src/cli/commands/runtime.ts +191 -0
  496. package/src/cli/commands/security.ts +440 -0
  497. package/src/cli/commands/status.ts +137 -0
  498. package/src/cli/commands/tools.ts +167 -0
  499. package/src/cli/controller/check-runner.ts +1022 -0
  500. package/src/cli/controller/codex-continuation.ts +153 -0
  501. package/src/cli/controller/completion-backlog.ts +380 -0
  502. package/src/cli/controller/completion-orchestrator.ts +1807 -0
  503. package/src/cli/controller/completion-target.ts +96 -0
  504. package/src/cli/controller/composite-operations.ts +196 -0
  505. package/src/cli/controller/composite-result.ts +130 -0
  506. package/src/cli/controller/context-pack.ts +652 -0
  507. package/src/cli/controller/execution-completion.ts +175 -0
  508. package/src/cli/controller/execution-policy.ts +392 -0
  509. package/src/cli/controller/governance.ts +594 -0
  510. package/src/cli/controller/issue-store.ts +1421 -0
  511. package/src/cli/controller/launch-agents.ts +410 -0
  512. package/src/cli/controller/legacy-issue-cutover.ts +415 -0
  513. package/src/cli/controller/lifecycle-authority.ts +16 -0
  514. package/src/cli/controller/migrated-issue-decision.ts +237 -0
  515. package/src/cli/controller/operational-plan.ts +226 -0
  516. package/src/cli/controller/postcondition.ts +134 -0
  517. package/src/cli/controller/progress.ts +656 -0
  518. package/src/cli/controller/project-state.ts +147 -0
  519. package/src/cli/controller/requirement-portfolio-export.ts +146 -0
  520. package/src/cli/controller/requirement-portfolio-migration.ts +613 -0
  521. package/src/cli/controller/run-evidence.ts +43 -0
  522. package/src/cli/controller/runtime-config.ts +92 -0
  523. package/src/cli/controller/stuck-state-migration.ts +396 -0
  524. package/src/cli/controller/task-ledger.ts +632 -0
  525. package/src/cli/controller/task-status-resolver.ts +403 -0
  526. package/src/cli/controller/types.ts +273 -0
  527. package/src/cli/controller/work-mode.ts +186 -0
  528. package/src/cli/controller/worklog.ts +201 -0
  529. package/src/cli/diagnostic-entry.ts +39 -0
  530. package/src/cli/editing/edit-session.ts +1606 -0
  531. package/src/cli/editing/executable-modes.ts +70 -0
  532. package/src/cli/github/github.ts +274 -0
  533. package/src/cli/github/plugin.ts +345 -0
  534. package/src/cli/github/session.ts +104 -0
  535. package/src/cli/hook/prompt-guard-decision.ts +238 -0
  536. package/src/cli/hook/prompt-intents.ts +534 -0
  537. package/src/cli/hook/route-registry.ts +107 -0
  538. package/src/cli/hook/runtime.ts +303 -0
  539. package/src/cli/hook/state-snapshot.ts +388 -0
  540. package/src/cli/hook-entry.ts +51 -0
  541. package/src/cli/index.ts +574 -0
  542. package/src/cli/installer/managed-entries.ts +78 -0
  543. package/src/cli/installer/shared.ts +65 -0
  544. package/src/cli/installer/targets/claude.ts +136 -0
  545. package/src/cli/installer/targets/codex.ts +174 -0
  546. package/src/cli/installer/targets/registry.ts +28 -0
  547. package/src/cli/installer/types.ts +72 -0
  548. package/src/cli/local-bridge/connector-freshness.ts +529 -0
  549. package/src/cli/local-bridge/console-view-models.ts +324 -0
  550. package/src/cli/local-bridge/dashboard.ts +1312 -0
  551. package/src/cli/local-bridge/facade-api.ts +1877 -0
  552. package/src/cli/local-bridge/job-store.ts +1451 -0
  553. package/src/cli/local-bridge/mobile-intents.ts +344 -0
  554. package/src/cli/local-bridge/mobile-monitor.ts +209 -0
  555. package/src/cli/local-bridge/server.ts +3183 -0
  556. package/src/cli/local-bridge/types.ts +176 -0
  557. package/src/cli/mcp/access-mode.ts +132 -0
  558. package/src/cli/mcp/access-tools.ts +387 -0
  559. package/src/cli/mcp/audit.ts +32 -0
  560. package/src/cli/mcp/auth.ts +402 -0
  561. package/src/cli/mcp/instructions.ts +33 -0
  562. package/src/cli/mcp/legacy-context.ts +16 -0
  563. package/src/cli/mcp/legacy-tool-service.ts +5516 -0
  564. package/src/cli/mcp/multi-repository.ts +423 -0
  565. package/src/cli/mcp/oauth.ts +226 -0
  566. package/src/cli/mcp/paths.ts +134 -0
  567. package/src/cli/mcp/policy.ts +230 -0
  568. package/src/cli/mcp/proxy-env.ts +62 -0
  569. package/src/cli/mcp/readiness-projection.ts +24 -0
  570. package/src/cli/mcp/redaction.ts +21 -0
  571. package/src/cli/mcp/repo.ts +24 -0
  572. package/src/cli/mcp/repository-tools.ts +1295 -0
  573. package/src/cli/mcp/server.ts +341 -0
  574. package/src/cli/mcp/setup.ts +793 -0
  575. package/src/cli/mcp/tool-capability-cache.ts +87 -0
  576. package/src/cli/mcp/tools.ts +9 -0
  577. package/src/cli/mcp/toolset-names.ts +70 -0
  578. package/src/cli/mcp/toolset-selection.ts +41 -0
  579. package/src/cli/mcp/toolset.ts +300 -0
  580. package/src/cli/mcp/transports/AGENTS.md +39 -0
  581. package/src/cli/mcp/transports/CLAUDE.md +39 -0
  582. package/src/cli/mcp/transports/http.ts +1234 -0
  583. package/src/cli/mcp/transports/session-registry.ts +428 -0
  584. package/src/cli/mcp/transports/stdio.ts +8 -0
  585. package/src/cli/mcp/types.ts +41 -0
  586. package/src/cli/mcp/umbrella-tools.ts +117 -0
  587. package/src/cli/repo-adoption/reclaim-runtime.ts +681 -0
  588. package/src/cli/repositories/branch-name-policy.ts +57 -0
  589. package/src/cli/repositories/command-classifier.ts +600 -0
  590. package/src/cli/repositories/command-executor.ts +1066 -0
  591. package/src/cli/repositories/command-normalization.ts +53 -0
  592. package/src/cli/repositories/command-scope.ts +264 -0
  593. package/src/cli/repositories/controller-home.ts +88 -0
  594. package/src/cli/repositories/entity-migration.ts +199 -0
  595. package/src/cli/repositories/ephemeral-workspace.ts +62 -0
  596. package/src/cli/repositories/git-command-executor.ts +301 -0
  597. package/src/cli/repositories/goal-registry.ts +239 -0
  598. package/src/cli/repositories/identity.ts +64 -0
  599. package/src/cli/repositories/local-project-onboarding.ts +539 -0
  600. package/src/cli/repositories/locks.ts +262 -0
  601. package/src/cli/repositories/registry.ts +1057 -0
  602. package/src/cli/repositories/runtime-storage.ts +411 -0
  603. package/src/cli/repositories/safe-patch.ts +421 -0
  604. package/src/cli/repositories/selected-path-actions.ts +341 -0
  605. package/src/cli/repositories/structured-git.ts +257 -0
  606. package/src/cli/repositories/types.ts +155 -0
  607. package/src/cli/repositories/umbrella.ts +134 -0
  608. package/src/cli/repositories/workbench.ts +140 -0
  609. package/src/cli/repositories/worktree-storage.ts +137 -0
  610. package/src/cli/repository/inspector.ts +637 -0
  611. package/src/cli/repository/session-cache.ts +453 -0
  612. package/src/cli/runtime/helper-runner.ts +172 -0
  613. package/src/cli/runtime-invocation.ts +318 -0
  614. package/src/cli/tools/codegraph.ts +676 -0
  615. package/src/cli/v81-entry.ts +29 -0
  616. package/src/core/adoption/gitignore-plan.ts +127 -0
  617. package/src/core/adoption/helper-wrapper-plan.ts +159 -0
  618. package/src/core/adoption/manifest-templates.ts +60 -0
  619. package/src/core/adoption/modes.ts +7 -0
  620. package/src/core/adoption/operations.ts +126 -0
  621. package/src/core/adoption/plan.ts +149 -0
  622. package/src/core/adoption/render.ts +70 -0
  623. package/src/core/adoption/rollback.ts +62 -0
  624. package/src/core/adoption/summary.ts +43 -0
  625. package/src/core/adoption/workflow-contract-asset.ts +14 -0
  626. package/src/core/adoption/workflow-contract-plan.ts +31 -0
  627. package/src/effects/fs-transaction.ts +540 -0
  628. package/src/effects/git-executable.ts +59 -0
  629. package/src/effects/managed-block.ts +86 -0
  630. package/src/effects/path-safety.ts +47 -0
  631. package/src/effects/process-runner.ts +192 -0
  632. package/src/runtime/assistant/action-proposals.ts +279 -0
  633. package/src/runtime/assistant/intent.ts +395 -0
  634. package/src/runtime/assistant/model-provider.ts +460 -0
  635. package/src/runtime/assistant/openapi.ts +223 -0
  636. package/src/runtime/assistant/policy.ts +89 -0
  637. package/src/runtime/assistant/readiness.ts +258 -0
  638. package/src/runtime/assistant/routine-runtime.ts +477 -0
  639. package/src/runtime/assistant/schedule-binding.ts +171 -0
  640. package/src/runtime/assistant/standing-grants.ts +375 -0
  641. package/src/runtime/assistant/store.ts +243 -0
  642. package/src/runtime/assistant/types.ts +135 -0
  643. package/src/runtime/context/codegraph-read-provider.ts +347 -0
  644. package/src/runtime/context/codegraph-sidecar.cjs +207 -0
  645. package/src/runtime/control-plane/dispatch-priority.ts +67 -0
  646. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +151 -0
  647. package/src/runtime/control-plane/execution/execution-identity.ts +456 -0
  648. package/src/runtime/control-plane/execution/session-store.ts +175 -0
  649. package/src/runtime/control-plane/execution/validation.ts +117 -0
  650. package/src/runtime/control-plane/execution/verification-evidence.ts +191 -0
  651. package/src/runtime/control-plane/execution/work-handle-store.ts +225 -0
  652. package/src/runtime/control-plane/execution/work-prepare-request-store.ts +159 -0
  653. package/src/runtime/control-plane/execution/work-task-receipt.ts +445 -0
  654. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +821 -0
  655. package/src/runtime/control-plane/facade/capability-registry.ts +279 -0
  656. package/src/runtime/control-plane/facade/check-normalization.ts +233 -0
  657. package/src/runtime/control-plane/facade/codex-delegation.ts +196 -0
  658. package/src/runtime/control-plane/facade/controller-session-store.ts +199 -0
  659. package/src/runtime/control-plane/facade/facade-result.ts +41 -0
  660. package/src/runtime/control-plane/facade/goal-workloop-access.ts +177 -0
  661. package/src/runtime/control-plane/facade/goal-workloop.ts +1216 -0
  662. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +221 -0
  663. package/src/runtime/control-plane/facade/index.ts +16 -0
  664. package/src/runtime/control-plane/facade/operation-digest.ts +528 -0
  665. package/src/runtime/control-plane/facade/plan-contract-store.ts +403 -0
  666. package/src/runtime/control-plane/facade/policy-gate.ts +149 -0
  667. package/src/runtime/control-plane/facade/requirement-board.ts +280 -0
  668. package/src/runtime/control-plane/facade/self-healing-loop.ts +555 -0
  669. package/src/runtime/control-plane/facade/suggested-actions.ts +108 -0
  670. package/src/runtime/control-plane/facade/types.ts +729 -0
  671. package/src/runtime/control-plane/facade/work-admission-policy.ts +93 -0
  672. package/src/runtime/control-plane/facade/work-continuation.ts +104 -0
  673. package/src/runtime/control-plane/facade/work-contract-store.ts +1118 -0
  674. package/src/runtime/control-plane/facade/work-task-projection.ts +66 -0
  675. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +365 -0
  676. package/src/runtime/control-plane/global-scheduler/scheduler.ts +920 -0
  677. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +89 -0
  678. package/src/runtime/control-plane/goal-loop/config-facade.ts +700 -0
  679. package/src/runtime/control-plane/goal-loop/config-store.ts +570 -0
  680. package/src/runtime/control-plane/goal-loop/config-types.ts +213 -0
  681. package/src/runtime/control-plane/goal-loop/executor-router.ts +109 -0
  682. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +149 -0
  683. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +304 -0
  684. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +1001 -0
  685. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +160 -0
  686. package/src/runtime/control-plane/goal-loop/index.ts +13 -0
  687. package/src/runtime/control-plane/goal-loop/local-tools.ts +290 -0
  688. package/src/runtime/control-plane/goal-loop/policy-gates.ts +203 -0
  689. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +93 -0
  690. package/src/runtime/control-plane/goal-loop/provider-registry.ts +545 -0
  691. package/src/runtime/control-plane/goal-loop/types.ts +378 -0
  692. package/src/runtime/control-plane/governance/access-policy.ts +147 -0
  693. package/src/runtime/control-plane/governance/authorization.ts +195 -0
  694. package/src/runtime/control-plane/governance/external-effects.ts +43 -0
  695. package/src/runtime/control-plane/launcher/thin-launcher.ts +97 -0
  696. package/src/runtime/control-plane/persistence/metadata-payload-policy.ts +53 -0
  697. package/src/runtime/control-plane/persistence/requirement-store.ts +241 -0
  698. package/src/runtime/control-plane/persistence/sqlite-store.ts +539 -0
  699. package/src/runtime/control-plane/release-retention.ts +447 -0
  700. package/src/runtime/control-plane/repo-actor/actor.ts +181 -0
  701. package/src/runtime/control-plane/repo-actor/registry.ts +20 -0
  702. package/src/runtime/control-plane/routing/index.ts +1 -0
  703. package/src/runtime/control-plane/routing/route-policy.ts +379 -0
  704. package/src/runtime/control-plane/runtime-cleanup.ts +727 -0
  705. package/src/runtime/control-plane/runtime-generation.ts +509 -0
  706. package/src/runtime/control-plane/runtime-pid-ownership.ts +11 -0
  707. package/src/runtime/control-plane/runtime-status-client.ts +90 -0
  708. package/src/runtime/control-plane/startup-recovery.ts +198 -0
  709. package/src/runtime/diagnostics/connectivity-observability.ts +475 -0
  710. package/src/runtime/diagnostics/mcp-timing.ts +64 -0
  711. package/src/runtime/diagnostics/performance.ts +379 -0
  712. package/src/runtime/diagnostics/process-facade.ts +350 -0
  713. package/src/runtime/diagnostics/read-only-tool.ts +226 -0
  714. package/src/runtime/evidence/artifact-store.ts +154 -0
  715. package/src/runtime/evidence/event-ledger.ts +80 -0
  716. package/src/runtime/evidence/evidence-store.ts +68 -0
  717. package/src/runtime/evidence/process-check-receipt.ts +43 -0
  718. package/src/runtime/evidence/result-store.ts +209 -0
  719. package/src/runtime/evidence/sensitive-output.ts +353 -0
  720. package/src/runtime/execution/jobs/child-reference.ts +124 -0
  721. package/src/runtime/execution/jobs/legacy-adapter.ts +22 -0
  722. package/src/runtime/execution/jobs/receipt-recovery.ts +119 -0
  723. package/src/runtime/execution/jobs/receipt-store.ts +243 -0
  724. package/src/runtime/execution/jobs/store.ts +737 -0
  725. package/src/runtime/execution/jobs/timeouts.ts +109 -0
  726. package/src/runtime/execution/jobs/types.ts +230 -0
  727. package/src/runtime/execution/jobs/wait.ts +45 -0
  728. package/src/runtime/execution/process-runtime/canary.ts +26 -0
  729. package/src/runtime/execution/process-runtime/check-facade.ts +272 -0
  730. package/src/runtime/execution/process-runtime/check-receipt.ts +185 -0
  731. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +60 -0
  732. package/src/runtime/execution/process-runtime/command-facade.ts +321 -0
  733. package/src/runtime/execution/process-runtime/gc.ts +171 -0
  734. package/src/runtime/execution/process-runtime/index.ts +9 -0
  735. package/src/runtime/execution/process-runtime/interactive-admission.ts +23 -0
  736. package/src/runtime/execution/process-runtime/process-runner-entry.ts +466 -0
  737. package/src/runtime/execution/process-runtime/resource-claims.ts +440 -0
  738. package/src/runtime/execution/process-runtime/runtime.ts +1816 -0
  739. package/src/runtime/execution/process-runtime/store.ts +687 -0
  740. package/src/runtime/execution/process-runtime/types.ts +352 -0
  741. package/src/runtime/execution/thin-harness/async-process.ts +181 -0
  742. package/src/runtime/execution/thin-harness/batch-executor.ts +671 -0
  743. package/src/runtime/execution/thin-harness/execution-router.ts +700 -0
  744. package/src/runtime/execution/thin-harness/fast-executor.ts +1263 -0
  745. package/src/runtime/execution/thin-harness/fast-receipt.ts +235 -0
  746. package/src/runtime/execution/thin-harness/fingerprint-worker.ts +191 -0
  747. package/src/runtime/execution/thin-harness/index.ts +13 -0
  748. package/src/runtime/execution/thin-harness/latency-trace.ts +107 -0
  749. package/src/runtime/execution/thin-harness/lightweight-lanes.ts +745 -0
  750. package/src/runtime/execution/thin-harness/mutation-gate.ts +578 -0
  751. package/src/runtime/execution/thin-harness/proposal-store.ts +409 -0
  752. package/src/runtime/execution/thin-harness/request-ledger.ts +595 -0
  753. package/src/runtime/execution/thin-harness/search-worker.ts +114 -0
  754. package/src/runtime/execution/thin-harness/types.ts +313 -0
  755. package/src/runtime/execution/thin-harness/workspace-savepoint.ts +333 -0
  756. package/src/runtime/execution/workers/executor.ts +687 -0
  757. package/src/runtime/execution/workers/ownership.ts +94 -0
  758. package/src/runtime/execution/workers/worker-entry.ts +277 -0
  759. package/src/runtime/gateway/mcp/execution-tools.ts +2009 -0
  760. package/src/runtime/gateway/mcp/persisted-check-process.ts +255 -0
  761. package/src/runtime/gateway/mcp/process-tools.ts +230 -0
  762. package/src/runtime/gateway/mcp/resource-policy.ts +195 -0
  763. package/src/runtime/gateway/mcp/router.ts +1088 -0
  764. package/src/runtime/gateway/mcp/runtime-tools.ts +5994 -0
  765. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +219 -0
  766. package/src/runtime/health/evaluator.ts +474 -0
  767. package/src/runtime/health/index.ts +2 -0
  768. package/src/runtime/health/operational-view.ts +198 -0
  769. package/src/runtime/maintenance/cleanup.ts +419 -0
  770. package/src/runtime/model-clients/deepseek-adapter.ts +312 -0
  771. package/src/runtime/model-clients/index.ts +2 -0
  772. package/src/runtime/model-clients/types.ts +101 -0
  773. package/src/runtime/observability/gateway-contention-metrics.ts +129 -0
  774. package/src/runtime/observability/route-session-benchmark.ts +110 -0
  775. package/src/runtime/personal-assistant/gmail-triage-manager.ts +231 -0
  776. package/src/runtime/personal-assistant/reporting-runtime.ts +344 -0
  777. package/src/runtime/personal-assistant/triage-runtime.ts +748 -0
  778. package/src/runtime/plugins/app-store-connect-adapter.ts +868 -0
  779. package/src/runtime/plugins/browser-adapter.ts +2812 -0
  780. package/src/runtime/plugins/browser-automation-service.ts +46 -0
  781. package/src/runtime/plugins/browser-handoff-host.ts +304 -0
  782. package/src/runtime/plugins/browser-handoff.ts +371 -0
  783. package/src/runtime/plugins/browser-macos-bridge.ts +865 -0
  784. package/src/runtime/plugins/browser-node-bridge-host.ts +64 -0
  785. package/src/runtime/plugins/browser-node-bridge.ts +249 -0
  786. package/src/runtime/plugins/desktop-adapter.ts +374 -0
  787. package/src/runtime/plugins/desktop-operator-registration.ts +418 -0
  788. package/src/runtime/plugins/errors.ts +39 -0
  789. package/src/runtime/plugins/execution-origin.ts +26 -0
  790. package/src/runtime/plugins/external-adapter.ts +322 -0
  791. package/src/runtime/plugins/external-registration.ts +308 -0
  792. package/src/runtime/plugins/external-unix-socket-probe.cjs +79 -0
  793. package/src/runtime/plugins/external-unix-socket.ts +238 -0
  794. package/src/runtime/plugins/first-party-registry.ts +37 -0
  795. package/src/runtime/plugins/github-adapter.ts +266 -0
  796. package/src/runtime/plugins/gmail-adapter.ts +729 -0
  797. package/src/runtime/plugins/google-calendar-adapter.ts +468 -0
  798. package/src/runtime/plugins/google-shared.ts +578 -0
  799. package/src/runtime/plugins/google-tasks-adapter.ts +535 -0
  800. package/src/runtime/plugins/interaction-session.ts +252 -0
  801. package/src/runtime/plugins/ios/agent-device-capabilities.ts +258 -0
  802. package/src/runtime/plugins/ios/agent-device-failures.ts +95 -0
  803. package/src/runtime/plugins/ios/agent-device-provider.ts +63 -0
  804. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +268 -0
  805. package/src/runtime/plugins/ios/app-adapters.ts +122 -0
  806. package/src/runtime/plugins/ios-adapter.ts +509 -0
  807. package/src/runtime/plugins/ios-agent-device.ts +2311 -0
  808. package/src/runtime/plugins/ios-physical-device.ts +955 -0
  809. package/src/runtime/plugins/local-system-adapter.ts +1016 -0
  810. package/src/runtime/plugins/macos-capability-broker.ts +73 -0
  811. package/src/runtime/plugins/managed-process-adapter.ts +366 -0
  812. package/src/runtime/plugins/resend-adapter.ts +506 -0
  813. package/src/runtime/plugins/store.ts +1025 -0
  814. package/src/runtime/plugins/types.ts +138 -0
  815. package/src/runtime/projections/controller-context.ts +596 -0
  816. package/src/runtime/projections/git-status-sampler.ts +84 -0
  817. package/src/runtime/projections/invalidation.ts +250 -0
  818. package/src/runtime/projections/materialized-view.ts +694 -0
  819. package/src/runtime/recovery/actions.ts +158 -0
  820. package/src/runtime/recovery/audit.ts +38 -0
  821. package/src/runtime/recovery/classifier.ts +163 -0
  822. package/src/runtime/recovery/index.ts +9 -0
  823. package/src/runtime/recovery/local-jobs-repair.ts +393 -0
  824. package/src/runtime/recovery/maintenance-executor.ts +822 -0
  825. package/src/runtime/recovery/patch-handoff.ts +50 -0
  826. package/src/runtime/recovery/probe.ts +308 -0
  827. package/src/runtime/recovery/store.ts +35 -0
  828. package/src/runtime/recovery/types.ts +175 -0
  829. package/src/runtime/release/identity.ts +101 -0
  830. package/src/runtime/release/release-gate.ts +137 -0
  831. package/src/runtime/resources/claims/conflicts.ts +205 -0
  832. package/src/runtime/resources/index.ts +1 -0
  833. package/src/runtime/resources/leases/store.ts +539 -0
  834. package/src/runtime/resources/leases/types.ts +50 -0
  835. package/src/runtime/resources/ownership.ts +72 -0
  836. package/src/runtime/root/controller-services.ts +42 -0
  837. package/src/runtime/root/entry.ts +70 -0
  838. package/src/runtime/root/gateway-adapter.ts +46 -0
  839. package/src/runtime/root/local-bridge.ts +72 -0
  840. package/src/runtime/root/mcp-transport.ts +198 -0
  841. package/src/runtime/root/ownership.ts +94 -0
  842. package/src/runtime/root/readiness.ts +69 -0
  843. package/src/runtime/root/release-manifest.ts +147 -0
  844. package/src/runtime/root/release-materialize.ts +509 -0
  845. package/src/runtime/root/release-store.ts +236 -0
  846. package/src/runtime/root/runtime.ts +318 -0
  847. package/src/runtime/root/scheduler.ts +58 -0
  848. package/src/runtime/root/service-runner-entry.ts +20 -0
  849. package/src/runtime/root/service-runner.ts +69 -0
  850. package/src/runtime/root/service.ts +291 -0
  851. package/src/runtime/root/status.ts +127 -0
  852. package/src/runtime/root/types.ts +112 -0
  853. package/src/runtime/root/write-fence.ts +309 -0
  854. package/src/runtime/safe-tooling/browser-safe.ts +133 -0
  855. package/src/runtime/safe-tooling/external-filesystem.ts +304 -0
  856. package/src/runtime/safe-tooling/google-credential-store.ts +95 -0
  857. package/src/runtime/safe-tooling/google-oauth-broker.ts +286 -0
  858. package/src/runtime/safe-tooling/index.ts +11 -0
  859. package/src/runtime/safe-tooling/ios-development.ts +1039 -0
  860. package/src/runtime/safe-tooling/job-summary.ts +361 -0
  861. package/src/runtime/safe-tooling/plugin-summary.ts +53 -0
  862. package/src/runtime/safe-tooling/resend-oauth.ts +387 -0
  863. package/src/runtime/safe-tooling/review-artifacts.ts +133 -0
  864. package/src/runtime/safe-tooling/types.ts +103 -0
  865. package/src/runtime/safe-tooling/workspace-auth.ts +116 -0
  866. package/src/runtime/shared/bounded-child-supervisor.ts +235 -0
  867. package/src/runtime/shared/idempotent-retry.ts +128 -0
  868. package/src/runtime/shared/json-files.ts +43 -0
  869. package/src/runtime/shared/local-bridge-surface.ts +231 -0
  870. package/src/runtime/shared/managed-env.ts +154 -0
  871. package/src/runtime/shared/node-ts-loader.mjs +50 -0
  872. package/src/runtime/shared/process-environment.ts +97 -0
  873. package/src/runtime/shared/process-identity.ts +72 -0
  874. package/src/runtime/shared/process-tree.ts +227 -0
  875. package/src/runtime/shared/response-budget.ts +246 -0
  876. package/src/runtime/standalone-recovery/core.ts +2275 -0
  877. package/src/runtime/standalone-recovery/entry.ts +686 -0
  878. package/src/runtime/standalone-recovery/http-transport.ts +317 -0
  879. package/src/runtime/standalone-recovery/installer.ts +747 -0
  880. package/src/runtime/standalone-recovery/release.ts +241 -0
  881. package/src/runtime/watchdog/workflow-watchdog.ts +118 -0
  882. package/src/runtime/workflow/campaigns/cleanup.ts +263 -0
  883. package/src/runtime/workflow/campaigns/engine.ts +112 -0
  884. package/src/runtime/workflow/campaigns/normalize.ts +100 -0
  885. package/src/runtime/workflow/campaigns/review.ts +315 -0
  886. package/src/runtime/workflow/campaigns/store.ts +526 -0
  887. package/src/runtime/workflow/campaigns/supervisor.ts +112 -0
  888. package/src/runtime/workflow/campaigns/types.ts +290 -0
  889. package/src/runtime/workflow/campaigns/workspace-agent.ts +155 -0
  890. package/src/runtime/workflow/campaigns/workspace.ts +200 -0
  891. package/src/runtime/workflow/findings/store.ts +165 -0
  892. package/src/runtime/workflow/findings/types.ts +36 -0
  893. package/src/runtime/workflow/portfolio/engine.ts +20 -0
  894. package/src/runtime/workflow/portfolio/store.ts +185 -0
  895. package/src/runtime/workflow/portfolio/types.ts +29 -0
  896. package/src/runtime/workflow/schedules/engine.ts +620 -0
  897. package/src/runtime/workflow/schedules/settlement.ts +144 -0
  898. package/src/runtime/workflow/schedules/store.ts +417 -0
  899. package/src/runtime/workflow/schedules/types.ts +124 -0
  900. package/src/runtime/workspace-targets/index.ts +24 -0
  901. package/src/runtime/workspace-targets/target-grant.ts +721 -0
  902. package/src/testing/test-governance.ts +626 -0
  903. package/src/version.ts +21 -0
@@ -0,0 +1,1312 @@
1
+ export function localBridgeDashboardHtml(): string {
2
+ return `<!doctype html>
3
+ <html lang="zh-CN">
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
7
+ <title>forge · 执行助手控制台</title>
8
+ <style>
9
+ :root{color-scheme:dark;--bg:#070b10;--panel:#0f1620;--panel2:#131c28;--line:rgba(255,255,255,.08);--text:#f3f6f9;--muted:#95a0ab;--faint:#6d7784;--green:#34d399;--amber:#fbbf24;--red:#f87171;--blue:#60a5fa;--radius:16px}
10
+ *{box-sizing:border-box}html,body{height:100%;margin:0}body{background:radial-gradient(circle at 80% -10%,rgba(52,211,153,.14),transparent 32%),linear-gradient(160deg,#05080c,#0a1118 55%,#06090d);color:var(--text);font:14px/1.5 Inter,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",system-ui,sans-serif}
11
+ button,input,textarea{font:inherit}button{cursor:pointer}.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
12
+ .app{min-height:100vh;display:grid;grid-template-rows:64px 1fr}
13
+ .top{display:flex;align-items:center;gap:12px;padding:0 18px;border-bottom:1px solid var(--line);background:rgba(8,12,18,.88);backdrop-filter:blur(16px);position:sticky;top:0;z-index:20}
14
+ .brand{display:flex;align-items:center;gap:10px;font-weight:800;min-width:180px}
15
+ .logo{width:28px;height:28px;border-radius:9px;display:grid;place-items:center;background:rgba(52,211,153,.12);color:var(--green);border:1px solid rgba(52,211,153,.28)}
16
+ .top-actions{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
17
+ .chip,.btn,.pill{border:1px solid var(--line);background:rgba(255,255,255,.04);color:var(--text);border-radius:12px;padding:8px 12px}
18
+ .chip{display:inline-flex;align-items:center;gap:8px;min-height:36px}.chip strong{font-weight:700}
19
+ .btn{min-height:38px}.btn.primary{background:linear-gradient(180deg,#2f9f6b,#1f7a51);border-color:rgba(52,211,153,.4)}.btn.danger{background:rgba(248,113,113,.12);border-color:rgba(248,113,113,.35);color:#fecaca}.btn.ghost{background:transparent}
20
+ .dot{width:8px;height:8px;border-radius:50%;background:var(--green);box-shadow:0 0 0 4px rgba(52,211,153,.12)}.dot.amber{background:var(--amber);box-shadow:0 0 0 4px rgba(251,191,36,.12)}.dot.red{background:var(--red);box-shadow:0 0 0 4px rgba(248,113,113,.12)}.dot.blue{background:var(--blue);box-shadow:0 0 0 4px rgba(96,165,250,.12)}.dot.gray{background:#7b8794}
21
+ .body{display:grid;grid-template-columns:220px 1fr;min-height:0}
22
+ .side{border-right:1px solid var(--line);padding:16px 12px;background:rgba(8,12,18,.55)}
23
+ .nav{display:grid;gap:6px}.nav button{text-align:left;width:100%;padding:11px 12px;border-radius:12px;border:1px solid transparent;background:transparent;color:var(--text)}.nav button.active,.nav button:hover{background:rgba(255,255,255,.05);border-color:var(--line)}
24
+ .nav .count{margin-left:6px;display:inline-grid;place-items:center;min-width:20px;height:20px;border-radius:999px;background:rgba(248,113,113,.18);color:#fecaca;font-size:12px;font-weight:700}
25
+ .main{padding:24px 28px 48px;overflow:auto}.main>.view{width:min(1240px,100%);margin:0 auto}
26
+ .view{display:none}.view.active{display:block}
27
+ .page-head{display:flex;justify-content:space-between;gap:12px;align-items:flex-start;margin-bottom:16px}.page-head h1{margin:0 0 4px;font-size:24px}.page-head p{margin:0;color:var(--muted)}
28
+ .grid{display:grid;gap:14px}.grid.two{grid-template-columns:1.4fr .9fr}.grid.cards{grid-template-columns:repeat(3,1fr)}.grid.stats{grid-template-columns:repeat(4,minmax(0,1fr))}
29
+ .panel{background:rgba(15,22,32,.92);border:1px solid var(--line);border-radius:var(--radius);padding:16px;box-shadow:0 18px 40px rgba(0,0,0,.22)}
30
+ .panel h2,.panel h3{margin:0 0 8px}.muted{color:var(--muted)}.faint{color:var(--faint)}
31
+ .stat strong{display:block;font-size:22px;margin-top:4px}.stat span{color:var(--muted);font-size:12px}
32
+ .plugin-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:start}
33
+ .action-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:center;padding:10px 0;border-top:1px solid var(--line)}
34
+ .action-row:first-child{border-top:0;padding-top:0}
35
+ .composer textarea,.composer input,.input,textarea,input[type=text],input[type=number]{width:100%;border:1px solid var(--line);background:rgba(0,0,0,.22);color:var(--text);border-radius:12px;padding:12px 14px}
36
+ .composer textarea{min-height:120px;resize:vertical}
37
+ .composer .row{display:flex;gap:10px;flex-wrap:wrap;margin-top:10px;align-items:center}
38
+ .mode-card{display:grid;gap:6px}.mode-card .label{font-weight:800;font-size:16px}
39
+ .pill{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;font-size:12px;font-weight:700;border-radius:999px}
40
+ .pill.green{background:rgba(52,211,153,.12);color:#a7f3d0;border-color:rgba(52,211,153,.28)}
41
+ .pill.amber{background:rgba(251,191,36,.12);color:#fde68a;border-color:rgba(251,191,36,.28)}
42
+ .pill.red{background:rgba(248,113,113,.12);color:#fecaca;border-color:rgba(248,113,113,.28)}
43
+ .pill.blue{background:rgba(96,165,250,.12);color:#bfdbfe;border-color:rgba(96,165,250,.28)}
44
+ .pill.gray{background:rgba(255,255,255,.05);color:#cbd5e1}
45
+ .steps{display:flex;flex-wrap:wrap;gap:8px;margin:10px 0}
46
+ .step{padding:6px 10px;border-radius:999px;border:1px solid var(--line);color:var(--faint);font-size:12px}.step.done{color:#a7f3d0;border-color:rgba(52,211,153,.3)}.step.active{color:#bfdbfe;border-color:rgba(96,165,250,.35)}
47
+ .actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
48
+ .list{display:grid;gap:10px}
49
+ .card-row{display:grid;grid-template-columns:1fr auto;gap:12px;align-items:start;padding:14px;border:1px solid var(--line);border-radius:14px;background:rgba(255,255,255,.02)}
50
+ .card-row h3{margin:0 0 6px;font-size:15px}.card-row p{margin:0 0 6px;color:var(--muted)}
51
+ .evidence{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}.evidence span{font-size:12px;padding:4px 8px;border-radius:999px;background:rgba(255,255,255,.04);border:1px solid var(--line);color:var(--muted)}
52
+ details.advanced{margin-top:12px;border-top:1px dashed var(--line);padding-top:10px}.advanced summary{cursor:pointer;color:var(--muted)}
53
+ .toast{position:fixed;right:18px;bottom:18px;background:#111827;border:1px solid var(--line);padding:12px 14px;border-radius:12px;opacity:0;transform:translateY(8px);transition:.2s;z-index:50;max-width:360px}.toast.show{opacity:1;transform:none}
54
+ .empty{padding:22px;border:1px dashed var(--line);border-radius:14px;color:var(--muted);text-align:center}
55
+ .section-title{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
56
+ .warn{padding:10px 12px;border-radius:12px;background:rgba(251,191,36,.08);border:1px solid rgba(251,191,36,.25);color:#fde68a;margin-bottom:12px}
57
+ .errbox{padding:12px 14px;border-radius:12px;background:rgba(248,113,113,.08);border:1px solid rgba(248,113,113,.28);color:#fecaca;margin:10px 0}
58
+ .errbox h4{margin:0 0 6px;font-size:14px}.errbox .muted{color:#fca5a5}
59
+ .setup{padding:14px 16px;border-radius:14px;background:rgba(96,165,250,.08);border:1px solid rgba(96,165,250,.28);margin-bottom:14px}
60
+ .files{display:grid;gap:6px;margin-top:8px}.file-row{display:flex;justify-content:space-between;gap:10px;padding:6px 8px;border-radius:8px;background:rgba(255,255,255,.03);border:1px solid var(--line);font-size:12px}
61
+ .opbar{margin-bottom:12px;padding:10px 12px;border-radius:12px;border:1px solid var(--line);background:rgba(255,255,255,.03);display:flex;gap:10px;align-items:center;flex-wrap:wrap}
62
+ .opbar.running{border-color:rgba(96,165,250,.35);background:rgba(96,165,250,.08)}
63
+ .opbar.ok{border-color:rgba(52,211,153,.35);background:rgba(52,211,153,.08)}
64
+ .opbar.err{border-color:rgba(248,113,113,.35);background:rgba(248,113,113,.08)}
65
+ .btn:disabled{opacity:.55;cursor:not-allowed}
66
+ .busy-banner{font-size:12px;color:var(--muted)}
67
+ .refresh-meta{font-size:12px;color:var(--faint);margin-left:auto}
68
+ .composer h2{font-size:20px}.composer .hint{color:var(--muted);margin:0 0 10px;font-size:13px}
69
+ .decision-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:12px 0}.decision-box{padding:12px;border:1px solid var(--line);border-radius:12px;background:rgba(255,255,255,.025)}.decision-box strong{display:block;margin-bottom:5px}.decision-box p{margin:0;color:var(--muted)}
70
+ .flow{display:flex;align-items:stretch;gap:6px;margin:12px 0;overflow:auto}.flow-step{min-width:130px;flex:1;padding:9px 10px;border-radius:10px;border:1px solid var(--line);background:rgba(255,255,255,.025);color:var(--muted);font-size:12px}.flow-arrow{display:grid;place-items:center;color:var(--faint)}
71
+ @media(max-width:980px){.body{grid-template-columns:1fr}.side{display:none}.grid.two,.grid.cards,.grid.stats,.decision-grid{grid-template-columns:1fr}.top{flex-wrap:wrap;height:auto;padding:10px 12px}}
72
+ </style>
73
+ </head>
74
+ <body>
75
+ <div class="app">
76
+ <header class="top">
77
+ <div class="brand"><span class="logo">∞</span><span>执行助手控制台</span></div>
78
+ <button class="chip" id="repoChip" onclick="switchView('repositories')">仓库 · <strong id="topRepo">—</strong></button>
79
+ <span class="chip"><span class="dot" id="readyDot"></span><strong id="topReady">检查中</strong></span>
80
+ <span class="chip"><span class="dot" id="connectorDot"></span><span id="topConnector">连接</span></span>
81
+ <button class="chip" onclick="switchView('capabilities')">插件 <strong id="topPlugins">—</strong></button>
82
+ <button class="chip" onclick="switchView('inbox')">需要处理 <span class="count" id="topHandoffs">0</span></button>
83
+ <div class="top-actions">
84
+ <button class="btn ghost" onclick="refreshAll()">刷新</button>
85
+ <button class="btn ghost" onclick="switchView('advanced')">高级</button>
86
+ </div>
87
+ </header>
88
+ <div class="body">
89
+ <aside class="side">
90
+ <nav class="nav">
91
+ <button class="active" data-view="home">⌂ 指挥中心</button>
92
+ <button data-view="inbox">△ 需要处理 <span class="count" id="sideHandoffs">0</span></button>
93
+ <button data-view="work">▷ 当前任务</button>
94
+ <button data-view="capabilities">◇ 能力 / 插件 <span class="count" id="sidePlugins" style="display:none">0</span></button>
95
+ <button data-view="automation">⚙ 模型与工具</button>
96
+ <button data-view="readiness">◎ 系统状态</button>
97
+ <button data-view="repositories">□ 仓库</button>
98
+ <button data-view="advanced">⌁ 高级诊断</button>
99
+ </nav>
100
+ </aside>
101
+ <main class="main">
102
+ <section class="view active" id="view-home"></section>
103
+ <section class="view" id="view-inbox"></section>
104
+ <section class="view" id="view-work"></section>
105
+ <section class="view" id="view-capabilities"></section>
106
+ <section class="view" id="view-automation"></section>
107
+ <section class="view" id="view-readiness"></section>
108
+ <section class="view" id="view-repositories"></section>
109
+ <section class="view" id="view-advanced"></section>
110
+ </main>
111
+ </div>
112
+ </div>
113
+ <div class="toast" id="toast"></div>
114
+ <script>
115
+ function safeGet(k){try{return sessionStorage.getItem(k)||''}catch(_e){return ''}}
116
+ function safeSet(k,v){try{if(v)sessionStorage.setItem(k,v);else sessionStorage.removeItem(k)}catch(_e){}}
117
+ function queryRepoId(){try{return new URLSearchParams(location.search).get('repoId')||''}catch(_e){return ''}}
118
+ function setQueryRepoId(id){try{var u=new URL(location.href);if(id)u.searchParams.set('repoId',id);else u.searchParams.delete('repoId');history.replaceState(null,'',u)}catch(_e){}}
119
+ function esc(v){return String(v==null?'':v).replace(/[&<>"']/g,function(c){return({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[c]})}
120
+ function arr(v){return Array.isArray(v)?v:[]}
121
+ function obj(v){return v&&typeof v==='object'&&!Array.isArray(v)?v:{}}
122
+ function toast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show')},2800)}
123
+ function pill(tone,label){return '<span class="pill '+esc(tone||'gray')+'">'+esc(label||'')+'</span>'}
124
+ function setDot(id,tone){document.getElementById(id).className='dot '+(tone&&tone!=='green'?tone:'')}
125
+
126
+ var selectedRepoId=queryRepoId()||safeGet('forgeSelectedRepoId')||'';
127
+ var commandCenter=null;
128
+ var automationSettings=null;
129
+ var selectedWorkId=safeGet('forgeSelectedWorkId')||'';
130
+ var selectedHandoffId='';
131
+ var selectedPluginId=safeGet('forgeSelectedPluginId')||'';
132
+ var modePreview=null;
133
+ var advancedRaw=null;
134
+ var lastFacade=null;
135
+ var lastOperation=null; // {phase,statusLabel,summary,errorMessage,at}
136
+ var pluginActionResult=null;
137
+ var busy=false;
138
+ var pollTimer=null;
139
+ var refreshInFlight=false;
140
+ var lastRefreshedAt='';
141
+ var pageVisible=!document.hidden;
142
+ var workExtras={}; // workId -> {changedFiles, error, summary}
143
+
144
+ document.addEventListener('visibilitychange',function(){
145
+ pageVisible=!document.hidden;
146
+ if(!pageVisible){
147
+ if(pollTimer){clearInterval(pollTimer);pollTimer=null}
148
+ return;
149
+ }
150
+ ensurePoll();
151
+ if(shouldPoll())refreshAll({silent:true});
152
+ });
153
+
154
+ function repoQuery(){return selectedRepoId?'?repoId='+encodeURIComponent(selectedRepoId):''}
155
+ function rememberRepo(id){selectedRepoId=id||'';safeSet('forgeSelectedRepoId',selectedRepoId);setQueryRepoId(selectedRepoId)}
156
+ function rememberWork(id){selectedWorkId=id||'';safeSet('forgeSelectedWorkId',selectedWorkId)}
157
+ function api(path,opts){opts=opts||{};var headers=Object.assign({'content-type':'application/json'},opts.headers||{});return fetch(path,Object.assign({},opts,{credentials:'same-origin',headers:headers})).then(function(r){return r.json().catch(function(){return{}}).then(function(body){if(!r.ok){var msg=(body.error&&body.error.title)||body.summary||body.errorMessage||body.error||body.message||('请求失败 '+r.status);if(!msg||msg==='undefined')msg='请求失败,请查看高级诊断';var err=new Error(msg);err.payload=body;err.status=r.status;throw err}return body})})}
158
+ function setBusy(on,label){
159
+ busy=!!on;
160
+ document.querySelectorAll('button.btn').forEach(function(b){
161
+ if(on)b.setAttribute('disabled','disabled');else b.removeAttribute('disabled');
162
+ });
163
+ if(on){
164
+ lastOperation={phase:'running',statusLabel:label||'执行中',summary:label||'正在处理…',at:new Date().toISOString()};
165
+ renderOpBar();
166
+ }
167
+ }
168
+ function setLastOp(res,fallback){
169
+ res=obj(res);
170
+ var feedback=obj(res.feedback);
171
+ var phase=feedback.phase||res.phase||(res.status==='ok'?'succeeded':(res.status==='failed'||res.status==='blocked'||res.status==='approval_required')?'failed':'succeeded');
172
+ var next='';
173
+ var actions=arr(feedback.suggestedNextActions||res.suggestedNextActions);
174
+ if(actions.length)next=actions[0].label||'';
175
+ if(feedback.error&&feedback.error.nextActions&&feedback.error.nextActions[0])next=next||feedback.error.nextActions[0];
176
+ lastOperation={
177
+ phase:phase,
178
+ statusLabel:feedback.statusLabel||res.statusLabel||fallback||'已更新',
179
+ summary:feedback.summary||res.summary||fallback||'操作已完成',
180
+ errorMessage:(feedback.error&&feedback.error.title)||res.errorMessage||'',
181
+ error:feedback.error||res.error||null,
182
+ next:next,
183
+ changedFiles:feedback.changedFiles||res.changedFiles||null,
184
+ at:new Date().toISOString()
185
+ };
186
+ // Remember changed files / errors against active work for card rendering.
187
+ var wid=selectedWorkId||(res.data&&(res.data.work&&(res.data.work.workId||res.data.work.id)||res.data.workId));
188
+ if(wid){
189
+ workExtras[wid]=workExtras[wid]||{};
190
+ if(lastOperation.changedFiles)workExtras[wid].changedFiles=lastOperation.changedFiles;
191
+ if(lastOperation.error)workExtras[wid].error=lastOperation.error;
192
+ if(lastOperation.summary)workExtras[wid].summary=lastOperation.summary;
193
+ }
194
+ lastFacade=res;
195
+ renderOpBar();
196
+ }
197
+ function renderOpBar(){
198
+ var nodes=document.querySelectorAll('#opBar');
199
+ if(!nodes.length)return;
200
+ var html='';
201
+ if(lastOperation){
202
+ var cls=lastOperation.phase==='running'||lastOperation.phase==='queued'||lastOperation.phase==='waiting'||lastOperation.phase==='submitting'?'running':(lastOperation.phase==='failed'||lastOperation.phase==='timed_out'||lastOperation.phase==='blocked'||lastOperation.phase==='needs_attention')?'err':'ok';
203
+ html='<div class="opbar '+cls+'">'+
204
+ '<span class="pill '+(cls==='ok'?'green':cls==='err'?'red':'blue')+'">'+esc(lastOperation.statusLabel)+'</span>'+
205
+ '<span>'+esc(lastOperation.summary||'')+'</span>'+
206
+ (lastOperation.errorMessage?'<span class="muted">'+esc(lastOperation.errorMessage)+'</span>':'')+
207
+ (lastOperation.next?'<span class="muted">下一步:'+esc(lastOperation.next)+'</span>':'')+
208
+ (busy?'<span class="busy-banner">请稍候,勿重复点击…</span>':'')+
209
+ (lastRefreshedAt?'<span class="refresh-meta">刷新于 '+esc(lastRefreshedAt)+'</span>':'')+
210
+ '</div>';
211
+ if(lastOperation.error&&lastOperation.error.title){
212
+ html+=renderErrorBox(lastOperation.error);
213
+ }
214
+ } else if(lastRefreshedAt){
215
+ html='<div class="opbar"><span class="refresh-meta">刷新于 '+esc(lastRefreshedAt)+'</span></div>';
216
+ }
217
+ nodes.forEach(function(n){n.innerHTML=html});
218
+ }
219
+ function renderErrorBox(err){
220
+ err=obj(err);
221
+ if(!err.title)return '';
222
+ var next=arr(err.nextActions).map(function(a){return '<span class="pill amber">'+esc(a)+'</span>'}).join(' ');
223
+ return '<div class="errbox"><h4>'+esc(err.title)+'</h4><div class="muted">'+esc(err.explanation||'')+'</div>'+(next?'<div class="actions" style="margin-top:8px">'+next+'</div>':'')+
224
+ '<details class="advanced"><summary>高级详情(仅调试)</summary><pre class="mono" style="white-space:pre-wrap;font-size:12px">'+esc(JSON.stringify(err,null,2))+'</pre></details></div>';
225
+ }
226
+ function renderChangedFiles(summary){
227
+ summary=obj(summary);
228
+ if(!summary.total&&!arr(summary.files).length)return '';
229
+ var files=arr(summary.files).slice(0,12);
230
+ return '<div style="margin-top:10px"><div class="section-title"><strong>改动文件</strong>'+pill('blue',summary.summaryLabel||((summary.total||files.length)+' 个文件'))+'</div>'+
231
+ '<div class="files">'+files.map(function(f){
232
+ return '<div class="file-row"><span class="mono">'+esc(f.path)+'</span><span class="pill gray">'+esc(f.statusLabel||f.status||'修改')+'</span></div>';
233
+ }).join('')+'</div>'+
234
+ (files.length<(summary.total||0)?'<div class="faint" style="margin-top:6px">仅显示前 '+files.length+' 项</div>':'')+
235
+ '</div>';
236
+ }
237
+ function shouldPoll(){
238
+ if(!pageVisible||refreshInFlight)return false;
239
+ var work=obj(commandCenter&&commandCenter.currentWork);
240
+ if(!work||!work.id)return false;
241
+ var phase=work.phase||'';
242
+ return phase==='running'||phase==='queued'||phase==='waiting'||phase==='submitting'||work.tone==='blue'||work.statusLabel==='进行中'||work.statusLabel==='待开始';
243
+ }
244
+ function ensurePoll(){
245
+ if(!pageVisible||pollTimer)return;
246
+ pollTimer=setInterval(function(){
247
+ if(!shouldPoll()){
248
+ if(pollTimer){clearInterval(pollTimer);pollTimer=null}
249
+ return;
250
+ }
251
+ refreshAll({silent:true});
252
+ },3500);
253
+ }
254
+
255
+ function switchView(name){
256
+ document.querySelectorAll('.nav button').forEach(function(b){b.classList.toggle('active',b.dataset.view===name)});
257
+ document.querySelectorAll('.view').forEach(function(v){v.classList.toggle('active',v.id==='view-'+name)});
258
+ renderAll();
259
+ }
260
+ document.querySelectorAll('.nav button[data-view]').forEach(function(b){b.addEventListener('click',function(){switchView(b.dataset.view)})});
261
+
262
+ function btn(label, attrs, cls){
263
+ return '<button class="btn'+(cls?(' '+cls):'')+'" '+attrs+'>'+esc(label)+'</button>';
264
+ }
265
+ function stepsHtml(steps){
266
+ return '<div class="steps">'+arr(steps).map(function(s){return '<span class="step '+(s.done?'done':'')+(s.active?' active':'')+'">'+esc(s.label)+'</span>'}).join('')+'</div>';
267
+ }
268
+
269
+ function evidenceHtml(labels){
270
+ if(!arr(labels).length)return '';
271
+ return '<div class="evidence">'+arr(labels).map(function(x){return '<span>'+esc(x)+'</span>'}).join('')+'</div>';
272
+ }
273
+
274
+ function advancedBlock(data){
275
+ if(!data)return '';
276
+ return '<details class="advanced"><summary>高级详情</summary><pre class="mono" style="white-space:pre-wrap;color:var(--muted);font-size:12px">'+esc(JSON.stringify(data,null,2))+'</pre></details>';
277
+ }
278
+
279
+ function renderChrome(){
280
+ var cc=obj(commandCenter), ready=obj(cc.readiness), repo=obj(cc.currentRepository);
281
+ var plug=obj(cc.pluginSummary);
282
+ document.getElementById('topRepo').textContent=repo.name||'未选择';
283
+ document.getElementById('topReady').textContent=ready.label||'未知';
284
+ setDot('readyDot', ready.state==='blocked'?'red':ready.state==='needs_setup'?'amber':'green');
285
+ document.getElementById('topConnector').textContent=ready.connectorLabel||'连接';
286
+ setDot('connectorDot', ready.connectorTone||'gray');
287
+ var n=ready.pendingHandoffCount||arr(cc.handoffs).length||0;
288
+ document.getElementById('topHandoffs').textContent=n;
289
+ document.getElementById('sideHandoffs').textContent=n;
290
+ var readyPlugins=plug.ready||0, totalPlugins=plug.total||arr(cc.plugins).length||0;
291
+ document.getElementById('topPlugins').textContent=totalPlugins?(readyPlugins+'/'+totalPlugins):'—';
292
+ var need=plug.needsAttention||0;
293
+ var sidePlugins=document.getElementById('sidePlugins');
294
+ if(sidePlugins){
295
+ if(need>0){sidePlugins.style.display='inline-grid';sidePlugins.textContent=String(need)}
296
+ else {sidePlugins.style.display='none'}
297
+ }
298
+ }
299
+
300
+ function renderHome(){
301
+ var cc=obj(commandCenter), ready=obj(cc.readiness), work=obj(cc.currentWork), handoffs=arr(cc.handoffs).slice(0,3);
302
+ var repo=obj(cc.currentRepository);
303
+ var setup=obj(cc.setupGuide);
304
+ var warnings=arr(cc.warnings).map(function(w){return '<div class="warn">'+esc(w)+'</div>'}).join('');
305
+ var mode=obj(modePreview||cc.modePreviewDefault);
306
+ var el=document.getElementById('view-home');
307
+ var setupHtml=setup.needed
308
+ ? '<div class="setup"><strong>'+esc(setup.title||'需要先设置仓库')+'</strong><p class="muted" style="margin:6px 0 10px">'+esc(setup.body||'')+'</p>'+btn(setup.actionLabel||'去设置仓库','data-nav="repositories"','primary')+'</div>'
309
+ : '';
310
+ el.innerHTML=
311
+ '<div id="opBar"></div>'+
312
+ warnings+
313
+ setupHtml+
314
+ '<div class="page-head"><div><h1>指挥中心</h1><p>描述目标,开始执行,然后只关注当前进度和需要你决定的事项。</p></div>'+
315
+ '<div class="muted">当前仓库:<strong>'+esc(repo.name||'未选择')+'</strong>'+(repo.branchLabel?' · '+esc(repo.branchLabel):'')+(repo.dirtyLabel?' · '+esc(repo.dirtyLabel):'')+'</div></div>'+
316
+ '<div class="panel composer">'+
317
+ '<div class="section-title"><div><h2>你想让它完成什么?</h2><p class="hint">直接描述目标。路径、验收标准和执行模式由系统先判断,你仍可在开始前预览。</p></div>'+pill(ready.state==='ready'?'green':ready.state==='needs_setup'?'amber':'red',ready.label||'未知')+'</div>'+
318
+ '<textarea id="taskObjective" placeholder="例如:优化 Controller 首页的信息层级,让当前任务和待决定事项更容易找到,不改变后端行为。"></textarea>'+
319
+ '<details class="advanced" style="margin-top:10px"><summary>补充验收标准和允许修改的路径</summary>'+
320
+ '<div class="row" style="margin-top:10px"><input class="input" id="taskAcceptance" placeholder="验收标准(可选,用分号分隔)" style="flex:1"></div>'+
321
+ '<div class="row"><input class="input" id="taskPaths" placeholder="允许修改的路径(可选,逗号分隔)" style="flex:1"><input class="input" id="taskFiles" type="number" min="0" placeholder="预计文件数" style="width:140px"></div>'+
322
+ '</details>'+
323
+ '<div class="row" style="margin-top:14px">'+
324
+ '<button class="btn primary" id="btnStart" onclick="startTask()">开始执行</button>'+
325
+ '<button class="btn" id="btnPreview" onclick="previewMode()">预览执行方式</button>'+
326
+ '<button class="btn ghost" onclick="diagnoseFirst()">只做诊断</button>'+
327
+ '<span class="muted" style="margin-left:auto">建议:<strong>'+esc(mode.label||'直接执行')+'</strong></span>'+
328
+ '</div>'+
329
+ '</div>'+
330
+ '<div class="grid two" style="margin-top:16px">'+
331
+ renderWorkCard(work, '当前任务')+
332
+ '<div class="panel"><div class="section-title"><h2>需要处理</h2>'+btn('查看全部','data-nav="inbox"','ghost')+'</div>'+
333
+ (handoffs.length?handoffs.map(function(h){return handoffMini(h)}).join(''):'<div class="empty">目前没有需要你拍板的事项</div>')+
334
+ '</div>'+
335
+ '</div>'+
336
+ '<div class="panel" style="margin-top:16px">'+
337
+ '<div class="section-title"><div><h2>运行状态</h2><p class="muted" style="margin:0">'+esc(ready.headline||ready.description||'系统状态可用')+'</p></div>'+pill(ready.connectorTone||'gray',ready.connectorLabel||'连接')+'</div>'+
338
+ '<div class="actions">'+btn('系统状态','data-nav="readiness"')+btn('能力与插件','data-nav="capabilities"')+btn('模型与工具','data-nav="automation"')+btn('切换仓库','data-nav="repositories"')+'</div>'+
339
+ '</div>'+
340
+ renderGoalLoopPanel(cc.goalLoop);
341
+ bindNav(el);
342
+ renderOpBar();
343
+ }
344
+
345
+ function renderGoalLoopPanel(gl){
346
+ gl=obj(gl);
347
+ var goals=arr(gl.goals);
348
+ var inv=arr(gl.invokableProviders);
349
+ var handoff=arr(gl.handoffOnlyProviders);
350
+ var active=gl.activeCount||goals.length||0;
351
+ return '<details class="panel advanced" style="margin-top:16px">'+
352
+ '<summary style="display:flex;align-items:center;gap:10px;list-style:none">'+
353
+ '<strong>自动化目标</strong>'+pill(active?'blue':'gray',active+' 个活跃目标')+
354
+ '<span class="muted">'+inv.length+' 个提供方可直接调用 · '+handoff.length+' 个仅支持 Handoff</span>'+
355
+ '<span class="muted" style="margin-left:auto">展开查看</span>'+
356
+ '</summary>'+
357
+ '<div style="margin-top:14px">'+
358
+ (gl.automationSummary?'<p class="muted">'+esc(gl.automationSummary)+'</p>':'')+
359
+ (goals.length?goals.slice(0,3).map(function(g){
360
+ return '<div class="card-row" style="margin-top:10px"><div>'+
361
+ '<h3>'+esc(g.title||'目标')+'</h3>'+
362
+ '<p class="muted">阶段:'+esc(g.stage)+' · 提供方:'+esc(g.providerSelected||'—')+'</p>'+
363
+ (g.whatIsBlocked?'<p class="muted">阻塞:'+esc(g.whatIsBlocked)+'</p>':'')+
364
+ (g.whatHappensNext?'<p class="faint">下一步:'+esc(g.whatHappensNext)+'</p>':'')+
365
+ '</div>'+pill(g.approvalRequired?'amber':g.handoffPacketAvailable?'blue':'green',g.handoffPacketAvailable?'有 Handoff 包':g.stage)+'</div>';
366
+ }).join(''):'<div class="empty">暂无活跃自动化目标</div>')+
367
+ '<div class="actions">'+btn('打开模型与工具','data-nav="automation"')+'</div>'+
368
+ '</div>'+
369
+ '</details>';
370
+ }
371
+
372
+ function mergeWorkExtras(work){
373
+ work=obj(work);
374
+ var extra=obj(workExtras[work.id]);
375
+ if(extra.changedFiles&&!work.changedFiles)work.changedFiles=extra.changedFiles;
376
+ if(extra.error&&!work.error)work.error=extra.error;
377
+ if(extra.summary&&!work.latestSummary)work.latestSummary=extra.summary;
378
+ return work;
379
+ }
380
+
381
+ function renderWorkCard(work, title){
382
+ work=mergeWorkExtras(obj(work));
383
+ if(!work.id){
384
+ return '<div class="panel"><div class="section-title"><h2>'+esc(title||'当前任务')+'</h2></div><div class="empty">还没有任务。在左侧描述目标并点击“开始”。</div></div>';
385
+ }
386
+ var v=obj(work.latestVerification);
387
+ var id=esc(work.id);
388
+ var primary=work.primaryActionLabel||work.nextAction||'继续';
389
+ var primaryKind='continue';
390
+ var suggested=arr(work.suggestedActions);
391
+ if(suggested.length&&suggested[0].kind)primaryKind=suggested[0].kind;
392
+ return '<div class="panel work-card" data-work-id="'+id+'">'+
393
+ '<div class="section-title"><h2>'+esc(title||'当前任务')+'</h2>'+pill(work.tone, work.statusLabel||work.phaseLabel||'状态')+'</div>'+
394
+ '<h3 style="margin:0 0 6px">'+esc(work.title||work.objective||'未命名任务')+'</h3>'+
395
+ '<div class="muted">模式:'+esc(work.modeLabel||'—')+' · 阶段:'+esc(work.phaseLabel||work.statusLabel||'—')+'</div>'+
396
+ '<div class="muted" style="margin-top:4px">最近动作:'+esc(work.latestAction||primary)+'</div>'+
397
+ (work.latestSummary?'<p class="muted" style="margin:8px 0 0">'+esc(work.latestSummary)+'</p>':'')+
398
+ stepsHtml(work.progressSteps)+
399
+ (v.summary?'<div style="margin-top:8px">'+pill(v.tone,v.label)+' <span class="muted">'+esc(v.summary)+'</span></div>':'')+
400
+ (work.error?renderErrorBox(work.error):'')+
401
+ renderChangedFiles(work.changedFiles)+
402
+ (work.delegateSummary?'<p class="muted" style="margin-top:8px">'+esc(work.delegateSummary)+'</p>':'')+
403
+ evidenceHtml(work.evidenceLabels)+
404
+ (arr(work.acceptanceCriteria).length?'<p class="faint" style="margin-top:8px">验收:'+esc(arr(work.acceptanceCriteria).join(' · '))+'</p>':'')+
405
+ '<div class="actions">'+
406
+ btn(primary,'data-work-act="'+(primaryKind==='verify'?'verify':primaryKind==='finalize'?'finalize':primaryKind==='repair'?'repair':'continue')+'" data-work-id="'+id+'"','primary')+
407
+ btn('验证','data-work-act="verify" data-work-id="'+id+'"')+
408
+ btn('委派 Codex','data-work-act="delegate-codex" data-work-id="'+id+'"')+
409
+ btn('请 Grok 审阅','data-work-act="delegate-grok" data-work-id="'+id+'"')+
410
+ btn('修复诊断','data-work-act="repair" data-work-id="'+id+'"')+
411
+ btn('收尾','data-work-act="finalize" data-work-id="'+id+'"')+
412
+ btn('停止','data-work-act="stop" data-work-id="'+id+'"','danger')+
413
+ btn('打开详情','data-open-work="'+id+'"','ghost')+
414
+ '</div>'+
415
+ advancedBlock(work.advanced)+
416
+ '</div>';
417
+ }
418
+
419
+ function handoffMini(h){
420
+ var id=esc(h.id);
421
+ var d=obj(h.decision);
422
+ return '<div class="card-row" style="margin-bottom:8px">'+
423
+ '<div><div style="margin-bottom:6px">'+pill(h.tone,d.typeLabel||h.severityLabel||'需要决定')+'</div><h3>'+esc(h.title)+'</h3>'+
424
+ '<p><strong>需要你决定:</strong>'+esc(d.requestedAction||h.reason||'请打开查看详情')+'</p>'+
425
+ '<div class="faint">'+esc(d.afterApproval||h.recommendedDecision||'请先阅读详情')+'</div></div>'+
426
+ '<div class="actions" style="flex-direction:column">'+
427
+ btn(d.canApproveAndContinue?'查看审批详情':'查看并决定','data-open-handoff="'+id+'"','primary')+
428
+ '</div></div>';
429
+ }
430
+
431
+ function renderInbox(){
432
+ var items=arr(obj(commandCenter).handoffs);
433
+ var detail=selectedHandoffId?items.find(function(x){return x.id===selectedHandoffId}):null;
434
+ if(!detail&&items.length){selectedHandoffId=items[0].id;detail=items[0]}
435
+ var root=document.getElementById('view-inbox');
436
+ root.innerHTML=
437
+ '<div class="page-head"><div><h1>需要处理</h1><p>这里只展示真正阻塞执行的业务决定、不可逆操作和无法自动恢复的问题。</p></div><button class="btn" onclick="refreshAll()">刷新</button></div>'+
438
+ '<div class="grid two">'+
439
+ '<div class="list">'+(items.length?items.map(function(h){
440
+ var id=esc(h.id);var d=obj(h.decision);
441
+ return '<div class="panel" style="padding:14px;cursor:pointer;border-color:'+(selectedHandoffId===h.id?'rgba(96,165,250,.45)':'')+'" data-open-handoff="'+id+'">'+
442
+ '<div class="section-title"><h3 style="margin:0">'+esc(h.title)+'</h3>'+pill(h.tone,d.typeLabel||h.severityLabel)+'</div>'+
443
+ '<p class="muted"><strong>需要决定:</strong>'+esc(d.requestedAction||h.reason)+'</p>'+
444
+ '<p class="faint"><strong>处理后:</strong>'+esc(d.afterApproval||h.recommendedDecision||'—')+'</p></div>';
445
+ }).join(''):'<div class="empty">没有待审批或待决定事项。你可以回到指挥中心开始新任务。</div>')+'</div>'+
446
+ '<div class="panel" id="handoffDetail">'+(detail?renderHandoffDetail(detail):'<div class="empty">选择左侧事项查看详情</div>')+'</div>'+
447
+ '</div>';
448
+ bindActions(root);
449
+ }
450
+
451
+ function renderHandoffDetail(h){
452
+ var id=esc(h.id);var d=obj(h.decision);
453
+ var primary=d.canApproveAndContinue
454
+ ? btn(d.primaryActionLabel||'批准并继续执行','data-handoff-act="approve" data-handoff-id="'+id+'"','primary')
455
+ : btn(d.primaryActionLabel||'记录决定','data-handoff-act="resolve" data-handoff-id="'+id+'"','primary');
456
+ return '<div class="section-title"><div><h2>'+esc(h.title)+'</h2><div>'+pill(h.tone,d.typeLabel||h.severityLabel)+' '+pill(d.necessityLabel==='必须确认'?'amber':'gray',d.necessityLabel||'需要判断')+'</div></div>'+pill(h.tone,h.statusLabel)+'</div>'+
457
+ '<div class="setup" style="margin:12px 0"><strong>你正在批准 / 决定什么</strong><p class="muted" style="margin:6px 0 0">'+esc(d.requestedAction||h.reason||'—')+'</p></div>'+
458
+ '<div class="decision-grid">'+
459
+ '<div class="decision-box"><strong>是否有必要</strong><p>'+esc(d.necessityExplanation||h.reason||'—')+'</p></div>'+
460
+ '<div class="decision-box"><strong>会产生什么影响</strong><p>'+esc(d.impact||'—')+'</p></div>'+
461
+ '<div class="decision-box"><strong>批准 / 记录后</strong><p>'+esc(d.afterApproval||'—')+'</p></div>'+
462
+ '<div class="decision-box"><strong>不批准会怎样</strong><p>'+esc(d.ifRejected||'—')+'</p></div>'+
463
+ '</div>'+
464
+ '<div class="flow"><div class="flow-step">1. 当前停在安全点</div><div class="flow-arrow">→</div><div class="flow-step">2. 阅读对象、必要性和影响</div><div class="flow-arrow">→</div><div class="flow-step">3. '+esc(d.canApproveAndContinue?'批准后创建任务':'记录决定或补充信息')+'</div><div class="flow-arrow">→</div><div class="flow-step">4. 打开任务详情并显示下一步</div></div>'+
465
+ '<p><strong>为什么停下来</strong><br><span class="muted">'+esc(h.reason)+'</span></p>'+
466
+ '<p><strong>相关任务</strong><br><span class="muted">'+esc(h.workTitle||'尚未创建任务')+'</span></p>'+
467
+ '<div class="setup" style="margin:10px 0"><strong>系统建议</strong><p class="muted" style="margin:6px 0 0">'+esc(h.recommendedDecision||'请阅读后自行判断')+'</p></div>'+
468
+ (arr(h.attemptedActions).length?'<p><strong>已尝试</strong><br><span class="muted">'+esc(h.attemptedActions.join(' · '))+'</span></p>':'')+
469
+ evidenceHtml(h.evidenceLabels)+
470
+ '<div class="actions">'+primary+
471
+ (d.canApproveAndContinue?btn('仅记录其他决定','data-handoff-act="resolve" data-handoff-id="'+id+'"'):'')+
472
+ btn('确认已知晓','data-handoff-act="ack" data-handoff-id="'+id+'"')+
473
+ btn('暂不处理','data-handoff-act="dismiss" data-handoff-id="'+id+'"')+
474
+ (h.continuationPrompt?btn('复制人工继续提示','data-copy="1" data-copy-text="'+esc(h.continuationPrompt)+'"'):'')+
475
+ (h.advanced&&h.advanced.workId?btn('查看相关任务','data-open-work="'+esc(h.advanced.workId)+'"'):'')+
476
+ '</div>'+
477
+ advancedBlock(h.advanced);
478
+ }
479
+
480
+ function renderWork(){
481
+ var work=null;
482
+ if(selectedWorkId){
483
+ var all=[obj(commandCenter).currentWork].concat(arr(obj(commandCenter).recentWork));
484
+ work=all.find(function(w){return w&&w.id===selectedWorkId})||obj(commandCenter).currentWork;
485
+ } else {
486
+ work=obj(commandCenter).currentWork;
487
+ }
488
+ var recent=arr(obj(commandCenter).recentWork);
489
+ var root=document.getElementById('view-work');
490
+ root.innerHTML=
491
+ '<div class="page-head"><div><h1>任务详情</h1><p>用自然语言理解进度,不必关心内部 ID。</p></div></div>'+
492
+ renderWorkCard(work,'任务')+
493
+ '<div class="panel" style="margin-top:14px"><div class="section-title"><h2>最近任务</h2></div>'+
494
+ (recent.length?recent.map(function(w){
495
+ return '<div class="card-row" style="margin-bottom:8px"><div><h3>'+esc(w.title)+'</h3><div class="muted">'+esc(w.modeLabel)+' · '+esc(w.statusLabel)+'</div></div>'+
496
+ btn('打开','data-open-work="'+esc(w.id)+'"')+'</div>';
497
+ }).join(''):'<div class="empty">暂无任务记录</div>')+
498
+ '</div>';
499
+ bindActions(root);
500
+ }
501
+
502
+ function renderConnectorHowToFix(fresh){
503
+ fresh=obj(fresh);
504
+ var steps=arr(fresh.howToFix);
505
+ if(!steps.length && !fresh.summary) return '';
506
+ var actions=arr(fresh.suggestedActions);
507
+ return '<div class="panel" style="margin-top:14px">'+
508
+ '<div class="section-title"><h2 style="margin:0">连接器诊断</h2>'+pill(fresh.severity==='error'?'red':fresh.severity==='warning'?'amber':fresh.severity==='ok'?'green':'blue', fresh.severity||'info')+'</div>'+
509
+ '<p class="muted">'+esc(fresh.summary||'')+'</p>'+
510
+ (arr(fresh.expectedFacadeTools).length?'<p class="faint">期望 facade:'+esc(arr(fresh.expectedFacadeTools).join(' · '))+'</p>':'')+
511
+ (arr(fresh.missingLocalTools).length?'<p class="muted">本地缺失:'+esc(arr(fresh.missingLocalTools).join(', '))+'</p>':'')+
512
+ (arr(fresh.missingConnectorTools).length?'<p class="muted">连接器快照缺失:'+esc(arr(fresh.missingConnectorTools).join(', '))+'</p>':'')+
513
+ (steps.length
514
+ ? '<details class="advanced" style="margin-top:10px"><summary>如何修复</summary><ol style="margin:10px 0 0 18px;color:var(--muted);font-size:13px;line-height:1.55">'+
515
+ steps.map(function(s){return '<li>'+esc(s)+'</li>';}).join('')+
516
+ '</ol>'+
517
+ (actions.length?'<p class="faint" style="margin-top:10px">建议:'+esc(actions.join(' · '))+'</p>':'')+
518
+ '</details>'
519
+ : '')+
520
+ '</div>';
521
+ }
522
+
523
+ function renderReadiness(){
524
+ var ready=obj(obj(commandCenter).readiness);
525
+ var fresh=obj(ready.connectorFreshness);
526
+ document.getElementById('view-readiness').innerHTML=
527
+ '<div class="page-head"><div><h1>系统状态</h1><p>用白话告诉你 forge 是否可用。</p></div>'+
528
+ '<div class="actions"><button class="btn primary" onclick="diagnoseFirst()">诊断</button><button class="btn" onclick="repairDryRun()">预览修复</button></div></div>'+
529
+ '<div class="panel" style="margin-bottom:14px"><h2>'+esc(ready.headline||'')+'</h2><p class="muted">'+esc(ready.description||'')+'</p></div>'+
530
+ '<div class="grid cards">'+arr(ready.sections).map(function(s){
531
+ return '<div class="panel"><div class="section-title"><h3 style="margin:0">'+esc(s.title)+'</h3>'+pill(s.tone,s.statusLabel)+'</div><p class="muted">'+esc(s.detail)+'</p></div>';
532
+ }).join('')+'</div>'+
533
+ renderConnectorHowToFix(fresh);
534
+ }
535
+
536
+ function renderRepositories(){
537
+ var repos=arr(obj(commandCenter).repositories);
538
+ var root=document.getElementById('view-repositories');
539
+ root.innerHTML=
540
+ '<div class="page-head"><div><h1>仓库</h1><p>选择当前工作仓库。显示名称、分支和是否干净会直接影响你是否能开始任务。</p></div>'+
541
+ '<button class="btn primary" onclick="toggleAddRepo()">添加本地仓库</button></div>'+
542
+ '<div class="panel" id="repoAdd" style="display:none;margin-bottom:14px">'+
543
+ '<div class="row" style="display:grid;grid-template-columns:1.4fr .8fr auto;gap:10px">'+
544
+ '<input class="input" id="repoPath" placeholder="./YourRepo">'+
545
+ '<input class="input" id="repoName" placeholder="显示名称(可选)">'+
546
+ '<button class="btn primary" onclick="registerRepo()">注册</button>'+
547
+ '</div></div>'+
548
+ (repos.length?'':'<div class="setup"><strong>还没有仓库</strong><p class="muted" style="margin:6px 0 0">添加一个本地 Git 仓库后,指挥中心才能启动任务。</p></div>')+
549
+ '<div class="list">'+repos.map(function(r){
550
+ return '<div class="panel card-row"><div><h3>'+esc(r.name)+'</h3><div class="muted mono">'+esc(r.path)+'</div>'+
551
+ '<div class="muted" style="margin-top:6px">'+(r.branchLabel?('分支 '+esc(r.branchLabel)):'')+(r.dirtyLabel?' · '+esc(r.dirtyLabel):'')+(r.readinessLabel?' · '+esc(r.readinessLabel):'')+'</div></div>'+
552
+ '<div class="actions">'+
553
+ btn(r.current?'当前仓库':'设为当前','data-select-repo="'+esc(r.id)+'"',r.current?'primary':'')+
554
+ btn('删除注册','data-remove-repo="'+esc(r.id)+'" data-remove-repo-name="'+esc(r.name||r.id)+'"','danger')+
555
+ '</div>'+
556
+ advancedBlock(r.advanced)+
557
+ '</div>';
558
+ }).join('')+'</div>';
559
+ bindActions(root);
560
+ }
561
+
562
+ function rememberPlugin(id){
563
+ selectedPluginId=id||'';
564
+ safeSet('forgeSelectedPluginId', selectedPluginId);
565
+ }
566
+
567
+ function pluginById(id){
568
+ return arr(obj(commandCenter).plugins).find(function(p){return p.id===id})||null;
569
+ }
570
+
571
+ function renderCapabilities(){
572
+ var cc=obj(commandCenter);
573
+ var plugins=arr(cc.plugins);
574
+ var summary=obj(cc.pluginSummary);
575
+ var selected=selectedPluginId?pluginById(selectedPluginId):null;
576
+ if(selectedPluginId&&!selected&&plugins.length){
577
+ selected=plugins[0];
578
+ rememberPlugin(selected.id);
579
+ }
580
+ var ready=summary.ready||plugins.filter(function(p){return p.status==='ready'}).length;
581
+ var need=summary.needsAttention||plugins.filter(function(p){return p.status!=='ready'&&p.status!=='disabled'}).length;
582
+ var failed=plugins.filter(function(p){return p.status==='failed'||p.status==='disabled'}).length;
583
+ var root=document.getElementById('view-capabilities');
584
+ root.innerHTML=
585
+ '<div class="page-head"><div><h1>能力 / 插件</h1><p>预览并管理 forge 可调用的助手插件;普通动作直接执行,不可逆操作需要强确认。</p></div>'+
586
+ '<div class="actions"><button class="btn" onclick="refreshPlugins()">检查连接</button></div></div>'+
587
+ '<div class="grid stats" style="margin-bottom:14px">'+
588
+ '<div class="panel stat"><span>能力总数</span><strong>'+plugins.length+'</strong></div>'+
589
+ '<div class="panel stat"><span>可用</span><strong>'+ready+'</strong></div>'+
590
+ '<div class="panel stat"><span>需要配置</span><strong>'+need+'</strong></div>'+
591
+ '<div class="panel stat"><span>不可用</span><strong>'+failed+'</strong></div>'+
592
+ '</div>'+
593
+ '<div class="grid two">'+
594
+ '<div class="list">'+
595
+ (plugins.length?plugins.map(function(p){
596
+ var active=selected&&selected.id===p.id;
597
+ return '<div class="panel plugin-card" style="cursor:pointer;border-color:'+(active?'rgba(96,165,250,.45)':'')+'" data-open-plugin="'+esc(p.id)+'">'+
598
+ '<div><h3 style="margin:0 0 6px">'+esc(p.name)+'</h3>'+
599
+ '<div class="muted">'+esc(p.description||'')+'</div>'+
600
+ '<div class="muted" style="margin-top:6px">'+esc(p.nextStep||'')+'</div>'+
601
+ (arr(p.capabilityLabels).length?'<div class="evidence" style="margin-top:8px">'+arr(p.capabilityLabels).map(function(c){return '<span>'+esc(c)+'</span>'}).join('')+'</div>':'')+
602
+ '</div>'+
603
+ '<div style="text-align:right">'+pill(p.tone,p.statusLabel)+
604
+ '<div class="actions" style="margin-top:8px;justify-content:flex-end">'+btn(active?'已选中':'查看', 'data-open-plugin="'+esc(p.id)+'"', active?'primary':'')+'</div>'+
605
+ '</div></div>';
606
+ }).join(''):'<div class="empty">当前仓库没有发现插件</div>')+
607
+ '</div>'+
608
+ '<div class="panel" id="pluginDetail">'+renderPluginDetail(selected)+'</div>'+
609
+ '</div>'+
610
+ (pluginActionResult?'<div class="panel" style="margin-top:14px"><div class="section-title"><h2>最近动作结果</h2></div><pre class="mono" style="white-space:pre-wrap;font-size:12px;color:var(--muted)">'+esc(JSON.stringify(pluginActionResult,null,2))+'</pre></div>':'');
611
+ bindActions(root);
612
+ }
613
+
614
+ function renderPluginDetail(p){
615
+ if(!p||!p.id){
616
+ return '<div class="empty">选择左侧插件查看能力、健康状态与可执行动作</div>';
617
+ }
618
+ var actions=arr(p.actions);
619
+ var previewActions=actions.filter(function(a){return a.canPreview});
620
+ var otherActions=actions.filter(function(a){return !a.canPreview});
621
+ return '<div class="section-title"><h2 style="margin:0">'+esc(p.name)+'</h2>'+pill(p.tone,p.statusLabel)+'</div>'+
622
+ '<p class="muted">'+esc(p.nextStep||'')+'</p>'+
623
+ '<div class="meta muted" style="display:flex;gap:10px;flex-wrap:wrap;margin:8px 0 12px">'+
624
+ '<span>提供方:'+esc(p.provider||'—')+'</span>'+
625
+ '<span>健康:'+esc(p.healthLabel||'—')+'</span>'+
626
+ '<span>生命周期:'+esc(p.lifecycleLabel||'—')+'</span>'+
627
+ '<span>动作:'+esc(String(p.actionCount||actions.length))+'</span>'+
628
+ '</div>'+
629
+ (arr(p.warnings).length?'<div class="warn">'+esc(arr(p.warnings).join(' · '))+'</div>':'')+
630
+ (arr(p.capabilityLabels).length?'<p><strong>能力域</strong></p><div class="evidence">'+arr(p.capabilityLabels).map(function(c){return '<span>'+esc(c)+'</span>'}).join('')+'</div>':'')+
631
+ '<div style="margin-top:14px"><div class="section-title"><h3 style="margin:0">预览 / 状态动作</h3><span class="muted">只读或配置检查,优先使用</span></div>'+
632
+ (previewActions.length?previewActions.map(function(a){return pluginActionRow(p.id,a,true)}).join(''):'<div class="empty">没有可预览动作</div>')+
633
+ '</div>'+
634
+ '<div style="margin-top:14px"><div class="section-title"><h3 style="margin:0">写入动作</h3><span class="muted">只有不可逆操作需要强确认</span></div>'+
635
+ (otherActions.length?otherActions.map(function(a){return pluginActionRow(p.id,a,false)}).join(''):'<div class="empty">没有写入动作</div>')+
636
+ '</div>'+
637
+ advancedBlock(p.advanced);
638
+ }
639
+
640
+ function pluginActionRow(pluginId, action, isPreview){
641
+ var id=esc(pluginId), aid=esc(action.id);
642
+ return '<div class="action-row">'+
643
+ '<div><div><strong>'+esc(action.title||action.id)+'</strong> '+pill(action.readOnly?'green':action.risk==='destructive'?'red':'amber', action.riskLabel)+'</div>'+
644
+ '<div class="muted">'+esc(action.description||'')+'</div>'+
645
+ '<div class="faint">'+esc(action.confirmationLabel||'')+'</div></div>'+
646
+ '<div class="actions">'+
647
+ btn(isPreview?'运行预览':'执行', 'data-plugin-act="run" data-plugin-id="'+id+'" data-action-id="'+aid+'"', isPreview?'primary':'')+
648
+ '</div></div>';
649
+ }
650
+
651
+ function fmtDuration(ms){
652
+ if(typeof ms!=='number'||!isFinite(ms)||ms<0)return '—';
653
+ if(ms<1000)return Math.round(ms)+' ms';
654
+ var sec=ms/1000;
655
+ if(sec<60)return (sec<10?sec.toFixed(1):Math.round(sec))+' s';
656
+ var min=Math.floor(sec/60), rem=Math.round(sec%60);
657
+ return min+'m '+rem+'s';
658
+ }
659
+
660
+ function renderConnectivitySection(payload){
661
+ payload=obj(payload);
662
+ var conn=obj(payload.connectivity);
663
+ var summary=obj(conn.summary);
664
+ if(!summary.headline)return '';
665
+ var latest=obj(conn.latestEvent);
666
+ var attr=obj(latest.attribution||summary.latestAttribution);
667
+ var observations=arr(latest.observations);
668
+ var jobs=arr(latest.jobTimings);
669
+ var counts=obj(summary.attributionCounts);
670
+ var evidence=arr(attr.evidence);
671
+ return '<div class="panel" style="margin-bottom:14px">'+
672
+ '<div class="section-title"><h2 style="margin:0">连接稳定性</h2>'+pill(summary.tone||attr.tone||'gray', summary.statusLabel||attr.overallStatusLabel||'观察中')+'</div>'+
673
+ '<p class="muted">'+esc(summary.headline||'')+'</p>'+
674
+ '<div class="muted" style="display:flex;gap:10px;flex-wrap:wrap;margin-top:8px">'+
675
+ '<span>归因:'+esc(attr.categoryLabel||'—')+'</span>'+
676
+ '<span>置信度:'+esc(attr.confidenceLabel||'—')+'</span>'+
677
+ '<span>最近探测:'+esc(summary.latestObservedAt||'—')+'</span>'+
678
+ '<span>样本:'+esc(String(summary.eventsStored||0))+'</span>'+
679
+ '</div>'+
680
+ '<div class="evidence" style="margin-top:10px">'+
681
+ '<span>公网路径 '+esc(String(counts.public_path||0))+'</span>'+
682
+ '<span>Gateway '+esc(String(counts.gateway||0))+'</span>'+
683
+ '<span>Local Bridge '+esc(String(counts.local_bridge||0))+'</span>'+
684
+ '<span>Controller '+esc(String(counts.controller||0))+'</span>'+
685
+ '<span>连接器/未知 '+esc(String(counts.connector_or_unknown||0))+'</span>'+
686
+ '</div>'+
687
+ (observations.length?'<div class="grid cards" style="margin-top:14px">'+observations.map(function(item){
688
+ item=obj(item);
689
+ return '<div class="panel" style="padding:12px;background:rgba(255,255,255,.02)">'+
690
+ '<div class="section-title"><strong>'+esc(item.label||item.component||'组件')+'</strong>'+pill(item.tone||'gray', item.stateLabel||item.state||'未知')+'</div>'+
691
+ '<p class="muted" style="margin:0">'+esc(item.detail||'')+'</p>'+
692
+ '</div>';
693
+ }).join('')+'</div>':'')+
694
+ (jobs.length?'<div style="margin-top:14px"><div class="section-title"><h3 style="margin:0">最近 durable Job 时序</h3><span class="muted">基于 queued/dispatched/started/finished 持久时间戳</span></div><div class="list">'+jobs.map(function(job){
695
+ job=obj(job);
696
+ return '<div class="card-row" style="padding:12px"><div><h3 style="margin:0 0 6px">'+esc(job.operation||job.jobId||'job')+'</h3>'+
697
+ '<p class="muted">Job '+esc(job.jobId||'—')+' · '+esc(job.statusLabel||job.status||'未知')+' · '+esc(job.stageLabel||'—')+'</p>'+
698
+ '<div class="evidence">'+
699
+ '<span>排队 '+esc(fmtDuration(job.queuedDelayMs))+'</span>'+
700
+ '<span>派发到启动 '+esc(fmtDuration(job.dispatchToStartMs))+'</span>'+
701
+ '<span>执行 '+esc(fmtDuration(job.executionDurationMs))+'</span>'+
702
+ '<span>总计 '+esc(fmtDuration(job.totalMs))+'</span>'+
703
+ '</div></div>'+pill((job.status==='failed'||job.status==='timed_out'||job.status==='orphaned'||job.status==='stale')?'red':(job.status==='running'||job.status==='dispatched')?'blue':'gray', job.statusLabel||job.status||'')+'</div>';
704
+ }).join('')+'</div></div>':'')+
705
+ (evidence.length?'<details class="advanced" style="margin-top:14px"><summary>归因证据</summary><ul style="margin:10px 0 0 18px;color:var(--muted);font-size:13px;line-height:1.55">'+evidence.map(function(line){return '<li>'+esc(line)+'</li>';}).join('')+'</ul></details>':'')+
706
+ '</div>';
707
+ }
708
+
709
+ function renderAdvanced(){
710
+ var root=document.getElementById('view-advanced');
711
+ var payload=advancedRaw||lastFacade||{note:'点击“读取原始快照”加载调试数据。日常任务请使用指挥中心。'};
712
+ root.innerHTML=
713
+ '<div class="page-head"><div><h1>高级诊断</h1><p>仅用于排错。默认任务流请回到指挥中心,不要从这里开始日常开发。</p></div>'+
714
+ '<div class="actions"><button class="btn" onclick="loadAdvanced()">读取原始快照</button>'+
715
+ '<button class="btn" onclick="copyText(JSON.stringify(advancedRaw||lastFacade||{},null,2))">复制 JSON</button>'+
716
+ btn('返回指挥中心','data-nav="home"','primary')+'</div></div>'+
717
+ renderConnectivitySection(payload)+
718
+ '<div class="panel"><div class="warn">调试信息默认折叠,避免干扰主流程。</div>'+
719
+ '<details class="advanced" open><summary>原始 JSON(调试)</summary>'+
720
+ '<pre class="mono" style="white-space:pre-wrap;font-size:12px;color:var(--muted);max-height:60vh;overflow:auto">'+esc(JSON.stringify(payload,null,2))+'</pre></details></div>';
721
+ bindNav(root);
722
+ }
723
+
724
+ function renderAutomation(){
725
+ var root=document.getElementById('view-automation');
726
+ if(!root)return;
727
+ var s=obj(automationSettings);
728
+ if(!s.schemaVersion){
729
+ root.innerHTML='<div class="page-head"><div><h1>模型与工具提供方</h1><p>配置 LLM、本地工具与路由偏好。</p></div>'+
730
+ '<button class="btn primary" onclick="loadAutomationSettings()">加载配置</button></div>'+
731
+ '<div class="empty">正在读取 Automation Settings…</div>';
732
+ loadAutomationSettings();
733
+ return;
734
+ }
735
+ var ov=obj(s.overview);
736
+ var providers=arr(s.providers);
737
+ var tools=arr(s.localTools);
738
+ var creds=arr(s.credentials);
739
+ var routing=obj(s.routing);
740
+ var warnings=arr(s.warnings).map(function(w){return '<div class="warn">'+esc(w)+'</div>'}).join('');
741
+ root.innerHTML=
742
+ '<div class="page-head"><div><h1>模型与工具提供方</h1><p>控制 goal loop 可用哪些 LLM / 本地工具、优先级与安全策略。密钥只读状态,永不展示值。</p></div>'+
743
+ '<div class="actions"><button class="btn" onclick="loadAutomationSettings()">刷新</button>'+
744
+ '<button class="btn" onclick="previewRoute()">预览路由</button>'+
745
+ '<button class="btn danger" onclick="resetProviders()">恢复默认</button></div></div>'+
746
+ warnings+
747
+ '<div class="panel" style="margin-bottom:14px"><h2>总览</h2>'+
748
+ '<p class="muted">'+esc(ov.plainLanguageSummary||'')+'</p>'+
749
+ '<div class="grid stats" style="margin-top:10px">'+
750
+ '<div class="stat"><span>Goal loop</span><strong>'+(ov.goalLoopEnabled?'开':'关')+'</strong></div>'+
751
+ '<div class="stat"><span>Live API(有效)</span><strong>'+(ov.liveModelProvidersEffective?'开':'关')+'</strong></div>'+
752
+ '<div class="stat"><span>直接可用</span><strong>'+esc(String(ov.directProvidersReady||0))+'</strong></div>'+
753
+ '<div class="stat"><span>需配置</span><strong>'+esc(String(ov.providersNeedingConfig||0))+'</strong></div>'+
754
+ '</div>'+
755
+ '<p class="faint" style="margin-top:10px">环境 Live 标志:'+(ov.liveModelProvidersEnv?'已设置':'未设置')+' · GUI 偏好:'+(ov.liveModelProvidersPreference?'已开启':'未开启')+' · 两者同时满足才允许远程 API 直接调度。</p>'+
756
+ '<div class="actions" style="margin-top:10px">'+
757
+ '<button class="btn" onclick="toggleLivePref('+(ov.liveModelProvidersPreference?'false':'true')+')">'+(ov.liveModelProvidersPreference?'关闭 GUI Live 偏好':'开启 GUI Live 偏好')+'</button>'+
758
+ '<button class="btn" onclick="toggleGoalLoop('+(ov.goalLoopEnabled?'false':'true')+')">'+(ov.goalLoopEnabled?'暂停 Goal Loop':'启用 Goal Loop')+'</button>'+
759
+ '</div>'+
760
+ '<p class="muted" style="margin-top:10px">默认路由:小改动 <strong>'+esc(obj(ov.defaultRoutes).small_edit||'—')+'</strong> · 实现 <strong>'+esc(obj(ov.defaultRoutes).normal_code_task||'—')+'</strong> · 修复 <strong>'+esc(obj(ov.defaultRoutes).repair||'—')+'</strong> · 规划 <strong>'+esc(obj(ov.defaultRoutes).planning||'—')+'</strong></p>'+
761
+ '</div>'+
762
+ '<div class="panel" style="margin-bottom:14px"><div class="section-title"><h2>LLM 提供方</h2></div><div class="list">'+
763
+ providers.map(function(p){return providerCardHtml(p)}).join('')+
764
+ '</div></div>'+
765
+ '<div class="panel" style="margin-bottom:14px"><div class="section-title"><h2>API 凭证状态</h2><span class="muted">env 或页面存储 · 永不显示明文</span></div>'+
766
+ (creds.length?creds.map(function(c){
767
+ return '<div class="card-row" style="margin-bottom:8px"><div>'+
768
+ '<h3>'+esc(c.displayName)+'</h3>'+
769
+ '<p class="muted">URL:'+esc(c.baseUrl||'—')+' · model:'+esc(c.model||'—')+'</p>'+
770
+ '<p class="muted">env:'+(arr(c.presentEnvVars).length?esc(arr(c.presentEnvVars).join(', ')):'未设置')+
771
+ ' · 页面密钥:'+(c.storedAuthPresent?esc(c.storedKeyHint||'已保存'):'未保存')+'</p>'+
772
+ '<p class="faint">模式:'+esc(c.storageMode)+'</p>'+
773
+ '<details class="advanced"><summary>Shell 示例</summary><pre class="mono" style="white-space:pre-wrap;font-size:12px;color:var(--muted)">'+esc(c.setupExample||'')+'</pre></details>'+
774
+ '</div>'+pill(c.authPresent?'green':'amber', c.authPresent?'已配置':'缺失')+'</div>';
775
+ }).join(''):'<div class="empty">无 API 凭证条目</div>')+
776
+ '</div>'+
777
+ '<div class="panel" style="margin-bottom:14px"><div class="section-title"><h2>本地执行工具</h2></div><div class="list">'+
778
+ tools.map(function(t){
779
+ return '<div class="card-row" style="margin-bottom:8px"><div>'+
780
+ '<h3>'+esc(t.displayName)+'</h3>'+
781
+ '<p class="muted">'+esc(t.summary||'')+'</p>'+
782
+ (t.executablePath?'<p class="faint mono">'+esc(t.executablePath)+(t.version?(' · '+esc(t.version)):'')+'</p>':'')+
783
+ '<div class="evidence">'+(arr(t.usedByWorkflows).map(function(w){return '<span>'+esc(w)+'</span>'}).join(''))+'</div>'+
784
+ '</div><div class="actions" style="flex-direction:column">'+
785
+ pill(t.status==='detected'?'green':t.status==='disabled'?'gray':'amber', t.status)+
786
+ (t.enabled
787
+ ? '<button class="btn" onclick="setToolEnabled(\\''+esc(t.toolId)+'\\',false)">禁用</button>'
788
+ : '<button class="btn primary" onclick="setToolEnabled(\\''+esc(t.toolId)+'\\',true)">启用</button>')+
789
+ '<button class="btn ghost" onclick="healthTool(\\''+esc(t.toolId)+'\\')">健康检查</button>'+
790
+ '</div></div>';
791
+ }).join('')+
792
+ '</div></div>'+
793
+ '<div class="panel" style="margin-bottom:14px"><div class="section-title"><h2>路由偏好</h2><button class="btn" onclick="resetRouting()">使用自动路由</button></div>'+
794
+ '<p class="muted">自动路由会按提供方优先级、能力和健康状态选择;显式路由会覆盖通用优先级。Handoff-only(ChatGPT)只能作为回退。</p>'+
795
+ ['implementation','repair','planning','review','browser_planning','ios_analysis'].map(function(key){
796
+ var order=arr(obj(routing.orders)[key]);
797
+ return '<div style="margin:10px 0;padding:10px;border:1px solid var(--line);border-radius:12px">'+
798
+ '<strong>'+esc(key)+'</strong><div class="muted mono" style="margin-top:6px">'+esc(order.join(' → ')||'—')+'</div></div>';
799
+ }).join('')+
800
+ '<p class="faint">若无可直接调用提供方:forge 会创建 continuation packet,而不是假装调用 ChatGPT 会话。</p>'+
801
+ '</div>';
802
+ bindNav(root);
803
+ }
804
+
805
+ function providerCardHtml(p){
806
+ p=obj(p);
807
+ var id=esc(p.providerId);
808
+ var handoff=!!p.handoffOnly;
809
+ var api=obj(p.apiSettings);
810
+ var apiForm='';
811
+ if(api.configurable){
812
+ var keyHint=api.hasStoredApiKey?('已保存密钥 '+(api.storedKeyHint||'••••')):(p.credential&&p.credential.envAuthPresent?'使用环境变量':'未配置密钥');
813
+ apiForm=
814
+ '<div class="setup" style="margin-top:10px">'+
815
+ '<strong>API 配置</strong>'+
816
+ '<p class="faint" style="margin:4px 0 8px">密钥仅存 controllerHome,不进 git;列表接口永不回显明文。</p>'+
817
+ '<label class="faint">Base URL</label>'+
818
+ '<input class="input" id="api-url-'+id+'" value="'+esc(api.baseUrl||api.defaultBaseUrl||'')+'" placeholder="'+esc(api.defaultBaseUrl||'https://…')+'">'+
819
+ '<label class="faint" style="display:block;margin-top:8px">Model</label>'+
820
+ '<input class="input" id="api-model-'+id+'" value="'+esc(api.model||api.defaultModel||'')+'" placeholder="'+esc(api.defaultModel||'model-id')+'">'+
821
+ '<label class="faint" style="display:block;margin-top:8px">API Key(留空则保留原密钥)</label>'+
822
+ '<input class="input" id="api-key-'+id+'" type="password" autocomplete="off" placeholder="'+esc(keyHint)+'">'+
823
+ '<div class="actions" style="margin-top:8px">'+
824
+ '<button class="btn primary" onclick="saveProviderApi(\\''+id+'\\')">保存 API 配置</button>'+
825
+ (api.hasStoredApiKey?'<button class="btn danger" onclick="clearProviderApiKey(\\''+id+'\\')">清除已存密钥</button>':'')+
826
+ '</div>'+
827
+ '<p class="faint" style="margin-top:6px">状态:'+esc(keyHint)+
828
+ (p.credential&&p.credential.envAuthPresent?' · 环境变量已就绪':'')+
829
+ '</p>'+
830
+ '</div>';
831
+ }
832
+ return '<div class="card-row" style="margin-bottom:10px;grid-template-columns:1fr"><div>'+
833
+ '<div style="display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:start">'+
834
+ '<div>'+
835
+ '<div class="section-title" style="margin:0"><h3 style="margin:0">'+esc(p.displayName)+'</h3>'+pill(p.directDispatch?'green':handoff?'blue':p.status==='disabled'?'gray':'amber', p.statusLabel)+'</div>'+
836
+ '<p class="muted">'+esc(p.kindLabel)+' · 优先级 '+esc(String(p.priority))+'</p>'+
837
+ '<p class="muted">'+esc(p.explanation||p.summary||'')+'</p>'+
838
+ '<div class="evidence">'+(arr(p.capabilities).slice(0,8).map(function(c){return '<span>'+esc(c)+'</span>'}).join(''))+'</div>'+
839
+ '<p class="faint" style="margin-top:6px">文件直接改动:'+(p.safety&&p.safety.canMutateFilesDirectly?'是':'否')+
840
+ ' · harness apply:'+(p.safety&&p.safety.requiresForgeApply?'是':'否')+
841
+ ' · 外部副作用:'+esc((p.safety&&p.safety.externalSideEffects)||'approval_required')+'</p>'+
842
+ (p.lastErrorSummary?'<p class="faint">最近错误码:'+esc(p.lastErrorSummary)+'</p>':'')+
843
+ (handoff?'<div class="setup" style="margin-top:8px"><strong>Direct dispatch:不支持</strong><p class="muted" style="margin:6px 0 0">'+esc(p.explanation||'')+'</p></div>':'')+
844
+ apiForm+
845
+ '</div>'+
846
+ '<div class="actions" style="flex-direction:column">'+
847
+ (!handoff?(p.enabled
848
+ ? '<button class="btn" onclick="setProviderEnabled(\\''+id+'\\',false)">禁用</button>'
849
+ : '<button class="btn primary" onclick="setProviderEnabled(\\''+id+'\\',true)">启用</button>'):'<span class="pill blue">Handoff-only</span>')+
850
+ (!handoff?'<button class="btn ghost" onclick="moveProvider(\\''+id+'\\',\\'up\\')">优先级↑</button><button class="btn ghost" onclick="moveProvider(\\''+id+'\\',\\'down\\')">优先级↓</button>':'')+
851
+ '<button class="btn ghost" onclick="healthProvider(\\''+id+'\\')">健康检查</button>'+
852
+ '</div>'+
853
+ '</div>'+
854
+ '</div></div>';
855
+ }
856
+
857
+ function loadAutomationSettings(){
858
+ return api('/api/console/automation-settings'+repoQuery()).then(function(res){
859
+ automationSettings=res;
860
+ renderAutomation();
861
+ }).catch(function(e){toast(e.message||'加载配置失败')});
862
+ }
863
+ function setProviderEnabled(id,on){
864
+ setBusy(true,on?'启用提供方':'禁用提供方');
865
+ api('/api/console/providers/'+encodeURIComponent(id)+'/'+(on?'enable':'disable')+repoQuery(),{method:'POST',body:'{}'}).then(function(){
866
+ toast(on?'已启用':'已禁用');return loadAutomationSettings();
867
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
868
+ }
869
+ function moveProvider(id,dir){
870
+ setBusy(true,'调整优先级');
871
+ api('/api/console/providers/'+encodeURIComponent(id)+'/priority'+repoQuery(),{method:'POST',body:JSON.stringify({direction:dir})}).then(function(){
872
+ toast('优先级已更新');return loadAutomationSettings();
873
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
874
+ }
875
+ function healthProvider(id){
876
+ api('/api/console/providers/health'+repoQuery(),{method:'POST',body:JSON.stringify({providerId:id})}).then(function(res){
877
+ toast((res.health&&res.health.summary)||'健康检查完成');
878
+ advancedRaw=res;
879
+ }).catch(function(e){toast(e.message)});
880
+ }
881
+ function saveProviderApi(id){
882
+ var urlEl=document.getElementById('api-url-'+id);
883
+ var modelEl=document.getElementById('api-model-'+id);
884
+ var keyEl=document.getElementById('api-key-'+id);
885
+ var body={
886
+ baseUrl:urlEl?String(urlEl.value||'').trim():undefined,
887
+ model:modelEl?String(modelEl.value||'').trim():undefined
888
+ };
889
+ if(keyEl&&String(keyEl.value||'').trim())body.apiKey=String(keyEl.value).trim();
890
+ setBusy(true,'保存 API 配置');
891
+ api('/api/console/providers/'+encodeURIComponent(id)+'/api-settings'+repoQuery(),{method:'POST',body:JSON.stringify(body)}).then(function(res){
892
+ toast('已保存 '+id+(res.storedKeyHint?(' · 密钥 '+res.storedKeyHint):''));
893
+ if(keyEl)keyEl.value='';
894
+ return loadAutomationSettings();
895
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
896
+ }
897
+ function clearProviderApiKey(id){
898
+ if(!confirm('清除页面保存的 API Key?(环境变量密钥不受影响)'))return;
899
+ setBusy(true,'清除密钥');
900
+ api('/api/console/providers/'+encodeURIComponent(id)+'/api-settings'+repoQuery(),{method:'POST',body:JSON.stringify({clearApiKey:true})}).then(function(){
901
+ toast('已清除存储密钥');return loadAutomationSettings();
902
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
903
+ }
904
+ function setToolEnabled(id,on){
905
+ setBusy(true,on?'启用工具':'禁用工具');
906
+ api('/api/console/local-tools/'+encodeURIComponent(id)+'/'+(on?'enable':'disable')+repoQuery(),{method:'POST',body:'{}'}).then(function(){
907
+ toast(on?'工具已启用':'工具已禁用');return loadAutomationSettings();
908
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
909
+ }
910
+ function healthTool(id){
911
+ api('/api/console/local-tools/health'+repoQuery(),{method:'POST',body:JSON.stringify({toolId:id})}).then(function(res){
912
+ toast((res.tool&&res.tool.summary)||'工具检查完成');
913
+ }).catch(function(e){toast(e.message)});
914
+ }
915
+ function toggleLivePref(on){
916
+ setBusy(true,'更新 Live 偏好');
917
+ api('/api/console/provider-config'+repoQuery(),{method:'POST',body:JSON.stringify({preferLiveModelProviders:!!on})}).then(function(){
918
+ toast(on?'已开启 GUI Live 偏好(仍需环境变量)':'已关闭 GUI Live 偏好');return loadAutomationSettings();
919
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
920
+ }
921
+ function toggleGoalLoop(on){
922
+ setBusy(true,'更新 Goal Loop');
923
+ api('/api/console/provider-config'+repoQuery(),{method:'POST',body:JSON.stringify({goalLoopEnabled:!!on})}).then(function(){
924
+ toast(on?'Goal Loop 已启用':'Goal Loop 已暂停');return loadAutomationSettings();
925
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
926
+ }
927
+ function previewRoute(){
928
+ api('/api/console/executor-route-preview'+repoQuery(),{method:'POST',body:JSON.stringify({task_intent:'code_implementation'})}).then(function(res){
929
+ toast(res.explanation||res.whyThisProvider||'路由预览完成');
930
+ advancedRaw=res;
931
+ }).catch(function(e){toast(e.message)});
932
+ }
933
+ function resetProviders(){
934
+ if(!confirm('恢复提供方默认配置?(不会删除环境变量)'))return;
935
+ setBusy(true,'恢复默认');
936
+ api('/api/console/providers/reset'+repoQuery(),{method:'POST',body:'{}'}).then(function(){
937
+ toast('已恢复默认');return loadAutomationSettings();
938
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
939
+ }
940
+ function resetRouting(){
941
+ if(!confirm('移除显式路由并恢复按提供方优先级、能力与健康状态自动选择?'))return;
942
+ setBusy(true,'恢复自动路由');
943
+ api('/api/console/executor-routing/reset'+repoQuery(),{method:'POST',body:'{}'}).then(function(){
944
+ toast('已恢复自动路由');return loadAutomationSettings();
945
+ }).catch(function(e){toast(e.message)}).finally(function(){setBusy(false)});
946
+ }
947
+
948
+ function bindNav(root){
949
+ if(!root)return;
950
+ root.querySelectorAll('[data-nav]').forEach(function(el){
951
+ el.addEventListener('click',function(){switchView(el.getAttribute('data-nav'))});
952
+ });
953
+ bindActions(root);
954
+ }
955
+
956
+ function bindActions(root){
957
+ if(!root)return;
958
+ root.querySelectorAll('[data-work-act]').forEach(function(el){
959
+ el.addEventListener('click',function(ev){ev.stopPropagation();workAction(el.getAttribute('data-work-act'),el.getAttribute('data-work-id'))});
960
+ });
961
+ root.querySelectorAll('[data-open-work]').forEach(function(el){
962
+ el.addEventListener('click',function(ev){ev.stopPropagation();openWork(el.getAttribute('data-open-work'))});
963
+ });
964
+ root.querySelectorAll('[data-open-handoff]').forEach(function(el){
965
+ el.addEventListener('click',function(ev){ev.stopPropagation();openHandoff(el.getAttribute('data-open-handoff'))});
966
+ });
967
+ root.querySelectorAll('[data-handoff-act]').forEach(function(el){
968
+ el.addEventListener('click',function(ev){ev.stopPropagation();handoffAction(el.getAttribute('data-handoff-act'),el.getAttribute('data-handoff-id'))});
969
+ });
970
+ root.querySelectorAll('[data-select-repo]').forEach(function(el){
971
+ el.addEventListener('click',function(ev){ev.stopPropagation();selectRepo(el.getAttribute('data-select-repo'))});
972
+ });
973
+ root.querySelectorAll('[data-remove-repo]').forEach(function(el){
974
+ el.addEventListener('click',function(ev){
975
+ ev.stopPropagation();
976
+ removeRepo(el.getAttribute('data-remove-repo'), el.getAttribute('data-remove-repo-name'));
977
+ });
978
+ });
979
+ root.querySelectorAll('[data-open-plugin]').forEach(function(el){
980
+ el.addEventListener('click',function(ev){ev.stopPropagation();openPlugin(el.getAttribute('data-open-plugin'))});
981
+ });
982
+ root.querySelectorAll('[data-plugin-act]').forEach(function(el){
983
+ el.addEventListener('click',function(ev){
984
+ ev.stopPropagation();
985
+ runPluginAction(el.getAttribute('data-plugin-id'), el.getAttribute('data-action-id'));
986
+ });
987
+ });
988
+ root.querySelectorAll('[data-copy]').forEach(function(el){
989
+ el.addEventListener('click',function(ev){ev.stopPropagation();copyText(el.getAttribute('data-copy-text')||'')});
990
+ });
991
+ }
992
+
993
+ function renderAll(){
994
+ if(!commandCenter){
995
+ document.getElementById('view-home').innerHTML='<div class="panel"><h2>正在读取控制台状态</h2><p class="muted">如果长时间无响应,请刷新或打开高级诊断。</p><button class="btn" onclick="refreshAll()">重新载入</button></div>';
996
+ return;
997
+ }
998
+ try{
999
+ renderChrome();
1000
+ renderHome();
1001
+ renderInbox();
1002
+ renderWork();
1003
+ renderCapabilities();
1004
+ renderAutomation();
1005
+ renderReadiness();
1006
+ renderRepositories();
1007
+ renderAdvanced();
1008
+ }catch(e){
1009
+ toast(e.message||String(e));
1010
+ }
1011
+ }
1012
+
1013
+ function openWork(id){rememberWork(id);switchView('work');refreshWorkDetail(id)}
1014
+ function openHandoff(id){selectedHandoffId=id;switchView('inbox');renderInbox()}
1015
+ function openPlugin(id){
1016
+ rememberPlugin(id);
1017
+ switchView('capabilities');
1018
+ renderCapabilities();
1019
+ // Refresh detail from console API for latest health/actions.
1020
+ api('/api/console/plugins/'+encodeURIComponent(id)+repoQuery()).then(function(res){
1021
+ if(res&&res.plugin){
1022
+ commandCenter=commandCenter||{};
1023
+ var list=arr(commandCenter.plugins);
1024
+ var idx=list.findIndex(function(p){return p.id===id});
1025
+ if(idx>=0)list[idx]=res.plugin; else list.push(res.plugin);
1026
+ commandCenter.plugins=list;
1027
+ commandCenter.pluginSummary=obj(commandCenter.pluginSummary);
1028
+ renderCapabilities();
1029
+ }
1030
+ }).catch(function(){});
1031
+ }
1032
+ function refreshPlugins(){
1033
+ api('/api/console/plugins'+repoQuery()).then(function(res){
1034
+ commandCenter=commandCenter||{};
1035
+ commandCenter.plugins=arr(res.plugins);
1036
+ commandCenter.pluginSummary=obj(res.summary);
1037
+ renderChrome();
1038
+ renderCapabilities();
1039
+ toast('插件状态已刷新');
1040
+ }).catch(function(e){toast(e.message)});
1041
+ }
1042
+ function runPluginAction(pluginId, actionId){
1043
+ if(busy){toast('上一步仍在处理,请稍候');return}
1044
+ var plugin=pluginById(pluginId)||{};
1045
+ var action=arr(plugin.actions).find(function(a){return a.id===actionId})||{id:actionId,title:actionId};
1046
+ var confirmAuth=false;
1047
+ var confirmationText=undefined;
1048
+ if(action.requiredConfirmationText||action.confirmation==='strong_confirmation'){
1049
+ var required=action.requiredConfirmationText||('CONFIRM '+actionId);
1050
+ var typed=prompt('该动作不可逆,请输入强确认文本:'+required,'');
1051
+ if(typed==null)return;
1052
+ if(typed!==required){toast('确认文本不匹配');return}
1053
+ confirmationText=typed;
1054
+ confirmAuth=true;
1055
+ }
1056
+ var requestId='gui-'+Date.now().toString(36)+'-'+Math.random().toString(36).slice(2,8);
1057
+ setBusy(true,'运行插件动作…');
1058
+ api('/api/plugins/'+encodeURIComponent(pluginId)+'/actions/'+encodeURIComponent(actionId)+repoQuery(),{
1059
+ method:'POST',
1060
+ body:JSON.stringify({
1061
+ requestId:requestId,
1062
+ arguments:{},
1063
+ confirmAuthorization:confirmAuth,
1064
+ confirmationText:confirmationText
1065
+ })
1066
+ }).then(function(res){
1067
+ pluginActionResult={
1068
+ at:new Date().toISOString(),
1069
+ pluginId:pluginId,
1070
+ actionId:actionId,
1071
+ accepted:res.accepted,
1072
+ deduplicated:res.deduplicated,
1073
+ job:res.job,
1074
+ action:res.action
1075
+ };
1076
+ setLastOp({phase:'succeeded',statusLabel:'动作已提交',summary:'插件动作 '+(action.title||actionId)+' 已提交'},'插件动作已提交');
1077
+ toast(res.deduplicated?'动作已去重复用':'插件动作已提交');
1078
+ return refreshAll({silent:true}).then(function(){renderCapabilities()});
1079
+ }).catch(function(e){
1080
+ pluginActionResult={at:new Date().toISOString(),pluginId:pluginId,actionId:actionId,error:e.message,payload:e.payload||null};
1081
+ setLastOp(e.payload||{phase:'failed',summary:e.message},e.message);
1082
+ toast(e.message);
1083
+ renderCapabilities();
1084
+ }).finally(function(){setBusy(false)});
1085
+ }
1086
+ function copyText(text){if(!text){toast('没有可复制内容');return}navigator.clipboard.writeText(text).then(function(){toast('已复制')}).catch(function(){toast('复制失败')})}
1087
+ function toggleAddRepo(){var el=document.getElementById('repoAdd');if(el)el.style.display=el.style.display==='none'?'block':'none'}
1088
+
1089
+ function taskPayload(){
1090
+ var objective=(document.getElementById('taskObjective')||{}).value||'';
1091
+ var acceptance=((document.getElementById('taskAcceptance')||{}).value||'').split(/[;;\\n]/).map(function(s){return s.trim()}).filter(Boolean);
1092
+ var paths=((document.getElementById('taskPaths')||{}).value||'').split(',').map(function(s){return s.trim()}).filter(Boolean);
1093
+ var files=Number((document.getElementById('taskFiles')||{}).value||0)||undefined;
1094
+ return {
1095
+ objective:objective.trim(),
1096
+ acceptanceCriteria:acceptance,
1097
+ allowedPaths:paths,
1098
+ expectedFiles:files,
1099
+ scopeClear:true
1100
+ };
1101
+ }
1102
+
1103
+ function previewMode(){
1104
+ if(busy){toast('上一步仍在处理,请稍候');return}
1105
+ var body=taskPayload();
1106
+ if(!body.objective){toast('请先输入任务目标');return}
1107
+ setBusy(true,'预览模式…');
1108
+ api('/api/console/mode-preview'+repoQuery(),{method:'POST',body:JSON.stringify(body)}).then(function(res){
1109
+ modePreview=res.modePreview||res;
1110
+ setLastOp({phase:'succeeded',statusLabel:'模式已预览',summary:'建议:'+(modePreview.label||'直接执行')+'。'+(modePreview.explanation||'')},'模式已预览');
1111
+ renderHome();
1112
+ toast('建议模式:'+(modePreview.label||''));
1113
+ }).catch(function(e){setLastOp(e.payload||{phase:'failed',summary:e.message},e.message);toast(e.message||'预览失败')}).finally(function(){setBusy(false)});
1114
+ }
1115
+
1116
+ function startTask(){
1117
+ if(busy){toast('上一步仍在处理,请勿重复提交');return}
1118
+ var body=taskPayload();
1119
+ if(!body.objective){toast('请先输入任务目标');return}
1120
+ setBusy(true,'正在提交任务…');
1121
+ api('/api/console/work/start'+repoQuery(),{method:'POST',body:JSON.stringify(body)}).then(function(res){
1122
+ setLastOp(res,'任务已提交');
1123
+ var data=obj(res.data);
1124
+ if(data.work&&data.work.workId){rememberWork(data.work.workId)}
1125
+ else if(data.work&&data.work.id){rememberWork(data.work.id)}
1126
+ else if(data.workId){rememberWork(data.workId)}
1127
+ toast(res.summary||(res.status==='blocked'?'已创建待决定事项':'任务已提交'));
1128
+ return refreshAll();
1129
+ }).then(function(){
1130
+ if(arr(obj(commandCenter).handoffs).length&&!selectedWorkId)switchView('inbox');
1131
+ else if(selectedWorkId)switchView('work');
1132
+ else switchView('home');
1133
+ }).catch(function(e){
1134
+ setLastOp(e.payload||{phase:'failed',summary:e.message||'启动失败'},e.message||'启动失败');
1135
+ toast(e.message||'启动失败');
1136
+ }).finally(function(){setBusy(false)});
1137
+ }
1138
+
1139
+ function diagnoseFirst(){
1140
+ if(busy){toast('上一步仍在处理,请稍候');return}
1141
+ setBusy(true,'正在诊断…');
1142
+ api('/api/console/repair'+repoQuery(),{method:'POST',body:JSON.stringify({operation:'diagnose',dryRun:true})}).then(function(res){
1143
+ setLastOp(res,'诊断完成');toast(res.summary||'诊断完成');switchView('readiness');
1144
+ }).catch(function(e){setLastOp(e.payload||{phase:'failed',summary:e.message},e.message);toast(e.message)}).finally(function(){setBusy(false)});
1145
+ }
1146
+ function repairDryRun(){
1147
+ if(busy){toast('上一步仍在处理,请稍候');return}
1148
+ setBusy(true,'正在预览修复…');
1149
+ api('/api/console/repair'+repoQuery(),{method:'POST',body:JSON.stringify({operation:'repair',dryRun:true})}).then(function(res){
1150
+ setLastOp(res,'已生成修复预览');advancedRaw=res;toast(res.summary||'已生成修复预览');switchView('advanced');
1151
+ }).catch(function(e){setLastOp(e.payload||{phase:'failed',summary:e.message},e.message);toast(e.message)}).finally(function(){setBusy(false)});
1152
+ }
1153
+
1154
+ function workAction(kind,workId){
1155
+ if(busy){toast('上一步仍在处理,请稍候');return}
1156
+ rememberWork(workId);
1157
+ if(kind==='continue')return postWork('/api/console/work/continue',{workId:workId},'继续任务');
1158
+ if(kind==='verify')return postWork('/api/console/work/verify',{workId:workId},'运行验证');
1159
+ if(kind==='finalize')return postWork('/api/console/work/finalize',{workId:workId},'收尾任务');
1160
+ if(kind==='stop')return postWork('/api/console/work/stop',{workId:workId,reason:'stopped from console'},'停止任务');
1161
+ if(kind==='repair'){
1162
+ setBusy(true,'正在诊断…');
1163
+ return api('/api/console/repair'+repoQuery(),{method:'POST',body:JSON.stringify({operation:'diagnose',dryRun:true,workId:workId})}).then(function(res){setLastOp(res,'诊断完成');toast(res.summary||'诊断完成')}).catch(function(e){setLastOp(e.payload||{phase:'failed',summary:e.message},e.message);toast(e.message)}).finally(function(){setBusy(false)});
1164
+ }
1165
+ if(kind==='delegate-codex')return postWork('/api/console/work/delegate',{workId:workId,target:'codex',available:true},'委派 Codex');
1166
+ if(kind==='delegate-grok')return postWork('/api/console/work/delegate',{workId:workId,target:'grok'},'准备 Grok 审阅包');
1167
+ }
1168
+ function postWork(path,body,label){
1169
+ setBusy(true,label||'处理中…');
1170
+ return api(path+repoQuery(),{method:'POST',body:JSON.stringify(body)}).then(function(res){
1171
+ setLastOp(res,label||'已更新');
1172
+ // Clarify handoff-only / request-packet outcomes for small-brain delegation.
1173
+ if(res&&res.data&&res.data.directExecutionAvailable===false){
1174
+ toast((res.summary||'已准备外部审阅请求')+'(非自动执行)');
1175
+ } else {
1176
+ toast(res.summary||'已更新');
1177
+ }
1178
+ return refreshAll();
1179
+ }).catch(function(e){setLastOp(e.payload||{phase:'failed',summary:e.message},e.message);toast(e.message)}).finally(function(){setBusy(false)});
1180
+ }
1181
+ function refreshWorkDetail(id){
1182
+ api('/api/console/work/'+encodeURIComponent(id)+repoQuery()).then(function(res){
1183
+ if(res.work){
1184
+ // merge into command center recent
1185
+ commandCenter=commandCenter||{};
1186
+ commandCenter.currentWork=res.work;
1187
+ renderWork();
1188
+ }
1189
+ }).catch(function(){});
1190
+ }
1191
+
1192
+ function handoffAction(kind,id){
1193
+ if(busy){toast('上一步仍在处理,请稍候');return}
1194
+ var item=arr(obj(commandCenter).handoffs).find(function(h){return h.id===id})||{};
1195
+ var d=obj(item.decision);var body={};
1196
+ if(kind==='approve'){
1197
+ var approvalText='确认'+(d.primaryActionLabel||'批准并创建任务')+'?\\n\\n批准对象:'+(d.requestedAction||item.title||'当前操作')+'\\n影响:'+(d.impact||'按当前任务范围执行')+'\\n后续:'+(d.afterApproval||'打开任务详情');
1198
+ if(!confirm(approvalText))return;
1199
+ }
1200
+ if(kind==='resolve'){
1201
+ var decision=prompt('记录你的决定。注意:此操作只保存决定并移出待处理,不会自动继续任务。',item.recommendedDecision||'');
1202
+ if(decision==null)return;
1203
+ if(!String(decision).trim()){toast('请填写决定内容');return}
1204
+ body={decision:decision,resolver:'user'};
1205
+ }
1206
+ if(kind==='dismiss'){
1207
+ if(!confirm('确认暂不处理此事项?它会从待处理列表移除,相关操作不会执行。'))return;
1208
+ body={decision:'dismissed',resolver:'user'};
1209
+ }
1210
+ setBusy(true,kind==='approve'?'正在批准并创建任务…':kind==='resolve'?'仅记录决定…':kind==='dismiss'?'暂不处理…':'更新中…');
1211
+ api('/api/console/inbox/'+encodeURIComponent(id)+'/'+kind+repoQuery(),{method:'POST',body:JSON.stringify(body)}).then(function(res){
1212
+ if(kind==='approve'){
1213
+ setLastOp(res,'已批准并创建任务');
1214
+ var data=obj(obj(res.actionResult).data);var work=obj(data.work);
1215
+ if(work.workId)rememberWork(work.workId);else if(work.id)rememberWork(work.id);
1216
+ toast(res.summary||'已批准并创建任务');
1217
+ } else {
1218
+ setLastOp({phase:'succeeded',statusLabel:kind==='resolve'?'已记录决定':kind==='dismiss'?'已暂不处理':'已确认',summary:kind==='resolve'?'决定已保存;未触发任何后续执行':kind==='dismiss'?'事项已移出列表,相关操作未执行':'已确认已知晓'}, '已更新');
1219
+ toast(kind==='resolve'?'已记录决定(未自动继续)':kind==='dismiss'?'已暂不处理':'已确认');
1220
+ }
1221
+ selectedHandoffId='';
1222
+ return refreshAll().then(function(){if(kind==='approve'&&selectedWorkId)switchView('work')});
1223
+ }).catch(function(e){setLastOp(e.payload||{phase:'failed',summary:e.message||'更新失败'},e.message||'更新失败');toast(e.message||'更新失败')}).finally(function(){setBusy(false)});
1224
+ }
1225
+
1226
+ function selectRepo(id){
1227
+ rememberRepo(id);
1228
+ toast('已切换仓库');
1229
+ refreshAll().then(function(){switchView('home')});
1230
+ }
1231
+ function registerRepo(){
1232
+ var path=(document.getElementById('repoPath')||{}).value||'';
1233
+ var name=(document.getElementById('repoName')||{}).value||'';
1234
+ if(!path.trim()){toast('请输入仓库路径');return}
1235
+ api('/api/repositories/register',{method:'POST',body:JSON.stringify({path:path.trim(),displayName:name.trim()||undefined})}).then(function(res){
1236
+ var repo=obj(res.repository);if(repo.repoId)rememberRepo(repo.repoId);
1237
+ toast('仓库已注册');return refreshAll();
1238
+ }).catch(function(e){toast(e.message)});
1239
+ }
1240
+ function removeRepo(id, name){
1241
+ if(!id)return;
1242
+ var label=name||id;
1243
+ if(!confirm('从控制台删除「'+label+'」的注册?\\n不会删除磁盘上的仓库文件,仅从 Controller 注册表中移除(可重新注册)。'))return;
1244
+ if(busy)return;
1245
+ setBusy(true,'删除注册中');
1246
+ api('/api/repositories/'+encodeURIComponent(id)+'/remove',{method:'POST',body:JSON.stringify({})}).then(function(res){
1247
+ if(selectedRepoId===id){
1248
+ var remaining=arr(res.repositories);
1249
+ var next=remaining.find(function(r){return r.id&&r.id!==id})||remaining[0];
1250
+ rememberRepo(next&&next.id?next.id:'');
1251
+ }
1252
+ toast(res.summary||'已删除仓库注册');
1253
+ return refreshAll();
1254
+ }).catch(function(e){
1255
+ var msg=e.message||'删除失败';
1256
+ if(String(msg).indexOf('REPOSITORY_SELF_PROTECTED')===0||(e.payload&&e.payload.errorMessage)){
1257
+ msg=(e.payload&&e.payload.errorMessage)||'不能删除当前进程所在仓库的注册(自我保护)';
1258
+ }
1259
+ toast(msg);
1260
+ }).finally(function(){setBusy(false)});
1261
+ }
1262
+ function loadAdvanced(){
1263
+ api('/api/console/advanced'+repoQuery()).then(function(res){advancedRaw=res;renderAdvanced();toast('原始快照已刷新')}).catch(function(e){toast(e.message)});
1264
+ }
1265
+
1266
+ function refreshAll(opts){
1267
+ opts=opts||{};
1268
+ if(refreshInFlight)return Promise.resolve();
1269
+ refreshInFlight=true;
1270
+ return api('/api/console/command-center'+repoQuery()).then(function(res){
1271
+ commandCenter=res;
1272
+ lastRefreshedAt=new Date().toLocaleTimeString();
1273
+ var repo=obj(res.currentRepository);
1274
+ if(repo.id)rememberRepo(repo.id);
1275
+ if(!selectedWorkId&&res.currentWork&&res.currentWork.id)rememberWork(res.currentWork.id);
1276
+ // Merge extras into current work for card display after silent polls.
1277
+ if(res.currentWork&&res.currentWork.id)res.currentWork=mergeWorkExtras(res.currentWork);
1278
+ var loadSettings=(!opts.silent||!automationSettings)
1279
+ ? api('/api/console/automation-settings'+repoQuery()).then(function(s){automationSettings=s}).catch(function(){/* optional */})
1280
+ : Promise.resolve();
1281
+ return loadSettings.then(function(){
1282
+ if(!opts.silent)renderAll();
1283
+ else {
1284
+ renderChrome();
1285
+ renderOpBar();
1286
+ try{renderHome();renderWork();renderInbox()}catch(_e){renderAll()}
1287
+ }
1288
+ ensurePoll();
1289
+ });
1290
+ }).catch(function(e){
1291
+ if(opts.silent){
1292
+ lastOperation={phase:'failed',statusLabel:'重连中',summary:e.message||'控制台暂时不可用,正在重试…',at:new Date().toISOString()};
1293
+ renderOpBar();
1294
+ return;
1295
+ }
1296
+ commandCenter={
1297
+ readiness:{state:'blocked',label:'读取失败',headline:'控制台不可用',description:e.message||'本地 API 暂时不可用',connectorLabel:'未知',connectorTone:'red',pendingHandoffCount:0,sections:[]},
1298
+ handoffs:[],recentWork:[],repositories:[],warnings:[e.message||'读取失败'],modePreviewDefault:{label:'—',explanation:''},
1299
+ setupGuide:{needed:true,title:'控制台暂不可用',body:e.message||'请确认 controller 已启动。',actionLabel:'重试'}
1300
+ };
1301
+ setLastOp({phase:'failed',statusLabel:'读取失败',summary:e.message||'本地 API 暂时不可用',error:{title:'控制器暂不可用',explanation:e.message||'本地 API 暂时不可用',nextActions:['刷新页面','重启 controller']}},e.message);
1302
+ renderAll();
1303
+ toast(e.message||'读取失败');
1304
+ }).finally(function(){refreshInFlight=false});
1305
+ }
1306
+
1307
+ window.onerror=function(message){toast(String(message));return false};
1308
+ refreshAll();
1309
+ </script>
1310
+ </body>
1311
+ </html>`;
1312
+ }