@selesai/code 0.5.28 → 0.5.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/dist/cli/args.d.ts.map +1 -1
  2. package/dist/cli/args.js +9 -1
  3. package/dist/cli/args.js.map +1 -1
  4. package/dist/cli/config-selector.d.ts.map +1 -1
  5. package/dist/cli/config-selector.js +1 -1
  6. package/dist/cli/config-selector.js.map +1 -1
  7. package/dist/cli/credential-print.d.ts +23 -0
  8. package/dist/cli/credential-print.d.ts.map +1 -0
  9. package/dist/cli/credential-print.js +117 -0
  10. package/dist/cli/credential-print.js.map +1 -0
  11. package/dist/cli/startup-ui.d.ts.map +1 -1
  12. package/dist/cli/startup-ui.js +1 -1
  13. package/dist/cli/startup-ui.js.map +1 -1
  14. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  15. package/dist/core/agent-session-runtime.js +3 -0
  16. package/dist/core/agent-session-runtime.js.map +1 -1
  17. package/dist/core/agent-session.d.ts +12 -1
  18. package/dist/core/agent-session.d.ts.map +1 -1
  19. package/dist/core/agent-session.js +20 -14
  20. package/dist/core/agent-session.js.map +1 -1
  21. package/dist/core/compaction/compaction.d.ts.map +1 -1
  22. package/dist/core/compaction/compaction.js +11 -3
  23. package/dist/core/compaction/compaction.js.map +1 -1
  24. package/dist/core/extensions/runner.d.ts +1 -0
  25. package/dist/core/extensions/runner.d.ts.map +1 -1
  26. package/dist/core/extensions/runner.js +11 -0
  27. package/dist/core/extensions/runner.js.map +1 -1
  28. package/dist/core/extensions/types.d.ts +14 -1
  29. package/dist/core/extensions/types.d.ts.map +1 -1
  30. package/dist/core/extensions/types.js.map +1 -1
  31. package/dist/core/footer-data-provider.d.ts +10 -0
  32. package/dist/core/footer-data-provider.d.ts.map +1 -1
  33. package/dist/core/footer-data-provider.js +1 -1
  34. package/dist/core/footer-data-provider.js.map +1 -1
  35. package/dist/core/llama/provider.d.ts.map +1 -1
  36. package/dist/core/llama/provider.js +8 -3
  37. package/dist/core/llama/provider.js.map +1 -1
  38. package/dist/core/model-config.d.ts +30 -0
  39. package/dist/core/model-config.d.ts.map +1 -1
  40. package/dist/core/model-config.js +6 -0
  41. package/dist/core/model-config.js.map +1 -1
  42. package/dist/core/model-registry.d.ts.map +1 -1
  43. package/dist/core/model-registry.js +2 -2
  44. package/dist/core/model-registry.js.map +1 -1
  45. package/dist/core/model-resolver.d.ts +1 -0
  46. package/dist/core/model-resolver.d.ts.map +1 -1
  47. package/dist/core/model-resolver.js +20 -3
  48. package/dist/core/model-resolver.js.map +1 -1
  49. package/dist/core/model-runtime.d.ts +2 -0
  50. package/dist/core/model-runtime.d.ts.map +1 -1
  51. package/dist/core/model-runtime.js +5 -4
  52. package/dist/core/model-runtime.js.map +1 -1
  53. package/dist/core/package-manager.d.ts.map +1 -1
  54. package/dist/core/package-manager.js +13 -6
  55. package/dist/core/package-manager.js.map +1 -1
  56. package/dist/core/remote-catalog-provider.d.ts +1 -1
  57. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  58. package/dist/core/remote-catalog-provider.js +24 -11
  59. package/dist/core/remote-catalog-provider.js.map +1 -1
  60. package/dist/core/resource-loader.d.ts +15 -0
  61. package/dist/core/resource-loader.d.ts.map +1 -1
  62. package/dist/core/resource-loader.js +66 -9
  63. package/dist/core/resource-loader.js.map +1 -1
  64. package/dist/core/settings-manager.d.ts +1 -1
  65. package/dist/core/settings-manager.d.ts.map +1 -1
  66. package/dist/core/settings-manager.js.map +1 -1
  67. package/dist/core/system-prompt.d.ts.map +1 -1
  68. package/dist/core/system-prompt.js +1 -1
  69. package/dist/core/system-prompt.js.map +1 -1
  70. package/dist/core/tools/bash.d.ts +2 -0
  71. package/dist/core/tools/bash.d.ts.map +1 -1
  72. package/dist/core/tools/bash.js +34 -5
  73. package/dist/core/tools/bash.js.map +1 -1
  74. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  75. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  76. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  77. package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
  78. package/dist/extensions/pi-intercom/README.md +102 -39
  79. package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
  80. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
  81. package/dist/extensions/pi-intercom/broker/client.ts +315 -12
  82. package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
  83. package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
  84. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
  85. package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
  86. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
  87. package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
  88. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
  89. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
  90. package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
  91. package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
  92. package/dist/extensions/pi-intercom/config.test.ts +93 -0
  93. package/dist/extensions/pi-intercom/config.ts +55 -6
  94. package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
  95. package/dist/extensions/pi-intercom/cwd.ts +31 -0
  96. package/dist/extensions/pi-intercom/extension-api.ts +44 -0
  97. package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
  98. package/dist/extensions/pi-intercom/format-context.ts +32 -0
  99. package/dist/extensions/pi-intercom/index.ts +742 -145
  100. package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
  101. package/dist/extensions/pi-intercom/package.json +15 -5
  102. package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
  103. package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
  104. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
  105. package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
  106. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
  107. package/dist/extensions/pi-intercom/types.ts +94 -4
  108. package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
  109. package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
  110. package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
  111. package/dist/extensions/pi-subagents/CHANGELOG.md +85 -0
  112. package/dist/extensions/pi-subagents/LICENSE +21 -0
  113. package/dist/extensions/pi-subagents/README.md +146 -52
  114. package/dist/extensions/pi-subagents/agents/architect.md +1 -0
  115. package/dist/extensions/pi-subagents/agents/builder.md +1 -0
  116. package/dist/extensions/pi-subagents/package-lock.json +2 -2
  117. package/dist/extensions/pi-subagents/package.json +3 -3
  118. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  119. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +21 -989
  120. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
  121. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +430 -0
  122. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
  123. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +282 -0
  124. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +71 -30
  125. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
  126. package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
  127. package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
  128. package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
  129. package/dist/extensions/pi-subagents/src/api/preflight.ts +16 -12
  130. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
  131. package/dist/extensions/pi-subagents/src/extension/index.ts +17 -7
  132. package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
  133. package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -6
  134. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +8 -7
  135. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
  136. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
  137. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +63 -16
  138. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
  139. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
  140. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
  141. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
  142. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
  143. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +29 -4
  144. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +29 -6
  145. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
  146. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +372 -28
  147. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
  148. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
  149. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +143 -43
  150. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +527 -247
  151. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
  152. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +426 -123
  153. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +15 -7
  154. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
  155. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
  156. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  157. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
  158. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
  159. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
  160. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
  161. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
  162. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
  163. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
  164. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
  165. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
  166. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
  167. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +1 -1
  168. package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
  169. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
  170. package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
  171. package/dist/extensions/pi-subagents/src/shared/types.ts +155 -10
  172. package/dist/extensions/pi-subagents/src/shared/utils.ts +73 -4
  173. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -0
  174. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
  175. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
  176. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
  177. package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
  178. package/dist/extensions/pi-subagents/src/tui/render.ts +27 -28
  179. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
  180. package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
  181. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
  182. package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
  183. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
  184. package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
  185. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  186. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +348 -7
  187. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
  188. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
  189. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
  190. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +26 -1
  191. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
  192. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +3 -3
  193. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +213 -13
  194. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +34 -0
  195. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
  196. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +118 -12
  197. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +850 -7
  198. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
  199. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
  200. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  201. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
  202. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
  203. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +128 -0
  204. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
  205. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
  206. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
  207. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +102 -0
  208. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
  209. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
  210. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
  211. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
  212. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
  213. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
  214. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +4 -2
  215. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
  216. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
  217. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
  218. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
  219. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +11 -11
  220. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
  221. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
  222. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
  223. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +10 -2
  224. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
  225. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
  226. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
  227. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +46 -0
  228. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
  229. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
  230. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
  231. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
  232. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
  233. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +34 -2
  234. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  235. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
  236. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
  237. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
  238. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
  239. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +3 -0
  240. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +1 -1
  241. package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
  245. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
  246. package/dist/main.d.ts.map +1 -1
  247. package/dist/main.js +43 -0
  248. package/dist/main.js.map +1 -1
  249. package/dist/modes/interactive/components/custom-message.d.ts +3 -1
  250. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  251. package/dist/modes/interactive/components/custom-message.js +10 -2
  252. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  253. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  254. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  255. package/dist/modes/interactive/components/extension-editor.js +16 -46
  256. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  257. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  258. package/dist/modes/interactive/components/model-selector.js +4 -1
  259. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  260. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  261. package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
  262. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  263. package/dist/modes/interactive/external-editor.d.ts +12 -0
  264. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  265. package/dist/modes/interactive/external-editor.js +37 -0
  266. package/dist/modes/interactive/external-editor.js.map +1 -0
  267. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  268. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  269. package/dist/modes/interactive/interactive-mode.js +72 -64
  270. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  271. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  272. package/dist/modes/rpc/rpc-mode.js +14 -0
  273. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  274. package/dist/utils/clipboard.d.ts.map +1 -1
  275. package/dist/utils/clipboard.js +19 -8
  276. package/dist/utils/clipboard.js.map +1 -1
  277. package/dist/utils/version-check.d.ts.map +1 -1
  278. package/dist/utils/version-check.js +1 -1
  279. package/dist/utils/version-check.js.map +1 -1
  280. package/docs/compaction.md +1 -1
  281. package/docs/custom-provider.md +14 -5
  282. package/docs/environment-variables.md +86 -0
  283. package/docs/extensions.md +15 -5
  284. package/docs/index.md +1 -0
  285. package/docs/models.md +9 -2
  286. package/docs/providers.md +21 -2
  287. package/docs/rpc.md +23 -6
  288. package/docs/session-format.md +2 -0
  289. package/docs/settings.md +1 -1
  290. package/docs/usage.md +0 -13
  291. package/examples/extensions/custom-compaction.ts +5 -2
  292. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  293. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  294. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  295. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  296. package/examples/extensions/gondolin/package-lock.json +2 -2
  297. package/examples/extensions/gondolin/package.json +1 -1
  298. package/examples/extensions/handoff.ts +11 -3
  299. package/examples/extensions/message-renderer.ts +3 -3
  300. package/examples/extensions/sandbox/package-lock.json +2 -2
  301. package/examples/extensions/sandbox/package.json +1 -1
  302. package/examples/extensions/summarize.ts +5 -2
  303. package/examples/extensions/with-deps/package-lock.json +2 -2
  304. package/examples/extensions/with-deps/package.json +1 -1
  305. package/examples/sdk/12-full-control.ts +3 -1
  306. package/package.json +15 -6
  307. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
@@ -44,11 +44,15 @@ describe("resolveIntercomBridgeMode", () => {
44
44
 
45
45
  describe("resolveIntercomSessionTarget", () => {
46
46
  it("prefers an explicit session name", () => {
47
- assert.equal(resolveIntercomSessionTarget("planner", "session-12345678"), "planner");
47
+ assert.equal(resolveIntercomSessionTarget("planner", "session-12345678", "session-stableabcdef"), "planner");
48
48
  });
49
49
 
50
50
  it("uses a runtime-only subagent chat alias when unnamed", () => {
51
- assert.equal(resolveIntercomSessionTarget(undefined, "session-12345678"), "subagent-chat-12345678");
51
+ assert.equal(resolveIntercomSessionTarget(undefined, "session-12345678", ""), "subagent-chat-12345678");
52
+ });
53
+
54
+ it("uses the current pi-intercom runtime id for unnamed fallback when present", () => {
55
+ assert.equal(resolveIntercomSessionTarget(undefined, "session-12345678", "session-stableabcdef"), "subagent-chat-stableab");
52
56
  });
53
57
  });
54
58
 
@@ -94,10 +98,21 @@ describe("resolveIntercomBridge", () => {
94
98
  });
95
99
 
96
100
  assert.equal(bridge.active, true);
101
+ assert.equal(bridge.resultDelivery, true);
97
102
  assert.equal(bridge.orchestratorTarget, "main");
98
103
  assert.equal(bridge.extensionDir, NATIVE_INTERCOM_EXTENSION_DIR);
99
104
  });
100
105
 
106
+ it("can disable external grouped-result delivery without disabling supervisor coordination", () => {
107
+ const bridge = resolveIntercomBridge({
108
+ config: { mode: "always", resultDelivery: false },
109
+ context: "fresh",
110
+ orchestratorTarget: "main",
111
+ });
112
+ assert.equal(bridge.active, true);
113
+ assert.equal(bridge.resultDelivery, false);
114
+ });
115
+
101
116
  it("stays inactive for fresh context when mode is fork-only", () => {
102
117
  const bridge = resolveIntercomBridge({
103
118
  config: { mode: "fork-only" },
@@ -144,6 +159,7 @@ describe("applyIntercomBridgeToAgent", () => {
144
159
  const activeBridge: IntercomBridgeState = {
145
160
  active: true,
146
161
  mode: "always",
162
+ resultDelivery: true,
147
163
  orchestratorTarget: "main",
148
164
  extensionDir: NATIVE_INTERCOM_EXTENSION_DIR,
149
165
  instruction: "Intercom orchestration channel:\n- Need a decision or blocked: contact_supervisor({ reason: \"need_decision\", message: \"<question>\" })\n- Blocked/update: contact_supervisor({ reason: \"progress_update\", message: \"UPDATE: <summary>\" })",
@@ -5,7 +5,7 @@ import * as path from "node:path";
5
5
  import { afterEach, describe, it } from "node:test";
6
6
  import registerFanoutChildSubagentExtension from "../../src/extension/fanout-child.ts";
7
7
  import { createSubagentExecutor } from "../../src/runs/foreground/subagent-executor.ts";
8
- import { createNestedRoute, projectNestedEvents, readNestedControlRequests, readNestedControlResults, writeNestedControlRequest, writeNestedControlResult, writeNestedEvent } from "../../src/runs/shared/nested-events.ts";
8
+ import { createNestedRoute, findNestedControlResult, projectNestedEvents, readNestedControlRequests, readNestedControlResults, snapshotNestedEventFiles, writeNestedControlRequest, writeNestedControlResult, writeNestedEvent } from "../../src/runs/shared/nested-events.ts";
9
9
  import {
10
10
  SUBAGENT_CHILD_ENV,
11
11
  SUBAGENT_FANOUT_CHILD_ENV,
@@ -129,6 +129,25 @@ async function waitFor(predicate: () => boolean, timeoutMs = 1_000): Promise<voi
129
129
  }
130
130
 
131
131
  describe("nested control routing", () => {
132
+ it("finds a control result without considering files present before its request", () => {
133
+ const route = createNestedRoute("root-targeted-result");
134
+ routeRoots.push(path.dirname(route.eventSink));
135
+ const requestedAt = Date.now();
136
+ writeNestedControlResult(route, { ts: requestedAt, requestId: "older", targetRunId: "child", ok: true, message: "older result" });
137
+ writeNestedEvent(route, {
138
+ type: "subagent.nested.updated",
139
+ ts: requestedAt + 1,
140
+ parentRunId: route.rootRunId,
141
+ child: { id: "child", parentRunId: route.rootRunId, depth: 1, path: [], state: "running" },
142
+ });
143
+ const ignoredFiles = snapshotNestedEventFiles(route);
144
+ writeNestedControlResult(route, { ts: requestedAt - 1, requestId: "target", targetRunId: "child", ok: true, message: "target result" });
145
+
146
+ assert.equal(findNestedControlResult(route, "target", "child", ignoredFiles)?.message, "target result");
147
+ assert.equal(findNestedControlResult(route, "older", "child", ignoredFiles), undefined);
148
+ assert.equal(readNestedControlResults(route).length, 2);
149
+ });
150
+
132
151
  it("routes interrupt to an explicit nested id through the control inbox", async () => {
133
152
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-nested-control-"));
134
153
  try {
@@ -157,14 +157,18 @@ describe("nested event parsing and projection", () => {
157
157
  ts: 200,
158
158
  parentRunId: "root-run",
159
159
  parentStepIndex: 1,
160
- child: { ...child("nested-a", "running", 200), currentTool: "read" },
160
+ child: {
161
+ ...child("nested-a", "running", 200),
162
+ currentTool: "read",
163
+ runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", ids: ["ext.ok", "bad/path", "ext.ok"], omitted: 1 },
164
+ },
161
165
  });
162
166
  writeNestedEvent(route, {
163
167
  type: "subagent.nested.completed",
164
168
  ts: 300,
165
169
  parentRunId: "root-run",
166
170
  parentStepIndex: 1,
167
- child: child("nested-a", "complete", 300),
171
+ child: { ...child("nested-a", "complete", 300), runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", ids: ["ext.ok", "bad/path", "ext.ok"], omitted: 1 } },
168
172
  });
169
173
 
170
174
  const registry = projectNestedEvents(route);
@@ -172,6 +176,12 @@ describe("nested event parsing and projection", () => {
172
176
  assert.equal(registry.children[0]?.id, "nested-a");
173
177
  assert.equal(registry.children[0]?.state, "complete");
174
178
  assert.equal(registry.children[0]?.steps?.[0]?.agent, "leaf");
179
+ assert.deepEqual(registry.children[0]?.runtimeAcknowledgedExtensions, {
180
+ version: 1,
181
+ source: "child-runtime",
182
+ ids: ["ext.ok"],
183
+ omitted: 1,
184
+ });
175
185
 
176
186
  const job: AsyncJobState = {
177
187
  asyncId: "root-run",
@@ -349,6 +359,24 @@ describe("nested event parsing and projection", () => {
349
359
  assert.equal(summary.steps?.[0]?.processTerminal?.reason, "proof-write-failed");
350
360
  });
351
361
 
362
+ it("sanitizes runtime acknowledged extensions in nested status summaries", () => {
363
+ const summary = nestedSummaryFromAsyncStatus({
364
+ runId: "child-run",
365
+ mode: "single",
366
+ state: "complete",
367
+ startedAt: 1,
368
+ runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", ids: ["/Users/alice/.secret-extension", "ok-ext", "x".repeat(5000)], omitted: 0 } as never,
369
+ steps: [{
370
+ agent: "worker",
371
+ status: "complete",
372
+ runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", ids: ["C:/Users/alice/secret"], omitted: 0 } as never,
373
+ }],
374
+ }, "/tmp/child-run", { id: "child-run", parentRunId: "parent-run", depth: 1, mode: "single", ts: 2 });
375
+
376
+ assert.deepEqual(summary.runtimeAcknowledgedExtensions?.ids, ["ok-ext"]);
377
+ assert.equal(summary.steps?.[0]?.runtimeAcknowledgedExtensions, undefined);
378
+ });
379
+
352
380
  it("removes evicted status files without replaying completed children", () => {
353
381
  const route = trackRoute();
354
382
  for (let index = 0; index < 1000; index++) {
@@ -140,6 +140,12 @@ describe("registerSubagentNotify", () => {
140
140
  assert.equal(sent.length, 1);
141
141
  });
142
142
 
143
+ it("suppresses local delivery after an acknowledged grouped intercom relay", async () => {
144
+ const { notifier, sent } = createPi("session-a");
145
+ assert.equal(await notifier.deliver(completionResult({ id: "intercom-delivered", intercomDelivered: true })), true);
146
+ assert.equal(sent.length, 0);
147
+ });
148
+
143
149
  it("rejects a pending batch when the notifier is disposed", async () => {
144
150
  const clock = createFakeClock();
145
151
  const { notifier, sent } = createBatchingPi(clock);
@@ -466,10 +472,12 @@ describe("completion formatting helpers", () => {
466
472
  notifier.dispose();
467
473
  });
468
474
 
469
- it("buildCompletionDetails derives paused status from state and summary", () => {
475
+ it("buildCompletionDetails derives paused and stopped statuses", () => {
470
476
  assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: false, state: "paused", summary: "Paused after interrupt.", timestamp: 1 }).status, "paused");
471
477
  assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: false, summary: "boom", exitCode: 1, timestamp: 1 }).status, "failed");
472
- assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: true, summary: "ok", exitCode: 0, timestamp: 1 }).status, "completed");
478
+ assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: false, summary: "terminated", exitCode: 1, processSignal: "SIGTERM", timestamp: 1 }).status, "stopped");
479
+ assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: false, summary: "terminated", results: [{ success: false, exitCode: 1, processSignal: "SIGTERM" }], timestamp: 1 }).status, "stopped");
480
+ assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: true, summary: "ok", exitCode: 0, processSignal: "SIGTERM", timestamp: 1 }).status, "completed");
473
481
  });
474
482
 
475
483
  it("buildCompletionDetails falls back to the unknown agent label", () => {
@@ -153,6 +153,28 @@ describe("mapConcurrent", () => {
153
153
  assert.ok(d2 < 20, `worker 2 should start immediately, got ${d2}ms delay`);
154
154
  });
155
155
 
156
+ it("notifies scheduling settlement only after workers outliving an early rejection stop", async () => {
157
+ let release!: () => void;
158
+ const gate = new Promise<void>((resolve) => { release = resolve; });
159
+ const started: number[] = [];
160
+ let schedulingSettled = false;
161
+ const run = mapConcurrent([0, 1, 2], 2, async (item) => {
162
+ started.push(item);
163
+ if (item === 0) throw new Error("early rejection");
164
+ await gate;
165
+ return item;
166
+ }, undefined, () => { schedulingSettled = true; });
167
+
168
+ await assert.rejects(run, /early rejection/);
169
+ assert.equal(schedulingSettled, false);
170
+ release();
171
+ for (let attempt = 0; attempt < 20 && !schedulingSettled; attempt++) {
172
+ await new Promise((resolve) => setTimeout(resolve, 5));
173
+ }
174
+ assert.equal(schedulingSettled, true);
175
+ assert.deepEqual(started, [0, 1, 2]);
176
+ });
177
+
156
178
  it("respects a shared global semaphore across simultaneous calls", async () => {
157
179
  const globalSemaphore = new Semaphore(2);
158
180
  let running = 0;
@@ -23,8 +23,12 @@ import {
23
23
  SUBAGENT_ORCHESTRATOR_SESSION_ID_ENV,
24
24
  SUBAGENT_SUPERVISOR_CHANNEL_DIR_ENV,
25
25
  SUBAGENT_RUN_ID_ENV,
26
+ PI_INTERCOM_STABLE_ID_ENV,
27
+ PI_INTERCOM_SESSION_ID_ENV,
26
28
  applyThinkingSuffix,
27
29
  buildPiArgs,
30
+ projectLaunchResolvedChildExtensions,
31
+ resolvePiLaunchToolPlan,
28
32
  } from "../../src/runs/shared/pi-args.ts";
29
33
 
30
34
  const originalEnv = {
@@ -45,6 +49,10 @@ const originalEnv = {
45
49
  [MCP_DIRECT_CHILD_TOOLS_ENV]: process.env[MCP_DIRECT_CHILD_TOOLS_ENV],
46
50
  [TOOL_BUDGET_ZERO_AUTH_ENV]: process.env[TOOL_BUDGET_ZERO_AUTH_ENV],
47
51
  [SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV]: process.env[SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV],
52
+ [PI_INTERCOM_STABLE_ID_ENV]: process.env[PI_INTERCOM_STABLE_ID_ENV],
53
+ [PI_INTERCOM_SESSION_ID_ENV]: process.env[PI_INTERCOM_SESSION_ID_ENV],
54
+ MCP_HASH_ROOT: process.env.MCP_HASH_ROOT,
55
+ MCP_HASH_TOKEN: process.env.MCP_HASH_TOKEN,
48
56
  };
49
57
  const originalCwd = process.cwd();
50
58
  const tempRoots: string[] = [];
@@ -126,6 +134,29 @@ afterEach(() => {
126
134
  });
127
135
 
128
136
  describe("buildPiArgs session wiring", () => {
137
+ it("projects launch-resolved extension identifiers without raw paths", () => {
138
+ const privateExt = path.join(os.tmpdir(), "private-extension-root", "secret-extension.ts");
139
+ const toolExt = path.join(os.tmpdir(), "tool-extension-root", "tool-extension.ts");
140
+ const plan = resolvePiLaunchToolPlan({
141
+ tools: ["read", toolExt],
142
+ extensions: [privateExt],
143
+ subagentOnlyExtensions: ["package-extension"],
144
+ });
145
+
146
+ const projection = projectLaunchResolvedChildExtensions(plan);
147
+
148
+ assert.equal(projection.version, 1);
149
+ assert.equal(projection.source, "launch-resolved");
150
+ assert.equal(projection.disableAmbientExtensions, true);
151
+ assert.equal(projection.runtime.length, 1);
152
+ assert.equal(projection.configured.length, 3);
153
+ assert.equal(projection.effective.length, 4);
154
+ for (const id of [...projection.runtime, ...projection.configured, ...projection.effective]) {
155
+ assert.match(id, /^sha256:[a-f0-9]{16}$/);
156
+ }
157
+ assert.ok(!JSON.stringify(projection).includes(os.tmpdir()), "projection should not expose raw extension paths");
158
+ });
159
+
129
160
  it("uses --session when sessionFile is provided", () => {
130
161
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-args-session-"));
131
162
  try {
@@ -415,11 +446,24 @@ describe("buildPiArgs system prompt mode wiring", () => {
415
446
 
416
447
  const extensionArgs = args.filter((arg, index) => args[index - 1] === "--extension");
417
448
  assert.ok(extensionArgs.some((arg) => arg.endsWith(path.join("src", "runs", "shared", "subagent-prompt-runtime.ts"))));
449
+ assert.ok(args.includes("--no-context-files"));
418
450
  assert.equal(env.SELESAI_SUBAGENT_CHILD, "1");
419
451
  assert.equal(env.SELESAI_SUBAGENT_INHERIT_PROJECT_CONTEXT, "0");
420
452
  assert.equal(env.SELESAI_SUBAGENT_INHERIT_SKILLS, "1");
421
453
  });
422
454
 
455
+ it("keeps context file loading enabled when project context is inherited", () => {
456
+ const { args } = buildPiArgs({
457
+ baseArgs: ["-p"],
458
+ task: "hello",
459
+ sessionEnabled: false,
460
+ inheritProjectContext: true,
461
+ inheritSkills: true,
462
+ });
463
+
464
+ assert.equal(args.includes("--no-context-files"), false);
465
+ });
466
+
423
467
  it("passes tool budget through env", () => {
424
468
  const { env } = buildPiArgs({
425
469
  baseArgs: ["-p"],
@@ -475,6 +519,8 @@ describe("buildPiArgs system prompt mode wiring", () => {
475
519
  });
476
520
 
477
521
  it("passes child intercom and orchestrator metadata through env", () => {
522
+ process.env[PI_INTERCOM_STABLE_ID_ENV] = "subagent-chat-parent";
523
+ process.env[PI_INTERCOM_SESSION_ID_ENV] = "session-parent-runtime";
478
524
  const { env } = buildPiArgs({
479
525
  baseArgs: ["-p"],
480
526
  task: "hello",
@@ -490,6 +536,8 @@ describe("buildPiArgs system prompt mode wiring", () => {
490
536
  });
491
537
 
492
538
  assert.equal(env.SELESAI_SUBAGENT_INTERCOM_SESSION_NAME, "subagent-worker-78f659a3");
539
+ assert.equal(env[PI_INTERCOM_STABLE_ID_ENV], "subagent-worker-78f659a3");
540
+ assert.equal(env[PI_INTERCOM_SESSION_ID_ENV], undefined);
493
541
  assert.equal(env.SELESAI_SUBAGENT_ORCHESTRATOR_TARGET, "subagent-chat-parent");
494
542
  assert.equal(env[SUBAGENT_ORCHESTRATOR_SESSION_ID_ENV], "session-parent-123");
495
543
  assert.equal(env.SELESAI_SUBAGENT_RUN_ID, "78f659a3");
@@ -499,6 +547,21 @@ describe("buildPiArgs system prompt mode wiring", () => {
499
547
  assert.match(env[SUBAGENT_SUPERVISOR_CHANNEL_DIR_ENV] ?? "", /supervisor-channels/);
500
548
  });
501
549
 
550
+ it("clears inherited pi-intercom identity when no child intercom session name is set", () => {
551
+ process.env[PI_INTERCOM_STABLE_ID_ENV] = "subagent-chat-parent";
552
+ process.env[PI_INTERCOM_SESSION_ID_ENV] = "session-parent-runtime";
553
+ const { env } = buildPiArgs({
554
+ baseArgs: ["-p"],
555
+ task: "hello",
556
+ sessionEnabled: false,
557
+ inheritProjectContext: true,
558
+ inheritSkills: true,
559
+ });
560
+
561
+ assert.equal(env[PI_INTERCOM_STABLE_ID_ENV], undefined);
562
+ assert.equal(env[PI_INTERCOM_SESSION_ID_ENV], undefined);
563
+ });
564
+
502
565
  it("does not create a supervisor channel without an exact parent session id", () => {
503
566
  const { env } = buildPiArgs({
504
567
  baseArgs: ["-p"],
@@ -592,6 +655,46 @@ describe("buildPiArgs system prompt mode wiring", () => {
592
655
  assert.equal(args[args.indexOf("--tools") + 1], "read,bash");
593
656
  });
594
657
 
658
+ it("includes adapter tool filters in MCP cache identity", () => {
659
+ const base = { command: "npx", args: ["browser-mcp"] };
660
+
661
+ assert.notEqual(
662
+ computeMcpServerHash(base),
663
+ computeMcpServerHash({ ...base, includeTools: ["browser_navigate"] }),
664
+ );
665
+ });
666
+
667
+ it("matches pi-mcp-adapter 2.15.0 metadata cache hashes", () => {
668
+ process.env.MCP_HASH_ROOT = "/tmp/mcp-root";
669
+ process.env.MCP_HASH_TOKEN = "token-value";
670
+
671
+ assert.deepEqual(
672
+ [
673
+ computeMcpServerHash({
674
+ command: "npx",
675
+ args: ["-y", "browser-mcp"],
676
+ env: { ROOT: "{env:MCP_HASH_ROOT}", SECRET_COMMAND: "!op read test" },
677
+ cwd: "${MCP_HASH_ROOT}/server",
678
+ exposeResources: false,
679
+ includeTools: ["browser_navigate"],
680
+ excludeTools: ["browser_close"],
681
+ }),
682
+ computeMcpServerHash({
683
+ url: "https://example.test/$env:MCP_HASH_TOKEN",
684
+ headers: { Authorization: "Bearer ${MCP_HASH_TOKEN}", Secret: "!op read test" },
685
+ auth: "bearer",
686
+ bearerTokenEnv: "MCP_HASH_TOKEN",
687
+ }),
688
+ computeMcpServerHash({ socket: "{env:MCP_HASH_ROOT}/rmcp.sock" }),
689
+ ],
690
+ [
691
+ "8af47bd5a801f42bd252789826df883c6f4db6f1d425b82f8561d75063fbe3a8",
692
+ "77db141e556d24c3740a4b4f0cd50d8c23309a28062282cc1ca724207359ef5a",
693
+ "77f7f77a3e8df990d8c78e99ca81508fd8d1f954e814ee7cbfa46719f71eb46b",
694
+ ],
695
+ );
696
+ });
697
+
595
698
  it("augments explicit builtin allowlists with selected direct MCP tool names", () => {
596
699
  const fixture = createMcpFixture();
597
700
  writeMcpFixture(fixture);
@@ -252,6 +252,24 @@ Package skill content.
252
252
  assert.equal(history[1]?.taskHash, taskHash("legacy customer secret"));
253
253
  });
254
254
 
255
+ it("re-sanitizes run history after an external write", () => {
256
+ recordRun("env-agent", "first secret", 0, 1);
257
+ const historyPath = path.join(agentDir, "run-history.jsonl");
258
+ fs.appendFileSync(historyPath, `${JSON.stringify({
259
+ agent: "env-agent",
260
+ task: "externally written secret",
261
+ ts: 2,
262
+ status: "ok",
263
+ duration: 2,
264
+ })}\n`);
265
+
266
+ recordRun("env-agent", "second secret", 0, 3);
267
+
268
+ const rawHistory = fs.readFileSync(historyPath, "utf-8");
269
+ assert.doesNotMatch(rawHistory, /first secret|externally written secret|second secret/);
270
+ assert.equal(loadRunsForAgent("env-agent").length, 3);
271
+ });
272
+
255
273
  it("uses the configured agent dir for subagent bridge instruction files", () => {
256
274
  const instructionPath = path.join(agentDir, "extensions", "subagent", "bridge.md");
257
275
  writeFile(instructionPath, "Native bridge for {orchestratorTarget}");
@@ -153,6 +153,52 @@ Project prompt.
153
153
  }
154
154
  });
155
155
 
156
+ it("resolves agent aliases to the canonical launch contract agent", async () => {
157
+ const cwd = path.join(tempDir, "repo-alias");
158
+ fs.mkdirSync(cwd, { recursive: true });
159
+ writeAgent(path.join(cwd, ".selesai", "agents", "worker.md"), `---
160
+ name: worker
161
+ description: Project worker
162
+ aliases: shipper, worker-alias
163
+ ---
164
+ Project prompt.
165
+ `);
166
+
167
+ const result = await resolveSubagentLaunchContract({
168
+ agent: "shipper",
169
+ cwd,
170
+ task: "Implement the change",
171
+ });
172
+
173
+ assert.equal(result.ok, true);
174
+ assert.equal(result.contract.agent.name, "worker");
175
+ });
176
+
177
+ it("reports alias collisions as ambiguous agents", async () => {
178
+ const cwd = path.join(tempDir, "repo-alias-collision");
179
+ fs.mkdirSync(cwd, { recursive: true });
180
+ writeAgent(path.join(cwd, ".selesai", "agents", "worker.md"), `---
181
+ name: worker
182
+ description: Project worker
183
+ aliases: shared-alias
184
+ ---
185
+ Project prompt.
186
+ `);
187
+ writeAgent(path.join(cwd, ".selesai", "agents", "reviewer.md"), `---
188
+ name: reviewer
189
+ description: Project reviewer
190
+ aliases: shared-alias
191
+ ---
192
+ Review prompt.
193
+ `);
194
+
195
+ const result = await resolveSubagentLaunchContract({ agent: "shared-alias", cwd });
196
+
197
+ assert.equal(result.ok, false);
198
+ assert.equal(result.code, "ambiguous_agent");
199
+ assert.match(result.message, /Ambiguous agent alias 'shared-alias': reviewer, worker|Ambiguous agent alias 'shared-alias': worker, reviewer/);
200
+ });
201
+
156
202
  it("changes definition and launch digests when selected agent content changes", async () => {
157
203
  const cwd = path.join(tempDir, "repo");
158
204
  fs.mkdirSync(cwd, { recursive: true });
@@ -3,7 +3,7 @@ import assert from "node:assert/strict";
3
3
 
4
4
  import { visibleWidth } from "@earendil-works/pi-tui";
5
5
  import { row } from "../../src/tui/render-helpers.ts";
6
- import { renderSubagentResult } from "../../src/tui/render.ts";
6
+ import { renderSubagentResult, truncLine } from "../../src/tui/render.ts";
7
7
 
8
8
  const theme = {
9
9
  fg(_name: string, text: string): string {
@@ -49,6 +49,18 @@ test("row keeps styled multiline content within the available width", () => {
49
49
  assert.doesNotMatch(rendered, /[\r\n\t]/);
50
50
  });
51
51
 
52
+ test("truncLine preserves ANSI styles and resets through the ellipsis", () => {
53
+ assert.equal(truncLine("\u001b[31mabcdef\u001b[0m", 4), "\u001b[31mabc\u001b[31m…");
54
+ assert.equal(truncLine("\u001b[31mab\u001b[0mcdef", 4), "\u001b[31mab\u001b[0mc…");
55
+ assert.equal(truncLine("ab\u001b[xcd", 4), "ab\u001b[…");
56
+ });
57
+
58
+ test("truncLine respects grapheme display width", () => {
59
+ const rendered = truncLine("🙂🙂🙂", 5);
60
+ assert.equal(rendered, "🙂🙂…");
61
+ assert.equal(visibleWidth(rendered), 5);
62
+ });
63
+
52
64
  test("compact chain rendering uses workflow graph spans for dynamic fanout results", () => {
53
65
  const component = renderSubagentResult({
54
66
  content: [{ type: "text", text: "done" }],
@@ -43,13 +43,14 @@ describe("result intercom formatter", () => {
43
43
  assert.match(payload.message, /^subagent results/m);
44
44
  assert.match(payload.message, /Run: run-123/);
45
45
  assert.match(payload.message, /Mode: chain/);
46
- assert.match(payload.message, /Status: failed/);
46
+ assert.match(payload.message, /Process status: failed/);
47
47
  assert.match(payload.message, /Children: 1 completed, 1 failed/);
48
+ assert.match(payload.message, /Outputs: 2 unknown \(semantic adequacy unassessed\)/);
48
49
  assert.match(payload.message, /Chain steps: 4/);
49
50
  assert.match(payload.message, /Intercom targets below identify child sessions used while they were running/);
50
- assert.match(payload.message, /1\. reviewer-a — completed/);
51
+ assert.match(payload.message, /1\. reviewer-a — process completed · output unknown/);
51
52
  assert.match(payload.message, /Run intercom target: subagent-reviewer-a-run-123-1/);
52
- assert.match(payload.message, /2\. reviewer-b — failed/);
53
+ assert.match(payload.message, /2\. reviewer-b — process failed · output unknown/);
53
54
  assert.match(payload.message, /Output artifact: \/tmp\/a\.md/);
54
55
  assert.match(payload.message, /Session: \/tmp\/a-session\.jsonl/);
55
56
  });
@@ -161,6 +162,27 @@ describe("result intercom formatter", () => {
161
162
  assert.match(payload.message, /↳ reviewer — complete \[nested-a\]/);
162
163
  });
163
164
 
165
+ it("separates process failure from output presence and gives salvage guidance", () => {
166
+ const payload = buildSubagentResultIntercomPayload({
167
+ to: "chat",
168
+ runId: "run-salvage",
169
+ mode: "parallel",
170
+ source: "foreground",
171
+ children: [
172
+ { agent: "a", status: "completed", outputState: "present", summary: "answer a" },
173
+ { agent: "b", status: "failed", outputState: "present", summary: "runner crashed after answer b" },
174
+ { agent: "c", status: "failed", outputState: "absent", summary: "startup failed" },
175
+ ],
176
+ });
177
+
178
+ assert.equal(payload.status, "failed");
179
+ assert.equal(payload.children[1]?.outputState, "present");
180
+ assert.match(payload.message, /Process status: failed/);
181
+ assert.match(payload.message, /Outputs: 2 present, 1 absent \(semantic adequacy unassessed\)/);
182
+ assert.match(payload.message, /Inspect that output before retrying/);
183
+ assert.match(payload.message, /2\. b — process failed · output present/);
184
+ });
185
+
164
186
  it("keeps full child summaries inside grouped payloads", () => {
165
187
  const longSummary = `${"x".repeat(2000)}\n${"y".repeat(2000)}`;
166
188
  const payload = buildSubagentResultIntercomPayload({
@@ -217,9 +239,12 @@ describe("result intercom formatter", () => {
217
239
  assert.equal(stripped.results[0]?.truncation, undefined);
218
240
  });
219
241
 
220
- it("resolves paused and detached statuses", () => {
242
+ it("resolves paused, detached, and signal-terminated statuses", () => {
221
243
  assert.equal(resolveSubagentResultStatus({ interrupted: true }), "paused");
222
244
  assert.equal(resolveSubagentResultStatus({ detached: true }), "detached");
245
+ assert.equal(resolveSubagentResultStatus({ processSignal: "SIGTERM", exitCode: 1 }), "stopped");
246
+ assert.equal(resolveSubagentResultStatus({ processSignal: "SIGTERM", exitCode: 1, timedOut: true }), "failed");
247
+ assert.equal(resolveSubagentResultStatus({ processSignal: "SIGTERM", exitCode: 0, success: true }), "completed");
223
248
  assert.equal(resolveSubagentResultStatus({ success: true }), "completed");
224
249
  assert.equal(resolveSubagentResultStatus({ exitCode: 1 }), "failed");
225
250
  });