@m-kopa/launchpad-cli 0.61.1 → 0.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cli.js +282 -97
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/migrate.d.ts +3 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/dispatcher.d.ts.map +1 -1
- package/dist/http/api-client.d.ts.map +1 -1
- package/dist/http/errors.d.ts +3 -0
- package/dist/http/errors.d.ts.map +1 -1
- package/dist/manifest/migrate-dispatch.d.ts +4 -0
- package/dist/manifest/migrate-dispatch.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/skills/launchpad-content-pr/SKILL.md +1 -1
- package/skills/launchpad-deploy/SKILL.md +9 -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 +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,20 @@ pre-1.0 minor bumps may carry breaking changes per ADR 0005.
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 0.62.0 - 2026-09-17
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `launchpad migrate --origin dispatch` converts compatible, unprovisioned static and React apps to Workers without hand-editing v1 manifests.
|
|
16
|
+
It preserves access and application settings, keeps the original YAML, and refuses unsupported runtimes or an existing app record.
|
|
17
|
+
Failed writes clean up only the current attempt's files so migration can be retried.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Pages quota errors explain why the existing manifest still selects Pages and give the supported migration command.
|
|
22
|
+
Pages Functions apps get build-specific guidance instead of an unsafe origin-only edit.
|
|
23
|
+
- Deploy prints when the manifest selects Pages, so a CLI update is not mistaken for a runtime migration.
|
|
24
|
+
|
|
11
25
|
## 0.61.1 - 2026-09-17
|
|
12
26
|
|
|
13
27
|
### Fixed
|
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.62.0";
|
|
23
23
|
|
|
24
24
|
// src/config.ts
|
|
25
25
|
import { readFileSync } from "node:fs";
|
|
@@ -226,7 +226,12 @@ class ForbiddenError extends Error {
|
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
class NotFoundError extends Error {
|
|
229
|
+
serverCode;
|
|
229
230
|
code = "not_found";
|
|
231
|
+
constructor(message, serverCode) {
|
|
232
|
+
super(message);
|
|
233
|
+
this.serverCode = serverCode;
|
|
234
|
+
}
|
|
230
235
|
}
|
|
231
236
|
var EXIT_CLI_UPGRADE_REQUIRED = 42;
|
|
232
237
|
|
|
@@ -1148,8 +1153,9 @@ async function apiRaw(cfg, opts, fetcher = fetch) {
|
|
|
1148
1153
|
throw recordedFault(new ForbiddenError(`bot returned 403 for ${opts.path}: ${detail}`));
|
|
1149
1154
|
}
|
|
1150
1155
|
if (res.status === 404) {
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1156
|
+
const envelope = await readErrorEnvelope(res, opts.path);
|
|
1157
|
+
const detail = formatErrorEnvelope(envelope);
|
|
1158
|
+
throw recordedFault(new NotFoundError(`bot returned 404 for ${opts.path}: ${detail}`, envelope.code));
|
|
1153
1159
|
}
|
|
1154
1160
|
if (!res.ok) {
|
|
1155
1161
|
if (opts.nonThrowingStatuses?.includes(res.status) === true) {
|
|
@@ -9076,6 +9082,12 @@ async function runModelADeploy(args) {
|
|
|
9076
9082
|
return 64;
|
|
9077
9083
|
}
|
|
9078
9084
|
io.out(`Bundling ${cwd} for ${slug} (Model A) …`);
|
|
9085
|
+
if (declaredOrigin !== "dispatch" && appType !== "container") {
|
|
9086
|
+
io.out("Deployment target: Cloudflare Pages, selected by launchpad.yaml.");
|
|
9087
|
+
if (appType === "static" || appType === "react") {
|
|
9088
|
+
io.out("For an app that has never provisioned, `launchpad migrate --origin dispatch` checks whether it can use Workers without a Pages project.");
|
|
9089
|
+
}
|
|
9090
|
+
}
|
|
9079
9091
|
let cfg;
|
|
9080
9092
|
try {
|
|
9081
9093
|
cfg = loadConfig();
|
|
@@ -11828,6 +11840,178 @@ function describe25(e) {
|
|
|
11828
11840
|
return e instanceof Error ? e.message : String(e);
|
|
11829
11841
|
}
|
|
11830
11842
|
|
|
11843
|
+
// src/commands/migrate.ts
|
|
11844
|
+
import { closeSync, existsSync as existsSync11, lstatSync as lstatSync4, mkdirSync as mkdirSync4, mkdtempSync, openSync, readFileSync as readFileSync16, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
11845
|
+
import path12 from "node:path";
|
|
11846
|
+
import { stringify } from "yaml";
|
|
11847
|
+
|
|
11848
|
+
// src/manifest/migrate-dispatch.ts
|
|
11849
|
+
function dispatchManifest(manifest) {
|
|
11850
|
+
const v2 = manifest.apiVersion === "launchpad.m-kopa.us/v2";
|
|
11851
|
+
const source = v2 ? manifest.spec : manifest;
|
|
11852
|
+
const appType = v2 ? manifest.spec.appType : manifest.deployment.type;
|
|
11853
|
+
if (appType !== "static" && appType !== "react") {
|
|
11854
|
+
throw new Error("Only static and React apps can use this converter. Pages Functions (react+api) need a compiled Worker build before switching to dispatch; containers use their own runtime.");
|
|
11855
|
+
}
|
|
11856
|
+
if (source.secrets !== undefined || source.containers !== undefined) {
|
|
11857
|
+
throw new Error("Secret and container bindings cannot be converted automatically.");
|
|
11858
|
+
}
|
|
11859
|
+
if (!v2)
|
|
11860
|
+
assertConvertibleV1(manifest);
|
|
11861
|
+
const spec = v2 ? { ...manifest.spec } : {
|
|
11862
|
+
appType,
|
|
11863
|
+
display: {
|
|
11864
|
+
name: manifest.metadata.name,
|
|
11865
|
+
team: manifest.metadata.team,
|
|
11866
|
+
...manifest.metadata.description === undefined ? {} : { description: manifest.metadata.description }
|
|
11867
|
+
},
|
|
11868
|
+
owner: { email: manifest.metadata.owner },
|
|
11869
|
+
access: {
|
|
11870
|
+
audience: manifest.access.audience,
|
|
11871
|
+
private_owner: manifest.access.private_owner,
|
|
11872
|
+
allowed_entra_groups: [...allowedEntraGroups(manifest.access)],
|
|
11873
|
+
identity_types: manifest.access.identity_types
|
|
11874
|
+
},
|
|
11875
|
+
build: manifest.build,
|
|
11876
|
+
app: manifest.app,
|
|
11877
|
+
verify: manifest.verify,
|
|
11878
|
+
sensitive: manifest.sensitive,
|
|
11879
|
+
catalogue: manifest.catalogue,
|
|
11880
|
+
...manifest.production_env === undefined ? {} : {
|
|
11881
|
+
env_vars: Object.fromEntries(Object.entries(manifest.production_env).map(([name, value]) => [name, { type: "plain_text", value }]))
|
|
11882
|
+
}
|
|
11883
|
+
};
|
|
11884
|
+
const candidate = {
|
|
11885
|
+
apiVersion: "launchpad.m-kopa.us/v2",
|
|
11886
|
+
kind: "App",
|
|
11887
|
+
metadata: v2 ? manifest.metadata : { slug: manifest.metadata.name, schemaVersion: 2 },
|
|
11888
|
+
spec: { ...spec, origin: "dispatch", auth: "gateway", confine_origin: undefined }
|
|
11889
|
+
};
|
|
11890
|
+
const parsed = parseManifestV2(candidate);
|
|
11891
|
+
if (parsed.kind !== "ok") {
|
|
11892
|
+
throw new Error(`Cannot convert manifest: ${parsed.issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ")}`);
|
|
11893
|
+
}
|
|
11894
|
+
return parsed.manifest;
|
|
11895
|
+
}
|
|
11896
|
+
function assertConvertibleV1(manifest) {
|
|
11897
|
+
const unsupported2 = [
|
|
11898
|
+
manifest.hostnames !== undefined && "hostnames",
|
|
11899
|
+
manifest.targets !== undefined && "targets",
|
|
11900
|
+
manifest.access.session_duration !== undefined && "access.session_duration",
|
|
11901
|
+
manifest.deployment.runtime !== undefined && "deployment.runtime"
|
|
11902
|
+
].filter(Boolean);
|
|
11903
|
+
if (unsupported2.length > 0) {
|
|
11904
|
+
throw new Error(`Cannot preserve ${unsupported2.join(", ")} on dispatch. Review these settings with the platform team before migrating.`);
|
|
11905
|
+
}
|
|
11906
|
+
}
|
|
11907
|
+
|
|
11908
|
+
// src/commands/migrate.ts
|
|
11909
|
+
var USAGE = "usage: launchpad migrate --origin dispatch [--dry-run]";
|
|
11910
|
+
var migrateCommand = {
|
|
11911
|
+
name: "migrate",
|
|
11912
|
+
summary: "convert an unprovisioned static or React app to Workers dispatch",
|
|
11913
|
+
run: runMigrate
|
|
11914
|
+
};
|
|
11915
|
+
async function runMigrate(args, io) {
|
|
11916
|
+
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
11917
|
+
io.out(USAGE);
|
|
11918
|
+
return 0;
|
|
11919
|
+
}
|
|
11920
|
+
const flags = args.filter((arg) => arg !== "--dry-run");
|
|
11921
|
+
if (flags.length !== 2 || flags[0] !== "--origin" || flags[1] !== "dispatch" || args.length > 3) {
|
|
11922
|
+
io.err(USAGE);
|
|
11923
|
+
return 64;
|
|
11924
|
+
}
|
|
11925
|
+
const cwd = process.cwd();
|
|
11926
|
+
const file = path12.join(cwd, "launchpad.yaml");
|
|
11927
|
+
try {
|
|
11928
|
+
if (!lstatSync4(file).isFile())
|
|
11929
|
+
throw new Error("launchpad.yaml must be a regular file, not a symlink.");
|
|
11930
|
+
const original = readFileSync16(file, "utf8");
|
|
11931
|
+
const loaded = parseManifestAnyVersion(original, file);
|
|
11932
|
+
if (loaded.kind !== "ok")
|
|
11933
|
+
throw new Error("launchpad.yaml is invalid. Run `launchpad validate` and correct it first.");
|
|
11934
|
+
const manifest = loaded.manifest;
|
|
11935
|
+
if (manifest.apiVersion === "launchpad.m-kopa.us/v2" && manifest.spec.origin === "dispatch") {
|
|
11936
|
+
io.out("launchpad.yaml already selects Workers dispatch. Run `launchpad deploy`.");
|
|
11937
|
+
return 0;
|
|
11938
|
+
}
|
|
11939
|
+
const converted = dispatchManifest(manifest);
|
|
11940
|
+
assertNoCustomRuntime(cwd, converted);
|
|
11941
|
+
const slug = converted.metadata.slug;
|
|
11942
|
+
await assertUnregistered(slug);
|
|
11943
|
+
if (args.includes("--dry-run")) {
|
|
11944
|
+
io.out(`${slug}: eligible for v2 Workers dispatch with gateway authentication. No files changed.`);
|
|
11945
|
+
return 0;
|
|
11946
|
+
}
|
|
11947
|
+
saveMigration(file, original, converted);
|
|
11948
|
+
io.out(`${slug}: launchpad.yaml now uses v2 Workers dispatch with gateway authentication.`);
|
|
11949
|
+
io.out("Audience, owner and application settings are preserved. Original: .launchpad/manifest-before-dispatch.yaml");
|
|
11950
|
+
io.out("Run `launchpad deploy`. No Pages project is needed.");
|
|
11951
|
+
return 0;
|
|
11952
|
+
} catch (error) {
|
|
11953
|
+
io.err(`launchpad migrate: ${error instanceof Error ? error.message : String(error)}`);
|
|
11954
|
+
return 1;
|
|
11955
|
+
}
|
|
11956
|
+
}
|
|
11957
|
+
async function assertUnregistered(slug) {
|
|
11958
|
+
try {
|
|
11959
|
+
await apiRaw(loadConfig(), { path: `/apps/${encodeURIComponent(slug)}/manifest/state` });
|
|
11960
|
+
} catch (error) {
|
|
11961
|
+
if (error instanceof NotFoundError && error.serverCode === "not_found")
|
|
11962
|
+
return;
|
|
11963
|
+
throw error;
|
|
11964
|
+
}
|
|
11965
|
+
throw new Error("This app is already registered. This command only converts apps that have never provisioned; ask the platform team to migrate an existing app.");
|
|
11966
|
+
}
|
|
11967
|
+
function assertNoCustomRuntime(cwd, manifest) {
|
|
11968
|
+
const appRoot = path12.resolve(cwd, manifest.spec.app?.root ?? ".");
|
|
11969
|
+
const buildRoot = path12.resolve(appRoot, manifest.spec.build?.root_dir ?? ".");
|
|
11970
|
+
const roots = new Set([
|
|
11971
|
+
cwd,
|
|
11972
|
+
appRoot,
|
|
11973
|
+
buildRoot,
|
|
11974
|
+
path12.resolve(cwd, manifest.spec.build?.root_dir ?? "."),
|
|
11975
|
+
path12.resolve(buildRoot, manifest.spec.build?.destination_dir ?? "dist")
|
|
11976
|
+
]);
|
|
11977
|
+
for (const root of roots) {
|
|
11978
|
+
for (const name of ["functions", "_worker.js", "wrangler.toml", "wrangler.json", "wrangler.jsonc"]) {
|
|
11979
|
+
if (existsSync11(path12.join(root, name))) {
|
|
11980
|
+
throw new Error(`${name} needs a runtime review before conversion. Pages Functions and custom Worker bindings must not be dropped. Ask the platform team to review this app.`);
|
|
11981
|
+
}
|
|
11982
|
+
}
|
|
11983
|
+
}
|
|
11984
|
+
}
|
|
11985
|
+
function saveMigration(file, original, converted) {
|
|
11986
|
+
if (readFileSync16(file, "utf8") !== original)
|
|
11987
|
+
throw new Error("launchpad.yaml changed during the check. Retry migration.");
|
|
11988
|
+
const backupDir = path12.join(path12.dirname(file), ".launchpad");
|
|
11989
|
+
mkdirSync4(backupDir, { recursive: true });
|
|
11990
|
+
const backup = path12.join(backupDir, "manifest-before-dispatch.yaml");
|
|
11991
|
+
const attemptDir = mkdtempSync(path12.join(backupDir, "migration-"));
|
|
11992
|
+
let backupCreated = false;
|
|
11993
|
+
try {
|
|
11994
|
+
const fd = openSync(backup, "wx", 384);
|
|
11995
|
+
backupCreated = true;
|
|
11996
|
+
try {
|
|
11997
|
+
writeFileSync4(fd, original);
|
|
11998
|
+
} finally {
|
|
11999
|
+
closeSync(fd);
|
|
12000
|
+
}
|
|
12001
|
+
const temporary = path12.join(attemptDir, "launchpad.yaml");
|
|
12002
|
+
writeFileSync4(temporary, stringify(converted), { flag: "wx", mode: 384 });
|
|
12003
|
+
if (readFileSync16(file, "utf8") !== original)
|
|
12004
|
+
throw new Error("launchpad.yaml changed during migration. Retry migration.");
|
|
12005
|
+
renameSync(temporary, file);
|
|
12006
|
+
} catch (error) {
|
|
12007
|
+
if (backupCreated)
|
|
12008
|
+
rmSync2(backup);
|
|
12009
|
+
throw error;
|
|
12010
|
+
} finally {
|
|
12011
|
+
rmSync2(attemptDir, { recursive: true, force: true });
|
|
12012
|
+
}
|
|
12013
|
+
}
|
|
12014
|
+
|
|
11831
12015
|
// src/commands/plan.ts
|
|
11832
12016
|
import { resolve as resolve12 } from "node:path";
|
|
11833
12017
|
var planCommand = {
|
|
@@ -12292,18 +12476,18 @@ function describe26(e) {
|
|
|
12292
12476
|
}
|
|
12293
12477
|
|
|
12294
12478
|
// src/commands/pull.ts
|
|
12295
|
-
import { writeFileSync as
|
|
12479
|
+
import { writeFileSync as writeFileSync5 } from "node:fs";
|
|
12296
12480
|
import { stringify as stringifyYaml } from "yaml";
|
|
12297
12481
|
|
|
12298
12482
|
// src/deploy/manifest-status.ts
|
|
12299
12483
|
async function fetchManifestStatus(cfg, slug, fetcher = fetch) {
|
|
12300
|
-
const
|
|
12301
|
-
return apiJson(cfg, { path:
|
|
12484
|
+
const path13 = `/apps/${encodeURIComponent(slug)}/manifest/status`;
|
|
12485
|
+
return apiJson(cfg, { path: path13 }, fetcher);
|
|
12302
12486
|
}
|
|
12303
12487
|
|
|
12304
12488
|
// src/pull/source-sync.ts
|
|
12305
12489
|
import * as fs6 from "node:fs/promises";
|
|
12306
|
-
import * as
|
|
12490
|
+
import * as path13 from "node:path";
|
|
12307
12491
|
import { constants as fsConstants } from "node:fs";
|
|
12308
12492
|
import { createHash as createHash3 } from "node:crypto";
|
|
12309
12493
|
import { execFile } from "node:child_process";
|
|
@@ -12342,9 +12526,9 @@ async function runSourceSync(args) {
|
|
|
12342
12526
|
args.io.out(`Already current at ${compare.headSha.slice(0, 12)}.`);
|
|
12343
12527
|
return 0;
|
|
12344
12528
|
}
|
|
12345
|
-
const stageRoot =
|
|
12346
|
-
const baseDir =
|
|
12347
|
-
const headDir =
|
|
12529
|
+
const stageRoot = path13.resolve(args.cwd, MARKER_DIR, `pull-stage-${process.pid}-${crypto.randomUUID()}`);
|
|
12530
|
+
const baseDir = path13.join(stageRoot, "base");
|
|
12531
|
+
const headDir = path13.join(stageRoot, "head");
|
|
12348
12532
|
await fs6.mkdir(baseDir, { recursive: true });
|
|
12349
12533
|
await fs6.mkdir(headDir, { recursive: true });
|
|
12350
12534
|
try {
|
|
@@ -12396,7 +12580,7 @@ async function bootstrapProvenance(args) {
|
|
|
12396
12580
|
args.io.err(" Preserve this directory and obtain a separate current clone for comparison.");
|
|
12397
12581
|
return 1;
|
|
12398
12582
|
}
|
|
12399
|
-
const stageRoot =
|
|
12583
|
+
const stageRoot = path13.resolve(args.cwd, MARKER_DIR, `pull-bootstrap-${process.pid}-${crypto.randomUUID()}`);
|
|
12400
12584
|
await fs6.mkdir(stageRoot, { recursive: true });
|
|
12401
12585
|
try {
|
|
12402
12586
|
const headSha = await fetchSnapshotRef(args.cfg, args.slug, "main", stageRoot);
|
|
@@ -12422,7 +12606,7 @@ async function treesEqual(cwd, tracked, headDir, headPaths) {
|
|
|
12422
12606
|
for (const relative6 of tracked) {
|
|
12423
12607
|
if (!expected.has(relative6))
|
|
12424
12608
|
return false;
|
|
12425
|
-
if (!equal(await readEntry(
|
|
12609
|
+
if (!equal(await readEntry(path13.resolve(cwd, relative6)), await readEntry(path13.resolve(headDir, relative6)))) {
|
|
12426
12610
|
return false;
|
|
12427
12611
|
}
|
|
12428
12612
|
}
|
|
@@ -12430,7 +12614,7 @@ async function treesEqual(cwd, tracked, headDir, headPaths) {
|
|
|
12430
12614
|
}
|
|
12431
12615
|
async function listFiles(root, relative6 = "") {
|
|
12432
12616
|
const files = [];
|
|
12433
|
-
const entries = await fs6.readdir(
|
|
12617
|
+
const entries = await fs6.readdir(path13.resolve(root, relative6), {
|
|
12434
12618
|
withFileTypes: true
|
|
12435
12619
|
});
|
|
12436
12620
|
for (const entry of entries) {
|
|
@@ -12506,7 +12690,7 @@ async function cleanAncestorRemovals(args) {
|
|
|
12506
12690
|
const checked = await checkParents(args.cwd, relative6, removals);
|
|
12507
12691
|
if (checked.kind === "blocked")
|
|
12508
12692
|
continue;
|
|
12509
|
-
const base = await readEntry(
|
|
12693
|
+
const base = await readEntry(path13.resolve(args.baseDir, relative6));
|
|
12510
12694
|
const local = checked.projectedMissing ? { kind: "missing" } : await readEntry(checked.target);
|
|
12511
12695
|
if (local.kind !== "missing" && cleanLocal(base, local))
|
|
12512
12696
|
removals.add(relative6);
|
|
@@ -12516,9 +12700,9 @@ async function cleanAncestorRemovals(args) {
|
|
|
12516
12700
|
async function planPath(args, relative6, removals) {
|
|
12517
12701
|
assertSafePath(relative6);
|
|
12518
12702
|
const checked = await checkParents(args.cwd, relative6, removals);
|
|
12519
|
-
const base = await readEntry(
|
|
12703
|
+
const base = await readEntry(path13.resolve(args.baseDir, relative6));
|
|
12520
12704
|
const upstreamDeleted = args.compare.deleted.includes(relative6);
|
|
12521
|
-
const head = upstreamDeleted ? { kind: "missing" } : await readEntry(
|
|
12705
|
+
const head = upstreamDeleted ? { kind: "missing" } : await readEntry(path13.resolve(args.headDir, relative6));
|
|
12522
12706
|
const unsupported2 = (args.compare.unsupported ?? []).includes(relative6);
|
|
12523
12707
|
if (checked.kind === "blocked") {
|
|
12524
12708
|
return conflictPlan(relative6, checked.target, { kind: "missing" }, head, upstreamDeleted, checked.reason);
|
|
@@ -12655,7 +12839,7 @@ async function writeAtomic(cwd, relative6, bytes, mode, allowMetadata = false) {
|
|
|
12655
12839
|
if (checked.kind === "blocked")
|
|
12656
12840
|
throw new Error(checked.reason);
|
|
12657
12841
|
const file = checked.target;
|
|
12658
|
-
await fs6.mkdir(
|
|
12842
|
+
await fs6.mkdir(path13.dirname(file), { recursive: true });
|
|
12659
12843
|
const rechecked = await checkParents(cwd, relative6, new Set, allowMetadata);
|
|
12660
12844
|
if (rechecked.kind === "blocked")
|
|
12661
12845
|
throw new Error(rechecked.reason);
|
|
@@ -12697,14 +12881,14 @@ function isSafeSourcePath(relative6) {
|
|
|
12697
12881
|
return isSafeRelativePath(relative6) && !relative6.startsWith(`${MARKER_DIR}/`);
|
|
12698
12882
|
}
|
|
12699
12883
|
function isSafeRelativePath(relative6) {
|
|
12700
|
-
const normalized =
|
|
12701
|
-
return relative6.length > 0 && !relative6.includes("\\") && !
|
|
12884
|
+
const normalized = path13.posix.normalize(relative6);
|
|
12885
|
+
return relative6.length > 0 && !relative6.includes("\\") && !path13.isAbsolute(relative6) && normalized === relative6 && normalized !== ".." && !normalized.startsWith("../");
|
|
12702
12886
|
}
|
|
12703
12887
|
function resolveInsideClone(cwd, relative6) {
|
|
12704
|
-
const root =
|
|
12705
|
-
const target =
|
|
12706
|
-
const fromRoot =
|
|
12707
|
-
if (fromRoot.length === 0 ||
|
|
12888
|
+
const root = path13.resolve(cwd);
|
|
12889
|
+
const target = path13.resolve(root, relative6);
|
|
12890
|
+
const fromRoot = path13.relative(root, target);
|
|
12891
|
+
if (fromRoot.length === 0 || path13.isAbsolute(fromRoot) || fromRoot === ".." || fromRoot.startsWith(`..${path13.sep}`)) {
|
|
12708
12892
|
throw new Error(`unsafe source path returned by bot: ${relative6}`);
|
|
12709
12893
|
}
|
|
12710
12894
|
return target;
|
|
@@ -12719,9 +12903,9 @@ async function checkParents(cwd, relative6, projectedRemovals, allowMetadata = f
|
|
|
12719
12903
|
}
|
|
12720
12904
|
const target = resolveInsideClone(cwd, relative6);
|
|
12721
12905
|
const components = relative6.split("/");
|
|
12722
|
-
let current =
|
|
12906
|
+
let current = path13.resolve(cwd);
|
|
12723
12907
|
for (let index = 0;index < components.length - 1; index += 1) {
|
|
12724
|
-
current =
|
|
12908
|
+
current = path13.join(current, components[index]);
|
|
12725
12909
|
const ancestor = components.slice(0, index + 1).join("/");
|
|
12726
12910
|
const stat = await lstatIfPresent(current);
|
|
12727
12911
|
if (stat === null)
|
|
@@ -12747,12 +12931,12 @@ async function checkParents(cwd, relative6, projectedRemovals, allowMetadata = f
|
|
|
12747
12931
|
return { kind: "safe", target, projectedMissing: false };
|
|
12748
12932
|
}
|
|
12749
12933
|
async function assertSafeCloneRoot(cwd) {
|
|
12750
|
-
const root = await fs6.lstat(
|
|
12934
|
+
const root = await fs6.lstat(path13.resolve(cwd));
|
|
12751
12935
|
if (!root.isDirectory() || root.isSymbolicLink()) {
|
|
12752
12936
|
throw new Error("launchpad pull requires a real clone directory");
|
|
12753
12937
|
}
|
|
12754
12938
|
try {
|
|
12755
|
-
const metadata = await fs6.lstat(
|
|
12939
|
+
const metadata = await fs6.lstat(path13.resolve(cwd, MARKER_DIR));
|
|
12756
12940
|
if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
12757
12941
|
throw new Error("launchpad pull refuses a non-directory or symlinked .launchpad path");
|
|
12758
12942
|
}
|
|
@@ -12808,7 +12992,7 @@ async function runPull(args, io) {
|
|
|
12808
12992
|
}
|
|
12809
12993
|
const yaml = stringifyYaml(res.status);
|
|
12810
12994
|
if (parsed.out !== null) {
|
|
12811
|
-
|
|
12995
|
+
writeFileSync5(parsed.out, yaml);
|
|
12812
12996
|
io.err(`launchpad pull: wrote status (${res.role} view) to ${parsed.out}`);
|
|
12813
12997
|
} else {
|
|
12814
12998
|
io.out(yaml.replace(/\n$/, ""));
|
|
@@ -12829,7 +13013,7 @@ async function runPull(args, io) {
|
|
|
12829
13013
|
return 1;
|
|
12830
13014
|
}
|
|
12831
13015
|
if (parsed.out !== null) {
|
|
12832
|
-
|
|
13016
|
+
writeFileSync5(parsed.out, state.manifestYaml);
|
|
12833
13017
|
io.err(`launchpad pull: wrote ${state.manifestYaml.length} bytes to ${parsed.out}`);
|
|
12834
13018
|
} else {
|
|
12835
13019
|
io.out(state.manifestYaml.replace(/\n$/, ""));
|
|
@@ -13230,7 +13414,7 @@ var watchCommand = {
|
|
|
13230
13414
|
};
|
|
13231
13415
|
|
|
13232
13416
|
// src/commands/review.ts
|
|
13233
|
-
import * as
|
|
13417
|
+
import * as path14 from "node:path";
|
|
13234
13418
|
var reviewCommand = {
|
|
13235
13419
|
name: "review",
|
|
13236
13420
|
summary: "show the review state for a PR (slug-scoped)",
|
|
@@ -13250,7 +13434,7 @@ async function runReview(args, io) {
|
|
|
13250
13434
|
} else {
|
|
13251
13435
|
const inferred = inferSlug({ cwd: process.cwd(), warn: (l) => io.err(l) });
|
|
13252
13436
|
if (inferred === null) {
|
|
13253
|
-
io.err(`launchpad review: could not infer slug from cwd (${
|
|
13437
|
+
io.err(`launchpad review: could not infer slug from cwd (${path14.basename(process.cwd())});
|
|
13254
13438
|
` + ` pass --slug <slug>, or cd into a directory named launchpad-app-<slug>.`);
|
|
13255
13439
|
return 64;
|
|
13256
13440
|
}
|
|
@@ -13383,7 +13567,7 @@ function describe28(e) {
|
|
|
13383
13567
|
}
|
|
13384
13568
|
|
|
13385
13569
|
// src/deploy/rollback.ts
|
|
13386
|
-
import { existsSync as
|
|
13570
|
+
import { existsSync as existsSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "node:fs";
|
|
13387
13571
|
import { resolve as resolvePath3 } from "node:path";
|
|
13388
13572
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
13389
13573
|
|
|
@@ -13485,7 +13669,7 @@ async function runRollback(opts, io, deps = {}) {
|
|
|
13485
13669
|
}
|
|
13486
13670
|
}
|
|
13487
13671
|
try {
|
|
13488
|
-
|
|
13672
|
+
writeFileSync6(manifestPath, historicalYaml, "utf8");
|
|
13489
13673
|
} catch (e) {
|
|
13490
13674
|
io.err(`launchpad rollback: failed to write ${manifestPath}: ${describe29(e)}`);
|
|
13491
13675
|
return 2;
|
|
@@ -13507,16 +13691,16 @@ async function runRollback(opts, io, deps = {}) {
|
|
|
13507
13691
|
yes: true
|
|
13508
13692
|
}, io, applyDeps);
|
|
13509
13693
|
}
|
|
13510
|
-
function readCurrentManifest(
|
|
13511
|
-
if (!
|
|
13694
|
+
function readCurrentManifest(path15) {
|
|
13695
|
+
if (!existsSync12(path15))
|
|
13512
13696
|
return null;
|
|
13513
13697
|
let raw;
|
|
13514
13698
|
try {
|
|
13515
|
-
raw =
|
|
13699
|
+
raw = readFileSync17(path15, "utf8");
|
|
13516
13700
|
} catch {
|
|
13517
13701
|
return null;
|
|
13518
13702
|
}
|
|
13519
|
-
const parsed = parseManifest2(raw,
|
|
13703
|
+
const parsed = parseManifest2(raw, path15);
|
|
13520
13704
|
if (parsed.kind !== "ok")
|
|
13521
13705
|
return null;
|
|
13522
13706
|
return summarise(parsed.manifest);
|
|
@@ -13668,7 +13852,7 @@ function parseArgs12(args) {
|
|
|
13668
13852
|
}
|
|
13669
13853
|
|
|
13670
13854
|
// src/secrets/push.ts
|
|
13671
|
-
import { existsSync as
|
|
13855
|
+
import { existsSync as existsSync13, readFileSync as readFileSync18 } from "node:fs";
|
|
13672
13856
|
import { resolve as resolvePath4 } from "node:path";
|
|
13673
13857
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
13674
13858
|
import { stdin as input2, stdout as output2 } from "node:process";
|
|
@@ -13729,14 +13913,14 @@ async function runSecretsPush(opts, io, deps = {}) {
|
|
|
13729
13913
|
return 0;
|
|
13730
13914
|
}
|
|
13731
13915
|
const envPath = resolvePath4(process.cwd(), opts.env ?? ".env");
|
|
13732
|
-
if (!
|
|
13916
|
+
if (!existsSync13(envPath)) {
|
|
13733
13917
|
io.err(`launchpad secrets push: ${envPath}`);
|
|
13734
13918
|
io.err(" .env file not found. Run `launchpad secrets template` to scaffold one.");
|
|
13735
13919
|
return 2;
|
|
13736
13920
|
}
|
|
13737
13921
|
let envText;
|
|
13738
13922
|
try {
|
|
13739
|
-
envText =
|
|
13923
|
+
envText = readFileSync18(envPath, "utf8");
|
|
13740
13924
|
} catch (e) {
|
|
13741
13925
|
io.err(`launchpad secrets push: failed to read ${envPath}: ${describe30(e)}`);
|
|
13742
13926
|
return 2;
|
|
@@ -14079,7 +14263,7 @@ function renderManifestError5(result, io) {
|
|
|
14079
14263
|
}
|
|
14080
14264
|
|
|
14081
14265
|
// src/secrets/set.ts
|
|
14082
|
-
import { existsSync as
|
|
14266
|
+
import { existsSync as existsSync14, readFileSync as readFileSync19 } from "node:fs";
|
|
14083
14267
|
import { resolve as resolvePath6 } from "node:path";
|
|
14084
14268
|
import { parse as parseYaml8 } from "yaml";
|
|
14085
14269
|
var CELL_LABEL2 = {
|
|
@@ -14088,23 +14272,23 @@ var CELL_LABEL2 = {
|
|
|
14088
14272
|
not_deployed: "NOT_DEPLOYED"
|
|
14089
14273
|
};
|
|
14090
14274
|
function loadSet(fleetFile, setName, io) {
|
|
14091
|
-
const
|
|
14092
|
-
if (!
|
|
14093
|
-
io.err(`✗ ${
|
|
14275
|
+
const path15 = resolvePath6(process.cwd(), fleetFile ?? "fleet-secret-sets.yaml");
|
|
14276
|
+
if (!existsSync14(path15)) {
|
|
14277
|
+
io.err(`✗ ${path15}`);
|
|
14094
14278
|
io.err(" fleet-secret-sets.yaml not found. Run from the platform repo root or pass --fleet-file.");
|
|
14095
14279
|
return 2;
|
|
14096
14280
|
}
|
|
14097
14281
|
let obj;
|
|
14098
14282
|
try {
|
|
14099
|
-
obj = parseYaml8(
|
|
14283
|
+
obj = parseYaml8(readFileSync19(path15, "utf8"));
|
|
14100
14284
|
} catch (e) {
|
|
14101
|
-
io.err(`✗ ${
|
|
14285
|
+
io.err(`✗ ${path15}`);
|
|
14102
14286
|
io.err(` YAML parse error: ${e instanceof Error ? e.message : String(e)}`);
|
|
14103
14287
|
return 1;
|
|
14104
14288
|
}
|
|
14105
14289
|
const parsed = parseFleetSecretSets(obj);
|
|
14106
14290
|
if (!parsed.ok) {
|
|
14107
|
-
io.err(`✗ ${
|
|
14291
|
+
io.err(`✗ ${path15}`);
|
|
14108
14292
|
io.err(` ${parsed.issues.length} schema issue(s):`);
|
|
14109
14293
|
for (const i of parsed.issues)
|
|
14110
14294
|
io.err(` ${i.path}: ${i.message}`);
|
|
@@ -14113,7 +14297,7 @@ function loadSet(fleetFile, setName, io) {
|
|
|
14113
14297
|
const set = parsed.manifest.secretSets.find((s) => s.name === setName);
|
|
14114
14298
|
if (set === undefined) {
|
|
14115
14299
|
const names = parsed.manifest.secretSets.map((s) => s.name).join(", ");
|
|
14116
|
-
io.err(`✗ secret-set "${setName}" not found in ${
|
|
14300
|
+
io.err(`✗ secret-set "${setName}" not found in ${path15}`);
|
|
14117
14301
|
io.err(` declared sets: ${names}`);
|
|
14118
14302
|
return 1;
|
|
14119
14303
|
}
|
|
@@ -14181,14 +14365,14 @@ async function runSecretsPushSet(opts, io, deps = {}) {
|
|
|
14181
14365
|
if (typeof set === "number")
|
|
14182
14366
|
return set;
|
|
14183
14367
|
const envPath = resolvePath6(process.cwd(), opts.env ?? ".env");
|
|
14184
|
-
if (!
|
|
14368
|
+
if (!existsSync14(envPath)) {
|
|
14185
14369
|
io.err(`launchpad secrets push --set: ${envPath} not found.`);
|
|
14186
14370
|
io.err(` Create a .env carrying the set's secrets: ${set.secrets.join(", ")}`);
|
|
14187
14371
|
return 2;
|
|
14188
14372
|
}
|
|
14189
14373
|
let envText;
|
|
14190
14374
|
try {
|
|
14191
|
-
envText =
|
|
14375
|
+
envText = readFileSync19(envPath, "utf8");
|
|
14192
14376
|
} catch (e) {
|
|
14193
14377
|
io.err(`launchpad secrets push --set: failed to read ${envPath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
14194
14378
|
return 2;
|
|
@@ -14332,7 +14516,7 @@ function setPushExit(e) {
|
|
|
14332
14516
|
}
|
|
14333
14517
|
|
|
14334
14518
|
// src/commands/secrets-template.ts
|
|
14335
|
-
import { existsSync as
|
|
14519
|
+
import { existsSync as existsSync15, writeFileSync as writeFileSync7 } from "node:fs";
|
|
14336
14520
|
import { resolve as resolve14 } from "node:path";
|
|
14337
14521
|
async function runSecretsTemplate(args, io) {
|
|
14338
14522
|
const flags = parseFlags4(args);
|
|
@@ -14356,13 +14540,13 @@ async function runSecretsTemplate(args, io) {
|
|
|
14356
14540
|
return 0;
|
|
14357
14541
|
}
|
|
14358
14542
|
const outPath = resolve14(process.cwd(), flags.out);
|
|
14359
|
-
if (
|
|
14543
|
+
if (existsSync15(outPath) && !flags.force) {
|
|
14360
14544
|
io.err(`launchpad secrets template: ${outPath} already exists`);
|
|
14361
14545
|
io.err("Pass --force to overwrite, or --stdout to print without writing.");
|
|
14362
14546
|
return 64;
|
|
14363
14547
|
}
|
|
14364
14548
|
try {
|
|
14365
|
-
|
|
14549
|
+
writeFileSync7(outPath, body, { encoding: "utf8" });
|
|
14366
14550
|
} catch (err) {
|
|
14367
14551
|
const e = err;
|
|
14368
14552
|
io.err(`launchpad secrets template: failed to write ${outPath}`);
|
|
@@ -14653,12 +14837,12 @@ function printHelp3(io) {
|
|
|
14653
14837
|
// src/commands/skills.ts
|
|
14654
14838
|
import { fileURLToPath } from "node:url";
|
|
14655
14839
|
import { dirname as dirname10, join as join16, resolve as resolve15 } from "node:path";
|
|
14656
|
-
import { promises as fs7, existsSync as
|
|
14840
|
+
import { promises as fs7, existsSync as existsSync16 } from "node:fs";
|
|
14657
14841
|
|
|
14658
14842
|
// src/skills-bundle.ts
|
|
14659
14843
|
import { homedir as homedir2 } from "node:os";
|
|
14660
14844
|
import { join as join15 } from "node:path";
|
|
14661
|
-
import { readFileSync as
|
|
14845
|
+
import { readFileSync as readFileSync20, readdirSync as readdirSync2 } from "node:fs";
|
|
14662
14846
|
var SKILL_PREFIX = "launchpad-";
|
|
14663
14847
|
function skillsTargetDir() {
|
|
14664
14848
|
return process.env.LAUNCHPAD_SKILLS_TARGET_DIR ?? join15(homedir2(), ".claude", "skills");
|
|
@@ -14677,9 +14861,9 @@ function readInstalledSkills() {
|
|
|
14677
14861
|
return { present: false, version: null };
|
|
14678
14862
|
}
|
|
14679
14863
|
}
|
|
14680
|
-
function readSkillVersion(
|
|
14864
|
+
function readSkillVersion(path15) {
|
|
14681
14865
|
try {
|
|
14682
|
-
const text =
|
|
14866
|
+
const text = readFileSync20(path15, "utf8");
|
|
14683
14867
|
const fenceEnd = text.indexOf(`
|
|
14684
14868
|
---`, 4);
|
|
14685
14869
|
const front = fenceEnd === -1 ? text.slice(0, 1024) : text.slice(0, fenceEnd);
|
|
@@ -14762,7 +14946,7 @@ function defaultBundleDir() {
|
|
|
14762
14946
|
resolve15(here, "..", "..", "skills")
|
|
14763
14947
|
];
|
|
14764
14948
|
for (const c of candidates) {
|
|
14765
|
-
if (
|
|
14949
|
+
if (existsSync16(join16(c, "launchpad-onboard", "SKILL.md"))) {
|
|
14766
14950
|
return c;
|
|
14767
14951
|
}
|
|
14768
14952
|
}
|
|
@@ -14842,10 +15026,10 @@ async function doList(io) {
|
|
|
14842
15026
|
}
|
|
14843
15027
|
return 0;
|
|
14844
15028
|
}
|
|
14845
|
-
async function readVersion(
|
|
15029
|
+
async function readVersion(path15) {
|
|
14846
15030
|
let text;
|
|
14847
15031
|
try {
|
|
14848
|
-
text = await fs7.readFile(
|
|
15032
|
+
text = await fs7.readFile(path15, "utf8");
|
|
14849
15033
|
} catch {
|
|
14850
15034
|
return null;
|
|
14851
15035
|
}
|
|
@@ -14855,9 +15039,9 @@ async function readVersion(path14) {
|
|
|
14855
15039
|
const m = /^version:\s*(.+?)\s*$/m.exec(front);
|
|
14856
15040
|
return m === null ? null : m[1] ?? null;
|
|
14857
15041
|
}
|
|
14858
|
-
async function isDir(
|
|
15042
|
+
async function isDir(path15) {
|
|
14859
15043
|
try {
|
|
14860
|
-
const stat = await fs7.stat(
|
|
15044
|
+
const stat = await fs7.stat(path15);
|
|
14861
15045
|
return stat.isDirectory();
|
|
14862
15046
|
} catch {
|
|
14863
15047
|
return false;
|
|
@@ -14873,7 +15057,7 @@ import { promisify } from "node:util";
|
|
|
14873
15057
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
14874
15058
|
import { dirname as dirname11, resolve as resolve16, relative as relative6, isAbsolute as isAbsolute3, join as join17 } from "node:path";
|
|
14875
15059
|
import { homedir as homedir3, tmpdir } from "node:os";
|
|
14876
|
-
import { readFileSync as
|
|
15060
|
+
import { readFileSync as readFileSync21, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync8, rmSync as rmSync3 } from "node:fs";
|
|
14877
15061
|
|
|
14878
15062
|
// src/commands/channel-auth.ts
|
|
14879
15063
|
import { createServer as createServer2 } from "node:http";
|
|
@@ -15123,17 +15307,17 @@ async function openSystemBrowser(url) {
|
|
|
15123
15307
|
await execFileAsync(opener, [url]);
|
|
15124
15308
|
}
|
|
15125
15309
|
async function runInstallerScript(script) {
|
|
15126
|
-
const dir =
|
|
15310
|
+
const dir = mkdtempSync2(join17(tmpdir(), "launchpad-update-"));
|
|
15127
15311
|
const file = join17(dir, "install.sh");
|
|
15128
15312
|
try {
|
|
15129
|
-
|
|
15313
|
+
writeFileSync8(file, script, { mode: 448 });
|
|
15130
15314
|
return await new Promise((resolvePromise) => {
|
|
15131
15315
|
const child = spawn5("bash", [file], { stdio: "inherit" });
|
|
15132
15316
|
child.on("error", () => resolvePromise(127));
|
|
15133
15317
|
child.on("close", (c) => resolvePromise(c ?? 1));
|
|
15134
15318
|
});
|
|
15135
15319
|
} finally {
|
|
15136
|
-
|
|
15320
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
15137
15321
|
}
|
|
15138
15322
|
}
|
|
15139
15323
|
async function runChannelInstaller() {
|
|
@@ -15148,7 +15332,7 @@ function resolveLatestVersion() {
|
|
|
15148
15332
|
}
|
|
15149
15333
|
function detectInstallChannel() {
|
|
15150
15334
|
try {
|
|
15151
|
-
return
|
|
15335
|
+
return readFileSync21(CHANNEL_MARKER, "utf8").trim() === "platform" ? "platform" : "github";
|
|
15152
15336
|
} catch {
|
|
15153
15337
|
return "github";
|
|
15154
15338
|
}
|
|
@@ -15356,7 +15540,7 @@ function printHelp5(io) {
|
|
|
15356
15540
|
}
|
|
15357
15541
|
|
|
15358
15542
|
// src/commands/validate.ts
|
|
15359
|
-
import { existsSync as
|
|
15543
|
+
import { existsSync as existsSync17, readFileSync as readFileSync22, readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
|
|
15360
15544
|
import { dirname as dirname12, resolve as resolve17 } from "node:path";
|
|
15361
15545
|
var validateCommand = {
|
|
15362
15546
|
name: "validate",
|
|
@@ -15371,14 +15555,14 @@ async function runValidate(args, io) {
|
|
|
15371
15555
|
return 64;
|
|
15372
15556
|
}
|
|
15373
15557
|
const { file, json, strictGroups } = parseResult;
|
|
15374
|
-
const
|
|
15375
|
-
const result = loadManifestAnyVersion(
|
|
15558
|
+
const path15 = resolve17(process.cwd(), file ?? "launchpad.yaml");
|
|
15559
|
+
const result = loadManifestAnyVersion(path15);
|
|
15376
15560
|
if (result.kind !== "ok") {
|
|
15377
15561
|
return json ? renderJsonError(result, io) : renderHumanError(result, io);
|
|
15378
15562
|
}
|
|
15379
15563
|
const unsupported2 = rejectUnsupportedCliRuntime({
|
|
15380
15564
|
command: "validate",
|
|
15381
|
-
manifestPath:
|
|
15565
|
+
manifestPath: path15,
|
|
15382
15566
|
manifest: result.manifest,
|
|
15383
15567
|
io,
|
|
15384
15568
|
json,
|
|
@@ -15387,8 +15571,8 @@ async function runValidate(args, io) {
|
|
|
15387
15571
|
if (unsupported2 !== null)
|
|
15388
15572
|
return unsupported2;
|
|
15389
15573
|
const view = manifestView(result.manifest);
|
|
15390
|
-
const boundary = checkBoundary(
|
|
15391
|
-
const serveErrors = checkStaticServeDir(
|
|
15574
|
+
const boundary = checkBoundary(path15, view.appDeclared);
|
|
15575
|
+
const serveErrors = checkStaticServeDir(path15, result.manifest);
|
|
15392
15576
|
if (serveErrors.length > 0) {
|
|
15393
15577
|
boundary.errors = [...boundary.errors, ...serveErrors];
|
|
15394
15578
|
}
|
|
@@ -15405,7 +15589,7 @@ function checkBoundary(manifestPath, declared) {
|
|
|
15405
15589
|
}
|
|
15406
15590
|
let manifestYaml;
|
|
15407
15591
|
try {
|
|
15408
|
-
manifestYaml =
|
|
15592
|
+
manifestYaml = readFileSync22(manifestPath, "utf8");
|
|
15409
15593
|
} catch {
|
|
15410
15594
|
manifestYaml = null;
|
|
15411
15595
|
}
|
|
@@ -15431,7 +15615,7 @@ function checkStaticServeDir(manifestPath, manifest) {
|
|
|
15431
15615
|
}
|
|
15432
15616
|
const dir = dirname12(manifestPath);
|
|
15433
15617
|
const abs = resolve17(dir, serveDir);
|
|
15434
|
-
if (!
|
|
15618
|
+
if (!existsSync17(abs)) {
|
|
15435
15619
|
return [
|
|
15436
15620
|
`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).`
|
|
15437
15621
|
];
|
|
@@ -15456,7 +15640,7 @@ function checkStaticServeDir(manifestPath, manifest) {
|
|
|
15456
15640
|
`static app's served directory '${serveDir}/' is empty — the deploy would serve an empty site.`
|
|
15457
15641
|
];
|
|
15458
15642
|
}
|
|
15459
|
-
if (!
|
|
15643
|
+
if (!existsSync17(resolve17(abs, "index.html"))) {
|
|
15460
15644
|
return [
|
|
15461
15645
|
`static app's served directory '${serveDir}/' has no index.html — the deploy would serve a directory with no entrypoint.`
|
|
15462
15646
|
];
|
|
@@ -16433,10 +16617,10 @@ import { spawn as spawn6 } from "node:child_process";
|
|
|
16433
16617
|
import { homedir as homedir4 } from "node:os";
|
|
16434
16618
|
import { join as join18 } from "node:path";
|
|
16435
16619
|
import {
|
|
16436
|
-
existsSync as
|
|
16437
|
-
mkdirSync as
|
|
16438
|
-
readFileSync as
|
|
16439
|
-
writeFileSync as
|
|
16620
|
+
existsSync as existsSync18,
|
|
16621
|
+
mkdirSync as mkdirSync5,
|
|
16622
|
+
readFileSync as readFileSync23,
|
|
16623
|
+
writeFileSync as writeFileSync9
|
|
16440
16624
|
} from "node:fs";
|
|
16441
16625
|
var INTERNAL_REFRESH_VERB = "__refresh-update-cache";
|
|
16442
16626
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -16444,7 +16628,7 @@ var OPT_OUT_ENV = "LAUNCHPAD_NO_UPDATE_NOTIFIER";
|
|
|
16444
16628
|
var CACHE_FILE = join18(homedir4(), ".launchpad", "update-check.json");
|
|
16445
16629
|
function readCache2() {
|
|
16446
16630
|
try {
|
|
16447
|
-
const raw = JSON.parse(
|
|
16631
|
+
const raw = JSON.parse(readFileSync23(CACHE_FILE, "utf8"));
|
|
16448
16632
|
if (typeof raw === "object" && raw !== null && typeof raw.checkedAt === "number") {
|
|
16449
16633
|
const latest = raw.latest;
|
|
16450
16634
|
return {
|
|
@@ -16457,23 +16641,23 @@ function readCache2() {
|
|
|
16457
16641
|
}
|
|
16458
16642
|
function writeCache2(state) {
|
|
16459
16643
|
try {
|
|
16460
|
-
|
|
16461
|
-
|
|
16644
|
+
mkdirSync5(join18(homedir4(), ".launchpad"), { recursive: true });
|
|
16645
|
+
writeFileSync9(CACHE_FILE, `${JSON.stringify(state)}
|
|
16462
16646
|
`, { mode: 384 });
|
|
16463
16647
|
} catch {}
|
|
16464
16648
|
}
|
|
16465
16649
|
var SKILLS_HINT_MARKER = join18(homedir4(), ".launchpad", "skills-hint-shown");
|
|
16466
16650
|
function absentHintShown() {
|
|
16467
16651
|
try {
|
|
16468
|
-
return
|
|
16652
|
+
return existsSync18(SKILLS_HINT_MARKER);
|
|
16469
16653
|
} catch {
|
|
16470
16654
|
return false;
|
|
16471
16655
|
}
|
|
16472
16656
|
}
|
|
16473
16657
|
function markAbsentHintShown() {
|
|
16474
16658
|
try {
|
|
16475
|
-
|
|
16476
|
-
|
|
16659
|
+
mkdirSync5(join18(homedir4(), ".launchpad"), { recursive: true });
|
|
16660
|
+
writeFileSync9(SKILLS_HINT_MARKER, `${Date.now()}
|
|
16477
16661
|
`, { mode: 384 });
|
|
16478
16662
|
} catch {}
|
|
16479
16663
|
}
|
|
@@ -16576,7 +16760,7 @@ var refreshUpdateCacheCommand = {
|
|
|
16576
16760
|
import { spawn as spawn7 } from "node:child_process";
|
|
16577
16761
|
import { homedir as homedir5 } from "node:os";
|
|
16578
16762
|
import { join as join19 } from "node:path";
|
|
16579
|
-
import { existsSync as
|
|
16763
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync6, readFileSync as readFileSync24, writeFileSync as writeFileSync10 } from "node:fs";
|
|
16580
16764
|
import { randomUUID } from "node:crypto";
|
|
16581
16765
|
var INTERNAL_EMIT_VERB = "__emit-telemetry";
|
|
16582
16766
|
var POSTHOG_HOST = "https://us.i.posthog.com";
|
|
@@ -16652,15 +16836,15 @@ async function resolveIdentityReal() {
|
|
|
16652
16836
|
}
|
|
16653
16837
|
function getOrCreateDeviceId() {
|
|
16654
16838
|
try {
|
|
16655
|
-
const raw = JSON.parse(
|
|
16839
|
+
const raw = JSON.parse(readFileSync24(DEVICE_ID_FILE, "utf8"));
|
|
16656
16840
|
const id2 = raw?.deviceId;
|
|
16657
16841
|
if (typeof id2 === "string" && id2)
|
|
16658
16842
|
return id2;
|
|
16659
16843
|
} catch {}
|
|
16660
16844
|
const id = randomUUID();
|
|
16661
16845
|
try {
|
|
16662
|
-
|
|
16663
|
-
|
|
16846
|
+
mkdirSync6(join19(homedir5(), ".launchpad"), { recursive: true });
|
|
16847
|
+
writeFileSync10(DEVICE_ID_FILE, `${JSON.stringify({ deviceId: id })}
|
|
16664
16848
|
`, {
|
|
16665
16849
|
mode: 384
|
|
16666
16850
|
});
|
|
@@ -16730,15 +16914,15 @@ function telemetryNoticeLine() {
|
|
|
16730
16914
|
}
|
|
16731
16915
|
function firstRunNoticeShown() {
|
|
16732
16916
|
try {
|
|
16733
|
-
return
|
|
16917
|
+
return existsSync19(FIRST_RUN_MARKER);
|
|
16734
16918
|
} catch {
|
|
16735
16919
|
return false;
|
|
16736
16920
|
}
|
|
16737
16921
|
}
|
|
16738
16922
|
function markFirstRunNotice() {
|
|
16739
16923
|
try {
|
|
16740
|
-
|
|
16741
|
-
|
|
16924
|
+
mkdirSync6(join19(homedir5(), ".launchpad"), { recursive: true });
|
|
16925
|
+
writeFileSync10(FIRST_RUN_MARKER, `${Date.now()}
|
|
16742
16926
|
`, { mode: 384 });
|
|
16743
16927
|
} catch {}
|
|
16744
16928
|
}
|
|
@@ -16803,7 +16987,7 @@ import { createInterface as createInterface7 } from "node:readline/promises";
|
|
|
16803
16987
|
import { platform } from "node:os";
|
|
16804
16988
|
|
|
16805
16989
|
// src/report/breadcrumb.ts
|
|
16806
|
-
import { writeFileSync as
|
|
16990
|
+
import { writeFileSync as writeFileSync11, readFileSync as readFileSync25, mkdirSync as mkdirSync7 } from "node:fs";
|
|
16807
16991
|
import { homedir as homedir6 } from "node:os";
|
|
16808
16992
|
import { join as join20, dirname as dirname13 } from "node:path";
|
|
16809
16993
|
function breadcrumbPath() {
|
|
@@ -16812,13 +16996,13 @@ function breadcrumbPath() {
|
|
|
16812
16996
|
function writeBreadcrumb(verb, exit) {
|
|
16813
16997
|
try {
|
|
16814
16998
|
const p = breadcrumbPath();
|
|
16815
|
-
|
|
16816
|
-
|
|
16999
|
+
mkdirSync7(dirname13(p), { recursive: true });
|
|
17000
|
+
writeFileSync11(p, JSON.stringify({ verb, exit, ts: Date.now() }), "utf8");
|
|
16817
17001
|
} catch {}
|
|
16818
17002
|
}
|
|
16819
17003
|
function readBreadcrumb() {
|
|
16820
17004
|
try {
|
|
16821
|
-
const raw = JSON.parse(
|
|
17005
|
+
const raw = JSON.parse(readFileSync25(breadcrumbPath(), "utf8"));
|
|
16822
17006
|
if (typeof raw !== "object" || raw === null)
|
|
16823
17007
|
return null;
|
|
16824
17008
|
const r = raw;
|
|
@@ -16987,6 +17171,7 @@ var COMMANDS = [
|
|
|
16987
17171
|
createCommand,
|
|
16988
17172
|
cloneCommand,
|
|
16989
17173
|
deployCommand,
|
|
17174
|
+
migrateCommand,
|
|
16990
17175
|
redeployCommand,
|
|
16991
17176
|
reviewCommand,
|
|
16992
17177
|
mergeCommand,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AA0EA,OAAO,EAGL,4BAA4B,EAC7B,MAAM,uBAAuB,CAAC;AAY/B,OAAO,EAAa,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,KAAK,EAAS,OAAO,EAAY,MAAM,kBAAkB,CAAC;AAQjE,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;AA6RD;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAoBpC;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,GAAG,IAAI,CA4BpE;AAiMD,2BAA2B;AAC3B,OAAO,EAAE,4BAA4B,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AA0EA,OAAO,EAGL,4BAA4B,EAC7B,MAAM,uBAAuB,CAAC;AAY/B,OAAO,EAAa,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,KAAK,EAAS,OAAO,EAAY,MAAM,kBAAkB,CAAC;AAQjE,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;AA6RD;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAoBpC;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,GAAG,IAAI,CA4BpE;AAiMD,2BAA2B;AAC3B,OAAO,EAAE,4BAA4B,EAAE,CAAC;AA4tBxC,2EAA2E;AAC3E;+EAC+E;AAC/E,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAE9D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,cAAc,CAG/E;AAED;;;4EAG4E;AAC5E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;CACrD,GAAG,OAAO,CAIV;AAED,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,OAAO,EACvB,UAAU,GAAE,OAAO,GAAG,SAAqB,GAC1C,MAAM,CAOR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAS,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAIvD,eAAO,MAAM,cAAc,EAAE,OAI5B,CAAC"}
|
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":"AA2DA,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,EA2CtC,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;AAuDD,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":"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,
|
|
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,CA8FnB"}
|
package/dist/http/errors.d.ts
CHANGED
|
@@ -13,7 +13,10 @@ export declare class ForbiddenError extends Error {
|
|
|
13
13
|
/** 404 — the bot returned not-found. Distinct from UnauthenticatedError
|
|
14
14
|
* so the CLI doesn't suggest re-login when the slug is just unknown. */
|
|
15
15
|
export declare class NotFoundError extends Error {
|
|
16
|
+
readonly serverCode?: string | undefined;
|
|
16
17
|
readonly code: "not_found";
|
|
18
|
+
/** Retain the server's code so registry misses differ from unknown routes. */
|
|
19
|
+
constructor(message: string, serverCode?: string | undefined);
|
|
17
20
|
}
|
|
18
21
|
/** Stable process exit used only for a server-enforced CLI upgrade. */
|
|
19
22
|
export declare const EXIT_CLI_UPGRADE_REQUIRED = 42;
|
|
@@ -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;
|
|
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;IAIT,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM;IAHzD,QAAQ,CAAC,IAAI,EAAG,WAAW,CAAU;IAErC,8EAA8E;gBAClE,OAAO,EAAE,MAAM,EAAW,UAAU,CAAC,EAAE,MAAM,YAAA;CAG1D;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,4 @@
|
|
|
1
|
+
import { type DeploymentManifest, type ManifestV2 } from "@m-kopa/launchpad-engine";
|
|
2
|
+
/** Convert only the static subset whose deployment contract dispatch preserves. */
|
|
3
|
+
export declare function dispatchManifest(manifest: DeploymentManifest): ManifestV2;
|
|
4
|
+
//# sourceMappingURL=migrate-dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-dispatch.d.ts","sourceRoot":"","sources":["../../src/manifest/migrate-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EAEvB,KAAK,UAAU,EAChB,MAAM,0BAA0B,CAAC;AAElC,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,UAAU,CAkDzE"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.
|
|
1
|
+
export declare const CLI_VERSION = "0.62.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -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.62.0
|
|
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.62.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -151,6 +151,14 @@ Gateway placement is automatic for new gateway-fronted apps, including Pages API
|
|
|
151
151
|
The platform selects the configured gateway with the most free hostname slots, counting pending deployments as reservations.
|
|
152
152
|
Do not ask the author to choose a gateway or add gateway project names to the manifest.
|
|
153
153
|
Existing apps and retries retain their assigned gateway and public URL.
|
|
154
|
+
Updating the CLI does not rewrite an existing Pages manifest.
|
|
155
|
+
If an unprovisioned static or React app hits the Pages project limit, run `launchpad update`, then `launchpad migrate --origin dispatch --dry-run`.
|
|
156
|
+
When eligible, run `launchpad migrate --origin dispatch`, review the preserved audience and build settings, then run `launchpad deploy`.
|
|
157
|
+
The command checks the live registry and saves the original YAML under `.launchpad/manifest-before-dispatch.yaml`.
|
|
158
|
+
Do not regenerate the manifest with `init`, broaden its groups, or change private ownership to work around the quota.
|
|
159
|
+
If migration refuses functions, custom runtime configuration or bindings, stop and explain the named limitation.
|
|
160
|
+
Pages Functions apps need a compiled Worker build; changing `appType` to `react` would not convert their API.
|
|
161
|
+
Do not use this command to migrate a registered app or delete its Pages resources.
|
|
154
162
|
If the pool is full or inventory cannot be read, report the capacity error; do not fall back to Pages or change authentication to bypass it.
|
|
155
163
|
Do not replace that manifest with a v1 example or add `--origin pages` just because an older app uses Pages.
|
|
156
164
|
Use `--origin pages` only when Pages is deliberately required.
|
|
@@ -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.62.0
|
|
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.62.0
|
|
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.62.0
|
|
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.62.0
|
|
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.62.0
|
|
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.62.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|