mixdog 0.9.44 → 0.9.46

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 (117) hide show
  1. package/package.json +5 -2
  2. package/scripts/agent-dispatch-abort-compose-test.mjs +31 -0
  3. package/scripts/agent-model-liveness-test.mjs +618 -0
  4. package/scripts/agent-trace-io-test.mjs +68 -4
  5. package/scripts/bench-run.mjs +30 -3
  6. package/scripts/compact-pressure-test.mjs +187 -4
  7. package/scripts/compact-prior-context-flatten-test.mjs +252 -0
  8. package/scripts/compact-trigger-migration-smoke.mjs +8 -6
  9. package/scripts/compacted-placeholder-scrub-test.mjs +20 -34
  10. package/scripts/context-mcp-metering-test.mjs +75 -0
  11. package/scripts/explore-prompt-policy-test.mjs +15 -16
  12. package/scripts/explore-timeout-cancel-test.mjs +345 -0
  13. package/scripts/headless-pristine-execution-test.mjs +614 -0
  14. package/scripts/internal-comms-smoke.mjs +15 -6
  15. package/scripts/live-worker-smoke.mjs +1 -1
  16. package/scripts/memory-core-input-test.mjs +137 -0
  17. package/scripts/memory-rule-contract-test.mjs +5 -5
  18. package/scripts/openai-oauth-refresh-race-test.mjs +120 -0
  19. package/scripts/openai-oauth-ws-1006-retry-test.mjs +26 -0
  20. package/scripts/parent-abort-link-test.mjs +22 -0
  21. package/scripts/provider-toolcall-test.mjs +22 -0
  22. package/scripts/reactive-compact-persist-smoke.mjs +8 -4
  23. package/scripts/session-bench.mjs +3 -70
  24. package/scripts/task-bench.mjs +0 -2
  25. package/scripts/terminal-bench-isolation-guards-test.mjs +102 -0
  26. package/scripts/tool-smoke.mjs +21 -21
  27. package/scripts/tool-tui-presentation-test.mjs +68 -0
  28. package/scripts/tui-transcript-jitter-harness-entry.jsx +91 -10
  29. package/src/app.mjs +28 -103
  30. package/src/cli.mjs +17 -13
  31. package/src/headless-command.mjs +139 -0
  32. package/src/headless-role.mjs +121 -10
  33. package/src/help.mjs +4 -1
  34. package/src/rules/agent/00-common.md +3 -3
  35. package/src/rules/agent/00-core.md +8 -9
  36. package/src/rules/agent/20-skip-protocol.md +2 -3
  37. package/src/rules/agent/30-explorer.md +50 -56
  38. package/src/rules/agent/40-cycle1-agent.md +10 -12
  39. package/src/rules/agent/41-cycle2-agent.md +12 -9
  40. package/src/rules/agent/42-cycle3-agent.md +4 -6
  41. package/src/rules/lead/01-general.md +5 -6
  42. package/src/rules/lead/02-channels.md +1 -1
  43. package/src/rules/lead/lead-brief.md +14 -17
  44. package/src/rules/lead/lead-tool.md +3 -3
  45. package/src/rules/shared/01-tool.md +41 -43
  46. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +46 -10
  47. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +44 -31
  48. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +18 -3
  49. package/src/runtime/agent/orchestrator/config.mjs +96 -30
  50. package/src/runtime/agent/orchestrator/context/collect.mjs +9 -0
  51. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
  52. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +18 -5
  53. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -6
  54. package/src/runtime/agent/orchestrator/providers/gemini.mjs +6 -6
  55. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +123 -3
  56. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -3
  57. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +148 -30
  58. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +5 -7
  59. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +62 -14
  60. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +141 -19
  61. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -4
  62. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +19 -1
  63. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +85 -17
  64. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -8
  65. package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -17
  66. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +159 -20
  67. package/src/runtime/agent/orchestrator/session/context-utils.mjs +83 -10
  68. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +75 -7
  69. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +4 -374
  70. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +0 -75
  71. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +0 -5
  72. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +20 -3
  73. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +32 -16
  74. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +5 -2
  75. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +86 -15
  76. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +30 -27
  77. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +1 -14
  78. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +21 -27
  79. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +1 -3
  80. package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -51
  81. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +4 -4
  82. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  83. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +26 -0
  84. package/src/runtime/memory/index.mjs +0 -1
  85. package/src/runtime/memory/lib/core-memory-store.mjs +44 -24
  86. package/src/runtime/memory/lib/http-router.mjs +0 -193
  87. package/src/runtime/memory/lib/memory-action-handlers.mjs +37 -11
  88. package/src/runtime/memory/tool-defs.mjs +5 -6
  89. package/src/runtime/shared/config.mjs +11 -34
  90. package/src/runtime/shared/pristine-execution-contract.json +75 -0
  91. package/src/runtime/shared/pristine-execution.mjs +356 -0
  92. package/src/runtime/shared/provider-api-key.mjs +43 -0
  93. package/src/runtime/shared/provider-auth-binding.mjs +21 -0
  94. package/src/runtime/shared/update-checker.mjs +40 -10
  95. package/src/session-runtime/context-status.mjs +61 -13
  96. package/src/session-runtime/mcp-glue.mjs +29 -2
  97. package/src/session-runtime/plugin-mcp.mjs +7 -0
  98. package/src/session-runtime/resource-api.mjs +38 -5
  99. package/src/session-runtime/runtime-core.mjs +5 -1
  100. package/src/session-runtime/session-turn-api.mjs +14 -2
  101. package/src/session-runtime/settings-api.mjs +5 -0
  102. package/src/session-runtime/tool-catalog.mjs +13 -2
  103. package/src/session-runtime/tool-defs.mjs +1 -3
  104. package/src/standalone/agent-task-status.mjs +50 -11
  105. package/src/standalone/agent-tool/tool-def.mjs +1 -1
  106. package/src/standalone/explore-tool.mjs +257 -49
  107. package/src/standalone/seeds.mjs +1 -0
  108. package/src/tui/App.jsx +26 -16
  109. package/src/tui/app/use-transcript-scroll.mjs +4 -3
  110. package/src/tui/app/use-transcript-window.mjs +12 -21
  111. package/src/tui/components/ContextPanel.jsx +19 -25
  112. package/src/tui/dist/index.mjs +89 -78
  113. package/src/tui/engine/agent-envelope.mjs +16 -5
  114. package/src/tui/engine/labels.mjs +1 -1
  115. package/src/workflows/default/WORKFLOW.md +21 -51
  116. package/src/workflows/solo/WORKFLOW.md +12 -17
  117. package/src/workflows/solo-review/WORKFLOW.md +0 -47
@@ -63,7 +63,8 @@ function usageColor(pct) {
63
63
 
64
64
  function ProgressBar({ value = 0, total = 0, width = 24 }) {
65
65
  const pct = percent(value, total) ?? 0;
66
- const safeWidth = Math.max(8, Math.floor(width));
66
+ const safeWidth = Math.max(0, Math.floor(width));
67
+ if (safeWidth === 0) return null;
67
68
  const filled = Math.max(0, Math.min(safeWidth, Math.round((pct / 100) * safeWidth)));
68
69
  const empty = safeWidth - filled;
69
70
  return (
@@ -95,28 +96,27 @@ function bucketTokens(map, names) {
95
96
  return names.reduce((sum, name) => sum + finiteNumber(map?.[name]?.tokens), 0);
96
97
  }
97
98
 
98
- function bucketCount(map, names) {
99
- return names.reduce((sum, name) => sum + finiteNumber(map?.[name]?.count), 0);
100
- }
101
-
102
99
  function semanticTokens(semantic, names) {
103
100
  return names.reduce((sum, name) => sum + finiteNumber(semantic?.[name]?.tokens), 0);
104
101
  }
105
102
 
106
103
  function CategoryItem({ label, tokens, total, width }) {
107
- const labelWidth = Math.min(11, Math.max(7, Math.floor(width * 0.22)));
104
+ const rowWidth = Math.max(0, Math.floor(width));
105
+ const labelWidth = Math.min(11, Math.max(7, Math.floor(rowWidth * 0.22)));
108
106
  const pctWidth = 6;
109
- const tokenWidth = 7;
110
- const barWidth = Math.max(6, Math.min(20, width - labelWidth - pctWidth - tokenWidth - 4));
107
+ const structuralWidth = labelWidth + 1 + pctWidth + 1;
108
+ const flexibleWidth = Math.max(0, rowWidth - structuralWidth);
109
+ const tokenWidth = Math.min(7, flexibleWidth);
110
+ const barWidth = Math.max(0, flexibleWidth - tokenWidth);
111
111
  const pct = percent(tokens, total);
112
112
  return (
113
- <Box flexDirection="row" width={width}>
113
+ <Box flexDirection="row" width={rowWidth}>
114
114
  <Text color={theme.subtle}>{padCells(truncateText(label, labelWidth), labelWidth)}</Text>
115
115
  <Text color={theme.inactive}> </Text>
116
116
  <Text color={usageColor(pct)}>{padCells(percentLabel(tokens, total), pctWidth)}</Text>
117
117
  <ProgressBar value={tokens} total={total} width={barWidth} />
118
118
  <Text color={theme.inactive}> </Text>
119
- <Text color={theme.text}>{padCells(formatTokens(tokens), tokenWidth)}</Text>
119
+ <Text color={theme.text}>{padCells(truncateText(formatTokens(tokens), tokenWidth), tokenWidth)}</Text>
120
120
  </Box>
121
121
  );
122
122
  }
@@ -156,13 +156,9 @@ function ContextUsageView({ detail, columns }) {
156
156
  const usage = detail?.usage || {};
157
157
  const compaction = detail?.compaction || {};
158
158
  const messages = detail?.messages || {};
159
- const tools = detail?.tools || {};
160
- const toolIo = detail?.toolIo || {};
161
159
  const request = detail?.request || {};
162
160
  const lastApi = detail?.lastApi || {};
163
161
  const cache = detail?.cache || {};
164
- const extensions = detail?.extensions || {};
165
- const mcp = detail?.mcp || {};
166
162
  const semantic = messages.semantic || {};
167
163
  const schema = request.toolSchemaBreakdown || {};
168
164
  const usedTokens = finiteNumber(usage.usedTokens);
@@ -173,7 +169,6 @@ function ContextUsageView({ detail, columns }) {
173
169
  const pctText = `${percentLabel(usedTokens, windowTokens)} used`;
174
170
  const barWidth = Math.max(12, Math.min(34, innerWidth - stringWidth(summaryText) - stringWidth(pctText) - 5));
175
171
  const builtInToolTokens = bucketTokens(schema, ['code', 'web', 'mutation', 'channels', 'setup', 'other']);
176
- const builtInToolCount = bucketCount(schema, ['code', 'web', 'mutation', 'channels', 'setup', 'other']);
177
172
  const sessionTokens = semanticTokens(semantic, ['workspace', 'environment', 'other']);
178
173
  const compactionLine = metricValue([
179
174
  compaction.stage && compaction.stage !== 'pending' ? compaction.stage : '',
@@ -194,16 +189,15 @@ function ContextUsageView({ detail, columns }) {
194
189
  `cache ${cache.hitRate || 'N/A'}`,
195
190
  ]);
196
191
  const categories = [
197
- { label: 'Messages', tokens: semanticTokens(semantic, ['chat', 'assistant']), meta: '' },
198
- { label: 'Tools', tokens: builtInToolTokens, meta: `${tools.active || 0}/${tools.count || 0} active${builtInToolCount ? ` · ${builtInToolCount} defs` : ''}` },
199
- { label: 'MCP', tokens: bucketTokens(schema, ['mcp']), meta: `${mcp.connected || 0}/${mcp.configured || 0} servers` },
200
- { label: 'Skills', tokens: bucketTokens(schema, ['skills']), meta: `${extensions.skills || 0} skills` },
201
- { label: 'Memory', tokens: semanticTokens(semantic, ['memory']) + bucketTokens(schema, ['memory']), meta: 'core + recall tools' },
202
- { label: 'Session', tokens: sessionTokens, meta: 'workspace · environment' },
203
- { label: 'Workflow', tokens: semanticTokens(semantic, ['workflow']) + bucketTokens(schema, ['agents']), meta: 'workflow · agents' },
204
- { label: 'System', tokens: semanticTokens(semantic, ['system']), meta: 'rules · role catalog' },
205
- { label: 'Overhead', tokens: finiteNumber(request.overheadTokens), meta: 'request frame' },
206
- { label: 'Tool I/O', tokens: semanticTokens(semantic, ['toolResults']), meta: `${toolIo.calls || 0} calls · ${toolIo.results || 0} results` },
192
+ { label: 'Messages', tokens: semanticTokens(semantic, ['chat', 'assistant']) },
193
+ { label: 'Tools', tokens: builtInToolTokens },
194
+ { label: 'MCP', tokens: bucketTokens(schema, ['mcp']) },
195
+ { label: 'Skills', tokens: bucketTokens(schema, ['skills']) },
196
+ { label: 'Memory', tokens: semanticTokens(semantic, ['memory']) + bucketTokens(schema, ['memory']) },
197
+ { label: 'Session', tokens: sessionTokens },
198
+ { label: 'Workflow', tokens: semanticTokens(semantic, ['workflow']) + bucketTokens(schema, ['agents']) },
199
+ { label: 'System', tokens: semanticTokens(semantic, ['system']) },
200
+ { label: 'Tool I/O', tokens: semanticTokens(semantic, ['toolResults']) },
207
201
  ];
208
202
 
209
203
  return (
@@ -3140,8 +3140,8 @@ function formatAggregateDetail(summaries) {
3140
3140
  }
3141
3141
 
3142
3142
  // src/runtime/shared/update-checker.mjs
3143
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3144
- import { dirname as dirname2, join as join2 } from "node:path";
3143
+ import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
3144
+ import { basename, delimiter, dirname as dirname2, join as join2 } from "node:path";
3145
3145
  import { fileURLToPath as fileURLToPath2 } from "node:url";
3146
3146
 
3147
3147
  // src/runtime/shared/plugin-paths.mjs
@@ -6120,7 +6120,8 @@ function usageColor(pct) {
6120
6120
  }
6121
6121
  function ProgressBar({ value = 0, total = 0, width = 24 }) {
6122
6122
  const pct = percent(value, total) ?? 0;
6123
- const safeWidth2 = Math.max(8, Math.floor(width));
6123
+ const safeWidth2 = Math.max(0, Math.floor(width));
6124
+ if (safeWidth2 === 0) return null;
6124
6125
  const filled = Math.max(0, Math.min(safeWidth2, Math.round(pct / 100 * safeWidth2)));
6125
6126
  const empty = safeWidth2 - filled;
6126
6127
  return /* @__PURE__ */ jsxs6(Box8, { flexDirection: "row", width: safeWidth2, children: [
@@ -6144,25 +6145,25 @@ function DetailLine({ label, value, columns }) {
6144
6145
  function bucketTokens(map, names) {
6145
6146
  return names.reduce((sum, name) => sum + finiteNumber(map?.[name]?.tokens), 0);
6146
6147
  }
6147
- function bucketCount(map, names) {
6148
- return names.reduce((sum, name) => sum + finiteNumber(map?.[name]?.count), 0);
6149
- }
6150
6148
  function semanticTokens(semantic, names) {
6151
6149
  return names.reduce((sum, name) => sum + finiteNumber(semantic?.[name]?.tokens), 0);
6152
6150
  }
6153
6151
  function CategoryItem({ label, tokens, total, width }) {
6154
- const labelWidth = Math.min(11, Math.max(7, Math.floor(width * 0.22)));
6152
+ const rowWidth = Math.max(0, Math.floor(width));
6153
+ const labelWidth = Math.min(11, Math.max(7, Math.floor(rowWidth * 0.22)));
6155
6154
  const pctWidth = 6;
6156
- const tokenWidth = 7;
6157
- const barWidth = Math.max(6, Math.min(20, width - labelWidth - pctWidth - tokenWidth - 4));
6155
+ const structuralWidth = labelWidth + 1 + pctWidth + 1;
6156
+ const flexibleWidth = Math.max(0, rowWidth - structuralWidth);
6157
+ const tokenWidth = Math.min(7, flexibleWidth);
6158
+ const barWidth = Math.max(0, flexibleWidth - tokenWidth);
6158
6159
  const pct = percent(tokens, total);
6159
- return /* @__PURE__ */ jsxs6(Box8, { flexDirection: "row", width, children: [
6160
+ return /* @__PURE__ */ jsxs6(Box8, { flexDirection: "row", width: rowWidth, children: [
6160
6161
  /* @__PURE__ */ jsx8(Text8, { color: theme.subtle, children: padCells3(truncateText3(label, labelWidth), labelWidth) }),
6161
6162
  /* @__PURE__ */ jsx8(Text8, { color: theme.inactive, children: " " }),
6162
6163
  /* @__PURE__ */ jsx8(Text8, { color: usageColor(pct), children: padCells3(percentLabel(tokens, total), pctWidth) }),
6163
6164
  /* @__PURE__ */ jsx8(ProgressBar, { value: tokens, total, width: barWidth }),
6164
6165
  /* @__PURE__ */ jsx8(Text8, { color: theme.inactive, children: " " }),
6165
- /* @__PURE__ */ jsx8(Text8, { color: theme.text, children: padCells3(formatTokens(tokens), tokenWidth) })
6166
+ /* @__PURE__ */ jsx8(Text8, { color: theme.text, children: padCells3(truncateText3(formatTokens(tokens), tokenWidth), tokenWidth) })
6166
6167
  ] });
6167
6168
  }
6168
6169
  function CategoryGrid({ categories, columns, total }) {
@@ -6187,13 +6188,9 @@ function ContextUsageView({ detail, columns }) {
6187
6188
  const usage = detail?.usage || {};
6188
6189
  const compaction = detail?.compaction || {};
6189
6190
  const messages = detail?.messages || {};
6190
- const tools = detail?.tools || {};
6191
- const toolIo = detail?.toolIo || {};
6192
6191
  const request = detail?.request || {};
6193
6192
  const lastApi = detail?.lastApi || {};
6194
6193
  const cache = detail?.cache || {};
6195
- const extensions = detail?.extensions || {};
6196
- const mcp = detail?.mcp || {};
6197
6194
  const semantic = messages.semantic || {};
6198
6195
  const schema = request.toolSchemaBreakdown || {};
6199
6196
  const usedTokens = finiteNumber(usage.usedTokens);
@@ -6204,7 +6201,6 @@ function ContextUsageView({ detail, columns }) {
6204
6201
  const pctText = `${percentLabel(usedTokens, windowTokens)} used`;
6205
6202
  const barWidth = Math.max(12, Math.min(34, innerWidth - stringWidth4(summaryText) - stringWidth4(pctText) - 5));
6206
6203
  const builtInToolTokens = bucketTokens(schema, ["code", "web", "mutation", "channels", "setup", "other"]);
6207
- const builtInToolCount = bucketCount(schema, ["code", "web", "mutation", "channels", "setup", "other"]);
6208
6204
  const sessionTokens = semanticTokens(semantic, ["workspace", "environment", "other"]);
6209
6205
  const compactionLine = metricValue([
6210
6206
  compaction.stage && compaction.stage !== "pending" ? compaction.stage : "",
@@ -6225,16 +6221,15 @@ function ContextUsageView({ detail, columns }) {
6225
6221
  `cache ${cache.hitRate || "N/A"}`
6226
6222
  ]);
6227
6223
  const categories = [
6228
- { label: "Messages", tokens: semanticTokens(semantic, ["chat", "assistant"]), meta: "" },
6229
- { label: "Tools", tokens: builtInToolTokens, meta: `${tools.active || 0}/${tools.count || 0} active${builtInToolCount ? ` \xB7 ${builtInToolCount} defs` : ""}` },
6230
- { label: "MCP", tokens: bucketTokens(schema, ["mcp"]), meta: `${mcp.connected || 0}/${mcp.configured || 0} servers` },
6231
- { label: "Skills", tokens: bucketTokens(schema, ["skills"]), meta: `${extensions.skills || 0} skills` },
6232
- { label: "Memory", tokens: semanticTokens(semantic, ["memory"]) + bucketTokens(schema, ["memory"]), meta: "core + recall tools" },
6233
- { label: "Session", tokens: sessionTokens, meta: "workspace \xB7 environment" },
6234
- { label: "Workflow", tokens: semanticTokens(semantic, ["workflow"]) + bucketTokens(schema, ["agents"]), meta: "workflow \xB7 agents" },
6235
- { label: "System", tokens: semanticTokens(semantic, ["system"]), meta: "rules \xB7 role catalog" },
6236
- { label: "Overhead", tokens: finiteNumber(request.overheadTokens), meta: "request frame" },
6237
- { label: "Tool I/O", tokens: semanticTokens(semantic, ["toolResults"]), meta: `${toolIo.calls || 0} calls \xB7 ${toolIo.results || 0} results` }
6224
+ { label: "Messages", tokens: semanticTokens(semantic, ["chat", "assistant"]) },
6225
+ { label: "Tools", tokens: builtInToolTokens },
6226
+ { label: "MCP", tokens: bucketTokens(schema, ["mcp"]) },
6227
+ { label: "Skills", tokens: bucketTokens(schema, ["skills"]) },
6228
+ { label: "Memory", tokens: semanticTokens(semantic, ["memory"]) + bucketTokens(schema, ["memory"]) },
6229
+ { label: "Session", tokens: sessionTokens },
6230
+ { label: "Workflow", tokens: semanticTokens(semantic, ["workflow"]) + bucketTokens(schema, ["agents"]) },
6231
+ { label: "System", tokens: semanticTokens(semantic, ["system"]) },
6232
+ { label: "Tool I/O", tokens: semanticTokens(semantic, ["toolResults"]) }
6238
6233
  ];
6239
6234
  return /* @__PURE__ */ jsxs6(Box8, { flexDirection: "column", width: "100%", children: [
6240
6235
  /* @__PURE__ */ jsxs6(Box8, { flexDirection: "row", width: "100%", children: [
@@ -7128,7 +7123,7 @@ import { randomBytes } from "node:crypto";
7128
7123
  import { existsSync as existsSync2, unlinkSync } from "node:fs";
7129
7124
  import { readFile as readFileAsync, stat as statAsync } from "node:fs/promises";
7130
7125
  import { tmpdir } from "node:os";
7131
- import { basename, extname, isAbsolute, resolve } from "node:path";
7126
+ import { basename as basename2, extname, isAbsolute, resolve } from "node:path";
7132
7127
 
7133
7128
  // src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs
7134
7129
  var API_IMAGE_MAX_BASE64_SIZE = 5 * 1024 * 1024;
@@ -7396,7 +7391,7 @@ async function readImageAttachmentFromPath(rawPath, cwd = process.cwd()) {
7396
7391
  if (!st.isFile()) return null;
7397
7392
  const buffer = await readFileAsync(fullPath);
7398
7393
  return imageAttachmentFromBuffer(buffer, mimeType, {
7399
- filename: basename(fullPath),
7394
+ filename: basename2(fullPath),
7400
7395
  sourcePath: fullPath
7401
7396
  });
7402
7397
  }
@@ -7467,7 +7462,7 @@ async function readClipboardText() {
7467
7462
  // src/standalone/projects.mjs
7468
7463
  import { homedir as homedir2 } from "node:os";
7469
7464
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, statSync, writeFileSync as writeFileSync2 } from "node:fs";
7470
- import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve as resolve2 } from "node:path";
7465
+ import { basename as basename3, dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve as resolve2 } from "node:path";
7471
7466
  var MIXDOG_HOME = process.env.MIXDOG_HOME || join3(homedir2(), ".mixdog");
7472
7467
  var PROJECTS_FILE = join3(MIXDOG_HOME, "projects.json");
7473
7468
  function toAbsolute(rawPath) {
@@ -7487,7 +7482,7 @@ function readStore() {
7487
7482
  const projects = Array.isArray(parsed?.projects) ? parsed.projects : [];
7488
7483
  return {
7489
7484
  projects: projects.filter((entry) => entry && typeof entry.path === "string" && entry.path.trim()).map((entry) => ({
7490
- name: String(entry.name || basename2(entry.path) || entry.path),
7485
+ name: String(entry.name || basename3(entry.path) || entry.path),
7491
7486
  path: String(entry.path),
7492
7487
  addedAt: Number(entry.addedAt) || 0,
7493
7488
  ...Number(entry.lastSelectedAt) > 0 ? { lastSelectedAt: Number(entry.lastSelectedAt) } : {}
@@ -7517,7 +7512,7 @@ function ensureProjectIdMarker(absPath, name) {
7517
7512
  }
7518
7513
  const markerPath = join3(absPath, ".mixdog", "project.id");
7519
7514
  if (existsSync3(markerPath)) return;
7520
- const value = String(name || basename2(absPath) || "").trim();
7515
+ const value = String(name || basename3(absPath) || "").trim();
7521
7516
  if (!value || value.toLowerCase() === "common") return;
7522
7517
  const markerDir = join3(absPath, ".mixdog");
7523
7518
  mkdirSync2(markerDir, { recursive: true });
@@ -7555,7 +7550,7 @@ function addProject(rawPath) {
7555
7550
  return existing;
7556
7551
  }
7557
7552
  const entry = {
7558
- name: basename2(absPath) || absPath,
7553
+ name: basename3(absPath) || absPath,
7559
7554
  path: absPath,
7560
7555
  addedAt: Date.now()
7561
7556
  };
@@ -7584,7 +7579,7 @@ function renameProject(rawPath, nextName) {
7584
7579
  const entry = store.projects.find((item) => normalizeKey(item.path) === key);
7585
7580
  if (!entry) return null;
7586
7581
  const trimmed = String(nextName || "").trim();
7587
- entry.name = trimmed || basename2(absPath) || absPath;
7582
+ entry.name = trimmed || basename3(absPath) || absPath;
7588
7583
  writeStore(store);
7589
7584
  return entry;
7590
7585
  }
@@ -11588,7 +11583,7 @@ function useTranscriptScroll({
11588
11583
  if (appliedDelta !== 0) cancelTranscriptFollow();
11589
11584
  scrollTargetRef.current = target;
11590
11585
  if (appliedDelta !== 0) {
11591
- if (target <= Math.max(0, Number(transcriptBottomSlackRowsRef.current) || 0)) {
11586
+ if (target === 0) {
11592
11587
  transcriptAnchorRef.current = null;
11593
11588
  transcriptAnchorDirtyRef.current = false;
11594
11589
  } else {
@@ -11799,7 +11794,6 @@ function useTranscriptWindow({
11799
11794
  setMeasuredRowsVersion
11800
11795
  }) {
11801
11796
  const transcriptTotalRowsRef = useRef9(0);
11802
- const preservedScrollDeltaRef = useRef9(0);
11803
11797
  const committedMaxScrollRowsRef = useRef9(0);
11804
11798
  const incrementalRowIndexCacheRef = useRef9(null);
11805
11799
  const prevViewportGeomRef = useRef9({ contentHeight: 0, floatingPanelRows: 0 });
@@ -11831,7 +11825,7 @@ function useTranscriptWindow({
11831
11825
  }, []);
11832
11826
  const streamingTailItem = streamingTail?.kind === "assistant" && streamingTail.streaming ? streamingTail : null;
11833
11827
  const scrolledUpRowsForPin = Math.max(0, Number(scrollTargetRef.current) || 0);
11834
- const transcriptPinnedForStreaming = followingRef.current || scrolledUpRowsForPin <= transcriptBottomSlackRows;
11828
+ const transcriptPinnedForStreaming = followingRef.current || scrolledUpRowsForPin === 0;
11835
11829
  setStreamingBottomPinned(transcriptPinnedForStreaming);
11836
11830
  const tailRows = streamingTailItem ? estimateTranscriptItemRowsCached(streamingTailItem, frameColumns, toolOutputExpanded) : 0;
11837
11831
  const tailSig = streamingTailItem ? `${streamingTailItem.id}:${tailRows}` : "_";
@@ -11843,7 +11837,7 @@ function useTranscriptWindow({
11843
11837
  );
11844
11838
  const transcriptStructureSig = `${revision}#${tailSig}`;
11845
11839
  const transcriptStreamingActive = !!streamingTailItem;
11846
- const scrolledUpForStreamingMeasure = scrolledUpRowsForPin > transcriptBottomSlackRows;
11840
+ const scrolledUpForStreamingMeasure = scrolledUpRowsForPin > 0;
11847
11841
  const prevEstimateGeometry = transcriptGeomRef.current?.suppressMeasuredRowHeights === true;
11848
11842
  const hasStreamingReadingAnchor = !!transcriptAnchorRef.current || transcriptAnchorDirtyRef.current;
11849
11843
  const bottomPinnedForMeasure = transcriptPinnedForStreaming;
@@ -11859,7 +11853,7 @@ function useTranscriptWindow({
11859
11853
  }), [revision, tailSig, frameColumns, toolOutputExpanded, measuredRowsVersion, suppressMeasuredRowHeights]);
11860
11854
  const hasReadingAnchor = !!transcriptAnchorRef.current && !transcriptAnchorDirtyRef.current;
11861
11855
  const scrolledUpRows = Math.max(0, Number(scrollTargetRef.current) || 0);
11862
- const scrolledUp = scrolledUpRows > transcriptBottomSlackRows;
11856
+ const scrolledUp = scrolledUpRows > 0;
11863
11857
  const anchorLockActive = hasReadingAnchor && !followingRef.current && scrolledUp;
11864
11858
  const targetNearBottom = followingRef.current || !scrolledUp;
11865
11859
  const nearBottomWithoutAnchor = !transcriptAnchorRef.current && !transcriptAnchorDirtyRef.current && targetNearBottom;
@@ -12026,7 +12020,7 @@ function useTranscriptWindow({
12026
12020
  overlayHintAttachItemIndex = i;
12027
12021
  break;
12028
12022
  }
12029
- const transcriptTailPinned = Math.max(0, Number(transcriptWindow.effectiveScrollOffset) || 0) <= transcriptBottomSlackRows;
12023
+ const transcriptTailPinned = Math.max(0, Number(transcriptWindow.effectiveScrollOffset) || 0) === 0;
12030
12024
  const overlayHintOnLastItem = overlayHintRequested && floatingPanelRows <= 0 && transcriptWindow.bottomSpacerRows === 0 && transcriptTailPinned && overlayHintAttachItemIndex >= 0;
12031
12025
  const overlayHintFallbackRow = overlayHintRequested && floatingPanelRows <= 0 && transcriptGuardRows > 0 && !overlayHintOnLastItem;
12032
12026
  useLayoutEffect3(() => {
@@ -12113,7 +12107,7 @@ function useTranscriptWindow({
12113
12107
  const currentPosition = Math.max(0, Number(scrollPositionRef.current) || 0);
12114
12108
  const currentOffset = Math.max(0, Number(scrollOffset) || 0);
12115
12109
  const maxRows = Math.max(0, Number(transcriptWindow.maxScrollRows) || 0);
12116
- const nearBottom = followingRef.current || currentTarget <= transcriptBottomSlackRows;
12110
+ const nearBottom = followingRef.current || currentTarget === 0;
12117
12111
  const pinnedToBottom = nearBottom;
12118
12112
  const activeReadingAnchor = !!transcriptAnchorRef.current && !transcriptAnchorDirtyRef.current && !followingRef.current && !nearBottom;
12119
12113
  const followOnGrowth = followingRef.current && rowDelta > 0 && !activeReadingAnchor;
@@ -12171,22 +12165,20 @@ function useTranscriptWindow({
12171
12165
  stopSmoothScroll();
12172
12166
  scrollTargetRef.current = desired;
12173
12167
  scrollPositionRef.current = Math.max(0, Math.min(maxRows, currentPosition + appliedDelta));
12174
- preservedScrollDeltaRef.current += appliedDelta;
12175
12168
  setScrollOffset(Math.max(0, Math.round(desired)));
12176
- }, [transcriptWindow.totalRows, transcriptWindow.maxScrollRows, transcriptRowIndex, transcriptContentHeight, transcriptBottomSlackRows, scrollOffset, stopSmoothScroll]);
12169
+ }, [transcriptWindow.totalRows, transcriptWindow.maxScrollRows, transcriptRowIndex, transcriptContentHeight, scrollOffset, stopSmoothScroll]);
12177
12170
  useLayoutEffect3(() => {
12178
- if (transcriptBottomSlackRows <= 0) return;
12179
12171
  if (transcriptAnchorRef.current || transcriptAnchorDirtyRef.current || followingRef.current) return;
12180
12172
  const currentTarget = Math.max(0, Number(scrollTargetRef.current) || 0);
12181
12173
  const currentPosition = Math.max(0, Number(scrollPositionRef.current) || 0);
12182
12174
  const currentOffset = Math.max(0, Number(scrollOffset) || 0);
12175
+ if (currentTarget !== 0) return;
12183
12176
  if (Math.max(currentTarget, currentPosition, currentOffset) === 0) return;
12184
- if (Math.max(currentTarget, currentPosition, currentOffset) > transcriptBottomSlackRows) return;
12185
12177
  stopSmoothScroll();
12186
12178
  scrollTargetRef.current = 0;
12187
12179
  scrollPositionRef.current = 0;
12188
12180
  setScrollOffset(0);
12189
- }, [transcriptBottomSlackRows, scrollOffset, stopSmoothScroll]);
12181
+ }, [scrollOffset, stopSmoothScroll]);
12190
12182
  useLayoutEffect3(() => {
12191
12183
  const top = Math.max(0, Number(transcriptViewportRef.current?.top) || 0);
12192
12184
  const next = {
@@ -12195,11 +12187,6 @@ function useTranscriptWindow({
12195
12187
  totalRows: Math.max(0, Number(transcriptWindow.totalRows) || 0),
12196
12188
  scrollOffset: Math.max(0, Number(transcriptWindow.effectiveScrollOffset) || 0)
12197
12189
  };
12198
- const preservedDelta = Number(preservedScrollDeltaRef.current) || 0;
12199
- if (preservedDelta !== 0) {
12200
- next.scrollOffset = Math.max(0, next.scrollOffset + preservedDelta);
12201
- preservedScrollDeltaRef.current = 0;
12202
- }
12203
12190
  const previous = selectionLayoutRef.current;
12204
12191
  selectionLayoutRef.current = next;
12205
12192
  if (!previous || !dragRef.current.rect || dragRef.current.active) return;
@@ -14371,7 +14358,7 @@ function createOnboardingSteps({
14371
14358
  // src/runtime/shared/config.mjs
14372
14359
  import { readFileSync as readFileSync5, statSync as statSync4, mkdirSync as mkdirSync5, existsSync as existsSync6 } from "fs";
14373
14360
  import { join as join6, dirname as dirname6 } from "path";
14374
- import { createRequire as createRequire2 } from "module";
14361
+ import { createRequire as createRequire3 } from "module";
14375
14362
 
14376
14363
  // src/runtime/shared/atomic-file.mjs
14377
14364
  import {
@@ -14387,7 +14374,7 @@ import {
14387
14374
  unlinkSync as unlinkSync2,
14388
14375
  writeFileSync as writeFileSync3
14389
14376
  } from "fs";
14390
- import { dirname as dirname4, basename as basename3, join as join4 } from "path";
14377
+ import { dirname as dirname4, basename as basename4, join as join4 } from "path";
14391
14378
  import { randomBytes as randomBytes2 } from "crypto";
14392
14379
  import { execFile as execFile2, execFileSync } from "child_process";
14393
14380
  import { promisify } from "util";
@@ -14843,7 +14830,7 @@ function writeFileAtomicSync(filePath, data, opts = {}) {
14843
14830
  const run = () => {
14844
14831
  const dir = dirname4(filePath);
14845
14832
  mkdirSync3(dir, { recursive: true });
14846
- const tmp = join4(dir, `.${basename3(filePath)}.${randomBytes2(12).toString("hex")}.tmp`);
14833
+ const tmp = join4(dir, `.${basename4(filePath)}.${randomBytes2(12).toString("hex")}.tmp`);
14847
14834
  try {
14848
14835
  const writeOpts = { encoding: opts.encoding || "utf8", flag: "wx", mode: opts.mode !== void 0 ? opts.mode : 384 };
14849
14836
  writeFileSync3(tmp, data, writeOpts);
@@ -15080,8 +15067,24 @@ function backupUserData(dataDir, reason = "snapshot") {
15080
15067
  }
15081
15068
  var CASE_INSENSITIVE = process.platform === "win32";
15082
15069
 
15070
+ // src/runtime/shared/provider-api-key.mjs
15071
+ import { createRequire as createRequire2 } from "node:module";
15072
+ var require2 = createRequire2(import.meta.url);
15073
+ var { getSecret } = require2("../../lib/keychain-cjs.cjs");
15074
+ var AGENT_PROVIDER_ENV = Object.freeze({
15075
+ openai: "OPENAI_API_KEY",
15076
+ anthropic: "ANTHROPIC_API_KEY",
15077
+ gemini: "GEMINI_API_KEY",
15078
+ deepseek: "DEEPSEEK_API_KEY",
15079
+ xai: "XAI_API_KEY",
15080
+ "opencode-go": "OPENCODE_API_KEY"
15081
+ });
15082
+ var AGENT_PROVIDER_ENV_ALIASES = Object.freeze({
15083
+ xai: ["GROK_API_KEY"]
15084
+ });
15085
+
15083
15086
  // src/runtime/shared/config.mjs
15084
- var _require = createRequire2(import.meta.url);
15087
+ var _require = createRequire3(import.meta.url);
15085
15088
  var { getSecret: _getSecret, setSecret: _setSecret, deleteSecret: _deleteSecret, hasSecret: _hasSecret } = _require("../../lib/keychain-cjs.cjs");
15086
15089
  var DATA_DIR = resolvePluginData();
15087
15090
  var CONFIG_PATH = join6(DATA_DIR, "mixdog-config.json");
@@ -15280,17 +15283,6 @@ var SECRET_ACCOUNTS = Object.freeze({
15280
15283
  openaiUsageSessionKey: "agent.openai.usageSessionKey",
15281
15284
  opencodeGoAuthCookie: "agent.opencode-go.authCookie"
15282
15285
  });
15283
- var AGENT_PROVIDER_ENV = Object.freeze({
15284
- openai: "OPENAI_API_KEY",
15285
- anthropic: "ANTHROPIC_API_KEY",
15286
- gemini: "GEMINI_API_KEY",
15287
- deepseek: "DEEPSEEK_API_KEY",
15288
- xai: "XAI_API_KEY",
15289
- "opencode-go": "OPENCODE_API_KEY"
15290
- });
15291
- var AGENT_PROVIDER_ENV_ALIASES = Object.freeze({
15292
- xai: ["GROK_API_KEY"]
15293
- });
15294
15286
 
15295
15287
  // src/tui/lib/voice-setup.mjs
15296
15288
  var _voiceRuntimeFetcherPromise = null;
@@ -19528,8 +19520,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19528
19520
  const [resizeState, setResizeState] = useState8(() => ({ ...terminalSize(stdout2), epoch: 0 }));
19529
19521
  const [panelTransitionEpoch, setPanelTransitionEpoch] = useState8(0);
19530
19522
  const [panelInkMaskEpoch, setPanelInkMaskEpoch] = useState8(0);
19531
- const windowsLikeTerminal = process.platform === "win32" || Boolean(process.env.WT_SESSION);
19532
- const rightSafetyColumns = windowsLikeTerminal ? 1 : 0;
19523
+ const rightSafetyColumns = 1;
19533
19524
  const frameColumns = Math.max(1, resizeState.columns - rightSafetyColumns);
19534
19525
  const [scrollOffset, setScrollOffset] = useState8(0);
19535
19526
  const scrollPositionRef = useRef10(0);
@@ -20275,7 +20266,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
20275
20266
  return;
20276
20267
  }
20277
20268
  if (count === previousCount || dragRef.current.active) return;
20278
- if (scrollTargetRef.current <= transcriptBottomSlackRows || followingRef.current) followingRef.current = true;
20269
+ if (scrollTargetRef.current === 0 || followingRef.current) followingRef.current = true;
20279
20270
  }, [state.items.length, resetTranscriptScroll]);
20280
20271
  const requestExit = useCallback6(() => {
20281
20272
  if (exitRequestedRef.current) return;
@@ -20512,7 +20503,13 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
20512
20503
  }, 0);
20513
20504
  };
20514
20505
  const openContextPicker = () => {
20515
- const tools = store.toolsStatus?.() || { activeCount: 0, count: 0, activeTools: [] };
20506
+ const tools = store.toolsStatus?.() || {
20507
+ activeCount: 0,
20508
+ count: 0,
20509
+ mcpToolCount: 0,
20510
+ activeMcpToolCount: 0,
20511
+ activeTools: []
20512
+ };
20516
20513
  const mcp = store.mcpStatus?.() || { connectedCount: 0, configuredCount: 0, failedCount: 0 };
20517
20514
  const skills = store.skillsStatus?.() || { count: 0 };
20518
20515
  const plugins = store.pluginsStatus?.() || { count: 0 };
@@ -20520,6 +20517,13 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
20520
20517
  const usage = context.usage || {};
20521
20518
  const messages = context.messages || {};
20522
20519
  const request = context.request || {};
20520
+ const schemaBreakdown = request.toolSchemaBreakdown || {};
20521
+ const schemaTokensFor = (buckets) => buckets.reduce(
20522
+ (sum, bucket) => sum + Number(schemaBreakdown?.[bucket]?.tokens || 0),
20523
+ 0
20524
+ );
20525
+ const builtInToolSchemaTokens = schemaTokensFor(["code", "web", "mutation", "channels", "setup", "other"]);
20526
+ const mcpToolSchemaTokens = schemaTokensFor(["mcp"]);
20523
20527
  const compaction = context.compaction || {};
20524
20528
  const windowTokens = Number(context.contextWindow || state.contextWindow || context.rawContextWindow || state.rawContextWindow || 0);
20525
20529
  const rawWindowTokens = Number(context.rawContextWindow || state.rawContextWindow || windowTokens || 0);
@@ -20587,7 +20591,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
20587
20591
  {
20588
20592
  value: "tools",
20589
20593
  label: "Tools",
20590
- description: `${fmt(request.toolSchemaTokens)} schema tokens (${pct(request.toolSchemaTokens)}) \xB7 ${tools.activeCount || 0}/${tools.count || 0} active`,
20594
+ description: `${fmt(builtInToolSchemaTokens)} schema tokens (${pct(builtInToolSchemaTokens)}) \xB7 ${tools.activeCount || 0}/${tools.count || 0} active`,
20591
20595
  _action: "tools"
20592
20596
  },
20593
20597
  {
@@ -20661,7 +20665,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
20661
20665
  semantic: messages.semantic
20662
20666
  },
20663
20667
  tools: {
20664
- schemaTokens: request.toolSchemaTokens,
20668
+ schemaTokens: builtInToolSchemaTokens,
20665
20669
  active: tools.activeCount,
20666
20670
  count: tools.count
20667
20671
  },
@@ -20692,7 +20696,10 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
20692
20696
  mcp: {
20693
20697
  connected: mcp.connectedCount,
20694
20698
  configured: mcp.configuredCount,
20695
- failed: mcp.failedCount
20699
+ failed: mcp.failedCount,
20700
+ tools: tools.mcpToolCount,
20701
+ activeTools: tools.activeMcpToolCount,
20702
+ schemaTokens: mcpToolSchemaTokens
20696
20703
  }
20697
20704
  },
20698
20705
  rows: contextRows
@@ -22226,7 +22233,7 @@ function compactEventDetail(event = {}) {
22226
22233
  const trigger = String(event.trigger || "").toLowerCase();
22227
22234
  if (trigger === "reactive") parts.push("reactive");
22228
22235
  else if (trigger === "manual") parts.push("manual");
22229
- const before = Number(event.beforeTokens ?? event.pressureTokens ?? 0);
22236
+ const before = Number(event.pressureTokens ?? event.beforeTokens ?? 0);
22230
22237
  const after = Number(event.afterTokens ?? 0);
22231
22238
  const fmtTok = (n) => {
22232
22239
  const v = Number(n) || 0;
@@ -22684,7 +22691,10 @@ function parseAgentJob(text) {
22684
22691
  const targetMatch = /^target:\s*(.+)$/m.exec(value);
22685
22692
  const agentMatch = /^agent:\s*(.+)$/m.exec(value);
22686
22693
  const presetMatch = /^preset:\s*(.+)$/m.exec(value);
22687
- const modelMatch = /^model:\s*([^/\s]+)\/(.+)$/m.exec(value);
22694
+ const isAgentEnvelope = /^agent task:\s*/mi.test(value) || /^agent result\b/mi.test(value) || /^surface:\s*agent\s*$/mi.test(value);
22695
+ const providerMatch = isAgentEnvelope ? /^provider:\s*(.+)$/m.exec(value) : null;
22696
+ const modelLineMatch = isAgentEnvelope ? /^model:\s*(.+)$/m.exec(value) : null;
22697
+ const providerModelMatch = /^([^/\s]+)\/(.+)$/.exec(modelLineMatch?.[1]?.trim() || "");
22688
22698
  const effortMatch = /^effort:\s*(.+)$/m.exec(value);
22689
22699
  const fastMatch = /^fast:\s*(on|off|true|false)$/m.exec(value);
22690
22700
  return {
@@ -22694,8 +22704,8 @@ function parseAgentJob(text) {
22694
22704
  target: (targetMatch?.[1] || "").trim(),
22695
22705
  agent: (agentMatch?.[1] || "").trim(),
22696
22706
  preset: (presetMatch?.[1] || "").trim(),
22697
- provider: (modelMatch?.[1] || "").trim(),
22698
- model: (modelMatch?.[2] || "").trim(),
22707
+ provider: (providerMatch?.[1] || providerModelMatch?.[1] || "").trim(),
22708
+ model: (providerModelMatch?.[2] || modelLineMatch?.[1] || "").trim(),
22699
22709
  effort: (effortMatch?.[1] || "").trim(),
22700
22710
  fast: fastMatch ? /^(on|true)$/i.test(fastMatch[1]) : void 0
22701
22711
  };
@@ -22712,8 +22722,9 @@ function agentArgsWithResultMetadata(args, parsed) {
22712
22722
  if (parsed.taskId) next.task_id = parsed.taskId;
22713
22723
  if (parsed.agent) next.agent = parsed.agent;
22714
22724
  if (parsed.preset) next.preset = parsed.preset;
22715
- if (parsed.provider) next.provider = parsed.provider;
22716
- if (parsed.model) next.model = parsed.model;
22725
+ const hasExplicitProvider = [next.provider, next.providerId, next.provider_id].some((value) => String(value || "").trim());
22726
+ if (parsed.provider && !hasExplicitProvider) next.provider = parsed.provider;
22727
+ if (parsed.model && !String(next.model || "").trim()) next.model = parsed.model;
22717
22728
  if (parsed.effort) next.effort = parsed.effort;
22718
22729
  if (parsed.fast !== void 0) next.fast = parsed.fast;
22719
22730
  if (!next.tag && parsed.target) {
@@ -251,7 +251,16 @@ export function parseAgentJob(text) {
251
251
  const targetMatch = /^target:\s*(.+)$/m.exec(value);
252
252
  const agentMatch = /^agent:\s*(.+)$/m.exec(value);
253
253
  const presetMatch = /^preset:\s*(.+)$/m.exec(value);
254
- const modelMatch = /^model:\s*([^/\s]+)\/(.+)$/m.exec(value);
254
+ // Spawn acknowledgements normally use `model: provider/model`, but agent
255
+ // completion envelopes carry the resolved route as separate provider/model
256
+ // fields. A generic tool result can also contain task_id/provider/model
257
+ // diagnostics, so only recognize either route shape on an agent envelope.
258
+ const isAgentEnvelope = /^agent task:\s*/mi.test(value)
259
+ || /^agent result\b/mi.test(value)
260
+ || /^surface:\s*agent\s*$/mi.test(value);
261
+ const providerMatch = isAgentEnvelope ? /^provider:\s*(.+)$/m.exec(value) : null;
262
+ const modelLineMatch = isAgentEnvelope ? /^model:\s*(.+)$/m.exec(value) : null;
263
+ const providerModelMatch = /^([^/\s]+)\/(.+)$/.exec(modelLineMatch?.[1]?.trim() || '');
255
264
  const effortMatch = /^effort:\s*(.+)$/m.exec(value);
256
265
  const fastMatch = /^fast:\s*(on|off|true|false)$/m.exec(value);
257
266
  return {
@@ -261,8 +270,8 @@ export function parseAgentJob(text) {
261
270
  target: (targetMatch?.[1] || '').trim(),
262
271
  agent: (agentMatch?.[1] || '').trim(),
263
272
  preset: (presetMatch?.[1] || '').trim(),
264
- provider: (modelMatch?.[1] || '').trim(),
265
- model: (modelMatch?.[2] || '').trim(),
273
+ provider: (providerMatch?.[1] || providerModelMatch?.[1] || '').trim(),
274
+ model: (providerModelMatch?.[2] || modelLineMatch?.[1] || '').trim(),
266
275
  effort: (effortMatch?.[1] || '').trim(),
267
276
  fast: fastMatch ? /^(on|true)$/i.test(fastMatch[1]) : undefined,
268
277
  };
@@ -284,8 +293,10 @@ export function agentArgsWithResultMetadata(args, parsed) {
284
293
  if (parsed.taskId) next.task_id = parsed.taskId;
285
294
  if (parsed.agent) next.agent = parsed.agent;
286
295
  if (parsed.preset) next.preset = parsed.preset;
287
- if (parsed.provider) next.provider = parsed.provider;
288
- if (parsed.model) next.model = parsed.model;
296
+ const hasExplicitProvider = [next.provider, next.providerId, next.provider_id]
297
+ .some((value) => String(value || '').trim());
298
+ if (parsed.provider && !hasExplicitProvider) next.provider = parsed.provider;
299
+ if (parsed.model && !String(next.model || '').trim()) next.model = parsed.model;
289
300
  if (parsed.effort) next.effort = parsed.effort;
290
301
  if (parsed.fast !== undefined) next.fast = parsed.fast;
291
302
  if (!next.tag && parsed.target) {
@@ -50,7 +50,7 @@ export function compactEventDetail(event = {}) {
50
50
  const trigger = String(event.trigger || '').toLowerCase();
51
51
  if (trigger === 'reactive') parts.push('reactive');
52
52
  else if (trigger === 'manual') parts.push('manual');
53
- const before = Number(event.beforeTokens ?? event.pressureTokens ?? 0);
53
+ const before = Number(event.pressureTokens ?? event.beforeTokens ?? 0);
54
54
  const after = Number(event.afterTokens ?? 0);
55
55
  const fmtTok = (n) => {
56
56
  const v = Number(n) || 0;