@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,6 @@
1
+ /**
2
+ * Read the app name from percher.toml in the given directory, or return null.
3
+ * Does not throw on missing/invalid files — returns null instead.
4
+ */
5
+ export declare function readPercherTomlAppName(cwd: string): string | null;
6
+ //# sourceMappingURL=app-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-name.d.ts","sourceRoot":"","sources":["../src/app-name.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE"}
@@ -0,0 +1,20 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parse } from "@percher/toml";
4
+ /**
5
+ * Read the app name from percher.toml in the given directory, or return null.
6
+ * Does not throw on missing/invalid files — returns null instead.
7
+ */
8
+ export function readPercherTomlAppName(cwd) {
9
+ const p = join(cwd, "percher.toml");
10
+ if (!existsSync(p))
11
+ return null;
12
+ try {
13
+ const cfg = parse(readFileSync(p, "utf8"));
14
+ return cfg.app.name;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ //# sourceMappingURL=app-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-name.js","sourceRoot":"","sources":["../src/app-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC3C,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ import type { Context } from "../context";
3
+ import { type ScaffoldResult } from "../templates";
4
+ export declare const createInputSchema: z.ZodObject<{
5
+ name: z.ZodString;
6
+ template: z.ZodString;
7
+ directory: z.ZodOptional<z.ZodString>;
8
+ force: z.ZodOptional<z.ZodBoolean>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ name: string;
11
+ template: string;
12
+ force?: boolean | undefined;
13
+ directory?: string | undefined;
14
+ }, {
15
+ name: string;
16
+ template: string;
17
+ force?: boolean | undefined;
18
+ directory?: string | undefined;
19
+ }>;
20
+ export type CreateInput = z.infer<typeof createInputSchema>;
21
+ export interface CreateResult extends ScaffoldResult {
22
+ name: string;
23
+ template: string;
24
+ directory: string;
25
+ }
26
+ export declare function create(ctx: Context, input: CreateInput): Promise<CreateResult>;
27
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,KAAK,cAAc,EAAmC,MAAM,cAAc,CAAC;AAIpF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;EAO5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAkDpF"}
@@ -0,0 +1,60 @@
1
+ import { join, resolve } from "node:path";
2
+ import { z } from "zod";
3
+ import { PercherCoreError } from "../errors";
4
+ import { listTemplates, scaffoldTemplate } from "../templates";
5
+ const APP_NAME_RE = /^[a-z][a-z0-9-]{2,39}$/;
6
+ export const createInputSchema = z.object({
7
+ name: z
8
+ .string()
9
+ .regex(APP_NAME_RE, "must be 3-40 chars, lowercase, start with a letter, [a-z0-9-] only"),
10
+ template: z.string().min(1, "Template is required"),
11
+ directory: z.string().optional(),
12
+ force: z.boolean().optional(),
13
+ });
14
+ export async function create(ctx, input) {
15
+ const available = listTemplates();
16
+ if (!available.includes(input.template)) {
17
+ throw new PercherCoreError(`Unknown template "${input.template}". Available: ${available.join(", ")}`, {
18
+ code: "create.invalid-template",
19
+ hint: `Run "percher create --list-templates" to see available templates.`,
20
+ });
21
+ }
22
+ // Resolve directory relative to cwd, reject absolute paths outside workspace
23
+ let targetDir;
24
+ if (input.directory) {
25
+ targetDir = resolve(ctx.cwd, input.directory);
26
+ if (!targetDir.startsWith(resolve(ctx.cwd))) {
27
+ throw new PercherCoreError("Directory must be within the current workspace", {
28
+ code: "create.failed",
29
+ });
30
+ }
31
+ }
32
+ else {
33
+ targetDir = join(ctx.cwd, input.name);
34
+ }
35
+ try {
36
+ const result = scaffoldTemplate({
37
+ template: input.template,
38
+ appName: input.name,
39
+ targetDir,
40
+ force: input.force,
41
+ });
42
+ return {
43
+ ...result,
44
+ name: input.name,
45
+ template: input.template,
46
+ directory: targetDir,
47
+ };
48
+ }
49
+ catch (err) {
50
+ const msg = err instanceof Error ? err.message : String(err);
51
+ if (msg.includes("not empty")) {
52
+ throw new PercherCoreError(msg, {
53
+ code: "create.dir-not-empty",
54
+ hint: "Use --force to overwrite existing files.",
55
+ });
56
+ }
57
+ throw new PercherCoreError(msg, { code: "create.failed" });
58
+ }
59
+ }
60
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAuB,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEpF,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAE7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,KAAK,CAAC,WAAW,EAAE,oEAAoE,CAAC;IAC3F,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC;IACnD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAC,CAAC;AAUH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAY,EAAE,KAAkB;IAC3D,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAElC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,gBAAgB,CACxB,qBAAqB,KAAK,CAAC,QAAQ,iBAAiB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAC1E;YACE,IAAI,EAAE,yBAAyB;YAC/B,IAAI,EAAE,mEAAmE;SAC1E,CACF,CAAC;IACJ,CAAC;IAED,6EAA6E;IAC7E,IAAI,SAAiB,CAAC;IACtB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,gBAAgB,CAAC,gDAAgD,EAAE;gBAC3E,IAAI,EAAE,eAAe;aACtB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,gBAAgB,CAAC;YAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO,EAAE,KAAK,CAAC,IAAI;YACnB,SAAS;YACT,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC,CAAC;QAEH,OAAO;YACL,GAAG,MAAM;YACT,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,SAAS;SACrB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,gBAAgB,CAAC,GAAG,EAAE;gBAC9B,IAAI,EAAE,sBAAsB;gBAC5B,IAAI,EAAE,0CAA0C;aACjD,CAAC,CAAC;QACL,CAAC;QACD,MAAM,IAAI,gBAAgB,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ import type { Context } from "../context";
3
+ export declare const dataInputSchema: z.ZodObject<{
4
+ app: z.ZodOptional<z.ZodString>;
5
+ json: z.ZodOptional<z.ZodBoolean>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ app?: string | undefined;
8
+ json?: boolean | undefined;
9
+ }, {
10
+ app?: string | undefined;
11
+ json?: boolean | undefined;
12
+ }>;
13
+ export type DataInput = z.infer<typeof dataInputSchema>;
14
+ export interface DataResult {
15
+ mode: string;
16
+ status: string;
17
+ collections: Array<{
18
+ name: string;
19
+ type: string;
20
+ }>;
21
+ stats: {
22
+ collections: number;
23
+ totalRecords: number;
24
+ };
25
+ adminUrl: string | null;
26
+ }
27
+ export declare function data(ctx: Context, input?: DataInput): Promise<DataResult>;
28
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/commands/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,eAAe;;;;;;;;;EAG1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wBAAsB,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,SAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAqBnF"}
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ import { readPercherTomlAppName } from "../app-name";
3
+ import { PercherCoreError } from "../errors";
4
+ export const dataInputSchema = z.object({
5
+ app: z.string().optional(),
6
+ json: z.boolean().optional(),
7
+ });
8
+ export async function data(ctx, input = {}) {
9
+ const name = input.app ?? readPercherTomlAppName(ctx.cwd);
10
+ if (!name) {
11
+ throw new PercherCoreError("No app specified and no percher.toml found", {
12
+ code: "data.no-app",
13
+ hint: "Pass an app name or run from a directory with percher.toml.",
14
+ });
15
+ }
16
+ const status = await ctx.client.data.getStatus(name);
17
+ const collections = await ctx.client.data.getCollections(name);
18
+ const stats = await ctx.client.data.getStats(name);
19
+ const adminLink = await ctx.client.data.getAdminLink(name);
20
+ return {
21
+ mode: status.mode,
22
+ status: status.status,
23
+ collections: collections.map((c) => ({ name: c.name, type: c.type })),
24
+ stats,
25
+ adminUrl: adminLink.adminUrl ?? null,
26
+ };
27
+ }
28
+ //# sourceMappingURL=data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/commands/data.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,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAWH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,GAAY,EAAE,QAAmB,EAAE;IAC5D,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;IAED,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAE3D,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACrE,KAAK;QACL,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,IAAI;KACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ import type { Context } from "../context";
3
+ export declare const devInputSchema: 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 DevInput = z.infer<typeof devInputSchema>;
11
+ export interface DevCallbacks {
12
+ /** Called when file changes are detected. Returns true to push, false to skip. */
13
+ onFilesChanged: (files: string[]) => Promise<boolean>;
14
+ /** Called to write a line to stdout */
15
+ writeLine: (line: string) => Promise<void>;
16
+ /** Signal to stop the dev loop (resolved when user wants to exit) */
17
+ signal: AbortSignal;
18
+ }
19
+ /**
20
+ * Run the dev loop: watch files, prompt to push on changes, stream logs.
21
+ *
22
+ * This is the core logic — the CLI layer provides the interactive callbacks.
23
+ */
24
+ export declare function dev(ctx: Context, input: DevInput, callbacks: DevCallbacks): Promise<void>;
25
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAK1C,eAAO,MAAM,cAAc;;;;;;EAEzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,uCAAuC;IACvC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,qEAAqE;IACrE,MAAM,EAAE,WAAW,CAAC;CACrB;AAwED;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE/F"}
@@ -0,0 +1,143 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parseFile } from "@percher/toml";
4
+ import { z } from "zod";
5
+ import { PercherCoreError } from "../errors";
6
+ import { createTarball } from "../tarball";
7
+ import { createWatcher } from "../watcher";
8
+ export const devInputSchema = z.object({
9
+ app: z.string().optional(),
10
+ });
11
+ async function loadConfig(ctx, appOverride) {
12
+ const tomlPath = join(ctx.cwd, "percher.toml");
13
+ if (!existsSync(tomlPath)) {
14
+ throw new PercherCoreError("No percher.toml found. Run: percher init", {
15
+ code: "dev.no-app",
16
+ hint: "Create a percher.toml first with `percher init`.",
17
+ });
18
+ }
19
+ const config = await parseFile(tomlPath);
20
+ // Override app name if explicitly provided via CLI
21
+ if (appOverride) {
22
+ return { ...config, app: { ...config.app, name: appOverride } };
23
+ }
24
+ return config;
25
+ }
26
+ async function ensureApp(ctx, config) {
27
+ try {
28
+ return await ctx.client.apps.get(config.app.name);
29
+ }
30
+ catch (err) {
31
+ if (err.code === "APP_NOT_FOUND") {
32
+ return ctx.client.apps.create({
33
+ name: config.app.name,
34
+ runtime: config.app.runtime,
35
+ framework: config.app.framework,
36
+ });
37
+ }
38
+ throw err;
39
+ }
40
+ }
41
+ async function doPush(ctx, config, callbacks) {
42
+ const tarball = await createTarball({ cwd: ctx.cwd, config });
43
+ const app = await ensureApp(ctx, config);
44
+ await callbacks.writeLine(`Pushing ${tarball.fileCount} files (${(tarball.bytes / 1024).toFixed(0)} KB)...`);
45
+ let deployment = await ctx.client.apps.deploy(app.id, { tarball: tarball.stream });
46
+ const startedAt = Date.now();
47
+ const timeoutMs = 5 * 60 * 1000;
48
+ const pollInterval = 2000;
49
+ let lastStatus = "";
50
+ while (deployment.status !== "live" && deployment.status !== "failed") {
51
+ if (Date.now() - startedAt > timeoutMs) {
52
+ await callbacks.writeLine("Deploy timed out");
53
+ return;
54
+ }
55
+ if (callbacks.signal.aborted)
56
+ return;
57
+ // Only log on status change to reduce noise
58
+ if (deployment.status !== lastStatus) {
59
+ lastStatus = deployment.status;
60
+ await callbacks.writeLine(` ${deployment.status}...`);
61
+ }
62
+ await new Promise((r) => setTimeout(r, pollInterval));
63
+ deployment = await ctx.client.apps.getDeployment(app.id, deployment.id);
64
+ }
65
+ if (deployment.status === "failed") {
66
+ await callbacks.writeLine("Deploy failed. Run `percher logs` for details.");
67
+ }
68
+ else {
69
+ await callbacks.writeLine(`Live at ${deployment.url ?? app.url}`);
70
+ }
71
+ }
72
+ /**
73
+ * Run the dev loop: watch files, prompt to push on changes, stream logs.
74
+ *
75
+ * This is the core logic — the CLI layer provides the interactive callbacks.
76
+ */
77
+ export async function dev(ctx, input, callbacks) {
78
+ const config = await loadConfig(ctx, input.app);
79
+ const app = await ensureApp(ctx, config);
80
+ await callbacks.writeLine(`App: ${app.url}`);
81
+ await callbacks.writeLine("Watching for changes...");
82
+ await callbacks.writeLine("");
83
+ // Serialize onChange callbacks to prevent parallel deploys
84
+ let busy = false;
85
+ let queued = null;
86
+ async function handleChange(files) {
87
+ if (busy) {
88
+ // Queue the latest batch — only the most recent matters
89
+ queued = files;
90
+ return;
91
+ }
92
+ busy = true;
93
+ try {
94
+ const shortList = files.length <= 3
95
+ ? files.join(", ")
96
+ : `${files.slice(0, 3).join(", ")} +${files.length - 3} more`;
97
+ await callbacks.writeLine(`Change detected: ${shortList}`);
98
+ const shouldPush = await callbacks.onFilesChanged(files);
99
+ if (shouldPush) {
100
+ try {
101
+ const freshConfig = await loadConfig(ctx, input.app);
102
+ await doPush(ctx, freshConfig, callbacks);
103
+ }
104
+ catch (err) {
105
+ await callbacks.writeLine(`Push error: ${err.message}`);
106
+ }
107
+ }
108
+ }
109
+ finally {
110
+ busy = false;
111
+ // Process queued changes
112
+ if (queued) {
113
+ const next = queued;
114
+ queued = null;
115
+ await handleChange(next);
116
+ }
117
+ }
118
+ }
119
+ // Dev loop: watch → prompt → push
120
+ const devConfig = config.dev;
121
+ const watcher = createWatcher({
122
+ cwd: ctx.cwd,
123
+ extraIgnore: devConfig?.ignore,
124
+ debounceMs: devConfig?.debounce,
125
+ onChange(files) {
126
+ void handleChange(files);
127
+ },
128
+ });
129
+ // Wait until aborted (user presses Ctrl+C)
130
+ try {
131
+ await new Promise((resolve) => {
132
+ if (callbacks.signal.aborted) {
133
+ resolve();
134
+ return;
135
+ }
136
+ callbacks.signal.addEventListener("abort", () => resolve(), { once: true });
137
+ });
138
+ }
139
+ finally {
140
+ watcher.close();
141
+ }
142
+ }
143
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import type { Context } from "../context";
3
+ export declare const doctorInputSchema: z.ZodObject<{
4
+ app: z.ZodOptional<z.ZodString>;
5
+ json: z.ZodOptional<z.ZodBoolean>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ app?: string | undefined;
8
+ json?: boolean | undefined;
9
+ }, {
10
+ app?: string | undefined;
11
+ json?: boolean | undefined;
12
+ }>;
13
+ export type DoctorInput = z.infer<typeof doctorInputSchema>;
14
+ type CheckStatus = "pass" | "fail" | "warn" | "skip";
15
+ export interface DoctorCheck {
16
+ name: string;
17
+ status: CheckStatus;
18
+ message: string;
19
+ }
20
+ export interface DoctorResult {
21
+ checks: DoctorCheck[];
22
+ passed: number;
23
+ failed: number;
24
+ warned: number;
25
+ total: number;
26
+ }
27
+ export declare function doctor(ctx: Context, input?: DoctorInput): Promise<DoctorResult>;
28
+ export {};
29
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,iBAAiB;;;;;;;;;EAG5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CA2JzF"}
@@ -0,0 +1,159 @@
1
+ import { z } from "zod";
2
+ import { readPercherTomlAppName } from "../app-name";
3
+ export const doctorInputSchema = z.object({
4
+ app: z.string().optional(),
5
+ json: z.boolean().optional(),
6
+ });
7
+ export async function doctor(ctx, input = {}) {
8
+ const checks = [];
9
+ // 1. Auth token
10
+ const hasToken = !!ctx.client.token;
11
+ checks.push({
12
+ name: "Auth token",
13
+ status: hasToken ? "pass" : "fail",
14
+ message: hasToken ? "Token configured" : "No token found. Run: percher login",
15
+ });
16
+ if (!hasToken) {
17
+ return summarize(checks);
18
+ }
19
+ // 2. API reachability + user account
20
+ try {
21
+ const start = Date.now();
22
+ const me = await ctx.client.auth.whoami();
23
+ const latency = Date.now() - start;
24
+ checks.push({
25
+ name: "API reachability",
26
+ status: "pass",
27
+ message: `${ctx.client.apiUrl} (${latency}ms)`,
28
+ });
29
+ // 3. User account
30
+ checks.push({
31
+ name: "User account",
32
+ status: "pass",
33
+ message: me.email,
34
+ });
35
+ }
36
+ catch (err) {
37
+ checks.push({
38
+ name: "API reachability",
39
+ status: "fail",
40
+ message: `Cannot reach ${ctx.client.apiUrl}: ${err.message}`,
41
+ });
42
+ return summarize(checks);
43
+ }
44
+ // 4. App resolution
45
+ const appName = input.app ?? readPercherTomlAppName(ctx.cwd);
46
+ if (!appName) {
47
+ checks.push({
48
+ name: "App",
49
+ status: "skip",
50
+ message: "No app specified and no percher.toml found",
51
+ });
52
+ return summarize(checks);
53
+ }
54
+ // 5. Fetch diagnostics from the API
55
+ try {
56
+ const diag = await ctx.client.apps.getDiagnostics(appName);
57
+ // App status
58
+ const appOk = diag.app.status === "live";
59
+ checks.push({
60
+ name: `App: ${diag.app.name}`,
61
+ status: appOk ? "pass" : diag.app.status === "crashed" ? "fail" : "warn",
62
+ message: `Status: ${diag.app.status}`,
63
+ });
64
+ // Container — uses actual inspect state
65
+ checks.push({
66
+ name: "Container",
67
+ status: diag.container.running ? "pass" : "fail",
68
+ message: diag.container.running
69
+ ? "Running"
70
+ : diag.container.state === "not-found"
71
+ ? "No container found"
72
+ : `State: ${diag.container.state}`,
73
+ });
74
+ // Container health — direct HTTP to container
75
+ if (diag.containerHealth) {
76
+ checks.push({
77
+ name: "Container health",
78
+ status: diag.containerHealth.healthy ? "pass" : "fail",
79
+ message: diag.containerHealth.healthy
80
+ ? `${diag.containerHealth.path} OK (${diag.containerHealth.latencyMs}ms)`
81
+ : `${diag.containerHealth.path} — not responding`,
82
+ });
83
+ }
84
+ // Public route — tests actual Caddy/TLS/DNS path
85
+ if (diag.publicRoute) {
86
+ checks.push({
87
+ name: "Public route",
88
+ status: diag.publicRoute.healthy ? "pass" : "fail",
89
+ message: diag.publicRoute.healthy
90
+ ? `${diag.publicRoute.url} (${diag.publicRoute.latencyMs}ms)`
91
+ : `${diag.publicRoute.url} — not responding`,
92
+ });
93
+ }
94
+ // Data backend
95
+ if (diag.pocketbase) {
96
+ const pbOk = diag.pocketbase.status === "running";
97
+ checks.push({
98
+ name: "PocketBase",
99
+ status: pbOk ? "pass" : diag.pocketbase.status === "stopped" ? "warn" : "skip",
100
+ message: diag.pocketbase.status,
101
+ });
102
+ }
103
+ else if (diag.app.dataMode === "convex" || diag.app.dataMode === "supabase") {
104
+ checks.push({
105
+ name: `Data (${diag.app.dataMode})`,
106
+ status: "pass",
107
+ message: "External provider configured",
108
+ });
109
+ }
110
+ // Env vars
111
+ checks.push({
112
+ name: "Env vars",
113
+ status: "pass",
114
+ message: diag.env.count > 0 ? `${diag.env.count} set (${diag.env.keys.join(", ")})` : "None set",
115
+ });
116
+ // percher.toml
117
+ const hasToml = readPercherTomlAppName(ctx.cwd) !== null;
118
+ checks.push({
119
+ name: "percher.toml",
120
+ status: hasToml ? "pass" : "warn",
121
+ message: hasToml ? "Valid" : "Not found in current directory",
122
+ });
123
+ // Last deploy
124
+ if (diag.lastDeploy) {
125
+ const deployOk = diag.lastDeploy.status === "live";
126
+ checks.push({
127
+ name: "Last deploy",
128
+ status: deployOk ? "pass" : "warn",
129
+ message: `${diag.lastDeploy.status} (${diag.lastDeploy.createdAt})`,
130
+ });
131
+ }
132
+ // Last crash
133
+ if (diag.lastCrash) {
134
+ checks.push({
135
+ name: "Last crash",
136
+ status: "warn",
137
+ message: `Exit code ${diag.lastCrash.exitCode}${diag.lastCrash.oomKilled ? " (OOM killed)" : ""} at ${diag.lastCrash.createdAt}`,
138
+ });
139
+ }
140
+ }
141
+ catch (err) {
142
+ checks.push({
143
+ name: `App: ${appName}`,
144
+ status: "fail",
145
+ message: err.message,
146
+ });
147
+ }
148
+ return summarize(checks);
149
+ }
150
+ function summarize(checks) {
151
+ return {
152
+ checks,
153
+ passed: checks.filter((c) => c.status === "pass").length,
154
+ failed: checks.filter((c) => c.status === "fail").length,
155
+ warned: checks.filter((c) => c.status === "warn").length,
156
+ total: checks.filter((c) => c.status !== "skip").length,
157
+ };
158
+ }
159
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { CustomDomainAddResult, CustomDomainEntry, CustomDomainVerifyResult } from "@percher/client";
2
+ import { z } from "zod";
3
+ import type { Context } from "../context";
4
+ export declare const domainAddInputSchema: z.ZodObject<{
5
+ app: z.ZodOptional<z.ZodString>;
6
+ domain: z.ZodString;
7
+ }, "strip", z.ZodTypeAny, {
8
+ domain: string;
9
+ app?: string | undefined;
10
+ }, {
11
+ domain: string;
12
+ app?: string | undefined;
13
+ }>;
14
+ export type DomainAddInput = z.infer<typeof domainAddInputSchema>;
15
+ export declare const domainVerifyInputSchema: z.ZodObject<{
16
+ app: z.ZodOptional<z.ZodString>;
17
+ domain: z.ZodString;
18
+ }, "strip", z.ZodTypeAny, {
19
+ domain: string;
20
+ app?: string | undefined;
21
+ }, {
22
+ domain: string;
23
+ app?: string | undefined;
24
+ }>;
25
+ export type DomainVerifyInput = z.infer<typeof domainVerifyInputSchema>;
26
+ export declare const domainListInputSchema: z.ZodObject<{
27
+ app: z.ZodOptional<z.ZodString>;
28
+ }, "strip", z.ZodTypeAny, {
29
+ app?: string | undefined;
30
+ }, {
31
+ app?: string | undefined;
32
+ }>;
33
+ export type DomainListInput = z.infer<typeof domainListInputSchema>;
34
+ export declare const domainRemoveInputSchema: z.ZodObject<{
35
+ app: z.ZodOptional<z.ZodString>;
36
+ domain: z.ZodString;
37
+ }, "strip", z.ZodTypeAny, {
38
+ domain: string;
39
+ app?: string | undefined;
40
+ }, {
41
+ domain: string;
42
+ app?: string | undefined;
43
+ }>;
44
+ export type DomainRemoveInput = z.infer<typeof domainRemoveInputSchema>;
45
+ export declare function domainAdd(ctx: Context, input: DomainAddInput): Promise<CustomDomainAddResult>;
46
+ export declare function domainVerify(ctx: Context, input: DomainVerifyInput): Promise<CustomDomainVerifyResult>;
47
+ export declare function domainList(ctx: Context, input?: DomainListInput): Promise<CustomDomainEntry[]>;
48
+ export declare function domainRemove(ctx: Context, input: DomainRemoveInput): Promise<void>;
49
+ //# sourceMappingURL=domains.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../../src/commands/domains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,oBAAoB;;;;;;;;;EAG/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,uBAAuB;;;;;;;;;EAGlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,qBAAqB;;;;;;EAEhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,uBAAuB;;;;;;;;;EAGlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAaxE,wBAAsB,SAAS,CAC7B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,qBAAqB,CAAC,CAGhC;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,wBAAwB,CAAC,CAGnC;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,KAAK,GAAE,eAAoB,GAC1B,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAG9B;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxF"}