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
@@ -1,43 +1,67 @@
1
1
  /**
2
- * claude-context extension — assembles Claude Code's `# claudeMd` context block
3
- * (CLAUDE.md files + MEMORY.md index + userEmail + currentDate) and injects it as
4
- * a `<system-reminder>` at the front of the first user message, matching Claude
5
- * Code byte-for-byte (see extensions/lib/claude-context.ts for the format).
6
- *
7
- * The block is emitted `first-prepend` at CONTEXT_ORDER.claudeMd — last in Claude
8
- * Code's context stack (deferred tools → agents → MCP → skills → claudeMd), just
9
- * before the user's text. It rides the reminder queue (transient per-request via
10
- * pi's `context` event), so it never persists to the session and never doubles up
11
- * on resume.
2
+ * claude-context extension — assembles Claude Code's three first-message context
3
+ * reminders and queues them `first-prepend` (lib/claude-context.ts has the
4
+ * formats): the instructions block (CLAUDE.md files + MEMORY.md index) at
5
+ * CONTEXT_ORDER.claudeMd, the context block (userEmail + the git snapshot) at
6
+ * CONTEXT_ORDER.context, and the date at CONTEXT_ORDER.date, which on a model
7
+ * that takes a mid-conversation system message rides that message instead
8
+ * (system-reminder, lib/system-role.ts). They ride the reminder queue
9
+ * (per-request via pi's `context` event). system-reminder persists a hidden
10
+ * snapshot so a resume retains the original facts without doubling the blocks.
12
11
  *
13
12
  * When ONECODE.md files exist, this extension also emits a separate `# oneCodeMd`
14
- * block at CONTEXT_ORDER.oneCodeMd — after # claudeMd, so One Code-specific
15
- * instructions take precedence over CLAUDE.md. Keeping them out of # claudeMd
16
- * leaves that block byte-exact with Claude Code.
13
+ * block at CONTEXT_ORDER.oneCodeMd — after the instructions block, so One
14
+ * Code-specific instructions take precedence over CLAUDE.md. Keeping them out
15
+ * of that block leaves it byte-exact with Claude Code.
17
16
  *
18
17
  * Paths are re-derived from home/cwd here rather than shared with the memory
19
- * extension (jiti gives each extension its own module instance). CLAUDE.md is no
20
- * longer put in the system prompt, and MEMORY.md is no longer a separate reminder
21
- * — both fold into this one block, as Claude Code does.
18
+ * extension (jiti gives each extension its own module instance).
22
19
  */
23
20
 
24
21
  import { execFileSync } from "node:child_process";
25
22
  import { readFileSync } from "node:fs";
26
23
  import os from "node:os";
27
- import { join } from "node:path";
28
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
29
- import { buildClaudeMdBlock, buildOneCodeBlock, discoverContextFiles, discoverOneCodeFiles } from "../lib/claude-context.ts";
30
- import { projectMemoryDir, truncateIndex } from "../lib/memory.ts";
31
- import { claudeConfigDir, oneCodeStateDir } from "../lib/paths.ts";
32
- import { CONTEXT_ORDER, REMINDER_CHANNEL } from "../lib/reminders.ts";
24
+ import { dirname } from "node:path";
25
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
26
+ import {
27
+ buildClaudeMdBlock,
28
+ buildContextBlock,
29
+ buildOneCodeBlock,
30
+ collectImportedPaths,
31
+ dateBlock,
32
+ dateChangeReminder,
33
+ discoverContextFiles,
34
+ discoverOneCodeFiles,
35
+ externalInstructionIncludes,
36
+ localDate,
37
+ instructionRule,
38
+ nestedInstructionFiles,
39
+ nestedInstructionText,
40
+ } from "../lib/claude-context.ts";
41
+ import { collectGitStatus, GIT_SNAPSHOT_OWNER_CHANNEL } from "../lib/git-status.ts";
42
+ import { readMemoryIndex } from "../lib/memory-index.ts";
43
+ import { claudeConfigDir, oneCodeStateDir, tryRealpath } from "../lib/paths.ts";
44
+ import { CONTEXT_ORDER, REMINDER_CHANNEL, type ReminderEntry } from "../lib/reminders.ts";
45
+ import { inContextEntries } from "../lib/compaction-boundary.ts";
46
+ import { CONTEXT_BASELINE_CHANNEL, CONTEXT_FACTS_REFRESH_CHANNEL, contextStackOnBranch, restoredContext, type ContextStackSnapshot } from "../lib/context-stack.ts";
47
+ import { compactionGitStatus, contextFactsBaseline, DATE_CHANGE_KEY, legacyResumeFactsNotice, RESUME_FACTS_KEY, resumeFactsNotice, storedFactsBaseline, type ContextFactsBaseline } from "../lib/context-facts.ts";
48
+ import { resolveToolPath } from "../lib/tool-path.ts";
49
+ import { sessionWorkCwd, WORKTREE_CHANNEL, type WorktreeLocation } from "../lib/worktree-channel.ts";
50
+ import { pathArgument } from "../auto-mode/paths.ts";
51
+ import { HARNESS_GIT_CONFIG } from "../lib/git.ts";
52
+ import { EXTERNAL_INCLUDES_NO, EXTERNAL_INCLUDES_NONE, EXTERNAL_INCLUDES_SETTING, EXTERNAL_INCLUDES_YES, externalIncludesDialog, persistExternalIncludesApproval, readExternalIncludesApproval } from "../lib/claude-external-includes.ts";
53
+ import { registerLocalCommand } from "../lib/local-command.ts";
54
+ import { consentDialog, installConsentDialogs, startupConsentReady } from "../lib/consent-dialogs.ts";
33
55
 
34
56
  const REMINDER_KEY = "claude-context";
35
57
  const ONECODE_REMINDER_KEY = "one-code-context";
58
+ const CONTEXT_REMINDER_KEY = "claude-context-context";
59
+ const DATE_REMINDER_KEY = "claude-context-date";
36
60
 
37
61
  /** The account email Claude Code stamps as `# userEmail`. git config is our proxy. */
38
62
  function resolveEmail(cwd: string): string | null {
39
63
  try {
40
- const email = execFileSync("git", ["config", "user.email"], { cwd, encoding: "utf8" }).trim();
64
+ const email = execFileSync("git", [...HARNESS_GIT_CONFIG, "config", "user.email"], { cwd, encoding: "utf8" }).trim();
41
65
  if (email) return email;
42
66
  } catch {
43
67
  // no git / no config — fall through
@@ -45,55 +69,276 @@ function resolveEmail(cwd: string): string | null {
45
69
  return process.env.GIT_AUTHOR_EMAIL?.trim() || process.env.EMAIL?.trim() || null;
46
70
  }
47
71
 
48
- function readMemoryIndex(cwd: string): { path: string; content: string } | null {
49
- const dir = projectMemoryDir(cwd, os.homedir());
50
- const path = join(dir, "MEMORY.md");
72
+ function readOrEmpty(path: string): string {
51
73
  try {
52
- const raw = readFileSync(path, "utf8");
53
- if (!raw.trim()) return null;
54
- return { path, content: truncateIndex(raw) };
74
+ return readFileSync(path, "utf8");
55
75
  } catch {
56
- return null;
76
+ return "";
57
77
  }
58
78
  }
59
79
 
80
+ /** A tool result and the nested instruction files it carried into context (`remember`). */
81
+ const NESTED_SHOWN_ENTRY = "one-code:nested-instructions-shown";
82
+
60
83
  export default function claudeContextExtension(pi: ExtensionAPI) {
61
- pi.on("session_start", (_event, ctx) => {
62
- // The # claudeMd block carries the CLAUDE.md family, falling back to a
63
- // directory's AGENTS.md when it has no CLAUDE.md (CLAUDE.md > AGENTS.md). It
64
- // stays byte-exact with Claude Code wherever CLAUDE.md is present, since
65
- // AGENTS.md only fills in for a missing one. ONECODE.md rides its own
66
- // higher-precedence block below.
67
- const inner = buildClaudeMdBlock({
68
- contextFiles: discoverContextFiles({
69
- cwd: ctx.cwd,
70
- homeClaudeDir: claudeConfigDir(),
71
- agentsFallback: true,
72
- home: os.homedir(),
73
- }),
74
- memoryIndex: readMemoryIndex(ctx.cwd),
75
- email: resolveEmail(ctx.cwd),
76
- // Per-session date, matching the cached Environment section; Claude Code's
77
- // block changes only across days too.
78
- date: new Date().toISOString().slice(0, 10),
84
+ const resetConsentDialogs = installConsentDialogs(pi.events);
85
+ /** The account email stand-in, resolved at session start. */
86
+ let email: string | null = null;
87
+ /** Claude Code's git snapshot, taken once at the conversation's first turn; undefined until then. */
88
+ let gitStatus: string | null | undefined;
89
+ /**
90
+ * Only the main session takes the snapshot, as before it moved here: its
91
+ * system-prompt extension (never loaded in a child) claims it at session
92
+ * start. A subagent or workflow agent would otherwise run its own git
93
+ * commands, synchronously on the shared event loop, for every child.
94
+ */
95
+ let takesGitSnapshot = false;
96
+ pi.events.on(GIT_SNAPSHOT_OWNER_CHANNEL, () => {
97
+ takesGitSnapshot = true;
98
+ });
99
+ /** The date the date reminder carries. */
100
+ let blockDate = "";
101
+ /** The date the model was last told: the reminder's, or a later date-change notice's. */
102
+ let shownDate = "";
103
+ let hadInstructions = false;
104
+ let hadOneCode = false;
105
+ /**
106
+ * Instruction files in context, by real path: the startup block's files and
107
+ * their imports (`startupShown`, fixed for the session), plus nested files
108
+ * attached, their imports, and files the model read itself.
109
+ */
110
+ let startupShown = new Set<string>();
111
+ let attachedNested = new Set<string>();
112
+ /** Where a nested instruction actually landed: a persisted result or a pinned request tail. */
113
+ const shownByResult = new Map<string, Set<string>>();
114
+ /** Nested files queued on a read's result, not yet sent in a request. */
115
+ const pendingNested = new Map<string, string[]>();
116
+ const remember = (toolCallId: string | undefined, keys: Iterable<string>) => {
117
+ if (!toolCallId) return;
118
+ const shown = shownByResult.get(toolCallId) ?? new Set<string>();
119
+ const before = shown.size;
120
+ for (const key of keys) shown.add(key);
121
+ if (shown.size === before) return;
122
+ shownByResult.set(toolCallId, shown);
123
+ // Recorded on the branch, so a resume or a /tree switch knows what is already in context.
124
+ pi.appendEntry(NESTED_SHOWN_ENTRY, { toolCallId, keys: [...shown] });
125
+ };
126
+ /** Rebuild what the branch's own results showed (a resume, a /tree switch), then keep what is still in context. */
127
+ const restoreAttachments = (ctx: ExtensionContext) => {
128
+ shownByResult.clear();
129
+ for (const entry of ctx.sessionManager.getBranch() as { type: string; customType?: string; data?: unknown }[]) {
130
+ if (entry.type !== "custom" || entry.customType !== NESTED_SHOWN_ENTRY) continue;
131
+ const data = entry.data as { toolCallId?: unknown; keys?: unknown } | undefined;
132
+ if (typeof data?.toolCallId !== "string" || !Array.isArray(data.keys)) continue;
133
+ shownByResult.set(data.toolCallId, new Set(data.keys.filter((key): key is string => typeof key === "string")));
134
+ }
135
+ keepRetainedAttachments(ctx);
136
+ };
137
+ const keepRetainedAttachments = (ctx: ExtensionContext) => {
138
+ attachedNested = new Set(startupShown);
139
+ const kept = new Set(inContextEntries(ctx.sessionManager.getBranch()).flatMap((entry) =>
140
+ entry.type === "message" && entry.message.role === "toolResult" ? [entry.message.toolCallId] : [],
141
+ ));
142
+ for (const [id, keys] of shownByResult) {
143
+ if (kept.has(id)) for (const key of keys) attachedNested.add(key);
144
+ else shownByResult.delete(id);
145
+ }
146
+ };
147
+ /** The entered worktree: reads there resolve below its root, not the session's original directory. */
148
+ let entered: WorktreeLocation | undefined;
149
+ pi.events.on(WORKTREE_CHANNEL, (data) => {
150
+ const location = data as WorktreeLocation | null | undefined;
151
+ entered = location?.path ? location : undefined;
152
+ });
153
+ /** The instruction rule, read with the startup block (it is settings, read once a session). */
154
+ let rule: ReturnType<typeof instructionRule> | undefined;
155
+ let includeExternal = false;
156
+ let approvalPending: Promise<void> | undefined;
157
+ let approvalAbort = new AbortController();
158
+ let sessionGeneration = 0;
159
+ let requestStarted = false;
160
+
161
+ const emitDate = (date: string) => {
162
+ blockDate = date;
163
+ shownDate = date;
164
+ pi.events.emit(REMINDER_CHANNEL, {
165
+ text: dateBlock(date),
166
+ scope: "every-turn",
167
+ key: DATE_REMINDER_KEY,
168
+ placement: "first-prepend",
169
+ order: CONTEXT_ORDER.date,
79
170
  });
80
- if (inner) {
171
+ };
172
+
173
+ let facts: ContextFactsBaseline | undefined;
174
+ let pendingResume: ContextStackSnapshot | undefined;
175
+ const baseline = () => ({ startupShown: [...startupShown], shownDate, facts });
176
+ const publishBaseline = () => pi.events.emit(CONTEXT_BASELINE_CHANNEL, { key: "claude-context", value: baseline() });
177
+ const readFiles = (cwd: string) => {
178
+ const oneCodeFiles = discoverOneCodeFiles({ cwd, homeOneCodeDir: oneCodeStateDir(), home: os.homedir(), includeExternal });
179
+ return {
180
+ contextFiles: discoverContextFiles({ cwd, homeClaudeDir: claudeConfigDir(), rule: instructionRule(os.homedir()), home: os.homedir(), includeExternal }),
181
+ memoryIndex: readMemoryIndex(cwd),
182
+ oneCodeFiles,
183
+ oneCode: buildOneCodeBlock(oneCodeFiles),
184
+ };
185
+ };
186
+ /** What a stored snapshot says the model was shown: its facts, the files its blocks carry, and its dates. */
187
+ const adoptSnapshot = (snapshot: ContextStackSnapshot) => {
188
+ const saved = snapshot.baselines["claude-context"] as { startupShown?: unknown; shownDate?: unknown; facts?: unknown } | undefined;
189
+ facts = storedFactsBaseline(saved?.facts);
190
+ startupShown = new Set(Array.isArray(saved?.startupShown) ? saved.startupShown.filter((p): p is string => typeof p === "string") : []);
191
+ attachedNested = new Set(startupShown);
192
+ blockDate = snapshot.stack.find((entry) => entry.key === DATE_REMINDER_KEY)?.text.match(/^Today's date is (\d{4}-\d{2}-\d{2})\.$/)?.[1] ?? "";
193
+ shownDate = typeof saved?.shownDate === "string" ? saved.shownDate : blockDate;
194
+ hadInstructions = snapshot.stack.some((entry) => entry.key === REMINDER_KEY);
195
+ hadOneCode = snapshot.stack.some((entry) => entry.key === ONECODE_REMINDER_KEY);
196
+ };
197
+ let files: ReturnType<typeof readFiles> | undefined;
198
+ const adoptFiles = (current: ReturnType<typeof readFiles>) => {
199
+ files = current;
200
+ // A file either startup block carries (or imports) is never attached again on a read.
201
+ startupShown = new Set([...current.contextFiles, ...current.oneCodeFiles].flatMap((file) =>
202
+ [file.path, ...(file.imported ?? collectImportedPaths(readOrEmpty(file.path), dirname(file.path), { home: os.homedir() }))],
203
+ ).map((path) => tryRealpath(path) ?? path));
204
+ attachedNested = new Set(startupShown);
205
+ rule = instructionRule(os.homedir());
206
+ };
207
+ const snapshotGit = (cwd: string) => {
208
+ const tools = pi.getActiveTools();
209
+ const shellTool = tools.includes("powershell") && !tools.includes("bash") ? "powershell" : "bash";
210
+ return takesGitSnapshot ? collectGitStatus(cwd, undefined, shellTool) : null;
211
+ };
212
+
213
+ const externalPaths = (cwd: string) => externalInstructionIncludes({ cwd, homeClaudeDir: claudeConfigDir(), rule: instructionRule(os.homedir()), home: os.homedir() });
214
+ const saveApproval = (ctx: ExtensionContext, approved: boolean) => {
215
+ includeExternal = approved;
216
+ try { persistExternalIncludesApproval(ctx.cwd, os.homedir(), approved); }
217
+ catch (error) { ctx.ui.notify(`Could not remember external CLAUDE.md include approval: ${String(error)}`, "error"); }
218
+ };
219
+ const refreshUnsentInstructions = (cwd: string) => {
220
+ if (requestStarted || pendingResume) return;
221
+ const current = readFiles(cwd);
222
+ adoptFiles(current);
223
+ const text = buildClaudeMdBlock(current);
224
+ if (text) pi.events.emit(REMINDER_CHANNEL, { text, scope: "every-turn", key: REMINDER_KEY, placement: "first-prepend", order: CONTEXT_ORDER.claudeMd });
225
+ if (current.oneCode) pi.events.emit(REMINDER_CHANNEL, { text: current.oneCode, scope: "every-turn", key: ONECODE_REMINDER_KEY, placement: "first-prepend", order: CONTEXT_ORDER.oneCodeMd });
226
+ publishBaseline();
227
+ };
228
+ const askApproval = async (ctx: ExtensionContext, paths: string[], afterStartup = false) => {
229
+ const gen = sessionGeneration;
230
+ const signal = approvalAbort.signal;
231
+ // No is first and focused, as in Claude Code. Escape is also a remembered no;
232
+ // a shutdown/superseded session is not an answer at all.
233
+ const choice = await consentDialog(pi.events, () => ctx.ui.select(externalIncludesDialog(paths, os.homedir()), [EXTERNAL_INCLUDES_NO, EXTERNAL_INCLUDES_YES], { signal }), afterStartup);
234
+ if (signal.aborted || gen !== sessionGeneration) return;
235
+ saveApproval(ctx, choice === EXTERNAL_INCLUDES_YES);
236
+ refreshUnsentInstructions(ctx.cwd);
237
+ };
238
+ registerLocalCommand(pi, "config", {
239
+ description: "Configure external CLAUDE.md includes for this project",
240
+ reportsResult: true,
241
+ handler: async (_args, ctx) => {
242
+ if (!ctx.hasUI) {
243
+ const text = "/config requires an interactive UI to change external CLAUDE.md include approval.";
244
+ process.stderr.write(`${text}\n`);
245
+ return text;
246
+ }
247
+ const gen = sessionGeneration;
248
+ startupConsentReady(pi.events);
249
+ await approvalPending;
250
+ if (gen !== sessionGeneration || approvalAbort.signal.aborted) return;
251
+ const paths = externalPaths(ctx.cwd);
252
+ if (!paths.length) {
253
+ const text = EXTERNAL_INCLUDES_NONE;
254
+ ctx.ui.notify(text, "info");
255
+ return text;
256
+ }
257
+ const row = `${EXTERNAL_INCLUDES_SETTING}: ${includeExternal ? "true" : "false"}`;
258
+ const picked = await consentDialog(pi.events, () => ctx.ui.select("Config", [row], { signal: approvalAbort.signal }));
259
+ if (picked !== row || gen !== sessionGeneration || approvalAbort.signal.aborted) return;
260
+ if (includeExternal) {
261
+ saveApproval(ctx, false);
262
+ refreshUnsentInstructions(ctx.cwd);
263
+ } else await askApproval(ctx, paths);
264
+ // As in Claude Code, this changes future loads, never retracts text or
265
+ // rewrites the frozen first-message block after a request was sent.
266
+ return `${EXTERNAL_INCLUDES_SETTING}: ${includeExternal ? "true" : "false"}`;
267
+ },
268
+ });
269
+ const drainApproval = async () => { startupConsentReady(pi.events); await approvalPending; };
270
+ pi.on("before_agent_start", drainApproval);
271
+ pi.on("session_shutdown", () => {
272
+ resetConsentDialogs();
273
+ ++sessionGeneration;
274
+ approvalAbort.abort();
275
+ approvalPending = undefined;
276
+ });
277
+
278
+ pi.on("session_start", (event, ctx) => {
279
+ resetConsentDialogs();
280
+ ++sessionGeneration;
281
+ approvalAbort.abort();
282
+ approvalAbort = new AbortController();
283
+ approvalPending = undefined;
284
+ requestStarted = false;
285
+ const approval = readExternalIncludesApproval(ctx.cwd, os.homedir());
286
+ includeExternal = approval.approved;
287
+ const restored = restoredContext(pi.events);
288
+ pendingResume = restored;
289
+ files = undefined;
290
+ facts = undefined;
291
+ if ((event.reason ?? "startup") === "startup" && ctx.hasUI && !approval.approved && !approval.warningShown) {
292
+ const paths = externalPaths(ctx.cwd);
293
+ if (paths.length) {
294
+ // RPC installs its input reader only AFTER session_start returns.
295
+ // Queue after hooks/MCP consent; gate the first turn, not startup.
296
+ // A dialog that fails is no answer: nothing is approved or remembered, and the turn goes on.
297
+ approvalPending = askApproval(ctx, paths, true).catch(() => {});
298
+ }
299
+ }
300
+ if (restored) {
301
+ adoptSnapshot(restored);
302
+ restoreAttachments(ctx);
303
+ rule = instructionRule(os.homedir());
304
+ gitStatus = null; // The stored snapshot wins; do not take another one.
305
+ publishBaseline();
306
+ return;
307
+ }
308
+ // The instructions block carries the instruction files the mode and Claude
309
+ // Code's instructionFiles pick (lib/claude-context.ts instructionRule): by
310
+ // default the CLAUDE.md family, or the project's AGENTS.md files when it
311
+ // has no CLAUDE.md, byte-exact with Claude Code either way. ONECODE.md
312
+ // rides its own higher-precedence block below.
313
+ const current = readFiles(ctx.cwd);
314
+ adoptFiles(current);
315
+ const instructions = buildClaudeMdBlock(current);
316
+ if (instructions) {
81
317
  pi.events.emit(REMINDER_CHANNEL, {
82
- text: inner,
318
+ text: instructions,
83
319
  scope: "every-turn",
84
320
  key: REMINDER_KEY,
85
321
  placement: "first-prepend",
86
322
  order: CONTEXT_ORDER.claudeMd,
87
- // Claude Code's claudeMd block ends `</system-reminder>\n\n` on the wire.
88
- suffix: "\n\n",
89
323
  });
324
+ } else if (hadInstructions) {
325
+ pi.events.emit(REMINDER_CHANNEL, { remove: true, key: REMINDER_KEY });
90
326
  }
327
+ hadInstructions = instructions !== null;
328
+ email = resolveEmail(ctx.cwd);
329
+ attachedNested = new Set(startupShown);
330
+ shownByResult.clear();
331
+ pendingNested.clear();
332
+ rule = instructionRule(os.homedir());
333
+ // /clear re-fires session_start: the next conversation takes its own snapshot.
334
+ gitStatus = undefined;
335
+ // The user's local date, taken once: the reminder is frozen after the first
336
+ // request, so a later date rides a one-shot (before_agent_start below).
337
+ emitDate(localDate());
91
338
 
92
- // One Code's own instructions ride in a separate block AFTER # claudeMd, so
93
- // they take precedence over CLAUDE.md (higher order = closer to the user text).
94
- const oneCode = buildOneCodeBlock(
95
- discoverOneCodeFiles({ cwd: ctx.cwd, homeOneCodeDir: oneCodeStateDir(), home: os.homedir() }),
96
- );
339
+ // One Code's own instructions ride in a separate block AFTER the instructions
340
+ // block, so they take precedence over CLAUDE.md (higher order = closer to the user text).
341
+ const oneCode = current.oneCode;
97
342
  if (oneCode) {
98
343
  pi.events.emit(REMINDER_CHANNEL, {
99
344
  text: oneCode,
@@ -101,8 +346,151 @@ export default function claudeContextExtension(pi: ExtensionAPI) {
101
346
  key: ONECODE_REMINDER_KEY,
102
347
  placement: "first-prepend",
103
348
  order: CONTEXT_ORDER.oneCodeMd,
104
- suffix: "\n\n",
105
349
  });
350
+ } else if (hadOneCode) {
351
+ pi.events.emit(REMINDER_CHANNEL, { remove: true, key: ONECODE_REMINDER_KEY });
352
+ }
353
+ publishBaseline();
354
+ hadOneCode = oneCode !== null;
355
+ });
356
+
357
+ // Claude Code snapshots git "at the start of the conversation": on the first
358
+ // turn, typed or opened from idle, never in session_start, so the several
359
+ // synchronous git spawns never delay the prompt opening (findings §15). The
360
+ // clip note names the shell tool the model has (PowerShell only without bash).
361
+ pi.on("turn_start", async (_event, ctx) => {
362
+ const gen = sessionGeneration;
363
+ await drainApproval();
364
+ if (gen !== sessionGeneration || approvalAbort.signal.aborted) return;
365
+ requestStarted = true;
366
+ // Check only once, just before the first resumed request. No startup git
367
+ // subprocesses, and no changes to the historical first-message blocks.
368
+ if (pendingResume) {
369
+ const restored = pendingResume;
370
+ pendingResume = undefined;
371
+ // Compare in the directory the facts were read in: a resume inside a worktree entered
372
+ // after the session started would otherwise report every path as changed.
373
+ const cwd = facts?.cwd ?? (facts?.atCompaction ? sessionWorkCwd(entered, ctx.cwd) : ctx.cwd);
374
+ const current = readFiles(cwd);
375
+ const liveGit = snapshotGit(cwd);
376
+ const liveFacts = contextFactsBaseline({ ...current, gitStatus: liveGit, atCompaction: false });
377
+ const text = facts ? resumeFactsNotice(facts, liveFacts) : legacyResumeFactsNotice(restored.stack, {
378
+ instructions: buildClaudeMdBlock(current), email: resolveEmail(cwd), gitStatus: liveGit,
379
+ });
380
+ if (text) pi.events.emit(REMINDER_CHANNEL, { key: RESUME_FACTS_KEY, text });
381
+ }
382
+ if (gitStatus !== undefined) return;
383
+ gitStatus = snapshotGit(ctx.cwd);
384
+ if (files) facts = contextFactsBaseline({ ...files, gitStatus, atCompaction: false, cwd: ctx.cwd });
385
+ publishBaseline();
386
+ const context = buildContextBlock({ email, gitStatus });
387
+ if (!context) return;
388
+ pi.events.emit(REMINDER_CHANNEL, {
389
+ text: context,
390
+ scope: "every-turn",
391
+ key: CONTEXT_REMINDER_KEY,
392
+ placement: "first-prepend",
393
+ order: CONTEXT_ORDER.context,
394
+ });
395
+ });
396
+
397
+ // A session that crosses local midnight learns the new date on its next
398
+ // turn, as a one-shot on that turn's prompt (Claude Code's notice), so the
399
+ // frozen reminder on message 1 and the cached prefix stay as they are.
400
+ const announceDate = () => {
401
+ if (!blockDate) return;
402
+ const today = localDate();
403
+ if (today === shownDate) return;
404
+ shownDate = today;
405
+ pi.events.emit(REMINDER_CHANNEL, { key: DATE_CHANGE_KEY, text: dateChangeReminder(today) });
406
+ publishBaseline();
407
+ };
408
+ pi.on("before_agent_start", announceDate);
409
+
410
+ // All successful compactions (manual, automatic and idle) fire this hook.
411
+ // The summary starts a new prefix: refresh facts silently, then persist the
412
+ // replacement even if the process exits before another model request.
413
+ pi.on("session_compact", (_event, ctx) => {
414
+ pendingResume = undefined;
415
+ const cwd = sessionWorkCwd(entered, ctx.cwd);
416
+ const current = readFiles(cwd);
417
+ adoptFiles(current);
418
+ // Only discarded carriers need reattachment; pi can retain the recent read/tool-result tail.
419
+ keepRetainedAttachments(ctx);
420
+ email = resolveEmail(cwd);
421
+ gitStatus = snapshotGit(cwd);
422
+ blockDate = shownDate = localDate();
423
+ facts = contextFactsBaseline({ ...current, gitStatus, atCompaction: true, cwd });
424
+ const entries: ReminderEntry[] = [];
425
+ const add = (key: string, text: string | null, order: number) => {
426
+ if (text) entries.push({ key, text, order, placement: "first-prepend" });
427
+ };
428
+ add(REMINDER_KEY, buildClaudeMdBlock(current), CONTEXT_ORDER.claudeMd);
429
+ add(ONECODE_REMINDER_KEY, current.oneCode, CONTEXT_ORDER.oneCodeMd);
430
+ add(CONTEXT_REMINDER_KEY, buildContextBlock({ email, gitStatus: compactionGitStatus(gitStatus) }), CONTEXT_ORDER.context);
431
+ add(DATE_REMINDER_KEY, dateBlock(blockDate), CONTEXT_ORDER.date);
432
+ pi.events.emit(CONTEXT_FACTS_REFRESH_CHANNEL, { entries, baseline: baseline() });
433
+ });
434
+
435
+ // A branch switch leaves the attachments of the branch left behind; the new one may lack them.
436
+ // Its facts are the selected branch's (system-reminder restores its blocks): a branch from
437
+ // before a compaction still shows the session-start facts, and a later compaction or date
438
+ // notice compares against those.
439
+ pi.on("session_tree", (_event, ctx) => {
440
+ const branch = contextStackOnBranch(ctx.sessionManager.getBranch());
441
+ if (branch) {
442
+ adoptSnapshot(branch);
443
+ if (pendingResume) pendingResume = branch;
444
+ publishBaseline();
445
+ }
446
+ restoreAttachments(ctx);
447
+ pendingNested.clear();
448
+ });
449
+
450
+ // A successful read attaches nested instruction files and matching path rules
451
+ // once each. These are one-shots: never replace the frozen first-prepend block.
452
+ // lib/claude-context.ts owns traversal, matching and source ordering.
453
+ pi.on("tool_result", (event, ctx) => {
454
+ if (event.toolName !== "read" || event.isError) return;
455
+ const raw = pathArgument(event.input);
456
+ if (!raw) return;
457
+ rule ??= instructionRule(os.homedir());
458
+ const filePath = resolveToolPath(raw, ctx.cwd);
459
+ // In a worktree, the directories between are below the worktree's root (its own root files
460
+ // are the shared checkout's, which the startup block carries).
461
+ const files = nestedInstructionFiles({ filePath, cwd: sessionWorkCwd(entered, ctx.cwd), rule, home: os.homedir(), includeExternal });
462
+ // A partial read is not evidence that the entire instruction file is shown.
463
+ const input = event.input as { offset?: number; limit?: number };
464
+ const truncated = (event.details as { truncation?: { truncated?: boolean } } | undefined)?.truncation?.truncated;
465
+ if ((input.offset ?? 1) <= 1 && input.limit == null && !truncated) {
466
+ const readKey = tryRealpath(filePath) ?? filePath;
467
+ attachedNested.add(readKey);
468
+ remember(event.toolCallId, [readKey]);
469
+ }
470
+ // Bound to this read: system-reminder's hook for it has already run, so the
471
+ // queue pins them to this result at the next request; unbound, the next result
472
+ // in a parallel batch took them, beside another file (battery round 7).
473
+ const shown: string[] = [];
474
+ for (const file of files) {
475
+ if (attachedNested.has(file.key)) continue;
476
+ attachedNested.add(file.key);
477
+ shown.push(file.key);
478
+ for (const imported of file.imported) {
479
+ attachedNested.add(imported);
480
+ shown.push(imported);
481
+ }
482
+ pi.events.emit(REMINDER_CHANNEL, { text: nestedInstructionText(file), toolCallId: event.toolCallId });
483
+ }
484
+ if (shown.length > 0) pendingNested.set(event.toolCallId, shown);
485
+ });
486
+
487
+ // Recorded once the request carrying the read's result goes out, so a reload
488
+ // before then (the queued text is not persisted) leaves them unshown.
489
+ pi.on("context", (event) => {
490
+ for (const [toolCallId, keys] of pendingNested) {
491
+ if (!event.messages.some((m) => m.role === "toolResult" && m.toolCallId === toolCallId)) continue;
492
+ remember(toolCallId, keys);
493
+ pendingNested.delete(toolCallId);
106
494
  }
107
495
  });
108
496
  }