one-code-extension 0.4.1 → 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 +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 +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 +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 +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 +18 -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
@@ -15,9 +15,11 @@
15
15
  */
16
16
 
17
17
  import { readdirSync, readFileSync, statSync } from "node:fs";
18
- import { basename, join } from "node:path";
18
+ import { basename, dirname, join } from "node:path";
19
+ import { fileURLToPath } from "node:url";
19
20
  import { parseFrontmatterLoosely } from "../lib/frontmatter.ts";
20
- import { claudeUserDir } from "../lib/paths.ts";
21
+ import { projectConfigDir, userConfigDir } from "../lib/config-mode.ts";
22
+ import { SUBAGENT_HANDBACK } from "../lib/subagent-handback.ts";
21
23
  import { normalizeToolName } from "../permissions/matcher.ts";
22
24
 
23
25
  export interface AgentDefinition {
@@ -66,24 +68,65 @@ function collectMarkdownFiles(dir: string, out: string[] = []): string[] {
66
68
  return out;
67
69
  }
68
70
 
71
+ /**
72
+ * Split one frontmatter tool string the way Claude Code does: on commas and
73
+ * spaces, except inside a rule's parentheses, so `Bash(git push:*), Write` is
74
+ * two entries and `Agent(worker, researcher)` is one.
75
+ */
76
+ function splitToolSpecs(text: string): string[] {
77
+ const specs: string[] = [];
78
+ let current = "";
79
+ let inParens = false;
80
+ for (const char of text) {
81
+ if (char === "(") inParens = true;
82
+ else if (char === ")") inParens = false;
83
+ else if ((char === "," || /\s/.test(char)) && !inParens) {
84
+ if (current.trim()) specs.push(current.trim());
85
+ current = "";
86
+ continue;
87
+ }
88
+ current += char;
89
+ }
90
+ if (current.trim()) specs.push(current.trim());
91
+ return specs;
92
+ }
93
+
94
+ /**
95
+ * The tool a spec names. A rule-shaped entry (`Bash(git push:*)`) names its
96
+ * whole tool: Claude Code grants or removes the entire tool for it in an agent
97
+ * file, never only the rule's commands, so `disallowedTools: Bash(git push:*)`
98
+ * removes `bash`. Anything that is not `Name(…)` is taken as a plain name.
99
+ */
100
+ function specToolName(spec: string): string {
101
+ const open = spec.indexOf("(");
102
+ return open > 0 && spec.endsWith(")") ? spec.slice(0, open) : spec;
103
+ }
104
+
69
105
  /**
70
106
  * A frontmatter tool list (comma string or YAML list) as pi tool names: Claude
71
107
  * Code spellings map through the alias table (`Glob` → `find`, `WebFetch` →
72
108
  * `web_fetch`, `Task` → `Agent`, …), pi names and `mcp__*` pass through,
73
- * duplicates collapse. Exported for tests.
109
+ * rule-shaped entries reduce to their tool, duplicates collapse. A list that
110
+ * contains `*` returns `["*"]`; `parseAgentFile` reads that as "all tools".
111
+ * Exported for tests.
74
112
  */
75
113
  export function parseToolList(raw: unknown): string[] | undefined {
76
- const list =
77
- typeof raw === "string"
78
- ? raw
79
- .split(",")
80
- .map((t) => t.trim())
81
- .filter(Boolean)
82
- : Array.isArray(raw)
83
- ? raw.filter((t): t is string => typeof t === "string").map((t) => t.trim()).filter(Boolean)
84
- : undefined;
85
- if (!list || list.length === 0) return undefined;
86
- return [...new Set(list.map(normalizeToolName))];
114
+ const entries =
115
+ typeof raw === "string" ? [raw] : Array.isArray(raw) ? raw.filter((t): t is string => typeof t === "string") : undefined;
116
+ const specs = entries?.flatMap(splitToolSpecs);
117
+ if (!specs || specs.length === 0) return undefined;
118
+ if (specs.includes("*")) return ["*"];
119
+ return [...new Set(specs.map((spec) => normalizeToolName(specToolName(spec))))];
120
+ }
121
+
122
+ /**
123
+ * An agent file's `tools` allowlist. Claude Code reads a list containing `*`
124
+ * as "all tools", the same as no list; kept as `["*"]` the allowlist matched
125
+ * no tool and every spawn failed.
126
+ */
127
+ function parseAllowlist(raw: unknown): string[] | undefined {
128
+ const tools = parseToolList(raw);
129
+ return tools?.includes("*") ? undefined : tools;
87
130
  }
88
131
 
89
132
  export function parseAgentFile(path: string, content: string): AgentDefinition | undefined {
@@ -98,7 +141,7 @@ export function parseAgentFile(path: string, content: string): AgentDefinition |
98
141
  return {
99
142
  name,
100
143
  description: typeof fm.description === "string" ? fm.description : "",
101
- tools: parseToolList(fm.tools),
144
+ tools: parseAllowlist(fm.tools),
102
145
  excludeTools: disallowed.length > 0 ? [...new Set(disallowed)] : undefined,
103
146
  // "inherit" is Claude Code's way of saying "use the session model".
104
147
  model: typeof fm.model === "string" && fm.model !== "inherit" ? fm.model : undefined,
@@ -109,11 +152,25 @@ export function parseAgentFile(path: string, content: string): AgentDefinition |
109
152
 
110
153
  /**
111
154
  * Lowest to highest precedence: the catalog bundled with this package, then the
112
- * user's `~/.claude/agents`, then the project's `.claude/agents`. A user or
113
- * project definition with the same name replaces a bundled one.
155
+ * user's `~/.claude/agents`, then the project's `.claude/agents` (`~/.onecode`
156
+ * and `.onecode` in independent mode, lib/config-mode.ts). A user or project
157
+ * definition with the same name replaces a bundled one.
114
158
  */
115
159
  export function agentDirs(cwd: string, home: string, bundled?: string): string[] {
116
- return [...(bundled ? [bundled] : []), join(claudeUserDir(home), "agents"), join(cwd, ".claude", "agents")];
160
+ return [...(bundled ? [bundled] : []), join(userConfigDir(home), "agents"), join(projectConfigDir(cwd), "agents")];
161
+ }
162
+
163
+ /** The agent files the package ships (general-purpose, explore, plan, …). */
164
+ export const BUNDLED_AGENTS_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "agents");
165
+
166
+ /**
167
+ * Every agent-file source in rank order, as the Agent tool loads them:
168
+ * bundled, then plugin agents, then the user and project folders. Workflows
169
+ * resolve `agentType` from the same list (the code-defined guide is the Agent
170
+ * tool's alone).
171
+ */
172
+ export function agentFileSources(cwd: string, home: string, pluginAgentDirs: readonly (string | AgentSource)[]): Array<string | AgentSource> {
173
+ return [BUNDLED_AGENTS_DIR, ...pluginAgentDirs, ...agentDirs(cwd, home)];
117
174
  }
118
175
 
119
176
  /** A directory whose agents are exposed as `<namespace>:<name>` (plugins). */
@@ -122,10 +179,19 @@ export interface AgentSource {
122
179
  namespace?: string;
123
180
  }
124
181
 
182
+ /** Agents defined in code (`one-code-guide`), taken as they are: never copied, so a lazy prompt stays lazy. */
183
+ export interface CodeAgents {
184
+ agents: readonly AgentDefinition[];
185
+ }
186
+
125
187
  /** Later sources override earlier ones on name collisions. */
126
- export function discoverAgents(sources: Array<string | AgentSource>): AgentDefinition[] {
188
+ export function discoverAgents(sources: Array<string | AgentSource | CodeAgents>): AgentDefinition[] {
127
189
  const byName = new Map<string, AgentDefinition>();
128
190
  for (const source of sources) {
191
+ if (typeof source !== "string" && "agents" in source) {
192
+ for (const agent of source.agents) byName.set(agent.name, agent);
193
+ continue;
194
+ }
129
195
  const { dir, namespace } = typeof source === "string" ? { dir: source, namespace: undefined } : source;
130
196
  for (const file of collectMarkdownFiles(dir)) {
131
197
  try {
@@ -145,11 +211,12 @@ export function discoverAgents(sources: Array<string | AgentSource>): AgentDefin
145
211
  * Tools a child cannot function without, re-added when an agent file's `tools`
146
212
  * allowlist omits them: pi's allowlist filters built-ins, extension tools AND
147
213
  * injected custom tools by exact name, so a CC-style `tools: Read, Grep` would
148
- * otherwise also strip the child's report channel (`SendMessage` → main), its
149
- * deferred-tool loader and the runtime's `structured_output`. Claude Code's
150
- * allowlist never strips its own plumbing either.
214
+ * otherwise also strip the child's report channels (`SendMessage` → main and
215
+ * the final `SubagentHandback`), its deferred-tool loader and the runtime's
216
+ * `structured_output`. Claude Code's allowlist never strips its own plumbing
217
+ * either.
151
218
  */
152
- const ALLOWLIST_ESSENTIALS = ["SendMessage", "tool_search", "structured_output"];
219
+ const ALLOWLIST_ESSENTIALS = ["SendMessage", SUBAGENT_HANDBACK, "tool_search", "structured_output"];
153
220
 
154
221
  /** Apply an agent's allowlist to pi's `tools` option, keeping the essentials. */
155
222
  export function childToolAllowlist(tools: string[] | undefined): string[] | undefined {
@@ -168,3 +235,29 @@ export function usableAllowlistedTools(registered: string[], allowlist: string[]
168
235
  const available = new Set(registered);
169
236
  return allowlist.filter((name) => available.has(name));
170
237
  }
238
+
239
+ /**
240
+ * pi's session tool options for a named agent: its allowlist with the child's
241
+ * plumbing re-added, and its denylist. The one builder both runners use (the
242
+ * subagent runner and the workflow runner), so an agent file means the same
243
+ * thing wherever it runs; the workflow runner once passed the raw allowlist and
244
+ * no denylist, which stripped `structured_output` and ignored `disallowedTools`
245
+ * (SUBAGENTS-WORKFLOWS-REVIEW-2026-09-26 H2, H3).
246
+ */
247
+ export function agentToolOptions(agent: AgentDefinition | undefined): { tools?: string[]; excludeTools?: string[] } {
248
+ return { tools: childToolAllowlist(agent?.tools), excludeTools: agent?.excludeTools };
249
+ }
250
+
251
+ /**
252
+ * The fail-loud error for an agent whose `tools` allowlist matched no tool the
253
+ * session registered, or undefined when the agent is usable. pi drops unknown
254
+ * names silently, so without this the agent would run with no tools and
255
+ * "complete" with an excuse.
256
+ */
257
+ export function unusableAllowlistError(agent: AgentDefinition | undefined, registered: string[]): string | undefined {
258
+ if (!agent?.tools || usableAllowlistedTools(registered, agent.tools).length > 0) return undefined;
259
+ return (
260
+ `Agent "${agent.name}" lists tools (${agent.tools.join(", ")}) that match no available tool. ` +
261
+ "Use Claude Code names (Read, Edit, Write, Bash, Grep, Glob, WebFetch, WebSearch, NotebookEdit, Skill, Agent, SendMessage) or pi names (read, edit, write, bash, grep, find, ls, …) in the agent file's `tools` list."
262
+ );
263
+ }
@@ -0,0 +1,69 @@
1
+ /** Pure state for resumed-session subagent capability announcements. */
2
+
3
+ export type SubagentCapability = "models" | "agents" | "delegation";
4
+ export interface SubagentBaseline {
5
+ models: string | null;
6
+ agents: string | null;
7
+ delegation: string | null;
8
+ /** Account refusals the narrow tail correction has already communicated. */
9
+ refusedModels: string[];
10
+ }
11
+
12
+ export function emptySubagentBaseline(): SubagentBaseline {
13
+ return { models: null, agents: null, delegation: null, refusedModels: [] };
14
+ }
15
+
16
+ /** Stored baseline validation deliberately permits arbitrary reminder text. */
17
+ export function subagentBaseline(value: unknown): SubagentBaseline | undefined {
18
+ if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
19
+ const input = value as Record<string, unknown>;
20
+ const output = emptySubagentBaseline();
21
+ for (const key of ["models", "agents", "delegation"] as const) {
22
+ if (input[key] !== null && typeof input[key] !== "string") return undefined;
23
+ output[key] = (input[key] as string | null | undefined) ?? null;
24
+ }
25
+ // v1 phase-2 snapshots did not carry this field; absence means no known
26
+ // refusal, not malformed state. Keep the list JSON-safe and deterministic.
27
+ if (input.refusedModels !== undefined && (!Array.isArray(input.refusedModels) || !input.refusedModels.every((model) => typeof model === "string"))) return undefined;
28
+ output.refusedModels = [...new Set((input.refusedModels as string[] | undefined) ?? [])];
29
+ return output;
30
+ }
31
+
32
+ /** A restored first-prepend block is a usable fallback for snapshots predating structured baselines. */
33
+ export function subagentBaselineFromStack(stack: readonly { key?: string; text: string }[]): SubagentBaseline {
34
+ const baseline = emptySubagentBaseline();
35
+ const keys: Record<SubagentCapability, string> = {
36
+ models: "subagent-models", agents: "subagent-agents", delegation: "subagent-delegation",
37
+ };
38
+ for (const capability of Object.keys(keys) as SubagentCapability[]) {
39
+ const entry = stack.find((item) => item.key === keys[capability]);
40
+ baseline[capability] = entry?.text ?? null;
41
+ }
42
+ return baseline;
43
+ }
44
+
45
+ export type SubagentAnnouncement =
46
+ | { kind: "none"; baseline: SubagentBaseline }
47
+ | { kind: "standing"; baseline: SubagentBaseline }
48
+ | { kind: "addendum"; text: string; baseline: SubagentBaseline };
49
+
50
+ /**
51
+ * Fresh sessions may rewrite message 1; resumed sessions must leave its locked
52
+ * block alone and describe a real capability change at the tail instead.
53
+ */
54
+ export function planSubagentAnnouncement(input: {
55
+ restored: boolean;
56
+ baseline: SubagentBaseline;
57
+ capability: SubagentCapability;
58
+ text: string | null;
59
+ }): SubagentAnnouncement {
60
+ if (input.baseline[input.capability] === input.text) return { kind: "none", baseline: input.baseline };
61
+ const baseline = { ...input.baseline, [input.capability]: input.text };
62
+ if (!input.restored) return { kind: "standing", baseline };
63
+ if (input.text !== null) return { kind: "addendum", text: input.text, baseline };
64
+ return {
65
+ kind: "addendum",
66
+ text: "The subagent delegation guidance previously shown for this conversation is no longer active.",
67
+ baseline,
68
+ };
69
+ }
@@ -10,15 +10,14 @@
10
10
  * not read: both project files live in the repository, and a checked-in `env`
11
11
  * block must not get to pick which provider receives subagent tasks — the
12
12
  * same containment rule as `autoMode` config.
13
- * - `subagentModel` — One Code's own top-level setting, same shape as
14
- * `autoMode.classifierModel`. Wins over the env var when both are set,
13
+ * - `subagentModel` — One Code's own top-level setting. Wins over the env var when both are set,
15
14
  * because it is the more specific statement of intent. It is One Code's key,
16
15
  * not Claude Code's: it is written to and read from `~/.onecode/settings.json`
17
16
  * (+ managed settings), never from `~/.claude`, where an old One Code build may
18
17
  * have left a stale value the current session cannot reach. Claude Code's own
19
18
  * `CLAUDE_CODE_SUBAGENT_MODEL` env block is still honoured from `~/.claude`
20
19
  * (that key *is* Claude Code's). See "Own state, borrowed config" in
21
- * docs/decisions/memory-state.md.
20
+ * working-docs/decisions/memory-state.md.
22
21
  *
23
22
  * The env var additionally applies only to Claude-family sessions (see
24
23
  * `applicableSubagentDefault`): it is Claude Code's knob, and its typical
@@ -16,8 +16,8 @@
16
16
  */
17
17
 
18
18
  export const DELEGATION_STEER = [
19
- 'Delegation policy: when a request requires reading or searching MANY files (a codebase overview, "find every place where…", a consistency audit, exploring unfamiliar code), do NOT sweep the files yourself.',
20
- 'Make ONE Agent tool call with subagent_type: "explore" and the complete question as the task. The agent searches in its own separate context and returns just the answer; reading file after file yourself fills your context and degrades your answer.',
21
- "Search directly only for a single targeted lookup (one known file or symbol).",
22
- "When the agent has answered, report its answer and move on — do not re-read the files it already covered.",
19
+ "Delegation policy: when a request requires reading MANY files (a codebase overview, how a feature works across modules, exploring unfamiliar code), do NOT sweep the files yourself.",
20
+ 'Make one Agent tool call per independent question, with subagent_type: "explore" and the complete question as the task; for several independent questions, issue those calls together in one message. The agent searches in its own separate context and returns just the answer; reading file after file yourself fills your context and degrades your answer.',
21
+ "Search directly for a single targeted lookup: one known file or symbol, or a word one grep can find everywhere.",
22
+ "When the agent has answered, report its answer and move on — do not re-read the files it already covered, except one you are about to edit (an edit needs a read first).",
23
23
  ].join("\n");
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The fork's side of reading the parent's prompt cache (decisions/caching.md,
3
+ * "A call that inherits the session's context reads the session's cache").
4
+ *
5
+ * A fork's own session builds its requests from its own system prompt, tools
6
+ * and reminder stack, so every fork re-read the parent's whole transcript
7
+ * uncached: on a parent near a 1M-token window, the whole window per fork.
8
+ * This inline extension, loaded last in a fork's session, sends the parent's
9
+ * last captured request instead, with the fork's own messages after it:
10
+ *
11
+ * - `context_with_system` (it runs after every `context` handler, so the
12
+ * fork's reminder stack is already on the messages it drops) removes the
13
+ * messages the capture carries, leaving pi to convert only the fork's tail;
14
+ * - `before_provider_request` (inline extensions load after the path ones, so
15
+ * tool-search has already edited the body) replaces everything but the tail
16
+ * with the captured body (`forkRequestPayload`);
17
+ * - `before_provider_headers` sends the parent's session-affinity headers, so a
18
+ * gateway such as OpenRouter routes the fork to the host holding the cache.
19
+ *
20
+ * Both steps check the same thing first (the capture's model and its boundary
21
+ * message in this context); when either fails, or the tail leaves less than
22
+ * `MIN_REPLAY_OUTPUT_TOKENS` of the captured output room, the request goes out
23
+ * the ordinary way, whole, and uncached. That happens only for a fork that
24
+ * compacted its own history away, runs on another model, or has nearly
25
+ * filled the window.
26
+ */
27
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
28
+ import { DEFER_CHANNEL } from "../lib/deferred.ts";
29
+ import { type AffinityModel, affinityHeaders, captureMatches, forkOutputRoom, forkRequestPayload, MIN_REPLAY_OUTPUT_TOKENS, type RequestCapture, toolNames, uncoveredMessages } from "../lib/request-replay.ts";
30
+
31
+ type ModelRef = { api?: string; provider?: string; id?: string };
32
+
33
+ export function forkCacheExtension(capture: RequestCapture) {
34
+ return (pi: ExtensionAPI) => {
35
+ // The fork advertises the parent's tools, where SendMessage is deferred
36
+ // (subagents/index.ts). Defer the fork's own SendMessage the same way, so a
37
+ // tool_search load reaches it: on a model without tool references the load
38
+ // appends it, and elsewhere the parent's compatible schema (to: "main")
39
+ // already declares it. Inline extensions load after tool-search.
40
+ pi.events.emit(DEFER_CHANNEL, { name: "SendMessage", keywords: ["message", "main", "report", "progress"] });
41
+ /** Set by the context step for the request it shaped; the payload step splices only then. */
42
+ let shaped = false;
43
+ /** The tool names of the fork's first request: anything added later was loaded during the run. */
44
+ let baseline: Set<string> | undefined;
45
+
46
+ pi.on("context_with_system", (event, ctx) => {
47
+ shaped = false;
48
+ const covers = capture.covers;
49
+ if (!covers || !captureMatches(capture, ctx.model as ModelRef | undefined)) return undefined;
50
+ const tail = uncoveredMessages(event.messages as { role: string; timestamp?: number }[], covers);
51
+ if (!tail) return undefined;
52
+ // Too little output room left after the prefix: send the fork whole
53
+ // (pi's overflow handling then compacts it) rather than a splice the
54
+ // window cannot hold. The messages' JSON overstates the wire tail.
55
+ const room = forkOutputRoom(capture, tail.filter((message) => message.role !== "system"));
56
+ if (room !== undefined && room < MIN_REPLAY_OUTPUT_TOKENS) return undefined;
57
+ shaped = true;
58
+ return { messages: tail as typeof event.messages };
59
+ });
60
+
61
+ // Route to the parent's host: a gateway picks it by the session-affinity
62
+ // headers, and the parent's cache lives there. Harmless on a whole request.
63
+ pi.on("before_provider_headers", (event, ctx) => {
64
+ if (!capture.sessionId || !captureMatches(capture, ctx.model as ModelRef | undefined)) return;
65
+ Object.assign(event.headers, affinityHeaders(ctx.model as AffinityModel, capture.sessionId));
66
+ });
67
+
68
+ pi.on("before_provider_request", (event, ctx) => {
69
+ if (!shaped || !captureMatches(capture, ctx.model as ModelRef | undefined)) return undefined;
70
+ shaped = false;
71
+ const payload = event.payload as Record<string, unknown>;
72
+ baseline ??= new Set(toolNames(payload.tools));
73
+ return forkRequestPayload(capture, payload, baseline);
74
+ });
75
+ };
76
+ }
@@ -0,0 +1,189 @@
1
+ /**
2
+ * The `one-code-guide` agent — One Code's counterpart of Claude Code's built-in
3
+ * `claude-code-guide` (2.1.283): a read-only agent the model spawns when the
4
+ * user asks how One Code works, which answers from the documentation on disk
5
+ * rather than from memory, and knows the user's live setup.
6
+ *
7
+ * Claude Code's guide fetches its docs over the web and runs on `haiku`. Ours
8
+ * reads the user guide shipped in this package and the running pi's docs and
9
+ * examples (lib/guide-docs.ts), so the answer matches the installed version,
10
+ * and runs on the session's subagent model (no `model` here, so the usual
11
+ * resolution applies). It answers about One Code only, and when One Code lacks
12
+ * something it suggests how to add it, down to a custom pi extension.
13
+ *
14
+ * Built in code, not as an `agents/*.md` file, because the prompt names paths
15
+ * and configuration known only at runtime. It is the lowest-precedence
16
+ * definition, so a user or project agent file of the same name replaces it.
17
+ * Pure (no pi imports): the subagents extension gathers the inputs. The brand
18
+ * text lives here only, so a downstream fork swaps this one module.
19
+ */
20
+
21
+ import type { AgentDefinition } from "./agents.ts";
22
+ import { claudeSourcesOn, projectConfigDirName } from "../lib/config-mode.ts";
23
+
24
+ export const GUIDE_AGENT = "one-code-guide";
25
+
26
+ const REPO_URL = "https://github.com/IsuruMaduranga/one-code";
27
+
28
+ /**
29
+ * Claude Code's guide tools where search runs through the shell (its
30
+ * embedded-search shape): bash for `grep`/`find`, read, and the web tools.
31
+ * pi's own grep/find/ls are active only on the tiny tier (search-tools), so an
32
+ * allowlist naming them left the child without search.
33
+ */
34
+ export const GUIDE_TOOLS = ["bash", "read", "web_fetch", "web_search"];
35
+
36
+ export const GUIDE_DESCRIPTION =
37
+ 'Use this agent when the user asks questions ("Can One Code...", "Does One Code...", "How do I...") about One Code itself: features, slash commands, settings, permission modes and auto mode, hooks, skills, plugins, MCP servers, subagents and workflows, models and providers, keyboard shortcuts, installation and troubleshooting. Also use it when the user wants One Code to do something it does not do yet: it suggests an existing feature or setting, or how to add it with a skill, agent, hook, MCP server or a custom pi extension. **IMPORTANT:** Before spawning a new agent, check if there is already a running or recently completed one-code-guide agent that you can continue via SendMessage.';
38
+
39
+ export interface GuideInstall {
40
+ /** `app` for the bundled `onecode`, `extension` for One Code on the user's own pi. */
41
+ shape: "app" | "extension";
42
+ /** How the app was installed (`npm`, `brew`), when known. */
43
+ method?: string;
44
+ /** pi's agent directory for this session (`getAgentDir()`). */
45
+ agentDir: string;
46
+ /** The One Code version, when known. */
47
+ version?: string;
48
+ }
49
+
50
+ /** The user's live setup, listed so the answer can build on it. Names only. */
51
+ export interface GuideSetup {
52
+ skills: string[];
53
+ agents: string[];
54
+ plugins: string[];
55
+ /** Every configured MCP server, with its status when it is not connected. */
56
+ mcpServers: { name: string; status?: string }[];
57
+ /** Extensions dropped into the user's pi extensions directory. */
58
+ extensions: string[];
59
+ /** pi packages the user installed, One Code's own entry excluded. */
60
+ packages: string[];
61
+ /** Keys set in pi's settings file for this session (values omitted). */
62
+ settingsKeys: string[];
63
+ }
64
+
65
+ export interface GuideInput {
66
+ docs: { guide: string; piDocs?: string; piExamples?: string };
67
+ install: GuideInstall;
68
+ setup: GuideSetup;
69
+ }
70
+
71
+ /**
72
+ * The packages and settings keys in pi's settings file (its raw text), minus
73
+ * One Code's own package entry (`ownRoot`, this package's directory, which the
74
+ * app registers on every launch). Unreadable text gives nothing.
75
+ */
76
+ export function settingsSetup(raw: string | undefined, ownRoot: string): Pick<GuideSetup, "packages" | "settingsKeys"> {
77
+ let settings: unknown;
78
+ try {
79
+ settings = raw === undefined ? undefined : JSON.parse(raw);
80
+ } catch {
81
+ return { packages: [], settingsKeys: [] };
82
+ }
83
+ if (typeof settings !== "object" || settings === null || Array.isArray(settings)) return { packages: [], settingsKeys: [] };
84
+ const record = settings as Record<string, unknown>;
85
+ const sources = (Array.isArray(record.packages) ? record.packages : [])
86
+ .map((entry) => (typeof entry === "string" ? entry : (entry as { source?: unknown } | null)?.source))
87
+ .filter((source): source is string => typeof source === "string");
88
+ const own = (source: string) => source === ownRoot || /[/\\]one-code-extension$/.test(source) || /^npm:one-code-extension(@.*)?$/.test(source);
89
+ return { packages: sources.filter((source) => !own(source)), settingsKeys: Object.keys(record).sort() };
90
+ }
91
+
92
+ function installSection({ shape, method, agentDir, version }: GuideInstall): string {
93
+ const v = version ? ` ${version}` : "";
94
+ if (shape === "app") {
95
+ return `This session runs the bundled One Code app (\`onecode\`${v}${method ? `, installed with ${method}` : ""}). It carries its own pinned pi and keeps pi's state in its agent directory, \`${agentDir}\`. pi's commands work through it: \`onecode install <source>\` installs a pi package (npm, git or a local path) into that directory's \`settings.json\`, \`onecode remove <source>\` removes one, and \`onecode list\` lists them. A plain \`pi\` command on the same machine is a separate installation and does not see these.`;
96
+ }
97
+ return `This session runs One Code as an extension on the user's own pi installation${v ? ` (One Code${v})` : ""}. pi's agent directory is \`${agentDir}\`; \`pi install <source>\`, \`pi remove <source>\` and \`pi list\` manage packages there.`;
98
+ }
99
+
100
+ /**
101
+ * Whether a repository-supplied name may be listed in the guide's system
102
+ * prompt: an identifier (letters, digits, `_ . : @ -`, at most 64), never free
103
+ * text a cloned repo could use to smuggle instructions in.
104
+ */
105
+ export function listableName(name: string): boolean {
106
+ return /^[A-Za-z0-9_.:@-]{1,64}$/.test(name);
107
+ }
108
+
109
+ function setupSection(setup: GuideSetup): string | undefined {
110
+ const rows: string[] = [];
111
+ const list = (label: string, items: string[]) => {
112
+ if (items.length > 0) rows.push(`**${label}:** ${items.join(", ")}`);
113
+ };
114
+ // Skill folders, agent files and .mcp.json servers can come from a cloned
115
+ // repository, so only identifier-shaped names reach the system prompt.
116
+ list("Custom skills", setup.skills.filter(listableName));
117
+ list("Custom agents", setup.agents.filter(listableName));
118
+ list("Enabled plugins", setup.plugins);
119
+ list(
120
+ "Configured MCP servers",
121
+ setup.mcpServers.filter((server) => listableName(server.name)).map((server) => (server.status ? `${server.name} (${server.status})` : server.name)),
122
+ );
123
+ list("Installed pi packages", setup.packages);
124
+ list("Extensions in the user extensions directory", setup.extensions);
125
+ list("Settings keys configured (values omitted)", setup.settingsKeys);
126
+ if (rows.length === 0) return undefined;
127
+ return `# User's Current Configuration\nThe user has the following custom setup in their environment:\n${rows.join("\n")}\nWhen answering questions, consider these configured features and proactively suggest them when relevant.`;
128
+ }
129
+
130
+ export function guideSystemPrompt({ docs, install, setup }: GuideInput): string {
131
+ const piDocs = docs.piDocs ? `\`${docs.piDocs}\`` : "pi's `docs/` folder (not found on this machine; use https://pi.dev/docs/latest)";
132
+ const piExamples = docs.piExamples ? `\`${docs.piExamples}\`` : "pi's `examples/` folder (not found on this machine)";
133
+ const extensionsDir = `${install.agentDir}/extensions/`;
134
+ const prompt = `You are the One Code guide agent. Your primary responsibility is helping users understand and use One Code effectively, and showing them how to make it do more.
135
+
136
+ **What One Code is:** a coding agent that recreates the Claude Code experience on any model provider. It is built as a package of extensions for the pi agent harness, so everything it does is an ordinary pi extension, and users can extend it the same way.
137
+
138
+ **How this session is installed:** ${installSection(install)}
139
+
140
+ **Documentation sources (all on this machine, matching the installed version):**
141
+ - **One Code user guide** (\`${docs.guide}\`): start with its \`README.md\`, the index of every page. Read it for any question about One Code's features, commands, settings, permissions and auto mode, hooks, skills, plugins, MCP, subagents, workflows, models, the terminal interface, Windows, troubleshooting, and how One Code differs from Claude Code.
142
+ - **pi documentation** (${piDocs}): read it for what One Code inherits from pi and for extending it: \`extensions.md\` (writing an extension), \`packages.md\` (installing and publishing packages), \`settings.md\`, \`keybindings.md\`, \`providers.md\` and \`models.md\`.
143
+ - **pi examples** (${piExamples}): working extensions to base a suggestion on (\`examples/extensions/\`).
144
+
145
+ **Approach:**
146
+ 1. Read the One Code guide's index and pick the pages that cover the question
147
+ 2. Read those pages; search the docs with \`grep\` and \`find\` through the shell when the index does not name the topic
148
+ 3. For customization and extension questions, read pi's docs and examples too
149
+ 4. Read the user's own configuration (settings files, ${claudeSourcesOn() ? "CLAUDE.md" : "AGENTS.md, ONECODE.md"}, \`${projectConfigDirName()}/\`) when it bears on the answer
150
+ 5. Provide clear, actionable guidance based on the documentation, citing the file each fact came from
151
+
152
+ **When One Code does not do what the user wants,** say so plainly, then suggest the smallest change that gets them there, in this order:
153
+ 1. An existing feature, command or setting that covers it
154
+ 2. Configuration they can add themselves: a skill, a custom agent, a hook, an MCP server, or a plugin (the guide explains each)
155
+ 3. A custom pi extension. Describe what it would do and which pi events or APIs it would use, from pi's \`extensions.md\` and the examples. To try it, the user drops a \`.ts\` file (or a folder with an \`index.ts\`) into \`${extensionsDir}\` for every project, or \`.pi/extensions/\` in one project (loaded once the project is trusted), then restarts or runs \`/reload\`. To share it, they make it a pi package and install it with the commands above. Community packages may already exist: search https://pi.dev/packages first, and tell the user to review a package's source before installing it, because extensions run with full access.
156
+ 4. If it is a gap or a bug in One Code itself, suggest opening an issue at ${REPO_URL}/issues
157
+
158
+ **Guidelines:**
159
+ - Your training data does not know One Code. Never answer from memory: every fact about One Code comes from the documentation above. If the docs do not cover the topic, say so rather than guess.
160
+ - Answer questions about One Code (and pi, as far as it shapes One Code) only. For anything else, say it is outside what you cover and suggest asking in the main conversation.
161
+ - Read files with the read tool, not the shell. Use the shell only for read-only searches (\`grep\`, \`find\`). Never edit, write, install or delete anything: when a suggestion needs a file written or a package installed, describe it; the main agent or the user does it.
162
+ - Keep responses concise and actionable
163
+ - Include specific examples, commands or code snippets when helpful
164
+ - Reference the documentation file paths in your responses
165
+ - Help users discover features by proactively suggesting related commands, shortcuts, or capabilities
166
+
167
+ Complete the user's request by providing accurate, documentation-based guidance.`;
168
+ const setupText = setupSection(setup);
169
+ return setupText ? `${prompt}\n\n${setupText}` : prompt;
170
+ }
171
+
172
+ /**
173
+ * The definition, with the prompt built on first read: the catalog lists the
174
+ * guide on every agent listing and spawn, and only a spawn of the guide needs
175
+ * its prompt (the setup it lists costs a settings read and directory scans).
176
+ */
177
+ export function guideAgentDefinition(input: () => GuideInput): AgentDefinition {
178
+ let prompt: string | undefined;
179
+ return {
180
+ name: GUIDE_AGENT,
181
+ description: GUIDE_DESCRIPTION,
182
+ tools: GUIDE_TOOLS,
183
+ get systemPrompt() {
184
+ prompt ??= guideSystemPrompt(input());
185
+ return prompt;
186
+ },
187
+ source: "built-in",
188
+ };
189
+ }
@@ -42,6 +42,8 @@ export function awaitHandBackReview(
42
42
  run: { taskId: string; name: string },
43
43
  actions: ChildAction[] | undefined,
44
44
  timeoutMs = HAND_BACK_REVIEW_TIMEOUT_MS,
45
+ /** The main-session call that started the turn (SubagentActionsPayload.startedBy). */
46
+ startedBy?: string,
45
47
  ): Promise<HandBackVerdict | undefined> {
46
48
  if (!actions?.length) return Promise.resolve(undefined);
47
49
  return new Promise((resolve) => {
@@ -59,6 +61,7 @@ export function awaitHandBackReview(
59
61
  actions,
60
62
  background: true,
61
63
  agentName: run.name,
64
+ ...(startedBy ? { startedBy } : {}),
62
65
  onReview: finish,
63
66
  } satisfies SubagentActionsPayload);
64
67
  });