myshell-tools 1.0.0 → 2.0.0
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/CHANGELOG.md +44 -69
- package/LICENSE +21 -21
- package/README.md +178 -318
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +130 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/cost.d.ts +36 -0
- package/dist/commands/cost.js +103 -0
- package/dist/commands/cost.js.map +1 -0
- package/dist/commands/doctor.d.ts +36 -0
- package/dist/commands/doctor.js +115 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/login.d.ts +20 -0
- package/dist/commands/login.js +60 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/core/assess.d.ts +25 -0
- package/dist/core/assess.js +142 -0
- package/dist/core/assess.js.map +1 -0
- package/dist/core/classify.d.ts +19 -0
- package/dist/core/classify.js +80 -0
- package/dist/core/classify.js.map +1 -0
- package/dist/core/escalate.d.ts +32 -0
- package/dist/core/escalate.js +57 -0
- package/dist/core/escalate.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +12 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/orchestrate.d.ts +42 -0
- package/dist/core/orchestrate.js +439 -0
- package/dist/core/orchestrate.js.map +1 -0
- package/dist/core/policy.d.ts +9 -0
- package/dist/core/policy.js +27 -0
- package/dist/core/policy.js.map +1 -0
- package/dist/core/prompt.d.ts +26 -0
- package/dist/core/prompt.js +125 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/review.d.ts +46 -0
- package/dist/core/review.js +148 -0
- package/dist/core/review.js.map +1 -0
- package/dist/core/route.d.ts +28 -0
- package/dist/core/route.js +52 -0
- package/dist/core/route.js.map +1 -0
- package/dist/core/types.d.ts +141 -0
- package/dist/core/types.js +14 -0
- package/dist/core/types.js.map +1 -0
- package/dist/infra/atomic.d.ts +53 -0
- package/dist/infra/atomic.js +171 -0
- package/dist/infra/atomic.js.map +1 -0
- package/dist/infra/clock.d.ts +9 -0
- package/dist/infra/clock.js +15 -0
- package/dist/infra/clock.js.map +1 -0
- package/dist/infra/index.d.ts +9 -0
- package/dist/infra/index.js +7 -0
- package/dist/infra/index.js.map +1 -0
- package/dist/infra/ledger.d.ts +49 -0
- package/dist/infra/ledger.js +90 -0
- package/dist/infra/ledger.js.map +1 -0
- package/dist/infra/paths.d.ts +28 -0
- package/dist/infra/paths.js +38 -0
- package/dist/infra/paths.js.map +1 -0
- package/dist/infra/pricing.d.ts +47 -0
- package/dist/infra/pricing.js +151 -0
- package/dist/infra/pricing.js.map +1 -0
- package/dist/infra/session.d.ts +28 -0
- package/dist/infra/session.js +61 -0
- package/dist/infra/session.js.map +1 -0
- package/dist/interface/render.d.ts +27 -0
- package/dist/interface/render.js +134 -0
- package/dist/interface/render.js.map +1 -0
- package/dist/interface/repl.d.ts +23 -0
- package/dist/interface/repl.js +90 -0
- package/dist/interface/repl.js.map +1 -0
- package/dist/interface/run.d.ts +20 -0
- package/dist/interface/run.js +31 -0
- package/dist/interface/run.js.map +1 -0
- package/dist/providers/claude-parse.d.ts +24 -0
- package/dist/providers/claude-parse.js +113 -0
- package/dist/providers/claude-parse.js.map +1 -0
- package/dist/providers/claude.d.ts +45 -0
- package/dist/providers/claude.js +122 -0
- package/dist/providers/claude.js.map +1 -0
- package/dist/providers/codex-parse.d.ts +32 -0
- package/dist/providers/codex-parse.js +145 -0
- package/dist/providers/codex-parse.js.map +1 -0
- package/dist/providers/codex.d.ts +44 -0
- package/dist/providers/codex.js +124 -0
- package/dist/providers/codex.js.map +1 -0
- package/dist/providers/detect.d.ts +49 -0
- package/dist/providers/detect.js +125 -0
- package/dist/providers/detect.js.map +1 -0
- package/dist/providers/errors.d.ts +49 -0
- package/dist/providers/errors.js +189 -0
- package/dist/providers/errors.js.map +1 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.js +7 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/port.d.ts +74 -0
- package/dist/providers/port.js +16 -0
- package/dist/providers/port.js.map +1 -0
- package/dist/providers/registry.d.ts +21 -0
- package/dist/providers/registry.js +34 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/ui/banner.d.ts +19 -0
- package/dist/ui/banner.js +32 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/spinner.d.ts +27 -0
- package/dist/ui/spinner.js +67 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/theme.d.ts +32 -0
- package/dist/ui/theme.js +56 -0
- package/dist/ui/theme.js.map +1 -0
- package/package.json +55 -49
- package/data/orchestrator.json +0 -113
- package/src/auth/recovery.mjs +0 -328
- package/src/auth/refresh.mjs +0 -373
- package/src/chef.mjs +0 -348
- package/src/cli/doctor.mjs +0 -568
- package/src/cli/reset.mjs +0 -447
- package/src/cli/status.mjs +0 -379
- package/src/cli.mjs +0 -429
- package/src/commands/doctor.mjs +0 -375
- package/src/commands/help.mjs +0 -324
- package/src/commands/status.mjs +0 -331
- package/src/monitor/health.mjs +0 -486
- package/src/monitor/performance.mjs +0 -442
- package/src/monitor/report.mjs +0 -535
- package/src/orchestrator/classify.mjs +0 -391
- package/src/orchestrator/confidence.mjs +0 -151
- package/src/orchestrator/handoffs.mjs +0 -231
- package/src/orchestrator/review.mjs +0 -222
- package/src/providers/balance.mjs +0 -201
- package/src/providers/claude.mjs +0 -236
- package/src/providers/codex.mjs +0 -255
- package/src/providers/detect.mjs +0 -185
- package/src/providers/errors.mjs +0 -373
- package/src/providers/select.mjs +0 -162
- package/src/repl-enhanced.mjs +0 -417
- package/src/repl.mjs +0 -321
- package/src/state/archive.mjs +0 -366
- package/src/state/atomic.mjs +0 -116
- package/src/state/cleanup.mjs +0 -440
- package/src/state/recovery.mjs +0 -461
- package/src/state/session.mjs +0 -147
- package/src/ui/errors.mjs +0 -456
- package/src/ui/formatter.mjs +0 -327
- package/src/ui/icons.mjs +0 -318
- package/src/ui/progress.mjs +0 -468
- package/templates/prompts/confidence-format.txt +0 -14
- package/templates/prompts/ic-with-feedback.txt +0 -41
- package/templates/prompts/ic.txt +0 -13
- package/templates/prompts/manager-review.txt +0 -40
- package/templates/prompts/manager.txt +0 -14
- package/templates/prompts/worker.txt +0 -12
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/interface/render.ts — Human-readable event stream renderer.
|
|
3
|
+
*
|
|
4
|
+
* Consumes the AsyncIterable<CoreEvent> produced by orchestrate() and writes
|
|
5
|
+
* a clean, truthful transcript to an OutputSink. All displayed values come
|
|
6
|
+
* directly from CoreEvent data — no fabricated metrics, no hardcoded strings.
|
|
7
|
+
*
|
|
8
|
+
* Honesty Contract: confidence is rendered as a computed percentage or the
|
|
9
|
+
* literal word "unrated" when null. No digit-% literals appear in this file.
|
|
10
|
+
*/
|
|
11
|
+
import { bold, cyan, dim, green, red, yellow } from '../ui/theme.js';
|
|
12
|
+
import { createSpinner } from '../ui/spinner.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Internal helpers
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/**
|
|
17
|
+
* Render a confidence value as a computed percentage string or 'unrated'.
|
|
18
|
+
* No digit-% literal is used here — the percentage is always interpolated
|
|
19
|
+
* from the real numeric value.
|
|
20
|
+
*/
|
|
21
|
+
function renderConfidence(confidence, color) {
|
|
22
|
+
if (confidence === null)
|
|
23
|
+
return dim('unrated', color);
|
|
24
|
+
const pct = Math.round(confidence * 100);
|
|
25
|
+
const str = `${pct}%`;
|
|
26
|
+
if (pct >= 80)
|
|
27
|
+
return green(str, color);
|
|
28
|
+
if (pct >= 50)
|
|
29
|
+
return yellow(str, color);
|
|
30
|
+
return red(str, color);
|
|
31
|
+
}
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// renderStream
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
/**
|
|
36
|
+
* Iterate events from orchestrate() and write a human-readable, truthful
|
|
37
|
+
* transcript to the OutputSink. Returns the success flag and the final event
|
|
38
|
+
* once the stream is exhausted.
|
|
39
|
+
*/
|
|
40
|
+
export async function renderStream(events, out) {
|
|
41
|
+
const c = out.color;
|
|
42
|
+
let finalEvent;
|
|
43
|
+
// Spinner is only used in TTY mode; we create one per tier-start and stop it
|
|
44
|
+
// when the first real output arrives or when tier-done fires.
|
|
45
|
+
const spinner = createSpinner(out);
|
|
46
|
+
let spinnerActive = false;
|
|
47
|
+
function stopSpinner() {
|
|
48
|
+
if (spinnerActive) {
|
|
49
|
+
spinner.stop();
|
|
50
|
+
spinnerActive = false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
for await (const ev of events) {
|
|
54
|
+
switch (ev.type) {
|
|
55
|
+
case 'classified': {
|
|
56
|
+
const cl = ev.classification;
|
|
57
|
+
out.write(cyan(`Classified: ${cl.tier} tier, ${cl.risk} risk`, c) +
|
|
58
|
+
` — ${cl.rationale}\n`);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case 'tier-start': {
|
|
62
|
+
out.write(bold(`▶ ${ev.tier.toUpperCase()} (${ev.provider}/${ev.model}) attempt ${ev.attempt}`, c) +
|
|
63
|
+
`\n`);
|
|
64
|
+
// Start spinner while waiting for the first provider output.
|
|
65
|
+
if (out.isTty) {
|
|
66
|
+
spinner.start(`${ev.tier.toUpperCase()} (${ev.provider}/${ev.model}) working…`);
|
|
67
|
+
spinnerActive = true;
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case 'provider-event': {
|
|
72
|
+
const pe = ev.event;
|
|
73
|
+
if (pe.type === 'text') {
|
|
74
|
+
// First real output — clear the spinner line.
|
|
75
|
+
stopSpinner();
|
|
76
|
+
// Stream the real model output verbatim.
|
|
77
|
+
out.write(pe.delta);
|
|
78
|
+
}
|
|
79
|
+
else if (pe.type === 'tool') {
|
|
80
|
+
stopSpinner();
|
|
81
|
+
out.write(dim(`[tool] ${pe.name} ${pe.phase}`, c) + `\n`);
|
|
82
|
+
}
|
|
83
|
+
else if (pe.type === 'reasoning') {
|
|
84
|
+
stopSpinner();
|
|
85
|
+
out.write(dim(pe.delta, c));
|
|
86
|
+
}
|
|
87
|
+
// 'usage', 'done', 'error' are handled via tier-done / final
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case 'tier-done': {
|
|
91
|
+
stopSpinner();
|
|
92
|
+
const confidenceStr = renderConfidence(ev.confidence, c);
|
|
93
|
+
const costStr = `$${ev.costUsd.toFixed(4)}`;
|
|
94
|
+
const successMark = ev.success ? green('✓', c) : red('✗', c);
|
|
95
|
+
out.write(`\n${successMark} ${bold('tier done', c)} — ` +
|
|
96
|
+
`confidence: ${confidenceStr}, ` +
|
|
97
|
+
`cost: ${costStr}, ` +
|
|
98
|
+
`duration: ${ev.durationMs}ms\n`);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case 'escalate': {
|
|
102
|
+
out.write(yellow(`↑ Escalating ${ev.from} → ${ev.to}: ${ev.reason}`, c) + `\n`);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case 'notice': {
|
|
106
|
+
const prefix = ev.level === 'error' ? red('[error]', c) :
|
|
107
|
+
ev.level === 'warn' ? yellow('[warn]', c) :
|
|
108
|
+
dim('[info]', c);
|
|
109
|
+
out.write(`${prefix} ${ev.message}\n`);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case 'final': {
|
|
113
|
+
finalEvent = ev;
|
|
114
|
+
const successLabel = ev.success
|
|
115
|
+
? bold(green('Success', c), c)
|
|
116
|
+
: bold(red('Failed', c), c);
|
|
117
|
+
const costStr = `$${ev.totalCostUsd.toFixed(4)}`;
|
|
118
|
+
out.write(`\n${successLabel} — ` +
|
|
119
|
+
`tier: ${ev.tier}, ` +
|
|
120
|
+
`cost: ${costStr}, ` +
|
|
121
|
+
`attempts: ${ev.attempts}, ` +
|
|
122
|
+
`session: ${ev.sessionId}\n`);
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Safety: ensure spinner is stopped if stream ended without a terminal event.
|
|
128
|
+
stopSpinner();
|
|
129
|
+
if (finalEvent !== undefined) {
|
|
130
|
+
return { success: finalEvent.success, final: finalEvent };
|
|
131
|
+
}
|
|
132
|
+
return { success: false };
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/interface/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/interface/repl.ts — interactive REPL for myshell-tools.
|
|
3
|
+
*
|
|
4
|
+
* Presents a `myshell-tools> ` prompt, dispatching each line as a task via runTask().
|
|
5
|
+
* Built-in commands: /exit, /quit, /help.
|
|
6
|
+
*
|
|
7
|
+
* SIGINT behaviour:
|
|
8
|
+
* - If a task is in flight → abort it and keep the REPL alive.
|
|
9
|
+
* - If idle → close the readline interface and resolve.
|
|
10
|
+
*
|
|
11
|
+
* Never calls process.exit() — that responsibility belongs exclusively to
|
|
12
|
+
* src/cli.ts.
|
|
13
|
+
*/
|
|
14
|
+
import type { OrchestrateDeps } from '../core/types.js';
|
|
15
|
+
import type { OutputSink } from './render.js';
|
|
16
|
+
/**
|
|
17
|
+
* Start an interactive REPL session. Resolves when the user exits or when the
|
|
18
|
+
* readline interface is closed.
|
|
19
|
+
*
|
|
20
|
+
* @param deps - Injected orchestration dependencies.
|
|
21
|
+
* @param out - Where rendered output is written.
|
|
22
|
+
*/
|
|
23
|
+
export declare function startRepl(deps: OrchestrateDeps, out: OutputSink): Promise<void>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/interface/repl.ts — interactive REPL for myshell-tools.
|
|
3
|
+
*
|
|
4
|
+
* Presents a `myshell-tools> ` prompt, dispatching each line as a task via runTask().
|
|
5
|
+
* Built-in commands: /exit, /quit, /help.
|
|
6
|
+
*
|
|
7
|
+
* SIGINT behaviour:
|
|
8
|
+
* - If a task is in flight → abort it and keep the REPL alive.
|
|
9
|
+
* - If idle → close the readline interface and resolve.
|
|
10
|
+
*
|
|
11
|
+
* Never calls process.exit() — that responsibility belongs exclusively to
|
|
12
|
+
* src/cli.ts.
|
|
13
|
+
*/
|
|
14
|
+
import readline from 'node:readline';
|
|
15
|
+
import { runTask } from './run.js';
|
|
16
|
+
const REPL_HELP = `\
|
|
17
|
+
Available commands:
|
|
18
|
+
/help Show this help message
|
|
19
|
+
/exit Exit the REPL
|
|
20
|
+
/quit Exit the REPL
|
|
21
|
+
<task> Run a task (any other non-empty line)
|
|
22
|
+
`;
|
|
23
|
+
/**
|
|
24
|
+
* Start an interactive REPL session. Resolves when the user exits or when the
|
|
25
|
+
* readline interface is closed.
|
|
26
|
+
*
|
|
27
|
+
* @param deps - Injected orchestration dependencies.
|
|
28
|
+
* @param out - Where rendered output is written.
|
|
29
|
+
*/
|
|
30
|
+
export async function startRepl(deps, out) {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
const rl = readline.createInterface({
|
|
33
|
+
input: process.stdin,
|
|
34
|
+
output: process.stdout,
|
|
35
|
+
prompt: 'myshell-tools> ',
|
|
36
|
+
terminal: out.isTty,
|
|
37
|
+
});
|
|
38
|
+
// Track the in-flight AbortController so SIGINT can cancel it.
|
|
39
|
+
let currentAc = null;
|
|
40
|
+
rl.on('SIGINT', () => {
|
|
41
|
+
if (currentAc !== null) {
|
|
42
|
+
// Task in flight — abort it, keep the REPL alive.
|
|
43
|
+
currentAc.abort();
|
|
44
|
+
out.write('\n[warn] Task cancelled.\n');
|
|
45
|
+
rl.prompt();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Idle — close and resolve.
|
|
49
|
+
out.write('\n');
|
|
50
|
+
rl.close();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
rl.on('close', () => {
|
|
54
|
+
resolve();
|
|
55
|
+
});
|
|
56
|
+
rl.on('line', (rawLine) => {
|
|
57
|
+
const line = rawLine.trim();
|
|
58
|
+
if (line.length === 0) {
|
|
59
|
+
rl.prompt();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (line === '/exit' || line === '/quit') {
|
|
63
|
+
rl.close();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (line === '/help') {
|
|
67
|
+
out.write(REPL_HELP);
|
|
68
|
+
rl.prompt();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// Pause readline while the task runs to avoid interleaved output.
|
|
72
|
+
rl.pause();
|
|
73
|
+
const ac = new AbortController();
|
|
74
|
+
currentAc = ac;
|
|
75
|
+
runTask(line, deps, out, ac.signal).then(() => {
|
|
76
|
+
currentAc = null;
|
|
77
|
+
rl.resume();
|
|
78
|
+
rl.prompt();
|
|
79
|
+
}).catch((err) => {
|
|
80
|
+
currentAc = null;
|
|
81
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
82
|
+
out.write(`[error] ${msg}\n`);
|
|
83
|
+
rl.resume();
|
|
84
|
+
rl.prompt();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
rl.prompt();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=repl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repl.js","sourceRoot":"","sources":["../../src/interface/repl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,QAAQ,MAAM,eAAe,CAAC;AAGrC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,MAAM,SAAS,GAAG;;;;;;CAMjB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAqB,EAAE,GAAe;IACpE,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACnC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;YAClC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,iBAAiB;YACzB,QAAQ,EAAE,GAAG,CAAC,KAAK;SACpB,CAAC,CAAC;QAEH,+DAA+D;QAC/D,IAAI,SAAS,GAA2B,IAAI,CAAC;QAE7C,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACnB,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvB,kDAAkD;gBAClD,SAAS,CAAC,KAAK,EAAE,CAAC;gBAClB,GAAG,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;gBACxC,EAAE,CAAC,MAAM,EAAE,CAAC;YACd,CAAC;iBAAM,CAAC;gBACN,4BAA4B;gBAC5B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAChB,EAAE,CAAC,KAAK,EAAE,CAAC;YACb,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAClB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAe,EAAE,EAAE;YAChC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAE5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,EAAE,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;YAED,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBACzC,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO;YACT,CAAC;YAED,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBACrB,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACrB,EAAE,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;YAED,kEAAkE;YAClE,EAAE,CAAC,KAAK,EAAE,CAAC;YAEX,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;YACjC,SAAS,GAAG,EAAE,CAAC;YAEf,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC5C,SAAS,GAAG,IAAI,CAAC;gBACjB,EAAE,CAAC,MAAM,EAAE,CAAC;gBACZ,EAAE,CAAC,MAAM,EAAE,CAAC;YACd,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;gBACxB,SAAS,GAAG,IAAI,CAAC;gBACjB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7D,GAAG,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;gBAC9B,EAAE,CAAC,MAAM,EAAE,CAAC;gBACZ,EAAE,CAAC,MAAM,EAAE,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,MAAM,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/interface/run.ts — single-task runner for the CLI `run` command.
|
|
3
|
+
*
|
|
4
|
+
* Bridges the orchestration core to the terminal output: calls orchestrate(),
|
|
5
|
+
* pipes the event stream through renderStream(), and returns a numeric exit
|
|
6
|
+
* code so that src/cli.ts — the only file allowed to call process.exit() —
|
|
7
|
+
* can terminate the process appropriately.
|
|
8
|
+
*/
|
|
9
|
+
import type { OrchestrateDeps } from '../core/types.js';
|
|
10
|
+
import type { OutputSink } from './render.js';
|
|
11
|
+
/**
|
|
12
|
+
* Run a single task end-to-end, rendering every CoreEvent to the OutputSink.
|
|
13
|
+
*
|
|
14
|
+
* @param task - The raw user task description.
|
|
15
|
+
* @param deps - Injected orchestration dependencies.
|
|
16
|
+
* @param out - Where rendered output is written.
|
|
17
|
+
* @param signal - AbortSignal; abort to cancel the in-flight task.
|
|
18
|
+
* @returns 0 on success, 1 on failure or error.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runTask(task: string, deps: OrchestrateDeps, out: OutputSink, signal: AbortSignal): Promise<number>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/interface/run.ts — single-task runner for the CLI `run` command.
|
|
3
|
+
*
|
|
4
|
+
* Bridges the orchestration core to the terminal output: calls orchestrate(),
|
|
5
|
+
* pipes the event stream through renderStream(), and returns a numeric exit
|
|
6
|
+
* code so that src/cli.ts — the only file allowed to call process.exit() —
|
|
7
|
+
* can terminate the process appropriately.
|
|
8
|
+
*/
|
|
9
|
+
import { orchestrate } from '../core/orchestrate.js';
|
|
10
|
+
import { renderStream } from './render.js';
|
|
11
|
+
/**
|
|
12
|
+
* Run a single task end-to-end, rendering every CoreEvent to the OutputSink.
|
|
13
|
+
*
|
|
14
|
+
* @param task - The raw user task description.
|
|
15
|
+
* @param deps - Injected orchestration dependencies.
|
|
16
|
+
* @param out - Where rendered output is written.
|
|
17
|
+
* @param signal - AbortSignal; abort to cancel the in-flight task.
|
|
18
|
+
* @returns 0 on success, 1 on failure or error.
|
|
19
|
+
*/
|
|
20
|
+
export async function runTask(task, deps, out, signal) {
|
|
21
|
+
try {
|
|
22
|
+
const result = await renderStream(orchestrate(task, deps, signal), out);
|
|
23
|
+
return result.success ? 0 : 1;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27
|
+
out.write(`[error] ${msg}\n`);
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/interface/run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,IAAY,EACZ,IAAqB,EACrB,GAAe,EACf,MAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;QACxE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,GAAG,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;QAC9B,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/providers/claude-parse.ts — pure JSONL parser for `claude -p --output-format stream-json`.
|
|
3
|
+
*
|
|
4
|
+
* PURE MODULE: no I/O, no execa, no side effects. All logic is a function from
|
|
5
|
+
* string → ProviderEvent[]. This is the hermetic, fixture-tested heart of the
|
|
6
|
+
* Claude adapter.
|
|
7
|
+
*
|
|
8
|
+
* Stream-json schema (matched from the captured fixture):
|
|
9
|
+
* - rate_limit_event → emit nothing
|
|
10
|
+
* - system/init → emit nothing
|
|
11
|
+
* - assistant → text/tool events per content[] item
|
|
12
|
+
* - result/success → usage event + done event
|
|
13
|
+
* - result/is_error or !success → usage event + error event
|
|
14
|
+
* - unparseable line → emit nothing (skip)
|
|
15
|
+
*/
|
|
16
|
+
import type { ProviderEvent } from './port.js';
|
|
17
|
+
/**
|
|
18
|
+
* Parse a single JSONL line from `claude --output-format stream-json` stdout.
|
|
19
|
+
*
|
|
20
|
+
* Returns 0 or more {@link ProviderEvent}s. Returns an empty array for:
|
|
21
|
+
* - Lines that fail JSON.parse
|
|
22
|
+
* - Event types we intentionally ignore (rate_limit_event, system/init)
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseClaudeLine(line: string): ProviderEvent[];
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/providers/claude-parse.ts — pure JSONL parser for `claude -p --output-format stream-json`.
|
|
3
|
+
*
|
|
4
|
+
* PURE MODULE: no I/O, no execa, no side effects. All logic is a function from
|
|
5
|
+
* string → ProviderEvent[]. This is the hermetic, fixture-tested heart of the
|
|
6
|
+
* Claude adapter.
|
|
7
|
+
*
|
|
8
|
+
* Stream-json schema (matched from the captured fixture):
|
|
9
|
+
* - rate_limit_event → emit nothing
|
|
10
|
+
* - system/init → emit nothing
|
|
11
|
+
* - assistant → text/tool events per content[] item
|
|
12
|
+
* - result/success → usage event + done event
|
|
13
|
+
* - result/is_error or !success → usage event + error event
|
|
14
|
+
* - unparseable line → emit nothing (skip)
|
|
15
|
+
*/
|
|
16
|
+
import { classifyError } from './errors.js';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Helpers
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
function mapUsage(u) {
|
|
21
|
+
const base = {
|
|
22
|
+
inputTokens: u.input_tokens ?? 0,
|
|
23
|
+
outputTokens: u.output_tokens ?? 0,
|
|
24
|
+
};
|
|
25
|
+
// exactOptionalPropertyTypes: only include cachedInputTokens if it is a
|
|
26
|
+
// number — omit the key entirely otherwise.
|
|
27
|
+
if (typeof u.cache_read_input_tokens === 'number') {
|
|
28
|
+
return { ...base, cachedInputTokens: u.cache_read_input_tokens };
|
|
29
|
+
}
|
|
30
|
+
return base;
|
|
31
|
+
}
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Public API
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
/**
|
|
36
|
+
* Parse a single JSONL line from `claude --output-format stream-json` stdout.
|
|
37
|
+
*
|
|
38
|
+
* Returns 0 or more {@link ProviderEvent}s. Returns an empty array for:
|
|
39
|
+
* - Lines that fail JSON.parse
|
|
40
|
+
* - Event types we intentionally ignore (rate_limit_event, system/init)
|
|
41
|
+
*/
|
|
42
|
+
export function parseClaudeLine(line) {
|
|
43
|
+
const trimmed = line.trim();
|
|
44
|
+
if (!trimmed)
|
|
45
|
+
return [];
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(trimmed);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
54
|
+
return [];
|
|
55
|
+
const obj = parsed;
|
|
56
|
+
const eventType = obj['type'];
|
|
57
|
+
// -------------------------------------------------------------------------
|
|
58
|
+
// rate_limit_event / system — emit nothing
|
|
59
|
+
// -------------------------------------------------------------------------
|
|
60
|
+
if (eventType === 'rate_limit_event' || eventType === 'system') {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
// -------------------------------------------------------------------------
|
|
64
|
+
// assistant — emit text/tool events per content[] item
|
|
65
|
+
// Do NOT emit usage from assistant events (it's intermediate).
|
|
66
|
+
// -------------------------------------------------------------------------
|
|
67
|
+
if (eventType === 'assistant') {
|
|
68
|
+
const ev = parsed;
|
|
69
|
+
const events = [];
|
|
70
|
+
for (const item of ev.message.content) {
|
|
71
|
+
if (item.type === 'text') {
|
|
72
|
+
const textItem = item;
|
|
73
|
+
events.push({ type: 'text', delta: textItem.text });
|
|
74
|
+
}
|
|
75
|
+
else if (item.type === 'tool_use') {
|
|
76
|
+
const toolItem = item;
|
|
77
|
+
events.push({ type: 'tool', name: toolItem.name, phase: 'start' });
|
|
78
|
+
}
|
|
79
|
+
// Other content types: ignore
|
|
80
|
+
}
|
|
81
|
+
return events;
|
|
82
|
+
}
|
|
83
|
+
// -------------------------------------------------------------------------
|
|
84
|
+
// result — emit usage event + done or error event
|
|
85
|
+
// -------------------------------------------------------------------------
|
|
86
|
+
if (eventType === 'result') {
|
|
87
|
+
const ev = parsed;
|
|
88
|
+
const events = [];
|
|
89
|
+
const usage = ev.usage ? mapUsage(ev.usage) : { inputTokens: 0, outputTokens: 0 };
|
|
90
|
+
// Always emit usage first
|
|
91
|
+
events.push({ type: 'usage', usage });
|
|
92
|
+
const isFailure = ev.is_error === true || ev.subtype !== 'success';
|
|
93
|
+
if (isFailure) {
|
|
94
|
+
const errorText = String(ev.result ?? ev.subtype ?? 'unknown error');
|
|
95
|
+
events.push({ type: 'error', error: classifyError(errorText, 1) });
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const resultText = ev.result ?? '';
|
|
99
|
+
const doneEvent = {
|
|
100
|
+
type: 'done',
|
|
101
|
+
text: resultText,
|
|
102
|
+
usage,
|
|
103
|
+
...(typeof ev.total_cost_usd === 'number' ? { costUsd: ev.total_cost_usd } : {}),
|
|
104
|
+
raw: parsed,
|
|
105
|
+
};
|
|
106
|
+
events.push(doneEvent);
|
|
107
|
+
}
|
|
108
|
+
return events;
|
|
109
|
+
}
|
|
110
|
+
// Unknown event type — emit nothing
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=claude-parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-parse.js","sourceRoot":"","sources":["../../src/providers/claude-parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/providers/claude.ts — Claude CLI adapter implementing the Provider port.
|
|
3
|
+
*
|
|
4
|
+
* Spawns `claude -p --output-format stream-json --verbose` via execa v9,
|
|
5
|
+
* delivers the prompt via STDIN (never as an argv argument), and streams
|
|
6
|
+
* parsed ProviderEvents to the caller as they arrive.
|
|
7
|
+
*
|
|
8
|
+
* Sandbox enforcement note (Phase-4 item):
|
|
9
|
+
* The `req.sandbox` level is accepted but NOT yet translated into Claude CLI
|
|
10
|
+
* flags. Default headless `claude -p` is inherently safe — tool calls that
|
|
11
|
+
* would require elevated permissions are auto-denied by the Claude CLI. Full
|
|
12
|
+
* sandbox→flag mapping (e.g. `--allowedTools` restrictions) is deferred to
|
|
13
|
+
* Phase 4. Do NOT pass `--dangerously-skip-permissions` or any
|
|
14
|
+
* permission-bypass flag here.
|
|
15
|
+
*
|
|
16
|
+
* Authentication note:
|
|
17
|
+
* Auth state is OPTIMISTIC at detect() time — we cannot cheaply probe it.
|
|
18
|
+
* The real auth state surfaces at run time: an unauthenticated run produces
|
|
19
|
+
* a stderr that classifyError() maps to category 'auth'.
|
|
20
|
+
*
|
|
21
|
+
* Execa v9 streaming:
|
|
22
|
+
* We use `subprocess[Symbol.asyncIterator]()` (i.e. `for await … of subprocess`)
|
|
23
|
+
* which by default iterates over stdout lines as strings. Confirmed from
|
|
24
|
+
* types/subprocess/subprocess.d.ts: the subprocess IS an AsyncIterable that
|
|
25
|
+
* yields one string per stdout line.
|
|
26
|
+
*/
|
|
27
|
+
import type { Provider } from './port.js';
|
|
28
|
+
/**
|
|
29
|
+
* Map a concrete model id to a CLI-safe alias so a stale full id never 404s.
|
|
30
|
+
*
|
|
31
|
+
* Patterns:
|
|
32
|
+
* - claude-opus-* → 'opus'
|
|
33
|
+
* - claude-sonnet-* → 'sonnet'
|
|
34
|
+
* - claude-haiku-* → 'haiku'
|
|
35
|
+
* - anything else → returned unchanged
|
|
36
|
+
*/
|
|
37
|
+
export declare function toClaudeModelArg(model: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Create a Claude provider adapter.
|
|
40
|
+
*
|
|
41
|
+
* @param opts.bin - Override the binary name/path (default: `'claude'`).
|
|
42
|
+
*/
|
|
43
|
+
export declare function createClaudeProvider(opts?: {
|
|
44
|
+
bin?: string;
|
|
45
|
+
}): Provider;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/providers/claude.ts — Claude CLI adapter implementing the Provider port.
|
|
3
|
+
*
|
|
4
|
+
* Spawns `claude -p --output-format stream-json --verbose` via execa v9,
|
|
5
|
+
* delivers the prompt via STDIN (never as an argv argument), and streams
|
|
6
|
+
* parsed ProviderEvents to the caller as they arrive.
|
|
7
|
+
*
|
|
8
|
+
* Sandbox enforcement note (Phase-4 item):
|
|
9
|
+
* The `req.sandbox` level is accepted but NOT yet translated into Claude CLI
|
|
10
|
+
* flags. Default headless `claude -p` is inherently safe — tool calls that
|
|
11
|
+
* would require elevated permissions are auto-denied by the Claude CLI. Full
|
|
12
|
+
* sandbox→flag mapping (e.g. `--allowedTools` restrictions) is deferred to
|
|
13
|
+
* Phase 4. Do NOT pass `--dangerously-skip-permissions` or any
|
|
14
|
+
* permission-bypass flag here.
|
|
15
|
+
*
|
|
16
|
+
* Authentication note:
|
|
17
|
+
* Auth state is OPTIMISTIC at detect() time — we cannot cheaply probe it.
|
|
18
|
+
* The real auth state surfaces at run time: an unauthenticated run produces
|
|
19
|
+
* a stderr that classifyError() maps to category 'auth'.
|
|
20
|
+
*
|
|
21
|
+
* Execa v9 streaming:
|
|
22
|
+
* We use `subprocess[Symbol.asyncIterator]()` (i.e. `for await … of subprocess`)
|
|
23
|
+
* which by default iterates over stdout lines as strings. Confirmed from
|
|
24
|
+
* types/subprocess/subprocess.d.ts: the subprocess IS an AsyncIterable that
|
|
25
|
+
* yields one string per stdout line.
|
|
26
|
+
*/
|
|
27
|
+
import { execa } from 'execa';
|
|
28
|
+
import { detectProvider } from './detect.js';
|
|
29
|
+
import { classifyError } from './errors.js';
|
|
30
|
+
import { parseClaudeLine } from './claude-parse.js';
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Model alias mapping
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/**
|
|
35
|
+
* Map a concrete model id to a CLI-safe alias so a stale full id never 404s.
|
|
36
|
+
*
|
|
37
|
+
* Patterns:
|
|
38
|
+
* - claude-opus-* → 'opus'
|
|
39
|
+
* - claude-sonnet-* → 'sonnet'
|
|
40
|
+
* - claude-haiku-* → 'haiku'
|
|
41
|
+
* - anything else → returned unchanged
|
|
42
|
+
*/
|
|
43
|
+
export function toClaudeModelArg(model) {
|
|
44
|
+
if (model.startsWith('claude-opus'))
|
|
45
|
+
return 'opus';
|
|
46
|
+
if (model.startsWith('claude-sonnet'))
|
|
47
|
+
return 'sonnet';
|
|
48
|
+
if (model.startsWith('claude-haiku'))
|
|
49
|
+
return 'haiku';
|
|
50
|
+
return model;
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Factory
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
/**
|
|
56
|
+
* Create a Claude provider adapter.
|
|
57
|
+
*
|
|
58
|
+
* @param opts.bin - Override the binary name/path (default: `'claude'`).
|
|
59
|
+
*/
|
|
60
|
+
export function createClaudeProvider(opts) {
|
|
61
|
+
const bin = opts?.bin ?? 'claude';
|
|
62
|
+
return {
|
|
63
|
+
id: 'claude',
|
|
64
|
+
detect() {
|
|
65
|
+
return detectProvider('claude');
|
|
66
|
+
},
|
|
67
|
+
async *run(req, signal) {
|
|
68
|
+
const args = [
|
|
69
|
+
'-p',
|
|
70
|
+
'--output-format',
|
|
71
|
+
'stream-json',
|
|
72
|
+
'--verbose',
|
|
73
|
+
'--model',
|
|
74
|
+
toClaudeModelArg(req.model),
|
|
75
|
+
];
|
|
76
|
+
// Spawn with reject:false so we always get the result object (never throws).
|
|
77
|
+
// cancelSignal wires our AbortSignal directly to execa's termination path.
|
|
78
|
+
const subprocess = execa(bin, args, {
|
|
79
|
+
cwd: req.cwd,
|
|
80
|
+
input: req.prompt, // deliver prompt via STDIN, not argv
|
|
81
|
+
cancelSignal: signal,
|
|
82
|
+
timeout: req.timeoutMs,
|
|
83
|
+
reject: false,
|
|
84
|
+
});
|
|
85
|
+
let emittedTerminal = false;
|
|
86
|
+
// Stream stdout line by line.
|
|
87
|
+
// execa v9: the subprocess itself is an AsyncIterable that yields one
|
|
88
|
+
// string per stdout line (from types/subprocess/subprocess.d.ts).
|
|
89
|
+
try {
|
|
90
|
+
for await (const line of subprocess) {
|
|
91
|
+
const events = parseClaudeLine(line);
|
|
92
|
+
for (const ev of events) {
|
|
93
|
+
yield ev;
|
|
94
|
+
if (ev.type === 'done' || ev.type === 'error') {
|
|
95
|
+
emittedTerminal = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Iteration errors (e.g. stream abort) are handled below via the result.
|
|
102
|
+
}
|
|
103
|
+
// Wait for the subprocess to fully exit and collect the result.
|
|
104
|
+
const result = await subprocess;
|
|
105
|
+
if (!emittedTerminal) {
|
|
106
|
+
if (result.isCanceled) {
|
|
107
|
+
yield {
|
|
108
|
+
type: 'error',
|
|
109
|
+
error: classifyError('cancelled', 1),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
else if (result.failed || (result.exitCode !== undefined && result.exitCode !== 0)) {
|
|
113
|
+
yield {
|
|
114
|
+
type: 'error',
|
|
115
|
+
error: classifyError(typeof result.stderr === 'string' ? result.stderr : '', result.exitCode ?? 1),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/providers/claude.ts"],"names":[],"mappings":"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"}
|