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
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * effort extension — Claude Code's `/effort`, including the `ultracode` stop.
3
3
  *
4
+ * Interactive low/medium/high/xhigh choices persist per model in pi's own
5
+ * settings (`modelThinkingLevels`); max and ultracode stay session-only. pi
6
+ * restores the saved level natively, so launch overrides and resume still win.
7
+ *
4
8
  * Reasoning effort is pi's thinking level under another name, and shift+tab
5
9
  * already cycles it. pi reserves that key (`app.thinking.cycle` is on its
6
10
  * RESERVED_KEYBINDINGS_FOR_EXTENSION_CONFLICTS list, so `registerShortcut` on
@@ -17,10 +21,14 @@
17
21
  * same shape the permissions extension uses for plan mode.
18
22
  */
19
23
 
24
+ import os from "node:os";
25
+ import { join } from "node:path";
20
26
  import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
21
27
  import { getSupportedThinkingLevels } from "@earendil-works/pi-ai/compat";
22
- import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
23
- import { REMINDER_CHANNEL } from "../lib/reminders.ts";
28
+ import { getAgentDir, SettingsManager, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
29
+ import { effortSetMessage, isPersistedEffort, type PersistedEffort } from "./settings.ts";
30
+ import { REMINDER_CHANNEL, RENDER_CHANNEL, type RenderRequest, stickyFact, toldBlockFact } from "../lib/reminders.ts";
31
+ import { readState, recordState } from "../lib/ledger/state.ts";
24
32
  import { dimRightAlignedWidget, safeThemePaint, truncateLine } from "../lib/tui-render.ts";
25
33
  import {
26
34
  acceptedEffortArgs,
@@ -43,6 +51,9 @@ import {
43
51
  ULTRACODE_STATUS_KEY,
44
52
  } from "./slider.ts";
45
53
  import { registerLocalCommand } from "../lib/local-command.ts";
54
+ import { readWorkflowSettings } from "../lib/one-code-settings.ts";
55
+ import { panelUi } from "../lib/panel-focus.ts";
56
+ import { extendingCompletions } from "../lib/argument-hints.ts";
46
57
 
47
58
  /** The levels pi says the active model can reach; the full ladder when unknown. */
48
59
  function supportedLevels(ctx: ExtensionContext): ThinkingLevel[] {
@@ -70,6 +81,28 @@ const ULTRACODE_STANDING_REMINDER =
70
81
  "Token cost is not the constraint here; the most exhaustive correct answer is. " +
71
82
  "Work solo only on conversational turns and trivial mechanical edits.";
72
83
 
84
+ /**
85
+ * Said once when ultracode is off while the model has read its standing block:
86
+ * the earlier messages keep the block in the record, so without this the model
87
+ * reads the opt-in as standing (lifecycle-grid-hunt round 3, R3-M21).
88
+ */
89
+ const ULTRACODE_OFF_REMINDER =
90
+ "Ultracode mode is off now: the user's standing opt-in to multi-agent orchestration has ended. Run a workflow only when the task calls for one or the user asks.";
91
+ /**
92
+ * The told key of the standing block: a request that carries its first
93
+ * delivery records the block's hash under it (system-reminder).
94
+ */
95
+ const STANDING_TOLD_KEY = stickyFact({ key: REMINDER_KEY, text: "", since: 0 }).key;
96
+ /**
97
+ * What the off notice tells, under the same key: the model last read "off".
98
+ * The standing block switched on again is then a first delivery once more,
99
+ * and a later off is told again only after that delivery.
100
+ */
101
+ const OFF_TOLD = toldBlockFact(STANDING_TOLD_KEY, ULTRACODE_OFF_REMINDER);
102
+
103
+ /** The `one-code:state` key ultracode is recorded under on the branch. */
104
+ const ULTRACODE_STATE = "ultracode";
105
+
73
106
  export default function effortExtension(pi: ExtensionAPI) {
74
107
  let ultracodeActive = false;
75
108
  /**
@@ -109,15 +142,22 @@ export default function effortExtension(pi: ExtensionAPI) {
109
142
  pi.on("session_start", cancelEffortNote);
110
143
  pi.on("session_shutdown", cancelEffortNote);
111
144
 
112
- const setUltracode = (on: boolean, level?: ThinkingLevel) => {
113
- const changed = ultracodeActive !== on;
145
+ /** Whether workflows are on for this session, read with workflow's own settings at session start. */
146
+ let workflowsOn = true;
147
+ /** `record` false when the state comes from the branch itself (a resume, a /tree switch). */
148
+ const setUltracode = (on: boolean, level?: ThinkingLevel, { record = true }: { record?: boolean } = {}) => {
149
+ const changed = ultracodeActive !== on || (on && ultracodeLevel !== level);
114
150
  ultracodeActive = on;
115
151
  ultracodeLevel = on ? level : undefined;
116
152
  if (changed) pi.events.emit(ULTRACODE_MODE_CHANNEL, { active: on });
117
- if (on) {
153
+ // Ultracode follows the branch: recorded on every change.
154
+ if (changed && record) recordState(pi, ULTRACODE_STATE, on ? { on, level } : { on });
155
+ // With workflows turned off (enableWorkflows/disableWorkflows) the block's
156
+ // "run a workflow for every task" would steer to a tool the session does
157
+ // not offer, so ultracode is only its reasoning level there (R3-M21).
158
+ if (on && workflowsOn) {
118
159
  pi.events.emit(REMINDER_CHANNEL, {
119
160
  text: ULTRACODE_STANDING_REMINDER,
120
- scope: "every-turn",
121
161
  key: REMINDER_KEY,
122
162
  placement: "sticky-append",
123
163
  });
@@ -126,8 +166,40 @@ export default function effortExtension(pi: ExtensionAPI) {
126
166
  }
127
167
  };
128
168
 
169
+ // The off notice derives from what the epoch told, when a request goes out:
170
+ // only a model that read the standing block hears it ended, a switch off and
171
+ // on again before the request says nothing, and the notice's own told fact
172
+ // keeps a /reload or a resume from saying it twice.
173
+ pi.events.on(RENDER_CHANNEL, (data) => {
174
+ const request = data as RenderRequest;
175
+ if (request.epoch || ultracodeActive) return;
176
+ const told = request.toldBlocks.get(STANDING_TOLD_KEY);
177
+ if (told === undefined || told === OFF_TOLD.hash) return;
178
+ request.blocks.push({ text: ULTRACODE_OFF_REMINDER, facts: [OFF_TOLD] });
179
+ });
180
+
181
+ const canPersist = (ctx: ExtensionContext) => ctx.hasUI && (ctx.mode === "tui" || ctx.mode === "rpc") && !!ctx.model;
182
+ /** Through pi's own settings writer: its key format, file lock and merge of changed fields. */
183
+ const persist = async (ctx: ExtensionContext, level: PersistedEffort | undefined): Promise<string | undefined> => {
184
+ const settings = SettingsManager.create(ctx.cwd, getAgentDir());
185
+ const loadError = settings.drainErrors().find((entry) => entry.scope === "global");
186
+ // An unreadable file would be rewritten from empty settings; leave it for the user.
187
+ if (loadError) return `Failed to set effort level: ${loadError.error.message}`;
188
+ if (level === undefined) settings.removeModelThinkingLevel(ctx.model!.provider, ctx.model!.id);
189
+ else settings.setModelThinkingLevel(ctx.model!.provider, ctx.model!.id, level);
190
+ await settings.flush();
191
+ const writeError = settings.drainErrors()[0];
192
+ if (writeError) return `Failed to set effort level: ${writeError.error.message}`;
193
+ };
194
+ const report = (ctx: ExtensionContext, message: string, error = false) => {
195
+ ctx.ui.notify(message, error ? "error" : "info");
196
+ return message;
197
+ };
198
+
129
199
  /** Apply a chosen stop and report what actually took effect. */
130
- const applyChoice = (choice: EffortChoice, ctx: ExtensionContext) => {
200
+ const applyChoice = async (choice: EffortChoice, ctx: ExtensionContext, asDefault = true): Promise<string> => {
201
+ const wasUltracode = ultracodeActive;
202
+ const previous = pi.getThinkingLevel();
131
203
  const wanted = thinkingLevelFor(choice);
132
204
  pi.setThinkingLevel(wanted);
133
205
  const actual = pi.getThinkingLevel();
@@ -144,13 +216,25 @@ export default function effortExtension(pi: ExtensionAPI) {
144
216
  const cappedDown = ar >= 0 && wr >= 0 && ar < wr;
145
217
  const note = cappedDown ? ` (${modelLabel(ctx)} tops out at ${actual})` : "";
146
218
  if (choice === ULTRACODE) {
147
- ctx.ui.notify(`Effort: ultracode — ${actual} reasoning, workflows armed every turn${note}`, "info");
148
- } else {
149
- ctx.ui.notify(`Effort: ${actual}${note}`, "info");
219
+ return report(ctx, `Effort: ultracode — ${actual} reasoning, workflows armed every turn${note}`);
220
+ }
221
+ const saved = asDefault && canPersist(ctx) && isPersistedEffort(choice) && actual === wanted;
222
+ if (saved) {
223
+ const error = await persist(ctx, choice);
224
+ if (error) {
225
+ // Claude Code changes nothing when the save fails.
226
+ pi.setThinkingLevel(previous);
227
+ setUltracode(wasUltracode, previous);
228
+ applyStatus(ctx);
229
+ showEffortNote(ctx, previous);
230
+ return report(ctx, error, true);
231
+ }
150
232
  }
233
+ if (isPersistedEffort(actual) || actual === "max") return report(ctx, `${effortSetMessage(actual, saved)}${wasUltracode ? " · Ultracode off" : ""}`);
234
+ return report(ctx, `Effort: ${actual}${note}`);
151
235
  };
152
236
 
153
- const showSlider = async (ctx: ExtensionContext): Promise<void> => {
237
+ const showSlider = async (ctx: ExtensionContext): Promise<string | void> => {
154
238
  const supported = supportedLevels(ctx);
155
239
  if (!supported.some((level) => level !== "off")) {
156
240
  ctx.ui.notify(`${modelLabel(ctx)} doesn't support reasoning effort.`, "info");
@@ -165,7 +249,7 @@ export default function effortExtension(pi: ExtensionAPI) {
165
249
  index = nearestEnabled(index, enabled);
166
250
 
167
251
  const label = modelLabel(ctx);
168
- const chosen = await ctx.ui.custom<EffortChoice | null>((tui, theme, _keybindings, done) => {
252
+ const chosen = await panelUi(pi.events, ctx.ui).custom<{ choice: EffortChoice; asDefault: boolean } | null>((tui, theme, _keybindings, done) => {
169
253
  const paint = safeThemePaint(theme);
170
254
  return {
171
255
  // The slider's own layout is column-safe for its ASCII labels, but this
@@ -180,8 +264,8 @@ export default function effortExtension(pi: ExtensionAPI) {
180
264
  done(null);
181
265
  return;
182
266
  }
183
- if (key === "confirm") {
184
- done(EFFORT_CHOICES[index]);
267
+ if (key === "confirm" || key === "session") {
268
+ done({ choice: EFFORT_CHOICES[index], asDefault: key === "confirm" });
185
269
  return;
186
270
  }
187
271
  index = moveIndex(index, key, enabled);
@@ -191,18 +275,32 @@ export default function effortExtension(pi: ExtensionAPI) {
191
275
  };
192
276
  });
193
277
 
194
- if (chosen) applyChoice(chosen, ctx);
278
+ if (!chosen) return "Cancelled";
279
+ return applyChoice(chosen.choice, ctx, chosen.asDefault);
195
280
  };
196
281
 
197
282
  registerLocalCommand(pi, "effort", {
198
- description: `Set reasoning effort (shift+tab cycles the plain levels): /effort [${EFFORT_CHOICES.join("|")}] — ultracode is ${ULTRACODE_LEVEL} + workflows`,
199
- getArgumentCompletions: (prefix) => {
200
- const matches = acceptedEffortArgs().filter((value) => value.startsWith(prefix.trim().toLowerCase()));
201
- return matches.length ? matches.map((value) => ({ value, label: value })) : null;
202
- },
283
+ description: `Set reasoning effort (shift+tab cycles the plain levels): /effort [${EFFORT_CHOICES.join("|")}|auto] — ultracode is ${ULTRACODE_LEVEL} + workflows`,
284
+ argumentHint: `[${EFFORT_CHOICES.join("|")}|auto]`,
285
+ reportsResult: true,
286
+ getArgumentCompletions: (prefix) => extendingCompletions(prefix, [...acceptedEffortArgs(), "auto", "unset"].map((value) => ({ value, label: value }))),
203
287
  handler: async (args, ctx) => {
204
288
  const typed = args.trim();
205
289
  if (typed) {
290
+ if (typed.toLowerCase() === "auto" || typed.toLowerCase() === "unset") {
291
+ // Clear the saved level first: a failed save changes nothing.
292
+ const saved = canPersist(ctx);
293
+ if (saved) {
294
+ const error = await persist(ctx, undefined);
295
+ if (error) return report(ctx, error, true);
296
+ }
297
+ // getSettings arrived in pi 1.0.1; a 1.0.0 install falls back to pi's default.
298
+ pi.setThinkingLevel(pi.getSettings?.().defaultThinkingLevel ?? "medium");
299
+ setUltracode(false);
300
+ applyStatus(ctx);
301
+ showEffortNote(ctx, pi.getThinkingLevel());
302
+ return report(ctx, `Effort level set to auto${saved ? "" : " (this session only)"}`);
303
+ }
206
304
  const parsed = parseEffortArg(typed);
207
305
  if (!parsed) {
208
306
  ctx.ui.notify(`Unknown effort "${typed}". Use one of: ${acceptedEffortArgs().join(", ")}`, "error");
@@ -220,20 +318,19 @@ export default function effortExtension(pi: ExtensionAPI) {
220
318
  return;
221
319
  }
222
320
  }
223
- applyChoice(parsed, ctx);
224
- return;
321
+ return applyChoice(parsed, ctx);
225
322
  }
226
323
 
227
324
  // The picker needs focus and a terminal; elsewhere say what to type.
228
325
  if (!ctx.hasUI || ctx.mode !== "tui") {
229
326
  ctx.ui.notify(
230
327
  `Current effort: ${ultracodeActive ? `ultracode (${pi.getThinkingLevel()} + workflows)` : pi.getThinkingLevel()}. ` +
231
- `Set one with /effort <${acceptedEffortArgs().join("|")}>.`,
328
+ `Set one with /effort <${acceptedEffortArgs().join("|")}|auto>.`,
232
329
  "info",
233
330
  );
234
331
  return;
235
332
  }
236
- await showSlider(ctx);
333
+ return await showSlider(ctx);
237
334
  },
238
335
  });
239
336
 
@@ -248,7 +345,26 @@ export default function effortExtension(pi: ExtensionAPI) {
248
345
  showEffortNote(ctx, event.level);
249
346
  });
250
347
 
251
- pi.on("session_start", (_event, ctx) => {
348
+ /**
349
+ * Take the branch's ultracode state (a resume, /reload, a fork, a /tree
350
+ * switch). At a session start it is on only while pi's reasoning level,
351
+ * which pi restores from the branch itself, is still the level ultracode
352
+ * settled on (a launch `--thinking` flag wins). pi restores no level at a
353
+ * /tree switch, so there the branch's level is put back with the mode.
354
+ * When the branch's model read it on and it resolves off, the next request
355
+ * tells it (the RENDER_CHANNEL listener above).
356
+ */
357
+ const followBranch = (ctx: ExtensionContext, tree: boolean) => {
358
+ const stored = readState(ctx, ULTRACODE_STATE) as { on?: unknown; level?: unknown } | undefined;
359
+ const storedOn = stored?.on === true && typeof stored.level === "string";
360
+ const on = storedOn && (tree || stored.level === pi.getThinkingLevel());
361
+ setUltracode(on, on ? (stored?.level as ThinkingLevel) : undefined, { record: false });
362
+ if (on && tree && pi.getThinkingLevel() !== stored?.level) pi.setThinkingLevel(stored?.level as ThinkingLevel);
252
363
  applyStatus(ctx);
364
+ };
365
+ pi.on("session_start", (_event, ctx) => {
366
+ workflowsOn = readWorkflowSettings(ctx.cwd, os.homedir()).enabled;
367
+ followBranch(ctx, false);
253
368
  });
369
+ pi.on("session_tree", (_event, ctx) => followBranch(ctx, true));
254
370
  }
@@ -0,0 +1,21 @@
1
+ /** Which effort levels are saved, and the result text (pure, no pi imports). */
2
+
3
+ const PERSISTED_LEVELS = ["low", "medium", "high", "xhigh"] as const;
4
+ export type PersistedEffort = (typeof PERSISTED_LEVELS)[number];
5
+
6
+ export function isPersistedEffort(level: string): level is PersistedEffort {
7
+ return (PERSISTED_LEVELS as readonly string[]).includes(level);
8
+ }
9
+
10
+ const DESCRIPTIONS: Record<string, string> = {
11
+ low: "Quick, straightforward implementation with minimal overhead",
12
+ medium: "Balanced approach with standard implementation and testing",
13
+ high: "Comprehensive implementation with extensive testing and documentation",
14
+ xhigh: "Deeper reasoning than high, just below maximum (on supported models)",
15
+ max: "Maximum capability with deepest reasoning. May use excessive tokens resulting in long response times or overthinking. Use sparingly for the hardest tasks.",
16
+ };
17
+
18
+ /** The ordinary local response, without organization or environment overrides. */
19
+ export function effortSetMessage(level: PersistedEffort | "max", saved: boolean): string {
20
+ return `Set effort level to ${level} (${saved ? "saved as your default for new sessions" : "this session only"}): ${DESCRIPTIONS[level]}`;
21
+ }
@@ -18,6 +18,7 @@
18
18
  */
19
19
 
20
20
  import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
21
+ import { keyId, keyText } from "../lib/key-input.ts";
21
22
 
22
23
  /** The final stop on the track: top reasoning + workflows armed every turn. */
23
24
  export const ULTRACODE = "ultracode";
@@ -73,35 +74,38 @@ export function choiceForState(level: ThinkingLevel | undefined, ultracodeActive
73
74
  return "medium";
74
75
  }
75
76
 
76
- export type SliderKey = "left" | "right" | "first" | "last" | "confirm" | "cancel";
77
+ export type SliderKey = "left" | "right" | "first" | "last" | "confirm" | "session" | "cancel";
77
78
 
78
79
  /**
79
80
  * Decode a raw terminal chunk. `Component.handleInput` hands over bytes, not key
80
- * names, so the sequences are matched directly: CSI C/D for arrows (plus the
81
- * older SS3 form some terminals still send), CR/LF to confirm, ESC to cancel.
81
+ * names; `lib/key-input.ts` names them, so every terminal encoding of a key
82
+ * (legacy, kitty, modifyOtherKeys) decodes alike.
82
83
  */
83
84
  export function decodeKey(data: string): SliderKey | undefined {
84
- switch (data) {
85
- case "\x1b[C":
86
- case "\x1bOC":
87
- case "l":
85
+ switch (keyId(data)) {
86
+ case "right":
88
87
  return "right";
89
- case "\x1b[D":
90
- case "\x1bOD":
91
- case "h":
88
+ case "left":
92
89
  return "left";
93
- case "\x1b[H":
94
- case "\x1b[1~":
90
+ case "home":
95
91
  return "first";
96
- case "\x1b[F":
97
- case "\x1b[4~":
92
+ case "end":
98
93
  return "last";
99
- case "\r":
100
- case "\n":
94
+ case "enter":
101
95
  return "confirm";
102
- case "\x1b":
103
- case "\x03": // ctrl+c — same intent as escape while a picker is focused
96
+ case "escape":
97
+ case "ctrl+c": // same intent as escape while a picker is focused
104
98
  return "cancel";
99
+ default:
100
+ break;
101
+ }
102
+ switch (keyText(data)) {
103
+ case "s":
104
+ return "session";
105
+ case "l":
106
+ return "right";
107
+ case "h":
108
+ return "left";
105
109
  default:
106
110
  return undefined;
107
111
  }
@@ -178,10 +182,10 @@ export interface SliderView {
178
182
  }
179
183
 
180
184
  const TITLE = "Effort";
181
- const HINTS = "←/→ or h/l adjust · Enter confirm · Esc cancel · shift+tab cycles the plain levels";
185
+ const HINTS = "←/→ or h/l adjust · Enter confirm · s for this session only · Esc cancel · shift+tab cycles the plain levels";
182
186
  /** Anthropic's cache hierarchy: a thinking/effort change invalidates the message cache once (CACHE-REVIEW-2026-09-04 M4). */
183
187
  const CACHE_NOTE = "changing effort re-caches the conversation (one uncached request)";
184
- const SHORT_HINTS = "←/→ h/l · Enter · Esc";
188
+ const SHORT_HINTS = "←/→ h/l · Enter · s · Esc";
185
189
  const ULTRACODE_SUBTITLE = `${ULTRACODE_LEVEL} + workflows`;
186
190
 
187
191
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * exit extension — Claude Code's `/exit`.
2
+ * exit extension — Claude Code's `/exit` and one-shot failure status.
3
3
  *
4
4
  * pi's built-in quit command is `/quit`; Claude Code's is `/exit` (with `quit`
5
5
  * shown as an alias). A user coming from Claude Code types `/exit` out of habit
@@ -17,8 +17,39 @@
17
17
  */
18
18
 
19
19
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
20
+ import { ONE_SHOT_COMMAND_FAILED_CHANNEL, type RunOutcome, RunOutcomeLatch, TURN_FAILED_CHANNEL } from "../lib/interrupt.ts";
20
21
 
21
22
  export default function exitExtension(pi: ExtensionAPI) {
23
+ const outcome = new RunOutcomeLatch();
24
+ let settled: RunOutcome | undefined;
25
+ // The harness stopped the turn in progress: its run ends "aborted", which
26
+ // must not read as a user cancel when the turn settles.
27
+ let turnFailed = false;
28
+ pi.on("agent_end", (event, ctx) => {
29
+ outcome.record(event.messages, ctx.signal?.aborted);
30
+ });
31
+ pi.on("agent_settled", () => {
32
+ const run = outcome.take();
33
+ settled = turnFailed ? "error" : run ?? settled;
34
+ turnFailed = false;
35
+ });
36
+ pi.events.on(ONE_SHOT_COMMAND_FAILED_CHANNEL, () => {
37
+ settled = "error";
38
+ });
39
+ pi.events.on(TURN_FAILED_CHANNEL, () => {
40
+ turnFailed = true;
41
+ });
42
+ pi.on("session_shutdown", (event, ctx) => {
43
+ if (ctx.mode !== "print" && ctx.mode !== "json") return;
44
+ if (event.reason !== "quit" || (settled !== "error" && !turnFailed)) return;
45
+ // pi 1.0.1 checks provider errors for text output, but not JSON. A print
46
+ // run may submit several prompts or replace the session (/clear), so a
47
+ // settled turn is not yet the process's final outcome. Commit only at
48
+ // final disposal, after retries/compaction and every prompt. main preserves
49
+ // this code when runPrintMode returns zero; never clear another failure.
50
+ if (process.exitCode === undefined || Number(process.exitCode) === 0) process.exitCode = 1;
51
+ });
52
+
22
53
  pi.registerCommand("exit", {
23
54
  description: "Quit One Code (same as /quit)",
24
55
  handler: async (_args, ctx) => {