@gajae-code/coding-agent 0.11.11 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/CHANGELOG.md +131 -4
  2. package/dist/types/async/job-manager.d.ts +17 -3
  3. package/dist/types/cli/read-cli.d.ts +1 -0
  4. package/dist/types/commands/deep-interview.d.ts +9 -0
  5. package/dist/types/commands/harness.d.ts +22 -0
  6. package/dist/types/commands/read.d.ts +6 -0
  7. package/dist/types/config/model-registry.d.ts +4 -0
  8. package/dist/types/config/provider-auth-health.d.ts +14 -0
  9. package/dist/types/config/provider-ranking.d.ts +59 -0
  10. package/dist/types/config/settings-schema.d.ts +83 -1
  11. package/dist/types/config/settings.d.ts +2 -0
  12. package/dist/types/exa/mcp-client.d.ts +10 -1
  13. package/dist/types/exec/bash-executor.d.ts +45 -12
  14. package/dist/types/extensibility/extensions/types.d.ts +38 -4
  15. package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
  16. package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
  17. package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
  18. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
  19. package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
  20. package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
  21. package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
  22. package/dist/types/extensibility/shared-events.d.ts +6 -0
  23. package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
  24. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
  25. package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
  26. package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
  27. package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
  28. package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
  29. package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
  30. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +70 -1
  31. package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
  32. package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
  33. package/dist/types/gjc-runtime/team-runtime.d.ts +27 -1
  34. package/dist/types/gjc-runtime/team-store.d.ts +12 -0
  35. package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
  36. package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
  37. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +17 -0
  38. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
  39. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +31 -80
  40. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
  41. package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
  42. package/dist/types/main.d.ts +1 -1
  43. package/dist/types/memories/index.d.ts +2 -0
  44. package/dist/types/modes/acp/acp-agent.d.ts +10 -19
  45. package/dist/types/modes/components/assistant-message.d.ts +3 -1
  46. package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
  47. package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
  48. package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
  49. package/dist/types/modes/components/read-tool-group.d.ts +4 -4
  50. package/dist/types/modes/components/session-observer-overlay.d.ts +22 -0
  51. package/dist/types/modes/components/settings-selector.d.ts +11 -0
  52. package/dist/types/modes/components/status-line/gh.d.ts +5 -0
  53. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  54. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
  55. package/dist/types/modes/controllers/event-controller.d.ts +3 -0
  56. package/dist/types/modes/interactive-mode.d.ts +2 -0
  57. package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
  58. package/dist/types/modes/types.d.ts +2 -0
  59. package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
  60. package/dist/types/reminders/star-reminder.d.ts +3 -13
  61. package/dist/types/runtime-mcp/manager.d.ts +1 -0
  62. package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
  63. package/dist/types/sdk/acp/adapter.d.ts +3 -1
  64. package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
  65. package/dist/types/sdk/broker/transport.d.ts +2 -0
  66. package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
  67. package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -1
  68. package/dist/types/sdk/bus/config.d.ts +6 -2
  69. package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
  70. package/dist/types/sdk/bus/index.d.ts +44 -1
  71. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +44 -0
  72. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  73. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
  74. package/dist/types/sdk/bus/reconciliation-store.d.ts +69 -0
  75. package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
  76. package/dist/types/sdk/bus/rich-render.d.ts +2 -0
  77. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
  78. package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
  79. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +11 -4
  80. package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
  81. package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
  82. package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
  83. package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
  84. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  85. package/dist/types/sdk/host/host.d.ts +2 -0
  86. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  87. package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
  88. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  89. package/dist/types/sdk/prompt-status.d.ts +23 -3
  90. package/dist/types/sdk/session.d.ts +6 -0
  91. package/dist/types/session/agent-session.d.ts +82 -12
  92. package/dist/types/session/artifacts.d.ts +8 -0
  93. package/dist/types/session/blob-store.d.ts +57 -4
  94. package/dist/types/session/internal/managed-session-storage.d.ts +8 -1
  95. package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
  96. package/dist/types/session/session-manager.d.ts +48 -19
  97. package/dist/types/session/session-storage.d.ts +4 -0
  98. package/dist/types/session/streaming-output.d.ts +96 -12
  99. package/dist/types/setup/credential-import.d.ts +12 -0
  100. package/dist/types/skill-state/active-state.d.ts +12 -4
  101. package/dist/types/skill-state/workflow-hud.d.ts +9 -0
  102. package/dist/types/task/executor.d.ts +3 -2
  103. package/dist/types/task/index.d.ts +3 -1
  104. package/dist/types/task/provider-retry-status.d.ts +8 -0
  105. package/dist/types/task/receipt.d.ts +7 -1
  106. package/dist/types/task/types.d.ts +23 -0
  107. package/dist/types/tools/ask-answer-registry.d.ts +2 -2
  108. package/dist/types/tools/bash-interactive.d.ts +4 -1
  109. package/dist/types/tools/bash.d.ts +3 -1
  110. package/dist/types/tools/browser/launch.d.ts +7 -0
  111. package/dist/types/tools/fetch.d.ts +17 -1
  112. package/dist/types/tools/image-gen.d.ts +4 -0
  113. package/dist/types/tools/index.d.ts +4 -0
  114. package/dist/types/tools/output-meta.d.ts +44 -3
  115. package/dist/types/tools/path-utils.d.ts +1 -0
  116. package/dist/types/tools/read-internals.d.ts +12 -0
  117. package/dist/types/tools/read.d.ts +45 -7
  118. package/dist/types/tools/resource-gc.d.ts +4 -0
  119. package/dist/types/tools/review.d.ts +5 -7
  120. package/dist/types/tools/subagent.d.ts +2 -0
  121. package/dist/types/tools/tool-result.d.ts +7 -1
  122. package/dist/types/utils/gh.d.ts +13 -0
  123. package/dist/types/utils/image-resize.d.ts +1 -0
  124. package/dist/types/web/search/providers/kimi.d.ts +2 -0
  125. package/dist/types/web/search/providers/searxng.d.ts +7 -0
  126. package/dist/types/web/search/providers/xai.d.ts +2 -0
  127. package/package.json +11 -13
  128. package/scripts/acp-conformance-agent.ts +218 -0
  129. package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
  130. package/scripts/capture-gjc-bundle-settings.ts +306 -0
  131. package/scripts/capture-sticky-viewport-showcase.ts +292 -0
  132. package/scripts/generate-sdk-operation-inventory.ts +5 -0
  133. package/scripts/resident-memory-bench.ts +1341 -0
  134. package/scripts/run-acp-conformance.ts +285 -0
  135. package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
  136. package/scripts/verify-sticky-viewport-showcase.ts +611 -0
  137. package/src/async/job-manager.ts +78 -20
  138. package/src/capability/index.ts +8 -0
  139. package/src/cli/fast-help.ts +1 -1
  140. package/src/cli/plugin-cli.ts +176 -18
  141. package/src/cli/read-cli.ts +2 -1
  142. package/src/cli.ts +1 -0
  143. package/src/commands/deep-interview.ts +29 -9
  144. package/src/commands/harness.ts +35 -12
  145. package/src/commands/read.ts +11 -2
  146. package/src/commands/team.ts +20 -2
  147. package/src/config/file-lock.ts +11 -2
  148. package/src/config/model-registry.ts +21 -2
  149. package/src/config/provider-auth-health.ts +42 -0
  150. package/src/config/provider-ranking.ts +119 -0
  151. package/src/config/settings-schema.ts +74 -1
  152. package/src/config/settings.ts +246 -108
  153. package/src/coordinator-mcp/question-gate-codec.ts +1 -1
  154. package/src/coordinator-mcp/server.ts +5 -12
  155. package/src/defaults/gjc/skills/deep-interview/SKILL.md +230 -82
  156. package/src/defaults/gjc/skills/ralplan/SKILL.md +77 -41
  157. package/src/defaults/gjc/skills/team/SKILL.md +3 -1
  158. package/src/defaults/gjc/skills/ultragoal/SKILL.md +62 -39
  159. package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
  160. package/src/defaults/gjc-defaults.ts +4 -4
  161. package/src/eval/py/executor.ts +7 -2
  162. package/src/exa/mcp-client.ts +12 -3
  163. package/src/exec/bash-executor.ts +144 -27
  164. package/src/extensibility/extensions/runner.ts +15 -0
  165. package/src/extensibility/extensions/types.ts +46 -5
  166. package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
  167. package/src/extensibility/gjc-plugins/index.ts +19 -2
  168. package/src/extensibility/gjc-plugins/installer.ts +189 -50
  169. package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
  170. package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
  171. package/src/extensibility/gjc-plugins/observability.ts +3 -3
  172. package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
  173. package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
  174. package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
  175. package/src/extensibility/gjc-plugins/schema.ts +84 -12
  176. package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
  177. package/src/extensibility/gjc-plugins/types.ts +141 -0
  178. package/src/extensibility/gjc-plugins/validation.ts +9 -0
  179. package/src/extensibility/shared-events.ts +5 -0
  180. package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
  181. package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
  182. package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
  183. package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
  184. package/src/gjc-runtime/deep-interview-state.ts +12 -943
  185. package/src/gjc-runtime/gc-render.ts +1 -0
  186. package/src/gjc-runtime/gc-runtime.ts +11 -1
  187. package/src/gjc-runtime/launch-tmux.ts +25 -6
  188. package/src/gjc-runtime/managed-owner-admission.ts +1 -1
  189. package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
  190. package/src/gjc-runtime/ralplan-runtime.ts +1149 -98
  191. package/src/gjc-runtime/state-runtime.ts +2 -1
  192. package/src/gjc-runtime/state-writer.ts +70 -222
  193. package/src/gjc-runtime/team-launch.ts +42 -5
  194. package/src/gjc-runtime/team-runtime.ts +1085 -40
  195. package/src/gjc-runtime/team-store.ts +32 -0
  196. package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
  197. package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
  198. package/src/gjc-runtime/team-workers.ts +1 -0
  199. package/src/gjc-runtime/tmux-owner-isolation.ts +28 -0
  200. package/src/gjc-runtime/tmux-sessions.ts +58 -13
  201. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
  202. package/src/gjc-runtime/ultragoal-runtime.ts +414 -618
  203. package/src/gjc-runtime/workflow-manifest.generated.json +105 -449
  204. package/src/gjc-runtime/workflow-manifest.ts +38 -247
  205. package/src/hooks/native-skill-hook.ts +17 -4
  206. package/src/hooks/skill-state.ts +1 -23
  207. package/src/internal-urls/docs-index.generated.ts +21 -22
  208. package/src/internal-urls/local-root-gc.ts +127 -0
  209. package/src/main.ts +9 -5
  210. package/src/memories/index.ts +10 -0
  211. package/src/modes/DESIGN.md +98 -0
  212. package/src/modes/acp/acp-agent.ts +339 -191
  213. package/src/modes/acp/acp-event-mapper.ts +14 -7
  214. package/src/modes/acp/acp-mode.ts +39 -3
  215. package/src/modes/components/assistant-message.ts +123 -22
  216. package/src/modes/components/gjc-bundle-settings.ts +508 -0
  217. package/src/modes/components/irc-sidebar.ts +176 -62
  218. package/src/modes/components/model-selector.ts +61 -4
  219. package/src/modes/components/notifications-settings-editor.ts +12 -1
  220. package/src/modes/components/oauth-selector.ts +96 -28
  221. package/src/modes/components/read-tool-group.ts +82 -14
  222. package/src/modes/components/session-observer-overlay.ts +457 -83
  223. package/src/modes/components/settings-selector.ts +116 -23
  224. package/src/modes/components/status-line/gh.ts +16 -0
  225. package/src/modes/components/tool-execution.ts +138 -27
  226. package/src/modes/components/tool-status-header.ts +3 -14
  227. package/src/modes/components/transcript-viewer-overlay.ts +99 -24
  228. package/src/modes/controllers/command-controller.ts +4 -0
  229. package/src/modes/controllers/event-controller.ts +109 -27
  230. package/src/modes/controllers/extension-ui-controller.ts +26 -2
  231. package/src/modes/controllers/input-controller.ts +18 -3
  232. package/src/modes/controllers/selector-controller.ts +127 -36
  233. package/src/modes/interactive-mode.ts +62 -3
  234. package/src/modes/irc-observation-ledger.ts +71 -15
  235. package/src/modes/runtime-init.ts +22 -2
  236. package/src/modes/types.ts +2 -0
  237. package/src/modes/utils/ui-helpers.ts +94 -1
  238. package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
  239. package/src/prompts/agents/architect.md +9 -1
  240. package/src/prompts/agents/critic.md +9 -0
  241. package/src/prompts/system/eager-todo.md +8 -4
  242. package/src/prompts/system/system-prompt.md +11 -5
  243. package/src/prompts/tools/bash.md +5 -5
  244. package/src/prompts/tools/read.md +4 -2
  245. package/src/prompts/tools/search-tool-bm25.md +5 -0
  246. package/src/prompts/tools/task.md +1 -1
  247. package/src/reminders/star-reminder.ts +4 -42
  248. package/src/runtime-mcp/manager.ts +19 -4
  249. package/src/runtime-mcp/smithery-auth.ts +17 -2
  250. package/src/runtime-mcp/smithery-connect.ts +11 -1
  251. package/src/sdk/acp/adapter.ts +22 -6
  252. package/src/sdk/broker/lifecycle.ts +25 -6
  253. package/src/sdk/broker/transport.ts +35 -3
  254. package/src/sdk/bus/attachment-registry.ts +5 -1
  255. package/src/sdk/bus/chat-daemon-cli.ts +4 -39
  256. package/src/sdk/bus/chat-daemon-control.ts +6 -3
  257. package/src/sdk/bus/config.ts +18 -2
  258. package/src/sdk/bus/control-drain-lease.ts +104 -0
  259. package/src/sdk/bus/index.ts +984 -146
  260. package/src/sdk/bus/kind-aware-reconciliation.ts +317 -0
  261. package/src/sdk/bus/lifecycle-commands.ts +4 -1
  262. package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
  263. package/src/sdk/bus/prompt-reconciliation.ts +2 -1
  264. package/src/sdk/bus/reconciliation-store.ts +303 -0
  265. package/src/sdk/bus/rich-draft.ts +1 -1
  266. package/src/sdk/bus/rich-render.ts +2 -2
  267. package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
  268. package/src/sdk/bus/telegram-cli.ts +33 -8
  269. package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
  270. package/src/sdk/bus/telegram-daemon-contract.ts +11 -4
  271. package/src/sdk/bus/telegram-daemon.ts +916 -23
  272. package/src/sdk/bus/telegram-reference.ts +40 -3
  273. package/src/sdk/bus/threaded-render.ts +48 -3
  274. package/src/sdk/bus/topic-registry.ts +20 -0
  275. package/src/sdk/host/control/dispatch.ts +5 -1
  276. package/src/sdk/host/control/operations.ts +1 -1
  277. package/src/sdk/host/host.ts +23 -1
  278. package/src/sdk/host/query/handlers.ts +55 -0
  279. package/src/sdk/host/query/revision-store.ts +36 -2
  280. package/src/sdk/host/reverse-leases.ts +44 -7
  281. package/src/sdk/mcp/server.ts +46 -18
  282. package/src/sdk/prompt-status.ts +16 -3
  283. package/src/sdk/protocol/operation-inventory.generated.json +51 -0
  284. package/src/sdk/protocol/operation-registry.ts +7 -2
  285. package/src/sdk/session.ts +101 -10
  286. package/src/session/agent-session.ts +1286 -220
  287. package/src/session/artifacts.ts +22 -0
  288. package/src/session/auth-broker-config.ts +10 -3
  289. package/src/session/blob-store.ts +915 -24
  290. package/src/session/internal/managed-session-scope.ts +44 -6
  291. package/src/session/internal/managed-session-storage.ts +48 -6
  292. package/src/session/memory-guard-checkpoint-participant.ts +131 -0
  293. package/src/session/session-manager.ts +2364 -438
  294. package/src/session/session-storage.ts +9 -1
  295. package/src/session/streaming-output.ts +500 -111
  296. package/src/setup/credential-import.ts +75 -13
  297. package/src/setup/provider-onboarding.ts +19 -4
  298. package/src/skill-state/active-state.ts +32 -10
  299. package/src/skill-state/workflow-hud.ts +42 -2
  300. package/src/skill-state/workflow-mutation-guard.ts +560 -8
  301. package/src/task/executor.ts +122 -39
  302. package/src/task/index.ts +23 -14
  303. package/src/task/provider-retry-status.ts +16 -0
  304. package/src/task/receipt.ts +23 -7
  305. package/src/task/render.ts +6 -2
  306. package/src/task/types.ts +108 -0
  307. package/src/tools/ask-answer-registry.ts +12 -6
  308. package/src/tools/ask.ts +169 -118
  309. package/src/tools/ast-edit.ts +1 -0
  310. package/src/tools/ast-grep.ts +1 -0
  311. package/src/tools/bash-interactive.ts +8 -3
  312. package/src/tools/bash.ts +503 -60
  313. package/src/tools/browser/launch.ts +41 -6
  314. package/src/tools/fetch.ts +114 -23
  315. package/src/tools/find.ts +1 -0
  316. package/src/tools/image-gen.ts +29 -5
  317. package/src/tools/index.ts +4 -0
  318. package/src/tools/output-meta.ts +281 -20
  319. package/src/tools/path-utils.ts +8 -3
  320. package/src/tools/read-internals.ts +44 -0
  321. package/src/tools/read.ts +1560 -310
  322. package/src/tools/resource-gc.ts +182 -18
  323. package/src/tools/review.ts +5 -7
  324. package/src/tools/search.ts +1 -0
  325. package/src/tools/subagent-render.ts +6 -2
  326. package/src/tools/subagent.ts +6 -0
  327. package/src/tools/telegram-send.ts +6 -3
  328. package/src/tools/tool-result.ts +14 -1
  329. package/src/utils/gh.ts +39 -0
  330. package/src/utils/image-resize.ts +3 -0
  331. package/src/web/search/providers/anthropic.ts +4 -4
  332. package/src/web/search/providers/codex.ts +1 -1
  333. package/src/web/search/providers/kimi.ts +15 -5
  334. package/src/web/search/providers/searxng.ts +47 -4
  335. package/src/web/search/providers/xai.ts +7 -2
  336. package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
  337. package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
  338. package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
  339. package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
  340. package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
  341. package/src/gjc-runtime/deep-interview-draft.ts +0 -843
  342. package/src/gjc-runtime/deep-interview-payload.ts +0 -262
  343. package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
  344. package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
@@ -0,0 +1,303 @@
1
+ /**
2
+ * Session-scoped durable store for kind-aware invocation reconciliation (#3032/#3035).
3
+ *
4
+ * Path is always a private sibling of the transcript, never under artifactsDir:
5
+ * <dirname(sessionFile)>/.sdk-reconciliation/<safeSessionId>.json
6
+ *
7
+ * Safe session ids only: /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/
8
+ * Atomic write: temp + fsync + rename + 0600. Corrupt → quarantine + empty.
9
+ * Non-terminal skill records settle to failed/process_restart on bootstrap; prompt
10
+ * records finalize their pending outcome or a prompt_failed fallback.
11
+ */
12
+ import * as fs from "node:fs/promises";
13
+ import * as path from "node:path";
14
+ import type { PromptReconciliationStatus, SdkPromptTerminalOutcome } from "../prompt-status";
15
+ import type { PromptCorrelation } from "./prompt-reconciliation";
16
+
17
+ export const RECONCILIATION_STORE_VERSION = 1;
18
+ export const RECONCILIATION_SESSION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
19
+ export const RECONCILIATION_DIR_NAME = ".sdk-reconciliation";
20
+
21
+ export type ReconciliationKind = "prompt" | "skill";
22
+
23
+ export interface DurableReconciliationRecord extends PromptCorrelation {
24
+ kind: ReconciliationKind;
25
+ clientRef?: string;
26
+ status: PromptReconciliationStatus;
27
+ error?: { code: string; message: string };
28
+ acceptedAt: number;
29
+ startedAt?: number;
30
+ terminalAt?: number;
31
+ outcome?: SdkPromptTerminalOutcome;
32
+ pendingOutcome?: SdkPromptTerminalOutcome;
33
+ /** Skill-only safe token; never skill args bodies. */
34
+ skillName?: string;
35
+ }
36
+
37
+ export interface ReconciliationStoreDocument {
38
+ version: typeof RECONCILIATION_STORE_VERSION;
39
+ sessionId: string;
40
+ records: DurableReconciliationRecord[];
41
+ }
42
+
43
+ export interface ReconciliationStoreFs {
44
+ mkdir(directory: string, options: { recursive: true; mode: number }): Promise<unknown>;
45
+ readFile(file: string, encoding: "utf8"): Promise<string>;
46
+ writeFile(file: string, data: string, options: { mode: number }): Promise<void>;
47
+ rename(from: string, to: string): Promise<void>;
48
+ unlink(file: string): Promise<void>;
49
+ open(
50
+ file: string,
51
+ flags: string,
52
+ ): Promise<{
53
+ sync(): Promise<void>;
54
+ close(): Promise<void>;
55
+ writeFile(data: string, encoding: "utf8"): Promise<void>;
56
+ }>;
57
+ }
58
+
59
+ const nodeFs: ReconciliationStoreFs = {
60
+ mkdir: fs.mkdir,
61
+ readFile: fs.readFile,
62
+ writeFile: fs.writeFile,
63
+ rename: fs.rename,
64
+ unlink: fs.unlink,
65
+ open: fs.open as ReconciliationStoreFs["open"],
66
+ };
67
+
68
+ export function isSafeReconciliationSessionId(sessionId: string): boolean {
69
+ return RECONCILIATION_SESSION_ID_PATTERN.test(sessionId);
70
+ }
71
+
72
+ /** Derive private store path; throws if sessionId is unsafe (path escape). */
73
+ export function reconciliationStorePath(sessionFile: string, sessionId: string): string {
74
+ if (!isSafeReconciliationSessionId(sessionId))
75
+ throw Object.assign(new Error("Unsafe session id for reconciliation store path."), {
76
+ code: "invalid_input",
77
+ });
78
+ return path.join(path.dirname(sessionFile), RECONCILIATION_DIR_NAME, `${sessionId}.json`);
79
+ }
80
+
81
+ function isRecord(value: unknown): value is Record<string, unknown> {
82
+ return typeof value === "object" && value !== null && !Array.isArray(value);
83
+ }
84
+
85
+ /** Record-level validation: JSON-valid but malformed entries must be quarantined too. */
86
+ function isValidRecord(value: unknown): boolean {
87
+ if (!isRecord(value)) return false;
88
+ const { kind, commandId, turnId, status, acceptedAt, terminalAt, outcome, pendingOutcome } = value;
89
+ if (kind !== "prompt" && kind !== "skill") return false;
90
+ if (typeof commandId !== "string" || !commandId || typeof turnId !== "string" || !turnId) return false;
91
+ if (status !== "accepted" && status !== "in_flight" && status !== "terminal_ok" && status !== "failed") return false;
92
+ if (typeof acceptedAt !== "number" || !Number.isFinite(acceptedAt)) return false;
93
+ if (terminalAt !== undefined && (typeof terminalAt !== "number" || !Number.isFinite(terminalAt))) return false;
94
+ // Durable invariants: only prompts carry a pending claim, a finalized record has no
95
+ // pending claim left, and terminal/active status must agree with `terminalAt`.
96
+ if (pendingOutcome !== undefined && kind !== "prompt") return false;
97
+ if (pendingOutcome !== undefined && terminalAt !== undefined) return false;
98
+ const isTerminalStatus = status === "terminal_ok" || status === "failed";
99
+ if (isTerminalStatus !== (terminalAt !== undefined)) return false;
100
+ if (outcome !== undefined && !isTerminalStatus) return false;
101
+ if (
102
+ outcome !== undefined &&
103
+ ((status === "terminal_ok" && (!isRecord(outcome) || outcome.kind !== "stopped")) ||
104
+ (status === "failed" && (!isRecord(outcome) || outcome.kind !== "failed")))
105
+ )
106
+ return false;
107
+ if (value.startedAt !== undefined && (typeof value.startedAt !== "number" || !Number.isFinite(value.startedAt)))
108
+ return false;
109
+ if (value.clientRef !== undefined && typeof value.clientRef !== "string") return false;
110
+ if (value.skillName !== undefined && typeof value.skillName !== "string") return false;
111
+ if (value.error !== undefined) {
112
+ if (!isRecord(value.error)) return false;
113
+ if (typeof value.error.code !== "string" || typeof value.error.message !== "string") return false;
114
+ }
115
+ return [outcome, pendingOutcome].every(candidate => {
116
+ if (candidate === undefined) return true;
117
+ if (!isRecord(candidate)) return false;
118
+ if (candidate.kind === "stopped")
119
+ return (
120
+ ["end_turn", "max_tokens", "max_turn_requests", "refusal", "cancelled"].includes(
121
+ candidate.reason as string,
122
+ ) && ["agent", "client_cancel"].includes(candidate.provenance as string)
123
+ );
124
+ return (
125
+ candidate.kind === "failed" &&
126
+ ["prompt_failed", "prompt_deadline_exceeded"].includes(candidate.code as string) &&
127
+ typeof candidate.message === "string" &&
128
+ ["agent_failed", "deadline"].includes(candidate.provenance as string)
129
+ );
130
+ });
131
+ }
132
+
133
+ function parseDocument(raw: string, expectedSessionId: string): ReconciliationStoreDocument {
134
+ const value = JSON.parse(raw) as unknown;
135
+ if (!isRecord(value) || value.version !== RECONCILIATION_STORE_VERSION)
136
+ throw new Error("invalid reconciliation store version");
137
+ if (value.sessionId !== expectedSessionId) throw new Error("session id mismatch");
138
+ if (!Array.isArray(value.records)) throw new Error("invalid records");
139
+ if (!value.records.every(isValidRecord)) throw new Error("invalid reconciliation record");
140
+ return value as unknown as ReconciliationStoreDocument;
141
+ }
142
+
143
+ /**
144
+ * Settle non-terminal durable records after process death.
145
+ * Prompt records preserve a durable pending outcome; skills retain the existing
146
+ * reconciliation-incomplete result.
147
+ */
148
+ export function settleProcessRestart(
149
+ records: DurableReconciliationRecord[],
150
+ now: number,
151
+ ): DurableReconciliationRecord[] {
152
+ return records.map(record => {
153
+ if (record.terminalAt !== undefined) return record;
154
+ if (record.kind === "prompt") {
155
+ const outcome: SdkPromptTerminalOutcome = record.pendingOutcome ?? {
156
+ kind: "failed",
157
+ code: "prompt_failed",
158
+ message: "Prompt did not complete before process restart.",
159
+ provenance: "agent_failed",
160
+ };
161
+ return {
162
+ ...record,
163
+ status: outcome.kind === "stopped" ? "terminal_ok" : "failed",
164
+ terminalAt: now,
165
+ outcome,
166
+ pendingOutcome: undefined,
167
+ ...(outcome.kind === "failed" ? { error: { code: outcome.code, message: outcome.message } } : {}),
168
+ };
169
+ }
170
+ return {
171
+ ...record,
172
+ status: "failed",
173
+ terminalAt: now,
174
+ error: { code: "process_restart", message: "Reconciliation incomplete after process restart." },
175
+ };
176
+ });
177
+ }
178
+
179
+ export interface ReconciliationStore {
180
+ readonly path: string | null;
181
+ readonly sessionId: string;
182
+ /** Serialize mutations; reload not required for single-process host (in-memory + write). */
183
+ transact(mutator: (records: DurableReconciliationRecord[]) => DurableReconciliationRecord[]): Promise<void>;
184
+ load(): Promise<DurableReconciliationRecord[]>;
185
+ /** Snapshot currently held in memory after last load/transact. */
186
+ snapshot(): DurableReconciliationRecord[];
187
+ delete(): Promise<void>;
188
+ }
189
+
190
+ export function createReconciliationStore(options: {
191
+ sessionFile: string | null | undefined;
192
+ sessionId: string;
193
+ fs?: ReconciliationStoreFs;
194
+ now?: () => number;
195
+ }): ReconciliationStore {
196
+ const fileFs = options.fs ?? nodeFs;
197
+ const now = options.now ?? Date.now;
198
+ const sessionId = options.sessionId;
199
+ const filePath =
200
+ options.sessionFile && isSafeReconciliationSessionId(sessionId)
201
+ ? reconciliationStorePath(options.sessionFile, sessionId)
202
+ : null;
203
+
204
+ let memory: DurableReconciliationRecord[] = [];
205
+ let chain: Promise<void> = Promise.resolve();
206
+
207
+ const writeAtomic = async (document: ReconciliationStoreDocument): Promise<void> => {
208
+ if (!filePath) return;
209
+ const directory = path.dirname(filePath);
210
+ await fileFs.mkdir(directory, { recursive: true, mode: 0o700 });
211
+ const temporary = `${filePath}.${process.pid}.${Date.now()}.tmp`;
212
+ try {
213
+ await fileFs.writeFile(temporary, `${JSON.stringify(document)}\n`, { mode: 0o600 });
214
+ try {
215
+ const handle = await fileFs.open(temporary, "r+");
216
+ try {
217
+ await handle.sync();
218
+ } finally {
219
+ await handle.close();
220
+ }
221
+ } catch {
222
+ // fsync optional on some fs seams
223
+ }
224
+ await fileFs.rename(temporary, filePath);
225
+ } catch (error) {
226
+ await fileFs.unlink(temporary).catch(() => {});
227
+ throw Object.assign(error instanceof Error ? error : new Error("reconciliation persist failed"), {
228
+ code: "reconciliation_persist_failed",
229
+ });
230
+ }
231
+ };
232
+
233
+ const load = async (): Promise<DurableReconciliationRecord[]> => {
234
+ if (!filePath) {
235
+ memory = [];
236
+ return memory;
237
+ }
238
+ let raw: string;
239
+ try {
240
+ raw = await fileFs.readFile(filePath, "utf8");
241
+ } catch (error) {
242
+ // Only a missing file is an empty store. Permission/IO failures must propagate
243
+ // so the endpoint never becomes ready as if no prompt had been accepted.
244
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
245
+ memory = [];
246
+ return memory;
247
+ }
248
+ let document: ReconciliationStoreDocument;
249
+ try {
250
+ document = parseDocument(raw, sessionId);
251
+ } catch {
252
+ // Corrupt → quarantine
253
+ try {
254
+ await fileFs.rename(filePath, `${filePath}.corrupt.${now()}`);
255
+ } catch {
256
+ // ignore
257
+ }
258
+ memory = [];
259
+ return memory;
260
+ }
261
+ const settled = settleProcessRestart(document.records, now());
262
+ // Restart settlement must be durable before it is observable: a failed rewrite
263
+ // propagates so the endpoint stays unready instead of serving empty state as if
264
+ // no prompt had ever been accepted.
265
+ if (settled.some((record, index) => record !== document.records[index]))
266
+ await writeAtomic({ version: RECONCILIATION_STORE_VERSION, sessionId, records: settled });
267
+ memory = settled;
268
+ return memory;
269
+ };
270
+
271
+ const transact = async (
272
+ mutator: (records: DurableReconciliationRecord[]) => DurableReconciliationRecord[],
273
+ ): Promise<void> => {
274
+ const run = async () => {
275
+ const next = mutator(memory.map(r => ({ ...r })));
276
+ await writeAtomic({ version: RECONCILIATION_STORE_VERSION, sessionId, records: next });
277
+ memory = next;
278
+ };
279
+ const pending = chain.then(run, run);
280
+ chain = pending.then(
281
+ () => undefined,
282
+ () => undefined,
283
+ );
284
+ await pending;
285
+ };
286
+
287
+ const deleteStore = async (): Promise<void> => {
288
+ memory = [];
289
+ if (!filePath) return;
290
+ await fileFs.unlink(filePath).catch(error => {
291
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
292
+ });
293
+ };
294
+
295
+ return {
296
+ path: filePath,
297
+ sessionId,
298
+ transact,
299
+ load,
300
+ snapshot: () => memory.map(r => ({ ...r })),
301
+ delete: deleteStore,
302
+ };
303
+ }
@@ -88,7 +88,7 @@ export class DraftStreamState {
88
88
  */
89
89
  export async function deliverDraft(
90
90
  botApi: BotApi,
91
- base: { chat_id: string | number; message_thread_id?: number },
91
+ base: { chat_id: string | number; message_thread_id?: number; disable_notification?: true },
92
92
  draftId: number,
93
93
  raw: string,
94
94
  log?: { warn(msg: string): void },
@@ -62,7 +62,7 @@ export function shouldPromoteRich(input: { enabled?: boolean; send: ThreadedSend
62
62
  */
63
63
  export async function deliverRichWithFallback(
64
64
  botApi: BotApi,
65
- base: { chat_id: string | number; message_thread_id?: number },
65
+ base: { chat_id: string | number; message_thread_id?: number; disable_notification?: true },
66
66
  send: ThreadedSend,
67
67
  signal: AbortSignal,
68
68
  fallbackDeliver: () => Promise<void>,
@@ -99,7 +99,7 @@ export async function deliverRichWithFallback(
99
99
  */
100
100
  export async function deliverRichActionWithFallback(
101
101
  botApi: BotApi,
102
- base: { chat_id: string | number; message_thread_id?: number },
102
+ base: { chat_id: string | number; message_thread_id?: number; disable_notification?: true },
103
103
  opts: { markdown: string; replyMarkup?: unknown },
104
104
  signal: AbortSignal,
105
105
  htmlFallback: () => Promise<number | undefined>,