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
@@ -11,51 +11,134 @@
11
11
  *
12
12
  * The widget mirrors Claude Code's pinned task list (summary line + ✔/◼/◻
13
13
  * rows). Claude Code toggles it with ctrl+t, but pi reserves that key for
14
- * thinking blocks — `/tasks hide` / `/tasks show` covers it instead.
14
+ * thinking blocks, so alt+t (ctrl+\ on macOS; `taskToggleKey`) and `/tasks
15
+ * hide` / `/tasks show` toggle it here; the key's hint is always on screen.
15
16
  */
16
17
 
17
18
  import { StringEnum } from "@earendil-works/pi-ai";
18
19
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
19
20
  import { Type } from "typebox";
20
21
  import { restoreLatestDetails } from "../lib/branch-restore.ts";
21
- import { DEFER_CHANNEL } from "../lib/deferred.ts";
22
+ import { DEFER_CHANNEL, WITHHOLD_CHANNEL } from "../lib/deferred.ts";
23
+ import { taskToolsEnabled } from "../lib/model-tier.ts";
24
+ import { sessionModelTier } from "../lib/session-model-tier.ts";
22
25
  import { ccToolRenderers, linesComponent, safeThemeBold, safeThemePaint, strike } from "../lib/tui-render.ts";
23
26
  import { REMINDER_CHANNEL } from "../lib/reminders.ts";
24
- import { formatTaskDetails, formatTaskLine, formatTaskList, formatTaskWidget, nudgeMessage, type TaskSnapshot, TaskStore } from "./store.ts";
27
+ import {
28
+ TASK_CREATE_DESCRIPTION,
29
+ TASK_CREATE_PARAMS,
30
+ TASK_GET_DESCRIPTION,
31
+ TASK_GET_PARAMS,
32
+ TASK_LIST_DESCRIPTION,
33
+ TASK_UPDATE_DESCRIPTION,
34
+ TASK_UPDATE_PARAMS,
35
+ } from "./descriptions.ts";
36
+ import {
37
+ FINISHED_LIST_CLEAR_MS,
38
+ formatHiddenTaskWidget,
39
+ formatTaskDetails,
40
+ formatTaskList,
41
+ formatTaskWidget,
42
+ normalizeTaskId,
43
+ nudgeMessage,
44
+ type TaskSnapshot,
45
+ TaskStore,
46
+ } from "./store.ts";
25
47
  import { registerLocalCommand } from "../lib/local-command.ts";
48
+ import { canShowCustomUi } from "../lib/headless-output.ts";
49
+ import { taskToggleKey } from "../lib/keys.ts";
26
50
 
27
51
  interface TaskDetails {
28
52
  taskSnapshot: TaskSnapshot;
29
53
  }
30
54
 
31
55
  const TASK_TOOLS = new Set(["task_create", "task_get", "task_list", "task_update"]);
56
+ const TASK_KEYWORDS = ["task", "todo", "plan", "progress", "dependencies", "tracking"];
32
57
 
33
58
  export default function tasksExtension(pi: ExtensionAPI) {
59
+ const requestTier = sessionModelTier(pi);
34
60
  const store = new TaskStore();
61
+ const toggleKey = taskToggleKey();
35
62
  let widgetHidden = false;
36
63
 
37
64
  const updateWidget = (ctx: ExtensionContext) => {
38
65
  if (!ctx.hasUI) return;
39
- if (widgetHidden || store.list().length === 0) {
66
+ if (store.list().length === 0) {
40
67
  ctx.ui.setWidget("cc-tasks", undefined);
41
68
  return;
42
69
  }
70
+ // RPC forwards line arrays only, and has no terminal shortcut to hide it.
71
+ if (!canShowCustomUi(ctx)) {
72
+ ctx.ui.setWidget("cc-tasks", formatTaskWidget(store));
73
+ return;
74
+ }
43
75
  // Component form so every line passes truncateLine — subjects are
44
76
  // unbounded model text, and pi-tui crashes on an over-wide line.
45
77
  ctx.ui.setWidget("cc-tasks", (_tui, theme) => {
46
78
  const style = { paint: safeThemePaint(theme), bold: safeThemeBold(theme), strike };
47
- return linesComponent(() => formatTaskWidget(store, 12, style));
79
+ return linesComponent(() =>
80
+ widgetHidden
81
+ ? formatHiddenTaskWidget(store, `${toggleKey} to show`, style)
82
+ : formatTaskWidget(store, 12, style, `${toggleKey} to hide`),
83
+ );
48
84
  });
49
85
  };
86
+ const setWidgetHidden = (hidden: boolean, ctx: ExtensionContext) => {
87
+ widgetHidden = hidden;
88
+ updateWidget(ctx);
89
+ };
90
+
91
+ // Claude Code clears a finished list (every task completed) 5 s after it
92
+ // gets there, and the panel goes with it; reopening or adding a task first
93
+ // cancels the clear. Only where there is a widget: a one-shot run keeps its
94
+ // list. The timer is unref'd and cancelled on shutdown, so it never holds
95
+ // the process or fires into a disposed session.
96
+ let clearTimer: ReturnType<typeof setTimeout> | undefined;
97
+ const cancelClear = () => {
98
+ if (clearTimer) clearTimeout(clearTimer);
99
+ clearTimer = undefined;
100
+ };
101
+ const scheduleClear = (ctx: ExtensionContext) => {
102
+ if (!ctx.hasUI || !store.isFinished()) return cancelClear();
103
+ if (clearTimer) return;
104
+ clearTimer = setTimeout(() => {
105
+ clearTimer = undefined;
106
+ if (!store.isFinished()) return;
107
+ store.clear();
108
+ updateWidget(ctx);
109
+ }, FINISHED_LIST_CLEAR_MS);
110
+ clearTimer.unref?.();
111
+ };
50
112
 
51
113
  const reconstructState = (ctx: ExtensionContext) => {
114
+ cancelClear();
52
115
  const details = restoreLatestDetails<TaskDetails>(ctx.sessionManager.getBranch(), TASK_TOOLS, (d) => Boolean(d?.taskSnapshot));
53
116
  store.restore(details?.taskSnapshot);
54
117
  updateWidget(ctx);
55
118
  };
56
119
 
57
- pi.on("session_start", (_event, ctx) => reconstructState(ctx));
120
+ // Claude Code's model gate: frontier models and Sonnet 5+ run without the
121
+ // task tools unless CLAUDE_CODE_ENABLE_TODO_TOOLS is set (lib/model-tier.ts
122
+ // taskToolsEnabled). Re-applied on a model change, so switching to a model
123
+ // that has them brings them back through the deferred listing.
124
+ let withheld = false;
125
+ const applyModelGate = (model: Parameters<typeof taskToolsEnabled>[0]) => {
126
+ const enabled = taskToolsEnabled(model, process.env, requestTier());
127
+ if (enabled === !withheld) return;
128
+ withheld = !enabled;
129
+ for (const name of TASK_TOOLS) {
130
+ if (withheld) pi.events.emit(WITHHOLD_CHANNEL, { name });
131
+ else pi.events.emit(DEFER_CHANNEL, { name, keywords: TASK_KEYWORDS });
132
+ }
133
+ };
134
+
135
+ pi.on("session_start", (_event, ctx) => {
136
+ reconstructState(ctx);
137
+ applyModelGate(ctx.model);
138
+ });
58
139
  pi.on("session_tree", (_event, ctx) => reconstructState(ctx));
140
+ pi.on("model_select", (event) => applyModelGate(event.model));
141
+ pi.on("session_shutdown", () => cancelClear());
59
142
 
60
143
  // Claude Code's periodic task_reminder (TODO_REMINDER_CONFIG): a gentle
61
144
  // nudge once the task tools have gone unused for TURNS_SINCE_WRITE turns,
@@ -71,6 +154,8 @@ export default function tasksExtension(pi: ExtensionAPI) {
71
154
  let turnsSinceReminder = TURNS_BETWEEN_REMINDERS;
72
155
 
73
156
  pi.on("turn_end", () => {
157
+ // Claude Code's reminder needs TaskUpdate in the tool list.
158
+ if (withheld) return;
74
159
  turnsSinceTaskUse++;
75
160
  turnsSinceReminder++;
76
161
  if (turnsSinceTaskUse < TURNS_SINCE_WRITE || turnsSinceReminder < TURNS_BETWEEN_REMINDERS) return;
@@ -86,6 +171,7 @@ export default function tasksExtension(pi: ExtensionAPI) {
86
171
 
87
172
  const result = (text: string, ctx: ExtensionContext, isError = false) => {
88
173
  updateWidget(ctx);
174
+ scheduleClear(ctx);
89
175
  return {
90
176
  content: [{ type: "text" as const, text }],
91
177
  details: { taskSnapshot: store.snapshot() } satisfies TaskDetails,
@@ -97,18 +183,17 @@ export default function tasksExtension(pi: ExtensionAPI) {
97
183
  name: "task_create",
98
184
  label: "Create Task",
99
185
  ...ccToolRenderers("Create Task"),
100
- description:
101
- "Add a task to the session's structured task list. Tasks are addressable by id and can carry owners, metadata, and dependencies — use task_update to change status or link tasks, task_list/task_get to read them. Create tasks for multi-step work (3+ steps) so progress is visible, and mark exactly one in_progress while working on it.",
186
+ description: TASK_CREATE_DESCRIPTION,
102
187
  parameters: Type.Object({
103
- subject: Type.String({ description: "A brief title for the task" }),
104
- description: Type.String({ description: "What needs to be done" }),
105
- activeForm: Type.Optional(Type.String({ description: 'Present continuous form shown while in_progress (e.g. "Running tests")' })),
106
- metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Arbitrary metadata to attach to the task" })),
188
+ subject: Type.String({ description: TASK_CREATE_PARAMS.subject }),
189
+ description: Type.String({ description: TASK_CREATE_PARAMS.description }),
190
+ activeForm: Type.Optional(Type.String({ description: TASK_CREATE_PARAMS.activeForm })),
191
+ metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: TASK_CREATE_PARAMS.metadata })),
107
192
  }),
108
193
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
109
194
  markUsed();
110
195
  const task = store.create(params);
111
- return result(`Created task #${task.id}: ${task.subject}`, ctx);
196
+ return result(`Task #${task.id} created successfully: ${task.subject}`, ctx);
112
197
  },
113
198
  });
114
199
 
@@ -116,9 +201,9 @@ export default function tasksExtension(pi: ExtensionAPI) {
116
201
  name: "task_get",
117
202
  label: "Get Task",
118
203
  ...ccToolRenderers("Get Task"),
119
- description: "Retrieve one task by id: full description, status, owner, and dependency links. Verify blockedBy is empty before starting work on it.",
204
+ description: TASK_GET_DESCRIPTION,
120
205
  parameters: Type.Object({
121
- taskId: Type.String({ description: "The id of the task to retrieve" }),
206
+ taskId: Type.String({ description: TASK_GET_PARAMS.taskId }),
122
207
  }),
123
208
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
124
209
  const task = store.get(params.taskId);
@@ -131,7 +216,7 @@ export default function tasksExtension(pi: ExtensionAPI) {
131
216
  name: "task_list",
132
217
  label: "List Tasks",
133
218
  ...ccToolRenderers("List Tasks", { maxCollapsedLines: 12 }),
134
- description: "List all tasks: id, subject, status, owner, and open blockers. Prefer working on unblocked pending tasks in id order.",
219
+ description: TASK_LIST_DESCRIPTION,
135
220
  parameters: Type.Object({}),
136
221
  async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
137
222
  return result(formatTaskList(store), ctx);
@@ -142,49 +227,43 @@ export default function tasksExtension(pi: ExtensionAPI) {
142
227
  name: "task_update",
143
228
  label: "Update Task",
144
229
  ...ccToolRenderers("Update Task"),
145
- description:
146
- "Update a task: status (pending/in_progress/completed, or deleted to remove it), subject, description, owner, metadata (merge; null deletes a key), and dependencies via addBlocks/addBlockedBy. Mark a task in_progress before starting it and completed only when fully done.",
230
+ description: TASK_UPDATE_DESCRIPTION,
147
231
  parameters: Type.Object({
148
- taskId: Type.String({ description: "The id of the task to update" }),
149
- status: Type.Optional(StringEnum(["pending", "in_progress", "completed", "deleted"] as const)),
150
- subject: Type.Optional(Type.String()),
151
- description: Type.Optional(Type.String()),
152
- activeForm: Type.Optional(Type.String()),
153
- owner: Type.Optional(Type.String({ description: "New owner for the task" })),
154
- metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Metadata keys to merge; a null value deletes the key" })),
155
- addBlocks: Type.Optional(Type.Array(Type.String(), { description: "Task ids that cannot start until this one completes" })),
156
- addBlockedBy: Type.Optional(Type.Array(Type.String(), { description: "Task ids that must complete before this one" })),
232
+ taskId: Type.String({ description: TASK_UPDATE_PARAMS.taskId }),
233
+ subject: Type.Optional(Type.String({ description: TASK_UPDATE_PARAMS.subject })),
234
+ description: Type.Optional(Type.String({ description: TASK_UPDATE_PARAMS.description })),
235
+ activeForm: Type.Optional(Type.String({ description: TASK_UPDATE_PARAMS.activeForm })),
236
+ status: Type.Optional(StringEnum(["pending", "in_progress", "completed", "deleted"] as const, { description: TASK_UPDATE_PARAMS.status })),
237
+ addBlocks: Type.Optional(Type.Array(Type.String(), { description: TASK_UPDATE_PARAMS.addBlocks })),
238
+ addBlockedBy: Type.Optional(Type.Array(Type.String(), { description: TASK_UPDATE_PARAMS.addBlockedBy })),
239
+ owner: Type.Optional(Type.String({ description: TASK_UPDATE_PARAMS.owner })),
240
+ metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: TASK_UPDATE_PARAMS.metadata })),
157
241
  }),
158
242
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
159
243
  const { taskId, ...input } = params;
160
244
  const outcome = store.update(taskId, input as Parameters<TaskStore["update"]>[1]);
161
245
  if (outcome.deleted) {
162
246
  markUsed();
163
- return result(`Deleted task #${taskId}.`, ctx);
247
+ return result(`Updated task #${normalizeTaskId(taskId)} deleted`, ctx);
164
248
  }
165
249
  // A failed update (unknown id) is not "using" the tracker — a model
166
250
  // looping on a hallucinated id must not suppress the nudge.
167
251
  if (outcome.error && !outcome.task) return result(outcome.error, ctx, true);
168
252
  markUsed();
169
- const line = formatTaskLine(store, outcome.task!);
253
+ // Claude Code's result names the fields that changed.
254
+ const line = `Updated task #${outcome.task!.id} ${(outcome.updatedFields ?? []).join(", ")}`;
170
255
  return result(outcome.error ? `${line}\n${outcome.error}` : line, ctx, Boolean(outcome.error));
171
256
  },
172
257
  });
173
258
 
174
259
  for (const name of TASK_TOOLS) {
175
- pi.events.emit(DEFER_CHANNEL, { name, keywords: ["task", "todo", "plan", "progress", "dependencies", "tracking"] });
260
+ pi.events.emit(DEFER_CHANNEL, { name, keywords: TASK_KEYWORDS });
176
261
  }
177
262
 
178
- registerLocalCommand(pi, "tasks", {
179
- description: "Show the structured task list; 'hide'/'show' toggles the widget",
180
- handler: async (args, ctx) => {
181
- const arg = args?.trim().toLowerCase();
182
- if (arg === "hide" || arg === "show") {
183
- widgetHidden = arg === "hide";
184
- updateWidget(ctx);
185
- return;
186
- }
187
- ctx.ui.notify(formatTaskList(store), "info");
188
- },
263
+ // `/tasks` is Claude Code's Background dialog (the subagents extension, findings
264
+ // §40); the task list toggles with its key only, as Claude Code's does.
265
+ pi.registerShortcut(toggleKey, {
266
+ description: "Show or hide the task list",
267
+ handler: (ctx) => setWidgetHidden(!widgetHidden, ctx),
189
268
  });
190
269
  }
@@ -38,6 +38,11 @@ export interface TaskUpdateInput {
38
38
  addBlockedBy?: string[];
39
39
  }
40
40
 
41
+ /** A task id as the model may write it: tasks show as `#3`, so a leading `#` names task 3. */
42
+ export function normalizeTaskId(id: string): string {
43
+ return id.startsWith("#") ? id.slice(1) : id;
44
+ }
45
+
41
46
  export class TaskStore {
42
47
  private tasks = new Map<string, TaskItem>();
43
48
  private nextId = 1;
@@ -58,7 +63,7 @@ export class TaskStore {
58
63
  }
59
64
 
60
65
  get(id: string): TaskItem | undefined {
61
- return this.tasks.get(id);
66
+ return this.tasks.get(normalizeTaskId(id));
62
67
  }
63
68
 
64
69
  list(): TaskItem[] {
@@ -73,9 +78,14 @@ export class TaskStore {
73
78
  });
74
79
  }
75
80
 
76
- update(id: string, input: TaskUpdateInput): { task?: TaskItem; deleted?: boolean; error?: string } {
81
+ /**
82
+ * Apply an update. `updatedFields` names what actually changed, in Claude
83
+ * Code's order (its TaskUpdate result lists them).
84
+ */
85
+ update(rawId: string, input: TaskUpdateInput): { task?: TaskItem; deleted?: boolean; error?: string; updatedFields?: string[] } {
86
+ const id = normalizeTaskId(rawId);
77
87
  const task = this.tasks.get(id);
78
- if (!task) return { error: `No task with id "${id}". Use task_list to see ids.` };
88
+ if (!task) return { error: `No task with id "${rawId}". Use task_list to see ids.` };
79
89
 
80
90
  if (input.status === "deleted") {
81
91
  this.tasks.delete(id);
@@ -86,17 +96,33 @@ export class TaskStore {
86
96
  return { deleted: true };
87
97
  }
88
98
 
89
- if (input.subject !== undefined) task.subject = input.subject;
90
- if (input.description !== undefined) task.description = input.description;
91
- if (input.activeForm !== undefined) task.activeForm = input.activeForm;
92
- if (input.status !== undefined) task.status = input.status;
93
- if (input.owner !== undefined) task.owner = input.owner || undefined;
94
-
99
+ const updatedFields: string[] = [];
100
+ if (input.subject !== undefined && input.subject !== task.subject) {
101
+ task.subject = input.subject;
102
+ updatedFields.push("subject");
103
+ }
104
+ if (input.description !== undefined && input.description !== task.description) {
105
+ task.description = input.description;
106
+ updatedFields.push("description");
107
+ }
108
+ if (input.activeForm !== undefined && input.activeForm !== task.activeForm) {
109
+ task.activeForm = input.activeForm;
110
+ updatedFields.push("activeForm");
111
+ }
112
+ if (input.owner !== undefined && (input.owner || undefined) !== task.owner) {
113
+ task.owner = input.owner || undefined;
114
+ updatedFields.push("owner");
115
+ }
95
116
  if (input.metadata) {
96
117
  for (const [key, value] of Object.entries(input.metadata)) {
97
118
  if (value === null) delete task.metadata[key];
98
119
  else task.metadata[key] = value;
99
120
  }
121
+ updatedFields.push("metadata");
122
+ }
123
+ if (input.status !== undefined && input.status !== task.status) {
124
+ task.status = input.status;
125
+ updatedFields.push("status");
100
126
  }
101
127
 
102
128
  // Separate a self-reference from a genuinely unknown id: link() rejects
@@ -104,19 +130,23 @@ export class TaskStore {
104
130
  // task id" — sending the model to hunt a typo that isn't there.
105
131
  const unknown: string[] = [];
106
132
  let selfRef = false;
107
- for (const other of input.addBlocks ?? []) {
133
+ const blocksBefore = task.blocks.length;
134
+ for (const other of (input.addBlocks ?? []).map(normalizeTaskId)) {
108
135
  if (other === id) selfRef = true;
109
136
  else if (!this.link(id, other)) unknown.push(other);
110
137
  }
111
- for (const other of input.addBlockedBy ?? []) {
138
+ if (task.blocks.length > blocksBefore) updatedFields.push("blocks");
139
+ const blockedByBefore = task.blockedBy.length;
140
+ for (const other of (input.addBlockedBy ?? []).map(normalizeTaskId)) {
112
141
  if (other === id) selfRef = true;
113
142
  else if (!this.link(other, id)) unknown.push(other);
114
143
  }
144
+ if (task.blockedBy.length > blockedByBefore) updatedFields.push("blockedBy");
115
145
  const errors: string[] = [];
116
146
  if (selfRef) errors.push(`Task #${id} cannot block or be blocked by itself`);
117
147
  if (unknown.length > 0) errors.push(`Unknown task id(s) in dependency list: ${unknown.join(", ")}`);
118
- if (errors.length > 0) return { task, error: errors.join(". ") };
119
- return { task };
148
+ if (errors.length > 0) return { task, error: errors.join(". "), updatedFields };
149
+ return { task, updatedFields };
120
150
  }
121
151
 
122
152
  /** Record "blocker blocks blocked" on both sides. False if either id is unknown. */
@@ -133,15 +163,42 @@ export class TaskStore {
133
163
  return { nextId: this.nextId, tasks: this.list().map((t) => ({ ...t, metadata: { ...t.metadata }, blocks: [...t.blocks], blockedBy: [...t.blockedBy] })) };
134
164
  }
135
165
 
166
+ /**
167
+ * A non-empty list with every task completed: the state Claude Code clears
168
+ * itself from, 5 s after it is reached (`FINISHED_LIST_CLEAR_MS`).
169
+ */
170
+ isFinished(): boolean {
171
+ const tasks = this.list();
172
+ return tasks.length > 0 && tasks.every((t) => t.status === "completed");
173
+ }
174
+
175
+ /**
176
+ * Drop every task and keep the id counter, as Claude Code's reset does (it
177
+ * records the high-water mark before deleting), so a task created after a
178
+ * clear never reuses an id the transcript already mentions.
179
+ */
180
+ clear(): void {
181
+ this.tasks.clear();
182
+ }
183
+
184
+ /**
185
+ * A finished snapshot restores as empty: the clear runs on a timer and never
186
+ * lands in a tool result, so without this rule `/resume` or a `/tree` switch
187
+ * would bring back a list Claude Code would already have cleared.
188
+ */
136
189
  restore(snapshot: TaskSnapshot | undefined): void {
137
190
  this.tasks.clear();
138
191
  this.nextId = snapshot?.nextId ?? 1;
139
192
  for (const task of snapshot?.tasks ?? []) {
140
193
  this.tasks.set(task.id, { ...task, metadata: { ...task.metadata }, blocks: [...task.blocks], blockedBy: [...task.blockedBy] });
141
194
  }
195
+ if (this.isFinished()) this.clear();
142
196
  }
143
197
  }
144
198
 
199
+ /** How long a finished list stays on screen before it clears (Claude Code's 5000 ms). */
200
+ export const FINISHED_LIST_CLEAR_MS = 5_000;
201
+
145
202
  const STATUS_MARK: Record<TaskStatus, string> = { pending: " ", in_progress: "▸", completed: "x" };
146
203
 
147
204
  export function formatTaskLine(store: TaskStore, task: TaskItem): string {
@@ -193,7 +250,7 @@ function taskRow(task: TaskItem, { paint, bold, strike }: WidgetStyle): string {
193
250
  * past `maxTasks` so the widget cannot swallow the screen (Claude Code's
194
251
  * cutoff is unverified).
195
252
  */
196
- export function formatTaskWidget(store: TaskStore, maxTasks = 12, style: WidgetStyle = PLAIN_STYLE): string[] {
253
+ export function formatTaskWidget(store: TaskStore, maxTasks = 12, style: WidgetStyle = PLAIN_STYLE, hint?: string): string[] {
197
254
  const { paint, bold } = style;
198
255
  const tasks = store.list();
199
256
  if (tasks.length === 0) return [];
@@ -203,13 +260,23 @@ export function formatTaskWidget(store: TaskStore, maxTasks = 12, style: WidgetS
203
260
  const dim = (text: string) => paint("dim", text);
204
261
  const count = (n: number) => bold(dim(String(n)));
205
262
  const lines = [
206
- ` ${count(tasks.length)}${dim(` ${tasks.length === 1 ? "task" : "tasks"} (`)}${count(done)}${dim(" done, ")}${count(inProgress)}${dim(" in progress, ")}${count(open)}${dim(" open)")}`,
263
+ ` ${count(tasks.length)}${dim(` ${tasks.length === 1 ? "task" : "tasks"} (`)}${count(done)}${dim(" done, ")}${count(inProgress)}${dim(" in progress, ")}${count(open)}${dim(" open)")}${hint ? dim(` · ${hint}`) : ""}`,
207
264
  ];
208
265
  for (const t of tasks.slice(0, maxTasks)) lines.push(` ${taskRow(t, style)}`);
209
266
  if (tasks.length > maxTasks) lines.push(` ${dim(`… +${tasks.length - maxTasks} more`)}`);
210
267
  return lines;
211
268
  }
212
269
 
270
+ /**
271
+ * The one line left when the user hides the list, so the key that brings it
272
+ * back stays on screen (Claude Code shows "ctrl+t to show tasks" in its footer).
273
+ */
274
+ export function formatHiddenTaskWidget(store: TaskStore, hint: string, style: WidgetStyle = PLAIN_STYLE): string[] {
275
+ const n = store.list().length;
276
+ if (n === 0) return [];
277
+ return [` ${style.paint("dim", `${n} ${n === 1 ? "task" : "tasks"} hidden · ${hint}`)}`];
278
+ }
279
+
213
280
  /**
214
281
  * The periodic task-tool reminder (Claude Code's `task_reminder`): a single
215
282
  * gentle nudge fired when the task tools have gone unused for a while, with the
@@ -217,7 +284,7 @@ export function formatTaskWidget(store: TaskStore, maxTasks = 12, style: WidgetS
217
284
  * when the user pivots mid-session and the plan no longer matches the work.
218
285
  *
219
286
  * Byte-for-byte Claude Code's text (messages.ts) except the tool names, which
220
- * stay our snake_case (docs/decisions/tools.md). We do NOT branch on list state
287
+ * stay our snake_case (working-docs/decisions/tools.md). We do NOT branch on list state
221
288
  * the way CC's earlier prompt did — one reminder, always the same, and the
222
289
  * appended list is what the model reasons over.
223
290
  */
@@ -0,0 +1,7 @@
1
+ /** The OpenRouter stream guard for an in-process child session (lib/child-extensions.ts): blocks and stops, prints nothing. */
2
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ import { toolCallCorruptionGuard } from "./index.ts";
4
+
5
+ export default function childToolCallCorruptionExtension(pi: ExtensionAPI) {
6
+ toolCallCorruptionGuard(pi, { announce: false });
7
+ }