one-code-extension 0.4.1 → 0.6.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 (439) hide show
  1. package/README.md +16 -5
  2. package/agents/general-purpose.md +2 -2
  3. package/docs/guide/README.md +2 -1
  4. package/docs/guide/bring-your-claude-code-setup.md +60 -9
  5. package/docs/guide/configuration.md +48 -14
  6. package/docs/guide/differences-from-claude-code.md +40 -28
  7. package/docs/guide/doctor.md +20 -13
  8. package/docs/guide/hooks.md +18 -3
  9. package/docs/guide/installation.md +26 -4
  10. package/docs/guide/permissions-modes-and-auto-mode.md +225 -49
  11. package/docs/guide/providers-and-models.md +137 -54
  12. package/docs/guide/reference.md +27 -15
  13. package/docs/guide/sessions-and-context.md +69 -16
  14. package/docs/guide/skills-plugins-and-mcp.md +57 -20
  15. package/docs/guide/subagents-and-workflows.md +95 -29
  16. package/docs/guide/tasks-and-background-work.md +101 -26
  17. package/docs/guide/terminal-interface.md +24 -12
  18. package/docs/guide/tools.md +46 -5
  19. package/docs/guide/troubleshooting.md +13 -9
  20. package/docs/guide/windows.md +58 -31
  21. package/extensions/artifacts/gallery.ts +227 -0
  22. package/extensions/artifacts/index.ts +288 -0
  23. package/extensions/artifacts/store.ts +570 -0
  24. package/extensions/artifacts/viewer.ts +199 -0
  25. package/extensions/ask-user/description.ts +67 -0
  26. package/extensions/ask-user/dialogs.ts +80 -0
  27. package/extensions/ask-user/index.ts +37 -33
  28. package/extensions/ask-user/questions.ts +32 -7
  29. package/extensions/ask-user/widget.ts +45 -25
  30. package/extensions/auto-mode/actions.ts +6 -0
  31. package/extensions/auto-mode/cache.ts +88 -0
  32. package/extensions/auto-mode/classifier-prompt.ts +5 -4
  33. package/extensions/auto-mode/classifier.ts +290 -65
  34. package/extensions/auto-mode/config.ts +72 -20
  35. package/extensions/auto-mode/decision-log.ts +2 -0
  36. package/extensions/auto-mode/defaults.ts +1 -1
  37. package/extensions/auto-mode/denials.ts +124 -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 +642 -0
  56. package/extensions/background/index.ts +614 -248
  57. package/extensions/background/loop-fire.ts +173 -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 +56 -0
  63. package/extensions/background/wakeup.ts +178 -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 +66 -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 +250 -78
  77. package/extensions/btw/panel.ts +228 -100
  78. package/extensions/btw/prompt.ts +41 -4
  79. package/extensions/cache-marks/index.ts +42 -0
  80. package/extensions/claude-compat/index.ts +7 -11
  81. package/extensions/claude-context/index.ts +436 -63
  82. package/extensions/compaction/cut.ts +157 -0
  83. package/extensions/compaction/index.ts +219 -75
  84. package/extensions/compaction/kept-thinking.ts +62 -0
  85. package/extensions/compaction/prompt.ts +15 -12
  86. package/extensions/context-budget/budget.ts +16 -2
  87. package/extensions/context-budget/index.ts +35 -15
  88. package/extensions/context-management/index.ts +36 -28
  89. package/extensions/doctor/build.ts +59 -8
  90. package/extensions/doctor/builtins.ts +84 -0
  91. package/extensions/doctor/cli.ts +7 -1
  92. package/extensions/doctor/compat.ts +88 -23
  93. package/extensions/doctor/dependencies.ts +41 -5
  94. package/extensions/doctor/fix-prompt.ts +9 -2
  95. package/extensions/doctor/index.ts +102 -58
  96. package/extensions/doctor/models.ts +102 -63
  97. package/extensions/doctor/presets.ts +42 -27
  98. package/extensions/doctor/report.ts +19 -2
  99. package/extensions/doctor/viewer.ts +49 -27
  100. package/extensions/effort/index.ts +141 -25
  101. package/extensions/effort/settings.ts +21 -0
  102. package/extensions/effort/slider.ts +24 -20
  103. package/extensions/exit/index.ts +32 -1
  104. package/extensions/file-tracker/index.ts +420 -42
  105. package/extensions/file-tracker/replay.ts +137 -24
  106. package/extensions/file-tracker/restore.ts +66 -0
  107. package/extensions/file-tracker/results.ts +66 -0
  108. package/extensions/file-tracker/shell-reads.ts +211 -0
  109. package/extensions/file-tracker/tracker.ts +45 -15
  110. package/extensions/footer/footer-line.ts +45 -24
  111. package/extensions/footer/index.ts +47 -2
  112. package/extensions/footer/pr.ts +34 -5
  113. package/extensions/hooks/compaction.ts +7 -0
  114. package/extensions/hooks/executor.ts +32 -30
  115. package/extensions/hooks/index.ts +209 -58
  116. package/extensions/hooks/matcher.ts +3 -0
  117. package/extensions/hooks/prompt-context.ts +59 -0
  118. package/extensions/hooks/protocol.ts +41 -3
  119. package/extensions/hooks/settings.ts +50 -19
  120. package/extensions/hooks/subagent-bridge.ts +2 -0
  121. package/extensions/hooks/trust.ts +26 -12
  122. package/extensions/idle-compact/index.ts +119 -0
  123. package/extensions/idle-compact/policy.ts +143 -0
  124. package/extensions/init/index.ts +11 -10
  125. package/extensions/init/prompt.ts +25 -32
  126. package/extensions/interrupted/index.ts +13 -1
  127. package/extensions/kept-thinking/index.ts +27 -0
  128. package/extensions/ledger/index.ts +46 -0
  129. package/extensions/ledger/wire.ts +154 -0
  130. package/extensions/lib/agent-cron.ts +146 -0
  131. package/extensions/lib/agent-loader.ts +18 -3
  132. package/extensions/lib/agent-view.ts +85 -0
  133. package/extensions/lib/anthropic-auth.ts +98 -0
  134. package/extensions/lib/anthropic-payload.ts +82 -1
  135. package/extensions/lib/anthropic-server-call.ts +230 -0
  136. package/extensions/lib/anthropic-server-tools.ts +485 -0
  137. package/extensions/lib/app-launch.mjs +94 -0
  138. package/extensions/lib/argument-hints.ts +190 -0
  139. package/extensions/lib/atomic-write.ts +6 -2
  140. package/extensions/lib/auto-memory.ts +75 -0
  141. package/extensions/lib/bash-parser.ts +84 -0
  142. package/extensions/lib/btw-fork.ts +93 -0
  143. package/extensions/lib/child-extensions.ts +52 -0
  144. package/extensions/lib/child-writes.ts +45 -0
  145. package/extensions/lib/claude-context.ts +515 -100
  146. package/extensions/lib/claude-external-includes.ts +68 -0
  147. package/extensions/lib/claude-id.ts +22 -0
  148. package/extensions/lib/claude-rules.ts +323 -0
  149. package/extensions/lib/claude-settings.ts +76 -4
  150. package/extensions/lib/compaction-boundary.ts +36 -0
  151. package/extensions/lib/compaction-keep.mjs +83 -0
  152. package/extensions/lib/config-mode.ts +112 -0
  153. package/extensions/lib/consent-dialogs.ts +63 -0
  154. package/extensions/lib/consent-preview.ts +5 -1
  155. package/extensions/lib/consent-stores.ts +48 -0
  156. package/extensions/lib/context-facts.ts +97 -0
  157. package/extensions/lib/covered-messages.ts +23 -0
  158. package/extensions/lib/deferred.ts +359 -25
  159. package/extensions/lib/dock-rows.ts +60 -0
  160. package/extensions/lib/empty-tool-result.ts +27 -0
  161. package/extensions/lib/environment-block.ts +76 -0
  162. package/extensions/lib/fetch-timeout.ts +24 -6
  163. package/extensions/{system-prompt → lib}/git-status.ts +51 -13
  164. package/extensions/lib/git.ts +75 -13
  165. package/extensions/lib/grammars/LICENSE-tree-sitter-bash +21 -0
  166. package/extensions/lib/grammars/README.md +2 -0
  167. package/extensions/lib/grammars/tree-sitter-bash.wasm +0 -0
  168. package/extensions/lib/guide-docs.ts +45 -0
  169. package/extensions/lib/headless-output.ts +46 -0
  170. package/extensions/lib/hook-gate.ts +7 -7
  171. package/extensions/lib/interrupt.ts +20 -4
  172. package/extensions/lib/key-input.ts +455 -0
  173. package/extensions/lib/keys.ts +14 -1
  174. package/extensions/lib/ledger/fold-memo.ts +49 -0
  175. package/extensions/lib/ledger/fold.ts +265 -0
  176. package/extensions/lib/ledger/layout.ts +72 -0
  177. package/extensions/lib/ledger/plan.ts +102 -0
  178. package/extensions/lib/ledger/records.ts +276 -0
  179. package/extensions/lib/ledger/state.ts +47 -0
  180. package/extensions/lib/ledger/validate.ts +141 -0
  181. package/extensions/lib/ledger/wire.ts +632 -0
  182. package/extensions/lib/local-command.ts +71 -19
  183. package/extensions/lib/mcp-overrides.ts +1 -1
  184. package/extensions/lib/mcp-share.ts +46 -0
  185. package/extensions/lib/memory-content.ts +146 -0
  186. package/extensions/lib/memory-index.ts +18 -0
  187. package/extensions/lib/memory.ts +134 -123
  188. package/extensions/lib/model-catalog/huggingface.json +178 -0
  189. package/extensions/lib/model-catalog/models-dev.json +18533 -0
  190. package/extensions/lib/model-catalog/openrouter.json +5050 -0
  191. package/extensions/lib/model-catalog-data.ts +513 -0
  192. package/extensions/lib/model-catalog.ts +462 -0
  193. package/extensions/lib/model-choice-warnings.ts +137 -0
  194. package/extensions/lib/model-pairings.ts +152 -0
  195. package/extensions/{auto-mode → lib}/model-picker.ts +26 -43
  196. package/extensions/lib/model-policy.ts +112 -15
  197. package/extensions/lib/model-tier.ts +283 -355
  198. package/extensions/lib/model-unusable.ts +1 -1
  199. package/extensions/lib/newer-model.ts +100 -0
  200. package/extensions/lib/notices.ts +87 -0
  201. package/extensions/lib/notifications.ts +357 -73
  202. package/extensions/lib/one-code-settings.ts +74 -8
  203. package/extensions/lib/open-browser.ts +63 -0
  204. package/extensions/lib/openrouter-generation.ts +94 -0
  205. package/extensions/lib/operation-deadline.ts +30 -0
  206. package/extensions/lib/original-command.ts +4 -4
  207. package/extensions/lib/package-version.ts +1 -1
  208. package/extensions/lib/panel-focus.ts +134 -0
  209. package/extensions/lib/paths.ts +17 -2
  210. package/extensions/lib/permission-gate.ts +72 -6
  211. package/extensions/lib/persisted-output.ts +60 -8
  212. package/extensions/lib/pi-ai-estimate.ts +19 -3
  213. package/extensions/lib/pi-version.ts +38 -2
  214. package/extensions/lib/plan-mode-channels.ts +42 -5
  215. package/extensions/lib/plugins.ts +26 -17
  216. package/extensions/lib/powershell-parse-script.ts +208 -0
  217. package/extensions/lib/powershell-parser.ts +344 -0
  218. package/extensions/lib/previous-mark.ts +101 -0
  219. package/extensions/lib/process-state.ts +48 -0
  220. package/extensions/lib/process-tree.ts +132 -8
  221. package/extensions/lib/prompt-options.ts +82 -0
  222. package/extensions/lib/queued-delivery.ts +44 -0
  223. package/extensions/lib/reminders.ts +370 -358
  224. package/extensions/lib/replaced-builtins.mjs +199 -0
  225. package/extensions/lib/replay-call.ts +70 -0
  226. package/extensions/lib/request-replay.ts +547 -0
  227. package/extensions/lib/scratchpad.ts +81 -14
  228. package/extensions/lib/send-now-channel.ts +7 -0
  229. package/extensions/lib/session-model-tier.ts +51 -0
  230. package/extensions/lib/session-work.ts +64 -0
  231. package/extensions/lib/settings-channels.ts +4 -4
  232. package/extensions/lib/shell-exit-semantics.ts +170 -0
  233. package/extensions/lib/shell-quote.ts +11 -0
  234. package/extensions/lib/shell-result.ts +70 -0
  235. package/extensions/lib/shell-spawn.ts +70 -6
  236. package/extensions/lib/shell-tool.ts +75 -25
  237. package/extensions/lib/side-call-cache.ts +124 -0
  238. package/extensions/lib/side-call-run.ts +96 -0
  239. package/extensions/lib/side-call-usage.ts +38 -0
  240. package/extensions/lib/side-call.ts +24 -1
  241. package/extensions/lib/single-flight.ts +18 -0
  242. package/extensions/lib/skill-body.ts +42 -0
  243. package/extensions/lib/skill-scan.ts +63 -24
  244. package/extensions/lib/spill-file.ts +140 -0
  245. package/extensions/lib/subagent-handback.ts +112 -0
  246. package/extensions/lib/system-role.ts +156 -0
  247. package/extensions/lib/terminal-text.ts +114 -0
  248. package/extensions/lib/text-width.ts +47 -16
  249. package/extensions/lib/timer-ops.ts +20 -0
  250. package/extensions/lib/tool-additions.ts +129 -0
  251. package/extensions/lib/tool-call-corruption.ts +134 -0
  252. package/extensions/lib/tool-path.ts +66 -0
  253. package/extensions/lib/tool-variants.ts +69 -0
  254. package/extensions/lib/tui-render.ts +255 -27
  255. package/extensions/lib/turn-budget-layout.ts +159 -0
  256. package/extensions/lib/update-check.mjs +15 -2
  257. package/extensions/lib/usage-bus.ts +1 -1
  258. package/extensions/lib/user-denial.ts +38 -0
  259. package/extensions/lib/workspace-channel.ts +16 -0
  260. package/extensions/lib/worktree-channel.ts +31 -3
  261. package/extensions/lib/worktree-isolation.ts +40 -10
  262. package/extensions/lsp/client.ts +8 -9
  263. package/extensions/lsp/index.ts +76 -12
  264. package/extensions/lsp/keep-alive.ts +1 -1
  265. package/extensions/lsp/trust.ts +119 -0
  266. package/extensions/lsp/watcher.ts +1 -1
  267. package/extensions/mcp/announce.ts +90 -43
  268. package/extensions/mcp/client.ts +161 -48
  269. package/extensions/mcp/config.ts +132 -8
  270. package/extensions/mcp/discovery.ts +19 -0
  271. package/extensions/mcp/index.ts +220 -121
  272. package/extensions/mcp/oauth/browser.ts +38 -17
  273. package/extensions/mcp/oauth/flow.ts +25 -17
  274. package/extensions/mcp/oauth/provider.ts +14 -8
  275. package/extensions/mcp/oauth/store.ts +34 -16
  276. package/extensions/mcp/panel/keys.ts +12 -11
  277. package/extensions/mcp/panel/render.ts +9 -6
  278. package/extensions/mcp/schema.ts +104 -5
  279. package/extensions/mcp/trust.ts +164 -73
  280. package/extensions/memory/entries.ts +23 -14
  281. package/extensions/memory/index.ts +134 -28
  282. package/extensions/memory/open-external.ts +33 -18
  283. package/extensions/memory/panel.ts +135 -26
  284. package/extensions/model-default/index.ts +86 -19
  285. package/extensions/newer-model/index.ts +31 -0
  286. package/extensions/notebook/description.ts +18 -0
  287. package/extensions/notebook/index.ts +6 -5
  288. package/extensions/notebook/notebook.ts +1 -1
  289. package/extensions/permissions/index.ts +1426 -398
  290. package/extensions/permissions/matcher.ts +425 -74
  291. package/extensions/permissions/modes.ts +11 -4
  292. package/extensions/permissions/panel/host.ts +130 -0
  293. package/extensions/permissions/panel/keys.ts +48 -0
  294. package/extensions/permissions/panel/render.ts +450 -0
  295. package/extensions/permissions/panel/state.ts +550 -0
  296. package/extensions/permissions/powershell-cmdlets.ts +198 -0
  297. package/extensions/permissions/powershell-paths.ts +197 -0
  298. package/extensions/permissions/powershell-rules.ts +207 -280
  299. package/extensions/permissions/powershell-tree.ts +557 -0
  300. package/extensions/permissions/project-trust.ts +27 -11
  301. package/extensions/permissions/protected-paths.ts +14 -2
  302. package/extensions/permissions/session-grant.ts +6 -0
  303. package/extensions/permissions/settings.ts +166 -31
  304. package/extensions/permissions/subagent-gate.ts +25 -0
  305. package/extensions/permissions/workspace.ts +78 -0
  306. package/extensions/plan-mode/index.ts +276 -92
  307. package/extensions/plan-mode/reminder.ts +89 -21
  308. package/extensions/plan-mode/run-state.ts +26 -0
  309. package/extensions/plan-mode/texts.ts +177 -0
  310. package/extensions/plan-mode/viewer.ts +92 -27
  311. package/extensions/plugins/counts.ts +3 -3
  312. package/extensions/plugins/index.ts +64 -46
  313. package/extensions/plugins/install/install.ts +16 -0
  314. package/extensions/plugins/marketplace/sync.ts +9 -3
  315. package/extensions/plugins/marketplace/types.ts +3 -1
  316. package/extensions/plugins/panel/keys.ts +21 -24
  317. package/extensions/plugins/panel/render.ts +12 -6
  318. package/extensions/plugins/shell-expand.ts +107 -0
  319. package/extensions/plugins/template.ts +32 -15
  320. package/extensions/powershell/child.ts +7 -0
  321. package/extensions/powershell/description.ts +38 -6
  322. package/extensions/powershell/guards.ts +1 -1
  323. package/extensions/powershell/index.ts +14 -7
  324. package/extensions/recap/index.ts +73 -71
  325. package/extensions/recap/prompt.ts +2 -2
  326. package/extensions/recap/scheduler.ts +3 -5
  327. package/extensions/search-tools/grep-merge.ts +39 -0
  328. package/extensions/search-tools/index.ts +0 -0
  329. package/extensions/send-now/chord.ts +62 -0
  330. package/extensions/send-now/index.ts +133 -0
  331. package/extensions/session-title/index.ts +3 -0
  332. package/extensions/session-title/title.ts +4 -1
  333. package/extensions/skill/announce.ts +30 -0
  334. package/extensions/skill/code-review.ts +97 -0
  335. package/extensions/skill/index.ts +469 -132
  336. package/extensions/skill/invoke.ts +118 -75
  337. package/extensions/skill/listing.ts +133 -9
  338. package/extensions/skill/panel/keys.ts +15 -16
  339. package/extensions/skill/panel/render.ts +5 -2
  340. package/extensions/skill/panel/state.ts +12 -1
  341. package/extensions/subagents/agent-args.ts +39 -0
  342. package/extensions/subagents/agent-description.ts +132 -0
  343. package/extensions/subagents/agents.ts +146 -31
  344. package/extensions/subagents/default-model.ts +2 -3
  345. package/extensions/subagents/delegation-steer.ts +4 -4
  346. package/extensions/subagents/fork-cache.ts +82 -0
  347. package/extensions/subagents/guide-agent.ts +189 -0
  348. package/extensions/subagents/hand-back-review.ts +3 -0
  349. package/extensions/subagents/index.ts +1594 -852
  350. package/extensions/subagents/live-runs.ts +26 -6
  351. package/extensions/subagents/model-select.ts +38 -25
  352. package/extensions/subagents/outcome.ts +5 -2
  353. package/extensions/subagents/panel-keys.ts +73 -31
  354. package/extensions/subagents/panel-render.ts +120 -96
  355. package/extensions/subagents/panel-widget.ts +60 -89
  356. package/extensions/subagents/parent-mode.ts +50 -0
  357. package/extensions/subagents/pending-claim.ts +18 -1
  358. package/extensions/subagents/runner.ts +135 -80
  359. package/extensions/subagents/runs.ts +44 -5
  360. package/extensions/subagents/send-to-main-tool.ts +1 -1
  361. package/extensions/subagents/session-turns.ts +32 -8
  362. package/extensions/subagents/shell-panel.ts +36 -178
  363. package/extensions/subagents/tasks-dialog.ts +170 -0
  364. package/extensions/subagents/viewport-mirror.ts +95 -0
  365. package/extensions/subagents/worktree.ts +57 -13
  366. package/extensions/system-prompt/environment.ts +19 -19
  367. package/extensions/system-prompt/idle-turn.ts +65 -0
  368. package/extensions/system-prompt/index.ts +165 -47
  369. package/extensions/system-prompt/template.ts +34 -51
  370. package/extensions/system-prompt/tiers/common.ts +23 -64
  371. package/extensions/system-prompt/tiers/frontier.ts +32 -11
  372. package/extensions/system-prompt/tiers/low.ts +67 -45
  373. package/extensions/system-prompt/tiers/mid.ts +96 -38
  374. package/extensions/system-reminder/index.ts +204 -70
  375. package/extensions/tasks/descriptions.ts +190 -0
  376. package/extensions/tasks/index.ts +120 -41
  377. package/extensions/tasks/store.ts +83 -16
  378. package/extensions/tool-call-corruption/child.ts +7 -0
  379. package/extensions/tool-call-corruption/index.ts +237 -0
  380. package/extensions/tool-search/index.ts +366 -144
  381. package/extensions/tool-style/index.ts +68 -10
  382. package/extensions/tool-style/write-description.ts +40 -0
  383. package/extensions/tool-style/write-render.ts +237 -0
  384. package/extensions/turn-duration/index.ts +7 -3
  385. package/extensions/turn-duration/line.ts +47 -4
  386. package/extensions/web/backends.ts +6 -9
  387. package/extensions/web/description.ts +50 -0
  388. package/extensions/web/index.ts +118 -53
  389. package/extensions/web/native-call.ts +15 -0
  390. package/extensions/web/native-results.ts +41 -0
  391. package/extensions/web-fetch/description.ts +42 -0
  392. package/extensions/web-fetch/extract.ts +53 -6
  393. package/extensions/web-fetch/index.ts +125 -76
  394. package/extensions/web-fetch/page-content.ts +19 -0
  395. package/extensions/web-fetch/response.ts +49 -0
  396. package/extensions/web-fetch/summarize.ts +9 -10
  397. package/extensions/workflow/agent-session.ts +108 -18
  398. package/extensions/workflow/args.ts +24 -0
  399. package/extensions/workflow/description.ts +67 -0
  400. package/extensions/workflow/globals.ts +17 -3
  401. package/extensions/workflow/index.ts +157 -162
  402. package/extensions/workflow/records.ts +1 -0
  403. package/extensions/workflow/run-manager.ts +33 -6
  404. package/extensions/workflow/saved-workflows.ts +3 -2
  405. package/extensions/workflow/types.ts +22 -1
  406. package/extensions/workflow/viewer.ts +54 -24
  407. package/extensions/workflow/widget.ts +20 -0
  408. package/extensions/worktree/descriptions.ts +91 -0
  409. package/extensions/worktree/guards.ts +316 -54
  410. package/extensions/worktree/index.ts +162 -44
  411. package/extensions/worktree/powershell-guards.ts +167 -0
  412. package/extensions/worktree/rewrite.ts +14 -16
  413. package/package.json +21 -7
  414. package/skills/artifact-design/SKILL.md +85 -0
  415. package/skills/code-review/SKILL.md +20 -20
  416. package/skills/code-review/cells/arguments-and-flags.md +19 -0
  417. package/skills/code-review/cells/high-3x5-recall-verify.md +137 -0
  418. package/skills/code-review/cells/high-8-inline.md +122 -0
  419. package/skills/code-review/cells/low-1-pass-max4.md +27 -0
  420. package/skills/code-review/cells/low-1-pass-min-files-4.md +28 -0
  421. package/skills/code-review/cells/max-5x5-verify-sweep.md +162 -0
  422. package/skills/code-review/cells/medium-3x5-verify.md +132 -0
  423. package/skills/code-review/cells/minimal-prompt.md +32 -0
  424. package/skills/code-review/cells/xhigh-10-inline-sweep.md +149 -0
  425. package/skills/code-review/cells/xhigh-5x5-verify-sweep.md +162 -0
  426. package/skills/fewer-permission-prompts/SKILL.md +1 -1
  427. package/skills/loop/SKILL.md +11 -0
  428. package/skills/security-review/SKILL.md +2 -5
  429. package/skills/simplify/SKILL.md +7 -5
  430. package/skills/workflow-authoring/SKILL.md +143 -0
  431. package/themes/onecode-light.json +1 -1
  432. package/themes/onecode.json +1 -1
  433. package/types/app.d.ts +58 -0
  434. package/types/community-packages.d.ts +26 -1
  435. package/extensions/auto-mode/recoverability.ts +0 -229
  436. package/extensions/lib/capability-index.ts +0 -466
  437. package/extensions/lib/model-facts.generated.json +0 -2675
  438. package/extensions/lib/model-facts.ts +0 -162
  439. package/extensions/tool-search/announce.ts +0 -42
@@ -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,
@@ -0,0 +1,49 @@
1
+ /**
2
+ * One fold per branch state: the extensions that read the ledger's fold
3
+ * (the ledger's `context` hook, its payload hook, tool-search, claude-context)
4
+ * share the last fold of each session instead of folding the same branch
5
+ * again. `foldBranch` is O(requests × list length), and tool-search folds at
6
+ * every `turn_start`, moments before the ledger's `context` hook folds the
7
+ * same branch for the request (in every child session too).
8
+ *
9
+ * The memo lives in process state (lib/process-state.ts), since each
10
+ * extension file evaluates its own copy of this module (findings §3), keyed
11
+ * by the session manager. A hit needs the same identity and the same entries
12
+ * (every entry the same object, in the same order): any appended entry, a
13
+ * different leaf or a rebuilt branch misses, so it never returns another
14
+ * branch's fold. The fold is a pure function of the two, and its readers
15
+ * never mutate it.
16
+ *
17
+ * Pure: no pi imports.
18
+ */
19
+ import { processState } from "../process-state.ts";
20
+ import { foldBranch, type LedgerFold } from "./fold.ts";
21
+ import type { EntryLike, RequestIdentity } from "./records.ts";
22
+
23
+ interface Memo {
24
+ /** A copy of the branch it folded: `getBranch()` may hand back a list that grows in place. */
25
+ entries: readonly EntryLike[];
26
+ identity: string;
27
+ fold: LedgerFold;
28
+ }
29
+
30
+ const memos = () => processState("ledger:fold-memo", () => new WeakMap<object, Memo>());
31
+
32
+ /** Whether two branches hold the same entries, each the same object, in the same order: the key a memo of anything derived from a branch takes. */
33
+ export const sameEntries = (a: readonly unknown[], b: readonly unknown[]) => a.length === b.length && a.every((entry, i) => entry === b[i]);
34
+
35
+ /** `foldBranch(branch, identity)`, reused while `owner`'s branch and the identity stay the same. Without an owner it folds. */
36
+ export function foldOnce(owner: object | undefined, branch: readonly EntryLike[], identity: RequestIdentity | undefined): LedgerFold {
37
+ if (!owner) return foldBranch(branch, identity);
38
+ const key = JSON.stringify(identity ?? null);
39
+ const memo = memos().get(owner);
40
+ if (memo && memo.identity === key && sameEntries(memo.entries, branch)) return memo.fold;
41
+ const fold = foldBranch(branch, identity);
42
+ memos().set(owner, { entries: [...branch], identity: key, fold });
43
+ return fold;
44
+ }
45
+
46
+ /** The fold of a session's current branch under `identity` (`sessionIdentity`, lib/anthropic-auth.ts). */
47
+ export function foldSession(sessionManager: { getBranch(): unknown[] } | undefined, identity: RequestIdentity | undefined): LedgerFold {
48
+ return foldOnce(sessionManager, (sessionManager?.getBranch() ?? []) as EntryLike[], identity);
49
+ }