@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,296 @@
1
+ import { type EventFrame, SessionEventStream } from "./events";
2
+ import { type ProviderLease, ReverseLeaseError, ReverseLeaseRuntime } from "./reverse-leases";
3
+ import type { BrokerIndexWriter, HostEndpointAdapters, SdkFrame } from "./types";
4
+
5
+ export type SdkRequestObserver = (kind: "control" | "query", connectionId: string, frame: SdkFrame) => void;
6
+
7
+ export interface SessionSdkHostOptions extends HostEndpointAdapters {
8
+ control?: (connectionId: string, frame: SdkFrame) => unknown | Promise<unknown>;
9
+ query?: (connectionId: string, frame: SdkFrame) => unknown | Promise<unknown>;
10
+ /** Best-effort diagnostic observation of accepted control/query frames. */
11
+ onRequest?: SdkRequestObserver;
12
+ /** Runs only after a successful control response has been sent to the client. */
13
+ afterControlResponse?: (connectionId: string, request: SdkFrame, response: SdkFrame) => void | Promise<void>;
14
+ installProviderDefinitions?: (capability: string, definitions: unknown) => void;
15
+ onProviderDefinitionsRemoved?: (capability: string) => void;
16
+ onReverseCancel?: (requestId: string, reason: "provider_disconnected" | "lease_released") => void;
17
+ }
18
+
19
+ /** SDK hosting is independent of notification configuration. Only root sessions host an endpoint. */
20
+ export function shouldHostSdk(_settings: unknown, isTopLevel: boolean, env: NodeJS.ProcessEnv = process.env): boolean {
21
+ return isTopLevel && env.GJC_SDK_DISABLE !== "1";
22
+ }
23
+
24
+ function errorFrame(connectionId: string, frame: SdkFrame, error: unknown): SdkFrame {
25
+ const candidate = error as { code?: unknown; message?: unknown };
26
+ const code =
27
+ error instanceof ReverseLeaseError
28
+ ? error.code
29
+ : typeof candidate?.code === "string"
30
+ ? candidate.code
31
+ : "internal";
32
+ const message = typeof candidate?.message === "string" ? candidate.message : "SDK host operation failed.";
33
+ return {
34
+ type: "reverse_response",
35
+ id: typeof frame.id === "string" ? frame.id : "",
36
+ connectionId,
37
+ leaseId: typeof frame.leaseId === "string" ? frame.leaseId : "",
38
+ ok: false,
39
+ error: { code, message },
40
+ };
41
+ }
42
+
43
+ function leaseState(id: unknown, lease: ProviderLease, active = lease.active): SdkFrame {
44
+ return {
45
+ type: "lease_state",
46
+ id: typeof id === "string" ? id : "",
47
+ connectionId: lease.connectionId,
48
+ capability: lease.capability,
49
+ leaseId: lease.leaseId,
50
+ leaseExpiresAt: new Date(lease.expiresAt).toISOString(),
51
+ active,
52
+ };
53
+ }
54
+
55
+ function registeredNames(definitions: unknown): string[] {
56
+ const entries = Array.isArray(definitions)
57
+ ? definitions
58
+ : definitions && typeof definitions === "object"
59
+ ? Object.values(definitions as Record<string, unknown>).flatMap(value => (Array.isArray(value) ? value : []))
60
+ : [];
61
+ return entries.flatMap(entry =>
62
+ entry && typeof entry === "object" && typeof (entry as Record<string, unknown>).name === "string"
63
+ ? [(entry as Record<string, string>).name]
64
+ : [],
65
+ );
66
+ }
67
+
68
+ function invalidFrame(message: string): Error {
69
+ return Object.assign(new Error(message), { code: "invalid_reverse_frame" });
70
+ }
71
+ function record(value: unknown): Record<string, unknown> | undefined {
72
+ return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
73
+ }
74
+ function requiredString(frame: SdkFrame, field: string): string {
75
+ const value = frame[field];
76
+ if (typeof value !== "string") throw invalidFrame(`${field} must be a string.`);
77
+ return value;
78
+ }
79
+ function optionalString(frame: SdkFrame, field: string): string | undefined {
80
+ const value = frame[field];
81
+ if (value === undefined) return undefined;
82
+ if (typeof value !== "string") throw invalidFrame(`${field} must be a string.`);
83
+ return value;
84
+ }
85
+ function requireConnection(connectionId: string, frame: SdkFrame): void {
86
+ if (requiredString(frame, "connectionId") !== connectionId)
87
+ throw invalidFrame("connectionId does not match the transport connection.");
88
+ }
89
+ function has(frame: SdkFrame, field: string): boolean {
90
+ return Object.hasOwn(frame, field);
91
+ }
92
+
93
+ /** Adapter-based session host; bus wiring owns NotificationServer creation and transport framing. */
94
+ export class SessionSdkHost {
95
+ readonly events = new SessionEventStream();
96
+ readonly reverse: ReverseLeaseRuntime;
97
+ readonly #options: SessionSdkHostOptions;
98
+ #started = false;
99
+ #unsubscribe?: () => void;
100
+ #registration?: { writer: BrokerIndexWriter; generation: number };
101
+
102
+ constructor(options: SessionSdkHostOptions) {
103
+ this.#options = options;
104
+ this.reverse = new ReverseLeaseRuntime({
105
+ sendFrame: options.sendFrame,
106
+ installDefinitions: options.installProviderDefinitions,
107
+ onDefinitionsRemoved: options.onProviderDefinitionsRemoved,
108
+ onCancel: options.onReverseCancel,
109
+ });
110
+ }
111
+
112
+ get started(): boolean {
113
+ return this.#started;
114
+ }
115
+ get generation(): number {
116
+ return this.events.generation;
117
+ }
118
+ /** Current installed definitions for a live provider capability. */
119
+ getProviderDefinitions(capability: string): unknown | undefined {
120
+ return this.reverse.getInstalledDefinitions(capability);
121
+ }
122
+ /** Release reverse leases after the transport reports a WebSocket disconnect. */
123
+ handleDisconnect(connectionId: string): void {
124
+ this.reverse.disconnect(connectionId);
125
+ }
126
+
127
+ /** Adds an event to the resumable event ring. Transport delivery is owned by bus wiring. */
128
+ emitEvent(frame: SdkFrame): EventFrame {
129
+ return this.events.emit(frame);
130
+ }
131
+
132
+ async start(): Promise<"started" | "already"> {
133
+ if (this.#started) return "already";
134
+ this.events.restart();
135
+ this.emitEvent({ name: "session_ready", sessionId: this.#options.sessionId, generation: this.events.generation });
136
+ const disposer = this.#options.onFrame((connectionId, frame) => {
137
+ void this.#onFrame(connectionId, frame);
138
+ });
139
+ this.#unsubscribe = typeof disposer === "function" ? disposer : undefined;
140
+ this.#started = true;
141
+ if (this.#registration)
142
+ await this.#registration.writer.register({
143
+ sessionId: this.#options.sessionId,
144
+ stateRoot: this.#options.stateRoot,
145
+ endpointGeneration: this.events.generation,
146
+ });
147
+ return "started";
148
+ }
149
+
150
+ async stop(): Promise<"stopped" | "already"> {
151
+ if (!this.#started) return "already";
152
+ this.#unsubscribe?.();
153
+ this.#unsubscribe = undefined;
154
+ this.#started = false;
155
+ if (this.#registration?.writer.unregister)
156
+ await this.#registration.writer.unregister({
157
+ sessionId: this.#options.sessionId,
158
+ stateRoot: this.#options.stateRoot,
159
+ endpointGeneration: this.events.generation,
160
+ });
161
+ return "stopped";
162
+ }
163
+
164
+ async registerWithBroker(writer: BrokerIndexWriter): Promise<void> {
165
+ this.#registration = { writer, generation: this.events.generation };
166
+ if (this.#started)
167
+ await writer.register({
168
+ sessionId: this.#options.sessionId,
169
+ stateRoot: this.#options.stateRoot,
170
+ endpointGeneration: this.events.generation,
171
+ });
172
+ }
173
+
174
+ async #send(connectionId: string, frame: SdkFrame): Promise<void> {
175
+ await this.#options.sendFrame(connectionId, frame);
176
+ }
177
+
178
+ async #onFrame(connectionId: string, frame: SdkFrame): Promise<void> {
179
+ try {
180
+ switch (frame.type) {
181
+ case "control_request": {
182
+ this.#observeRequest("control", connectionId, frame);
183
+ const result = await this.#options.control?.(connectionId, frame);
184
+ if (result !== undefined) {
185
+ const response = { type: "control_response", ...(result as SdkFrame) };
186
+ await this.#send(connectionId, response);
187
+ await this.#options.afterControlResponse?.(connectionId, frame, response);
188
+ }
189
+ break;
190
+ }
191
+ case "event_replay": {
192
+ const id = requiredString(frame, "id");
193
+ const rawGeneration =
194
+ frame.sinceGeneration === undefined ? this.events.generation : frame.sinceGeneration;
195
+ const rawSeq = frame.sinceSeq === undefined ? 0 : frame.sinceSeq;
196
+ if (typeof rawGeneration !== "number" || !Number.isSafeInteger(rawGeneration) || rawGeneration < 0)
197
+ throw invalidFrame("sinceGeneration must be a non-negative integer.");
198
+ if (typeof rawSeq !== "number" || !Number.isSafeInteger(rawSeq) || rawSeq < 0)
199
+ throw invalidFrame("sinceSeq must be a non-negative integer.");
200
+ const sinceGeneration = rawGeneration;
201
+ const sinceSeq = rawSeq;
202
+ const replay = this.events.replay(sinceSeq, sinceGeneration);
203
+ await this.#send(connectionId, {
204
+ type: "event_replay_result",
205
+ id,
206
+ ok: true,
207
+ ...replay,
208
+ generation: this.events.generation,
209
+ lastSeq: this.events.sequence,
210
+ });
211
+ break;
212
+ }
213
+ case "query_request": {
214
+ this.#observeRequest("query", connectionId, frame);
215
+ const result = await this.#options.query?.(connectionId, frame);
216
+ if (result !== undefined)
217
+ await this.#send(connectionId, { type: "query_response", ...(result as SdkFrame) });
218
+ break;
219
+ }
220
+ case "register_provider": {
221
+ requiredString(frame, "id");
222
+ requireConnection(connectionId, frame);
223
+ const capability = requiredString(frame, "capability");
224
+ if (!has(frame, "definitions")) throw invalidFrame("definitions is required.");
225
+ const lease = this.reverse.registerProvider(
226
+ connectionId,
227
+ capability,
228
+ frame.definitions,
229
+ optionalString(frame, "expectedLeaseId"),
230
+ optionalString(frame, "idempotencyKey"),
231
+ );
232
+ await this.#send(connectionId, {
233
+ id: frame.id,
234
+ type: "register_provider_result",
235
+ leaseId: lease.leaseId,
236
+ leaseExpiresAt: new Date(lease.expiresAt).toISOString(),
237
+ registeredNames: registeredNames(frame.definitions),
238
+ });
239
+ break;
240
+ }
241
+ case "provider_heartbeat": {
242
+ requireConnection(connectionId, frame);
243
+ const lease = this.reverse.heartbeat(connectionId, requiredString(frame, "leaseId"));
244
+ await this.#send(connectionId, leaseState(undefined, lease));
245
+ break;
246
+ }
247
+ case "lease_release": {
248
+ requireConnection(connectionId, frame);
249
+ const handoffTo = optionalString(frame, "handoffTo");
250
+ const lease = this.reverse.release(connectionId, requiredString(frame, "leaseId"), handoffTo);
251
+ await this.#send(connectionId, leaseState(undefined, lease));
252
+ break;
253
+ }
254
+ case "reverse_response": {
255
+ const id = requiredString(frame, "id");
256
+ requireConnection(connectionId, frame);
257
+ const leaseId = requiredString(frame, "leaseId");
258
+ if (typeof frame.ok !== "boolean") throw invalidFrame("ok must be a boolean.");
259
+ const responseError = record(frame.error);
260
+ if (frame.ok) {
261
+ if (!has(frame, "result") || has(frame, "error"))
262
+ throw invalidFrame("Successful reverse responses require result and no error.");
263
+ this.reverse.respond(connectionId, id, leaseId, frame.result);
264
+ } else {
265
+ if (
266
+ has(frame, "result") ||
267
+ !responseError ||
268
+ typeof responseError.code !== "string" ||
269
+ typeof responseError.message !== "string"
270
+ )
271
+ throw invalidFrame("Failed reverse responses require a structured error and no result.");
272
+ this.reverse.respond(connectionId, id, leaseId, undefined, {
273
+ code: responseError.code,
274
+ message: responseError.message,
275
+ });
276
+ }
277
+ break;
278
+ }
279
+ default:
280
+ // Unknown/future frame types are tolerated silently per the v3
281
+ // forward-compatibility contract; only malformed frames of KNOWN
282
+ // types produce structured errors (thrown above).
283
+ return;
284
+ }
285
+ } catch (error) {
286
+ await this.#send(connectionId, errorFrame(connectionId, frame, error));
287
+ }
288
+ }
289
+ #observeRequest(kind: "control" | "query", connectionId: string, frame: SdkFrame): void {
290
+ try {
291
+ this.#options.onRequest?.(kind, connectionId, frame);
292
+ } catch {
293
+ // Diagnostic observers must not change request handling.
294
+ }
295
+ }
296
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./events";
2
+ export * from "./host";
3
+ export * from "./reverse-leases";
4
+ export * from "./types";
@@ -0,0 +1,189 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ import { MAX_PINNED_REVISIONS, type RevisionStore, RevisionStoreError, SNAPSHOT_TTL_MS } from "./revision-store.js";
3
+
4
+ export const CURSOR_TTL_MS = SNAPSHOT_TTL_MS;
5
+ export const MAX_CURSORS_PER_CONNECTION = 32;
6
+ export const MAX_CURSORS_PER_SESSION = MAX_PINNED_REVISIONS;
7
+
8
+ export interface CursorEnvelope {
9
+ cursorVersion: 1;
10
+ protocolMajor: 3;
11
+ sessionId: string;
12
+ resource: string;
13
+ revision: string;
14
+ highWatermark?: unknown;
15
+ position: unknown;
16
+ direction: string;
17
+ pageShape: unknown;
18
+ }
19
+
20
+ export interface CursorSelector {
21
+ queryId: string;
22
+ entryId?: string;
23
+ field?: string;
24
+ fileId?: string;
25
+ hunkId?: string;
26
+ resourceKind?: string;
27
+ resourceId?: string;
28
+ itemId?: string;
29
+ }
30
+
31
+ export interface CursorPosition {
32
+ offset?: number;
33
+ byteOffset?: number;
34
+ selector?: CursorSelector;
35
+ }
36
+
37
+ export function cursorSelector(position: unknown): CursorSelector | undefined {
38
+ if (!position || typeof position !== "object") return undefined;
39
+ const selector = (position as CursorPosition).selector;
40
+ return selector && typeof selector.queryId === "string" ? selector : undefined;
41
+ }
42
+
43
+ export function assertCursorSelector(
44
+ cursor: CursorSelector | undefined,
45
+ requested: Partial<CursorSelector>,
46
+ ): CursorSelector {
47
+ if (!cursor) throw new CursorError("invalid_input", false, "cursor does not match query");
48
+ for (const [key, value] of Object.entries(requested)) {
49
+ if (value !== undefined && cursor[key as keyof CursorSelector] !== value)
50
+ throw new CursorError("invalid_input", false, "cursor does not match query");
51
+ }
52
+ return cursor;
53
+ }
54
+
55
+ export interface CursorQueryContext {
56
+ sessionId: string;
57
+ resource?: string;
58
+ resourceId?: string;
59
+ direction: string;
60
+ pageShape: unknown;
61
+ }
62
+
63
+ export class CursorError extends Error {
64
+ constructor(
65
+ readonly code:
66
+ | "cursor_expired"
67
+ | "invalid_cursor"
68
+ | "invalid_input"
69
+ | "resource_gone"
70
+ | "snapshot_capacity_exceeded",
71
+ readonly restartQuery = code === "cursor_expired",
72
+ message: string = code,
73
+ ) {
74
+ super(message);
75
+ }
76
+ }
77
+
78
+ function canonicalise(value: unknown): unknown {
79
+ if (Array.isArray(value)) return value.map(canonicalise);
80
+ if (value && typeof value === "object")
81
+ return Object.fromEntries(
82
+ Object.entries(value)
83
+ .sort(([a], [b]) => a.localeCompare(b))
84
+ .map(([key, entry]) => [key, canonicalise(entry)]),
85
+ );
86
+ return value;
87
+ }
88
+
89
+ function canonicalJson(value: unknown): string {
90
+ return JSON.stringify(canonicalise(value));
91
+ }
92
+ export function canonicalCursorJson(envelope: CursorEnvelope): string {
93
+ return canonicalJson(envelope);
94
+ }
95
+ export function cursorMac(envelope: CursorEnvelope, sessionToken: string | Uint8Array): string {
96
+ return createHmac("sha256", sessionToken).update(canonicalCursorJson(envelope)).digest("hex");
97
+ }
98
+ export function signCursor(envelope: CursorEnvelope, sessionToken: string | Uint8Array): string {
99
+ return JSON.stringify({ envelope, mac: cursorMac(envelope, sessionToken) });
100
+ }
101
+ export function verifyCursor(cursor: string, sessionToken: string | Uint8Array): CursorEnvelope | undefined {
102
+ try {
103
+ const signed = JSON.parse(cursor) as { envelope: CursorEnvelope; mac: string };
104
+ const expected = Buffer.from(cursorMac(signed.envelope, sessionToken), "hex");
105
+ const actual = Buffer.from(signed.mac, "hex");
106
+ if (expected.length !== actual.length || !timingSafeEqual(expected, actual)) return undefined;
107
+ const envelope = signed.envelope;
108
+ return envelope.cursorVersion === 1 && envelope.protocolMajor === 3 ? envelope : undefined;
109
+ } catch {
110
+ return undefined;
111
+ }
112
+ }
113
+
114
+ interface ActiveCursor {
115
+ connectionId: string;
116
+ resourceId: string;
117
+ expiresAt: number;
118
+ }
119
+
120
+ /** Tracks cursor budgets and binds snapshot pins to authenticated cursor strings. */
121
+ export class CursorRegistry {
122
+ readonly #active = new Map<string, ActiveCursor>();
123
+ constructor(
124
+ private readonly sessionToken: string | Uint8Array,
125
+ private readonly revisions: RevisionStore,
126
+ private readonly now: () => number = Date.now,
127
+ ) {}
128
+
129
+ async grant(
130
+ connectionId: string,
131
+ envelope: CursorEnvelope,
132
+ resourceKind: string,
133
+ resourceId: string,
134
+ ): Promise<string> {
135
+ this.sweep();
136
+ if (
137
+ this.#active.size >= MAX_CURSORS_PER_SESSION ||
138
+ [...this.#active.values()].filter(item => item.connectionId === connectionId).length >=
139
+ MAX_CURSORS_PER_CONNECTION
140
+ )
141
+ throw new CursorError("snapshot_capacity_exceeded", false);
142
+ const cursor = signCursor(envelope, this.sessionToken);
143
+ try {
144
+ await this.revisions.pin(cursor, resourceKind, resourceId, envelope.revision);
145
+ } catch (error) {
146
+ if (error instanceof RevisionStoreError) throw new CursorError(error.code, false);
147
+ throw error;
148
+ }
149
+ this.#active.set(cursor, { connectionId, resourceId, expiresAt: this.now() + CURSOR_TTL_MS });
150
+ return cursor;
151
+ }
152
+
153
+ consume(cursor: string, connectionId: string, expected: CursorQueryContext): CursorEnvelope {
154
+ const envelope = verifyCursor(cursor, this.sessionToken);
155
+ if (!envelope) throw new CursorError("invalid_cursor", false);
156
+ const active = this.#active.get(cursor);
157
+ if (!active || active.connectionId !== connectionId || active.expiresAt <= this.now()) {
158
+ this.release(cursor);
159
+ throw new CursorError("cursor_expired");
160
+ }
161
+ if (
162
+ envelope.sessionId !== expected.sessionId ||
163
+ (expected.resource !== undefined && envelope.resource !== expected.resource) ||
164
+ envelope.direction !== expected.direction ||
165
+ canonicalJson(envelope.pageShape) !== canonicalJson(expected.pageShape) ||
166
+ (expected.resourceId !== undefined && active.resourceId !== expected.resourceId)
167
+ ) {
168
+ throw new CursorError("invalid_input", false, "cursor does not match query");
169
+ }
170
+ this.release(cursor);
171
+ return envelope;
172
+ }
173
+
174
+ release(cursor: string): void {
175
+ this.#active.delete(cursor);
176
+ this.revisions.unpin(cursor);
177
+ }
178
+
179
+ close(): void {
180
+ for (const cursor of this.#active.keys()) this.release(cursor);
181
+ }
182
+ sweep(): void {
183
+ for (const [cursor, active] of this.#active) if (active.expiresAt <= this.now()) this.release(cursor);
184
+ this.revisions.sweep();
185
+ }
186
+ get size(): number {
187
+ return this.#active.size;
188
+ }
189
+ }