@selesai/code 0.13.16 → 0.13.19

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 (479) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +2 -14
  3. package/dist/bun/cli.d.ts +3 -1
  4. package/dist/bun/cli.js +3 -9
  5. package/dist/bun/{register-bedrock.js → runtime-setup.js} +5 -0
  6. package/dist/bun/sandbox-env-setup.d.ts +1 -0
  7. package/dist/bun/sandbox-env-setup.js +3 -0
  8. package/dist/cli/auth-command.d.ts +23 -0
  9. package/dist/cli/auth-command.js +102 -0
  10. package/dist/cli/config-selector.js +2 -1
  11. package/dist/cli/setup.d.ts +1 -0
  12. package/dist/cli/setup.js +11 -0
  13. package/dist/cli.js +2 -14
  14. package/dist/config.d.ts +3 -2
  15. package/dist/config.js +9 -4
  16. package/dist/core/agent-session-runtime.js +15 -7
  17. package/dist/core/agent-session.d.ts +2 -6
  18. package/dist/core/agent-session.js +15 -4
  19. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  20. package/dist/core/compaction/branch-summarization.js +2 -1
  21. package/dist/core/extensions/loader.js +3 -0
  22. package/dist/core/extensions/types.d.ts +16 -2
  23. package/dist/core/http-dispatcher.js +2 -0
  24. package/dist/core/keybindings.d.ts +5 -0
  25. package/dist/core/keybindings.js +4 -0
  26. package/dist/core/messages.d.ts +1 -1
  27. package/dist/core/model-config.d.ts +15 -0
  28. package/dist/core/model-config.js +3 -0
  29. package/dist/core/model-runtime.d.ts +1 -0
  30. package/dist/core/model-runtime.js +5 -2
  31. package/dist/core/provider-composer.js +8 -2
  32. package/dist/core/session-export.d.ts +3 -0
  33. package/dist/core/session-export.js +31 -0
  34. package/dist/core/session-manager.d.ts +3 -2
  35. package/dist/core/session-manager.js +40 -13
  36. package/dist/core/skills.d.ts +1 -1
  37. package/dist/core/skills.js +4 -2
  38. package/dist/core/system-prompt.js +10 -10
  39. package/dist/core/tools/bash.js +3 -117
  40. package/dist/core/tools/edit.d.ts +1 -12
  41. package/dist/core/tools/edit.js +5 -163
  42. package/dist/core/tools/find.js +4 -55
  43. package/dist/core/tools/grep.js +4 -60
  44. package/dist/core/tools/ls.js +4 -49
  45. package/dist/core/tools/read.d.ts +4 -0
  46. package/dist/core/tools/read.js +10 -122
  47. package/dist/core/tools/renderers/bash.d.ts +11 -0
  48. package/dist/core/tools/renderers/bash.js +129 -0
  49. package/dist/core/tools/renderers/edit.d.ts +22 -0
  50. package/dist/core/tools/renderers/edit.js +166 -0
  51. package/dist/core/tools/renderers/find.d.ts +9 -0
  52. package/dist/core/tools/renderers/find.js +63 -0
  53. package/dist/core/tools/renderers/grep.d.ts +9 -0
  54. package/dist/core/tools/renderers/grep.js +68 -0
  55. package/dist/core/tools/renderers/index.d.ts +27 -0
  56. package/dist/core/tools/renderers/index.js +46 -0
  57. package/dist/core/tools/renderers/ls.d.ts +9 -0
  58. package/dist/core/tools/renderers/ls.js +57 -0
  59. package/dist/core/tools/renderers/read.d.ts +10 -0
  60. package/dist/core/tools/renderers/read.js +128 -0
  61. package/dist/core/tools/renderers/write.d.ts +9 -0
  62. package/dist/core/tools/renderers/write.js +152 -0
  63. package/dist/core/tools/write.js +5 -146
  64. package/dist/extensions/agent-browser.ts +1 -2
  65. package/dist/extensions/package.json +0 -1
  66. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +18 -0
  67. package/dist/extensions/pi-hermes-memory/README.md +16 -12
  68. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +1 -1
  69. package/dist/extensions/pi-hermes-memory/package-lock.json +587 -62
  70. package/dist/extensions/pi-hermes-memory/package.json +4 -4
  71. package/dist/extensions/pi-hermes-memory/src/config.ts +32 -0
  72. package/dist/extensions/pi-hermes-memory/src/constants.ts +12 -2
  73. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +109 -51
  74. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +9 -3
  75. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +257 -98
  76. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +9 -2
  77. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +5 -0
  78. package/dist/extensions/pi-hermes-memory/src/index.ts +22 -2
  79. package/dist/extensions/pi-hermes-memory/src/paths.ts +1 -1
  80. package/dist/extensions/pi-hermes-memory/src/store/db.ts +6 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +58 -1
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +60 -8
  83. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +169 -7
  84. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +7 -21
  85. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +134 -15
  86. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +4 -2
  87. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +24 -9
  88. package/dist/extensions/pi-hermes-memory/src/types.ts +11 -0
  89. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +42 -0
  90. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +159 -3
  91. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +452 -0
  92. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +39 -0
  93. package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +91 -0
  94. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +29 -0
  95. package/dist/extensions/pi-hermes-memory/tests/store/fts-query.test.ts +116 -0
  96. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +163 -0
  97. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +233 -0
  98. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +12 -0
  99. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +175 -0
  100. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +2 -2
  101. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +22 -0
  102. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +37 -1
  103. package/dist/extensions/pi-intercom/CHANGELOG.md +13 -0
  104. package/dist/extensions/pi-intercom/README.md +16 -2
  105. package/dist/extensions/pi-intercom/broker/spawn.test.ts +19 -2
  106. package/dist/extensions/pi-intercom/broker/spawn.ts +4 -4
  107. package/dist/extensions/pi-intercom/index.ts +1 -1
  108. package/dist/extensions/pi-intercom/intercom.integration.test.ts +121 -2
  109. package/dist/extensions/pi-intercom/package.json +1 -1
  110. package/dist/extensions/pi-intercom/project-agent.test.ts +1 -1
  111. package/dist/extensions/pi-intercom/project-agent.ts +1 -6
  112. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +7 -6
  113. package/dist/extensions/pi-rewind-hook/index.test.ts +7 -0
  114. package/dist/extensions/pi-subagents/.github/workflows/test.yml +36 -4
  115. package/dist/extensions/pi-subagents/CHANGELOG.md +120 -0
  116. package/dist/extensions/pi-subagents/README.md +3 -3
  117. package/dist/extensions/pi-subagents/agents/researcher.md +23 -13
  118. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -1
  119. package/dist/extensions/pi-subagents/agents/scout.md +1 -1
  120. package/dist/extensions/pi-subagents/docs/agents.md +32 -16
  121. package/dist/extensions/pi-subagents/docs/configuration.md +41 -15
  122. package/dist/extensions/pi-subagents/docs/extension-api.md +109 -6
  123. package/dist/extensions/pi-subagents/docs/missions.md +2 -0
  124. package/dist/extensions/pi-subagents/docs/models.md +58 -1
  125. package/dist/extensions/pi-subagents/docs/observability.md +50 -12
  126. package/dist/extensions/pi-subagents/docs/tool-reference.md +17 -10
  127. package/dist/extensions/pi-subagents/docs/watchdog.md +1 -1
  128. package/dist/extensions/pi-subagents/docs/workflows.md +26 -9
  129. package/dist/extensions/pi-subagents/package-lock.json +747 -177
  130. package/dist/extensions/pi-subagents/package.json +6 -4
  131. package/dist/extensions/pi-subagents/runner-server-preload.mjs +13 -0
  132. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -1
  133. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
  134. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +21 -4
  135. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
  136. package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
  137. package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +63 -0
  138. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +61 -16
  139. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
  140. package/dist/extensions/pi-subagents/src/agents/agents.ts +8 -0
  141. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +0 -1
  142. package/dist/extensions/pi-subagents/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
  143. package/dist/extensions/pi-subagents/src/api/preflight.ts +7 -4
  144. package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -2
  145. package/dist/extensions/pi-subagents/src/api/workflow-resources.ts +6 -0
  146. package/dist/extensions/pi-subagents/src/extension/config.ts +4 -2
  147. package/dist/extensions/pi-subagents/src/extension/doctor.ts +2 -10
  148. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +9 -11
  149. package/dist/extensions/pi-subagents/src/extension/index.ts +99 -10
  150. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +13 -0
  151. package/dist/extensions/pi-subagents/src/extension/rpc.ts +7 -23
  152. package/dist/extensions/pi-subagents/src/extension/schemas.ts +11 -8
  153. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +25 -7
  154. package/dist/extensions/pi-subagents/src/integrations/pi-web-session-liveness.ts +73 -0
  155. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +228 -136
  156. package/dist/extensions/pi-subagents/src/intercom/supervisor-ui.ts +244 -0
  157. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +37 -16
  158. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +18 -18
  159. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +51 -25
  160. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +46 -3
  161. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -3
  162. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +9 -0
  163. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +10 -12
  164. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -15
  165. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +40 -29
  166. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +8 -0
  167. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +79 -247
  168. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +88 -12
  169. package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +6 -6
  170. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +24 -24
  171. package/dist/extensions/pi-subagents/src/runs/background/retained-nested-route-tracker.ts +96 -0
  172. package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +642 -0
  173. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +75 -6
  174. package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +163 -0
  175. package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +86 -0
  176. package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +31 -0
  177. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +18 -4
  178. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -1
  179. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +597 -1092
  180. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +3 -0
  181. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +4 -0
  182. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +20 -17
  183. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +296 -394
  184. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +4 -0
  185. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +3 -1
  186. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +9 -5
  187. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +630 -283
  188. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
  189. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +78 -98
  190. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +3 -3
  191. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +16 -3
  192. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
  193. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +47 -47
  194. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -2
  195. package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +174 -0
  196. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +14 -3
  197. package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +319 -0
  198. package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +25 -0
  199. package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +126 -0
  200. package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +373 -0
  201. package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +530 -0
  202. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +2 -2
  203. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +2 -1
  204. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +16 -0
  205. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +11 -11
  206. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +30 -20
  207. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
  208. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +84 -15
  209. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +88 -12
  210. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +37 -53
  211. package/dist/extensions/pi-subagents/src/runs/shared/nested-path.ts +1 -1
  212. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +18 -7
  213. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +57 -12
  214. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +3 -4
  215. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +0 -11
  216. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +4 -1
  217. package/dist/extensions/pi-subagents/src/runs/shared/readonly-drain-observation.ts +42 -0
  218. package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +69 -0
  219. package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +307 -0
  220. package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +8 -21
  221. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +3 -30
  222. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +17 -4
  223. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +2 -0
  224. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +99 -386
  225. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +18 -62
  226. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +0 -14
  227. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +31 -9
  228. package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +190 -0
  229. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +506 -226
  230. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +1 -1
  231. package/dist/extensions/pi-subagents/src/shared/jsonl-writer.ts +11 -0
  232. package/dist/extensions/pi-subagents/src/shared/model-response-aliases.ts +13 -0
  233. package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +0 -6
  234. package/dist/extensions/pi-subagents/src/shared/types.ts +145 -89
  235. package/dist/extensions/pi-subagents/src/shared/utils.ts +13 -6
  236. package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +2 -0
  237. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +18 -13
  238. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +0 -6
  239. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +1 -1
  240. package/dist/extensions/pi-subagents/src/tui/fleet.ts +11 -6
  241. package/dist/extensions/pi-subagents/src/tui/render.ts +277 -46
  242. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +0 -1
  243. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +12 -12
  244. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
  245. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +116 -15
  246. package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +15 -18
  247. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +57 -8
  248. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +19 -19
  249. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +3 -3
  250. package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +97 -22
  251. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +3 -0
  252. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +336 -21
  253. package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +1181 -0
  254. package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +2240 -0
  255. package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +2268 -0
  256. package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +1512 -0
  257. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +231 -16
  258. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +4 -18
  259. package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +95 -0
  260. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +9 -15
  261. package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +374 -0
  262. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -10
  263. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +18 -6
  264. package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +151 -0
  265. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +42 -1
  266. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +150 -25
  267. package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +354 -0
  268. package/dist/extensions/pi-subagents/test/integration/shared-cwd-terminal-evidence.test.ts +117 -0
  269. package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +3678 -0
  270. package/dist/extensions/pi-subagents/test/integration/{single-execution.test.ts → single-execution.part-2.test.ts} +500 -4207
  271. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -2
  272. package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +127 -0
  273. package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +365 -0
  274. package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +31 -0
  275. package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +74 -0
  276. package/dist/extensions/pi-subagents/test/smoke/pi085-extension.ts +16 -0
  277. package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +699 -0
  278. package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +418 -0
  279. package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +13 -0
  280. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +30 -76
  281. package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +84 -0
  282. package/dist/extensions/pi-subagents/test/support/result-publication-capacity-preload.mjs +70 -0
  283. package/dist/extensions/pi-subagents/test/support/runner-child-session-factory.ts +17 -0
  284. package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +390 -0
  285. package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +120 -0
  286. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +24 -3
  287. package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +87 -0
  288. package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +163 -0
  289. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -31
  290. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +78 -3
  291. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +2 -8
  292. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +1 -1
  293. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +73 -66
  294. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +51 -1
  295. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +49 -1
  296. package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +103 -0
  297. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +3 -3
  298. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +9 -8
  299. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +10 -7
  300. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +48 -6
  301. package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +90 -0
  302. package/dist/extensions/pi-subagents/test/unit/{pi-args-permission-system.test.ts → child-tool-plan-permission-system.test.ts} +48 -86
  303. package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +33 -0
  304. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +18 -18
  305. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +9 -9
  306. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +8 -7
  307. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +225 -65
  308. package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +17 -22
  309. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +11 -1
  310. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +47 -3
  311. package/dist/extensions/pi-subagents/test/unit/foreign-workflow-steering.test.ts +74 -0
  312. package/dist/extensions/pi-subagents/test/unit/fork-cache-key.test.ts +23 -29
  313. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +96 -4
  314. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +4 -4
  315. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +116 -55
  316. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +58 -1
  317. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +104 -3
  318. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
  319. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +31 -1
  320. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +102 -51
  321. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +196 -6
  322. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +181 -38
  323. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +62 -70
  324. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +58 -53
  325. package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +42 -0
  326. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +84 -0
  327. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +13 -5
  328. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +21 -5
  329. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +5 -4
  330. package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +2 -6
  331. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +28 -2
  332. package/dist/extensions/pi-subagents/test/unit/pi-web-session-liveness.test.ts +209 -0
  333. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +38 -1
  334. package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +43 -0
  335. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +24 -2
  336. package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +174 -0
  337. package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +94 -0
  338. package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +1329 -0
  339. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +29 -80
  340. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +11 -8
  341. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +2 -2
  342. package/dist/extensions/pi-subagents/test/unit/retained-nested-route-tracker.test.ts +175 -0
  343. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +38 -12
  344. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +2 -5
  345. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +89 -1
  346. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +2 -16
  347. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +27 -3
  348. package/dist/extensions/pi-subagents/test/unit/scheduled-supervisor-demand.test.ts +215 -0
  349. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +15 -11
  350. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +237 -1
  351. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -5
  352. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +2 -2
  353. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +14 -1
  354. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +130 -739
  355. package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +682 -0
  356. package/dist/extensions/pi-subagents/test/unit/supervisor-ui.test.ts +137 -0
  357. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +1 -11
  358. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +23 -3
  359. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +8 -1
  360. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +19 -1
  361. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +72 -4
  362. package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +17 -3
  363. package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +34 -0
  364. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +12 -2
  365. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +46 -6
  366. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +3 -3
  367. package/dist/extensions/pi-subagents/test/unit/workflow-resources.test.ts +133 -1
  368. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +53 -2
  369. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +222 -14
  370. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +526 -85
  371. package/dist/extensions/pi-web-agent/README.md +6 -5
  372. package/dist/extensions/pi-web-agent/src/backends/config.ts +12 -6
  373. package/dist/extensions/pi-web-agent/src/backends/factory.ts +2 -2
  374. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +4 -5
  375. package/dist/extensions/pi-web-agent/src/commands/web-agent-config.ts +8 -8
  376. package/dist/extensions/pi-web-agent/src/extension.ts +3 -3
  377. package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +2 -2
  378. package/dist/extensions/pi-web-agent/src/search/tokenin.ts +14 -3
  379. package/dist/extensions/pi-zentui/README.md +17 -0
  380. package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
  381. package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
  382. package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
  383. package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
  384. package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
  385. package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
  386. package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
  387. package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
  388. package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
  389. package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
  390. package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
  391. package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
  392. package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
  393. package/dist/extensions/pi-zentui/package-lock.json +277 -517
  394. package/dist/extensions/pi-zentui/package.json +7 -4
  395. package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
  396. package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
  397. package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
  398. package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
  399. package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
  400. package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
  401. package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
  402. package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
  403. package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
  404. package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
  405. package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
  406. package/dist/index.d.ts +1 -1
  407. package/dist/main.js +4 -1
  408. package/dist/modes/interactive/chat-viewport.d.ts +19 -0
  409. package/dist/modes/interactive/chat-viewport.js +27 -0
  410. package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
  411. package/dist/modes/interactive/components/assistant-message.js +30 -13
  412. package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
  413. package/dist/modes/interactive/components/custom-editor.js +39 -1
  414. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  415. package/dist/modes/interactive/components/index.d.ts +1 -1
  416. package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
  417. package/dist/modes/interactive/components/markdown-transform.js +18 -0
  418. package/dist/modes/interactive/components/model-selector.js +19 -17
  419. package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
  420. package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
  421. package/dist/modes/interactive/components/settings-selector.js +128 -20
  422. package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
  423. package/dist/modes/interactive/components/settings-submenu.js +164 -0
  424. package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
  425. package/dist/modes/interactive/components/status-indicator.js +10 -3
  426. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  427. package/dist/modes/interactive/components/thinking-selector.js +75 -18
  428. package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
  429. package/dist/modes/interactive/components/tool-execution.js +35 -33
  430. package/dist/modes/interactive/components/trust-selector.js +2 -2
  431. package/dist/modes/interactive/interactive-mode.d.ts +13 -15
  432. package/dist/modes/interactive/interactive-mode.js +144 -80
  433. package/dist/modes/interactive/session-share.d.ts +15 -0
  434. package/dist/modes/interactive/session-share.js +183 -0
  435. package/dist/modes/interactive/theme/dark.json +2 -1
  436. package/dist/modes/interactive/theme/light.json +2 -1
  437. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
  438. package/dist/modes/interactive/theme/theme-controller.js +5 -0
  439. package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
  440. package/dist/modes/interactive/theme/theme-json.js +129 -0
  441. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  442. package/dist/modes/interactive/theme/theme.d.ts +14 -5
  443. package/dist/modes/interactive/theme/theme.js +18 -119
  444. package/dist/modes/interactive/tui-renderer.d.ts +20 -0
  445. package/dist/modes/interactive/tui-renderer.js +65 -0
  446. package/dist/utils/exif-orientation.js +2 -3
  447. package/dist/utils/management-http.d.ts +24 -0
  448. package/dist/utils/management-http.js +53 -0
  449. package/dist/utils/text.d.ts +7 -0
  450. package/dist/utils/text.js +8 -0
  451. package/dist/utils/tools-manager.d.ts +1 -0
  452. package/dist/utils/tools-manager.js +43 -21
  453. package/docs/docs.json +0 -4
  454. package/package.json +6 -6
  455. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
  456. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
  457. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
  458. package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  459. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
  460. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
  461. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
  462. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
  463. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
  464. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
  465. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
  466. package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
  467. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
  468. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
  469. package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
  470. package/dist/extensions/web-agent-onboarding.test.ts +0 -415
  471. package/dist/extensions/web-agent-onboarding.ts +0 -222
  472. package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
  473. package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
  474. package/dist/skills/implanger/SKILL.md +0 -70
  475. package/dist/skills/output/SKILL.md +0 -49
  476. package/dist/skills/planger/SKILL.md +0 -167
  477. package/dist/skills/workflow/SKILL.md +0 -95
  478. package/docs/workflows.md +0 -18
  479. /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
@@ -1,104 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { describe, it } from "node:test";
3
- import type { Usage } from "../../src/shared/types.ts";
4
- import {
5
- MAX_SUBAGENT_STARTUP_FAILURE_DURATION_MS,
6
- SUBAGENT_STARTUP_RETRY_DELAYS_MS,
7
- formatSubagentExtensionConflictError,
8
- formatSubagentStartupRetryExhaustedError,
9
- formatSubagentStartupRetryNote,
10
- isRetryableSubagentStartupFailure,
11
- waitForSubagentStartupRetry,
12
- type SubagentStartupFailureEvidence,
13
- } from "../../src/runs/shared/subagent-startup-retry.ts";
14
-
15
- function emptyUsage(): Usage {
16
- return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
17
- }
18
-
19
- function startupFailure(overrides: Partial<SubagentStartupFailureEvidence> = {}): SubagentStartupFailureEvidence {
20
- return {
21
- exitCode: 1,
22
- messageCount: 0,
23
- toolCount: 0,
24
- usage: emptyUsage(),
25
- durationMs: 20,
26
- ...overrides,
27
- };
28
- }
29
-
30
- describe("subagent startup retry", () => {
31
- it("uses a bounded retry schedule", () => {
32
- assert.deepEqual(SUBAGENT_STARTUP_RETRY_DELAYS_MS, [250, 750, 1500]);
33
- });
34
-
35
- it("classifies a short non-zero exit with no child activity", () => {
36
- assert.equal(isRetryableSubagentStartupFailure(startupFailure()), true);
37
- });
38
-
39
- it("retries only the canonical zero-activity SIGKILL startup failure", () => {
40
- assert.equal(
41
- isRetryableSubagentStartupFailure(startupFailure({
42
- processSignal: "SIGKILL",
43
- error: "Subagent process terminated by signal SIGKILL.",
44
- })),
45
- true,
46
- );
47
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ processSignal: "SIGKILL" })), true);
48
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ processSignal: "SIGTERM" })), false);
49
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ processSignal: "SIGKILL", error: "authentication failed" })), false);
50
- });
51
-
52
- it("rejects successful, long-running, and diagnosed exits", () => {
53
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ exitCode: 0 })), false);
54
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ durationMs: MAX_SUBAGENT_STARTUP_FAILURE_DURATION_MS + 1 })), false);
55
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ error: "authentication failed" })), false);
56
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ finalOutput: "partial response" })), false);
57
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ protocolError: { code: "protocol_output_limit" } })), false);
58
- });
59
-
60
- it("rejects any model, tool, usage, mutation, or lifecycle activity", () => {
61
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ messageCount: 1 })), false);
62
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ toolCount: 1 })), false);
63
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ usage: { ...emptyUsage(), input: 1 } })), false);
64
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ usage: { ...emptyUsage(), turns: 1 } })), false);
65
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ observedMutationAttempt: true })), false);
66
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ detached: true })), false);
67
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ interrupted: true })), false);
68
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ timedOut: true })), false);
69
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ stopped: true })), false);
70
- assert.equal(isRetryableSubagentStartupFailure(startupFailure({ turnBudgetExceeded: true })), false);
71
- });
72
-
73
- it("adds actionable guidance for ambient extension registration conflicts", () => {
74
- const conflict = 'Error: Failed to load extension "/tmp/pi-mcp-adapter-clone/index.ts": Tool "mcpScript" conflicts with /tmp/pi-mcp-adapter/index.ts\nError: Failed to load extension "/tmp/pi-mcp-adapter-clone/index.ts": Flag "--mcp-config" conflicts with /tmp/pi-mcp-adapter/index.ts';
75
- const formatted = formatSubagentExtensionConflictError(conflict, {
76
- agent: "reviewer",
77
- ambientExtensionsEnabled: true,
78
- });
79
-
80
- assert.match(formatted ?? "", /loaded conflicting ambient Pi extensions/);
81
- assert.match(formatted ?? "", /\.selesai[\\/]settings\.json/);
82
- assert.match(formatted ?? "", /\{"subagents":\{"agentOverrides":\{"reviewer":\{"extensions":\[\]\}\}\}\}/);
83
- assert.equal(formatSubagentExtensionConflictError(conflict, { agent: "reviewer", ambientExtensionsEnabled: false }), conflict);
84
- assert.equal(formatSubagentExtensionConflictError("authentication failed", { agent: "reviewer", ambientExtensionsEnabled: true }), "authentication failed");
85
- });
86
-
87
- it("formats retry and exhaustion diagnostics without task content", () => {
88
- assert.equal(
89
- formatSubagentStartupRetryNote({ model: "openai/test", attempt: 1, maxAttempts: 4, delayMs: 250 }),
90
- "[startup-retry] openai/test exited before model or tool activity (attempt 1/4). Retrying the same model in 250ms.",
91
- );
92
- assert.match(
93
- formatSubagentStartupRetryExhaustedError({ model: "openai/test", attempts: 4 }),
94
- /failed to start after 4 attempts.*concurrent Pi startup race.*lower subagent concurrency/i,
95
- );
96
- });
97
-
98
- it("cancels a pending retry delay", async () => {
99
- const controller = new AbortController();
100
- const wait = waitForSubagentStartupRetry(5000, [controller.signal]);
101
- controller.abort();
102
- assert.equal(await wait, false);
103
- });
104
- });
@@ -1,49 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import * as fs from "node:fs";
3
- import * as path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { describe, it } from "node:test";
6
-
7
- const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
8
-
9
- function assertNestedPiSpawnHidesWindows(sourcePath: string): void {
10
- const source = fs.readFileSync(path.join(projectRoot, sourcePath), "utf-8");
11
- assert.match(
12
- source,
13
- /spawn\(spawnSpec\.command,\s*spawnSpec\.args,\s*\{[^}]*windowsHide:\s*true/s,
14
- `${sourcePath} nested Pi spawn should set windowsHide: true`,
15
- );
16
- }
17
-
18
- describe("nested child Pi process visibility", () => {
19
- it("publishes detached terminal results before terminal status", () => {
20
- const sourcePath = "src/runs/background/subagent-runner.ts";
21
- const source = fs.readFileSync(path.join(projectRoot, sourcePath), "utf-8");
22
- const terminalBlockStart = source.indexOf("\tstatusPayload.endedAt = runEndedAt;");
23
- const resultWrite = source.indexOf("\trunPersistence.write(resultPath, {", terminalBlockStart);
24
- const terminalStatusWrite = source.indexOf("\twriteStatusPayload();", terminalBlockStart);
25
-
26
- assert.ok(terminalBlockStart >= 0, `${sourcePath} terminal block should exist`);
27
- assert.ok(resultWrite > terminalBlockStart, `${sourcePath} should publish the terminal result`);
28
- assert.ok(terminalStatusWrite > resultWrite, `${sourcePath} must not expose terminal status before the terminal result`);
29
- });
30
-
31
- it("hides foreground child Pi process windows on Windows", () => {
32
- assertNestedPiSpawnHidesWindows("src/runs/foreground/execution.ts");
33
- });
34
-
35
- it("hides background child Pi process windows on Windows", () => {
36
- assertNestedPiSpawnHidesWindows("src/runs/background/subagent-runner.ts");
37
- });
38
-
39
- it("hides mutation-evidence Git process windows on Windows", () => {
40
- const sourcePath = "src/runs/shared/mutation-evidence.ts";
41
- const source = fs.readFileSync(path.join(projectRoot, sourcePath), "utf-8");
42
- const gitExecCalls = source.match(/execFileSync\(\s*"git"[\s\S]*?\{[^}]*\}\s*\)/g) ?? [];
43
-
44
- assert.equal(gitExecCalls.length, 2, `${sourcePath} should have exactly two Git execFileSync calls`);
45
- for (const call of gitExecCalls) {
46
- assert.match(call, /\bwindowsHide:\s*true\b/, `${sourcePath} Git execFileSync should set windowsHide: true`);
47
- }
48
- });
49
- });
@@ -1,415 +0,0 @@
1
- import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
-
6
- vi.mock("@selesai/code", () => ({
7
- getAgentDir: () => process.env.SELESAI_CODING_AGENT_DIR ?? join(require("node:os").homedir(), ".selesai", "agent"),
8
- getSettingsPath: () => join(process.env.SELESAI_CODING_AGENT_DIR ?? join(require("node:os").homedir(), ".selesai", "agent"), "settings.json"),
9
- }));
10
-
11
- import {
12
- BRAVE_KEYS_URL,
13
- getBraveApiKey,
14
- getWebAgentConfigPath,
15
- isPlaceholderKey,
16
- ONBOARDING_MARKER_NAME,
17
- readSettingsJson,
18
- setBraveApiKey,
19
- validateBraveKey,
20
- WEB_AGENT_CONFIG_SUBPATH,
21
- writeSettingsJson,
22
- writeWebAgentBraveBackendConfig,
23
- } from "./web-agent-onboarding.ts";
24
- import webAgentOnboardingExtension from "./web-agent-onboarding.ts";
25
- import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, SessionStartEvent } from "../core/extensions/types.ts";
26
-
27
- let agentDir: string;
28
-
29
- beforeEach(() => {
30
- agentDir = mkdtempSync(join(tmpdir(), "web-agent-ob-"));
31
- process.env.SELESAI_CODING_AGENT_DIR = agentDir;
32
- });
33
-
34
- afterEach(() => {
35
- rmSync(agentDir, { recursive: true, force: true });
36
- delete process.env.SELESAI_CODING_AGENT_DIR;
37
- });
38
-
39
- describe("web-agent-onboarding helpers", () => {
40
- it("isPlaceholderKey returns true for missing/empty/non-string values", () => {
41
- expect(isPlaceholderKey(undefined)).toBe(true);
42
- expect(isPlaceholderKey(null)).toBe(true);
43
- expect(isPlaceholderKey("")).toBe(true);
44
- expect(isPlaceholderKey(" ")).toBe(true);
45
- expect(isPlaceholderKey(42)).toBe(true);
46
- expect(isPlaceholderKey("BSA123abc")).toBe(false);
47
- });
48
-
49
- it("getBraveApiKey reads the nested value safely", () => {
50
- expect(getBraveApiKey({})).toBeUndefined();
51
- expect(getBraveApiKey({ webAgent: "not-an-object" })).toBeUndefined();
52
- expect(getBraveApiKey({ webAgent: [] })).toBeUndefined();
53
- expect(getBraveApiKey({ webAgent: { braveApiKey: "key-1" } })).toBe("key-1");
54
- });
55
-
56
- it("setBraveApiKey clones and sets the nested value", () => {
57
- const original = { other: 1, webAgent: { braveApiKey: "old" } };
58
- const next = setBraveApiKey(original, "new-key");
59
- expect(next.webAgent).toEqual({ braveApiKey: "new-key" });
60
- expect(next.other).toBe(1);
61
- // original is not mutated
62
- expect(original.webAgent.braveApiKey).toBe("old");
63
- // missing/non-object webAgent is replaced
64
- expect(setBraveApiKey({}, "k").webAgent).toEqual({ braveApiKey: "k" });
65
- expect(setBraveApiKey({ webAgent: "x" }, "k").webAgent).toEqual({ braveApiKey: "k" });
66
- expect(setBraveApiKey({ webAgent: [] }, "k").webAgent).toEqual({ braveApiKey: "k" });
67
- });
68
-
69
- it("validateBraveKey trims and reports errors", () => {
70
- expect(validateBraveKey(" BSA-key ")).toEqual({ key: "BSA-key" });
71
- expect(validateBraveKey("")).toEqual({ error: "Key cannot be empty." });
72
- expect(validateBraveKey(" ")).toEqual({ error: "Key cannot be empty." });
73
- expect(validateBraveKey(undefined)).toEqual({ error: "No key entered." });
74
- expect(validateBraveKey(null as unknown as string)).toEqual({ error: "No key entered." });
75
- });
76
-
77
- it("readSettingsJson parses existing file, defaults to {} for missing/corrupt", () => {
78
- const settingsPath = join(agentDir, "settings.json");
79
- writeFileSync(settingsPath, '{"webAgent":{"braveApiKey":"k"}}', "utf-8");
80
- expect(readSettingsJson(settingsPath)).toEqual({ webAgent: { braveApiKey: "k" } });
81
- expect(readSettingsJson(join(agentDir, "missing.json"))).toEqual({});
82
- writeFileSync(settingsPath, "{not json", "utf-8");
83
- expect(readSettingsJson(settingsPath)).toEqual({});
84
- });
85
-
86
- it("writeSettingsJson creates dirs and writes pretty JSON with trailing newline", () => {
87
- const deep = join(agentDir, "nested", "dir");
88
- const settingsPath = join(deep, "settings.json");
89
- writeSettingsJson({ a: 1 }, settingsPath);
90
- expect(readFileSync(settingsPath, "utf-8")).toBe('{\n "a": 1\n}\n');
91
- });
92
-
93
- it("getWebAgentConfigPath joins agentDir with the config subpath", () => {
94
- expect(getWebAgentConfigPath(agentDir)).toBe(join(agentDir, "extensions", "pi-web-agent", "config.json"));
95
- expect(WEB_AGENT_CONFIG_SUBPATH).toBe(join("extensions", "pi-web-agent", "config.json"));
96
- });
97
-
98
- it("writeWebAgentBraveBackendConfig writes brave with duckduckgo fallback, merging existing", () => {
99
- const configPath = getWebAgentConfigPath(agentDir);
100
- // Pre-seed an existing config to verify merge-not-clobber.
101
- mkdirSync(join(agentDir, "extensions", "pi-web-agent"), { recursive: true });
102
- writeFileSync(configPath, '{"presentation":{"theme":"dark"}}', "utf-8");
103
- writeWebAgentBraveBackendConfig(agentDir);
104
- const parsed = JSON.parse(readFileSync(configPath, "utf-8"));
105
- expect(parsed.presentation).toEqual({ theme: "dark" });
106
- expect(parsed.backends.search).toEqual({ provider: "brave", fallback: "duckduckgo" });
107
- });
108
-
109
- it("writeWebAgentBraveBackendConfig tolerates missing/corrupt existing config", () => {
110
- const configPath = getWebAgentConfigPath(agentDir);
111
- mkdirSync(join(agentDir, "extensions", "pi-web-agent"), { recursive: true });
112
- writeFileSync(configPath, "{corrupt", "utf-8");
113
- writeWebAgentBraveBackendConfig(agentDir);
114
- const parsed = JSON.parse(readFileSync(configPath, "utf-8"));
115
- expect(parsed.backends.search).toEqual({ provider: "brave", fallback: "duckduckgo" });
116
-
117
- // Missing file entirely -> starts fresh.
118
- const freshDir = mkdtempSync(join(tmpdir(), "web-agent-fresh-"));
119
- writeWebAgentBraveBackendConfig(freshDir);
120
- const freshParsed = JSON.parse(readFileSync(join(freshDir, WEB_AGENT_CONFIG_SUBPATH), "utf-8"));
121
- expect(freshParsed.backends.search).toEqual({ provider: "brave", fallback: "duckduckgo" });
122
- rmSync(freshDir, { recursive: true, force: true });
123
- });
124
- });
125
-
126
- describe("web-agent-onboarding constants and markers", () => {
127
- it("exports the Brave keys URL and marker name", () => {
128
- expect(BRAVE_KEYS_URL).toContain("brave.com");
129
- expect(ONBOARDING_MARKER_NAME).toBe(".webAgentOnboardingComplete");
130
- });
131
- });
132
-
133
- describe("web-agent-onboarding extension lifecycle", () => {
134
- function makePi(overrides: Partial<ExtensionAPI> = {}): { pi: ExtensionAPI; on: ReturnType<typeof vi.fn>; registerCommand: ReturnType<typeof vi.fn> } {
135
- const on = vi.fn();
136
- const registerCommand = vi.fn();
137
- const pi = { on, registerCommand, ...overrides } as unknown as ExtensionAPI;
138
- webAgentOnboardingExtension(pi);
139
- return { pi, on, registerCommand };
140
- }
141
-
142
- function sessionStartHandler(pi: ExtensionAPI): (event: SessionStartEvent, ctx: ExtensionContext) => Promise<void> {
143
- return (pi.on as ReturnType<typeof vi.fn>).mock.calls.find(([event]: [string]) => event === "session_start")![1];
144
- }
145
-
146
- it("registers session_start and setup-web-search command", () => {
147
- const { on, registerCommand } = makePi();
148
- expect(on).toHaveBeenCalledWith("session_start", expect.any(Function));
149
- expect(registerCommand).toHaveBeenCalledWith("setup-web-search", expect.objectContaining({ description: expect.stringContaining("Brave") }));
150
- });
151
-
152
- it("session_start ignores non-startup reasons", async () => {
153
- const { pi } = makePi();
154
- const handler = sessionStartHandler(pi);
155
- const ctx = { hasUI: true } as unknown as ExtensionContext;
156
- await handler({ reason: "reload" } as SessionStartEvent, ctx);
157
- // No marker written, no prompt: marker missing proves no completion occurred.
158
- expect(existsSync(join(agentDir, ONBOARDING_MARKER_NAME))).toBe(false);
159
- });
160
-
161
- it("session_start skips when onboarding is already complete", async () => {
162
- writeFileSync(join(agentDir, ONBOARDING_MARKER_NAME), "1", "utf-8");
163
- const { pi } = makePi();
164
- const handler = sessionStartHandler(pi);
165
- const input = vi.fn();
166
- const ctx = { hasUI: true, ui: { input } } as unknown as ExtensionContext;
167
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
168
- expect(input).not.toHaveBeenCalled();
169
- });
170
-
171
- it("session_start defers when SELESAI_SKIP_WEB_AGENT_ONBOARDING=1", async () => {
172
- process.env.SELESAI_SKIP_WEB_AGENT_ONBOARDING = "1";
173
- try {
174
- const { pi } = makePi();
175
- const handler = sessionStartHandler(pi);
176
- const input = vi.fn();
177
- const ctx = { hasUI: true, ui: { input } } as unknown as ExtensionContext;
178
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
179
- expect(input).not.toHaveBeenCalled();
180
- } finally {
181
- delete process.env.SELESAI_SKIP_WEB_AGENT_ONBOARDING;
182
- }
183
- });
184
-
185
- it("session_start skips when no UI is available", async () => {
186
- const { pi } = makePi();
187
- const handler = sessionStartHandler(pi);
188
- const input = vi.fn();
189
- const ctx = { hasUI: false, ui: { input } } as unknown as ExtensionContext;
190
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
191
- expect(input).not.toHaveBeenCalled();
192
- });
193
-
194
- it("already-configured key defers and marks complete", async () => {
195
- const settingsPath = join(agentDir, "settings.json");
196
- writeFileSync(settingsPath, '{"webAgent":{"braveApiKey":"existing-key"}}', "utf-8");
197
- const { pi } = makePi();
198
- const handler = sessionStartHandler(pi);
199
- const confirm = vi.fn();
200
- const ctx = { hasUI: true, ui: { confirm } } as unknown as ExtensionContext;
201
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
202
- expect(confirm).not.toHaveBeenCalled();
203
- expect(existsSync(join(agentDir, ONBOARDING_MARKER_NAME))).toBe(true);
204
- });
205
-
206
- it("declining Brave skips onboarding and notifies", async () => {
207
- const { pi } = makePi();
208
- const handler = sessionStartHandler(pi);
209
- const notify = vi.fn();
210
- const ctx = { hasUI: true, ui: { confirm: async () => false, notify } } as unknown as ExtensionContext;
211
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
212
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("skipped"), "info");
213
- expect(existsSync(join(agentDir, ONBOARDING_MARKER_NAME))).toBe(true);
214
- });
215
-
216
- it("accepting Brave saves the key and config", async () => {
217
- const { pi } = makePi();
218
- const handler = sessionStartHandler(pi);
219
- const notify = vi.fn();
220
- const exec = vi.fn().mockResolvedValue({ code: 0, stdout: "", stderr: "" });
221
- const ctx = {
222
- hasUI: true,
223
- ui: { confirm: async () => true, input: async () => " BSA-my-key ", notify },
224
- } as unknown as ExtensionContext;
225
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
226
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("saved"), "info");
227
- expect(exec).not.toHaveBeenCalled(); // openBraveKeysUrl uses pi.exec — not provided here
228
- const settings = JSON.parse(readFileSync(join(agentDir, "settings.json"), "utf-8"));
229
- expect(settings.webAgent.braveApiKey).toBe("BSA-my-key");
230
- const config = JSON.parse(readFileSync(join(agentDir, WEB_AGENT_CONFIG_SUBPATH), "utf-8"));
231
- expect(config.backends.search).toEqual({ provider: "brave", fallback: "duckduckgo" });
232
- expect(existsSync(join(agentDir, ONBOARDING_MARKER_NAME))).toBe(true);
233
- });
234
-
235
- it("accepting Brave with browser open failure still saves", async () => {
236
- const { pi } = makePi();
237
- const handler = sessionStartHandler(pi);
238
- const notify = vi.fn();
239
- const exec = vi.fn().mockResolvedValue({ code: 1, stdout: "", stderr: "no browser" });
240
- const ctx = {
241
- hasUI: true,
242
- ui: { confirm: async () => true, input: async () => "BSA-key", notify },
243
- } as unknown as ExtensionContext;
244
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
245
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("Could not open browser"), "warning");
246
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("manually"), "info");
247
- const settings = JSON.parse(readFileSync(join(agentDir, "settings.json"), "utf-8"));
248
- expect(settings.webAgent.braveApiKey).toBe("BSA-key");
249
- });
250
-
251
- describe("openBraveKeysUrl platform branches", () => {
252
- it("uses win32 command and still saves on zero exit", async () => {
253
- const original = process.platform;
254
- const exec = vi.fn().mockResolvedValue({ code: 0, stdout: "", stderr: "" });
255
- try {
256
- Object.defineProperty(process, "platform", { value: "win32", configurable: true });
257
- const { pi } = makePi({ exec } as unknown as ExtensionAPI);
258
- const handler = sessionStartHandler(pi);
259
- const notify = vi.fn();
260
- const ctx = {
261
- hasUI: true,
262
- ui: { confirm: async () => true, input: async () => "BSA-win", notify },
263
- } as unknown as ExtensionContext;
264
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
265
- expect(exec).toHaveBeenCalledWith("cmd", ["/c", "start", "", BRAVE_KEYS_URL], { timeout: 10_000 });
266
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("Opened the Brave API key dashboard"), "info");
267
- } finally {
268
- Object.defineProperty(process, "platform", { value: original, configurable: true });
269
- }
270
- });
271
-
272
- it("uses xdg-open on other platforms", async () => {
273
- const original = process.platform;
274
- const exec = vi.fn().mockResolvedValue({ code: 0, stdout: "", stderr: "" });
275
- try {
276
- Object.defineProperty(process, "platform", { value: "linux", configurable: true });
277
- const { pi } = makePi({ exec } as unknown as ExtensionAPI);
278
- const handler = sessionStartHandler(pi);
279
- const notify = vi.fn();
280
- const ctx = {
281
- hasUI: true,
282
- ui: { confirm: async () => true, input: async () => "BSA-lin", notify },
283
- } as unknown as ExtensionContext;
284
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
285
- expect(exec).toHaveBeenCalledWith("xdg-open", [BRAVE_KEYS_URL], { timeout: 10_000 });
286
- } finally {
287
- Object.defineProperty(process, "platform", { value: original, configurable: true });
288
- }
289
- });
290
-
291
- it("non-zero exit warns and opens the manual URL even after a string error", async () => {
292
- const original = process.platform;
293
- const exec = vi.fn().mockResolvedValue({ code: 1, stdout: "", stderr: "browser failed" });
294
- try {
295
- Object.defineProperty(process, "platform", { value: "darwin", configurable: true });
296
- const { pi } = makePi({ exec } as unknown as ExtensionAPI);
297
- const handler = sessionStartHandler(pi);
298
- const notify = vi.fn();
299
- const ctx = {
300
- hasUI: true,
301
- ui: { confirm: async () => true, input: async () => "BSA-err", notify },
302
- } as unknown as ExtensionContext;
303
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
304
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("Could not open browser: Failed to open"), "warning");
305
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("manually"), "info");
306
- // Even though the browser failed, the key is still saved.
307
- const settings = JSON.parse(readFileSync(join(agentDir, "settings.json"), "utf-8"));
308
- expect(settings.webAgent.braveApiKey).toBe("BSA-err");
309
- } finally {
310
- Object.defineProperty(process, "platform", { value: original, configurable: true });
311
- }
312
- });
313
-
314
- it("a rejecting exec (non-Error) still warns without crashing the flow", async () => {
315
- const original = process.platform;
316
- const exec = vi.fn().mockRejectedValue("plain string failure");
317
- try {
318
- Object.defineProperty(process, "platform", { value: "darwin", configurable: true });
319
- const { pi } = makePi({ exec } as unknown as ExtensionAPI);
320
- const handler = sessionStartHandler(pi);
321
- const notify = vi.fn();
322
- const ctx = {
323
- hasUI: true,
324
- ui: { confirm: async () => true, input: async () => "BSA-rej", notify },
325
- } as unknown as ExtensionContext;
326
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
327
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("Could not open browser: plain string failure"), "warning");
328
- const settings = JSON.parse(readFileSync(join(agentDir, "settings.json"), "utf-8"));
329
- expect(settings.webAgent.braveApiKey).toBe("BSA-rej");
330
- } finally {
331
- Object.defineProperty(process, "platform", { value: original, configurable: true });
332
- }
333
- });
334
- it("non-zero exit with both stderr and stdout empty falls back to unknown error", async () => {
335
- const original = process.platform;
336
- const exec = vi.fn().mockResolvedValue({ code: 1, stdout: "", stderr: "" });
337
- try {
338
- Object.defineProperty(process, "platform", { value: "darwin", configurable: true });
339
- const { pi } = makePi({ exec } as unknown as ExtensionAPI);
340
- const handler = sessionStartHandler(pi);
341
- const notify = vi.fn();
342
- const ctx = {
343
- hasUI: true,
344
- ui: { confirm: async () => true, input: async () => "BSA-un", notify },
345
- } as unknown as ExtensionContext;
346
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
347
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("unknown error"), "warning");
348
- const settings = JSON.parse(readFileSync(join(agentDir, "settings.json"), "utf-8"));
349
- expect(settings.webAgent.braveApiKey).toBe("BSA-un");
350
- } finally {
351
- Object.defineProperty(process, "platform", { value: original, configurable: true });
352
- }
353
- });
354
- });
355
-
356
- it("empty pasted key defers without saving", async () => {
357
- const { pi } = makePi();
358
- const handler = sessionStartHandler(pi);
359
- const notify = vi.fn();
360
- const ctx = {
361
- hasUI: true,
362
- ui: { confirm: async () => true, input: async () => " ", notify },
363
- } as unknown as ExtensionContext;
364
- await handler({ reason: "startup" } as SessionStartEvent, ctx);
365
- expect(notify).toHaveBeenCalledWith("Key cannot be empty.", "warning");
366
- expect(existsSync(join(agentDir, ONBOARDING_MARKER_NAME))).toBe(false);
367
- expect(existsSync(join(agentDir, "settings.json"))).toBe(false);
368
- });
369
-
370
- it("setup-web-search command saves and reloads extensions", async () => {
371
- const exec = vi.fn().mockResolvedValue({ code: 0, stdout: "", stderr: "" });
372
- const { registerCommand } = makePi({ exec } as unknown as ExtensionAPI);
373
- const { handler } = registerCommand.mock.calls.find(([name]: [string]) => name === "setup-web-search")![1] as { handler: (args: string, ctx: ExtensionCommandContext) => Promise<void> };
374
- const reload = vi.fn().mockResolvedValue(undefined);
375
- const notify = vi.fn();
376
- const ctx = {
377
- hasUI: true,
378
- reload,
379
- ui: { confirm: async () => true, input: async () => "BSA-key", notify },
380
- } as unknown as ExtensionCommandContext;
381
- await handler("", ctx);
382
- expect(reload).toHaveBeenCalled();
383
- expect(notify).toHaveBeenCalledWith(expect.stringContaining("reloading extensions"), "info");
384
- const settings = JSON.parse(readFileSync(join(agentDir, "settings.json"), "utf-8"));
385
- expect(settings.webAgent.braveApiKey).toBe("BSA-key");
386
- });
387
-
388
- it("setup-web-search command does not reload when skipped", async () => {
389
- const { registerCommand } = makePi();
390
- const { handler } = registerCommand.mock.calls.find(([name]: [string]) => name === "setup-web-search")![1] as { handler: (args: string, ctx: ExtensionCommandContext) => Promise<void> };
391
- const reload = vi.fn();
392
- const notify = vi.fn();
393
- const ctx = {
394
- hasUI: true,
395
- reload,
396
- ui: { confirm: async () => false, notify },
397
- } as unknown as ExtensionCommandContext;
398
- await handler("", ctx);
399
- expect(reload).not.toHaveBeenCalled();
400
- });
401
-
402
- it("setup-web-search command defers (no reload) when key is invalid", async () => {
403
- const { registerCommand } = makePi();
404
- const { handler } = registerCommand.mock.calls.find(([name]: [string]) => name === "setup-web-search")![1] as { handler: (args: string, ctx: ExtensionCommandContext) => Promise<void> };
405
- const reload = vi.fn();
406
- const notify = vi.fn();
407
- const ctx = {
408
- hasUI: true,
409
- reload,
410
- ui: { confirm: async () => true, input: async () => "", notify },
411
- } as unknown as ExtensionCommandContext;
412
- await handler("", ctx);
413
- expect(reload).not.toHaveBeenCalled();
414
- });
415
- });