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
@@ -0,0 +1,188 @@
1
+ /**
2
+ * The bash tool's model-facing texts: Claude Code's Bash descriptions (pure).
3
+ *
4
+ * Claude Code has three: a short form for its current models, with one extra
5
+ * bullet ("IMPORTANT: Avoid using this tool to run `cat`…") when auto mode is
6
+ * off, and a long form for its weakest models that is the same in every mode.
7
+ * One Code picks the form by tier (lib/tool-variants.ts) and the extra bullet
8
+ * by the permission mode. Two kinds of change from Claude Code's text: tool
9
+ * names are One Code's (`read`, `edit`, `write`, `monitor`, `task_create`),
10
+ * and the working-directory sentence says what this tool does, since each
11
+ * command starts in the session's working directory and a `cd` does not carry
12
+ * over (lib/shell-tool.ts), where Claude Code tracks the directory between
13
+ * calls. The parameter texts are Claude Code's. On the tiny tier, the one
14
+ * with dedicated grep, find and ls tools (search-tools/tools.ts), the long
15
+ * form's two shell-`find` bullets give way to a pointer at those tools, as
16
+ * tiny's system prompt says (system-prompt/tiers/low.ts).
17
+ */
18
+
19
+ import type { DescriptionForm } from "../lib/tool-variants.ts";
20
+
21
+ /** The bullet Claude Code adds to the short form when auto mode is off. */
22
+ export const BASH_AVOID_SHELL_READS_LINE = "- IMPORTANT: Avoid using this tool to run `cat`, `head`, `tail`, `sed`, `awk`, or `echo` commands, unless explicitly instructed or after you have verified that a dedicated tool cannot accomplish your task. Instead, use the appropriate dedicated tool as this will provide a much better experience for the user.\n";
23
+
24
+ /** The short form outside auto mode. */
25
+ export const BASH_SHORT_DESCRIPTION = `Executes a bash command and returns its output.
26
+
27
+ - Each call starts in the session's working directory and a \`cd\` does not carry over, so prefer absolute paths — \`cd\` in a compound command can trigger a permission prompt. Shell state (env vars, functions) does not persist.
28
+ - IMPORTANT: Avoid using this tool to run \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or after you have verified that a dedicated tool cannot accomplish your task. Instead, use the appropriate dedicated tool as this will provide a much better experience for the user.
29
+ - Command output is displayed to you, not reliably to the user.
30
+ - \`timeout\` is in milliseconds: default 120000, max 600000 for a foreground command.
31
+ - \`run_in_background\` runs the command detached: it keeps running across turns and re-invokes you when it exits. No \`&\` needed. Foreground \`sleep\` is blocked; use monitor with an until-loop to wait on a condition.
32
+
33
+ # Git
34
+ - Interactive flags (\`-i\`, e.g. \`git rebase -i\`, \`git add -i\`) are not supported in this environment.
35
+ - Use the \`gh\` CLI for GitHub operations (PRs, issues, API).
36
+ - Commit or push only when the user asks. If on the default branch, branch first.
37
+ - End git commit messages and PR bodies with the attribution lines given in the conversation's system-reminder, when one is present.`;
38
+
39
+ /** The long form (every permission mode). */
40
+ export const BASH_LONG_DESCRIPTION = `Executes a given bash command and returns its output.
41
+
42
+ Each command starts in the session's working directory; neither a directory change (\`cd\`) nor shell state (variables, functions) carries over to the next command.
43
+
44
+ IMPORTANT: Avoid using this tool to run \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or after you have verified that a dedicated tool cannot accomplish your task. Instead, use the appropriate dedicated tool as this will provide a much better experience for the user:
45
+
46
+ - Read files: Use read (NOT cat/head/tail)
47
+ - Edit files: Use edit (NOT sed/awk)
48
+ - Write files: Use write (NOT echo >/cat <<EOF)
49
+ - Communication: Output text directly (NOT echo/printf)
50
+ While the bash tool can do similar things, it’s better to use the built-in tools as they provide a better user experience and make it easier to review tool calls and give permission.
51
+
52
+ # Instructions
53
+ - If your command will create new directories or files, first use this tool to run \`ls\` to verify the parent directory exists and is the correct location.
54
+ - Always quote file paths that contain spaces with double quotes in your command (e.g., cd "path with spaces/file.txt")
55
+ - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of \`cd\`. You may use \`cd\` if the User explicitly requests it. In particular, never prepend \`cd <current-directory>\` to a \`git\` command — \`git\` already operates on the current working tree, and the compound triggers a permission prompt.
56
+ - You may specify an optional timeout in milliseconds (up to 600000ms / 10 minutes for a foreground command). By default, your command will timeout after 120000ms (2 minutes).
57
+ - You can use the \`run_in_background\` parameter to run the command in the background. Only use this if you don't need the result immediately and are OK being notified when the command completes later. You do not need to check the output right away - you'll be notified when it finishes. You do not need to use '&' at the end of the command when using this parameter.
58
+ - For git commands:
59
+ - Prefer to create a new commit rather than amending an existing commit.
60
+ - Before running destructive operations (e.g., git reset --hard, git push --force, git checkout --), consider whether there is a safer alternative that achieves the same goal. Only use destructive operations when they are truly the best approach.
61
+ - Never skip hooks (--no-verify) or bypass signing (--no-gpg-sign, -c commit.gpgsign=false) unless the user has explicitly asked for it. If a hook fails, investigate and fix the underlying issue.
62
+ - Avoid unnecessary \`sleep\` commands:
63
+ - Do not sleep between commands that can run immediately — just run them.
64
+ - Use the monitor tool to stream events from a background process (each stdout line is a notification). For one-shot "wait until done," use bash with run_in_background instead.
65
+ - If your command is long running and you would like to be notified when it finishes — use \`run_in_background\`. No sleep needed.
66
+ - Do not retry failing commands in a sleep loop — diagnose the root cause.
67
+ - If waiting for a background task you started with \`run_in_background\`, you will be notified when it completes — do not poll.
68
+ - Long leading \`sleep\` commands are blocked. To poll until a condition is met, use monitor with an until-loop (e.g. \`until <check>; do sleep 2; done\`) — you get a notification when the loop exits. Do not chain shorter sleeps to work around the block.
69
+ - When running \`find\`, search from \`.\` (or a specific path), not \`/\` — scanning the full filesystem can exhaust system resources on large trees.
70
+ - When using \`find -regex\` with alternation, put the longest alternative first. Example: use \`'.*\\.\\(tsx\\|ts\\)'\` not \`'.*\\.\\(ts\\|tsx\\)'\` — the second form silently skips \`.tsx\` files.
71
+
72
+
73
+ # Committing changes with git
74
+
75
+ Only create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:
76
+
77
+ You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. The numbered steps below indicate which commands should be batched in parallel.
78
+
79
+ Git Safety Protocol:
80
+ - NEVER update the git config
81
+ - NEVER run destructive git commands (push --force, reset --hard, checkout ., restore ., clean -f, branch -D) unless the user explicitly requests these actions. Taking unauthorized destructive actions is unhelpful and can result in lost work, so it's best to ONLY run these commands when given direct instructions
82
+ - NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
83
+ - NEVER run force push to main/master, warn the user if they request it
84
+ - CRITICAL: Always create NEW commits rather than amending, unless the user explicitly requests a git amend. When a pre-commit hook fails, the commit did NOT happen — so --amend would modify the PREVIOUS commit, which may result in destroying work or losing previous changes. Instead, after hook failure, fix the issue, re-stage, and create a NEW commit
85
+ - When staging files, prefer adding specific files by name rather than using "git add -A" or "git add .", which can accidentally include sensitive files (.env, credentials) or large binaries
86
+ - NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive
87
+
88
+ 1. Run the following bash commands in parallel, each using the bash tool:
89
+ - Run a git status command to see all untracked files. IMPORTANT: Never use the -uall flag as it can cause memory issues on large repos.
90
+ - Run a git diff command to see both staged and unstaged changes that will be committed.
91
+ - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.
92
+ 2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:
93
+ - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. "add" means a wholly new feature, "update" means an enhancement to an existing feature, "fix" means a bug fix, etc.).
94
+ - Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files
95
+ - Draft a concise (1-2 sentences) commit message that focuses on the "why" rather than the "what"
96
+ - Ensure it accurately reflects the changes and their purpose
97
+ 3. Run the following commands in parallel:
98
+ - Add relevant untracked files to the staging area.
99
+ - Create the commit with a message, ending with the attribution lines given in the conversation's system-reminder, when one is present.
100
+ - Run git status after the commit completes to verify success.
101
+ Note: git status depends on the commit completing, so run it sequentially after the commit.
102
+ 4. If the commit fails due to pre-commit hook: fix the issue and create a NEW commit
103
+
104
+ Important notes:
105
+ - NEVER run additional commands to read or explore code, besides git bash commands
106
+ - NEVER use the task_create or Agent tools
107
+ - DO NOT push to the remote repository unless the user explicitly asks you to do so
108
+ - IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.
109
+ - IMPORTANT: Do not use --no-edit with git rebase commands, as the --no-edit flag is not a valid option for git rebase.
110
+ - If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit
111
+ - In order to ensure good formatting, ALWAYS pass the commit message via a HEREDOC, a la this example:
112
+ <example>
113
+ git commit -m "$(cat <<'EOF'
114
+ Commit message here.
115
+ EOF
116
+ )"
117
+ </example>
118
+
119
+ # Creating pull requests
120
+ Use the gh command via the bash tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a Github URL use the gh command to get the information needed.
121
+
122
+ IMPORTANT: When the user asks you to create a pull request, follow these steps carefully:
123
+
124
+ 1. Run the following bash commands in parallel using the bash tool, in order to understand the current state of the branch since it diverged from the main branch:
125
+ - Run a git status command to see all untracked files (never use -uall flag)
126
+ - Run a git diff command to see both staged and unstaged changes that will be committed
127
+ - Check if the current branch tracks a remote branch and is up to date with the remote, so you know if you need to push to the remote
128
+ - Run a git log command and \`git diff [base-branch]...HEAD\` to understand the full commit history for the current branch (from the time it diverged from the base branch)
129
+ 2. Analyze all changes that will be included in the pull request, making sure to look at all relevant commits (NOT just the latest commit, but ALL commits that will be included in the pull request!!!), and draft a pull request title and summary:
130
+ - Keep the PR title short (under 70 characters)
131
+ - Use the description/body for details, not the title
132
+ 3. Run the following commands in parallel:
133
+ - Create new branch if needed
134
+ - Push to remote with -u flag if needed
135
+ - Create PR using gh pr create with the format below. Use a HEREDOC to pass the body to ensure correct formatting. End the body with the attribution lines given in the conversation's system-reminder, when one is present.
136
+ <example>
137
+ gh pr create --title "the pr title" --body "$(cat <<'EOF'
138
+ ## Summary
139
+ <1-3 bullet points>
140
+
141
+ ## Test plan
142
+ [Bulleted markdown checklist of TODOs for testing the pull request...]
143
+ EOF
144
+ )"
145
+ </example>
146
+
147
+ Important:
148
+ - DO NOT use the task_create or Agent tools
149
+ - Return the PR URL when you're done, so the user can see it
150
+
151
+ # Other common operations
152
+ - View comments on a Github PR: gh api repos/foo/bar/pulls/123/comments`;
153
+
154
+ /** The long form's shell-`find` advice, which the tiny tier's search tools replace. */
155
+ const SHELL_FIND_LINES = ` - When running \`find\`, search from \`.\` (or a specific path), not \`/\` — scanning the full filesystem can exhaust system resources on large trees.
156
+ - When using \`find -regex\` with alternation, put the longest alternative first. Example: use \`'.*\\.\\(tsx\\|ts\\)'\` not \`'.*\\.\\(ts\\|tsx\\)'\` — the second form silently skips \`.tsx\` files.
157
+ `;
158
+ const SEARCH_TOOLS_LINE = ` - Search with the dedicated tools, not this shell: the find tool for files, the grep tool for content, the ls tool to list a directory.
159
+ `;
160
+
161
+ /** The long form on the tiny tier, whose grep, find and ls tools replace shell searches. */
162
+ export const BASH_LONG_SEARCH_TOOLS_DESCRIPTION = BASH_LONG_DESCRIPTION.replace(SHELL_FIND_LINES, SEARCH_TOOLS_LINE);
163
+
164
+ /** The description for a form and permission mode; `searchTools` when the session has the dedicated search tools. */
165
+ export function bashDescription(form: DescriptionForm, autoMode: boolean, searchTools = false): string {
166
+ if (form === "long") return searchTools ? BASH_LONG_SEARCH_TOOLS_DESCRIPTION : BASH_LONG_DESCRIPTION;
167
+ return autoMode ? BASH_SHORT_DESCRIPTION.replace(BASH_AVOID_SHELL_READS_LINE, "") : BASH_SHORT_DESCRIPTION;
168
+ }
169
+
170
+ /** Claude Code's parameter descriptions. */
171
+ export const BASH_PARAMS = {
172
+ command: `The command to execute`,
173
+ timeout: `Optional timeout in milliseconds (max 600000 for a foreground command)`,
174
+ description: `Clear, concise description of what this command does in active voice. Never use words like "complex" or "risk" in the description - just describe what it does.
175
+
176
+ Say what the command does in plain words: do not echo the command's text, its flags, or file paths - the user reads this description, often without seeing the command.
177
+
178
+ For simple commands (git, npm, standard CLI tools), keep it brief (5-10 words):
179
+ - ls → "List files in current directory"
180
+ - git status → "Show working tree status"
181
+ - npm install → "Install package dependencies"
182
+
183
+ For commands that are harder to parse at a glance (piped commands, obscure flags, etc.), add enough context to clarify what it does:
184
+ - find . -name "*.tmp" -exec rm {} \\; → "Find and delete all .tmp files recursively"
185
+ - git reset --hard origin/main → "Discard all local changes and match remote main"
186
+ - curl -s url | jq '.data[]' → "Fetch JSON from URL and extract data array elements"`,
187
+ run_in_background: `Set to true to run this command in the background.`,
188
+ } as const;
@@ -28,6 +28,7 @@
28
28
  import {
29
29
  gitSubcommand,
30
30
  leadTokens,
31
+ LOOPS,
31
32
  parseCommand,
32
33
  resolvePayload,
33
34
  type Segment,
@@ -37,18 +38,14 @@ import {
37
38
  export const clip = (text: string, max = 200): string => (text.length > max ? `${text.slice(0, max)}…` : text);
38
39
 
39
40
  export function bashGuardReason(command: string, opts: { background: boolean }): string | undefined {
40
- // A heredoc/here-string body is data, but parseCommand tokenizes it as live
41
- // shell — every guard would misfire on body text (a literal `vim` or
42
- // `while … sleep` inside a document). Judge only the command that PRECEDES
43
- // the first `<<`: `sleep 600 <<< ""` is still a sleep (review T14), while a
44
- // `cat <<EOF` body is never read.
45
- const lead = command.split(/<</)[0];
46
- if (lead !== command && !lead.trim()) return undefined;
47
- const { segments, parseFailed } = parseCommand(lead);
48
- if (parseFailed || segments.length === 0) return undefined;
41
+ // A heredoc body is data to the grammar, so a literal `vim` or `while …
42
+ // sleep` inside a document never trips a guard (review T14).
43
+ const parsed = parseCommand(command);
44
+ if (parsed.parseFailed || parsed.segments.length === 0) return undefined;
45
+ const { segments } = parsed;
49
46
  const interactive = interactiveReason(segments);
50
47
  if (interactive || opts.background) return interactive;
51
- return waitReason(segments) ?? pollLoopReason(lead, segments) ?? orphanReason(lead, segments);
48
+ return waitReason(segments) ?? pollLoopReason(command, segments) ?? orphanReason(parsed.background, segments);
52
49
  }
53
50
 
54
51
  // ---------------------------------------------------------------------------
@@ -123,15 +120,13 @@ function waitReason(segments: Segment[]): string | undefined {
123
120
  // ---------------------------------------------------------------------------
124
121
  // Poll-loop guard
125
122
 
123
+ const inLoop = (seg: Segment) => seg.enclosing.some((construct) => LOOPS.has(construct));
124
+
126
125
  function pollLoopReason(command: string, segments: Segment[]): string | undefined {
127
- const first = leadTokens(segments[0])[0]?.value;
128
- if (first !== "while" && first !== "until" && first !== "for") return undefined;
129
- // `sleep` counts only in command position (segment lead, or right after a
130
- // `do`/`then`/`else` keyword) — `echo sleep` is data, not a wait.
131
- const sleeps = segments.some((seg) => {
132
- const { command: cmd } = resolvePayload(leadTokens(seg));
133
- return cmd === "sleep";
134
- });
126
+ // Wherever the loop sits in the line: `echo start; while true; do sleep 5;
127
+ // done` stalls the session as surely as the loop alone. `sleep` counts only
128
+ // as a command inside the loop: `echo sleep` is data.
129
+ const sleeps = segments.some((seg) => inLoop(seg) && resolvePayload(leadTokens(seg)).command === "sleep");
135
130
  if (!sleeps) return undefined;
136
131
  return (
137
132
  `Blocked: a foreground polling loop (\`${clip(command, 160)}\`). It occupies the whole session while it spins. ` +
@@ -143,54 +138,7 @@ function pollLoopReason(command: string, segments: Segment[]): string | undefine
143
138
  // ---------------------------------------------------------------------------
144
139
  // Orphan guard
145
140
 
146
- /** True when the command backgrounds something with a top-level unquoted `&`. */
147
- export function hasBackgroundAmp(command: string): boolean {
148
- let inSingle = false;
149
- let inDouble = false;
150
- let inAnsiC = false; // $'…' honors backslash-escaped quotes, unlike '…'
151
- let escape = false;
152
- for (let i = 0; i < command.length; i++) {
153
- const ch = command[i];
154
- if (escape) {
155
- escape = false;
156
- continue;
157
- }
158
- if (inAnsiC) {
159
- if (ch === "\\") escape = true;
160
- else if (ch === "'") inAnsiC = false;
161
- continue;
162
- }
163
- if (ch === "'" && !inSingle && !inDouble && command[i - 1] === "$") {
164
- inAnsiC = true;
165
- continue;
166
- }
167
- if (ch === "\\" && !inSingle) {
168
- escape = true;
169
- continue;
170
- }
171
- if (ch === "'" && !inDouble) {
172
- inSingle = !inSingle;
173
- continue;
174
- }
175
- if (ch === '"' && !inSingle) {
176
- inDouble = !inDouble;
177
- continue;
178
- }
179
- if (inSingle || inDouble || ch !== "&") continue;
180
- const prev = command[i - 1];
181
- const next = command[i + 1];
182
- if (next === "&") {
183
- i++; // logical &&
184
- continue;
185
- }
186
- if (next === ">") continue; // &> redirect
187
- if (prev === ">" || prev === "|") continue; // 2>&1 fd duplication, |& pipe
188
- return true;
189
- }
190
- return false;
191
- }
192
-
193
- function orphanReason(command: string, segments: Segment[]): string | undefined {
141
+ function orphanReason(background: boolean, segments: Segment[]): string | undefined {
194
142
  const message = (via: string) =>
195
143
  `Blocked: this command detaches a process with ${via}, leaving an orphan this session cannot manage — its output and exit status would be lost. ` +
196
144
  "Run it with run_in_background: true instead: it returns a task id immediately, completion arrives as a task notification, output stays readable with task_output, and it can be stopped with task_stop. " +
@@ -204,7 +152,7 @@ function orphanReason(command: string, segments: Segment[]): string | undefined
204
152
  // Only a `wait` that comes LAST reaps the children — `wait; job &` still
205
153
  // orphans the job it precedes.
206
154
  const lastCmd = resolvePayload(leadTokens(segments[segments.length - 1])).command;
207
- if (hasBackgroundAmp(command) && lastCmd !== "wait") return message("`&`");
155
+ if (background && lastCmd !== "wait") return message("`&`");
208
156
  return undefined;
209
157
  }
210
158
 
@@ -5,77 +5,108 @@
5
5
  * Registering a tool named `bash` overrides the built-in (findings §2), which
6
6
  * is how pi's official sandbox example does it too. The foreground path
7
7
  * delegates to pi's real executor (`createBashToolDefinition`) so upstream
8
- * bash behavior — timeout handling, truncation, PI_* env, spawn hooks — stays
9
- * exactly pi's; the shared body in lib/shell-tool.ts adds the background
8
+ * bash behavior — timeout handling, PI_* env, spawn hooks — stays exactly
9
+ * pi's (its tail cut of a long output is replaced by Claude Code's head-first
10
+ * one, lib/spill-file.ts); the shared body in lib/shell-tool.ts adds the background
10
11
  * branch (spool to `<sessionDir>/bash/<taskId>/output.log`, the shared
11
12
  * background registry, a steered completion notification), and this file only
12
13
  * supplies what is bash's: pi's definition, the bash the session resolved
13
14
  * (lib/shell-spawn.ts — Git Bash on Windows, `CLAUDE_CODE_GIT_BASH_PATH`
14
- * honoured), the CC-shaped description and the bash guards. The permission
15
+ * honoured), Claude Code's description (description.ts) and the bash guards. The permission
15
16
  * gate and auto-mode classifier run before execute like any bash call — a
16
17
  * background command is NOT auto-allowed, and the gate fires before anything
17
18
  * detaches.
18
19
  */
19
20
 
20
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
21
- import { createBashToolDefinition } from "@earendil-works/pi-coding-agent";
21
+ import { join } from "node:path";
22
+ import type { BashSpawnContext, ExtensionAPI } from "@earendil-works/pi-coding-agent";
23
+ import { createBashToolDefinition, createLocalBashOperations, getAgentDir } from "@earendil-works/pi-coding-agent";
22
24
  import { Type } from "typebox";
25
+ import { childProcessEnv, LAUNCHER_ENV_VAR } from "../lib/app-launch.mjs";
23
26
  import { perCwd } from "../lib/per-cwd.ts";
24
- import { bashSpawn } from "../lib/shell-spawn.ts";
27
+ import { bashSpawn, piShellEnv, withChildProcessEnv } from "../lib/shell-spawn.ts";
25
28
  import { registerShellTool } from "../lib/shell-tool.ts";
29
+ import { type DescriptionForm, followDescriptionForm } from "../lib/tool-variants.ts";
30
+ import { PERMISSION_STATUS_CHANNEL, type PermissionStatus } from "../permissions/modes.ts";
31
+ import { BASH_PARAMS, bashDescription } from "./description.ts";
26
32
  import { bashGuardReason } from "./guards.ts";
27
33
 
28
34
  const BashParams = Type.Object({
29
- command: Type.String({ description: "Bash command to execute" }),
30
- timeout: Type.Optional(Type.Number({ description: "Optional timeout in milliseconds (max 600000)" })),
31
- run_in_background: Type.Optional(
32
- Type.Boolean({
33
- description:
34
- "Run detached and return a task id immediately instead of waiting. Completion arrives as a task notification; inspect with task_output, stop with task_stop. Use this instead of nohup/'&' — those leave an unmanaged orphan process",
35
- }),
36
- ),
37
- description: Type.Optional(
38
- Type.String({ description: "5-10 word description of what the command does (shown in notifications)" }),
39
- ),
35
+ command: Type.String({ description: BASH_PARAMS.command }),
36
+ timeout: Type.Optional(Type.Number({ description: BASH_PARAMS.timeout })),
37
+ description: Type.Optional(Type.String({ description: BASH_PARAMS.description })),
38
+ run_in_background: Type.Optional(Type.Boolean({ description: BASH_PARAMS.run_in_background })),
40
39
  });
41
40
 
42
41
  export default function bashExtension(pi: ExtensionAPI) {
42
+ bashTool(pi, { announce: true });
43
+ }
44
+
45
+ /**
46
+ * The tool itself. `announce: false` is the in-process child's shape
47
+ * (bash/child.ts): the same tool, but a child has no terminal of its own
48
+ * (stderr is the parent's TUI), so it prints nothing.
49
+ */
50
+ export function bashTool(pi: ExtensionAPI, { announce }: { announce: boolean }) {
43
51
  // The session's bash, resolved once (lib/shell-spawn.ts). An ignored
44
52
  // CLAUDE_CODE_GIT_BASH_PATH is reported once, at the first session start.
45
53
  const bash = bashSpawn();
46
54
  const shellPath = bash.spawn?.commandTransport === "stdin" ? undefined : bash.spawn?.shell;
47
55
  let warned = false;
48
- pi.on("session_start", (_event, ctx) => {
56
+ if (announce) pi.on("session_start", (_event, ctx) => {
49
57
  if (warned || !bash.warning) return;
50
58
  warned = true;
51
59
  if (ctx.hasUI) ctx.ui.notify(bash.warning, "warning");
52
60
  else process.stderr.write(`${bash.warning}\n`);
53
61
  });
54
62
 
55
- // pi's definition supplies the description and TUI renderers; the executor
56
- // is re-created per working directory because it closes over cwd (worktree
57
- // switches change ctx.cwd mid-session). The same bash drives pi's foreground
63
+ // pi's definition supplies the TUI renderers; the executor is re-created
64
+ // per working directory because it closes over cwd (worktree switches
65
+ // change ctx.cwd mid-session). The same bash drives pi's foreground
58
66
  // executor, so the override applies there too.
59
- const base = createBashToolDefinition(process.cwd(), { shellPath });
60
- // pi's base sentence is "Optionally provide a timeout in seconds." — but the
61
- // `timeout` parameter and the execute path both use milliseconds (Claude
62
- // Code's Bash unit; the executor divides by 1000). The two must not
63
- // contradict, or a model that trusts the description sends `timeout: 120`
64
- // and gets a 120 ms deadline (TOOL-FIDELITY-REVIEW-2026-09-07 H3). Swap in
65
- // CC's Bash sentence.
66
- const baseDescription = base.description.replace(
67
- "Optionally provide a timeout in seconds.",
68
- "`timeout` is in milliseconds: default 120000, max 600000.",
69
- );
67
+ // Every command the model runs gets the user's own environment back under
68
+ // the bundled app (lib/app-launch.mjs), so a `pi` it starts is the user's pi.
69
+ const spawnHook = (context: BashSpawnContext): BashSpawnContext => ({ ...context, env: childProcessEnv(context.env) });
70
+ const base = createBashToolDefinition(process.cwd(), { shellPath, spawnHook });
70
71
 
71
- registerShellTool(pi, {
72
+ // The description follows the tier and the permission mode. It reaches the
73
+ // wire only when a request opens an epoch: inside one the ledger keeps the
74
+ // tools array as recorded (extensions/ledger), so a mode switch never moves
75
+ // the tool or re-caches the prefix; mode reminders and the live permission
76
+ // gate carry the change instead.
77
+ let form: DescriptionForm = "short";
78
+ // Tiny's dedicated search tools replace the long form's shell-find advice.
79
+ let searchTools = false;
80
+ let autoMode = false;
81
+ const describe = () => bashDescription(form, autoMode, searchTools);
82
+ const setDescription = registerShellTool(pi, {
72
83
  name: "bash",
73
84
  ccLabel: "Bash",
74
- description: `${baseDescription} Pass run_in_background: true for long-running commands (builds, servers, watches): it returns a task id immediately so you can keep working, 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). Foreground \`sleep\` is blocked; to wait on a condition use the monitor tool (deferred — load it with tool_search select:monitor) with an until-loop.`,
85
+ description: describe(),
75
86
  parameters: BashParams,
76
87
  base,
77
- foreground: perCwd((cwd: string) => createBashToolDefinition(cwd, { shellPath })),
88
+ foreground: perCwd((cwd: string) => createBashToolDefinition(cwd, { shellPath, spawnHook })),
78
89
  guard: bashGuardReason,
79
90
  backgroundShell: () => bash.spawn,
80
91
  });
92
+ followDescriptionForm(pi, (next, tier) => {
93
+ form = next;
94
+ searchTools = tier === "tiny";
95
+ setDescription(describe());
96
+ });
97
+ pi.events.on(PERMISSION_STATUS_CHANNEL, (data) => {
98
+ const next = (data as PermissionStatus).mode === "auto";
99
+ if (next === autoMode) return;
100
+ autoMode = next;
101
+ setDescription(describe());
102
+ });
103
+
104
+ // The user's own `!` commands, under the bundled app only: pi runs them with
105
+ // its full process environment, so they get the same restore. Outside the app
106
+ // pi's default path runs untouched. They run in the session's bash, the one
107
+ // the bash tool uses.
108
+ pi.on("user_bash", () => {
109
+ if (process.env[LAUNCHER_ENV_VAR] === undefined) return undefined;
110
+ return { operations: withChildProcessEnv(createLocalBashOperations({ shellPath }), () => piShellEnv(join(getAgentDir(), "bin"))) };
111
+ });
81
112
  }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * pi's compaction keep window, at startup (lib/compaction-keep.mjs has the
3
+ * rule and why).
4
+ *
5
+ * On the user's own pi, while neither the user's nor the project's settings set
6
+ * `compaction.keepRecentTokens`, One Code asks once whether to set it to 0 in
7
+ * the user's settings. "Yes" writes that one key (pi merges nested settings
8
+ * key by key when it saves its own, so the value survives); pi reads it at
9
+ * the next start. "No" is remembered in `~/.onecode/settings.json` and never
10
+ * asked again; Escape asks again next start. An explicit value is the user's
11
+ * and is never questioned; `/doctor` shows it. The bundled app sets 0 itself.
12
+ */
13
+
14
+ import os from "node:os";
15
+ import { join } from "node:path";
16
+ import { type ExtensionContext, getAgentDir, SettingsManager } from "@earendil-works/pi-coding-agent";
17
+ import { installKind } from "../doctor/builtins.ts";
18
+ import {
19
+ compactionKeepView,
20
+ KEEP_NO,
21
+ KEEP_YES,
22
+ keepWindowPrompt,
23
+ ONE_CODE_KEEP_RECENT_TOKENS,
24
+ withCompactionKeepBackfilled,
25
+ } from "../lib/compaction-keep.mjs";
26
+ import { readSettingsForWrite, writeSettings } from "../lib/one-code-settings.ts";
27
+ import { tildify } from "../lib/paths.ts";
28
+ import { declined, recordDeclined } from "./declined.ts";
29
+
30
+ /** `~/.onecode/settings.json` key: the user answered "No" to the question. */
31
+ export const KEEP_DECLINED_KEY = "compactionKeepDeclined";
32
+
33
+ /** Ask once, when nothing sets the keep window. Never throws. */
34
+ export async function handleCompactionKeep(ctx: ExtensionContext): Promise<void> {
35
+ try {
36
+ if (installKind() === "app" || !ctx.hasUI || process.env.CC_COMPACTION === "0") return;
37
+ if (declined(KEEP_DECLINED_KEY)) return;
38
+ const agentDir = getAgentDir();
39
+ const manager = SettingsManager.create(ctx.cwd, agentDir);
40
+ const modelKey = ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined;
41
+ if (compactionKeepView(manager.getGlobalSettings(), manager.getProjectSettings(), modelKey).source !== "default") return;
42
+
43
+ const userPath = join(agentDir, "settings.json");
44
+ const choice = await ctx.ui.select(keepWindowPrompt(tildify(userPath, os.homedir())), [KEEP_YES, KEEP_NO]);
45
+ if (choice === KEEP_YES) {
46
+ const { settings, changed } = withCompactionKeepBackfilled(readSettingsForWrite(userPath));
47
+ if (changed) writeSettings(userPath, settings);
48
+ ctx.ui.notify(`Set compaction.keepRecentTokens to ${ONE_CODE_KEEP_RECENT_TOKENS}; /compact works on short sessions from the next start.`, "info");
49
+ } else if (choice === KEEP_NO) {
50
+ try {
51
+ recordDeclined(KEEP_DECLINED_KEY);
52
+ } catch (error) {
53
+ ctx.ui.notify(`Could not remember the answer in ~/.onecode/settings.json: ${(error as Error).message}. One Code asks again next start.`, "warning");
54
+ }
55
+ }
56
+ } catch (error) {
57
+ try {
58
+ ctx.ui.notify(`Could not set pi's compaction keep window: ${(error as Error).message}. Run /doctor for the settings change.`, "warning");
59
+ } catch {
60
+ // The session ended while the dialog was open: nothing is left to tell.
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The startup questions' remembered "No" (replaced-builtins.ts,
3
+ * compaction-keep.ts): a key set to true in `~/.onecode/settings.json`.
4
+ */
5
+
6
+ import os from "node:os";
7
+ import { oneCodeSettingsPath, readSettingsForWrite, writeSettings } from "../lib/one-code-settings.ts";
8
+
9
+ /** Whether the user answered "No" to the question kept under `key`; a malformed settings file reads as not declined. */
10
+ export function declined(key: string): boolean {
11
+ try {
12
+ return readSettingsForWrite(oneCodeSettingsPath(os.homedir()))[key] === true;
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+
18
+ /** Remember a "No" to the question kept under `key`. */
19
+ export function recordDeclined(key: string): void {
20
+ const path = oneCodeSettingsPath(os.homedir());
21
+ writeSettings(path, { ...readSettingsForWrite(path), [key]: true });
22
+ }