codehere 1.0.1 → 1.0.3
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/README.md +35 -193
- package/dist/application/use-cases/check-claimed-tests.js +81 -0
- package/dist/application/use-cases/detect-test-weakening.js +237 -0
- package/dist/application/use-cases/rerun-tests.js +110 -7
- package/dist/index.js +38 -1212
- package/dist/infrastructure/orchestration/artifacts-extractor.js +2 -323
- package/dist/presentation/cli/commands/check-command.js +178 -23
- package/dist/presentation/cli/commands/help-command.js +21 -285
- package/dist/ui.js +5 -236
- package/dist/utils/version.js +0 -6
- package/package.json +9 -38
- package/dist/application/services/verdict-service.js +0 -154
- package/dist/application/use-cases/assess-cross-vendor.js +0 -126
- package/dist/application/use-cases/build-cross-vendor-verdict.js +0 -118
- package/dist/application/use-cases/domain-trust.js +0 -110
- package/dist/application/use-cases/export-aat.js +0 -107
- package/dist/application/use-cases/generate-acceptance-criteria.js +0 -223
- package/dist/application/use-cases/generate-final-report.js +0 -259
- package/dist/application/use-cases/generate-narration.js +0 -130
- package/dist/application/use-cases/generate-thread-title.js +0 -181
- package/dist/application/use-cases/narrator-prompt-template.js +0 -158
- package/dist/application/use-cases/plan-auto-review.js +0 -57
- package/dist/application/use-cases/reconcile-audit.js +0 -100
- package/dist/application/use-cases/search-sessions.js +0 -70
- package/dist/application/use-cases/should-auto-review.js +0 -71
- package/dist/application/use-cases/thread-export.js +0 -245
- package/dist/application/use-cases/verify-claim.js +0 -456
- package/dist/application/use-cases/write-pass.js +0 -277
- package/dist/domain/audit.js +0 -11
- package/dist/domain/services/codebase-detector.js +0 -85
- package/dist/domain/task.js +0 -91
- package/dist/error-handler.js +0 -139
- package/dist/infrastructure/completion/bash-completion.js +0 -29
- package/dist/infrastructure/completion/fish-completion.js +0 -17
- package/dist/infrastructure/completion/zsh-completion.js +0 -25
- package/dist/infrastructure/config/config-manager.js +0 -174
- package/dist/infrastructure/config/product-context.js +0 -49
- package/dist/infrastructure/context/adapters/drawio-source.js +0 -157
- package/dist/infrastructure/context/adapters/figma-source.js +0 -198
- package/dist/infrastructure/context/adapters/github-issue-source.js +0 -160
- package/dist/infrastructure/context/adapters/linear-source.js +0 -190
- package/dist/infrastructure/context/context-resolver.js +0 -144
- package/dist/infrastructure/context/context-source.js +0 -114
- package/dist/infrastructure/context/github-api.js +0 -110
- package/dist/infrastructure/context/github-device-flow.js +0 -65
- package/dist/infrastructure/context/oauth-flow.js +0 -207
- package/dist/infrastructure/context/oauth-store.js +0 -122
- package/dist/infrastructure/context/registry-bootstrap.js +0 -95
- package/dist/infrastructure/context/write-pass-resolver.js +0 -106
- package/dist/infrastructure/cost/budget-config.js +0 -114
- package/dist/infrastructure/cost/cost-router.js +0 -97
- package/dist/infrastructure/cost/spend-aggregator.js +0 -222
- package/dist/infrastructure/cost/team-ledger.js +0 -355
- package/dist/infrastructure/discovery/discovery-log.js +0 -85
- package/dist/infrastructure/hooks/audit-tip-signature.js +0 -336
- package/dist/infrastructure/hooks/claude-sdk-hook.js +0 -1018
- package/dist/infrastructure/hooks/hook-mode.js +0 -87
- package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +0 -49
- package/dist/infrastructure/hooks/pre-prompt-scan.js +0 -122
- package/dist/infrastructure/hooks/session-analyzer.js +0 -177
- package/dist/infrastructure/observability/execution-tracer.js +0 -227
- package/dist/infrastructure/orchestration/agent-adapter.js +0 -13
- package/dist/infrastructure/orchestration/agent-installer.js +0 -101
- package/dist/infrastructure/orchestration/agents-config-seed.js +0 -68
- package/dist/infrastructure/orchestration/aider-adapter.js +0 -611
- package/dist/infrastructure/orchestration/cassette-recorder.js +0 -120
- package/dist/infrastructure/orchestration/claude-code-adapter.js +0 -592
- package/dist/infrastructure/orchestration/codex-adapter.js +0 -574
- package/dist/infrastructure/orchestration/conductor-adapter.js +0 -416
- package/dist/infrastructure/orchestration/context-handoff.js +0 -162
- package/dist/infrastructure/orchestration/control/codex-control-surface.js +0 -99
- package/dist/infrastructure/orchestration/control/control-surface.js +0 -15
- package/dist/infrastructure/orchestration/detect-ollama.js +0 -75
- package/dist/infrastructure/orchestration/failover-classifier.js +0 -151
- package/dist/infrastructure/orchestration/failover-config.js +0 -67
- package/dist/infrastructure/orchestration/failover-policy.js +0 -106
- package/dist/infrastructure/orchestration/gemini-adapter.js +0 -663
- package/dist/infrastructure/orchestration/generic-cli-adapter.js +0 -689
- package/dist/infrastructure/orchestration/graphify-context.js +0 -209
- package/dist/infrastructure/orchestration/memory-injector.js +0 -380
- package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +0 -388
- package/dist/infrastructure/orchestration/mocks/mock-codex-app-server.js +0 -73
- package/dist/infrastructure/orchestration/mocks/mock-synthesis.js +0 -83
- package/dist/infrastructure/orchestration/mocks/resolve-agent-spawn.js +0 -37
- package/dist/infrastructure/orchestration/opencode-adapter.js +0 -580
- package/dist/infrastructure/orchestration/progress-aggregator.js +0 -906
- package/dist/infrastructure/orchestration/readiness.js +0 -103
- package/dist/infrastructure/orchestration/session-manager.js +0 -1590
- package/dist/infrastructure/orchestration/session-persistence.js +0 -394
- package/dist/infrastructure/orchestration/thread-key-store.js +0 -127
- package/dist/infrastructure/orchestration/write-pass-store.js +0 -38
- package/dist/infrastructure/protocols/cloud-sync.js +0 -207
- package/dist/infrastructure/protocols/mcp-helpers.js +0 -25
- package/dist/infrastructure/protocols/mcp-server-impl.js +0 -3935
- package/dist/infrastructure/protocols/mcp-tools.js +0 -401
- package/dist/infrastructure/protocols/probe-port.js +0 -36
- package/dist/infrastructure/protocols/thread-phase.js +0 -105
- package/dist/infrastructure/protocols/ui/app-script-artifacts.js +0 -121
- package/dist/infrastructure/protocols/ui/app-script-audit-footer.js +0 -44
- package/dist/infrastructure/protocols/ui/app-script-audit-verify.js +0 -56
- package/dist/infrastructure/protocols/ui/app-script-composer-cost.js +0 -588
- package/dist/infrastructure/protocols/ui/app-script-context-sources.js +0 -168
- package/dist/infrastructure/protocols/ui/app-script-conversation.js +0 -67
- package/dist/infrastructure/protocols/ui/app-script-drawer.js +0 -115
- package/dist/infrastructure/protocols/ui/app-script-failover.js +0 -133
- package/dist/infrastructure/protocols/ui/app-script-github.js +0 -113
- package/dist/infrastructure/protocols/ui/app-script-observer.js +0 -104
- package/dist/infrastructure/protocols/ui/app-script-onboarding.js +0 -80
- package/dist/infrastructure/protocols/ui/app-script-overlay.js +0 -203
- package/dist/infrastructure/protocols/ui/app-script-recovery.js +0 -136
- package/dist/infrastructure/protocols/ui/app-script-render.js +0 -166
- package/dist/infrastructure/protocols/ui/app-script-share.js +0 -78
- package/dist/infrastructure/protocols/ui/app-script-sidebar.js +0 -194
- package/dist/infrastructure/protocols/ui/app-script-tour.js +0 -78
- package/dist/infrastructure/protocols/ui/app-script-wpass.js +0 -312
- package/dist/infrastructure/protocols/ui/app-script.js +0 -2998
- package/dist/infrastructure/protocols/ui/font-faces.js +0 -7
- package/dist/infrastructure/protocols/ui/styles.js +0 -2147
- package/dist/infrastructure/protocols/ui/tokens.js +0 -96
- package/dist/infrastructure/protocols/ui-page-v2.js +0 -320
- package/dist/infrastructure/protocols/verify-page.js +0 -1677
- package/dist/infrastructure/security/file-collection.js +0 -118
- package/dist/infrastructure/security/fix-code.js +0 -144
- package/dist/infrastructure/security/fix-secret.js +0 -89
- package/dist/infrastructure/security/permissions-config.js +0 -235
- package/dist/infrastructure/security/scan-types.js +0 -10
- package/dist/infrastructure/security/ship-scan.js +0 -195
- package/dist/infrastructure/security/trust-scorer.js +0 -724
- package/dist/infrastructure/security/vibe-checks.js +0 -99
- package/dist/infrastructure/storage/atomic-write.js +0 -86
- package/dist/infrastructure/storage/cross-tool-agents.js +0 -268
- package/dist/infrastructure/storage/project-thread-migration.js +0 -237
- package/dist/infrastructure/storage/project-thread-mirror.js +0 -671
- package/dist/infrastructure/storage/project-thread-reader.js +0 -409
- package/dist/infrastructure/storage/project-thread-title-backfill.js +0 -214
- package/dist/monitoring.js +0 -212
- package/dist/presentation/cli/commands/audit-command.js +0 -201
- package/dist/presentation/cli/commands/budget-command.js +0 -79
- package/dist/presentation/cli/commands/config-command.js +0 -125
- package/dist/presentation/cli/commands/context-source-command.js +0 -217
- package/dist/presentation/cli/commands/hook-command.js +0 -265
- package/dist/presentation/cli/commands/init-command.js +0 -590
- package/dist/presentation/cli/commands/memory-command.js +0 -1031
- package/dist/presentation/cli/commands/narrator-command.js +0 -101
- package/dist/presentation/cli/commands/permission-command.js +0 -105
- package/dist/presentation/cli/commands/protocols-builder.js +0 -254
- package/dist/presentation/cli/commands/protocols-command.js +0 -84
- package/dist/presentation/cli/commands/repo-map-builder.js +0 -247
- package/dist/presentation/cli/commands/report-command.js +0 -403
- package/dist/presentation/cli/commands/scan-command.js +0 -52
- package/dist/presentation/cli/commands/scan-tool-command.js +0 -110
- package/dist/presentation/cli/commands/search-command.js +0 -51
- package/dist/presentation/cli/commands/setup-command.js +0 -330
- package/dist/presentation/cli/commands/status-command.js +0 -614
- package/dist/presentation/cli/commands/team-command.js +0 -256
- package/dist/presentation/cli/commands/thread-command.js +0 -370
- package/dist/presentation/cli/commands/trust-command.js +0 -328
- package/dist/presentation/cli/commands/verify-command.js +0 -298
- package/dist/presentation/cli/error-display.js +0 -328
- package/dist/presentation/cli/repl.js +0 -805
- package/dist/presentation/cli/task-deliverable.js +0 -153
- package/dist/testing/cassette.js +0 -125
- package/dist/testing/replay-adapter.js +0 -147
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock agent REPL · the synthetic subprocess codehere spawns under CODEHERE_MOCK=1
|
|
3
|
-
* INSTEAD of a real agent CLI. Zero API spend, zero rate limits — lets us build +
|
|
4
|
-
* dogfood the REAL execution path (spawn → tool calls → audit → artifacts → Final
|
|
5
|
-
* Report) and remote-control against a stand-in agent.
|
|
6
|
-
*
|
|
7
|
-
* Run as: node mock-agent-repl.js --agent <id> -p "<prompt>" [...ignored flags]
|
|
8
|
-
*
|
|
9
|
-
* Each agent emits its OWN CLI output format so the matching adapter parses it
|
|
10
|
-
* unchanged. claude-code → newline-delimited stream-json. (codex/aider/gemini/
|
|
11
|
-
* opencode formats added as their adapters get wired.)
|
|
12
|
-
*
|
|
13
|
-
* Honest scope: synthetic, deterministic-ish output derived from the prompt. It
|
|
14
|
-
* is NOT a real model — it produces plausible steps + a summary so the pipeline
|
|
15
|
-
* runs end-to-end. For replaying REAL captured runs, that's the cassette system.
|
|
16
|
-
*/
|
|
17
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
18
|
-
import { join } from 'path';
|
|
19
|
-
function argVal(flag) {
|
|
20
|
-
const i = process.argv.indexOf(flag);
|
|
21
|
-
return i >= 0 && i + 1 < process.argv.length ? process.argv[i + 1] : undefined;
|
|
22
|
-
}
|
|
23
|
-
/** The single dedicated file the mock edits — claimed in the step AND written on
|
|
24
|
-
* disk, so they stay consistent. ALWAYS a mock-only file, NEVER an existing real
|
|
25
|
-
* source file. The prior version derived a path from the prompt and appended to
|
|
26
|
-
* it; when the daemon's cwd was a real repo and the prompt carried injected
|
|
27
|
-
* memory (which lists repo paths like `src/ui.ts`), it corrupted real tracked
|
|
28
|
-
* source. gitignored so it never rides along. */
|
|
29
|
-
const MOCK_EDIT_FILE = 'codehere-mock-change.md';
|
|
30
|
-
/** CODEHERE_MOCK fidelity: apply a small, safe on-disk edit so the run has a
|
|
31
|
-
* genuine change — WITHOUT touching real source. Writes only to the dedicated
|
|
32
|
-
* MOCK_EDIT_FILE. Note: that file is gitignored, so INSIDE a git repo the
|
|
33
|
-
* artifacts extractor (git ls-files --others --exclude-standard) won't count it
|
|
34
|
-
* — but verify-all runs the mock in a NON-git sandbox where file counts don't
|
|
35
|
-
* apply, and the polished demo uses seeded sessions, not live mock edits. */
|
|
36
|
-
function materializeEdit() {
|
|
37
|
-
try {
|
|
38
|
-
const target = join(process.cwd(), MOCK_EDIT_FILE);
|
|
39
|
-
const header = '# codehere mock scratch — synthetic edits under CODEHERE_MOCK (safe to delete)\n\n';
|
|
40
|
-
const marker = `codehere(mock): change applied for "${prompt.slice(0, 60).replace(/"/g, "'")}"\n`;
|
|
41
|
-
writeFileSync(target, (existsSync(target) ? readFileSync(target, 'utf-8') : header) + marker);
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
/* best-effort — mock fidelity must never crash the run */
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const agent = argVal('--agent') || 'claude-code';
|
|
48
|
-
let prompt = argVal('--mock-prompt') || argVal('-p') || argVal('--prompt') || argVal('--message') || '';
|
|
49
|
-
// Some agents (codex) pass the prompt via stdin, not an arg. Read it if no arg.
|
|
50
|
-
function readStdin(timeoutMs = 1500) {
|
|
51
|
-
return new Promise((resolve) => {
|
|
52
|
-
let buf = '';
|
|
53
|
-
let done = false;
|
|
54
|
-
const finish = () => {
|
|
55
|
-
if (done)
|
|
56
|
-
return;
|
|
57
|
-
done = true;
|
|
58
|
-
resolve(buf.trim());
|
|
59
|
-
};
|
|
60
|
-
if (process.stdin.isTTY)
|
|
61
|
-
return finish();
|
|
62
|
-
process.stdin.setEncoding('utf-8');
|
|
63
|
-
process.stdin.on('data', (c) => (buf += c));
|
|
64
|
-
process.stdin.on('end', finish);
|
|
65
|
-
setTimeout(finish, timeoutMs);
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
// CODEHERE_MOCK_SLOW multiplies step delays so the "watch it work" running
|
|
69
|
-
// state can actually be observed — for dogfood screenshots and the record-replay
|
|
70
|
-
// webm. Default 1 (fast, for tests). e.g. CODEHERE_MOCK_SLOW=8 ≈ 1s/step.
|
|
71
|
-
const SLOW = Math.max(1, Number(process.env.CODEHERE_MOCK_SLOW) || 1);
|
|
72
|
-
const sleep = (ms) => new Promise((r) => setTimeout(r, ms * SLOW));
|
|
73
|
-
const out = (o) => process.stdout.write(JSON.stringify(o) + '\n');
|
|
74
|
-
// Mock-currency rule: every agent emits token usage in ITS vendor's exact
|
|
75
|
-
// shape, so each adapter's cost-parse branch runs under CODEHERE_MOCK instead
|
|
76
|
-
// of being dead-until-a-real-run. Small fixed values → the session cost
|
|
77
|
-
// estimate is deterministic and non-zero under mock.
|
|
78
|
-
const MOCK_TOKENS = { input: 1200, output: 800 };
|
|
79
|
-
// Derive a few plausible steps from the prompt. Heuristic, not modeled — enough
|
|
80
|
-
// for the execution path to produce real steps/artifacts without an API call.
|
|
81
|
-
function plannedSteps(p) {
|
|
82
|
-
const lc = p.toLowerCase();
|
|
83
|
-
const file = MOCK_EDIT_FILE;
|
|
84
|
-
const steps = [
|
|
85
|
-
{ tool: 'Read', input: { file_path: 'REPO_MAP.md' }, result: 'context loaded · 84 files indexed' },
|
|
86
|
-
{ tool: 'Edit', input: { file_path: file }, result: '+' + (20 + (p.length % 90)) + ' lines · change applied' },
|
|
87
|
-
];
|
|
88
|
-
if (/test|spec/.test(lc))
|
|
89
|
-
steps.push({ tool: 'Bash', input: { command: 'npm test' }, result: 'tests passed' });
|
|
90
|
-
else
|
|
91
|
-
steps.push({ tool: 'Bash', input: { command: 'npm run build' }, result: 'build clean' });
|
|
92
|
-
return steps;
|
|
93
|
-
}
|
|
94
|
-
/** The wrap-up say every real agent emits before its result. The mock never
|
|
95
|
-
* did, so a mock report's only prose was the "On it" ack and every glance
|
|
96
|
-
* led with narration instead of the finding (journey-QA 2026-07-06).
|
|
97
|
-
* Finding first, in the same artifacts plannedSteps claims. */
|
|
98
|
-
function wrapUpText(steps) {
|
|
99
|
-
const edit = steps.find((s) => s.tool === 'Edit');
|
|
100
|
-
const check = steps.find((s) => s.tool === 'Bash');
|
|
101
|
-
const wrote = edit
|
|
102
|
-
? 'Wrote the change to ' + String(edit.input.file_path) + ' (' + edit.result.split(' ·')[0] + ')'
|
|
103
|
-
: 'No file changes';
|
|
104
|
-
const checked = check ? String(check.input.command) + ' — ' + check.result : '';
|
|
105
|
-
return wrote + (checked ? '; ' + checked : '') + '. (mock · no API spend)';
|
|
106
|
-
}
|
|
107
|
-
async function runClaudeCode() {
|
|
108
|
-
const resumeId = argVal('--resume');
|
|
109
|
-
const sid = resumeId || 'mock-' + Math.random().toString(36).slice(2, 10);
|
|
110
|
-
out({
|
|
111
|
-
type: 'system',
|
|
112
|
-
subtype: 'init',
|
|
113
|
-
session_id: sid,
|
|
114
|
-
tools: ['Read', 'Edit', 'Bash', 'AskUserQuestion'],
|
|
115
|
-
model: 'mock',
|
|
116
|
-
});
|
|
117
|
-
await sleep(120);
|
|
118
|
-
// Continuation (answering a question / a follow-up): acknowledge + do the work.
|
|
119
|
-
if (resumeId) {
|
|
120
|
-
const ans = prompt.replace(/^[\s\S]*?My answer:\s*/i, '').trim() || prompt;
|
|
121
|
-
out({
|
|
122
|
-
type: 'assistant',
|
|
123
|
-
message: {
|
|
124
|
-
content: [{ type: 'thinking', thinking: 'The user chose: ' + ans + '. I will implement that path now.' }],
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
await sleep(160);
|
|
128
|
-
out({
|
|
129
|
-
type: 'assistant',
|
|
130
|
-
message: { content: [{ type: 'text', text: 'Got it — going with **' + ans + '**. Implementing now.' }] },
|
|
131
|
-
});
|
|
132
|
-
await sleep(160);
|
|
133
|
-
out({
|
|
134
|
-
type: 'assistant',
|
|
135
|
-
message: { content: [{ type: 'tool_use', id: 'r0', name: 'Edit', input: { file_path: MOCK_EDIT_FILE } }] },
|
|
136
|
-
});
|
|
137
|
-
await sleep(160);
|
|
138
|
-
out({
|
|
139
|
-
type: 'user',
|
|
140
|
-
message: {
|
|
141
|
-
content: [
|
|
142
|
-
{ type: 'tool_result', tool_use_id: 'r0', content: '+18 lines · applied your choice', is_error: false },
|
|
143
|
-
],
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
await sleep(140);
|
|
147
|
-
out({
|
|
148
|
-
type: 'result',
|
|
149
|
-
subtype: 'success',
|
|
150
|
-
session_id: sid,
|
|
151
|
-
result: 'Done — applied your answer (' + ans + ').',
|
|
152
|
-
usage: { input_tokens: MOCK_TOKENS.input, output_tokens: MOCK_TOKENS.output },
|
|
153
|
-
});
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
out({ type: 'assistant', message: { content: [{ type: 'text', text: 'On it — ' + prompt }] } });
|
|
157
|
-
// Ambiguous prompt → ask the user, then pause (the headless tool can't be
|
|
158
|
-
// answered, so the turn ends; codehere surfaces the card + resumes on answer).
|
|
159
|
-
if (/\bask\b|which|approach|prefer|option|client|server/.test(prompt.toLowerCase())) {
|
|
160
|
-
await sleep(160);
|
|
161
|
-
out({
|
|
162
|
-
type: 'assistant',
|
|
163
|
-
message: {
|
|
164
|
-
content: [
|
|
165
|
-
{
|
|
166
|
-
type: 'tool_use',
|
|
167
|
-
id: 'tu_ask',
|
|
168
|
-
name: 'AskUserQuestion',
|
|
169
|
-
input: {
|
|
170
|
-
questions: [
|
|
171
|
-
{
|
|
172
|
-
question: 'Which approach should I use?',
|
|
173
|
-
header: 'Approach',
|
|
174
|
-
options: [
|
|
175
|
-
{ label: 'Client-side only', description: 'fast, no backend changes' },
|
|
176
|
-
{ label: 'Client + server', description: 'safer — validates on the server too' },
|
|
177
|
-
],
|
|
178
|
-
},
|
|
179
|
-
],
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
],
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
await sleep(120);
|
|
186
|
-
out({
|
|
187
|
-
type: 'user',
|
|
188
|
-
message: {
|
|
189
|
-
content: [{ type: 'tool_result', tool_use_id: 'tu_ask', is_error: true, content: 'awaiting your answer' }],
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
await sleep(120);
|
|
193
|
-
out({
|
|
194
|
-
type: 'result',
|
|
195
|
-
subtype: 'success',
|
|
196
|
-
session_id: sid,
|
|
197
|
-
result: 'Waiting for your answer to continue.',
|
|
198
|
-
usage: { input_tokens: MOCK_TOKENS.input, output_tokens: MOCK_TOKENS.output },
|
|
199
|
-
});
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const steps = plannedSteps(prompt);
|
|
203
|
-
for (let i = 0; i < steps.length; i++) {
|
|
204
|
-
const s = steps[i];
|
|
205
|
-
const id = 'tu_' + i;
|
|
206
|
-
await sleep(180);
|
|
207
|
-
out({ type: 'assistant', message: { content: [{ type: 'tool_use', id, name: s.tool, input: s.input }] } });
|
|
208
|
-
await sleep(160);
|
|
209
|
-
out({
|
|
210
|
-
type: 'user',
|
|
211
|
-
message: { content: [{ type: 'tool_result', tool_use_id: id, content: s.result, is_error: false }] },
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
await sleep(140);
|
|
215
|
-
// The wrap-up say (real claude always emits one) — the report leads with it.
|
|
216
|
-
out({ type: 'assistant', message: { content: [{ type: 'text', text: wrapUpText(steps) }] } });
|
|
217
|
-
await sleep(120);
|
|
218
|
-
// Real claude stream-json carries the session's usage totals on the final
|
|
219
|
-
// `result` event (input_tokens / output_tokens / cache_*_input_tokens).
|
|
220
|
-
out({
|
|
221
|
-
type: 'result',
|
|
222
|
-
subtype: 'success',
|
|
223
|
-
session_id: sid,
|
|
224
|
-
result: 'Completed (mock): ' + prompt + '. ' + steps.length + ' steps · no API spend.',
|
|
225
|
-
usage: { input_tokens: MOCK_TOKENS.input, output_tokens: MOCK_TOKENS.output },
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
// codex exec --json format · thread.started → item.completed events → turn.completed
|
|
229
|
-
async function runCodex() {
|
|
230
|
-
const tid = 'mock-thread-' + Math.random().toString(36).slice(2, 8);
|
|
231
|
-
out({ type: 'thread.started', thread_id: tid });
|
|
232
|
-
await sleep(120);
|
|
233
|
-
// codex puts `item` at the TOP LEVEL of the event (sibling of type), not nested.
|
|
234
|
-
out({ type: 'item.completed', item: { type: 'agent_message', text: 'On it — ' + prompt } });
|
|
235
|
-
// Representative extra item types codex emits (so the timeline parser is exercised):
|
|
236
|
-
// a web_search when the task implies lookup, an mcp_tool_call when it implies an integration.
|
|
237
|
-
const lc = prompt.toLowerCase();
|
|
238
|
-
if (/search|find|research|look ?up|latest|docs?\b/.test(lc)) {
|
|
239
|
-
await sleep(120);
|
|
240
|
-
out({ type: 'item.completed', item: { type: 'web_search', query: prompt.slice(0, 60) } });
|
|
241
|
-
}
|
|
242
|
-
if (/linear|github|jira|figma|mcp|issue|ticket/.test(lc)) {
|
|
243
|
-
await sleep(120);
|
|
244
|
-
out({
|
|
245
|
-
type: 'item.completed',
|
|
246
|
-
item: { type: 'mcp_tool_call', server: 'linear', tool: 'get_issue', arguments: { id: 'INFRA-247' } },
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
const steps = plannedSteps(prompt);
|
|
250
|
-
for (const s of steps) {
|
|
251
|
-
await sleep(170);
|
|
252
|
-
if (s.tool === 'Bash') {
|
|
253
|
-
out({
|
|
254
|
-
type: 'item.completed',
|
|
255
|
-
item: {
|
|
256
|
-
type: 'command_execution',
|
|
257
|
-
command: String(s.input.command),
|
|
258
|
-
aggregated_output: s.result,
|
|
259
|
-
exit_code: 0,
|
|
260
|
-
status: 'completed',
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
const kind = s.tool === 'Read' ? 'read' : 'update';
|
|
266
|
-
out({
|
|
267
|
-
type: 'item.completed',
|
|
268
|
-
item: { type: 'file_change', changes: [{ path: String(s.input.file_path), kind }] },
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
await sleep(120);
|
|
273
|
-
out({ type: 'turn.completed', usage: { input_tokens: 1200, output_tokens: 340 } });
|
|
274
|
-
out({ type: 'item.completed', item: { type: 'agent_message', text: wrapUpText(steps) } });
|
|
275
|
-
}
|
|
276
|
-
// aider · plain-text stdout · "Applied edit to <p>" + "Running <cmd>"
|
|
277
|
-
async function runAider() {
|
|
278
|
-
process.stdout.write('Aider v0.x (mock)\n');
|
|
279
|
-
const steps = plannedSteps(prompt);
|
|
280
|
-
// Real aider narrates BEFORE its edits/commands (its prose precedes the
|
|
281
|
-
// "Applied edit"/"Running" lines; nothing prose-shaped follows the last
|
|
282
|
-
// command — the adapter attributes post-Running lines to that command's
|
|
283
|
-
// output). Mock-currency: same order, so the say capture sees the finding.
|
|
284
|
-
await sleep(140);
|
|
285
|
-
process.stdout.write(wrapUpText(steps).replace(/^Wrote the change to/, 'I will write the change to') + '\n');
|
|
286
|
-
for (const s of steps) {
|
|
287
|
-
await sleep(170);
|
|
288
|
-
if (s.tool === 'Bash')
|
|
289
|
-
process.stdout.write('Running ' + String(s.input.command) + '\n' + s.result + '\n');
|
|
290
|
-
else if (s.tool === 'Edit')
|
|
291
|
-
process.stdout.write('Applied edit to ' + String(s.input.file_path) + '\n');
|
|
292
|
-
else
|
|
293
|
-
process.stdout.write(String(s.input.file_path) + '\n'); // read → plain mention
|
|
294
|
-
}
|
|
295
|
-
await sleep(120);
|
|
296
|
-
// Real aider prints a cost summary line at turn end; the adapter's token
|
|
297
|
-
// extraction parses exactly this "Tokens: Nk sent, N received" shape.
|
|
298
|
-
process.stdout.write('Tokens: 1.2k sent, 800 received. Cost: $0.0046 message, $0.0046 session.\n');
|
|
299
|
-
}
|
|
300
|
-
// gemini · JSON tool_use / tool_result (tool_id, tool_name, parameters).
|
|
301
|
-
// Narration matches the REAL gemini-cli stream: `message` events with
|
|
302
|
-
// role:'assistant' + delta:true chunks (verified against gemini-cli 0.39.1 —
|
|
303
|
-
// assistant messages are ALWAYS delta'd; a `content` event type doesn't
|
|
304
|
-
// exist). Mock-currency rule: the mock emits what the real CLI emits, or
|
|
305
|
-
// mock runs silently exercise dead branches (this gap hid the no-say bug
|
|
306
|
-
// that made every real gemini report degrade to the deterministic fallback).
|
|
307
|
-
async function runGemini() {
|
|
308
|
-
out({ type: 'session', session_id: 'mock-gem-' + Math.random().toString(36).slice(2, 8) });
|
|
309
|
-
await sleep(120);
|
|
310
|
-
out({ type: 'message', role: 'assistant', content: 'Working on it (mock): ', delta: true });
|
|
311
|
-
out({ type: 'message', role: 'assistant', content: prompt.slice(0, 60), delta: true });
|
|
312
|
-
const steps = plannedSteps(prompt);
|
|
313
|
-
for (let i = 0; i < steps.length; i++) {
|
|
314
|
-
const s = steps[i];
|
|
315
|
-
const id = 'g' + i;
|
|
316
|
-
const name = s.tool === 'Read' ? 'read_file' : s.tool === 'Edit' ? 'edit_file' : 'run_shell_command';
|
|
317
|
-
await sleep(170);
|
|
318
|
-
out({ type: 'tool_use', tool_id: id, tool_name: name, parameters: s.input });
|
|
319
|
-
await sleep(150);
|
|
320
|
-
out({ type: 'tool_result', tool_id: id, output: s.result });
|
|
321
|
-
}
|
|
322
|
-
await sleep(120);
|
|
323
|
-
out({ type: 'message', role: 'assistant', content: wrapUpText(steps), delta: true });
|
|
324
|
-
// Real gemini carries token usage ONLY on the final success `result` event,
|
|
325
|
-
// under `stats` (the adapter reads input_tokens/output_tokens/cached).
|
|
326
|
-
out({
|
|
327
|
-
type: 'result',
|
|
328
|
-
status: 'success',
|
|
329
|
-
stats: {
|
|
330
|
-
total_tokens: MOCK_TOKENS.input + MOCK_TOKENS.output,
|
|
331
|
-
input_tokens: MOCK_TOKENS.input,
|
|
332
|
-
output_tokens: MOCK_TOKENS.output,
|
|
333
|
-
cached: 0,
|
|
334
|
-
},
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
// opencode · JSON tool_use with part:{tool,state:{input,output,status}}
|
|
338
|
-
async function runOpencode() {
|
|
339
|
-
const steps = plannedSteps(prompt);
|
|
340
|
-
for (const s of steps) {
|
|
341
|
-
const tool = s.tool === 'Read' ? 'read' : s.tool === 'Edit' ? 'edit' : 'bash';
|
|
342
|
-
await sleep(180);
|
|
343
|
-
out({ type: 'tool_use', part: { tool, state: { input: s.input, output: s.result, status: 'completed' } } });
|
|
344
|
-
}
|
|
345
|
-
await sleep(120);
|
|
346
|
-
// Real opencode carries token usage on step_finish events under
|
|
347
|
-
// part.tokens.{input,output,cache.{read,write}}; the adapter sums them.
|
|
348
|
-
out({
|
|
349
|
-
type: 'step_finish',
|
|
350
|
-
part: { tokens: { input: MOCK_TOKENS.input, output: MOCK_TOKENS.output, cache: { read: 0, write: 0 } } },
|
|
351
|
-
});
|
|
352
|
-
// Real opencode carries narrative text in part.text (the adapter's summary
|
|
353
|
-
// extraction and the aggregator's say capture both read that shape) — the
|
|
354
|
-
// prior top-level `text` field was mock drift no real parser ever saw.
|
|
355
|
-
out({ type: 'text', part: { text: wrapUpText(steps) } });
|
|
356
|
-
}
|
|
357
|
-
async function main() {
|
|
358
|
-
if (!prompt)
|
|
359
|
-
prompt = (await readStdin()) || 'task';
|
|
360
|
-
// Apply the real on-disk edit before emitting the run so the artifacts
|
|
361
|
-
// extractor (which diffs at exit) sees a genuine change.
|
|
362
|
-
materializeEdit();
|
|
363
|
-
switch (agent) {
|
|
364
|
-
case 'claude-code':
|
|
365
|
-
case 'claude':
|
|
366
|
-
await runClaudeCode();
|
|
367
|
-
break;
|
|
368
|
-
case 'codex':
|
|
369
|
-
await runCodex();
|
|
370
|
-
break;
|
|
371
|
-
case 'aider':
|
|
372
|
-
await runAider();
|
|
373
|
-
break;
|
|
374
|
-
case 'gemini':
|
|
375
|
-
await runGemini();
|
|
376
|
-
break;
|
|
377
|
-
case 'opencode':
|
|
378
|
-
await runOpencode();
|
|
379
|
-
break;
|
|
380
|
-
default:
|
|
381
|
-
// Other agents' formats land here as their adapters get wired.
|
|
382
|
-
process.stderr.write('mock-agent-repl: agent "' + agent + '" not yet mocked\n');
|
|
383
|
-
out({ type: 'result', subtype: 'success', result: 'mock stub for ' + agent });
|
|
384
|
-
}
|
|
385
|
-
process.exit(0);
|
|
386
|
-
}
|
|
387
|
-
void main();
|
|
388
|
-
//# sourceMappingURL=mock-agent-repl.js.map
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock codex app-server · speaks the real app-server JSON-RPC protocol
|
|
3
|
-
* (newline-delimited over stdio) so the codehere ControlSurface can be built +
|
|
4
|
-
* tested WITHOUT real codex (rate-limited until 2026-05-26) and zero API spend.
|
|
5
|
-
*
|
|
6
|
-
* Subset for remote-control inject: initialize · thread/start · turn/start
|
|
7
|
-
* (running turn emitting items) · turn/steer (inject mid-turn) · turn/interrupt.
|
|
8
|
-
* Schema source: `codex app-server generate-json-schema` (dumped 2026-05-25).
|
|
9
|
-
*
|
|
10
|
-
* Runs as a subprocess (node dist/.../mock-codex-app-server.js). Production code
|
|
11
|
-
* never imports it; only CODEHERE_MOCK spawns it.
|
|
12
|
-
*/
|
|
13
|
-
import { createInterface } from 'readline';
|
|
14
|
-
const send = (o) => void process.stdout.write(JSON.stringify(o) + '\n');
|
|
15
|
-
const reply = (id, result) => send({ jsonrpc: '2.0', id, result });
|
|
16
|
-
const notify = (method, params) => send({ jsonrpc: '2.0', method, params });
|
|
17
|
-
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
18
|
-
let threadSeq = 0;
|
|
19
|
-
let steeredText = null;
|
|
20
|
-
const rl = createInterface({ input: process.stdin });
|
|
21
|
-
rl.on('line', async (line) => {
|
|
22
|
-
const t = line.trim();
|
|
23
|
-
if (!t)
|
|
24
|
-
return;
|
|
25
|
-
let msg;
|
|
26
|
-
try {
|
|
27
|
-
msg = JSON.parse(t);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const { id, method, params } = msg;
|
|
33
|
-
switch (method) {
|
|
34
|
-
case 'initialize':
|
|
35
|
-
reply(id, { userAgent: 'mock-codex-app-server/1.0', platformOs: 'mock', protocolVersion: '1' });
|
|
36
|
-
break;
|
|
37
|
-
case 'thread/start':
|
|
38
|
-
reply(id, { thread_id: 'mock-thread-' + ++threadSeq });
|
|
39
|
-
break;
|
|
40
|
-
case 'turn/start': {
|
|
41
|
-
reply(id, { accepted: true });
|
|
42
|
-
const prompt = String((params?.input ?? params?.prompt ?? 'task'));
|
|
43
|
-
await sleep(120);
|
|
44
|
-
notify('item.completed', { item: { type: 'agent_message', text: 'starting: ' + prompt.slice(0, 80) } });
|
|
45
|
-
// Real codex turns run for seconds; keep a window open so a mid-turn
|
|
46
|
-
// turn/steer (incl. from the web UI, which takes ~1-2s to fire) lands and
|
|
47
|
-
// gets reflected. Poll for a steer ~6s, then finish the turn.
|
|
48
|
-
for (let i = 0; i < 12; i++) {
|
|
49
|
-
await sleep(500);
|
|
50
|
-
if (steeredText) {
|
|
51
|
-
notify('item.completed', { item: { type: 'agent_message', text: 'STEERED mid-turn: ' + steeredText } });
|
|
52
|
-
steeredText = null;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
notify('item.completed', {
|
|
56
|
-
item: { type: 'command_execution', command: 'npm test', exit_code: 0, status: 'completed' },
|
|
57
|
-
});
|
|
58
|
-
notify('turn.completed', { usage: { input_tokens: 900, output_tokens: 210 } });
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
case 'turn/steer':
|
|
62
|
-
steeredText = String((params?.input ?? params?.text ?? params?.message ?? '(empty)'));
|
|
63
|
-
reply(id, { accepted: true });
|
|
64
|
-
break;
|
|
65
|
-
case 'turn/interrupt':
|
|
66
|
-
reply(id, { interrupted: true });
|
|
67
|
-
break;
|
|
68
|
-
default:
|
|
69
|
-
if (id !== undefined)
|
|
70
|
-
reply(id, { ok: true });
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
//# sourceMappingURL=mock-codex-app-server.js.map
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock synthesis · the CODEHERE_MOCK stand-in for the three LLM "narrator"
|
|
3
|
-
* calls (Final Report, mid-task narration, thread title).
|
|
4
|
-
*
|
|
5
|
-
* The agent-spawn seam (resolve-agent-spawn.ts) already mocks the coding agents
|
|
6
|
-
* themselves. But the Final Report / narration / title are SEPARATE `claude`
|
|
7
|
-
* subprocess calls, so under CODEHERE_MOCK they would still hit a real model (or
|
|
8
|
-
* fail) and the headline deliverable would be missing in a demo. These builders
|
|
9
|
-
* produce deterministic, grounded text from the run's own data — zero API spend
|
|
10
|
-
* — so the whole flow (incl. the Final Report + verify cross-check) runs under
|
|
11
|
-
* mock end-to-end.
|
|
12
|
-
*
|
|
13
|
-
* Honest scope: this is demo/dev output, only active when CODEHERE_MOCK=1. It is
|
|
14
|
-
* grounded in the real (mock) run's steps + artifacts so the verifier still
|
|
15
|
-
* cross-checks it the same way it checks a real report.
|
|
16
|
-
*/
|
|
17
|
-
function stepVerbs(steps) {
|
|
18
|
-
const labels = steps
|
|
19
|
-
.filter((s) => s.kind !== 'say')
|
|
20
|
-
.map((s) => s.label)
|
|
21
|
-
.filter(Boolean);
|
|
22
|
-
if (labels.length === 0)
|
|
23
|
-
return 'started the task but recorded no structured steps';
|
|
24
|
-
if (labels.length <= 3)
|
|
25
|
-
return labels.join(', then ');
|
|
26
|
-
return `${labels.slice(0, 3).join(', ')}, and ${labels.length - 3} more step${labels.length - 3 === 1 ? '' : 's'}`;
|
|
27
|
-
}
|
|
28
|
-
/** Build the "files" paragraph so it stays consistent with what the verifier
|
|
29
|
-
* checks against artifacts — same truth rules as the real prompt template. */
|
|
30
|
-
function filesParagraph(artifacts) {
|
|
31
|
-
const files = artifacts?.files ?? [];
|
|
32
|
-
if (artifacts?.noGitTracking) {
|
|
33
|
-
return 'codehere could not track file changes here because this folder is not a git repository, so there is no per-file diff to show.';
|
|
34
|
-
}
|
|
35
|
-
if (files.length === 0) {
|
|
36
|
-
return 'No files were changed.';
|
|
37
|
-
}
|
|
38
|
-
const list = files
|
|
39
|
-
.map((f) => `${f.path} (+${f.added}/-${f.removed}${typeof f.trust === 'number' ? `, trust ${f.trust}` : ''})`)
|
|
40
|
-
.join('; ');
|
|
41
|
-
return `The agent touched ${files.length} file${files.length === 1 ? '' : 's'}: ${list}.`;
|
|
42
|
-
}
|
|
43
|
-
export function mockFinalReport(input) {
|
|
44
|
-
const p1 = `Working on "${input.prompt.slice(0, 120)}", the ${input.agent} agent ${stepVerbs(input.steps)}.`;
|
|
45
|
-
const p2 = filesParagraph(input.artifacts);
|
|
46
|
-
const files = input.artifacts?.files ?? [];
|
|
47
|
-
const tests = input.artifacts?.tests;
|
|
48
|
-
let p3;
|
|
49
|
-
if (tests) {
|
|
50
|
-
p3 = `Tests ran with ${tests.passed} passing${tests.failed ? ` and ${tests.failed} failing` : ''} — ${tests.failed ? 'look at the failures before relying on this' : 'a quick glance at the changed lines is still worth it'}.`;
|
|
51
|
-
}
|
|
52
|
-
else if (files.length > 0) {
|
|
53
|
-
p3 = `Open ${files[0].path} and confirm the change does what you asked before relying on it.`;
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
p3 = 'Nothing to verify on disk; this looks like a read-only session.';
|
|
57
|
-
}
|
|
58
|
-
return { summary: `${p1}\n\n${p2}\n\n${p3}`, generatedAt: Date.now(), durationMs: 8 };
|
|
59
|
-
}
|
|
60
|
-
export function mockNarration(input) {
|
|
61
|
-
const recent = input.steps
|
|
62
|
-
.filter((s) => s.kind !== 'say')
|
|
63
|
-
.slice(-2)
|
|
64
|
-
.map((s) => s.label)
|
|
65
|
-
.filter(Boolean);
|
|
66
|
-
const summary = recent.length > 0
|
|
67
|
-
? `The agent is working through it — most recently: ${recent.join(', then ')}.`
|
|
68
|
-
: 'The agent is getting started on your task.';
|
|
69
|
-
return { summary, durationMs: 5 };
|
|
70
|
-
}
|
|
71
|
-
export function mockTitle(firstPrompt, cwd) {
|
|
72
|
-
const words = firstPrompt
|
|
73
|
-
.replace(/[^a-zA-Z0-9 ]/g, ' ')
|
|
74
|
-
.split(/\s+/)
|
|
75
|
-
.filter(Boolean)
|
|
76
|
-
.slice(0, 6);
|
|
77
|
-
if (words.length >= 2) {
|
|
78
|
-
return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
79
|
-
}
|
|
80
|
-
const seg = cwd.split('/').filter(Boolean).pop() || 'Project';
|
|
81
|
-
return seg.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()) + ' Workspace';
|
|
82
|
-
}
|
|
83
|
-
//# sourceMappingURL=mock-synthesis.js.map
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock spawn seam · the ONE place adapters route through to get mocked.
|
|
3
|
-
*
|
|
4
|
-
* When CODEHERE_MOCK=1, resolveAgentSpawn() swaps the real agent binary for the
|
|
5
|
-
* mock REPL subprocess (node mock-agent-repl.js --agent <id> ...same args). The
|
|
6
|
-
* adapter's spawn/parse path is otherwise untouched — it parses the mock's
|
|
7
|
-
* output exactly as it would the real CLI's. Zero API spend, zero rate limits.
|
|
8
|
-
*
|
|
9
|
-
* Off by default: without the env var it returns the real binary + args verbatim,
|
|
10
|
-
* so production behavior is unchanged.
|
|
11
|
-
*/
|
|
12
|
-
import { fileURLToPath } from 'url';
|
|
13
|
-
import { dirname, join } from 'path';
|
|
14
|
-
export function isMockMode() {
|
|
15
|
-
return process.env.CODEHERE_MOCK === '1' || process.env.CODEHERE_MOCK === 'true';
|
|
16
|
-
}
|
|
17
|
-
const mockReplPath = () => join(dirname(fileURLToPath(import.meta.url)), 'mock-agent-repl.js');
|
|
18
|
-
/**
|
|
19
|
-
* @param agentId stable adapter id (e.g. 'claude-code', 'codex') — tells the
|
|
20
|
-
* mock which CLI output format to emit.
|
|
21
|
-
* @param realBin the real binary the adapter would spawn (e.g. 'claude').
|
|
22
|
-
* @param args the args the adapter would pass.
|
|
23
|
-
* @returns { command, args } to hand to child_process.spawn().
|
|
24
|
-
*/
|
|
25
|
-
export function resolveAgentSpawn(agentId, realBin, args, prompt) {
|
|
26
|
-
if (!isMockMode())
|
|
27
|
-
return { command: realBin, args, mocked: false };
|
|
28
|
-
// Pass the prompt explicitly (agents take it differently: -p / --message /
|
|
29
|
-
// stdin / positional) so the mock doesn't have to guess where it is.
|
|
30
|
-
const promptArgs = prompt ? ['--mock-prompt', prompt] : [];
|
|
31
|
-
return {
|
|
32
|
-
command: process.execPath, // node
|
|
33
|
-
args: [mockReplPath(), '--agent', agentId, ...promptArgs, ...args],
|
|
34
|
-
mocked: true,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=resolve-agent-spawn.js.map
|