mixdog 0.9.46 → 0.9.49

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 (90) hide show
  1. package/package.json +14 -4
  2. package/scripts/agent-parallel-smoke.mjs +4 -1
  3. package/scripts/agent-route-batch-test.mjs +40 -0
  4. package/scripts/code-graph-aggregate-cwd-test.mjs +154 -0
  5. package/scripts/code-graph-description-contract.mjs +185 -0
  6. package/scripts/code-graph-disk-hit-test.mjs +55 -0
  7. package/scripts/code-graph-dispatch-test.mjs +96 -0
  8. package/scripts/compact-pressure-test.mjs +40 -0
  9. package/scripts/deferred-tool-loading-test.mjs +233 -0
  10. package/scripts/execution-completion-dedup-test.mjs +48 -0
  11. package/scripts/explore-prompt-policy-test.mjs +88 -3
  12. package/scripts/live-worker-smoke.mjs +68 -16
  13. package/scripts/memory-core-input-test.mjs +33 -13
  14. package/scripts/native-edit-wire-test.mjs +152 -0
  15. package/scripts/openai-oauth-ws-1006-retry-test.mjs +294 -16
  16. package/scripts/patch-binary-cache-test.mjs +181 -0
  17. package/scripts/prompt-immediate-render-test.mjs +89 -0
  18. package/scripts/provider-toolcall-test.mjs +280 -15
  19. package/scripts/shell-failure-diagnostics-test.mjs +211 -0
  20. package/scripts/statusline-quota-hysteresis-test.mjs +26 -1
  21. package/scripts/streaming-tail-window-test.mjs +29 -0
  22. package/scripts/tool-failures.mjs +21 -3
  23. package/scripts/tool-smoke.mjs +263 -38
  24. package/scripts/tool-tui-presentation-test.mjs +17 -1
  25. package/scripts/tui-perf-run.ps1 +26 -0
  26. package/scripts/tui-transcript-perf-test.mjs +7 -1
  27. package/scripts/verify-release-assets-test.mjs +647 -0
  28. package/scripts/verify-release-assets.mjs +293 -0
  29. package/scripts/windows-hide-spawn-options-test.mjs +19 -0
  30. package/src/cli.mjs +1 -0
  31. package/src/defaults/cycle3-review-prompt.md +10 -4
  32. package/src/defaults/memory-promote-prompt.md +4 -3
  33. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +16 -5
  34. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +35 -11
  35. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +35 -11
  36. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +28 -0
  37. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +1 -1
  38. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +34 -34
  39. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +45 -38
  40. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +36 -11
  41. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +4 -4
  42. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +10 -6
  43. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +4 -3
  44. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +4 -3
  45. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +16 -1
  46. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +2 -2
  47. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +0 -1
  48. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +13 -8
  49. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +30 -16
  50. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +25 -8
  51. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +69 -4
  52. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +5 -4
  53. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  54. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +12 -12
  55. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +12 -7
  56. package/src/runtime/agent/orchestrator/tools/patch-binary-fetcher.mjs +77 -18
  57. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
  58. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +99 -24
  59. package/src/runtime/memory/lib/memory-action-handlers.mjs +21 -11
  60. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +13 -5
  61. package/src/runtime/memory/lib/memory-cycle2.mjs +8 -5
  62. package/src/runtime/memory/lib/memory-cycle3.mjs +41 -6
  63. package/src/runtime/memory/lib/query-handlers.mjs +49 -6
  64. package/src/runtime/memory/lib/recall-format.mjs +21 -6
  65. package/src/runtime/memory/tool-defs.mjs +2 -3
  66. package/src/session-runtime/context-status.mjs +25 -16
  67. package/src/session-runtime/model-route-api.mjs +2 -0
  68. package/src/session-runtime/runtime-core.mjs +2 -2
  69. package/src/session-runtime/session-turn-api.mjs +4 -1
  70. package/src/session-runtime/tool-catalog.mjs +113 -19
  71. package/src/session-runtime/tool-defs.mjs +1 -0
  72. package/src/standalone/agent-tool/helpers.mjs +25 -6
  73. package/src/standalone/agent-tool.mjs +75 -41
  74. package/src/tui/App.jsx +4 -0
  75. package/src/tui/app/input-parsers.mjs +8 -9
  76. package/src/tui/components/Markdown.jsx +6 -1
  77. package/src/tui/components/Message.jsx +11 -2
  78. package/src/tui/components/PromptInput.jsx +19 -21
  79. package/src/tui/components/Spinner.jsx +4 -4
  80. package/src/tui/components/StatusLine.jsx +6 -6
  81. package/src/tui/components/TranscriptItem.jsx +2 -2
  82. package/src/tui/components/prompt-input/immediate-render.mjs +47 -0
  83. package/src/tui/components/tool-execution/surface-detail.mjs +14 -9
  84. package/src/tui/dist/index.mjs +130 -45
  85. package/src/tui/engine/agent-job-feed.mjs +21 -2
  86. package/src/tui/engine/turn.mjs +12 -1
  87. package/src/tui/markdown/measure-rendered-rows.mjs +1 -1
  88. package/src/tui/markdown/streaming-markdown.mjs +20 -0
  89. package/src/ui/statusline.mjs +5 -5
  90. package/src/vendor/statusline/src/gateway/session-routes.mjs +22 -10
@@ -79,6 +79,9 @@ export function createAgentJobFeed({
79
79
  const terminalExecutionNotificationKeys = new Set();
80
80
  const terminalExecutionResponseKeys = new Set();
81
81
  const executionNotificationKeys = new Map();
82
+ const AGENT_STATUS_COALESCE_MS = 16;
83
+ let agentStatusRefreshTimer = null;
84
+ let agentStatusRefreshForce = false;
82
85
 
83
86
  const clearExecutionDedupState = () => {
84
87
  displayedExecutionNotificationKeys.clear();
@@ -261,7 +264,16 @@ export function createAgentJobFeed({
261
264
  if (!parsed?.taskId) return;
262
265
  const status = String(parsed.status || '').toLowerCase();
263
266
  const terminal = /^(completed|complete|done|success|succeeded|ok|failed|error|timeout|killed|cancelled|canceled|denied)$/.test(status);
264
- set(agentStatusState(terminal ? { force: true } : undefined));
267
+ agentStatusRefreshForce = agentStatusRefreshForce || terminal;
268
+ if (agentStatusRefreshTimer) return;
269
+ agentStatusRefreshTimer = setTimeout(() => {
270
+ agentStatusRefreshTimer = null;
271
+ if (getDisposed()) return;
272
+ const force = agentStatusRefreshForce;
273
+ agentStatusRefreshForce = false;
274
+ set(agentStatusState(force ? { force: true } : undefined));
275
+ }, AGENT_STATUS_COALESCE_MS);
276
+ agentStatusRefreshTimer.unref?.();
265
277
  }
266
278
 
267
279
  function subscribeRuntimeNotifications() {
@@ -399,7 +411,14 @@ export function createAgentJobFeed({
399
411
  return true;
400
412
  });
401
413
  return () => {
402
- try { unsubscribe?.(); } finally { clearExecutionDedupState(); }
414
+ try {
415
+ unsubscribe?.();
416
+ } finally {
417
+ if (agentStatusRefreshTimer) clearTimeout(agentStatusRefreshTimer);
418
+ agentStatusRefreshTimer = null;
419
+ agentStatusRefreshForce = false;
420
+ clearExecutionDedupState();
421
+ }
403
422
  };
404
423
  }
405
424
 
@@ -1007,8 +1007,12 @@ export function createRunTurn(bag) {
1007
1007
  label: compactEventLabel(event),
1008
1008
  detail: compactEventDetail(event),
1009
1009
  });
1010
+ // Compaction itself remains owned by the pre-provider-send pass.
1011
+ // This event only refreshes the gauge from the already-mutated
1012
+ // transcript before another render can show stale pressure.
1013
+ syncContextStats({ allowEstimated: true });
1010
1014
  },
1011
- onStageChange: async (stage) => {
1015
+ onStageChange: async (stage, detail = null) => {
1012
1016
  if (!markTurnProgress(`stage:${String(stage || '')}`)) return;
1013
1017
  if (!getState().spinner) return;
1014
1018
  const value = String(stage || '');
@@ -1031,6 +1035,13 @@ export function createRunTurn(bag) {
1031
1035
  await yieldToRenderer();
1032
1036
  return;
1033
1037
  }
1038
+ if (value === 'reconnecting') {
1039
+ compactingActive = false;
1040
+ const retryVerb = String(detail?.message || 'Reconnecting');
1041
+ set({ spinner: { ...getState().spinner, mode: 'reconnecting', verb: retryVerb } });
1042
+ await yieldToRenderer();
1043
+ return;
1044
+ }
1034
1045
  if (value === 'requesting' || value === 'streaming') compactingActive = false;
1035
1046
  const mode = value === 'requesting'
1036
1047
  ? 'requesting'
@@ -67,7 +67,7 @@ export function measureStreamingMarkdownRenderedRows(text, columns, streamKey) {
67
67
  if (!value) return 1;
68
68
  const parts = resolveStreamingMarkdownParts(value, streamKey);
69
69
  if (parts.plain) {
70
- return measureMarkdownRenderedRows(value, columns, { trimPartialFences: false });
70
+ return estimateWrappedRowsFallback(parts.unstableForRender, columns, 3);
71
71
  }
72
72
  let rows = 0;
73
73
  let childCount = 0;
@@ -5,6 +5,7 @@
5
5
  import { marked } from 'marked';
6
6
  import { configureMarked, hasMarkdownSyntax } from './render-ansi.mjs';
7
7
  import { trimPartialClosingFences, findOpenFenceStart } from './stream-fence.mjs';
8
+ import { displayWidth } from '../display-width.mjs';
8
9
 
9
10
  const stablePrefixByStreamKey = new Map();
10
11
  // Reuse the current normalized-text split across measure → render → harvest.
@@ -16,6 +17,25 @@ export function streamingLayoutText(text) {
16
17
  return String(text ?? '').replace(/^\n+|\n+$/g, '');
17
18
  }
18
19
 
20
+ export function windowPlainStreamingText(text, columns, maxRows) {
21
+ const value = streamingLayoutText(text);
22
+ const rowBudget = Math.max(0, Math.floor(Number(maxRows) || 0));
23
+ if (!value || rowBudget <= 0 || hasMarkdownSyntax(value)) return value;
24
+ const lines = value.split('\n');
25
+ const width = Math.max(1, Math.floor(Number(columns) || 80));
26
+ let rows = 0;
27
+ let start = lines.length;
28
+ while (start > 0) {
29
+ const line = lines[start - 1];
30
+ const lineRows = Math.max(1, Math.ceil(displayWidth(line) / width));
31
+ if (rows > 0 && rows + lineRows > rowBudget) break;
32
+ rows += lineRows;
33
+ start -= 1;
34
+ if (rows >= rowBudget) break;
35
+ }
36
+ return start > 0 ? lines.slice(start).join('\n') : value;
37
+ }
38
+
19
39
  function isWhitespaceOnlyText(text) {
20
40
  return !String(text ?? '').trim();
21
41
  }
@@ -189,7 +189,7 @@ function displayContextBoundary({
189
189
  return modelContextWindow('', '', boundarySeed);
190
190
  }
191
191
 
192
- function resolveContextUsedPct({
192
+ export function resolveContextUsedPct({
193
193
  provider = '',
194
194
  model = '',
195
195
  stats = null,
@@ -210,10 +210,10 @@ function resolveContextUsedPct({
210
210
  autoCompactTokenLimit,
211
211
  compact,
212
212
  });
213
- // Boundary-only denominator: context % is always measured against the single
214
- // compaction boundary value (shared with the gateway), never against a
215
- // separate auto-compact trigger. This keeps the statusline and gateway
216
- // display on the same denominator with no before/after trigger semantics.
213
+ const trigger = num(autoCompactTokenLimit);
214
+ // A resolved trigger means this is the runtime compaction gauge: keep both
215
+ // operands local so a gateway boundary percentage cannot replace it.
216
+ if (trigger > 0) return (numerator / trigger) * 100;
217
217
  const gatewayRawPct = gatewayStatus?.contextUsedPct;
218
218
  if (
219
219
  gatewayStatus
@@ -140,22 +140,30 @@ export function readLatestGatewayHostRoute(clientHostPid, options = {}) {
140
140
  return best;
141
141
  }
142
142
 
143
- export function writeGatewaySessionRoute(sessionId, route, options = {}) {
144
- const sid = normalizeGatewaySessionId(sessionId);
145
- const normalized = normalizeGatewayRouteSection(route || {});
146
- if (!sid || !normalized) return false;
147
- const pid = normalizeClientHostPid(options?.clientHostPid ?? route?.clientHostPid);
143
+ export function writeGatewaySessionRoutes(entries = []) {
144
+ const normalizedEntries = [];
145
+ for (const entry of Array.isArray(entries) ? entries : []) {
146
+ const sid = normalizeGatewaySessionId(entry?.sessionId);
147
+ const route = normalizeGatewayRouteSection(entry?.route || {});
148
+ if (!sid || !route) continue;
149
+ const pid = normalizeClientHostPid(entry?.options?.clientHostPid ?? entry?.route?.clientHostPid);
150
+ normalizedEntries.push({ sid, route, pid });
151
+ }
152
+ if (normalizedEntries.length === 0) return false;
148
153
  try {
149
154
  updateJsonAtomicSync(gatewaySessionRoutesPath(), (curRaw) => {
150
155
  const cur = curRaw && typeof curRaw === 'object' ? curRaw : {};
151
156
  const sessions = cur.sessions && typeof cur.sessions === 'object' ? { ...cur.sessions } : {};
152
157
  const sessionHosts = cur.sessionHosts && typeof cur.sessionHosts === 'object' ? { ...cur.sessionHosts } : {};
153
- if (pid) {
154
- sessionHosts[hostRouteKey(sid, pid)] = { ...normalized, sessionId: sid, clientHostPid: pid, updatedAt: Date.now() };
155
- } else {
156
- sessions[sid] = { ...normalized, sessionId: sid, updatedAt: Date.now() };
158
+ const updatedAt = Date.now();
159
+ for (const { sid, route, pid } of normalizedEntries) {
160
+ if (pid) {
161
+ sessionHosts[hostRouteKey(sid, pid)] = { ...route, sessionId: sid, clientHostPid: pid, updatedAt };
162
+ } else {
163
+ sessions[sid] = { ...route, sessionId: sid, updatedAt };
164
+ }
157
165
  }
158
- return { version: 2, updatedAt: Date.now(), sessions, sessionHosts };
166
+ return { version: 2, updatedAt, sessions, sessionHosts };
159
167
  }, { compact: true, fsync: false, fsyncDir: false });
160
168
  return true;
161
169
  } catch {
@@ -163,6 +171,10 @@ export function writeGatewaySessionRoute(sessionId, route, options = {}) {
163
171
  }
164
172
  }
165
173
 
174
+ export function writeGatewaySessionRoute(sessionId, route, options = {}) {
175
+ return writeGatewaySessionRoutes([{ sessionId, route, options }]);
176
+ }
177
+
166
178
  export function clearGatewaySessionRoute(sessionId, options = {}) {
167
179
  const sid = normalizeGatewaySessionId(sessionId);
168
180
  if (!sid) return false;