@delegance/claude-autopilot 5.2.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 +1027 -1
- package/README.md +104 -17
- package/dist/src/adapters/council/claude.js +2 -1
- package/dist/src/adapters/council/openai.js +14 -7
- 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/generic.d.ts +39 -0
- package/dist/src/adapters/deploy/generic.js +98 -0
- package/dist/src/adapters/deploy/index.d.ts +15 -0
- package/dist/src/adapters/deploy/index.js +78 -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 +221 -0
- package/dist/src/adapters/deploy/types.js +15 -0
- package/dist/src/adapters/deploy/vercel.d.ts +143 -0
- package/dist/src/adapters/deploy/vercel.js +426 -0
- package/dist/src/adapters/pricing.d.ts +36 -0
- package/dist/src/adapters/pricing.js +40 -0
- package/dist/src/adapters/review-engine/claude.js +2 -1
- package/dist/src/adapters/review-engine/codex.js +12 -8
- package/dist/src/adapters/review-engine/gemini.js +2 -1
- package/dist/src/adapters/review-engine/openai-compatible.js +2 -1
- package/dist/src/adapters/sdk-loader.d.ts +15 -0
- package/dist/src/adapters/sdk-loader.js +77 -0
- 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 +71 -0
- package/dist/src/cli/deploy.js +539 -0
- 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 +784 -222
- 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 +102 -1
- 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 +43 -0
- package/dist/src/core/config/schema.js +25 -0
- package/dist/src/core/config/types.d.ts +17 -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 +12 -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/detector-rules.js +6 -0
- package/dist/src/core/migrate/schema-validator.js +22 -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 +9 -5
- package/scripts/autoregress.ts +3 -2
- package/skills/claude-autopilot.md +1 -1
- package/skills/make-interfaces-feel-better/SKILL.md +104 -0
- package/skills/migrate/SKILL.md +193 -47
- 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,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
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// src/core/run-state/cli-internal.ts
|
|
2
|
+
//
|
|
3
|
+
// Hidden CLI verb: `claude-autopilot internal log-phase-event`.
|
|
4
|
+
//
|
|
5
|
+
// Markdown-driven skills (brainstorm, plan, implement) can't directly import
|
|
6
|
+
// the run-state module — they spawn `claude-autopilot` as a subprocess. This
|
|
7
|
+
// helper gives them a one-shot way to append a typed event into a known run
|
|
8
|
+
// without rewriting the skills as TypeScript modules.
|
|
9
|
+
//
|
|
10
|
+
// Surface:
|
|
11
|
+
//
|
|
12
|
+
// claude-autopilot internal log-phase-event \
|
|
13
|
+
// --run-id 01HZK7... \
|
|
14
|
+
// --event '<json>' \
|
|
15
|
+
// [--cwd /path/to/repo]
|
|
16
|
+
//
|
|
17
|
+
// `<json>` is the RunEventInput shape (no seq/ts/runId/schema_version/
|
|
18
|
+
// writerId — the appender fills those in). Examples:
|
|
19
|
+
//
|
|
20
|
+
// --event '{"event":"phase.cost","phase":"plan","phaseIdx":1,
|
|
21
|
+
// "provider":"anthropic","inputTokens":1200,
|
|
22
|
+
// "outputTokens":3400,"costUSD":0.07}'
|
|
23
|
+
//
|
|
24
|
+
// The verb is HIDDEN — not in HELP_GROUPS, not in HELP_VERBS, not in the
|
|
25
|
+
// welcome text. It is documented only via `claude-autopilot internal --help`
|
|
26
|
+
// for diagnostics.
|
|
27
|
+
//
|
|
28
|
+
// Spec: docs/specs/v6-run-state-engine.md "Phase contract" — the markdown
|
|
29
|
+
// skills shell out to write events.
|
|
30
|
+
import * as path from 'node:path';
|
|
31
|
+
import { GuardrailError } from "../errors.js";
|
|
32
|
+
import { appendEvent } from "./events.js";
|
|
33
|
+
import { makeWriterId } from "./lock.js";
|
|
34
|
+
import { runDirFor } from "./runs.js";
|
|
35
|
+
const HELP_TEXT = `
|
|
36
|
+
Usage: claude-autopilot internal <verb> [options]
|
|
37
|
+
|
|
38
|
+
Internal / diagnostic verbs. NOT for end-user use — these are called by
|
|
39
|
+
markdown-driven skills (brainstorm, plan, implement) that can't import the
|
|
40
|
+
run-state TS module directly. Surface stability is best-effort; do NOT
|
|
41
|
+
script against this in user-facing code.
|
|
42
|
+
|
|
43
|
+
Verbs:
|
|
44
|
+
log-phase-event Append a typed event to a run's events.ndjson
|
|
45
|
+
|
|
46
|
+
Options (log-phase-event):
|
|
47
|
+
--run-id <id> Required. ULID of the run to append to.
|
|
48
|
+
--event <json> Required. RunEventInput JSON (no seq/ts/runId — those
|
|
49
|
+
are filled in by the appender).
|
|
50
|
+
--cwd <path> Optional. Repo root containing .guardrail-cache/runs/.
|
|
51
|
+
Defaults to the current working directory.
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
|
|
55
|
+
claude-autopilot internal log-phase-event \\
|
|
56
|
+
--run-id 01HZK7XXXXXXXXXXXXXXXXXXXX \\
|
|
57
|
+
--event '{"event":"phase.cost","phase":"plan","phaseIdx":1,
|
|
58
|
+
"provider":"anthropic","inputTokens":1200,
|
|
59
|
+
"outputTokens":3400,"costUSD":0.07}'
|
|
60
|
+
`;
|
|
61
|
+
/** Parse argv pairs of the form `--name <value>`. Multi-value not supported
|
|
62
|
+
* here — there is exactly one value per flag. Returns undefined when the
|
|
63
|
+
* flag is missing, throws when the flag is present but its value is missing
|
|
64
|
+
* or starts with another `--`. */
|
|
65
|
+
function readFlag(args, name) {
|
|
66
|
+
const idx = args.indexOf(`--${name}`);
|
|
67
|
+
if (idx < 0)
|
|
68
|
+
return undefined;
|
|
69
|
+
const val = args[idx + 1];
|
|
70
|
+
if (val === undefined || val.startsWith('--')) {
|
|
71
|
+
throw new GuardrailError(`--${name} requires a value`, { code: 'user_input', provider: 'cli', details: { flag: name } });
|
|
72
|
+
}
|
|
73
|
+
return val;
|
|
74
|
+
}
|
|
75
|
+
export async function runInternalCli(opts) {
|
|
76
|
+
const args = opts.args;
|
|
77
|
+
const verb = args[0];
|
|
78
|
+
if (!verb || verb === '--help' || verb === '-h' || verb === 'help') {
|
|
79
|
+
return { exit: 0, stdout: [HELP_TEXT.trimStart()], stderr: [] };
|
|
80
|
+
}
|
|
81
|
+
if (verb !== 'log-phase-event') {
|
|
82
|
+
return {
|
|
83
|
+
exit: 1,
|
|
84
|
+
stdout: [],
|
|
85
|
+
stderr: [
|
|
86
|
+
`[claude-autopilot] internal: unknown verb "${verb}"`,
|
|
87
|
+
HELP_TEXT.trimStart(),
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// log-phase-event
|
|
92
|
+
let runId;
|
|
93
|
+
let eventJson;
|
|
94
|
+
let cwdOverride;
|
|
95
|
+
try {
|
|
96
|
+
runId = readFlag(args, 'run-id');
|
|
97
|
+
eventJson = readFlag(args, 'event');
|
|
98
|
+
cwdOverride = readFlag(args, 'cwd');
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
return {
|
|
102
|
+
exit: 1,
|
|
103
|
+
stdout: [],
|
|
104
|
+
stderr: [`[claude-autopilot] internal: ${err.message}`],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (!runId) {
|
|
108
|
+
return {
|
|
109
|
+
exit: 1,
|
|
110
|
+
stdout: [],
|
|
111
|
+
stderr: [`[claude-autopilot] internal: --run-id is required`],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (!eventJson) {
|
|
115
|
+
return {
|
|
116
|
+
exit: 1,
|
|
117
|
+
stdout: [],
|
|
118
|
+
stderr: [`[claude-autopilot] internal: --event is required`],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
let parsed;
|
|
122
|
+
try {
|
|
123
|
+
parsed = JSON.parse(eventJson);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
return {
|
|
127
|
+
exit: 1,
|
|
128
|
+
stdout: [],
|
|
129
|
+
stderr: [
|
|
130
|
+
`[claude-autopilot] internal: --event is not valid JSON: ${err.message}`,
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (!parsed || typeof parsed !== 'object' || typeof parsed.event !== 'string') {
|
|
135
|
+
return {
|
|
136
|
+
exit: 1,
|
|
137
|
+
stdout: [],
|
|
138
|
+
stderr: [
|
|
139
|
+
`[claude-autopilot] internal: --event must be an object with an "event" string field`,
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const cwd = cwdOverride ? path.resolve(cwdOverride) : (opts.cwd ?? process.cwd());
|
|
144
|
+
const runDir = runDirFor(cwd, runId);
|
|
145
|
+
// Best-effort writerId. The internal verb does NOT take the run's lock —
|
|
146
|
+
// the markdown skill that calls it is operating "out-of-band" of any
|
|
147
|
+
// currently-held lock by design (skills can't hold a lock across multiple
|
|
148
|
+
// bash invocations). Stamping the writerId of the calling process keeps
|
|
149
|
+
// the event auditable even though it sidesteps the single-writer
|
|
150
|
+
// invariant. Phase 6 may add a `--writer-id <id>` flag for stricter
|
|
151
|
+
// attribution; Phase 2 keeps the surface minimal.
|
|
152
|
+
const writerId = makeWriterId();
|
|
153
|
+
let appended;
|
|
154
|
+
try {
|
|
155
|
+
appended = appendEvent(runDir, parsed, { writerId, runId });
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
return {
|
|
159
|
+
exit: 1,
|
|
160
|
+
stdout: [],
|
|
161
|
+
stderr: [
|
|
162
|
+
`[claude-autopilot] internal: appendEvent failed: ${err.message}`,
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
exit: 0,
|
|
168
|
+
stdout: [
|
|
169
|
+
`[claude-autopilot] internal: appended seq=${appended.seq} event=${appended.event} runId=${runId}`,
|
|
170
|
+
],
|
|
171
|
+
stderr: [],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=cli-internal.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type RunEvent, type RunEventInput, type RunIndexEntry, type RunState, type WriterId } from './types.ts';
|
|
2
|
+
export declare function eventsPath(runDir: string): string;
|
|
3
|
+
export interface ReadEventsOptions {
|
|
4
|
+
/** Skip events with seq < this value. */
|
|
5
|
+
fromSeq?: number;
|
|
6
|
+
/** Return only the last N events. Applied after `fromSeq` filter. */
|
|
7
|
+
tail?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ReadEventsResult {
|
|
10
|
+
events: RunEvent[];
|
|
11
|
+
/** True if the last line of the file was a partial JSON write and was
|
|
12
|
+
* ignored. The next append should emit a `run.recovery` event. */
|
|
13
|
+
truncatedTail: boolean;
|
|
14
|
+
/** Highest seq observed in the file (after dropping a truncated tail). */
|
|
15
|
+
maxSeq: number;
|
|
16
|
+
}
|
|
17
|
+
/** Stream all events from disk. Detects partial-JSON tail and signals
|
|
18
|
+
* recovery via `truncatedTail`. Does NOT throw on individual line parse
|
|
19
|
+
* errors that are NOT the last line — those produce a `partial_write`
|
|
20
|
+
* GuardrailError because mid-log corruption is unrecoverable here. */
|
|
21
|
+
export declare function readEvents(runDir: string, opts?: ReadEventsOptions): ReadEventsResult;
|
|
22
|
+
/** Read just the highest seq from disk. Prefers the sidecar; falls back to
|
|
23
|
+
* rescanning the events file. */
|
|
24
|
+
export declare function readMaxSeq(runDir: string): number;
|
|
25
|
+
export interface AppendEventOptions {
|
|
26
|
+
/** Override the runId stamped onto the event. Required for runs whose
|
|
27
|
+
* ID isn't derivable from the runDir (almost never; we accept it for
|
|
28
|
+
* test fixtures). */
|
|
29
|
+
runId?: string;
|
|
30
|
+
writerId: WriterId;
|
|
31
|
+
}
|
|
32
|
+
/** Append a single event to events.ndjson. Strict ordering:
|
|
33
|
+
* 1. open(O_APPEND), write line, fsync(fd), close.
|
|
34
|
+
* 2. Update sidecar with new seq (best-effort).
|
|
35
|
+
*
|
|
36
|
+
* Returns the fully-formed RunEvent that landed on disk (with seq, ts,
|
|
37
|
+
* schema_version, etc. filled in).
|
|
38
|
+
*
|
|
39
|
+
* This is the ONLY supported way to append. Bypassing it with raw fs writes
|
|
40
|
+
* will desync the seq sidecar and may break recovery. */
|
|
41
|
+
export declare function appendEvent(runDir: string, input: RunEventInput, opts: AppendEventOptions): RunEvent;
|
|
42
|
+
/** Replay events.ndjson into a fresh RunState snapshot. The events file is
|
|
43
|
+
* the source of truth — this is always callable; if the file is missing or
|
|
44
|
+
* empty, the result is a minimal "pending" state with no phases.
|
|
45
|
+
*
|
|
46
|
+
* Throws GuardrailError(corrupted_state) if the log has internal
|
|
47
|
+
* contradictions that prevent a coherent snapshot (e.g. seq gaps,
|
|
48
|
+
* phase.success without a prior phase.start), OR if the persisted
|
|
49
|
+
* `schema_version` falls outside this binary's supported window
|
|
50
|
+
* (`RUN_STATE_MIN_SUPPORTED_SCHEMA_VERSION..RUN_STATE_MAX_SUPPORTED_SCHEMA_VERSION`).
|
|
51
|
+
* Per v6.2.2 spec — the prior shape would fail with a cryptic
|
|
52
|
+
* `cannot read property 'phases' of undefined` instead of an actionable
|
|
53
|
+
* "this run dir is from a newer/older version" message. */
|
|
54
|
+
export declare function replayState(runDir: string): RunState;
|
|
55
|
+
export declare function foldEvents(runDir: string, events: RunEvent[]): RunState;
|
|
56
|
+
/** Fold an in-memory state into a list-row used by `runs list`. Lives here
|
|
57
|
+
* because it's a pure projection over RunState — no IO, no side effects. */
|
|
58
|
+
export declare function stateToIndexEntry(state: RunState, recovered?: boolean): RunIndexEntry;
|
|
59
|
+
//# sourceMappingURL=events.d.ts.map
|