@selesai/code 0.9.10 → 0.9.12

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 (862) hide show
  1. package/CHANGELOG.md +271 -255
  2. package/dist/cli/args.js +13 -2
  3. package/dist/cli/args.test.js +8 -0
  4. package/dist/cli/credential-print.js +4 -4
  5. package/dist/cli.js +0 -0
  6. package/dist/config.d.ts +4 -6
  7. package/dist/config.js +10 -14
  8. package/dist/core/agent-session-auto-handoff.test.js +24 -1
  9. package/dist/core/agent-session.d.ts +10 -4
  10. package/dist/core/agent-session.js +61 -46
  11. package/dist/core/compaction/branch-summarization.js +30 -30
  12. package/dist/core/compaction/compaction.js +81 -81
  13. package/dist/core/compaction/utils.js +2 -2
  14. package/dist/core/defaults.d.ts +1 -0
  15. package/dist/core/defaults.js +9 -0
  16. package/dist/core/export-html/template.css +1066 -1066
  17. package/dist/core/export-html/template.html +55 -55
  18. package/dist/core/export-html/template.js +1864 -1864
  19. package/dist/core/export-html/vendor/highlight.min.js +1212 -1212
  20. package/dist/core/export-html/vendor/marked.min.js +78 -78
  21. package/dist/core/extensions/loader.js +108 -35
  22. package/dist/core/extensions/loader.test.js +21 -0
  23. package/dist/core/extensions/types.d.ts +12 -4
  24. package/dist/core/keybindings.d.ts +2 -2
  25. package/dist/core/messages.js +7 -7
  26. package/dist/core/model-resolver.d.ts +1 -0
  27. package/dist/core/model-resolver.js +10 -4
  28. package/dist/core/package-manager.js +4 -4
  29. package/dist/core/sdk.d.ts +5 -5
  30. package/dist/core/sdk.js +16 -4
  31. package/dist/core/settings-manager.d.ts +6 -2
  32. package/dist/core/settings-manager.js +22 -3
  33. package/dist/core/tools/bash.d.ts +18 -1
  34. package/dist/core/tools/bash.js +41 -23
  35. package/dist/core/tools/index.d.ts +4 -2
  36. package/dist/core/tools/index.js +9 -2
  37. package/dist/core/tools/powershell.d.ts +15 -0
  38. package/dist/core/tools/powershell.js +38 -0
  39. package/dist/core/tools/powershell.test.d.ts +1 -0
  40. package/dist/core/tools/powershell.test.js +20 -0
  41. package/dist/defaults/settings.json +0 -1
  42. package/dist/extensions/context-compaction-reminder.test.ts +82 -82
  43. package/dist/extensions/context-compaction-reminder.ts +28 -28
  44. package/dist/extensions/model-prompt-injector/index.test.ts +0 -10
  45. package/dist/extensions/model-prompt-injector/index.ts +0 -3
  46. package/dist/extensions/pi-intercom/CHANGELOG.md +53 -16
  47. package/dist/extensions/pi-intercom/LICENSE +21 -21
  48. package/dist/extensions/pi-intercom/README.md +41 -8
  49. package/dist/extensions/pi-intercom/banner.png +0 -0
  50. package/dist/extensions/pi-intercom/broker/broker.ts +498 -215
  51. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -83
  52. package/dist/extensions/pi-intercom/broker/client.ts +39 -12
  53. package/dist/extensions/pi-intercom/broker/extension.test.ts +486 -387
  54. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -114
  55. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -153
  56. package/dist/extensions/pi-intercom/broker/paths.ts +134 -134
  57. package/dist/extensions/pi-intercom/broker/protocol.ts +26 -0
  58. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -34
  59. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -21
  60. package/dist/extensions/pi-intercom/broker/spawn.test.ts +5 -20
  61. package/dist/extensions/pi-intercom/config.test.ts +41 -0
  62. package/dist/extensions/pi-intercom/config.ts +21 -0
  63. package/dist/extensions/pi-intercom/cwd.test.ts +40 -40
  64. package/dist/extensions/pi-intercom/cwd.ts +31 -31
  65. package/dist/extensions/pi-intercom/extension-api.ts +84 -44
  66. package/dist/extensions/pi-intercom/format-context.test.ts +31 -31
  67. package/dist/extensions/pi-intercom/format-context.ts +32 -32
  68. package/dist/extensions/pi-intercom/index.ts +362 -26
  69. package/dist/extensions/pi-intercom/intercom.integration.test.ts +819 -13
  70. package/dist/extensions/pi-intercom/package.json +1 -1
  71. package/dist/extensions/pi-intercom/project-agent.ts +2 -2
  72. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +8 -110
  73. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -66
  74. package/dist/extensions/pi-intercom/types.ts +32 -5
  75. package/dist/extensions/pi-intercom/ui/compose.ts +143 -143
  76. package/dist/extensions/pi-intercom/ui/inline-message.ts +6 -0
  77. package/dist/extensions/pi-intercom/ui/session-list.ts +166 -166
  78. package/dist/extensions/pi-powerline-footer/bash-mode/shell-session.ts +286 -286
  79. package/dist/extensions/pi-powerline-footer/bash-mode/transcript.ts +108 -108
  80. package/dist/extensions/pi-powerline-footer/separators.ts +57 -57
  81. package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +47 -47
  82. package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +39 -39
  83. package/dist/extensions/pi-powerline-footer/theme.example.json +24 -24
  84. package/dist/extensions/pi-powerline-footer/theme.json +12 -12
  85. package/dist/extensions/pi-powerline-footer/tps.ts +345 -345
  86. package/dist/extensions/pi-rewind-hook/README.md +245 -245
  87. package/dist/extensions/pi-rewind-hook/index.ts +1445 -1445
  88. package/dist/extensions/pi-rewind-hook/package.json +29 -29
  89. package/dist/extensions/pi-subagents/.github/assets/subagent-fleet-inspector.png +0 -0
  90. package/dist/extensions/pi-subagents/.github/workflows/release.yml +28 -0
  91. package/dist/extensions/pi-subagents/.github/workflows/test.yml +51 -0
  92. package/dist/extensions/pi-subagents/.greptile/config.json +33 -0
  93. package/dist/extensions/pi-subagents/.greptile/files.json +8 -0
  94. package/dist/extensions/pi-subagents/.greptile/rules.md +16 -0
  95. package/dist/extensions/pi-subagents/CHANGELOG.md +309 -87
  96. package/dist/extensions/pi-subagents/README.md +15 -17
  97. package/dist/extensions/pi-subagents/agents/oracle.md +3 -1
  98. package/dist/extensions/pi-subagents/agents/researcher.md +32 -13
  99. package/dist/extensions/pi-subagents/agents/reviewer.md +13 -2
  100. package/dist/extensions/pi-subagents/agents/scout.md +2 -2
  101. package/dist/extensions/pi-subagents/agents/worker.md +2 -1
  102. package/dist/extensions/pi-subagents/async-retention-discovery-worker.mjs +180 -0
  103. package/dist/extensions/pi-subagents/docs/configuration.md +106 -27
  104. package/dist/extensions/pi-subagents/docs/extension-api.md +85 -21
  105. package/dist/extensions/pi-subagents/docs/missions.md +41 -4
  106. package/dist/extensions/pi-subagents/docs/models.md +52 -9
  107. package/dist/extensions/pi-subagents/docs/observability.md +103 -16
  108. package/dist/extensions/pi-subagents/docs/tool-reference.md +60 -45
  109. package/dist/extensions/pi-subagents/docs/watchdog.md +60 -3
  110. package/dist/extensions/pi-subagents/docs/workflows.md +181 -7
  111. package/dist/extensions/pi-subagents/index.ts +10 -1
  112. package/dist/extensions/pi-subagents/install.mjs +4 -4
  113. package/dist/extensions/pi-subagents/package-lock.json +1483 -1470
  114. package/dist/extensions/pi-subagents/package.json +6 -3
  115. package/dist/extensions/pi-subagents/prompts/council.md +60 -0
  116. package/dist/extensions/pi-subagents/prompts/parallel-review.md +5 -1
  117. package/dist/extensions/pi-subagents/prompts/review-loop.md +9 -5
  118. package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +254 -0
  119. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +18 -17
  120. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +31 -9
  121. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +107 -140
  122. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +9 -12
  123. package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +39 -0
  124. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +44 -92
  125. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +261 -368
  126. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +6 -2
  127. package/dist/extensions/pi-subagents/src/agents/agents.ts +388 -85
  128. package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +14 -0
  129. package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +418 -0
  130. package/dist/extensions/pi-subagents/src/agents/skills.ts +1 -1
  131. package/dist/extensions/pi-subagents/src/api/agents.ts +7 -0
  132. package/dist/extensions/pi-subagents/src/api/external-job-provider.ts +195 -0
  133. package/dist/extensions/pi-subagents/src/api/preflight.ts +88 -27
  134. package/dist/extensions/pi-subagents/src/api/project-panes.ts +2 -0
  135. package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -0
  136. package/dist/extensions/pi-subagents/src/extension/config.ts +20 -11
  137. package/dist/extensions/pi-subagents/src/extension/doctor.ts +14 -6
  138. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -4
  139. package/dist/extensions/pi-subagents/src/extension/index.ts +270 -187
  140. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +65 -28
  141. package/dist/extensions/pi-subagents/src/extension/rpc.ts +120 -11
  142. package/dist/extensions/pi-subagents/src/extension/schemas.ts +46 -64
  143. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +51 -37
  144. package/dist/extensions/pi-subagents/src/extension/tool-result.ts +19 -0
  145. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -2
  146. package/dist/extensions/pi-subagents/src/inspectors/herdr/client.ts +3 -3
  147. package/dist/extensions/pi-subagents/src/inspectors/herdr/focus.ts +55 -0
  148. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -1
  149. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +230 -46
  150. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +26 -4
  151. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +32 -10
  152. package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +6 -1
  153. package/dist/extensions/pi-subagents/src/missions/store.ts +4 -9
  154. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +2 -2
  155. package/dist/extensions/pi-subagents/src/policy/authority.ts +2 -0
  156. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +3 -1
  157. package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +31 -8
  158. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +210 -52
  159. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +63 -33
  160. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +71 -17
  161. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +886 -0
  162. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +14 -5
  163. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +49 -56
  164. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +1 -0
  165. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +3 -33
  166. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +5 -0
  167. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +5 -1
  168. package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +22 -12
  169. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +105 -71
  170. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +68 -19
  171. package/dist/extensions/pi-subagents/src/runs/background/index-segment.ts +59 -0
  172. package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +443 -0
  173. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +94 -10
  174. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +158 -90
  175. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +141 -53
  176. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +8 -5
  177. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +14 -4
  178. package/dist/extensions/pi-subagents/src/runs/background/run-id-query.ts +7 -0
  179. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +13 -14
  180. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +46 -25
  181. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +823 -0
  182. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +9 -3
  183. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +11 -1
  184. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +594 -216
  185. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +17 -13
  186. package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +138 -0
  187. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +23 -4
  188. package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +82 -4
  189. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +5 -3
  190. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +21 -14
  191. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +23 -2
  192. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +153 -58
  193. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +7 -9
  194. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1283 -1657
  195. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +274 -0
  196. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +6 -5
  197. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +59 -10
  198. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
  199. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +1 -3
  200. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +36 -0
  201. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +52 -2
  202. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  203. package/dist/extensions/pi-subagents/src/runs/shared/extension-bindings.ts +78 -0
  204. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +2 -0
  205. package/dist/extensions/pi-subagents/src/runs/shared/external-job-bridge.ts +460 -0
  206. package/dist/extensions/pi-subagents/src/runs/shared/external-job-runner.ts +389 -0
  207. package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +10 -0
  208. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +14 -0
  209. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +243 -0
  210. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +201 -85
  211. package/dist/extensions/pi-subagents/src/runs/shared/model-scope.ts +106 -39
  212. package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +145 -0
  213. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +150 -27
  214. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +46 -4
  215. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +19 -15
  216. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +5 -1
  217. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +86 -2
  218. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +9 -9
  219. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +0 -6
  220. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +18 -4
  221. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +51 -7
  222. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +62 -21
  223. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +1 -3
  224. package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +1 -3
  225. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +1 -23
  226. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +14 -2
  227. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +2 -2
  228. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +22 -2
  229. package/dist/extensions/pi-subagents/src/shared/capacity-resilient-json.ts +102 -0
  230. package/dist/extensions/pi-subagents/src/shared/completion-owner.ts +14 -0
  231. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +49 -1
  232. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +59 -1
  233. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +12 -5
  234. package/dist/extensions/pi-subagents/src/shared/model-info.ts +20 -0
  235. package/dist/extensions/pi-subagents/src/shared/prompt-resources.ts +0 -40
  236. package/dist/extensions/pi-subagents/src/shared/settings.ts +11 -30
  237. package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +52 -0
  238. package/dist/extensions/pi-subagents/src/shared/types.ts +228 -49
  239. package/dist/extensions/pi-subagents/src/shared/utils.ts +11 -3
  240. package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +10 -0
  241. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +0 -162
  242. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +2 -5
  243. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +105 -13
  244. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +6 -36
  245. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +829 -0
  246. package/dist/extensions/pi-subagents/src/tui/fleet.ts +1415 -0
  247. package/dist/extensions/pi-subagents/src/tui/render.ts +78 -7
  248. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +1 -1
  249. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +1 -0
  250. package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +59 -51
  251. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +8 -2
  252. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +2 -1
  253. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +4 -4
  254. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +471 -86
  255. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +140 -0
  256. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  257. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/cli.d.ts +3 -0
  258. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/register-bedrock.d.ts +2 -0
  259. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/restore-sandbox-env.d.ts +17 -0
  260. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/args.d.ts +57 -0
  261. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/config-selector.d.ts +16 -0
  262. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/file-processor.d.ts +15 -0
  263. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/initial-message.d.ts +18 -0
  264. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/list-models.d.ts +9 -0
  265. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/project-trust.d.ts +10 -0
  266. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/session-picker.d.ts +10 -0
  267. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/startup-ui.d.ts +20 -0
  268. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli.d.ts +3 -0
  269. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/config.d.ts +96 -0
  270. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session-runtime.d.ts +119 -0
  271. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session-services.d.ts +85 -0
  272. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session.d.ts +620 -0
  273. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/auth-guidance.d.ts +5 -0
  274. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/auth-storage.d.ts +56 -0
  275. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/bash-executor.d.ts +32 -0
  276. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/cache-stats.d.ts +49 -0
  277. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/branch-summarization.d.ts +93 -0
  278. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/compaction.d.ts +128 -0
  279. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/index.d.ts +7 -0
  280. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/utils.d.ts +38 -0
  281. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/defaults.d.ts +3 -0
  282. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/diagnostics.d.ts +15 -0
  283. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/event-bus.d.ts +9 -0
  284. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/exec.d.ts +29 -0
  285. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/experimental.d.ts +2 -0
  286. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/ansi-to-html.d.ts +22 -0
  287. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/index.d.ts +37 -0
  288. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/tool-renderer.d.ts +34 -0
  289. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/index.d.ts +12 -0
  290. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/loader.d.ts +23 -0
  291. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/runner.d.ts +171 -0
  292. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +1261 -0
  293. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/wrapper.d.ts +20 -0
  294. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/footer-data-provider.d.ts +54 -0
  295. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/http-dispatcher.d.ts +22 -0
  296. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/index.d.ts +13 -0
  297. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/keybindings.d.ts +358 -0
  298. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/messages.d.ts +77 -0
  299. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-config.d.ts +512 -0
  300. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-registry.d.ts +43 -0
  301. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-resolver.d.ts +121 -0
  302. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-runtime.d.ts +82 -0
  303. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/models-store.d.ts +17 -0
  304. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/output-guard.d.ts +7 -0
  305. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/package-manager.d.ts +210 -0
  306. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/project-trust.d.ts +15 -0
  307. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/prompt-templates.d.ts +54 -0
  308. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/provider-attribution.d.ts +4 -0
  309. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/provider-composer.d.ts +55 -0
  310. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/radius.d.ts +2 -0
  311. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/remote-catalog-provider.d.ts +5 -0
  312. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/resolve-config-value.d.ts +30 -0
  313. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/resource-loader.d.ts +206 -0
  314. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/runtime-credentials.d.ts +15 -0
  315. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/sdk.d.ts +106 -0
  316. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/session-cwd.d.ts +19 -0
  317. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/session-manager.d.ts +356 -0
  318. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/settings-manager.d.ts +297 -0
  319. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/skills.d.ts +60 -0
  320. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/slash-commands.d.ts +15 -0
  321. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/source-info.d.ts +18 -0
  322. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/system-prompt.d.ts +28 -0
  323. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/telemetry.d.ts +3 -0
  324. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/timings.d.ts +10 -0
  325. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/bash.d.ts +68 -0
  326. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/edit-diff.d.ts +106 -0
  327. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/edit.d.ts +51 -0
  328. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/file-mutation-queue.d.ts +6 -0
  329. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/find.d.ts +35 -0
  330. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/grep.d.ts +37 -0
  331. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/index.d.ts +40 -0
  332. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/ls.d.ts +37 -0
  333. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/output-accumulator.d.ts +52 -0
  334. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/path-utils.d.ts +10 -0
  335. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/read.d.ts +35 -0
  336. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/render-utils.d.ts +24 -0
  337. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  338. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/truncate.d.ts +70 -0
  339. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/write.d.ts +26 -0
  340. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/trust-manager.d.ts +36 -0
  341. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/usage-totals.d.ts +19 -0
  342. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/index.d.ts +3 -0
  343. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/client.d.ts +61 -0
  344. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/huggingface.d.ts +23 -0
  345. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/index.d.ts +3 -0
  346. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/provider.d.ts +10 -0
  347. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/ui.d.ts +42 -0
  348. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/index.d.ts +35 -0
  349. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/main.d.ts +12 -0
  350. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/migrations.d.ts +33 -0
  351. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/index.d.ts +9 -0
  352. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/armin.d.ts +34 -0
  353. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/assistant-message.d.ts +22 -0
  354. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/bash-execution.d.ts +34 -0
  355. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
  356. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
  357. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
  358. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/config-selector.d.ts +102 -0
  359. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
  360. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-editor.d.ts +21 -0
  361. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-entry.d.ts +19 -0
  362. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-message.d.ts +20 -0
  363. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/daxnuts.d.ts +23 -0
  364. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/diff.d.ts +12 -0
  365. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
  366. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  367. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-editor.d.ts +22 -0
  368. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-input.d.ts +23 -0
  369. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-selector.d.ts +26 -0
  370. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
  371. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/footer.d.ts +32 -0
  372. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/index.d.ts +34 -0
  373. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/keybinding-hints.d.ts +13 -0
  374. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/login-dialog.d.ts +52 -0
  375. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/model-selector.d.ts +54 -0
  376. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/oauth-selector.d.ts +33 -0
  377. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/scoped-models-selector.d.ts +42 -0
  378. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
  379. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/session-selector.d.ts +95 -0
  380. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/settings-selector.d.ts +77 -0
  381. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
  382. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
  383. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/status-indicator.d.ts +28 -0
  384. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/theme-selector.d.ts +11 -0
  385. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
  386. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/tool-execution.d.ts +63 -0
  387. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/tree-selector.d.ts +94 -0
  388. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/trust-selector.d.ts +23 -0
  389. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
  390. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/user-message.d.ts +14 -0
  391. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
  392. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/interactive-mode.d.ts +394 -0
  393. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/model-search.d.ts +12 -0
  394. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/theme/theme-controller.d.ts +29 -0
  395. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/theme/theme.d.ts +120 -0
  396. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/print-mode.d.ts +28 -0
  397. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/jsonl.d.ts +17 -0
  398. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-client.d.ts +246 -0
  399. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-mode.d.ts +20 -0
  400. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-types.d.ts +457 -0
  401. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/package-manager-cli.d.ts +8 -0
  402. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/rpc-entry.d.ts +3 -0
  403. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/ansi.d.ts +2 -0
  404. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/changelog.d.ts +22 -0
  405. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/child-process.d.ts +18 -0
  406. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard-image.d.ts +11 -0
  407. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard-native.d.ts +11 -0
  408. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard.d.ts +4 -0
  409. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/deprecation.d.ts +4 -0
  410. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/exif-orientation.d.ts +5 -0
  411. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/frontmatter.d.ts +8 -0
  412. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/fs-watch.d.ts +5 -0
  413. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/git.d.ts +26 -0
  414. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/html.d.ts +7 -0
  415. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-convert.d.ts +10 -0
  416. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-process.d.ts +18 -0
  417. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize-core.d.ts +30 -0
  418. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize-worker.d.ts +2 -0
  419. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize.d.ts +16 -0
  420. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/json.d.ts +3 -0
  421. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/mime.d.ts +3 -0
  422. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/open-browser.d.ts +9 -0
  423. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/paths.d.ts +31 -0
  424. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/photon.d.ts +21 -0
  425. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/pi-user-agent.d.ts +2 -0
  426. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/shell.d.ts +31 -0
  427. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/sleep.d.ts +5 -0
  428. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/syntax-highlight.d.ts +12 -0
  429. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/tools-manager.d.ts +3 -0
  430. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/version-check.d.ts +15 -0
  431. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/windows-self-update.d.ts +3 -0
  432. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/index.mjs +1 -1
  433. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +0 -54
  434. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1053 -414
  435. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +194 -4
  436. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +59 -4
  437. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +0 -77
  438. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +107 -6
  439. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +211 -897
  440. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +265 -375
  441. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +77 -7
  442. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +1 -1
  443. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +10 -10
  444. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +547 -30
  445. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +2112 -310
  446. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +274 -34
  447. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +1 -1
  448. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +20 -3
  449. package/dist/extensions/pi-subagents/test/support/isolated-temp-root.mjs +9 -0
  450. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +30 -5
  451. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  452. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +4 -2
  453. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +1 -0
  454. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +197 -0
  455. package/dist/extensions/pi-subagents/test/unit/agent-contract.test.ts +14 -0
  456. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  457. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +204 -27
  458. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +444 -145
  459. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +256 -4
  460. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +9 -7
  461. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +152 -22
  462. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +29 -0
  463. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +205 -23
  464. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +579 -0
  465. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +24 -0
  466. package/dist/extensions/pi-subagents/test/unit/authority-policy.test.ts +1 -0
  467. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +3 -3
  468. package/dist/extensions/pi-subagents/test/unit/capacity-resilient-json.test.ts +155 -0
  469. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +2 -2
  470. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +7 -0
  471. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +123 -0
  472. package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +81 -3
  473. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +109 -7
  474. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +2 -2
  475. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +5 -2
  476. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -2
  477. package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +79 -0
  478. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +22 -0
  479. package/dist/extensions/pi-subagents/test/unit/external-job-runner.test.ts +961 -0
  480. package/dist/extensions/pi-subagents/test/unit/file-system-retry.test.ts +64 -0
  481. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +1110 -0
  482. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +1664 -0
  483. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +81 -1
  484. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +138 -11
  485. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +41 -2
  486. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +210 -79
  487. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +95 -0
  488. package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +596 -0
  489. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
  490. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +3 -5
  491. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +167 -0
  492. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +319 -18
  493. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +78 -0
  494. package/dist/extensions/pi-subagents/test/unit/model-scope-settings.test.ts +19 -5
  495. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +44 -0
  496. package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +129 -0
  497. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +231 -2
  498. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +28 -1
  499. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +106 -2
  500. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +204 -7
  501. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +59 -4
  502. package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +2 -6
  503. package/dist/extensions/pi-subagents/test/unit/pi-args-permission-system.test.ts +34 -2
  504. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +116 -6
  505. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +12 -3
  506. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +56 -61
  507. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +416 -1
  508. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +9 -2
  509. package/dist/extensions/pi-subagents/test/unit/project-panes-public-api.test.ts +42 -0
  510. package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +21 -30
  511. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +86 -11
  512. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +49 -1
  513. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +233 -5
  514. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +28 -5
  515. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +323 -20
  516. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +66 -10
  517. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +68 -5
  518. package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +174 -0
  519. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +679 -0
  520. package/dist/extensions/pi-subagents/test/unit/scheduled-store-root.test.ts +67 -0
  521. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +55 -44
  522. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +399 -84
  523. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +13 -0
  524. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  525. package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +15 -10
  526. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +11 -7
  527. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -0
  528. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +40 -1
  529. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +10 -2
  530. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +38 -3
  531. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +110 -12
  532. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +204 -19
  533. package/dist/extensions/pi-subagents/test/unit/temp-paths.test.ts +25 -0
  534. package/dist/extensions/pi-subagents/test/unit/thinking-ceiling.test.ts +73 -0
  535. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +90 -50
  536. package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +1 -2
  537. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +234 -7
  538. package/dist/extensions/pi-subagents/test/unit/watch-strategy.test.ts +24 -0
  539. package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +36 -0
  540. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +37 -9
  541. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +302 -0
  542. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +167 -7
  543. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +113 -0
  544. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +6 -6
  545. package/dist/extensions/pi-web-agent/package.json +31 -31
  546. package/dist/extensions/pi-web-agent/src/backends/config.ts +205 -205
  547. package/dist/extensions/pi-web-agent/src/backends/doctor.ts +136 -136
  548. package/dist/extensions/pi-web-agent/src/backends/factory.ts +152 -152
  549. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +25 -25
  550. package/dist/extensions/pi-web-agent/src/cache/ttl-cache.ts +28 -28
  551. package/dist/extensions/pi-web-agent/src/changelog-notice.ts +136 -136
  552. package/dist/extensions/pi-web-agent/src/commands/web-agent-config.ts +946 -946
  553. package/dist/extensions/pi-web-agent/src/extension.ts +126 -126
  554. package/dist/extensions/pi-web-agent/src/extract/readability.ts +118 -118
  555. package/dist/extensions/pi-web-agent/src/fetch/browser-resolution.ts +199 -199
  556. package/dist/extensions/pi-web-agent/src/fetch/firecrawl-fetch.ts +100 -100
  557. package/dist/extensions/pi-web-agent/src/fetch/headless-fetch.ts +117 -117
  558. package/dist/extensions/pi-web-agent/src/fetch/http-fetch.ts +67 -67
  559. package/dist/extensions/pi-web-agent/src/orchestration/answer-synthesizer.ts +60 -60
  560. package/dist/extensions/pi-web-agent/src/orchestration/candidate-selector.ts +50 -50
  561. package/dist/extensions/pi-web-agent/src/orchestration/direct-url.ts +52 -52
  562. package/dist/extensions/pi-web-agent/src/orchestration/evidence-quality.ts +105 -105
  563. package/dist/extensions/pi-web-agent/src/orchestration/evidence-ranker.ts +45 -45
  564. package/dist/extensions/pi-web-agent/src/orchestration/index.ts +28 -28
  565. package/dist/extensions/pi-web-agent/src/orchestration/query-planner.ts +47 -47
  566. package/dist/extensions/pi-web-agent/src/orchestration/research-orchestrator.ts +376 -376
  567. package/dist/extensions/pi-web-agent/src/orchestration/research-types.ts +64 -64
  568. package/dist/extensions/pi-web-agent/src/orchestration/research-worker.ts +181 -181
  569. package/dist/extensions/pi-web-agent/src/orchestration/source-profile.ts +101 -101
  570. package/dist/extensions/pi-web-agent/src/orchestration/stop-decider.ts +81 -81
  571. package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +210 -210
  572. package/dist/extensions/pi-web-agent/src/presentation/config.ts +75 -75
  573. package/dist/extensions/pi-web-agent/src/presentation/explore-presentation.ts +61 -61
  574. package/dist/extensions/pi-web-agent/src/presentation/fetch-presentation.ts +54 -54
  575. package/dist/extensions/pi-web-agent/src/presentation/search-presentation.ts +41 -41
  576. package/dist/extensions/pi-web-agent/src/presentation/select-view.ts +20 -20
  577. package/dist/extensions/pi-web-agent/src/presentation/types.ts +63 -63
  578. package/dist/extensions/pi-web-agent/src/search/brave.ts +114 -114
  579. package/dist/extensions/pi-web-agent/src/search/duckduckgo.ts +72 -72
  580. package/dist/extensions/pi-web-agent/src/search/searxng.ts +96 -96
  581. package/dist/extensions/pi-web-agent/src/tools/web-explore.ts +71 -71
  582. package/dist/extensions/pi-web-agent/src/tools/web-fetch-headless.ts +31 -31
  583. package/dist/extensions/pi-web-agent/src/tools/web-fetch.ts +31 -31
  584. package/dist/extensions/pi-web-agent/src/tools/web-search.ts +157 -157
  585. package/dist/extensions/pi-web-agent/src/types.ts +88 -88
  586. package/dist/extensions/ponytail/index.js +31 -25
  587. package/dist/extensions/ponytail/package.json +8 -8
  588. package/dist/extensions/ponytail/ponytail-config.cjs +34 -7
  589. package/dist/extensions/ponytail/ponytail-instructions.cjs +7 -9
  590. package/dist/extensions/ponytail/test/extension.test.js +7 -8
  591. package/dist/extensions/ponytail/test/helpers.test.js +1 -1
  592. package/dist/extensions/question/batch.ts +103 -103
  593. package/dist/extensions/question/constants.ts +30 -30
  594. package/dist/extensions/question/helpers.ts +58 -58
  595. package/dist/extensions/question/navigation.ts +14 -14
  596. package/dist/extensions/question/package.json +19 -19
  597. package/dist/extensions/question/schemas.ts +43 -43
  598. package/dist/extensions/question/selection-mode.ts +46 -46
  599. package/dist/extensions/question/shortcuts.ts +44 -44
  600. package/dist/extensions/question/types.ts +132 -132
  601. package/dist/extensions/test-resolve-hook-impl.mjs +6 -6
  602. package/dist/extensions/test-resolve-hook.mjs +6 -6
  603. package/dist/extensions/web-agent-onboarding.ts +222 -222
  604. package/dist/extensions/workflow/package.json +17 -17
  605. package/dist/package-manager-cli.js +71 -71
  606. package/dist/rpc-entry.js +0 -0
  607. package/dist/skills/agent-browser/SKILL.md +52 -52
  608. package/dist/skills/batch-grill-me/SKILL.md +19 -19
  609. package/dist/skills/brandkit/SKILL.md +799 -0
  610. package/dist/skills/design-taste-frontend/SKILL.md +1207 -0
  611. package/dist/skills/design-taste-frontend-v1/SKILL.md +227 -0
  612. package/dist/skills/full-output-enforcement/SKILL.md +50 -0
  613. package/dist/skills/gpt-taste/SKILL.md +75 -0
  614. package/dist/skills/grill-me/SKILL.md +10 -10
  615. package/dist/skills/handoff/SKILL.md +16 -16
  616. package/dist/skills/handoff-text/SKILL.md +14 -14
  617. package/dist/skills/high-end-visual-design/SKILL.md +99 -0
  618. package/dist/skills/image-to-code/SKILL.md +1229 -0
  619. package/dist/skills/imagegen-frontend-mobile/SKILL.md +1466 -0
  620. package/dist/skills/imagegen-frontend-web/SKILL.md +988 -0
  621. package/dist/skills/implanger/SKILL.md +69 -69
  622. package/dist/skills/improve-codebase/REFERENCE.md +78 -78
  623. package/dist/skills/improve-codebase/SKILL.md +178 -178
  624. package/dist/skills/industrial-brutalist-ui/SKILL.md +93 -0
  625. package/dist/skills/minimalist-ui/SKILL.md +86 -0
  626. package/dist/skills/pi-subagents/SKILL.md +18 -17
  627. package/dist/skills/pi-subagents/references/constraints-and-recipes.md +31 -9
  628. package/dist/skills/pi-subagents/references/execution-controls.md +95 -143
  629. package/dist/skills/pi-subagents/references/management-authoring-rpc.md +9 -12
  630. package/dist/skills/pi-subagents/references/multi-lane-orchestration.md +39 -0
  631. package/dist/skills/pi-subagents/references/prompting-and-roles.md +45 -94
  632. package/dist/skills/planger/SKILL.md +166 -166
  633. package/dist/skills/ponytail/SKILL.md +120 -116
  634. package/dist/skills/ponytail-audit/SKILL.md +41 -42
  635. package/dist/skills/ponytail-debt/SKILL.md +44 -45
  636. package/dist/skills/ponytail-gain/SKILL.md +50 -51
  637. package/dist/skills/ponytail-help/SKILL.md +71 -70
  638. package/dist/skills/ponytail-review/SKILL.md +57 -58
  639. package/dist/skills/redesign-existing-projects/SKILL.md +179 -0
  640. package/dist/skills/selesai-handoff/SKILL.md +20 -20
  641. package/dist/skills/stitch-design-taste/SKILL.md +185 -0
  642. package/dist/skills/unlazy/CHANGELOG.md +100 -0
  643. package/dist/skills/unlazy/CONTRIBUTING.md +66 -0
  644. package/dist/skills/unlazy/LICENSE +21 -0
  645. package/dist/skills/unlazy/README.md +242 -0
  646. package/dist/skills/unlazy/SECURITY.md +70 -0
  647. package/dist/skills/unlazy/SKILL.md +100 -0
  648. package/dist/skills/unlazy/package.json +13 -0
  649. package/dist/skills/unlazy/references/dispatch.md +82 -0
  650. package/dist/skills/unlazy/references/gates.md +132 -0
  651. package/dist/skills/unlazy/references/method.md +49 -0
  652. package/dist/skills/unlazy/references/orchestration.md +99 -0
  653. package/dist/skills/unlazy/references/parallel.md +123 -0
  654. package/dist/skills/unlazy/references/token-economy.md +39 -0
  655. package/dist/skills/unlazy/research/validation-protocol.md +81 -0
  656. package/dist/skills/unlazy/scripts/dispatch-check.mjs +108 -0
  657. package/dist/skills/unlazy/scripts/gate-check.mjs +894 -0
  658. package/dist/skills/unlazy/scripts/gate-lint.mjs +178 -0
  659. package/dist/skills/unlazy/scripts/install-hooks.mjs +206 -0
  660. package/dist/skills/unlazy/scripts/lib/check-supervisor.mjs +46 -0
  661. package/dist/skills/unlazy/scripts/lib/dispatch.mjs +283 -0
  662. package/dist/skills/unlazy/scripts/lib/gates.mjs +629 -0
  663. package/dist/skills/unlazy/scripts/lib/process-tree.mjs +161 -0
  664. package/dist/skills/unlazy/scripts/lib/regex-worker.mjs +9 -0
  665. package/dist/skills/unlazy/scripts/stop-hook.mjs +174 -0
  666. package/dist/skills/unlazy/templates/PLAN.md +65 -0
  667. package/dist/skills/unlazy/templates/gates-leaf.md +51 -0
  668. package/dist/skills/unlazy/templates/gates-node.md +50 -0
  669. package/dist/skills/unlazy/tests/contract-tests.mjs +127 -0
  670. package/dist/skills/unlazy/tests/dispatch-tests.mjs +481 -0
  671. package/dist/skills/unlazy/tests/hardening-tests.mjs +903 -0
  672. package/dist/skills/unlazy/tests/lint-tests.mjs +242 -0
  673. package/dist/skills/unlazy/tests/run-tests.mjs +554 -0
  674. package/dist/skills/unlazy/tests/self-check.mjs +165 -0
  675. package/dist/skills/unlazy/tests/stress-tests.mjs +356 -0
  676. package/dist/skills/web-design-guidelines/SKILL.md +40 -0
  677. package/dist/skills/workflow-creation/SKILL.md +73 -73
  678. package/dist/themes/powerline-footer/theme.json +33 -33
  679. package/dist/utils/shell.d.ts +3 -0
  680. package/dist/utils/shell.js +17 -5
  681. package/docs/compaction.md +396 -396
  682. package/docs/containerization.md +111 -111
  683. package/docs/development.md +71 -71
  684. package/docs/docs.json +164 -164
  685. package/docs/environment-variables.md +86 -86
  686. package/docs/index.md +83 -83
  687. package/docs/json.md +82 -82
  688. package/docs/models.md +502 -502
  689. package/docs/packages.md +227 -227
  690. package/docs/plans/subagent-delegation/phase-0-correctness.md +264 -264
  691. package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +485 -485
  692. package/docs/plans/subagent-delegation/phase-2-context-controls.md +281 -281
  693. package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +361 -361
  694. package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +380 -380
  695. package/docs/prompt-templates.md +95 -95
  696. package/docs/providers.md +293 -293
  697. package/docs/sdk.md +1144 -1143
  698. package/docs/security.md +59 -59
  699. package/docs/session-format.md +414 -414
  700. package/docs/sessions.md +145 -145
  701. package/docs/settings.md +0 -5
  702. package/docs/shared-host-extensions.md +109 -109
  703. package/docs/shell-aliases.md +13 -13
  704. package/docs/skills.md +231 -231
  705. package/docs/terminal-setup.md +142 -142
  706. package/docs/termux.md +127 -127
  707. package/docs/themes.md +295 -295
  708. package/docs/tmux.md +63 -63
  709. package/docs/tui.md +927 -927
  710. package/docs/windows.md +17 -17
  711. package/examples/README.md +25 -25
  712. package/examples/extensions/README.md +211 -211
  713. package/examples/extensions/auto-commit-on-exit.ts +49 -49
  714. package/examples/extensions/bash-spawn-hook.ts +30 -30
  715. package/examples/extensions/bookmark.ts +50 -50
  716. package/examples/extensions/border-status-editor.ts +150 -150
  717. package/examples/extensions/built-in-tool-renderer.ts +249 -249
  718. package/examples/extensions/claude-rules.ts +86 -86
  719. package/examples/extensions/commands.ts +72 -72
  720. package/examples/extensions/confirm-destructive.ts +59 -59
  721. package/examples/extensions/custom-compaction.ts +130 -130
  722. package/examples/extensions/custom-footer.ts +64 -64
  723. package/examples/extensions/custom-header.ts +73 -73
  724. package/examples/extensions/custom-provider-anthropic/index.ts +610 -610
  725. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -24
  726. package/examples/extensions/custom-provider-anthropic/package.json +19 -19
  727. package/examples/extensions/custom-provider-gitlab-duo/index.ts +404 -404
  728. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -16
  729. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -82
  730. package/examples/extensions/dirty-repo-guard.ts +56 -56
  731. package/examples/extensions/doom-overlay/README.md +46 -46
  732. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -21
  733. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  734. package/examples/extensions/doom-overlay/doom/build.sh +152 -152
  735. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -72
  736. package/examples/extensions/doom-overlay/doom-component.ts +132 -132
  737. package/examples/extensions/doom-overlay/doom-engine.ts +173 -173
  738. package/examples/extensions/doom-overlay/doom-keys.ts +104 -104
  739. package/examples/extensions/doom-overlay/index.ts +74 -74
  740. package/examples/extensions/doom-overlay/wad-finder.ts +51 -51
  741. package/examples/extensions/dynamic-resources/SKILL.md +8 -8
  742. package/examples/extensions/dynamic-resources/dynamic.json +79 -79
  743. package/examples/extensions/dynamic-resources/dynamic.md +5 -5
  744. package/examples/extensions/dynamic-resources/index.ts +15 -15
  745. package/examples/extensions/dynamic-tools.ts +74 -74
  746. package/examples/extensions/event-bus.ts +43 -43
  747. package/examples/extensions/file-trigger.ts +41 -41
  748. package/examples/extensions/git-checkpoint.ts +53 -53
  749. package/examples/extensions/git-merge-and-resolve.ts +115 -115
  750. package/examples/extensions/github-issue-autocomplete.ts +185 -185
  751. package/examples/extensions/gondolin/index.ts +531 -531
  752. package/examples/extensions/gondolin/package-lock.json +185 -185
  753. package/examples/extensions/gondolin/package.json +19 -19
  754. package/examples/extensions/handoff.ts +199 -199
  755. package/examples/extensions/hello.ts +26 -26
  756. package/examples/extensions/hidden-thinking-label.ts +53 -53
  757. package/examples/extensions/inline-bash.ts +94 -94
  758. package/examples/extensions/input-transform-streaming.ts +39 -39
  759. package/examples/extensions/input-transform.ts +43 -43
  760. package/examples/extensions/interactive-shell.ts +196 -196
  761. package/examples/extensions/mac-system-theme.ts +47 -47
  762. package/examples/extensions/message-renderer.ts +59 -59
  763. package/examples/extensions/minimal-mode.ts +426 -426
  764. package/examples/extensions/modal-editor.ts +85 -85
  765. package/examples/extensions/model-status.ts +31 -31
  766. package/examples/extensions/notify.ts +55 -55
  767. package/examples/extensions/overlay-qa-tests.ts +1450 -1450
  768. package/examples/extensions/overlay-test.ts +153 -153
  769. package/examples/extensions/permission-gate.ts +34 -34
  770. package/examples/extensions/pirate.ts +47 -47
  771. package/examples/extensions/plan-mode/README.md +66 -66
  772. package/examples/extensions/plan-mode/index.ts +390 -390
  773. package/examples/extensions/plan-mode/utils.ts +168 -168
  774. package/examples/extensions/preset.ts +436 -436
  775. package/examples/extensions/project-trust.ts +64 -64
  776. package/examples/extensions/prompt-customizer.ts +97 -97
  777. package/examples/extensions/protected-paths.ts +30 -30
  778. package/examples/extensions/provider-payload.ts +18 -18
  779. package/examples/extensions/qna.ts +122 -122
  780. package/examples/extensions/question.ts +285 -285
  781. package/examples/extensions/questionnaire.ts +448 -448
  782. package/examples/extensions/rainbow-editor.ts +88 -88
  783. package/examples/extensions/reload-runtime.ts +37 -37
  784. package/examples/extensions/rpc-demo.ts +118 -118
  785. package/examples/extensions/sandbox/index.ts +321 -321
  786. package/examples/extensions/sandbox/package-lock.json +92 -92
  787. package/examples/extensions/sandbox/package.json +19 -19
  788. package/examples/extensions/send-user-message.ts +97 -97
  789. package/examples/extensions/session-name.ts +27 -27
  790. package/examples/extensions/shutdown-command.ts +63 -63
  791. package/examples/extensions/snake.ts +343 -343
  792. package/examples/extensions/space-invaders.ts +560 -560
  793. package/examples/extensions/ssh.ts +220 -220
  794. package/examples/extensions/status-line.ts +32 -32
  795. package/examples/extensions/structured-output.ts +65 -65
  796. package/examples/extensions/subagent/README.md +175 -175
  797. package/examples/extensions/subagent/agents/planner.md +37 -37
  798. package/examples/extensions/subagent/agents/reviewer.md +35 -35
  799. package/examples/extensions/subagent/agents/scout.md +50 -50
  800. package/examples/extensions/subagent/agents/worker.md +24 -24
  801. package/examples/extensions/subagent/agents.ts +126 -126
  802. package/examples/extensions/subagent/index.ts +1015 -1015
  803. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -10
  804. package/examples/extensions/subagent/prompts/implement.md +10 -10
  805. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -9
  806. package/examples/extensions/summarize.ts +209 -209
  807. package/examples/extensions/system-prompt-header.ts +17 -17
  808. package/examples/extensions/tic-tac-toe.ts +1008 -1008
  809. package/examples/extensions/timed-confirm.ts +70 -70
  810. package/examples/extensions/titlebar-spinner.ts +58 -58
  811. package/examples/extensions/todo.ts +297 -297
  812. package/examples/extensions/tool-override.ts +144 -144
  813. package/examples/extensions/tools.ts +146 -146
  814. package/examples/extensions/trigger-compact.ts +50 -50
  815. package/examples/extensions/truncated-tool.ts +195 -195
  816. package/examples/extensions/widget-placement.ts +9 -9
  817. package/examples/extensions/with-deps/index.ts +32 -32
  818. package/examples/extensions/with-deps/package-lock.json +31 -31
  819. package/examples/extensions/with-deps/package.json +22 -22
  820. package/examples/extensions/working-indicator.ts +123 -123
  821. package/examples/extensions/working-message-test.ts +25 -25
  822. package/examples/rpc-extension-ui.ts +632 -632
  823. package/examples/sdk/01-minimal.ts +26 -26
  824. package/examples/sdk/02-custom-model.ts +53 -53
  825. package/examples/sdk/03-custom-prompt.ts +75 -75
  826. package/examples/sdk/04-skills.ts +55 -55
  827. package/examples/sdk/05-tools.ts +48 -48
  828. package/examples/sdk/06-extensions.ts +99 -99
  829. package/examples/sdk/07-context-files.ts +47 -47
  830. package/examples/sdk/08-prompt-templates.ts +51 -51
  831. package/examples/sdk/09-api-keys-and-oauth.ts +52 -52
  832. package/examples/sdk/10-settings.ts +53 -53
  833. package/examples/sdk/11-sessions.ts +52 -52
  834. package/examples/sdk/12-full-control.ts +79 -79
  835. package/examples/sdk/13-session-runtime.ts +67 -67
  836. package/examples/sdk/README.md +144 -144
  837. package/package.json +4 -4
  838. package/dist/core/tools/schema-prune.d.ts +0 -16
  839. package/dist/core/tools/schema-prune.js +0 -39
  840. package/dist/core/tools/schema-prune.test.js +0 -111
  841. package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +0 -172
  842. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +0 -55
  843. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +0 -61
  844. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +0 -132
  845. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +0 -181
  846. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +0 -1354
  847. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +0 -1581
  848. package/dist/extensions/pi-subagents/src/shared/env.ts +0 -16
  849. package/dist/extensions/pi-subagents/src/shared/session-lineage.ts +0 -71
  850. package/dist/extensions/pi-subagents/src/slash/inline-subagents.ts +0 -136
  851. package/dist/extensions/pi-subagents/src/workflows/workflow-auto-relaunch.ts +0 -41
  852. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +0 -466
  853. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +0 -1859
  854. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +0 -733
  855. package/dist/extensions/pi-subagents/test/unit/builtin-agent-documentation.test.ts +0 -63
  856. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +0 -326
  857. package/dist/extensions/pi-subagents/test/unit/handoff-adoption.test.ts +0 -103
  858. package/dist/extensions/pi-subagents/test/unit/inline-subagents.test.ts +0 -127
  859. package/dist/extensions/pi-subagents/test/unit/session-lineage.test.ts +0 -73
  860. package/dist/extensions/pi-subagents/test/unit/task-aware-routing.test.ts +0 -213
  861. package/dist/extensions/pi-subagents/test/unit/workflow-auto-relaunch.test.ts +0 -65
  862. /package/dist/core/{tools/schema-prune.test.d.ts → extensions/loader.test.d.ts} +0 -0
@@ -1,7 +1,7 @@
1
1
  import net from "net";
2
- import { writeFileSync, unlinkSync } from "fs";
2
+ import { chmodSync, mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
3
3
  import { join } from "path";
4
- import { randomUUID } from "crypto";
4
+ import { createHash, randomUUID } from "crypto";
5
5
  import { writeMessage, createMessageReader } from "./framing.ts";
6
6
  import { isMessage, isMessageReceipt, isSessionId, isSessionRegistration } from "./protocol.ts";
7
7
  import {
@@ -9,6 +9,7 @@ import {
9
9
  getBrokerListenTarget,
10
10
  getBrokerPortFilePath,
11
11
  getIntercomDirPath,
12
+ INTERCOM_DIR_MODE,
12
13
  INTERCOM_PROTOCOL_NAME,
13
14
  INTERCOM_PROTOCOL_VERSION,
14
15
  INTERCOM_RUNTIME_FILE_MODE,
@@ -17,8 +18,8 @@ import {
17
18
  } from "./paths.ts";
18
19
  import { getAskTimeoutMs } from "../config.ts";
19
20
  import { sameCwd } from "../cwd.ts";
20
- import { EXTENSION_BUS_FEATURE } from "../types.ts";
21
- import type { SessionInfo, Message, BrokerMessage, ExtensionCapability, MessageControl } from "../types.ts";
21
+ import { EXACT_SEND_FEATURE, EXTENSION_BUS_FEATURE } from "../types.ts";
22
+ import type { DeliveryState, SessionInfo, Message, BrokerMessage, ExtensionCapability, MessageControl } from "../types.ts";
22
23
  import { ExtensionStateManager } from "./extension-state.ts";
23
24
  import { assertNoLiveBroker } from "./runtime-claim.ts";
24
25
 
@@ -26,6 +27,7 @@ const INTERCOM_DIR = getIntercomDirPath();
26
27
  const LISTEN_TARGET = getBrokerListenTarget();
27
28
  const PID_PATH = join(INTERCOM_DIR, "broker.pid");
28
29
  const PORT_PATH = getBrokerPortFilePath(INTERCOM_DIR);
30
+ const PENDING_ASKS_DIR = join(INTERCOM_DIR, "pending-asks");
29
31
  const BROKER_STATE_ID = randomUUID();
30
32
  const MAX_SESSIONS = 128;
31
33
  const MAX_UNREGISTERED_CONNECTIONS = 32;
@@ -40,6 +42,8 @@ const MESSAGE_RECEIPT_ROUTE_RETENTION_MS = 60 * 60 * 1000;
40
42
  const DISCONNECTED_SESSION_RETENTION_MS = 24 * 60 * 60 * 1000;
41
43
  const MAILBOX_MESSAGE_RETENTION_MS = 24 * 60 * 60 * 1000;
42
44
  const MAX_MAILBOX_MESSAGES = 256;
45
+ const DELIVERY_RECORD_RETENTION_MS = 60 * 60 * 1000;
46
+ const MAX_DELIVERY_RECORDS = 4096;
43
47
 
44
48
  function serializedPayloadSize(payload: unknown): number | null {
45
49
  try {
@@ -53,15 +57,30 @@ function serializedPayloadSize(payload: unknown): number | null {
53
57
  interface ConnectedSession {
54
58
  socket: net.Socket;
55
59
  info: SessionInfo;
60
+ key: string;
61
+ scopeId?: string;
56
62
  lastPresenceBroadcastAt: number;
57
63
  ownerOrder: number;
58
64
  extensions?: ExtensionCapability[];
59
65
  }
60
66
 
67
+ interface DeliveryRecord {
68
+ fingerprint: string;
69
+ state: DeliveryState;
70
+ reason?: string;
71
+ code?: string;
72
+ retryable: boolean;
73
+ outcomeKnown: boolean;
74
+ createdAt: number;
75
+ }
76
+
61
77
  interface NamespaceOwner {
78
+ namespace: string;
79
+ sessionKey: string;
62
80
  sessionId: string;
63
81
  socket: net.Socket;
64
82
  epoch: string;
83
+ scopeId?: string;
65
84
  }
66
85
 
67
86
  interface ConnectionState {
@@ -73,9 +92,20 @@ interface ConnectionState {
73
92
  interface AskEdge {
74
93
  from: string;
75
94
  to: string;
95
+ scopeId?: string;
76
96
  createdAt: number;
77
97
  }
78
98
 
99
+ interface PendingAskRecord {
100
+ askId: string;
101
+ messageId: string;
102
+ asker: { sessionId: string; name: string | null };
103
+ target: { sessionId: string; name: string | null };
104
+ question: string;
105
+ createdAt: number;
106
+ expiresAt: number;
107
+ }
108
+
79
109
  interface MessageReceiptRoute {
80
110
  from: string;
81
111
  to: string;
@@ -84,22 +114,98 @@ interface MessageReceiptRoute {
84
114
 
85
115
  interface DisconnectedSession {
86
116
  info: SessionInfo;
117
+ key: string;
118
+ scopeId?: string;
87
119
  disconnectedAt: number;
88
120
  }
89
121
 
90
122
  interface MailboxMessage {
91
123
  from: SessionInfo;
124
+ fromKey: string;
125
+ fromScopeId?: string;
92
126
  target: SessionInfo;
127
+ targetKey: string;
128
+ targetScopeId?: string;
93
129
  message: Message;
94
130
  queuedAt: number;
95
131
  }
96
132
 
133
+ function normalizeScopeId(value: unknown): string | undefined {
134
+ if (value === undefined) {
135
+ return undefined;
136
+ }
137
+ if (typeof value !== "string") {
138
+ throw new Error("Invalid register scopeId");
139
+ }
140
+ const trimmed = value.trim();
141
+ return trimmed ? trimmed : undefined;
142
+ }
143
+
144
+ function sameScope(a: string | undefined, b: string | undefined): boolean {
145
+ return a === b;
146
+ }
147
+
148
+ function scopedSessionKey(scopeId: string | undefined, sessionId: string): string {
149
+ return JSON.stringify([scopeId ?? null, sessionId]);
150
+ }
151
+
152
+ function scopedExtensionKey(scopeId: string | undefined, namespace: string): string {
153
+ return JSON.stringify([scopeId ?? null, namespace]);
154
+ }
155
+
156
+ function scopedExtensionStateNamespace(scopeId: string | undefined, namespace: string): string {
157
+ if (!scopeId) {
158
+ return namespace;
159
+ }
160
+ return JSON.stringify(["scope", createHash("sha256").update(scopeId).digest("hex"), namespace]);
161
+ }
162
+
163
+ function scopedPendingAskRecordPath(scopeId: string | undefined, messageId: string): string {
164
+ if (!scopeId) {
165
+ return pendingAskRecordPath(messageId);
166
+ }
167
+ const scopeHash = createHash("sha256").update(scopeId).digest("hex");
168
+ return join(PENDING_ASKS_DIR, `${scopeHash}-${encodeURIComponent(messageId)}.json`);
169
+ }
170
+
171
+ function isRecord(value: unknown): value is Record<string, unknown> {
172
+ return typeof value === "object" && value !== null && !Array.isArray(value);
173
+ }
174
+
175
+ function isPendingAskRecord(value: unknown): value is PendingAskRecord {
176
+ if (!isRecord(value) || !isRecord(value.asker) || !isRecord(value.target)) {
177
+ return false;
178
+ }
179
+ return typeof value.askId === "string"
180
+ && typeof value.messageId === "string"
181
+ && typeof value.asker.sessionId === "string"
182
+ && (typeof value.asker.name === "string" || value.asker.name === null)
183
+ && typeof value.target.sessionId === "string"
184
+ && (typeof value.target.name === "string" || value.target.name === null)
185
+ && typeof value.question === "string"
186
+ && Number.isSafeInteger(value.createdAt)
187
+ && Number.isSafeInteger(value.expiresAt)
188
+ && value.expiresAt >= value.createdAt;
189
+ }
190
+
191
+ function pendingAskRecordPath(messageId: string): string {
192
+ return join(PENDING_ASKS_DIR, `${encodeURIComponent(messageId)}.json`);
193
+ }
194
+
195
+ function ensurePendingAskRecordDir(): void {
196
+ mkdirSync(PENDING_ASKS_DIR, { recursive: true, mode: INTERCOM_DIR_MODE });
197
+ if (process.platform !== "win32") {
198
+ chmodSync(PENDING_ASKS_DIR, INTERCOM_DIR_MODE);
199
+ }
200
+ }
201
+
97
202
  class IntercomBroker {
98
203
  private sessions = new Map<string, ConnectedSession>();
99
204
  private askEdges = new Map<string, AskEdge>();
100
205
  private messageReceiptRoutes = new Map<string, MessageReceiptRoute>();
101
206
  private disconnectedSessions = new Map<string, DisconnectedSession>();
102
207
  private mailboxMessages: MailboxMessage[] = [];
208
+ private deliveryRecords = new Map<string, DeliveryRecord>();
103
209
  private connections = new Set<net.Socket>();
104
210
  private unregisteredConnections = new Set<net.Socket>();
105
211
  private server: net.Server;
@@ -112,6 +218,8 @@ class IntercomBroker {
112
218
  constructor() {
113
219
  ensureIntercomRuntimeDir(INTERCOM_DIR);
114
220
  assertNoLiveBroker(PID_PATH);
221
+ ensurePendingAskRecordDir();
222
+ this.prunePendingAskRecords();
115
223
  this.extensionStateManager = new ExtensionStateManager(INTERCOM_DIR);
116
224
  if (typeof LISTEN_TARGET === "string" && process.platform !== "win32") {
117
225
  try {
@@ -157,7 +265,7 @@ class IntercomBroker {
157
265
 
158
266
  private handleConnection(socket: net.Socket): void {
159
267
  this.connections.add(socket);
160
- let sessionId: string | null = null;
268
+ let sessionKey: string | null = null;
161
269
  let registrationTimeout: NodeJS.Timeout | null = null;
162
270
  const armRegistrationTimeout = () => {
163
271
  if (registrationTimeout) {
@@ -167,7 +275,7 @@ class IntercomBroker {
167
275
  this.unregisteredConnections.add(socket);
168
276
  this.evictOldestUnregisteredConnections(socket);
169
277
  registrationTimeout = setTimeout(() => {
170
- if (!sessionId) {
278
+ if (!sessionKey) {
171
279
  socket.destroy();
172
280
  }
173
281
  }, REGISTRATION_TIMEOUT_MS);
@@ -193,8 +301,8 @@ class IntercomBroker {
193
301
  socket.destroy(new Error("Intercom broker rate limit exceeded"));
194
302
  return;
195
303
  }
196
- this.handleMessage(socket, msg, sessionId, (id) => {
197
- sessionId = id;
304
+ this.handleMessage(socket, msg, sessionKey, (id) => {
305
+ sessionKey = id;
198
306
  if (id) {
199
307
  clearRegistrationTimeout();
200
308
  } else {
@@ -210,13 +318,13 @@ class IntercomBroker {
210
318
  socket.on("close", () => {
211
319
  clearRegistrationTimeout();
212
320
  this.connections.delete(socket);
213
- if (sessionId) {
214
- const existing = this.sessions.get(sessionId);
321
+ if (sessionKey) {
322
+ const existing = this.sessions.get(sessionKey);
215
323
  if (existing?.socket === socket) {
216
- this.rememberDisconnectedSession(existing.info);
217
- this.sessions.delete(sessionId);
218
- this.clearMessageReceiptRoutesForSession(sessionId);
219
- this.broadcast({ type: "session_left", sessionId }, sessionId);
324
+ this.rememberDisconnectedSession(existing);
325
+ this.sessions.delete(sessionKey);
326
+ this.clearMessageReceiptRoutesForSession(sessionKey);
327
+ this.broadcast({ type: "session_left", sessionId: existing.info.id }, sessionKey, existing.scopeId);
220
328
  this.recomputeNamespaceOwners();
221
329
  this.scheduleShutdownCheck();
222
330
  }
@@ -273,8 +381,8 @@ class IntercomBroker {
273
381
  private handleMessage(
274
382
  socket: net.Socket,
275
383
  msg: unknown,
276
- currentId: string | null,
277
- setId: (id: string | null) => void,
384
+ currentKey: string | null,
385
+ setKey: (key: string | null) => void,
278
386
  ): void {
279
387
  if (typeof msg !== "object" || msg === null || !("type" in msg) || typeof msg.type !== "string") {
280
388
  throw new Error("Invalid client message");
@@ -304,7 +412,7 @@ class IntercomBroker {
304
412
  throw new Error("Invalid intercom TCP endpoint credentials");
305
413
  }
306
414
 
307
- if (currentId === null && clientMessage.type !== "register") {
415
+ if (currentKey === null && clientMessage.type !== "register") {
308
416
  throw new Error(`Received ${clientMessage.type} before register`);
309
417
  }
310
418
 
@@ -314,7 +422,7 @@ class IntercomBroker {
314
422
  throw new Error("Invalid register message");
315
423
  }
316
424
 
317
- if (currentId) {
425
+ if (currentKey) {
318
426
  throw new Error("Received duplicate register message");
319
427
  }
320
428
 
@@ -325,6 +433,8 @@ class IntercomBroker {
325
433
  }
326
434
  id = clientMessage.sessionId;
327
435
  }
436
+ const scopeId = normalizeScopeId(clientMessage.scopeId);
437
+ const key = scopedSessionKey(scopeId, id);
328
438
  const session = clientMessage.session;
329
439
  const extensions = session.extensions;
330
440
  if (extensions !== undefined) {
@@ -340,20 +450,20 @@ class IntercomBroker {
340
450
 
341
451
  this.pruneDisconnectedSessions();
342
452
  this.pruneMailboxMessages();
343
- const previous = this.sessions.get(id);
453
+ const previous = this.sessions.get(key);
344
454
  if (!previous && this.sessions.size >= MAX_SESSIONS) {
345
455
  writeMessage(socket, { type: "error", error: "Too many registered intercom sessions" });
346
456
  socket.destroy();
347
457
  break;
348
458
  }
349
459
  if (previous) {
350
- this.clearAskEdgesForSession(id);
351
- this.clearMessageReceiptRoutesForSession(id);
460
+ this.clearMessageReceiptRoutesForSession(key);
352
461
  previous.socket.end();
353
462
  }
354
- setId(id);
463
+ setKey(key);
355
464
  const info: SessionInfo = {
356
465
  id,
466
+ endpointEpoch: randomUUID(),
357
467
  ...(session.name !== undefined ? { name: session.name } : {}),
358
468
  ...(session.runtimeFallbackAlias !== undefined ? { runtimeFallbackAlias: session.runtimeFallbackAlias } : {}),
359
469
  cwd: session.cwd,
@@ -362,18 +472,21 @@ class IntercomBroker {
362
472
  startedAt: session.startedAt,
363
473
  lastActivity: session.lastActivity,
364
474
  ...(session.status !== undefined ? { status: session.status } : {}),
475
+ ...(session.tmuxPane !== undefined ? { tmuxPane: session.tmuxPane } : {}),
365
476
  trustedLocal: typeof LISTEN_TARGET === "string" && process.platform !== "win32",
366
477
  };
367
478
 
368
479
  const connectedSession: ConnectedSession = {
369
480
  socket,
370
481
  info,
482
+ key,
483
+ ...(scopeId ? { scopeId } : {}),
371
484
  lastPresenceBroadcastAt: Date.now(),
372
485
  ownerOrder: previous?.ownerOrder ?? this.nextOwnerOrder++,
373
486
  extensions,
374
487
  };
375
- this.sessions.set(id, connectedSession);
376
- this.disconnectedSessions.delete(id);
488
+ this.sessions.set(key, connectedSession);
489
+ this.disconnectedSessions.delete(key);
377
490
 
378
491
  if (this.shutdownTimer) {
379
492
  clearTimeout(this.shutdownTimer);
@@ -386,22 +499,22 @@ class IntercomBroker {
386
499
  writeMessage(socket, {
387
500
  type: "registered",
388
501
  sessionId: id,
389
- features: [EXTENSION_BUS_FEATURE],
502
+ features: [EXTENSION_BUS_FEATURE, EXACT_SEND_FEATURE],
390
503
  });
391
- this.broadcast({ type: "session_joined", session: info }, id);
504
+ this.broadcast({ type: "session_joined", session: info }, key, scopeId);
392
505
 
393
506
  this.recomputeNamespaceOwners();
394
507
  this.flushMailboxForSession(connectedSession);
395
508
 
396
509
  if (extensions) {
397
510
  for (const ext of extensions) {
398
- const owner = this.namespaceOwners.get(ext.namespace);
511
+ const owner = this.namespaceOwners.get(scopedExtensionKey(scopeId, ext.namespace));
399
512
  writeMessage(socket, {
400
513
  type: "extension_owner",
401
514
  namespace: ext.namespace,
402
515
  ...(owner ? { ownerId: owner.sessionId, ownerEpoch: owner.epoch } : {}),
403
516
  });
404
- const state = this.extensionStateManager.loadState(ext.namespace);
517
+ const state = this.extensionStateManager.loadState(scopedExtensionStateNamespace(scopeId, ext.namespace));
405
518
  if (state) {
406
519
  writeMessage(socket, {
407
520
  type: "extension_state",
@@ -416,27 +529,27 @@ class IntercomBroker {
416
529
  }
417
530
 
418
531
  case "unregister": {
419
- if (!currentId) {
532
+ if (!currentKey) {
420
533
  throw new Error("Received unregister before register");
421
534
  }
422
- const existing = this.sessions.get(currentId);
535
+ const existing = this.sessions.get(currentKey);
423
536
  if (existing?.socket === socket) {
424
- this.rememberDisconnectedSession(existing.info);
425
- this.sessions.delete(currentId);
426
- this.clearMessageReceiptRoutesForSession(currentId);
427
- this.broadcast({ type: "session_left", sessionId: currentId }, currentId);
537
+ this.rememberDisconnectedSession(existing);
538
+ this.sessions.delete(currentKey);
539
+ this.clearMessageReceiptRoutesForSession(currentKey);
540
+ this.broadcast({ type: "session_left", sessionId: existing.info.id }, currentKey, existing.scopeId);
428
541
  this.recomputeNamespaceOwners();
429
542
  this.scheduleShutdownCheck();
430
543
  }
431
- setId(null);
544
+ setKey(null);
432
545
  break;
433
546
  }
434
547
 
435
548
  case "extension_capabilities_update": {
436
- if (!currentId) {
549
+ if (!currentKey) {
437
550
  throw new Error("Received extension_capabilities_update before register");
438
551
  }
439
- const session = this.sessions.get(currentId);
552
+ const session = this.sessions.get(currentKey);
440
553
  if (!session || session.socket !== socket) {
441
554
  throw new Error("Extension capability session not found");
442
555
  }
@@ -452,13 +565,13 @@ class IntercomBroker {
452
565
  session.extensions = extensions;
453
566
  this.recomputeNamespaceOwners();
454
567
  for (const extension of extensions) {
455
- const owner = this.namespaceOwners.get(extension.namespace);
568
+ const owner = this.namespaceOwners.get(scopedExtensionKey(session.scopeId, extension.namespace));
456
569
  writeMessage(socket, {
457
570
  type: "extension_owner",
458
571
  namespace: extension.namespace,
459
572
  ...(owner ? { ownerId: owner.sessionId, ownerEpoch: owner.epoch } : {}),
460
573
  });
461
- const state = this.extensionStateManager.loadState(extension.namespace);
574
+ const state = this.extensionStateManager.loadState(scopedExtensionStateNamespace(session.scopeId, extension.namespace));
462
575
  if (state) {
463
576
  writeMessage(socket, {
464
577
  type: "extension_state",
@@ -476,24 +589,31 @@ class IntercomBroker {
476
589
  throw new Error("Invalid list message");
477
590
  }
478
591
 
479
- const sessions = Array.from(this.sessions.values()).map(s => s.info);
592
+ const requester = currentKey ? this.sessions.get(currentKey) : undefined;
593
+ if (!requester || requester.socket !== socket) {
594
+ throw new Error("List session not found");
595
+ }
596
+ const sessions = Array.from(this.sessions.values())
597
+ .filter(session => sameScope(session.scopeId, requester.scopeId))
598
+ .map(s => s.info);
480
599
  writeMessage(socket, { type: "sessions", requestId: clientMessage.requestId, sessions });
481
600
  break;
482
601
  }
483
602
 
484
603
  case "send": {
485
- if (!currentId) {
604
+ if (!currentKey) {
486
605
  throw new Error("Received send before register");
487
606
  }
488
607
  const message = clientMessage.message;
489
608
  const messageId = isMessage(message) ? message.id : "unknown";
490
609
 
491
610
  if (typeof clientMessage.to !== "string" || !isMessage(message)) {
492
- writeMessage(socket, {
493
- type: "delivery_failed",
494
- messageId,
495
- reason: "Invalid message format",
496
- });
611
+ this.writeDeliveryFailure(socket, messageId, "Invalid message format", "E_INVALID_MESSAGE");
612
+ break;
613
+ }
614
+ const fromSession = this.sessions.get(currentKey);
615
+ if (!fromSession || fromSession.socket !== socket) {
616
+ this.writeDeliveryFailure(socket, message.id, "Sender session not found", "E_SENDER_NOT_FOUND");
497
617
  break;
498
618
  }
499
619
 
@@ -502,56 +622,72 @@ class IntercomBroker {
502
622
  this.pruneMessageReceiptRoutes(brokerReceivedAt);
503
623
  const replyEdge = message.replyTo ? this.askEdges.get(message.replyTo) : undefined;
504
624
 
505
- const targets = this.findSessions(clientMessage.to);
625
+ const hasTargetId = clientMessage.targetId !== undefined;
626
+ const hasTargetEpoch = clientMessage.targetEpoch !== undefined;
627
+ if (
628
+ hasTargetId !== hasTargetEpoch
629
+ || (hasTargetId && (typeof clientMessage.targetId !== "string" || clientMessage.targetId.length === 0))
630
+ || (hasTargetEpoch && (typeof clientMessage.targetEpoch !== "string" || clientMessage.targetEpoch.length === 0))
631
+ ) {
632
+ this.writeDeliveryFailure(socket, message.id, "Exact target requires an id and endpoint epoch", "E_INVALID_TARGET");
633
+ break;
634
+ }
635
+ if (hasTargetId && hasTargetEpoch) {
636
+ const targetId = clientMessage.targetId as string;
637
+ const targetEpoch = clientMessage.targetEpoch as string;
638
+ const fingerprint = this.deliveryFingerprint(message, targetId);
639
+ if (this.replayOrReject(socket, currentKey, message.id, fingerprint)) {
640
+ break;
641
+ }
642
+ const exactTarget = this.sessions.get(scopedSessionKey(fromSession.scopeId, targetId));
643
+ if (!exactTarget) {
644
+ this.recordDelivery(currentKey, message.id, fingerprint, "failed", "Session not found", "E_TARGET_NOT_FOUND");
645
+ this.writeDeliveryFailure(socket, message.id, "Session not found", "E_TARGET_NOT_FOUND");
646
+ break;
647
+ }
648
+ if (exactTarget.info.endpointEpoch !== targetEpoch) {
649
+ this.recordDelivery(currentKey, message.id, fingerprint, "failed", "Target endpoint changed before delivery", "E_TARGET_REBOUND", true);
650
+ this.writeDeliveryFailure(socket, message.id, "Target endpoint changed before delivery", "E_TARGET_REBOUND", true);
651
+ break;
652
+ }
653
+ clientMessage.to = targetId;
654
+ }
655
+
656
+ const targets = this.findSessions(clientMessage.to, fromSession.scopeId);
506
657
  if (targets.length === 1) {
507
658
  if (message.replyTo && !replyEdge) {
508
- writeMessage(socket, {
509
- type: "delivery_failed",
510
- messageId: message.id,
511
- reason: "Reply target does not match a pending ask",
512
- });
659
+ this.writeDeliveryFailure(socket, message.id, "Reply target does not match a pending ask", "E_REPLY_TARGET");
513
660
  break;
514
661
  }
515
- const fromSession = this.sessions.get(currentId);
516
- if (!fromSession || fromSession.socket !== socket) {
517
- writeMessage(socket, {
518
- type: "delivery_failed",
519
- messageId: message.id,
520
- reason: "Sender session not found",
521
- });
662
+ const target = targets[0];
663
+ const fingerprint = this.deliveryFingerprint(message, target.info.id);
664
+ if (this.replayOrReject(socket, currentKey, message.id, fingerprint)) {
522
665
  break;
523
666
  }
524
- const target = targets[0];
525
667
  if (message.supersedes) {
526
668
  const supersededRoute = this.messageReceiptRoutes.get(message.supersedes);
527
- if (!supersededRoute || supersededRoute.from !== currentId || supersededRoute.to !== target.info.id) {
528
- writeMessage(socket, {
529
- type: "delivery_failed",
530
- messageId: message.id,
531
- reason: "Supersede target does not match a previous message from this sender to this receiver",
532
- });
669
+ if (!supersededRoute || supersededRoute.from !== currentKey || supersededRoute.to !== target.key) {
670
+ this.writeDeliveryFailure(socket, message.id, "Supersede target does not match a previous message from this sender to this receiver", "E_SUPERSEDE_TARGET");
533
671
  break;
534
672
  }
535
673
  }
536
- if (replyEdge && (replyEdge.to !== currentId || replyEdge.from !== target.info.id)) {
537
- writeMessage(socket, {
538
- type: "delivery_failed",
539
- messageId: message.id,
540
- reason: "Reply target does not match the pending ask",
541
- });
674
+ if (replyEdge && (replyEdge.to !== currentKey || replyEdge.from !== target.key)) {
675
+ this.writeDeliveryFailure(socket, message.id, "Reply target does not match the pending ask", "E_REPLY_TARGET");
542
676
  break;
543
677
  }
544
678
  if (message.expectsReply) {
545
- const reverseEdge = Array.from(this.askEdges.entries()).find(([edgeMessageId, edge]) => edgeMessageId !== message.replyTo && edge.from === target.info.id && edge.to === currentId);
679
+ const reverseEdge = Array.from(this.askEdges.entries()).find(([edgeMessageId, edge]) => edgeMessageId !== message.replyTo && edge.from === target.key && edge.to === currentKey);
546
680
  if (reverseEdge) {
547
- writeMessage(socket, {
548
- type: "delivery_failed",
549
- messageId: message.id,
550
- reason: "Mutual ask refused: target session is already waiting for a reply from this session.",
551
- });
681
+ this.writeDeliveryFailure(socket, message.id, "Mutual ask refused: target session is already waiting for a reply from this session.", "E_MUTUAL_ASK");
552
682
  break;
553
683
  }
554
- this.askEdges.set(message.id, { from: currentId, to: target.info.id, createdAt: Date.now() });
684
+ this.writePendingAskRecord(message, fromSession, target.info, brokerReceivedAt);
685
+ this.askEdges.set(message.id, {
686
+ from: currentKey,
687
+ to: target.key,
688
+ ...(fromSession.scopeId ? { scopeId: fromSession.scopeId } : {}),
689
+ createdAt: brokerReceivedAt,
690
+ });
555
691
  }
556
692
  const deliveredMessage: Message = {
557
693
  ...message,
@@ -570,6 +706,7 @@ class IntercomBroker {
570
706
  from: fromSession.info,
571
707
  control,
572
708
  });
709
+ this.updateDeliveryRecord(currentKey, message.supersedes, "failed", `Superseded by ${message.id}`, "E_DELIVERY_SUPERSEDED");
573
710
  }
574
711
  writeMessage(target.socket, {
575
712
  type: "message",
@@ -578,66 +715,44 @@ class IntercomBroker {
578
715
  });
579
716
  if (message.replyTo) {
580
717
  this.askEdges.delete(message.replyTo);
718
+ this.removePendingAskRecord(message.replyTo, fromSession.scopeId);
581
719
  }
582
- this.messageReceiptRoutes.set(message.id, { from: currentId, to: target.info.id, createdAt: brokerReceivedAt });
583
- writeMessage(socket, { type: "delivered", messageId: message.id });
720
+ this.messageReceiptRoutes.set(message.id, { from: currentKey, to: target.key, createdAt: brokerReceivedAt });
721
+ this.recordDelivery(currentKey, message.id, fingerprint, "socket_delivered");
722
+ this.writeDeliverySuccess(socket, message.id, "socket_delivered");
584
723
  break;
585
724
  }
586
725
 
587
726
  if (targets.length > 1) {
588
- writeMessage(socket, {
589
- type: "delivery_failed",
590
- messageId: message.id,
591
- reason: `Multiple sessions named \"${clientMessage.to}\" are connected. Use the session ID instead.`,
592
- });
727
+ this.writeDeliveryFailure(socket, message.id, `Multiple sessions named \"${clientMessage.to}\" are connected. Use the session ID instead.`, "E_AMBIGUOUS_TARGET");
593
728
  break;
594
729
  }
595
730
 
596
- const disconnectedTargets = this.findDisconnectedSessions(clientMessage.to);
731
+ const disconnectedTargets = this.findDisconnectedSessions(clientMessage.to, fromSession.scopeId);
597
732
  if (disconnectedTargets.length === 1) {
598
733
  if (message.replyTo && !replyEdge) {
599
- writeMessage(socket, {
600
- type: "delivery_failed",
601
- messageId: message.id,
602
- reason: "Reply target does not match a pending ask",
603
- });
734
+ this.writeDeliveryFailure(socket, message.id, "Reply target does not match a pending ask", "E_REPLY_TARGET");
604
735
  break;
605
736
  }
606
- const fromSession = this.sessions.get(currentId);
607
- if (!fromSession || fromSession.socket !== socket) {
608
- writeMessage(socket, {
609
- type: "delivery_failed",
610
- messageId: message.id,
611
- reason: "Sender session not found",
612
- });
737
+ const disconnectedTarget = disconnectedTargets[0]!;
738
+ const target = disconnectedTarget.info;
739
+ const fingerprint = this.deliveryFingerprint(message, target.id);
740
+ if (this.replayOrReject(socket, currentKey, message.id, fingerprint)) {
613
741
  break;
614
742
  }
615
- const target = disconnectedTargets[0]!.info;
616
743
  if (message.supersedes) {
617
- writeMessage(socket, {
618
- type: "delivery_failed",
619
- messageId: message.id,
620
- reason: "Supersede target is not connected",
621
- });
744
+ this.writeDeliveryFailure(socket, message.id, "Supersede target is not connected", "E_SUPERSEDE_TARGET");
622
745
  break;
623
746
  }
624
- if (replyEdge && (replyEdge.to !== currentId || replyEdge.from !== target.id)) {
625
- writeMessage(socket, {
626
- type: "delivery_failed",
627
- messageId: message.id,
628
- reason: "Reply target does not match the pending ask",
629
- });
747
+ if (replyEdge && (replyEdge.to !== currentKey || replyEdge.from !== disconnectedTarget.key)) {
748
+ this.writeDeliveryFailure(socket, message.id, "Reply target does not match the pending ask", "E_REPLY_TARGET");
630
749
  break;
631
750
  }
632
751
  if (message.expectsReply) {
633
- writeMessage(socket, {
634
- type: "delivery_failed",
635
- messageId: message.id,
636
- reason: "Target session is not currently connected; blocking asks are not queued",
637
- });
752
+ this.writeDeliveryFailure(socket, message.id, "Target session is not currently connected; blocking asks are not queued", "E_TARGET_DISCONNECTED");
638
753
  break;
639
754
  }
640
- const liveMailboxTarget = this.findUniqueLiveSessionForDisconnectedSession(target, currentId);
755
+ const liveMailboxTarget = this.findUniqueLiveSessionForDisconnectedSession(disconnectedTarget, currentKey);
641
756
  if (liveMailboxTarget) {
642
757
  const deliveredMessage: Message = {
643
758
  ...message,
@@ -649,36 +764,30 @@ class IntercomBroker {
649
764
  from: fromSession.info,
650
765
  message: deliveredMessage,
651
766
  });
652
- this.messageReceiptRoutes.set(message.id, { from: currentId, to: liveMailboxTarget.info.id, createdAt: brokerReceivedAt });
767
+ this.messageReceiptRoutes.set(message.id, { from: currentKey, to: liveMailboxTarget.key, createdAt: brokerReceivedAt });
653
768
  } else {
654
- this.queueMailboxMessage(fromSession.info, target, message, brokerReceivedAt);
769
+ this.queueMailboxMessage(fromSession, disconnectedTarget, message, brokerReceivedAt);
655
770
  }
656
771
  if (message.replyTo) {
657
772
  this.askEdges.delete(message.replyTo);
773
+ this.removePendingAskRecord(message.replyTo, fromSession.scopeId);
658
774
  }
659
- writeMessage(socket, { type: "delivered", messageId: message.id });
775
+ this.recordDelivery(currentKey, message.id, fingerprint, liveMailboxTarget ? "socket_delivered" : "queued");
776
+ this.writeDeliverySuccess(socket, message.id, liveMailboxTarget ? "socket_delivered" : "queued");
660
777
  break;
661
778
  }
662
779
 
663
780
  if (disconnectedTargets.length > 1) {
664
- writeMessage(socket, {
665
- type: "delivery_failed",
666
- messageId: message.id,
667
- reason: `Multiple disconnected sessions named \"${clientMessage.to}\" can receive queued mail. Use the session ID instead.`,
668
- });
781
+ this.writeDeliveryFailure(socket, message.id, `Multiple disconnected sessions named \"${clientMessage.to}\" can receive queued mail. Use the session ID instead.`, "E_AMBIGUOUS_TARGET");
669
782
  break;
670
783
  }
671
784
 
672
- writeMessage(socket, {
673
- type: "delivery_failed",
674
- messageId: message.id,
675
- reason: "Session not found",
676
- });
785
+ this.writeDeliveryFailure(socket, message.id, "Session not found", "E_TARGET_NOT_FOUND");
677
786
  break;
678
787
  }
679
788
 
680
789
  case "message_receipt": {
681
- if (!currentId) {
790
+ if (!currentKey) {
682
791
  throw new Error("Received message_receipt before register");
683
792
  }
684
793
  if (!isMessageReceipt(clientMessage.receipt)) {
@@ -686,9 +795,9 @@ class IntercomBroker {
686
795
  }
687
796
  this.pruneMessageReceiptRoutes();
688
797
  const route = this.messageReceiptRoutes.get(clientMessage.receipt.messageId);
689
- const receiver = this.sessions.get(currentId);
798
+ const receiver = this.sessions.get(currentKey);
690
799
  const sender = route ? this.sessions.get(route.from) : undefined;
691
- if (route?.to === currentId && receiver?.socket === socket && sender) {
800
+ if (route?.to === currentKey && receiver?.socket === socket && sender) {
692
801
  writeMessage(sender.socket, {
693
802
  type: "message_receipt",
694
803
  from: receiver.info,
@@ -699,7 +808,7 @@ class IntercomBroker {
699
808
  }
700
809
 
701
810
  case "cancel_message": {
702
- if (!currentId) {
811
+ if (!currentKey) {
703
812
  throw new Error("Received cancel_message before register");
704
813
  }
705
814
  if (typeof clientMessage.messageId !== "string") {
@@ -707,20 +816,22 @@ class IntercomBroker {
707
816
  }
708
817
  this.pruneMessageReceiptRoutes();
709
818
  this.pruneMailboxMessages();
710
- const sender = this.sessions.get(currentId);
711
- const queuedIndex = this.mailboxMessages.findIndex(entry => entry.message.id === clientMessage.messageId && entry.from.id === currentId);
819
+ const sender = this.sessions.get(currentKey);
820
+ const queuedIndex = this.mailboxMessages.findIndex(entry => entry.message.id === clientMessage.messageId && entry.fromKey === currentKey);
712
821
  if (queuedIndex >= 0 && sender?.socket === socket) {
713
822
  this.mailboxMessages.splice(queuedIndex, 1);
823
+ this.updateDeliveryRecord(currentKey, clientMessage.messageId, "failed", "Sender cancelled the queued delivery", "E_DELIVERY_CANCELLED");
714
824
  const edge = this.askEdges.get(clientMessage.messageId);
715
- if (edge?.from === currentId) {
825
+ if (edge?.from === currentKey) {
716
826
  this.askEdges.delete(clientMessage.messageId);
827
+ this.removePendingAskRecord(clientMessage.messageId, sender.scopeId);
717
828
  }
718
829
  writeMessage(socket, { type: "delivered", messageId: clientMessage.messageId });
719
830
  break;
720
831
  }
721
832
  const route = this.messageReceiptRoutes.get(clientMessage.messageId);
722
833
  const receiver = route ? this.sessions.get(route.to) : undefined;
723
- if (route?.from !== currentId || sender?.socket !== socket || !receiver) {
834
+ if (route?.from !== currentKey || sender?.socket !== socket || !receiver) {
724
835
  writeMessage(socket, {
725
836
  type: "delivery_failed",
726
837
  messageId: clientMessage.messageId,
@@ -738,33 +849,36 @@ class IntercomBroker {
738
849
  },
739
850
  });
740
851
  const edge = this.askEdges.get(clientMessage.messageId);
741
- if (edge?.from === currentId) {
852
+ if (edge?.from === currentKey) {
742
853
  this.askEdges.delete(clientMessage.messageId);
854
+ this.removePendingAskRecord(clientMessage.messageId, sender.scopeId);
743
855
  }
856
+ this.updateDeliveryRecord(currentKey, clientMessage.messageId, "failed", "Sender cancelled the delivery", "E_DELIVERY_CANCELLED");
744
857
  writeMessage(socket, { type: "delivered", messageId: clientMessage.messageId });
745
858
  break;
746
859
  }
747
860
 
748
861
  case "cancel_ask": {
749
- if (!currentId) {
862
+ if (!currentKey) {
750
863
  throw new Error("Received cancel_ask before register");
751
864
  }
752
865
  if (typeof clientMessage.messageId !== "string") {
753
866
  throw new Error("Invalid cancel_ask message");
754
867
  }
755
- const session = this.sessions.get(currentId);
868
+ const session = this.sessions.get(currentKey);
756
869
  const edge = this.askEdges.get(clientMessage.messageId);
757
- if (session?.socket === socket && edge?.from === currentId) {
870
+ if (session?.socket === socket && edge?.from === currentKey) {
758
871
  this.askEdges.delete(clientMessage.messageId);
872
+ this.removePendingAskRecord(clientMessage.messageId, session.scopeId);
759
873
  }
760
874
  break;
761
875
  }
762
876
 
763
877
  case "presence": {
764
- if (!currentId) {
878
+ if (!currentKey) {
765
879
  throw new Error("Received presence before register");
766
880
  }
767
- const session = this.sessions.get(currentId);
881
+ const session = this.sessions.get(currentKey);
768
882
  if (session?.socket === socket) {
769
883
  let changed = false;
770
884
  if (clientMessage.name !== undefined) {
@@ -840,19 +954,19 @@ class IntercomBroker {
840
954
  session.info.lastActivity = now;
841
955
  if (changed || now - session.lastPresenceBroadcastAt >= PRESENCE_HEARTBEAT_MS) {
842
956
  session.lastPresenceBroadcastAt = now;
843
- this.broadcast({ type: "presence_update", session: session.info }, currentId);
957
+ this.broadcast({ type: "presence_update", session: session.info }, currentKey, session.scopeId);
844
958
  }
845
959
  }
846
960
  break;
847
961
  }
848
962
 
849
963
  case "extension_publish": {
850
- this.handleExtensionPublish(socket, currentId, clientMessage);
964
+ this.handleExtensionPublish(socket, currentKey, clientMessage);
851
965
  break;
852
966
  }
853
967
 
854
968
  case "extension_state_commit": {
855
- this.handleExtensionStateCommit(socket, currentId, clientMessage);
969
+ this.handleExtensionStateCommit(socket, currentKey, clientMessage);
856
970
  break;
857
971
  }
858
972
 
@@ -861,8 +975,13 @@ class IntercomBroker {
861
975
  }
862
976
  }
863
977
 
864
- private rememberDisconnectedSession(info: SessionInfo, now = Date.now()): void {
865
- this.disconnectedSessions.set(info.id, { info: { ...info }, disconnectedAt: now });
978
+ private rememberDisconnectedSession(session: ConnectedSession, now = Date.now()): void {
979
+ this.disconnectedSessions.set(session.key, {
980
+ info: { ...session.info },
981
+ key: session.key,
982
+ ...(session.scopeId ? { scopeId: session.scopeId } : {}),
983
+ disconnectedAt: now,
984
+ });
866
985
  this.pruneDisconnectedSessions(now);
867
986
  }
868
987
 
@@ -880,41 +999,132 @@ class IntercomBroker {
880
999
  if (now - entry.queuedAt > MAILBOX_MESSAGE_RETENTION_MS) {
881
1000
  if (entry.message.expectsReply) {
882
1001
  this.askEdges.delete(entry.message.id);
1002
+ this.removePendingAskRecord(entry.message.id, entry.fromScopeId);
883
1003
  }
884
1004
  this.messageReceiptRoutes.delete(entry.message.id);
1005
+ this.updateDeliveryRecord(entry.fromKey, entry.message.id, "failed", "Mailbox delivery expired", "E_DELIVERY_EXPIRED");
885
1006
  this.mailboxMessages.splice(index, 1);
886
1007
  }
887
1008
  }
888
1009
  }
889
1010
 
890
- private queueMailboxMessage(from: SessionInfo, target: SessionInfo, message: Message, brokerReceivedAt: number): void {
1011
+ private queueMailboxMessage(from: ConnectedSession, target: DisconnectedSession, message: Message, brokerReceivedAt: number): void {
891
1012
  this.pruneMailboxMessages(brokerReceivedAt);
892
1013
  while (this.mailboxMessages.length >= MAX_MAILBOX_MESSAGES) {
893
1014
  const evicted = this.mailboxMessages.shift();
894
1015
  if (!evicted) break;
895
1016
  if (evicted.message.expectsReply) {
896
1017
  this.askEdges.delete(evicted.message.id);
1018
+ this.removePendingAskRecord(evicted.message.id, evicted.fromScopeId);
897
1019
  }
898
1020
  this.messageReceiptRoutes.delete(evicted.message.id);
1021
+ this.updateDeliveryRecord(evicted.fromKey, evicted.message.id, "failed", "Mailbox capacity evicted the delivery", "E_DELIVERY_EVICTED");
899
1022
  }
900
1023
  this.mailboxMessages.push({
901
- from: { ...from },
902
- target: { ...target },
1024
+ from: { ...from.info },
1025
+ fromKey: from.key,
1026
+ ...(from.scopeId ? { fromScopeId: from.scopeId } : {}),
1027
+ target: { ...target.info },
1028
+ targetKey: target.key,
1029
+ ...(target.scopeId ? { targetScopeId: target.scopeId } : {}),
903
1030
  message: { ...message, brokerReceivedAt },
904
1031
  queuedAt: brokerReceivedAt,
905
1032
  });
906
1033
  }
907
1034
 
1035
+ private writeDeliverySuccess(socket: net.Socket, messageId: string, delivery: "socket_delivered" | "queued"): void {
1036
+ writeMessage(socket, { type: "delivered", messageId, delivery, retryable: false, outcomeKnown: true });
1037
+ }
1038
+
1039
+ private writeDeliveryFailure(socket: net.Socket, messageId: string, reason: string, code: string, retryable = false): void {
1040
+ writeMessage(socket, { type: "delivery_failed", messageId, reason, delivery: "failed", code, retryable, outcomeKnown: true });
1041
+ }
1042
+
1043
+ private deliveryFingerprint(message: Message, targetId: string): string {
1044
+ return JSON.stringify({
1045
+ targetId,
1046
+ text: message.content.text,
1047
+ attachments: message.content.attachments,
1048
+ replyTo: message.replyTo,
1049
+ expectsReply: message.expectsReply,
1050
+ supersedes: message.supersedes,
1051
+ retryOf: message.retryOf,
1052
+ provenance: message.provenance,
1053
+ });
1054
+ }
1055
+
1056
+ private deliveryRecordKey(fromSessionId: string, messageId: string): string {
1057
+ return JSON.stringify([fromSessionId, messageId]);
1058
+ }
1059
+
1060
+ private replayOrReject(socket: net.Socket, fromSessionId: string, messageId: string, fingerprint: string): boolean {
1061
+ this.pruneDeliveryRecords();
1062
+ const record = this.deliveryRecords.get(this.deliveryRecordKey(fromSessionId, messageId));
1063
+ if (!record) return false;
1064
+ if (record.fingerprint !== fingerprint) {
1065
+ this.writeDeliveryFailure(socket, messageId, "Message id was reused with different authored content", "E_MESSAGE_ID_REUSE");
1066
+ return true;
1067
+ }
1068
+ if (record.code === "E_TARGET_REBOUND" && record.retryable) {
1069
+ return false;
1070
+ }
1071
+ if (record.state === "socket_delivered" || record.state === "queued") {
1072
+ this.writeDeliverySuccess(socket, messageId, record.state);
1073
+ } else {
1074
+ this.writeDeliveryFailure(socket, messageId, record.reason ?? "Previous delivery failed", record.code ?? "E_DELIVERY_FAILED", record.retryable);
1075
+ }
1076
+ return true;
1077
+ }
1078
+
1079
+ private recordDelivery(fromSessionId: string, messageId: string, fingerprint: string, state: DeliveryState, reason?: string, code?: string, retryable = false): void {
1080
+ this.pruneDeliveryRecords();
1081
+ while (this.deliveryRecords.size >= MAX_DELIVERY_RECORDS) {
1082
+ const oldest = this.deliveryRecords.keys().next().value;
1083
+ if (oldest === undefined) break;
1084
+ this.deliveryRecords.delete(oldest);
1085
+ }
1086
+ this.deliveryRecords.set(this.deliveryRecordKey(fromSessionId, messageId), {
1087
+ fingerprint,
1088
+ state,
1089
+ ...(reason ? { reason } : {}),
1090
+ ...(code ? { code } : {}),
1091
+ retryable,
1092
+ outcomeKnown: true,
1093
+ createdAt: Date.now(),
1094
+ });
1095
+ }
1096
+
1097
+ private pruneDeliveryRecords(now = Date.now()): void {
1098
+ for (const [key, record] of this.deliveryRecords) {
1099
+ if (now - record.createdAt > DELIVERY_RECORD_RETENTION_MS) this.deliveryRecords.delete(key);
1100
+ }
1101
+ }
1102
+
1103
+ private updateDeliveryRecord(fromSessionId: string, messageId: string, state: DeliveryState, reason?: string, code?: string): void {
1104
+ const record = this.deliveryRecords.get(this.deliveryRecordKey(fromSessionId, messageId));
1105
+ if (!record) return;
1106
+ record.state = state;
1107
+ record.reason = reason;
1108
+ record.code = code;
1109
+ record.retryable = false;
1110
+ record.outcomeKnown = true;
1111
+ }
1112
+
908
1113
  private flushMailboxForSession(session: ConnectedSession, now = Date.now()): void {
909
1114
  this.pruneMailboxMessages(now);
910
1115
  const sessionName = session.info.name?.toLowerCase();
911
- const uniqueMailboxIdentity = this.findLiveSessionsSharingMailboxIdentity(session.info).length === 1;
1116
+ const uniqueMailboxIdentity = this.findLiveSessionsSharingMailboxIdentity(session).length === 1;
912
1117
 
913
1118
  for (let index = 0; index < this.mailboxMessages.length;) {
914
1119
  const entry = this.mailboxMessages[index]!;
915
- const matchesId = entry.target.id === session.info.id;
1120
+ if (!sameScope(entry.targetScopeId, session.scopeId)) {
1121
+ index += 1;
1122
+ continue;
1123
+ }
1124
+ const matchesId = entry.targetKey === session.key;
916
1125
  const matchesSenderIdentity = Boolean(
917
1126
  sessionName
1127
+ && sameScope(entry.fromScopeId, session.scopeId)
918
1128
  && entry.from.name?.toLowerCase() === sessionName
919
1129
  && sameCwd(entry.from.cwd, session.info.cwd),
920
1130
  );
@@ -932,8 +1142,8 @@ class IntercomBroker {
932
1142
 
933
1143
  this.mailboxMessages.splice(index, 1);
934
1144
  const edge = this.askEdges.get(entry.message.id);
935
- if (edge?.to === entry.target.id) {
936
- edge.to = session.info.id;
1145
+ if (edge?.to === entry.targetKey) {
1146
+ edge.to = session.key;
937
1147
  }
938
1148
  const deliveredMessage: Message = {
939
1149
  ...entry.message,
@@ -945,25 +1155,75 @@ class IntercomBroker {
945
1155
  message: deliveredMessage,
946
1156
  });
947
1157
  this.messageReceiptRoutes.set(entry.message.id, {
948
- from: entry.from.id,
949
- to: session.info.id,
1158
+ from: entry.fromKey,
1159
+ to: session.key,
950
1160
  createdAt: entry.message.brokerReceivedAt ?? entry.queuedAt,
951
1161
  });
1162
+ this.updateDeliveryRecord(entry.fromKey, entry.message.id, "socket_delivered");
952
1163
  }
953
1164
  }
954
1165
 
955
1166
  private pruneAskEdges(now = Date.now()): void {
1167
+ this.prunePendingAskRecords(now);
956
1168
  for (const [messageId, edge] of this.askEdges) {
957
1169
  if (now - edge.createdAt > this.askTimeoutMs) {
958
1170
  this.askEdges.delete(messageId);
1171
+ this.removePendingAskRecord(messageId, edge.scopeId);
959
1172
  }
960
1173
  }
961
1174
  }
962
1175
 
963
- private clearAskEdgesForSession(sessionId: string): void {
1176
+ private clearAskEdgesForSession(sessionKey: string): void {
964
1177
  for (const [messageId, edge] of this.askEdges) {
965
- if (edge.from === sessionId || edge.to === sessionId) {
1178
+ if (edge.from === sessionKey || edge.to === sessionKey) {
966
1179
  this.askEdges.delete(messageId);
1180
+ this.removePendingAskRecord(messageId, edge.scopeId);
1181
+ }
1182
+ }
1183
+ }
1184
+
1185
+ private writePendingAskRecord(message: Message, from: ConnectedSession, target: SessionInfo, createdAt: number): void {
1186
+ ensurePendingAskRecordDir();
1187
+ const record: PendingAskRecord = {
1188
+ askId: message.id,
1189
+ messageId: message.id,
1190
+ asker: { sessionId: from.info.id, name: from.info.name ?? null },
1191
+ target: { sessionId: target.id, name: target.name ?? null },
1192
+ question: message.content.text,
1193
+ createdAt,
1194
+ expiresAt: createdAt + this.askTimeoutMs,
1195
+ };
1196
+ const filePath = scopedPendingAskRecordPath(from.scopeId, message.id);
1197
+ writeFileSync(filePath, `${JSON.stringify(record, null, 2)}\n`, { mode: INTERCOM_RUNTIME_FILE_MODE });
1198
+ restrictIntercomRuntimeFile(filePath);
1199
+ }
1200
+
1201
+ private removePendingAskRecord(messageId: string, scopeId?: string): void {
1202
+ try {
1203
+ unlinkSync(scopedPendingAskRecordPath(scopeId, messageId));
1204
+ } catch (error) {
1205
+ if (!isRecord(error) || error.code !== "ENOENT") {
1206
+ throw error;
1207
+ }
1208
+ }
1209
+ }
1210
+
1211
+ private prunePendingAskRecords(now = Date.now()): void {
1212
+ ensurePendingAskRecordDir();
1213
+ for (const entry of readdirSync(PENDING_ASKS_DIR, { withFileTypes: true })) {
1214
+ if (!entry.isFile() || !entry.name.endsWith(".json")) {
1215
+ continue;
1216
+ }
1217
+ const filePath = join(PENDING_ASKS_DIR, entry.name);
1218
+ let parsed: unknown;
1219
+ try {
1220
+ parsed = JSON.parse(readFileSync(filePath, "utf-8"));
1221
+ } catch {
1222
+ unlinkSync(filePath);
1223
+ continue;
1224
+ }
1225
+ if (!isPendingAskRecord(parsed) || now > parsed.expiresAt) {
1226
+ unlinkSync(filePath);
967
1227
  }
968
1228
  }
969
1229
  }
@@ -976,52 +1236,52 @@ class IntercomBroker {
976
1236
  }
977
1237
  }
978
1238
 
979
- private clearMessageReceiptRoutesForSession(sessionId: string): void {
1239
+ private clearMessageReceiptRoutesForSession(sessionKey: string): void {
980
1240
  for (const [messageId, route] of this.messageReceiptRoutes) {
981
- if (route.from === sessionId || route.to === sessionId) {
1241
+ if (route.from === sessionKey || route.to === sessionKey) {
982
1242
  this.messageReceiptRoutes.delete(messageId);
983
1243
  }
984
1244
  }
985
1245
  }
986
1246
 
987
- private findSessions(nameOrId: string): ConnectedSession[] {
988
- const byId = this.sessions.get(nameOrId);
1247
+ private findSessions(nameOrId: string, scopeId: string | undefined): ConnectedSession[] {
1248
+ const byId = this.sessions.get(scopedSessionKey(scopeId, nameOrId));
989
1249
  if (byId) {
990
1250
  return [byId];
991
1251
  }
992
1252
 
993
1253
  const lowerName = nameOrId.toLowerCase();
994
- const byName = Array.from(this.sessions.values()).filter(session => session.info.name?.toLowerCase() === lowerName);
1254
+ const byName = Array.from(this.sessions.values()).filter(session => sameScope(session.scopeId, scopeId) && session.info.name?.toLowerCase() === lowerName);
995
1255
  if (byName.length > 0) {
996
1256
  return byName;
997
1257
  }
998
1258
 
999
1259
  return Array.from(this.sessions.entries())
1000
- .filter(([id]) => id.startsWith(nameOrId))
1260
+ .filter(([, session]) => sameScope(session.scopeId, scopeId) && session.info.id.startsWith(nameOrId))
1001
1261
  .map(([, session]) => session);
1002
1262
  }
1003
1263
 
1004
- private findDisconnectedSessions(nameOrId: string): DisconnectedSession[] {
1264
+ private findDisconnectedSessions(nameOrId: string, scopeId: string | undefined): DisconnectedSession[] {
1005
1265
  this.pruneDisconnectedSessions();
1006
- const byId = this.disconnectedSessions.get(nameOrId);
1266
+ const byId = this.disconnectedSessions.get(scopedSessionKey(scopeId, nameOrId));
1007
1267
  if (byId) {
1008
1268
  return [byId];
1009
1269
  }
1010
1270
 
1011
1271
  const lowerName = nameOrId.toLowerCase();
1012
- const byName = Array.from(this.disconnectedSessions.values()).filter(session => session.info.name?.toLowerCase() === lowerName);
1272
+ const byName = Array.from(this.disconnectedSessions.values()).filter(session => sameScope(session.scopeId, scopeId) && session.info.name?.toLowerCase() === lowerName);
1013
1273
  if (byName.length > 0) {
1014
1274
  return byName;
1015
1275
  }
1016
1276
 
1017
1277
  return Array.from(this.disconnectedSessions.entries())
1018
- .filter(([id]) => id.startsWith(nameOrId))
1278
+ .filter(([, session]) => sameScope(session.scopeId, scopeId) && session.info.id.startsWith(nameOrId))
1019
1279
  .map(([, session]) => session);
1020
1280
  }
1021
1281
 
1022
- private findUniqueLiveSessionForDisconnectedSession(info: SessionInfo, senderId?: string): ConnectedSession | null {
1023
- const matches = this.findLiveSessionsSharingMailboxIdentity(info)
1024
- .filter((session) => session.info.id !== senderId);
1282
+ private findUniqueLiveSessionForDisconnectedSession(disconnected: DisconnectedSession, senderKey?: string): ConnectedSession | null {
1283
+ const matches = this.findLiveSessionsSharingMailboxIdentity(disconnected)
1284
+ .filter((session) => session.key !== senderKey);
1025
1285
  return matches.length === 1 ? matches[0]! : null;
1026
1286
  }
1027
1287
 
@@ -1036,21 +1296,22 @@ class IntercomBroker {
1036
1296
  * directory differently (trailing slash, "."/"..", or a symlink such as macOS
1037
1297
  * /tmp vs /private/tmp) still matches.
1038
1298
  */
1039
- private findLiveSessionsSharingMailboxIdentity(info: SessionInfo): ConnectedSession[] {
1040
- const lowerName = info.name?.toLowerCase();
1041
- if (!lowerName || info.runtimeFallbackAlias) {
1299
+ private findLiveSessionsSharingMailboxIdentity(sessionInfo: ConnectedSession | DisconnectedSession): ConnectedSession[] {
1300
+ const lowerName = sessionInfo.info.name?.toLowerCase();
1301
+ if (!lowerName || sessionInfo.info.runtimeFallbackAlias) {
1042
1302
  return [];
1043
1303
  }
1044
1304
  return Array.from(this.sessions.values()).filter(session =>
1045
- !session.info.runtimeFallbackAlias
1305
+ sameScope(session.scopeId, sessionInfo.scopeId)
1306
+ && !session.info.runtimeFallbackAlias
1046
1307
  && session.info.name?.toLowerCase() === lowerName
1047
- && sameCwd(session.info.cwd, info.cwd)
1308
+ && sameCwd(session.info.cwd, sessionInfo.info.cwd)
1048
1309
  );
1049
1310
  }
1050
1311
 
1051
- private broadcast(msg: BrokerMessage, exclude?: string): void {
1312
+ private broadcast(msg: BrokerMessage, exclude?: string, scopeId?: string): void {
1052
1313
  for (const [id, session] of this.sessions) {
1053
- if (id !== exclude) {
1314
+ if (id !== exclude && sameScope(session.scopeId, scopeId)) {
1054
1315
  writeMessage(session.socket, msg);
1055
1316
  }
1056
1317
  }
@@ -1082,31 +1343,42 @@ class IntercomBroker {
1082
1343
  }
1083
1344
 
1084
1345
  private recomputeNamespaceOwners(): void {
1085
- const namespaces = new Set(this.namespaceOwners.keys());
1346
+ const namespaces = new Map<string, { namespace: string; scopeId?: string }>();
1347
+ for (const [key, owner] of this.namespaceOwners) {
1348
+ namespaces.set(key, {
1349
+ namespace: owner.namespace,
1350
+ ...(owner.scopeId ? { scopeId: owner.scopeId } : {}),
1351
+ });
1352
+ }
1086
1353
  for (const session of this.sessions.values()) {
1087
1354
  for (const extension of session.extensions ?? []) {
1088
- namespaces.add(extension.namespace);
1355
+ namespaces.set(scopedExtensionKey(session.scopeId, extension.namespace), {
1356
+ namespace: extension.namespace,
1357
+ ...(session.scopeId ? { scopeId: session.scopeId } : {}),
1358
+ });
1089
1359
  }
1090
1360
  }
1091
1361
 
1092
1362
  // For each namespace, elect owner by (startedAt, sessionId).
1093
- for (const namespace of namespaces) {
1094
- const candidates: Array<{ sessionId: string; session: ConnectedSession }> = [];
1095
- for (const [sessionId, session] of this.sessions) {
1363
+ for (const [namespaceKey, scopedNamespace] of namespaces) {
1364
+ const { namespace, scopeId } = scopedNamespace;
1365
+ const candidates: Array<{ sessionKey: string; session: ConnectedSession }> = [];
1366
+ for (const [sessionKey, session] of this.sessions) {
1096
1367
  if (session.extensions) {
1097
1368
  const hasNamespace = session.extensions.some(
1098
- (ext) => ext.namespace === namespace && ext.ownerEligible
1369
+ (ext) => sameScope(session.scopeId, scopeId) && ext.namespace === namespace && ext.ownerEligible
1099
1370
  );
1100
1371
  if (hasNamespace) {
1101
- candidates.push({ sessionId, session });
1372
+ candidates.push({ sessionKey, session });
1102
1373
  }
1103
1374
  }
1104
1375
  }
1105
1376
 
1106
1377
  if (candidates.length === 0) {
1107
- if (this.namespaceOwners.delete(namespace)) {
1378
+ if (this.namespaceOwners.delete(namespaceKey)) {
1108
1379
  for (const session of this.sessions.values()) {
1109
- const isCapable = session.extensions?.some((extension) => extension.namespace === namespace);
1380
+ const isCapable = sameScope(session.scopeId, scopeId)
1381
+ && session.extensions?.some((extension) => extension.namespace === namespace);
1110
1382
  if (isCapable) {
1111
1383
  writeMessage(session.socket, { type: "extension_owner", namespace });
1112
1384
  }
@@ -1122,31 +1394,35 @@ class IntercomBroker {
1122
1394
  if (a.session.ownerOrder !== b.session.ownerOrder) {
1123
1395
  return a.session.ownerOrder - b.session.ownerOrder;
1124
1396
  }
1125
- return a.sessionId.localeCompare(b.sessionId);
1397
+ return a.session.info.id.localeCompare(b.session.info.id);
1126
1398
  });
1127
1399
 
1128
1400
  const winner = candidates[0];
1129
- const existing = this.namespaceOwners.get(namespace);
1401
+ const existing = this.namespaceOwners.get(namespaceKey);
1130
1402
 
1131
- const ownerChanged = !existing || existing.sessionId !== winner.sessionId;
1403
+ const ownerChanged = !existing || existing.sessionKey !== winner.sessionKey;
1132
1404
  const socketChanged = existing && existing.socket !== winner.session.socket;
1133
1405
 
1134
1406
  if (ownerChanged || socketChanged) {
1135
1407
  const epoch = randomUUID();
1136
- this.namespaceOwners.set(namespace, {
1137
- sessionId: winner.sessionId,
1408
+ this.namespaceOwners.set(namespaceKey, {
1409
+ namespace,
1410
+ sessionKey: winner.sessionKey,
1411
+ sessionId: winner.session.info.id,
1138
1412
  socket: winner.session.socket,
1139
1413
  epoch,
1414
+ ...(scopeId ? { scopeId } : {}),
1140
1415
  });
1141
1416
 
1142
1417
  for (const session of this.sessions.values()) {
1143
1418
  if (session.extensions?.length) {
1144
- const isCapable = session.extensions.some((ext) => ext.namespace === namespace);
1419
+ const isCapable = sameScope(session.scopeId, scopeId)
1420
+ && session.extensions.some((ext) => ext.namespace === namespace);
1145
1421
  if (isCapable) {
1146
1422
  writeMessage(session.socket, {
1147
1423
  type: "extension_owner",
1148
1424
  namespace,
1149
- ownerId: winner.sessionId,
1425
+ ownerId: winner.session.info.id,
1150
1426
  ownerEpoch: epoch,
1151
1427
  });
1152
1428
  }
@@ -1158,14 +1434,14 @@ class IntercomBroker {
1158
1434
 
1159
1435
  private handleExtensionPublish(
1160
1436
  socket: net.Socket,
1161
- currentId: string | null,
1437
+ currentKey: string | null,
1162
1438
  msg: Record<string, unknown>
1163
1439
  ): void {
1164
- if (!currentId) {
1440
+ if (!currentKey) {
1165
1441
  throw new Error("Received extension_publish before register");
1166
1442
  }
1167
1443
 
1168
- const session = this.sessions.get(currentId);
1444
+ const session = this.sessions.get(currentKey);
1169
1445
  if (!session || session.socket !== socket) {
1170
1446
  writeMessage(socket, { type: "error", error: "Session not found" });
1171
1447
  return;
@@ -1205,7 +1481,7 @@ class IntercomBroker {
1205
1481
  return;
1206
1482
  }
1207
1483
 
1208
- const owner = this.namespaceOwners.get(namespace);
1484
+ const owner = this.namespaceOwners.get(scopedExtensionKey(session.scopeId, namespace));
1209
1485
  if ((audience === "owner" || ownerOnly) && !owner) {
1210
1486
  writeMessage(socket, { type: "error", error: "No owner for this namespace" });
1211
1487
  return;
@@ -1217,7 +1493,7 @@ class IntercomBroker {
1217
1493
  writeMessage(socket, { type: "error", error: "ownerEpoch required for owner-only messages" });
1218
1494
  return;
1219
1495
  }
1220
- if (currentId !== owner.sessionId || socket !== owner.socket || ownerEpoch !== owner.epoch) {
1496
+ if (currentKey !== owner.sessionKey || socket !== owner.socket || ownerEpoch !== owner.epoch) {
1221
1497
  writeMessage(socket, { type: "error", error: "Owner validation failed" });
1222
1498
  return;
1223
1499
  }
@@ -1225,6 +1501,9 @@ class IntercomBroker {
1225
1501
 
1226
1502
  // Route message to appropriate audience
1227
1503
  for (const [recipientId, recipientSession] of this.sessions) {
1504
+ if (!sameScope(recipientSession.scopeId, session.scopeId)) {
1505
+ continue;
1506
+ }
1228
1507
  if (!recipientSession.extensions?.length) {
1229
1508
  continue;
1230
1509
  }
@@ -1237,14 +1516,14 @@ class IntercomBroker {
1237
1516
  const shouldReceive =
1238
1517
  audience === "capable" ||
1239
1518
  (audience === "owner" && owner !== undefined &&
1240
- recipientId === owner.sessionId &&
1519
+ recipientId === owner.sessionKey &&
1241
1520
  recipientSession.socket === owner.socket);
1242
1521
 
1243
1522
  if (shouldReceive) {
1244
1523
  writeMessage(recipientSession.socket, {
1245
1524
  type: "extension_message",
1246
1525
  namespace,
1247
- fromSessionId: currentId,
1526
+ fromSessionId: session.info.id,
1248
1527
  ...(owner ? { ownerId: owner.sessionId, ownerEpoch: owner.epoch } : {}),
1249
1528
  payload,
1250
1529
  });
@@ -1254,14 +1533,14 @@ class IntercomBroker {
1254
1533
 
1255
1534
  private handleExtensionStateCommit(
1256
1535
  socket: net.Socket,
1257
- currentId: string | null,
1536
+ currentKey: string | null,
1258
1537
  msg: Record<string, unknown>
1259
1538
  ): void {
1260
- if (!currentId) {
1539
+ if (!currentKey) {
1261
1540
  throw new Error("Received extension_state_commit before register");
1262
1541
  }
1263
1542
 
1264
- const session = this.sessions.get(currentId);
1543
+ const session = this.sessions.get(currentKey);
1265
1544
  if (!session || session.socket !== socket) {
1266
1545
  writeMessage(socket, {
1267
1546
  type: "extension_state_result",
@@ -1299,13 +1578,14 @@ class IntercomBroker {
1299
1578
  });
1300
1579
  return;
1301
1580
  }
1581
+ const stateNamespace = scopedExtensionStateNamespace(session.scopeId, namespace);
1302
1582
 
1303
1583
  if (typeof ownerEpoch !== "string") {
1304
1584
  writeMessage(socket, {
1305
1585
  type: "extension_state_result",
1306
1586
  namespace,
1307
1587
  committed: false,
1308
- revision: this.extensionStateManager.getCurrentRevision(namespace),
1588
+ revision: this.extensionStateManager.getCurrentRevision(stateNamespace),
1309
1589
  reason: "Invalid ownerEpoch",
1310
1590
  });
1311
1591
  return;
@@ -1316,7 +1596,7 @@ class IntercomBroker {
1316
1596
  type: "extension_state_result",
1317
1597
  namespace,
1318
1598
  committed: false,
1319
- revision: this.extensionStateManager.getCurrentRevision(namespace),
1599
+ revision: this.extensionStateManager.getCurrentRevision(stateNamespace),
1320
1600
  reason: "Invalid expectedRevision",
1321
1601
  });
1322
1602
  return;
@@ -1328,7 +1608,7 @@ class IntercomBroker {
1328
1608
  type: "extension_state_result",
1329
1609
  namespace,
1330
1610
  committed: false,
1331
- revision: this.extensionStateManager.getCurrentRevision(namespace),
1611
+ revision: this.extensionStateManager.getCurrentRevision(stateNamespace),
1332
1612
  reason: "Invalid extension state or payload exceeds 64 KiB limit",
1333
1613
  });
1334
1614
  return;
@@ -1341,37 +1621,37 @@ class IntercomBroker {
1341
1621
  type: "extension_state_result",
1342
1622
  namespace,
1343
1623
  committed: false,
1344
- revision: this.extensionStateManager.getCurrentRevision(namespace),
1624
+ revision: this.extensionStateManager.getCurrentRevision(stateNamespace),
1345
1625
  reason: "Sender does not have capability for this namespace",
1346
1626
  });
1347
1627
  return;
1348
1628
  }
1349
1629
 
1350
- const owner = this.namespaceOwners.get(namespace);
1630
+ const owner = this.namespaceOwners.get(scopedExtensionKey(session.scopeId, namespace));
1351
1631
  if (!owner) {
1352
1632
  writeMessage(socket, {
1353
1633
  type: "extension_state_result",
1354
1634
  namespace,
1355
1635
  committed: false,
1356
- revision: this.extensionStateManager.getCurrentRevision(namespace),
1636
+ revision: this.extensionStateManager.getCurrentRevision(stateNamespace),
1357
1637
  reason: "No owner for this namespace",
1358
1638
  });
1359
1639
  return;
1360
1640
  }
1361
1641
 
1362
1642
  // Validate owner, socket, and epoch
1363
- if (currentId !== owner.sessionId || socket !== owner.socket || ownerEpoch !== owner.epoch) {
1643
+ if (currentKey !== owner.sessionKey || socket !== owner.socket || ownerEpoch !== owner.epoch) {
1364
1644
  writeMessage(socket, {
1365
1645
  type: "extension_state_result",
1366
1646
  namespace,
1367
1647
  committed: false,
1368
- revision: this.extensionStateManager.getCurrentRevision(namespace),
1648
+ revision: this.extensionStateManager.getCurrentRevision(stateNamespace),
1369
1649
  reason: "Owner validation failed",
1370
1650
  });
1371
1651
  return;
1372
1652
  }
1373
1653
 
1374
- const result = this.extensionStateManager.commitState(namespace, expectedRevision, payload);
1654
+ const result = this.extensionStateManager.commitState(stateNamespace, expectedRevision, payload);
1375
1655
 
1376
1656
  // Send result to committer
1377
1657
  writeMessage(socket, {
@@ -1385,6 +1665,9 @@ class IntercomBroker {
1385
1665
  // If committed, broadcast new state to all capable sessions
1386
1666
  if (result.committed) {
1387
1667
  for (const recipientSession of this.sessions.values()) {
1668
+ if (!sameScope(recipientSession.scopeId, session.scopeId)) {
1669
+ continue;
1670
+ }
1388
1671
  if (!recipientSession.extensions?.length) {
1389
1672
  continue;
1390
1673
  }