@selesai/code 0.8.2 → 0.8.4

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 (528) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +4 -2
  3. package/dist/cli/args.d.ts +2 -0
  4. package/dist/cli/args.js +18 -0
  5. package/dist/cli/config-selector.js +2 -2
  6. package/dist/cli/startup-ui.d.ts +1 -1
  7. package/dist/cli/startup-ui.js +2 -2
  8. package/dist/core/keybindings.d.ts +44 -4
  9. package/dist/core/llama/provider.js +22 -7
  10. package/dist/core/model-resolver.js +2 -0
  11. package/dist/core/model-runtime.d.ts +4 -2
  12. package/dist/core/model-runtime.js +23 -2
  13. package/dist/core/remote-catalog-provider.js +72 -67
  14. package/dist/core/settings-manager.d.ts +8 -0
  15. package/dist/core/settings-manager.js +18 -0
  16. package/dist/extensions/handoff-new.ts +1 -1
  17. package/dist/extensions/inline-skills.test.ts +1 -0
  18. package/dist/extensions/inline-skills.ts +1 -1
  19. package/dist/extensions/pi-intercom/CHANGELOG.md +25 -3
  20. package/dist/extensions/pi-intercom/README.md +34 -15
  21. package/dist/extensions/pi-intercom/broker/broker.ts +38 -141
  22. package/dist/extensions/pi-intercom/broker/client-liveness.test.ts +173 -0
  23. package/dist/extensions/pi-intercom/broker/client.ts +78 -150
  24. package/dist/extensions/pi-intercom/broker/extension-state.ts +18 -7
  25. package/dist/extensions/pi-intercom/broker/framing.ts +1 -1
  26. package/dist/extensions/pi-intercom/broker/protocol.ts +182 -0
  27. package/dist/extensions/pi-intercom/broker/spawn.test.ts +106 -7
  28. package/dist/extensions/pi-intercom/broker/spawn.ts +37 -11
  29. package/dist/extensions/pi-intercom/config.test.ts +8 -10
  30. package/dist/extensions/pi-intercom/config.ts +3 -3
  31. package/dist/extensions/pi-intercom/index.ts +218 -147
  32. package/dist/extensions/pi-intercom/intercom.integration.test.ts +891 -103
  33. package/dist/extensions/pi-intercom/package.json +3 -2
  34. package/dist/extensions/pi-intercom/project-agent.test.ts +145 -0
  35. package/dist/extensions/pi-intercom/project-agent.ts +324 -0
  36. package/dist/extensions/pi-intercom/reply-tracker.test.ts +86 -1
  37. package/dist/extensions/pi-intercom/reply-tracker.ts +41 -9
  38. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +49 -9
  39. package/dist/extensions/pi-intercom/test/inline-message.test.ts +9 -9
  40. package/dist/extensions/pi-intercom/types.ts +3 -1
  41. package/dist/extensions/pi-intercom/ui/inline-message.ts +7 -7
  42. package/dist/extensions/pi-powerline-footer/.github/workflows/test.yml +2 -2
  43. package/dist/extensions/pi-powerline-footer/CHANGELOG.md +15 -1
  44. package/dist/extensions/pi-powerline-footer/README.md +20 -37
  45. package/dist/extensions/pi-powerline-footer/bash-mode/completion.ts +40 -25
  46. package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +149 -18
  47. package/dist/extensions/pi-powerline-footer/bash-mode/types.ts +1 -0
  48. package/dist/extensions/pi-powerline-footer/editor-performance.ts +99 -0
  49. package/dist/extensions/pi-powerline-footer/git-status.ts +15 -0
  50. package/dist/extensions/pi-powerline-footer/index.ts +394 -586
  51. package/dist/extensions/pi-powerline-footer/package.json +5 -6
  52. package/dist/extensions/pi-powerline-footer/powerline-config.ts +0 -18
  53. package/dist/extensions/pi-powerline-footer/queue/store.ts +8 -56
  54. package/dist/extensions/pi-powerline-footer/queue/types.ts +1 -2
  55. package/dist/extensions/pi-powerline-footer/segments.ts +0 -3
  56. package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +231 -1
  57. package/dist/extensions/pi-powerline-footer/tests/custom-items.test.ts +5 -19
  58. package/dist/extensions/pi-powerline-footer/tests/editor-performance.test.ts +43 -0
  59. package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +2 -2
  60. package/dist/extensions/pi-powerline-footer/tests/git-optional-locks.test.ts +64 -0
  61. package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +1 -1
  62. package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +86 -19
  63. package/dist/extensions/pi-powerline-footer/tests/queue-store.test.ts +19 -149
  64. package/dist/extensions/pi-powerline-footer/tests/remaining-regressions.test.ts +6 -0
  65. package/dist/extensions/pi-powerline-footer/tests/usage-display.test.ts +5 -5
  66. package/dist/extensions/pi-powerline-footer/tsconfig.json +1 -1
  67. package/dist/extensions/pi-powerline-footer/types.ts +1 -2
  68. package/dist/extensions/pi-subagents/CHANGELOG.md +202 -14
  69. package/dist/extensions/pi-subagents/README.md +65 -1614
  70. package/dist/extensions/pi-subagents/agents/builder.md +0 -1
  71. package/dist/extensions/pi-subagents/agents/delegate.md +14 -0
  72. package/dist/extensions/pi-subagents/agents/oracle.md +74 -0
  73. package/dist/extensions/pi-subagents/agents/reviewer.md +78 -0
  74. package/dist/extensions/pi-subagents/agents/scout.md +50 -0
  75. package/dist/extensions/pi-subagents/agents/worker.md +58 -0
  76. package/dist/extensions/pi-subagents/docs/configuration.md +328 -0
  77. package/dist/extensions/pi-subagents/docs/extension-api.md +308 -0
  78. package/dist/extensions/pi-subagents/docs/missions.md +119 -0
  79. package/dist/extensions/pi-subagents/docs/models.md +192 -0
  80. package/dist/extensions/pi-subagents/docs/observability.md +174 -0
  81. package/dist/extensions/pi-subagents/docs/tool-reference.md +343 -0
  82. package/dist/extensions/pi-subagents/docs/watchdog.md +176 -0
  83. package/dist/extensions/pi-subagents/docs/workflows.md +163 -0
  84. package/dist/extensions/pi-subagents/inspector-runner.mjs +11 -0
  85. package/dist/extensions/pi-subagents/package-lock.json +152 -194
  86. package/dist/extensions/pi-subagents/package.json +9 -10
  87. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  88. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  89. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  90. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  91. package/dist/extensions/pi-subagents/prompts/review-loop.md +12 -12
  92. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +22 -17
  93. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +77 -72
  94. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +177 -69
  95. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +28 -8
  96. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +88 -66
  97. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +3 -3
  98. package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +624 -0
  99. package/dist/extensions/pi-subagents/src/agents/agents.ts +29 -16
  100. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +7 -3
  101. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  102. package/dist/extensions/pi-subagents/src/agents/skills.ts +2 -9
  103. package/dist/extensions/pi-subagents/src/api/delegation.ts +1 -2
  104. package/dist/extensions/pi-subagents/src/api/project-panes.ts +30 -0
  105. package/dist/extensions/pi-subagents/src/extension/config.ts +56 -8
  106. package/dist/extensions/pi-subagents/src/extension/control-notices.ts +2 -2
  107. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +51 -26
  108. package/dist/extensions/pi-subagents/src/extension/index.ts +119 -50
  109. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +72 -0
  110. package/dist/extensions/pi-subagents/src/extension/rpc.ts +15 -15
  111. package/dist/extensions/pi-subagents/src/extension/schemas.ts +58 -21
  112. package/dist/extensions/pi-subagents/src/extension/subagent-guide.ts +39 -0
  113. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +47 -25
  114. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +3 -3
  115. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +460 -64
  116. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +102 -4
  117. package/dist/extensions/pi-subagents/src/missions/actions.ts +77 -16
  118. package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +162 -0
  119. package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +65 -14
  120. package/dist/extensions/pi-subagents/src/missions/store.ts +147 -5
  121. package/dist/extensions/pi-subagents/src/missions/types.ts +58 -3
  122. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +256 -0
  123. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -8
  124. package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +42 -0
  125. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +41 -7
  126. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +294 -134
  127. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +19 -3
  128. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +39 -6
  129. package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +267 -0
  130. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +145 -60
  131. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +114 -6
  132. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +33 -0
  133. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +68 -0
  134. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +71 -0
  135. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +21 -2
  136. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +42 -14
  137. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +12 -24
  138. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +7 -5
  139. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +152 -68
  140. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +17 -4
  141. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +146 -0
  142. package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +21 -5
  143. package/dist/extensions/pi-subagents/src/runs/foreground/async-dismiss-action.ts +85 -0
  144. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +43 -18
  145. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +20 -19
  146. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +3 -0
  147. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +55 -26
  148. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +137 -0
  149. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +798 -112
  150. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +187 -0
  151. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +165 -22
  152. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  153. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +2 -0
  154. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +9 -5
  155. package/dist/extensions/pi-subagents/src/runs/shared/model-scope.ts +12 -2
  156. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +1 -0
  157. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +465 -116
  158. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +10 -10
  159. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +189 -32
  160. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +2 -2
  161. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +3 -3
  162. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +128 -3
  163. package/dist/extensions/pi-subagents/src/shared/display-text.ts +100 -0
  164. package/dist/extensions/pi-subagents/src/shared/file-coalescer.ts +9 -0
  165. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +13 -0
  166. package/dist/extensions/pi-subagents/src/shared/formatters.ts +4 -6
  167. package/dist/extensions/pi-subagents/src/shared/prompt-resources.ts +51 -0
  168. package/dist/extensions/pi-subagents/src/shared/settings.ts +41 -11
  169. package/dist/extensions/pi-subagents/src/shared/types.ts +100 -3
  170. package/dist/extensions/pi-subagents/src/shared/utf8.ts +11 -0
  171. package/dist/extensions/pi-subagents/src/shared/utils.ts +43 -33
  172. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -14
  173. package/dist/extensions/pi-subagents/src/slash/inline-subagents.ts +1 -1
  174. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +14 -12
  175. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +176 -21
  176. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +12 -6
  177. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +52 -18
  178. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +36 -5
  179. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +30 -16
  180. package/dist/extensions/pi-subagents/src/tui/fleet.ts +151 -31
  181. package/dist/extensions/pi-subagents/src/tui/render.ts +201 -68
  182. package/dist/extensions/pi-subagents/src/types/pi-runtime-compat.d.ts +0 -6
  183. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +5 -4
  184. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +0 -1
  185. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +313 -25
  186. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +15 -15
  187. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/cli.d.ts +3 -0
  188. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/register-bedrock.d.ts +2 -0
  189. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/restore-sandbox-env.d.ts +17 -0
  190. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/args.d.ts +57 -0
  191. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/config-selector.d.ts +16 -0
  192. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/file-processor.d.ts +15 -0
  193. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/initial-message.d.ts +18 -0
  194. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/list-models.d.ts +9 -0
  195. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/project-trust.d.ts +10 -0
  196. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/session-picker.d.ts +10 -0
  197. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/startup-ui.d.ts +20 -0
  198. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli.d.ts +3 -0
  199. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/config.d.ts +96 -0
  200. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session-runtime.d.ts +119 -0
  201. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session-services.d.ts +85 -0
  202. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session.d.ts +620 -0
  203. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/auth-guidance.d.ts +5 -0
  204. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/auth-storage.d.ts +56 -0
  205. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/bash-executor.d.ts +32 -0
  206. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/cache-stats.d.ts +49 -0
  207. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/branch-summarization.d.ts +93 -0
  208. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/compaction.d.ts +128 -0
  209. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/index.d.ts +7 -0
  210. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/utils.d.ts +38 -0
  211. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/defaults.d.ts +3 -0
  212. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/diagnostics.d.ts +15 -0
  213. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/event-bus.d.ts +9 -0
  214. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/exec.d.ts +29 -0
  215. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/experimental.d.ts +2 -0
  216. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/ansi-to-html.d.ts +22 -0
  217. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/index.d.ts +37 -0
  218. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/tool-renderer.d.ts +34 -0
  219. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/index.d.ts +12 -0
  220. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/loader.d.ts +23 -0
  221. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/runner.d.ts +171 -0
  222. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +1261 -0
  223. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/wrapper.d.ts +20 -0
  224. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/footer-data-provider.d.ts +54 -0
  225. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/http-dispatcher.d.ts +22 -0
  226. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/index.d.ts +13 -0
  227. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/keybindings.d.ts +358 -0
  228. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/messages.d.ts +77 -0
  229. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-config.d.ts +512 -0
  230. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-registry.d.ts +43 -0
  231. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-resolver.d.ts +121 -0
  232. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-runtime.d.ts +82 -0
  233. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/models-store.d.ts +17 -0
  234. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/output-guard.d.ts +7 -0
  235. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/package-manager.d.ts +210 -0
  236. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/project-trust.d.ts +15 -0
  237. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/prompt-templates.d.ts +54 -0
  238. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/provider-attribution.d.ts +4 -0
  239. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/provider-composer.d.ts +55 -0
  240. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/radius.d.ts +2 -0
  241. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/remote-catalog-provider.d.ts +5 -0
  242. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/resolve-config-value.d.ts +30 -0
  243. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/resource-loader.d.ts +206 -0
  244. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/runtime-credentials.d.ts +15 -0
  245. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/sdk.d.ts +106 -0
  246. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/session-cwd.d.ts +19 -0
  247. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/session-manager.d.ts +356 -0
  248. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/settings-manager.d.ts +297 -0
  249. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/skills.d.ts +60 -0
  250. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/slash-commands.d.ts +15 -0
  251. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/source-info.d.ts +18 -0
  252. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/system-prompt.d.ts +28 -0
  253. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/telemetry.d.ts +3 -0
  254. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/timings.d.ts +10 -0
  255. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/bash.d.ts +68 -0
  256. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/edit-diff.d.ts +106 -0
  257. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/edit.d.ts +51 -0
  258. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/file-mutation-queue.d.ts +6 -0
  259. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/find.d.ts +35 -0
  260. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/grep.d.ts +37 -0
  261. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/index.d.ts +40 -0
  262. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/ls.d.ts +37 -0
  263. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/output-accumulator.d.ts +52 -0
  264. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/path-utils.d.ts +10 -0
  265. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/read.d.ts +35 -0
  266. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/render-utils.d.ts +24 -0
  267. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  268. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/truncate.d.ts +70 -0
  269. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/write.d.ts +26 -0
  270. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/trust-manager.d.ts +36 -0
  271. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/usage-totals.d.ts +19 -0
  272. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/index.d.ts +3 -0
  273. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/client.d.ts +61 -0
  274. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/huggingface.d.ts +23 -0
  275. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/index.d.ts +3 -0
  276. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/provider.d.ts +10 -0
  277. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/ui.d.ts +42 -0
  278. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/index.d.ts +35 -0
  279. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/main.d.ts +12 -0
  280. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/migrations.d.ts +33 -0
  281. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/index.d.ts +9 -0
  282. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/armin.d.ts +34 -0
  283. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/assistant-message.d.ts +22 -0
  284. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/bash-execution.d.ts +34 -0
  285. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
  286. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
  287. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
  288. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/config-selector.d.ts +102 -0
  289. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
  290. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-editor.d.ts +21 -0
  291. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-entry.d.ts +19 -0
  292. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-message.d.ts +20 -0
  293. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/daxnuts.d.ts +23 -0
  294. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/diff.d.ts +12 -0
  295. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
  296. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  297. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-editor.d.ts +22 -0
  298. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-input.d.ts +23 -0
  299. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-selector.d.ts +26 -0
  300. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
  301. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/footer.d.ts +32 -0
  302. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/index.d.ts +34 -0
  303. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/keybinding-hints.d.ts +13 -0
  304. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/login-dialog.d.ts +52 -0
  305. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/model-selector.d.ts +54 -0
  306. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/oauth-selector.d.ts +33 -0
  307. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/scoped-models-selector.d.ts +42 -0
  308. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
  309. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/session-selector.d.ts +95 -0
  310. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/settings-selector.d.ts +77 -0
  311. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
  312. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
  313. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/status-indicator.d.ts +28 -0
  314. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/theme-selector.d.ts +11 -0
  315. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
  316. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/tool-execution.d.ts +63 -0
  317. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/tree-selector.d.ts +94 -0
  318. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/trust-selector.d.ts +23 -0
  319. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
  320. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/user-message.d.ts +14 -0
  321. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
  322. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/interactive-mode.d.ts +394 -0
  323. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/model-search.d.ts +12 -0
  324. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/theme/theme-controller.d.ts +29 -0
  325. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/theme/theme.d.ts +120 -0
  326. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/print-mode.d.ts +28 -0
  327. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/jsonl.d.ts +17 -0
  328. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-client.d.ts +246 -0
  329. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-mode.d.ts +20 -0
  330. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-types.d.ts +457 -0
  331. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/package-manager-cli.d.ts +8 -0
  332. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/rpc-entry.d.ts +3 -0
  333. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/ansi.d.ts +2 -0
  334. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/changelog.d.ts +22 -0
  335. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/child-process.d.ts +18 -0
  336. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard-image.d.ts +11 -0
  337. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard-native.d.ts +11 -0
  338. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard.d.ts +4 -0
  339. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/deprecation.d.ts +4 -0
  340. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/exif-orientation.d.ts +5 -0
  341. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/frontmatter.d.ts +8 -0
  342. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/fs-watch.d.ts +5 -0
  343. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/git.d.ts +26 -0
  344. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/html.d.ts +7 -0
  345. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-convert.d.ts +10 -0
  346. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-process.d.ts +18 -0
  347. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize-core.d.ts +30 -0
  348. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize-worker.d.ts +2 -0
  349. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize.d.ts +16 -0
  350. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/json.d.ts +3 -0
  351. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/mime.d.ts +3 -0
  352. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/open-browser.d.ts +9 -0
  353. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/paths.d.ts +31 -0
  354. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/photon.d.ts +21 -0
  355. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/pi-user-agent.d.ts +2 -0
  356. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/shell.d.ts +31 -0
  357. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/sleep.d.ts +5 -0
  358. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/syntax-highlight.d.ts +12 -0
  359. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/tools-manager.d.ts +3 -0
  360. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/version-check.d.ts +15 -0
  361. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/windows-self-update.d.ts +3 -0
  362. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/index.mjs +84 -0
  363. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/package.json +14 -0
  364. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +15 -15
  365. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +411 -300
  366. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +309 -123
  367. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +99 -56
  368. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +62 -16
  369. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +159 -108
  370. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +1 -1
  371. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +4 -2
  372. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +56 -56
  373. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +114 -45
  374. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +57 -19
  375. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +106 -106
  376. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +416 -106
  377. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +287 -17
  378. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +809 -87
  379. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +107 -20
  380. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +9 -9
  381. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +26 -6
  382. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +2 -2
  383. package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
  384. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +1 -1
  385. package/dist/extensions/pi-subagents/test/support/ts-loader.mjs +0 -8
  386. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +163 -58
  387. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  388. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  389. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +334 -248
  390. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +52 -52
  391. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +26 -26
  392. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +99 -99
  393. package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +160 -0
  394. package/dist/extensions/pi-subagents/test/unit/agent-selection.test.ts +9 -9
  395. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +43 -1
  396. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +36 -10
  397. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +387 -30
  398. package/dist/extensions/pi-subagents/test/unit/async-permission-session.test.ts +9 -9
  399. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +2 -2
  400. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +94 -40
  401. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +5 -3
  402. package/dist/extensions/pi-subagents/test/unit/builtin-agent-documentation.test.ts +7 -7
  403. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +19 -19
  404. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +19 -19
  405. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +9 -9
  406. package/dist/extensions/pi-subagents/test/unit/chain-serializer.test.ts +20 -20
  407. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +9 -9
  408. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +35 -5
  409. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +2 -2
  410. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +52 -52
  411. package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +187 -0
  412. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +125 -71
  413. package/dist/extensions/pi-subagents/test/unit/control-notices.test.ts +18 -3
  414. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +12 -12
  415. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +17 -23
  416. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  417. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +25 -25
  418. package/dist/extensions/pi-subagents/test/unit/extra-agent-dirs.test.ts +3 -3
  419. package/dist/extensions/pi-subagents/test/unit/file-coalescer.test.ts +15 -0
  420. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +62 -44
  421. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +329 -37
  422. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +4 -4
  423. package/dist/extensions/pi-subagents/test/unit/foreground-tool-call-compaction.test.ts +37 -0
  424. package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +69 -0
  425. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +79 -2
  426. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +102 -49
  427. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +98 -32
  428. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +5 -5
  429. package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +116 -0
  430. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +55 -7
  431. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +289 -13
  432. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +28 -1
  433. package/dist/extensions/pi-subagents/test/unit/model-scope-settings.test.ts +2 -2
  434. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +11 -2
  435. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +84 -10
  436. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +122 -8
  437. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +8 -8
  438. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +24 -24
  439. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +16 -2
  440. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +7 -7
  441. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +10 -10
  442. package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +3 -3
  443. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +26 -17
  444. package/dist/extensions/pi-subagents/test/unit/pi-args-permission-system.test.ts +405 -0
  445. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +357 -92
  446. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +22 -6
  447. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +6 -6
  448. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +43 -43
  449. package/dist/extensions/pi-subagents/test/unit/proactive-skills.test.ts +13 -13
  450. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +4 -4
  451. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +19 -19
  452. package/dist/extensions/pi-subagents/test/unit/project-panes-public-api.test.ts +243 -0
  453. package/dist/extensions/pi-subagents/test/unit/prompt-template-bridge.test.ts +68 -168
  454. package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +58 -15
  455. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +40 -0
  456. package/dist/extensions/pi-subagents/test/unit/reads-resolution.test.ts +66 -0
  457. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +47 -28
  458. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +12 -12
  459. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +57 -0
  460. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +107 -27
  461. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +1 -1
  462. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +56 -50
  463. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +69 -28
  464. package/dist/extensions/pi-subagents/test/unit/scheduled-store-root.test.ts +67 -0
  465. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +59 -44
  466. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +424 -49
  467. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +23 -1
  468. package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +32 -5
  469. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +13 -13
  470. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +120 -91
  471. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +2 -2
  472. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +85 -0
  473. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +35 -35
  474. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +24 -0
  475. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +312 -22
  476. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +150 -15
  477. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +26 -26
  478. package/dist/extensions/pi-subagents/test/unit/timeout-defaults.test.ts +73 -0
  479. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +76 -25
  480. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +5 -5
  481. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +55 -6
  482. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +13 -13
  483. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +1 -1
  484. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +1 -1
  485. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +8 -8
  486. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +6 -6
  487. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +138 -11
  488. package/dist/extensions/pi-subagents/test/unit/workflow-graph.test.ts +8 -8
  489. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +113 -0
  490. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +7 -7
  491. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +6 -6
  492. package/dist/extensions/workflow/extension.ts +21 -19
  493. package/dist/extensions/workflow/modes.ts +65 -0
  494. package/dist/index.d.ts +1 -1
  495. package/dist/main.js +1 -0
  496. package/dist/modes/interactive/components/settings-selector.d.ts +6 -2
  497. package/dist/modes/interactive/components/settings-selector.js +20 -0
  498. package/dist/modes/interactive/interactive-mode.d.ts +28 -0
  499. package/dist/modes/interactive/interactive-mode.js +214 -28
  500. package/dist/modes/interactive/theme/dark.json +1 -0
  501. package/dist/modes/interactive/theme/light.json +1 -0
  502. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  503. package/dist/modes/interactive/theme/theme-controller.js +10 -1
  504. package/dist/modes/interactive/theme/theme.d.ts +2 -2
  505. package/dist/modes/interactive/theme/theme.js +24 -6
  506. package/dist/skills/pi-subagents/SKILL.md +20 -15
  507. package/dist/skills/pi-subagents/references/constraints-and-recipes.md +77 -83
  508. package/dist/skills/pi-subagents/references/execution-controls.md +215 -106
  509. package/dist/skills/pi-subagents/references/management-authoring-rpc.md +29 -9
  510. package/dist/skills/pi-subagents/references/prompting-and-roles.md +58 -43
  511. package/docs/keybindings.md +35 -7
  512. package/docs/plans/workflow-autoloop-reference.md +192 -0
  513. package/docs/plans/workflow-subagent-consolidation-planb.md +374 -0
  514. package/docs/plans/workflow-subagent-scripted-merge.md +406 -0
  515. package/docs/settings.md +16 -14
  516. package/docs/usage.md +5 -0
  517. package/package.json +5 -5
  518. package/dist/extensions/pi-powerline-footer/fixed-editor/cluster.ts +0 -113
  519. package/dist/extensions/pi-powerline-footer/fixed-editor/terminal-split.ts +0 -1080
  520. package/dist/extensions/pi-powerline-footer/tests/fixed-editor.test.ts +0 -1452
  521. package/dist/extensions/workflow/adapter.ts +0 -949
  522. package/dist/extensions/workflow/modes/loop.ts +0 -74
  523. package/dist/extensions/workflow/modes/prototype.ts +0 -170
  524. package/dist/extensions/workflow/modes/quicktype.ts +0 -150
  525. package/dist/extensions/workflow/modes/task.ts +0 -105
  526. package/dist/extensions/workflow/run-state.ts +0 -124
  527. package/dist/extensions/workflow/state-machine.ts +0 -484
  528. package/dist/extensions/workflow/validators.ts +0 -42
@@ -56,7 +56,7 @@ A session becomes intercom-connected when all of these are true:
56
56
 
57
57
  The session list only shows intercom-connected sessions, not every open Selesai process on the machine.
58
58
 
59
- If a session is unnamed, pi-intercom now exposes a runtime-only fallback alias like `subagent-chat-1a2b3c4d` so other sessions can still target it. That alias is not persisted as the Selesai session title, so `selesai --resume` can keep showing the transcript snippet instead of a generic `session-...` name.
59
+ If a session is unnamed, pi-intercom exposes a collision-resistant runtime-only fallback alias like `subagent-chat-1a2b3c4d-5e6f-7a8b` so other connected sessions can target it. That alias is not persisted as the Selesai session title or treated as a reconnect identity, so `selesai --resume` can keep showing the transcript snippet without allowing a different unnamed process to inherit queued mail.
60
60
 
61
61
  ## Quick Start
62
62
 
@@ -87,6 +87,15 @@ intercom({ action: "list-cwd" })
87
87
  intercom({ action: "send", to: "research", message: "Check if UserService.validate() handles null" })
88
88
  // → Message sent to research
89
89
 
90
+ // Send to a visible peer session in another codebase, opening a Herdr project pane if needed
91
+ intercom({
92
+ action: "send",
93
+ cwd: "/Users/me/projects/billing",
94
+ openProjectPaneIfMissing: true,
95
+ message: "Let's discuss the billing retry design in this repo."
96
+ })
97
+ // → Opened Herdr project pane pane-... for /Users/me/projects/billing and sent message to subagent-chat-...
98
+
90
99
  // Check connection status
91
100
  intercom({ action: "status" })
92
101
  // → Connected: Yes, Session ID: abc123, Active sessions: 3
@@ -118,7 +127,7 @@ Found the issue — UserService.validate() doesn't check for null input.
118
127
  See auth.ts:142-156.
119
128
  ```
120
129
 
121
- The reply hint (enabled by default) points to `intercom({ action: "reply", ... })`, so recipients do not need raw sender or `replyTo` IDs. Idle recipients get a new turn immediately; busy interactive recipients receive the message once they go idle. Attachment content is included in the agent-visible body, and messages are rendered inline and stored in Selesai session history.
130
+ The reply hint (enabled by default) points to `intercom({ action: "reply", ... })`, so recipients do not need raw sender or `replyTo` IDs. Idle recipients get a new turn immediately; busy interactive recipients receive the message through Selesai's steering queue at the next safe model boundary without aborting the active turn. Attachment content is included in the agent-visible body, and messages are rendered inline and stored in Selesai session history.
122
131
 
123
132
  ## Workflow: Planner-Worker Coordination
124
133
 
@@ -205,21 +214,21 @@ To reply, use the intercom tool: intercom({ action: "reply", message: "..." })
205
214
  Only GET/PUT/DELETE — never POST. Max 3 retries with exponential backoff starting at 100ms.
206
215
  ```
207
216
 
208
- This matters because the agent receiving the message doesn't need to reconstruct raw `to` and `replyTo` IDs — the hint is right there. Combined with idle-gated `triggerTurn` delivery, it enables real back-and-forth conversation without interrupting work in progress. If the reply happens later instead of in the triggered turn, `intercom({ action: "reply" })` falls back to the single unresolved inbound ask, and `intercom({ action: "pending" })` shows who is still waiting.
217
+ This matters because the agent receiving the message doesn't need to reconstruct raw `to` and `replyTo` IDs — the hint is right there. Combined with immediate idle triggering and safe busy-turn steering, it enables real back-and-forth conversation without aborting work in progress or delaying messages until they become stale. If the reply happens later instead of in the triggered turn, `intercom({ action: "reply" })` falls back to the single unresolved inbound ask, and `intercom({ action: "pending" })` shows who is still waiting.
209
218
 
210
219
  ### `send` vs `ask`
211
220
 
212
- `send` is fire-and-forget — the tool returns immediately after delivery. By default, it sends immediately even in interactive sessions. If you want an approval dialog before non-reply sends, set `confirmSend: true` in config. Replies that include `replyTo` still skip confirmation so reply-hint flows can continue without an extra approval step.
221
+ `send` is fire-and-forget — the tool returns immediately after delivery. When the destination has exactly one pending inbound ask, `send` infers that it is the answer, attaches the ask's `replyTo`, and reports `Reply sent to <target> (inferred from pending ask)`. With zero or multiple matching asks, it remains an ordinary unthreaded send. An inferred answer still uses the `confirmSend` dialog when configured; only a caller-supplied `replyTo` skips confirmation.
213
222
 
214
- `ask` sends the message and blocks until the recipient responds (10-minute timeout by default; set `PI_INTERCOM_ASK_TIMEOUT_MS` to a positive millisecond value to change it). The reply comes back as the tool result, so the agent continues in the same turn with full context. No confirmation dialog — if you're asking and waiting, the intent is clear.
223
+ `ask` requires a currently connected recipient, then blocks until it responds (10-minute timeout by default; set `PI_INTERCOM_ASK_TIMEOUT_MS` to a positive millisecond value to change it). If the target is disconnected, `ask` fails immediately; use `send` when queued, non-blocking mailbox delivery is appropriate. The reply comes back as the tool result, so the agent continues in the same turn with full context. No confirmation dialog — if you're asking and waiting, the intent is clear.
215
224
 
216
225
  `reply` is receiver-side sugar for replying to an inbound ask. In the turn triggered by an incoming intercom ask, `intercom({ action: "reply", message: "..." })` targets that exact sender and message automatically. If you reply later, it falls back to the single unresolved inbound ask. If multiple asks are pending, use `intercom({ action: "pending" })` to inspect them and then call `reply` with `to` to disambiguate.
217
226
 
218
- The broker keeps a bounded in-memory mailbox for recently disconnected named sessions. If a lightweight CLI sender asks a long-running session something and exits before the answer, the later `reply` is accepted into that mailbox instead of failing with `Session not found`; a process that reconnects with the same name receives the queued reply. This is per-broker runtime state, not durable storage across broker restarts.
227
+ The broker keeps a bounded in-memory mailbox for recently disconnected explicitly named sessions. If a lightweight CLI sender asks a long-running session something and exits before the answer, the later `reply` is accepted into that mailbox instead of failing with `Session not found`; a process that reconnects with the same explicit name and directory receives the queued reply. Runtime-only unnamed-session aliases never transfer mailbox ownership, and routing never remaps mail back to its sender. This is per-broker runtime state, not durable storage across broker restarts.
219
228
 
220
- Incoming messages now carry diagnostic metadata end to end: stable message ID, sender sequence, sender timestamp, broker receive/delivery timestamps, receiver receive timestamp, and injection timestamp. Receivers emit lifecycle receipts for `receiver_received`, `acknowledged`, `queued`, `injected`, `expired`, `cancelled`, `superseded`, and `cancellation_requested`; duplicate message IDs are acknowledged but injected at most once per receiving session. If an `ask` times out, the timeout names the message ID and last known delivery state. Timeout is not cancellation: the recipient may still have the message queued or actionable unless an explicit cancellation path says otherwise.
229
+ Incoming messages carry diagnostic metadata end to end: stable message ID, sender sequence, sender timestamp, broker receive/delivery timestamps, receiver receive timestamp, and injection timestamp. Connected interactive receivers emit `receiver_received`, `acknowledged`, and `injected` as they hand messages to Pi; duplicate IDs are acknowledged but injected at most once per receiving session. Broker mailbox delivery for temporarily disconnected targets can still report queued delivery. If an `ask` times out, the timeout names the message ID and last known delivery state. Timeout is not cancellation: an injected or broker-queued message may remain actionable unless an explicit cancellation path says otherwise.
221
230
 
222
- Cancellation is explicit: call `intercom({ action: "cancel", messageId })` to request cancellation of a message you originally sent. If the receiver has not injected it yet, it is removed from the queue and reported as `cancelled`; if it is already injected or processed, the receiver reports `cancellation_requested` instead of hiding it. Supersede is also explicit: pass `supersedes: "old-message-id"` on a new `send` or `ask`. The broker only allows same sender → same receiver supersedes, marks the old message `superseded`, and sends the replacement with a new message ID. Retries are never automatic; a retry should be a new authored message, optionally linked with `retryOf`.
231
+ Cancellation is explicit: call `intercom({ action: "cancel", messageId })` to request cancellation of a message you originally sent. Connected interactive messages are injected immediately, so the receiver normally reports `cancellation_requested` rather than pretending it removed work from a private queue. Supersede is also explicit: pass `supersedes: "old-message-id"` on a new `send` or `ask`. The broker only allows same sender → same receiver supersedes, marks the old message `superseded`, and sends the replacement with a new ID; an already-steered old message may still be processed. Retries are never automatic; a retry should be a new authored message, optionally linked with `retryOf`.
223
232
 
224
233
  The planner typically uses `send`. If you prefer manual approval for outgoing non-reply messages, turn on `confirmSend: true`. The worker uses `ask` for everything (no confirmation needed, gets answers inline), so it can operate autonomously either way.
225
234
 
@@ -248,6 +257,10 @@ If any are missing, the session falls back to the regular `intercom` tool.
248
257
 
249
258
  Do not use `contact_supervisor` for routine completion handoffs. Return the final subagent result normally through `pi-subagents`.
250
259
 
260
+ A child subagent can still use the regular `intercom` tool to coordinate with an explicit peer session. Use `to` alone for any live peer on the machine, `cwd` alone for the sole live peer in another codebase, or `to` plus `cwd` when the directory is a safety guard. Use `contact_supervisor` instead when the answer changes the task contract, needs owner approval, or would require opening a new visible project pane.
261
+
262
+ For bounded work in another codebase, prefer `pi-subagents` with an explicit `cwd`. Intercom project panes are for durable visible peer conversations, not ordinary delegated work.
263
+
251
264
  ### Example: Blocked Subagent Asks for Guidance
252
265
 
253
266
  ```typescript
@@ -322,13 +335,16 @@ The supervisor can reply with plain JSON or a fenced `json` block. If the reply
322
335
  | Parameter | Type | Description |
323
336
  |-----------|------|-------------|
324
337
  | `action` | string | `"list"`, `"list-cwd"`, `"send"`, `"ask"`, `"reply"`, `"pending"`, `"status"`, or `"cancel"` |
325
- | `to` | string | Target session name or ID (for send/ask, or to disambiguate reply) |
338
+ | `to` | string | Target session name or ID. Without `cwd`, send/ask resolve it globally. With `cwd`, send/ask require the target to be in that directory. Also disambiguates reply. |
326
339
  | `message` | string | Message text (for send/ask/reply) |
327
340
  | `attachments` | array | Optional `file`, `snippet`, or `context` attachments |
328
341
  | `replyTo` | string | Optional message ID for threading or replying to an `ask` |
329
342
  | `messageId` | string | Optional explicit message ID for send/ask, or required message ID for `cancel` |
330
343
  | `supersedes` | string | Optional previous message ID that this send/ask explicitly replaces |
331
344
  | `retryOf` | string | Optional previous message ID that this send/ask explicitly retries |
345
+ | `cwd` | string | Working directory filter for `list-cwd`. For send/ask, scopes target lookup to that directory; without `to`, selects the sole live peer there. |
346
+ | `openProjectPaneIfMissing` | boolean | For `send`/`ask` with `cwd`, open a visible Herdr project pane and launch Selesai when no matching live session exists |
347
+ | `focus` | boolean | For `openProjectPaneIfMissing`, focus the new Herdr pane. Defaults to true |
332
348
 
333
349
  ### contact_supervisor
334
350
 
@@ -350,9 +366,9 @@ Only registered in sessions where `pi-subagents` supplied the required child bri
350
366
 
351
367
  **`list`** — Returns the current session plus other active intercom-connected sessions with name, short ID, working directory, model, and live status. Status is derived automatically from Selesai lifecycle events: `idle`, `thinking`, or `tool:<name>`.
352
368
 
353
- **`send`** — Sends a message to the specified session. By default it sends immediately, including in interactive sessions. Set `confirmSend: true` in config if you want a confirmation dialog for non-reply sends. Replies that include `replyTo` skip confirmation. Returns delivery confirmation.
369
+ **`send`** — Sends a message to the specified session and returns immediately after delivery. If the destination has exactly one pending inbound ask, `send` infers the message is its answer and returns `Reply sent to <target> (inferred from pending ask)`; zero or multiple matches remain unthreaded sends. Set `confirmSend: true` to confirm ordinary and inferred sends. A caller-supplied `replyTo` skips confirmation. `to` alone resolves globally across all live sessions. `cwd` alone targets the sole live peer in that directory. `to` plus `cwd` requires that peer to be in the directory. With `openProjectPaneIfMissing: true`, pi-intercom opens a visible Herdr project pane, starts Selesai there, waits for that session to register, then delivers the message through normal intercom routing.
354
370
 
355
- **`ask`** — Sends a message and waits for the recipient to reply (10-minute timeout by default; configurable with `PI_INTERCOM_ASK_TIMEOUT_MS`). The reply is returned as the tool result. No confirmation dialog. Only one pending `ask` is allowed per session at a time. Use this when the agent needs the answer to continue working.
371
+ **`ask`** — Requires a currently connected recipient, sends a message, and waits for the recipient to reply (10-minute timeout by default; configurable with `PI_INTERCOM_ASK_TIMEOUT_MS`). A disconnected target fails immediately rather than queueing a blocking request. The reply is returned as the tool result. No confirmation dialog. Only one pending `ask` is allowed per session at a time. Use this when the agent needs the answer to continue working. The same `to`, `cwd`, and `openProjectPaneIfMissing` targeting rules apply.
356
372
 
357
373
  **`reply`** — Replies to the current intercom-triggered message if there is one. Otherwise it falls back to the single unresolved inbound ask. If multiple asks are pending, pass `to` or inspect them with `pending` first. Under the hood this is still a normal `send` with the exact `replyTo` value.
358
374
 
@@ -391,13 +407,13 @@ Create `~/.selesai/agent/intercom/config.json`:
391
407
  |---------|---------|-------------|
392
408
  | `brokerCommand` | `"npx"` | Advanced trusted override for the broker executable. The default value is hardened internally to launch the resolved bundled `tsx` CLI through the current Node executable instead of resolving `npx` through `PATH`. |
393
409
  | `brokerArgs` | `["--no-install", "tsx"]` | Advanced trusted arguments passed to custom `brokerCommand` before the broker script path |
394
- | `confirmSend` | false | Show a confirmation dialog before non-reply sends from an interactive session with UI |
410
+ | `confirmSend` | false | Show a confirmation dialog before ordinary or inferred sends from an interactive session with UI; caller-supplied `replyTo` skips it |
395
411
  | `inboundTrigger` | `"always"` | Auto-trigger policy for inbound broker messages: `"always"`, `"replies"`, or `"never"`. Local in-process subagent relay events still trigger the addressed session. |
396
412
  | `enabled` | true | Enable/disable intercom entirely |
397
413
  | `replyHint` | true | Include reply instruction in incoming messages |
398
414
  | `status` | — | Optional custom status suffix shown after the automatic lifecycle status, for example `thinking · researching` |
399
415
 
400
- If `config.json` cannot be parsed or contains an invalid value, pi-intercom logs the error and fails closed for inbound broker auto-triggering by using `inboundTrigger: "never"` until the config is fixed.
416
+ If `config.json` cannot be parsed or contains an invalid value, pi-intercom fails to load the config and throws an error, so the misconfiguration is surfaced immediately instead of silently changing behavior.
401
417
 
402
418
  Custom broker commands are trusted local configuration: anyone who can edit this config can choose the executable used for future broker auto-spawns. For example, if you have Bun installed and want it to start the broker directly, use:
403
419
 
@@ -408,7 +424,7 @@ Custom broker commands are trusted local configuration: anyone who can edit this
408
424
  }
409
425
  ```
410
426
 
411
- pi-intercom publishes live session status automatically. Sessions register as `idle`, switch to `thinking` while the agent is running, show `tool:<name>` during tool execution, and return to `idle` on agent completion. If `status` is set in config, it is appended as context instead of replacing the lifecycle status.
427
+ Pi-intercom publishes live session status automatically. Sessions register as `idle`, switch to `thinking` while the agent is running, show `tool:<name>` during tool execution, and return to `idle` on agent completion. If `status` is set in config, it is appended as context instead of replacing the lifecycle status.
412
428
 
413
429
  By default, runtime state and config live under `~/.selesai/agent/intercom`. If Selesai is launched with `SELESAI_CODING_AGENT_DIR`, pi-intercom uses `$SELESAI_CODING_AGENT_DIR/intercom` instead, including `config.json`, broker PID/lock files, sockets, and launcher state.
414
430
 
@@ -477,9 +493,11 @@ graph TB
477
493
 
478
494
  The broker is a standalone TypeScript process that manages session registration and message routing. It auto-spawns when the first intercom-enabled session needs it and exits after 5 seconds when the last connected session disconnects. Clients now reconnect automatically if the broker disappears and later comes back.
479
495
 
496
+ **Liveness heartbeat.** A client whose broker is killed without a clean shutdown (SIGKILL, crash, or host loss) is left on a half-open socket: the OS never delivers a `close` event, so the client cannot tell it is alone and silently drops out of the roster forever. To close that gap, each registered client runs a liveness heartbeat that round-trips a lightweight `list` request and tears down the socket if the broker does not respond within the timeout, letting the existing `disconnected` → reconnect path fire. The interval defaults to 30s and the probe timeout to 5s; override them with `PI_INTERCOM_LIVENESS_INTERVAL_MS` and `PI_INTERCOM_LIVENESS_TIMEOUT_MS` (the timeout is clamped to the interval).
497
+
480
498
  Messages use length-prefixed JSON over a local socket/pipe transport (4-byte length + JSON payload) to handle fragmentation properly. The protocol includes request correlation for session listing, explicit delivery failures, validation for malformed or out-of-order messages, a frame-size cap, per-connection local rate limiting, and no-op presence coalescing.
481
499
 
482
- Session IDs are the trusted addressing key. Duplicate names remain allowed for same-user workflows, but sends to ambiguous names fail and users should target the stable session ID shown by `list`/`status` in trust-sensitive flows. Mail queued for a disconnected session is redelivered to a session that reconnects under the same session ID, or to a session that matches both its name and its directory, so a same-named session in a different project never inherits another project's queued messages. Set `PI_INTERCOM_STABLE_ID` or `stableId` in `config.json` to pin a session's intercom ID across full process relaunches; `config.json` is machine-global, so a fixed `stableId` there applies to every session on the machine and the newest registration takes over that identity. The broker owns local trust metadata such as `trustedLocal`; `peerUid` is reserved for runtimes that can expose real peer credentials and is left unset otherwise. Client-supplied cwd/model/pid/status are display metadata, not authentication.
500
+ Session IDs are the trusted addressing key. Duplicate names remain allowed for same-user workflows, but sends to ambiguous names fail and users should target the stable session ID shown by `list`/`status` in trust-sensitive flows. Mail queued for a disconnected session is redelivered to a session that reconnects under the same session ID, or to a session that matches both its explicit name and its directory, so a same-named session in a different project never inherits another project's queued messages. Runtime-only `subagent-chat-...` aliases are excluded from name-based mailbox reconnection, and a disconnected mailbox is never remapped to the sender. Set `PI_INTERCOM_STABLE_ID` or `stableId` in `config.json` to pin a session's intercom ID across full process relaunches; `config.json` is machine-global, so a fixed `stableId` there applies to every session on the machine and the newest registration takes over that identity. The broker owns local trust metadata such as `trustedLocal`; `peerUid` is reserved for runtimes that can expose real peer credentials and is left unset otherwise. Client-supplied cwd/model/pid/status are display metadata, not authentication.
483
501
 
484
502
  Async extension work (startup, inbound flushes, reconnects, overlays, and relays) no-ops if the session shuts down or reloads before it settles.
485
503
 
@@ -521,6 +539,7 @@ Use pi-messenger for multi-agent swarms working on a shared task. Use pi-interco
521
539
  ├── index.ts # Extension entry point
522
540
  ├── types.ts # SessionInfo, Message, protocol types
523
541
  ├── config.ts # Config loading
542
+ ├── project-agent.ts # Herdr project-pane launch and cwd target resolution
524
543
  ├── broker/
525
544
  │ ├── broker.ts # Broker process
526
545
  │ ├── client.ts # IntercomClient class
@@ -3,6 +3,7 @@ import { writeFileSync, unlinkSync } from "fs";
3
3
  import { join } from "path";
4
4
  import { randomUUID } from "crypto";
5
5
  import { writeMessage, createMessageReader } from "./framing.ts";
6
+ import { isMessage, isMessageReceipt, isSessionId, isSessionRegistration } from "./protocol.ts";
6
7
  import {
7
8
  ensureIntercomRuntimeDir,
8
9
  getBrokerListenTarget,
@@ -17,7 +18,7 @@ import {
17
18
  import { getAskTimeoutMs } from "../config.ts";
18
19
  import { sameCwd } from "../cwd.ts";
19
20
  import { EXTENSION_BUS_FEATURE } from "../types.ts";
20
- import type { SessionInfo, Message, Attachment, BrokerMessage, SessionRegistration, ExtensionCapability, MessageControl, MessageReceipt, MessageReceiptStatus } from "../types.ts";
21
+ import type { SessionInfo, Message, BrokerMessage, ExtensionCapability, MessageControl } from "../types.ts";
21
22
  import { ExtensionStateManager } from "./extension-state.ts";
22
23
  import { assertNoLiveBroker } from "./runtime-claim.ts";
23
24
 
@@ -93,124 +94,6 @@ interface MailboxMessage {
93
94
  queuedAt: number;
94
95
  }
95
96
 
96
- function isMessageReceiptStatus(value: unknown): value is MessageReceiptStatus {
97
- return value === "receiver_received"
98
- || value === "queued"
99
- || value === "injected"
100
- || value === "acknowledged"
101
- || value === "expired"
102
- || value === "cancelled"
103
- || value === "superseded"
104
- || value === "cancellation_requested";
105
- }
106
-
107
- function isMessageReceipt(value: unknown): value is MessageReceipt {
108
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
109
- return false;
110
- }
111
- const receipt = value as Record<string, unknown>;
112
- if (typeof receipt.messageId !== "string" || !isMessageReceiptStatus(receipt.status) || typeof receipt.timestamp !== "number") {
113
- return false;
114
- }
115
- return receipt.detail === undefined || typeof receipt.detail === "string";
116
- }
117
-
118
- function isAttachment(value: unknown): value is Attachment {
119
- if (typeof value !== "object" || value === null) {
120
- return false;
121
- }
122
-
123
- const attachment = value as Record<string, unknown>;
124
-
125
- if (
126
- attachment.type !== "file"
127
- && attachment.type !== "snippet"
128
- && attachment.type !== "context"
129
- ) {
130
- return false;
131
- }
132
-
133
- if (typeof attachment.name !== "string" || typeof attachment.content !== "string") {
134
- return false;
135
- }
136
-
137
- return attachment.language === undefined || typeof attachment.language === "string";
138
- }
139
-
140
- function isMessage(value: unknown): value is Message {
141
- if (typeof value !== "object" || value === null) {
142
- return false;
143
- }
144
-
145
- const message = value as Record<string, unknown>;
146
-
147
- if (typeof message.id !== "string" || typeof message.timestamp !== "number") {
148
- return false;
149
- }
150
-
151
- for (const key of ["senderSequence", "brokerReceivedAt", "brokerDeliveredAt", "receiverReceivedAt", "injectedAt"] as const) {
152
- if (message[key] !== undefined && typeof message[key] !== "number") {
153
- return false;
154
- }
155
- }
156
-
157
- if (message.supersedes !== undefined && typeof message.supersedes !== "string") {
158
- return false;
159
- }
160
-
161
- if (message.retryOf !== undefined && typeof message.retryOf !== "string") {
162
- return false;
163
- }
164
-
165
- if (message.replyTo !== undefined && typeof message.replyTo !== "string") {
166
- return false;
167
- }
168
-
169
- if (message.expectsReply !== undefined && typeof message.expectsReply !== "boolean") {
170
- return false;
171
- }
172
-
173
- if (typeof message.content !== "object" || message.content === null) {
174
- return false;
175
- }
176
-
177
- const content = message.content as Record<string, unknown>;
178
- if (typeof content.text !== "string") {
179
- return false;
180
- }
181
-
182
- return content.attachments === undefined
183
- || (Array.isArray(content.attachments) && content.attachments.every(isAttachment));
184
- }
185
-
186
- function isSessionId(value: unknown): value is string {
187
- return typeof value === "string" && value.trim().length > 0;
188
- }
189
-
190
- function isSessionRegistration(value: unknown): value is SessionRegistration {
191
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
192
- return false;
193
- }
194
-
195
- const session = value as Record<string, unknown>;
196
-
197
- if (
198
- typeof session.cwd !== "string"
199
- || typeof session.model !== "string"
200
- || typeof session.pid !== "number"
201
- || typeof session.startedAt !== "number"
202
- || typeof session.lastActivity !== "number"
203
- ) {
204
- return false;
205
- }
206
-
207
- if (session.name !== undefined && typeof session.name !== "string") {
208
- return false;
209
- }
210
-
211
- return session.status === undefined || typeof session.status === "string";
212
- }
213
-
214
97
  class IntercomBroker {
215
98
  private sessions = new Map<string, ConnectedSession>();
216
99
  private askEdges = new Map<string, AskEdge>();
@@ -472,6 +355,7 @@ class IntercomBroker {
472
355
  const info: SessionInfo = {
473
356
  id,
474
357
  ...(session.name !== undefined ? { name: session.name } : {}),
358
+ ...(session.runtimeFallbackAlias !== undefined ? { runtimeFallbackAlias: session.runtimeFallbackAlias } : {}),
475
359
  cwd: session.cwd,
476
360
  model: session.model,
477
361
  pid: session.pid,
@@ -745,20 +629,15 @@ class IntercomBroker {
745
629
  });
746
630
  break;
747
631
  }
748
- const liveMailboxTarget = this.findUniqueLiveSessionForDisconnectedSession(target);
749
- const effectiveTargetId = liveMailboxTarget?.info.id ?? target.id;
750
632
  if (message.expectsReply) {
751
- const reverseEdge = Array.from(this.askEdges.entries()).find(([edgeMessageId, edge]) => edgeMessageId !== message.replyTo && edge.from === effectiveTargetId && edge.to === currentId);
752
- if (reverseEdge) {
753
- writeMessage(socket, {
754
- type: "delivery_failed",
755
- messageId: message.id,
756
- reason: "Mutual ask refused: target session is already waiting for a reply from this session.",
757
- });
758
- break;
759
- }
760
- this.askEdges.set(message.id, { from: currentId, to: effectiveTargetId, createdAt: Date.now() });
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
+ });
638
+ break;
761
639
  }
640
+ const liveMailboxTarget = this.findUniqueLiveSessionForDisconnectedSession(target, currentId);
762
641
  if (liveMailboxTarget) {
763
642
  const deliveredMessage: Message = {
764
643
  ...message,
@@ -897,6 +776,15 @@ class IntercomBroker {
897
776
  changed = true;
898
777
  }
899
778
  }
779
+ if (clientMessage.runtimeFallbackAlias !== undefined) {
780
+ if (typeof clientMessage.runtimeFallbackAlias !== "boolean") {
781
+ throw new Error("Invalid presence runtimeFallbackAlias");
782
+ }
783
+ if (session.info.runtimeFallbackAlias !== clientMessage.runtimeFallbackAlias) {
784
+ session.info.runtimeFallbackAlias = clientMessage.runtimeFallbackAlias;
785
+ changed = true;
786
+ }
787
+ }
900
788
  if (clientMessage.status !== undefined) {
901
789
  if (typeof clientMessage.status !== "string") {
902
790
  throw new Error("Invalid presence status");
@@ -1025,9 +913,15 @@ class IntercomBroker {
1025
913
  for (let index = 0; index < this.mailboxMessages.length;) {
1026
914
  const entry = this.mailboxMessages[index]!;
1027
915
  const matchesId = entry.target.id === session.info.id;
916
+ const matchesSenderIdentity = Boolean(
917
+ sessionName
918
+ && entry.from.name?.toLowerCase() === sessionName
919
+ && sameCwd(entry.from.cwd, session.info.cwd),
920
+ );
1028
921
  const matchesUniqueName = Boolean(
1029
922
  uniqueMailboxIdentity
1030
923
  && sessionName
924
+ && !matchesSenderIdentity
1031
925
  && entry.target.name?.toLowerCase() === sessionName
1032
926
  && sameCwd(entry.target.cwd, session.info.cwd),
1033
927
  );
@@ -1125,26 +1019,32 @@ class IntercomBroker {
1125
1019
  .map(([, session]) => session);
1126
1020
  }
1127
1021
 
1128
- private findUniqueLiveSessionForDisconnectedSession(info: SessionInfo): ConnectedSession | null {
1129
- const matches = this.findLiveSessionsSharingMailboxIdentity(info);
1022
+ private findUniqueLiveSessionForDisconnectedSession(info: SessionInfo, senderId?: string): ConnectedSession | null {
1023
+ const matches = this.findLiveSessionsSharingMailboxIdentity(info)
1024
+ .filter((session) => session.info.id !== senderId);
1130
1025
  return matches.length === 1 ? matches[0]! : null;
1131
1026
  }
1132
1027
 
1133
1028
  /**
1134
- * Mailbox identity is name plus directory, never name alone. A name on its own
1135
- * is display metadata that unrelated projects reuse, so matching on it would
1136
- * hand one project's queued mail to a same-named session in another project.
1029
+ * Mailbox identity is an explicit name plus directory, never name alone. A
1030
+ * runtime fallback alias is derived from the session id rather than chosen as
1031
+ * a durable identity, so it must not transfer mail to another process. This
1032
+ * also prevents two unnamed UUIDv7 sessions started close together from
1033
+ * inheriting each other's mailbox through a shared short alias.
1034
+ *
1137
1035
  * Directories compare through sameCwd so a relaunch that reports the same
1138
1036
  * directory differently (trailing slash, "."/"..", or a symlink such as macOS
1139
1037
  * /tmp vs /private/tmp) still matches.
1140
1038
  */
1141
1039
  private findLiveSessionsSharingMailboxIdentity(info: SessionInfo): ConnectedSession[] {
1142
1040
  const lowerName = info.name?.toLowerCase();
1143
- if (!lowerName) {
1041
+ if (!lowerName || info.runtimeFallbackAlias) {
1144
1042
  return [];
1145
1043
  }
1146
1044
  return Array.from(this.sessions.values()).filter(session =>
1147
- session.info.name?.toLowerCase() === lowerName && sameCwd(session.info.cwd, info.cwd)
1045
+ !session.info.runtimeFallbackAlias
1046
+ && session.info.name?.toLowerCase() === lowerName
1047
+ && sameCwd(session.info.cwd, info.cwd)
1148
1048
  );
1149
1049
  }
1150
1050
 
@@ -1228,12 +1128,10 @@ class IntercomBroker {
1228
1128
  const winner = candidates[0];
1229
1129
  const existing = this.namespaceOwners.get(namespace);
1230
1130
 
1231
- // Check if owner changed or socket changed
1232
1131
  const ownerChanged = !existing || existing.sessionId !== winner.sessionId;
1233
1132
  const socketChanged = existing && existing.socket !== winner.session.socket;
1234
1133
 
1235
1134
  if (ownerChanged || socketChanged) {
1236
- // Generate new epoch
1237
1135
  const epoch = randomUUID();
1238
1136
  this.namespaceOwners.set(namespace, {
1239
1137
  sessionId: winner.sessionId,
@@ -1241,7 +1139,6 @@ class IntercomBroker {
1241
1139
  epoch,
1242
1140
  });
1243
1141
 
1244
- // Broadcast owner change to all capable sessions
1245
1142
  for (const session of this.sessions.values()) {
1246
1143
  if (session.extensions?.length) {
1247
1144
  const isCapable = session.extensions.some((ext) => ext.namespace === namespace);
@@ -0,0 +1,173 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import net from "node:net";
4
+ import { once } from "node:events";
5
+ import { mkdtempSync, rmSync } from "node:fs";
6
+ import path from "node:path";
7
+ import { tmpdir } from "node:os";
8
+ import { IntercomClient } from "./client.ts";
9
+ import { writeMessage } from "./framing.ts";
10
+
11
+ /**
12
+ * Unit tests for the half-open socket fix.
13
+ *
14
+ * Bug: when the broker dies without sending a FIN (SIGKILL, crash, host loss),
15
+ * the client's socket stays "writable" indefinitely. isConnected() keeps
16
+ * returning true, no "disconnected" event fires, and the extension's
17
+ * scheduleReconnect() is never called — so the agent silently drops out of the
18
+ * intercom roster forever (this is why long-lived headless/RPC pi agents
19
+ * vanish from `intercom list` after a broker restart).
20
+ *
21
+ * The fix: (1) a socket "error" after registration destroys the socket so the
22
+ * existing onClose -> "disconnected" path runs, and (2) a liveness heartbeat
23
+ * that round-trips a lightweight request and tears down the socket on timeout
24
+ * or write error, so a half-open connection is detected within a bounded
25
+ * window even when the OS never delivers an error.
26
+ */
27
+
28
+ const homeDir = mkdtempSync(path.join(tmpdir(), "pi-intercom-liveness-unit-"));
29
+ const runtimeAgentDir = process.platform === "win32" ? undefined : mkdtempSync("/tmp/piic-");
30
+ const previousHome = process.env.HOME;
31
+ const previousUserProfile = process.env.USERPROFILE;
32
+ const previousAgentDir = process.env.SELESAI_CODING_AGENT_DIR;
33
+ process.env.HOME = homeDir;
34
+ process.env.USERPROFILE = homeDir;
35
+ if (runtimeAgentDir) process.env.SELESAI_CODING_AGENT_DIR = runtimeAgentDir;
36
+ process.env.PI_INTERCOM_LIVENESS_INTERVAL_MS = "100";
37
+ process.env.PI_INTERCOM_LIVENESS_TIMEOUT_MS = "200";
38
+
39
+ test.after(() => {
40
+ process.env.HOME = previousHome;
41
+ process.env.USERPROFILE = previousUserProfile;
42
+ if (previousAgentDir === undefined) delete process.env.SELESAI_CODING_AGENT_DIR;
43
+ else process.env.SELESAI_CODING_AGENT_DIR = previousAgentDir;
44
+ rmSync(homeDir, { recursive: true, force: true });
45
+ if (runtimeAgentDir) rmSync(runtimeAgentDir, { recursive: true, force: true });
46
+ });
47
+
48
+ /**
49
+ * Build a registered IntercomClient wired to a fake server socket pair, so we
50
+ * can simulate a half-open connection without spawning a real broker.
51
+ */
52
+ async function registeredClientAgainstFakeSocket(): Promise<{
53
+ client: IntercomClient;
54
+ serverSide: net.Socket;
55
+ closeServerSideAbruptly(): void;
56
+ stopResponding(): void;
57
+ }> {
58
+ const { getBrokerSocketPath } = await import("./paths.ts");
59
+ const { mkdirSync, unlinkSync } = await import("node:fs");
60
+ const socketPath = getBrokerSocketPath();
61
+ const intercomDir = path.dirname(socketPath);
62
+ mkdirSync(intercomDir, { recursive: true });
63
+ try { unlinkSync(socketPath); } catch { /* no stale socket */ }
64
+
65
+ const client = new IntercomClient();
66
+ let resolveReady: (value: { serverSide: net.Socket; closeServerSideAbruptly(): void; stopResponding(): void }) => void;
67
+ let rejectReady: (reason: unknown) => void;
68
+ const ready = new Promise<{ serverSide: net.Socket; closeServerSideAbruptly(): void; stopResponding(): void }>((res, rej) => {
69
+ resolveReady = res;
70
+ rejectReady = rej;
71
+ });
72
+
73
+ let responding = true;
74
+ const server = net.createServer((serverSide) => {
75
+ serverSide.on("data", (data) => {
76
+ if (!responding) return; // simulate a dead/unresponsive broker: drop everything
77
+ try {
78
+ const len = data.readUInt32BE(0);
79
+ const json = JSON.parse(data.subarray(4, 4 + len).toString("utf-8"));
80
+ if (json.type === "register") {
81
+ writeMessage(serverSide, { type: "registered", sessionId: json.sessionId ?? "stable-test", features: [] });
82
+ }
83
+ if (json.type === "list") {
84
+ writeMessage(serverSide, { type: "sessions", requestId: json.requestId, sessions: [] });
85
+ }
86
+ } catch {
87
+ // ignore parse errors in the fake
88
+ }
89
+ });
90
+ server.close();
91
+ resolveReady({
92
+ serverSide,
93
+ closeServerSideAbruptly() {
94
+ // Destroy WITHOUT a clean FIN — simulates a SIGKILL'd broker peer.
95
+ serverSide.destroy();
96
+ },
97
+ stopResponding() {
98
+ // Simulate a half-open socket: the peer stops reading/replying but the
99
+ // connection is not closed, so no "close"/"error" event reaches the
100
+ // client. Only an active liveness probe can detect this.
101
+ responding = false;
102
+ },
103
+ });
104
+ });
105
+ server.on("error", (err) => rejectReady(err));
106
+ await new Promise<void>((resolve) => server.listen(socketPath, () => resolve()));
107
+
108
+ await client.connect(
109
+ {
110
+ name: "liveness-unit",
111
+ cwd: homeDir,
112
+ model: "test-model",
113
+ pid: process.pid,
114
+ startedAt: Date.now(),
115
+ lastActivity: Date.now(),
116
+ },
117
+ "stable-liveness-unit",
118
+ );
119
+ const { serverSide, closeServerSideAbruptly, stopResponding } = await ready;
120
+ return { client, serverSide, closeServerSideAbruptly, stopResponding };
121
+ }
122
+
123
+ test("client emits disconnected when the peer destroys the socket without a FIN", async () => {
124
+ const { client, closeServerSideAbruptly } = await registeredClientAgainstFakeSocket();
125
+ try {
126
+ assert.equal(client.isConnected(), true, "client should be connected after register");
127
+
128
+ const disconnected = once(client, "disconnected");
129
+ closeServerSideAbruptly();
130
+
131
+ const event = await Promise.race([
132
+ disconnected,
133
+ new Promise<never>((_, reject) =>
134
+ setTimeout(
135
+ () => reject(new Error("client never noticed the abruptly-closed peer (half-open socket)")),
136
+ 3000,
137
+ ),
138
+ ),
139
+ ]);
140
+ assert.ok(event, "expected a disconnected event");
141
+ assert.equal(client.isConnected(), false);
142
+ } finally {
143
+ await client.disconnect().catch(() => undefined);
144
+ }
145
+ });
146
+
147
+ test("client liveness heartbeat detects a half-open socket within a bounded window", async () => {
148
+ const { client, stopResponding } = await registeredClientAgainstFakeSocket();
149
+ try {
150
+ assert.equal(client.isConnected(), true);
151
+
152
+ const disconnected = once(client, "disconnected");
153
+ // Simulate a half-open socket: the peer stops replying but does NOT close
154
+ // the connection. No "close"/"error" event reaches the client, so passive
155
+ // detection cannot fire — only the liveness heartbeat can notice.
156
+ stopResponding();
157
+
158
+ // The heartbeat (interval ~100ms, timeout ~200ms) must notice and tear down.
159
+ const event = await Promise.race([
160
+ disconnected,
161
+ new Promise<never>((_, reject) =>
162
+ setTimeout(
163
+ () => reject(new Error("liveness heartbeat did not detect the half-open socket within 3s")),
164
+ 3000,
165
+ ),
166
+ ),
167
+ ]);
168
+ assert.ok(event, "expected the heartbeat to surface a disconnected event");
169
+ assert.equal(client.isConnected(), false);
170
+ } finally {
171
+ await client.disconnect().catch(() => undefined);
172
+ }
173
+ });