@gajae-code/coding-agent 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/CHANGELOG.md +70 -2
  2. package/dist/types/append-only-mode.d.ts +1 -1
  3. package/dist/types/cli/args.d.ts +4 -5
  4. package/dist/types/cli/daemon-cli.d.ts +12 -1
  5. package/dist/types/cli/notify-cli.d.ts +21 -1
  6. package/dist/types/cli.d.ts +3 -0
  7. package/dist/types/commands/daemon.d.ts +39 -0
  8. package/dist/types/commands/launch.d.ts +3 -0
  9. package/dist/types/commands/notify.d.ts +28 -1
  10. package/dist/types/commands/sdk.d.ts +33 -0
  11. package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
  12. package/dist/types/config/model-profile-activation.d.ts +35 -15
  13. package/dist/types/config/model-profiles.d.ts +11 -5
  14. package/dist/types/config/model-registry.d.ts +3 -3
  15. package/dist/types/config/model-resolver.d.ts +39 -6
  16. package/dist/types/config/model-selector-value.d.ts +17 -0
  17. package/dist/types/config/models-config-schema.d.ts +10 -6
  18. package/dist/types/config/settings-schema.d.ts +133 -6
  19. package/dist/types/config/settings.d.ts +63 -35
  20. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
  21. package/dist/types/coordinator-mcp/server.d.ts +6 -49
  22. package/dist/types/daemon/builtin.d.ts +6 -5
  23. package/dist/types/daemon/control-types.d.ts +1 -1
  24. package/dist/types/discovery/mcp-json.d.ts +12 -1
  25. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  26. package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
  27. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
  28. package/dist/types/extensibility/extensions/loader.d.ts +10 -1
  29. package/dist/types/extensibility/extensions/runner.d.ts +3 -3
  30. package/dist/types/extensibility/extensions/types.d.ts +141 -16
  31. package/dist/types/extensibility/hooks/types.d.ts +1 -1
  32. package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
  33. package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
  34. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
  35. package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
  36. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
  37. package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
  38. package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
  39. package/dist/types/harness-control-plane/operate.d.ts +5 -5
  40. package/dist/types/harness-control-plane/owner.d.ts +18 -4
  41. package/dist/types/harness-control-plane/receipts.d.ts +0 -1
  42. package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
  43. package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
  44. package/dist/types/harness-control-plane/types.d.ts +3 -4
  45. package/dist/types/lsp/index.d.ts +1 -1
  46. package/dist/types/main.d.ts +32 -38
  47. package/dist/types/modes/acp/acp-agent.d.ts +224 -53
  48. package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
  49. package/dist/types/modes/acp/acp-mode.d.ts +6 -15
  50. package/dist/types/modes/acp/permission-mode.d.ts +4 -0
  51. package/dist/types/modes/acp/startup-options.d.ts +6 -0
  52. package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
  53. package/dist/types/modes/components/gajae-pet-widget.d.ts +1 -0
  54. package/dist/types/modes/components/model-selector.d.ts +1 -0
  55. package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
  56. package/dist/types/modes/components/pet-capability.d.ts +37 -0
  57. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  58. package/dist/types/modes/components/settings-selector.d.ts +15 -4
  59. package/dist/types/modes/components/welcome.d.ts +1 -1
  60. package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
  61. package/dist/types/modes/index.d.ts +0 -4
  62. package/dist/types/modes/interactive-mode.d.ts +5 -1
  63. package/dist/types/modes/runtime-init.d.ts +2 -2
  64. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
  65. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
  66. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
  67. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
  68. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
  69. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +169 -30
  70. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
  71. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
  72. package/dist/types/modes/types.d.ts +16 -1
  73. package/dist/types/runtime-mcp/client.d.ts +2 -0
  74. package/dist/types/runtime-mcp/config.d.ts +5 -1
  75. package/dist/types/runtime-mcp/manager.d.ts +8 -1
  76. package/dist/types/runtime-mcp/types.d.ts +4 -0
  77. package/dist/types/sdk/acp/adapter.d.ts +67 -0
  78. package/dist/types/sdk/acp/index.d.ts +2 -0
  79. package/dist/types/sdk/broker/broker.d.ts +53 -0
  80. package/dist/types/sdk/broker/discovery.d.ts +30 -0
  81. package/dist/types/sdk/broker/ensure.d.ts +33 -0
  82. package/dist/types/sdk/broker/identity.d.ts +3 -0
  83. package/dist/types/sdk/broker/index.d.ts +8 -0
  84. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
  85. package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
  86. package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
  87. package/dist/types/sdk/broker/runtime.d.ts +33 -0
  88. package/dist/types/sdk/broker/session-index.d.ts +57 -0
  89. package/dist/types/sdk/broker/state-version.d.ts +8 -0
  90. package/dist/types/sdk/broker/transport.d.ts +9 -0
  91. package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
  95. package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
  96. package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
  97. package/dist/types/sdk/bus/config.d.ts +274 -0
  98. package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
  99. package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
  100. package/dist/types/sdk/bus/discord-daemon.d.ts +45 -0
  101. package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
  102. package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
  103. package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
  104. package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
  105. package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
  106. package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
  107. package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
  108. package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
  109. package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
  110. package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
  111. package/dist/types/sdk/bus/session-control.d.ts +83 -0
  112. package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
  113. package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
  114. package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
  115. package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
  116. package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
  117. package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
  118. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
  119. package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
  120. package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +55 -17
  121. package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
  122. package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
  123. package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
  124. package/dist/types/sdk/cli/index.d.ts +1 -0
  125. package/dist/types/sdk/cli/session-cli.d.ts +19 -0
  126. package/dist/types/sdk/client/client.d.ts +1 -0
  127. package/dist/types/sdk/client/discovery.d.ts +27 -0
  128. package/dist/types/sdk/client/index.d.ts +2 -0
  129. package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
  130. package/dist/types/sdk/host/control/index.d.ts +2 -0
  131. package/dist/types/sdk/host/control/operations.d.ts +65 -0
  132. package/dist/types/sdk/host/events.d.ts +35 -0
  133. package/dist/types/sdk/host/host.d.ts +35 -0
  134. package/dist/types/sdk/host/index.d.ts +4 -0
  135. package/dist/types/sdk/host/query/cursor.d.ts +62 -0
  136. package/dist/types/sdk/host/query/handlers.d.ts +70 -0
  137. package/dist/types/sdk/host/query/index.d.ts +3 -0
  138. package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
  139. package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
  140. package/dist/types/sdk/host/types.d.ts +32 -0
  141. package/dist/types/sdk/index.d.ts +6 -0
  142. package/dist/types/sdk/lifecycle-session.d.ts +14 -0
  143. package/dist/types/sdk/mcp/index.d.ts +1 -0
  144. package/dist/types/sdk/mcp/server.d.ts +37 -0
  145. package/dist/types/sdk/models.d.ts +44 -0
  146. package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
  147. package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
  148. package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
  149. package/dist/types/sdk/startup-capability.d.ts +50 -0
  150. package/dist/types/session/agent-session.d.ts +114 -21
  151. package/dist/types/session/default-model-selection.d.ts +25 -0
  152. package/dist/types/session/fallback-chain-controller.d.ts +52 -0
  153. package/dist/types/session/session-manager.d.ts +58 -1
  154. package/dist/types/setup/credential-auto-import.d.ts +36 -6
  155. package/dist/types/tools/ask-answer-registry.d.ts +1 -1
  156. package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
  157. package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
  158. package/dist/types/tools/browser/launch.d.ts +22 -0
  159. package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
  160. package/dist/types/tools/browser/profile-posture.d.ts +37 -0
  161. package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
  162. package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
  163. package/dist/types/tools/browser/registry.d.ts +19 -0
  164. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  165. package/dist/types/tools/index.d.ts +8 -8
  166. package/package.json +34 -13
  167. package/scripts/build-sdk-package-smoke.ts +94 -0
  168. package/scripts/capture-notifications-settings-showcase.ts +435 -0
  169. package/scripts/compile-args.ts +4 -2
  170. package/scripts/g005-daemon-smoke.ts +4 -5
  171. package/scripts/g011-daemon-path-smoke.ts +5 -5
  172. package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
  173. package/scripts/generate-sdk-operation-inventory.ts +867 -0
  174. package/scripts/generate-telegram-baseline-manifest.ts +128 -0
  175. package/scripts/manifest-schema.ts +124 -0
  176. package/scripts/run-test-manifest.ts +153 -0
  177. package/scripts/run-threat-model-check.ts +157 -0
  178. package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
  179. package/scripts/verify-gjc-sdk-rename.ts +90 -0
  180. package/src/append-only-mode.ts +1 -1
  181. package/src/cli/args.ts +43 -12
  182. package/src/cli/auth-gateway-cli.ts +2 -2
  183. package/src/cli/config-cli.ts +2 -1
  184. package/src/cli/daemon-cli.ts +63 -14
  185. package/src/cli/list-models.ts +1 -1
  186. package/src/cli/notify-cli.ts +288 -286
  187. package/src/cli.ts +21 -2
  188. package/src/commands/daemon.ts +50 -6
  189. package/src/commands/harness.ts +93 -36
  190. package/src/commands/launch.ts +5 -2
  191. package/src/commands/mcp-serve.ts +19 -12
  192. package/src/commands/notify.ts +36 -3
  193. package/src/commands/sdk.ts +426 -0
  194. package/src/commit/agentic/agent.ts +1 -0
  195. package/src/config/atomic-yaml-patch.ts +423 -0
  196. package/src/config/model-profile-activation.ts +240 -89
  197. package/src/config/model-profiles.ts +37 -34
  198. package/src/config/model-registry.ts +51 -26
  199. package/src/config/model-resolver.ts +138 -51
  200. package/src/config/model-selector-value.ts +50 -0
  201. package/src/config/models-config-schema.ts +14 -21
  202. package/src/config/settings-schema.ts +128 -10
  203. package/src/config/settings.ts +1120 -158
  204. package/src/coordinator-mcp/model-preset.ts +74 -20
  205. package/src/coordinator-mcp/server.ts +1597 -3052
  206. package/src/daemon/builtin.ts +8 -5
  207. package/src/daemon/control-types.ts +1 -1
  208. package/src/defaults/gjc/skills/team/SKILL.md +4 -4
  209. package/src/discovery/mcp-json.ts +327 -20
  210. package/src/extensibility/custom-tools/types.ts +1 -1
  211. package/src/extensibility/extensions/compact-handler.ts +3 -3
  212. package/src/extensibility/extensions/get-commands-handler.ts +2 -2
  213. package/src/extensibility/extensions/loader.ts +69 -5
  214. package/src/extensibility/extensions/runner.ts +112 -4
  215. package/src/extensibility/extensions/types.ts +176 -17
  216. package/src/extensibility/hooks/types.ts +1 -1
  217. package/src/extensibility/slash-commands.ts +3 -3
  218. package/src/gjc-runtime/launch-tmux.ts +170 -86
  219. package/src/gjc-runtime/psmux-detect.ts +82 -4
  220. package/src/gjc-runtime/session-state-sidecar.ts +41 -31
  221. package/src/gjc-runtime/team-runtime.ts +54 -35
  222. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
  223. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -2
  224. package/src/gjc-runtime/tmux-sessions.ts +19 -13
  225. package/src/gjc-runtime/ultragoal-guard.ts +53 -6
  226. package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
  227. package/src/gjc-runtime/windows-powershell-command.ts +58 -0
  228. package/src/harness-control-plane/operate.ts +9 -9
  229. package/src/harness-control-plane/owner.ts +283 -39
  230. package/src/harness-control-plane/receipts.ts +0 -1
  231. package/src/harness-control-plane/sdk-transport.ts +395 -0
  232. package/src/harness-control-plane/session-transport.ts +94 -0
  233. package/src/harness-control-plane/types.ts +1 -1
  234. package/src/internal-urls/docs-index.generated.ts +36 -37
  235. package/src/lsp/client.ts +42 -6
  236. package/src/lsp/index.ts +2 -2
  237. package/src/main.ts +299 -204
  238. package/src/modes/DESIGN.md +258 -0
  239. package/src/modes/acp/acp-agent.ts +1228 -2612
  240. package/src/modes/acp/acp-client-bridge.ts +2 -20
  241. package/src/modes/acp/acp-event-mapper.ts +18 -2
  242. package/src/modes/acp/acp-mode.ts +8 -36
  243. package/src/modes/acp/permission-mode.ts +25 -0
  244. package/src/modes/acp/startup-options.ts +6 -0
  245. package/src/modes/components/agent-dashboard.ts +37 -17
  246. package/src/modes/components/custom-editor.ts +1 -0
  247. package/src/modes/components/gajae-pet-widget.ts +169 -20
  248. package/src/modes/components/model-selector.ts +93 -35
  249. package/src/modes/components/notifications-settings-editor.ts +1379 -0
  250. package/src/modes/components/pet-capability.ts +115 -0
  251. package/src/modes/components/pet-selector.ts +4 -6
  252. package/src/modes/components/settings-selector.ts +86 -11
  253. package/src/modes/components/welcome.ts +4 -4
  254. package/src/modes/controllers/command-controller.ts +1 -2
  255. package/src/modes/controllers/event-controller.ts +11 -16
  256. package/src/modes/controllers/extension-ui-controller.ts +357 -12
  257. package/src/modes/controllers/input-controller.ts +43 -13
  258. package/src/modes/controllers/selector-controller.ts +671 -44
  259. package/src/modes/index.ts +0 -22
  260. package/src/modes/interactive-mode.ts +108 -24
  261. package/src/modes/runtime-init.ts +298 -6
  262. package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
  263. package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
  264. package/src/modes/shared/agent-wire/event-contract.ts +7 -8
  265. package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
  266. package/src/modes/shared/agent-wire/event-observation.ts +16 -7
  267. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1254 -87
  268. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
  269. package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
  270. package/src/modes/types.ts +16 -1
  271. package/src/runtime-mcp/client.ts +94 -19
  272. package/src/runtime-mcp/config.ts +27 -15
  273. package/src/runtime-mcp/manager.ts +343 -105
  274. package/src/runtime-mcp/oauth-flow.ts +42 -12
  275. package/src/runtime-mcp/transports/http.ts +49 -19
  276. package/src/runtime-mcp/transports/stdio.ts +47 -28
  277. package/src/runtime-mcp/types.ts +10 -0
  278. package/src/sdk/acp/adapter.ts +418 -0
  279. package/src/sdk/acp/index.ts +2 -0
  280. package/src/sdk/broker/broker.ts +642 -0
  281. package/src/sdk/broker/discovery.ts +94 -0
  282. package/src/sdk/broker/ensure.ts +249 -0
  283. package/src/sdk/broker/identity.ts +42 -0
  284. package/src/sdk/broker/index.ts +8 -0
  285. package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
  286. package/src/sdk/broker/internal-source.bunfig.toml +1 -0
  287. package/src/sdk/broker/lifecycle-ledger.ts +286 -0
  288. package/src/sdk/broker/lifecycle.ts +2157 -0
  289. package/src/sdk/broker/process-incarnation.ts +159 -0
  290. package/src/sdk/broker/runtime.ts +164 -0
  291. package/src/sdk/broker/session-index.ts +318 -0
  292. package/src/sdk/broker/state-version.ts +23 -0
  293. package/src/sdk/broker/transport.ts +125 -0
  294. package/src/sdk/bus/chat-command-policy.ts +107 -0
  295. package/src/sdk/bus/chat-daemon-cli.ts +214 -0
  296. package/src/sdk/bus/chat-daemon-control.ts +713 -0
  297. package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
  298. package/src/sdk/bus/chat-effect-journal.ts +353 -0
  299. package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
  300. package/src/sdk/bus/config.ts +433 -0
  301. package/src/sdk/bus/conversation-store.ts +391 -0
  302. package/src/sdk/bus/discord-conversation.ts +85 -0
  303. package/src/sdk/bus/discord-daemon.ts +2275 -0
  304. package/src/sdk/bus/discord-live-provider.ts +521 -0
  305. package/src/sdk/bus/discord-provider.ts +56 -0
  306. package/src/{notifications → sdk/bus}/html-format.ts +2 -2
  307. package/src/sdk/bus/index.ts +3943 -0
  308. package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
  309. package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
  310. package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
  311. package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
  312. package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
  313. package/src/sdk/bus/natives-augment.d.ts +38 -0
  314. package/src/sdk/bus/notification-orchestration.ts +535 -0
  315. package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
  316. package/src/sdk/bus/session-control.ts +333 -0
  317. package/src/sdk/bus/slack-conversation.ts +74 -0
  318. package/src/sdk/bus/slack-daemon.ts +2144 -0
  319. package/src/sdk/bus/slack-live-provider.ts +380 -0
  320. package/src/sdk/bus/slack-provider.ts +76 -0
  321. package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
  322. package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
  323. package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
  324. package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
  325. package/src/{notifications → sdk/bus}/telegram-daemon.ts +502 -54
  326. package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
  327. package/src/sdk/bus/telegram-setup.ts +663 -0
  328. package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
  329. package/src/sdk/cli/index.ts +1 -0
  330. package/src/sdk/cli/session-cli.ts +275 -0
  331. package/src/sdk/client/client.ts +1 -0
  332. package/src/sdk/client/discovery.ts +108 -0
  333. package/src/sdk/client/index.ts +2 -0
  334. package/src/sdk/host/control/dispatch.ts +367 -0
  335. package/src/sdk/host/control/index.ts +10 -0
  336. package/src/sdk/host/control/operations.ts +63 -0
  337. package/src/sdk/host/events.ts +91 -0
  338. package/src/sdk/host/host.ts +296 -0
  339. package/src/sdk/host/index.ts +4 -0
  340. package/src/sdk/host/query/cursor.ts +189 -0
  341. package/src/sdk/host/query/handlers.ts +533 -0
  342. package/src/sdk/host/query/index.ts +3 -0
  343. package/src/sdk/host/query/revision-store.ts +1126 -0
  344. package/src/sdk/host/reverse-leases.ts +325 -0
  345. package/src/sdk/host/types.ts +29 -0
  346. package/src/sdk/index.ts +13 -0
  347. package/src/sdk/lifecycle-session.ts +39 -0
  348. package/src/sdk/mcp/index.ts +1 -0
  349. package/src/sdk/mcp/server.ts +332 -0
  350. package/src/sdk/models.ts +168 -0
  351. package/src/sdk/protocol/adapter-validation.ts +48 -0
  352. package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
  353. package/src/sdk/protocol/operation-registry.ts +312 -0
  354. package/src/{sdk.ts → sdk/session.ts} +339 -212
  355. package/src/sdk/startup-capability.ts +189 -0
  356. package/src/session/agent-session.ts +2470 -866
  357. package/src/session/default-model-selection.ts +93 -0
  358. package/src/session/fallback-chain-controller.ts +136 -0
  359. package/src/session/session-manager.ts +447 -13
  360. package/src/session/session-storage.ts +8 -1
  361. package/src/setup/credential-auto-import.ts +290 -35
  362. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
  363. package/src/slash-commands/builtin-registry.ts +33 -30
  364. package/src/task/executor.ts +62 -13
  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/telegram-send.ts +2 -2
  384. package/vendor/insane-search/MANIFEST.json +2 -1
  385. package/vendor/insane-search/engine/bias_check.py +4 -1
  386. package/vendor/insane-search/engine/phase0.py +26 -1
  387. package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
  388. package/dist/types/modes/bridge/auth.d.ts +0 -12
  389. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
  390. package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
  391. package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
  392. package/dist/types/modes/bridge/event-stream.d.ts +0 -8
  393. package/dist/types/modes/rpc/host-tools.d.ts +0 -1
  394. package/dist/types/modes/rpc/host-uris.d.ts +0 -1
  395. package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
  396. package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
  397. package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
  398. package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
  399. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
  400. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
  401. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
  402. package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
  403. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
  404. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
  405. package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
  406. package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
  407. package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
  408. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
  409. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
  410. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
  411. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
  412. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
  413. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
  414. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
  415. package/dist/types/notifications/config.d.ts +0 -132
  416. package/src/harness-control-plane/rpc-adapter.ts +0 -290
  417. package/src/modes/bridge/auth.ts +0 -41
  418. package/src/modes/bridge/bridge-client-bridge.ts +0 -47
  419. package/src/modes/bridge/bridge-mode.ts +0 -675
  420. package/src/modes/bridge/bridge-ui-context.ts +0 -200
  421. package/src/modes/bridge/event-stream.ts +0 -70
  422. package/src/modes/rpc/host-tools.ts +0 -1
  423. package/src/modes/rpc/host-uris.ts +0 -1
  424. package/src/modes/rpc/rpc-client.ts +0 -1166
  425. package/src/modes/rpc/rpc-mode.ts +0 -1029
  426. package/src/modes/rpc/rpc-socket-security.ts +0 -115
  427. package/src/modes/rpc/rpc-types.ts +0 -637
  428. package/src/modes/shared/agent-wire/command-contract.ts +0 -18
  429. package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
  430. package/src/modes/shared/agent-wire/command-validation.ts +0 -181
  431. package/src/modes/shared/agent-wire/handshake.ts +0 -157
  432. package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
  433. package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
  434. package/src/modes/shared/agent-wire/protocol.ts +0 -46
  435. package/src/modes/shared/agent-wire/responses.ts +0 -17
  436. package/src/modes/shared/agent-wire/scopes.ts +0 -94
  437. package/src/modes/shared/agent-wire/session-registry.ts +0 -109
  438. package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
  439. package/src/modes/shared/agent-wire/ui-result.ts +0 -48
  440. package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
  441. package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
  442. package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
  443. package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
  444. package/src/notifications/config.ts +0 -219
  445. package/src/notifications/index.ts +0 -1835
  446. package/src/notifications/telegram-daemon-cli.ts +0 -243
  447. package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
  448. /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
  449. /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
  450. /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
  451. /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
  452. /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
  453. /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
  454. /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
  455. /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
  456. /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
  457. /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
  458. /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
  459. /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
  460. /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
  461. /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
  462. /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
  463. /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
  464. /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
  465. /package/src/{notifications → sdk/bus}/engine.ts +0 -0
  466. /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
  467. /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
  468. /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
  469. /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
  470. /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
  471. /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
  472. /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
  473. /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
  474. /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
+ }