@percher/core 0.2.6 → 0.4.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/dist/ai-files-manifest.d.ts +28 -0
- package/dist/ai-files-manifest.d.ts.map +1 -0
- package/dist/ai-files-manifest.js +96 -0
- package/dist/ai-files-manifest.js.map +1 -0
- package/dist/commands/account.d.ts +51 -0
- package/dist/commands/account.d.ts.map +1 -0
- package/dist/commands/account.js +88 -0
- package/dist/commands/account.js.map +1 -0
- package/dist/commands/ai-files.d.ts +73 -0
- package/dist/commands/ai-files.d.ts.map +1 -0
- package/dist/commands/ai-files.js +179 -0
- package/dist/commands/ai-files.js.map +1 -0
- package/dist/commands/billing.d.ts +1 -1
- package/dist/commands/billing.d.ts.map +1 -1
- package/dist/commands/billing.js +1 -1
- package/dist/commands/billing.js.map +1 -1
- package/dist/commands/continue.d.ts +48 -0
- package/dist/commands/continue.d.ts.map +1 -0
- package/dist/commands/continue.js +121 -0
- package/dist/commands/continue.js.map +1 -0
- package/dist/commands/create.d.ts +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +1 -1
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/dashboard.d.ts +15 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +33 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/data-export.d.ts +21 -0
- package/dist/commands/data-export.d.ts.map +1 -0
- package/dist/commands/data-export.js +36 -0
- package/dist/commands/data-export.js.map +1 -0
- package/dist/commands/data.d.ts +3 -3
- package/dist/commands/data.d.ts.map +1 -1
- package/dist/commands/data.js +1 -1
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/delete.d.ts +1 -1
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +1 -1
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/deploys.d.ts +2 -2
- package/dist/commands/deploys.d.ts.map +1 -1
- package/dist/commands/deploys.js +21 -5
- package/dist/commands/deploys.js.map +1 -1
- package/dist/commands/dev.d.ts +1 -9
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +79 -24
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/diagnose.d.ts +1 -1
- package/dist/commands/diagnose.d.ts.map +1 -1
- package/dist/commands/diagnose.js +1 -1
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/doctor.d.ts +75 -3
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +822 -10
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/domains.d.ts +1 -1
- package/dist/commands/domains.d.ts.map +1 -1
- package/dist/commands/domains.js +1 -1
- package/dist/commands/domains.js.map +1 -1
- package/dist/commands/env-scan.d.ts +2 -0
- package/dist/commands/env-scan.d.ts.map +1 -0
- package/dist/commands/env-scan.js +92 -0
- package/dist/commands/env-scan.js.map +1 -0
- package/dist/commands/env.d.ts +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +1 -1
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/export.d.ts +1 -1
- package/dist/commands/export.js +1 -1
- package/dist/commands/generate.d.ts +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +14 -9
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/github.d.ts +60 -0
- package/dist/commands/github.d.ts.map +1 -0
- package/dist/commands/github.js +112 -0
- package/dist/commands/github.js.map +1 -0
- package/dist/commands/import-project.d.ts +1 -1
- package/dist/commands/import-project.d.ts.map +1 -1
- package/dist/commands/import-project.js +1 -1
- package/dist/commands/import-project.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/insights.d.ts +1 -1
- package/dist/commands/insights.d.ts.map +1 -1
- package/dist/commands/insights.js +1 -1
- package/dist/commands/insights.js.map +1 -1
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logs.d.ts +1 -1
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +1 -1
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/mcp.d.ts +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +1 -1
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/open.d.ts +1 -1
- package/dist/commands/open.d.ts.map +1 -1
- package/dist/commands/open.js +1 -1
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/publish-failure.d.ts +31 -0
- package/dist/commands/publish-failure.d.ts.map +1 -0
- package/dist/commands/publish-failure.js +150 -0
- package/dist/commands/publish-failure.js.map +1 -0
- package/dist/commands/publish-node.d.ts +16 -0
- package/dist/commands/publish-node.d.ts.map +1 -0
- package/dist/commands/publish-node.js +42 -0
- package/dist/commands/publish-node.js.map +1 -0
- package/dist/commands/publish.d.ts +105 -3
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +746 -158
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/push.d.ts +45 -8
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +233 -22
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/redeploy.d.ts +28 -0
- package/dist/commands/redeploy.d.ts.map +1 -0
- package/dist/commands/redeploy.js +421 -0
- package/dist/commands/redeploy.js.map +1 -0
- package/dist/commands/rename.d.ts +1 -1
- package/dist/commands/rename.d.ts.map +1 -1
- package/dist/commands/rename.js +1 -1
- package/dist/commands/rename.js.map +1 -1
- package/dist/commands/reproduce.d.ts +64 -0
- package/dist/commands/reproduce.d.ts.map +1 -0
- package/dist/commands/reproduce.js +211 -0
- package/dist/commands/reproduce.js.map +1 -0
- package/dist/commands/reset-superuser.d.ts +1 -1
- package/dist/commands/reset-superuser.d.ts.map +1 -1
- package/dist/commands/reset-superuser.js +1 -1
- package/dist/commands/reset-superuser.js.map +1 -1
- package/dist/commands/restore.d.ts +79 -0
- package/dist/commands/restore.d.ts.map +1 -0
- package/dist/commands/restore.js +164 -0
- package/dist/commands/restore.js.map +1 -0
- package/dist/commands/resume.d.ts +1 -1
- package/dist/commands/resume.d.ts.map +1 -1
- package/dist/commands/resume.js +1 -1
- package/dist/commands/resume.js.map +1 -1
- package/dist/commands/rollback.d.ts +21 -8
- package/dist/commands/rollback.d.ts.map +1 -1
- package/dist/commands/rollback.js +12 -6
- package/dist/commands/rollback.js.map +1 -1
- package/dist/commands/status.d.ts +33 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +48 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/unsuspend.d.ts +35 -0
- package/dist/commands/unsuspend.d.ts.map +1 -0
- package/dist/commands/unsuspend.js +27 -0
- package/dist/commands/unsuspend.js.map +1 -0
- package/dist/commands/versions.d.ts +1 -1
- package/dist/commands/versions.d.ts.map +1 -1
- package/dist/commands/versions.js +1 -1
- package/dist/commands/versions.js.map +1 -1
- package/dist/commands/wait-deploy.d.ts +92 -0
- package/dist/commands/wait-deploy.d.ts.map +1 -0
- package/dist/commands/wait-deploy.js +226 -0
- package/dist/commands/wait-deploy.js.map +1 -0
- package/dist/env-scan-source.d.ts +39 -0
- package/dist/env-scan-source.d.ts.map +1 -0
- package/dist/env-scan-source.js +332 -0
- package/dist/env-scan-source.js.map +1 -0
- package/dist/error-classifier.d.ts.map +1 -1
- package/dist/error-classifier.js +67 -4
- package/dist/error-classifier.js.map +1 -1
- package/dist/errors.d.ts +8 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -1
- package/dist/event-renderer.d.ts +17 -0
- package/dist/event-renderer.d.ts.map +1 -0
- package/dist/event-renderer.js +130 -0
- package/dist/event-renderer.js.map +1 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/plans.d.ts +20 -0
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +15 -0
- package/dist/plans.js.map +1 -1
- package/dist/poll-deployment.d.ts +59 -0
- package/dist/poll-deployment.d.ts.map +1 -0
- package/dist/poll-deployment.js +93 -0
- package/dist/poll-deployment.js.map +1 -0
- package/dist/publish-retry.d.ts +29 -0
- package/dist/publish-retry.d.ts.map +1 -0
- package/dist/publish-retry.js +224 -0
- package/dist/publish-retry.js.map +1 -0
- package/dist/recovery.d.ts +356 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +300 -0
- package/dist/recovery.js.map +1 -0
- package/dist/stream-utils.d.ts +21 -0
- package/dist/stream-utils.d.ts.map +1 -0
- package/dist/stream-utils.js +41 -0
- package/dist/stream-utils.js.map +1 -0
- package/dist/structured-error-codes.d.ts +30 -0
- package/dist/structured-error-codes.d.ts.map +1 -0
- package/dist/structured-error-codes.js +86 -0
- package/dist/structured-error-codes.js.map +1 -0
- package/dist/tarball.d.ts +11 -0
- package/dist/tarball.d.ts.map +1 -1
- package/dist/tarball.js +30 -9
- package/dist/tarball.js.map +1 -1
- package/dist/templates/ai-files/claude-md.d.ts +7 -0
- package/dist/templates/ai-files/claude-md.d.ts.map +1 -0
- package/dist/templates/ai-files/claude-md.js +78 -0
- package/dist/templates/ai-files/claude-md.js.map +1 -0
- package/dist/templates/ai-files/cursor-percher-mdc.d.ts +7 -0
- package/dist/templates/ai-files/cursor-percher-mdc.d.ts.map +1 -0
- package/dist/templates/ai-files/cursor-percher-mdc.js +111 -0
- package/dist/templates/ai-files/cursor-percher-mdc.js.map +1 -0
- package/dist/templates/ai-files/index.d.ts +8 -0
- package/dist/templates/ai-files/index.d.ts.map +1 -0
- package/dist/templates/ai-files/index.js +4 -0
- package/dist/templates/ai-files/index.js.map +1 -0
- package/package.json +6 -5
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publish-retry classifier and runner (Phase 7.2).
|
|
3
|
+
*
|
|
4
|
+
* The 2026-05-07 incident batch surfaced a class of agent-perceived
|
|
5
|
+
* failure where the platform's `WORKER_UNAVAILABLE` (transient — the
|
|
6
|
+
* worker was restarting) bubbled through the CLI as a hard error.
|
|
7
|
+
* Humans/agents recovered by typing `percher publish` again. The CLI
|
|
8
|
+
* should do that itself.
|
|
9
|
+
*
|
|
10
|
+
* Rules table (mirrored in `docs/plans/IMPLEMENTING_publish-resilience-and-clarity-plan.md`):
|
|
11
|
+
*
|
|
12
|
+
* WORKER_UNAVAILABLE retry 3× — 5s / 15s / 45s
|
|
13
|
+
* WORKER_UNAVAILABLE_PERSISTENT no retry — surface as platform incident
|
|
14
|
+
* DEPLOY_RATE_LIMITED retry 2× — honour retryAfterSec from response
|
|
15
|
+
* network error / TCP reset retry 3× — 2s / 8s / 24s
|
|
16
|
+
* HTTP 5xx retry 2× — 5s / 20s
|
|
17
|
+
* HTTP 4xx (incl. 429 quota, 422 config) no retry
|
|
18
|
+
* BUILD_FAILED / BUILD_TIMEOUT / DEPLOY_STALLED no retry — these are
|
|
19
|
+
* observed during the *poll* phase, not the upload, but listed here
|
|
20
|
+
* defensively so any future code path that encounters them while
|
|
21
|
+
* retrying still classifies them correctly.
|
|
22
|
+
*
|
|
23
|
+
* Every retry reuses the same `Idempotency-Key` header so the API treats
|
|
24
|
+
* a re-attempt as "are you still working on this one?" rather than
|
|
25
|
+
* minting a new deploy row. The caller is responsible for generating the
|
|
26
|
+
* key (via `crypto.randomUUID()`) and threading it into the request.
|
|
27
|
+
*/
|
|
28
|
+
import { PercherApiError } from "@percher/client";
|
|
29
|
+
const NON_RETRYABLE_CODES = new Set([
|
|
30
|
+
"WORKER_UNAVAILABLE_PERSISTENT",
|
|
31
|
+
"BUILD_FAILED",
|
|
32
|
+
"BUILD_TIMEOUT",
|
|
33
|
+
"DEPLOY_STALLED",
|
|
34
|
+
"REQUIRED_ENV_MISSING",
|
|
35
|
+
"ENV_KEY_UNDECLARED",
|
|
36
|
+
"DAILY_QUOTA_EXCEEDED",
|
|
37
|
+
"RETRY_LIMIT_REACHED",
|
|
38
|
+
"ACCOUNT_SUSPENDED",
|
|
39
|
+
"APP_SUSPENDED",
|
|
40
|
+
"EMAIL_NOT_VERIFIED",
|
|
41
|
+
"PREVIEW_LIMIT_REACHED",
|
|
42
|
+
"VALIDATION_ERROR",
|
|
43
|
+
// Phase 8.1 — past hardCap the queue is so deep that retry-after
|
|
44
|
+
// would lie about wait time. Treat as a platform incident: surface
|
|
45
|
+
// immediately so the user sees the status-page link instead of
|
|
46
|
+
// a CLI that loops every minute claiming "should be back in 5s".
|
|
47
|
+
"PLATFORM_DOWN",
|
|
48
|
+
]);
|
|
49
|
+
const WORKER_UNAVAILABLE_BACKOFF_MS = [5_000, 15_000, 45_000];
|
|
50
|
+
const NETWORK_BACKOFF_MS = [2_000, 8_000, 24_000];
|
|
51
|
+
const HTTP_5XX_BACKOFF_MS = [5_000, 20_000];
|
|
52
|
+
export function classifyDeployRetry(err, attempt) {
|
|
53
|
+
// attempt is 1-indexed — `attempt = 1` means "first failure, decide
|
|
54
|
+
// delay before attempt 2"; the schedule arrays are 0-indexed.
|
|
55
|
+
const idx = attempt - 1;
|
|
56
|
+
if (err instanceof PercherApiError) {
|
|
57
|
+
if (err.code === "WORKER_UNAVAILABLE_PERSISTENT") {
|
|
58
|
+
return {
|
|
59
|
+
retryable: false,
|
|
60
|
+
delayMs: 0,
|
|
61
|
+
reason: "platform circuit breaker open — surfacing as incident",
|
|
62
|
+
category: "persistent",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (err.code === "WORKER_UNAVAILABLE") {
|
|
66
|
+
const delay = WORKER_UNAVAILABLE_BACKOFF_MS[idx];
|
|
67
|
+
if (delay === undefined) {
|
|
68
|
+
return {
|
|
69
|
+
retryable: false,
|
|
70
|
+
delayMs: 0,
|
|
71
|
+
reason: "worker unavailable after 3 attempts",
|
|
72
|
+
category: "worker_unavailable",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
retryable: true,
|
|
77
|
+
delayMs: delay,
|
|
78
|
+
reason: "worker was restarting",
|
|
79
|
+
category: "worker_unavailable",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (err.code === "DEPLOY_RATE_LIMITED") {
|
|
83
|
+
if (idx >= 2) {
|
|
84
|
+
return {
|
|
85
|
+
retryable: false,
|
|
86
|
+
delayMs: 0,
|
|
87
|
+
reason: "rate-limited after 2 attempts",
|
|
88
|
+
category: "rate_limited",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const retryAfterSec = typeof err.extra?.retryAfterSec === "number" ? err.extra.retryAfterSec : 5;
|
|
92
|
+
return {
|
|
93
|
+
retryable: true,
|
|
94
|
+
delayMs: Math.min(60_000, Math.max(1_000, retryAfterSec * 1000)),
|
|
95
|
+
reason: "per-app rate limit",
|
|
96
|
+
category: "rate_limited",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (err.code === "USER_CONCURRENT_LIMIT") {
|
|
100
|
+
// Phase 8.2 — the user has the most parallel deploys their plan
|
|
101
|
+
// allows. Retrying after the suggested window often clears one
|
|
102
|
+
// of the in-flight builds. Single retry is enough; past that the
|
|
103
|
+
// user almost certainly needs to take action (upgrade or stop
|
|
104
|
+
// looping), so surface the error.
|
|
105
|
+
if (idx >= 1) {
|
|
106
|
+
return {
|
|
107
|
+
retryable: false,
|
|
108
|
+
delayMs: 0,
|
|
109
|
+
reason: "concurrent-deploy cap still saturated after one wait",
|
|
110
|
+
category: "rate_limited",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const retryAfterSec = typeof err.extra?.retryAfterSec === "number" ? err.extra.retryAfterSec : 60;
|
|
114
|
+
return {
|
|
115
|
+
retryable: true,
|
|
116
|
+
delayMs: Math.min(2 * 60_000, Math.max(5_000, retryAfterSec * 1000)),
|
|
117
|
+
reason: "per-user concurrent-deploy cap",
|
|
118
|
+
category: "rate_limited",
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (err.code === "PLATFORM_OVERLOADED") {
|
|
122
|
+
// Phase 8.1 — global backpressure. The API supplies a
|
|
123
|
+
// Retry-After header computed from the realistic drain estimate;
|
|
124
|
+
// honor it (capped at 5 min so a misbehaving server can't hold
|
|
125
|
+
// the CLI hostage). Up to 3 retries — past that the queue isn't
|
|
126
|
+
// draining for this caller and surfacing the incident is fairer.
|
|
127
|
+
if (idx >= 3) {
|
|
128
|
+
return {
|
|
129
|
+
retryable: false,
|
|
130
|
+
delayMs: 0,
|
|
131
|
+
reason: "platform overloaded after 3 attempts",
|
|
132
|
+
category: "rate_limited",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const retryAfterSec = typeof err.extra?.retryAfterSec === "number" ? err.extra.retryAfterSec : 30;
|
|
136
|
+
return {
|
|
137
|
+
retryable: true,
|
|
138
|
+
delayMs: Math.min(5 * 60_000, Math.max(5_000, retryAfterSec * 1000)),
|
|
139
|
+
reason: "platform overloaded — queue-depth backpressure",
|
|
140
|
+
category: "rate_limited",
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (NON_RETRYABLE_CODES.has(err.code)) {
|
|
144
|
+
return {
|
|
145
|
+
retryable: false,
|
|
146
|
+
delayMs: 0,
|
|
147
|
+
reason: `non-retryable: ${err.code}`,
|
|
148
|
+
category: "non_retryable",
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (err.status >= 500 && err.status < 600) {
|
|
152
|
+
const delay = HTTP_5XX_BACKOFF_MS[idx];
|
|
153
|
+
if (delay === undefined) {
|
|
154
|
+
return {
|
|
155
|
+
retryable: false,
|
|
156
|
+
delayMs: 0,
|
|
157
|
+
reason: `HTTP ${err.status} after 2 attempts`,
|
|
158
|
+
category: "http_5xx",
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
retryable: true,
|
|
163
|
+
delayMs: delay,
|
|
164
|
+
reason: `HTTP ${err.status}`,
|
|
165
|
+
category: "http_5xx",
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
retryable: false,
|
|
170
|
+
delayMs: 0,
|
|
171
|
+
reason: `HTTP ${err.status} ${err.code}`,
|
|
172
|
+
category: "non_retryable",
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (err instanceof Error &&
|
|
176
|
+
/network error|fetch failed|ECONNRESET|ENOTFOUND|ETIMEDOUT/i.test(err.message)) {
|
|
177
|
+
const delay = NETWORK_BACKOFF_MS[idx];
|
|
178
|
+
if (delay === undefined) {
|
|
179
|
+
return {
|
|
180
|
+
retryable: false,
|
|
181
|
+
delayMs: 0,
|
|
182
|
+
reason: "network error after 3 attempts",
|
|
183
|
+
category: "network",
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
retryable: true,
|
|
188
|
+
delayMs: delay,
|
|
189
|
+
reason: "network blip",
|
|
190
|
+
category: "network",
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
retryable: false,
|
|
195
|
+
delayMs: 0,
|
|
196
|
+
reason: "unknown error",
|
|
197
|
+
category: "non_retryable",
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
201
|
+
export async function runDeployWithRetry(opts) {
|
|
202
|
+
const max = opts.maxAttempts ?? 4;
|
|
203
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
204
|
+
let attempt = 0;
|
|
205
|
+
let lastErr;
|
|
206
|
+
while (attempt < max) {
|
|
207
|
+
attempt += 1;
|
|
208
|
+
try {
|
|
209
|
+
const result = await opts.call(attempt);
|
|
210
|
+
return { result, attempts: attempt };
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
lastErr = err;
|
|
214
|
+
const decision = classifyDeployRetry(err, attempt);
|
|
215
|
+
if (!decision.retryable || attempt >= max) {
|
|
216
|
+
throw err;
|
|
217
|
+
}
|
|
218
|
+
opts.onRetry?.({ attempt, decision, err });
|
|
219
|
+
await sleep(decision.delayMs);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
throw lastErr;
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=publish-retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish-retry.js","sourceRoot":"","sources":["../src/publish-retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAiBlD,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,+BAA+B;IAC/B,cAAc;IACd,eAAe;IACf,gBAAgB;IAChB,sBAAsB;IACtB,oBAAoB;IACpB,sBAAsB;IACtB,qBAAqB;IACrB,mBAAmB;IACnB,eAAe;IACf,oBAAoB;IACpB,uBAAuB;IACvB,kBAAkB;IAClB,iEAAiE;IACjE,mEAAmE;IACnE,+DAA+D;IAC/D,iEAAiE;IACjE,eAAe;CAChB,CAAC,CAAC;AAEH,MAAM,6BAA6B,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AACvE,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAU,CAAC;AAC3D,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,MAAM,CAAU,CAAC;AAErD,MAAM,UAAU,mBAAmB,CAAC,GAAY,EAAE,OAAe;IAC/D,oEAAoE;IACpE,8DAA8D;IAC9D,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,CAAC;IAExB,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;QACnC,IAAI,GAAG,CAAC,IAAI,KAAK,+BAA+B,EAAE,CAAC;YACjD,OAAO;gBACL,SAAS,EAAE,KAAK;gBAChB,OAAO,EAAE,CAAC;gBACV,MAAM,EAAE,uDAAuD;gBAC/D,QAAQ,EAAE,YAAY;aACvB,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,6BAA6B,CAAC,GAAG,CAAC,CAAC;YACjD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO;oBACL,SAAS,EAAE,KAAK;oBAChB,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,qCAAqC;oBAC7C,QAAQ,EAAE,oBAAoB;iBAC/B,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,uBAAuB;gBAC/B,QAAQ,EAAE,oBAAoB;aAC/B,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACvC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;gBACb,OAAO;oBACL,SAAS,EAAE,KAAK;oBAChB,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,+BAA+B;oBACvC,QAAQ,EAAE,cAAc;iBACzB,CAAC;YACJ,CAAC;YACD,MAAM,aAAa,GACjB,OAAO,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,KAAK,CAAC,aAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;YACzF,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC;gBAChE,MAAM,EAAE,oBAAoB;gBAC5B,QAAQ,EAAE,cAAc;aACzB,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;YACzC,gEAAgE;YAChE,+DAA+D;YAC/D,iEAAiE;YACjE,8DAA8D;YAC9D,kCAAkC;YAClC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;gBACb,OAAO;oBACL,SAAS,EAAE,KAAK;oBAChB,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,sDAAsD;oBAC9D,QAAQ,EAAE,cAAc;iBACzB,CAAC;YACJ,CAAC;YACD,MAAM,aAAa,GACjB,OAAO,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,KAAK,CAAC,aAAwB,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1F,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC;gBACpE,MAAM,EAAE,gCAAgC;gBACxC,QAAQ,EAAE,cAAc;aACzB,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACvC,sDAAsD;YACtD,iEAAiE;YACjE,+DAA+D;YAC/D,gEAAgE;YAChE,iEAAiE;YACjE,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;gBACb,OAAO;oBACL,SAAS,EAAE,KAAK;oBAChB,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,sCAAsC;oBAC9C,QAAQ,EAAE,cAAc;iBACzB,CAAC;YACJ,CAAC;YACD,MAAM,aAAa,GACjB,OAAO,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,KAAK,CAAC,aAAwB,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1F,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC;gBACpE,MAAM,EAAE,gDAAgD;gBACxD,QAAQ,EAAE,cAAc;aACzB,CAAC;QACJ,CAAC;QACD,IAAI,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,OAAO;gBACL,SAAS,EAAE,KAAK;gBAChB,OAAO,EAAE,CAAC;gBACV,MAAM,EAAE,kBAAkB,GAAG,CAAC,IAAI,EAAE;gBACpC,QAAQ,EAAE,eAAe;aAC1B,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO;oBACL,SAAS,EAAE,KAAK;oBAChB,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,QAAQ,GAAG,CAAC,MAAM,mBAAmB;oBAC7C,QAAQ,EAAE,UAAU;iBACrB,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE;gBAC5B,QAAQ,EAAE,UAAU;aACrB,CAAC;QACJ,CAAC;QACD,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,QAAQ,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE;YACxC,QAAQ,EAAE,eAAe;SAC1B,CAAC;IACJ,CAAC;IAED,IACE,GAAG,YAAY,KAAK;QACpB,4DAA4D,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAC9E,CAAC;QACD,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO;gBACL,SAAS,EAAE,KAAK;gBAChB,OAAO,EAAE,CAAC;gBACV,MAAM,EAAE,gCAAgC;gBACxC,QAAQ,EAAE,SAAS;aACpB,CAAC;QACJ,CAAC;QACD,OAAO;YACL,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,cAAc;YACtB,QAAQ,EAAE,SAAS;SACpB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,eAAe;QACvB,QAAQ,EAAE,eAAe;KAC1B,CAAC;AACJ,CAAC;AAkBD,MAAM,YAAY,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAOjF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAA4B;IAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC;IACzC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,OAAgB,CAAC;IACrB,OAAO,OAAO,GAAG,GAAG,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC,CAAC;QACb,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACxC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,GAAG,GAAG,CAAC;YACd,MAAM,QAAQ,GAAG,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACnD,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;gBAC1C,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YAC3C,MAAM,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,MAAM,OAAO,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import type { BuildProblem } from "@percher/client";
|
|
2
|
+
import type { ErrorClass } from "./error-classifier";
|
|
3
|
+
/**
|
|
4
|
+
* Action an AI agent should take after a deploy result.
|
|
5
|
+
*
|
|
6
|
+
* Stable, machine-readable enum. Treat values as a public API: agents will
|
|
7
|
+
* hardcode `===` comparisons against these strings, so removing or renaming
|
|
8
|
+
* a value is a breaking change.
|
|
9
|
+
*/
|
|
10
|
+
export type RecoveryAction =
|
|
11
|
+
/** User is unauthenticated; agent should call `percher_login`. */
|
|
12
|
+
"open_login"
|
|
13
|
+
/** Build/runtime is missing env vars; call `percher_env_set`. */
|
|
14
|
+
| "set_env_vars"
|
|
15
|
+
/**
|
|
16
|
+
* FUTURE11 Phase 2 — deploy is in flight (queued/building/deploying);
|
|
17
|
+
* agent should call `percher_wait_for_deploy` to keep checking in
|
|
18
|
+
* short intervals instead of starting a new deploy.
|
|
19
|
+
*/
|
|
20
|
+
| "wait_deploy"
|
|
21
|
+
/** Transient infra failure; safe to call `percher_publish` again. */
|
|
22
|
+
| "retry"
|
|
23
|
+
/**
|
|
24
|
+
* FUTURE12 Phase 1a — additive enum value. Reserved for ambiguous
|
|
25
|
+
* failures (generic `build_failed`, stalled deploys, runtime crashes,
|
|
26
|
+
* unclear state) where the right path is to ask `percher_doctor`
|
|
27
|
+
* for a primary recommendation rather than hopping straight to a
|
|
28
|
+
* specific low-level inspector. Phase 4 of FUTURE12 migrates the
|
|
29
|
+
* existing `inspect_build_log` primary cases over to this action.
|
|
30
|
+
*/
|
|
31
|
+
| "run_doctor"
|
|
32
|
+
/** Build failed for a code reason; agent should call `percher_deploys_inspect`. */
|
|
33
|
+
| "inspect_build_log"
|
|
34
|
+
/**
|
|
35
|
+
* FUTURE1 Phase 2.3 — build failed and the API extracted at least one
|
|
36
|
+
* structured BuildProblem (file + line + actionable hint). Agent
|
|
37
|
+
* should patch the offending file directly using `problems` rather
|
|
38
|
+
* than fetching/parsing the build log.
|
|
39
|
+
*/
|
|
40
|
+
| "fix_problems"
|
|
41
|
+
/**
|
|
42
|
+
* FUTURE1 Phase 4.2 — explicit opt-in path for reproducing a build
|
|
43
|
+
* failure locally. Never auto-suggested as `nextAction`: cloud-side
|
|
44
|
+
* `inspect_build_log` always works while local reproduction needs
|
|
45
|
+
* nixpacks installed AND only ships env *keys* (no values), so it
|
|
46
|
+
* makes recovery WORSE for runtime-secret failures and dockerfile-
|
|
47
|
+
* only flows. Surfaces via `alternativeActions` instead so an agent
|
|
48
|
+
* can opt in after `inspect_build_log` didn't yield a fix.
|
|
49
|
+
*/
|
|
50
|
+
| "reproduce_locally"
|
|
51
|
+
/** `percher.toml` is invalid; agent should ask the user or repair the file. */
|
|
52
|
+
| "fix_config"
|
|
53
|
+
/** Plan limits exceeded or otherwise needs human input; agent should ask the user. */
|
|
54
|
+
| "ask_user"
|
|
55
|
+
/** Success path — no further action required. */
|
|
56
|
+
| "none";
|
|
57
|
+
/** MCP tool the agent should invoke for `nextAction`, when applicable. */
|
|
58
|
+
export type SuggestedTool = "percher_login" | "percher_env_set" | "percher_deploys_inspect" | "percher_publish"
|
|
59
|
+
/** FUTURE11 Phase 2 — short-poll a specific deploy without starting a new one. */
|
|
60
|
+
| "percher_wait_for_deploy"
|
|
61
|
+
/**
|
|
62
|
+
* FUTURE12 Phase 1a — pairs with `run_doctor` action. Phase 4 of
|
|
63
|
+
* FUTURE12 migrates publish/wait's generic-failure paths to emit
|
|
64
|
+
* `percher_doctor` instead of `percher_deploys_inspect`.
|
|
65
|
+
*/
|
|
66
|
+
| "percher_doctor"
|
|
67
|
+
/** FUTURE1 Phase 3.2 — percher_redeploy tool, used by burst-rate-
|
|
68
|
+
* limit recovery so agents retry the rerun after retryAfterSec
|
|
69
|
+
* instead of hopping to a fresh percher_publish. */
|
|
70
|
+
| "percher_redeploy"
|
|
71
|
+
/** FUTURE1 Phase 4.2 — percher_reproduce tool, surfaced via
|
|
72
|
+
* alternativeActions on build-failure recovery. */
|
|
73
|
+
| "percher_reproduce";
|
|
74
|
+
/**
|
|
75
|
+
* FUTURE12 Phase 1a — stable, enumerated reason an agent or human can
|
|
76
|
+
* branch on. Intentionally orthogonal to `RecoveryAction`: action says
|
|
77
|
+
* *what to do next*, reasonCode says *why we're here*. Two recoveries
|
|
78
|
+
* can share `nextAction` (e.g. both `ask_user`) but emit different
|
|
79
|
+
* reasonCodes (`quota_exceeded` vs `retry_limit_reached`) so the agent
|
|
80
|
+
* can produce a different prompt to the user.
|
|
81
|
+
*
|
|
82
|
+
* **Treat values as a public API.** Agents will hardcode `===` checks.
|
|
83
|
+
*/
|
|
84
|
+
export type ReasonCode =
|
|
85
|
+
/** Success or otherwise no specific reason to surface. */
|
|
86
|
+
"none"
|
|
87
|
+
/** User is unauthenticated; needs to log in before any deploy can run. */
|
|
88
|
+
| "auth_required"
|
|
89
|
+
/** App referenced in config doesn't exist (or was deleted). */
|
|
90
|
+
| "app_not_found"
|
|
91
|
+
/** No `percher.toml` in cwd; can't determine app config. */
|
|
92
|
+
| "config_missing"
|
|
93
|
+
/** `percher.toml` parsed but failed schema validation. */
|
|
94
|
+
| "config_invalid"
|
|
95
|
+
/** `[env].required`/`optional`/`ignore` rules conflict (e.g. duplicate key). */
|
|
96
|
+
| "env_contract_invalid"
|
|
97
|
+
/** Source code references env keys that the contract doesn't declare. */
|
|
98
|
+
| "env_key_undeclared"
|
|
99
|
+
/** Reserved alias for `env_contract_invalid` — used when the missing
|
|
100
|
+
* contract block itself is the problem. */
|
|
101
|
+
| "env_contract_missing"
|
|
102
|
+
/** App exists but no deploys have ever run (or all were pruned). */
|
|
103
|
+
| "no_deploys"
|
|
104
|
+
/** Deploy is sitting in the queue, not yet picked up by a worker. */
|
|
105
|
+
| "deploy_queued"
|
|
106
|
+
/** Deploy worker is actively building. */
|
|
107
|
+
| "deploy_building"
|
|
108
|
+
/** Build done; deploy is being swapped in / health-checked. */
|
|
109
|
+
| "deploy_deploying"
|
|
110
|
+
/** Deploy hasn't progressed for longer than the watchdog window. */
|
|
111
|
+
| "deploy_stalled"
|
|
112
|
+
/** Wait window elapsed without terminal status; no stall judgement made. */
|
|
113
|
+
| "deploy_timeout"
|
|
114
|
+
/** Caller tried to publish while another deploy is already in flight. */
|
|
115
|
+
| "deploy_already_in_progress"
|
|
116
|
+
/** This deploy row was superseded by a newer one. */
|
|
117
|
+
| "replaced_by_newer"
|
|
118
|
+
/** Build/runtime needs env keys that aren't set. */
|
|
119
|
+
| "missing_env"
|
|
120
|
+
/** Build itself failed (compile error, missing dep, bad command, etc). */
|
|
121
|
+
| "build_failed"
|
|
122
|
+
/** Container booted but the app crashed at runtime. */
|
|
123
|
+
| "runtime_crashed"
|
|
124
|
+
/** Daily/burst quota hit; not retryable until reset. */
|
|
125
|
+
| "quota_exceeded"
|
|
126
|
+
/** Already retried once after transient infra failure; stop auto-retrying. */
|
|
127
|
+
| "retry_limit_reached"
|
|
128
|
+
/** Likely-transient infra issue (network, image registry, etc). */
|
|
129
|
+
| "infra_transient"
|
|
130
|
+
/** Hard infra outage — Percher can't deploy at all right now. */
|
|
131
|
+
| "infra_unavailable"
|
|
132
|
+
/** Build log isn't in storage yet (deploy too fresh). */
|
|
133
|
+
| "log_unavailable_yet"
|
|
134
|
+
/** Build log fetch errored (transport / encoding / size cap). */
|
|
135
|
+
| "log_fetch_failed"
|
|
136
|
+
/** Deploy died before the build phase started (e.g. tarball validation). */
|
|
137
|
+
| "failed_before_build"
|
|
138
|
+
/** Catch-all for unclassified state — agents should route to doctor. */
|
|
139
|
+
| "unknown";
|
|
140
|
+
/**
|
|
141
|
+
* FUTURE12 Phase 1a — `percher_doctor` mode hint. Public MCP path
|
|
142
|
+
* defaults to `auto`. Other modes exist for CLI `--mode` and for
|
|
143
|
+
* cases where publish/wait can give doctor an exact starting point
|
|
144
|
+
* (e.g. `mode: "deploy"` with a known `deployId`).
|
|
145
|
+
*/
|
|
146
|
+
export type DoctorMode = "auto" | "deploy" | "runtime" | "config" | "env" | "account";
|
|
147
|
+
/**
|
|
148
|
+
* FUTURE12 Phase 1a — single source of truth for `PublishResult.status`.
|
|
149
|
+
*
|
|
150
|
+
* `already_in_progress` is reserved for Phase 6's server-side guardrail
|
|
151
|
+
* that short-circuits publish when the app already has an active
|
|
152
|
+
* deploy. Pinning the value here so the CLI/MCP can declare exhaustive
|
|
153
|
+
* switches before the server path lands.
|
|
154
|
+
*/
|
|
155
|
+
export type PublishStatus = "live" | "failed" | "needs_login" | "dry_run" | "queued" | "replaced" | "already_in_progress";
|
|
156
|
+
/**
|
|
157
|
+
* Structured problem entry used by `fix_config` and `fix_problems`
|
|
158
|
+
* recoveries. Agents apply file edits directly using these.
|
|
159
|
+
*/
|
|
160
|
+
export interface RecoveryProblem {
|
|
161
|
+
file: string;
|
|
162
|
+
line?: number;
|
|
163
|
+
column?: number;
|
|
164
|
+
message: string;
|
|
165
|
+
}
|
|
166
|
+
/** Secondary affordance — see `BaseRecovery.alternativeActions`. */
|
|
167
|
+
export interface RecoveryAlternative {
|
|
168
|
+
action: RecoveryAction;
|
|
169
|
+
suggestedTool?: SuggestedTool;
|
|
170
|
+
args?: Record<string, unknown>;
|
|
171
|
+
/** When this alternative is preferable to `nextAction`. */
|
|
172
|
+
when: string;
|
|
173
|
+
}
|
|
174
|
+
/** Fields shared by every recovery branch. */
|
|
175
|
+
interface BaseRecovery {
|
|
176
|
+
/** True if calling the same tool again with no changes might succeed. */
|
|
177
|
+
retryable: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* FUTURE12 Phase 1b — required, machine-readable reason. Branches
|
|
180
|
+
* orthogonally to `nextAction`: two recoveries can share `nextAction`
|
|
181
|
+
* but emit different `reasonCode`s so an agent can produce a
|
|
182
|
+
* different prompt or telemetry tag.
|
|
183
|
+
*/
|
|
184
|
+
reasonCode: ReasonCode;
|
|
185
|
+
/**
|
|
186
|
+
* FUTURE1 Phase 4.2 — optional secondary affordances the agent MAY
|
|
187
|
+
* use after `nextAction` if the primary path didn't yield a fix.
|
|
188
|
+
* Always populated on build-failure paths so the reproduce-locally
|
|
189
|
+
* option is discoverable, but `nextAction` stays at the always-
|
|
190
|
+
* works cloud path so a passive follow-the-arrow agent doesn't get
|
|
191
|
+
* steered into a flow that needs nixpacks installed locally.
|
|
192
|
+
*/
|
|
193
|
+
alternativeActions?: RecoveryAlternative[];
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Tool-action recovery — `nextAction` maps to a concrete MCP tool and
|
|
197
|
+
* `args` carries everything the agent needs to invoke it. The
|
|
198
|
+
* `inspect_build_log` value is kept here for legacy callers; FUTURE12
|
|
199
|
+
* Phase 4 migrates it to `run_doctor`.
|
|
200
|
+
*/
|
|
201
|
+
export interface ToolRecovery extends BaseRecovery {
|
|
202
|
+
nextAction: "open_login" | "wait_deploy" | "run_doctor" | "set_env_vars" | "retry" | "inspect_build_log";
|
|
203
|
+
suggestedTool: SuggestedTool;
|
|
204
|
+
args: Record<string, unknown>;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* File-edit recovery — `problems` describes what to fix. The agent
|
|
208
|
+
* applies file edits in its own surface, not via an MCP tool.
|
|
209
|
+
*/
|
|
210
|
+
export interface UserRecovery extends BaseRecovery {
|
|
211
|
+
nextAction: "fix_config" | "fix_problems";
|
|
212
|
+
problems: RecoveryProblem[];
|
|
213
|
+
}
|
|
214
|
+
/** Success / no-action recovery. `url` is set when a current live URL is known. */
|
|
215
|
+
export interface NoneRecovery extends BaseRecovery {
|
|
216
|
+
nextAction: "none";
|
|
217
|
+
url?: string;
|
|
218
|
+
}
|
|
219
|
+
/** Human-input recovery — `prompt` is the question the agent should ask the user. */
|
|
220
|
+
export interface AskUserRecovery extends BaseRecovery {
|
|
221
|
+
nextAction: "ask_user";
|
|
222
|
+
prompt: string;
|
|
223
|
+
options?: string[];
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Discriminated union over `nextAction`. Agents narrow by checking
|
|
227
|
+
* `nextAction` first, then read the branch-specific fields:
|
|
228
|
+
*
|
|
229
|
+
* - `ask_user` → `prompt`, optional `options`
|
|
230
|
+
* - `none` → optional `url`
|
|
231
|
+
* - `fix_config` / `fix_problems` → `problems`
|
|
232
|
+
* - everything else → `suggestedTool` + `args`
|
|
233
|
+
*/
|
|
234
|
+
export type PublishRecovery = ToolRecovery | UserRecovery | NoneRecovery | AskUserRecovery;
|
|
235
|
+
/** Success / no-op recovery. `url` is the current live URL when known. */
|
|
236
|
+
export declare function recoveryNone(opts?: {
|
|
237
|
+
reasonCode?: ReasonCode;
|
|
238
|
+
url?: string;
|
|
239
|
+
}): NoneRecovery;
|
|
240
|
+
/** Authentication required — agent should call `percher_login`. */
|
|
241
|
+
export declare function recoveryLogin(opts?: {
|
|
242
|
+
reasonCode?: ReasonCode;
|
|
243
|
+
}): ToolRecovery;
|
|
244
|
+
/** Wait on an in-flight deploy — agent should call `percher_wait_for_deploy`. */
|
|
245
|
+
export declare function recoveryWait(opts: {
|
|
246
|
+
app: string;
|
|
247
|
+
deployId: string;
|
|
248
|
+
timeoutSeconds?: number;
|
|
249
|
+
reasonCode: ReasonCode;
|
|
250
|
+
}): ToolRecovery;
|
|
251
|
+
/** Route to `percher_doctor` for an ambiguous failure that needs diagnosis. */
|
|
252
|
+
export declare function recoveryDoctor(opts: {
|
|
253
|
+
app?: string;
|
|
254
|
+
deployId?: string;
|
|
255
|
+
mode?: DoctorMode;
|
|
256
|
+
reasonCode: ReasonCode;
|
|
257
|
+
alternativeActions?: RecoveryAlternative[];
|
|
258
|
+
}): ToolRecovery;
|
|
259
|
+
/** Build/runtime needs env keys — agent should call `percher_env_set`. */
|
|
260
|
+
export declare function recoveryEnv(opts: {
|
|
261
|
+
app?: string;
|
|
262
|
+
keys: string[];
|
|
263
|
+
reasonCode?: ReasonCode;
|
|
264
|
+
}): ToolRecovery;
|
|
265
|
+
/**
|
|
266
|
+
* `percher.toml` is invalid or missing — agent should fix the file
|
|
267
|
+
* directly. `problems` carries the structured issue list (file,
|
|
268
|
+
* line/column, message) so the agent can apply edits without parsing
|
|
269
|
+
* a free-text error.
|
|
270
|
+
*/
|
|
271
|
+
export declare function recoveryFixConfig(opts: {
|
|
272
|
+
problems: RecoveryProblem[];
|
|
273
|
+
reasonCode?: ReasonCode;
|
|
274
|
+
}): UserRecovery;
|
|
275
|
+
/**
|
|
276
|
+
* Build failed and the API extracted at least one structured problem
|
|
277
|
+
* with file/line data — agent should patch the offending file(s).
|
|
278
|
+
*/
|
|
279
|
+
export declare function recoveryFixProblems(opts: {
|
|
280
|
+
problems: RecoveryProblem[];
|
|
281
|
+
reasonCode?: ReasonCode;
|
|
282
|
+
alternativeActions?: RecoveryAlternative[];
|
|
283
|
+
}): UserRecovery;
|
|
284
|
+
/** Transient infra failure — agent can re-issue the same call. */
|
|
285
|
+
export declare function recoveryRetry(opts: {
|
|
286
|
+
suggestedTool: SuggestedTool;
|
|
287
|
+
args: Record<string, unknown>;
|
|
288
|
+
reasonCode: ReasonCode;
|
|
289
|
+
}): ToolRecovery;
|
|
290
|
+
/**
|
|
291
|
+
* Human-input required. `prompt` MUST be a concrete question — agents
|
|
292
|
+
* surface it verbatim, so empty/placeholder strings violate the
|
|
293
|
+
* contract.
|
|
294
|
+
*/
|
|
295
|
+
export declare function recoveryAsk(opts: {
|
|
296
|
+
prompt: string;
|
|
297
|
+
options?: string[];
|
|
298
|
+
reasonCode: ReasonCode;
|
|
299
|
+
retryable?: boolean;
|
|
300
|
+
}): AskUserRecovery;
|
|
301
|
+
/**
|
|
302
|
+
* Legacy `inspect_build_log` recovery — kept for the build-failure
|
|
303
|
+
* paths that haven't migrated to `run_doctor` yet. FUTURE12 Phase 4
|
|
304
|
+
* will replace these emit sites with `recoveryDoctor`.
|
|
305
|
+
*/
|
|
306
|
+
export declare function recoveryInspectBuildLog(opts: {
|
|
307
|
+
app?: string;
|
|
308
|
+
deployId?: string;
|
|
309
|
+
reasonCode?: ReasonCode;
|
|
310
|
+
alternativeActions?: RecoveryAlternative[];
|
|
311
|
+
}): ToolRecovery;
|
|
312
|
+
/** Recovery on the success path. */
|
|
313
|
+
export declare const RECOVERY_NONE: NoneRecovery;
|
|
314
|
+
/** Recovery for the unauthenticated path. */
|
|
315
|
+
export declare const RECOVERY_NEEDS_LOGIN: ToolRecovery;
|
|
316
|
+
interface FailureContext {
|
|
317
|
+
/** Concrete env var names the classifier extracted, if any. */
|
|
318
|
+
missingEnvVars?: string[];
|
|
319
|
+
/** Deploy id, used to point `percher_deploys_inspect` at the right build. */
|
|
320
|
+
deployId?: string;
|
|
321
|
+
/** App name, optional — `percher_deploys_inspect` defaults to the toml app. */
|
|
322
|
+
appName?: string;
|
|
323
|
+
/**
|
|
324
|
+
* Original publish input, echoed back as `args` for `retry`. Lets an agent
|
|
325
|
+
* re-issue the same call (preview/dryRun/message/force) without re-deriving.
|
|
326
|
+
*/
|
|
327
|
+
publishInput?: Record<string, unknown>;
|
|
328
|
+
/**
|
|
329
|
+
* FUTURE1 Phase 2.3 — structured build problems from the API parser.
|
|
330
|
+
* When at least one carries a `file` field, the recovery action
|
|
331
|
+
* upgrades to `fix_problems` with the problems echoed in `args` so
|
|
332
|
+
* agents can issue file edits directly without log archaeology.
|
|
333
|
+
*/
|
|
334
|
+
problems?: BuildProblem[];
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Convert a `BuildProblem` into the lossless `RecoveryProblem` shape.
|
|
338
|
+
* Drops fields that aren't part of the recovery contract (severity,
|
|
339
|
+
* code) — those still ride on `error.problems` for the CLI's pretty
|
|
340
|
+
* printer. `hint` is folded into the message because it carries the
|
|
341
|
+
* actionable next step (especially for problems without a line, like
|
|
342
|
+
* malformed package.json) and the recovery contract has no separate
|
|
343
|
+
* hint slot.
|
|
344
|
+
*
|
|
345
|
+
* Exported so doctor (Phase 2c fix_problems path) can reuse the
|
|
346
|
+
* same hint-preserving mapping rather than re-implementing it.
|
|
347
|
+
*/
|
|
348
|
+
export declare function buildProblemToRecoveryProblem(p: BuildProblem): RecoveryProblem;
|
|
349
|
+
/**
|
|
350
|
+
* Map an `ErrorClass` to a recovery action. Conservative by default —
|
|
351
|
+
* unknown classes resolve to `ask_user` so an agent never blindly retries
|
|
352
|
+
* something we haven't classified.
|
|
353
|
+
*/
|
|
354
|
+
export declare function recoveryFromErrorClass(errorClass: ErrorClass, failure?: FailureContext): PublishRecovery;
|
|
355
|
+
export {};
|
|
356
|
+
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"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"}
|