mixdog 1.4.1 → 1.4.2

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 (326) hide show
  1. package/package.json +3 -2
  2. package/scripts/build-shipped-history.mjs +115 -33
  3. package/scripts/gate-local.mjs +172 -61
  4. package/scripts/lib/gate-scheduler.mjs +138 -32
  5. package/scripts/lib/gate-timing-reporter.mjs +16 -0
  6. package/scripts/lib/run-node-tests.mjs +54 -29
  7. package/scripts/lib/scoped-temp.mjs +1 -0
  8. package/scripts/lib/test-failure-records.mjs +14 -1
  9. package/scripts/lib/test-failure-summary.mjs +16 -4
  10. package/scripts/lib/test-spawn-ledger.mjs +12 -3
  11. package/scripts/pptx-kit-index.mjs +5 -6
  12. package/scripts/suite-health.mjs +110 -28
  13. package/scripts/test.mjs +9 -14
  14. package/src/agents/advisor/AGENT.md +4 -4
  15. package/src/agents/advisor/agent.json +1 -1
  16. package/src/agents/explore/AGENT.md +22 -0
  17. package/src/agents/explore/agent.json +6 -0
  18. package/src/cli.mjs +7 -0
  19. package/src/defaults/agents.json +7 -0
  20. package/src/defaults/shipped-history.json +18 -2
  21. package/src/defaults/skills/browser-use/SKILL.md +4 -1
  22. package/src/defaults/skills/code-tidy/SKILL.md +71 -102
  23. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
  24. package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
  25. package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
  26. package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
  27. package/src/defaults/skills/computer-use/SKILL.md +12 -2
  28. package/src/defaults/skills/goal-management/SKILL.md +1 -1
  29. package/src/defaults/skills/setup/references/actions.md +12 -6
  30. package/src/defaults/skills/setup/references/surfaces.md +2 -2
  31. package/src/defaults/skills/setup-guide/SKILL.md +5 -2
  32. package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
  33. package/src/defaults/skills/skill-creator/SKILL.md +85 -190
  34. package/src/defaults/skills/skill-creator/references/design.md +70 -162
  35. package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
  36. package/src/defaults/skills/test-suite/SKILL.md +194 -0
  37. package/src/defaults/skills/test-suite/references/case-management.md +51 -0
  38. package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
  39. package/src/defaults/skills/test-suite/references/reliability.md +49 -0
  40. package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
  41. package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
  42. package/src/defaults/skills/visualize/SKILL.md +6 -2
  43. package/src/lib/rules-builder.cjs +6 -30
  44. package/src/rules/lead/LEAD.md +3 -3
  45. package/src/rules/shared/20-research.md +3 -6
  46. package/src/rules/shared/40-editing.md +1 -0
  47. package/src/rules/shared/60-verification.md +10 -9
  48. package/src/rules/shared/70-delivery.md +4 -3
  49. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
  50. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
  51. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +130 -21
  52. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
  53. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
  54. package/src/runtime/agent/orchestrator/config.mjs +12 -7
  55. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +7 -7
  56. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
  57. package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
  58. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
  59. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
  60. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
  61. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
  62. package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
  63. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +83 -52
  64. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
  65. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +43 -8
  66. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +30 -28
  67. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
  69. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
  71. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  72. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
  73. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
  74. package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
  75. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
  76. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
  77. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
  78. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
  79. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
  80. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +48 -31
  81. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
  82. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
  83. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
  84. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
  85. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
  86. package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +26 -28
  88. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +3 -1
  89. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +1 -0
  90. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
  92. package/src/runtime/agent/orchestrator/providers/registry.mjs +33 -2
  93. package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
  94. package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
  95. package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
  96. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
  97. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  98. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +2 -1
  99. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  100. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -0
  101. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
  102. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
  103. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
  104. package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
  105. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +94 -10
  106. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +3 -3
  107. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +10 -5
  108. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +5 -5
  109. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +11 -1
  110. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
  111. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
  112. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +5 -3
  113. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +21 -2
  114. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
  115. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
  116. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
  117. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
  118. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
  119. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +3 -4
  120. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +2 -0
  121. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
  122. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
  123. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +25 -14
  124. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +17 -14
  125. package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
  126. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
  127. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -3
  128. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +47 -29
  129. package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
  130. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
  131. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +1 -1
  132. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +243 -38
  133. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
  134. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
  135. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
  136. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
  137. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +36 -26
  138. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +3 -5
  139. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
  141. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
  142. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
  143. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  144. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
  145. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
  146. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
  147. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
  148. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
  149. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
  150. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
  151. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
  153. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
  154. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  155. package/src/runtime/channels/lib/whisper-port.mjs +19 -10
  156. package/src/runtime/channels/lib/whisper-server.mjs +10 -1
  157. package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
  158. package/src/runtime/connectors/gmail-app-password.mjs +3 -3
  159. package/src/runtime/explore/explorer.mjs +93 -0
  160. package/src/runtime/explore/tool-defs.mjs +35 -0
  161. package/src/runtime/explore/tool.mjs +123 -0
  162. package/src/runtime/memory/index.mjs +4 -0
  163. package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
  164. package/src/runtime/memory/lib/embedding-worker.mjs +4 -0
  165. package/src/runtime/office/quality/assurance-structure-docx.mjs +1 -1
  166. package/src/runtime/shared/agent-route-config.mjs +17 -2
  167. package/src/runtime/shared/atomic-file.mjs +103 -2
  168. package/src/runtime/shared/background-tasks.mjs +15 -6
  169. package/src/runtime/shared/connector-accounts.mjs +5 -5
  170. package/src/runtime/shared/connector-catalog.d.mts +11 -4
  171. package/src/runtime/shared/connector-catalog.mjs +60 -52
  172. package/src/runtime/shared/custom-provider-keys.mjs +20 -0
  173. package/src/runtime/shared/file-has-data.mjs +26 -2
  174. package/src/runtime/shared/file-lock.mjs +13 -15
  175. package/src/runtime/shared/git-launch.d.mts +9 -0
  176. package/src/runtime/shared/git-launch.mjs +213 -0
  177. package/src/runtime/shared/git-runner-worker.mjs +2 -1
  178. package/src/runtime/shared/llm/cost.mjs +6 -1
  179. package/src/runtime/shared/llm/http-agent.mjs +313 -29
  180. package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
  181. package/src/runtime/shared/llm/model-catalog.mjs +46 -6
  182. package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
  183. package/src/runtime/shared/llm/system-proxy.mjs +452 -0
  184. package/src/runtime/shared/provider-accounts.mjs +52 -2
  185. package/src/runtime/shared/staged-install-worker.mjs +5 -0
  186. package/src/runtime/shared/staged-update.mjs +47 -2
  187. package/src/runtime/shared/tool-surface.mjs +110 -36
  188. package/src/runtime/shared/tool-work-units.mjs +4 -0
  189. package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
  190. package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
  191. package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
  192. package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
  193. package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
  194. package/src/runtime/shared/worktrees/git.mjs +57 -0
  195. package/src/runtime/shared/worktrees/manager.mjs +205 -137
  196. package/src/runtime/tidy/install.mjs +95 -15
  197. package/src/runtime/tidy/languages.mjs +17 -15
  198. package/src/runtime/tidy/process.mjs +7 -4
  199. package/src/runtime/tidy/resolve.mjs +19 -16
  200. package/src/runtime/tidy/runners/biome.mjs +3 -3
  201. package/src/runtime/tidy/tool.mjs +1 -1
  202. package/src/runtime/tidy/worktree.mjs +10 -6
  203. package/src/runtime/visualize-bridge/client.mjs +4 -1
  204. package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
  205. package/src/runtime/web-search/index.mjs +1 -1
  206. package/src/session-runtime/agent-task-sessions.mjs +410 -353
  207. package/src/session-runtime/boot/tools.mjs +2 -0
  208. package/src/session-runtime/bot-status.mjs +103 -103
  209. package/src/session-runtime/connector-merge-migration.mjs +18 -15
  210. package/src/session-runtime/conversation-import/discovery.mjs +159 -40
  211. package/src/session-runtime/conversation-import/service.mjs +9 -3
  212. package/src/session-runtime/handoff-attachments.mjs +1 -1
  213. package/src/session-runtime/held-requests.mjs +3 -1
  214. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
  215. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
  216. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +143 -116
  217. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
  218. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  219. package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
  220. package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
  221. package/src/session-runtime/mixy-heartbeat.mjs +1 -1
  222. package/src/session-runtime/provider-auth/login.mjs +2 -2
  223. package/src/session-runtime/resource-mcp-api.mjs +98 -35
  224. package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
  225. package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
  226. package/src/session-runtime/resource-mcp-servers.mjs +5 -4
  227. package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
  228. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
  229. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
  230. package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
  231. package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
  232. package/src/session-runtime/services/daemon-candidate.mjs +4 -1
  233. package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
  234. package/src/session-runtime/services/plugin-admin.mjs +10 -6
  235. package/src/session-runtime/services/provider-admin.mjs +281 -10
  236. package/src/session-runtime/session-turn-api.mjs +2 -0
  237. package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
  238. package/src/session-runtime/settings-system-api.mjs +1 -1
  239. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
  240. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
  241. package/src/session-runtime/setup-tool/executor.mjs +6 -2
  242. package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
  243. package/src/session-runtime/turn/agent-ops.mjs +23 -0
  244. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
  245. package/src/session-runtime/workflow-agents-api/agent-route.mjs +10 -1
  246. package/src/session-runtime/workspace/activity-guards.mjs +176 -0
  247. package/src/session-runtime/workspace/session-view.mjs +149 -0
  248. package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
  249. package/src/session-runtime/workspace/transition-runner.mjs +188 -0
  250. package/src/session-runtime/workspace/transitions.mjs +108 -1066
  251. package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
  252. package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
  253. package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
  254. package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
  255. package/src/session-runtime/workspace/worktree-tool.mjs +54 -54
  256. package/src/standalone/daemon-desktop-runtime.mjs +2 -0
  257. package/src/standalone/daemon-session-control.mjs +151 -136
  258. package/src/standalone/daemon.mjs +7 -0
  259. package/src/standalone/desktop-service-registry.mjs +9 -0
  260. package/src/standalone/local-session-runtime.mjs +5 -1
  261. package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
  262. package/src/standalone/session-client.mjs +5 -1
  263. package/src/standalone/session-frame-stream.mjs +83 -11
  264. package/src/standalone/session-protocol.mjs +4 -0
  265. package/src/standalone/session-service/agent-tree.mjs +45 -9
  266. package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
  267. package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
  268. package/src/standalone/session-service/stored-reader.mjs +127 -40
  269. package/src/tui/App.jsx +154 -164
  270. package/src/tui/app/app-view/floating-panel.jsx +3 -0
  271. package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
  272. package/src/tui/app/clipboard.mjs +21 -10
  273. package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
  274. package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
  275. package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
  276. package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
  277. package/src/tui/app/provider-setup/oauth-actions.mjs +25 -6
  278. package/src/tui/app/provider-setup-picker.mjs +20 -13
  279. package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
  280. package/src/tui/app/slash-commands.mjs +1 -0
  281. package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
  282. package/src/tui/app/slash-dispatch.mjs +1 -1
  283. package/src/tui/app/use-btw-panel.mjs +29 -0
  284. package/src/tui/app/use-context-panel-refresh.mjs +31 -0
  285. package/src/tui/app/use-model-catalog-cache.mjs +13 -10
  286. package/src/tui/app/use-mouse-input.mjs +11 -0
  287. package/src/tui/app/use-onboarding-start.mjs +8 -3
  288. package/src/tui/app/use-panel-transition.mjs +10 -1
  289. package/src/tui/app/use-pasted-buffers.mjs +28 -20
  290. package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
  291. package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
  292. package/src/tui/app/use-prompt-queue-history.mjs +3 -2
  293. package/src/tui/app/use-selection-focus.mjs +11 -2
  294. package/src/tui/app/use-selection-geometry.mjs +18 -9
  295. package/src/tui/app/use-selection-paint.mjs +4 -4
  296. package/src/tui/app/use-selection-stitch.mjs +3 -3
  297. package/src/tui/app/use-slash-palette.mjs +62 -0
  298. package/src/tui/app/use-terminal-chrome.mjs +2 -2
  299. package/src/tui/app/use-transcript-activity.mjs +47 -32
  300. package/src/tui/app/use-transcript-follow.mjs +12 -4
  301. package/src/tui/app/use-transcript-scroll.mjs +46 -17
  302. package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
  303. package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
  304. package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
  305. package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
  306. package/src/tui/app/use-transcript-window.mjs +21 -11
  307. package/src/tui/app/use-tui-ready.mjs +18 -0
  308. package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
  309. package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
  310. package/src/tui/components/Picker.jsx +27 -3
  311. package/src/tui/components/SignInUrl.jsx +68 -0
  312. package/src/tui/components/TextEntryPanel.jsx +76 -46
  313. package/src/tui/components/sign-in-url-layout.mjs +24 -0
  314. package/src/tui/dist/index.mjs +1896 -1341
  315. package/src/tui/session/goal-turn-state.mjs +6 -2
  316. package/src/tui/session/session-api/controls.mjs +4 -0
  317. package/src/tui/session/session-api/extensions.mjs +8 -0
  318. package/src/tui/session/session-api/intake/abort.mjs +2 -1
  319. package/src/tui/session/session-api/intake.mjs +2 -0
  320. package/src/tui/session/session-api/integrations.mjs +2 -2
  321. package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
  322. package/src/tui/session/session-api/settings.mjs +2 -2
  323. package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
  324. package/src/tui/session/transcript-spill.mjs +92 -4
  325. package/src/tui/session/transcript-store.mjs +2 -0
  326. package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
@@ -19,6 +19,8 @@ import { theme } from '../theme.mjs';
19
19
  import { ConfirmBar, clampConfirmFocus } from './ConfirmBar.jsx';
20
20
  import { truncatePanelText as truncateText } from './panel-cell-text.mjs';
21
21
  import { PickerItemRow } from './picker/PickerItemRow.jsx';
22
+ import { SignInUrl, isSignInCopyKey, signInUrlNote, useCopyUrl } from './SignInUrl.jsx';
23
+ import { signInUrlLayout } from './sign-in-url-layout.mjs';
22
24
  import {
23
25
  ADJUST_HELP,
24
26
  CONFIRM_HELP,
@@ -43,6 +45,10 @@ export function Picker({
43
45
  onHighlight,
44
46
  title,
45
47
  description = '',
48
+ // Optional sign-in URL, drawn complete and borderless under the panel (never
49
+ // truncated like `description`); Ctrl+Y copies it. `copyText` overrides the clipboard.
50
+ detail = '',
51
+ copyText,
46
52
  footer = '',
47
53
  help,
48
54
  columns = 80,
@@ -89,7 +95,21 @@ export function Picker({
89
95
  const footerGap = footerLines.length > 0 ? Math.max(0, Math.floor(Number(footerGapRows) || 0)) : 0;
90
96
  const footerReserveRows = footerLines.length > 0 ? footerLines.length + footerGap : 0;
91
97
  const confirmReserveRows = hasConfirm && footerLines.length === 0 ? 2 : 0;
92
- const effectiveVisibleLimit = Math.max(1, visibleLimit - footerReserveRows - confirmReserveRows);
98
+ const detailText = String(detail || '').trim();
99
+ // The URL is drawn under the panel (no border). Its rows (wrapped URL + copy
100
+ // hint) come out of the list so the total height is unchanged. It gets the
101
+ // rows left beside up to two list rows (one, if that leaves nothing) and
102
+ // degrades step by step (see sign-in-url-layout.mjs) until it fits.
103
+ const rowsAfterChrome = visibleLimit - footerReserveRows - confirmReserveRows;
104
+ const keptListRows = rowsAfterChrome - Math.min(items.length, 2) >= 1 ? Math.min(items.length, 2) : 1;
105
+ const urlLayout = signInUrlLayout(detailText, columns, rowsAfterChrome - keptListRows);
106
+ const detailRows = urlLayout.rows;
107
+ const copyUrl = useCopyUrl(detailText, copyText);
108
+ const handleKey = (input, key, item, index) => {
109
+ if (detailText && isSignInCopyKey(input, key)) copyUrl.copy();
110
+ else onKey?.(input, key, item, index);
111
+ };
112
+ const effectiveVisibleLimit = Math.max(1, visibleLimit - footerReserveRows - confirmReserveRows - detailRows);
93
113
  let helpText = help;
94
114
  if (!helpText) {
95
115
  if (hasConfirm) helpText = CONFIRM_HELP;
@@ -112,7 +132,7 @@ export function Picker({
112
132
  onLeft,
113
133
  onRight,
114
134
  onTab,
115
- onKey,
135
+ onKey: handleKey,
116
136
  effectiveVisibleLimit,
117
137
  hasConfirm,
118
138
  confirmButtons,
@@ -124,8 +144,9 @@ export function Picker({
124
144
  // line so a multi-line description (e.g. ToolApproval) cannot push the title
125
145
  // off the top. The slot is always reserved so panel chrome is a constant 6
126
146
  // rows (title + blank + desc + blank + 2 border), matching PICKER_CHROME_ROWS.
147
+ // With no hint row under the URL, the description row carries the copy note.
127
148
  const panelDescription = truncateText(
128
- String(description || '')
149
+ String(!urlLayout.hint && detailText ? signInUrlNote(copyUrl.status) : description || '')
129
150
  .replace(/\s+/g, ' ')
130
151
  .trim(),
131
152
  Math.max(0, columns - 4)
@@ -134,6 +155,7 @@ export function Picker({
134
155
  if (items.length === 0) {
135
156
  const loadingRows = loading
136
157
  ? Array.from({ length: visibleLimit }, (_, index) => (
158
+ // biome-ignore lint/suspicious/noArrayIndexKey: identical blank placeholder rows have no identity besides position
137
159
  <Text key={`loading-${index}`} color={theme.inactive}>
138
160
  {' '}
139
161
  </Text>
@@ -253,6 +275,7 @@ export function Picker({
253
275
  const attachConfirm = hasConfirm && index === footerLines.length - 1;
254
276
  return (
255
277
  <Box
278
+ // biome-ignore lint/suspicious/noArrayIndexKey: footer lines are positional and may repeat text
256
279
  key={`footer-${index}`}
257
280
  flexDirection="row"
258
281
  width="100%"
@@ -277,6 +300,7 @@ export function Picker({
277
300
  </>
278
301
  ) : null}
279
302
  </Box>
303
+ <SignInUrl url={detailText} layout={urlLayout} status={copyUrl.status} />
280
304
  </Box>
281
305
  );
282
306
  }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * components/SignInUrl.jsx — a sign-in URL shown OUTSIDE any bordered panel.
3
+ *
4
+ * Inside a bordered panel a wrapped URL carries the `│` border and padding on
5
+ * every row, so a terminal selection copies junk. Here the rows are plain text
6
+ * with no border, the URL is an OSC 8 hyperlink whose target is the complete
7
+ * URL (click it, or "Copy link" in the terminal), and SIGN_IN_COPY_KEY copies the
8
+ * exact URL through the clipboard helper. `layout` (sign-in-url-layout.mjs) may shorten
9
+ * the visible label to fit the panel; the link target and the copy stay complete.
10
+ */
11
+ import { useState } from 'react';
12
+ import { Box, Text } from 'ink';
13
+ import { theme } from '../theme.mjs';
14
+ import { copyToClipboard } from '../app/clipboard.mjs';
15
+
16
+ const SAFE_URL_RE = /^https?:\/\//i;
17
+
18
+ // OSC 8 needs no support probe: a terminal that does not know the hyperlink
19
+ // sequence ignores it and shows the label (its documented fallback). Only
20
+ // http(s) targets are linked.
21
+ const linkedUrl = (url, label) => (SAFE_URL_RE.test(url) ? `\x1b]8;;${url}\x07${label}\x1b]8;;\x07` : label);
22
+
23
+ const STATUS_TEXT = {
24
+ copied: 'URL copied',
25
+ sent: 'Sent to terminal clipboard (not confirmed)',
26
+ failed: 'Copy failed: no clipboard available, use the link above',
27
+ };
28
+
29
+ /** The one key that copies a sign-in URL in every panel, with or without a focused text input. */
30
+ const SIGN_IN_COPY_KEY = 'Ctrl+Y';
31
+ export const isSignInCopyKey = (input, key) => Boolean(key?.ctrl) && String(input || '').toLowerCase() === 'y';
32
+
33
+ /** The copy-key note, or what the last copy did. */
34
+ export const signInUrlNote = (status) => STATUS_TEXT[status] || `${SIGN_IN_COPY_KEY} copies the full URL`;
35
+
36
+ /** { copy, status } — status is '', 'copied', 'sent' (OSC 52 only) or 'failed'. */
37
+ export function useCopyUrl(url, copyText = (text) => copyToClipboard(text, { confirm: true })) {
38
+ const [status, setStatus] = useState('');
39
+ const copy = () => {
40
+ if (!url) return;
41
+ Promise.resolve()
42
+ .then(() => copyText(url))
43
+ .then((how) => setStatus(how === 'terminal' ? 'sent' : 'copied'))
44
+ .catch(() => setStatus('failed'));
45
+ };
46
+ return { copy, status };
47
+ }
48
+
49
+ export function SignInUrl({ url, layout, status = '' }) {
50
+ const text = String(url || '').trim();
51
+ if (!text || layout.rows === 0) return null;
52
+ return (
53
+ // flexShrink 0 everywhere: the layout reserved exactly these rows, and in a
54
+ // height-constrained panel (fillHeight) yoga would otherwise shrink the
55
+ // wrapped URL Text below its row count, so the hint row lands on the
56
+ // URL's last row. The panel's bordered box gives the rows up instead.
57
+ <Box flexDirection="column" flexShrink={0} width="100%">
58
+ <Text color={theme.text} wrap={layout.compact ? 'truncate-end' : 'wrap'} flexShrink={0}>
59
+ {linkedUrl(text, layout.label)}
60
+ </Text>
61
+ {layout.hint ? (
62
+ <Text color={theme.subtle} wrap="truncate-end" flexShrink={0}>
63
+ {signInUrlNote(status)}
64
+ </Text>
65
+ ) : null}
66
+ </Box>
67
+ );
68
+ }
@@ -9,6 +9,8 @@ import { clearSelection, lineEnd, lineStart, moveCursor, replaceSelection, selec
9
9
  import { textEntryReservedRows } from '../app/text-layout.mjs';
10
10
  import { createTextEntryCursorAnchor, singleLine } from './text-entry-layout.mjs';
11
11
  import { renderTextEntryValue } from './text-entry-value.jsx';
12
+ import { SignInUrl, isSignInCopyKey, signInUrlNote, useCopyUrl } from './SignInUrl.jsx';
13
+ import { signInUrlLayout } from './sign-in-url-layout.mjs';
12
14
  import { canSubmitTextEntry } from '../app/text-entry-policy.mjs';
13
15
  import { truncatePanelText as truncateText } from './panel-cell-text.mjs';
14
16
  import { applyEditChord, createVerticalMover } from './prompt-input/edit-chords.mjs';
@@ -23,10 +25,53 @@ import {
23
25
  } from './prompt-input/edit-helpers.mjs';
24
26
  import { isCsiPrivateReply } from './prompt-input/key-signals.mjs';
25
27
 
28
+ /** The bordered panel: title row, hint row and the editable value. `boxRef`
29
+ * is the value box the cursor anchor is installed on. */
30
+ function TextEntryFrame({ title, helpText, hintText, multiline, promptLabel, boxRef, contentHeight, renderedValue }) {
31
+ return (
32
+ <Box borderStyle="round" borderColor={theme.promptBorder} paddingX={1} width="100%" flexDirection="column">
33
+ <Box flexDirection="row" justifyContent="space-between">
34
+ <Text color={theme.panelTitle}>{title}</Text>
35
+ <Text color={theme.subtle}>{helpText}</Text>
36
+ </Box>
37
+ <Text> </Text>
38
+ <Text color={theme.subtle}>{hintText || ' '}</Text>
39
+ <Text> </Text>
40
+ {multiline ? (
41
+ <Box flexDirection="row" width="100%" alignItems="flex-start" backgroundColor={surfaceBackground()}>
42
+ <Text color={theme.inactive}>{promptLabel}</Text>
43
+ <Box
44
+ ref={boxRef}
45
+ flexGrow={1}
46
+ flexDirection="column"
47
+ height={contentHeight}
48
+ overflow="hidden"
49
+ backgroundColor={surfaceBackground()}
50
+ >
51
+ <Text color={theme.text} wrap="hard">
52
+ {renderedValue}
53
+ </Text>
54
+ </Box>
55
+ </Box>
56
+ ) : (
57
+ <Box ref={boxRef} flexDirection="row" width="100%" backgroundColor={surfaceBackground()}>
58
+ <Text color={theme.inactive}>{promptLabel}</Text>
59
+ <Text color={theme.text} wrap="truncate">
60
+ {renderedValue}
61
+ </Text>
62
+ </Box>
63
+ )}
64
+ </Box>
65
+ );
66
+ }
67
+
26
68
  export function TextEntryPanel({
27
69
  title,
28
70
  hint = '',
29
71
  detail = '',
72
+ copyText,
73
+ // Rows the panel can give the detail URL block (row-budgets.mjs); unbounded when unknown.
74
+ urlMaxRows = Number.POSITIVE_INFINITY,
30
75
  initialValue = '',
31
76
  // Blank submit = the documented reset/clear action for some prompt kinds
32
77
  // (system shell → auto, provider auto-clear → built-in, profile title →
@@ -56,6 +101,11 @@ export function TextEntryPanel({
56
101
  const preferredColumnRef = useRef(null);
57
102
  const { isRawModeSupported } = useStdin();
58
103
  draftRef.current = draft;
104
+ // Optional sign-in URL (e.g. the OAuth URL), drawn complete and borderless
105
+ // under the panel — in the live panel only, never pushed to the transcript, so
106
+ // it disappears when the panel closes instead of lingering in scrollback.
107
+ const detailText = String(detail || '').trim();
108
+ const copyUrl = useCopyUrl(detailText, copyText);
59
109
 
60
110
  const flushImmediate = () => {
61
111
  let node = boxRef.current;
@@ -81,6 +131,7 @@ export function TextEntryPanel({
81
131
 
82
132
  const moveDraftVertically = createVerticalMover({ draftRef, contentWidthRef, preferredColumnRef, commitDraft });
83
133
 
134
+ // biome-ignore lint/correctness/useExhaustiveDependencies: reset only when the prompt (title/initialValue) changes; commitDraft is recreated every render and only touches refs/setState
84
135
  useEffect(() => {
85
136
  const value = String(initialValue || '');
86
137
  commitDraft({ value, cursor: value.length, selectionAnchor: null });
@@ -133,6 +184,7 @@ export function TextEntryPanel({
133
184
  (input, key) => {
134
185
  const rawSource = String(input ?? '');
135
186
  const rawInput = normalizePastedText(input);
187
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: matches the ESC byte of SGR mouse reports
136
188
  if (/(?:\x1b)?\[<\d+;\d+;\d+[Mm]/.test(rawSource)) return;
137
189
  // Safety net: drop CSI-private replies/fragments (\x1b[?<n>u / \x1b[?...c);
138
190
  // a volunteered report must never type into the field.
@@ -230,6 +282,10 @@ export function TextEntryPanel({
230
282
  updateDraft((d) => moveCursor(d, lineEnd(d.value, d.cursor), { extend: key.shift }));
231
283
  return;
232
284
  }
285
+ if (detailText && isSignInCopyKey(input, key)) {
286
+ copyUrl.copy();
287
+ return;
288
+ }
233
289
  if (applyEditChord(key, inputKey, updateDraft)) return;
234
290
  if (rawInput && !key.ctrl && !key.meta) {
235
291
  updateDraft((d) => insertText(d, rawInput));
@@ -256,12 +312,14 @@ export function TextEntryPanel({
256
312
  cursorEnabledRef.current = isRawModeSupported;
257
313
  installCursorAnchor();
258
314
 
315
+ // biome-ignore lint/correctness/useExhaustiveDependencies: mount-only anchor install; the helpers are per-render closures over refs
259
316
  useLayoutEffect(() => {
260
317
  if (!installCursorAnchor()) return;
261
318
  bumpCursorAnchorEpoch((epoch) => epoch + 1);
262
319
  queueMicrotask(flushImmediate);
263
320
  }, []);
264
321
 
322
+ // biome-ignore lint/correctness/useExhaustiveDependencies: title/multiline/draft are deliberate triggers to re-flush after content changes; flushImmediate is a per-render ref closure
265
323
  useLayoutEffect(() => {
266
324
  if (!isRawModeSupported) return;
267
325
  queueMicrotask(flushImmediate);
@@ -279,55 +337,27 @@ export function TextEntryPanel({
279
337
  // Standard panel rhythm: title row, blank, single-line hint, blank, content.
280
338
  // The hint is collapsed to one line and width-truncated so a long manual
281
339
  // OAuth URL can never wrap and push the bordered title off the top.
282
- const hintText = truncateText(singleLine(hint), Math.max(0, columns - 4));
283
- // Optional wrapped detail block (e.g. the manual OAuth URL). Lives INSIDE the
284
- // live panel — never pushed to the transcript — so it disappears completely
285
- // when the panel closes instead of lingering in terminal scrollback.
286
- const detailText = String(detail || '').trim();
340
+ // The URL block gets the rows the panel really has (urlMaxRows) and degrades
341
+ // to fit; with no hint row under the URL, the hint row carries the copy note.
342
+ const urlLayout = signInUrlLayout(detailText, columns, urlMaxRows);
343
+ const hintText = truncateText(
344
+ !urlLayout.hint && detailText ? signInUrlNote(copyUrl.status) : singleLine(hint),
345
+ Math.max(0, columns - 4)
346
+ );
287
347
 
288
348
  return (
289
349
  <Box flexDirection="column" flexShrink={0} width="100%">
290
- <Box borderStyle="round" borderColor={theme.promptBorder} paddingX={1} width="100%" flexDirection="column">
291
- <Box flexDirection="row" justifyContent="space-between">
292
- <Text color={theme.panelTitle}>{title}</Text>
293
- <Text color={theme.subtle}>{helpText}</Text>
294
- </Box>
295
- <Text> </Text>
296
- <Text color={theme.subtle}>{hintText || ' '}</Text>
297
- {detailText ? (
298
- <Box flexDirection="column" width="100%">
299
- <Text> </Text>
300
- <Text color={theme.subtle} wrap="wrap">
301
- {detailText}
302
- </Text>
303
- </Box>
304
- ) : null}
305
- <Text> </Text>
306
- {multiline ? (
307
- <Box flexDirection="row" width="100%" alignItems="flex-start" backgroundColor={surfaceBackground()}>
308
- <Text color={theme.inactive}>{promptLabel}</Text>
309
- <Box
310
- ref={boxRef}
311
- flexGrow={1}
312
- flexDirection="column"
313
- height={contentHeight}
314
- overflow="hidden"
315
- backgroundColor={surfaceBackground()}
316
- >
317
- <Text color={theme.text} wrap="hard">
318
- {renderedValue}
319
- </Text>
320
- </Box>
321
- </Box>
322
- ) : (
323
- <Box ref={boxRef} flexDirection="row" width="100%" backgroundColor={surfaceBackground()}>
324
- <Text color={theme.inactive}>{promptLabel}</Text>
325
- <Text color={theme.text} wrap="truncate">
326
- {renderedValue}
327
- </Text>
328
- </Box>
329
- )}
330
- </Box>
350
+ <TextEntryFrame
351
+ title={title}
352
+ helpText={helpText}
353
+ hintText={hintText}
354
+ multiline={multiline}
355
+ promptLabel={promptLabel}
356
+ boxRef={boxRef}
357
+ contentHeight={contentHeight}
358
+ renderedValue={renderedValue}
359
+ />
360
+ <SignInUrl url={detailText} layout={urlLayout} status={copyUrl.status} />
331
361
  </Box>
332
362
  );
333
363
  }
@@ -0,0 +1,24 @@
1
+ // components/sign-in-url-layout.mjs — row budget for a borderless sign-in URL block.
2
+ //
3
+ // `maxRows` is the height the panel can actually give the block. The block
4
+ // degrades until it fits, and ONLY the visible text shrinks: the OSC 8 link
5
+ // target and the clipboard copy always use the full URL.
6
+ // 1. full URL wrapped over its rows + a copy-hint row
7
+ // 2. one row with the URL's start and `…` + the hint row
8
+ // 3. that one row alone (hint dropped)
9
+ // 4. nothing (0 rows); the panel's own description/hint row carries the copy note
10
+ import { wrappedDetailRows } from '../app/text-layout.mjs';
11
+ import { truncatePanelText } from './panel-cell-text.mjs';
12
+
13
+ export function signInUrlLayout(url, columns, maxRows) {
14
+ const text = String(url || '').trim();
15
+ if (!text) return { compact: false, rows: 0, hint: false, label: '' };
16
+ const width = Math.max(1, Math.floor(Number(columns) || 1));
17
+ const max = Math.max(0, Math.floor(Number(maxRows)));
18
+ const fullRows = wrappedDetailRows(text, width) + 1;
19
+ if (fullRows <= max) return { compact: false, rows: fullRows, hint: true, label: text };
20
+ const label = truncatePanelText(text, width);
21
+ if (max >= 2) return { compact: true, rows: 2, hint: true, label };
22
+ if (max >= 1) return { compact: true, rows: 1, hint: false, label };
23
+ return { compact: true, rows: 0, hint: false, label: '' };
24
+ }