@m-kopa/launchpad-cli 0.53.0 → 0.54.1
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/CHANGELOG.md +19 -0
- package/dist/auth/discovery.d.ts.map +1 -1
- package/dist/auth/gateway-flow.d.ts.map +1 -1
- package/dist/auth/registration.d.ts.map +1 -1
- package/dist/auth/token.d.ts.map +1 -1
- package/dist/bundle/upload.d.ts +2 -0
- package/dist/bundle/upload.d.ts.map +1 -1
- package/dist/cli.js +251 -91
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/deploy/git-files.d.ts +7 -11
- package/dist/deploy/git-files.d.ts.map +1 -1
- package/dist/dispatcher.d.ts +5 -1
- package/dist/dispatcher.d.ts.map +1 -1
- package/dist/http/api-client.d.ts.map +1 -1
- package/dist/http/errors.d.ts +11 -0
- package/dist/http/errors.d.ts.map +1 -1
- package/dist/http/preflight.d.ts +7 -0
- package/dist/http/preflight.d.ts.map +1 -0
- package/dist/http/version-headers.d.ts +10 -0
- package/dist/http/version-headers.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +4 -1
- package/skills/launchpad-content-pr/SKILL.md +1 -1
- package/skills/launchpad-deploy/SKILL.md +1 -1
- package/skills/launchpad-deploy-status/SKILL.md +1 -1
- package/skills/launchpad-destroy/SKILL.md +1 -1
- package/skills/launchpad-identity/SKILL.md +1 -1
- package/skills/launchpad-onboard/SKILL.md +1 -1
- package/skills/launchpad-report/SKILL.md +1 -1
- package/skills/launchpad-status/SKILL.md +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,25 @@ pre-1.0 minor bumps may carry breaking changes per ADR 0005.
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 0.54.1 - 2026-07-29
|
|
12
|
+
|
|
13
|
+
**Deleted application files now stay deleted after deployment.**
|
|
14
|
+
|
|
15
|
+
- The legacy clone deploy path excludes tracked files that no longer exist in the working tree, allowing the server to derive their deletion from the complete upload.
|
|
16
|
+
- The platform applies updates and proved app-owned deletions in one Git tree while preserving governance, workflow, ownership, Wrangler, Launchpad metadata, and out-of-boundary files.
|
|
17
|
+
- The server uses exact managed-tree enumeration before absence can authorize deletion and returns a retryable failure when that proof is unavailable.
|
|
18
|
+
|
|
19
|
+
## 0.54.0 - 2026-07-19
|
|
20
|
+
|
|
21
|
+
**Server-visible CLI compatibility, with dormant minimum-version enforcement.**
|
|
22
|
+
|
|
23
|
+
- Every request to the Launchpad bot now sends the real CLI release in `x-launchpad-cli-version` and the `User-Agent`, replacing the placeholder `launchpad-cli/0.x` value.
|
|
24
|
+
This lets the platform measure authenticated CLI adoption from server observations and reconcile it with PostHog telemetry.
|
|
25
|
+
- Mutating commands make one authenticated compatibility preflight before local build or upload work.
|
|
26
|
+
A future server-configured minimum can return HTTP `426 Upgrade Required`; the CLI then prints its version, the minimum version, and `run launchpad update`, and exits with the dedicated code `42`.
|
|
27
|
+
- Upload and deployment requests also handle `426` directly so a floor change between preflight and mutation cannot proceed silently.
|
|
28
|
+
- No minimum version is configured by this release, so the compatibility machinery is dormant and no client is blocked.
|
|
29
|
+
|
|
11
30
|
## 0.53.0 - 2026-07-18
|
|
12
31
|
|
|
13
32
|
**Breaking: `launchpad pull` now synchronizes source.**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/auth/discovery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/auth/discovery.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAU;CAC5C;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,cAAc,CAAC,CA0EzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-flow.d.ts","sourceRoot":"","sources":["../../src/auth/gateway-flow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gateway-flow.d.ts","sourceRoot":"","sources":["../../src/auth/gateway-flow.ts"],"names":[],"mappings":"AA4CA,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,qBAAqB,wBAAwB,CAAC;AAC3D,eAAO,MAAM,sBAAsB,yBAAyB,CAAC;AAC7D,eAAO,MAAM,eAAe,kBAAkB,CAAC;AAE/C;;6DAE6D;AAC7D,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAU;CAChD;AAED;;sCAEsC;AACtC,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAU;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBACjB,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAKjD;AAED;;;gCAGgC;AAChC,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAG,sBAAsB,CAAU;IAChD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;gBACnB,aAAa,EAAE,MAAM;CAOlC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;wBAEoB;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,kCAAkC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,iBAAiB,CAAC,CAkD5B;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE;IAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EACtE,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAS3B;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE;IAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EACtE,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,IAAI,CAAC,CAwBf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/auth/registration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/auth/registration.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAG,oBAAoB,CAAU;CAC/C;AAED,wBAAsB,cAAc,CAClC,oBAAoB,EAAE,MAAM,EAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CA6C7B"}
|
package/dist/auth/token.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/auth/token.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/auth/token.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;qEACiE;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAG,aAAa,CAAU;IACvC;;qDAEiD;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBACjB,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAKjD;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE;IACN,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;6DAGyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,EACD,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,aAAa,CAAC,CAUxB;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE;IACN,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;+CAE2C;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,EACD,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,aAAa,CAAC,CAQxB"}
|
package/dist/bundle/upload.d.ts
CHANGED
|
@@ -110,6 +110,8 @@ export interface DeployBundleError extends StructuredErrorEnvelope {
|
|
|
110
110
|
readonly head_sha?: string;
|
|
111
111
|
readonly paths?: readonly string[];
|
|
112
112
|
readonly reason?: string;
|
|
113
|
+
readonly minimum?: string;
|
|
114
|
+
readonly yours?: string;
|
|
113
115
|
}
|
|
114
116
|
export type DeployBundleResult = {
|
|
115
117
|
kind: "ok";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/bundle/upload.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/bundle/upload.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
19
19
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
20
|
|
|
21
21
|
// src/version.ts
|
|
22
|
-
var CLI_VERSION = "0.
|
|
22
|
+
var CLI_VERSION = "0.54.1";
|
|
23
23
|
|
|
24
24
|
// src/config.ts
|
|
25
25
|
import * as os from "node:os";
|
|
@@ -213,6 +213,22 @@ class ForbiddenError extends Error {
|
|
|
213
213
|
class NotFoundError extends Error {
|
|
214
214
|
code = "not_found";
|
|
215
215
|
}
|
|
216
|
+
var EXIT_CLI_UPGRADE_REQUIRED = 42;
|
|
217
|
+
|
|
218
|
+
class UpgradeRequiredError extends Error {
|
|
219
|
+
code = "cli_upgrade_required";
|
|
220
|
+
minimum;
|
|
221
|
+
yours;
|
|
222
|
+
constructor(minimum, yours) {
|
|
223
|
+
super(upgradeRequiredMessage(minimum, yours));
|
|
224
|
+
this.name = "UpgradeRequiredError";
|
|
225
|
+
this.minimum = minimum;
|
|
226
|
+
this.yours = yours;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function upgradeRequiredMessage(minimum, yours) {
|
|
230
|
+
return `you're on ${yours}; minimum supported is ${minimum} - run launchpad update`;
|
|
231
|
+
}
|
|
216
232
|
|
|
217
233
|
class ApiError extends Error {
|
|
218
234
|
faultCode = "api_error";
|
|
@@ -363,6 +379,21 @@ function escapeHtml(s) {
|
|
|
363
379
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
364
380
|
}
|
|
365
381
|
|
|
382
|
+
// src/http/version-headers.ts
|
|
383
|
+
var CLI_VERSION_HEADER = "x-launchpad-cli-version";
|
|
384
|
+
function cliVersionHeaders(headers = {}) {
|
|
385
|
+
const result = { ...headers };
|
|
386
|
+
for (const key of Object.keys(result)) {
|
|
387
|
+
const lower = key.toLowerCase();
|
|
388
|
+
if (lower === CLI_VERSION_HEADER || lower === "user-agent") {
|
|
389
|
+
delete result[key];
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
result[CLI_VERSION_HEADER] = CLI_VERSION;
|
|
393
|
+
result["user-agent"] = `launchpad-cli/${CLI_VERSION}`;
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
396
|
+
|
|
366
397
|
// src/auth/discovery.ts
|
|
367
398
|
class DiscoveryError extends Error {
|
|
368
399
|
code = "discovery_error";
|
|
@@ -401,7 +432,10 @@ async function discoverOauthEndpoints(botUrl, fetcher = fetch) {
|
|
|
401
432
|
async function fetchJson(fetcher, url) {
|
|
402
433
|
let res;
|
|
403
434
|
try {
|
|
404
|
-
res = await fetcher(url, {
|
|
435
|
+
res = await fetcher(url, {
|
|
436
|
+
method: "GET",
|
|
437
|
+
headers: cliVersionHeaders()
|
|
438
|
+
});
|
|
405
439
|
} catch (e) {
|
|
406
440
|
throw new DiscoveryError(`discovery: network error fetching ${url}: ${describe(e)}`);
|
|
407
441
|
}
|
|
@@ -471,10 +505,10 @@ async function registerClient(registrationEndpoint, redirectUri, fetcher = fetch
|
|
|
471
505
|
try {
|
|
472
506
|
res = await fetcher(registrationEndpoint, {
|
|
473
507
|
method: "POST",
|
|
474
|
-
headers: {
|
|
508
|
+
headers: cliVersionHeaders({
|
|
475
509
|
"content-type": "application/json",
|
|
476
510
|
accept: "application/json"
|
|
477
|
-
},
|
|
511
|
+
}),
|
|
478
512
|
body: JSON.stringify(body)
|
|
479
513
|
});
|
|
480
514
|
} catch (e) {
|
|
@@ -535,10 +569,10 @@ async function postTokenForm(tokenEndpoint, form, fetcher) {
|
|
|
535
569
|
try {
|
|
536
570
|
res = await fetcher(tokenEndpoint, {
|
|
537
571
|
method: "POST",
|
|
538
|
-
headers: {
|
|
572
|
+
headers: cliVersionHeaders({
|
|
539
573
|
"content-type": "application/x-www-form-urlencoded",
|
|
540
574
|
accept: "application/json"
|
|
541
|
-
},
|
|
575
|
+
}),
|
|
542
576
|
body: form.toString()
|
|
543
577
|
});
|
|
544
578
|
} catch (e) {
|
|
@@ -805,7 +839,9 @@ async function revokeGatewaySession(params, fetcher = fetch) {
|
|
|
805
839
|
try {
|
|
806
840
|
res = await fetcher(url, {
|
|
807
841
|
method: "POST",
|
|
808
|
-
headers: {
|
|
842
|
+
headers: cliVersionHeaders({
|
|
843
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
844
|
+
}),
|
|
809
845
|
body: new URLSearchParams({ refresh_token: params.refreshToken }).toString()
|
|
810
846
|
});
|
|
811
847
|
} catch (e) {
|
|
@@ -823,7 +859,10 @@ async function probeGateway(gatewayUrl, fetcher) {
|
|
|
823
859
|
const url = `${gatewayUrl}${CLI_SESSION_AUTH_PATH}`;
|
|
824
860
|
let res;
|
|
825
861
|
try {
|
|
826
|
-
res = await fetcher(url, {
|
|
862
|
+
res = await fetcher(url, {
|
|
863
|
+
method: "GET",
|
|
864
|
+
headers: cliVersionHeaders()
|
|
865
|
+
});
|
|
827
866
|
} catch (e) {
|
|
828
867
|
throw new GatewayUnavailableError(`auth gateway unreachable at ${gatewayUrl}: ${describe5(e)}`);
|
|
829
868
|
}
|
|
@@ -840,10 +879,10 @@ async function postSessionTokenForm(gatewayUrl, form, fetcher) {
|
|
|
840
879
|
try {
|
|
841
880
|
res = await fetcher(url, {
|
|
842
881
|
method: "POST",
|
|
843
|
-
headers: {
|
|
882
|
+
headers: cliVersionHeaders({
|
|
844
883
|
"content-type": "application/x-www-form-urlencoded",
|
|
845
884
|
accept: "application/json"
|
|
846
|
-
},
|
|
885
|
+
}),
|
|
847
886
|
body: form.toString()
|
|
848
887
|
});
|
|
849
888
|
} catch (e) {
|
|
@@ -1054,12 +1093,11 @@ async function apiRaw(cfg, opts, fetcher = fetch) {
|
|
|
1054
1093
|
}
|
|
1055
1094
|
throw e;
|
|
1056
1095
|
}
|
|
1057
|
-
const headers = {
|
|
1096
|
+
const headers = cliVersionHeaders({
|
|
1058
1097
|
accept: "application/json",
|
|
1059
1098
|
...opts.headers,
|
|
1060
|
-
authorization: `Bearer ${token}
|
|
1061
|
-
|
|
1062
|
-
};
|
|
1099
|
+
authorization: `Bearer ${token}`
|
|
1100
|
+
});
|
|
1063
1101
|
for (const k of Object.keys(headers)) {
|
|
1064
1102
|
if (k !== "authorization" && k.toLowerCase() === "authorization") {
|
|
1065
1103
|
delete headers[k];
|
|
@@ -1083,6 +1121,9 @@ async function apiRaw(cfg, opts, fetcher = fetch) {
|
|
|
1083
1121
|
} catch (e) {
|
|
1084
1122
|
throw recordedFault(new TransportError(`network error calling ${url}: ${describe7(e)}`));
|
|
1085
1123
|
}
|
|
1124
|
+
if (res.status === 426) {
|
|
1125
|
+
throw recordedFault(await decodeUpgradeRequired(res, opts.path));
|
|
1126
|
+
}
|
|
1086
1127
|
if (res.status === 401) {
|
|
1087
1128
|
const detail = await errorDetail(res, opts.path);
|
|
1088
1129
|
throw recordedFault(new UnauthenticatedError(`bot returned 401 for ${opts.path}: ${detail} — run \`launchpad login\``));
|
|
@@ -1104,6 +1145,18 @@ async function apiRaw(cfg, opts, fetcher = fetch) {
|
|
|
1104
1145
|
clearFault();
|
|
1105
1146
|
return res;
|
|
1106
1147
|
}
|
|
1148
|
+
async function decodeUpgradeRequired(response, endpoint) {
|
|
1149
|
+
const body = await readErrorText(response);
|
|
1150
|
+
if (body.kind === "text") {
|
|
1151
|
+
try {
|
|
1152
|
+
const parsed = JSON.parse(body.text);
|
|
1153
|
+
if (typeof parsed.minimum === "string" && typeof parsed.yours === "string") {
|
|
1154
|
+
return new UpgradeRequiredError(parsed.minimum, parsed.yours);
|
|
1155
|
+
}
|
|
1156
|
+
} catch {}
|
|
1157
|
+
}
|
|
1158
|
+
return new ApiError(decodeErrorEnvelope({ code: "cli_upgrade_required", message: "CLI upgrade required" }, { status: 426, endpoint }));
|
|
1159
|
+
}
|
|
1107
1160
|
async function readErrorText(res) {
|
|
1108
1161
|
const reader = res.body?.getReader();
|
|
1109
1162
|
if (reader === undefined)
|
|
@@ -1814,7 +1867,7 @@ function describe10(e) {
|
|
|
1814
1867
|
}
|
|
1815
1868
|
|
|
1816
1869
|
// src/commands/deploy.ts
|
|
1817
|
-
import { existsSync as
|
|
1870
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
1818
1871
|
import * as path8 from "node:path";
|
|
1819
1872
|
|
|
1820
1873
|
// src/bundle/orchestrate.ts
|
|
@@ -1995,11 +2048,11 @@ async function uploadBundle(cfg, slug, manifestYaml, bundleTarGz, workerArtifact
|
|
|
1995
2048
|
}
|
|
1996
2049
|
const url = `${cfg.botUrl}/apps/${slug}/deploy/bundle`;
|
|
1997
2050
|
const { accessToken } = await getValidAccessToken(cfg.sessionPath);
|
|
1998
|
-
const headers = {
|
|
2051
|
+
const headers = cliVersionHeaders({
|
|
1999
2052
|
authorization: `Bearer ${accessToken}`,
|
|
2000
2053
|
accept: "application/json",
|
|
2001
2054
|
"x-launchpad-capabilities": `${ACCESS_RECONCILE_EXACT_SHA_V1},${SOURCE_PROVENANCE_V1}`
|
|
2002
|
-
};
|
|
2055
|
+
});
|
|
2003
2056
|
if (baseSha)
|
|
2004
2057
|
headers["x-launchpad-base-sha"] = baseSha;
|
|
2005
2058
|
if (overrideStale)
|
|
@@ -2128,7 +2181,9 @@ function deployBundleError(envelope, body) {
|
|
|
2128
2181
|
...manifestOnly === undefined ? {} : { manifest_only: manifestOnly },
|
|
2129
2182
|
...typeof body.head_sha === "string" ? { head_sha: body.head_sha } : {},
|
|
2130
2183
|
...paths === undefined ? {} : { paths },
|
|
2131
|
-
...typeof body.reason === "string" ? { reason: body.reason } : {}
|
|
2184
|
+
...typeof body.reason === "string" ? { reason: body.reason } : {},
|
|
2185
|
+
...typeof body.minimum === "string" ? { minimum: body.minimum } : {},
|
|
2186
|
+
...typeof body.yours === "string" ? { yours: body.yours } : {}
|
|
2132
2187
|
};
|
|
2133
2188
|
}
|
|
2134
2189
|
function readStringArray(value) {
|
|
@@ -2602,6 +2657,7 @@ var ManifestSchema = z.object({
|
|
|
2602
2657
|
app: AppBoundarySchema.optional(),
|
|
2603
2658
|
verify: VerifySchema.optional(),
|
|
2604
2659
|
confine_origin: z.boolean().optional(),
|
|
2660
|
+
origin: z.enum(["pages", "dispatch"]).optional(),
|
|
2605
2661
|
catalogue: z.object({ listed: z.boolean().default(true) }).strict().optional(),
|
|
2606
2662
|
sensitive: z.boolean().optional()
|
|
2607
2663
|
}).strict().superRefine((m, ctx) => {
|
|
@@ -2992,7 +3048,9 @@ var PLATFORM_SEEDED_GITHUB_PATHS = new Set([
|
|
|
2992
3048
|
".github/scripts/parse-tsc.mjs",
|
|
2993
3049
|
".github/scripts/parse-vitest.mjs",
|
|
2994
3050
|
".github/scripts/parse-gitleaks.mjs",
|
|
2995
|
-
".github/scripts/parse-bun-audit.mjs"
|
|
3051
|
+
".github/scripts/parse-bun-audit.mjs",
|
|
3052
|
+
".github/scripts/parse-html-validate.mjs",
|
|
3053
|
+
".github/scripts/parse-hadolint.mjs"
|
|
2996
3054
|
]);
|
|
2997
3055
|
function checkDenyList(path7) {
|
|
2998
3056
|
const segments = path7.split("/");
|
|
@@ -3235,6 +3293,7 @@ var SpecSchema = z2.object({
|
|
|
3235
3293
|
app: AppBoundarySchema.optional(),
|
|
3236
3294
|
verify: VerifySchema.optional(),
|
|
3237
3295
|
confine_origin: z2.boolean().optional(),
|
|
3296
|
+
origin: z2.enum(["pages", "dispatch"]).optional(),
|
|
3238
3297
|
sensitive: z2.boolean().optional(),
|
|
3239
3298
|
catalogue: z2.object({ listed: z2.boolean().default(true) }).strict().optional(),
|
|
3240
3299
|
env_vars: z2.record(z2.string().regex(ENV_NAME_REGEX, "env_vars keys must be UPPER_SNAKE_CASE"), EnvVarSchema).optional(),
|
|
@@ -3280,6 +3339,43 @@ var SpecSchema = z2.object({
|
|
|
3280
3339
|
});
|
|
3281
3340
|
}
|
|
3282
3341
|
}
|
|
3342
|
+
if (s.origin === "dispatch") {
|
|
3343
|
+
if (isContainer) {
|
|
3344
|
+
ctx.addIssue({
|
|
3345
|
+
code: z2.ZodIssueCode.custom,
|
|
3346
|
+
path: ["origin"],
|
|
3347
|
+
message: "origin: dispatch is not available for container apps — they run on the container runtime (ADR 0015/0016), not in a Workers dispatch namespace."
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
if ((s.auth ?? "access") !== "gateway") {
|
|
3351
|
+
ctx.addIssue({
|
|
3352
|
+
code: z2.ZodIssueCode.custom,
|
|
3353
|
+
path: ["origin"],
|
|
3354
|
+
message: "origin: dispatch requires an explicit auth: gateway (auth defaults to 'access' when omitted). A dispatch-namespace Worker has no public hostname for Cloudflare Access to gate, so the gateway must be the sole gate."
|
|
3355
|
+
});
|
|
3356
|
+
}
|
|
3357
|
+
if (s.confine_origin !== undefined) {
|
|
3358
|
+
ctx.addIssue({
|
|
3359
|
+
code: z2.ZodIssueCode.custom,
|
|
3360
|
+
path: ["confine_origin"],
|
|
3361
|
+
message: "confine_origin has no meaning with origin: dispatch — there is no public pages.dev apex to confine. Remove it."
|
|
3362
|
+
});
|
|
3363
|
+
}
|
|
3364
|
+
if (s.env_vars !== undefined) {
|
|
3365
|
+
ctx.addIssue({
|
|
3366
|
+
code: z2.ZodIssueCode.custom,
|
|
3367
|
+
path: ["env_vars"],
|
|
3368
|
+
message: "env_vars are not yet supported with origin: dispatch — a dispatch workspace has no Pages module to apply them, and accepting them here would silently drop them. Worker-level vars land with the v2 deploy path."
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
if (s.build !== undefined) {
|
|
3372
|
+
ctx.addIssue({
|
|
3373
|
+
code: z2.ZodIssueCode.custom,
|
|
3374
|
+
path: ["build"],
|
|
3375
|
+
message: "build is not yet supported with origin: dispatch — a dispatch workspace has no Pages module to carry it, and the v2 deploy path that will consume it is not shipped yet. Accepting it here would silently drop it."
|
|
3376
|
+
});
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3283
3379
|
if (!isContainer && s.containers !== undefined) {
|
|
3284
3380
|
ctx.addIssue({
|
|
3285
3381
|
code: z2.ZodIssueCode.custom,
|
|
@@ -6130,6 +6226,8 @@ import { readFileSync as readFileSync10 } from "node:fs";
|
|
|
6130
6226
|
|
|
6131
6227
|
// src/deploy/git-files.ts
|
|
6132
6228
|
import { spawn as spawn3 } from "node:child_process";
|
|
6229
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
6230
|
+
import { resolve as resolve7 } from "node:path";
|
|
6133
6231
|
|
|
6134
6232
|
class GitFilesError extends Error {
|
|
6135
6233
|
code = "git_files_error";
|
|
@@ -6147,6 +6245,7 @@ var PROTECTED_PATHS = new Set([
|
|
|
6147
6245
|
]);
|
|
6148
6246
|
async function listDeployFiles(opts) {
|
|
6149
6247
|
const sp = opts.spawner ?? spawn3;
|
|
6248
|
+
const exists = opts.exists ?? existsSync5;
|
|
6150
6249
|
const stdout = await runGit2(sp, opts.cwd, [
|
|
6151
6250
|
"ls-files",
|
|
6152
6251
|
"-c",
|
|
@@ -6154,11 +6253,11 @@ async function listDeployFiles(opts) {
|
|
|
6154
6253
|
"--exclude-standard",
|
|
6155
6254
|
"-z"
|
|
6156
6255
|
]);
|
|
6157
|
-
const paths = stdout.split("\x00").filter((p) => p.length > 0 && !PROTECTED_PATHS.has(p));
|
|
6256
|
+
const paths = stdout.split("\x00").filter((p) => p.length > 0 && exists(resolve7(opts.cwd, p)) && !PROTECTED_PATHS.has(p));
|
|
6158
6257
|
return [...paths].sort();
|
|
6159
6258
|
}
|
|
6160
6259
|
function runGit2(sp, cwd, args) {
|
|
6161
|
-
return new Promise((
|
|
6260
|
+
return new Promise((resolve8, reject) => {
|
|
6162
6261
|
const spawnOpts = { cwd, stdio: ["ignore", "pipe", "pipe"] };
|
|
6163
6262
|
const child = sp("git", [...args], spawnOpts);
|
|
6164
6263
|
let stdout = "";
|
|
@@ -6174,7 +6273,7 @@ function runGit2(sp, cwd, args) {
|
|
|
6174
6273
|
});
|
|
6175
6274
|
child.once("close", (code) => {
|
|
6176
6275
|
if (code === 0) {
|
|
6177
|
-
|
|
6276
|
+
resolve8(stdout);
|
|
6178
6277
|
return;
|
|
6179
6278
|
}
|
|
6180
6279
|
reject(new GitFilesError(`\`git ${args.join(" ")}\` exited ${code}: ${stderr.trim()}`));
|
|
@@ -6751,7 +6850,7 @@ function parseDeployFlags(args) {
|
|
|
6751
6850
|
}
|
|
6752
6851
|
|
|
6753
6852
|
// src/deploy/apply.ts
|
|
6754
|
-
import { existsSync as
|
|
6853
|
+
import { existsSync as existsSync6, rmSync } from "node:fs";
|
|
6755
6854
|
import { resolve as resolvePath, join as join10 } from "node:path";
|
|
6756
6855
|
|
|
6757
6856
|
// src/manifest/load.ts
|
|
@@ -7118,7 +7217,7 @@ function sleep(ms) {
|
|
|
7118
7217
|
}
|
|
7119
7218
|
function deletePinIfPresent(cfg, slug, io) {
|
|
7120
7219
|
const pinPath = join10(cfg.stateDir, slug, "group.json");
|
|
7121
|
-
if (!
|
|
7220
|
+
if (!existsSync6(pinPath))
|
|
7122
7221
|
return;
|
|
7123
7222
|
try {
|
|
7124
7223
|
rmSync(pinPath, { force: true });
|
|
@@ -7256,12 +7355,12 @@ async function handleAccessDrift(params) {
|
|
|
7256
7355
|
|
|
7257
7356
|
// src/deploy/dry-run.ts
|
|
7258
7357
|
import { execFileSync } from "node:child_process";
|
|
7259
|
-
import { resolve as
|
|
7358
|
+
import { resolve as resolve8 } from "node:path";
|
|
7260
7359
|
var MANIFEST_SHA_REGEX2 = /^[0-9a-f]{40}$/;
|
|
7261
7360
|
async function runDeployDryRun(opts, io, deps = {}) {
|
|
7262
7361
|
const cfg = deps.config ?? loadConfig();
|
|
7263
7362
|
const fetcher = deps.fetcher ?? fetch;
|
|
7264
|
-
const manifestPath =
|
|
7363
|
+
const manifestPath = resolve8(process.cwd(), opts.file ?? "launchpad.yaml");
|
|
7265
7364
|
const loaded = loadManifest(manifestPath);
|
|
7266
7365
|
if (loaded.kind !== "ok") {
|
|
7267
7366
|
return renderManifestError2(loaded, opts.json, io);
|
|
@@ -7671,7 +7770,7 @@ async function runDeploy(args, io) {
|
|
|
7671
7770
|
}
|
|
7672
7771
|
const cwd = process.cwd();
|
|
7673
7772
|
const manifestPath = path8.join(cwd, "launchpad.yaml");
|
|
7674
|
-
if (
|
|
7773
|
+
if (existsSync7(manifestPath)) {
|
|
7675
7774
|
const contentMode = flags.mode.kind === "content" ? flags.mode : {
|
|
7676
7775
|
allowStale: false,
|
|
7677
7776
|
rebaseOntoHead: false,
|
|
@@ -7725,7 +7824,7 @@ async function runDeploy(args, io) {
|
|
|
7725
7824
|
}
|
|
7726
7825
|
let contentManifestYaml = null;
|
|
7727
7826
|
const contentManifestPath = path8.join(process.cwd(), "launchpad.yaml");
|
|
7728
|
-
if (
|
|
7827
|
+
if (existsSync7(contentManifestPath)) {
|
|
7729
7828
|
try {
|
|
7730
7829
|
contentManifestYaml = readFileSync10(contentManifestPath, "utf8");
|
|
7731
7830
|
} catch {
|
|
@@ -7773,6 +7872,10 @@ async function runDeploy(args, io) {
|
|
|
7773
7872
|
}
|
|
7774
7873
|
return 0;
|
|
7775
7874
|
} catch (e) {
|
|
7875
|
+
if (e instanceof UpgradeRequiredError) {
|
|
7876
|
+
io.err(e.message);
|
|
7877
|
+
return EXIT_CLI_UPGRADE_REQUIRED;
|
|
7878
|
+
}
|
|
7776
7879
|
if (e instanceof UnauthenticatedError) {
|
|
7777
7880
|
io.err(e.message);
|
|
7778
7881
|
return 1;
|
|
@@ -7944,11 +8047,11 @@ function surfaceStaleBlock(body, io) {
|
|
|
7944
8047
|
}
|
|
7945
8048
|
var MANIFEST_DIFF_READ_TIMEOUT_MS = 5000;
|
|
7946
8049
|
function withTimeout(p, ms) {
|
|
7947
|
-
return new Promise((
|
|
8050
|
+
return new Promise((resolve9, reject) => {
|
|
7948
8051
|
const timer = setTimeout(() => reject(new Error(`manifest read timed out after ${ms}ms`)), ms);
|
|
7949
8052
|
p.then((v) => {
|
|
7950
8053
|
clearTimeout(timer);
|
|
7951
|
-
|
|
8054
|
+
resolve9(v);
|
|
7952
8055
|
}, (e) => {
|
|
7953
8056
|
clearTimeout(timer);
|
|
7954
8057
|
reject(e instanceof Error ? e : new Error(String(e)));
|
|
@@ -8086,6 +8189,10 @@ async function runModelADeploy(args) {
|
|
|
8086
8189
|
}
|
|
8087
8190
|
}
|
|
8088
8191
|
} catch (e) {
|
|
8192
|
+
if (e instanceof UpgradeRequiredError) {
|
|
8193
|
+
io.err(e.message);
|
|
8194
|
+
return EXIT_CLI_UPGRADE_REQUIRED;
|
|
8195
|
+
}
|
|
8089
8196
|
if (e instanceof UnauthenticatedError) {
|
|
8090
8197
|
io.err(`launchpad deploy: ${e.message}`);
|
|
8091
8198
|
io.err(" run `launchpad login` to refresh your session.");
|
|
@@ -8113,6 +8220,10 @@ async function runModelADeploy(args) {
|
|
|
8113
8220
|
case "upload-error": {
|
|
8114
8221
|
const body = result.body;
|
|
8115
8222
|
const errorCode = body.error;
|
|
8223
|
+
if (result.status === 426 && typeof body.minimum === "string" && typeof body.yours === "string") {
|
|
8224
|
+
io.err(upgradeRequiredMessage(body.minimum, body.yours));
|
|
8225
|
+
return EXIT_CLI_UPGRADE_REQUIRED;
|
|
8226
|
+
}
|
|
8116
8227
|
if (result.status === 409 && errorCode === "slug_in_flight") {
|
|
8117
8228
|
io.err(`launchpad deploy: slug "${slug}" is already provisioning.`);
|
|
8118
8229
|
if (typeof body.message === "string") {
|
|
@@ -8299,7 +8410,7 @@ function pendingReconcileOutcome(body) {
|
|
|
8299
8410
|
}
|
|
8300
8411
|
|
|
8301
8412
|
// src/commands/redeploy.ts
|
|
8302
|
-
import { existsSync as
|
|
8413
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
|
|
8303
8414
|
import { resolve as resolvePath2 } from "node:path";
|
|
8304
8415
|
import { parse as parseYaml7 } from "yaml";
|
|
8305
8416
|
var SLUG_RE6 = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
|
|
@@ -8377,7 +8488,7 @@ async function runRedeploy(opts, io, deps = {}) {
|
|
|
8377
8488
|
}
|
|
8378
8489
|
function readLocalAppType(cwd, file) {
|
|
8379
8490
|
const manifestPath = resolvePath2(cwd, file ?? "launchpad.yaml");
|
|
8380
|
-
if (!
|
|
8491
|
+
if (!existsSync8(manifestPath))
|
|
8381
8492
|
return null;
|
|
8382
8493
|
try {
|
|
8383
8494
|
const obj = parseYaml7(readFileSync11(manifestPath, "utf8"));
|
|
@@ -8665,7 +8776,7 @@ function describe16(e) {
|
|
|
8665
8776
|
|
|
8666
8777
|
// src/commands/generate.ts
|
|
8667
8778
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync12, writeFileSync as writeFileSync2 } from "node:fs";
|
|
8668
|
-
import { dirname as dirname6, resolve as
|
|
8779
|
+
import { dirname as dirname6, resolve as resolve9, relative as relative3 } from "node:path";
|
|
8669
8780
|
var generateCommand = {
|
|
8670
8781
|
name: "generate",
|
|
8671
8782
|
summary: "emit derived artefacts (wrangler.toml, deploy.yml) from launchpad.yaml",
|
|
@@ -8678,14 +8789,14 @@ async function runGenerate(args, io) {
|
|
|
8678
8789
|
io.err("Usage: launchpad generate [--file <path>] [--dry-run] [--force] [--json]");
|
|
8679
8790
|
return 64;
|
|
8680
8791
|
}
|
|
8681
|
-
const manifestPath =
|
|
8792
|
+
const manifestPath = resolve9(process.cwd(), flags.file ?? "launchpad.yaml");
|
|
8682
8793
|
const result = loadManifest(manifestPath);
|
|
8683
8794
|
if (result.kind !== "ok") {
|
|
8684
8795
|
return flags.json ? renderManifestErrorJson(result, io) : renderManifestErrorHuman(result, io);
|
|
8685
8796
|
}
|
|
8686
8797
|
const appRoot = dirname6(manifestPath);
|
|
8687
|
-
const wranglerPath =
|
|
8688
|
-
const workflowPath =
|
|
8798
|
+
const wranglerPath = resolve9(appRoot, "container", "wrangler.toml");
|
|
8799
|
+
const workflowPath = resolve9(appRoot, ".github", "workflows", "deploy.yml");
|
|
8689
8800
|
const wranglerOut = generateWranglerToml(result.manifest);
|
|
8690
8801
|
const workflowOut = generateGithubDeployWorkflow(result.manifest);
|
|
8691
8802
|
if (flags.dryRun) {
|
|
@@ -9490,17 +9601,17 @@ function describe19(e) {
|
|
|
9490
9601
|
|
|
9491
9602
|
// src/commands/init.ts
|
|
9492
9603
|
import { createInterface } from "node:readline/promises";
|
|
9493
|
-
import { existsSync as
|
|
9494
|
-
import { dirname as dirname7, resolve as
|
|
9604
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync3 } from "node:fs";
|
|
9605
|
+
import { dirname as dirname7, resolve as resolve10 } from "node:path";
|
|
9495
9606
|
import { stringify as yamlStringify } from "yaml";
|
|
9496
9607
|
|
|
9497
9608
|
// src/detect/index.ts
|
|
9498
|
-
import { existsSync as
|
|
9609
|
+
import { existsSync as existsSync9, readFileSync as readFileSync13, statSync } from "node:fs";
|
|
9499
9610
|
import { join as join12 } from "node:path";
|
|
9500
9611
|
function detectAppShape(cwd) {
|
|
9501
|
-
const hasPackageJson =
|
|
9502
|
-
const hasAnyLockfile = LOCKFILES.some(({ file }) =>
|
|
9503
|
-
const hasViteConfig = VITE_CONFIG_NAMES.some((n) =>
|
|
9612
|
+
const hasPackageJson = existsSync9(join12(cwd, "package.json"));
|
|
9613
|
+
const hasAnyLockfile = LOCKFILES.some(({ file }) => existsSync9(join12(cwd, file)));
|
|
9614
|
+
const hasViteConfig = VITE_CONFIG_NAMES.some((n) => existsSync9(join12(cwd, n)));
|
|
9504
9615
|
if (!hasPackageJson && !hasAnyLockfile && !hasViteConfig) {
|
|
9505
9616
|
return {
|
|
9506
9617
|
kind: "not-applicable",
|
|
@@ -9546,7 +9657,7 @@ var LOCKFILES = [
|
|
|
9546
9657
|
{ file: "yarn.lock", pm: "yarn" }
|
|
9547
9658
|
];
|
|
9548
9659
|
function detectPackageManager(cwd) {
|
|
9549
|
-
const present = LOCKFILES.filter(({ file }) =>
|
|
9660
|
+
const present = LOCKFILES.filter(({ file }) => existsSync9(join12(cwd, file)));
|
|
9550
9661
|
if (present.length === 0) {
|
|
9551
9662
|
return {
|
|
9552
9663
|
kind: "ambiguous",
|
|
@@ -9569,7 +9680,7 @@ function detectPackageManager(cwd) {
|
|
|
9569
9680
|
function detectVitePresence(cwd) {
|
|
9570
9681
|
for (const name of VITE_CONFIG_NAMES) {
|
|
9571
9682
|
const p = join12(cwd, name);
|
|
9572
|
-
if (
|
|
9683
|
+
if (existsSync9(p)) {
|
|
9573
9684
|
return { kind: "ok", value: { path: p } };
|
|
9574
9685
|
}
|
|
9575
9686
|
}
|
|
@@ -9581,7 +9692,7 @@ function detectVitePresence(cwd) {
|
|
|
9581
9692
|
function detectAppType(cwd) {
|
|
9582
9693
|
const fnDir = join12(cwd, "functions");
|
|
9583
9694
|
let hasFunctionsDir = false;
|
|
9584
|
-
if (
|
|
9695
|
+
if (existsSync9(fnDir)) {
|
|
9585
9696
|
try {
|
|
9586
9697
|
hasFunctionsDir = statSync(fnDir).isDirectory();
|
|
9587
9698
|
} catch {
|
|
@@ -9592,7 +9703,7 @@ function detectAppType(cwd) {
|
|
|
9592
9703
|
}
|
|
9593
9704
|
function detectBuildCommand(cwd, pm) {
|
|
9594
9705
|
const pkgJsonPath = join12(cwd, "package.json");
|
|
9595
|
-
if (!
|
|
9706
|
+
if (!existsSync9(pkgJsonPath)) {
|
|
9596
9707
|
return {
|
|
9597
9708
|
kind: "ambiguous",
|
|
9598
9709
|
reason: "no package.json at repo root. Run your package manager's `init` first."
|
|
@@ -9664,8 +9775,8 @@ async function runInit(args, io, prompt) {
|
|
|
9664
9775
|
return 64;
|
|
9665
9776
|
}
|
|
9666
9777
|
const { inputs, options } = parsed;
|
|
9667
|
-
const outPath =
|
|
9668
|
-
if (
|
|
9778
|
+
const outPath = resolve10(process.cwd(), options.out);
|
|
9779
|
+
if (existsSync10(outPath) && !options.force) {
|
|
9669
9780
|
io.err(`launchpad init: ${outPath} already exists`);
|
|
9670
9781
|
io.err("Pass --force to overwrite.");
|
|
9671
9782
|
return 64;
|
|
@@ -9712,7 +9823,7 @@ async function runInit(args, io, prompt) {
|
|
|
9712
9823
|
}
|
|
9713
9824
|
io.out(`✓ wrote ${outPath}`);
|
|
9714
9825
|
if (options.gitignore) {
|
|
9715
|
-
const gitignorePath =
|
|
9826
|
+
const gitignorePath = resolve10(process.cwd(), ".gitignore");
|
|
9716
9827
|
try {
|
|
9717
9828
|
const changed = ensureGitignoreEntries(gitignorePath, [".env", ".env.local"]);
|
|
9718
9829
|
if (changed.length > 0) {
|
|
@@ -9727,9 +9838,9 @@ async function runInit(args, io, prompt) {
|
|
|
9727
9838
|
}
|
|
9728
9839
|
}
|
|
9729
9840
|
if (fillResult.inputs.type === "static") {
|
|
9730
|
-
const serveDir =
|
|
9731
|
-
const indexPath =
|
|
9732
|
-
if (!
|
|
9841
|
+
const serveDir = resolve10(dirname7(outPath), STATIC_SERVE_DIR);
|
|
9842
|
+
const indexPath = resolve10(serveDir, "index.html");
|
|
9843
|
+
if (!existsSync10(indexPath)) {
|
|
9733
9844
|
try {
|
|
9734
9845
|
mkdirSync3(serveDir, { recursive: true });
|
|
9735
9846
|
writeFileSync3(indexPath, starterIndexHtml(fillResult.inputs.name), {
|
|
@@ -10121,7 +10232,7 @@ function renderYaml(manifest) {
|
|
|
10121
10232
|
}
|
|
10122
10233
|
function ensureGitignoreEntries(path10, entries) {
|
|
10123
10234
|
let current = "";
|
|
10124
|
-
if (
|
|
10235
|
+
if (existsSync10(path10)) {
|
|
10125
10236
|
current = readFileSync14(path10, "utf8");
|
|
10126
10237
|
}
|
|
10127
10238
|
const lines = current.split(/\r?\n/);
|
|
@@ -10650,7 +10761,7 @@ function describe23(e) {
|
|
|
10650
10761
|
}
|
|
10651
10762
|
|
|
10652
10763
|
// src/commands/plan.ts
|
|
10653
|
-
import { resolve as
|
|
10764
|
+
import { resolve as resolve11 } from "node:path";
|
|
10654
10765
|
var planCommand = {
|
|
10655
10766
|
name: "plan",
|
|
10656
10767
|
summary: "summarise what the manifest would deploy (offline)",
|
|
@@ -10663,7 +10774,7 @@ async function runPlan(args, io) {
|
|
|
10663
10774
|
io.err("Usage: launchpad plan [--file <path>] [--json]");
|
|
10664
10775
|
return 64;
|
|
10665
10776
|
}
|
|
10666
|
-
const manifestPath =
|
|
10777
|
+
const manifestPath = resolve11(process.cwd(), flags.file ?? "launchpad.yaml");
|
|
10667
10778
|
const result = loadManifest(manifestPath);
|
|
10668
10779
|
return flags.json ? renderJson(result, io) : renderHuman(result, io);
|
|
10669
10780
|
}
|
|
@@ -11253,12 +11364,12 @@ async function listFiles(root, relative5 = "") {
|
|
|
11253
11364
|
return files.sort();
|
|
11254
11365
|
}
|
|
11255
11366
|
function gitOutput(cwd, args) {
|
|
11256
|
-
return new Promise((
|
|
11367
|
+
return new Promise((resolve13, reject) => {
|
|
11257
11368
|
execFile("git", [...args], { cwd, encoding: "utf8" }, (error, stdout) => {
|
|
11258
11369
|
if (error !== null)
|
|
11259
11370
|
reject(error);
|
|
11260
11371
|
else
|
|
11261
|
-
|
|
11372
|
+
resolve13(stdout);
|
|
11262
11373
|
});
|
|
11263
11374
|
});
|
|
11264
11375
|
}
|
|
@@ -12193,7 +12304,7 @@ function describe26(e) {
|
|
|
12193
12304
|
}
|
|
12194
12305
|
|
|
12195
12306
|
// src/deploy/rollback.ts
|
|
12196
|
-
import { existsSync as
|
|
12307
|
+
import { existsSync as existsSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync5 } from "node:fs";
|
|
12197
12308
|
import { resolve as resolvePath3 } from "node:path";
|
|
12198
12309
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
12199
12310
|
|
|
@@ -12318,7 +12429,7 @@ async function runRollback(opts, io, deps = {}) {
|
|
|
12318
12429
|
}, io, applyDeps);
|
|
12319
12430
|
}
|
|
12320
12431
|
function readCurrentManifest(path14) {
|
|
12321
|
-
if (!
|
|
12432
|
+
if (!existsSync11(path14))
|
|
12322
12433
|
return null;
|
|
12323
12434
|
let raw;
|
|
12324
12435
|
try {
|
|
@@ -12478,7 +12589,7 @@ function parseArgs12(args) {
|
|
|
12478
12589
|
}
|
|
12479
12590
|
|
|
12480
12591
|
// src/secrets/push.ts
|
|
12481
|
-
import { existsSync as
|
|
12592
|
+
import { existsSync as existsSync12, readFileSync as readFileSync16 } from "node:fs";
|
|
12482
12593
|
import { resolve as resolvePath4 } from "node:path";
|
|
12483
12594
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
12484
12595
|
import { stdin as input2, stdout as output2 } from "node:process";
|
|
@@ -12535,7 +12646,7 @@ async function runSecretsPush(opts, io, deps = {}) {
|
|
|
12535
12646
|
return 0;
|
|
12536
12647
|
}
|
|
12537
12648
|
const envPath = resolvePath4(process.cwd(), opts.env ?? ".env");
|
|
12538
|
-
if (!
|
|
12649
|
+
if (!existsSync12(envPath)) {
|
|
12539
12650
|
io.err(`launchpad secrets push: ${envPath}`);
|
|
12540
12651
|
io.err(" .env file not found. Run `launchpad secrets template` to scaffold one.");
|
|
12541
12652
|
return 2;
|
|
@@ -12867,7 +12978,7 @@ function renderManifestError5(result, io) {
|
|
|
12867
12978
|
}
|
|
12868
12979
|
|
|
12869
12980
|
// src/secrets/set.ts
|
|
12870
|
-
import { existsSync as
|
|
12981
|
+
import { existsSync as existsSync13, readFileSync as readFileSync17 } from "node:fs";
|
|
12871
12982
|
import { resolve as resolvePath6 } from "node:path";
|
|
12872
12983
|
import { parse as parseYaml8 } from "yaml";
|
|
12873
12984
|
var CELL_LABEL2 = {
|
|
@@ -12877,7 +12988,7 @@ var CELL_LABEL2 = {
|
|
|
12877
12988
|
};
|
|
12878
12989
|
function loadSet(fleetFile, setName, io) {
|
|
12879
12990
|
const path14 = resolvePath6(process.cwd(), fleetFile ?? "fleet-secret-sets.yaml");
|
|
12880
|
-
if (!
|
|
12991
|
+
if (!existsSync13(path14)) {
|
|
12881
12992
|
io.err(`✗ ${path14}`);
|
|
12882
12993
|
io.err(" fleet-secret-sets.yaml not found. Run from the platform repo root or pass --fleet-file.");
|
|
12883
12994
|
return 2;
|
|
@@ -12969,7 +13080,7 @@ async function runSecretsPushSet(opts, io, deps = {}) {
|
|
|
12969
13080
|
if (typeof set === "number")
|
|
12970
13081
|
return set;
|
|
12971
13082
|
const envPath = resolvePath6(process.cwd(), opts.env ?? ".env");
|
|
12972
|
-
if (!
|
|
13083
|
+
if (!existsSync13(envPath)) {
|
|
12973
13084
|
io.err(`launchpad secrets push --set: ${envPath} not found.`);
|
|
12974
13085
|
io.err(` Create a .env carrying the set's secrets: ${set.secrets.join(", ")}`);
|
|
12975
13086
|
return 2;
|
|
@@ -13120,8 +13231,8 @@ function setPushExit(e) {
|
|
|
13120
13231
|
}
|
|
13121
13232
|
|
|
13122
13233
|
// src/commands/secrets-template.ts
|
|
13123
|
-
import { existsSync as
|
|
13124
|
-
import { resolve as
|
|
13234
|
+
import { existsSync as existsSync14, writeFileSync as writeFileSync6 } from "node:fs";
|
|
13235
|
+
import { resolve as resolve13 } from "node:path";
|
|
13125
13236
|
async function runSecretsTemplate(args, io) {
|
|
13126
13237
|
const flags = parseFlags4(args);
|
|
13127
13238
|
if (flags.kind === "usage-error") {
|
|
@@ -13129,7 +13240,7 @@ async function runSecretsTemplate(args, io) {
|
|
|
13129
13240
|
io.err("Usage: launchpad secrets template [--file <path>] [--out <path>] " + "[--stdout] [--force] [--include-platform-managed]");
|
|
13130
13241
|
return 64;
|
|
13131
13242
|
}
|
|
13132
|
-
const manifestPath =
|
|
13243
|
+
const manifestPath = resolve13(process.cwd(), flags.file ?? "launchpad.yaml");
|
|
13133
13244
|
const result = loadManifest(manifestPath);
|
|
13134
13245
|
const renderResult = renderManifest(result, io);
|
|
13135
13246
|
if (renderResult.kind !== "ok") {
|
|
@@ -13143,8 +13254,8 @@ async function runSecretsTemplate(args, io) {
|
|
|
13143
13254
|
}
|
|
13144
13255
|
return 0;
|
|
13145
13256
|
}
|
|
13146
|
-
const outPath =
|
|
13147
|
-
if (
|
|
13257
|
+
const outPath = resolve13(process.cwd(), flags.out);
|
|
13258
|
+
if (existsSync14(outPath) && !flags.force) {
|
|
13148
13259
|
io.err(`launchpad secrets template: ${outPath} already exists`);
|
|
13149
13260
|
io.err("Pass --force to overwrite, or --stdout to print without writing.");
|
|
13150
13261
|
return 64;
|
|
@@ -13440,8 +13551,8 @@ function printHelp3(io) {
|
|
|
13440
13551
|
|
|
13441
13552
|
// src/commands/skills.ts
|
|
13442
13553
|
import { fileURLToPath } from "node:url";
|
|
13443
|
-
import { dirname as dirname9, join as join15, resolve as
|
|
13444
|
-
import { promises as fs7, existsSync as
|
|
13554
|
+
import { dirname as dirname9, join as join15, resolve as resolve14 } from "node:path";
|
|
13555
|
+
import { promises as fs7, existsSync as existsSync15 } from "node:fs";
|
|
13445
13556
|
|
|
13446
13557
|
// src/skills-bundle.ts
|
|
13447
13558
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -13546,11 +13657,11 @@ function resolveInstallEnv() {
|
|
|
13546
13657
|
function defaultBundleDir() {
|
|
13547
13658
|
const here = dirname9(fileURLToPath(import.meta.url));
|
|
13548
13659
|
const candidates = [
|
|
13549
|
-
|
|
13550
|
-
|
|
13660
|
+
resolve14(here, "..", "skills"),
|
|
13661
|
+
resolve14(here, "..", "..", "skills")
|
|
13551
13662
|
];
|
|
13552
13663
|
for (const c of candidates) {
|
|
13553
|
-
if (
|
|
13664
|
+
if (existsSync15(join15(c, "launchpad-onboard", "SKILL.md"))) {
|
|
13554
13665
|
return c;
|
|
13555
13666
|
}
|
|
13556
13667
|
}
|
|
@@ -13659,7 +13770,7 @@ function describe29(e) {
|
|
|
13659
13770
|
import { execFile as execFile2, spawn as spawn5 } from "node:child_process";
|
|
13660
13771
|
import { promisify } from "node:util";
|
|
13661
13772
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
13662
|
-
import { dirname as dirname10, resolve as
|
|
13773
|
+
import { dirname as dirname10, resolve as resolve15, relative as relative5, isAbsolute as isAbsolute3, join as join16 } from "node:path";
|
|
13663
13774
|
import { homedir as homedir3, tmpdir } from "node:os";
|
|
13664
13775
|
import { readFileSync as readFileSync19, mkdtempSync, writeFileSync as writeFileSync7, rmSync as rmSync2 } from "node:fs";
|
|
13665
13776
|
|
|
@@ -13704,9 +13815,9 @@ async function startLoopback(state, timeoutMs) {
|
|
|
13704
13815
|
resolveCode(code);
|
|
13705
13816
|
}
|
|
13706
13817
|
});
|
|
13707
|
-
const bound = await new Promise((
|
|
13708
|
-
server.once("error", () =>
|
|
13709
|
-
server.listen(0, "127.0.0.1", () =>
|
|
13818
|
+
const bound = await new Promise((resolve15) => {
|
|
13819
|
+
server.once("error", () => resolve15(false));
|
|
13820
|
+
server.listen(0, "127.0.0.1", () => resolve15(true));
|
|
13710
13821
|
});
|
|
13711
13822
|
if (!bound)
|
|
13712
13823
|
return null;
|
|
@@ -13999,7 +14110,7 @@ function errStderr(e) {
|
|
|
13999
14110
|
return "";
|
|
14000
14111
|
}
|
|
14001
14112
|
async function detectPackageManager2() {
|
|
14002
|
-
const pkgRoot =
|
|
14113
|
+
const pkgRoot = resolve15(dirname10(fileURLToPath2(import.meta.url)), "..", "..");
|
|
14003
14114
|
const candidates = [];
|
|
14004
14115
|
const npmRoot = await pmRoot("npm");
|
|
14005
14116
|
if (npmRoot !== null)
|
|
@@ -14007,7 +14118,7 @@ async function detectPackageManager2() {
|
|
|
14007
14118
|
const pnpmRoot = await pmRoot("pnpm");
|
|
14008
14119
|
if (pnpmRoot !== null)
|
|
14009
14120
|
candidates.push(["pnpm", pnpmRoot]);
|
|
14010
|
-
candidates.push(["bun",
|
|
14121
|
+
candidates.push(["bun", resolve15(homedir3(), ".bun/install/global/node_modules")]);
|
|
14011
14122
|
const matches = candidates.filter(([, root]) => pathContains(root, pkgRoot));
|
|
14012
14123
|
return matches.length === 1 ? matches[0][0] : null;
|
|
14013
14124
|
}
|
|
@@ -14144,8 +14255,8 @@ function printHelp5(io) {
|
|
|
14144
14255
|
}
|
|
14145
14256
|
|
|
14146
14257
|
// src/commands/validate.ts
|
|
14147
|
-
import { existsSync as
|
|
14148
|
-
import { dirname as dirname11, resolve as
|
|
14258
|
+
import { existsSync as existsSync16, readFileSync as readFileSync20, readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
|
|
14259
|
+
import { dirname as dirname11, resolve as resolve16 } from "node:path";
|
|
14149
14260
|
var validateCommand = {
|
|
14150
14261
|
name: "validate",
|
|
14151
14262
|
summary: "validate launchpad.yaml against the v1alpha1 schema",
|
|
@@ -14159,7 +14270,7 @@ async function runValidate(args, io) {
|
|
|
14159
14270
|
return 64;
|
|
14160
14271
|
}
|
|
14161
14272
|
const { file, json, strictGroups } = parseResult;
|
|
14162
|
-
const path14 =
|
|
14273
|
+
const path14 = resolve16(process.cwd(), file ?? "launchpad.yaml");
|
|
14163
14274
|
const result = loadManifest(path14);
|
|
14164
14275
|
if (result.kind !== "ok") {
|
|
14165
14276
|
return json ? renderJsonError(result, io) : renderHumanError(result, io);
|
|
@@ -14206,8 +14317,8 @@ function checkStaticServeDir(manifestPath, manifest) {
|
|
|
14206
14317
|
];
|
|
14207
14318
|
}
|
|
14208
14319
|
const dir = dirname11(manifestPath);
|
|
14209
|
-
const abs =
|
|
14210
|
-
if (!
|
|
14320
|
+
const abs = resolve16(dir, serveDir);
|
|
14321
|
+
if (!existsSync16(abs)) {
|
|
14211
14322
|
return [
|
|
14212
14323
|
`static app serves '${serveDir}/' but that directory does not exist — nothing would be served. ` + `Create ${serveDir}/index.html (or run \`launchpad init\` to scaffold it).`
|
|
14213
14324
|
];
|
|
@@ -14232,7 +14343,7 @@ function checkStaticServeDir(manifestPath, manifest) {
|
|
|
14232
14343
|
`static app's served directory '${serveDir}/' is empty — the deploy would serve an empty site.`
|
|
14233
14344
|
];
|
|
14234
14345
|
}
|
|
14235
|
-
if (!
|
|
14346
|
+
if (!existsSync16(resolve16(abs, "index.html"))) {
|
|
14236
14347
|
return [
|
|
14237
14348
|
`static app's served directory '${serveDir}/' has no index.html — the deploy would serve a directory with no entrypoint.`
|
|
14238
14349
|
];
|
|
@@ -15103,7 +15214,7 @@ import { spawn as spawn6 } from "node:child_process";
|
|
|
15103
15214
|
import { homedir as homedir4 } from "node:os";
|
|
15104
15215
|
import { join as join17 } from "node:path";
|
|
15105
15216
|
import {
|
|
15106
|
-
existsSync as
|
|
15217
|
+
existsSync as existsSync17,
|
|
15107
15218
|
mkdirSync as mkdirSync4,
|
|
15108
15219
|
readFileSync as readFileSync21,
|
|
15109
15220
|
writeFileSync as writeFileSync8
|
|
@@ -15135,7 +15246,7 @@ function writeCache2(state) {
|
|
|
15135
15246
|
var SKILLS_HINT_MARKER = join17(homedir4(), ".launchpad", "skills-hint-shown");
|
|
15136
15247
|
function absentHintShown() {
|
|
15137
15248
|
try {
|
|
15138
|
-
return
|
|
15249
|
+
return existsSync17(SKILLS_HINT_MARKER);
|
|
15139
15250
|
} catch {
|
|
15140
15251
|
return false;
|
|
15141
15252
|
}
|
|
@@ -15246,7 +15357,7 @@ var refreshUpdateCacheCommand = {
|
|
|
15246
15357
|
import { spawn as spawn7 } from "node:child_process";
|
|
15247
15358
|
import { homedir as homedir5 } from "node:os";
|
|
15248
15359
|
import { join as join18 } from "node:path";
|
|
15249
|
-
import { existsSync as
|
|
15360
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync5, readFileSync as readFileSync22, writeFileSync as writeFileSync9 } from "node:fs";
|
|
15250
15361
|
import { randomUUID } from "node:crypto";
|
|
15251
15362
|
var INTERNAL_EMIT_VERB = "__emit-telemetry";
|
|
15252
15363
|
var POSTHOG_HOST = "https://us.i.posthog.com";
|
|
@@ -15400,7 +15511,7 @@ function telemetryNoticeLine() {
|
|
|
15400
15511
|
}
|
|
15401
15512
|
function firstRunNoticeShown() {
|
|
15402
15513
|
try {
|
|
15403
|
-
return
|
|
15514
|
+
return existsSync18(FIRST_RUN_MARKER);
|
|
15404
15515
|
} catch {
|
|
15405
15516
|
return false;
|
|
15406
15517
|
}
|
|
@@ -15642,6 +15753,12 @@ function makeReportCommand(kind, deps = realDeps5()) {
|
|
|
15642
15753
|
};
|
|
15643
15754
|
}
|
|
15644
15755
|
|
|
15756
|
+
// src/http/preflight.ts
|
|
15757
|
+
async function preflightMinimumCliVersion(config, fetcher = fetch) {
|
|
15758
|
+
const detachedFetcher = fetcher;
|
|
15759
|
+
await apiRaw(config, { method: "POST", path: "/cli/preflight" }, detachedFetcher);
|
|
15760
|
+
}
|
|
15761
|
+
|
|
15645
15762
|
// src/dispatcher.ts
|
|
15646
15763
|
var COMMANDS = [
|
|
15647
15764
|
loginCommand,
|
|
@@ -15681,7 +15798,7 @@ var COMMANDS = [
|
|
|
15681
15798
|
refreshUpdateCacheCommand,
|
|
15682
15799
|
emitTelemetryCommand
|
|
15683
15800
|
];
|
|
15684
|
-
async function dispatch(argv, io, commands = COMMANDS) {
|
|
15801
|
+
async function dispatch(argv, io, commands = COMMANDS, deps = {}) {
|
|
15685
15802
|
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
|
|
15686
15803
|
printHelp6(io, commands);
|
|
15687
15804
|
return 0;
|
|
@@ -15699,12 +15816,55 @@ async function dispatch(argv, io, commands = COMMANDS) {
|
|
|
15699
15816
|
io.err("Run `launchpad --help` for the list of available commands.");
|
|
15700
15817
|
return 64;
|
|
15701
15818
|
}
|
|
15819
|
+
const preflightExit = await runCliFloorPreflight(verb, rest, io, deps);
|
|
15820
|
+
if (preflightExit !== null)
|
|
15821
|
+
return preflightExit;
|
|
15702
15822
|
const code = await cmd.run(rest, io);
|
|
15703
15823
|
if (!cmd.hidden && verb !== "bug" && verb !== "feature") {
|
|
15704
15824
|
writeBreadcrumb(verb, code);
|
|
15705
15825
|
}
|
|
15706
15826
|
return code;
|
|
15707
15827
|
}
|
|
15828
|
+
async function runCliFloorPreflight(verb, args, io, deps) {
|
|
15829
|
+
if (!requiresCliFloorPreflight(verb, args))
|
|
15830
|
+
return null;
|
|
15831
|
+
try {
|
|
15832
|
+
const preflight = deps.preflight ?? preflightMinimumCliVersion;
|
|
15833
|
+
await preflight(loadConfig());
|
|
15834
|
+
return null;
|
|
15835
|
+
} catch (error) {
|
|
15836
|
+
if (error instanceof UpgradeRequiredError) {
|
|
15837
|
+
io.err(error.message);
|
|
15838
|
+
return EXIT_CLI_UPGRADE_REQUIRED;
|
|
15839
|
+
}
|
|
15840
|
+
io.err(`launchpad ${verb}: version preflight failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
15841
|
+
return 1;
|
|
15842
|
+
}
|
|
15843
|
+
}
|
|
15844
|
+
function requiresCliFloorPreflight(verb, args) {
|
|
15845
|
+
if (args.includes("--help") || args.includes("-h"))
|
|
15846
|
+
return false;
|
|
15847
|
+
if ([
|
|
15848
|
+
"create",
|
|
15849
|
+
"deploy",
|
|
15850
|
+
"redeploy",
|
|
15851
|
+
"merge",
|
|
15852
|
+
"destroy",
|
|
15853
|
+
"recover",
|
|
15854
|
+
"rollback",
|
|
15855
|
+
"grant-editor",
|
|
15856
|
+
"revoke-editor",
|
|
15857
|
+
"add-owner",
|
|
15858
|
+
"remove-owner"
|
|
15859
|
+
].includes(verb)) {
|
|
15860
|
+
return true;
|
|
15861
|
+
}
|
|
15862
|
+
if (verb === "envvars")
|
|
15863
|
+
return args[0] === "set" || args[0] === "rm";
|
|
15864
|
+
if (verb === "secrets")
|
|
15865
|
+
return args[0] === "push";
|
|
15866
|
+
return false;
|
|
15867
|
+
}
|
|
15708
15868
|
function printHelp6(io, commands) {
|
|
15709
15869
|
io.out("launchpad — manage Launchpad-deployed apps from the command line.");
|
|
15710
15870
|
io.out("");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAyEA,OAAO,EAGL,4BAA4B,EAC7B,MAAM,uBAAuB,CAAC;AAc/B,OAAO,EAAa,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,KAAK,EAAS,OAAO,EAAY,MAAM,kBAAkB,CAAC;AAKjE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;AAEjD,eAAO,MAAM,aAAa,EAAE,OAI3B,CAAC;AAEF,UAAU,UAAU;IAClB,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAoRD;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAoBpC;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,GAAG,IAAI,CAwBpE;AAiMD,2BAA2B;AAC3B,OAAO,EAAE,4BAA4B,EAAE,CAAC"}
|
|
@@ -3,23 +3,19 @@ export declare class GitFilesError extends Error {
|
|
|
3
3
|
readonly code: "git_files_error";
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* (see `PROTECTED_PATHS` in `portal-bot/src/deploy-pr.ts`). Mirrored
|
|
8
|
-
* here so the CLI excludes them up front rather than shipping a
|
|
9
|
-
* tarball the bot will reject.
|
|
6
|
+
* Legacy convenience filter for known bot-owned files.
|
|
10
7
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* Keep in lock-step with the bot's list. A future endpoint that
|
|
16
|
-
* exposes this list would let the CLI fetch it dynamically; for
|
|
17
|
-
* v1 the set is small and rarely changes.
|
|
8
|
+
* This list is not a security boundary and does not grant deletion
|
|
9
|
+
* authority. The server owns the canonical, family-based path policy
|
|
10
|
+
* and preserves platform files even when an older or newer client
|
|
11
|
+
* sends a different set.
|
|
18
12
|
*/
|
|
19
13
|
export declare const PROTECTED_PATHS: ReadonlySet<string>;
|
|
20
14
|
export interface ListFilesOptions {
|
|
21
15
|
readonly cwd: string;
|
|
22
16
|
readonly spawner?: typeof spawn;
|
|
17
|
+
/** Test seam for the worktree existence check. Receives an absolute path. */
|
|
18
|
+
readonly exists?: (path: string) => boolean;
|
|
23
19
|
}
|
|
24
20
|
/**
|
|
25
21
|
* Return the deploy-eligible file paths under `cwd`, relative to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-files.d.ts","sourceRoot":"","sources":["../../src/deploy/git-files.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"git-files.d.ts","sourceRoot":"","sources":["../../src/deploy/git-files.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAI9D,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAU;CAC5C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAU9C,CAAC;AAEH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IAChC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC7C;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CA4BxF"}
|
package/dist/dispatcher.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CliConfig } from "./config.js";
|
|
1
2
|
export interface CliIo {
|
|
2
3
|
/** Where regular CLI output goes (matches stdout). */
|
|
3
4
|
readonly out: (line: string) => void;
|
|
@@ -15,6 +16,9 @@ export interface Command {
|
|
|
15
16
|
*/
|
|
16
17
|
readonly hidden?: boolean;
|
|
17
18
|
}
|
|
19
|
+
export interface DispatchDeps {
|
|
20
|
+
readonly preflight?: (config: CliConfig) => Promise<void>;
|
|
21
|
+
}
|
|
18
22
|
/**
|
|
19
23
|
* Verb table. Each slice imports + appends its `Command` here.
|
|
20
24
|
* Keeping the registry as a const array (rather than a Map)
|
|
@@ -25,6 +29,6 @@ export declare const COMMANDS: readonly Command[];
|
|
|
25
29
|
* Top-level dispatcher. Returns an exit code; never calls
|
|
26
30
|
* `process.exit` itself (the bin wrapper does).
|
|
27
31
|
*/
|
|
28
|
-
export declare function dispatch(argv: readonly string[], io: CliIo, commands?: readonly Command[]): Promise<ExitCode>;
|
|
32
|
+
export declare function dispatch(argv: readonly string[], io: CliIo, commands?: readonly Command[], deps?: DispatchDeps): Promise<ExitCode>;
|
|
29
33
|
export declare function printHelp(io: CliIo, commands: readonly Command[]): void;
|
|
30
34
|
//# sourceMappingURL=dispatcher.d.ts.map
|
package/dist/dispatcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"AAyDA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAOzD,MAAM,WAAW,KAAK;IACpB,sDAAsD;IACtD,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,wCAAwC;IACxC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxE;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,OAAO,EAyCtC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,KAAK,EACT,QAAQ,GAAE,SAAS,OAAO,EAAa,EACvC,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,QAAQ,CAAC,CA4BnB;AAsDD,wBAAgB,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAyBvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/http/api-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/http/api-client.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAgB9C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD;;;;;;;OAOG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClD;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,CAAC,EAC7B,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,iBAAiB,EACvB,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,CAAC,CAAC,CAWZ;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAC1B,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,iBAAiB,EACvB,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,QAAQ,CAAC,CA6FnB"}
|
package/dist/http/errors.d.ts
CHANGED
|
@@ -15,6 +15,17 @@ export declare class ForbiddenError extends Error {
|
|
|
15
15
|
export declare class NotFoundError extends Error {
|
|
16
16
|
readonly code: "not_found";
|
|
17
17
|
}
|
|
18
|
+
/** Stable process exit used only for a server-enforced CLI upgrade. */
|
|
19
|
+
export declare const EXIT_CLI_UPGRADE_REQUIRED = 42;
|
|
20
|
+
/** HTTP 426 with the server's current minimum and the presented CLI version. */
|
|
21
|
+
export declare class UpgradeRequiredError extends Error {
|
|
22
|
+
readonly code: "cli_upgrade_required";
|
|
23
|
+
readonly minimum: string;
|
|
24
|
+
readonly yours: string;
|
|
25
|
+
constructor(minimum: string, yours: string);
|
|
26
|
+
}
|
|
27
|
+
/** Render the one-line recovery message shared by preflight and upload. */
|
|
28
|
+
export declare function upgradeRequiredMessage(minimum: string, yours: string): string;
|
|
18
29
|
import { type StructuredErrorEnvelope } from "./error-envelope.js";
|
|
19
30
|
/** Any other non-2xx. Carries the complete bounded structured envelope. */
|
|
20
31
|
export declare class ApiError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/http/errors.ts"],"names":[],"mappings":"AAIA;;2DAE2D;AAC3D,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAU;CAC5C;AAED;;uCAEuC;AACvC,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAG,WAAW,CAAU;CACtC;AAED;yEACyE;AACzE,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAG,WAAW,CAAU;CACtC;AAED,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAE7B,2EAA2E;AAC3E,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,SAAS,EAAG,WAAW,CAAU;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IACnD,QAAQ,CAAC,UAAU,EAAE,uBAAuB,CAAC,YAAY,CAAC,CAAC;IAC3D,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,uBAAuB,CAAC;gBAE/B,QAAQ,EAAE,uBAAuB;CAgB9C;AAED;2BAC2B;AAC3B,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAU;CAC5C"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/http/errors.ts"],"names":[],"mappings":"AAIA;;2DAE2D;AAC3D,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAU;CAC5C;AAED;;uCAEuC;AACvC,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAG,WAAW,CAAU;CACtC;AAED;yEACyE;AACzE,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAG,WAAW,CAAU;CACtC;AAED,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,gFAAgF;AAChF,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAG,sBAAsB,CAAU;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAM3C;AAED,2EAA2E;AAC3E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAE7B,2EAA2E;AAC3E,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,SAAS,EAAG,WAAW,CAAU;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IACnD,QAAQ,CAAC,UAAU,EAAE,uBAAuB,CAAC,YAAY,CAAC,CAAC;IAC3D,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,uBAAuB,CAAC;gBAE/B,QAAQ,EAAE,uBAAuB;CAgB9C;AAED;2BAC2B;AAC3B,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAU;CAC5C"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CliConfig } from "../config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Run the no-side-effect bot endpoint governed by the same floor as mutations.
|
|
4
|
+
* The injected fetcher is passed as a bare callable through `apiRaw`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function preflightMinimumCliVersion(config: CliConfig, fetcher?: typeof fetch): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=preflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../../src/http/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,IAAI,CAAC,CAOf"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Stable header used by Launchpad services to observe the real CLI version. */
|
|
2
|
+
export declare const CLI_VERSION_HEADER = "x-launchpad-cli-version";
|
|
3
|
+
/**
|
|
4
|
+
* Add the real CLI version to a Launchpad-controlled HTTP request.
|
|
5
|
+
*
|
|
6
|
+
* Caller-provided casing variants are removed so neither the version header
|
|
7
|
+
* nor the user-agent can be spoofed accidentally by a command-specific map.
|
|
8
|
+
*/
|
|
9
|
+
export declare function cliVersionHeaders(headers?: Readonly<Record<string, string>>): Record<string, string>;
|
|
10
|
+
//# sourceMappingURL=version-headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-headers.d.ts","sourceRoot":"","sources":["../../src/http/version-headers.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,4BAA4B,CAAC;AAE5D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,GAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWxB"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.
|
|
1
|
+
export declare const CLI_VERSION = "0.54.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m-kopa/launchpad-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.1",
|
|
4
4
|
"description": "Launchpad CLI — clone / deploy / review / merge against Launchpad-managed apps. Talks to the portal-bot endpoints (SCOPE-M-760 / T4).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
"directory": "packages/launchpad-cli"
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/M-KOPA/launchpad-platform/tree/main/packages/launchpad-cli#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/M-KOPA/launchpad-platform/issues"
|
|
31
|
+
},
|
|
29
32
|
"license": "UNLICENSED",
|
|
30
33
|
"dependencies": {
|
|
31
34
|
"esbuild": "0.28.1",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-content-pr
|
|
3
3
|
description: Push a content change to a Launchpad app via `launchpad deploy` and verify it shipped via `launchpad status`. Covers the post-first-deploy iteration loop (edit → deploy → verify) — subsequent deploys commit directly to the app repo's main and the Pages build runs asynchronously, so verification is its own step. Use when someone says "push a content change", "ship an update", "/launchpad-content-pr", "verify my deploy", or after `/launchpad-deploy` reports `done` and they want to follow up with an edit.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-deploy
|
|
3
3
|
description: Walk a Launchpad user through deploying an app from their local working directory (Model A — `launchpad init` + `launchpad deploy`). Wraps the CLI verbs end-to-end: detects the app shape, scaffolds `launchpad.yaml`, resolves the allowed Entra group via `launchpad groups`, bundles the CWD via `launchpad deploy`, and watches the rollout via `launchpad status`. Use when someone says "deploy a new app", "ship my app to Launchpad", "/launchpad-deploy", "I have an app locally — get it on Launchpad", or any variant. Resume/abandon for legacy in-flight provisioning is at the bottom.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-deploy-status
|
|
3
3
|
description: Show the current provisioning stage + failure reason for a Launchpad app via `launchpad status` (Model A drift + deployment_verified) and `launchpad apps` (lifecycle bucket), or watch provisioning live with `launchpad watch`. Renders the M-892 stage trace for in-flight provisioning, and is the canonical home for `launchpad recover` (repair a terminal-failed app record that is actually live). Use when someone says "what's the status of demo-X", "/launchpad-deploy-status", "is my deploy stuck", "watch my deploy go live", "watch provisioning", "my app says failed but it's serving", or after `/launchpad-deploy` reports a non-`done` terminal stage.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-destroy
|
|
3
3
|
description: Tear down a Launchpad app end-to-end via `launchpad destroy` — Cloudflare Pages project, edge-auth wiring (gateway KV/audience entries, or the Access app for `auth: access` apps), custom hostname, platform-repo TF, and the app repo (archive-renamed). Owner-only verb with a two-step destructive confirmation. Use when someone says "destroy this app", "/launchpad-destroy", "tear down `<slug>`", "delete the app", or asks to clean up a smoke-test / orphan / retired app.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-identity
|
|
3
3
|
description: Teach an app author how to use the signed-in user's identity inside a Launchpad app — read the gateway-forwarded X-Launchpad-User-Assertion in a Pages Function, VERIFY it with @m-kopa/platform-auth (fail-closed), and show who's logged in (sub/email/name). Use when someone says "who is logged in", "show the current user", "get the user's email in my app", "auth in my launchpad app", "read the user identity", "/launchpad-identity", or is wiring up an /api/me for a gateway-fronted app.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-onboard
|
|
3
3
|
description: One-time setup for the Launchpad CLI + Claude Code skill bundle. Verifies the `launchpad` CLI is installed and current, runs `launchpad whoami` to confirm the session is fresh, and checks the bundled skills are installed and in lock-step with the CLI. Idempotent — safe to re-run any time. Use when someone says "set me up for Launchpad", "I just got a new machine and want to use Launchpad", "/launchpad-onboard", or any of the other launchpad-* skills fails on a prereq check.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-report
|
|
3
3
|
description: File a bug report or feature request to the Launchpad team's tracker from the CLI. Use when someone reports something broken, hits an error in a launchpad command, or wishes a feature existed — e.g. "this is broken", "report a bug", "can you file that", "I wish launchpad could…", "/launchpad-bug", "/launchpad-feature". Always confirm and show exactly what you'll send before filing; never file silently.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-status
|
|
3
3
|
description: Safely refresh a Launchpad clone, show manifest drift, or read the deployed manifest. Wraps bare `launchpad pull` for source sync, `launchpad pull --manifest` for deployed YAML, and `launchpad status` for drift. Use for "sync my clone", "what's deployed", "show drift", "/launchpad-status", "/launchpad-pull", or post-deploy verification.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -378,4 +378,4 @@ CI.
|
|
|
378
378
|
|
|
379
379
|
## Version
|
|
380
380
|
|
|
381
|
-
This skill ships in launchpad-cli v0.
|
|
381
|
+
This skill ships in launchpad-cli v0.54.0+.
|