one-code-extension 0.4.0 → 0.5.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 (419) hide show
  1. package/README.md +219 -219
  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 +32 -23
  7. package/docs/guide/doctor.md +20 -13
  8. package/docs/guide/hooks.md +18 -3
  9. package/docs/guide/installation.md +27 -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 +66 -34
  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 +123 -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 +515 -0
  56. package/extensions/background/index.ts +514 -236
  57. package/extensions/background/loop-fire.ts +136 -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 +52 -0
  63. package/extensions/background/wakeup.ts +159 -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 +88 -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 +229 -71
  77. package/extensions/btw/panel.ts +228 -100
  78. package/extensions/btw/prompt.ts +41 -4
  79. package/extensions/claude-compat/index.ts +7 -11
  80. package/extensions/claude-context/index.ts +446 -58
  81. package/extensions/compaction/cut.ts +157 -0
  82. package/extensions/compaction/index.ts +216 -75
  83. package/extensions/compaction/kept-thinking.ts +62 -0
  84. package/extensions/compaction/prompt.ts +15 -12
  85. package/extensions/context-budget/index.ts +24 -5
  86. package/extensions/context-management/index.ts +25 -0
  87. package/extensions/doctor/build.ts +59 -8
  88. package/extensions/doctor/builtins.ts +84 -0
  89. package/extensions/doctor/cli.ts +7 -1
  90. package/extensions/doctor/compat.ts +88 -23
  91. package/extensions/doctor/dependencies.ts +41 -5
  92. package/extensions/doctor/fix-prompt.ts +9 -2
  93. package/extensions/doctor/index.ts +102 -58
  94. package/extensions/doctor/models.ts +102 -63
  95. package/extensions/doctor/presets.ts +42 -27
  96. package/extensions/doctor/report.ts +19 -2
  97. package/extensions/doctor/viewer.ts +49 -27
  98. package/extensions/effort/index.ts +72 -19
  99. package/extensions/effort/settings.ts +21 -0
  100. package/extensions/effort/slider.ts +24 -20
  101. package/extensions/exit/index.ts +32 -1
  102. package/extensions/file-tracker/index.ts +337 -26
  103. package/extensions/file-tracker/replay.ts +96 -10
  104. package/extensions/file-tracker/restore.ts +63 -0
  105. package/extensions/file-tracker/results.ts +66 -0
  106. package/extensions/file-tracker/shell-reads.ts +211 -0
  107. package/extensions/file-tracker/tracker.ts +32 -15
  108. package/extensions/footer/footer-line.ts +45 -24
  109. package/extensions/footer/index.ts +47 -2
  110. package/extensions/footer/pr.ts +34 -5
  111. package/extensions/hooks/compaction.ts +7 -0
  112. package/extensions/hooks/executor.ts +32 -30
  113. package/extensions/hooks/index.ts +198 -31
  114. package/extensions/hooks/matcher.ts +3 -0
  115. package/extensions/hooks/protocol.ts +41 -3
  116. package/extensions/hooks/settings.ts +50 -19
  117. package/extensions/hooks/subagent-bridge.ts +2 -0
  118. package/extensions/hooks/trust.ts +13 -5
  119. package/extensions/idle-compact/index.ts +119 -0
  120. package/extensions/idle-compact/policy.ts +143 -0
  121. package/extensions/init/index.ts +11 -10
  122. package/extensions/init/prompt.ts +25 -32
  123. package/extensions/interrupted/index.ts +13 -1
  124. package/extensions/kept-thinking/index.ts +27 -0
  125. package/extensions/lib/agent-cron.ts +130 -0
  126. package/extensions/lib/agent-loader.ts +15 -1
  127. package/extensions/lib/agent-view.ts +85 -0
  128. package/extensions/lib/anthropic-payload.ts +82 -1
  129. package/extensions/lib/anthropic-server-call.ts +230 -0
  130. package/extensions/lib/anthropic-server-tools.ts +485 -0
  131. package/extensions/lib/app-launch.mjs +94 -0
  132. package/extensions/lib/argument-hints.ts +190 -0
  133. package/extensions/lib/atomic-write.ts +6 -2
  134. package/extensions/lib/auto-memory.ts +75 -0
  135. package/extensions/lib/bash-parser.ts +84 -0
  136. package/extensions/lib/btw-fork.ts +93 -0
  137. package/extensions/lib/child-extensions.ts +42 -0
  138. package/extensions/lib/child-writes.ts +45 -0
  139. package/extensions/lib/claude-context.ts +515 -100
  140. package/extensions/lib/claude-external-includes.ts +68 -0
  141. package/extensions/lib/claude-id.ts +22 -0
  142. package/extensions/lib/claude-rules.ts +323 -0
  143. package/extensions/lib/claude-settings.ts +76 -4
  144. package/extensions/lib/compaction-boundary.ts +36 -0
  145. package/extensions/lib/compaction-keep.mjs +83 -0
  146. package/extensions/lib/config-mode.ts +112 -0
  147. package/extensions/lib/consent-dialogs.ts +63 -0
  148. package/extensions/lib/consent-preview.ts +5 -1
  149. package/extensions/lib/consent-stores.ts +48 -0
  150. package/extensions/lib/context-facts.ts +78 -0
  151. package/extensions/lib/context-stack.ts +81 -0
  152. package/extensions/lib/deferred.ts +219 -25
  153. package/extensions/lib/dock-rows.ts +60 -0
  154. package/extensions/lib/empty-tool-result.ts +27 -0
  155. package/extensions/lib/environment-block.ts +76 -0
  156. package/extensions/lib/fetch-timeout.ts +24 -6
  157. package/extensions/{system-prompt → lib}/git-status.ts +51 -13
  158. package/extensions/lib/git.ts +75 -13
  159. package/extensions/lib/grammars/LICENSE-tree-sitter-bash +21 -0
  160. package/extensions/lib/grammars/README.md +2 -0
  161. package/extensions/lib/grammars/tree-sitter-bash.wasm +0 -0
  162. package/extensions/lib/guide-docs.ts +45 -0
  163. package/extensions/lib/headless-output.ts +46 -0
  164. package/extensions/lib/hook-gate.ts +7 -7
  165. package/extensions/lib/interrupt.ts +20 -4
  166. package/extensions/lib/key-input.ts +455 -0
  167. package/extensions/lib/keys.ts +14 -1
  168. package/extensions/lib/local-command.ts +47 -13
  169. package/extensions/lib/mcp-overrides.ts +1 -1
  170. package/extensions/lib/mcp-share.ts +46 -0
  171. package/extensions/lib/memory-content.ts +146 -0
  172. package/extensions/lib/memory-index.ts +18 -0
  173. package/extensions/lib/memory.ts +134 -123
  174. package/extensions/lib/model-catalog/huggingface.json +174 -0
  175. package/extensions/lib/model-catalog/models-dev.json +18297 -0
  176. package/extensions/lib/model-catalog/openrouter.json +5252 -0
  177. package/extensions/lib/model-catalog-data.ts +513 -0
  178. package/extensions/lib/model-catalog.ts +462 -0
  179. package/extensions/lib/model-choice-warnings.ts +137 -0
  180. package/extensions/lib/model-pairings.ts +152 -0
  181. package/extensions/{auto-mode → lib}/model-picker.ts +26 -43
  182. package/extensions/lib/model-policy.ts +112 -15
  183. package/extensions/lib/model-tier.ts +283 -355
  184. package/extensions/lib/model-unusable.ts +1 -1
  185. package/extensions/lib/newer-model.ts +100 -0
  186. package/extensions/lib/notices.ts +87 -0
  187. package/extensions/lib/notifications.ts +308 -64
  188. package/extensions/lib/one-code-settings.ts +74 -8
  189. package/extensions/lib/open-browser.ts +63 -0
  190. package/extensions/lib/openrouter-generation.ts +94 -0
  191. package/extensions/lib/operation-deadline.ts +30 -0
  192. package/extensions/lib/original-command.ts +4 -4
  193. package/extensions/lib/package-version.ts +1 -1
  194. package/extensions/lib/panel-focus.ts +134 -0
  195. package/extensions/lib/paths.ts +17 -2
  196. package/extensions/lib/permission-gate.ts +72 -6
  197. package/extensions/lib/persisted-output.ts +60 -8
  198. package/extensions/lib/pi-ai-estimate.ts +19 -3
  199. package/extensions/lib/pi-version.ts +21 -2
  200. package/extensions/lib/plan-mode-channels.ts +20 -5
  201. package/extensions/lib/plugins.ts +26 -17
  202. package/extensions/lib/powershell-parse-script.ts +208 -0
  203. package/extensions/lib/powershell-parser.ts +344 -0
  204. package/extensions/lib/process-tree.ts +131 -8
  205. package/extensions/lib/prompt-options.ts +82 -0
  206. package/extensions/lib/queued-delivery.ts +44 -0
  207. package/extensions/lib/reminders.ts +364 -58
  208. package/extensions/lib/replaced-builtins.mjs +199 -0
  209. package/extensions/lib/replay-call.ts +70 -0
  210. package/extensions/lib/request-replay.ts +439 -0
  211. package/extensions/lib/scratchpad.ts +81 -14
  212. package/extensions/lib/send-now-channel.ts +7 -0
  213. package/extensions/lib/session-model-tier.ts +51 -0
  214. package/extensions/lib/session-work.ts +64 -0
  215. package/extensions/lib/settings-channels.ts +4 -4
  216. package/extensions/lib/shell-exit-semantics.ts +170 -0
  217. package/extensions/lib/shell-quote.ts +11 -0
  218. package/extensions/lib/shell-result.ts +70 -0
  219. package/extensions/lib/shell-spawn.ts +70 -6
  220. package/extensions/lib/shell-tool.ts +75 -25
  221. package/extensions/lib/side-call-cache.ts +124 -0
  222. package/extensions/lib/side-call-run.ts +96 -0
  223. package/extensions/lib/side-call-usage.ts +38 -0
  224. package/extensions/lib/side-call.ts +13 -1
  225. package/extensions/lib/single-flight.ts +18 -0
  226. package/extensions/lib/skill-body.ts +42 -0
  227. package/extensions/lib/skill-scan.ts +63 -24
  228. package/extensions/lib/spill-file.ts +140 -0
  229. package/extensions/lib/subagent-handback.ts +113 -0
  230. package/extensions/lib/system-role.ts +156 -0
  231. package/extensions/lib/terminal-text.ts +114 -0
  232. package/extensions/lib/text-width.ts +47 -16
  233. package/extensions/lib/timer-ops.ts +20 -0
  234. package/extensions/lib/tool-additions.ts +149 -0
  235. package/extensions/lib/tool-call-corruption.ts +134 -0
  236. package/extensions/lib/tool-path.ts +66 -0
  237. package/extensions/lib/tool-variants.ts +69 -0
  238. package/extensions/lib/tui-render.ts +255 -27
  239. package/extensions/lib/turn-budget-layout.ts +143 -0
  240. package/extensions/lib/update-check.mjs +15 -2
  241. package/extensions/lib/usage-bus.ts +1 -1
  242. package/extensions/lib/user-denial.ts +38 -0
  243. package/extensions/lib/workspace-channel.ts +16 -0
  244. package/extensions/lib/worktree-channel.ts +31 -3
  245. package/extensions/lib/worktree-isolation.ts +40 -10
  246. package/extensions/lsp/client.ts +8 -9
  247. package/extensions/lsp/index.ts +70 -4
  248. package/extensions/lsp/keep-alive.ts +1 -1
  249. package/extensions/lsp/trust.ts +119 -0
  250. package/extensions/lsp/watcher.ts +1 -1
  251. package/extensions/mcp/announce.ts +87 -5
  252. package/extensions/mcp/client.ts +161 -48
  253. package/extensions/mcp/config.ts +132 -8
  254. package/extensions/mcp/discovery.ts +19 -0
  255. package/extensions/mcp/index.ts +209 -71
  256. package/extensions/mcp/oauth/browser.ts +38 -17
  257. package/extensions/mcp/oauth/flow.ts +25 -17
  258. package/extensions/mcp/oauth/provider.ts +14 -8
  259. package/extensions/mcp/oauth/store.ts +34 -16
  260. package/extensions/mcp/panel/keys.ts +12 -11
  261. package/extensions/mcp/panel/render.ts +9 -6
  262. package/extensions/mcp/schema.ts +104 -5
  263. package/extensions/mcp/trust.ts +151 -67
  264. package/extensions/memory/entries.ts +23 -14
  265. package/extensions/memory/index.ts +134 -28
  266. package/extensions/memory/open-external.ts +33 -18
  267. package/extensions/memory/panel.ts +135 -26
  268. package/extensions/newer-model/index.ts +31 -0
  269. package/extensions/notebook/description.ts +18 -0
  270. package/extensions/notebook/index.ts +6 -5
  271. package/extensions/notebook/notebook.ts +1 -1
  272. package/extensions/permissions/index.ts +1300 -381
  273. package/extensions/permissions/matcher.ts +425 -74
  274. package/extensions/permissions/modes.ts +6 -4
  275. package/extensions/permissions/panel/host.ts +130 -0
  276. package/extensions/permissions/panel/keys.ts +48 -0
  277. package/extensions/permissions/panel/render.ts +450 -0
  278. package/extensions/permissions/panel/state.ts +550 -0
  279. package/extensions/permissions/powershell-cmdlets.ts +198 -0
  280. package/extensions/permissions/powershell-paths.ts +197 -0
  281. package/extensions/permissions/powershell-rules.ts +207 -280
  282. package/extensions/permissions/powershell-tree.ts +557 -0
  283. package/extensions/permissions/project-trust.ts +27 -11
  284. package/extensions/permissions/protected-paths.ts +14 -2
  285. package/extensions/permissions/session-grant.ts +6 -0
  286. package/extensions/permissions/settings.ts +166 -31
  287. package/extensions/permissions/subagent-gate.ts +25 -0
  288. package/extensions/permissions/workspace.ts +78 -0
  289. package/extensions/plan-mode/index.ts +156 -69
  290. package/extensions/plan-mode/reminder.ts +89 -21
  291. package/extensions/plan-mode/texts.ts +177 -0
  292. package/extensions/plan-mode/viewer.ts +92 -27
  293. package/extensions/plugins/counts.ts +3 -3
  294. package/extensions/plugins/index.ts +61 -46
  295. package/extensions/plugins/install/install.ts +16 -0
  296. package/extensions/plugins/marketplace/sync.ts +9 -3
  297. package/extensions/plugins/marketplace/types.ts +3 -1
  298. package/extensions/plugins/panel/keys.ts +21 -24
  299. package/extensions/plugins/panel/render.ts +12 -6
  300. package/extensions/plugins/shell-expand.ts +107 -0
  301. package/extensions/plugins/template.ts +32 -15
  302. package/extensions/powershell/child.ts +7 -0
  303. package/extensions/powershell/description.ts +38 -6
  304. package/extensions/powershell/guards.ts +1 -1
  305. package/extensions/powershell/index.ts +12 -7
  306. package/extensions/recap/index.ts +65 -60
  307. package/extensions/recap/prompt.ts +2 -2
  308. package/extensions/recap/scheduler.ts +3 -5
  309. package/extensions/search-tools/grep-merge.ts +39 -0
  310. package/extensions/search-tools/index.ts +0 -0
  311. package/extensions/send-now/chord.ts +62 -0
  312. package/extensions/send-now/index.ts +133 -0
  313. package/extensions/session-title/index.ts +3 -0
  314. package/extensions/session-title/title.ts +4 -1
  315. package/extensions/skill/code-review.ts +97 -0
  316. package/extensions/skill/index.ts +421 -101
  317. package/extensions/skill/invoke.ts +128 -18
  318. package/extensions/skill/listing.ts +133 -9
  319. package/extensions/skill/panel/keys.ts +15 -16
  320. package/extensions/skill/panel/render.ts +5 -2
  321. package/extensions/skill/panel/state.ts +12 -1
  322. package/extensions/subagents/agent-args.ts +39 -0
  323. package/extensions/subagents/agent-description.ts +132 -0
  324. package/extensions/subagents/agents.ts +116 -23
  325. package/extensions/subagents/announce.ts +69 -0
  326. package/extensions/subagents/default-model.ts +2 -3
  327. package/extensions/subagents/delegation-steer.ts +4 -4
  328. package/extensions/subagents/fork-cache.ts +76 -0
  329. package/extensions/subagents/guide-agent.ts +189 -0
  330. package/extensions/subagents/hand-back-review.ts +3 -0
  331. package/extensions/subagents/index.ts +1493 -824
  332. package/extensions/subagents/live-runs.ts +26 -6
  333. package/extensions/subagents/model-select.ts +38 -25
  334. package/extensions/subagents/outcome.ts +2 -2
  335. package/extensions/subagents/panel-keys.ts +73 -31
  336. package/extensions/subagents/panel-render.ts +120 -96
  337. package/extensions/subagents/panel-widget.ts +60 -89
  338. package/extensions/subagents/runner.ts +108 -80
  339. package/extensions/subagents/runs.ts +39 -5
  340. package/extensions/subagents/send-to-main-tool.ts +1 -1
  341. package/extensions/subagents/session-turns.ts +32 -8
  342. package/extensions/subagents/shell-panel.ts +36 -178
  343. package/extensions/subagents/tasks-dialog.ts +170 -0
  344. package/extensions/subagents/viewport-mirror.ts +95 -0
  345. package/extensions/subagents/worktree.ts +57 -13
  346. package/extensions/system-prompt/environment.ts +19 -19
  347. package/extensions/system-prompt/idle-turn.ts +65 -0
  348. package/extensions/system-prompt/index.ts +131 -47
  349. package/extensions/system-prompt/template.ts +24 -50
  350. package/extensions/system-prompt/tiers/common.ts +23 -64
  351. package/extensions/system-prompt/tiers/frontier.ts +32 -11
  352. package/extensions/system-prompt/tiers/low.ts +67 -45
  353. package/extensions/system-prompt/tiers/mid.ts +96 -38
  354. package/extensions/system-reminder/index.ts +175 -13
  355. package/extensions/tasks/descriptions.ts +190 -0
  356. package/extensions/tasks/index.ts +120 -41
  357. package/extensions/tasks/store.ts +83 -16
  358. package/extensions/tool-call-corruption/child.ts +7 -0
  359. package/extensions/tool-call-corruption/index.ts +237 -0
  360. package/extensions/tool-search/announce.ts +16 -0
  361. package/extensions/tool-search/index.ts +189 -41
  362. package/extensions/tool-style/index.ts +68 -10
  363. package/extensions/tool-style/write-description.ts +40 -0
  364. package/extensions/tool-style/write-render.ts +237 -0
  365. package/extensions/turn-duration/index.ts +7 -3
  366. package/extensions/turn-duration/line.ts +47 -4
  367. package/extensions/web/backends.ts +6 -9
  368. package/extensions/web/description.ts +50 -0
  369. package/extensions/web/index.ts +118 -53
  370. package/extensions/web/native-call.ts +15 -0
  371. package/extensions/web/native-results.ts +41 -0
  372. package/extensions/web-fetch/description.ts +42 -0
  373. package/extensions/web-fetch/extract.ts +53 -6
  374. package/extensions/web-fetch/index.ts +125 -76
  375. package/extensions/web-fetch/page-content.ts +19 -0
  376. package/extensions/web-fetch/response.ts +49 -0
  377. package/extensions/web-fetch/summarize.ts +9 -10
  378. package/extensions/workflow/agent-session.ts +105 -18
  379. package/extensions/workflow/args.ts +24 -0
  380. package/extensions/workflow/description.ts +67 -0
  381. package/extensions/workflow/globals.ts +17 -3
  382. package/extensions/workflow/index.ts +145 -162
  383. package/extensions/workflow/records.ts +1 -0
  384. package/extensions/workflow/run-manager.ts +29 -6
  385. package/extensions/workflow/saved-workflows.ts +3 -2
  386. package/extensions/workflow/types.ts +22 -1
  387. package/extensions/workflow/viewer.ts +54 -24
  388. package/extensions/workflow/widget.ts +20 -0
  389. package/extensions/worktree/descriptions.ts +91 -0
  390. package/extensions/worktree/guards.ts +316 -54
  391. package/extensions/worktree/index.ts +121 -39
  392. package/extensions/worktree/powershell-guards.ts +167 -0
  393. package/extensions/worktree/rewrite.ts +14 -16
  394. package/package.json +19 -7
  395. package/skills/artifact-design/SKILL.md +85 -0
  396. package/skills/code-review/SKILL.md +20 -20
  397. package/skills/code-review/cells/arguments-and-flags.md +19 -0
  398. package/skills/code-review/cells/high-3x5-recall-verify.md +137 -0
  399. package/skills/code-review/cells/high-8-inline.md +122 -0
  400. package/skills/code-review/cells/low-1-pass-max4.md +27 -0
  401. package/skills/code-review/cells/low-1-pass-min-files-4.md +28 -0
  402. package/skills/code-review/cells/max-5x5-verify-sweep.md +162 -0
  403. package/skills/code-review/cells/medium-3x5-verify.md +132 -0
  404. package/skills/code-review/cells/minimal-prompt.md +32 -0
  405. package/skills/code-review/cells/xhigh-10-inline-sweep.md +149 -0
  406. package/skills/code-review/cells/xhigh-5x5-verify-sweep.md +162 -0
  407. package/skills/fewer-permission-prompts/SKILL.md +1 -1
  408. package/skills/loop/SKILL.md +11 -0
  409. package/skills/security-review/SKILL.md +2 -5
  410. package/skills/simplify/SKILL.md +7 -5
  411. package/skills/workflow-authoring/SKILL.md +143 -0
  412. package/themes/onecode-light.json +1 -1
  413. package/themes/onecode.json +1 -1
  414. package/types/app.d.ts +58 -0
  415. package/types/community-packages.d.ts +26 -1
  416. package/extensions/auto-mode/recoverability.ts +0 -229
  417. package/extensions/lib/capability-index.ts +0 -466
  418. package/extensions/lib/model-facts.generated.json +0 -2675
  419. package/extensions/lib/model-facts.ts +0 -162
@@ -1,18 +1,18 @@
1
1
  /**
2
2
  * User-invoked skill commands (pure). pi registers each skill as a `/skill:<name>`
3
3
  * slash command and, on invocation, expands it into a `<skill>` block that it
4
- * submits as a *user message* — so loading a skill shows up in the transcript as
5
- * a new user turn. One Code intercepts that command in the `input` hook and
6
- * re-delivers the same block as a hidden message instead (see index.ts), so the
7
- * model receives byte-identical content but nothing renders.
4
+ * submits as a *user message*. One Code intercepts that command (and its own
5
+ * bare `/<name>` and typed `/<plugin>:<skill>` forms) and delivers the skill
6
+ * the way Claude Code does: a hidden message holding the command breadcrumb
7
+ * and the skill's text, so nothing renders and no `skill` call is needed.
8
+ * A model's `skill` call gets Claude Code's "Launching skill" result with the
9
+ * same text beside it (see index.ts).
8
10
  *
9
- * These helpers mirror pi's own `_expandSkillCommand`/`formatSkillInvocation`
10
- * exactly (same `/skill:` prefix, same block template) so the model sees the same
11
- * bytes it would have without the interception — only the display changes.
11
+ * pi's own `<skill>` block still reaches a session through pi's native
12
+ * expansion on older pi (steer/followUp skip the `input` hook there), which
13
+ * is why the off-skill redaction below still matches it.
12
14
  */
13
15
 
14
- import { dirname } from "node:path";
15
-
16
16
  const SKILL_PREFIX = "/skill:";
17
17
 
18
18
  /** Parse a `/skill:<name> [args]` command; undefined if it is not one. */
@@ -45,23 +45,121 @@ export function resolveSkill<T extends { name: string }>(all: T[], wanted: strin
45
45
  }
46
46
 
47
47
  /**
48
- * Rebuild the exact `<skill>` block pi's `/skill:` expansion produces. `body` is
49
- * the SKILL.md with frontmatter already stripped and trimmed; `filePath` is the
50
- * skill file (its directory is the base for relative references, as pi does).
48
+ * Claude Code's breadcrumb for a typed slash command, the first text block of
49
+ * the message a typed skill becomes. Its arguments ride `<command-args>` only
50
+ * when there are some.
51
+ */
52
+ export function commandBreadcrumb(name: string, args: string): string {
53
+ return `<command-message>${name}</command-message>\n<command-name>/${name}</command-name>${args ? `\n<command-args>${args}</command-args>` : ""}\n`;
54
+ }
55
+
56
+ // commandBreadcrumb's shape at the start of a message; the arguments may span lines.
57
+ const BREADCRUMB = /^<command-message>[^<\n]*<\/command-message>\n<command-name>(\/[^<\n]*)<\/command-name>(?:\n<command-args>([\s\S]*?)<\/command-args>)?\n/;
58
+
59
+ /**
60
+ * What a user message that opens with commandBreadcrumb shows in the
61
+ * transcript: the command as typed, `/name args`. Claude Code shows a prompt
62
+ * command (a skill, `/init`, `/doctor`) by its command line and keeps the
63
+ * expanded text out of the transcript. `undefined` for any other message.
64
+ */
65
+ export function commandDisplayLine(text: string): string | undefined {
66
+ const match = BREADCRUMB.exec(text);
67
+ if (!match) return undefined;
68
+ return match[2] ? `${match[1]} ${match[2]}` : match[1];
69
+ }
70
+
71
+ /**
72
+ * Claude Code's argument substitution in a skill's text: `$ARGUMENTS`,
73
+ * `$ARGUMENTS[n]` and `$n` (both counted from 0) take the arguments, and a
74
+ * backslash keeps a `$` literal. When nothing was substituted, the arguments
75
+ * follow the text on an `ARGUMENTS:` line.
76
+ */
77
+ export function substituteSkillArguments(text: string, args: string): string {
78
+ if (!args.trim()) return text;
79
+ const parts = args.trim().split(/\s+/);
80
+ let used = false;
81
+ // One pass, so an argument holding `$0` is never substituted again.
82
+ const out = text.replace(/\\\$(?=\d|ARGUMENTS)|\$ARGUMENTS\[(\d+)\]|\$ARGUMENTS|\$(\d+)(?!\w)/g, (match, listed?: string, positional?: string) => {
83
+ if (match.startsWith("\\")) return "$";
84
+ if (match === "$ARGUMENTS") {
85
+ used = true;
86
+ return args;
87
+ }
88
+ const part = parts[Number(listed ?? positional)];
89
+ if (part === undefined) return match;
90
+ used = true;
91
+ return part;
92
+ });
93
+ return used ? out : `${out}\n\nARGUMENTS: ${args}`;
94
+ }
95
+
96
+ /**
97
+ * The text a skill hands the model, as Claude Code builds it: the skill's
98
+ * folder first (`Base directory for this skill: …`, so relative `references/`
99
+ * and `scripts/` resolve), then the body with its arguments. A skill that
100
+ * ships inside One Code, like Claude Code's own, names no folder.
101
+ */
102
+ export function skillPromptText(body: string, args: string, baseDir: string | undefined): string {
103
+ const text = substituteSkillArguments(body, args);
104
+ return baseDir ? `Base directory for this skill: ${baseDir}\n\n${text}` : text;
105
+ }
106
+
107
+ /**
108
+ * The message a typed skill command becomes, as Claude Code sends it: the
109
+ * breadcrumb, then the skill's text, each ending in a newline. Arguments a
110
+ * generated body already carries are not passed again.
51
111
  */
52
- export function buildSkillBlock(skill: { name: string; filePath: string }, body: string, args: string): string {
53
- const block = `<skill name="${skill.name}" location="${skill.filePath}">
54
- References are relative to ${dirname(skill.filePath)}.
112
+ export function typedSkillContent(name: string, typedArgs: string, promptText: string): [string, string] {
113
+ return [commandBreadcrumb(name, typedArgs), promptText.endsWith("\n") ? promptText : `${promptText}\n`];
114
+ }
55
115
 
56
- ${body}
57
- </skill>`;
58
- return args ? `${block}\n\n${args}` : block;
116
+ /**
117
+ * A prompt command (`/init`, `/doctor`, a plugin command) as one user message,
118
+ * in a typed skill's exact bytes: Claude Code sends every prompt command led by
119
+ * its breadcrumb, and the transcript shows it as its command line
120
+ * (commandDisplayLine).
121
+ */
122
+ export function promptCommandText(name: string, args: string, prompt: string): string {
123
+ return typedSkillContent(name, args, prompt).join("\n");
124
+ }
125
+
126
+ /** Claude Code's result for a model's skill call; the skill's text follows it as a second block. */
127
+ export const launchingSkill = (name: string): string => `Launching skill: ${name}`;
128
+
129
+ /**
130
+ * The lines that open and close a skill tool result when the model called a
131
+ * skill that takes arguments without passing any. A skill's text is its
132
+ * instructions, not a manual: a weak model "checking the interface" of
133
+ * `/loop` got the no-argument body, which starts an autonomous loop. A mild
134
+ * opening line lost to that body's "The user invoked /loop with no prompt"
135
+ * on DeepSeek V4.1 Flash; telling it to stop and check, plus a closing
136
+ * reminder, turned it around. Only the model's tool calls get this; a user's
137
+ * bare `/<name>` is deliberate.
138
+ */
139
+ export function missingArgumentsNote(argumentHint: string): { before: string; after: string } {
140
+ return {
141
+ before: `Stop and check before following this. This skill takes arguments (${argumentHint}) and this call passed none, so what follows is its no-argument mode, written as if the user asked for the skill with nothing after it. If the user's request names any of those arguments, do not follow the instructions below: call the skill again with them in \`args\`.`,
142
+ after: "Reminder: those were the no-argument instructions. If the user's request included arguments, call the skill again with them in `args` instead of following them.",
143
+ };
59
144
  }
60
145
 
61
146
  /** Fast pre-check before the regex walk; also the marker `redactOffSkillText` scans for. */
62
147
  const SKILL_BLOCK_START = '<skill name="';
63
148
  const SKILL_BLOCK_RE = /<skill name="([^"]+)"[^>]*>[\s\S]*?<\/skill>/g;
64
149
 
150
+ /**
151
+ * The hidden message a `/skill:` command is delivered as. `details.input` is
152
+ * the text the user typed, so an extension that saw that text at `input` (the
153
+ * hooks extension's UserPromptSubmit context) can find the message that
154
+ * replaced it.
155
+ */
156
+ export const SKILL_INVOCATION_TYPE = "one-code:skill-invocation";
157
+ export interface SkillInvocationDetails {
158
+ skill: string;
159
+ args: string;
160
+ input?: string;
161
+ }
162
+
65
163
  export const offSkillNotice = (name: string): string =>
66
164
  `[Skill "${name}" is turned off — its instructions were removed. The user can re-enable it from /skills or /plugins.]`;
67
165
 
@@ -184,3 +282,15 @@ export function skillCommandCandidates<T extends { name: string; source: string
184
282
  }
185
283
  return out;
186
284
  }
285
+
286
+ /**
287
+ * The `/` suggestions without pi's `/skill:<name>` entry for a skill that also
288
+ * has its bare `/<name>` command, so each skill is listed once, as in Claude
289
+ * Code. Kept when the user is typing `/skill:` themselves, and for a skill
290
+ * whose bare name was skipped (a collision), where `/skill:` is its only form.
291
+ * Typed `/skill:<name>` still runs either way: this only trims the list.
292
+ */
293
+ export function withoutDuplicateSkillCommands<T extends { value: string }>(items: T[], prefix: string, bareSkills: ReadonlySet<string>): T[] {
294
+ if (!prefix.startsWith("/") || prefix.startsWith("/skill:")) return items;
295
+ return items.filter((item) => !(item.value.startsWith("skill:") && bareSkills.has(item.value.slice("skill:".length))));
296
+ }
@@ -2,20 +2,144 @@
2
2
  * The model-facing skills listing (pure). The state decides visibility: "on"
3
3
  * carries name + description, "name-only" just the name (saving context
4
4
  * tokens), "user-only"/"off" are hidden so the model won't auto-trigger them.
5
- * The description goes in whole, newlines included, the way Claude Code lists
6
- * it: a skill written with a YAML block description puts its "Use when…"
7
- * trigger on the later lines, and a first-line-only listing dropped exactly
8
- * the sentence that tells the model when to reach for the skill.
5
+ * A skill whose frontmatter sets `disable-model-invocation: true` is hidden
6
+ * whatever its state: only the user may start it, as in Claude Code.
7
+ *
8
+ * Each line is built the way Claude Code builds it: the description, then
9
+ * " - " and the `when_to_use` frontmatter when there is one, clipped at 1,536
10
+ * characters (1,535 and an ellipsis). The description keeps its newlines: a
11
+ * skill written with a YAML block description puts its "Use when…" trigger on
12
+ * the later lines, and a first-line-only listing dropped exactly the sentence
13
+ * that tells the model when to reach for the skill.
14
+ *
15
+ * The whole listing has a budget, 1% of the context window in characters
16
+ * (`SLASH_COMMAND_TOOL_CHAR_BUDGET` replaces it). Over budget, a bundled skill
17
+ * and a name-only one keep their lines; the others keep theirs by usage rank
18
+ * while the budget lasts and are listed by name after that.
9
19
  */
10
20
 
11
21
  import { type SkillState, skillListingVisibility } from "../lib/skill-overrides.ts";
22
+ import type { UsageEntry } from "../lib/usage-tracker.ts";
12
23
 
13
- export function skillListingText(skills: ReadonlyArray<{ name: string; description?: string; state: SkillState }>): string {
14
- const lines = skills.flatMap((skill) => {
24
+ /** Claude Code's per-entry cap (its `skillListingMaxDescChars` default). */
25
+ export const SKILL_DESCRIPTION_CAP = 1536;
26
+ /** The listing's share of the context window, at 4 characters per token, 200K tokens when the window is unknown. */
27
+ const BUDGET_FRACTION = 0.01;
28
+ const CHARS_PER_TOKEN = 4;
29
+ const DEFAULT_CONTEXT_WINDOW = 200_000;
30
+
31
+ export interface ListedSkill {
32
+ name: string;
33
+ description?: string;
34
+ /** The `when_to_use` frontmatter, appended after " - ". */
35
+ whenToUse?: string;
36
+ state: SkillState;
37
+ disableModelInvocation?: boolean;
38
+ /** Ships inside One Code: keeps its line over budget, as Claude Code's bundled skills do. */
39
+ bundled?: boolean;
40
+ /** The usage score that ranks the line over budget (`usageScore`). */
41
+ usage?: number;
42
+ }
43
+
44
+ /** The text after `- <name>: `, clipped as Claude Code clips it. */
45
+ export function listingDescription(skill: Pick<ListedSkill, "description" | "whenToUse">): string {
46
+ const description = skill.description?.trim() ?? "";
47
+ const whenToUse = skill.whenToUse?.trim();
48
+ const text = whenToUse ? `${description} - ${whenToUse}` : description;
49
+ return text.length > SKILL_DESCRIPTION_CAP ? `${text.slice(0, SKILL_DESCRIPTION_CAP - 1)}…` : text;
50
+ }
51
+
52
+ /** The listing's character budget for a context window (tokens). */
53
+ export function skillListingBudget(contextWindow: number | undefined, env: NodeJS.ProcessEnv = process.env): number {
54
+ const fromEnv = Number.parseInt(env.SLASH_COMMAND_TOOL_CHAR_BUDGET ?? "", 10);
55
+ if (fromEnv > 0) return fromEnv;
56
+ const window = contextWindow && contextWindow > 0 ? contextWindow : DEFAULT_CONTEXT_WINDOW;
57
+ return Math.max(1, Math.floor(window * CHARS_PER_TOKEN * BUDGET_FRACTION));
58
+ }
59
+
60
+ /** Claude Code's ranking score: uses, halved every week since the last one, never below a tenth. */
61
+ export function usageScore(entry: UsageEntry | undefined, now: Date = new Date()): number {
62
+ if (!entry) return 0;
63
+ const last = Date.parse(entry.lastUsedAt);
64
+ if (Number.isNaN(last)) return 0;
65
+ const days = (now.getTime() - last) / 86_400_000;
66
+ return entry.count * Math.max(0.5 ** (days / 7), 0.1);
67
+ }
68
+
69
+ export function skillListingText(skills: ReadonlyArray<ListedSkill>, budget = Number.POSITIVE_INFINITY): string {
70
+ const listed = skills.flatMap((skill) => {
71
+ if (skill.disableModelInvocation) return [];
15
72
  const visibility = skillListingVisibility(skill.state);
16
73
  if (visibility === "hidden") return [];
17
- if (visibility === "name") return [`- ${skill.name}`];
18
- return [`- ${skill.name}${skill.description?.trim() ? `: ${skill.description.trim()}` : ""}`];
74
+ const short = `- ${skill.name}`;
75
+ if (visibility === "name") return [{ skill, short, full: short }];
76
+ const text = listingDescription(skill);
77
+ return [{ skill, short, full: text ? `${short}: ${text}` : short }];
19
78
  });
20
- return lines.length === 0 ? "(no skills available)" : lines.join("\n");
79
+ if (listed.length === 0) return "(no skills available)";
80
+ const separators = listed.length - 1;
81
+ const whole = listed.reduce((sum, line) => sum + line.full.length, 0) + separators;
82
+ if (whole <= budget) return listed.map((line) => line.full).join("\n");
83
+
84
+ // A name-only line's full form is its short form, so it needs no place in `kept`.
85
+ const kept = new Set(listed.filter((line) => line.skill.bundled));
86
+ const ranked = listed.filter((line) => !kept.has(line));
87
+ let left = budget - (listed.reduce((sum, line) => sum + (kept.has(line) ? line.full.length : line.short.length), 0) + separators);
88
+ // A stable sort: equal scores keep the listing's order.
89
+ for (const line of [...ranked].sort((a, b) => (b.skill.usage ?? 0) - (a.skill.usage ?? 0))) {
90
+ const extra = line.full.length - line.short.length;
91
+ if (extra > left) continue;
92
+ kept.add(line);
93
+ left -= extra;
94
+ }
95
+ return listed.map((line) => (kept.has(line) ? line.full : line.short)).join("\n");
96
+ }
97
+
98
+ /**
99
+ * The skills listing for a session without the skill tool: each skill's file,
100
+ * to read with `reader`. The same states as the tool's listing: user-only and
101
+ * off skills stay hidden, a name-only skill shows no description. Undefined
102
+ * when nothing is listable.
103
+ */
104
+ export function readableSkillListing(
105
+ skills: ReadonlyArray<ListedSkill & { path?: string; kind?: string }>,
106
+ reader: string,
107
+ ): string | undefined {
108
+ const lines = skills
109
+ .filter((skill) => !skill.kind && !skill.disableModelInvocation && skill.path && skillListingVisibility(skill.state) !== "hidden")
110
+ .map((skill) => {
111
+ const text = skillListingVisibility(skill.state) === "full" ? listingDescription(skill) : "";
112
+ return `- ${skill.name}${text ? `: ${text}` : ""} (${skill.path})`;
113
+ });
114
+ if (lines.length === 0) return undefined;
115
+ return `The following skills provide specialized instructions for specific tasks. Read a skill's file with ${reader} when the task matches its description:\n\n${lines.join("\n")}`;
116
+ }
117
+
118
+ /**
119
+ * Claude Code's reading of a boolean frontmatter flag such as
120
+ * `disable-model-invocation`: `true` or the string `"true"`, nothing else.
121
+ */
122
+ export function frontmatterFlag(value: unknown): boolean {
123
+ return value === true || value === "true";
124
+ }
125
+
126
+ /**
127
+ * pi's own skills section in a rendered system prompt (`formatSkillsForPrompt`):
128
+ * pi 1.0 renders it as a `<skills>` section, older pi (the 0.84 floor)
129
+ * appends it after a blank line. Both start with this sentence.
130
+ */
131
+ const PI_SKILLS_LEAD = "The following skills provide specialized instructions for specific tasks.";
132
+ const PI_SKILLS_SECTION = /\n*<skills>\nThe following skills provide specialized instructions for specific tasks\.[\s\S]*?<\/available_skills>\n<\/skills>/;
133
+ const PI_SKILLS_APPENDED = /\n\nThe following skills provide specialized instructions for specific tasks\.[\s\S]*?<\/available_skills>/;
134
+
135
+ /**
136
+ * `prompt` without pi's own skills section ("Use the read tool to load a
137
+ * skill's file …" and its `<available_skills>` list), unchanged when it has
138
+ * none. A session with the skill tool lists skills for that tool instead, and
139
+ * a child agent's prompt (pi adds the section to an agent's own prompt)
140
+ * otherwise told it both "read the file" and "call the skill tool first".
141
+ */
142
+ export function withoutPiSkillsBlock(prompt: string): string {
143
+ if (!prompt.includes(PI_SKILLS_LEAD)) return prompt;
144
+ return prompt.replace(PI_SKILLS_SECTION, "").replace(PI_SKILLS_APPENDED, "");
21
145
  }
@@ -1,41 +1,40 @@
1
1
  /**
2
- * Raw-byte key decoding for the /skills panel (pure).
2
+ * Key decoding for the /skills panel (pure), named through
3
+ * `lib/key-input.ts` so every terminal encoding of a key decodes alike.
3
4
  *
4
- * Same control-byte map as the /plugins panel; kept local so the skill
5
+ * Same key map as the /plugins panel; kept local so the skill
5
6
  * extension carries no dependency on another extension's internals. Printable
6
7
  * input is a `text` intent the state layer routes (into the search box, or as a
7
8
  * single-letter action when search is inactive). Skill names never contain
8
9
  * spaces, so Space is always the cycle action, never typed.
9
10
  */
10
11
 
12
+ import { keyId, keyText } from "../../lib/key-input.ts";
13
+
11
14
  export type SkillsKey =
12
15
  | { kind: "up" | "down" | "enter" | "space" | "back" | "backspace" | "close" }
13
16
  | { kind: "text"; text: string };
14
17
 
15
18
  export function decodeSkillsKey(data: string): SkillsKey | undefined {
16
- switch (data) {
17
- case "\x1b[A":
18
- case "\x1bOA":
19
+ switch (keyId(data)) {
20
+ case "up":
19
21
  return { kind: "up" };
20
- case "\x1b[B":
21
- case "\x1bOB":
22
+ case "down":
22
23
  return { kind: "down" };
23
- case "\r":
24
- case "\n":
24
+ case "enter":
25
25
  return { kind: "enter" };
26
- case " ":
26
+ case "space":
27
27
  return { kind: "space" };
28
- case "\x1b":
28
+ case "escape":
29
29
  return { kind: "back" };
30
- case "\x7f":
31
- case "\b":
30
+ case "backspace":
31
+ case "ctrl+backspace":
32
32
  return { kind: "backspace" };
33
- case "\x03":
33
+ case "ctrl+c":
34
34
  return { kind: "close" };
35
35
  default:
36
36
  break;
37
37
  }
38
- if (data.startsWith("\x1b")) return undefined;
39
- const text = [...data].filter((ch) => ch >= " " && ch !== "\x7f").join("");
38
+ const text = keyText(data);
40
39
  return text ? { kind: "text", text } : undefined;
41
40
  }
@@ -9,7 +9,7 @@
9
9
  * under-measure and risk pi's overwide-line crash.
10
10
  */
11
11
 
12
- import { cutPlainText, padPlainText, panelTopRule, searchBoxLines, visibleWidth } from "../../lib/tui-render.ts";
12
+ import { cutPlainText, padPlainText, panelTopRule, searchBoxLines, visibleWidth, wrapHints } from "../../lib/tui-render.ts";
13
13
  import type { SkillState } from "../../lib/skill-overrides.ts";
14
14
  import { clampSkillsCursor, type SkillsPanelState, type SkillsRow, visibleRows } from "./state.ts";
15
15
 
@@ -64,7 +64,10 @@ export function renderSkillsPanel(input: SkillsRenderInput, paint: SkillsPaint):
64
64
  const out: string[] = [panelTopRule(paint.fg, width)];
65
65
  out.push(` ${paint.bold("Skills")}`);
66
66
  const sortNote = state.sort === "state" ? "sorted by state" : "sorted by name";
67
- out.push(paint.fg("dim", cutPlainText(` ${rows.length} skill${rows.length === 1 ? "" : "s"} · ${sortNote} · enter/space to cycle, / to search, t to sort, Esc to close`, width - 1)));
67
+ // Wraps at the separators on a narrow terminal, so no key is cut off; the
68
+ // list budget below is taken after it.
69
+ const hints = `${rows.length} skill${rows.length === 1 ? "" : "s"} · ${sortNote} · enter/space to cycle · / to search · t to sort · Esc to close`;
70
+ for (const line of wrapHints(hints, Math.max(1, width - 2))) out.push(paint.fg("dim", ` ${line}`));
68
71
  out.push("");
69
72
  out.push(...searchBoxLines(state.search, "Search skills…", paint.fg, width));
70
73
  out.push("");
@@ -14,7 +14,8 @@ export interface SkillsRow {
14
14
  /** Override-store key, `<scope>:<name>`. */
15
15
  key: string;
16
16
  name: string;
17
- scope: SkillScope;
17
+ /** Shown in the row: where the skill comes from; "bundled" is One Code's own catalog. */
18
+ scope: SkillScope | "bundled";
18
19
  tokens: number;
19
20
  /** Current state; for locked (plugin) rows this is the effective on/off. */
20
21
  state: SkillState;
@@ -63,6 +64,16 @@ export function clampSkillsCursor(state: SkillsPanelState, visible: SkillsRow[])
63
64
  state.cursor = Math.max(0, Math.min(state.cursor, visible.length - 1));
64
65
  }
65
66
 
67
+ /**
68
+ * Keep the cursor on the skill `key` after the list reordered (a sort toggle,
69
+ * or a state change under the state sort), so the next key acts on the skill
70
+ * the user was looking at, not the one that slid into its row.
71
+ */
72
+ export function followRow(state: SkillsPanelState, visible: SkillsRow[], key: string): void {
73
+ const index = visible.findIndex((row) => row.key === key);
74
+ if (index >= 0) state.cursor = index;
75
+ }
76
+
66
77
  /**
67
78
  * Fold a key into the state, returning an effect the wiring must act on. The
68
79
  * caller passes the already-filtered/sorted rows so "the selected row" matches
@@ -0,0 +1,39 @@
1
+ import { DEFAULT_AGENT } from "./runs.ts";
2
+
3
+ /**
4
+ * The Agent tool's argument preparation (pure), run by pi before schema
5
+ * validation. `task` is required in the schema: a weak model read an optional
6
+ * task as optional and sent run options with no task, again and again
7
+ * (DeepSeek V3.2, live, 2026-10-05). Two callers still validate:
8
+ *
9
+ * - a Claude Code-trained model writes the task as `prompt`, which is moved
10
+ * into `task` (TOOL-FIDELITY-REVIEW-2026-09-07 H1);
11
+ * - `action: "list"` only browses the catalog and needs no task.
12
+ *
13
+ * A run that names no agent gets general-purpose here, as in Claude Code, so
14
+ * the permission gate, hooks and the stored call see the agent that runs: an
15
+ * `Agent(general-purpose)` deny rule must stop a call that omits the type.
16
+ *
17
+ * Anything that is not a plain object is passed through for the validator to
18
+ * reject as it does today.
19
+ */
20
+ export function prepareAgentArguments(args: unknown): unknown {
21
+ if (!args || typeof args !== "object" || Array.isArray(args)) return args;
22
+ const input = args as Record<string, unknown>;
23
+ const prepared = withTask(input);
24
+ if (!isRun(input) || (typeof input.subagent_type === "string" && input.subagent_type)) return prepared;
25
+ return { ...prepared, subagent_type: DEFAULT_AGENT };
26
+ }
27
+
28
+ function withTask(input: Record<string, unknown>): Record<string, unknown> {
29
+ if (typeof input.task === "string" && input.task.length > 0) return input;
30
+ if (typeof input.prompt === "string" && input.prompt.length > 0) return { ...input, task: input.prompt };
31
+ if (input.action === "list" && input.task === undefined) return { ...input, task: "" };
32
+ return input;
33
+ }
34
+
35
+ /** A call carrying run options (a task, a name, a model/thinking/isolation override, or action:"run"); one with none lists the catalog. */
36
+ function isRun(input: Record<string, unknown>): boolean {
37
+ if (input.action === "list") return false;
38
+ return input.action === "run" || [input.task, input.prompt, input.name, input.model, input.isolation, input.thinking].some((value) => value != null);
39
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * The Agent tool's model-facing description: Claude Code's Agent text plus
3
+ * One Code's own paragraph (pure).
4
+ *
5
+ * The short form goes to frontier and workhorse models, the long form (the
6
+ * text Claude Code writes for its weakest models, with the fork guidance,
7
+ * the briefing section and worked examples) to cheap and tiny ones
8
+ * (lib/tool-variants.ts). Changes from Claude Code's text: a fork rejects a
9
+ * `model` override rather than ignoring it, agent definitions come from
10
+ * `.claude/agents/*.md` only, and tool names are One Code's. The closing
11
+ * paragraph describes what only One Code has: `task_output` and `task_stop`,
12
+ * the one-shot print session, run names and `action: "list"`.
13
+ */
14
+
15
+ import type { DescriptionForm } from "../lib/tool-variants.ts";
16
+
17
+ export const AGENT_SHORT_DESCRIPTION = `Launch a new agent to handle complex, multi-step tasks. Each agent type has specific capabilities and tools available to it.
18
+
19
+ Available agent types are listed in <system-reminder> messages in the conversation.
20
+
21
+ When using the Agent tool, specify a subagent_type to select an agent: \`"fork"\` forks yourself (the fork inherits your full conversation context and always runs on your model — a \`model\` override is rejected); any other type — or omitting it — starts a fresh agent (general-purpose by default).
22
+
23
+ ## When to use
24
+
25
+ Reach for this when the task matches an available agent type, when you have independent work to run in parallel, or when answering would mean reading across several files — delegate it and you keep the conclusion, not the file dumps. For a single-fact lookup where you already know the file, symbol, or value, search directly. Once you've delegated a search, don't also run it yourself — wait for the result.
26
+
27
+ A fork runs in the background and keeps its tool output out of your context. If you are the fork, execute directly — don't re-delegate. Subagents run in the background; you'll be notified when one completes. Never fabricate or predict a pending agent's results — the notification is never something you write yourself; if the user asks before it arrives, say it's still running.
28
+
29
+ - The agent's final report is not shown to the user — relay what matters.
30
+ - Use SendMessage with the agent's ID or name to continue a previously spawned agent with its context intact; a new Agent call starts fresh (except subagent_type: "fork", which inherits your context).
31
+ - Each agent type's model, reasoning effort, and tools come from its definition (\`.claude/agents/*.md\` frontmatter).
32
+ - \`isolation: "worktree"\` gives the agent its own git worktree (auto-cleaned if unchanged).`;
33
+
34
+ export const AGENT_LONG_DESCRIPTION = `Launch a new agent to handle complex, multi-step tasks. Each agent type has specific capabilities and tools available to it.
35
+
36
+ Available agent types are listed in <system-reminder> messages in the conversation.
37
+
38
+ When using the Agent tool, specify a subagent_type to select an agent: \`"fork"\` forks yourself (the fork inherits your full conversation context and always runs on your model — a \`model\` override is rejected); any other type — or omitting it — starts a fresh agent (general-purpose by default).
39
+
40
+ ## Usage notes
41
+
42
+ - Always include a short description summarizing what the agent will do
43
+ - When the agent is done, its final report is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
44
+ - Trust but verify: an agent's summary describes what it intended to do, not necessarily what it did. When an agent writes or edits code, check the actual changes before reporting the work as done.
45
+ - To continue a previously spawned agent, use SendMessage with the agent's ID or name as the \`to\` field — that resumes it with full context. A new Agent call starts a fresh agent with no memory of prior runs (except subagent_type: "fork"), so the prompt must be self-contained.
46
+ - Each agent type's model, reasoning effort, and tool access are set in its definition (\`.claude/agents/*.md\` frontmatter); the \`model\` parameter here overrides the definition for this one call.
47
+ - Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since a fresh agent is not aware of the user's intent
48
+ - If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first.
49
+ - If the user specifies that they want you to run agents "in parallel", you MUST send a single message with multiple Agent tool use content blocks. For example, if you need to launch both a build-validator agent and a test-runner agent in parallel, send a single message with both tool calls.
50
+ - With \`isolation: "worktree"\`, the worktree is automatically cleaned up if the agent makes no changes; otherwise the path and branch are returned in the result.
51
+
52
+ ## When to fork
53
+
54
+ Fork yourself (pass \`subagent_type: "fork"\`) when the intermediate tool output isn't worth keeping in your context. The criterion is qualitative — "will I need this output again" — not task size. Fork open-ended questions. If research can be broken into independent questions, launch parallel forks in one message. A fork beats a fresh subagent for this — it inherits context and shares your cache.
55
+
56
+ Forks are cheap because they share your prompt cache.
57
+
58
+ **Don't peek.** The tool result includes an \`output_file\` path — do not read or tail it. You get a completion notification; trust it. Reading the transcript mid-flight pulls the fork's tool noise into your context, which defeats the point of forking.
59
+
60
+ **Don't race.** After launching, you know nothing about what the fork found. Never fabricate or predict fork results in any format — not as prose, summary, or structured output. The notification arrives as a user-role message in a later turn; it is never something you write yourself. If the user asks a follow-up before the notification lands, tell them the fork is still running — give status, not a guess.
61
+
62
+ **Writing a fork prompt.** Since the fork inherits your context, the prompt is a *directive* — what to do, not what the situation is. Be specific about scope: what's in, what's out, what another agent is handling. Don't re-explain background.
63
+
64
+
65
+ ## Writing the prompt
66
+
67
+ Any agent other than a fork starts with zero context. Brief the agent like a smart colleague who just walked into the room — it hasn't seen this conversation, doesn't know what you've tried, doesn't understand why this task matters.
68
+ - Explain what you're trying to accomplish and why.
69
+ - Describe what you've already learned or ruled out.
70
+ - Give enough context about the surrounding problem that the agent can make judgment calls rather than just following a narrow instruction.
71
+ - If you need a short response, say so ("report in under 200 words").
72
+ - Lookups: hand over the exact command. Investigations: hand over the question — prescribed steps become dead weight when the premise is wrong.
73
+
74
+ For fresh agents, terse command-style prompts produce shallow, generic work.
75
+
76
+ **Never delegate understanding.** Don't write "based on your findings, fix the bug" or "based on the research, implement it." Those phrases push synthesis onto the agent instead of doing it yourself. Write prompts that prove you understood: include file paths, line numbers, what specifically to change.
77
+
78
+ Example usage:
79
+
80
+ <example>
81
+ user: "What's left on this branch before we can ship?"
82
+ assistant: <thinking>Forking this — it's a survey question. I want the punch list, not the git output in my context.</thinking>
83
+ Agent({
84
+ subagent_type: "fork",
85
+ name: "ship-audit",
86
+ description: "Branch ship-readiness audit",
87
+ prompt: "Audit what's left before this branch can ship. Check: uncommitted changes, commits ahead of main, whether tests exist, whether the GrowthBook gate is wired up, whether CI-relevant files changed. Report a punch list — done vs. missing. Under 200 words."
88
+ })
89
+ assistant: Ship-readiness audit running.
90
+ <commentary>
91
+ Turn ends here. The coordinator knows nothing about the findings yet. What follows is a SEPARATE turn — the notification arrives from outside, as a user-role message. It is not something the coordinator writes.
92
+ </commentary>
93
+ [later turn — notification arrives as user message]
94
+ assistant: Audit's back. Three blockers: no tests for the new prompt path, GrowthBook gate wired but not in build_flags.yaml, and one uncommitted file.
95
+ </example>
96
+
97
+ <example>
98
+ user: "so is the gate wired up or not"
99
+ <commentary>
100
+ User asks mid-wait. The audit fork was launched to answer exactly this, and it hasn't returned. The coordinator does not have this answer. Give status, not a fabricated result.
101
+ </commentary>
102
+ assistant: Still waiting on the audit — that's one of the things it's checking. Should land shortly.
103
+ </example>
104
+
105
+ <example>
106
+ user: "Can you get a second opinion on whether this migration is safe?"
107
+ assistant: <thinking>I'll ask the code-reviewer agent — it won't see my analysis, so it can give an independent read.</thinking>
108
+ <commentary>
109
+ A non-fork subagent_type is specified, so the agent starts fresh. It needs full context in the prompt. The briefing explains what to assess and why.
110
+ </commentary>
111
+ Agent({
112
+ name: "migration-review",
113
+ description: "Independent migration review",
114
+ subagent_type: "code-reviewer",
115
+ prompt: "Review migration 0042_user_schema.sql for safety. Context: we're adding a NOT NULL column to a 50M-row table. Existing rows get a backfill default. I want a second opinion on whether the backfill approach is safe under concurrent writes — I've checked locking behavior but want independent verification. Report: is this safe, and if not, what specifically breaks?"
116
+ })
117
+ </example>
118
+ `;
119
+
120
+ /** One Code's own part, after Claude Code's text in both forms. */
121
+ export const AGENT_HOW_AGENTS_RUN = `## How agents run
122
+
123
+ - Call task_output only if your next step cannot proceed without the result (block=true waits); stop a run with task_stop. Both are deferred — load them with tool_search first.
124
+ - In a one-shot print session the call blocks and returns the report directly — no notification follows.
125
+ - Give a complete, self-contained task: the agent cannot ask follow-up questions.
126
+ - Each run gets a name — SendMessage reaches it live while it runs and continues it after it finishes. \`action: "list"\` re-prints the agent catalog.`;
127
+
128
+ /** The Agent description for a form, naming the mode's agent folder (`.onecode` in independent mode, lib/config-mode.ts). */
129
+ export function agentDescription(form: DescriptionForm, configDir = ".claude"): string {
130
+ const base = form === "long" ? AGENT_LONG_DESCRIPTION : AGENT_SHORT_DESCRIPTION;
131
+ return `${base.trimEnd()}\n\n${AGENT_HOW_AGENTS_RUN}`.replaceAll("`.claude/agents/*.md`", `\`${configDir}/agents/*.md\``);
132
+ }