@percher/core 0.2.2 → 0.2.4
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/commands/billing.d.ts +43 -0
- package/dist/commands/billing.d.ts.map +1 -0
- package/dist/commands/billing.js +65 -0
- package/dist/commands/billing.js.map +1 -0
- package/dist/commands/data.d.ts +10 -0
- package/dist/commands/data.d.ts.map +1 -1
- package/dist/commands/data.js +33 -3
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/delete.d.ts +15 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +26 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/deploys.d.ts +45 -0
- package/dist/commands/deploys.d.ts.map +1 -0
- package/dist/commands/deploys.js +73 -0
- package/dist/commands/deploys.js.map +1 -0
- package/dist/commands/diagnose.d.ts +75 -0
- package/dist/commands/diagnose.d.ts.map +1 -0
- package/dist/commands/diagnose.js +102 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +58 -13
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/export.d.ts +39 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +107 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/import-project.d.ts +21 -0
- package/dist/commands/import-project.d.ts.map +1 -0
- package/dist/commands/import-project.js +134 -0
- package/dist/commands/import-project.js.map +1 -0
- package/dist/commands/insights.d.ts +44 -0
- package/dist/commands/insights.d.ts.map +1 -0
- package/dist/commands/insights.js +54 -0
- package/dist/commands/insights.js.map +1 -0
- package/dist/commands/mcp.d.ts +29 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +35 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/publish.d.ts +35 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +163 -9
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +8 -4
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/rename.d.ts +21 -0
- package/dist/commands/rename.d.ts.map +1 -0
- package/dist/commands/rename.js +18 -0
- package/dist/commands/rename.js.map +1 -0
- package/dist/commands/reset-superuser.d.ts +16 -0
- package/dist/commands/reset-superuser.d.ts.map +1 -0
- package/dist/commands/reset-superuser.js +17 -0
- package/dist/commands/reset-superuser.js.map +1 -0
- package/dist/error-classifier.d.ts +16 -0
- package/dist/error-classifier.d.ts.map +1 -1
- package/dist/error-classifier.js +135 -3
- package/dist/error-classifier.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +14 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/integrations.d.ts +24 -0
- package/dist/integrations.d.ts.map +1 -0
- package/dist/integrations.js +106 -0
- package/dist/integrations.js.map +1 -0
- package/dist/plans.d.ts +43 -0
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +83 -1
- package/dist/plans.js.map +1 -1
- package/dist/qr.d.ts +5 -0
- package/dist/qr.d.ts.map +1 -0
- package/dist/qr.js +10 -0
- package/dist/qr.js.map +1 -0
- package/dist/templates.d.ts +24 -0
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +331 -0
- package/dist/templates.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/doctor.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { PercherTomlError, parseFile } from "@percher/toml";
|
|
1
4
|
import { z } from "zod";
|
|
2
5
|
import { readPercherTomlAppName } from "../app-name";
|
|
3
6
|
export const doctorInputSchema = z.object({
|
|
@@ -41,14 +44,62 @@ export async function doctor(ctx, input = {}) {
|
|
|
41
44
|
});
|
|
42
45
|
return summarize(checks);
|
|
43
46
|
}
|
|
44
|
-
// 4.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
// 4. percher.toml — validated *before* app resolution. readPercherTomlAppName
|
|
48
|
+
// returns null on parse errors AND when the file is missing, so if we waited
|
|
49
|
+
// until after app resolution to validate, an invalid TOML would skip out as
|
|
50
|
+
// "no app" and never get a real failure check. Run validation independently
|
|
51
|
+
// so the user sees the actual issue list either way.
|
|
52
|
+
const tomlPath = join(ctx.cwd, "percher.toml");
|
|
53
|
+
const tomlExists = existsSync(tomlPath);
|
|
54
|
+
let tomlValid = false;
|
|
55
|
+
if (!tomlExists) {
|
|
47
56
|
checks.push({
|
|
48
|
-
name: "
|
|
49
|
-
status: "
|
|
50
|
-
message: "
|
|
57
|
+
name: "percher.toml",
|
|
58
|
+
status: "warn",
|
|
59
|
+
message: "Not found in current directory",
|
|
51
60
|
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
try {
|
|
64
|
+
await parseFile(tomlPath);
|
|
65
|
+
tomlValid = true;
|
|
66
|
+
checks.push({ name: "percher.toml", status: "pass", message: "Valid" });
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (err instanceof PercherTomlError && err.issues && err.issues.length > 0) {
|
|
70
|
+
const summary = err.issues
|
|
71
|
+
.slice(0, 3)
|
|
72
|
+
.map((i) => {
|
|
73
|
+
const where = i.path.length > 0 ? `[${i.path.join(".")}]` : "(root)";
|
|
74
|
+
return `${where} ${i.message}`;
|
|
75
|
+
})
|
|
76
|
+
.join("; ");
|
|
77
|
+
const more = err.issues.length > 3 ? ` (+${err.issues.length - 3} more)` : "";
|
|
78
|
+
checks.push({
|
|
79
|
+
name: "percher.toml",
|
|
80
|
+
status: "fail",
|
|
81
|
+
message: `${summary}${more}`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
checks.push({
|
|
86
|
+
name: "percher.toml",
|
|
87
|
+
status: "fail",
|
|
88
|
+
message: err.message,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// 5. App resolution
|
|
94
|
+
// If --app is given, we don't depend on percher.toml. Otherwise we can only
|
|
95
|
+
// pull the app name when the TOML actually parsed — readPercherTomlAppName
|
|
96
|
+
// would re-attempt the parse and return null silently otherwise.
|
|
97
|
+
const appName = input.app ?? (tomlValid ? readPercherTomlAppName(ctx.cwd) : null);
|
|
98
|
+
if (!appName) {
|
|
99
|
+
const reason = tomlExists && !tomlValid
|
|
100
|
+
? "percher.toml is invalid — fix the issues above and re-run"
|
|
101
|
+
: "No app specified and no percher.toml found";
|
|
102
|
+
checks.push({ name: "App", status: "skip", message: reason });
|
|
52
103
|
return summarize(checks);
|
|
53
104
|
}
|
|
54
105
|
// 5. Fetch diagnostics from the API
|
|
@@ -113,13 +164,7 @@ export async function doctor(ctx, input = {}) {
|
|
|
113
164
|
status: "pass",
|
|
114
165
|
message: diag.env.count > 0 ? `${diag.env.count} set (${diag.env.keys.join(", ")})` : "None set",
|
|
115
166
|
});
|
|
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
|
-
});
|
|
167
|
+
// (percher.toml validation now happens up-front — see step 4)
|
|
123
168
|
// Last deploy
|
|
124
169
|
if (diag.lastDeploy) {
|
|
125
170
|
const deployOk = diag.lastDeploy.status === "live";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAGrD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAmBH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAY,EAAE,QAAqB,EAAE;IAChE,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,gBAAgB;IAChB,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;IACpC,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAClC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,oCAAoC;KAC9E,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,OAAO,KAAK;SAC/C,CAAC,CAAC;QAEH,kBAAkB;QAClB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,cAAc;YACpB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,CAAC,KAAK;SAClB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,gBAAgB,GAAG,CAAC,MAAM,CAAC,MAAM,KAAM,GAAa,CAAC,OAAO,EAAE;SACxE,CAAC,CAAC;QACH,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Context } from "../context";
|
|
3
|
+
export declare const exportInputSchema: z.ZodObject<{
|
|
4
|
+
app: z.ZodOptional<z.ZodString>;
|
|
5
|
+
/** Where to write the bundle. Defaults to `./{appName}-{date}.tar.gz` in cwd.
|
|
6
|
+
* Absolute paths are honored as-is; relative paths are resolved against
|
|
7
|
+
* the context's cwd. */
|
|
8
|
+
out: z.ZodOptional<z.ZodString>;
|
|
9
|
+
/** Delivery channel — used by the API for export-history bookkeeping. */
|
|
10
|
+
deliveryKind: z.ZodDefault<z.ZodEnum<["cli", "mcp"]>>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
deliveryKind: "cli" | "mcp";
|
|
13
|
+
app?: string | undefined;
|
|
14
|
+
out?: string | undefined;
|
|
15
|
+
}, {
|
|
16
|
+
app?: string | undefined;
|
|
17
|
+
out?: string | undefined;
|
|
18
|
+
deliveryKind?: "cli" | "mcp" | undefined;
|
|
19
|
+
}>;
|
|
20
|
+
export type ExportInput = z.infer<typeof exportInputSchema>;
|
|
21
|
+
export interface ExportResult {
|
|
22
|
+
appName: string;
|
|
23
|
+
outPath: string;
|
|
24
|
+
bytes: number;
|
|
25
|
+
expiresAt: string;
|
|
26
|
+
/**
|
|
27
|
+
* Whether env values were included in the bundle. Always `false` from
|
|
28
|
+
* the CLI/MCP path — the API rejects `includeSecrets: true` over the
|
|
29
|
+
* bearer surface. To export values, the user must use the dashboard's
|
|
30
|
+
* password-confirm flow.
|
|
31
|
+
*/
|
|
32
|
+
includedSecrets: false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Mint an export token for `app`, follow the download URL, and write the
|
|
36
|
+
* `.tar.gz` bundle to disk. Always non-secrets — see `ExportInput.includedSecrets`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function exportApp(ctx: Context, input: ExportInput): Promise<ExportResult>;
|
|
39
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,iBAAiB;;IAE5B;;6BAEyB;;IAEzB,yEAAyE;;;;;;;;;;EAEzE,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,eAAe,EAAE,KAAK,CAAC;CACxB;AAkED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAyBvF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { isAbsolute, resolve as resolvePath } from "node:path";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { readPercherTomlAppName } from "../app-name";
|
|
4
|
+
import { PercherCoreError } from "../errors";
|
|
5
|
+
export const exportInputSchema = z.object({
|
|
6
|
+
app: z.string().optional(),
|
|
7
|
+
/** Where to write the bundle. Defaults to `./{appName}-{date}.tar.gz` in cwd.
|
|
8
|
+
* Absolute paths are honored as-is; relative paths are resolved against
|
|
9
|
+
* the context's cwd. */
|
|
10
|
+
out: z.string().optional(),
|
|
11
|
+
/** Delivery channel — used by the API for export-history bookkeeping. */
|
|
12
|
+
deliveryKind: z.enum(["cli", "mcp"]).default("cli"),
|
|
13
|
+
});
|
|
14
|
+
function resolveAppName(ctx, provided) {
|
|
15
|
+
const name = provided ?? readPercherTomlAppName(ctx.cwd);
|
|
16
|
+
if (!name) {
|
|
17
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
18
|
+
code: "export.no-app",
|
|
19
|
+
hint: "Pass --app <name> or run from a directory with percher.toml.",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return name;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Stream the response body straight to disk via Bun's file writer — no
|
|
26
|
+
* full-archive buffering, so a 200 MB PocketBase-bearing bundle uses
|
|
27
|
+
* constant memory regardless of size.
|
|
28
|
+
*/
|
|
29
|
+
async function streamToFile(outPath, source) {
|
|
30
|
+
const file = Bun.file(outPath);
|
|
31
|
+
const writer = file.writer();
|
|
32
|
+
let bytes = 0;
|
|
33
|
+
const reader = source.getReader();
|
|
34
|
+
try {
|
|
35
|
+
while (true) {
|
|
36
|
+
const { done, value } = await reader.read();
|
|
37
|
+
if (done)
|
|
38
|
+
break;
|
|
39
|
+
if (value && value.length > 0) {
|
|
40
|
+
writer.write(value);
|
|
41
|
+
bytes += value.length;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
await writer.end();
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
// Make sure the writer is closed and the partial file is removed —
|
|
48
|
+
// a half-written .tar.gz on disk would confuse users into thinking
|
|
49
|
+
// the export succeeded.
|
|
50
|
+
try {
|
|
51
|
+
await writer.end();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
/* writer may already be closed by the error path */
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
await Bun.write(outPath, "");
|
|
58
|
+
await Bun.file(outPath).delete?.();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* best effort */
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
return { bytes };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve `out` against `cwd`. Absolute paths win as-is; relative paths
|
|
69
|
+
* are joined onto cwd. This matches the CLI's documented behavior and
|
|
70
|
+
* matches what users expect from `--out /tmp/foo.tar.gz`.
|
|
71
|
+
*/
|
|
72
|
+
function resolveOutPath(ctxCwd, filename) {
|
|
73
|
+
if (isAbsolute(filename))
|
|
74
|
+
return filename;
|
|
75
|
+
return resolvePath(ctxCwd, filename);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Mint an export token for `app`, follow the download URL, and write the
|
|
79
|
+
* `.tar.gz` bundle to disk. Always non-secrets — see `ExportInput.includedSecrets`.
|
|
80
|
+
*/
|
|
81
|
+
export async function exportApp(ctx, input) {
|
|
82
|
+
const name = resolveAppName(ctx, input.app);
|
|
83
|
+
const mint = await ctx.client.export.mint(name, { deliveryKind: input.deliveryKind });
|
|
84
|
+
const dl = await ctx.client.export.download(mint.downloadUrl);
|
|
85
|
+
if (!dl.body) {
|
|
86
|
+
throw new PercherCoreError("Export download returned an empty body", {
|
|
87
|
+
code: "export.empty-body",
|
|
88
|
+
hint: "Try again — the link is single-use, so a new mint is required.",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const filenameFromHeader = (() => {
|
|
92
|
+
const cd = dl.headers.get("Content-Disposition") ?? "";
|
|
93
|
+
const m = cd.match(/filename="?([^";]+)"?/);
|
|
94
|
+
return m?.[1];
|
|
95
|
+
})();
|
|
96
|
+
const filename = input.out ?? filenameFromHeader ?? `${name}-export.tar.gz`;
|
|
97
|
+
const outPath = resolveOutPath(ctx.cwd, filename);
|
|
98
|
+
const { bytes } = await streamToFile(outPath, dl.body);
|
|
99
|
+
return {
|
|
100
|
+
appName: name,
|
|
101
|
+
outPath,
|
|
102
|
+
bytes,
|
|
103
|
+
expiresAt: mint.expiresAt,
|
|
104
|
+
includedSecrets: false,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Context } from "../context";
|
|
3
|
+
export declare const importInputSchema: z.ZodObject<{
|
|
4
|
+
from: z.ZodOptional<z.ZodEnum<["vercel", "netlify"]>>;
|
|
5
|
+
app: z.ZodOptional<z.ZodString>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
app?: string | undefined;
|
|
8
|
+
from?: "vercel" | "netlify" | undefined;
|
|
9
|
+
}, {
|
|
10
|
+
app?: string | undefined;
|
|
11
|
+
from?: "vercel" | "netlify" | undefined;
|
|
12
|
+
}>;
|
|
13
|
+
export type ImportInput = z.infer<typeof importInputSchema>;
|
|
14
|
+
export interface ImportResult {
|
|
15
|
+
provider: string;
|
|
16
|
+
configGenerated: boolean;
|
|
17
|
+
warnings: string[];
|
|
18
|
+
envVars: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function importProject(ctx: Context, input?: ImportInput): Promise<ImportResult>;
|
|
21
|
+
//# sourceMappingURL=import-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-project.d.ts","sourceRoot":"","sources":["../../src/commands/import-project.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,iBAAiB;;;;;;;;;EAM5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAwID,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsChG"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { PercherCoreError } from "../errors";
|
|
5
|
+
export const importInputSchema = z.object({
|
|
6
|
+
from: z
|
|
7
|
+
.enum(["vercel", "netlify"])
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Provider to import from (auto-detected if omitted)"),
|
|
10
|
+
app: z.string().optional().describe("App name to import into"),
|
|
11
|
+
});
|
|
12
|
+
function detectProvider(cwd) {
|
|
13
|
+
if (existsSync(join(cwd, "vercel.json")))
|
|
14
|
+
return "vercel";
|
|
15
|
+
if (existsSync(join(cwd, "netlify.toml")))
|
|
16
|
+
return "netlify";
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
function mapVercelFramework(framework) {
|
|
20
|
+
const map = {
|
|
21
|
+
nextjs: { runtime: "node", framework: "nextjs" },
|
|
22
|
+
"create-react-app": { runtime: "static", framework: "vite" },
|
|
23
|
+
vite: { runtime: "static", framework: "vite" },
|
|
24
|
+
svelte: { runtime: "node", framework: "sveltekit" },
|
|
25
|
+
remix: { runtime: "node", framework: "remix" },
|
|
26
|
+
astro: { runtime: "static", framework: "astro" },
|
|
27
|
+
nuxtjs: { runtime: "node" },
|
|
28
|
+
gatsby: { runtime: "static" },
|
|
29
|
+
};
|
|
30
|
+
return map[framework ?? ""] ?? { runtime: "node" };
|
|
31
|
+
}
|
|
32
|
+
function parseVercelJson(cwd) {
|
|
33
|
+
const raw = readFileSync(join(cwd, "vercel.json"), "utf-8");
|
|
34
|
+
const config = JSON.parse(raw);
|
|
35
|
+
const warnings = [];
|
|
36
|
+
const envVars = [];
|
|
37
|
+
const { runtime, framework } = mapVercelFramework(config.framework);
|
|
38
|
+
const buildCommand = config.buildCommand ?? "bun run build";
|
|
39
|
+
const output = config.outputDirectory ?? (framework === "nextjs" ? ".next" : "dist");
|
|
40
|
+
let toml = `[app]\nname = "imported-app"\nruntime = "${runtime}"\n`;
|
|
41
|
+
if (framework)
|
|
42
|
+
toml += `framework = "${framework}"\n`;
|
|
43
|
+
toml += `\n[build]\ncommand = "${buildCommand}"\noutput = "${output}"\n`;
|
|
44
|
+
if (runtime !== "static") {
|
|
45
|
+
toml += `\n[web]\nport = 3000\nhealth = "/api/health"\n`;
|
|
46
|
+
}
|
|
47
|
+
if (config.env) {
|
|
48
|
+
const keys = Object.keys(config.env);
|
|
49
|
+
if (keys.length > 0) {
|
|
50
|
+
toml += "\n[env]\n";
|
|
51
|
+
for (const key of keys) {
|
|
52
|
+
toml += `${key} = "add-your-key-here"\n`;
|
|
53
|
+
envVars.push(key);
|
|
54
|
+
}
|
|
55
|
+
warnings.push(`Found ${keys.length} env var(s) in vercel.json. Set them with: bunx percher env set KEY=value`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (config.installCommand && config.installCommand !== "npm install") {
|
|
59
|
+
warnings.push(`Custom install command "${config.installCommand}" — Percher uses bun install by default`);
|
|
60
|
+
}
|
|
61
|
+
return { toml, warnings, envVars };
|
|
62
|
+
}
|
|
63
|
+
function parseNetlifyToml(cwd) {
|
|
64
|
+
const raw = readFileSync(join(cwd, "netlify.toml"), "utf-8");
|
|
65
|
+
const warnings = [];
|
|
66
|
+
const envVars = [];
|
|
67
|
+
// Simple TOML parsing for netlify.toml (build section)
|
|
68
|
+
const buildCommand = raw.match(/command\s*=\s*"([^"]+)"/)?.[1] ?? "bun run build";
|
|
69
|
+
const publishDir = raw.match(/publish\s*=\s*"([^"]+)"/)?.[1] ?? "dist";
|
|
70
|
+
// Detect if static or server
|
|
71
|
+
const isStatic = !existsSync(join(cwd, "package.json")) ||
|
|
72
|
+
publishDir === "dist" ||
|
|
73
|
+
publishDir === "build" ||
|
|
74
|
+
publishDir === "public";
|
|
75
|
+
let toml = `[app]\nname = "imported-app"\nruntime = "${isStatic ? "static" : "node"}"\n`;
|
|
76
|
+
toml += `\n[build]\ncommand = "${buildCommand.replace(/npm run/g, "bun run")}"\noutput = "${publishDir}"\n`;
|
|
77
|
+
if (!isStatic) {
|
|
78
|
+
toml += `\n[web]\nport = 3000\nhealth = "/health"\n`;
|
|
79
|
+
}
|
|
80
|
+
// Check for environment variables
|
|
81
|
+
const envMatch = raw.match(/\[build\.environment\]\s*\n((?:\s*\w+\s*=.*\n)*)/);
|
|
82
|
+
if (envMatch?.[1]) {
|
|
83
|
+
const lines = envMatch[1].trim().split("\n");
|
|
84
|
+
toml += "\n[env]\n";
|
|
85
|
+
for (const line of lines) {
|
|
86
|
+
const [key] = line.split("=").map((s) => s.trim());
|
|
87
|
+
if (key) {
|
|
88
|
+
toml += `${key} = "add-your-key-here"\n`;
|
|
89
|
+
envVars.push(key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Check for redirects (not directly supported, but warn)
|
|
94
|
+
if (raw.includes("[[redirects]]")) {
|
|
95
|
+
warnings.push("Netlify redirects detected — Percher doesn't support _redirects. Use your framework's built-in routing instead.");
|
|
96
|
+
}
|
|
97
|
+
return { toml, warnings, envVars };
|
|
98
|
+
}
|
|
99
|
+
export async function importProject(ctx, input = {}) {
|
|
100
|
+
const provider = input.from ?? detectProvider(ctx.cwd);
|
|
101
|
+
if (!provider) {
|
|
102
|
+
throw new PercherCoreError("Could not detect provider. No vercel.json or netlify.toml found.", {
|
|
103
|
+
code: "env.no-app",
|
|
104
|
+
hint: "Use --from vercel|netlify to specify the provider, or run from a directory with the provider's config file. For GitHub import, use the dashboard.",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
let result;
|
|
108
|
+
if (provider === "vercel") {
|
|
109
|
+
result = parseVercelJson(ctx.cwd);
|
|
110
|
+
}
|
|
111
|
+
else if (provider === "netlify") {
|
|
112
|
+
result = parseNetlifyToml(ctx.cwd);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
throw new PercherCoreError(`Unknown provider: ${provider}`, {
|
|
116
|
+
code: "env.no-app",
|
|
117
|
+
hint: "Supported providers: vercel, netlify",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Write percher.toml
|
|
121
|
+
const tomlPath = join(ctx.cwd, "percher.toml");
|
|
122
|
+
if (existsSync(tomlPath)) {
|
|
123
|
+
result.warnings.unshift("percher.toml already exists — overwriting with imported config");
|
|
124
|
+
}
|
|
125
|
+
const { writeFileSync } = await import("node:fs");
|
|
126
|
+
writeFileSync(tomlPath, result.toml);
|
|
127
|
+
return {
|
|
128
|
+
provider,
|
|
129
|
+
configGenerated: true,
|
|
130
|
+
warnings: result.warnings,
|
|
131
|
+
envVars: result.envVars,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=import-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-project.js","sourceRoot":"","sources":["../../src/commands/import-project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Context } from "../context";
|
|
3
|
+
export declare const insightsInputSchema: 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 InsightsInput = z.infer<typeof insightsInputSchema>;
|
|
11
|
+
export interface InsightSuggestion {
|
|
12
|
+
id: string;
|
|
13
|
+
kind: "idle" | "memory-pressure" | "overprovisioned" | "deploy-regression";
|
|
14
|
+
severity: "info" | "warning" | "critical";
|
|
15
|
+
title: string;
|
|
16
|
+
detail: string;
|
|
17
|
+
suggestion: string;
|
|
18
|
+
confidence: "low" | "medium" | "high";
|
|
19
|
+
signal: Record<string, number | string | boolean | null>;
|
|
20
|
+
}
|
|
21
|
+
export interface InsightsResult {
|
|
22
|
+
appName: string;
|
|
23
|
+
plan: string;
|
|
24
|
+
generatedAt: string;
|
|
25
|
+
insights: InsightSuggestion[];
|
|
26
|
+
/**
|
|
27
|
+
* Short human-readable summary for AI assistants to echo back. Lists the
|
|
28
|
+
* most actionable insight first; empty string if no insights fired.
|
|
29
|
+
*/
|
|
30
|
+
summary: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* AI-driven cost optimization (MCP).
|
|
34
|
+
*
|
|
35
|
+
* Surfaces per-app suggestions computed by the API's `AppInsightsService`.
|
|
36
|
+
* Rules read DB-backed signals (analytics, crashes, deploys, plan) and
|
|
37
|
+
* return suggestions like "looks idle — delete it", "OOM kills in last 14d
|
|
38
|
+
* — upgrade memory", or "plan headroom unused — downgrade".
|
|
39
|
+
*
|
|
40
|
+
* Read-only. Does not execute downgrades/upgrades — that needs Polar billing
|
|
41
|
+
* to be live. For now the assistant can only describe + propose.
|
|
42
|
+
*/
|
|
43
|
+
export declare function insights(ctx: Context, input?: InsightsInput): Promise<InsightsResult>;
|
|
44
|
+
//# sourceMappingURL=insights.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insights.d.ts","sourceRoot":"","sources":["../../src/commands/insights.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,eAAO,MAAM,mBAAmB;;;;;;EAE9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;IAC3E,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAqC/F"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readPercherTomlAppName } from "../app-name";
|
|
3
|
+
import { PercherCoreError } from "../errors";
|
|
4
|
+
export const insightsInputSchema = z.object({
|
|
5
|
+
app: z.string().optional(),
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* AI-driven cost optimization (MCP).
|
|
9
|
+
*
|
|
10
|
+
* Surfaces per-app suggestions computed by the API's `AppInsightsService`.
|
|
11
|
+
* Rules read DB-backed signals (analytics, crashes, deploys, plan) and
|
|
12
|
+
* return suggestions like "looks idle — delete it", "OOM kills in last 14d
|
|
13
|
+
* — upgrade memory", or "plan headroom unused — downgrade".
|
|
14
|
+
*
|
|
15
|
+
* Read-only. Does not execute downgrades/upgrades — that needs Polar billing
|
|
16
|
+
* to be live. For now the assistant can only describe + propose.
|
|
17
|
+
*/
|
|
18
|
+
export async function insights(ctx, input = {}) {
|
|
19
|
+
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
20
|
+
if (!name) {
|
|
21
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
22
|
+
code: "insights.no-app",
|
|
23
|
+
hint: "Pass an app name or run from a directory with percher.toml.",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const data = await ctx.client.apps.getInsights(name);
|
|
27
|
+
const priority = {
|
|
28
|
+
critical: 0,
|
|
29
|
+
warning: 1,
|
|
30
|
+
info: 2,
|
|
31
|
+
};
|
|
32
|
+
const sorted = [...data.insights].sort((a, b) => priority[a.severity] - priority[b.severity]);
|
|
33
|
+
let summary = "";
|
|
34
|
+
if (sorted.length === 0) {
|
|
35
|
+
summary = `No suggestions for "${data.appName}" (plan: ${data.plan}).`;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const top = sorted[0];
|
|
39
|
+
if (top) {
|
|
40
|
+
summary = `${data.appName}: ${top.title}. ${top.suggestion}`;
|
|
41
|
+
if (sorted.length > 1) {
|
|
42
|
+
summary += ` (${sorted.length - 1} more suggestion${sorted.length - 1 === 1 ? "" : "s"}.)`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
appName: data.appName,
|
|
48
|
+
plan: data.plan,
|
|
49
|
+
generatedAt: data.generatedAt,
|
|
50
|
+
insights: sorted,
|
|
51
|
+
summary,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=insights.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insights.js","sourceRoot":"","sources":["../../src/commands/insights.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;IAC1C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC3B,CAAC,CAAC;AA0BH;;;;;;;;;;GAUG;AACH,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,iBAAiB;YACvB,IAAI,EAAE,6DAA6D;SACpE,CAAC,CAAC;IACL,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAErD,MAAM,QAAQ,GAAkD;QAC9D,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,CAAC;KACR,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE9F,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,uBAAuB,IAAI,CAAC,OAAO,YAAY,IAAI,CAAC,IAAI,IAAI,CAAC;IACzE,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,GAAG,GAAG,IAAI,CAAC,OAAO,KAAK,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,UAAU,EAAE,CAAC;YAC7D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,IAAI,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,mBAAmB,MAAM,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YAC7F,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,MAAM;QAChB,OAAO;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Context } from "../context";
|
|
3
|
+
export declare const mcpInputSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
4
|
+
export type McpInput = z.infer<typeof mcpInputSchema>;
|
|
5
|
+
export interface McpConfigResult {
|
|
6
|
+
/** Canonical mcpServers entry that any MCP-aware client can paste in. */
|
|
7
|
+
config: {
|
|
8
|
+
mcpServers: {
|
|
9
|
+
percher: {
|
|
10
|
+
command: string;
|
|
11
|
+
args: string[];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/** Per-client paste-target paths (informational, no install performed). */
|
|
16
|
+
installLocations: Array<{
|
|
17
|
+
client: string;
|
|
18
|
+
path: string;
|
|
19
|
+
note?: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns the canonical Percher MCP server config plus the file paths
|
|
24
|
+
* each major MCP client reads it from. Intentionally does not install
|
|
25
|
+
* anything — the CLI just prints what to paste, so the user can choose
|
|
26
|
+
* which tool gets the entry without us touching their dotfiles.
|
|
27
|
+
*/
|
|
28
|
+
export declare function mcp(_ctx: Context, _input?: McpInput): McpConfigResult;
|
|
29
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,cAAc,gDAAe,CAAC;AAC3C,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,MAAM,EAAE;QAAE,UAAU,EAAE;YAAE,OAAO,EAAE;gBAAE,OAAO,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,EAAE,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAC;IACzE,2EAA2E;IAC3E,gBAAgB,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1E;AAED;;;;;GAKG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,GAAE,QAAa,GAAG,eAAe,CAyBzE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const mcpInputSchema = z.object({});
|
|
3
|
+
/**
|
|
4
|
+
* Returns the canonical Percher MCP server config plus the file paths
|
|
5
|
+
* each major MCP client reads it from. Intentionally does not install
|
|
6
|
+
* anything — the CLI just prints what to paste, so the user can choose
|
|
7
|
+
* which tool gets the entry without us touching their dotfiles.
|
|
8
|
+
*/
|
|
9
|
+
export function mcp(_ctx, _input = {}) {
|
|
10
|
+
return {
|
|
11
|
+
config: {
|
|
12
|
+
mcpServers: {
|
|
13
|
+
percher: {
|
|
14
|
+
command: "npx",
|
|
15
|
+
args: ["-y", "@percher/mcp"],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
installLocations: [
|
|
20
|
+
{
|
|
21
|
+
client: "Claude Code",
|
|
22
|
+
path: "~/.claude.json (under mcpServers, or a per-project .mcp.json)",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
client: "Cursor / Windsurf",
|
|
26
|
+
path: "settings → MCP → add server (use the same npx command)",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
client: "VS Code (Continue / Cline)",
|
|
30
|
+
path: "extension settings → MCP servers",
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAU3C;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CAAC,IAAa,EAAE,SAAmB,EAAE;IACtD,OAAO;QACL,MAAM,EAAE;YACN,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE,CAAC,IAAI,EAAE,cAAc,CAAC;iBAC7B;aACF;SACF;QACD,gBAAgB,EAAE;YAChB;gBACE,MAAM,EAAE,aAAa;gBACrB,IAAI,EAAE,+DAA+D;aACtE;YACD;gBACE,MAAM,EAAE,mBAAmB;gBAC3B,IAAI,EAAE,wDAAwD;aAC/D;YACD;gBACE,MAAM,EAAE,4BAA4B;gBACpC,IAAI,EAAE,kCAAkC;aACzC;SACF;KACF,CAAC;AACJ,CAAC"}
|