mixdog 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/README.md +7 -5
  2. package/package.json +1 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/src/agents/reviewer/AGENT.md +3 -3
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +5 -0
  8. package/src/defaults/skills/pptx/SKILL.md +6 -6
  9. package/src/defaults/skills/pptx/references/review.md +6 -4
  10. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  11. package/src/defaults/skills/setup/references/actions.md +13 -3
  12. package/src/defaults/skills/visualize/SKILL.md +12 -9
  13. package/src/repl/slash-commands.mjs +16 -1
  14. package/src/rules/shared/60-verification.md +3 -1
  15. package/src/rules/shared/70-delivery.md +4 -2
  16. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  17. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  18. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  19. package/src/runtime/agent/orchestrator/config.mjs +10 -4
  20. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  21. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  22. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  23. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +122 -15
  24. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +54 -11
  25. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +104 -9
  26. package/src/runtime/agent/orchestrator/mcp/client.mjs +358 -140
  27. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  28. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  29. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  30. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  31. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  32. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  33. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  36. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  37. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +294 -44
  38. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  40. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
  41. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  42. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
  45. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  46. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  49. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  50. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  51. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
  53. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  54. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  55. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +53 -18
  57. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  58. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  59. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
  60. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
  61. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
  62. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
  63. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  64. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  65. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  66. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +447 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
  68. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  70. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
  71. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
  73. package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
  74. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  75. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +86 -19
  76. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
  78. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
  79. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  80. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  81. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  82. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  83. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
  84. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
  85. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
  86. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
  87. package/src/runtime/agent/orchestrator/providers/gemini.mjs +97 -51
  88. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  89. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
  90. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  91. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  92. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  93. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  94. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
  95. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
  96. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  97. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
  98. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +5 -3
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  108. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
  109. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  110. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  111. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
  115. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +26 -6
  116. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
  117. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  119. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
  120. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
  121. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  122. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
  123. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  125. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
  126. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
  127. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  128. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
  130. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  132. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  133. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  134. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  135. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +35 -24
  136. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
  137. package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
  138. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  139. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
  140. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  141. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  142. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  143. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  146. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  147. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  148. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  149. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  150. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +268 -181
  151. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  154. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +270 -0
  156. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  157. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  158. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
  159. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  160. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  161. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  162. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  163. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  164. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  165. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  166. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  167. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
  169. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -4
  170. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
  171. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
  172. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  173. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
  174. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +42 -5
  175. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +14 -3
  176. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
  177. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +50 -23
  178. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
  179. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +22 -14
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  182. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  183. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
  184. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
  185. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  186. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  187. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  188. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  189. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  190. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +819 -0
  191. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +12 -0
  192. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +22 -12
  193. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  194. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
  195. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  196. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  197. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +41 -3
  198. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
  199. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  200. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  201. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  202. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  203. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  205. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  206. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  208. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
  209. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
  210. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  211. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  212. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  213. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  214. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  216. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  217. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  218. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  219. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  220. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  221. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  222. package/src/runtime/attachments/store.d.mts +3 -0
  223. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  224. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  225. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  226. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  227. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  228. package/src/runtime/memory/lib/memory.mjs +1 -1
  229. package/src/runtime/memory/lib/pg/process.mjs +34 -24
  230. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
  231. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  232. package/src/runtime/office/README.md +1 -1
  233. package/src/runtime/office/shared/values.mjs +0 -5
  234. package/src/runtime/shared/atomic-file.mjs +25 -4
  235. package/src/runtime/shared/background-tasks.mjs +92 -14
  236. package/src/runtime/shared/err-text.mjs +25 -0
  237. package/src/runtime/shared/error-presentation.mjs +159 -19
  238. package/src/runtime/shared/extension-scopes.mjs +5 -3
  239. package/src/runtime/shared/file-lock.mjs +37 -11
  240. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  241. package/src/runtime/shared/llm/anthropic-effort.mjs +134 -131
  242. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  243. package/src/runtime/shared/llm/model-catalog.mjs +53 -52
  244. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  245. package/src/runtime/shared/llm/provider-catalog-registry.mjs +17 -0
  246. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  247. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  248. package/src/runtime/shared/model-display.mjs +13 -0
  249. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  250. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  251. package/src/runtime/shared/pristine-execution.mjs +28 -4
  252. package/src/runtime/shared/provider-accounts.mjs +124 -20
  253. package/src/runtime/shared/provider-api-key.mjs +12 -0
  254. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  255. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  256. package/src/runtime/shared/shell-display.mjs +9 -3
  257. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  258. package/src/runtime/shared/skill-mentions.mjs +133 -0
  259. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  260. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  261. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  262. package/src/runtime/shared/tool-primitives.mjs +35 -2
  263. package/src/runtime/shared/turn-changes.mjs +447 -219
  264. package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
  265. package/src/runtime/shared/turn-snapshot.mjs +170 -48
  266. package/src/runtime/shared/turn-worktree-snapshot.mjs +160 -51
  267. package/src/runtime/shared/worker-requests.mjs +15 -2
  268. package/src/runtime/shared/worktrees/contract.mjs +0 -24
  269. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  270. package/src/session-runtime/automation-agents.mjs +8 -2
  271. package/src/session-runtime/boot/apis.mjs +61 -0
  272. package/src/session-runtime/boot/config.mjs +5 -2
  273. package/src/session-runtime/boot/facade.mjs +1 -0
  274. package/src/session-runtime/boot/infrastructure.mjs +35 -18
  275. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  276. package/src/session-runtime/conversation-import/service.mjs +369 -0
  277. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
  278. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  279. package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
  280. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  281. package/src/session-runtime/mcp-glue/connect.mjs +83 -16
  282. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  283. package/src/session-runtime/mcp-glue/server-catalog.mjs +135 -33
  284. package/src/session-runtime/mcp-glue.mjs +25 -2
  285. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  286. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  287. package/src/session-runtime/model-route/set-route.mjs +83 -15
  288. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  289. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  290. package/src/session-runtime/new-session-config.mjs +3 -2
  291. package/src/session-runtime/notification-bus.mjs +9 -2
  292. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  293. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  294. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  295. package/src/session-runtime/provider-readiness.mjs +16 -10
  296. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  297. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  298. package/src/session-runtime/resource-extension-sync.mjs +24 -5
  299. package/src/session-runtime/resource-mcp-api.mjs +198 -78
  300. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  301. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  302. package/src/session-runtime/resource-skills-api.mjs +23 -2
  303. package/src/session-runtime/runtime-review-api.mjs +13 -0
  304. package/src/session-runtime/schedule-session-run.mjs +1 -1
  305. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  306. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  307. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  308. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  310. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  311. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  312. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  313. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  314. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  315. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  316. package/src/session-runtime/services/provider-admin.mjs +64 -18
  317. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  318. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  319. package/src/session-runtime/setup-tool/executor.mjs +12 -1
  320. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  321. package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
  322. package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
  323. package/src/session-runtime/skills-api.mjs +7 -3
  324. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  325. package/src/session-runtime/webhook-session-run.mjs +16 -4
  326. package/src/skill-script-entry.mjs +36 -0
  327. package/src/standalone/daemon-drain-policy.mjs +8 -0
  328. package/src/standalone/daemon-stored-session-views.mjs +11 -3
  329. package/src/standalone/daemon-telemetry.mjs +55 -0
  330. package/src/standalone/daemon.mjs +44 -11
  331. package/src/standalone/session-protocol.mjs +12 -0
  332. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  333. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  334. package/src/standalone/session-service/agent-tree.mjs +12 -0
  335. package/src/standalone/session-service/quota-resume.mjs +8 -0
  336. package/src/standalone/session-service/retention/busy.mjs +15 -1
  337. package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
  338. package/src/standalone/session-service-api.mjs +5 -0
  339. package/src/standalone/session-service.mjs +1 -0
  340. package/src/tui/App.jsx +9 -1
  341. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  342. package/src/tui/app/app-view.jsx +7 -0
  343. package/src/tui/app/create-app-pickers.mjs +4 -0
  344. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  345. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  346. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  347. package/src/tui/app/extension-pickers.mjs +2 -1
  348. package/src/tui/app/model-options.mjs +13 -16
  349. package/src/tui/app/skill-mention-palette.mjs +88 -0
  350. package/src/tui/app/slash-commands.mjs +7 -2
  351. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  352. package/src/tui/app/slash-palette.mjs +23 -7
  353. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  354. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  355. package/src/tui/app/use-prompt-state.mjs +5 -0
  356. package/src/tui/components/Message.jsx +22 -1
  357. package/src/tui/components/PromptInput.jsx +21 -3
  358. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  359. package/src/tui/components/StatusLine.jsx +2 -0
  360. package/src/tui/components/TranscriptItem.jsx +9 -1
  361. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  362. package/src/tui/components/status-line/local-line.mjs +5 -2
  363. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  364. package/src/tui/components/user-message-skills.mjs +38 -0
  365. package/src/tui/dist/index.mjs +1323 -214
  366. package/src/tui/session/queue-helpers.mjs +7 -2
  367. package/src/tui/session/quota-resume.mjs +46 -14
  368. package/src/tui/session/session-api/commands.mjs +33 -24
  369. package/src/tui/session/session-api/extensions.mjs +26 -2
  370. package/src/tui/session/session-api/integrations.mjs +7 -0
  371. package/src/tui/session/session-api/lifecycle.mjs +5 -1
  372. package/src/tui/session/session-api/routes.mjs +71 -7
  373. package/src/tui/session/session-api/settings.mjs +12 -14
  374. package/src/tui/session/session-flow/drain.mjs +21 -5
  375. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  376. package/src/tui/session/tui-steering-persist.mjs +25 -9
  377. package/src/tui/session/turn.mjs +55 -15
  378. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  379. package/src/ui/statusline-agents.mjs +15 -4
  380. package/src/ui/statusline.mjs +7 -3
  381. package/src/ui/streaming-markdown-heal.mjs +34 -3
  382. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  383. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  384. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
  385. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  386. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -296,6 +296,7 @@ export function createSessionService({
296
296
  },
297
297
  getSize: () => sessions.size,
298
298
  getBusyCount: retention.liveBusyCount,
299
+ getTurnBusyCount: retention.liveTurnBusyCount,
299
300
  getStatus,
300
301
  getExternalClientCount: () => desktopServices.externalClientCount,
301
302
  });
package/src/tui/App.jsx CHANGED
@@ -21,6 +21,7 @@ import { useApp, useStdin, useStdout } from 'ink';
21
21
  import { useSession } from './hooks/useSession.mjs';
22
22
  import { pickFolder } from '../standalone/folder-dialog.mjs';
23
23
  import { deriveSlashPalette } from './app/slash-palette.mjs';
24
+ import { skillMentionQuery, useSkillMentionSkills } from './app/skill-mention-palette.mjs';
24
25
  import { shouldSupersedePanelEpoch, supersedePanelEpoch } from './app/panel-epoch.mjs';
25
26
  import { createPanelSurface } from './app/panel-surface.mjs';
26
27
  import { resolvePickerState } from './app/picker-index-mode.mjs';
@@ -215,6 +216,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
215
216
  setPromptDraft,
216
217
  promptDraftOverride,
217
218
  setPromptDraftOverride,
219
+ promptCaret,
220
+ setPromptCaret,
218
221
  promptLayoutValueRef,
219
222
  setPromptLayoutRows,
220
223
  textEntryLayoutRows,
@@ -625,7 +628,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
625
628
  pastedTextsRef,
626
629
  });
627
630
 
628
- const { activeSlashQuery, slashCommands, slashPaletteOpen } = deriveSlashPalette({
631
+ const mentionSkills = useSkillMentionSkills(store, skillMentionQuery(promptDraft, promptCaret) !== null);
632
+ const { activeSlashQuery, slashCommands, slashPaletteOpen, paletteKind } = deriveSlashPalette({
629
633
  providerPrompt,
630
634
  settingsPrompt,
631
635
  toolApproval,
@@ -636,6 +640,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
636
640
  commandBusy: state.commandBusy,
637
641
  promptDraft,
638
642
  slashDismissedFor,
643
+ skills: mentionSkills,
644
+ promptCaret,
639
645
  });
640
646
  slashPaletteRef.current = { open: slashPaletteOpen, count: slashCommands.length };
641
647
  scrollFocusRef.current = {
@@ -833,10 +839,12 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
833
839
  hasUserMessages,
834
840
  initialStatusLine,
835
841
  onPromptDraftChange,
842
+ onPromptCaretChange: setPromptCaret,
836
843
  onSubmit,
837
844
  overlayHintAttachItemIndex,
838
845
  overlayHintFallbackRow,
839
846
  overlayHintOnLastItem,
847
+ paletteKind,
840
848
  panelInkMaskEpoch,
841
849
  panelTransitionEpoch,
842
850
  picker,
@@ -18,6 +18,12 @@ import { textEntryClearsByEmpty } from '../text-entry-policy.mjs';
18
18
  import { withPickerEnterLatch } from '../picker-enter-latch.mjs';
19
19
  import { providerPromptFields, settingsPromptFields } from './text-entry-labels.mjs';
20
20
 
21
+ // `$name` skill completion reuses the command palette with its own copy.
22
+ const SKILL_PALETTE_TEXT = {
23
+ description: 'Type to filter · Enter or Tab inserts the highlighted skill.',
24
+ help: '↑/↓ select · Enter insert · Esc cancel',
25
+ };
26
+
21
27
  function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionPanel }) {
22
28
  const resolve = (approved) => {
23
29
  store.resolveToolApproval?.(toolApproval.id, {
@@ -166,13 +172,15 @@ export function renderFloatingPanel(ctx) {
166
172
  );
167
173
  }
168
174
  if (slashPaletteOpen) {
175
+ const skills = ctx.paletteKind === 'skills';
169
176
  return (
170
177
  <SlashCommandPalette
171
178
  commands={slashCommands}
172
179
  selectedIndex={slashIndex}
173
- title="Commands"
180
+ title={skills ? 'Skills' : 'Commands'}
174
181
  columns={frameColumns}
175
182
  query={activeSlashQuery}
183
+ {...(skills ? SKILL_PALETTE_TEXT : {})}
176
184
  />
177
185
  );
178
186
  }
@@ -52,8 +52,10 @@ export function renderAppView(ctx) {
52
52
  inputHint,
53
53
  inputHintTone,
54
54
  liveSpinner,
55
+ onPromptCaretChange,
55
56
  onPromptDraftChange,
56
57
  onSubmit,
58
+ paletteKind,
57
59
  panelTransitionClearRows,
58
60
  picker,
59
61
  promptBoxRectRef,
@@ -85,6 +87,7 @@ export function renderAppView(ctx) {
85
87
  onSubmit={onSubmit}
86
88
  disabled={exiting || !!picker || !!contextPanel || !!toolApproval || !tuiReady}
87
89
  onDraftChange={onPromptDraftChange}
90
+ onCaretChange={onPromptCaretChange}
88
91
  interruptActive={state.busy}
89
92
  onInterrupt={handlePromptInterrupt}
90
93
  initialValue={promptDraft}
@@ -108,6 +111,9 @@ export function renderAppView(ctx) {
108
111
  commandPaletteActive={slashPaletteOpen && slashCommands.length > 0}
109
112
  commandPaletteOpen={slashPaletteOpen}
110
113
  commandPaletteOptionCount={slashCommands.length}
114
+ // The `$name` skill palette leaves Left/Right to the caret: the
115
+ // mention follows it.
116
+ commandPaletteMovesCaret={paletteKind === 'skills'}
111
117
  onCommandPaletteNavigate={(direction) => {
112
118
  setSlashIndex((index) => stepPaletteIndex(index, direction, slashCommands.length));
113
119
  }}
@@ -229,6 +235,7 @@ export function renderAppView(ctx) {
229
235
  model={state.model}
230
236
  effort={state.effort}
231
237
  fast={state.fast}
238
+ ultra={state.fast === true && state.modelParameters?.serviceTier === 'ultrafast'}
232
239
  cwd={state.cwd}
233
240
  stats={statuslineStats}
234
241
  contextWindow={state.contextWindow}
@@ -88,6 +88,8 @@ export function createAppPickers({
88
88
  const {
89
89
  openMcpServersPicker,
90
90
  openMcpPicker,
91
+ loginMcpServer,
92
+ logoutMcpServer,
91
93
  openProjectSkillsPicker,
92
94
  openSkillsPicker,
93
95
  openSkillDetailPicker,
@@ -219,6 +221,8 @@ export function createAppPickers({
219
221
  enterProject: (...a) => enterProject(...a),
220
222
  openProjectPicker: (...a) => openProjectPicker(...a),
221
223
  openMcpPicker: (...a) => openMcpPicker(...a),
224
+ loginMcpServer,
225
+ logoutMcpServer,
222
226
  openSkillsPicker: (...a) => openSkillsPicker(...a),
223
227
  openPluginsPicker: (...a) => openPluginsPicker(...a),
224
228
  openProviderSetupPicker: (...a) => openProviderSetupPicker(...a),
@@ -0,0 +1,107 @@
1
+ // extension-pickers/mcp-login.mjs
2
+ // `/mcp login <name>` and `/mcp logout <name>`. The sign-in URL is always
3
+ // printed (and kept in the live prompt); the runtime may open the browser. The
4
+ // flow is polled while a paste prompt (the shared 'oauth-code' provider prompt)
5
+ // accepts the final redirect address. Pasted text is never echoed.
6
+ const POLL_MS = 1500;
7
+
8
+ export function createMcpLogin({ store, setProviderPrompt, pollMs = POLL_MS }) {
9
+ let active = null;
10
+
11
+ const stop = (flow) => {
12
+ flow.finished = true;
13
+ clearTimeout(flow.timer);
14
+ if (active === flow) active = null;
15
+ };
16
+
17
+ const closePrompt = (flow) => setProviderPrompt((prompt) => (prompt === flow.prompt ? null : prompt));
18
+
19
+ const showPrompt = (flow) => {
20
+ if (flow.finished) return;
21
+ const prompt = {
22
+ kind: 'oauth-code',
23
+ providerName: `MCP ${flow.name}`,
24
+ // The shared prompt pushes the one completion notice; no provider picker follows.
25
+ successReturn: () => {},
26
+ label: `MCP sign-in · ${flow.name}`,
27
+ hint: 'If the browser page fails to load, paste its address here.',
28
+ detail: flow.url,
29
+ login: {
30
+ completeCode: async (text) => {
31
+ const result = await store.completeMcpOAuthLogin(flow.id, text);
32
+ if (result?.state !== 'complete') throw new Error(result?.error || 'sign-in did not complete');
33
+ stop(flow);
34
+ },
35
+ cancel: () => {
36
+ if (flow.finished) return;
37
+ stop(flow);
38
+ void Promise.resolve(store.cancelMcpOAuthLogin(flow.id)).catch(() => {});
39
+ store.pushNotice(`MCP sign-in cancelled for ${flow.name}`, 'info');
40
+ },
41
+ },
42
+ failureReturn: () => showPrompt(flow),
43
+ };
44
+ flow.prompt = prompt;
45
+ setProviderPrompt(prompt);
46
+ };
47
+
48
+ const poll = (flow) => {
49
+ flow.timer = setTimeout(async () => {
50
+ if (flow.finished) return;
51
+ let status;
52
+ try {
53
+ status = await store.getMcpOAuthLoginStatus(flow.id);
54
+ } catch (e) {
55
+ if (flow.finished) return;
56
+ stop(flow);
57
+ closePrompt(flow);
58
+ store.pushNotice(`MCP sign-in failed for ${flow.name}: ${e?.message || e}`, 'error');
59
+ return;
60
+ }
61
+ if (flow.finished) return;
62
+ if (status?.state === 'pending') {
63
+ poll(flow);
64
+ return;
65
+ }
66
+ stop(flow);
67
+ closePrompt(flow);
68
+ if (status?.state === 'complete') store.pushNotice(`MCP sign-in complete for ${flow.name}`, 'info');
69
+ else if (status?.state === 'cancelled') store.pushNotice(`MCP sign-in cancelled for ${flow.name}`, 'info');
70
+ else store.pushNotice(`MCP sign-in failed for ${flow.name}${status?.error ? `: ${status.error}` : ''}`, 'error');
71
+ }, pollMs);
72
+ };
73
+
74
+ const loginMcpServer = async (name) => {
75
+ if (active) {
76
+ const previous = active;
77
+ stop(previous);
78
+ closePrompt(previous);
79
+ void Promise.resolve(store.cancelMcpOAuthLogin(previous.id)).catch(() => {});
80
+ }
81
+ try {
82
+ const started = await store.beginMcpOAuthLogin(name, { openBrowser: true });
83
+ if (started?.state === 'complete') {
84
+ store.pushNotice(`MCP sign-in complete for ${name}`, 'info');
85
+ return;
86
+ }
87
+ const flow = { id: started.flowId, name, url: started.url || '', finished: false, timer: null, prompt: null };
88
+ active = flow;
89
+ if (flow.url) store.pushNotice(`Sign in to ${name}: ${flow.url}`, 'info');
90
+ showPrompt(flow);
91
+ poll(flow);
92
+ } catch (e) {
93
+ store.pushNotice(`MCP sign-in failed for ${name}: ${e?.message || e}`, 'error');
94
+ }
95
+ };
96
+
97
+ const logoutMcpServer = async (name) => {
98
+ try {
99
+ await store.signOutMcpServer(name);
100
+ store.pushNotice(`MCP signed out of ${name}`, 'info');
101
+ } catch (e) {
102
+ store.pushNotice(`MCP sign-out failed for ${name}: ${e?.message || e}`, 'error');
103
+ }
104
+ };
105
+
106
+ return { loginMcpServer, logoutMcpServer };
107
+ }
@@ -8,8 +8,9 @@ const serverDescription = (server, pending, optimistic) => {
8
8
  const transport = server.transport || 'unknown';
9
9
  if (pending) return `${optimistic.enabled ? 'enabling' : 'disabling'}… · ${transport}`;
10
10
  const error = server.error ? ` · ${server.error}` : '';
11
+ const signIn = server.authRequired ? ` · sign-in required: /mcp login ${server.name}` : '';
11
12
  return withScope(
12
- `${server.source || 'config'} · ${server.status || 'unknown'} · ${transport} · ${server.toolCount || 0} tools${error}`,
13
+ `${server.source || 'config'} · ${server.status || 'unknown'} · ${transport} · ${server.toolCount || 0} tools${error}${signIn}`,
13
14
  server
14
15
  );
15
16
  };
@@ -3,34 +3,52 @@
3
3
  // (info / update / MCP / copy / uninstall) and the add-plugin prompt.
4
4
  import { readStatus, withScope } from './scope-note.mjs';
5
5
 
6
+ // A plugin's MCP servers are derived from its declarations (`mcpServers` on
7
+ // the status row); older hosts only report `mcpScript`/`mcpServerName`.
8
+ function mcpNames(p) {
9
+ if (Array.isArray(p.mcpServers)) return p.mcpServers.map((server) => server.name);
10
+ return p.mcpServerName ? [p.mcpServerName] : [];
11
+ }
12
+ const hasMcp = (p) => mcpNames(p).length > 0 || Boolean(p.mcpScript || p.mcpInline);
13
+
14
+ function serverState(server) {
15
+ if (server.serverEnabled === false) return 'off';
16
+ if (server.enabled === false) return 'plugin off';
17
+ return server.status || (server.connected ? 'connected' : 'disconnected');
18
+ }
19
+
6
20
  const mcpSummary = (p) => {
7
- if (!p.mcpScript) return '(none)';
8
- const state = p.mcpEnabled ? 'enabled' : 'available';
9
- return `${state} (${p.mcpServerName || 'plugin-mcp'})`;
21
+ if (!hasMcp(p))
22
+ return Array.isArray(p.mcpErrors) && p.mcpErrors.length ? `(invalid: ${p.mcpErrors[0].message})` : '(none)';
23
+ if (!Array.isArray(p.mcpServers)) return `${p.mcpEnabled ? 'enabled' : 'available'} (${mcpNames(p).join(', ')})`;
24
+ const errors =
25
+ Array.isArray(p.mcpErrors) && p.mcpErrors.length ? ` · ${p.mcpErrors.length} declaration error(s)` : '';
26
+ return `${p.mcpServers.map((server) => `${server.name} ${serverState(server)}`).join(', ')}${errors}`;
10
27
  };
11
28
 
12
29
  function mcpActionItem(p) {
13
- if (!p.mcpScript) {
30
+ if (!hasMcp(p)) {
14
31
  return {
15
32
  value: 'enable-mcp',
16
- label: 'No MCP script',
17
- description: 'plugin does not expose scripts/run-mcp.mjs or mcp/server.mjs',
33
+ label: 'No MCP server',
34
+ description: 'plugin declares no MCP servers (.mcp.json or manifest mcpServers)',
18
35
  _action: 'noop',
19
36
  };
20
37
  }
21
38
  return {
22
39
  value: 'enable-mcp',
23
- label: p.mcpEnabled ? 'Refresh MCP server' : 'Enable MCP server',
24
- description: `${p.mcpServerName || 'plugin-mcp'} · ${p.mcpEnabled ? 'configured' : p.mcpScript}`,
40
+ label: p.mcpEnabled ? 'Reconnect MCP servers' : 'Enable MCP servers',
41
+ description: `${mcpNames(p).join(', ') || 'plugin MCP'} · ${p.mcpEnabled ? 'on' : 'turned off'}`,
25
42
  _action: 'enable-mcp',
26
43
  };
27
44
  }
28
45
 
29
46
  function pluginSummary(plugin) {
30
47
  const version = plugin.version ? ` · ${plugin.version}` : '';
31
- const mcpState = plugin.mcpEnabled ? 'enabled' : plugin.mcpScript;
32
- const mcp = plugin.mcpScript ? ` · mcp ${mcpState}` : '';
33
- return `${plugin.sourceType || plugin.source}${version} · skills ${plugin.skillCount || 0}${mcp}`;
48
+ const mcpOff = plugin.mcpEnabled ? '' : ' off';
49
+ const mcp = hasMcp(plugin) ? ` · mcp ${mcpNames(plugin).length || 1}${mcpOff}` : '';
50
+ const warning = plugin.warning ? ` · ⚠ ${plugin.warning}` : '';
51
+ return `${plugin.sourceType || plugin.source}${version} · skills ${plugin.skillCount || 0}${mcp}${warning}`;
34
52
  }
35
53
 
36
54
  const pluginInfoNotice = (p) =>
@@ -41,6 +59,7 @@ const pluginInfoNotice = (p) =>
41
59
  `mcp: ${mcpSummary(p)}`,
42
60
  `applies to: ${Array.isArray(p.scope) && p.scope.length ? p.scope.join(', ') : 'all projects'}`,
43
61
  `root: ${p.root}`,
62
+ p.warning ? `warning: ${p.warning}` : '',
44
63
  p.description ? `\n${p.description}` : '',
45
64
  ]
46
65
  .filter(Boolean)
@@ -68,9 +87,9 @@ const pluginDetailItems = (p) => [
68
87
  },
69
88
  {
70
89
  value: 'copy-mcp-name',
71
- label: p.mcpScript ? 'Copy MCP server name' : 'No MCP server name',
72
- description: p.mcpServerName || '',
73
- _action: p.mcpScript ? 'copy-mcp-name' : 'noop',
90
+ label: mcpNames(p).length ? 'Copy MCP server name' : 'No MCP server name',
91
+ description: mcpNames(p).join(', '),
92
+ _action: mcpNames(p).length ? 'copy-mcp-name' : 'noop',
74
93
  },
75
94
  {
76
95
  value: 'uninstall',
@@ -127,7 +146,7 @@ export function createPluginsPickers({
127
146
  void store
128
147
  .enablePluginMcp?.(p)
129
148
  .then(own.defer(() => openMcpPicker()))
130
- .catch((e) => store.pushNotice(`plugin MCP enable failed: ${e?.message || e}`, 'error'));
149
+ .catch((e) => store.pushNotice(`plugin MCP reconnect failed: ${e?.message || e}`, 'error'));
131
150
  return;
132
151
  }
133
152
  if (detail._action === 'copy-root') {
@@ -135,7 +154,7 @@ export function createPluginsPickers({
135
154
  return;
136
155
  }
137
156
  if (detail._action === 'copy-mcp-name') {
138
- copyText(p.mcpServerName || '', `copied plugin MCP server: ${p.mcpServerName}`);
157
+ copyText(mcpNames(p).join(', '), `copied plugin MCP server: ${mcpNames(p).join(', ')}`);
139
158
  return;
140
159
  }
141
160
  if (detail._action === 'uninstall') {
@@ -7,6 +7,7 @@
7
7
  * store state, so they can't be pure. openMcpPicker is exposed for the
8
8
  * plugin-detail enable-mcp path (also aliased on the App body).
9
9
  */
10
+ import { createMcpLogin } from './extension-pickers/mcp-login.mjs';
10
11
  import { createMcpServersPicker } from './extension-pickers/mcp-servers-picker.mjs';
11
12
  import { createPluginsPickers } from './extension-pickers/plugins-pickers.mjs';
12
13
  import { createSkillsPickers } from './extension-pickers/skills-pickers.mjs';
@@ -43,5 +44,5 @@ export function createExtensionPickers({
43
44
  setSettingsPrompt,
44
45
  openMcpPicker: mcp.openMcpPicker,
45
46
  });
46
- return { ...mcp, ...skills, ...plugins };
47
+ return { ...mcp, ...createMcpLogin({ store, setProviderPrompt }), ...skills, ...plugins };
47
48
  }
@@ -6,7 +6,7 @@
6
6
  * displayModelName formatter.
7
7
  */
8
8
  import { theme } from '../theme.mjs';
9
- import { displayModelName } from '../../runtime/shared/model-display.mjs';
9
+ import { displayModelName, effortDisplayLabel } from '../../runtime/shared/model-display.mjs';
10
10
  import { isRollingModelAlias } from '../../runtime/shared/model-alias.mjs';
11
11
  import { DAYBREAK_PROVIDER, daybreakBlueOn } from '../../runtime/shared/llm/openai-daybreak.mjs';
12
12
 
@@ -169,6 +169,7 @@ const PROVIDER_DISPLAY_NAMES = new Map([
169
169
  ['anthropic-oauth', 'Anthropic OAuth'],
170
170
  ['grok-oauth', 'Grok OAuth'],
171
171
  ['muse-code-oauth', 'Muse Code'],
172
+ ['command-code-oauth', 'Command Code'],
172
173
  ['mimo-oauth', 'MiMo'],
173
174
  ['cursor-oauth', 'Cursor OAuth'],
174
175
  ['antigravity-oauth', 'Antigravity OAuth'],
@@ -225,6 +226,7 @@ const PROVIDER_DISPLAY_RANKS = {
225
226
  'anthropic-oauth': 20,
226
227
  'grok-oauth': 30,
227
228
  'muse-code-oauth': 33,
229
+ 'command-code-oauth': 33.5,
228
230
  'mimo-oauth': 34,
229
231
  'antigravity-oauth': 31,
230
232
  'cursor-oauth': 32,
@@ -246,18 +248,7 @@ const PROVIDER_DISPLAY_RANKS = {
246
248
 
247
249
  export const providerDisplayRank = (provider) => PROVIDER_DISPLAY_RANKS[String(provider || '').toLowerCase()] ?? 900;
248
250
 
249
- const titleCaseOption = (value) =>
250
- String(value || '')
251
- .split(/([\s_-]+)/)
252
- .map((part) => (/^[\s_-]+$/.test(part) ? part : `${part.charAt(0).toUpperCase()}${part.slice(1).toLowerCase()}`))
253
- .join('');
254
-
255
- export const effortDisplayLabel = (value) => {
256
- const text = String(value || '').trim();
257
- if (!text) return '';
258
- if (text.toLowerCase() === 'xhigh') return 'XHigh';
259
- return titleCaseOption(text);
260
- };
251
+ export { effortDisplayLabel };
261
252
 
262
253
  export const fastDisplayLabel = (enabled = true) => `Fast ${enabled ? 'On' : 'Off'}`;
263
254
 
@@ -328,9 +319,15 @@ export const buildProviderModelItems = (models, provider, currentRoute = null) =
328
319
  }));
329
320
  };
330
321
 
331
- // Model · Effort · Fast, dropping the empty parts.
322
+ // The configured speed tier: Ultrafast when the fast route asks for it.
323
+ const routeSpeedLabel = (route) => {
324
+ if (!route?.fast) return '';
325
+ return route.modelParameters?.serviceTier === 'ultrafast' ? 'Ultrafast' : 'Fast';
326
+ };
327
+
328
+ // Model · Effort · Fast/Ultrafast, dropping the empty parts.
332
329
  const routeModelDetails = (route) =>
333
- [routeModelDisplayName(route), route.effort ? effortDisplayLabel(route.effort) : '', route.fast ? 'Fast' : '']
330
+ [routeModelDisplayName(route), route.effort ? effortDisplayLabel(route.effort) : '', routeSpeedLabel(route)]
334
331
  .filter(Boolean)
335
332
  .join(' · ');
336
333
 
@@ -346,7 +343,7 @@ export const agentModelProfile = (route) => (route?.model ? routeModelDetails(ro
346
343
  export const agentModelParts = (route) => [
347
344
  { text: route?.model ? routeModelDisplayName(route) : '', width: 17 },
348
345
  { text: route?.effort ? effortDisplayLabel(route.effort) : '', width: 6 },
349
- { text: route?.fast ? 'Fast' : '', width: 4 },
346
+ { text: routeSpeedLabel(route), width: 9 },
350
347
  ];
351
348
 
352
349
  export const routeFromModel = (model, effort = null) => ({
@@ -0,0 +1,88 @@
1
+ /*
2
+ * app/skill-mention-palette.mjs — `$name` skill completion in the prompt.
3
+ *
4
+ * Typing `$` at the start of the draft or after whitespace/an opening
5
+ * bracket or quote (the shared runtime mention rule, runtime/shared/
6
+ * skill-mentions.mjs) opens the command palette with the user's enabled
7
+ * custom skills; accepting inserts `$name `. Built-in skills are not listed,
8
+ * but still load when their name is typed: the runtime resolves mentions.
9
+ */
10
+ import { useEffect, useState } from 'react';
11
+ import { isInMarkdownCode, isReservedMentionName } from '../../runtime/shared/skill-mentions.mjs';
12
+
13
+ // A mention being typed just before the caret: `$` plus a partial name.
14
+ const MENTION_TAIL = /(^|[\s([{"'`])\$([a-z0-9][a-z0-9-]{0,63})?$/;
15
+
16
+ const caretIn = (text, caret) => (Number.isInteger(caret) ? Math.max(0, Math.min(text.length, caret)) : text.length);
17
+
18
+ /** The mention being typed before `caret` (default: end of `value`), or null.
19
+ * `start` is the `$`, `end` the caret. */
20
+ export function skillMentionQuery(value, caret) {
21
+ const text = String(value ?? '');
22
+ const end = caretIn(text, caret);
23
+ const match = MENTION_TAIL.exec(text.slice(0, end));
24
+ if (!match) return null;
25
+ const start = match.index + match[1].length;
26
+ // `$` inside inline code or a fenced block is never a mention (the shared
27
+ // parser's rule, judged on the whole draft like the desktop composer).
28
+ if (isInMarkdownCode(text, start)) return null;
29
+ return { query: match[2] || '', start, end };
30
+ }
31
+
32
+ const byName = (a, b) => a.name.localeCompare(b.name, 'en');
33
+
34
+ /** Palette rows for `query`: enabled, in-project (not `activeHere:false`)
35
+ * non-built-in skills whose name starts with the query, then those that
36
+ * merely contain it, each alphabetical. */
37
+ export function skillMentionItems(skills, query) {
38
+ const needle = String(query || '').toLowerCase();
39
+ const usable = (Array.isArray(skills) ? skills : []).filter(
40
+ (skill) =>
41
+ typeof skill?.name === 'string' &&
42
+ skill.name &&
43
+ skill.enabled !== false &&
44
+ skill.activeHere !== false &&
45
+ skill.source !== 'builtin' &&
46
+ // `$path`/`$300` are never mentions, so offering them would insert prose.
47
+ !isReservedMentionName(skill.name)
48
+ );
49
+ const prefix = usable.filter((skill) => skill.name.startsWith(needle)).sort(byName);
50
+ const contains = needle
51
+ ? usable.filter((skill) => !skill.name.startsWith(needle) && skill.name.includes(needle)).sort(byName)
52
+ : [];
53
+ return [...prefix, ...contains].map((skill) => ({
54
+ kind: 'skill',
55
+ name: skill.name,
56
+ label: `$${skill.name}`,
57
+ description: skill.description || '',
58
+ }));
59
+ }
60
+
61
+ /** The draft with the `$fragment` before `caret` replaced by `$name `; the
62
+ * text after the caret is kept and the caret lands after the insertion. */
63
+ export function completeSkillMention(value, name, caret) {
64
+ const text = String(value ?? '');
65
+ const mention = skillMentionQuery(text, caret);
66
+ if (!mention || !name) return undefined;
67
+ const head = `${text.slice(0, mention.start)}$${name} `;
68
+ return { value: head + text.slice(mention.end), cursor: head.length };
69
+ }
70
+
71
+ /** The skill list for the palette, fetched each time a mention starts. */
72
+ export function useSkillMentionSkills(store, active) {
73
+ const [skills, setSkills] = useState([]);
74
+ useEffect(() => {
75
+ if (!active) return undefined;
76
+ let live = true;
77
+ Promise.resolve()
78
+ .then(() => store.skillsStatus?.())
79
+ .then((status) => {
80
+ if (live) setSkills(Array.isArray(status?.skills) ? status.skills : []);
81
+ })
82
+ .catch(() => {});
83
+ return () => {
84
+ live = false;
85
+ };
86
+ }, [store, active]);
87
+ return skills;
88
+ }
@@ -50,8 +50,13 @@ export const SLASH_COMMANDS = [
50
50
  { name: 'theme', usage: '/theme', params: '[id]', description: 'Change the TUI color theme' },
51
51
  { name: 'agents', usage: '/agents', params: '[refresh]', description: 'Show available workflow agents' },
52
52
  { name: 'effort', usage: '/effort', params: '[level]', description: 'Set reasoning effort for the current model' },
53
- { name: 'fast', usage: '/fast', params: '[on|off|ultra]', description: 'Set Fast or Ultrafast mode for the current model' },
54
- { name: 'mcp', usage: '/mcp', description: 'Manage MCP servers and tools' },
53
+ {
54
+ name: 'fast',
55
+ usage: '/fast',
56
+ params: '[on|off|ultra]',
57
+ description: 'Set Fast or Ultrafast mode for the current model',
58
+ },
59
+ { name: 'mcp', usage: '/mcp', params: '[login|logout <name>]', description: 'Manage MCP servers and tools' },
55
60
  { name: 'skills', usage: '/skills', description: 'Choose a skill for the next request' },
56
61
  { name: 'memory', usage: '/memory', params: '[status|core ...]', description: 'List and edit core memories' },
57
62
  { name: 'plugins', usage: '/plugins', description: 'Manage local plugin integrations' },
@@ -14,6 +14,8 @@ const desktopOnlyNotice = (ctx) => {
14
14
  return true;
15
15
  };
16
16
 
17
+ const openMcpPanel = panelCommand('mcp', 'MCP Servers', (deps) => deps.openMcpPicker());
18
+
17
19
  const openSettings = panelCommand('settings', 'Settings', (deps) => deps.openSettingsPicker());
18
20
 
19
21
  export const panelCommands = {
@@ -26,7 +28,20 @@ export const panelCommands = {
26
28
  ctx.openSlashPanel('project', 'Projects', () => ctx.deps.openProjectPicker());
27
29
  return true;
28
30
  },
29
- mcp: panelCommand('mcp', 'MCP Servers', (deps) => deps.openMcpPicker()),
31
+ mcp(ctx, arg) {
32
+ const [sub, ...rest] = arg.trim().split(/\s+/);
33
+ const action = sub?.toLowerCase();
34
+ if (action === 'login' || action === 'logout') {
35
+ const name = rest.join(' ');
36
+ if (!name) {
37
+ ctx.store.pushNotice(`usage: /mcp ${action} <name>`, 'warn');
38
+ return true;
39
+ }
40
+ void (action === 'login' ? ctx.deps.loginMcpServer(name) : ctx.deps.logoutMcpServer(name));
41
+ return true;
42
+ }
43
+ return openMcpPanel(ctx);
44
+ },
30
45
  skills: panelCommand('skills', 'Skills', (deps) => deps.openSkillsPicker()),
31
46
  plugins: panelCommand('plugins', 'Plugins', (deps) => deps.openPluginsPicker()),
32
47
  providers: panelCommand('providers', 'Providers', (deps) => deps.openProviderSetupPicker()),
@@ -2,6 +2,7 @@
2
2
  * app/slash-palette.mjs — which slash palette (if any) the prompt draft opens.
3
3
  */
4
4
  import { SLASH_COMMANDS, slashQuery, slashCommandMatches, compareSlashCommands } from './slash-commands.mjs';
5
+ import { skillMentionItems, skillMentionQuery } from './skill-mention-palette.mjs';
5
6
 
6
7
  export function deriveSlashPalette({
7
8
  providerPrompt,
@@ -14,18 +15,33 @@ export function deriveSlashPalette({
14
15
  commandBusy,
15
16
  promptDraft,
16
17
  slashDismissedFor,
18
+ skills = [],
19
+ promptCaret = null,
17
20
  }) {
18
21
  const activeSlashQuery =
19
22
  providerPrompt || settingsPrompt || toolApproval || contextPanel || usagePanel ? null : slashQuery(promptDraft);
23
+ const surfaceFree = !picker && !toolApproval && !contextPanel && !usagePanel && !exiting && !commandBusy;
20
24
  // "Slash mode" is live whenever a /token is being edited and no other
21
25
  // surface owns the floating area. The palette stays OPEN for the whole
22
26
  // slash session — including 0-match frames — so its 14-row layout never
23
27
  // unmounts/remounts per keystroke (fullscreen repaint flicker fix).
24
- const slashModeLive =
25
- activeSlashQuery !== null && !picker && !toolApproval && !contextPanel && !usagePanel && !exiting && !commandBusy;
26
- const slashCommands = !slashModeLive
27
- ? []
28
- : SLASH_COMMANDS.filter((command) => slashCommandMatches(command, activeSlashQuery)).sort(compareSlashCommands);
29
- const slashPaletteOpen = slashModeLive && slashDismissedFor !== promptDraft;
30
- return { activeSlashQuery, slashCommands, slashPaletteOpen };
28
+ const slashModeLive = activeSlashQuery !== null && surfaceFree;
29
+ if (!slashModeLive) {
30
+ // `$name` completion shares the palette, but opens only while a skill
31
+ // matches: `$HOME` or `$300` in prose must not raise a panel.
32
+ const mention =
33
+ surfaceFree && !providerPrompt && !settingsPrompt ? skillMentionQuery(promptDraft, promptCaret) : null;
34
+ const slashCommands = mention ? skillMentionItems(skills, mention.query) : [];
35
+ return {
36
+ activeSlashQuery: mention ? mention.query : null,
37
+ slashCommands,
38
+ slashPaletteOpen: slashCommands.length > 0 && slashDismissedFor !== promptDraft,
39
+ paletteKind: mention ? 'skills' : 'commands',
40
+ };
41
+ }
42
+ const slashCommands = SLASH_COMMANDS.filter((command) => slashCommandMatches(command, activeSlashQuery)).sort(
43
+ compareSlashCommands
44
+ );
45
+ const slashPaletteOpen = slashDismissedFor !== promptDraft;
46
+ return { activeSlashQuery, slashCommands, slashPaletteOpen, paletteKind: 'commands' };
31
47
  }