@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.
- package/dist/server/chart-serve.js +167 -2
- package/dist/server/cli.js +249 -41
- package/dist/server/council-entry.js +0 -0
- package/dist/server/course-entry.js +1 -1
- package/dist/server/fb-wizard.js +0 -0
- package/dist/server/graph-mcp-entry.js +180 -4
- package/dist/server/init-entry.js +438 -43
- package/dist/server/launch-radar-entry.js +45 -0
- package/dist/server/parse-worker-entry.js +167 -2
- package/dist/server/radar-docker-init-entry.js +444 -39
- package/dist/server/radar-entrypoint-entry.js +0 -0
- package/dist/server/radar-teardown-entry.js +23 -22
- package/dist/server/rover-entry.js +20122 -0
- package/package.json +28 -25
- package/scaffolds/ls-marketplace/plugins/kit/commands/standup.md +6 -6
- package/scaffolds/ls-marketplace/plugins/kit/skills/analyse/SKILL.md +6 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/brief/SKILL.md +40 -48
- package/scaffolds/ls-marketplace/plugins/kit/skills/debug/SKILL.md +45 -20
- package/scaffolds/ls-marketplace/plugins/kit/skills/deploy-check/SKILL.md +76 -67
- package/scaffolds/ls-marketplace/plugins/kit/skills/handoff/SKILL.md +132 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/ship/SKILL.md +149 -133
- package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +0 -0
- package/scaffolds/recall-hook/scripts/ensure-recall.sh +0 -0
package/dist/server/cli.js
CHANGED
|
@@ -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/
|
|
24574
|
+
// src/server/sequencer-terminal-init.ts
|
|
24546
24575
|
var import_path = __toESM(require("path"));
|
|
24547
24576
|
init_launch_kit_paths();
|
|
24548
|
-
function
|
|
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 (
|
|
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
|
-
|
|
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
|
|
24660
|
-
`[mcp_servers.launch-
|
|
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" +
|
|
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/
|
|
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/
|
|
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(
|
|
28408
|
-
const
|
|
28409
|
-
const
|
|
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 ?
|
|
28445
|
+
const missing = !token ? tokenKey : hostKey;
|
|
28413
28446
|
throw new Error(
|
|
28414
|
-
`[
|
|
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(
|
|
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("[
|
|
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(`[
|
|
28489
|
+
console.log(`[tunnel] mode=named host=${this.mode.hostname} (paid \xB7 stable URL)`);
|
|
28456
28490
|
} else {
|
|
28457
|
-
console.log(`[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
28540
|
-
console.error(`[
|
|
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}
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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
|
-
|
|
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: "
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
37807
|
+
initSequencerTerminalBridge(server, PROJECT_DIR);
|
|
37600
37808
|
}
|
|
37601
37809
|
startPipelineSystem(existingCreds, activeCapabilities);
|
|
37602
37810
|
} else if (activeCapabilities.terminal) {
|
|
37603
|
-
|
|
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-
|
|
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.
|
package/dist/server/fb-wizard.js
CHANGED
|
File without changes
|