@gajae-code/coding-agent 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/CHANGELOG.md +70 -2
  2. package/dist/types/append-only-mode.d.ts +1 -1
  3. package/dist/types/cli/args.d.ts +4 -5
  4. package/dist/types/cli/daemon-cli.d.ts +12 -1
  5. package/dist/types/cli/notify-cli.d.ts +21 -1
  6. package/dist/types/cli.d.ts +3 -0
  7. package/dist/types/commands/daemon.d.ts +39 -0
  8. package/dist/types/commands/launch.d.ts +3 -0
  9. package/dist/types/commands/notify.d.ts +28 -1
  10. package/dist/types/commands/sdk.d.ts +33 -0
  11. package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
  12. package/dist/types/config/model-profile-activation.d.ts +35 -15
  13. package/dist/types/config/model-profiles.d.ts +11 -5
  14. package/dist/types/config/model-registry.d.ts +3 -3
  15. package/dist/types/config/model-resolver.d.ts +39 -6
  16. package/dist/types/config/model-selector-value.d.ts +17 -0
  17. package/dist/types/config/models-config-schema.d.ts +10 -6
  18. package/dist/types/config/settings-schema.d.ts +133 -6
  19. package/dist/types/config/settings.d.ts +63 -35
  20. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
  21. package/dist/types/coordinator-mcp/server.d.ts +6 -49
  22. package/dist/types/daemon/builtin.d.ts +6 -5
  23. package/dist/types/daemon/control-types.d.ts +1 -1
  24. package/dist/types/discovery/mcp-json.d.ts +12 -1
  25. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  26. package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
  27. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
  28. package/dist/types/extensibility/extensions/loader.d.ts +10 -1
  29. package/dist/types/extensibility/extensions/runner.d.ts +3 -3
  30. package/dist/types/extensibility/extensions/types.d.ts +141 -16
  31. package/dist/types/extensibility/hooks/types.d.ts +1 -1
  32. package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
  33. package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
  34. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
  35. package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
  36. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
  37. package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
  38. package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
  39. package/dist/types/harness-control-plane/operate.d.ts +5 -5
  40. package/dist/types/harness-control-plane/owner.d.ts +18 -4
  41. package/dist/types/harness-control-plane/receipts.d.ts +0 -1
  42. package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
  43. package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
  44. package/dist/types/harness-control-plane/types.d.ts +3 -4
  45. package/dist/types/lsp/index.d.ts +1 -1
  46. package/dist/types/main.d.ts +32 -38
  47. package/dist/types/modes/acp/acp-agent.d.ts +224 -53
  48. package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
  49. package/dist/types/modes/acp/acp-mode.d.ts +6 -15
  50. package/dist/types/modes/acp/permission-mode.d.ts +4 -0
  51. package/dist/types/modes/acp/startup-options.d.ts +6 -0
  52. package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
  53. package/dist/types/modes/components/gajae-pet-widget.d.ts +1 -0
  54. package/dist/types/modes/components/model-selector.d.ts +1 -0
  55. package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
  56. package/dist/types/modes/components/pet-capability.d.ts +37 -0
  57. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  58. package/dist/types/modes/components/settings-selector.d.ts +15 -4
  59. package/dist/types/modes/components/welcome.d.ts +1 -1
  60. package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
  61. package/dist/types/modes/index.d.ts +0 -4
  62. package/dist/types/modes/interactive-mode.d.ts +5 -1
  63. package/dist/types/modes/runtime-init.d.ts +2 -2
  64. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
  65. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
  66. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
  67. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
  68. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
  69. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +169 -30
  70. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
  71. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
  72. package/dist/types/modes/types.d.ts +16 -1
  73. package/dist/types/runtime-mcp/client.d.ts +2 -0
  74. package/dist/types/runtime-mcp/config.d.ts +5 -1
  75. package/dist/types/runtime-mcp/manager.d.ts +8 -1
  76. package/dist/types/runtime-mcp/types.d.ts +4 -0
  77. package/dist/types/sdk/acp/adapter.d.ts +67 -0
  78. package/dist/types/sdk/acp/index.d.ts +2 -0
  79. package/dist/types/sdk/broker/broker.d.ts +53 -0
  80. package/dist/types/sdk/broker/discovery.d.ts +30 -0
  81. package/dist/types/sdk/broker/ensure.d.ts +33 -0
  82. package/dist/types/sdk/broker/identity.d.ts +3 -0
  83. package/dist/types/sdk/broker/index.d.ts +8 -0
  84. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
  85. package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
  86. package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
  87. package/dist/types/sdk/broker/runtime.d.ts +33 -0
  88. package/dist/types/sdk/broker/session-index.d.ts +57 -0
  89. package/dist/types/sdk/broker/state-version.d.ts +8 -0
  90. package/dist/types/sdk/broker/transport.d.ts +9 -0
  91. package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
  95. package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
  96. package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
  97. package/dist/types/sdk/bus/config.d.ts +274 -0
  98. package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
  99. package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
  100. package/dist/types/sdk/bus/discord-daemon.d.ts +45 -0
  101. package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
  102. package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
  103. package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
  104. package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
  105. package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
  106. package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
  107. package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
  108. package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
  109. package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
  110. package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
  111. package/dist/types/sdk/bus/session-control.d.ts +83 -0
  112. package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
  113. package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
  114. package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
  115. package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
  116. package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
  117. package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
  118. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
  119. package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
  120. package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +55 -17
  121. package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
  122. package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
  123. package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
  124. package/dist/types/sdk/cli/index.d.ts +1 -0
  125. package/dist/types/sdk/cli/session-cli.d.ts +19 -0
  126. package/dist/types/sdk/client/client.d.ts +1 -0
  127. package/dist/types/sdk/client/discovery.d.ts +27 -0
  128. package/dist/types/sdk/client/index.d.ts +2 -0
  129. package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
  130. package/dist/types/sdk/host/control/index.d.ts +2 -0
  131. package/dist/types/sdk/host/control/operations.d.ts +65 -0
  132. package/dist/types/sdk/host/events.d.ts +35 -0
  133. package/dist/types/sdk/host/host.d.ts +35 -0
  134. package/dist/types/sdk/host/index.d.ts +4 -0
  135. package/dist/types/sdk/host/query/cursor.d.ts +62 -0
  136. package/dist/types/sdk/host/query/handlers.d.ts +70 -0
  137. package/dist/types/sdk/host/query/index.d.ts +3 -0
  138. package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
  139. package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
  140. package/dist/types/sdk/host/types.d.ts +32 -0
  141. package/dist/types/sdk/index.d.ts +6 -0
  142. package/dist/types/sdk/lifecycle-session.d.ts +14 -0
  143. package/dist/types/sdk/mcp/index.d.ts +1 -0
  144. package/dist/types/sdk/mcp/server.d.ts +37 -0
  145. package/dist/types/sdk/models.d.ts +44 -0
  146. package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
  147. package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
  148. package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
  149. package/dist/types/sdk/startup-capability.d.ts +50 -0
  150. package/dist/types/session/agent-session.d.ts +114 -21
  151. package/dist/types/session/default-model-selection.d.ts +25 -0
  152. package/dist/types/session/fallback-chain-controller.d.ts +52 -0
  153. package/dist/types/session/session-manager.d.ts +58 -1
  154. package/dist/types/setup/credential-auto-import.d.ts +36 -6
  155. package/dist/types/tools/ask-answer-registry.d.ts +1 -1
  156. package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
  157. package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
  158. package/dist/types/tools/browser/launch.d.ts +22 -0
  159. package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
  160. package/dist/types/tools/browser/profile-posture.d.ts +37 -0
  161. package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
  162. package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
  163. package/dist/types/tools/browser/registry.d.ts +19 -0
  164. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  165. package/dist/types/tools/index.d.ts +8 -8
  166. package/package.json +34 -13
  167. package/scripts/build-sdk-package-smoke.ts +94 -0
  168. package/scripts/capture-notifications-settings-showcase.ts +435 -0
  169. package/scripts/compile-args.ts +4 -2
  170. package/scripts/g005-daemon-smoke.ts +4 -5
  171. package/scripts/g011-daemon-path-smoke.ts +5 -5
  172. package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
  173. package/scripts/generate-sdk-operation-inventory.ts +867 -0
  174. package/scripts/generate-telegram-baseline-manifest.ts +128 -0
  175. package/scripts/manifest-schema.ts +124 -0
  176. package/scripts/run-test-manifest.ts +153 -0
  177. package/scripts/run-threat-model-check.ts +157 -0
  178. package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
  179. package/scripts/verify-gjc-sdk-rename.ts +90 -0
  180. package/src/append-only-mode.ts +1 -1
  181. package/src/cli/args.ts +43 -12
  182. package/src/cli/auth-gateway-cli.ts +2 -2
  183. package/src/cli/config-cli.ts +2 -1
  184. package/src/cli/daemon-cli.ts +63 -14
  185. package/src/cli/list-models.ts +1 -1
  186. package/src/cli/notify-cli.ts +288 -286
  187. package/src/cli.ts +21 -2
  188. package/src/commands/daemon.ts +50 -6
  189. package/src/commands/harness.ts +93 -36
  190. package/src/commands/launch.ts +5 -2
  191. package/src/commands/mcp-serve.ts +19 -12
  192. package/src/commands/notify.ts +36 -3
  193. package/src/commands/sdk.ts +426 -0
  194. package/src/commit/agentic/agent.ts +1 -0
  195. package/src/config/atomic-yaml-patch.ts +423 -0
  196. package/src/config/model-profile-activation.ts +240 -89
  197. package/src/config/model-profiles.ts +37 -34
  198. package/src/config/model-registry.ts +51 -26
  199. package/src/config/model-resolver.ts +138 -51
  200. package/src/config/model-selector-value.ts +50 -0
  201. package/src/config/models-config-schema.ts +14 -21
  202. package/src/config/settings-schema.ts +128 -10
  203. package/src/config/settings.ts +1120 -158
  204. package/src/coordinator-mcp/model-preset.ts +74 -20
  205. package/src/coordinator-mcp/server.ts +1597 -3052
  206. package/src/daemon/builtin.ts +8 -5
  207. package/src/daemon/control-types.ts +1 -1
  208. package/src/defaults/gjc/skills/team/SKILL.md +4 -4
  209. package/src/discovery/mcp-json.ts +327 -20
  210. package/src/extensibility/custom-tools/types.ts +1 -1
  211. package/src/extensibility/extensions/compact-handler.ts +3 -3
  212. package/src/extensibility/extensions/get-commands-handler.ts +2 -2
  213. package/src/extensibility/extensions/loader.ts +69 -5
  214. package/src/extensibility/extensions/runner.ts +112 -4
  215. package/src/extensibility/extensions/types.ts +176 -17
  216. package/src/extensibility/hooks/types.ts +1 -1
  217. package/src/extensibility/slash-commands.ts +3 -3
  218. package/src/gjc-runtime/launch-tmux.ts +170 -86
  219. package/src/gjc-runtime/psmux-detect.ts +82 -4
  220. package/src/gjc-runtime/session-state-sidecar.ts +41 -31
  221. package/src/gjc-runtime/team-runtime.ts +54 -35
  222. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
  223. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -2
  224. package/src/gjc-runtime/tmux-sessions.ts +19 -13
  225. package/src/gjc-runtime/ultragoal-guard.ts +53 -6
  226. package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
  227. package/src/gjc-runtime/windows-powershell-command.ts +58 -0
  228. package/src/harness-control-plane/operate.ts +9 -9
  229. package/src/harness-control-plane/owner.ts +283 -39
  230. package/src/harness-control-plane/receipts.ts +0 -1
  231. package/src/harness-control-plane/sdk-transport.ts +395 -0
  232. package/src/harness-control-plane/session-transport.ts +94 -0
  233. package/src/harness-control-plane/types.ts +1 -1
  234. package/src/internal-urls/docs-index.generated.ts +36 -37
  235. package/src/lsp/client.ts +42 -6
  236. package/src/lsp/index.ts +2 -2
  237. package/src/main.ts +299 -204
  238. package/src/modes/DESIGN.md +258 -0
  239. package/src/modes/acp/acp-agent.ts +1228 -2612
  240. package/src/modes/acp/acp-client-bridge.ts +2 -20
  241. package/src/modes/acp/acp-event-mapper.ts +18 -2
  242. package/src/modes/acp/acp-mode.ts +8 -36
  243. package/src/modes/acp/permission-mode.ts +25 -0
  244. package/src/modes/acp/startup-options.ts +6 -0
  245. package/src/modes/components/agent-dashboard.ts +37 -17
  246. package/src/modes/components/custom-editor.ts +1 -0
  247. package/src/modes/components/gajae-pet-widget.ts +169 -20
  248. package/src/modes/components/model-selector.ts +93 -35
  249. package/src/modes/components/notifications-settings-editor.ts +1379 -0
  250. package/src/modes/components/pet-capability.ts +115 -0
  251. package/src/modes/components/pet-selector.ts +4 -6
  252. package/src/modes/components/settings-selector.ts +86 -11
  253. package/src/modes/components/welcome.ts +4 -4
  254. package/src/modes/controllers/command-controller.ts +1 -2
  255. package/src/modes/controllers/event-controller.ts +11 -16
  256. package/src/modes/controllers/extension-ui-controller.ts +357 -12
  257. package/src/modes/controllers/input-controller.ts +43 -13
  258. package/src/modes/controllers/selector-controller.ts +671 -44
  259. package/src/modes/index.ts +0 -22
  260. package/src/modes/interactive-mode.ts +108 -24
  261. package/src/modes/runtime-init.ts +298 -6
  262. package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
  263. package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
  264. package/src/modes/shared/agent-wire/event-contract.ts +7 -8
  265. package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
  266. package/src/modes/shared/agent-wire/event-observation.ts +16 -7
  267. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1254 -87
  268. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
  269. package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
  270. package/src/modes/types.ts +16 -1
  271. package/src/runtime-mcp/client.ts +94 -19
  272. package/src/runtime-mcp/config.ts +27 -15
  273. package/src/runtime-mcp/manager.ts +343 -105
  274. package/src/runtime-mcp/oauth-flow.ts +42 -12
  275. package/src/runtime-mcp/transports/http.ts +49 -19
  276. package/src/runtime-mcp/transports/stdio.ts +47 -28
  277. package/src/runtime-mcp/types.ts +10 -0
  278. package/src/sdk/acp/adapter.ts +418 -0
  279. package/src/sdk/acp/index.ts +2 -0
  280. package/src/sdk/broker/broker.ts +642 -0
  281. package/src/sdk/broker/discovery.ts +94 -0
  282. package/src/sdk/broker/ensure.ts +249 -0
  283. package/src/sdk/broker/identity.ts +42 -0
  284. package/src/sdk/broker/index.ts +8 -0
  285. package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
  286. package/src/sdk/broker/internal-source.bunfig.toml +1 -0
  287. package/src/sdk/broker/lifecycle-ledger.ts +286 -0
  288. package/src/sdk/broker/lifecycle.ts +2157 -0
  289. package/src/sdk/broker/process-incarnation.ts +159 -0
  290. package/src/sdk/broker/runtime.ts +164 -0
  291. package/src/sdk/broker/session-index.ts +318 -0
  292. package/src/sdk/broker/state-version.ts +23 -0
  293. package/src/sdk/broker/transport.ts +125 -0
  294. package/src/sdk/bus/chat-command-policy.ts +107 -0
  295. package/src/sdk/bus/chat-daemon-cli.ts +214 -0
  296. package/src/sdk/bus/chat-daemon-control.ts +713 -0
  297. package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
  298. package/src/sdk/bus/chat-effect-journal.ts +353 -0
  299. package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
  300. package/src/sdk/bus/config.ts +433 -0
  301. package/src/sdk/bus/conversation-store.ts +391 -0
  302. package/src/sdk/bus/discord-conversation.ts +85 -0
  303. package/src/sdk/bus/discord-daemon.ts +2275 -0
  304. package/src/sdk/bus/discord-live-provider.ts +521 -0
  305. package/src/sdk/bus/discord-provider.ts +56 -0
  306. package/src/{notifications → sdk/bus}/html-format.ts +2 -2
  307. package/src/sdk/bus/index.ts +3943 -0
  308. package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
  309. package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
  310. package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
  311. package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
  312. package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
  313. package/src/sdk/bus/natives-augment.d.ts +38 -0
  314. package/src/sdk/bus/notification-orchestration.ts +535 -0
  315. package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
  316. package/src/sdk/bus/session-control.ts +333 -0
  317. package/src/sdk/bus/slack-conversation.ts +74 -0
  318. package/src/sdk/bus/slack-daemon.ts +2144 -0
  319. package/src/sdk/bus/slack-live-provider.ts +380 -0
  320. package/src/sdk/bus/slack-provider.ts +76 -0
  321. package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
  322. package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
  323. package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
  324. package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
  325. package/src/{notifications → sdk/bus}/telegram-daemon.ts +502 -54
  326. package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
  327. package/src/sdk/bus/telegram-setup.ts +663 -0
  328. package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
  329. package/src/sdk/cli/index.ts +1 -0
  330. package/src/sdk/cli/session-cli.ts +275 -0
  331. package/src/sdk/client/client.ts +1 -0
  332. package/src/sdk/client/discovery.ts +108 -0
  333. package/src/sdk/client/index.ts +2 -0
  334. package/src/sdk/host/control/dispatch.ts +367 -0
  335. package/src/sdk/host/control/index.ts +10 -0
  336. package/src/sdk/host/control/operations.ts +63 -0
  337. package/src/sdk/host/events.ts +91 -0
  338. package/src/sdk/host/host.ts +296 -0
  339. package/src/sdk/host/index.ts +4 -0
  340. package/src/sdk/host/query/cursor.ts +189 -0
  341. package/src/sdk/host/query/handlers.ts +533 -0
  342. package/src/sdk/host/query/index.ts +3 -0
  343. package/src/sdk/host/query/revision-store.ts +1126 -0
  344. package/src/sdk/host/reverse-leases.ts +325 -0
  345. package/src/sdk/host/types.ts +29 -0
  346. package/src/sdk/index.ts +13 -0
  347. package/src/sdk/lifecycle-session.ts +39 -0
  348. package/src/sdk/mcp/index.ts +1 -0
  349. package/src/sdk/mcp/server.ts +332 -0
  350. package/src/sdk/models.ts +168 -0
  351. package/src/sdk/protocol/adapter-validation.ts +48 -0
  352. package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
  353. package/src/sdk/protocol/operation-registry.ts +312 -0
  354. package/src/{sdk.ts → sdk/session.ts} +339 -212
  355. package/src/sdk/startup-capability.ts +189 -0
  356. package/src/session/agent-session.ts +2470 -866
  357. package/src/session/default-model-selection.ts +93 -0
  358. package/src/session/fallback-chain-controller.ts +136 -0
  359. package/src/session/session-manager.ts +447 -13
  360. package/src/session/session-storage.ts +8 -1
  361. package/src/setup/credential-auto-import.ts +290 -35
  362. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
  363. package/src/slash-commands/builtin-registry.ts +33 -30
  364. package/src/task/executor.ts +62 -13
  365. package/src/tools/ask-answer-registry.ts +1 -1
  366. package/src/tools/ask.ts +13 -8
  367. package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
  368. package/src/tools/browser/benchmark/detector-report.ts +157 -0
  369. package/src/tools/browser/benchmark/run-suite.ts +39 -0
  370. package/src/tools/browser/launch.ts +124 -19
  371. package/src/tools/browser/profile-discovery.ts +63 -0
  372. package/src/tools/browser/profile-posture.ts +59 -0
  373. package/src/tools/browser/profile-reuse.ts +102 -0
  374. package/src/tools/browser/profile-warmup.ts +109 -0
  375. package/src/tools/browser/registry.ts +87 -11
  376. package/src/tools/browser/tab-protocol.ts +1 -0
  377. package/src/tools/browser/tab-supervisor.ts +1 -0
  378. package/src/tools/browser/tab-worker.ts +1 -1
  379. package/src/tools/browser.ts +6 -0
  380. package/src/tools/index.ts +8 -8
  381. package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
  382. package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
  383. package/src/tools/telegram-send.ts +2 -2
  384. package/vendor/insane-search/MANIFEST.json +2 -1
  385. package/vendor/insane-search/engine/bias_check.py +4 -1
  386. package/vendor/insane-search/engine/phase0.py +26 -1
  387. package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
  388. package/dist/types/modes/bridge/auth.d.ts +0 -12
  389. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
  390. package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
  391. package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
  392. package/dist/types/modes/bridge/event-stream.d.ts +0 -8
  393. package/dist/types/modes/rpc/host-tools.d.ts +0 -1
  394. package/dist/types/modes/rpc/host-uris.d.ts +0 -1
  395. package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
  396. package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
  397. package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
  398. package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
  399. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
  400. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
  401. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
  402. package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
  403. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
  404. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
  405. package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
  406. package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
  407. package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
  408. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
  409. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
  410. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
  411. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
  412. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
  413. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
  414. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
  415. package/dist/types/notifications/config.d.ts +0 -132
  416. package/src/harness-control-plane/rpc-adapter.ts +0 -290
  417. package/src/modes/bridge/auth.ts +0 -41
  418. package/src/modes/bridge/bridge-client-bridge.ts +0 -47
  419. package/src/modes/bridge/bridge-mode.ts +0 -675
  420. package/src/modes/bridge/bridge-ui-context.ts +0 -200
  421. package/src/modes/bridge/event-stream.ts +0 -70
  422. package/src/modes/rpc/host-tools.ts +0 -1
  423. package/src/modes/rpc/host-uris.ts +0 -1
  424. package/src/modes/rpc/rpc-client.ts +0 -1166
  425. package/src/modes/rpc/rpc-mode.ts +0 -1029
  426. package/src/modes/rpc/rpc-socket-security.ts +0 -115
  427. package/src/modes/rpc/rpc-types.ts +0 -637
  428. package/src/modes/shared/agent-wire/command-contract.ts +0 -18
  429. package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
  430. package/src/modes/shared/agent-wire/command-validation.ts +0 -181
  431. package/src/modes/shared/agent-wire/handshake.ts +0 -157
  432. package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
  433. package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
  434. package/src/modes/shared/agent-wire/protocol.ts +0 -46
  435. package/src/modes/shared/agent-wire/responses.ts +0 -17
  436. package/src/modes/shared/agent-wire/scopes.ts +0 -94
  437. package/src/modes/shared/agent-wire/session-registry.ts +0 -109
  438. package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
  439. package/src/modes/shared/agent-wire/ui-result.ts +0 -48
  440. package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
  441. package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
  442. package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
  443. package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
  444. package/src/notifications/config.ts +0 -219
  445. package/src/notifications/index.ts +0 -1835
  446. package/src/notifications/telegram-daemon-cli.ts +0 -243
  447. package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
  448. /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
  449. /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
  450. /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
  451. /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
  452. /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
  453. /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
  454. /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
  455. /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
  456. /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
  457. /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
  458. /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
  459. /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
  460. /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
  461. /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
  462. /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
  463. /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
  464. /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
  465. /package/src/{notifications → sdk/bus}/engine.ts +0 -0
  466. /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
  467. /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
  468. /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
  469. /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
  470. /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
  471. /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
  472. /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
  473. /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
  474. /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
@@ -6,8 +6,18 @@
6
6
  import { createInterface } from "node:readline/promises";
7
7
  import { APP_NAME } from "@gajae-code/utils/dirs";
8
8
  import chalk from "chalk";
9
- import type { Settings } from "../config/settings";
10
- import { maskToken } from "../notifications/config";
9
+ import { Settings, type SettingsAtomicPatch } from "../config/settings";
10
+ import { type EnsureChatDaemonResult, ensureDiscordDaemon, ensureSlackDaemon } from "../sdk/bus/chat-daemon-control";
11
+ import { getNotificationConfig, maskToken, tokenFingerprint } from "../sdk/bus/config";
12
+ import {
13
+ clearTelegramActivationMarker,
14
+ createTelegramActivationMarker,
15
+ observedTelegramActivationMarker,
16
+ type ProposedTelegramIdentity,
17
+ persistTelegramActivationMarker,
18
+ proposedTelegramIdentity,
19
+ reconcileCommittedTelegramConfiguration,
20
+ } from "../sdk/bus/notification-orchestration";
11
21
  import {
12
22
  buildNotificationStatusReport,
13
23
  checkNotificationHealth,
@@ -16,17 +26,36 @@ import {
16
26
  formatNotificationStatusReport,
17
27
  formatNotificationTestResult,
18
28
  recoverNotifications,
29
+ sanitizeDiagnostic,
19
30
  sendNotificationTest,
20
- } from "../notifications/notification-service";
31
+ } from "../sdk/bus/notification-service";
32
+ import { ensureTelegramDaemonRunningDetailed, readDaemonState } from "../sdk/bus/telegram-daemon";
33
+ import { runDaemonInternal } from "../sdk/bus/telegram-daemon-cli";
34
+ import {
35
+ runTelegramSetup as runTelegramPairingSetup,
36
+ type TelegramSetupPreflight,
37
+ type TelegramSetupTimers,
38
+ } from "../sdk/bus/telegram-setup";
21
39
 
22
40
  export type NotifyAction = "setup" | "status" | "health" | "test" | "recovery" | "daemon-internal";
41
+ export type NotifySetupProvider = "telegram" | "discord" | "slack";
23
42
 
24
43
  export interface NotifyCommandArgs {
25
44
  action: NotifyAction;
26
45
  smoke?: boolean;
27
46
  rawArgs: string[];
47
+ provider?: NotifySetupProvider;
28
48
  token?: string;
29
49
  chatId?: string;
50
+ discordBotToken?: string;
51
+ discordApplicationId?: string;
52
+ discordGuildId?: string;
53
+ discordParentChannelId?: string;
54
+ slackBotToken?: string;
55
+ slackAppToken?: string;
56
+ slackWorkspaceId?: string;
57
+ slackChannelId?: string;
58
+ slackAuthorizedUserId?: string;
30
59
  redact?: boolean;
31
60
  probe?: boolean;
32
61
  message?: string;
@@ -46,45 +75,18 @@ export interface NotifyCommandDeps {
46
75
  tokenPrompt?: () => Promise<string>;
47
76
  setExitCode?: (code: number) => void;
48
77
  exitProcess?: (code: number) => void;
78
+ /** Optional daemon ownership facts collected by an embedding host. */
79
+ setupPreflight?: TelegramSetupPreflight;
80
+ /** Injectable timers and cancellation for setup pairing. */
81
+ setupTimers?: TelegramSetupTimers;
82
+ setupAbortSignal?: AbortSignal;
83
+ setupPidAlive?: (pid: number) => boolean;
84
+ ensureProviderDaemon?: (
85
+ provider: "discord" | "slack",
86
+ settings: Settings,
87
+ ) => Promise<EnsureChatDaemonResult | "failed">;
49
88
  }
50
89
 
51
- interface TelegramApiResponse<T> {
52
- ok: boolean;
53
- result?: T;
54
- description?: string;
55
- }
56
-
57
- interface TelegramUpdate {
58
- update_id: number;
59
- message?: {
60
- chat?: {
61
- id?: number | string;
62
- type?: string;
63
- };
64
- };
65
- }
66
-
67
- interface TelegramUser {
68
- id: number;
69
- is_bot?: boolean;
70
- first_name?: string;
71
- username?: string;
72
- has_topics_enabled?: boolean;
73
- allows_users_to_create_topics?: boolean;
74
- }
75
-
76
- interface TelegramChat {
77
- id?: number | string;
78
- type?: string;
79
- }
80
-
81
- type ThreadedModeState = "enabled" | "disabled" | "unknown";
82
- type ThreadedModeFinalLabel = "verified" | "unverified" | "unknown";
83
-
84
- const DEFAULT_API_BASE = "https://api.telegram.org";
85
- const DEFAULT_POLL_TIMEOUT_MS = 60_000;
86
- const DEFAULT_POLL_INTERVAL_MS = 1_000;
87
-
88
90
  export function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined {
89
91
  if (args.length === 0 || args[0] !== "notify") {
90
92
  return undefined;
@@ -97,11 +99,27 @@ export function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined {
97
99
  const i = rest.indexOf(name);
98
100
  return i >= 0 ? rest[i + 1] : undefined;
99
101
  };
102
+ const provider = rest[0]?.startsWith("--") ? undefined : rest[0];
103
+ if (provider !== undefined && provider !== "telegram" && provider !== "discord" && provider !== "slack") {
104
+ return undefined;
105
+ }
100
106
  return {
101
107
  action,
102
108
  rawArgs: rest,
109
+ ...(provider ? { provider } : {}),
103
110
  token: flag("--token"),
104
111
  chatId: flag("--chat-id"),
112
+ ...(flag("--discord-bot-token") ? { discordBotToken: flag("--discord-bot-token") } : {}),
113
+ ...(flag("--discord-application-id") ? { discordApplicationId: flag("--discord-application-id") } : {}),
114
+ ...(flag("--discord-guild-id") ? { discordGuildId: flag("--discord-guild-id") } : {}),
115
+ ...(flag("--discord-parent-channel-id")
116
+ ? { discordParentChannelId: flag("--discord-parent-channel-id") }
117
+ : {}),
118
+ ...(flag("--slack-bot-token") ? { slackBotToken: flag("--slack-bot-token") } : {}),
119
+ ...(flag("--slack-app-token") ? { slackAppToken: flag("--slack-app-token") } : {}),
120
+ ...(flag("--slack-workspace-id") ? { slackWorkspaceId: flag("--slack-workspace-id") } : {}),
121
+ ...(flag("--slack-channel-id") ? { slackChannelId: flag("--slack-channel-id") } : {}),
122
+ ...(flag("--slack-authorized-user-id") ? { slackAuthorizedUserId: flag("--slack-authorized-user-id") } : {}),
105
123
  redact: rest.includes("--redact"),
106
124
  };
107
125
  }
@@ -132,7 +150,7 @@ export function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined {
132
150
  export async function runNotifyCommand(cmd: NotifyCommandArgs, deps: NotifyCommandDeps = {}): Promise<void> {
133
151
  switch (cmd.action) {
134
152
  case "setup":
135
- await runSetup({
153
+ await runSetup(cmd, {
136
154
  ...deps,
137
155
  setupToken: deps.setupToken ?? cmd.token,
138
156
  setupChatId: deps.setupChatId ?? cmd.chatId,
@@ -151,15 +169,13 @@ export async function runNotifyCommand(cmd: NotifyCommandArgs, deps: NotifyComma
151
169
  case "recovery":
152
170
  await runRecovery(deps);
153
171
  return;
154
- case "daemon-internal": {
155
- const m = await import("../notifications/telegram-daemon-cli");
172
+ case "daemon-internal":
156
173
  if (cmd.smoke) {
157
- await m.runDaemonSmoke();
174
+ await runDaemonInternal(["--smoke"]);
158
175
  } else {
159
- await m.runDaemonInternal(cmd.rawArgs);
176
+ await runDaemonInternal(cmd.rawArgs);
160
177
  }
161
178
  return;
162
- }
163
179
  }
164
180
  }
165
181
 
@@ -171,8 +187,9 @@ export async function runNotifyCliCommand(cmd: NotifyCommandArgs, deps: NotifyCo
171
187
  throw error;
172
188
  }
173
189
 
174
- const cancelled = error.message === "Telegram bot token prompt cancelled.";
175
- process.stderr.write(cancelled ? "Telegram notify setup cancelled.\n" : `Error: ${error.message}\n`);
190
+ const cancelled =
191
+ error.message === "Telegram bot token prompt cancelled." || error.message === "Telegram setup cancelled.";
192
+ process.stderr.write(cancelled ? "Notify setup cancelled.\n" : `Error: ${error.message}\n`);
176
193
  const code = cancelled ? 130 : 1;
177
194
  if (deps.setExitCode) {
178
195
  deps.setExitCode(code);
@@ -186,52 +203,230 @@ export async function runNotifyCliCommand(cmd: NotifyCommandArgs, deps: NotifyCo
186
203
 
187
204
  async function getSettings(deps: NotifyCommandDeps): Promise<Settings> {
188
205
  if (deps.settings) return deps.settings;
189
- const { Settings } = await import("../config/settings");
190
206
  return await Settings.init();
191
207
  }
192
208
 
193
- async function runSetup(deps: NotifyCommandDeps): Promise<void> {
209
+ async function runSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promise<void> {
210
+ const provider = cmd.provider ?? "telegram";
211
+ if (provider === "discord") {
212
+ await runDiscordSetup(cmd, deps);
213
+ return;
214
+ }
215
+ if (provider === "slack") {
216
+ await runSlackSetup(cmd, deps);
217
+ return;
218
+ }
219
+ await runTelegramSetup(cmd, deps);
220
+ }
221
+
222
+ function requiredSetupValue(value: string | undefined, flag: string): string {
223
+ if (!value?.trim()) throw new Error(`${flag} is required for non-interactive setup.`);
224
+ return value.trim();
225
+ }
226
+
227
+ async function runDiscordSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promise<void> {
228
+ const botToken = requiredSetupValue(cmd.discordBotToken, "--discord-bot-token");
229
+ const applicationId = requiredSetupValue(cmd.discordApplicationId, "--discord-application-id");
230
+ const guildId = requiredSetupValue(cmd.discordGuildId, "--discord-guild-id");
231
+ const parentChannelId = requiredSetupValue(cmd.discordParentChannelId, "--discord-parent-channel-id");
232
+ const settings = await getSettings(deps);
233
+ settings.set("notifications.discord.botToken", botToken);
234
+ settings.set("notifications.discord.applicationId", applicationId);
235
+ settings.set("notifications.discord.guildId", guildId);
236
+ settings.set("notifications.discord.parentChannelId", parentChannelId);
237
+ settings.set("notifications.enabled", true);
238
+ if (cmd.redact) settings.set("notifications.redact", true);
239
+ await settings.flushOrThrow();
240
+ const daemon = await ensureConfiguredProviderDaemon("discord", settings, deps);
241
+ process.stdout.write(
242
+ `Discord notifications enabled. botToken=${maskToken(botToken)} applicationId=${applicationId} guildId=${guildId} parentChannelId=${parentChannelId} daemon=${daemon}\n`,
243
+ );
244
+ }
245
+
246
+ async function runSlackSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promise<void> {
247
+ const botToken = requiredSetupValue(cmd.slackBotToken, "--slack-bot-token");
248
+ const appToken = requiredSetupValue(cmd.slackAppToken, "--slack-app-token");
249
+ const workspaceId = requiredSetupValue(cmd.slackWorkspaceId, "--slack-workspace-id");
250
+ const channelId = requiredSetupValue(cmd.slackChannelId, "--slack-channel-id");
251
+ const authorizedUserId = cmd.slackAuthorizedUserId?.trim() || undefined;
194
252
  const settings = await getSettings(deps);
195
- const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
196
- const apiBase = deps.apiBase ?? DEFAULT_API_BASE;
197
- const token = deps.setupToken ?? (await (deps.tokenPrompt ?? promptForToken)());
198
- if (!token.trim()) {
199
- throw new Error("Telegram bot token is required.");
253
+ settings.set("notifications.slack.botToken", botToken);
254
+ settings.set("notifications.slack.appToken", appToken);
255
+ settings.set("notifications.slack.workspaceId", workspaceId);
256
+ settings.set("notifications.slack.channelId", channelId);
257
+ settings.set("notifications.slack.authorizedUserId", authorizedUserId);
258
+ settings.set("notifications.enabled", true);
259
+ if (cmd.redact) settings.set("notifications.redact", true);
260
+ await settings.flushOrThrow();
261
+ const daemon = await ensureConfiguredProviderDaemon("slack", settings, deps);
262
+ process.stdout.write(
263
+ `Slack notifications enabled. botToken=${maskToken(botToken)} appToken=${maskToken(appToken)} workspaceId=${workspaceId} channelId=${channelId} authorizedUserId=${authorizedUserId ?? "(unset; inbound denied)"} daemon=${daemon}\n`,
264
+ );
265
+ }
266
+
267
+ async function ensureConfiguredProviderDaemon(
268
+ provider: "discord" | "slack",
269
+ settings: Settings,
270
+ deps: NotifyCommandDeps,
271
+ ): Promise<EnsureChatDaemonResult | "failed"> {
272
+ try {
273
+ if (deps.ensureProviderDaemon) return await deps.ensureProviderDaemon(provider, settings);
274
+ return provider === "discord" ? await ensureDiscordDaemon(settings) : await ensureSlackDaemon(settings);
275
+ } catch {
276
+ return "failed";
200
277
  }
278
+ }
201
279
 
202
- const user = await getMe(fetchImpl, apiBase, token);
203
- const threadedState = await verifyThreadedMode(fetchImpl, apiBase, token, user, {
280
+ async function runTelegramSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promise<void> {
281
+ const settings = await getSettings(deps);
282
+ const token = deps.setupToken ?? cmd.token ?? (await (deps.tokenPrompt ?? promptForToken)());
283
+ if (!token.trim()) throw new Error("Telegram bot token is required.");
284
+
285
+ const result = await runTelegramPairingSetup({
286
+ token,
287
+ preflight: deps.setupPreflight ?? (await resolveSetupPreflight(settings, deps)),
288
+ revalidatePreflight: async () => deps.setupPreflight ?? (await resolveSetupPreflight(settings, deps)),
289
+ chatId: deps.setupChatId,
204
290
  interactive: resolveSetupInteractive(deps),
205
- prompt: deps.threadedModePrompt ?? promptForThreadedMode,
291
+ threadedModePrompt: deps.threadedModePrompt ?? promptForThreadedMode,
292
+ pollTimeoutMs: deps.pollTimeoutMs,
293
+ pollIntervalMs: deps.pollIntervalMs,
294
+ signal: deps.setupAbortSignal,
295
+ deps: {
296
+ fetchImpl: deps.fetchImpl ?? globalThis.fetch,
297
+ apiBase: deps.apiBase,
298
+ timers: deps.setupTimers,
299
+ },
300
+ onEvent: event => {
301
+ const output = event.kind === "rejected_chat" ? process.stderr : process.stdout;
302
+ output.write(event.message);
303
+ },
206
304
  });
305
+ if (!result.ok) throw new Error(result.detail);
306
+ if (result.pairingSource === "provided") {
307
+ process.stdout.write(`Using provided chat id ${result.chatId} (non-interactive).\n`);
308
+ }
309
+ try {
310
+ const proposedIdentity = deps.setupPreflight
311
+ ? proposedIdentityFromSetupPreflight(deps.setupPreflight, token.trim(), result.chatId)
312
+ : await proposedTelegramIdentity({
313
+ settings,
314
+ botToken: token.trim(),
315
+ chatId: result.chatId,
316
+ chatDisplay: result.chatId,
317
+ });
318
+ if (proposedIdentity.status === "foreign" || proposedIdentity.status === "unknown") {
319
+ throw new Error(
320
+ "Telegram activation was not saved because the current daemon owner has an untrusted identity.",
321
+ );
322
+ }
323
+
324
+ const inactiveMarkerToClear = observedTelegramActivationMarker(settings, token.trim(), result.chatId);
325
+ const patches: SettingsAtomicPatch[] = [
326
+ { path: "notifications.telegram.botToken", op: "set", value: token.trim() },
327
+ { path: "notifications.telegram.chatId", op: "set", value: result.chatId },
328
+ { path: "notifications.enabled", op: "set", value: true },
329
+ ];
330
+ if (deps.setupRedact ?? cmd.redact) patches.push({ path: "notifications.redact", op: "set", value: true });
331
+ const receipt = await settings.commitAtomicBatch(patches);
332
+ const activationMarker = createTelegramActivationMarker({
333
+ botToken: token.trim(),
334
+ chatId: result.chatId,
335
+ state: "blocked",
336
+ reason: "identity_mismatch",
337
+ });
338
+ const activation = await reconcileCommittedTelegramConfiguration({
339
+ receipt,
340
+ inactiveMarkerToClear,
341
+ activation: {
342
+ // The CLI does not host a session endpoint. The settings editor supplies
343
+ // its live controller here; a CLI identity block therefore has no local
344
+ // endpoint to stop before the durable rollback below.
345
+ controller: {
346
+ enterBlockedRuntime: async () => undefined,
347
+ clearBlockedRuntime: async () => undefined,
348
+ reconcileCurrentSession: async () => undefined,
349
+ },
350
+ reconnect: async () =>
351
+ await ensureTelegramDaemonRunningDetailed({
352
+ settings,
353
+ cwd: process.cwd(),
354
+ sessionId: `notify-cli-${process.pid}`,
355
+ }),
356
+ persistInactive: async marker => await persistTelegramActivationMarker(settings, marker),
357
+ clearInactive: async marker => await clearTelegramActivationMarker(settings, marker),
358
+ marker: activationMarker,
359
+ },
360
+ });
361
+ if (activation.status === "blocked_identity") {
362
+ const restored = await activation.restore();
363
+ const detail =
364
+ restored.status === "restored"
365
+ ? "Telegram activation was blocked by a foreign daemon; previous settings were restored."
366
+ : restored.status === "still_blocked"
367
+ ? "Telegram activation remains blocked by a foreign daemon; previous settings were restored."
368
+ : restored.status === "conflict"
369
+ ? "Telegram activation was blocked and settings changed concurrently; refusing to report setup success."
370
+ : "Telegram activation was blocked; refusing to report setup success.";
371
+ throw new Error(detail);
372
+ }
373
+ } catch (error) {
374
+ const detail = sanitizeDiagnostic(error instanceof Error ? error.message : "unknown persistence failure", token);
375
+ throw new Error(`Unable to persist and activate Telegram notification settings: ${detail}`);
376
+ }
207
377
  process.stdout.write(
208
- "Token validated. Message your bot now from the private Telegram chat to pair notifications.\n",
378
+ `Notifications enabled. botToken=${maskToken(token)} chatId=${result.chatId} threaded=${result.threadedLabel}\n`,
209
379
  );
380
+ }
210
381
 
211
- let chatId: string;
212
- if (deps.setupChatId?.trim()) {
213
- chatId = deps.setupChatId.trim();
214
- await verifyPrivateChatId(fetchImpl, apiBase, token, chatId);
215
- process.stdout.write(`Using provided chat id ${chatId} (non-interactive).\n`);
216
- } else {
217
- const stale = await getUpdates(fetchImpl, apiBase, token, { timeout: 0, allowed_updates: ["message"] });
218
- const offset = nextOffset(stale);
219
- chatId = await waitForPrivateChat(fetchImpl, apiBase, token, {
220
- offset,
221
- pollTimeoutMs: deps.pollTimeoutMs ?? DEFAULT_POLL_TIMEOUT_MS,
222
- pollIntervalMs: deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,
223
- });
382
+ function proposedIdentityFromSetupPreflight(
383
+ preflight: TelegramSetupPreflight,
384
+ botToken: string,
385
+ chatId: string,
386
+ ): ProposedTelegramIdentity {
387
+ const daemon = preflight.daemon;
388
+ if (!daemon?.live) return { status: "absent" };
389
+ if (typeof daemon.tokenFingerprint !== "string" || typeof daemon.chatId !== "string") {
390
+ return { status: "unknown" };
224
391
  }
392
+ return daemon.tokenFingerprint === tokenFingerprint(botToken) && daemon.chatId === chatId
393
+ ? { status: "same" }
394
+ : { status: "foreign" };
395
+ }
225
396
 
226
- settings.set("notifications.telegram.botToken", token);
227
- settings.set("notifications.telegram.chatId", chatId);
228
- settings.set("notifications.enabled", true);
229
- if (deps.setupRedact) settings.set("notifications.redact", true);
230
- await settings.flush();
397
+ async function resolveSetupPreflight(settings: Settings, deps: NotifyCommandDeps): Promise<TelegramSetupPreflight> {
398
+ if (deps.setupPreflight) return deps.setupPreflight;
399
+ const cfg = getNotificationConfig(settings);
400
+ try {
401
+ const state = await readDaemonState(settings);
402
+ if (!state) return { storedChatId: cfg.chatId };
403
+ const validPid = Number.isSafeInteger(state.pid) && state.pid > 0;
404
+ // Owner-proof: only block discovery for a daemon we can positively prove is
405
+ // live (present state with a valid, alive pid). A malformed/no-pid record is
406
+ // not evidence of a live poller, mirroring recoverNotifications' semantics.
407
+ if (!validPid) return { storedChatId: cfg.chatId };
408
+ return {
409
+ storedChatId: cfg.chatId,
410
+ daemon: {
411
+ live: (deps.setupPidAlive ?? daemonPidAlive)(state.pid),
412
+ tokenFingerprint: typeof state.tokenFingerprint === "string" ? state.tokenFingerprint : undefined,
413
+ chatId: typeof state.chatId === "string" ? state.chatId : undefined,
414
+ },
415
+ };
416
+ } catch {
417
+ // A state read failure is not proof of a live daemon; proceed normally. The
418
+ // daemon's own 409 handling remains the backstop against poller contention.
419
+ return { storedChatId: cfg.chatId };
420
+ }
421
+ }
231
422
 
232
- process.stdout.write(
233
- `Notifications enabled. botToken=${maskToken(token)} chatId=${chatId} threaded=${threadedLabel(threadedState)}\n`,
234
- );
423
+ function daemonPidAlive(pid: number): boolean {
424
+ try {
425
+ process.kill(pid, 0);
426
+ return true;
427
+ } catch (error) {
428
+ return (error as NodeJS.ErrnoException).code === "EPERM";
429
+ }
235
430
  }
236
431
 
237
432
  type TokenPromptInput = NodeJS.ReadStream & {
@@ -308,77 +503,6 @@ export async function promptForToken(
308
503
  });
309
504
  }
310
505
 
311
- const THREADED_ENABLED_SUCCESS =
312
- "Telegram Threaded Mode capability verified for this bot. GJC will request a private-chat topic per session; if Telegram ever refuses topic creation, notifications fall back to this flat chat with inline ask buttons only and a one-time Threaded Mode nudge.\n";
313
-
314
- const THREADED_MISSING_WARNING =
315
- "Warning: Telegram getMe did not include has_topics_enabled, so GJC cannot verify private-chat Threaded Mode capability for this bot. Setup will continue; flat private-chat fallback supports outbound notifications and inline ask buttons only. Free-text replies and session commands require Threaded Mode/topic routing.\n";
316
-
317
- const THREADED_NONINTERACTIVE_WARNING =
318
- "Warning: Telegram Threaded Mode capability is OFF for this bot. Setup will be saved because this run is non-interactive. Flat private-chat fallback supports outbound notifications and inline ask buttons only; free-text replies and session commands require enabling Threaded Mode in @BotFather > Bot Settings > Threads Settings.\n";
319
-
320
- const THREADED_DISABLED_GUIDANCE =
321
- "Telegram Threaded Mode is OFF for this bot. GJC needs Telegram private-chat topics so each session can use its own thread.\n" +
322
- "GJC cannot enable this through the Bot API. Open @BotFather > Bot Settings > Threads Settings for this bot, enable Threaded Mode / forum topics for private chats, then return here.\n" +
323
- "Without Threaded Mode, flat private-chat fallback supports outbound notifications and inline ask buttons only; free-text replies and session commands require topic routing.\n";
324
-
325
- const THREADED_DISABLED_PROMPT =
326
- "Press Enter after enabling Threaded Mode, or type skip to finish setup with a warning: ";
327
-
328
- const THREADED_STILL_OFF = "Telegram still reports Threaded Mode OFF for this bot.\n";
329
-
330
- const THREADED_RETRY_PROMPT = "Press Enter to check again, or type skip to finish setup with a warning: ";
331
-
332
- const THREADED_SKIP_WARNING =
333
- "Warning: continuing without verified Telegram Threaded Mode capability. Setup will be saved. Flat private-chat fallback supports outbound notifications and inline ask buttons only; free-text replies and session commands require enabling Threaded Mode in BotFather.\n";
334
-
335
- const THREADED_INVALID_INPUT = "Type Enter to retry or skip to continue with a warning.\n";
336
-
337
- const THREADED_RETRY_INPUTS = new Set(["", "y", "yes", "r", "retry"]);
338
- const THREADED_SKIP_INPUTS = new Set(["s", "skip", "n", "no"]);
339
-
340
- function isTelegramUser(value: unknown): value is TelegramUser {
341
- return Boolean(value) && typeof value === "object" && typeof (value as { id?: unknown }).id === "number";
342
- }
343
-
344
- async function getMe(fetchImpl: typeof fetch, apiBase: string, token: string): Promise<TelegramUser> {
345
- const user = await callTelegram<unknown>(fetchImpl, apiBase, token, "getMe", {});
346
- if (!isTelegramUser(user)) {
347
- throw new Error("Telegram getMe returned invalid Telegram response: missing valid User result.");
348
- }
349
- return user;
350
- }
351
-
352
- async function verifyPrivateChatId(
353
- fetchImpl: typeof fetch,
354
- apiBase: string,
355
- token: string,
356
- chatId: string,
357
- ): Promise<void> {
358
- const chat = (await callTelegram<unknown>(fetchImpl, apiBase, token, "getChat", { chat_id: chatId })) as
359
- | TelegramChat
360
- | undefined;
361
- if (!chat || typeof chat !== "object") {
362
- throw new Error("Telegram getChat returned invalid Telegram response: missing valid Chat result.");
363
- }
364
- if (chat.type !== "private") {
365
- const type = typeof chat.type === "string" && chat.type ? chat.type : "unknown";
366
- throw new Error(`Provided chat id ${chatId} is a ${type} chat; pairing requires a private Telegram chat.`);
367
- }
368
- }
369
-
370
- function threadedModeState(user: TelegramUser): ThreadedModeState {
371
- if (user.has_topics_enabled === true) return "enabled";
372
- if (user.has_topics_enabled === false) return "disabled";
373
- return "unknown";
374
- }
375
-
376
- function threadedLabel(state: ThreadedModeState): ThreadedModeFinalLabel {
377
- if (state === "enabled") return "verified";
378
- if (state === "disabled") return "unverified";
379
- return "unknown";
380
- }
381
-
382
506
  function resolveSetupInteractive(deps: NotifyCommandDeps): boolean {
383
507
  if (deps.setupInteractive !== undefined) return deps.setupInteractive;
384
508
  return Boolean(process.stdin.isTTY) && !deps.setupChatId?.trim();
@@ -394,55 +518,6 @@ async function promptForThreadedMode(message: string): Promise<string> {
394
518
  }
395
519
  }
396
520
 
397
- async function verifyThreadedMode(
398
- fetchImpl: typeof fetch,
399
- apiBase: string,
400
- token: string,
401
- initialUser: TelegramUser,
402
- opts: { interactive: boolean; prompt: (message: string) => Promise<string> },
403
- ): Promise<ThreadedModeState> {
404
- const classify = (user: TelegramUser): ThreadedModeState | undefined => {
405
- const state = threadedModeState(user);
406
- if (state === "enabled") {
407
- process.stdout.write(THREADED_ENABLED_SUCCESS);
408
- return "enabled";
409
- }
410
- if (state === "unknown") {
411
- process.stdout.write(THREADED_MISSING_WARNING);
412
- return "unknown";
413
- }
414
- return undefined;
415
- };
416
-
417
- const initial = classify(initialUser);
418
- if (initial) return initial;
419
-
420
- if (!opts.interactive) {
421
- process.stdout.write(THREADED_NONINTERACTIVE_WARNING);
422
- return "disabled";
423
- }
424
-
425
- process.stdout.write(THREADED_DISABLED_GUIDANCE);
426
- let firstPrompt = true;
427
- for (;;) {
428
- const answer = (await opts.prompt(firstPrompt ? THREADED_DISABLED_PROMPT : THREADED_RETRY_PROMPT))
429
- .trim()
430
- .toLowerCase();
431
- firstPrompt = false;
432
- if (THREADED_SKIP_INPUTS.has(answer)) {
433
- process.stdout.write(THREADED_SKIP_WARNING);
434
- return "disabled";
435
- }
436
- if (!THREADED_RETRY_INPUTS.has(answer)) {
437
- process.stdout.write(THREADED_INVALID_INPUT);
438
- continue;
439
- }
440
- const resolved = classify(await getMe(fetchImpl, apiBase, token));
441
- if (resolved) return resolved;
442
- process.stdout.write(THREADED_STILL_OFF);
443
- }
444
- }
445
-
446
521
  async function runStatus(deps: NotifyCommandDeps): Promise<void> {
447
522
  const settings = await getSettings(deps);
448
523
  const report = buildNotificationStatusReport(settings);
@@ -481,101 +556,25 @@ async function runRecovery(deps: NotifyCommandDeps): Promise<void> {
481
556
  process.stdout.write(`${formatNotificationRecoveryReport(report)}\n`);
482
557
  }
483
558
 
484
- async function waitForPrivateChat(
485
- fetchImpl: typeof fetch,
486
- apiBase: string,
487
- token: string,
488
- opts: { offset: number | undefined; pollTimeoutMs: number; pollIntervalMs: number },
489
- ): Promise<string> {
490
- const deadline = Date.now() + opts.pollTimeoutMs;
491
- let offset = opts.offset;
492
- let sawRejectedChatType: string | undefined;
493
-
494
- while (Date.now() <= deadline) {
495
- const updates = await getUpdates(fetchImpl, apiBase, token, { offset, timeout: 0, allowed_updates: ["message"] });
496
- offset = nextOffset(updates, offset);
497
- for (const update of updates) {
498
- const chat = update.message?.chat;
499
- if (!chat) continue;
500
- if (chat.type === "private" && chat.id !== undefined) {
501
- return String(chat.id);
502
- }
503
- if (chat.type === "group" || chat.type === "supergroup" || chat.type === "channel") {
504
- sawRejectedChatType = chat.type;
505
- process.stderr.write(
506
- `Rejected ${chat.type} chat. Pairing requires a private Telegram chat with the bot.\n`,
507
- );
508
- }
509
- }
510
- if (opts.pollIntervalMs > 0) {
511
- await new Promise(resolve =>
512
- setTimeout(resolve, Math.min(opts.pollIntervalMs, Math.max(0, deadline - Date.now()))),
513
- );
514
- }
515
- }
516
-
517
- if (sawRejectedChatType) {
518
- throw new Error(`Pairing rejected ${sawRejectedChatType} chat; message the bot from a private chat.`);
519
- }
520
- throw new Error("Timed out waiting for a private Telegram message to pair notifications.");
521
- }
522
-
523
- function nextOffset(updates: TelegramUpdate[], fallback?: number): number | undefined {
524
- let max = fallback === undefined ? undefined : fallback - 1;
525
- for (const update of updates) {
526
- if (typeof update.update_id === "number" && (max === undefined || update.update_id > max)) {
527
- max = update.update_id;
528
- }
529
- }
530
- return max === undefined ? fallback : max + 1;
531
- }
532
-
533
- async function getUpdates(
534
- fetchImpl: typeof fetch,
535
- apiBase: string,
536
- token: string,
537
- params: Record<string, unknown>,
538
- ): Promise<TelegramUpdate[]> {
539
- return await callTelegram<TelegramUpdate[]>(fetchImpl, apiBase, token, "getUpdates", params);
540
- }
541
-
542
- async function callTelegram<T>(
543
- fetchImpl: typeof fetch,
544
- apiBase: string,
545
- token: string,
546
- method: string,
547
- body: Record<string, unknown>,
548
- ): Promise<T> {
549
- const response = await fetchImpl(`${apiBase.replace(/\/$/, "")}/bot${token}/${method}`, {
550
- method: "POST",
551
- headers: { "content-type": "application/json" },
552
- body: JSON.stringify(body),
553
- });
554
- let payload: TelegramApiResponse<T>;
555
- try {
556
- payload = (await response.json()) as TelegramApiResponse<T>;
557
- } catch {
558
- throw new Error(`Telegram ${method} returned invalid JSON.`);
559
- }
560
- if (!response.ok || !payload.ok) {
561
- throw new Error(`Telegram ${method} failed: ${payload.description ?? response.statusText}`);
562
- }
563
- return payload.result as T;
564
- }
565
-
566
559
  export function printNotifyHelp(): void {
567
- process.stdout.write(`${chalk.bold(`${APP_NAME} notify`)} - Configure Telegram notifications
560
+ process.stdout.write(`${chalk.bold(`${APP_NAME} notify`)} - Configure Telegram, Discord, or Slack notifications
561
+
562
+ ${chalk.bold("Interactive path:")}
563
+ In a running GJC session, use /settings → Notifications for setup, health, test, recovery,
564
+ reconnect, global enable/disable, adapter-local Telegram removal, and session on/off.
565
+ The CLI subcommands below remain the authoritative headless and automation fallback.
568
566
 
569
567
  ${chalk.bold("Usage:")}
570
- ${APP_NAME} notify setup
571
- ${APP_NAME} notify setup --token <botToken> --chat-id <chatId> [--redact]
568
+ ${APP_NAME} notify setup [telegram]
569
+ ${APP_NAME} notify setup discord --discord-bot-token <token> --discord-application-id <id> --discord-guild-id <id> --discord-parent-channel-id <id>
570
+ ${APP_NAME} notify setup slack --slack-bot-token <token> --slack-app-token <token> --slack-workspace-id <id> --slack-channel-id <id> [--slack-authorized-user-id <id>]
572
571
  ${APP_NAME} notify status
573
572
  ${APP_NAME} notify health [--probe]
574
573
  ${APP_NAME} notify test [--message <text>]
575
574
  ${APP_NAME} notify recovery
576
575
 
577
576
  ${chalk.bold("Subcommands:")}
578
- setup Pair a Telegram bot token with a private chat and verify Threaded Mode capability
577
+ setup Pair Telegram or save complete non-interactive Discord/Slack notification settings
579
578
  status Show notification configuration without secrets
580
579
  health Report config, daemon-ownership and endpoint health (--probe adds a Telegram reachability check)
581
580
  test Send a one-off test notification through the configured Telegram adapter
@@ -583,6 +582,9 @@ ${chalk.bold("Subcommands:")}
583
582
 
584
583
  ${chalk.bold("Examples:")}
585
584
  ${APP_NAME} notify setup
585
+ ${APP_NAME} notify setup --token <botToken> --chat-id <chatId> [--redact]
586
+ ${APP_NAME} notify setup discord --discord-bot-token <token> --discord-application-id <id> --discord-guild-id <id> --discord-parent-channel-id <id>
587
+ ${APP_NAME} notify setup slack --slack-bot-token <token> --slack-app-token <token> --slack-workspace-id <id> --slack-channel-id <id> [--slack-authorized-user-id <id>]
586
588
  ${APP_NAME} notify status
587
589
  ${APP_NAME} notify health --probe
588
590
  ${APP_NAME} notify test --message "hello from gjc"