@gajae-code/coding-agent 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. package/CHANGELOG.md +50 -2
  2. package/dist/types/append-only-mode.d.ts +1 -1
  3. package/dist/types/cli/args.d.ts +4 -5
  4. package/dist/types/cli/daemon-cli.d.ts +12 -1
  5. package/dist/types/cli/notify-cli.d.ts +21 -1
  6. package/dist/types/cli.d.ts +3 -0
  7. package/dist/types/commands/daemon.d.ts +39 -0
  8. package/dist/types/commands/launch.d.ts +3 -0
  9. package/dist/types/commands/notify.d.ts +28 -1
  10. package/dist/types/commands/sdk.d.ts +33 -0
  11. package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
  12. package/dist/types/config/model-profile-activation.d.ts +35 -15
  13. package/dist/types/config/model-profiles.d.ts +11 -5
  14. package/dist/types/config/model-registry.d.ts +3 -3
  15. package/dist/types/config/model-resolver.d.ts +39 -6
  16. package/dist/types/config/model-selector-value.d.ts +17 -0
  17. package/dist/types/config/models-config-schema.d.ts +10 -6
  18. package/dist/types/config/settings-schema.d.ts +133 -6
  19. package/dist/types/config/settings.d.ts +63 -35
  20. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
  21. package/dist/types/coordinator-mcp/server.d.ts +6 -49
  22. package/dist/types/daemon/builtin.d.ts +6 -5
  23. package/dist/types/daemon/control-types.d.ts +1 -1
  24. package/dist/types/discovery/mcp-json.d.ts +12 -1
  25. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  26. package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
  27. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
  28. package/dist/types/extensibility/extensions/loader.d.ts +10 -1
  29. package/dist/types/extensibility/extensions/runner.d.ts +3 -3
  30. package/dist/types/extensibility/extensions/types.d.ts +141 -16
  31. package/dist/types/extensibility/hooks/types.d.ts +1 -1
  32. package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
  33. package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
  34. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
  35. package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
  36. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
  37. package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
  38. package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
  39. package/dist/types/harness-control-plane/operate.d.ts +5 -5
  40. package/dist/types/harness-control-plane/owner.d.ts +18 -4
  41. package/dist/types/harness-control-plane/receipts.d.ts +0 -1
  42. package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
  43. package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
  44. package/dist/types/harness-control-plane/types.d.ts +3 -4
  45. package/dist/types/lsp/index.d.ts +1 -1
  46. package/dist/types/main.d.ts +32 -38
  47. package/dist/types/modes/acp/acp-agent.d.ts +224 -53
  48. package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
  49. package/dist/types/modes/acp/acp-mode.d.ts +6 -15
  50. package/dist/types/modes/acp/permission-mode.d.ts +4 -0
  51. package/dist/types/modes/acp/startup-options.d.ts +6 -0
  52. package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
  53. package/dist/types/modes/components/model-selector.d.ts +1 -0
  54. package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
  55. package/dist/types/modes/components/settings-selector.d.ts +6 -4
  56. package/dist/types/modes/components/welcome.d.ts +1 -1
  57. package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
  58. package/dist/types/modes/index.d.ts +0 -4
  59. package/dist/types/modes/interactive-mode.d.ts +3 -0
  60. package/dist/types/modes/runtime-init.d.ts +2 -2
  61. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
  62. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
  63. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
  64. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
  65. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
  66. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +169 -30
  67. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
  68. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
  69. package/dist/types/modes/types.d.ts +5 -0
  70. package/dist/types/runtime-mcp/client.d.ts +2 -0
  71. package/dist/types/runtime-mcp/config.d.ts +5 -1
  72. package/dist/types/runtime-mcp/manager.d.ts +8 -1
  73. package/dist/types/runtime-mcp/types.d.ts +4 -0
  74. package/dist/types/sdk/acp/adapter.d.ts +67 -0
  75. package/dist/types/sdk/acp/index.d.ts +2 -0
  76. package/dist/types/sdk/broker/broker.d.ts +53 -0
  77. package/dist/types/sdk/broker/discovery.d.ts +30 -0
  78. package/dist/types/sdk/broker/ensure.d.ts +33 -0
  79. package/dist/types/sdk/broker/identity.d.ts +3 -0
  80. package/dist/types/sdk/broker/index.d.ts +8 -0
  81. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
  82. package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
  83. package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
  84. package/dist/types/sdk/broker/runtime.d.ts +33 -0
  85. package/dist/types/sdk/broker/session-index.d.ts +57 -0
  86. package/dist/types/sdk/broker/state-version.d.ts +8 -0
  87. package/dist/types/sdk/broker/transport.d.ts +9 -0
  88. package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
  89. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
  90. package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
  91. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
  92. package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
  93. package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
  94. package/dist/types/sdk/bus/config.d.ts +274 -0
  95. package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
  96. package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
  97. package/dist/types/sdk/bus/discord-daemon.d.ts +45 -0
  98. package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
  99. package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
  100. package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
  101. package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
  102. package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
  103. package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
  104. package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
  105. package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
  106. package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
  107. package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
  108. package/dist/types/sdk/bus/session-control.d.ts +83 -0
  109. package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
  110. package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
  111. package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
  112. package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
  113. package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
  114. package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
  115. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
  116. package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
  117. package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +55 -17
  118. package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
  119. package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
  120. package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
  121. package/dist/types/sdk/cli/index.d.ts +1 -0
  122. package/dist/types/sdk/cli/session-cli.d.ts +19 -0
  123. package/dist/types/sdk/client/client.d.ts +1 -0
  124. package/dist/types/sdk/client/discovery.d.ts +27 -0
  125. package/dist/types/sdk/client/index.d.ts +2 -0
  126. package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
  127. package/dist/types/sdk/host/control/index.d.ts +2 -0
  128. package/dist/types/sdk/host/control/operations.d.ts +65 -0
  129. package/dist/types/sdk/host/events.d.ts +35 -0
  130. package/dist/types/sdk/host/host.d.ts +35 -0
  131. package/dist/types/sdk/host/index.d.ts +4 -0
  132. package/dist/types/sdk/host/query/cursor.d.ts +62 -0
  133. package/dist/types/sdk/host/query/handlers.d.ts +70 -0
  134. package/dist/types/sdk/host/query/index.d.ts +3 -0
  135. package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
  136. package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
  137. package/dist/types/sdk/host/types.d.ts +32 -0
  138. package/dist/types/sdk/index.d.ts +6 -0
  139. package/dist/types/sdk/lifecycle-session.d.ts +14 -0
  140. package/dist/types/sdk/mcp/index.d.ts +1 -0
  141. package/dist/types/sdk/mcp/server.d.ts +37 -0
  142. package/dist/types/sdk/models.d.ts +44 -0
  143. package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
  144. package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
  145. package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
  146. package/dist/types/sdk/startup-capability.d.ts +50 -0
  147. package/dist/types/session/agent-session.d.ts +114 -21
  148. package/dist/types/session/default-model-selection.d.ts +25 -0
  149. package/dist/types/session/fallback-chain-controller.d.ts +52 -0
  150. package/dist/types/session/session-manager.d.ts +58 -1
  151. package/dist/types/setup/credential-auto-import.d.ts +36 -6
  152. package/dist/types/tools/ask-answer-registry.d.ts +1 -1
  153. package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
  154. package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
  155. package/dist/types/tools/browser/launch.d.ts +22 -0
  156. package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
  157. package/dist/types/tools/browser/profile-posture.d.ts +37 -0
  158. package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
  159. package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
  160. package/dist/types/tools/browser/registry.d.ts +19 -0
  161. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  162. package/dist/types/tools/index.d.ts +8 -8
  163. package/package.json +34 -13
  164. package/scripts/build-sdk-package-smoke.ts +94 -0
  165. package/scripts/capture-notifications-settings-showcase.ts +435 -0
  166. package/scripts/compile-args.ts +4 -2
  167. package/scripts/g005-daemon-smoke.ts +4 -5
  168. package/scripts/g011-daemon-path-smoke.ts +5 -5
  169. package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
  170. package/scripts/generate-sdk-operation-inventory.ts +867 -0
  171. package/scripts/generate-telegram-baseline-manifest.ts +128 -0
  172. package/scripts/manifest-schema.ts +124 -0
  173. package/scripts/run-test-manifest.ts +153 -0
  174. package/scripts/run-threat-model-check.ts +157 -0
  175. package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
  176. package/scripts/verify-gjc-sdk-rename.ts +90 -0
  177. package/src/append-only-mode.ts +1 -1
  178. package/src/cli/args.ts +43 -12
  179. package/src/cli/auth-gateway-cli.ts +2 -2
  180. package/src/cli/config-cli.ts +2 -1
  181. package/src/cli/daemon-cli.ts +63 -14
  182. package/src/cli/list-models.ts +1 -1
  183. package/src/cli/notify-cli.ts +288 -286
  184. package/src/cli.ts +21 -2
  185. package/src/commands/daemon.ts +50 -6
  186. package/src/commands/harness.ts +93 -36
  187. package/src/commands/launch.ts +5 -2
  188. package/src/commands/mcp-serve.ts +19 -12
  189. package/src/commands/notify.ts +36 -3
  190. package/src/commands/sdk.ts +426 -0
  191. package/src/commit/agentic/agent.ts +1 -0
  192. package/src/config/atomic-yaml-patch.ts +423 -0
  193. package/src/config/model-profile-activation.ts +240 -89
  194. package/src/config/model-profiles.ts +18 -15
  195. package/src/config/model-registry.ts +51 -26
  196. package/src/config/model-resolver.ts +138 -51
  197. package/src/config/model-selector-value.ts +50 -0
  198. package/src/config/models-config-schema.ts +14 -21
  199. package/src/config/settings-schema.ts +128 -10
  200. package/src/config/settings.ts +1120 -158
  201. package/src/coordinator-mcp/model-preset.ts +74 -20
  202. package/src/coordinator-mcp/server.ts +1597 -3052
  203. package/src/daemon/builtin.ts +8 -5
  204. package/src/daemon/control-types.ts +1 -1
  205. package/src/defaults/gjc/skills/team/SKILL.md +4 -4
  206. package/src/discovery/mcp-json.ts +327 -20
  207. package/src/extensibility/custom-tools/types.ts +1 -1
  208. package/src/extensibility/extensions/compact-handler.ts +3 -3
  209. package/src/extensibility/extensions/get-commands-handler.ts +2 -2
  210. package/src/extensibility/extensions/loader.ts +69 -5
  211. package/src/extensibility/extensions/runner.ts +112 -4
  212. package/src/extensibility/extensions/types.ts +176 -17
  213. package/src/extensibility/hooks/types.ts +1 -1
  214. package/src/gjc-runtime/launch-tmux.ts +170 -86
  215. package/src/gjc-runtime/psmux-detect.ts +82 -4
  216. package/src/gjc-runtime/session-state-sidecar.ts +41 -31
  217. package/src/gjc-runtime/team-runtime.ts +54 -35
  218. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
  219. package/src/gjc-runtime/tmux-owner-isolation.ts +1 -1
  220. package/src/gjc-runtime/tmux-sessions.ts +19 -13
  221. package/src/gjc-runtime/ultragoal-guard.ts +53 -6
  222. package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
  223. package/src/gjc-runtime/windows-powershell-command.ts +58 -0
  224. package/src/harness-control-plane/operate.ts +9 -9
  225. package/src/harness-control-plane/owner.ts +283 -39
  226. package/src/harness-control-plane/receipts.ts +0 -1
  227. package/src/harness-control-plane/sdk-transport.ts +395 -0
  228. package/src/harness-control-plane/session-transport.ts +94 -0
  229. package/src/harness-control-plane/types.ts +1 -1
  230. package/src/internal-urls/docs-index.generated.ts +34 -35
  231. package/src/lsp/client.ts +42 -6
  232. package/src/lsp/index.ts +2 -2
  233. package/src/main.ts +299 -204
  234. package/src/modes/DESIGN.md +258 -0
  235. package/src/modes/acp/acp-agent.ts +1228 -2612
  236. package/src/modes/acp/acp-client-bridge.ts +2 -20
  237. package/src/modes/acp/acp-event-mapper.ts +18 -2
  238. package/src/modes/acp/acp-mode.ts +8 -36
  239. package/src/modes/acp/permission-mode.ts +25 -0
  240. package/src/modes/acp/startup-options.ts +6 -0
  241. package/src/modes/components/agent-dashboard.ts +37 -17
  242. package/src/modes/components/model-selector.ts +93 -35
  243. package/src/modes/components/notifications-settings-editor.ts +1379 -0
  244. package/src/modes/components/settings-selector.ts +60 -11
  245. package/src/modes/components/welcome.ts +4 -4
  246. package/src/modes/controllers/command-controller.ts +1 -2
  247. package/src/modes/controllers/event-controller.ts +11 -16
  248. package/src/modes/controllers/extension-ui-controller.ts +348 -4
  249. package/src/modes/controllers/selector-controller.ts +674 -36
  250. package/src/modes/index.ts +0 -22
  251. package/src/modes/interactive-mode.ts +59 -20
  252. package/src/modes/runtime-init.ts +298 -6
  253. package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
  254. package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
  255. package/src/modes/shared/agent-wire/event-contract.ts +7 -8
  256. package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
  257. package/src/modes/shared/agent-wire/event-observation.ts +16 -7
  258. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1254 -87
  259. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
  260. package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
  261. package/src/modes/types.ts +5 -0
  262. package/src/runtime-mcp/client.ts +94 -19
  263. package/src/runtime-mcp/config.ts +27 -15
  264. package/src/runtime-mcp/manager.ts +343 -105
  265. package/src/runtime-mcp/oauth-flow.ts +42 -12
  266. package/src/runtime-mcp/transports/http.ts +49 -19
  267. package/src/runtime-mcp/transports/stdio.ts +47 -28
  268. package/src/runtime-mcp/types.ts +10 -0
  269. package/src/sdk/acp/adapter.ts +418 -0
  270. package/src/sdk/acp/index.ts +2 -0
  271. package/src/sdk/broker/broker.ts +642 -0
  272. package/src/sdk/broker/discovery.ts +94 -0
  273. package/src/sdk/broker/ensure.ts +249 -0
  274. package/src/sdk/broker/identity.ts +42 -0
  275. package/src/sdk/broker/index.ts +8 -0
  276. package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
  277. package/src/sdk/broker/internal-source.bunfig.toml +1 -0
  278. package/src/sdk/broker/lifecycle-ledger.ts +286 -0
  279. package/src/sdk/broker/lifecycle.ts +2157 -0
  280. package/src/sdk/broker/process-incarnation.ts +159 -0
  281. package/src/sdk/broker/runtime.ts +164 -0
  282. package/src/sdk/broker/session-index.ts +318 -0
  283. package/src/sdk/broker/state-version.ts +23 -0
  284. package/src/sdk/broker/transport.ts +125 -0
  285. package/src/sdk/bus/chat-command-policy.ts +107 -0
  286. package/src/sdk/bus/chat-daemon-cli.ts +214 -0
  287. package/src/sdk/bus/chat-daemon-control.ts +713 -0
  288. package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
  289. package/src/sdk/bus/chat-effect-journal.ts +353 -0
  290. package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
  291. package/src/sdk/bus/config.ts +433 -0
  292. package/src/sdk/bus/conversation-store.ts +391 -0
  293. package/src/sdk/bus/discord-conversation.ts +85 -0
  294. package/src/sdk/bus/discord-daemon.ts +2275 -0
  295. package/src/sdk/bus/discord-live-provider.ts +521 -0
  296. package/src/sdk/bus/discord-provider.ts +56 -0
  297. package/src/{notifications → sdk/bus}/html-format.ts +2 -2
  298. package/src/sdk/bus/index.ts +3943 -0
  299. package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
  300. package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
  301. package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
  302. package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
  303. package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
  304. package/src/sdk/bus/natives-augment.d.ts +38 -0
  305. package/src/sdk/bus/notification-orchestration.ts +535 -0
  306. package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
  307. package/src/sdk/bus/session-control.ts +333 -0
  308. package/src/sdk/bus/slack-conversation.ts +74 -0
  309. package/src/sdk/bus/slack-daemon.ts +2144 -0
  310. package/src/sdk/bus/slack-live-provider.ts +380 -0
  311. package/src/sdk/bus/slack-provider.ts +76 -0
  312. package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
  313. package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
  314. package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
  315. package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
  316. package/src/{notifications → sdk/bus}/telegram-daemon.ts +502 -54
  317. package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
  318. package/src/sdk/bus/telegram-setup.ts +663 -0
  319. package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
  320. package/src/sdk/cli/index.ts +1 -0
  321. package/src/sdk/cli/session-cli.ts +275 -0
  322. package/src/sdk/client/client.ts +1 -0
  323. package/src/sdk/client/discovery.ts +108 -0
  324. package/src/sdk/client/index.ts +2 -0
  325. package/src/sdk/host/control/dispatch.ts +367 -0
  326. package/src/sdk/host/control/index.ts +10 -0
  327. package/src/sdk/host/control/operations.ts +63 -0
  328. package/src/sdk/host/events.ts +91 -0
  329. package/src/sdk/host/host.ts +296 -0
  330. package/src/sdk/host/index.ts +4 -0
  331. package/src/sdk/host/query/cursor.ts +189 -0
  332. package/src/sdk/host/query/handlers.ts +533 -0
  333. package/src/sdk/host/query/index.ts +3 -0
  334. package/src/sdk/host/query/revision-store.ts +1126 -0
  335. package/src/sdk/host/reverse-leases.ts +325 -0
  336. package/src/sdk/host/types.ts +29 -0
  337. package/src/sdk/index.ts +13 -0
  338. package/src/sdk/lifecycle-session.ts +39 -0
  339. package/src/sdk/mcp/index.ts +1 -0
  340. package/src/sdk/mcp/server.ts +332 -0
  341. package/src/sdk/models.ts +168 -0
  342. package/src/sdk/protocol/adapter-validation.ts +48 -0
  343. package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
  344. package/src/sdk/protocol/operation-registry.ts +312 -0
  345. package/src/{sdk.ts → sdk/session.ts} +339 -212
  346. package/src/sdk/startup-capability.ts +189 -0
  347. package/src/session/agent-session.ts +2453 -894
  348. package/src/session/default-model-selection.ts +93 -0
  349. package/src/session/fallback-chain-controller.ts +136 -0
  350. package/src/session/session-manager.ts +438 -11
  351. package/src/session/session-storage.ts +8 -1
  352. package/src/setup/credential-auto-import.ts +290 -35
  353. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
  354. package/src/slash-commands/builtin-registry.ts +2 -1
  355. package/src/task/executor.ts +62 -13
  356. package/src/tools/ask-answer-registry.ts +1 -1
  357. package/src/tools/ask.ts +13 -8
  358. package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
  359. package/src/tools/browser/benchmark/detector-report.ts +157 -0
  360. package/src/tools/browser/benchmark/run-suite.ts +39 -0
  361. package/src/tools/browser/launch.ts +124 -19
  362. package/src/tools/browser/profile-discovery.ts +63 -0
  363. package/src/tools/browser/profile-posture.ts +59 -0
  364. package/src/tools/browser/profile-reuse.ts +102 -0
  365. package/src/tools/browser/profile-warmup.ts +109 -0
  366. package/src/tools/browser/registry.ts +87 -11
  367. package/src/tools/browser/tab-protocol.ts +1 -0
  368. package/src/tools/browser/tab-supervisor.ts +1 -0
  369. package/src/tools/browser/tab-worker.ts +1 -1
  370. package/src/tools/browser.ts +6 -0
  371. package/src/tools/index.ts +8 -8
  372. package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
  373. package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
  374. package/src/tools/telegram-send.ts +2 -2
  375. package/vendor/insane-search/MANIFEST.json +2 -1
  376. package/vendor/insane-search/engine/bias_check.py +4 -1
  377. package/vendor/insane-search/engine/phase0.py +26 -1
  378. package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
  379. package/dist/types/modes/bridge/auth.d.ts +0 -12
  380. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
  381. package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
  382. package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
  383. package/dist/types/modes/bridge/event-stream.d.ts +0 -8
  384. package/dist/types/modes/rpc/host-tools.d.ts +0 -1
  385. package/dist/types/modes/rpc/host-uris.d.ts +0 -1
  386. package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
  387. package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
  388. package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
  389. package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
  390. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
  391. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
  392. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
  393. package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
  394. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
  395. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
  396. package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
  397. package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
  398. package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
  399. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
  400. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
  401. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
  402. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
  403. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
  404. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
  405. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
  406. package/dist/types/notifications/config.d.ts +0 -132
  407. package/src/harness-control-plane/rpc-adapter.ts +0 -290
  408. package/src/modes/bridge/auth.ts +0 -41
  409. package/src/modes/bridge/bridge-client-bridge.ts +0 -47
  410. package/src/modes/bridge/bridge-mode.ts +0 -675
  411. package/src/modes/bridge/bridge-ui-context.ts +0 -200
  412. package/src/modes/bridge/event-stream.ts +0 -70
  413. package/src/modes/rpc/host-tools.ts +0 -1
  414. package/src/modes/rpc/host-uris.ts +0 -1
  415. package/src/modes/rpc/rpc-client.ts +0 -1166
  416. package/src/modes/rpc/rpc-mode.ts +0 -1029
  417. package/src/modes/rpc/rpc-socket-security.ts +0 -115
  418. package/src/modes/rpc/rpc-types.ts +0 -637
  419. package/src/modes/shared/agent-wire/command-contract.ts +0 -18
  420. package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
  421. package/src/modes/shared/agent-wire/command-validation.ts +0 -181
  422. package/src/modes/shared/agent-wire/handshake.ts +0 -157
  423. package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
  424. package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
  425. package/src/modes/shared/agent-wire/protocol.ts +0 -46
  426. package/src/modes/shared/agent-wire/responses.ts +0 -17
  427. package/src/modes/shared/agent-wire/scopes.ts +0 -94
  428. package/src/modes/shared/agent-wire/session-registry.ts +0 -109
  429. package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
  430. package/src/modes/shared/agent-wire/ui-result.ts +0 -48
  431. package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
  432. package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
  433. package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
  434. package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
  435. package/src/notifications/config.ts +0 -219
  436. package/src/notifications/index.ts +0 -1835
  437. package/src/notifications/telegram-daemon-cli.ts +0 -243
  438. package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
  439. /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
  440. /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
  441. /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
  442. /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
  443. /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
  444. /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
  445. /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
  446. /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
  447. /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
  448. /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
  449. /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
  450. /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
  451. /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
  452. /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
  453. /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
  454. /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
  455. /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
  456. /package/src/{notifications → sdk/bus}/engine.ts +0 -0
  457. /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
  458. /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
  459. /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
  460. /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
  461. /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
  462. /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
  463. /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
  464. /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
  465. /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
@@ -19,7 +19,7 @@ import {
19
19
  type VanishEvidence,
20
20
  validateReceipt,
21
21
  } from "./receipts";
22
- import { type HarnessRpc, singleFlightAccept } from "./rpc-adapter";
22
+ import { type HarnessSessionTransport, singleFlightAccept } from "./session-transport";
23
23
  import { writeReceiptImmutable } from "./storage";
24
24
  import {
25
25
  DEFAULT_RETRY_BUDGET,
@@ -35,10 +35,10 @@ export interface OperateOptions {
35
35
  sessionId: string;
36
36
  workspace: string;
37
37
  branch: string;
38
- rpc: HarnessRpc;
39
- /** Factory used to (re)create the RPC subprocess on restart recovery. Defaults to reusing `rpc`. */
40
- rpcFactory?: () => HarnessRpc;
41
- /** Bounded observation provider (scripted in tests; real = git + rpc state). */
38
+ transport: HarnessSessionTransport;
39
+ /** Factory used to recreate an SDK transport on restart recovery. Defaults to reusing `transport`. */
40
+ transportFactory?: () => HarnessSessionTransport;
41
+ /** Bounded observation provider (scripted in tests; real = git + SDK session state). */
42
42
  observe: () => Promise<Observation>;
43
43
  /** Real dirty-worktree preservation; injectable for tests. Defaults to git stash/diff capture. */
44
44
  preserve?: (workspace: string) => PreserveResult;
@@ -71,7 +71,7 @@ export async function operate(goal: string, opts: OperateOptions): Promise<Opera
71
71
  const vanishReceiptIds: string[] = [];
72
72
  const blockers: string[] = [];
73
73
 
74
- let rpc = opts.rpc;
74
+ let transport = opts.transport;
75
75
 
76
76
  const now = (): string => new Date(opts.clock ? opts.clock() : Date.now()).toISOString();
77
77
  let lifecycle: HarnessLifecycle = "started";
@@ -118,7 +118,7 @@ export async function operate(goal: string, opts: OperateOptions): Promise<Opera
118
118
  };
119
119
 
120
120
  const submit = async (): Promise<boolean> => {
121
- const acc = await singleFlightAccept(rpc, goal, acceptanceTimeoutMs);
121
+ const acc = await singleFlightAccept(transport, goal, acceptanceTimeoutMs);
122
122
  await emit(acc.accepted ? "info" : "warn", acc.accepted ? "prompt_accepted" : "prompt_not_accepted", {
123
123
  reason: acc.reason,
124
124
  });
@@ -160,11 +160,11 @@ export async function operate(goal: string, opts: OperateOptions): Promise<Opera
160
160
  accepted = await submit();
161
161
  } else if (decision.classification === "restart-clean") {
162
162
  budget.zeroDeltaVanish = Math.max(0, budget.zeroDeltaVanish - 1);
163
- rpc = opts.rpcFactory ? opts.rpcFactory() : rpc;
163
+ transport = opts.transportFactory ? opts.transportFactory() : transport;
164
164
  accepted = await submit();
165
165
  } else if (decision.classification === "restart-preserve-delta") {
166
166
  budget.dirtyVanishPreserve = Math.max(0, budget.dirtyVanishPreserve - 1);
167
- rpc = opts.rpcFactory ? opts.rpcFactory() : rpc;
167
+ transport = opts.transportFactory ? opts.transportFactory() : transport;
168
168
  accepted = await submit();
169
169
  } else if (decision.classification === "fallback-codex-exec") {
170
170
  lifecycle = "blocked";
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Responsibilities:
5
5
  * - hold the {@link SessionLease} (single writer),
6
- * - own the {@link HarnessRpc} subprocess (injected; real `GajaeCodeRpc` in prod, fake in tests),
6
+ * - own an injected SDK session transport,
7
7
  * - serve owner-routed primitives over the {@link ControlServer} endpoint,
8
8
  * - be the SOLE writer of the severity event stream,
9
9
  * - heartbeat the lease.
@@ -15,9 +15,9 @@ import { execFileSync } from "node:child_process";
15
15
  import { randomBytes, randomUUID } from "node:crypto";
16
16
  import { existsSync } from "node:fs";
17
17
  import type { AgentWireOwnerObservation } from "../modes/shared/agent-wire/event-contract";
18
- import { observeRpcOutboundFrame } from "../modes/shared/agent-wire/event-observation";
18
+ import { observeAgentWireFrame } from "../modes/shared/agent-wire/event-observation";
19
19
  import { classifyRecovery } from "./classifier";
20
- import { ControlServer, type EndpointRequest } from "./control-endpoint";
20
+ import { ControlServer, type EndpointHandler, type EndpointRequest } from "./control-endpoint";
21
21
  import { defaultFinalizeChecks, type FinalizeChecks, runFinalize, type ValidationCommandSpec } from "./finalize";
22
22
  import { type OperateResult, operate } from "./operate";
23
23
  import { preserveDirtyWorktree } from "./preserve";
@@ -30,16 +30,22 @@ import {
30
30
  type VanishEvidence,
31
31
  validateReceipt,
32
32
  } from "./receipts";
33
- import { type HarnessRpc, type RpcStateSnapshot, singleFlightAccept } from "./rpc-adapter";
34
33
  import {
35
34
  acquireLease,
36
35
  canWriteEvents,
37
36
  classifyLeaseStatus,
38
37
  heartbeat,
38
+ LeaseError,
39
39
  readLease,
40
40
  releaseLease,
41
41
  type SessionLease,
42
42
  } from "./session-lease";
43
+ import {
44
+ type HarnessSessionTransport,
45
+ type HarnessSessionTransportCloseContext,
46
+ type SessionStateSnapshot,
47
+ singleFlightAccept,
48
+ } from "./session-transport";
43
49
  import { buildStateView, nextAllowedActions, submitUnavailableReason } from "./state-machine";
44
50
  import {
45
51
  appendEvent,
@@ -78,10 +84,26 @@ function reconcileLiveOwnerState(state: SessionState): { state: SessionState; re
78
84
  };
79
85
  }
80
86
 
87
+ function flattenAggregateCauses(errors: readonly unknown[]): unknown[] {
88
+ const causes: unknown[] = [];
89
+ for (const error of errors) {
90
+ if (error instanceof AggregateError) causes.push(...flattenAggregateCauses(error.errors));
91
+ else causes.push(error);
92
+ }
93
+ return causes;
94
+ }
95
+
96
+ /**
97
+ * Nominal sentinel: raised only after #stopOnce has verified teardown so the
98
+ * retry loop can rethrow it immediately. A private class prevents a lookalike
99
+ * cleanup AggregateError (message collision) from bypassing verification retries.
100
+ */
101
+ class FramePumpAfterVerifiedCleanupError extends AggregateError {}
102
+
81
103
  export interface OwnerOptions {
82
104
  root: string;
83
105
  sessionId: string;
84
- rpc: HarnessRpc;
106
+ transport: HarnessSessionTransport;
85
107
  ownerId?: string;
86
108
  ttlMs?: number;
87
109
  heartbeatMs?: number;
@@ -89,6 +111,18 @@ export interface OwnerOptions {
89
111
  clock?: () => number;
90
112
  finalizeChecks?: FinalizeChecks;
91
113
  validationCommands?: ValidationCommandSpec[];
114
+ /** Test seam for deterministic control-endpoint teardown failures. */
115
+ controlServerFactory?: (socketPath: string, handler: EndpointHandler) => ControlServer;
116
+ /** Test seam for deterministic lease-release teardown failures. */
117
+ leaseRelease?: typeof releaseLease;
118
+ /** Test seams for frame persistence failures. */
119
+ framePersistence?: {
120
+ appendEvent?: typeof appendEvent;
121
+ writeSessionState?: typeof writeSessionState;
122
+ };
123
+ /** Test seams; production retries verified shutdown without a finite limit. */
124
+ cleanupRetryMs?: number;
125
+ cleanupRetryLimit?: number;
92
126
  }
93
127
 
94
128
  export interface OwnerStartInfo {
@@ -100,20 +134,35 @@ export interface OwnerStartInfo {
100
134
  const DEFAULT_TTL_MS = 30_000;
101
135
  const DEFAULT_HEARTBEAT_MS = 10_000;
102
136
  const DEFAULT_ACCEPT_TIMEOUT_MS = 60_000;
137
+ const DEFAULT_CLEANUP_RETRY_MS = 500;
138
+ const MAX_RETAINED_CLEANUP_FAILURES = 32;
103
139
 
104
140
  export class RuntimeOwner {
105
141
  readonly ownerId: string;
106
- #opts: Required<Omit<OwnerOptions, "clock" | "finalizeChecks" | "validationCommands">> & { clock?: () => number };
142
+ #opts: Required<
143
+ Omit<
144
+ OwnerOptions,
145
+ "clock" | "finalizeChecks" | "validationCommands" | "controlServerFactory" | "framePersistence"
146
+ >
147
+ > & { clock?: () => number };
107
148
  #server: ControlServer;
108
149
  #cursor = 0;
109
150
  #leaseEpoch = 0;
151
+ #leaseHeld = false;
110
152
  #heartbeatTimer: NodeJS.Timeout | null = null;
111
153
  #socketPath: string;
112
154
  #finalizeChecks?: FinalizeChecks;
113
155
  #validationCommands?: ValidationCommandSpec[];
114
156
  #unsubscribeFrames: (() => void) | null = null;
115
157
  #framePump: Promise<void> = Promise.resolve();
158
+ #framePumpFailure: unknown = null;
116
159
  #coalesced = new Map<string, true>();
160
+ #stopPromise: Promise<void> | null = null;
161
+ #lastStopFailures: unknown[] = [];
162
+ #reportedStopFailures = new Set<string>();
163
+ #transportClosed = false;
164
+ #serverClosed = false;
165
+ #framePersistence: Required<NonNullable<OwnerOptions["framePersistence"]>>;
117
166
 
118
167
  constructor(opts: OwnerOptions) {
119
168
  this.ownerId = opts.ownerId ?? `owner-${randomUUID()}`;
@@ -121,19 +170,51 @@ export class RuntimeOwner {
121
170
  this.#opts = {
122
171
  root: opts.root,
123
172
  sessionId: opts.sessionId,
124
- rpc: opts.rpc,
173
+ transport: opts.transport,
125
174
  ownerId: this.ownerId,
126
175
  ttlMs: opts.ttlMs ?? DEFAULT_TTL_MS,
127
176
  heartbeatMs: opts.heartbeatMs ?? DEFAULT_HEARTBEAT_MS,
128
177
  acceptanceTimeoutMs: opts.acceptanceTimeoutMs ?? DEFAULT_ACCEPT_TIMEOUT_MS,
129
178
  clock: opts.clock,
179
+ cleanupRetryMs: opts.cleanupRetryMs ?? DEFAULT_CLEANUP_RETRY_MS,
180
+ cleanupRetryLimit: opts.cleanupRetryLimit ?? Number.POSITIVE_INFINITY,
181
+ leaseRelease: opts.leaseRelease ?? releaseLease,
130
182
  };
131
183
  this.#finalizeChecks = opts.finalizeChecks;
132
184
  this.#validationCommands = opts.validationCommands;
133
- this.#server = new ControlServer(this.#socketPath, req => this.#handle(req));
185
+ this.#framePersistence = {
186
+ appendEvent: opts.framePersistence?.appendEvent ?? appendEvent,
187
+ writeSessionState: opts.framePersistence?.writeSessionState ?? writeSessionState,
188
+ };
189
+ this.#server = (opts.controlServerFactory ?? ((socketPath, handler) => new ControlServer(socketPath, handler)))(
190
+ this.#socketPath,
191
+ req => this.#handle(req),
192
+ );
134
193
  }
135
194
 
136
195
  async start(): Promise<OwnerStartInfo> {
196
+ try {
197
+ return await this.#startOnce();
198
+ } catch (startError) {
199
+ try {
200
+ await this.stop();
201
+ } catch (cleanupError) {
202
+ const cleanupCauses = flattenAggregateCauses([cleanupError]);
203
+ throw new AggregateError(
204
+ [startError, ...cleanupCauses],
205
+ "Runtime owner startup and exact-child rollback failed.",
206
+ );
207
+ }
208
+ if (this.#lastStopFailures.length > 0)
209
+ throw new AggregateError(
210
+ [startError, ...flattenAggregateCauses(this.#lastStopFailures)],
211
+ "Runtime owner startup failed after retrying exact-child rollback.",
212
+ );
213
+ throw startError;
214
+ }
215
+ }
216
+
217
+ async #startOnce(): Promise<OwnerStartInfo> {
137
218
  const { root, sessionId } = this.#opts;
138
219
  const eventsPath = sessionPaths(root, sessionId).events;
139
220
  const existing = await readEvents(root, sessionId, 0);
@@ -146,19 +227,20 @@ export class RuntimeOwner {
146
227
  ttlMs: this.#opts.ttlMs,
147
228
  clock: this.#opts.clock,
148
229
  });
230
+ this.#leaseHeld = true;
149
231
  this.#leaseEpoch = lease.leaseEpoch;
150
- await this.#server.listen();
151
- await this.#emit("info", "owner_started", { ownerId: this.ownerId, leaseEpoch: this.#leaseEpoch });
152
- if (this.#opts.rpc.onEventFrame) {
153
- this.#unsubscribeFrames = this.#opts.rpc.onEventFrame(frame => this.#handleFrame(frame));
154
- }
155
232
  this.#heartbeatTimer = setInterval(() => {
156
233
  void heartbeat(root, sessionId, this.ownerId, this.#opts.ttlMs, this.#opts.clock).catch(err => {
157
234
  // Self-stop if a legitimate dead-owner takeover revoked our lease.
158
- if (err instanceof Error && err.message.includes("not_lease_holder")) void this.stop();
235
+ if (err instanceof Error && err.message.includes("not_lease_holder")) void this.stop().catch(() => {});
159
236
  });
160
237
  }, this.#opts.heartbeatMs);
161
238
  this.#heartbeatTimer.unref?.();
239
+ await this.#server.listen();
240
+ await this.#emit("info", "owner_started", { ownerId: this.ownerId, leaseEpoch: this.#leaseEpoch });
241
+ if (this.#opts.transport.onEventFrame) {
242
+ this.#unsubscribeFrames = this.#opts.transport.onEventFrame(frame => this.#handleFrame(frame));
243
+ }
162
244
  return { ownerId: this.ownerId, socketPath: this.#socketPath, leaseEpoch: this.#leaseEpoch };
163
245
  }
164
246
 
@@ -175,13 +257,18 @@ export class RuntimeOwner {
175
257
 
176
258
  /** Map an RPC frame and route it: semantic/signal-bearing -> serial emit; high-frequency progress -> coalesce. */
177
259
  #handleFrame(frame: Record<string, unknown>): void {
178
- const mapped = observeRpcOutboundFrame(frame);
260
+ const mapped = observeAgentWireFrame(frame);
179
261
  if (!mapped) return;
180
262
  if (mapped.semantic || (mapped.signal && !mapped.coalesceKey)) {
181
263
  this.#framePump = this.#framePump
182
- .then(() => this.#flushCoalesced())
183
- .then(() => this.#emitMapped(mapped))
184
- .catch(() => {});
264
+ .then(async () => {
265
+ if (this.#framePumpFailure !== null) return;
266
+ await this.#flushCoalesced();
267
+ await this.#emitMapped(mapped);
268
+ })
269
+ .catch(error => {
270
+ if (this.#framePumpFailure === null) this.#framePumpFailure = error;
271
+ });
185
272
  } else if (mapped.coalesceKey) {
186
273
  // Coalesce progress-noise by key; never enqueues a per-frame emit, so a message_update
187
274
  // storm cannot starve semantic frames. Bound memory.
@@ -197,7 +284,7 @@ export class RuntimeOwner {
197
284
  if (this.#coalesced.size === 0) return;
198
285
  const coalescedFrames = this.#coalesced.size;
199
286
  this.#coalesced.clear();
200
- await this.#emit("info", "rpc_activity", { coalescedFrames });
287
+ await this.#emit("info", "rpc_activity", { coalescedFrames }, true);
201
288
  }
202
289
 
203
290
  async #emitMapped(mapped: AgentWireOwnerObservation): Promise<void> {
@@ -211,13 +298,14 @@ export class RuntimeOwner {
211
298
  ) {
212
299
  state.lifecycle = "finalizing";
213
300
  state.updatedAt = new Date(this.#opts.clock ? this.#opts.clock() : Date.now()).toISOString();
214
- await writeSessionState(this.#opts.root, state);
301
+ await this.#framePersistence.writeSessionState(this.#opts.root, state);
215
302
  }
216
303
  }
217
304
  await this.#emit(
218
305
  mapped.severity,
219
306
  mapped.kind,
220
307
  mapped.signal ? { ...mapped.evidence, signal: mapped.signal } : mapped.evidence,
308
+ true,
221
309
  );
222
310
  }
223
311
 
@@ -248,7 +336,12 @@ export class RuntimeOwner {
248
336
  return rpcActive ? "rpc-not-idle" : null;
249
337
  }
250
338
 
251
- async #emit(severity: Severity, kind: string, evidence: Record<string, unknown>): Promise<void> {
339
+ async #emit(
340
+ severity: Severity,
341
+ kind: string,
342
+ evidence: Record<string, unknown>,
343
+ framePersistence = false,
344
+ ): Promise<void> {
252
345
  const lease = await readLease(this.#opts.root, this.#opts.sessionId);
253
346
  // Single-writer guard: only emit while we still hold a live lease.
254
347
  if (!lease || !canWriteEvents(lease, this.ownerId, this.#opts.clock)) return;
@@ -274,7 +367,11 @@ export class RuntimeOwner {
274
367
  nextAllowedActions: nextAllowedActions(view.lifecycle, true, { submitUnavailableReason: submitGateReason }),
275
368
  writer: { ownerId: this.ownerId, leaseEpoch: this.#leaseEpoch },
276
369
  };
277
- await appendEvent(this.#opts.root, this.#opts.sessionId, envelope);
370
+ await (framePersistence ? this.#framePersistence.appendEvent : appendEvent)(
371
+ this.#opts.root,
372
+ this.#opts.sessionId,
373
+ envelope,
374
+ );
278
375
  }
279
376
 
280
377
  #response(
@@ -291,7 +388,7 @@ export class RuntimeOwner {
291
388
  };
292
389
  }
293
390
 
294
- #submitGateReason(state: SessionState, rpcState: RpcStateSnapshot | null): string | null {
391
+ #submitGateReason(state: SessionState, rpcState: SessionStateSnapshot | null): string | null {
295
392
  const rpcReason = rpcState
296
393
  ? rpcState.isStreaming || rpcState.steeringQueueDepth > 0 || rpcState.followupQueueDepth > 0
297
394
  ? "rpc-not-idle"
@@ -333,9 +430,9 @@ export class RuntimeOwner {
333
430
  const state = await this.#loadState();
334
431
  const workspace = state.handle.workspace;
335
432
  let streaming = false;
336
- let rpcState: RpcStateSnapshot | null = null;
433
+ let rpcState: SessionStateSnapshot | null = null;
337
434
  try {
338
- rpcState = await this.#opts.rpc.getState();
435
+ rpcState = await this.#opts.transport.getState();
339
436
  streaming = rpcState.isStreaming;
340
437
  } catch {
341
438
  streaming = false;
@@ -366,8 +463,8 @@ export class RuntimeOwner {
366
463
  gitDelta = "unknown";
367
464
  }
368
465
  }
369
- const rpcLive = this.#opts.rpc.isLive ? this.#opts.rpc.isLive() : rpcState !== null;
370
- const rpcLastFrameAt = this.#opts.rpc.lastFrameAt ? this.#opts.rpc.lastFrameAt() : null;
466
+ const rpcLive = this.#opts.transport.isLive ? this.#opts.transport.isLive() : rpcState !== null;
467
+ const rpcLastFrameAt = this.#opts.transport.lastFrameAt ? this.#opts.transport.lastFrameAt() : null;
371
468
  // Sticky semantic signals come from the persisted owner event log -> survive polling gaps.
372
469
  const recent = (await readEvents(this.#opts.root, this.#opts.sessionId, 0)).slice(-200);
373
470
  const observedSignals = this.#aggregateSignals(recent).slice(0, 7);
@@ -519,7 +616,7 @@ export class RuntimeOwner {
519
616
  sessionId: this.#opts.sessionId,
520
617
  workspace: state.handle.workspace,
521
618
  branch: state.handle.branch ?? "",
522
- rpc: this.#opts.rpc,
619
+ transport: this.#opts.transport,
523
620
  observe: () => this.#observeGit(),
524
621
  finalizeChecks: this.#finalizeChecks ?? defaultFinalizeChecks(state.handle.workspace),
525
622
  validationCommands: this.#validationCommands,
@@ -544,8 +641,8 @@ export class RuntimeOwner {
544
641
  // Review-only finalize with no explicit verdict pulls the final assistant text from the live
545
642
  // RPC owner so the verdict can be extracted deterministically instead of demanded from the operator.
546
643
  let assistantText: string | null = null;
547
- if (reviewOnly && inputVerdict == null && this.#opts.rpc.getLastAssistantText) {
548
- assistantText = await this.#opts.rpc.getLastAssistantText().catch(() => null);
644
+ if (reviewOnly && inputVerdict == null && this.#opts.transport.getLastAssistantText) {
645
+ assistantText = await this.#opts.transport.getLastAssistantText().catch(() => null);
549
646
  }
550
647
  const fin = await runFinalize({
551
648
  root: this.#opts.root,
@@ -595,7 +692,7 @@ export class RuntimeOwner {
595
692
  lifecycleGate,
596
693
  );
597
694
  }
598
- const result = await singleFlightAccept(this.#opts.rpc, prompt, this.#opts.acceptanceTimeoutMs);
695
+ const result = await singleFlightAccept(this.#opts.transport, prompt, this.#opts.acceptanceTimeoutMs);
599
696
  if (result.accepted) {
600
697
  state.lifecycle = "observing";
601
698
  state.updatedAt = new Date(this.#opts.clock ? this.#opts.clock() : Date.now()).toISOString();
@@ -625,7 +722,31 @@ export class RuntimeOwner {
625
722
  }
626
723
 
627
724
  async #observe(): Promise<PrimitiveResponse> {
725
+ // Observation is a read barrier over every frame accepted before this request.
726
+ // Without it, a fast poll can read state/event storage while the serial frame
727
+ // pump is still persisting a terminal event, losing sticky completion evidence.
728
+ await this.#framePump;
628
729
  const state = await this.#loadState();
730
+ if (this.#framePumpFailure !== null) {
731
+ const failedState: SessionState = {
732
+ ...state,
733
+ lifecycle: "blocked",
734
+ blockers: [...new Set([...state.blockers, "frame-persistence-failed"])],
735
+ };
736
+ return this.#response(
737
+ failedState,
738
+ {
739
+ observation: {
740
+ lifecycle: "blocked",
741
+ observedSignals: ["frame-persistence-failed"],
742
+ rpcLive: this.#opts.transport.isLive?.() ?? true,
743
+ },
744
+ framePumpFailure: { severity: "critical", error: String(this.#framePumpFailure) },
745
+ ownerRouted: true,
746
+ },
747
+ false,
748
+ );
749
+ }
629
750
  const observation = await this.#observeGit();
630
751
  const submitGateReason =
631
752
  typeof observation.submitUnavailableReason === "string" ? observation.submitUnavailableReason : null;
@@ -638,21 +759,144 @@ export class RuntimeOwner {
638
759
  state.updatedAt = new Date(this.#opts.clock ? this.#opts.clock() : Date.now()).toISOString();
639
760
  await writeSessionState(this.#opts.root, state);
640
761
  await this.#emit("info", "owner_retired", {});
641
- queueMicrotask(() => void this.stop());
762
+ queueMicrotask(() => void this.stop().catch(() => {}));
642
763
  return this.#response(state, { retired: true });
643
764
  }
644
765
 
645
- async stop(): Promise<void> {
646
- this.#unsubscribeFrames?.();
647
- this.#unsubscribeFrames = null;
648
- await this.#framePump.catch(() => {});
766
+ stop(): Promise<void> {
767
+ // Every public caller receives the one truthful shared teardown result. Only
768
+ // the object capability passed to the exact transport.close() invocation can
769
+ // break a direct cleanup cycle; ambient synchronous callers have no bypass.
770
+ if (this.#stopPromise) return this.#stopPromise;
771
+ const pending = Promise.withResolvers<void>();
772
+ this.#stopPromise = pending.promise;
773
+ void this.#stopUntilVerified().then(pending.resolve, pending.reject);
774
+ return pending.promise;
775
+ }
776
+
777
+ #closeTransport(): Promise<void> {
778
+ let available = true;
779
+ // `available` is the authority boundary; freezing the wrapper is only
780
+ // defense-in-depth against mutation by the receiving transport.
781
+ const context: HarnessSessionTransportCloseContext = Object.freeze({
782
+ acknowledgeDirectOwnerStopReentry(): Promise<void> {
783
+ if (!available) throw new Error("Runtime owner direct stop reentry capability is no longer available.");
784
+ available = false;
785
+ return Promise.resolve();
786
+ },
787
+ });
788
+ try {
789
+ return this.#opts.transport.close(context);
790
+ } finally {
791
+ // An async close implementation runs synchronously until it returns its
792
+ // promise. Expire the capability at that boundary so descendants cannot
793
+ // acquire completion authority after the direct invocation.
794
+ available = false;
795
+ }
796
+ }
797
+
798
+ async #stopUntilVerified(): Promise<void> {
799
+ this.#lastStopFailures = [];
800
+ this.#reportedStopFailures.clear();
801
+ for (let attempt = 1; ; attempt++) {
802
+ try {
803
+ await this.#stopOnce();
804
+ if (this.#framePumpFailure !== null) {
805
+ throw new FramePumpAfterVerifiedCleanupError(
806
+ [this.#framePumpFailure, ...flattenAggregateCauses(this.#lastStopFailures)],
807
+ `Runtime owner frame pump failed after verified cleanup: ${String(this.#framePumpFailure)}`,
808
+ );
809
+ }
810
+ return;
811
+ } catch (error) {
812
+ if (error instanceof FramePumpAfterVerifiedCleanupError) throw error;
813
+ if (this.#lastStopFailures.length === MAX_RETAINED_CLEANUP_FAILURES) this.#lastStopFailures.shift();
814
+ this.#lastStopFailures.push(error);
815
+ if (attempt >= this.#opts.cleanupRetryLimit)
816
+ throw new AggregateError(
817
+ [
818
+ ...(this.#framePumpFailure === null ? [] : [this.#framePumpFailure]),
819
+ ...flattenAggregateCauses(this.#lastStopFailures),
820
+ ],
821
+ "Runtime owner cleanup could not be verified.",
822
+ );
823
+ await Bun.sleep(this.#opts.cleanupRetryMs);
824
+ }
825
+ }
826
+ }
827
+
828
+ async #reportStopFailure(kind: string, error: unknown): Promise<unknown | null> {
829
+ if (this.#reportedStopFailures.has(kind)) return null;
830
+ this.#reportedStopFailures.add(kind);
831
+ try {
832
+ await this.#emit("critical", kind, { error: String(error) });
833
+ return null;
834
+ } catch (reportError) {
835
+ return reportError;
836
+ }
837
+ }
838
+
839
+ async #stopOnce(): Promise<void> {
840
+ const failures: unknown[] = [];
841
+ const recordFailure = async (kind: string, error: unknown): Promise<void> => {
842
+ failures.push(error);
843
+ const reportFailure = await this.#reportStopFailure(kind, error);
844
+ if (reportFailure !== null) failures.push(reportFailure);
845
+ };
846
+ const unsubscribe = this.#unsubscribeFrames;
847
+ if (unsubscribe) {
848
+ try {
849
+ unsubscribe();
850
+ this.#unsubscribeFrames = null;
851
+ } catch (error) {
852
+ await recordFailure("owner_unsubscribe_failed", error);
853
+ }
854
+ }
855
+ await this.#framePump;
856
+
857
+ // The transport owns the exact spawned child. Do not surrender the lease while
858
+ // it is unverified; once each stage succeeds, retain that proof across retries.
859
+ if (!this.#transportClosed) {
860
+ try {
861
+ await this.#closeTransport();
862
+ this.#transportClosed = true;
863
+ } catch (error) {
864
+ await recordFailure("owner_transport_stop_failed", error);
865
+ }
866
+ }
867
+ if (!this.#transportClosed) throw new AggregateError(failures, "Runtime owner transport cleanup failed.");
868
+
869
+ if (!this.#serverClosed) {
870
+ try {
871
+ await this.#server.close();
872
+ this.#serverClosed = true;
873
+ } catch (error) {
874
+ await recordFailure("owner_server_stop_failed", error);
875
+ }
876
+ }
877
+ if (!this.#serverClosed) throw new AggregateError(failures, "Runtime owner endpoint cleanup failed.");
878
+
879
+ if (this.#leaseHeld) {
880
+ try {
881
+ await this.#opts.leaseRelease(this.#opts.root, this.#opts.sessionId, this.ownerId);
882
+ this.#leaseHeld = false;
883
+ } catch (error) {
884
+ if (error instanceof LeaseError && error.code === "not_lease_holder") {
885
+ // A successor already owns the lease. Our transport and endpoint are
886
+ // verified closed, so there is no old authority left to release.
887
+ this.#leaseHeld = false;
888
+ } else {
889
+ await recordFailure("owner_lease_release_failed", error);
890
+ }
891
+ }
892
+ }
893
+ if (this.#leaseHeld) throw new AggregateError(failures, "Runtime owner lease cleanup failed.");
894
+
649
895
  if (this.#heartbeatTimer) {
650
896
  clearInterval(this.#heartbeatTimer);
651
897
  this.#heartbeatTimer = null;
652
898
  }
653
- await this.#server.close().catch(() => {});
654
- await this.#opts.rpc.close().catch(() => {});
655
- await releaseLease(this.#opts.root, this.#opts.sessionId, this.ownerId).catch(() => {});
899
+ if (failures.length > 0) throw new AggregateError(failures, "Runtime owner cleanup failed.");
656
900
  }
657
901
  }
658
902
 
@@ -163,7 +163,6 @@ export interface VanishEvidence {
163
163
 
164
164
  export interface PromptAcceptanceEvidence {
165
165
  promptSha256: string;
166
- rpcCommandId: string;
167
166
  preSubmitState: { isStreaming: boolean; steeringQueueDepth: number; followupQueueDepth: number };
168
167
  preSubmitCursor: number;
169
168
  agentStartCursor: number;