@moretea-labs/forge 1.8.1 → 1.8.2

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 (328) hide show
  1. package/AGENTS.md +5 -2
  2. package/CHANGELOG.md +20 -0
  3. package/README.en.md +24 -3
  4. package/README.md +10 -6
  5. package/README.zh-CN.md +5 -3
  6. package/THIRD_PARTY_NOTICES.md +1 -2
  7. package/adapters/chatgpt/browser-delivery-runtime.ts +5 -3
  8. package/adapters/chatgpt/provider-delivery.ts +1 -1
  9. package/adapters/chatgpt/work-conversation-binding-store.ts +20 -1
  10. package/adapters/computer/chatgpt-extension-target.ts +295 -50
  11. package/adapters/computer/chrome-extension/background.js +227 -71
  12. package/adapters/computer/chrome-extension/content.js +181 -157
  13. package/adapters/computer/chrome-extension/manifest.json +3 -1
  14. package/adapters/computer/desktop-operator-provider.ts +18 -6
  15. package/adapters/computer/interaction-target-authority.ts +39 -9
  16. package/adapters/mcp/access-mode.ts +18 -39
  17. package/adapters/mcp/auth.ts +2 -6
  18. package/adapters/mcp/instructions.ts +2 -2
  19. package/adapters/mcp/multi-repository.ts +7 -28
  20. package/adapters/mcp/runtime-gateway/context-adapter.ts +79 -40
  21. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +7 -15
  22. package/adapters/mcp/runtime-gateway/execution-tools.ts +7 -13
  23. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +16 -3
  24. package/adapters/mcp/runtime-gateway/process-tools.ts +3 -21
  25. package/adapters/mcp/runtime-gateway/router.ts +3 -5
  26. package/adapters/mcp/runtime-gateway/routing-policy.ts +17 -10
  27. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1 -1
  28. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +14 -9
  29. package/adapters/mcp/runtime-gateway/runtime-tools.ts +1 -5
  30. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +36 -1
  31. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +58 -4
  32. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +7 -3
  33. package/adapters/mcp/runtime-gateway/work-adapter.ts +16 -16
  34. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +0 -17
  35. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +69 -12
  36. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +26 -2
  37. package/adapters/mcp/server.ts +24 -3
  38. package/adapters/mcp/setup.ts +4 -10
  39. package/adapters/mcp/tool-mapping/access-tools.ts +0 -6
  40. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +672 -2935
  41. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +1 -1
  42. package/adapters/mcp/tool-mapping/repository-tools.ts +52 -86
  43. package/adapters/mcp/toolset-names.ts +11 -42
  44. package/adapters/mcp/toolset.ts +16 -90
  45. package/{src/cli → adapters}/mcp/transports/AGENTS.md +5 -5
  46. package/{src/cli → adapters}/mcp/transports/CLAUDE.md +5 -5
  47. package/adapters/mcp/transports/http-observation.ts +18 -6
  48. package/adapters/mcp/transports/http-post-lifecycle.ts +19 -0
  49. package/adapters/mcp/transports/http.ts +54 -14
  50. package/adapters/mcp/types.ts +0 -6
  51. package/assets/hooks/lib/session-state.sh +0 -38
  52. package/assets/hooks/post-bash.sh +1 -1
  53. package/assets/hooks/post-tool-observer.sh +0 -5
  54. package/assets/hooks/prompt-guard.sh +0 -55
  55. package/assets/partials/04-project-structure.partial.md +1 -1
  56. package/assets/partials/07-footer.partial.md +1 -1
  57. package/assets/partials-agents/02-operating-mode.partial.md +1 -1
  58. package/assets/partials-agents/08-deep-docs.partial.md +1 -1
  59. package/assets/reference-configs/agentic-development-flow.md +1 -1
  60. package/assets/reference-configs/external-tooling.md +0 -76
  61. package/assets/reference-configs/release-deploy.md +1 -1
  62. package/assets/templates/helpers/architecture-queue.sh +1 -1
  63. package/assets/templates/helpers/check-agent-tooling.sh +1 -327
  64. package/assets/templates/helpers/check-task-workflow.sh +1 -1
  65. package/assets/templates/helpers/ensure-task-workflow.sh +0 -14
  66. package/assets/templates/helpers/migrate-project-template.sh +2 -2
  67. package/assets/workflow-contract.v1.json +0 -2
  68. package/docs/README.md +5 -2
  69. package/docs/architecture/CURRENT.md +114 -30
  70. package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +42 -0
  71. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +15 -2
  72. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +4 -2
  73. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +109 -4
  74. package/docs/architecture/decisions/20261009-exact-code-context-discovery.md +19 -0
  75. package/docs/architecture/decisions/20261009-generated-xcode-cache-retention.md +37 -0
  76. package/docs/architecture/decisions/20261011-autonomous-continuation-convergence.md +597 -0
  77. package/docs/architecture/decisions/20261017-edit-session-finalization-reconciliation.md +17 -0
  78. package/docs/architecture/decisions/20261019-retire-host-skills.md +16 -0
  79. package/docs/architecture/diagrams/agentic-dev-plugin-architecture.html +1 -1
  80. package/docs/architecture/domains/public-surface.md +3 -5
  81. package/docs/architecture/domains/verification.md +5 -5
  82. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +2 -2
  83. package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +4 -4
  84. package/docs/architecture/reviews/20261015-code-search-runtime-acceptance.md +75 -0
  85. package/docs/forge-plugin-management.md +14 -2
  86. package/docs/operations/controller-browser-plugin.md +23 -0
  87. package/docs/operations/features.md +6 -7
  88. package/docs/operations/features.zh-CN.md +1 -1
  89. package/docs/operations/github-repository.md +4 -4
  90. package/docs/operations/github-semantic-release-projection.md +20 -0
  91. package/docs/operations/homebrew.md +2 -2
  92. package/docs/operations/mcp-tool-exposure.md +13 -54
  93. package/docs/operations/runtime-performance-diagnostics.md +8 -0
  94. package/docs/operations/standalone-disaster-recovery.md +1 -1
  95. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  96. package/docs/tutorials/03-first-repository-task.md +2 -0
  97. package/docs/wiki/Computer-and-Plugins.md +78 -0
  98. package/docs/wiki/Computer-and-Plugins.zh-CN.md +88 -0
  99. package/docs/wiki/Home.md +16 -2
  100. package/docs/wiki/Implementation.md +24 -12
  101. package/docs/wiki/Installation.md +28 -32
  102. package/docs/wiki/Integrations.md +4 -0
  103. package/docs/wiki/Quick-Start.md +35 -22
  104. package/docs/wiki/Releases-and-Upgrades.md +15 -25
  105. package/docs/wiki/_Sidebar.md +5 -1
  106. package/package.json +1 -12
  107. package/packages/kernel/controller/infrastructure/controller-session-store.ts +63 -38
  108. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +10 -0
  109. package/packages/kernel/scheduler/application/eligibility.ts +4 -1
  110. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +13 -10
  111. package/packages/kernel/work/application/work-service.ts +1 -0
  112. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  113. package/packages/kernel/work/domain/state-machine.ts +9 -2
  114. package/packages/kernel/work/infrastructure/work-contract-store.ts +28 -1
  115. package/packages/plugin-runtime/browser/provider-registry.ts +12 -36
  116. package/packages/plugin-runtime/computer/conversation-target.ts +17 -7
  117. package/scripts/assemble-template.ts +11 -72
  118. package/scripts/check-mcp-compatibility.ts +55 -74
  119. package/scripts/check-package-identity.mjs +0 -5
  120. package/scripts/check-runtime-architecture.mjs +305 -28
  121. package/scripts/init-project.sh +0 -46
  122. package/scripts/install-ios-hid-toolchain.sh +60 -0
  123. package/scripts/install-standalone-recovery.ts +1 -1
  124. package/scripts/lib/project-init-lib.sh +3 -3
  125. package/scripts/migrate-windows-wsl-controller-home.ts +2 -0
  126. package/scripts/open-source-audit-allowlist.txt +0 -1
  127. package/scripts/run-governed-gate.ts +2 -0
  128. package/scripts/smoke-ios-physical-device.ts +38 -10
  129. package/scripts/smoke-mcp-http-runtime.ts +7 -8
  130. package/scripts/smoke-mcp-tool-surface.ts +27 -41
  131. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +6 -3
  132. package/scripts/sync-generated-authority.mjs +0 -1
  133. package/src/cli/agent-jobs/executor-health.ts +1 -1
  134. package/src/cli/agent-jobs/integration.ts +2 -2
  135. package/src/cli/chatgpt-browser/file-policy.ts +2 -2
  136. package/src/cli/commands/doctor.ts +1 -143
  137. package/src/cli/commands/global-runtime.ts +3 -196
  138. package/src/cli/commands/init-hook.ts +6 -23
  139. package/src/cli/commands/init.ts +3 -252
  140. package/src/cli/commands/mcp.ts +0 -5
  141. package/src/cli/commands/prompt-guard-decision.ts +0 -2
  142. package/src/cli/commands/recovery.ts +2 -14
  143. package/src/cli/commands/repository.ts +17 -1
  144. package/src/cli/commands/setup-execution.ts +41 -0
  145. package/src/cli/controller/completion-orchestrator.ts +1 -1
  146. package/src/cli/controller/composite-operations.ts +1 -1
  147. package/src/cli/controller/context/instruction-context.ts +1 -1
  148. package/src/cli/controller/context/known-paths.ts +2 -2
  149. package/src/cli/controller/context/query-planning.ts +11 -4
  150. package/src/cli/controller/context/rule-resolution.ts +2 -2
  151. package/src/cli/controller/context/source-materializer.ts +2 -2
  152. package/src/cli/controller/context/structural-provider.ts +84 -0
  153. package/src/cli/controller/context/structural.ts +6 -6
  154. package/src/cli/controller/context/types.ts +8 -9
  155. package/src/cli/controller/context-pack.ts +97 -76
  156. package/src/cli/controller/operational-plan.ts +1 -1
  157. package/src/cli/controller/systemd-user.ts +4 -10
  158. package/src/cli/editing/edit-session.ts +17 -5
  159. package/src/cli/github/github.ts +4 -4
  160. package/src/cli/github/semantic-projection.ts +174 -0
  161. package/src/cli/hook/prompt-intents.ts +0 -9
  162. package/src/cli/index.ts +1 -43
  163. package/src/cli/local-bridge/connector-freshness.ts +1 -12
  164. package/src/cli/local-bridge/console-automations.ts +1 -1
  165. package/src/cli/local-bridge/console-view-models.ts +1 -1
  166. package/src/cli/local-bridge/facade-api.ts +0 -2
  167. package/src/cli/repositories/command-classifier.ts +0 -9
  168. package/src/cli/repositories/command-scope.ts +2 -2
  169. package/src/cli/repositories/locks.ts +20 -0
  170. package/src/cli/repositories/registry.ts +2 -1
  171. package/src/cli/repositories/safe-patch.ts +2 -12
  172. package/src/cli/repositories/structured-git.ts +39 -3
  173. package/src/cli/repository/inspector.ts +185 -343
  174. package/src/effects/process-runner.ts +17 -1
  175. package/src/runtime/context/generic-lsp-provider.ts +1 -1
  176. package/src/runtime/context/semantic-navigation-contract.ts +7 -0
  177. package/src/runtime/context/semantic-navigation.ts +1 -1
  178. package/src/runtime/control-plane/cleanup-artifact-retention.ts +4 -4
  179. package/src/runtime/control-plane/execution/work-delivery-service.ts +150 -31
  180. package/src/runtime/control-plane/execution/work-handle-authority.ts +12 -4
  181. package/src/runtime/control-plane/execution/work-handle-store.ts +53 -1
  182. package/src/runtime/control-plane/execution/work-operation-service.ts +20 -10
  183. package/src/runtime/control-plane/execution/work-preparation-service.ts +108 -4
  184. package/src/runtime/control-plane/execution/work-process-evidence.ts +2 -2
  185. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +28 -13
  186. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +5 -1
  187. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +1 -1
  188. package/src/runtime/control-plane/facade/capability-registry.ts +2 -0
  189. package/src/runtime/control-plane/facade/work-continuation.ts +1 -1
  190. package/src/runtime/control-plane/generated-cache-retention.ts +114 -63
  191. package/src/runtime/control-plane/global-scheduler/maintenance.ts +20 -8
  192. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +1 -11
  193. package/src/runtime/control-plane/governance/external-effects.ts +1 -1
  194. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +1 -0
  195. package/src/runtime/control-plane/runtime-cleanup.ts +12 -93
  196. package/src/runtime/evidence/sensitive-output.ts +22 -2
  197. package/src/runtime/execution/jobs/child-reference.ts +11 -0
  198. package/src/runtime/execution/jobs/receipt-recovery.ts +1 -11
  199. package/src/runtime/execution/process-runtime/command-facade.ts +3 -3
  200. package/src/runtime/execution/process-runtime/runtime.ts +20 -16
  201. package/src/runtime/execution/thin-harness/execution-router.ts +16 -16
  202. package/src/runtime/execution/thin-harness/fast-executor.ts +2 -2
  203. package/src/runtime/execution/thin-harness/search-worker.ts +2 -2
  204. package/src/runtime/execution/workers/executor.ts +1 -2
  205. package/src/runtime/maintenance/cleanup.ts +41 -5
  206. package/src/runtime/plugins/action-application.ts +12 -1
  207. package/src/runtime/plugins/app-store-connect-adapter.ts +252 -4
  208. package/src/runtime/plugins/browser-adapter.ts +381 -313
  209. package/src/runtime/plugins/browser-macos-bridge.ts +114 -112
  210. package/src/runtime/plugins/browser-manifest-surface.ts +2 -1
  211. package/src/runtime/plugins/browser-registration.ts +2 -0
  212. package/src/runtime/plugins/browser-runtime.ts +26 -35
  213. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +11 -2
  214. package/src/runtime/plugins/computer-registration.ts +76 -9
  215. package/src/runtime/plugins/github-adapter.ts +30 -3
  216. package/src/runtime/plugins/gmail-adapter.ts +166 -1
  217. package/src/runtime/plugins/google-shared.ts +10 -5
  218. package/src/runtime/plugins/ios/remote-xpc-hid.ts +70 -30
  219. package/src/runtime/plugins/ios-adapter.ts +45 -40
  220. package/src/runtime/plugins/ios-agent-device.ts +54 -4
  221. package/src/runtime/plugins/ios-device-ownership.ts +103 -0
  222. package/src/runtime/plugins/ios-physical-device.ts +497 -79
  223. package/src/runtime/plugins/local-system-adapter.ts +1 -99
  224. package/src/runtime/plugins/store.ts +80 -7
  225. package/src/runtime/plugins/types.ts +4 -0
  226. package/src/runtime/projections/git-status-sampler.ts +2 -19
  227. package/src/runtime/recovery/actions.ts +1 -1
  228. package/src/runtime/recovery/lifecycle-inventory.ts +1 -11
  229. package/src/runtime/recovery/probe.ts +2 -2
  230. package/src/runtime/release/release-coordinator.ts +20 -4
  231. package/src/runtime/root/controller-progression-composition.ts +67 -5
  232. package/src/runtime/root/package-connector-service.ts +123 -11
  233. package/src/runtime/root/package-runtime-release.ts +6 -18
  234. package/src/runtime/root/package-runtime-service.ts +7 -13
  235. package/src/runtime/root/release-execution-canary.ts +18 -5
  236. package/src/runtime/root/release-manifest.ts +0 -34
  237. package/src/runtime/root/release-materialize.ts +0 -78
  238. package/src/runtime/root/runtime.ts +1 -2
  239. package/src/runtime/root/scheduled-controller-composition.ts +2 -1
  240. package/src/runtime/root/service.ts +90 -11
  241. package/src/runtime/root/types.ts +0 -6
  242. package/src/runtime/root/workflow-supervisor-composition.ts +207 -19
  243. package/src/runtime/root/workflow-supervisor-runtime.ts +365 -10
  244. package/src/runtime/safe-tooling/google-credential-store.ts +1 -11
  245. package/src/runtime/safe-tooling/ios-development.ts +22 -8
  246. package/src/runtime/safe-tooling/job-summary.ts +1 -1
  247. package/src/runtime/safe-tooling/workspace-auth.ts +4 -1
  248. package/src/runtime/shared/atomic-text-file.ts +21 -0
  249. package/src/runtime/shared/json-files.ts +8 -3
  250. package/src/runtime/standalone-recovery/core.ts +189 -174
  251. package/src/runtime/standalone-recovery/entry.ts +62 -30
  252. package/src/runtime/standalone-recovery/operation-lock.ts +11 -1
  253. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +1 -0
  254. package/src/runtime/workflow/schedules/engine.ts +36 -14
  255. package/src/runtime/workflow/schedules/pending-activation.ts +11 -4
  256. package/src/runtime/workflow/schedules/work-continuation.ts +51 -6
  257. package/supervisor/client.ts +31 -14
  258. package/supervisor/control-plane.ts +210 -115
  259. package/supervisor/forge-validators.ts +88 -21
  260. package/supervisor/native-browser-adapter.ts +393 -28
  261. package/supervisor/native-messaging/host.ts +21 -2
  262. package/supervisor/protocol.ts +74 -26
  263. package/supervisor/server.ts +16 -8
  264. package/supervisor/store.ts +476 -57
  265. package/supervisor/types.ts +19 -13
  266. package/SKILL.md +0 -427
  267. package/adapters/computer/chatgpt-target-router.ts +0 -103
  268. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +0 -87
  269. package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +0 -1
  270. package/adapters/mcp/toolset-selection.ts +0 -41
  271. package/agents/openai.yaml +0 -4
  272. package/assets/skill-hooks.json +0 -41
  273. package/assets/skill-version.json +0 -189
  274. package/assets/skills/claude-review/SKILL.md +0 -231
  275. package/assets/skills/codex-review/SKILL.md +0 -103
  276. package/assets/templates/helpers/check-skill-version.ts +0 -193
  277. package/scripts/check-skill-version.ts +0 -5
  278. package/scripts/ensure-codegraph.sh +0 -16
  279. package/scripts/run-skill-hook.ts +0 -244
  280. package/scripts/sync-codex-installed-copies.sh +0 -182
  281. package/src/cli/commands/tools.ts +0 -167
  282. package/src/cli/mcp/access-mode.ts +0 -2
  283. package/src/cli/mcp/access-tools.ts +0 -2
  284. package/src/cli/mcp/audit.ts +0 -2
  285. package/src/cli/mcp/auth.ts +0 -2
  286. package/src/cli/mcp/instructions.ts +0 -2
  287. package/src/cli/mcp/legacy-context.ts +0 -2
  288. package/src/cli/mcp/legacy-tool-service.ts +0 -2
  289. package/src/cli/mcp/multi-repository.ts +0 -2
  290. package/src/cli/mcp/oauth.ts +0 -2
  291. package/src/cli/mcp/openai-secure-tunnel.ts +0 -2
  292. package/src/cli/mcp/paths.ts +0 -2
  293. package/src/cli/mcp/policy.ts +0 -2
  294. package/src/cli/mcp/post-finalize-work-attribution.ts +0 -2
  295. package/src/cli/mcp/proxy-env.ts +0 -2
  296. package/src/cli/mcp/readiness-projection.ts +0 -2
  297. package/src/cli/mcp/redaction.ts +0 -2
  298. package/src/cli/mcp/repo.ts +0 -2
  299. package/src/cli/mcp/repository-tools.ts +0 -2
  300. package/src/cli/mcp/server.ts +0 -2
  301. package/src/cli/mcp/setup.ts +0 -2
  302. package/src/cli/mcp/tool-capability-cache.ts +0 -2
  303. package/src/cli/mcp/tool-contract.ts +0 -2
  304. package/src/cli/mcp/tools.ts +0 -2
  305. package/src/cli/mcp/toolset-names.ts +0 -2
  306. package/src/cli/mcp/toolset-selection.ts +0 -2
  307. package/src/cli/mcp/toolset.ts +0 -2
  308. package/src/cli/mcp/transports/http.ts +0 -2
  309. package/src/cli/mcp/transports/session-registry.ts +0 -2
  310. package/src/cli/mcp/transports/stdio.ts +0 -2
  311. package/src/cli/mcp/types.ts +0 -2
  312. package/src/cli/mcp/umbrella-tools.ts +0 -2
  313. package/src/cli/tools/codegraph.ts +0 -695
  314. package/src/core/adoption/helper-wrapper-plan.ts +0 -159
  315. package/src/runtime/context/codegraph-cache-boundary.ts +0 -255
  316. package/src/runtime/context/codegraph-read-provider.ts +0 -611
  317. package/src/runtime/context/codegraph-sidecar.cjs +0 -248
  318. package/src/runtime/control-plane/codegraph-cache-retention.ts +0 -164
  319. package/src/runtime/gateway/mcp/execution-tools.ts +0 -2
  320. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +0 -2
  321. package/src/runtime/gateway/mcp/persisted-check-process.ts +0 -2
  322. package/src/runtime/gateway/mcp/process-tools.ts +0 -2
  323. package/src/runtime/gateway/mcp/router.ts +0 -2
  324. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +0 -2
  325. package/src/runtime/gateway/mcp/runtime-tools.ts +0 -2
  326. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +0 -2
  327. package/src/runtime/plugins/browser-provider-registry.ts +0 -2
  328. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +0 -891
@@ -28,11 +28,30 @@ export async function forwardNativeRequest(value: unknown, forgeHome?: string):
28
28
  }
29
29
  export function runNativeMessagingHost(forgeHome?: string): void {
30
30
  const decoder = new NativeMessageDecoder();
31
- let chain = Promise.resolve();
32
31
  process.stdin.on('data', (chunk: Buffer) => {
33
32
  let messages: unknown[];
34
33
  try { messages = decoder.push(chunk); } catch (error) { process.stdout.write(encodeNativeMessage({ id: 'invalid', ok: false, error: { code: 'WORKFLOW_SUPERVISOR_NATIVE_FRAME_INVALID', message: String(error) } })); return; }
35
- for (const message of messages) chain = chain.then(async () => { process.stdout.write(encodeNativeMessage(await forwardNativeRequest(message, forgeHome))); });
34
+ // Chrome matches replies by request id, not FIFO position. A slow page
35
+ // discovery/command must never queue heartbeats behind its 30s RPC budget:
36
+ // the Computer broker expires a provider heartbeat after 15s. Requests
37
+ // use independent Supervisor socket calls; the broker still exclusively
38
+ // owns effect claims, dispatch outcomes and exactly-once Send safety.
39
+ for (const message of messages) {
40
+ void forwardNativeRequest(message, forgeHome).then(
41
+ (response) => { process.stdout.write(encodeNativeMessage(response)); },
42
+ (error) => {
43
+ // Bad individual requests must not poison subsequent heartbeats.
44
+ const id = message && typeof message === 'object' && !Array.isArray(message)
45
+ && typeof (message as { id?: unknown }).id === 'string'
46
+ ? (message as { id: string }).id : 'invalid';
47
+ const detail = error instanceof Error ? error.message : String(error);
48
+ process.stdout.write(encodeNativeMessage({ id, ok: false, error: {
49
+ code: detail.split(':', 1)[0] || 'WORKFLOW_SUPERVISOR_NATIVE_REQUEST_INVALID',
50
+ message: detail,
51
+ } }));
52
+ },
53
+ );
54
+ }
36
55
  });
37
56
  process.stdin.resume();
38
57
  }
@@ -6,7 +6,16 @@ import type { WorkflowEffectKind, WorkflowSupervisorProposal, WorkflowSupervisor
6
6
  // block formats remain read-only compatibility for already-durable conversations.
7
7
  export const SUPERVISOR_BLOCK_START = 'FORGE_WORKFLOW_SUPERVISOR_V1_BEGIN';
8
8
  export const SUPERVISOR_BLOCK_END = 'FORGE_WORKFLOW_SUPERVISOR_V1_END';
9
- const COMPACT_RECEIPT = /^([CDU]) ([0-9a-f]{7})$/;
9
+ const COMPACT_RECEIPT = /(?:^|\n)([CWDU]) ([0-9a-f]{7})\s*$/;
10
+ // Older installed Chrome content scripts flattened an entire completed reply
11
+ // into one line. The immutable Effect challenge remains the sole authority;
12
+ // recover only its terminal token, never an inline token in multiline text.
13
+ const FLATTENED_COMPACT_RECEIPT = /(?:^| )([CWDU]) ([0-9a-f]{7})$/;
14
+ function terminalCompactReceipt(responseText: string): RegExpExecArray | null {
15
+ const text = responseText.trim();
16
+ return COMPACT_RECEIPT.exec(text)
17
+ ?? (!/[\r\n]/.test(text) ? FLATTENED_COMPACT_RECEIPT.exec(text) : null);
18
+ }
10
19
  export const LEGACY_BRACKET_SUPERVISOR_BLOCK_START = '[[[FORGE_WORKFLOW_SUPERVISOR_V1]]]';
11
20
  export const LEGACY_BRACKET_SUPERVISOR_BLOCK_END = '[[[END_FORGE_WORKFLOW_SUPERVISOR_V1]]]';
12
21
  export const LEGACY_SUPERVISOR_BLOCK_START = '<<<FORGE_WORKFLOW_SUPERVISOR_V1>>>';
@@ -16,6 +25,14 @@ export const SUPERVISOR_TURN_BLOCK_START = 'FORGE_WORKFLOW_TURN_V2_BEGIN';
16
25
  export const SUPERVISOR_TURN_BLOCK_END = 'FORGE_WORKFLOW_TURN_V2_END';
17
26
  const EFFECT_ID = /^(?:fx|crpe)_[a-zA-Z0-9_-]{8,120}$/;
18
27
  const MAX_RESPONSE = 512 * 1024;
28
+ export const MAX_SUPERVISOR_OBJECTIVE_CHARS = 8_000;
29
+
30
+ /** A goal cannot be silently shortened between durable Task and sent effect. */
31
+ export function validateSupervisorObjective(value: string): string {
32
+ if (typeof value !== 'string' || !value.trim()) throw new Error('WORKFLOW_SUPERVISOR_OBJECTIVE_REQUIRED');
33
+ if (value.length > MAX_SUPERVISOR_OBJECTIVE_CHARS) throw new Error('WORKFLOW_SUPERVISOR_OBJECTIVE_TOO_LARGE');
34
+ return value;
35
+ }
19
36
  const SUPERVISOR_BLOCK_MARKERS = [
20
37
  { start: SUPERVISOR_BLOCK_START, end: SUPERVISOR_BLOCK_END },
21
38
  { start: LEGACY_BRACKET_SUPERVISOR_BLOCK_START, end: LEGACY_BRACKET_SUPERVISOR_BLOCK_END },
@@ -50,7 +67,7 @@ export function renderSupervisorReceipt(
50
67
  effectId: string,
51
68
  action: WorkflowSupervisorProposal['action'],
52
69
  ): string {
53
- const code = action === 'CONTINUE' ? 'C' : action === 'DONE' ? 'D' : 'U';
70
+ const code = action === 'CONTINUE' ? 'C' : action === 'WAIT' ? 'W' : action === 'DONE' ? 'D' : 'U';
54
71
  return `${code} ${supervisorReceiptChallenge(task, effectId)}`;
55
72
  }
56
73
 
@@ -73,34 +90,58 @@ function supervisorBlockEnvelope(responseText: string): { start: number; end: nu
73
90
 
74
91
  export function hasCommittedSupervisorEnvelope(responseText: string): boolean {
75
92
  if (Buffer.byteLength(responseText, 'utf8') > MAX_RESPONSE) return false;
76
- if (COMPACT_RECEIPT.test(responseText.trim())) return true;
93
+ if (terminalCompactReceipt(responseText)) return true;
77
94
  try { supervisorBlockEnvelope(responseText); return true; } catch { return false; }
78
95
  }
79
96
 
80
97
  export function parseSupervisorCompletion(
81
98
  responseText: string,
82
- expected?: { task: Pick<WorkflowSupervisorTask, 'taskId' | 'conversationId'>; effectId: string },
99
+ expected?: { task: Pick<WorkflowSupervisorTask, 'taskId' | 'conversationId' | 'continuationPolicy'>; effectId: string; prompt?: string },
83
100
  ): { proposal: WorkflowSupervisorProposal; controlBlock: string } {
84
101
  if (Buffer.byteLength(responseText, 'utf8') > MAX_RESPONSE) throw new Error('WORKFLOW_SUPERVISOR_RESPONSE_TOO_LARGE');
85
- const compact = COMPACT_RECEIPT.exec(responseText.trim());
102
+ const compact = terminalCompactReceipt(responseText);
86
103
  if (compact) {
87
104
  if (!expected) throw new Error('WORKFLOW_SUPERVISOR_COMPACT_RECEIPT_CONTEXT_REQUIRED');
88
- const challenge = supervisorReceiptChallenge(expected.task, expected.effectId);
105
+ let challenge = supervisorReceiptChallenge(expected.task, expected.effectId);
106
+ // Bootstrap binding changes the Task's conversation identity after Send.
107
+ // Validate the challenge actually sent in the immutable effect, never a
108
+ // recomputation from that subsequently changed Task projection.
109
+ if (expected.prompt?.includes(SUPERVISOR_TURN_BLOCK_START)) {
110
+ const start = expected.prompt.indexOf(SUPERVISOR_TURN_BLOCK_START + '\n') + SUPERVISOR_TURN_BLOCK_START.length + 1;
111
+ const end = expected.prompt.indexOf('\n' + SUPERVISOR_TURN_BLOCK_END, start);
112
+ let envelope: WorkflowSupervisorTurnEnvelope;
113
+ try { envelope = JSON.parse(expected.prompt.slice(start, end)); }
114
+ catch { throw new Error('WORKFLOW_SUPERVISOR_EFFECT_RECEIPT_INVALID'); }
115
+ if (end < start || envelope?.schema_version !== 2
116
+ || envelope.identity?.task_id !== expected.task.taskId
117
+ || envelope.identity?.effect_id !== expected.effectId
118
+ || !/^[0-9a-f]{7}$/.test(envelope.receipt?.challenge ?? '')) {
119
+ throw new Error('WORKFLOW_SUPERVISOR_EFFECT_RECEIPT_INVALID');
120
+ }
121
+ challenge = envelope.receipt.challenge;
122
+ }
89
123
  if (compact[2] !== challenge) throw new Error('WORKFLOW_SUPERVISOR_COMPACT_RECEIPT_CHALLENGE_MISMATCH');
90
- const action = compact[1] === 'C' ? 'CONTINUE' : compact[1] === 'D' ? 'DONE' : 'NEEDS_USER';
91
- const supervisorState: WorkflowSupervisorState = action === 'CONTINUE' ? 'running' : action === 'DONE' ? 'done' : 'needs_user';
124
+ const action = compact[1] === 'C' ? 'CONTINUE' : compact[1] === 'W' ? 'WAIT' : compact[1] === 'D' ? 'DONE' : 'NEEDS_USER';
125
+ if (action === 'WAIT' && typeof expected.task.continuationPolicy.scheduled_wake_schedule_id !== 'string') {
126
+ throw new Error('WORKFLOW_SUPERVISOR_WAIT_NOT_SCHEDULED');
127
+ }
128
+ const supervisorState: WorkflowSupervisorState = action === 'CONTINUE' ? 'running' : action === 'WAIT' ? 'waiting' : action === 'DONE' ? 'done' : 'needs_user';
92
129
  return {
93
130
  proposal: {
94
131
  action,
95
132
  sourceEffectId: validateEffectId(expected.effectId),
96
133
  checkpoint: `receipt:${challenge}`,
97
134
  reason: 'compact_receipt',
98
- evidence: [],
135
+ // A transient missing tool is mechanical evidence, never user-only
136
+ // authorization. Persist the explicit model diagnostic on this same
137
+ // completion so crash reconciliation uses identical validation.
138
+ evidence: action === 'NEEDS_USER' && /(?:^|\r?\n)\s*NO_TOOL_RECEIPT(?=\s|[::]|$)/.test(responseText)
139
+ ? ['NO_TOOL_RECEIPT'] : [],
99
140
  conversationId: expected.task.conversationId,
100
141
  taskId: expected.task.taskId,
101
142
  supervisorState,
102
143
  },
103
- controlBlock: responseText.trim(),
144
+ controlBlock: compact[0].trim(),
104
145
  };
105
146
  }
106
147
  const { start, end, startMarker, endMarker } = supervisorBlockEnvelope(responseText);
@@ -112,7 +153,10 @@ export function parseSupervisorCompletion(
112
153
  const allowed = new Set(['action', 'source_effect_id', 'checkpoint', 'reason', 'evidence', 'conversation_id', 'task_id', 'supervisor_state', 'active_scope']);
113
154
  if (Object.keys(record).some((key) => !allowed.has(key))) throw new Error('WORKFLOW_SUPERVISOR_CONTROL_BLOCK_FIELD_INVALID');
114
155
  const action = boundedString(record.action, 'ACTION', 32);
115
- if (!['CONTINUE', 'DONE', 'NEEDS_USER'].includes(action)) throw new Error('WORKFLOW_SUPERVISOR_ACTION_INVALID');
156
+ if (!['CONTINUE', 'WAIT', 'DONE', 'NEEDS_USER'].includes(action)) throw new Error('WORKFLOW_SUPERVISOR_ACTION_INVALID');
157
+ if (action === 'WAIT' && (!expected || typeof expected.task.continuationPolicy.scheduled_wake_schedule_id !== 'string')) {
158
+ throw new Error('WORKFLOW_SUPERVISOR_WAIT_NOT_SCHEDULED');
159
+ }
116
160
  const sourceEffectId = validateEffectId(boundedString(record.source_effect_id, 'SOURCE_EFFECT_ID', 128));
117
161
  const checkpoint = boundedString(record.checkpoint, 'CHECKPOINT', 2_000);
118
162
  const reason = boundedString(record.reason, 'REASON', 2_000);
@@ -122,8 +166,8 @@ export function parseSupervisorCompletion(
122
166
  const taskId = record.task_id === undefined ? undefined : boundedString(record.task_id, 'TASK_ID', 512);
123
167
  const supervisorState = record.supervisor_state === undefined ? undefined : boundedString(record.supervisor_state, 'SUPERVISOR_STATE', 32) as WorkflowSupervisorState;
124
168
  const activeScope = record.active_scope === undefined ? undefined : boundedString(record.active_scope, 'ACTIVE_SCOPE', 512);
125
- if (supervisorState && !['running', 'done', 'needs_user'].includes(supervisorState)) throw new Error('WORKFLOW_SUPERVISOR_STATE_INVALID');
126
- const expectedState: WorkflowSupervisorState = action === 'CONTINUE' ? 'running' : action === 'DONE' ? 'done' : 'needs_user';
169
+ if (supervisorState && !['running', 'waiting', 'done', 'needs_user'].includes(supervisorState)) throw new Error('WORKFLOW_SUPERVISOR_STATE_INVALID');
170
+ const expectedState: WorkflowSupervisorState = action === 'CONTINUE' ? 'running' : action === 'WAIT' ? 'waiting' : action === 'DONE' ? 'done' : 'needs_user';
127
171
  if (supervisorState && supervisorState !== expectedState) throw new Error('WORKFLOW_SUPERVISOR_STATE_ACTION_MISMATCH');
128
172
  if (activeScope && !/^(?:requirement|goal):[^\s]{1,480}$/.test(activeScope)) throw new Error('WORKFLOW_SUPERVISOR_ACTIVE_SCOPE_INVALID');
129
173
  const controlBlock = responseText.slice(start, end + endMarker.length);
@@ -154,7 +198,10 @@ export function renderSupervisorPrompt(
154
198
  const checkoutId = typeof task.completionContract.checkout_id === 'string'
155
199
  ? task.completionContract.checkout_id.trim()
156
200
  : typeof task.continuationPolicy.checkout_id === 'string' ? task.continuationPolicy.checkout_id.trim() : '';
157
- const checkpoint = typeof _checkpoint === 'string' ? _checkpoint.trim().slice(0, 2_000) : '';
201
+ // An automation receipt is a causal key, not an engineering handoff.
202
+ // Conversation context and live project evidence guide the next action.
203
+ const rawCheckpoint = typeof _checkpoint === 'string' ? _checkpoint.trim() : '';
204
+ const checkpoint = /^(?:automation:|receipt:)/.test(rawCheckpoint) ? '' : rawCheckpoint.slice(0, 2_000);
158
205
  // Recovery/correction context is model-facing advisory evidence, not another
159
206
  // authority. Discarding it made a recovery look like the original request
160
207
  // and allowed the model to repeat previously completed work.
@@ -174,28 +221,29 @@ export function renderSupervisorPrompt(
174
221
  },
175
222
  goal: {
176
223
  role: 'outcome',
177
- objective: task.objective.slice(0, 8_000),
224
+ objective: validateSupervisorObjective(task.objective),
178
225
  },
179
226
  ...(continuity ? { continuity: { role: 'advisory' as const, summary: continuity } } : {}),
180
227
  ...(repoId ? { repository: { repo_id: repoId, ...(checkoutId ? { checkout_id: checkoutId } : {}) } } : {}),
181
228
  ...(cognition ? { cognition: { role: 'advisory' as const, projection: cognition } } : {}),
182
- automation: {
183
- automation_task_id: task.taskId,
184
- automation_type: 'autonomous_continuation',
185
- intermediate_status: 'working',
186
- final_statuses: ['continue', 'done', 'needs_user'],
187
- },
229
+ receipt: { challenge: supervisorReceiptChallenge(task, effectId) },
188
230
  };
189
231
  return [
190
- '@forge',
191
232
  renderEffectMarker(effectId),
233
+ // Keep the exact Effect marker first for existing target matching, but
234
+ // surface tool intent before the potentially long JSON goal envelope.
235
+ 'forge 继续。使用真实可用的 Forge 工具接续未完成的工作;不必每轮先做工具或全局状态自检。',
192
236
  SUPERVISOR_TURN_BLOCK_START,
193
237
  JSON.stringify(envelope),
194
238
  SUPERVISOR_TURN_BLOCK_END,
195
- // The tool receipt, not prose in the page, settles the same applied effect.
196
- // One instruction for every turn: no new scheduler, no extra state, no
197
- // unconditional CONTINUE when no real work has been done.
198
- 'FORGE_AUTONOMOUS_RECEIPT_V1: Use automation_task_id and automation_type from this envelope on Forge calls. Use automation_status=working during execution. After substantive progress, submit automation_status=continue in the final Forge call; use done only after the stated goal is met, or needs_user only for a genuine external decision/blocker. A text-only answer does not settle the turn. Do not report continue for a status-only or empty round.',
239
+ // Textual intent only: Project instructions and literal @forge are not proof
240
+ // of an App binding. No browser/plugin UI mutation belongs in this renderer.
241
+ 'USE FORGE: 使用 forge。已有真实工具时直接执行相关源码、验证或交付动作,不要强制以 rh_status 开始。JSON、项目指令或文字 @forge 不会授予工具权限;如果工具完全不可见,仅检查一次实际提供的发现入口(如有 functions.exec 可经 ALL_TOOLS 查询 mcp__forge__),不要反复自检或要求用户选择 App,也不能伪造调用。无工具时正文写 NO_TOOL_RECEIPT 和真实缺口,不宣称工程产出。',
242
+ 'DELIVER WORK: 把 objective 当作持续目标,像用户直接发送“继续”一样从本会话最近的未完成工作处继续;同一交付仍有安全、相关且必要的步骤时,本轮持续实现、验证、审阅并合法交付,不要因完成一次查询或一个微步而收尾。只补充当前真正缺失的证据,复用已有检查;不重复全局盘点,不机械新增 Work/Plan/测试。守住单一 writer、exact target、未知发送不重放和不可逆发布授权边界。不要在只有状态检查、计划或解释时结束本轮。',
243
+ ...(typeof task.continuationPolicy.scheduled_wake_schedule_id === 'string' ? [
244
+ 'SCHEDULED WORK: 本轮仍有同一日的必要步骤时继续实现并以 C ' + supervisorReceiptChallenge(task, effectId) + ' 结束;当日目标已完成且没有剩余安全必要步骤时,使用 WAIT 并以 W ' + supervisorReceiptChallenge(task, effectId) + ' 结束。若存在真实人工阻塞,先记录精确且持久的 UserRequest、停止不安全动作,并在授权可用时通知用户,然后使用 WAIT 保持同一任务开放;不要用 DONE 或 NEEDS_USER 终结每日循环,也不要自行创建新日程。WAIT 让同一任务保持非终结状态,直到绑定的 Scheduler 下次触发。',
245
+ ] : []),
246
+ 'END OF TURN: 本轮工作实际结束时才简述可核验产出和剩余事项,不要为尽快输出 C 提前终止仍可继续的安全开发。NO_TOOL_RECEIPT 只能写在正文中;工具不可用不等于用户必须介入,临时无工具且仍需下一轮探测时同样以 C ' + supervisorReceiptChallenge(task, effectId) + ' 结束,并写明零工程产出;不能将 C 视为成功或进展。D ' + supervisorReceiptChallenge(task, effectId) + ' 仅用于原目标真实交付;U ' + supervisorReceiptChallenge(task, effectId) + ' 仅用于确需用户决定/授权的阻塞。C/D/U' + (typeof task.continuationPolicy.scheduled_wake_schedule_id === 'string' ? '/W' : '') + ' 校验码必须独占最终助手回复最后一行,不得在中间消息提前输出,不要向 MCP 传 automation_status;Supervisor 只结算已完成的最终助手回复(only the completed final assistant reply)。',
199
247
  ].join('\n');
200
248
  }
201
249
 
@@ -347,10 +347,12 @@ async function dispatch(control: WorkflowSupervisorControlPlane, discovery: Work
347
347
  if (req.method === 'bootstrap_poll') return control.bootstrapPoll(text(p, 'task_id'));
348
348
  if (req.method === 'bootstrap_project_url') return { project_url: control.bootstrapProjectUrl(text(p, 'task_id')) };
349
349
  if (req.method === 'bootstrap_begin_effect') return { started: control.bootstrapBeginEffect({ taskId: text(p, 'task_id'), effectId: text(p, 'effect_id'), dispatchId: text(p, 'dispatch_id'), dispatchGeneration: positiveInteger(p, 'dispatch_generation') }) };
350
- if (req.method === 'bootstrap_observe_effect') { const outcome = text(p, 'outcome'); if (!['applied','not_applied','unknown'].includes(outcome)) throw new Error('WORKFLOW_SUPERVISOR_RPC_OUTCOME_INVALID'); control.bootstrapObserveEffect({ taskId: text(p, 'task_id'), effectId: text(p, 'effect_id'), observationId: text(p, 'observation_id'), outcome: outcome as 'applied'|'not_applied'|'unknown', evidence: object(p.evidence) }); return { recorded: true }; }
350
+ if (req.method === 'bootstrap_observe_effect') { const outcome = text(p, 'outcome'); if (!['applied','unknown'].includes(outcome)) throw new Error('WORKFLOW_SUPERVISOR_RPC_OUTCOME_INVALID'); control.bootstrapObserveEffect({ taskId: text(p, 'task_id'), effectId: text(p, 'effect_id'), observationId: text(p, 'observation_id'), outcome: outcome as 'applied'|'unknown', evidence: object(p.evidence) }); return { recorded: true }; }
351
351
  if (req.method === 'browser_begin_effect') return control.browserBeginEffect({ conversationId: text(p, 'conversation_id'), conversationUrl: text(p, 'conversation_url'), effectId: text(p, 'effect_id'), dispatchId: text(p, 'dispatch_id'), dispatchGeneration: positiveInteger(p, 'dispatch_generation'), evidence: object(p.evidence) });
352
352
  if (req.method === 'browser_observe_effect') { const outcome = text(p, 'outcome'); if (!['applied','not_applied','unknown'].includes(outcome)) throw new Error('WORKFLOW_SUPERVISOR_RPC_OUTCOME_INVALID'); return control.browserObserveEffect({ conversationId: text(p, 'conversation_id'), conversationUrl: text(p, 'conversation_url'), effectId: text(p, 'effect_id'), observationId: text(p, 'observation_id'), outcome: outcome as 'applied'|'not_applied'|'unknown', evidence: object(p.evidence) }); }
353
- if (req.method === 'browser_observe_dispatch_failure') { control.browserObserveDispatchFailure({ conversationId: text(p, 'conversation_id'), conversationUrl: text(p, 'conversation_url'), effectId: text(p, 'effect_id'), observationId: text(p, 'observation_id'), dispatchGeneration: positiveInteger(p, 'dispatch_generation'), reason: text(p, 'reason'), surface: 'chrome-extension' }); return { recorded: true }; }
353
+ // A generic observer cannot attest that a provider dispatch returned before Send.
354
+ // Only the in-process Computer dispatch owner may write a negative proof.
355
+ if (req.method === 'browser_observe_dispatch_failure') throw new Error('WORKFLOW_SUPERVISOR_RPC_DISPATCH_OWNER_ONLY');
354
356
  if (req.method === 'browser_observe_provider_turn') return control.browserObserveProviderTurn({ conversationId: text(p, 'conversation_id'), conversationUrl: text(p, 'conversation_url'), generating: p.generating === true, latestAssistantResponse: stringValue(p.latest_assistant_response), providerActivityText: stringValue(p.provider_activity_text), providerFailureCode: chatgptProviderPageFailure(stringValue(p.provider_failure_text)), observedAtMs: safeInteger(p, 'observed_at_ms'), graceMs: positiveInteger(p, 'grace_ms') });
355
357
  if (req.method === 'browser_observe_assistant') return control.browserObserveAssistant({ conversationId: text(p, 'conversation_id'), conversationUrl: text(p, 'conversation_url'), responseText: text(p, 'response_text') });
356
358
  if (req.method === 'task_register') return control.registerTask({ taskId: text(p, 'task_id'), conversationId: text(p, 'conversation_id'), conversationUrl: text(p, 'conversation_url'), objective: text(p, 'objective'), completionContract: object(p.completion_contract), continuationPolicy: object(p.continuation_policy), userBlockerPolicy: object(p.user_blocker_policy) });
@@ -359,9 +361,14 @@ async function dispatch(control: WorkflowSupervisorControlPlane, discovery: Work
359
361
  objective: text(p, 'objective'),
360
362
  expectedObjectiveSha256: text(p, 'expected_objective_sha256'),
361
363
  requestId: text(p, 'request_id'),
364
+ ...(typeof p.work_id === 'string' && p.work_id.trim() ? { workId: p.work_id.trim() } : {}),
365
+ ...(typeof p.requirement_id === 'string' && p.requirement_id.trim() ? { requirementId: p.requirement_id.trim() } : {}),
366
+ ...(typeof p.expected_completion_contract_sha256 === 'string' && p.expected_completion_contract_sha256.trim() ? { expectedCompletionContractSha256: p.expected_completion_contract_sha256.trim() } : {}),
362
367
  ...(typeof p.authorized_by === 'string' && p.authorized_by.trim() ? { authorizedBy: p.authorized_by.trim() } : {}),
363
368
  });
364
- if (req.method === 'task_list') return { tasks: control.listTasks(p.active_only === true) };
369
+ if (req.method === 'task_list') return p.terminal_only === true
370
+ ? { tasks: [], terminalTasks: control.listTerminalTasks() }
371
+ : { tasks: control.listTasks(p.active_only === true) };
365
372
  if (req.method === 'task_stop') return control.stopTask(text(p, 'task_id'), typeof p.reason === 'string' && p.reason.trim() ? p.reason.trim() : 'Stopped by operator request.');
366
373
  if (req.method === 'task_recover') return control.recoverTask({
367
374
  taskId: text(p, 'task_id'),
@@ -372,6 +379,12 @@ async function dispatch(control: WorkflowSupervisorControlPlane, discovery: Work
372
379
  ...(typeof p.authorized_by === 'string' && p.authorized_by.trim() ? { authorizedBy: p.authorized_by.trim() } : {}),
373
380
  });
374
381
  if (req.method === 'task_stall') return control.taskStall(text(p, 'task_id'));
382
+ if (req.method === 'task_bind_scheduled_wake') return control.bindScheduledWake({
383
+ taskId: text(p, 'task_id'), repoId: text(p, 'repo_id'), workId: text(p, 'work_id'), scheduleId: text(p, 'schedule_id'),
384
+ });
385
+ if (req.method === 'task_wake_scheduled') return control.wakeScheduledTask({
386
+ taskId: text(p, 'task_id'), scheduleId: text(p, 'schedule_id'), occurrenceId: text(p, 'occurrence_id'),
387
+ });
375
388
  if (req.method === 'task_migrate_conversation') return control.migrateConversation({
376
389
  taskId: text(p, 'task_id'),
377
390
  expectedConversationId: text(p, 'expected_conversation_id'),
@@ -386,11 +399,6 @@ async function dispatch(control: WorkflowSupervisorControlPlane, discovery: Work
386
399
  if (req.method === 'reserve_enrollment') return control.reserveEnrollment(text(p, 'task_id'), typeof p.effect_id === 'string' ? p.effect_id : undefined);
387
400
  if (req.method === 'observe_effect') { const outcome = text(p, 'outcome'); if (!['applied','unknown'].includes(outcome)) throw new Error('WORKFLOW_SUPERVISOR_RPC_OUTCOME_INVALID'); control.observeEffect({ effectId: text(p, 'effect_id'), observationId: text(p, 'observation_id'), outcome: outcome as 'applied'|'unknown', evidence: object(p.evidence) }); return { recorded: true }; }
388
401
  if (req.method === 'observe_assistant') return control.observeAssistantTurn({ taskId: text(p, 'task_id'), conversationId: text(p, 'conversation_id'), responseText: text(p, 'response_text') });
389
- if (req.method === 'automation_receipt') {
390
- const status = text(p, 'automation_status');
391
- if (!['working', 'continue', 'done', 'needs_user'].includes(status)) throw new Error('WORKFLOW_SUPERVISOR_RPC_AUTOMATION_STATUS_INVALID');
392
- return control.observeAutomationReceipt({ taskId: text(p, 'task_id'), conversationId: text(p, 'conversation_id'), status: status as import('./types').WorkflowSupervisorAutomationStatus, receiptId: text(p, 'receipt_id') });
393
- }
394
402
  if (req.method === 'task_get') return control.getTask(text(p, 'task_id')) ?? null;
395
403
  if (req.method === 'task_get_by_conversation') return control.getTaskByConversationId(text(p, 'conversation_id')) ?? null;
396
404
  if (req.method === 'effect_get') return control.getEffect(text(p, 'effect_id')) ?? null;