@launchsecure/launch-kit 0.0.27 → 0.0.29

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 (48) 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/server/beacon-monitor-entry.js +353 -0
  28. package/dist/server/chart-serve.js +3 -1
  29. package/dist/server/cli.js +276 -218
  30. package/dist/server/course-entry.js +246 -0
  31. package/dist/server/graph-mcp-entry.js +35 -72
  32. package/dist/server/init-entry.js +1051 -122
  33. package/dist/server/orbit-entry.js +187 -24
  34. package/package.json +5 -3
  35. package/scaffolds/ls-marketplace/.claude-plugin/marketplace.json +15 -0
  36. package/scaffolds/ls-marketplace/plugins/kit/.claude-plugin/plugin.json +19 -0
  37. package/scaffolds/ls-marketplace/plugins/kit/commands/activate-beacon.md +216 -0
  38. package/scaffolds/ls-marketplace/plugins/kit/commands/activate-statusline.md +46 -0
  39. package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-array.md +92 -0
  40. package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-clear.md +68 -0
  41. package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-pulse.md +80 -0
  42. package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-scan.md +62 -0
  43. package/scaffolds/ls-marketplace/plugins/kit/commands/deactivate-statusline.md +34 -0
  44. package/scaffolds/ls-marketplace/plugins/kit/commands/show-mcp-status.md +109 -0
  45. package/scaffolds/ls-marketplace/plugins/kit/commands/standup.md +191 -0
  46. package/scaffolds/recall-hook/scripts/ensure-recall.sh +69 -0
  47. package/scaffolds/statusline/statusline-mcp.sh +192 -0
  48. package/scaffolds/statusline/statusline-wrapper.sh +50 -0
@@ -553,8 +553,8 @@ var require_claude_bridge = __commonJS({
553
553
  "../claude-code-web/src/claude-bridge.js"(exports2, module2) {
554
554
  "use strict";
555
555
  var { spawn: spawn4 } = require("node-pty");
556
- var path12 = require("path");
557
- var fs10 = require("fs");
556
+ var path13 = require("path");
557
+ var fs11 = require("fs");
558
558
  var ClaudeBridge = class {
559
559
  constructor() {
560
560
  this.sessions = /* @__PURE__ */ new Map();
@@ -565,14 +565,14 @@ var require_claude_bridge = __commonJS({
565
565
  "/home/ec2-user/.claude/local/claude",
566
566
  "claude",
567
567
  "claude-code",
568
- path12.join(process.env.HOME || "/", ".claude", "local", "claude"),
569
- path12.join(process.env.HOME || "/", ".local", "bin", "claude"),
568
+ path13.join(process.env.HOME || "/", ".claude", "local", "claude"),
569
+ path13.join(process.env.HOME || "/", ".local", "bin", "claude"),
570
570
  "/usr/local/bin/claude",
571
571
  "/usr/bin/claude"
572
572
  ];
573
573
  for (const cmd of possibleCommands) {
574
574
  try {
575
- if (fs10.existsSync(cmd) || this.commandExists(cmd)) {
575
+ if (fs11.existsSync(cmd) || this.commandExists(cmd)) {
576
576
  console.log(`Found Claude command at: ${cmd}`);
577
577
  return cmd;
578
578
  }
@@ -797,8 +797,8 @@ var require_codex_bridge = __commonJS({
797
797
  "../claude-code-web/src/codex-bridge.js"(exports2, module2) {
798
798
  "use strict";
799
799
  var { spawn: spawn4 } = require("node-pty");
800
- var path12 = require("path");
801
- var fs10 = require("fs");
800
+ var path13 = require("path");
801
+ var fs11 = require("fs");
802
802
  var CodexBridge = class {
803
803
  constructor() {
804
804
  this.sessions = /* @__PURE__ */ new Map();
@@ -806,16 +806,16 @@ var require_codex_bridge = __commonJS({
806
806
  }
807
807
  findCodexCommand() {
808
808
  const possibleCommands = [
809
- path12.join(process.env.HOME || "/", ".codex", "local", "codex"),
809
+ path13.join(process.env.HOME || "/", ".codex", "local", "codex"),
810
810
  "codex",
811
811
  "codex-code",
812
- path12.join(process.env.HOME || "/", ".local", "bin", "codex"),
812
+ path13.join(process.env.HOME || "/", ".local", "bin", "codex"),
813
813
  "/usr/local/bin/codex",
814
814
  "/usr/bin/codex"
815
815
  ];
816
816
  for (const cmd of possibleCommands) {
817
817
  try {
818
- if (fs10.existsSync(cmd) || this.commandExists(cmd)) {
818
+ if (fs11.existsSync(cmd) || this.commandExists(cmd)) {
819
819
  console.log(`Found Codex command at: ${cmd}`);
820
820
  return cmd;
821
821
  }
@@ -990,8 +990,8 @@ var require_agent_bridge = __commonJS({
990
990
  "../claude-code-web/src/agent-bridge.js"(exports2, module2) {
991
991
  "use strict";
992
992
  var { spawn: spawn4 } = require("node-pty");
993
- var path12 = require("path");
994
- var fs10 = require("fs");
993
+ var path13 = require("path");
994
+ var fs11 = require("fs");
995
995
  var AgentBridge = class {
996
996
  constructor() {
997
997
  this.sessions = /* @__PURE__ */ new Map();
@@ -999,15 +999,15 @@ var require_agent_bridge = __commonJS({
999
999
  }
1000
1000
  findAgentCommand() {
1001
1001
  const possibleCommands = [
1002
- path12.join(process.env.HOME || "/", ".cursor", "local", "cursor-agent"),
1002
+ path13.join(process.env.HOME || "/", ".cursor", "local", "cursor-agent"),
1003
1003
  "cursor-agent",
1004
- path12.join(process.env.HOME || "/", ".local", "bin", "cursor-agent"),
1004
+ path13.join(process.env.HOME || "/", ".local", "bin", "cursor-agent"),
1005
1005
  "/usr/local/bin/cursor-agent",
1006
1006
  "/usr/bin/cursor-agent"
1007
1007
  ];
1008
1008
  for (const cmd of possibleCommands) {
1009
1009
  try {
1010
- if (fs10.existsSync(cmd) || this.commandExists(cmd)) {
1010
+ if (fs11.existsSync(cmd) || this.commandExists(cmd)) {
1011
1011
  console.log(`Found Agent command at: ${cmd}`);
1012
1012
  return cmd;
1013
1013
  }
@@ -1331,25 +1331,25 @@ var require_script_bridge = __commonJS({
1331
1331
  var require_session_store = __commonJS({
1332
1332
  "../claude-code-web/src/utils/session-store.js"(exports2, module2) {
1333
1333
  "use strict";
1334
- var fs10 = require("fs").promises;
1335
- var path12 = require("path");
1334
+ var fs11 = require("fs").promises;
1335
+ var path13 = require("path");
1336
1336
  var os4 = require("os");
1337
1337
  var SessionStore = class {
1338
1338
  constructor(options = {}) {
1339
- this.storageDir = options.storageDir || path12.join(os4.homedir(), ".claude-code-web");
1340
- this.sessionsFile = path12.join(this.storageDir, "sessions.json");
1339
+ this.storageDir = options.storageDir || path13.join(os4.homedir(), ".claude-code-web");
1340
+ this.sessionsFile = path13.join(this.storageDir, "sessions.json");
1341
1341
  this.initializeStorage();
1342
1342
  }
1343
1343
  async initializeStorage() {
1344
1344
  try {
1345
- await fs10.mkdir(this.storageDir, { recursive: true });
1345
+ await fs11.mkdir(this.storageDir, { recursive: true });
1346
1346
  } catch (error) {
1347
1347
  console.error("Failed to create storage directory:", error);
1348
1348
  }
1349
1349
  }
1350
1350
  async saveSessions(sessions) {
1351
1351
  try {
1352
- await fs10.mkdir(this.storageDir, { recursive: true });
1352
+ await fs11.mkdir(this.storageDir, { recursive: true });
1353
1353
  const sessionsArray = Array.from(sessions.entries()).map(([id, session]) => ({
1354
1354
  id,
1355
1355
  name: session.name || "Unnamed Session",
@@ -1380,9 +1380,9 @@ var require_session_store = __commonJS({
1380
1380
  sessions: sessionsArray
1381
1381
  };
1382
1382
  const tempFile = `${this.sessionsFile}.tmp`;
1383
- await fs10.writeFile(tempFile, JSON.stringify(data, null, 2));
1384
- await fs10.mkdir(this.storageDir, { recursive: true });
1385
- await fs10.rename(tempFile, this.sessionsFile);
1383
+ await fs11.writeFile(tempFile, JSON.stringify(data, null, 2));
1384
+ await fs11.mkdir(this.storageDir, { recursive: true });
1385
+ await fs11.rename(tempFile, this.sessionsFile);
1386
1386
  return true;
1387
1387
  } catch (error) {
1388
1388
  console.error("Failed to save sessions:", error.message);
@@ -1391,8 +1391,8 @@ var require_session_store = __commonJS({
1391
1391
  }
1392
1392
  async loadSessions() {
1393
1393
  try {
1394
- await fs10.access(this.sessionsFile);
1395
- const data = await fs10.readFile(this.sessionsFile, "utf8");
1394
+ await fs11.access(this.sessionsFile);
1395
+ const data = await fs11.readFile(this.sessionsFile, "utf8");
1396
1396
  if (!data || !data.trim()) {
1397
1397
  console.log("Sessions file is empty, starting fresh");
1398
1398
  return /* @__PURE__ */ new Map();
@@ -1403,7 +1403,7 @@ var require_session_store = __commonJS({
1403
1403
  } catch (parseError) {
1404
1404
  console.error("Sessions file is corrupted, starting fresh:", parseError.message);
1405
1405
  try {
1406
- await fs10.rename(this.sessionsFile, `${this.sessionsFile}.corrupted.${Date.now()}`);
1406
+ await fs11.rename(this.sessionsFile, `${this.sessionsFile}.corrupted.${Date.now()}`);
1407
1407
  } catch (renameError) {
1408
1408
  }
1409
1409
  return /* @__PURE__ */ new Map();
@@ -1447,7 +1447,7 @@ var require_session_store = __commonJS({
1447
1447
  }
1448
1448
  async clearOldSessions() {
1449
1449
  try {
1450
- await fs10.unlink(this.sessionsFile);
1450
+ await fs11.unlink(this.sessionsFile);
1451
1451
  console.log("Cleared old sessions");
1452
1452
  return true;
1453
1453
  } catch (error) {
@@ -1459,9 +1459,9 @@ var require_session_store = __commonJS({
1459
1459
  }
1460
1460
  async getSessionMetadata() {
1461
1461
  try {
1462
- await fs10.access(this.sessionsFile);
1463
- const stats = await fs10.stat(this.sessionsFile);
1464
- const data = await fs10.readFile(this.sessionsFile, "utf8");
1462
+ await fs11.access(this.sessionsFile);
1463
+ const stats = await fs11.stat(this.sessionsFile);
1464
+ const data = await fs11.readFile(this.sessionsFile, "utf8");
1465
1465
  const parsed = JSON.parse(data);
1466
1466
  return {
1467
1467
  exists: true,
@@ -1486,13 +1486,13 @@ var require_session_store = __commonJS({
1486
1486
  var require_usage_reader = __commonJS({
1487
1487
  "../claude-code-web/src/usage-reader.js"(exports2, module2) {
1488
1488
  "use strict";
1489
- var fs10 = require("fs").promises;
1490
- var path12 = require("path");
1489
+ var fs11 = require("fs").promises;
1490
+ var path13 = require("path");
1491
1491
  var readline = require("readline");
1492
1492
  var { createReadStream } = require("fs");
1493
1493
  var UsageReader = class {
1494
1494
  constructor(sessionDurationHours = 5) {
1495
- this.claudeProjectsPath = path12.join(process.env.HOME, ".claude", "projects");
1495
+ this.claudeProjectsPath = path13.join(process.env.HOME, ".claude", "projects");
1496
1496
  this.cache = null;
1497
1497
  this.cacheTime = null;
1498
1498
  this.cacheTimeout = 5e3;
@@ -1692,14 +1692,14 @@ var require_usage_reader = __commonJS({
1692
1692
  try {
1693
1693
  const cwd = process.cwd();
1694
1694
  const projectDirName = cwd.replace(/\//g, "-");
1695
- let projectPath = path12.join(this.claudeProjectsPath, projectDirName);
1695
+ let projectPath = path13.join(this.claudeProjectsPath, projectDirName);
1696
1696
  try {
1697
- await fs10.access(projectPath);
1697
+ await fs11.access(projectPath);
1698
1698
  } catch (err2) {
1699
1699
  console.log(`Project directory not found: ${projectPath}`);
1700
1700
  return null;
1701
1701
  }
1702
- const files = await fs10.readdir(projectPath);
1702
+ const files = await fs11.readdir(projectPath);
1703
1703
  const jsonlFiles = files.filter((f) => f.endsWith(".jsonl"));
1704
1704
  if (jsonlFiles.length === 0) {
1705
1705
  return null;
@@ -1707,8 +1707,8 @@ var require_usage_reader = __commonJS({
1707
1707
  let mostRecentFile = null;
1708
1708
  let mostRecentTime = 0;
1709
1709
  for (const file of jsonlFiles) {
1710
- const filePath = path12.join(projectPath, file);
1711
- const stat = await fs10.stat(filePath);
1710
+ const filePath = path13.join(projectPath, file);
1711
+ const stat = await fs11.stat(filePath);
1712
1712
  if (stat.mtime.getTime() > mostRecentTime) {
1713
1713
  mostRecentTime = stat.mtime.getTime();
1714
1714
  mostRecentFile = filePath;
@@ -1723,17 +1723,17 @@ var require_usage_reader = __commonJS({
1723
1723
  async findJsonlFiles(onlyRecent = false) {
1724
1724
  const files = [];
1725
1725
  try {
1726
- const projectDirs = await fs10.readdir(this.claudeProjectsPath);
1726
+ const projectDirs = await fs11.readdir(this.claudeProjectsPath);
1727
1727
  for (const projectDir of projectDirs) {
1728
- const projectPath = path12.join(this.claudeProjectsPath, projectDir);
1729
- const stat = await fs10.stat(projectPath);
1728
+ const projectPath = path13.join(this.claudeProjectsPath, projectDir);
1729
+ const stat = await fs11.stat(projectPath);
1730
1730
  if (stat.isDirectory()) {
1731
- const projectFiles = await fs10.readdir(projectPath);
1731
+ const projectFiles = await fs11.readdir(projectPath);
1732
1732
  const jsonlFiles = projectFiles.filter((f) => f.endsWith(".jsonl"));
1733
1733
  for (const jsonlFile of jsonlFiles) {
1734
- const filePath = path12.join(projectPath, jsonlFile);
1734
+ const filePath = path13.join(projectPath, jsonlFile);
1735
1735
  if (onlyRecent) {
1736
- const fileStat = await fs10.stat(filePath);
1736
+ const fileStat = await fs11.stat(filePath);
1737
1737
  const hoursSinceModified = (Date.now() - fileStat.mtime.getTime()) / (1e3 * 60 * 60);
1738
1738
  if (hoursSinceModified <= 24) {
1739
1739
  files.push(filePath);
@@ -1894,9 +1894,9 @@ var require_usage_reader = __commonJS({
1894
1894
  if (!sessionId) {
1895
1895
  return null;
1896
1896
  }
1897
- const sessionFile = path12.join(this.claudeProjectsPath, path12.basename(process.cwd()).replace(/[^a-zA-Z0-9-]/g, "-"), `${sessionId}.jsonl`);
1897
+ const sessionFile = path13.join(this.claudeProjectsPath, path13.basename(process.cwd()).replace(/[^a-zA-Z0-9-]/g, "-"), `${sessionId}.jsonl`);
1898
1898
  try {
1899
- await fs10.access(sessionFile);
1899
+ await fs11.access(sessionFile);
1900
1900
  } catch (err2) {
1901
1901
  return null;
1902
1902
  }
@@ -2552,7 +2552,7 @@ var require_usage_analytics = __commonJS({
2552
2552
  var require_src = __commonJS({
2553
2553
  "../claude-code-web/src/index.js"(exports2, module2) {
2554
2554
  "use strict";
2555
- var path12 = require("path");
2555
+ var path13 = require("path");
2556
2556
  var WebSocket2 = require("ws");
2557
2557
  var { v4: uuidv4 } = (init_esm_node(), __toCommonJS(esm_node_exports));
2558
2558
  var ClaudeBridge = require_claude_bridge();
@@ -2562,7 +2562,7 @@ var require_src = __commonJS({
2562
2562
  var SessionStore = require_session_store();
2563
2563
  var UsageReader = require_usage_reader();
2564
2564
  var UsageAnalytics = require_usage_analytics();
2565
- var fs10 = require("fs");
2565
+ var fs11 = require("fs");
2566
2566
  function stripAnsi2(str) {
2567
2567
  return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").replace(/\x1b\][^\x07]*\x07/g, "").replace(/\x1b[()][AB012]/g, "").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "").replace(/\r\n?/g, "\n").trim();
2568
2568
  }
@@ -2637,8 +2637,8 @@ var require_src = __commonJS({
2637
2637
  // ── Path validation ──────────────────────────────────────────────────
2638
2638
  isPathWithinBase(targetPath) {
2639
2639
  try {
2640
- const resolvedTarget = path12.resolve(targetPath);
2641
- const resolvedBase = path12.resolve(this.baseFolder);
2640
+ const resolvedTarget = path13.resolve(targetPath);
2641
+ const resolvedBase = path13.resolve(this.baseFolder);
2642
2642
  return resolvedTarget.startsWith(resolvedBase);
2643
2643
  } catch (error) {
2644
2644
  return false;
@@ -2648,7 +2648,7 @@ var require_src = __commonJS({
2648
2648
  if (!targetPath) {
2649
2649
  return { valid: false, error: "Path is required" };
2650
2650
  }
2651
- const resolvedPath = path12.resolve(targetPath);
2651
+ const resolvedPath = path13.resolve(targetPath);
2652
2652
  if (!this.isPathWithinBase(resolvedPath)) {
2653
2653
  return {
2654
2654
  valid: false,
@@ -2820,14 +2820,14 @@ var require_src = __commonJS({
2820
2820
  return true;
2821
2821
  }
2822
2822
  try {
2823
- const items = fs10.readdirSync(validation.path, { withFileTypes: true });
2823
+ const items = fs11.readdirSync(validation.path, { withFileTypes: true });
2824
2824
  const showHidden = url.searchParams.get("showHidden") === "true";
2825
2825
  const folders = items.filter((item) => item.isDirectory()).filter((item) => !item.name.startsWith(".") || showHidden).map((item) => ({
2826
2826
  name: item.name,
2827
- path: path12.join(validation.path, item.name),
2827
+ path: path13.join(validation.path, item.name),
2828
2828
  isDirectory: true
2829
2829
  })).sort((a, b) => a.name.localeCompare(b.name));
2830
- const parentDir = path12.dirname(validation.path);
2830
+ const parentDir = path13.dirname(validation.path);
2831
2831
  const canGoUp = this.isPathWithinBase(parentDir) && parentDir !== validation.path;
2832
2832
  res.writeHead(200, { "Content-Type": "application/json" });
2833
2833
  res.end(JSON.stringify({
@@ -2855,7 +2855,7 @@ var require_src = __commonJS({
2855
2855
  res.end(JSON.stringify({ error: validation.error }));
2856
2856
  return;
2857
2857
  }
2858
- if (!fs10.existsSync(validation.path) || !fs10.statSync(validation.path).isDirectory()) {
2858
+ if (!fs11.existsSync(validation.path) || !fs11.statSync(validation.path).isDirectory()) {
2859
2859
  res.writeHead(400, { "Content-Type": "application/json" });
2860
2860
  res.end(JSON.stringify({ error: "Not a valid directory" }));
2861
2861
  return;
@@ -2882,7 +2882,7 @@ var require_src = __commonJS({
2882
2882
  res.end(JSON.stringify({ error: validation.error }));
2883
2883
  return;
2884
2884
  }
2885
- if (!fs10.existsSync(validation.path) || !fs10.statSync(validation.path).isDirectory()) {
2885
+ if (!fs11.existsSync(validation.path) || !fs11.statSync(validation.path).isDirectory()) {
2886
2886
  res.writeHead(400, { "Content-Type": "application/json" });
2887
2887
  res.end(JSON.stringify({ error: "Invalid directory path" }));
2888
2888
  return;
@@ -2909,7 +2909,7 @@ var require_src = __commonJS({
2909
2909
  return;
2910
2910
  }
2911
2911
  const basePath = parentPath || this.baseFolder;
2912
- const fullPath = path12.join(basePath, folderName);
2912
+ const fullPath = path13.join(basePath, folderName);
2913
2913
  const parentValidation = this.validatePath(basePath);
2914
2914
  const fullValidation = this.validatePath(fullPath);
2915
2915
  if (!parentValidation.valid || !fullValidation.valid) {
@@ -2917,12 +2917,12 @@ var require_src = __commonJS({
2917
2917
  res.end(JSON.stringify({ message: "Cannot create folder outside the allowed area" }));
2918
2918
  return;
2919
2919
  }
2920
- if (fs10.existsSync(fullValidation.path)) {
2920
+ if (fs11.existsSync(fullValidation.path)) {
2921
2921
  res.writeHead(409, { "Content-Type": "application/json" });
2922
2922
  res.end(JSON.stringify({ message: "Folder already exists" }));
2923
2923
  return;
2924
2924
  }
2925
- fs10.mkdirSync(fullValidation.path, { recursive: true });
2925
+ fs11.mkdirSync(fullValidation.path, { recursive: true });
2926
2926
  res.writeHead(200, { "Content-Type": "application/json" });
2927
2927
  res.end(JSON.stringify({ success: true, path: fullValidation.path }));
2928
2928
  } catch (e) {
@@ -2946,10 +2946,10 @@ var require_src = __commonJS({
2946
2946
  const url = new URL(req.url || "/", `http://localhost`);
2947
2947
  let filePath = url.pathname.replace(/^\/terminal\/?/, "");
2948
2948
  if (!filePath || filePath === "") filePath = "index.html";
2949
- const fullPath = path12.join(__dirname, "public", filePath);
2949
+ const fullPath = path13.join(__dirname, "public", filePath);
2950
2950
  try {
2951
- if (!fs10.existsSync(fullPath)) return false;
2952
- const ext = path12.extname(fullPath);
2951
+ if (!fs11.existsSync(fullPath)) return false;
2952
+ const ext = path13.extname(fullPath);
2953
2953
  const mimeTypes = {
2954
2954
  ".html": "text/html",
2955
2955
  ".js": "application/javascript",
@@ -2960,7 +2960,7 @@ var require_src = __commonJS({
2960
2960
  ".ico": "image/x-icon"
2961
2961
  };
2962
2962
  const mime = mimeTypes[ext] || "application/octet-stream";
2963
- const content = fs10.readFileSync(fullPath);
2963
+ const content = fs11.readFileSync(fullPath);
2964
2964
  res.writeHead(200, { "Content-Type": mime });
2965
2965
  res.end(content);
2966
2966
  return true;
@@ -4553,14 +4553,14 @@ var require_util = __commonJS({
4553
4553
  }
4554
4554
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
4555
4555
  let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
4556
- let path12 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
4556
+ let path13 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
4557
4557
  if (origin[origin.length - 1] === "/") {
4558
4558
  origin = origin.slice(0, origin.length - 1);
4559
4559
  }
4560
- if (path12 && path12[0] !== "/") {
4561
- path12 = `/${path12}`;
4560
+ if (path13 && path13[0] !== "/") {
4561
+ path13 = `/${path13}`;
4562
4562
  }
4563
- return new URL(`${origin}${path12}`);
4563
+ return new URL(`${origin}${path13}`);
4564
4564
  }
4565
4565
  if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
4566
4566
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -5011,39 +5011,39 @@ var require_diagnostics = __commonJS({
5011
5011
  });
5012
5012
  diagnosticsChannel.channel("undici:client:sendHeaders").subscribe((evt) => {
5013
5013
  const {
5014
- request: { method, path: path12, origin }
5014
+ request: { method, path: path13, origin }
5015
5015
  } = evt;
5016
- debuglog("sending request to %s %s/%s", method, origin, path12);
5016
+ debuglog("sending request to %s %s/%s", method, origin, path13);
5017
5017
  });
5018
5018
  diagnosticsChannel.channel("undici:request:headers").subscribe((evt) => {
5019
5019
  const {
5020
- request: { method, path: path12, origin },
5020
+ request: { method, path: path13, origin },
5021
5021
  response: { statusCode }
5022
5022
  } = evt;
5023
5023
  debuglog(
5024
5024
  "received response to %s %s/%s - HTTP %d",
5025
5025
  method,
5026
5026
  origin,
5027
- path12,
5027
+ path13,
5028
5028
  statusCode
5029
5029
  );
5030
5030
  });
5031
5031
  diagnosticsChannel.channel("undici:request:trailers").subscribe((evt) => {
5032
5032
  const {
5033
- request: { method, path: path12, origin }
5033
+ request: { method, path: path13, origin }
5034
5034
  } = evt;
5035
- debuglog("trailers received from %s %s/%s", method, origin, path12);
5035
+ debuglog("trailers received from %s %s/%s", method, origin, path13);
5036
5036
  });
5037
5037
  diagnosticsChannel.channel("undici:request:error").subscribe((evt) => {
5038
5038
  const {
5039
- request: { method, path: path12, origin },
5039
+ request: { method, path: path13, origin },
5040
5040
  error
5041
5041
  } = evt;
5042
5042
  debuglog(
5043
5043
  "request to %s %s/%s errored - %s",
5044
5044
  method,
5045
5045
  origin,
5046
- path12,
5046
+ path13,
5047
5047
  error.message
5048
5048
  );
5049
5049
  });
@@ -5092,9 +5092,9 @@ var require_diagnostics = __commonJS({
5092
5092
  });
5093
5093
  diagnosticsChannel.channel("undici:client:sendHeaders").subscribe((evt) => {
5094
5094
  const {
5095
- request: { method, path: path12, origin }
5095
+ request: { method, path: path13, origin }
5096
5096
  } = evt;
5097
- debuglog("sending request to %s %s/%s", method, origin, path12);
5097
+ debuglog("sending request to %s %s/%s", method, origin, path13);
5098
5098
  });
5099
5099
  }
5100
5100
  diagnosticsChannel.channel("undici:websocket:open").subscribe((evt) => {
@@ -5157,7 +5157,7 @@ var require_request = __commonJS({
5157
5157
  var kHandler = /* @__PURE__ */ Symbol("handler");
5158
5158
  var Request = class {
5159
5159
  constructor(origin, {
5160
- path: path12,
5160
+ path: path13,
5161
5161
  method,
5162
5162
  body,
5163
5163
  headers,
@@ -5172,11 +5172,11 @@ var require_request = __commonJS({
5172
5172
  expectContinue,
5173
5173
  servername
5174
5174
  }, handler2) {
5175
- if (typeof path12 !== "string") {
5175
+ if (typeof path13 !== "string") {
5176
5176
  throw new InvalidArgumentError("path must be a string");
5177
- } else if (path12[0] !== "/" && !(path12.startsWith("http://") || path12.startsWith("https://")) && method !== "CONNECT") {
5177
+ } else if (path13[0] !== "/" && !(path13.startsWith("http://") || path13.startsWith("https://")) && method !== "CONNECT") {
5178
5178
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
5179
- } else if (invalidPathRegex.test(path12)) {
5179
+ } else if (invalidPathRegex.test(path13)) {
5180
5180
  throw new InvalidArgumentError("invalid request path");
5181
5181
  }
5182
5182
  if (typeof method !== "string") {
@@ -5242,7 +5242,7 @@ var require_request = __commonJS({
5242
5242
  this.completed = false;
5243
5243
  this.aborted = false;
5244
5244
  this.upgrade = upgrade || null;
5245
- this.path = query ? buildURL(path12, query) : path12;
5245
+ this.path = query ? buildURL(path13, query) : path13;
5246
5246
  this.origin = origin;
5247
5247
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
5248
5248
  this.blocking = blocking == null ? false : blocking;
@@ -9768,7 +9768,7 @@ var require_client_h1 = __commonJS({
9768
9768
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
9769
9769
  }
9770
9770
  function writeH1(client, request) {
9771
- const { method, path: path12, host, upgrade, blocking, reset } = request;
9771
+ const { method, path: path13, host, upgrade, blocking, reset } = request;
9772
9772
  let { body, headers, contentLength } = request;
9773
9773
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
9774
9774
  if (util.isFormDataLike(body)) {
@@ -9834,7 +9834,7 @@ var require_client_h1 = __commonJS({
9834
9834
  if (blocking) {
9835
9835
  socket[kBlocking] = true;
9836
9836
  }
9837
- let header = `${method} ${path12} HTTP/1.1\r
9837
+ let header = `${method} ${path13} HTTP/1.1\r
9838
9838
  `;
9839
9839
  if (typeof host === "string") {
9840
9840
  header += `host: ${host}\r
@@ -10360,7 +10360,7 @@ var require_client_h2 = __commonJS({
10360
10360
  }
10361
10361
  function writeH2(client, request) {
10362
10362
  const session = client[kHTTP2Session];
10363
- const { method, path: path12, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
10363
+ const { method, path: path13, host, upgrade, expectContinue, signal, headers: reqHeaders } = request;
10364
10364
  let { body } = request;
10365
10365
  if (upgrade) {
10366
10366
  util.errorRequest(client, request, new Error("Upgrade not supported for H2"));
@@ -10427,7 +10427,7 @@ var require_client_h2 = __commonJS({
10427
10427
  });
10428
10428
  return true;
10429
10429
  }
10430
- headers[HTTP2_HEADER_PATH] = path12;
10430
+ headers[HTTP2_HEADER_PATH] = path13;
10431
10431
  headers[HTTP2_HEADER_SCHEME] = "https";
10432
10432
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
10433
10433
  if (body && typeof body.read === "function") {
@@ -10780,9 +10780,9 @@ var require_redirect_handler = __commonJS({
10780
10780
  return this.handler.onHeaders(statusCode, headers, resume, statusText);
10781
10781
  }
10782
10782
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
10783
- const path12 = search ? `${pathname}${search}` : pathname;
10783
+ const path13 = search ? `${pathname}${search}` : pathname;
10784
10784
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
10785
- this.opts.path = path12;
10785
+ this.opts.path = path13;
10786
10786
  this.opts.origin = origin;
10787
10787
  this.opts.maxRedirections = 0;
10788
10788
  this.opts.query = null;
@@ -12017,10 +12017,10 @@ var require_proxy_agent = __commonJS({
12017
12017
  };
12018
12018
  const {
12019
12019
  origin,
12020
- path: path12 = "/",
12020
+ path: path13 = "/",
12021
12021
  headers = {}
12022
12022
  } = opts;
12023
- opts.path = origin + path12;
12023
+ opts.path = origin + path13;
12024
12024
  if (!("host" in headers) && !("Host" in headers)) {
12025
12025
  const { host } = new URL3(origin);
12026
12026
  headers.host = host;
@@ -13941,20 +13941,20 @@ var require_mock_utils = __commonJS({
13941
13941
  }
13942
13942
  return true;
13943
13943
  }
13944
- function safeUrl(path12) {
13945
- if (typeof path12 !== "string") {
13946
- return path12;
13944
+ function safeUrl(path13) {
13945
+ if (typeof path13 !== "string") {
13946
+ return path13;
13947
13947
  }
13948
- const pathSegments = path12.split("?");
13948
+ const pathSegments = path13.split("?");
13949
13949
  if (pathSegments.length !== 2) {
13950
- return path12;
13950
+ return path13;
13951
13951
  }
13952
13952
  const qp = new URLSearchParams(pathSegments.pop());
13953
13953
  qp.sort();
13954
13954
  return [...pathSegments, qp.toString()].join("?");
13955
13955
  }
13956
- function matchKey(mockDispatch2, { path: path12, method, body, headers }) {
13957
- const pathMatch = matchValue(mockDispatch2.path, path12);
13956
+ function matchKey(mockDispatch2, { path: path13, method, body, headers }) {
13957
+ const pathMatch = matchValue(mockDispatch2.path, path13);
13958
13958
  const methodMatch = matchValue(mockDispatch2.method, method);
13959
13959
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
13960
13960
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -13976,7 +13976,7 @@ var require_mock_utils = __commonJS({
13976
13976
  function getMockDispatch(mockDispatches, key) {
13977
13977
  const basePath = key.query ? buildURL(key.path, key.query) : key.path;
13978
13978
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
13979
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path12 }) => matchValue(safeUrl(path12), resolvedPath));
13979
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path13 }) => matchValue(safeUrl(path13), resolvedPath));
13980
13980
  if (matchedMockDispatches.length === 0) {
13981
13981
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
13982
13982
  }
@@ -14014,9 +14014,9 @@ var require_mock_utils = __commonJS({
14014
14014
  }
14015
14015
  }
14016
14016
  function buildKey(opts) {
14017
- const { path: path12, method, body, headers, query } = opts;
14017
+ const { path: path13, method, body, headers, query } = opts;
14018
14018
  return {
14019
- path: path12,
14019
+ path: path13,
14020
14020
  method,
14021
14021
  body,
14022
14022
  headers,
@@ -14479,10 +14479,10 @@ var require_pending_interceptors_formatter = __commonJS({
14479
14479
  }
14480
14480
  format(pendingInterceptors) {
14481
14481
  const withPrettyHeaders = pendingInterceptors.map(
14482
- ({ method, path: path12, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
14482
+ ({ method, path: path13, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
14483
14483
  Method: method,
14484
14484
  Origin: origin,
14485
- Path: path12,
14485
+ Path: path13,
14486
14486
  "Status code": statusCode,
14487
14487
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
14488
14488
  Invocations: timesInvoked,
@@ -19363,9 +19363,9 @@ var require_util6 = __commonJS({
19363
19363
  }
19364
19364
  }
19365
19365
  }
19366
- function validateCookiePath(path12) {
19367
- for (let i = 0; i < path12.length; ++i) {
19368
- const code = path12.charCodeAt(i);
19366
+ function validateCookiePath(path13) {
19367
+ for (let i = 0; i < path13.length; ++i) {
19368
+ const code = path13.charCodeAt(i);
19369
19369
  if (code < 32 || // exclude CTLs (0-31)
19370
19370
  code === 127 || // DEL
19371
19371
  code === 59) {
@@ -22042,11 +22042,11 @@ var require_undici = __commonJS({
22042
22042
  if (typeof opts.path !== "string") {
22043
22043
  throw new InvalidArgumentError("invalid opts.path");
22044
22044
  }
22045
- let path12 = opts.path;
22045
+ let path13 = opts.path;
22046
22046
  if (!opts.path.startsWith("/")) {
22047
- path12 = `/${path12}`;
22047
+ path13 = `/${path13}`;
22048
22048
  }
22049
- url = new URL(util.parseOrigin(url).origin + path12);
22049
+ url = new URL(util.parseOrigin(url).origin + path13);
22050
22050
  } else {
22051
22051
  if (!opts) {
22052
22052
  opts = typeof url === "object" ? url : {};
@@ -22727,9 +22727,9 @@ function buildEffectsIndex(layerOutputs) {
22727
22727
  return idx;
22728
22728
  }
22729
22729
  function writeEffectsIndex(rootDir, idx) {
22730
- const path12 = (0, import_node_path11.join)(rootDir, LAUNCHSECURE_DIR, "graphs", "effects-index.json");
22731
- atomicWriteFileSync(path12, JSON.stringify(idx, null, 2) + "\n");
22732
- return path12;
22730
+ const path13 = (0, import_node_path11.join)(rootDir, LAUNCHSECURE_DIR, "graphs", "effects-index.json");
22731
+ atomicWriteFileSync(path13, JSON.stringify(idx, null, 2) + "\n");
22732
+ return path13;
22733
22733
  }
22734
22734
  var import_node_path11;
22735
22735
  var init_effects_index = __esm({
@@ -23040,10 +23040,10 @@ async function generateGraph(rootDir, layer) {
23040
23040
  return results;
23041
23041
  }
23042
23042
  function readEffectsIndex(rootDir) {
23043
- const path12 = (0, import_node_path13.join)(rootDir, GRAPHS_DIR2, "effects-index.json");
23044
- if (!(0, import_node_fs11.existsSync)(path12)) return null;
23043
+ const path13 = (0, import_node_path13.join)(rootDir, GRAPHS_DIR2, "effects-index.json");
23044
+ if (!(0, import_node_fs11.existsSync)(path13)) return null;
23045
23045
  try {
23046
- return JSON.parse((0, import_node_fs11.readFileSync)(path12, "utf-8"));
23046
+ return JSON.parse((0, import_node_fs11.readFileSync)(path13, "utf-8"));
23047
23047
  } catch {
23048
23048
  return null;
23049
23049
  }
@@ -24463,6 +24463,18 @@ function initLaunchPodTerminalBridge(httpServer, projectDir) {
24463
24463
  var import_fs = __toESM(require("fs"));
24464
24464
  var import_path2 = __toESM(require("path"));
24465
24465
  var MANAGED_SERVERS = ["launch-pod", "launch-chart"];
24466
+ function mergeMcpEntry(existing, ours) {
24467
+ if (!existing || typeof existing !== "object") return ours;
24468
+ const prev = existing;
24469
+ const merged = { ...prev, ...ours };
24470
+ if (prev.headers || ours.headers) {
24471
+ merged.headers = { ...prev.headers ?? {}, ...ours.headers ?? {} };
24472
+ }
24473
+ if (prev.env || ours.env) {
24474
+ merged.env = { ...prev.env ?? {}, ...ours.env ?? {} };
24475
+ }
24476
+ return merged;
24477
+ }
24466
24478
  var writtenPaths = [];
24467
24479
  function writeMcpConfigs(opts) {
24468
24480
  const { projectDir, token, serverUrl } = opts;
@@ -24524,17 +24536,17 @@ function writeClaudeConfig(projectDir, mcpUrl, token) {
24524
24536
  }
24525
24537
  }
24526
24538
  const servers = existing.mcpServers ?? {};
24527
- servers["launch-pod"] = {
24539
+ servers["launch-pod"] = mergeMcpEntry(servers["launch-pod"], {
24528
24540
  type: "http",
24529
24541
  url: mcpUrl,
24530
24542
  headers: {
24531
24543
  Authorization: `Bearer ${token}`
24532
24544
  }
24533
- };
24534
- servers["launch-chart"] = {
24545
+ });
24546
+ servers["launch-chart"] = mergeMcpEntry(servers["launch-chart"], {
24535
24547
  command: "launch-chart",
24536
24548
  args: []
24537
- };
24549
+ });
24538
24550
  existing.mcpServers = servers;
24539
24551
  import_fs.default.writeFileSync(filePath, JSON.stringify(existing, null, 2) + "\n", { mode: 384 });
24540
24552
  writtenPaths.push(filePath);
@@ -27072,8 +27084,7 @@ function buildAnalyzerMcpConfig() {
27072
27084
  "launch-chart": {
27073
27085
  command: process.execPath,
27074
27086
  // current node binary, guaranteed-resolvable
27075
- args: [graphEntry],
27076
- env: { LAUNCH_CHART_AUTOSERVE: "1" }
27087
+ args: [graphEntry]
27077
27088
  }
27078
27089
  }
27079
27090
  });
@@ -27091,7 +27102,7 @@ function buildAnalyzerPrompt(ctx) {
27091
27102
  lines.push("If this feedback contains MULTIPLE distinct issues, the first line categorises the PRIMARY one. List the others on subsequent lines as `also <bug|feature|\u2026>: <one sentence>`. The first line is harvested as the card preview; the rest belong to your detailed analysis.");
27092
27103
  lines.push("");
27093
27104
  lines.push("ISSUE ENUMERATION \u2014 DO THIS BEFORE ANY OTHER STEP.");
27094
- lines.push("The user's intent is spread across THREE places: the FEEDBACK BODY, each PIN's NOTE, and the SCREENSHOT. Sub-bugs frequently live in pin notes, not the body. Before any tool call, enumerate every distinct issue you can identify across all three sources. For each issue, decide one of:");
27105
+ lines.push("The user's intent + diagnostic signal is spread across FOUR places: the FEEDBACK BODY, each PIN's NOTE, any RUNTIME EVENTS the beacon captured around the report (silent errors / unhandled rejections \u2014 these often reveal the real failure even when the body is vague), and the SCREENSHOT. Sub-bugs frequently live in pin notes, not the body. Before any tool call, enumerate every distinct issue you can identify across all four sources. For each issue, decide one of:");
27095
27106
  lines.push(" \u2022 fix it now (add to your plan)");
27096
27107
  lines.push(" \u2022 defer it (note why \u2014 out of scope, requires user input, etc.)");
27097
27108
  lines.push(" \u2022 ambiguous \u2192 surface via `AskUserQuestion` BEFORE editing. Do NOT silently drop unclear fragments.");
@@ -27141,6 +27152,21 @@ function buildAnalyzerPrompt(ctx) {
27141
27152
  }
27142
27153
  lines.push("");
27143
27154
  }
27155
+ if (ctx.events && ctx.events.length > 0) {
27156
+ lines.push(`RUNTIME EVENTS (${ctx.events.length}) \u2014 captured by the beacon between page load and Send. Treat these as the highest-signal diagnostic when the body is short. Always check whether the named source file matches a route/component you're investigating before blaming the user-described symptom.`);
27157
+ for (const ev of ctx.events) {
27158
+ const offset = formatEventOffset(ev.ts, ctx.capturedAt);
27159
+ const kindLabel = ev.kind === "unhandledrejection" ? "rejection" : "error";
27160
+ const location = ev.source ? `${ev.source}${ev.line ? `:${ev.line}` : ""}${ev.col ? `:${ev.col}` : ""}` : null;
27161
+ lines.push(`${kindLabel.toUpperCase()} (${offset}): ${ev.message}`);
27162
+ if (location) lines.push(` at ${location}`);
27163
+ if (ev.stack) {
27164
+ const stackHead = ev.stack.split("\n").slice(0, 5).join("\n").slice(0, 600);
27165
+ for (const sl of stackHead.split("\n")) lines.push(` ${sl}`);
27166
+ }
27167
+ }
27168
+ lines.push("");
27169
+ }
27144
27170
  lines.push("PROCEDURE (step 0 is the mandatory category line above \u2014 do NOT repeat the format instruction):");
27145
27171
  let n = 1;
27146
27172
  if (ctx.screenshotLocalPath) {
@@ -27161,6 +27187,16 @@ function buildAnalyzerPrompt(ctx) {
27161
27187
  lines.push(` ${n++}. If any fix is non-trivial, ambiguous, or would touch many files, STOP and either (a) ask via \`AskUserQuestion\`, or (b) write a plan in your final response instead of editing. Better to leave the user a clear next-step than to commit a wrong change.`);
27162
27188
  return lines.join("\n");
27163
27189
  }
27190
+ function formatEventOffset(eventTs, capturedAt) {
27191
+ if (!capturedAt) return `ts=${eventTs}`;
27192
+ const diffMs = eventTs - new Date(capturedAt).getTime();
27193
+ if (!Number.isFinite(diffMs)) return `ts=${eventTs}`;
27194
+ const direction = diffMs <= 0 ? "before report" : "after report";
27195
+ const abs = Math.abs(diffMs);
27196
+ if (abs < 1e3) return `${abs}ms ${direction}`;
27197
+ if (abs < 6e4) return `${(abs / 1e3).toFixed(1)}s ${direction}`;
27198
+ return `${(abs / 6e4).toFixed(1)}m ${direction}`;
27199
+ }
27164
27200
  async function resumeAnalysisSession(params) {
27165
27201
  const { sessionId, projectDir } = params;
27166
27202
  const id = createSessionDirect(`radar: ${sessionId.slice(-8)} (resumed)`, projectDir, sessionId);
@@ -27561,6 +27597,23 @@ function buildContext(payload) {
27561
27597
  const body = typeof resource.body === "string" ? resource.body : payload.message;
27562
27598
  const severity = typeof fields.severity === "string" ? fields.severity : void 0;
27563
27599
  const route = typeof beaconMeta.url === "string" ? beaconMeta.url : void 0;
27600
+ const rawEvents = Array.isArray(fields.events) ? fields.events : [];
27601
+ const events = rawEvents.map((e) => {
27602
+ const kind = e.kind === "error" || e.kind === "unhandledrejection" ? e.kind : null;
27603
+ const ts = typeof e.ts === "number" ? e.ts : null;
27604
+ const message = typeof e.message === "string" ? e.message : null;
27605
+ if (!kind || ts === null || !message) return null;
27606
+ return {
27607
+ ts,
27608
+ kind,
27609
+ message,
27610
+ ...typeof e.stack === "string" ? { stack: e.stack } : {},
27611
+ ...typeof e.source === "string" ? { source: e.source } : {},
27612
+ ...typeof e.line === "number" ? { line: e.line } : {},
27613
+ ...typeof e.col === "number" ? { col: e.col } : {}
27614
+ };
27615
+ }).filter((e) => e !== null);
27616
+ const capturedAt = typeof beaconMeta.capturedAt === "string" ? beaconMeta.capturedAt : void 0;
27564
27617
  const viewport = isViewport(beaconMeta.viewport) ? { w: beaconMeta.viewport.w, h: beaconMeta.viewport.h } : void 0;
27565
27618
  const theme = beaconMeta.theme === "light" || beaconMeta.theme === "dark" ? beaconMeta.theme : void 0;
27566
27619
  const userAgent = typeof beaconMeta.userAgent === "string" ? beaconMeta.userAgent : void 0;
@@ -27573,6 +27626,8 @@ function buildContext(payload) {
27573
27626
  severity,
27574
27627
  route,
27575
27628
  pins: pins.length > 0 ? pins : void 0,
27629
+ events: events.length > 0 ? events : void 0,
27630
+ capturedAt,
27576
27631
  viewport,
27577
27632
  theme,
27578
27633
  userAgent,
@@ -27718,19 +27773,19 @@ var import_node_path3 = require("node:path");
27718
27773
  init_launch_kit_paths();
27719
27774
  var MAX_DEDUPE_SET = 1e3;
27720
27775
  var MAX_PINGS = 200;
27721
- function readJson(path12, fallback) {
27722
- if (!(0, import_node_fs2.existsSync)(path12)) return fallback;
27776
+ function readJson(path13, fallback) {
27777
+ if (!(0, import_node_fs2.existsSync)(path13)) return fallback;
27723
27778
  try {
27724
- return JSON.parse((0, import_node_fs2.readFileSync)(path12, "utf-8"));
27779
+ return JSON.parse((0, import_node_fs2.readFileSync)(path13, "utf-8"));
27725
27780
  } catch {
27726
27781
  return fallback;
27727
27782
  }
27728
27783
  }
27729
- function writeJsonAtomic(path12, value) {
27730
- (0, import_node_fs2.mkdirSync)((0, import_node_path3.dirname)(path12), { recursive: true });
27731
- const tmp = `${path12}.tmp.${process.pid}.${Date.now()}`;
27784
+ function writeJsonAtomic(path13, value) {
27785
+ (0, import_node_fs2.mkdirSync)((0, import_node_path3.dirname)(path13), { recursive: true });
27786
+ const tmp = `${path13}.tmp.${process.pid}.${Date.now()}`;
27732
27787
  (0, import_node_fs2.writeFileSync)(tmp, JSON.stringify(value, null, 2), "utf-8");
27733
- (0, import_node_fs2.renameSync)(tmp, path12);
27788
+ (0, import_node_fs2.renameSync)(tmp, path13);
27734
27789
  }
27735
27790
  var RadarState = class {
27736
27791
  constructor(projectRoot) {
@@ -27863,9 +27918,9 @@ var RadarState = class {
27863
27918
  });
27864
27919
  }
27865
27920
  /** Persist the local path of a successfully-prefetched screenshot. */
27866
- setScreenshotLocalPath(id, path12) {
27921
+ setScreenshotLocalPath(id, path13) {
27867
27922
  return this.mutate(id, (p) => {
27868
- p.context.screenshotLocalPath = path12;
27923
+ p.context.screenshotLocalPath = path13;
27869
27924
  });
27870
27925
  }
27871
27926
  /**
@@ -30882,12 +30937,12 @@ init_launch_kit_paths();
30882
30937
  function loadApiRoutesFromOutput(apiOutput) {
30883
30938
  const routes = [];
30884
30939
  for (const n of apiOutput.nodes) {
30885
- const path12 = n.path;
30886
- if (!path12 || typeof path12 !== "string") continue;
30940
+ const path13 = n.path;
30941
+ if (!path13 || typeof path13 !== "string") continue;
30887
30942
  routes.push({
30888
- path: path12,
30943
+ path: path13,
30889
30944
  nodeId: n.id,
30890
- segments: path12.split("/").filter(Boolean)
30945
+ segments: path13.split("/").filter(Boolean)
30891
30946
  });
30892
30947
  }
30893
30948
  return routes;
@@ -30979,16 +31034,16 @@ function resolveFetchCall(call, apiPathMap, apiRoutes) {
30979
31034
  if (call.isConcat) {
30980
31035
  return { kind: "dynamic", normalizedUrl: raw };
30981
31036
  }
30982
- const { path: path12, hadInterpolation } = normalizeFetchUrl(raw);
30983
- if (!path12.startsWith("/")) {
30984
- return { kind: "unresolved", normalizedUrl: path12 };
31037
+ const { path: path13, hadInterpolation } = normalizeFetchUrl(raw);
31038
+ if (!path13.startsWith("/")) {
31039
+ return { kind: "unresolved", normalizedUrl: path13 };
30985
31040
  }
30986
- const segs = path12.split("/").filter(Boolean);
31041
+ const segs = path13.split("/").filter(Boolean);
30987
31042
  if (hadInterpolation && segs.length > 0 && segs[0].startsWith(":")) {
30988
- return { kind: "dynamic", normalizedUrl: path12 };
31043
+ return { kind: "dynamic", normalizedUrl: path13 };
30989
31044
  }
30990
- const exact = apiPathMap.get(path12);
30991
- if (exact) return { kind: "resolved", nodeId: exact, normalizedUrl: path12 };
31045
+ const exact = apiPathMap.get(path13);
31046
+ if (exact) return { kind: "resolved", nodeId: exact, normalizedUrl: path13 };
30992
31047
  let bestScore = -1;
30993
31048
  let bestId = null;
30994
31049
  for (const r of apiRoutes) {
@@ -30999,21 +31054,21 @@ function resolveFetchCall(call, apiPathMap, apiRoutes) {
30999
31054
  }
31000
31055
  }
31001
31056
  if (bestId && bestScore > 0) {
31002
- return { kind: "resolved", nodeId: bestId, normalizedUrl: path12 };
31057
+ return { kind: "resolved", nodeId: bestId, normalizedUrl: path13 };
31003
31058
  }
31004
- return { kind: "unresolved", normalizedUrl: path12 };
31059
+ return { kind: "unresolved", normalizedUrl: path13 };
31005
31060
  }
31006
31061
  function resolveUrlPath(urlPath, apiPathMap, apiRoutes) {
31007
- const { path: path12, hadInterpolation } = normalizeFetchUrl(urlPath);
31008
- if (!path12.startsWith("/")) {
31009
- return { kind: "unresolved", normalizedUrl: path12 };
31062
+ const { path: path13, hadInterpolation } = normalizeFetchUrl(urlPath);
31063
+ if (!path13.startsWith("/")) {
31064
+ return { kind: "unresolved", normalizedUrl: path13 };
31010
31065
  }
31011
- const segs = path12.split("/").filter(Boolean);
31066
+ const segs = path13.split("/").filter(Boolean);
31012
31067
  if (hadInterpolation && segs.length > 0 && segs[0].startsWith(":")) {
31013
- return { kind: "dynamic", normalizedUrl: path12 };
31068
+ return { kind: "dynamic", normalizedUrl: path13 };
31014
31069
  }
31015
- const exact = apiPathMap.get(path12);
31016
- if (exact) return { kind: "resolved", nodeId: exact, normalizedUrl: path12 };
31070
+ const exact = apiPathMap.get(path13);
31071
+ if (exact) return { kind: "resolved", nodeId: exact, normalizedUrl: path13 };
31017
31072
  let bestScore = -1;
31018
31073
  let bestId = null;
31019
31074
  for (const r of apiRoutes) {
@@ -31024,9 +31079,9 @@ function resolveUrlPath(urlPath, apiPathMap, apiRoutes) {
31024
31079
  }
31025
31080
  }
31026
31081
  if (bestId && bestScore > 0) {
31027
- return { kind: "resolved", nodeId: bestId, normalizedUrl: path12 };
31082
+ return { kind: "resolved", nodeId: bestId, normalizedUrl: path13 };
31028
31083
  }
31029
- return { kind: "unresolved", normalizedUrl: path12 };
31084
+ return { kind: "unresolved", normalizedUrl: path13 };
31030
31085
  }
31031
31086
 
31032
31087
  // src/server/graph/parsers/crosslayer/fetch-resolver.ts
@@ -32004,9 +32059,9 @@ function collectTargets(apiOutput, uiOutput) {
32004
32059
  const out = [];
32005
32060
  for (const n of apiOutput?.nodes ?? []) {
32006
32061
  if (n.type !== "endpoint") continue;
32007
- const path12 = n.path;
32008
- if (typeof path12 !== "string" || !path12) continue;
32009
- out.push({ id: n.id, route: path12, layer: "api" });
32062
+ const path13 = n.path;
32063
+ if (typeof path13 !== "string" || !path13) continue;
32064
+ out.push({ id: n.id, route: path13, layer: "api" });
32010
32065
  }
32011
32066
  for (const n of uiOutput?.nodes ?? []) {
32012
32067
  if (n.type !== "page") continue;
@@ -34297,8 +34352,7 @@ function handleStartChartServer(args) {
34297
34352
  const portArgs = args.port ? ["--port", String(args.port)] : [];
34298
34353
  const child = (0, import_node_child_process3.spawn)(process.execPath, [entryPath, "serve", ...portArgs], {
34299
34354
  detached: true,
34300
- stdio: ["ignore", out, err2],
34301
- env: { ...process.env, LAUNCH_CHART_AUTOSERVE: "" }
34355
+ stdio: ["ignore", out, err2]
34302
34356
  });
34303
34357
  child.unref();
34304
34358
  return okJson({
@@ -34633,6 +34687,53 @@ function startGraphMcpServer() {
34633
34687
 
34634
34688
  // src/server/cli.ts
34635
34689
  init_launch_kit_paths();
34690
+
34691
+ // src/server/cred-shape.ts
34692
+ var fs9 = __toESM(require("node:fs"));
34693
+ var path11 = __toESM(require("node:path"));
34694
+ var CONFIG_FILENAME = ".launch-secure.cred.config";
34695
+ function inferCourseName(serverUrl) {
34696
+ try {
34697
+ const host = new URL(serverUrl).hostname.toLowerCase();
34698
+ if (host === "localhost" || host === "127.0.0.1" || host.endsWith(".local")) return "local";
34699
+ if (host.includes("staging")) return "staging";
34700
+ if (host.endsWith(".vercel.app")) return "prod";
34701
+ return host.split(".")[0] || "default";
34702
+ } catch {
34703
+ return "default";
34704
+ }
34705
+ }
34706
+ function toNested(cred) {
34707
+ if (cred.profiles && cred.active && cred.profiles[cred.active]) {
34708
+ return { active: cred.active, profiles: cred.profiles };
34709
+ }
34710
+ if (!cred.pat || !cred.orgSlug || !cred.projectSlug || !cred.serverUrl) {
34711
+ return null;
34712
+ }
34713
+ const name = inferCourseName(cred.serverUrl);
34714
+ return {
34715
+ active: name,
34716
+ profiles: {
34717
+ [name]: {
34718
+ pat: cred.pat,
34719
+ orgSlug: cred.orgSlug,
34720
+ projectSlug: cred.projectSlug,
34721
+ serverUrl: cred.serverUrl
34722
+ }
34723
+ }
34724
+ };
34725
+ }
34726
+ function readCredFile(repoRoot) {
34727
+ const p = path11.join(repoRoot, CONFIG_FILENAME);
34728
+ if (!fs9.existsSync(p)) return null;
34729
+ try {
34730
+ return JSON.parse(fs9.readFileSync(p, "utf-8"));
34731
+ } catch (err2) {
34732
+ throw new Error(`could not parse ${CONFIG_FILENAME}: ${err2 instanceof Error ? err2.message : String(err2)}`);
34733
+ }
34734
+ }
34735
+
34736
+ // src/server/cli.ts
34636
34737
  var DEFAULT_CAPABILITIES = {
34637
34738
  workspace_setup: true,
34638
34739
  terminal: true
@@ -35246,7 +35347,7 @@ if (parsedArgs.subcommand === "graph:generate" || parsedArgs.subcommand === "gra
35246
35347
  const result = (0, import_child_process4.spawnSync)(
35247
35348
  process.execPath,
35248
35349
  [chartEntry, chartSubcommand, ...process.argv.slice(3)],
35249
- { stdio: "inherit", env: { ...process.env, LAUNCH_CHART_AUTOSERVE: "" } }
35350
+ { stdio: "inherit" }
35250
35351
  );
35251
35352
  process.exit(result.status ?? 1);
35252
35353
  }
@@ -35256,71 +35357,28 @@ if (parsedArgs.subcommand === "mcp:graph") {
35256
35357
  var __isMcpMode = parsedArgs.subcommand === "mcp:graph";
35257
35358
  var __isRadarMode = parsedArgs.subcommand === "radar";
35258
35359
  var radar = null;
35259
- var CRED_CONFIG_FILENAME = ".launch-secure.cred.config";
35260
- var LEGACY_CRED_CONFIG_FILENAME = ".launch-secure.config";
35261
- function migrateLegacyCredConfig(repoRoot) {
35262
- const legacy = import_path9.default.join(repoRoot, LEGACY_CRED_CONFIG_FILENAME);
35263
- const dest = import_path9.default.join(repoRoot, CRED_CONFIG_FILENAME);
35264
- if (!import_fs8.default.existsSync(legacy) || import_fs8.default.existsSync(dest)) return;
35265
- let parsed;
35266
- try {
35267
- parsed = JSON.parse(import_fs8.default.readFileSync(legacy, "utf-8"));
35268
- } catch {
35269
- return;
35270
- }
35271
- const pat = parsed?.pat;
35272
- if (typeof pat !== "string" || !pat.startsWith("ls_pat_")) return;
35273
- import_fs8.default.renameSync(legacy, dest);
35274
- console.warn(`[launchpod] migrated legacy ${LEGACY_CRED_CONFIG_FILENAME} \u2192 ${CRED_CONFIG_FILENAME} (the old name is now reserved for file-backed-config)`);
35275
- }
35276
35360
  function readLaunchSecureMcpConfig() {
35277
- migrateLegacyCredConfig(REPO_ROOT);
35278
- const configPath = import_path9.default.join(REPO_ROOT, CRED_CONFIG_FILENAME);
35279
- if (import_fs8.default.existsSync(configPath)) {
35280
- let parsed;
35281
- try {
35282
- parsed = JSON.parse(import_fs8.default.readFileSync(configPath, "utf-8"));
35283
- } catch (err2) {
35284
- throw new Error(`Could not parse ${configPath}: ${err2 instanceof Error ? err2.message : String(err2)}`);
35285
- }
35286
- const { pat: pat2, orgSlug: orgSlug2, projectSlug: projectSlug2, serverUrl } = parsed;
35287
- if (!pat2 || !pat2.startsWith("ls_pat_")) {
35288
- throw new Error(`${CRED_CONFIG_FILENAME} "pat" is missing or not a LaunchSecure PAT (ls_pat_...).`);
35289
- }
35290
- if (!orgSlug2 || !projectSlug2 || !serverUrl) {
35291
- throw new Error(`${CRED_CONFIG_FILENAME} is missing required fields (orgSlug, projectSlug, serverUrl).`);
35292
- }
35293
- return { pat: pat2, orgSlug: orgSlug2, projectSlug: projectSlug2, serverUrl, source: CRED_CONFIG_FILENAME };
35361
+ const fix = `Run \`npx @launchsecure/launch-kit@latest refresh\` to re-sync this project (or \`init\` if you haven't bootstrapped yet).`;
35362
+ const cred = readCredFile(REPO_ROOT);
35363
+ if (!cred) {
35364
+ throw new Error(`${CONFIG_FILENAME} not found in ${REPO_ROOT}. ${fix}`);
35294
35365
  }
35295
- const mcpPath = import_path9.default.join(REPO_ROOT, ".mcp.json");
35296
- if (!import_fs8.default.existsSync(mcpPath)) {
35297
- throw new Error(
35298
- `Neither ${CRED_CONFIG_FILENAME} nor .mcp.json found in ${REPO_ROOT}. Run \`npx launch-kit init --token=... --org=... --project=...\` to bootstrap.`
35299
- );
35366
+ const nested = toNested(cred);
35367
+ if (!nested) {
35368
+ throw new Error(`${CONFIG_FILENAME} is malformed or missing required fields (pat/orgSlug/projectSlug/serverUrl). ${fix}`);
35300
35369
  }
35301
- const raw = JSON.parse(import_fs8.default.readFileSync(mcpPath, "utf-8"));
35302
- const envName = process.env.LAUNCHPOD_MCP_NAME;
35303
- const entryName = envName ?? (raw.mcpServers?.["local-launch-secure"] ? "local-launch-secure" : "launch-secure");
35304
- const entry = raw.mcpServers?.[entryName];
35305
- if (!entry?.url) {
35306
- throw new Error(`No "${entryName}" entry with url found in .mcp.json (set LAUNCHPOD_MCP_NAME=<name> to pick a different one, or migrate to ${CRED_CONFIG_FILENAME} via \`launch-kit init\`)`);
35370
+ const profile = nested.profiles[nested.active];
35371
+ if (!profile) {
35372
+ throw new Error(`${CONFIG_FILENAME} active course "${nested.active}" not found in profiles. ${fix}`);
35307
35373
  }
35308
- const auth = entry.headers?.["Authorization"] ?? "";
35309
- const pat = auth.replace(/^Bearer\s+/i, "").trim();
35310
- if (!pat.startsWith("ls_pat_")) {
35311
- throw new Error(
35312
- `.mcp.json launch-secure Authorization header is not a PAT (ls_pat_...). Migrate to ${CRED_CONFIG_FILENAME} via \`launch-kit init\`, or update the header.`
35313
- );
35374
+ const { pat, orgSlug, projectSlug, serverUrl } = profile;
35375
+ if (!pat || !pat.startsWith("ls_pat_")) {
35376
+ throw new Error(`${CONFIG_FILENAME} "pat" is missing or not a LaunchSecure PAT (ls_pat_...). ${fix}`);
35314
35377
  }
35315
- const orgSlug = entry.headers?.["X-Org-Slug"];
35316
- const projectSlug = entry.headers?.["X-Project-Slug"];
35317
- if (!orgSlug || !projectSlug) {
35318
- throw new Error(
35319
- "Missing X-Org-Slug / X-Project-Slug headers in .mcp.json launch-secure entry."
35320
- );
35378
+ if (!orgSlug || !projectSlug || !serverUrl) {
35379
+ throw new Error(`${CONFIG_FILENAME} is missing required fields (orgSlug, projectSlug, serverUrl). ${fix}`);
35321
35380
  }
35322
- const url = new URL(entry.url);
35323
- return { pat, orgSlug, projectSlug, serverUrl: `${url.protocol}//${url.host}`, source: `.mcp.json[${entryName}]` };
35381
+ return { pat, orgSlug, projectSlug, serverUrl, source: `${CONFIG_FILENAME}[${nested.active}]` };
35324
35382
  }
35325
35383
  if (!__isMcpMode) {
35326
35384
  let gracefulShutdown = function() {