@gajae-code/coding-agent 0.13.2 → 0.14.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 (610) hide show
  1. package/CHANGELOG.md +215 -8
  2. package/README.md +2 -0
  3. package/bin/gajaessi.js +4 -0
  4. package/dist/types/async/job-manager.d.ts +55 -2
  5. package/dist/types/async/support.d.ts +14 -0
  6. package/dist/types/capability/mcp.d.ts +6 -0
  7. package/dist/types/capability/types.d.ts +6 -0
  8. package/dist/types/cli/accounts-cli.d.ts +19 -0
  9. package/dist/types/cli/args.d.ts +3 -0
  10. package/dist/types/cli/config-cli.d.ts +6 -0
  11. package/dist/types/cli/crash-cli.d.ts +10 -0
  12. package/dist/types/cli/customize-doctor.d.ts +145 -0
  13. package/dist/types/cli/daemon-cli.d.ts +3 -1
  14. package/dist/types/cli/mcp-cli.d.ts +11 -0
  15. package/dist/types/cli/notify-cli.d.ts +1 -1
  16. package/dist/types/cli/root-flags.d.ts +12 -0
  17. package/dist/types/cli/setup-cli.d.ts +3 -1
  18. package/dist/types/cli/skills-cli.d.ts +2 -1
  19. package/dist/types/cli/update-cli.d.ts +19 -1
  20. package/dist/types/cli.d.ts +6 -0
  21. package/dist/types/commands/accounts.d.ts +40 -0
  22. package/dist/types/commands/crash.d.ts +24 -0
  23. package/dist/types/commands/customize.d.ts +22 -0
  24. package/dist/types/commands/daemon.d.ts +1 -1
  25. package/dist/types/commands/launch.d.ts +6 -0
  26. package/dist/types/commands/setup.d.ts +6 -0
  27. package/dist/types/commands/skills.d.ts +6 -1
  28. package/dist/types/commands/update.d.ts +7 -0
  29. package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
  30. package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
  31. package/dist/types/config/config-schema-version.d.ts +10 -0
  32. package/dist/types/config/file-lock.d.ts +18 -0
  33. package/dist/types/config/model-profile-activation.d.ts +3 -1
  34. package/dist/types/config/model-registry.d.ts +10 -1
  35. package/dist/types/config/models-config-schema.d.ts +2 -0
  36. package/dist/types/config/settings-schema.d.ts +73 -9
  37. package/dist/types/config/settings.d.ts +63 -0
  38. package/dist/types/config/skill-settings-defaults.d.ts +26 -0
  39. package/dist/types/config/task-delegation.d.ts +39 -0
  40. package/dist/types/config/update-channel.d.ts +10 -0
  41. package/dist/types/coordinator-mcp/server.d.ts +5 -1
  42. package/dist/types/crash/index-store.d.ts +87 -0
  43. package/dist/types/crash/nudge.d.ts +50 -0
  44. package/dist/types/crash/record-loader.d.ts +17 -0
  45. package/dist/types/crash/report.d.ts +134 -0
  46. package/dist/types/crash/sanitize.d.ts +25 -0
  47. package/dist/types/cursor.d.ts +13 -2
  48. package/dist/types/customization/import.d.ts +37 -0
  49. package/dist/types/customization/index.d.ts +4 -0
  50. package/dist/types/customization/inventory.d.ts +25 -0
  51. package/dist/types/customization/mutations.d.ts +32 -0
  52. package/dist/types/customization/types.d.ts +115 -0
  53. package/dist/types/daemon/control-types.d.ts +8 -1
  54. package/dist/types/daemon/operator-contract.d.ts +4 -4
  55. package/dist/types/discovery/claude.d.ts +39 -1
  56. package/dist/types/discovery/codex.d.ts +39 -1
  57. package/dist/types/discovery/index.d.ts +2 -0
  58. package/dist/types/discovery/mcp-compat.d.ts +30 -0
  59. package/dist/types/edit/renderer.d.ts +23 -0
  60. package/dist/types/extensibility/extensions/runner.d.ts +3 -0
  61. package/dist/types/extensibility/extensions/types.d.ts +21 -4
  62. package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
  63. package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
  64. package/dist/types/extensibility/hooks/loader.d.ts +19 -5
  65. package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
  66. package/dist/types/extensibility/skill-management.d.ts +107 -0
  67. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
  68. package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
  69. package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
  70. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
  71. package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
  72. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
  73. package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
  74. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
  75. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
  76. package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
  77. package/dist/types/hooks/events.d.ts +60 -0
  78. package/dist/types/hooks/normalize.d.ts +83 -0
  79. package/dist/types/hooks/skill-state.d.ts +9 -2
  80. package/dist/types/main.d.ts +2 -1
  81. package/dist/types/modes/acp/abort-scope.d.ts +13 -0
  82. package/dist/types/modes/acp/acp-agent.d.ts +7 -4
  83. package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
  84. package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
  85. package/dist/types/modes/components/customization/index.d.ts +1 -0
  86. package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
  87. package/dist/types/modes/components/gajae-pet-widget.d.ts +6 -28
  88. package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
  89. package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
  90. package/dist/types/modes/components/oauth-selector.d.ts +10 -4
  91. package/dist/types/modes/components/pet-capability.d.ts +7 -21
  92. package/dist/types/modes/components/settings-selector.d.ts +5 -0
  93. package/dist/types/modes/components/status-line/gh.d.ts +6 -2
  94. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  95. package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
  96. package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
  97. package/dist/types/modes/interactive-mode.d.ts +1 -0
  98. package/dist/types/modes/theme/defaults/index.d.ts +118 -0
  99. package/dist/types/modes/types.d.ts +1 -0
  100. package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
  101. package/dist/types/runtime-mcp/config.d.ts +9 -0
  102. package/dist/types/runtime-mcp/manager.d.ts +26 -1
  103. package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
  104. package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
  105. package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
  106. package/dist/types/runtime-mcp/protocol.d.ts +278 -0
  107. package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
  108. package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
  109. package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
  110. package/dist/types/runtime-mcp/types.d.ts +102 -10
  111. package/dist/types/sdk/acp/adapter.d.ts +26 -5
  112. package/dist/types/sdk/broker/broker.d.ts +3 -55
  113. package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
  114. package/dist/types/sdk/broker/session-index.d.ts +14 -5
  115. package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
  116. package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
  117. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
  118. package/dist/types/sdk/bus/config.d.ts +11 -0
  119. package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
  120. package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
  121. package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
  122. package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
  123. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
  124. package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
  125. package/dist/types/sdk/bus/index.d.ts +85 -99
  126. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
  127. package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
  128. package/dist/types/sdk/bus/notification-service.d.ts +52 -0
  129. package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
  130. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
  131. package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
  132. package/dist/types/sdk/bus/session-control.d.ts +25 -1
  133. package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
  134. package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
  135. package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
  136. package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
  137. package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
  138. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
  139. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
  140. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
  141. package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
  142. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
  143. package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
  144. package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
  145. package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
  146. package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
  147. package/dist/types/sdk/cli/rows.d.ts +2 -11
  148. package/dist/types/sdk/cli/session-cli.d.ts +15 -25
  149. package/dist/types/sdk/client/client.d.ts +97 -1
  150. package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
  151. package/dist/types/sdk/host/control/index.d.ts +1 -1
  152. package/dist/types/sdk/host/control/operations.d.ts +18 -5
  153. package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
  154. package/dist/types/sdk/host/host.d.ts +15 -1
  155. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  156. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  157. package/dist/types/sdk/host/session-runtime.d.ts +127 -7
  158. package/dist/types/sdk/host/types.d.ts +1 -1
  159. package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
  160. package/dist/types/sdk/index.d.ts +2 -1
  161. package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
  162. package/dist/types/sdk/lifecycle/client.d.ts +59 -0
  163. package/dist/types/sdk/lifecycle/index.d.ts +3 -0
  164. package/dist/types/sdk/lifecycle/service.d.ts +232 -0
  165. package/dist/types/sdk/mcp/server.d.ts +9 -6
  166. package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
  167. package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
  168. package/dist/types/sdk/prompt-status.d.ts +10 -3
  169. package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
  170. package/dist/types/sdk/receipt-state.d.ts +17 -0
  171. package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
  172. package/dist/types/sdk/router/index.d.ts +1 -0
  173. package/dist/types/sdk/router/session-router.d.ts +152 -0
  174. package/dist/types/sdk/session-list.d.ts +22 -0
  175. package/dist/types/sdk/session-reconnect.d.ts +43 -1
  176. package/dist/types/sdk/session.d.ts +34 -1
  177. package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
  178. package/dist/types/session/account-inventory.d.ts +86 -0
  179. package/dist/types/session/agent-session.d.ts +145 -6
  180. package/dist/types/session/agent-storage.d.ts +10 -0
  181. package/dist/types/session/coordinator-tool-label.d.ts +28 -0
  182. package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
  183. package/dist/types/session/messages.d.ts +1 -1
  184. package/dist/types/session/secure-token-file.d.ts +3 -0
  185. package/dist/types/session/session-manager.d.ts +47 -1
  186. package/dist/types/session/startup-auth-config.d.ts +44 -0
  187. package/dist/types/session/terminal-abort.d.ts +378 -0
  188. package/dist/types/session/yield-queue.d.ts +7 -0
  189. package/dist/types/session-import/claude.d.ts +26 -0
  190. package/dist/types/session-import/codex.d.ts +88 -0
  191. package/dist/types/session-import/command.d.ts +35 -0
  192. package/dist/types/session-import/detect.d.ts +22 -0
  193. package/dist/types/session-import/index.d.ts +7 -0
  194. package/dist/types/session-import/provider-codex.d.ts +22 -0
  195. package/dist/types/session-import/provider-service.d.ts +38 -0
  196. package/dist/types/session-import/redact.d.ts +23 -0
  197. package/dist/types/session-import/service.d.ts +47 -0
  198. package/dist/types/session-import/types.d.ts +120 -0
  199. package/dist/types/setup/paseo/check.d.ts +16 -0
  200. package/dist/types/setup/paseo/install-saga.d.ts +115 -0
  201. package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
  202. package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
  203. package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
  204. package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
  205. package/dist/types/setup/paseo/provider-config.d.ts +35 -0
  206. package/dist/types/setup/paseo/remove.d.ts +14 -0
  207. package/dist/types/setup/paseo/result-types.d.ts +59 -0
  208. package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
  209. package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
  210. package/dist/types/skill-state/active-state.d.ts +5 -1
  211. package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
  212. package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
  213. package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
  214. package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
  215. package/dist/types/slash-commands/types.d.ts +7 -1
  216. package/dist/types/task/executor.d.ts +10 -0
  217. package/dist/types/task/index.d.ts +3 -1
  218. package/dist/types/tools/ask-answer-registry.d.ts +6 -3
  219. package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
  220. package/dist/types/tools/bash.d.ts +2 -6
  221. package/dist/types/tools/browser/attach.d.ts +11 -0
  222. package/dist/types/tools/browser/launch.d.ts +20 -0
  223. package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
  224. package/dist/types/tools/browser/render.d.ts +1 -0
  225. package/dist/types/tools/browser.d.ts +3 -1
  226. package/dist/types/tools/image-gen.d.ts +10 -2
  227. package/dist/types/tools/index.d.ts +8 -0
  228. package/dist/types/tools/monitor.d.ts +1 -1
  229. package/dist/types/tools/skill-discovery.d.ts +8 -1
  230. package/dist/types/tools/subagent.d.ts +2 -0
  231. package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
  232. package/dist/types/utils/herdr-pane.d.ts +76 -0
  233. package/package.json +19 -9
  234. package/scripts/build-binary.ts +2 -1
  235. package/scripts/build-sdk-package-smoke.ts +2 -13
  236. package/scripts/capture-sticky-viewport-showcase.ts +0 -1
  237. package/scripts/compile-args.ts +2 -0
  238. package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
  239. package/scripts/generate-sdk-operation-inventory.ts +28 -0
  240. package/scripts/generate-telegram-baseline-manifest.ts +1 -0
  241. package/scripts/generate-tool-catalog.ts +6 -4
  242. package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
  243. package/src/async/job-manager.ts +352 -17
  244. package/src/async/support.ts +25 -0
  245. package/src/autoresearch/dashboard.ts +28 -13
  246. package/src/capability/index.ts +3 -1
  247. package/src/capability/mcp.ts +6 -0
  248. package/src/capability/types.ts +6 -0
  249. package/src/cli/accounts-cli.ts +395 -0
  250. package/src/cli/args.ts +23 -0
  251. package/src/cli/auth-broker-cli.ts +136 -66
  252. package/src/cli/auth-gateway-cli.ts +94 -70
  253. package/src/cli/config-cli.ts +27 -2
  254. package/src/cli/crash-cli.ts +78 -0
  255. package/src/cli/customize-doctor.ts +1605 -0
  256. package/src/cli/daemon-cli.ts +12 -3
  257. package/src/cli/fast-help.ts +1 -0
  258. package/src/cli/mcp-cli.ts +128 -60
  259. package/src/cli/notify-cli.ts +8 -14
  260. package/src/cli/root-flags.ts +8 -0
  261. package/src/cli/setup-cli.ts +145 -0
  262. package/src/cli/skills-cli.ts +38 -2
  263. package/src/cli/update-cli.ts +167 -12
  264. package/src/cli.ts +4 -0
  265. package/src/commands/accounts.ts +71 -0
  266. package/src/commands/crash.ts +35 -0
  267. package/src/commands/customize.ts +84 -0
  268. package/src/commands/daemon.ts +2 -2
  269. package/src/commands/deep-interview.ts +2 -0
  270. package/src/commands/launch.ts +1 -0
  271. package/src/commands/mcp.ts +12 -7
  272. package/src/commands/ralplan.ts +2 -0
  273. package/src/commands/sdk.ts +65 -32
  274. package/src/commands/setup.ts +5 -0
  275. package/src/commands/skills.ts +14 -4
  276. package/src/commands/ultragoal.ts +10 -1
  277. package/src/commands/update.ts +26 -15
  278. package/src/config/atomic-yaml-patch-worker.ts +57 -0
  279. package/src/config/atomic-yaml-patch.ts +769 -29
  280. package/src/config/config-schema-version.ts +10 -0
  281. package/src/config/file-lock.ts +70 -1
  282. package/src/config/mcp-schema.json +52 -14
  283. package/src/config/model-profile-activation.ts +23 -2
  284. package/src/config/model-profiles.ts +88 -21
  285. package/src/config/model-registry.ts +147 -21
  286. package/src/config/models-config-schema.ts +1 -1
  287. package/src/config/settings-schema.ts +77 -7
  288. package/src/config/settings.ts +4038 -199
  289. package/src/config/skill-settings-defaults.ts +41 -3
  290. package/src/config/task-delegation.ts +87 -0
  291. package/src/config/update-channel.ts +23 -0
  292. package/src/coordinator-mcp/server.ts +377 -308
  293. package/src/crash/index-store.ts +723 -0
  294. package/src/crash/nudge.ts +89 -0
  295. package/src/crash/record-loader.ts +149 -0
  296. package/src/crash/report.ts +551 -0
  297. package/src/crash/sanitize.ts +129 -0
  298. package/src/cursor.ts +36 -10
  299. package/src/customization/import.ts +946 -0
  300. package/src/customization/index.ts +4 -0
  301. package/src/customization/inventory.ts +335 -0
  302. package/src/customization/mutations.ts +141 -0
  303. package/src/customization/types.ts +223 -0
  304. package/src/daemon/control-types.ts +8 -1
  305. package/src/daemon/operator-contract.ts +6 -6
  306. package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
  307. package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
  308. package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
  309. package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
  310. package/src/discovery/claude-hooks.ts +38 -0
  311. package/src/discovery/claude.ts +142 -209
  312. package/src/discovery/codex-hooks.ts +38 -0
  313. package/src/discovery/codex.ts +132 -198
  314. package/src/discovery/helpers.ts +8 -1
  315. package/src/discovery/index.ts +2 -0
  316. package/src/discovery/mcp-compat.ts +234 -0
  317. package/src/discovery/mcp-json.ts +6 -0
  318. package/src/edit/renderer.ts +40 -0
  319. package/src/edit/streaming.ts +4 -2
  320. package/src/exec/bash-executor.ts +24 -20
  321. package/src/export/html/index.ts +51 -2
  322. package/src/extensibility/extensions/loader.ts +9 -1
  323. package/src/extensibility/extensions/runner.ts +17 -4
  324. package/src/extensibility/extensions/types.ts +31 -6
  325. package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
  326. package/src/extensibility/gjc-plugins/installer.ts +9 -5
  327. package/src/extensibility/gjc-plugins/observability.ts +8 -2
  328. package/src/extensibility/gjc-plugins/registry.ts +13 -2
  329. package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
  330. package/src/extensibility/gjc-plugins/schema.ts +222 -39
  331. package/src/extensibility/hooks/loader.ts +154 -10
  332. package/src/extensibility/runtime-skill-discovery.ts +257 -60
  333. package/src/extensibility/skill-management.ts +368 -0
  334. package/src/extensibility/skills.ts +52 -16
  335. package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
  336. package/src/gjc-runtime/launch-worktree.ts +56 -2
  337. package/src/gjc-runtime/linux-proc.ts +7 -1
  338. package/src/gjc-runtime/ralplan-runtime.ts +100 -164
  339. package/src/gjc-runtime/session-state-lock.ts +992 -0
  340. package/src/gjc-runtime/session-state-sidecar.ts +644 -142
  341. package/src/gjc-runtime/state-writer.ts +39 -14
  342. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
  343. package/src/gjc-runtime/ultragoal-guard.ts +11 -4
  344. package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
  345. package/src/gjc-runtime/workflow-settings.ts +596 -0
  346. package/src/goals/tools/goal-tool.ts +6 -1
  347. package/src/hooks/events.ts +291 -0
  348. package/src/hooks/native-skill-hook.ts +4 -0
  349. package/src/hooks/normalize.ts +369 -0
  350. package/src/hooks/skill-state.ts +165 -46
  351. package/src/internal-urls/docs-index.generated.ts +41 -32
  352. package/src/main.ts +36 -5
  353. package/src/migrate/mcp-mapper.ts +25 -2
  354. package/src/modes/acp/abort-scope.ts +29 -0
  355. package/src/modes/acp/acp-agent.ts +423 -98
  356. package/src/modes/components/assistant-message.ts +6 -1
  357. package/src/modes/components/chrome.ts +4 -3
  358. package/src/modes/components/customization/customization-dashboard.ts +443 -0
  359. package/src/modes/components/customization/import-wizard.ts +372 -0
  360. package/src/modes/components/customization/index.ts +1 -0
  361. package/src/modes/components/dynamic-theme-text.ts +22 -0
  362. package/src/modes/components/gajae-pet-widget.ts +607 -193
  363. package/src/modes/components/irc-sidebar.ts +11 -0
  364. package/src/modes/components/iterm-pet-transport.ts +585 -0
  365. package/src/modes/components/model-selector.ts +1 -6
  366. package/src/modes/components/oauth-selector.ts +277 -86
  367. package/src/modes/components/pet-capability.ts +35 -31
  368. package/src/modes/components/settings-selector.ts +29 -5
  369. package/src/modes/components/status-line/gh.ts +45 -1
  370. package/src/modes/components/status-line/segments.ts +19 -4
  371. package/src/modes/components/tool-status-header.ts +13 -3
  372. package/src/modes/controllers/command-controller.ts +20 -8
  373. package/src/modes/controllers/extension-ui-controller.ts +56 -257
  374. package/src/modes/controllers/input-controller.ts +10 -0
  375. package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
  376. package/src/modes/controllers/selector-controller.ts +238 -77
  377. package/src/modes/controllers/stt-controller.ts +3 -3
  378. package/src/modes/interactive-mode.ts +88 -16
  379. package/src/modes/print-mode.ts +35 -6
  380. package/src/modes/runtime-init.ts +21 -68
  381. package/src/modes/theme/defaults/index.ts +2 -0
  382. package/src/modes/theme/defaults/ouroboros.json +118 -0
  383. package/src/modes/types.ts +1 -0
  384. package/src/modes/utils/injected-user-submission.ts +25 -0
  385. package/src/modes/utils/terminal-bell.ts +15 -1
  386. package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
  387. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  388. package/src/prompts/agents/critic.md +1 -1
  389. package/src/prompts/system/rlm-research.md +1 -1
  390. package/src/prompts/system/system-prompt.md +0 -2
  391. package/src/prompts/tools/bash.md +7 -1
  392. package/src/prompts/tools/browser.md +1 -1
  393. package/src/prompts/tools/cron.md +6 -6
  394. package/src/prompts/tools/read.md +0 -2
  395. package/src/prompts/tools/skill-discovery.md +4 -2
  396. package/src/runtime-mcp/client.ts +427 -23
  397. package/src/runtime-mcp/config.ts +37 -5
  398. package/src/runtime-mcp/manager-pool.test.ts +56 -0
  399. package/src/runtime-mcp/manager.ts +52 -2
  400. package/src/runtime-mcp/oauth-discovery.ts +13 -0
  401. package/src/runtime-mcp/oauth-flow.ts +46 -1
  402. package/src/runtime-mcp/pool-key.ts +5 -1
  403. package/src/runtime-mcp/pool.test.ts +9 -0
  404. package/src/runtime-mcp/protocol.test.ts +353 -0
  405. package/src/runtime-mcp/protocol.ts +624 -0
  406. package/src/runtime-mcp/scope-config.ts +78 -0
  407. package/src/runtime-mcp/tool-bridge.ts +44 -10
  408. package/src/runtime-mcp/transports/http.ts +84 -13
  409. package/src/runtime-mcp/types.ts +123 -12
  410. package/src/sdk/acp/adapter.ts +328 -97
  411. package/src/sdk/broker/broker.ts +160 -741
  412. package/src/sdk/broker/ensure.ts +9 -1
  413. package/src/sdk/broker/lifecycle.ts +510 -116
  414. package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
  415. package/src/sdk/broker/process-incarnation.ts +19 -0
  416. package/src/sdk/broker/session-index.ts +516 -117
  417. package/src/sdk/broker/startup-failure.ts +28 -5
  418. package/src/sdk/broker/transport.ts +1 -13
  419. package/src/sdk/bus/chat-daemon-cli.ts +4 -2
  420. package/src/sdk/bus/chat-daemon-control.ts +67 -6
  421. package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
  422. package/src/sdk/bus/config.ts +13 -0
  423. package/src/sdk/bus/conversation-store.ts +59 -171
  424. package/src/sdk/bus/daemon-paths.ts +20 -0
  425. package/src/sdk/bus/discord-conversation.ts +2 -0
  426. package/src/sdk/bus/discord-daemon.ts +524 -126
  427. package/src/sdk/bus/discord-live-provider.ts +206 -79
  428. package/src/sdk/bus/existing-thread-readiness.ts +4 -97
  429. package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
  430. package/src/sdk/bus/index.ts +2480 -456
  431. package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
  432. package/src/sdk/bus/lifecycle-commands.ts +2 -2
  433. package/src/sdk/bus/managed-daemon.ts +2 -145
  434. package/src/sdk/bus/notification-service.ts +196 -0
  435. package/src/sdk/bus/operator-runtime.ts +1 -1
  436. package/src/sdk/bus/prompt-reconciliation.ts +24 -15
  437. package/src/sdk/bus/reconciliation-store.ts +553 -24
  438. package/src/sdk/bus/session-control.ts +49 -3
  439. package/src/sdk/bus/slack-conversation.ts +4 -0
  440. package/src/sdk/bus/slack-daemon.ts +733 -134
  441. package/src/sdk/bus/slack-live-provider.ts +65 -15
  442. package/src/sdk/bus/slack-provider.ts +4 -0
  443. package/src/sdk/bus/slack-thread-binding.ts +9 -104
  444. package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
  445. package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
  446. package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
  447. package/src/sdk/bus/telegram-daemon-control.ts +3 -13
  448. package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
  449. package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
  450. package/src/sdk/bus/telegram-daemon.ts +2552 -2280
  451. package/src/sdk/bus/telegram-reference.ts +1 -226
  452. package/src/sdk/bus/telegram-setup.ts +2 -2
  453. package/src/sdk/bus/threaded-render.ts +1 -0
  454. package/src/sdk/bus/topic-registry.ts +279 -146
  455. package/src/sdk/cli/rows.ts +2 -35
  456. package/src/sdk/cli/session-cli.ts +776 -700
  457. package/src/sdk/client/client.ts +892 -1
  458. package/src/sdk/host/control/dispatch.ts +93 -58
  459. package/src/sdk/host/control/index.ts +1 -1
  460. package/src/sdk/host/control/operations.ts +18 -10
  461. package/src/sdk/host/control/runtime-gate.ts +40 -0
  462. package/src/sdk/host/host.ts +63 -12
  463. package/src/sdk/host/query/handlers.ts +66 -7
  464. package/src/sdk/host/reverse-leases.ts +2 -2
  465. package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
  466. package/src/sdk/host/session-runtime.test.ts +2787 -34
  467. package/src/sdk/host/session-runtime.ts +1489 -101
  468. package/src/sdk/host/surface-policy.ts +12 -8
  469. package/src/sdk/host/types.ts +1 -1
  470. package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
  471. package/src/sdk/host/websocket-transport.ts +85 -50
  472. package/src/sdk/index.ts +2 -1
  473. package/src/sdk/lifecycle/broker-client.ts +53 -0
  474. package/src/sdk/lifecycle/client.ts +234 -0
  475. package/src/sdk/lifecycle/index.ts +3 -0
  476. package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
  477. package/src/sdk/lifecycle/service.ts +720 -0
  478. package/src/sdk/mcp/server.ts +226 -188
  479. package/src/sdk/prompt-deadline-lease.ts +55 -0
  480. package/src/sdk/prompt-deadline-manager.ts +148 -0
  481. package/src/sdk/prompt-status.ts +11 -3
  482. package/src/sdk/protocol/operation-inventory.generated.json +272 -129
  483. package/src/sdk/protocol/operation-registry.ts +71 -8
  484. package/src/sdk/receipt-state.ts +43 -0
  485. package/src/sdk/reconciliation-extensions.ts +14 -0
  486. package/src/sdk/router/index.ts +1 -0
  487. package/src/sdk/router/session-router.ts +1658 -0
  488. package/src/sdk/session-list.ts +93 -0
  489. package/src/sdk/session-reconnect.ts +45 -1
  490. package/src/sdk/session.ts +716 -120
  491. package/src/sdk/transport/serve-cli.ts +18 -34
  492. package/src/session/account-inventory.ts +603 -0
  493. package/src/session/agent-session.ts +2873 -559
  494. package/src/session/agent-storage.ts +35 -0
  495. package/src/session/blob-store.ts +32 -1
  496. package/src/session/coordinator-tool-label.ts +40 -0
  497. package/src/session/internal/managed-session-scope.ts +4 -0
  498. package/src/session/internal/managed-session-storage.ts +199 -31
  499. package/src/session/messages.ts +1 -1
  500. package/src/session/secure-token-file.ts +80 -0
  501. package/src/session/session-manager.ts +757 -57
  502. package/src/session/session-storage.ts +25 -16
  503. package/src/session/startup-auth-config.ts +297 -0
  504. package/src/session/terminal-abort.ts +1253 -0
  505. package/src/session/yield-queue.ts +57 -15
  506. package/src/session-import/claude.ts +334 -0
  507. package/src/session-import/codex.ts +1033 -0
  508. package/src/session-import/command.ts +77 -0
  509. package/src/session-import/detect.ts +133 -0
  510. package/src/session-import/index.ts +7 -0
  511. package/src/session-import/provider-codex.ts +327 -0
  512. package/src/session-import/provider-service.ts +457 -0
  513. package/src/session-import/redact.ts +128 -0
  514. package/src/session-import/service.ts +1264 -0
  515. package/src/session-import/types.ts +148 -0
  516. package/src/setup/paseo/check.ts +213 -0
  517. package/src/setup/paseo/install-saga.ts +293 -0
  518. package/src/setup/paseo/json-publisher.ts +263 -0
  519. package/src/setup/paseo/orchestration-preferences.ts +86 -0
  520. package/src/setup/paseo/paseo-ownership.ts +224 -0
  521. package/src/setup/paseo/paseo-setup.ts +253 -0
  522. package/src/setup/paseo/provider-config.ts +139 -0
  523. package/src/setup/paseo/remove.ts +183 -0
  524. package/src/setup/paseo/result-types.ts +79 -0
  525. package/src/setup/paseo/setup-deps.ts +175 -0
  526. package/src/setup/paseo/skills-bridge.ts +260 -0
  527. package/src/skill-state/active-state.ts +21 -11
  528. package/src/slash-commands/acp-builtins.ts +9 -1
  529. package/src/slash-commands/builtin-registry.ts +117 -19
  530. package/src/slash-commands/helpers/credential-switch.ts +143 -0
  531. package/src/slash-commands/helpers/mcp.ts +9 -3
  532. package/src/slash-commands/helpers/usage-report.ts +61 -56
  533. package/src/slash-commands/types.ts +7 -2
  534. package/src/task/executor.ts +30 -11
  535. package/src/task/index.ts +66 -7
  536. package/src/task/render.ts +23 -9
  537. package/src/tools/ask-answer-registry.ts +23 -7
  538. package/src/tools/ask.ts +8 -4
  539. package/src/tools/bash-sleep-advisory.ts +115 -0
  540. package/src/tools/bash.ts +98 -18
  541. package/src/tools/browser/attach.ts +71 -3
  542. package/src/tools/browser/launch.ts +86 -13
  543. package/src/tools/browser/profile-discovery.ts +57 -7
  544. package/src/tools/browser/render.ts +8 -1
  545. package/src/tools/browser.ts +130 -21
  546. package/src/tools/computer.enforcement.test.ts +1 -1
  547. package/src/tools/computer.ts +3 -2
  548. package/src/tools/cron.ts +12 -1
  549. package/src/tools/image-gen.ts +349 -142
  550. package/src/tools/index.ts +8 -0
  551. package/src/tools/job.ts +33 -6
  552. package/src/tools/monitor.ts +41 -2
  553. package/src/tools/skill-discovery.ts +21 -29
  554. package/src/tools/subagent.ts +142 -24
  555. package/src/tools/todo-contract.ts +55 -3
  556. package/src/tools/todo-write.ts +4 -3
  557. package/src/tools/tool-catalog.generated.ts +6 -6
  558. package/src/tools/ultragoal-ask-guard.ts +10 -3
  559. package/src/utils/herdr-pane.ts +345 -0
  560. package/src/utils/title-generator.ts +2 -0
  561. package/src/web/scrapers/index.ts +6 -4
  562. package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
  563. package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
  564. package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
  565. package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
  566. package/dist/types/runtime/lazy-service.test.d.ts +0 -1
  567. package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
  568. package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
  569. package/dist/types/runtime-mcp/config.test.d.ts +0 -1
  570. package/dist/types/runtime-mcp/http.test.d.ts +0 -1
  571. package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
  572. package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
  573. package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
  574. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
  575. package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
  576. package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
  577. package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
  578. package/dist/types/sdk/elevation/audit.d.ts +0 -93
  579. package/dist/types/sdk/elevation/capability.d.ts +0 -3
  580. package/dist/types/sdk/elevation/digest.d.ts +0 -72
  581. package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
  582. package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
  583. package/dist/types/sdk/elevation/owner.d.ts +0 -48
  584. package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
  585. package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
  586. package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
  587. package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
  588. package/dist/types/session/auth-broker-config.d.ts +0 -13
  589. package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
  590. package/dist/types/skills/skills.test.d.ts +0 -1
  591. package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
  592. package/dist/types/task/token-log.test.d.ts +0 -1
  593. package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
  594. package/dist/types/tools/descriptors.test.d.ts +0 -1
  595. package/scripts/g005-daemon-smoke.ts +0 -180
  596. package/scripts/g011-daemon-path-smoke.ts +0 -153
  597. package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
  598. package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
  599. package/src/sdk/bus/telegram-cli.ts +0 -212
  600. package/src/sdk/elevation/allowlist.ts +0 -54
  601. package/src/sdk/elevation/audit.ts +0 -208
  602. package/src/sdk/elevation/capability.ts +0 -41
  603. package/src/sdk/elevation/digest.ts +0 -129
  604. package/src/sdk/elevation/dispatch-receipt.ts +0 -184
  605. package/src/sdk/elevation/grant-ledger.ts +0 -1142
  606. package/src/sdk/elevation/owner.ts +0 -109
  607. package/src/session/auth-broker-config.ts +0 -109
  608. /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
  609. /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
  610. /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
@@ -11,6 +11,7 @@ import type {
11
11
  const API_BASE = "https://discord.com/api/v10";
12
12
  const GATEWAY_INTENTS = 1 + 512 + 32_768;
13
13
  const MAX_RATE_LIMIT_RETRIES = 2;
14
+ const REST_REQUEST_TIMEOUT_MS = 5_000;
14
15
  const NONCE_PREFIX = "<!-- gjc-thread-nonce:";
15
16
  const INVALID_SESSION_RECONNECT_DELAY_MS = 1_000;
16
17
  const TERMINAL_GATEWAY_CLOSE_CODES: ReadonlySet<number> = new Set([4_004, 4_010, 4_011, 4_012, 4_013, 4_014]);
@@ -42,6 +43,22 @@ export interface DiscordLiveProviderOptions {
42
43
  }
43
44
 
44
45
  type JsonRecord = Record<string, unknown>;
46
+ type DiscordRequestContext = {
47
+ deadline: number;
48
+ controller: AbortController;
49
+ signal: AbortSignal;
50
+ timeoutError: Error;
51
+ timeout: NodeJS.Timeout;
52
+ };
53
+
54
+ function discordRequestTimeoutError(): Error {
55
+ return new Error("Discord API request timed out");
56
+ }
57
+
58
+ function discordAbortError(signal: AbortSignal): Error {
59
+ const reason = signal.reason;
60
+ return reason instanceof Error ? reason : new Error("Discord API request aborted");
61
+ }
45
62
 
46
63
  /** Discord REST/Gateway implementation. The only credential is held privately and is never emitted. */
47
64
  export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticProvider {
@@ -112,33 +129,47 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
112
129
  name: string;
113
130
  nonce: string;
114
131
  }): Promise<DiscordThread> {
115
- const marker = `${NONCE_PREFIX}${input.nonce}${NONCE_SUFFIX}`;
116
- const starter = await this.#findStarterMessage(input.parentId, marker);
117
- if (starter?.thread) {
118
- const existing = this.#starterThread(starter.thread, input.guildId, input.parentId);
119
- if (!existing) throw new Error("Discord returned an invalid starter-message thread");
120
- return existing;
121
- }
122
- const messageId = starter?.id ?? (await this.#createStarterMessage(input.parentId, marker));
123
- const body = await this.#request(`/channels/${input.parentId}/messages/${messageId}/threads`, {
124
- method: "POST",
125
- body: JSON.stringify({ name: input.name, auto_archive_duration: 1_440 }),
132
+ return await this.#withRequestContext(undefined, async context => {
133
+ const marker = `${NONCE_PREFIX}${input.nonce}${NONCE_SUFFIX}`;
134
+ const starter = await this.#findStarterMessage(input.parentId, marker, context);
135
+ if (starter?.thread) {
136
+ const existing = this.#starterThread(starter.thread, input.guildId, input.parentId);
137
+ if (!existing) throw new Error("Discord returned an invalid starter-message thread");
138
+ return existing;
139
+ }
140
+ const messageId = starter?.id ?? (await this.#createStarterMessage(input.parentId, marker, context));
141
+ const body = await this.#request(
142
+ `/channels/${input.parentId}/messages/${messageId}/threads`,
143
+ {
144
+ method: "POST",
145
+ body: JSON.stringify({ name: input.name, auto_archive_duration: 1_440 }),
146
+ },
147
+ context,
148
+ );
149
+ return this.#thread(body, input.guildId, input.parentId);
126
150
  });
127
- return this.#thread(body, input.guildId, input.parentId);
128
151
  }
129
152
 
130
- async #createStarterMessage(parentId: string, marker: string): Promise<string> {
131
- const message = await this.#request(`/channels/${parentId}/messages`, {
132
- method: "POST",
133
- body: JSON.stringify({ content: marker }),
134
- });
153
+ async #createStarterMessage(parentId: string, marker: string, context: DiscordRequestContext): Promise<string> {
154
+ const message = await this.#request(
155
+ `/channels/${parentId}/messages`,
156
+ {
157
+ method: "POST",
158
+ body: JSON.stringify({ content: marker }),
159
+ },
160
+ context,
161
+ );
135
162
  const id = this.#string(message, "id");
136
163
  if (!id) throw new Error("Discord returned an invalid starter-message response");
137
164
  return id;
138
165
  }
139
166
 
140
- async #findStarterMessage(parentId: string, marker: string): Promise<{ id: string; thread?: unknown } | undefined> {
141
- const messages = await this.#request(`/channels/${parentId}/messages?limit=100`);
167
+ async #findStarterMessage(
168
+ parentId: string,
169
+ marker: string,
170
+ context: DiscordRequestContext,
171
+ ): Promise<{ id: string; thread?: unknown } | undefined> {
172
+ const messages = await this.#request(`/channels/${parentId}/messages?limit=100`, {}, context);
142
173
  if (!Array.isArray(messages)) return undefined;
143
174
  for (const message of messages) {
144
175
  if (!this.#messageContent(message).includes(marker)) continue;
@@ -153,21 +184,23 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
153
184
  }
154
185
 
155
186
  async findThreadByNonce(input: { guildId: string; parentId: string; nonce: string }): Promise<DiscordThread | null> {
156
- const marker = `${NONCE_PREFIX}${input.nonce}${NONCE_SUFFIX}`;
157
- const parentMessages = await this.#request(`/channels/${input.parentId}/messages?limit=100`);
158
- if (Array.isArray(parentMessages))
159
- for (const message of parentMessages) {
160
- if (!this.#messageContent(message).includes(marker)) continue;
161
- const thread = this.#starterThread(this.#record(message).thread, input.guildId, input.parentId);
162
- if (thread) return thread;
187
+ return await this.#withRequestContext(undefined, async context => {
188
+ const marker = `${NONCE_PREFIX}${input.nonce}${NONCE_SUFFIX}`;
189
+ const parentMessages = await this.#request(`/channels/${input.parentId}/messages?limit=100`, {}, context);
190
+ if (Array.isArray(parentMessages))
191
+ for (const message of parentMessages) {
192
+ if (!this.#messageContent(message).includes(marker)) continue;
193
+ const thread = this.#starterThread(this.#record(message).thread, input.guildId, input.parentId);
194
+ if (thread) return thread;
195
+ }
196
+ const candidates = await this.#listThreads(input.guildId, input.parentId, context);
197
+ for (const candidate of candidates) {
198
+ const messages = await this.#request(`/channels/${candidate.id}/messages?limit=25`, {}, context);
199
+ if (Array.isArray(messages) && messages.some(message => this.#messageContent(message).includes(marker)))
200
+ return candidate;
163
201
  }
164
- const candidates = await this.#listThreads(input.guildId, input.parentId);
165
- for (const candidate of candidates) {
166
- const messages = await this.#request(`/channels/${candidate.id}/messages?limit=25`);
167
- if (Array.isArray(messages) && messages.some(message => this.#messageContent(message).includes(marker)))
168
- return candidate;
169
- }
170
- return null;
202
+ return null;
203
+ });
171
204
  }
172
205
 
173
206
  async postMessage(input: {
@@ -242,15 +275,17 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
242
275
  async probeConfiguration(signal?: AbortSignal): Promise<DiscordConfigurationProbeResult> {
243
276
  if (signal?.aborted) return { ok: false, detail: "Discord configuration probe cancelled." };
244
277
  try {
245
- const currentUser = await this.#request("/users/@me", { signal });
246
- const botUserId = this.#string(currentUser, "id");
247
- if (!botUserId) return { ok: false, detail: "Discord returned an invalid bot identity." };
248
- const application = await this.#request("/applications/@me", { signal });
249
- const applicationId = this.#string(application, "id");
250
- if (!applicationId || applicationId !== this.applicationId) {
251
- return { ok: false, detail: "Discord application identity does not match the configured application ID." };
252
- }
253
- return { ok: true, detail: "Discord bot and application credentials are valid.", botUserId };
278
+ return await this.#withRequestContext(signal, async context => {
279
+ const currentUser = await this.#request("/users/@me", {}, context);
280
+ const botUserId = this.#string(currentUser, "id");
281
+ if (!botUserId) throw new Error("Discord returned an invalid bot identity.");
282
+ const application = await this.#request("/applications/@me", {}, context);
283
+ const applicationId = this.#string(application, "id");
284
+ if (!applicationId || applicationId !== this.applicationId) {
285
+ throw new Error("Discord application identity does not match the configured application ID.");
286
+ }
287
+ return { ok: true, detail: "Discord bot and application credentials are valid.", botUserId };
288
+ });
254
289
  } catch (error) {
255
290
  if (signal?.aborted) return { ok: false, detail: "Discord configuration probe cancelled." };
256
291
  const detail = error instanceof Error ? error.message : "Discord configuration probe failed.";
@@ -265,20 +300,25 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
265
300
  }): Promise<DiscordOneShotTestResult> {
266
301
  if (input.signal?.aborted) return { ok: false, detail: "Discord notification test cancelled." };
267
302
  try {
268
- const response = await this.#request(`/channels/${input.channelId}/messages`, {
269
- method: "POST",
270
- body: JSON.stringify({ content: input.message }),
271
- signal: input.signal,
303
+ return await this.#withRequestContext(input.signal, async context => {
304
+ const response = await this.#request(
305
+ `/channels/${input.channelId}/messages`,
306
+ {
307
+ method: "POST",
308
+ body: JSON.stringify({ content: input.message }),
309
+ },
310
+ context,
311
+ );
312
+ const messageId = this.#string(response, "id");
313
+ if (!messageId) {
314
+ return {
315
+ ok: false,
316
+ detail: "Discord may have accepted the message but returned no message receipt.",
317
+ uncertain: true,
318
+ };
319
+ }
320
+ return { ok: true, detail: "Discord notification test delivered.", messageId };
272
321
  });
273
- const messageId = this.#string(response, "id");
274
- if (!messageId) {
275
- return {
276
- ok: false,
277
- detail: "Discord may have accepted the message but returned no message receipt.",
278
- uncertain: true,
279
- };
280
- }
281
- return { ok: true, detail: "Discord notification test delivered.", messageId };
282
322
  } catch (error) {
283
323
  if (input.signal?.aborted) return { ok: false, detail: "Discord notification test cancelled." };
284
324
  const detail = error instanceof Error ? error.message : "Discord notification test failed.";
@@ -291,15 +331,17 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
291
331
  this.#onEvent = onEvent;
292
332
  this.#stopped = false;
293
333
  try {
294
- const me = await this.#request("/users/@me");
295
- const id = this.#string(me, "id");
296
- if (!id) throw new Error("Discord returned an invalid current-user response");
297
- this.#botUserId = id;
298
- const gateway = await this.#request("/gateway/bot");
299
- const url = this.#string(gateway, "url");
300
- if (!url) throw new Error("Discord returned an invalid gateway response");
301
- this.#gatewayUrl = url;
302
- this.#connect(url);
334
+ await this.#withRequestContext(undefined, async context => {
335
+ const me = await this.#request("/users/@me", {}, context);
336
+ const id = this.#string(me, "id");
337
+ if (!id) throw new Error("Discord returned an invalid current-user response");
338
+ this.#botUserId = id;
339
+ const gateway = await this.#request("/gateway/bot", {}, context);
340
+ const url = this.#string(gateway, "url");
341
+ if (!url) throw new Error("Discord returned an invalid gateway response");
342
+ this.#gatewayUrl = url;
343
+ this.#connect(url);
344
+ });
303
345
  } catch (error) {
304
346
  await this.stop();
305
347
  throw error;
@@ -462,16 +504,18 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
462
504
  );
463
505
  }
464
506
 
465
- async #listThreads(guildId: string, parentId: string): Promise<DiscordThread[]> {
507
+ async #listThreads(guildId: string, parentId: string, context: DiscordRequestContext): Promise<DiscordThread[]> {
466
508
  const result: DiscordThread[] = [];
467
- const active = this.#record(await this.#request(`/guilds/${guildId}/threads/active`));
509
+ const active = this.#record(await this.#request(`/guilds/${guildId}/threads/active`, {}, context));
468
510
  const activeThreads = active.threads;
469
511
  if (Array.isArray(activeThreads))
470
512
  for (const thread of activeThreads) {
471
513
  const parsed = this.#threadOrUndefined(thread, guildId, parentId);
472
514
  if (parsed) result.push(parsed);
473
515
  }
474
- const archived = this.#record(await this.#request(`/channels/${parentId}/threads/archived/public?limit=100`));
516
+ const archived = this.#record(
517
+ await this.#request(`/channels/${parentId}/threads/archived/public?limit=100`, {}, context),
518
+ );
475
519
  const archivedThreads = archived.threads;
476
520
  if (Array.isArray(archivedThreads))
477
521
  for (const thread of archivedThreads) {
@@ -481,29 +525,112 @@ export class DiscordLiveProvider implements DiscordProvider, DiscordDiagnosticPr
481
525
  return result;
482
526
  }
483
527
 
484
- async #request(path: string, init: RequestInit = {}): Promise<unknown> {
485
- return await this.#requestWithHeaders(
486
- path,
487
- { Authorization: `Bot ${this.#token}`, "Content-Type": "application/json" },
488
- init,
528
+ async #withRequestContext<T>(
529
+ callerSignal: AbortSignal | undefined,
530
+ run: (context: DiscordRequestContext) => Promise<T>,
531
+ ): Promise<T> {
532
+ const controller = new AbortController();
533
+ const timeoutError = discordRequestTimeoutError();
534
+ const deadline = this.#now() + REST_REQUEST_TIMEOUT_MS;
535
+ const signal = callerSignal ? AbortSignal.any([callerSignal, controller.signal]) : controller.signal;
536
+ const timeout = setTimeout(() => controller.abort(timeoutError), REST_REQUEST_TIMEOUT_MS);
537
+ const context: DiscordRequestContext = {
538
+ deadline,
539
+ controller,
540
+ signal,
541
+ timeoutError,
542
+ timeout,
543
+ };
544
+ try {
545
+ return await run(context);
546
+ } finally {
547
+ clearTimeout(timeout);
548
+ }
549
+ }
550
+
551
+ async #request(path: string, init: RequestInit = {}, context?: DiscordRequestContext): Promise<unknown> {
552
+ if (context) {
553
+ return await this.#requestWithHeaders(
554
+ path,
555
+ { Authorization: `Bot ${this.#token}`, "Content-Type": "application/json" },
556
+ init,
557
+ context,
558
+ );
559
+ }
560
+ return await this.#withRequestContext(init.signal ?? undefined, requestContext =>
561
+ this.#requestWithHeaders(
562
+ path,
563
+ { Authorization: `Bot ${this.#token}`, "Content-Type": "application/json" },
564
+ init,
565
+ requestContext,
566
+ ),
489
567
  );
490
568
  }
491
- async #interactionRequest(path: string, init: RequestInit = {}): Promise<unknown> {
492
- return await this.#requestWithHeaders(path, { "Content-Type": "application/json" }, init);
569
+ async #interactionRequest(path: string, init: RequestInit = {}, context?: DiscordRequestContext): Promise<unknown> {
570
+ if (context) return await this.#requestWithHeaders(path, { "Content-Type": "application/json" }, init, context);
571
+ return await this.#withRequestContext(init.signal ?? undefined, requestContext =>
572
+ this.#requestWithHeaders(path, { "Content-Type": "application/json" }, init, requestContext),
573
+ );
493
574
  }
494
- async #requestWithHeaders(path: string, headers: Record<string, string>, init: RequestInit): Promise<unknown> {
575
+ async #requestWithHeaders(
576
+ path: string,
577
+ headers: Record<string, string>,
578
+ init: RequestInit,
579
+ context: DiscordRequestContext,
580
+ ): Promise<unknown> {
495
581
  for (let attempt = 0; ; attempt++) {
582
+ this.#assertRequestDeadline(context);
496
583
  const mergedHeaders = new Headers(headers);
497
584
  for (const [key, value] of new Headers(init.headers)) mergedHeaders.set(key, value);
498
- const response = await this.#fetch(`${this.#apiBaseUrl}${path}`, { ...init, headers: mergedHeaders });
585
+ const response = await this.#requestPhase(
586
+ () =>
587
+ this.#fetch(`${this.#apiBaseUrl}${path}`, { ...init, headers: mergedHeaders, signal: context.signal }),
588
+ context,
589
+ );
499
590
  if (response.status !== 429) {
500
591
  if (!response.ok) throw new Error(`Discord API request failed (${response.status})`);
501
- return response.status === 204 ? undefined : await response.json();
592
+ return response.status === 204 ? undefined : await this.#responseJson(response, context);
502
593
  }
503
594
  if (attempt >= MAX_RATE_LIMIT_RETRIES) throw new Error("Discord API rate limit retry exhausted");
504
- const limited = this.#record(await response.json());
595
+ const limited = this.#record(await this.#responseJson(response, context));
505
596
  const seconds = this.#number(limited, "retry_after") ?? 1;
506
- await this.#sleep(Math.max(0, seconds * 1_000));
597
+ this.#assertRequestDeadline(context);
598
+ const retryRemaining = context.deadline - this.#now();
599
+ await this.#requestPhase(() => this.#sleep(Math.min(Math.max(0, seconds * 1_000), retryRemaining)), context);
600
+ }
601
+ }
602
+
603
+ async #responseJson(response: Response, context: DiscordRequestContext): Promise<unknown> {
604
+ return await this.#requestPhase(() => response.json(), context);
605
+ }
606
+
607
+ async #requestPhase<T>(phase: () => Promise<T> | T, context: DiscordRequestContext): Promise<T> {
608
+ this.#assertRequestDeadline(context);
609
+ const aborted = Promise.withResolvers<never>();
610
+ const onAbort = () => aborted.reject(discordAbortError(context.signal));
611
+ context.signal.addEventListener("abort", onAbort, { once: true });
612
+ if (context.signal.aborted) onAbort();
613
+ try {
614
+ const value = await Promise.race([Promise.resolve().then(phase), aborted.promise]);
615
+ this.#assertRequestDeadline(context);
616
+ return value as T;
617
+ } catch (error) {
618
+ if (context.controller.signal.aborted || this.#now() >= context.deadline) {
619
+ if (!context.controller.signal.aborted) context.controller.abort(context.timeoutError);
620
+ throw context.timeoutError;
621
+ }
622
+ throw error;
623
+ } finally {
624
+ context.signal.removeEventListener("abort", onAbort);
625
+ }
626
+ }
627
+
628
+ #assertRequestDeadline(context: DiscordRequestContext): void {
629
+ if (context.controller.signal.aborted) throw context.timeoutError;
630
+ if (context.signal.aborted) throw discordAbortError(context.signal);
631
+ if (this.#now() >= context.deadline) {
632
+ context.controller.abort(context.timeoutError);
633
+ throw context.timeoutError;
507
634
  }
508
635
  }
509
636
 
@@ -4,29 +4,17 @@
4
4
  * Stock startup publishes a session's readiness immediately, so the running
5
5
  * chat daemon surfaces the session and creates its own root before an operator
6
6
  * could ever name an existing one. A session that opts in is *prepared*
7
- * instead: its id, endpoint, and broker registration are discoverable authority
8
- * while readiness stays withheld, which leaves exactly one root claim for
9
- * `gjc notify bind-thread` to fill. Activation then publishes readiness once,
10
- * and the daemon adopts the bound root instead of replacing it.
7
+ * instead: readiness stays withheld while the provider applies its one root
8
+ * claim. The SessionRouter owns endpoint authority and activation; this module
9
+ * only proves that the provider mapping authorizes readiness publication.
11
10
  *
12
11
  * Nothing here mutates a mapping. The gate only reads the daemon-owned store to
13
- * prove a binding exists, and the activation client only asks the session's own
14
- * host to publish the readiness it withheld.
12
+ * prove a binding exists for the exact session and endpoint generation.
15
13
  */
16
14
 
17
- import type { SessionIndex } from "../broker/session-index";
18
- import { SdkClient } from "../client/client";
19
- import type { SdkSessionEndpoint, SdkSessionEndpointScope } from "../client/discovery";
20
15
  import type { SessionActivationGate } from "../host";
21
- import {
22
- type ActivatedPreparedSession,
23
- type PreparedSessionActivationClient,
24
- requestPreparedSessionActivation,
25
- SessionActivationError,
26
- } from "../session-activation";
27
16
  import type { ConversationStore } from "./conversation-store";
28
17
  import type { SlackConversation } from "./slack-conversation";
29
- import { resolveSessionBindingAuthority } from "./slack-thread-binding";
30
18
 
31
19
  /** Explicit, session-scoped opt-in for withholding readiness until a root is bound. */
32
20
  export const EXISTING_THREAD_BIND_ENV = "GJC_NOTIFY_BIND_EXISTING_THREAD";
@@ -72,84 +60,3 @@ export function createSlackBindingActivationGate(input: SlackBindingActivationIn
72
60
  );
73
61
  };
74
62
  }
75
-
76
- export type {
77
- ActivatedPreparedSession,
78
- PreparedSessionActivationClient,
79
- SessionActivationErrorCode,
80
- } from "../session-activation";
81
- export { requestPreparedSessionActivation, SessionActivationError } from "../session-activation";
82
-
83
- export interface PreparedSessionActivationInput {
84
- sessionIndex: SessionIndex;
85
- sessionId: string;
86
- }
87
-
88
- export interface PreparedSessionActivationDeps {
89
- readEndpoint?: (
90
- repo: string,
91
- sessionId: string,
92
- scope?: SdkSessionEndpointScope,
93
- ) => Promise<SdkSessionEndpoint | null>;
94
- connect?: (endpoint: { url: string; token: string }) => Promise<PreparedSessionActivationClient>;
95
- }
96
-
97
- /**
98
- * Ask a prepared session to publish the readiness it withheld.
99
- *
100
- * The same discovery authority the binding requires is resolved first, so an
101
- * unindexed, terminated, or endpoint-rolled session is refused before any
102
- * connection is opened. The request names the exact session and endpoint
103
- * generation, and the answer is accepted only when it proves both, so a
104
- * replacement session can never be activated in place of the requested one.
105
- * Activation is idempotent: an exact retry answers `already` without a second
106
- * readiness signal.
107
- */
108
- export async function activatePreparedSession(
109
- input: PreparedSessionActivationInput,
110
- deps: PreparedSessionActivationDeps = {},
111
- ): Promise<ActivatedPreparedSession> {
112
- const authority = await resolveSessionBindingAuthority({
113
- sessionIndex: input.sessionIndex,
114
- sessionId: input.sessionId,
115
- ...(deps.readEndpoint ? { readEndpoint: deps.readEndpoint } : {}),
116
- });
117
- if (!authority)
118
- throw new SessionActivationError(
119
- "session_not_live",
120
- "Session activation requires an exact live session endpoint.",
121
- );
122
- // Deliberately not a second discovery read. The authority proof is bound to
123
- // one endpoint file, verified by pid and mtime at one scope; re-resolving here
124
- // could connect to a replacement process whose endpoint generation repeats,
125
- // and the generation carried below could not tell the two apart.
126
- const endpoint = authority.endpoint;
127
- if (!endpoint.url || !endpoint.token)
128
- throw new SessionActivationError(
129
- "session_not_live",
130
- "Session activation requires a readable session discovery endpoint.",
131
- );
132
- let client: PreparedSessionActivationClient;
133
- try {
134
- client = await (deps.connect ?? defaultActivationClient)({ url: endpoint.url, token: endpoint.token });
135
- } catch {
136
- // Nothing was ever sent, so no activation can have been applied.
137
- throw new SessionActivationError("activation_unavailable", "The session endpoint could not be reached.");
138
- }
139
- try {
140
- return await requestPreparedSessionActivation(client, input.sessionId, authority.endpointGeneration);
141
- } finally {
142
- await client.close().catch(() => undefined);
143
- }
144
- }
145
-
146
- async function defaultActivationClient(endpoint: {
147
- url: string;
148
- token: string;
149
- }): Promise<PreparedSessionActivationClient> {
150
- const client = await SdkClient.connect(endpoint.url, endpoint.token, { reconnectAttempts: 0 });
151
- return {
152
- request: async frame => (await client.request(frame)) as Record<string, unknown>,
153
- close: async () => await client.close(),
154
- };
155
- }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Pure per-update inbound reaction transition ordering.
3
+ *
4
+ * Extracted from the Telegram daemon so the serialization and terminal-state
5
+ * contract is testable without daemon/attachment/topic-lease infrastructure.
6
+ * The production router dispatches notification frames without awaiting prior
7
+ * callbacks, so an `accepted` handler can still be in flight when the
8
+ * `consumed` handler runs. Chaining every transition for one update through a
9
+ * single promise keeps effects ordered, and skipping nonterminal transitions
10
+ * after a terminal one makes the terminal state monotonic: a late queued
11
+ * marker can never overwrite an already-sent consumed marker or retraction.
12
+ */
13
+
14
+ /** A single ordered Bot API reaction transition for one update id. */
15
+ export interface InboundReactionTransition {
16
+ /** Serialized in submission order per update id. */
17
+ readonly effect: () => Promise<void>;
18
+ /** Terminal transitions (consumed / retraction) close the update. */
19
+ readonly terminal: boolean;
20
+ }
21
+
22
+ /**
23
+ * Terminal tombstones are retained only for a bounded window of recent update
24
+ * ids. Telegram update ids are monotonically increasing per bot, so a stale
25
+ * `accepted` ack that could overwrite a terminal state always carries an id at
26
+ * or below the terminal one; ids far below the window are long-expired updates
27
+ * whose correction target no longer exists, so the daemon's own target lookup
28
+ * already ignores them.
29
+ */
30
+ export const INBOUND_REACTION_TOMBSTONE_WINDOW = 512;
31
+
32
+ export class InboundReactionSequencer {
33
+ /** Update ids whose reaction reached a terminal (consumed/retracted) state. */
34
+ readonly #terminal = new Map<number, true>();
35
+ /** Per-update serialization chain, deleted once settled. */
36
+ readonly #chains = new Map<number, Promise<void>>();
37
+
38
+ /** True once a terminal transition completed for this update. */
39
+ isTerminal(updateId: number): boolean {
40
+ return this.#terminal.has(updateId);
41
+ }
42
+
43
+ /**
44
+ * Enqueue one transition. The returned promise settles when the transition
45
+ * has run (or was skipped because a terminal state already closed it).
46
+ */
47
+ apply(updateId: number, transition: InboundReactionTransition): Promise<void> {
48
+ const run = async (): Promise<void> => {
49
+ if (this.#terminal.has(updateId)) return;
50
+ await transition.effect();
51
+ if (transition.terminal) {
52
+ this.#terminal.set(updateId, true);
53
+ this.#evictStaleTombstones(updateId);
54
+ }
55
+ };
56
+ const prior = this.#chains.get(updateId) ?? Promise.resolve();
57
+ const next = prior.then(run, run);
58
+ // The chain is retained only while unsettled work exists for the update;
59
+ // once settled it is deleted so the map cannot grow without bound. The
60
+ // stored tail never rejects (both arms handle) so an unawaited chain can
61
+ // never surface an unhandled rejection.
62
+ const settled = next.then(
63
+ () => this.#chains.delete(updateId),
64
+ () => this.#chains.delete(updateId),
65
+ );
66
+ this.#chains.set(
67
+ updateId,
68
+ settled.then(() => undefined),
69
+ );
70
+ return next;
71
+ }
72
+
73
+ /** @internal Test-only: number of retained per-update chains. */
74
+ debugChainCount(): number {
75
+ return this.#chains.size;
76
+ }
77
+
78
+ /** @internal Test-only: number of retained terminal tombstones. */
79
+ debugTombstoneCount(): number {
80
+ return this.#terminal.size;
81
+ }
82
+
83
+ /** Keep only recent terminal tombstones relative to the newest terminal id. */
84
+ #evictStaleTombstones(newestTerminalId: number): void {
85
+ // Distance-based, not count-based: any terminal id further than the
86
+ // retention window below the newest terminal id is evicted regardless of
87
+ // how many tombstones are currently retained, so the map stays bounded by
88
+ // the window while near-term tombstones always survive.
89
+ for (const updateId of this.#terminal.keys()) {
90
+ if (newestTerminalId - updateId >= INBOUND_REACTION_TOMBSTONE_WINDOW) this.#terminal.delete(updateId);
91
+ }
92
+ }
93
+ }
94
+
95
+ /** Body for setting an emoji reaction on an inbound Telegram message. */
96
+ export function inboundReactionSetPayload(
97
+ chatId: string,
98
+ messageId: number,
99
+ emoji: string,
100
+ ): {
101
+ chat_id: string;
102
+ message_id: number;
103
+ reaction: Array<{ type: "emoji"; emoji: string }>;
104
+ } {
105
+ return { chat_id: chatId, message_id: messageId, reaction: [{ type: "emoji", emoji }] };
106
+ }
107
+
108
+ /**
109
+ * Body for retracting a reaction. The Bot API clears a bot reaction with the
110
+ * empty reaction list; an empty `emoji` string is not a valid reaction and is
111
+ * silently rejected, leaving the stale queued marker visible.
112
+ */
113
+ export function inboundReactionRetractPayload(
114
+ chatId: string,
115
+ messageId: number,
116
+ ): {
117
+ chat_id: string;
118
+ message_id: number;
119
+ reaction: [];
120
+ } {
121
+ return { chat_id: chatId, message_id: messageId, reaction: [] };
122
+ }