@launchsecure/launch-kit 0.0.33 → 0.0.34

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.
@@ -23251,6 +23251,7 @@ function emptyParsedFile(absPath) {
23251
23251
  return {
23252
23252
  name: absPath.split("/").pop() ?? absPath,
23253
23253
  exports: [],
23254
+ defines: [],
23254
23255
  imports: [],
23255
23256
  reExports: [],
23256
23257
  jsxElements: /* @__PURE__ */ new Set(),
@@ -23363,6 +23364,34 @@ function parseFileTS(absPath) {
23363
23364
  reExports.push({ name: "*", from: caps["reexport.wildcard.source"], isWildcard: true });
23364
23365
  }
23365
23366
  }
23367
+ const definesSet = /* @__PURE__ */ new Set();
23368
+ function recordCallable(decl) {
23369
+ if (decl.type === "function_declaration" || decl.type === "generator_function_declaration") {
23370
+ const id = childOfType(decl, "identifier");
23371
+ if (id) definesSet.add(id.text);
23372
+ return;
23373
+ }
23374
+ if (decl.type === "class_declaration") {
23375
+ const id = childOfType(decl, "type_identifier") ?? childOfType(decl, "identifier");
23376
+ if (id) definesSet.add(id.text);
23377
+ return;
23378
+ }
23379
+ if (decl.type === "lexical_declaration" || decl.type === "variable_declaration") {
23380
+ for (const d of childrenOfType(decl, "variable_declarator")) {
23381
+ const id = childOfType(d, "identifier");
23382
+ if (!id) continue;
23383
+ const isCallable = !!childOfType(d, "arrow_function") || !!childOfType(d, "function_expression") || !!childOfType(d, "function") || !!childOfType(d, "generator_function");
23384
+ if (isCallable) definesSet.add(id.text);
23385
+ }
23386
+ }
23387
+ }
23388
+ for (const child of root.children) {
23389
+ if (child.type === "export_statement") {
23390
+ for (const gc of child.children) recordCallable(gc);
23391
+ } else {
23392
+ recordCallable(child);
23393
+ }
23394
+ }
23366
23395
  const jsxElements = /* @__PURE__ */ new Set();
23367
23396
  const jsxQuery = getQuery("jsx-elements");
23368
23397
  const jsxCaptures = jsxQuery.captures(root);
@@ -23451,7 +23480,7 @@ function parseFileTS(absPath) {
23451
23480
  }
23452
23481
  }
23453
23482
  const name = defaultName ?? firstValueExport ?? firstTypeExport ?? "";
23454
- return { name, exports: exportsOrdered, imports, reExports, jsxElements, navigations, fetchCalls };
23483
+ return { name, exports: exportsOrdered, defines: [...definesSet], imports, reExports, jsxElements, navigations, fetchCalls };
23455
23484
  }
23456
23485
  function extractDbCallsTS(absPath) {
23457
23486
  const tree = parseSource(absPath);
@@ -24542,17 +24571,17 @@ function shutdownTerminalBridge() {
24542
24571
  }
24543
24572
  }
24544
24573
 
24545
- // src/server/launchpod-terminal-init.ts
24574
+ // src/server/sequencer-terminal-init.ts
24546
24575
  var import_path = __toESM(require("path"));
24547
24576
  init_launch_kit_paths();
24548
- function initLaunchPodTerminalBridge(httpServer, projectDir) {
24577
+ function initSequencerTerminalBridge(httpServer, projectDir) {
24549
24578
  return initTerminalBridge(httpServer, projectDir, import_path.default.join(projectDir, LAUNCHPOD_DIR, "sessions"));
24550
24579
  }
24551
24580
 
24552
24581
  // src/server/mcp-config-writer.ts
24553
24582
  var import_fs = __toESM(require("fs"));
24554
24583
  var import_path2 = __toESM(require("path"));
24555
- var MANAGED_SERVERS = ["launch-pod", "launch-chart"];
24584
+ var MANAGED_SERVERS = ["launch-pod", "launch-sequencer", "launch-chart"];
24556
24585
  function mergeMcpEntry(existing, ours) {
24557
24586
  if (!existing || typeof existing !== "object") return ours;
24558
24587
  const prev = existing;
@@ -24601,7 +24630,7 @@ function removeClaudeEntries(filePath) {
24601
24630
  } else {
24602
24631
  existing.mcpServers = servers;
24603
24632
  import_fs.default.writeFileSync(filePath, JSON.stringify(existing, null, 2) + "\n", { mode: 384 });
24604
- console.log(`MCP config cleaned (LaunchPod entries removed): ${filePath}`);
24633
+ console.log(`MCP config cleaned (launch-sequencer entries removed): ${filePath}`);
24605
24634
  }
24606
24635
  } catch {
24607
24636
  try {
@@ -24626,7 +24655,8 @@ function writeClaudeConfig(projectDir, mcpUrl, token) {
24626
24655
  }
24627
24656
  }
24628
24657
  const servers = existing.mcpServers ?? {};
24629
- servers["launch-pod"] = mergeMcpEntry(servers["launch-pod"], {
24658
+ delete servers["launch-pod"];
24659
+ servers["launch-sequencer"] = mergeMcpEntry(servers["launch-sequencer"], {
24630
24660
  type: "http",
24631
24661
  url: mcpUrl,
24632
24662
  headers: {
@@ -24655,9 +24685,9 @@ function writeCodexConfig(projectDir, mcpUrl, token) {
24655
24685
  }
24656
24686
  } catch {
24657
24687
  }
24658
- const cleaned = existingContent.replace(/\[mcp_servers\.launch-pod\][^\[]*/, "").replace(/\[mcp_servers\.launch-chart\][^\[]*/, "").trim();
24659
- const launchPodBlock = [
24660
- `[mcp_servers.launch-pod]`,
24688
+ const cleaned = existingContent.replace(/\[mcp_servers\.launch-pod\][^\[]*/, "").replace(/\[mcp_servers\.launch-sequencer\][^\[]*/, "").replace(/\[mcp_servers\.launch-chart\][^\[]*/, "").trim();
24689
+ const managedBlock = [
24690
+ `[mcp_servers.launch-sequencer]`,
24661
24691
  `url = "${mcpUrl}"`,
24662
24692
  `http_headers = { "Authorization" = "Bearer ${token}" }`,
24663
24693
  ``,
@@ -24665,7 +24695,7 @@ function writeCodexConfig(projectDir, mcpUrl, token) {
24665
24695
  `command = "launch-chart"`,
24666
24696
  `args = []`
24667
24697
  ].join("\n");
24668
- const merged = cleaned ? cleaned + "\n\n" + launchPodBlock + "\n" : launchPodBlock + "\n";
24698
+ const merged = cleaned ? cleaned + "\n\n" + managedBlock + "\n" : managedBlock + "\n";
24669
24699
  import_fs.default.writeFileSync(filePath, merged, { mode: 384 });
24670
24700
  writtenPaths.push(filePath);
24671
24701
  console.log(`Codex MCP config merged into ${filePath}`);
@@ -28032,7 +28062,7 @@ var RadarState = class {
28032
28062
  }
28033
28063
  };
28034
28064
 
28035
- // src/server/radar/tunnel.ts
28065
+ // src/server/tunnel/index.ts
28036
28066
  var import_node_fs3 = require("node:fs");
28037
28067
  var import_node_events = require("node:events");
28038
28068
  var import_promises = require("node:dns/promises");
@@ -28386,7 +28416,7 @@ var CacheableLookup = class {
28386
28416
  }
28387
28417
  };
28388
28418
 
28389
- // src/server/radar/tunnel.ts
28419
+ // src/server/tunnel/index.ts
28390
28420
  var import_undici = __toESM(require_undici());
28391
28421
  var import_cloudflared = require("cloudflared");
28392
28422
  var dnsResolver = new import_promises.Resolver();
@@ -28404,14 +28434,17 @@ var BACKOFF_MIN_MS = 1e3;
28404
28434
  var BACKOFF_MAX_MS = 3e5;
28405
28435
  var SELFTEST_INTERVAL_MS = 1e3;
28406
28436
  var SELFTEST_TIMEOUT_MS = 9e4;
28407
- function resolveTunnelMode(env = process.env) {
28408
- const token = env.RADAR_CF_TUNNEL_TOKEN?.trim();
28409
- const hostname = env.RADAR_CF_TUNNEL_HOSTNAME?.trim()?.replace(/^https?:\/\//, "").replace(/\/$/, "");
28437
+ function resolveTunnelMode(opts) {
28438
+ const env = opts.env ?? process.env;
28439
+ const tokenKey = `${opts.varPrefix}_TUNNEL_TOKEN`;
28440
+ const hostKey = `${opts.varPrefix}_TUNNEL_HOSTNAME`;
28441
+ const token = env[tokenKey]?.trim();
28442
+ const hostname = env[hostKey]?.trim()?.replace(/^https?:\/\//, "").replace(/\/$/, "");
28410
28443
  if (!token && !hostname) return { kind: "quick" };
28411
28444
  if (!token || !hostname) {
28412
- const missing = !token ? "RADAR_CF_TUNNEL_TOKEN" : "RADAR_CF_TUNNEL_HOSTNAME";
28445
+ const missing = !token ? tokenKey : hostKey;
28413
28446
  throw new Error(
28414
- `[radar] named-tunnel config is partial \u2014 ${missing} is not set. Set BOTH RADAR_CF_TUNNEL_TOKEN and RADAR_CF_TUNNEL_HOSTNAME for a stable paid tunnel, or unset both to fall back to the free quick tunnel.`
28447
+ `[tunnel] named-tunnel config is partial \u2014 ${missing} is not set. Set BOTH ${tokenKey} and ${hostKey} for a stable paid tunnel, or unset both to fall back to the free quick tunnel.`
28415
28448
  );
28416
28449
  }
28417
28450
  return { kind: "named", token, hostname };
@@ -28427,15 +28460,16 @@ var NAMED_FATAL_PATTERNS = [
28427
28460
  /jwt.*expired/i
28428
28461
  ];
28429
28462
  var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28430
- constructor(localPort, mode = { kind: "quick" }) {
28463
+ constructor(opts) {
28431
28464
  super();
28432
28465
  this.tunnel = null;
28433
28466
  this.currentUrl = null;
28434
28467
  this.stopping = false;
28435
28468
  this.fatal = false;
28436
28469
  this.restartAttempt = 0;
28437
- this.localPort = localPort;
28438
- this.mode = mode;
28470
+ this.localPort = opts.localPort;
28471
+ this.mode = opts.mode;
28472
+ this.probePath = opts.probePath;
28439
28473
  }
28440
28474
  get publicUrl() {
28441
28475
  return this.currentUrl;
@@ -28443,7 +28477,7 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28443
28477
  async start() {
28444
28478
  if (this.tunnel) return;
28445
28479
  if (!(0, import_node_fs3.existsSync)(import_cloudflared.bin)) {
28446
- console.log("[radar] downloading cloudflared binary (one-time setup)\u2026");
28480
+ console.log("[tunnel] downloading cloudflared binary (one-time setup)\u2026");
28447
28481
  try {
28448
28482
  await (0, import_cloudflared.install)(import_cloudflared.bin);
28449
28483
  } catch (err2) {
@@ -28452,9 +28486,9 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28452
28486
  }
28453
28487
  }
28454
28488
  if (this.mode.kind === "named") {
28455
- console.log(`[radar] mode=named host=${this.mode.hostname} (paid \xB7 stable URL)`);
28489
+ console.log(`[tunnel] mode=named host=${this.mode.hostname} (paid \xB7 stable URL)`);
28456
28490
  } else {
28457
- console.log(`[radar] mode=quick (free \xB7 *.trycloudflare.com \xB7 ephemeral URL)`);
28491
+ console.log(`[tunnel] mode=quick (free \xB7 *.trycloudflare.com \xB7 ephemeral URL)`);
28458
28492
  }
28459
28493
  this.spawnOnce();
28460
28494
  }
@@ -28493,13 +28527,13 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28493
28527
  if (this.mode.kind === "named") return;
28494
28528
  if (urlSeen === url) return;
28495
28529
  urlSeen = url;
28496
- console.log(`[radar] tunnel subdomain assigned: ${url} (waiting for edge connection)`);
28530
+ console.log(`[tunnel] subdomain assigned: ${url} (waiting for edge connection)`);
28497
28531
  announceIfReady();
28498
28532
  });
28499
28533
  tun.on("connected", (conn) => {
28500
28534
  if (!connectedSeen) {
28501
28535
  connectedSeen = true;
28502
- console.log(`[radar] tunnel connected to edge: ${conn?.location ?? "?"} (${conn?.id ?? "?"})`);
28536
+ console.log(`[tunnel] connected to edge: ${conn?.location ?? "?"} (${conn?.id ?? "?"})`);
28503
28537
  }
28504
28538
  announceIfReady();
28505
28539
  });
@@ -28516,7 +28550,7 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28516
28550
  }
28517
28551
  tun.on("error", (err2) => {
28518
28552
  if (this.stopping) return;
28519
- console.error(`[radar] cloudflared error: ${err2.message}`);
28553
+ console.error(`[tunnel] cloudflared error: ${err2.message}`);
28520
28554
  });
28521
28555
  tun.on("exit", (code) => {
28522
28556
  if (this.stopping) return;
@@ -28536,8 +28570,8 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28536
28570
  if (this.fatal) return;
28537
28571
  this.fatal = true;
28538
28572
  this.stopping = true;
28539
- console.error(`[radar] FATAL: ${reason}`);
28540
- console.error(`[radar] not falling back to free tunnel \u2014 fix RADAR_CF_TUNNEL_TOKEN / RADAR_CF_TUNNEL_HOSTNAME (or unset both) and restart.`);
28573
+ console.error(`[tunnel] FATAL: ${reason}`);
28574
+ console.error(`[tunnel] not falling back to free tunnel \u2014 fix the named-tunnel env vars (or unset both) and restart.`);
28541
28575
  this.emit("fatal", reason);
28542
28576
  try {
28543
28577
  this.tunnel?.stop();
@@ -28551,7 +28585,7 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28551
28585
  * we log loudly but keep cloudflared alive so a later retry can succeed.
28552
28586
  */
28553
28587
  async selfTestAndAnnounce(url) {
28554
- const probeUrl = `${url}/api/radar/ingest`;
28588
+ const probeUrl = `${url}${this.probePath}`;
28555
28589
  const started = Date.now();
28556
28590
  let attempts = 0;
28557
28591
  while (Date.now() - started < SELFTEST_TIMEOUT_MS) {
@@ -28563,7 +28597,7 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28563
28597
  signal: AbortSignal.timeout(5e3),
28564
28598
  dispatcher: dnsResilientDispatcher
28565
28599
  });
28566
- console.log(`[radar] self-test ok (${res.status}) after ${attempts} attempt(s)`);
28600
+ console.log(`[tunnel] self-test ok (${res.status}) after ${attempts} attempt(s)`);
28567
28601
  this.currentUrl = url;
28568
28602
  this.restartAttempt = 0;
28569
28603
  this.emit("ready", url);
@@ -28571,26 +28605,42 @@ var CloudflaredTunnel = class extends import_node_events.EventEmitter {
28571
28605
  } catch (err2) {
28572
28606
  if (attempts === 1 || attempts % 10 === 0) {
28573
28607
  const msg = err2 instanceof Error ? err2.message : String(err2);
28574
- console.log(`[radar] self-test attempt ${attempts}: ${msg} \u2014 retrying`);
28608
+ console.log(`[tunnel] self-test attempt ${attempts}: ${msg} \u2014 retrying`);
28575
28609
  }
28576
28610
  await new Promise((r) => setTimeout(r, SELFTEST_INTERVAL_MS));
28577
28611
  }
28578
28612
  }
28579
- console.error(`[radar] self-test gave up after ${Math.round(SELFTEST_TIMEOUT_MS / 1e3)}s \u2014 tunnel announced but unreachable from this host`);
28613
+ console.error(`[tunnel] self-test gave up after ${Math.round(SELFTEST_TIMEOUT_MS / 1e3)}s \u2014 tunnel announced but unreachable from this host`);
28580
28614
  }
28581
28615
  scheduleRestart() {
28582
28616
  if (this.stopping) return;
28583
28617
  this.restartAttempt += 1;
28584
28618
  const delay = Math.min(BACKOFF_MIN_MS * 2 ** (this.restartAttempt - 1), BACKOFF_MAX_MS);
28585
- console.log(`[radar] tunnel down \u2014 restarting in ${Math.round(delay / 1e3)}s (attempt ${this.restartAttempt})`);
28619
+ console.log(`[tunnel] down \u2014 restarting in ${Math.round(delay / 1e3)}s (attempt ${this.restartAttempt})`);
28586
28620
  setTimeout(() => this.spawnOnce(), delay);
28587
28621
  }
28588
28622
  };
28623
+ function createTunnel(opts) {
28624
+ if (opts.provider === null) return null;
28625
+ if (opts.provider === "cloudflare") {
28626
+ if (!opts.varPrefix) {
28627
+ throw new Error(`[tunnel] createTunnel({ provider: "cloudflare" }) requires varPrefix`);
28628
+ }
28629
+ const mode = resolveTunnelMode({ varPrefix: opts.varPrefix, env: opts.env });
28630
+ return new CloudflaredTunnel({
28631
+ localPort: opts.localPort,
28632
+ mode,
28633
+ probePath: opts.probePath
28634
+ });
28635
+ }
28636
+ const exhaustive = opts.provider;
28637
+ throw new Error(`[tunnel] unknown provider: ${String(exhaustive)}`);
28638
+ }
28589
28639
 
28590
28640
  // src/server/radar/agent.ts
28591
28641
  var SLOT_RELEASE_MS = 15 * 60 * 1e3;
28592
28642
  var AUTO_RESUME_STALENESS_MS = 60 * 60 * 1e3;
28593
- var Radar = class {
28643
+ var Radar = class _Radar {
28594
28644
  constructor(opts) {
28595
28645
  this.wss = null;
28596
28646
  this.clients = /* @__PURE__ */ new Set();
@@ -28615,7 +28665,18 @@ var Radar = class {
28615
28665
  orgSlug: opts.orgSlug,
28616
28666
  projectSlug: opts.projectSlug
28617
28667
  });
28618
- this.tunnel = new CloudflaredTunnel(opts.localPort, resolveTunnelMode());
28668
+ const tunnel = createTunnel({
28669
+ provider: _Radar.TUNNEL_PROVIDER,
28670
+ localPort: opts.localPort,
28671
+ probePath: RECEIVER_PATH,
28672
+ varPrefix: "RADAR_CF"
28673
+ });
28674
+ if (!tunnel) {
28675
+ throw new Error(
28676
+ `[radar] tunnel provider "${_Radar.TUNNEL_PROVIDER}" produced no tunnel \u2014 radar requires a public URL to register its receiver webhook.`
28677
+ );
28678
+ }
28679
+ this.tunnel = tunnel;
28619
28680
  this.maxConcurrent = parsePositiveInt(process.env.RADAR_MAX_CONCURRENT_ANALYSES);
28620
28681
  const callbacks = {
28621
28682
  onLive: () => this.handleLive(),
@@ -28627,6 +28688,13 @@ var Radar = class {
28627
28688
  };
28628
28689
  this.receiver = createReceiver({ state: this.state, callbacks });
28629
28690
  }
28691
+ static {
28692
+ // Tunnel provider is hardcoded for now — radar today cannot function
28693
+ // without a public URL (it has to register the receiver as a webhook with
28694
+ // LaunchSecure). If a future story wants radar to run behind a pre-existing
28695
+ // public hostname, add a "none" branch with a RADAR_PUBLIC_URL escape hatch.
28696
+ this.TUNNEL_PROVIDER = "cloudflare";
28697
+ }
28630
28698
  /** Spawn tunnel, register (or refresh) the webhook, wait for activation. */
28631
28699
  start() {
28632
28700
  this.status = "tunneling";
@@ -29870,6 +29938,11 @@ function generate(rootDir) {
29870
29938
  const parsed = parsedByPath.get(absPath);
29871
29939
  const name = parsed.name || nameFromFilename(absPath);
29872
29940
  const layer = CLASSIFICATION_TO_LAYER[type] ?? "ui";
29941
+ const importedNames = [...new Set(
29942
+ parsed.imports.flatMap(
29943
+ (imp) => imp.isTypeOnly ? [] : imp.names.filter((n) => !imp.typeNames.has(n))
29944
+ )
29945
+ )];
29873
29946
  nodeIdSet.add(id);
29874
29947
  if (layer === "api") {
29875
29948
  const dbCalls = extractDbCallsTS(absPath);
@@ -29908,6 +29981,8 @@ function generate(rootDir) {
29908
29981
  responses: deep.responses,
29909
29982
  params: deep.params,
29910
29983
  ...deep.effects ? { effects: deep.effects } : {},
29984
+ ...parsed.defines.length > 0 ? { defines: parsed.defines } : {},
29985
+ ...importedNames.length > 0 ? { imported_names: importedNames } : {},
29911
29986
  ...deep.notes ? { notes: deep.notes } : {},
29912
29987
  _dbCalls: dbCalls
29913
29988
  // temp: used for cross-ref building below
@@ -29924,6 +29999,8 @@ function generate(rootDir) {
29924
29999
  layer: "ui",
29925
30000
  route,
29926
30001
  exports: parsed.exports,
30002
+ ...parsed.defines.length > 0 ? { defines: parsed.defines } : {},
30003
+ ...importedNames.length > 0 ? { imported_names: importedNames } : {},
29927
30004
  elements: deep.elements,
29928
30005
  stateVars: deep.stateVars,
29929
30006
  conditions: deep.conditions,
@@ -32884,6 +32961,132 @@ var middlewareGatesParser = {
32884
32961
  }
32885
32962
  };
32886
32963
 
32964
+ // src/server/graph/parsers/crosslayer/call-resolver.ts
32965
+ var BARE_IDENT = /^[A-Za-z_$][\w$]*$/;
32966
+ var callResolverParser = {
32967
+ id: "call-resolver",
32968
+ layer: "crosslayer",
32969
+ concern: "call-graph",
32970
+ detect(_rootDir) {
32971
+ return true;
32972
+ },
32973
+ generate(_rootDir, layerOutputs) {
32974
+ const definers = /* @__PURE__ */ new Map();
32975
+ const addDef = (sym, entry) => {
32976
+ if (!BARE_IDENT.test(sym)) return;
32977
+ const list = definers.get(sym);
32978
+ if (!list) {
32979
+ definers.set(sym, [entry]);
32980
+ } else if (!list.some((d) => d.nodeId === entry.nodeId)) {
32981
+ list.push(entry);
32982
+ }
32983
+ };
32984
+ const nodeLayer = /* @__PURE__ */ new Map();
32985
+ for (const [layer, output] of layerOutputs) {
32986
+ if (layer === "db" || layer === "static") continue;
32987
+ for (const node of output.nodes) {
32988
+ nodeLayer.set(node.id, layer);
32989
+ const entry = { nodeId: node.id, layer };
32990
+ for (const s of node.exports ?? []) addDef(s, entry);
32991
+ for (const s of node.defines ?? []) addDef(s, entry);
32992
+ }
32993
+ }
32994
+ const importTargets = /* @__PURE__ */ new Map();
32995
+ for (const [, output] of layerOutputs) {
32996
+ for (const e of output.edges) {
32997
+ if (e.type !== "imports" && e.type !== "imports_type" && e.type !== "renders") continue;
32998
+ let set = importTargets.get(e.source);
32999
+ if (!set) {
33000
+ set = /* @__PURE__ */ new Set();
33001
+ importTargets.set(e.source, set);
33002
+ }
33003
+ set.add(e.target);
33004
+ }
33005
+ }
33006
+ const crossRefs = [];
33007
+ const seen = /* @__PURE__ */ new Set();
33008
+ let resolvedSelf = 0;
33009
+ let resolvedImport = 0;
33010
+ let ambiguous = 0;
33011
+ let dropped = 0;
33012
+ for (const [, output] of layerOutputs) {
33013
+ for (const node of output.nodes) {
33014
+ const calls = node.effects?.calls;
33015
+ if (!calls || calls.length === 0) continue;
33016
+ const selfSyms = /* @__PURE__ */ new Set([
33017
+ ...node.exports ?? [],
33018
+ ...node.defines ?? []
33019
+ ]);
33020
+ const importedSyms = new Set(node.imported_names ?? []);
33021
+ const myImports = importTargets.get(node.id);
33022
+ const localSeen = /* @__PURE__ */ new Set();
33023
+ for (const callee of calls) {
33024
+ if (!BARE_IDENT.test(callee)) continue;
33025
+ if (localSeen.has(callee)) continue;
33026
+ localSeen.add(callee);
33027
+ const key = `${node.id}\u2192${callee}`;
33028
+ if (selfSyms.has(callee)) {
33029
+ if (seen.has(key)) continue;
33030
+ seen.add(key);
33031
+ crossRefs.push({
33032
+ source: node.id,
33033
+ target: callee,
33034
+ type: "calls",
33035
+ layer: nodeLayer.get(node.id) ?? "ui",
33036
+ defined_in: node.id
33037
+ });
33038
+ resolvedSelf++;
33039
+ continue;
33040
+ }
33041
+ if (!importedSyms.has(callee)) {
33042
+ dropped++;
33043
+ continue;
33044
+ }
33045
+ const defs = (definers.get(callee) ?? []).filter((d) => d.nodeId !== node.id);
33046
+ if (defs.length === 0) {
33047
+ dropped++;
33048
+ continue;
33049
+ }
33050
+ const fromImported = myImports ? defs.filter((d) => myImports.has(d.nodeId)) : [];
33051
+ const chosen = fromImported.length > 0 ? fromImported : defs;
33052
+ const owner = chosen[0];
33053
+ const isAmbiguous = chosen.length > 1;
33054
+ if (isAmbiguous) ambiguous++;
33055
+ if (seen.has(key)) continue;
33056
+ seen.add(key);
33057
+ const ref = {
33058
+ source: node.id,
33059
+ target: callee,
33060
+ type: "calls",
33061
+ layer: owner.layer,
33062
+ defined_in: owner.nodeId
33063
+ };
33064
+ if (isAmbiguous) ref.ambiguous = true;
33065
+ crossRefs.push(ref);
33066
+ resolvedImport++;
33067
+ }
33068
+ }
33069
+ }
33070
+ crossRefs.sort(
33071
+ (a, b) => a.source.localeCompare(b.source) || a.target.localeCompare(b.target)
33072
+ );
33073
+ return {
33074
+ cross_refs: crossRefs,
33075
+ flagged_edges: [],
33076
+ warnings: [],
33077
+ patterns: {
33078
+ call_resolution: {
33079
+ resolved_self: resolvedSelf,
33080
+ resolved_import: resolvedImport,
33081
+ ambiguous,
33082
+ dropped,
33083
+ symbols_defined: definers.size
33084
+ }
33085
+ }
33086
+ };
33087
+ }
33088
+ };
33089
+
32887
33090
  // src/server/graph/core/parser-registry.ts
32888
33091
  function isMultiLayerParser(p) {
32889
33092
  return "layers" in p && Array.isArray(p.layers);
@@ -32950,7 +33153,8 @@ function registerBuiltins2(registry, disabled) {
32950
33153
  apiAnnotationsParser,
32951
33154
  urlLiteralScannerParser,
32952
33155
  staticRefScannerParser,
32953
- middlewareGatesParser
33156
+ middlewareGatesParser,
33157
+ callResolverParser
32954
33158
  ];
32955
33159
  for (const parser of builtins) {
32956
33160
  if (disabled.has(parser.id)) continue;
@@ -35954,6 +36158,10 @@ function handleWhoUses(args) {
35954
36158
  };
35955
36159
  const via = cr.via;
35956
36160
  if (Array.isArray(via)) entry.via = via;
36161
+ const definedIn = cr.defined_in;
36162
+ if (typeof definedIn === "string") entry.defined_in = definedIn;
36163
+ const ambiguous = cr.ambiguous;
36164
+ if (ambiguous) entry.ambiguous = true;
35957
36165
  hits.push(entry);
35958
36166
  }
35959
36167
  }
@@ -36621,7 +36829,7 @@ var McpSession = class {
36621
36829
  jsonrpc: "2.0",
36622
36830
  id: this.callId++,
36623
36831
  method: "initialize",
36624
- params: { protocolVersion: "2025-03-26", capabilities: {}, clientInfo: { name: "launchpod", version: "0.0.1" } }
36832
+ params: { protocolVersion: "2025-03-26", capabilities: {}, clientInfo: { name: "launch-sequencer", version: "0.0.1" } }
36625
36833
  });
36626
36834
  const initResp = await httpRequest2(this.mcpUrl, {
36627
36835
  method: "POST",
@@ -36775,7 +36983,7 @@ async function validateRepoUrl(serverUrl, token) {
36775
36983
  console.error("Error: Repository URL mismatch");
36776
36984
  console.error(` Project expects: ${remoteRepoUrl}`);
36777
36985
  console.error(` Local origin: ${localOrigin}`);
36778
- console.error("Run launchpod from the correct repository.");
36986
+ console.error("Run launch-sequencer from the correct repository.");
36779
36987
  process.exit(1);
36780
36988
  }
36781
36989
  }
@@ -37547,7 +37755,7 @@ if (!__isMcpMode) {
37547
37755
  }
37548
37756
  radar.attachWebSocketServer(server, "/api/radar/stream");
37549
37757
  radar.start();
37550
- initLaunchPodTerminalBridge(server, PROJECT_DIR);
37758
+ initSequencerTerminalBridge(server, PROJECT_DIR);
37551
37759
  return;
37552
37760
  }
37553
37761
  if (token) {
@@ -37596,11 +37804,11 @@ if (!__isMcpMode) {
37596
37804
  activeCapabilities = await fetchCapabilities(existingCreds.serverUrl, existingCreds.token);
37597
37805
  }
37598
37806
  if (activeCapabilities.terminal) {
37599
- initLaunchPodTerminalBridge(server, PROJECT_DIR);
37807
+ initSequencerTerminalBridge(server, PROJECT_DIR);
37600
37808
  }
37601
37809
  startPipelineSystem(existingCreds, activeCapabilities);
37602
37810
  } else if (activeCapabilities.terminal) {
37603
- initLaunchPodTerminalBridge(server, PROJECT_DIR);
37811
+ initSequencerTerminalBridge(server, PROJECT_DIR);
37604
37812
  }
37605
37813
  }
37606
37814
  main().catch((err2) => {
File without changes
@@ -214,7 +214,7 @@ Usage:
214
214
  launch-course rm <name>
215
215
 
216
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
217
+ with \`active\` selecting which one drives MCP / launch-sequencer auth. Legacy flat
218
218
  files are auto-migrated on the first multi-profile op. \`launch-course set\`
219
219
  also rewrites .mcp.json's launch-secure.url so Claude Code routes to the right
220
220
  server on next MCP reconnect.
File without changes