@m-kopa/launchpad-cli 0.55.0 → 0.56.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 +16 -0
- package/dist/bundle/upload.d.ts +4 -0
- package/dist/bundle/upload.d.ts.map +1 -1
- package/dist/cli.js +260 -151
- package/dist/commands/deploy-flags.d.ts +2 -0
- package/dist/commands/deploy-flags.d.ts.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/deploy/access-drift-offer.d.ts +2 -0
- package/dist/deploy/access-drift-offer.d.ts.map +1 -1
- package/dist/deploy/apply.d.ts +2 -0
- package/dist/deploy/apply.d.ts.map +1 -1
- package/dist/deploy/manifest-state.d.ts +2 -1
- package/dist/deploy/manifest-state.d.ts.map +1 -1
- package/dist/status-page-output.d.ts +12 -0
- package/dist/status-page-output.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/watch/index.d.ts +3 -0
- package/dist/watch/index.d.ts.map +1 -1
- package/dist/watch/model.d.ts +1 -0
- package/dist/watch/model.d.ts.map +1 -1
- package/package.json +1 -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/dist/cli.js
CHANGED
|
@@ -19,9 +19,10 @@ 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.56.0";
|
|
23
23
|
|
|
24
24
|
// src/config.ts
|
|
25
|
+
import { readFileSync } from "node:fs";
|
|
25
26
|
import * as os from "node:os";
|
|
26
27
|
import * as path from "node:path";
|
|
27
28
|
var DEFAULT_BOT_URL = "https://launchpad-portal-bot.mkopa-launchpad.workers.dev";
|
|
@@ -39,6 +40,8 @@ function loadConfig(env = process.env) {
|
|
|
39
40
|
const stateDir = env.LAUNCHPAD_STATE_DIR ?? path.join(os.homedir(), ".launchpad", "state");
|
|
40
41
|
const rawPlatformRepo = env.LAUNCHPAD_PLATFORM_REPO;
|
|
41
42
|
const platformRepoPath = rawPlatformRepo !== undefined && rawPlatformRepo.length > 0 ? path.resolve(rawPlatformRepo) : null;
|
|
43
|
+
const configPath = env.LAUNCHPAD_CONFIG_PATH ?? path.join(os.homedir(), ".launchpad", "config.json");
|
|
44
|
+
const statusPageAutoOpen = readStatusPageAutoOpen(configPath);
|
|
42
45
|
return {
|
|
43
46
|
botUrl,
|
|
44
47
|
authGatewayUrl,
|
|
@@ -47,9 +50,18 @@ function loadConfig(env = process.env) {
|
|
|
47
50
|
sessionPath,
|
|
48
51
|
cacheDir,
|
|
49
52
|
stateDir,
|
|
50
|
-
platformRepoPath
|
|
53
|
+
platformRepoPath,
|
|
54
|
+
statusPageAutoOpen
|
|
51
55
|
};
|
|
52
56
|
}
|
|
57
|
+
function readStatusPageAutoOpen(configPath) {
|
|
58
|
+
try {
|
|
59
|
+
const value = JSON.parse(readFileSync(configPath, "utf8"));
|
|
60
|
+
return !(typeof value === "object" && value !== null && value.statusPageAutoOpen === false);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return error.code === "ENOENT";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
53
65
|
|
|
54
66
|
// src/http/error-envelope.ts
|
|
55
67
|
var MAX_TEXT_CHARS = 16384;
|
|
@@ -1874,7 +1886,7 @@ import { existsSync as existsSync7 } from "node:fs";
|
|
|
1874
1886
|
import * as path8 from "node:path";
|
|
1875
1887
|
|
|
1876
1888
|
// src/bundle/orchestrate.ts
|
|
1877
|
-
import { readFileSync as
|
|
1889
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
1878
1890
|
import { join as join7 } from "node:path";
|
|
1879
1891
|
|
|
1880
1892
|
// src/deploy/tar-pack.ts
|
|
@@ -2186,7 +2198,8 @@ function deployBundleError(envelope, body) {
|
|
|
2186
2198
|
...paths === undefined ? {} : { paths },
|
|
2187
2199
|
...typeof body.reason === "string" ? { reason: body.reason } : {},
|
|
2188
2200
|
...typeof body.minimum === "string" ? { minimum: body.minimum } : {},
|
|
2189
|
-
...typeof body.yours === "string" ? { yours: body.yours } : {}
|
|
2201
|
+
...typeof body.yours === "string" ? { yours: body.yours } : {},
|
|
2202
|
+
...typeof body.statusPageUrl === "string" ? { statusPageUrl: body.statusPageUrl } : {}
|
|
2190
2203
|
};
|
|
2191
2204
|
}
|
|
2192
2205
|
function readStringArray(value) {
|
|
@@ -2210,7 +2223,7 @@ function isRecord2(value) {
|
|
|
2210
2223
|
}
|
|
2211
2224
|
|
|
2212
2225
|
// src/bundle/cwd-walker.ts
|
|
2213
|
-
import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
|
|
2226
|
+
import { existsSync, lstatSync, readFileSync as readFileSync2, readdirSync } from "node:fs";
|
|
2214
2227
|
import { join as join4, relative as relative2, sep } from "node:path";
|
|
2215
2228
|
var DEFAULT_IGNORE = [
|
|
2216
2229
|
".git",
|
|
@@ -2316,7 +2329,7 @@ function loadIgnore(cwd) {
|
|
|
2316
2329
|
}
|
|
2317
2330
|
let content;
|
|
2318
2331
|
try {
|
|
2319
|
-
content =
|
|
2332
|
+
content = readFileSync2(file, "utf8");
|
|
2320
2333
|
} catch {
|
|
2321
2334
|
return { matches: () => false };
|
|
2322
2335
|
}
|
|
@@ -2390,7 +2403,7 @@ function globToRegExp(glob) {
|
|
|
2390
2403
|
}
|
|
2391
2404
|
|
|
2392
2405
|
// src/bundle/cron-bundle.ts
|
|
2393
|
-
import { readFileSync as
|
|
2406
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
2394
2407
|
import { dirname as dirname4, join as join5, resolve as resolve5 } from "node:path";
|
|
2395
2408
|
import { parse as parseYaml } from "yaml";
|
|
2396
2409
|
import { build as esbuild } from "esbuild";
|
|
@@ -2470,7 +2483,7 @@ function locateWorkerConfig(cwd, walkFiles, script) {
|
|
|
2470
2483
|
const abs = resolve5(cwd, rel);
|
|
2471
2484
|
let text;
|
|
2472
2485
|
try {
|
|
2473
|
-
text =
|
|
2486
|
+
text = readFileSync3(abs, "utf8");
|
|
2474
2487
|
} catch {
|
|
2475
2488
|
continue;
|
|
2476
2489
|
}
|
|
@@ -2549,7 +2562,7 @@ async function buildWorkerArtifact(cwd, manifestYaml, walkFiles) {
|
|
|
2549
2562
|
}
|
|
2550
2563
|
|
|
2551
2564
|
// src/bundle/boundary.ts
|
|
2552
|
-
import { existsSync as existsSync2, lstatSync as lstatSync2, readFileSync as
|
|
2565
|
+
import { existsSync as existsSync2, lstatSync as lstatSync2, readFileSync as readFileSync4 } from "node:fs";
|
|
2553
2566
|
import { join as join6 } from "node:path";
|
|
2554
2567
|
import { parse as parseYaml2 } from "yaml";
|
|
2555
2568
|
|
|
@@ -4390,7 +4403,7 @@ function applyBoundaryToFiles(args) {
|
|
|
4390
4403
|
const ignorePath = join6(cwd, ".launchpadignore");
|
|
4391
4404
|
if (existsSync2(ignorePath)) {
|
|
4392
4405
|
try {
|
|
4393
|
-
launchpadIgnore = parseLaunchpadIgnore(
|
|
4406
|
+
launchpadIgnore = parseLaunchpadIgnore(readFileSync4(ignorePath, "utf8"));
|
|
4394
4407
|
} catch {}
|
|
4395
4408
|
}
|
|
4396
4409
|
const result = applyAppBoundary(contract, files, {
|
|
@@ -4401,7 +4414,7 @@ function applyBoundaryToFiles(args) {
|
|
|
4401
4414
|
const stat = lstatSync2(abs);
|
|
4402
4415
|
if (!stat.isFile() || stat.size > MAX_CONTENT_PROBE_BYTES)
|
|
4403
4416
|
return;
|
|
4404
|
-
return
|
|
4417
|
+
return readFileSync4(abs, "utf8");
|
|
4405
4418
|
} catch {
|
|
4406
4419
|
return;
|
|
4407
4420
|
}
|
|
@@ -4453,7 +4466,7 @@ async function bundleAndDeploy(args) {
|
|
|
4453
4466
|
const manifestPath = join7(cwd, "launchpad.yaml");
|
|
4454
4467
|
let manifestYaml;
|
|
4455
4468
|
try {
|
|
4456
|
-
manifestYaml =
|
|
4469
|
+
manifestYaml = readFileSync5(manifestPath, "utf8");
|
|
4457
4470
|
} catch (e) {
|
|
4458
4471
|
return {
|
|
4459
4472
|
kind: "no-manifest",
|
|
@@ -4515,7 +4528,7 @@ async function bundleAndDeploy(args) {
|
|
|
4515
4528
|
}
|
|
4516
4529
|
|
|
4517
4530
|
// src/deploy/verify-deploy.ts
|
|
4518
|
-
import { readFileSync as
|
|
4531
|
+
import { readFileSync as readFileSync9, existsSync as existsSync4 } from "node:fs";
|
|
4519
4532
|
import { join as join9 } from "node:path";
|
|
4520
4533
|
|
|
4521
4534
|
// src/deploy/redact-diagnostic.ts
|
|
@@ -4760,7 +4773,7 @@ async function verifyServed(args, deps = { fetch }) {
|
|
|
4760
4773
|
}
|
|
4761
4774
|
|
|
4762
4775
|
// src/commands/status.ts
|
|
4763
|
-
import { readFileSync as
|
|
4776
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
4764
4777
|
|
|
4765
4778
|
// src/deploy/manifest-state.ts
|
|
4766
4779
|
async function fetchManifestState(cfg, slug, opts = {}, fetcher = fetch) {
|
|
@@ -4770,6 +4783,7 @@ async function fetchManifestState(cfg, slug, opts = {}, fetcher = fetch) {
|
|
|
4770
4783
|
slug: raw.slug,
|
|
4771
4784
|
hasAppFile: raw.hasAppFile,
|
|
4772
4785
|
lastAppliedManifestSha: raw.lastAppliedManifestSha,
|
|
4786
|
+
deployedManifestSha: raw.deployedManifestSha ?? raw.lastAppliedManifestSha,
|
|
4773
4787
|
appRepoHeadSha: raw.appRepoHeadSha ?? null,
|
|
4774
4788
|
openPr: raw.openPr,
|
|
4775
4789
|
enforcedGroups: raw.enforcedGroups ?? null,
|
|
@@ -4779,7 +4793,7 @@ async function fetchManifestState(cfg, slug, opts = {}, fetcher = fetch) {
|
|
|
4779
4793
|
|
|
4780
4794
|
// src/commands/infer-slug.ts
|
|
4781
4795
|
import * as path7 from "node:path";
|
|
4782
|
-
import { existsSync as existsSync3, readFileSync as
|
|
4796
|
+
import { existsSync as existsSync3, readFileSync as readFileSync6 } from "node:fs";
|
|
4783
4797
|
import { parse as parseYaml3 } from "yaml";
|
|
4784
4798
|
var DIRNAME_RE = /^launchpad-app-([a-z0-9][a-z0-9-]*[a-z0-9])$/;
|
|
4785
4799
|
function inferSlugFromCwd(cwd) {
|
|
@@ -4802,7 +4816,7 @@ function inferSlugFromManifestFile(manifestPath) {
|
|
|
4802
4816
|
if (!existsSync3(manifestPath))
|
|
4803
4817
|
return null;
|
|
4804
4818
|
try {
|
|
4805
|
-
return resolveManifestSlug(parseYaml3(
|
|
4819
|
+
return resolveManifestSlug(parseYaml3(readFileSync6(manifestPath, "utf8")));
|
|
4806
4820
|
} catch {
|
|
4807
4821
|
return null;
|
|
4808
4822
|
}
|
|
@@ -4818,7 +4832,7 @@ function inferSlug(opts) {
|
|
|
4818
4832
|
}
|
|
4819
4833
|
|
|
4820
4834
|
// src/groups/client.ts
|
|
4821
|
-
import { mkdirSync, readFileSync as
|
|
4835
|
+
import { mkdirSync, readFileSync as readFileSync7, writeFileSync } from "node:fs";
|
|
4822
4836
|
import { dirname as dirname5, join as join8 } from "node:path";
|
|
4823
4837
|
var CACHE_TTL_MS = 60 * 60 * 1000;
|
|
4824
4838
|
var CACHE_FILENAME = "groups.json";
|
|
@@ -4862,7 +4876,7 @@ async function fetchGroups(cfg, opts = {}) {
|
|
|
4862
4876
|
function readCache(path8) {
|
|
4863
4877
|
let raw;
|
|
4864
4878
|
try {
|
|
4865
|
-
raw =
|
|
4879
|
+
raw = readFileSync7(path8, "utf8");
|
|
4866
4880
|
} catch {
|
|
4867
4881
|
return null;
|
|
4868
4882
|
}
|
|
@@ -5498,9 +5512,10 @@ async function runWatch(slug, io, deps = {}) {
|
|
|
5498
5512
|
const cfg = loadConfig();
|
|
5499
5513
|
const now = deps.now ?? (() => Date.now());
|
|
5500
5514
|
const stdout = deps.stdout ?? process.stdout;
|
|
5515
|
+
const readLifecycle = deps.fetchLifecycle ?? (() => fetchLifecycleView(cfg, slug));
|
|
5501
5516
|
let first;
|
|
5502
5517
|
try {
|
|
5503
|
-
first = await
|
|
5518
|
+
first = await readLifecycle();
|
|
5504
5519
|
} catch (e) {
|
|
5505
5520
|
return mapWatchError(e, slug, io);
|
|
5506
5521
|
}
|
|
@@ -5508,6 +5523,9 @@ async function runWatch(slug, io, deps = {}) {
|
|
|
5508
5523
|
io.err(`launchpad watch: no app "${slug}" to watch (unknown slug, or first deploy not started)`);
|
|
5509
5524
|
return 1;
|
|
5510
5525
|
}
|
|
5526
|
+
if (first.statusPageUrl !== undefined) {
|
|
5527
|
+
io.out(`Status page: ${first.statusPageUrl}`);
|
|
5528
|
+
}
|
|
5511
5529
|
if (first.state === "destroyed" || first.state === "destroying" || first.state === "destroy_failed") {
|
|
5512
5530
|
io.out(`${slug}: ${first.state} — nothing to watch.`);
|
|
5513
5531
|
return 0;
|
|
@@ -5534,7 +5552,7 @@ async function runWatch(slug, io, deps = {}) {
|
|
|
5534
5552
|
};
|
|
5535
5553
|
try {
|
|
5536
5554
|
const res = await runWatchLoop(slug, {
|
|
5537
|
-
fetchLifecycle:
|
|
5555
|
+
fetchLifecycle: readLifecycle,
|
|
5538
5556
|
now,
|
|
5539
5557
|
sleep: makeRealSleep(),
|
|
5540
5558
|
signal: controller.signal,
|
|
@@ -5571,6 +5589,19 @@ var statusCommand = {
|
|
|
5571
5589
|
run: runStatus
|
|
5572
5590
|
};
|
|
5573
5591
|
var SLUG_RE3 = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
|
|
5592
|
+
function statusTruthFields(args) {
|
|
5593
|
+
return {
|
|
5594
|
+
slug: args.slug,
|
|
5595
|
+
deployedSha: args.deployedSha,
|
|
5596
|
+
headSha: args.headSha,
|
|
5597
|
+
hasOpenPr: args.openPrNumber !== null,
|
|
5598
|
+
openPrNumber: args.openPrNumber,
|
|
5599
|
+
driftFields: [],
|
|
5600
|
+
driftDetails: [],
|
|
5601
|
+
...args.deployment !== undefined ? { deployment: args.deployment } : {},
|
|
5602
|
+
...args.standingExceptions !== undefined ? { standingExceptions: args.standingExceptions } : {}
|
|
5603
|
+
};
|
|
5604
|
+
}
|
|
5574
5605
|
async function fetchLifecycle(cfg, slug) {
|
|
5575
5606
|
try {
|
|
5576
5607
|
return await apiJson(cfg, { path: `/apps/${slug}/lifecycle` });
|
|
@@ -5646,7 +5677,7 @@ async function runStatus(args, io) {
|
|
|
5646
5677
|
}
|
|
5647
5678
|
let localYaml = null;
|
|
5648
5679
|
try {
|
|
5649
|
-
localYaml =
|
|
5680
|
+
localYaml = readFileSync8(parsed.file, "utf8");
|
|
5650
5681
|
} catch (e) {
|
|
5651
5682
|
if (!isEnoent(e)) {
|
|
5652
5683
|
io.err(`launchpad status: cannot read local manifest at ${parsed.file}: ${describe12(e)}`);
|
|
@@ -5707,16 +5738,16 @@ async function runStatus(args, io) {
|
|
|
5707
5738
|
const platformTracked = state.hasAppFile === true || live?.trigger === "bot";
|
|
5708
5739
|
const out = {
|
|
5709
5740
|
state: contentIsLive ? platformTracked ? "live_drift_unknown" : "live_content_untracked" : platformTracked && !deploymentKnown ? "live_drift_unknown" : liveButEmpty ? "live_no_content" : "no_deployed_manifest",
|
|
5710
|
-
slug: parsed.slug,
|
|
5711
5741
|
...local === null ? { drift: null } : {},
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5742
|
+
...statusTruthFields({
|
|
5743
|
+
slug: parsed.slug,
|
|
5744
|
+
deployedSha: state.deployedManifestSha,
|
|
5745
|
+
headSha: state.appRepoHeadSha,
|
|
5746
|
+
openPrNumber: state.openPr?.number ?? null,
|
|
5747
|
+
...deploymentKnown ? { deployment } : {},
|
|
5748
|
+
...standingExceptions !== null ? { standingExceptions } : {}
|
|
5749
|
+
}),
|
|
5750
|
+
...lifecycle?.statusPageUrl !== undefined ? { statusPageUrl: lifecycle.statusPageUrl } : {}
|
|
5720
5751
|
};
|
|
5721
5752
|
emit4(out, parsed.json, io);
|
|
5722
5753
|
return 0;
|
|
@@ -5724,16 +5755,16 @@ async function runStatus(args, io) {
|
|
|
5724
5755
|
if (local === null) {
|
|
5725
5756
|
const out = {
|
|
5726
5757
|
state: "live_drift_unknown",
|
|
5727
|
-
slug: parsed.slug,
|
|
5728
5758
|
drift: null,
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5759
|
+
...statusTruthFields({
|
|
5760
|
+
slug: parsed.slug,
|
|
5761
|
+
deployedSha: state.deployedManifestSha,
|
|
5762
|
+
headSha: state.appRepoHeadSha,
|
|
5763
|
+
openPrNumber: state.openPr?.number ?? null,
|
|
5764
|
+
...deploymentKnown ? { deployment } : {},
|
|
5765
|
+
...standingExceptions !== null ? { standingExceptions } : {}
|
|
5766
|
+
}),
|
|
5767
|
+
...lifecycle?.statusPageUrl !== undefined ? { statusPageUrl: lifecycle.statusPageUrl } : {}
|
|
5737
5768
|
};
|
|
5738
5769
|
emit4(out, parsed.json, io);
|
|
5739
5770
|
if (parsed.strict) {
|
|
@@ -5750,12 +5781,12 @@ async function runStatus(args, io) {
|
|
|
5750
5781
|
const { parse: parseYaml4 } = await import("yaml");
|
|
5751
5782
|
deployedObj = parseYaml4(state.manifestYaml);
|
|
5752
5783
|
} catch (e) {
|
|
5753
|
-
io.err(`launchpad status: deployed manifest at ${state.
|
|
5784
|
+
io.err(`launchpad status: deployed manifest at ${state.deployedManifestSha} is not valid YAML: ${describe12(e)}`);
|
|
5754
5785
|
return 2;
|
|
5755
5786
|
}
|
|
5756
5787
|
const deployedParse = parseManifest(deployedObj);
|
|
5757
5788
|
if (deployedParse.kind !== "ok") {
|
|
5758
|
-
io.err(`launchpad status: deployed manifest at ${state.
|
|
5789
|
+
io.err(`launchpad status: deployed manifest at ${state.deployedManifestSha} failed schema validation:`);
|
|
5759
5790
|
for (const issue of deployedParse.issues) {
|
|
5760
5791
|
io.err(` - ${issue.path}: ${issue.message}`);
|
|
5761
5792
|
}
|
|
@@ -5775,7 +5806,7 @@ async function runStatus(args, io) {
|
|
|
5775
5806
|
cfg,
|
|
5776
5807
|
refs: allowedEntraGroups(deployed.access),
|
|
5777
5808
|
source: "deployed manifest",
|
|
5778
|
-
manifestSha: state.
|
|
5809
|
+
manifestSha: state.deployedManifestSha
|
|
5779
5810
|
});
|
|
5780
5811
|
if (deployedGroups.kind === "error") {
|
|
5781
5812
|
return renderStatusGroupError(deployedGroups.envelope, parsed.json, io);
|
|
@@ -5790,7 +5821,7 @@ async function runStatus(args, io) {
|
|
|
5790
5821
|
cfg,
|
|
5791
5822
|
refs: state.enforcedGroups,
|
|
5792
5823
|
source: "enforced access",
|
|
5793
|
-
manifestSha: state.
|
|
5824
|
+
manifestSha: state.deployedManifestSha
|
|
5794
5825
|
});
|
|
5795
5826
|
if (enforcedGroups.kind === "error") {
|
|
5796
5827
|
return renderStatusGroupError(enforcedGroups.envelope, parsed.json, io);
|
|
@@ -5799,7 +5830,7 @@ async function runStatus(args, io) {
|
|
|
5799
5830
|
}
|
|
5800
5831
|
const localAssignmentGroups = (local.auth ?? "access") === "access" ? localGroups : null;
|
|
5801
5832
|
const deployedAssignmentGroups = (deployed.auth ?? "access") === "access" ? deployedGroups : null;
|
|
5802
|
-
const assignmentCheck = localAssignmentGroups === null && deployedAssignmentGroups === null ? { kind: "ok", issues: [] } : await findAssignmentIssues(cfg, localAssignmentGroups, deployedAssignmentGroups, state.
|
|
5833
|
+
const assignmentCheck = localAssignmentGroups === null && deployedAssignmentGroups === null ? { kind: "ok", issues: [] } : await findAssignmentIssues(cfg, localAssignmentGroups, deployedAssignmentGroups, state.deployedManifestSha);
|
|
5803
5834
|
if (assignmentCheck.kind === "error") {
|
|
5804
5835
|
return renderStatusGroupError(assignmentCheck.envelope, parsed.json, io);
|
|
5805
5836
|
}
|
|
@@ -5807,7 +5838,7 @@ async function runStatus(args, io) {
|
|
|
5807
5838
|
const result = {
|
|
5808
5839
|
state: drift.length === 0 ? "in_sync" : "drift",
|
|
5809
5840
|
slug: parsed.slug,
|
|
5810
|
-
deployedSha: state.
|
|
5841
|
+
deployedSha: state.deployedManifestSha,
|
|
5811
5842
|
headSha: state.appRepoHeadSha,
|
|
5812
5843
|
hasOpenPr: state.openPr !== null,
|
|
5813
5844
|
openPrNumber: state.openPr?.number ?? null,
|
|
@@ -5816,7 +5847,8 @@ async function runStatus(args, io) {
|
|
|
5816
5847
|
...deploymentKnown ? { deployment } : {},
|
|
5817
5848
|
...standingExceptions !== null ? { standingExceptions } : {},
|
|
5818
5849
|
...accessDrift !== undefined ? { accessDrift } : {},
|
|
5819
|
-
...groupIssues.length === 0 ? {} : { groupIssues }
|
|
5850
|
+
...groupIssues.length === 0 ? {} : { groupIssues },
|
|
5851
|
+
...lifecycle?.statusPageUrl !== undefined ? { statusPageUrl: lifecycle.statusPageUrl } : {}
|
|
5820
5852
|
};
|
|
5821
5853
|
emit4(result, parsed.json, io);
|
|
5822
5854
|
if (parsed.strict && (result.state === "drift" || accessDrift?.inSync === false || groupIssues.length > 0)) {
|
|
@@ -6011,7 +6043,8 @@ function lifecycleOutput(slug, lc) {
|
|
|
6011
6043
|
hasOpenPr: false,
|
|
6012
6044
|
openPrNumber: null,
|
|
6013
6045
|
driftFields: [],
|
|
6014
|
-
driftDetails: []
|
|
6046
|
+
driftDetails: [],
|
|
6047
|
+
...lc.statusPageUrl !== undefined ? { statusPageUrl: lc.statusPageUrl } : {}
|
|
6015
6048
|
};
|
|
6016
6049
|
}
|
|
6017
6050
|
function emit4(out, asJson, io) {
|
|
@@ -6019,6 +6052,9 @@ function emit4(out, asJson, io) {
|
|
|
6019
6052
|
io.out(JSON.stringify(out, null, 2));
|
|
6020
6053
|
return;
|
|
6021
6054
|
}
|
|
6055
|
+
if (out.statusPageUrl !== undefined) {
|
|
6056
|
+
io.out(`Status page: ${out.statusPageUrl}`);
|
|
6057
|
+
}
|
|
6022
6058
|
switch (out.state) {
|
|
6023
6059
|
case "provisioning":
|
|
6024
6060
|
io.out(`${out.slug}: provisioning (stage: ${out.stage ?? "starting"})` + (out.submissionId ? ` — submission ${out.submissionId}` : ""));
|
|
@@ -6343,7 +6379,7 @@ function readLocalEntrypoint(cwd) {
|
|
|
6343
6379
|
for (const rel of ["index.html", join9("static", "index.html")]) {
|
|
6344
6380
|
const p = join9(cwd, rel);
|
|
6345
6381
|
if (existsSync4(p))
|
|
6346
|
-
return new Uint8Array(
|
|
6382
|
+
return new Uint8Array(readFileSync9(p));
|
|
6347
6383
|
}
|
|
6348
6384
|
return null;
|
|
6349
6385
|
}
|
|
@@ -6577,7 +6613,7 @@ async function verifyFirstDeployServed(args, liveUrl, io, deps) {
|
|
|
6577
6613
|
|
|
6578
6614
|
// src/commands/deploy.ts
|
|
6579
6615
|
import { parse as parseYaml6 } from "yaml";
|
|
6580
|
-
import { readFileSync as
|
|
6616
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
6581
6617
|
|
|
6582
6618
|
// src/deploy/git-files.ts
|
|
6583
6619
|
import { spawn as spawn3 } from "node:child_process";
|
|
@@ -6834,6 +6870,7 @@ function parseDeployFlags(args) {
|
|
|
6834
6870
|
let rebaseOntoHead = false;
|
|
6835
6871
|
let overrideStale = null;
|
|
6836
6872
|
let allowUnguarded = false;
|
|
6873
|
+
let noOpen = false;
|
|
6837
6874
|
let i = 0;
|
|
6838
6875
|
while (i < args.length) {
|
|
6839
6876
|
const a = args[i] ?? "";
|
|
@@ -7038,6 +7075,11 @@ function parseDeployFlags(args) {
|
|
|
7038
7075
|
i += 1;
|
|
7039
7076
|
continue;
|
|
7040
7077
|
}
|
|
7078
|
+
if (a === "--no-open") {
|
|
7079
|
+
noOpen = true;
|
|
7080
|
+
i += 1;
|
|
7081
|
+
continue;
|
|
7082
|
+
}
|
|
7041
7083
|
if (a.startsWith("--verify-timeout=")) {
|
|
7042
7084
|
const v = a.slice("--verify-timeout=".length);
|
|
7043
7085
|
const n = Number(v);
|
|
@@ -7058,6 +7100,9 @@ function parseDeployFlags(args) {
|
|
|
7058
7100
|
if (rebaseOntoHead && overrideStale !== null) {
|
|
7059
7101
|
return "--rebase-onto-head and --override-stale are mutually exclusive — re-stamp to head, or override in place, not both";
|
|
7060
7102
|
}
|
|
7103
|
+
if (noOpen && mode !== "content" && mode !== "apply") {
|
|
7104
|
+
return "--no-open is only valid for a content deploy or --apply";
|
|
7105
|
+
}
|
|
7061
7106
|
if (mode === "dry-run") {
|
|
7062
7107
|
if (slug !== null)
|
|
7063
7108
|
return "--dry-run does not accept --slug (slug is read from launchpad.yaml)";
|
|
@@ -7114,7 +7159,8 @@ function parseDeployFlags(args) {
|
|
|
7114
7159
|
timeoutMinutes
|
|
7115
7160
|
},
|
|
7116
7161
|
message: null,
|
|
7117
|
-
timeoutSeconds: null
|
|
7162
|
+
timeoutSeconds: null,
|
|
7163
|
+
...noOpen ? { noOpen: true } : {}
|
|
7118
7164
|
};
|
|
7119
7165
|
}
|
|
7120
7166
|
if (resumePrNumber !== null) {
|
|
@@ -7155,7 +7201,8 @@ function parseDeployFlags(args) {
|
|
|
7155
7201
|
allowUnguarded
|
|
7156
7202
|
},
|
|
7157
7203
|
message,
|
|
7158
|
-
timeoutSeconds
|
|
7204
|
+
timeoutSeconds,
|
|
7205
|
+
...noOpen ? { noOpen: true } : {}
|
|
7159
7206
|
};
|
|
7160
7207
|
}
|
|
7161
7208
|
if (mode === "resume" || mode === "abandon") {
|
|
@@ -7209,12 +7256,12 @@ import { existsSync as existsSync6, rmSync } from "node:fs";
|
|
|
7209
7256
|
import { resolve as resolvePath, join as join10 } from "node:path";
|
|
7210
7257
|
|
|
7211
7258
|
// src/manifest/load.ts
|
|
7212
|
-
import { readFileSync as
|
|
7259
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
7213
7260
|
import { parse as parseYaml5, YAMLParseError } from "yaml";
|
|
7214
7261
|
function loadManifest(path8) {
|
|
7215
7262
|
let raw;
|
|
7216
7263
|
try {
|
|
7217
|
-
raw =
|
|
7264
|
+
raw = readFileSync10(path8, "utf8");
|
|
7218
7265
|
} catch (err) {
|
|
7219
7266
|
const e = err;
|
|
7220
7267
|
if (e.code === "ENOENT") {
|
|
@@ -7249,6 +7296,38 @@ function formatIssues(error) {
|
|
|
7249
7296
|
}));
|
|
7250
7297
|
}
|
|
7251
7298
|
|
|
7299
|
+
// src/status-page-output.ts
|
|
7300
|
+
async function surfaceStatusPageUrl(url, io, options) {
|
|
7301
|
+
if (typeof url !== "string" || url.length === 0)
|
|
7302
|
+
return;
|
|
7303
|
+
io.out(`Status page: ${url}`);
|
|
7304
|
+
const env = options.env ?? process.env;
|
|
7305
|
+
const isTty = options.isTty ?? process.stdout.isTTY === true;
|
|
7306
|
+
if (options.noOpen || !options.autoOpenEnabled || !isTty || env.CI !== undefined) {
|
|
7307
|
+
return;
|
|
7308
|
+
}
|
|
7309
|
+
if (!isAllowedStatusPageUrl(url, options.allowedHost)) {
|
|
7310
|
+
io.err("warning: refused to open an untrusted status page URL");
|
|
7311
|
+
return;
|
|
7312
|
+
}
|
|
7313
|
+
try {
|
|
7314
|
+
await (options.open ?? openBrowser)(url);
|
|
7315
|
+
} catch (error) {
|
|
7316
|
+
io.err(`warning: couldn't open the status page automatically: ${describe13(error)}`);
|
|
7317
|
+
}
|
|
7318
|
+
}
|
|
7319
|
+
function isAllowedStatusPageUrl(url, allowedHost) {
|
|
7320
|
+
try {
|
|
7321
|
+
const parsed = new URL(url);
|
|
7322
|
+
return parsed.protocol === "https:" && (allowedHost === undefined || parsed.hostname === allowedHost);
|
|
7323
|
+
} catch {
|
|
7324
|
+
return false;
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7327
|
+
function describe13(error) {
|
|
7328
|
+
return error instanceof Error ? error.message : String(error);
|
|
7329
|
+
}
|
|
7330
|
+
|
|
7252
7331
|
// src/deploy/apply.ts
|
|
7253
7332
|
var DEFAULT_TIMEOUT_MINUTES = 90;
|
|
7254
7333
|
var DEFAULT_POLL_INTERVAL_SECONDS = 10;
|
|
@@ -7383,6 +7462,11 @@ async function runDeployApply(opts, io, deps = {}) {
|
|
|
7383
7462
|
io.err(`launchpad deploy --apply: protocol failure from /apps/${slug}/manifest/apply: ` + `requested ${manifestSha}, received ${String(apply.manifestSha)}`);
|
|
7384
7463
|
return 2;
|
|
7385
7464
|
}
|
|
7465
|
+
await surfaceStatusPageUrl(apply.statusPageUrl, io, {
|
|
7466
|
+
noOpen: opts.noOpen === true,
|
|
7467
|
+
autoOpenEnabled: cfg.statusPageAutoOpen,
|
|
7468
|
+
allowedHost: cfg.statusPageHost
|
|
7469
|
+
});
|
|
7386
7470
|
io.out("");
|
|
7387
7471
|
io.out(`PR opened: ${apply.prUrl}`);
|
|
7388
7472
|
io.out(`Branch: ${apply.branch}`);
|
|
@@ -7457,7 +7541,7 @@ async function pollUntilApplied(args) {
|
|
|
7457
7541
|
breakDots();
|
|
7458
7542
|
return { kind: "failed", reason: e.message };
|
|
7459
7543
|
}
|
|
7460
|
-
args.io.err(`! apply-status fetch failed (will retry): ${
|
|
7544
|
+
args.io.err(`! apply-status fetch failed (will retry): ${describe14(e)}`);
|
|
7461
7545
|
await sleep(args.pollIntervalSec * 1000);
|
|
7462
7546
|
continue;
|
|
7463
7547
|
}
|
|
@@ -7504,7 +7588,7 @@ async function pollUntilApplied(args) {
|
|
|
7504
7588
|
path: `/apps/${args.slug}/manifest/state`
|
|
7505
7589
|
}, args.fetcher);
|
|
7506
7590
|
} catch (e) {
|
|
7507
|
-
args.io.err(`! state fetch failed (will retry): ${
|
|
7591
|
+
args.io.err(`! state fetch failed (will retry): ${describe14(e)}`);
|
|
7508
7592
|
await sleep(args.pollIntervalSec * 1000);
|
|
7509
7593
|
continue;
|
|
7510
7594
|
}
|
|
@@ -7578,7 +7662,7 @@ function deletePinIfPresent(cfg, slug, io) {
|
|
|
7578
7662
|
rmSync(pinPath, { force: true });
|
|
7579
7663
|
io.out(` (cleaned up obsolete pin file ${pinPath})`);
|
|
7580
7664
|
} catch (e) {
|
|
7581
|
-
io.err(`! warning: failed to delete obsolete pin file ${pinPath}: ${
|
|
7665
|
+
io.err(`! warning: failed to delete obsolete pin file ${pinPath}: ${describe14(e)}`);
|
|
7582
7666
|
}
|
|
7583
7667
|
}
|
|
7584
7668
|
async function loadSlugForResume(opts, io) {
|
|
@@ -7602,7 +7686,7 @@ async function defaultPrompt(question) {
|
|
|
7602
7686
|
rl.close();
|
|
7603
7687
|
}
|
|
7604
7688
|
}
|
|
7605
|
-
function
|
|
7689
|
+
function describe14(e) {
|
|
7606
7690
|
return e instanceof Error ? e.message : String(e);
|
|
7607
7691
|
}
|
|
7608
7692
|
function mapHttpError(e, slug, io) {
|
|
@@ -7626,7 +7710,7 @@ function mapHttpError(e, slug, io) {
|
|
|
7626
7710
|
io.err(`launchpad deploy --apply: ${e.message}`);
|
|
7627
7711
|
return 1;
|
|
7628
7712
|
}
|
|
7629
|
-
io.err(`launchpad deploy --apply failed: ${
|
|
7713
|
+
io.err(`launchpad deploy --apply failed: ${describe14(e)}`);
|
|
7630
7714
|
return 2;
|
|
7631
7715
|
}
|
|
7632
7716
|
function renderManifestError(loaded, io) {
|
|
@@ -7669,7 +7753,7 @@ function renderAccessDriftSummary(slug, body) {
|
|
|
7669
7753
|
return lines;
|
|
7670
7754
|
}
|
|
7671
7755
|
async function handleAccessDrift(params) {
|
|
7672
|
-
const { slug, manifestPath, body, io, deps, outcome } = params;
|
|
7756
|
+
const { slug, manifestPath, body, io, deps, noOpen, outcome } = params;
|
|
7673
7757
|
if (outcome === undefined) {
|
|
7674
7758
|
for (const line of renderAccessDriftSummary(slug, body))
|
|
7675
7759
|
io.err(line);
|
|
@@ -7685,6 +7769,7 @@ async function handleAccessDrift(params) {
|
|
|
7685
7769
|
platformRepo: null,
|
|
7686
7770
|
rePin: false,
|
|
7687
7771
|
yes: true,
|
|
7772
|
+
noOpen,
|
|
7688
7773
|
...outcome === undefined ? {} : { atSha: outcome.manifest_sha },
|
|
7689
7774
|
...outcome?.pr === undefined ? {} : {
|
|
7690
7775
|
preopenedPr: {
|
|
@@ -7725,7 +7810,7 @@ async function runDeployDryRun(opts, io, deps = {}) {
|
|
|
7725
7810
|
try {
|
|
7726
7811
|
manifestSha = (deps.gitHeadSha ?? defaultGitHeadSha)(process.cwd());
|
|
7727
7812
|
} catch (e) {
|
|
7728
|
-
const msg = `failed to resolve git HEAD in ${process.cwd()}: ${
|
|
7813
|
+
const msg = `failed to resolve git HEAD in ${process.cwd()}: ${describe15(e)}`;
|
|
7729
7814
|
if (opts.json) {
|
|
7730
7815
|
io.out(JSON.stringify({ ok: false, kind: "git-error", message: msg }));
|
|
7731
7816
|
} else {
|
|
@@ -7774,7 +7859,7 @@ function defaultGitHeadSha(cwd) {
|
|
|
7774
7859
|
});
|
|
7775
7860
|
return out.trim();
|
|
7776
7861
|
}
|
|
7777
|
-
function
|
|
7862
|
+
function describe15(e) {
|
|
7778
7863
|
return e instanceof Error ? e.message : String(e);
|
|
7779
7864
|
}
|
|
7780
7865
|
function mapHttpError2(e, slug, json, io) {
|
|
@@ -8086,7 +8171,7 @@ function validateContainerFilesystem(manifestPath, capability) {
|
|
|
8086
8171
|
try {
|
|
8087
8172
|
stat = lstatSync3(current);
|
|
8088
8173
|
} catch (error) {
|
|
8089
|
-
return failure("container_image_unreadable", relative3(root, current), `cannot inspect container image path: ${
|
|
8174
|
+
return failure("container_image_unreadable", relative3(root, current), `cannot inspect container image path: ${describe16(error)}`);
|
|
8090
8175
|
}
|
|
8091
8176
|
if (stat.isSymbolicLink()) {
|
|
8092
8177
|
return failure("container_image_symlink", relative3(root, current), "container image path must not contain symbolic links");
|
|
@@ -8096,7 +8181,7 @@ function validateContainerFilesystem(manifestPath, capability) {
|
|
|
8096
8181
|
try {
|
|
8097
8182
|
finalPath = realpathSync(current);
|
|
8098
8183
|
} catch (error) {
|
|
8099
|
-
return failure("container_image_unreadable", relative3(root, current), `cannot resolve container image path: ${
|
|
8184
|
+
return failure("container_image_unreadable", relative3(root, current), `cannot resolve container image path: ${describe16(error)}`);
|
|
8100
8185
|
}
|
|
8101
8186
|
const rootPrefix = resolve9(root) + sep2;
|
|
8102
8187
|
if (!resolve9(finalPath).startsWith(rootPrefix)) {
|
|
@@ -8110,7 +8195,7 @@ function validateContainerFilesystem(manifestPath, capability) {
|
|
|
8110
8195
|
function failure(reason, path8, message) {
|
|
8111
8196
|
return { kind: "error", reason, path: path8, message };
|
|
8112
8197
|
}
|
|
8113
|
-
function
|
|
8198
|
+
function describe16(error) {
|
|
8114
8199
|
return error instanceof Error ? error.message : String(error);
|
|
8115
8200
|
}
|
|
8116
8201
|
|
|
@@ -8179,7 +8264,8 @@ async function runDeploy(args, io) {
|
|
|
8179
8264
|
yes: flags.mode.yes,
|
|
8180
8265
|
...flags.mode.atSha !== null ? { atSha: flags.mode.atSha } : {},
|
|
8181
8266
|
...flags.mode.resumePrNumber !== null ? { resumePrNumber: flags.mode.resumePrNumber } : {},
|
|
8182
|
-
...flags.mode.timeoutMinutes !== null ? { timeoutMinutes: flags.mode.timeoutMinutes } : {}
|
|
8267
|
+
...flags.mode.timeoutMinutes !== null ? { timeoutMinutes: flags.mode.timeoutMinutes } : {},
|
|
8268
|
+
noOpen: flags.noOpen === true
|
|
8183
8269
|
}, io);
|
|
8184
8270
|
}
|
|
8185
8271
|
if (flags.mode.kind === "abandon") {
|
|
@@ -8215,7 +8301,8 @@ async function runDeploy(args, io) {
|
|
|
8215
8301
|
allowStale: contentMode.allowStale,
|
|
8216
8302
|
rebaseOntoHead: contentMode.rebaseOntoHead,
|
|
8217
8303
|
overrideStale: contentMode.overrideStale,
|
|
8218
|
-
allowUnguarded: contentMode.allowUnguarded
|
|
8304
|
+
allowUnguarded: contentMode.allowUnguarded,
|
|
8305
|
+
noOpen: flags.noOpen === true
|
|
8219
8306
|
});
|
|
8220
8307
|
}
|
|
8221
8308
|
if (flags.mode.kind === "content" && flags.mode.allowUnguarded) {
|
|
@@ -8256,7 +8343,7 @@ async function runDeploy(args, io) {
|
|
|
8256
8343
|
const contentManifestPath = path8.join(process.cwd(), "launchpad.yaml");
|
|
8257
8344
|
if (existsSync7(contentManifestPath)) {
|
|
8258
8345
|
try {
|
|
8259
|
-
contentManifestYaml =
|
|
8346
|
+
contentManifestYaml = readFileSync11(contentManifestPath, "utf8");
|
|
8260
8347
|
} catch {
|
|
8261
8348
|
contentManifestYaml = null;
|
|
8262
8349
|
}
|
|
@@ -8289,6 +8376,11 @@ async function runDeploy(args, io) {
|
|
|
8289
8376
|
headers,
|
|
8290
8377
|
jsonBody: undefined
|
|
8291
8378
|
}, makeBytesFetcher(packed.bytes, `/apps/${slug}/deploy-pr`));
|
|
8379
|
+
await surfaceStatusPageUrl(response.statusPageUrl, io, {
|
|
8380
|
+
noOpen: flags.noOpen === true,
|
|
8381
|
+
autoOpenEnabled: cfg.statusPageAutoOpen,
|
|
8382
|
+
allowedHost: cfg.statusPageHost
|
|
8383
|
+
});
|
|
8292
8384
|
io.out("");
|
|
8293
8385
|
io.out(`PR opened: ${response.reviewUrl}`);
|
|
8294
8386
|
io.out(`Branch: ${response.branch}`);
|
|
@@ -8334,12 +8426,12 @@ async function runDeploy(args, io) {
|
|
|
8334
8426
|
io.err(`launchpad deploy: ${e.message}`);
|
|
8335
8427
|
return 1;
|
|
8336
8428
|
}
|
|
8337
|
-
io.err(`launchpad deploy failed: ${
|
|
8429
|
+
io.err(`launchpad deploy failed: ${describe17(e)}`);
|
|
8338
8430
|
return 1;
|
|
8339
8431
|
}
|
|
8340
8432
|
}
|
|
8341
8433
|
function deployUsage() {
|
|
8342
|
-
return `usage: launchpad deploy [--message <text>] [--slug <slug>] [--allow-unguarded]
|
|
8434
|
+
return `usage: launchpad deploy [--message <text>] [--slug <slug>] [--allow-unguarded] [--no-open]
|
|
8343
8435
|
` + ` (slug comes from launchpad.yaml at cwd when present — Model A —
|
|
8344
8436
|
` + " else from the current directory's `launchpad-app-<slug>` suffix)\n" + `
|
|
8345
8437
|
` + `provisioning modes:
|
|
@@ -8377,6 +8469,10 @@ function parseArgs3(args) {
|
|
|
8377
8469
|
i += 2;
|
|
8378
8470
|
continue;
|
|
8379
8471
|
}
|
|
8472
|
+
if (a === "--no-open") {
|
|
8473
|
+
i += 1;
|
|
8474
|
+
continue;
|
|
8475
|
+
}
|
|
8380
8476
|
return null;
|
|
8381
8477
|
}
|
|
8382
8478
|
return { slug, message };
|
|
@@ -8405,7 +8501,7 @@ function formatBytes2(n) {
|
|
|
8405
8501
|
return `${(n / 1024).toFixed(1)}KB`;
|
|
8406
8502
|
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
8407
8503
|
}
|
|
8408
|
-
function
|
|
8504
|
+
function describe17(e) {
|
|
8409
8505
|
return e instanceof Error ? e.message : String(e);
|
|
8410
8506
|
}
|
|
8411
8507
|
function surfaceDeployExtras(body, io, slug, allowStale = false) {
|
|
@@ -8491,7 +8587,7 @@ function withTimeout(p, ms) {
|
|
|
8491
8587
|
async function surfaceManifestDiff(cfg, slug, manifestPath, io) {
|
|
8492
8588
|
let localYaml;
|
|
8493
8589
|
try {
|
|
8494
|
-
localYaml =
|
|
8590
|
+
localYaml = readFileSync11(manifestPath, "utf8");
|
|
8495
8591
|
} catch {
|
|
8496
8592
|
return;
|
|
8497
8593
|
}
|
|
@@ -8528,7 +8624,7 @@ async function advanceBaseShaMarker(cwd, sha, io) {
|
|
|
8528
8624
|
return;
|
|
8529
8625
|
await writeBaseShaMarker(cwd, sha);
|
|
8530
8626
|
} catch (e) {
|
|
8531
|
-
io.err(`warning: couldn't update the local base-sha marker (${
|
|
8627
|
+
io.err(`warning: couldn't update the local base-sha marker (${describe17(e)}); ` + `a future deploy may re-warn about staleness. Harmless — your deploy landed.`);
|
|
8532
8628
|
}
|
|
8533
8629
|
}
|
|
8534
8630
|
async function runModelADeploy(args) {
|
|
@@ -8536,7 +8632,7 @@ async function runModelADeploy(args) {
|
|
|
8536
8632
|
let slug;
|
|
8537
8633
|
let appType = "static";
|
|
8538
8634
|
try {
|
|
8539
|
-
const manifestObj = parseYaml6(
|
|
8635
|
+
const manifestObj = parseYaml6(readFileSync11(manifestPath, "utf8"));
|
|
8540
8636
|
const metaSlug = resolveManifestSlug(manifestObj);
|
|
8541
8637
|
if (metaSlug === null) {
|
|
8542
8638
|
io.err(`launchpad deploy: launchpad.yaml is missing metadata.slug (v2) / metadata.name (v1). ` + `Run \`launchpad init\` again to regenerate the manifest.`);
|
|
@@ -8566,7 +8662,7 @@ async function runModelADeploy(args) {
|
|
|
8566
8662
|
}
|
|
8567
8663
|
}
|
|
8568
8664
|
} catch (e) {
|
|
8569
|
-
io.err(`launchpad deploy: failed to read ${manifestPath}: ${
|
|
8665
|
+
io.err(`launchpad deploy: failed to read ${manifestPath}: ${describe17(e)}`);
|
|
8570
8666
|
return 1;
|
|
8571
8667
|
}
|
|
8572
8668
|
const noVerify = args.argv.includes("--no-verify");
|
|
@@ -8596,7 +8692,7 @@ async function runModelADeploy(args) {
|
|
|
8596
8692
|
try {
|
|
8597
8693
|
cfg = loadConfig();
|
|
8598
8694
|
} catch (e) {
|
|
8599
|
-
io.err(`launchpad deploy: ${
|
|
8695
|
+
io.err(`launchpad deploy: ${describe17(e)}`);
|
|
8600
8696
|
return 1;
|
|
8601
8697
|
}
|
|
8602
8698
|
try {
|
|
@@ -8646,7 +8742,7 @@ async function runModelADeploy(args) {
|
|
|
8646
8742
|
io.err(" run `launchpad login` to refresh your session.");
|
|
8647
8743
|
return 1;
|
|
8648
8744
|
}
|
|
8649
|
-
io.err(`launchpad deploy: unexpected error: ${
|
|
8745
|
+
io.err(`launchpad deploy: unexpected error: ${describe17(e)}`);
|
|
8650
8746
|
return 1;
|
|
8651
8747
|
}
|
|
8652
8748
|
switch (result.kind) {
|
|
@@ -8667,6 +8763,11 @@ async function runModelADeploy(args) {
|
|
|
8667
8763
|
return 1;
|
|
8668
8764
|
case "upload-error": {
|
|
8669
8765
|
const body = result.body;
|
|
8766
|
+
await surfaceStatusPageUrl(body.statusPageUrl, io, {
|
|
8767
|
+
noOpen: args.noOpen,
|
|
8768
|
+
autoOpenEnabled: cfg.statusPageAutoOpen,
|
|
8769
|
+
allowedHost: cfg.statusPageHost
|
|
8770
|
+
});
|
|
8670
8771
|
const errorCode = body.error;
|
|
8671
8772
|
if (result.status === 426 && typeof body.minimum === "string" && typeof body.yours === "string") {
|
|
8672
8773
|
io.err(upgradeRequiredMessage(body.minimum, body.yours));
|
|
@@ -8703,6 +8804,7 @@ async function runModelADeploy(args) {
|
|
|
8703
8804
|
manifestPath,
|
|
8704
8805
|
body,
|
|
8705
8806
|
io,
|
|
8807
|
+
noOpen: args.noOpen,
|
|
8706
8808
|
deps: { runApply: runDeployApply }
|
|
8707
8809
|
});
|
|
8708
8810
|
}
|
|
@@ -8720,6 +8822,7 @@ async function runModelADeploy(args) {
|
|
|
8720
8822
|
body,
|
|
8721
8823
|
outcome,
|
|
8722
8824
|
io,
|
|
8825
|
+
noOpen: args.noOpen,
|
|
8723
8826
|
deps: { runApply: runDeployApply }
|
|
8724
8827
|
});
|
|
8725
8828
|
if (accessExit !== 0)
|
|
@@ -8763,6 +8866,11 @@ async function runModelADeploy(args) {
|
|
|
8763
8866
|
io.err(`warning: ${w}`);
|
|
8764
8867
|
}
|
|
8765
8868
|
const success = result.result;
|
|
8869
|
+
await surfaceStatusPageUrl(success.statusPageUrl, io, {
|
|
8870
|
+
noOpen: args.noOpen,
|
|
8871
|
+
autoOpenEnabled: cfg.statusPageAutoOpen,
|
|
8872
|
+
allowedHost: cfg.statusPageHost
|
|
8873
|
+
});
|
|
8766
8874
|
if ("outcome" in success) {
|
|
8767
8875
|
io.out("Nothing to deploy — your app is already live at this content.");
|
|
8768
8876
|
if (typeof success.head_sha === "string") {
|
|
@@ -8807,6 +8915,7 @@ async function runModelADeploy(args) {
|
|
|
8807
8915
|
body: {},
|
|
8808
8916
|
outcome: success.reconcile,
|
|
8809
8917
|
io,
|
|
8918
|
+
noOpen: args.noOpen,
|
|
8810
8919
|
deps: { runApply: runDeployApply }
|
|
8811
8920
|
});
|
|
8812
8921
|
if (accessExit !== 0)
|
|
@@ -8858,7 +8967,7 @@ function pendingReconcileOutcome(body) {
|
|
|
8858
8967
|
}
|
|
8859
8968
|
|
|
8860
8969
|
// src/commands/redeploy.ts
|
|
8861
|
-
import { existsSync as existsSync8, readFileSync as
|
|
8970
|
+
import { existsSync as existsSync8, readFileSync as readFileSync12 } from "node:fs";
|
|
8862
8971
|
import { resolve as resolvePath2 } from "node:path";
|
|
8863
8972
|
import { parse as parseYaml7 } from "yaml";
|
|
8864
8973
|
var SLUG_RE6 = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
|
|
@@ -8939,7 +9048,7 @@ function readLocalAppType(cwd, file) {
|
|
|
8939
9048
|
if (!existsSync8(manifestPath))
|
|
8940
9049
|
return null;
|
|
8941
9050
|
try {
|
|
8942
|
-
const obj = parseYaml7(
|
|
9051
|
+
const obj = parseYaml7(readFileSync12(manifestPath, "utf8"));
|
|
8943
9052
|
return coerceAppType(obj?.deployment?.type);
|
|
8944
9053
|
} catch {
|
|
8945
9054
|
return null;
|
|
@@ -9121,7 +9230,7 @@ async function runEnvvars(args, io) {
|
|
|
9121
9230
|
io.err(`launchpad envvars: ${e.message}`);
|
|
9122
9231
|
return 1;
|
|
9123
9232
|
}
|
|
9124
|
-
io.err(`launchpad envvars failed: ${
|
|
9233
|
+
io.err(`launchpad envvars failed: ${describe18(e)}`);
|
|
9125
9234
|
return 1;
|
|
9126
9235
|
}
|
|
9127
9236
|
}
|
|
@@ -9218,12 +9327,12 @@ function renderList(envVars, io) {
|
|
|
9218
9327
|
io.out(fmt(row));
|
|
9219
9328
|
}
|
|
9220
9329
|
}
|
|
9221
|
-
function
|
|
9330
|
+
function describe18(e) {
|
|
9222
9331
|
return e instanceof Error ? e.message : String(e);
|
|
9223
9332
|
}
|
|
9224
9333
|
|
|
9225
9334
|
// src/commands/generate.ts
|
|
9226
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
9335
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync13, writeFileSync as writeFileSync2 } from "node:fs";
|
|
9227
9336
|
import { dirname as dirname7, resolve as resolve10, relative as relative4 } from "node:path";
|
|
9228
9337
|
var generateCommand = {
|
|
9229
9338
|
name: "generate",
|
|
@@ -9328,7 +9437,7 @@ function applyOne(artefact, path10, out, force) {
|
|
|
9328
9437
|
}
|
|
9329
9438
|
function readIfExists(path10) {
|
|
9330
9439
|
try {
|
|
9331
|
-
return { kind: "ok", content:
|
|
9440
|
+
return { kind: "ok", content: readFileSync13(path10, "utf8") };
|
|
9332
9441
|
} catch (err) {
|
|
9333
9442
|
const e = err;
|
|
9334
9443
|
if (e.code === "ENOENT")
|
|
@@ -9552,13 +9661,13 @@ function decodeJwtPayload(token) {
|
|
|
9552
9661
|
try {
|
|
9553
9662
|
json = Buffer.from(b64UrlToB64(payload), "base64").toString("utf8");
|
|
9554
9663
|
} catch (e) {
|
|
9555
|
-
throw new JwtParseError(`could not base64-decode JWT payload: ${
|
|
9664
|
+
throw new JwtParseError(`could not base64-decode JWT payload: ${describe19(e)}`);
|
|
9556
9665
|
}
|
|
9557
9666
|
let parsed;
|
|
9558
9667
|
try {
|
|
9559
9668
|
parsed = JSON.parse(json);
|
|
9560
9669
|
} catch (e) {
|
|
9561
|
-
throw new JwtParseError(`JWT payload is not JSON: ${
|
|
9670
|
+
throw new JwtParseError(`JWT payload is not JSON: ${describe19(e)}`);
|
|
9562
9671
|
}
|
|
9563
9672
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
9564
9673
|
throw new JwtParseError(`JWT payload is not an object`);
|
|
@@ -9569,7 +9678,7 @@ function b64UrlToB64(s) {
|
|
|
9569
9678
|
const padded = s.padEnd(s.length + (4 - s.length % 4) % 4, "=");
|
|
9570
9679
|
return padded.replace(/-/g, "+").replace(/_/g, "/");
|
|
9571
9680
|
}
|
|
9572
|
-
function
|
|
9681
|
+
function describe19(e) {
|
|
9573
9682
|
return e instanceof Error ? e.message : String(e);
|
|
9574
9683
|
}
|
|
9575
9684
|
|
|
@@ -9596,7 +9705,7 @@ async function runGroupsWhoami(args, io) {
|
|
|
9596
9705
|
try {
|
|
9597
9706
|
payload = decodeJwtPayload(session.accessToken);
|
|
9598
9707
|
} catch (e) {
|
|
9599
|
-
const message = e instanceof JwtParseError ? e.message :
|
|
9708
|
+
const message = e instanceof JwtParseError ? e.message : describe20(e);
|
|
9600
9709
|
if (json) {
|
|
9601
9710
|
io.out(JSON.stringify({ ok: false, kind: "jwt-parse-error", message }));
|
|
9602
9711
|
} else {
|
|
@@ -9677,7 +9786,7 @@ function parseFlags2(args) {
|
|
|
9677
9786
|
}
|
|
9678
9787
|
return { kind: "ok", json };
|
|
9679
9788
|
}
|
|
9680
|
-
function
|
|
9789
|
+
function describe20(e) {
|
|
9681
9790
|
return e instanceof Error ? e.message : String(e);
|
|
9682
9791
|
}
|
|
9683
9792
|
|
|
@@ -9780,7 +9889,7 @@ async function loadGroups(io, refresh, json) {
|
|
|
9780
9889
|
}
|
|
9781
9890
|
return { kind: "error", code: 3 };
|
|
9782
9891
|
}
|
|
9783
|
-
renderFetchError(io,
|
|
9892
|
+
renderFetchError(io, describe21(e), json);
|
|
9784
9893
|
return { kind: "error", code: 2 };
|
|
9785
9894
|
}
|
|
9786
9895
|
}
|
|
@@ -9817,7 +9926,7 @@ async function lookupTenantWide(key) {
|
|
|
9817
9926
|
return { kind: "unauthenticated", message: e.message };
|
|
9818
9927
|
if (e instanceof ForbiddenError)
|
|
9819
9928
|
return { kind: "forbidden", message: e.message };
|
|
9820
|
-
return { kind: "error", message:
|
|
9929
|
+
return { kind: "error", message: describe21(e) };
|
|
9821
9930
|
}
|
|
9822
9931
|
}
|
|
9823
9932
|
function renderLookupFailure(io, json, hit) {
|
|
@@ -10061,18 +10170,18 @@ function renderTable2(io, groups) {
|
|
|
10061
10170
|
for (const r of rows)
|
|
10062
10171
|
io.out(fmt(r));
|
|
10063
10172
|
}
|
|
10064
|
-
function
|
|
10173
|
+
function describe21(e) {
|
|
10065
10174
|
return e instanceof Error ? e.message : String(e);
|
|
10066
10175
|
}
|
|
10067
10176
|
|
|
10068
10177
|
// src/commands/init.ts
|
|
10069
10178
|
import { createInterface } from "node:readline/promises";
|
|
10070
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as
|
|
10179
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync15, writeFileSync as writeFileSync3 } from "node:fs";
|
|
10071
10180
|
import { dirname as dirname8, resolve as resolve11 } from "node:path";
|
|
10072
10181
|
import { stringify as yamlStringify } from "yaml";
|
|
10073
10182
|
|
|
10074
10183
|
// src/detect/index.ts
|
|
10075
|
-
import { existsSync as existsSync9, readFileSync as
|
|
10184
|
+
import { existsSync as existsSync9, readFileSync as readFileSync14, statSync } from "node:fs";
|
|
10076
10185
|
import { join as join13 } from "node:path";
|
|
10077
10186
|
function detectAppShape(cwd) {
|
|
10078
10187
|
const hasPackageJson = existsSync9(join13(cwd, "package.json"));
|
|
@@ -10177,7 +10286,7 @@ function detectBuildCommand(cwd, pm) {
|
|
|
10177
10286
|
}
|
|
10178
10287
|
let pkgJson;
|
|
10179
10288
|
try {
|
|
10180
|
-
pkgJson = JSON.parse(
|
|
10289
|
+
pkgJson = JSON.parse(readFileSync14(pkgJsonPath, "utf8"));
|
|
10181
10290
|
} catch (e) {
|
|
10182
10291
|
return {
|
|
10183
10292
|
kind: "ambiguous",
|
|
@@ -10212,7 +10321,7 @@ var OUT_DIR_REGEX = /\bbuild\s*:\s*\{[^{}]*?\boutDir\s*:\s*['"]([^'"]+)['"]/s;
|
|
|
10212
10321
|
function detectDestinationDir(cwd, vite) {
|
|
10213
10322
|
let text;
|
|
10214
10323
|
try {
|
|
10215
|
-
text =
|
|
10324
|
+
text = readFileSync14(vite.path, "utf8");
|
|
10216
10325
|
} catch (e) {
|
|
10217
10326
|
return {
|
|
10218
10327
|
kind: "ambiguous",
|
|
@@ -10699,7 +10808,7 @@ function renderYaml(manifest) {
|
|
|
10699
10808
|
function ensureGitignoreEntries(path10, entries) {
|
|
10700
10809
|
let current = "";
|
|
10701
10810
|
if (existsSync10(path10)) {
|
|
10702
|
-
current =
|
|
10811
|
+
current = readFileSync15(path10, "utf8");
|
|
10703
10812
|
}
|
|
10704
10813
|
const lines = current.split(/\r?\n/);
|
|
10705
10814
|
const present = new Set(lines.map((l) => l.trim()));
|
|
@@ -10772,13 +10881,13 @@ async function runLogin(args, io, deps) {
|
|
|
10772
10881
|
io.out(`Access token expires in ~${expiresIn}s; refreshes silently.`);
|
|
10773
10882
|
return 0;
|
|
10774
10883
|
} catch (e) {
|
|
10775
|
-
io.err(`Gateway login failed: ${
|
|
10884
|
+
io.err(`Gateway login failed: ${describe22(e)}`);
|
|
10776
10885
|
io.err("Falling back to the legacy Cloudflare Access flow (DEPRECATED — this fallback will be removed when the dual-auth window closes).");
|
|
10777
10886
|
io.err("");
|
|
10778
10887
|
return await runLegacyLogin(io, cfg.botUrl, cfg.sessionPath, deps);
|
|
10779
10888
|
}
|
|
10780
10889
|
} catch (e) {
|
|
10781
|
-
io.err(`launchpad login failed: ${
|
|
10890
|
+
io.err(`launchpad login failed: ${describe22(e)}`);
|
|
10782
10891
|
return 1;
|
|
10783
10892
|
}
|
|
10784
10893
|
}
|
|
@@ -10820,7 +10929,7 @@ function printLoginHelp(io) {
|
|
|
10820
10929
|
io.out(" 0 signed in / session stored");
|
|
10821
10930
|
io.out(" 1 login failed (network, browser, or gateway error)");
|
|
10822
10931
|
}
|
|
10823
|
-
function
|
|
10932
|
+
function describe22(e) {
|
|
10824
10933
|
return e instanceof Error ? e.message : String(e);
|
|
10825
10934
|
}
|
|
10826
10935
|
|
|
@@ -10857,14 +10966,14 @@ async function runLogout(args, io, deps) {
|
|
|
10857
10966
|
});
|
|
10858
10967
|
io.out("Server-side session revoked.");
|
|
10859
10968
|
} catch (e) {
|
|
10860
|
-
io.err(`warning: could not revoke the session server-side (${
|
|
10969
|
+
io.err(`warning: could not revoke the session server-side (${describe23(e)}) — clearing the local session anyway. Any in-flight access token expires within 15 minutes.`);
|
|
10861
10970
|
}
|
|
10862
10971
|
}
|
|
10863
10972
|
const had = await clearSession(cfg.sessionPath);
|
|
10864
10973
|
io.out(had ? `Logged out. Session cleared at ${cfg.sessionPath}` : "Already logged out.");
|
|
10865
10974
|
return 0;
|
|
10866
10975
|
} catch (e) {
|
|
10867
|
-
io.err(`launchpad logout failed: ${
|
|
10976
|
+
io.err(`launchpad logout failed: ${describe23(e)}`);
|
|
10868
10977
|
return 1;
|
|
10869
10978
|
}
|
|
10870
10979
|
}
|
|
@@ -10884,7 +10993,7 @@ function printLogoutHelp(io) {
|
|
|
10884
10993
|
io.out(" 0 logged out (or already logged out)");
|
|
10885
10994
|
io.out(" 1 could not clear the local session (file IO / config error)");
|
|
10886
10995
|
}
|
|
10887
|
-
function
|
|
10996
|
+
function describe23(e) {
|
|
10888
10997
|
return e instanceof Error ? e.message : String(e);
|
|
10889
10998
|
}
|
|
10890
10999
|
|
|
@@ -10954,7 +11063,7 @@ async function runLogs(args, io) {
|
|
|
10954
11063
|
io.err(`launchpad logs: ${e.message}`);
|
|
10955
11064
|
return 1;
|
|
10956
11065
|
}
|
|
10957
|
-
io.err(`launchpad logs failed: ${
|
|
11066
|
+
io.err(`launchpad logs failed: ${describe24(e)}`);
|
|
10958
11067
|
return 1;
|
|
10959
11068
|
}
|
|
10960
11069
|
}
|
|
@@ -11034,7 +11143,7 @@ function formatRelative2(iso) {
|
|
|
11034
11143
|
return `${hr}h ago`;
|
|
11035
11144
|
return `${Math.floor(hr / 24)}d ago`;
|
|
11036
11145
|
}
|
|
11037
|
-
function
|
|
11146
|
+
function describe24(e) {
|
|
11038
11147
|
return e instanceof Error ? e.message : String(e);
|
|
11039
11148
|
}
|
|
11040
11149
|
|
|
@@ -11083,7 +11192,7 @@ async function runMerge(args, io) {
|
|
|
11083
11192
|
try {
|
|
11084
11193
|
body = await res.json();
|
|
11085
11194
|
} catch (e) {
|
|
11086
|
-
io.err(`launchpad merge: bot returned 2xx with malformed body: ${
|
|
11195
|
+
io.err(`launchpad merge: bot returned 2xx with malformed body: ${describe25(e)}`);
|
|
11087
11196
|
return 1;
|
|
11088
11197
|
}
|
|
11089
11198
|
io.out("");
|
|
@@ -11123,7 +11232,7 @@ async function runMerge(args, io) {
|
|
|
11123
11232
|
io.err(`launchpad merge: ${e.message}`);
|
|
11124
11233
|
return 1;
|
|
11125
11234
|
}
|
|
11126
|
-
io.err(`launchpad merge failed: ${
|
|
11235
|
+
io.err(`launchpad merge failed: ${describe25(e)}`);
|
|
11127
11236
|
return 1;
|
|
11128
11237
|
}
|
|
11129
11238
|
}
|
|
@@ -11222,7 +11331,7 @@ function renderBotError(status, env, io, prNumber = null) {
|
|
|
11222
11331
|
io.err(`launchpad merge: bot returned ${status} ${code}${detail !== undefined ? `: ${detail}` : ""}`);
|
|
11223
11332
|
}
|
|
11224
11333
|
}
|
|
11225
|
-
function
|
|
11334
|
+
function describe25(e) {
|
|
11226
11335
|
return e instanceof Error ? e.message : String(e);
|
|
11227
11336
|
}
|
|
11228
11337
|
|
|
@@ -11485,7 +11594,7 @@ async function runDestroy(args, io, prompt, isTty) {
|
|
|
11485
11594
|
io.err(`launchpad destroy: ${e.message}`);
|
|
11486
11595
|
return 1;
|
|
11487
11596
|
}
|
|
11488
|
-
io.err(`launchpad destroy failed: ${
|
|
11597
|
+
io.err(`launchpad destroy failed: ${describe26(e)}`);
|
|
11489
11598
|
return 1;
|
|
11490
11599
|
}
|
|
11491
11600
|
}
|
|
@@ -11685,7 +11794,7 @@ function printUsage4(io) {
|
|
|
11685
11794
|
].join(`
|
|
11686
11795
|
`));
|
|
11687
11796
|
}
|
|
11688
|
-
function
|
|
11797
|
+
function describe26(e) {
|
|
11689
11798
|
return e instanceof Error ? e.message : String(e);
|
|
11690
11799
|
}
|
|
11691
11800
|
|
|
@@ -12255,7 +12364,7 @@ async function runPull(args, io) {
|
|
|
12255
12364
|
io.err(`launchpad pull: ${e.message}`);
|
|
12256
12365
|
return 1;
|
|
12257
12366
|
}
|
|
12258
|
-
io.err(`launchpad pull failed: ${
|
|
12367
|
+
io.err(`launchpad pull failed: ${describe27(e)}`);
|
|
12259
12368
|
return 1;
|
|
12260
12369
|
}
|
|
12261
12370
|
}
|
|
@@ -12363,7 +12472,7 @@ function printUsage5(io) {
|
|
|
12363
12472
|
].join(`
|
|
12364
12473
|
`));
|
|
12365
12474
|
}
|
|
12366
|
-
function
|
|
12475
|
+
function describe27(e) {
|
|
12367
12476
|
return e instanceof Error ? e.message : String(e);
|
|
12368
12477
|
}
|
|
12369
12478
|
|
|
@@ -12698,7 +12807,7 @@ async function runReview(args, io) {
|
|
|
12698
12807
|
io.err(`launchpad review: ${e.message}`);
|
|
12699
12808
|
return 1;
|
|
12700
12809
|
}
|
|
12701
|
-
io.err(`launchpad review failed: ${
|
|
12810
|
+
io.err(`launchpad review failed: ${describe28(e)}`);
|
|
12702
12811
|
return 1;
|
|
12703
12812
|
}
|
|
12704
12813
|
}
|
|
@@ -12776,12 +12885,12 @@ function severityRank(s) {
|
|
|
12776
12885
|
return 3;
|
|
12777
12886
|
}
|
|
12778
12887
|
}
|
|
12779
|
-
function
|
|
12888
|
+
function describe28(e) {
|
|
12780
12889
|
return e instanceof Error ? e.message : String(e);
|
|
12781
12890
|
}
|
|
12782
12891
|
|
|
12783
12892
|
// src/deploy/rollback.ts
|
|
12784
|
-
import { existsSync as existsSync11, readFileSync as
|
|
12893
|
+
import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync5 } from "node:fs";
|
|
12785
12894
|
import { resolve as resolvePath3 } from "node:path";
|
|
12786
12895
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
12787
12896
|
|
|
@@ -12836,7 +12945,7 @@ async function runRollback(opts, io, deps = {}) {
|
|
|
12836
12945
|
cwd: process.cwd()
|
|
12837
12946
|
});
|
|
12838
12947
|
} catch (e) {
|
|
12839
|
-
io.err(`launchpad rollback: git rev-parse failed to start: ${
|
|
12948
|
+
io.err(`launchpad rollback: git rev-parse failed to start: ${describe29(e)}`);
|
|
12840
12949
|
return 2;
|
|
12841
12950
|
}
|
|
12842
12951
|
if (revParse.exitCode !== 0) {
|
|
@@ -12851,7 +12960,7 @@ async function runRollback(opts, io, deps = {}) {
|
|
|
12851
12960
|
try {
|
|
12852
12961
|
show = await runner.run("git", ["show", `${verifiedSha}:${manifestRelpath}`], { cwd: process.cwd() });
|
|
12853
12962
|
} catch (e) {
|
|
12854
|
-
io.err(`launchpad rollback: git show failed to start: ${
|
|
12963
|
+
io.err(`launchpad rollback: git show failed to start: ${describe29(e)}`);
|
|
12855
12964
|
return 2;
|
|
12856
12965
|
}
|
|
12857
12966
|
if (show.exitCode !== 0) {
|
|
@@ -12885,7 +12994,7 @@ async function runRollback(opts, io, deps = {}) {
|
|
|
12885
12994
|
try {
|
|
12886
12995
|
writeFileSync5(manifestPath, historicalYaml, "utf8");
|
|
12887
12996
|
} catch (e) {
|
|
12888
|
-
io.err(`launchpad rollback: failed to write ${manifestPath}: ${
|
|
12997
|
+
io.err(`launchpad rollback: failed to write ${manifestPath}: ${describe29(e)}`);
|
|
12889
12998
|
return 2;
|
|
12890
12999
|
}
|
|
12891
13000
|
io.out(`Restored ${manifestPath} from ${verifiedSha.slice(0, 12)}.`);
|
|
@@ -12910,7 +13019,7 @@ function readCurrentManifest(path14) {
|
|
|
12910
13019
|
return null;
|
|
12911
13020
|
let raw;
|
|
12912
13021
|
try {
|
|
12913
|
-
raw =
|
|
13022
|
+
raw = readFileSync16(path14, "utf8");
|
|
12914
13023
|
} catch {
|
|
12915
13024
|
return null;
|
|
12916
13025
|
}
|
|
@@ -12967,7 +13076,7 @@ async function defaultPrompt4(question) {
|
|
|
12967
13076
|
rl.close();
|
|
12968
13077
|
}
|
|
12969
13078
|
}
|
|
12970
|
-
function
|
|
13079
|
+
function describe29(e) {
|
|
12971
13080
|
return e instanceof Error ? e.message : String(e);
|
|
12972
13081
|
}
|
|
12973
13082
|
function renderManifestError3(result, io) {
|
|
@@ -13066,7 +13175,7 @@ function parseArgs12(args) {
|
|
|
13066
13175
|
}
|
|
13067
13176
|
|
|
13068
13177
|
// src/secrets/push.ts
|
|
13069
|
-
import { existsSync as existsSync12, readFileSync as
|
|
13178
|
+
import { existsSync as existsSync12, readFileSync as readFileSync17 } from "node:fs";
|
|
13070
13179
|
import { resolve as resolvePath4 } from "node:path";
|
|
13071
13180
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
13072
13181
|
import { stdin as input2, stdout as output2 } from "node:process";
|
|
@@ -13130,9 +13239,9 @@ async function runSecretsPush(opts, io, deps = {}) {
|
|
|
13130
13239
|
}
|
|
13131
13240
|
let envText;
|
|
13132
13241
|
try {
|
|
13133
|
-
envText =
|
|
13242
|
+
envText = readFileSync17(envPath, "utf8");
|
|
13134
13243
|
} catch (e) {
|
|
13135
|
-
io.err(`launchpad secrets push: failed to read ${envPath}: ${
|
|
13244
|
+
io.err(`launchpad secrets push: failed to read ${envPath}: ${describe30(e)}`);
|
|
13136
13245
|
return 2;
|
|
13137
13246
|
}
|
|
13138
13247
|
const parsed = parseEnv(envText);
|
|
@@ -13316,10 +13425,10 @@ function mapPushError(e, slug, name, io) {
|
|
|
13316
13425
|
io.err(`✗ secrets push ${name}: ${e.message}`);
|
|
13317
13426
|
return 1;
|
|
13318
13427
|
}
|
|
13319
|
-
io.err(`✗ secrets push ${name} failed: ${
|
|
13428
|
+
io.err(`✗ secrets push ${name} failed: ${describe30(e)}`);
|
|
13320
13429
|
return 2;
|
|
13321
13430
|
}
|
|
13322
|
-
function
|
|
13431
|
+
function describe30(e) {
|
|
13323
13432
|
return e instanceof Error ? e.message : String(e);
|
|
13324
13433
|
}
|
|
13325
13434
|
function renderManifestError4(result, io) {
|
|
@@ -13455,7 +13564,7 @@ function renderManifestError5(result, io) {
|
|
|
13455
13564
|
}
|
|
13456
13565
|
|
|
13457
13566
|
// src/secrets/set.ts
|
|
13458
|
-
import { existsSync as existsSync13, readFileSync as
|
|
13567
|
+
import { existsSync as existsSync13, readFileSync as readFileSync18 } from "node:fs";
|
|
13459
13568
|
import { resolve as resolvePath6 } from "node:path";
|
|
13460
13569
|
import { parse as parseYaml8 } from "yaml";
|
|
13461
13570
|
var CELL_LABEL2 = {
|
|
@@ -13472,7 +13581,7 @@ function loadSet(fleetFile, setName, io) {
|
|
|
13472
13581
|
}
|
|
13473
13582
|
let obj;
|
|
13474
13583
|
try {
|
|
13475
|
-
obj = parseYaml8(
|
|
13584
|
+
obj = parseYaml8(readFileSync18(path14, "utf8"));
|
|
13476
13585
|
} catch (e) {
|
|
13477
13586
|
io.err(`✗ ${path14}`);
|
|
13478
13587
|
io.err(` YAML parse error: ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -13564,7 +13673,7 @@ async function runSecretsPushSet(opts, io, deps = {}) {
|
|
|
13564
13673
|
}
|
|
13565
13674
|
let envText;
|
|
13566
13675
|
try {
|
|
13567
|
-
envText =
|
|
13676
|
+
envText = readFileSync18(envPath, "utf8");
|
|
13568
13677
|
} catch (e) {
|
|
13569
13678
|
io.err(`launchpad secrets push --set: failed to read ${envPath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
13570
13679
|
return 2;
|
|
@@ -14034,7 +14143,7 @@ import { promises as fs7, existsSync as existsSync15 } from "node:fs";
|
|
|
14034
14143
|
// src/skills-bundle.ts
|
|
14035
14144
|
import { homedir as homedir2 } from "node:os";
|
|
14036
14145
|
import { join as join15 } from "node:path";
|
|
14037
|
-
import { readFileSync as
|
|
14146
|
+
import { readFileSync as readFileSync19, readdirSync as readdirSync2 } from "node:fs";
|
|
14038
14147
|
var SKILL_PREFIX = "launchpad-";
|
|
14039
14148
|
function skillsTargetDir() {
|
|
14040
14149
|
return process.env.LAUNCHPAD_SKILLS_TARGET_DIR ?? join15(homedir2(), ".claude", "skills");
|
|
@@ -14055,7 +14164,7 @@ function readInstalledSkills() {
|
|
|
14055
14164
|
}
|
|
14056
14165
|
function readSkillVersion(path14) {
|
|
14057
14166
|
try {
|
|
14058
|
-
const text =
|
|
14167
|
+
const text = readFileSync19(path14, "utf8");
|
|
14059
14168
|
const fenceEnd = text.indexOf(`
|
|
14060
14169
|
---`, 4);
|
|
14061
14170
|
const front = fenceEnd === -1 ? text.slice(0, 1024) : text.slice(0, fenceEnd);
|
|
@@ -14109,7 +14218,7 @@ async function runSkills(args, io) {
|
|
|
14109
14218
|
return 64;
|
|
14110
14219
|
}
|
|
14111
14220
|
} catch (e) {
|
|
14112
|
-
io.err(`launchpad skills ${action}: ${
|
|
14221
|
+
io.err(`launchpad skills ${action}: ${describe31(e)}`);
|
|
14113
14222
|
return 1;
|
|
14114
14223
|
}
|
|
14115
14224
|
}
|
|
@@ -14239,7 +14348,7 @@ async function isDir(path14) {
|
|
|
14239
14348
|
return false;
|
|
14240
14349
|
}
|
|
14241
14350
|
}
|
|
14242
|
-
function
|
|
14351
|
+
function describe31(e) {
|
|
14243
14352
|
return e instanceof Error ? e.message : String(e);
|
|
14244
14353
|
}
|
|
14245
14354
|
|
|
@@ -14249,7 +14358,7 @@ import { promisify } from "node:util";
|
|
|
14249
14358
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
14250
14359
|
import { dirname as dirname11, resolve as resolve16, relative as relative6, isAbsolute as isAbsolute3, join as join17 } from "node:path";
|
|
14251
14360
|
import { homedir as homedir3, tmpdir } from "node:os";
|
|
14252
|
-
import { readFileSync as
|
|
14361
|
+
import { readFileSync as readFileSync20, mkdtempSync, writeFileSync as writeFileSync7, rmSync as rmSync2 } from "node:fs";
|
|
14253
14362
|
|
|
14254
14363
|
// src/commands/channel-auth.ts
|
|
14255
14364
|
import { createServer as createServer2 } from "node:http";
|
|
@@ -14524,7 +14633,7 @@ function resolveLatestVersion() {
|
|
|
14524
14633
|
}
|
|
14525
14634
|
function detectInstallChannel() {
|
|
14526
14635
|
try {
|
|
14527
|
-
return
|
|
14636
|
+
return readFileSync20(CHANNEL_MARKER, "utf8").trim() === "platform" ? "platform" : "github";
|
|
14528
14637
|
} catch {
|
|
14529
14638
|
return "github";
|
|
14530
14639
|
}
|
|
@@ -14732,7 +14841,7 @@ function printHelp5(io) {
|
|
|
14732
14841
|
}
|
|
14733
14842
|
|
|
14734
14843
|
// src/commands/validate.ts
|
|
14735
|
-
import { existsSync as existsSync16, readFileSync as
|
|
14844
|
+
import { existsSync as existsSync16, readFileSync as readFileSync21, readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
|
|
14736
14845
|
import { dirname as dirname12, resolve as resolve17 } from "node:path";
|
|
14737
14846
|
var validateCommand = {
|
|
14738
14847
|
name: "validate",
|
|
@@ -14780,7 +14889,7 @@ function checkBoundary(manifestPath, declared) {
|
|
|
14780
14889
|
}
|
|
14781
14890
|
let manifestYaml;
|
|
14782
14891
|
try {
|
|
14783
|
-
manifestYaml =
|
|
14892
|
+
manifestYaml = readFileSync21(manifestPath, "utf8");
|
|
14784
14893
|
} catch {
|
|
14785
14894
|
manifestYaml = null;
|
|
14786
14895
|
}
|
|
@@ -14814,7 +14923,7 @@ function checkStaticServeDir(manifestPath, manifest) {
|
|
|
14814
14923
|
try {
|
|
14815
14924
|
isDir2 = statSync2(abs).isDirectory();
|
|
14816
14925
|
} catch (e) {
|
|
14817
|
-
return [`failed to inspect static served directory '${serveDir}/': ${
|
|
14926
|
+
return [`failed to inspect static served directory '${serveDir}/': ${describe32(e)}`];
|
|
14818
14927
|
}
|
|
14819
14928
|
if (!isDir2) {
|
|
14820
14929
|
return [`static app serves '${serveDir}/' but that path is not a directory.`];
|
|
@@ -14823,7 +14932,7 @@ function checkStaticServeDir(manifestPath, manifest) {
|
|
|
14823
14932
|
try {
|
|
14824
14933
|
entries = readdirSync3(abs);
|
|
14825
14934
|
} catch (e) {
|
|
14826
|
-
return [`failed to read static served directory '${serveDir}/': ${
|
|
14935
|
+
return [`failed to read static served directory '${serveDir}/': ${describe32(e)}`];
|
|
14827
14936
|
}
|
|
14828
14937
|
if (entries.length === 0) {
|
|
14829
14938
|
return [
|
|
@@ -14878,7 +14987,7 @@ async function checkGroup(allowedGroup, cfg) {
|
|
|
14878
14987
|
if (e instanceof ForbiddenError) {
|
|
14879
14988
|
return { kind: "forbidden", message: e.message };
|
|
14880
14989
|
}
|
|
14881
|
-
return { kind: "network", message:
|
|
14990
|
+
return { kind: "network", message: describe32(e) };
|
|
14882
14991
|
}
|
|
14883
14992
|
}
|
|
14884
14993
|
async function checkGroups(groups) {
|
|
@@ -15093,7 +15202,7 @@ function parseArgs13(args) {
|
|
|
15093
15202
|
}
|
|
15094
15203
|
return { kind: "ok", file, json, strictGroups };
|
|
15095
15204
|
}
|
|
15096
|
-
function
|
|
15205
|
+
function describe32(e) {
|
|
15097
15206
|
return e instanceof Error ? e.message : String(e);
|
|
15098
15207
|
}
|
|
15099
15208
|
|
|
@@ -15146,7 +15255,7 @@ async function runWhoami(args, io) {
|
|
|
15146
15255
|
io.err(e.message);
|
|
15147
15256
|
return 1;
|
|
15148
15257
|
}
|
|
15149
|
-
io.err(`launchpad whoami failed: ${
|
|
15258
|
+
io.err(`launchpad whoami failed: ${describe33(e)}`);
|
|
15150
15259
|
return 1;
|
|
15151
15260
|
}
|
|
15152
15261
|
}
|
|
@@ -15176,11 +15285,11 @@ async function runShare(args, io) {
|
|
|
15176
15285
|
io.err(e.message);
|
|
15177
15286
|
return 1;
|
|
15178
15287
|
}
|
|
15179
|
-
io.err(`launchpad whoami --share failed: ${
|
|
15288
|
+
io.err(`launchpad whoami --share failed: ${describe33(e)}`);
|
|
15180
15289
|
return 1;
|
|
15181
15290
|
}
|
|
15182
15291
|
}
|
|
15183
|
-
function
|
|
15292
|
+
function describe33(e) {
|
|
15184
15293
|
return e instanceof Error ? e.message : String(e);
|
|
15185
15294
|
}
|
|
15186
15295
|
|
|
@@ -15346,7 +15455,7 @@ async function runEditor(action, args, io, deps) {
|
|
|
15346
15455
|
io.err(`launchpad ${verb}: no app "${slug}" — check the slug with \`launchpad apps\`.`);
|
|
15347
15456
|
return 1;
|
|
15348
15457
|
}
|
|
15349
|
-
io.err(`launchpad ${verb} failed: ${
|
|
15458
|
+
io.err(`launchpad ${verb} failed: ${describe34(e)}`);
|
|
15350
15459
|
return 1;
|
|
15351
15460
|
}
|
|
15352
15461
|
}
|
|
@@ -15380,7 +15489,7 @@ async function sendMutation(action, slug, target, version, cfg, deps) {
|
|
|
15380
15489
|
nonThrowingStatuses: [409]
|
|
15381
15490
|
});
|
|
15382
15491
|
}
|
|
15383
|
-
function
|
|
15492
|
+
function describe34(e) {
|
|
15384
15493
|
return e instanceof Error ? e.message : String(e);
|
|
15385
15494
|
}
|
|
15386
15495
|
var grantEditorCommand = makeEditorCommand("grant");
|
|
@@ -15586,7 +15695,7 @@ async function runOwner(action, args, io, deps) {
|
|
|
15586
15695
|
io.err(`launchpad ${verb}: no app "${slug}" — check the slug with \`launchpad apps\`.`);
|
|
15587
15696
|
return 1;
|
|
15588
15697
|
}
|
|
15589
|
-
io.err(`launchpad ${verb} failed: ${
|
|
15698
|
+
io.err(`launchpad ${verb} failed: ${describe35(e)}`);
|
|
15590
15699
|
return 1;
|
|
15591
15700
|
}
|
|
15592
15701
|
}
|
|
@@ -15620,7 +15729,7 @@ async function sendMutation2(action, slug, target, version, cfg, deps) {
|
|
|
15620
15729
|
nonThrowingStatuses: [409]
|
|
15621
15730
|
});
|
|
15622
15731
|
}
|
|
15623
|
-
function
|
|
15732
|
+
function describe35(e) {
|
|
15624
15733
|
return e instanceof Error ? e.message : String(e);
|
|
15625
15734
|
}
|
|
15626
15735
|
var addOwnerCommand = makeOwnerCommand("add");
|
|
@@ -15785,7 +15894,7 @@ import { join as join18 } from "node:path";
|
|
|
15785
15894
|
import {
|
|
15786
15895
|
existsSync as existsSync17,
|
|
15787
15896
|
mkdirSync as mkdirSync4,
|
|
15788
|
-
readFileSync as
|
|
15897
|
+
readFileSync as readFileSync22,
|
|
15789
15898
|
writeFileSync as writeFileSync8
|
|
15790
15899
|
} from "node:fs";
|
|
15791
15900
|
var INTERNAL_REFRESH_VERB = "__refresh-update-cache";
|
|
@@ -15794,7 +15903,7 @@ var OPT_OUT_ENV = "LAUNCHPAD_NO_UPDATE_NOTIFIER";
|
|
|
15794
15903
|
var CACHE_FILE = join18(homedir4(), ".launchpad", "update-check.json");
|
|
15795
15904
|
function readCache2() {
|
|
15796
15905
|
try {
|
|
15797
|
-
const raw = JSON.parse(
|
|
15906
|
+
const raw = JSON.parse(readFileSync22(CACHE_FILE, "utf8"));
|
|
15798
15907
|
if (typeof raw === "object" && raw !== null && typeof raw.checkedAt === "number") {
|
|
15799
15908
|
const latest = raw.latest;
|
|
15800
15909
|
return {
|
|
@@ -15926,7 +16035,7 @@ var refreshUpdateCacheCommand = {
|
|
|
15926
16035
|
import { spawn as spawn7 } from "node:child_process";
|
|
15927
16036
|
import { homedir as homedir5 } from "node:os";
|
|
15928
16037
|
import { join as join19 } from "node:path";
|
|
15929
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync5, readFileSync as
|
|
16038
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync5, readFileSync as readFileSync23, writeFileSync as writeFileSync9 } from "node:fs";
|
|
15930
16039
|
import { randomUUID } from "node:crypto";
|
|
15931
16040
|
var INTERNAL_EMIT_VERB = "__emit-telemetry";
|
|
15932
16041
|
var POSTHOG_HOST = "https://us.i.posthog.com";
|
|
@@ -16002,7 +16111,7 @@ async function resolveIdentityReal() {
|
|
|
16002
16111
|
}
|
|
16003
16112
|
function getOrCreateDeviceId() {
|
|
16004
16113
|
try {
|
|
16005
|
-
const raw = JSON.parse(
|
|
16114
|
+
const raw = JSON.parse(readFileSync23(DEVICE_ID_FILE, "utf8"));
|
|
16006
16115
|
const id2 = raw?.deviceId;
|
|
16007
16116
|
if (typeof id2 === "string" && id2)
|
|
16008
16117
|
return id2;
|
|
@@ -16153,7 +16262,7 @@ import { createInterface as createInterface7 } from "node:readline/promises";
|
|
|
16153
16262
|
import { platform } from "node:os";
|
|
16154
16263
|
|
|
16155
16264
|
// src/report/breadcrumb.ts
|
|
16156
|
-
import { writeFileSync as writeFileSync10, readFileSync as
|
|
16265
|
+
import { writeFileSync as writeFileSync10, readFileSync as readFileSync24, mkdirSync as mkdirSync6 } from "node:fs";
|
|
16157
16266
|
import { homedir as homedir6 } from "node:os";
|
|
16158
16267
|
import { join as join20, dirname as dirname13 } from "node:path";
|
|
16159
16268
|
function breadcrumbPath() {
|
|
@@ -16168,7 +16277,7 @@ function writeBreadcrumb(verb, exit) {
|
|
|
16168
16277
|
}
|
|
16169
16278
|
function readBreadcrumb() {
|
|
16170
16279
|
try {
|
|
16171
|
-
const raw = JSON.parse(
|
|
16280
|
+
const raw = JSON.parse(readFileSync24(breadcrumbPath(), "utf8"));
|
|
16172
16281
|
if (typeof raw !== "object" || raw === null)
|
|
16173
16282
|
return null;
|
|
16174
16283
|
const r = raw;
|