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
@@ -0,0 +1,455 @@
1
+ /**
2
+ * Terminal key decoding for One Code's panels, dialogs and input listeners.
3
+ *
4
+ * A key reaches an extension as raw bytes, and one key has several encodings.
5
+ * pi-tui asks the terminal for the kitty keyboard protocol (flags 7:
6
+ * disambiguate, event types, alternate keys), and when the terminal does not
7
+ * answer it turns on xterm's modifyOtherKeys. So Esc is `\x1b` in a legacy
8
+ * terminal and `\x1b[27u` in kitty, Ghostty, WezTerm or VS Code; ctrl+c is
9
+ * `\x03`, `\x1b[99;5u`, or `\x1b[27;5;99~` under tmux with `extended-keys on`;
10
+ * and with event types on, every press is followed by a release such as
11
+ * `\x1b[1;1:3B`. A decoder that compares legacy bytes misses all of those.
12
+ *
13
+ * `parseKey` is pi-tui's own parser (`dist/keys.js`, MIT; unchanged from
14
+ * 0.87.1 to 1.1.0, then 1.2.0's logical shifted-symbol reading), ported
15
+ * verbatim so every panel names a key exactly as pi-tui and pi's
16
+ * keybindings do. It stays here because `lib/` modules
17
+ * import nothing from pi, and the bare `@earendil-works/pi-tui` specifier
18
+ * resolves to a different pi-tui in tests than at runtime.
19
+ * `key-input.test.ts` compares this port with the installed pi-tui over
20
+ * every encoding, so a pi bump that changes the parser fails the suite.
21
+ *
22
+ * Decoders switch on `keyId(data)` (pi-tui's key ids: `escape`, `ctrl+c`,
23
+ * `shift+tab`, `up`, `pageDown`, `x`) and read typed text with `keyText`.
24
+ * An input listener, which pi-tui calls before it filters releases, checks
25
+ * `isKeyRelease` first.
26
+ */
27
+
28
+ const MODIFIERS = { shift: 1, alt: 2, ctrl: 4, super: 8 } as const;
29
+ /** Caps lock and num lock, which the kitty protocol reports as modifier bits. */
30
+ const LOCK_MASK = 64 + 128;
31
+
32
+ const CODEPOINTS = { escape: 27, tab: 9, enter: 13, space: 32, backspace: 127, kpEnter: 57414 } as const;
33
+ const ARROW_CODEPOINTS = { up: -1, down: -2, right: -3, left: -4 } as const;
34
+ const FUNCTIONAL_CODEPOINTS = { delete: -10, insert: -11, pageUp: -12, pageDown: -13, home: -14, end: -15 } as const;
35
+
36
+ /** Kitty keypad codes and the keys they stand for. */
37
+ const KITTY_FUNCTIONAL_KEY_EQUIVALENTS = new Map<number, number>([
38
+ [57399, 48],
39
+ [57400, 49],
40
+ [57401, 50],
41
+ [57402, 51],
42
+ [57403, 52],
43
+ [57404, 53],
44
+ [57405, 54],
45
+ [57406, 55],
46
+ [57407, 56],
47
+ [57408, 57],
48
+ [57409, 46],
49
+ [57410, 47],
50
+ [57411, 42],
51
+ [57412, 45],
52
+ [57413, 43],
53
+ [57415, 61],
54
+ [57416, 44],
55
+ [57417, ARROW_CODEPOINTS.left],
56
+ [57418, ARROW_CODEPOINTS.right],
57
+ [57419, ARROW_CODEPOINTS.up],
58
+ [57420, ARROW_CODEPOINTS.down],
59
+ [57421, FUNCTIONAL_CODEPOINTS.pageUp],
60
+ [57422, FUNCTIONAL_CODEPOINTS.pageDown],
61
+ [57423, FUNCTIONAL_CODEPOINTS.home],
62
+ [57424, FUNCTIONAL_CODEPOINTS.end],
63
+ [57425, FUNCTIONAL_CODEPOINTS.insert],
64
+ [57426, FUNCTIONAL_CODEPOINTS.delete],
65
+ ]);
66
+
67
+ const SYMBOL_KEYS = new Set([
68
+ "`", "-", "=", "[", "]", "\\", ";", "'", ",", ".", "/", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_",
69
+ "+", "|", "~", "{", "}", ":", "<", ">", "?",
70
+ ]);
71
+
72
+ const LEGACY_SEQUENCE_KEY_IDS: Record<string, string> = {
73
+ "\x1bOA": "up",
74
+ "\x1bOB": "down",
75
+ "\x1bOC": "right",
76
+ "\x1bOD": "left",
77
+ "\x1bOH": "home",
78
+ "\x1bOF": "end",
79
+ "\x1b[E": "clear",
80
+ "\x1bOE": "clear",
81
+ "\x1bOe": "ctrl+clear",
82
+ "\x1b[e": "shift+clear",
83
+ "\x1b[2~": "insert",
84
+ "\x1b[2$": "shift+insert",
85
+ "\x1b[2^": "ctrl+insert",
86
+ "\x1b[3$": "shift+delete",
87
+ "\x1b[3^": "ctrl+delete",
88
+ "\x1b[[5~": "pageUp",
89
+ "\x1b[[6~": "pageDown",
90
+ "\x1b[a": "shift+up",
91
+ "\x1b[b": "shift+down",
92
+ "\x1b[c": "shift+right",
93
+ "\x1b[d": "shift+left",
94
+ "\x1bOa": "ctrl+up",
95
+ "\x1bOb": "ctrl+down",
96
+ "\x1bOc": "ctrl+right",
97
+ "\x1bOd": "ctrl+left",
98
+ "\x1b[5$": "shift+pageUp",
99
+ "\x1b[6$": "shift+pageDown",
100
+ "\x1b[7$": "shift+home",
101
+ "\x1b[8$": "shift+end",
102
+ "\x1b[5^": "ctrl+pageUp",
103
+ "\x1b[6^": "ctrl+pageDown",
104
+ "\x1b[7^": "ctrl+home",
105
+ "\x1b[8^": "ctrl+end",
106
+ "\x1bOP": "f1",
107
+ "\x1bOQ": "f2",
108
+ "\x1bOR": "f3",
109
+ "\x1bOS": "f4",
110
+ "\x1b[11~": "f1",
111
+ "\x1b[12~": "f2",
112
+ "\x1b[13~": "f3",
113
+ "\x1b[14~": "f4",
114
+ "\x1b[[A": "f1",
115
+ "\x1b[[B": "f2",
116
+ "\x1b[[C": "f3",
117
+ "\x1b[[D": "f4",
118
+ "\x1b[[E": "f5",
119
+ "\x1b[15~": "f5",
120
+ "\x1b[17~": "f6",
121
+ "\x1b[18~": "f7",
122
+ "\x1b[19~": "f8",
123
+ "\x1b[20~": "f9",
124
+ "\x1b[21~": "f10",
125
+ "\x1b[23~": "f11",
126
+ "\x1b[24~": "f12",
127
+ "\x1bb": "alt+left",
128
+ "\x1bf": "alt+right",
129
+ "\x1bp": "alt+up",
130
+ "\x1bn": "alt+down",
131
+ };
132
+
133
+ export type KeyEventType = "press" | "repeat" | "release";
134
+
135
+ interface ParsedSequence {
136
+ codepoint: number;
137
+ shiftedKey?: number;
138
+ baseLayoutKey?: number;
139
+ modifier: number;
140
+ eventType: KeyEventType;
141
+ }
142
+
143
+ function parseEventType(field: string | undefined): KeyEventType {
144
+ if (!field) return "press";
145
+ const eventType = Number.parseInt(field, 10);
146
+ if (eventType === 2) return "repeat";
147
+ if (eventType === 3) return "release";
148
+ return "press";
149
+ }
150
+
151
+ const KITTY_CSI_U = /^\x1b\[(\d+)(?::(\d*))?(?::(\d+))?(?:;(\d+))?(?::(\d+))?u$/;
152
+
153
+ function parseKittySequence(data: string): ParsedSequence | undefined {
154
+ const csiU = data.match(KITTY_CSI_U);
155
+ if (csiU) {
156
+ return {
157
+ codepoint: Number.parseInt(csiU[1], 10),
158
+ shiftedKey: csiU[2] && csiU[2].length > 0 ? Number.parseInt(csiU[2], 10) : undefined,
159
+ baseLayoutKey: csiU[3] ? Number.parseInt(csiU[3], 10) : undefined,
160
+ modifier: (csiU[4] ? Number.parseInt(csiU[4], 10) : 1) - 1,
161
+ eventType: parseEventType(csiU[5]),
162
+ };
163
+ }
164
+ const arrow = data.match(/^\x1b\[1;(\d+)(?::(\d+))?([ABCD])$/);
165
+ if (arrow) {
166
+ const codes: Record<string, number> = { A: -1, B: -2, C: -3, D: -4 };
167
+ return { codepoint: codes[arrow[3]], modifier: Number.parseInt(arrow[1], 10) - 1, eventType: parseEventType(arrow[2]) };
168
+ }
169
+ const func = data.match(/^\x1b\[(\d+)(?:;(\d+))?(?::(\d+))?~$/);
170
+ if (func) {
171
+ const funcCodes: Record<number, number> = {
172
+ 2: FUNCTIONAL_CODEPOINTS.insert,
173
+ 3: FUNCTIONAL_CODEPOINTS.delete,
174
+ 5: FUNCTIONAL_CODEPOINTS.pageUp,
175
+ 6: FUNCTIONAL_CODEPOINTS.pageDown,
176
+ 7: FUNCTIONAL_CODEPOINTS.home,
177
+ 8: FUNCTIONAL_CODEPOINTS.end,
178
+ };
179
+ const codepoint = funcCodes[Number.parseInt(func[1], 10)];
180
+ if (codepoint !== undefined) {
181
+ return { codepoint, modifier: (func[2] ? Number.parseInt(func[2], 10) : 1) - 1, eventType: parseEventType(func[3]) };
182
+ }
183
+ }
184
+ const homeEnd = data.match(/^\x1b\[1;(\d+)(?::(\d+))?([HF])$/);
185
+ if (homeEnd) {
186
+ return {
187
+ codepoint: homeEnd[3] === "H" ? FUNCTIONAL_CODEPOINTS.home : FUNCTIONAL_CODEPOINTS.end,
188
+ modifier: Number.parseInt(homeEnd[1], 10) - 1,
189
+ eventType: parseEventType(homeEnd[2]),
190
+ };
191
+ }
192
+ return undefined;
193
+ }
194
+
195
+ function parseModifyOtherKeysSequence(data: string): { codepoint: number; modifier: number } | undefined {
196
+ const match = data.match(/^\x1b\[27;(\d+);(\d+)~$/);
197
+ if (!match) return undefined;
198
+ return { codepoint: Number.parseInt(match[2], 10), modifier: Number.parseInt(match[1], 10) - 1 };
199
+ }
200
+
201
+ function normalizeKittyFunctionalCodepoint(codepoint: number): number {
202
+ return KITTY_FUNCTIONAL_KEY_EQUIVALENTS.get(codepoint) ?? codepoint;
203
+ }
204
+
205
+ function normalizeShiftedLetterIdentityCodepoint(codepoint: number, modifier: number): number {
206
+ const effective = modifier & ~LOCK_MASK;
207
+ if ((effective & MODIFIERS.shift) !== 0 && codepoint >= 65 && codepoint <= 90) return codepoint + 32;
208
+ return codepoint;
209
+ }
210
+
211
+ function formatKeyNameWithModifiers(keyName: string, modifier: number): string | undefined {
212
+ const effective = modifier & ~LOCK_MASK;
213
+ const supported = MODIFIERS.shift | MODIFIERS.ctrl | MODIFIERS.alt | MODIFIERS.super;
214
+ if ((effective & ~supported) !== 0) return undefined;
215
+ const mods: string[] = [];
216
+ if (effective & MODIFIERS.shift) mods.push("shift");
217
+ if (effective & MODIFIERS.ctrl) mods.push("ctrl");
218
+ if (effective & MODIFIERS.alt) mods.push("alt");
219
+ if (effective & MODIFIERS.super) mods.push("super");
220
+ return mods.length > 0 ? `${mods.join("+")}+${keyName}` : keyName;
221
+ }
222
+
223
+ const NAMED_CODEPOINTS = new Map<number, string>([
224
+ [CODEPOINTS.escape, "escape"],
225
+ [CODEPOINTS.tab, "tab"],
226
+ [CODEPOINTS.enter, "enter"],
227
+ [CODEPOINTS.kpEnter, "enter"],
228
+ [CODEPOINTS.space, "space"],
229
+ [CODEPOINTS.backspace, "backspace"],
230
+ [FUNCTIONAL_CODEPOINTS.delete, "delete"],
231
+ [FUNCTIONAL_CODEPOINTS.insert, "insert"],
232
+ [FUNCTIONAL_CODEPOINTS.home, "home"],
233
+ [FUNCTIONAL_CODEPOINTS.end, "end"],
234
+ [FUNCTIONAL_CODEPOINTS.pageUp, "pageUp"],
235
+ [FUNCTIONAL_CODEPOINTS.pageDown, "pageDown"],
236
+ [ARROW_CODEPOINTS.up, "up"],
237
+ [ARROW_CODEPOINTS.down, "down"],
238
+ [ARROW_CODEPOINTS.left, "left"],
239
+ [ARROW_CODEPOINTS.right, "right"],
240
+ ]);
241
+
242
+ /** Symbols a modifyOtherKeys terminal reports as Shift plus the physical key (pi-tui 1.2.0). */
243
+ const SHIFTED_SYMBOL_KEYS = new Set("~!@#$%^&*()_+|{}:<>?");
244
+
245
+ /**
246
+ * pi-tui 1.2.0's logical reading of a shifted symbol: kitty reports "+" as
247
+ * Shift plus the physical "=" key (the produced symbol in the shifted-key
248
+ * field), and bindings name the produced symbol, so the implicit Shift is
249
+ * consumed while Ctrl, Alt and Super stay.
250
+ */
251
+ function logicalShiftedSymbol(codepoint: number | undefined, modifier: number, allowed: ReadonlySet<string>): { codepoint: number; modifier: number } | undefined {
252
+ if (codepoint === undefined || (modifier & MODIFIERS.shift) === 0) return undefined;
253
+ const normalized = normalizeKittyFunctionalCodepoint(codepoint);
254
+ if (!allowed.has(String.fromCharCode(normalized))) return undefined;
255
+ return { codepoint: normalized, modifier: modifier & ~MODIFIERS.shift };
256
+ }
257
+
258
+ function formatParsedKey(codepoint: number, modifier: number, baseLayoutKey?: number): string | undefined {
259
+ const identity = normalizeShiftedLetterIdentityCodepoint(normalizeKittyFunctionalCodepoint(codepoint), modifier);
260
+ // The codepoint is authoritative for a Latin letter, digit or known symbol
261
+ // (remapped layouts); otherwise the base-layout key names it.
262
+ const isLatinLetter = identity >= 97 && identity <= 122;
263
+ const isDigit = identity >= 48 && identity <= 57;
264
+ const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(identity));
265
+ const effective = isLatinLetter || isDigit || isKnownSymbol ? identity : (baseLayoutKey ?? identity);
266
+ let keyName = NAMED_CODEPOINTS.get(effective);
267
+ if (!keyName) {
268
+ if ((effective >= 48 && effective <= 57) || (effective >= 97 && effective <= 122)) keyName = String.fromCharCode(effective);
269
+ else if (SYMBOL_KEYS.has(String.fromCharCode(effective))) keyName = String.fromCharCode(effective);
270
+ }
271
+ if (!keyName) return undefined;
272
+ return formatKeyNameWithModifiers(keyName, modifier);
273
+ }
274
+
275
+ export interface ParseKeyOptions {
276
+ /** pi-tui's kitty-protocol state: `\n` and `\x1b\r` then mean shift+enter. Default false. */
277
+ kittyActive?: boolean;
278
+ /** Windows Terminal outside SSH, where a raw `\x08` is ctrl+backspace. Default read from the environment. */
279
+ windowsTerminal?: boolean;
280
+ }
281
+
282
+ function isWindowsTerminalSession(env: NodeJS.ProcessEnv = process.env): boolean {
283
+ return Boolean(env.WT_SESSION) && !env.SSH_CONNECTION && !env.SSH_CLIENT && !env.SSH_TTY;
284
+ }
285
+
286
+ /** pi-tui's `parseKey` (1.2.0): the key id of one input chunk, or undefined. Releases parse like presses. */
287
+ export function parseKey(data: string, options: ParseKeyOptions = {}): string | undefined {
288
+ const kitty = options.kittyActive ?? false;
289
+ const kittySeq = parseKittySequence(data);
290
+ if (kittySeq) {
291
+ const symbol = logicalShiftedSymbol(kittySeq.shiftedKey, kittySeq.modifier, SYMBOL_KEYS);
292
+ return formatParsedKey(symbol?.codepoint ?? kittySeq.codepoint, symbol?.modifier ?? kittySeq.modifier, kittySeq.baseLayoutKey);
293
+ }
294
+ const mok = parseModifyOtherKeysSequence(data);
295
+ if (mok) {
296
+ const symbol = logicalShiftedSymbol(mok.codepoint, mok.modifier, SHIFTED_SYMBOL_KEYS);
297
+ return formatParsedKey(symbol?.codepoint ?? mok.codepoint, symbol?.modifier ?? mok.modifier);
298
+ }
299
+ if (kitty && (data === "\x1b\r" || data === "\n")) return "shift+enter";
300
+ const legacy = LEGACY_SEQUENCE_KEY_IDS[data];
301
+ if (legacy) return legacy;
302
+ switch (data) {
303
+ case "\x1b":
304
+ return "escape";
305
+ case "\x1c":
306
+ return "ctrl+\\";
307
+ case "\x1d":
308
+ return "ctrl+]";
309
+ case "\x1f":
310
+ return "ctrl+-";
311
+ case "\x1b\x1b":
312
+ return "ctrl+alt+[";
313
+ case "\x1b\x1c":
314
+ return "ctrl+alt+\\";
315
+ case "\x1b\x1d":
316
+ return "ctrl+alt+]";
317
+ case "\x1b\x1f":
318
+ return "ctrl+alt+-";
319
+ case "\t":
320
+ return "tab";
321
+ case "\r":
322
+ case "\x1bOM":
323
+ return "enter";
324
+ case "\x00":
325
+ return "ctrl+space";
326
+ case " ":
327
+ return "space";
328
+ case "\x7f":
329
+ return "backspace";
330
+ case "\x08":
331
+ return (options.windowsTerminal ?? isWindowsTerminalSession()) ? "ctrl+backspace" : "backspace";
332
+ case "\x1b[Z":
333
+ return "shift+tab";
334
+ case "\x1b\x7f":
335
+ case "\x1b\b":
336
+ return "alt+backspace";
337
+ }
338
+ if (!kitty) {
339
+ if (data === "\n") return "enter";
340
+ if (data === "\x1b\r") return "alt+enter";
341
+ if (data === "\x1b ") return "alt+space";
342
+ if (data === "\x1bB") return "alt+left";
343
+ if (data === "\x1bF") return "alt+right";
344
+ if (data.length === 2 && data[0] === "\x1b") {
345
+ const code = data.charCodeAt(1);
346
+ if (code >= 1 && code <= 26) return `ctrl+alt+${String.fromCharCode(code + 96)}`;
347
+ const key = String.fromCharCode(code);
348
+ if ((code >= 97 && code <= 122) || (code >= 48 && code <= 57) || SYMBOL_KEYS.has(key)) return `alt+${key}`;
349
+ }
350
+ }
351
+ switch (data) {
352
+ case "\x1b[A":
353
+ return "up";
354
+ case "\x1b[B":
355
+ return "down";
356
+ case "\x1b[C":
357
+ return "right";
358
+ case "\x1b[D":
359
+ return "left";
360
+ case "\x1b[H":
361
+ case "\x1bOH":
362
+ return "home";
363
+ case "\x1b[F":
364
+ case "\x1bOF":
365
+ return "end";
366
+ case "\x1b[3~":
367
+ return "delete";
368
+ case "\x1b[5~":
369
+ return "pageUp";
370
+ case "\x1b[6~":
371
+ return "pageDown";
372
+ }
373
+ if (data.length === 1) {
374
+ const code = data.charCodeAt(0);
375
+ if (code >= 1 && code <= 26) return `ctrl+${String.fromCharCode(code + 96)}`;
376
+ if (code >= 32 && code <= 126) return data;
377
+ }
378
+ return undefined;
379
+ }
380
+
381
+ /**
382
+ * Legacy Home and End forms that pi-tui's `matchesKey` accepts but its
383
+ * `parseKey` does not name (rxvt and the Linux console send them).
384
+ */
385
+ const EXTRA_KEY_IDS: Record<string, string> = { "\x1b[1~": "home", "\x1b[4~": "end" };
386
+
387
+ /**
388
+ * The key id for a panel decoder: pi-tui's `parseKey`, plus the legacy Home
389
+ * and End forms. A release or repeat names the same key as its press; pi-tui
390
+ * drops releases before a focused component sees them.
391
+ */
392
+ export function keyId(data: string, options?: ParseKeyOptions): string | undefined {
393
+ return parseKey(data, options) ?? EXTRA_KEY_IDS[data];
394
+ }
395
+
396
+ /** pi-tui's `isKeyRelease`: the kitty protocol's release event (flag 2). Pasted text never counts. */
397
+ export function isKeyRelease(data: string): boolean {
398
+ if (data.includes("\x1b[200~")) return false;
399
+ return /:3[u~ABCDHF]/.test(data);
400
+ }
401
+
402
+ /** pi-tui's `isKeyRepeat`: the kitty protocol's auto-repeat event (flag 2). */
403
+ export function isKeyRepeat(data: string): boolean {
404
+ if (data.includes("\x1b[200~")) return false;
405
+ return /:2[u~ABCDHF]/.test(data);
406
+ }
407
+
408
+ const KITTY_PRINTABLE_ALLOWED_MODIFIERS = MODIFIERS.shift | LOCK_MASK;
409
+
410
+ /** pi-tui's `decodePrintableKey`: the character a kitty CSI u or modifyOtherKeys sequence types, if any. */
411
+ export function decodePrintableKey(data: string): string | undefined {
412
+ const csiU = data.match(KITTY_CSI_U);
413
+ if (csiU) {
414
+ const codepoint = Number.parseInt(csiU[1] ?? "", 10);
415
+ if (!Number.isFinite(codepoint)) return undefined;
416
+ const shiftedKey = csiU[2] && csiU[2].length > 0 ? Number.parseInt(csiU[2], 10) : undefined;
417
+ const modValue = csiU[4] ? Number.parseInt(csiU[4], 10) : 1;
418
+ const modifier = Number.isFinite(modValue) ? modValue - 1 : 0;
419
+ if ((modifier & ~KITTY_PRINTABLE_ALLOWED_MODIFIERS) !== 0) return undefined;
420
+ if (modifier & (MODIFIERS.alt | MODIFIERS.ctrl)) return undefined;
421
+ let effective = codepoint;
422
+ if (modifier & MODIFIERS.shift && typeof shiftedKey === "number") effective = shiftedKey;
423
+ effective = normalizeKittyFunctionalCodepoint(effective);
424
+ if (!Number.isFinite(effective) || effective < 32) return undefined;
425
+ try {
426
+ return String.fromCodePoint(effective);
427
+ } catch {
428
+ return undefined;
429
+ }
430
+ }
431
+ const mok = parseModifyOtherKeysSequence(data);
432
+ if (!mok) return undefined;
433
+ if (((mok.modifier & ~LOCK_MASK) & ~MODIFIERS.shift) !== 0) return undefined;
434
+ if (!Number.isFinite(mok.codepoint) || mok.codepoint < 32) return undefined;
435
+ try {
436
+ return String.fromCodePoint(mok.codepoint);
437
+ } catch {
438
+ return undefined;
439
+ }
440
+ }
441
+
442
+ /**
443
+ * The text a chunk types, for a search box, a draft or a letter shortcut:
444
+ * plain input (a key or a paste) with control characters removed, or the
445
+ * character an encoded printable key stands for. A control sequence types
446
+ * nothing, so its tail never leaks into a draft.
447
+ */
448
+ export function keyText(data: string): string | undefined {
449
+ if (data.startsWith("\x1b")) {
450
+ if (isKeyRelease(data)) return undefined;
451
+ return decodePrintableKey(data);
452
+ }
453
+ const text = [...data].filter((ch) => ch >= " " && ch !== "\x7f").join("");
454
+ return text.length > 0 ? text : undefined;
455
+ }
@@ -11,7 +11,7 @@
11
11
  * warning, and mode cycling had no key at all on Windows (seen on the Vultr
12
12
  * VM, 2026-09-19). No ctrl+letter is free on Windows once pi's app and editor
13
13
  * bindings are counted, and pi itself reaches for alt there, so mode cycling
14
- * is alt+m on Windows and WSL — docs/decisions/windows.md.
14
+ * is alt+m on Windows and WSL — working-docs/decisions/windows.md.
15
15
  */
16
16
 
17
17
  /** pi's rule for its Windows key table: native Windows, or a WSL distro. */
@@ -24,6 +24,19 @@ export function modeCycleKey(platform: string = process.platform, env: NodeJS.Pr
24
24
  return useWindowsKeybindings(platform, env) ? "alt+m" : "ctrl+q";
25
25
  }
26
26
 
27
+ /**
28
+ * The key that shows or hides the pinned task list. Claude Code uses ctrl+t,
29
+ * which pi reserves for its thinking-block toggle (an extension shortcut on a
30
+ * reserved key is skipped), so One Code uses alt+t, free in pi's key tables
31
+ * on every platform. macOS terminals send option+t as the typed character †
32
+ * unless "Use Option as Meta" is on, so alt+t never arrives there; macOS gets
33
+ * ctrl+\ instead, a control byte every terminal passes through, free in pi's
34
+ * tables (ctrl+] and ctrl+- are taken, and no ctrl+letter is left).
35
+ */
36
+ export function taskToggleKey(platform: string = process.platform): "alt+t" | "ctrl+\\" {
37
+ return platform === "darwin" ? "ctrl+\\" : "alt+t";
38
+ }
39
+
27
40
  /**
28
41
  * The footer badge's pause icon. Claude Code's is U+23F8 (⏸); Windows Terminal
29
42
  * draws that code point with its emoji font, two cells wide and coloured,
@@ -7,7 +7,7 @@
7
7
  * of the next user message, after the reminder stack and before the user's own
8
8
  * text —
9
9
  *
10
- * <local-command-caveat>Caveat: …</local-command-caveat>\n
10
+ * <local-command-caveat>The command below was run directly in …</local-command-caveat>\n
11
11
  * <command-name>/model</command-name>\n
12
12
  * <command-message>model</command-message>\n
13
13
  * <command-args></command-args>\n
@@ -16,19 +16,23 @@
16
16
  * (twelve-space indent on the second and third command lines, verbatim from
17
17
  * CC's `formatCommandInputTags`; stdout XML-escaped like CC's `escapeXml`, `&
18
18
  * < >` only). `/clear` carries an EMPTY stdout block and opens the new
19
- * conversation. The caveat tells the model not to act on any of it.
19
+ * conversation. The caveat tells the model the command was the user's, not a
20
+ * request to it, kept as context.
20
21
  *
21
22
  * One Code emits these through the reminder queue's `user-prepend` placement
22
23
  * (`lib/reminders.ts`): pi dispatches an extension command BEFORE its `input`
23
24
  * event fires and handles its own built-ins (`/model`, `/name`, …) before
24
25
  * either, so there is no single interception point — every One Code local
25
26
  * command is registered through `registerLocalCommand`, which announces before
26
- * the handler runs, and `/model` is announced from the `model_select` event by
27
- * the extension that persists the choice. pi built-ins we cannot see
27
+ * the handler runs (or, with `reportsResult`, after it, carrying the handler's
28
+ * returned text as the stdout, as CC's `onDone(result)` does), and `/model` is
29
+ * announced from the `model_select` event by the extension that persists the
30
+ * choice. pi built-ins we cannot see
28
31
  * (`/compact`, `/settings`, …) stay silent. The blocks are pinned in process
29
32
  * memory, not written to the session file as CC does — a `--resume` drops them.
30
33
  */
31
34
 
35
+ import { announceArgumentHint, type HintEmitter, withoutExactMatch } from "./argument-hints.ts";
32
36
  import { REMINDER_CHANNEL, type ReminderPayload } from "./reminders.ts";
33
37
 
34
38
  /** The slice of pi's ExtensionAPI the announcer needs (its event bus). */
@@ -43,8 +47,9 @@ export interface ReminderEmitter {
43
47
  */
44
48
  export const LOCAL_COMMAND_TAG_PREFIXES = ["<local-command-caveat>", "<command-name>", "<command-message>", "<local-command-stdout>"] as const;
45
49
 
50
+ /** Claude Code 2.1.288's caveat, naming the harness the command ran in. */
46
51
  export const LOCAL_COMMAND_CAVEAT =
47
- "<local-command-caveat>Caveat: The messages below were generated by the user while running local commands. DO NOT respond to these messages or otherwise consider them in your response unless the user explicitly asks you to.</local-command-caveat>\n";
52
+ "<local-command-caveat>The command below was run directly in One Code, not sent to you as a request, and its output goes straight to the user. It's recorded here as context for later messages.</local-command-caveat>\n";
48
53
 
49
54
  /** CC's `escapeXml` (utils/xml.ts): `& < >` only. */
50
55
  export function escapeXml(s: string): string {
@@ -91,22 +96,51 @@ export function announceLocalCommand(pi: ReminderEmitter, command: LocalCommand)
91
96
 
92
97
  type CommandOptions = { handler: (args: string, ctx: any) => Promise<void> | void } & Record<string, unknown>;
93
98
 
99
+ /**
100
+ * What a local command passes: pi's options, plus `reportsResult` when its
101
+ * handler returns the stdout (a returned string is never silently dropped).
102
+ */
103
+ type LocalCommandOptions<O extends CommandOptions> = Omit<O, "handler"> & { argumentHint?: string } & (
104
+ | { reportsResult: true; handler: (args: string, ctx: Parameters<O["handler"]>[1]) => Promise<string | void> | string | void }
105
+ | { reportsResult?: false; handler: (args: string, ctx: Parameters<O["handler"]>[1]) => Promise<void> | void }
106
+ );
107
+
94
108
  /**
95
109
  * `pi.registerCommand` for a One Code local command: the breadcrumb is
96
- * announced before the handler runs, so no command can forget it. `/clear`
110
+ * announced before the handler runs, so no command can forget it. With
111
+ * `reportsResult`, it is announced once the handler settles instead, its
112
+ * stdout the string the handler returned (CC's `onDone(result)`; "" for none
113
+ * or a throw). Only a command that never starts a turn of its own may opt in:
114
+ * a breadcrumb queued after `sendUserMessage` would miss that message. `/clear`
97
115
  * is the one exception — it announces from the NEW session's `session_start`
98
- * (see clear/index.ts) and registers plainly.
116
+ * (see clear/index.ts) and registers plainly. `argumentHint` is the prompt's
117
+ * dim placeholder for the command's argument (lib/argument-hints.ts). Its
118
+ * completions leave out an exact match, so a fully typed argument runs on the
119
+ * first Enter (`withoutExactMatch`).
99
120
  */
100
121
  export function registerLocalCommand<O extends CommandOptions>(
101
- pi: ReminderEmitter & { registerCommand(name: string, options: O): void },
122
+ pi: ReminderEmitter & HintEmitter & { registerCommand(name: string, options: O): void },
102
123
  name: string,
103
- options: O,
124
+ options: LocalCommandOptions<O>,
104
125
  ): void {
126
+ const { argumentHint, reportsResult, ...rest } = options;
127
+ if (argumentHint) announceArgumentHint(pi, name, argumentHint);
128
+ const complete = (rest as { getArgumentCompletions?: Parameters<typeof withoutExactMatch>[0] }).getArgumentCompletions;
105
129
  pi.registerCommand(name, {
106
- ...options,
107
- handler: (args: string, ctx: unknown) => {
108
- announceLocalCommand(pi, { name, args });
109
- return options.handler(args, ctx);
130
+ ...(rest as unknown as O),
131
+ ...(complete ? { getArgumentCompletions: withoutExactMatch(complete) } : {}),
132
+ handler: async (args: string, ctx: Parameters<O["handler"]>[1]) => {
133
+ if (!reportsResult) {
134
+ announceLocalCommand(pi, { name, args });
135
+ await options.handler(args, ctx);
136
+ return;
137
+ }
138
+ let stdout = "";
139
+ try {
140
+ stdout = (await options.handler(args, ctx)) ?? "";
141
+ } finally {
142
+ announceLocalCommand(pi, { name, args, stdout });
143
+ }
110
144
  },
111
145
  });
112
146
  }
@@ -4,7 +4,7 @@
4
4
  * The /mcp panel's Disable/Enable action persists across sessions here rather
5
5
  * than by mutating the user's `~/.claude.json` or a plugin's `.mcp.json`: those
6
6
  * are Claude Code's / a plugin's config, which One Code only ever reads (the
7
- * "own state, borrowed config" rule — docs/decisions/memory-state.md). A
7
+ * "own state, borrowed config" rule — working-docs/decisions/memory-state.md). A
8
8
  * disabled server is still discovered and listed; the mcp extension just skips
9
9
  * connecting it, and the panel offers Enable to bring it back.
10
10
  *
@@ -23,3 +23,49 @@ export interface McpToolsPayload {
23
23
  */
24
24
  settled?: boolean;
25
25
  }
26
+
27
+ /** How long a child spawned while MCP is still connecting waits for the settled set. */
28
+ export const MCP_SETTLE_CAP_MS = 10_000;
29
+
30
+ /** The events slice `watchMcpTools` needs. */
31
+ export interface McpToolsEvents {
32
+ on(channel: string, handler: (data: unknown) => void): unknown;
33
+ }
34
+
35
+ /**
36
+ * Track the parent's live MCP tool definitions for in-process children (the
37
+ * subagent runner and the workflow runner). Subscribe at extension load; the
38
+ * getter resolves to the current set. The parent's MCP connect runs in the
39
+ * background, so a child spawned in the first seconds of a session waits for
40
+ * the settled publish, capped so a hung server cannot stall spawns, instead of
41
+ * baking in a still-connecting (possibly empty) snapshot. Empty when no MCP
42
+ * servers are configured.
43
+ */
44
+ export function watchMcpTools(events: McpToolsEvents, settleCapMs = MCP_SETTLE_CAP_MS): () => Promise<ToolDefinition[]> {
45
+ let tools: ToolDefinition[] = [];
46
+ let settled = false;
47
+ let resolveSettled: (() => void) | undefined;
48
+ const settledPromise = new Promise<void>((resolve) => {
49
+ resolveSettled = resolve;
50
+ });
51
+ events.on(MCP_TOOLS_CHANNEL, (data) => {
52
+ const payload = data as McpToolsPayload | undefined;
53
+ tools = payload?.tools ?? [];
54
+ if (payload?.settled) {
55
+ settled = true;
56
+ resolveSettled?.();
57
+ }
58
+ });
59
+ return async () => {
60
+ if (!settled) {
61
+ await Promise.race([
62
+ settledPromise,
63
+ new Promise<void>((resolve) => {
64
+ const timer = setTimeout(resolve, settleCapMs);
65
+ timer.unref?.();
66
+ }),
67
+ ]);
68
+ }
69
+ return tools;
70
+ };
71
+ }