@delegance/claude-autopilot 5.5.2 → 6.2.2
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 +935 -6
- package/README.md +55 -0
- package/dist/src/adapters/council/openai.js +12 -6
- package/dist/src/adapters/deploy/_http.d.ts +43 -0
- package/dist/src/adapters/deploy/_http.js +99 -0
- package/dist/src/adapters/deploy/fly.d.ts +206 -0
- package/dist/src/adapters/deploy/fly.js +696 -0
- package/dist/src/adapters/deploy/index.d.ts +2 -0
- package/dist/src/adapters/deploy/index.js +33 -0
- package/dist/src/adapters/deploy/render.d.ts +181 -0
- package/dist/src/adapters/deploy/render.js +550 -0
- package/dist/src/adapters/deploy/types.d.ts +67 -3
- package/dist/src/adapters/deploy/vercel.d.ts +17 -1
- package/dist/src/adapters/deploy/vercel.js +29 -49
- package/dist/src/adapters/pricing.d.ts +36 -0
- package/dist/src/adapters/pricing.js +40 -0
- package/dist/src/adapters/review-engine/codex.js +10 -7
- package/dist/src/cli/autopilot.d.ts +71 -0
- package/dist/src/cli/autopilot.js +735 -0
- package/dist/src/cli/brainstorm.d.ts +23 -0
- package/dist/src/cli/brainstorm.js +131 -0
- package/dist/src/cli/costs.d.ts +15 -1
- package/dist/src/cli/costs.js +99 -10
- package/dist/src/cli/deploy.d.ts +3 -3
- package/dist/src/cli/deploy.js +34 -9
- package/dist/src/cli/fix.d.ts +18 -0
- package/dist/src/cli/fix.js +105 -11
- package/dist/src/cli/help-text.d.ts +52 -0
- package/dist/src/cli/help-text.js +400 -0
- package/dist/src/cli/implement.d.ts +91 -0
- package/dist/src/cli/implement.js +196 -0
- package/dist/src/cli/index.js +719 -245
- package/dist/src/cli/json-envelope.d.ts +187 -0
- package/dist/src/cli/json-envelope.js +270 -0
- package/dist/src/cli/json-mode.d.ts +33 -0
- package/dist/src/cli/json-mode.js +201 -0
- package/dist/src/cli/migrate.d.ts +111 -0
- package/dist/src/cli/migrate.js +305 -0
- package/dist/src/cli/plan.d.ts +81 -0
- package/dist/src/cli/plan.js +149 -0
- package/dist/src/cli/pr.d.ts +106 -0
- package/dist/src/cli/pr.js +191 -19
- package/dist/src/cli/preflight.js +26 -0
- package/dist/src/cli/review.d.ts +27 -0
- package/dist/src/cli/review.js +126 -0
- package/dist/src/cli/runs-watch-renderer.d.ts +45 -0
- package/dist/src/cli/runs-watch-renderer.js +275 -0
- package/dist/src/cli/runs-watch.d.ts +41 -0
- package/dist/src/cli/runs-watch.js +395 -0
- package/dist/src/cli/runs.d.ts +122 -0
- package/dist/src/cli/runs.js +902 -0
- package/dist/src/cli/scan.d.ts +93 -0
- package/dist/src/cli/scan.js +166 -40
- package/dist/src/cli/spec.d.ts +66 -0
- package/dist/src/cli/spec.js +132 -0
- package/dist/src/cli/validate.d.ts +29 -0
- package/dist/src/cli/validate.js +131 -0
- package/dist/src/core/config/schema.d.ts +9 -0
- package/dist/src/core/config/schema.js +7 -0
- package/dist/src/core/config/types.d.ts +11 -0
- package/dist/src/core/council/runner.d.ts +10 -1
- package/dist/src/core/council/runner.js +25 -3
- package/dist/src/core/council/types.d.ts +7 -0
- package/dist/src/core/errors.d.ts +1 -1
- package/dist/src/core/errors.js +11 -0
- package/dist/src/core/logging/redaction.d.ts +13 -0
- package/dist/src/core/logging/redaction.js +20 -0
- package/dist/src/core/migrate/schema-validator.js +15 -1
- package/dist/src/core/phases/static-rules.d.ts +5 -1
- package/dist/src/core/phases/static-rules.js +2 -5
- package/dist/src/core/run-state/budget.d.ts +88 -0
- package/dist/src/core/run-state/budget.js +141 -0
- package/dist/src/core/run-state/cli-internal.d.ts +21 -0
- package/dist/src/core/run-state/cli-internal.js +174 -0
- package/dist/src/core/run-state/events.d.ts +59 -0
- package/dist/src/core/run-state/events.js +504 -0
- package/dist/src/core/run-state/lock.d.ts +61 -0
- package/dist/src/core/run-state/lock.js +206 -0
- package/dist/src/core/run-state/phase-context.d.ts +60 -0
- package/dist/src/core/run-state/phase-context.js +108 -0
- package/dist/src/core/run-state/phase-registry.d.ts +137 -0
- package/dist/src/core/run-state/phase-registry.js +162 -0
- package/dist/src/core/run-state/phase-runner.d.ts +80 -0
- package/dist/src/core/run-state/phase-runner.js +447 -0
- package/dist/src/core/run-state/provider-readback.d.ts +130 -0
- package/dist/src/core/run-state/provider-readback.js +426 -0
- package/dist/src/core/run-state/replay-decision.d.ts +69 -0
- package/dist/src/core/run-state/replay-decision.js +144 -0
- package/dist/src/core/run-state/resolve-engine.d.ts +100 -0
- package/dist/src/core/run-state/resolve-engine.js +190 -0
- package/dist/src/core/run-state/resume-preflight.d.ts +66 -0
- package/dist/src/core/run-state/resume-preflight.js +116 -0
- package/dist/src/core/run-state/run-phase-with-lifecycle.d.ts +73 -0
- package/dist/src/core/run-state/run-phase-with-lifecycle.js +186 -0
- package/dist/src/core/run-state/runs.d.ts +57 -0
- package/dist/src/core/run-state/runs.js +288 -0
- package/dist/src/core/run-state/snapshot.d.ts +14 -0
- package/dist/src/core/run-state/snapshot.js +114 -0
- package/dist/src/core/run-state/state.d.ts +40 -0
- package/dist/src/core/run-state/state.js +164 -0
- package/dist/src/core/run-state/types.d.ts +278 -0
- package/dist/src/core/run-state/types.js +13 -0
- package/dist/src/core/run-state/ulid.d.ts +11 -0
- package/dist/src/core/run-state/ulid.js +95 -0
- package/dist/src/core/schema-alignment/extractor/index.d.ts +1 -1
- package/dist/src/core/schema-alignment/extractor/index.js +2 -2
- package/dist/src/core/schema-alignment/extractor/prisma.d.ts +13 -1
- package/dist/src/core/schema-alignment/extractor/prisma.js +65 -10
- package/dist/src/core/schema-alignment/git-history.d.ts +19 -0
- package/dist/src/core/schema-alignment/git-history.js +53 -0
- package/dist/src/core/static-rules/rules/brand-tokens.js +2 -2
- package/dist/src/core/static-rules/rules/schema-alignment.js +14 -4
- package/package.json +2 -1
- package/scripts/autoregress.ts +1 -1
- package/skills/claude-autopilot.md +1 -1
- package/skills/make-interfaces-feel-better/SKILL.md +104 -0
- package/skills/simplify-ui/SKILL.md +103 -0
- package/skills/ui/SKILL.md +117 -0
- package/skills/ui-ux-pro-max/SKILL.md +90 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { loadConfig } from "../core/config/loader.js";
|
|
4
|
+
import { runPhaseWithLifecycle } from "../core/run-state/run-phase-with-lifecycle.js";
|
|
5
|
+
const C = {
|
|
6
|
+
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
7
|
+
green: '\x1b[32m', yellow: '\x1b[33m', cyan: '\x1b[36m', red: '\x1b[31m',
|
|
8
|
+
};
|
|
9
|
+
const fmt = (c, t) => `${C[c]}${t}${C.reset}`;
|
|
10
|
+
export async function runValidate(options = {}) {
|
|
11
|
+
const cwd = options.cwd ?? process.cwd();
|
|
12
|
+
const configPath = options.configPath ?? path.join(cwd, 'guardrail.config.yaml');
|
|
13
|
+
let config = { configVersion: 1 };
|
|
14
|
+
if (fs.existsSync(configPath)) {
|
|
15
|
+
const loaded = await loadConfig(configPath);
|
|
16
|
+
if (loaded)
|
|
17
|
+
config = loaded;
|
|
18
|
+
}
|
|
19
|
+
// INTENTIONAL DEVIATION FROM THE SPEC TABLE (preserved in v6.0.6):
|
|
20
|
+
// the v6 spec (docs/specs/v6-run-state-engine.md, line 161) lists
|
|
21
|
+
// `validate` with `idempotent: yes, hasSideEffects: no,
|
|
22
|
+
// externalRefs: sarif-artifact`. This wrap declares
|
|
23
|
+
// `idempotent: true, hasSideEffects: false` (matches the spec) but
|
|
24
|
+
// does **not** plumb a `sarif-artifact` externalRef. The reasoning:
|
|
25
|
+
// the `validate` CLI verb is an engine-wrap shell pointing at the
|
|
26
|
+
// Claude Code `/validate` skill — it does not itself emit a SARIF
|
|
27
|
+
// artifact. SARIF emission lives in `claude-autopilot run --format
|
|
28
|
+
// sarif --output <path>` (a separate verb, see help-text.ts → `run`
|
|
29
|
+
// Options block). The `sarif-artifact` externalRef is local-only file
|
|
30
|
+
// output (no remote upload), so the engine doesn't need a readback
|
|
31
|
+
// rule for it on resume — `idempotent: true` covers replay safety. If
|
|
32
|
+
// a future PR adds SARIF emission directly to this verb (or moves the
|
|
33
|
+
// `--format sarif` flag here), the wrap can add an
|
|
34
|
+
// `ctx.emitExternalRef({ kind: 'sarif-artifact', id: '<path>',
|
|
35
|
+
// observedAt: ... })` call after the file write lands. Until then, no
|
|
36
|
+
// ledger entry is needed because there's nothing to read back from.
|
|
37
|
+
const context = options.context ?? null;
|
|
38
|
+
const outputPath = options.outputPath
|
|
39
|
+
? path.resolve(cwd, options.outputPath)
|
|
40
|
+
: path.join(cwd, '.guardrail-cache', 'validate', `${new Date().toISOString().replace(/[:.]/g, '-')}-validate.md`);
|
|
41
|
+
const validateInput = { cwd, context, outputPath };
|
|
42
|
+
// The wrapped phase body — writes a validate log stub to disk. The actual
|
|
43
|
+
// validation work (static checks → auto-fix → tests → Codex review →
|
|
44
|
+
// bugbot triage) is produced by the Claude Code `/validate` skill.
|
|
45
|
+
// Engine-off callers invoke this directly via `executeValidatePhase()`;
|
|
46
|
+
// engine-on callers route through `runPhase()`.
|
|
47
|
+
const phase = {
|
|
48
|
+
name: 'validate',
|
|
49
|
+
// Re-running the validate verb against the same context writes the same
|
|
50
|
+
// log file. Engine treats local file writes as overwrite-style — same
|
|
51
|
+
// precedent as scan's findings-cache and review's review-log.
|
|
52
|
+
idempotent: true,
|
|
53
|
+
// Local file write only — no PR comment posting, no git push, no
|
|
54
|
+
// provider-side mutation, no SARIF upload. See the long deviation note
|
|
55
|
+
// above where the engine resolution is computed for the externalRefs
|
|
56
|
+
// rationale.
|
|
57
|
+
hasSideEffects: false,
|
|
58
|
+
run: async (input) => executeValidatePhase(input),
|
|
59
|
+
};
|
|
60
|
+
// v6.0.6 — lifecycle wiring lives in `runPhaseWithLifecycle`.
|
|
61
|
+
let output;
|
|
62
|
+
try {
|
|
63
|
+
const result = await runPhaseWithLifecycle({
|
|
64
|
+
cwd,
|
|
65
|
+
phase,
|
|
66
|
+
input: validateInput,
|
|
67
|
+
config,
|
|
68
|
+
cliEngine: options.cliEngine,
|
|
69
|
+
envEngine: options.envEngine,
|
|
70
|
+
runEngineOff: () => executeValidatePhase(validateInput),
|
|
71
|
+
});
|
|
72
|
+
output = result.output;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
return renderValidateOutput(output, validateInput);
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Phase body — write a validate log stub. Pure: no console output, no exit
|
|
81
|
+
// codes. Returns a JSON-serializable ValidateOutput so the engine can persist
|
|
82
|
+
// it as `result` on the phase snapshot. The actual validation work is
|
|
83
|
+
// produced by the Claude Code `/validate` skill; this CLI verb's job is to
|
|
84
|
+
// provide a checkpointable phase shell.
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
async function executeValidatePhase(input) {
|
|
87
|
+
const { context, outputPath } = input;
|
|
88
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
89
|
+
const lines = [
|
|
90
|
+
'# Validate',
|
|
91
|
+
'',
|
|
92
|
+
`Generated: ${new Date().toISOString()}`,
|
|
93
|
+
'',
|
|
94
|
+
context ? `Context: ${context}` : 'Context: (none provided)',
|
|
95
|
+
'',
|
|
96
|
+
'<!--',
|
|
97
|
+
'This is the v6 engine-wrap stub for the `validate` phase. The actual',
|
|
98
|
+
'validation work (static checks, auto-fix, tests, Codex review with',
|
|
99
|
+
'auto-fix, bugbot triage) is produced by the Claude Code `/validate`',
|
|
100
|
+
'skill. The CLI verb exists to provide a checkpointable phase shell so',
|
|
101
|
+
'`claude-autopilot runs show <id>` reflects a `validate` phase entry',
|
|
102
|
+
'when the pipeline includes one. SARIF emission lives in',
|
|
103
|
+
'`claude-autopilot run --format sarif --output <path>` (a separate',
|
|
104
|
+
'verb).',
|
|
105
|
+
'-->',
|
|
106
|
+
'',
|
|
107
|
+
];
|
|
108
|
+
fs.writeFileSync(outputPath, lines.join('\n'), 'utf8');
|
|
109
|
+
return {
|
|
110
|
+
validateLogPath: outputPath,
|
|
111
|
+
context,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Render — translate ValidateOutput back to a stdout summary + exit code.
|
|
116
|
+
// Lives outside the wrapped phase because it's pure presentation.
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
function renderValidateOutput(output, input) {
|
|
119
|
+
const { validateLogPath, context } = output;
|
|
120
|
+
const { cwd } = input;
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log(fmt('bold', '[validate]') + ' ' + fmt('dim', context ? `context: ${context}` : 'no context provided'));
|
|
123
|
+
console.log(fmt('dim', ` → ${path.relative(cwd, validateLogPath)}`));
|
|
124
|
+
console.log('');
|
|
125
|
+
console.log(fmt('cyan', 'Note:') + fmt('dim', ' the validation pipeline lives in Claude Code (/validate skill —'));
|
|
126
|
+
console.log(fmt('dim', ' static checks, auto-fix, tests, Codex review, bugbot triage).'));
|
|
127
|
+
console.log(fmt('dim', ' SARIF emission lives in `claude-autopilot run --format sarif --output <path>`.'));
|
|
128
|
+
console.log('');
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -298,6 +298,15 @@ export declare const GUARDRAIL_CONFIG_SCHEMA: {
|
|
|
298
298
|
readonly concurrency: {
|
|
299
299
|
readonly type: "object";
|
|
300
300
|
};
|
|
301
|
+
readonly engine: {
|
|
302
|
+
readonly type: "object";
|
|
303
|
+
readonly additionalProperties: false;
|
|
304
|
+
readonly properties: {
|
|
305
|
+
readonly enabled: {
|
|
306
|
+
readonly type: "boolean";
|
|
307
|
+
};
|
|
308
|
+
};
|
|
309
|
+
};
|
|
301
310
|
readonly council: {
|
|
302
311
|
readonly type: "object";
|
|
303
312
|
readonly required: readonly ["models", "synthesizer"];
|
|
@@ -152,6 +152,13 @@ export const GUARDRAIL_CONFIG_SCHEMA = {
|
|
|
152
152
|
cache: { type: 'object' },
|
|
153
153
|
persistence: { type: 'object' },
|
|
154
154
|
concurrency: { type: 'object' },
|
|
155
|
+
engine: {
|
|
156
|
+
type: 'object',
|
|
157
|
+
additionalProperties: false,
|
|
158
|
+
properties: {
|
|
159
|
+
enabled: { type: 'boolean' },
|
|
160
|
+
},
|
|
161
|
+
},
|
|
155
162
|
council: {
|
|
156
163
|
type: 'object',
|
|
157
164
|
required: ['models', 'synthesizer'],
|
|
@@ -101,6 +101,17 @@ export interface GuardrailConfig {
|
|
|
101
101
|
cache?: Record<string, unknown>;
|
|
102
102
|
persistence?: Record<string, unknown>;
|
|
103
103
|
concurrency?: Record<string, unknown>;
|
|
104
|
+
/**
|
|
105
|
+
* Run State Engine (v6) configuration. v6.0 ships the engine OFF by default
|
|
106
|
+
* to preserve v5.x behavior; v6.1+ flips the default to ON per
|
|
107
|
+
* `docs/specs/v6.1-default-flip.md`. The `engine.enabled` knob is the
|
|
108
|
+
* lowest-priority opt-in — env (`CLAUDE_AUTOPILOT_ENGINE`) and CLI flags
|
|
109
|
+
* (`--engine` / `--no-engine`) override it. See
|
|
110
|
+
* `src/core/run-state/resolve-engine.ts` for the precedence resolver.
|
|
111
|
+
*/
|
|
112
|
+
engine?: {
|
|
113
|
+
enabled?: boolean;
|
|
114
|
+
};
|
|
104
115
|
council?: {
|
|
105
116
|
models: Array<{
|
|
106
117
|
adapter: string;
|
|
@@ -8,5 +8,14 @@ export interface CouncilRunOutput {
|
|
|
8
8
|
costUSD: number;
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
/** Phase 4 — bounded recursion options. The current single-shot
|
|
12
|
+
* synthesizer never sets this; it's plumbed for future self-eat
|
|
13
|
+
* patterns where the synthesizer recursively calls runCouncil. */
|
|
14
|
+
export interface CouncilRunOptions {
|
|
15
|
+
/** Current recursion depth. Top-level callers omit this (default 0).
|
|
16
|
+
* A synthesizer that calls runCouncil internally MUST pass
|
|
17
|
+
* `currentDepth + 1` so the bound takes effect. */
|
|
18
|
+
currentDepth?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function runCouncil(config: CouncilConfig, adapters: CouncilAdapter[], synthesizer: CouncilAdapter, prompt: string, contextDoc: string, options?: CouncilRunOptions): Promise<CouncilRunOutput>;
|
|
12
21
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -32,8 +32,26 @@ async function consultWithTimeout(adapter, prompt, context, timeoutMs) {
|
|
|
32
32
|
clearTimeout(timer);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
export async function runCouncil(config, adapters, synthesizer, prompt, contextDoc) {
|
|
35
|
+
export async function runCouncil(config, adapters, synthesizer, prompt, contextDoc, options = {}) {
|
|
36
36
|
const run_id = crypto.randomUUID();
|
|
37
|
+
const currentDepth = options.currentDepth ?? 0;
|
|
38
|
+
// -- Recursion bound (Phase 4) ------------------------------------------
|
|
39
|
+
// Strict `>` so a maxDepth of N permits N nested self-calls — i.e.
|
|
40
|
+
// depth 0 (top-level) + N inner calls. Exceeding aborts with `partial`
|
|
41
|
+
// and never recurses deeper.
|
|
42
|
+
if (typeof config.councilMaxRecursionDepth === 'number'
|
|
43
|
+
&& currentDepth > config.councilMaxRecursionDepth) {
|
|
44
|
+
return {
|
|
45
|
+
result: {
|
|
46
|
+
schema_version: 1,
|
|
47
|
+
run_id,
|
|
48
|
+
status: 'partial',
|
|
49
|
+
prompt,
|
|
50
|
+
responses: [],
|
|
51
|
+
},
|
|
52
|
+
usage: { inputTokens: 0, outputTokens: 0, costUSD: 0 },
|
|
53
|
+
};
|
|
54
|
+
}
|
|
37
55
|
const context = windowContext(contextDoc, config.parallelInputMaxTokens);
|
|
38
56
|
const responses = await Promise.all(adapters.map(a => consultWithTimeout(a, prompt, context, config.timeoutMs)));
|
|
39
57
|
const aggregateUsage = (entries) => {
|
|
@@ -61,8 +79,12 @@ export async function runCouncil(config, adapters, synthesizer, prompt, contextD
|
|
|
61
79
|
const responseSections = successful
|
|
62
80
|
.map(r => `### ${r.label}\n${r.text}`)
|
|
63
81
|
.join('\n\n');
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
// Advisor responses go in synthesisPrompt only (structured form). The
|
|
83
|
+
// context the synthesizer sees is the original conversation document
|
|
84
|
+
// re-windowed for its own token budget — keeping responseSections out of
|
|
85
|
+
// it avoids duplicating them and also avoids letting large responses
|
|
86
|
+
// squeeze contextDoc out of synthesisInputMaxTokens.
|
|
87
|
+
const synthesisCtx = windowContext(contextDoc, config.synthesisInputMaxTokens);
|
|
66
88
|
const synthesisPrompt = [
|
|
67
89
|
`You have received responses from multiple technical advisors on the following question:\n\n## Original Question\n\n${prompt}`,
|
|
68
90
|
`## Advisor Responses\n\n${responseSections}`,
|
|
@@ -10,6 +10,13 @@ export interface CouncilConfig {
|
|
|
10
10
|
minSuccessfulResponses: number;
|
|
11
11
|
parallelInputMaxTokens: number;
|
|
12
12
|
synthesisInputMaxTokens: number;
|
|
13
|
+
/** Phase 4 (v6) — bounded recursion for the synthesizer. If set, every
|
|
14
|
+
* synthesizer self-call increments an internal depth counter; exceeding
|
|
15
|
+
* this value aborts the council with `partial` status (never deeper).
|
|
16
|
+
* Default: undefined (no bound; current single-shot synthesizer is
|
|
17
|
+
* unaffected — the bound only matters when the synthesizer itself
|
|
18
|
+
* recurses into runCouncil). */
|
|
19
|
+
councilMaxRecursionDepth?: number;
|
|
13
20
|
}
|
|
14
21
|
export type ModelResponseStatus = 'ok' | 'timeout' | 'error';
|
|
15
22
|
export interface ModelResponse {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ErrorCode = 'auth' | 'rate_limit' | 'transient_network' | 'invalid_config' | 'adapter_bug' | 'user_input' | 'budget_exceeded' | 'concurrency_lock' | 'superseded' | 'no_previous_deploy';
|
|
1
|
+
export type ErrorCode = 'auth' | 'rate_limit' | 'transient_network' | 'invalid_config' | 'adapter_bug' | 'user_input' | 'budget_exceeded' | 'concurrency_lock' | 'superseded' | 'no_previous_deploy' | 'not_found' | 'lock_held' | 'corrupted_state' | 'partial_write' | 'needs_human';
|
|
2
2
|
export interface GuardrailErrorOptions {
|
|
3
3
|
code: ErrorCode;
|
|
4
4
|
retryable?: boolean;
|
package/dist/src/core/errors.js
CHANGED
|
@@ -4,6 +4,17 @@ const DEFAULT_RETRYABLE = {
|
|
|
4
4
|
adapter_bug: false, user_input: false, budget_exceeded: false,
|
|
5
5
|
concurrency_lock: false, superseded: false,
|
|
6
6
|
no_previous_deploy: false,
|
|
7
|
+
// 404 — caller-fixable (slug typo, wrong scope). Not retryable; the
|
|
8
|
+
// resource won't materialize on its own.
|
|
9
|
+
not_found: false,
|
|
10
|
+
// v6 Run State Engine — none retry automatically; takeover/recovery is an
|
|
11
|
+
// explicit user-driven decision (--force-takeover / --force).
|
|
12
|
+
lock_held: false,
|
|
13
|
+
corrupted_state: false,
|
|
14
|
+
partial_write: false,
|
|
15
|
+
// v6.2.1 — needs_human is by definition a stop-the-pipeline signal; the
|
|
16
|
+
// user (or `--force-replay`) decides whether to retry.
|
|
17
|
+
needs_human: false,
|
|
7
18
|
};
|
|
8
19
|
export class GuardrailError extends Error {
|
|
9
20
|
code;
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
export declare const DEFAULT_REDACTION_PATTERNS: readonly string[];
|
|
2
2
|
export declare function applyRedaction(text: string, patterns: readonly string[]): string;
|
|
3
3
|
export declare function containsSecret(text: string, patterns: readonly string[]): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Convenience wrapper around {@link applyRedaction} that defaults to the
|
|
6
|
+
* built-in {@link DEFAULT_REDACTION_PATTERNS} list and accepts an optional
|
|
7
|
+
* caller-supplied extension. Designed for adapter `output` fields and other
|
|
8
|
+
* "last N lines" surfaces where a pattern list is rarely available at the
|
|
9
|
+
* call site (the v5.6 spec § "Log redaction" requires this for all new
|
|
10
|
+
* adapters).
|
|
11
|
+
*
|
|
12
|
+
* Pass extra patterns when the caller has loaded
|
|
13
|
+
* `config.persistence.redactionPatterns`; otherwise omit the argument and
|
|
14
|
+
* the defaults handle the well-known token shapes.
|
|
15
|
+
*/
|
|
16
|
+
export declare function redactLogLines(text: string, patterns?: readonly string[]): string;
|
|
4
17
|
//# sourceMappingURL=redaction.d.ts.map
|
|
@@ -15,4 +15,24 @@ export function applyRedaction(text, patterns) {
|
|
|
15
15
|
export function containsSecret(text, patterns) {
|
|
16
16
|
return patterns.some(p => new RegExp(p).test(text));
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Convenience wrapper around {@link applyRedaction} that defaults to the
|
|
20
|
+
* built-in {@link DEFAULT_REDACTION_PATTERNS} list and accepts an optional
|
|
21
|
+
* caller-supplied extension. Designed for adapter `output` fields and other
|
|
22
|
+
* "last N lines" surfaces where a pattern list is rarely available at the
|
|
23
|
+
* call site (the v5.6 spec § "Log redaction" requires this for all new
|
|
24
|
+
* adapters).
|
|
25
|
+
*
|
|
26
|
+
* Pass extra patterns when the caller has loaded
|
|
27
|
+
* `config.persistence.redactionPatterns`; otherwise omit the argument and
|
|
28
|
+
* the defaults handle the well-known token shapes.
|
|
29
|
+
*/
|
|
30
|
+
export function redactLogLines(text, patterns) {
|
|
31
|
+
if (!text)
|
|
32
|
+
return text;
|
|
33
|
+
const merged = patterns && patterns.length > 0
|
|
34
|
+
? [...DEFAULT_REDACTION_PATTERNS, ...patterns]
|
|
35
|
+
: DEFAULT_REDACTION_PATTERNS;
|
|
36
|
+
return applyRedaction(text, merged);
|
|
37
|
+
}
|
|
18
38
|
//# sourceMappingURL=redaction.js.map
|
|
@@ -54,7 +54,20 @@ function buildValidator() {
|
|
|
54
54
|
}
|
|
55
55
|
return ajv.compile(schema);
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
// Lazy-init: previously the validator was built at module load, which meant
|
|
58
|
+
// every `claude-autopilot --version` (or any CLI invocation that imports the
|
|
59
|
+
// migrate module via dispatch chain) eagerly read presets/aliases.lock.json
|
|
60
|
+
// + presets/schemas/migrate.schema.json. Missing files crashed the entire
|
|
61
|
+
// CLI with a stack trace before the user-facing entry point even started.
|
|
62
|
+
// Rebuilding on first use also keeps tests that don't touch validation
|
|
63
|
+
// from paying the AJV compile cost. Caught by the tombstone-bin test
|
|
64
|
+
// (`does not leak a node stack trace when claude-autopilot is unreachable`).
|
|
65
|
+
let _validate;
|
|
66
|
+
function getValidator() {
|
|
67
|
+
if (_validate === undefined)
|
|
68
|
+
_validate = buildValidator();
|
|
69
|
+
return _validate;
|
|
70
|
+
}
|
|
58
71
|
function commandsEqual(a, b) {
|
|
59
72
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
60
73
|
}
|
|
@@ -99,6 +112,7 @@ export function validateStackMd(yamlSource) {
|
|
|
99
112
|
}],
|
|
100
113
|
};
|
|
101
114
|
}
|
|
115
|
+
const validate = getValidator();
|
|
102
116
|
const ok = validate(parsed);
|
|
103
117
|
const schemaErrors = ok ? [] : ajvErrorsToValidationErrors(validate.errors ?? []);
|
|
104
118
|
const crossFieldErrors = ok ? checkDevCommandReuse(parsed) : [];
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { Finding, FixAttempt, FixStatus } from '../findings/types.ts';
|
|
2
2
|
import type { GuardrailConfig } from '../config/types.ts';
|
|
3
3
|
import type { ReviewEngine } from '../../adapters/review-engine/types.ts';
|
|
4
|
+
export interface StaticRuleContext {
|
|
5
|
+
config?: GuardrailConfig;
|
|
6
|
+
engine?: ReviewEngine;
|
|
7
|
+
}
|
|
4
8
|
export interface StaticRule {
|
|
5
9
|
name: string;
|
|
6
10
|
severity: 'critical' | 'warning' | 'note';
|
|
7
|
-
check(touchedFiles: string[],
|
|
11
|
+
check(touchedFiles: string[], ctx?: StaticRuleContext): Promise<Finding[]>;
|
|
8
12
|
autofix?(finding: Finding): Promise<FixStatus>;
|
|
9
13
|
}
|
|
10
14
|
export interface StaticRulesPhaseInput {
|
|
@@ -42,13 +42,10 @@ export async function runStaticRulesPhase(input) {
|
|
|
42
42
|
return { phase: 'static-rules', status, findings: preFixFindings, fixAttempts, durationMs: Date.now() - start };
|
|
43
43
|
}
|
|
44
44
|
async function runAllChecks(rules, files, config, engine) {
|
|
45
|
-
const
|
|
46
|
-
...(config ? config : {}),
|
|
47
|
-
_engine: engine,
|
|
48
|
-
};
|
|
45
|
+
const ctx = { config, engine };
|
|
49
46
|
const all = [];
|
|
50
47
|
for (const rule of rules)
|
|
51
|
-
all.push(...(await rule.check(files,
|
|
48
|
+
all.push(...(await rule.check(files, ctx)));
|
|
52
49
|
return all;
|
|
53
50
|
}
|
|
54
51
|
function findRuleForFinding(rules, finding) {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** Default Layer 2 reserve when none is configured. Conservative — phases
|
|
2
|
+
* without an `estimateCost` are assumed to consume at least this much,
|
|
3
|
+
* which keeps the cap from "failing open" the moment a phase forgets to
|
|
4
|
+
* declare its cost shape. */
|
|
5
|
+
export declare const DEFAULT_CONSERVATIVE_PHASE_RESERVE_USD = 5;
|
|
6
|
+
export interface BudgetConfig {
|
|
7
|
+
/** Total run cap (USD). Hard stop. Required — phases that don't want
|
|
8
|
+
* budget enforcement should not pass a `BudgetConfig` at all. */
|
|
9
|
+
perRunUSD: number;
|
|
10
|
+
/** Per-phase cap (USD). Phases that haven't declared `estimateCost`
|
|
11
|
+
* still pay the conservativePhaseReserve under Layer 2. Optional. */
|
|
12
|
+
perPhaseUSD?: number;
|
|
13
|
+
/** Bounded recursion for council synthesizer. Wired in
|
|
14
|
+
* `src/core/council/runner.ts`; no effect inside `runPhase`. */
|
|
15
|
+
councilMaxRecursionDepth?: number;
|
|
16
|
+
/** Bounded autopilot self-eat rounds (per spec). Reserved field —
|
|
17
|
+
* consumed by the autopilot orchestrator, not the runner. */
|
|
18
|
+
bgAutopilotMaxRoundsPerSelfEat?: number;
|
|
19
|
+
/** Used by Layer 2 (mandatory runtime guard) when a phase has no
|
|
20
|
+
* `estimateCost` — represents the "we don't know how big this gets,
|
|
21
|
+
* reserve at least this much from the cap" floor. Defaults to
|
|
22
|
+
* `DEFAULT_CONSERVATIVE_PHASE_RESERVE_USD` when omitted. */
|
|
23
|
+
conservativePhaseReserveUSD?: number;
|
|
24
|
+
/** v6.2.0 — budget scope. `'phase'` (default) keeps the legacy
|
|
25
|
+
* per-phase semantics where each `runPhase` invocation reasons against
|
|
26
|
+
* its own phase budget (back-compat for single-phase wrappers like
|
|
27
|
+
* `runPhaseWithLifecycle`). `'run'` is the orchestrator's
|
|
28
|
+
* cross-phase mode: the actualSoFar reservoir already sums every
|
|
29
|
+
* prior `phase.cost` event in the run, so `perRunUSD` is policed
|
|
30
|
+
* monotonically against the WHOLE pipeline's spend.
|
|
31
|
+
*
|
|
32
|
+
* In practice the policy math is identical between the two scopes —
|
|
33
|
+
* Layer 1 + Layer 2 both consume `actualSoFarUSD` regardless. The
|
|
34
|
+
* scope flag exists so the `budget.check` event tells observers
|
|
35
|
+
* which mode produced the decision (so a CI dashboard can attribute
|
|
36
|
+
* a reject to "run scope" vs "single-phase scope") and so future
|
|
37
|
+
* policy changes (e.g. divergent perPhase reserves under run scope)
|
|
38
|
+
* have a place to land without an event-shape break.
|
|
39
|
+
*
|
|
40
|
+
* Per spec docs/specs/v6.2-multi-phase-orchestrator.md "Budget
|
|
41
|
+
* enforcement": `checkPhaseBudget` gains `scope: 'phase' | 'run'`
|
|
42
|
+
* (default 'phase' for back-compat). Orchestrator passes
|
|
43
|
+
* `scope: 'run'`; per-phase callers keep the default. */
|
|
44
|
+
scope?: 'phase' | 'run';
|
|
45
|
+
}
|
|
46
|
+
/** The decision the runner consumes. Mirrors the `budget.check` event
|
|
47
|
+
* payload one-to-one so wiring is trivial. */
|
|
48
|
+
export interface BudgetCheck {
|
|
49
|
+
decision: 'proceed' | 'pause' | 'hard-fail';
|
|
50
|
+
phase: string;
|
|
51
|
+
phaseIdx: number;
|
|
52
|
+
/** `estimate.high` from the phase's `estimateCost` if it returned a
|
|
53
|
+
* value; null when the phase doesn't implement estimateCost. */
|
|
54
|
+
estimatedHigh: number | null;
|
|
55
|
+
actualSoFar: number;
|
|
56
|
+
/** The reserve the policy deducted against `perRunUSD` for this phase
|
|
57
|
+
* (the larger of `estimate.high` and `conservativePhaseReserveUSD`). */
|
|
58
|
+
reserveApplied: number;
|
|
59
|
+
/** USD remaining under `perRunUSD` after `actualSoFar` + the larger of
|
|
60
|
+
* `estimatedHigh` and `reserveApplied`. May be negative on hard-fail. */
|
|
61
|
+
capRemaining: number;
|
|
62
|
+
reason: string;
|
|
63
|
+
/** v6.2.0 — which scope produced the decision. Echoes `BudgetConfig.scope`
|
|
64
|
+
* back into the `budget.check` event so observers can attribute
|
|
65
|
+
* cross-phase rejections to the orchestrator vs single-phase wrappers
|
|
66
|
+
* passing the legacy default. */
|
|
67
|
+
scope: 'phase' | 'run';
|
|
68
|
+
}
|
|
69
|
+
export interface CheckPhaseBudgetOpts {
|
|
70
|
+
budget: BudgetConfig;
|
|
71
|
+
phaseName: string;
|
|
72
|
+
phaseIdx: number;
|
|
73
|
+
/** What `RunPhase.estimateCost(input)` returned, or null if absent. */
|
|
74
|
+
estimatedCost: {
|
|
75
|
+
lowUSD: number;
|
|
76
|
+
highUSD: number;
|
|
77
|
+
} | null;
|
|
78
|
+
/** Sum of every prior `phase.cost` event in the run, in USD. */
|
|
79
|
+
actualSoFarUSD: number;
|
|
80
|
+
/** When true, a `pause` decision becomes `hard-fail` (CI / `--json`
|
|
81
|
+
* mode can't prompt for human approval). */
|
|
82
|
+
nonInteractive: boolean;
|
|
83
|
+
}
|
|
84
|
+
/** Policy decision for a single about-to-run phase. Pure — no IO. The
|
|
85
|
+
* caller (`runPhase`) is responsible for emitting the `budget.check`
|
|
86
|
+
* event with this payload and acting on the decision. */
|
|
87
|
+
export declare function checkPhaseBudget(opts: CheckPhaseBudgetOpts): BudgetCheck;
|
|
88
|
+
//# sourceMappingURL=budget.d.ts.map
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// src/core/run-state/budget.ts
|
|
2
|
+
//
|
|
3
|
+
// v6 Phase 4 — budget enforcement policy.
|
|
4
|
+
//
|
|
5
|
+
// Pure data + a pure decision function. No IO, no globals, no side effects.
|
|
6
|
+
// `checkPhaseBudget` is the authoritative answer to "may this phase run?"
|
|
7
|
+
// — `runPhase` consumes the result, emits a `budget.check` event with the
|
|
8
|
+
// full payload, and throws `budget_exceeded` on hard-fail.
|
|
9
|
+
//
|
|
10
|
+
// Two-layer policy per spec (Codex CRITICAL #3 fold-in — estimates can fail
|
|
11
|
+
// open, the runtime guard MUST run independently):
|
|
12
|
+
//
|
|
13
|
+
// - Layer 1 (advisory) — only fires when the phase declares
|
|
14
|
+
// `estimateCost`. Compares `actualSoFar + estimate.high` against
|
|
15
|
+
// `perRunUSD`. Pause-and-prompt (interactive) or hard-fail (CI mode)
|
|
16
|
+
// if it would exceed.
|
|
17
|
+
// - Layer 2 (mandatory) — ALWAYS runs. Compares `actualSoFar +
|
|
18
|
+
// conservativePhaseReserveUSD` against `perRunUSD`. Phases without
|
|
19
|
+
// estimates therefore still trigger budget gates. Default reserve is
|
|
20
|
+
// $5 (overridable in config).
|
|
21
|
+
// - `perPhaseUSD` gate — if set AND the larger of the per-phase estimate
|
|
22
|
+
// or reserve would push this phase's cost over the per-phase cap,
|
|
23
|
+
// applies the same pause/hard-fail rule.
|
|
24
|
+
//
|
|
25
|
+
// Spec: docs/specs/v6-run-state-engine.md "Budget enforcement".
|
|
26
|
+
/** Default Layer 2 reserve when none is configured. Conservative — phases
|
|
27
|
+
* without an `estimateCost` are assumed to consume at least this much,
|
|
28
|
+
* which keeps the cap from "failing open" the moment a phase forgets to
|
|
29
|
+
* declare its cost shape. */
|
|
30
|
+
export const DEFAULT_CONSERVATIVE_PHASE_RESERVE_USD = 5;
|
|
31
|
+
/** Policy decision for a single about-to-run phase. Pure — no IO. The
|
|
32
|
+
* caller (`runPhase`) is responsible for emitting the `budget.check`
|
|
33
|
+
* event with this payload and acting on the decision. */
|
|
34
|
+
export function checkPhaseBudget(opts) {
|
|
35
|
+
const { budget, phaseName, phaseIdx, estimatedCost, actualSoFarUSD, nonInteractive, } = opts;
|
|
36
|
+
// v6.2.0 — `'phase'` (default for back-compat) vs `'run'` (orchestrator).
|
|
37
|
+
// The math is intentionally identical between the two; `actualSoFarUSD`
|
|
38
|
+
// is already the cross-phase sum produced by `sumRunCost` in
|
|
39
|
+
// phase-runner.ts. The flag exists so the `budget.check` event tells
|
|
40
|
+
// observers which scope generated the decision and so future policy
|
|
41
|
+
// tweaks (e.g. divergent perPhase reserves under run scope) have a
|
|
42
|
+
// place to land without an event-shape break.
|
|
43
|
+
const scope = budget.scope ?? 'phase';
|
|
44
|
+
const reserveFloor = typeof budget.conservativePhaseReserveUSD === 'number'
|
|
45
|
+
? budget.conservativePhaseReserveUSD
|
|
46
|
+
: DEFAULT_CONSERVATIVE_PHASE_RESERVE_USD;
|
|
47
|
+
// The reserve actually deducted is the larger of "what the phase says
|
|
48
|
+
// it will cost (high end)" and "the conservative floor we always apply".
|
|
49
|
+
// This is the core of Codex CRITICAL #3 — even if estimateCost is
|
|
50
|
+
// present and tiny, the floor still applies, and even if estimateCost
|
|
51
|
+
// is absent, the floor still applies.
|
|
52
|
+
const estimatedHigh = estimatedCost?.highUSD ?? null;
|
|
53
|
+
const reserveApplied = Math.max(estimatedHigh ?? 0, reserveFloor);
|
|
54
|
+
const projected = actualSoFarUSD + reserveApplied;
|
|
55
|
+
const capRemaining = budget.perRunUSD - projected;
|
|
56
|
+
// Layer 1 — ADVISORY using the explicit estimate. Runs FIRST so a precise
|
|
57
|
+
// estimate produces a precise reason ("estimate would exceed cap") instead
|
|
58
|
+
// of falling through to Layer 2's conservative-floor wording. Only fires
|
|
59
|
+
// when an estimate is present AND would push us past perRunUSD on its own.
|
|
60
|
+
// (Bugbot LOW on PR #89 caught the prior ordering, where Layer 2 always
|
|
61
|
+
// ran first and Layer 1 was provably unreachable since `reserveApplied =
|
|
62
|
+
// max(estimatedHigh, floor) >= estimatedHigh`.)
|
|
63
|
+
if (estimatedHigh !== null && actualSoFarUSD + estimatedHigh > budget.perRunUSD) {
|
|
64
|
+
const decision = nonInteractive ? 'hard-fail' : 'pause';
|
|
65
|
+
return {
|
|
66
|
+
decision,
|
|
67
|
+
phase: phaseName,
|
|
68
|
+
phaseIdx,
|
|
69
|
+
estimatedHigh,
|
|
70
|
+
actualSoFar: actualSoFarUSD,
|
|
71
|
+
reserveApplied,
|
|
72
|
+
capRemaining: budget.perRunUSD - (actualSoFarUSD + estimatedHigh),
|
|
73
|
+
reason: `advisory estimate would exceed run cap — actual ` +
|
|
74
|
+
`$${fmtUSD(actualSoFarUSD)} + estimate.high ` +
|
|
75
|
+
`$${fmtUSD(estimatedHigh)} > perRunUSD $${fmtUSD(budget.perRunUSD)}`,
|
|
76
|
+
scope,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Layer 2 — MANDATORY floor against perRunUSD. Catches the case where the
|
|
80
|
+
// estimate is missing (Layer 1 didn't fire) OR present-but-tiny (estimate
|
|
81
|
+
// alone fits, but the conservative reserve floor pushes over). This is the
|
|
82
|
+
// safety net that prevents phases without `estimateCost` from sneaking
|
|
83
|
+
// past the cap.
|
|
84
|
+
if (projected > budget.perRunUSD) {
|
|
85
|
+
const decision = nonInteractive ? 'hard-fail' : 'pause';
|
|
86
|
+
return {
|
|
87
|
+
decision,
|
|
88
|
+
phase: phaseName,
|
|
89
|
+
phaseIdx,
|
|
90
|
+
estimatedHigh,
|
|
91
|
+
actualSoFar: actualSoFarUSD,
|
|
92
|
+
reserveApplied,
|
|
93
|
+
capRemaining,
|
|
94
|
+
reason: `run cap exceeded — actual $${fmtUSD(actualSoFarUSD)} + reserve ` +
|
|
95
|
+
`$${fmtUSD(reserveApplied)} = $${fmtUSD(projected)} > perRunUSD ` +
|
|
96
|
+
`$${fmtUSD(budget.perRunUSD)}`,
|
|
97
|
+
scope,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// perPhaseUSD gate — independent of the run cap. Applies the same
|
|
101
|
+
// reserve logic but compares against the per-phase cap.
|
|
102
|
+
if (typeof budget.perPhaseUSD === 'number' && reserveApplied > budget.perPhaseUSD) {
|
|
103
|
+
const decision = nonInteractive ? 'hard-fail' : 'pause';
|
|
104
|
+
return {
|
|
105
|
+
decision,
|
|
106
|
+
phase: phaseName,
|
|
107
|
+
phaseIdx,
|
|
108
|
+
estimatedHigh,
|
|
109
|
+
actualSoFar: actualSoFarUSD,
|
|
110
|
+
reserveApplied,
|
|
111
|
+
capRemaining,
|
|
112
|
+
reason: `per-phase cap exceeded — reserve $${fmtUSD(reserveApplied)} > ` +
|
|
113
|
+
`perPhaseUSD $${fmtUSD(budget.perPhaseUSD)}`,
|
|
114
|
+
scope,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
decision: 'proceed',
|
|
119
|
+
phase: phaseName,
|
|
120
|
+
phaseIdx,
|
|
121
|
+
estimatedHigh,
|
|
122
|
+
actualSoFar: actualSoFarUSD,
|
|
123
|
+
reserveApplied,
|
|
124
|
+
capRemaining,
|
|
125
|
+
reason: estimatedHigh !== null
|
|
126
|
+
? `within budget — projected $${fmtUSD(projected)} of $${fmtUSD(budget.perRunUSD)}`
|
|
127
|
+
: `within budget (no estimate, applied $${fmtUSD(reserveApplied)} ` +
|
|
128
|
+
`reserve floor) — projected $${fmtUSD(projected)} of ` +
|
|
129
|
+
`$${fmtUSD(budget.perRunUSD)}`,
|
|
130
|
+
scope,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Format a USD amount with 2 decimal places for human-readable reasons.
|
|
134
|
+
* Kept local — the run-state module doesn't have a shared formatter and
|
|
135
|
+
* budget reasons are the only consumer. */
|
|
136
|
+
function fmtUSD(n) {
|
|
137
|
+
// toFixed(2) returns "0.00" for 0; we keep the trailing zeros so the
|
|
138
|
+
// reason strings line up visually in CLI output.
|
|
139
|
+
return n.toFixed(2);
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Result of a single internal-CLI invocation. The dispatcher in
|
|
2
|
+
* src/cli/index.ts converts this to an exit code + console output. Pure
|
|
3
|
+
* data so we can unit-test the dispatch shape without spawning a child. */
|
|
4
|
+
export interface RunInternalCliResult {
|
|
5
|
+
/** Process exit code. */
|
|
6
|
+
exit: number;
|
|
7
|
+
/** Lines to print on stdout (text mode only). */
|
|
8
|
+
stdout: string[];
|
|
9
|
+
/** Lines to print on stderr (text mode only). */
|
|
10
|
+
stderr: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface RunInternalCliOptions {
|
|
13
|
+
/** argv after `claude-autopilot internal`. e.g. ['log-phase-event',
|
|
14
|
+
* '--run-id', '01HZK', '--event', '{...}']. */
|
|
15
|
+
args: string[];
|
|
16
|
+
/** Working directory containing `.guardrail-cache/runs/`. Defaults to
|
|
17
|
+
* process.cwd(). */
|
|
18
|
+
cwd?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function runInternalCli(opts: RunInternalCliOptions): Promise<RunInternalCliResult>;
|
|
21
|
+
//# sourceMappingURL=cli-internal.d.ts.map
|