@percher/core 0.2.6 → 0.3.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 +1 -1
- 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 +77 -23
- 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 +63 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +792 -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 +142 -0
- package/dist/commands/publish-failure.js.map +1 -0
- package/dist/commands/publish-node.d.ts +13 -0
- package/dist/commands/publish-node.d.ts.map +1 -0
- package/dist/commands/publish-node.js +38 -0
- package/dist/commands/publish-node.js.map +1 -0
- package/dist/commands/publish.d.ts +87 -3
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +589 -156
- 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 +215 -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 +417 -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 +20 -8
- package/dist/commands/rollback.d.ts.map +1 -1
- package/dist/commands/rollback.js +11 -6
- package/dist/commands/rollback.js.map +1 -1
- 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 +225 -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/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/plans.d.ts +11 -0
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +10 -0
- package/dist/plans.js.map +1 -1
- package/dist/poll-deployment.d.ts +47 -0
- package/dist/poll-deployment.d.ts.map +1 -0
- package/dist/poll-deployment.js +57 -0
- package/dist/poll-deployment.js.map +1 -0
- package/dist/recovery.d.ts +356 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +299 -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/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 +5 -5
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { PercherApiError } from "@percher/client";
|
|
5
|
+
import { z } from "zod/v3";
|
|
6
|
+
import { readPercherTomlAppName } from "../app-name";
|
|
7
|
+
export const reproduceInputSchema = z.object({
|
|
8
|
+
app: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("App name. Defaults to the [app].name in the current directory's percher.toml."),
|
|
12
|
+
deployId: z
|
|
13
|
+
.string()
|
|
14
|
+
.describe("Deploy id (e.g. dep_abc123) to reproduce. Required — usually the failed deploy you want to debug."),
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* FUTURE1 Phase 4.2 — download a deploy's source tarball + (optionally)
|
|
18
|
+
* run nixpacks against it locally. The intended use is "build failed
|
|
19
|
+
* in cloud, reproduce here to fix" — surfaced via
|
|
20
|
+
* `recovery.alternativeActions[]` after `inspect_build_log` didn't
|
|
21
|
+
* yield a clear fix.
|
|
22
|
+
*
|
|
23
|
+
* Privacy invariant: env values are NEVER fetched. The endpoint
|
|
24
|
+
* surfaces only env *keys* so the user knows what to set locally; the
|
|
25
|
+
* values come from their own machine (or stay missing if compile-only
|
|
26
|
+
* errors are what we're debugging).
|
|
27
|
+
*/
|
|
28
|
+
export async function reproduce(ctx, input) {
|
|
29
|
+
const appName = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
30
|
+
if (!appName) {
|
|
31
|
+
return {
|
|
32
|
+
status: "failed",
|
|
33
|
+
deployId: input.deployId,
|
|
34
|
+
error: {
|
|
35
|
+
title: "App name required",
|
|
36
|
+
explanation: "reproduce needs either an explicit `app` argument or a percher.toml in the current directory.",
|
|
37
|
+
suggestion: "Pass --app=<name>, or cd into a project that has a percher.toml.",
|
|
38
|
+
},
|
|
39
|
+
summary: "App name required.",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
let app;
|
|
43
|
+
try {
|
|
44
|
+
app = await ctx.client.apps.get(appName);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (err instanceof PercherApiError) {
|
|
48
|
+
if (err.status === 401) {
|
|
49
|
+
return {
|
|
50
|
+
status: "needs_login",
|
|
51
|
+
deployId: input.deployId,
|
|
52
|
+
summary: "Not logged in — run `bunx percher login` first.",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (err.status === 404) {
|
|
56
|
+
return {
|
|
57
|
+
status: "failed",
|
|
58
|
+
deployId: input.deployId,
|
|
59
|
+
error: {
|
|
60
|
+
title: "App not found",
|
|
61
|
+
explanation: `Could not resolve app "${appName}".`,
|
|
62
|
+
suggestion: "Check the app name with `bunx percher whoami` or your dashboard.",
|
|
63
|
+
},
|
|
64
|
+
summary: "App not found.",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
ctx.status(`Downloading source for ${input.deployId}...`);
|
|
71
|
+
let bytes;
|
|
72
|
+
try {
|
|
73
|
+
bytes = await ctx.client.apps.downloadSource(app.id, input.deployId);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
if (err instanceof PercherApiError && err.code === "TARBALL_GONE") {
|
|
77
|
+
return {
|
|
78
|
+
status: "failed",
|
|
79
|
+
appName: app.name,
|
|
80
|
+
deployId: input.deployId,
|
|
81
|
+
error: {
|
|
82
|
+
title: "Source has been retention-evicted",
|
|
83
|
+
explanation: "Percher only keeps deploy tarballs for a bounded window per plan; this deploy's source is gone.",
|
|
84
|
+
suggestion: "Run `bunx percher publish` to upload a fresh source, then reproduce that deploy in the future.",
|
|
85
|
+
},
|
|
86
|
+
summary: "Source tarball is gone.",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (err instanceof PercherApiError && err.status === 404) {
|
|
90
|
+
return {
|
|
91
|
+
status: "failed",
|
|
92
|
+
appName: app.name,
|
|
93
|
+
deployId: input.deployId,
|
|
94
|
+
error: {
|
|
95
|
+
title: "Deploy not found",
|
|
96
|
+
explanation: `No deploy with id ${input.deployId} on app ${app.name}.`,
|
|
97
|
+
suggestion: "Check the id with `bunx percher deploys list`.",
|
|
98
|
+
},
|
|
99
|
+
summary: "Deploy not found.",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
// Privacy: fetch env KEYS only, never values. The endpoint we hit
|
|
105
|
+
// here returns masked values; we discard them and pass keys to the
|
|
106
|
+
// user so they know what to set locally. Failures are non-fatal —
|
|
107
|
+
// the source extraction is the load-bearing artifact.
|
|
108
|
+
// env.list returns `Record<string, string>` (key → masked value)
|
|
109
|
+
// for the CURRENT app env, not a snapshot from the failed deploy.
|
|
110
|
+
// Percher doesn't persist a per-deploy env snapshot today (the
|
|
111
|
+
// image-cache hash includes them but the values aren't stored). We
|
|
112
|
+
// discard the values; only the keys reach the user — privacy
|
|
113
|
+
// invariant on Phase 4.2 — and the result+CLI text both label this
|
|
114
|
+
// as "current app" so a user who rotated keys between failure and
|
|
115
|
+
// reproduce isn't misled into chasing the wrong missing var. Codex
|
|
116
|
+
// P2 follow-up on 3b609f9.
|
|
117
|
+
let currentAppEnvKeys = [];
|
|
118
|
+
try {
|
|
119
|
+
const envMap = await ctx.client.env.list(app.id);
|
|
120
|
+
currentAppEnvKeys = Object.keys(envMap).sort();
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
/* env list unavailable; reproduce can still proceed */
|
|
124
|
+
}
|
|
125
|
+
// Write to tmp + extract. Use system `tar` because:
|
|
126
|
+
// - macOS/Linux ship it
|
|
127
|
+
// - Windows 10+ has `tar.exe` since 1803 (April 2018)
|
|
128
|
+
// - Bun.spawn streams correctly across platforms
|
|
129
|
+
// Fall back to "saved tarball, extract manually" if tar isn't
|
|
130
|
+
// available — the user keeps the bytes either way.
|
|
131
|
+
const tmpDir = mkdtempSync(join(tmpdir(), `percher-reproduce-${input.deployId}-`));
|
|
132
|
+
const tarballPath = join(tmpDir, "source.tar.gz");
|
|
133
|
+
writeFileSync(tarballPath, bytes);
|
|
134
|
+
let extracted = false;
|
|
135
|
+
try {
|
|
136
|
+
const proc = Bun.spawn(["tar", "-xzf", tarballPath, "-C", tmpDir], {
|
|
137
|
+
stdout: "pipe",
|
|
138
|
+
stderr: "pipe",
|
|
139
|
+
});
|
|
140
|
+
const exitCode = await proc.exited;
|
|
141
|
+
extracted = exitCode === 0;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
/* tar not on PATH — fall through */
|
|
145
|
+
}
|
|
146
|
+
const envHint = currentAppEnvKeys.length > 0
|
|
147
|
+
? `Current app env keys (NOT a deploy-time snapshot): ${currentAppEnvKeys.join(", ")}`
|
|
148
|
+
: "No env vars currently configured on the app.";
|
|
149
|
+
if (!extracted) {
|
|
150
|
+
ctx.status(`Source saved to ${tarballPath}`);
|
|
151
|
+
return {
|
|
152
|
+
status: "extracted",
|
|
153
|
+
appName: app.name,
|
|
154
|
+
deployId: input.deployId,
|
|
155
|
+
tmpDir,
|
|
156
|
+
tarballPath,
|
|
157
|
+
currentAppEnvKeys,
|
|
158
|
+
summary: `Source saved to ${tarballPath}. Extract with: tar -xzf ${tarballPath} -C ${tmpDir}`,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
ctx.status(`Extracted to ${tmpDir}`);
|
|
162
|
+
// Try nixpacks if installed — best-effort. If it's not on PATH OR
|
|
163
|
+
// returns non-zero, the user is left with the extracted source and
|
|
164
|
+
// a clear next step (run their own build command). builtLocally
|
|
165
|
+
// tracks the outcome for the agent's recovery loop.
|
|
166
|
+
let builtLocally = false;
|
|
167
|
+
let nixpacksAvailable = false;
|
|
168
|
+
try {
|
|
169
|
+
const which = Bun.spawn(["nixpacks", "--version"], { stdout: "pipe", stderr: "pipe" });
|
|
170
|
+
const code = await which.exited;
|
|
171
|
+
nixpacksAvailable = code === 0;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
/* not installed */
|
|
175
|
+
}
|
|
176
|
+
if (nixpacksAvailable) {
|
|
177
|
+
ctx.status("Running nixpacks build locally...");
|
|
178
|
+
try {
|
|
179
|
+
const build = Bun.spawn(["nixpacks", "build", tmpDir, "--name", `repro-${input.deployId}`], {
|
|
180
|
+
cwd: tmpDir,
|
|
181
|
+
stdout: "inherit",
|
|
182
|
+
stderr: "inherit",
|
|
183
|
+
});
|
|
184
|
+
const code = await build.exited;
|
|
185
|
+
builtLocally = code === 0;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
/* spawn failed despite version check passing — rare but tolerable */
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Codex P2 follow-up on 3b609f9: pin the redeploy suggestion to
|
|
192
|
+
// THIS deploy id, not the bare `redeploy` form. Without it,
|
|
193
|
+
// `bunx percher redeploy` resolves to the LATEST LIVE deploy —
|
|
194
|
+
// typically the previous successful one, not the failed source the
|
|
195
|
+
// user just reproduced. That'd retry the wrong source entirely.
|
|
196
|
+
const buildHint = builtLocally
|
|
197
|
+
? `Build succeeded locally — the cloud failure may have been infra-flake. Retry the same source server-side: \`bunx percher redeploy ${input.deployId} --app ${app.name}\``
|
|
198
|
+
: nixpacksAvailable
|
|
199
|
+
? "nixpacks build also failed locally — same error as cloud. Iterate on the source in the tmp dir, then `bunx percher publish` from the project root once fixed."
|
|
200
|
+
: `nixpacks not on PATH. Install from https://nixpacks.com to reproduce the build, or run your own build command in ${tmpDir}.`;
|
|
201
|
+
return {
|
|
202
|
+
status: builtLocally ? "extracted_and_built" : "extracted",
|
|
203
|
+
appName: app.name,
|
|
204
|
+
deployId: input.deployId,
|
|
205
|
+
tmpDir,
|
|
206
|
+
currentAppEnvKeys,
|
|
207
|
+
builtLocally,
|
|
208
|
+
summary: `Source extracted to ${tmpDir}. ${envHint} ${buildHint}`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=reproduce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reproduce.js","sourceRoot":"","sources":["../../src/commands/reproduce.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reset-superuser.d.ts","sourceRoot":"","sources":["../../src/commands/reset-superuser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"reset-superuser.d.ts","sourceRoot":"","sources":["../../src/commands/reset-superuser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,yBAAyB;;IAEpC;;;;;;;OAOG;;;;;;;;EAEH,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,KAAK,GAAE,mBAAwB,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAS/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reset-superuser.js","sourceRoot":"","sources":["../../src/commands/reset-superuser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"reset-superuser.js","sourceRoot":"","sources":["../../src/commands/reset-superuser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B;;;;;;;OAOG;IACH,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAUH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAY,EACZ,QAA6B,EAAE;IAE/B,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,IAAI,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,gBAAgB,CAAC,4CAA4C,EAAE;YACvE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,6DAA6D;SACpE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { BackupSidecar, RestoreJob } from "@percher/client";
|
|
2
|
+
import { z } from "zod/v3";
|
|
3
|
+
import type { Context } from "../context";
|
|
4
|
+
/**
|
|
5
|
+
* Per-app restore (B.2 — CLI/MCP entry point on top of B.1.4).
|
|
6
|
+
*
|
|
7
|
+
* Two surfaces:
|
|
8
|
+
* - listBackups(ctx, input) → resolved sidecar list, no mutation
|
|
9
|
+
* - restore(ctx, input) → kicks off + polls until terminal
|
|
10
|
+
*
|
|
11
|
+
* `--dry-run`: validates source resolves to a backup the user actually
|
|
12
|
+
* has + lists what would be restored. Doesn't touch the API beyond
|
|
13
|
+
* GET /apps/:app/backups. Equivalent to "show me what restore <date>
|
|
14
|
+
* would do" — the documented v1 affordance from plan-doc B.2.
|
|
15
|
+
*/
|
|
16
|
+
export declare const listBackupsInputSchema: z.ZodObject<{
|
|
17
|
+
app: z.ZodOptional<z.ZodString>;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
app?: string | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
app?: string | undefined;
|
|
22
|
+
}>;
|
|
23
|
+
export type ListBackupsInput = z.infer<typeof listBackupsInputSchema>;
|
|
24
|
+
export declare function listBackups(ctx: Context, input: ListBackupsInput): Promise<{
|
|
25
|
+
backups: BackupSidecar[];
|
|
26
|
+
skipped: Array<{
|
|
27
|
+
filename: string;
|
|
28
|
+
reason: string;
|
|
29
|
+
}>;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Public input — what shows up in MCP `inputSchema` for AI assistants
|
|
33
|
+
* + on CLI flags. Only fields a real caller should set live here. Test
|
|
34
|
+
* + internal injection (poll cadence, timeout overrides) goes via the
|
|
35
|
+
* second `RestoreInternals` parameter so they don't leak into the
|
|
36
|
+
* public schema. Pre-fix had `_pollIntervalMs`/`_timeoutMs` on this
|
|
37
|
+
* schema with underscore-prefixes — visible to MCP, confusing for AI
|
|
38
|
+
* tooling that didn't know "_" meant "test-only".
|
|
39
|
+
*/
|
|
40
|
+
export declare const restoreInputSchema: z.ZodObject<{
|
|
41
|
+
app: z.ZodOptional<z.ZodString>;
|
|
42
|
+
/** "latest" | "YYYY-MM-DD" | "<backup_id>" — passed through to API. */
|
|
43
|
+
source: z.ZodString;
|
|
44
|
+
/** Defaults to ["appdata", "pocketbase"] when undefined — matches API. */
|
|
45
|
+
components: z.ZodOptional<z.ZodArray<z.ZodEnum<["appdata", "pocketbase"]>, "many">>;
|
|
46
|
+
/** Validate source + show what would happen, but don't actually start
|
|
47
|
+
* the restore. */
|
|
48
|
+
dryRun: z.ZodDefault<z.ZodBoolean>;
|
|
49
|
+
}, "strip", z.ZodTypeAny, {
|
|
50
|
+
dryRun: boolean;
|
|
51
|
+
source: string;
|
|
52
|
+
app?: string | undefined;
|
|
53
|
+
components?: ("pocketbase" | "appdata")[] | undefined;
|
|
54
|
+
}, {
|
|
55
|
+
source: string;
|
|
56
|
+
app?: string | undefined;
|
|
57
|
+
dryRun?: boolean | undefined;
|
|
58
|
+
components?: ("pocketbase" | "appdata")[] | undefined;
|
|
59
|
+
}>;
|
|
60
|
+
export type RestoreInput = z.infer<typeof restoreInputSchema>;
|
|
61
|
+
/**
|
|
62
|
+
* Internal-only knobs for tests + future automation. NOT part of the
|
|
63
|
+
* Zod schema → not surfaced to MCP / CLI users. Production callers
|
|
64
|
+
* pass nothing; tests pass small intervals so they don't sleep.
|
|
65
|
+
*/
|
|
66
|
+
export interface RestoreInternals {
|
|
67
|
+
/** Poll cadence between status checks (ms). Default 2000. */
|
|
68
|
+
pollIntervalMs?: number;
|
|
69
|
+
/** Hard cap before throwing restore.timeout (ms). Default 35 min. */
|
|
70
|
+
timeoutMs?: number;
|
|
71
|
+
}
|
|
72
|
+
export interface DryRunResult {
|
|
73
|
+
kind: "dry-run";
|
|
74
|
+
app: string;
|
|
75
|
+
resolvedBackup: BackupSidecar;
|
|
76
|
+
components: ("appdata" | "pocketbase")[];
|
|
77
|
+
}
|
|
78
|
+
export declare function restore(ctx: Context, input: RestoreInput, internals?: RestoreInternals): Promise<RestoreJob | DryRunResult>;
|
|
79
|
+
//# sourceMappingURL=restore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../../src/commands/restore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,sBAAsB;;;;;;EAEjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,EAAE,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAS7F;AAID;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB;;IAE7B,uEAAuE;;IAEvE,0EAA0E;;IAE1E;uBACmB;;;;;;;;;;;;EAEnB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,aAAa,CAAC;IAC9B,UAAU,EAAE,CAAC,SAAS,GAAG,YAAY,CAAC,EAAE,CAAC;CAC1C;AAED,wBAAsB,OAAO,CAC3B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,YAAY,EACnB,SAAS,GAAE,gBAAqB,GAC/B,OAAO,CAAC,UAAU,GAAG,YAAY,CAAC,CAiFpC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { z } from "zod/v3";
|
|
2
|
+
import { readPercherTomlAppName } from "../app-name";
|
|
3
|
+
import { PercherCoreError } from "../errors";
|
|
4
|
+
/**
|
|
5
|
+
* Per-app restore (B.2 — CLI/MCP entry point on top of B.1.4).
|
|
6
|
+
*
|
|
7
|
+
* Two surfaces:
|
|
8
|
+
* - listBackups(ctx, input) → resolved sidecar list, no mutation
|
|
9
|
+
* - restore(ctx, input) → kicks off + polls until terminal
|
|
10
|
+
*
|
|
11
|
+
* `--dry-run`: validates source resolves to a backup the user actually
|
|
12
|
+
* has + lists what would be restored. Doesn't touch the API beyond
|
|
13
|
+
* GET /apps/:app/backups. Equivalent to "show me what restore <date>
|
|
14
|
+
* would do" — the documented v1 affordance from plan-doc B.2.
|
|
15
|
+
*/
|
|
16
|
+
export const listBackupsInputSchema = z.object({
|
|
17
|
+
app: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
export async function listBackups(ctx, input) {
|
|
20
|
+
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
21
|
+
if (!name) {
|
|
22
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
23
|
+
code: "logs.no-app",
|
|
24
|
+
hint: "Pass --app <name> or run from a directory with percher.toml.",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return ctx.client.apps.listBackups(name);
|
|
28
|
+
}
|
|
29
|
+
const RESTORE_COMPONENTS = ["appdata", "pocketbase"];
|
|
30
|
+
/**
|
|
31
|
+
* Public input — what shows up in MCP `inputSchema` for AI assistants
|
|
32
|
+
* + on CLI flags. Only fields a real caller should set live here. Test
|
|
33
|
+
* + internal injection (poll cadence, timeout overrides) goes via the
|
|
34
|
+
* second `RestoreInternals` parameter so they don't leak into the
|
|
35
|
+
* public schema. Pre-fix had `_pollIntervalMs`/`_timeoutMs` on this
|
|
36
|
+
* schema with underscore-prefixes — visible to MCP, confusing for AI
|
|
37
|
+
* tooling that didn't know "_" meant "test-only".
|
|
38
|
+
*/
|
|
39
|
+
export const restoreInputSchema = z.object({
|
|
40
|
+
app: z.string().optional(),
|
|
41
|
+
/** "latest" | "YYYY-MM-DD" | "<backup_id>" — passed through to API. */
|
|
42
|
+
source: z.string().min(1),
|
|
43
|
+
/** Defaults to ["appdata", "pocketbase"] when undefined — matches API. */
|
|
44
|
+
components: z.array(z.enum(RESTORE_COMPONENTS)).optional(),
|
|
45
|
+
/** Validate source + show what would happen, but don't actually start
|
|
46
|
+
* the restore. */
|
|
47
|
+
dryRun: z.boolean().default(false),
|
|
48
|
+
});
|
|
49
|
+
export async function restore(ctx, input, internals = {}) {
|
|
50
|
+
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
51
|
+
if (!name) {
|
|
52
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
53
|
+
code: "logs.no-app",
|
|
54
|
+
hint: "Pass --app <name> or run from a directory with percher.toml.",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (input.dryRun) {
|
|
58
|
+
// Resolve source against listBackups so we can show what WOULD restore.
|
|
59
|
+
// Trust the API's source-resolution logic — don't reimplement
|
|
60
|
+
// "latest"/date/id matching here. Hits the same logic the worker
|
|
61
|
+
// /restore/inspect would; just no GPG decrypt + no orchestration.
|
|
62
|
+
const { backups } = await ctx.client.apps.listBackups(name);
|
|
63
|
+
const resolved = resolveSource(backups, input.source);
|
|
64
|
+
if (!resolved) {
|
|
65
|
+
throw new PercherCoreError(`No backup matches "${input.source}" for app "${name}"`, {
|
|
66
|
+
code: "restore.source-not-found",
|
|
67
|
+
hint: 'Try "latest", a date "YYYY-MM-DD", or a full backup id.',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
kind: "dry-run",
|
|
72
|
+
app: name,
|
|
73
|
+
resolvedBackup: resolved,
|
|
74
|
+
components: input.components ?? ["appdata", "pocketbase"],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
let job = await ctx.client.apps.startRestore(name, {
|
|
78
|
+
source: input.source,
|
|
79
|
+
components: input.components,
|
|
80
|
+
});
|
|
81
|
+
const pollInterval = internals.pollIntervalMs ?? 2000;
|
|
82
|
+
// 35 min default — generous enough for big PB volumes (typically 30
|
|
83
|
+
// min worker watchdog cleans up orphans, so we want CLI to stay alive
|
|
84
|
+
// long enough that "timed out" never fires when the actual job is
|
|
85
|
+
// still running). Override via internals.timeoutMs in tests.
|
|
86
|
+
const timeoutMs = internals.timeoutMs ?? 35 * 60 * 1000;
|
|
87
|
+
const startedAt = Date.now();
|
|
88
|
+
let lastStatus = job.status;
|
|
89
|
+
const TERMINAL = ["done", "rolled_back", "failed"];
|
|
90
|
+
while (!TERMINAL.includes(job.status)) {
|
|
91
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
92
|
+
throw new PercherCoreError("Restore timed out from the CLI's perspective. The job may still be running on the server — check the dashboard or `percher backups` to confirm before retrying.", {
|
|
93
|
+
code: "restore.timeout",
|
|
94
|
+
hint: "If the job is genuinely stuck, the watchdog will mark it failed within 5 min so you can retry from a clean slate.",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (job.status !== lastStatus) {
|
|
98
|
+
ctx.status(`${humanizeStatus(job.status)}...`);
|
|
99
|
+
lastStatus = job.status;
|
|
100
|
+
}
|
|
101
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
102
|
+
job = await ctx.client.apps.getRestoreJob(name, job.id);
|
|
103
|
+
}
|
|
104
|
+
if (job.status === "failed") {
|
|
105
|
+
throw new PercherCoreError(`Restore failed: ${job.errorMessage ?? "unknown error"}`, {
|
|
106
|
+
code: "restore.failed",
|
|
107
|
+
hint: "Run `percher logs` or check the dashboard for details.",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (job.status === "rolled_back") {
|
|
111
|
+
throw new PercherCoreError(`Restore rolled back: ${job.errorMessage ?? "an error during restore was caught and undone"}`, {
|
|
112
|
+
code: "restore.rolled-back",
|
|
113
|
+
hint: "Your app is back to its pre-restore state. Check logs for what failed.",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return job;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Match a `source` spec ("latest" | "YYYY-MM-DD" | "<id>") against the
|
|
120
|
+
* sidecar list. Mirrors the API's resolveBackup logic but on the
|
|
121
|
+
* sidecar projection instead of file metadata. Used only by --dry-run.
|
|
122
|
+
*/
|
|
123
|
+
function resolveSource(backups, source) {
|
|
124
|
+
if (backups.length === 0)
|
|
125
|
+
return null;
|
|
126
|
+
const sorted = [...backups].sort((a, b) => b.backup_id.localeCompare(a.backup_id));
|
|
127
|
+
if (source === "latest")
|
|
128
|
+
return sorted[0] ?? null;
|
|
129
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(source)) {
|
|
130
|
+
// Reject malformed dates. Two cases:
|
|
131
|
+
// 1. Hard parse failure ("9999-99-99") — Date.parse returns NaN.
|
|
132
|
+
// 2. Calendar overflow ("2026-02-30") — Date.parse SILENTLY rolls
|
|
133
|
+
// to "2026-03-02". The regex can't tell them apart, and
|
|
134
|
+
// isNaN(parse) returns false because the rolled date is valid.
|
|
135
|
+
// Defense: compare the roundtripped ISO prefix to the input.
|
|
136
|
+
const ts = Date.parse(`${source}T00:00:00Z`);
|
|
137
|
+
if (Number.isNaN(ts))
|
|
138
|
+
return null;
|
|
139
|
+
const roundtrip = new Date(ts).toISOString().slice(0, 10);
|
|
140
|
+
if (roundtrip !== source)
|
|
141
|
+
return null;
|
|
142
|
+
return sorted.find((b) => b.backup_id.startsWith(`${source}_`)) ?? null;
|
|
143
|
+
}
|
|
144
|
+
return sorted.find((b) => b.backup_id === source) ?? null;
|
|
145
|
+
}
|
|
146
|
+
function humanizeStatus(status) {
|
|
147
|
+
switch (status) {
|
|
148
|
+
case "preparing":
|
|
149
|
+
return "Preparing";
|
|
150
|
+
case "quiescing":
|
|
151
|
+
return "Stopping containers";
|
|
152
|
+
case "restoring_data":
|
|
153
|
+
return "Restoring data";
|
|
154
|
+
case "starting":
|
|
155
|
+
return "Starting containers";
|
|
156
|
+
case "verifying":
|
|
157
|
+
return "Verifying health";
|
|
158
|
+
case "rolling_back":
|
|
159
|
+
return "Rolling back";
|
|
160
|
+
default:
|
|
161
|
+
return status;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=restore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.js","sourceRoot":"","sources":["../../src/commands/restore.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC3B,CAAC,CAAC;AAGH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAY,EACZ,KAAuB;IAEvB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,IAAI,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,gBAAgB,CAAC,4CAA4C,EAAE;YACvE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,8DAA8D;SACrE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,kBAAkB,GAAG,CAAC,SAAS,EAAE,YAAY,CAAU,CAAC;AAE9D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,uEAAuE;IACvE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,0EAA0E;IAC1E,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC1D;uBACmB;IACnB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACnC,CAAC,CAAC;AAsBH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAY,EACZ,KAAmB,EACnB,YAA8B,EAAE;IAEhC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,IAAI,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,gBAAgB,CAAC,4CAA4C,EAAE;YACvE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,8DAA8D;SACrE,CAAC,CAAC;IACL,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,wEAAwE;QACxE,8DAA8D;QAC9D,iEAAiE;QACjE,kEAAkE;QAClE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,gBAAgB,CAAC,sBAAsB,KAAK,CAAC,MAAM,cAAc,IAAI,GAAG,EAAE;gBAClF,IAAI,EAAE,0BAA0B;gBAChC,IAAI,EAAE,yDAAyD;aAChE,CAAC,CAAC;QACL,CAAC;QACD,OAAO;YACL,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,IAAI;YACT,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;SAC1D,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;QACjD,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,SAAS,CAAC,cAAc,IAAI,IAAI,CAAC;IACtD,oEAAoE;IACpE,sEAAsE;IACtE,kEAAkE;IAClE,6DAA6D;IAC7D,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC;IAE5B,MAAM,QAAQ,GAA2B,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;IAE3E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;YACvC,MAAM,IAAI,gBAAgB,CACxB,iKAAiK,EACjK;gBACE,IAAI,EAAE,iBAAiB;gBACvB,IAAI,EAAE,mHAAmH;aAC1H,CACF,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC9B,GAAG,CAAC,MAAM,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/C,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC;QAC1B,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;QACtD,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,gBAAgB,CAAC,mBAAmB,GAAG,CAAC,YAAY,IAAI,eAAe,EAAE,EAAE;YACnF,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,wDAAwD;SAC/D,CAAC,CAAC;IACL,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;QACjC,MAAM,IAAI,gBAAgB,CACxB,wBAAwB,GAAG,CAAC,YAAY,IAAI,+CAA+C,EAAE,EAC7F;YACE,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE,wEAAwE;SAC/E,CACF,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,OAAwB,EAAE,MAAc;IAC7D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACnF,IAAI,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAClD,IAAI,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,qCAAqC;QACrC,mEAAmE;QACnE,oEAAoE;QACpE,6DAA6D;QAC7D,oEAAoE;QACpE,kEAAkE;QAClE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,CAAC;QAC7C,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,SAAS,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QACtC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;IAC1E,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC;AAC5D,CAAC;AAED,SAAS,cAAc,CAAC,MAA4B;IAClD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,WAAW;YACd,OAAO,WAAW,CAAC;QACrB,KAAK,WAAW;YACd,OAAO,qBAAqB,CAAC;QAC/B,KAAK,gBAAgB;YACnB,OAAO,gBAAgB,CAAC;QAC1B,KAAK,UAAU;YACb,OAAO,qBAAqB,CAAC;QAC/B,KAAK,WAAW;YACd,OAAO,kBAAkB,CAAC;QAC5B,KAAK,cAAc;YACjB,OAAO,cAAc,CAAC;QACxB;YACE,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/commands/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/commands/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,iBAAiB;;;;;;EAE5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,wBAAsB,MAAM,CAC1B,GAAG,EAAE,OAAO,EACZ,KAAK,GAAE,WAAgB,GACtB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAS9C"}
|
package/dist/commands/resume.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/commands/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/commands/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC3B,CAAC,CAAC;AAGH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,GAAY,EACZ,QAAqB,EAAE;IAEvB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,IAAI,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,gBAAgB,CAAC,4CAA4C,EAAE;YACvE,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,6DAA6D;SACpE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -1,22 +1,34 @@
|
|
|
1
1
|
import type { Deployment } from "@percher/client";
|
|
2
|
-
import { z } from "zod";
|
|
2
|
+
import { z } from "zod/v3";
|
|
3
3
|
import type { Context } from "../context";
|
|
4
|
+
/**
|
|
5
|
+
* Public input — surfaces in MCP `inputSchema` for AI assistants + on
|
|
6
|
+
* CLI flags. Internal knobs (poll cadence, timeout overrides) used to
|
|
7
|
+
* sit here with `_pollIntervalMs`/`_timeoutMs` underscore-prefix names.
|
|
8
|
+
* Visible to MCP, confusing for AI tooling. Moved to a separate
|
|
9
|
+
* `RollbackInternals` parameter — same shape used by push/restore.
|
|
10
|
+
*/
|
|
4
11
|
export declare const rollbackInputSchema: z.ZodObject<{
|
|
5
12
|
app: z.ZodOptional<z.ZodString>;
|
|
6
13
|
commitSha: z.ZodString;
|
|
7
|
-
_pollIntervalMs: z.ZodOptional<z.ZodNumber>;
|
|
8
|
-
_timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
9
14
|
}, "strip", z.ZodTypeAny, {
|
|
10
15
|
commitSha: string;
|
|
11
16
|
app?: string | undefined;
|
|
12
|
-
_pollIntervalMs?: number | undefined;
|
|
13
|
-
_timeoutMs?: number | undefined;
|
|
14
17
|
}, {
|
|
15
18
|
commitSha: string;
|
|
16
19
|
app?: string | undefined;
|
|
17
|
-
_pollIntervalMs?: number | undefined;
|
|
18
|
-
_timeoutMs?: number | undefined;
|
|
19
20
|
}>;
|
|
20
21
|
export type RollbackInput = z.infer<typeof rollbackInputSchema>;
|
|
21
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Internal-only knobs for tests + future automation. NOT part of the
|
|
24
|
+
* Zod schema → not surfaced to MCP / CLI users. Production callers
|
|
25
|
+
* pass nothing; tests pass small intervals so they don't sleep.
|
|
26
|
+
*/
|
|
27
|
+
export interface RollbackInternals {
|
|
28
|
+
/** Poll cadence between deployment status checks (ms). Default 2000. */
|
|
29
|
+
pollIntervalMs?: number;
|
|
30
|
+
/** Hard cap before throwing push.deploy-timeout (ms). Default 5 min. */
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
}
|
|
33
|
+
export declare function rollback(ctx: Context, input: RollbackInput, internals?: RollbackInternals): Promise<Deployment>;
|
|
22
34
|
//# sourceMappingURL=rollback.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/commands/rollback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/commands/rollback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;EAG9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,aAAa,EACpB,SAAS,GAAE,iBAAsB,GAChC,OAAO,CAAC,UAAU,CAAC,CAkCrB"}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
1
|
+
import { z } from "zod/v3";
|
|
2
2
|
import { readPercherTomlAppName } from "../app-name";
|
|
3
3
|
import { PercherCoreError } from "../errors";
|
|
4
|
+
/**
|
|
5
|
+
* Public input — surfaces in MCP `inputSchema` for AI assistants + on
|
|
6
|
+
* CLI flags. Internal knobs (poll cadence, timeout overrides) used to
|
|
7
|
+
* sit here with `_pollIntervalMs`/`_timeoutMs` underscore-prefix names.
|
|
8
|
+
* Visible to MCP, confusing for AI tooling. Moved to a separate
|
|
9
|
+
* `RollbackInternals` parameter — same shape used by push/restore.
|
|
10
|
+
*/
|
|
4
11
|
export const rollbackInputSchema = z.object({
|
|
5
12
|
app: z.string().optional(),
|
|
6
13
|
commitSha: z.string().min(1),
|
|
7
|
-
_pollIntervalMs: z.number().int().positive().optional(),
|
|
8
|
-
_timeoutMs: z.number().int().positive().optional(),
|
|
9
14
|
});
|
|
10
|
-
export async function rollback(ctx, input) {
|
|
15
|
+
export async function rollback(ctx, input, internals = {}) {
|
|
11
16
|
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
12
17
|
if (!name) {
|
|
13
18
|
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
@@ -16,8 +21,8 @@ export async function rollback(ctx, input) {
|
|
|
16
21
|
});
|
|
17
22
|
}
|
|
18
23
|
let deployment = await ctx.client.apps.rollback(name, input.commitSha);
|
|
19
|
-
const pollInterval =
|
|
20
|
-
const timeoutMs =
|
|
24
|
+
const pollInterval = internals.pollIntervalMs ?? 2000;
|
|
25
|
+
const timeoutMs = internals.timeoutMs ?? 5 * 60 * 1000;
|
|
21
26
|
const startedAt = Date.now();
|
|
22
27
|
while (deployment.status !== "live" && deployment.status !== "failed") {
|
|
23
28
|
if (Date.now() - startedAt > timeoutMs) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/commands/rollback.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/commands/rollback.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC7B,CAAC,CAAC;AAeH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAY,EACZ,KAAoB,EACpB,YAA+B,EAAE;IAEjC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,IAAI,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,gBAAgB,CAAC,4CAA4C,EAAE;YACvE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,8DAA8D;SACrE,CAAC,CAAC;IACL,CAAC;IACD,IAAI,UAAU,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAEvE,MAAM,YAAY,GAAG,SAAS,CAAC,cAAc,IAAI,IAAI,CAAC;IACtD,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,OAAO,UAAU,CAAC,MAAM,KAAK,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACtE,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;YACvC,MAAM,IAAI,gBAAgB,CAAC,oBAAoB,EAAE;gBAC/C,IAAI,EAAE,qBAAqB;gBAC3B,IAAI,EAAE,0CAA0C;aACjD,CAAC,CAAC;QACL,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC;QACtC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;QACtD,UAAU,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACnC,MAAM,IAAI,gBAAgB,CAAC,iBAAiB,EAAE;YAC5C,IAAI,EAAE,oBAAoB;YAC1B,IAAI,EAAE,4CAA4C;SACnD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
|