@selesai/code 0.13.15 → 0.13.18

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 (473) hide show
  1. package/CHANGELOG.md +37 -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/capability-gateway/index.ts +12 -1
  65. package/dist/extensions/capability-gateway/integration.test.ts +23 -0
  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/src/backends/config.ts +1 -0
  372. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +5 -3
  373. package/dist/extensions/pi-web-agent/src/search/tokenin.ts +7 -3
  374. package/dist/extensions/pi-web-agent/src/types.ts +1 -1
  375. package/dist/extensions/pi-zentui/README.md +17 -0
  376. package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
  377. package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
  378. package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
  379. package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
  380. package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
  381. package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
  382. package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
  383. package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
  384. package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
  385. package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
  386. package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
  387. package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
  388. package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
  389. package/dist/extensions/pi-zentui/package-lock.json +277 -517
  390. package/dist/extensions/pi-zentui/package.json +7 -4
  391. package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
  392. package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
  393. package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
  394. package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
  395. package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
  396. package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
  397. package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
  398. package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
  399. package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
  400. package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
  401. package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
  402. package/dist/index.d.ts +1 -1
  403. package/dist/main.js +4 -1
  404. package/dist/modes/interactive/chat-viewport.d.ts +19 -0
  405. package/dist/modes/interactive/chat-viewport.js +27 -0
  406. package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
  407. package/dist/modes/interactive/components/assistant-message.js +30 -13
  408. package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
  409. package/dist/modes/interactive/components/custom-editor.js +39 -1
  410. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  411. package/dist/modes/interactive/components/index.d.ts +1 -1
  412. package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
  413. package/dist/modes/interactive/components/markdown-transform.js +18 -0
  414. package/dist/modes/interactive/components/model-selector.js +19 -17
  415. package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
  416. package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
  417. package/dist/modes/interactive/components/settings-selector.js +128 -20
  418. package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
  419. package/dist/modes/interactive/components/settings-submenu.js +164 -0
  420. package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
  421. package/dist/modes/interactive/components/status-indicator.js +10 -3
  422. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  423. package/dist/modes/interactive/components/thinking-selector.js +75 -18
  424. package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
  425. package/dist/modes/interactive/components/tool-execution.js +35 -33
  426. package/dist/modes/interactive/components/trust-selector.js +2 -2
  427. package/dist/modes/interactive/interactive-mode.d.ts +13 -15
  428. package/dist/modes/interactive/interactive-mode.js +144 -80
  429. package/dist/modes/interactive/session-share.d.ts +15 -0
  430. package/dist/modes/interactive/session-share.js +183 -0
  431. package/dist/modes/interactive/theme/dark.json +2 -1
  432. package/dist/modes/interactive/theme/light.json +2 -1
  433. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
  434. package/dist/modes/interactive/theme/theme-controller.js +5 -0
  435. package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
  436. package/dist/modes/interactive/theme/theme-json.js +129 -0
  437. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  438. package/dist/modes/interactive/theme/theme.d.ts +14 -5
  439. package/dist/modes/interactive/theme/theme.js +18 -119
  440. package/dist/modes/interactive/tui-renderer.d.ts +20 -0
  441. package/dist/modes/interactive/tui-renderer.js +65 -0
  442. package/dist/utils/exif-orientation.js +2 -3
  443. package/dist/utils/management-http.d.ts +24 -0
  444. package/dist/utils/management-http.js +53 -0
  445. package/dist/utils/text.d.ts +7 -0
  446. package/dist/utils/text.js +8 -0
  447. package/dist/utils/tools-manager.d.ts +1 -0
  448. package/dist/utils/tools-manager.js +43 -21
  449. package/docs/docs.json +0 -4
  450. package/package.json +4 -4
  451. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
  452. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
  453. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
  454. package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  455. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
  456. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
  457. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
  458. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
  459. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
  460. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
  461. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
  462. package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
  463. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
  464. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
  465. package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
  466. package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
  467. package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
  468. package/dist/skills/implanger/SKILL.md +0 -70
  469. package/dist/skills/output/SKILL.md +0 -49
  470. package/dist/skills/planger/SKILL.md +0 -167
  471. package/dist/skills/workflow/SKILL.md +0 -95
  472. package/docs/workflows.md +0 -18
  473. /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
@@ -22,6 +22,7 @@ export interface ApplyReviewOperationsResult {
22
22
  appliedCount: number;
23
23
  skippedCount: number;
24
24
  error?: string;
25
+ aborted?: boolean;
25
26
  }
26
27
 
27
28
  export interface DirectReviewResult {
@@ -34,7 +35,7 @@ export interface DirectReviewResult {
34
35
  export interface RunDirectMemoryCompletionOptions {
35
36
  userPrompt: string;
36
37
  systemPrompt: string;
37
- config: Pick<MemoryConfig, "llmModelOverride" | "llmThinkingOverride">;
38
+ config: Pick<MemoryConfig, "llmModelOverride" | "llmFallbackModels" | "llmThinkingOverride">;
38
39
  timeoutMs?: number;
39
40
  signal?: AbortSignal;
40
41
  requireAtomicShrink?: boolean;
@@ -48,7 +49,7 @@ export function usesDirectTransport(config: Pick<MemoryConfig, "reviewTransport"
48
49
  return (config.reviewTransport ?? "direct") === "direct";
49
50
  }
50
51
 
51
- type ReviewLlmConfig = Pick<MemoryConfig, "llmModelOverride" | "llmThinkingOverride">;
52
+ type ReviewLlmConfig = Pick<MemoryConfig, "llmModelOverride" | "llmFallbackModels" | "llmThinkingOverride">;
52
53
 
53
54
  function findExactModelReferenceMatch(modelReference: string, availableModels: Model<Api>[]): Model<Api> | undefined {
54
55
  const trimmedReference = modelReference.trim();
@@ -83,6 +84,22 @@ function normalizedModelOverride(config: ReviewLlmConfig): string | undefined {
83
84
  return trimmed ? trimmed : undefined;
84
85
  }
85
86
 
87
+ function collectFallbackOverrides(config: ReviewLlmConfig): string[] {
88
+ const out: string[] = [];
89
+ for (const raw of config.llmFallbackModels ?? []) {
90
+ const t = raw.trim();
91
+ if (t) out.push(t);
92
+ }
93
+ return out;
94
+ }
95
+
96
+ function allModelOverrides(config: ReviewLlmConfig): string[] {
97
+ const primary = normalizedModelOverride(config);
98
+ const fallbacks = collectFallbackOverrides(config);
99
+ const chain = primary ? [primary, ...fallbacks] : fallbacks;
100
+ return [...new Set(chain)];
101
+ }
102
+
86
103
  function effectiveThinkingOverride(config: ReviewLlmConfig): ThinkingLevel | undefined {
87
104
  return config.llmThinkingOverride ?? (normalizedModelOverride(config) ? "off" : undefined);
88
105
  }
@@ -92,7 +109,7 @@ type ReviewModelRegistry = ExtensionContext["modelRegistry"];
92
109
  /** Derived from the installed SDK so headers/baseUrl track ProviderHeaders instead of a local mirror. */
93
110
  export type ResolvedRequestAuth = Awaited<ReturnType<ReviewModelRegistry["getApiKeyAndHeaders"]>>;
94
111
 
95
- type DirectReviewAuth = Omit<Extract<ResolvedRequestAuth, { ok: true }>, "ok"> & { apiKey: string };
112
+ type DirectReviewAuth = Omit<Extract<ResolvedRequestAuth, { ok: true }>, "ok">;
96
113
 
97
114
  export function buildDirectReviewCompletionOptions(
98
115
  model: Model<Api>,
@@ -125,6 +142,28 @@ export function resolveReviewModel(
125
142
  return ctxModel;
126
143
  }
127
144
 
145
+ export function resolveReviewModels(
146
+ ctxModel: Model<Api> | undefined,
147
+ modelRegistry: ReviewModelRegistry,
148
+ config: ReviewLlmConfig,
149
+ ): Model<Api>[] {
150
+ const chain = allModelOverrides(config);
151
+ if (chain.length === 0) return ctxModel ? [ctxModel] : [];
152
+ const all = modelRegistry.getAll();
153
+ const resolved: Model<Api>[] = [];
154
+ for (const ref of chain) {
155
+ const m = findExactModelReferenceMatch(ref, all);
156
+ if (m) resolved.push(m);
157
+ }
158
+ // If none of the chain resolved, fall back to active model so we still try something
159
+ if (resolved.length === 0 && ctxModel) resolved.push(ctxModel);
160
+ return resolved;
161
+ }
162
+
163
+ export function getReviewModelChain(config: ReviewLlmConfig): string[] {
164
+ return allModelOverrides(config);
165
+ }
166
+
128
167
  /**
129
168
  * Provider responses that mean "this key is no longer good", as opposed to a
130
169
  * transport hiccup or a model error worth falling back to a subprocess for.
@@ -143,6 +182,54 @@ export function isAuthRejection(message: string): boolean {
143
182
  return AUTH_REJECTION_PATTERN.test(message);
144
183
  }
145
184
 
185
+ const CREDENTIAL_HEADER_NAMES = new Set(["authorization", "x-api-key", "cf-aig-authorization"]);
186
+
187
+ function isNonEmptyString(value: unknown): value is string {
188
+ return typeof value === "string" && value.trim().length > 0;
189
+ }
190
+
191
+ function hasRequestAuth(auth: DirectReviewAuth): boolean {
192
+ if (isNonEmptyString(auth.apiKey)) return true;
193
+ return Object.entries(auth.headers ?? {}).some(
194
+ ([key, value]) => CREDENTIAL_HEADER_NAMES.has(key.toLowerCase()) && isNonEmptyString(value),
195
+ );
196
+ }
197
+
198
+ function sameStringRecord(
199
+ left: Record<string, string> | undefined,
200
+ right: Record<string, string> | undefined,
201
+ ): boolean {
202
+ const leftEntries = Object.entries(left ?? {});
203
+ const rightKeys = Object.keys(right ?? {});
204
+ return leftEntries.length === rightKeys.length
205
+ && leftEntries.every(([key, value]) => right?.[key] === value);
206
+ }
207
+
208
+ function headerPairs(headers: DirectReviewAuth["headers"]): Array<[string, string | null]> {
209
+ return Object.entries(headers ?? {}).map(([key, value]) => [key.toLowerCase(), value]);
210
+ }
211
+
212
+ function sameHeaders(
213
+ left: DirectReviewAuth["headers"],
214
+ right: DirectReviewAuth["headers"],
215
+ ): boolean {
216
+ const remaining = headerPairs(right);
217
+ const leftPairs = headerPairs(left);
218
+ if (leftPairs.length !== remaining.length) return false;
219
+ for (const [key, value] of leftPairs) {
220
+ const index = remaining.findIndex((pair) => pair[0] === key && pair[1] === value);
221
+ if (index === -1) return false;
222
+ remaining.splice(index, 1);
223
+ }
224
+ return true;
225
+ }
226
+
227
+ function sameRequestAuth(left: DirectReviewAuth, right: DirectReviewAuth): boolean {
228
+ return left.apiKey === right.apiKey
229
+ && sameHeaders(left.headers, right.headers)
230
+ && sameStringRecord(left.env, right.env);
231
+ }
232
+
146
233
  /**
147
234
  * Resolve request auth through the public ModelRegistry API. Resolve it again
148
235
  * after an auth rejection so Pi can supply refreshed credentials when its
@@ -246,6 +333,7 @@ export async function applyReviewOperations(
246
333
  options: {
247
334
  requireAtomicShrink?: boolean;
248
335
  expectedTarget?: ReviewMemoryOperation["target"];
336
+ signal?: AbortSignal;
249
337
  } = {},
250
338
  ): Promise<ApplyReviewOperationsResult> {
251
339
  if (options.requireAtomicShrink) {
@@ -280,6 +368,9 @@ export async function applyReviewOperations(
280
368
  };
281
369
  }
282
370
 
371
+ if (options.signal?.aborted) {
372
+ return { appliedCount: 0, skippedCount: operations.length, aborted: true };
373
+ }
283
374
  const activeStore = target === "project" ? projectStore! : store;
284
375
  const memoryTarget = target === "project" ? "memory" : target;
285
376
  const mutationOperations = operations.map((operation) => ({
@@ -290,7 +381,13 @@ export async function applyReviewOperations(
290
381
  failureReason: operation.failure_reason,
291
382
  project: target === "failure" ? projectName ?? undefined : undefined,
292
383
  }));
293
- const result = await activeStore.applyMutationPlan(memoryTarget, mutationOperations, { requireShrink: true });
384
+ const result = await activeStore.applyMutationPlan(memoryTarget, mutationOperations, {
385
+ requireShrink: true,
386
+ signal: options.signal,
387
+ });
388
+ if (options.signal?.aborted && !result.success) {
389
+ return { appliedCount: 0, skippedCount: operations.length, aborted: true };
390
+ }
294
391
  return result.success
295
392
  ? { appliedCount: operations.length, skippedCount: 0 }
296
393
  : {
@@ -303,7 +400,12 @@ export async function applyReviewOperations(
303
400
  let appliedCount = 0;
304
401
  let skippedCount = 0;
305
402
 
306
- for (const op of operations) {
403
+ for (let i = 0; i < operations.length; i++) {
404
+ if (options.signal?.aborted) {
405
+ skippedCount += operations.length - i;
406
+ return { appliedCount, skippedCount, aborted: appliedCount === 0 };
407
+ }
408
+ const op = operations[i];
307
409
  if (op.target === "project" && !projectStore) {
308
410
  skippedCount++;
309
411
  continue;
@@ -326,6 +428,7 @@ export async function applyReviewOperations(
326
428
  category,
327
429
  failureReason: op.failure_reason,
328
430
  project: projectName ?? undefined,
431
+ signal: options.signal,
329
432
  });
330
433
  if (result.success) {
331
434
  appliedCount++;
@@ -333,7 +436,7 @@ export async function applyReviewOperations(
333
436
  skippedCount++;
334
437
  }
335
438
  } else {
336
- result = await activeStore.add(memoryTarget, op.content);
439
+ result = await activeStore.add(memoryTarget, op.content, options.signal);
337
440
  if (result.success) {
338
441
  appliedCount++;
339
442
  } else {
@@ -347,7 +450,7 @@ export async function applyReviewOperations(
347
450
  skippedCount++;
348
451
  continue;
349
452
  }
350
- result = await activeStore.replace(memoryTarget, op.old_text, op.content);
453
+ result = await activeStore.replace(memoryTarget, op.old_text, op.content, options.signal);
351
454
  if (result.success) {
352
455
  appliedCount++;
353
456
  } else {
@@ -360,7 +463,7 @@ export async function applyReviewOperations(
360
463
  skippedCount++;
361
464
  continue;
362
465
  }
363
- result = await activeStore.remove(memoryTarget, op.old_text);
466
+ result = await activeStore.remove(memoryTarget, op.old_text, options.signal);
364
467
  if (result.success) {
365
468
  appliedCount++;
366
469
  } else {
@@ -373,6 +476,10 @@ export async function applyReviewOperations(
373
476
  continue;
374
477
  }
375
478
 
479
+ if (options.signal?.aborted) {
480
+ skippedCount += operations.length - i - 1;
481
+ return { appliedCount, skippedCount, aborted: appliedCount === 0 };
482
+ }
376
483
  }
377
484
 
378
485
  return { appliedCount, skippedCount };
@@ -398,109 +505,161 @@ export async function runDirectMemoryCompletion(
398
505
  deps: { completeSimple?: typeof completeSimple } = {},
399
506
  ): Promise<DirectReviewResult> {
400
507
  const complete = deps.completeSimple ?? completeSimple;
401
- const model = resolveReviewModel(ctx.model, ctx.modelRegistry, options.config);
402
- if (!model) {
403
- return { ok: false, appliedCount: 0, fallbackReason: "no_model" };
404
- }
508
+ const aborted = (): DirectReviewResult => ({ ok: false, appliedCount: 0, fallbackReason: "aborted" });
509
+ if (options.signal?.aborted) return aborted();
405
510
 
406
- const auth = await resolveRequestAuth(ctx.modelRegistry, model);
407
- if (!auth.ok || !auth.apiKey) {
408
- return {
409
- ok: false,
410
- appliedCount: 0,
411
- fallbackReason: "no_auth",
412
- error: auth.ok ? `No API key for ${model.provider}` : auth.error,
413
- };
511
+ const models = resolveReviewModels(ctx.model, ctx.modelRegistry, options.config);
512
+ if (models.length === 0) {
513
+ return { ok: false, appliedCount: 0, fallbackReason: "no_model" };
414
514
  }
415
- let requestAuth: DirectReviewAuth = { apiKey: auth.apiKey, headers: auth.headers, env: auth.env };
416
515
 
417
- const controller = new AbortController();
418
- const timeoutMs = options.timeoutMs ?? 120000;
419
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
420
- if (options.signal) {
421
- options.signal.addEventListener("abort", () => controller.abort(), { once: true });
422
- }
516
+ // Try each model in chain: primary + llmFallbackModels. Only retry on
517
+ // provider/auth/transport failures; parse errors are prompt-specific so we
518
+ // still try the next model as it may have better instruction following.
519
+ let lastResult: DirectReviewResult | undefined;
520
+ for (let mi = 0; mi < models.length; mi++) {
521
+ const model = models[mi]!;
522
+ // A caller abort (user cancel, shutdown bound) ends the whole chain: the
523
+ // next iteration's listener would never fire for an already-aborted
524
+ // signal, so continuing would burn a full timeout per remaining model.
525
+ if (options.signal?.aborted) return aborted();
526
+ const auth = await resolveRequestAuth(ctx.modelRegistry, model);
527
+ if (options.signal?.aborted) return aborted();
528
+ if (!auth.ok || !hasRequestAuth(auth)) {
529
+ lastResult = {
530
+ ok: false,
531
+ appliedCount: 0,
532
+ fallbackReason: "no_auth",
533
+ error: auth.ok ? `No request authentication for ${model.provider}` : auth.error,
534
+ };
535
+ if (mi < models.length - 1) continue;
536
+ return lastResult;
537
+ }
538
+ let requestAuth: DirectReviewAuth = { apiKey: auth.apiKey, headers: auth.headers, env: auth.env };
539
+
540
+ const controller = new AbortController();
541
+ const timeoutMs = options.timeoutMs ?? 120000;
542
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
543
+ const onExternalAbort = () => controller.abort();
544
+ if (options.signal) {
545
+ options.signal.addEventListener("abort", onExternalAbort, { once: true });
546
+ if (options.signal.aborted) controller.abort();
547
+ }
423
548
 
424
- const thinking = effectiveThinkingOverride(options.config);
425
- const userMessage: Message = {
426
- role: "user",
427
- content: [{ type: "text", text: options.userPrompt }],
428
- timestamp: Date.now(),
429
- };
549
+ const thinking = effectiveThinkingOverride(options.config);
550
+ const userMessage: Message = {
551
+ role: "user",
552
+ content: [{ type: "text", text: options.userPrompt }],
553
+ timestamp: Date.now(),
554
+ };
430
555
 
431
- const request = { systemPrompt: options.systemPrompt, messages: [userMessage] };
556
+ const request = { systemPrompt: options.systemPrompt, messages: [userMessage] };
432
557
 
433
- try {
434
- let response;
435
- try {
436
- response = await complete(
558
+ const completeOnce = async () => {
559
+ const response = await complete(
437
560
  model,
438
561
  request,
439
562
  buildDirectReviewCompletionOptions(model, requestAuth, thinking, controller.signal),
440
563
  );
441
- } catch (err) {
442
- const message = err instanceof Error ? err.message : String(err);
443
- if (controller.signal.aborted || !isAuthRejection(message)) throw err;
444
-
445
- // The provider rejected the key mid-flight. A rotation tool may have
446
- // re-resolve through Pi and retry once only if it returns a different
447
- // key; otherwise this is a real auth problem and the subprocess
448
- // fallback should handle it (#139).
449
- const rotated = await resolveRequestAuth(ctx.modelRegistry, model);
450
- if (!rotated.ok || !rotated.apiKey || rotated.apiKey === requestAuth.apiKey) throw err;
451
-
452
- requestAuth = { apiKey: rotated.apiKey, headers: rotated.headers, env: rotated.env };
453
- response = await complete(
454
- model,
455
- request,
456
- buildDirectReviewCompletionOptions(model, requestAuth, thinking, controller.signal),
457
- );
458
- }
564
+ if (response.stopReason === "error" && isAuthRejection(response.errorMessage ?? "")) {
565
+ throw new Error(response.errorMessage ?? "error");
566
+ }
567
+ return response;
568
+ };
459
569
 
460
- if (response.stopReason === "aborted") {
461
- return { ok: false, appliedCount: 0, fallbackReason: "aborted" };
462
- }
570
+ try {
571
+ let response;
572
+ try {
573
+ response = await completeOnce();
574
+ } catch (err) {
575
+ const message = err instanceof Error ? err.message : String(err);
576
+ if (controller.signal.aborted || !isAuthRejection(message)) throw err;
577
+
578
+ // Thrown failures and error assistant responses share this path. API keys
579
+ // and OAuth headers can both rotate, so re-resolve through Pi and retry
580
+ // once only when the effective request auth actually changed; otherwise
581
+ // this is a real auth problem and the subprocess fallback should handle
582
+ // it (#139).
583
+ const rotated = await resolveRequestAuth(ctx.modelRegistry, model);
584
+ if (!rotated.ok || !hasRequestAuth(rotated) || sameRequestAuth(rotated, requestAuth)) throw err;
585
+
586
+ requestAuth = { apiKey: rotated.apiKey, headers: rotated.headers, env: rotated.env };
587
+ response = await completeOnce();
588
+ }
463
589
 
464
- const text = responseText(response.content);
465
- const operations = parseReviewOperations(text);
466
- if (operations === null) {
467
- return { ok: false, appliedCount: 0, fallbackReason: "parse_error" };
468
- }
469
- if (operations.length === 0) {
470
- return { ok: true, appliedCount: 0, fallbackReason: "empty" };
471
- }
590
+ if (options.signal?.aborted) {
591
+ clearTimeout(timeout);
592
+ return aborted();
593
+ }
594
+ if (response.stopReason === "aborted" || controller.signal.aborted) {
595
+ lastResult = { ok: false, appliedCount: 0, fallbackReason: "aborted" };
596
+ if (mi < models.length - 1) { clearTimeout(timeout); continue; }
597
+ return lastResult;
598
+ }
472
599
 
473
- const applied = await applyReviewOperations(
474
- store,
475
- projectStore,
476
- operations,
477
- dbManager,
478
- projectName,
479
- {
480
- requireAtomicShrink: options.requireAtomicShrink,
481
- expectedTarget: options.expectedTarget,
482
- },
483
- );
484
- if (applied.error) {
485
- return {
486
- ok: false,
487
- appliedCount: 0,
488
- fallbackReason: "provider_error",
489
- error: applied.error,
490
- };
491
- }
492
- return { ok: true, appliedCount: applied.appliedCount };
493
- } catch (err) {
494
- if (controller.signal.aborted) {
495
- return { ok: false, appliedCount: 0, fallbackReason: "aborted" };
600
+ const text = responseText(response.content);
601
+ const operations = parseReviewOperations(text);
602
+ if (operations === null) {
603
+ lastResult = { ok: false, appliedCount: 0, fallbackReason: "parse_error" };
604
+ if (mi < models.length - 1) { clearTimeout(timeout); continue; }
605
+ return lastResult;
606
+ }
607
+ if (operations.length === 0) {
608
+ clearTimeout(timeout);
609
+ return { ok: true, appliedCount: 0, fallbackReason: "empty" };
610
+ }
611
+ if (controller.signal.aborted || options.signal?.aborted) {
612
+ return aborted();
613
+ }
614
+
615
+ const applied = await applyReviewOperations(
616
+ store,
617
+ projectStore,
618
+ operations,
619
+ dbManager,
620
+ projectName,
621
+ {
622
+ requireAtomicShrink: options.requireAtomicShrink,
623
+ expectedTarget: options.expectedTarget,
624
+ signal: options.signal,
625
+ },
626
+ );
627
+ if (applied.aborted && applied.appliedCount === 0) {
628
+ return aborted();
629
+ }
630
+ if (applied.error) {
631
+ lastResult = {
632
+ ok: false,
633
+ appliedCount: 0,
634
+ fallbackReason: "provider_error",
635
+ error: applied.error,
636
+ };
637
+ if (mi < models.length - 1) { clearTimeout(timeout); continue; }
638
+ return lastResult;
639
+ }
640
+ clearTimeout(timeout);
641
+ return { ok: true, appliedCount: applied.appliedCount };
642
+ } catch (err) {
643
+ if (options.signal?.aborted) {
644
+ clearTimeout(timeout);
645
+ return aborted();
646
+ }
647
+ if (controller.signal.aborted) {
648
+ lastResult = { ok: false, appliedCount: 0, fallbackReason: "aborted" };
649
+ } else {
650
+ lastResult = {
651
+ ok: false,
652
+ appliedCount: 0,
653
+ fallbackReason: "provider_error",
654
+ error: err instanceof Error ? err.message : String(err),
655
+ };
656
+ }
657
+ if (mi < models.length - 1) { clearTimeout(timeout); continue; }
658
+ return lastResult!;
659
+ } finally {
660
+ clearTimeout(timeout);
661
+ options.signal?.removeEventListener("abort", onExternalAbort);
496
662
  }
497
- return {
498
- ok: false,
499
- appliedCount: 0,
500
- fallbackReason: "provider_error",
501
- error: err instanceof Error ? err.message : String(err),
502
- };
503
- } finally {
504
- clearTimeout(timeout);
505
663
  }
664
+ return lastResult ?? { ok: false, appliedCount: 0, fallbackReason: "provider_error", error: "All fallback models failed" };
506
665
  }
@@ -33,6 +33,12 @@ export interface ScheduleSessionBackfillOptions {
33
33
  indexSessionsFn?: typeof indexChangedSessions;
34
34
  maxFilesToIndex?: number;
35
35
  touchBackfillTimestampFn?: typeof touchBackfillTimestamp;
36
+ /**
37
+ * Optional retention cutoff (ms epoch). Files older than this are excluded
38
+ * from the backfill file set so that sessions pruned by retention are not
39
+ * re-indexed and do not repeatedly schedule a startup backfill.
40
+ */
41
+ retentionCutoffMs?: number;
36
42
  }
37
43
 
38
44
  function formatBackfillResult(result: BulkIndexResult): string {
@@ -69,6 +75,7 @@ export function scheduleSessionBackfill(
69
75
  const indexSessionsFn = options.indexSessionsFn ?? indexChangedSessions;
70
76
  const maxFilesToIndex = options.maxFilesToIndex ?? SESSION_BACKFILL_MAX_FILES;
71
77
  const touchBackfillTimestampFn = options.touchBackfillTimestampFn ?? touchBackfillTimestamp;
78
+ const retentionCutoffMs = options.retentionCutoffMs ?? 0;
72
79
 
73
80
  if (state.inProgress) {
74
81
  return false;
@@ -77,7 +84,7 @@ export function scheduleSessionBackfill(
77
84
  try {
78
85
  if (!measureLifecycleSync(
79
86
  'session-backfill.check',
80
- () => needsBackfillFn(dbManager, sessionsDir),
87
+ () => needsBackfillFn(dbManager, sessionsDir, undefined, retentionCutoffMs),
81
88
  )) {
82
89
  return false;
83
90
  }
@@ -95,7 +102,7 @@ export function scheduleSessionBackfill(
95
102
  setTimeoutFn(() => {
96
103
  measureLifecycleSync('session-backfill.callback', () => {
97
104
  try {
98
- const result = indexSessionsFn(dbManager, sessionsDir, { maxFilesToIndex });
105
+ const result = indexSessionsFn(dbManager, sessionsDir, { maxFilesToIndex, retentionCutoffMs });
99
106
  if (!result.reachedLimit) touchBackfillTimestampFn(dbManager);
100
107
  notifyBestEffort(options.notify, formatBackfillResult(result), result.errors.length > 0 || result.reachedLimit ? 'warning' : 'info');
101
108
  } catch (err) {
@@ -165,6 +165,11 @@ export async function syncMarkdownMemoriesToSqlite(
165
165
  counters.imported += result.inserted;
166
166
  counters.skipped += result.existing;
167
167
  counters.removed += result.removed;
168
+ if (result.degraded) {
169
+ counters.warnings.push(
170
+ `${path.basename(project ?? 'global')}/${target}: FTS5 search index error (${result.degradedReason}); run /memory-sync-markdown to rebuild`,
171
+ );
172
+ }
168
173
  } catch (err) {
169
174
  counters.warnings.push(
170
175
  `${path.basename(project ?? 'global')}/${target}: ${err instanceof Error ? err.message : String(err)}`,
@@ -28,7 +28,7 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
28
28
  import { MemoryStore } from "./store/memory-store.js";
29
29
  import { SkillStore } from "./store/skill-store.js";
30
30
  import { DatabaseManager } from "./store/db.js";
31
- import { indexSession, upsertSessionFileMetadata, pruneEphemeralReviewSessions } from "./store/session-indexer.js";
31
+ import { indexSession, upsertSessionFileMetadata, pruneEphemeralReviewSessions, pruneOldSessions, retentionCutoffMs } from "./store/session-indexer.js";
32
32
  import { runRecoveryMaintenance } from "./store/recovery-maintenance.js";
33
33
  import { scheduleSessionBackfill, waitForSessionBackfill, SESSION_BACKFILL_SHUTDOWN_TIMEOUT_MS } from "./handlers/session-backfill.js";
34
34
  import { scheduleLiveSessionIndex, waitForLiveSessionIndex, SESSION_LIVE_INDEX_SHUTDOWN_TIMEOUT_MS } from "./handlers/session-live-index.js";
@@ -125,6 +125,7 @@ export default function (pi: ExtensionAPI) {
125
125
  migrationSentinelPath: path.join(globalDir, ".skills-migrated-to-extension-storage"),
126
126
  });
127
127
  const dbManager = new DatabaseManager(globalDir);
128
+ dbManager.setQuickCheckOnOpen(config.quickCheckOnOpen ?? true);
128
129
  let databaseMigrationPending = shouldMigrateExtensionRoot
129
130
  && isDatabaseMigrationPending(legacyGlobalDir, globalDir);
130
131
  if (databaseMigrationPending) {
@@ -226,6 +227,22 @@ export default function (pi: ExtensionAPI) {
226
227
  } catch (err) {
227
228
  console.warn(`⚠️ Ephemeral session cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
228
229
  }
230
+ // Prune sessions older than the configured retention window to bound the
231
+ // size of the session index database (see #183). Runs before
232
+ // scheduleSessionBackfill so pruned sessions are never re-indexed by a
233
+ // backfill started in the same startup.
234
+ if (config.sessionRetentionDays && config.sessionRetentionDays > 0) {
235
+ try {
236
+ const pruneResult = pruneOldSessions(dbManager, config.sessionRetentionDays);
237
+ if (pruneResult.sessionsRemoved > 0) {
238
+ console.info(
239
+ `🧠 Pruned ${pruneResult.sessionsRemoved} old session(s) (> ${config.sessionRetentionDays} days old)`,
240
+ );
241
+ }
242
+ } catch (err) {
243
+ console.warn(`⚠️ Session pruning failed: ${err instanceof Error ? err.message : String(err)}`);
244
+ }
245
+ }
229
246
  try {
230
247
  await runRecoveryMaintenance({ config, globalDir });
231
248
  } catch (err) {
@@ -242,6 +259,9 @@ export default function (pi: ExtensionAPI) {
242
259
  console.info(message);
243
260
  }
244
261
  },
262
+ // Exclude files older than the retention cutoff so sessions pruned by
263
+ // retention are never re-indexed and never schedule another backfill.
264
+ retentionCutoffMs: retentionCutoffMs(config.sessionRetentionDays),
245
265
  });
246
266
  }
247
267
  });
@@ -334,7 +354,7 @@ export default function (pi: ExtensionAPI) {
334
354
  // ── 11. SQLite session search + extended memory ──
335
355
  registerSessionSearchTool(pi, dbManager, config.sessionSearch ?? { variant: "legacy" });
336
356
  registerMemorySearchTool(pi, dbManager);
337
- registerIndexSessionsCommand(pi);
357
+ registerIndexSessionsCommand(pi, config);
338
358
 
339
359
  // ── 12. Auto-index session on shutdown ──
340
360
  // Registered last, so this runs after the session-flush shutdown handler and
@@ -5,7 +5,7 @@ import { DEFAULT_PROJECTS_MEMORY_DIR } from "./constants.js";
5
5
 
6
6
  // Route through the host resolver only. The upstream `PI_CODING_AGENT_DIR`
7
7
  // env var is deliberately NOT honored here: on the Selesai fork it would
8
- // silently point memory at ~/.pi/agent while the host reads ~/.selesai/agent.
8
+ // silently point memory at the upstream agent dir while the host reads ~/.selesai/agent.
9
9
  export const AGENT_ROOT = getAgentDir();
10
10
 
11
11
  export function expandHome(input: string): string {
@@ -164,6 +164,7 @@ export class DatabaseManager {
164
164
  private lastRecovery: DatabaseRecoveryResult | null = null;
165
165
  private openGuard: (() => void) | null = null;
166
166
  private pendingOpenIntegrityScan: Promise<void> | null = null;
167
+ private quickCheckOnOpen = true;
167
168
  private activeRecoveryLease: { coordinator: AtomicLockCoordinator; key: string; token: string } | null = null;
168
169
 
169
170
  constructor(memoryDir: string, recoveryOptions: DatabaseRecoveryOptions = {}) {
@@ -182,6 +183,10 @@ export class DatabaseManager {
182
183
  this.openGuard = guard;
183
184
  }
184
185
 
186
+ setQuickCheckOnOpen(enabled: boolean): void {
187
+ this.quickCheckOnOpen = enabled;
188
+ }
189
+
185
190
  /**
186
191
  * True when an error indicates SQLite file/page corruption rather than a
187
192
  * normal constraint, migration, or query failure.
@@ -304,6 +309,7 @@ export class DatabaseManager {
304
309
  * at operation time.
305
310
  */
306
311
  private scheduleOpenIntegrityScan(db: DatabaseLike): void {
312
+ if (!this.quickCheckOnOpen) return;
307
313
  if (this.pendingOpenIntegrityScan) return;
308
314
  const scan = new Promise<void>((resolve) => {
309
315
  setTimeout(() => {