@selesai/code 0.5.27 → 0.5.29

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 (310) hide show
  1. package/dist/cli/args.d.ts.map +1 -1
  2. package/dist/cli/args.js +9 -1
  3. package/dist/cli/args.js.map +1 -1
  4. package/dist/cli/config-selector.d.ts.map +1 -1
  5. package/dist/cli/config-selector.js +1 -1
  6. package/dist/cli/config-selector.js.map +1 -1
  7. package/dist/cli/credential-print.d.ts +23 -0
  8. package/dist/cli/credential-print.d.ts.map +1 -0
  9. package/dist/cli/credential-print.js +117 -0
  10. package/dist/cli/credential-print.js.map +1 -0
  11. package/dist/cli/startup-ui.d.ts.map +1 -1
  12. package/dist/cli/startup-ui.js +1 -1
  13. package/dist/cli/startup-ui.js.map +1 -1
  14. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  15. package/dist/core/agent-session-runtime.js +3 -0
  16. package/dist/core/agent-session-runtime.js.map +1 -1
  17. package/dist/core/agent-session.d.ts +12 -1
  18. package/dist/core/agent-session.d.ts.map +1 -1
  19. package/dist/core/agent-session.js +20 -14
  20. package/dist/core/agent-session.js.map +1 -1
  21. package/dist/core/compaction/compaction.d.ts.map +1 -1
  22. package/dist/core/compaction/compaction.js +11 -3
  23. package/dist/core/compaction/compaction.js.map +1 -1
  24. package/dist/core/extensions/runner.d.ts +1 -0
  25. package/dist/core/extensions/runner.d.ts.map +1 -1
  26. package/dist/core/extensions/runner.js +11 -0
  27. package/dist/core/extensions/runner.js.map +1 -1
  28. package/dist/core/extensions/types.d.ts +14 -1
  29. package/dist/core/extensions/types.d.ts.map +1 -1
  30. package/dist/core/extensions/types.js.map +1 -1
  31. package/dist/core/footer-data-provider.d.ts +10 -0
  32. package/dist/core/footer-data-provider.d.ts.map +1 -1
  33. package/dist/core/footer-data-provider.js +1 -1
  34. package/dist/core/footer-data-provider.js.map +1 -1
  35. package/dist/core/llama/provider.d.ts.map +1 -1
  36. package/dist/core/llama/provider.js +8 -3
  37. package/dist/core/llama/provider.js.map +1 -1
  38. package/dist/core/model-config.d.ts +30 -0
  39. package/dist/core/model-config.d.ts.map +1 -1
  40. package/dist/core/model-config.js +6 -0
  41. package/dist/core/model-config.js.map +1 -1
  42. package/dist/core/model-registry.d.ts.map +1 -1
  43. package/dist/core/model-registry.js +2 -2
  44. package/dist/core/model-registry.js.map +1 -1
  45. package/dist/core/model-resolver.d.ts +1 -0
  46. package/dist/core/model-resolver.d.ts.map +1 -1
  47. package/dist/core/model-resolver.js +20 -3
  48. package/dist/core/model-resolver.js.map +1 -1
  49. package/dist/core/model-runtime.d.ts +2 -0
  50. package/dist/core/model-runtime.d.ts.map +1 -1
  51. package/dist/core/model-runtime.js +5 -4
  52. package/dist/core/model-runtime.js.map +1 -1
  53. package/dist/core/package-manager.d.ts.map +1 -1
  54. package/dist/core/package-manager.js +13 -6
  55. package/dist/core/package-manager.js.map +1 -1
  56. package/dist/core/remote-catalog-provider.d.ts +1 -1
  57. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  58. package/dist/core/remote-catalog-provider.js +24 -11
  59. package/dist/core/remote-catalog-provider.js.map +1 -1
  60. package/dist/core/resource-loader.d.ts +15 -0
  61. package/dist/core/resource-loader.d.ts.map +1 -1
  62. package/dist/core/resource-loader.js +66 -9
  63. package/dist/core/resource-loader.js.map +1 -1
  64. package/dist/core/settings-manager.d.ts +1 -1
  65. package/dist/core/settings-manager.d.ts.map +1 -1
  66. package/dist/core/settings-manager.js.map +1 -1
  67. package/dist/core/system-prompt.d.ts.map +1 -1
  68. package/dist/core/system-prompt.js +1 -1
  69. package/dist/core/system-prompt.js.map +1 -1
  70. package/dist/core/tools/bash.d.ts +2 -0
  71. package/dist/core/tools/bash.d.ts.map +1 -1
  72. package/dist/core/tools/bash.js +34 -5
  73. package/dist/core/tools/bash.js.map +1 -1
  74. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  75. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  76. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  77. package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
  78. package/dist/extensions/pi-intercom/README.md +102 -39
  79. package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
  80. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
  81. package/dist/extensions/pi-intercom/broker/client.ts +315 -12
  82. package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
  83. package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
  84. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
  85. package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
  86. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
  87. package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
  88. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
  89. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
  90. package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
  91. package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
  92. package/dist/extensions/pi-intercom/config.test.ts +93 -0
  93. package/dist/extensions/pi-intercom/config.ts +55 -6
  94. package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
  95. package/dist/extensions/pi-intercom/cwd.ts +31 -0
  96. package/dist/extensions/pi-intercom/extension-api.ts +44 -0
  97. package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
  98. package/dist/extensions/pi-intercom/format-context.ts +32 -0
  99. package/dist/extensions/pi-intercom/index.ts +742 -145
  100. package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
  101. package/dist/extensions/pi-intercom/package.json +15 -5
  102. package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
  103. package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
  104. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
  105. package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
  106. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
  107. package/dist/extensions/pi-intercom/types.ts +94 -4
  108. package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
  109. package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
  110. package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
  111. package/dist/extensions/pi-subagents/CHANGELOG.md +85 -0
  112. package/dist/extensions/pi-subagents/LICENSE +21 -0
  113. package/dist/extensions/pi-subagents/README.md +146 -52
  114. package/dist/extensions/pi-subagents/agents/architect.md +1 -0
  115. package/dist/extensions/pi-subagents/agents/builder.md +1 -0
  116. package/dist/extensions/pi-subagents/package-lock.json +2 -2
  117. package/dist/extensions/pi-subagents/package.json +3 -3
  118. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  119. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +21 -989
  120. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
  121. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +430 -0
  122. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
  123. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +282 -0
  124. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +71 -30
  125. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
  126. package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
  127. package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
  128. package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
  129. package/dist/extensions/pi-subagents/src/api/preflight.ts +16 -12
  130. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
  131. package/dist/extensions/pi-subagents/src/extension/index.ts +17 -7
  132. package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
  133. package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -6
  134. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +8 -7
  135. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
  136. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
  137. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +63 -16
  138. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
  139. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
  140. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
  141. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
  142. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
  143. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +29 -4
  144. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +29 -6
  145. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
  146. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +372 -28
  147. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
  148. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
  149. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +143 -43
  150. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +527 -247
  151. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
  152. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +426 -123
  153. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +15 -7
  154. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
  155. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
  156. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  157. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
  158. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
  159. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
  160. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
  161. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
  162. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
  163. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
  164. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
  165. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
  166. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
  167. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +1 -1
  168. package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
  169. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
  170. package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
  171. package/dist/extensions/pi-subagents/src/shared/types.ts +155 -10
  172. package/dist/extensions/pi-subagents/src/shared/utils.ts +73 -4
  173. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -0
  174. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
  175. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
  176. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
  177. package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
  178. package/dist/extensions/pi-subagents/src/tui/render.ts +27 -28
  179. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
  180. package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
  181. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
  182. package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
  183. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
  184. package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
  185. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  186. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +348 -7
  187. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
  188. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
  189. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
  190. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +26 -1
  191. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
  192. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +3 -3
  193. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +213 -13
  194. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +34 -0
  195. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
  196. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +118 -12
  197. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +850 -7
  198. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
  199. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
  200. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  201. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
  202. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
  203. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +128 -0
  204. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
  205. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
  206. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
  207. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +102 -0
  208. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
  209. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
  210. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
  211. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
  212. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
  213. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
  214. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +4 -2
  215. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
  216. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
  217. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
  218. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
  219. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +11 -11
  220. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
  221. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
  222. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
  223. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +10 -2
  224. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
  225. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
  226. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
  227. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +46 -0
  228. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
  229. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
  230. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
  231. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
  232. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
  233. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +34 -2
  234. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  235. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
  236. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
  237. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
  238. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
  239. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +3 -0
  240. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +1 -1
  241. package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
  245. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
  246. package/dist/extensions/question/index.ts +14 -1
  247. package/dist/extensions/question/tests/wizard.test.ts +11 -8
  248. package/dist/main.d.ts.map +1 -1
  249. package/dist/main.js +43 -0
  250. package/dist/main.js.map +1 -1
  251. package/dist/modes/interactive/components/custom-message.d.ts +3 -1
  252. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  253. package/dist/modes/interactive/components/custom-message.js +10 -2
  254. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  255. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  256. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  257. package/dist/modes/interactive/components/extension-editor.js +16 -46
  258. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  259. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  260. package/dist/modes/interactive/components/model-selector.js +4 -1
  261. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  262. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  263. package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
  264. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  265. package/dist/modes/interactive/external-editor.d.ts +12 -0
  266. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  267. package/dist/modes/interactive/external-editor.js +37 -0
  268. package/dist/modes/interactive/external-editor.js.map +1 -0
  269. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  270. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  271. package/dist/modes/interactive/interactive-mode.js +72 -64
  272. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  273. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  274. package/dist/modes/rpc/rpc-mode.js +14 -0
  275. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  276. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  277. package/dist/utils/clipboard.d.ts.map +1 -1
  278. package/dist/utils/clipboard.js +19 -8
  279. package/dist/utils/clipboard.js.map +1 -1
  280. package/dist/utils/version-check.d.ts.map +1 -1
  281. package/dist/utils/version-check.js +1 -1
  282. package/dist/utils/version-check.js.map +1 -1
  283. package/docs/compaction.md +1 -1
  284. package/docs/custom-provider.md +14 -5
  285. package/docs/environment-variables.md +86 -0
  286. package/docs/extensions.md +15 -5
  287. package/docs/index.md +1 -0
  288. package/docs/models.md +9 -2
  289. package/docs/providers.md +21 -2
  290. package/docs/rpc.md +23 -6
  291. package/docs/session-format.md +2 -0
  292. package/docs/settings.md +1 -1
  293. package/docs/usage.md +0 -13
  294. package/examples/extensions/custom-compaction.ts +5 -2
  295. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  296. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  297. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  298. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  299. package/examples/extensions/gondolin/package-lock.json +2 -2
  300. package/examples/extensions/gondolin/package.json +1 -1
  301. package/examples/extensions/handoff.ts +11 -3
  302. package/examples/extensions/message-renderer.ts +3 -3
  303. package/examples/extensions/sandbox/package-lock.json +2 -2
  304. package/examples/extensions/sandbox/package.json +1 -1
  305. package/examples/extensions/summarize.ts +5 -2
  306. package/examples/extensions/with-deps/package-lock.json +2 -2
  307. package/examples/extensions/with-deps/package.json +1 -1
  308. package/examples/sdk/12-full-control.ts +3 -1
  309. package/package.json +15 -6
  310. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
@@ -0,0 +1,83 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { IntercomClient } from "./client.ts";
4
+
5
+ test("validated session lifecycle messages reach broker-message subscribers", () => {
6
+ const client = new IntercomClient();
7
+ (client as any)._sessionId = "session-1";
8
+ const received: unknown[] = [];
9
+ client.onBrokerMessage((message) => received.push(message));
10
+ const session = {
11
+ id: "session-2",
12
+ cwd: "/test",
13
+ model: "test",
14
+ pid: 2,
15
+ startedAt: 1,
16
+ lastActivity: 1,
17
+ };
18
+
19
+ (client as any).handleBrokerMessage({ type: "session_joined", session });
20
+ (client as any).handleBrokerMessage({ type: "presence_update", session });
21
+ (client as any).handleBrokerMessage({ type: "session_left", sessionId: "session-2" });
22
+
23
+ assert.deepEqual(received, [
24
+ { type: "session_joined", session },
25
+ { type: "presence_update", session },
26
+ { type: "session_left", sessionId: "session-2" },
27
+ ]);
28
+ });
29
+
30
+ test("registered feature negotiation rejects non-string feature entries", () => {
31
+ const client = new IntercomClient();
32
+ assert.throws(
33
+ () => (client as any).handleBrokerMessage({ type: "registered", sessionId: "session-1", features: ["valid", 123] }),
34
+ /Invalid registered features/,
35
+ );
36
+ });
37
+
38
+ test("malformed extension broker messages are rejected", () => {
39
+ const client = new IntercomClient();
40
+ (client as any)._sessionId = "session-1";
41
+
42
+ assert.throws(
43
+ () => (client as any).handleBrokerMessage({ type: "extension_owner", namespace: "test/v1", ownerId: "owner" }),
44
+ /Invalid extension_owner/,
45
+ );
46
+ assert.throws(
47
+ () => (client as any).handleBrokerMessage({ type: "extension_owner", namespace: "test/v1", ownerEpoch: "epoch" }),
48
+ /Invalid extension_owner/,
49
+ );
50
+ assert.throws(
51
+ () => (client as any).handleBrokerMessage({ type: "extension_message", namespace: "test/v1" }),
52
+ /Invalid extension_message/,
53
+ );
54
+ assert.throws(
55
+ () => (client as any).handleBrokerMessage({ type: "extension_state", namespace: "test/v1", revision: -1 }),
56
+ /Invalid extension_state/,
57
+ );
58
+ assert.throws(
59
+ () => (client as any).handleBrokerMessage({ type: "extension_state_result", namespace: "test/v1", committed: "yes", revision: 1 }),
60
+ /Invalid extension_state_result/,
61
+ );
62
+ assert.doesNotThrow(() => (client as any).handleBrokerMessage({
63
+ type: "extension_message",
64
+ namespace: "test/v1",
65
+ fromSessionId: "session-2",
66
+ payload: { peerOnly: true },
67
+ }));
68
+ });
69
+
70
+ test("cancelAsk ignores synchronous socket write failures", () => {
71
+ const client = new IntercomClient();
72
+ (client as any)._sessionId = "session-1";
73
+ (client as any).socket = {
74
+ destroyed: false,
75
+ writableEnded: false,
76
+ writable: true,
77
+ write() {
78
+ throw new Error("write failed");
79
+ },
80
+ };
81
+
82
+ assert.doesNotThrow(() => client.cancelAsk("ask-1"));
83
+ });
@@ -1,11 +1,20 @@
1
1
  import { EventEmitter } from "events";
2
2
  import net from "net";
3
3
  import { randomUUID } from "crypto";
4
- import { writeMessage, createMessageReader } from "./framing.js";
5
- import { getBrokerSocketPath } from "./paths.js";
6
- import type { SessionInfo, Message, Attachment } from "../types.js";
7
-
8
- const BROKER_SOCKET = getBrokerSocketPath();
4
+ import { writeMessage, createMessageReader } from "./framing.ts";
5
+ import { getBrokerConnectTarget, type BrokerConnectTarget } from "./paths.ts";
6
+ import { EXTENSION_BUS_FEATURE } from "../types.ts";
7
+ import type {
8
+ Attachment,
9
+ BrokerMessage,
10
+ ClientMessage,
11
+ Message,
12
+ MessageControl,
13
+ MessageReceipt,
14
+ MessageReceiptStatus,
15
+ SessionInfo,
16
+ SessionRegistration,
17
+ } from "../types.ts";
9
18
 
10
19
  interface SendOptions {
11
20
  text: string;
@@ -13,6 +22,8 @@ interface SendOptions {
13
22
  replyTo?: string;
14
23
  expectsReply?: boolean;
15
24
  messageId?: string;
25
+ supersedes?: string;
26
+ retryOf?: string;
16
27
  }
17
28
 
18
29
  interface SendResult {
@@ -25,6 +36,51 @@ function toError(error: unknown): Error {
25
36
  return error instanceof Error ? error : new Error(String(error));
26
37
  }
27
38
 
39
+ function connectToBrokerTarget(target: BrokerConnectTarget): net.Socket {
40
+ return typeof target === "string"
41
+ ? net.connect(target)
42
+ : net.connect({ host: target.host, port: target.port });
43
+ }
44
+
45
+ function isMessageReceiptStatus(value: unknown): value is MessageReceiptStatus {
46
+ return value === "receiver_received"
47
+ || value === "queued"
48
+ || value === "injected"
49
+ || value === "acknowledged"
50
+ || value === "expired"
51
+ || value === "cancelled"
52
+ || value === "superseded"
53
+ || value === "cancellation_requested";
54
+ }
55
+
56
+ function isMessageReceipt(value: unknown): value is MessageReceipt {
57
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
58
+ return false;
59
+ }
60
+ const receipt = value as Record<string, unknown>;
61
+ if (typeof receipt.messageId !== "string" || !isMessageReceiptStatus(receipt.status) || typeof receipt.timestamp !== "number") {
62
+ return false;
63
+ }
64
+ return receipt.detail === undefined || typeof receipt.detail === "string";
65
+ }
66
+
67
+ function isMessageControl(value: unknown): value is MessageControl {
68
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
69
+ return false;
70
+ }
71
+ const control = value as Record<string, unknown>;
72
+ if (typeof control.messageId !== "string" || typeof control.timestamp !== "number") {
73
+ return false;
74
+ }
75
+ if (control.action !== "cancel" && control.action !== "supersede") {
76
+ return false;
77
+ }
78
+ if (control.supersededBy !== undefined && typeof control.supersededBy !== "string") {
79
+ return false;
80
+ }
81
+ return control.detail === undefined || typeof control.detail === "string";
82
+ }
83
+
28
84
  function isAttachment(value: unknown): value is Attachment {
29
85
  if (typeof value !== "object" || value === null) {
30
86
  return false;
@@ -58,6 +114,20 @@ function isMessage(value: unknown): value is Message {
58
114
  return false;
59
115
  }
60
116
 
117
+ for (const key of ["senderSequence", "brokerReceivedAt", "brokerDeliveredAt", "receiverReceivedAt", "injectedAt"] as const) {
118
+ if (message[key] !== undefined && typeof message[key] !== "number") {
119
+ return false;
120
+ }
121
+ }
122
+
123
+ if (message.supersedes !== undefined && typeof message.supersedes !== "string") {
124
+ return false;
125
+ }
126
+
127
+ if (message.retryOf !== undefined && typeof message.retryOf !== "string") {
128
+ return false;
129
+ }
130
+
61
131
  if (message.replyTo !== undefined && typeof message.replyTo !== "string") {
62
132
  return false;
63
133
  }
@@ -101,14 +171,30 @@ function isSessionInfo(value: unknown): value is SessionInfo {
101
171
  return false;
102
172
  }
103
173
 
104
- return session.status === undefined || typeof session.status === "string";
174
+ if (session.status !== undefined && typeof session.status !== "string") {
175
+ return false;
176
+ }
177
+
178
+ if (session.peerUid !== undefined && typeof session.peerUid !== "number") {
179
+ return false;
180
+ }
181
+
182
+ for (const key of ["contextPct", "contextTokens", "contextWindow"] as const) {
183
+ if (session[key] !== undefined && typeof session[key] !== "number") {
184
+ return false;
185
+ }
186
+ }
187
+
188
+ return session.trustedLocal === undefined || typeof session.trustedLocal === "boolean";
105
189
  }
106
190
 
107
191
  export class IntercomClient extends EventEmitter {
108
192
  private socket: net.Socket | null = null;
109
193
  private _sessionId: string | null = null;
194
+ private _features = new Set<string>();
110
195
  private pendingSends = new Map<string, { resolve: (r: SendResult) => void; reject: (e: Error) => void }>();
111
196
  private pendingLists = new Map<string, { resolve: (sessions: SessionInfo[]) => void; reject: (e: Error) => void }>();
197
+ private nextSenderSequence = 1;
112
198
  private disconnecting = false;
113
199
  private disconnectError: Error | null = null;
114
200
 
@@ -127,6 +213,10 @@ export class IntercomClient extends EventEmitter {
127
213
  return this._sessionId;
128
214
  }
129
215
 
216
+ supportsFeature(feature: string): boolean {
217
+ return this._features.has(feature);
218
+ }
219
+
130
220
  isConnected(): boolean {
131
221
  const socket = this.socket;
132
222
  return Boolean(socket && this._sessionId && !this.disconnecting && !socket.destroyed && !socket.writableEnded && socket.writable);
@@ -149,13 +239,21 @@ export class IntercomClient extends EventEmitter {
149
239
  return socket;
150
240
  }
151
241
 
152
- connect(session: Omit<SessionInfo, "id">): Promise<void> {
242
+ connect(session: SessionRegistration, sessionId?: string): Promise<void> {
153
243
  if (this.socket) {
154
244
  return Promise.reject(new Error("Already connected"));
155
245
  }
156
246
 
157
247
  return new Promise((resolve, reject) => {
158
- const socket = net.connect(BROKER_SOCKET);
248
+ let socket: net.Socket;
249
+ let target: BrokerConnectTarget;
250
+ try {
251
+ target = getBrokerConnectTarget();
252
+ socket = connectToBrokerTarget(target);
253
+ } catch (error) {
254
+ reject(toError(error));
255
+ return;
256
+ }
159
257
  this.socket = socket;
160
258
  this.disconnectError = null;
161
259
  let settled = false;
@@ -203,6 +301,7 @@ export class IntercomClient extends EventEmitter {
203
301
  this.socket = null;
204
302
  }
205
303
  this._sessionId = null;
304
+ this._features.clear();
206
305
  this.disconnectError = null;
207
306
  if (connectionEstablished && !wasDisconnecting) {
208
307
  this.emit("disconnected", disconnectError);
@@ -254,7 +353,12 @@ export class IntercomClient extends EventEmitter {
254
353
  this.once("_registered", onRegistered);
255
354
 
256
355
  try {
257
- writeMessage(socket, { type: "register", session });
356
+ writeMessage(socket, {
357
+ type: "register",
358
+ session,
359
+ ...(sessionId ? { sessionId } : {}),
360
+ ...(typeof target === "string" ? {} : { stateId: target.stateId }),
361
+ });
258
362
  } catch (error) {
259
363
  cleanupConnectionAttempt();
260
364
  cleanupSocketListeners();
@@ -274,7 +378,7 @@ export class IntercomClient extends EventEmitter {
274
378
 
275
379
  const brokerMessage = msg as { type: string } & Record<string, unknown>;
276
380
 
277
- if (this._sessionId === null && brokerMessage.type !== "registered") {
381
+ if (this._sessionId === null && brokerMessage.type !== "registered" && brokerMessage.type !== "error") {
278
382
  throw new Error(`Received ${brokerMessage.type} before registered`);
279
383
  }
280
384
 
@@ -288,8 +392,22 @@ export class IntercomClient extends EventEmitter {
288
392
  throw new Error("Received duplicate registered message");
289
393
  }
290
394
 
395
+ if (
396
+ brokerMessage.features !== undefined
397
+ && (!Array.isArray(brokerMessage.features) || !brokerMessage.features.every((feature) => typeof feature === "string"))
398
+ ) {
399
+ throw new Error("Invalid registered features");
400
+ }
401
+
291
402
  this._sessionId = brokerMessage.sessionId;
292
- this.emit("_registered", { type: "registered", sessionId: brokerMessage.sessionId });
403
+ this._features = new Set((brokerMessage.features as string[] | undefined) ?? []);
404
+ const registered: BrokerMessage = {
405
+ type: "registered",
406
+ sessionId: brokerMessage.sessionId,
407
+ ...(this._features.size > 0 ? { features: [...this._features] } : {}),
408
+ };
409
+ this.emit("broker_message", registered);
410
+ this.emit("_registered", registered);
293
411
  break;
294
412
  }
295
413
 
@@ -354,11 +472,31 @@ export class IntercomClient extends EventEmitter {
354
472
  break;
355
473
  }
356
474
 
475
+ case "message_receipt": {
476
+ if (!isSessionInfo(brokerMessage.from) || !isMessageReceipt(brokerMessage.receipt)) {
477
+ throw new Error("Invalid message_receipt event");
478
+ }
479
+ this.emit("broker_message", brokerMessage as BrokerMessage);
480
+ this.emit("message_receipt", brokerMessage.from, brokerMessage.receipt);
481
+ break;
482
+ }
483
+
484
+ case "message_control": {
485
+ if (!isSessionInfo(brokerMessage.from) || !isMessageControl(brokerMessage.control)) {
486
+ throw new Error("Invalid message_control event");
487
+ }
488
+ this.emit("broker_message", brokerMessage as BrokerMessage);
489
+ this.emit("message_control", brokerMessage.from, brokerMessage.control);
490
+ break;
491
+ }
492
+
357
493
  case "session_joined": {
358
494
  if (!isSessionInfo(brokerMessage.session)) {
359
495
  throw new Error("Invalid session_joined message");
360
496
  }
361
497
 
498
+ const message: BrokerMessage = { type: "session_joined", session: brokerMessage.session };
499
+ this.emit("broker_message", message);
362
500
  this.emit("session_joined", brokerMessage.session);
363
501
  break;
364
502
  }
@@ -368,6 +506,8 @@ export class IntercomClient extends EventEmitter {
368
506
  throw new Error("Invalid session_left message");
369
507
  }
370
508
 
509
+ const message: BrokerMessage = { type: "session_left", sessionId: brokerMessage.sessionId };
510
+ this.emit("broker_message", message);
371
511
  this.emit("session_left", brokerMessage.sessionId);
372
512
  break;
373
513
  }
@@ -377,6 +517,8 @@ export class IntercomClient extends EventEmitter {
377
517
  throw new Error("Invalid presence_update message");
378
518
  }
379
519
 
520
+ const message: BrokerMessage = { type: "presence_update", session: brokerMessage.session };
521
+ this.emit("broker_message", message);
380
522
  this.emit("presence_update", brokerMessage.session);
381
523
  break;
382
524
  }
@@ -386,10 +528,74 @@ export class IntercomClient extends EventEmitter {
386
528
  throw new Error("Invalid error message");
387
529
  }
388
530
 
531
+ if (this._sessionId === null) {
532
+ throw new Error(brokerMessage.error);
533
+ }
389
534
  this.emit("error", new Error(brokerMessage.error));
390
535
  break;
391
536
  }
392
537
 
538
+ case "extension_owner": {
539
+ const hasOwnerId = typeof brokerMessage.ownerId === "string";
540
+ const hasOwnerEpoch = typeof brokerMessage.ownerEpoch === "string";
541
+ if (
542
+ typeof brokerMessage.namespace !== "string"
543
+ || hasOwnerId !== hasOwnerEpoch
544
+ || (brokerMessage.ownerId !== undefined && !hasOwnerId)
545
+ || (brokerMessage.ownerEpoch !== undefined && !hasOwnerEpoch)
546
+ ) {
547
+ throw new Error("Invalid extension_owner message");
548
+ }
549
+ this.emit("broker_message", brokerMessage as BrokerMessage);
550
+ this.emit("extension_owner", brokerMessage);
551
+ break;
552
+ }
553
+
554
+ case "extension_message": {
555
+ const hasOwnerId = typeof brokerMessage.ownerId === "string";
556
+ const hasOwnerEpoch = typeof brokerMessage.ownerEpoch === "string";
557
+ if (
558
+ typeof brokerMessage.namespace !== "string"
559
+ || typeof brokerMessage.fromSessionId !== "string"
560
+ || hasOwnerId !== hasOwnerEpoch
561
+ || (brokerMessage.ownerId !== undefined && !hasOwnerId)
562
+ || (brokerMessage.ownerEpoch !== undefined && !hasOwnerEpoch)
563
+ ) {
564
+ throw new Error("Invalid extension_message");
565
+ }
566
+ this.emit("broker_message", brokerMessage as BrokerMessage);
567
+ this.emit("extension_message", brokerMessage);
568
+ break;
569
+ }
570
+
571
+ case "extension_state": {
572
+ if (
573
+ typeof brokerMessage.namespace !== "string"
574
+ || !Number.isSafeInteger(brokerMessage.revision)
575
+ || Number(brokerMessage.revision) < 0
576
+ ) {
577
+ throw new Error("Invalid extension_state");
578
+ }
579
+ this.emit("broker_message", brokerMessage as BrokerMessage);
580
+ this.emit("extension_state", brokerMessage);
581
+ break;
582
+ }
583
+
584
+ case "extension_state_result": {
585
+ if (
586
+ typeof brokerMessage.namespace !== "string"
587
+ || typeof brokerMessage.committed !== "boolean"
588
+ || !Number.isSafeInteger(brokerMessage.revision)
589
+ || Number(brokerMessage.revision) < 0
590
+ || (brokerMessage.reason !== undefined && typeof brokerMessage.reason !== "string")
591
+ ) {
592
+ throw new Error("Invalid extension_state_result");
593
+ }
594
+ this.emit("broker_message", brokerMessage as BrokerMessage);
595
+ this.emit("extension_state_result", brokerMessage);
596
+ break;
597
+ }
598
+
393
599
  default:
394
600
  throw new Error(`Unknown broker message type: ${brokerMessage.type}`);
395
601
  }
@@ -438,6 +644,12 @@ export class IntercomClient extends EventEmitter {
438
644
  });
439
645
  }
440
646
 
647
+ updateExtensionCapabilities(extensions: SessionRegistration["extensions"]): void {
648
+ if (!this.supportsFeature(EXTENSION_BUS_FEATURE)) return;
649
+ const socket = this.requireActiveSocket();
650
+ writeMessage(socket, { type: "extension_capabilities_update", extensions: extensions ?? [] });
651
+ }
652
+
441
653
  listSessions(): Promise<SessionInfo[]> {
442
654
  let socket: net.Socket;
443
655
  try {
@@ -485,6 +697,9 @@ export class IntercomClient extends EventEmitter {
485
697
  const message: Message = {
486
698
  id: messageId,
487
699
  timestamp: Date.now(),
700
+ senderSequence: this.nextSenderSequence++,
701
+ supersedes: options.supersedes,
702
+ retryOf: options.retryOf,
488
703
  replyTo: options.replyTo,
489
704
  expectsReply: options.expectsReply,
490
705
  content: {
@@ -520,7 +735,72 @@ export class IntercomClient extends EventEmitter {
520
735
  });
521
736
  }
522
737
 
523
- updatePresence(updates: { name?: string; status?: string; model?: string }): void {
738
+ cancelMessage(messageId: string): Promise<SendResult> {
739
+ let socket: net.Socket;
740
+ try {
741
+ socket = this.requireActiveSocket();
742
+ } catch (error) {
743
+ return Promise.reject(toError(error));
744
+ }
745
+
746
+ return new Promise((resolve, reject) => {
747
+ const wrappedResolve = (result: SendResult) => {
748
+ clearTimeout(timeout);
749
+ resolve(result);
750
+ };
751
+ const wrappedReject = (error: Error) => {
752
+ clearTimeout(timeout);
753
+ reject(error);
754
+ };
755
+ const timeout = setTimeout(() => {
756
+ if (this.pendingSends.has(messageId)) {
757
+ this.pendingSends.delete(messageId);
758
+ wrappedReject(new Error("Cancel timeout"));
759
+ }
760
+ }, 10000);
761
+ this.pendingSends.set(messageId, { resolve: wrappedResolve, reject: wrappedReject });
762
+
763
+ try {
764
+ writeMessage(socket, { type: "cancel_message", messageId });
765
+ } catch (error) {
766
+ clearTimeout(timeout);
767
+ this.pendingSends.delete(messageId);
768
+ reject(toError(error));
769
+ }
770
+ });
771
+ }
772
+
773
+ sendMessageReceipt(receipt: MessageReceipt): void {
774
+ if (this.disconnecting) {
775
+ return;
776
+ }
777
+
778
+ const socket = this.socket;
779
+ if (!socket || !this._sessionId || socket.destroyed || socket.writableEnded || !socket.writable) {
780
+ return;
781
+ }
782
+
783
+ writeMessage(socket, { type: "message_receipt", receipt });
784
+ }
785
+
786
+ cancelAsk(messageId: string): void {
787
+ if (this.disconnecting) {
788
+ return;
789
+ }
790
+
791
+ const socket = this.socket;
792
+ if (!socket || !this._sessionId || socket.destroyed || socket.writableEnded || !socket.writable) {
793
+ return;
794
+ }
795
+
796
+ try {
797
+ writeMessage(socket, { type: "cancel_ask", messageId });
798
+ } catch {
799
+ // Cancellation is best-effort; local waiter cleanup must still proceed.
800
+ }
801
+ }
802
+
803
+ updatePresence(updates: { name?: string; status?: string; model?: string; contextPct?: number | null; contextTokens?: number | null; contextWindow?: number | null }): void {
524
804
  if (this.disconnecting) {
525
805
  return;
526
806
  }
@@ -532,4 +812,27 @@ export class IntercomClient extends EventEmitter {
532
812
 
533
813
  writeMessage(socket, { type: "presence", ...updates });
534
814
  }
815
+
816
+ sendExtensionMessage(message: Extract<ClientMessage, { type: "extension_publish" | "extension_state_commit" }>): void {
817
+ if (!this.supportsFeature(EXTENSION_BUS_FEATURE)) {
818
+ throw new Error(`Connected broker does not support ${EXTENSION_BUS_FEATURE}`);
819
+ }
820
+ const socket = this.requireActiveSocket();
821
+ writeMessage(socket, message);
822
+ }
823
+
824
+ onBrokerMessage(handler: (message: BrokerMessage) => void): () => void {
825
+ this.on("broker_message", handler);
826
+ return () => this.off("broker_message", handler);
827
+ }
828
+
829
+ onMessageReceipt(handler: (from: SessionInfo, receipt: MessageReceipt) => void): () => void {
830
+ this.on("message_receipt", handler);
831
+ return () => this.off("message_receipt", handler);
832
+ }
833
+
834
+ onMessageControl(handler: (from: SessionInfo, control: MessageControl) => void): () => void {
835
+ this.on("message_control", handler);
836
+ return () => this.off("message_control", handler);
837
+ }
535
838
  }