@selesai/code 0.5.19 → 0.5.21

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 (265) hide show
  1. package/dist/extensions/handoff-new.test.ts +8 -9
  2. package/dist/extensions/handoff-new.ts +6 -8
  3. package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
  4. package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
  5. package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
  6. package/dist/extensions/pi-subagents/README.md +602 -220
  7. package/dist/extensions/pi-subagents/banner.png +0 -0
  8. package/dist/extensions/pi-subagents/index.ts +1 -0
  9. package/dist/extensions/pi-subagents/install.mjs +3 -3
  10. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  11. package/dist/extensions/pi-subagents/package.json +26 -14
  12. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  13. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  14. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  15. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  16. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  17. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  18. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  19. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  20. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  21. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  22. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  23. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  24. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  25. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  26. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  27. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  28. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  29. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  30. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  31. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  32. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  33. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  34. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  35. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  36. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  37. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  38. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  39. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  40. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  41. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  42. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  43. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  44. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  45. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  46. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  47. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  48. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  49. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  50. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  51. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  52. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  53. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  54. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  55. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  56. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  57. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  58. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  59. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  60. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  61. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  63. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  65. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  66. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  67. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  68. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  69. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  70. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  71. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  72. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  73. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  74. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  76. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  78. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  80. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  82. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  83. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  84. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  85. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  86. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  87. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  88. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  89. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  90. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  92. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  93. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  94. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  95. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  96. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  97. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  98. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  99. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  100. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  101. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  102. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  103. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  104. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  105. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  106. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  107. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  108. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  109. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  110. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  111. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  112. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  113. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  114. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  115. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  116. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  117. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  118. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  119. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  120. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  121. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  122. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  124. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  125. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  126. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  127. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  140. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  141. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  142. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  143. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  144. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  145. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  146. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  147. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  148. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  149. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  150. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  151. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  152. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  153. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  154. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  155. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  156. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  157. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  158. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  159. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  160. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  161. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  162. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  163. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  164. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  165. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  166. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  167. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  168. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  169. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  170. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  171. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  172. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  173. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  174. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  175. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  176. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  177. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  178. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  179. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  180. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  181. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  182. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  183. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  184. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  185. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  186. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  187. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  188. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  189. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  190. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  191. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  192. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  193. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  194. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  195. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  196. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  197. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  198. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  199. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  200. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  201. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  202. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  203. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  204. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  205. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  206. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  207. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  208. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  209. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  210. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  211. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  212. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  213. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  214. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  215. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  216. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  217. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  218. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  219. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  220. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  221. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  222. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  223. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  224. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  225. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  226. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  227. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  228. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  229. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  230. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  232. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  233. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  234. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  235. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  236. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  237. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  238. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  239. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  240. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  250. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  251. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  252. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  253. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  254. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  255. package/dist/extensions/question/batch.ts +39 -0
  256. package/dist/extensions/question/dialog-adapter.ts +23 -1
  257. package/dist/extensions/question/index.ts +237 -7
  258. package/dist/extensions/question/schemas.ts +28 -15
  259. package/dist/extensions/question/tests/batch.test.ts +26 -0
  260. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  261. package/dist/extensions/question/tui-adapter.ts +2 -3
  262. package/dist/extensions/question/types.ts +37 -0
  263. package/dist/extensions/question/ui-protocol.ts +3 -3
  264. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  265. package/package.json +2 -1
@@ -4,7 +4,11 @@ import * as os from "node:os";
4
4
  import * as path from "node:path";
5
5
  import { afterEach, describe, it } from "node:test";
6
6
  import { computeMcpServerHash } from "../../src/runs/shared/mcp-direct-tool-allowlist.ts";
7
- import { TOOL_BUDGET_ENV } from "../../src/runs/shared/tool-budget.ts";
7
+ import { TOOL_BUDGET_ENV, TOOL_BUDGET_ZERO_AUTH_ENV } from "../../src/runs/shared/tool-budget.ts";
8
+ import { WAIT_TOOL_ENABLED_ENV } from "../../src/runs/background/wait-config.ts";
9
+ import { SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV } from "../../src/shared/utils.ts";
10
+ import { CHILD_TOOL_DIAGNOSTIC_PATH_ENV, MCP_DIRECT_CHILD_TOOLS_ENV, REQUIRED_CHILD_TOOLS_ENV } from "../../src/runs/shared/tool-availability.ts";
11
+ import { CHILD_WATCHDOG_CONFIG_ENV } from "../../src/watchdog/child-status.ts";
8
12
  import {
9
13
  SUBAGENT_FANOUT_CHILD_ENV,
10
14
  SUBAGENT_PARENT_CHILD_INDEX_ENV,
@@ -38,6 +42,9 @@ const originalEnv = {
38
42
  SELESAI_SUBAGENT_PARENT_CAPABILITY_TOKEN: process.env.SELESAI_SUBAGENT_PARENT_CAPABILITY_TOKEN,
39
43
  SELESAI_SUBAGENT_PARENT_SESSION: process.env.SELESAI_SUBAGENT_PARENT_SESSION,
40
44
  SELESAI_SUBAGENT_RUN_ID: process.env.SELESAI_SUBAGENT_RUN_ID,
45
+ [MCP_DIRECT_CHILD_TOOLS_ENV]: process.env[MCP_DIRECT_CHILD_TOOLS_ENV],
46
+ [TOOL_BUDGET_ZERO_AUTH_ENV]: process.env[TOOL_BUDGET_ZERO_AUTH_ENV],
47
+ [SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV]: process.env[SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV],
41
48
  };
42
49
  const originalCwd = process.cwd();
43
50
  const tempRoots: string[] = [];
@@ -184,6 +191,66 @@ describe("buildPiArgs session wiring", () => {
184
191
 
185
192
  assert.equal(env[SUBAGENT_PARENT_SESSION_ENV], "inherited-parent");
186
193
  });
194
+
195
+ it("passes the effective wait-tool setting explicitly to children", () => {
196
+ assert.equal(buildPiArgs({
197
+ baseArgs: [], task: "test", sessionEnabled: false,
198
+ inheritProjectContext: true, inheritSkills: true,
199
+ waitToolEnabled: false,
200
+ }).env[WAIT_TOOL_ENABLED_ENV], "false");
201
+ assert.equal(buildPiArgs({
202
+ baseArgs: [], task: "test", sessionEnabled: false,
203
+ inheritProjectContext: true, inheritSkills: true,
204
+ waitToolEnabled: true,
205
+ }).env[WAIT_TOOL_ENABLED_ENV], "true");
206
+ });
207
+
208
+ it("passes child watchdog config only when explicitly provided", () => {
209
+ const withoutWatchdog = buildPiArgs({
210
+ baseArgs: ["-p"],
211
+ task: "hello",
212
+ sessionEnabled: false,
213
+ inheritProjectContext: false,
214
+ inheritSkills: false,
215
+ });
216
+ assert.equal(withoutWatchdog.env[CHILD_WATCHDOG_CONFIG_ENV], undefined);
217
+
218
+ const withWatchdog = buildPiArgs({
219
+ baseArgs: ["-p"],
220
+ task: "hello",
221
+ sessionEnabled: false,
222
+ inheritProjectContext: false,
223
+ inheritSkills: false,
224
+ childWatchdog: {
225
+ enabled: true,
226
+ runId: "run-1",
227
+ agent: "worker",
228
+ childIndex: 2,
229
+ watchdogTailTimeoutMs: 1234,
230
+ agentEndTimeoutMs: 500,
231
+ maxWarnings: 1,
232
+ lsp: { enabled: false, timeoutMs: 50, maxFiles: 2, maxDiagnostics: 3 },
233
+ autoFollowBlockers: true,
234
+ autoFollowMaxAttempts: 3,
235
+ stalemateRepeats: 2,
236
+ },
237
+ });
238
+ const encoded = withWatchdog.env[CHILD_WATCHDOG_CONFIG_ENV];
239
+ assert.equal(typeof encoded, "string");
240
+ assert.deepEqual(JSON.parse(encoded ?? "{}"), {
241
+ enabled: true,
242
+ runId: "run-1",
243
+ agent: "worker",
244
+ childIndex: 2,
245
+ watchdogTailTimeoutMs: 1234,
246
+ agentEndTimeoutMs: 500,
247
+ maxWarnings: 1,
248
+ lsp: { enabled: false, timeoutMs: 50, maxFiles: 2, maxDiagnostics: 3 },
249
+ autoFollowBlockers: true,
250
+ autoFollowMaxAttempts: 3,
251
+ stalemateRepeats: 2,
252
+ });
253
+ });
187
254
  });
188
255
 
189
256
  describe("buildPiArgs model wiring", () => {
@@ -234,6 +301,24 @@ describe("buildPiArgs model wiring", () => {
234
301
  assert.ok(args.includes("openai-codex/gpt-5.4-mini:high"));
235
302
  });
236
303
 
304
+ it("passes max thinking through to the model argument", () => {
305
+ const { args } = buildPiArgs({
306
+ baseArgs: ["-p"],
307
+ task: "hello",
308
+ model: "openai/gpt-5",
309
+ thinking: "max",
310
+ sessionEnabled: false,
311
+ inheritProjectContext: false,
312
+ inheritSkills: false,
313
+ });
314
+
315
+ assert.equal(applyThinkingSuffix("openai/gpt-5", "max"), "openai/gpt-5:max");
316
+ assert.equal(applyThinkingSuffix("openai/gpt-5:max", "high"), "openai/gpt-5:max");
317
+ assert.equal(applyThinkingSuffix("openai/gpt-5:max", "high", true), "openai/gpt-5:high");
318
+ assert.ok(args.includes("--model"));
319
+ assert.ok(args.includes("openai/gpt-5:max"));
320
+ });
321
+
237
322
  it("passes explicit thinking off through to the model arg", () => {
238
323
  const { args } = buildPiArgs({
239
324
  baseArgs: ["-p"],
@@ -251,6 +336,27 @@ describe("buildPiArgs model wiring", () => {
251
336
  assert.ok(args.includes("anthropic/claude-haiku-4-5:off"));
252
337
  });
253
338
 
339
+ it("does not append a thinking suffix for boolean false", () => {
340
+ const model = "glm-5.2-short-fast";
341
+ const once = applyThinkingSuffix(model, false);
342
+ assert.equal(once, model);
343
+ assert.equal(applyThinkingSuffix(once, false), model);
344
+
345
+ const { args } = buildPiArgs({
346
+ baseArgs: ["-p"],
347
+ task: "hello",
348
+ sessionEnabled: false,
349
+ model,
350
+ thinking: false,
351
+ inheritProjectContext: false,
352
+ inheritSkills: false,
353
+ });
354
+
355
+ assert.ok(args.includes("--model"));
356
+ assert.ok(args.includes(model));
357
+ assert.ok(!args.some((arg) => arg.includes(":false")));
358
+ });
359
+
254
360
  it("leaves provider-specific model suffixes untouched when thinking is disabled", () => {
255
361
  const model = "openai-compatible/qwen2.5-coder:7b";
256
362
  const { args } = buildPiArgs({
@@ -325,6 +431,47 @@ describe("buildPiArgs system prompt mode wiring", () => {
325
431
  });
326
432
 
327
433
  assert.deepEqual(JSON.parse(env[TOOL_BUDGET_ENV] ?? "{}"), { soft: 2, hard: 3, block: ["read"] });
434
+ assert.equal(env[TOOL_BUDGET_ZERO_AUTH_ENV], undefined);
435
+ });
436
+
437
+ it("clears inherited zero tool-budget authorization unless this launch owns it", () => {
438
+ process.env[TOOL_BUDGET_ZERO_AUTH_ENV] = "1";
439
+ const inherited = buildPiArgs({
440
+ baseArgs: ["-p"],
441
+ task: "hello",
442
+ sessionEnabled: false,
443
+ inheritProjectContext: false,
444
+ inheritSkills: false,
445
+ toolBudget: { hard: 1, block: ["read"] },
446
+ });
447
+ assert.equal(inherited.env[TOOL_BUDGET_ZERO_AUTH_ENV], undefined);
448
+
449
+ const owned = buildPiArgs({
450
+ baseArgs: ["-p"],
451
+ task: "hello",
452
+ sessionEnabled: false,
453
+ inheritProjectContext: false,
454
+ inheritSkills: false,
455
+ toolBudget: { hard: 0, block: "*" },
456
+ allowZeroToolBudget: true,
457
+ });
458
+ assert.equal(owned.env[TOOL_BUDGET_ZERO_AUTH_ENV], "1");
459
+ });
460
+
461
+ it("clears inherited MCP direct-tool metadata for non-MCP launches", () => {
462
+ for (const staleValue of [JSON.stringify(["fixture_search"]), "not-json"]) {
463
+ process.env[MCP_DIRECT_CHILD_TOOLS_ENV] = staleValue;
464
+ const { env } = buildPiArgs({
465
+ baseArgs: ["-p"],
466
+ task: "hello",
467
+ sessionEnabled: false,
468
+ inheritProjectContext: false,
469
+ inheritSkills: false,
470
+ tools: ["read", "fixture_search"],
471
+ });
472
+
473
+ assert.equal(env[MCP_DIRECT_CHILD_TOOLS_ENV], undefined);
474
+ }
328
475
  });
329
476
 
330
477
  it("passes child intercom and orchestrator metadata through env", () => {
@@ -370,7 +517,7 @@ describe("buildPiArgs system prompt mode wiring", () => {
370
517
  });
371
518
 
372
519
  it("emits explicit builtin tool allowlists", () => {
373
- const { args } = buildPiArgs({
520
+ const { args, env, toolDiagnosticPath } = buildPiArgs({
374
521
  baseArgs: ["-p"],
375
522
  task: "hello",
376
523
  sessionEnabled: false,
@@ -381,6 +528,40 @@ describe("buildPiArgs system prompt mode wiring", () => {
381
528
 
382
529
  const toolsArg = args[args.indexOf("--tools") + 1];
383
530
  assert.equal(toolsArg, "read,grep,find,ls,bash,edit,write,contact_supervisor");
531
+ assert.deepEqual(JSON.parse(env[REQUIRED_CHILD_TOOLS_ENV] ?? "[]"), toolsArg.split(","));
532
+ assert.equal(env[CHILD_TOOL_DIAGNOSTIC_PATH_ENV], toolDiagnosticPath);
533
+ });
534
+
535
+ it("keeps structured_output available under explicit tool allowlists", () => {
536
+ const { args, env } = buildPiArgs({
537
+ baseArgs: ["-p"],
538
+ task: "hello",
539
+ sessionEnabled: false,
540
+ inheritProjectContext: false,
541
+ inheritSkills: false,
542
+ tools: ["read", "fixture_search"],
543
+ structuredOutput: {
544
+ schema: { type: "object", properties: {}, additionalProperties: false },
545
+ schemaPath: "/tmp/schema.json",
546
+ outputPath: "/tmp/output.json",
547
+ },
548
+ });
549
+
550
+ assert.equal(args[args.indexOf("--tools") + 1], "read,fixture_search,structured_output");
551
+ assert.deepEqual(JSON.parse(env[REQUIRED_CHILD_TOOLS_ENV] ?? "[]"), ["read", "fixture_search", "structured_output"]);
552
+ });
553
+
554
+ it("forwards the Pi package root to child processes for host peer resolution", () => {
555
+ process.env[SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV] = "/opt/pi-coding-agent";
556
+ const { env } = buildPiArgs({
557
+ baseArgs: ["-p"],
558
+ task: "hello",
559
+ sessionEnabled: false,
560
+ inheritProjectContext: false,
561
+ inheritSkills: false,
562
+ });
563
+
564
+ assert.equal(env[SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV], "/opt/pi-coding-agent");
384
565
  });
385
566
 
386
567
  it("adds read to explicit tool allowlists when skills must be loaded lazily", () => {
@@ -427,23 +608,69 @@ describe("buildPiArgs system prompt mode wiring", () => {
427
608
 
428
609
  assert.equal(args[args.indexOf("--tools") + 1], "read,bash,chrome_devtools_take_screenshot,chrome_devtools_click");
429
610
  assert.equal(env.MCP_DIRECT_TOOLS, "chrome-devtools");
611
+ assert.equal(env[REQUIRED_CHILD_TOOLS_ENV], JSON.stringify(["read", "bash", "chrome_devtools_take_screenshot", "chrome_devtools_click"]));
612
+ assert.equal(env[MCP_DIRECT_CHILD_TOOLS_ENV], JSON.stringify(["chrome_devtools_take_screenshot", "chrome_devtools_click"]));
430
613
  });
431
614
 
432
- it("preserves no --tools for MCP-only agents", () => {
433
- const fixture = createMcpFixture();
434
- writeMcpFixture(fixture);
615
+ it("emits --no-tools for explicit empty tool allowlists", () => {
616
+ for (const requireReadTool of [false, true]) {
617
+ const { args, env } = buildPiArgs({
618
+ baseArgs: ["-p"],
619
+ task: "hello",
620
+ sessionEnabled: false,
621
+ inheritProjectContext: false,
622
+ inheritSkills: false,
623
+ requireReadTool,
624
+ tools: [],
625
+ });
435
626
 
436
- const { args, env } = buildPiArgs({
437
- baseArgs: ["-p"],
438
- task: "hello",
439
- sessionEnabled: false,
440
- inheritProjectContext: false,
441
- inheritSkills: false,
442
- mcpDirectTools: ["chrome-devtools"],
443
- });
627
+ assert.ok(args.includes("--no-tools"));
628
+ assert.equal(args.includes("--tools"), false);
629
+ assert.equal(env.MCP_DIRECT_TOOLS, "__none__");
630
+ }
631
+ });
444
632
 
445
- assert.equal(args.includes("--tools"), false);
446
- assert.equal(env.MCP_DIRECT_TOOLS, "chrome-devtools");
633
+ it("restricts MCP-only agents to selected direct MCP tool names", () => {
634
+ for (const requireReadTool of [false, true]) {
635
+ const fixture = createMcpFixture();
636
+ writeMcpFixture(fixture);
637
+
638
+ const { args, env } = buildPiArgs({
639
+ baseArgs: ["-p"],
640
+ task: "hello",
641
+ sessionEnabled: false,
642
+ inheritProjectContext: false,
643
+ inheritSkills: false,
644
+ requireReadTool,
645
+ mcpDirectTools: ["chrome-devtools"],
646
+ });
647
+
648
+ assert.equal(args[args.indexOf("--tools") + 1], "chrome_devtools_take_screenshot,chrome_devtools_click");
649
+ assert.equal(env.MCP_DIRECT_TOOLS, "chrome-devtools");
650
+ }
651
+ });
652
+
653
+ it("fails closed with --no-tools when MCP-only names cannot be resolved", () => {
654
+ for (const requireReadTool of [false, true]) {
655
+ const fixture = createMcpFixture();
656
+ writeJson(path.join(fixture.agentDir, "mcp.json"), {
657
+ mcpServers: { "chrome-devtools": { command: "npx", args: ["chrome-devtools-mcp"] } },
658
+ });
659
+
660
+ const { args, env } = buildPiArgs({
661
+ baseArgs: ["-p"],
662
+ task: "hello",
663
+ sessionEnabled: false,
664
+ inheritProjectContext: false,
665
+ inheritSkills: false,
666
+ requireReadTool,
667
+ mcpDirectTools: ["chrome-devtools"],
668
+ });
669
+
670
+ assert.ok(args.includes("--no-tools"));
671
+ assert.equal(args.includes("--tools"), false);
672
+ assert.equal(env.MCP_DIRECT_TOOLS, "chrome-devtools");
673
+ }
447
674
  });
448
675
 
449
676
  it("supports direct MCP server/tool filters", () => {
@@ -548,7 +775,7 @@ describe("buildPiArgs system prompt mode wiring", () => {
548
775
 
549
776
  it("resolves project MCP config from the child cwd and expands SELESAI_CODING_AGENT_DIR", () => {
550
777
  const fixture = createMcpFixture();
551
- process.env.SELESAI_CODING_AGENT_DIR = "~/.pi/agent";
778
+ process.env.SELESAI_CODING_AGENT_DIR = "~/.selesai/agent";
552
779
  process.chdir(fixture.root);
553
780
  writeMcpFixture(fixture, {
554
781
  serverName: "project-mcp",
@@ -1,15 +1,17 @@
1
1
  import assert from "node:assert/strict";
2
+ import { createHash } from "node:crypto";
2
3
  import * as fs from "node:fs";
3
4
  import * as os from "node:os";
4
5
  import * as path from "node:path";
5
6
  import { afterEach, beforeEach, describe, it } from "node:test";
6
- import { discoverAgentsAll, ensureDefaultUserSubagentSettings } from "../../src/agents/agents.ts";
7
+ import { discoverAgentsAll } from "../../src/agents/agents.ts";
7
8
  import { handleCreate } from "../../src/agents/agent-management.ts";
8
9
  import { clearSkillCache, discoverAvailableSkills, resolveSkillPath } from "../../src/agents/skills.ts";
9
- import { loadConfig } from "../../src/extension/config.ts";
10
+ import { loadConfig, updateConfig } from "../../src/extension/config.ts";
10
11
  import { diagnoseIntercomBridge, resolveIntercomBridge } from "../../src/intercom/intercom-bridge.ts";
11
12
  import { loadRunsForAgent, recordRun } from "../../src/runs/shared/run-history.ts";
12
- import { cleanupAllArtifactDirs } from "../../src/shared/artifacts.ts";
13
+ import { cleanupAllArtifactDirs, getArtifactsDir, getProjectArtifactsDir } from "../../src/shared/artifacts.ts";
14
+ import { TEMP_ARTIFACTS_DIR } from "../../src/shared/types.ts";
13
15
  import { getAgentDir, getConfigDirName, getProjectConfigDir, resolveConfigDirName } from "../../src/shared/utils.ts";
14
16
 
15
17
  let tempDir = "";
@@ -33,6 +35,16 @@ function readText(result: { content: Array<{ type: string; text?: string }> }):
33
35
  return first.text;
34
36
  }
35
37
 
38
+ function taskHash(task: string): string {
39
+ return createHash("sha256").update(task).digest("hex");
40
+ }
41
+
42
+ function assertPrivateHistoryModes(historyPath: string): void {
43
+ if (process.platform === "win32") return;
44
+ assert.equal(fs.statSync(path.dirname(historyPath)).mode & 0o777, 0o700);
45
+ assert.equal(fs.statSync(historyPath).mode & 0o777, 0o600);
46
+ }
47
+
36
48
  describe("SELESAI_CODING_AGENT_DIR runtime paths", () => {
37
49
  beforeEach(() => {
38
50
  oldAgentDir = process.env.SELESAI_CODING_AGENT_DIR;
@@ -79,35 +91,12 @@ describe("SELESAI_CODING_AGENT_DIR runtime paths", () => {
79
91
 
80
92
  process.env.SELESAI_CODING_AGENT_DIR = agentDir;
81
93
  const configPath = path.join(agentDir, "extensions", "subagent", "config.json");
82
- writeFile(configPath, JSON.stringify({ asyncByDefault: true, maxSubagentDepth: 3 }));
94
+ writeFile(configPath, JSON.stringify({ asyncByDefault: true, maxSubagentDepth: 3, artifactDir: "session" }));
83
95
 
84
96
  const config = loadConfig();
85
97
  assert.equal(config.asyncByDefault, true);
86
98
  assert.equal(config.maxSubagentDepth, 3);
87
- });
88
-
89
- it("seeds an editable user subagent model default without replacing existing settings", () => {
90
- const settingsPath = path.join(agentDir, "settings.json");
91
- writeFile(settingsPath, JSON.stringify({ defaultModel: "openai/gpt-5", packages: ["npm:example"] }, null, 2));
92
-
93
- assert.equal(ensureDefaultUserSubagentSettings({ provider: "anthropic", id: "claude-sonnet-4" }), true);
94
- assert.deepEqual(JSON.parse(fs.readFileSync(settingsPath, "utf-8")), {
95
- defaultModel: "openai/gpt-5",
96
- packages: ["npm:example"],
97
- subagents: {
98
- defaultModel: "anthropic/claude-sonnet-4",
99
- agentOverrides: {
100
- architect: { model: "anthropic/claude-sonnet-4" },
101
- builder: { model: "anthropic/claude-sonnet-4" },
102
- commentator: { model: "anthropic/claude-sonnet-4" },
103
- explorer: { model: "anthropic/claude-sonnet-4" },
104
- recapper: { model: "anthropic/claude-sonnet-4" },
105
- researcher: { model: "anthropic/claude-sonnet-4" },
106
- },
107
- },
108
- });
109
- assert.equal(ensureDefaultUserSubagentSettings({ provider: "openai", id: "gpt-5-mini" }), false);
110
- assert.equal(ensureDefaultUserSubagentSettings(undefined), false);
99
+ assert.equal(config.artifactDir, "session");
111
100
  });
112
101
 
113
102
  it("discovers user agents, chains, and settings under the configured agent dir", () => {
@@ -131,7 +120,7 @@ Inspect env.
131
120
  writeFile(settingsPath, JSON.stringify({
132
121
  subagents: {
133
122
  agentOverrides: {
134
- worker: { systemPrompt: "Use env-rooted settings." },
123
+ builder: { systemPrompt: "Use env-rooted settings." },
135
124
  },
136
125
  },
137
126
  }, null, 2));
@@ -143,10 +132,10 @@ Inspect env.
143
132
  assert.ok(discovered.user.find((agent) => agent.name === "env-agent" && agent.filePath === path.join(agentDir, "agents", "env-agent.md")));
144
133
  assert.ok(discovered.chains.find((chain) => chain.name === "env-chain" && chain.filePath === path.join(agentDir, "chains", "env-chain.chain.md")));
145
134
 
146
- const worker = discovered.builtin.find((agent) => agent.name === "worker");
147
- assert.equal(worker?.systemPrompt, "Use env-rooted settings.");
148
- assert.equal(worker?.override?.path, settingsPath);
149
- assert.equal(worker?.override?.scope, "user");
135
+ const builder = discovered.builtin.find((agent) => agent.name === "builder");
136
+ assert.equal(builder?.systemPrompt, "Use env-rooted settings.");
137
+ assert.equal(builder?.override?.path, settingsPath);
138
+ assert.equal(builder?.override?.scope, "user");
150
139
 
151
140
  const createdName = "created-env-agent";
152
141
  const created = handleCreate(
@@ -191,13 +180,22 @@ Package skill content.
191
180
  assert.ok(available.find((skill) => skill.name === "package-skill" && skill.source === "user-package"));
192
181
  });
193
182
 
194
- it("records run history and cleans session artifacts under the configured agent dir", () => {
195
- recordRun("env-agent", "Inspect", 0, 42);
183
+ it("records private redacted run history and cleans session artifacts under the configured agent dir", () => {
184
+ const task = "Inspect customer ACME token=SECRET";
185
+ recordRun("env-agent", task, 0, 42);
196
186
  const historyPath = path.join(agentDir, "run-history.jsonl");
197
187
  assert.equal(fs.existsSync(historyPath), true);
188
+ assertPrivateHistoryModes(historyPath);
189
+
190
+ const rawHistory = fs.readFileSync(historyPath, "utf-8");
191
+ assert.doesNotMatch(rawHistory, /Inspect customer|ACME|SECRET/);
192
+ assert.match(rawHistory, /"task":"\[redacted\]"/);
193
+ assert.match(rawHistory, /"taskHash":"[a-f0-9]{64}"/);
194
+
198
195
  const history = loadRunsForAgent("env-agent");
199
196
  assert.equal(history.length, 1);
200
- assert.equal(history[0]?.task, "Inspect");
197
+ assert.equal(history[0]?.task, "[redacted]");
198
+ assert.equal(history[0]?.taskHash, taskHash(task));
201
199
  assert.equal(history[0]?.status, "ok");
202
200
 
203
201
  const artifactPath = path.join(agentDir, "sessions", "session-1", "subagent-artifacts", "old_output.md");
@@ -209,6 +207,51 @@ Package skill content.
209
207
  assert.equal(fs.existsSync(artifactPath), false);
210
208
  });
211
209
 
210
+ it("resolves configured artifact directory preferences", () => {
211
+ const sessionFile = path.join(agentDir, "sessions", "session-1", "session.jsonl");
212
+
213
+ assert.equal(getArtifactsDir(sessionFile, cwd), getProjectArtifactsDir(cwd));
214
+ assert.equal(getArtifactsDir(sessionFile, cwd, "project"), getProjectArtifactsDir(cwd));
215
+ assert.equal(getArtifactsDir(sessionFile, cwd, "session"), path.join(path.dirname(sessionFile), "subagent-artifacts"));
216
+ assert.equal(getArtifactsDir(sessionFile, cwd, "temp"), TEMP_ARTIFACTS_DIR);
217
+ assert.equal(getArtifactsDir(null, cwd, "session"), TEMP_ARTIFACTS_DIR);
218
+ assert.throws(() => getArtifactsDir(sessionFile, cwd, "workspace" as never), /Unsupported artifactDir/);
219
+ });
220
+
221
+ it("rejects invalid artifactDir config values", () => {
222
+ const configPath = path.join(agentDir, "extensions", "subagent", "config.json");
223
+ writeFile(configPath, JSON.stringify({ artifactDir: "workspace" }));
224
+
225
+ assert.throws(() => updateConfig((config) => config), /config\.artifactDir must be "project", "session", or "temp"/);
226
+ });
227
+
228
+ it("hardens and redacts existing run history while recording", () => {
229
+ const historyPath = path.join(agentDir, "run-history.jsonl");
230
+ fs.mkdirSync(agentDir, { recursive: true, mode: 0o755 });
231
+ fs.writeFileSync(historyPath, `${JSON.stringify({
232
+ agent: "env-agent",
233
+ task: "legacy customer secret",
234
+ ts: 1,
235
+ status: "ok",
236
+ duration: 2,
237
+ })}\nnot json with pasted secret\n`, { encoding: "utf-8", mode: 0o644 });
238
+
239
+ recordRun("env-agent", "new customer secret", 1, 9);
240
+
241
+ assertPrivateHistoryModes(historyPath);
242
+ const rawHistory = fs.readFileSync(historyPath, "utf-8");
243
+ assert.doesNotMatch(rawHistory, /legacy customer secret|new customer secret|not json with pasted secret/);
244
+
245
+ const history = loadRunsForAgent("env-agent");
246
+ assert.equal(history.length, 2);
247
+ assert.equal(history[0]?.task, "[redacted]");
248
+ assert.equal(history[0]?.taskHash, taskHash("new customer secret"));
249
+ assert.equal(history[0]?.status, "error");
250
+ assert.equal(history[0]?.exit, 1);
251
+ assert.equal(history[1]?.task, "[redacted]");
252
+ assert.equal(history[1]?.taskHash, taskHash("legacy customer secret"));
253
+ });
254
+
212
255
  it("uses the configured agent dir for subagent bridge instruction files", () => {
213
256
  const instructionPath = path.join(agentDir, "extensions", "subagent", "bridge.md");
214
257
  writeFile(instructionPath, "Native bridge for {orchestratorTarget}");