one-code-extension 0.4.1 → 0.6.0

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 (439) hide show
  1. package/README.md +16 -5
  2. package/agents/general-purpose.md +2 -2
  3. package/docs/guide/README.md +2 -1
  4. package/docs/guide/bring-your-claude-code-setup.md +60 -9
  5. package/docs/guide/configuration.md +48 -14
  6. package/docs/guide/differences-from-claude-code.md +40 -28
  7. package/docs/guide/doctor.md +20 -13
  8. package/docs/guide/hooks.md +18 -3
  9. package/docs/guide/installation.md +26 -4
  10. package/docs/guide/permissions-modes-and-auto-mode.md +225 -49
  11. package/docs/guide/providers-and-models.md +137 -54
  12. package/docs/guide/reference.md +27 -15
  13. package/docs/guide/sessions-and-context.md +69 -16
  14. package/docs/guide/skills-plugins-and-mcp.md +57 -20
  15. package/docs/guide/subagents-and-workflows.md +95 -29
  16. package/docs/guide/tasks-and-background-work.md +101 -26
  17. package/docs/guide/terminal-interface.md +24 -12
  18. package/docs/guide/tools.md +46 -5
  19. package/docs/guide/troubleshooting.md +13 -9
  20. package/docs/guide/windows.md +58 -31
  21. package/extensions/artifacts/gallery.ts +227 -0
  22. package/extensions/artifacts/index.ts +288 -0
  23. package/extensions/artifacts/store.ts +570 -0
  24. package/extensions/artifacts/viewer.ts +199 -0
  25. package/extensions/ask-user/description.ts +67 -0
  26. package/extensions/ask-user/dialogs.ts +80 -0
  27. package/extensions/ask-user/index.ts +37 -33
  28. package/extensions/ask-user/questions.ts +32 -7
  29. package/extensions/ask-user/widget.ts +45 -25
  30. package/extensions/auto-mode/actions.ts +6 -0
  31. package/extensions/auto-mode/cache.ts +88 -0
  32. package/extensions/auto-mode/classifier-prompt.ts +5 -4
  33. package/extensions/auto-mode/classifier.ts +290 -65
  34. package/extensions/auto-mode/config.ts +72 -20
  35. package/extensions/auto-mode/decision-log.ts +2 -0
  36. package/extensions/auto-mode/defaults.ts +1 -1
  37. package/extensions/auto-mode/denials.ts +124 -0
  38. package/extensions/auto-mode/git-checkout-programs.ts +187 -0
  39. package/extensions/auto-mode/git-status-meta.ts +159 -0
  40. package/extensions/auto-mode/history.ts +189 -0
  41. package/extensions/auto-mode/instructions.ts +58 -52
  42. package/extensions/auto-mode/model-select.ts +159 -134
  43. package/extensions/auto-mode/paths.ts +57 -5
  44. package/extensions/auto-mode/pause.ts +57 -2
  45. package/extensions/auto-mode/prompt.ts +37 -21
  46. package/extensions/auto-mode/read-only-options.ts +724 -0
  47. package/extensions/auto-mode/resolved-paths-meta.ts +133 -0
  48. package/extensions/auto-mode/rules.ts +18 -1
  49. package/extensions/auto-mode/safety-floor.ts +361 -18
  50. package/extensions/auto-mode/setup-run.ts +20 -14
  51. package/extensions/auto-mode/shell-analysis.ts +764 -490
  52. package/extensions/auto-mode/shell-parse.ts +885 -0
  53. package/extensions/auto-mode/system-note.ts +33 -0
  54. package/extensions/auto-mode/transcript.ts +80 -51
  55. package/extensions/background/cron.ts +642 -0
  56. package/extensions/background/index.ts +614 -248
  57. package/extensions/background/loop-fire.ts +173 -0
  58. package/extensions/background/loop-preamble.ts +59 -0
  59. package/extensions/background/loop-skill.ts +163 -0
  60. package/extensions/background/monitor-batch.ts +53 -0
  61. package/extensions/background/noop-fold.ts +128 -0
  62. package/extensions/background/switch-guard.ts +56 -0
  63. package/extensions/background/wakeup.ts +178 -55
  64. package/extensions/bash/background.ts +53 -17
  65. package/extensions/bash/child.ts +7 -0
  66. package/extensions/bash/description.ts +188 -0
  67. package/extensions/bash/guards.ts +15 -67
  68. package/extensions/bash/index.ts +66 -35
  69. package/extensions/branding/compaction-keep.ts +63 -0
  70. package/extensions/branding/declined.ts +22 -0
  71. package/extensions/branding/index.ts +133 -9
  72. package/extensions/branding/prompt-editor.ts +53 -6
  73. package/extensions/branding/queued-edit.ts +31 -0
  74. package/extensions/branding/replaced-builtins.ts +68 -0
  75. package/extensions/branding/startup.ts +33 -71
  76. package/extensions/btw/index.ts +250 -78
  77. package/extensions/btw/panel.ts +228 -100
  78. package/extensions/btw/prompt.ts +41 -4
  79. package/extensions/cache-marks/index.ts +42 -0
  80. package/extensions/claude-compat/index.ts +7 -11
  81. package/extensions/claude-context/index.ts +436 -63
  82. package/extensions/compaction/cut.ts +157 -0
  83. package/extensions/compaction/index.ts +219 -75
  84. package/extensions/compaction/kept-thinking.ts +62 -0
  85. package/extensions/compaction/prompt.ts +15 -12
  86. package/extensions/context-budget/budget.ts +16 -2
  87. package/extensions/context-budget/index.ts +35 -15
  88. package/extensions/context-management/index.ts +36 -28
  89. package/extensions/doctor/build.ts +59 -8
  90. package/extensions/doctor/builtins.ts +84 -0
  91. package/extensions/doctor/cli.ts +7 -1
  92. package/extensions/doctor/compat.ts +88 -23
  93. package/extensions/doctor/dependencies.ts +41 -5
  94. package/extensions/doctor/fix-prompt.ts +9 -2
  95. package/extensions/doctor/index.ts +102 -58
  96. package/extensions/doctor/models.ts +102 -63
  97. package/extensions/doctor/presets.ts +42 -27
  98. package/extensions/doctor/report.ts +19 -2
  99. package/extensions/doctor/viewer.ts +49 -27
  100. package/extensions/effort/index.ts +141 -25
  101. package/extensions/effort/settings.ts +21 -0
  102. package/extensions/effort/slider.ts +24 -20
  103. package/extensions/exit/index.ts +32 -1
  104. package/extensions/file-tracker/index.ts +420 -42
  105. package/extensions/file-tracker/replay.ts +137 -24
  106. package/extensions/file-tracker/restore.ts +66 -0
  107. package/extensions/file-tracker/results.ts +66 -0
  108. package/extensions/file-tracker/shell-reads.ts +211 -0
  109. package/extensions/file-tracker/tracker.ts +45 -15
  110. package/extensions/footer/footer-line.ts +45 -24
  111. package/extensions/footer/index.ts +47 -2
  112. package/extensions/footer/pr.ts +34 -5
  113. package/extensions/hooks/compaction.ts +7 -0
  114. package/extensions/hooks/executor.ts +32 -30
  115. package/extensions/hooks/index.ts +209 -58
  116. package/extensions/hooks/matcher.ts +3 -0
  117. package/extensions/hooks/prompt-context.ts +59 -0
  118. package/extensions/hooks/protocol.ts +41 -3
  119. package/extensions/hooks/settings.ts +50 -19
  120. package/extensions/hooks/subagent-bridge.ts +2 -0
  121. package/extensions/hooks/trust.ts +26 -12
  122. package/extensions/idle-compact/index.ts +119 -0
  123. package/extensions/idle-compact/policy.ts +143 -0
  124. package/extensions/init/index.ts +11 -10
  125. package/extensions/init/prompt.ts +25 -32
  126. package/extensions/interrupted/index.ts +13 -1
  127. package/extensions/kept-thinking/index.ts +27 -0
  128. package/extensions/ledger/index.ts +46 -0
  129. package/extensions/ledger/wire.ts +154 -0
  130. package/extensions/lib/agent-cron.ts +146 -0
  131. package/extensions/lib/agent-loader.ts +18 -3
  132. package/extensions/lib/agent-view.ts +85 -0
  133. package/extensions/lib/anthropic-auth.ts +98 -0
  134. package/extensions/lib/anthropic-payload.ts +82 -1
  135. package/extensions/lib/anthropic-server-call.ts +230 -0
  136. package/extensions/lib/anthropic-server-tools.ts +485 -0
  137. package/extensions/lib/app-launch.mjs +94 -0
  138. package/extensions/lib/argument-hints.ts +190 -0
  139. package/extensions/lib/atomic-write.ts +6 -2
  140. package/extensions/lib/auto-memory.ts +75 -0
  141. package/extensions/lib/bash-parser.ts +84 -0
  142. package/extensions/lib/btw-fork.ts +93 -0
  143. package/extensions/lib/child-extensions.ts +52 -0
  144. package/extensions/lib/child-writes.ts +45 -0
  145. package/extensions/lib/claude-context.ts +515 -100
  146. package/extensions/lib/claude-external-includes.ts +68 -0
  147. package/extensions/lib/claude-id.ts +22 -0
  148. package/extensions/lib/claude-rules.ts +323 -0
  149. package/extensions/lib/claude-settings.ts +76 -4
  150. package/extensions/lib/compaction-boundary.ts +36 -0
  151. package/extensions/lib/compaction-keep.mjs +83 -0
  152. package/extensions/lib/config-mode.ts +112 -0
  153. package/extensions/lib/consent-dialogs.ts +63 -0
  154. package/extensions/lib/consent-preview.ts +5 -1
  155. package/extensions/lib/consent-stores.ts +48 -0
  156. package/extensions/lib/context-facts.ts +97 -0
  157. package/extensions/lib/covered-messages.ts +23 -0
  158. package/extensions/lib/deferred.ts +359 -25
  159. package/extensions/lib/dock-rows.ts +60 -0
  160. package/extensions/lib/empty-tool-result.ts +27 -0
  161. package/extensions/lib/environment-block.ts +76 -0
  162. package/extensions/lib/fetch-timeout.ts +24 -6
  163. package/extensions/{system-prompt → lib}/git-status.ts +51 -13
  164. package/extensions/lib/git.ts +75 -13
  165. package/extensions/lib/grammars/LICENSE-tree-sitter-bash +21 -0
  166. package/extensions/lib/grammars/README.md +2 -0
  167. package/extensions/lib/grammars/tree-sitter-bash.wasm +0 -0
  168. package/extensions/lib/guide-docs.ts +45 -0
  169. package/extensions/lib/headless-output.ts +46 -0
  170. package/extensions/lib/hook-gate.ts +7 -7
  171. package/extensions/lib/interrupt.ts +20 -4
  172. package/extensions/lib/key-input.ts +455 -0
  173. package/extensions/lib/keys.ts +14 -1
  174. package/extensions/lib/ledger/fold-memo.ts +49 -0
  175. package/extensions/lib/ledger/fold.ts +265 -0
  176. package/extensions/lib/ledger/layout.ts +72 -0
  177. package/extensions/lib/ledger/plan.ts +102 -0
  178. package/extensions/lib/ledger/records.ts +276 -0
  179. package/extensions/lib/ledger/state.ts +47 -0
  180. package/extensions/lib/ledger/validate.ts +141 -0
  181. package/extensions/lib/ledger/wire.ts +632 -0
  182. package/extensions/lib/local-command.ts +71 -19
  183. package/extensions/lib/mcp-overrides.ts +1 -1
  184. package/extensions/lib/mcp-share.ts +46 -0
  185. package/extensions/lib/memory-content.ts +146 -0
  186. package/extensions/lib/memory-index.ts +18 -0
  187. package/extensions/lib/memory.ts +134 -123
  188. package/extensions/lib/model-catalog/huggingface.json +178 -0
  189. package/extensions/lib/model-catalog/models-dev.json +18533 -0
  190. package/extensions/lib/model-catalog/openrouter.json +5050 -0
  191. package/extensions/lib/model-catalog-data.ts +513 -0
  192. package/extensions/lib/model-catalog.ts +462 -0
  193. package/extensions/lib/model-choice-warnings.ts +137 -0
  194. package/extensions/lib/model-pairings.ts +152 -0
  195. package/extensions/{auto-mode → lib}/model-picker.ts +26 -43
  196. package/extensions/lib/model-policy.ts +112 -15
  197. package/extensions/lib/model-tier.ts +283 -355
  198. package/extensions/lib/model-unusable.ts +1 -1
  199. package/extensions/lib/newer-model.ts +100 -0
  200. package/extensions/lib/notices.ts +87 -0
  201. package/extensions/lib/notifications.ts +357 -73
  202. package/extensions/lib/one-code-settings.ts +74 -8
  203. package/extensions/lib/open-browser.ts +63 -0
  204. package/extensions/lib/openrouter-generation.ts +94 -0
  205. package/extensions/lib/operation-deadline.ts +30 -0
  206. package/extensions/lib/original-command.ts +4 -4
  207. package/extensions/lib/package-version.ts +1 -1
  208. package/extensions/lib/panel-focus.ts +134 -0
  209. package/extensions/lib/paths.ts +17 -2
  210. package/extensions/lib/permission-gate.ts +72 -6
  211. package/extensions/lib/persisted-output.ts +60 -8
  212. package/extensions/lib/pi-ai-estimate.ts +19 -3
  213. package/extensions/lib/pi-version.ts +38 -2
  214. package/extensions/lib/plan-mode-channels.ts +42 -5
  215. package/extensions/lib/plugins.ts +26 -17
  216. package/extensions/lib/powershell-parse-script.ts +208 -0
  217. package/extensions/lib/powershell-parser.ts +344 -0
  218. package/extensions/lib/previous-mark.ts +101 -0
  219. package/extensions/lib/process-state.ts +48 -0
  220. package/extensions/lib/process-tree.ts +132 -8
  221. package/extensions/lib/prompt-options.ts +82 -0
  222. package/extensions/lib/queued-delivery.ts +44 -0
  223. package/extensions/lib/reminders.ts +370 -358
  224. package/extensions/lib/replaced-builtins.mjs +199 -0
  225. package/extensions/lib/replay-call.ts +70 -0
  226. package/extensions/lib/request-replay.ts +547 -0
  227. package/extensions/lib/scratchpad.ts +81 -14
  228. package/extensions/lib/send-now-channel.ts +7 -0
  229. package/extensions/lib/session-model-tier.ts +51 -0
  230. package/extensions/lib/session-work.ts +64 -0
  231. package/extensions/lib/settings-channels.ts +4 -4
  232. package/extensions/lib/shell-exit-semantics.ts +170 -0
  233. package/extensions/lib/shell-quote.ts +11 -0
  234. package/extensions/lib/shell-result.ts +70 -0
  235. package/extensions/lib/shell-spawn.ts +70 -6
  236. package/extensions/lib/shell-tool.ts +75 -25
  237. package/extensions/lib/side-call-cache.ts +124 -0
  238. package/extensions/lib/side-call-run.ts +96 -0
  239. package/extensions/lib/side-call-usage.ts +38 -0
  240. package/extensions/lib/side-call.ts +24 -1
  241. package/extensions/lib/single-flight.ts +18 -0
  242. package/extensions/lib/skill-body.ts +42 -0
  243. package/extensions/lib/skill-scan.ts +63 -24
  244. package/extensions/lib/spill-file.ts +140 -0
  245. package/extensions/lib/subagent-handback.ts +112 -0
  246. package/extensions/lib/system-role.ts +156 -0
  247. package/extensions/lib/terminal-text.ts +114 -0
  248. package/extensions/lib/text-width.ts +47 -16
  249. package/extensions/lib/timer-ops.ts +20 -0
  250. package/extensions/lib/tool-additions.ts +129 -0
  251. package/extensions/lib/tool-call-corruption.ts +134 -0
  252. package/extensions/lib/tool-path.ts +66 -0
  253. package/extensions/lib/tool-variants.ts +69 -0
  254. package/extensions/lib/tui-render.ts +255 -27
  255. package/extensions/lib/turn-budget-layout.ts +159 -0
  256. package/extensions/lib/update-check.mjs +15 -2
  257. package/extensions/lib/usage-bus.ts +1 -1
  258. package/extensions/lib/user-denial.ts +38 -0
  259. package/extensions/lib/workspace-channel.ts +16 -0
  260. package/extensions/lib/worktree-channel.ts +31 -3
  261. package/extensions/lib/worktree-isolation.ts +40 -10
  262. package/extensions/lsp/client.ts +8 -9
  263. package/extensions/lsp/index.ts +76 -12
  264. package/extensions/lsp/keep-alive.ts +1 -1
  265. package/extensions/lsp/trust.ts +119 -0
  266. package/extensions/lsp/watcher.ts +1 -1
  267. package/extensions/mcp/announce.ts +90 -43
  268. package/extensions/mcp/client.ts +161 -48
  269. package/extensions/mcp/config.ts +132 -8
  270. package/extensions/mcp/discovery.ts +19 -0
  271. package/extensions/mcp/index.ts +220 -121
  272. package/extensions/mcp/oauth/browser.ts +38 -17
  273. package/extensions/mcp/oauth/flow.ts +25 -17
  274. package/extensions/mcp/oauth/provider.ts +14 -8
  275. package/extensions/mcp/oauth/store.ts +34 -16
  276. package/extensions/mcp/panel/keys.ts +12 -11
  277. package/extensions/mcp/panel/render.ts +9 -6
  278. package/extensions/mcp/schema.ts +104 -5
  279. package/extensions/mcp/trust.ts +164 -73
  280. package/extensions/memory/entries.ts +23 -14
  281. package/extensions/memory/index.ts +134 -28
  282. package/extensions/memory/open-external.ts +33 -18
  283. package/extensions/memory/panel.ts +135 -26
  284. package/extensions/model-default/index.ts +86 -19
  285. package/extensions/newer-model/index.ts +31 -0
  286. package/extensions/notebook/description.ts +18 -0
  287. package/extensions/notebook/index.ts +6 -5
  288. package/extensions/notebook/notebook.ts +1 -1
  289. package/extensions/permissions/index.ts +1426 -398
  290. package/extensions/permissions/matcher.ts +425 -74
  291. package/extensions/permissions/modes.ts +11 -4
  292. package/extensions/permissions/panel/host.ts +130 -0
  293. package/extensions/permissions/panel/keys.ts +48 -0
  294. package/extensions/permissions/panel/render.ts +450 -0
  295. package/extensions/permissions/panel/state.ts +550 -0
  296. package/extensions/permissions/powershell-cmdlets.ts +198 -0
  297. package/extensions/permissions/powershell-paths.ts +197 -0
  298. package/extensions/permissions/powershell-rules.ts +207 -280
  299. package/extensions/permissions/powershell-tree.ts +557 -0
  300. package/extensions/permissions/project-trust.ts +27 -11
  301. package/extensions/permissions/protected-paths.ts +14 -2
  302. package/extensions/permissions/session-grant.ts +6 -0
  303. package/extensions/permissions/settings.ts +166 -31
  304. package/extensions/permissions/subagent-gate.ts +25 -0
  305. package/extensions/permissions/workspace.ts +78 -0
  306. package/extensions/plan-mode/index.ts +276 -92
  307. package/extensions/plan-mode/reminder.ts +89 -21
  308. package/extensions/plan-mode/run-state.ts +26 -0
  309. package/extensions/plan-mode/texts.ts +177 -0
  310. package/extensions/plan-mode/viewer.ts +92 -27
  311. package/extensions/plugins/counts.ts +3 -3
  312. package/extensions/plugins/index.ts +64 -46
  313. package/extensions/plugins/install/install.ts +16 -0
  314. package/extensions/plugins/marketplace/sync.ts +9 -3
  315. package/extensions/plugins/marketplace/types.ts +3 -1
  316. package/extensions/plugins/panel/keys.ts +21 -24
  317. package/extensions/plugins/panel/render.ts +12 -6
  318. package/extensions/plugins/shell-expand.ts +107 -0
  319. package/extensions/plugins/template.ts +32 -15
  320. package/extensions/powershell/child.ts +7 -0
  321. package/extensions/powershell/description.ts +38 -6
  322. package/extensions/powershell/guards.ts +1 -1
  323. package/extensions/powershell/index.ts +14 -7
  324. package/extensions/recap/index.ts +73 -71
  325. package/extensions/recap/prompt.ts +2 -2
  326. package/extensions/recap/scheduler.ts +3 -5
  327. package/extensions/search-tools/grep-merge.ts +39 -0
  328. package/extensions/search-tools/index.ts +0 -0
  329. package/extensions/send-now/chord.ts +62 -0
  330. package/extensions/send-now/index.ts +133 -0
  331. package/extensions/session-title/index.ts +3 -0
  332. package/extensions/session-title/title.ts +4 -1
  333. package/extensions/skill/announce.ts +30 -0
  334. package/extensions/skill/code-review.ts +97 -0
  335. package/extensions/skill/index.ts +469 -132
  336. package/extensions/skill/invoke.ts +118 -75
  337. package/extensions/skill/listing.ts +133 -9
  338. package/extensions/skill/panel/keys.ts +15 -16
  339. package/extensions/skill/panel/render.ts +5 -2
  340. package/extensions/skill/panel/state.ts +12 -1
  341. package/extensions/subagents/agent-args.ts +39 -0
  342. package/extensions/subagents/agent-description.ts +132 -0
  343. package/extensions/subagents/agents.ts +146 -31
  344. package/extensions/subagents/default-model.ts +2 -3
  345. package/extensions/subagents/delegation-steer.ts +4 -4
  346. package/extensions/subagents/fork-cache.ts +82 -0
  347. package/extensions/subagents/guide-agent.ts +189 -0
  348. package/extensions/subagents/hand-back-review.ts +3 -0
  349. package/extensions/subagents/index.ts +1594 -852
  350. package/extensions/subagents/live-runs.ts +26 -6
  351. package/extensions/subagents/model-select.ts +38 -25
  352. package/extensions/subagents/outcome.ts +5 -2
  353. package/extensions/subagents/panel-keys.ts +73 -31
  354. package/extensions/subagents/panel-render.ts +120 -96
  355. package/extensions/subagents/panel-widget.ts +60 -89
  356. package/extensions/subagents/parent-mode.ts +50 -0
  357. package/extensions/subagents/pending-claim.ts +18 -1
  358. package/extensions/subagents/runner.ts +135 -80
  359. package/extensions/subagents/runs.ts +44 -5
  360. package/extensions/subagents/send-to-main-tool.ts +1 -1
  361. package/extensions/subagents/session-turns.ts +32 -8
  362. package/extensions/subagents/shell-panel.ts +36 -178
  363. package/extensions/subagents/tasks-dialog.ts +170 -0
  364. package/extensions/subagents/viewport-mirror.ts +95 -0
  365. package/extensions/subagents/worktree.ts +57 -13
  366. package/extensions/system-prompt/environment.ts +19 -19
  367. package/extensions/system-prompt/idle-turn.ts +65 -0
  368. package/extensions/system-prompt/index.ts +165 -47
  369. package/extensions/system-prompt/template.ts +34 -51
  370. package/extensions/system-prompt/tiers/common.ts +23 -64
  371. package/extensions/system-prompt/tiers/frontier.ts +32 -11
  372. package/extensions/system-prompt/tiers/low.ts +67 -45
  373. package/extensions/system-prompt/tiers/mid.ts +96 -38
  374. package/extensions/system-reminder/index.ts +204 -70
  375. package/extensions/tasks/descriptions.ts +190 -0
  376. package/extensions/tasks/index.ts +120 -41
  377. package/extensions/tasks/store.ts +83 -16
  378. package/extensions/tool-call-corruption/child.ts +7 -0
  379. package/extensions/tool-call-corruption/index.ts +237 -0
  380. package/extensions/tool-search/index.ts +366 -144
  381. package/extensions/tool-style/index.ts +68 -10
  382. package/extensions/tool-style/write-description.ts +40 -0
  383. package/extensions/tool-style/write-render.ts +237 -0
  384. package/extensions/turn-duration/index.ts +7 -3
  385. package/extensions/turn-duration/line.ts +47 -4
  386. package/extensions/web/backends.ts +6 -9
  387. package/extensions/web/description.ts +50 -0
  388. package/extensions/web/index.ts +118 -53
  389. package/extensions/web/native-call.ts +15 -0
  390. package/extensions/web/native-results.ts +41 -0
  391. package/extensions/web-fetch/description.ts +42 -0
  392. package/extensions/web-fetch/extract.ts +53 -6
  393. package/extensions/web-fetch/index.ts +125 -76
  394. package/extensions/web-fetch/page-content.ts +19 -0
  395. package/extensions/web-fetch/response.ts +49 -0
  396. package/extensions/web-fetch/summarize.ts +9 -10
  397. package/extensions/workflow/agent-session.ts +108 -18
  398. package/extensions/workflow/args.ts +24 -0
  399. package/extensions/workflow/description.ts +67 -0
  400. package/extensions/workflow/globals.ts +17 -3
  401. package/extensions/workflow/index.ts +157 -162
  402. package/extensions/workflow/records.ts +1 -0
  403. package/extensions/workflow/run-manager.ts +33 -6
  404. package/extensions/workflow/saved-workflows.ts +3 -2
  405. package/extensions/workflow/types.ts +22 -1
  406. package/extensions/workflow/viewer.ts +54 -24
  407. package/extensions/workflow/widget.ts +20 -0
  408. package/extensions/worktree/descriptions.ts +91 -0
  409. package/extensions/worktree/guards.ts +316 -54
  410. package/extensions/worktree/index.ts +162 -44
  411. package/extensions/worktree/powershell-guards.ts +167 -0
  412. package/extensions/worktree/rewrite.ts +14 -16
  413. package/package.json +21 -7
  414. package/skills/artifact-design/SKILL.md +85 -0
  415. package/skills/code-review/SKILL.md +20 -20
  416. package/skills/code-review/cells/arguments-and-flags.md +19 -0
  417. package/skills/code-review/cells/high-3x5-recall-verify.md +137 -0
  418. package/skills/code-review/cells/high-8-inline.md +122 -0
  419. package/skills/code-review/cells/low-1-pass-max4.md +27 -0
  420. package/skills/code-review/cells/low-1-pass-min-files-4.md +28 -0
  421. package/skills/code-review/cells/max-5x5-verify-sweep.md +162 -0
  422. package/skills/code-review/cells/medium-3x5-verify.md +132 -0
  423. package/skills/code-review/cells/minimal-prompt.md +32 -0
  424. package/skills/code-review/cells/xhigh-10-inline-sweep.md +149 -0
  425. package/skills/code-review/cells/xhigh-5x5-verify-sweep.md +162 -0
  426. package/skills/fewer-permission-prompts/SKILL.md +1 -1
  427. package/skills/loop/SKILL.md +11 -0
  428. package/skills/security-review/SKILL.md +2 -5
  429. package/skills/simplify/SKILL.md +7 -5
  430. package/skills/workflow-authoring/SKILL.md +143 -0
  431. package/themes/onecode-light.json +1 -1
  432. package/themes/onecode.json +1 -1
  433. package/types/app.d.ts +58 -0
  434. package/types/community-packages.d.ts +26 -1
  435. package/extensions/auto-mode/recoverability.ts +0 -229
  436. package/extensions/lib/capability-index.ts +0 -466
  437. package/extensions/lib/model-facts.generated.json +0 -2675
  438. package/extensions/lib/model-facts.ts +0 -162
  439. package/extensions/tool-search/announce.ts +0 -42
@@ -1,52 +1,49 @@
1
1
  /**
2
- * Raw-byte key decoding for the /plugins panel (pure).
2
+ * Key decoding for the /plugins panel (pure), named through
3
+ * `lib/key-input.ts` so every terminal encoding of a key decodes alike.
3
4
  *
4
- * Navigation bytes are always controls; any other printable input is a `text`
5
+ * Navigation keys are always controls; any other printable input is a `text`
5
6
  * intent the state layer routes (search box, Add Marketplace draft, or a
6
7
  * single-letter action where the active view has no text field). Unrecognized
7
8
  * escape sequences are swallowed so they never leak into a draft.
8
9
  */
9
10
 
11
+ import { keyId, keyText } from "../../lib/key-input.ts";
12
+
10
13
  export type PanelKey =
11
14
  | { kind: "up" | "down" | "pageUp" | "pageDown" | "nextTab" | "prevTab" | "enter" | "back" | "space" | "backspace" | "close" }
12
15
  | { kind: "text"; text: string };
13
16
 
14
17
  export function decodePanelKey(data: string): PanelKey | undefined {
15
- switch (data) {
16
- case "\x1b[A":
17
- case "\x1bOA":
18
+ switch (keyId(data)) {
19
+ case "up":
18
20
  return { kind: "up" };
19
- case "\x1b[B":
20
- case "\x1bOB":
21
+ case "down":
21
22
  return { kind: "down" };
22
- case "\x1b[5~":
23
+ case "pageUp":
23
24
  return { kind: "pageUp" };
24
- case "\x1b[6~":
25
+ case "pageDown":
25
26
  return { kind: "pageDown" };
26
- case "\x1b[C":
27
- case "\x1bOC":
28
- case "\t":
27
+ case "right":
28
+ case "tab":
29
29
  return { kind: "nextTab" };
30
- case "\x1b[D":
31
- case "\x1bOD":
32
- case "\x1b[Z":
30
+ case "left":
31
+ case "shift+tab":
33
32
  return { kind: "prevTab" };
34
- case "\r":
35
- case "\n":
33
+ case "enter":
36
34
  return { kind: "enter" };
37
- case "\x1b":
35
+ case "escape":
38
36
  return { kind: "back" };
39
- case " ":
37
+ case "space":
40
38
  return { kind: "space" };
41
- case "\x7f":
42
- case "\b":
39
+ case "backspace":
40
+ case "ctrl+backspace":
43
41
  return { kind: "backspace" };
44
- case "\x03": // ctrl+c
42
+ case "ctrl+c":
45
43
  return { kind: "close" };
46
44
  default:
47
45
  break;
48
46
  }
49
- if (data.startsWith("\x1b")) return undefined;
50
- const text = [...data].filter((ch) => ch >= " " && ch !== "\x7f").join("");
47
+ const text = keyText(data);
51
48
  return text ? { kind: "text", text } : undefined;
52
49
  }
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { formatInstallCount } from "../counts.ts";
10
- import { cutPlainText, panelTopRule, type RenderBlock as Block, searchBoxLines, windowBlocks } from "../../lib/tui-render.ts";
10
+ import { cutPlainText, hintLines, panelTopRule, type RenderBlock as Block, searchBoxLines, windowBlocks } from "../../lib/tui-render.ts";
11
11
  import type { DiscoverRow, InstalledRow } from "./rows.ts";
12
12
  import { clampPanelState, type PanelState, type PanelView, resolveDetail, selectableRows, TABS, type Tab } from "./state.ts";
13
13
 
@@ -176,7 +176,7 @@ function detailLines(input: PanelRenderInput, paint: PanelPaint): { lines: strin
176
176
  const discover = row as DiscoverRow;
177
177
  const detail = input.discoverDetails.get(discover.id);
178
178
  push(`${discover.name} · ${discover.marketplace}`, paint.bold);
179
- if (discover.description) push(discover.description);
179
+ if (discover.description) for (const line of wrapNote(discover.description, width - 4)) push(line);
180
180
  push("");
181
181
  if (detail?.version) push(`Version: ${detail.version}`, (t) => paint.fg("dim", t));
182
182
  if (detail?.author) push(`Author: ${detail.author}`, (t) => paint.fg("dim", t));
@@ -250,20 +250,26 @@ const FOOTERS: Record<Tab, string[]> = {
250
250
  /** Installed search hints while the `/` box is open (Esc leaves it). */
251
251
  const INSTALLED_SEARCH_FOOTER = ["Type to search · Enter/Space to toggle · Esc to leave search"];
252
252
 
253
+ /** Footer hint lines wrapped at their separators to the panel's width (one leading space), so no key is cut off. */
254
+ function fitFooter(lines: string[], width: number): string[] {
255
+ return hintLines(lines, width - 1, " ");
256
+ }
257
+
253
258
  export function renderPanel(input: PanelRenderInput, paint: PanelPaint): string[] {
254
259
  const { state, view, width, height } = input;
255
260
  clampPanelState(state, view);
256
261
 
257
262
  const out: string[] = [panelTopRule(paint.fg, width), tabBar(state, view, paint, width), ""];
263
+ // Wrapped to the width where it is set: the list counts its lines for the budget.
258
264
  let footer: string[];
259
265
 
260
266
  if (state.addDialog) {
261
267
  out.push(...addDialogLines(state.addDialog.draft, paint, width));
262
- footer = ["Enter to add · Esc to cancel"];
268
+ footer = fitFooter(["Enter to add · Esc to cancel"], width);
263
269
  } else if (state.detail) {
264
270
  const detail = detailLines(input, paint);
265
271
  out.push(...detail.lines);
266
- footer = [detail.footer];
272
+ footer = fitFooter([detail.footer], width);
267
273
  } else {
268
274
  let blocks: Block[];
269
275
  switch (state.tab) {
@@ -293,7 +299,7 @@ export function renderPanel(input: PanelRenderInput, paint: PanelPaint): string[
293
299
  break;
294
300
  }
295
301
  }
296
- footer = state.tab === "installed" && state.installedSearching ? INSTALLED_SEARCH_FOOTER : FOOTERS[state.tab];
302
+ footer = fitFooter(state.tab === "installed" && state.installedSearching ? INSTALLED_SEARCH_FOOTER : FOOTERS[state.tab], width);
297
303
  const budget = Math.max(3, height - out.length - 2 - footer.length);
298
304
  const windowed = windowBlocks(blocks, state.cursor[state.tab], budget);
299
305
  out.push(...windowed.lines);
@@ -310,6 +316,6 @@ export function renderPanel(input: PanelRenderInput, paint: PanelPaint): string[
310
316
  ),
311
317
  );
312
318
  }
313
- out.push("", ...footer.map((line) => paint.fg("dim", cutPlainText(` ${line}`, width - 1))));
319
+ out.push("", ...footer.map((line) => paint.fg("dim", line)));
314
320
  return out;
315
321
  }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Expanding a plugin command body: arguments, then each `` !`command` ``
3
+ * placeholder replaced with that command's output.
4
+ *
5
+ * Two rules keep a typed argument from becoming shell syntax. Placeholders
6
+ * are found in the body as written, before any argument goes in, and an
7
+ * argument substituted into a placeholder's command goes in as a
8
+ * single-quoted word (`template.ts`), so `$(…)`, `;` or a backtick pair in
9
+ * what the user typed stays text. And the command runs in the bash every
10
+ * other shell path uses (`lib/shell-spawn.ts`: Git Bash on Windows, never a
11
+ * bare `/bin/sh` or `cmd.exe`), as Claude Code runs these in its bash:
12
+ * Node's `shell: true` used `/bin/sh` (dash on Debian and Ubuntu) and
13
+ * `cmd.exe`, where `[[ ]]`, `head` and process substitution fail and the
14
+ * error text became the placeholder's output.
15
+ */
16
+
17
+ import type { ChildProcess } from "node:child_process";
18
+ import { detachedSpawnOptions, killProcessTree, waitForChildExit } from "../lib/process-tree.ts";
19
+ import { bashSpawn, type ShellSpawn, spawnShellCommand } from "../lib/shell-spawn.ts";
20
+ import { shellQuote } from "../lib/shell-quote.ts";
21
+ import { splitShellPlaceholders, substituteArguments } from "./template.ts";
22
+
23
+ export const SHELL_TIMEOUT_MS = 30_000;
24
+ /** A placeholder output past this many characters stops being collected, and says so. */
25
+ const MAX_OUTPUT_CHARS = 2 * 1024 * 1024;
26
+
27
+ /**
28
+ * Run one placeholder command in bash and return its stdout (stderr when
29
+ * stdout is empty), trimmed. A failure returns its error text, as before:
30
+ * the placeholder shows what went wrong rather than vanishing.
31
+ */
32
+ export async function runPlaceholderCommand(
33
+ command: string,
34
+ cwd: string,
35
+ opts: { spec?: ShellSpawn; timeoutMs?: number; maxOutputChars?: number } = {},
36
+ ): Promise<string> {
37
+ const spec = opts.spec ?? bashSpawn().spawn;
38
+ if (!spec) return `command failed: ${bashSpawn().error ?? "no bash shell found"}`;
39
+ let child: ChildProcess;
40
+ try {
41
+ child = spawnShellCommand(spec, command, { cwd, stdio: ["ignore", "pipe", "pipe"], ...detachedSpawnOptions() });
42
+ } catch (error) {
43
+ return `command failed: ${error instanceof Error ? error.message : String(error)}`;
44
+ }
45
+ const maxChars = opts.maxOutputChars ?? MAX_OUTPUT_CHARS;
46
+ let stdout = "";
47
+ let stderr = "";
48
+ const cut = { stdout: false, stderr: false };
49
+ const capture = (sink: "stdout" | "stderr") => (chunk: string) => {
50
+ const current = sink === "stdout" ? stdout : stderr;
51
+ if (current.length + chunk.length > maxChars) cut[sink] = true;
52
+ if (current.length >= maxChars) return;
53
+ const next = current + chunk.slice(0, maxChars - current.length);
54
+ if (sink === "stdout") stdout = next;
55
+ else stderr = next;
56
+ };
57
+ child.stdout?.setEncoding("utf8");
58
+ child.stderr?.setEncoding("utf8");
59
+ child.stdout?.on("data", capture("stdout"));
60
+ child.stderr?.on("data", capture("stderr"));
61
+ let timedOut = false;
62
+ const timeoutMs = opts.timeoutMs ?? SHELL_TIMEOUT_MS;
63
+ const timer = setTimeout(() => {
64
+ timedOut = true;
65
+ killProcessTree(child, "SIGKILL");
66
+ }, timeoutMs);
67
+ timer.unref();
68
+ try {
69
+ await waitForChildExit(child);
70
+ } catch (error) {
71
+ return `command failed: ${error instanceof Error ? error.message : String(error)}`;
72
+ } finally {
73
+ clearTimeout(timer);
74
+ }
75
+ // The model must know an output is incomplete (a `git diff` cut mid-file).
76
+ const shown = stdout ? "stdout" : "stderr";
77
+ const text = `${(stdout || stderr).trim()}${cut[shown] ? `\n[output cut after ${maxChars} characters]` : ""}`;
78
+ if (timedOut) return `${text ? `${text}\n` : ""}command timed out after ${Math.round(timeoutMs / 1000)} seconds`;
79
+ return text;
80
+ }
81
+
82
+ /**
83
+ * Expand a command body: every placeholder's command runs once (with the
84
+ * arguments quoted in), text pieces get the arguments as typed, and an
85
+ * output is never scanned for arguments or placeholders again. `persist`
86
+ * bounds each output (a large `git diff`) before it lands in the prompt.
87
+ */
88
+ export async function expandTemplate(
89
+ body: string,
90
+ args: string,
91
+ cwd: string,
92
+ opts: { persist?: (text: string, index: number) => string; run?: (command: string, cwd: string) => Promise<string> } = {},
93
+ ): Promise<string> {
94
+ const pieces = splitShellPlaceholders(body);
95
+ const commands = [...new Set(pieces.flatMap((piece) => (piece.kind === "shell" ? [substituteArguments(piece.command, args, shellQuote)] : [])))];
96
+ const run = opts.run ?? ((command: string, dir: string) => runPlaceholderCommand(command, dir));
97
+ const outputs = new Map<string, string>();
98
+ await Promise.all(
99
+ commands.map(async (command, index) => {
100
+ const text = await run(command, cwd);
101
+ outputs.set(command, opts.persist ? opts.persist(text, index) : text);
102
+ }),
103
+ );
104
+ return pieces
105
+ .map((piece) => (piece.kind === "text" ? substituteArguments(piece.text, args) : (outputs.get(substituteArguments(piece.command, args, shellQuote)) ?? "")))
106
+ .join("");
107
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Claude Code command-template expansion (pure apart from the shell hook).
2
+ * Claude Code command-template expansion (pure; `shell-expand.ts` runs the commands).
3
3
  *
4
4
  * A command markdown file has frontmatter (`description`, `allowed-tools`,
5
5
  * `argument-hint`) and a body that may contain:
@@ -17,26 +17,43 @@ export interface CommandTemplate {
17
17
  body: string;
18
18
  }
19
19
 
20
- export function substituteArguments(body: string, args: string): string {
20
+ /**
21
+ * Replace `$ARGUMENTS`, `$@` and `$1`… with the invocation's arguments. With
22
+ * `quote`, each argument word is passed through it (a shell placeholder's
23
+ * command gets them as quoted words), so `$ARGUMENTS` stays one word per
24
+ * argument and no argument can add shell syntax.
25
+ */
26
+ export function substituteArguments(body: string, args: string, quote?: (word: string) => string): string {
21
27
  const parts = args.trim().length > 0 ? args.trim().split(/\s+/) : [];
22
- return body
23
- .replace(/\$ARGUMENTS\b/g, args.trim())
24
- .replace(/\$@/g, args.trim())
25
- .replace(/\$(\d+)/g, (_match, index) => parts[Number(index) - 1] ?? "");
28
+ const all = quote ? parts.map(quote).join(" ") : args.trim();
29
+ // One pass: a second pass would substitute inside argument text the first
30
+ // one inserted (an argument holding `$1`), unquoting it.
31
+ return body.replace(/\$ARGUMENTS\b|\$@|\$(\d+)/g, (_match, index: string | undefined) => {
32
+ if (index === undefined) return all;
33
+ const part = parts[Number(index) - 1];
34
+ return quote ? quote(part ?? "") : (part ?? "");
35
+ });
26
36
  }
27
37
 
28
- /** Finds each !`command` occurrence so the caller can run them. */
29
- export function findShellPlaceholders(body: string): string[] {
30
- const found: string[] = [];
38
+ export type TemplatePiece = { kind: "text"; text: string } | { kind: "shell"; command: string };
39
+
40
+ /**
41
+ * A template body split into text and `` !`command` `` placeholders, found in
42
+ * the body as written: an argument substituted later can never become a
43
+ * placeholder. Until 2026-09-27 the arguments went in first, so an argument
44
+ * holding `` !`…` `` ran as a command of its own.
45
+ */
46
+ export function splitShellPlaceholders(body: string): TemplatePiece[] {
47
+ const pieces: TemplatePiece[] = [];
31
48
  const pattern = /!`([^`]+)`/g;
49
+ let last = 0;
32
50
  let match = pattern.exec(body);
33
51
  while (match) {
34
- found.push(match[1]);
52
+ if (match.index > last) pieces.push({ kind: "text", text: body.slice(last, match.index) });
53
+ pieces.push({ kind: "shell", command: match[1] });
54
+ last = match.index + match[0].length;
35
55
  match = pattern.exec(body);
36
56
  }
37
- return found;
38
- }
39
-
40
- export function replaceShellPlaceholders(body: string, outputs: Map<string, string>): string {
41
- return body.replace(/!`([^`]+)`/g, (_match, command: string) => outputs.get(command) ?? "");
57
+ if (last < body.length) pieces.push({ kind: "text", text: body.slice(last) });
58
+ return pieces;
42
59
  }
@@ -0,0 +1,7 @@
1
+ /** One Code's PowerShell tool for an in-process child session (lib/child-extensions.ts): the same tool and activation, prints nothing. */
2
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ import { powershellTool } from "./index.ts";
4
+
5
+ export default function childPowershellExtension(pi: ExtensionAPI) {
6
+ powershellTool(pi, { announce: false });
7
+ }
@@ -10,9 +10,11 @@
10
10
  * (identical in the reconstructed `PowerShellTool/prompt.ts`). The
11
11
  * "Developer tools verified on this machine's PATH" list Claude Code can add
12
12
  * sits behind a remote flag that was off in the capture, so it is not
13
- * reproduced. One Code appends its own short note about the deferred task
14
- * tools and the `Start-Sleep` guard, after the captured text, the way the
15
- * bash tool does.
13
+ * reproduced. The shipped text corrects the captured working-directory
14
+ * sentence (`CC_CWD_SENTENCE`), drops the Glob/Grep lines
15
+ * (`CC_SEARCH_LINES`) and appends One
16
+ * Code's own short note about the deferred task tools and the `Start-Sleep`
17
+ * guard, after the captured text, the way the bash tool does.
16
18
  */
17
19
 
18
20
  export type PowerShellEditionName = "core" | "desktop" | "unknown";
@@ -126,14 +128,44 @@ Usage notes:
126
128
 
127
129
  /** One Code's addendum: where the harness differs from Claude Code's runtime (task tools are deferred, the sleep guard). */
128
130
  export const ONE_CODE_ADDENDUM =
129
- " A background run returns a task id immediately; completion arrives as a task notification, and the output is retrievable with task_output / stoppable with task_stop (both deferred — load them with tool_search; in a one-shot print/json session the call runs to completion and returns the output directly). A foreground command that LEADS with `Start-Sleep` is blocked; to wait on a condition use the monitor tool (deferred — load it with tool_search select:monitor).";
131
+ " A background run returns a task id immediately; completion arrives as a task notification, and the output is retrievable with task_output / stoppable with task_stop (both deferred — load them with tool_search; in a one-shot print/json session the call runs to completion within the foreground timeout and returns the output directly). A foreground command that LEADS with `Start-Sleep` is blocked; to wait on a condition use the monitor tool (deferred — load it with tool_search select:monitor).";
130
132
 
131
133
  /** Claude Code's description for the detected edition, verbatim, without One Code's addendum. */
132
134
  export function claudeCodePowerShellDescription(edition: PowerShellEditionName): string {
133
135
  return TEMPLATE.replace("{{EDITION}}", EDITION_SECTIONS[edition]);
134
136
  }
135
137
 
136
- /** The description the `powershell` tool ships: Claude Code's text plus One Code's addendum. */
138
+ /**
139
+ * Claude Code's shell keeps its working directory between calls; pi's
140
+ * PowerShell tool spawns a fresh process per call in the session's directory,
141
+ * so a `Set-Location` ends with its command. A model that trusts the captured
142
+ * sentence would `cd` in one call and resolve relative paths against the
143
+ * wrong folder in the next, so the shipped text swaps it.
144
+ */
145
+ export const CC_CWD_SENTENCE = "Working directory persists between commands; shell state (variables, functions) does not.";
146
+ export const ONE_CODE_CWD_SENTENCE =
147
+ "Each command starts in the session's working directory; neither a directory change (`cd`, `Set-Location`) nor shell state (variables, functions) carries over to the next command.";
148
+
149
+ /**
150
+ * Claude Code's PowerShell prompt names Glob and Grep even in its native
151
+ * builds, which ship neither (their Bash prompt drops the same two lines).
152
+ * One Code ships no search tools outside the tiny tier, so the lines would
153
+ * forbid the only search route left (`Get-ChildItem -Recurse`,
154
+ * `Select-String`); they are dropped on every tier. A tiny model still sees
155
+ * `find` and `grep` in its tool list.
156
+ */
157
+ export const CC_SEARCH_LINES =
158
+ " - File search: Use Glob (NOT Get-ChildItem -Recurse)\n - Content search: Use Grep (NOT Select-String)\n";
159
+
160
+ /** The same reason takes searching out of the file operations the tool is told to leave alone. */
161
+ export const CC_FILE_OPERATIONS = "(reading, writing, editing, searching, finding files)";
162
+ export const ONE_CODE_FILE_OPERATIONS = "(reading, writing, editing files)";
163
+
164
+ /** The description the `powershell` tool ships: Claude Code's text with the corrections above, plus One Code's addendum. */
137
165
  export function powerShellToolDescription(edition: PowerShellEditionName): string {
138
- return `${claudeCodePowerShellDescription(edition)}${ONE_CODE_ADDENDUM}`;
166
+ const text = claudeCodePowerShellDescription(edition)
167
+ .replace(CC_CWD_SENTENCE, ONE_CODE_CWD_SENTENCE)
168
+ .replace(CC_SEARCH_LINES, "")
169
+ .replace(CC_FILE_OPERATIONS, ONE_CODE_FILE_OPERATIONS);
170
+ return `${text}${ONE_CODE_ADDENDUM}`;
139
171
  }
@@ -64,7 +64,7 @@ export function powershellGuardReason(command: string, opts: { background: boole
64
64
  // finds "rebase" instead of misreading the flag's value as the
65
65
  // subcommand and missing the interactive-editor guard entirely.
66
66
  const words = statement.trim().split(/\s+/).slice(1);
67
- const { sub, rest } = gitSubcommand(words.map((value) => ({ value, hadExpansion: false })));
67
+ const { sub, rest } = gitSubcommand(words.map((value) => ({ value })));
68
68
  const flags = new Set(rest.map((t) => t.value));
69
69
  if (sub === "rebase" && (flags.has("-i") || flags.has("--interactive"))) {
70
70
  return (
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * powershell extension — Claude Code's PowerShell tool on top of pi's own
3
- * `powershell` built-in (docs/decisions/windows.md, findings §22).
3
+ * `powershell` built-in (working-docs/decisions/windows.md, findings §22).
4
4
  *
5
5
  * Registering a tool named `powershell` overrides pi's built-in (findings §2),
6
6
  * exactly as `extensions/bash` overrides `bash`, and the shared body in
7
7
  * lib/shell-tool.ts supplies the `run_in_background` orchestration for both.
8
8
  * The foreground path delegates to pi's real definition
9
- * (`createPowerShellToolDefinition`) so schema, cwd handling, truncation and
10
- * streaming stay upstream's — with One Code's own `operations`
9
+ * (`createPowerShellToolDefinition`) so schema, cwd handling and streaming
10
+ * stay upstream's (a long output is cut Claude Code's way, as for bash) — with One Code's own `operations`
11
11
  * (lib/shell-spawn.ts), because pi's local operations throw off Windows and
12
12
  * this tool is developed against a `pwsh` on this Mac. The description is
13
13
  * Claude Code's captured text (description.ts); the guards are the PowerShell
@@ -25,7 +25,7 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
25
25
  import { createPowerShellToolDefinition } from "@earendil-works/pi-coding-agent";
26
26
  import { Type } from "typebox";
27
27
  import { perCwd } from "../lib/per-cwd.ts";
28
- import { bashSpawn, createPowerShellOperations, POWERSHELL_UTF8_PREFIX, powerShellEdition, powerShellSpawn } from "../lib/shell-spawn.ts";
28
+ import { bashSpawn, createPowerShellOperations, POWERSHELL_TOOL_PREFIX, powerShellEdition, powerShellSpawn } from "../lib/shell-spawn.ts";
29
29
  import { registerShellTool } from "../lib/shell-tool.ts";
30
30
  import { powerShellToolDescription } from "./description.ts";
31
31
  import { powershellGuardReason } from "./guards.ts";
@@ -40,6 +40,11 @@ const PowerShellParams = Type.Object({
40
40
  });
41
41
 
42
42
  export default function powershellExtension(pi: ExtensionAPI) {
43
+ powershellTool(pi, { announce: true });
44
+ }
45
+
46
+ /** The tool itself; `announce: false` is the in-process child's shape (powershell/child.ts), which prints no notices. */
47
+ export function powershellTool(pi: ExtensionAPI, { announce }: { announce: boolean }) {
43
48
  const spec = powerShellSpawn();
44
49
  const operations = createPowerShellOperations(() => spec);
45
50
  const base = createPowerShellToolDefinition(process.cwd(), { operations });
@@ -66,8 +71,8 @@ export default function powershellExtension(pi: ExtensionAPI) {
66
71
  foreground: perCwd((cwd: string) => createPowerShellToolDefinition(cwd, { operations })),
67
72
  guard: powershellGuardReason,
68
73
  backgroundShell: () => spec,
69
- // The foreground path prepends pi's UTF-8 prefix inside the operations; the background spawn needs it too.
70
- wrapBackgroundCommand: (command) => `${POWERSHELL_UTF8_PREFIX}${command}`,
74
+ // The foreground path prepends the tool's prefix inside the operations; the background spawn needs it too.
75
+ wrapBackgroundCommand: (command) => `${POWERSHELL_TOOL_PREFIX}${command}`,
71
76
  });
72
77
 
73
78
  let noticesShown = false;
@@ -76,7 +81,7 @@ export default function powershellExtension(pi: ExtensionAPI) {
76
81
  const active = pi.getActiveTools();
77
82
  const next = withShellTools(active, current);
78
83
  if (next.join(" ") !== active.join(" ")) pi.setActiveTools(next);
79
- if (noticesShown || current.notices.length === 0) return;
84
+ if (!announce || noticesShown || current.notices.length === 0) return;
80
85
  noticesShown = true;
81
86
  for (const notice of current.notices) {
82
87
  if (ctx?.hasUI) ctx.ui.notify(notice, "warning");
@@ -86,4 +91,6 @@ export default function powershellExtension(pi: ExtensionAPI) {
86
91
 
87
92
  pi.on("session_start", (_event, ctx) => reconcile(ctx));
88
93
  pi.on("model_select", () => reconcile());
94
+ // pi restores the selected branch's tool loadout at a /tree switch.
95
+ pi.on("session_tree", () => reconcile());
89
96
  }