@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.
Files changed (226) hide show
  1. package/dist/ai-files-manifest.d.ts +28 -0
  2. package/dist/ai-files-manifest.d.ts.map +1 -0
  3. package/dist/ai-files-manifest.js +96 -0
  4. package/dist/ai-files-manifest.js.map +1 -0
  5. package/dist/commands/account.d.ts +51 -0
  6. package/dist/commands/account.d.ts.map +1 -0
  7. package/dist/commands/account.js +88 -0
  8. package/dist/commands/account.js.map +1 -0
  9. package/dist/commands/ai-files.d.ts +73 -0
  10. package/dist/commands/ai-files.d.ts.map +1 -0
  11. package/dist/commands/ai-files.js +179 -0
  12. package/dist/commands/ai-files.js.map +1 -0
  13. package/dist/commands/billing.d.ts +1 -1
  14. package/dist/commands/billing.d.ts.map +1 -1
  15. package/dist/commands/billing.js +1 -1
  16. package/dist/commands/billing.js.map +1 -1
  17. package/dist/commands/continue.d.ts +48 -0
  18. package/dist/commands/continue.d.ts.map +1 -0
  19. package/dist/commands/continue.js +121 -0
  20. package/dist/commands/continue.js.map +1 -0
  21. package/dist/commands/create.d.ts +1 -1
  22. package/dist/commands/create.d.ts.map +1 -1
  23. package/dist/commands/create.js +1 -1
  24. package/dist/commands/create.js.map +1 -1
  25. package/dist/commands/dashboard.d.ts +15 -0
  26. package/dist/commands/dashboard.d.ts.map +1 -0
  27. package/dist/commands/dashboard.js +33 -0
  28. package/dist/commands/dashboard.js.map +1 -0
  29. package/dist/commands/data-export.d.ts +21 -0
  30. package/dist/commands/data-export.d.ts.map +1 -0
  31. package/dist/commands/data-export.js +36 -0
  32. package/dist/commands/data-export.js.map +1 -0
  33. package/dist/commands/data.d.ts +3 -3
  34. package/dist/commands/data.d.ts.map +1 -1
  35. package/dist/commands/data.js +1 -1
  36. package/dist/commands/data.js.map +1 -1
  37. package/dist/commands/delete.d.ts +1 -1
  38. package/dist/commands/delete.d.ts.map +1 -1
  39. package/dist/commands/delete.js +1 -1
  40. package/dist/commands/delete.js.map +1 -1
  41. package/dist/commands/deploys.d.ts +2 -2
  42. package/dist/commands/deploys.d.ts.map +1 -1
  43. package/dist/commands/deploys.js +21 -5
  44. package/dist/commands/deploys.js.map +1 -1
  45. package/dist/commands/dev.d.ts +1 -9
  46. package/dist/commands/dev.d.ts.map +1 -1
  47. package/dist/commands/dev.js +79 -24
  48. package/dist/commands/dev.js.map +1 -1
  49. package/dist/commands/diagnose.d.ts +1 -1
  50. package/dist/commands/diagnose.d.ts.map +1 -1
  51. package/dist/commands/diagnose.js +1 -1
  52. package/dist/commands/diagnose.js.map +1 -1
  53. package/dist/commands/doctor.d.ts +75 -3
  54. package/dist/commands/doctor.d.ts.map +1 -1
  55. package/dist/commands/doctor.js +822 -10
  56. package/dist/commands/doctor.js.map +1 -1
  57. package/dist/commands/domains.d.ts +1 -1
  58. package/dist/commands/domains.d.ts.map +1 -1
  59. package/dist/commands/domains.js +1 -1
  60. package/dist/commands/domains.js.map +1 -1
  61. package/dist/commands/env-scan.d.ts +2 -0
  62. package/dist/commands/env-scan.d.ts.map +1 -0
  63. package/dist/commands/env-scan.js +92 -0
  64. package/dist/commands/env-scan.js.map +1 -0
  65. package/dist/commands/env.d.ts +1 -1
  66. package/dist/commands/env.d.ts.map +1 -1
  67. package/dist/commands/env.js +1 -1
  68. package/dist/commands/env.js.map +1 -1
  69. package/dist/commands/export.d.ts +1 -1
  70. package/dist/commands/export.js +1 -1
  71. package/dist/commands/generate.d.ts +1 -1
  72. package/dist/commands/generate.d.ts.map +1 -1
  73. package/dist/commands/generate.js +14 -9
  74. package/dist/commands/generate.js.map +1 -1
  75. package/dist/commands/github.d.ts +60 -0
  76. package/dist/commands/github.d.ts.map +1 -0
  77. package/dist/commands/github.js +112 -0
  78. package/dist/commands/github.js.map +1 -0
  79. package/dist/commands/import-project.d.ts +1 -1
  80. package/dist/commands/import-project.d.ts.map +1 -1
  81. package/dist/commands/import-project.js +1 -1
  82. package/dist/commands/import-project.js.map +1 -1
  83. package/dist/commands/init.d.ts +1 -1
  84. package/dist/commands/init.d.ts.map +1 -1
  85. package/dist/commands/init.js +1 -1
  86. package/dist/commands/init.js.map +1 -1
  87. package/dist/commands/insights.d.ts +1 -1
  88. package/dist/commands/insights.d.ts.map +1 -1
  89. package/dist/commands/insights.js +1 -1
  90. package/dist/commands/insights.js.map +1 -1
  91. package/dist/commands/login.d.ts +1 -1
  92. package/dist/commands/login.d.ts.map +1 -1
  93. package/dist/commands/login.js +1 -1
  94. package/dist/commands/login.js.map +1 -1
  95. package/dist/commands/logs.d.ts +1 -1
  96. package/dist/commands/logs.d.ts.map +1 -1
  97. package/dist/commands/logs.js +1 -1
  98. package/dist/commands/logs.js.map +1 -1
  99. package/dist/commands/mcp.d.ts +1 -1
  100. package/dist/commands/mcp.d.ts.map +1 -1
  101. package/dist/commands/mcp.js +1 -1
  102. package/dist/commands/mcp.js.map +1 -1
  103. package/dist/commands/open.d.ts +1 -1
  104. package/dist/commands/open.d.ts.map +1 -1
  105. package/dist/commands/open.js +1 -1
  106. package/dist/commands/open.js.map +1 -1
  107. package/dist/commands/publish-failure.d.ts +31 -0
  108. package/dist/commands/publish-failure.d.ts.map +1 -0
  109. package/dist/commands/publish-failure.js +150 -0
  110. package/dist/commands/publish-failure.js.map +1 -0
  111. package/dist/commands/publish-node.d.ts +16 -0
  112. package/dist/commands/publish-node.d.ts.map +1 -0
  113. package/dist/commands/publish-node.js +42 -0
  114. package/dist/commands/publish-node.js.map +1 -0
  115. package/dist/commands/publish.d.ts +105 -3
  116. package/dist/commands/publish.d.ts.map +1 -1
  117. package/dist/commands/publish.js +746 -158
  118. package/dist/commands/publish.js.map +1 -1
  119. package/dist/commands/push.d.ts +45 -8
  120. package/dist/commands/push.d.ts.map +1 -1
  121. package/dist/commands/push.js +233 -22
  122. package/dist/commands/push.js.map +1 -1
  123. package/dist/commands/redeploy.d.ts +28 -0
  124. package/dist/commands/redeploy.d.ts.map +1 -0
  125. package/dist/commands/redeploy.js +421 -0
  126. package/dist/commands/redeploy.js.map +1 -0
  127. package/dist/commands/rename.d.ts +1 -1
  128. package/dist/commands/rename.d.ts.map +1 -1
  129. package/dist/commands/rename.js +1 -1
  130. package/dist/commands/rename.js.map +1 -1
  131. package/dist/commands/reproduce.d.ts +64 -0
  132. package/dist/commands/reproduce.d.ts.map +1 -0
  133. package/dist/commands/reproduce.js +211 -0
  134. package/dist/commands/reproduce.js.map +1 -0
  135. package/dist/commands/reset-superuser.d.ts +1 -1
  136. package/dist/commands/reset-superuser.d.ts.map +1 -1
  137. package/dist/commands/reset-superuser.js +1 -1
  138. package/dist/commands/reset-superuser.js.map +1 -1
  139. package/dist/commands/restore.d.ts +79 -0
  140. package/dist/commands/restore.d.ts.map +1 -0
  141. package/dist/commands/restore.js +164 -0
  142. package/dist/commands/restore.js.map +1 -0
  143. package/dist/commands/resume.d.ts +1 -1
  144. package/dist/commands/resume.d.ts.map +1 -1
  145. package/dist/commands/resume.js +1 -1
  146. package/dist/commands/resume.js.map +1 -1
  147. package/dist/commands/rollback.d.ts +21 -8
  148. package/dist/commands/rollback.d.ts.map +1 -1
  149. package/dist/commands/rollback.js +12 -6
  150. package/dist/commands/rollback.js.map +1 -1
  151. package/dist/commands/status.d.ts +33 -0
  152. package/dist/commands/status.d.ts.map +1 -0
  153. package/dist/commands/status.js +48 -0
  154. package/dist/commands/status.js.map +1 -0
  155. package/dist/commands/unsuspend.d.ts +35 -0
  156. package/dist/commands/unsuspend.d.ts.map +1 -0
  157. package/dist/commands/unsuspend.js +27 -0
  158. package/dist/commands/unsuspend.js.map +1 -0
  159. package/dist/commands/versions.d.ts +1 -1
  160. package/dist/commands/versions.d.ts.map +1 -1
  161. package/dist/commands/versions.js +1 -1
  162. package/dist/commands/versions.js.map +1 -1
  163. package/dist/commands/wait-deploy.d.ts +92 -0
  164. package/dist/commands/wait-deploy.d.ts.map +1 -0
  165. package/dist/commands/wait-deploy.js +226 -0
  166. package/dist/commands/wait-deploy.js.map +1 -0
  167. package/dist/env-scan-source.d.ts +39 -0
  168. package/dist/env-scan-source.d.ts.map +1 -0
  169. package/dist/env-scan-source.js +332 -0
  170. package/dist/env-scan-source.js.map +1 -0
  171. package/dist/error-classifier.d.ts.map +1 -1
  172. package/dist/error-classifier.js +67 -4
  173. package/dist/error-classifier.js.map +1 -1
  174. package/dist/errors.d.ts +8 -1
  175. package/dist/errors.d.ts.map +1 -1
  176. package/dist/errors.js +2 -0
  177. package/dist/errors.js.map +1 -1
  178. package/dist/event-renderer.d.ts +17 -0
  179. package/dist/event-renderer.d.ts.map +1 -0
  180. package/dist/event-renderer.js +130 -0
  181. package/dist/event-renderer.js.map +1 -0
  182. package/dist/index.d.ts +16 -1
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.js +15 -0
  185. package/dist/index.js.map +1 -1
  186. package/dist/plans.d.ts +20 -0
  187. package/dist/plans.d.ts.map +1 -1
  188. package/dist/plans.js +15 -0
  189. package/dist/plans.js.map +1 -1
  190. package/dist/poll-deployment.d.ts +59 -0
  191. package/dist/poll-deployment.d.ts.map +1 -0
  192. package/dist/poll-deployment.js +93 -0
  193. package/dist/poll-deployment.js.map +1 -0
  194. package/dist/publish-retry.d.ts +29 -0
  195. package/dist/publish-retry.d.ts.map +1 -0
  196. package/dist/publish-retry.js +224 -0
  197. package/dist/publish-retry.js.map +1 -0
  198. package/dist/recovery.d.ts +356 -0
  199. package/dist/recovery.d.ts.map +1 -0
  200. package/dist/recovery.js +300 -0
  201. package/dist/recovery.js.map +1 -0
  202. package/dist/stream-utils.d.ts +21 -0
  203. package/dist/stream-utils.d.ts.map +1 -0
  204. package/dist/stream-utils.js +41 -0
  205. package/dist/stream-utils.js.map +1 -0
  206. package/dist/structured-error-codes.d.ts +30 -0
  207. package/dist/structured-error-codes.d.ts.map +1 -0
  208. package/dist/structured-error-codes.js +86 -0
  209. package/dist/structured-error-codes.js.map +1 -0
  210. package/dist/tarball.d.ts +11 -0
  211. package/dist/tarball.d.ts.map +1 -1
  212. package/dist/tarball.js +30 -9
  213. package/dist/tarball.js.map +1 -1
  214. package/dist/templates/ai-files/claude-md.d.ts +7 -0
  215. package/dist/templates/ai-files/claude-md.d.ts.map +1 -0
  216. package/dist/templates/ai-files/claude-md.js +78 -0
  217. package/dist/templates/ai-files/claude-md.js.map +1 -0
  218. package/dist/templates/ai-files/cursor-percher-mdc.d.ts +7 -0
  219. package/dist/templates/ai-files/cursor-percher-mdc.d.ts.map +1 -0
  220. package/dist/templates/ai-files/cursor-percher-mdc.js +111 -0
  221. package/dist/templates/ai-files/cursor-percher-mdc.js.map +1 -0
  222. package/dist/templates/ai-files/index.d.ts +8 -0
  223. package/dist/templates/ai-files/index.d.ts.map +1 -0
  224. package/dist/templates/ai-files/index.js +4 -0
  225. package/dist/templates/ai-files/index.js.map +1 -0
  226. 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":"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"}
@@ -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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"}