mixdog 0.9.45 → 0.9.47
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 +5 -2
- package/scripts/agent-dispatch-abort-compose-test.mjs +31 -0
- package/scripts/agent-model-liveness-test.mjs +618 -0
- package/scripts/agent-trace-io-test.mjs +68 -4
- package/scripts/bench-run.mjs +30 -3
- package/scripts/compact-pressure-test.mjs +187 -4
- package/scripts/compact-prior-context-flatten-test.mjs +252 -0
- package/scripts/compact-trigger-migration-smoke.mjs +8 -6
- package/scripts/compacted-placeholder-scrub-test.mjs +20 -34
- package/scripts/context-mcp-metering-test.mjs +75 -0
- package/scripts/explore-prompt-policy-test.mjs +15 -16
- package/scripts/explore-timeout-cancel-test.mjs +345 -0
- package/scripts/headless-pristine-execution-test.mjs +614 -0
- package/scripts/internal-comms-smoke.mjs +15 -6
- package/scripts/live-worker-smoke.mjs +1 -1
- package/scripts/memory-core-input-test.mjs +137 -0
- package/scripts/memory-rule-contract-test.mjs +5 -5
- package/scripts/openai-oauth-refresh-race-test.mjs +120 -0
- package/scripts/openai-oauth-ws-1006-retry-test.mjs +26 -0
- package/scripts/parent-abort-link-test.mjs +22 -0
- package/scripts/provider-toolcall-test.mjs +22 -0
- package/scripts/reactive-compact-persist-smoke.mjs +8 -4
- package/scripts/session-bench.mjs +3 -70
- package/scripts/task-bench.mjs +0 -2
- package/scripts/terminal-bench-isolation-guards-test.mjs +102 -0
- package/scripts/tool-smoke.mjs +21 -21
- package/scripts/tool-tui-presentation-test.mjs +68 -0
- package/scripts/tui-transcript-jitter-harness-entry.jsx +91 -10
- package/src/app.mjs +28 -103
- package/src/cli.mjs +17 -13
- package/src/defaults/cycle3-review-prompt.md +10 -4
- package/src/defaults/memory-promote-prompt.md +4 -3
- package/src/headless-command.mjs +139 -0
- package/src/headless-role.mjs +121 -10
- package/src/help.mjs +4 -1
- package/src/rules/agent/00-common.md +3 -3
- package/src/rules/agent/00-core.md +8 -9
- package/src/rules/agent/20-skip-protocol.md +2 -3
- package/src/rules/agent/30-explorer.md +50 -56
- package/src/rules/agent/40-cycle1-agent.md +10 -12
- package/src/rules/agent/41-cycle2-agent.md +12 -9
- package/src/rules/agent/42-cycle3-agent.md +4 -6
- package/src/rules/lead/01-general.md +5 -6
- package/src/rules/lead/02-channels.md +1 -1
- package/src/rules/lead/lead-brief.md +14 -17
- package/src/rules/lead/lead-tool.md +3 -3
- package/src/rules/shared/01-tool.md +41 -43
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +46 -10
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +44 -31
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +18 -3
- package/src/runtime/agent/orchestrator/config.mjs +96 -30
- package/src/runtime/agent/orchestrator/context/collect.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +18 -5
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +123 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +148 -30
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +5 -7
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +62 -14
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +141 -19
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -4
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +19 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +85 -17
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -17
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +159 -20
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +83 -10
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +75 -7
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +4 -374
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +0 -75
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +0 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +20 -3
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +32 -16
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +86 -15
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +30 -27
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +1 -14
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +21 -27
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +1 -3
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -51
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +26 -0
- package/src/runtime/memory/index.mjs +0 -1
- package/src/runtime/memory/lib/core-memory-store.mjs +44 -24
- package/src/runtime/memory/lib/http-router.mjs +0 -193
- package/src/runtime/memory/lib/memory-action-handlers.mjs +37 -11
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +13 -5
- package/src/runtime/memory/lib/memory-cycle2.mjs +8 -5
- package/src/runtime/memory/lib/memory-cycle3.mjs +41 -6
- package/src/runtime/memory/lib/query-handlers.mjs +49 -6
- package/src/runtime/memory/lib/recall-format.mjs +21 -6
- package/src/runtime/memory/tool-defs.mjs +5 -6
- package/src/runtime/shared/config.mjs +11 -34
- package/src/runtime/shared/pristine-execution-contract.json +75 -0
- package/src/runtime/shared/pristine-execution.mjs +356 -0
- package/src/runtime/shared/provider-api-key.mjs +43 -0
- package/src/runtime/shared/provider-auth-binding.mjs +21 -0
- package/src/session-runtime/context-status.mjs +61 -13
- package/src/session-runtime/mcp-glue.mjs +29 -2
- package/src/session-runtime/plugin-mcp.mjs +7 -0
- package/src/session-runtime/resource-api.mjs +38 -5
- package/src/session-runtime/runtime-core.mjs +5 -1
- package/src/session-runtime/session-turn-api.mjs +14 -2
- package/src/session-runtime/settings-api.mjs +5 -0
- package/src/session-runtime/tool-catalog.mjs +13 -2
- package/src/session-runtime/tool-defs.mjs +1 -3
- package/src/standalone/agent-task-status.mjs +50 -11
- package/src/standalone/agent-tool/tool-def.mjs +1 -1
- package/src/standalone/explore-tool.mjs +257 -49
- package/src/standalone/seeds.mjs +1 -0
- package/src/tui/App.jsx +23 -10
- package/src/tui/app/use-transcript-scroll.mjs +4 -3
- package/src/tui/app/use-transcript-window.mjs +12 -21
- package/src/tui/components/ContextPanel.jsx +19 -25
- package/src/tui/dist/index.mjs +77 -65
- package/src/tui/engine/agent-envelope.mjs +16 -5
- package/src/tui/engine/labels.mjs +1 -1
- package/src/workflows/default/WORKFLOW.md +21 -51
- package/src/workflows/solo/WORKFLOW.md +12 -17
- package/src/workflows/solo-review/WORKFLOW.md +0 -47
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const VALUE_OPTIONS = new Set(['--provider', '--model', '--effort', '--workflow']);
|
|
2
|
+
const FLAG_OPTIONS = new Set([
|
|
3
|
+
'--readonly', '--help', '-h', '--plain', '--react', '--remote', '--onboarding', '--fast',
|
|
4
|
+
]);
|
|
5
|
+
const HEADLESS_ROLE_ALIASES = new Map([
|
|
6
|
+
['explorer', 'explore'], ['explore', 'explore'],
|
|
7
|
+
['maint', 'maintainer'], ['maintenance', 'maintainer'], ['maintainer', 'maintainer'],
|
|
8
|
+
['worker', 'worker'],
|
|
9
|
+
['heavy', 'heavy-worker'], ['heavyworker', 'heavy-worker'], ['heavy-worker', 'heavy-worker'],
|
|
10
|
+
['review', 'reviewer'], ['reviewer', 'reviewer'],
|
|
11
|
+
['debug', 'debugger'], ['debugger', 'debugger'],
|
|
12
|
+
['web', 'web-researcher'], ['web-researcher', 'web-researcher'],
|
|
13
|
+
]);
|
|
14
|
+
const HEADLESS_WORKFLOW_ERROR = 'option --workflow is not supported for headless role commands';
|
|
15
|
+
|
|
16
|
+
function roleKey(value) {
|
|
17
|
+
return String(value || '').trim().toLowerCase().replace(/[\s_]+/g, '-');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function argvIndicatesHeadlessRole(argv) {
|
|
21
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
22
|
+
const arg = String(argv[index] ?? '');
|
|
23
|
+
if (VALUE_OPTIONS.has(arg)) {
|
|
24
|
+
const value = argv[index + 1];
|
|
25
|
+
if (value !== undefined && value !== '' && !String(value).startsWith('-')) {
|
|
26
|
+
if (HEADLESS_ROLE_ALIASES.has(roleKey(value))) return true;
|
|
27
|
+
index += 1;
|
|
28
|
+
}
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (FLAG_OPTIONS.has(arg) || arg.startsWith('-')) continue;
|
|
32
|
+
return HEADLESS_ROLE_ALIASES.has(roleKey(arg));
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function parseTokens(argv, { strictValues = true } = {}) {
|
|
38
|
+
const positional = [];
|
|
39
|
+
const values = {};
|
|
40
|
+
const allowHeadlessIntent = strictValues && !argv.includes('--react');
|
|
41
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
42
|
+
const arg = String(argv[index] ?? '');
|
|
43
|
+
if (VALUE_OPTIONS.has(arg)) {
|
|
44
|
+
const value = argv[index + 1];
|
|
45
|
+
if (value === undefined || value === '' || String(value).startsWith('-')) {
|
|
46
|
+
if (strictValues) {
|
|
47
|
+
return {
|
|
48
|
+
error: `option ${arg} requires a non-option value`,
|
|
49
|
+
skipHostPrelude: arg === '--provider' || arg === '--model',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const valueKey = roleKey(value);
|
|
55
|
+
if (allowHeadlessIntent && arg === '--workflow' && HEADLESS_ROLE_ALIASES.has(valueKey)) {
|
|
56
|
+
return {
|
|
57
|
+
error: HEADLESS_WORKFLOW_ERROR,
|
|
58
|
+
skipHostPrelude: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (allowHeadlessIntent
|
|
62
|
+
&& (arg === '--provider' || arg === '--model' || arg === '--effort')
|
|
63
|
+
&& HEADLESS_ROLE_ALIASES.has(valueKey)) {
|
|
64
|
+
return {
|
|
65
|
+
error: `option ${arg} requires a route value before headless role ${JSON.stringify(String(value))}`,
|
|
66
|
+
skipHostPrelude: true,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!(arg in values)) values[arg] = String(value);
|
|
70
|
+
index += 1;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (FLAG_OPTIONS.has(arg)) continue;
|
|
74
|
+
if (arg.startsWith('-')) {
|
|
75
|
+
return {
|
|
76
|
+
error: `unknown option ${arg}`,
|
|
77
|
+
...(allowHeadlessIntent
|
|
78
|
+
&& argvIndicatesHeadlessRole(argv)
|
|
79
|
+
? { skipHostPrelude: true }
|
|
80
|
+
: {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
positional.push(arg);
|
|
84
|
+
}
|
|
85
|
+
return { positional, values };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function headlessFromPositional(positional) {
|
|
89
|
+
if (!positional.length) return null;
|
|
90
|
+
if (String(positional[0]).toLowerCase() === 'role') {
|
|
91
|
+
return { error: 'usage: mixdog <role> <message...>' };
|
|
92
|
+
}
|
|
93
|
+
const key = roleKey(positional[0]);
|
|
94
|
+
const agent = HEADLESS_ROLE_ALIASES.get(key) || null;
|
|
95
|
+
if (!agent) return null;
|
|
96
|
+
const message = positional.slice(1).join(' ').trim();
|
|
97
|
+
if (!message) return { error: `usage: mixdog ${positional[0]} <message...>` };
|
|
98
|
+
return { agent, message };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function classifyCliInvocation(argv = []) {
|
|
102
|
+
const hasHelp = argv.includes('--help') || argv.includes('-h');
|
|
103
|
+
const hasPlain = argv.includes('--plain');
|
|
104
|
+
const parsed = parseTokens(argv, { strictValues: !hasHelp && !hasPlain });
|
|
105
|
+
if (parsed.error) return { kind: 'error', ...parsed };
|
|
106
|
+
const options = {
|
|
107
|
+
provider: parsed.values['--provider'],
|
|
108
|
+
model: parsed.values['--model'],
|
|
109
|
+
effort: parsed.values['--effort'],
|
|
110
|
+
fast: argv.includes('--fast'),
|
|
111
|
+
toolMode: argv.includes('--readonly') ? 'readonly' : 'full',
|
|
112
|
+
remote: argv.includes('--remote'),
|
|
113
|
+
forceOnboarding: argv.includes('--onboarding'),
|
|
114
|
+
};
|
|
115
|
+
if (hasHelp) return { kind: 'help', options };
|
|
116
|
+
if (hasPlain) return { kind: 'plain', options };
|
|
117
|
+
if (argv.includes('--react')) return { kind: 'react', options };
|
|
118
|
+
const headless = headlessFromPositional(parsed.positional);
|
|
119
|
+
if (headless?.error) {
|
|
120
|
+
return { kind: 'error', error: headless.error, skipHostPrelude: true };
|
|
121
|
+
}
|
|
122
|
+
if (headless) {
|
|
123
|
+
if (parsed.values['--workflow'] !== undefined) {
|
|
124
|
+
return {
|
|
125
|
+
kind: 'error',
|
|
126
|
+
error: HEADLESS_WORKFLOW_ERROR,
|
|
127
|
+
skipHostPrelude: true,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return { kind: 'headless', headless, options, skipHostPrelude: true };
|
|
131
|
+
}
|
|
132
|
+
return { kind: 'general', options };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function parseHeadlessRoleCommand(argv = []) {
|
|
136
|
+
const invocation = classifyCliInvocation(argv);
|
|
137
|
+
if (invocation.kind === 'error') return { error: invocation.error };
|
|
138
|
+
return invocation.kind === 'headless' ? invocation.headless : null;
|
|
139
|
+
}
|
package/src/headless-role.mjs
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { stdout, stderr } from 'node:process';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import {
|
|
3
|
+
createPristineExecutionBoundary,
|
|
4
|
+
formatPristineExecutionAudit,
|
|
5
|
+
validateExplicitPristineRoute,
|
|
6
|
+
} from './runtime/shared/pristine-execution.mjs';
|
|
7
|
+
import {
|
|
8
|
+
installProcessSignalCleanup,
|
|
9
|
+
waitWithTimeout,
|
|
10
|
+
} from './runtime/shared/process-shutdown.mjs';
|
|
6
11
|
|
|
7
12
|
const TERMINAL_STATUS_RE = /^status:\s*(completed|failed|error|cancelled|canceled)\b/im;
|
|
8
13
|
const FAILURE_STATUS_RE = /^status:\s*(failed|error|cancelled|canceled)\b/im;
|
|
@@ -40,10 +45,28 @@ export function buildHeadlessSpawnArgs({ agent, tag, cwd, message, provider, mod
|
|
|
40
45
|
return spawnArgs;
|
|
41
46
|
}
|
|
42
47
|
|
|
43
|
-
|
|
48
|
+
const HEADLESS_CLOSE_TIMEOUT_MS = 4500;
|
|
49
|
+
const HEADLESS_SHUTDOWN_TIMEOUT_MS = 6000;
|
|
50
|
+
const HEADLESS_CLEANUP_RESERVE_MS = 500;
|
|
51
|
+
|
|
52
|
+
async function buildAgentRunner(cwd, boundary) {
|
|
53
|
+
// Import runtime/config modules only after MIXDOG_DATA_DIR and all behavioral
|
|
54
|
+
// guards point at the ephemeral pristine boundary.
|
|
55
|
+
const [
|
|
56
|
+
{ createStandaloneAgent },
|
|
57
|
+
cfgMod,
|
|
58
|
+
reg,
|
|
59
|
+
mgr,
|
|
60
|
+
] = await Promise.all([
|
|
61
|
+
import('./standalone/agent-tool.mjs'),
|
|
62
|
+
import('./runtime/agent/orchestrator/config.mjs'),
|
|
63
|
+
import('./runtime/agent/orchestrator/providers/registry.mjs'),
|
|
64
|
+
import('./runtime/agent/orchestrator/session/manager.mjs'),
|
|
65
|
+
]);
|
|
44
66
|
return createStandaloneAgent({
|
|
45
67
|
cfgMod: {
|
|
46
|
-
|
|
68
|
+
// Never call the general loader here: it scans every OS-keychain provider.
|
|
69
|
+
loadConfig: boundary.loadConfig,
|
|
47
70
|
resolveRuntimeSpec: cfgMod.resolveRuntimeSpec,
|
|
48
71
|
},
|
|
49
72
|
reg,
|
|
@@ -63,6 +86,7 @@ export async function runHeadlessRole({
|
|
|
63
86
|
cwd = process.cwd(),
|
|
64
87
|
write = (text) => stdout.write(text),
|
|
65
88
|
writeErr = (text) => stderr.write(text),
|
|
89
|
+
agentRunnerFactory = buildAgentRunner,
|
|
66
90
|
} = {}) {
|
|
67
91
|
const cleanAgent = clean(agent);
|
|
68
92
|
const cleanMessage = clean(message);
|
|
@@ -74,8 +98,12 @@ export async function runHeadlessRole({
|
|
|
74
98
|
writeErr('mixdog: message is required\n');
|
|
75
99
|
return 1;
|
|
76
100
|
}
|
|
101
|
+
const routeError = validateExplicitPristineRoute({ provider, model, effort, fast });
|
|
102
|
+
if (routeError) {
|
|
103
|
+
writeErr(`mixdog: ${routeError}\n`);
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
77
106
|
|
|
78
|
-
const agentRunner = buildAgentRunner(cwd);
|
|
79
107
|
const tag = makeTag(cleanAgent);
|
|
80
108
|
const context = {
|
|
81
109
|
invocationSource: 'headless',
|
|
@@ -94,9 +122,92 @@ export async function runHeadlessRole({
|
|
|
94
122
|
fast,
|
|
95
123
|
});
|
|
96
124
|
|
|
125
|
+
let boundary = null;
|
|
126
|
+
let agentRunner = null;
|
|
127
|
+
let signalCleanup = null;
|
|
128
|
+
let cleanupPromise = null;
|
|
129
|
+
let drainTrace = null;
|
|
97
130
|
let taskId = null;
|
|
98
131
|
let lastOutput = '';
|
|
132
|
+
const cleanup = (reason = 'headless-exit') => {
|
|
133
|
+
if (cleanupPromise) return cleanupPromise;
|
|
134
|
+
cleanupPromise = (async () => {
|
|
135
|
+
const deadline = Date.now()
|
|
136
|
+
+ HEADLESS_SHUTDOWN_TIMEOUT_MS
|
|
137
|
+
- HEADLESS_CLEANUP_RESERVE_MS;
|
|
138
|
+
const runCleanupStep = async (start, maxMs, label) => {
|
|
139
|
+
const remaining = deadline - Date.now();
|
|
140
|
+
if (remaining <= 0) return;
|
|
141
|
+
const budget = Math.min(maxMs, remaining);
|
|
142
|
+
// waitWithTimeout intentionally unrefs its timer. Keep this one-shot
|
|
143
|
+
// headless cleanup alive until the step settles or consumes its budget,
|
|
144
|
+
// otherwise an unresolved close can terminate Node before `finally`.
|
|
145
|
+
const keepAlive = setTimeout(() => {}, budget + 1);
|
|
146
|
+
try {
|
|
147
|
+
await waitWithTimeout(start(), budget, label);
|
|
148
|
+
} finally {
|
|
149
|
+
clearTimeout(keepAlive);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
try {
|
|
153
|
+
if (agentRunner) {
|
|
154
|
+
await runCleanupStep(
|
|
155
|
+
() => agentRunner.execute({ type: 'close', tag }, context),
|
|
156
|
+
HEADLESS_CLOSE_TIMEOUT_MS,
|
|
157
|
+
'headless agent close',
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
// Trace drain and boundary cleanup remain mandatory when close hangs.
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
if (drainTrace) {
|
|
165
|
+
await runCleanupStep(
|
|
166
|
+
drainTrace,
|
|
167
|
+
HEADLESS_SHUTDOWN_TIMEOUT_MS,
|
|
168
|
+
'headless trace drain',
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
// Telemetry must never block cleanup of the pristine boundary.
|
|
173
|
+
} finally {
|
|
174
|
+
try {
|
|
175
|
+
await runCleanupStep(async () => {
|
|
176
|
+
const closeNativePatchServers = globalThis.__mixdogCloseNativePatchServers;
|
|
177
|
+
if (typeof closeNativePatchServers === 'function') {
|
|
178
|
+
await closeNativePatchServers();
|
|
179
|
+
}
|
|
180
|
+
}, HEADLESS_CLOSE_TIMEOUT_MS, 'headless native patch close');
|
|
181
|
+
} catch {
|
|
182
|
+
// The boundary cleanup below remains mandatory if native shutdown hangs.
|
|
183
|
+
} finally {
|
|
184
|
+
boundary?.cleanup();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
})();
|
|
188
|
+
return cleanupPromise;
|
|
189
|
+
};
|
|
99
190
|
try {
|
|
191
|
+
try {
|
|
192
|
+
boundary = createPristineExecutionBoundary({ provider, model, effort, fast });
|
|
193
|
+
} catch (error) {
|
|
194
|
+
writeErr(`mixdog: ${error?.message || error}\n`);
|
|
195
|
+
return 1;
|
|
196
|
+
}
|
|
197
|
+
writeErr(`${formatPristineExecutionAudit(boundary.audit)}\n`);
|
|
198
|
+
signalCleanup = installProcessSignalCleanup({
|
|
199
|
+
name: 'mixdog-headless',
|
|
200
|
+
timeoutMs: HEADLESS_SHUTDOWN_TIMEOUT_MS,
|
|
201
|
+
cleanup,
|
|
202
|
+
});
|
|
203
|
+
agentRunner = await agentRunnerFactory(cwd, boundary);
|
|
204
|
+
try {
|
|
205
|
+
({ drainAgentTrace: drainTrace } = await import(
|
|
206
|
+
'./runtime/agent/orchestrator/agent-trace.mjs'
|
|
207
|
+
));
|
|
208
|
+
} catch {
|
|
209
|
+
drainTrace = null;
|
|
210
|
+
}
|
|
100
211
|
const started = await agentRunner.execute(spawnArgs, context);
|
|
101
212
|
lastOutput = clean(started);
|
|
102
213
|
taskId = taskIdFromOutput(started);
|
|
@@ -115,9 +226,9 @@ export async function runHeadlessRole({
|
|
|
115
226
|
return FAILURE_STATUS_RE.test(lastOutput) ? 1 : 0;
|
|
116
227
|
} finally {
|
|
117
228
|
try {
|
|
118
|
-
await
|
|
119
|
-
}
|
|
120
|
-
|
|
229
|
+
await cleanup('headless-exit');
|
|
230
|
+
} finally {
|
|
231
|
+
signalCleanup?.uninstall();
|
|
121
232
|
}
|
|
122
233
|
}
|
|
123
234
|
}
|
package/src/help.mjs
CHANGED
|
@@ -7,9 +7,12 @@ export const HELP_LINES = [
|
|
|
7
7
|
'Usage:',
|
|
8
8
|
' mixdog [--provider <name>] [--model <name>] [--readonly]',
|
|
9
9
|
' mixdog [--onboarding] re-run the first-run setup wizard',
|
|
10
|
-
' mixdog <role> <message...>',
|
|
10
|
+
' mixdog --provider <name> --model <name> [--effort <level>] [--fast] <role> <message...>',
|
|
11
11
|
' mixdog --help',
|
|
12
12
|
'',
|
|
13
|
+
'Headless role commands require an explicit provider/model pair and run with',
|
|
14
|
+
'ephemeral config/data; host behavioral config and personal state are not loaded.',
|
|
15
|
+
'',
|
|
13
16
|
'Slash commands (inside mixdog):',
|
|
14
17
|
' /clear reset the conversation and clear the screen',
|
|
15
18
|
' /compact compact older conversation context',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Public Agent Constraints
|
|
2
2
|
|
|
3
|
-
-
|
|
3
|
+
- Never touch git/Ship. Refuse `git add`/`commit`/`push`/`stash` with `git
|
|
4
4
|
operations deferred to Lead`.
|
|
5
|
-
-
|
|
6
|
-
|
|
5
|
+
- Use shell only to verify your edits; never explore, install, or change state
|
|
6
|
+
beyond the brief.
|
|
7
7
|
- Overflow goes to a file; hand off path + fragments.
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
# Agent Constraints
|
|
2
2
|
|
|
3
|
-
- Agent communication
|
|
4
|
-
|
|
3
|
+
- Agent communication is English. One turn is one batch; include every
|
|
4
|
+
compatible read-only call.
|
|
5
5
|
- Call tools immediately: no preamble/progress; text only in final handoff.
|
|
6
6
|
- Final handoff is fragments: outcome, key `file:line`, verification
|
|
7
|
-
command+result, material risk/blocker
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- Runtime wrap-up overrides; it may require done/remaining/blocking summary.
|
|
7
|
+
command+result, material risk/blocker. Never repeat the brief, process,
|
|
8
|
+
search path, or facts; never retrieve only to report.
|
|
9
|
+
- Limit the handoff to 30 lines unless `Deliver:` sets another limit. Never use
|
|
10
|
+
unrequested headings/tables, prose narration, raw logs/tool traces,
|
|
11
|
+
speculative next checks, restated briefs, articles, or politeness.
|
|
12
|
+
- Follow stricter role contracts and runtime wrap-up requirements.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# Skip Protocol
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
with `[meta:silent]`.
|
|
3
|
+
Prefix every non-actionable `webhook-handler` or `scheduler-task` inbound-event
|
|
4
|
+
report with `[meta:silent]`.
|
|
@@ -6,59 +6,53 @@ kind: retrieval
|
|
|
6
6
|
|
|
7
7
|
# Role: explorer
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
-
unverified path/name
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
on every line; with none, return `EXPLORATION_FAILED`, never a bare filename or
|
|
60
|
-
vague prose. Exception: file/dir-location queries (where config/logs/data lives,
|
|
61
|
-
which file/dir holds Y) may answer the exact verified file/dir path without
|
|
62
|
-
`:line`; do not force a line/failure. Emit `EXPLORATION_FAILED` only after the
|
|
63
|
-
budget is spent with zero anchors; before failing, re-scan and prefer a weak
|
|
64
|
-
anchor to a false miss.
|
|
9
|
+
Return only WHERE (`path:line`), never WHY. You ARE `explore`; never call it.
|
|
10
|
+
Use only grep/find/glob/code_graph; `read` and `list` are forbidden.
|
|
11
|
+
|
|
12
|
+
Turn 1 (`turn 1/3`) is the whole search. Split broad/uncertain input into every
|
|
13
|
+
known facet and send one batch under the shared one-route contract. Use
|
|
14
|
+
`pattern[]` with 4–8 code-token variants for concept facets, `code_graph`
|
|
15
|
+
`symbol_search` for symbol facets, and `find` `query[]` for unknown/broad
|
|
16
|
+
targets or unverified path/name fragments. For a symptom/behavior query, add
|
|
17
|
+
the upstream producer/derivation layer of the reported surface as extra facets
|
|
18
|
+
in the SAME batch (more `pattern[]` variants or `code_graph` `symbol_search`),
|
|
19
|
+
never as a later turn. Follow-up turns batch every unresolved facet in
|
|
20
|
+
parallel; a single-tool turn is allowed only when exactly one
|
|
21
|
+
pre-anchor/zero-hit facet remains.
|
|
22
|
+
|
|
23
|
+
For broad grep use `output_mode:"files_with_matches"`. Use
|
|
24
|
+
`content_with_context` with `head_limit` only on paths returned this session.
|
|
25
|
+
Each pattern is one identifier, camel/snake variant, or concept synonym; never
|
|
26
|
+
a prose phrase. Spaces and non-ASCII are allowed only in verbatim quoted
|
|
27
|
+
error/log literals. Translate other non-English queries to English identifiers.
|
|
28
|
+
|
|
29
|
+
Scope is session cwd; `path` may be omitted. For unverified `src` paths, use
|
|
30
|
+
`find` first; never guess or invent directories or pair `path:"."` with guessed
|
|
31
|
+
`src/**`. Scoped grep/glob may use only an exact find-returned path, no earlier
|
|
32
|
+
than turn 2. After zero hits, change tokens or scope, never wording or guessed
|
|
33
|
+
paths.
|
|
34
|
+
|
|
35
|
+
An anchor is a `path:line` containing a query token or synonym, including a
|
|
36
|
+
code_graph hit. Generic terms without query specificity are zero. Never
|
|
37
|
+
re-locate, reconfirm, or upgrade an anchor. A path without `:line` is a
|
|
38
|
+
pre-anchor and counts as zero. After every result, stop and answer on any
|
|
39
|
+
specific-token anchor; mark a weak anchor `?`.
|
|
40
|
+
|
|
41
|
+
For a code-location query left only with pre-anchors, the sole anchor-minting
|
|
42
|
+
follow-up is one scoped `content_with_context` grep with `head_limit` on those
|
|
43
|
+
paths. If it returns zero, recovery may continue within budget with changed
|
|
44
|
+
tokens or scope. Never make a second minting hop or fabricate/estimate a line.
|
|
45
|
+
|
|
46
|
+
Use at most 3 turns and label every tool message `turn N/3`; normally use one
|
|
47
|
+
batch and one answer. Turns 2–3 are allowed only when turn 1 has zero anchors.
|
|
48
|
+
The first matching entry/definition anchors a concept, value, or default; never
|
|
49
|
+
trace its chain. Only an explicit flow or default-resolution query with an
|
|
50
|
+
entry anchor but no resolved value may use turn 2 for one resolving hop.
|
|
51
|
+
|
|
52
|
+
Answer in at most 3 lines, most specific first:
|
|
53
|
+
`path:line — symbol — short reason`. Copy every cited `path:line` verbatim from
|
|
54
|
+
a tool result in this session; never estimate, adjust, or recall it. Every
|
|
55
|
+
code-location line requires `:line`; never return a bare filename or vague
|
|
56
|
+
prose. A file/dir-location query may return an exact verified path without
|
|
57
|
+
`:line`. Return `EXPLORATION_FAILED` only after spending the budget with zero
|
|
58
|
+
anchors; first prefer a weak anchor to a false miss.
|
|
@@ -10,17 +10,15 @@ maintKey: memory
|
|
|
10
10
|
Turn numbered chat rows into memory chunks. Output only digit-starting
|
|
11
11
|
pipe-separated lines: `<idx_csv>|<element>|<category>|<summary>`.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
versions, numbers, errors, causes, and outcomes verbatim and match input
|
|
21
|
-
language.
|
|
13
|
+
`idx_csv` is the included input row numbers, comma-separated, without `@`.
|
|
14
|
+
`element` is a 5–10-word recall key. `category` is exactly `rule` (standing
|
|
15
|
+
policy), `constraint` (hard limit), `decision` (agreed choice), `fact`
|
|
16
|
+
(verified truth), `goal` (open target), `preference` (style/taste), `task`
|
|
17
|
+
(pending work), or `issue` (broken state). `summary` is 1–3 complete sentences
|
|
18
|
+
that match input language and preserve important names, paths, IDs, versions,
|
|
19
|
+
numbers, errors, causes, and outcomes verbatim.
|
|
22
20
|
|
|
23
21
|
Every input row appears exactly once. Group nearby same-topic rows, splitting
|
|
24
|
-
only at real topic changes
|
|
25
|
-
`[sess:XXX]` markers in a chunk. Replace literal `|` with `/`; fields
|
|
26
|
-
no newlines. No JSON, fences, prose, preamble, or tool calls.
|
|
22
|
+
only at real topic changes, and retain clarifications with their topic. Never
|
|
23
|
+
mix `[sess:XXX]` markers in a chunk. Replace literal `|` with `/`; fields
|
|
24
|
+
contain no newlines. No JSON, fences, prose, preamble, or tool calls.
|
|
@@ -7,27 +7,30 @@ maintKey: memory
|
|
|
7
7
|
|
|
8
8
|
# Role: cycle2-agent
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Re-score `is_root` long-term memory from phase, core memory, and candidate
|
|
11
|
+
`id`/`category`/`score`/`element`/`summary`. Output only digit-starting pipe
|
|
12
|
+
lines; no JSON, fences, prose, or preamble.
|
|
13
13
|
|
|
14
|
-
Promote
|
|
14
|
+
Promote only when clearly exactly one essential concept:
|
|
15
15
|
identity (stable non-derivable user fact); preference (durable
|
|
16
16
|
taste/style/interaction preference); goal (long-running committed goal);
|
|
17
17
|
principle (cross-session behavior directive); policy (standing team decision);
|
|
18
18
|
procedure (recurring trigger + steps + caveats); event (rare foundational
|
|
19
19
|
change not reconstructible from its rule); system constant (durable
|
|
20
20
|
path/schema/model/channel invariant needed later and absent from rules).
|
|
21
|
+
Promote only durable knowledge not derivable from code/git/rules.
|
|
21
22
|
Anything unclear or outside these concepts is `archived`.
|
|
22
23
|
|
|
23
24
|
Phase verbs: `phase1_new_chunks` → `active` if clearly essential, otherwise
|
|
24
25
|
`archived`; `phase2_reevaluate` → `active` to promote, otherwise `archived`;
|
|
25
|
-
`phase3_active_review` requires
|
|
26
|
-
|
|
26
|
+
`phase3_active_review` requires an `archived`, `active`, `update`, or `merge`
|
|
27
|
+
verdict for every row, defaults to `archived`, and never treats silence as keep.
|
|
27
28
|
|
|
28
29
|
Archive work narratives; static facts without behavior/user value; rule-system
|
|
29
30
|
meta; resolved bug/fix logs; rule-file duplicates; single-run
|
|
30
|
-
measurements/counts/versions;
|
|
31
|
+
measurements/counts/versions; session-scoped or in-progress decisions;
|
|
32
|
+
code-derivable implementation details; expiring temp paths; and one-task
|
|
33
|
+
directives. Merge cross-language duplicates.
|
|
31
34
|
|
|
32
35
|
`<id>|<verb>`
|
|
33
36
|
`<id>|update|<element>|<summary>`
|
|
@@ -38,5 +41,5 @@ Use only input IDs; never invent IDs. `update` supplies fresh `element` and a
|
|
|
38
41
|
uses only one `project_id`. Summaries are complete sentences in input language,
|
|
39
42
|
preserve important specifics verbatim, and omit actor/meta filler. Category
|
|
40
43
|
priority: `rule > constraint > decision > fact > goal > preference > task >
|
|
41
|
-
issue`. Replace literal `|` with `/`; fields contain no newlines.
|
|
42
|
-
|
|
44
|
+
issue`. Replace literal `|` with `/`; fields contain no newlines. Start every
|
|
45
|
+
verdict with a digit.
|
|
@@ -12,10 +12,9 @@ Output only one digit-starting pipe verdict line per input id; no JSON, fences,
|
|
|
12
12
|
prose, or preamble.
|
|
13
13
|
|
|
14
14
|
CORE is durable standing knowledge: rules, preferences, identity, goals, and
|
|
15
|
-
current system/structure descriptions—not a log. Each entry is one short
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
keep.
|
|
15
|
+
current system/structure descriptions—not a log. Each entry is one short clause
|
|
16
|
+
(≤120 chars). Current rule/preference/live structure = durable; a past event =
|
|
17
|
+
not durable. When unsure, keep.
|
|
19
18
|
|
|
20
19
|
- `keep`: durable, already one short clause.
|
|
21
20
|
- `update`: durable but verbose/multi-sentence; compress to one ≤120-char
|
|
@@ -33,5 +32,4 @@ Verbose durable is always `update`, never `keep`.
|
|
|
33
32
|
IDs match input rows; never invent them. An `update` summary is one ≤120-char
|
|
34
33
|
clause and its `element` is short. A `merge` retains `target_id`, absorbs
|
|
35
34
|
sources, and stays within one `project_id`. Replace literal `|` with `/`;
|
|
36
|
-
fields contain no newlines. Emit a verdict for every input row
|
|
37
|
-
digit.
|
|
35
|
+
fields contain no newlines. Emit a digit-starting verdict for every input row.
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# General
|
|
2
2
|
|
|
3
|
-
- You are Mixdog,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
headings, labels, routine lookup narration.
|
|
3
|
+
- You are Mixdog, the current coding-agent CLI/TUI assistant with
|
|
4
|
+
multi-provider agent workflows. Never identify as generic OpenAI/ChatGPT.
|
|
5
|
+
- A preamble is at most one useful sentence. Never use direct names,
|
|
6
|
+
honorifics, headings, labels, or routine lookup narration.
|
|
8
7
|
- Destructive/hard-to-reverse action needs explicit confirmation.
|
|
9
|
-
- Act proactively; ask
|
|
8
|
+
- Act proactively; ask only for decisions.
|