@gajae-code/coding-agent 0.10.2 → 0.11.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 (476) hide show
  1. package/CHANGELOG.md +58 -2
  2. package/dist/types/append-only-mode.d.ts +1 -1
  3. package/dist/types/async/job-manager.d.ts +46 -7
  4. package/dist/types/cli/args.d.ts +4 -5
  5. package/dist/types/cli/daemon-cli.d.ts +12 -1
  6. package/dist/types/cli/notify-cli.d.ts +21 -1
  7. package/dist/types/cli.d.ts +3 -0
  8. package/dist/types/commands/daemon.d.ts +39 -0
  9. package/dist/types/commands/launch.d.ts +3 -0
  10. package/dist/types/commands/notify.d.ts +28 -1
  11. package/dist/types/commands/sdk.d.ts +33 -0
  12. package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
  13. package/dist/types/config/model-profile-activation.d.ts +35 -15
  14. package/dist/types/config/model-profiles.d.ts +11 -5
  15. package/dist/types/config/model-registry.d.ts +3 -3
  16. package/dist/types/config/model-resolver.d.ts +39 -6
  17. package/dist/types/config/model-selector-value.d.ts +17 -0
  18. package/dist/types/config/models-config-schema.d.ts +10 -6
  19. package/dist/types/config/settings-schema.d.ts +133 -6
  20. package/dist/types/config/settings.d.ts +63 -35
  21. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
  22. package/dist/types/coordinator-mcp/server.d.ts +6 -49
  23. package/dist/types/daemon/builtin.d.ts +6 -5
  24. package/dist/types/daemon/control-types.d.ts +1 -1
  25. package/dist/types/discovery/mcp-json.d.ts +12 -1
  26. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  27. package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
  28. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
  29. package/dist/types/extensibility/extensions/loader.d.ts +10 -1
  30. package/dist/types/extensibility/extensions/runner.d.ts +3 -3
  31. package/dist/types/extensibility/extensions/types.d.ts +141 -16
  32. package/dist/types/extensibility/hooks/types.d.ts +1 -1
  33. package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
  34. package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
  35. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
  36. package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
  37. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
  38. package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
  39. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +11 -0
  40. package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
  41. package/dist/types/harness-control-plane/operate.d.ts +5 -5
  42. package/dist/types/harness-control-plane/owner.d.ts +18 -4
  43. package/dist/types/harness-control-plane/receipts.d.ts +0 -1
  44. package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
  45. package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
  46. package/dist/types/harness-control-plane/types.d.ts +3 -4
  47. package/dist/types/lsp/index.d.ts +1 -1
  48. package/dist/types/main.d.ts +32 -38
  49. package/dist/types/modes/acp/acp-agent.d.ts +224 -53
  50. package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
  51. package/dist/types/modes/acp/acp-mode.d.ts +6 -15
  52. package/dist/types/modes/acp/permission-mode.d.ts +4 -0
  53. package/dist/types/modes/acp/startup-options.d.ts +6 -0
  54. package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
  55. package/dist/types/modes/components/model-selector.d.ts +1 -0
  56. package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
  57. package/dist/types/modes/components/settings-selector.d.ts +6 -4
  58. package/dist/types/modes/components/welcome.d.ts +1 -1
  59. package/dist/types/modes/controllers/command-controller.d.ts +2 -2
  60. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -0
  61. package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
  62. package/dist/types/modes/index.d.ts +0 -4
  63. package/dist/types/modes/interactive-mode.d.ts +5 -2
  64. package/dist/types/modes/runtime-init.d.ts +2 -2
  65. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
  66. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
  67. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
  68. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
  69. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
  70. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +170 -30
  71. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
  72. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
  73. package/dist/types/modes/types.d.ts +7 -2
  74. package/dist/types/runtime-mcp/client.d.ts +2 -0
  75. package/dist/types/runtime-mcp/config.d.ts +5 -1
  76. package/dist/types/runtime-mcp/manager.d.ts +8 -1
  77. package/dist/types/runtime-mcp/types.d.ts +4 -0
  78. package/dist/types/sdk/acp/adapter.d.ts +67 -0
  79. package/dist/types/sdk/acp/index.d.ts +2 -0
  80. package/dist/types/sdk/broker/broker.d.ts +53 -0
  81. package/dist/types/sdk/broker/discovery.d.ts +30 -0
  82. package/dist/types/sdk/broker/ensure.d.ts +42 -0
  83. package/dist/types/sdk/broker/identity.d.ts +3 -0
  84. package/dist/types/sdk/broker/index.d.ts +8 -0
  85. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
  86. package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
  87. package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
  88. package/dist/types/sdk/broker/runtime.d.ts +33 -0
  89. package/dist/types/sdk/broker/session-index.d.ts +57 -0
  90. package/dist/types/sdk/broker/state-version.d.ts +8 -0
  91. package/dist/types/sdk/broker/transport.d.ts +9 -0
  92. package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
  93. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
  94. package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
  95. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
  96. package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
  97. package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
  98. package/dist/types/sdk/bus/config.d.ts +274 -0
  99. package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
  100. package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
  101. package/dist/types/sdk/bus/discord-daemon.d.ts +50 -0
  102. package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
  103. package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
  104. package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
  105. package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
  106. package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
  107. package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
  108. package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
  109. package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
  110. package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
  111. package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
  112. package/dist/types/sdk/bus/session-control.d.ts +83 -0
  113. package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
  114. package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
  115. package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
  116. package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
  117. package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
  118. package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
  119. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
  120. package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
  121. package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +78 -17
  122. package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
  123. package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
  124. package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
  125. package/dist/types/sdk/cli/index.d.ts +1 -0
  126. package/dist/types/sdk/cli/session-cli.d.ts +19 -0
  127. package/dist/types/sdk/client/client.d.ts +1 -0
  128. package/dist/types/sdk/client/discovery.d.ts +27 -0
  129. package/dist/types/sdk/client/index.d.ts +2 -0
  130. package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
  131. package/dist/types/sdk/host/control/index.d.ts +2 -0
  132. package/dist/types/sdk/host/control/operations.d.ts +65 -0
  133. package/dist/types/sdk/host/events.d.ts +35 -0
  134. package/dist/types/sdk/host/host.d.ts +35 -0
  135. package/dist/types/sdk/host/index.d.ts +4 -0
  136. package/dist/types/sdk/host/query/cursor.d.ts +62 -0
  137. package/dist/types/sdk/host/query/handlers.d.ts +70 -0
  138. package/dist/types/sdk/host/query/index.d.ts +3 -0
  139. package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
  140. package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
  141. package/dist/types/sdk/host/types.d.ts +32 -0
  142. package/dist/types/sdk/index.d.ts +6 -0
  143. package/dist/types/sdk/lifecycle-session.d.ts +14 -0
  144. package/dist/types/sdk/mcp/index.d.ts +1 -0
  145. package/dist/types/sdk/mcp/server.d.ts +37 -0
  146. package/dist/types/sdk/models.d.ts +44 -0
  147. package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
  148. package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
  149. package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
  150. package/dist/types/sdk/startup-capability.d.ts +50 -0
  151. package/dist/types/session/agent-session.d.ts +114 -21
  152. package/dist/types/session/default-model-selection.d.ts +25 -0
  153. package/dist/types/session/fallback-chain-controller.d.ts +52 -0
  154. package/dist/types/session/session-manager.d.ts +58 -1
  155. package/dist/types/setup/credential-auto-import.d.ts +36 -6
  156. package/dist/types/tools/ask-answer-registry.d.ts +1 -1
  157. package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
  158. package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
  159. package/dist/types/tools/browser/launch.d.ts +22 -0
  160. package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
  161. package/dist/types/tools/browser/profile-posture.d.ts +37 -0
  162. package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
  163. package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
  164. package/dist/types/tools/browser/registry.d.ts +19 -0
  165. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  166. package/dist/types/tools/index.d.ts +8 -8
  167. package/dist/types/tools/subagent-render.d.ts +1 -0
  168. package/dist/types/tools/subagent.d.ts +6 -1
  169. package/package.json +34 -13
  170. package/scripts/build-sdk-package-smoke.ts +99 -0
  171. package/scripts/capture-notifications-settings-showcase.ts +435 -0
  172. package/scripts/compile-args.ts +4 -2
  173. package/scripts/g005-daemon-smoke.ts +4 -5
  174. package/scripts/g011-daemon-path-smoke.ts +5 -5
  175. package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
  176. package/scripts/generate-sdk-operation-inventory.ts +867 -0
  177. package/scripts/generate-telegram-baseline-manifest.ts +128 -0
  178. package/scripts/manifest-schema.ts +124 -0
  179. package/scripts/run-test-manifest.ts +153 -0
  180. package/scripts/run-threat-model-check.ts +157 -0
  181. package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
  182. package/scripts/verify-gjc-sdk-rename.ts +90 -0
  183. package/src/append-only-mode.ts +1 -1
  184. package/src/async/job-manager.ts +406 -63
  185. package/src/cli/args.ts +43 -12
  186. package/src/cli/auth-gateway-cli.ts +2 -2
  187. package/src/cli/config-cli.ts +2 -1
  188. package/src/cli/daemon-cli.ts +63 -14
  189. package/src/cli/list-models.ts +1 -1
  190. package/src/cli/notify-cli.ts +288 -286
  191. package/src/cli.ts +21 -2
  192. package/src/commands/daemon.ts +50 -6
  193. package/src/commands/harness.ts +93 -36
  194. package/src/commands/launch.ts +5 -2
  195. package/src/commands/mcp-serve.ts +19 -12
  196. package/src/commands/notify.ts +36 -3
  197. package/src/commands/sdk.ts +426 -0
  198. package/src/commit/agentic/agent.ts +1 -0
  199. package/src/config/atomic-yaml-patch.ts +423 -0
  200. package/src/config/model-profile-activation.ts +240 -89
  201. package/src/config/model-profiles.ts +18 -15
  202. package/src/config/model-registry.ts +51 -26
  203. package/src/config/model-resolver.ts +138 -51
  204. package/src/config/model-selector-value.ts +50 -0
  205. package/src/config/models-config-schema.ts +14 -21
  206. package/src/config/settings-schema.ts +128 -10
  207. package/src/config/settings.ts +1120 -158
  208. package/src/coordinator-mcp/model-preset.ts +74 -20
  209. package/src/coordinator-mcp/server.ts +1597 -3052
  210. package/src/daemon/builtin.ts +8 -5
  211. package/src/daemon/control-types.ts +1 -1
  212. package/src/defaults/gjc/skills/team/SKILL.md +4 -4
  213. package/src/discovery/mcp-json.ts +327 -20
  214. package/src/extensibility/custom-tools/types.ts +1 -1
  215. package/src/extensibility/extensions/compact-handler.ts +3 -3
  216. package/src/extensibility/extensions/get-commands-handler.ts +2 -2
  217. package/src/extensibility/extensions/loader.ts +69 -5
  218. package/src/extensibility/extensions/runner.ts +112 -4
  219. package/src/extensibility/extensions/types.ts +176 -17
  220. package/src/extensibility/hooks/types.ts +1 -1
  221. package/src/gjc-runtime/launch-tmux.ts +170 -86
  222. package/src/gjc-runtime/psmux-detect.ts +82 -4
  223. package/src/gjc-runtime/session-state-sidecar.ts +41 -31
  224. package/src/gjc-runtime/team-runtime.ts +54 -35
  225. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
  226. package/src/gjc-runtime/tmux-owner-isolation.ts +1 -1
  227. package/src/gjc-runtime/tmux-sessions.ts +19 -13
  228. package/src/gjc-runtime/ultragoal-guard.ts +108 -14
  229. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +102 -1
  230. package/src/gjc-runtime/ultragoal-runtime.ts +227 -11
  231. package/src/gjc-runtime/windows-powershell-command.ts +58 -0
  232. package/src/harness-control-plane/operate.ts +9 -9
  233. package/src/harness-control-plane/owner.ts +283 -39
  234. package/src/harness-control-plane/receipts.ts +0 -1
  235. package/src/harness-control-plane/sdk-transport.ts +395 -0
  236. package/src/harness-control-plane/session-transport.ts +94 -0
  237. package/src/harness-control-plane/types.ts +1 -1
  238. package/src/internal-urls/docs-index.generated.ts +34 -35
  239. package/src/lsp/client.ts +42 -6
  240. package/src/lsp/index.ts +2 -2
  241. package/src/main.ts +299 -204
  242. package/src/modes/DESIGN.md +258 -0
  243. package/src/modes/acp/acp-agent.ts +1228 -2612
  244. package/src/modes/acp/acp-client-bridge.ts +2 -20
  245. package/src/modes/acp/acp-event-mapper.ts +18 -2
  246. package/src/modes/acp/acp-mode.ts +8 -36
  247. package/src/modes/acp/permission-mode.ts +25 -0
  248. package/src/modes/acp/startup-options.ts +6 -0
  249. package/src/modes/components/agent-dashboard.ts +37 -17
  250. package/src/modes/components/model-selector.ts +93 -35
  251. package/src/modes/components/notifications-settings-editor.ts +1379 -0
  252. package/src/modes/components/settings-selector.ts +60 -11
  253. package/src/modes/components/welcome.ts +4 -4
  254. package/src/modes/controllers/command-controller.ts +10 -17
  255. package/src/modes/controllers/event-controller.ts +11 -16
  256. package/src/modes/controllers/extension-ui-controller.ts +396 -28
  257. package/src/modes/controllers/selector-controller.ts +674 -36
  258. package/src/modes/index.ts +0 -22
  259. package/src/modes/interactive-mode.ts +87 -36
  260. package/src/modes/runtime-init.ts +298 -6
  261. package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
  262. package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
  263. package/src/modes/shared/agent-wire/event-contract.ts +7 -8
  264. package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
  265. package/src/modes/shared/agent-wire/event-observation.ts +16 -7
  266. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1258 -87
  267. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
  268. package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
  269. package/src/modes/types.ts +7 -2
  270. package/src/runtime-mcp/client.ts +94 -19
  271. package/src/runtime-mcp/config.ts +27 -15
  272. package/src/runtime-mcp/manager.ts +343 -105
  273. package/src/runtime-mcp/oauth-flow.ts +42 -12
  274. package/src/runtime-mcp/transports/http.ts +49 -19
  275. package/src/runtime-mcp/transports/stdio.ts +47 -28
  276. package/src/runtime-mcp/types.ts +10 -0
  277. package/src/sdk/acp/adapter.ts +418 -0
  278. package/src/sdk/acp/index.ts +2 -0
  279. package/src/sdk/broker/broker.ts +642 -0
  280. package/src/sdk/broker/discovery.ts +113 -0
  281. package/src/sdk/broker/ensure.ts +307 -0
  282. package/src/sdk/broker/identity.ts +42 -0
  283. package/src/sdk/broker/index.ts +8 -0
  284. package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
  285. package/src/sdk/broker/internal-source.bunfig.toml +1 -0
  286. package/src/sdk/broker/lifecycle-ledger.ts +286 -0
  287. package/src/sdk/broker/lifecycle.ts +2157 -0
  288. package/src/sdk/broker/process-incarnation.ts +159 -0
  289. package/src/sdk/broker/runtime.ts +164 -0
  290. package/src/sdk/broker/session-index.ts +318 -0
  291. package/src/sdk/broker/state-version.ts +23 -0
  292. package/src/sdk/broker/transport.ts +125 -0
  293. package/src/sdk/bus/chat-command-policy.ts +107 -0
  294. package/src/sdk/bus/chat-daemon-cli.ts +214 -0
  295. package/src/sdk/bus/chat-daemon-control.ts +713 -0
  296. package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
  297. package/src/sdk/bus/chat-effect-journal.ts +355 -0
  298. package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
  299. package/src/sdk/bus/config.ts +433 -0
  300. package/src/sdk/bus/conversation-store.ts +391 -0
  301. package/src/sdk/bus/discord-conversation.ts +85 -0
  302. package/src/sdk/bus/discord-daemon.ts +2292 -0
  303. package/src/sdk/bus/discord-live-provider.ts +521 -0
  304. package/src/sdk/bus/discord-provider.ts +56 -0
  305. package/src/{notifications → sdk/bus}/html-format.ts +2 -2
  306. package/src/sdk/bus/index.ts +3979 -0
  307. package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
  308. package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
  309. package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
  310. package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
  311. package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
  312. package/src/sdk/bus/natives-augment.d.ts +38 -0
  313. package/src/sdk/bus/notification-orchestration.ts +535 -0
  314. package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
  315. package/src/sdk/bus/session-control.ts +333 -0
  316. package/src/sdk/bus/slack-conversation.ts +74 -0
  317. package/src/sdk/bus/slack-daemon.ts +2144 -0
  318. package/src/sdk/bus/slack-live-provider.ts +380 -0
  319. package/src/sdk/bus/slack-provider.ts +76 -0
  320. package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
  321. package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
  322. package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
  323. package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
  324. package/src/{notifications → sdk/bus}/telegram-daemon.ts +603 -63
  325. package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
  326. package/src/sdk/bus/telegram-setup.ts +663 -0
  327. package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
  328. package/src/sdk/cli/index.ts +1 -0
  329. package/src/sdk/cli/session-cli.ts +275 -0
  330. package/src/sdk/client/client.ts +1 -0
  331. package/src/sdk/client/discovery.ts +108 -0
  332. package/src/sdk/client/index.ts +2 -0
  333. package/src/sdk/host/control/dispatch.ts +367 -0
  334. package/src/sdk/host/control/index.ts +10 -0
  335. package/src/sdk/host/control/operations.ts +63 -0
  336. package/src/sdk/host/events.ts +91 -0
  337. package/src/sdk/host/host.ts +296 -0
  338. package/src/sdk/host/index.ts +4 -0
  339. package/src/sdk/host/query/cursor.ts +189 -0
  340. package/src/sdk/host/query/handlers.ts +533 -0
  341. package/src/sdk/host/query/index.ts +3 -0
  342. package/src/sdk/host/query/revision-store.ts +1126 -0
  343. package/src/sdk/host/reverse-leases.ts +325 -0
  344. package/src/sdk/host/types.ts +29 -0
  345. package/src/sdk/index.ts +13 -0
  346. package/src/sdk/lifecycle-session.ts +39 -0
  347. package/src/sdk/mcp/index.ts +1 -0
  348. package/src/sdk/mcp/server.ts +332 -0
  349. package/src/sdk/models.ts +168 -0
  350. package/src/sdk/protocol/adapter-validation.ts +48 -0
  351. package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
  352. package/src/sdk/protocol/operation-registry.ts +312 -0
  353. package/src/{sdk.ts → sdk/session.ts} +339 -212
  354. package/src/sdk/startup-capability.ts +189 -0
  355. package/src/session/agent-session.ts +2650 -944
  356. package/src/session/default-model-selection.ts +93 -0
  357. package/src/session/fallback-chain-controller.ts +136 -0
  358. package/src/session/session-manager.ts +438 -11
  359. package/src/session/session-storage.ts +8 -1
  360. package/src/setup/credential-auto-import.ts +290 -35
  361. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
  362. package/src/slash-commands/builtin-registry.ts +2 -1
  363. package/src/task/executor.ts +62 -13
  364. package/src/task/index.ts +26 -16
  365. package/src/tools/ask-answer-registry.ts +1 -1
  366. package/src/tools/ask.ts +13 -8
  367. package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
  368. package/src/tools/browser/benchmark/detector-report.ts +157 -0
  369. package/src/tools/browser/benchmark/run-suite.ts +39 -0
  370. package/src/tools/browser/launch.ts +124 -19
  371. package/src/tools/browser/profile-discovery.ts +63 -0
  372. package/src/tools/browser/profile-posture.ts +59 -0
  373. package/src/tools/browser/profile-reuse.ts +102 -0
  374. package/src/tools/browser/profile-warmup.ts +109 -0
  375. package/src/tools/browser/registry.ts +87 -11
  376. package/src/tools/browser/tab-protocol.ts +1 -0
  377. package/src/tools/browser/tab-supervisor.ts +1 -0
  378. package/src/tools/browser/tab-worker.ts +1 -1
  379. package/src/tools/browser.ts +6 -0
  380. package/src/tools/index.ts +8 -8
  381. package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
  382. package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
  383. package/src/tools/subagent-render.ts +19 -8
  384. package/src/tools/subagent.ts +84 -32
  385. package/src/tools/telegram-send.ts +2 -2
  386. package/vendor/insane-search/MANIFEST.json +2 -1
  387. package/vendor/insane-search/engine/bias_check.py +4 -1
  388. package/vendor/insane-search/engine/phase0.py +26 -1
  389. package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
  390. package/dist/types/modes/bridge/auth.d.ts +0 -12
  391. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
  392. package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
  393. package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
  394. package/dist/types/modes/bridge/event-stream.d.ts +0 -8
  395. package/dist/types/modes/rpc/host-tools.d.ts +0 -1
  396. package/dist/types/modes/rpc/host-uris.d.ts +0 -1
  397. package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
  398. package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
  399. package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
  400. package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
  401. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
  402. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
  403. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
  404. package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
  405. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
  406. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
  407. package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
  408. package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
  409. package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
  410. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
  411. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
  412. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
  413. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
  414. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
  415. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
  416. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
  417. package/dist/types/notifications/config.d.ts +0 -132
  418. package/src/harness-control-plane/rpc-adapter.ts +0 -290
  419. package/src/modes/bridge/auth.ts +0 -41
  420. package/src/modes/bridge/bridge-client-bridge.ts +0 -47
  421. package/src/modes/bridge/bridge-mode.ts +0 -675
  422. package/src/modes/bridge/bridge-ui-context.ts +0 -200
  423. package/src/modes/bridge/event-stream.ts +0 -70
  424. package/src/modes/rpc/host-tools.ts +0 -1
  425. package/src/modes/rpc/host-uris.ts +0 -1
  426. package/src/modes/rpc/rpc-client.ts +0 -1166
  427. package/src/modes/rpc/rpc-mode.ts +0 -1029
  428. package/src/modes/rpc/rpc-socket-security.ts +0 -115
  429. package/src/modes/rpc/rpc-types.ts +0 -637
  430. package/src/modes/shared/agent-wire/command-contract.ts +0 -18
  431. package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
  432. package/src/modes/shared/agent-wire/command-validation.ts +0 -181
  433. package/src/modes/shared/agent-wire/handshake.ts +0 -157
  434. package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
  435. package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
  436. package/src/modes/shared/agent-wire/protocol.ts +0 -46
  437. package/src/modes/shared/agent-wire/responses.ts +0 -17
  438. package/src/modes/shared/agent-wire/scopes.ts +0 -94
  439. package/src/modes/shared/agent-wire/session-registry.ts +0 -109
  440. package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
  441. package/src/modes/shared/agent-wire/ui-result.ts +0 -48
  442. package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
  443. package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
  444. package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
  445. package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
  446. package/src/notifications/config.ts +0 -219
  447. package/src/notifications/index.ts +0 -1835
  448. package/src/notifications/telegram-daemon-cli.ts +0 -243
  449. package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
  450. /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
  451. /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
  452. /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
  453. /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
  454. /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
  455. /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
  456. /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
  457. /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
  458. /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
  459. /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
  460. /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
  461. /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
  462. /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
  463. /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
  464. /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
  465. /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
  466. /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
  467. /package/src/{notifications → sdk/bus}/engine.ts +0 -0
  468. /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
  469. /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
  470. /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
  471. /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
  472. /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
  473. /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
  474. /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
  475. /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
  476. /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
@@ -0,0 +1,423 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+ import { YAML } from "bun";
5
+ import { withFileLock } from "./file-lock";
6
+
7
+ export interface AtomicYamlSetPatch {
8
+ path: string;
9
+ op: "set";
10
+ value: unknown;
11
+ }
12
+
13
+ export interface AtomicYamlUnsetPatch {
14
+ path: string;
15
+ op: "unset";
16
+ }
17
+
18
+ export type AtomicYamlPatch = AtomicYamlSetPatch | AtomicYamlUnsetPatch;
19
+
20
+ export interface AtomicYamlPatchRevision {
21
+ path: string;
22
+ beforeHash: string;
23
+ afterHash: string;
24
+ beforeRevision: number;
25
+ afterRevision: number;
26
+ }
27
+
28
+ export type CasRestoreResult =
29
+ | { status: "restored"; receipt: CasReceipt }
30
+ | { status: "conflict"; paths: readonly string[] }
31
+ | { status: "discarded" };
32
+
33
+ /**
34
+ * A receipt intentionally exposes only path-level hashes and opaque revisions.
35
+ * The before values needed by restore stay in this module's closure.
36
+ */
37
+ export interface CasReceipt {
38
+ readonly revisions: readonly AtomicYamlPatchRevision[];
39
+ restore(): Promise<CasRestoreResult>;
40
+ discard(): void;
41
+ }
42
+
43
+ export interface AtomicYamlUpdate<T> {
44
+ apply(current: Record<string, unknown>): T | Promise<T>;
45
+ shouldWrite?(result: T): boolean;
46
+ committed?(current: Record<string, unknown>, result: T): void | Promise<void>;
47
+ }
48
+
49
+ export interface AtomicYamlPatchOptions {
50
+ /** Test seam for deterministic pre-rename and Windows sharing-violation failures. */
51
+ rename?: (from: string, to: string) => Promise<void>;
52
+ /** Test seam for bounded retry timing. */
53
+ sleep?: (ms: number) => Promise<void>;
54
+ /** Test seam for Windows rename retry behavior. */
55
+ platform?: NodeJS.Platform;
56
+ /** Called under the config lock after a successful CAS restore. */
57
+ onRestored?: (patches: readonly AtomicYamlPatch[]) => void | Promise<void>;
58
+ }
59
+
60
+ /** A replacement failure never unlinks the destination as a fallback. */
61
+ export class AtomicYamlReplaceError extends Error {
62
+ readonly code = "ATOMIC_YAML_REPLACE_FAILED";
63
+
64
+ constructor(
65
+ readonly configPath: string,
66
+ readonly attempts: number,
67
+ readonly cause: unknown,
68
+ ) {
69
+ super(`Failed to atomically replace ${configPath} after ${attempts} rename attempts.`);
70
+ this.name = "AtomicYamlReplaceError";
71
+ }
72
+ }
73
+
74
+ type PathState = { exists: boolean; value: unknown };
75
+ type ReceiptChange = {
76
+ path: string;
77
+ before: PathState;
78
+ after: PathState;
79
+ publicRevision: AtomicYamlPatchRevision;
80
+ };
81
+
82
+ const queues = new Map<string, Promise<void>>();
83
+ let nextReceiptRevision = 0;
84
+ /** Bounded Windows sharing-violation retries: 10, 25, 50, 100, then 200 ms. */
85
+ const WINDOWS_RENAME_BACKOFF_MS = [10, 25, 50, 100, 200] as const;
86
+ const WINDOWS_SHARING_VIOLATION_CODES = new Set(["EPERM", "EACCES", "EBUSY"]);
87
+
88
+ function canonicalConfigPath(configPath: string): string {
89
+ return path.normalize(path.resolve(configPath));
90
+ }
91
+
92
+ function assertPatch(patch: AtomicYamlPatch): void {
93
+ if (
94
+ !patch ||
95
+ typeof patch.path !== "string" ||
96
+ patch.path.length === 0 ||
97
+ patch.path.split(".").some(part => !part)
98
+ ) {
99
+ throw new Error("Atomic YAML patches require a non-empty dotted path.");
100
+ }
101
+ if (patch.op === "set") {
102
+ if (patch.value === undefined) {
103
+ throw new TypeError(`Atomic YAML set patch for ${patch.path} cannot carry undefined; use unset instead.`);
104
+ }
105
+ return;
106
+ }
107
+ if (patch.op !== "unset") {
108
+ throw new Error(`Unknown atomic YAML patch operation: ${(patch as { op?: unknown }).op}`);
109
+ }
110
+ }
111
+
112
+ function record(value: unknown): Record<string, unknown> | undefined {
113
+ return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
114
+ }
115
+
116
+ function stateAtPath(value: Record<string, unknown>, segments: readonly string[]): PathState {
117
+ let current: Record<string, unknown> = value;
118
+ for (let index = 0; index < segments.length - 1; index++) {
119
+ const next = record(current[segments[index]!]);
120
+ if (!next) return { exists: false, value: undefined };
121
+ current = next;
122
+ }
123
+ const key = segments[segments.length - 1]!;
124
+ return Object.hasOwn(current, key) ? { exists: true, value: current[key] } : { exists: false, value: undefined };
125
+ }
126
+
127
+ /** Set a dotted YAML path, creating object intermediates as needed. */
128
+ export function setByPath(value: Record<string, unknown>, segments: readonly string[], nextValue: unknown): void {
129
+ let current = value;
130
+ for (let index = 0; index < segments.length - 1; index++) {
131
+ const segment = segments[index]!;
132
+ const next = record(current[segment]);
133
+ if (!next) current[segment] = {};
134
+ current = current[segment] as Record<string, unknown>;
135
+ }
136
+ current[segments[segments.length - 1]!] = nextValue;
137
+ }
138
+
139
+ /** Delete a dotted YAML path without disturbing sibling keys or parent objects. */
140
+ export function deleteByPath(value: Record<string, unknown>, segments: readonly string[]): void {
141
+ let current = value;
142
+ for (let index = 0; index < segments.length - 1; index++) {
143
+ const next = record(current[segments[index]!]);
144
+ if (!next) return;
145
+ current = next;
146
+ }
147
+ delete current[segments[segments.length - 1]!];
148
+ }
149
+
150
+ function stableValue(value: unknown): string {
151
+ if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "undefined";
152
+ if (Array.isArray(value)) return `[${value.map(stableValue).join(",")}]`;
153
+ const object = value as Record<string, unknown>;
154
+ return `{${Object.keys(object)
155
+ .sort()
156
+ .map(key => `${JSON.stringify(key)}:${stableValue(object[key])}`)
157
+ .join(",")}}`;
158
+ }
159
+
160
+ function stateHash(state: PathState): string {
161
+ return createHash("sha256")
162
+ .update(state.exists ? `present:${stableValue(state.value)}` : "absent")
163
+ .digest("hex");
164
+ }
165
+
166
+ function cloneState(state: PathState): PathState {
167
+ return state.exists ? { exists: true, value: structuredClone(state.value) } : state;
168
+ }
169
+
170
+ async function readYaml(configPath: string): Promise<Record<string, unknown>> {
171
+ try {
172
+ const parsed = YAML.parse(await fs.readFile(configPath, "utf8"));
173
+ return record(parsed) ?? {};
174
+ } catch (error) {
175
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return {};
176
+ throw error;
177
+ }
178
+ }
179
+
180
+ async function syncParentDirectory(directory: string): Promise<void> {
181
+ try {
182
+ const directoryHandle = await fs.open(directory, "r");
183
+ try {
184
+ await directoryHandle.sync();
185
+ } finally {
186
+ await directoryHandle.close();
187
+ }
188
+ } catch {
189
+ // Directory fsync is not supported by every platform/filesystem. The renamed
190
+ // destination remains valid even where the durability barrier is unavailable.
191
+ }
192
+ }
193
+
194
+ async function replaceWithRetry(tempPath: string, configPath: string, options: AtomicYamlPatchOptions): Promise<void> {
195
+ const rename = options.rename ?? fs.rename;
196
+ const sleep = options.sleep ?? (async (delay: number): Promise<void> => await Bun.sleep(delay));
197
+ const isWindows = (options.platform ?? process.platform) === "win32";
198
+ let attempts = 0;
199
+
200
+ for (;;) {
201
+ attempts++;
202
+ try {
203
+ await rename(tempPath, configPath);
204
+ return;
205
+ } catch (error) {
206
+ const code = (error as NodeJS.ErrnoException).code;
207
+ const retryDelay = WINDOWS_RENAME_BACKOFF_MS[attempts - 1];
208
+ if (!isWindows || !code || !WINDOWS_SHARING_VIOLATION_CODES.has(code) || retryDelay === undefined) {
209
+ if (isWindows && code && WINDOWS_SHARING_VIOLATION_CODES.has(code)) {
210
+ throw new AtomicYamlReplaceError(configPath, attempts, error);
211
+ }
212
+ throw error;
213
+ }
214
+ await sleep(retryDelay);
215
+ }
216
+ }
217
+ }
218
+
219
+ async function writeAtomicYaml(
220
+ configPath: string,
221
+ value: Record<string, unknown>,
222
+ options: AtomicYamlPatchOptions,
223
+ ): Promise<void> {
224
+ const directory = path.dirname(configPath);
225
+ const tempPath = path.join(directory, `.${path.basename(configPath)}.${process.pid}.${randomUUID()}.tmp`);
226
+ try {
227
+ const tempHandle = await fs.open(tempPath, "wx", 0o600);
228
+ try {
229
+ await tempHandle.writeFile(YAML.stringify(value, null, 2), "utf8");
230
+ await tempHandle.sync();
231
+ } finally {
232
+ await tempHandle.close();
233
+ }
234
+ await replaceWithRetry(tempPath, configPath, options);
235
+ await syncParentDirectory(directory);
236
+ } finally {
237
+ await fs.rm(tempPath, { force: true }).catch(() => undefined);
238
+ }
239
+ }
240
+
241
+ function createReceipt(
242
+ configPath: string,
243
+ changes: readonly ReceiptChange[],
244
+ options: AtomicYamlPatchOptions,
245
+ ): CasReceipt {
246
+ let discarded = false;
247
+ const revisions = changes.map(change => change.publicRevision);
248
+
249
+ return {
250
+ revisions,
251
+ discard(): void {
252
+ discarded = true;
253
+ },
254
+ async restore(): Promise<CasRestoreResult> {
255
+ if (discarded) return { status: "discarded" };
256
+ return await enqueueAtomicYamlOperation(configPath, async canonicalPath => {
257
+ return await withFileLock(canonicalPath, async () => {
258
+ const current = await readYaml(canonicalPath);
259
+ const conflicts = changes
260
+ .filter(
261
+ change =>
262
+ stateHash(stateAtPath(current, change.path.split("."))) !== change.publicRevision.afterHash,
263
+ )
264
+ .map(change => change.path);
265
+ if (conflicts.length > 0) return { status: "conflict", paths: conflicts };
266
+
267
+ const restorePatches: AtomicYamlPatch[] = changes.map(change =>
268
+ change.before.exists
269
+ ? { path: change.path, op: "set", value: structuredClone(change.before.value) }
270
+ : { path: change.path, op: "unset" },
271
+ );
272
+ const receipt = await applyPatchesUnderLock(canonicalPath, current, restorePatches, options);
273
+ await options.onRestored?.(restorePatches);
274
+ return { status: "restored", receipt };
275
+ });
276
+ });
277
+ },
278
+ };
279
+ }
280
+
281
+ async function applyPatchesUnderLock(
282
+ configPath: string,
283
+ current: Record<string, unknown>,
284
+ patches: readonly AtomicYamlPatch[],
285
+ options: AtomicYamlPatchOptions,
286
+ ): Promise<CasReceipt> {
287
+ if (patches.length === 0) return createReceipt(configPath, [], options);
288
+
289
+ const changesByPath = new Map<string, ReceiptChange>();
290
+ for (const patch of patches) {
291
+ const segments = patch.path.split(".");
292
+ const existingChange = changesByPath.get(patch.path);
293
+ const before = existingChange?.before ?? cloneState(stateAtPath(current, segments));
294
+ if (patch.op === "set") {
295
+ setByPath(current, segments, structuredClone(patch.value));
296
+ } else {
297
+ deleteByPath(current, segments);
298
+ }
299
+ const after = cloneState(stateAtPath(current, segments));
300
+ const beforeRevision = existingChange?.publicRevision.beforeRevision ?? ++nextReceiptRevision;
301
+ const afterRevision = ++nextReceiptRevision;
302
+ changesByPath.set(patch.path, {
303
+ path: patch.path,
304
+ before,
305
+ after,
306
+ publicRevision: {
307
+ path: patch.path,
308
+ beforeHash: stateHash(before),
309
+ afterHash: stateHash(after),
310
+ beforeRevision,
311
+ afterRevision,
312
+ },
313
+ });
314
+ }
315
+ const changes = [...changesByPath.values()];
316
+
317
+ await writeAtomicYaml(configPath, current, options);
318
+ return createReceipt(configPath, changes, options);
319
+ }
320
+
321
+ /** Build patches from current durable YAML while holding the shared queue and file lock. */
322
+ export function applyAtomicYamlPatchesWithCurrent(
323
+ configPath: string,
324
+ buildPatches: (
325
+ current: Readonly<Record<string, unknown>>,
326
+ ) => Promise<readonly AtomicYamlPatch[]> | readonly AtomicYamlPatch[],
327
+ options: AtomicYamlPatchOptions = {},
328
+ ): Promise<CasReceipt> {
329
+ return enqueueAtomicYamlOperation(configPath, async canonicalPath => {
330
+ await fs.mkdir(path.dirname(canonicalPath), { recursive: true, mode: 0o700 });
331
+ return await withFileLock(canonicalPath, async () => {
332
+ const current = await readYaml(canonicalPath);
333
+ const patches = await buildPatches(current);
334
+ for (const patch of patches) assertPatch(patch);
335
+ return await applyPatchesUnderLock(canonicalPath, current, patches, options);
336
+ });
337
+ });
338
+ }
339
+
340
+ /**
341
+ * Reserve a FIFO operation for a config file immediately. The patch supplier runs
342
+ * only when this operation reaches the front of the in-process queue, which lets
343
+ * Settings debounce/coalesce inside its already-reserved causal slot.
344
+ */
345
+ export function enqueueAtomicYamlOperation<T>(
346
+ configPath: string,
347
+ operation: (canonicalConfigPath: string) => Promise<T>,
348
+ ): Promise<T> {
349
+ const canonicalPath = canonicalConfigPath(configPath);
350
+ const prior = queues.get(canonicalPath) ?? Promise.resolve();
351
+ const result = prior.catch(() => undefined).then(() => operation(canonicalPath));
352
+ const completion = result.then(
353
+ () => undefined,
354
+ () => undefined,
355
+ );
356
+ queues.set(canonicalPath, completion);
357
+ void completion.finally(() => {
358
+ if (queues.get(canonicalPath) === completion) queues.delete(canonicalPath);
359
+ });
360
+ return result;
361
+ }
362
+
363
+ /**
364
+ * Reserve an atomic patch slot now, producing patches only after earlier slots
365
+ * complete. Writers with state-aware merges use {@link reserveAtomicYamlUpdateSlot}.
366
+ */
367
+ export function reserveAtomicYamlPatchSlot(
368
+ configPath: string,
369
+ patches: () => Promise<readonly AtomicYamlPatch[]> | readonly AtomicYamlPatch[],
370
+ options: AtomicYamlPatchOptions = {},
371
+ ): Promise<CasReceipt> {
372
+ return enqueueAtomicYamlOperation(configPath, async canonicalPath => {
373
+ const nextPatches = await patches();
374
+ for (const patch of nextPatches) assertPatch(patch);
375
+ await fs.mkdir(path.dirname(canonicalPath), { recursive: true, mode: 0o700 });
376
+ return await withFileLock(canonicalPath, async () => {
377
+ const current = await readYaml(canonicalPath);
378
+ return await applyPatchesUnderLock(canonicalPath, current, nextPatches, options);
379
+ });
380
+ });
381
+ }
382
+
383
+ /**
384
+ * Reserve a FIFO update slot and atomically persist a caller-owned YAML mutation.
385
+ * The supplier runs only when its operation reaches the front of the queue.
386
+ */
387
+ export function reserveAtomicYamlUpdateSlot<T>(
388
+ configPath: string,
389
+ update: () => Promise<AtomicYamlUpdate<T>> | AtomicYamlUpdate<T>,
390
+ options: AtomicYamlPatchOptions = {},
391
+ ): Promise<T> {
392
+ return enqueueAtomicYamlOperation(configPath, async canonicalPath => {
393
+ const atomicUpdate = await update();
394
+ await fs.mkdir(path.dirname(canonicalPath), { recursive: true, mode: 0o700 });
395
+ return await withFileLock(canonicalPath, async () => {
396
+ const current = await readYaml(canonicalPath);
397
+ const result = await atomicUpdate.apply(current);
398
+ if (atomicUpdate.shouldWrite?.(result) !== false) {
399
+ await writeAtomicYaml(canonicalPath, current, options);
400
+ }
401
+ await atomicUpdate.committed?.(current, result);
402
+ return result;
403
+ });
404
+ });
405
+ }
406
+
407
+ /**
408
+ * Apply tagged patches through the one per-file in-process queue and the shared
409
+ * cross-process file lock. Success means the temp file was fsynced and renamed.
410
+ */
411
+ export function applyAtomicYamlPatches(
412
+ configPath: string,
413
+ patches: readonly AtomicYamlPatch[],
414
+ options: AtomicYamlPatchOptions = {},
415
+ ): Promise<CasReceipt> {
416
+ for (const patch of patches) assertPatch(patch);
417
+ const immutablePatches = patches.map(patch =>
418
+ patch.op === "set"
419
+ ? ({ path: patch.path, op: "set", value: structuredClone(patch.value) } as const)
420
+ : ({ path: patch.path, op: "unset" } as const),
421
+ );
422
+ return reserveAtomicYamlPatchSlot(configPath, () => immutablePatches, options);
423
+ }