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,40 +1,33 @@
1
1
  /**
2
- * The `/init` prompt — adapted from Claude Code's `/init`, kept provider-neutral
3
- * (One Code writes a CLAUDE.md that any Claude Code-compatible agent reads) and
4
- * self-contained (no dependency on CC-internal skills like `update-config`).
2
+ * The `/init` prompt: Claude Code's classic one, the prompt it sends by
3
+ * default, submitted verbatim as a user turn by extensions/init/index.ts.
5
4
  *
6
- * Submitted verbatim as a user turn by extensions/init/index.ts; the model does
7
- * the work with the normal tool set (subagent survey, ask_user_question, write).
5
+ * Three adaptations. The CLAUDE.md it writes is read by every Claude
6
+ * Code-compatible agent, One Code included, so the opening sentence and the
7
+ * file's header name AI coding agents rather than one product (the header is
8
+ * the one One Code's /init has always written). And the rules to fold in
9
+ * include an AGENTS.md: One Code reads a directory's AGENTS.md only when that
10
+ * directory has no CLAUDE.md, so once /init writes one, anything left in
11
+ * AGENTS.md alone would stop reaching the model.
8
12
  */
9
- export const INIT_PROMPT = `Analyze this codebase and set up a concise CLAUDE.md at the repository root, to be loaded into every future session working here. Keep it minimal — every line must earn its place: include only what an agent would get wrong or waste time rediscovering without it.
10
-
11
- ## 1. Survey the codebase
12
- Launch an Explore subagent (or read directly if the repo is small) to gather:
13
- - Build, test, and lint commands — especially non-standard scripts, flags, or how to run a *single* test.
14
- - Languages, frameworks, package manager, and whether this is a monorepo/multi-module or single project.
15
- - High-level architecture that requires reading several files to grasp (the "big picture", not a file listing).
16
- - Non-obvious gotchas, required env vars, or workflow quirks.
17
- - Existing AI-tool config to fold in: an existing CLAUDE.md, AGENTS.md, .cursor/rules or .cursorrules, .github/copilot-instructions.md, .windsurfrules, .clinerules — and the important parts of README.md.
18
-
19
- ## 2. Fill the gaps
20
- Use ask_user_question only for things the code cannot answer — branch/PR conventions, required setup, testing quirks, communication preferences. Skip anything already obvious from manifests or the README. Do not mark options as "recommended": this is how their team works, not best practices.
21
-
22
- ## 3. Write CLAUDE.md
23
- Prefix the file with:
13
+ export const INIT_PROMPT = `Please analyze this codebase and create a CLAUDE.md file, which will be given to future AI coding agents (Claude Code and compatible tools) to operate in this repository.
14
+
15
+ What to add:
16
+ 1. Commands that will be commonly used, such as how to build, lint, and run tests. Include the necessary commands to develop in this codebase, such as how to run a single test.
17
+ 2. High-level code architecture and structure so that future instances can be productive more quickly. Focus on the "big picture" architecture that requires reading multiple files to understand.
18
+
19
+ Usage notes:
20
+ - If there's already a CLAUDE.md, suggest improvements to it.
21
+ - When you make the initial CLAUDE.md, do not repeat yourself and do not include obvious instructions like "Provide helpful error messages to users", "Write unit tests for all new utilities", "Never include sensitive information (API keys, tokens) in code or commits".
22
+ - Avoid listing every component or file structure that can be easily discovered.
23
+ - Don't include generic development practices.
24
+ - If there are Cursor rules (in .cursor/rules/ or .cursorrules), Copilot rules (in .github/copilot-instructions.md) or an AGENTS.md, make sure to include the important parts.
25
+ - If there is a README.md, make sure to include the important parts.
26
+ - Do not make up information such as "Common Development Tasks", "Tips for Development", "Support and Documentation" unless this is expressly included in other files that you read.
27
+ - Be sure to prefix the file with the following text:
24
28
 
25
29
  \`\`\`
26
30
  # CLAUDE.md
27
31
 
28
32
  This file gives guidance to AI coding agents (Claude Code and compatible tools) working in this repository.
29
- \`\`\`
30
-
31
- Include: build/test/lint commands an agent can't guess; code-style rules that DIFFER from language defaults; testing instructions and quirks; repo etiquette (branch naming, PR/commit conventions); required env vars or setup; non-obvious gotchas and architectural decisions; the important parts of any existing AI-tool config.
32
-
33
- Exclude: file-by-file structure or component lists (discoverable by reading); standard language conventions; generic advice ("write clean code", "handle errors"); long references or API docs (link them with \`@path/to/file\` import syntax instead of inlining); anything that changes frequently (reference the source with \`@path\`).
34
-
35
- Be specific — "Use 2-space indentation in TypeScript" beats "format code properly." Do not repeat yourself and do not invent sections like "Common Development Tasks" — only include what you actually found.
36
-
37
- If a CLAUDE.md already exists: read it, propose concrete improvements as diffs, and explain each. Do NOT silently overwrite. For projects with distinct subdirectories (monorepos), mention that per-directory CLAUDE.md files are loaded automatically when working in those directories, and offer to create them.
38
-
39
- ## 4. Recap
40
- Summarize which file(s) you wrote and the key points in each. Remind the user this is a starting point to review and tweak, and that they can run \`/init\` again anytime to re-scan.`;
33
+ \`\`\``;
@@ -11,11 +11,13 @@
11
11
  * InterruptedByUser component. The paired turn-duration line suppresses itself
12
12
  * on the same signal, so an interrupted turn shows this note in place of the
13
13
  * "Cooked for …" line — CC's behaviour (its turn-duration render is gated on
14
- * `!aborted`).
14
+ * `!aborted`). A send now (ctrl+x ctrl+s, the send-now extension) aborts the
15
+ * turn too, but gets no note: the user has already said what to do instead.
15
16
  */
16
17
 
17
18
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
18
19
  import { wasInterrupted } from "../lib/interrupt.ts";
20
+ import { SEND_NOW_CHANNEL } from "../lib/send-now-channel.ts";
19
21
  import { linesComponent, safeThemePaint } from "../lib/tui-render.ts";
20
22
  import { INTERRUPTED_TEXT } from "./line.ts";
21
23
 
@@ -27,7 +29,17 @@ export default function interruptedExtension(pi: ExtensionAPI) {
27
29
  return linesComponent(() => [paint("dim", INTERRUPTED_TEXT)]);
28
30
  });
29
31
 
32
+ // Send now aborts the turn to deliver the queued messages: the user has
33
+ // already said what to do instead, so that abort gets no note.
34
+ let sendingNow = false;
35
+ pi.events.on(SEND_NOW_CHANNEL, () => {
36
+ sendingNow = true;
37
+ });
38
+
30
39
  pi.on("agent_end", (event, ctx) => {
40
+ const skip = sendingNow;
41
+ sendingNow = false;
42
+ if (skip) return;
31
43
  if (!ctx.hasUI) return;
32
44
  if (!wasInterrupted(event.messages, ctx.signal?.aborted)) return;
33
45
  pi.appendEntry(ENTRY_TYPE);
@@ -0,0 +1,27 @@
1
+ /**
2
+ * kept-thinking extension — removes thinking from the turns a compaction keeps,
3
+ * on APIs that check a thinking block's signature against the conversation
4
+ * before it (`compaction/kept-thinking.ts` says why and which turns).
5
+ *
6
+ * The boundary comes from the session branch, not from the request's messages:
7
+ * system-reminder rewrites the compaction summary message into a plain user
8
+ * message, so a strip keyed on it found nothing (seen live on Opus 5.5: every
9
+ * request after the compaction was a 400). It is the first `context` hook in
10
+ * the package manifest, before every extension that captures the request's
11
+ * messages for a side call (skill, background, subagents, recap, btw,
12
+ * compaction), so each capture carries the stripped history the session sent.
13
+ */
14
+
15
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
16
+ import { signsThinking, withoutKeptThinking } from "../compaction/kept-thinking.ts";
17
+ import { latestCompaction } from "../lib/compaction-boundary.ts";
18
+
19
+ export default function keptThinkingExtension(pi: ExtensionAPI) {
20
+ pi.on("context", (event, ctx) => {
21
+ const api = ctx.model?.api;
22
+ // Only a signing API pays for the branch walk.
23
+ if (!signsThinking(api)) return undefined;
24
+ const messages = withoutKeptThinking(event.messages, api, latestCompaction(ctx.sessionManager.getBranch())?.time);
25
+ return messages ? { messages } : undefined;
26
+ });
27
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Cron jobs for subagents, Claude Code's way (findings §21): a subagent's
3
+ * `cron_create` stamps its task id on the job, `cron_list` shows it only its
4
+ * own jobs, `cron_delete` refuses another's, and a fire goes to that agent
5
+ * while it lives and is dropped once it has ended.
6
+ *
7
+ * Children never load the background extension, so the subagents extension
8
+ * gives each child proxy tools (`agentCronTools`) that reach the main
9
+ * session's store over the main session's bus: an `AgentCronRequest` on
10
+ * AGENT_CRON_CHANNEL, answered synchronously by the background extension. A
11
+ * fire for an agent's job goes the other way as an `AgentCronFire` on
12
+ * AGENT_CRON_FIRE_CHANNEL; the subagents extension sets `delivered` when the
13
+ * agent took it.
14
+ *
15
+ * Pure: no pi imports.
16
+ */
17
+
18
+ import {
19
+ CRON_CREATE_DESCRIPTION,
20
+ CRON_CREATE_PARAMETERS,
21
+ CRON_DELETE_DESCRIPTION,
22
+ CRON_DELETE_PARAMETERS,
23
+ CRON_LIST_DESCRIPTION,
24
+ CRON_LIST_PARAMETERS,
25
+ } from "../background/cron.ts";
26
+
27
+ export const AGENT_CRON_CHANNEL = "one-code:agent-cron";
28
+ export const AGENT_CRON_FIRE_CHANNEL = "one-code:agent-cron-fire";
29
+
30
+ export type AgentCronRequest =
31
+ | { op: "create"; agentId: string; cwd: string; cron: string; prompt: string; recurring?: boolean; result?: AgentCronResult }
32
+ | { op: "list"; agentId: string; result?: AgentCronResult }
33
+ | { op: "delete"; agentId: string; id: string; result?: AgentCronResult };
34
+
35
+ export interface AgentCronResult {
36
+ text: string;
37
+ isError?: boolean;
38
+ details?: Record<string, unknown>;
39
+ }
40
+
41
+ export interface AgentCronFire {
42
+ agentId: string;
43
+ jobId: string;
44
+ prompt: string;
45
+ /** Set by the subagents extension when a live agent received it. */
46
+ delivered?: boolean;
47
+ }
48
+
49
+ /**
50
+ * cron_create's refusal in an agent that runs to completion (a nested spawn,
51
+ * or any spawn in a one-shot run): a fire reaches only a background agent,
52
+ * and this one ends first.
53
+ */
54
+ export const BLOCKING_RUN_REFUSAL =
55
+ "Nothing was scheduled: this agent runs until its task is done and then ends, so a job it schedules could never fire. Do the work now, or report back so the main session can schedule it.";
56
+
57
+ /** Claude Code's refusal when an agent deletes a job it does not own. */
58
+ export function formatNotOwner(id: string): string {
59
+ return `Cannot delete cron job '${id}': owned by another agent`;
60
+ }
61
+
62
+ interface Emitter {
63
+ emit(channel: string, data: unknown): unknown;
64
+ }
65
+
66
+ /**
67
+ * Whether `agentId` owns a pending job in the main session's store (its
68
+ * `cron_list` count). The subagents extension keeps such an agent resident,
69
+ * since a fire reaches only a live one.
70
+ */
71
+ export function agentOwnsCronJobs(events: Emitter, agentId: string): boolean {
72
+ const request: AgentCronRequest = { op: "list", agentId };
73
+ events.emit(AGENT_CRON_CHANNEL, request);
74
+ return ((request.result?.details?.jobCount as number | undefined) ?? 0) > 0;
75
+ }
76
+
77
+ /** Where a child's cron tools live: only a `resident` (background) run can receive a fire. */
78
+ export interface AgentCronOwner {
79
+ agentId: string;
80
+ cwd: string;
81
+ resident: boolean;
82
+ }
83
+
84
+ /**
85
+ * The three cron tools for a child session, bound to its owner and the MAIN
86
+ * session's bus. Same names, schemas and descriptions as the main session's
87
+ * (background/index.ts). A run that is not resident keeps all three, as in
88
+ * Claude Code, but its cron_create refuses.
89
+ */
90
+ export function agentCronTools(events: Emitter, { agentId, cwd, resident }: AgentCronOwner) {
91
+ const toolResult = (result: AgentCronResult) => ({
92
+ content: [{ type: "text" as const, text: result.text }],
93
+ details: result.details ?? {},
94
+ ...(result.isError ? { isError: true } : {}),
95
+ });
96
+ const ask = (request: AgentCronRequest) => {
97
+ events.emit(AGENT_CRON_CHANNEL, request);
98
+ return toolResult(request.result ?? { text: "The session's cron store is not loaded; nothing was scheduled.", isError: true });
99
+ };
100
+ return [
101
+ {
102
+ name: "cron_create",
103
+ label: "Cron Create",
104
+ description: CRON_CREATE_DESCRIPTION,
105
+ parameters: CRON_CREATE_PARAMETERS,
106
+ async execute(_id: string, params: { cron: string; prompt: string; recurring?: boolean; durable?: boolean }) {
107
+ if (!resident) return toolResult({ text: BLOCKING_RUN_REFUSAL, isError: true });
108
+ return ask({ op: "create", agentId, cwd, cron: params.cron, prompt: params.prompt, recurring: params.recurring });
109
+ },
110
+ },
111
+ {
112
+ name: "cron_list",
113
+ label: "Cron List",
114
+ description: CRON_LIST_DESCRIPTION,
115
+ parameters: CRON_LIST_PARAMETERS,
116
+ async execute() {
117
+ return ask({ op: "list", agentId });
118
+ },
119
+ },
120
+ {
121
+ name: "cron_delete",
122
+ label: "Cron Delete",
123
+ description: CRON_DELETE_DESCRIPTION,
124
+ parameters: CRON_DELETE_PARAMETERS,
125
+ async execute(_id: string, params: { id: string }) {
126
+ return ask({ op: "delete", agentId, id: params.id });
127
+ },
128
+ },
129
+ ];
130
+ }
@@ -31,6 +31,7 @@ import type { PermissionBridge } from "../permissions/subagent-gate.ts";
31
31
  import { withShortCacheRetention } from "./cache-retention.ts";
32
32
  import { hookGateFactory } from "./hook-gate.ts";
33
33
  import { permissionGateFactory } from "./permission-gate.ts";
34
+ import { releaseSideCalls } from "./side-call-run.ts";
34
35
  import { worktreeGuardFactory } from "./worktree-isolation.ts";
35
36
 
36
37
  /** The last assistant message's text (the value an agent run returns). */
@@ -126,7 +127,8 @@ export async function buildAgentLoader(options: AgentLoaderOptions): Promise<Def
126
127
  // Order is load-bearing, mirroring the main session's extension order:
127
128
  // hooks first (a hook's updatedInput must be what every guard judges),
128
129
  // then the worktree git-isolation guard, then the permission gate.
129
- ...(options.getHookBridge ? [hookGateFactory(options.getHookBridge, { agentTypeOf: options.agentTypeOf, neverGate: options.neverGate })] : []),
130
+ // Permission-autoallowed orchestration tools still run the user's hooks.
131
+ ...(options.getHookBridge ? [hookGateFactory(options.getHookBridge, { agentTypeOf: options.agentTypeOf })] : []),
130
132
  worktreeGuardFactory(options.cwd),
131
133
  permissionGateFactory(options.cwd, os.homedir(), options.neverGate, options.getPermissionBridge),
132
134
  ...(options.extraFactories ?? []),
@@ -181,3 +183,15 @@ export async function openChildSession(options: OpenChildSessionOptions): Promis
181
183
  await session.bindExtensions({ onError: options.onError });
182
184
  return session;
183
185
  }
186
+
187
+ /**
188
+ * Dispose a child opened by openChildSession. `dispose()` never emits
189
+ * `session_shutdown`, so the child's side-call keys (its web_fetch reader),
190
+ * which that event releases in a main session, are released here
191
+ * (lib/side-call-run.ts).
192
+ */
193
+ export function disposeChildSession(session: AgentSession): void {
194
+ const sessionId = session.sessionManager.getSessionId();
195
+ session.dispose();
196
+ releaseSideCalls(sessionId);
197
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The agent view's shared half: while the user views an agent (the subagents
3
+ * panel's Enter-to-view), the editor targets that agent, as Claude Code
4
+ * 2.1.283's does (findings §40). A label sits on the editor's top border, the
5
+ * empty editor shows `Message @<label>…`, and what the user submits goes to
6
+ * the agent in Claude Code's mid-turn wrapper. The subagents extension owns
7
+ * the view and announces it over `AGENT_VIEW_CHANNEL`; the branding extension
8
+ * owns the editor and paints it (extensions share no module state).
9
+ */
10
+
11
+ import { fitPainted, visibleWidth } from "./text-width.ts";
12
+ import { cutPlainText } from "./tui-render.ts";
13
+
14
+ /** `{ target }` while an agent is viewed, `{}` when the view returns to main. */
15
+ export const AGENT_VIEW_CHANNEL = "one-code:agent-view";
16
+
17
+ export interface AgentViewTarget {
18
+ /** The top-border label: `@<name>` for a fork, the run's description otherwise. */
19
+ badge: string;
20
+ /** The empty editor's placeholder: `Message @<name or agent type>…`. */
21
+ placeholder: string;
22
+ }
23
+
24
+ export interface AgentViewAnnouncement {
25
+ target?: AgentViewTarget;
26
+ }
27
+
28
+ /** The slice of a live run the target is built from. */
29
+ export interface ViewedRun {
30
+ name: string;
31
+ agentType: string;
32
+ label: string;
33
+ }
34
+
35
+ /**
36
+ * The editor target for a viewed run, Claude Code's shapes: a fork shows
37
+ * `@what-word-is` on the border and `Message @what-word-is…`; a regular agent
38
+ * shows its description on the border and `Message @general-purpose…`.
39
+ */
40
+ export function agentViewTarget(run: ViewedRun, fork: boolean): AgentViewTarget {
41
+ const handle = fork ? run.name : run.agentType;
42
+ return { badge: fork ? `@${run.name}` : run.label, placeholder: `Message @${handle}…` };
43
+ }
44
+
45
+ /**
46
+ * Claude Code's wrapper for a message the user types at an agent, idle or
47
+ * running (findings §40), verbatim.
48
+ */
49
+ export function userMessageForAgent(text: string): string {
50
+ return `The user sent a new message while you were working:\n${text}\n\nThis is how Claude Code surfaces messages the user sends mid-turn — within the running turn, often alongside the next tool result, rather than as a separate conversation turn. Address the message above as you continue this turn.`;
51
+ }
52
+
53
+ const USER_MESSAGE_OPENER = "The user sent a new message while you were working:\n";
54
+ const USER_MESSAGE_CLOSER = "\n\nThis is how Claude Code surfaces messages the user sends mid-turn";
55
+
56
+ /** The user's own text inside `userMessageForAgent`'s wrapper, or undefined for any other prompt. */
57
+ export function unwrapUserMessage(prompt: string): string | undefined {
58
+ if (!prompt.startsWith(USER_MESSAGE_OPENER)) return undefined;
59
+ const end = prompt.lastIndexOf(USER_MESSAGE_CLOSER);
60
+ return end < USER_MESSAGE_OPENER.length ? undefined : prompt.slice(USER_MESSAGE_OPENER.length, end);
61
+ }
62
+
63
+ /**
64
+ * Draw `badge` (already painted, padding included, `badgeWidth` columns) at the
65
+ * right end of the editor's top border, followed by one border glyph:
66
+ * `─── @name ─`. The rest of the border, and anything pi embeds at its left
67
+ * (the working status), keeps its paint. No-op when the border is too narrow.
68
+ */
69
+ export function applyBorderBadge(lines: string[], badge: string, badgeWidth: number, borderGlyph: string): string[] {
70
+ const top = lines[0];
71
+ if (top === undefined) return lines;
72
+ const width = visibleWidth(top);
73
+ const tail = badgeWidth + 1;
74
+ if (width < tail + 4) return lines;
75
+ const head = fitPainted(top, width - tail).text;
76
+ const out = lines.slice();
77
+ out[0] = `${head}\x1b[0m${badge}${borderGlyph}`;
78
+ return out;
79
+ }
80
+
81
+ /** The label cut to fit a border of `width` columns, keeping room for the border itself. */
82
+ export function fitBadge(label: string, width: number): string {
83
+ const room = Math.floor(width / 2) - 3;
84
+ return room <= 1 ? "" : cutPlainText(label, room);
85
+ }
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Recognising an Anthropic Messages request body inside a `before_provider_request`
3
3
  * payload (pure). Shared by context-management (clear_thinking), compaction
4
- * (its replayed request) and tool-search (deferred tool definitions).
4
+ * (its replayed request), tool-search (deferred tool definitions) and
5
+ * idle-compact (the cache lifetime).
5
6
  */
6
7
 
7
8
  /** Anthropic Messages API shape: `messages` + `max_tokens`, and not an OpenAI `input`. */
@@ -13,3 +14,83 @@ export function looksLikeAnthropicRequest(payload: unknown): boolean {
13
14
  const model = typeof record.model === "string" ? record.model : "";
14
15
  return model.includes("claude") || typeof record.max_tokens === "number";
15
16
  }
17
+
18
+ /**
19
+ * The payload with `betas` added, each once, after the ones pi set. pi-ai 1.0
20
+ * sends `payload.betas` as the final `anthropic-beta` header (it wins over a
21
+ * configured header), so a beta goes here, never into the headers (findings
22
+ * §54). The payload is returned unchanged when nothing is missing.
23
+ */
24
+ export function withBetas<T extends Record<string, unknown>>(payload: T, betas: readonly string[]): T {
25
+ const existing: unknown[] = Array.isArray(payload.betas) ? payload.betas : [];
26
+ const missing = [...new Set(betas)].filter((beta) => !existing.includes(beta));
27
+ if (missing.length === 0) return payload;
28
+ return { ...payload, betas: [...existing, ...missing] };
29
+ }
30
+
31
+ /** Anthropic's beta for a `role: "system"` message after the first one. */
32
+ export const MID_CONVERSATION_SYSTEM_BETA = "mid-conversation-system-2026-04-07";
33
+ /** Anthropic's beta for a system message's `clear_at`. */
34
+ export const CLEAR_AT_BETA = "mid-conversation-system-clear-at-2026-08-21";
35
+ /** Anthropic's beta for reference-form `tool_addition` blocks. */
36
+ export const MID_CONVERSATION_TOOL_CHANGES_BETA = "mid-conversation-tool-changes-2026-07-01";
37
+
38
+ type Message = { role?: unknown; content?: unknown };
39
+ type Block = Record<string, unknown> & { cache_control?: unknown };
40
+
41
+ /** pi's directive-only effort message, which cannot carry a cache mark. */
42
+ export function isEmptySystemMessage(message: Message | undefined): boolean {
43
+ return message?.role === "system" && Array.isArray(message.content) && message.content.length === 0;
44
+ }
45
+
46
+ /** A system message with a `clear_at` nudge: a string body, and Anthropic refuses a cache mark on it. */
47
+ function isClearAtMessage(message: Message): boolean {
48
+ return message?.role === "system" && "clear_at" in (message as object);
49
+ }
50
+
51
+ /**
52
+ * The messages with pi's conversation cache mark on the last block that can
53
+ * carry it. pi marks the last block of the last message it built; system
54
+ * messages added after it in `before_provider_request` (the context message,
55
+ * the per-turn budget, a tool addition) would otherwise sit outside the mark,
56
+ * so it moves onto the last one, as Claude Code marks its own. pi's empty
57
+ * effort messages and a `clear_at` nudge are skipped over. Unchanged when the
58
+ * mark already sits there or no added system message ends the request.
59
+ */
60
+ export function reseatMessageMark<T extends Message>(messages: T[]): T[] {
61
+ let target = messages.length - 1;
62
+ while (target >= 0 && (isEmptySystemMessage(messages[target]) || isClearAtMessage(messages[target]))) target--;
63
+ const tail = messages[target];
64
+ if (tail?.role !== "system" || !Array.isArray(tail.content) || tail.content.length === 0) return messages;
65
+ const tailBlocks = tail.content as Block[];
66
+ if (tailBlocks[tailBlocks.length - 1].cache_control !== undefined) return messages;
67
+ let from = target - 1;
68
+ while (from >= 0 && messages[from]?.role === "system") from--;
69
+ const source = messages[from];
70
+ if (!source || !Array.isArray(source.content) || source.content.length === 0) return messages;
71
+ const sourceBlocks = source.content as Block[];
72
+ const { cache_control, ...unmarked } = sourceBlocks[sourceBlocks.length - 1];
73
+ if (cache_control === undefined) return messages;
74
+ const copy = [...messages];
75
+ copy[from] = { ...source, content: [...sourceBlocks.slice(0, -1), unmarked] };
76
+ copy[target] = { ...tail, content: [...tailBlocks.slice(0, -1), { ...tailBlocks[tailBlocks.length - 1], cache_control }] };
77
+ return copy;
78
+ }
79
+
80
+ /**
81
+ * Whether a request body caches with a one-hour TTL: a breakpoint on the
82
+ * system, the tools or a message carries `cache_control.ttl: "1h"` (pi's long
83
+ * retention on Anthropic, through pi's own compat gating, so the body is the
84
+ * ground truth). OpenAI bodies have no breakpoints and answer false.
85
+ */
86
+ export function hasOneHourCache(payload: unknown): boolean {
87
+ if (!payload || typeof payload !== "object") return false;
88
+ const body = payload as { system?: unknown; tools?: unknown; messages?: unknown };
89
+ const list = (value: unknown): unknown[] => (Array.isArray(value) ? value : []);
90
+ const oneHour = (block: unknown) => (block as { cache_control?: { ttl?: unknown } } | null)?.cache_control?.ttl === "1h";
91
+ return (
92
+ list(body.system).some(oneHour) ||
93
+ list(body.tools).some(oneHour) ||
94
+ list(body.messages).some((message) => oneHour(message) || list((message as { content?: unknown } | null)?.content).some(oneHour))
95
+ );
96
+ }