@launchsecure/launch-kit 0.0.26 → 0.0.28

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.
Files changed (123) hide show
  1. package/dist/beacon/beacon.mjs +1003 -440
  2. package/dist/beacon/beacon.mjs.map +1 -1
  3. package/dist/beacon/beacon.umd.js +45 -24
  4. package/dist/beacon/beacon.umd.js.map +1 -1
  5. package/dist/beacon/types/capture/events.d.ts +20 -0
  6. package/dist/beacon/types/capture/events.d.ts.map +1 -0
  7. package/dist/beacon/types/element.d.ts +1 -0
  8. package/dist/beacon/types/element.d.ts.map +1 -1
  9. package/dist/beacon/types/index.d.ts +2 -1
  10. package/dist/beacon/types/index.d.ts.map +1 -1
  11. package/dist/beacon/types/monitor/dom.d.ts +13 -0
  12. package/dist/beacon/types/monitor/dom.d.ts.map +1 -0
  13. package/dist/beacon/types/monitor/index.d.ts +19 -0
  14. package/dist/beacon/types/monitor/index.d.ts.map +1 -0
  15. package/dist/beacon/types/monitor/network.d.ts +12 -0
  16. package/dist/beacon/types/monitor/network.d.ts.map +1 -0
  17. package/dist/beacon/types/monitor/transport.d.ts +27 -0
  18. package/dist/beacon/types/monitor/transport.d.ts.map +1 -0
  19. package/dist/beacon/types/monitor/types.d.ts +117 -0
  20. package/dist/beacon/types/monitor/types.d.ts.map +1 -0
  21. package/dist/beacon/types/types.d.ts +10 -0
  22. package/dist/beacon/types/types.d.ts.map +1 -1
  23. package/dist/beacon/types/ui/drawer.d.ts +3 -1
  24. package/dist/beacon/types/ui/drawer.d.ts.map +1 -1
  25. package/dist/beacon/types/ui/monitor-panel.d.ts +19 -0
  26. package/dist/beacon/types/ui/monitor-panel.d.ts.map +1 -0
  27. package/dist/chart-client/assets/index-CJ4mgRRF.css +1 -0
  28. package/dist/chart-client/assets/{index-Bk1hawjD.js → index-Ccy-DpI-.js} +46 -42
  29. package/dist/chart-client/index.html +2 -2
  30. package/dist/client/assets/index-DI5qSR_w.css +32 -0
  31. package/dist/client/assets/index-Dp0_okva.js +294 -0
  32. package/dist/client/index.html +2 -2
  33. package/dist/council-client/assets/index-C_-vAM9L.css +1 -0
  34. package/dist/council-client/index.html +2 -2
  35. package/dist/deck-client/assets/{_baseUniq-C2xT_eYu.js → _baseUniq-W2JQDmje.js} +1 -1
  36. package/dist/deck-client/assets/{arc-CmVL9pGd.js → arc-DIBWAId9.js} +1 -1
  37. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-BSFgdjve.js → architectureDiagram-Q4EWVU46-CAIRMvJK.js} +1 -1
  38. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-DuLzscvP.js → blockDiagram-DXYQGD6D-BeNaNiOi.js} +1 -1
  39. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CfCJB8eY.js → c4Diagram-AHTNJAMY-B9Ozi62h.js} +1 -1
  40. package/dist/deck-client/assets/channel-CRdozqbp.js +1 -0
  41. package/dist/deck-client/assets/{chunk-4BX2VUAB-DxmLYTWZ.js → chunk-4BX2VUAB-D7AZ47dt.js} +1 -1
  42. package/dist/deck-client/assets/{chunk-4TB4RGXK-CCnf7GFE.js → chunk-4TB4RGXK-DnVnNPcI.js} +1 -1
  43. package/dist/deck-client/assets/{chunk-55IACEB6-Db9DApcj.js → chunk-55IACEB6-UKYs-YNd.js} +1 -1
  44. package/dist/deck-client/assets/{chunk-EDXVE4YY-DmYDq8ZI.js → chunk-EDXVE4YY-D43b-SKn.js} +1 -1
  45. package/dist/deck-client/assets/{chunk-FMBD7UC4-BGhUlF20.js → chunk-FMBD7UC4-QzBAoyyW.js} +1 -1
  46. package/dist/deck-client/assets/{chunk-OYMX7WX6-CpEnicQZ.js → chunk-OYMX7WX6-Cjif4r6W.js} +1 -1
  47. package/dist/deck-client/assets/{chunk-QZHKN3VN-Doa7LKwf.js → chunk-QZHKN3VN-CqLDirEI.js} +1 -1
  48. package/dist/deck-client/assets/{chunk-YZCP3GAM-CpkIlH6V.js → chunk-YZCP3GAM-_FQvmMs4.js} +1 -1
  49. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-lIZMp57W.js +1 -0
  50. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-lIZMp57W.js +1 -0
  51. package/dist/deck-client/assets/clone-BtWeSTyJ.js +1 -0
  52. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-Bkh8Bfcb.js → cose-bilkent-S5V4N54A-rfrocesE.js} +1 -1
  53. package/dist/deck-client/assets/{dagre-KV5264BT-Bp0XpTgH.js → dagre-KV5264BT-Bv_7DJat.js} +1 -1
  54. package/dist/deck-client/assets/{diagram-5BDNPKRD-ZHiyGYPQ.js → diagram-5BDNPKRD-4F1414G5.js} +1 -1
  55. package/dist/deck-client/assets/{diagram-G4DWMVQ6-BW-Q8_H5.js → diagram-G4DWMVQ6-C4-Pszqm.js} +1 -1
  56. package/dist/deck-client/assets/{diagram-MMDJMWI5-6I3LTafu.js → diagram-MMDJMWI5-B647TIx9.js} +1 -1
  57. package/dist/deck-client/assets/{diagram-TYMM5635-CyM5YK28.js → diagram-TYMM5635-BFAqpezd.js} +1 -1
  58. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-CjNxVJHk.js → erDiagram-SMLLAGMA-BfBfrJOC.js} +1 -1
  59. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-BDQHuAJR.js → flowDiagram-DWJPFMVM-DX9YAYes.js} +1 -1
  60. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-B7MnkpbP.js → ganttDiagram-T4ZO3ILL-DCuiy7wF.js} +1 -1
  61. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-C9dZAcYD.js → gitGraphDiagram-UUTBAWPF-CGp1IXUh.js} +1 -1
  62. package/dist/deck-client/assets/{graph-CjdBnzUy.js → graph-B7g8aoxv.js} +1 -1
  63. package/dist/deck-client/assets/{index-DeIVPW63.js → index-Dg1r-WSN.js} +3 -3
  64. package/dist/deck-client/assets/index-DsIZ3LqL.css +1 -0
  65. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-C7d3iRC3.js → infoDiagram-42DDH7IO-L3fahMkF.js} +1 -1
  66. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-BcYGKj09.js → ishikawaDiagram-UXIWVN3A-aS_EjWBZ.js} +1 -1
  67. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-DqFlRrOL.js → journeyDiagram-VCZTEJTY-djTSQZF9.js} +1 -1
  68. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-BJhPp1NR.js → kanban-definition-6JOO6SKY-CcTHo4CM.js} +1 -1
  69. package/dist/deck-client/assets/{layout-DIeS6GvK.js → layout-mEJiadb7.js} +1 -1
  70. package/dist/deck-client/assets/{linear-He_yJy5H.js → linear-XgTKqyRu.js} +1 -1
  71. package/dist/deck-client/assets/{min-DQ6Kx06t.js → min-Ct9jZdpd.js} +1 -1
  72. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-sQ62L8T2.js → mindmap-definition-QFDTVHPH-BaFxCGNU.js} +1 -1
  73. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-BqCWmU2K.js → pieDiagram-DEJITSTG-CIbYYjtw.js} +1 -1
  74. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-rQ1TJOoe.js → quadrantDiagram-34T5L4WZ-D9EtCOvh.js} +1 -1
  75. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-BO2MPBOM.js → requirementDiagram-MS252O5E-xeni9eVG.js} +1 -1
  76. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BgsHEVex.js → sankeyDiagram-XADWPNL6-LYeknz9h.js} +1 -1
  77. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-B3j1yMLU.js → sequenceDiagram-FGHM5R23-RDbsKFZf.js} +1 -1
  78. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-C8jFlZou.js → stateDiagram-FHFEXIEX-BH1Zjglk.js} +1 -1
  79. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BrV78NDR.js +1 -0
  80. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-tM-qo4Zk.js → timeline-definition-GMOUNBTQ-IFXxKptt.js} +1 -1
  81. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-B0-6kOEu.js → vennDiagram-DHZGUBPP-D-sLkQs9.js} +1 -1
  82. package/dist/deck-client/assets/{wardley-RL74JXVD-HpBk07P-.js → wardley-RL74JXVD-C010F8l4.js} +1 -1
  83. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-BkA1NLDE.js → wardleyDiagram-NUSXRM2D-BTjjuDU3.js} +1 -1
  84. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CEKGSuI-.js → xychartDiagram-5P7HB3ND-AYbv92n-.js} +1 -1
  85. package/dist/deck-client/index.html +2 -2
  86. package/dist/server/beacon-monitor-entry.js +353 -0
  87. package/dist/server/chart-serve.js +3836 -3750
  88. package/dist/server/cli.js +8789 -8219
  89. package/dist/server/council-entry.js +17 -5
  90. package/dist/server/council-serve.js +8 -3
  91. package/dist/server/course-entry.js +246 -0
  92. package/dist/server/deck-mcp-entry.js +24 -12
  93. package/dist/server/deck-serve.js +11 -8
  94. package/dist/server/graph-mcp-entry.js +5005 -4865
  95. package/dist/server/init-entry.js +939 -0
  96. package/dist/server/orbit-entry.js +2435 -0
  97. package/dist/server/parse-worker-entry.js +4721 -0
  98. package/dist/server/recall-entry.js +356 -18
  99. package/package.json +11 -4
  100. package/scaffolds/ls-marketplace/.claude-plugin/marketplace.json +15 -0
  101. package/scaffolds/ls-marketplace/plugins/ls/.claude-plugin/plugin.json +28 -0
  102. package/scaffolds/ls-marketplace/plugins/ls/commands/activate-beacon.md +216 -0
  103. package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-array.md +92 -0
  104. package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-clear.md +68 -0
  105. package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-pulse.md +80 -0
  106. package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-scan.md +62 -0
  107. package/scaffolds/ls-marketplace/plugins/ls/commands/show-mcp-status.md +109 -0
  108. package/scaffolds/ls-marketplace/plugins/ls/commands/standup.md +177 -0
  109. package/scaffolds/migrate-safety/.github/workflows/backup-on-migration.yml +72 -0
  110. package/scaffolds/migrate-safety/docs/migrations-runbook.md +172 -0
  111. package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +294 -0
  112. package/scaffolds/recall-hook/scripts/ensure-recall.sh +69 -0
  113. package/dist/chart-client/assets/index-DpaGa3bY.css +0 -1
  114. package/dist/client/assets/index-Bfel4OQ5.css +0 -32
  115. package/dist/client/assets/index-eC-WuUWB.js +0 -291
  116. package/dist/council-client/assets/index-P5kMsT5a.css +0 -1
  117. package/dist/deck-client/assets/channel-B4aNO8ZB.js +0 -1
  118. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-BHTI0yWz.js +0 -1
  119. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-BHTI0yWz.js +0 -1
  120. package/dist/deck-client/assets/clone-HduFm7qU.js +0 -1
  121. package/dist/deck-client/assets/index-LKZDAS9S.css +0 -1
  122. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BoqepHW0.js +0 -1
  123. /package/dist/council-client/assets/{index-Cs_MVXHf.js → index-Dt4zWKSj.js} +0 -0
@@ -31,9 +31,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  ));
32
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
33
 
34
+ // src/server/launch-kit-paths.ts
35
+ var LAUNCHSECURE_DIR;
36
+ var init_launch_kit_paths = __esm({
37
+ "src/server/launch-kit-paths.ts"() {
38
+ "use strict";
39
+ LAUNCHSECURE_DIR = ".launchsecure";
40
+ }
41
+ });
42
+
34
43
  // src/server/council-lockfile.ts
35
44
  function lockDir(projectRoot) {
36
- return projectRoot ? (0, import_node_path.join)(projectRoot, ".launchsecure") : (0, import_node_path.join)((0, import_node_os.homedir)(), ".launchsecure");
45
+ return projectRoot ? (0, import_node_path.join)(projectRoot, LAUNCHSECURE_DIR) : (0, import_node_path.join)((0, import_node_os.homedir)(), LAUNCHSECURE_DIR);
37
46
  }
38
47
  function lockPath(projectRoot) {
39
48
  return (0, import_node_path.join)(lockDir(projectRoot), "launch-council.lock");
@@ -111,6 +120,7 @@ var init_council_lockfile = __esm({
111
120
  import_node_fs = require("node:fs");
112
121
  import_node_os = require("node:os");
113
122
  import_node_path = require("node:path");
123
+ init_launch_kit_paths();
114
124
  }
115
125
  });
116
126
 
@@ -446,7 +456,7 @@ Be specific with search terms \u2014 use actual names that would appear in code
446
456
 
447
457
  // src/server/graph-reader.ts
448
458
  function readGraphLayer(projectRoot, layer) {
449
- const filePath = (0, import_node_path4.join)(projectRoot, GRAPH_DIR, `${layer}.json`);
459
+ const filePath = (0, import_node_path4.join)(projectRoot, LAUNCHSECURE_DIR, GRAPHS_SUBDIR, `${layer}.json`);
450
460
  if (!(0, import_node_fs4.existsSync)(filePath)) return null;
451
461
  try {
452
462
  return JSON.parse((0, import_node_fs4.readFileSync)(filePath, "utf-8"));
@@ -503,13 +513,14 @@ function searchGraph(projectRoot, searchTerms, layers = ["ui", "api", "db"]) {
503
513
  layers: usedLayers
504
514
  };
505
515
  }
506
- var import_node_fs4, import_node_path4, GRAPH_DIR;
516
+ var import_node_fs4, import_node_path4, GRAPHS_SUBDIR;
507
517
  var init_graph_reader = __esm({
508
518
  "src/server/graph-reader.ts"() {
509
519
  "use strict";
510
520
  import_node_fs4 = require("node:fs");
511
521
  import_node_path4 = require("node:path");
512
- GRAPH_DIR = ".launchsecure/graphs";
522
+ init_launch_kit_paths();
523
+ GRAPHS_SUBDIR = "graphs";
513
524
  }
514
525
  });
515
526
 
@@ -1186,7 +1197,7 @@ async function handleTool(name, args) {
1186
1197
  }));
1187
1198
  }
1188
1199
  try {
1189
- const logDir = (0, import_node_path6.join)((0, import_node_os2.homedir)(), ".launchsecure");
1200
+ const logDir = (0, import_node_path6.join)((0, import_node_os2.homedir)(), LAUNCHSECURE_DIR);
1190
1201
  (0, import_node_fs6.mkdirSync)(logDir, { recursive: true });
1191
1202
  const logPath = (0, import_node_path6.join)(logDir, "launch-council.log");
1192
1203
  const out = (0, import_node_fs6.openSync)(logPath, "a");
@@ -1326,6 +1337,7 @@ var init_council_mcp = __esm({
1326
1337
  import_node_child_process3 = require("node:child_process");
1327
1338
  import_node_fs6 = require("node:fs");
1328
1339
  import_node_os2 = require("node:os");
1340
+ init_launch_kit_paths();
1329
1341
  init_council_lockfile();
1330
1342
  init_council_config();
1331
1343
  SERVER_INFO = {
@@ -152,8 +152,13 @@ var import_node_child_process = require("node:child_process");
152
152
  var import_node_fs = require("node:fs");
153
153
  var import_node_os = require("node:os");
154
154
  var import_node_path = require("node:path");
155
+
156
+ // src/server/launch-kit-paths.ts
157
+ var LAUNCHSECURE_DIR = ".launchsecure";
158
+
159
+ // src/server/council-lockfile.ts
155
160
  function lockDir(projectRoot) {
156
- return projectRoot ? (0, import_node_path.join)(projectRoot, ".launchsecure") : (0, import_node_path.join)((0, import_node_os.homedir)(), ".launchsecure");
161
+ return projectRoot ? (0, import_node_path.join)(projectRoot, LAUNCHSECURE_DIR) : (0, import_node_path.join)((0, import_node_os.homedir)(), LAUNCHSECURE_DIR);
157
162
  }
158
163
  function lockPath(projectRoot) {
159
164
  return (0, import_node_path.join)(lockDir(projectRoot), "launch-council.lock");
@@ -531,9 +536,9 @@ async function extractIntent(adapter, discussionContent) {
531
536
  // src/server/graph-reader.ts
532
537
  var import_node_fs4 = require("node:fs");
533
538
  var import_node_path4 = require("node:path");
534
- var GRAPH_DIR = ".launchsecure/graphs";
539
+ var GRAPHS_SUBDIR = "graphs";
535
540
  function readGraphLayer(projectRoot, layer) {
536
- const filePath = (0, import_node_path4.join)(projectRoot, GRAPH_DIR, `${layer}.json`);
541
+ const filePath = (0, import_node_path4.join)(projectRoot, LAUNCHSECURE_DIR, GRAPHS_SUBDIR, `${layer}.json`);
537
542
  if (!(0, import_node_fs4.existsSync)(filePath)) return null;
538
543
  try {
539
544
  return JSON.parse((0, import_node_fs4.readFileSync)(filePath, "utf-8"));
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/server/course-entry.ts
27
+ var fs2 = __toESM(require("node:fs"));
28
+ var path2 = __toESM(require("node:path"));
29
+
30
+ // src/server/cred-shape.ts
31
+ var fs = __toESM(require("node:fs"));
32
+ var path = __toESM(require("node:path"));
33
+ var CONFIG_FILENAME = ".launch-secure.cred.config";
34
+ function inferCourseName(serverUrl) {
35
+ try {
36
+ const host = new URL(serverUrl).hostname.toLowerCase();
37
+ if (host === "localhost" || host === "127.0.0.1" || host.endsWith(".local")) return "local";
38
+ if (host.includes("staging")) return "staging";
39
+ if (host.endsWith(".vercel.app")) return "prod";
40
+ return host.split(".")[0] || "default";
41
+ } catch {
42
+ return "default";
43
+ }
44
+ }
45
+ function toNested(cred) {
46
+ if (cred.profiles && cred.active && cred.profiles[cred.active]) {
47
+ return { active: cred.active, profiles: cred.profiles };
48
+ }
49
+ if (!cred.pat || !cred.orgSlug || !cred.projectSlug || !cred.serverUrl) {
50
+ return null;
51
+ }
52
+ const name = inferCourseName(cred.serverUrl);
53
+ return {
54
+ active: name,
55
+ profiles: {
56
+ [name]: {
57
+ pat: cred.pat,
58
+ orgSlug: cred.orgSlug,
59
+ projectSlug: cred.projectSlug,
60
+ serverUrl: cred.serverUrl
61
+ }
62
+ }
63
+ };
64
+ }
65
+ function readCredFile(repoRoot) {
66
+ const p = path.join(repoRoot, CONFIG_FILENAME);
67
+ if (!fs.existsSync(p)) return null;
68
+ try {
69
+ return JSON.parse(fs.readFileSync(p, "utf-8"));
70
+ } catch (err) {
71
+ throw new Error(`could not parse ${CONFIG_FILENAME}: ${err instanceof Error ? err.message : String(err)}`);
72
+ }
73
+ }
74
+ function writeJsonAtomic(absPath, value, mode) {
75
+ const tmp = `${absPath}.tmp`;
76
+ fs.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n", "utf-8");
77
+ if (mode !== void 0) {
78
+ try {
79
+ fs.chmodSync(tmp, mode);
80
+ } catch {
81
+ }
82
+ }
83
+ fs.renameSync(tmp, absPath);
84
+ }
85
+
86
+ // src/server/course-entry.ts
87
+ var MCP_FILENAME = ".mcp.json";
88
+ var DEFAULT_SERVER_URL = "https://launchsecure-v2.vercel.app";
89
+ function info(msg) {
90
+ console.log(`[launch-course] ${msg}`);
91
+ }
92
+ function ok(msg) {
93
+ console.log(`[launch-course] \u2713 ${msg}`);
94
+ }
95
+ function fail(msg) {
96
+ console.error(`[launch-course] \u2717 ${msg}`);
97
+ process.exit(1);
98
+ }
99
+ function readCredFile2() {
100
+ const cred = readCredFile(process.cwd());
101
+ if (!cred) {
102
+ fail(`${CONFIG_FILENAME} not found in ${process.cwd()}. Run \`npx launch-kit init \u2026\` first.`);
103
+ }
104
+ return cred;
105
+ }
106
+ function toNested2(cred) {
107
+ const nested = toNested(cred);
108
+ if (!nested) {
109
+ fail(`${CONFIG_FILENAME} is missing required fields (pat, orgSlug, projectSlug, serverUrl) and has no profiles. Run \`npx launch-kit init \u2026\` to (re)bootstrap.`);
110
+ }
111
+ return nested;
112
+ }
113
+ function parseFlag(argv, key) {
114
+ const prefix = `--${key}=`;
115
+ const found = argv.find((a) => a.startsWith(prefix));
116
+ return found ? found.slice(prefix.length) : void 0;
117
+ }
118
+ function cmdList() {
119
+ const nested = toNested2(readCredFile2());
120
+ const names = Object.keys(nested.profiles).sort();
121
+ if (names.length === 0) {
122
+ info("(no courses)");
123
+ return;
124
+ }
125
+ info(`courses (${names.length}):`);
126
+ const nameWidth = Math.max(...names.map((n) => n.length), 8);
127
+ for (const name of names) {
128
+ const p = nested.profiles[name];
129
+ const marker = name === nested.active ? "\u2605" : " ";
130
+ console.log(` ${marker} ${name.padEnd(nameWidth)} ${p.serverUrl} (${p.orgSlug}/${p.projectSlug})`);
131
+ }
132
+ }
133
+ function cmdAdd(argv) {
134
+ const name = argv.find((a) => !a.startsWith("--"));
135
+ if (!name) fail("usage: launch-course add <name> --token=ls_pat_... --org=<slug> --project=<slug> [--url=<serverUrl>]");
136
+ const token = parseFlag(argv, "token");
137
+ const org = parseFlag(argv, "org");
138
+ const project = parseFlag(argv, "project");
139
+ const url = (parseFlag(argv, "url") ?? DEFAULT_SERVER_URL).replace(/\/+$/, "");
140
+ if (!token || !token.startsWith("ls_pat_")) fail("--token=<ls_pat_...> required");
141
+ if (!org) fail("--org=<slug> required");
142
+ if (!project) fail("--project=<slug> required");
143
+ const nested = toNested2(readCredFile2());
144
+ const existed = Boolean(nested.profiles[name]);
145
+ nested.profiles[name] = { pat: token, orgSlug: org, projectSlug: project, serverUrl: url };
146
+ writeJsonAtomic(path2.join(process.cwd(), CONFIG_FILENAME), nested, 384);
147
+ ok(`${existed ? "updated" : "added"} course "${name}" (${url})`);
148
+ if (nested.active !== name) {
149
+ info(`active course is still "${nested.active}" \u2014 run \`launch-course set ${name}\` to switch`);
150
+ }
151
+ }
152
+ function cmdSet(argv) {
153
+ const name = argv[0];
154
+ if (!name) fail("usage: launch-course set <name>");
155
+ const nested = toNested2(readCredFile2());
156
+ const target = nested.profiles[name];
157
+ if (!target) {
158
+ const known = Object.keys(nested.profiles).sort().join(", ") || "(none)";
159
+ fail(`no course named "${name}". known: ${known}`);
160
+ }
161
+ if (nested.active === name) {
162
+ info(`already on "${name}" \u2014 nothing to do`);
163
+ return;
164
+ }
165
+ const next = { active: name, profiles: nested.profiles };
166
+ writeJsonAtomic(path2.join(process.cwd(), CONFIG_FILENAME), next, 384);
167
+ const mcpStatus = updateMcpUrl(target.serverUrl);
168
+ ok(`active course \u2192 "${name}" (${target.serverUrl})`);
169
+ if (mcpStatus === "updated") {
170
+ info("reconnect MCP in Claude Code: /mcp \u2192 toggle launch-secure off/on (URL is read at connect time)");
171
+ }
172
+ }
173
+ function cmdRm(argv) {
174
+ const name = argv[0];
175
+ if (!name) fail("usage: launch-course rm <name>");
176
+ const nested = toNested2(readCredFile2());
177
+ if (!nested.profiles[name]) fail(`no course named "${name}"`);
178
+ if (nested.active === name) {
179
+ fail(`cannot remove the active course "${name}". \`launch-course set <other>\` first.`);
180
+ }
181
+ delete nested.profiles[name];
182
+ writeJsonAtomic(path2.join(process.cwd(), CONFIG_FILENAME), nested, 384);
183
+ ok(`removed course "${name}"`);
184
+ }
185
+ function updateMcpUrl(serverUrl) {
186
+ const p = path2.join(process.cwd(), MCP_FILENAME);
187
+ if (!fs2.existsSync(p)) {
188
+ info(`(no ${MCP_FILENAME} \u2014 skipped URL update; run \`npx launch-kit init \u2026\` to wire MCP)`);
189
+ return "missing-file";
190
+ }
191
+ let mcp;
192
+ try {
193
+ mcp = JSON.parse(fs2.readFileSync(p, "utf-8"));
194
+ } catch (err) {
195
+ fail(`could not parse ${MCP_FILENAME}: ${err instanceof Error ? err.message : String(err)}`);
196
+ }
197
+ const entry = mcp.mcpServers?.["launch-secure"];
198
+ if (!entry) {
199
+ info(`(no "launch-secure" entry in ${MCP_FILENAME} \u2014 skipped URL update)`);
200
+ return "missing-entry";
201
+ }
202
+ entry.url = `${serverUrl.replace(/\/+$/, "")}/api/mcp/project`;
203
+ writeJsonAtomic(p, mcp);
204
+ ok(`updated ${MCP_FILENAME} launch-secure.url \u2192 ${entry.url}`);
205
+ return "updated";
206
+ }
207
+ function help() {
208
+ console.log(`launch-course \u2014 manage LaunchSecure server profiles ("courses").
209
+
210
+ Usage:
211
+ launch-course list
212
+ launch-course add <name> --token=ls_pat_... --org=<slug> --project=<slug> [--url=<serverUrl>]
213
+ launch-course set <name>
214
+ launch-course rm <name>
215
+
216
+ The cred file (.launch-secure.cred.config) holds every course under \`profiles\`,
217
+ with \`active\` selecting which one drives MCP / launch-pod auth. Legacy flat
218
+ files are auto-migrated on the first multi-profile op. \`launch-course set\`
219
+ also rewrites .mcp.json's launch-secure.url so Claude Code routes to the right
220
+ server on next MCP reconnect.
221
+ `);
222
+ }
223
+ function main() {
224
+ const [cmd, ...rest] = process.argv.slice(2);
225
+ switch (cmd) {
226
+ case "list":
227
+ return cmdList();
228
+ case "add":
229
+ return cmdAdd(rest);
230
+ case "set":
231
+ case "use":
232
+ return cmdSet(rest);
233
+ case "rm":
234
+ case "remove":
235
+ case "delete":
236
+ return cmdRm(rest);
237
+ case void 0:
238
+ case "help":
239
+ case "--help":
240
+ case "-h":
241
+ return help();
242
+ default:
243
+ fail(`unknown command "${cmd}". try \`launch-course help\``);
244
+ }
245
+ }
246
+ main();
@@ -30,12 +30,21 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  mod
31
31
  ));
32
32
 
33
+ // src/server/launch-kit-paths.ts
34
+ var LAUNCHSECURE_DIR;
35
+ var init_launch_kit_paths = __esm({
36
+ "src/server/launch-kit-paths.ts"() {
37
+ "use strict";
38
+ LAUNCHSECURE_DIR = ".launchsecure";
39
+ }
40
+ });
41
+
33
42
  // src/server/deck-lockfile.ts
34
43
  function lockDir(projectRoot) {
35
44
  if (projectRoot) {
36
- return (0, import_node_path.join)(projectRoot, ".launchsecure");
45
+ return (0, import_node_path.join)(projectRoot, LAUNCHSECURE_DIR);
37
46
  }
38
- return (0, import_node_path.join)((0, import_node_os.homedir)(), ".launchsecure");
47
+ return (0, import_node_path.join)((0, import_node_os.homedir)(), LAUNCHSECURE_DIR);
39
48
  }
40
49
  function lockPath(projectRoot) {
41
50
  return (0, import_node_path.join)(lockDir(projectRoot), "launch-deck.lock");
@@ -113,6 +122,7 @@ var init_deck_lockfile = __esm({
113
122
  import_node_fs = require("node:fs");
114
123
  import_node_os = require("node:os");
115
124
  import_node_path = require("node:path");
125
+ init_launch_kit_paths();
116
126
  }
117
127
  });
118
128
 
@@ -1322,7 +1332,7 @@ async function startDeckServer(opts = {}) {
1322
1332
  const baseUrl = `/deck-files/${sessionEncoded}`;
1323
1333
  const html = generateBlastRadiusHtml(block.manifest, baseUrl);
1324
1334
  const report = generateBlastRadiusReport(block.manifest);
1325
- const dir = import_node_path3.default.join(cwd, ".launchsecure", "deck-files", body.session);
1335
+ const dir = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
1326
1336
  import_node_fs3.default.mkdirSync(dir, { recursive: true });
1327
1337
  import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, "blast-radius.html"), html);
1328
1338
  import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, "blast-radius-report.md"), report);
@@ -1349,7 +1359,7 @@ async function startDeckServer(opts = {}) {
1349
1359
  const sessionEncoded = encodeURIComponent(body.session);
1350
1360
  const baseUrl = `/deck-files/${sessionEncoded}`;
1351
1361
  const filename = `${slugify(block.label)}.html`;
1352
- const dir = import_node_path3.default.join(cwd, ".launchsecure", "deck-files", body.session);
1362
+ const dir = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
1353
1363
  import_node_fs3.default.mkdirSync(dir, { recursive: true });
1354
1364
  import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, filename), html);
1355
1365
  block.type = "iframe";
@@ -1397,7 +1407,7 @@ async function startDeckServer(opts = {}) {
1397
1407
  resolveFeedback(session, { comment: "", closed: true });
1398
1408
  }
1399
1409
  try {
1400
- const deckFilesBase = import_node_path3.default.join(cwd, ".launchsecure", "deck-files");
1410
+ const deckFilesBase = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1401
1411
  if (session === "all") {
1402
1412
  if (import_node_fs3.default.existsSync(deckFilesBase)) {
1403
1413
  import_node_fs3.default.rmSync(deckFilesBase, { recursive: true, force: true });
@@ -1425,7 +1435,7 @@ async function startDeckServer(opts = {}) {
1425
1435
  res.end("Forbidden");
1426
1436
  return;
1427
1437
  }
1428
- const filePath = import_node_path3.default.join(cwd, ".launchsecure", "deck-files", relative);
1438
+ const filePath = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", relative);
1429
1439
  if (serveStatic(res, filePath)) return;
1430
1440
  res.writeHead(404);
1431
1441
  res.end("Not found");
@@ -1438,7 +1448,7 @@ async function startDeckServer(opts = {}) {
1438
1448
  res.end("Forbidden");
1439
1449
  return;
1440
1450
  }
1441
- const filePath = import_node_path3.default.join(cwd, ".launchsecure", "deck-files", relative);
1451
+ const filePath = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", relative);
1442
1452
  if (!import_node_fs3.default.existsSync(filePath) || !import_node_fs3.default.statSync(filePath).isFile()) {
1443
1453
  res.writeHead(404);
1444
1454
  res.end("Not found");
@@ -1523,7 +1533,7 @@ async function startDeckServer(opts = {}) {
1523
1533
  pendingFeedback.delete(id);
1524
1534
  }
1525
1535
  try {
1526
- const deckFilesBase = import_node_path3.default.join(cwd, ".launchsecure", "deck-files");
1536
+ const deckFilesBase = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1527
1537
  if (import_node_fs3.default.existsSync(deckFilesBase)) {
1528
1538
  import_node_fs3.default.rmSync(deckFilesBase, { recursive: true, force: true });
1529
1539
  }
@@ -1570,6 +1580,7 @@ var init_deck_serve = __esm({
1570
1580
  import_node_fs3 = __toESM(require("node:fs"));
1571
1581
  import_node_path3 = __toESM(require("node:path"));
1572
1582
  import_ws = require("ws");
1583
+ init_launch_kit_paths();
1573
1584
  init_deck_lockfile();
1574
1585
  init_deck_config();
1575
1586
  init_blast_radius_render();
@@ -1660,7 +1671,7 @@ async function handleTool(name, args) {
1660
1671
  const baseUrl = `/deck-files/${sessionEncoded}`;
1661
1672
  const html = generateBlastRadiusHtml(block.manifest, baseUrl);
1662
1673
  const report = generateBlastRadiusReport(block.manifest);
1663
- const dir = (0, import_node_path4.join)(projectRoot, ".launchsecure", "deck-files", session);
1674
+ const dir = (0, import_node_path4.join)(projectRoot, LAUNCHSECURE_DIR, "deck-files", session);
1664
1675
  import_node_fs4.default.mkdirSync(dir, { recursive: true });
1665
1676
  import_node_fs4.default.writeFileSync((0, import_node_path4.join)(dir, "blast-radius.html"), html);
1666
1677
  import_node_fs4.default.writeFileSync((0, import_node_path4.join)(dir, "blast-radius-report.md"), report);
@@ -1687,7 +1698,7 @@ async function handleTool(name, args) {
1687
1698
  const sessionEncoded = encodeURIComponent(session);
1688
1699
  const baseUrl = `/deck-files/${sessionEncoded}`;
1689
1700
  const filename = `${slugify(block.label)}.html`;
1690
- const dir = (0, import_node_path4.join)(projectRoot, ".launchsecure", "deck-files", session);
1701
+ const dir = (0, import_node_path4.join)(projectRoot, LAUNCHSECURE_DIR, "deck-files", session);
1691
1702
  import_node_fs4.default.mkdirSync(dir, { recursive: true });
1692
1703
  import_node_fs4.default.writeFileSync((0, import_node_path4.join)(dir, filename), html);
1693
1704
  block.type = "iframe";
@@ -1782,7 +1793,7 @@ async function handleTool(name, args) {
1782
1793
  }));
1783
1794
  }
1784
1795
  try {
1785
- const logDir = (0, import_node_path4.join)((0, import_node_os2.homedir)(), ".launchsecure");
1796
+ const logDir = (0, import_node_path4.join)((0, import_node_os2.homedir)(), LAUNCHSECURE_DIR);
1786
1797
  (0, import_node_fs5.mkdirSync)(logDir, { recursive: true });
1787
1798
  const logPath = (0, import_node_path4.join)(logDir, "launch-deck.log");
1788
1799
  const out = (0, import_node_fs5.openSync)(logPath, "a");
@@ -1842,7 +1853,7 @@ async function handleTool(name, args) {
1842
1853
  }
1843
1854
  case "generate_contract": {
1844
1855
  const session = args.session;
1845
- const dir = (0, import_node_path4.join)(projectRoot, ".launchsecure", "deck-files", session);
1856
+ const dir = (0, import_node_path4.join)(projectRoot, LAUNCHSECURE_DIR, "deck-files", session);
1846
1857
  const manifestPath = (0, import_node_path4.join)(dir, "blast-radius-manifest.json");
1847
1858
  if (!import_node_fs4.default.existsSync(manifestPath)) {
1848
1859
  return text(JSON.stringify({
@@ -1957,6 +1968,7 @@ var init_deck_mcp = __esm({
1957
1968
  import_node_child_process2 = require("node:child_process");
1958
1969
  import_node_fs5 = require("node:fs");
1959
1970
  import_node_os2 = require("node:os");
1971
+ init_launch_kit_paths();
1960
1972
  init_deck_lockfile();
1961
1973
  init_deck_config();
1962
1974
  init_blast_radius_render();
@@ -43,6 +43,9 @@ var import_node_fs3 = __toESM(require("node:fs"));
43
43
  var import_node_path3 = __toESM(require("node:path"));
44
44
  var import_ws = require("ws");
45
45
 
46
+ // src/server/launch-kit-paths.ts
47
+ var LAUNCHSECURE_DIR = ".launchsecure";
48
+
46
49
  // src/server/deck-lockfile.ts
47
50
  var import_node_child_process = require("node:child_process");
48
51
  var import_node_fs = require("node:fs");
@@ -50,9 +53,9 @@ var import_node_os = require("node:os");
50
53
  var import_node_path = require("node:path");
51
54
  function lockDir(projectRoot) {
52
55
  if (projectRoot) {
53
- return (0, import_node_path.join)(projectRoot, ".launchsecure");
56
+ return (0, import_node_path.join)(projectRoot, LAUNCHSECURE_DIR);
54
57
  }
55
- return (0, import_node_path.join)((0, import_node_os.homedir)(), ".launchsecure");
58
+ return (0, import_node_path.join)((0, import_node_os.homedir)(), LAUNCHSECURE_DIR);
56
59
  }
57
60
  function lockPath(projectRoot) {
58
61
  return (0, import_node_path.join)(lockDir(projectRoot), "launch-deck.lock");
@@ -1312,7 +1315,7 @@ async function startDeckServer(opts = {}) {
1312
1315
  const baseUrl = `/deck-files/${sessionEncoded}`;
1313
1316
  const html = generateBlastRadiusHtml(block.manifest, baseUrl);
1314
1317
  const report = generateBlastRadiusReport(block.manifest);
1315
- const dir = import_node_path3.default.join(cwd, ".launchsecure", "deck-files", body.session);
1318
+ const dir = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
1316
1319
  import_node_fs3.default.mkdirSync(dir, { recursive: true });
1317
1320
  import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, "blast-radius.html"), html);
1318
1321
  import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, "blast-radius-report.md"), report);
@@ -1339,7 +1342,7 @@ async function startDeckServer(opts = {}) {
1339
1342
  const sessionEncoded = encodeURIComponent(body.session);
1340
1343
  const baseUrl = `/deck-files/${sessionEncoded}`;
1341
1344
  const filename = `${slugify(block.label)}.html`;
1342
- const dir = import_node_path3.default.join(cwd, ".launchsecure", "deck-files", body.session);
1345
+ const dir = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
1343
1346
  import_node_fs3.default.mkdirSync(dir, { recursive: true });
1344
1347
  import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, filename), html);
1345
1348
  block.type = "iframe";
@@ -1387,7 +1390,7 @@ async function startDeckServer(opts = {}) {
1387
1390
  resolveFeedback(session, { comment: "", closed: true });
1388
1391
  }
1389
1392
  try {
1390
- const deckFilesBase = import_node_path3.default.join(cwd, ".launchsecure", "deck-files");
1393
+ const deckFilesBase = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1391
1394
  if (session === "all") {
1392
1395
  if (import_node_fs3.default.existsSync(deckFilesBase)) {
1393
1396
  import_node_fs3.default.rmSync(deckFilesBase, { recursive: true, force: true });
@@ -1415,7 +1418,7 @@ async function startDeckServer(opts = {}) {
1415
1418
  res.end("Forbidden");
1416
1419
  return;
1417
1420
  }
1418
- const filePath = import_node_path3.default.join(cwd, ".launchsecure", "deck-files", relative);
1421
+ const filePath = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", relative);
1419
1422
  if (serveStatic(res, filePath)) return;
1420
1423
  res.writeHead(404);
1421
1424
  res.end("Not found");
@@ -1428,7 +1431,7 @@ async function startDeckServer(opts = {}) {
1428
1431
  res.end("Forbidden");
1429
1432
  return;
1430
1433
  }
1431
- const filePath = import_node_path3.default.join(cwd, ".launchsecure", "deck-files", relative);
1434
+ const filePath = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", relative);
1432
1435
  if (!import_node_fs3.default.existsSync(filePath) || !import_node_fs3.default.statSync(filePath).isFile()) {
1433
1436
  res.writeHead(404);
1434
1437
  res.end("Not found");
@@ -1513,7 +1516,7 @@ async function startDeckServer(opts = {}) {
1513
1516
  pendingFeedback.delete(id);
1514
1517
  }
1515
1518
  try {
1516
- const deckFilesBase = import_node_path3.default.join(cwd, ".launchsecure", "deck-files");
1519
+ const deckFilesBase = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1517
1520
  if (import_node_fs3.default.existsSync(deckFilesBase)) {
1518
1521
  import_node_fs3.default.rmSync(deckFilesBase, { recursive: true, force: true });
1519
1522
  }