@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,35 @@
|
|
|
1
|
+
import { z } from "zod/v3";
|
|
2
|
+
import type { Context } from "../context";
|
|
3
|
+
export declare const unsuspendInputSchema: z.ZodObject<{
|
|
4
|
+
app: z.ZodString;
|
|
5
|
+
}, "strip", z.ZodTypeAny, {
|
|
6
|
+
app: string;
|
|
7
|
+
}, {
|
|
8
|
+
app: string;
|
|
9
|
+
}>;
|
|
10
|
+
export type UnsuspendInput = z.infer<typeof unsuspendInputSchema>;
|
|
11
|
+
export interface UnsuspendResult {
|
|
12
|
+
ok: true;
|
|
13
|
+
app: {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
status: string;
|
|
17
|
+
};
|
|
18
|
+
/** True if this call flipped the app from suspended to active.
|
|
19
|
+
* False if the app was already active (idempotent). */
|
|
20
|
+
flipped: boolean;
|
|
21
|
+
summary: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Unsuspend an app. Used from CLI ("Lock removed") and from the
|
|
25
|
+
* agent surface (`percher_unsuspend` MCP tool) when an auto-suspend
|
|
26
|
+
* is the recovery action the agent should take after the user has
|
|
27
|
+
* fixed the underlying failure.
|
|
28
|
+
*
|
|
29
|
+
* Server-side this triggers the cooldown threshold in
|
|
30
|
+
* FailureLoopGuard: if the app fails N=3 more times within an hour,
|
|
31
|
+
* it auto-suspends again (faster than the standard N=8) — discourages
|
|
32
|
+
* the "unsuspend → resume the loop → re-burn the budget" antipattern.
|
|
33
|
+
*/
|
|
34
|
+
export declare function unsuspend(ctx: Context, input: UnsuspendInput): Promise<UnsuspendResult>;
|
|
35
|
+
//# sourceMappingURL=unsuspend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsuspend.d.ts","sourceRoot":"","sources":["../../src/commands/unsuspend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,oBAAoB;;;;;;EAE/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD;4DACwD;IACxD,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAU7F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod/v3";
|
|
2
|
+
export const unsuspendInputSchema = z.object({
|
|
3
|
+
app: z.string().min(1).describe("App name or id to unsuspend"),
|
|
4
|
+
});
|
|
5
|
+
/**
|
|
6
|
+
* Unsuspend an app. Used from CLI ("Lock removed") and from the
|
|
7
|
+
* agent surface (`percher_unsuspend` MCP tool) when an auto-suspend
|
|
8
|
+
* is the recovery action the agent should take after the user has
|
|
9
|
+
* fixed the underlying failure.
|
|
10
|
+
*
|
|
11
|
+
* Server-side this triggers the cooldown threshold in
|
|
12
|
+
* FailureLoopGuard: if the app fails N=3 more times within an hour,
|
|
13
|
+
* it auto-suspends again (faster than the standard N=8) — discourages
|
|
14
|
+
* the "unsuspend → resume the loop → re-burn the budget" antipattern.
|
|
15
|
+
*/
|
|
16
|
+
export async function unsuspend(ctx, input) {
|
|
17
|
+
const result = await ctx.client.apps.unsuspend(input.app);
|
|
18
|
+
return {
|
|
19
|
+
ok: true,
|
|
20
|
+
app: result.app,
|
|
21
|
+
flipped: result.flipped,
|
|
22
|
+
summary: result.flipped
|
|
23
|
+
? `Unsuspended ${result.app.name}. If it fails 3 more times in the next hour, the cooldown threshold will auto-suspend it again — fix the cause before retrying.`
|
|
24
|
+
: `${result.app.name} was already active (no change).`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=unsuspend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsuspend.js","sourceRoot":"","sources":["../../src/commands/unsuspend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAG3B,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;CAC/D,CAAC,CAAC;AAYH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAY,EAAE,KAAqB;IACjE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1D,OAAO;QACL,EAAE,EAAE,IAAI;QACR,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO;YACrB,CAAC,CAAC,eAAe,MAAM,CAAC,GAAG,CAAC,IAAI,iIAAiI;YACjK,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,kCAAkC;KACzD,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../src/commands/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../src/commands/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,mBAAmB;;;;;;EAA2C,CAAC;AAC5E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,aAAkB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAS7F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../src/commands/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../src/commands/versions.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,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAS5E,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,QAAuB,EAAE;IACpE,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,6DAA6D;SACpE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { App, Deployment } from "@percher/client";
|
|
2
|
+
import { z } from "zod/v3";
|
|
3
|
+
import type { Context } from "../context";
|
|
4
|
+
import { type PublishRecovery } from "../recovery";
|
|
5
|
+
import type { PublishError } from "./publish";
|
|
6
|
+
export declare const waitForDeployInputSchema: z.ZodObject<{
|
|
7
|
+
app: z.ZodString;
|
|
8
|
+
deployId: z.ZodString;
|
|
9
|
+
timeoutSeconds: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
pollIntervalSeconds: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
app: string;
|
|
13
|
+
deployId: string;
|
|
14
|
+
timeoutSeconds?: number | undefined;
|
|
15
|
+
pollIntervalSeconds?: number | undefined;
|
|
16
|
+
}, {
|
|
17
|
+
app: string;
|
|
18
|
+
deployId: string;
|
|
19
|
+
timeoutSeconds?: number | undefined;
|
|
20
|
+
pollIntervalSeconds?: number | undefined;
|
|
21
|
+
}>;
|
|
22
|
+
export type WaitForDeployInput = z.infer<typeof waitForDeployInputSchema>;
|
|
23
|
+
export interface WaitForDeployResult {
|
|
24
|
+
/**
|
|
25
|
+
* - `live` — deployment reached terminal success.
|
|
26
|
+
* - `failed` — deployment reached terminal failure (`error` populated).
|
|
27
|
+
* - `replaced` — deployment was superseded. Resolver looks at the
|
|
28
|
+
* latest deploy on the app and routes accordingly:
|
|
29
|
+
* • newer live exists → `nextAction: "none"`, `url` is the
|
|
30
|
+
* current live URL, `summary` includes the resolved deployId.
|
|
31
|
+
* • newer deploy still in flight → `nextAction: "wait_deploy"`
|
|
32
|
+
* pointing at the newer deployId.
|
|
33
|
+
* • no newer / latest also failed → `nextAction: "ask_user"`.
|
|
34
|
+
* Never `retry` — replaced isn't a transient failure of this row.
|
|
35
|
+
* - `still_running` — timeout hit before terminal status; agent should
|
|
36
|
+
* call this tool again with the same deployId.
|
|
37
|
+
*/
|
|
38
|
+
status: "live" | "failed" | "replaced" | "still_running";
|
|
39
|
+
app: {
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
url: string;
|
|
43
|
+
};
|
|
44
|
+
deployment: Deployment;
|
|
45
|
+
/** Live or preview URL on success. */
|
|
46
|
+
url?: string;
|
|
47
|
+
/** Wall-clock seconds spent in this single wait call. */
|
|
48
|
+
elapsedSeconds: number;
|
|
49
|
+
/**
|
|
50
|
+
* Total seconds since the deployment was first created (server-side
|
|
51
|
+
* `createdAt`). Helps the agent answer "is this stuck?" — combined
|
|
52
|
+
* with status, an `elapsedSeconds`-since-create > 600 in `building`
|
|
53
|
+
* is a strong signal of a real stall, not just a slow build.
|
|
54
|
+
*/
|
|
55
|
+
totalElapsedSeconds: number;
|
|
56
|
+
error?: PublishError;
|
|
57
|
+
recovery: PublishRecovery;
|
|
58
|
+
summary: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* FUTURE11 Phase 2 — short-poll a specific deploy without starting a new
|
|
62
|
+
* one. Returns terminal results when the deploy reaches live/failed
|
|
63
|
+
* within the timeout, otherwise returns `still_running` with a
|
|
64
|
+
* `wait_deploy` recovery so the agent loops without growing the call
|
|
65
|
+
* stack. Never starts a new deploy.
|
|
66
|
+
*/
|
|
67
|
+
export declare function waitForDeploy(ctx: Context, input: WaitForDeployInput): Promise<WaitForDeployResult>;
|
|
68
|
+
/**
|
|
69
|
+
* FUTURE11 review round 5 — resolve what `replaced` actually means by
|
|
70
|
+
* looking at the latest deploy. Two API code-paths produce `replaced`:
|
|
71
|
+
*
|
|
72
|
+
* 1. `markPreviousLiveAsReplaced` — a NEWER live deploy succeeded
|
|
73
|
+
* and pushed this row aside. App is live; route to nextAction='none'.
|
|
74
|
+
* 2. `markLiveDeployReplaced` — reconcile saw the container is gone
|
|
75
|
+
* (CONTAINER_NOT_FOUND). No newer live exists; app is effectively
|
|
76
|
+
* down. Route to ask_user.
|
|
77
|
+
*
|
|
78
|
+
* Resolver also handles the in-flight case where the newer deploy is
|
|
79
|
+
* still building — point at it via wait_deploy. Matches FUTURE12 Phase
|
|
80
|
+
* 4's locked behavior for `replaced_by_newer`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function resolveReplaced(opts: {
|
|
83
|
+
ctx: Context;
|
|
84
|
+
app: App;
|
|
85
|
+
replacedDeployment: Deployment;
|
|
86
|
+
}): Promise<{
|
|
87
|
+
recovery: PublishRecovery;
|
|
88
|
+
url?: string;
|
|
89
|
+
summary: string;
|
|
90
|
+
resolvedDeployment?: Deployment;
|
|
91
|
+
}>;
|
|
92
|
+
//# sourceMappingURL=wait-deploy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-deploy.d.ts","sourceRoot":"","sources":["../../src/commands/wait-deploy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACL,KAAK,eAAe,EAKrB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;EAmBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;OAaG;IACH,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,eAAe,CAAC;IACzD,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,UAAU,EAAE,UAAU,CAAC;IACvB,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAoE9B;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,kBAAkB,EAAE,UAAU,CAAC;CAChC,GAAG,OAAO,CAAC;IACV,QAAQ,EAAE,eAAe,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,UAAU,CAAC;CACjC,CAAC,CA4ED"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { z } from "zod/v3";
|
|
2
|
+
import { RECOVERY_NONE, recoveryAsk, recoveryNone, recoveryWait, } from "../recovery";
|
|
3
|
+
import { classifyDeploymentFailure } from "./publish-failure";
|
|
4
|
+
export const waitForDeployInputSchema = z.object({
|
|
5
|
+
app: z.string().describe("App name (the value of [app].name in percher.toml)"),
|
|
6
|
+
deployId: z.string().describe("Deploy id returned by percher_publish (e.g. dep_abc123)"),
|
|
7
|
+
timeoutSeconds: z
|
|
8
|
+
.number()
|
|
9
|
+
.int()
|
|
10
|
+
.min(1)
|
|
11
|
+
.max(120)
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Maximum wall-clock seconds to wait before returning still_running (default 30, max 120). Keeping this short is the point — the agent can resume in another short call without holding a long-lived connection."),
|
|
14
|
+
pollIntervalSeconds: z
|
|
15
|
+
.number()
|
|
16
|
+
.int()
|
|
17
|
+
.min(1)
|
|
18
|
+
.max(30)
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Seconds between polls (default 2)."),
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* FUTURE11 Phase 2 — short-poll a specific deploy without starting a new
|
|
24
|
+
* one. Returns terminal results when the deploy reaches live/failed
|
|
25
|
+
* within the timeout, otherwise returns `still_running` with a
|
|
26
|
+
* `wait_deploy` recovery so the agent loops without growing the call
|
|
27
|
+
* stack. Never starts a new deploy.
|
|
28
|
+
*/
|
|
29
|
+
export async function waitForDeploy(ctx, input) {
|
|
30
|
+
const timeoutSeconds = input.timeoutSeconds ?? 30;
|
|
31
|
+
const pollIntervalSeconds = input.pollIntervalSeconds ?? 2;
|
|
32
|
+
// Fetch app + initial deployment in parallel; the app row is needed for
|
|
33
|
+
// the URL on success and for failure-classification context.
|
|
34
|
+
const [app, initial] = await Promise.all([
|
|
35
|
+
ctx.client.apps.get(input.app),
|
|
36
|
+
ctx.client.apps.getDeployment(input.app, input.deployId),
|
|
37
|
+
]);
|
|
38
|
+
const startedAt = Date.now();
|
|
39
|
+
const deadlineMs = startedAt + timeoutSeconds * 1000;
|
|
40
|
+
let deployment = initial;
|
|
41
|
+
while (!isTerminal(deployment.status)) {
|
|
42
|
+
if (Date.now() >= deadlineMs) {
|
|
43
|
+
return buildStillRunningResult(app, deployment, startedAt);
|
|
44
|
+
}
|
|
45
|
+
await new Promise((r) => setTimeout(r, pollIntervalSeconds * 1000));
|
|
46
|
+
try {
|
|
47
|
+
deployment = await ctx.client.apps.getDeployment(input.app, input.deployId);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
// Transient fetch errors during a short wait don't justify
|
|
51
|
+
// throwing — return still_running so the agent retries. The
|
|
52
|
+
// deploy may already be live server-side; the agent's next call
|
|
53
|
+
// will pick that up.
|
|
54
|
+
const msg = err.message ?? String(err);
|
|
55
|
+
if (msg.startsWith("network error:")) {
|
|
56
|
+
return buildStillRunningResult(app, deployment, startedAt, msg);
|
|
57
|
+
}
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (deployment.status === "failed") {
|
|
62
|
+
const { error, recovery, summary } = await classifyDeploymentFailure({
|
|
63
|
+
ctx,
|
|
64
|
+
app,
|
|
65
|
+
deployment,
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
status: "failed",
|
|
69
|
+
app: { id: app.id, name: app.name, url: app.url },
|
|
70
|
+
deployment,
|
|
71
|
+
elapsedSeconds: Math.round((Date.now() - startedAt) / 1000),
|
|
72
|
+
totalElapsedSeconds: secondsSinceCreated(deployment),
|
|
73
|
+
error,
|
|
74
|
+
recovery,
|
|
75
|
+
summary,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (deployment.status === "replaced") {
|
|
79
|
+
return await buildReplacedResult({ ctx, app, deployment, startedAt });
|
|
80
|
+
}
|
|
81
|
+
const url = deployment.previewUrl ?? deployment.url ?? app.url;
|
|
82
|
+
return {
|
|
83
|
+
status: "live",
|
|
84
|
+
app: { id: app.id, name: app.name, url: app.url },
|
|
85
|
+
deployment,
|
|
86
|
+
url,
|
|
87
|
+
elapsedSeconds: Math.round((Date.now() - startedAt) / 1000),
|
|
88
|
+
totalElapsedSeconds: secondsSinceCreated(deployment),
|
|
89
|
+
recovery: RECOVERY_NONE,
|
|
90
|
+
summary: `${app.name} deploy ${deployment.id} is live → ${url}`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function isTerminal(status) {
|
|
94
|
+
return status === "live" || status === "failed" || status === "replaced";
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* FUTURE11 review round 5 — resolve what `replaced` actually means by
|
|
98
|
+
* looking at the latest deploy. Two API code-paths produce `replaced`:
|
|
99
|
+
*
|
|
100
|
+
* 1. `markPreviousLiveAsReplaced` — a NEWER live deploy succeeded
|
|
101
|
+
* and pushed this row aside. App is live; route to nextAction='none'.
|
|
102
|
+
* 2. `markLiveDeployReplaced` — reconcile saw the container is gone
|
|
103
|
+
* (CONTAINER_NOT_FOUND). No newer live exists; app is effectively
|
|
104
|
+
* down. Route to ask_user.
|
|
105
|
+
*
|
|
106
|
+
* Resolver also handles the in-flight case where the newer deploy is
|
|
107
|
+
* still building — point at it via wait_deploy. Matches FUTURE12 Phase
|
|
108
|
+
* 4's locked behavior for `replaced_by_newer`.
|
|
109
|
+
*/
|
|
110
|
+
export async function resolveReplaced(opts) {
|
|
111
|
+
const { ctx, app, replacedDeployment } = opts;
|
|
112
|
+
// Filter the lookup to the same deploy kind. A `replaced` row is
|
|
113
|
+
// always a live deploy in the API (both markPreviousLiveAsReplaced
|
|
114
|
+
// and markLiveDeployReplaced enforce eq(deployments.type, "live")),
|
|
115
|
+
// so without `type` filtering a newer preview deploy could hijack
|
|
116
|
+
// recovery — the resolver might wait on the preview, surface a
|
|
117
|
+
// preview URL as if it were the canonical live, or fall back to
|
|
118
|
+
// ask_user when previews push the real successor past the limit.
|
|
119
|
+
// Default to "live" when the row's type is missing for any reason.
|
|
120
|
+
const deployType = replacedDeployment.type ?? "live";
|
|
121
|
+
let latest;
|
|
122
|
+
try {
|
|
123
|
+
const deploys = await ctx.client.apps.listDeploys(app.name, {
|
|
124
|
+
limit: 5,
|
|
125
|
+
type: deployType,
|
|
126
|
+
});
|
|
127
|
+
// Skip the row we already know is replaced; pick the most recent
|
|
128
|
+
// deploy that's not this one. The list is ordered desc by createdAt.
|
|
129
|
+
latest = deploys.find((d) => d.id !== replacedDeployment.id);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return {
|
|
133
|
+
recovery: recoveryAsk({
|
|
134
|
+
prompt: `${app.name} deploy ${replacedDeployment.id} was replaced, but listing recent deploys failed. Check the dashboard or run \`percher doctor --app ${app.name}\` to inspect current state.`,
|
|
135
|
+
reasonCode: "replaced_by_newer",
|
|
136
|
+
}),
|
|
137
|
+
summary: `${app.name} deploy ${replacedDeployment.id} was replaced, but listing recent deploys failed. Surface to user — they can check the dashboard.`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (!latest) {
|
|
141
|
+
return {
|
|
142
|
+
recovery: recoveryAsk({
|
|
143
|
+
prompt: `${app.name} deploy ${replacedDeployment.id} was replaced and there are no other deploys to resolve to. Surface this to the user — they may need to redeploy.`,
|
|
144
|
+
reasonCode: "replaced_by_newer",
|
|
145
|
+
}),
|
|
146
|
+
summary: `${app.name} deploy ${replacedDeployment.id} was replaced and there are no other deploys to resolve to. Surface to user.`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (latest.status === "live") {
|
|
150
|
+
const url = latest.previewUrl ?? latest.url ?? app.url;
|
|
151
|
+
return {
|
|
152
|
+
recovery: recoveryNone({ reasonCode: "replaced_by_newer", url }),
|
|
153
|
+
url,
|
|
154
|
+
resolvedDeployment: latest,
|
|
155
|
+
summary: `${app.name} deploy ${replacedDeployment.id} was replaced — the app is live at ${url} via deploy ${latest.id}.`,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (latest.status === "queued" || latest.status === "building" || latest.status === "deploying") {
|
|
159
|
+
const reasonCode = latest.status === "queued"
|
|
160
|
+
? "deploy_queued"
|
|
161
|
+
: latest.status === "building"
|
|
162
|
+
? "deploy_building"
|
|
163
|
+
: "deploy_deploying";
|
|
164
|
+
return {
|
|
165
|
+
recovery: recoveryWait({ app: app.name, deployId: latest.id, reasonCode }),
|
|
166
|
+
resolvedDeployment: latest,
|
|
167
|
+
summary: `${app.name} deploy ${replacedDeployment.id} was replaced; the newer deploy ${latest.id} is ${latest.status} — call percher_wait_for_deploy.`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// latest is failed or another replaced — there's no clear current
|
|
171
|
+
// live state. Surface to user; FUTURE12's expanded doctor will own
|
|
172
|
+
// deeper diagnostics.
|
|
173
|
+
return {
|
|
174
|
+
recovery: recoveryAsk({
|
|
175
|
+
prompt: `${app.name} deploy ${replacedDeployment.id} was replaced, and the latest deploy ${latest.id} is also ${latest.status}. Run \`percher doctor --app ${app.name}\` to diagnose, or surface this to the user.`,
|
|
176
|
+
reasonCode: "replaced_by_newer",
|
|
177
|
+
}),
|
|
178
|
+
resolvedDeployment: latest,
|
|
179
|
+
summary: `${app.name} deploy ${replacedDeployment.id} was replaced; the latest deploy ${latest.id} is ${latest.status}. Surface to user.`,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async function buildReplacedResult(opts) {
|
|
183
|
+
const { ctx, app, deployment, startedAt } = opts;
|
|
184
|
+
const resolved = await resolveReplaced({ ctx, app, replacedDeployment: deployment });
|
|
185
|
+
return {
|
|
186
|
+
status: "replaced",
|
|
187
|
+
app: { id: app.id, name: app.name, url: app.url },
|
|
188
|
+
deployment,
|
|
189
|
+
url: resolved.url,
|
|
190
|
+
elapsedSeconds: Math.round((Date.now() - startedAt) / 1000),
|
|
191
|
+
totalElapsedSeconds: secondsSinceCreated(deployment),
|
|
192
|
+
recovery: resolved.recovery,
|
|
193
|
+
summary: resolved.summary,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function buildStillRunningResult(app, deployment, startedAt, networkHint) {
|
|
197
|
+
return {
|
|
198
|
+
status: "still_running",
|
|
199
|
+
app: { id: app.id, name: app.name, url: app.url },
|
|
200
|
+
deployment,
|
|
201
|
+
elapsedSeconds: Math.round((Date.now() - startedAt) / 1000),
|
|
202
|
+
totalElapsedSeconds: secondsSinceCreated(deployment),
|
|
203
|
+
recovery: recoveryWait({
|
|
204
|
+
app: app.name,
|
|
205
|
+
deployId: deployment.id,
|
|
206
|
+
reasonCode: deployment.status === "queued"
|
|
207
|
+
? "deploy_queued"
|
|
208
|
+
: deployment.status === "building"
|
|
209
|
+
? "deploy_building"
|
|
210
|
+
: deployment.status === "deploying"
|
|
211
|
+
? "deploy_deploying"
|
|
212
|
+
: "deploy_timeout",
|
|
213
|
+
}),
|
|
214
|
+
summary: networkHint
|
|
215
|
+
? `${app.name} deploy ${deployment.id} still ${deployment.status} (transient: ${networkHint}) — call percher_wait_for_deploy again.`
|
|
216
|
+
: `${app.name} deploy ${deployment.id} still ${deployment.status} — call percher_wait_for_deploy again.`,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function secondsSinceCreated(deployment) {
|
|
220
|
+
const t = Date.parse(deployment.createdAt);
|
|
221
|
+
if (Number.isNaN(t))
|
|
222
|
+
return 0;
|
|
223
|
+
return Math.max(0, Math.round((Date.now() - t) / 1000));
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=wait-deploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-deploy.js","sourceRoot":"","sources":["../../src/commands/wait-deploy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single env reference discovered by the source scanner.
|
|
3
|
+
*
|
|
4
|
+
* The scanner inspects an extracted upload tarball before queueing a deploy.
|
|
5
|
+
* Phase 6c uses these references to enforce the `[env]` contract in
|
|
6
|
+
* `percher.toml`: any static key not declared in `required`, `optional`, or
|
|
7
|
+
* `ignore` blocks the deploy with a `fix_config` problem.
|
|
8
|
+
*/
|
|
9
|
+
export interface EnvReference {
|
|
10
|
+
/** The env key referenced. Empty string when `shape` is `"dynamic"`. */
|
|
11
|
+
key: string;
|
|
12
|
+
/** File path relative to the source root (forward slashes). */
|
|
13
|
+
file: string;
|
|
14
|
+
/** 1-based line number where the reference appears. */
|
|
15
|
+
line: number;
|
|
16
|
+
/** Verbatim source line (trimmed) for diagnostics. */
|
|
17
|
+
context: string;
|
|
18
|
+
/** Static (literal key) vs dynamic (e.g. `process.env[varName]`). */
|
|
19
|
+
shape: "static" | "dynamic";
|
|
20
|
+
}
|
|
21
|
+
export interface ScanOptions {
|
|
22
|
+
/** Optional list of relative paths to skip on top of the built-in defaults. */
|
|
23
|
+
exclude?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Files larger than this in bytes are skipped silently (default 1 MiB).
|
|
26
|
+
* Prevents pathological inputs (minified bundles, huge JSON blobs) from
|
|
27
|
+
* dominating scan time.
|
|
28
|
+
*/
|
|
29
|
+
maxFileBytes?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Recursively scans `rootDir` for env references in supported source files.
|
|
33
|
+
*
|
|
34
|
+
* Read-only: never modifies the source tree. Tolerant of unreadable files and
|
|
35
|
+
* directories — they are skipped silently. Files exceeding `maxFileBytes` are
|
|
36
|
+
* skipped to bound runtime on pathological inputs (minified bundles, etc.).
|
|
37
|
+
*/
|
|
38
|
+
export declare function scanSourceForEnvRefs(rootDir: string, opts?: ScanOptions): Promise<EnvReference[]>;
|
|
39
|
+
//# sourceMappingURL=env-scan-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-scan-source.d.ts","sourceRoot":"","sources":["../src/env-scan-source.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA6QD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CA+CzB"}
|