@delegance/claude-autopilot 5.5.2 → 7.2.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 +1776 -6
- package/README.md +65 -1
- package/bin/_launcher.js +38 -23
- 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 +75 -0
- package/dist/src/cli/autopilot.js +750 -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/dashboard/index.d.ts +5 -0
- package/dist/src/cli/dashboard/index.js +49 -0
- package/dist/src/cli/dashboard/login.d.ts +22 -0
- package/dist/src/cli/dashboard/login.js +260 -0
- package/dist/src/cli/dashboard/logout.d.ts +12 -0
- package/dist/src/cli/dashboard/logout.js +45 -0
- package/dist/src/cli/dashboard/status.d.ts +30 -0
- package/dist/src/cli/dashboard/status.js +65 -0
- package/dist/src/cli/dashboard/upload.d.ts +16 -0
- package/dist/src/cli/dashboard/upload.js +48 -0
- package/dist/src/cli/deploy.d.ts +3 -3
- package/dist/src/cli/deploy.js +34 -9
- package/dist/src/cli/engine-flag-deprecation.d.ts +14 -0
- package/dist/src/cli/engine-flag-deprecation.js +20 -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 +416 -0
- package/dist/src/cli/implement.d.ts +91 -0
- package/dist/src/cli/implement.js +196 -0
- package/dist/src/cli/index.d.ts +2 -1
- package/dist/src/cli/index.js +774 -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/scaffold.d.ts +39 -0
- package/dist/src/cli/scaffold.js +287 -0
- package/dist/src/cli/scan.d.ts +93 -0
- package/dist/src/cli/scan.js +166 -40
- package/dist/src/cli/setup.d.ts +30 -0
- package/dist/src/cli/setup.js +137 -0
- 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 +512 -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 +45 -0
- package/dist/src/core/run-state/resolve-engine.js +74 -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 +69 -0
- package/dist/src/core/run-state/run-phase-with-lifecycle.js +193 -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 +284 -0
- package/dist/src/core/run-state/types.js +19 -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/dist/src/dashboard/auto-upload.d.ts +26 -0
- package/dist/src/dashboard/auto-upload.js +107 -0
- package/dist/src/dashboard/config.d.ts +22 -0
- package/dist/src/dashboard/config.js +109 -0
- package/dist/src/dashboard/upload/canonical.d.ts +3 -0
- package/dist/src/dashboard/upload/canonical.js +16 -0
- package/dist/src/dashboard/upload/chain.d.ts +9 -0
- package/dist/src/dashboard/upload/chain.js +27 -0
- package/dist/src/dashboard/upload/snapshot.d.ts +23 -0
- package/dist/src/dashboard/upload/snapshot.js +66 -0
- package/dist/src/dashboard/upload/uploader.d.ts +54 -0
- package/dist/src/dashboard/upload/uploader.js +330 -0
- package/package.json +19 -3
- package/scripts/autoregress.ts +1 -1
- package/scripts/test-runner.mjs +4 -0
- 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
package/README.md
CHANGED
|
@@ -4,7 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
**Autonomous development pipeline for Claude Code. Brainstorm → spec → plan → implement → migrate → validate → PR → review → merge — all from your terminal, on your codebase, with your test suite.**
|
|
6
6
|
|
|
7
|
-
**Open source, MIT-licensed, runs on your machine with your API keys.** No hosted agent, no per-seat subscription — `npm install -g @delegance/claude-autopilot` and you're done.
|
|
7
|
+
**Open source, MIT-licensed, runs on your machine with your API keys.** No hosted agent, no per-seat subscription — `npm install -g @delegance/claude-autopilot@latest` and you're done.
|
|
8
|
+
|
|
9
|
+
## Hosted product (v7)
|
|
10
|
+
|
|
11
|
+
A hosted dashboard at **[autopilot.dev](https://autopilot.dev)** complements the self-hosted CLI. The CLI keeps doing all the work locally on your machine — running models, writing code, opening PRs — and optionally uploads each completed run's state + cost summary to the hosted dashboard so your team can see what's been shipped, audit cost, and manage memberships from the browser.
|
|
12
|
+
|
|
13
|
+
- **CLI (this package)** — local-first, no telemetry by default, your machine + your API keys. Pipeline stays the same.
|
|
14
|
+
- **Dashboard ([autopilot.dev](https://autopilot.dev))** — opt-in. After `claude-autopilot dashboard login` mints a personal API key via a loopback OAuth flow, every engine-on autopilot run uploads its `state.json` + `events.ndjson` + cost roll-up at run.complete. Org admin (members, billing, SSO) lives there.
|
|
15
|
+
|
|
16
|
+
The CLI works offline; the dashboard is purely additive. See [docs/v7/runbook.md](./docs/v7/runbook.md) for operating the hosted product and [docs/v7/breaking-changes.md](./docs/v7/breaking-changes.md) for the v6→v7 migration checklist.
|
|
8
17
|
|
|
9
18
|
```bash
|
|
10
19
|
claude-autopilot brainstorm "add SSO with SAML for enterprise tenants"
|
|
@@ -80,6 +89,34 @@ claude-autopilot brainstorm "add rate limiting to the public API"
|
|
|
80
89
|
claude-autopilot run --pr 123
|
|
81
90
|
```
|
|
82
91
|
|
|
92
|
+
## Run State Engine (v6)
|
|
93
|
+
|
|
94
|
+
Persistent state for autopilot runs. Resume after crashes, enforce hard budget caps, and surface typed JSON events for CI consumers — all opt-in, all on disk.
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
# guardrail.config.yaml
|
|
98
|
+
engine:
|
|
99
|
+
enabled: true # default in v6.1+; explicit `false` is deprecated and removed in v7
|
|
100
|
+
budgets:
|
|
101
|
+
perRunUSD: 10 # hard stop; mandatory runtime guard
|
|
102
|
+
perPhaseUSD: 5
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
claude-autopilot scan --all # any command — engine writes a per-run dir
|
|
107
|
+
claude-autopilot runs list # newest-first, with status / cost / lastPhase
|
|
108
|
+
claude-autopilot runs show 01HZK7P3D8Q9V… # state snapshot + optional event tail
|
|
109
|
+
claude-autopilot run resume 01HZK7P3D8Q9V… # lookup-only today; live execution in a later v6.x
|
|
110
|
+
claude-autopilot runs gc --older-than-days 7 # retire completed runs
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Every state transition appends a typed event to `.guardrail-cache/runs/<ulid>/events.ndjson`; every CLI verb supports `--json` with strict stdout-envelope / stderr-NDJSON channel discipline. Side-effect phase replay consults persisted `externalRefs` plus a live provider read-back so resume is safe by construction.
|
|
114
|
+
|
|
115
|
+
**v6.1+ ships with the engine ON by default** (flipped from v6.0's off-by-default after the stabilization criteria in [`docs/specs/v6.1-default-flip.md`](docs/specs/v6.1-default-flip.md) were met). Users who want the legacy v5.x output shape can opt out for one minor version via `--no-engine`, `CLAUDE_AUTOPILOT_ENGINE=off`, or `engine.enabled: false` — each prints a deprecation warning and is removed in v7.
|
|
116
|
+
|
|
117
|
+
→ [`docs/v6/quickstart.md`](docs/v6/quickstart.md) — five-minute setup
|
|
118
|
+
→ [`docs/v6/migration-guide.md`](docs/v6/migration-guide.md) — full v5.x → v6 walkthrough with precedence matrix, per-phase idempotency rules, and troubleshooting
|
|
119
|
+
|
|
83
120
|
## The pipeline, phase by phase
|
|
84
121
|
|
|
85
122
|
Each phase is a Claude Code skill (`.claude/skills/<name>/SKILL.md`). You can invoke any phase directly (`/brainstorm`, `/plan`, `/migrate`, `/validate`) without running the full pipeline. You can also rewire the pipeline by editing the `autopilot` skill.
|
|
@@ -96,6 +133,7 @@ Each phase is a Claude Code skill (`.claude/skills/<name>/SKILL.md`). You can in
|
|
|
96
133
|
| **PR** | `commit-push-pr` | Opens the PR with auto-generated title, summary, and test plan | Claude |
|
|
97
134
|
| **Review** | `review-2pass` / `council` | Multi-model review of the diff (critical pass + informational pass) | Multiple |
|
|
98
135
|
| **Triage** | `bugbot` | Fetches automated reviewer findings, auto-fixes real bugs, dismisses false positives | Claude |
|
|
136
|
+
| **Deploy** | `deploy` | Deploys via configured adapter (`vercel` \| `fly` \| `render` \| `generic`) with optional log streaming, health check, and bounded auto-rollback (see [Deploy phase](#deploy-phase)) | Deterministic |
|
|
99
137
|
|
|
100
138
|
### Migrate phase
|
|
101
139
|
|
|
@@ -116,6 +154,32 @@ migrate:
|
|
|
116
154
|
|
|
117
155
|
See `skills/migrate/SKILL.md` for examples covering Alembic, Django, Prisma, Drizzle, golang-migrate, dbmate, flyway, and custom scripts.
|
|
118
156
|
|
|
157
|
+
### Deploy phase
|
|
158
|
+
|
|
159
|
+
Configure your deploy target in `guardrail.config.yaml` under a `deploy:` block. Four adapters ship in 5.6:
|
|
160
|
+
|
|
161
|
+
- **`vercel`** — Vercel v13 deployments API. SSE+NDJSON log streaming, native rollback via `/promote`. Auth: `VERCEL_TOKEN`.
|
|
162
|
+
- **`fly`** — Fly.io Machines API. WebSocket log streaming, native rollback with simulated fallback. Auth: `FLY_API_TOKEN`. Requires the image to be pre-pushed (`fly deploy --build-only --push`).
|
|
163
|
+
- **`render`** — Render REST API. Polling-based log stream with `(timestamp, logId)` cursor dedup, simulated rollback (re-deploys prior commit). Auth: `RENDER_API_KEY`.
|
|
164
|
+
- **`generic`** — runs any shell `deployCommand` (`vercel --prod`, `kubectl apply`, `make deploy`, etc). No platform integration; `--watch` and `rollback` aren't supported.
|
|
165
|
+
|
|
166
|
+
Each adapter speaks the same `DeployAdapter` contract: `deploy()`, optional `status()` / `rollback()` / `streamLogs()`, plus a `capabilities` block (`streamMode: 'websocket' | 'polling' | 'none'`, `nativeRollback: boolean`) so the CLI can degrade UX honestly (polling adapters print a one-line stderr notice under `--watch`). Auto-rollback is bounded: max one rollback per deploy attempt, with `runHealthCheck` capped at 5×6s. Log lines emitted into PR comments run through a redaction pass (`AKIA…`, `sk-…`, `eyJ…`, `ghp_`, `xoxb-`, plus configurable patterns) so build output can't leak secrets.
|
|
167
|
+
|
|
168
|
+
Example (Fly):
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
deploy:
|
|
172
|
+
adapter: fly
|
|
173
|
+
app: my-app
|
|
174
|
+
image: registry.fly.io/my-app:latest
|
|
175
|
+
region: ord
|
|
176
|
+
watchBuildLogs: true
|
|
177
|
+
healthCheckUrl: https://my-app.fly.dev/health
|
|
178
|
+
rollbackOn: [healthCheckFailure]
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`claude-autopilot doctor` checks for the relevant auth env var when an adapter is configured. See `docs/specs/v5.6-fly-render-adapters.md` for the full adapter contract.
|
|
182
|
+
|
|
119
183
|
## What's distinctive
|
|
120
184
|
|
|
121
185
|
Features that are hard or impossible to find in the competitive set:
|
package/bin/_launcher.js
CHANGED
|
@@ -31,44 +31,52 @@ function findTsx() {
|
|
|
31
31
|
return 'tsx';
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
// v7.1.7 — Per-calendar-day deprecation dedup, keyed in the user's home dir.
|
|
35
|
+
//
|
|
36
|
+
// The previous (v6.3+) implementation used a temp file keyed by `process.ppid
|
|
37
|
+
// + stderr.isTTY` to dedup once per "terminal session." That worked in
|
|
38
|
+
// interactive shells but FAILED for the most common deprecation trigger —
|
|
39
|
+
// the pre-commit/pre-push git hooks. Git spawns a fresh shell for each hook
|
|
40
|
+
// invocation, so the parent PID is fresh on every commit, the stamp file
|
|
41
|
+
// path is unique each time, and the notice printed on every single commit.
|
|
42
|
+
// The v7.1.6 blank-repo benchmark agent surfaced this as the #1 paper cut.
|
|
43
|
+
//
|
|
44
|
+
// New strategy: stamp at `~/.claude-autopilot/.deprecation-shown`, contents =
|
|
45
|
+
// `YYYY-MM-DD` (UTC). Show at most once per day per machine. Operator gets a
|
|
46
|
+
// daily reminder of the rename without per-commit spam. Override env vars
|
|
47
|
+
// (`CLAUDE_AUTOPILOT_DEPRECATION=always|never`) preserved.
|
|
48
|
+
const DEPRECATION_STAMP_PATH = path.join(os.homedir(), '.claude-autopilot', '.deprecation-shown');
|
|
49
|
+
function todayUtc() {
|
|
50
|
+
return new Date().toISOString().slice(0, 10);
|
|
51
|
+
}
|
|
52
|
+
function hasShownDeprecationToday() {
|
|
39
53
|
try {
|
|
40
|
-
if (!fs.existsSync(
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
const key = `${process.ppid}-${process.stderr.isTTY ? 'tty' : 'pipe'}.stamp`;
|
|
44
|
-
const stampPath = path.join(DEPRECATION_STAMP_DIR, key);
|
|
45
|
-
if (fs.existsSync(stampPath)) return true;
|
|
46
|
-
fs.writeFileSync(stampPath, String(Date.now()));
|
|
47
|
-
// Best-effort cleanup of stamps older than 1h to keep tmpdir tidy.
|
|
48
|
-
const cutoff = Date.now() - 60 * 60 * 1000;
|
|
49
|
-
for (const f of fs.readdirSync(DEPRECATION_STAMP_DIR)) {
|
|
50
|
-
const p = path.join(DEPRECATION_STAMP_DIR, f);
|
|
51
|
-
try {
|
|
52
|
-
if (fs.statSync(p).mtimeMs < cutoff) fs.unlinkSync(p);
|
|
53
|
-
} catch { /* ignore */ }
|
|
54
|
-
}
|
|
55
|
-
return false;
|
|
54
|
+
if (!fs.existsSync(DEPRECATION_STAMP_PATH)) return false;
|
|
55
|
+
return fs.readFileSync(DEPRECATION_STAMP_PATH, 'utf8').trim() === todayUtc();
|
|
56
56
|
} catch {
|
|
57
|
+
// Stamp unreadable — show notice (better than silently swallowing).
|
|
57
58
|
return false;
|
|
58
59
|
}
|
|
59
60
|
}
|
|
61
|
+
function markDeprecationShown() {
|
|
62
|
+
try {
|
|
63
|
+
const dir = path.dirname(DEPRECATION_STAMP_PATH);
|
|
64
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
65
|
+
fs.writeFileSync(DEPRECATION_STAMP_PATH, todayUtc());
|
|
66
|
+
} catch { /* best-effort; missing stamp re-prints next invocation */ }
|
|
67
|
+
}
|
|
60
68
|
|
|
61
69
|
/**
|
|
62
70
|
* Decide whether to emit the deprecation notice. Order:
|
|
63
71
|
* CLAUDE_AUTOPILOT_DEPRECATION=never → never emit (CI/automation)
|
|
64
72
|
* CLAUDE_AUTOPILOT_DEPRECATION=always → always emit (deterministic testing)
|
|
65
|
-
* otherwise → once per
|
|
73
|
+
* otherwise → at most once per UTC day
|
|
66
74
|
*/
|
|
67
75
|
function shouldEmitDeprecation() {
|
|
68
76
|
const override = process.env.CLAUDE_AUTOPILOT_DEPRECATION;
|
|
69
77
|
if (override === 'never') return false;
|
|
70
78
|
if (override === 'always') return true;
|
|
71
|
-
return !
|
|
79
|
+
return !hasShownDeprecationToday();
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
/**
|
|
@@ -83,6 +91,13 @@ export function launch(opts) {
|
|
|
83
91
|
'Migration guide: https://github.com/axledbetter/claude-autopilot/blob/master/docs/migration/v4-to-v5.md\n' +
|
|
84
92
|
'Silence: set CLAUDE_AUTOPILOT_DEPRECATION=never\n',
|
|
85
93
|
);
|
|
94
|
+
// v7.1.7 — mark stamp AFTER successful emission so a write-failure on
|
|
95
|
+
// stderr still results in the next invocation re-trying. Skip when
|
|
96
|
+
// CLAUDE_AUTOPILOT_DEPRECATION=always (deterministic-testing override
|
|
97
|
+
// shouldn't write the stamp).
|
|
98
|
+
if (process.env.CLAUDE_AUTOPILOT_DEPRECATION !== 'always') {
|
|
99
|
+
markDeprecationShown();
|
|
100
|
+
}
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
const entry = resolveEntry();
|
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
import { GuardrailError } from "../../core/errors.js";
|
|
2
2
|
import { classifyError } from "../review-engine/prompt-builder.js";
|
|
3
3
|
import { loadOpenAI } from "../sdk-loader.js";
|
|
4
|
+
import { getModelPricing } from "../pricing.js";
|
|
4
5
|
const SYSTEM_PROMPT = `You are a technical advisor reviewing a software design decision. Evaluate the provided context and question critically. Be direct and specific. Surface tradeoffs, risks, and your recommendation.`;
|
|
5
6
|
const MAX_OUTPUT_TOKENS = 2048;
|
|
6
7
|
// Models that ONLY work via the Responses API (not chat.completions).
|
|
7
8
|
// Codex variants and the o-series reasoning models all 404 on chat.completions.
|
|
8
|
-
// Without this branch, putting `gpt-5.3-codex` (the
|
|
9
|
+
// Without this branch, putting `gpt-5.3-codex` (the prior default) in
|
|
9
10
|
// council.models throws model_not_found, AND the synthesizer (also typically
|
|
10
|
-
//
|
|
11
|
+
// the same model) fails the same way — so the whole council returns `partial`
|
|
11
12
|
// with no synthesis. That regression made the marketed multi-model differentiator
|
|
12
13
|
// unusable for any user who only had OPENAI_API_KEY.
|
|
14
|
+
// gpt-5.5 (the new default, 2026-04-23) drops the `-codex` suffix and works
|
|
15
|
+
// via standard chat.completions, so it is intentionally NOT matched here.
|
|
13
16
|
function isResponsesOnlyModel(model) {
|
|
14
17
|
return /codex|^o[1-9]|^gpt-5\.3-/i.test(model);
|
|
15
18
|
}
|
|
16
|
-
// Per-million-token rates
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
// Per-million-token rates. Bugbot LOW PR #93: wired to read from the
|
|
20
|
+
// canonical MODEL_PRICING table (no longer dead code). Resolution order:
|
|
21
|
+
// env override → MODEL_PRICING entry for the council's default
|
|
22
|
+
// (gpt-5.5) → numeric fallback. Mirrors the review-engine codex adapter.
|
|
23
|
+
const _pricing = getModelPricing(process.env.CODEX_MODEL ?? 'gpt-5.5');
|
|
24
|
+
const COST_PER_M_INPUT = Number(process.env.CODEX_COST_INPUT_PER_M ?? _pricing?.inputPer1M ?? 5.0);
|
|
25
|
+
const COST_PER_M_OUTPUT = Number(process.env.CODEX_COST_OUTPUT_PER_M ?? _pricing?.outputPer1M ?? 30.0);
|
|
20
26
|
export function makeOpenAICouncilAdapter(model, label) {
|
|
21
27
|
return {
|
|
22
28
|
label,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for {@link fetchWithRetry}. `provider` is mandatory — it's the
|
|
3
|
+
* value baked into the `GuardrailError` thrown when retries exhaust, so
|
|
4
|
+
* callers must always identify themselves. `attempts`, `baseMs`, and
|
|
5
|
+
* `sleepImpl` are tuning knobs with sensible defaults that match the
|
|
6
|
+
* pre-extraction behavior of all three adapters.
|
|
7
|
+
*/
|
|
8
|
+
export interface FetchWithRetryOptions {
|
|
9
|
+
/** Adapter name baked into the GuardrailError thrown on exhaustion. */
|
|
10
|
+
provider: string;
|
|
11
|
+
/** Max attempts (inclusive). Default: 3. */
|
|
12
|
+
attempts?: number;
|
|
13
|
+
/** Base backoff in ms — exponential per attempt. Default: 500. */
|
|
14
|
+
baseMs?: number;
|
|
15
|
+
/** Injected sleep — adapters pass `this.sleep` so tests stay instant. */
|
|
16
|
+
sleepImpl?: (ms: number) => Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Free-function port of the per-adapter `fetchWithRetry` helper. Behavior
|
|
20
|
+
* is intentionally identical to the previous private copies:
|
|
21
|
+
* - 5xx responses are retried with exponential backoff (`baseMs * 2 ** i`).
|
|
22
|
+
* - 4xx responses are returned as-is so the per-adapter `assertOkOrThrow`
|
|
23
|
+
* can classify them precisely (auth vs not_found vs invalid_config).
|
|
24
|
+
* - Network errors are retried unless `AbortError`, which is rethrown so
|
|
25
|
+
* intentional cancellation is never silently retried.
|
|
26
|
+
* - On exhaustion, throws `GuardrailError({ code: 'transient_network',
|
|
27
|
+
* provider })` with the last error's message embedded.
|
|
28
|
+
*
|
|
29
|
+
* Adapters call this as `await fetchWithRetry(this.fetchImpl, url, init,
|
|
30
|
+
* { sleepImpl: this.sleep, provider: 'fly' })` — passing both the fetch
|
|
31
|
+
* implementation and the sleep impl explicitly keeps the adapter's
|
|
32
|
+
* `nowImpl`/`sleepImpl` injection points working for tests.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fetchWithRetry(fetchImpl: typeof fetch, url: string, init: RequestInit, opts: FetchWithRetryOptions): Promise<Response>;
|
|
35
|
+
/**
|
|
36
|
+
* Read at most 500 bytes of a `Response` body as text. Used by the
|
|
37
|
+
* per-adapter `assertOkOrThrow` helpers to embed the API's error body in
|
|
38
|
+
* the thrown `GuardrailError` for debugging without dumping multi-MB HTML
|
|
39
|
+
* pages. Returns `<no body>` if the body is unreadable (e.g. already
|
|
40
|
+
* consumed, network error mid-read).
|
|
41
|
+
*/
|
|
42
|
+
export declare function safeReadBody(res: Response): Promise<string>;
|
|
43
|
+
//# sourceMappingURL=_http.d.ts.map
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// src/adapters/deploy/_http.ts
|
|
2
|
+
//
|
|
3
|
+
// Shared HTTP plumbing extracted in v5.6 Phase 5 — see
|
|
4
|
+
// docs/specs/v5.6-fly-render-adapters.md § "Implementation phases".
|
|
5
|
+
//
|
|
6
|
+
// Three identical copies of `fetchWithRetry` and `safeReadBody` lived in
|
|
7
|
+
// `vercel.ts`, `fly.ts`, and `render.ts` before this module existed. Phase 5
|
|
8
|
+
// consolidates them as free functions so each adapter imports them as
|
|
9
|
+
// HTTP plumbing without `this` context. The deliberate decision (per the
|
|
10
|
+
// spec and PR #72 review) was to wait until a third copy materialized
|
|
11
|
+
// before reaching for shared abstractions, so each adapter's seam was
|
|
12
|
+
// settled.
|
|
13
|
+
//
|
|
14
|
+
// Out of scope on purpose:
|
|
15
|
+
// - `assertOkOrThrow` style HTTP-status mappers stay per-adapter. Each one
|
|
16
|
+
// composes a different error message (auth-token doc URL, 422 hint copy)
|
|
17
|
+
// and reads a different request-id header (`Fly-Request-Id` vs
|
|
18
|
+
// `x-request-id`). Sharing those would force a configuration object that's
|
|
19
|
+
// bigger than the function it replaces.
|
|
20
|
+
// - The Vercel `fetchEventsWithRetry` SSE helper is still adapter-private —
|
|
21
|
+
// it has different retry rules (404 race retried, 5xx retried with
|
|
22
|
+
// different shape) and returns the last response rather than throwing on
|
|
23
|
+
// exhaustion.
|
|
24
|
+
import { GuardrailError } from "../../core/errors.js";
|
|
25
|
+
const DEFAULT_SLEEP = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
26
|
+
/**
|
|
27
|
+
* Free-function port of the per-adapter `fetchWithRetry` helper. Behavior
|
|
28
|
+
* is intentionally identical to the previous private copies:
|
|
29
|
+
* - 5xx responses are retried with exponential backoff (`baseMs * 2 ** i`).
|
|
30
|
+
* - 4xx responses are returned as-is so the per-adapter `assertOkOrThrow`
|
|
31
|
+
* can classify them precisely (auth vs not_found vs invalid_config).
|
|
32
|
+
* - Network errors are retried unless `AbortError`, which is rethrown so
|
|
33
|
+
* intentional cancellation is never silently retried.
|
|
34
|
+
* - On exhaustion, throws `GuardrailError({ code: 'transient_network',
|
|
35
|
+
* provider })` with the last error's message embedded.
|
|
36
|
+
*
|
|
37
|
+
* Adapters call this as `await fetchWithRetry(this.fetchImpl, url, init,
|
|
38
|
+
* { sleepImpl: this.sleep, provider: 'fly' })` — passing both the fetch
|
|
39
|
+
* implementation and the sleep impl explicitly keeps the adapter's
|
|
40
|
+
* `nowImpl`/`sleepImpl` injection points working for tests.
|
|
41
|
+
*/
|
|
42
|
+
export async function fetchWithRetry(fetchImpl, url, init, opts) {
|
|
43
|
+
const attempts = opts.attempts ?? 3;
|
|
44
|
+
const baseMs = opts.baseMs ?? 500;
|
|
45
|
+
const sleep = opts.sleepImpl ?? DEFAULT_SLEEP;
|
|
46
|
+
let lastErr;
|
|
47
|
+
for (let i = 0; i < attempts; i++) {
|
|
48
|
+
try {
|
|
49
|
+
const res = await fetchImpl(url, init);
|
|
50
|
+
// 5xx is transient — retry. 4xx is the caller's problem — fail fast
|
|
51
|
+
// so the per-adapter error mapper can classify it precisely.
|
|
52
|
+
if (res.status >= 500 && res.status < 600 && i < attempts - 1) {
|
|
53
|
+
lastErr = new Error(`HTTP ${res.status}`);
|
|
54
|
+
await sleep(baseMs * 2 ** i);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
return res;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
lastErr = err;
|
|
61
|
+
// AbortError is intentional cancellation — surface it directly without
|
|
62
|
+
// retry. Wrapping or retrying would silently defeat caller-side
|
|
63
|
+
// cancellation.
|
|
64
|
+
if (err instanceof Error && err.name === 'AbortError')
|
|
65
|
+
throw err;
|
|
66
|
+
if (i < attempts - 1) {
|
|
67
|
+
await sleep(baseMs * 2 ** i);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
throw new GuardrailError(`${capitalize(opts.provider)} API unreachable after ${attempts} attempts: ${lastErr?.message ?? String(lastErr)}`, { code: 'transient_network', provider: opts.provider });
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Read at most 500 bytes of a `Response` body as text. Used by the
|
|
76
|
+
* per-adapter `assertOkOrThrow` helpers to embed the API's error body in
|
|
77
|
+
* the thrown `GuardrailError` for debugging without dumping multi-MB HTML
|
|
78
|
+
* pages. Returns `<no body>` if the body is unreadable (e.g. already
|
|
79
|
+
* consumed, network error mid-read).
|
|
80
|
+
*/
|
|
81
|
+
export async function safeReadBody(res) {
|
|
82
|
+
try {
|
|
83
|
+
return (await res.text()).slice(0, 500);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return '<no body>';
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Title-case the first letter of an adapter name so the exhaustion error
|
|
91
|
+
* reads "Vercel API unreachable…" instead of "vercel API unreachable…",
|
|
92
|
+
* matching the wording of the pre-extraction copies.
|
|
93
|
+
*/
|
|
94
|
+
function capitalize(s) {
|
|
95
|
+
if (!s)
|
|
96
|
+
return s;
|
|
97
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=_http.js.map
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import type { DeployAdapter, DeployAdapterCapabilities, DeployInput, DeployLogLine, DeployResult, DeployRollbackInput, DeployStatusInput, DeployStatusResult, DeployStreamLogsInput } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Fly release lifecycle states.
|
|
4
|
+
*
|
|
5
|
+
* The first three are terminal; the rest are interim. Fly's actual status
|
|
6
|
+
* vocabulary has evolved across the Nomad → Machines transition; this set
|
|
7
|
+
* is the conservative intersection that maps cleanly onto our
|
|
8
|
+
* `pass | fail | in-progress` tri-state. New states observed in the wild
|
|
9
|
+
* are treated as `in-progress` until the polling budget runs out.
|
|
10
|
+
*/
|
|
11
|
+
type FlyReleaseState = 'succeeded' | 'failed' | 'cancelled' | 'pending' | 'running' | 'starting';
|
|
12
|
+
interface FlyReleaseResponse {
|
|
13
|
+
id: string;
|
|
14
|
+
/** Public hostname (e.g. `my-app.fly.dev`) — Fly returns this on the release. */
|
|
15
|
+
hostname?: string;
|
|
16
|
+
/** Terminal/interim state. */
|
|
17
|
+
status?: FlyReleaseState;
|
|
18
|
+
/** Newer Fly responses use `state`; older use `status`. We accept either. */
|
|
19
|
+
state?: FlyReleaseState;
|
|
20
|
+
/**
|
|
21
|
+
* Image reference the release was built from (e.g.
|
|
22
|
+
* `registry.fly.io/my-app:deployment-01`). Surfaced on list-releases
|
|
23
|
+
* responses and used by the simulated-rollback path to re-deploy a
|
|
24
|
+
* known-good image when native `/rollback` is unavailable.
|
|
25
|
+
*/
|
|
26
|
+
image?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface FlyDeployAdapterOptions {
|
|
29
|
+
/** Personal access token. Falls back to `process.env.FLY_API_TOKEN`. */
|
|
30
|
+
token?: string;
|
|
31
|
+
/** Fly app slug. Required. */
|
|
32
|
+
app: string;
|
|
33
|
+
/**
|
|
34
|
+
* Image reference (e.g. `registry.fly.io/my-app:deployment-01`).
|
|
35
|
+
* Required — the adapter never builds; the user pushes via
|
|
36
|
+
* `fly deploy --build-only --push` or equivalent.
|
|
37
|
+
*/
|
|
38
|
+
image: string;
|
|
39
|
+
/** Optional region pin. Falls back to the app's default region. */
|
|
40
|
+
region?: string;
|
|
41
|
+
/** Polling interval (ms) when waiting for the release to reach a terminal state. Default: 2000. */
|
|
42
|
+
pollIntervalMs?: number;
|
|
43
|
+
/** Maximum total time to poll before returning `in-progress`. Default: 15 minutes. */
|
|
44
|
+
maxPollMs?: number;
|
|
45
|
+
/** Injected fetch implementation — defaults to `globalThis.fetch`. Tests pass a mock. */
|
|
46
|
+
fetchImpl?: typeof fetch;
|
|
47
|
+
/** Injected sleep implementation — tests pass a no-op so they don't actually wait. */
|
|
48
|
+
sleepImpl?: (ms: number) => Promise<void>;
|
|
49
|
+
/** Wall-clock source — tests pass a controllable counter. */
|
|
50
|
+
nowImpl?: () => number;
|
|
51
|
+
/**
|
|
52
|
+
* Optional caller-supplied redaction patterns (in addition to the
|
|
53
|
+
* built-in default set in `core/logging/redaction.ts`). Typically wired
|
|
54
|
+
* from `config.persistence.redactionPatterns` by the CLI; tests omit it.
|
|
55
|
+
*/
|
|
56
|
+
redactionPatterns?: readonly string[];
|
|
57
|
+
/**
|
|
58
|
+
* Injected WebSocket constructor for `streamLogs` — defaults to Node 22's
|
|
59
|
+
* built-in `globalThis.WebSocket`. Tests pass a stub that emulates the
|
|
60
|
+
* standard `addEventListener('message' | 'error' | 'close')` surface.
|
|
61
|
+
*
|
|
62
|
+
* Phase 3 of v5.6 — Fly streams build logs over WS with NDJSON-encoded
|
|
63
|
+
* messages. The adapter never imports a WS library; we rely on Node's
|
|
64
|
+
* built-in (Node 22+) for production and the injected stub for unit tests.
|
|
65
|
+
*/
|
|
66
|
+
wsImpl?: typeof WebSocket;
|
|
67
|
+
/**
|
|
68
|
+
* Optional override for the Fly log-streaming WebSocket URL builder.
|
|
69
|
+
* Defaults to the spec's stated path (see comment on `streamLogs` for
|
|
70
|
+
* the divergence-from-spec note that Phase 7 will reconcile against
|
|
71
|
+
* captured fixtures). Tests use this to point at a local stub.
|
|
72
|
+
*/
|
|
73
|
+
buildLogsWsUrl?: (app: string, releaseId: string) => string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Fly.io deploy adapter.
|
|
77
|
+
*
|
|
78
|
+
* Construct once per pipeline run. The adapter is stateless across calls —
|
|
79
|
+
* all configuration (token, app, image, region) is captured at construction
|
|
80
|
+
* time. Per the v5.6 spec, only `deploy()` and `status()` are wired in
|
|
81
|
+
* Phase 1; `streamLogs` (WebSocket) and `rollback` (native + simulated)
|
|
82
|
+
* land in Phases 3 and 4 respectively.
|
|
83
|
+
*/
|
|
84
|
+
export declare class FlyDeployAdapter implements DeployAdapter {
|
|
85
|
+
readonly name = "fly";
|
|
86
|
+
readonly capabilities: DeployAdapterCapabilities;
|
|
87
|
+
private readonly token;
|
|
88
|
+
private readonly app;
|
|
89
|
+
private readonly image;
|
|
90
|
+
private readonly region;
|
|
91
|
+
private readonly pollIntervalMs;
|
|
92
|
+
private readonly maxPollMs;
|
|
93
|
+
private readonly fetchImpl;
|
|
94
|
+
private readonly sleep;
|
|
95
|
+
private readonly now;
|
|
96
|
+
private readonly redactionPatterns;
|
|
97
|
+
private readonly wsImpl;
|
|
98
|
+
private readonly buildLogsWsUrlFn;
|
|
99
|
+
constructor(opts: FlyDeployAdapterOptions);
|
|
100
|
+
deploy(input: DeployInput): Promise<DeployResult>;
|
|
101
|
+
status(input: DeployStatusInput): Promise<DeployStatusResult>;
|
|
102
|
+
/**
|
|
103
|
+
* Phase 3 of v5.6 — subscribe to real-time build logs for a release via
|
|
104
|
+
* Fly's WebSocket log endpoint.
|
|
105
|
+
*
|
|
106
|
+
* Wire shape:
|
|
107
|
+
* - Connect to `wss://api.machines.dev/v1/apps/{app}/machines/{releaseId}/logs`
|
|
108
|
+
* (intent-level URL per the v5.6 spec's "Logs" bullet — exact path will
|
|
109
|
+
* be reconciled against captured fixtures in Phase 7; the `wsImpl` and
|
|
110
|
+
* `buildLogsWsUrl` injection points keep this overridable until then).
|
|
111
|
+
* - Each WS message is a single NDJSON line containing one log entry.
|
|
112
|
+
* Multiple lines per message are also tolerated (split on `\n`). Malformed
|
|
113
|
+
* JSON lines are skipped silently rather than crashing the iterator.
|
|
114
|
+
* - Auth via `Authorization: Bearer <FLY_API_TOKEN>` is passed through the
|
|
115
|
+
* `protocols` argument (Node's built-in WebSocket doesn't accept custom
|
|
116
|
+
* `headers` directly the way `ws` does); Fly accepts the token as the
|
|
117
|
+
* first protocol value. This is the documented pattern for browsers and
|
|
118
|
+
* matches Node 22's WS surface.
|
|
119
|
+
* - One reconnect with exponential backoff (1s, 2s) on disconnect, then
|
|
120
|
+
* yield a final `level: 'warn'` line referencing `buildLogsUrl` and
|
|
121
|
+
* finish the iterator.
|
|
122
|
+
* - `signal.aborted` is honored at every await boundary; the underlying
|
|
123
|
+
* socket is closed eagerly.
|
|
124
|
+
* - Every yielded line's `text` is run through `redactLogLines()` before
|
|
125
|
+
* leaving the adapter.
|
|
126
|
+
*/
|
|
127
|
+
streamLogs(input: DeployStreamLogsInput): AsyncGenerator<DeployLogLine>;
|
|
128
|
+
/**
|
|
129
|
+
* Phase 4 of v5.6 — roll back to a previous Fly release.
|
|
130
|
+
*
|
|
131
|
+
* Two modes per spec § "Fly.io adapter → Rollback":
|
|
132
|
+
*
|
|
133
|
+
* 1. Native: try `POST /v1/apps/{app}/releases/{releaseId}/rollback`.
|
|
134
|
+
* This is the historical Fly API; the Machines-era replacement may
|
|
135
|
+
* differ — Phase 7 fixture-capture reconciles. If the endpoint returns
|
|
136
|
+
* 404 / 405 / 410 (removed across the Nomad → Machines transition),
|
|
137
|
+
* fall through to the simulated path. Any other non-OK status
|
|
138
|
+
* (auth, invalid_config, etc.) propagates via `assertOkOrThrow`.
|
|
139
|
+
*
|
|
140
|
+
* 2. Simulated: list prior releases via
|
|
141
|
+
* `GET /v1/apps/{app}/releases?limit=10`, find the most recent one
|
|
142
|
+
* with `status === 'succeeded'` whose `id` differs from the one we'd
|
|
143
|
+
* be rolling back from, and trigger a new deploy with that release's
|
|
144
|
+
* `image`. Re-uses the same POST + poll machinery as `deploy()` via
|
|
145
|
+
* `deployImage()`.
|
|
146
|
+
*
|
|
147
|
+
* When `input.to` is set we treat that as a specific release ID:
|
|
148
|
+
* - Native path uses it as the URL fragment.
|
|
149
|
+
* - Simulated path looks it up in the list to grab its `image`. If the
|
|
150
|
+
* release is not present in the recent-10 window, throw
|
|
151
|
+
* `not_found` — caller almost certainly typo'd the ID.
|
|
152
|
+
*
|
|
153
|
+
* Throws `GuardrailError({ code: 'no_previous_deploy', provider: 'fly' })`
|
|
154
|
+
* when the simulated path runs out of candidates (i.e. no prior release
|
|
155
|
+
* with `status === 'succeeded'` exists).
|
|
156
|
+
*/
|
|
157
|
+
rollback(input: DeployRollbackInput): Promise<DeployResult>;
|
|
158
|
+
/**
|
|
159
|
+
* Private helper — re-uses the deploy() POST + poll machinery to deploy a
|
|
160
|
+
* specific image without going through the constructor-stamped image. Used
|
|
161
|
+
* by `rollback()`'s simulated path to redeploy a previous successful image.
|
|
162
|
+
*/
|
|
163
|
+
private deployImage;
|
|
164
|
+
/**
|
|
165
|
+
* List the most recent releases for the configured app. Newest-first.
|
|
166
|
+
* `limit` caps the result set — defaults to 10 (the spec's recommended
|
|
167
|
+
* window for the rollback lookup). 4xx/5xx errors propagate via
|
|
168
|
+
* `assertOkOrThrow`.
|
|
169
|
+
*/
|
|
170
|
+
listReleases(limit?: number, signal?: AbortSignal): Promise<FlyReleaseResponse[]>;
|
|
171
|
+
/**
|
|
172
|
+
* Find the most recent prior release with `status === 'succeeded'`. When
|
|
173
|
+
* `excludeId` is supplied, that release is skipped (used to ensure
|
|
174
|
+
* `rollback()` never returns "rolled back to the deploy I'm rolling back
|
|
175
|
+
* from" when the caller didn't supply `input.to`).
|
|
176
|
+
*
|
|
177
|
+
* Returns `null` when no candidate exists.
|
|
178
|
+
*/
|
|
179
|
+
private findPreviousSucceededRelease;
|
|
180
|
+
/**
|
|
181
|
+
* Apply the adapter's redaction patterns to a log line's `text` field.
|
|
182
|
+
* Pure helper — keeps the streamLogs loop readable.
|
|
183
|
+
*/
|
|
184
|
+
private redactLine;
|
|
185
|
+
private pollUntilTerminal;
|
|
186
|
+
private shapeResult;
|
|
187
|
+
private headers;
|
|
188
|
+
private buildLogsUrl;
|
|
189
|
+
/**
|
|
190
|
+
* HTTP-status-keyed error mapper. Per v5.6 spec:
|
|
191
|
+
*
|
|
192
|
+
* | Status | ErrorCode |
|
|
193
|
+
* |---|---|
|
|
194
|
+
* | 401 / 403 | `auth` |
|
|
195
|
+
* | 404 | `not_found` |
|
|
196
|
+
* | 422 / 400 | `invalid_config` |
|
|
197
|
+
* | 5xx | `transient_network` (retryable) |
|
|
198
|
+
* | other 4xx | `adapter_bug` |
|
|
199
|
+
*
|
|
200
|
+
* The `Fly-Request-Id` response header is captured into `details` whenever
|
|
201
|
+
* present so support tickets can quote it back to Fly.
|
|
202
|
+
*/
|
|
203
|
+
private assertOkOrThrow;
|
|
204
|
+
}
|
|
205
|
+
export {};
|
|
206
|
+
//# sourceMappingURL=fly.d.ts.map
|