mixdog 0.9.38 → 0.9.40
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 +9 -4
- package/scripts/abort-recovery-test.mjs +43 -2
- package/scripts/agent-tag-reuse-smoke.mjs +146 -6
- package/scripts/agent-terminal-reap-test.mjs +127 -0
- package/scripts/agent-trace-io-test.mjs +69 -0
- package/scripts/code-graph-disk-hit-test.mjs +224 -0
- package/scripts/execution-completion-dedup-test.mjs +157 -0
- package/scripts/execution-pending-resume-kick-test.mjs +57 -2
- package/scripts/execution-resume-esc-integration-test.mjs +176 -0
- package/scripts/explore-bench.mjs +38 -2
- package/scripts/explore-prompt-policy-test.mjs +152 -11
- package/scripts/find-fuzzy-hidden-test.mjs +122 -0
- package/scripts/internal-comms-bench-test.mjs +226 -0
- package/scripts/internal-comms-bench.mjs +185 -58
- package/scripts/internal-comms-smoke.mjs +171 -23
- package/scripts/live-worker-smoke.mjs +38 -2
- package/scripts/memory-cycle-routing-test.mjs +111 -0
- package/scripts/memory-rule-contract-test.mjs +93 -0
- package/scripts/output-style-smoke.mjs +2 -2
- package/scripts/rg-runner-test.mjs +240 -0
- package/scripts/routing-corpus-test.mjs +349 -0
- package/scripts/routing-corpus.mjs +211 -32
- package/scripts/session-orphan-sweep-test.mjs +83 -0
- package/scripts/steering-drain-buckets-test.mjs +316 -2
- package/scripts/tool-smoke.mjs +21 -13
- package/scripts/tool-tui-presentation-test.mjs +202 -0
- package/scripts/tui-transcript-perf-test.mjs +279 -0
- package/src/agents/heavy-worker/AGENT.md +10 -7
- package/src/agents/reviewer/AGENT.md +6 -4
- package/src/agents/worker/AGENT.md +7 -5
- package/src/rules/agent/00-common.md +4 -4
- package/src/rules/agent/00-core.md +11 -14
- package/src/rules/agent/20-skip-protocol.md +3 -3
- package/src/rules/agent/30-explorer.md +50 -60
- package/src/rules/agent/40-cycle1-agent.md +15 -24
- package/src/rules/agent/41-cycle2-agent.md +33 -57
- package/src/rules/agent/42-cycle3-agent.md +28 -42
- package/src/rules/lead/01-general.md +7 -10
- package/src/rules/lead/lead-brief.md +11 -14
- package/src/rules/lead/lead-tool.md +6 -5
- package/src/rules/shared/01-tool.md +44 -45
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +44 -1
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +20 -5
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +21 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +17 -38
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +17 -8
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +270 -78
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/delivered-completions.mjs +123 -0
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +15 -2
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +67 -2
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +232 -43
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +43 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +27 -13
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +25 -20
- package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +118 -53
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +106 -29
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +151 -64
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +37 -13
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +84 -49
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +172 -23
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +3 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +68 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +17 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +24 -10
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +4 -7
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +1 -0
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +4 -4
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +4 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +12 -2
- package/src/runtime/shared/buffered-appender.mjs +13 -2
- package/src/runtime/shared/tool-primitives.mjs +4 -1
- package/src/runtime/shared/tool-status.mjs +27 -0
- package/src/runtime/shared/tool-surface.mjs +6 -3
- package/src/session-runtime/config-helpers.mjs +14 -0
- package/src/session-runtime/context-status.mjs +1 -0
- package/src/session-runtime/effort.mjs +6 -2
- package/src/session-runtime/lifecycle-api.mjs +4 -0
- package/src/session-runtime/model-recency.mjs +5 -2
- package/src/session-runtime/runtime-core.mjs +36 -2
- package/src/session-runtime/session-turn-api.mjs +12 -0
- package/src/session-runtime/tool-catalog.mjs +34 -0
- package/src/standalone/agent-tool/notify.mjs +13 -0
- package/src/standalone/agent-tool.mjs +53 -70
- package/src/standalone/explore-tool.mjs +6 -7
- package/src/tui/App.jsx +33 -1
- package/src/tui/app/model-options.mjs +5 -3
- package/src/tui/app/model-picker.mjs +12 -24
- package/src/tui/app/transcript-window.mjs +10 -10
- package/src/tui/app/use-transcript-window.mjs +38 -56
- package/src/tui/components/ToolExecution.jsx +11 -6
- package/src/tui/components/TranscriptItem.jsx +1 -1
- package/src/tui/components/tool-execution/surface-detail.mjs +24 -10
- package/src/tui/components/tool-execution/text-format.mjs +10 -19
- package/src/tui/dist/index.mjs +866 -300
- package/src/tui/engine/agent-job-feed.mjs +216 -19
- package/src/tui/engine/agent-response-tail.mjs +68 -0
- package/src/tui/engine/notification-plan.mjs +16 -0
- package/src/tui/engine/session-api.mjs +14 -2
- package/src/tui/engine/session-flow.mjs +22 -2
- package/src/tui/engine/tool-card-results.mjs +64 -37
- package/src/tui/engine/tool-result-status.mjs +75 -21
- package/src/tui/engine/turn.mjs +172 -77
- package/src/tui/engine.mjs +199 -39
- package/src/tui/index.jsx +2 -2
- package/src/workflows/bench/WORKFLOW.md +25 -35
- package/src/workflows/default/WORKFLOW.md +38 -32
- package/src/workflows/solo/WORKFLOW.md +19 -22
- package/scripts/_jitter-fuzz.mjs +0 -44410
- package/scripts/_jitter-fuzz2.mjs +0 -44400
- package/scripts/_jitter-probe.mjs +0 -44397
- package/scripts/_jp2.mjs +0 -45614
package/src/tui/engine.mjs
CHANGED
|
@@ -81,6 +81,7 @@ import {
|
|
|
81
81
|
import { createToolApproval } from './engine/tool-approval.mjs';
|
|
82
82
|
import { createToolCardResults } from './engine/tool-card-results.mjs';
|
|
83
83
|
import { createAgentJobFeed } from './engine/agent-job-feed.mjs';
|
|
84
|
+
import { appendAgentResponseTail } from './engine/agent-response-tail.mjs';
|
|
84
85
|
import {
|
|
85
86
|
appendTuiSteeringPersist,
|
|
86
87
|
dropTuiSteeringPersist,
|
|
@@ -141,6 +142,87 @@ export { parseBackgroundTaskEnvelope };
|
|
|
141
142
|
// so importers/tests keep resolving resolveTuiRuntimeNotificationDelivery from engine.mjs.
|
|
142
143
|
export { resolveTuiRuntimeNotificationDelivery };
|
|
143
144
|
|
|
145
|
+
export function replaceEngineItemsState({
|
|
146
|
+
state,
|
|
147
|
+
items,
|
|
148
|
+
itemIndexById,
|
|
149
|
+
preserveStreamingTail = false,
|
|
150
|
+
extra = {},
|
|
151
|
+
}) {
|
|
152
|
+
const nextItems = Array.isArray(items) ? items : [];
|
|
153
|
+
itemIndexById.clear();
|
|
154
|
+
for (let i = 0; i < nextItems.length; i++) {
|
|
155
|
+
const id = nextItems[i]?.id;
|
|
156
|
+
if (id != null) itemIndexById.set(id, i);
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
...state,
|
|
160
|
+
...extra,
|
|
161
|
+
items: nextItems,
|
|
162
|
+
structureRevision: (Number(state.structureRevision) || 0) + 1,
|
|
163
|
+
streamingTail: preserveStreamingTail ? state.streamingTail : null,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Shared by the live engine and focused transcript tests so revision/tail
|
|
168
|
+
// regressions exercise the exact mutation implementation used in production.
|
|
169
|
+
export function createEngineItemMutators({ getState, set, itemIndexById }) {
|
|
170
|
+
const patchItem = (id, patch) => {
|
|
171
|
+
const state = getState();
|
|
172
|
+
let index = itemIndexById.get(id);
|
|
173
|
+
if (!Number.isInteger(index) || state.items[index]?.id !== id) {
|
|
174
|
+
index = state.items.findIndex((it) => it.id === id);
|
|
175
|
+
if (index >= 0) itemIndexById.set(id, index);
|
|
176
|
+
}
|
|
177
|
+
if (index < 0) return false;
|
|
178
|
+
const current = state.items[index];
|
|
179
|
+
let changed = false;
|
|
180
|
+
for (const [key, value] of Object.entries(patch || {})) {
|
|
181
|
+
if (!Object.is(current[key], value)) {
|
|
182
|
+
changed = true;
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (!changed) return false;
|
|
187
|
+
const items = state.items.slice();
|
|
188
|
+
items[index] = { ...current, ...patch };
|
|
189
|
+
set({ items, structureRevision: (Number(state.structureRevision) || 0) + 1 });
|
|
190
|
+
return true;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const settleStreamingTail = (id, patch = {}, extra = {}) => {
|
|
194
|
+
const state = getState();
|
|
195
|
+
const tail = state.streamingTail?.id === id ? state.streamingTail : null;
|
|
196
|
+
// Bulk transcript replacement/reset owns the new transcript. A stale turn
|
|
197
|
+
// must never append into it after replaceItems deliberately cleared its tail.
|
|
198
|
+
if (!tail) return false;
|
|
199
|
+
let existingIndex = itemIndexById.get(id);
|
|
200
|
+
if (!Number.isInteger(existingIndex) || state.items[existingIndex]?.id !== id) {
|
|
201
|
+
existingIndex = state.items.findIndex((item) => item?.id === id);
|
|
202
|
+
}
|
|
203
|
+
if (existingIndex >= 0) return false;
|
|
204
|
+
const item = {
|
|
205
|
+
...(tail || {}),
|
|
206
|
+
...patch,
|
|
207
|
+
kind: 'assistant',
|
|
208
|
+
id,
|
|
209
|
+
streaming: false,
|
|
210
|
+
};
|
|
211
|
+
const index = state.items.length;
|
|
212
|
+
const items = [...state.items, item];
|
|
213
|
+
itemIndexById.set(id, index);
|
|
214
|
+
set({
|
|
215
|
+
items,
|
|
216
|
+
structureRevision: (Number(state.structureRevision) || 0) + 1,
|
|
217
|
+
streamingTail: null,
|
|
218
|
+
...extra,
|
|
219
|
+
});
|
|
220
|
+
return true;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return { patchItem, settleStreamingTail };
|
|
224
|
+
}
|
|
225
|
+
|
|
144
226
|
export async function createEngineSession({
|
|
145
227
|
provider: providerName,
|
|
146
228
|
model,
|
|
@@ -204,6 +286,8 @@ export async function createEngineSession({
|
|
|
204
286
|
};
|
|
205
287
|
let state = {
|
|
206
288
|
items: [],
|
|
289
|
+
structureRevision: 0,
|
|
290
|
+
streamingTail: null,
|
|
207
291
|
toasts: [],
|
|
208
292
|
progressHint: null,
|
|
209
293
|
busy: false,
|
|
@@ -282,13 +366,8 @@ export async function createEngineSession({
|
|
|
282
366
|
};
|
|
283
367
|
|
|
284
368
|
const itemIndexById = new Map();
|
|
285
|
-
const replaceItems = (items) => {
|
|
369
|
+
const replaceItems = (items, { preserveStreamingTail = false } = {}) => {
|
|
286
370
|
const nextItems = Array.isArray(items) ? items : [];
|
|
287
|
-
itemIndexById.clear();
|
|
288
|
-
for (let i = 0; i < nextItems.length; i++) {
|
|
289
|
-
const id = nextItems[i]?.id;
|
|
290
|
-
if (id != null) itemIndexById.set(id, i);
|
|
291
|
-
}
|
|
292
371
|
// Bulk item swap (session load / clear / compact). Derive the prompt-history
|
|
293
372
|
// list from the NEW items and stage it onto state here so App never rescans;
|
|
294
373
|
// the callers that invoke replaceItems always follow with a set({items:...,
|
|
@@ -296,12 +375,21 @@ export async function createEngineSession({
|
|
|
296
375
|
// emit (the accompanying set() diffs the full patch). A bulk swap also
|
|
297
376
|
// discards the old transcript, so drop any tracked active tool calls.
|
|
298
377
|
activeToolCalls.clear();
|
|
299
|
-
state = {
|
|
300
|
-
|
|
378
|
+
state = replaceEngineItemsState({
|
|
379
|
+
state,
|
|
301
380
|
items: nextItems,
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
381
|
+
itemIndexById,
|
|
382
|
+
preserveStreamingTail,
|
|
383
|
+
extra: {
|
|
384
|
+
promptHistoryList: buildMergedPromptHistory(recomputePromptHistory(nextItems), loadPromptHistory(state.cwd)),
|
|
385
|
+
activeToolSummary: null,
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
// replaceItems stages the bulk state before its callers compose their
|
|
389
|
+
// accompanying patch. Emit here as well so an items-only replacement
|
|
390
|
+
// (for example removeNotice) cannot be hidden by the outer set seeing the
|
|
391
|
+
// already-installed array identity.
|
|
392
|
+
emit();
|
|
305
393
|
return nextItems;
|
|
306
394
|
};
|
|
307
395
|
// --- Prompt-history list (newest-first, deduped) maintained incrementally ---
|
|
@@ -370,11 +458,39 @@ export async function createEngineSession({
|
|
|
370
458
|
// first — set() diffs against the current state, so a pre-assign would make
|
|
371
459
|
// the references identical and skip emit().
|
|
372
460
|
const promptHistoryList = buildMergedPromptHistory(recomputePromptHistory(items), loadPromptHistory(state.cwd));
|
|
373
|
-
set({ items, promptHistoryList });
|
|
461
|
+
set({ items, structureRevision: state.structureRevision + 1, promptHistoryList });
|
|
374
462
|
} else {
|
|
375
|
-
set({ items });
|
|
463
|
+
set({ items, structureRevision: state.structureRevision + 1 });
|
|
376
464
|
}
|
|
377
465
|
};
|
|
466
|
+
const updateStreamingTail = (id, patch = {}, extra = {}) => {
|
|
467
|
+
if (id == null) return false;
|
|
468
|
+
const current = state.streamingTail?.id === id
|
|
469
|
+
? state.streamingTail
|
|
470
|
+
: { kind: 'assistant', id, text: '', streaming: true };
|
|
471
|
+
const next = { ...current, ...patch, kind: 'assistant', id, streaming: true };
|
|
472
|
+
let changed = state.streamingTail !== current;
|
|
473
|
+
if (!changed) {
|
|
474
|
+
for (const [key, value] of Object.entries(next)) {
|
|
475
|
+
if (!Object.is(current[key], value)) {
|
|
476
|
+
changed = true;
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return set(changed ? { streamingTail: next, ...extra } : extra);
|
|
482
|
+
};
|
|
483
|
+
const clearStreamingTail = (id = null, extra = {}) => {
|
|
484
|
+
if (!state.streamingTail || (id != null && state.streamingTail.id !== id)) {
|
|
485
|
+
return set(extra);
|
|
486
|
+
}
|
|
487
|
+
return set({ streamingTail: null, ...extra });
|
|
488
|
+
};
|
|
489
|
+
const { patchItem, settleStreamingTail } = createEngineItemMutators({
|
|
490
|
+
getState: () => state,
|
|
491
|
+
set,
|
|
492
|
+
itemIndexById,
|
|
493
|
+
});
|
|
378
494
|
const upsertSyntheticToolItem = (text, id = nextId(), parsed = null) => {
|
|
379
495
|
const synthetic = parseSyntheticAgentMessage(text);
|
|
380
496
|
if (!synthetic) return false;
|
|
@@ -424,6 +540,64 @@ export async function createEngineSession({
|
|
|
424
540
|
if (origin === 'user') appendPromptHistory(state.cwd, text);
|
|
425
541
|
pushItem({ kind: 'user', id, text });
|
|
426
542
|
};
|
|
543
|
+
const pushAsyncAgentResponse = (text, id = nextId(), origin = 'injected', metadata = {}) => {
|
|
544
|
+
const synthetic = parseSyntheticAgentMessage(text);
|
|
545
|
+
const isAgent = synthetic?.name === 'agent';
|
|
546
|
+
if (!isAgent) return pushUserOrSyntheticItem(text, id, origin);
|
|
547
|
+
const responseHasBody = /\n\s*\n[\s\S]*\S/.test(String(text || ''));
|
|
548
|
+
const rawResult = synthetic.rawResult ?? text;
|
|
549
|
+
const args = {
|
|
550
|
+
...(synthetic.args && typeof synthetic.args === 'object' ? synthetic.args : {}),
|
|
551
|
+
type: 'result',
|
|
552
|
+
};
|
|
553
|
+
const responseKey = String(metadata.responseKey || metadata.executionId || args.task_id || '').trim();
|
|
554
|
+
const previous = state.items.at(-1);
|
|
555
|
+
// Tail-only aggregation prevents a later completion from mutating a card
|
|
556
|
+
// above any outbound tool, assistant, user, or preview/body boundary.
|
|
557
|
+
if (
|
|
558
|
+
previous?.kind === 'tool'
|
|
559
|
+
&& previous.agentDirection === 'inbound'
|
|
560
|
+
) {
|
|
561
|
+
const patch = appendAgentResponseTail(previous, {
|
|
562
|
+
key: responseKey,
|
|
563
|
+
args,
|
|
564
|
+
result: synthetic.result,
|
|
565
|
+
rawResult,
|
|
566
|
+
hasBody: responseHasBody,
|
|
567
|
+
isError: synthetic.isError === true,
|
|
568
|
+
});
|
|
569
|
+
if (patch) {
|
|
570
|
+
patchItem(previous.id, patch);
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
pushItem({
|
|
575
|
+
kind: 'tool',
|
|
576
|
+
id,
|
|
577
|
+
name: 'agent',
|
|
578
|
+
args,
|
|
579
|
+
result: synthetic.result,
|
|
580
|
+
rawResult,
|
|
581
|
+
isError: synthetic.isError === true,
|
|
582
|
+
expanded: false,
|
|
583
|
+
count: 1,
|
|
584
|
+
completedCount: 1,
|
|
585
|
+
startedAt: Date.now(),
|
|
586
|
+
completedAt: Date.now(),
|
|
587
|
+
agentDirection: 'inbound',
|
|
588
|
+
agentResponseKey: responseKey,
|
|
589
|
+
agentResponseHasBody: responseHasBody,
|
|
590
|
+
agentResponseAggregate: false,
|
|
591
|
+
agentResponseEntries: [{
|
|
592
|
+
key: responseKey,
|
|
593
|
+
raw: String(rawResult ?? '').trim(),
|
|
594
|
+
result: synthetic.result,
|
|
595
|
+
hasBody: responseHasBody,
|
|
596
|
+
isError: synthetic.isError === true,
|
|
597
|
+
}],
|
|
598
|
+
});
|
|
599
|
+
return true;
|
|
600
|
+
};
|
|
427
601
|
const pushToast = (text, tone = 'info', ttlMs = 3000) => {
|
|
428
602
|
const id = nextId();
|
|
429
603
|
const value = String(text ?? '').trim();
|
|
@@ -454,7 +628,7 @@ export async function createEngineSession({
|
|
|
454
628
|
if (id == null) return false;
|
|
455
629
|
const items = state.items.filter((it) => !(it?.kind === 'notice' && it?.id === id));
|
|
456
630
|
if (items.length === state.items.length) return false;
|
|
457
|
-
set({ items: replaceItems(items) });
|
|
631
|
+
set({ items: replaceItems(items, { preserveStreamingTail: true }) });
|
|
458
632
|
return true;
|
|
459
633
|
};
|
|
460
634
|
// Sticky (non-TTL) input-hint-line progress state, for long-running
|
|
@@ -479,27 +653,6 @@ export async function createEngineSession({
|
|
|
479
653
|
getDisposed: () => flags.disposed,
|
|
480
654
|
timeoutMs: TOOL_APPROVAL_TIMEOUT_MS,
|
|
481
655
|
});
|
|
482
|
-
const patchItem = (id, patch) => {
|
|
483
|
-
let index = itemIndexById.get(id);
|
|
484
|
-
if (!Number.isInteger(index) || state.items[index]?.id !== id) {
|
|
485
|
-
index = state.items.findIndex((it) => it.id === id);
|
|
486
|
-
if (index >= 0) itemIndexById.set(id, index);
|
|
487
|
-
}
|
|
488
|
-
if (index < 0) return false;
|
|
489
|
-
const current = state.items[index];
|
|
490
|
-
let changed = false;
|
|
491
|
-
for (const [key, value] of Object.entries(patch || {})) {
|
|
492
|
-
if (!Object.is(current[key], value)) {
|
|
493
|
-
changed = true;
|
|
494
|
-
break;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
if (!changed) return false;
|
|
498
|
-
const items = state.items.slice();
|
|
499
|
-
items[index] = { ...current, ...patch };
|
|
500
|
-
set({ items });
|
|
501
|
-
return true;
|
|
502
|
-
};
|
|
503
656
|
const toastTimers = new Set();
|
|
504
657
|
lifecycle.runtimePulseTimer = setInterval(() => {
|
|
505
658
|
if (flags.disposed) return;
|
|
@@ -524,9 +677,11 @@ export async function createEngineSession({
|
|
|
524
677
|
kickExecutionPendingResume,
|
|
525
678
|
flushDeferredExecutionPendingResumeKick,
|
|
526
679
|
scheduleExecutionPendingResumeKick,
|
|
680
|
+
discardExecutionPendingResume,
|
|
527
681
|
updateAgentJobCard,
|
|
528
682
|
buildAgentJobCardPatch,
|
|
529
683
|
subscribeRuntimeNotifications,
|
|
684
|
+
clearExecutionDedupState,
|
|
530
685
|
} = createAgentJobFeed({
|
|
531
686
|
runtime,
|
|
532
687
|
getState: () => state,
|
|
@@ -537,11 +692,13 @@ export async function createEngineSession({
|
|
|
537
692
|
enqueue: (...args) => bag.enqueue(...args),
|
|
538
693
|
drain: (...args) => bag.drain(...args),
|
|
539
694
|
pushUserOrSyntheticItem,
|
|
695
|
+
pushAsyncAgentResponse,
|
|
540
696
|
makeQueueEntry: (...args) => bag.makeQueueEntry(...args),
|
|
541
697
|
getPending: () => pending,
|
|
542
698
|
agentStatusState,
|
|
543
699
|
displayedExecutionNotificationKeys,
|
|
544
700
|
pushNotice,
|
|
701
|
+
itemIndexById,
|
|
545
702
|
});
|
|
546
703
|
lifecycle.unsubscribeRuntimeNotifications = subscribeRuntimeNotifications();
|
|
547
704
|
|
|
@@ -566,20 +723,23 @@ export async function createEngineSession({
|
|
|
566
723
|
updateAgentJobCard,
|
|
567
724
|
buildAgentJobCardPatch,
|
|
568
725
|
agentStatusState,
|
|
726
|
+
itemIndexById,
|
|
569
727
|
});
|
|
570
728
|
|
|
571
729
|
|
|
572
730
|
Object.assign(bag, {
|
|
573
731
|
runtime, nextId, tuiDebug, LEAD_TURN_TIMEOUT_MS,
|
|
574
|
-
flags, lifecycle, pending, pendingNotificationKeys, displayedExecutionNotificationKeys, listeners, itemIndexById,
|
|
732
|
+
flags, lifecycle, pending, pendingNotificationKeys, displayedExecutionNotificationKeys, clearExecutionDedupState, listeners, itemIndexById,
|
|
575
733
|
getState: () => state, set,
|
|
576
|
-
pushItem, patchItem, replaceItems,
|
|
577
|
-
|
|
734
|
+
pushItem, patchItem, replaceItems, updateStreamingTail, settleStreamingTail, clearStreamingTail,
|
|
735
|
+
pushToast, pushNotice, removeNotice, setProgressHint,
|
|
736
|
+
pushUserOrSyntheticItem, pushAsyncAgentResponse, upsertSyntheticToolItem,
|
|
578
737
|
markToolCallActive, markToolCallDone, clearActiveToolSummary, clearToastTimers,
|
|
579
738
|
autoClearState, agentStatusState, baseRouteState, routeState, syncContextStats,
|
|
580
739
|
presentNextToolApproval, finishToolApproval, denyAllToolApprovals, requestToolApproval,
|
|
581
740
|
patchToolCardResult, flushToolResults,
|
|
582
|
-
|
|
741
|
+
clearExecutionDedupState,
|
|
742
|
+
kickExecutionPendingResume, flushDeferredExecutionPendingResumeKick, scheduleExecutionPendingResumeKick, discardExecutionPendingResume, updateAgentJobCard, subscribeRuntimeNotifications,
|
|
583
743
|
});
|
|
584
744
|
Object.assign(bag, createSessionFlow(bag));
|
|
585
745
|
bag.runTurn = createRunTurn(bag);
|
package/src/tui/index.jsx
CHANGED
|
@@ -281,7 +281,7 @@ function paintBootSplash() {
|
|
|
281
281
|
const rows = Math.max(1, Number(process.stdout.rows) || 24);
|
|
282
282
|
const windowsLikeTerminal = process.platform === 'win32' || Boolean(process.env.WT_SESSION);
|
|
283
283
|
const frameCols = Math.max(1, cols - (windowsLikeTerminal ? 1 : 0));
|
|
284
|
-
const center = (s) => `${' '.repeat(Math.max(0, Math.floor((frameCols - displayWidth(s)) / 2)))}${s}`;
|
|
284
|
+
const center = (s, reserve = 0) => `${' '.repeat(Math.max(0, Math.floor((frameCols - reserve - displayWidth(s)) / 2)))}${s}`;
|
|
285
285
|
const logo = [
|
|
286
286
|
'███╗ ███╗██╗██╗ ██╗██████╗ ██████╗ ██████╗ ',
|
|
287
287
|
'████╗ ████║██║╚██╗██╔╝██╔══██╗██╔═══██╗██╔════╝ ',
|
|
@@ -300,7 +300,7 @@ function paintBootSplash() {
|
|
|
300
300
|
out += `${bold}${fg}${center(logo[i])}${reset}\r\n`;
|
|
301
301
|
}
|
|
302
302
|
out += '\r\n';
|
|
303
|
-
out += `${subtleFg}${center(`mixdog coding agent · v${localPackageVersion()} · ${process.cwd()}
|
|
303
|
+
out += `${subtleFg}${center(`mixdog coding agent · v${localPackageVersion()} · ${process.cwd()}`, 4)}${reset}`;
|
|
304
304
|
|
|
305
305
|
// Park the cursor at home so ink's first frame paints top-down over the
|
|
306
306
|
// splash instead of starting at the bottom row and scrolling the screen.
|
|
@@ -6,41 +6,31 @@ hidden: true
|
|
|
6
6
|
agents: worker, heavy-worker, reviewer, debugger, maintainer
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
# Bench
|
|
9
|
+
# Bench
|
|
10
10
|
|
|
11
|
-
Autonomous
|
|
12
|
-
|
|
13
|
-
complete or provably blocked.
|
|
11
|
+
Autonomous: no user. Never wait for approval or ask questions; decide/proceed.
|
|
12
|
+
Loop until verified complete or provably blocked.
|
|
14
13
|
|
|
15
|
-
Lead supervises
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- Reviewer: verify implementation scopes (diff, regressions, missing checks).
|
|
21
|
-
- Debugger: very high complexity, or when root-causing has already failed at
|
|
22
|
-
least once.
|
|
14
|
+
Lead supervises, delegates, coordinates, judges, decides. Lead directly handles
|
|
15
|
+
simple 1–2-step work, coordination, pre-planning, config, final git deployment.
|
|
16
|
+
Worker: several-step implementation; Heavy Worker: high-complexity multi-step
|
|
17
|
+
implementation; Reviewer: implementation diff/regression/missing-check review;
|
|
18
|
+
Debugger: very high complexity or root cause already failed once.
|
|
23
19
|
|
|
24
|
-
1. Plan
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
re-verify until clean. Skip review only for simple, low-risk tasks. If a bug
|
|
42
|
-
survives 2+ fix cycles, have the debugger investigate first instead of
|
|
43
|
-
another fix round.
|
|
44
|
-
4. Finish — verify the final state yourself; only stop when the task is
|
|
45
|
-
complete and verified, or a hard blocker makes progress impossible. State
|
|
46
|
-
the outcome and evidence in the final message.
|
|
20
|
+
1. Plan: form it and execute immediately; no approval step.
|
|
21
|
+
2. Delegate: split to the maximum independent scopes. Parallelize independent
|
|
22
|
+
implementation/analysis/review/debugging, spawning every scope in one turn.
|
|
23
|
+
Shared/cross-cutting code does not justify merging: split by path and verify
|
|
24
|
+
shared parts yourself. A single scope needs a genuinely inseparable
|
|
25
|
+
dependency; state it. Within one complex scope, sequence steps with a
|
|
26
|
+
build/test-green gate between them. Briefs follow the Lead brief contract.
|
|
27
|
+
After async spawn, end turn: no polling, guessing, or dependent work until
|
|
28
|
+
completion notification.
|
|
29
|
+
3. Review: one Reviewer per implementation scope, spawned 1:1 in the same turn,
|
|
30
|
+
never deferred/batched; wait. Fact-check agent responses and cross-check
|
|
31
|
+
implementation/review yourself before acting. Return fixes to the original
|
|
32
|
+
scope; loop verify -> fix -> re-verify until clean. Skip only simple,
|
|
33
|
+
low-risk review. If a bug survives 2+ fix cycles, Debugger investigates
|
|
34
|
+
before another fix round.
|
|
35
|
+
4. Finish: verify final state yourself; stop only verified complete or hard
|
|
36
|
+
blocked. Final states outcome and evidence.
|
|
@@ -5,39 +5,45 @@ description: "Default agent workflow — fan-out parallel delegation across inde
|
|
|
5
5
|
agents: worker, heavy-worker, reviewer, debugger, maintainer
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# Default
|
|
8
|
+
# Default
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
before explicit go-ahead.
|
|
10
|
+
GATE: Before approval, only read-only investigation/planning while consulting.
|
|
11
|
+
Approval is a later explicit user message after the latest plan ("do it",
|
|
12
|
+
"proceed", "go ahead"). Initial/additional/changed requests reset planning;
|
|
13
|
+
approval with a scope change needs a revised plan and fresh approval. Before
|
|
14
|
+
approval: no edits, state mutation, or delegation.
|
|
16
15
|
|
|
17
|
-
Lead supervises
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
Lead supervises, delegates, coordinates, judges, decides. After approval,
|
|
17
|
+
delegate by default; Lead only coordinates, does git, or an obvious 1-edit/
|
|
18
|
+
1-check change. Route other implementation/research/debugging to its matching
|
|
19
|
+
agent. Worker: bounded established path, low local risk/coupling/verification,
|
|
20
|
+
clear local check. Heavy Worker: high risk/coupling/verification (including any
|
|
21
|
+
high-risk scope), or coupled staged work needing coordinated verification.
|
|
22
|
+
Architecture, contracts, storage, concurrency, security, lifecycle are
|
|
23
|
+
indicators, not automatic categories. Reviewer verifies an implementation;
|
|
24
|
+
Debugger handles requested debugging or root cause after a failed fix.
|
|
23
25
|
|
|
24
|
-
1. Plan
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
26
|
+
1. Plan: draft before any implementation; settle scope/plan, ask if ambiguous,
|
|
27
|
+
then await the gate.
|
|
28
|
+
2. Delegate: maximize useful fan-out—one suitable Worker/Heavy Worker per ready
|
|
29
|
+
independent scope whose parallel gain exceeds coordination/merge cost; spawn
|
|
30
|
+
all in one turn, with no count cap. Serialize only a real dependency,
|
|
31
|
+
overlapping write, or inseparable coupling. Briefs follow the Lead brief
|
|
32
|
+
contract. After async spawn, end the turn.
|
|
33
|
+
3. Review: after approval, complete delegation, review, self-verification, and
|
|
34
|
+
in-scope fixes without reapproval. Every delegated implementation gets one
|
|
35
|
+
Reviewer (all ready reviewers in one turn) and Lead integration/cross-scope
|
|
36
|
+
verification in parallel. Reviewer independently judges risk, intent,
|
|
37
|
+
boundaries; Lead checks acceptance/interactions, not duplicate same-scope
|
|
38
|
+
work. High-risk scopes add distinct lenses. Synthesize one verdict; send
|
|
39
|
+
merged fixes to the original live session; loop fix -> re-verify (same
|
|
40
|
+
Reviewer + Lead re-check) until clean. Debugger first for requested debugging
|
|
41
|
+
or a bug surviving 2+ fix cycles. Agent reports relay scope, verdict, next
|
|
42
|
+
work as in-progress, never conclusions.
|
|
43
|
+
4. Report: final (not interim) report compares work to approved plan and gives
|
|
44
|
+
verified result; never forward raw agent output. Ask about ship/deploy when
|
|
45
|
+
relevant. Build/deploy/commit/push require an explicit user request after
|
|
46
|
+
issue-free feedback; implementation approval alone is insufficient.
|
|
42
47
|
|
|
43
|
-
On
|
|
48
|
+
On outcome/direction change, pause and re-consult; otherwise continue approved
|
|
49
|
+
work without reapproval.
|
|
@@ -1,31 +1,28 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: solo
|
|
3
3
|
name: Solo
|
|
4
|
-
description: "Solo workflow — Lead handles everything directly
|
|
4
|
+
description: "Solo workflow — Lead handles everything directly."
|
|
5
5
|
agents:
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# Solo
|
|
8
|
+
# Solo
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
explicit go-ahead.
|
|
10
|
+
GATE: Before approval, only read-only investigation/planning while consulting.
|
|
11
|
+
Approval is a later explicit user message after the latest plan ("do it",
|
|
12
|
+
"proceed", "go ahead"). Initial/additional/changed requests reset planning;
|
|
13
|
+
approval with a scope change needs a revised plan and fresh approval. Before
|
|
14
|
+
approval: no edits or state mutation.
|
|
16
15
|
|
|
17
|
-
1. Plan
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
are in-progress, never conclusions.
|
|
22
|
-
3. Verify
|
|
23
|
-
4. Report
|
|
24
|
-
remaining risk/next step
|
|
25
|
-
|
|
16
|
+
1. Plan: draft before any implementation; settle scope/plan, ask if ambiguous,
|
|
17
|
+
then await the gate.
|
|
18
|
+
2. Execute: after approval, Lead does all work. Never spawn, send, delegate, or
|
|
19
|
+
ask agents to work. Complete execution/in-scope fixes without reapproval;
|
|
20
|
+
interim updates are in-progress, never conclusions.
|
|
21
|
+
3. Verify: Lead checks/fixes directly until clean or reports a blocker.
|
|
22
|
+
4. Report: final (not interim) report compares work to approved plan and gives
|
|
23
|
+
verification, remaining risk/next step. Build/deploy/commit/push require an
|
|
24
|
+
explicit user request after issue-free feedback; implementation approval
|
|
25
|
+
alone is insufficient.
|
|
26
26
|
|
|
27
|
-
On
|
|
28
|
-
|
|
29
|
-
Delegation rule:
|
|
30
|
-
- Never delegate/spawn/send or ask agents to work; ignore available-agent
|
|
31
|
-
sections while this workflow is active.
|
|
27
|
+
On outcome/direction change, pause and re-consult; otherwise continue approved
|
|
28
|
+
work without reapproval.
|