mixdog 0.9.24 → 0.9.26
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.
- package/package.json +2 -1
- package/scripts/build-runtime-windows.ps1 +242 -242
- package/scripts/explore-bench-tmp.mjs +1 -1
- package/scripts/recall-usecase-cases.json +1 -1
- package/scripts/smoke-runtime-negative.ps1 +106 -106
- package/scripts/steering-fold-provenance-test.mjs +71 -0
- package/scripts/tool-efficiency-diag.mjs +1 -1
- package/scripts/webhook-smoke.mjs +46 -53
- package/src/defaults/cycle3-review-prompt.md +11 -4
- package/src/defaults/memory-promote-prompt.md +9 -0
- package/src/defaults/skills/setup/SKILL.md +6 -1
- package/src/rules/lead/02-channels.md +3 -3
- package/src/rules/shared/01-tool.md +8 -4
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +17 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +2 -2
- package/src/runtime/agent/orchestrator/mcp/client.mjs +28 -10
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +51 -15
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +164 -9
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +45 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +7 -3
- package/src/runtime/channels/backends/discord.mjs +10 -3
- package/src/runtime/channels/lib/config.mjs +13 -11
- package/src/runtime/channels/lib/inbound-handler.mjs +45 -1
- package/src/runtime/channels/lib/memory-client.mjs +22 -2
- package/src/runtime/channels/lib/owned-runtime.mjs +1 -1
- package/src/runtime/channels/lib/scheduler.mjs +226 -208
- package/src/runtime/channels/lib/status-snapshot.mjs +16 -0
- package/src/runtime/channels/lib/webhook/deliveries.mjs +7 -318
- package/src/runtime/channels/lib/webhook.mjs +98 -150
- package/src/runtime/channels/lib/worker-main.mjs +1 -1
- package/src/runtime/memory/index.mjs +50 -25
- package/src/runtime/memory/lib/cycle-scheduler.mjs +20 -2
- package/src/runtime/memory/lib/memory-config-flags.mjs +13 -1
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +59 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +10 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +79 -9
- package/src/runtime/memory/lib/pg/adapter.mjs +6 -1
- package/src/runtime/memory/lib/pg/process.mjs +19 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +125 -14
- package/src/runtime/memory/lib/query-handlers.mjs +102 -0
- package/src/runtime/memory/lib/recall-format.mjs +60 -22
- package/src/runtime/memory/lib/session-ingest-runtime.mjs +20 -6
- package/src/runtime/memory/tool-defs.mjs +1 -1
- package/src/runtime/shared/child-guardian.mjs +2 -2
- package/src/runtime/shared/open-url.mjs +2 -1
- package/src/runtime/shared/schedules-db.mjs +350 -0
- package/src/runtime/shared/service-discovery.mjs +169 -0
- package/src/runtime/shared/spawn-flags.mjs +27 -0
- package/src/runtime/shared/tool-primitives.mjs +3 -1
- package/src/runtime/shared/tool-surface.mjs +19 -3
- package/src/runtime/shared/update-checker.mjs +54 -10
- package/src/runtime/shared/webhooks-db.mjs +405 -0
- package/src/session-runtime/channel-config-api.mjs +13 -13
- package/src/session-runtime/lifecycle-api.mjs +14 -0
- package/src/session-runtime/runtime-core.mjs +39 -20
- package/src/standalone/agent-tool.mjs +42 -11
- package/src/standalone/channel-admin.mjs +173 -121
- package/src/standalone/channel-worker.mjs +2 -2
- package/src/standalone/memory-runtime-proxy.mjs +10 -5
- package/src/tui/App.jsx +32 -10
- package/src/tui/app/channel-pickers.mjs +9 -9
- package/src/tui/app/clipboard.mjs +14 -0
- package/src/tui/app/doctor.mjs +1 -1
- package/src/tui/app/maintenance-pickers.mjs +17 -7
- package/src/tui/app/settings-picker.mjs +2 -2
- package/src/tui/app/transcript-window.mjs +37 -1
- package/src/tui/app/use-mouse-input.mjs +19 -6
- package/src/tui/components/ToolExecution.jsx +12 -4
- package/src/tui/display-width.mjs +10 -4
- package/src/tui/dist/index.mjs +166 -58
- package/src/tui/engine/agent-job-feed.mjs +42 -3
- package/src/tui/engine/session-api-ext.mjs +12 -12
- package/src/tui/index.jsx +12 -2
- package/src/ui/statusline-segments.mjs +12 -1
- package/src/workflows/default/WORKFLOW.md +29 -38
- package/src/workflows/solo/WORKFLOW.md +15 -20
- package/vendor/ink/build/display-width.js +5 -4
- package/src/runtime/shared/schedules-store.mjs +0 -82
|
@@ -31,6 +31,10 @@ export function createMaintenancePickers({
|
|
|
31
31
|
const upd = readSettings();
|
|
32
32
|
const status = readStatus();
|
|
33
33
|
const current = upd.currentVersion || 'unknown';
|
|
34
|
+
// After a successful in-place install the running process is still the
|
|
35
|
+
// old version; surface the pending version so "Current" doesn't look
|
|
36
|
+
// stale/broken until restart.
|
|
37
|
+
const installedVersion = status.phase === 'installed' ? (status.version || upd.latestVersion || null) : null;
|
|
34
38
|
const latestMeta = checking || status.phase === 'checking'
|
|
35
39
|
? 'checking…'
|
|
36
40
|
: (upd.latestVersion || 'unknown');
|
|
@@ -38,8 +42,10 @@ export function createMaintenancePickers({
|
|
|
38
42
|
{
|
|
39
43
|
value: 'current',
|
|
40
44
|
label: 'Current version',
|
|
41
|
-
meta: current,
|
|
42
|
-
description:
|
|
45
|
+
meta: installedVersion ? `${current} → ${installedVersion}` : current,
|
|
46
|
+
description: installedVersion
|
|
47
|
+
? `v${installedVersion} installed — restart mixdog to apply.`
|
|
48
|
+
: 'Installed mixdog version.',
|
|
43
49
|
_action: 'current',
|
|
44
50
|
},
|
|
45
51
|
{
|
|
@@ -73,13 +79,17 @@ export function createMaintenancePickers({
|
|
|
73
79
|
buttons: [
|
|
74
80
|
{
|
|
75
81
|
value: 'update-now',
|
|
76
|
-
label:
|
|
77
|
-
? `
|
|
78
|
-
:
|
|
82
|
+
label: installedVersion
|
|
83
|
+
? `v${installedVersion} installed — restart to apply`
|
|
84
|
+
: (status.phase === 'installing'
|
|
85
|
+
? 'Installing…'
|
|
86
|
+
: (upd.updateAvailable
|
|
87
|
+
? `Update to v${upd.latestVersion || 'latest'}`
|
|
88
|
+
: 'Update now')),
|
|
79
89
|
},
|
|
80
90
|
],
|
|
81
91
|
onConfirm: (button) => {
|
|
82
|
-
if (button?.value === 'update-now') runUpdate();
|
|
92
|
+
if (button?.value === 'update-now' && !installedVersion && status.phase !== 'installing') runUpdate();
|
|
83
93
|
},
|
|
84
94
|
},
|
|
85
95
|
onSelect: (_value, item) => {
|
|
@@ -118,7 +128,7 @@ export function createMaintenancePickers({
|
|
|
118
128
|
void Promise.resolve(store.runUpdateNow?.())
|
|
119
129
|
.then((result) => {
|
|
120
130
|
if (result?.ok) {
|
|
121
|
-
store.pushNotice(`v${result.version} installed — restart to apply`, '
|
|
131
|
+
store.pushNotice(`v${result.version} installed — restart to apply`, 'warn');
|
|
122
132
|
} else {
|
|
123
133
|
store.pushNotice(`Update failed: ${result?.error || 'unknown error'}`, 'error');
|
|
124
134
|
}
|
|
@@ -43,7 +43,7 @@ export function createSettingsPicker({
|
|
|
43
43
|
openUpdatePicker,
|
|
44
44
|
openChannelSettingTypePicker,
|
|
45
45
|
}) {
|
|
46
|
-
const openSettingsPicker = (opts = {}) => {
|
|
46
|
+
const openSettingsPicker = async (opts = {}) => {
|
|
47
47
|
const light = opts.light === true;
|
|
48
48
|
const overrides = opts.overrides || null;
|
|
49
49
|
const heavyCache = light ? settingsHeavyCacheRef.current : null;
|
|
@@ -63,7 +63,7 @@ export function createSettingsPicker({
|
|
|
63
63
|
channelBackend = heavyCache.channelBackend || 'discord';
|
|
64
64
|
} else {
|
|
65
65
|
try {
|
|
66
|
-
channelBackend = store.getChannelSetup?.()?.backend || 'discord';
|
|
66
|
+
channelBackend = (await store.getChannelSetup?.())?.backend || 'discord';
|
|
67
67
|
} catch {
|
|
68
68
|
channelBackend = 'discord';
|
|
69
69
|
}
|
|
@@ -272,6 +272,33 @@ function toolArgPathForRows(item) {
|
|
|
272
272
|
return a?.path ?? a?.file_path ?? a?.file ?? '';
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
+
// Mirror ToolExecution's collapsed agent-card rule: an agent surface collapses
|
|
276
|
+
// to a SINGLE header row unless the detail row carries failure info (the call
|
|
277
|
+
// errored, or the brief/status reads as a failure/cancel). Pending agent cards
|
|
278
|
+
// never carry failure info yet, so they collapse to one row. A header-failure-
|
|
279
|
+
// only card is handled earlier by toolHeaderFailureOnlyForRows (also one row).
|
|
280
|
+
function agentCardKeepsCollapsedDetailForRows(item, normalizedName) {
|
|
281
|
+
if (normalizedName !== 'agent') return false;
|
|
282
|
+
if (toolItemPendingForRows(item)) return false;
|
|
283
|
+
const bgArgs = backgroundArgsForRows(item.args);
|
|
284
|
+
const isError = Boolean(item.isError);
|
|
285
|
+
const hasDisplayResult = toolHasDisplayResultForRows(item);
|
|
286
|
+
const displayedResultText = toolDisplayedResultTextForRows(item);
|
|
287
|
+
const rt = item.result == null ? '' : String(item.result).replace(/\s+$/, '');
|
|
288
|
+
const isAgentResponse = hasDisplayResult && isAgentResponseResultText(rt);
|
|
289
|
+
const briefRaw = summarizeAgentSurfaceBrief(item.name, bgArgs, displayedResultText, {
|
|
290
|
+
isError,
|
|
291
|
+
isResponse: isAgentResponse,
|
|
292
|
+
});
|
|
293
|
+
const brief = String(briefRaw || '').trim();
|
|
294
|
+
const status = String(bgArgs.status || '').toLowerCase();
|
|
295
|
+
const failureText = /\b(cancelled|canceled|failed)\b/i.test(brief)
|
|
296
|
+
|| /^(failed|error|timeout|cancelled|canceled|killed)$/i.test(status);
|
|
297
|
+
const agentHeaderFailure = isError && String(bgArgs.error || '').trim() && !hasDisplayResult;
|
|
298
|
+
if (agentHeaderFailure && !brief) return false;
|
|
299
|
+
return isError || failureText;
|
|
300
|
+
}
|
|
301
|
+
|
|
275
302
|
function isShellSurfaceForRows(normalizedName, label = '') {
|
|
276
303
|
const n = String(normalizedName || '').toLowerCase();
|
|
277
304
|
const l = String(label || '').toLowerCase();
|
|
@@ -332,6 +359,11 @@ function estimateTranscriptItemRows(item, columns, toolOutputExpanded) {
|
|
|
332
359
|
if (toolHeaderFailureOnlyForRows(item, normalizedName, hasDisplayResult)) {
|
|
333
360
|
return TOOL_MARGIN_TOP + 1;
|
|
334
361
|
}
|
|
362
|
+
if (isAgentSurface) {
|
|
363
|
+
return agentCardKeepsCollapsedDetailForRows(item, normalizedName)
|
|
364
|
+
? TOOL_MARGIN_TOP + 1 + 1
|
|
365
|
+
: TOOL_MARGIN_TOP + 1;
|
|
366
|
+
}
|
|
335
367
|
return TOOL_MARGIN_TOP + 1 + 1;
|
|
336
368
|
}
|
|
337
369
|
if (hasRawResult) {
|
|
@@ -341,7 +373,11 @@ function estimateTranscriptItemRows(item, columns, toolOutputExpanded) {
|
|
|
341
373
|
: { pathArg: toolArgPathForRows(item), isShell: isShellSurfaceForToolItem(item, normalizedName) };
|
|
342
374
|
return TOOL_MARGIN_TOP + 1 + estimateToolRenderedResultRows(estimateText, { ...rawOpts, columns });
|
|
343
375
|
}
|
|
344
|
-
if (isAgentSurface && !hasResult)
|
|
376
|
+
if (isAgentSurface && !hasResult) {
|
|
377
|
+
return agentCardKeepsCollapsedDetailForRows(item, normalizedName)
|
|
378
|
+
? TOOL_MARGIN_TOP + 1 + 1
|
|
379
|
+
: TOOL_MARGIN_TOP + 1;
|
|
380
|
+
}
|
|
345
381
|
if (isSkillSurface && !hasResult) return TOOL_MARGIN_TOP + 1;
|
|
346
382
|
if (item.aggregate) {
|
|
347
383
|
if (hasRawResult) {
|
|
@@ -18,8 +18,11 @@ const MOUSE_TRACKING_OFF = '\x1b[?1006l\x1b[?1002l\x1b[?1000l';
|
|
|
18
18
|
// conversion WINS over WT's native ctrl+wheel font zoom. During the zoom
|
|
19
19
|
// passthrough window we must turn BOTH mouse tracking and alternate scroll
|
|
20
20
|
// off, or ctrl+wheel lands as Up/Down (prompt history) instead of zooming.
|
|
21
|
+
// 1007 is kept OFF for the entire session (index.jsx boots with ?1007l and
|
|
22
|
+
// the restore below re-asserts it): if mouse tracking ever drops while 1007
|
|
23
|
+
// is on, every wheel notch turns into prompt-history Up/Down. Off means a
|
|
24
|
+
// degraded wheel is a no-op, never history navigation.
|
|
21
25
|
const ALT_SCROLL_OFF = '\x1b[?1007l';
|
|
22
|
-
const ALT_SCROLL_ON = '\x1b[?1007h';
|
|
23
26
|
const MOUSE_MODIFIER_MASK = 4 | 8 | 16;
|
|
24
27
|
const MOUSE_CTRL_MASK = 16;
|
|
25
28
|
// Bit 2 (4) of the SGR button byte = shift held during the click. Wheel/ctrl
|
|
@@ -76,15 +79,25 @@ export function useMouseInput({
|
|
|
76
79
|
} catch {
|
|
77
80
|
return;
|
|
78
81
|
}
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
// Re-enable with RETRIES: a single swallowed write failure (EAGAIN
|
|
83
|
+
// backpressure is real on Windows console streams) used to leave mouse
|
|
84
|
+
// tracking off for the rest of the session — wheel scroll dead, and with
|
|
85
|
+
// alternate scroll enabled the wheel then typed into prompt history.
|
|
86
|
+
const restore = (attempt) => {
|
|
81
87
|
zoomTimerRef.current = null;
|
|
82
88
|
try {
|
|
83
|
-
stdout.write(
|
|
89
|
+
stdout.write(MOUSE_TRACKING_ON + ALT_SCROLL_OFF);
|
|
84
90
|
} catch {
|
|
85
|
-
// The terminal may
|
|
91
|
+
// The terminal may be closing — but it may also be transient
|
|
92
|
+
// backpressure; retry a few times before giving up.
|
|
93
|
+
if (attempt < 5) {
|
|
94
|
+
zoomTimerRef.current = setTimeout(() => restore(attempt + 1), 200);
|
|
95
|
+
zoomTimerRef.current.unref?.();
|
|
96
|
+
}
|
|
86
97
|
}
|
|
87
|
-
}
|
|
98
|
+
};
|
|
99
|
+
if (zoomTimerRef.current) clearTimeout(zoomTimerRef.current);
|
|
100
|
+
zoomTimerRef.current = setTimeout(() => restore(0), 700);
|
|
88
101
|
zoomTimerRef.current.unref?.();
|
|
89
102
|
}, [stdout, zoomTimerRef]);
|
|
90
103
|
|
|
@@ -198,9 +198,10 @@ export function ToolExecution({ name, args, result, rawResult, isError, errorCou
|
|
|
198
198
|
// Mirror estimateTranscriptItemRows: a non-aggregate skill surface collapses
|
|
199
199
|
// to a single header row; everything else reserves header + one detail row.
|
|
200
200
|
const placeholderNormalizedName = String(formatToolSurface(name, args)?.normalizedName || '').toLowerCase();
|
|
201
|
-
// Skill surfaces collapse to a single header row
|
|
202
|
-
//
|
|
203
|
-
const placeholderSingleRow = !aggregate
|
|
201
|
+
// Skill AND agent surfaces collapse to a single header row when collapsed
|
|
202
|
+
// (see estimateTranscriptItemRows); reserve one row for both.
|
|
203
|
+
const placeholderSingleRow = !aggregate
|
|
204
|
+
&& (SKILL_SURFACE_NAMES.has(placeholderNormalizedName) || isAgentTool(placeholderNormalizedName));
|
|
204
205
|
return (
|
|
205
206
|
<Box flexDirection="column" marginTop={attached ? 0 : 1} width={rowWidth} overflow="hidden">
|
|
206
207
|
<Text> </Text>
|
|
@@ -443,11 +444,18 @@ export function ToolExecution({ name, args, result, rawResult, isError, errorCou
|
|
|
443
444
|
} else if (isBackgroundMetadataResult && backgroundMetadataHeaderFailure && !showRawResult) {
|
|
444
445
|
visibleDetailLines = [];
|
|
445
446
|
} else if (isAgentSurfaceCard && !showRawResult) {
|
|
447
|
+
// Agent cards collapse to a SINGLE header row like skill surfaces. Keep the
|
|
448
|
+
// ⎿ detail row ONLY when it carries failure info: the call errored, or the
|
|
449
|
+
// brief/summary reads as a failure/cancel. A header-failure-only card (no
|
|
450
|
+
// brief) shows the cause in the header, so it stays a single row too.
|
|
451
|
+
// Expanded (ctrl+o raw) still flows through the showRawResult path above.
|
|
446
452
|
const agentDetailFallback = collapsedDetail
|
|
447
453
|
|| (pending ? (pendingDetailPlaceholder || 'Running') : 'Finished');
|
|
448
454
|
const agentDetailLine = agentSurfaceBrief
|
|
449
455
|
|| truncateToWidth(String(agentDetailFallback), Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars));
|
|
450
|
-
|
|
456
|
+
const agentFailureText = /\b(Cancelled|Canceled|Failed)\b/i.test(agentSurfaceBrief || collapsedDetail || '');
|
|
457
|
+
const keepAgentDetail = (isError || agentFailureText) && !(agentHeaderFailure && !agentSurfaceBrief);
|
|
458
|
+
visibleDetailLines = keepAgentDetail ? [agentDetailLine] : [];
|
|
451
459
|
}
|
|
452
460
|
const finalStatusColor = toolStatusColor({ pending, groupCount, failedCount, terminalStatus });
|
|
453
461
|
const dotColor = finalStatusColor;
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
* - Widen ONLY the two problem ranges below. NEVER widen box-drawing
|
|
13
13
|
* (U+2500–U+257F └ │ ⎿ ─), block elements, or the figures.mjs glyphs —
|
|
14
14
|
* those are also EAW-ambiguous but must stay 1 cell.
|
|
15
|
-
* - Enabled by default
|
|
15
|
+
* - Enabled by default on Windows (process.platform === 'win32') or under
|
|
16
|
+
* Windows Terminal (WT_SESSION set — covers WT reached via e.g. SSH from
|
|
17
|
+
* a non-Windows host).
|
|
16
18
|
* - MIXDOG_TUI_AMBIGUOUS_WIDE overrides the default: '1' forces on, '0'
|
|
17
19
|
* forces off; the override always wins.
|
|
18
20
|
* - When OFF, behaviour is byte-for-byte identical to plain string-width.
|
|
@@ -43,12 +45,16 @@ export function isProblemCodePoint(cp) {
|
|
|
43
45
|
// vendor/ink/build/display-width.js.
|
|
44
46
|
const PROBLEM_RE = /[\u2190-\u21ff\u2460-\u24ff]/;
|
|
45
47
|
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the wide policy from env. Override wins over the default; the
|
|
50
|
+
* default is ON on Windows (WT_SESSION does not reliably propagate to child
|
|
51
|
+
* processes, so gate on the OS itself) or when WT_SESSION is present.
|
|
52
|
+
*/
|
|
53
|
+
export function resolveAmbiguousWidePolicy(env = process.env, platform = process.platform) {
|
|
48
54
|
const override = env?.MIXDOG_TUI_AMBIGUOUS_WIDE;
|
|
49
55
|
if (override === '1') return true;
|
|
50
56
|
if (override === '0') return false;
|
|
51
|
-
return Boolean(env?.WT_SESSION);
|
|
57
|
+
return platform === 'win32' || Boolean(env?.WT_SESSION);
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
/** Resolved once at module load (matches the "computed once" requirement). */
|