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,62 @@
1
+ /**
2
+ * Thinking removed from the turns a compaction keeps. Pure: no pi imports.
3
+ *
4
+ * On Fable 5.1, Opus 5.5 and Sonnet 5.5 a signed thinking block is bound to
5
+ * the conversation before it, and a compaction rewrites that conversation:
6
+ * the kept reply's thinking fails the check on every later request (a 400 on
7
+ * accounts created from 2026-08-31; dropped silently under pi-ai 0.99.2's
8
+ * `drop_block`; findings §46). Blocks may be removed from the start, so the
9
+ * kept turns go out without theirs, from the first request after the
10
+ * compaction on, the same bytes every time. Thinking produced after the
11
+ * compaction binds to that stripped history and stays.
12
+ *
13
+ * The kept turns are the assistant messages older than the latest compaction
14
+ * entry on the session branch (`lib/compaction-boundary.ts`): every message
15
+ * produced since is newer. Text and tool calls stay.
16
+ */
17
+
18
+ /** APIs whose replayed thinking carries a signature the provider checks (pi-ai's converters). */
19
+ const SIGNED_THINKING_APIS = new Set(["anthropic-messages", "bedrock-converse-stream"]);
20
+
21
+ type ContextMessage = { role: string; timestamp?: number; content?: unknown };
22
+
23
+ /**
24
+ * The messages with every thinking block (redacted ones included) removed from
25
+ * assistant messages older than `compactionTime`, or undefined when nothing
26
+ * changes: another API, no compaction, or no kept thinking. An assistant
27
+ * message left empty is skipped by pi-ai's converter, as any empty one is.
28
+ */
29
+ export function withoutKeptThinking<M extends ContextMessage>(
30
+ messages: readonly M[],
31
+ api: string | undefined,
32
+ compactionTime: number | undefined,
33
+ ): M[] | undefined {
34
+ if (!signsThinking(api) || compactionTime === undefined || Number.isNaN(compactionTime)) return undefined;
35
+ return stripThinking(messages, (message) => typeof message.timestamp === "number" && message.timestamp < compactionTime);
36
+ }
37
+
38
+ /**
39
+ * The messages with every assistant message's thinking removed, for a request
40
+ * whose system prompt and tools are not the session's (the standalone
41
+ * compaction request): none of its signed blocks would pass the check. The
42
+ * messages unchanged on other APIs.
43
+ */
44
+ export function withoutThinking<M extends ContextMessage>(messages: M[], api: string | undefined): M[] {
45
+ return (signsThinking(api) && stripThinking(messages, () => true)) || messages;
46
+ }
47
+
48
+ /** Whether requests on `api` carry signed thinking the provider checks. */
49
+ export const signsThinking = (api: string | undefined): boolean => api !== undefined && SIGNED_THINKING_APIS.has(api);
50
+
51
+ /** The messages with thinking removed from the assistant messages `applies` picks, or undefined when none had any. Copies only on a change. */
52
+ function stripThinking<M extends ContextMessage>(messages: readonly M[], applies: (message: M) => boolean): M[] | undefined {
53
+ let result: M[] | undefined;
54
+ messages.forEach((message, i) => {
55
+ if (message.role !== "assistant" || !Array.isArray(message.content) || !message.content.some(isThinking) || !applies(message)) return;
56
+ result ??= messages.slice();
57
+ result[i] = { ...message, content: message.content.filter((block) => !isThinking(block)) };
58
+ });
59
+ return result;
60
+ }
61
+
62
+ const isThinking = (block: unknown): boolean => (block as { type?: unknown } | null)?.type === "thinking";
@@ -4,15 +4,17 @@
4
4
  * COMPACTION_INSTRUCTION matches Claude Code's: appended as a user text block
5
5
  * after the full conversation, the model answers with an <analysis> block
6
6
  * followed by a <summary> block, and only the <summary> content becomes the
7
- * surviving context. Auto-compaction uses the same prompt.
7
+ * surviving context. Auto-compaction uses the same prompt. Two lines end in a
8
+ * space, as Claude Code's do; they are written `\x20` so editors keep them.
8
9
  *
9
10
  * Claude Code runs the call on the *session's own model* with max_tokens
10
- * 32000, keeping the system prompt, tools, and message prefix intact — so the
11
- * provider prompt cache pays for most of the compaction call. The extension
12
- * does the same.
11
+ * 128000 (findings §47), keeping the system prompt, tools, and message
12
+ * prefix intact — so the provider prompt cache pays for most of the compaction
13
+ * call. The extension does the same; the cap is lowered to the model's output
14
+ * limit and to the room the context window leaves.
13
15
  */
14
16
 
15
- export const COMPACTION_MAX_TOKENS = 32_000;
17
+ export const COMPACTION_MAX_TOKENS = 128_000;
16
18
 
17
19
  export const COMPACTION_INSTRUCTION = `CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.
18
20
 
@@ -87,7 +89,7 @@ Here's an example of how your output should be structured:
87
89
  5. Problem Solving:
88
90
  [Description of solved problems and ongoing troubleshooting]
89
91
 
90
- 6. All user messages:
92
+ 6. All user messages:\x20
91
93
  - [Detailed non tool use user message]
92
94
  - [...]
93
95
 
@@ -105,7 +107,7 @@ Here's an example of how your output should be structured:
105
107
  </summary>
106
108
  </example>
107
109
 
108
- Please provide your summary based on the conversation so far, following this structure and ensuring precision and thoroughness in your response.
110
+ Please provide your summary based on the conversation so far, following this structure and ensuring precision and thoroughness in your response.\x20
109
111
 
110
112
  There may be additional summarization instructions provided in the included context. If so, remember to follow these instructions when creating the above summary. Examples of instructions include:
111
113
  <example>
@@ -138,7 +140,7 @@ export function buildCompactionInstruction(options: {
138
140
  * says so, so the summary covers the part that is actually discarded
139
141
  * instead of re-telling what the model will still see in full.
140
142
  */
141
- keptTail?: { count: number; opening?: string };
143
+ keptTail?: { count: number; landmark?: string };
142
144
  }): string {
143
145
  const notice =
144
146
  options.reason === "manual"
@@ -155,11 +157,12 @@ export function buildCompactionInstruction(options: {
155
157
 
156
158
  /**
157
159
  * The scope note for pi's kept tail: the summary replaces only what precedes
158
- * it. Quoting how the first kept message opens gives the model a landmark it
159
- * can find in the transcript, since a bare count is easy to miscount.
160
+ * it. Naming the first kept message (how it opens, or the tool it calls) gives
161
+ * the model a landmark it can find in the transcript, since a bare count is
162
+ * easy to miscount.
160
163
  */
161
- export function keptTailNote(tail: { count: number; opening?: string }): string {
162
- const landmark = tail.opening?.trim() ? `, beginning with the message that opens "${tail.opening.trim()}"` : "";
164
+ export function keptTailNote(tail: { count: number; landmark?: string }): string {
165
+ const landmark = tail.landmark?.trim() ? `, beginning with ${tail.landmark.trim()}` : "";
163
166
  return ` Only the earlier part of the conversation is being summarized: the final ${tail.count} ${
164
167
  tail.count === 1 ? "message" : "messages"
165
168
  }${landmark}, stay in context verbatim after the summary. Do not summarize them; cover everything before them, and use them only to judge which earlier details still matter.`;
@@ -32,17 +32,31 @@ function finite(n: number | null | undefined): number | undefined {
32
32
  * from; `left` takes the size now and returns what remains of the budget. The
33
33
  * value never rises within a turn (as CC's does not), the first known size
34
34
  * becomes the baseline when the turn started without an estimate, and an
35
- * unknown size repeats the last value.
35
+ * unknown size repeats the last value. A compaction inside the turn shrinks
36
+ * the context below the baseline, so `rebase` measures growth from the
37
+ * smaller context on top of what the turn had already spent; without it the
38
+ * countdown stood still until the context regrew past the turn's start.
36
39
  */
37
40
  export class TurnBudget {
38
41
  private start: number | undefined;
42
+ /** Spent since `start`. */
39
43
  private spent = 0;
44
+ /** Spent before the last rebase. */
45
+ private banked = 0;
40
46
 
41
47
  constructor(readonly budget: number) {}
42
48
 
43
49
  startTurn(contextTokens: number | null | undefined): void {
44
50
  this.start = finite(contextTokens);
45
51
  this.spent = 0;
52
+ this.banked = 0;
53
+ }
54
+
55
+ /** Measure from `contextTokens` (or the next known size) on, keeping what the turn spent so far. */
56
+ rebase(contextTokens: number | null | undefined): void {
57
+ this.banked += this.spent;
58
+ this.spent = 0;
59
+ this.start = finite(contextTokens);
46
60
  }
47
61
 
48
62
  left(contextTokens: number | null | undefined): number {
@@ -51,7 +65,7 @@ export class TurnBudget {
51
65
  if (this.start === undefined) this.start = now;
52
66
  this.spent = Math.max(this.spent, now - this.start);
53
67
  }
54
- return Math.max(0, this.budget - this.spent);
68
+ return Math.max(0, this.budget - this.banked - this.spent);
55
69
  }
56
70
  }
57
71
 
@@ -1,31 +1,37 @@
1
1
  /**
2
2
  * context-budget extension — Claude Code's `<total_tokens>N tokens left</total_tokens>`
3
- * line, in the three places CC puts it (budget.ts says what the number is):
3
+ * line, in the places CC puts it (budget.ts says what the number is). It
4
+ * stores the line in One Code's own way; system-reminder's payload hook turns
5
+ * the stored line into Claude Code's per-model shapes on the wire
6
+ * (lib/turn-budget-layout.ts):
4
7
  *
5
- * - the end of every user message: the constant budget, a raw `sticky-append`
6
- * reminder keyed once per session (`since: 0`, so a resumed session's earlier
7
- * user messages carry it too — byte-identical to what they carried before);
8
+ * - the first prompt: the constant budget in the first-message context stack
9
+ * (CONTEXT_ORDER.totalTokens), so it joins the mid-conversation system
10
+ * message where there is one;
11
+ * - every later user message: the constant budget as a raw marker, a `sticky-append`
12
+ * reminder keyed once per session (`since: 0`: every user message a request
13
+ * sends carries it, the first prompt excepted);
8
14
  * - every tool result: the countdown, a RAW `last-append` one-shot queued at
9
- * `tool_result` time and written into the stored result by system-reminder
10
- * (so it persists in the session like CC's and no later request re-caches the
11
- * message). That is why this extension sits BEFORE `system-reminder` in the
12
- * package manifest — pi runs `tool_result` handlers in load order, and the
13
- * block must be queued before system-reminder's handler takes the one-shots.
14
- * It emits only at runtime, never at load, so the "listeners load first" rule
15
- * for the bus is not at stake;
15
+ * `tool_result` time and bound to its call's id, so it rides that result on
16
+ * the next request (pi runs a parallel batch's `tool_result` hooks
17
+ * concurrently; unbound, every countdown would land on the batch's last
18
+ * result). The request that carries it records it (extensions/ledger), so no
19
+ * later request re-renders it;
16
20
  * - the system prompt, before the gitStatus block — appended by the
17
21
  * system-prompt extension from the same pure module.
18
22
  *
19
23
  * A turn starts at the first `agent_start` after a settle (whoever opened it: a
20
24
  * prompt or a harness notification) and its baseline is pi's context estimate
21
- * at that moment. CC_TOTAL_TOKENS=0 turns all three off.
25
+ * at that moment; a compaction rebases it (budget.ts). CC_TOTAL_TOKENS=0 turns
26
+ * all three off.
22
27
  */
23
28
 
24
29
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
25
- import { REMINDER_CHANNEL, type ReminderPayload } from "../lib/reminders.ts";
30
+ import { CONTEXT_ORDER, REMINDER_CHANNEL, type ReminderPayload } from "../lib/reminders.ts";
26
31
  import { totalTokensBlock, TurnBudget, turnTokenBudget } from "./budget.ts";
27
32
 
28
33
  const USER_MESSAGE_KEY = "total-tokens";
34
+ const FIRST_PROMPT_KEY = "total-tokens-first";
29
35
 
30
36
  export default function contextBudgetExtension(pi: ExtensionAPI) {
31
37
  const enabled = () => process.env.CC_TOTAL_TOKENS !== "0";
@@ -38,11 +44,18 @@ export default function contextBudgetExtension(pi: ExtensionAPI) {
38
44
  if (!enabled()) return;
39
45
  pi.events.emit(REMINDER_CHANNEL, {
40
46
  text: totalTokensBlock(budget.budget),
41
- scope: "every-turn",
47
+ key: FIRST_PROMPT_KEY,
48
+ placement: "first-prepend",
49
+ order: CONTEXT_ORDER.totalTokens,
50
+ } satisfies ReminderPayload);
51
+ pi.events.emit(REMINDER_CHANNEL, {
52
+ text: totalTokensBlock(budget.budget),
42
53
  key: USER_MESSAGE_KEY,
43
54
  placement: "sticky-append",
44
55
  raw: true,
45
56
  since: 0,
57
+ // The first prompt carries the line in the context stack instead.
58
+ skipStackCarrier: true,
46
59
  } satisfies ReminderPayload);
47
60
  });
48
61
 
@@ -54,13 +67,20 @@ export default function contextBudgetExtension(pi: ExtensionAPI) {
54
67
  pi.on("agent_settled", () => {
55
68
  busy = false;
56
69
  });
70
+ // A compaction (an auto one mid-turn, an overflow retry) drops the context
71
+ // below the turn's baseline; pi knows its new size only after the next reply,
72
+ // so the first size it reports becomes the baseline.
73
+ pi.on("session_compact", (_event, ctx) => {
74
+ budget.rebase(ctx.getContextUsage()?.tokens);
75
+ });
57
76
 
58
- pi.on("tool_result", (_event, ctx) => {
77
+ pi.on("tool_result", (event, ctx) => {
59
78
  if (!enabled()) return;
60
79
  pi.events.emit(REMINDER_CHANNEL, {
61
80
  text: totalTokensBlock(budget.left(ctx.getContextUsage()?.tokens)),
62
81
  placement: "last-append",
63
82
  raw: true,
83
+ toolCallId: event.toolCallId,
64
84
  } satisfies ReminderPayload);
65
85
  });
66
86
  }
@@ -38,9 +38,8 @@
38
38
  * for an anthropic-messages endpoint you have confirmed accepts it.
39
39
  */
40
40
 
41
- import { readFileSync, statSync } from "node:fs";
42
- import { join } from "node:path";
43
- import { type ExtensionAPI, getAgentDir } from "@earendil-works/pi-coding-agent";
41
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
42
+ import { isAnthropicOAuth } from "../lib/anthropic-auth.ts";
44
43
  import { looksLikeAnthropicRequest } from "../lib/anthropic-payload.ts";
45
44
  import { CACHE_RETENTION_ENV, mainSessionCacheRetention } from "../lib/cache-retention.ts";
46
45
 
@@ -59,11 +58,20 @@ const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
59
58
  // "fallbacks: Extra inputs are not permitted" (verified live, api.anthropic.com
60
59
  // 2026-09-01). Mirrors pi's shouldUseServerSideFallbackBeta.
61
60
  const SERVER_SIDE_FALLBACK_BETA = "server-side-fallback-2026-07-01";
61
+ // The same trap for models whose compat carries `supportsMidConvoEffort` (Opus 5,
62
+ // Opus 5.5, Fable 5.1): pi inserts `role: "system"` messages holding an
63
+ // `output_config`, and without these two betas the API 400s with
64
+ // "messages.1.output_config: Extra inputs are not permitted" (verified live,
65
+ // 2026-09-23). `test/unit/context-management.test.ts` fails when the installed
66
+ // pi-ai declares a beta this list does not account for.
67
+ const MID_CONVERSATION_OUTPUT_CONFIG_BETA = "mid-conversation-output-config-2026-07-01";
68
+ const THINKING_BINDING_CONTROLS_BETA = "thinking-binding-controls-2026-08-01";
62
69
 
63
70
  export interface AnthropicModelCompat {
64
71
  forceAdaptiveThinking?: boolean;
65
72
  supportsEagerToolInputStreaming?: boolean;
66
73
  allowedFallbackModels?: unknown[];
74
+ supportsMidConvoEffort?: boolean;
67
75
  }
68
76
 
69
77
  /** pi's beta list for this model/auth, with the context-management beta appended. */
@@ -75,6 +83,7 @@ export function anthropicBetas(oauth: boolean, compat: AnthropicModelCompat | un
75
83
  if (compat?.forceAdaptiveThinking !== true) betas.push(INTERLEAVED_THINKING_BETA);
76
84
  // pi puts a `fallbacks` body field on these models; the beta must ride along.
77
85
  if ((compat?.allowedFallbackModels?.length ?? 0) > 0) betas.push(SERVER_SIDE_FALLBACK_BETA);
86
+ if (compat?.supportsMidConvoEffort === true) betas.push(MID_CONVERSATION_OUTPUT_CONFIG_BETA, THINKING_BINDING_CONTROLS_BETA);
78
87
  betas.push(CONTEXT_MANAGEMENT_BETA);
79
88
  return betas.join(",");
80
89
  }
@@ -83,9 +92,16 @@ export function anthropicBetas(oauth: boolean, compat: AnthropicModelCompat | un
83
92
  // tool-search); re-exported so existing importers keep working.
84
93
  export { looksLikeAnthropicRequest } from "../lib/anthropic-payload.ts";
85
94
 
86
- /** The edit is rejected unless thinking is enabled or the model is adaptive. */
95
+ /**
96
+ * The edit is rejected unless thinking is on: enabled or adaptive in the
97
+ * request, or left to an adaptive model's default. A request that turns
98
+ * thinking off (`{ type: "disabled" }`, "off" effort on Opus 5 and Haiku 5.5)
99
+ * takes no edit, adaptive model or not (round-2 review H3).
100
+ */
87
101
  export function clearThinkingApplies(payload: Record<string, unknown>, forceAdaptiveThinking: boolean): boolean {
88
- return payload.thinking !== undefined || forceAdaptiveThinking;
102
+ const type = (payload.thinking as { type?: unknown } | undefined)?.type;
103
+ if (type === undefined) return payload.thinking === undefined && forceAdaptiveThinking;
104
+ return type === "enabled" || type === "adaptive";
89
105
  }
90
106
 
91
107
  export function withClearThinking(payload: Record<string, unknown>): Record<string, unknown> {
@@ -99,29 +115,6 @@ export function withClearThinking(payload: Record<string, unknown>): Record<stri
99
115
  };
100
116
  }
101
117
 
102
- /** mtime cache: this runs on every provider request, the hottest path there is. */
103
- let authCache: { mtimeMs: number; oauth: boolean } | undefined;
104
-
105
- /** OAuth logins need pi's identity betas kept in the header we overwrite. */
106
- export function isAnthropicOAuth(): boolean {
107
- // getAgentDir() honours PI_CODING_AGENT_DIR, so an isolated one-code app
108
- // reads its own auth.json rather than ~/.pi's.
109
- const path = join(getAgentDir(), "auth.json");
110
- try {
111
- const mtimeMs = statSync(path).mtimeMs;
112
- const cached = authCache;
113
- if (cached && cached.mtimeMs === mtimeMs) return cached.oauth;
114
- const auth = JSON.parse(readFileSync(path, "utf8"));
115
- const entry = auth?.anthropic;
116
- const oauth = entry?.type === "oauth" || typeof entry?.refresh === "string";
117
- authCache = { mtimeMs, oauth };
118
- return oauth;
119
- } catch {
120
- authCache = undefined;
121
- return false;
122
- }
123
- }
124
-
125
118
  interface AnthropicishModel {
126
119
  api?: string;
127
120
  provider?: string;
@@ -141,6 +134,21 @@ export function clearThinkingEnabled(flag: string | undefined, model: Anthropici
141
134
  return model.provider === "anthropic" && (model.baseUrl ?? "").includes("api.anthropic.com");
142
135
  }
143
136
 
137
+ /**
138
+ * The headers a side call on the session model needs so its request matches the
139
+ * session's: the auth headers plus, where clear_thinking is on, the beta header
140
+ * the session's requests carry (completeSimple bypasses our header hook).
141
+ */
142
+ export function sessionRequestHeaders<H extends Record<string, string | null>>(
143
+ model: { api?: string; provider?: string; baseUrl?: string; compat?: unknown } | undefined,
144
+ headers: H | undefined,
145
+ ): H | Record<string, string | null> | undefined {
146
+ // compat is a provider union; clearThinkingEnabled only passes Anthropic models.
147
+ const anthropic = model as AnthropicishModel | undefined;
148
+ if (!clearThinkingEnabled(process.env.CC_CLEAR_THINKING, anthropic)) return headers;
149
+ return { ...headers, "anthropic-beta": anthropicBetas(isAnthropicOAuth(), anthropic?.compat) };
150
+ }
151
+
144
152
  export default function contextManagementExtension(pi: ExtensionAPI) {
145
153
  const flag = () => process.env.CC_CLEAR_THINKING;
146
154
 
@@ -7,8 +7,6 @@
7
7
  * MCP servers reachable, what external programs are missing — then the issues.
8
8
  */
9
9
 
10
- import { dirname, join } from "node:path";
11
- import { fileURLToPath } from "node:url";
12
10
  import type { Api, Model } from "@earendil-works/pi-ai";
13
11
  import { extensionVersion } from "../lib/package-version.ts";
14
12
  import { piVersionWarning, TESTED_PI_MAX_EXCLUSIVE, TESTED_PI_MIN } from "../lib/pi-version.ts";
@@ -20,6 +18,10 @@ import { collectCompat, importedConfigSection, mcpSection } from "./compat.ts";
20
18
  import { checkDependencies, dependenciesSection, type ShellsInput } from "./dependencies.ts";
21
19
  import { readSettingsEnv } from "../lib/claude-settings.ts";
22
20
  import { resolveBashSpawn, resolvePowerShellSpawn } from "../lib/shell-spawn.ts";
21
+ import { upgradeCommandFor } from "../lib/update-check.mjs";
22
+ import { replacedBuiltinsFix } from "../lib/replaced-builtins.mjs";
23
+ import { keepWindowFix } from "../lib/compaction-keep.mjs";
24
+ import { configCommand } from "./builtins.ts";
23
25
  import { shellToolPolicy } from "../powershell/policy.ts";
24
26
  import { collectModelFacts, modelsSection } from "./models.ts";
25
27
  import { computePresets, presetsSection } from "./presets.ts";
@@ -35,8 +37,8 @@ import {
35
37
  type SessionView,
36
38
  shortenHome,
37
39
  } from "./report.ts";
38
-
39
- export const BUNDLED_AGENTS_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "agents");
40
+ import { MODE_LABELS } from "../lib/config-mode.ts";
41
+ import { BUNDLED_AGENTS_DIR } from "../subagents/agents.ts";
40
42
 
41
43
  /** The environment variables a first-time user is most likely to already have; hinted when nothing is configured. */
42
44
  export const COMMON_KEY_ENV_VARS = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "OPENROUTER_API_KEY", "OPENCODE_API_KEY"];
@@ -60,14 +62,21 @@ export function installationSection(env: DoctorEnvironment, findings: Finding[])
60
62
  lines.push({ text: `Node ${env.nodeVersion} · ${env.platform}-${env.arch}`, level: "dim" });
61
63
  lines.push({ text: `pi agent dir: ${shortenHome(env.agentDir, env.home)} (auth, models, sessions, pi settings)`, level: "dim" });
62
64
  lines.push({ text: `One Code state: ${shortenHome(env.stateDir, env.home)} (own settings, plans)`, level: "dim" });
63
- const claudeDir = env.env.CLAUDE_CONFIG_DIR ? `${env.env.CLAUDE_CONFIG_DIR} (CLAUDE_CONFIG_DIR)` : shortenHome(`${env.home}/.claude`, env.home);
64
- lines.push({ text: `Claude Code config read from: ${claudeDir} (never written)`, level: "dim" });
65
+ lines.push({ text: `Config sources: ${MODE_LABELS[env.configMode]} (switch in /memory)`, level: "dim" });
66
+ if (env.configMode === "independent") {
67
+ lines.push({ text: "Claude Code config: not read (~/.claude, .claude/, CLAUDE.md, ~/.claude.json, managed settings)", level: "dim" });
68
+ } else {
69
+ const claudeDir = env.env.CLAUDE_CONFIG_DIR ? `${env.env.CLAUDE_CONFIG_DIR} (CLAUDE_CONFIG_DIR)` : shortenHome(`${env.home}/.claude`, env.home);
70
+ lines.push({ text: `Claude Code config read from: ${claudeDir} (never written)`, level: "dim" });
71
+ }
65
72
 
66
73
  const versionWarning = piVersionWarning(env.piVersion);
67
74
  if (versionWarning) {
68
75
  lines.push({ text: `pi ${env.piVersion} is outside the tested range ${TESTED_PI_MIN} – <${TESTED_PI_MAX_EXCLUSIVE}`, level: "warn" });
69
76
  findings.push({ level: "warn", text: versionWarning, fix: env.install === "app" ? "Upgrade One Code (it pins a tested pi)." : "Update one-code-extension, or pin pi inside the tested range." });
70
77
  }
78
+ replacedBuiltinsLines(env, lines, findings);
79
+ compactionKeepLines(env, lines, findings);
71
80
 
72
81
  if (env.latest) {
73
82
  switch (env.latest.status) {
@@ -76,7 +85,7 @@ export function installationSection(env: DoctorEnvironment, findings: Finding[])
76
85
  break;
77
86
  case "behind":
78
87
  lines.push({
79
- text: `Updates: ${env.latest.version} is available (you have ${env.oneCodeVersion}) — ${env.install === "app" ? "npm install -g @one-ai/one-code" : "pi update"}`,
88
+ text: `Updates: ${env.latest.version} is available (you have ${env.oneCodeVersion}) — ${upgradeCommandFor(env.install, env.env)}`,
80
89
  level: "warn",
81
90
  });
82
91
  break;
@@ -90,6 +99,40 @@ export function installationSection(env: DoctorEnvironment, findings: Finding[])
90
99
  return { title: "Installation", lines };
91
100
  }
92
101
 
102
+ /** pi 0.99's built-in tool search and MCP, which ours replace: off, or still loaded with the fix. */
103
+ function replacedBuiltinsLines(env: DoctorEnvironment, lines: ReportLine[], findings: Finding[]): void {
104
+ const view = env.replacedBuiltins;
105
+ if (!view) return;
106
+ if (view.left.length === 0) {
107
+ lines.push({ text: "pi's built-in tool-search and mcp: off (One Code provides its own)", level: "dim" });
108
+ return;
109
+ }
110
+ const names = view.left.map((builtin) => builtin.name).join(" and ");
111
+ lines.push({ text: `pi's built-in ${names}: still on, so pi warns at every start`, level: "warn" });
112
+ findings.push({
113
+ level: "warn",
114
+ text: `pi skips its built-in ${names} because One Code provides its own, and warns about it at every start, advising you to remove One Code. Keep One Code; turning the built-in off silences the warning.`,
115
+ fix: replacedBuiltinsFix(view.left, view.paths, configCommand(env.install)),
116
+ });
117
+ }
118
+
119
+ /** pi's compaction keep window: 0, or above 0 with the fix (lib/compaction-keep.mjs). */
120
+ function compactionKeepLines(env: DoctorEnvironment, lines: ReportLine[], findings: Finding[]): void {
121
+ const view = env.compactionKeep;
122
+ if (!view) return;
123
+ if (view.value === 0) {
124
+ lines.push({ text: "pi's compaction keep window: 0 (One Code keeps the last reply, as Claude Code does)", level: "dim" });
125
+ return;
126
+ }
127
+ const where = view.source === "default" ? "pi's default" : `set in the ${view.source} settings${view.model ? ` for ${view.model}` : ""}`;
128
+ lines.push({ text: `pi's compaction keep window: ${view.value} tokens (${where}), so /compact refuses shorter sessions`, level: "warn" });
129
+ findings.push({
130
+ level: "warn",
131
+ text: `One Code keeps only the last reply after a compaction, so pi's keep window of ${view.value} tokens only stops /compact on a session shorter than that.`,
132
+ fix: keepWindowFix(shortenHome(view.source === "project" ? view.paths.project : view.paths.user, env.home), view.model),
133
+ });
134
+ }
135
+
93
136
  export interface ProviderSummary {
94
137
  provider: string;
95
138
  name: string;
@@ -178,7 +221,15 @@ export function buildDoctorReport({ env, registry, session }: BuildInput): Docto
178
221
  const presets = computePresets(registry.available, session.model);
179
222
  sections.push(presetsSection(presets, session.model));
180
223
 
181
- const compat = collectCompat({ cwd: env.cwd, home: env.home, agentDir: env.agentDir, env: env.env, bundledAgentsDir: BUNDLED_AGENTS_DIR });
224
+ const compat = collectCompat({
225
+ cwd: env.cwd,
226
+ home: env.home,
227
+ agentDir: env.agentDir,
228
+ env: env.env,
229
+ bundledAgentsDir: BUNDLED_AGENTS_DIR,
230
+ piConfigDirName: env.piConfigDirName,
231
+ registeredMcpServers: env.registeredMcpServers,
232
+ });
182
233
  findings.push(...compat.findings);
183
234
  sections.push(importedConfigSection(compat, env.home));
184
235
  sections.push(mcpSection(compat, session, env.home));
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Which of pi's built-in extensions that One Code replaces the running pi
3
+ * still loads, read from pi's own settings (lib/replaced-builtins.mjs has the
4
+ * rule). Shared by the startup notice (branding) and `/doctor`, in the
5
+ * session and from `onecode doctor`.
6
+ */
7
+
8
+ import { createRequire } from "node:module";
9
+ import { join } from "node:path";
10
+ import { CONFIG_DIR_NAME, getPackageDir, type SettingsManager } from "@earendil-works/pi-coding-agent";
11
+ import { piHasBuiltinExtensions } from "../lib/pi-version.ts";
12
+ import { type CompactionKeepView, compactionKeepView } from "../lib/compaction-keep.mjs";
13
+ import { BUILTIN_EXTENSIONS_PI, type BuiltinLeftOn, builtinsLeftOn, type GlobMatcher, globMatches } from "../lib/replaced-builtins.mjs";
14
+
15
+ /**
16
+ * pi's own minimatch, the matcher its `!` override entries go through, loaded
17
+ * from pi's install so every glob form (extglobs included) reads as pi reads
18
+ * it. Falls back to the module's port when that copy cannot be loaded (a
19
+ * compiled pi binary, an unusual layout).
20
+ */
21
+ function piGlobMatcher(): GlobMatcher {
22
+ try {
23
+ const { minimatch } = createRequire(join(getPackageDir(), "package.json"))("minimatch") as { minimatch?: unknown };
24
+ if (typeof minimatch === "function") return (pattern, path) => (minimatch as (path: string, pattern: string) => boolean)(path, pattern);
25
+ } catch {
26
+ // pi's copy is not reachable: use the port.
27
+ }
28
+ return globMatches;
29
+ }
30
+
31
+ export interface ReplacedBuiltinsView {
32
+ /** The replaced built-ins pi still loads; empty when the settings turn them all off. */
33
+ left: BuiltinLeftOn[];
34
+ /** The settings files a fix edits. */
35
+ paths: { user: string; project: string };
36
+ }
37
+
38
+ /**
39
+ * The view for a pi with the built-ins, or undefined on an older pi (nothing
40
+ * to report) or when the settings cannot be read (pi reports that itself).
41
+ */
42
+ export function replacedBuiltinsView(
43
+ piVersion: string | undefined,
44
+ settings: () => Pick<SettingsManager, "getGlobalSettings" | "getProjectSettings">,
45
+ paths: { agentDir: string; cwd: string },
46
+ ): ReplacedBuiltinsView | undefined {
47
+ if (!piHasBuiltinExtensions(piVersion, BUILTIN_EXTENSIONS_PI)) return undefined;
48
+ try {
49
+ const manager = settings();
50
+ return {
51
+ left: builtinsLeftOn(manager.getGlobalSettings().extensions, manager.getProjectSettings().extensions, piGlobMatcher()),
52
+ paths: { user: join(paths.agentDir, "settings.json"), project: join(paths.cwd, CONFIG_DIR_NAME, "settings.json") },
53
+ };
54
+ } catch {
55
+ return undefined;
56
+ }
57
+ }
58
+
59
+ /** pi's compaction keep window and the settings files that set it, or undefined when they cannot be read. */
60
+ export function keepView(
61
+ settings: () => Pick<SettingsManager, "getGlobalSettings" | "getProjectSettings">,
62
+ paths: { agentDir: string; cwd: string },
63
+ modelKey?: string,
64
+ ): (CompactionKeepView & { paths: { user: string; project: string } }) | undefined {
65
+ try {
66
+ const manager = settings();
67
+ return {
68
+ ...compactionKeepView(manager.getGlobalSettings(), manager.getProjectSettings(), modelKey),
69
+ paths: { user: join(paths.agentDir, "settings.json"), project: join(paths.cwd, CONFIG_DIR_NAME, "settings.json") },
70
+ };
71
+ } catch {
72
+ return undefined;
73
+ }
74
+ }
75
+
76
+ /** Whether this is the bundled app (its launcher sets `CC_VERSION`) or One Code on the user's own pi. */
77
+ export function installKind(env: NodeJS.ProcessEnv = process.env): "app" | "pi-package" {
78
+ return env.CC_VERSION ? "app" : "pi-package";
79
+ }
80
+
81
+ /** How the user opens pi's config UI: `onecode config` under the bundled app. */
82
+ export function configCommand(install: "app" | "pi-package"): string {
83
+ return install === "app" ? "onecode config" : "pi config";
84
+ }
@@ -11,12 +11,14 @@
11
11
  */
12
12
 
13
13
  import { join } from "node:path";
14
- import { ModelRegistry, ModelRuntime, SettingsManager } from "@earendil-works/pi-coding-agent";
14
+ import { CONFIG_DIR_NAME, ModelRegistry, ModelRuntime, SettingsManager } from "@earendil-works/pi-coding-agent";
15
+ import { keepView, replacedBuiltinsView } from "./builtins.ts";
15
16
  import { oneCodeStateDir } from "../lib/paths.ts";
16
17
  import { loadPermissionSettings } from "../permissions/settings.ts";
17
18
  import { buildDoctorReport } from "./build.ts";
18
19
  import { type DoctorReport, renderDoctorText, type SessionView } from "./report.ts";
19
20
  import { lookupLatestVersion } from "./update-lookup.ts";
21
+ import { configMode } from "../lib/config-mode.ts";
20
22
 
21
23
  export interface DoctorCliOptions {
22
24
  agentDir: string;
@@ -68,6 +70,7 @@ export async function collectDoctorCliReport(options: DoctorCliOptions): Promise
68
70
  home,
69
71
  agentDir,
70
72
  stateDir: oneCodeStateDir(env, home),
73
+ configMode: configMode(),
71
74
  env,
72
75
  platform: process.platform,
73
76
  arch: process.arch,
@@ -75,6 +78,9 @@ export async function collectDoctorCliReport(options: DoctorCliOptions): Promise
75
78
  oneCodeVersion: options.version,
76
79
  install: options.install,
77
80
  piVersion: options.piVersion,
81
+ replacedBuiltins: replacedBuiltinsView(options.piVersion, () => settings, { agentDir, cwd }),
82
+ compactionKeep: keepView(() => settings, { agentDir, cwd }),
83
+ piConfigDirName: CONFIG_DIR_NAME,
78
84
  latest,
79
85
  },
80
86
  registry: {