@gajae-code/coding-agent 0.14.2 → 0.15.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 (345) hide show
  1. package/CHANGELOG.md +120 -1
  2. package/dist/types/async/job-manager.d.ts +4 -1
  3. package/dist/types/autoresearch/dashboard.d.ts +29 -4
  4. package/dist/types/autoresearch/data-context.d.ts +25 -0
  5. package/dist/types/autoresearch/git.d.ts +65 -7
  6. package/dist/types/autoresearch/harness.d.ts +58 -0
  7. package/dist/types/autoresearch/prompts.d.ts +51 -0
  8. package/dist/types/autoresearch/runs.d.ts +173 -0
  9. package/dist/types/autoresearch/types.d.ts +9 -139
  10. package/dist/types/capability/types.d.ts +20 -0
  11. package/dist/types/cli/accounts-cli.d.ts +1 -0
  12. package/dist/types/commands/{rlm.d.ts → autoresearch.d.ts} +2 -4
  13. package/dist/types/config/autorouting-contract.d.ts +146 -0
  14. package/dist/types/config/autorouting-generator.d.ts +40 -0
  15. package/dist/types/config/autorouting-tier-map.d.ts +16844 -0
  16. package/dist/types/config/autorouting.d.ts +35 -0
  17. package/dist/types/config/model-discovery-manager.d.ts +8 -1
  18. package/dist/types/config/model-registry.d.ts +30 -1
  19. package/dist/types/config/provider-selection-policy.d.ts +23 -0
  20. package/dist/types/config/settings-schema.d.ts +61 -3
  21. package/dist/types/config/settings.d.ts +3 -0
  22. package/dist/types/coordinator/contract.d.ts +1 -1
  23. package/dist/types/coordinator-mcp/durability.d.ts +29 -0
  24. package/dist/types/coordinator-mcp/event-webhook.d.ts +50 -0
  25. package/dist/types/coordinator-mcp/question-state.d.ts +1 -1
  26. package/dist/types/coordinator-mcp/server.d.ts +14 -0
  27. package/dist/types/crash/index-store.d.ts +3 -0
  28. package/dist/types/crash/record-loader.d.ts +2 -0
  29. package/dist/types/crash/upstream/relay.d.ts +5 -3
  30. package/dist/types/cursor.d.ts +12 -0
  31. package/dist/types/defaults/gjc-defaults.d.ts +35 -1
  32. package/dist/types/defaults/gjc-skills.generated.d.ts +1 -1
  33. package/dist/types/discovery/helpers.d.ts +1 -1
  34. package/dist/types/edit/index.d.ts +2 -1
  35. package/dist/types/eval/py/executor.d.ts +2 -0
  36. package/dist/types/extensibility/extensions/loader.d.ts +32 -0
  37. package/dist/types/extensibility/gjc-plugins/types.d.ts +1 -1
  38. package/dist/types/extensibility/skills.d.ts +2 -0
  39. package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +194 -0
  40. package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
  41. package/dist/types/gjc-runtime/psmux-detect.d.ts +1 -1
  42. package/dist/types/gjc-runtime/python-transcript.d.ts +19 -0
  43. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +2 -8
  44. package/dist/types/gjc-runtime/session-layout.d.ts +6 -3
  45. package/dist/types/gjc-runtime/state-renderer.d.ts +0 -22
  46. package/dist/types/gjc-runtime/state-schema.d.ts +7 -7
  47. package/dist/types/gjc-runtime/tmux-common.d.ts +2 -2
  48. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +38 -1
  49. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +2 -24
  50. package/dist/types/gjc-runtime/ultragoal-validation-policy.d.ts +73 -0
  51. package/dist/types/gjc-runtime/workflow-recovery-projection.d.ts +100 -0
  52. package/dist/types/hooks/skill-keywords.d.ts +1 -1
  53. package/dist/types/main.d.ts +0 -10
  54. package/dist/types/modes/acp/acp-agent.d.ts +13 -6
  55. package/dist/types/modes/components/model-selector.d.ts +14 -0
  56. package/dist/types/modes/components/skill-hud/render.d.ts +6 -1
  57. package/dist/types/modes/components/smart-routing-panel.d.ts +82 -0
  58. package/dist/types/modes/controllers/selector-controller.d.ts +14 -0
  59. package/dist/types/modes/interactive-mode.d.ts +3 -0
  60. package/dist/types/modes/types.d.ts +9 -0
  61. package/dist/types/rlm/artifacts.d.ts +4 -4
  62. package/dist/types/runtime/optional-runtime-services.d.ts +2 -1
  63. package/dist/types/runtime/workspace-tree-service.d.ts +5 -1
  64. package/dist/types/runtime-mcp/config.d.ts +6 -0
  65. package/dist/types/runtime-mcp/manager.d.ts +10 -0
  66. package/dist/types/sdk/acp/adapter.d.ts +0 -4
  67. package/dist/types/sdk/broker/broker.d.ts +1 -1
  68. package/dist/types/sdk/broker/lifecycle.d.ts +57 -2
  69. package/dist/types/sdk/broker/session-index.d.ts +15 -0
  70. package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -0
  71. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -0
  72. package/dist/types/sdk/bus/index.d.ts +8 -0
  73. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +2 -0
  74. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -2
  75. package/dist/types/sdk/client/client.d.ts +39 -4
  76. package/dist/types/sdk/host/host.d.ts +1 -0
  77. package/dist/types/sdk/host/internal-autorouting-state.d.ts +3 -0
  78. package/dist/types/sdk/host/model-pin.d.ts +29 -0
  79. package/dist/types/sdk/host/session-runtime.d.ts +2 -1
  80. package/dist/types/sdk/lifecycle-session.d.ts +13 -0
  81. package/dist/types/sdk/router/session-router.d.ts +27 -1
  82. package/dist/types/sdk/session.d.ts +11 -1
  83. package/dist/types/session/agent-session.d.ts +36 -6
  84. package/dist/types/session/artifacts.d.ts +16 -1
  85. package/dist/types/session/internal/managed-session-storage.d.ts +7 -0
  86. package/dist/types/session/session-manager.d.ts +84 -2
  87. package/dist/types/session/session-staging-paths.d.ts +3 -0
  88. package/dist/types/skill-state/canonical-skills.d.ts +1 -1
  89. package/dist/types/skill-state/workflow-hud.d.ts +12 -21
  90. package/dist/types/skill-state/workflow-mutation-guard.d.ts +1 -0
  91. package/dist/types/slash-commands/helpers/autorouting-status.d.ts +8 -0
  92. package/dist/types/system-prompt.d.ts +23 -0
  93. package/dist/types/task/executor.d.ts +35 -4
  94. package/dist/types/task/index.d.ts +17 -3
  95. package/dist/types/task/receipt.d.ts +3 -1
  96. package/dist/types/task/types.d.ts +144 -0
  97. package/dist/types/tools/atomic-file-write.d.ts +72 -0
  98. package/dist/types/tools/descriptors.d.ts +1 -0
  99. package/dist/types/tools/index.d.ts +36 -1
  100. package/dist/types/tools/move-session.d.ts +40 -0
  101. package/dist/types/tools/python.d.ts +12 -0
  102. package/dist/types/tools/resource-gc.d.ts +0 -3
  103. package/dist/types/tools/search.d.ts +8 -1
  104. package/dist/types/tools/skill.d.ts +9 -4
  105. package/dist/types/tools/subagent.d.ts +33 -3
  106. package/dist/types/utils/xml-escape.d.ts +2 -0
  107. package/dist/types/workflow/workflow-intent-diff.d.ts +2 -2
  108. package/dist/types/workflow/workflow-intent-report-consumer.d.ts +1 -1
  109. package/package.json +11 -12
  110. package/scripts/build-sdk-package-smoke.ts +7 -5
  111. package/scripts/check-autorouting-tier-map.ts +183 -0
  112. package/scripts/generate-sdk-operation-inventory.ts +12 -0
  113. package/scripts/generate-tool-catalog.ts +40 -5
  114. package/src/async/job-manager.ts +5 -2
  115. package/src/autoresearch/dashboard.ts +134 -314
  116. package/src/autoresearch/data-context.ts +35 -0
  117. package/src/autoresearch/git.ts +186 -26
  118. package/src/autoresearch/{helpers.ts → harness.ts} +65 -40
  119. package/src/autoresearch/{prompt-setup.md → prompts/prompt-setup.md} +7 -7
  120. package/src/autoresearch/prompts/prompt.md +103 -0
  121. package/src/autoresearch/prompts.ts +126 -0
  122. package/src/autoresearch/runs.ts +708 -0
  123. package/src/autoresearch/types.ts +9 -150
  124. package/src/capability/index.ts +4 -4
  125. package/src/capability/types.ts +20 -0
  126. package/src/cli/accounts-cli.ts +21 -5
  127. package/src/cli/config-cli.ts +25 -1
  128. package/src/cli/fast-help.ts +1 -2
  129. package/src/cli/list-models.ts +5 -8
  130. package/src/cli/setup-cli.ts +8 -0
  131. package/src/cli.ts +2 -21
  132. package/src/commands/autoresearch.ts +33 -0
  133. package/src/commands/coordinator.ts +15 -0
  134. package/src/commands/launch.ts +2 -4
  135. package/src/commands/quick-lane.ts +1 -1
  136. package/src/commands/sdk.ts +24 -0
  137. package/src/commands/state.ts +1 -1
  138. package/src/config/autorouting-contract.ts +474 -0
  139. package/src/config/autorouting-generator.ts +238 -0
  140. package/src/config/autorouting-tier-map.ts +6108 -0
  141. package/src/config/autorouting.ts +120 -0
  142. package/src/config/model-discovery-manager.ts +42 -11
  143. package/src/config/model-registry.ts +348 -68
  144. package/src/config/provider-selection-policy.ts +60 -9
  145. package/src/config/settings-schema.ts +195 -6
  146. package/src/config/settings.ts +62 -1
  147. package/src/config.ts +2 -3
  148. package/src/coordinator/contract.ts +0 -1
  149. package/src/coordinator-mcp/codex-handoff.ts +68 -42
  150. package/src/coordinator-mcp/durability.ts +200 -0
  151. package/src/coordinator-mcp/event-webhook.ts +278 -0
  152. package/src/coordinator-mcp/question-state.ts +109 -46
  153. package/src/coordinator-mcp/server.ts +932 -504
  154. package/src/crash/index-store.ts +126 -22
  155. package/src/crash/record-loader.ts +7 -0
  156. package/src/crash/upstream/relay.ts +82 -34
  157. package/src/cursor.ts +84 -1
  158. package/src/debug/index.ts +26 -0
  159. package/src/defaults/gjc/skills/autoresearch/SKILL.md +116 -0
  160. package/src/defaults/gjc/skills/autoresearch/auto-critic.md +46 -0
  161. package/src/defaults/gjc/skills/autoresearch/auto-iterate.md +42 -0
  162. package/src/defaults/gjc/skills/deep-interview/SKILL.md +17 -37
  163. package/src/defaults/gjc/skills/ralplan/SKILL.md +21 -18
  164. package/src/defaults/gjc/skills/ultragoal/SKILL.md +6 -17
  165. package/src/defaults/gjc/skills/ultragoal/ai-slop-cleaner.md +2 -2
  166. package/src/defaults/gjc-defaults.ts +89 -2
  167. package/src/defaults/gjc-skills.generated.ts +24 -17
  168. package/src/discovery/builtin.ts +18 -5
  169. package/src/discovery/helpers.ts +6 -6
  170. package/src/edit/index.ts +5 -2
  171. package/src/eval/py/executor.ts +8 -0
  172. package/src/extensibility/extensions/loader.ts +135 -13
  173. package/src/extensibility/extensions/wrapper.ts +1 -2
  174. package/src/extensibility/gjc-plugins/schema.ts +1 -1
  175. package/src/extensibility/runtime-skill-discovery.ts +2 -2
  176. package/src/extensibility/skill-management.ts +2 -3
  177. package/src/extensibility/skills.ts +16 -8
  178. package/src/gjc-runtime/autoresearch-runtime.ts +1509 -0
  179. package/src/gjc-runtime/gc-render.ts +0 -1
  180. package/src/gjc-runtime/gc-runtime.ts +1 -11
  181. package/src/gjc-runtime/launch-tmux.ts +3 -3
  182. package/src/gjc-runtime/psmux-detect.ts +2 -2
  183. package/src/gjc-runtime/python-transcript.ts +58 -0
  184. package/src/gjc-runtime/ralplan-runtime.ts +6 -18
  185. package/src/gjc-runtime/session-layout.ts +18 -7
  186. package/src/gjc-runtime/session-state-sidecar.ts +58 -9
  187. package/src/gjc-runtime/state-renderer.ts +0 -38
  188. package/src/gjc-runtime/state-runtime.ts +43 -22
  189. package/src/gjc-runtime/state-schema.ts +1 -1
  190. package/src/gjc-runtime/tmux-common.ts +7 -7
  191. package/src/gjc-runtime/ultragoal-change-set.ts +232 -11
  192. package/src/gjc-runtime/ultragoal-runtime.ts +309 -114
  193. package/src/gjc-runtime/ultragoal-validation-policy.ts +247 -0
  194. package/src/gjc-runtime/workflow-command-ref.ts +15 -11
  195. package/src/gjc-runtime/workflow-manifest.generated.json +413 -532
  196. package/src/gjc-runtime/workflow-manifest.ts +43 -83
  197. package/src/gjc-runtime/workflow-recovery-projection.ts +616 -0
  198. package/src/hooks/skill-keywords.ts +3 -3
  199. package/src/hooks/skill-state.ts +2 -2
  200. package/src/internal-urls/docs-index.generated.ts +26 -24
  201. package/src/lsp/index.ts +25 -5
  202. package/src/main.ts +2 -27
  203. package/src/modes/acp/acp-agent.ts +200 -75
  204. package/src/modes/components/model-selector.ts +216 -13
  205. package/src/modes/components/oauth-selector.ts +5 -5
  206. package/src/modes/components/skill-hud/render.ts +173 -35
  207. package/src/modes/components/smart-routing-panel.ts +531 -0
  208. package/src/modes/components/tool-status-header.ts +6 -3
  209. package/src/modes/controllers/command-controller.ts +17 -7
  210. package/src/modes/controllers/input-controller.ts +44 -9
  211. package/src/modes/controllers/runtime-mcp-command-controller.ts +4 -0
  212. package/src/modes/controllers/selector-controller.ts +298 -65
  213. package/src/modes/interactive-mode.ts +8 -1
  214. package/src/modes/shared/agent-wire/workflow-gate-types.ts +1 -1
  215. package/src/modes/types.ts +9 -1
  216. package/src/prompts/agents/planner.md +1 -1
  217. package/src/prompts/system/system-prompt.md +1 -1
  218. package/src/prompts/system/volatile-project-context.md +2 -1
  219. package/src/prompts/tools/move-session.md +15 -0
  220. package/src/prompts/tools/python.md +12 -0
  221. package/src/prompts/tools/skill-discovery.md +1 -1
  222. package/src/prompts/tools/skill.md +2 -2
  223. package/src/prompts/tools/task-summary.md +1 -0
  224. package/src/prompts/tools/task.md +6 -0
  225. package/src/rlm/artifacts.ts +12 -10
  226. package/src/runtime/optional-runtime-services.ts +3 -2
  227. package/src/runtime/workspace-tree-service.ts +11 -3
  228. package/src/runtime-mcp/config.ts +8 -1
  229. package/src/runtime-mcp/manager.ts +33 -0
  230. package/src/sdk/acp/adapter.ts +48 -1
  231. package/src/sdk/broker/broker.ts +30 -2
  232. package/src/sdk/broker/discovery.ts +217 -2
  233. package/src/sdk/broker/lifecycle.ts +385 -59
  234. package/src/sdk/broker/session-index.ts +243 -48
  235. package/src/sdk/broker/transport.ts +1 -0
  236. package/src/sdk/bus/chat-daemon-control.ts +8 -2
  237. package/src/sdk/bus/chat-daemon-runtime.ts +5 -0
  238. package/src/sdk/bus/index.ts +208 -11
  239. package/src/sdk/bus/kind-aware-reconciliation.ts +16 -0
  240. package/src/sdk/bus/reconciliation-store.ts +27 -5
  241. package/src/sdk/bus/telegram-daemon-contract.ts +12 -2
  242. package/src/sdk/client/client.ts +204 -22
  243. package/src/sdk/host/host.ts +16 -0
  244. package/src/sdk/host/internal-autorouting-state.ts +13 -0
  245. package/src/sdk/host/model-pin.ts +101 -0
  246. package/src/sdk/host/reverse-leases.ts +2 -1
  247. package/src/sdk/host/session-runtime.test.ts +224 -1
  248. package/src/sdk/host/session-runtime.ts +125 -37
  249. package/src/sdk/lifecycle/service.ts +3 -1
  250. package/src/sdk/lifecycle-session.ts +42 -1
  251. package/src/sdk/protocol/operation-inventory.generated.json +66 -0
  252. package/src/sdk/router/session-router.ts +375 -36
  253. package/src/sdk/session.ts +547 -47
  254. package/src/session/account-inventory.ts +1 -1
  255. package/src/session/agent-session.ts +765 -189
  256. package/src/session/artifacts.ts +234 -4
  257. package/src/session/internal/managed-session-storage.ts +91 -4
  258. package/src/session/provider-safety-stop-hint.ts +3 -2
  259. package/src/session/session-manager.ts +775 -16
  260. package/src/session/session-staging-paths.ts +8 -0
  261. package/src/setup/hermes/templates/operator-instructions.v1.md +0 -1
  262. package/src/setup/host-plugin-setup.ts +2 -2
  263. package/src/skill-state/active-state.ts +2 -2
  264. package/src/skill-state/canonical-skills.ts +1 -1
  265. package/src/skill-state/initial-phase.ts +1 -1
  266. package/src/skill-state/workflow-hud.ts +41 -41
  267. package/src/skill-state/workflow-mutation-guard.ts +26 -7
  268. package/src/slash-commands/builtin-registry.ts +77 -0
  269. package/src/slash-commands/helpers/autorouting-status.ts +55 -0
  270. package/src/system-prompt.ts +102 -5
  271. package/src/task/discovery.ts +2 -3
  272. package/src/task/executor.ts +617 -43
  273. package/src/task/index.ts +262 -15
  274. package/src/task/receipt.ts +30 -0
  275. package/src/task/render.ts +11 -1
  276. package/src/task/types.ts +316 -0
  277. package/src/tools/atomic-file-write.ts +594 -0
  278. package/src/tools/bisect.ts +3 -2
  279. package/src/tools/descriptors.test.ts +3 -0
  280. package/src/tools/descriptors.ts +24 -0
  281. package/src/tools/image-gen.ts +5 -1
  282. package/src/tools/index.ts +62 -5
  283. package/src/tools/move-session.ts +107 -0
  284. package/src/tools/python.ts +205 -0
  285. package/src/tools/read.ts +88 -15
  286. package/src/tools/renderers.ts +2 -0
  287. package/src/tools/resource-gc.ts +8 -177
  288. package/src/tools/search.ts +30 -6
  289. package/src/tools/skill-discovery.ts +1 -0
  290. package/src/tools/skill.ts +37 -7
  291. package/src/tools/subagent-render.ts +119 -13
  292. package/src/tools/subagent.ts +91 -74
  293. package/src/tools/tool-catalog.generated.ts +64 -2
  294. package/src/tools/write.ts +16 -12
  295. package/src/utils/xml-escape.ts +14 -0
  296. package/src/web/search/providers/codex.ts +2 -2
  297. package/src/workflow/workflow-intent-diff.ts +13 -12
  298. package/src/workflow/workflow-intent-report-consumer.ts +6 -6
  299. package/dist/types/autoresearch/helpers.d.ts +0 -24
  300. package/dist/types/autoresearch/index.d.ts +0 -2
  301. package/dist/types/autoresearch/state.d.ts +0 -17
  302. package/dist/types/autoresearch/storage.d.ts +0 -142
  303. package/dist/types/autoresearch/tools/init-experiment.d.ts +0 -31
  304. package/dist/types/autoresearch/tools/log-experiment.d.ts +0 -23
  305. package/dist/types/autoresearch/tools/run-experiment.d.ts +0 -8
  306. package/dist/types/autoresearch/tools/update-notes.d.ts +0 -12
  307. package/dist/types/commands/team.d.ts +0 -24
  308. package/dist/types/gjc-runtime/team-gc.d.ts +0 -7
  309. package/dist/types/gjc-runtime/team-launch.d.ts +0 -61
  310. package/dist/types/gjc-runtime/team-notify.d.ts +0 -45
  311. package/dist/types/gjc-runtime/team-runtime.d.ts +0 -336
  312. package/dist/types/gjc-runtime/team-store.d.ts +0 -168
  313. package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +0 -43
  314. package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +0 -92
  315. package/dist/types/gjc-runtime/team-workers.d.ts +0 -83
  316. package/dist/types/rlm/index.d.ts +0 -47
  317. package/dist/types/rlm/preset.d.ts +0 -23
  318. package/dist/types/rlm/python-tool.d.ts +0 -16
  319. package/src/autoresearch/command-resume.md +0 -14
  320. package/src/autoresearch/index.ts +0 -536
  321. package/src/autoresearch/prompt.md +0 -103
  322. package/src/autoresearch/resume-message.md +0 -10
  323. package/src/autoresearch/state.ts +0 -273
  324. package/src/autoresearch/storage.ts +0 -699
  325. package/src/autoresearch/tools/init-experiment.ts +0 -272
  326. package/src/autoresearch/tools/log-experiment.ts +0 -524
  327. package/src/autoresearch/tools/run-experiment.ts +0 -475
  328. package/src/autoresearch/tools/update-notes.ts +0 -109
  329. package/src/commands/rlm.ts +0 -19
  330. package/src/commands/team.ts +0 -238
  331. package/src/defaults/gjc/skills/deep-interview/auto-research-greenfield.md +0 -42
  332. package/src/defaults/gjc/skills/team/SKILL.md +0 -467
  333. package/src/gjc-runtime/team-gc.ts +0 -49
  334. package/src/gjc-runtime/team-launch.ts +0 -404
  335. package/src/gjc-runtime/team-notify.ts +0 -326
  336. package/src/gjc-runtime/team-runtime.ts +0 -5923
  337. package/src/gjc-runtime/team-store.ts +0 -878
  338. package/src/gjc-runtime/team-worker-heartbeat.ts +0 -149
  339. package/src/gjc-runtime/team-worker-memory-guard.ts +0 -363
  340. package/src/gjc-runtime/team-workers.ts +0 -1123
  341. package/src/prompts/system/rlm-report-command.md +0 -1
  342. package/src/prompts/system/rlm-research.md +0 -23
  343. package/src/rlm/index.ts +0 -365
  344. package/src/rlm/preset.ts +0 -76
  345. package/src/rlm/python-tool.ts +0 -68
@@ -2,6 +2,12 @@ import { createHash } from "node:crypto";
2
2
  import * as fs from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
  import { withFileLock } from "../config/file-lock";
5
+ import {
6
+ appendCoordinatorFile,
7
+ ensureCoordinatorDirectory,
8
+ syncCoordinatorDirectory,
9
+ writeCoordinatorAtomic,
10
+ } from "./durability";
5
11
  import type { PrivateAskGateCodecV1, PublicReason } from "./question-gate-codec";
6
12
 
7
13
  export type CoordinatorSessionState =
@@ -183,6 +189,9 @@ export interface OutboxEventV1 {
183
189
  payload: Record<string, string | number | boolean | null>;
184
190
  emitted: boolean;
185
191
  }
192
+ function isOutboxEntity(value: unknown): value is OutboxEventV1["entity"] {
193
+ return value === "turn" || value === "question" || value === "report" || value === "session" || value === "deletion";
194
+ }
186
195
  export interface CoordinatorSessionTransactionV1 {
187
196
  schema_version: 1;
188
197
  namespace_id: string;
@@ -234,7 +243,7 @@ export type CanonicalCreateIntentV1 =
234
243
  }
235
244
  | {
236
245
  kind: "delegate";
237
- workflow: "plan" | "execute" | "team";
246
+ workflow: "plan" | "execute";
238
247
  session: CanonicalSessionSnapshotV1;
239
248
  remote_create_key: string;
240
249
  initial_state: CoordinatorSessionState;
@@ -310,37 +319,38 @@ export function transactionPath(paths: CoordinatorStatePaths, sessionId: string)
310
319
  export function transactionLockPath(paths: CoordinatorStatePaths, sessionId: string): string {
311
320
  return path.join(paths.sessions, safeSessionId(sessionId), "transaction.lock");
312
321
  }
313
- async function fsyncDirectory(directory: string): Promise<void> {
314
- const handle = await fs.open(directory, "r");
315
- try {
316
- await handle.sync();
317
- } finally {
318
- await handle.close();
319
- }
320
- }
321
322
  async function ensureNamespaceParents(paths: CoordinatorStatePaths): Promise<void> {
322
- await fs.mkdir(paths.root, { recursive: true, mode: 0o700 });
323
+ await ensureCoordinatorDirectory(paths.root);
323
324
  }
324
325
 
325
- async function writeAtomic(file: string, value: unknown): Promise<void> {
326
- await fs.mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
327
- const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
328
- const handle = await fs.open(temp, "wx", 0o600);
326
+ async function removeCoordinatorStateFile(file: string): Promise<void> {
329
327
  try {
330
- await handle.writeFile(JSON.stringify(value));
331
- await handle.sync();
332
- } finally {
333
- await handle.close();
328
+ await fs.lstat(file);
329
+ } catch (error) {
330
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
331
+ try {
332
+ await fs.stat(path.dirname(file));
333
+ } catch (parentError) {
334
+ if ((parentError as NodeJS.ErrnoException).code === "ENOENT") return;
335
+ throw parentError;
336
+ }
337
+ await syncCoordinatorDirectory(path.dirname(file));
338
+ return;
334
339
  }
335
- await fs.rename(temp, file);
336
- await fsyncDirectory(path.dirname(file));
340
+ await fs.rm(file);
341
+ await syncCoordinatorDirectory(path.dirname(file));
342
+ }
343
+
344
+ async function writeAtomic(file: string, value: unknown): Promise<void> {
345
+ await writeCoordinatorAtomic(file, JSON.stringify(value));
337
346
  }
338
347
  async function readJson<T>(file: string): Promise<T | null> {
339
348
  try {
340
349
  return JSON.parse(await fs.readFile(file, "utf8")) as T;
341
350
  } catch (error) {
342
351
  if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
343
- throw new Error("state_corrupt");
352
+ if (error instanceof SyntaxError) throw new Error("state_corrupt");
353
+ throw error;
344
354
  }
345
355
  }
346
356
  function assertTransaction(transaction: CoordinatorSessionTransactionV1, namespaceId: string, sessionId: string): void {
@@ -356,8 +366,8 @@ function assertTransaction(transaction: CoordinatorSessionTransactionV1, namespa
356
366
  }
357
367
  export async function initializeCoordinatorNamespace(paths: CoordinatorStatePaths): Promise<void> {
358
368
  await ensureNamespaceParents(paths);
359
- await fs.mkdir(paths.sessions, { recursive: true, mode: 0o700 });
360
- await fs.mkdir(path.dirname(paths.journal), { recursive: true, mode: 0o700 });
369
+ await ensureCoordinatorDirectory(paths.sessions);
370
+ await ensureCoordinatorDirectory(path.dirname(paths.journal));
361
371
  await withFileLock(paths.registryLock, async () => {
362
372
  const existing = await readJson<NamespaceRegistryV1>(paths.registry);
363
373
  if (existing === null)
@@ -391,7 +401,7 @@ export async function withSessionTransaction<T>(
391
401
  operation: (transaction: CoordinatorSessionTransactionV1) => Promise<T>,
392
402
  ): Promise<T> {
393
403
  const file = transactionPath(paths, sessionId);
394
- await fs.mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
404
+ await ensureCoordinatorDirectory(path.dirname(file));
395
405
  return await withFileLock(transactionLockPath(paths, sessionId), async () => {
396
406
  const transaction = await readJson<CoordinatorSessionTransactionV1>(file);
397
407
  if (!transaction) throw new Error("resource_gone");
@@ -504,7 +514,7 @@ export async function commitCreationWal(
504
514
  entry.phase === "completed",
505
515
  );
506
516
  if (!priorDeleted) throw new Error("session_closing");
507
- await fs.rm(transactionPath(paths, session.session_id), { force: true });
517
+ await removeCoordinatorStateFile(transactionPath(paths, session.session_id));
508
518
  existing = null;
509
519
  }
510
520
  if (existing) {
@@ -648,34 +658,87 @@ export async function appendOutboxEvents(
648
658
  paths: CoordinatorStatePaths,
649
659
  transaction: CoordinatorSessionTransactionV1,
650
660
  ): Promise<void> {
651
- await fs.mkdir(path.dirname(paths.journal), { recursive: true, mode: 0o700 });
661
+ await ensureCoordinatorDirectory(path.dirname(paths.journal));
652
662
  await withFileLock(paths.journalLock, async () => {
653
663
  const existing = await fs.readFile(paths.journal, "utf8").catch(error => {
654
664
  if ((error as NodeJS.ErrnoException).code === "ENOENT") return "";
655
665
  throw error;
656
666
  });
657
- const ids = new Set(
658
- existing
659
- .split("\n")
660
- .filter(Boolean)
661
- .map(line => {
662
- try {
663
- return (JSON.parse(line) as { id?: unknown }).id;
664
- } catch {
665
- return null;
666
- }
667
- })
668
- .filter((id): id is string => typeof id === "string"),
669
- );
670
- const events = Object.values(transaction.outbox).filter(event => !event.emitted && !ids.has(event.id));
671
- if (events.length > 0) {
672
- const handle = await fs.open(paths.journal, "a", 0o600);
667
+ const existingEvents = new Map<string, OutboxEventV1>();
668
+ for (const rawLine of existing.split("\n")) {
669
+ const line = rawLine.trim();
670
+ if (!line) continue;
671
+ let parsed: unknown;
673
672
  try {
674
- await handle.writeFile(`${events.map(event => JSON.stringify(event)).join("\n")}\n`);
675
- await handle.sync();
676
- } finally {
677
- await handle.close();
673
+ parsed = JSON.parse(line);
674
+ } catch {
675
+ throw new Error("state_corrupt");
678
676
  }
677
+ const candidate = parsed as Partial<OutboxEventV1>;
678
+ const identity = typeof candidate.id === "string" ? candidate.id.split(":") : [];
679
+ const identityRevision = identity.length >= 6 ? Number(identity[2]) : Number.NaN;
680
+ const identityEntity = identity.length >= 6 ? identity[4] : undefined;
681
+ const identityEntityId = identity.length >= 6 ? identity.slice(5).join(":") : "";
682
+ const identitySession = identity.length >= 6 ? identity[1] : "";
683
+ const identityKind = identity.length >= 6 ? identity[3] : "";
684
+ const canonicalIdentity =
685
+ identity.length >= 6 &&
686
+ identity[0] === "txn" &&
687
+ identitySession &&
688
+ Number.isSafeInteger(identityRevision) &&
689
+ identityRevision > 0 &&
690
+ identityKind &&
691
+ isOutboxEntity(identityEntity) &&
692
+ identityEntityId &&
693
+ candidate.id ===
694
+ deterministicOutboxId(identitySession, identityRevision, identityKind, identityEntity, identityEntityId);
695
+ if (
696
+ typeof parsed !== "object" ||
697
+ parsed === null ||
698
+ Array.isArray(parsed) ||
699
+ typeof candidate.id !== "string" ||
700
+ candidate.id.length === 0 ||
701
+ typeof candidate.transaction_revision !== "number" ||
702
+ !Number.isSafeInteger(candidate.transaction_revision) ||
703
+ candidate.transaction_revision <= 0 ||
704
+ typeof candidate.kind !== "string" ||
705
+ !candidate.kind ||
706
+ !isOutboxEntity(candidate.entity) ||
707
+ typeof candidate.entity_id !== "string" ||
708
+ !candidate.entity_id ||
709
+ typeof candidate.payload !== "object" ||
710
+ candidate.payload === null ||
711
+ Array.isArray(candidate.payload) ||
712
+ typeof candidate.emitted !== "boolean" ||
713
+ !canonicalIdentity ||
714
+ candidate.transaction_revision !== identityRevision ||
715
+ existingEvents.has(candidate.id)
716
+ )
717
+ throw new Error("state_corrupt");
718
+ existingEvents.set(candidate.id, candidate as OutboxEventV1);
719
+ }
720
+ for (const event of Object.values(transaction.outbox)) {
721
+ if (
722
+ event.id !==
723
+ deterministicOutboxId(
724
+ transaction.session_id,
725
+ event.transaction_revision,
726
+ event.kind,
727
+ event.entity,
728
+ event.entity_id,
729
+ )
730
+ )
731
+ throw new Error("state_corrupt");
732
+ }
733
+ const events = Object.values(transaction.outbox).filter(event => {
734
+ if (event.emitted) return false;
735
+ const existing = existingEvents.get(event.id);
736
+ if (!existing) return true;
737
+ if (JSON.stringify(existing) !== JSON.stringify(event)) throw new Error("state_corrupt");
738
+ return false;
739
+ });
740
+ if (events.length > 0) {
741
+ await appendCoordinatorFile(paths.journal, `${events.map(event => JSON.stringify(event)).join("\n")}\n`);
679
742
  }
680
743
  for (const event of Object.values(transaction.outbox)) event.emitted = true;
681
744
  transaction.projection.applied_events_revision = transaction.revision;