@launchsecure/launch-kit 0.0.31 → 0.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/beacon/beacon.mjs +550 -521
- package/dist/beacon/beacon.mjs.map +1 -1
- package/dist/beacon/beacon.umd.js +9 -9
- package/dist/beacon/beacon.umd.js.map +1 -1
- package/dist/beacon/types/internal/pick-mode-overlay.d.ts.map +1 -1
- package/dist/beacon/types/internal/picker.d.ts.map +1 -1
- package/dist/beacon/types/internal/pin-popover.d.ts.map +1 -1
- package/dist/beacon/types/internal/selector.d.ts.map +1 -1
- package/dist/deck-client/assets/{_baseUniq-DdHaBFYO.js → _baseUniq-C7GsHvgg.js} +1 -1
- package/dist/deck-client/assets/{arc-D98e_18X.js → arc-CSrZRINY.js} +1 -1
- package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-DNFZzh-4.js → architectureDiagram-Q4EWVU46-zoB-G17J.js} +1 -1
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-DeQvGUdX.js → blockDiagram-DXYQGD6D-BRjjtYH6.js} +1 -1
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-B6ekZf1n.js → c4Diagram-AHTNJAMY-C3D3sd2U.js} +1 -1
- package/dist/deck-client/assets/channel-8ReQnQfH.js +1 -0
- package/dist/deck-client/assets/{chunk-4BX2VUAB-9aDWymq2.js → chunk-4BX2VUAB-DhpDMOPO.js} +1 -1
- package/dist/deck-client/assets/{chunk-4TB4RGXK-DtKQqaI7.js → chunk-4TB4RGXK-BIRgPXRl.js} +1 -1
- package/dist/deck-client/assets/{chunk-55IACEB6-COy9hEae.js → chunk-55IACEB6-BF24dwDZ.js} +1 -1
- package/dist/deck-client/assets/{chunk-EDXVE4YY-D_f861An.js → chunk-EDXVE4YY-CW75Y61B.js} +1 -1
- package/dist/deck-client/assets/{chunk-FMBD7UC4-CmuA5UKn.js → chunk-FMBD7UC4-B5-oyL79.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-vT8z8D-0.js → chunk-OYMX7WX6-BB2bHe_Q.js} +1 -1
- package/dist/deck-client/assets/{chunk-QZHKN3VN-CTlwwg-R.js → chunk-QZHKN3VN-D80eZO4B.js} +1 -1
- package/dist/deck-client/assets/{chunk-YZCP3GAM-C44yr620.js → chunk-YZCP3GAM-Dz9787p_.js} +1 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-cRxTeGkK.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-cRxTeGkK.js +1 -0
- package/dist/deck-client/assets/clone-LSHZ3K6R.js +1 -0
- package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-DBB2J2nL.js → cose-bilkent-S5V4N54A-MQjiZLcL.js} +1 -1
- package/dist/deck-client/assets/{dagre-KV5264BT-DxDTYbKl.js → dagre-KV5264BT-DG4EcLpJ.js} +1 -1
- package/dist/deck-client/assets/{diagram-5BDNPKRD-DByWrWd1.js → diagram-5BDNPKRD-1n7hM3Gc.js} +1 -1
- package/dist/deck-client/assets/{diagram-G4DWMVQ6-B8B6ddMq.js → diagram-G4DWMVQ6-CYMarncV.js} +1 -1
- package/dist/deck-client/assets/{diagram-MMDJMWI5-BMUZ2PWK.js → diagram-MMDJMWI5-DSisoipe.js} +1 -1
- package/dist/deck-client/assets/{diagram-TYMM5635-Bk9e8BB-.js → diagram-TYMM5635-Btnq49OJ.js} +1 -1
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-DcOSwSol.js → erDiagram-SMLLAGMA-Cu2Hb_Tz.js} +1 -1
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-DI-4BR0F.js → flowDiagram-DWJPFMVM-CGJzUzsO.js} +1 -1
- package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-BeZuXBoU.js → ganttDiagram-T4ZO3ILL-D9sqGUBT.js} +1 -1
- package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-Bcki__f-.js → gitGraphDiagram-UUTBAWPF-C0QwX2od.js} +1 -1
- package/dist/deck-client/assets/{graph-CifKx6G1.js → graph-CcBjOQCl.js} +1 -1
- package/dist/deck-client/assets/{index-CB-qlwRT.js → index-0arwoc0z.js} +76 -76
- package/dist/deck-client/assets/{infoDiagram-42DDH7IO-CReN1nFN.js → infoDiagram-42DDH7IO-DTimhhhS.js} +1 -1
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-CDF_VLN_.js → ishikawaDiagram-UXIWVN3A-DxOxg_B4.js} +1 -1
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-DwgGrNVB.js → journeyDiagram-VCZTEJTY-Bpq0qa4j.js} +1 -1
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-DB_zohh5.js → kanban-definition-6JOO6SKY-aTIrpcVO.js} +1 -1
- package/dist/deck-client/assets/{layout-DFfX1O3z.js → layout-DqglLR2E.js} +1 -1
- package/dist/deck-client/assets/{linear-CtKb4EXj.js → linear-D5GxehPc.js} +1 -1
- package/dist/deck-client/assets/{min-DCRRwUZv.js → min-DXLfSREq.js} +1 -1
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-D0QBOiFe.js → mindmap-definition-QFDTVHPH-mO5Vys7I.js} +1 -1
- package/dist/deck-client/assets/{pieDiagram-DEJITSTG-CD-EV5WB.js → pieDiagram-DEJITSTG-Dm0gzdAr.js} +1 -1
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-B-JXZ8xI.js → quadrantDiagram-34T5L4WZ-Daq7j3qD.js} +1 -1
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-D2_OK5Dp.js → requirementDiagram-MS252O5E-CmwV95um.js} +1 -1
- package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BbBJqVSC.js → sankeyDiagram-XADWPNL6-BOYl3Nkf.js} +1 -1
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-Db8A-Rkk.js → sequenceDiagram-FGHM5R23-BuUjhIcW.js} +1 -1
- package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-DGJnanjS.js → stateDiagram-FHFEXIEX-LUZ_uwio.js} +1 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CnnRwE5D.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-BRkr6T4w.js → timeline-definition-GMOUNBTQ-CDUxCCAW.js} +1 -1
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-d0rsTqFo.js → vennDiagram-DHZGUBPP-BRb24Tf7.js} +1 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-B0BYyVBY.js +162 -0
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-DzboAsHh.js → wardleyDiagram-NUSXRM2D-BLGlYrQz.js} +1 -1
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CgTP9u2V.js → xychartDiagram-5P7HB3ND-De31MSnk.js} +1 -1
- package/dist/deck-client/index.html +1 -1
- package/dist/server/deck-mcp-entry.js +83 -40
- package/dist/server/deck-serve.js +54 -20
- package/dist/server/init-entry.js +216 -73
- package/package.json +1 -1
- package/scaffolds/ls-marketplace/plugins/kit/skills/diagram/SKILL.md +27 -5
- package/dist/deck-client/assets/channel-DmR7Tyyt.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-Bl4ozQWs.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-Bl4ozQWs.js +0 -1
- package/dist/deck-client/assets/clone-BAy58j24.js +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CR7riiab.js +0 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-2t7cMqdS.js +0 -162
|
@@ -295,6 +295,50 @@ function recoverCred(targetDir, opts) {
|
|
|
295
295
|
init_statusline_install();
|
|
296
296
|
var DEFAULT_SERVER_URL = "https://launchsecure-v2.vercel.app";
|
|
297
297
|
var ONBOARD_SCRIPT_NAME = "onboard";
|
|
298
|
+
var TTY = process.stdout.isTTY === true && process.env.NO_COLOR !== "1";
|
|
299
|
+
var c = {
|
|
300
|
+
dim: (s) => TTY ? `\x1B[2m${s}\x1B[0m` : s,
|
|
301
|
+
bold: (s) => TTY ? `\x1B[1m${s}\x1B[0m` : s,
|
|
302
|
+
cyan: (s) => TTY ? `\x1B[36m${s}\x1B[0m` : s,
|
|
303
|
+
green: (s) => TTY ? `\x1B[32m${s}\x1B[0m` : s,
|
|
304
|
+
yellow: (s) => TTY ? `\x1B[33m${s}\x1B[0m` : s,
|
|
305
|
+
red: (s) => TTY ? `\x1B[31m${s}\x1B[0m` : s
|
|
306
|
+
};
|
|
307
|
+
var PHASE_NAME_COL = 16;
|
|
308
|
+
var HEADER_WIDTH = 64;
|
|
309
|
+
function header(title, kv) {
|
|
310
|
+
if (VERBOSE) return;
|
|
311
|
+
const dashes = "\u2500".repeat(Math.max(3, HEADER_WIDTH - title.length - 5));
|
|
312
|
+
console.log("");
|
|
313
|
+
console.log(c.cyan(`\u2500\u2500\u2500 ${c.bold(title)} ${dashes}`));
|
|
314
|
+
if (kv.length > 0) {
|
|
315
|
+
const labelWidth = Math.max(...kv.map(([k]) => k.length));
|
|
316
|
+
for (const [k, v] of kv) console.log(` ${c.dim(k.padEnd(labelWidth))} ${v}`);
|
|
317
|
+
}
|
|
318
|
+
console.log("");
|
|
319
|
+
}
|
|
320
|
+
function phase(name, result) {
|
|
321
|
+
if (VERBOSE) return;
|
|
322
|
+
const mark = result.status === "ok" ? c.green("\u2713") : result.status === "in-sync" ? c.dim("\xB7") : result.status === "skipped" ? c.dim("\u2212") : c.yellow("\u26A0");
|
|
323
|
+
const summary = result.status === "in-sync" || result.status === "skipped" ? c.dim(result.summary) : result.summary;
|
|
324
|
+
const label = name.padEnd(PHASE_NAME_COL);
|
|
325
|
+
console.log(` ${result.status === "warn" ? c.yellow(label) : label} ${mark} ${summary}`);
|
|
326
|
+
}
|
|
327
|
+
function section(title) {
|
|
328
|
+
if (VERBOSE) return;
|
|
329
|
+
console.log("");
|
|
330
|
+
console.log(` ${c.dim("\u2500 " + title + " \u2500")}`);
|
|
331
|
+
}
|
|
332
|
+
function footer(msg, hints = []) {
|
|
333
|
+
if (VERBOSE) return;
|
|
334
|
+
console.log("");
|
|
335
|
+
console.log(` ${c.bold(msg)}`);
|
|
336
|
+
for (const h of hints) console.log(` ${c.dim(h)}`);
|
|
337
|
+
console.log("");
|
|
338
|
+
}
|
|
339
|
+
function warn(msg) {
|
|
340
|
+
console.log(` ${c.yellow("\u26A0")} ${msg}`);
|
|
341
|
+
}
|
|
298
342
|
var LAUNCH_KIT_PKG = "@launchsecure/launch-kit";
|
|
299
343
|
var LAUNCH_KIT_TOOLS_GUIDE_STATIC_HEAD = `
|
|
300
344
|
Wired in Claude Code (.mcp.json):
|
|
@@ -369,7 +413,10 @@ var KNOWN_BOOL_FLAGS = /* @__PURE__ */ new Set([
|
|
|
369
413
|
"--refresh-scaffolds",
|
|
370
414
|
"--quiet",
|
|
371
415
|
"--force",
|
|
372
|
-
"--dry-run"
|
|
416
|
+
"--dry-run",
|
|
417
|
+
"--verbose",
|
|
418
|
+
"--guide",
|
|
419
|
+
"--no-guide"
|
|
373
420
|
]);
|
|
374
421
|
var KNOWN_KV_KEYS = /* @__PURE__ */ new Set(["token", "org", "project", "url", "dir", "course"]);
|
|
375
422
|
function parseArgs(argv) {
|
|
@@ -390,6 +437,8 @@ function parseArgs(argv) {
|
|
|
390
437
|
quiet: false,
|
|
391
438
|
force: false,
|
|
392
439
|
dryRun: false,
|
|
440
|
+
verbose: false,
|
|
441
|
+
guide: null,
|
|
393
442
|
help: false
|
|
394
443
|
};
|
|
395
444
|
const unknown = [];
|
|
@@ -440,6 +489,18 @@ function parseArgs(argv) {
|
|
|
440
489
|
args.dryRun = true;
|
|
441
490
|
continue;
|
|
442
491
|
}
|
|
492
|
+
if (raw === "--verbose") {
|
|
493
|
+
args.verbose = true;
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
if (raw === "--guide") {
|
|
497
|
+
args.guide = true;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (raw === "--no-guide") {
|
|
501
|
+
args.guide = false;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
443
504
|
const eq = raw.indexOf("=");
|
|
444
505
|
if (raw.startsWith("--") && eq > 0) {
|
|
445
506
|
const key = raw.slice(2, eq);
|
|
@@ -511,8 +572,15 @@ Options:
|
|
|
511
572
|
--refresh-scaffolds Force-overwrite migrate-safety files (default is to
|
|
512
573
|
preserve user edits). Use this to pull updates
|
|
513
574
|
published to @launchsecure/launch-kit.
|
|
514
|
-
--
|
|
575
|
+
--verbose Print the legacy per-line debug log instead of the
|
|
576
|
+
default compact phase summary. Useful when refresh
|
|
577
|
+
reports a warn-status phase and you want detail.
|
|
578
|
+
--guide Print the trailing tools guide (MCP table + every
|
|
579
|
+
/kit:* command). Off by default on refresh.
|
|
580
|
+
--quiet Suppress the tools guide and the next-steps hint.
|
|
581
|
+
Overrides --guide.
|
|
515
582
|
--dry-run Preview every file write without making changes.
|
|
583
|
+
Implies --verbose.
|
|
516
584
|
--help Show this help.
|
|
517
585
|
|
|
518
586
|
Tip: prefix the command with @latest (\`launch-kit@latest refresh\`) to force
|
|
@@ -570,9 +638,17 @@ Options:
|
|
|
570
638
|
user edits; use this to pull updates published to
|
|
571
639
|
@launchsecure/launch-kit (e.g., a newer
|
|
572
640
|
migrate-with-backup.sh).
|
|
573
|
-
--
|
|
574
|
-
|
|
575
|
-
|
|
641
|
+
--verbose Print the legacy per-line debug log instead of the
|
|
642
|
+
default compact phase summary. Useful when a phase
|
|
643
|
+
reports a warn status and you want per-file detail.
|
|
644
|
+
--guide Print the trailing tools guide (MCP table + every
|
|
645
|
+
/kit:* command). On by default for init; pair with
|
|
646
|
+
--no-guide to suppress.
|
|
647
|
+
--no-guide Suppress the trailing tools guide (handy after the
|
|
648
|
+
first init, when you don't need the catalog again).
|
|
649
|
+
--quiet Suppress the post-run tools guide AND the next-steps
|
|
650
|
+
hint. Useful for idempotent re-runs in CI or scripts.
|
|
651
|
+
Overrides --guide.
|
|
576
652
|
--force Skip the auto-delegate-to-refresh check. By default
|
|
577
653
|
init detects an existing bootstrap (cred file +
|
|
578
654
|
launch-secure MCP entry) and runs refresh instead.
|
|
@@ -623,11 +699,12 @@ function fail(msg) {
|
|
|
623
699
|
console.error(`[launch-kit] \u2717 ${msg}`);
|
|
624
700
|
process.exit(1);
|
|
625
701
|
}
|
|
702
|
+
var VERBOSE = false;
|
|
626
703
|
function info(msg) {
|
|
627
|
-
console.log(`[launch-kit] ${msg}`);
|
|
704
|
+
if (VERBOSE) console.log(`[launch-kit] ${msg}`);
|
|
628
705
|
}
|
|
629
706
|
function ok(msg) {
|
|
630
|
-
console.log(`[launch-kit] \u2713 ${msg}`);
|
|
707
|
+
if (VERBOSE) console.log(`[launch-kit] \u2713 ${msg}`);
|
|
631
708
|
}
|
|
632
709
|
var DRY_RUN = false;
|
|
633
710
|
function dryNote(msg) {
|
|
@@ -685,7 +762,7 @@ function attemptProjectInfo(args) {
|
|
|
685
762
|
},
|
|
686
763
|
(res) => {
|
|
687
764
|
const chunks = [];
|
|
688
|
-
res.on("data", (
|
|
765
|
+
res.on("data", (c2) => chunks.push(c2));
|
|
689
766
|
res.on("end", () => {
|
|
690
767
|
const text = Buffer.concat(chunks).toString("utf-8");
|
|
691
768
|
if (res.statusCode === 401) {
|
|
@@ -936,13 +1013,15 @@ function mergeMcpFile(targetDir, launchKitEntries) {
|
|
|
936
1013
|
}
|
|
937
1014
|
}
|
|
938
1015
|
if (DRY_RUN) {
|
|
939
|
-
const
|
|
940
|
-
dryNote(`${
|
|
941
|
-
return;
|
|
1016
|
+
const action = hadExisting && existingServerCount > 0 ? "would merge into" : "would write";
|
|
1017
|
+
dryNote(`${action} .mcp.json \u2014 overwriting [${overwrites.join(", ") || "none"}], adding [${additions.join(", ") || "none"}]`);
|
|
1018
|
+
return { status: "skipped", summary: "(dry-run)" };
|
|
942
1019
|
}
|
|
943
1020
|
fs4.writeFileSync(p, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
944
|
-
const
|
|
945
|
-
ok(`${
|
|
1021
|
+
const verb = hadExisting && existingServerCount > 0 ? "merged" : "wrote";
|
|
1022
|
+
ok(`${verb === "merged" ? "merged into" : "wrote"} .mcp.json (${Object.keys(launchKitEntries).length} launch-kit entries)`);
|
|
1023
|
+
const total = Object.keys(launchKitEntries).length;
|
|
1024
|
+
return { status: "ok", summary: `${verb} ${total} entries` };
|
|
946
1025
|
}
|
|
947
1026
|
function detectPackageManager(repoDir) {
|
|
948
1027
|
const pkgPath = path4.join(repoDir, "package.json");
|
|
@@ -1093,8 +1172,8 @@ function copyScaffoldDirAlways(srcDir, destDir, labelPrefix) {
|
|
|
1093
1172
|
function scaffoldMigrateSafety(targetDir, refreshScaffolds = false) {
|
|
1094
1173
|
const scaffoldsRoot = path4.resolve(__dirname, "..", "..", "scaffolds", "migrate-safety");
|
|
1095
1174
|
if (!fs4.existsSync(scaffoldsRoot)) {
|
|
1096
|
-
|
|
1097
|
-
return;
|
|
1175
|
+
warn(`migrate-safety scaffolds missing at ${scaffoldsRoot} \u2014 packaging bug; main onboarding unaffected`);
|
|
1176
|
+
return { status: "warn", summary: "scaffolds missing (packaging bug)" };
|
|
1098
1177
|
}
|
|
1099
1178
|
const files = [
|
|
1100
1179
|
{
|
|
@@ -1114,9 +1193,33 @@ function scaffoldMigrateSafety(targetDir, refreshScaffolds = false) {
|
|
|
1114
1193
|
}
|
|
1115
1194
|
];
|
|
1116
1195
|
info(`scaffolding migrate-safety (pg_dump wrapper + GHA backup workflow + runbook)${refreshScaffolds ? " \u2014 --refresh-scaffolds active" : ""} \u2026`);
|
|
1117
|
-
|
|
1196
|
+
const counts = { wrote: 0, inSync: 0, drifted: 0, refreshed: 0, missing: 0 };
|
|
1197
|
+
for (const f of files) {
|
|
1198
|
+
const r = copyScaffoldDriftAware(f.src, f.dest, f.label, refreshScaffolds);
|
|
1199
|
+
if (r === "wrote") counts.wrote++;
|
|
1200
|
+
else if (r === "in-sync") counts.inSync++;
|
|
1201
|
+
else if (r === "drifted-preserved") counts.drifted++;
|
|
1202
|
+
else if (r === "drifted-refreshed") counts.refreshed++;
|
|
1203
|
+
else counts.missing++;
|
|
1204
|
+
}
|
|
1118
1205
|
ensureGitignoreLine(targetDir, ".backups/");
|
|
1119
1206
|
ok("migrate-safety ready \u2014 see docs/migrations-runbook.md for db:migrate wiring + PROD_DATABASE_URL secret setup");
|
|
1207
|
+
return summarizeFileCounts(counts);
|
|
1208
|
+
}
|
|
1209
|
+
function summarizeFileCounts(counts) {
|
|
1210
|
+
const total = counts.wrote + counts.inSync + counts.drifted + counts.refreshed + counts.missing;
|
|
1211
|
+
const parts = [];
|
|
1212
|
+
if (counts.wrote) parts.push(`${counts.wrote} written`);
|
|
1213
|
+
if (counts.refreshed) parts.push(`${counts.refreshed} refreshed`);
|
|
1214
|
+
if (counts.drifted) parts.push(`${counts.drifted} drifted (preserved \u2014 pass --refresh-scaffolds to update)`);
|
|
1215
|
+
if (counts.inSync && (counts.wrote || counts.refreshed || counts.drifted)) parts.push(`${counts.inSync} in sync`);
|
|
1216
|
+
if (counts.missing) parts.push(`${counts.missing} missing scaffold src`);
|
|
1217
|
+
if (parts.length === 0) parts.push(`in sync (${total} file${total === 1 ? "" : "s"})`);
|
|
1218
|
+
else if (!counts.wrote && !counts.refreshed && !counts.drifted && counts.inSync === total) {
|
|
1219
|
+
return { status: "in-sync", summary: `in sync (${total} file${total === 1 ? "" : "s"})` };
|
|
1220
|
+
}
|
|
1221
|
+
const status = counts.drifted || counts.missing ? "warn" : counts.wrote || counts.refreshed ? "ok" : "in-sync";
|
|
1222
|
+
return { status, summary: parts.join(", ") };
|
|
1120
1223
|
}
|
|
1121
1224
|
function hashFile(p) {
|
|
1122
1225
|
try {
|
|
@@ -1186,21 +1289,22 @@ function isDogfoodMarketplace(targetDir) {
|
|
|
1186
1289
|
function scaffoldLsMarketplace(targetDir) {
|
|
1187
1290
|
const scaffoldsRoot = path4.resolve(__dirname, "..", "..", "scaffolds", "ls-marketplace");
|
|
1188
1291
|
if (!fs4.existsSync(scaffoldsRoot)) {
|
|
1189
|
-
|
|
1190
|
-
return;
|
|
1292
|
+
warn(`ls-marketplace scaffolds missing at ${scaffoldsRoot} \u2014 packaging bug`);
|
|
1293
|
+
return { status: "warn", summary: "scaffolds missing (packaging bug)" };
|
|
1191
1294
|
}
|
|
1192
1295
|
const dogfood = isDogfoodMarketplace(targetDir);
|
|
1193
1296
|
if (dogfood.isDogfood) {
|
|
1194
1297
|
info(`dogfood marketplace pointer detected (${dogfood.existingPath}) \u2014 skipping copy, only refreshing enabledPlugins`);
|
|
1195
1298
|
wireLsSettings(targetDir);
|
|
1196
1299
|
ok(`launch-secure marketplace (dogfood) \u2014 Claude Code loads commands from ${dogfood.existingPath}`);
|
|
1197
|
-
return;
|
|
1300
|
+
return { status: "ok", summary: `dogfood pointer (${dogfood.existingPath})` };
|
|
1198
1301
|
}
|
|
1199
1302
|
const marketplaceRoot = path4.join(targetDir, ".claude", "marketplace");
|
|
1200
1303
|
info("scaffolding launch-secure marketplace (Claude Code /kit: namespace \u2014 refreshes every /kit:* command found in the scaffold) \u2026");
|
|
1201
1304
|
copyScaffoldDirAlways(scaffoldsRoot, marketplaceRoot, ".claude/marketplace");
|
|
1202
1305
|
wireLsSettings(targetDir);
|
|
1203
1306
|
ok(`launch-secure marketplace ready \u2014 open this repo in Claude Code, approve the "${MARKETPLACE_ID}" marketplace prompt, then try /kit:activate-beacon, /kit:standup, or /kit:show-mcp-status`);
|
|
1307
|
+
return { status: "ok", summary: "marketplace tree + settings refreshed" };
|
|
1204
1308
|
}
|
|
1205
1309
|
function wireLsSettings(targetDir) {
|
|
1206
1310
|
const p = path4.join(targetDir, ".claude", "settings.json");
|
|
@@ -1247,13 +1351,14 @@ var RECALL_HOOK_COMMAND = 'bash "${CLAUDE_PROJECT_DIR:-$PWD}/scripts/ensure-reca
|
|
|
1247
1351
|
function scaffoldRecallHook(targetDir) {
|
|
1248
1352
|
const scaffoldsRoot = path4.resolve(__dirname, "..", "..", "scaffolds", "recall-hook");
|
|
1249
1353
|
if (!fs4.existsSync(scaffoldsRoot)) {
|
|
1250
|
-
|
|
1251
|
-
return;
|
|
1354
|
+
warn(`recall-hook scaffolds missing at ${scaffoldsRoot} \u2014 packaging bug`);
|
|
1355
|
+
return { status: "warn", summary: "scaffolds missing (packaging bug)" };
|
|
1252
1356
|
}
|
|
1253
1357
|
info("scaffolding recall-hook (SessionStart watcher-respawn hook + ensure-recall.sh) \u2026");
|
|
1254
1358
|
copyScaffoldDirAlways(scaffoldsRoot, targetDir, "");
|
|
1255
|
-
wireRecallHook(targetDir);
|
|
1359
|
+
const wired = wireRecallHook(targetDir);
|
|
1256
1360
|
ok("recall-hook ready \u2014 opens with Claude Code will respawn the launch-recall watcher if it died between sessions");
|
|
1361
|
+
return wired ? { status: "ok", summary: "ensure-recall.sh refreshed + SessionStart hook appended" } : { status: "ok", summary: "ensure-recall.sh refreshed (hook already wired)" };
|
|
1257
1362
|
}
|
|
1258
1363
|
function wireRecallHook(targetDir) {
|
|
1259
1364
|
const p = path4.join(targetDir, ".claude", "settings.json");
|
|
@@ -1273,7 +1378,7 @@ function wireRecallHook(targetDir) {
|
|
|
1273
1378
|
);
|
|
1274
1379
|
if (alreadyWired) {
|
|
1275
1380
|
info(".claude/settings.json SessionStart hook already references ensure-recall.sh \u2014 leaving alone");
|
|
1276
|
-
return;
|
|
1381
|
+
return false;
|
|
1277
1382
|
}
|
|
1278
1383
|
const newGroup = {
|
|
1279
1384
|
hooks: [{ type: "command", command: RECALL_HOOK_COMMAND }]
|
|
@@ -1287,23 +1392,28 @@ function wireRecallHook(targetDir) {
|
|
|
1287
1392
|
};
|
|
1288
1393
|
if (DRY_RUN) {
|
|
1289
1394
|
dryNote(`would append SessionStart hook to .claude/settings.json (bash scripts/ensure-recall.sh; preserves every other key + existing hooks)`);
|
|
1290
|
-
return;
|
|
1395
|
+
return true;
|
|
1291
1396
|
}
|
|
1292
1397
|
fs4.mkdirSync(path4.dirname(p), { recursive: true });
|
|
1293
1398
|
fs4.writeFileSync(p, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
1294
1399
|
ok(`appended SessionStart hook to .claude/settings.json (bash scripts/ensure-recall.sh)`);
|
|
1400
|
+
return true;
|
|
1295
1401
|
}
|
|
1296
1402
|
function tryActivateStatusline() {
|
|
1297
1403
|
if (DRY_RUN) {
|
|
1298
1404
|
dryNote(`would wrap ~/.claude/settings.json statusLine.command with launch-kit's MCP chip wrapper (skips silently if no statusline configured)`);
|
|
1299
|
-
return;
|
|
1405
|
+
return { status: "skipped", summary: "(dry-run)" };
|
|
1300
1406
|
}
|
|
1301
1407
|
const res = activateStatusline();
|
|
1302
1408
|
if (res.ok && res.outcome === "activated") {
|
|
1303
1409
|
ok(`statusline wrapped \u2014 MCP chips will render alongside your existing statusline next session`);
|
|
1304
|
-
|
|
1410
|
+
return { status: "ok", summary: "wrapped \u2014 MCP chips render next session" };
|
|
1411
|
+
}
|
|
1412
|
+
if (res.ok && res.outcome === "refreshed") {
|
|
1305
1413
|
info(`statusline already wrapped \u2014 refreshed chip scripts`);
|
|
1414
|
+
return { status: "ok", summary: "chip scripts refreshed" };
|
|
1306
1415
|
}
|
|
1416
|
+
return null;
|
|
1307
1417
|
}
|
|
1308
1418
|
async function main() {
|
|
1309
1419
|
const subcommand = process.argv[2];
|
|
@@ -1347,11 +1457,12 @@ async function main() {
|
|
|
1347
1457
|
fail(`Unknown subcommand "${subcommand}". Supported: init, refresh, statusline. Run with --help for usage.`);
|
|
1348
1458
|
}
|
|
1349
1459
|
DRY_RUN = args.dryRun;
|
|
1460
|
+
VERBOSE = args.verbose || DRY_RUN;
|
|
1350
1461
|
if (DRY_RUN) {
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1462
|
+
console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1463
|
+
console.log(c.bold("DRY RUN") + c.dim(" \u2014 no files will be written, no commands will run."));
|
|
1464
|
+
console.log(c.dim("Lines tagged (dry-run) show what would happen."));
|
|
1465
|
+
console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1355
1466
|
}
|
|
1356
1467
|
if (subcommand === "refresh") return mainRefresh(args);
|
|
1357
1468
|
return mainInit(args);
|
|
@@ -1390,25 +1501,34 @@ async function mainRefresh(args) {
|
|
|
1390
1501
|
const active = nested.profiles[nested.active];
|
|
1391
1502
|
if (!active) fail(`${CONFIG_FILENAME} active profile "${nested.active}" is not present in profiles.`);
|
|
1392
1503
|
info(`refreshing launch-kit in ${targetDir} (course: ${nested.active}, project: ${active.orgSlug}/${active.projectSlug}) \u2026`);
|
|
1504
|
+
header("launch-kit refresh", [
|
|
1505
|
+
["course", nested.active],
|
|
1506
|
+
["project", `${active.orgSlug}/${active.projectSlug}`],
|
|
1507
|
+
["dir", path4.relative(cwd, targetDir) || "."]
|
|
1508
|
+
]);
|
|
1393
1509
|
const cfg = { pat: active.pat, orgSlug: active.orgSlug, projectSlug: active.projectSlug, serverUrl: active.serverUrl };
|
|
1394
|
-
mergeMcpFile(targetDir, buildLaunchKitMcpEntries(cfg));
|
|
1510
|
+
phase(".mcp.json", mergeMcpFile(targetDir, buildLaunchKitMcpEntries(cfg)));
|
|
1395
1511
|
ensureGitignoreLine(targetDir, CONFIG_FILENAME);
|
|
1396
|
-
if (!args.noMigrateSafety) scaffoldMigrateSafety(targetDir, args.refreshScaffolds);
|
|
1397
|
-
if (!args.noLsMarketplace) scaffoldLsMarketplace(targetDir);
|
|
1398
|
-
if (!args.noRecallHook) scaffoldRecallHook(targetDir);
|
|
1399
|
-
tryActivateStatusline();
|
|
1400
|
-
|
|
1512
|
+
if (!args.noMigrateSafety) phase("migrate-safety", scaffoldMigrateSafety(targetDir, args.refreshScaffolds));
|
|
1513
|
+
if (!args.noLsMarketplace) phase("ls-marketplace", scaffoldLsMarketplace(targetDir));
|
|
1514
|
+
if (!args.noRecallHook) phase("recall-hook", scaffoldRecallHook(targetDir));
|
|
1515
|
+
const slR = tryActivateStatusline();
|
|
1516
|
+
if (slR) phase("statusline", slR);
|
|
1401
1517
|
if (DRY_RUN) {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1518
|
+
console.log("");
|
|
1519
|
+
console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1520
|
+
console.log(c.bold("DRY RUN COMPLETE") + c.dim(" \u2014 refresh would have applied the above; no files modified."));
|
|
1521
|
+
console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1405
1522
|
return;
|
|
1406
1523
|
}
|
|
1407
1524
|
ok(`refresh complete \u2014 restart Claude Code to pick up any new /kit:* commands`);
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1525
|
+
const showGuide = args.quiet ? false : args.guide === true;
|
|
1526
|
+
const hints = ["Restart Claude Code to pick up any new /kit:* commands."];
|
|
1527
|
+
if (!showGuide && !args.quiet) hints.push("Run with --guide to print the full MCP + slash-command catalog. --verbose for per-file detail.");
|
|
1528
|
+
footer("Refresh complete.", hints);
|
|
1529
|
+
if (showGuide) {
|
|
1530
|
+
console.log(c.dim(`(refresh never runs these: clone, dependency install, onboard script, launch-recall init \u2014 use \`launch-kit init\` for a full bootstrap)`));
|
|
1531
|
+
console.log(getLaunchKitToolsGuide());
|
|
1412
1532
|
}
|
|
1413
1533
|
}
|
|
1414
1534
|
async function mainInit(args) {
|
|
@@ -1454,7 +1574,13 @@ async function mainInit(args) {
|
|
|
1454
1574
|
if (!/^ls_pat_/.test(args.token)) fail("Token does not look like a LaunchSecure PAT (expected prefix ls_pat_).");
|
|
1455
1575
|
if (!args.orgSlug) fail("--org=<orgSlug> is required.");
|
|
1456
1576
|
if (!args.projectSlug) fail("--project=<projectSlug> is required.");
|
|
1577
|
+
header("launch-kit init", [
|
|
1578
|
+
["org", args.orgSlug],
|
|
1579
|
+
["project", args.projectSlug],
|
|
1580
|
+
["server", args.serverUrl]
|
|
1581
|
+
]);
|
|
1457
1582
|
const { hasGh } = preflight();
|
|
1583
|
+
phase("preflight", { status: "ok", summary: `node ${process.versions.node}${hasGh ? " \xB7 git \xB7 gh" : " \xB7 git (gh not found \u2014 will use git for clone)"}` });
|
|
1458
1584
|
info(`resolving project ${args.orgSlug}/${args.projectSlug} on ${args.serverUrl} \u2026`);
|
|
1459
1585
|
let resolved;
|
|
1460
1586
|
try {
|
|
@@ -1463,6 +1589,7 @@ async function mainInit(args) {
|
|
|
1463
1589
|
fail(err instanceof Error ? err.message : String(err));
|
|
1464
1590
|
}
|
|
1465
1591
|
ok(`resolved "${resolved.projectName}"`);
|
|
1592
|
+
phase("project_info", { status: "ok", summary: `"${resolved.projectName}"` });
|
|
1466
1593
|
if (!resolved.repositoryUrl) {
|
|
1467
1594
|
fail(
|
|
1468
1595
|
`Project "${resolved.projectSlug}" has no GitHub repository configured. Connect GitHub at ${args.serverUrl}/${resolved.orgSlug}/projects/${resolved.projectSlug}/settings/integrations, then re-run init.`
|
|
@@ -1486,7 +1613,14 @@ async function mainInit(args) {
|
|
|
1486
1613
|
fail(`${targetDir} exists and is not empty (and not a matching git repo). Refusing to clone into it. Pass --dir=<other-path>.`);
|
|
1487
1614
|
}
|
|
1488
1615
|
}
|
|
1489
|
-
|
|
1616
|
+
const relTarget = path4.relative(cwd, targetDir) || ".";
|
|
1617
|
+
if (!skipClone) {
|
|
1618
|
+
section(`Cloning ${repoUrl}`);
|
|
1619
|
+
cloneRepo(repoUrl, targetDir, hasGh);
|
|
1620
|
+
phase("clone", { status: "ok", summary: `\u2192 ${relTarget}` });
|
|
1621
|
+
} else {
|
|
1622
|
+
phase("clone", { status: "in-sync", summary: `${relTarget} (already a clone of this repo)` });
|
|
1623
|
+
}
|
|
1490
1624
|
const cfg = {
|
|
1491
1625
|
pat: args.token,
|
|
1492
1626
|
orgSlug: resolved.orgSlug,
|
|
@@ -1495,7 +1629,8 @@ async function mainInit(args) {
|
|
|
1495
1629
|
};
|
|
1496
1630
|
const courseName = args.course ?? inferCourseName(cfg.serverUrl);
|
|
1497
1631
|
writeConfigFile(targetDir, cfg, courseName);
|
|
1498
|
-
|
|
1632
|
+
phase("cred file", { status: "ok", summary: `course=${courseName}, active` });
|
|
1633
|
+
phase(".mcp.json", mergeMcpFile(targetDir, buildLaunchKitMcpEntries(cfg)));
|
|
1499
1634
|
ensureGitignoreLine(targetDir, CONFIG_FILENAME);
|
|
1500
1635
|
let installSkippedReason = null;
|
|
1501
1636
|
const detected = detectPackageManager(targetDir);
|
|
@@ -1505,43 +1640,51 @@ async function mainInit(args) {
|
|
|
1505
1640
|
} else if (!detected) {
|
|
1506
1641
|
installSkippedReason = "no package.json found";
|
|
1507
1642
|
} else {
|
|
1643
|
+
section(`Installing dependencies (${detected.pm.name})`);
|
|
1508
1644
|
runInstall(targetDir, detected);
|
|
1509
|
-
|
|
1645
|
+
phase("install", { status: "ok", summary: `${detected.pm.binary} ${detected.pm.installArgs.join(" ")}` });
|
|
1646
|
+
if (!args.noOnboard && hasOnboardScript(targetDir)) {
|
|
1647
|
+
section(`Running ${detected.pm.binary} run ${ONBOARD_SCRIPT_NAME}`);
|
|
1648
|
+
runOnboard(targetDir, detected.pm);
|
|
1649
|
+
phase("onboard", { status: "ok", summary: `${detected.pm.binary} run ${ONBOARD_SCRIPT_NAME}` });
|
|
1650
|
+
}
|
|
1510
1651
|
}
|
|
1511
1652
|
const hasOnboard = hasOnboardScript(targetDir);
|
|
1512
|
-
if (
|
|
1513
|
-
if (!args.
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1653
|
+
if (installSkippedReason) phase("install", { status: "skipped", summary: installSkippedReason });
|
|
1654
|
+
if (!args.noRecall) {
|
|
1655
|
+
section("Initializing launch-recall (shadow git backup)");
|
|
1656
|
+
runRecallInit(targetDir);
|
|
1657
|
+
phase("launch-recall", { status: "ok", summary: "shadow git ready" });
|
|
1658
|
+
}
|
|
1659
|
+
if (!args.noMigrateSafety) phase("migrate-safety", scaffoldMigrateSafety(targetDir, args.refreshScaffolds));
|
|
1660
|
+
if (!args.noLsMarketplace) phase("ls-marketplace", scaffoldLsMarketplace(targetDir));
|
|
1661
|
+
if (!args.noRecallHook) phase("recall-hook", scaffoldRecallHook(targetDir));
|
|
1662
|
+
const slR = tryActivateStatusline();
|
|
1663
|
+
if (slR) phase("statusline", slR);
|
|
1519
1664
|
if (DRY_RUN) {
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1665
|
+
console.log("");
|
|
1666
|
+
console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1667
|
+
console.log(c.bold("DRY RUN COMPLETE") + c.dim(` \u2014 no files were modified, no commands ran.`));
|
|
1668
|
+
console.log(c.dim(`Target: ${targetDir}`));
|
|
1669
|
+
console.log(c.dim(`Re-run without --dry-run to apply the changes shown above.`));
|
|
1670
|
+
console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1525
1671
|
return;
|
|
1526
1672
|
}
|
|
1527
1673
|
ok(`done \u2014 ${resolved.projectName} is ready at ${targetDir}`);
|
|
1674
|
+
const showGuide = args.quiet ? false : args.guide ?? true;
|
|
1675
|
+
const nextSteps = [`cd ${relTarget}`];
|
|
1528
1676
|
if (installSkippedReason) {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
Next steps (install skipped: ${installSkippedReason}):
|
|
1534
|
-
cd ${relTarget}
|
|
1535
|
-
${installLine}${onboardLine}
|
|
1536
|
-
claude # launch Claude Code (5 MCPs wired)${args.quiet ? "" : `
|
|
1537
|
-
${getLaunchKitToolsGuide()}`}`);
|
|
1538
|
-
} else if (!args.quiet) {
|
|
1539
|
-
console.log(`
|
|
1540
|
-
Next steps:
|
|
1541
|
-
cd ${relTarget}
|
|
1542
|
-
claude # launch Claude Code (5 MCPs wired)
|
|
1543
|
-
${getLaunchKitToolsGuide()}`);
|
|
1677
|
+
nextSteps.push(detected ? `${detected.pm.binary} ${detected.pm.installArgs.join(" ")} # install skipped: ${installSkippedReason}` : `npm install # install skipped: ${installSkippedReason}`);
|
|
1678
|
+
if (hasOnboard && detected && !args.noOnboard) {
|
|
1679
|
+
nextSteps.push(`${detected.pm.binary} run ${ONBOARD_SCRIPT_NAME} # project setup hook`);
|
|
1680
|
+
}
|
|
1544
1681
|
}
|
|
1682
|
+
nextSteps.push("claude # launch Claude Code (5 MCPs wired)");
|
|
1683
|
+
footer(`${resolved.projectName} is ready at ${relTarget}.`, [
|
|
1684
|
+
"Next:",
|
|
1685
|
+
...nextSteps.map((s) => " " + s)
|
|
1686
|
+
]);
|
|
1687
|
+
if (showGuide) console.log(getLaunchKitToolsGuide());
|
|
1545
1688
|
}
|
|
1546
1689
|
main().catch((err) => {
|
|
1547
1690
|
console.error(`[launch-kit] unexpected error: ${err instanceof Error ? err.stack ?? err.message : String(err)}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@launchsecure/launch-kit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"description": "LaunchSecure toolkit — launch-pod (pipeline), launch-chart (project graph MCP), launch-deck (visual playground MCP), launch-kit-beacon (feedback Web Component), launch-recall (file-watcher backup).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "LaunchSecure - AutomateWithUs",
|
|
@@ -31,7 +31,7 @@ Parse `$ARGUMENTS`:
|
|
|
31
31
|
- **--scope=<filter>** — for ERDs, limit to one module or table set (e.g. `--scope=auth` or `--scope=User,Org,Membership`). Default: all tables.
|
|
32
32
|
- **--session=<id>** — deck session name. Default `diagram-<kind>-<subject-slug>`.
|
|
33
33
|
- **--dsl=<raw-mermaid>** — bypass auto-generation; push the user's DSL verbatim.
|
|
34
|
-
- **--feedback** —
|
|
34
|
+
- **--no-feedback** — skip feedback round-trip (rare; only when the caller has already validated the DSL).
|
|
35
35
|
|
|
36
36
|
Examples:
|
|
37
37
|
- `/kit:diagram flowchart user login flow`
|
|
@@ -97,18 +97,38 @@ Rules:
|
|
|
97
97
|
- `read_graph(layer: "db")` returns 0 nodes
|
|
98
98
|
- the chart shows tables but `inspect_node` returns no `columns` (parser misconfiguration)
|
|
99
99
|
|
|
100
|
-
## Push to deck
|
|
100
|
+
## Push to deck — feedback mode is the default
|
|
101
|
+
|
|
102
|
+
**Always use `mode: "feedback"` for diagrams.** Mermaid DSL frequently fails on the first attempt (syntax pitfalls below), and the deck server's auto-error poll is racy (1500ms timeout in `deck-mcp.ts`). Feedback mode gives you two backstops: a synchronous render-error capture *and* explicit user confirmation. Skip only when `--no-feedback` was passed.
|
|
101
103
|
|
|
102
104
|
Call `mcp__launch-deck__deck` with:
|
|
103
105
|
- `session: <session>`
|
|
104
|
-
- `mode: "
|
|
106
|
+
- `mode: "feedback"`
|
|
107
|
+
- `prompt: "Diagram render OK? Reply 'ok' to accept, or paste the error / describe what's wrong."` (ERDs: append "Does this match the schema you expected?")
|
|
105
108
|
- `blocks: [{ type: "mermaid", label: <kind>-<subject>, content: <mermaid-dsl> }]`
|
|
106
109
|
|
|
107
|
-
|
|
110
|
+
### Render-error retry loop
|
|
111
|
+
|
|
112
|
+
The deck MCP catches mermaid parse/render errors via the browser's `onMermaidError` → `/api/render-errors` channel and surfaces them on the `deck` tool response. Handle both signal paths:
|
|
113
|
+
|
|
114
|
+
1. **Synchronous render error** — if the `deck` response is `{ok: false, mermaid_error, failed_source, ...}`, inspect `failed_source` first:
|
|
115
|
+
- If `failed_source` matches the DSL you just pushed → real error. Fix the DSL based on `mermaid_error` and re-push immediately (same session — the tab is already open). Cap at 2 auto-retries before surfacing to the user.
|
|
116
|
+
- If `failed_source` does NOT match what you just pushed → **stale error**. The deck server's `lastRenderError` is a module-level pop register (`consumeRenderError` in `deck-serve.ts`) populated via WebSocket from the browser; if the previous push's render error arrived AFTER its 1500ms MCP poll, it leaks into this push's response. Ignore it and proceed to `await_feedback`.
|
|
117
|
+
2. **User feedback** — if `deck` returned `ok: true`, call `mcp__launch-deck__await_feedback({ session })`. If the reply is positive ("ok", "looks good", thumbs up), you're done. Otherwise treat the reply as a correction (syntax error pasted, "missing X", "wrong direction") and regenerate. Cap at 2 user-feedback retries before stopping and asking for a clearer instruction.
|
|
118
|
+
|
|
119
|
+
### Common Mermaid pitfalls (avoid on first attempt)
|
|
120
|
+
|
|
121
|
+
- **No `<br/>` in participant aliases.** `participant Pod as LaunchPod CLI<br/>(agent)` breaks the parser in many Mermaid builds. Use one-line names or a trailing parenthetical.
|
|
122
|
+
- **Multi-line notes are fragile.** `Note over X: line1<br/>line2` is risky inside `rect` blocks. Keep notes one-line, or chain two `Note` statements.
|
|
123
|
+
- **Multiple `else` branches.** `alt … else … else … else … end` works in current Mermaid but failure modes are noisy; prefer 2-branch alts or split into separate alt blocks.
|
|
124
|
+
- **`rect rgb(...)`** uses **space-separated** values, not commas: `rect rgb(230 240 255)` — not `rect rgb(230,240,255)`. Comma form errors silently in some builds.
|
|
125
|
+
- **Special chars in labels** — wrap in double quotes when using `:`, `(`, `,`, or unicode arrows: `A->>B: "step (1): start"`.
|
|
126
|
+
- **Reserved keywords as actor names** — avoid `end`, `note`, `loop`, `alt`, `opt` as participant ids.
|
|
127
|
+
- **ERD column types** must be one word: `string`, `int`, `datetime`, `enum`. No spaces, no parens.
|
|
108
128
|
|
|
109
129
|
## Open in browser
|
|
110
130
|
|
|
111
|
-
After the push (and after `await_feedback`
|
|
131
|
+
After the final successful push (and after `await_feedback` returns positive), open the per-session URL so the user lands directly on this diagram:
|
|
112
132
|
|
|
113
133
|
```
|
|
114
134
|
open "<deck-url>/#<session>" # macOS
|
|
@@ -150,3 +170,5 @@ Then fall back: render a `flowchart` placeholder explaining "DB layer not availa
|
|
|
150
170
|
- **Cap entities at 25.** Past that, Mermaid wraps unreadably; ask the user to narrow scope.
|
|
151
171
|
- **Mermaid only.** This skill does not draw raster images — Mermaid DSL is the deliverable.
|
|
152
172
|
- **One block per push.**
|
|
173
|
+
- **Feedback mode by default.** Never push a diagram with `mode: "show"` unless `--no-feedback` was explicitly passed. Diagrams are validated artifacts, not fire-and-forget output.
|
|
174
|
+
- **Retry caps.** 2 auto-retries on synchronous render error + 2 user-feedback retries. Beyond that, hand the broken DSL back to the user with the last error message and stop.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{aq as o,ar as n}from"./index-CB-qlwRT.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-DtKQqaI7.js";import{_ as i}from"./index-CB-qlwRT.js";import"./chunk-FMBD7UC4-CmuA5UKn.js";import"./chunk-YZCP3GAM-C44yr620.js";import"./chunk-55IACEB6-COy9hEae.js";import"./chunk-EDXVE4YY-D_f861An.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-DtKQqaI7.js";import{_ as i}from"./index-CB-qlwRT.js";import"./chunk-FMBD7UC4-CmuA5UKn.js";import"./chunk-YZCP3GAM-C44yr620.js";import"./chunk-55IACEB6-COy9hEae.js";import"./chunk-EDXVE4YY-D_f861An.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r}from"./graph-CifKx6G1.js";var e=4;function a(o){return r(o,e)}export{a as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as t,b as r,a,S as s}from"./chunk-OYMX7WX6-vT8z8D-0.js";import{_ as i}from"./index-CB-qlwRT.js";import"./chunk-55IACEB6-COy9hEae.js";import"./chunk-EDXVE4YY-D_f861An.js";var l={parser:a,get db(){return new s(2)},renderer:r,styles:t,init:i(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},"init")};export{l as diagram};
|