mixdog 1.4.0 → 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 (493) hide show
  1. package/package.json +3 -2
  2. package/scripts/build-shipped-history.mjs +115 -33
  3. package/scripts/check-voice-runtime-inputs.mjs +25 -0
  4. package/scripts/gate-local.mjs +183 -63
  5. package/scripts/latest-guard.mjs +21 -9
  6. package/scripts/lib/gate-scheduler.mjs +138 -32
  7. package/scripts/lib/gate-timing-reporter.mjs +16 -0
  8. package/scripts/lib/isolated-test-env.mjs +10 -5
  9. package/scripts/lib/run-node-tests.mjs +91 -66
  10. package/scripts/lib/scoped-temp.d.mts +16 -0
  11. package/scripts/lib/scoped-temp.mjs +124 -0
  12. package/scripts/lib/stale-temp.mjs +44 -0
  13. package/scripts/lib/test-failure-records.mjs +14 -1
  14. package/scripts/lib/test-failure-summary.mjs +16 -4
  15. package/scripts/lib/test-spawn-ledger.mjs +12 -3
  16. package/scripts/post-release-check.mjs +1 -6
  17. package/scripts/pptx-kit-index.mjs +17 -5
  18. package/scripts/suite-health.mjs +115 -24
  19. package/scripts/test-data-dir.mjs +10 -7
  20. package/scripts/test.mjs +9 -14
  21. package/src/agents/advisor/AGENT.md +4 -4
  22. package/src/agents/advisor/agent.json +1 -1
  23. package/src/agents/explore/AGENT.md +22 -0
  24. package/src/agents/explore/agent.json +6 -0
  25. package/src/app.mjs +4 -0
  26. package/src/cli.mjs +7 -0
  27. package/src/defaults/agents.json +7 -0
  28. package/src/defaults/shipped-history.json +23 -2
  29. package/src/defaults/skills/browser-use/SKILL.md +10 -5
  30. package/src/defaults/skills/code-tidy/SKILL.md +71 -102
  31. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
  32. package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
  33. package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
  34. package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
  35. package/src/defaults/skills/computer-use/SKILL.md +16 -4
  36. package/src/defaults/skills/goal-management/SKILL.md +1 -1
  37. package/src/defaults/skills/setup/references/actions.md +12 -6
  38. package/src/defaults/skills/setup/references/surfaces.md +2 -2
  39. package/src/defaults/skills/setup-guide/SKILL.md +5 -2
  40. package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
  41. package/src/defaults/skills/skill-creator/SKILL.md +85 -190
  42. package/src/defaults/skills/skill-creator/references/design.md +70 -162
  43. package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
  44. package/src/defaults/skills/test-suite/SKILL.md +194 -0
  45. package/src/defaults/skills/test-suite/references/case-management.md +51 -0
  46. package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
  47. package/src/defaults/skills/test-suite/references/reliability.md +49 -0
  48. package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
  49. package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
  50. package/src/defaults/skills/visualize/SKILL.md +6 -2
  51. package/src/lib/rules-builder.cjs +35 -42
  52. package/src/output-styles/common.md +2 -2
  53. package/src/output-styles/simple.md +1 -1
  54. package/src/rules/agent/AGENT.md +5 -4
  55. package/src/rules/lead/LEAD.md +12 -7
  56. package/src/rules/shared/10-tool-workflow.md +3 -1
  57. package/src/rules/shared/20-research.md +3 -6
  58. package/src/rules/shared/40-editing.md +1 -0
  59. package/src/rules/shared/45-destructive.md +0 -2
  60. package/src/rules/shared/50-execution.md +2 -0
  61. package/src/rules/shared/60-verification.md +10 -9
  62. package/src/rules/shared/70-delivery.md +8 -9
  63. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
  64. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
  65. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
  66. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
  67. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
  69. package/src/runtime/agent/orchestrator/config.mjs +12 -7
  70. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
  71. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
  72. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
  73. package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
  74. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
  75. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
  76. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
  77. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
  78. package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
  79. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
  80. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
  81. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
  82. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
  83. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
  84. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
  85. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
  86. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
  87. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
  89. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
  90. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
  91. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
  92. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
  93. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
  94. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
  95. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
  97. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
  98. package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
  99. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
  100. package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
  101. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
  102. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
  103. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
  104. package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
  105. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
  106. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
  107. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
  108. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
  109. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
  110. package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
  113. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
  114. package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
  115. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
  116. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
  117. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
  118. package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
  119. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  120. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
  121. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
  122. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
  123. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  125. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
  126. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
  127. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  128. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
  129. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
  130. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
  131. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
  132. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
  133. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
  134. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
  135. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
  136. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
  137. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
  138. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
  139. package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
  140. package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
  141. package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
  142. package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
  143. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
  145. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  146. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
  147. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
  148. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  149. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
  150. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
  151. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
  152. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
  153. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
  154. package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
  155. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
  156. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
  157. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  158. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
  159. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
  160. package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
  161. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
  162. package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
  163. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
  164. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
  165. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
  166. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
  167. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
  168. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
  169. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
  170. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
  171. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
  172. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
  174. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
  175. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
  176. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
  177. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
  178. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
  179. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
  180. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
  181. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
  182. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
  183. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
  184. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
  185. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
  186. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
  187. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
  188. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
  189. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
  190. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
  191. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
  192. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
  193. package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
  194. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
  195. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
  196. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
  197. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
  198. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
  199. package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
  200. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
  201. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
  202. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
  203. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
  204. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
  206. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
  207. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
  208. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
  209. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
  210. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
  211. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
  212. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
  213. package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
  214. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
  215. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
  216. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
  217. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
  218. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
  219. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
  220. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
  221. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
  222. package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
  223. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
  224. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
  225. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
  226. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
  227. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
  228. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
  229. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
  230. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
  231. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
  232. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
  233. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
  234. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  235. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  236. package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
  237. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
  238. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
  239. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
  240. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
  241. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
  242. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
  243. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
  244. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
  245. package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
  246. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  248. package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
  249. package/src/runtime/channels/lib/whisper-port.mjs +29 -11
  250. package/src/runtime/channels/lib/whisper-server.mjs +10 -1
  251. package/src/runtime/computer-bridge/action-schema.mjs +2 -2
  252. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  253. package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
  254. package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
  255. package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
  256. package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
  257. package/src/runtime/connectors/gmail-app-password.mjs +3 -3
  258. package/src/runtime/explore/explorer.mjs +93 -0
  259. package/src/runtime/explore/tool-defs.mjs +35 -0
  260. package/src/runtime/explore/tool.mjs +123 -0
  261. package/src/runtime/local-provider/server-process.mjs +2 -1
  262. package/src/runtime/media/adapters/gemini-video.mjs +4 -1
  263. package/src/runtime/media/adapters/xai-media.mjs +2 -1
  264. package/src/runtime/memory/index.mjs +4 -0
  265. package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
  266. package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
  267. package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
  268. package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
  269. package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
  270. package/src/runtime/office/design/design-art-direction.mjs +29 -27
  271. package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
  272. package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
  273. package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
  274. package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
  275. package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
  276. package/src/runtime/office/quality/design-review.mjs +1 -5
  277. package/src/runtime/office/quality/document-brief.mjs +1 -5
  278. package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
  279. package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
  280. package/src/runtime/shared/agent-route-config.mjs +17 -2
  281. package/src/runtime/shared/atomic-file.mjs +103 -2
  282. package/src/runtime/shared/background-tasks.mjs +15 -6
  283. package/src/runtime/shared/bot-owned-work.mjs +56 -0
  284. package/src/runtime/shared/connector-accounts.mjs +5 -5
  285. package/src/runtime/shared/connector-catalog.d.mts +11 -4
  286. package/src/runtime/shared/connector-catalog.mjs +60 -52
  287. package/src/runtime/shared/custom-provider-keys.mjs +20 -0
  288. package/src/runtime/shared/defaults-separation.mjs +1 -4
  289. package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
  290. package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
  291. package/src/runtime/shared/file-has-data.mjs +26 -2
  292. package/src/runtime/shared/file-lock.mjs +13 -15
  293. package/src/runtime/shared/git-launch.d.mts +9 -0
  294. package/src/runtime/shared/git-launch.mjs +213 -0
  295. package/src/runtime/shared/git-runner-worker.mjs +2 -1
  296. package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
  297. package/src/runtime/shared/handoff-artifacts.mjs +18 -8
  298. package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
  299. package/src/runtime/shared/llm/cost.mjs +11 -2
  300. package/src/runtime/shared/llm/http-agent.mjs +313 -29
  301. package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
  302. package/src/runtime/shared/llm/model-catalog.mjs +46 -6
  303. package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
  304. package/src/runtime/shared/llm/system-proxy.mjs +452 -0
  305. package/src/runtime/shared/loopback-listener.mjs +25 -2
  306. package/src/runtime/shared/model-route-chain.d.mts +7 -2
  307. package/src/runtime/shared/model-route-chain.mjs +22 -4
  308. package/src/runtime/shared/open-url.mjs +10 -0
  309. package/src/runtime/shared/provider-accounts.mjs +52 -2
  310. package/src/runtime/shared/session-activity-signal.mjs +14 -0
  311. package/src/runtime/shared/session-scratch.mjs +37 -0
  312. package/src/runtime/shared/staged-install-worker.mjs +5 -0
  313. package/src/runtime/shared/staged-update.mjs +47 -2
  314. package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
  315. package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
  316. package/src/runtime/shared/tool-result-summary.mjs +1 -1
  317. package/src/runtime/shared/tool-surface.mjs +113 -36
  318. package/src/runtime/shared/tool-work-units.mjs +6 -0
  319. package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
  320. package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
  321. package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
  322. package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
  323. package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
  324. package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
  325. package/src/runtime/shared/worktrees/contract.mjs +4 -1
  326. package/src/runtime/shared/worktrees/git.mjs +72 -0
  327. package/src/runtime/shared/worktrees/manager.mjs +285 -168
  328. package/src/runtime/shared/worktrees/test-support.mjs +6 -10
  329. package/src/runtime/tidy/install.mjs +95 -15
  330. package/src/runtime/tidy/languages.mjs +17 -15
  331. package/src/runtime/tidy/process.mjs +7 -4
  332. package/src/runtime/tidy/resolve.mjs +19 -16
  333. package/src/runtime/tidy/runners/biome.mjs +3 -3
  334. package/src/runtime/tidy/tool.mjs +1 -1
  335. package/src/runtime/tidy/worktree.mjs +10 -6
  336. package/src/runtime/visualize-bridge/client.mjs +6 -1
  337. package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
  338. package/src/runtime/web-search/index.mjs +1 -1
  339. package/src/session-runtime/agent-home-delivery.mjs +41 -0
  340. package/src/session-runtime/agent-task-sessions.mjs +458 -312
  341. package/src/session-runtime/agent-tool-routing.mjs +8 -41
  342. package/src/session-runtime/boot/tools.mjs +7 -1
  343. package/src/session-runtime/bot-status.mjs +107 -101
  344. package/src/session-runtime/bot-target.mjs +38 -0
  345. package/src/session-runtime/channel-config-api.mjs +6 -1
  346. package/src/session-runtime/connector-merge-migration.mjs +18 -15
  347. package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
  348. package/src/session-runtime/conversation-import/discovery.mjs +401 -36
  349. package/src/session-runtime/conversation-import/service.mjs +35 -8
  350. package/src/session-runtime/handoff-attachments.mjs +82 -31
  351. package/src/session-runtime/held-requests.mjs +3 -1
  352. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
  353. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
  354. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
  355. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
  356. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
  357. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
  358. package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
  359. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
  360. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
  361. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  362. package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
  363. package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
  364. package/src/session-runtime/mixy-heartbeat.mjs +1 -1
  365. package/src/session-runtime/model-route/set-route.mjs +11 -2
  366. package/src/session-runtime/provider-auth/login.mjs +2 -2
  367. package/src/session-runtime/provider-catalog-cache.mjs +82 -36
  368. package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
  369. package/src/session-runtime/provider-models.mjs +4 -2
  370. package/src/session-runtime/resource-mcp-api.mjs +98 -35
  371. package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
  372. package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
  373. package/src/session-runtime/resource-mcp-servers.mjs +5 -4
  374. package/src/session-runtime/resource-recall-api.mjs +6 -1
  375. package/src/session-runtime/runtime-feature-gates.mjs +5 -1
  376. package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
  377. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
  378. package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
  379. package/src/session-runtime/services/agent-tool/render.mjs +71 -17
  380. package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
  381. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
  382. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
  383. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
  384. package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
  385. package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
  386. package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
  387. package/src/session-runtime/services/daemon-candidate.mjs +4 -1
  388. package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
  389. package/src/session-runtime/services/plugin-admin.mjs +10 -6
  390. package/src/session-runtime/services/provider-admin.mjs +283 -11
  391. package/src/session-runtime/session-turn-api.mjs +2 -0
  392. package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
  393. package/src/session-runtime/settings-system-api.mjs +1 -1
  394. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
  395. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
  396. package/src/session-runtime/setup-tool/executor.mjs +6 -2
  397. package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
  398. package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
  399. package/src/session-runtime/turn/agent-ops.mjs +23 -0
  400. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
  401. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
  402. package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
  403. package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
  404. package/src/session-runtime/workspace/activity-guards.mjs +176 -0
  405. package/src/session-runtime/workspace/session-view.mjs +149 -0
  406. package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
  407. package/src/session-runtime/workspace/transition-runner.mjs +188 -0
  408. package/src/session-runtime/workspace/transitions.mjs +108 -1041
  409. package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
  410. package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
  411. package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
  412. package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
  413. package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
  414. package/src/standalone/daemon-desktop-runtime.mjs +2 -0
  415. package/src/standalone/daemon-session-control.mjs +169 -138
  416. package/src/standalone/daemon.mjs +7 -0
  417. package/src/standalone/desktop-service-registry.mjs +9 -0
  418. package/src/standalone/local-session-runtime.mjs +5 -1
  419. package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
  420. package/src/standalone/session-client.mjs +5 -1
  421. package/src/standalone/session-frame-stream.mjs +83 -11
  422. package/src/standalone/session-protocol.mjs +4 -0
  423. package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
  424. package/src/standalone/session-service/agent-tree.mjs +45 -9
  425. package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
  426. package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
  427. package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
  428. package/src/standalone/session-service/stored-reader.mjs +127 -40
  429. package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
  430. package/src/tui/App.jsx +154 -164
  431. package/src/tui/app/app-view/floating-panel.jsx +10 -4
  432. package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
  433. package/src/tui/app/clipboard.mjs +21 -10
  434. package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
  435. package/src/tui/app/model-picker/route-selection.mjs +5 -6
  436. package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
  437. package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
  438. package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
  439. package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
  440. package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
  441. package/src/tui/app/provider-setup/provider-items.mjs +8 -2
  442. package/src/tui/app/provider-setup-picker.mjs +29 -18
  443. package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
  444. package/src/tui/app/slash-commands.mjs +1 -0
  445. package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
  446. package/src/tui/app/slash-dispatch.mjs +1 -1
  447. package/src/tui/app/use-btw-panel.mjs +29 -0
  448. package/src/tui/app/use-context-panel-refresh.mjs +31 -0
  449. package/src/tui/app/use-model-catalog-cache.mjs +13 -10
  450. package/src/tui/app/use-mouse-input.mjs +11 -0
  451. package/src/tui/app/use-onboarding-start.mjs +8 -3
  452. package/src/tui/app/use-panel-transition.mjs +10 -1
  453. package/src/tui/app/use-pasted-buffers.mjs +28 -20
  454. package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
  455. package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
  456. package/src/tui/app/use-prompt-queue-history.mjs +3 -2
  457. package/src/tui/app/use-selection-focus.mjs +11 -2
  458. package/src/tui/app/use-selection-geometry.mjs +18 -9
  459. package/src/tui/app/use-selection-paint.mjs +4 -4
  460. package/src/tui/app/use-selection-stitch.mjs +3 -3
  461. package/src/tui/app/use-slash-palette.mjs +62 -0
  462. package/src/tui/app/use-terminal-chrome.mjs +2 -2
  463. package/src/tui/app/use-transcript-activity.mjs +47 -32
  464. package/src/tui/app/use-transcript-follow.mjs +12 -4
  465. package/src/tui/app/use-transcript-scroll.mjs +46 -17
  466. package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
  467. package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
  468. package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
  469. package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
  470. package/src/tui/app/use-transcript-window.mjs +21 -11
  471. package/src/tui/app/use-tui-ready.mjs +18 -0
  472. package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
  473. package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
  474. package/src/tui/components/Picker.jsx +27 -3
  475. package/src/tui/components/QuestionPanel.jsx +13 -4
  476. package/src/tui/components/SignInUrl.jsx +68 -0
  477. package/src/tui/components/TextEntryPanel.jsx +76 -46
  478. package/src/tui/components/sign-in-url-layout.mjs +24 -0
  479. package/src/tui/dist/index.mjs +1963 -1361
  480. package/src/tui/session/goal-turn-state.mjs +6 -2
  481. package/src/tui/session/session-api/controls.mjs +4 -0
  482. package/src/tui/session/session-api/extensions.mjs +8 -0
  483. package/src/tui/session/session-api/intake/abort.mjs +2 -1
  484. package/src/tui/session/session-api/intake.mjs +2 -0
  485. package/src/tui/session/session-api/integrations.mjs +2 -2
  486. package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
  487. package/src/tui/session/session-api/settings.mjs +2 -2
  488. package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
  489. package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
  490. package/src/tui/session/transcript-spill.mjs +92 -4
  491. package/src/tui/session/transcript-store.mjs +2 -0
  492. package/src/ui/statusline-agents.mjs +1 -3
  493. package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
@@ -13,7 +13,7 @@
13
13
  * use-transcript-window/visible-items.mjs — on-screen slice, overlay hint placement
14
14
  * use-transcript-window/selection-shift.mjs — selection rect follows geometry/theme
15
15
  */
16
- import { useCallback, useEffect, useLayoutEffect } from 'react';
16
+ import { useCallback, useEffect, useLayoutEffect, useMemo } from 'react';
17
17
  import { harvestMeasuredRows, measureRefFor } from './transcript-measure.mjs';
18
18
  import {
19
19
  clampScrollToOverflow,
@@ -66,7 +66,10 @@ export function useTranscriptWindow({
66
66
  selectionLayoutRef,
67
67
  };
68
68
  const state = useTranscriptInstanceState({ sessionKey, scrollOffset, setScrollOffset, refs });
69
- const transcriptMeasureRef = useCallback((item) => measureRefFor(state.measureStateRef.current, item), []);
69
+ const transcriptMeasureRef = useCallback(
70
+ (item) => measureRefFor(state.measureStateRef.current, item),
71
+ [state.measureStateRef]
72
+ );
70
73
  const { revision, streamingTailItem, transcriptItems, transcriptRowIndex, transcriptWindow } = useTranscriptGeometry(
71
74
  state,
72
75
  {
@@ -102,13 +105,12 @@ export function useTranscriptWindow({
102
105
  transcriptGuardRows,
103
106
  themeEpoch,
104
107
  };
105
- const scrollRefs = {
106
- transcriptAnchorRef,
107
- transcriptAnchorDirtyRef,
108
- scrollTargetRef,
109
- scrollPositionRef,
110
- followingRef,
111
- };
108
+ // Memoized over the App-owned refs (stable identities), so the effects below
109
+ // can depend on the bundle without re-running.
110
+ const scrollRefs = useMemo(
111
+ () => ({ transcriptAnchorRef, transcriptAnchorDirtyRef, scrollTargetRef, scrollPositionRef, followingRef }),
112
+ [transcriptAnchorRef, transcriptAnchorDirtyRef, scrollTargetRef, scrollPositionRef, followingRef]
113
+ );
112
114
  // ── Measured height harvest (every commit, no deps) ─────────────────────
113
115
  useLayoutEffect(() => {
114
116
  harvestMeasuredRows(state.measureStateRef.current, {
@@ -120,6 +122,10 @@ export function useTranscriptWindow({
120
122
  });
121
123
  });
122
124
  // ── Bottom-follow / anchor post-commit sync ─────────────────────────────
125
+ // transcriptItems is read alongside transcriptRowIndex, which is derived
126
+ // from it; the sync keys on the row index so a same-geometry items swap
127
+ // does not re-run it.
128
+ // biome-ignore lint/correctness/useExhaustiveDependencies(transcriptItems): keyed on the derived row index
123
129
  useLayoutEffect(() => {
124
130
  const totalRows = Math.max(0, Number(transcriptWindow.totalRows) || 0);
125
131
  const previousTotalRows = Math.max(0, Number(state.transcriptTotalRowsRef.current) || 0);
@@ -144,10 +150,14 @@ export function useTranscriptWindow({
144
150
  transcriptContentHeight,
145
151
  scrollOffset,
146
152
  stopSmoothScroll,
153
+ scrollRefs,
154
+ state.transcriptTotalRowsRef,
155
+ dragRef,
156
+ setScrollOffset,
147
157
  ]);
148
158
  useLayoutEffect(() => {
149
159
  resetScrollWhenUnanchored(scrollRefs, { scrollOffset, setScrollOffset, stopSmoothScroll });
150
- }, [scrollOffset, stopSmoothScroll]);
160
+ }, [scrollRefs, scrollOffset, setScrollOffset, stopSmoothScroll]);
151
161
  // ── Selection layout shift ──────────────────────────────────────────────
152
162
  useSelectionLayoutShift({
153
163
  transcriptWindow,
@@ -166,7 +176,7 @@ export function useTranscriptWindow({
166
176
  setScrollOffset,
167
177
  stopSmoothScroll,
168
178
  });
169
- }, [transcriptWindow.maxScrollRows, scrollOffset, stopSmoothScroll]);
179
+ }, [scrollRefs, transcriptWindow.maxScrollRows, scrollOffset, setScrollOffset, stopSmoothScroll]);
170
180
 
171
181
  return {
172
182
  transcriptWindow,
@@ -0,0 +1,18 @@
1
+ /*
2
+ * app/use-tui-ready.mjs — post-mount input gate.
3
+ *
4
+ * tuiReady stays false across the first render + commit. Let one event-loop
5
+ * poll pass so Ink processes (and discards, because PromptInput is still
6
+ * disabled) any keystrokes the OS buffered during terminal setup / initial
7
+ * mount. After the tick, enable the input — new keystrokes land normally.
8
+ */
9
+ import { useEffect, useState } from 'react';
10
+
11
+ export function useTuiReady() {
12
+ const [tuiReady, setTuiReady] = useState(false);
13
+ useEffect(() => {
14
+ const timer = setTimeout(() => setTuiReady(true), 0);
15
+ return () => clearTimeout(timer);
16
+ }, []);
17
+ return tuiReady;
18
+ }
@@ -26,6 +26,11 @@ export function useWelcomePromptHint({ store, state, toastErrorSignature }) {
26
26
  setWelcomePromptHintDismissed(true);
27
27
  }, []);
28
28
 
29
+ // The probe re-runs when the workflow id changes; the workflow snapshot it
30
+ // hands to the summary probe is read, not tracked, so an identity-only
31
+ // workflow refresh does not re-probe.
32
+ // biome-ignore lint/correctness/useExhaustiveDependencies(state.workflow): keyed by workflow id
33
+ // biome-ignore lint/correctness/useExhaustiveDependencies(state.workflow?.id): workflow id re-probe key
29
34
  useEffect(() => {
30
35
  let alive = true;
31
36
  const refreshConditionalWelcomeHint = async () => {
@@ -20,10 +20,12 @@ export function useWorkflowTabCycle({
20
20
  // async switch and pushes a toast, producing a rapid bottom-layout repaint
21
21
  // storm that can visually tear the prompt box in Windows Terminal.
22
22
  const workflowTabCycleRef = useRef({ pending: false, lastAt: 0 });
23
+ // The cycle reads only these two state fields.
24
+ const { commandBusy, workflow } = state;
23
25
  return useCallback(() => {
24
26
  if (slashPaletteOpen || toolApproval || picker || settingsPrompt || providerPrompt || contextPanel || usagePanel)
25
27
  return true;
26
- return cycleWorkflow({ store, state, cycleGuard: workflowTabCycleRef.current });
28
+ return cycleWorkflow({ store, state: { commandBusy, workflow }, cycleGuard: workflowTabCycleRef.current });
27
29
  }, [
28
30
  slashPaletteOpen,
29
31
  toolApproval,
@@ -32,8 +34,8 @@ export function useWorkflowTabCycle({
32
34
  providerPrompt,
33
35
  contextPanel,
34
36
  usagePanel,
35
- state.commandBusy,
36
- state.workflow,
37
+ commandBusy,
38
+ workflow,
37
39
  store,
38
40
  ]);
39
41
  }
@@ -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
  }
@@ -69,9 +69,12 @@ export function QuestionPanel({ questions, columns = 80, rows, onSubmit, onDismi
69
69
  if (text) commit({ ...s, buf: appendCapped(s.buf, text) });
70
70
  };
71
71
 
72
- usePaste((text) => {
73
- if (ref.current.typing) typeInto(text);
74
- }, { isActive: isRawModeSupported });
72
+ usePaste(
73
+ (text) => {
74
+ if (ref.current.typing) typeInto(text);
75
+ },
76
+ { isActive: isRawModeSupported }
77
+ );
75
78
 
76
79
  useInput(
77
80
  (input, key) => {
@@ -232,7 +235,13 @@ export function QuestionPanel({ questions, columns = 80, rows, onSubmit, onDismi
232
235
  }
233
236
  if (plan.below > 0) out.push(moreRow('below', `↓ ${plan.below} more`));
234
237
 
235
- const help = questionHelp({ multi, typing: state.typing, last: state.qi >= last, count: n, questionCount: questions.length });
238
+ const help = questionHelp({
239
+ multi,
240
+ typing: state.typing,
241
+ last: state.qi >= last,
242
+ count: n,
243
+ questionCount: questions.length,
244
+ });
236
245
 
237
246
  return (
238
247
  <Box flexDirection="column" flexShrink={0} width="100%">
@@ -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
+ }