@percher/core 0.1.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 (105) hide show
  1. package/dist/app-name.d.ts +6 -0
  2. package/dist/app-name.d.ts.map +1 -0
  3. package/dist/app-name.js +20 -0
  4. package/dist/app-name.js.map +1 -0
  5. package/dist/commands/create.d.ts +27 -0
  6. package/dist/commands/create.d.ts.map +1 -0
  7. package/dist/commands/create.js +60 -0
  8. package/dist/commands/create.js.map +1 -0
  9. package/dist/commands/data.d.ts +28 -0
  10. package/dist/commands/data.d.ts.map +1 -0
  11. package/dist/commands/data.js +28 -0
  12. package/dist/commands/data.js.map +1 -0
  13. package/dist/commands/dev.d.ts +25 -0
  14. package/dist/commands/dev.d.ts.map +1 -0
  15. package/dist/commands/dev.js +143 -0
  16. package/dist/commands/dev.js.map +1 -0
  17. package/dist/commands/doctor.d.ts +29 -0
  18. package/dist/commands/doctor.d.ts.map +1 -0
  19. package/dist/commands/doctor.js +159 -0
  20. package/dist/commands/doctor.js.map +1 -0
  21. package/dist/commands/domains.d.ts +49 -0
  22. package/dist/commands/domains.d.ts.map +1 -0
  23. package/dist/commands/domains.js +45 -0
  24. package/dist/commands/domains.js.map +1 -0
  25. package/dist/commands/env.d.ts +33 -0
  26. package/dist/commands/env.d.ts.map +1 -0
  27. package/dist/commands/env.js +49 -0
  28. package/dist/commands/env.js.map +1 -0
  29. package/dist/commands/generate.d.ts +15 -0
  30. package/dist/commands/generate.d.ts.map +1 -0
  31. package/dist/commands/generate.js +160 -0
  32. package/dist/commands/generate.js.map +1 -0
  33. package/dist/commands/init.d.ts +26 -0
  34. package/dist/commands/init.d.ts.map +1 -0
  35. package/dist/commands/init.js +71 -0
  36. package/dist/commands/init.js.map +1 -0
  37. package/dist/commands/login.d.ts +15 -0
  38. package/dist/commands/login.d.ts.map +1 -0
  39. package/dist/commands/login.js +52 -0
  40. package/dist/commands/login.js.map +1 -0
  41. package/dist/commands/logs.d.ts +18 -0
  42. package/dist/commands/logs.d.ts.map +1 -0
  43. package/dist/commands/logs.js +38 -0
  44. package/dist/commands/logs.js.map +1 -0
  45. package/dist/commands/open.d.ts +12 -0
  46. package/dist/commands/open.d.ts.map +1 -0
  47. package/dist/commands/open.js +19 -0
  48. package/dist/commands/open.js.map +1 -0
  49. package/dist/commands/push.d.ts +32 -0
  50. package/dist/commands/push.d.ts.map +1 -0
  51. package/dist/commands/push.js +179 -0
  52. package/dist/commands/push.js.map +1 -0
  53. package/dist/commands/resume.d.ts +15 -0
  54. package/dist/commands/resume.d.ts.map +1 -0
  55. package/dist/commands/resume.js +17 -0
  56. package/dist/commands/resume.js.map +1 -0
  57. package/dist/commands/rollback.d.ts +22 -0
  58. package/dist/commands/rollback.d.ts.map +1 -0
  59. package/dist/commands/rollback.js +41 -0
  60. package/dist/commands/rollback.js.map +1 -0
  61. package/dist/commands/versions.d.ts +17 -0
  62. package/dist/commands/versions.d.ts.map +1 -0
  63. package/dist/commands/versions.js +15 -0
  64. package/dist/commands/versions.js.map +1 -0
  65. package/dist/commands/whoami.d.ts +7 -0
  66. package/dist/commands/whoami.d.ts.map +1 -0
  67. package/dist/commands/whoami.js +4 -0
  68. package/dist/commands/whoami.js.map +1 -0
  69. package/dist/context.d.ts +17 -0
  70. package/dist/context.d.ts.map +1 -0
  71. package/dist/context.js +2 -0
  72. package/dist/context.js.map +1 -0
  73. package/dist/detect.d.ts +17 -0
  74. package/dist/detect.d.ts.map +1 -0
  75. package/dist/detect.js +173 -0
  76. package/dist/detect.js.map +1 -0
  77. package/dist/errors.d.ts +12 -0
  78. package/dist/errors.d.ts.map +1 -0
  79. package/dist/errors.js +11 -0
  80. package/dist/errors.js.map +1 -0
  81. package/dist/index.d.ts +26 -0
  82. package/dist/index.d.ts.map +1 -0
  83. package/dist/index.js +25 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/plans.d.ts +27 -0
  86. package/dist/plans.d.ts.map +1 -0
  87. package/dist/plans.js +84 -0
  88. package/dist/plans.js.map +1 -0
  89. package/dist/tarball.d.ts +17 -0
  90. package/dist/tarball.d.ts.map +1 -0
  91. package/dist/tarball.js +75 -0
  92. package/dist/tarball.js.map +1 -0
  93. package/dist/templates.d.ts +12 -0
  94. package/dist/templates.d.ts.map +1 -0
  95. package/dist/templates.js +58 -0
  96. package/dist/templates.js.map +1 -0
  97. package/dist/validation/blocked-names.d.ts +8 -0
  98. package/dist/validation/blocked-names.d.ts.map +1 -0
  99. package/dist/validation/blocked-names.js +86 -0
  100. package/dist/validation/blocked-names.js.map +1 -0
  101. package/dist/watcher.d.ts +15 -0
  102. package/dist/watcher.d.ts.map +1 -0
  103. package/dist/watcher.js +62 -0
  104. package/dist/watcher.js.map +1 -0
  105. package/package.json +52 -0
@@ -0,0 +1,32 @@
1
+ import { type App, type Deployment } from "@percher/client";
2
+ import { z } from "zod";
3
+ import type { Context } from "../context";
4
+ export declare const pushInputSchema: z.ZodObject<{
5
+ dryRun: z.ZodOptional<z.ZodBoolean>;
6
+ force: z.ZodOptional<z.ZodBoolean>;
7
+ preview: z.ZodOptional<z.ZodBoolean>;
8
+ _pollIntervalMs: z.ZodOptional<z.ZodNumber>;
9
+ _timeoutMs: z.ZodOptional<z.ZodNumber>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ force?: boolean | undefined;
12
+ dryRun?: boolean | undefined;
13
+ preview?: boolean | undefined;
14
+ _pollIntervalMs?: number | undefined;
15
+ _timeoutMs?: number | undefined;
16
+ }, {
17
+ force?: boolean | undefined;
18
+ dryRun?: boolean | undefined;
19
+ preview?: boolean | undefined;
20
+ _pollIntervalMs?: number | undefined;
21
+ _timeoutMs?: number | undefined;
22
+ }>;
23
+ export type PushInput = z.infer<typeof pushInputSchema>;
24
+ export interface PushResult {
25
+ app: App;
26
+ deployment?: Deployment;
27
+ dryRun: boolean;
28
+ bytes: number;
29
+ fileCount: number;
30
+ }
31
+ export declare function push(ctx: Context, input?: PushInput): Promise<PushResult>;
32
+ //# sourceMappingURL=push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/commands/push.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,UAAU,EAAkC,MAAM,iBAAiB,CAAC;AAE5F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAM1C,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;EAM1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,GAAG,CAAC;IACT,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AA4ED,wBAAsB,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,SAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAqHnF"}
@@ -0,0 +1,179 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { PercherApiError, PercherClient } from "@percher/client";
4
+ import { parseFile } from "@percher/toml";
5
+ import { z } from "zod";
6
+ import { PercherCoreError } from "../errors";
7
+ import { createTarball } from "../tarball";
8
+ import { init } from "./init";
9
+ import { login } from "./login";
10
+ export const pushInputSchema = z.object({
11
+ dryRun: z.boolean().optional(),
12
+ force: z.boolean().optional(),
13
+ preview: z.boolean().optional(),
14
+ _pollIntervalMs: z.number().int().positive().optional(),
15
+ _timeoutMs: z.number().int().positive().optional(),
16
+ });
17
+ const MAX_BYTES = 500 * 1024 * 1024; // 500 MB
18
+ const SUSPICIOUS_BYTES = 50 * 1024 * 1024; // 50 MB
19
+ const SUSPICIOUS_FILES = 10_000;
20
+ const PLACEHOLDER_PREFIXES = ["add-your-", "your-key-here"];
21
+ async function loadOrGenerate(ctx) {
22
+ const tomlPath = join(ctx.cwd, "percher.toml");
23
+ if (!existsSync(tomlPath)) {
24
+ ctx.status("No percher.toml found — detecting framework...");
25
+ const result = await init(ctx);
26
+ const answer = await ctx.prompt(`Generated percher.toml for ${result.detected?.framework ?? result.detected?.runtime ?? "node"}. Continue? [Y/n]`, { default: "y" });
27
+ if (!/^y(es)?$|^$/i.test(answer.trim())) {
28
+ throw new PercherCoreError("Push cancelled by user", {
29
+ code: "push.cancelled",
30
+ });
31
+ }
32
+ }
33
+ return parseFile(tomlPath);
34
+ }
35
+ function isPlaceholder(value) {
36
+ return PLACEHOLDER_PREFIXES.some((p) => value.startsWith(p));
37
+ }
38
+ async function checkPlaceholders(ctx, config) {
39
+ const placeholders = Object.entries(config.env ?? {})
40
+ .filter(([, v]) => isPlaceholder(v))
41
+ .map(([k]) => k);
42
+ if (placeholders.length === 0)
43
+ return;
44
+ ctx.status(`Warning: ${placeholders.length} env var(s) still have placeholder values: ${placeholders.join(", ")}`);
45
+ const answer = await ctx.prompt("Continue anyway? [y/N]", { default: "n" });
46
+ if (!/^y(es)?$/i.test(answer.trim())) {
47
+ throw new PercherCoreError("Env vars contain placeholder values", {
48
+ code: "push.placeholder-env",
49
+ hint: "Set real values via `percher env set KEY=value` or edit percher.toml.",
50
+ });
51
+ }
52
+ }
53
+ async function checkByoSecrets(ctx, config) {
54
+ const hints = [];
55
+ if (config.data?.mode === "convex") {
56
+ hints.push("Convex deploy key: percher env set CONVEX_DEPLOY_KEY=...");
57
+ }
58
+ if (config.data?.mode === "supabase") {
59
+ hints.push("Supabase service role key: percher env set SUPABASE_SERVICE_ROLE_KEY=...");
60
+ }
61
+ if (hints.length > 0) {
62
+ ctx.status(`BYO ${config.data?.mode} detected. Make sure you've set secrets via percher env set:\n ${hints.join("\n ")}`);
63
+ }
64
+ }
65
+ async function ensureApp(ctx, config) {
66
+ try {
67
+ return await ctx.client.apps.get(config.app.name);
68
+ }
69
+ catch (err) {
70
+ if (err.code === "APP_NOT_FOUND") {
71
+ return ctx.client.apps.create({
72
+ name: config.app.name,
73
+ runtime: config.app.runtime,
74
+ framework: config.app.framework,
75
+ });
76
+ }
77
+ throw err;
78
+ }
79
+ }
80
+ export async function push(ctx, input = {}) {
81
+ const config = await loadOrGenerate(ctx);
82
+ await checkPlaceholders(ctx, config);
83
+ await checkByoSecrets(ctx, config);
84
+ const tarball = await createTarball({ cwd: ctx.cwd, config });
85
+ if (tarball.bytes > MAX_BYTES) {
86
+ throw new PercherCoreError(`Repository is larger than 500 MB (current: ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB)`, {
87
+ code: "push.too-large",
88
+ hint: `Biggest files: ${tarball.topFiles.map((f) => f.path).join(", ")}`,
89
+ });
90
+ }
91
+ if (!input.force && (tarball.fileCount > SUSPICIOUS_FILES || tarball.bytes > SUSPICIOUS_BYTES)) {
92
+ ctx.status(`This looks suspicious: ${tarball.fileCount} files, ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB. Are node_modules / dist excluded?`);
93
+ const answer = await ctx.prompt("Continue anyway? [y/N]", { default: "n" });
94
+ if (!/^y(es)?$/i.test(answer.trim())) {
95
+ throw new PercherCoreError("Push aborted — looked suspicious", {
96
+ code: "push.suspicious",
97
+ hint: "Add node_modules, dist, etc. to .gitignore or pass --force.",
98
+ });
99
+ }
100
+ }
101
+ if (input.dryRun) {
102
+ return {
103
+ app: {
104
+ id: "",
105
+ name: config.app.name,
106
+ url: "",
107
+ status: "provisioning",
108
+ runtime: config.app.runtime,
109
+ createdAt: "",
110
+ },
111
+ dryRun: true,
112
+ bytes: tarball.bytes,
113
+ fileCount: tarball.fileCount,
114
+ };
115
+ }
116
+ let app;
117
+ try {
118
+ app = await ensureApp(ctx, config);
119
+ }
120
+ catch (err) {
121
+ if (err instanceof PercherApiError && err.status === 401) {
122
+ if (!ctx.interactiveLogin) {
123
+ throw new PercherCoreError("Not logged in. Run `percher login` first, or set PERCHER_TOKEN.", {
124
+ code: "push.cancelled",
125
+ hint: "The percher_login MCP tool can also start the login flow.",
126
+ });
127
+ }
128
+ ctx.status("Not logged in — starting login...");
129
+ const newToken = await login(ctx);
130
+ // Use the returned token directly — avoids stale PERCHER_TOKEN env override
131
+ ctx.client = new PercherClient({
132
+ apiUrl: ctx.client.apiUrl,
133
+ token: newToken,
134
+ });
135
+ app = await ensureApp(ctx, config);
136
+ }
137
+ else {
138
+ throw err;
139
+ }
140
+ }
141
+ ctx.status("Uploading...");
142
+ let deployment = await ctx.client.apps.deploy(app.id, {
143
+ tarball: tarball.stream,
144
+ type: input.preview ? "preview" : undefined,
145
+ });
146
+ const pollInterval = input._pollIntervalMs ?? 2000;
147
+ const timeoutMs = input._timeoutMs ?? 5 * 60 * 1000;
148
+ const startedAt = Date.now();
149
+ while (deployment.status !== "live" && deployment.status !== "failed") {
150
+ if (Date.now() - startedAt > timeoutMs) {
151
+ throw new PercherCoreError("Deploy timed out", {
152
+ code: "push.deploy-timeout",
153
+ hint: "Run `percher logs` to see what happened.",
154
+ });
155
+ }
156
+ ctx.status(`${deployment.status}...`);
157
+ await new Promise((r) => setTimeout(r, pollInterval));
158
+ deployment = await ctx.client.apps.getDeployment(app.id, deployment.id);
159
+ }
160
+ if (deployment.status === "failed") {
161
+ throw new PercherCoreError("Deployment failed", {
162
+ code: "push.deploy-failed",
163
+ hint: "Run `percher logs` to see what went wrong.",
164
+ });
165
+ }
166
+ const totalSec = ((Date.now() - startedAt) / 1000).toFixed(0);
167
+ const displayUrl = deployment.previewUrl;
168
+ ctx.status(displayUrl
169
+ ? `Preview at ${displayUrl} (${totalSec}s)`
170
+ : `Live at ${deployment.url ?? app.url} (${totalSec}s)`);
171
+ return {
172
+ app,
173
+ deployment,
174
+ dryRun: false,
175
+ bytes: tarball.bytes,
176
+ fileCount: tarball.fileCount,
177
+ };
178
+ }
179
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/commands/push.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ import type { Context } from "../context";
3
+ export declare const resumeInputSchema: z.ZodObject<{
4
+ app: z.ZodOptional<z.ZodString>;
5
+ }, "strip", z.ZodTypeAny, {
6
+ app?: string | undefined;
7
+ }, {
8
+ app?: string | undefined;
9
+ }>;
10
+ export type ResumeInput = z.infer<typeof resumeInputSchema>;
11
+ export declare function resume(ctx: Context, input?: ResumeInput): Promise<{
12
+ status: string;
13
+ message: string;
14
+ }>;
15
+ //# sourceMappingURL=resume.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/commands/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,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"}
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ import { readPercherTomlAppName } from "../app-name";
3
+ import { PercherCoreError } from "../errors";
4
+ export const resumeInputSchema = z.object({
5
+ app: z.string().optional(),
6
+ });
7
+ export async function resume(ctx, input = {}) {
8
+ const name = input.app ?? readPercherTomlAppName(ctx.cwd);
9
+ if (!name) {
10
+ throw new PercherCoreError("No app specified and no percher.toml found", {
11
+ code: "env.no-app",
12
+ hint: "Pass an app name or run from a directory with percher.toml.",
13
+ });
14
+ }
15
+ return ctx.client.apps.resumeApp(name);
16
+ }
17
+ //# sourceMappingURL=resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/commands/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,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"}
@@ -0,0 +1,22 @@
1
+ import type { Deployment } from "@percher/client";
2
+ import { z } from "zod";
3
+ import type { Context } from "../context";
4
+ export declare const rollbackInputSchema: z.ZodObject<{
5
+ app: z.ZodOptional<z.ZodString>;
6
+ commitSha: z.ZodString;
7
+ _pollIntervalMs: z.ZodOptional<z.ZodNumber>;
8
+ _timeoutMs: z.ZodOptional<z.ZodNumber>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ commitSha: string;
11
+ app?: string | undefined;
12
+ _pollIntervalMs?: number | undefined;
13
+ _timeoutMs?: number | undefined;
14
+ }, {
15
+ commitSha: string;
16
+ app?: string | undefined;
17
+ _pollIntervalMs?: number | undefined;
18
+ _timeoutMs?: number | undefined;
19
+ }>;
20
+ export type RollbackInput = z.infer<typeof rollbackInputSchema>;
21
+ export declare function rollback(ctx: Context, input: RollbackInput): Promise<Deployment>;
22
+ //# sourceMappingURL=rollback.d.ts.map
@@ -0,0 +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,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAK9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAkCtF"}
@@ -0,0 +1,41 @@
1
+ import { z } from "zod";
2
+ import { readPercherTomlAppName } from "../app-name";
3
+ import { PercherCoreError } from "../errors";
4
+ export const rollbackInputSchema = z.object({
5
+ app: z.string().optional(),
6
+ commitSha: z.string().min(1),
7
+ _pollIntervalMs: z.number().int().positive().optional(),
8
+ _timeoutMs: z.number().int().positive().optional(),
9
+ });
10
+ export async function rollback(ctx, input) {
11
+ const name = input.app ?? readPercherTomlAppName(ctx.cwd);
12
+ if (!name) {
13
+ throw new PercherCoreError("No app specified and no percher.toml found", {
14
+ code: "logs.no-app",
15
+ hint: "Pass --app <name> or run from a directory with percher.toml.",
16
+ });
17
+ }
18
+ let deployment = await ctx.client.apps.rollback(name, input.commitSha);
19
+ const pollInterval = input._pollIntervalMs ?? 2000;
20
+ const timeoutMs = input._timeoutMs ?? 5 * 60 * 1000;
21
+ const startedAt = Date.now();
22
+ while (deployment.status !== "live" && deployment.status !== "failed") {
23
+ if (Date.now() - startedAt > timeoutMs) {
24
+ throw new PercherCoreError("Rollback timed out", {
25
+ code: "push.deploy-timeout",
26
+ hint: "Run `percher logs` to see what happened.",
27
+ });
28
+ }
29
+ ctx.status(`${deployment.status}...`);
30
+ await new Promise((r) => setTimeout(r, pollInterval));
31
+ deployment = await ctx.client.apps.getDeployment(name, deployment.id);
32
+ }
33
+ if (deployment.status === "failed") {
34
+ throw new PercherCoreError("Rollback failed", {
35
+ code: "push.deploy-failed",
36
+ hint: "Run `percher logs` to see what went wrong.",
37
+ });
38
+ }
39
+ return deployment;
40
+ }
41
+ //# sourceMappingURL=rollback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/commands/rollback.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,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;IAC1C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACvD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACnD,CAAC,CAAC;AAGH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,KAAoB;IAC/D,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,KAAK,CAAC,eAAe,IAAI,IAAI,CAAC;IACnD,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACpD,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"}
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ import type { Context } from "../context";
3
+ export declare const versionsInputSchema: z.ZodObject<{
4
+ app: z.ZodOptional<z.ZodString>;
5
+ }, "strip", z.ZodTypeAny, {
6
+ app?: string | undefined;
7
+ }, {
8
+ app?: string | undefined;
9
+ }>;
10
+ export type VersionsInput = z.infer<typeof versionsInputSchema>;
11
+ export interface AppVersion {
12
+ sha: string;
13
+ message: string;
14
+ timestamp: string;
15
+ }
16
+ export declare function versions(ctx: Context, input?: VersionsInput): Promise<AppVersion[]>;
17
+ //# sourceMappingURL=versions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../src/commands/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,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"}
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ import { readPercherTomlAppName } from "../app-name";
3
+ import { PercherCoreError } from "../errors";
4
+ export const versionsInputSchema = z.object({ app: z.string().optional() });
5
+ export async function versions(ctx, input = {}) {
6
+ const name = input.app ?? readPercherTomlAppName(ctx.cwd);
7
+ if (!name) {
8
+ throw new PercherCoreError("No app specified and no percher.toml found", {
9
+ code: "logs.no-app",
10
+ hint: "Pass an app name or run from a directory with percher.toml.",
11
+ });
12
+ }
13
+ return ctx.client.apps.listVersions(name);
14
+ }
15
+ //# sourceMappingURL=versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.js","sourceRoot":"","sources":["../../src/commands/versions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,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,7 @@
1
+ import type { Context } from "../context";
2
+ export interface WhoAmI {
3
+ userId: string;
4
+ email: string;
5
+ }
6
+ export declare function whoami(ctx: Context): Promise<WhoAmI>;
7
+ //# sourceMappingURL=whoami.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAE1D"}
@@ -0,0 +1,4 @@
1
+ export async function whoami(ctx) {
2
+ return ctx.client.auth.whoami();
3
+ }
4
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAY;IACvC,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { PercherClient } from "@percher/client";
2
+ export interface PromptOptions {
3
+ default?: string;
4
+ }
5
+ export interface Context {
6
+ client: PercherClient;
7
+ cwd: string;
8
+ stdout: WritableStream<Uint8Array>;
9
+ stderr: WritableStream<Uint8Array>;
10
+ env: Record<string, string | undefined>;
11
+ prompt: (question: string, options?: PromptOptions) => Promise<string>;
12
+ openUrl: (url: string) => Promise<void>;
13
+ status: (message: string) => void;
14
+ /** Whether this context supports interactive auth (browser open + wait). CLI: true, MCP: false. */
15
+ interactiveLogin?: boolean;
16
+ }
17
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,mGAAmG;IACnG,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ export interface DetectedFramework {
2
+ runtime: "node" | "python" | "static" | "docker";
3
+ framework?: string;
4
+ build?: {
5
+ command: string;
6
+ output: string;
7
+ };
8
+ web?: {
9
+ port: number;
10
+ health?: string;
11
+ };
12
+ data?: {
13
+ mode: "pocketbase" | "postgres" | "sqlite" | "convex" | "supabase" | "none";
14
+ };
15
+ }
16
+ export declare function detectFramework(cwd: string): Promise<DetectedFramework | null>;
17
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAA;KAAE,CAAC;CACxF;AA2CD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAgJpF"}
package/dist/detect.js ADDED
@@ -0,0 +1,173 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ function exists(dir, ...names) {
4
+ return names.some((n) => existsSync(join(dir, n)));
5
+ }
6
+ function readJson(path) {
7
+ try {
8
+ return JSON.parse(readFileSync(path, "utf8"));
9
+ }
10
+ catch {
11
+ return null;
12
+ }
13
+ }
14
+ function hasDependency(pkg, name) {
15
+ if (!pkg)
16
+ return false;
17
+ const deps = (pkg.dependencies ?? {});
18
+ const dev = (pkg.devDependencies ?? {});
19
+ return name in deps || name in dev;
20
+ }
21
+ /**
22
+ * Detect data backend mode from project dependencies.
23
+ * Convex/Supabase SDKs override the default PocketBase mode.
24
+ */
25
+ function detectDataMode(pkg, cwd) {
26
+ if (exists(cwd, "convex.json", "convex/_generated")) {
27
+ return { mode: "convex" };
28
+ }
29
+ if (hasDependency(pkg, "convex")) {
30
+ return { mode: "convex" };
31
+ }
32
+ if (hasDependency(pkg, "@supabase/supabase-js") || hasDependency(pkg, "@supabase/ssr")) {
33
+ return { mode: "supabase" };
34
+ }
35
+ // No known data provider detected — default to none.
36
+ // PocketBase is only used when explicitly configured in percher.toml.
37
+ return { mode: "none" };
38
+ }
39
+ export async function detectFramework(cwd) {
40
+ const pkgPath = join(cwd, "package.json");
41
+ const pkg = existsSync(pkgPath) ? readJson(pkgPath) : null;
42
+ if (exists(cwd, "Dockerfile")) {
43
+ return {
44
+ runtime: "docker",
45
+ framework: "docker",
46
+ web: { port: 8080, health: "/health" },
47
+ data: detectDataMode(pkg, cwd),
48
+ };
49
+ }
50
+ if (exists(cwd, "next.config.js", "next.config.ts", "next.config.mjs")) {
51
+ return {
52
+ runtime: "node",
53
+ framework: "nextjs",
54
+ build: { command: "bun run build", output: ".next" },
55
+ web: { port: 3000, health: "/api/health" },
56
+ data: detectDataMode(pkg, cwd),
57
+ };
58
+ }
59
+ if (exists(cwd, "svelte.config.js", "svelte.config.ts")) {
60
+ return {
61
+ runtime: "node",
62
+ framework: "sveltekit",
63
+ build: { command: "bun run build", output: ".svelte-kit" },
64
+ web: { port: 3000, health: "/health" },
65
+ data: detectDataMode(pkg, cwd),
66
+ };
67
+ }
68
+ if (exists(cwd, "astro.config.mjs", "astro.config.ts", "astro.config.js")) {
69
+ const ssr = hasDependency(pkg, "@astrojs/node");
70
+ return {
71
+ runtime: ssr ? "node" : "static",
72
+ framework: "astro",
73
+ build: { command: "bun run build", output: "dist" },
74
+ ...(ssr ? { web: { port: 4321, health: "/health" } } : {}),
75
+ data: detectDataMode(pkg, cwd),
76
+ };
77
+ }
78
+ if (exists(cwd, "remix.config.js", "remix.config.ts") || hasDependency(pkg, "@remix-run/node")) {
79
+ return {
80
+ runtime: "node",
81
+ framework: "remix",
82
+ build: { command: "bun run build", output: "build" },
83
+ web: { port: 3000, health: "/health" },
84
+ data: detectDataMode(pkg, cwd),
85
+ };
86
+ }
87
+ if (exists(cwd, "vite.config.js", "vite.config.ts")) {
88
+ const viteData = detectDataMode(pkg, cwd);
89
+ return {
90
+ runtime: "static",
91
+ framework: "vite",
92
+ build: { command: "bun run build", output: "dist" },
93
+ ...(viteData && viteData.mode !== "pocketbase" ? { data: viteData } : {}),
94
+ };
95
+ }
96
+ if (hasDependency(pkg, "express")) {
97
+ return {
98
+ runtime: "node",
99
+ framework: "express",
100
+ web: { port: 3000, health: "/health" },
101
+ data: detectDataMode(pkg, cwd),
102
+ };
103
+ }
104
+ if (hasDependency(pkg, "fastify")) {
105
+ return {
106
+ runtime: "node",
107
+ framework: "fastify",
108
+ web: { port: 3000, health: "/health" },
109
+ data: detectDataMode(pkg, cwd),
110
+ };
111
+ }
112
+ if (hasDependency(pkg, "hono")) {
113
+ return {
114
+ runtime: "node",
115
+ framework: "hono",
116
+ web: { port: 3000, health: "/health" },
117
+ data: detectDataMode(pkg, cwd),
118
+ };
119
+ }
120
+ if (pkg) {
121
+ const detected = {
122
+ runtime: "node",
123
+ web: { port: 3000, health: "/health" },
124
+ data: detectDataMode(pkg, cwd),
125
+ };
126
+ const scripts = (pkg.scripts ?? {});
127
+ if (scripts.build) {
128
+ detected.build = { command: "bun run build", output: "dist" };
129
+ }
130
+ return detected;
131
+ }
132
+ const hasPython = exists(cwd, "requirements.txt", "pyproject.toml");
133
+ if (hasPython) {
134
+ if (existsSync(join(cwd, "manage.py"))) {
135
+ return {
136
+ runtime: "python",
137
+ framework: "django",
138
+ web: { port: 8000, health: "/health" },
139
+ data: detectDataMode(pkg, cwd),
140
+ };
141
+ }
142
+ const mainPy = existsSync(join(cwd, "main.py"))
143
+ ? readFileSync(join(cwd, "main.py"), "utf8")
144
+ : "";
145
+ if (/FastAPI\s*\(/.test(mainPy) || /from\s+fastapi/.test(mainPy)) {
146
+ return {
147
+ runtime: "python",
148
+ framework: "fastapi",
149
+ web: { port: 8000, health: "/health" },
150
+ data: detectDataMode(pkg, cwd),
151
+ };
152
+ }
153
+ const appPy = existsSync(join(cwd, "app.py")) ? readFileSync(join(cwd, "app.py"), "utf8") : "";
154
+ if (/Flask\s*\(/.test(appPy) || /from\s+flask/.test(appPy)) {
155
+ return {
156
+ runtime: "python",
157
+ framework: "flask",
158
+ web: { port: 5000, health: "/health" },
159
+ data: detectDataMode(pkg, cwd),
160
+ };
161
+ }
162
+ return {
163
+ runtime: "python",
164
+ web: { port: 8000, health: "/health" },
165
+ data: detectDataMode(pkg, cwd),
166
+ };
167
+ }
168
+ if (existsSync(join(cwd, "index.html"))) {
169
+ return { runtime: "static" };
170
+ }
171
+ return null;
172
+ }
173
+ //# sourceMappingURL=detect.js.map