@moretea-labs/forge 1.6.0 → 1.7.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 (469) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +39 -0
  3. package/CLAUDE.md +4 -0
  4. package/README.md +2 -2
  5. package/README.zh-CN.md +1 -1
  6. package/SKILL.md +2 -2
  7. package/THIRD_PARTY_NOTICES.md +1 -1
  8. package/agents/openai.yaml +1 -1
  9. package/assets/hooks/hook-input.sh +11 -8
  10. package/assets/hooks/lib/session-state.sh +10 -7
  11. package/assets/hooks/lib/workflow-state.sh +13 -177
  12. package/assets/hooks/post-tool-observer.sh +8 -2
  13. package/assets/hooks/prompt-guard.sh +5 -81
  14. package/assets/hooks/session-start-context.sh +56 -1
  15. package/assets/partials/05-workflow.partial.md +1 -1
  16. package/assets/partials-agents/02-operating-mode.partial.md +2 -0
  17. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  18. package/assets/plugin-registry.v1.json +3 -3
  19. package/assets/reference-configs/document-generation.md +1 -1
  20. package/assets/reference-configs/harness-overview.md +1 -1
  21. package/assets/reference-configs/sprint-contracts.md +3 -3
  22. package/assets/skill-version.json +2 -2
  23. package/assets/templates/contract.template.md +2 -7
  24. package/assets/templates/helpers/capture-plan.sh +2 -2
  25. package/assets/templates/helpers/check-architecture-sync.sh +17 -0
  26. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  27. package/assets/templates/helpers/contract-worktree.sh +1 -21
  28. package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
  29. package/assets/templates/helpers/inspect-project-state.ts +8 -6
  30. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  31. package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
  32. package/assets/templates/helpers/new-plan.sh +1 -1
  33. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  34. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  35. package/assets/templates/helpers/verify-contract.sh +1 -111
  36. package/assets/templates/helpers/verify-sprint.sh +3 -180
  37. package/assets/templates/helpers/workflow-contract.ts +5 -1
  38. package/assets/templates/plan.template.md +1 -1
  39. package/assets/templates/review.template.md +9 -34
  40. package/assets/workflow-contract.v1.json +10 -19
  41. package/docs/README.md +10 -10
  42. package/docs/architecture/CURRENT.md +178 -0
  43. package/docs/architecture/EVOLUTION.md +42 -0
  44. package/docs/architecture/current/README.md +4 -156
  45. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  46. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  47. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  48. package/docs/architecture/history/README.md +7 -0
  49. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  50. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  51. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  52. package/docs/architecture/history.md +3 -34
  53. package/docs/architecture/index.md +15 -98
  54. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  55. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  56. package/docs/architecture/versions/1.6.md +38 -0
  57. package/docs/architecture/versions/1.7.md +41 -0
  58. package/docs/forge-chatgpt-browser-engine.md +2 -2
  59. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  60. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  61. package/docs/forge-github-issue-launcher.md +1 -1
  62. package/docs/forge-plugin-management.md +1 -1
  63. package/docs/forge-runtime-self-healing-loop.md +1 -1
  64. package/docs/operations/controller-browser-plugin.md +26 -6
  65. package/docs/operations/controller-performance-and-502.md +143 -0
  66. package/docs/operations/controller-reliability-runbook.md +1 -1
  67. package/docs/operations/features.md +2 -2
  68. package/docs/operations/github-repository.md +1 -1
  69. package/docs/operations/homebrew.md +2 -2
  70. package/docs/operations/mcp-tool-exposure.md +5 -3
  71. package/docs/wiki/Architecture.md +6 -6
  72. package/docs/wiki/Implementation.md +2 -2
  73. package/docs/wiki/Integrations.md +2 -2
  74. package/docs/wiki/Work-Lifecycle.md +1 -1
  75. package/package.json +33 -11
  76. package/scripts/activate-source-baseline.ts +17 -13
  77. package/scripts/architecture-event.ts +2 -820
  78. package/scripts/architecture-queue.sh +2 -645
  79. package/scripts/archive-architecture-request.sh +2 -242
  80. package/scripts/archive-workflow.sh +1 -291
  81. package/scripts/benchmark-background-check-overlap.ts +228 -0
  82. package/scripts/benchmark-mcp-host.sh +117 -0
  83. package/scripts/benchmark-mcp-transport.ts +170 -0
  84. package/scripts/benchmark-quality-harness.ts +146 -0
  85. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  86. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  87. package/scripts/benchmark-typescript-navigation.ts +186 -0
  88. package/scripts/benchmark-work-efficiency.ts +334 -0
  89. package/scripts/capability-config.ts +2 -392
  90. package/scripts/capability-resolver.ts +2 -503
  91. package/scripts/capture-plan.sh +1 -332
  92. package/scripts/check-agent-tooling.sh +2 -1558
  93. package/scripts/check-architecture-sync.sh +2 -371
  94. package/scripts/check-brain-manifest.sh +2 -253
  95. package/scripts/check-context-files.sh +2 -47
  96. package/scripts/check-deploy-sql-order.sh +2 -115
  97. package/scripts/check-mcp-compatibility.ts +14 -0
  98. package/scripts/check-runtime-architecture.mjs +349 -79
  99. package/scripts/check-skill-version.ts +3 -191
  100. package/scripts/check-source-duplication.mjs +61 -0
  101. package/scripts/check-stable-baseline.ts +92 -0
  102. package/scripts/check-task-sync.sh +2 -63
  103. package/scripts/check-task-workflow.sh +2 -1000
  104. package/scripts/codex-handoff-resume.sh +2 -267
  105. package/scripts/context-contract-sync.sh +2 -514
  106. package/scripts/contract-run.ts +2 -463
  107. package/scripts/contract-worktree.sh +1 -722
  108. package/scripts/ensure-task-workflow.sh +1 -1225
  109. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  110. package/scripts/inspect-project-state.ts +4 -279
  111. package/scripts/install-standalone-recovery.ts +24 -0
  112. package/scripts/lib/project-init-lib.sh +22 -46
  113. package/scripts/lib/run-forge-helper.sh +19 -0
  114. package/scripts/lib/run-forge-helper.ts +26 -0
  115. package/scripts/migrate-project-template.sh +1 -1189
  116. package/scripts/migrate-workflow-docs.ts +4 -412
  117. package/scripts/new-plan.sh +1 -180
  118. package/scripts/new-spec.sh +1 -47
  119. package/scripts/new-sprint.sh +1 -46
  120. package/scripts/plan-to-todo.sh +1 -796
  121. package/scripts/prepare-codex-handoff.sh +2 -201
  122. package/scripts/prepare-handoff.sh +1 -78
  123. package/scripts/refresh-current-status.sh +2 -467
  124. package/scripts/run-governed-gate.ts +5 -1
  125. package/scripts/select-agent-context-blocks.sh +2 -64
  126. package/scripts/ship-worktrees.sh +1 -558
  127. package/scripts/smoke-ios-physical-device.ts +4 -2
  128. package/scripts/smoke-runtime-recovery.ts +1 -35
  129. package/scripts/smoke-schedule-engine.ts +1 -20
  130. package/scripts/sprint-backlog.sh +1 -834
  131. package/scripts/stage-runtime-release.ts +2 -1
  132. package/scripts/summarize-failures.sh +2 -123
  133. package/scripts/switch-plan.sh +1 -150
  134. package/scripts/sync-brain-docs.sh +2 -379
  135. package/scripts/sync-generated-authority.mjs +175 -0
  136. package/scripts/verify-contract.sh +2 -703
  137. package/scripts/verify-forge-runtime.sh +0 -1
  138. package/scripts/verify-sprint.sh +1 -677
  139. package/scripts/workflow-contract.ts +4 -205
  140. package/scripts/workstream-sync.sh +2 -261
  141. package/src/cli/agent-jobs/executor-health.ts +1 -1
  142. package/src/cli/commands/init-hook.ts +3 -3
  143. package/src/cli/commands/mcp.ts +9 -5
  144. package/src/cli/commands/plugin.ts +12 -3
  145. package/src/cli/commands/recovery.ts +25 -3
  146. package/src/cli/commands/runtime.ts +55 -3
  147. package/src/cli/commands/security.ts +12 -1
  148. package/src/cli/commands/setup-profile.ts +31 -21
  149. package/src/cli/controller/check-runner.ts +113 -5
  150. package/src/cli/controller/composite-result.ts +1 -1
  151. package/src/cli/controller/context/focus.ts +51 -0
  152. package/src/cli/controller/context/instruction-context.ts +114 -0
  153. package/src/cli/controller/context/known-paths.ts +76 -0
  154. package/src/cli/controller/context/query-planning.ts +110 -0
  155. package/src/cli/controller/context/rule-resolution.ts +532 -0
  156. package/src/cli/controller/context/source-materializer.ts +278 -0
  157. package/src/cli/controller/context/structural.ts +16 -0
  158. package/src/cli/controller/context/types.ts +286 -0
  159. package/src/cli/controller/context-pack.ts +828 -487
  160. package/src/cli/controller/launch-agents.ts +77 -2
  161. package/src/cli/controller/operational-plan.ts +2 -2
  162. package/src/cli/controller/work-mode.ts +6 -4
  163. package/src/cli/editing/edit-session.ts +60 -7
  164. package/src/cli/github/contracts.ts +16 -0
  165. package/src/cli/github/github.ts +135 -16
  166. package/src/cli/github/session.ts +2 -1
  167. package/src/cli/installer/managed-entries.ts +15 -1
  168. package/src/cli/local-bridge/console-automations.ts +54 -78
  169. package/src/cli/local-bridge/console-view-models.ts +1 -35
  170. package/src/cli/local-bridge/facade-api.ts +37 -264
  171. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  172. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
  173. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  174. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
  175. package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
  176. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  177. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
  178. package/src/cli/local-bridge/frontend/src/styles.css +1 -1
  179. package/src/cli/local-bridge/frontend/src/types.ts +5 -8
  180. package/src/cli/local-bridge/job-store.ts +1 -490
  181. package/src/cli/local-bridge/server.ts +2 -515
  182. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  183. package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
  184. package/src/cli/mcp/auth.ts +5 -5
  185. package/src/cli/mcp/instructions.ts +3 -2
  186. package/src/cli/mcp/legacy-tool-service.ts +10 -222
  187. package/src/cli/mcp/multi-repository.ts +16 -5
  188. package/src/cli/mcp/oauth.ts +175 -26
  189. package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
  190. package/src/cli/mcp/repository-tools.ts +282 -146
  191. package/src/cli/mcp/server.ts +586 -116
  192. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  193. package/src/cli/mcp/tool-contract.ts +14 -0
  194. package/src/cli/mcp/toolset-selection.ts +1 -1
  195. package/src/cli/mcp/toolset.ts +44 -7
  196. package/src/cli/mcp/transports/http.ts +124 -14
  197. package/src/cli/mcp/transports/session-registry.ts +43 -5
  198. package/src/cli/mcp/types.ts +3 -3
  199. package/src/cli/repositories/command-classifier.ts +103 -21
  200. package/src/cli/repositories/command-executor.ts +78 -526
  201. package/src/cli/repositories/command-process.ts +108 -0
  202. package/src/cli/repositories/command-scope.ts +99 -41
  203. package/src/cli/repositories/controller-home.ts +7 -8
  204. package/src/cli/repositories/git-command-executor.ts +2 -0
  205. package/src/cli/repositories/locks.ts +53 -16
  206. package/src/cli/repositories/repository-snapshot.ts +124 -0
  207. package/src/cli/repositories/selected-path-actions.ts +17 -9
  208. package/src/cli/repositories/structured-git.ts +118 -6
  209. package/src/cli/repository/inspector.ts +563 -65
  210. package/src/cli/repository/session-cache.ts +58 -17
  211. package/src/cli/v81-entry.ts +1 -4
  212. package/src/effects/fs-transaction.ts +85 -17
  213. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  214. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  215. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  216. package/src/runtime/context/lsp-client.ts +283 -0
  217. package/src/runtime/context/semantic-navigation-contract.ts +61 -0
  218. package/src/runtime/context/semantic-navigation.ts +223 -0
  219. package/src/runtime/context/swift-navigation.ts +565 -0
  220. package/src/runtime/context/typescript-navigation.ts +226 -0
  221. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  222. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +48 -16
  223. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  224. package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
  225. package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
  226. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  227. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  228. package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
  229. package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
  230. package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
  231. package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
  232. package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
  233. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  234. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  235. package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
  236. package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
  237. package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
  238. package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
  239. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  240. package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
  241. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
  242. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
  243. package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
  244. package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
  245. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
  246. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  247. package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
  248. package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
  249. package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
  250. package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
  251. package/src/runtime/control-plane/facade/index.ts +3 -0
  252. package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
  253. package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
  254. package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
  255. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  256. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  257. package/src/runtime/control-plane/facade/types.ts +90 -10
  258. package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
  259. package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
  260. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  261. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  262. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  263. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  264. package/src/runtime/control-plane/global-scheduler/maintenance.ts +152 -0
  265. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  266. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  267. package/src/runtime/control-plane/global-scheduler/scheduler.ts +278 -543
  268. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  269. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  270. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  271. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  272. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  273. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  274. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  275. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  276. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  277. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  278. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +63 -0
  279. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
  280. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
  281. package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
  282. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  283. package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
  284. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  285. package/src/runtime/control-plane/release-retention.ts +62 -2
  286. package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
  287. package/src/runtime/control-plane/routing/route-policy.ts +24 -21
  288. package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
  289. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  290. package/src/runtime/diagnostics/mcp-timing.ts +13 -0
  291. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  292. package/src/runtime/diagnostics/performance.ts +24 -1
  293. package/src/runtime/evidence/event-ledger.ts +1 -1
  294. package/src/runtime/evidence/process-check-execution.ts +18 -0
  295. package/src/runtime/execution/jobs/child-reference.ts +6 -2
  296. package/src/runtime/execution/jobs/store.ts +58 -4
  297. package/src/runtime/execution/jobs/types.ts +1 -1
  298. package/src/runtime/execution/managed-workspace.ts +203 -1
  299. package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
  300. package/src/runtime/execution/process-runtime/check-result.ts +88 -0
  301. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
  302. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  303. package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
  304. package/src/runtime/execution/process-runtime/gc.ts +38 -6
  305. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
  306. package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
  307. package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
  308. package/src/runtime/execution/process-runtime/runtime.ts +53 -3
  309. package/src/runtime/execution/process-runtime/store.ts +1 -0
  310. package/src/runtime/execution/process-runtime/types.ts +4 -12
  311. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  312. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  313. package/src/runtime/execution/work-activity.ts +21 -0
  314. package/src/runtime/execution/workers/executor.ts +18 -61
  315. package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
  316. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
  317. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  318. package/src/runtime/gateway/mcp/router.ts +186 -84
  319. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
  320. package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
  321. package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
  322. package/src/runtime/plugins/browser-adapter.ts +2662 -829
  323. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  324. package/src/runtime/plugins/browser-handoff-host.ts +2 -25
  325. package/src/runtime/plugins/browser-handoff.ts +110 -5
  326. package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
  327. package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
  328. package/src/runtime/plugins/browser-native-session-service.ts +222 -0
  329. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  330. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  331. package/src/runtime/plugins/browser-runtime-contract.ts +154 -0
  332. package/src/runtime/plugins/browser-runtime.ts +193 -0
  333. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  334. package/src/runtime/plugins/browser-session-store.ts +121 -0
  335. package/src/runtime/plugins/browser-session-types.ts +98 -0
  336. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  337. package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
  338. package/src/runtime/plugins/external-adapter.ts +358 -3
  339. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  340. package/src/runtime/plugins/first-party-registry.ts +2 -0
  341. package/src/runtime/plugins/github-adapter.ts +125 -0
  342. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  343. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  344. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  345. package/src/runtime/plugins/ios-adapter.ts +106 -16
  346. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  347. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  348. package/src/runtime/plugins/lightweight-action.ts +153 -0
  349. package/src/runtime/plugins/local-system-adapter.ts +123 -6
  350. package/src/runtime/plugins/macos-capability-broker.ts +47 -9
  351. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  352. package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
  353. package/src/runtime/plugins/resend-adapter.ts +1 -1
  354. package/src/runtime/plugins/store.ts +330 -33
  355. package/src/runtime/plugins/types.ts +38 -3
  356. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  357. package/src/runtime/projections/git-status-sampler.ts +16 -16
  358. package/src/runtime/projections/materialized-view.ts +28 -10
  359. package/src/runtime/recovery/maintenance-executor.ts +426 -25
  360. package/src/runtime/root/mcp-transport.ts +180 -10
  361. package/src/runtime/root/package-connector-service.ts +230 -10
  362. package/src/runtime/root/package-runtime-release.ts +143 -17
  363. package/src/runtime/root/package-runtime-service.ts +461 -22
  364. package/src/runtime/root/release-manifest.ts +144 -18
  365. package/src/runtime/root/release-materialize.ts +125 -32
  366. package/src/runtime/root/release-store.ts +48 -11
  367. package/src/runtime/root/runtime.ts +23 -5
  368. package/src/runtime/root/service.ts +100 -29
  369. package/src/runtime/root/types.ts +12 -0
  370. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  371. package/src/runtime/shared/trusted-executable.ts +62 -0
  372. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  373. package/src/runtime/standalone-recovery/core.ts +1079 -240
  374. package/src/runtime/standalone-recovery/entry.ts +100 -24
  375. package/src/runtime/standalone-recovery/installer.ts +20 -4
  376. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  377. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  378. package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
  379. package/src/runtime/workflow/schedules/engine.ts +364 -202
  380. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  381. package/src/runtime/workflow/schedules/settlement.ts +64 -17
  382. package/src/runtime/workflow/schedules/store.ts +209 -19
  383. package/src/runtime/workflow/schedules/types.ts +2 -4
  384. package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
  385. package/src/testing/test-governance.ts +8 -40
  386. package/assets/reference-configs/heartbeat-triage.md +0 -57
  387. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  388. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  389. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  390. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  391. package/docs/architecture/current/architecture-invariants.md +0 -331
  392. package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
  393. package/docs/architecture/current/codegraph-context-provider.md +0 -238
  394. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  395. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  396. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
  397. package/docs/architecture/current/entity-model.md +0 -612
  398. package/docs/architecture/current/external-plugin-governance.md +0 -396
  399. package/docs/architecture/current/failure-recovery.md +0 -447
  400. package/docs/architecture/current/governance.md +0 -213
  401. package/docs/architecture/current/human-interaction-plane.md +0 -87
  402. package/docs/architecture/current/implementation-status.md +0 -128
  403. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  404. package/docs/architecture/current/legacy-governance.md +0 -58
  405. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  406. package/docs/architecture/current/migration-roadmap.md +0 -105
  407. package/docs/architecture/current/multi-repository-execution.md +0 -371
  408. package/docs/architecture/current/operations-runbook.md +0 -45
  409. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  410. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  411. package/docs/architecture/current/repository-access-modes.md +0 -102
  412. package/docs/architecture/current/route-policy.md +0 -15
  413. package/docs/architecture/current/route-session-concurrency.md +0 -85
  414. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  415. package/docs/architecture/current/runtime-directory-map.md +0 -49
  416. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  417. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  418. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  419. package/docs/architecture/current/system-overview.md +0 -169
  420. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  421. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  422. package/docs/architecture/current/thin-harness-v1.md +0 -321
  423. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  424. package/docs/forge-autonomous-goal-loop.md +0 -9
  425. package/docs/forge-provider-configuration.md +0 -7
  426. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
  427. package/docs/operations/gmail-assistant-routines.md +0 -186
  428. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  429. package/docs/operations/provider-configuration.md +0 -31
  430. package/scripts/harness-trace-grade.sh +0 -150
  431. package/scripts/heartbeat-triage.sh +0 -361
  432. package/scripts/maintenance-triage.sh +0 -167
  433. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  434. package/src/cli/repositories/goal-registry.ts +0 -239
  435. package/src/runtime/assistant/action-proposals.ts +0 -279
  436. package/src/runtime/assistant/intent.ts +0 -395
  437. package/src/runtime/assistant/model-provider.ts +0 -460
  438. package/src/runtime/assistant/openapi.ts +0 -223
  439. package/src/runtime/assistant/policy.ts +0 -89
  440. package/src/runtime/assistant/readiness.ts +0 -258
  441. package/src/runtime/assistant/routine-runtime.ts +0 -477
  442. package/src/runtime/assistant/schedule-binding.ts +0 -171
  443. package/src/runtime/assistant/standing-grants.ts +0 -375
  444. package/src/runtime/assistant/store.ts +0 -243
  445. package/src/runtime/assistant/types.ts +0 -135
  446. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  447. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  448. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  449. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  450. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  451. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  452. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  453. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  454. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  455. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  456. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  457. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  458. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  459. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  460. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  461. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  462. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  463. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  464. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  465. package/src/runtime/workflow/findings/store.ts +0 -204
  466. package/src/runtime/workflow/findings/types.ts +0 -58
  467. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  468. package/src/runtime/workflow/portfolio/store.ts +0 -185
  469. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -1,6 +1,6 @@
1
1
  import { createHash } from 'crypto';
2
2
 
3
- export const ROUTE_POLICY_VERSION = 'route-policy-v3' as const;
3
+ export const ROUTE_POLICY_VERSION = 'route-policy-v5' as const;
4
4
 
5
5
  export type RouteExecutionMode = 'direct_control' | 'goal_workloop' | 'handoff_only';
6
6
  export type RouteWorkMode = 'direct_edit' | 'bounded_work' | 'quick_agent' | 'issue_task';
@@ -50,6 +50,10 @@ export interface RoutePolicyInput {
50
50
  dirty?: boolean;
51
51
  checkoutId?: string;
52
52
  fingerprint?: string;
53
+ /** Canonical typed placement constraint resolved before routing. */
54
+ placement?: 'current' | 'isolated' | 'auto';
55
+ /** Admission fence: Direct Control/current-main mutation is not permitted. */
56
+ directMainProhibited?: boolean;
53
57
  };
54
58
  policy: {
55
59
  risk?: string;
@@ -234,12 +238,12 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
234
238
  const protectedPath = paths.some((path) => PROTECTED_PATH.test(path));
235
239
  const explicitMode = input.intent.explicitMode;
236
240
  const explicitParallelMode = explicitMode === 'scale';
237
- const requiresIsolation = explicitMode === 'direct'
238
- ? false
239
- : input.recovery.isolationRequired === true || explicitParallelMode;
241
+ const placementIsolationRequired = input.workspace.placement === 'isolated'
242
+ || input.workspace.directMainProhibited === true;
243
+ const requiresIsolation = placementIsolationRequired
244
+ || input.recovery.isolationRequired === true
245
+ || explicitParallelMode;
240
246
  const requiresRecovery = input.recovery.required === true
241
- || input.intent.requiresLongRunningChecks === true
242
- || explicitMode === 'debug'
243
247
  || explicitMode === 'release'
244
248
  || explicitMode === 'scale';
245
249
  const coordinationRequired = explicitParallelMode || input.intent.requiresIndependentDeliverables === true
@@ -289,28 +293,29 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
289
293
  }
290
294
 
291
295
  if (input.workspace.dirty && mutation) {
292
- reasons.push({ code: 'dirty_workspace_requires_explicit_adoption', message: 'Mutation against a dirty workspace requires an exact reviewed adoption or a clean isolated checkout.' });
293
- return {
294
- executionMode: 'handoff_only', executorKind: 'handoff_only', selectedProviderId: null,
295
- workMode: 'direct_edit', executionPath: 'durable', requiresWork: true, requiresApproval: false,
296
- requiresIsolation: true, requiresRecovery: true, createHandoff: true, waitForUser: false,
297
- approvalState: 'approval_not_required', alternatives: [], ...decisionBase(input, reasons),
298
- };
296
+ reasons.push({
297
+ code: 'dirty_workspace_preserve_existing_changes',
298
+ message: 'The checkout is already dirty; preserve unrelated changes and treat inspected/actual scope as evidence instead of creating Work solely for adoption.',
299
+ });
299
300
  }
300
301
  if (explicitMode) reasons.push({ code: `explicit_${explicitMode}`, message: `Explicit -${explicitMode} mode overrides automatic work topology while policy gates remain authoritative.` });
301
302
  if (protectedPath) reasons.push({ code: 'protected_path', message: 'The predicted scope includes a protected or release-sensitive path.' });
302
303
  if (requiresRecovery) reasons.push({ code: 'recovery_required', message: 'The operation needs resumable Work and bounded recovery.' });
304
+ if (input.workspace.placement === 'isolated') reasons.push({ code: 'placement_isolated', message: 'Typed Work admission requires an isolated workspace.' });
305
+ if (input.workspace.directMainProhibited === true) reasons.push({ code: 'direct_main_prohibited', message: 'Typed Work admission forbids the Direct Control/current-main mutation lane.' });
303
306
  if (requiresIsolation) reasons.push({ code: 'isolation_required', message: 'The operation requires an isolated checkout or serialized lane.' });
304
- if (input.intent.requiresLongRunningChecks) reasons.push({ code: 'long_checks', message: 'Long-running checks require durable continuation.' });
307
+ if (input.intent.requiresLongRunningChecks) reasons.push({ code: 'long_checks', message: 'Long-running checks may use a lightweight handle; duration alone does not require durable Work.' });
305
308
  if (input.intent.requiresInvestigation) reasons.push({ code: 'investigation', message: 'Investigation is required before or during implementation.' });
306
309
  if (input.intent.needsDependencies) reasons.push({ code: 'dependencies', message: 'Dependency ordering requires durable Work.' });
307
310
  if (coordinationRequired) reasons.push({ code: 'independent_deliverables', message: 'Multiple independent deliverables require durable PlanContract/Work coordination.' });
308
311
 
309
312
  const explicitBoundedMode = explicitMode === 'plan'
310
- || explicitMode === 'debug'
311
- || explicitMode === 'review'
312
313
  || explicitMode === 'release';
313
- const complex = explicitMode === 'direct'
314
+ const directModeCanRemainFast = explicitMode === 'direct'
315
+ && !requiresIsolation
316
+ && !requiresRecovery
317
+ && !coordinationRequired;
318
+ const complex = directModeCanRemainFast
314
319
  ? false
315
320
  : coordinationRequired
316
321
  || explicitBoundedMode
@@ -320,16 +325,14 @@ export function decideRoute(input: RoutePolicyInput): RouteDecision {
320
325
  || input.capabilities.requiresWorker === true
321
326
  || input.capabilities.requiresExternalEffect === true
322
327
  || input.intent.needsDependencies === true
323
- || protectedPath
324
328
  || destructive
325
329
  || remoteWrite
326
- || secretAccess
327
- || (mutation && (expectedFiles > 4 || expectedChangedLines > 200));
330
+ || secretAccess;
328
331
  const executionMode: RouteExecutionMode = complex ? 'goal_workloop' : 'direct_control';
329
332
  // Work topology is independent from executor/provider choice. Independent or
330
333
  // parallel deliverables stay in the durable Goal Workloop and are decomposed by
331
334
  // PlanContract/Work rather than introducing another project-level lifecycle.
332
- const workMode: RouteWorkMode = explicitMode === 'direct'
335
+ const workMode: RouteWorkMode = directModeCanRemainFast
333
336
  ? 'direct_edit'
334
337
  : coordinationRequired
335
338
  ? 'bounded_work'
@@ -0,0 +1,70 @@
1
+ export type WorkspacePlacementMode = 'current' | 'isolated' | 'auto';
2
+
3
+ export interface WorkspaceAdmissionConstraintInput {
4
+ workspaceMode?: WorkspacePlacementMode;
5
+ requireWorktree?: boolean;
6
+ /**
7
+ * Forbid repository mutation through the current/direct-main lane. This is
8
+ * an admission constraint, not a routing hint: callers must never silently
9
+ * downgrade it to Direct Control.
10
+ */
11
+ directMainProhibited?: boolean;
12
+ }
13
+
14
+ export interface WorkspaceAdmissionConstraint {
15
+ workspaceMode: WorkspacePlacementMode;
16
+ requireWorktree: boolean;
17
+ directMainProhibited: boolean;
18
+ requiresIsolation: boolean;
19
+ }
20
+
21
+ export type WorkspaceAdmissionResolution =
22
+ | { ok: true; constraint: WorkspaceAdmissionConstraint }
23
+ | { ok: false; code: 'WORKSPACE_PLACEMENT_CONSTRAINT_CONFLICT'; message: string };
24
+
25
+ /**
26
+ * Canonicalize Work placement before Route Policy runs. Placement is a policy
27
+ * fence: explicit isolation / direct-main prohibition has precedence over an
28
+ * operator request for the fast Direct Control topology.
29
+ */
30
+ export function resolveWorkspaceAdmissionConstraint(
31
+ input: WorkspaceAdmissionConstraintInput = {},
32
+ ): WorkspaceAdmissionResolution {
33
+ const workspaceMode = input.workspaceMode ?? 'auto';
34
+ const directMainProhibited = input.directMainProhibited === true;
35
+
36
+ if (workspaceMode === 'current' && input.requireWorktree === true) {
37
+ return {
38
+ ok: false,
39
+ code: 'WORKSPACE_PLACEMENT_CONSTRAINT_CONFLICT',
40
+ message: 'workspaceMode=current conflicts with requireWorktree=true.',
41
+ };
42
+ }
43
+ if (workspaceMode === 'isolated' && input.requireWorktree === false) {
44
+ return {
45
+ ok: false,
46
+ code: 'WORKSPACE_PLACEMENT_CONSTRAINT_CONFLICT',
47
+ message: 'workspaceMode=isolated conflicts with requireWorktree=false.',
48
+ };
49
+ }
50
+ if (workspaceMode === 'current' && directMainProhibited) {
51
+ return {
52
+ ok: false,
53
+ code: 'WORKSPACE_PLACEMENT_CONSTRAINT_CONFLICT',
54
+ message: 'workspaceMode=current conflicts with directMainProhibited=true because the current lane cannot prove a non-main placement at admission time.',
55
+ };
56
+ }
57
+
58
+ const requiresIsolation = workspaceMode === 'isolated'
59
+ || input.requireWorktree === true
60
+ || directMainProhibited;
61
+ return {
62
+ ok: true,
63
+ constraint: {
64
+ workspaceMode: requiresIsolation ? 'isolated' : workspaceMode,
65
+ requireWorktree: requiresIsolation,
66
+ directMainProhibited,
67
+ requiresIsolation,
68
+ },
69
+ };
70
+ }
@@ -1,6 +1,5 @@
1
1
  import { resolveControllerHome } from '../../cli/repositories/controller-home';
2
2
  import { readSchedulerHealthSnapshot } from './global-scheduler/scheduler';
3
- import type { ControllerStartupRecoveryResult } from './startup-recovery';
4
3
  import type { RuntimeSourceIdentity } from './runtime-generation';
5
4
  import { readRuntimeOwner } from '../root/ownership';
6
5
  import { observeRuntimeStatus } from '../root/status';
@@ -26,7 +25,6 @@ export interface ForgeRuntimeStatus {
26
25
  gatewaySeparated?: boolean;
27
26
  workerIsolation?: boolean;
28
27
  degraded?: boolean;
29
- recovery?: ControllerStartupRecoveryResult;
30
28
  generation?: string;
31
29
  source?: RuntimeSourceIdentity;
32
30
  restartRequired?: boolean;
@@ -21,6 +21,19 @@ export interface McpTimingTrace {
21
21
  commandExecutionMs?: number;
22
22
  resultSerializationMs?: number;
23
23
  resultPersistenceMs?: number;
24
+ /** Public Gateway only: resolve current Canonical Runtime identity/token/endpoint. */
25
+ gatewayProxyResolveMs?: number;
26
+ /** Public Gateway only: establish or await a Canonical Runtime MCP client connection. */
27
+ gatewayProxyConnectMs?: number;
28
+ /** Public Gateway only: MCP call duration after a client is acquired, including Canonical Runtime work. */
29
+ gatewayProxyCallMs?: number;
30
+ /** Public Gateway only: time from forwarding the tool call until the Canonical Runtime handler starts. */
31
+ gatewayProxyCanonicalDispatchLagMs?: number;
32
+ /** Canonical Runtime server duration projected back through the proxy response. */
33
+ gatewayProxyCanonicalDurationMs?: number;
34
+ /** Public Gateway only: response/transport tail after canonical handler completion. */
35
+ gatewayProxyReturnMs?: number;
36
+ gatewayProxyConnectionState?: 'reused' | 'cold_connect' | 'coalesced_connect' | 'identity_reconnect';
24
37
  totalToolDurationMs: number;
25
38
  sessionId?: string;
26
39
  repoId?: string;
@@ -0,0 +1,129 @@
1
+ export type McpTransportTimingScope = 'tool_call' | 'connect_and_tool_call';
2
+
3
+ export interface McpTransportLatencySample {
4
+ label: string;
5
+ tool: string;
6
+ timingScope?: McpTransportTimingScope;
7
+ clientTotalMs: number;
8
+ serverDurationMs: number;
9
+ traceId?: string;
10
+ requestId?: string;
11
+ observedAt?: string;
12
+ }
13
+
14
+ export interface McpTransportLatencyStats {
15
+ p50: number;
16
+ p95: number;
17
+ max: number;
18
+ }
19
+
20
+ export interface McpTransportLatencyGroup {
21
+ label: string;
22
+ tool: string;
23
+ timingScope: McpTransportTimingScope;
24
+ sampleCount: number;
25
+ clientTotalMs: McpTransportLatencyStats;
26
+ serverDurationMs: McpTransportLatencyStats;
27
+ externalResidualMs: McpTransportLatencyStats;
28
+ externalSharePct: McpTransportLatencyStats;
29
+ serverExceedsClientCount: number;
30
+ }
31
+
32
+ export interface McpTransportLatencyReport {
33
+ schemaVersion: 1;
34
+ sampleCount: number;
35
+ groups: McpTransportLatencyGroup[];
36
+ }
37
+
38
+ function round(value: number): number {
39
+ return Math.round(value * 100) / 100;
40
+ }
41
+
42
+ function percentile(values: number[], fraction: number): number {
43
+ if (values.length === 0) return 0;
44
+ const sorted = [...values].sort((left, right) => left - right);
45
+ const index = Math.max(0, Math.min(sorted.length - 1, Math.ceil(sorted.length * fraction) - 1));
46
+ return round(sorted[index]!);
47
+ }
48
+
49
+ function stats(values: number[]): McpTransportLatencyStats {
50
+ return {
51
+ p50: percentile(values, 0.5),
52
+ p95: percentile(values, 0.95),
53
+ max: round(Math.max(...values, 0)),
54
+ };
55
+ }
56
+
57
+ function validDuration(value: unknown): value is number {
58
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0;
59
+ }
60
+
61
+ export function normalizeMcpTransportLatencySample(value: unknown): McpTransportLatencySample {
62
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
63
+ throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: sample must be an object');
64
+ }
65
+ const record = value as Record<string, unknown>;
66
+ const label = typeof record.label === 'string' ? record.label.trim() : '';
67
+ const tool = typeof record.tool === 'string' ? record.tool.trim() : '';
68
+ const timingScope = record.timingScope === undefined || record.timingScope === 'tool_call'
69
+ ? 'tool_call'
70
+ : record.timingScope === 'connect_and_tool_call'
71
+ ? 'connect_and_tool_call'
72
+ : undefined;
73
+ if (!label) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: label is required');
74
+ if (!tool) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: tool is required');
75
+ if (!timingScope) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: timingScope must be tool_call or connect_and_tool_call');
76
+ if (!validDuration(record.clientTotalMs)) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: clientTotalMs must be a non-negative finite number');
77
+ if (!validDuration(record.serverDurationMs)) throw new Error('MCP_TRANSPORT_SAMPLE_INVALID: serverDurationMs must be a non-negative finite number');
78
+ return {
79
+ label,
80
+ tool,
81
+ timingScope,
82
+ clientTotalMs: record.clientTotalMs,
83
+ serverDurationMs: record.serverDurationMs,
84
+ ...(typeof record.traceId === 'string' && record.traceId.trim() ? { traceId: record.traceId.trim() } : {}),
85
+ ...(typeof record.requestId === 'string' && record.requestId.trim() ? { requestId: record.requestId.trim() } : {}),
86
+ ...(typeof record.observedAt === 'string' && record.observedAt.trim() ? { observedAt: record.observedAt.trim() } : {}),
87
+ };
88
+ }
89
+
90
+ export function extractForgeServerDuration(result: unknown): number | undefined {
91
+ if (!result || typeof result !== 'object' || Array.isArray(result)) return undefined;
92
+ const structured = (result as Record<string, unknown>).structuredContent;
93
+ if (!structured || typeof structured !== 'object' || Array.isArray(structured)) return undefined;
94
+ const responseMeta = (structured as Record<string, unknown>).responseMeta;
95
+ if (!responseMeta || typeof responseMeta !== 'object' || Array.isArray(responseMeta)) return undefined;
96
+ const duration = (responseMeta as Record<string, unknown>).serverDurationMs;
97
+ return validDuration(duration) ? duration : undefined;
98
+ }
99
+
100
+ export function aggregateMcpTransportLatencySamples(values: unknown[]): McpTransportLatencyReport {
101
+ const samples = values.map(normalizeMcpTransportLatencySample);
102
+ const grouped = new Map<string, McpTransportLatencySample[]>();
103
+ for (const sample of samples) {
104
+ const key = `${sample.label}\u0000${sample.tool}\u0000${sample.timingScope ?? 'tool_call'}`;
105
+ const entries = grouped.get(key) ?? [];
106
+ entries.push(sample);
107
+ grouped.set(key, entries);
108
+ }
109
+ const groups = [...grouped.values()].map((entries): McpTransportLatencyGroup => {
110
+ const client = entries.map((sample) => sample.clientTotalMs);
111
+ const server = entries.map((sample) => sample.serverDurationMs);
112
+ const residual = entries.map((sample) => Math.max(0, sample.clientTotalMs - sample.serverDurationMs));
113
+ const share = entries.map((sample, index) => client[index]! > 0 ? residual[index]! / client[index]! * 100 : 0);
114
+ return {
115
+ label: entries[0]!.label,
116
+ tool: entries[0]!.tool,
117
+ timingScope: entries[0]!.timingScope ?? 'tool_call',
118
+ sampleCount: entries.length,
119
+ clientTotalMs: stats(client),
120
+ serverDurationMs: stats(server),
121
+ externalResidualMs: stats(residual),
122
+ externalSharePct: stats(share),
123
+ serverExceedsClientCount: entries.filter((sample) => sample.serverDurationMs > sample.clientTotalMs).length,
124
+ };
125
+ }).sort((left, right) => left.label.localeCompare(right.label)
126
+ || left.tool.localeCompare(right.tool)
127
+ || left.timingScope.localeCompare(right.timingScope));
128
+ return { schemaVersion: 1, sampleCount: samples.length, groups };
129
+ }
@@ -1,5 +1,5 @@
1
1
  import { execFileSync } from 'child_process';
2
- import { existsSync, lstatSync, readdirSync, rmSync } from 'fs';
2
+ import { existsSync, lstatSync, readdirSync, rmSync, statfsSync } from 'fs';
3
3
  import { tmpdir } from 'os';
4
4
  import { basename, dirname, join, resolve } from 'path';
5
5
 
@@ -46,6 +46,7 @@ export interface RuntimePerformanceDiagnostics {
46
46
  };
47
47
  processes: RuntimeProcessSample[];
48
48
  temp: { scannedRoots: string[]; totalEntries: number; cleanupCandidates: number; entries: RuntimeTempEntry[] };
49
+ storage: { availableBytes?: number; availableGiB?: number; pressure: 'normal' | 'warning' | 'critical' | 'unknown'; managedCacheRoots: string[] };
49
50
  cleanupPreview?: { safeToTerminate: RuntimeProcessSample[]; safeToRemoveTempEntries: RuntimeTempEntry[]; requiresConfirmation: true };
50
51
  truncated: {
51
52
  summary: boolean;
@@ -322,7 +323,27 @@ export function collectRuntimePerformanceDiagnostics(input: DiagnosticsInput): R
322
323
  const temp = input.includeTempDirs === false
323
324
  ? { roots: [] as string[], entries: [] as RuntimeTempEntry[] }
324
325
  : scanRuntimeTempEntries(processes);
326
+ let availableBytes: number | undefined;
327
+ try {
328
+ const fs = statfsSync(input.repoRoot);
329
+ availableBytes = Number(fs.bavail) * Number(fs.bsize);
330
+ } catch {}
331
+ const availableGiB = availableBytes === undefined ? undefined : Math.round((availableBytes / (1024 ** 3)) * 10) / 10;
332
+ const storagePressure: RuntimePerformanceDiagnostics['storage']['pressure'] = availableGiB === undefined
333
+ ? 'unknown'
334
+ : availableGiB < 30
335
+ ? 'critical'
336
+ : availableGiB < 50
337
+ ? 'warning'
338
+ : 'normal';
339
+ const managedCacheRoots = [
340
+ join(input.repoRoot, '.forge', 'ios', 'DerivedData'),
341
+ join(input.repoRoot, '.ai', 'harness'),
342
+ join(input.repoRoot, '.repo-harness'),
343
+ ].filter((path) => existsSync(path));
325
344
  const findings: RuntimePerformanceDiagnostics['findings'] = [];
345
+ if (storagePressure === 'critical') findings.push({ severity: 'critical', code: 'LOW_DISK_SPACE', message: `Only ${availableGiB} GiB of repository volume space is available.` });
346
+ else if (storagePressure === 'warning') findings.push({ severity: 'warning', code: 'LOW_DISK_SPACE', message: `Repository volume free space is ${availableGiB} GiB.` });
326
347
  if (orphanWorkers.length > 0) findings.push({ severity: orphanWorkers.length >= 3 ? 'critical' : 'warning', code: 'ORPHAN_WORKERS', message: 'Detected ' + orphanWorkers.length + ' orphan worker process(es).' });
327
348
  const totalCpu = Math.round(repoProcesses.reduce((sum, process) => sum + process.cpu, 0) * 10) / 10;
328
349
  if (totalCpu >= 100 || highCpu.length >= 3) findings.push({ severity: 'warning', code: 'HIGH_FORGE_CPU', message: 'Forge-related CPU is ' + totalCpu + '%.' });
@@ -341,6 +362,7 @@ export function collectRuntimePerformanceDiagnostics(input: DiagnosticsInput): R
341
362
  ...(orphanWorkers.length ? ['Terminate orphan workers only after reviewing cleanupPreview.safeToTerminate.'] : []),
342
363
  ...(tempCleanupCandidates.length ? ['Remove stale temp entries through runtime_maintenance_apply after reviewing cleanupPreview.safeToRemoveTempEntries.'] : []),
343
364
  ...(highCpu.length ? ['Inspect highCpuProcesses before restarting the controller stack.'] : []),
365
+ ...(storagePressure === 'critical' ? ['Allow Forge generated-cache retention to reclaim stale DerivedData before starting another heavy iOS verification.'] : []),
344
366
  ];
345
367
  return {
346
368
  schemaVersion: 1,
@@ -358,6 +380,7 @@ export function collectRuntimePerformanceDiagnostics(input: DiagnosticsInput): R
358
380
  cleanupCandidates: tempCleanupCandidates.length,
359
381
  entries: temp.entries.slice(0, MAX_DIAGNOSTIC_TEMP_ENTRIES),
360
382
  },
383
+ storage: { availableBytes, availableGiB, pressure: storagePressure, managedCacheRoots },
361
384
  cleanupPreview: input.cleanupPreview === true
362
385
  ? {
363
386
  safeToTerminate: rawCleanupProcesses,
@@ -18,7 +18,7 @@ export interface RuntimeEntityEvent {
18
18
  eventId: string;
19
19
  eventType: string;
20
20
  repoId: string;
21
- entityType: 'job' | 'plugin' | 'schedule' | 'occurrence' | 'portfolio' | 'candidate-finding' | 'release' | 'lease' | 'schedule-decision' | 'assistant-action-proposal' | 'assistant-standing-grant';
21
+ entityType: 'job' | 'plugin' | 'schedule' | 'occurrence' | 'portfolio' | 'release' | 'lease' | 'schedule-decision';
22
22
  entityId: string;
23
23
  correlationId?: string;
24
24
  causationId?: string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Content-bound Check identity shared by Process Runtime and Work validation.
3
+ *
4
+ * This is durable evidence metadata, not Process lifecycle state. Keeping the
5
+ * contract outside Process Runtime prevents WorkHandle persistence from
6
+ * depending on the Process implementation layer.
7
+ */
8
+ export interface ProcessCheckExecutionIdentity {
9
+ schemaVersion: 1;
10
+ checkId: string;
11
+ cacheKey: string;
12
+ revision: string;
13
+ definitionDigest: string;
14
+ environmentFingerprint: string;
15
+ timeoutMs: number;
16
+ reuseScope: 'repository' | 'checkout';
17
+ scopeKey: string;
18
+ }
@@ -1,5 +1,9 @@
1
1
  import type { ExecutionJob } from './types';
2
- import type { OperationReceipt } from './receipt-store';
2
+
3
+ export interface ChildReferenceReceiptLike {
4
+ childReference?: unknown;
5
+ result?: Record<string, unknown>;
6
+ }
3
7
 
4
8
  /** Durable pointer from a short-lived parent Execution Job to its child Agent Run. */
5
9
  export interface ExecutionChildReference {
@@ -72,7 +76,7 @@ export function childReferenceFromUnknown(value: unknown): ExecutionChildReferen
72
76
  return pickChildReference(value as Record<string, unknown>);
73
77
  }
74
78
 
75
- export function childReferenceFromReceipt(receipt: OperationReceipt | undefined): ExecutionChildReference | undefined {
79
+ export function childReferenceFromReceipt(receipt: ChildReferenceReceiptLike | undefined): ExecutionChildReference | undefined {
76
80
  if (!receipt) return undefined;
77
81
  return childReferenceFromUnknown(receipt.childReference)
78
82
  ?? childReferenceFromUnknown(receipt.result);
@@ -2,7 +2,7 @@ import { createHash, randomUUID } from 'crypto';
2
2
  import { existsSync, readdirSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import { ensureControllerHome, ensureRepositoryControllerLayout, repositoryControllerRoot } from '../../../cli/repositories/controller-home';
5
- import { withControllerLock } from '../../../cli/repositories/locks';
5
+ import { releaseControllerLock, tryAcquireControllerLock, withControllerLock } from '../../../cli/repositories/locks';
6
6
  import { appendJobEvent } from '../../evidence/event-ledger';
7
7
  import { writeExecutionArtifact } from '../../evidence/artifact-store';
8
8
  import { markRepositoryProjectionDirty } from '../../projections/invalidation';
@@ -206,7 +206,9 @@ function writeActiveIndex(controllerHome: string, index: ActiveJobIndex): void {
206
206
  writeJsonAtomic(activeIndexPath(controllerHome), {
207
207
  schemaVersion: 1,
208
208
  updatedAt: now(),
209
- jobs: [...deduped.values()].sort((a, b) => a.queuedAt.localeCompare(b.queuedAt)).slice(-5000),
209
+ // Active work is correctness state, not a presentation window. Dropping an
210
+ // entry here makes Scheduler/recovery reads forget a durable non-terminal Job.
211
+ jobs: [...deduped.values()].sort((a, b) => a.queuedAt.localeCompare(b.queuedAt)),
210
212
  } satisfies ActiveJobIndex);
211
213
  }
212
214
 
@@ -258,7 +260,9 @@ export function rebuildExecutionJobIndexes(controllerHome: string, repoIds: stri
258
260
  for (const repoId of targetRepos) {
259
261
  const records = join(executionJobRoot(controllerHome, repoId), 'records');
260
262
  let names: string[] = [];
261
- try { names = readdirSync(records).filter((name) => name.endsWith('.json')).slice(0, 5000); } catch { continue; }
263
+ // Startup repair must rebuild every active and request authority. Only the
264
+ // recent-history projection below is intentionally bounded.
265
+ try { names = readdirSync(records).filter((name) => name.endsWith('.json')); } catch { continue; }
262
266
  for (const name of names) {
263
267
  try {
264
268
  const job = readJsonFile<ExecutionJob>(join(records, name));
@@ -648,11 +652,61 @@ export function listActiveExecutionJobs(controllerHome: string, repoId?: string)
648
652
  try {
649
653
  const job = getExecutionJob(controllerHome, entry.repoId, entry.jobId);
650
654
  if (ACTIVE_JOB_STATUSES.has(job.status)) output.push(job);
651
- } catch { /* stale index repaired below */ }
655
+ } catch { /* maintenance reconciliation owns stale-index repair */ }
652
656
  }
653
657
  return output;
654
658
  }
655
659
 
660
+ /**
661
+ * Maintenance-only active-index convergence. The active index itself is the
662
+ * bounded candidate set; this never scans historical Job directories. Ordinary
663
+ * read APIs remain side-effect free, while the Scheduler can remove terminal or
664
+ * missing entries once and make subsequent idle reads genuinely cheap.
665
+ */
666
+ export function reconcileActiveExecutionJobIndex(
667
+ controllerHome: string,
668
+ repoId?: string,
669
+ ): ExecutionJob[] {
670
+ const key = { scope: 'global' as const, resource: 'execution-index' };
671
+ const owner = `execution-index-active-reconcile:${repoId ?? 'all'}`;
672
+ const acquired = tryAcquireControllerLock(controllerHome, key, owner);
673
+ if (!acquired.acquired) return listActiveExecutionJobs(controllerHome, repoId);
674
+ try {
675
+ const index = readActiveIndex(controllerHome);
676
+ const jobs: ExecutionJob[] = [];
677
+ const retained: ActiveJobIndex['jobs'] = [];
678
+ let removed = 0;
679
+ for (const entry of index.jobs) {
680
+ if (repoId && entry.repoId !== repoId) {
681
+ retained.push(entry);
682
+ continue;
683
+ }
684
+ try {
685
+ const job = getExecutionJob(controllerHome, entry.repoId, entry.jobId);
686
+ if (!ACTIVE_JOB_STATUSES.has(job.status)) {
687
+ removed += 1;
688
+ continue;
689
+ }
690
+ jobs.push(job);
691
+ retained.push({
692
+ jobId: job.jobId,
693
+ repoId: job.repoId,
694
+ status: job.status,
695
+ priority: job.priority,
696
+ queuedAt: job.queuedAt,
697
+ updatedAt: job.updatedAt,
698
+ });
699
+ } catch {
700
+ removed += 1;
701
+ }
702
+ }
703
+ if (removed > 0) writeActiveIndex(controllerHome, { ...index, jobs: retained });
704
+ return jobs;
705
+ } finally {
706
+ releaseControllerLock(controllerHome, key, acquired.lock.lockId);
707
+ }
708
+ }
709
+
656
710
  function executionJobApprovalRequestId(job: ExecutionJob): string | undefined {
657
711
  if (typeof job.result?.approvalRequestId === 'string') return job.result.approvalRequestId;
658
712
  const authorization = job.result?.authorization;
@@ -45,7 +45,7 @@ export interface ResourceClaimSpec {
45
45
  }
46
46
 
47
47
  export interface ExecutionJobOrigin {
48
- surface: 'mcp' | 'local-ui' | 'mobile-intent' | 'chatgpt-action' | 'assistant-routine' | 'standing-grant' | 'cli' | 'schedule' | 'reconciliation' | 'system';
48
+ surface: 'mcp' | 'local-ui' | 'mobile-intent' | 'chatgpt-action' | 'cli' | 'schedule' | 'reconciliation' | 'system';
49
49
  actor?: string;
50
50
  correlationId?: string;
51
51
  causationId?: string;