@selesai/code 0.5.27 → 0.5.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/dist/cli/args.d.ts.map +1 -1
  2. package/dist/cli/args.js +9 -1
  3. package/dist/cli/args.js.map +1 -1
  4. package/dist/cli/config-selector.d.ts.map +1 -1
  5. package/dist/cli/config-selector.js +1 -1
  6. package/dist/cli/config-selector.js.map +1 -1
  7. package/dist/cli/credential-print.d.ts +23 -0
  8. package/dist/cli/credential-print.d.ts.map +1 -0
  9. package/dist/cli/credential-print.js +117 -0
  10. package/dist/cli/credential-print.js.map +1 -0
  11. package/dist/cli/startup-ui.d.ts.map +1 -1
  12. package/dist/cli/startup-ui.js +1 -1
  13. package/dist/cli/startup-ui.js.map +1 -1
  14. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  15. package/dist/core/agent-session-runtime.js +3 -0
  16. package/dist/core/agent-session-runtime.js.map +1 -1
  17. package/dist/core/agent-session.d.ts +12 -1
  18. package/dist/core/agent-session.d.ts.map +1 -1
  19. package/dist/core/agent-session.js +20 -14
  20. package/dist/core/agent-session.js.map +1 -1
  21. package/dist/core/compaction/compaction.d.ts.map +1 -1
  22. package/dist/core/compaction/compaction.js +11 -3
  23. package/dist/core/compaction/compaction.js.map +1 -1
  24. package/dist/core/extensions/runner.d.ts +1 -0
  25. package/dist/core/extensions/runner.d.ts.map +1 -1
  26. package/dist/core/extensions/runner.js +11 -0
  27. package/dist/core/extensions/runner.js.map +1 -1
  28. package/dist/core/extensions/types.d.ts +14 -1
  29. package/dist/core/extensions/types.d.ts.map +1 -1
  30. package/dist/core/extensions/types.js.map +1 -1
  31. package/dist/core/footer-data-provider.d.ts +10 -0
  32. package/dist/core/footer-data-provider.d.ts.map +1 -1
  33. package/dist/core/footer-data-provider.js +1 -1
  34. package/dist/core/footer-data-provider.js.map +1 -1
  35. package/dist/core/llama/provider.d.ts.map +1 -1
  36. package/dist/core/llama/provider.js +8 -3
  37. package/dist/core/llama/provider.js.map +1 -1
  38. package/dist/core/model-config.d.ts +30 -0
  39. package/dist/core/model-config.d.ts.map +1 -1
  40. package/dist/core/model-config.js +6 -0
  41. package/dist/core/model-config.js.map +1 -1
  42. package/dist/core/model-registry.d.ts.map +1 -1
  43. package/dist/core/model-registry.js +2 -2
  44. package/dist/core/model-registry.js.map +1 -1
  45. package/dist/core/model-resolver.d.ts +1 -0
  46. package/dist/core/model-resolver.d.ts.map +1 -1
  47. package/dist/core/model-resolver.js +20 -3
  48. package/dist/core/model-resolver.js.map +1 -1
  49. package/dist/core/model-runtime.d.ts +2 -0
  50. package/dist/core/model-runtime.d.ts.map +1 -1
  51. package/dist/core/model-runtime.js +5 -4
  52. package/dist/core/model-runtime.js.map +1 -1
  53. package/dist/core/package-manager.d.ts.map +1 -1
  54. package/dist/core/package-manager.js +13 -6
  55. package/dist/core/package-manager.js.map +1 -1
  56. package/dist/core/remote-catalog-provider.d.ts +1 -1
  57. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  58. package/dist/core/remote-catalog-provider.js +24 -11
  59. package/dist/core/remote-catalog-provider.js.map +1 -1
  60. package/dist/core/resource-loader.d.ts +15 -0
  61. package/dist/core/resource-loader.d.ts.map +1 -1
  62. package/dist/core/resource-loader.js +66 -9
  63. package/dist/core/resource-loader.js.map +1 -1
  64. package/dist/core/settings-manager.d.ts +1 -1
  65. package/dist/core/settings-manager.d.ts.map +1 -1
  66. package/dist/core/settings-manager.js.map +1 -1
  67. package/dist/core/system-prompt.d.ts.map +1 -1
  68. package/dist/core/system-prompt.js +1 -1
  69. package/dist/core/system-prompt.js.map +1 -1
  70. package/dist/core/tools/bash.d.ts +2 -0
  71. package/dist/core/tools/bash.d.ts.map +1 -1
  72. package/dist/core/tools/bash.js +34 -5
  73. package/dist/core/tools/bash.js.map +1 -1
  74. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  75. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  76. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  77. package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
  78. package/dist/extensions/pi-intercom/README.md +102 -39
  79. package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
  80. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
  81. package/dist/extensions/pi-intercom/broker/client.ts +315 -12
  82. package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
  83. package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
  84. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
  85. package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
  86. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
  87. package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
  88. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
  89. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
  90. package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
  91. package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
  92. package/dist/extensions/pi-intercom/config.test.ts +93 -0
  93. package/dist/extensions/pi-intercom/config.ts +55 -6
  94. package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
  95. package/dist/extensions/pi-intercom/cwd.ts +31 -0
  96. package/dist/extensions/pi-intercom/extension-api.ts +44 -0
  97. package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
  98. package/dist/extensions/pi-intercom/format-context.ts +32 -0
  99. package/dist/extensions/pi-intercom/index.ts +742 -145
  100. package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
  101. package/dist/extensions/pi-intercom/package.json +15 -5
  102. package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
  103. package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
  104. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
  105. package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
  106. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
  107. package/dist/extensions/pi-intercom/types.ts +94 -4
  108. package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
  109. package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
  110. package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
  111. package/dist/extensions/pi-subagents/CHANGELOG.md +85 -0
  112. package/dist/extensions/pi-subagents/LICENSE +21 -0
  113. package/dist/extensions/pi-subagents/README.md +146 -52
  114. package/dist/extensions/pi-subagents/agents/architect.md +1 -0
  115. package/dist/extensions/pi-subagents/agents/builder.md +1 -0
  116. package/dist/extensions/pi-subagents/package-lock.json +2 -2
  117. package/dist/extensions/pi-subagents/package.json +3 -3
  118. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  119. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +21 -989
  120. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
  121. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +430 -0
  122. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
  123. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +282 -0
  124. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +71 -30
  125. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
  126. package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
  127. package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
  128. package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
  129. package/dist/extensions/pi-subagents/src/api/preflight.ts +16 -12
  130. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
  131. package/dist/extensions/pi-subagents/src/extension/index.ts +17 -7
  132. package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
  133. package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -6
  134. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +8 -7
  135. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
  136. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
  137. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +63 -16
  138. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
  139. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
  140. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
  141. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
  142. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
  143. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +29 -4
  144. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +29 -6
  145. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
  146. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +372 -28
  147. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
  148. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
  149. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +143 -43
  150. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +527 -247
  151. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
  152. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +426 -123
  153. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +15 -7
  154. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
  155. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
  156. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  157. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
  158. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
  159. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
  160. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
  161. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
  162. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
  163. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
  164. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
  165. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
  166. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
  167. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +1 -1
  168. package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
  169. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
  170. package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
  171. package/dist/extensions/pi-subagents/src/shared/types.ts +155 -10
  172. package/dist/extensions/pi-subagents/src/shared/utils.ts +73 -4
  173. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -0
  174. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
  175. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
  176. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
  177. package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
  178. package/dist/extensions/pi-subagents/src/tui/render.ts +27 -28
  179. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
  180. package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
  181. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
  182. package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
  183. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
  184. package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
  185. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  186. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +348 -7
  187. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
  188. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
  189. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
  190. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +26 -1
  191. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
  192. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +3 -3
  193. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +213 -13
  194. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +34 -0
  195. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
  196. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +118 -12
  197. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +850 -7
  198. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
  199. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
  200. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  201. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
  202. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
  203. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +128 -0
  204. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
  205. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
  206. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
  207. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +102 -0
  208. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
  209. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
  210. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
  211. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
  212. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
  213. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
  214. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +4 -2
  215. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
  216. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
  217. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
  218. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
  219. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +11 -11
  220. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
  221. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
  222. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
  223. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +10 -2
  224. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
  225. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
  226. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
  227. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +46 -0
  228. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
  229. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
  230. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
  231. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
  232. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
  233. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +34 -2
  234. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  235. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
  236. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
  237. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
  238. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
  239. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +3 -0
  240. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +1 -1
  241. package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
  245. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
  246. package/dist/extensions/question/index.ts +14 -1
  247. package/dist/extensions/question/tests/wizard.test.ts +11 -8
  248. package/dist/main.d.ts.map +1 -1
  249. package/dist/main.js +43 -0
  250. package/dist/main.js.map +1 -1
  251. package/dist/modes/interactive/components/custom-message.d.ts +3 -1
  252. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  253. package/dist/modes/interactive/components/custom-message.js +10 -2
  254. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  255. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  256. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  257. package/dist/modes/interactive/components/extension-editor.js +16 -46
  258. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  259. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  260. package/dist/modes/interactive/components/model-selector.js +4 -1
  261. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  262. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  263. package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
  264. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  265. package/dist/modes/interactive/external-editor.d.ts +12 -0
  266. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  267. package/dist/modes/interactive/external-editor.js +37 -0
  268. package/dist/modes/interactive/external-editor.js.map +1 -0
  269. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  270. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  271. package/dist/modes/interactive/interactive-mode.js +72 -64
  272. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  273. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  274. package/dist/modes/rpc/rpc-mode.js +14 -0
  275. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  276. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  277. package/dist/utils/clipboard.d.ts.map +1 -1
  278. package/dist/utils/clipboard.js +19 -8
  279. package/dist/utils/clipboard.js.map +1 -1
  280. package/dist/utils/version-check.d.ts.map +1 -1
  281. package/dist/utils/version-check.js +1 -1
  282. package/dist/utils/version-check.js.map +1 -1
  283. package/docs/compaction.md +1 -1
  284. package/docs/custom-provider.md +14 -5
  285. package/docs/environment-variables.md +86 -0
  286. package/docs/extensions.md +15 -5
  287. package/docs/index.md +1 -0
  288. package/docs/models.md +9 -2
  289. package/docs/providers.md +21 -2
  290. package/docs/rpc.md +23 -6
  291. package/docs/session-format.md +2 -0
  292. package/docs/settings.md +1 -1
  293. package/docs/usage.md +0 -13
  294. package/examples/extensions/custom-compaction.ts +5 -2
  295. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  296. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  297. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  298. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  299. package/examples/extensions/gondolin/package-lock.json +2 -2
  300. package/examples/extensions/gondolin/package.json +1 -1
  301. package/examples/extensions/handoff.ts +11 -3
  302. package/examples/extensions/message-renderer.ts +3 -3
  303. package/examples/extensions/sandbox/package-lock.json +2 -2
  304. package/examples/extensions/sandbox/package.json +1 -1
  305. package/examples/extensions/summarize.ts +5 -2
  306. package/examples/extensions/with-deps/package-lock.json +2 -2
  307. package/examples/extensions/with-deps/package.json +1 -1
  308. package/examples/sdk/12-full-control.ts +3 -1
  309. package/package.json +15 -6
  310. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
@@ -1,6 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { describe, it } from "node:test";
3
- import { Editor, visibleWidth } from "@earendil-works/pi-tui";
3
+ import { Editor, type EditorComponent, visibleWidth } from "@earendil-works/pi-tui";
4
4
  import type { ExtensionContext } from "@selesai/code";
5
5
  import type { SubagentState } from "../../src/shared/types.ts";
6
6
  import { collectFleetSnapshot } from "../../src/tui/fleet.ts";
@@ -10,6 +10,7 @@ import {
10
10
  collectFleetStatusEntries,
11
11
  formatFleetElapsed,
12
12
  formatFleetTokens,
13
+ resolveFleetViewPlacement,
13
14
  } from "../../src/tui/fleet-status.ts";
14
15
 
15
16
  function stateForTest(): SubagentState {
@@ -45,6 +46,13 @@ describe("below-editor subagent FleetView", () => {
45
46
  assert.equal(formatFleetTokens(1_250_000), "↓ 1.3M tokens");
46
47
  });
47
48
 
49
+ it("resolves configured FleetView placement with a below-editor fallback", () => {
50
+ assert.equal(resolveFleetViewPlacement(undefined), "belowEditor");
51
+ assert.equal(resolveFleetViewPlacement("belowEditor"), "belowEditor");
52
+ assert.equal(resolveFleetViewPlacement("aboveEditor"), "aboveEditor");
53
+ assert.equal(resolveFleetViewPlacement("side"), "belowEditor");
54
+ });
55
+
48
56
  it("renders main plus active children below the editor and bounds every line", () => {
49
57
  const state = stateForTest();
50
58
  const now = Date.now();
@@ -56,6 +64,7 @@ describe("below-editor subagent FleetView", () => {
56
64
  updatedAt: now,
57
65
  currentAgent: `worker-${index}`,
58
66
  description: index === 0 ? "Inspect\nmodule 0" : `Inspect module ${index}`,
67
+ ...(index === 0 ? { model: "anthropic/fable-5", thinking: "low" } : {}),
59
68
  tokens: index === 0 ? 13_100 : index,
60
69
  });
61
70
  }
@@ -85,7 +94,7 @@ describe("below-editor subagent FleetView", () => {
85
94
  const component = widgetFactory!({ requestRender() {} }, theme);
86
95
  const lines = component.render(80);
87
96
  assert.ok(lines.some((line) => line.includes("⏺ main")));
88
- assert.ok(lines.some((line) => line.includes("worker-0") && line.includes("Inspect module 0")));
97
+ assert.ok(lines.some((line) => line.includes("worker-0 (fable-5 · thinking low)") && line.includes("Inspect module 0")));
89
98
  assert.ok(lines.some((line) => line.includes("11s · ↓ 13.1k tokens")));
90
99
  assert.ok(lines.some((line) => line.includes("↓ 2 more")));
91
100
  for (const line of lines) assert.ok(visibleWidth(line) <= 80, `line exceeded width: ${line}`);
@@ -94,6 +103,143 @@ describe("below-editor subagent FleetView", () => {
94
103
  }
95
104
  });
96
105
 
106
+ it("registers above the editor when configured", () => {
107
+ const state = stateForTest();
108
+ state.foregroundControls.set("run-worker", {
109
+ runId: "run-worker",
110
+ mode: "single",
111
+ startedAt: 10,
112
+ updatedAt: 20,
113
+ currentAgent: "worker",
114
+ });
115
+ let placement: string | undefined;
116
+ const ctx = {
117
+ hasUI: true,
118
+ ui: {
119
+ setWidget(_key: string, content: unknown, options?: { placement?: string }) {
120
+ if (content) placement = options?.placement;
121
+ },
122
+ onTerminalInput() { return () => {}; },
123
+ getEditorText() { return ""; },
124
+ notify() {},
125
+ theme,
126
+ },
127
+ } as unknown as ExtensionContext;
128
+ const fleet = new SubagentFleetStatus(state, () => {}, { refreshMs: 60_000, placement: "aboveEditor" });
129
+ try {
130
+ fleet.setContext(ctx);
131
+ assert.equal(placement, "aboveEditor");
132
+ } finally {
133
+ fleet.dispose();
134
+ }
135
+ });
136
+
137
+ it("stops refreshing when the captured extension context becomes stale", () => {
138
+ const state = stateForTest();
139
+ state.foregroundControls.set("run-worker", {
140
+ runId: "run-worker",
141
+ mode: "single",
142
+ startedAt: 10,
143
+ updatedAt: 20,
144
+ currentAgent: "worker",
145
+ });
146
+ let stale = false;
147
+ let contextReads = 0;
148
+ let inputUnsubscribes = 0;
149
+ let widgetRemovals = 0;
150
+ const ctx = {
151
+ get hasUI() {
152
+ contextReads++;
153
+ if (stale) {
154
+ throw new Error("This extension ctx is stale after session replacement or reload.");
155
+ }
156
+ return true;
157
+ },
158
+ ui: {
159
+ setWidget(_key: string, content: unknown) {
160
+ if (content === undefined) widgetRemovals++;
161
+ },
162
+ onTerminalInput() { return () => { inputUnsubscribes++; }; },
163
+ getEditorText() { return ""; },
164
+ notify() {},
165
+ theme,
166
+ },
167
+ } as unknown as ExtensionContext;
168
+ const fleet = new SubagentFleetStatus(state, () => {}, { refreshMs: 60_000 });
169
+ try {
170
+ fleet.setContext(ctx);
171
+ stale = true;
172
+ assert.doesNotThrow(() => fleet.refresh());
173
+ assert.equal(inputUnsubscribes, 1);
174
+ assert.equal(widgetRemovals, 1);
175
+ assert.equal((fleet as unknown as { timer?: unknown }).timer, undefined);
176
+ const readsAfterStaleRefresh = contextReads;
177
+ fleet.refresh();
178
+ assert.equal(contextReads, readsAfterStaleRefresh, "later refreshes must not reuse the stale context");
179
+ } finally {
180
+ fleet.dispose();
181
+ }
182
+ });
183
+
184
+ it("does not swallow unrelated widget cleanup errors", () => {
185
+ const state = stateForTest();
186
+ state.foregroundControls.set("run-worker", {
187
+ runId: "run-worker",
188
+ mode: "single",
189
+ startedAt: 10,
190
+ updatedAt: 20,
191
+ currentAgent: "worker",
192
+ });
193
+ const ctx = {
194
+ hasUI: true,
195
+ ui: {
196
+ setWidget(_key: string, content: unknown) {
197
+ if (content === undefined) throw new Error("widget cleanup failed");
198
+ },
199
+ onTerminalInput() { return () => {}; },
200
+ getEditorText() { return ""; },
201
+ notify() {},
202
+ theme,
203
+ },
204
+ } as unknown as ExtensionContext;
205
+ const fleet = new SubagentFleetStatus(state, () => {}, { refreshMs: 60_000 });
206
+ fleet.setContext(ctx);
207
+ assert.throws(() => fleet.dispose(), /widget cleanup failed/);
208
+ });
209
+
210
+ it("preserves multiple unrelated UI cleanup errors", () => {
211
+ const state = stateForTest();
212
+ state.foregroundControls.set("run-worker", {
213
+ runId: "run-worker",
214
+ mode: "single",
215
+ startedAt: 10,
216
+ updatedAt: 20,
217
+ currentAgent: "worker",
218
+ });
219
+ const ctx = {
220
+ hasUI: true,
221
+ ui: {
222
+ setWidget(_key: string, content: unknown) {
223
+ if (content === undefined) throw new Error("widget cleanup failed");
224
+ },
225
+ onTerminalInput() {
226
+ return () => { throw new Error("input cleanup failed"); };
227
+ },
228
+ getEditorText() { return ""; },
229
+ notify() {},
230
+ theme,
231
+ },
232
+ } as unknown as ExtensionContext;
233
+ const fleet = new SubagentFleetStatus(state, () => {}, { refreshMs: 60_000 });
234
+ fleet.setContext(ctx);
235
+ assert.throws(
236
+ () => fleet.dispose(),
237
+ (error: unknown) => error instanceof AggregateError
238
+ && error.errors.map(String).join("\n").includes("input cleanup failed")
239
+ && error.errors.map(String).join("\n").includes("widget cleanup failed"),
240
+ );
241
+ });
242
+
97
243
  it("keeps widget ownership through invalidation so an empty refresh removes it", () => {
98
244
  const state = stateForTest();
99
245
  state.foregroundControls.set("run-worker", {
@@ -268,8 +414,8 @@ describe("below-editor subagent FleetView", () => {
268
414
  startedAt: 100,
269
415
  updatedAt: 200,
270
416
  steps: [
271
- { agent: "reviewer", index: 0, status: "running", startedAt: 120, tokens: { input: 4_000, output: 200, total: 4_200 } },
272
- { agent: "worker", index: 1, status: "complete", tokens: { input: 100, output: 20, total: 120 } },
417
+ { agent: "reviewer", index: 0, status: "running", description: "Review only authentication", startedAt: 120, model: "openai/gpt-5", thinking: "medium", tokens: { input: 4_000, output: 200, total: 4_200 } },
418
+ { agent: "worker", index: 1, status: "running", description: "Implement only billing", startedAt: 121, tokens: { input: 100, output: 20, total: 120 } },
273
419
  ],
274
420
  });
275
421
  const fleet = new SubagentFleetStatus(state, () => {}, { refreshMs: 60_000 });
@@ -288,9 +434,10 @@ describe("below-editor subagent FleetView", () => {
288
434
  try {
289
435
  fleet.setContext(ctx);
290
436
  const lines = widgetFactory!({ requestRender() {} }, theme).render(100);
291
- assert.ok(lines.some((line) => line.includes("reviewer") && line.includes("Review the authentication changes")));
437
+ assert.ok(lines.some((line) => line.includes("reviewer (gpt-5 · thinking medium)") && line.includes("Review only authentication")));
438
+ assert.ok(lines.some((line) => line.includes("worker") && line.includes("Implement only billing")));
439
+ assert.ok(lines.every((line) => !line.includes("Review the authentication changes")), "per-child descriptions should replace the run-level fallback when present");
292
440
  assert.ok(lines.some((line) => line.includes("↓ 4.2k tokens")));
293
- assert.ok(!lines.some((line) => line.includes("worker")), "completed async children should leave the status fleet");
294
441
  } finally {
295
442
  fleet.dispose();
296
443
  }
@@ -331,11 +478,32 @@ describe("below-editor subagent FleetView", () => {
331
478
 
332
479
  assert.equal(inputHandler!("\x1b[B"), undefined, "non-empty editor should retain Down");
333
480
  editorText = "";
334
- tui.focusedComponent = {} as Editor;
481
+ tui.focusedComponent = {
482
+ render() { return []; },
483
+ invalidate() {},
484
+ handleInput() {},
485
+ } as unknown as Editor;
335
486
  assert.equal(inputHandler!("\x1b[B"), undefined, "non-editor focus should retain Down");
487
+
488
+ const crossModuleCustomEditor = {
489
+ render() { return []; },
490
+ invalidate() {},
491
+ handleInput() {},
492
+ getText() { return ""; },
493
+ setText() {},
494
+ } satisfies EditorComponent;
495
+ assert.equal(crossModuleCustomEditor instanceof Editor, false, "regression setup must cross the instanceof boundary");
496
+ tui.focusedComponent = crossModuleCustomEditor as unknown as Editor;
497
+ assert.equal(inputHandler!("j"), undefined, "inactive FleetView should retain printable navigation keys");
498
+ assert.equal(inputHandler!("k"), undefined, "inactive FleetView should retain printable navigation keys");
499
+ assert.deepEqual(inputHandler!("\x1b[B"), { consume: true }, "custom editors should activate FleetView across jiti boundaries");
500
+ assert.deepEqual(inputHandler!("j"), { consume: true }, "active FleetView should navigate down with j");
501
+ assert.ok(component.render(100).some((line) => line.includes("⏺ worker")));
502
+ assert.deepEqual(inputHandler!("k"), { consume: true }, "active FleetView should navigate up with k");
503
+ assert.ok(component.render(100).some((line) => line.includes("⏺ main")));
504
+
336
505
  tui.focusedComponent = Object.create(Editor.prototype) as Editor;
337
506
  assert.deepEqual(inputHandler!("\x1b[B"), { consume: true });
338
- assert.deepEqual(inputHandler!("\x1b[B"), { consume: true });
339
507
  assert.ok(component.render(100).some((line) => line.includes("⏺ worker")));
340
508
  assert.deepEqual(inputHandler!("\r"), { consume: true });
341
509
  await Promise.resolve();
@@ -368,7 +368,7 @@ describe("native subagent fleet", () => {
368
368
  currentIndex: 1,
369
369
  description: "Review the active task",
370
370
  activeChildren: new Map([
371
- [0, { index: 0, agent: "worker", description: "Implement the active task", startedAt: now - 900, updatedAt: now - 100, tokens: 120 }],
371
+ [0, { index: 0, agent: "worker", description: "Implement the active task", startedAt: now - 900, updatedAt: now - 100, tokens: 120, model: "provider/live-model", thinking: "high" }],
372
372
  [1, { index: 1, agent: "reviewer", description: "Review the active task", startedAt: now - 800, updatedAt: now, tokens: 240 }],
373
373
  ]),
374
374
  });
@@ -388,6 +388,7 @@ describe("native subagent fleet", () => {
388
388
  assert.ok(lines.some((line) => line.includes("worker")));
389
389
  assert.ok(lines.some((line) => line.includes("reviewer")));
390
390
  assert.ok(lines.some((line) => line.includes("foreground · live")));
391
+ assert.ok(lines.some((line) => line.includes("live-model · thinking high")));
391
392
  assert.ok(lines.some((line) => line.includes("Task") && line.includes("Implement the active task")));
392
393
  assert.ok(lines.some((line) => line.includes("Conversation") && line.includes("assistant response")));
393
394
  assert.ok(lines.some((line) => line.includes("Worker live result")));
@@ -442,7 +443,7 @@ describe("native subagent fleet", () => {
442
443
  cwd: baseCwd,
443
444
  sessionId: "session-current",
444
445
  updatedAt: 200,
445
- children: [{ agent: "reviewer", index: 0, status: "completed", transcriptPath: recentTranscript }],
446
+ children: [{ agent: "reviewer", index: 0, status: "completed", transcriptPath: recentTranscript, model: "provider/recent-model", thinking: "xhigh" }],
446
447
  });
447
448
  state.asyncJobs.set(asyncId, {
448
449
  asyncId,
@@ -469,7 +470,11 @@ describe("native subagent fleet", () => {
469
470
  { initialKey, refreshMs: 60_000, markdownTheme },
470
471
  );
471
472
  try {
472
- assert.ok(component.render(100).some((line) => line.includes(expected)), `missing ${expected}`);
473
+ const lines = component.render(100);
474
+ assert.ok(lines.some((line) => line.includes(expected)), `missing ${expected}`);
475
+ if (initialKey.startsWith("foreground-recent:")) {
476
+ assert.ok(lines.some((line) => line.includes("recent-model · thinking xhigh")));
477
+ }
473
478
  } finally {
474
479
  component.dispose();
475
480
  }
@@ -506,7 +511,7 @@ describe("native subagent fleet", () => {
506
511
  assert.equal(state.fleetInspectorOpen, false);
507
512
  });
508
513
 
509
- it("opens the inspector with the FleetView-selected child focused", () => {
514
+ it("focuses the selected child and renders raw foreground model details", () => {
510
515
  const state = stateForTest();
511
516
  state.foregroundControls.set("run-worker", {
512
517
  runId: "run-worker",
@@ -515,6 +520,8 @@ describe("native subagent fleet", () => {
515
520
  updatedAt: 20,
516
521
  currentAgent: "worker",
517
522
  currentIndex: 0,
523
+ model: "provider/raw-model",
524
+ thinking: "medium",
518
525
  });
519
526
  state.foregroundControls.set("run-reviewer", {
520
527
  runId: "run-reviewer",
@@ -524,6 +531,14 @@ describe("native subagent fleet", () => {
524
531
  currentAgent: "reviewer",
525
532
  currentIndex: 0,
526
533
  });
534
+ state.foregroundRuns!.set("run-recent", {
535
+ runId: "run-recent",
536
+ mode: "single",
537
+ cwd: process.cwd(),
538
+ sessionId: "session-current",
539
+ updatedAt: 19,
540
+ children: [{ agent: "reviewer", index: 0, status: "completed", model: "provider/recent-raw-model", thinking: "xhigh" }],
541
+ });
527
542
  const component = new SubagentFleetComponent(
528
543
  { terminal: { rows: 28, columns: 90 }, requestRender() {} } as never,
529
544
  theme as never,
@@ -532,11 +547,148 @@ describe("native subagent fleet", () => {
532
547
  { initialKey: "foreground-active:run-worker:0", refreshMs: 60_000 },
533
548
  );
534
549
  try {
535
- const selectedLine = component.render(90).find((line) => line.includes("›"));
550
+ const lines = component.render(90);
551
+ const selectedLine = lines.find((line) => line.includes("›"));
536
552
  assert.ok(selectedLine?.includes("run-work"), `unexpected selected row: ${selectedLine}`);
553
+ assert.ok(lines.some((line) => line.includes("Model: raw-model · thinking medium")));
537
554
  } finally {
538
555
  component.dispose();
539
556
  }
557
+
558
+ const recentComponent = new SubagentFleetComponent(
559
+ { terminal: { rows: 28, columns: 90 }, requestRender() {} } as never,
560
+ theme as never,
561
+ state,
562
+ () => {},
563
+ { initialKey: "foreground-recent:run-recent:0", refreshMs: 60_000 },
564
+ );
565
+ try {
566
+ assert.ok(recentComponent.render(90).some((line) => line.includes("Model: recent-raw-model · thinking xhigh")));
567
+ } finally {
568
+ recentComponent.dispose();
569
+ }
570
+ });
571
+
572
+ it("steers the selected async child with an inline message", async () => {
573
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-steer-"));
574
+ try {
575
+ const asyncDir = writeAsyncRun(root, { id: "async-steer", agents: ["worker", "reviewer"] });
576
+ const state = stateForTest();
577
+ const calls: Array<{ runId: string; asyncDir: string; index?: number; message: string }> = [];
578
+ const component = new SubagentFleetComponent(
579
+ { terminal: { rows: 28, columns: 100 }, requestRender() {} } as never,
580
+ theme as never,
581
+ state,
582
+ () => {},
583
+ {
584
+ asyncDirRoot: root,
585
+ resultsDir: path.join(root, "results"),
586
+ initialKey: "async:async-steer:0",
587
+ refreshMs: 60_000,
588
+ actions: {
589
+ async steer(input) {
590
+ calls.push(input);
591
+ return { text: "Steering queued." };
592
+ },
593
+ stop() {
594
+ return { text: "unused" };
595
+ },
596
+ },
597
+ },
598
+ );
599
+ try {
600
+ component.handleInput("s");
601
+ assert.ok(component.render(100).some((line) => line.includes("Steer message:")));
602
+ for (const char of "please continue") component.handleInput(char);
603
+ component.handleInput("\r");
604
+ await new Promise((resolve) => setImmediate(resolve));
605
+ assert.deepEqual(calls, [{ runId: "async-steer", asyncDir, index: 0, message: "please continue" }]);
606
+ assert.ok(component.render(100).some((line) => line.includes("Steering queued.")));
607
+ } finally {
608
+ component.dispose();
609
+ }
610
+ } finally {
611
+ fs.rmSync(root, { recursive: true, force: true });
612
+ }
613
+ });
614
+
615
+ it("confirms stop for the selected async child before calling the action", async () => {
616
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-stop-"));
617
+ try {
618
+ const asyncDir = writeAsyncRun(root, { id: "async-stop" });
619
+ const state = stateForTest();
620
+ const calls: Array<{ runId: string; asyncDir: string; index?: number }> = [];
621
+ const component = new SubagentFleetComponent(
622
+ { terminal: { rows: 28, columns: 100 }, requestRender() {} } as never,
623
+ theme as never,
624
+ state,
625
+ () => {},
626
+ {
627
+ asyncDirRoot: root,
628
+ resultsDir: path.join(root, "results"),
629
+ refreshMs: 60_000,
630
+ actions: {
631
+ async steer() {
632
+ return { text: "unused" };
633
+ },
634
+ stop(input) {
635
+ calls.push(input);
636
+ return { text: "Stop requested." };
637
+ },
638
+ },
639
+ },
640
+ );
641
+ try {
642
+ component.handleInput("D");
643
+ assert.ok(component.render(100).some((line) => line.includes("Confirm stop for async run async-stop")));
644
+ component.handleInput("n");
645
+ assert.deepEqual(calls, []);
646
+ component.handleInput("D");
647
+ component.handleInput("y");
648
+ await new Promise((resolve) => setImmediate(resolve));
649
+ assert.deepEqual(calls, [{ runId: "async-stop", asyncDir, index: 0 }]);
650
+ assert.ok(component.render(100).some((line) => line.includes("Stop requested.")));
651
+ } finally {
652
+ component.dispose();
653
+ }
654
+ } finally {
655
+ fs.rmSync(root, { recursive: true, force: true });
656
+ }
657
+ });
658
+
659
+ it("explains unavailable controls for completed async children", () => {
660
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-unavailable-"));
661
+ try {
662
+ writeAsyncRun(root, { id: "async-complete", state: "complete" });
663
+ const state = stateForTest();
664
+ const component = new SubagentFleetComponent(
665
+ { terminal: { rows: 28, columns: 100 }, requestRender() {} } as never,
666
+ theme as never,
667
+ state,
668
+ () => {},
669
+ {
670
+ asyncDirRoot: root,
671
+ resultsDir: path.join(root, "results"),
672
+ refreshMs: 60_000,
673
+ actions: {
674
+ async steer() {
675
+ return { text: "unused" };
676
+ },
677
+ stop() {
678
+ return { text: "unused" };
679
+ },
680
+ },
681
+ },
682
+ );
683
+ try {
684
+ component.handleInput("s");
685
+ assert.ok(component.render(100).some((line) => line.includes("Selected child is complete")));
686
+ } finally {
687
+ component.dispose();
688
+ }
689
+ } finally {
690
+ fs.rmSync(root, { recursive: true, force: true });
691
+ }
540
692
  });
541
693
 
542
694
  it("refreshes the roster while the inspector remains open", async () => {
@@ -552,6 +704,12 @@ describe("native subagent fleet", () => {
552
704
  () => {},
553
705
  { asyncDirRoot: root, resultsDir: path.join(root, "results"), refreshMs: 10 },
554
706
  );
707
+ let invalidations = 0;
708
+ const originalInvalidate = component.invalidate.bind(component);
709
+ component.invalidate = () => {
710
+ invalidations++;
711
+ originalInvalidate();
712
+ };
555
713
  try {
556
714
  assert.ok(component.render(90).some((line) => line.includes("No tracked children")));
557
715
  const initialOutput = Array.from({ length: 40 }, (_, index) => `output line ${index}`).join("\n");
@@ -565,6 +723,7 @@ describe("native subagent fleet", () => {
565
723
  lines = component.render(90);
566
724
  assert.ok(lines.some((line) => line.includes("LATEST LIVE OUTPUT")), "live transcript should keep following new output");
567
725
  assert.ok(renderRequests > 0);
726
+ assert.ok(invalidations > 0, "live refresh must invalidate cached TUI frames before rendering");
568
727
  } finally {
569
728
  component.dispose();
570
729
  }
@@ -1,7 +1,14 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { describe, it } from "node:test";
3
3
  import type { AgentProgress, ForegroundRunControl } from "../../src/shared/types.ts";
4
- import { beginForegroundChild, finishForegroundChild, updateForegroundChild } from "../../src/runs/foreground/foreground-control.ts";
4
+ import {
5
+ beginForegroundChild,
6
+ finishForegroundChild,
7
+ foregroundSchedulingSettled,
8
+ retainForegroundSchedulingOwner,
9
+ settleForegroundSchedulingOwner,
10
+ updateForegroundChild,
11
+ } from "../../src/runs/foreground/foreground-control.ts";
5
12
 
6
13
  function progress(index: number, agent: string, tokens: number): AgentProgress {
7
14
  return {
@@ -13,6 +20,10 @@ function progress(index: number, agent: string, tokens: number): AgentProgress {
13
20
  recentOutput: [],
14
21
  toolCount: index + 1,
15
22
  tokens,
23
+ model: "openai/gpt-5.6-terra:high",
24
+ thinking: "high",
25
+ inputTokens: tokens - 20,
26
+ outputTokens: 20,
16
27
  durationMs: 10,
17
28
  };
18
29
  }
@@ -28,11 +39,13 @@ describe("foreground child control", () => {
28
39
  };
29
40
  let firstInterrupts = 0;
30
41
  let secondInterrupts = 0;
42
+ let firstDetaches = 0;
31
43
  beginForegroundChild(control, {
32
44
  index: 0,
33
45
  agent: "reviewer",
34
46
  description: "Review correctness",
35
47
  interrupt: () => { firstInterrupts++; return true; },
48
+ detach: () => { firstDetaches++; return true; },
36
49
  });
37
50
  beginForegroundChild(control, {
38
51
  index: 1,
@@ -46,10 +59,16 @@ describe("foreground child control", () => {
46
59
  updateForegroundChild(control, 0, progress(0, "reviewer", 120));
47
60
  assert.equal(control.currentIndex, 0);
48
61
  assert.equal(control.tokens, 120);
62
+ assert.equal(control.inputTokens, 100);
63
+ assert.equal(control.outputTokens, 20);
64
+ assert.equal(control.model, "openai/gpt-5.6-terra:high");
65
+ assert.equal(control.thinking, "high");
49
66
  assert.equal(control.activeChildren?.get(1)?.tokens, undefined);
50
67
  assert.equal(control.interrupt?.(), true);
51
68
  assert.equal(firstInterrupts, 1);
52
69
  assert.equal(secondInterrupts, 0);
70
+ assert.equal(control.detach?.(), true);
71
+ assert.equal(firstDetaches, 1);
53
72
 
54
73
  updateForegroundChild(control, 1, progress(1, "reviewer", 240));
55
74
  finishForegroundChild(control, 1);
@@ -60,6 +79,27 @@ describe("foreground child control", () => {
60
79
  finishForegroundChild(control, 0);
61
80
  assert.equal(control.activeChildren?.size, 0);
62
81
  assert.equal(control.currentIndex, undefined);
82
+ assert.equal(control.model, undefined);
83
+ assert.equal(control.inputTokens, undefined);
84
+ assert.equal(control.outputTokens, undefined);
63
85
  assert.equal(control.interrupt, undefined);
86
+ assert.equal(control.detach, undefined);
87
+ });
88
+
89
+ it("settles scheduling only after every owner releases", () => {
90
+ const control: ForegroundRunControl = {
91
+ runId: "owned-run",
92
+ mode: "parallel",
93
+ startedAt: 1,
94
+ updatedAt: 1,
95
+ schedulingOwners: 1,
96
+ };
97
+
98
+ retainForegroundSchedulingOwner(control);
99
+ settleForegroundSchedulingOwner(control);
100
+ assert.equal(foregroundSchedulingSettled(control), false);
101
+ settleForegroundSchedulingOwner(control);
102
+ assert.equal(foregroundSchedulingSettled(control), true);
103
+ assert.equal(control.schedulingOwners, 0);
64
104
  });
65
105
  });
@@ -60,7 +60,7 @@ describe("subagent extension child mode", () => {
60
60
  execFileSync(
61
61
  process.execPath,
62
62
  [
63
- "--experimental-transform-types",
63
+ "--experimental-strip-types",
64
64
  "--import",
65
65
  "./test/support/register-loader.mjs",
66
66
  "--input-type=module",
@@ -104,7 +104,7 @@ describe("subagent extension child mode", () => {
104
104
  execFileSync(
105
105
  process.execPath,
106
106
  [
107
- "--experimental-transform-types",
107
+ "--experimental-strip-types",
108
108
  "--import",
109
109
  "./test/support/register-loader.mjs",
110
110
  "--input-type=module",
@@ -155,7 +155,7 @@ describe("subagent extension child mode", () => {
155
155
  execFileSync(
156
156
  process.execPath,
157
157
  [
158
- "--experimental-transform-types",
158
+ "--experimental-strip-types",
159
159
  "--import",
160
160
  "./test/support/register-loader.mjs",
161
161
  "--input-type=module",
@@ -207,7 +207,7 @@ describe("subagent extension child mode", () => {
207
207
  const output = execFileSync(
208
208
  process.execPath,
209
209
  [
210
- "--experimental-transform-types",
210
+ "--experimental-strip-types",
211
211
  "--import",
212
212
  "./test/support/register-loader.mjs",
213
213
  "--input-type=module",
@@ -328,7 +328,7 @@ describe("subagent extension child mode", () => {
328
328
  env.SELESAI_CODING_AGENT_DIR = agentDir;
329
329
  execFileSync(
330
330
  process.execPath,
331
- ["--experimental-transform-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script],
331
+ ["--experimental-strip-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script],
332
332
  { cwd: projectRoot, env, stdio: "pipe" },
333
333
  );
334
334
  } finally {
@@ -422,7 +422,7 @@ describe("subagent extension child mode", () => {
422
422
  env.SELESAI_CODING_AGENT_DIR = agentDir;
423
423
  execFileSync(
424
424
  process.execPath,
425
- ["--experimental-transform-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script],
425
+ ["--experimental-strip-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script],
426
426
  { cwd: projectRoot, env, stdio: "pipe" },
427
427
  );
428
428
  } finally {
@@ -458,7 +458,7 @@ describe("subagent extension child mode", () => {
458
458
  execFileSync(
459
459
  process.execPath,
460
460
  [
461
- "--experimental-transform-types",
461
+ "--experimental-strip-types",
462
462
  "--import",
463
463
  "./test/support/register-loader.mjs",
464
464
  "--input-type=module",
@@ -493,7 +493,7 @@ describe("subagent extension child mode", () => {
493
493
  execFileSync(
494
494
  process.execPath,
495
495
  [
496
- "--experimental-transform-types",
496
+ "--experimental-strip-types",
497
497
  "--import",
498
498
  "./test/support/register-loader.mjs",
499
499
  "--input-type=module",
@@ -529,7 +529,7 @@ describe("subagent extension child mode", () => {
529
529
  execFileSync(
530
530
  process.execPath,
531
531
  [
532
- "--experimental-transform-types",
532
+ "--experimental-strip-types",
533
533
  "--import",
534
534
  "./test/support/register-loader.mjs",
535
535
  "--input-type=module",
@@ -574,7 +574,7 @@ describe("subagent extension child mode", () => {
574
574
  execFileSync(
575
575
  process.execPath,
576
576
  [
577
- "--experimental-transform-types",
577
+ "--experimental-strip-types",
578
578
  "--import",
579
579
  "./test/support/register-loader.mjs",
580
580
  "--input-type=module",
@@ -620,7 +620,7 @@ describe("subagent extension child mode", () => {
620
620
  execFileSync(
621
621
  process.execPath,
622
622
  [
623
- "--experimental-transform-types",
623
+ "--experimental-strip-types",
624
624
  "--import",
625
625
  "./test/support/register-loader.mjs",
626
626
  "--input-type=module",