@moretea-labs/forge 1.5.1 → 1.7.0

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 (434) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +46 -0
  3. package/CLAUDE.md +2 -0
  4. package/DESIGN.md +7 -2
  5. package/README.md +4 -4
  6. package/README.zh-CN.md +2 -2
  7. package/SKILL.md +2 -2
  8. package/THIRD_PARTY_NOTICES.md +1 -1
  9. package/agents/openai.yaml +1 -1
  10. package/assets/hooks/hook-input.sh +11 -8
  11. package/assets/hooks/lib/session-state.sh +10 -7
  12. package/assets/hooks/lib/workflow-state.sh +13 -177
  13. package/assets/hooks/post-tool-observer.sh +8 -2
  14. package/assets/hooks/pre-edit-guard.sh +8 -39
  15. package/assets/hooks/prompt-guard.sh +7 -83
  16. package/assets/hooks/session-start-context.sh +56 -1
  17. package/assets/partials/05-workflow.partial.md +1 -1
  18. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  19. package/assets/plugin-registry.v1.json +54 -3
  20. package/assets/reference-configs/document-generation.md +1 -1
  21. package/assets/reference-configs/harness-overview.md +1 -1
  22. package/assets/reference-configs/hook-operations.md +1 -1
  23. package/assets/reference-configs/sprint-contracts.md +3 -3
  24. package/assets/skill-version.json +2 -2
  25. package/assets/templates/contract.template.md +2 -7
  26. package/assets/templates/helpers/capture-plan.sh +2 -2
  27. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  28. package/assets/templates/helpers/contract-worktree.sh +1 -21
  29. package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
  30. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  31. package/assets/templates/helpers/new-plan.sh +1 -1
  32. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  33. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  34. package/assets/templates/helpers/sprint-backlog.sh +6 -6
  35. package/assets/templates/helpers/verify-contract.sh +1 -111
  36. package/assets/templates/helpers/verify-sprint.sh +3 -180
  37. package/assets/templates/plan.template.md +1 -1
  38. package/assets/templates/review.template.md +9 -34
  39. package/assets/workflow-contract.v1.json +10 -19
  40. package/docs/README.md +10 -10
  41. package/docs/architecture/CURRENT.md +170 -0
  42. package/docs/architecture/EVOLUTION.md +42 -0
  43. package/docs/architecture/current/README.md +4 -156
  44. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  45. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  46. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  47. package/docs/architecture/history/README.md +7 -0
  48. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  49. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  50. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  51. package/docs/architecture/history.md +3 -34
  52. package/docs/architecture/index.md +15 -98
  53. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  54. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  55. package/docs/architecture/versions/1.6.md +38 -0
  56. package/docs/architecture/versions/1.7.md +41 -0
  57. package/docs/forge-chatgpt-browser-engine.md +2 -2
  58. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  59. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  60. package/docs/forge-github-issue-launcher.md +1 -1
  61. package/docs/forge-runtime-self-healing-loop.md +1 -1
  62. package/docs/operations/controller-browser-plugin.md +38 -22
  63. package/docs/operations/controller-performance-and-502.md +124 -0
  64. package/docs/operations/controller-reliability-runbook.md +1 -1
  65. package/docs/operations/features.md +3 -3
  66. package/docs/operations/github-repository.md +1 -1
  67. package/docs/operations/homebrew.md +2 -2
  68. package/docs/operations/mcp-tool-exposure.md +5 -3
  69. package/docs/tutorials/01-install-and-start.md +1 -1
  70. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  71. package/docs/wiki/Architecture.md +6 -6
  72. package/docs/wiki/Implementation.md +2 -2
  73. package/docs/wiki/Installation.md +1 -1
  74. package/docs/wiki/Integrations.md +2 -2
  75. package/docs/wiki/Quick-Start.md +1 -1
  76. package/docs/wiki/Work-Lifecycle.md +1 -1
  77. package/package.json +29 -10
  78. package/scripts/activate-source-baseline.ts +17 -13
  79. package/scripts/benchmark-background-check-overlap.ts +228 -0
  80. package/scripts/benchmark-mcp-host.sh +117 -0
  81. package/scripts/benchmark-mcp-transport.ts +170 -0
  82. package/scripts/benchmark-quality-harness.ts +146 -0
  83. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  84. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  85. package/scripts/benchmark-typescript-navigation.ts +186 -0
  86. package/scripts/benchmark-work-efficiency.ts +334 -0
  87. package/scripts/capture-plan.sh +3 -3
  88. package/scripts/check-agent-tooling.sh +8 -35
  89. package/scripts/check-architecture-sync.sh +17 -86
  90. package/scripts/check-mcp-compatibility.ts +14 -0
  91. package/scripts/check-public-docs.sh +14 -1
  92. package/scripts/check-runtime-architecture.mjs +107 -64
  93. package/scripts/check-stable-baseline.ts +92 -0
  94. package/scripts/check-task-workflow.sh +4 -4
  95. package/scripts/contract-worktree.sh +1 -21
  96. package/scripts/ensure-task-workflow.sh +22 -55
  97. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  98. package/scripts/install-standalone-recovery.ts +24 -0
  99. package/scripts/lib/project-init-lib.sh +15 -44
  100. package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
  101. package/scripts/migrate-project-template.sh +23 -1179
  102. package/scripts/new-plan.sh +1 -1
  103. package/scripts/plan-to-todo.sh +11 -36
  104. package/scripts/run-governed-gate.ts +2 -1
  105. package/scripts/ship-worktrees.sh +2 -29
  106. package/scripts/smoke-ios-physical-device.ts +4 -2
  107. package/scripts/smoke-runtime-recovery.ts +1 -35
  108. package/scripts/smoke-schedule-engine.ts +1 -20
  109. package/scripts/sprint-backlog.sh +1 -1
  110. package/scripts/verify-contract.sh +1 -111
  111. package/scripts/verify-forge-runtime.sh +0 -1
  112. package/scripts/verify-sprint.sh +3 -180
  113. package/scripts/workflow-contract.ts +1 -5
  114. package/src/cli/commands/chatgpt.ts +31 -2
  115. package/src/cli/commands/init-hook.ts +3 -3
  116. package/src/cli/commands/mcp.ts +9 -5
  117. package/src/cli/commands/plugin.ts +37 -10
  118. package/src/cli/commands/recovery.ts +25 -3
  119. package/src/cli/commands/runtime.ts +55 -3
  120. package/src/cli/commands/security.ts +12 -1
  121. package/src/cli/commands/setup-profile.ts +31 -21
  122. package/src/cli/controller/check-runner.ts +106 -3
  123. package/src/cli/controller/composite-result.ts +1 -1
  124. package/src/cli/controller/context/focus.ts +51 -0
  125. package/src/cli/controller/context/instruction-context.ts +114 -0
  126. package/src/cli/controller/context/known-paths.ts +76 -0
  127. package/src/cli/controller/context/query-planning.ts +110 -0
  128. package/src/cli/controller/context/rule-resolution.ts +532 -0
  129. package/src/cli/controller/context/source-materializer.ts +278 -0
  130. package/src/cli/controller/context/structural.ts +16 -0
  131. package/src/cli/controller/context/types.ts +286 -0
  132. package/src/cli/controller/context-pack.ts +898 -430
  133. package/src/cli/controller/launch-agents.ts +77 -2
  134. package/src/cli/controller/operational-plan.ts +2 -2
  135. package/src/cli/controller/work-mode.ts +6 -4
  136. package/src/cli/editing/edit-session.ts +60 -7
  137. package/src/cli/github/github.ts +133 -0
  138. package/src/cli/hook/prompt-guard-decision.ts +17 -18
  139. package/src/cli/hook/prompt-intents.ts +1 -1
  140. package/src/cli/installer/managed-entries.ts +15 -1
  141. package/src/cli/local-bridge/console-automations.ts +225 -67
  142. package/src/cli/local-bridge/console-view-models.ts +3 -35
  143. package/src/cli/local-bridge/facade-api.ts +2 -217
  144. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  145. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
  146. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  147. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
  148. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
  149. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
  150. package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
  151. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  152. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
  153. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
  154. package/src/cli/local-bridge/frontend/src/styles.css +27 -11
  155. package/src/cli/local-bridge/frontend/src/types.ts +8 -7
  156. package/src/cli/local-bridge/job-store.ts +1 -490
  157. package/src/cli/local-bridge/server.ts +29 -532
  158. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  159. package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
  160. package/src/cli/mcp/auth.ts +5 -5
  161. package/src/cli/mcp/instructions.ts +3 -2
  162. package/src/cli/mcp/legacy-tool-service.ts +0 -189
  163. package/src/cli/mcp/multi-repository.ts +16 -5
  164. package/src/cli/mcp/oauth.ts +175 -26
  165. package/src/cli/mcp/paths.ts +8 -2
  166. package/src/cli/mcp/repository-tools.ts +356 -101
  167. package/src/cli/mcp/server.ts +625 -54
  168. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  169. package/src/cli/mcp/toolset-selection.ts +1 -1
  170. package/src/cli/mcp/toolset.ts +42 -5
  171. package/src/cli/mcp/transports/http.ts +125 -15
  172. package/src/cli/mcp/transports/session-registry.ts +67 -5
  173. package/src/cli/mcp/types.ts +3 -3
  174. package/src/cli/repositories/command-classifier.ts +209 -14
  175. package/src/cli/repositories/command-executor.ts +55 -521
  176. package/src/cli/repositories/command-process.ts +108 -0
  177. package/src/cli/repositories/command-scope.ts +99 -41
  178. package/src/cli/repositories/controller-home.ts +7 -8
  179. package/src/cli/repositories/git-command-executor.ts +2 -0
  180. package/src/cli/repositories/locks.ts +53 -16
  181. package/src/cli/repositories/repository-snapshot.ts +121 -0
  182. package/src/cli/repositories/safe-patch.ts +6 -4
  183. package/src/cli/repositories/selected-path-actions.ts +17 -9
  184. package/src/cli/repositories/structured-git.ts +110 -10
  185. package/src/cli/repository/inspector.ts +565 -62
  186. package/src/cli/repository/session-cache.ts +58 -17
  187. package/src/cli/v81-entry.ts +1 -4
  188. package/src/effects/fs-transaction.ts +85 -17
  189. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  190. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  191. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  192. package/src/runtime/context/lsp-client.ts +283 -0
  193. package/src/runtime/context/semantic-navigation.ts +275 -0
  194. package/src/runtime/context/swift-navigation.ts +565 -0
  195. package/src/runtime/context/typescript-navigation.ts +226 -0
  196. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  197. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
  198. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  199. package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
  200. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  201. package/src/runtime/control-plane/execution/validation.ts +15 -2
  202. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  203. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  204. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  205. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  206. package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
  207. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
  208. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
  209. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
  210. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  211. package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
  212. package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
  213. package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
  214. package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
  215. package/src/runtime/control-plane/facade/index.ts +1 -0
  216. package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
  217. package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
  218. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  219. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  220. package/src/runtime/control-plane/facade/types.ts +55 -11
  221. package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
  222. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  223. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  224. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  225. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  226. package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
  227. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  228. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  229. package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
  230. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  231. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  232. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  233. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  234. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  235. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  236. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  237. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  238. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  239. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  240. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
  241. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
  242. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
  243. package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
  244. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  245. package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
  246. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  247. package/src/runtime/control-plane/release-retention.ts +62 -2
  248. package/src/runtime/control-plane/routing/route-policy.ts +7 -16
  249. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  250. package/src/runtime/diagnostics/mcp-timing.ts +19 -0
  251. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  252. package/src/runtime/diagnostics/performance.ts +24 -1
  253. package/src/runtime/evidence/event-ledger.ts +1 -1
  254. package/src/runtime/execution/jobs/store.ts +58 -4
  255. package/src/runtime/execution/jobs/types.ts +1 -1
  256. package/src/runtime/execution/managed-workspace.ts +203 -1
  257. package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
  258. package/src/runtime/execution/process-runtime/check-result.ts +63 -2
  259. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  260. package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
  261. package/src/runtime/execution/process-runtime/gc.ts +98 -12
  262. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
  263. package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
  264. package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
  265. package/src/runtime/execution/process-runtime/runtime.ts +59 -4
  266. package/src/runtime/execution/process-runtime/store.ts +7 -0
  267. package/src/runtime/execution/process-runtime/types.ts +2 -0
  268. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  269. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  270. package/src/runtime/execution/workers/executor.ts +0 -48
  271. package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
  272. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  273. package/src/runtime/gateway/mcp/router.ts +185 -83
  274. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
  275. package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
  276. package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
  277. package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
  278. package/src/runtime/plugins/browser-adapter.ts +2925 -318
  279. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  280. package/src/runtime/plugins/browser-handoff-host.ts +6 -31
  281. package/src/runtime/plugins/browser-handoff.ts +92 -5
  282. package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
  283. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  284. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  285. package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
  286. package/src/runtime/plugins/browser-runtime.ts +183 -0
  287. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  288. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  289. package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
  290. package/src/runtime/plugins/external-adapter.ts +324 -3
  291. package/src/runtime/plugins/external-registration.ts +84 -5
  292. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  293. package/src/runtime/plugins/first-party-registry.ts +4 -2
  294. package/src/runtime/plugins/github-adapter.ts +125 -0
  295. package/src/runtime/plugins/gmail-adapter.ts +28 -2
  296. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  297. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  298. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  299. package/src/runtime/plugins/ios-adapter.ts +106 -16
  300. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  301. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  302. package/src/runtime/plugins/lightweight-action.ts +153 -0
  303. package/src/runtime/plugins/local-system-adapter.ts +125 -8
  304. package/src/runtime/plugins/macos-capability-broker.ts +55 -9
  305. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  306. package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
  307. package/src/runtime/plugins/resend-adapter.ts +1 -1
  308. package/src/runtime/plugins/store.ts +366 -24
  309. package/src/runtime/plugins/types.ts +39 -2
  310. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  311. package/src/runtime/projections/git-status-sampler.ts +16 -16
  312. package/src/runtime/projections/materialized-view.ts +28 -10
  313. package/src/runtime/recovery/actions.ts +0 -10
  314. package/src/runtime/recovery/classifier.ts +0 -9
  315. package/src/runtime/recovery/maintenance-executor.ts +415 -18
  316. package/src/runtime/recovery/probe.ts +0 -1
  317. package/src/runtime/recovery/types.ts +0 -1
  318. package/src/runtime/root/mcp-transport.ts +180 -10
  319. package/src/runtime/root/package-connector-service.ts +186 -8
  320. package/src/runtime/root/package-runtime-release.ts +143 -17
  321. package/src/runtime/root/package-runtime-service.ts +430 -22
  322. package/src/runtime/root/release-manifest.ts +7 -2
  323. package/src/runtime/root/release-materialize.ts +162 -19
  324. package/src/runtime/root/release-store.ts +48 -11
  325. package/src/runtime/root/runtime.ts +23 -5
  326. package/src/runtime/root/service.ts +100 -27
  327. package/src/runtime/root/types.ts +2 -0
  328. package/src/runtime/safe-tooling/index.ts +0 -1
  329. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  330. package/src/runtime/safe-tooling/types.ts +0 -30
  331. package/src/runtime/shared/trusted-executable.ts +62 -0
  332. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  333. package/src/runtime/standalone-recovery/core.ts +702 -94
  334. package/src/runtime/standalone-recovery/entry.ts +99 -23
  335. package/src/runtime/standalone-recovery/installer.ts +19 -3
  336. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  337. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  338. package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
  339. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
  340. package/src/runtime/workflow/schedules/engine.ts +509 -80
  341. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  342. package/src/runtime/workflow/schedules/settlement.ts +48 -4
  343. package/src/runtime/workflow/schedules/store.ts +131 -10
  344. package/src/runtime/workflow/schedules/types.ts +6 -3
  345. package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
  346. package/src/testing/test-governance.ts +8 -40
  347. package/assets/reference-configs/heartbeat-triage.md +0 -57
  348. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  349. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  350. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  351. package/bin/forge-desktop-helper.mjs +0 -204
  352. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  353. package/docs/architecture/current/architecture-invariants.md +0 -331
  354. package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
  355. package/docs/architecture/current/codegraph-context-provider.md +0 -226
  356. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  357. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  358. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
  359. package/docs/architecture/current/entity-model.md +0 -592
  360. package/docs/architecture/current/external-plugin-governance.md +0 -396
  361. package/docs/architecture/current/failure-recovery.md +0 -447
  362. package/docs/architecture/current/governance.md +0 -213
  363. package/docs/architecture/current/human-interaction-plane.md +0 -87
  364. package/docs/architecture/current/implementation-status.md +0 -128
  365. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  366. package/docs/architecture/current/legacy-governance.md +0 -58
  367. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  368. package/docs/architecture/current/migration-roadmap.md +0 -105
  369. package/docs/architecture/current/multi-repository-execution.md +0 -371
  370. package/docs/architecture/current/operations-runbook.md +0 -45
  371. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  372. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  373. package/docs/architecture/current/repository-access-modes.md +0 -102
  374. package/docs/architecture/current/route-policy.md +0 -15
  375. package/docs/architecture/current/route-session-concurrency.md +0 -85
  376. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  377. package/docs/architecture/current/runtime-directory-map.md +0 -49
  378. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  379. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  380. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  381. package/docs/architecture/current/system-overview.md +0 -144
  382. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  383. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  384. package/docs/architecture/current/thin-harness-v1.md +0 -311
  385. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  386. package/docs/forge-autonomous-goal-loop.md +0 -9
  387. package/docs/forge-provider-configuration.md +0 -7
  388. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
  389. package/docs/operations/controller-desktop-plugin.md +0 -112
  390. package/docs/operations/gmail-assistant-routines.md +0 -186
  391. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  392. package/docs/operations/provider-configuration.md +0 -31
  393. package/scripts/harness-trace-grade.sh +0 -150
  394. package/scripts/heartbeat-triage.sh +0 -361
  395. package/scripts/maintenance-triage.sh +0 -167
  396. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  397. package/src/cli/repositories/goal-registry.ts +0 -239
  398. package/src/runtime/assistant/action-proposals.ts +0 -279
  399. package/src/runtime/assistant/intent.ts +0 -395
  400. package/src/runtime/assistant/model-provider.ts +0 -460
  401. package/src/runtime/assistant/openapi.ts +0 -223
  402. package/src/runtime/assistant/policy.ts +0 -89
  403. package/src/runtime/assistant/readiness.ts +0 -258
  404. package/src/runtime/assistant/routine-runtime.ts +0 -477
  405. package/src/runtime/assistant/schedule-binding.ts +0 -171
  406. package/src/runtime/assistant/standing-grants.ts +0 -375
  407. package/src/runtime/assistant/store.ts +0 -243
  408. package/src/runtime/assistant/types.ts +0 -135
  409. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  410. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  411. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  412. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  413. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  414. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  415. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  416. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  417. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  418. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  419. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  420. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  421. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  422. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  423. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  424. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  425. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  426. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  427. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  428. package/src/runtime/plugins/desktop-adapter.ts +0 -374
  429. package/src/runtime/safe-tooling/browser-safe.ts +0 -133
  430. package/src/runtime/workflow/findings/store.ts +0 -204
  431. package/src/runtime/workflow/findings/types.ts +0 -58
  432. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  433. package/src/runtime/workflow/portfolio/store.ts +0 -185
  434. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -80,7 +80,6 @@ import type {
80
80
  CommandCenterViewModel,
81
81
  ConnectorFreshnessViewModel,
82
82
  ConsoleErrorViewModel,
83
- GoalLoopStatusViewModel,
84
83
  HandoffCardViewModel,
85
84
  ModePreviewViewModel,
86
85
  PlainStatusTone,
@@ -94,34 +93,6 @@ import type {
94
93
  VerificationViewModel,
95
94
  WorkSummaryViewModel,
96
95
  } from './console-view-models';
97
- import {
98
- buildAutomationSettingsView,
99
- executorRoutePreviewWithConfig,
100
- executorRoutingConfigGet,
101
- executorRoutingConfigReset,
102
- executorRoutingConfigUpdate,
103
- goalLoopPolicyGet,
104
- goalLoopPolicyUpdate,
105
- goalStatus as goalLoopStatusSnapshot,
106
- localToolDisable,
107
- localToolEnable,
108
- localToolHealthCheck,
109
- localToolList,
110
- localToolConfigGet,
111
- localToolConfigUpdate,
112
- providerApiSettingsGet,
113
- providerApiSettingsUpdate,
114
- providerConfigGet,
115
- providerConfigUpdate,
116
- providerCredentialsStatus,
117
- providerDisable,
118
- providerEnable,
119
- providerHealthCheck,
120
- providerPriorityUpdate,
121
- providerResetDefaults,
122
- type ConfigFacadeContext,
123
- type GoalLoopContext,
124
- } from '../../runtime/control-plane/goal-loop';
125
96
  import { listActiveOccurrences, listSchedules } from '../../runtime/workflow/schedules/store';
126
97
 
127
98
  export type ConsoleFacadeContext = {
@@ -414,6 +385,8 @@ export function mapWorkSummary(
414
385
  || (work.status === 'running' ? '任务执行中…' : status.label);
415
386
  return {
416
387
  id: work.workId,
388
+ repoId: work.repoId,
389
+ updatedAt: work.updatedAt,
417
390
  title: work.objective.slice(0, 160) || '未命名任务',
418
391
  objective: work.objective,
419
392
  modeLabel: mode.label,
@@ -993,7 +966,6 @@ export async function buildCommandCenter(
993
966
  const handoffs = listHandoffItems({ ...store(ctx), status: 'pending', limit: 20 }).map(mapHandoffCard);
994
967
  const plugins = listConsolePlugins(ctx);
995
968
  const pluginSummary = buildPluginSummary(plugins);
996
- const goalLoop = buildGoalLoopStatusView(ctx);
997
969
  const access = controllerAccessStateView(ctx);
998
970
  const banner = readiness.connectorFreshness?.severity === 'warning' || readiness.connectorFreshness?.severity === 'error'
999
971
  ? readiness.connectorFreshness.summary
@@ -1012,7 +984,6 @@ export async function buildCommandCenter(
1012
984
  currentWork: activeWork[0],
1013
985
  recentWork: allRecent,
1014
986
  handoffs,
1015
- goalLoop,
1016
987
  pluginSummary,
1017
988
  plugins,
1018
989
  modePreviewDefault: plainMode('direct_control'),
@@ -1029,192 +1000,6 @@ export async function buildCommandCenter(
1029
1000
  };
1030
1001
  }
1031
1002
 
1032
- function configCtx(ctx: ConsoleFacadeContext): ConfigFacadeContext {
1033
- return { controllerHome: ctx.controllerHome };
1034
- }
1035
-
1036
- export function buildGoalLoopStatusView(ctx: ConsoleFacadeContext): GoalLoopStatusViewModel {
1037
- const goalCtx: GoalLoopContext = {
1038
- goalStore: store(ctx),
1039
- packetStore: store(ctx),
1040
- repoId: ctx.repository.repoId,
1041
- configLocation: { controllerHome: ctx.controllerHome },
1042
- providerEnv: { configLocation: { controllerHome: ctx.controllerHome } },
1043
- };
1044
- const snapshot = goalLoopStatusSnapshot(goalCtx) as {
1045
- activeGoals?: Array<Record<string, unknown>>;
1046
- activeCount?: number;
1047
- invokableProviders?: string[];
1048
- handoffOnlyProviders?: string[];
1049
- providers?: Array<Record<string, unknown>>;
1050
- };
1051
- let automationSummary: string | undefined;
1052
- let liveEffective: boolean | undefined;
1053
- try {
1054
- const settings = buildAutomationSettingsView(configCtx(ctx));
1055
- automationSummary = settings.overview.plainLanguageSummary;
1056
- liveEffective = settings.overview.liveModelProvidersEffective;
1057
- } catch {
1058
- automationSummary = undefined;
1059
- }
1060
-
1061
- const goals = (snapshot.activeGoals ?? []).map((goal) => {
1062
- const stage = String(goal.stage ?? '');
1063
- const providerSelected = typeof goal.providerSelected === 'string' ? goal.providerSelected : undefined;
1064
- const waitingReason = typeof goal.waitingReason === 'string' ? goal.waitingReason : undefined;
1065
- const nextSafeAction = typeof goal.nextSafeAction === 'string' ? goal.nextSafeAction : undefined;
1066
- const handoffPacketAvailable = goal.handoffPacketAvailable === true;
1067
- return {
1068
- title: String(goal.title ?? ''),
1069
- stage,
1070
- currentStep: String(goal.currentStep ?? ''),
1071
- providerSelected,
1072
- waitingReason,
1073
- nextSafeAction,
1074
- handoffPacketAvailable,
1075
- approvalRequired: Boolean(waitingReason) || stage === 'waiting_for_user',
1076
- whyThisProvider: providerSelected
1077
- ? `Last selected provider: ${providerSelected}`
1078
- : 'No provider selected yet',
1079
- whatHappensNext: nextSafeAction
1080
- ?? (handoffPacketAvailable
1081
- ? 'Open handoff packet or configure a direct provider'
1082
- : 'Wait for next daemon tick or open Automation Settings'),
1083
- whatIsBlocked: waitingReason
1084
- ?? (stage === 'handoff_ready'
1085
- ? 'Waiting for handoff supervisor (ChatGPT is not auto-invokable)'
1086
- : undefined),
1087
- };
1088
- });
1089
- return {
1090
- activeCount: snapshot.activeCount ?? goals.length,
1091
- goals,
1092
- invokableProviders: snapshot.invokableProviders ?? [],
1093
- handoffOnlyProviders: snapshot.handoffOnlyProviders ?? [],
1094
- providerHealth: (snapshot.providers ?? []).map((provider) => ({
1095
- providerId: String(provider.providerId ?? ''),
1096
- status: String(provider.status ?? ''),
1097
- directDispatchAllowed: provider.directDispatchAllowed === true,
1098
- handoffOnly: provider.handoffOnly === true,
1099
- summary: String(provider.summary ?? ''),
1100
- })),
1101
- automationSummary,
1102
- liveModelProvidersEffective: liveEffective,
1103
- settingsPathHint: 'Model & Tool Providers',
1104
- nextTickHint: 'Daemon ticks active goals about every 5 seconds when the controller is running.',
1105
- };
1106
- }
1107
-
1108
- export function getAutomationSettings(ctx: ConsoleFacadeContext) {
1109
- return buildAutomationSettingsView(configCtx(ctx));
1110
- }
1111
-
1112
- export function consoleProviderConfigGet(ctx: ConsoleFacadeContext) {
1113
- return providerConfigGet(configCtx(ctx));
1114
- }
1115
-
1116
- export function consoleProviderConfigUpdate(ctx: ConsoleFacadeContext, body: Record<string, unknown>) {
1117
- return providerConfigUpdate(configCtx(ctx), body as unknown as Parameters<typeof providerConfigUpdate>[1]);
1118
- }
1119
-
1120
- export function consoleProviderEnable(ctx: ConsoleFacadeContext, providerId: string) {
1121
- return providerEnable(configCtx(ctx), providerId);
1122
- }
1123
-
1124
- export function consoleProviderDisable(ctx: ConsoleFacadeContext, providerId: string) {
1125
- return providerDisable(configCtx(ctx), providerId);
1126
- }
1127
-
1128
- export function consoleProviderPriority(ctx: ConsoleFacadeContext, providerId: string, direction: 'up' | 'down' | number) {
1129
- return providerPriorityUpdate(configCtx(ctx), providerId, direction);
1130
- }
1131
-
1132
- export function consoleProviderHealth(ctx: ConsoleFacadeContext, providerId?: string) {
1133
- return providerHealthCheck(configCtx(ctx), providerId);
1134
- }
1135
-
1136
- export function consoleProviderCredentials(ctx: ConsoleFacadeContext) {
1137
- return providerCredentialsStatus(configCtx(ctx));
1138
- }
1139
-
1140
- export function consoleProviderReset(ctx: ConsoleFacadeContext) {
1141
- return providerResetDefaults(configCtx(ctx));
1142
- }
1143
-
1144
- export function consoleProviderApiSettingsGet(ctx: ConsoleFacadeContext, providerId: string) {
1145
- return providerApiSettingsGet(configCtx(ctx), providerId);
1146
- }
1147
-
1148
- export function consoleProviderApiSettingsUpdate(
1149
- ctx: ConsoleFacadeContext,
1150
- providerId: string,
1151
- body: Record<string, unknown>,
1152
- ) {
1153
- return providerApiSettingsUpdate(configCtx(ctx), providerId, {
1154
- baseUrl: typeof body.baseUrl === 'string' ? body.baseUrl : typeof body.base_url === 'string' ? body.base_url : undefined,
1155
- model: typeof body.model === 'string' ? body.model : undefined,
1156
- apiKey: typeof body.apiKey === 'string'
1157
- ? body.apiKey
1158
- : typeof body.api_key === 'string'
1159
- ? body.api_key
1160
- : undefined,
1161
- clearApiKey: body.clearApiKey === true || body.clear_api_key === true,
1162
- });
1163
- }
1164
-
1165
- export function consoleLocalToolList(ctx: ConsoleFacadeContext) {
1166
- return localToolList(configCtx(ctx));
1167
- }
1168
-
1169
- export function consoleLocalToolEnable(ctx: ConsoleFacadeContext, toolId: string) {
1170
- return localToolEnable(configCtx(ctx), toolId);
1171
- }
1172
-
1173
- export function consoleLocalToolDisable(ctx: ConsoleFacadeContext, toolId: string) {
1174
- return localToolDisable(configCtx(ctx), toolId);
1175
- }
1176
-
1177
- export function consoleLocalToolHealth(ctx: ConsoleFacadeContext, toolId?: string) {
1178
- return localToolHealthCheck(configCtx(ctx), toolId);
1179
- }
1180
-
1181
- export function consoleLocalToolConfigGet(ctx: ConsoleFacadeContext) {
1182
- return localToolConfigGet(configCtx(ctx));
1183
- }
1184
-
1185
- export function consoleLocalToolConfigUpdate(ctx: ConsoleFacadeContext, body: Record<string, unknown>) {
1186
- return localToolConfigUpdate(configCtx(ctx), body as unknown as Parameters<typeof localToolConfigUpdate>[1]);
1187
- }
1188
-
1189
- export function consoleRoutingGet(ctx: ConsoleFacadeContext) {
1190
- return executorRoutingConfigGet(configCtx(ctx));
1191
- }
1192
-
1193
- export function consoleRoutingUpdate(ctx: ConsoleFacadeContext, body: Record<string, unknown>) {
1194
- return executorRoutingConfigUpdate(configCtx(ctx), body as unknown as Parameters<typeof executorRoutingConfigUpdate>[1]);
1195
- }
1196
-
1197
- export function consoleRoutingReset(ctx: ConsoleFacadeContext) {
1198
- return executorRoutingConfigReset(configCtx(ctx));
1199
- }
1200
-
1201
- export function consoleRoutePreview(ctx: ConsoleFacadeContext, body: Record<string, unknown> = {}) {
1202
- return executorRoutePreviewWithConfig(configCtx(ctx), {
1203
- taskIntent: typeof body.taskIntent === 'string' ? body.taskIntent as never : typeof body.task_intent === 'string' ? body.task_intent as never : undefined,
1204
- risk: typeof body.risk === 'string' ? body.risk as never : undefined,
1205
- objective: typeof body.objective === 'string' ? body.objective : undefined,
1206
- externalWrite: body.externalWrite === true || body.external_write === true,
1207
- });
1208
- }
1209
-
1210
- export function consoleGoalLoopPolicyGet(ctx: ConsoleFacadeContext) {
1211
- return goalLoopPolicyGet(configCtx(ctx));
1212
- }
1213
-
1214
- export function consoleGoalLoopPolicyUpdate(ctx: ConsoleFacadeContext, body: Record<string, unknown>) {
1215
- return goalLoopPolicyUpdate(configCtx(ctx), body as unknown as Parameters<typeof goalLoopPolicyUpdate>[1]);
1216
- }
1217
-
1218
1003
  export function getConsoleAccessPolicy(ctx: ConsoleFacadeContext) {
1219
1004
  const policy = readRepositoryAccessPolicy(ctx.controllerHome, ctx.repository.repoId);
1220
1005
  return {
@@ -1,10 +1,10 @@
1
- import{useCallback,useEffect,useState}from'react';import'./design/tokens.css';import'./styles.css';import type{AutomationView,ConsoleData,LocalToolView,ProviderView,RouteId}from'./types';import{api}from'./lib/api';import{routeFromHash}from'./lib/routes';import{AppShell}from'./shell/AppShell';import{OverviewView}from'./features/overview/OverviewView';import{AutomationsView}from'./features/automations/AutomationsView';import{WorkView}from'./features/work/WorkView';import{CapabilitiesView}from'./features/capabilities/CapabilitiesView';import{RepositoriesView}from'./features/repositories/RepositoriesView';import{SettingsView}from'./features/settings/SettingsView';import{SystemView}from'./features/system/SystemView';
2
- async function loadData():Promise<ConsoleData>{const[commandCenter,work,automations,automationSettings,connector]=await Promise.all([api.commandCenter(),api.work(),api.automations(),api.automationSettings(),api.connector().catch(()=>undefined)]);return{commandCenter,work,automations,automationSettings,connector,generatedAt:new Date().toISOString()}}
1
+ import{useCallback,useEffect,useState}from'react';import'./design/tokens.css';import'./styles.css';import type{AutomationView,ConsoleData,RouteId}from'./types';import{api}from'./lib/api';import{routeFromHash}from'./lib/routes';import{AppShell}from'./shell/AppShell';import{OverviewView}from'./features/overview/OverviewView';import{AutomationsView}from'./features/automations/AutomationsView';import{WorkView}from'./features/work/WorkView';import{CapabilitiesView}from'./features/capabilities/CapabilitiesView';import{RepositoriesView}from'./features/repositories/RepositoriesView';import{SystemView}from'./features/system/SystemView';
2
+ async function loadData():Promise<ConsoleData>{const[commandCenter,work,workPortfolio,automations,connector]=await Promise.all([api.commandCenter(),api.work(),api.workPortfolio(),api.automations(),api.connector().catch(()=>undefined)]);return{commandCenter,work,workPortfolio,automations,connector,generatedAt:new Date().toISOString()}}
3
3
  export default function App(){const[route,setRoute]=useState<RouteId>(routeFromHash());const[data,setData]=useState<ConsoleData>();const[busy,setBusy]=useState(false);const[error,setError]=useState('');
4
4
  const refresh=useCallback(async()=>{setBusy(true);setError('');try{setData(await loadData())}catch(e){setError(e instanceof Error?e.message:String(e))}finally{setBusy(false)}},[]);
5
5
  useEffect(()=>{void refresh();const onHash=()=>setRoute(routeFromHash());addEventListener('hashchange',onHash);return()=>removeEventListener('hashchange',onHash)},[refresh]);
6
6
  const mutate=useCallback(async(fn:()=>Promise<unknown>)=>{setBusy(true);try{await fn();setData(await loadData())}catch(e){setError(e instanceof Error?e.message:String(e))}finally{setBusy(false)}},[]);
7
7
  if(!data)return <div className="boot-state"><span className="brand-mark">F</span><strong>{error?'Forge console unavailable':'Loading Forge…'}</strong>{error&&<><p>{error}</p><button className="button" onClick={()=>void refresh()}>Retry</button></>}</div>;
8
8
  const common={data,busy,onRefresh:()=>void refresh()};let view;
9
- switch(route){case'automations':view=<AutomationsView {...common} onAction={(a:AutomationView,action:'run'|'pause'|'resume')=>mutate(()=>api.automationAction(a.source,a.repoId,a.id,action))}/>;break;case'work':view=<WorkView {...common}/>;break;case'capabilities':view=<CapabilitiesView {...common}/>;break;case'repositories':view=<RepositoriesView {...common} onRegister={(p,n)=>mutate(()=>api.registerRepository(p,n))} onRemove={id=>mutate(()=>api.removeRepository(id))}/>;break;case'settings':view=<SettingsView {...common} onProviderAction={(p:ProviderView,a:'enable'|'disable')=>mutate(()=>api.providerAction(p.providerId,a))} onProviderHealth={(p:ProviderView)=>mutate(()=>api.providerHealth(p.providerId))} onToolAction={(t:LocalToolView,a:'enable'|'disable')=>mutate(()=>api.localToolAction(t.toolId,a))} onToolHealth={(t:LocalToolView)=>mutate(()=>api.localToolHealth(t.toolId))}/>;break;case'system':view=<SystemView {...common}/>;break;default:view=<OverviewView {...common}/>}
9
+ switch(route){case'automations':view=<AutomationsView {...common} onAction={(a:AutomationView,action:'run'|'pause'|'resume')=>mutate(()=>api.automationAction(a.source,a.repoId,a.id,action))}/>;break;case'work':view=<WorkView {...common}/>;break;case'capabilities':view=<CapabilitiesView {...common}/>;break;case'repositories':view=<RepositoriesView {...common} onRegister={(p,n)=>mutate(()=>api.registerRepository(p,n))} onRemove={id=>mutate(()=>api.removeRepository(id))}/>;break;case'system':view=<SystemView {...common}/>;break;default:view=<OverviewView {...common}/>}
10
10
  return <AppShell route={route}>{error&&<div className="global-error"><strong>Last action failed</strong><span>{error}</span><button onClick={()=>setError('')}>×</button></div>}{view}</AppShell>}
@@ -1,3 +1,153 @@
1
- import{useMemo,useState}from'react';import type{AutomationView,ConsoleData}from'../../types';import{CommandBar}from'../../shell/CommandBar';import{Segmented}from'../../components/Segmented';import{DetailPane,DefinitionList}from'../../components/DetailPane';import{StatusText}from'../../components/StatusText';import{Button}from'../../components/Button';import{formatDate,compact}from'../../lib/format';
2
- type Filter='enabled'|'paused'|'attention'|'all';
3
- export function AutomationsView({data,busy,onRefresh,onAction}:{data:ConsoleData;busy:boolean;onRefresh:()=>void;onAction:(a:AutomationView,action:'run'|'pause'|'resume')=>Promise<void>}){const all=data.automations.automations;const[filter,setFilter]=useState<Filter>('enabled');const list=useMemo(()=>all.filter(a=>filter==='all'||a.status===filter),[all,filter]);const[selectedKey,setSelectedKey]=useState<string>();const key=(a:AutomationView)=>`${a.source}:${a.repoId}:${a.id}`;const selected=list.find(a=>key(a)===selectedKey)??list[0];return <><CommandBar eyebrow="LONG-RUNNING CONFIG" title="Automations" description="管理 Forge 持久化 Schedule 与 Assistant Routine;结果正文继续发送到 ChatGPT / Email。" refreshedAt={data.automations.generatedAt} busy={busy} onRefresh={onRefresh}/><div className="toolbar"><Segmented value={filter} onChange={setFilter} items={[{id:'enabled',label:'Enabled',count:all.filter(x=>x.status==='enabled').length},{id:'paused',label:'Paused',count:all.filter(x=>x.status==='paused').length},{id:'attention',label:'Attention',count:all.filter(x=>x.status==='attention').length},{id:'all',label:'All',count:all.length}]}/></div><div className="split-workspace automation-layout"><div className="table-wrap"><table className="data-table"><thead><tr><th>Automation</th><th>Schedule</th><th>Delivery</th><th>Status</th><th>Last</th><th>Next</th></tr></thead><tbody>{list.map(a=><tr key={key(a)} className={selected&&key(selected)===key(a)?'selected':''} onClick={()=>setSelectedKey(key(a))}><td><strong>{a.name}</strong><small>{a.repositoryName} · {a.source}</small></td><td>{a.schedule}</td><td>{a.delivery??'—'}</td><td><StatusText label={a.status} tone={a.status}/></td><td><span>{compact(a.lastResult,30)||'—'}</span><small>{formatDate(a.lastRunAt)}</small></td><td>{formatDate(a.nextRunHint)}</td></tr>)}</tbody></table>{!list.length&&<div className="quiet-empty">这个筛选条件下没有 Automation。</div>}</div><DetailPane title={selected?.name} subtitle={selected?.summary} empty="选择一个 Automation 查看配置">{selected&&<><DefinitionList items={[["Status",<StatusText label={selected.status} tone={selected.status}/>],["Schedule",selected.schedule],["Source",selected.source],["Repository",selected.repositoryName],["Delivery",selected.delivery??'—'],["Last result",selected.lastResult??'—'],["Last run",formatDate(selected.lastRunAt)],["Next",formatDate(selected.nextRunHint)]]}/>{selected.pausedReason&&<div className="detail-callout warning"><strong>Paused reason</strong><p>{selected.pausedReason}</p></div>}<div className="detail-button-row">{selected.actions.map(action=><Button key={action} disabled={busy} className={action==='pause'?'danger-text':''} onClick={()=>void onAction(selected,action)}>{action==='run'?'Run now':action==='pause'?'Pause':'Resume'}</Button>)}</div><p className="detail-note">这里只保存调度配置与最近一次结果摘要,不复制日报、SEO 或研究正文。</p></>}</DetailPane></div></>}
1
+ import { useMemo, useState } from 'react';
2
+ import type { AutomationHistoryView, AutomationView, ConsoleData } from '../../types';
3
+ import { CommandBar } from '../../shell/CommandBar';
4
+ import { Segmented } from '../../components/Segmented';
5
+ import { DetailPane, DefinitionList } from '../../components/DetailPane';
6
+ import { StatusText } from '../../components/StatusText';
7
+ import { Button } from '../../components/Button';
8
+ import { formatDate, compact } from '../../lib/format';
9
+
10
+ type Filter = 'enabled' | 'paused' | 'attention' | 'completed' | 'all';
11
+
12
+ function statusLabel(status: AutomationView['status']): string {
13
+ if (status === 'enabled') return '运行中';
14
+ if (status === 'paused') return '已暂停';
15
+ if (status === 'attention') return '需要处理';
16
+ if (status === 'completed') return '已完成';
17
+ return '已停用';
18
+ }
19
+
20
+ function statusTone(status: AutomationView['status']): string {
21
+ if (status === 'enabled') return 'success';
22
+ if (status === 'attention') return 'danger';
23
+ if (status === 'paused') return 'warning';
24
+ if (status === 'completed') return 'success';
25
+ return 'neutral';
26
+ }
27
+
28
+ function observationLabel(value?: AutomationView['observationStatus']): string | undefined {
29
+ if (value === 'baseline') return '已建立基线';
30
+ if (value === 'unchanged') return '无变化';
31
+ if (value === 'changed') return '检测到变化';
32
+ if (value === 'keepalive') return '登录保持正常';
33
+ if (value === 'auth_required') return '需要重新登录';
34
+ return undefined;
35
+ }
36
+
37
+ function reasoningLabel(value?: string): string {
38
+ if (value === 'high') return '高';
39
+ if (value === 'medium') return '中';
40
+ if (value === 'xhigh') return '超高';
41
+ return value ?? '—';
42
+ }
43
+
44
+ function tabPolicyLabel(value?: string): string {
45
+ if (value === 'auto') return '自动 · 同一任务优先复用';
46
+ if (value === 'reuse') return '始终复用已绑定会话';
47
+ if (value === 'new') return '每次新开标签页';
48
+ return value ?? '—';
49
+ }
50
+
51
+ function executionDetails(automation: AutomationView): Array<[string, string]> {
52
+ if (!automation.agentModel) return [];
53
+ return [
54
+ ['执行模型', `${automation.agentModel} · ${reasoningLabel(automation.reasoningLevel)}推理`],
55
+ ['标签页策略', tabPolicyLabel(automation.tabPolicy)],
56
+ ];
57
+ }
58
+
59
+ function nextRunLabel(value?: string, completed = false): string {
60
+ if (completed) return '不会再次触发';
61
+ if (!value) return '等待下一次计划';
62
+ return Number.isFinite(Date.parse(value)) ? formatDate(value) : value;
63
+ }
64
+
65
+ function historyTone(tone: AutomationHistoryView['tone']): string {
66
+ if (tone === 'green') return 'success';
67
+ if (tone === 'amber') return 'warning';
68
+ if (tone === 'red') return 'danger';
69
+ if (tone === 'blue') return 'info';
70
+ return 'neutral';
71
+ }
72
+
73
+ function History({ items }: { items: AutomationHistoryView[] }) {
74
+ if (!items.length) return <div className="automation-history-empty">还没有执行记录。</div>;
75
+ return <div className="automation-history">{items.map((item) => <div className="automation-history-row" key={item.id}>
76
+ <div className={`automation-history-mark ${item.tone}`} />
77
+ <div className="automation-history-copy">
78
+ <div className="automation-history-top"><StatusText label={item.result} tone={historyTone(item.tone)} /><time>{formatDate(item.at)}</time></div>
79
+ {item.reason && <p>{item.reason}</p>}
80
+ {item.trigger && <small>{item.trigger}触发</small>}
81
+ </div>
82
+ </div>)}</div>;
83
+ }
84
+
85
+ export function AutomationsView({ data, busy, onRefresh, onAction }: {
86
+ data: ConsoleData;
87
+ busy: boolean;
88
+ onRefresh: () => void;
89
+ onAction: (automation: AutomationView, action: 'run' | 'pause' | 'resume') => Promise<void>;
90
+ }) {
91
+ const all = data.automations.automations;
92
+ const [filter, setFilter] = useState<Filter>('enabled');
93
+ const list = useMemo(() => all.filter((automation) => filter === 'all'
94
+ || (filter === 'paused' ? automation.status === 'paused' || automation.status === 'disabled' : automation.status === filter)), [all, filter]);
95
+ const [selectedKey, setSelectedKey] = useState<string>();
96
+ const key = (automation: AutomationView) => `${automation.source}:${automation.repoId}:${automation.id}`;
97
+ const selected = list.find((automation) => key(automation) === selectedKey) ?? list[0];
98
+ const observation = selected ? observationLabel(selected.observationStatus) : undefined;
99
+
100
+ return <>
101
+ <CommandBar eyebrow="AUTOMATION" title="自动任务" description="查看哪些任务正在运行、何时再次执行、是否需要处理,以及最近实际发生了什么。" refreshedAt={data.automations.generatedAt} busy={busy} onRefresh={onRefresh} />
102
+ <div className="toolbar automation-toolbar">
103
+ <Segmented value={filter} onChange={setFilter} items={[
104
+ { id: 'enabled', label: '运行中', count: all.filter((item) => item.status === 'enabled').length },
105
+ { id: 'paused', label: '已暂停', count: all.filter((item) => item.status === 'paused' || item.status === 'disabled').length },
106
+ { id: 'attention', label: '需要处理', count: all.filter((item) => item.status === 'attention').length },
107
+ { id: 'completed', label: '已完成', count: all.filter((item) => item.status === 'completed').length },
108
+ { id: 'all', label: '全部', count: all.length },
109
+ ]} />
110
+ </div>
111
+ <div className="split-workspace automation-layout">
112
+ <div className="table-wrap">
113
+ <table className="data-table automation-table">
114
+ <thead><tr><th>自动任务</th><th>触发</th><th>行为</th><th>状态</th><th>最近结果</th></tr></thead>
115
+ <tbody>{list.map((automation) => <tr key={key(automation)} className={selected && key(selected) === key(automation) ? 'selected' : ''} onClick={() => setSelectedKey(key(automation))}>
116
+ <td><strong>{automation.name}</strong><small>{automation.repositoryName} · {automation.modeLabel}</small></td>
117
+ <td><span>{automation.schedule}</span><small>{automation.timezone ?? '本地时区'}</small></td>
118
+ <td><span>{automation.delivery ?? '本地执行'}</span>{automation.targetLabel && <small>{automation.targetLabel}</small>}</td>
119
+ <td><StatusText label={statusLabel(automation.status)} tone={statusTone(automation.status)} />{automation.live !== undefined && <small>{automation.live ? '实际执行' : '仅预演'}</small>}</td>
120
+ <td><span>{compact(automation.lastResult, 26) || '—'}</span><small>{formatDate(automation.lastRunAt)}</small></td>
121
+ </tr>)}</tbody>
122
+ </table>
123
+ {!list.length && <div className="quiet-empty">这个筛选条件下没有 Automation。</div>}
124
+ </div>
125
+ <DetailPane title={selected?.name} subtitle={selected?.summary} empty="选择一个 Automation 查看配置与执行历史">
126
+ {selected && <>
127
+ <div className="automation-detail-status">
128
+ <div><span className="eyebrow">当前状态</span><StatusText label={statusLabel(selected.status)} tone={statusTone(selected.status)} /></div>
129
+ <div className="automation-result"><strong>{selected.lastResult ?? '尚未执行'}</strong><small>{formatDate(selected.observationAt ?? selected.lastRunAt)}</small></div>
130
+ </div>
131
+ <DefinitionList items={[
132
+ ['类型', selected.modeLabel],
133
+ ['触发计划', `${selected.schedule}${selected.timezone ? ` · ${selected.timezone}` : ''}`],
134
+ ['触发后的行为', selected.delivery ?? '本地执行'],
135
+ ['下次执行', nextRunLabel(selected.nextRunHint, selected.status === 'completed')],
136
+ ['观察目标', selected.targetLabel ?? '—'],
137
+ ['观察状态', observation ?? '—'],
138
+ ['关联工作', selected.boundWorkObjective ? compact(selected.boundWorkObjective, 96) : selected.boundWorkId ?? '—'],
139
+ ['执行方式', selected.live === undefined ? '—' : selected.live ? '实际执行' : '仅预演'],
140
+ ...executionDetails(selected),
141
+ ]} />
142
+ {selected.attentionMessage && <div className="detail-callout danger"><strong>需要处理</strong><p>{selected.attentionMessage}</p></div>}
143
+ {!selected.attentionMessage && selected.pausedReason && <div className={`detail-callout ${selected.status === 'completed' ? 'success' : 'warning'}`}><strong>{selected.status === 'completed' ? '任务已完成' : '暂停原因'}</strong><p>{selected.pausedReason}</p></div>}
144
+ <div className="detail-button-row">{selected.actions.map((action) => <Button key={action} disabled={busy} className={action === 'pause' ? 'danger-text' : ''} onClick={() => void onAction(selected, action)}>{action === 'run' ? '立即运行' : action === 'pause' ? '暂停任务' : '恢复任务'}</Button>)}</div>
145
+ <div className="automation-section-head"><div><span className="eyebrow">执行记录</span><h3>最近执行</h3></div><span>{selected.history.length} 条</span></div>
146
+ <History items={selected.history} />
147
+ <details className="advanced automation-advanced"><summary>技术信息</summary><pre>{JSON.stringify({ scheduleId: selected.source === 'schedule' ? selected.id : undefined, workId: selected.boundWorkId, source: selected.source, next: selected.nextRunHint, failureCount: selected.failureCount, policy: selected.policySummary }, null, 2)}</pre></details>
148
+ <p className="detail-note">这里只展示配置、状态与执行摘要;邮件正文、浏览器 Cookie、登录凭据和 continuation prompt 不会复制到控制台。</p>
149
+ </>}
150
+ </DetailPane>
151
+ </div>
152
+ </>;
153
+ }
@@ -1,4 +1,37 @@
1
- import{useMemo,useState}from'react';import type{ConsoleData,PluginView}from'../../types';import{CommandBar}from'../../shell/CommandBar';import{Segmented}from'../../components/Segmented';import{DetailPane,DefinitionList}from'../../components/DetailPane';import{StatusText}from'../../components/StatusText';import{compact,pretty}from'../../lib/format';
2
- type Filter='all'|'extensions'|'services'|'execution'|'models';
3
- function category(p:PluginView):Exclude<Filter,'all'|'models'>{const s=`${p.name} ${p.provider} ${(p.capabilityLabels??[]).join(' ')}`.toLowerCase();if(/gmail|calendar|github|google task|notion/.test(s))return'services';if(/browser|desktop|ios|repository|codegraph|local/.test(s))return'execution';return'extensions'}
4
- export function CapabilitiesView({data,busy,onRefresh}:{data:ConsoleData;busy:boolean;onRefresh:()=>void}){const plugins=data.commandCenter.plugins??[],providers=data.automationSettings.providers??[];const[filter,setFilter]=useState<Filter>('all');const[selectedId,setSelectedId]=useState<string>();const filtered=useMemo(()=>plugins.filter(p=>filter==='all'||filter==='models'||category(p)===filter),[plugins,filter]);const selected=filtered.find(x=>x.id===selectedId)??filtered[0];return <><CommandBar eyebrow="CAPABILITY CATALOG" title="Capabilities" description="从“Forge 能做什么”查看扩展、服务、执行能力和模型,而不是浏览 MCP tool 清单。" refreshedAt={data.generatedAt} busy={busy} onRefresh={onRefresh}/><div className="toolbar"><Segmented value={filter} onChange={setFilter} items={[{id:'all',label:'All',count:plugins.length+providers.length},{id:'extensions',label:'Extensions',count:plugins.filter(x=>category(x)==='extensions').length},{id:'services',label:'Services',count:plugins.filter(x=>category(x)==='services').length},{id:'execution',label:'Execution',count:plugins.filter(x=>category(x)==='execution').length},{id:'models',label:'Models',count:providers.length}]}/></div>{filter==='models'?<div className="single-list"><div className="scan-list">{providers.map(p=><div className="scan-row static" key={p.providerId}><div className="scan-main"><strong>{p.displayName}</strong><p>{compact(p.explanation??p.summary,110)}</p></div><StatusText label={p.statusLabel??p.status??'Unknown'} tone={p.status}/></div>)}</div></div>:<div className="split-workspace"><div className="scan-list">{filtered.map(p=><button key={p.id} className={`scan-row ${selected?.id===p.id?'selected':''}`} onClick={()=>setSelectedId(p.id)}><div className="scan-main"><span className="row-eyebrow">{category(p).toUpperCase()}</span><strong>{p.name}</strong><p>{compact(p.description,100)}</p></div><StatusText label={p.statusLabel??p.status??'Unknown'} tone={p.status??p.tone}/></button>)}</div><DetailPane title={selected?.name} subtitle={selected?.description}>{selected&&<><DefinitionList items={[["Status",<StatusText label={selected.statusLabel??selected.status??'Unknown'} tone={selected.status??selected.tone}/>],["Provider",selected.provider??'—'],["Health",selected.healthLabel??'—'],["Lifecycle",selected.lifecycleLabel??'—']]}/>{selected.nextStep&&<div className="detail-callout warning"><strong>Next step</strong><p>{selected.nextStep}</p></div>}{(selected.capabilityLabels??[]).length>0&&<div className="capability-lines">{selected.capabilityLabels!.map(x=><span key={x}>{x}</span>)}</div>}{(selected.warnings??[]).map(w=><div className="detail-callout warning" key={w}>{w}</div>)}<details className="advanced"><summary>Advanced · actions & protocol</summary><pre>{pretty({actions:selected.actions,advanced:selected.advanced})}</pre></details></>}</DetailPane></div>}</>}
1
+ import{useMemo,useState}from'react';
2
+ import type{ConsoleData,PluginView}from'../../types';
3
+ import{CommandBar}from'../../shell/CommandBar';
4
+ import{Segmented}from'../../components/Segmented';
5
+ import{DetailPane,DefinitionList}from'../../components/DetailPane';
6
+ import{StatusText}from'../../components/StatusText';
7
+ import{compact,pretty}from'../../lib/format';
8
+
9
+ type Filter='all'|'extensions'|'services'|'execution';
10
+
11
+ function category(plugin:PluginView):Exclude<Filter,'all'>{
12
+ const text=`${plugin.name} ${plugin.provider} ${(plugin.capabilityLabels??[]).join(' ')}`.toLowerCase();
13
+ if(/gmail|calendar|github|google task|notion/.test(text))return'services';
14
+ if(/browser|desktop|ios|repository|codegraph|local/.test(text))return'execution';
15
+ return'extensions';
16
+ }
17
+
18
+ export function CapabilitiesView({data,busy,onRefresh}:{data:ConsoleData;busy:boolean;onRefresh:()=>void}){
19
+ const plugins=data.commandCenter.plugins??[];
20
+ const[filter,setFilter]=useState<Filter>('all');
21
+ const[selectedId,setSelectedId]=useState<string>();
22
+ const filtered=useMemo(()=>plugins.filter(plugin=>filter==='all'||category(plugin)===filter),[plugins,filter]);
23
+ const selected=filtered.find(plugin=>plugin.id===selectedId)??filtered[0];
24
+ return <>
25
+ <CommandBar eyebrow="CAPABILITY CATALOG" title="Capabilities" description="从“Forge 能做什么”查看扩展、服务与执行能力,而不是浏览 MCP tool 清单。" refreshedAt={data.generatedAt} busy={busy} onRefresh={onRefresh}/>
26
+ <div className="toolbar"><Segmented value={filter} onChange={setFilter} items={[
27
+ {id:'all',label:'All',count:plugins.length},
28
+ {id:'extensions',label:'Extensions',count:plugins.filter(plugin=>category(plugin)==='extensions').length},
29
+ {id:'services',label:'Services',count:plugins.filter(plugin=>category(plugin)==='services').length},
30
+ {id:'execution',label:'Execution',count:plugins.filter(plugin=>category(plugin)==='execution').length},
31
+ ]}/></div>
32
+ <div className="split-workspace">
33
+ <div className="scan-list">{filtered.map(plugin=><button key={plugin.id} className={`scan-row ${selected?.id===plugin.id?'selected':''}`} onClick={()=>setSelectedId(plugin.id)}><div className="scan-main"><span className="row-eyebrow">{category(plugin).toUpperCase()}</span><strong>{plugin.name}</strong><p>{compact(plugin.description,100)}</p></div><StatusText label={plugin.statusLabel??plugin.status??'Unknown'} tone={plugin.status??plugin.tone}/></button>)}</div>
34
+ <DetailPane title={selected?.name} subtitle={selected?.description}>{selected&&<><DefinitionList items={[["Status",<StatusText label={selected.statusLabel??selected.status??'Unknown'} tone={selected.status??selected.tone}/>],["Provider",selected.provider??'—'],["Health",selected.healthLabel??'—'],["Lifecycle",selected.lifecycleLabel??'—']]}/>{selected.nextStep&&<div className="detail-callout warning"><strong>Next step</strong><p>{selected.nextStep}</p></div>}{(selected.capabilityLabels??[]).length>0&&<div className="capability-lines">{selected.capabilityLabels!.map(label=><span key={label}>{label}</span>)}</div>}{(selected.warnings??[]).map(warning=><div className="detail-callout warning" key={warning}>{warning}</div>)}<details className="advanced"><summary>Advanced · actions & protocol</summary><pre>{pretty({actions:selected.actions,advanced:selected.advanced})}</pre></details></>}</DetailPane>
35
+ </div>
36
+ </>;
37
+ }