@selesai/code 0.13.15 → 0.13.18

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 (473) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +2 -14
  3. package/dist/bun/cli.d.ts +3 -1
  4. package/dist/bun/cli.js +3 -9
  5. package/dist/bun/{register-bedrock.js → runtime-setup.js} +5 -0
  6. package/dist/bun/sandbox-env-setup.d.ts +1 -0
  7. package/dist/bun/sandbox-env-setup.js +3 -0
  8. package/dist/cli/auth-command.d.ts +23 -0
  9. package/dist/cli/auth-command.js +102 -0
  10. package/dist/cli/config-selector.js +2 -1
  11. package/dist/cli/setup.d.ts +1 -0
  12. package/dist/cli/setup.js +11 -0
  13. package/dist/cli.js +2 -14
  14. package/dist/config.d.ts +3 -2
  15. package/dist/config.js +9 -4
  16. package/dist/core/agent-session-runtime.js +15 -7
  17. package/dist/core/agent-session.d.ts +2 -6
  18. package/dist/core/agent-session.js +15 -4
  19. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  20. package/dist/core/compaction/branch-summarization.js +2 -1
  21. package/dist/core/extensions/loader.js +3 -0
  22. package/dist/core/extensions/types.d.ts +16 -2
  23. package/dist/core/http-dispatcher.js +2 -0
  24. package/dist/core/keybindings.d.ts +5 -0
  25. package/dist/core/keybindings.js +4 -0
  26. package/dist/core/messages.d.ts +1 -1
  27. package/dist/core/model-config.d.ts +15 -0
  28. package/dist/core/model-config.js +3 -0
  29. package/dist/core/model-runtime.d.ts +1 -0
  30. package/dist/core/model-runtime.js +5 -2
  31. package/dist/core/provider-composer.js +8 -2
  32. package/dist/core/session-export.d.ts +3 -0
  33. package/dist/core/session-export.js +31 -0
  34. package/dist/core/session-manager.d.ts +3 -2
  35. package/dist/core/session-manager.js +40 -13
  36. package/dist/core/skills.d.ts +1 -1
  37. package/dist/core/skills.js +4 -2
  38. package/dist/core/system-prompt.js +10 -10
  39. package/dist/core/tools/bash.js +3 -117
  40. package/dist/core/tools/edit.d.ts +1 -12
  41. package/dist/core/tools/edit.js +5 -163
  42. package/dist/core/tools/find.js +4 -55
  43. package/dist/core/tools/grep.js +4 -60
  44. package/dist/core/tools/ls.js +4 -49
  45. package/dist/core/tools/read.d.ts +4 -0
  46. package/dist/core/tools/read.js +10 -122
  47. package/dist/core/tools/renderers/bash.d.ts +11 -0
  48. package/dist/core/tools/renderers/bash.js +129 -0
  49. package/dist/core/tools/renderers/edit.d.ts +22 -0
  50. package/dist/core/tools/renderers/edit.js +166 -0
  51. package/dist/core/tools/renderers/find.d.ts +9 -0
  52. package/dist/core/tools/renderers/find.js +63 -0
  53. package/dist/core/tools/renderers/grep.d.ts +9 -0
  54. package/dist/core/tools/renderers/grep.js +68 -0
  55. package/dist/core/tools/renderers/index.d.ts +27 -0
  56. package/dist/core/tools/renderers/index.js +46 -0
  57. package/dist/core/tools/renderers/ls.d.ts +9 -0
  58. package/dist/core/tools/renderers/ls.js +57 -0
  59. package/dist/core/tools/renderers/read.d.ts +10 -0
  60. package/dist/core/tools/renderers/read.js +128 -0
  61. package/dist/core/tools/renderers/write.d.ts +9 -0
  62. package/dist/core/tools/renderers/write.js +152 -0
  63. package/dist/core/tools/write.js +5 -146
  64. package/dist/extensions/capability-gateway/index.ts +12 -1
  65. package/dist/extensions/capability-gateway/integration.test.ts +23 -0
  66. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +18 -0
  67. package/dist/extensions/pi-hermes-memory/README.md +16 -12
  68. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +1 -1
  69. package/dist/extensions/pi-hermes-memory/package-lock.json +587 -62
  70. package/dist/extensions/pi-hermes-memory/package.json +4 -4
  71. package/dist/extensions/pi-hermes-memory/src/config.ts +32 -0
  72. package/dist/extensions/pi-hermes-memory/src/constants.ts +12 -2
  73. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +109 -51
  74. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +9 -3
  75. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +257 -98
  76. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +9 -2
  77. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +5 -0
  78. package/dist/extensions/pi-hermes-memory/src/index.ts +22 -2
  79. package/dist/extensions/pi-hermes-memory/src/paths.ts +1 -1
  80. package/dist/extensions/pi-hermes-memory/src/store/db.ts +6 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +58 -1
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +60 -8
  83. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +169 -7
  84. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +7 -21
  85. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +134 -15
  86. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +4 -2
  87. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +24 -9
  88. package/dist/extensions/pi-hermes-memory/src/types.ts +11 -0
  89. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +42 -0
  90. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +159 -3
  91. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +452 -0
  92. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +39 -0
  93. package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +91 -0
  94. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +29 -0
  95. package/dist/extensions/pi-hermes-memory/tests/store/fts-query.test.ts +116 -0
  96. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +163 -0
  97. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +233 -0
  98. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +12 -0
  99. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +175 -0
  100. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +2 -2
  101. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +22 -0
  102. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +37 -1
  103. package/dist/extensions/pi-intercom/CHANGELOG.md +13 -0
  104. package/dist/extensions/pi-intercom/README.md +16 -2
  105. package/dist/extensions/pi-intercom/broker/spawn.test.ts +19 -2
  106. package/dist/extensions/pi-intercom/broker/spawn.ts +4 -4
  107. package/dist/extensions/pi-intercom/index.ts +1 -1
  108. package/dist/extensions/pi-intercom/intercom.integration.test.ts +121 -2
  109. package/dist/extensions/pi-intercom/package.json +1 -1
  110. package/dist/extensions/pi-intercom/project-agent.test.ts +1 -1
  111. package/dist/extensions/pi-intercom/project-agent.ts +1 -6
  112. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +7 -6
  113. package/dist/extensions/pi-rewind-hook/index.test.ts +7 -0
  114. package/dist/extensions/pi-subagents/.github/workflows/test.yml +36 -4
  115. package/dist/extensions/pi-subagents/CHANGELOG.md +120 -0
  116. package/dist/extensions/pi-subagents/README.md +3 -3
  117. package/dist/extensions/pi-subagents/agents/researcher.md +23 -13
  118. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -1
  119. package/dist/extensions/pi-subagents/agents/scout.md +1 -1
  120. package/dist/extensions/pi-subagents/docs/agents.md +32 -16
  121. package/dist/extensions/pi-subagents/docs/configuration.md +41 -15
  122. package/dist/extensions/pi-subagents/docs/extension-api.md +109 -6
  123. package/dist/extensions/pi-subagents/docs/missions.md +2 -0
  124. package/dist/extensions/pi-subagents/docs/models.md +58 -1
  125. package/dist/extensions/pi-subagents/docs/observability.md +50 -12
  126. package/dist/extensions/pi-subagents/docs/tool-reference.md +17 -10
  127. package/dist/extensions/pi-subagents/docs/watchdog.md +1 -1
  128. package/dist/extensions/pi-subagents/docs/workflows.md +26 -9
  129. package/dist/extensions/pi-subagents/package-lock.json +747 -177
  130. package/dist/extensions/pi-subagents/package.json +6 -4
  131. package/dist/extensions/pi-subagents/runner-server-preload.mjs +13 -0
  132. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -1
  133. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
  134. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +21 -4
  135. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
  136. package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
  137. package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +63 -0
  138. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +61 -16
  139. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
  140. package/dist/extensions/pi-subagents/src/agents/agents.ts +8 -0
  141. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +0 -1
  142. package/dist/extensions/pi-subagents/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
  143. package/dist/extensions/pi-subagents/src/api/preflight.ts +7 -4
  144. package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -2
  145. package/dist/extensions/pi-subagents/src/api/workflow-resources.ts +6 -0
  146. package/dist/extensions/pi-subagents/src/extension/config.ts +4 -2
  147. package/dist/extensions/pi-subagents/src/extension/doctor.ts +2 -10
  148. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +9 -11
  149. package/dist/extensions/pi-subagents/src/extension/index.ts +99 -10
  150. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +13 -0
  151. package/dist/extensions/pi-subagents/src/extension/rpc.ts +7 -23
  152. package/dist/extensions/pi-subagents/src/extension/schemas.ts +11 -8
  153. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +25 -7
  154. package/dist/extensions/pi-subagents/src/integrations/pi-web-session-liveness.ts +73 -0
  155. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +228 -136
  156. package/dist/extensions/pi-subagents/src/intercom/supervisor-ui.ts +244 -0
  157. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +37 -16
  158. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +18 -18
  159. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +51 -25
  160. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +46 -3
  161. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -3
  162. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +9 -0
  163. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +10 -12
  164. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -15
  165. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +40 -29
  166. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +8 -0
  167. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +79 -247
  168. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +88 -12
  169. package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +6 -6
  170. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +24 -24
  171. package/dist/extensions/pi-subagents/src/runs/background/retained-nested-route-tracker.ts +96 -0
  172. package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +642 -0
  173. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +75 -6
  174. package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +163 -0
  175. package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +86 -0
  176. package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +31 -0
  177. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +18 -4
  178. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -1
  179. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +597 -1092
  180. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +3 -0
  181. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +4 -0
  182. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +20 -17
  183. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +296 -394
  184. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +4 -0
  185. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +3 -1
  186. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +9 -5
  187. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +630 -283
  188. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
  189. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +78 -98
  190. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +3 -3
  191. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +16 -3
  192. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
  193. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +47 -47
  194. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -2
  195. package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +174 -0
  196. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +14 -3
  197. package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +319 -0
  198. package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +25 -0
  199. package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +126 -0
  200. package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +373 -0
  201. package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +530 -0
  202. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +2 -2
  203. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +2 -1
  204. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +16 -0
  205. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +11 -11
  206. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +30 -20
  207. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
  208. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +84 -15
  209. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +88 -12
  210. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +37 -53
  211. package/dist/extensions/pi-subagents/src/runs/shared/nested-path.ts +1 -1
  212. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +18 -7
  213. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +57 -12
  214. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +3 -4
  215. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +0 -11
  216. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +4 -1
  217. package/dist/extensions/pi-subagents/src/runs/shared/readonly-drain-observation.ts +42 -0
  218. package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +69 -0
  219. package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +307 -0
  220. package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +8 -21
  221. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +3 -30
  222. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +17 -4
  223. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +2 -0
  224. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +99 -386
  225. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +18 -62
  226. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +0 -14
  227. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +31 -9
  228. package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +190 -0
  229. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +506 -226
  230. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +1 -1
  231. package/dist/extensions/pi-subagents/src/shared/jsonl-writer.ts +11 -0
  232. package/dist/extensions/pi-subagents/src/shared/model-response-aliases.ts +13 -0
  233. package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +0 -6
  234. package/dist/extensions/pi-subagents/src/shared/types.ts +145 -89
  235. package/dist/extensions/pi-subagents/src/shared/utils.ts +13 -6
  236. package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +2 -0
  237. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +18 -13
  238. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +0 -6
  239. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +1 -1
  240. package/dist/extensions/pi-subagents/src/tui/fleet.ts +11 -6
  241. package/dist/extensions/pi-subagents/src/tui/render.ts +277 -46
  242. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +0 -1
  243. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +12 -12
  244. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
  245. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +116 -15
  246. package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +15 -18
  247. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +57 -8
  248. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +19 -19
  249. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +3 -3
  250. package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +97 -22
  251. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +3 -0
  252. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +336 -21
  253. package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +1181 -0
  254. package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +2240 -0
  255. package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +2268 -0
  256. package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +1512 -0
  257. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +231 -16
  258. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +4 -18
  259. package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +95 -0
  260. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +9 -15
  261. package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +374 -0
  262. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -10
  263. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +18 -6
  264. package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +151 -0
  265. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +42 -1
  266. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +150 -25
  267. package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +354 -0
  268. package/dist/extensions/pi-subagents/test/integration/shared-cwd-terminal-evidence.test.ts +117 -0
  269. package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +3678 -0
  270. package/dist/extensions/pi-subagents/test/integration/{single-execution.test.ts → single-execution.part-2.test.ts} +500 -4207
  271. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -2
  272. package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +127 -0
  273. package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +365 -0
  274. package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +31 -0
  275. package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +74 -0
  276. package/dist/extensions/pi-subagents/test/smoke/pi085-extension.ts +16 -0
  277. package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +699 -0
  278. package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +418 -0
  279. package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +13 -0
  280. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +30 -76
  281. package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +84 -0
  282. package/dist/extensions/pi-subagents/test/support/result-publication-capacity-preload.mjs +70 -0
  283. package/dist/extensions/pi-subagents/test/support/runner-child-session-factory.ts +17 -0
  284. package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +390 -0
  285. package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +120 -0
  286. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +24 -3
  287. package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +87 -0
  288. package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +163 -0
  289. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -31
  290. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +78 -3
  291. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +2 -8
  292. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +1 -1
  293. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +73 -66
  294. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +51 -1
  295. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +49 -1
  296. package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +103 -0
  297. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +3 -3
  298. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +9 -8
  299. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +10 -7
  300. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +48 -6
  301. package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +90 -0
  302. package/dist/extensions/pi-subagents/test/unit/{pi-args-permission-system.test.ts → child-tool-plan-permission-system.test.ts} +48 -86
  303. package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +33 -0
  304. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +18 -18
  305. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +9 -9
  306. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +8 -7
  307. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +225 -65
  308. package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +17 -22
  309. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +11 -1
  310. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +47 -3
  311. package/dist/extensions/pi-subagents/test/unit/foreign-workflow-steering.test.ts +74 -0
  312. package/dist/extensions/pi-subagents/test/unit/fork-cache-key.test.ts +23 -29
  313. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +96 -4
  314. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +4 -4
  315. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +116 -55
  316. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +58 -1
  317. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +104 -3
  318. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
  319. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +31 -1
  320. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +102 -51
  321. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +196 -6
  322. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +181 -38
  323. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +62 -70
  324. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +58 -53
  325. package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +42 -0
  326. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +84 -0
  327. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +13 -5
  328. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +21 -5
  329. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +5 -4
  330. package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +2 -6
  331. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +28 -2
  332. package/dist/extensions/pi-subagents/test/unit/pi-web-session-liveness.test.ts +209 -0
  333. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +38 -1
  334. package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +43 -0
  335. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +24 -2
  336. package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +174 -0
  337. package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +94 -0
  338. package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +1329 -0
  339. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +29 -80
  340. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +11 -8
  341. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +2 -2
  342. package/dist/extensions/pi-subagents/test/unit/retained-nested-route-tracker.test.ts +175 -0
  343. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +38 -12
  344. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +2 -5
  345. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +89 -1
  346. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +2 -16
  347. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +27 -3
  348. package/dist/extensions/pi-subagents/test/unit/scheduled-supervisor-demand.test.ts +215 -0
  349. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +15 -11
  350. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +237 -1
  351. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -5
  352. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +2 -2
  353. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +14 -1
  354. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +130 -739
  355. package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +682 -0
  356. package/dist/extensions/pi-subagents/test/unit/supervisor-ui.test.ts +137 -0
  357. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +1 -11
  358. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +23 -3
  359. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +8 -1
  360. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +19 -1
  361. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +72 -4
  362. package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +17 -3
  363. package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +34 -0
  364. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +12 -2
  365. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +46 -6
  366. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +3 -3
  367. package/dist/extensions/pi-subagents/test/unit/workflow-resources.test.ts +133 -1
  368. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +53 -2
  369. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +222 -14
  370. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +526 -85
  371. package/dist/extensions/pi-web-agent/src/backends/config.ts +1 -0
  372. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +5 -3
  373. package/dist/extensions/pi-web-agent/src/search/tokenin.ts +7 -3
  374. package/dist/extensions/pi-web-agent/src/types.ts +1 -1
  375. package/dist/extensions/pi-zentui/README.md +17 -0
  376. package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
  377. package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
  378. package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
  379. package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
  380. package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
  381. package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
  382. package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
  383. package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
  384. package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
  385. package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
  386. package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
  387. package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
  388. package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
  389. package/dist/extensions/pi-zentui/package-lock.json +277 -517
  390. package/dist/extensions/pi-zentui/package.json +7 -4
  391. package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
  392. package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
  393. package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
  394. package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
  395. package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
  396. package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
  397. package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
  398. package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
  399. package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
  400. package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
  401. package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
  402. package/dist/index.d.ts +1 -1
  403. package/dist/main.js +4 -1
  404. package/dist/modes/interactive/chat-viewport.d.ts +19 -0
  405. package/dist/modes/interactive/chat-viewport.js +27 -0
  406. package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
  407. package/dist/modes/interactive/components/assistant-message.js +30 -13
  408. package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
  409. package/dist/modes/interactive/components/custom-editor.js +39 -1
  410. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  411. package/dist/modes/interactive/components/index.d.ts +1 -1
  412. package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
  413. package/dist/modes/interactive/components/markdown-transform.js +18 -0
  414. package/dist/modes/interactive/components/model-selector.js +19 -17
  415. package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
  416. package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
  417. package/dist/modes/interactive/components/settings-selector.js +128 -20
  418. package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
  419. package/dist/modes/interactive/components/settings-submenu.js +164 -0
  420. package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
  421. package/dist/modes/interactive/components/status-indicator.js +10 -3
  422. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  423. package/dist/modes/interactive/components/thinking-selector.js +75 -18
  424. package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
  425. package/dist/modes/interactive/components/tool-execution.js +35 -33
  426. package/dist/modes/interactive/components/trust-selector.js +2 -2
  427. package/dist/modes/interactive/interactive-mode.d.ts +13 -15
  428. package/dist/modes/interactive/interactive-mode.js +144 -80
  429. package/dist/modes/interactive/session-share.d.ts +15 -0
  430. package/dist/modes/interactive/session-share.js +183 -0
  431. package/dist/modes/interactive/theme/dark.json +2 -1
  432. package/dist/modes/interactive/theme/light.json +2 -1
  433. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
  434. package/dist/modes/interactive/theme/theme-controller.js +5 -0
  435. package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
  436. package/dist/modes/interactive/theme/theme-json.js +129 -0
  437. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  438. package/dist/modes/interactive/theme/theme.d.ts +14 -5
  439. package/dist/modes/interactive/theme/theme.js +18 -119
  440. package/dist/modes/interactive/tui-renderer.d.ts +20 -0
  441. package/dist/modes/interactive/tui-renderer.js +65 -0
  442. package/dist/utils/exif-orientation.js +2 -3
  443. package/dist/utils/management-http.d.ts +24 -0
  444. package/dist/utils/management-http.js +53 -0
  445. package/dist/utils/text.d.ts +7 -0
  446. package/dist/utils/text.js +8 -0
  447. package/dist/utils/tools-manager.d.ts +1 -0
  448. package/dist/utils/tools-manager.js +43 -21
  449. package/docs/docs.json +0 -4
  450. package/package.json +4 -4
  451. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
  452. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
  453. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
  454. package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  455. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
  456. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
  457. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
  458. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
  459. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
  460. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
  461. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
  462. package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
  463. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
  464. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
  465. package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
  466. package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
  467. package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
  468. package/dist/skills/implanger/SKILL.md +0 -70
  469. package/dist/skills/output/SKILL.md +0 -49
  470. package/dist/skills/planger/SKILL.md +0 -167
  471. package/dist/skills/workflow/SKILL.md +0 -95
  472. package/docs/workflows.md +0 -18
  473. /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
@@ -0,0 +1,77 @@
1
+ import {
2
+ type EditorComponentConfig,
3
+ type FooterComponentConfig,
4
+ hasUnsupportedComponentStyle,
5
+ type UserMessagesComponentConfig,
6
+ type ZentuiConfig,
7
+ } from "./config";
8
+
9
+ export type PresetId = "opencode" | "opencode-copy-friendly" | "rail" | "minimalist";
10
+ export type ComponentPreset = Readonly<{
11
+ id: PresetId;
12
+ label: string;
13
+ components: Readonly<{
14
+ editor: Readonly<Pick<EditorComponentConfig, "enabled" | "style">>;
15
+ footer: Readonly<Pick<FooterComponentConfig, "style">>;
16
+ userMessages: Readonly<
17
+ Pick<UserMessagesComponentConfig, "enabled"> &
18
+ Partial<Pick<UserMessagesComponentConfig, "style">>
19
+ >;
20
+ }>;
21
+ }>;
22
+
23
+ export const componentPresets: readonly ComponentPreset[] = [
24
+ {
25
+ id: "opencode",
26
+ label: "Opencode",
27
+ components: {
28
+ editor: { enabled: true, style: "opencode" },
29
+ footer: { style: "starship" },
30
+ userMessages: { enabled: true, style: "framed" },
31
+ },
32
+ },
33
+ {
34
+ id: "opencode-copy-friendly",
35
+ label: "Opencode (copy-friendly)",
36
+ components: {
37
+ editor: { enabled: true, style: "opencode-copy-friendly" },
38
+ footer: { style: "starship" },
39
+ userMessages: { enabled: true, style: "framed-copy-friendly" },
40
+ },
41
+ },
42
+ {
43
+ id: "rail",
44
+ label: "Rail",
45
+ components: {
46
+ editor: { enabled: true, style: "accent-rail" },
47
+ footer: { style: "starship" },
48
+ userMessages: { enabled: true, style: "compact" },
49
+ },
50
+ },
51
+ {
52
+ id: "minimalist",
53
+ label: "Minimalist",
54
+ components: {
55
+ editor: { enabled: true, style: "minimalist" },
56
+ footer: { style: "hidden" },
57
+ userMessages: { enabled: false },
58
+ },
59
+ },
60
+ ];
61
+
62
+ export function getComponentPreset(id: string): ComponentPreset | undefined {
63
+ return componentPresets.find((preset) => preset.id === id);
64
+ }
65
+
66
+ /** Match configured selections, not live ownership or dormant style options. */
67
+ export function matchingComponentPreset(config: ZentuiConfig): ComponentPreset | undefined {
68
+ return componentPresets.find(({ components }) =>
69
+ (["editor", "footer", "userMessages"] as const).every((owner) => {
70
+ const selection = components[owner];
71
+ if ("style" in selection && hasUnsupportedComponentStyle(config, owner)) return false;
72
+ return Object.entries(selection).every(
73
+ ([key, value]) => config.components[owner][key as keyof typeof selection] === value,
74
+ );
75
+ }),
76
+ );
77
+ }
@@ -53,8 +53,15 @@ import {
53
53
  type WorkingLineSpinner,
54
54
  type WorkingLineTextAnimation,
55
55
  } from "./config";
56
+ import { prepareEditorTextForCustomUi } from "./editor-transfer";
56
57
  import { sanitizeExtensionStatusText } from "./extension-status";
57
58
  import { isIconMode } from "./icons";
59
+ import {
60
+ componentPresets,
61
+ getComponentPreset,
62
+ matchingComponentPreset,
63
+ type PresetId,
64
+ } from "./presets";
58
65
  import type { SessionLifecycle } from "./session-lifecycle";
59
66
  import {
60
67
  renderEditorSettingsPreview,
@@ -213,7 +220,17 @@ function experimentalThinkingCapability(
213
220
  type SettingsCommandDeps = {
214
221
  sessionLifecycle: SessionLifecycle;
215
222
  getConfig: () => PolishedTuiConfig;
216
- setEditorComponent: (patch: EditorPatch, ctx: ExtensionContext) => ApplyResult;
223
+ applyPreset: (
224
+ id: PresetId,
225
+ ctx: ExtensionContext,
226
+ options?: { deferEditor?: boolean },
227
+ ) => ApplyResult;
228
+ reconcilePresetEditor: (ctx: ExtensionContext) => ApplyResult;
229
+ setEditorComponent: (
230
+ patch: EditorPatch,
231
+ ctx: ExtensionContext,
232
+ options?: { deferEditor?: boolean },
233
+ ) => ApplyResult;
217
234
  setPolished: (patch: Partial<PolishedEditorStyleConfig>, ctx: ExtensionContext) => void;
218
235
  setPolishedCopyFriendly: (
219
236
  patch: Partial<PolishedCopyFriendlyEditorStyleConfig>,
@@ -310,6 +327,7 @@ const footerSegmentSettingDescriptions: Record<FooterSegmentSettingId, string> =
310
327
  };
311
328
 
312
329
  const directCommandSuggestions = [
330
+ ...componentPresets.map(({ id }) => `preset ${id}`),
313
331
  "editor enable",
314
332
  "editor disable",
315
333
  "editor toggle",
@@ -471,12 +489,20 @@ function argumentCompletions(prefix: string): AutocompleteItem[] | null {
471
489
  }
472
490
 
473
491
  function usageText(): string {
474
- return "Usage: /zentui [editor|messages|statusline|viewport-indicators] [enable|disable|toggle], /zentui [messages|user-messages|working-line], or /zentui format <template>";
492
+ return "Usage: /zentui [editor|messages|statusline|viewport-indicators] [enable|disable|toggle], /zentui [messages|user-messages|working-line], /zentui preset <opencode|opencode-copy-friendly|rail|minimalist>, or /zentui format <template>";
475
493
  }
476
494
 
477
495
  function buildAppearanceItems(config: PolishedTuiConfig): SettingItem[] {
478
496
  const component = config.components.selectorBorders;
479
497
  return [
498
+ {
499
+ id: "preset",
500
+ label: "Preset",
501
+ description:
502
+ "Apply Editor, Footer, and User messages together once. Preserves colors and other settings; editor installation waits until this panel closes. Custom means no matching combination.",
503
+ currentValue: matchingComponentPreset(config)?.label ?? "Custom",
504
+ values: componentPresets.map(({ label }) => label),
505
+ },
480
506
  {
481
507
  id: "selectorBordersEnabled",
482
508
  label: "Selector borders",
@@ -1133,11 +1159,38 @@ export function registerZentuiSettingsCommand(pi: ExtensionAPI, deps: SettingsCo
1133
1159
  deps.setFooterComponent(patch, ctx);
1134
1160
  };
1135
1161
 
1162
+ const applyPreset = (id: PresetId, ctx: ExtensionContext) => {
1163
+ try {
1164
+ const result = deps.applyPreset(id, ctx);
1165
+ deps.requestRender();
1166
+ if (ctx.hasUI) {
1167
+ const detail = result.reason?.trim();
1168
+ ctx.ui.notify(
1169
+ `Preset saved: ${getComponentPreset(id)?.label}${detail ? ` (${detail})` : !result.applied ? " (reload Pi to apply this change)" : ""}`,
1170
+ !result.applied || detail ? "warning" : "info",
1171
+ );
1172
+ }
1173
+ } catch (error) {
1174
+ if (ctx.hasUI)
1175
+ ctx.ui.notify(
1176
+ `Could not update Zentui settings: ${error instanceof Error ? error.message : String(error)}`,
1177
+ "error",
1178
+ );
1179
+ }
1180
+ };
1181
+
1136
1182
  pi.registerCommand("zentui", {
1137
1183
  description: "Configure Zentui",
1138
1184
  getArgumentCompletions: argumentCompletions,
1139
1185
  handler: async (_args, ctx) => {
1140
1186
  const args = typeof _args === "string" ? _args : "";
1187
+ const words = args.trim().split(/\s+/);
1188
+ if (words[0]?.toLowerCase() === "preset") {
1189
+ const preset = words.length === 2 ? getComponentPreset(words[1] ?? "") : undefined;
1190
+ if (preset) applyPreset(preset.id, ctx);
1191
+ else if (ctx.hasUI) ctx.ui.notify(usageText(), "warning");
1192
+ return;
1193
+ }
1141
1194
  const format = parseFormatCommand(args);
1142
1195
  if (format) {
1143
1196
  try {
@@ -1210,8 +1263,19 @@ export function registerZentuiSettingsCommand(pi: ExtensionAPI, deps: SettingsCo
1210
1263
  let requestedSection = initialSection ?? "appearance";
1211
1264
  let requestedFocusId: string | undefined;
1212
1265
  while (true) {
1266
+ try {
1267
+ prepareEditorTextForCustomUi(ctx.ui);
1268
+ } catch (error) {
1269
+ ctx.ui.notify(
1270
+ `Could not open Zentui settings safely: ${error instanceof Error ? error.message : String(error)}`,
1271
+ "error",
1272
+ );
1273
+ return;
1274
+ }
1213
1275
  const initialFocusId = requestedFocusId;
1214
1276
  requestedFocusId = undefined;
1277
+ const generation = deps.sessionLifecycle.currentGeneration();
1278
+ let pendingPresetEditor = false;
1215
1279
  const outcome = await ctx.ui.custom<SettingsOutcome>((tui, theme, _keybindings, done) => {
1216
1280
  const listTheme = deps.settingsListTheme ?? getSettingsListTheme();
1217
1281
  let activeSection = requestedSection;
@@ -1315,8 +1379,26 @@ export function registerZentuiSettingsCommand(pi: ExtensionAPI, deps: SettingsCo
1315
1379
  listTheme,
1316
1380
  (id, newValue) => {
1317
1381
  try {
1382
+ if (id === "preset") {
1383
+ const preset = componentPresets.find(({ label }) => label === newValue);
1384
+ if (!preset) return;
1385
+ if (!deps.sessionLifecycle.isCurrent(generation)) return;
1386
+ const result = deps.applyPreset(preset.id, ctx, { deferEditor: true });
1387
+ pendingPresetEditor = true;
1388
+ settingsList = makeSettingsList("preset");
1389
+ notifyChange("Preset saved", preset.label, result);
1390
+ return;
1391
+ }
1318
1392
  const enabled = isFeatureState(newValue) ? newValue === "enabled" : undefined;
1319
1393
  if (id === "editorEnabled" && enabled !== undefined) {
1394
+ if (pendingPresetEditor) {
1395
+ const result = deps.setEditorComponent({ enabled }, ctx, {
1396
+ deferEditor: true,
1397
+ });
1398
+ notifyChange("Editor", newValue, result);
1399
+ finishSettings("close");
1400
+ return;
1401
+ }
1320
1402
  finishSettings("close");
1321
1403
  deps.sessionLifecycle.defer(() => {
1322
1404
  try {
@@ -1838,6 +1920,25 @@ export function registerZentuiSettingsCommand(pi: ExtensionAPI, deps: SettingsCo
1838
1920
  },
1839
1921
  };
1840
1922
  });
1923
+ // Pi restores its saved editor text before custom() resolves. Reconcile only
1924
+ // now, using the latest config and observed factory, never a captured factory.
1925
+ if (pendingPresetEditor && !deps.sessionLifecycle.isCurrent(generation)) return;
1926
+ if (pendingPresetEditor) {
1927
+ try {
1928
+ const result = deps.reconcilePresetEditor(ctx);
1929
+ if (!result.applied || result.reason) {
1930
+ ctx.ui.notify(
1931
+ `Preset saved: editor (${result.reason ?? "reload Pi to apply this change"})`,
1932
+ "warning",
1933
+ );
1934
+ }
1935
+ } catch (error) {
1936
+ ctx.ui.notify(
1937
+ `Could not apply preset editor; reload Pi: ${error instanceof Error ? error.message : String(error)}`,
1938
+ "error",
1939
+ );
1940
+ }
1941
+ }
1841
1942
  if (outcome === "close" || outcome === undefined) return;
1842
1943
  if (
1843
1944
  outcome === "edit-working-line-spinner-speed" ||
@@ -0,0 +1,115 @@
1
+ import type { EventBus } from "@earendil-works/pi-coding-agent";
2
+
3
+ export const ZENTUI_WORKING_LINE_SEGMENT_CAPABILITY_EVENT =
4
+ "zentui:working-line-segment-capability";
5
+ export const ZENTUI_WORKING_LINE_SEGMENT_EVENT = "zentui:working-line-segment";
6
+ export const ZENTUI_WORKING_LINE_SEGMENT_PROTOCOL_VERSION = 1;
7
+
8
+ export const MAX_WORKING_LINE_EXTENSION_SEGMENTS = 16;
9
+ export const MAX_WORKING_LINE_EXTENSION_KEY_CODE_UNITS = 64;
10
+ export const MAX_WORKING_LINE_EXTENSION_TEXT_CODE_UNITS = 256;
11
+
12
+ export type WorkingLineSegmentCapability = {
13
+ supported: boolean;
14
+ active: boolean;
15
+ /** Present in protocol version 1 and later. */
16
+ version?: number;
17
+ };
18
+
19
+ export type WorkingLineSegmentUpdate = {
20
+ key: string;
21
+ text?: string;
22
+ };
23
+
24
+ type EventRecord = Record<string, unknown>;
25
+
26
+ function eventRecord(value: unknown): EventRecord | undefined {
27
+ return value !== null && typeof value === "object" && !Array.isArray(value)
28
+ ? (value as EventRecord)
29
+ : undefined;
30
+ }
31
+
32
+ function segmentUpdate(value: unknown): WorkingLineSegmentUpdate | undefined {
33
+ const record = eventRecord(value);
34
+ if (!record) return undefined;
35
+ if (
36
+ typeof record.key !== "string" ||
37
+ record.key.length === 0 ||
38
+ record.key.length > MAX_WORKING_LINE_EXTENSION_KEY_CODE_UNITS
39
+ ) {
40
+ return undefined;
41
+ }
42
+ if (
43
+ record.text !== undefined &&
44
+ (typeof record.text !== "string" ||
45
+ record.text.length > MAX_WORKING_LINE_EXTENSION_TEXT_CODE_UNITS)
46
+ ) {
47
+ return undefined;
48
+ }
49
+ return { key: record.key, text: record.text as string | undefined };
50
+ }
51
+
52
+ /** Collects keyed third-party segments and publishes deterministic snapshots to the Working line. */
53
+ export class WorkingLineExtensionSegments {
54
+ private readonly segments = new Map<string, string>();
55
+ private publishDirty = false;
56
+
57
+ constructor(
58
+ events: EventBus | undefined,
59
+ private readonly isActive: () => boolean,
60
+ private readonly onChange: (segments: readonly string[]) => boolean | undefined,
61
+ ) {
62
+ if (!events) return;
63
+ events.on(ZENTUI_WORKING_LINE_SEGMENT_CAPABILITY_EVENT, (value) => {
64
+ const capability = eventRecord(value);
65
+ if (!capability) return;
66
+ capability.supported = true;
67
+ capability.active = this.isActive();
68
+ capability.version = ZENTUI_WORKING_LINE_SEGMENT_PROTOCOL_VERSION;
69
+ });
70
+ events.on(ZENTUI_WORKING_LINE_SEGMENT_EVENT, (value) => {
71
+ const update = segmentUpdate(value);
72
+ if (!update) return;
73
+ if (update.text !== undefined && update.text.length > 0 && !this.isActive()) return;
74
+ if (update.text === undefined || update.text.length === 0) {
75
+ if (!this.segments.delete(update.key) && !this.publishDirty) return;
76
+ } else {
77
+ if (
78
+ !this.segments.has(update.key) &&
79
+ this.segments.size >= MAX_WORKING_LINE_EXTENSION_SEGMENTS
80
+ )
81
+ return;
82
+ if (this.segments.get(update.key) === update.text && !this.publishDirty) return;
83
+ this.segments.set(update.key, update.text);
84
+ }
85
+ this.publishDirty = true;
86
+ this.publish();
87
+ });
88
+ }
89
+
90
+ clear(): void {
91
+ if (this.segments.size === 0 && !this.publishDirty) return;
92
+ this.segments.clear();
93
+ this.publishDirty = true;
94
+ this.publish();
95
+ }
96
+
97
+ /** Drops session-scoped publisher state without attempting a Working-row write. */
98
+ invalidate(): void {
99
+ this.segments.clear();
100
+ this.publishDirty = false;
101
+ }
102
+
103
+ private publish(): void {
104
+ const applied = this.onChange(
105
+ [...this.segments.entries()]
106
+ .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
107
+ .map(([, text]) => text),
108
+ );
109
+ if (applied === false && !this.isActive()) {
110
+ this.invalidate();
111
+ return;
112
+ }
113
+ this.publishDirty = applied === false;
114
+ }
115
+ }
@@ -494,6 +494,7 @@ export type WorkingLineRuntimeSegments = {
494
494
  elapsedMs?: number;
495
495
  thought?: { durationMs: number; active: boolean };
496
496
  tokens?: { input: number; output: number; outputApproximate?: boolean };
497
+ extensions?: readonly string[];
497
498
  };
498
499
 
499
500
  export type WorkingLineFrameState = {
@@ -573,6 +574,26 @@ function truncateWithEllipsis(value: string, capacity: number): string {
573
574
  return prefix ? `${prefix}…` : "";
574
575
  }
575
576
 
577
+ function fitWorkingLineExtensionSegments(
578
+ values: readonly string[],
579
+ budget: number,
580
+ delimiter: string,
581
+ ): string[] {
582
+ const fitted: string[] = [];
583
+ let used = 0;
584
+ for (const value of values) {
585
+ const normalized = normalizeWorkingLineMessage(value);
586
+ const remaining = budget - used - visibleWidth(delimiter);
587
+ if (!normalized || remaining <= 0) continue;
588
+ const text = truncateWithEllipsis(normalized, remaining);
589
+ if (!text) continue;
590
+ fitted.push(text);
591
+ used += visibleWidth(delimiter) + visibleWidth(text);
592
+ if (text !== normalized) break;
593
+ }
594
+ return fitted;
595
+ }
596
+
576
597
  export type ComposedWorkingLine = { message: string; row: string };
577
598
 
578
599
  /** Validate and measure the fixed visible width shared by every frame in a preset. */
@@ -596,7 +617,17 @@ export function composeWorkingLineRow(
596
617
  MAX_WORKING_LINE_FRAME_CELLS - workingLineSpinnerWidth(config.spinner) - visibleWidth(" ");
597
618
  const delimiter = " · ";
598
619
  const tokens = config.segments.tokens ? formatWorkingLineTokens(runtime.tokens) : undefined;
599
- const mandatoryWidth = tokens ? visibleWidth(delimiter) + visibleWidth(tokens) : 0;
620
+ const tokenWidth = tokens ? visibleWidth(delimiter) + visibleWidth(tokens) : 0;
621
+ const extensions = fitWorkingLineExtensionSegments(
622
+ runtime.extensions ?? [],
623
+ Math.max(0, maximumRowCells - tokenWidth - 1),
624
+ delimiter,
625
+ );
626
+ const extensionWidth = extensions.reduce(
627
+ (width, value) => width + visibleWidth(delimiter) + visibleWidth(value),
628
+ 0,
629
+ );
630
+ const mandatoryWidth = tokenWidth + extensionWidth;
600
631
  const messageCapacity = maximumRowCells - mandatoryWidth;
601
632
  const fittedMessage = truncateWithEllipsis(normalized, messageCapacity);
602
633
  const segments: string[] = [fittedMessage];
@@ -630,6 +661,7 @@ export function composeWorkingLineRow(
630
661
  if (accepted.has("elapsed") && elapsed) segments.push(elapsed);
631
662
  if (accepted.has("thought") && thought) segments.push(thought);
632
663
  if (tokens) segments.push(tokens);
664
+ segments.push(...extensions);
633
665
  return { message: normalized, row: segments.filter(Boolean).join(delimiter) };
634
666
  }
635
667
 
@@ -1027,6 +1059,8 @@ export class WorkingLineController {
1027
1059
  private installedIndicatorOptions: WorkingIndicatorOptions | undefined;
1028
1060
  private tokens: WorkingLineRuntimeSegments["tokens"];
1029
1061
  private thought: WorkingLineRuntimeSegments["thought"];
1062
+ private extensionSegments: readonly string[] = [];
1063
+ private extensionSegmentsDirty = false;
1030
1064
  private readonly activeTools = new Map<string, string>();
1031
1065
  private elapsedUpdatesActive = false;
1032
1066
  private elapsedUpdatesContext: WorkingLineContext | undefined;
@@ -1040,6 +1074,7 @@ export class WorkingLineController {
1040
1074
  private readonly random: () => number = Math.random,
1041
1075
  private readonly now: () => number = Date.now,
1042
1076
  private readonly getThought: () => WorkingLineRuntimeSegments["thought"] = () => this.thought,
1077
+ private readonly onUnavailable: () => void = () => {},
1043
1078
  ) {}
1044
1079
 
1045
1080
  startSession(ctx: WorkingLineContext): WorkingLineReconcileResult {
@@ -1087,6 +1122,24 @@ export class WorkingLineController {
1087
1122
  this.updateMetrics(tokens, this.getThought(), ctx);
1088
1123
  }
1089
1124
 
1125
+ updateExtensionSegments(segments: readonly string[], ctx: WorkingLineContext): boolean {
1126
+ const unchanged =
1127
+ this.extensionSegments.length === segments.length &&
1128
+ this.extensionSegments.every((value, index) => value === segments[index]);
1129
+ if (unchanged && !this.extensionSegmentsDirty) return true;
1130
+ if (!unchanged) {
1131
+ this.extensionSegments = [...segments];
1132
+ this.extensionSegmentsDirty = true;
1133
+ }
1134
+ return this.updateIndicator(ctx);
1135
+ }
1136
+
1137
+ /** Drops extension state that is no longer valid for the current owned Working row. */
1138
+ invalidateExtensionSegments(): void {
1139
+ this.extensionSegments = [];
1140
+ this.extensionSegmentsDirty = false;
1141
+ }
1142
+
1090
1143
  startTool(toolCallId: string, toolName: string, ctx: WorkingLineContext): void {
1091
1144
  this.activeTools.delete(toolCallId);
1092
1145
  this.activeTools.set(toolCallId, normalizeWorkingLineToolLabel(toolName));
@@ -1141,6 +1194,16 @@ export class WorkingLineController {
1141
1194
  return this.selectedMessage;
1142
1195
  }
1143
1196
 
1197
+ /** Whether this controller currently claims both required public Working-row surfaces. */
1198
+ isAvailable(): boolean {
1199
+ return (
1200
+ this.getConfig().components.workingLine.enabled &&
1201
+ this.installed &&
1202
+ this.ownsIndicator &&
1203
+ this.ownsMessage
1204
+ );
1205
+ }
1206
+
1144
1207
  private install(
1145
1208
  ctx: WorkingLineContext,
1146
1209
  forceIndicator = false,
@@ -1151,6 +1214,7 @@ export class WorkingLineController {
1151
1214
  if (!ui) {
1152
1215
  this.installed = false;
1153
1216
  this.deactivateElapsedUpdates();
1217
+ this.invalidateUnavailableExtensionSegments();
1154
1218
  return { applied: false, reason: "Working line requires a newer Pi TUI" };
1155
1219
  }
1156
1220
  const rootConfig = this.getConfig();
@@ -1206,6 +1270,7 @@ export class WorkingLineController {
1206
1270
  elapsedMs: this.agentActive ? this.durationClock.elapsedMs() : undefined,
1207
1271
  thought,
1208
1272
  tokens: this.tokens,
1273
+ extensions: this.extensionSegments,
1209
1274
  };
1210
1275
  }
1211
1276
 
@@ -1217,7 +1282,10 @@ export class WorkingLineController {
1217
1282
  rebase = false,
1218
1283
  ): void {
1219
1284
  const key = this.makeFrameKey(rootConfig, selectedMessage);
1220
- if (!force && this.installed && this.frameKey === key) return;
1285
+ if (!force && this.installed && this.frameKey === key) {
1286
+ this.extensionSegmentsDirty = false;
1287
+ return;
1288
+ }
1221
1289
  const config = rootConfig.components.workingLine;
1222
1290
  const sampledAtMs = this.now();
1223
1291
  let spinnerTick = 0;
@@ -1289,19 +1357,22 @@ export class WorkingLineController {
1289
1357
  this.installed = true;
1290
1358
  this.frameKey = key;
1291
1359
  this.installedIndicatorOptions = indicatorOptions;
1360
+ this.extensionSegmentsDirty = false;
1292
1361
  }
1293
1362
 
1294
- private updateIndicator(ctx: WorkingLineContext): void {
1363
+ private updateIndicator(ctx: WorkingLineContext): boolean {
1295
1364
  const rootConfig = this.getConfig();
1296
- if (!rootConfig.components.workingLine.enabled || !this.installed) return;
1365
+ if (!rootConfig.components.workingLine.enabled || !this.installed) return false;
1297
1366
  const ui = workingLineUi(ctx);
1298
- if (!ui) return;
1367
+ if (!ui) return false;
1299
1368
  const snapshot = this.installationSnapshot();
1300
1369
  try {
1301
1370
  this.applyIndicator(ui, rootConfig);
1371
+ return !this.extensionSegmentsDirty;
1302
1372
  } catch {
1303
1373
  // A transient last-writer/public-API failure must not break the agent turn.
1304
1374
  this.recoverOrReleaseAfterFailure(ui, snapshot);
1375
+ return false;
1305
1376
  }
1306
1377
  }
1307
1378
 
@@ -1378,6 +1449,15 @@ export class WorkingLineController {
1378
1449
  }
1379
1450
  }
1380
1451
 
1452
+ private invalidateUnavailableExtensionSegments(): void {
1453
+ this.invalidateExtensionSegments();
1454
+ try {
1455
+ this.onUnavailable();
1456
+ } catch {
1457
+ // Availability cleanup is fail-open like the public Working-row release.
1458
+ }
1459
+ }
1460
+
1381
1461
  private releaseAfterFailure(ui: WorkingLineUi): void {
1382
1462
  this.deactivateElapsedUpdates();
1383
1463
  if (this.ownsIndicator) {
@@ -1400,6 +1480,7 @@ export class WorkingLineController {
1400
1480
  this.frameKey = undefined;
1401
1481
  this.installedPhase = undefined;
1402
1482
  this.installedIndicatorOptions = undefined;
1483
+ this.invalidateUnavailableExtensionSegments();
1403
1484
  }
1404
1485
 
1405
1486
  private reset(ctx: WorkingLineContext): void {
@@ -1434,5 +1515,6 @@ export class WorkingLineController {
1434
1515
  this.activeTools.clear();
1435
1516
  this.tokens = undefined;
1436
1517
  this.thought = undefined;
1518
+ this.invalidateExtensionSegments();
1437
1519
  }
1438
1520
  }