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
@@ -14,6 +14,9 @@
14
14
  */
15
15
 
16
16
  import { existsSync, readFileSync } from "node:fs";
17
+ import { ARGUMENT_HINT_CHANNEL, type ArgumentHint, type CommandHint, frontmatterCommandHint, hintForInput, PI_BUILTIN_HINTS } from "../lib/argument-hints.ts";
18
+ import { parseFrontmatterLoosely } from "../lib/frontmatter.ts";
19
+ import { promptTemplateFiles } from "../lib/skill-scan.ts";
17
20
  import { modeCycleKey } from "../lib/keys.ts";
18
21
  import os from "node:os";
19
22
  import { fileURLToPath } from "node:url";
@@ -21,6 +24,8 @@ import { basename, dirname, join } from "node:path";
21
24
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
22
25
  import { getAgentDir, SettingsManager, VERSION as PI_VERSION } from "@earendil-works/pi-coding-agent";
23
26
  import { piVersionWarning } from "../lib/pi-version.ts";
27
+ import { handleCompactionKeep } from "./compaction-keep.ts";
28
+ import { handleReplacedBuiltins } from "./replaced-builtins.ts";
24
29
  import { extensionVersion } from "../lib/package-version.ts";
25
30
  import {
26
31
  formatModel,
@@ -38,9 +43,11 @@ import {
38
43
  shouldDefaultHideThinking,
39
44
  type StartupSection,
40
45
  } from "./startup.ts";
41
- import { linesComponent, safeThemePaint, truncateLine } from "../lib/tui-render.ts";
46
+ import { linesComponent, safeThemeInverse, safeThemePaint, truncateLine } from "../lib/tui-render.ts";
47
+ import { AGENT_VIEW_CHANNEL, type AgentViewAnnouncement, type AgentViewTarget } from "../lib/agent-view.ts";
42
48
  import { markAssistantMarkdown } from "./assistant-marker.ts";
43
49
  import { PROMPT_PADDING, PromptEditor } from "./prompt-editor.ts";
50
+ import { sanitizeTitle } from "../lib/terminal-text.ts";
44
51
 
45
52
  export { truncateLine };
46
53
 
@@ -138,6 +145,19 @@ export function sectionSummary(sections: StartupSection[], paint: (color: string
138
145
  .join(paint("muted", " · "));
139
146
  }
140
147
 
148
+ /** The mode line's words for each permission mode, so the banner never says "default" beside "manual mode on". */
149
+ const MODE_WORDS: Record<string, string> = {
150
+ default: "manual",
151
+ acceptEdits: "accept edits",
152
+ bypassPermissions: "bypass permissions",
153
+ dontAsk: "don't ask",
154
+ };
155
+
156
+ /** The banner's mode field: the permission display with the mode named as the mode line names it. */
157
+ export function bannerModeLabel(display: string): string {
158
+ return MODE_WORDS[display] ?? display;
159
+ }
160
+
141
161
  /**
142
162
  * Banner layout: the wordmark block, then a one-space-indented text column
143
163
  * (tagline + version, context, hints, sections). Kept pure so the layout is
@@ -213,7 +233,11 @@ interface BrandingEditorUI {
213
233
  * a pi-tui render change ever makes the marker misplace (cosmetic only — typing
214
234
  * is never affected; see prompt-marker.ts).
215
235
  */
216
- function installPromptMarker(ctx: { hasUI: boolean; mode: string; ui: BrandingEditorUI }): void {
236
+ function installPromptMarker(
237
+ ctx: { hasUI: boolean; mode: string; ui: BrandingEditorUI; isIdle(): boolean; hasPendingMessages(): boolean },
238
+ argumentHints: ReadonlyMap<string, CommandHint>,
239
+ agentView: { target?: AgentViewTarget },
240
+ ): void {
217
241
  if (process.env.CC_NO_INPUT_MARKER === "1") return;
218
242
  if (!ctx.hasUI || ctx.mode !== "tui") return;
219
243
  const ui = ctx.ui;
@@ -223,7 +247,26 @@ function installPromptMarker(ctx: { hasUI: boolean; mode: string; ui: BrandingEd
223
247
  // Bold makes the chevron read heavier than the input text beside it.
224
248
  return `\x1b[1m${safeThemePaint(ui.theme)("accent", PROMPT_GLYPH)}\x1b[0m${" ".repeat(PROMPT_PADDING - 1)}`;
225
249
  };
226
- ui.setEditorComponent((tui: unknown, theme: unknown, keybindings: unknown) => new PromptEditor(tui as never, theme as never, keybindings as never, renderMarker));
250
+ const renderHint = (text: string) => {
251
+ // While an agent is viewed the empty editor addresses it (lib/agent-view.ts).
252
+ const placeholder = text === "" && agentView.target ? agentView.target.placeholder : hintForInput(text, argumentHints);
253
+ return placeholder === undefined ? undefined : safeThemePaint(ui.theme)("dim", placeholder);
254
+ };
255
+ const badge = () => agentView.target?.badge;
256
+ const paintBadge = (label: string) => safeThemeInverse(ui.theme)(safeThemePaint(ui.theme)("accent", ` ${label} `));
257
+ // The editor can outlive this context across a session replacement; a stale
258
+ // context throws, and ↑ must still reach the editor then.
259
+ const queued = () => {
260
+ try {
261
+ return !ctx.isIdle() && ctx.hasPendingMessages();
262
+ } catch {
263
+ return false;
264
+ }
265
+ };
266
+ ui.setEditorComponent(
267
+ (tui: unknown, theme: unknown, keybindings: unknown) =>
268
+ new PromptEditor(tui as never, theme as never, keybindings as never, renderMarker, renderHint, badge, paintBadge, queued),
269
+ );
227
270
  }
228
271
 
229
272
  /**
@@ -268,6 +311,25 @@ function applyOutputPadDefault(): void {
268
311
  }
269
312
 
270
313
  export default function brandingExtension(pi: ExtensionAPI) {
314
+ /**
315
+ * pi's merged `quietStartup` (global settings with the project's
316
+ * `.pi/settings.json` over them), so the banner and pi agree on whether pi
317
+ * lists its own startup sections. `pi.getSettings()` is in pi 1.0.1; a pi
318
+ * near the 0.84.3 floor without it falls back to the global file alone.
319
+ */
320
+ const effectiveQuietStartup = (agentDir: string): unknown => {
321
+ try {
322
+ if (typeof (pi as { getSettings?: unknown }).getSettings === "function") return pi.getSettings().quietStartup;
323
+ } catch {
324
+ // The banner must still install: fall back to the global file.
325
+ }
326
+ try {
327
+ return (JSON.parse(readFileSync(join(agentDir, "settings.json"), "utf8")) as { quietStartup?: unknown }).quietStartup;
328
+ } catch {
329
+ return undefined;
330
+ }
331
+ };
332
+
271
333
  applyThinkingDefault();
272
334
  applyOutputPadDefault();
273
335
  // Mark each block of assistant prose with Claude Code's "●" bullet. Only
@@ -296,7 +358,9 @@ export default function brandingExtension(pi: ExtensionAPI) {
296
358
  const retitle = (ctx: { hasUI: boolean; cwd: string; ui: { setTitle(title: string): void } }) => {
297
359
  if (!live || !ctx.hasUI) return;
298
360
  const name = pi.getSessionName?.()?.trim();
299
- const title = name ? `${NAME} - ${name} - ${basename(ctx.cwd)}` : NAME;
361
+ // pi writes the title inside its OSC 0 and strips only CR and LF; a BEL or
362
+ // ESC in the session name (any source) or the directory would end it early.
363
+ const title = sanitizeTitle(name ? `${NAME} - ${name} - ${basename(ctx.cwd)}` : NAME);
300
364
  if (title === lastTitle) return; // agent_start fires every turn; write only on change
301
365
  lastTitle = title;
302
366
  ctx.ui.setTitle(title);
@@ -307,18 +371,76 @@ export default function brandingExtension(pi: ExtensionAPI) {
307
371
  live = false;
308
372
  });
309
373
 
310
- pi.on("session_start", (_event, ctx) => {
374
+ // Commands' argument placeholders (lib/argument-hints.ts), drawn by the prompt editor.
375
+ // Declared before the CC_NO_BANNER return below: session_start reads it.
376
+ const argumentHints = new Map<string, CommandHint>(Object.entries(PI_BUILTIN_HINTS).map(([command, hint]) => [command, { hint }]));
377
+ // The agent the user is viewing, if any: the editor then targets it (lib/agent-view.ts).
378
+ const agentView: { target?: AgentViewTarget } = {};
379
+ pi.events.on(AGENT_VIEW_CHANNEL, (data) => {
380
+ agentView.target = (data as AgentViewAnnouncement | undefined)?.target;
381
+ });
382
+ pi.events.on(ARGUMENT_HINT_CHANNEL, (data) => {
383
+ const { command, ...hint } = data as ArgumentHint;
384
+ argumentHints.set(command, hint);
385
+ });
386
+ // pi's prompt templates and `/skill:` commands carry their file's
387
+ // `argument-hint` frontmatter. pi lists them only once a turn resolves them,
388
+ // so the template folders are scanned at session_start (the skill extension
389
+ // announces `/skill:` hints from its own scan) and pi's list read each turn.
390
+ // pi runs a built-in or extension command before a command file of the same
391
+ // name, so such a file's hint is never read.
392
+ const hintedFiles = new Set<string>();
393
+ const readFileHints = (files: { name: string; path: string }[], commands = pi.getCommands()) => {
394
+ const extensionCommands = new Set(commands.filter((c) => c.source === "extension").map((c) => c.name));
395
+ for (const { name, path } of files) {
396
+ if (hintedFiles.has(path)) continue;
397
+ if (Object.hasOwn(PI_BUILTIN_HINTS, name) || extensionCommands.has(name)) continue;
398
+ try {
399
+ const hint = frontmatterCommandHint(parseFrontmatterLoosely(readFileSync(path, "utf-8")).frontmatter);
400
+ if (hint) argumentHints.set(name, hint);
401
+ hintedFiles.add(path);
402
+ } catch {
403
+ // Unreadable (mid-replace, say): no hint now; a later scan retries it.
404
+ }
405
+ }
406
+ };
407
+ pi.on("before_agent_start", () => {
408
+ try {
409
+ const commands = pi.getCommands();
410
+ readFileHints(
411
+ commands.filter((c) => c.source !== "extension").map((c) => ({ name: c.name, path: c.sourceInfo.path })),
412
+ commands,
413
+ );
414
+ } catch {
415
+ // Not bound (a torn-down session): the next turn looks again.
416
+ }
417
+ });
418
+ pi.on("session_start", (event, ctx) => {
311
419
  // pi's own write lands after this handler, so only the deferred write
312
420
  // sticks; a new session may carry a name (resume), so forget the last.
313
421
  lastTitle = undefined;
314
422
  live = true;
315
423
  setTimeout(() => retitle(ctx), 0).unref?.();
316
424
  ctx.ui.setHiddenThinkingLabel(THINKING_LABEL);
317
- installPromptMarker(ctx as unknown as { hasUI: boolean; mode: string; ui: BrandingEditorUI });
425
+ installPromptMarker(ctx as unknown as Parameters<typeof installPromptMarker>[0], argumentHints, agentView);
426
+ try {
427
+ readFileHints(promptTemplateFiles(ctx.cwd, os.homedir(), getAgentDir()));
428
+ } catch {
429
+ // Commands not bound: nothing was marked read, so the next turn reads pi's list.
430
+ }
318
431
  // Soft drift guard: warn once at startup when the hosting pi is outside
319
432
  // the range this release was tested against (see lib/pi-version.ts).
320
433
  const versionWarning = piVersionWarning(PI_VERSION);
321
434
  if (versionWarning) ctx.ui.notify(versionWarning, "warning");
435
+ // pi 0.99 skips its built-in tool search and MCP for ours and warns at
436
+ // every start, advising the user to remove One Code: offer to turn them
437
+ // off once, else answer with the notice (replaced-builtins.ts). Only
438
+ // when pi resolves its built-ins again (startup, /reload), not on a
439
+ // /new, resume or fork, which re-run this handler too. Not awaited: a
440
+ // dialog must not hold up startup. The compaction keep-window question
441
+ // (compaction-keep.ts) follows it, so the two dialogs never overlap.
442
+ const reason = (event as { reason?: string }).reason ?? "startup";
443
+ if (reason === "startup" || reason === "reload") void handleReplacedBuiltins(ctx).then(() => handleCompactionKeep(ctx));
322
444
  });
323
445
 
324
446
  if (process.env.CC_NO_BANNER === "1") return;
@@ -363,9 +485,11 @@ export default function brandingExtension(pi: ExtensionAPI) {
363
485
  // instead (minus the internal [Extensions] noise).
364
486
  const home = os.homedir();
365
487
  // Resolve pi's live agent dir (honours PI_CODING_AGENT_DIR) so an
366
- // isolated one-code app reads its own settings/skills, never ~/.pi.
488
+ // isolated one-code app reads its own skills, never ~/.pi.
367
489
  const agentDir = getAgentDir();
368
- const sections = quietStartupEnabled(join(agentDir, "settings.json"))
490
+ // Use pi's effective settings, including project overrides, so the two
491
+ // listings agree on whether quiet startup is enabled.
492
+ const sections = quietStartupEnabled(effectiveQuietStartup(agentDir))
369
493
  ? collectStartupSections(ctx.cwd, home, join(dirname(fileURLToPath(import.meta.url)), "..", "..", "themes"), agentDir)
370
494
  : undefined;
371
495
 
@@ -387,7 +511,7 @@ export default function brandingExtension(pi: ExtensionAPI) {
387
511
  version,
388
512
  model: modelLabel ?? "none",
389
513
  cwd: ctx.cwd,
390
- mode: permissionModeDisplay(permissionStatus ?? { mode: "default", paused: false }),
514
+ mode: bannerModeLabel(permissionModeDisplay(permissionStatus ?? { mode: "default", paused: false })),
391
515
  subagents:
392
516
  modelLabel === undefined
393
517
  ? "none"
@@ -3,14 +3,19 @@
3
3
  *
4
4
  * pi's editor has no prompt marker and no option for one, but `CustomEditor` is
5
5
  * the sanctioned base for a replacement (it already wires every app keybinding
6
- * through handleInput, which we leave untouched). We only reserve a two-column
7
- * left gutter and paint the marker into it — see prompt-marker.ts for why that
8
- * is cursor-safe. Registered via `ctx.ui.setEditorComponent`; this file is thin
6
+ * through handleInput). We reserve a two-column left gutter and paint the
7
+ * marker into it — see prompt-marker.ts for why that is cursor-safe — draw a
8
+ * slash command's argument hint after the cursor (lib/argument-hints.ts), and
9
+ * let ↑ restore queued messages through pi's dequeue action (queued-edit.ts). Registered via `ctx.ui.setEditorComponent`; this file is thin
9
10
  * wiring over the pure `applyPromptMarker`.
10
11
  */
11
12
 
12
13
  import { CustomEditor } from "@earendil-works/pi-coding-agent";
14
+ import { applyBorderBadge, fitBadge } from "../lib/agent-view.ts";
15
+ import { applyArgumentHint } from "../lib/argument-hints.ts";
16
+ import { visibleWidth } from "../lib/text-width.ts";
13
17
  import { applyPromptMarker } from "./prompt-marker.ts";
18
+ import { upEditsQueue } from "./queued-edit.ts";
14
19
 
15
20
  /** Width of the left gutter, and therefore the visible width the marker must fill. */
16
21
  export const PROMPT_PADDING = 2;
@@ -20,10 +25,45 @@ type EditorArgs = ConstructorParameters<typeof CustomEditor>;
20
25
  export class PromptEditor extends CustomEditor {
21
26
  /** Re-read per render so the marker follows live theme changes. */
22
27
  #renderMarker: () => string;
28
+ /** The painted argument placeholder for the current input, if it is a hinted command. */
29
+ #renderHint: (text: string) => string | undefined;
30
+ /** The viewed agent's top-border label (plain text), or undefined on main (lib/agent-view.ts). */
31
+ #badge: () => string | undefined;
32
+ /** Paints the fitted badge label as a chip, one space of padding on each side. */
33
+ #paintBadge: (label: string) => string;
34
+ /** Whether a message waits in pi's queue mid-turn (queued-edit.ts). */
35
+ #queued: () => boolean;
36
+ #keys: EditorArgs[2];
37
+ /** The width pi wraps the text at, from the last render (pi's own formula). */
38
+ #layoutWidth = Number.POSITIVE_INFINITY;
23
39
 
24
- constructor(tui: EditorArgs[0], theme: EditorArgs[1], keybindings: EditorArgs[2], renderMarker: () => string) {
25
- super(tui, theme, keybindings, { paddingX: PROMPT_PADDING });
40
+ constructor(
41
+ tui: EditorArgs[0],
42
+ theme: EditorArgs[1],
43
+ keybindings: EditorArgs[2],
44
+ renderMarker: () => string,
45
+ renderHint: (text: string) => string | undefined = () => undefined,
46
+ badge: () => string | undefined = () => undefined,
47
+ paintBadge: (label: string) => string = (label) => label,
48
+ queued: () => boolean = () => false,
49
+ ) {
50
+ super(tui, theme, keybindings, { paddingX: PROMPT_PADDING, embedWorkingStatus: true });
26
51
  this.#renderMarker = renderMarker;
52
+ this.#renderHint = renderHint;
53
+ this.#badge = badge;
54
+ this.#paintBadge = paintBadge;
55
+ this.#queued = queued;
56
+ this.#keys = keybindings;
57
+ }
58
+
59
+ /** ↑ on the first line restores queued messages, as in Claude Code (queued-edit.ts). */
60
+ handleInput(data: string): void {
61
+ const dequeue = this.actionHandlers.get("app.message.dequeue");
62
+ if (dequeue && this.#keys.matches(data, "tui.editor.cursorUp") && upEditsQueue(this, this.#queued(), this.#layoutWidth)) {
63
+ dequeue();
64
+ return;
65
+ }
66
+ super.handleInput(data);
27
67
  }
28
68
 
29
69
  /**
@@ -37,6 +77,13 @@ export class PromptEditor extends CustomEditor {
37
77
  }
38
78
 
39
79
  render(width: number): string[] {
40
- return applyPromptMarker(super.render(width), PROMPT_PADDING, this.#renderMarker());
80
+ const paddingX = Math.min(PROMPT_PADDING, Math.max(0, Math.floor((width - 1) / 2)));
81
+ this.#layoutWidth = Math.max(1, width - paddingX * 2 - (paddingX ? 0 : 1));
82
+ let lines = applyPromptMarker(super.render(width), PROMPT_PADDING, this.#renderMarker());
83
+ const hint = this.#renderHint(this.getText());
84
+ if (hint) lines = applyArgumentHint(lines, hint);
85
+ const label = this.#badge();
86
+ const fitted = label ? fitBadge(label, width) : "";
87
+ return fitted ? applyBorderBadge(lines, this.#paintBadge(fitted), visibleWidth(fitted) + 2, this.borderColor("─")) : lines;
41
88
  }
42
89
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Claude Code's key for editing queued messages: plain ↑. With a message
3
+ * queued mid-turn, ↑ moves every queued message into the editor instead of
4
+ * walking history, but only with the cursor on the draft's first line (lower
5
+ * lines need ↑ to move the cursor) and no autocomplete list open (↑ moves in
6
+ * the list). pi binds the same restore only to alt+up, which not every
7
+ * terminal sends: macOS Terminal's terminfo (nsterm) maps option+left and
8
+ * option+right but no modified up arrow. Pure: `prompt-editor.ts` calls pi's
9
+ * own dequeue action, so the alt+up binding keeps working alongside.
10
+ */
11
+
12
+ import { visibleWidth } from "../lib/text-width.ts";
13
+
14
+ export interface QueueEditEditor {
15
+ getCursor(): { line: number; col: number };
16
+ getLines(): string[];
17
+ isShowingAutocomplete(): boolean;
18
+ }
19
+
20
+ /**
21
+ * Whether a plain ↑ restores the queued messages rather than reaching the
22
+ * editor. Only on a first line that fits one row of `layoutWidth`: pi's
23
+ * public API does not say which visual row the cursor is on, so on a wrapped
24
+ * first line ↑ is left to pi (it moves the cursor) and alt+up restores.
25
+ */
26
+ export function upEditsQueue(editor: QueueEditEditor, queued: boolean, layoutWidth: number): boolean {
27
+ if (!queued) return false;
28
+ if (editor.isShowingAutocomplete()) return false;
29
+ if (editor.getCursor().line !== 0) return false;
30
+ return visibleWidth(editor.getLines()[0] ?? "") <= layoutWidth;
31
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * pi 0.99's built-in tool search and MCP, at startup (lib/replaced-builtins.mjs
3
+ * has the rule; decisions/tools.md "pi's built-in tool search and MCP").
4
+ *
5
+ * On the user's own pi, while the user's settings leave a built-in on, One
6
+ * Code asks once whether to turn them off, explaining why. "Yes" writes the
7
+ * `-builtin:<name>` entries through pi's own SettingsManager (a locked write
8
+ * of the `extensions` field only, so pi's in-memory settings keep theirs).
9
+ * "No" is remembered in `~/.onecode/settings.json` and never asked again;
10
+ * Escape asks again next start. Without a yes, the one-line notice answers
11
+ * pi's warning instead. Under the bundled app, which turns them off itself,
12
+ * a built-in left on is the user's own `+` entry, so only the notice shows.
13
+ */
14
+
15
+ import os from "node:os";
16
+ import { type ExtensionContext, getAgentDir, SettingsManager, VERSION as PI_VERSION } from "@earendil-works/pi-coding-agent";
17
+ import { configCommand, installKind, replacedBuiltinsView } from "../doctor/builtins.ts";
18
+ import { tildify } from "../lib/paths.ts";
19
+ import { declined, recordDeclined } from "./declined.ts";
20
+ import { replacedBuiltinsNotice, TURN_OFF_NO, TURN_OFF_YES, turnOffPrompt, withBuiltinsTurnedOff } from "../lib/replaced-builtins.mjs";
21
+
22
+ /** `~/.onecode/settings.json` key: the user answered "No" to the question. */
23
+ export const DECLINED_KEY = "piBuiltinsTurnOffDeclined";
24
+
25
+ /** Ask, or show the notice, for the built-ins the settings leave on. Never throws. */
26
+ export async function handleReplacedBuiltins(ctx: ExtensionContext): Promise<void> {
27
+ try {
28
+ const cwd = ctx.cwd;
29
+ const agentDir = getAgentDir();
30
+ const settings = () => SettingsManager.create(cwd, agentDir);
31
+ const view = replacedBuiltinsView(PI_VERSION, settings, { agentDir, cwd });
32
+ if (!view || view.left.length === 0) return;
33
+ const install = installKind();
34
+ const command = configCommand(install);
35
+ const notice = () => {
36
+ const text = replacedBuiltinsNotice(view.left, command);
37
+ if (text) ctx.ui.notify(text, "info");
38
+ };
39
+ // Only the user's own file is ours to offer: a project's `+builtin` entry stays.
40
+ const userScoped = view.left.filter((builtin) => builtin.scope === "user");
41
+ if (install === "app" || !ctx.hasUI || userScoped.length === 0 || declined(DECLINED_KEY)) return notice();
42
+
43
+ const shown = tildify(view.paths.user, os.homedir());
44
+ const choice = await ctx.ui.select(turnOffPrompt(userScoped, shown, command), [TURN_OFF_YES, TURN_OFF_NO]);
45
+ if (choice === TURN_OFF_YES) {
46
+ const manager = settings();
47
+ manager.setExtensionPaths(withBuiltinsTurnedOff(manager.getGlobalSettings().extensions, userScoped.map((builtin) => builtin.name)) as string[]);
48
+ await manager.flush();
49
+ const turnedOff = `Turned off pi's built-in ${userScoped.map((builtin) => builtin.name).join(" and ")} in ${shown}.`;
50
+ // A project's `+builtin` entry still wins over the user's file, so its warning stays.
51
+ const projectScoped = view.left.filter((builtin) => builtin.scope === "project");
52
+ const rest =
53
+ projectScoped.length === 0
54
+ ? "pi's warnings stop from the next start."
55
+ : `This project's settings keep ${projectScoped.map((builtin) => builtin.name).join(" and ")} on, so pi still warns about ${projectScoped.length > 1 ? "them" : "it"}; run /doctor for that change.`;
56
+ ctx.ui.notify(`${turnedOff} ${rest}`, "info");
57
+ return;
58
+ }
59
+ if (choice === TURN_OFF_NO) recordDeclined(DECLINED_KEY);
60
+ notice();
61
+ } catch (error) {
62
+ try {
63
+ ctx.ui.notify(`Could not turn off pi's built-in tool search and MCP: ${(error as Error).message}. Run /doctor for the settings change.`, "warning");
64
+ } catch {
65
+ // The session ended while the dialog was open: nothing is left to tell.
66
+ }
67
+ }
68
+ }
@@ -2,8 +2,8 @@
2
2
  * Compact startup sections for the banner: Context, Skills, Themes.
3
3
  *
4
4
  * pi's own startup listing has no per-section switch — hiding the noisy
5
- * [Extensions] block (20 internal module names) means `quietStartup: true`,
6
- * which hides everything. So when quiet startup is on, the banner shows its
5
+ * [Extensions] block (20 internal module names) means `quietStartup`, which
6
+ * hides the whole listing. So when quiet startup is on, the banner shows its
7
7
  * own compact versions of the sections that ARE useful. pi's resourceLoader
8
8
  * is not exposed to extensions, so these are re-derived the same way our
9
9
  * other extensions derive them (claude-compat's skill dirs, pi's git-root
@@ -12,11 +12,14 @@
12
12
  * PI_CODING_AGENT_DIR isolation).
13
13
  */
14
14
 
15
- import { existsSync, readdirSync, readFileSync } from "node:fs";
16
- import { basename, dirname, join, relative } from "node:path";
17
- import { findGitRoot } from "../lib/git.ts";
15
+ import { existsSync, readdirSync } from "node:fs";
16
+ import { basename, join, relative } from "node:path";
17
+ import os from "node:os";
18
+ import { projectInstructionFiles } from "../lib/claude-context.ts";
19
+ import { projectConfigDir, userConfigDir } from "../lib/config-mode.ts";
20
+ import { BUNDLED_SKILLS_DIR, scanSkills } from "../lib/skill-scan.ts";
18
21
  import { defaultDiscoverRoots, discoverPlugins } from "../lib/plugins.ts";
19
- import { claudeUserDir } from "../lib/paths.ts";
22
+ import { oneCodeStateDir } from "../lib/paths.ts";
20
23
 
21
24
  export interface StartupSection {
22
25
  label: string;
@@ -25,69 +28,29 @@ export interface StartupSection {
25
28
 
26
29
  /**
27
30
  * The project context files One Code actually gathers, from cwd up to the git
28
- * root (or just cwd outside a repo), for the startup banner. Mirrors what the
29
- * blocks send: a directory's CLAUDE.md, or its AGENTS.md when it has no CLAUDE.md
30
- * (CLAUDE.md > AGENTS.md), plus CLAUDE.local.md and ONECODE.md when present — so
31
- * AGENTS.md is listed only when it's really in play, not whenever it exists.
31
+ * root (or just cwd outside a repo), nearest directory first, for the startup
32
+ * banner. The same discovery and rule the blocks use (lib/claude-context.ts),
33
+ * so an AGENTS.md is listed only when it is really in play.
32
34
  */
33
- export function contextFileNames(cwd: string): string[] {
34
- const stop = findGitRoot(cwd) ?? cwd;
35
- const found: string[] = [];
36
- let dir = cwd;
37
- while (true) {
38
- const rel = (name: string) => relative(cwd, join(dir, name)) || name;
39
- const present = (name: string) => existsSync(join(dir, name));
40
- // CLAUDE.md is primary; AGENTS.md stands in only when there is no CLAUDE.md.
41
- if (present("CLAUDE.md")) found.push(rel("CLAUDE.md"));
42
- else if (present("AGENTS.md")) found.push(rel("AGENTS.md"));
43
- if (present("CLAUDE.local.md")) found.push(rel("CLAUDE.local.md"));
44
- for (const name of ["ONECODE.md", "onecode.md", "One Code.md"]) {
45
- if (present(name)) {
46
- found.push(rel(name));
47
- break;
48
- }
49
- }
50
- if (dir === stop) break;
51
- const parent = dirname(dir);
52
- if (parent === dir) break;
53
- dir = parent;
54
- }
55
- return found;
35
+ export function contextFileNames(cwd: string, home: string = os.homedir()): string[] {
36
+ return projectInstructionFiles({ cwd, home, homeOneCodeDir: oneCodeStateDir(process.env, home) }).map((path) => relative(cwd, path) || basename(path));
56
37
  }
57
38
 
58
39
  /**
59
- * Skills across the same sources our extensions feed to pi: project/user
60
- * Claude Code dirs, pi's own user dir, and installed plugins. An entry counts
61
- * when <dir>/<name>/SKILL.md exists — existsSync follows symlinked skill
62
- * directories, which readdir's isDirectory() would miss.
40
+ * Skills across the same sources our extensions feed to pi (lib/skill-scan.ts
41
+ * scanSkills: pi's own user dir, the mode's skill folders, the bundled
42
+ * catalog, installed plugins), each name once: the set `/skills` lists and
43
+ * `/doctor` counts.
63
44
  */
64
- export function skillNames(cwd: string, home: string, agentDir: string): string[] {
65
- const dirs = [
66
- join(cwd, ".claude", "skills"),
67
- join(claudeUserDir(home), "skills"),
68
- join(agentDir, "skills"),
69
- ];
70
- const names = new Set<string>();
71
- for (const dir of dirs) {
72
- if (!existsSync(dir)) continue;
73
- try {
74
- for (const entry of readdirSync(dir)) {
75
- if (existsSync(join(dir, entry, "SKILL.md"))) names.add(entry);
76
- }
77
- } catch {
78
- // Unreadable dir: skip, same as pi would.
79
- }
80
- }
81
- for (const skill of discoverPlugins(defaultDiscoverRoots(agentDir, cwd, home)).skills) {
82
- names.add(skill.name);
83
- }
84
- return [...names].sort((a, b) => a.localeCompare(b));
45
+ export function skillNames(cwd: string, home: string, agentDir: string, bundledDir: string = BUNDLED_SKILLS_DIR): string[] {
46
+ const plugins = discoverPlugins(defaultDiscoverRoots(agentDir, cwd, home)).skills;
47
+ return [...new Set(scanSkills(cwd, home, agentDir, plugins, bundledDir).map((skill) => skill.name))].sort((a, b) => a.localeCompare(b));
85
48
  }
86
49
 
87
- /** Saved workflow names from the Claude Code layout dirs (project shadows user). */
50
+ /** Saved workflow names from the mode's workflow dirs (project shadows user). */
88
51
  export function workflowNames(cwd: string, home: string): string[] {
89
52
  const names = new Set<string>();
90
- for (const dir of [join(cwd, ".claude", "workflows"), join(claudeUserDir(home), "workflows")]) {
53
+ for (const dir of [join(projectConfigDir(cwd), "workflows"), join(userConfigDir(home), "workflows")]) {
91
54
  if (!existsSync(dir)) continue;
92
55
  try {
93
56
  for (const entry of readdirSync(dir)) {
@@ -146,20 +109,19 @@ export function shouldDefaultFlushOutputPad(settingsRaw: string | undefined): bo
146
109
  }
147
110
  }
148
111
 
149
- /** True when pi's own startup listing is silenced, so ours should render instead. */
150
- export function quietStartupEnabled(piSettingsPath: string): boolean {
151
- try {
152
- const settings = JSON.parse(readFileSync(piSettingsPath, "utf8"));
153
- return settings?.quietStartup === true;
154
- } catch {
155
- return false;
156
- }
112
+ /**
113
+ * True when pi's own startup listing is silenced, so ours should render instead:
114
+ * `quietStartup: true`, or pi 1.0's `"header"`, which keeps pi's header and
115
+ * still hides the listing. The caller supplies pi's effective, merged value.
116
+ */
117
+ export function quietStartupEnabled(value: unknown): boolean {
118
+ return value === true || value === "header";
157
119
  }
158
120
 
159
- export function collectStartupSections(cwd: string, home: string, packageThemesDir: string, agentDir: string): StartupSection[] {
121
+ export function collectStartupSections(cwd: string, home: string, packageThemesDir: string, agentDir: string, bundledSkillsDir: string = BUNDLED_SKILLS_DIR): StartupSection[] {
160
122
  const sections: StartupSection[] = [
161
- { label: "context", items: contextFileNames(cwd) },
162
- { label: "skills", items: skillNames(cwd, home, agentDir) },
123
+ { label: "context", items: contextFileNames(cwd, home) },
124
+ { label: "skills", items: skillNames(cwd, home, agentDir, bundledSkillsDir) },
163
125
  { label: "workflows", items: workflowNames(cwd, home) },
164
126
  { label: "themes", items: themeNames(packageThemesDir) },
165
127
  ];