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
@@ -24,21 +24,34 @@ import {
24
24
  stampedDerivation,
25
25
  storedSessionCatalogRow,
26
26
  } from './store-summary-catalog.mjs';
27
- import { createStoredTranscriptCache, nextProjectionStamp } from './store-transcript-cache.mjs';
27
+ import {
28
+ createStoredTranscriptCache,
29
+ historyStampOf,
30
+ producedSlice,
31
+ projectionStampEpoch,
32
+ transcriptTextHash,
33
+ } from './store-transcript-cache.mjs';
28
34
  import {
29
35
  forgetStoredTranscriptOffThread,
30
36
  OFFLOAD_MIN_CHARS,
31
37
  projectStoredTranscriptOffThread,
32
38
  storedTranscriptWorkerRunning,
33
39
  } from './store-transcript-worker.mjs';
34
- import { projectStoredTranscript } from './store-transcript-projection.mjs';
40
+ import {
41
+ cursorPageRows,
42
+ heldRowsDigester,
43
+ prepareStoredTranscriptBase,
44
+ projectStoredTranscript,
45
+ storedHistorySlice,
46
+ windowStoredTranscript,
47
+ } from './store-transcript-projection.mjs';
35
48
  import { dataDir } from './store-summary-locations.mjs';
36
49
  import { isStoredSessionId, workspaceSummary } from './store-summary-fields.mjs';
37
50
  import { readArchivedAgentResult } from './store-summary-archived-agent.mjs';
38
51
  import {
52
+ compactionArchivePageFromText,
39
53
  compactionArchivePath,
40
54
  compactionArchiveRange,
41
- readCompactionArchivePage,
42
55
  visitCompactionArchive,
43
56
  } from './compaction-archive.mjs';
44
57
  import { attachmentHistoryRows } from './stored-attachment-history.mjs';
@@ -76,15 +89,55 @@ const storedTranscriptCache = createStoredTranscriptCache();
76
89
  // lookup can neither fill nor evict.
77
90
  const attachmentHistoryCache = createStoredTranscriptCache();
78
91
 
92
+ // The display histories of SMALL sessions (record and archive under
93
+ // OFFLOAD_MIN_CHARS, projected on this thread), kept for slicing within a
94
+ // source-character budget; a larger one never stays on this thread (its
95
+ // history lives in the projection worker, or is projected per read as a
96
+ // bounded window).
97
+ const SMALL_HISTORY_MAX_CHARS = 4 * 1024 * 1024;
98
+ const smallHistories = (() => {
99
+ const entries = new Map();
100
+ let chars = 0;
101
+ const drop = (sessionId) => {
102
+ const entry = entries.get(sessionId);
103
+ if (!entry) return;
104
+ entries.delete(sessionId);
105
+ chars -= entry.chars;
106
+ };
107
+ return {
108
+ get(sessionId, identity) {
109
+ const entry = entries.get(sessionId);
110
+ if (!entry || entry.identity !== identity) return null;
111
+ entries.delete(sessionId);
112
+ entries.set(sessionId, entry);
113
+ return entry.history;
114
+ },
115
+ retain(sessionId, identity, sourceChars, history) {
116
+ drop(sessionId);
117
+ if (sourceChars > SMALL_HISTORY_MAX_CHARS) return;
118
+ entries.set(sessionId, { identity, chars: sourceChars, history });
119
+ chars += sourceChars;
120
+ while (chars > SMALL_HISTORY_MAX_CHARS && entries.size > 1) drop(entries.keys().next().value);
121
+ },
122
+ forget: drop,
123
+ clear() {
124
+ entries.clear();
125
+ chars = 0;
126
+ },
127
+ };
128
+ })();
129
+
79
130
  /** Test seam: forget every cached projection. */
80
131
  export function clearStoredTranscriptCache() {
81
132
  storedTranscriptCache.clear();
133
+ smallHistories.clear();
82
134
  }
83
135
 
84
136
  /** Drop one session's cold projections: it went live, or its last view left. */
85
137
  export function forgetStoredSessionTranscript(sessionId) {
86
138
  const id = String(sessionId || '').trim();
87
139
  storedTranscriptCache.forget(`${id}|`);
140
+ smallHistories.forget(id);
88
141
  if (id) forgetStoredTranscriptOffThread(id);
89
142
  }
90
143
 
@@ -386,10 +439,16 @@ export function storedSessionTranscriptStamp(id) {
386
439
  * itself). The answer is the cache's `project` contract; a worker failure
387
440
  * rejects and the cache runs the in-process pipeline instead. */
388
441
  async function projectStoredTranscriptElsewhere(known, context) {
389
- const { sessionId, recordPath, itemLimit, timing } = context;
442
+ const { sessionId, recordPath, timing, fingerprint, slice } = context;
390
443
  timing.worker = storedTranscriptWorkerRunning(sessionId) ? 'warm' : 'cold';
391
444
  const workerStartedAt = performance.now();
392
- const answer = await projectStoredTranscriptOffThread({ sessionId, recordPath, itemLimit, known });
445
+ const answer = await projectStoredTranscriptOffThread({
446
+ sessionId,
447
+ recordPath,
448
+ known,
449
+ fingerprint,
450
+ slice: { ...slice, epoch: projectionStampEpoch() },
451
+ });
393
452
  timing.workerMs = performance.now() - workerStartedAt;
394
453
  Object.assign(timing, answer.timing);
395
454
  context.readState = answer.state;
@@ -397,15 +456,66 @@ async function projectStoredTranscriptElsewhere(known, context) {
397
456
  if (answer.same) return answer;
398
457
  if (answer.unreadable) return { ...answer, value: null };
399
458
  if (answer.stamp) readCanonicalLifecycle.rememberStrictVerdict(recordPath, answer.stamp, answer.lifecycle);
400
- // Stamps are process-unique per module realm; re-issue in this one.
401
- answer.value.projectionStamp = nextProjectionStamp();
459
+ if (answer.historyBuilt === false) timing.history = 'retained';
402
460
  return answer;
403
461
  }
404
462
 
463
+ /** A projector (projectStoredTranscript's signature) for a historical-position
464
+ * read on this thread (a checkpoint sidecar, or the worker unavailable): the
465
+ * base once, then tail windows doubling from twice the page until one holds
466
+ * the cursor's row with the page beside it, or history ends. Never the whole
467
+ * display history: only as deep as the row itself. */
468
+ const CURSOR_WINDOW_MAX_ITEMS = 8_192;
469
+
470
+ function cursorWindowProjector(cursor, timing) {
471
+ return async (sessionId, doc, options) => {
472
+ const base = await prepareStoredTranscriptBase(sessionId, doc, options);
473
+ const id = cursor.before ?? cursor.after;
474
+ for (
475
+ let itemLimit = Math.max(64, cursor.maxRows * 2);
476
+ ;
477
+ itemLimit = Math.min(itemLimit * 2, CURSOR_WINDOW_MAX_ITEMS)
478
+ ) {
479
+ timing.cursorWindowItems = itemLimit;
480
+ const window = await windowStoredTranscript(sessionId, base, { itemLimit, includeMessages: false });
481
+ const at = window.items.findIndex((item) => item?.id === id);
482
+ if ((at >= 0 && (cursor.before == null || at >= cursor.maxRows)) || !window.transcriptHasOlder) return window;
483
+ // Never deeper on this thread: a row past the bound answers `reset`
484
+ // (the slice finds no such row), one at its edge a shorter page.
485
+ if (itemLimit >= CURSOR_WINDOW_MAX_ITEMS) return at >= 0 ? window : { ...window, items: [] };
486
+ }
487
+ };
488
+ }
489
+
490
+ /** The slice `request` names of `history` (the display history, or a window
491
+ * of it), stamped `<history stamp>/<slice>`. */
492
+ async function sliceOf(history, request, historyStamp) {
493
+ const proven = Boolean(request.held) && request.baseHistory === historyStamp;
494
+ const value = storedHistorySlice(
495
+ history,
496
+ { ...request, proven },
497
+ { digestOf: request.held && !proven ? await heldRowsDigester() : null }
498
+ );
499
+ const { windowStamp } = value;
500
+ delete value.windowStamp;
501
+ value.projectionStamp = `${historyStamp}/${windowStamp}`;
502
+ return value;
503
+ }
504
+
405
505
  /** Projects the strictly parsed record `text` (read at full stamp `stamp`, or
406
506
  * null when not provably stable) into the cached transcript value. */
407
507
  async function produceStoredTranscript(text, stamp, context) {
408
- const { sessionId, recordPath, itemLimit, includeMessages, mode, checkpointAbsent, timing } = context;
508
+ const { sessionId, recordPath, itemLimit, slice, fingerprint, includeMessages, mode, checkpointAbsent, timing } =
509
+ context;
510
+ const historyStamp =
511
+ mode === 'items' ? historyStampOf(sessionId, transcriptTextHash(text), text.length, fingerprint) : null;
512
+ // A small session's retained history answers every other slice of it.
513
+ const keepHistory = mode === 'items' && checkpointAbsent && context.sourceChars < OFFLOAD_MIN_CHARS;
514
+ const retained = keepHistory ? smallHistories.get(sessionId, historyStamp) : null;
515
+ if (retained) {
516
+ timing.history = 'retained';
517
+ return producedSlice(await sliceOf(retained, slice, historyStamp), { historyBuilt: false });
518
+ }
409
519
  const parseStartedAt = performance.now();
410
520
  const record = readTopLevelLifecycleRecord(text);
411
521
  timing.parseMs = performance.now() - parseStartedAt;
@@ -431,22 +541,29 @@ async function produceStoredTranscript(text, stamp, context) {
431
541
  // load the hand-off serves, and projects the load cache's session
432
542
  // exactly as before; only that projection is detached.
433
543
  const projectStartedAt = performance.now();
434
- const value = await projectStoredTranscript(
435
- sessionId,
436
- handedOver && checkpointAbsent ? JSON.parse(text) : record.doc,
437
- {
438
- itemLimit,
439
- includeMessages,
440
- checkpointAbsent,
441
- }
442
- );
544
+ const project = keepHistory || !slice.cursor ? projectStoredTranscript : cursorWindowProjector(slice.cursor, timing);
545
+ const projected = await project(sessionId, handedOver && checkpointAbsent ? JSON.parse(text) : record.doc, {
546
+ itemLimit,
547
+ // Only a small session's whole display history is built (and kept) on
548
+ // this thread; any other item read projects just its bounded window
549
+ // (a tail of that history) and slices it; a historical-position read
550
+ // projects the tail window reaching its row (cursorWindowProjector).
551
+ history: keepHistory,
552
+ includeMessages,
553
+ checkpointAbsent,
554
+ });
443
555
  timing.projectMs = performance.now() - projectStartedAt;
444
- if (!handedOver || checkpointAbsent || !value || mode !== 'items') return value;
445
- try {
446
- return structuredClone(value);
447
- } catch {
448
- return value;
556
+ if (mode !== 'items' || !projected) return projected;
557
+ if (keepHistory) smallHistories.retain(sessionId, historyStamp, context.sourceChars, projected);
558
+ let value = await sliceOf(projected, slice, historyStamp);
559
+ if (handedOver && !checkpointAbsent) {
560
+ try {
561
+ value = structuredClone(value);
562
+ } catch {
563
+ // Served as projected.
564
+ }
449
565
  }
566
+ return producedSlice(value);
450
567
  }
451
568
 
452
569
  /** The rows of one session's whole stored conversation that name attachments
@@ -492,6 +609,37 @@ async function readStoredAttachmentHistory(sessionId, recordPath, archivePath) {
492
609
  return value ?? null;
493
610
  }
494
611
 
612
+ /** One page of a session's compaction archive (`{ after, before, skip,
613
+ * limit }`, as readCompactionArchivePage pages it), cut from its visible rows
614
+ * built once per archive content in the transcript cache: paging a live
615
+ * session through a large segment slices instead of re-parsing it; `paging`
616
+ * keeps it cached under pressure (the cache's `pin`). */
617
+ async function readCachedCompactionArchivePage(sessionId, archivePath, range, paging) {
618
+ const after = Math.max(0, Math.floor(Number(range.after) || 0));
619
+ const before = Number(range.before);
620
+ const visible = { after, before: Number.isFinite(before) ? before : Number.POSITIVE_INFINITY };
621
+ const archive = probePath(archivePath);
622
+ if (archive.state !== PROBE_PRESENT) return { items: [], hasOlder: false };
623
+ const { value } = await storedTranscriptCache.read({
624
+ key: `${sessionId}|archive|${visible.after}:${visible.before}`,
625
+ group: `${sessionId}|archive`,
626
+ fingerprint: '',
627
+ fileStat: archive,
628
+ pin: paging,
629
+ loadText: () => {
630
+ const body = readTextFile(archivePath);
631
+ return body.state === PROBE_PRESENT ? body.text : null;
632
+ },
633
+ produce: async (text) => ({
634
+ items: (await compactionArchivePageFromText(text, { ...visible, limit: Number.POSITIVE_INFINITY })).items,
635
+ }),
636
+ });
637
+ const items = Array.isArray(value?.items) ? value.items : [];
638
+ const end = Math.max(0, items.length - Math.max(0, Math.floor(Number(range.skip) || 0)));
639
+ const start = Math.max(0, end - Math.max(0, Math.floor(Number(range.limit) || 0)));
640
+ return { items: items.slice(start, end), hasOlder: start > 0 };
641
+ }
642
+
495
643
  /** Read exactly one persisted session for a visible desktop pane. This never
496
644
  * enumerates siblings. Normal reads stay independent of runtime ownership;
497
645
  * interrupted turns conditionally use the same durable reconnect recovery as
@@ -508,7 +656,7 @@ export async function readStoredSessionTranscript(id, options = {}) {
508
656
  // One page of the display-only compaction archive (the live head loader
509
657
  // pages it once a runtime's in-memory rows are exhausted).
510
658
  if (options.compactionArchive && typeof options.compactionArchive === 'object') {
511
- return readCompactionArchivePage(join(dataDir(), 'sessions'), sessionId, options.compactionArchive);
659
+ return readCachedCompactionArchivePage(sessionId, archivePath, options.compactionArchive, options.paging === true);
512
660
  }
513
661
  // The checkpoint sidecar shapes the projection as much as the record does,
514
662
  // so its identity joins the cache fingerprint. Only a PROVABLY absent
@@ -524,6 +672,51 @@ export async function readStoredSessionTranscript(id, options = {}) {
524
672
  const archive = probePath(archivePath);
525
673
  const requestedLimit = Number(options.transcriptItemLimit);
526
674
  const itemLimit = Number.isFinite(requestedLimit) && requestedLimit > 0 ? requestedLimit : Number.POSITIVE_INFINITY;
675
+ // `transcriptSkip`: the window's newest rows to leave out (a range read
676
+ // slices only the rows above them, with `skippedFirstId`).
677
+ const requestedSkip = Number(options.transcriptSkip);
678
+ const skip =
679
+ Number.isFinite(itemLimit) && Number.isSafeInteger(requestedSkip) && requestedSkip > 0
680
+ ? Math.min(requestedSkip, itemLimit)
681
+ : 0;
682
+ // `transcriptHeld` (`{ firstId, count, digest }`): the newest rows a paged
683
+ // caller holds, proven by `transcriptBaseHistory` (the history stamp they
684
+ // were served under) or their digest, where the history is: only the page
685
+ // above them (`transcriptPage`: `{ maxRows, byteBudget }`) is sliced,
686
+ // whatever their count. Unproven, a tail of at most `maxRows` rows.
687
+ const heldOption = options.transcriptHeld;
688
+ const held =
689
+ Number.isFinite(itemLimit) && heldOption && Number.isSafeInteger(heldOption.count) && heldOption.count > 0
690
+ ? { firstId: heldOption.firstId, count: heldOption.count, digest: String(heldOption.digest ?? '') }
691
+ : null;
692
+ const page = options.transcriptPage || {};
693
+ // `transcriptCursor` (`{ before | after, maxRows, byteBudget }`): a
694
+ // historical-position read — the rows next to one row, by its id.
695
+ const cursorOption = options.transcriptCursor;
696
+ const cursor =
697
+ cursorOption && (cursorOption.before != null || cursorOption.after != null)
698
+ ? {
699
+ ...(cursorOption.before != null ? { before: cursorOption.before } : { after: cursorOption.after }),
700
+ maxRows: cursorPageRows(cursorOption.maxRows),
701
+ byteBudget: Number(cursorOption.byteBudget) > 0 ? Number(cursorOption.byteBudget) : null,
702
+ }
703
+ : null;
704
+ const slice = cursor
705
+ ? { cursor }
706
+ : held
707
+ ? {
708
+ limit: itemLimit,
709
+ held,
710
+ baseHistory: typeof options.transcriptBaseHistory === 'string' ? options.transcriptBaseHistory : null,
711
+ maxRows: Math.max(1, Math.floor(Number(page.maxRows) || itemLimit)),
712
+ byteBudget: Number(page.byteBudget) > 0 ? Number(page.byteBudget) : null,
713
+ }
714
+ : { limit: itemLimit, skip };
715
+ const sliceKey = cursor
716
+ ? `cursor:${cursor.before ?? ''}:${cursor.after ?? ''}:${cursor.maxRows}:${cursor.byteBudget}`
717
+ : held
718
+ ? `held:${held.count}:${held.firstId}:${held.digest}:${slice.baseHistory}:${slice.maxRows}:${slice.byteBudget}`
719
+ : skip;
527
720
  // Full stamp the loaded text provably came from (unchanged around the
528
721
  // read), or null. Only such a parse may serve other readers.
529
722
  let readStamp = null;
@@ -533,11 +726,27 @@ export async function readStoredSessionTranscript(id, options = {}) {
533
726
  const mode = includeMessages ? 'messages' : 'items';
534
727
  const checkpointAbsent = checkpoint.state === PROBE_ABSENT;
535
728
  // Large, checkpoint-free item projections run off the daemon event loop.
536
- const offloadable = !includeMessages && checkpointAbsent && recordStat.size >= OFFLOAD_MIN_CHARS;
729
+ // A large compaction archive counts: the display history holds its rows.
730
+ const sourceChars = recordStat.size + (archive.state === PROBE_PRESENT ? Number(archive.size) || 0 : 0);
731
+ const offloadable = !includeMessages && checkpointAbsent && sourceChars >= OFFLOAD_MIN_CHARS;
732
+ const fingerprint = [
733
+ checkpoint.state,
734
+ checkpoint.mtimeMs,
735
+ checkpoint.ctimeMs,
736
+ checkpoint.size,
737
+ checkpoint.ino,
738
+ checkpoint.dev,
739
+ archive.state,
740
+ archive.mtimeMs,
741
+ archive.size,
742
+ ].join(':');
537
743
  const produceContext = {
538
744
  sessionId,
539
745
  recordPath,
540
746
  itemLimit,
747
+ slice,
748
+ sourceChars,
749
+ fingerprint,
541
750
  includeMessages,
542
751
  mode,
543
752
  checkpointAbsent,
@@ -545,21 +754,16 @@ export async function readStoredSessionTranscript(id, options = {}) {
545
754
  // How the record read went (the worker's read or loadText below).
546
755
  readState: PROBE_PRESENT,
547
756
  };
548
- const { value, hit, read } = await storedTranscriptCache.read({
549
- key: `${sessionId}|${itemLimit}|${mode}`,
757
+ const { value, hit, read, built } = await storedTranscriptCache.read({
758
+ // One slice (window or page) per request; the group keeps one per
759
+ // session: the display history it is cut from stays with the thread
760
+ // that built it.
761
+ key: `${sessionId}|${itemLimit}|${sliceKey}|${mode}`,
550
762
  // Growing history windows of one session replace each other.
551
763
  group: `${sessionId}|${mode}`,
552
- fingerprint: [
553
- checkpoint.state,
554
- checkpoint.mtimeMs,
555
- checkpoint.ctimeMs,
556
- checkpoint.size,
557
- checkpoint.ino,
558
- checkpoint.dev,
559
- archive.state,
560
- archive.mtimeMs,
561
- archive.size,
562
- ].join(':'),
764
+ // A page read keeps its slice cached under pressure.
765
+ pin: options.paging === true,
766
+ fingerprint,
563
767
  fileStat: recordStat,
564
768
  project: offloadable ? (known) => projectStoredTranscriptElsewhere(known, produceContext) : null,
565
769
  loadText: async () => {
@@ -589,7 +793,8 @@ export async function readStoredSessionTranscript(id, options = {}) {
589
793
  if (typeof options.trace === 'function') {
590
794
  options.trace({
591
795
  sessionId,
592
- hit,
796
+ // A slice of a history already built counts as a hit: nothing was projected.
797
+ hit: hit || built === false,
593
798
  read,
594
799
  ms: performance.now() - startedAt,
595
800
  chars: recordStat.size,