mixdog 1.1.2 → 1.2.1

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 (424) hide show
  1. package/README.md +8 -5
  2. package/package.json +2 -1
  3. package/scripts/lib/run-node-tests.mjs +9 -0
  4. package/scripts/prune-desktop-runtime.mjs +3 -0
  5. package/scripts/test-direct.mjs +4 -2
  6. package/src/defaults/shipped-history.json +10 -0
  7. package/src/defaults/skills/pptx/SKILL.md +6 -6
  8. package/src/defaults/skills/pptx/references/review.md +6 -4
  9. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  10. package/src/defaults/skills/setup/references/actions.md +18 -5
  11. package/src/defaults/skills/visualize/SKILL.md +160 -0
  12. package/src/defaults/skills/visualize/references/craft.md +88 -0
  13. package/src/headless-command.mjs +56 -3
  14. package/src/headless-exec.mjs +17 -1
  15. package/src/help.mjs +2 -0
  16. package/src/rules/shared/60-verification.md +3 -1
  17. package/src/rules/shared/70-delivery.md +4 -2
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
  21. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  22. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
  24. package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +19 -5
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +133 -15
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +55 -8
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +86 -8
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +474 -164
  33. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  34. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  35. package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
  36. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
  37. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  38. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
  40. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -12
  41. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
  42. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  43. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  45. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  50. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +21 -6
  51. package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
  52. package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
  53. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  54. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  55. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  56. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
  57. package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
  58. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
  59. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
  60. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  61. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +82 -0
  62. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +556 -0
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
  64. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
  65. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
  66. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +15 -0
  67. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  68. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
  72. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +15 -4
  73. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
  77. package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -7
  78. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
  79. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
  80. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -11
  81. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  82. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  83. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +278 -84
  85. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  86. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  87. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  88. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -3
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
  90. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
  91. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
  92. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  93. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
  94. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  95. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  96. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
  97. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +24 -13
  98. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
  99. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
  100. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
  101. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  102. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  103. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  104. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  105. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  106. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  107. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  108. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  109. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
  111. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
  112. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
  113. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
  114. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +5 -3
  115. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -4
  116. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +21 -10
  117. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  118. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
  119. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
  120. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -3
  121. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +22 -12
  122. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
  123. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +9 -3
  124. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
  125. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
  126. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
  127. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
  128. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
  129. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
  130. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
  131. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
  132. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
  133. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  136. package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
  137. package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
  138. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +33 -22
  139. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  140. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
  141. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  142. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
  143. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
  144. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
  145. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +36 -0
  146. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +23 -12
  147. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  148. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +202 -374
  149. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
  150. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  151. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +48 -9
  153. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +161 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  155. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  156. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
  157. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
  158. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
  159. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  160. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  161. package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
  162. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +203 -33
  163. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
  164. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  165. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
  166. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
  167. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -68
  168. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
  169. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +20 -3
  170. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
  171. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
  172. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
  173. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
  174. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
  175. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
  176. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  177. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  179. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
  180. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
  181. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  182. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  183. package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
  184. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  185. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  186. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  187. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  188. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  189. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  190. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
  191. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
  192. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  193. package/src/runtime/attachments/store.d.mts +3 -0
  194. package/src/runtime/attachments/store.mjs +38 -0
  195. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  196. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  197. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  198. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  199. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  200. package/src/runtime/memory/lib/memory.mjs +1 -1
  201. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  202. package/src/runtime/shared/atomic-file.mjs +33 -6
  203. package/src/runtime/shared/best-effort-stderr.mjs +8 -0
  204. package/src/runtime/shared/code-graph-state.mjs +12 -0
  205. package/src/runtime/shared/defaults-separation.mjs +2 -0
  206. package/src/runtime/shared/extension-scopes.mjs +5 -3
  207. package/src/runtime/shared/file-lock.mjs +37 -11
  208. package/src/runtime/shared/git-runner-worker.mjs +3 -2
  209. package/src/runtime/shared/git-runner.mjs +4 -3
  210. package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
  211. package/src/runtime/shared/llm/default-context-window.mjs +6 -0
  212. package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
  213. package/src/runtime/shared/llm/model-catalog.mjs +240 -130
  214. package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
  215. package/src/runtime/shared/llm/provider-catalog-registry.mjs +162 -0
  216. package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
  217. package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
  218. package/src/runtime/shared/model-proxy-mode.mjs +19 -0
  219. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  220. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  221. package/src/runtime/shared/pristine-execution.mjs +28 -4
  222. package/src/runtime/shared/provider-accounts.mjs +125 -21
  223. package/src/runtime/shared/provider-api-key.mjs +33 -1
  224. package/src/runtime/shared/schedule-model-ref.mjs +11 -2
  225. package/src/runtime/shared/session-usage-totals.mjs +19 -0
  226. package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
  227. package/src/runtime/shared/shell-display.mjs +9 -3
  228. package/src/runtime/shared/singleton-owner.mjs +36 -6
  229. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  230. package/src/runtime/shared/skill-mentions.mjs +133 -0
  231. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  232. package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
  233. package/src/runtime/shared/tool-primitives.mjs +35 -2
  234. package/src/runtime/shared/tool-surface.mjs +7 -0
  235. package/src/runtime/shared/tool-work-units.mjs +14 -0
  236. package/src/runtime/shared/transcript-metadata.mjs +17 -1
  237. package/src/runtime/shared/turn-changes.mjs +791 -0
  238. package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
  239. package/src/runtime/shared/turn-snapshot.mjs +690 -81
  240. package/src/runtime/shared/turn-worktree-snapshot.mjs +185 -15
  241. package/src/runtime/shared/worker-requests.mjs +15 -2
  242. package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
  243. package/src/runtime/shared/worktrees/contract.mjs +551 -0
  244. package/src/runtime/shared/worktrees/disk.mjs +57 -0
  245. package/src/runtime/shared/worktrees/git.mjs +247 -0
  246. package/src/runtime/shared/worktrees/include.mjs +480 -0
  247. package/src/runtime/shared/worktrees/lock.mjs +46 -0
  248. package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
  249. package/src/runtime/shared/worktrees/manager.mjs +1215 -0
  250. package/src/runtime/shared/worktrees/merge.mjs +182 -0
  251. package/src/runtime/shared/worktrees/owner.mjs +46 -0
  252. package/src/runtime/shared/worktrees/paths.mjs +62 -0
  253. package/src/runtime/shared/worktrees/registry.mjs +110 -0
  254. package/src/runtime/shared/worktrees/settings.mjs +84 -0
  255. package/src/runtime/shared/worktrees/slug.mjs +62 -0
  256. package/src/runtime/shared/worktrees/test-support.mjs +96 -0
  257. package/src/runtime/visualize-bridge/client.mjs +181 -0
  258. package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
  259. package/src/session-runtime/automation-agents.mjs +8 -2
  260. package/src/session-runtime/boot/apis.mjs +90 -0
  261. package/src/session-runtime/boot/config.mjs +7 -2
  262. package/src/session-runtime/boot/facade.mjs +21 -0
  263. package/src/session-runtime/boot/infrastructure.mjs +30 -18
  264. package/src/session-runtime/boot/session.mjs +1 -0
  265. package/src/session-runtime/boot/tools.mjs +4 -0
  266. package/src/session-runtime/config-lifecycle.mjs +10 -1
  267. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  268. package/src/session-runtime/conversation-import/service.mjs +369 -0
  269. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +21 -6
  270. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  271. package/src/session-runtime/global-extensions.mjs +2 -2
  272. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
  273. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
  274. package/src/session-runtime/internal-tool-executor.mjs +9 -1
  275. package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
  276. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
  277. package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
  278. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
  279. package/src/session-runtime/mcp-glue/connect.mjs +68 -16
  280. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  281. package/src/session-runtime/mcp-glue/server-catalog.mjs +122 -33
  282. package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
  283. package/src/session-runtime/mcp-glue.mjs +22 -2
  284. package/src/session-runtime/model-route/route-persist.mjs +3 -0
  285. package/src/session-runtime/model-route/set-route.mjs +15 -2
  286. package/src/session-runtime/new-session-config.mjs +3 -2
  287. package/src/session-runtime/notification-bus.mjs +18 -3
  288. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  289. package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
  290. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  291. package/src/session-runtime/provider-readiness.mjs +16 -10
  292. package/src/session-runtime/resource-extension-sync.mjs +45 -7
  293. package/src/session-runtime/resource-mcp-api.mjs +121 -84
  294. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  295. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  296. package/src/session-runtime/resource-skills-api.mjs +23 -2
  297. package/src/session-runtime/route-resolution.mjs +10 -1
  298. package/src/session-runtime/route-state.mjs +16 -2
  299. package/src/session-runtime/runtime-core.mjs +5 -0
  300. package/src/session-runtime/runtime-facade.mjs +8 -0
  301. package/src/session-runtime/runtime-review-api.mjs +9 -0
  302. package/src/session-runtime/schedule-session-run.mjs +1 -1
  303. package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
  304. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
  305. package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
  306. package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
  307. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
  308. package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
  310. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
  311. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  312. package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
  313. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
  314. package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
  315. package/src/session-runtime/services/agent-tool.mjs +1 -0
  316. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  317. package/src/session-runtime/services/daemon-candidate.mjs +3 -2
  318. package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
  319. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  320. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  321. package/src/session-runtime/services/provider-admin.mjs +64 -18
  322. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  323. package/src/session-runtime/session-create/session-options.mjs +10 -1
  324. package/src/session-runtime/session-turn-api.mjs +1 -0
  325. package/src/session-runtime/settings-api.mjs +4 -2
  326. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
  327. package/src/session-runtime/settings-worktree-api.mjs +17 -0
  328. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  329. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  330. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -1
  331. package/src/session-runtime/setup-tool/tool-defs.mjs +38 -4
  332. package/src/session-runtime/skills-api.mjs +7 -3
  333. package/src/session-runtime/turn/agent-ops.mjs +12 -1
  334. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +14 -3
  335. package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
  336. package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
  337. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
  338. package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
  339. package/src/session-runtime/turn/turn-run.mjs +6 -7
  340. package/src/session-runtime/webhook-session-run.mjs +16 -4
  341. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
  342. package/src/session-runtime/workspace/admission-gate.mjs +197 -0
  343. package/src/session-runtime/workspace/project-branches.mjs +136 -0
  344. package/src/session-runtime/workspace/transition-steps.mjs +364 -0
  345. package/src/session-runtime/workspace/transitions.mjs +651 -0
  346. package/src/session-runtime/workspace/workspace-state.mjs +112 -0
  347. package/src/skill-script-entry.mjs +36 -0
  348. package/src/standalone/channel-transport/http-routes.mjs +17 -0
  349. package/src/standalone/channel-transport.mjs +13 -1
  350. package/src/standalone/daemon-desktop-runtime.mjs +1 -0
  351. package/src/standalone/daemon-owner.mjs +372 -0
  352. package/src/standalone/daemon-stored-session-views.mjs +15 -4
  353. package/src/standalone/daemon.mjs +179 -8
  354. package/src/standalone/desktop-service-registry.mjs +20 -0
  355. package/src/standalone/local-session-runtime.mjs +11 -0
  356. package/src/standalone/session-client/attachment-calls.mjs +3 -1
  357. package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
  358. package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
  359. package/src/standalone/session-client.mjs +104 -13
  360. package/src/standalone/session-protocol.mjs +21 -0
  361. package/src/standalone/session-proxy.mjs +3 -0
  362. package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
  363. package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
  364. package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
  365. package/src/standalone/session-service/projection/revisions.mjs +2 -0
  366. package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
  367. package/src/standalone/session-service/projection/workspace.mjs +14 -0
  368. package/src/standalone/session-service/session-calls/session-action.mjs +17 -4
  369. package/src/standalone/session-transport/call-route.mjs +13 -0
  370. package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
  371. package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
  372. package/src/standalone/session-transport/client-registry.mjs +20 -3
  373. package/src/standalone/session-transport/routes.mjs +79 -2
  374. package/src/standalone/session-transport/stack.mjs +2 -0
  375. package/src/standalone/session-transport.mjs +24 -1
  376. package/src/tui/App.jsx +9 -1
  377. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  378. package/src/tui/app/app-view.jsx +6 -0
  379. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  380. package/src/tui/app/message-selector.mjs +2 -1
  381. package/src/tui/app/model-options.mjs +37 -5
  382. package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
  383. package/src/tui/app/model-picker.mjs +4 -2
  384. package/src/tui/app/skill-mention-palette.mjs +88 -0
  385. package/src/tui/app/slash-palette.mjs +23 -7
  386. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  387. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  388. package/src/tui/app/use-prompt-state.mjs +5 -0
  389. package/src/tui/components/Message.jsx +22 -1
  390. package/src/tui/components/PromptInput.jsx +21 -3
  391. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  392. package/src/tui/components/TranscriptItem.jsx +9 -1
  393. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  394. package/src/tui/components/user-message-skills.mjs +38 -0
  395. package/src/tui/dist/index.mjs +839 -207
  396. package/src/tui/index.jsx +10 -2
  397. package/src/tui/session/compaction-view.mjs +147 -0
  398. package/src/tui/session/context-state.mjs +6 -0
  399. package/src/tui/session/initial-state.mjs +3 -0
  400. package/src/tui/session/queue-helpers.mjs +7 -2
  401. package/src/tui/session/quota-resume.mjs +2 -1
  402. package/src/tui/session/session-api/commands.mjs +10 -2
  403. package/src/tui/session/session-api/controls.mjs +4 -0
  404. package/src/tui/session/session-api/extensions.mjs +4 -2
  405. package/src/tui/session/session-api/intake/rewind.mjs +2 -1
  406. package/src/tui/session/session-api/integrations.mjs +17 -0
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
  408. package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
  409. package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
  410. package/src/tui/session/session-api/routes.mjs +10 -1
  411. package/src/tui/session/session-api/settings.mjs +9 -0
  412. package/src/tui/session/session-api/worktree.mjs +60 -0
  413. package/src/tui/session/session-api.mjs +2 -0
  414. package/src/tui/session/session-flow/auto-clear.mjs +31 -12
  415. package/src/tui/session/session-flow/drain.mjs +27 -3
  416. package/src/tui/session/session-flow/session-reset.mjs +4 -3
  417. package/src/tui/session/session-flow.mjs +2 -0
  418. package/src/tui/session/transcript-intake.mjs +14 -5
  419. package/src/tui/session/tui-steering-persist.mjs +25 -9
  420. package/src/tui/session/turn-stream.mjs +32 -4
  421. package/src/tui/session/turn-tool-cards.mjs +10 -2
  422. package/src/tui/session/turn.mjs +56 -10
  423. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  424. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
@@ -23,6 +23,7 @@ export function createSessionFlow(bag) {
23
23
  steering,
24
24
  submissions,
25
25
  flushDeferredClearedSessionUi: autoClear.flushDeferredClearedSessionUi,
26
+ autoClearBeforeWake: autoClear.autoClearBeforeWake,
26
27
  });
27
28
 
28
29
  return {
@@ -41,6 +42,7 @@ export function createSessionFlow(bag) {
41
42
  drainPendingSteering: steering.drainPendingSteering,
42
43
  restoreLeadSteeringFromDisk: steering.restoreLeadSteeringFromDisk,
43
44
  autoClearBeforeSubmit: autoClear.autoClearBeforeSubmit,
45
+ autoClearBeforeWake: autoClear.autoClearBeforeWake,
44
46
  performAutoClear: autoClear.performAutoClear,
45
47
  restoreQueued: queue.restoreQueued,
46
48
  prioritizeQueued: queue.prioritizeQueued,
@@ -11,6 +11,7 @@ import {
11
11
  } from '../../runtime/shared/tool-execution-contract.mjs';
12
12
  import { isLateToolAnnouncement } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
13
13
  import { appendPromptHistory } from '../prompt-history-store.mjs';
14
+ import { newTranscriptMessageId } from '../../runtime/shared/transcript-metadata.mjs';
14
15
  import {
15
16
  buildExecutionResponseToolItem,
16
17
  completionCardFromExecution,
@@ -21,7 +22,7 @@ import { appendAgentResponseTail } from './agent-response-tail.mjs';
21
22
  import { nextId } from './transcript-spill.mjs';
22
23
 
23
24
  export function createTranscriptIntake({ getState, flags, pushItem, patchItem, transcriptRouteMetadata }) {
24
- const upsertSyntheticToolItem = (text, id = nextId(), parsed = null) => {
25
+ const upsertSyntheticToolItem = (text, id = nextId(), parsed = null, messageId = '') => {
25
26
  const synthetic = parsed || parseSyntheticAgentMessage(text);
26
27
  if (!synthetic) return false;
27
28
  const label = synthetic.label || 'notification';
@@ -56,6 +57,7 @@ export function createTranscriptIntake({ getState, flags, pushItem, patchItem, t
56
57
  pushItem({
57
58
  kind: 'tool',
58
59
  id,
60
+ ...(messageId ? { messageId } : {}),
59
61
  name: synthetic.name || 'agent',
60
62
  args,
61
63
  result: synthetic.result,
@@ -75,11 +77,11 @@ export function createTranscriptIntake({ getState, flags, pushItem, patchItem, t
75
77
  // the text parser cannot read still shows up instead of vanishing.
76
78
  if (origin === 'injected' && (extra?.mode === 'task-notification' || extra?.execution)) {
77
79
  const card = completionCardFromExecution(extra?.execution, text);
78
- if (card && upsertSyntheticToolItem(text, id, card)) return;
80
+ if (card && upsertSyntheticToolItem(text, id, card, extra?.messageId)) return;
79
81
  }
80
82
  if (origin === 'injected') {
81
83
  const completion = parseModelVisibleCompletionWrapper(text);
82
- if (completion && upsertSyntheticToolItem(text, id, completion)) return;
84
+ if (completion && upsertSyntheticToolItem(text, id, completion, extra?.messageId)) return;
83
85
  }
84
86
  // The lenient shape-only wrapper check is display-suppression only and
85
87
  // must never hide a real, directly-typed/pasted user prompt just because
@@ -95,13 +97,20 @@ export function createTranscriptIntake({ getState, flags, pushItem, patchItem, t
95
97
  // keep it in model context, but render NOTHING user-facing — not even the
96
98
  // collapsed one-line notice (user request: hide late-tool notices entirely).
97
99
  if (isLateToolAnnouncement(text)) return;
98
- if (upsertSyntheticToolItem(text, id)) return;
100
+ if (upsertSyntheticToolItem(text, id, null, extra?.messageId)) return;
99
101
  // Genuine, directly-typed/pasted user submissions only (never injected or
100
102
  // synthetic paths, which returned above): persist to the cwd-scoped store so
101
103
  // up-arrow history survives across sessions. Runs before pushItem so the
102
104
  // merge in pushItem's user branch (loadPromptHistory) already sees it.
103
105
  if (origin === 'user') appendPromptHistory(getState().cwd, text);
104
- const transcriptMeta = transcriptRouteMetadata();
106
+ // The row carries its message's stable id: the runtime's (a steered
107
+ // message reports it) or, for a typed prompt, a new one that goes with
108
+ // the prompt into the model transcript. An injected row with no message
109
+ // id of its own carries none.
110
+ let messageId = '';
111
+ if (typeof extra?.messageId === 'string' && extra.messageId) messageId = extra.messageId;
112
+ else if (origin === 'user') messageId = newTranscriptMessageId();
113
+ const transcriptMeta = { ...transcriptRouteMetadata(), ...(messageId ? { messageId } : {}) };
105
114
  if (origin === 'user') flags.pendingTranscriptMeta = transcriptMeta;
106
115
  pushItem({
107
116
  kind: 'user',
@@ -15,11 +15,19 @@ const STALE_STEERING_RESTORE_TTL_MS = 30 * 60 * 1000;
15
15
  // Cross-process mutual exclusion still comes from the shared lock protocol;
16
16
  // this chain only orders same-process operations that were previously
17
17
  // naturally ordered by the synchronous call site.
18
- let _persistChain = Promise.resolve();
19
- function _serialize(task) {
20
- const run = _persistChain.then(task, task);
18
+ // One chain per session key so a slow write for one session never delays
19
+ // another; an entry is removed once its chain is idle.
20
+ const _persistChains = new Map();
21
+ function _serialize(key, task) {
22
+ const prev = _persistChains.get(key) || Promise.resolve();
23
+ const run = prev.then(task, task);
21
24
  // Never let a rejection poison the chain; each op logs its own error.
22
- _persistChain = run.catch(() => {});
25
+ const tail = run
26
+ .catch(() => {})
27
+ .then(() => {
28
+ if (_persistChains.get(key) === tail) _persistChains.delete(key);
29
+ });
30
+ _persistChains.set(key, tail);
23
31
  return run;
24
32
  }
25
33
 
@@ -159,7 +167,7 @@ export function appendTuiSteeringPersist(leadSessionId, entry) {
159
167
  ...(submissionId ? { submissionId } : {}),
160
168
  ...(Number.isFinite(submittedAt) && submittedAt > 0 ? { submittedAt } : {}),
161
169
  };
162
- return _serialize(async () => {
170
+ return _serialize(key, async () => {
163
171
  try {
164
172
  await updatePendingShard(key, (raw) => {
165
173
  const next = normalizePendingStore(raw);
@@ -184,7 +192,7 @@ export function dropTuiSteeringPersist(leadSessionId, entries) {
184
192
  if (!key) return Promise.resolve();
185
193
  const batch = Array.isArray(entries) ? entries : [];
186
194
  if (batch.length === 0) return Promise.resolve();
187
- return _serialize(async () => {
195
+ return _serialize(key, async () => {
188
196
  try {
189
197
  await updatePendingShard(key, (raw) => {
190
198
  const next = normalizePendingStore(raw);
@@ -207,8 +215,16 @@ export function dropTuiSteeringPersist(leadSessionId, entries) {
207
215
  });
208
216
  }
209
217
 
210
- export function flushTuiSteeringPersist() {
211
- return _persistChain.catch(() => {});
218
+ export async function flushTuiSteeringPersist() {
219
+ // Loop: chains started while waiting are awaited too.
220
+ while (_persistChains.size > 0) {
221
+ await Promise.all([..._persistChains.values()]);
222
+ }
223
+ }
224
+
225
+ // Test hook: number of live per-key chains.
226
+ export function _steeringPersistChainCount() {
227
+ return _persistChains.size;
212
228
  }
213
229
 
214
230
  function drainedRowToRestore(row) {
@@ -233,7 +249,7 @@ function drainedRowToRestore(row) {
233
249
  export function drainTuiSteeringPersist(leadSessionId) {
234
250
  const key = tuiSteeringSessionKey(leadSessionId);
235
251
  if (!key) return Promise.resolve([]);
236
- return _serialize(async () => {
252
+ return _serialize(key, async () => {
237
253
  let drained = [];
238
254
  let droppedStale = 0;
239
255
  try {
@@ -5,6 +5,7 @@
5
5
  // scalars); every function here takes it as its first argument.
6
6
  import { TUI_FRAME_MS, yieldToRenderer } from './render-timing.mjs';
7
7
  import { retryStatusLine } from '../../runtime/shared/err-text.mjs';
8
+ import { newTranscriptMessageId } from '../../runtime/shared/transcript-metadata.mjs';
8
9
 
9
10
  // Share Ink's exact 120fps cadence with the frame-batched store. A separate
10
11
  // 16ms timer left every other terminal frame idle, so completed script lines
@@ -59,9 +60,27 @@ function ensureAssistant(stream, initialText = '') {
59
60
  if (!stream.currentAssistantId) {
60
61
  stream.currentAssistantId = stream.nextId();
61
62
  const meta = stream.transcriptMeta;
62
- const assistantAt =
63
- Number.isFinite(Number(meta.assistantAt)) && Number(meta.assistantAt) > 0 ? Number(meta.assistantAt) : Date.now();
64
- meta.assistantAt = assistantAt;
63
+ // A non-streaming continuation was persisted before its text reached this
64
+ // row: the runtime left that message's id and time (ask-session
65
+ // takeAssistant), and the row carries them instead of minting new ones.
66
+ const persisted = stream.claimPersistedAssistant ? meta.persistedAssistant : null;
67
+ if (persisted) meta.persistedAssistant = null;
68
+ let assistantAt = persisted?.at;
69
+ let messageId = persisted?.messageId;
70
+ if (!persisted) {
71
+ assistantAt =
72
+ Number.isFinite(Number(meta.assistantAt)) && Number(meta.assistantAt) > 0
73
+ ? Number(meta.assistantAt)
74
+ : Date.now();
75
+ meta.assistantAt = assistantAt;
76
+ // The reply this segment becomes is persisted with this stable id (the
77
+ // runtime takes it with assistantAt), so a compaction that drops the
78
+ // reply greys this row.
79
+ if (!(typeof meta.assistantMessageId === 'string' && meta.assistantMessageId)) {
80
+ meta.assistantMessageId = newTranscriptMessageId();
81
+ }
82
+ messageId = meta.assistantMessageId;
83
+ }
65
84
  // Do NOT reset currentAssistantText here: the first onTextDelta has
66
85
  // already accumulated the opening chunk before this batched flush runs.
67
86
  // Segment resets are owned by closeAssistantSegment(). Seed the new row
@@ -70,6 +89,7 @@ function ensureAssistant(stream, initialText = '') {
70
89
  stream.updateStreamingTail(stream.currentAssistantId, {
71
90
  text: String(initialText || ''),
72
91
  at: assistantAt,
92
+ messageId,
73
93
  ...stream.routeMeta,
74
94
  });
75
95
  }
@@ -86,6 +106,7 @@ function resetLineScan(stream) {
86
106
  function closeAssistantSegment(stream) {
87
107
  stream.currentAssistantId = null;
88
108
  stream.currentAssistantText = '';
109
+ stream.claimPersistedAssistant = false;
89
110
  resetLineScan(stream);
90
111
  }
91
112
 
@@ -290,11 +311,18 @@ export function appendTextDelta(stream, textChunk) {
290
311
  // Mid-turn assistant text that precedes a tool call from a provider that only
291
312
  // returns the final response.content (no deltas); the streaming path owns
292
313
  // the render when it already produced text for this segment.
293
- export function appendAssistantText(stream, full) {
314
+ export function appendAssistantText(stream, full, { committed = false } = {}) {
294
315
  endThinkingForText(stream);
295
316
  stream.assistantText += full;
296
317
  stream.currentAssistantText += full;
297
318
  stream.pendingTextFlush = true;
319
+ // Only post-commit text is the persisted message's own: its row takes that
320
+ // id. Any other text (a tool preamble published before its message commits)
321
+ // leaves an earlier recorded id unclaimed, so drop it.
322
+ stream.claimPersistedAssistant = committed;
323
+ if (!committed && stream.transcriptMeta && typeof stream.transcriptMeta === 'object') {
324
+ stream.transcriptMeta.persistedAssistant = null;
325
+ }
298
326
  flushStreamBatch(stream);
299
327
  }
300
328
 
@@ -57,10 +57,12 @@ export async function builtinSkillNamesFor(runtime, calls) {
57
57
  }
58
58
 
59
59
  // Transcript spec for a standalone (non-aggregated) tool card.
60
- function standaloneCardSpec(itemId, name, args) {
60
+ function standaloneCardSpec(itemId, name, args, callId = '') {
61
61
  return {
62
62
  kind: 'tool',
63
63
  id: itemId,
64
+ // Ties the card to its call (a compaction that drops it greys the card).
65
+ ...(callId ? { callId } : {}),
64
66
  name,
65
67
  args,
66
68
  result: null,
@@ -221,7 +223,13 @@ function openToolCard(cards, call, index, batch) {
221
223
  // Defer the visible push: the card enters the transcript when its real
222
224
  // header will paint (delay elapsed) or its result lands first, so no
223
225
  // blank placeholder height scrolls the body ahead of the glyphs.
224
- const card = { itemId, callId: callKey, done: false, pushed: false, spec: standaloneCardSpec(itemId, name, args) };
226
+ const card = {
227
+ itemId,
228
+ callId: callKey,
229
+ done: false,
230
+ pushed: false,
231
+ spec: standaloneCardSpec(itemId, name, args, callId),
232
+ };
225
233
  cards.deferredCards.registerCard(card);
226
234
  trackCard(cards, callId, card);
227
235
  // Immediate row-reserve is deferred until every touched aggregate has its
@@ -18,6 +18,7 @@ import { isRejected429, safeErrorDetails } from '../../runtime/shared/error-pres
18
18
  import { registerTaskWaitSteeringCheck } from '../../runtime/agent/orchestrator/session/task-wait-control.mjs';
19
19
  import { promptDisplayText, STEERING_SUPPRESSED_DISPLAY } from './queue-helpers.mjs';
20
20
  import { yieldToRenderer } from './render-timing.mjs';
21
+ import { archiveItemsForCompaction, compactionArchivedRows } from './compaction-view.mjs';
21
22
  import {
22
23
  createTurnStream,
23
24
  flushStreamBatch,
@@ -105,7 +106,8 @@ function beginTurn({ flags, getState, transcriptRouteMetadata }, options) {
105
106
  completionVerb,
106
107
  };
107
108
  flags.pendingTranscriptMeta = null;
108
- const { at: _userItemAt, ...routeMeta } = transcriptMeta;
109
+ // The prompt's own time and stable id stay on the prompt row.
110
+ const { at: _userItemAt, messageId: _promptMessageId, ...routeMeta } = transcriptMeta;
109
111
  return {
110
112
  index,
111
113
  startedAt,
@@ -182,6 +184,11 @@ function commitPromptRestore(flags, turn) {
182
184
 
183
185
  function steeringItemExtras(steeringMeta) {
184
186
  return {
187
+ // The steered message's stable id, so a compaction that drops it greys
188
+ // this row.
189
+ ...(typeof steeringMeta?.messageId === 'string' && steeringMeta.messageId
190
+ ? { messageId: steeringMeta.messageId }
191
+ : {}),
185
192
  // Queue mode + execution provenance: a task notification is rendered as
186
193
  // a tool card, never as an injected user bubble.
187
194
  ...(steeringMeta?.mode === 'task-notification' ? { mode: 'task-notification' } : {}),
@@ -261,10 +268,10 @@ function publishContextPressure({ syncContextStats, getState, set }, info) {
261
268
  }
262
269
 
263
270
  // Compaction itself remains owned by the pre-provider-send pass. This event
264
- // trims the visible transcript to the current turn and refreshes the gauge
265
- // from the already-mutated transcript before another render can show stale
266
- // pressure.
267
- function applyCompactEvent(ctx, event) {
271
+ // archives the visible rows before the current turn (they stay in view above
272
+ // the compaction divider) and refreshes the gauge from the already-mutated
273
+ // transcript before another render can show stale pressure.
274
+ export function applyCompactEvent(ctx, event) {
268
275
  const { turn, stream, cards, getState, set, replaceItems, pushItem, nextId, syncContextStats, routeState } = ctx;
269
276
  flushStreamBatch(stream);
270
277
  // Non-tool transcript item — same block-boundary rule as the steered user
@@ -272,12 +279,31 @@ function applyCompactEvent(ctx, event) {
272
279
  cards.aggregates.clearAggregateContinuation();
273
280
  const compactStatus = String(event?.status || '').toLowerCase();
274
281
  const compactChanged = !['failed', 'skipped', 'no_change'].includes(compactStatus);
282
+ const doneItem = {
283
+ kind: 'statusdone',
284
+ id: nextId(),
285
+ label: compactEventLabel(event),
286
+ detail: compactEventDetail(event),
287
+ };
275
288
  if (compactChanged) {
276
- set({ items: replaceItems(getState().items.slice(turn.currentItemsStart), { preserveStreamingTail: true }) });
277
- turn.currentItemsStart = 0;
289
+ // The current turn starts at its submitted row (spill paging may have
290
+ // shifted the index recorded at turn start).
291
+ const current = getState().items;
292
+ const submitted = new Set(turn.submittedIds.filter((id) => id != null));
293
+ const submittedIndex = submitted.size ? current.findIndex((item) => submitted.has(item?.id)) : -1;
294
+ const boundary = submittedIndex >= 0 ? submittedIndex : turn.currentItemsStart;
295
+ const { items, dividerIndex } = archiveItemsForCompaction(current, doneItem, boundary, {
296
+ archived: compactionArchivedRows(event),
297
+ // Only explicit identities name what left the current turn; a bare
298
+ // count says nothing about it.
299
+ archiveTail: Boolean(event?.droppedIdentities && typeof event.droppedIdentities === 'object'),
300
+ });
301
+ set({ items: replaceItems(items, { preserveStreamingTail: true, preserveSpill: true }) });
302
+ turn.currentItemsStart = dividerIndex + 1;
278
303
  turn.transcriptCompacted = true;
304
+ } else {
305
+ pushItem(doneItem);
279
306
  }
280
- pushItem({ kind: 'statusdone', id: nextId(), label: compactEventLabel(event), detail: compactEventDetail(event) });
281
307
  syncContextStats({ allowEstimated: true, invalidateExact: compactChanged });
282
308
  // syncContextStats only STAGES its patch; publication is the caller's, and
283
309
  // without this set the post-compact gauge reached React only if some later
@@ -296,9 +322,26 @@ function applyTurnUsageDelta({ turn, getState, set, syncContextStats }, delta) {
296
322
  set({ stats: { ...getState().stats }, ...(spinner ? { spinner: { ...spinner, inputTokens, outputTokens } } : {}) });
297
323
  }
298
324
 
325
+ // The runtime reports the skills a user turn actually loaded (`Skill:` header
326
+ // or inline `$name`); the prompt row carries them as `appliedSkills`, the same
327
+ // field a restored row reads from the persisted transcript metadata.
328
+ function applySkillsToPromptRow({ turn, getState, patchItem }, names, detail = {}) {
329
+ const appliedSkills = (Array.isArray(names) ? names : []).filter((name) => typeof name === 'string' && name);
330
+ if (!appliedSkills.length) return;
331
+ const messageId = typeof detail?.messageId === 'string' ? detail.messageId : '';
332
+ const submitted = turn.submittedIds[0];
333
+ const row = getState().items.findLast(
334
+ (item) => item?.kind === 'user' && (messageId ? item.messageId === messageId : item.id === submitted)
335
+ );
336
+ if (row) patchItem(row.id, { appliedSkills });
337
+ }
338
+
299
339
  function turnHandlers(ctx) {
300
340
  const { isCurrentTurn, drainPendingSteering } = ctx;
301
341
  return {
342
+ onSkillsApplied: (names, detail) => {
343
+ if (isCurrentTurn()) applySkillsToPromptRow(ctx, names, detail);
344
+ },
302
345
  drainSteering: (_sessionId, drainOptions) =>
303
346
  isCurrentTurn() ? drainPendingSteering({ ...drainOptions, turnEpoch: ctx.turn.epoch }) : [],
304
347
  onStreamDelta: () => {},
@@ -359,7 +402,7 @@ function streamHandlers(ctx) {
359
402
  appendTextDelta(stream, textChunk);
360
403
  },
361
404
  onTextReset: (reset = {}) => (isCurrentTurn() ? resetStreamedText(stream, reset) : false),
362
- onAssistantText: (text) => {
405
+ onAssistantText: (text, detail) => {
363
406
  const full = String(text ?? '');
364
407
  if (!full.trim() || !isCurrentTurn()) return;
365
408
  // The streaming path owns this segment when it already produced text.
@@ -367,7 +410,7 @@ function streamHandlers(ctx) {
367
410
  // there across tool calls.
368
411
  if (stream.currentAssistantText.trim()) return;
369
412
  ctx.markPromptCommitted();
370
- appendAssistantText(stream, full);
413
+ appendAssistantText(stream, full, { committed: detail?.committed === true });
371
414
  },
372
415
  onReasoningDelta: (chunk) => {
373
416
  if (isCurrentTurn()) appendReasoningDelta(stream, String(chunk ?? ''));
@@ -420,9 +463,12 @@ export function failTurn(ctx, error) {
420
463
  }
421
464
 
422
465
  export function turnDoneItem({ turn, stream, cards, getState, nextId }) {
466
+ // The outer prompt id is the turn's change-record key (runtime.ask `id`).
467
+ const checkpointId = turn.submittedIds[0] == null ? '' : String(turn.submittedIds[0]).trim();
423
468
  return {
424
469
  kind: 'turndone',
425
470
  id: nextId(),
471
+ ...(checkpointId ? { checkpointId } : {}),
426
472
  elapsedMs: Date.now() - turn.startedAt,
427
473
  status: turnOutcome(turn.cancelled, turn.failed),
428
474
  // Notifications resolve this exact terminal assistant item, never a
@@ -1,162 +0,0 @@
1
- // Pure pre-turn extraction of the previous human request and the assistant
2
- // text around it, from the session history as it stands BEFORE the current
3
- // turn is committed (the boundary resolveTurnAutoEffort runs at). Nothing here
4
- // reads the current prompt's outcome; nothing is mutated; no text is matched
5
- // against word lists. Ownership comes only from typed provenance that the
6
- // runtime already writes (meta.runtimeUserContext, meta.synthetic, meta.source,
7
- // the compaction/skill/reminder predicates in compact/messages.mjs).
8
- //
9
- // Result of previousHumanContext(messages, { retryPrompt }):
10
- // {
11
- // version: 1,
12
- // boundary: number, // messages[0..boundary) were considered
13
- // retryTrimmedIndex: number, // index of the unanswered resubmitted prompt
14
- // // dropped from the view, or -1
15
- // prevHuman: { text, index, source, runtimeContext } | null,
16
- // // latest actual human message before the boundary. `text` is the
17
- // // runtime-context-stripped, trimmed text (untruncated). `source` is
18
- // // meta.source or null ('steering' = a human interjection).
19
- // // `runtimeContext` is 'stripped' | 'none'.
20
- // prevHumanMissing: 'empty-history' | 'no-human-request' | null,
21
- // canonicalReply: { text, index } | null,
22
- // // exactly what the shipped rp `prev` is: the latest non-empty
23
- // // assistant message before the boundary, whatever turn it is from.
24
- // pairedReply: { text, index } | null,
25
- // // latest non-empty assistant text inside prevHuman's own turn span
26
- // // (after prevHuman up to the next human message / boundary). Never
27
- // // falls back to another turn: a tool-only or unanswered turn gives
28
- // // null with pairedMissing set.
29
- // pairedMissing: 'no-human-request' | 'no-assistant-text-in-turn' | null,
30
- // replyIsPaired: boolean, // canonicalReply and pairedReply are the same message
31
- // skipped: [{ index, role, reason }], // user messages passed over after
32
- // // prevHuman's search began (newest first); reasons: 'summary',
33
- // // 'protected-context', 'skill-body', 'synthetic-flag',
34
- // // 'typed-source', 'runtime-owned', 'empty'.
35
- // }
36
- //
37
- // Policy decisions (PREVIOUS_HUMAN_POLICY):
38
- // synthetic meta.synthetic === true, or a source the runtime stores as
39
- // "not the user speaking" (task-notification, skill-context),
40
- // or anything isActualUserInstructionMessage rejects
41
- // (goal-continuation/closeout, compact-*, *-recovery, control
42
- // lines), is skipped, not treated as a request.
43
- // steering meta.source === 'steering' is a human interjection (the
44
- // provider layer keeps it as its own user turn for that
45
- // reason) and counts as a human request.
46
- // retry when retryPrompt repeats the trailing unanswered user prompt
47
- // (trailingUnansweredPromptIndex), that stale copy is excluded
48
- // so the prompt is never its own "previous request".
49
- // summary compact summaries are skipped; nothing before them is
50
- // recovered, so history truncated by compaction yields
51
- // 'no-human-request' rather than a guess.
52
- // Limitation: user messages stored without meta (old transcripts) cannot be
53
- // told apart from the human when a runtime wrapper was never recorded; they
54
- // are accepted as human, and a wrapper with stale provenance stays unstripped.
55
- import { stripRuntimeUserContext } from '../agent/orchestrator/session/runtime-user-context.mjs';
56
- import {
57
- isActualUserInstructionMessage,
58
- isInjectedSkillBodyMessage,
59
- isProtectedContextUserMessage,
60
- isSummaryMessage,
61
- } from '../agent/orchestrator/session/compact/messages.mjs';
62
- import { trailingUnansweredPromptIndex } from '../agent/orchestrator/session/manager/failed-turn-rewind.mjs';
63
- import { promptContentText } from '../agent/orchestrator/session/manager/prompt-utils.mjs';
64
-
65
- export const PREVIOUS_HUMAN_POLICY = Object.freeze({
66
- synthetic: 'skip',
67
- steering: 'human',
68
- retry: 'exclude-trailing-unanswered-copy',
69
- summary: 'skip-no-recovery',
70
- });
71
-
72
- const TYPED_NON_HUMAN_SOURCES = new Set(['task-notification', 'skill-context']);
73
-
74
- const textOf = (message) => promptContentText(message?.content).trim();
75
-
76
- /** { human, reason?, message } for a user message; null for other roles. */
77
- function classify(message) {
78
- if (message?.role !== 'user') return null;
79
- const stripped = stripRuntimeUserContext(message);
80
- const meta = stripped.meta && typeof stripped.meta === 'object' ? stripped.meta : {};
81
- const no = (reason) => ({ human: false, reason, message: stripped });
82
- if (isSummaryMessage(stripped)) return no('summary');
83
- if (isProtectedContextUserMessage(stripped)) return no('protected-context');
84
- if (isInjectedSkillBodyMessage(stripped)) return no('skill-body');
85
- if (meta.synthetic === true) return no('synthetic-flag');
86
- if (TYPED_NON_HUMAN_SOURCES.has(String(meta.source || ''))) return no('typed-source');
87
- if (!isActualUserInstructionMessage(stripped)) return no('runtime-owned');
88
- if (!textOf(stripped)) return no('empty');
89
- return { human: true, message: stripped, stripped: stripped !== message };
90
- }
91
-
92
- function latestAssistant(messages, from, to) {
93
- for (let index = to - 1; index >= from; index -= 1) {
94
- if (messages[index]?.role !== 'assistant') continue;
95
- const text = textOf(messages[index]);
96
- if (text) return { text, index };
97
- }
98
- return null;
99
- }
100
-
101
- export function previousHumanContext(messages, { retryPrompt } = {}) {
102
- const list = Array.isArray(messages) ? messages : [];
103
- const retryTrimmedIndex = retryPrompt == null ? -1 : trailingUnansweredPromptIndex(list, retryPrompt);
104
- const boundary = retryTrimmedIndex >= 0 ? retryTrimmedIndex : list.length;
105
- const verdicts = [];
106
- for (let index = 0; index < boundary; index += 1) verdicts.push(classify(list[index]));
107
-
108
- const skipped = [];
109
- let humanIndex = -1;
110
- for (let index = boundary - 1; index >= 0; index -= 1) {
111
- const verdict = verdicts[index];
112
- if (!verdict) continue;
113
- if (verdict.human) {
114
- humanIndex = index;
115
- break;
116
- }
117
- skipped.push({ index, role: 'user', reason: verdict.reason });
118
- // A summary replaces earlier conversational context; do not recover a
119
- // request from an older retained fragment behind that boundary.
120
- if (verdict.reason === 'summary') break;
121
- }
122
-
123
- const canonicalReply = latestAssistant(list, 0, boundary);
124
- let prevHuman = null;
125
- let pairedReply = null;
126
- let pairedMissing = 'no-human-request';
127
- if (humanIndex >= 0) {
128
- const verdict = verdicts[humanIndex];
129
- const source = verdict.message.meta?.source;
130
- prevHuman = {
131
- text: textOf(verdict.message),
132
- index: humanIndex,
133
- source: typeof source === 'string' && source ? source : null,
134
- runtimeContext: verdict.stripped ? 'stripped' : 'none',
135
- };
136
- let end = boundary;
137
- for (let index = humanIndex + 1; index < boundary; index += 1) {
138
- if (verdicts[index]?.human) {
139
- end = index;
140
- break;
141
- }
142
- }
143
- pairedReply = latestAssistant(list, humanIndex + 1, end);
144
- pairedMissing = pairedReply ? null : 'no-assistant-text-in-turn';
145
- }
146
-
147
- let prevHumanMissing = null;
148
- if (!prevHuman) prevHumanMissing = boundary === 0 ? 'empty-history' : 'no-human-request';
149
-
150
- return {
151
- version: 1,
152
- boundary,
153
- retryTrimmedIndex,
154
- prevHuman,
155
- prevHumanMissing,
156
- canonicalReply,
157
- pairedReply,
158
- pairedMissing,
159
- replyIsPaired: Boolean(pairedReply && canonicalReply && pairedReply.index === canonicalReply.index),
160
- skipped,
161
- };
162
- }
@@ -1,10 +0,0 @@
1
- // Experimental input only. An unavailable verified request preserves rp exactly.
2
- // Ownership and pairing are established by the caller, never inferred here.
3
- export function verifiedContextText({ request, prev, prevRequestVerified } = {}) {
4
- const current = String(request || '').slice(0, 1500);
5
- const reply = String(prev || '').slice(-1000);
6
- const prior = Array.from(String(prevRequestVerified || ''))
7
- .slice(0, 300)
8
- .join('');
9
- return `request: ${current}${prior ? `\nprevious request: ${prior}` : ''}\nprevious reply: ${reply}`;
10
- }