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
@@ -23394,15 +23394,30 @@ function warnLockRateLimited(warnedAt, lockPath, line) {
23394
23394
  } catch {
23395
23395
  }
23396
23396
  }
23397
- function reportLockWait(lockPath, waitedMs, mode) {
23397
+ function formatLockTiming(timing) {
23398
+ return Object.entries(timing || {}).filter(([, ms]) => Number.isFinite(ms)).map(([name, ms]) => ` ${name}=${ms}ms`).join("");
23399
+ }
23400
+ function recordLockTiming(lockPath, fields) {
23401
+ const lease = heldLockPaths.getStore()?.get(lockPath);
23402
+ if (lease?.active) Object.assign(lease.timing, fields);
23403
+ }
23404
+ function reportLockWait(lockPath, waitedMs, mode, timing) {
23398
23405
  if (waitedMs < LOCK_WAIT_WARN_MS) return;
23399
- warnLockRateLimited(lockWaitWarnedAt, lockPath, `[atomic-file] ${mode} lock wait ${waitedMs}ms: ${lockPath}
23400
- `);
23406
+ warnLockRateLimited(
23407
+ lockWaitWarnedAt,
23408
+ lockPath,
23409
+ `[atomic-file] ${mode} lock wait ${waitedMs}ms:${formatLockTiming(timing)} ${lockPath}
23410
+ `
23411
+ );
23401
23412
  }
23402
- function reportLockHeld(lockPath, heldMs, mode) {
23413
+ function reportLockHeld(lockPath, heldMs, mode, timing) {
23403
23414
  if (heldMs < LOCK_HELD_WARN_MS) return;
23404
- warnLockRateLimited(lockHeldWarnedAt, lockPath, `[atomic-file] ${mode} lock held ${heldMs}ms: ${lockPath}
23405
- `);
23415
+ warnLockRateLimited(
23416
+ lockHeldWarnedAt,
23417
+ lockPath,
23418
+ `[atomic-file] ${mode} lock held ${heldMs}ms:${formatLockTiming(timing)} ${lockPath}
23419
+ `
23420
+ );
23406
23421
  }
23407
23422
  function* tryAcquireReclaimGuard(lockPath) {
23408
23423
  const guardPath = `${lockPath}.reclaim`;
@@ -23572,7 +23587,7 @@ function sweepStagedLockFiles(lockPath, now = Date.now()) {
23572
23587
  }
23573
23588
  return removed;
23574
23589
  }
23575
- function* acquireLock(lockPath, opts, mode, markHeld) {
23590
+ function* acquireLock(lockPath, opts, mode, markHeld, timing = null) {
23576
23591
  const timeoutMs = lockTimeoutMs(opts);
23577
23592
  const staleMs = lockStaleMs(opts);
23578
23593
  const deadline = Date.now() + timeoutMs;
@@ -23599,7 +23614,9 @@ function* acquireLock(lockPath, opts, mode, markHeld) {
23599
23614
  attempt += 1;
23600
23615
  continue;
23601
23616
  }
23602
- reportLockWait(lockPath, Date.now() - waitStartedAt, mode);
23617
+ const osMs = Date.now() - waitStartedAt;
23618
+ if (timing) timing.osAcquireMs = osMs;
23619
+ reportLockWait(lockPath, osMs, mode, timing);
23603
23620
  return;
23604
23621
  }
23605
23622
  throw timeoutError(lockPath, timeoutMs, lastError, yield* describeLockHolder(lockPath));
@@ -23625,12 +23642,14 @@ function withFileLockSync(lockPath, fn, opts = {}) {
23625
23642
  async function withFileLock(lockPath, fn, opts = {}) {
23626
23643
  if (heldLockPaths.getStore()?.get(lockPath)?.active) return fn();
23627
23644
  if (lockTimeoutMs(opts) <= 0) return withOsFileLock(lockPath, fn, opts);
23628
- return lockQueue(lockPath, () => withOsFileLock(lockPath, fn, opts));
23645
+ const enqueuedAt = Date.now();
23646
+ return lockQueue(lockPath, () => withOsFileLock(lockPath, fn, opts, Date.now() - enqueuedAt));
23629
23647
  }
23630
- async function withOsFileLock(lockPath, fn, opts = {}) {
23631
- await runAsync(acquireLock(lockPath, opts, "async", true));
23648
+ async function withOsFileLock(lockPath, fn, opts = {}, queueWaitMs = 0) {
23649
+ const timing = { queueWaitMs };
23650
+ await runAsync(acquireLock(lockPath, opts, "async", true, timing));
23632
23651
  const heldSince = Date.now();
23633
- const lease = { active: false };
23652
+ const lease = { active: false, timing };
23634
23653
  try {
23635
23654
  if (opts.secret === true) await enforceOwnerOnlyAclWin32Async(lockPath, { fresh: true });
23636
23655
  const held = new Map(heldLockPaths.getStore() || []);
@@ -23642,7 +23661,7 @@ async function withOsFileLock(lockPath, fn, opts = {}) {
23642
23661
  try {
23643
23662
  await runAsync(releaseLock(lockPath));
23644
23663
  } finally {
23645
- reportLockHeld(lockPath, Date.now() - heldSince, "async");
23664
+ reportLockHeld(lockPath, Date.now() - heldSince, "async", timing);
23646
23665
  unmarkOsHeld(lockPath);
23647
23666
  }
23648
23667
  }
@@ -23919,7 +23938,28 @@ async function writeFileAtomicAsync(filePath, data, opts = {}) {
23919
23938
  throw err;
23920
23939
  }
23921
23940
  };
23922
- return opts.lock === true ? withFileLock(`${filePath}.lock`, () => _runAdaptiveFileIo(run), opts) : _runAdaptiveFileIo(run);
23941
+ if (opts.lock !== true) return _runAdaptiveFileIo(run);
23942
+ const lockPath = `${filePath}.lock`;
23943
+ return withFileLock(
23944
+ lockPath,
23945
+ async () => {
23946
+ const queuedAt = Date.now();
23947
+ let startedAt = 0;
23948
+ try {
23949
+ return await _runAdaptiveFileIo(() => {
23950
+ startedAt = Date.now();
23951
+ return run();
23952
+ });
23953
+ } finally {
23954
+ const now = Date.now();
23955
+ recordLockTiming(lockPath, {
23956
+ ioGateWaitMs: (startedAt || now) - queuedAt,
23957
+ writeMs: startedAt ? now - startedAt : 0
23958
+ });
23959
+ }
23960
+ },
23961
+ opts
23962
+ );
23923
23963
  }
23924
23964
  function writeJsonAtomicAsync(filePath, value, opts = {}) {
23925
23965
  return writeFileAtomicAsync(filePath, `${JSON.stringify(value, null, opts.compact ? 0 : 2)}
@@ -35075,7 +35115,7 @@ import { performance as performance2 } from "node:perf_hooks";
35075
35115
  import { format } from "node:util";
35076
35116
 
35077
35117
  // src/tui/App.jsx
35078
- import { useState as useState19, useCallback as useCallback29, useEffect as useEffect30, useLayoutEffect as useLayoutEffect9, useMemo as useMemo9, useRef as useRef29 } from "react";
35118
+ import { useState as useState20, useCallback as useCallback29, useEffect as useEffect31, useLayoutEffect as useLayoutEffect9, useMemo as useMemo9, useRef as useRef29 } from "react";
35079
35119
 
35080
35120
  // src/tui/hooks/useSession.mjs
35081
35121
  import { useSyncExternalStore } from "react";
@@ -35489,6 +35529,154 @@ function slashArgumentHint(value) {
35489
35529
  return command?.params ? `${command.usage} ${command.params}` : "";
35490
35530
  }
35491
35531
 
35532
+ // src/tui/app/skill-mention-palette.mjs
35533
+ import { useEffect as useEffect7, useState as useState6 } from "react";
35534
+
35535
+ // src/runtime/shared/skill-mentions.mjs
35536
+ var MENTION = /(^|[\s([{"'`])\$([a-z0-9][a-z0-9-]{0,63})(?![A-Za-z0-9_-])/g;
35537
+ var RESERVED_NAMES = /* @__PURE__ */ new Set([
35538
+ "path",
35539
+ "home",
35540
+ "user",
35541
+ "shell",
35542
+ "pwd",
35543
+ "tmpdir",
35544
+ "temp",
35545
+ "tmp",
35546
+ "lang",
35547
+ "term",
35548
+ "xdg_config_home",
35549
+ "userprofile",
35550
+ "appdata",
35551
+ "localappdata",
35552
+ "programfiles",
35553
+ "systemroot",
35554
+ "windir",
35555
+ "comspec"
35556
+ ]);
35557
+ function isReservedMentionName(name) {
35558
+ const value = String(name ?? "");
35559
+ return /^[0-9]+$/.test(value) || RESERVED_NAMES.has(value.toLowerCase());
35560
+ }
35561
+ var FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})(.*)$/;
35562
+ var FENCE_CLOSE = /^ {0,3}(`{3,}|~{3,})[ \t]*$/;
35563
+ function inlineCodeRanges(source, from, to, ranges) {
35564
+ const runs = [];
35565
+ const re = /`+/g;
35566
+ re.lastIndex = from;
35567
+ for (let match = re.exec(source); match && match.index < to; match = re.exec(source)) {
35568
+ runs.push({ start: match.index, end: Math.min(to, match.index + match[0].length) });
35569
+ }
35570
+ for (let index = 0; index < runs.length; index += 1) {
35571
+ const length = runs[index].end - runs[index].start;
35572
+ const close = runs.findIndex((run, at) => at > index && run.end - run.start === length);
35573
+ if (close < 0) continue;
35574
+ ranges.push([runs[index].start, runs[close].end]);
35575
+ index = close;
35576
+ }
35577
+ }
35578
+ function codeRanges(source) {
35579
+ const ranges = [];
35580
+ let open = null;
35581
+ let proseStart = 0;
35582
+ for (let at = 0; at <= source.length; ) {
35583
+ const newline = source.indexOf("\n", at);
35584
+ const end = newline < 0 ? source.length : newline;
35585
+ const next = newline < 0 ? source.length + 1 : newline + 1;
35586
+ const line = source.slice(at, end).replace(/\r$/, "");
35587
+ if (!open) {
35588
+ const fence = FENCE_OPEN.exec(line);
35589
+ if (fence && !(fence[1][0] === "`" && fence[2].includes("`"))) {
35590
+ inlineCodeRanges(source, proseStart, at, ranges);
35591
+ open = { char: fence[1][0], length: fence[1].length, start: at };
35592
+ }
35593
+ } else {
35594
+ const fence = FENCE_CLOSE.exec(line);
35595
+ if (fence && fence[1][0] === open.char && fence[1].length >= open.length) {
35596
+ ranges.push([open.start, Math.min(next, source.length)]);
35597
+ proseStart = Math.min(next, source.length);
35598
+ open = null;
35599
+ }
35600
+ }
35601
+ at = next;
35602
+ }
35603
+ if (open) ranges.push([open.start, source.length]);
35604
+ else inlineCodeRanges(source, proseStart, source.length, ranges);
35605
+ return ranges;
35606
+ }
35607
+ function isInMarkdownCode(text, offset) {
35608
+ const source = typeof text === "string" ? text : "";
35609
+ if (!Number.isInteger(offset) || !source.includes("`") && !source.includes("~~~")) return false;
35610
+ return codeRanges(source).some(([from, to]) => offset >= from && offset < to);
35611
+ }
35612
+ function skillMentionCandidates(text) {
35613
+ const source = typeof text === "string" ? text : "";
35614
+ const found = [];
35615
+ let code = null;
35616
+ for (const match of source.matchAll(MENTION)) {
35617
+ if (isReservedMentionName(match[2])) continue;
35618
+ const start = match.index + match[1].length;
35619
+ code ??= source.includes("`") || source.includes("~~~") ? codeRanges(source) : [];
35620
+ if (code.some(([from, to]) => start >= from && start < to)) continue;
35621
+ found.push({ name: match[2], start, end: start + 1 + match[2].length });
35622
+ }
35623
+ return found;
35624
+ }
35625
+ function skillMentions(text, isSkill) {
35626
+ return skillMentionCandidates(text).filter((mention) => isSkill(mention.name));
35627
+ }
35628
+
35629
+ // src/tui/app/skill-mention-palette.mjs
35630
+ var MENTION_TAIL = /(^|[\s([{"'`])\$([a-z0-9][a-z0-9-]{0,63})?$/;
35631
+ var caretIn = (text, caret) => Number.isInteger(caret) ? Math.max(0, Math.min(text.length, caret)) : text.length;
35632
+ function skillMentionQuery(value, caret) {
35633
+ const text = String(value ?? "");
35634
+ const end = caretIn(text, caret);
35635
+ const match = MENTION_TAIL.exec(text.slice(0, end));
35636
+ if (!match) return null;
35637
+ const start = match.index + match[1].length;
35638
+ if (isInMarkdownCode(text, start)) return null;
35639
+ return { query: match[2] || "", start, end };
35640
+ }
35641
+ var byName = (a, b) => a.name.localeCompare(b.name, "en");
35642
+ function skillMentionItems(skills, query) {
35643
+ const needle = String(query || "").toLowerCase();
35644
+ const usable = (Array.isArray(skills) ? skills : []).filter(
35645
+ (skill) => typeof skill?.name === "string" && skill.name && skill.enabled !== false && skill.activeHere !== false && skill.source !== "builtin" && // `$path`/`$300` are never mentions, so offering them would insert prose.
35646
+ !isReservedMentionName(skill.name)
35647
+ );
35648
+ const prefix = usable.filter((skill) => skill.name.startsWith(needle)).sort(byName);
35649
+ const contains = needle ? usable.filter((skill) => !skill.name.startsWith(needle) && skill.name.includes(needle)).sort(byName) : [];
35650
+ return [...prefix, ...contains].map((skill) => ({
35651
+ kind: "skill",
35652
+ name: skill.name,
35653
+ label: `$${skill.name}`,
35654
+ description: skill.description || ""
35655
+ }));
35656
+ }
35657
+ function completeSkillMention(value, name, caret) {
35658
+ const text = String(value ?? "");
35659
+ const mention = skillMentionQuery(text, caret);
35660
+ if (!mention || !name) return void 0;
35661
+ const head = `${text.slice(0, mention.start)}$${name} `;
35662
+ return { value: head + text.slice(mention.end), cursor: head.length };
35663
+ }
35664
+ function useSkillMentionSkills(store, active) {
35665
+ const [skills, setSkills] = useState6([]);
35666
+ useEffect7(() => {
35667
+ if (!active) return void 0;
35668
+ let live = true;
35669
+ Promise.resolve().then(() => store.skillsStatus?.()).then((status) => {
35670
+ if (live) setSkills(Array.isArray(status?.skills) ? status.skills : []);
35671
+ }).catch(() => {
35672
+ });
35673
+ return () => {
35674
+ live = false;
35675
+ };
35676
+ }, [store, active]);
35677
+ return skills;
35678
+ }
35679
+
35492
35680
  // src/tui/app/slash-palette.mjs
35493
35681
  function deriveSlashPalette({
35494
35682
  providerPrompt,
@@ -35500,13 +35688,28 @@ function deriveSlashPalette({
35500
35688
  exiting,
35501
35689
  commandBusy,
35502
35690
  promptDraft,
35503
- slashDismissedFor
35691
+ slashDismissedFor,
35692
+ skills = [],
35693
+ promptCaret = null
35504
35694
  }) {
35505
35695
  const activeSlashQuery = providerPrompt || settingsPrompt || toolApproval || contextPanel || usagePanel ? null : slashQuery(promptDraft);
35506
- const slashModeLive = activeSlashQuery !== null && !picker && !toolApproval && !contextPanel && !usagePanel && !exiting && !commandBusy;
35507
- const slashCommands = !slashModeLive ? [] : SLASH_COMMANDS.filter((command) => slashCommandMatches(command, activeSlashQuery)).sort(compareSlashCommands);
35508
- const slashPaletteOpen = slashModeLive && slashDismissedFor !== promptDraft;
35509
- return { activeSlashQuery, slashCommands, slashPaletteOpen };
35696
+ const surfaceFree = !picker && !toolApproval && !contextPanel && !usagePanel && !exiting && !commandBusy;
35697
+ const slashModeLive = activeSlashQuery !== null && surfaceFree;
35698
+ if (!slashModeLive) {
35699
+ const mention = surfaceFree && !providerPrompt && !settingsPrompt ? skillMentionQuery(promptDraft, promptCaret) : null;
35700
+ const slashCommands2 = mention ? skillMentionItems(skills, mention.query) : [];
35701
+ return {
35702
+ activeSlashQuery: mention ? mention.query : null,
35703
+ slashCommands: slashCommands2,
35704
+ slashPaletteOpen: slashCommands2.length > 0 && slashDismissedFor !== promptDraft,
35705
+ paletteKind: mention ? "skills" : "commands"
35706
+ };
35707
+ }
35708
+ const slashCommands = SLASH_COMMANDS.filter((command) => slashCommandMatches(command, activeSlashQuery)).sort(
35709
+ compareSlashCommands
35710
+ );
35711
+ const slashPaletteOpen = slashDismissedFor !== promptDraft;
35712
+ return { activeSlashQuery, slashCommands, slashPaletteOpen, paletteKind: "commands" };
35510
35713
  }
35511
35714
 
35512
35715
  // src/tui/app/panel-epoch.mjs
@@ -35611,7 +35814,7 @@ function resolvePickerState(prev, resolved, { pickerOpenedFromEnterRef, pickerOp
35611
35814
  }
35612
35815
 
35613
35816
  // src/tui/app/use-prompt-layout-rows.mjs
35614
- import { useCallback as useCallback5, useEffect as useEffect7 } from "react";
35817
+ import { useCallback as useCallback5, useEffect as useEffect8 } from "react";
35615
35818
  import stringWidth3 from "string-width";
35616
35819
 
35617
35820
  // src/tui/display-width.mjs
@@ -35796,10 +35999,10 @@ function usePromptLayoutRows({
35796
35999
  },
35797
36000
  [promptContentColumns]
35798
36001
  );
35799
- useEffect7(() => {
36002
+ useEffect8(() => {
35800
36003
  syncPromptLayoutRows(promptLayoutValueRef.current);
35801
36004
  }, [syncPromptLayoutRows]);
35802
- useEffect7(() => {
36005
+ useEffect8(() => {
35803
36006
  const kind = String(settingsPrompt?.kind || "");
35804
36007
  if (!CORE_MULTILINE_TEXT_ENTRY_KINDS.has(kind)) {
35805
36008
  setTextEntryLayoutRows(1);
@@ -35812,7 +36015,7 @@ function usePromptLayoutRows({
35812
36015
  }
35813
36016
 
35814
36017
  // src/tui/app/use-panel-transition.mjs
35815
- import { useEffect as useEffect8 } from "react";
36018
+ import { useEffect as useEffect9 } from "react";
35816
36019
  function usePanelTransition({
35817
36020
  panelTransitionRef,
35818
36021
  panelCloseInkMaskRowsRef,
@@ -35824,7 +36027,7 @@ function usePanelTransition({
35824
36027
  setPanelInkMaskEpoch,
35825
36028
  setPanelTransitionEpoch
35826
36029
  }) {
35827
- useEffect8(() => {
36030
+ useEffect9(() => {
35828
36031
  const transition = panelTransitionRef.current;
35829
36032
  const pendingInkMask = panelCloseInkMaskRowsRef.current;
35830
36033
  const hadTransitionClearance = panelTransitionClearRows > 0 || panelTransitionGuardRows > 0;
@@ -35841,13 +36044,13 @@ function usePanelTransition({
35841
36044
  const timer2 = setTimeout(() => setPanelTransitionEpoch((epoch) => epoch + 1), 0);
35842
36045
  return () => clearTimeout(timer2);
35843
36046
  }, [panelLayoutSignature, bottomClusterRows, panelTransitionClearRows, panelTransitionGuardRows]);
35844
- useEffect8(() => {
36047
+ useEffect9(() => {
35845
36048
  panelTransitionRef.current.tailId = latestTranscriptItem?.id ?? null;
35846
36049
  });
35847
36050
  }
35848
36051
 
35849
36052
  // src/tui/app/use-ui-open-request.mjs
35850
- import { useEffect as useEffect9, useRef as useRef4 } from "react";
36053
+ import { useEffect as useEffect10, useRef as useRef4 } from "react";
35851
36054
  var SETUP_SECTION_TARGETS = Object.freeze({
35852
36055
  developer: ({ openDeveloperPicker }) => openDeveloperPicker(),
35853
36056
  voice: ({ openSettingsPicker }) => openSettingsPicker(),
@@ -35855,7 +36058,7 @@ var SETUP_SECTION_TARGETS = Object.freeze({
35855
36058
  });
35856
36059
  function useUiOpenRequest({ uiOpenRequest, runSlashCommand, sections }) {
35857
36060
  const seenRef = useRef4(0);
35858
- useEffect9(() => {
36061
+ useEffect10(() => {
35859
36062
  const request = uiOpenRequest;
35860
36063
  const seq = Number(request?.seq) || 0;
35861
36064
  if (!request?.command || seq <= seenRef.current) return;
@@ -35867,7 +36070,7 @@ function useUiOpenRequest({ uiOpenRequest, runSlashCommand, sections }) {
35867
36070
  }
35868
36071
 
35869
36072
  // src/tui/app/use-mouse-input.mjs
35870
- import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef5 } from "react";
36073
+ import { useCallback as useCallback6, useEffect as useEffect11, useRef as useRef5 } from "react";
35871
36074
 
35872
36075
  // src/tui/markdown/streaming-markdown.mjs
35873
36076
  import { marked as marked2 } from "marked";
@@ -38936,8 +39139,21 @@ function stripToolPrefix(name) {
38936
39139
  function rawToolName(name) {
38937
39140
  return String(name || "tool").replace(/^functions\./, "");
38938
39141
  }
38939
- function parseMcpToolName(name) {
38940
- const text = rawToolName(name);
39142
+ var mcpToolIdentities = /* @__PURE__ */ new Map();
39143
+ function knownMcpToolIdentity(name) {
39144
+ const known = mcpToolIdentities.get(rawToolName(name));
39145
+ return known ? { ...known } : null;
39146
+ }
39147
+ function parseMcpToolName(nameOrTool) {
39148
+ if (nameOrTool && typeof nameOrTool === "object") {
39149
+ const server = String(nameOrTool.mcpServerName || "").trim();
39150
+ const parsed = parseMcpToolName(nameOrTool.name);
39151
+ if (!server) return parsed;
39152
+ return { server, tool: String(nameOrTool.mcpToolName || "") || parsed?.tool || "" };
39153
+ }
39154
+ const text = rawToolName(nameOrTool);
39155
+ const known = mcpToolIdentities.get(text);
39156
+ if (known) return { ...known };
38941
39157
  const match = /^mcp__(.+?)__(.+)$/.exec(text);
38942
39158
  if (!match) return null;
38943
39159
  return { server: match[1], tool: match[2] };
@@ -39041,6 +39257,8 @@ function toolSearchDisplayLabel(args = {}) {
39041
39257
  function displayToolSearchTarget(value) {
39042
39258
  const text = String(value || "").trim();
39043
39259
  if (/^skill:/i.test(text)) return text.slice("skill:".length);
39260
+ const known = knownMcpToolIdentity(text);
39261
+ if (known) return `${known.server}.${known.tool}`;
39044
39262
  const mcp = /^mcp__(.*?)__(.+)$/.exec(text);
39045
39263
  if (mcp) return `${mcp[1]}.${mcp[2]}`;
39046
39264
  return stripToolPrefix(text);
@@ -39950,6 +40168,7 @@ var TOOL_CATEGORY = /* @__PURE__ */ new Map([
39950
40168
  ["office", "Office"],
39951
40169
  ["media", "Media"],
39952
40170
  ["tidy", "Tidy"],
40171
+ ["visualize", "Visualize"],
39953
40172
  ["list_mcp_resources", "Setup"],
39954
40173
  ["list_mcp_resource_templates", "Setup"],
39955
40174
  ["cwd", "Setup"],
@@ -39989,6 +40208,7 @@ var CATEGORY_COPY = /* @__PURE__ */ new Map([
39989
40208
  ["Office", { active: "Editing", done: "Edited", noun: "document action" }],
39990
40209
  ["Media", { active: "Generating", done: "Generated", noun: "media action" }],
39991
40210
  ["Tidy", { active: "Tidying", done: "Tidied", noun: "cleanup pass" }],
40211
+ ["Visualize", { active: "Showing", done: "Showed", noun: "artifact" }],
39992
40212
  ["Other", { active: "Calling", done: "Called", noun: "tool" }]
39993
40213
  ]);
39994
40214
  function categoryCopy(category) {
@@ -40179,6 +40399,16 @@ function officeUnit(a) {
40179
40399
  const [active, done] = OFFICE_ACTION_VERBS.get(action) || ["Editing", "Edited"];
40180
40400
  return unitDescriptor("Office", { count: 1, active, done, noun: "document action", effect: true });
40181
40401
  }
40402
+ function visualizeUnit(a) {
40403
+ const action = String(a.action || "").toLowerCase();
40404
+ if (action === "capture") return unitDescriptor("Visualize", { count: 1, active: "Capturing", done: "Captured", noun: "screenshot" });
40405
+ if (action === "export") return unitDescriptor("Visualize", { count: 1, active: "Exporting", done: "Exported", noun: "file" });
40406
+ if (action === "annotate") return unitDescriptor("Visualize", { count: 1, active: "Marking", done: "Marked", noun: "annotation" });
40407
+ if (action === "check") return unitDescriptor("Visualize", { count: 1, active: "Checking", done: "Checked", noun: "page" });
40408
+ if (action === "inspect") return unitDescriptor("Visualize", { count: 1, active: "Inspecting", done: "Inspected", noun: "page" });
40409
+ if (action === "close") return unitDescriptor("Visualize", { count: 1, active: "Closing", done: "Closed", noun: "tab" });
40410
+ return unitDescriptor("Visualize", { count: 1, active: "Showing", done: "Showed", noun: "artifact" });
40411
+ }
40182
40412
  function terminalUnit(a) {
40183
40413
  return String(a.action || "").toLowerCase() === "list" ? unitDescriptor("Terminal", { count: 1, active: "Listing", done: "Listed", noun: "terminal tab" }) : unitDescriptor("Terminal", { count: 1, active: "Reading", done: "Read", noun: "terminal output" });
40184
40414
  }
@@ -40449,6 +40679,7 @@ var TOOL_UNITS = /* @__PURE__ */ new Map([
40449
40679
  ["setup", setupUnit],
40450
40680
  ["media", mediaUnit],
40451
40681
  ["tidy", tidyUnit],
40682
+ ["visualize", visualizeUnit],
40452
40683
  ["fetch", fetchUnit],
40453
40684
  ["recall", memoryReadUnit],
40454
40685
  ["recall_memory", memoryReadUnit],
@@ -40562,6 +40793,8 @@ function displayToolName(name, args = {}) {
40562
40793
  return "Media";
40563
40794
  case "tidy":
40564
40795
  return "Tidy";
40796
+ case "visualize":
40797
+ return "Visualize";
40565
40798
  case "list_mcp_resources":
40566
40799
  case "list_mcp_resource_templates":
40567
40800
  case "cwd":
@@ -40723,6 +40956,11 @@ function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}) {
40723
40956
  }
40724
40957
  case "terminal":
40725
40958
  return compactParts([String(a.action || ""), a.tab ? `tab ${a.tab}` : ""]);
40959
+ case "visualize": {
40960
+ const input = a.input && typeof a.input === "object" ? a.input : {};
40961
+ const targets = Array.isArray(input.targets) ? input.targets.map(String).join(", ") : "";
40962
+ return compactParts([String(a.action || ""), targets || String(input.tab || "")]);
40963
+ }
40726
40964
  case "office":
40727
40965
  return compactParts([String(a.action || ""), pathOrId(a.path, a.session, max)]);
40728
40966
  case "media":
@@ -42740,6 +42978,29 @@ function deriveToolCardModel(input = {}, options = {}) {
42740
42978
  };
42741
42979
  }
42742
42980
 
42981
+ // src/tui/components/user-message-skills.mjs
42982
+ function appliedSkillNames(value) {
42983
+ return (Array.isArray(value) ? value : []).filter((name) => typeof name === "string" && name);
42984
+ }
42985
+ function appliedSkillsLine(value) {
42986
+ const names = appliedSkillNames(value);
42987
+ return names.length ? `Skills applied: ${names.join(", ")}` : "";
42988
+ }
42989
+ function userTextSegments(text, value) {
42990
+ const source = String(text ?? "");
42991
+ const applied = new Set(appliedSkillNames(value));
42992
+ if (!applied.size) return [{ text: source, mention: false }];
42993
+ const segments = [];
42994
+ let at = 0;
42995
+ for (const mention of skillMentions(source, (name) => applied.has(name))) {
42996
+ if (mention.start > at) segments.push({ text: source.slice(at, mention.start), mention: false });
42997
+ segments.push({ text: source.slice(mention.start, mention.end), mention: true });
42998
+ at = mention.end;
42999
+ }
43000
+ if (at < source.length || !segments.length) segments.push({ text: source.slice(at), mention: false });
43001
+ return segments;
43002
+ }
43003
+
42743
43004
  // src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs
42744
43005
  function aggregateRawResultForDisplay(text) {
42745
43006
  if (typeof text !== "string" || !/^\[lines \d+-\d+\]$/m.test(text)) return text;
@@ -43344,8 +43605,10 @@ function estimateToolRenderedResultRows(value, { pathArg = "", isShell = false,
43344
43605
  function estimateTranscriptItemRows(item, columns, toolOutputExpanded, attachedTool = false) {
43345
43606
  if (!item) return 1;
43346
43607
  switch (item.kind) {
43347
- case "user":
43348
- return 1 + estimateWrappedRows(item.text, columns, 4);
43608
+ case "user": {
43609
+ const skillsLine = appliedSkillsLine(item.appliedSkills);
43610
+ return 1 + estimateWrappedRows(item.text, columns, 4) + (skillsLine ? estimateWrappedRows(skillsLine, columns, 4) : 0);
43611
+ }
43349
43612
  case "assistant":
43350
43613
  return 1 + (item.streaming ? measureStreamingMarkdownRenderedRows(item.text, columns, item.id) : measureMarkdownRenderedRows(item.text, columns, { trimPartialFences: true }));
43351
43614
  case "tool": {
@@ -44396,12 +44659,12 @@ function useMouseInput({
44396
44659
  const passthroughCtrlWheelZoom = useCallback6(() => {
44397
44660
  zoomRestoreSchedulerRef.current.passthrough();
44398
44661
  }, []);
44399
- useEffect10(() => {
44662
+ useEffect11(() => {
44400
44663
  const scheduler = zoomRestoreSchedulerRef.current;
44401
44664
  scheduler.attach();
44402
44665
  return () => scheduler.detach();
44403
44666
  }, []);
44404
- useEffect10(() => {
44667
+ useEffect11(() => {
44405
44668
  if (!inkInput || !isRawModeSupported) return void 0;
44406
44669
  const geometry = createMouseGeometry({
44407
44670
  transcriptViewportRef,
@@ -44491,7 +44754,7 @@ function useMouseInput({
44491
44754
  }
44492
44755
 
44493
44756
  // src/tui/app/use-transcript-scroll.mjs
44494
- import { useCallback as useCallback12, useEffect as useEffect13, useLayoutEffect as useLayoutEffect3, useRef as useRef10 } from "react";
44757
+ import { useCallback as useCallback12, useEffect as useEffect14, useLayoutEffect as useLayoutEffect3, useRef as useRef10 } from "react";
44495
44758
 
44496
44759
  // src/tui/app/transcript-scroll-anchor.mjs
44497
44760
  function readingAnchorAt(geom, target) {
@@ -44513,7 +44776,7 @@ function bottomSnapRows(viewRows) {
44513
44776
  }
44514
44777
 
44515
44778
  // src/tui/app/use-selection-stitch.mjs
44516
- import { useCallback as useCallback7, useEffect as useEffect11, useRef as useRef6 } from "react";
44779
+ import { useCallback as useCallback7, useEffect as useEffect12, useRef as useRef6 } from "react";
44517
44780
  function storeStitchRows(buffer, rows2, scroll) {
44518
44781
  for (const row of rows2) {
44519
44782
  if (!row || typeof row.y !== "number") continue;
@@ -44527,7 +44790,7 @@ function useSelectionStitchBuffer({ store, dragRef, scrollTargetRef }) {
44527
44790
  const stitchBufferRef = useRef6(/* @__PURE__ */ new Map());
44528
44791
  const stitchHarvestTimerRef = useRef6(null);
44529
44792
  const stitchHarvestScrollRef = useRef6(0);
44530
- useEffect11(
44793
+ useEffect12(
44531
44794
  () => () => {
44532
44795
  if (stitchHarvestTimerRef.current) clearTimeout(stitchHarvestTimerRef.current);
44533
44796
  stitchHarvestTimerRef.current = null;
@@ -44656,7 +44919,7 @@ function useTranscriptFollow({
44656
44919
  }
44657
44920
 
44658
44921
  // src/tui/app/use-selection-paint.mjs
44659
- import { useCallback as useCallback9, useEffect as useEffect12, useRef as useRef8 } from "react";
44922
+ import { useCallback as useCallback9, useEffect as useEffect13, useRef as useRef8 } from "react";
44660
44923
 
44661
44924
  // src/tui/session/render-frame-source.mjs
44662
44925
  var sources = /* @__PURE__ */ new Set();
@@ -44848,7 +45111,7 @@ function useSelectionPaint({
44848
45111
  }) {
44849
45112
  const selectionPaintRef = useRef8({ t: 0, rect: null, pending: null, timer: null });
44850
45113
  const selectionTextCaptureRef = useRef8(0);
44851
- useEffect12(
45114
+ useEffect13(
44852
45115
  () => () => {
44853
45116
  const paintState = selectionPaintRef.current;
44854
45117
  if (paintState.timer) clearTimeout(paintState.timer);
@@ -45094,7 +45357,7 @@ function useSelectionFocusMove({
45094
45357
  // src/tui/app/use-transcript-scroll.mjs
45095
45358
  function useScrollCoalescer(scrollTranscriptRows) {
45096
45359
  const scrollCoalesceRef = useRef10({ pendingRows: 0, direction: 0, timer: null });
45097
- useEffect13(
45360
+ useEffect14(
45098
45361
  () => () => {
45099
45362
  const state = scrollCoalesceRef.current;
45100
45363
  if (state.timer) clearTimeout(state.timer);
@@ -45350,9 +45613,9 @@ function useTranscriptScroll({
45350
45613
  }
45351
45614
 
45352
45615
  // src/tui/app/use-transcript-scroll-state.mjs
45353
- import { useRef as useRef11, useState as useState6 } from "react";
45616
+ import { useRef as useRef11, useState as useState7 } from "react";
45354
45617
  function useTranscriptScrollState() {
45355
- const [scrollOffset, setScrollOffset] = useState6(0);
45618
+ const [scrollOffset, setScrollOffset] = useState7(0);
45356
45619
  const scrollPositionRef = useRef11(0);
45357
45620
  const scrollTargetRef = useRef11(0);
45358
45621
  const maxScrollRowsRef = useRef11(0);
@@ -45360,7 +45623,7 @@ function useTranscriptScrollState() {
45360
45623
  const transcriptAnchorRef = useRef11(null);
45361
45624
  const transcriptAnchorDirtyRef = useRef11(false);
45362
45625
  const transcriptGeomRef = useRef11({ prefixRows: null, totalRows: 0, viewRows: 1 });
45363
- const [measuredRowsVersion, setMeasuredRowsVersion] = useState6(0);
45626
+ const [measuredRowsVersion, setMeasuredRowsVersion] = useState7(0);
45364
45627
  const followingRef = useRef11(false);
45365
45628
  const lastItemsCountRef = useRef11(0);
45366
45629
  const lastFirstItemIdRef = useRef11(null);
@@ -45383,13 +45646,14 @@ function useTranscriptScrollState() {
45383
45646
  }
45384
45647
 
45385
45648
  // src/tui/app/use-prompt-state.mjs
45386
- import { useRef as useRef12, useState as useState7 } from "react";
45649
+ import { useRef as useRef12, useState as useState8 } from "react";
45387
45650
  function usePromptState() {
45388
- const [promptDraft, setPromptDraft] = useState7("");
45389
- const [promptDraftOverride, setPromptDraftOverride] = useState7(null);
45651
+ const [promptDraft, setPromptDraft] = useState8("");
45652
+ const [promptDraftOverride, setPromptDraftOverride] = useState8(null);
45653
+ const [promptCaret, setPromptCaret] = useState8(null);
45390
45654
  const promptLayoutValueRef = useRef12("");
45391
- const [, setPromptLayoutRows] = useState7(1);
45392
- const [textEntryLayoutRows, setTextEntryLayoutRows] = useState7(1);
45655
+ const [, setPromptLayoutRows] = useState8(1);
45656
+ const [textEntryLayoutRows, setTextEntryLayoutRows] = useState8(1);
45393
45657
  const promptValueRef = useRef12("");
45394
45658
  const promptSelectionRef = useRef12(null);
45395
45659
  const promptBoxRectRef = useRef12(null);
@@ -45401,6 +45665,8 @@ function usePromptState() {
45401
45665
  setPromptDraft,
45402
45666
  promptDraftOverride,
45403
45667
  setPromptDraftOverride,
45668
+ promptCaret,
45669
+ setPromptCaret,
45404
45670
  promptLayoutValueRef,
45405
45671
  setPromptLayoutRows,
45406
45672
  textEntryLayoutRows,
@@ -45448,7 +45714,7 @@ function useInteractionRefs() {
45448
45714
  }
45449
45715
 
45450
45716
  // src/tui/app/use-pasted-buffers.mjs
45451
- import { useCallback as useCallback13, useRef as useRef14, useState as useState8 } from "react";
45717
+ import { useCallback as useCallback13, useRef as useRef14, useState as useState9 } from "react";
45452
45718
 
45453
45719
  // src/tui/paste-attachments.mjs
45454
45720
  import { execFile } from "node:child_process";
@@ -46015,7 +46281,7 @@ async function readClipboardText() {
46015
46281
 
46016
46282
  // src/tui/app/use-pasted-buffers.mjs
46017
46283
  function usePastedBufferSlice({ toEntry, formatRef }) {
46018
- const [, setBuffers] = useState8({});
46284
+ const [, setBuffers] = useState9({});
46019
46285
  const buffersRef = useRef14({});
46020
46286
  const nextIdRef = useRef14(1);
46021
46287
  const install = useCallback13((buffers, { merge = true } = {}) => {
@@ -46084,11 +46350,11 @@ function usePastedBuffers() {
46084
46350
  }
46085
46351
 
46086
46352
  // src/tui/app/use-prompt-hint.mjs
46087
- import { useCallback as useCallback14, useEffect as useEffect14, useRef as useRef15, useState as useState9 } from "react";
46353
+ import { useCallback as useCallback14, useEffect as useEffect15, useRef as useRef15, useState as useState10 } from "react";
46088
46354
  var PROMPT_HINT_DISMISS_MS = 2200;
46089
46355
  function usePromptHint() {
46090
- const [promptHint, setPromptHint] = useState9("");
46091
- const [promptHintTone, setPromptHintTone] = useState9("info");
46356
+ const [promptHint, setPromptHint] = useState10("");
46357
+ const [promptHintTone, setPromptHintTone] = useState10("info");
46092
46358
  const promptHintTimerRef = useRef15(null);
46093
46359
  const promptHintActiveRef = useRef15(false);
46094
46360
  const showPromptHint = useCallback14((text, tone = "info", dismissMs = PROMPT_HINT_DISMISS_MS) => {
@@ -46115,7 +46381,7 @@ function usePromptHint() {
46115
46381
  setPromptHint("");
46116
46382
  setPromptHintTone("info");
46117
46383
  }, []);
46118
- useEffect14(
46384
+ useEffect15(
46119
46385
  () => () => {
46120
46386
  if (promptHintTimerRef.current) clearTimeout(promptHintTimerRef.current);
46121
46387
  },
@@ -46133,7 +46399,7 @@ function usePromptHint() {
46133
46399
  }
46134
46400
 
46135
46401
  // src/tui/app/use-welcome-prompt-hint.mjs
46136
- import { useCallback as useCallback15, useEffect as useEffect15, useRef as useRef16, useState as useState10 } from "react";
46402
+ import { useCallback as useCallback15, useEffect as useEffect16, useRef as useRef16, useState as useState11 } from "react";
46137
46403
 
46138
46404
  // src/tui/app/app-format.mjs
46139
46405
  import stringWidth5 from "string-width";
@@ -46634,8 +46900,8 @@ function cleanRightMessage(value) {
46634
46900
 
46635
46901
  // src/tui/app/use-welcome-prompt-hint.mjs
46636
46902
  function useWelcomePromptHint({ store, state, toastErrorSignature }) {
46637
- const [welcomePromptHintDismissed, setWelcomePromptHintDismissed] = useState10(false);
46638
- const [conditionalWelcomePromptHint, setConditionalWelcomePromptHint] = useState10("");
46903
+ const [welcomePromptHintDismissed, setWelcomePromptHintDismissed] = useState11(false);
46904
+ const [conditionalWelcomePromptHint, setConditionalWelcomePromptHint] = useState11("");
46639
46905
  const welcomePromptHintRef = useRef16(null);
46640
46906
  if (welcomePromptHintRef.current === null) {
46641
46907
  welcomePromptHintRef.current = randomWelcomePromptHint();
@@ -46645,7 +46911,7 @@ function useWelcomePromptHint({ store, state, toastErrorSignature }) {
46645
46911
  if (!welcomePromptHintVisibleRef.current) return;
46646
46912
  setWelcomePromptHintDismissed(true);
46647
46913
  }, []);
46648
- useEffect15(() => {
46914
+ useEffect16(() => {
46649
46915
  let alive = true;
46650
46916
  const refreshConditionalWelcomeHint = async () => {
46651
46917
  let quickModels;
@@ -48352,7 +48618,7 @@ function renderWelcomeBanner({ frameColumns, cwd: cwd2 }) {
48352
48618
  }
48353
48619
 
48354
48620
  // src/tui/hooks/useSharedTick.mjs
48355
- import { useEffect as useEffect16, useRef as useRef17, useState as useState11 } from "react";
48621
+ import { useEffect as useEffect17, useRef as useRef17, useState as useState12 } from "react";
48356
48622
  var TICK_SLOP_MS = 16;
48357
48623
  var subscribers = /* @__PURE__ */ new Set();
48358
48624
  var timer = null;
@@ -48387,10 +48653,10 @@ function onTick() {
48387
48653
  reconcileTimer();
48388
48654
  }
48389
48655
  function useSharedTick(intervalMs, isActive = true, onTick2 = null) {
48390
- const [, setTick] = useState11(0);
48656
+ const [, setTick] = useState12(0);
48391
48657
  const cbRef = useRef17(onTick2);
48392
48658
  cbRef.current = onTick2;
48393
- useEffect16(() => {
48659
+ useEffect17(() => {
48394
48660
  if (!isActive) return void 0;
48395
48661
  const interval = Math.max(1, Number(intervalMs) || 0);
48396
48662
  const sub = {
@@ -49046,14 +49312,192 @@ var RETIRED_MODEL_ALIASES = Object.freeze({
49046
49312
  "grok-code-fast-1-0825": "grok-build-0.1"
49047
49313
  });
49048
49314
 
49049
- // src/runtime/shared/llm/provider-catalog-cache.mjs
49050
- var PROVIDER_CACHE_FILES = Object.freeze({
49051
- "openai-oauth": ["openai-oauth-models.json"],
49052
- "anthropic-oauth": ["anthropic-oauth-models.json"],
49053
- anthropic: ["anthropic-oauth-models.json"],
49054
- gemini: ["gemini-models.json"],
49055
- "grok-oauth": ["grok-oauth-models.json"],
49056
- "antigravity-oauth": ["antigravity-oauth-models.json"]
49315
+ // src/runtime/shared/llm/provider-seed-rosters.mjs
49316
+ var MUSE_DEFAULT_EFFORT_LEVELS = Object.freeze(["minimal", "low", "medium", "high", "xhigh"]);
49317
+ var MUSE_SIX_LEVELS = Object.freeze([...MUSE_DEFAULT_EFFORT_LEVELS, "max"]);
49318
+ var MUSE_SPARK_CONTEXT = 1048576;
49319
+ var MUSE_SPARK_MAX_OUTPUT = 131072;
49320
+ var STANDARD_COST = { inputCostPerM: 1.25, outputCostPerM: 4.25, cacheReadCostPerM: 0.15, cacheWriteCostPerM: 0 };
49321
+ var CONTRIBUTOR_COST = { inputCostPerM: 0.1, outputCostPerM: 0.2, cacheReadCostPerM: 2e-3, cacheWriteCostPerM: 0 };
49322
+ var MUSE_SEEDS = Object.freeze({
49323
+ "muse-spark-1.1": { name: "Muse Spark 1.1", levels: MUSE_DEFAULT_EFFORT_LEVELS, cost: STANDARD_COST },
49324
+ "muse-spark-1.2": { name: "Muse Spark 1.2", levels: MUSE_DEFAULT_EFFORT_LEVELS, cost: STANDARD_COST },
49325
+ "muse-spark-1.2-contributor": {
49326
+ name: "Muse Spark 1.2 (C)",
49327
+ levels: MUSE_DEFAULT_EFFORT_LEVELS,
49328
+ cost: CONTRIBUTOR_COST
49329
+ },
49330
+ "muse-spark-1.3": { name: "Muse Spark 1.3", levels: MUSE_SIX_LEVELS, cost: STANDARD_COST },
49331
+ "muse-spark-1.3-contributor": { name: "Muse Spark 1.3 (C)", levels: MUSE_SIX_LEVELS, cost: CONTRIBUTOR_COST }
49332
+ });
49333
+ var MUSE_SEED_IDS = Object.freeze(Object.keys(MUSE_SEEDS));
49334
+ function museEffortRow(id, name, levels, cost) {
49335
+ return {
49336
+ id,
49337
+ name,
49338
+ provider: "muse-code-oauth",
49339
+ family: "muse-spark",
49340
+ contextWindow: MUSE_SPARK_CONTEXT,
49341
+ outputTokens: MUSE_SPARK_MAX_OUTPUT,
49342
+ supportsReasoning: true,
49343
+ supportsVision: true,
49344
+ supportsFunctionCalling: true,
49345
+ reasoningLevels: [...levels],
49346
+ reasoningOptions: [{ type: "effort", values: [...levels] }],
49347
+ ...cost
49348
+ };
49349
+ }
49350
+ var SPARK_ID_RE = /^muse-spark-(\d+)\.(\d+)(?:\.(\d+))?(-contributor)?$/i;
49351
+ function revisionOf(id) {
49352
+ const m = SPARK_ID_RE.exec(id);
49353
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3] || 0)] : null;
49354
+ }
49355
+ function compareRevision(a, b) {
49356
+ for (let i = 0; i < 3; i += 1) if (a[i] !== b[i]) return a[i] - b[i];
49357
+ return 0;
49358
+ }
49359
+ function museLineageRow(id) {
49360
+ const match = SPARK_ID_RE.exec(id);
49361
+ if (!match) return null;
49362
+ const contributor = Boolean(match[4]);
49363
+ let template = null;
49364
+ let templateRevision = null;
49365
+ for (const seedId of MUSE_SEED_IDS) {
49366
+ if (SPARK_ID_RE.exec(seedId)[4] ? !contributor : contributor) continue;
49367
+ const candidate = revisionOf(seedId);
49368
+ if (!templateRevision || compareRevision(candidate, templateRevision) > 0) {
49369
+ template = seedId;
49370
+ templateRevision = candidate;
49371
+ }
49372
+ }
49373
+ if (!template) return null;
49374
+ const revision = match[3] && Number(match[3]) !== 0 ? `${match[1]}.${match[2]}.${match[3]}` : `${match[1]}.${match[2]}`;
49375
+ return museEffortRow(
49376
+ id,
49377
+ `Muse Spark ${revision}${contributor ? " (C)" : ""}`,
49378
+ MUSE_DEFAULT_EFFORT_LEVELS,
49379
+ MUSE_SEEDS[template].cost
49380
+ );
49381
+ }
49382
+ function museSeedRow(id) {
49383
+ const key = String(id || "");
49384
+ const seed = MUSE_SEEDS[key];
49385
+ if (seed) return museEffortRow(key, seed.name, seed.levels, seed.cost);
49386
+ return museLineageRow(key);
49387
+ }
49388
+ var MIMO_SEED_CONTEXT = 1048576;
49389
+ var MIMO_SEED_OUTPUT = 131072;
49390
+ var MIMO_SEED_MODELS = Object.freeze(
49391
+ [
49392
+ ["mimo-v2.6-pro", "MiMo-V2.6-Pro", MIMO_SEED_CONTEXT],
49393
+ ["mimo-v2.6-flash", "MiMo-V2.6-Flash", MIMO_SEED_CONTEXT],
49394
+ ["mimo-v2.6-pro-ultraspeed", "MiMo-V2.6-Pro-Ultraspeed", MIMO_SEED_CONTEXT],
49395
+ ["mimo-v2.5-pro", "MiMo-V2.5-Pro", MIMO_SEED_CONTEXT],
49396
+ ["mimo-v2.5", "MiMo-V2.5", MIMO_SEED_CONTEXT],
49397
+ ["mimo-v2-pro", "MiMo-V2-Pro", MIMO_SEED_CONTEXT],
49398
+ ["mimo-v2-omni", "MiMo-V2-Omni", 262144]
49399
+ ].map(
49400
+ ([id, display_name, context_window]) => Object.freeze({ id, display_name, context_window, max_output_tokens: MIMO_SEED_OUTPUT })
49401
+ )
49402
+ );
49403
+ function mimoSeedRow(model) {
49404
+ const id = String(model || "").toLowerCase();
49405
+ let seed = MIMO_SEED_MODELS.find((item) => item.id === id) || null;
49406
+ if (!seed) {
49407
+ for (const item of MIMO_SEED_MODELS) {
49408
+ if (id.startsWith(`${item.id}-`) && (!seed || item.id.length > seed.id.length)) seed = item;
49409
+ }
49410
+ }
49411
+ if (!seed) return null;
49412
+ return {
49413
+ id: String(model),
49414
+ contextWindow: seed.context_window,
49415
+ outputTokens: seed.max_output_tokens,
49416
+ reasoning: true,
49417
+ vision: true,
49418
+ inputModalities: ["text", "image"]
49419
+ };
49420
+ }
49421
+
49422
+ // src/runtime/shared/llm/provider-catalog-registry.mjs
49423
+ function mimoSeedMetadata(model) {
49424
+ const seed = mimoSeedRow(model);
49425
+ return seed ? {
49426
+ contextWindow: seed.contextWindow,
49427
+ outputTokens: seed.outputTokens,
49428
+ supportsReasoning: seed.reasoning === true,
49429
+ supportsVision: seed.vision === true
49430
+ } : null;
49431
+ }
49432
+ var PROVIDER_CATALOGS = Object.freeze({
49433
+ // api.openai.com — the endpoint models.dev `openai` describes.
49434
+ openai: { modelsDev: "openai", sameEndpoint: true },
49435
+ // chatgpt.com/backend-api/codex: subscription backend, not the public API.
49436
+ "openai-oauth": {
49437
+ modelsDev: "openai",
49438
+ sameEndpoint: false,
49439
+ rosterFiles: ["openai-oauth-models.json"],
49440
+ rosterLimitsAuthoritative: true
49441
+ },
49442
+ // api.anthropic.com with a subscription token: account-scoped windows and
49443
+ // effort surface differ from the public API SKU.
49444
+ "anthropic-oauth": {
49445
+ modelsDev: "anthropic",
49446
+ sameEndpoint: false,
49447
+ rosterFiles: ["anthropic-oauth-models.json"],
49448
+ rosterLimitsAuthoritative: true
49449
+ },
49450
+ // api.anthropic.com with an API key. Shares the OAuth roster file.
49451
+ anthropic: { modelsDev: "anthropic", sameEndpoint: true, rosterFiles: ["anthropic-oauth-models.json"] },
49452
+ // generativelanguage.googleapis.com — the endpoint models.dev `google` describes.
49453
+ gemini: { modelsDev: "google", sameEndpoint: true, rosterFiles: ["gemini-models.json"] },
49454
+ // cli-chat-proxy.grok.com, not api.x.ai.
49455
+ "grok-oauth": {
49456
+ modelsDev: "xai",
49457
+ sameEndpoint: false,
49458
+ rosterFiles: ["grok-oauth-models.json"],
49459
+ rosterLimitsAuthoritative: true
49460
+ },
49461
+ // api.meta.ai/v1 — the endpoint models.dev `meta` describes.
49462
+ "muse-code-oauth": {
49463
+ modelsDev: "meta",
49464
+ sameEndpoint: true,
49465
+ rosterFiles: ["muse-code-oauth-models.json"],
49466
+ rosterLimitsAuthoritative: true,
49467
+ seedRow: museSeedRow
49468
+ },
49469
+ // token-plan-*.xiaomimimo.com subscription gateway, not the public API.
49470
+ "mimo-oauth": {
49471
+ modelsDev: "xiaomi",
49472
+ sameEndpoint: false,
49473
+ rosterFiles: ["mimo-oauth-models.json"],
49474
+ rosterLimitsAuthoritative: true,
49475
+ seedRow: mimoSeedMetadata
49476
+ },
49477
+ // Relays: their own models.dev id (when published) is their own endpoint.
49478
+ // Effort tiers live in the wire id; a row without levels has no effort
49479
+ // surface (resolveAntigravityWireModel drops the effort).
49480
+ "antigravity-oauth": { relay: true, rosterFiles: ["antigravity-oauth-models.json"], rosterLadderFinal: true },
49481
+ // api.commandcode.ai/provider/v1 relays other vendors' models.
49482
+ "command-code-oauth": {
49483
+ relay: true,
49484
+ rosterFiles: ["command-code-oauth-models.json"],
49485
+ rosterLimitsAuthoritative: true
49486
+ },
49487
+ "cursor-oauth": { relay: true },
49488
+ "cursor-api": { relay: true },
49489
+ "opencode-go": { relay: true }
49490
+ });
49491
+ var VERIFIED_CORRECTIONS = Object.freeze({
49492
+ "muse-code-oauth": Object.freeze({
49493
+ // models.dev `meta` stops this ladder at xhigh; the Muse OAuth endpoint
49494
+ // accepts reasoning.effort "max" for the contributor tier as for 1.3.
49495
+ "muse-spark-1.3-contributor": Object.freeze({
49496
+ reasoningOptions: Object.freeze([
49497
+ Object.freeze({ type: "effort", values: Object.freeze(["minimal", "low", "medium", "high", "xhigh", "max"]) })
49498
+ ])
49499
+ })
49500
+ })
49057
49501
  });
49058
49502
 
49059
49503
  // src/runtime/shared/llm/model-pricing-rates.mjs
@@ -49099,7 +49543,7 @@ function projectModelsDevRow(row) {
49099
49543
  if (limit) out.limit = limit;
49100
49544
  const modalities = pickArrays(row.modalities, MODELSDEV_MODALITY_FIELDS);
49101
49545
  if (modalities) out.modalities = modalities;
49102
- if (row.reasoning === true) out.reasoning = true;
49546
+ if (typeof row.reasoning === "boolean") out.reasoning = row.reasoning;
49103
49547
  if (Array.isArray(row.reasoning_options) && row.reasoning_options.length > 0) {
49104
49548
  out.reasoning_options = row.reasoning_options;
49105
49549
  }
@@ -49166,7 +49610,7 @@ function projectLitellmRow(row) {
49166
49610
  out[field] = value;
49167
49611
  }
49168
49612
  for (const field of LITELLM_FLAG_FIELDS) {
49169
- if (row[field] === true) out[field] = true;
49613
+ if (typeof row[field] === "boolean") out[field] = row[field];
49170
49614
  }
49171
49615
  for (const field of LITELLM_STRING_FIELDS) {
49172
49616
  const value = row[field];
@@ -49326,6 +49770,37 @@ var CURSOR_PRICING = Object.freeze({
49326
49770
  fast: { inputCostPerM: 30, cacheWriteCostPerM: 37.5, cacheReadCostPerM: 3, outputCostPerM: 150 }
49327
49771
  }
49328
49772
  });
49773
+ var PRICING_FIELDS = Object.freeze([
49774
+ ...PRICING_RATE_KEYS,
49775
+ "pricingTiers",
49776
+ "fastPricing",
49777
+ "ultrafastPricing",
49778
+ "offPeakMultiplier",
49779
+ "outputImageCostPerM",
49780
+ "outputVideoCostPerM",
49781
+ "outputCostPerImage",
49782
+ "outputCostPerSecond",
49783
+ "outputCostPerSecondByResolution",
49784
+ "pricingSource",
49785
+ "pricingProvider",
49786
+ // Decides whether a cache-read rate is required, so it travels with prices.
49787
+ "supportsPromptCaching"
49788
+ ]);
49789
+ var GUESSED_FLAGS = Object.freeze([
49790
+ "supportsVision",
49791
+ "supportsFunctionCalling",
49792
+ "supportsWebSearch",
49793
+ "supportsPromptCaching",
49794
+ "supportsReasoning"
49795
+ ]);
49796
+ var CAPABILITY_FLAGS = Object.freeze([
49797
+ "supportsVision",
49798
+ "supportsFunctionCalling",
49799
+ "supportsWebSearch",
49800
+ "supportsPromptCaching",
49801
+ "supportsFastMode",
49802
+ "supportsReasoning"
49803
+ ]);
49329
49804
 
49330
49805
  // src/runtime/shared/statusline/statusline-format.mjs
49331
49806
  var statusText = rgb(198, 198, 198);
@@ -49373,15 +49848,29 @@ function isPidAlive(value) {
49373
49848
  var DEFAULT_MIXDOG_HOME = process.env.MIXDOG_HOME || join9(homedir2(), ".mixdog");
49374
49849
  var DEFAULT_STANDALONE_DATA_DIR = join9(DEFAULT_MIXDOG_HOME, "data");
49375
49850
  var SHELL_JOBS_SEGMENT_CACHE_MS = 1e3;
49376
- var EMPTY_SHELL_JOBS_SESSION = Object.freeze({ count: 0, elapsedLabel: "", jobs: Object.freeze([]) });
49851
+ var FINISHED_SHELL_JOB_TTL_MS = 30 * 60 * 1e3;
49852
+ var EMPTY_SHELL_JOBS_SESSION = Object.freeze({
49853
+ count: 0,
49854
+ elapsedLabel: "",
49855
+ jobs: Object.freeze([]),
49856
+ finished: Object.freeze([])
49857
+ });
49377
49858
  var EMPTY_SHELL_JOBS = Object.freeze({
49378
49859
  count: 0,
49379
49860
  elapsedLabel: "",
49380
49861
  jobs: Object.freeze([]),
49381
49862
  sessions: Object.freeze({})
49382
49863
  });
49383
- var _shellJobsSegmentCache = { ownerPid: 0, at: 0, value: EMPTY_SHELL_JOBS };
49384
- var _shellJobsRefreshInFlight = false;
49864
+ var _shellJobsSegmentCache = /* @__PURE__ */ new Map();
49865
+ var _shellJobsRefreshInFlight = /* @__PURE__ */ new Set();
49866
+ var SHELL_JOBS_OWNER_CACHE_TTL_MS = 6e4;
49867
+ function rememberShellJobs(ownerPid, value) {
49868
+ const at = Date.now();
49869
+ for (const [pid, entry] of _shellJobsSegmentCache) {
49870
+ if (at - entry.at > SHELL_JOBS_OWNER_CACHE_TTL_MS) _shellJobsSegmentCache.delete(pid);
49871
+ }
49872
+ _shellJobsSegmentCache.set(ownerPid, { at, value });
49873
+ }
49385
49874
  function dataDir() {
49386
49875
  return process.env.MIXDOG_DATA_DIR || DEFAULT_STANDALONE_DATA_DIR;
49387
49876
  }
@@ -49391,15 +49880,15 @@ function shellJobsStatus({ clientHostPid, sessionId } = {}) {
49391
49880
  const scope = String(sessionId ?? "").trim();
49392
49881
  if (!ownerPid) return scoped ? EMPTY_SHELL_JOBS_SESSION : EMPTY_SHELL_JOBS;
49393
49882
  const now = Date.now();
49394
- const sameOwner = _shellJobsSegmentCache.ownerPid === ownerPid;
49395
- const fresh = sameOwner && now - _shellJobsSegmentCache.at < SHELL_JOBS_SEGMENT_CACHE_MS;
49396
- if (!fresh && !_shellJobsRefreshInFlight) {
49397
- _shellJobsRefreshInFlight = true;
49883
+ const cached = _shellJobsSegmentCache.get(ownerPid);
49884
+ const fresh = cached && now - cached.at < SHELL_JOBS_SEGMENT_CACHE_MS;
49885
+ if (!fresh && !_shellJobsRefreshInFlight.has(ownerPid)) {
49886
+ _shellJobsRefreshInFlight.add(ownerPid);
49398
49887
  refreshShellJobsStatus(ownerPid).finally(() => {
49399
- _shellJobsRefreshInFlight = false;
49888
+ _shellJobsRefreshInFlight.delete(ownerPid);
49400
49889
  });
49401
49890
  }
49402
- const value = sameOwner ? _shellJobsSegmentCache.value || EMPTY_SHELL_JOBS : EMPTY_SHELL_JOBS;
49891
+ const value = cached?.value || EMPTY_SHELL_JOBS;
49403
49892
  if (!scoped) return value;
49404
49893
  return scope && value.sessions?.[scope] || EMPTY_SHELL_JOBS_SESSION;
49405
49894
  }
@@ -49411,10 +49900,10 @@ async function refreshShellJobsStatus(ownerPid) {
49411
49900
  try {
49412
49901
  names = await readdir(dir);
49413
49902
  } catch {
49414
- _shellJobsSegmentCache = { ownerPid, at: Date.now(), value };
49903
+ rememberShellJobs(ownerPid, value);
49415
49904
  return;
49416
49905
  }
49417
- const { ids, ownerByJob } = listOpenShellJobs(names);
49906
+ const { ids, ownerByJob, doneIds } = listOpenShellJobs(names);
49418
49907
  let count = 0;
49419
49908
  let oldestMs = Infinity;
49420
49909
  const jobs = [];
@@ -49428,6 +49917,7 @@ async function refreshShellJobsStatus(ownerPid) {
49428
49917
  continue;
49429
49918
  }
49430
49919
  if (!await isShellJobAlive(detail, p, dir, id)) continue;
49920
+ if (detail?.foreground === true) continue;
49431
49921
  const ownedByThisHost = ownerByJob.get(id) === ownerPid;
49432
49922
  if (ownedByThisHost) count++;
49433
49923
  let jobMs = Infinity;
@@ -49446,17 +49936,42 @@ async function refreshShellJobsStatus(ownerPid) {
49446
49936
  };
49447
49937
  if (ownedByThisHost) jobs.push(job);
49448
49938
  if (!owner) continue;
49449
- const bucket = bySession.get(owner) || { count: 0, oldestMs: Infinity, jobs: [] };
49939
+ const bucket = bySession.get(owner) || { count: 0, oldestMs: Infinity, jobs: [], finished: [] };
49450
49940
  bucket.count += 1;
49451
49941
  if (jobMs < bucket.oldestMs) bucket.oldestMs = jobMs;
49452
49942
  bucket.jobs.push(job);
49453
49943
  bySession.set(owner, bucket);
49454
49944
  }
49945
+ const finishedCutoff = Date.now() - FINISHED_SHELL_JOB_TTL_MS;
49946
+ for (const id of doneIds) {
49947
+ let detail;
49948
+ try {
49949
+ detail = JSON.parse(await readFile(join9(dir, `${id}.json`), "utf-8"));
49950
+ } catch {
49951
+ continue;
49952
+ }
49953
+ if (detail?.foreground === true) continue;
49954
+ const owner = String(detail?.ownerSessionId ?? "").trim();
49955
+ if (!owner) continue;
49956
+ const finishedMs = Date.parse(detail?.finishedAt || detail?.recordedAt || "");
49957
+ if (Number.isFinite(finishedMs) && finishedMs < finishedCutoff) continue;
49958
+ const bucket = bySession.get(owner) || { count: 0, oldestMs: Infinity, jobs: [], finished: [] };
49959
+ bucket.finished.push({
49960
+ taskId: id,
49961
+ command: String(detail?.command || "").trim(),
49962
+ cwd: String(detail?.cwd || "").trim(),
49963
+ startedAt: detail?.startedAt || null,
49964
+ status: String(detail?.status || ""),
49965
+ exitCode: Number.isInteger(detail?.exitCode) ? detail.exitCode : null,
49966
+ finishedAt: detail?.finishedAt || detail?.recordedAt || null
49967
+ });
49968
+ bySession.set(owner, bucket);
49969
+ }
49455
49970
  if (count || bySession.size) value = summarizeShellJobs({ count, oldestMs, jobs, bySession });
49456
49971
  } catch {
49457
49972
  value = EMPTY_SHELL_JOBS;
49458
49973
  }
49459
- _shellJobsSegmentCache = { ownerPid, at: Date.now(), value };
49974
+ rememberShellJobs(ownerPid, value);
49460
49975
  }
49461
49976
  function listOpenShellJobs(names) {
49462
49977
  const done = new Set(names.filter((n) => n.endsWith(".done")).map((n) => n.slice(0, -5)));
@@ -49469,7 +49984,8 @@ function listOpenShellJobs(names) {
49469
49984
  }
49470
49985
  }
49471
49986
  const ids = names.filter((n) => n.endsWith(".json")).map((n) => n.slice(0, -5)).filter((id) => !done.has(id)).sort((a, b) => jobStampMs(b) - jobStampMs(a)).slice(0, 60);
49472
- return { ids, ownerByJob };
49987
+ const doneIds = [...done].filter((id) => names.includes(`${id}.json`)).sort((a, b) => jobStampMs(b) - jobStampMs(a)).slice(0, 30);
49988
+ return { ids, ownerByJob, doneIds };
49473
49989
  }
49474
49990
  function summarizeShellJobs({ count, oldestMs, jobs, bySession }) {
49475
49991
  const now = Date.now();
@@ -49479,7 +49995,8 @@ function summarizeShellJobs({ count, oldestMs, jobs, bySession }) {
49479
49995
  sessions[owner] = {
49480
49996
  count: bucket.count,
49481
49997
  elapsedLabel: Number.isFinite(bucket.oldestMs) ? formatElapsed(now - bucket.oldestMs) : "",
49482
- jobs: bucket.jobs
49998
+ jobs: bucket.jobs,
49999
+ finished: bucket.finished
49483
50000
  };
49484
50001
  }
49485
50002
  return { count, elapsedLabel, jobs, sessions };
@@ -49735,7 +50252,7 @@ ${freshL2}` : cachedL1;
49735
50252
  }
49736
50253
 
49737
50254
  // src/tui/components/status-line/use-statusline-text.mjs
49738
- import { useEffect as useEffect17, useRef as useRef19, useState as useState12 } from "react";
50255
+ import { useEffect as useEffect18, useRef as useRef19, useState as useState13 } from "react";
49739
50256
  function useStatusLineText({
49740
50257
  sessionId,
49741
50258
  clientHostPid,
@@ -49758,7 +50275,7 @@ function useStatusLineText({
49758
50275
  initialLine,
49759
50276
  themeEpoch
49760
50277
  }) {
49761
- const [line, setLine] = useState12(
50278
+ const [line, setLine] = useState13(
49762
50279
  () => normalizeStatusLine(
49763
50280
  initialLine || localBootStatusLine({
49764
50281
  provider,
@@ -49777,7 +50294,7 @@ function useStatusLineText({
49777
50294
  })
49778
50295
  )
49779
50296
  );
49780
- const [refreshTick, setRefreshTick] = useState12(0);
50297
+ const [refreshTick, setRefreshTick] = useState13(0);
49781
50298
  const statuslineArgsRef = useRef19(null);
49782
50299
  const bootFullDoneRef = useRef19(false);
49783
50300
  const mountAtRef = useRef19(Date.now());
@@ -49827,13 +50344,13 @@ function useStatusLineText({
49827
50344
  String(statsForSignature.currentContextSource || "")
49828
50345
  ].join("|");
49829
50346
  const refreshMs = hasActiveStatuslineWork(line, agentWorkers, agentJobs, activeTools) ? STATUSLINE_ACTIVE_REFRESH_MS : STATUSLINE_REFRESH_MS;
49830
- useEffect17(() => {
50347
+ useEffect18(() => {
49831
50348
  scheduleStatuslineModulePrewarm();
49832
50349
  }, []);
49833
50350
  useSharedTick(refreshMs, true, () => {
49834
50351
  setRefreshTick((tick) => (tick + 1) % 1e6);
49835
50352
  });
49836
- useEffect17(() => {
50353
+ useEffect18(() => {
49837
50354
  let alive = true;
49838
50355
  let bootRetryTimer = null;
49839
50356
  const effectId = renderEffectIdRef.current + 1;
@@ -50022,7 +50539,7 @@ function StatusLineView({
50022
50539
  var StatusLine = React11.memo(StatusLineView);
50023
50540
 
50024
50541
  // src/tui/components/PromptInput.jsx
50025
- import { useEffect as useEffect18, useLayoutEffect as useLayoutEffect4, useState as useState13, useRef as useRef20 } from "react";
50542
+ import { useEffect as useEffect19, useLayoutEffect as useLayoutEffect4, useState as useState14, useRef as useRef20 } from "react";
50026
50543
 
50027
50544
  // src/tui/input-editing.mjs
50028
50545
  var graphemeSegmenter4 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
@@ -50725,6 +51242,11 @@ function gridSelectionActive(suppressShiftNavRef) {
50725
51242
  if (typeof suppressShiftNavRef?.current === "function") return suppressShiftNavRef.current();
50726
51243
  return Boolean(suppressShiftNavRef?.current);
50727
51244
  }
51245
+ function paletteResultDraft(result) {
51246
+ if (typeof result === "string") return { value: result, cursor: result.length, selectionAnchor: null };
51247
+ if (typeof result?.value === "string") return { value: result.value, cursor: result.cursor, selectionAnchor: null };
51248
+ return null;
51249
+ }
50728
51250
  function createPromptKeyHandler(ctx) {
50729
51251
  const {
50730
51252
  disabled,
@@ -50738,6 +51260,7 @@ function createPromptKeyHandler(ctx) {
50738
51260
  submitDraft,
50739
51261
  commandPaletteActive,
50740
51262
  commandPaletteOptionCount,
51263
+ commandPaletteMovesCaret,
50741
51264
  onCommandPaletteNavigate,
50742
51265
  onCommandPaletteAccept,
50743
51266
  onCommandPaletteComplete,
@@ -50818,8 +51341,11 @@ function createPromptKeyHandler(ctx) {
50818
51341
  return;
50819
51342
  }
50820
51343
  if (commandPaletteActive) {
50821
- const accepted = onCommandPaletteAccept?.(draftRef.current.value);
50822
- if (accepted !== false) {
51344
+ const accepted = onCommandPaletteAccept?.(draftRef.current.value, draftRef.current.cursor);
51345
+ const replacement = paletteResultDraft(accepted);
51346
+ if (replacement) {
51347
+ commitDraft(replacement);
51348
+ } else if (accepted !== false) {
50823
51349
  commitDraft({ value: "", cursor: 0, selectionAnchor: null });
50824
51350
  }
50825
51351
  return;
@@ -50898,10 +51424,10 @@ ${d.value.slice(d.cursor)}`,
50898
51424
  }
50899
51425
  if (key.tab) {
50900
51426
  if (commandPaletteActive) {
50901
- const completed = onCommandPaletteComplete?.(draftRef.current.value);
50902
- if (typeof completed === "string") {
50903
- commitDraft({ value: completed, cursor: completed.length, selectionAnchor: null });
50904
- }
51427
+ const completed = paletteResultDraft(
51428
+ onCommandPaletteComplete?.(draftRef.current.value, draftRef.current.cursor)
51429
+ );
51430
+ if (completed) commitDraft(completed);
50905
51431
  return;
50906
51432
  }
50907
51433
  if (onTab?.(draftRef.current.value) === true) return;
@@ -50911,7 +51437,7 @@ ${d.value.slice(d.cursor)}`,
50911
51437
  return;
50912
51438
  }
50913
51439
  if (key.leftArrow || rawShiftLeft) {
50914
- if (commandPaletteActive) {
51440
+ if (commandPaletteActive && !commandPaletteMovesCaret) {
50915
51441
  onCommandPaletteNavigate?.("left");
50916
51442
  return;
50917
51443
  }
@@ -50921,7 +51447,7 @@ ${d.value.slice(d.cursor)}`,
50921
51447
  return;
50922
51448
  }
50923
51449
  if (key.rightArrow || rawShiftRight) {
50924
- if (commandPaletteActive) {
51450
+ if (commandPaletteActive && !commandPaletteMovesCaret) {
50925
51451
  onCommandPaletteNavigate?.("right");
50926
51452
  return;
50927
51453
  }
@@ -51128,6 +51654,8 @@ function PromptInput({
51128
51654
  commandPaletteActive = false,
51129
51655
  commandPaletteOpen = commandPaletteActive,
51130
51656
  commandPaletteOptionCount = commandPaletteActive ? 2 : 0,
51657
+ commandPaletteMovesCaret = false,
51658
+ onCaretChange,
51131
51659
  mask = false,
51132
51660
  hint = "",
51133
51661
  hintTone = "info",
@@ -51150,13 +51678,14 @@ function PromptInput({
51150
51678
  mouseSelectionRef,
51151
51679
  suppressShiftNavRef
51152
51680
  }) {
51153
- const [draft, setDraft] = useState13(() => {
51681
+ const [draft, setDraft] = useState14(() => {
51154
51682
  const value2 = String(initialValue || "");
51155
51683
  return { value: value2, cursor: value2.length, selectionAnchor: null };
51156
51684
  });
51157
- const [, bumpCursorAnchorEpoch] = useState13(0);
51685
+ const [, bumpCursorAnchorEpoch] = useState14(0);
51158
51686
  const draftRef = useRef20(draft);
51159
51687
  const lastReportedValueRef = useRef20(draft.value);
51688
+ const lastReportedCursorRef = useRef20(null);
51160
51689
  const pasteGenerationRef = useRef20(0);
51161
51690
  const submitGateRef = useRef20(false);
51162
51691
  const escapeClearAtRef = useRef20(0);
@@ -51199,7 +51728,7 @@ function PromptInput({
51199
51728
  flush: flushImmediate
51200
51729
  });
51201
51730
  };
51202
- useEffect18(
51731
+ useEffect19(
51203
51732
  () => () => {
51204
51733
  cancelPromptImmediateFlush(flushThrottleRef.current);
51205
51734
  },
@@ -51226,8 +51755,15 @@ function PromptInput({
51226
51755
  lastReportedValueRef.current = next.value;
51227
51756
  onDraftChange?.(next.value);
51228
51757
  }
51758
+ reportCaret(next.cursor);
51229
51759
  if (valueRef) valueRef.current = next.value;
51230
51760
  };
51761
+ function reportCaret(nextCursor) {
51762
+ if (nextCursor === lastReportedCursorRef.current) return;
51763
+ lastReportedCursorRef.current = nextCursor;
51764
+ onCaretChange?.(nextCursor);
51765
+ }
51766
+ useEffect19(() => reportCaret(draftRef.current.cursor), []);
51231
51767
  const installCursorAnchor = () => {
51232
51768
  if (!boxRef.current || boxRef.current.internal_cursorAnchor) return false;
51233
51769
  boxRef.current.internal_cursorAnchor = createCursorAnchor({
@@ -51250,7 +51786,7 @@ function PromptInput({
51250
51786
  commitDraft
51251
51787
  });
51252
51788
  }
51253
- useEffect18(
51789
+ useEffect19(
51254
51790
  () => () => {
51255
51791
  const state = mouseExtendCoalesceRef.current;
51256
51792
  if (state.timer) clearTimeout(state.timer);
@@ -51308,7 +51844,7 @@ function PromptInput({
51308
51844
  apply(handled);
51309
51845
  }
51310
51846
  };
51311
- useEffect18(() => {
51847
+ useEffect19(() => {
51312
51848
  if (!draftOverride || typeof draftOverride.value !== "string") return;
51313
51849
  pasteGenerationRef.current += 1;
51314
51850
  const nextValue = draftOverride.value;
@@ -51317,7 +51853,7 @@ function PromptInput({
51317
51853
  commitDraft({ value: nextValue, cursor: nextCursor, selectionAnchor: nextAnchor }, { skipHistory: true });
51318
51854
  undoStack.reset();
51319
51855
  }, [draftOverride?.id, draftOverride?.value, draftOverride?.cursor, draftOverride?.selectionAnchor]);
51320
- useEffect18(
51856
+ useEffect19(
51321
51857
  () => () => {
51322
51858
  pasteGenerationRef.current += 1;
51323
51859
  if (selectionRef) selectionRef.current = null;
@@ -51346,8 +51882,11 @@ function PromptInput({
51346
51882
  const current = draftRef.current;
51347
51883
  const next = prefix ? insertText(current, prefix) : current;
51348
51884
  if (commandPaletteActive) {
51349
- const accepted = onCommandPaletteAccept?.(next.value);
51350
- if (accepted !== false) {
51885
+ const accepted = onCommandPaletteAccept?.(next.value, next.cursor);
51886
+ const replacement = paletteResultDraft(accepted);
51887
+ if (replacement) {
51888
+ commitDraft(replacement);
51889
+ } else if (accepted !== false) {
51351
51890
  commitDraft({ value: "", cursor: 0, selectionAnchor: null });
51352
51891
  } else if (next !== current) {
51353
51892
  commitDraft(next);
@@ -51376,6 +51915,7 @@ function PromptInput({
51376
51915
  commandPaletteActive,
51377
51916
  commandPaletteOpen,
51378
51917
  commandPaletteOptionCount,
51918
+ commandPaletteMovesCaret,
51379
51919
  onCommandPaletteNavigate,
51380
51920
  onCommandPaletteAccept,
51381
51921
  onCommandPaletteCancel,
@@ -51767,20 +52307,20 @@ function usePickerInput({
51767
52307
  }
51768
52308
 
51769
52309
  // src/tui/components/picker/use-picker-selection.mjs
51770
- import { useEffect as useEffect19, useRef as useRef21, useState as useState14 } from "react";
52310
+ import { useEffect as useEffect20, useRef as useRef21, useState as useState15 } from "react";
51771
52311
  function usePickerSelection({ items, initialIndex, onHighlight, confirmButtons, confirmBar }) {
51772
- const [selectedIndex, setSelectedIndex] = useState14(() => clampItemIndex(initialIndex, items.length));
51773
- const [confirmFocus, setConfirmFocus] = useState14(-1);
52312
+ const [selectedIndex, setSelectedIndex] = useState15(() => clampItemIndex(initialIndex, items.length));
52313
+ const [confirmFocus, setConfirmFocus] = useState15(-1);
51774
52314
  const lastTabAtRef = useRef21(0);
51775
- useEffect19(() => {
52315
+ useEffect20(() => {
51776
52316
  setConfirmFocus(-1);
51777
52317
  }, [confirmButtons.length, confirmBar]);
51778
- const [selectionMemo] = useState14(() => ({ value: null, initialIndex }));
51779
- useEffect19(() => {
52318
+ const [selectionMemo] = useState15(() => ({ value: null, initialIndex }));
52319
+ useEffect20(() => {
51780
52320
  const item = items[selectedIndex];
51781
52321
  if (item && item.value != null) selectionMemo.value = item.value;
51782
52322
  }, [items, selectedIndex, selectionMemo]);
51783
- useEffect19(() => {
52323
+ useEffect20(() => {
51784
52324
  setSelectedIndex((i) => {
51785
52325
  if (selectionMemo.value != null) {
51786
52326
  const found = items.findIndex((entry) => entry && entry.value === selectionMemo.value);
@@ -51791,7 +52331,7 @@ function usePickerSelection({ items, initialIndex, onHighlight, confirmButtons,
51791
52331
  return Math.min(Math.max(0, i), Math.max(0, items.length - 1));
51792
52332
  });
51793
52333
  }, [items, selectionMemo, initialIndex]);
51794
- useEffect19(() => {
52334
+ useEffect20(() => {
51795
52335
  if (initialIndex == null) {
51796
52336
  selectionMemo.initialIndex = null;
51797
52337
  return;
@@ -51800,7 +52340,7 @@ function usePickerSelection({ items, initialIndex, onHighlight, confirmButtons,
51800
52340
  selectionMemo.initialIndex = initialIndex;
51801
52341
  setSelectedIndex(clampItemIndex(initialIndex, items.length));
51802
52342
  }, [initialIndex, items.length, selectionMemo]);
51803
- useEffect19(() => {
52343
+ useEffect20(() => {
51804
52344
  if (typeof onHighlight !== "function") return;
51805
52345
  const item = items[selectedIndex];
51806
52346
  if (item) onHighlight(item.value, item, selectedIndex);
@@ -52048,12 +52588,21 @@ function queryMatchesAlias(command, query) {
52048
52588
  );
52049
52589
  }
52050
52590
  function commandDisplayLabel(command, query) {
52591
+ if (command?.label) return command.label;
52051
52592
  const usage = String(command?.usage || command?.name || "").replace(/^\/+/, "");
52052
52593
  const aliasText = command?.showAliasUsage !== false && queryMatchesAlias(command, query) && Array.isArray(command?.aliasUsage) && command.aliasUsage.length > 0 ? ` (${command.aliasUsage.join(", ")})` : "";
52053
52594
  const label = ACRONYM_LABELS.get(usage.toLowerCase()) || (usage ? `${usage.charAt(0).toUpperCase()}${usage.slice(1)}` : usage);
52054
52595
  return `${label}${aliasText}`;
52055
52596
  }
52056
- function SlashCommandPalette({ commands: commands2, selectedIndex = 0, title = "Commands", columns = 80, query = "" }) {
52597
+ function SlashCommandPalette({
52598
+ commands: commands2,
52599
+ selectedIndex = 0,
52600
+ title = "Commands",
52601
+ columns = 80,
52602
+ query = "",
52603
+ description: descriptionText = SLASH_DESCRIPTION,
52604
+ help: helpText = SLASH_HELP
52605
+ }) {
52057
52606
  const total = commands2.length;
52058
52607
  const half = Math.floor(MAX_VISIBLE2 / 2);
52059
52608
  let start = Math.max(0, selectedIndex - half);
@@ -52066,9 +52615,9 @@ function SlashCommandPalette({ commands: commands2, selectedIndex = 0, title = "
52066
52615
  const blankRows = Math.max(0, MAX_VISIBLE2 - visible.length - (noMatches ? 1 : 0));
52067
52616
  const labelWidth = Math.min(COMMAND_LABEL_WIDTH, Math.max(12, Math.floor(columns * 0.45)));
52068
52617
  const descriptionWidth = Math.max(0, columns - labelWidth - 12);
52069
- const description = truncatePanelText(SLASH_DESCRIPTION, Math.max(0, columns - 4));
52618
+ const description = truncatePanelText(descriptionText, Math.max(0, columns - 4));
52070
52619
  const titleWidth = stringWidth9(String(title || ""));
52071
- const help = truncatePanelText(SLASH_HELP, Math.max(0, columns - titleWidth - 7));
52620
+ const help = truncatePanelText(helpText, Math.max(0, columns - titleWidth - 7));
52072
52621
  return /* @__PURE__ */ jsx11(Box_default, { flexDirection: "column", flexShrink: 0, width: "100%", children: /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: theme.promptBorder, paddingX: 1, width: "100%", children: [
52073
52622
  /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "row", justifyContent: "space-between", children: [
52074
52623
  /* @__PURE__ */ jsx11(Text, { color: theme.panelTitle, wrap: "truncate", children: title }),
@@ -52109,7 +52658,7 @@ var CommandRow = React13.memo(function CommandRow2({ command, isSelected, labelW
52109
52658
  import stringWidth11 from "string-width";
52110
52659
 
52111
52660
  // src/tui/components/ContextInspector.jsx
52112
- import { useEffect as useEffect20, useRef as useRef22, useState as useState15 } from "react";
52661
+ import { useEffect as useEffect21, useRef as useRef22, useState as useState16 } from "react";
52113
52662
  import wrapAnsi4 from "wrap-ansi";
52114
52663
  import stringWidth10 from "string-width";
52115
52664
 
@@ -52170,13 +52719,13 @@ function fitLine2(text, width) {
52170
52719
  return result;
52171
52720
  }
52172
52721
  function ContextInspector({ inspection, columns, rows: rows2 = 16, windowTokens, onInspect, onRefresh }) {
52173
- const [category, setCategory] = useState15("");
52174
- const [index, setIndex] = useState15(0);
52175
- const [preview, setPreview] = useState15(null);
52176
- const [scroll, setScroll] = useState15(0);
52177
- const [fit, setFit] = useState15(false);
52722
+ const [category, setCategory] = useState16("");
52723
+ const [index, setIndex] = useState16(0);
52724
+ const [preview, setPreview] = useState16(null);
52725
+ const [scroll, setScroll] = useState16(0);
52726
+ const [fit, setFit] = useState16(false);
52178
52727
  const request = useRef22(0);
52179
- useEffect20(
52728
+ useEffect21(
52180
52729
  () => () => {
52181
52730
  request.current += 1;
52182
52731
  },
@@ -52542,7 +53091,7 @@ function ContextPanel({
52542
53091
  }
52543
53092
 
52544
53093
  // src/tui/components/UsagePanel.jsx
52545
- import { useEffect as useEffect21, useState as useState16 } from "react";
53094
+ import { useEffect as useEffect22, useState as useState17 } from "react";
52546
53095
  import stringWidth12 from "string-width";
52547
53096
 
52548
53097
  // src/session-runtime/services/usage-dashboard-model.mjs
@@ -52758,11 +53307,11 @@ function UsagePanel({ dashboard, loading = false, columns = 80, fillHeight = fal
52758
53307
  const hasMeasuredRows = Number(panelRows) > 0;
52759
53308
  const maxProviderRows = hasMeasuredRows ? Math.max(1, Math.floor(panelRows) - 6) : rows2.length;
52760
53309
  const maxScrollOffset = Math.max(0, rows2.length - maxProviderRows);
52761
- const [scrollOffset, setScrollOffset] = useState16(0);
53310
+ const [scrollOffset, setScrollOffset] = useState17(0);
52762
53311
  const visibleRows = hasMeasuredRows ? rows2.slice(scrollOffset, scrollOffset + maxProviderRows) : rows2;
52763
53312
  const scrollable = rows2.length > maxProviderRows;
52764
53313
  const helpText = `${scrollable || isLoading || isChecking ? "\u2191/\u2193 Scroll \xB7 PgUp/PgDn Page \xB7 " : ""}Esc Back \xB7 /usage refresh`;
52765
- useEffect21(() => {
53314
+ useEffect22(() => {
52766
53315
  setScrollOffset((offset) => Math.min(Math.max(0, offset), maxScrollOffset));
52767
53316
  }, [maxScrollOffset]);
52768
53317
  use_input_default((_input, key) => {
@@ -52841,7 +53390,7 @@ function UsagePanel({ dashboard, loading = false, columns = 80, fillHeight = fal
52841
53390
  }
52842
53391
 
52843
53392
  // src/tui/components/TextEntryPanel.jsx
52844
- import { useEffect as useEffect22, useLayoutEffect as useLayoutEffect5, useRef as useRef23, useState as useState17 } from "react";
53393
+ import { useEffect as useEffect23, useLayoutEffect as useLayoutEffect5, useRef as useRef23, useState as useState18 } from "react";
52845
53394
  import stringWidth14 from "string-width";
52846
53395
 
52847
53396
  // src/tui/components/text-entry-layout.mjs
@@ -52996,12 +53545,12 @@ function TextEntryPanel({
52996
53545
  onSubmit,
52997
53546
  onCancel
52998
53547
  }) {
52999
- const [draft, setDraft] = useState17(() => ({
53548
+ const [draft, setDraft] = useState18(() => ({
53000
53549
  value: String(initialValue || ""),
53001
53550
  cursor: String(initialValue || "").length,
53002
53551
  selectionAnchor: null
53003
53552
  }));
53004
- const [, bumpCursorAnchorEpoch] = useState17(0);
53553
+ const [, bumpCursorAnchorEpoch] = useState18(0);
53005
53554
  const draftRef = useRef23(draft);
53006
53555
  const submitGateRef = useRef23(false);
53007
53556
  const boxRef = useRef23(null);
@@ -53030,13 +53579,13 @@ function TextEntryPanel({
53030
53579
  commitDraft(fn(draftRef.current), options);
53031
53580
  };
53032
53581
  const moveDraftVertically = createVerticalMover({ draftRef, contentWidthRef, preferredColumnRef, commitDraft });
53033
- useEffect22(() => {
53582
+ useEffect23(() => {
53034
53583
  const value = String(initialValue || "");
53035
53584
  commitDraft({ value, cursor: value.length, selectionAnchor: null });
53036
53585
  }, [title, initialValue]);
53037
53586
  const labelCells = stringWidth14(String(promptLabel || ""));
53038
53587
  const contentCells = Math.max(1, columns - 4 - labelCells);
53039
- useEffect22(() => {
53588
+ useEffect23(() => {
53040
53589
  if (!multiline) {
53041
53590
  onContentRowsChange?.(1);
53042
53591
  return;
@@ -53319,6 +53868,10 @@ function settingsPromptFields(kind) {
53319
53868
 
53320
53869
  // src/tui/app/app-view/floating-panel.jsx
53321
53870
  import { jsx as jsx16 } from "react/jsx-runtime";
53871
+ var SKILL_PALETTE_TEXT = {
53872
+ description: "Type to filter \xB7 Enter or Tab inserts the highlighted skill.",
53873
+ help: "\u2191/\u2193 select \xB7 Enter insert \xB7 Esc cancel"
53874
+ };
53322
53875
  function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionPanel }) {
53323
53876
  const resolve3 = (approved) => {
53324
53877
  store.resolveToolApproval?.(toolApproval.id, {
@@ -53465,14 +54018,16 @@ function renderFloatingPanel(ctx) {
53465
54018
  );
53466
54019
  }
53467
54020
  if (slashPaletteOpen) {
54021
+ const skills = ctx.paletteKind === "skills";
53468
54022
  return /* @__PURE__ */ jsx16(
53469
54023
  SlashCommandPalette,
53470
54024
  {
53471
54025
  commands: slashCommands,
53472
54026
  selectedIndex: slashIndex,
53473
- title: "Commands",
54027
+ title: skills ? "Skills" : "Commands",
53474
54028
  columns: frameColumns,
53475
- query: activeSlashQuery
54029
+ query: activeSlashQuery,
54030
+ ...skills ? SKILL_PALETTE_TEXT : {}
53476
54031
  }
53477
54032
  );
53478
54033
  }
@@ -53809,10 +54364,13 @@ var UserMessage = React16.memo(function UserMessage2({
53809
54364
  text,
53810
54365
  attached = false,
53811
54366
  columns,
54367
+ appliedSkills,
53812
54368
  themeEpoch: _themeEpoch = 0
53813
54369
  }) {
53814
54370
  const bandColumns = Math.max(1, columns - 1);
53815
- return /* @__PURE__ */ jsx20(
54371
+ const skillsLine = appliedSkillsLine(appliedSkills);
54372
+ const segments = userTextSegments(text, appliedSkills);
54373
+ return /* @__PURE__ */ jsxs15(
53816
54374
  Box_default,
53817
54375
  {
53818
54376
  flexDirection: "column",
@@ -53821,7 +54379,12 @@ var UserMessage = React16.memo(function UserMessage2({
53821
54379
  backgroundColor: theme.userMessageBackground,
53822
54380
  paddingLeft: 2,
53823
54381
  paddingRight: 1,
53824
- children: /* @__PURE__ */ jsx20(Text, { color: theme.mixdogIvory, wrap: "wrap", children: text })
54382
+ children: [
54383
+ /* @__PURE__ */ jsx20(Text, { color: theme.mixdogIvory, wrap: "wrap", children: segments.length === 1 && !segments[0].mention ? text : segments.map(
54384
+ (segment, index) => segment.mention ? /* @__PURE__ */ jsx20(Text, { color: theme.panelTitle, bold: true, children: segment.text }, index) : segment.text
54385
+ ) }),
54386
+ skillsLine ? /* @__PURE__ */ jsx20(Text, { color: theme.subtle, wrap: "wrap", children: skillsLine }) : null
54387
+ ]
53825
54388
  }
53826
54389
  );
53827
54390
  });
@@ -54384,7 +54947,16 @@ var Item = React17.memo(function Item2({
54384
54947
  let node = null;
54385
54948
  switch (item.kind) {
54386
54949
  case "user":
54387
- node = /* @__PURE__ */ jsx27(UserMessage, { text: item.text, attached: prevKind === "user", columns, themeEpoch });
54950
+ node = /* @__PURE__ */ jsx27(
54951
+ UserMessage,
54952
+ {
54953
+ text: item.text,
54954
+ attached: prevKind === "user",
54955
+ columns,
54956
+ appliedSkills: item.appliedSkills,
54957
+ themeEpoch
54958
+ }
54959
+ );
54388
54960
  break;
54389
54961
  case "assistant":
54390
54962
  node = /* @__PURE__ */ jsx27(
@@ -54681,8 +55253,10 @@ function renderAppView(ctx) {
54681
55253
  inputHint,
54682
55254
  inputHintTone,
54683
55255
  liveSpinner,
55256
+ onPromptCaretChange,
54684
55257
  onPromptDraftChange,
54685
55258
  onSubmit,
55259
+ paletteKind,
54686
55260
  panelTransitionClearRows,
54687
55261
  picker,
54688
55262
  promptBoxRectRef,
@@ -54715,6 +55289,7 @@ function renderAppView(ctx) {
54715
55289
  onSubmit,
54716
55290
  disabled: exiting || !!picker || !!contextPanel || !!toolApproval || !tuiReady,
54717
55291
  onDraftChange: onPromptDraftChange,
55292
+ onCaretChange: onPromptCaretChange,
54718
55293
  interruptActive: state.busy,
54719
55294
  onInterrupt: handlePromptInterrupt,
54720
55295
  initialValue: promptDraft,
@@ -54734,6 +55309,7 @@ function renderAppView(ctx) {
54734
55309
  commandPaletteActive: slashPaletteOpen && slashCommands.length > 0,
54735
55310
  commandPaletteOpen: slashPaletteOpen,
54736
55311
  commandPaletteOptionCount: slashCommands.length,
55312
+ commandPaletteMovesCaret: paletteKind === "skills",
54737
55313
  onCommandPaletteNavigate: (direction) => {
54738
55314
  setSlashIndex((index) => stepPaletteIndex(index, direction, slashCommands.length));
54739
55315
  },
@@ -55013,9 +55589,10 @@ function usePromptDraftFlow({
55013
55589
  [settingsPrompt, setSettingsPrompt, openProjectPicker, openMemoryCorePicker, openAutoClearPicker]
55014
55590
  );
55015
55591
  const acceptSlashPalette = useCallback18(
55016
- (draftValue = "") => {
55592
+ (draftValue = "", caret) => {
55017
55593
  const command = slashCommands[slashIndex];
55018
55594
  if (!command) return false;
55595
+ if (command.kind === "skill") return completeSkillMention(draftValue, command.name, caret) ?? false;
55019
55596
  return withPickerEnterLatch(
55020
55597
  pickerOpenedFromEnterRef,
55021
55598
  pickerOpenedFromEnterTimerRef,
@@ -55025,9 +55602,10 @@ function usePromptDraftFlow({
55025
55602
  [slashCommands, slashIndex, pickerOpenedFromEnterRef, pickerOpenedFromEnterTimerRef, runSlashCommand]
55026
55603
  );
55027
55604
  const completeSlashPalette = useCallback18(
55028
- (draftValue = "") => {
55605
+ (draftValue = "", caret) => {
55029
55606
  const command = slashCommands[slashIndex];
55030
55607
  if (!command) return void 0;
55608
+ if (command.kind === "skill") return completeSkillMention(draftValue, command.name, caret);
55031
55609
  const token = slashCommandTokenForPaletteAccept(command, draftValue);
55032
55610
  return token ? `/${token} ` : void 0;
55033
55611
  },
@@ -55634,32 +56212,45 @@ function createMcpServersPicker({ store, theme: theme2, surface, getPicker, setP
55634
56212
  }
55635
56213
 
55636
56214
  // src/tui/app/extension-pickers/plugins-pickers.mjs
56215
+ function mcpNames(p) {
56216
+ if (Array.isArray(p.mcpServers)) return p.mcpServers.map((server) => server.name);
56217
+ return p.mcpServerName ? [p.mcpServerName] : [];
56218
+ }
56219
+ var hasMcp = (p) => mcpNames(p).length > 0 || Boolean(p.mcpScript || p.mcpInline);
56220
+ function serverState(server) {
56221
+ if (server.serverEnabled === false) return "off";
56222
+ if (server.enabled === false) return "plugin off";
56223
+ return server.status || (server.connected ? "connected" : "disconnected");
56224
+ }
55637
56225
  var mcpSummary = (p) => {
55638
- if (!p.mcpScript) return "(none)";
55639
- const state = p.mcpEnabled ? "enabled" : "available";
55640
- return `${state} (${p.mcpServerName || "plugin-mcp"})`;
56226
+ if (!hasMcp(p))
56227
+ return Array.isArray(p.mcpErrors) && p.mcpErrors.length ? `(invalid: ${p.mcpErrors[0].message})` : "(none)";
56228
+ if (!Array.isArray(p.mcpServers)) return `${p.mcpEnabled ? "enabled" : "available"} (${mcpNames(p).join(", ")})`;
56229
+ const errors = Array.isArray(p.mcpErrors) && p.mcpErrors.length ? ` \xB7 ${p.mcpErrors.length} declaration error(s)` : "";
56230
+ return `${p.mcpServers.map((server) => `${server.name} ${serverState(server)}`).join(", ")}${errors}`;
55641
56231
  };
55642
56232
  function mcpActionItem(p) {
55643
- if (!p.mcpScript) {
56233
+ if (!hasMcp(p)) {
55644
56234
  return {
55645
56235
  value: "enable-mcp",
55646
- label: "No MCP script",
55647
- description: "plugin does not expose scripts/run-mcp.mjs or mcp/server.mjs",
56236
+ label: "No MCP server",
56237
+ description: "plugin declares no MCP servers (.mcp.json or manifest mcpServers)",
55648
56238
  _action: "noop"
55649
56239
  };
55650
56240
  }
55651
56241
  return {
55652
56242
  value: "enable-mcp",
55653
- label: p.mcpEnabled ? "Refresh MCP server" : "Enable MCP server",
55654
- description: `${p.mcpServerName || "plugin-mcp"} \xB7 ${p.mcpEnabled ? "configured" : p.mcpScript}`,
56243
+ label: p.mcpEnabled ? "Reconnect MCP servers" : "Enable MCP servers",
56244
+ description: `${mcpNames(p).join(", ") || "plugin MCP"} \xB7 ${p.mcpEnabled ? "on" : "turned off"}`,
55655
56245
  _action: "enable-mcp"
55656
56246
  };
55657
56247
  }
55658
56248
  function pluginSummary(plugin) {
55659
56249
  const version = plugin.version ? ` \xB7 ${plugin.version}` : "";
55660
- const mcpState = plugin.mcpEnabled ? "enabled" : plugin.mcpScript;
55661
- const mcp = plugin.mcpScript ? ` \xB7 mcp ${mcpState}` : "";
55662
- return `${plugin.sourceType || plugin.source}${version} \xB7 skills ${plugin.skillCount || 0}${mcp}`;
56250
+ const mcpOff = plugin.mcpEnabled ? "" : " off";
56251
+ const mcp = hasMcp(plugin) ? ` \xB7 mcp ${mcpNames(plugin).length || 1}${mcpOff}` : "";
56252
+ const warning = plugin.warning ? ` \xB7 \u26A0 ${plugin.warning}` : "";
56253
+ return `${plugin.sourceType || plugin.source}${version} \xB7 skills ${plugin.skillCount || 0}${mcp}${warning}`;
55663
56254
  }
55664
56255
  var pluginInfoNotice = (p) => [
55665
56256
  `${p.title || p.name}${p.version ? ` ${p.version}` : ""}`,
@@ -55668,6 +56259,7 @@ var pluginInfoNotice = (p) => [
55668
56259
  `mcp: ${mcpSummary(p)}`,
55669
56260
  `applies to: ${Array.isArray(p.scope) && p.scope.length ? p.scope.join(", ") : "all projects"}`,
55670
56261
  `root: ${p.root}`,
56262
+ p.warning ? `warning: ${p.warning}` : "",
55671
56263
  p.description ? `
55672
56264
  ${p.description}` : ""
55673
56265
  ].filter(Boolean).join("\n");
@@ -55693,9 +56285,9 @@ var pluginDetailItems = (p) => [
55693
56285
  },
55694
56286
  {
55695
56287
  value: "copy-mcp-name",
55696
- label: p.mcpScript ? "Copy MCP server name" : "No MCP server name",
55697
- description: p.mcpServerName || "",
55698
- _action: p.mcpScript ? "copy-mcp-name" : "noop"
56288
+ label: mcpNames(p).length ? "Copy MCP server name" : "No MCP server name",
56289
+ description: mcpNames(p).join(", "),
56290
+ _action: mcpNames(p).length ? "copy-mcp-name" : "noop"
55699
56291
  },
55700
56292
  {
55701
56293
  value: "uninstall",
@@ -55735,7 +56327,7 @@ function createPluginsPickers({
55735
56327
  return;
55736
56328
  }
55737
56329
  if (detail._action === "enable-mcp") {
55738
- void store.enablePluginMcp?.(p).then(own.defer(() => openMcpPicker())).catch((e) => store.pushNotice(`plugin MCP enable failed: ${e?.message || e}`, "error"));
56330
+ void store.enablePluginMcp?.(p).then(own.defer(() => openMcpPicker())).catch((e) => store.pushNotice(`plugin MCP reconnect failed: ${e?.message || e}`, "error"));
55739
56331
  return;
55740
56332
  }
55741
56333
  if (detail._action === "copy-root") {
@@ -55743,7 +56335,7 @@ function createPluginsPickers({
55743
56335
  return;
55744
56336
  }
55745
56337
  if (detail._action === "copy-mcp-name") {
55746
- copyText(p.mcpServerName || "", `copied plugin MCP server: ${p.mcpServerName}`);
56338
+ copyText(mcpNames(p).join(", "), `copied plugin MCP server: ${mcpNames(p).join(", ")}`);
55747
56339
  return;
55748
56340
  }
55749
56341
  if (detail._action === "uninstall") {
@@ -56829,6 +57421,7 @@ var PROVIDER_DISPLAY_NAMES = /* @__PURE__ */ new Map([
56829
57421
  ["anthropic-oauth", "Anthropic OAuth"],
56830
57422
  ["grok-oauth", "Grok OAuth"],
56831
57423
  ["muse-code-oauth", "Muse Code"],
57424
+ ["command-code-oauth", "Command Code"],
56832
57425
  ["mimo-oauth", "MiMo"],
56833
57426
  ["cursor-oauth", "Cursor OAuth"],
56834
57427
  ["antigravity-oauth", "Antigravity OAuth"],
@@ -56848,12 +57441,34 @@ var PROVIDER_DISPLAY_NAMES = /* @__PURE__ */ new Map([
56848
57441
  ["default", "Default"]
56849
57442
  ]);
56850
57443
  var providerDisplayName = (provider) => PROVIDER_DISPLAY_NAMES.get(String(provider || "").toLowerCase()) ?? (provider || "Provider");
57444
+ var resolveProviderDisplayName = (provider, providerNames = null) => String(provider || "").trim().startsWith("custom-") && providerNames?.[String(provider).trim()] || providerDisplayName(provider);
57445
+ var loadProviderDisplayNames = async (store) => {
57446
+ let setup = null;
57447
+ try {
57448
+ setup = await store?.getProviderSetup?.();
57449
+ } catch {
57450
+ return {};
57451
+ }
57452
+ const names = {};
57453
+ for (const group of ["api", "oauth", "local"]) {
57454
+ const entries = setup?.[group];
57455
+ if (!Array.isArray(entries)) continue;
57456
+ for (const entry of entries) {
57457
+ if (!entry || typeof entry !== "object") continue;
57458
+ const id = String(entry.id || entry.provider || "").trim();
57459
+ const name = String(entry.name || entry.label || "").trim();
57460
+ if (id && name) names[id] = name;
57461
+ }
57462
+ }
57463
+ return names;
57464
+ };
56851
57465
  var PROVIDER_DISPLAY_RANKS = {
56852
57466
  default: 0,
56853
57467
  "openai-oauth": 10,
56854
57468
  "anthropic-oauth": 20,
56855
57469
  "grok-oauth": 30,
56856
57470
  "muse-code-oauth": 33,
57471
+ "command-code-oauth": 33.5,
56857
57472
  "mimo-oauth": 34,
56858
57473
  "antigravity-oauth": 31,
56859
57474
  "cursor-oauth": 32,
@@ -56887,7 +57502,7 @@ var routeModelDisplayName = (route) => [
56887
57502
  displayModelName(route?.model, route?.provider, route?.modelDisplay || ""),
56888
57503
  route?.provider === DAYBREAK_PROVIDER && daybreakBlueOn(route?.modelParameters) ? "Blue" : ""
56889
57504
  ].filter(Boolean).join(" ");
56890
- var groupModelsByProvider = (models) => {
57505
+ var groupModelsByProvider = (models, providerNames = null) => {
56891
57506
  const providers = /* @__PURE__ */ new Map();
56892
57507
  for (const model of models) {
56893
57508
  if (!providers.has(model.provider)) providers.set(model.provider, []);
@@ -56896,20 +57511,22 @@ var groupModelsByProvider = (models) => {
56896
57511
  const orderedProviders = [...providers.keys()].sort((a, b) => {
56897
57512
  const rank = providerDisplayRank(a) - providerDisplayRank(b);
56898
57513
  if (rank !== 0) return rank;
56899
- const label = providerDisplayName(a).localeCompare(providerDisplayName(b));
57514
+ const label = resolveProviderDisplayName(a, providerNames).localeCompare(
57515
+ resolveProviderDisplayName(b, providerNames)
57516
+ );
56900
57517
  if (label !== 0) return label;
56901
57518
  return a.localeCompare(b);
56902
57519
  });
56903
57520
  return { providers, orderedProviders };
56904
57521
  };
56905
- var buildModelProviderItems = (models, currentRoute = null) => {
56906
- const { providers, orderedProviders } = groupModelsByProvider(models);
57522
+ var buildModelProviderItems = (models, currentRoute = null, providerNames = null) => {
57523
+ const { providers, orderedProviders } = groupModelsByProvider(models, providerNames);
56907
57524
  return orderedProviders.map((provider) => {
56908
57525
  const providerModels = providers.get(provider) || [];
56909
57526
  const currentModel = currentRoute?.provider === provider ? providerModels.find((model) => model.id === currentRoute.model) : null;
56910
57527
  return {
56911
57528
  value: `provider:${provider}`,
56912
- label: providerDisplayName(provider),
57529
+ label: resolveProviderDisplayName(provider, providerNames),
56913
57530
  marker: currentModel ? "\u2713" : "",
56914
57531
  markerColor: theme.success,
56915
57532
  meta: currentModel ? modelRecordDisplayName(currentModel) : "",
@@ -58295,7 +58912,7 @@ function openProviderModelsPicker({ view, provider, onBack, saveRoute }) {
58295
58912
  )
58296
58913
  );
58297
58914
  view.paint({
58298
- title: providerDisplayName(provider),
58915
+ title: resolveProviderDisplayName(provider, view.providerNames),
58299
58916
  description: options.modelDescription || "Select a model. Adjust Effort with \u2190/\u2192.",
58300
58917
  footer: (item) => modelFooter(selection, item?._model),
58301
58918
  help: returnOnNestedCancel && returnTo ? `${MODEL_LIST_HELP} \xB7 Esc ${returnLabel}` : `${MODEL_LIST_HELP} \xB7 Esc Back`,
@@ -58390,6 +59007,7 @@ function createModelPicker({
58390
59007
  return;
58391
59008
  }
58392
59009
  const models = normalizeModelOptions(providerModels);
59010
+ const providerNames = await loadProviderDisplayNames(store);
58393
59011
  const activeRoute = options.currentRoute || {
58394
59012
  provider: state.provider,
58395
59013
  model: state.model,
@@ -58403,6 +59021,7 @@ function createModelPicker({
58403
59021
  state,
58404
59022
  models,
58405
59023
  activeRoute,
59024
+ providerNames,
58406
59025
  returnTo,
58407
59026
  returnLabel,
58408
59027
  returnOnNestedCancel,
@@ -58426,7 +59045,7 @@ function createModelPicker({
58426
59045
  providerListHighlightProvider = renderOptions.highlightProvider;
58427
59046
  }
58428
59047
  const highlightProvider = renderOptions.highlightProvider || providerListHighlightProvider || null;
58429
- const providerItems = buildModelProviderItems(models, activeRoute);
59048
+ const providerItems = buildModelProviderItems(models, activeRoute, providerNames);
58430
59049
  const providerHighlight = highlightProvider || activeRoute?.provider || null;
58431
59050
  const providerInitialIndex = Math.max(
58432
59051
  0,
@@ -59041,7 +59660,7 @@ async function backupUserDataAsync(dataDir2, reason = "snapshot") {
59041
59660
  // src/runtime/shared/provider-api-key.mjs
59042
59661
  import { createRequire as createRequire2 } from "node:module";
59043
59662
  var require2 = createRequire2(import.meta.url);
59044
- var { getSecret, hasSecret } = require2("../../lib/keychain-cjs.cjs");
59663
+ var { getSecret, getSecretAsync, hasSecret } = require2("../../lib/keychain-cjs.cjs");
59045
59664
  var AGENT_PROVIDER_ENV = Object.freeze({
59046
59665
  openai: "OPENAI_API_KEY",
59047
59666
  anthropic: "ANTHROPIC_API_KEY",
@@ -60767,7 +61386,7 @@ function selectableUserItems(items, limit = MAX_SELECTABLE_MESSAGES) {
60767
61386
  for (let index = source.length - 1; index >= 0 && rows2.length < limit; index -= 1) {
60768
61387
  const item = source[index];
60769
61388
  if (item?.kind !== "user") continue;
60770
- if (item?.id == null) continue;
61389
+ if (item?.id == null || item.archived === true) continue;
60771
61390
  const text = String(item.text || "").trim();
60772
61391
  if (!text) continue;
60773
61392
  rows2.push({ id: String(item.id), text });
@@ -60845,7 +61464,7 @@ function useMessageSelector({
60845
61464
  }
60846
61465
 
60847
61466
  // src/tui/app/use-terminal-chrome.mjs
60848
- import { useEffect as useEffect23 } from "react";
61467
+ import { useEffect as useEffect24 } from "react";
60849
61468
 
60850
61469
  // src/tui/keyboard-protocol.mjs
60851
61470
  var ENABLE_KITTY_KEYBOARD = "\x1B[>1u";
@@ -60870,7 +61489,7 @@ function supportsExtendedKeys() {
60870
61489
 
60871
61490
  // src/tui/app/use-terminal-chrome.mjs
60872
61491
  function useTerminalChrome({ stdout: stdout2, isRawModeSupported, setResizeState }) {
60873
- useEffect23(() => {
61492
+ useEffect24(() => {
60874
61493
  if (!stdout2) return void 0;
60875
61494
  let trailing = null;
60876
61495
  const DEBOUNCE_MS = 80;
@@ -60905,7 +61524,7 @@ function useTerminalChrome({ stdout: stdout2, isRawModeSupported, setResizeState
60905
61524
  stdout2.off("resize", onResize);
60906
61525
  };
60907
61526
  }, [stdout2]);
60908
- useEffect23(() => {
61527
+ useEffect24(() => {
60909
61528
  if (!isRawModeSupported || !stdout2?.write) return;
60910
61529
  if (!supportsExtendedKeys()) return;
60911
61530
  try {
@@ -60916,7 +61535,7 @@ function useTerminalChrome({ stdout: stdout2, isRawModeSupported, setResizeState
60916
61535
  }
60917
61536
 
60918
61537
  // src/tui/app/use-transcript-window.mjs
60919
- import { useCallback as useCallback21, useEffect as useEffect25, useLayoutEffect as useLayoutEffect8 } from "react";
61538
+ import { useCallback as useCallback21, useEffect as useEffect26, useLayoutEffect as useLayoutEffect8 } from "react";
60920
61539
 
60921
61540
  // src/tui/session/transcript-spill.mjs
60922
61541
  import { readFileSync as readFileSync15 } from "node:fs";
@@ -61428,7 +62047,7 @@ function overlayHintPlacement(renderedItems, transcriptWindow, { overlayHintRequ
61428
62047
  }
61429
62048
 
61430
62049
  // src/tui/app/use-transcript-window/selection-shift.mjs
61431
- import { useEffect as useEffect24, useLayoutEffect as useLayoutEffect7 } from "react";
62050
+ import { useEffect as useEffect25, useLayoutEffect as useLayoutEffect7 } from "react";
61432
62051
  function useSelectionLayoutShift({
61433
62052
  transcriptWindow,
61434
62053
  transcriptContentHeight,
@@ -61462,7 +62081,7 @@ function useSelectionLayoutShift({
61462
62081
  withSelectionClip,
61463
62082
  paintSelectionRect
61464
62083
  ]);
61465
- useEffect24(() => {
62084
+ useEffect25(() => {
61466
62085
  if (!dragRef.current.rect) return;
61467
62086
  const clippedRect = withSelectionClip(dragRef.current.rect);
61468
62087
  dragRef.current = { ...dragRef.current, rect: clippedRect };
@@ -61602,7 +62221,7 @@ function useTranscriptWindow({
61602
62221
  withSelectionClip,
61603
62222
  paintSelectionRect
61604
62223
  });
61605
- useEffect25(() => {
62224
+ useEffect26(() => {
61606
62225
  clampScrollToOverflow(scrollRefs, {
61607
62226
  maxRows: transcriptWindow.maxScrollRows,
61608
62227
  scrollOffset,
@@ -61960,7 +62579,7 @@ function usePromptHistoryNavigation({
61960
62579
  }
61961
62580
 
61962
62581
  // src/tui/app/prompt-handlers/use-prompt-interrupt.mjs
61963
- import { useCallback as useCallback24, useEffect as useEffect26, useRef as useRef27 } from "react";
62582
+ import { useCallback as useCallback24, useEffect as useEffect27, useRef as useRef27 } from "react";
61964
62583
 
61965
62584
  // src/tui/components/prompt-input/interrupt-policy.mjs
61966
62585
  function promptInterruptRestoreText(result, currentText = "") {
@@ -62005,7 +62624,7 @@ function usePromptInterrupt({
62005
62624
  },
62006
62625
  [store, promptValueRef, restoreAttachments, clearPromptHint, syncPromptLayoutRows, setPromptDraftOverride]
62007
62626
  );
62008
- useEffect26(() => {
62627
+ useEffect27(() => {
62009
62628
  const pending = pendingRestoreRef.current;
62010
62629
  if (!pending) return;
62011
62630
  if (commitAsyncRestore(pending)) pendingRestoreRef.current = null;
@@ -62256,7 +62875,7 @@ function usePromptHandlers({
62256
62875
  }
62257
62876
 
62258
62877
  // src/tui/app/use-model-catalog-cache.mjs
62259
- import { useCallback as useCallback27, useEffect as useEffect27, useRef as useRef28 } from "react";
62878
+ import { useCallback as useCallback27, useEffect as useEffect28, useRef as useRef28 } from "react";
62260
62879
  function useModelCatalogCache({ store, onboardingRef }) {
62261
62880
  const providerModelsCacheRef = useRef28({ models: null, at: 0 });
62262
62881
  const webSearchModelsCacheRef = useRef28({ models: null, at: 0 });
@@ -62272,7 +62891,7 @@ function useModelCatalogCache({ store, onboardingRef }) {
62272
62891
  webSearchModelsCacheRef.current = { models: null, at: 0 };
62273
62892
  }
62274
62893
  }, []);
62275
- useEffect27(() => {
62894
+ useEffect28(() => {
62276
62895
  let alive = true;
62277
62896
  const timer2 = setTimeout(async () => {
62278
62897
  const seq = onboardingPrefetchSeqRef.current;
@@ -62308,10 +62927,10 @@ function useModelCatalogCache({ store, onboardingRef }) {
62308
62927
  }
62309
62928
 
62310
62929
  // src/tui/app/use-disabled-skills.mjs
62311
- import { useCallback as useCallback28, useEffect as useEffect28, useState as useState18 } from "react";
62930
+ import { useCallback as useCallback28, useEffect as useEffect29, useState as useState19 } from "react";
62312
62931
  function useDisabledSkills({ store }) {
62313
- const [disabledSkills, setDisabledSkillsInner] = useState18(() => /* @__PURE__ */ new Set());
62314
- useEffect28(() => {
62932
+ const [disabledSkills, setDisabledSkillsInner] = useState19(() => /* @__PURE__ */ new Set());
62933
+ useEffect29(() => {
62315
62934
  let alive = true;
62316
62935
  void Promise.resolve(store.getDisabledSkills?.()).then((result) => {
62317
62936
  if (!alive) return;
@@ -62345,7 +62964,7 @@ function useDisabledSkills({ store }) {
62345
62964
  }
62346
62965
 
62347
62966
  // src/tui/app/use-onboarding-start.mjs
62348
- import { useEffect as useEffect29 } from "react";
62967
+ import { useEffect as useEffect30 } from "react";
62349
62968
  function resolveOnboardingCompleted(store, onboardingCompleted) {
62350
62969
  if (typeof onboardingCompleted === "boolean") return onboardingCompleted;
62351
62970
  try {
@@ -62364,7 +62983,7 @@ function useOnboardingStart({
62364
62983
  setOnboardingActive,
62365
62984
  openOnboardingAuthStep
62366
62985
  }) {
62367
- useEffect29(() => {
62986
+ useEffect30(() => {
62368
62987
  if (onboardingStartedRef.current) return void 0;
62369
62988
  if (resolveOnboardingCompleted(store, onboardingCompleted) && !forceOnboarding) return void 0;
62370
62989
  let canceled = false;
@@ -62382,17 +63001,17 @@ function useOnboardingStart({
62382
63001
  // src/tui/App.jsx
62383
63002
  function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardingCompleted = void 0 }) {
62384
63003
  const state = useSession(store);
62385
- const [toolOutputExpanded, setToolOutputExpanded] = useState19(false);
62386
- const [onboardingActive, setOnboardingActive] = useState19(false);
63004
+ const [toolOutputExpanded, setToolOutputExpanded] = useState20(false);
63005
+ const [onboardingActive, setOnboardingActive] = useState20(false);
62387
63006
  const { exit } = use_app_default();
62388
63007
  const { isRawModeSupported, internal_eventEmitter: inkInput } = use_stdin_default();
62389
63008
  const { stdout: stdout2 } = use_stdout_default();
62390
- const [exiting, setExiting] = useState19(false);
62391
- const [tuiReady, setTuiReady] = useState19(false);
63009
+ const [exiting, setExiting] = useState20(false);
63010
+ const [tuiReady, setTuiReady] = useState20(false);
62392
63011
  const exitRequestedRef = useRef29(false);
62393
- const [resizeState, setResizeState] = useState19(() => ({ ...terminalSize2(stdout2), epoch: 0 }));
62394
- const [panelTransitionEpoch, setPanelTransitionEpoch] = useState19(0);
62395
- const [panelInkMaskEpoch, setPanelInkMaskEpoch] = useState19(0);
63012
+ const [resizeState, setResizeState] = useState20(() => ({ ...terminalSize2(stdout2), epoch: 0 }));
63013
+ const [panelTransitionEpoch, setPanelTransitionEpoch] = useState20(0);
63014
+ const [panelInkMaskEpoch, setPanelInkMaskEpoch] = useState20(0);
62396
63015
  const rightSafetyColumns = 1;
62397
63016
  const frameColumns = Math.max(1, resizeState.columns - rightSafetyColumns);
62398
63017
  const {
@@ -62414,7 +63033,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62414
63033
  const pickerOpenedFromEnterRef = useRef29(false);
62415
63034
  const pickerOpenedFromEnterTimerRef = useRef29(null);
62416
63035
  const projectPickerRef = useRef29(null);
62417
- const [picker, setPickerState] = useState19(null);
63036
+ const [picker, setPickerState] = useState20(null);
62418
63037
  const livePickerRef = useRef29(null);
62419
63038
  const setPicker = useCallback29((next) => {
62420
63039
  const previousPicker = livePickerRef.current;
@@ -62428,8 +63047,8 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62428
63047
  );
62429
63048
  }, []);
62430
63049
  livePickerRef.current = picker;
62431
- const [contextPanel, setContextPanel] = useState19(null);
62432
- const [usagePanel, setUsagePanel] = useState19(null);
63050
+ const [contextPanel, setContextPanel] = useState20(null);
63051
+ const [usagePanel, setUsagePanel] = useState20(null);
62433
63052
  const surfaceRef = useRef29(null);
62434
63053
  if (!surfaceRef.current) {
62435
63054
  surfaceRef.current = createPanelSurface({ setPicker, setContextPanel, setUsagePanel });
@@ -62438,9 +63057,9 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62438
63057
  const settingsHeavyCacheRef = useRef29(null);
62439
63058
  const settingsRequestRef = useRef29(0);
62440
63059
  const closeUsagePanel = useCallback29(() => surface.closeUsage(), [surface]);
62441
- const [providerPrompt, setProviderPrompt] = useState19(null);
63060
+ const [providerPrompt, setProviderPrompt] = useState20(null);
62442
63061
  const oauthSubmitRef = useRef29(false);
62443
- const [settingsPrompt, setSettingsPrompt] = useState19(null);
63062
+ const [settingsPrompt, setSettingsPrompt] = useState20(null);
62444
63063
  const projectPicker = createProjectPicker({
62445
63064
  state,
62446
63065
  store,
@@ -62460,7 +63079,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62460
63079
  setPicker(projectPicker.buildProjectPickerState({ initialEntry: true, loading: true }));
62461
63080
  }
62462
63081
  }
62463
- useEffect30(() => {
63082
+ useEffect31(() => {
62464
63083
  if (livePickerRef.current?._projectInitialPending !== true) return;
62465
63084
  void projectPickerRef.current?.openProjectPicker({ initialEntry: true });
62466
63085
  }, [store]);
@@ -62472,6 +63091,8 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62472
63091
  setPromptDraft,
62473
63092
  promptDraftOverride,
62474
63093
  setPromptDraftOverride,
63094
+ promptCaret,
63095
+ setPromptCaret,
62475
63096
  promptLayoutValueRef,
62476
63097
  setPromptLayoutRows,
62477
63098
  textEntryLayoutRows,
@@ -62513,8 +63134,8 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62513
63134
  welcomePromptHintVisibleRef,
62514
63135
  dismissWelcomePromptHint
62515
63136
  } = useWelcomePromptHint({ store, state, toastErrorSignature });
62516
- const [slashIndex, setSlashIndex] = useState19(0);
62517
- const [slashDismissedFor, setSlashDismissedFor] = useState19("");
63137
+ const [slashIndex, setSlashIndex] = useState20(0);
63138
+ const [slashDismissedFor, setSlashDismissedFor] = useState20("");
62518
63139
  const slashPaletteRef = useRef29({ open: false, count: 0 });
62519
63140
  const scrollFocusRef = useRef29({});
62520
63141
  const onboardingStartedRef = useRef29(false);
@@ -62596,7 +63217,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62596
63217
  settingsPrompt,
62597
63218
  setTextEntryLayoutRows
62598
63219
  });
62599
- useEffect30(() => {
63220
+ useEffect31(() => {
62600
63221
  const timer2 = setTimeout(() => setTuiReady(true), 0);
62601
63222
  return () => clearTimeout(timer2);
62602
63223
  }, []);
@@ -62642,7 +63263,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62642
63263
  getStitchedSelectionText,
62643
63264
  showSelectionCopyHint
62644
63265
  });
62645
- useEffect30(
63266
+ useEffect31(
62646
63267
  () => () => {
62647
63268
  stopSmoothScroll();
62648
63269
  },
@@ -62770,7 +63391,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62770
63391
  setSettingsPrompt,
62771
63392
  closeUsagePanel
62772
63393
  });
62773
- useEffect30(() => {
63394
+ useEffect31(() => {
62774
63395
  if (contextPanel?.kind === "context") openContextPicker();
62775
63396
  }, [
62776
63397
  contextPanel?.kind,
@@ -62822,7 +63443,8 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62822
63443
  pastedImagesRef,
62823
63444
  pastedTextsRef
62824
63445
  });
62825
- const { activeSlashQuery, slashCommands, slashPaletteOpen } = deriveSlashPalette({
63446
+ const mentionSkills = useSkillMentionSkills(store, skillMentionQuery(promptDraft, promptCaret) !== null);
63447
+ const { activeSlashQuery, slashCommands, slashPaletteOpen, paletteKind } = deriveSlashPalette({
62826
63448
  providerPrompt,
62827
63449
  settingsPrompt,
62828
63450
  toolApproval,
@@ -62832,7 +63454,9 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62832
63454
  exiting,
62833
63455
  commandBusy: state.commandBusy,
62834
63456
  promptDraft,
62835
- slashDismissedFor
63457
+ slashDismissedFor,
63458
+ skills: mentionSkills,
63459
+ promptCaret
62836
63460
  });
62837
63461
  slashPaletteRef.current = { open: slashPaletteOpen, count: slashCommands.length };
62838
63462
  scrollFocusRef.current = {
@@ -62844,7 +63468,7 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
62844
63468
  providerPrompt: !!providerPrompt,
62845
63469
  settingsPrompt: !!settingsPrompt
62846
63470
  };
62847
- useEffect30(() => {
63471
+ useEffect31(() => {
62848
63472
  setSlashIndex((index) => Math.min(index, Math.max(0, slashCommands.length - 1)));
62849
63473
  }, [slashCommands.length, activeSlashQuery]);
62850
63474
  const {
@@ -63012,10 +63636,12 @@ function App2({ store, initialStatusLine = "", forceOnboarding = false, onboardi
63012
63636
  hasUserMessages,
63013
63637
  initialStatusLine,
63014
63638
  onPromptDraftChange,
63639
+ onPromptCaretChange: setPromptCaret,
63015
63640
  onSubmit,
63016
63641
  overlayHintAttachItemIndex,
63017
63642
  overlayHintFallbackRow,
63018
63643
  overlayHintOnLastItem,
63644
+ paletteKind,
63019
63645
  panelInkMaskEpoch,
63020
63646
  panelTransitionEpoch,
63021
63647
  picker,
@@ -63486,7 +64112,7 @@ function registerStdioDeathGuards(signalCleanup) {
63486
64112
  register(process.stderr, "close");
63487
64113
  return listeners;
63488
64114
  }
63489
- async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {}) {
64115
+ async function runTui({ provider, model, toolMode, remote, forceOnboarding, worktree } = {}) {
63490
64116
  const startedAt = performance2.now();
63491
64117
  bootProfile("run:start", { provider, model, toolMode, remote });
63492
64118
  if (!process.stdin.isTTY) {
@@ -63520,7 +64146,13 @@ async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {
63520
64146
  );
63521
64147
  process.stdout.write("\x1B[5 q");
63522
64148
  process.on("exit", restoreTerminal);
63523
- const storeOutcomePromise = createSessionRuntime({ provider, model, toolMode, remote }).then(
64149
+ const storeOutcomePromise = createSessionRuntime({
64150
+ provider,
64151
+ model,
64152
+ toolMode,
64153
+ remote,
64154
+ worktree: worktree ?? { mode: "default" }
64155
+ }).then(
63524
64156
  (store2) => ({ store: store2, error: null }),
63525
64157
  (error) => ({ store: null, error })
63526
64158
  );