@launchsecure/launch-kit 0.0.36 → 0.0.37
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/chart-client/assets/index-DJrjyXbN.css +1 -0
- package/dist/chart-client/index.html +2 -2
- package/dist/client/assets/index-8eSXr3Ez.css +32 -0
- package/dist/client/index.html +2 -2
- package/dist/council-client/assets/index-4K0t2WrZ.css +1 -0
- package/dist/council-client/index.html +2 -2
- package/dist/deck-client/assets/{_baseUniq-BiVx0WO_.js → _baseUniq-Cn5TyL9s.js} +1 -1
- package/dist/deck-client/assets/{arc-DGMkiEzS.js → arc-D61amKYu.js} +1 -1
- package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-Y2WRmHtk.js → architectureDiagram-Q4EWVU46-CpKrvC2W.js} +1 -1
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-_Lbfu5BQ.js → blockDiagram-DXYQGD6D-Yj5OjxvG.js} +1 -1
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CTqpYTBX.js → c4Diagram-AHTNJAMY-BIR810Tv.js} +1 -1
- package/dist/deck-client/assets/channel-DrJz2x-n.js +1 -0
- package/dist/deck-client/assets/{chunk-4BX2VUAB-liEIbPHs.js → chunk-4BX2VUAB-BeSHwGvx.js} +1 -1
- package/dist/deck-client/assets/{chunk-4TB4RGXK-CCc6lYvL.js → chunk-4TB4RGXK-CCqzsLpg.js} +1 -1
- package/dist/deck-client/assets/{chunk-55IACEB6-D02jJUR2.js → chunk-55IACEB6-CuW_aq4-.js} +1 -1
- package/dist/deck-client/assets/{chunk-EDXVE4YY-BFmGMbLD.js → chunk-EDXVE4YY-Dl35ixYh.js} +1 -1
- package/dist/deck-client/assets/{chunk-FMBD7UC4-6wFLOVcJ.js → chunk-FMBD7UC4-TwreZQTv.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-Bnr8RiBf.js → chunk-OYMX7WX6-Ahfw8EUo.js} +1 -1
- package/dist/deck-client/assets/{chunk-QZHKN3VN-Ct82MksJ.js → chunk-QZHKN3VN-DlE_zlU-.js} +1 -1
- package/dist/deck-client/assets/{chunk-YZCP3GAM-BXmN1diQ.js → chunk-YZCP3GAM-Dj6QWzSg.js} +1 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-a3tg9w7z.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-a3tg9w7z.js +1 -0
- package/dist/deck-client/assets/clone-Dd7JBCL5.js +1 -0
- package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-CmQCT-mH.js → cose-bilkent-S5V4N54A-BO1z5aOM.js} +1 -1
- package/dist/deck-client/assets/{dagre-KV5264BT-DDdSa9EX.js → dagre-KV5264BT-DVsw17fE.js} +1 -1
- package/dist/deck-client/assets/{diagram-5BDNPKRD-Bccks2xJ.js → diagram-5BDNPKRD-6jYs7oZk.js} +1 -1
- package/dist/deck-client/assets/{diagram-G4DWMVQ6-CPPNgxmQ.js → diagram-G4DWMVQ6-6DbggeGE.js} +1 -1
- package/dist/deck-client/assets/{diagram-MMDJMWI5-KrD300pS.js → diagram-MMDJMWI5-CQtk1cSU.js} +1 -1
- package/dist/deck-client/assets/{diagram-TYMM5635-DefnLuQf.js → diagram-TYMM5635-BR-gt75b.js} +1 -1
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-DI9FfnFP.js → erDiagram-SMLLAGMA-C9qMtjdY.js} +1 -1
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-twKyd3Fx.js → flowDiagram-DWJPFMVM-CdaPhPYb.js} +1 -1
- package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-Wau3jhBr.js → ganttDiagram-T4ZO3ILL-BRsZWUy4.js} +1 -1
- package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-D9GgYXwb.js → gitGraphDiagram-UUTBAWPF-B8Z90jCj.js} +1 -1
- package/dist/deck-client/assets/{graph-BhNLzyXS.js → graph-my2Zphm4.js} +1 -1
- package/dist/deck-client/assets/index-ByqxPEgU.css +1 -0
- package/dist/deck-client/assets/{index-BtQBaQ7s.js → index-DqAoYZwV.js} +43 -42
- package/dist/deck-client/assets/{infoDiagram-42DDH7IO-TylGlSG-.js → infoDiagram-42DDH7IO-Csr9loin.js} +1 -1
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DAT8icpg.js → ishikawaDiagram-UXIWVN3A-HWdvUNFi.js} +1 -1
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-D3v_XL72.js → journeyDiagram-VCZTEJTY-CjYHG6EM.js} +1 -1
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-DNUOBiNr.js → kanban-definition-6JOO6SKY-CX3JdUu7.js} +1 -1
- package/dist/deck-client/assets/{layout-COfodgwF.js → layout-Bcucv5Gi.js} +1 -1
- package/dist/deck-client/assets/{linear-DmTsuIvK.js → linear-CUGM5FJZ.js} +1 -1
- package/dist/deck-client/assets/{min-BW1F7i1D.js → min-Dw4g5w9z.js} +1 -1
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-CErFzKWl.js → mindmap-definition-QFDTVHPH-C8oo61fg.js} +1 -1
- package/dist/deck-client/assets/{pieDiagram-DEJITSTG-DW5F757o.js → pieDiagram-DEJITSTG-D2WYGkq8.js} +1 -1
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-B1S2-TfI.js → quadrantDiagram-34T5L4WZ-Vh00GISt.js} +1 -1
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-BY5BAR-5.js → requirementDiagram-MS252O5E-DxI-DFrN.js} +1 -1
- package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-CE1Cp9HS.js → sankeyDiagram-XADWPNL6-QgwyjasI.js} +1 -1
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-IaHnbKye.js → sequenceDiagram-FGHM5R23-DmOmD5Ni.js} +1 -1
- package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-CwPJm9hU.js → stateDiagram-FHFEXIEX-CRwglGg_.js} +1 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BvZLEWAA.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-DVFGGSgN.js → timeline-definition-GMOUNBTQ-Dj9YGKOh.js} +1 -1
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-C1194MJi.js → vennDiagram-DHZGUBPP-xzIaOzEU.js} +1 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-CEAay09T.js +162 -0
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-hpwdFfGj.js → wardleyDiagram-NUSXRM2D-BIYYh-JZ.js} +1 -1
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-DYkotwy8.js → xychartDiagram-5P7HB3ND-Cy9EoJCh.js} +1 -1
- package/dist/deck-client/index.html +2 -2
- package/dist/server/cli.js +21 -2
- package/dist/server/council-entry.js +86 -2
- package/dist/server/council-serve.js +81 -2
- package/dist/server/deck-mcp-entry.js +449 -68
- package/dist/server/deck-serve.js +411 -42
- package/dist/server/fb-wizard.js +0 -0
- package/dist/server/init-entry.js +96 -4
- package/dist/server/radar-docker-init-entry.js +95 -3
- package/dist/server/radar-entrypoint-entry.js +0 -0
- package/dist/server/radar-teardown-entry.js +0 -0
- package/dist/server/rover-entry.js +25 -4
- package/package.json +22 -23
- package/scaffolds/ls-marketplace/plugins/kit/skills/deploy-check/SKILL.md +5 -0
- package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +0 -0
- package/scaffolds/recall-hook/scripts/ensure-recall.sh +0 -0
- package/dist/chart-client/assets/index-DpKO9p0s.css +0 -1
- package/dist/client/assets/index-Dv6dD2zY.css +0 -32
- package/dist/council-client/assets/index-AqQ9Sei6.css +0 -1
- package/dist/deck-client/assets/channel-DB6LxW_l.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-g944ZyG8.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-g944ZyG8.js +0 -1
- package/dist/deck-client/assets/clone-DiIRH1pI.js +0 -1
- package/dist/deck-client/assets/index-B-YQq5b5.css +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-DQYa2M1q.js +0 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-CHZiUbBa.js +0 -162
- /package/dist/chart-client/assets/{index-DFu2xIrM.js → index-BgUxHxwE.js} +0 -0
- /package/dist/client/assets/{index-Cbw6bVdx.js → index-CUivaQnN.js} +0 -0
- /package/dist/council-client/assets/{index-CAsmGTzg.js → index-DN8HN_5K.js} +0 -0
|
@@ -712,9 +712,9 @@ function generateBlastRadiusReport(manifest) {
|
|
|
712
712
|
`;
|
|
713
713
|
for (const n of nodes) {
|
|
714
714
|
const ln = layerMap[n.layer] || n.layer;
|
|
715
|
-
const
|
|
715
|
+
const path3 = (n.path || "-").replace(/\|/g, "/");
|
|
716
716
|
const reason = (n.reason || "-").replace(/\|/g, "/");
|
|
717
|
-
md += `| ${n.name} | ${ln} | ${n.type || "-"} | ${
|
|
717
|
+
md += `| ${n.name} | ${ln} | ${n.type || "-"} | ${path3} | ${reason} |
|
|
718
718
|
`;
|
|
719
719
|
}
|
|
720
720
|
md += `
|
|
@@ -1198,6 +1198,227 @@ var init_rich_html_render = __esm({
|
|
|
1198
1198
|
}
|
|
1199
1199
|
});
|
|
1200
1200
|
|
|
1201
|
+
// src/server/cred-shape.ts
|
|
1202
|
+
function inferCourseName(serverUrl) {
|
|
1203
|
+
try {
|
|
1204
|
+
const host = new URL(serverUrl).hostname.toLowerCase();
|
|
1205
|
+
if (host === "localhost" || host === "127.0.0.1" || host.endsWith(".local")) return "local";
|
|
1206
|
+
if (host.includes("staging")) return "staging";
|
|
1207
|
+
if (host.endsWith(".vercel.app")) return "prod";
|
|
1208
|
+
return host.split(".")[0] || "default";
|
|
1209
|
+
} catch {
|
|
1210
|
+
return "default";
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
function toNested(cred) {
|
|
1214
|
+
if (cred.profiles && cred.active && cred.profiles[cred.active]) {
|
|
1215
|
+
return { active: cred.active, profiles: cred.profiles };
|
|
1216
|
+
}
|
|
1217
|
+
if (!cred.pat || !cred.orgSlug || !cred.projectSlug || !cred.serverUrl) {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1220
|
+
const name = inferCourseName(cred.serverUrl);
|
|
1221
|
+
return {
|
|
1222
|
+
active: name,
|
|
1223
|
+
profiles: {
|
|
1224
|
+
[name]: {
|
|
1225
|
+
pat: cred.pat,
|
|
1226
|
+
orgSlug: cred.orgSlug,
|
|
1227
|
+
projectSlug: cred.projectSlug,
|
|
1228
|
+
serverUrl: cred.serverUrl
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
function readCredFile(repoRoot) {
|
|
1234
|
+
const p = path.join(repoRoot, CONFIG_FILENAME2);
|
|
1235
|
+
if (!fs.existsSync(p)) return null;
|
|
1236
|
+
try {
|
|
1237
|
+
return JSON.parse(fs.readFileSync(p, "utf-8"));
|
|
1238
|
+
} catch (err) {
|
|
1239
|
+
throw new Error(`could not parse ${CONFIG_FILENAME2}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
var fs, path, CONFIG_FILENAME2;
|
|
1243
|
+
var init_cred_shape = __esm({
|
|
1244
|
+
"src/server/cred-shape.ts"() {
|
|
1245
|
+
"use strict";
|
|
1246
|
+
fs = __toESM(require("node:fs"));
|
|
1247
|
+
path = __toESM(require("node:path"));
|
|
1248
|
+
CONFIG_FILENAME2 = ".launch-secure.cred.config";
|
|
1249
|
+
}
|
|
1250
|
+
});
|
|
1251
|
+
|
|
1252
|
+
// src/server/mcp-client.ts
|
|
1253
|
+
function mcpConfigFromCourse(projectRoot) {
|
|
1254
|
+
let cred;
|
|
1255
|
+
try {
|
|
1256
|
+
cred = readCredFile(projectRoot);
|
|
1257
|
+
} catch {
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
1260
|
+
if (!cred) return null;
|
|
1261
|
+
const nested = toNested(cred);
|
|
1262
|
+
if (!nested) return null;
|
|
1263
|
+
const profile = nested.profiles[nested.active];
|
|
1264
|
+
if (!profile?.pat || !profile.serverUrl || !profile.orgSlug || !profile.projectSlug) {
|
|
1265
|
+
return null;
|
|
1266
|
+
}
|
|
1267
|
+
return {
|
|
1268
|
+
url: new URL("/api/mcp/project", profile.serverUrl).toString(),
|
|
1269
|
+
headers: {
|
|
1270
|
+
Authorization: `Bearer ${profile.pat}`,
|
|
1271
|
+
"X-Org-Slug": profile.orgSlug,
|
|
1272
|
+
"X-Project-Slug": profile.projectSlug
|
|
1273
|
+
}
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
function loadMcpConfig(projectRoot) {
|
|
1277
|
+
if (_config) return _config;
|
|
1278
|
+
const fromCourse = mcpConfigFromCourse(projectRoot);
|
|
1279
|
+
if (fromCourse) {
|
|
1280
|
+
_config = fromCourse;
|
|
1281
|
+
return _config;
|
|
1282
|
+
}
|
|
1283
|
+
const mcpPath = (0, import_node_path3.join)(projectRoot, ".mcp.json");
|
|
1284
|
+
if (!(0, import_node_fs3.existsSync)(mcpPath)) {
|
|
1285
|
+
throw new Error(
|
|
1286
|
+
`No active course in ${CONFIG_FILENAME2} and no .mcp.json at ${mcpPath}. Run \`launch-course\` or bootstrap with \`launch-kit init\`.`
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
const raw = JSON.parse((0, import_node_fs3.readFileSync)(mcpPath, "utf-8"));
|
|
1290
|
+
const entry = raw.mcpServers["launch-secure"];
|
|
1291
|
+
if (!entry?.url) {
|
|
1292
|
+
throw new Error(
|
|
1293
|
+
`No active course in ${CONFIG_FILENAME2} and no "launch-secure" entry with url in .mcp.json`
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
_config = {
|
|
1297
|
+
url: entry.url,
|
|
1298
|
+
headers: entry.headers ?? {}
|
|
1299
|
+
};
|
|
1300
|
+
return _config;
|
|
1301
|
+
}
|
|
1302
|
+
function parseSSE(text2) {
|
|
1303
|
+
const lines = text2.split("\n");
|
|
1304
|
+
for (const line of lines) {
|
|
1305
|
+
if (line.startsWith("data: ")) {
|
|
1306
|
+
const data = line.slice(6);
|
|
1307
|
+
try {
|
|
1308
|
+
return JSON.parse(data);
|
|
1309
|
+
} catch {
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
return JSON.parse(text2);
|
|
1314
|
+
}
|
|
1315
|
+
async function mcpRequest(method, params) {
|
|
1316
|
+
const config = _config;
|
|
1317
|
+
if (!config) throw new Error("MCP config not loaded \u2014 call loadMcpConfig first");
|
|
1318
|
+
const id = ++_requestId;
|
|
1319
|
+
const headers = {
|
|
1320
|
+
...config.headers,
|
|
1321
|
+
"Content-Type": "application/json",
|
|
1322
|
+
"Accept": "application/json, text/event-stream"
|
|
1323
|
+
};
|
|
1324
|
+
if (_sessionId) {
|
|
1325
|
+
headers["Mcp-Session-Id"] = _sessionId;
|
|
1326
|
+
}
|
|
1327
|
+
const response = await fetch(config.url, {
|
|
1328
|
+
method: "POST",
|
|
1329
|
+
headers,
|
|
1330
|
+
body: JSON.stringify({ jsonrpc: "2.0", id, method, params })
|
|
1331
|
+
});
|
|
1332
|
+
const sid = response.headers.get("mcp-session-id");
|
|
1333
|
+
if (sid) _sessionId = sid;
|
|
1334
|
+
if (!response.ok) {
|
|
1335
|
+
const text2 = await response.text();
|
|
1336
|
+
throw new Error(`MCP ${method} failed (${response.status}): ${text2}`);
|
|
1337
|
+
}
|
|
1338
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1339
|
+
const body = await response.text();
|
|
1340
|
+
if (contentType.includes("text/event-stream")) {
|
|
1341
|
+
return parseSSE(body);
|
|
1342
|
+
}
|
|
1343
|
+
return JSON.parse(body);
|
|
1344
|
+
}
|
|
1345
|
+
async function ensureInitialized() {
|
|
1346
|
+
if (_sessionId) return;
|
|
1347
|
+
await mcpRequest("initialize", {
|
|
1348
|
+
protocolVersion: "2024-11-05",
|
|
1349
|
+
capabilities: {},
|
|
1350
|
+
clientInfo: { name: "launch-council", version: "0.0.1" }
|
|
1351
|
+
});
|
|
1352
|
+
const config = _config;
|
|
1353
|
+
const headers = {
|
|
1354
|
+
...config.headers,
|
|
1355
|
+
"Content-Type": "application/json",
|
|
1356
|
+
"Accept": "application/json, text/event-stream"
|
|
1357
|
+
};
|
|
1358
|
+
if (_sessionId) headers["Mcp-Session-Id"] = _sessionId;
|
|
1359
|
+
await fetch(config.url, {
|
|
1360
|
+
method: "POST",
|
|
1361
|
+
headers,
|
|
1362
|
+
body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" })
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
async function callTool(toolName, args) {
|
|
1366
|
+
await ensureInitialized();
|
|
1367
|
+
const result = await mcpRequest("tools/call", {
|
|
1368
|
+
name: toolName,
|
|
1369
|
+
arguments: args
|
|
1370
|
+
});
|
|
1371
|
+
if (result.error) {
|
|
1372
|
+
throw new Error(`MCP tool error: ${result.error.message}`);
|
|
1373
|
+
}
|
|
1374
|
+
const textContent = result.result?.content?.[0]?.text;
|
|
1375
|
+
if (!textContent) return null;
|
|
1376
|
+
return JSON.parse(textContent);
|
|
1377
|
+
}
|
|
1378
|
+
async function writeDeck(input) {
|
|
1379
|
+
const result = await callTool("communication_write", {
|
|
1380
|
+
title: input.title,
|
|
1381
|
+
body: input.body,
|
|
1382
|
+
resource_type: "deck",
|
|
1383
|
+
fields: {
|
|
1384
|
+
deckHtml: input.html,
|
|
1385
|
+
sessionId: input.sessionId,
|
|
1386
|
+
blockCount: input.blockCount,
|
|
1387
|
+
sharedFrom: "launch-deck"
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
return { id: result.created.id };
|
|
1391
|
+
}
|
|
1392
|
+
async function updateDeck(commentId, input) {
|
|
1393
|
+
await callTool("communication_update", {
|
|
1394
|
+
comment_id: commentId,
|
|
1395
|
+
title: input.title,
|
|
1396
|
+
body: input.body,
|
|
1397
|
+
fields: {
|
|
1398
|
+
deckHtml: input.html,
|
|
1399
|
+
sessionId: input.sessionId,
|
|
1400
|
+
blockCount: input.blockCount,
|
|
1401
|
+
sharedFrom: "launch-deck"
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
return { id: commentId };
|
|
1405
|
+
}
|
|
1406
|
+
async function deleteDeck(commentId) {
|
|
1407
|
+
await callTool("communication_delete", { comment_id: commentId });
|
|
1408
|
+
}
|
|
1409
|
+
var import_node_fs3, import_node_path3, _config, _requestId, _sessionId;
|
|
1410
|
+
var init_mcp_client = __esm({
|
|
1411
|
+
"src/server/mcp-client.ts"() {
|
|
1412
|
+
"use strict";
|
|
1413
|
+
import_node_fs3 = require("node:fs");
|
|
1414
|
+
import_node_path3 = require("node:path");
|
|
1415
|
+
init_cred_shape();
|
|
1416
|
+
_config = null;
|
|
1417
|
+
_requestId = 0;
|
|
1418
|
+
_sessionId = null;
|
|
1419
|
+
}
|
|
1420
|
+
});
|
|
1421
|
+
|
|
1201
1422
|
// src/server/deck-serve.ts
|
|
1202
1423
|
var deck_serve_exports = {};
|
|
1203
1424
|
__export(deck_serve_exports, {
|
|
@@ -1209,14 +1430,14 @@ __export(deck_serve_exports, {
|
|
|
1209
1430
|
startDeckServer: () => startDeckServer
|
|
1210
1431
|
});
|
|
1211
1432
|
function sessionDir(cwd, session) {
|
|
1212
|
-
return
|
|
1433
|
+
return import_node_path4.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", session);
|
|
1213
1434
|
}
|
|
1214
1435
|
function sessionJsonPath(cwd, session) {
|
|
1215
|
-
return
|
|
1436
|
+
return import_node_path4.default.join(sessionDir(cwd, session), "session.json");
|
|
1216
1437
|
}
|
|
1217
1438
|
function readPersistedSession(cwd, session) {
|
|
1218
1439
|
try {
|
|
1219
|
-
const raw =
|
|
1440
|
+
const raw = import_node_fs4.default.readFileSync(sessionJsonPath(cwd, session), "utf-8");
|
|
1220
1441
|
return JSON.parse(raw);
|
|
1221
1442
|
} catch {
|
|
1222
1443
|
return null;
|
|
@@ -1224,7 +1445,7 @@ function readPersistedSession(cwd, session) {
|
|
|
1224
1445
|
}
|
|
1225
1446
|
function writePersistedSession(cwd, session, payload) {
|
|
1226
1447
|
const dir = sessionDir(cwd, session);
|
|
1227
|
-
|
|
1448
|
+
import_node_fs4.default.mkdirSync(dir, { recursive: true });
|
|
1228
1449
|
const existing = readPersistedSession(cwd, session);
|
|
1229
1450
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1230
1451
|
const next = {
|
|
@@ -1236,13 +1457,13 @@ function writePersistedSession(cwd, session, payload) {
|
|
|
1236
1457
|
createdAt: existing?.createdAt ?? now,
|
|
1237
1458
|
updatedAt: now
|
|
1238
1459
|
};
|
|
1239
|
-
|
|
1460
|
+
import_node_fs4.default.writeFileSync(sessionJsonPath(cwd, session), JSON.stringify(next, null, 2));
|
|
1240
1461
|
return next;
|
|
1241
1462
|
}
|
|
1242
1463
|
function listPersistedSessions(cwd) {
|
|
1243
|
-
const base =
|
|
1244
|
-
if (!
|
|
1245
|
-
const entries =
|
|
1464
|
+
const base = import_node_path4.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
|
|
1465
|
+
if (!import_node_fs4.default.existsSync(base)) return [];
|
|
1466
|
+
const entries = import_node_fs4.default.readdirSync(base, { withFileTypes: true });
|
|
1246
1467
|
const sessions = [];
|
|
1247
1468
|
for (const entry of entries) {
|
|
1248
1469
|
if (!entry.isDirectory()) continue;
|
|
@@ -1254,20 +1475,106 @@ function listPersistedSessions(cwd) {
|
|
|
1254
1475
|
blockCount: Array.isArray(persisted.blocks) ? persisted.blocks.length : 0,
|
|
1255
1476
|
version: persisted.version,
|
|
1256
1477
|
createdAt: persisted.createdAt,
|
|
1257
|
-
updatedAt: persisted.updatedAt
|
|
1478
|
+
updatedAt: persisted.updatedAt,
|
|
1479
|
+
shared: Boolean(readSyncRecord(cwd, persisted.id))
|
|
1258
1480
|
});
|
|
1259
1481
|
}
|
|
1260
1482
|
sessions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
1261
1483
|
return sessions;
|
|
1262
1484
|
}
|
|
1263
1485
|
function deletePersistedSession(cwd, session) {
|
|
1264
|
-
const base =
|
|
1486
|
+
const base = import_node_path4.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
|
|
1265
1487
|
if (session === "all") {
|
|
1266
|
-
if (
|
|
1488
|
+
if (import_node_fs4.default.existsSync(base)) import_node_fs4.default.rmSync(base, { recursive: true, force: true });
|
|
1267
1489
|
return;
|
|
1268
1490
|
}
|
|
1269
1491
|
const dir = sessionDir(cwd, session);
|
|
1270
|
-
if (
|
|
1492
|
+
if (import_node_fs4.default.existsSync(dir)) import_node_fs4.default.rmSync(dir, { recursive: true, force: true });
|
|
1493
|
+
}
|
|
1494
|
+
function syncJsonPath(cwd, session) {
|
|
1495
|
+
return import_node_path4.default.join(sessionDir(cwd, session), ".sync.json");
|
|
1496
|
+
}
|
|
1497
|
+
function readSyncRecord(cwd, session) {
|
|
1498
|
+
try {
|
|
1499
|
+
return JSON.parse(import_node_fs4.default.readFileSync(syncJsonPath(cwd, session), "utf-8"));
|
|
1500
|
+
} catch {
|
|
1501
|
+
return null;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
function writeSyncRecord(cwd, session, rec) {
|
|
1505
|
+
import_node_fs4.default.writeFileSync(syncJsonPath(cwd, session), JSON.stringify(rec, null, 2));
|
|
1506
|
+
}
|
|
1507
|
+
function escHtml2(s) {
|
|
1508
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1509
|
+
}
|
|
1510
|
+
function escAttr(s) {
|
|
1511
|
+
return s.replace(/&/g, "&").replace(/"/g, """);
|
|
1512
|
+
}
|
|
1513
|
+
function readIframeArtifact(cwd, src) {
|
|
1514
|
+
if (typeof src !== "string" || !src.startsWith("/deck-files/")) return null;
|
|
1515
|
+
const rel = decodeURIComponent(src.slice("/deck-files/".length));
|
|
1516
|
+
if (rel.includes("..")) return null;
|
|
1517
|
+
try {
|
|
1518
|
+
return import_node_fs4.default.readFileSync(import_node_path4.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", rel), "utf-8");
|
|
1519
|
+
} catch {
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
function renderShareSection(cwd, block) {
|
|
1524
|
+
const label = block?.label ? `<h2 class="db-title">${escHtml2(String(block.label))}</h2>` : "";
|
|
1525
|
+
switch (block?.type) {
|
|
1526
|
+
case "iframe": {
|
|
1527
|
+
const doc = readIframeArtifact(cwd, block.src) ?? "<p>(missing artifact)</p>";
|
|
1528
|
+
return `<section class="db">${label}<iframe class="db-frame" sandbox="allow-scripts allow-popups" srcdoc="${escAttr(doc)}"></iframe></section>`;
|
|
1529
|
+
}
|
|
1530
|
+
case "rich-html":
|
|
1531
|
+
case "html":
|
|
1532
|
+
return `<section class="db">${label}<div class="db-html">${typeof block.content === "string" ? block.content : ""}</div></section>`;
|
|
1533
|
+
case "markdown":
|
|
1534
|
+
return `<section class="db">${label}<div class="db-md" data-md="${escAttr(typeof block.content === "string" ? block.content : "")}"></div></section>`;
|
|
1535
|
+
case "mermaid":
|
|
1536
|
+
return `<section class="db">${label}<pre class="mermaid">${escHtml2(typeof block.content === "string" ? block.content : "")}</pre></section>`;
|
|
1537
|
+
case "options": {
|
|
1538
|
+
const opts = Array.isArray(block.options) ? block.options : [];
|
|
1539
|
+
const lis = opts.map(
|
|
1540
|
+
(o) => `<li><strong>${escHtml2(String(o?.label ?? o?.id ?? ""))}</strong>${o?.description ? ` \u2014 ${escHtml2(String(o.description))}` : ""}</li>`
|
|
1541
|
+
).join("");
|
|
1542
|
+
return `<section class="db">${label}<ul>${lis}</ul></section>`;
|
|
1543
|
+
}
|
|
1544
|
+
default:
|
|
1545
|
+
return `<section class="db">${label}</section>`;
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
function buildShareHtml(cwd, session, blocks) {
|
|
1549
|
+
if (blocks.length === 1) {
|
|
1550
|
+
const only = blocks[0];
|
|
1551
|
+
if (only?.type === "iframe") {
|
|
1552
|
+
const doc = readIframeArtifact(cwd, only.src);
|
|
1553
|
+
if (doc) return doc;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
const list = blocks;
|
|
1557
|
+
const sections = list.map((b) => renderShareSection(cwd, b)).join("\n");
|
|
1558
|
+
const hasMd = list.some((b) => b?.type === "markdown");
|
|
1559
|
+
const hasMermaid = list.some((b) => b?.type === "mermaid");
|
|
1560
|
+
return `<!DOCTYPE html>
|
|
1561
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1562
|
+
<title>${escHtml2(session)}</title>
|
|
1563
|
+
<style>
|
|
1564
|
+
body { margin:0; font-family: ui-sans-serif, system-ui, sans-serif; background:#0b0e14; color:#e6e9ef; }
|
|
1565
|
+
.db { padding:20px 24px; border-bottom:1px solid #1e2433; }
|
|
1566
|
+
.db-title { font-size:13px; font-weight:600; margin:0 0 12px; color:#9aa4b2; text-transform:uppercase; letter-spacing:.05em; }
|
|
1567
|
+
.db-frame { width:100%; height:70vh; border:0; border-radius:8px; background:#fff; }
|
|
1568
|
+
.db-html { background:#fff; color:#111; border-radius:8px; padding:16px; overflow:auto; }
|
|
1569
|
+
ul { line-height:1.7; }
|
|
1570
|
+
.mermaid { background:#fff; border-radius:8px; padding:16px; }
|
|
1571
|
+
</style></head>
|
|
1572
|
+
<body>
|
|
1573
|
+
${sections}
|
|
1574
|
+
${hasMd ? `<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
1575
|
+
<script>document.querySelectorAll('.db-md').forEach(function(el){try{el.innerHTML=marked.parse(el.dataset.md||'')}catch(e){el.textContent=el.dataset.md||''}});</script>` : ""}
|
|
1576
|
+
${hasMermaid ? `<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';mermaid.initialize({startOnLoad:true,theme:'dark'});</script>` : ""}
|
|
1577
|
+
</body></html>`;
|
|
1271
1578
|
}
|
|
1272
1579
|
function consumeRenderError() {
|
|
1273
1580
|
const err = lastRenderError;
|
|
@@ -1305,23 +1612,23 @@ function broadcastToClients(message) {
|
|
|
1305
1612
|
}
|
|
1306
1613
|
}
|
|
1307
1614
|
function serveStatic(res, filePath) {
|
|
1308
|
-
if (!
|
|
1309
|
-
const ext =
|
|
1615
|
+
if (!import_node_fs4.default.existsSync(filePath) || !import_node_fs4.default.statSync(filePath).isFile()) return false;
|
|
1616
|
+
const ext = import_node_path4.default.extname(filePath).toLowerCase();
|
|
1310
1617
|
const mime = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
1311
1618
|
res.writeHead(200, { "Content-Type": mime, "Cache-Control": "no-cache" });
|
|
1312
|
-
|
|
1619
|
+
import_node_fs4.default.createReadStream(filePath).pipe(res);
|
|
1313
1620
|
return true;
|
|
1314
1621
|
}
|
|
1315
1622
|
function resolveClientDir() {
|
|
1316
|
-
const sibling =
|
|
1317
|
-
if (
|
|
1318
|
-
const devDist =
|
|
1319
|
-
if (
|
|
1623
|
+
const sibling = import_node_path4.default.join(__dirname, "..", "deck-client");
|
|
1624
|
+
if (import_node_fs4.default.existsSync(import_node_path4.default.join(sibling, "assets"))) return sibling;
|
|
1625
|
+
const devDist = import_node_path4.default.join(__dirname, "..", "..", "dist", "deck-client");
|
|
1626
|
+
if (import_node_fs4.default.existsSync(import_node_path4.default.join(devDist, "assets"))) return devDist;
|
|
1320
1627
|
return sibling;
|
|
1321
1628
|
}
|
|
1322
1629
|
function serveIndex(res, clientDir) {
|
|
1323
|
-
const indexPath =
|
|
1324
|
-
if (!
|
|
1630
|
+
const indexPath = import_node_path4.default.join(clientDir, "index.html");
|
|
1631
|
+
if (!import_node_fs4.default.existsSync(indexPath)) {
|
|
1325
1632
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
1326
1633
|
res.end(`LaunchDeck client bundle not found at ${clientDir}. Run 'npm run build:client'.`);
|
|
1327
1634
|
return;
|
|
@@ -1425,15 +1732,15 @@ async function startDeckServer(opts = {}) {
|
|
|
1425
1732
|
const baseUrl = `/deck-files/${sessionEncoded}`;
|
|
1426
1733
|
const html = generateBlastRadiusHtml(block.manifest, baseUrl);
|
|
1427
1734
|
const report = generateBlastRadiusReport(block.manifest);
|
|
1428
|
-
const dir =
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1735
|
+
const dir = import_node_path4.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
|
|
1736
|
+
import_node_fs4.default.mkdirSync(dir, { recursive: true });
|
|
1737
|
+
import_node_fs4.default.writeFileSync(import_node_path4.default.join(dir, "blast-radius.html"), html);
|
|
1738
|
+
import_node_fs4.default.writeFileSync(import_node_path4.default.join(dir, "blast-radius-report.md"), report);
|
|
1739
|
+
import_node_fs4.default.writeFileSync(import_node_path4.default.join(dir, "blast-radius-manifest.json"), JSON.stringify(block.manifest, null, 2));
|
|
1433
1740
|
const contractData = generateContract(block.manifest);
|
|
1434
1741
|
const contractMd = contractToMarkdown(contractData);
|
|
1435
|
-
|
|
1436
|
-
|
|
1742
|
+
import_node_fs4.default.writeFileSync(import_node_path4.default.join(dir, "contract.json"), JSON.stringify(contractData, null, 2));
|
|
1743
|
+
import_node_fs4.default.writeFileSync(import_node_path4.default.join(dir, "contract.md"), contractMd);
|
|
1437
1744
|
block.type = "iframe";
|
|
1438
1745
|
block.src = `${baseUrl}/blast-radius.html`;
|
|
1439
1746
|
delete block.manifest;
|
|
@@ -1460,9 +1767,9 @@ async function startDeckServer(opts = {}) {
|
|
|
1460
1767
|
const sessionEncoded = encodeURIComponent(body.session);
|
|
1461
1768
|
const baseUrl = `/deck-files/${sessionEncoded}`;
|
|
1462
1769
|
const filename = `${slugify(block.label)}.html`;
|
|
1463
|
-
const dir =
|
|
1464
|
-
|
|
1465
|
-
|
|
1770
|
+
const dir = import_node_path4.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
|
|
1771
|
+
import_node_fs4.default.mkdirSync(dir, { recursive: true });
|
|
1772
|
+
import_node_fs4.default.writeFileSync(import_node_path4.default.join(dir, filename), html);
|
|
1466
1773
|
block.type = "iframe";
|
|
1467
1774
|
block.src = `${baseUrl}/${filename}`;
|
|
1468
1775
|
delete block.content;
|
|
@@ -1494,6 +1801,79 @@ async function startDeckServer(opts = {}) {
|
|
|
1494
1801
|
jsonResponse(res, 200, { sessions: listPersistedSessions(cwd) });
|
|
1495
1802
|
return;
|
|
1496
1803
|
}
|
|
1804
|
+
const shareMatch = url2.pathname.match(/^\/api\/sessions\/([^/]+)\/share$/);
|
|
1805
|
+
if (shareMatch && req.method === "POST") {
|
|
1806
|
+
const id = decodeURIComponent(shareMatch[1]);
|
|
1807
|
+
const persisted = readPersistedSession(cwd, id);
|
|
1808
|
+
if (!persisted) {
|
|
1809
|
+
jsonResponse(res, 404, { ok: false, error: "session not found" });
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
try {
|
|
1813
|
+
loadMcpConfig(cwd);
|
|
1814
|
+
} catch (err) {
|
|
1815
|
+
jsonResponse(res, 400, {
|
|
1816
|
+
ok: false,
|
|
1817
|
+
error: `Cloud sharing needs an active LaunchSecure course (.launch-secure.cred.config) or a "launch-secure" entry in .mcp.json: ${String(err)}`
|
|
1818
|
+
});
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
try {
|
|
1822
|
+
const blocks = Array.isArray(persisted.blocks) ? persisted.blocks : [];
|
|
1823
|
+
const html = buildShareHtml(cwd, id, blocks);
|
|
1824
|
+
const types = blocks.map((b) => b?.type).filter(Boolean);
|
|
1825
|
+
const body = `Shared deck "${id}" \u2014 ${blocks.length} block${blocks.length === 1 ? "" : "s"}${types.length ? ` (${types.join(", ")})` : ""}. Open the Decks tab in the Communication Center to view.`;
|
|
1826
|
+
const input = { title: id, body, html, sessionId: id, blockCount: blocks.length };
|
|
1827
|
+
const existing2 = readSyncRecord(cwd, id);
|
|
1828
|
+
let resourceId;
|
|
1829
|
+
let updated = false;
|
|
1830
|
+
if (existing2?.resourceId) {
|
|
1831
|
+
try {
|
|
1832
|
+
({ id: resourceId } = await updateDeck(existing2.resourceId, input));
|
|
1833
|
+
updated = true;
|
|
1834
|
+
} catch {
|
|
1835
|
+
({ id: resourceId } = await writeDeck(input));
|
|
1836
|
+
}
|
|
1837
|
+
} else {
|
|
1838
|
+
({ id: resourceId } = await writeDeck(input));
|
|
1839
|
+
}
|
|
1840
|
+
writeSyncRecord(cwd, id, {
|
|
1841
|
+
resourceId,
|
|
1842
|
+
sharedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1843
|
+
version: persisted.version
|
|
1844
|
+
});
|
|
1845
|
+
jsonResponse(res, 200, { ok: true, resourceId, updated });
|
|
1846
|
+
} catch (err) {
|
|
1847
|
+
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
1848
|
+
}
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
const remoteDelMatch = url2.pathname.match(/^\/api\/sessions\/([^/]+)\/remote$/);
|
|
1852
|
+
if (remoteDelMatch && req.method === "DELETE") {
|
|
1853
|
+
const id = decodeURIComponent(remoteDelMatch[1]);
|
|
1854
|
+
const sync = readSyncRecord(cwd, id);
|
|
1855
|
+
if (!sync?.resourceId) {
|
|
1856
|
+
jsonResponse(res, 200, { ok: true, deleted: false, reason: "not shared" });
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
try {
|
|
1860
|
+
loadMcpConfig(cwd);
|
|
1861
|
+
} catch (err) {
|
|
1862
|
+
jsonResponse(res, 400, { ok: false, error: `Cloud delete needs an active LaunchSecure course (.launch-secure.cred.config) or a "launch-secure" entry in .mcp.json: ${String(err)}` });
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
try {
|
|
1866
|
+
await deleteDeck(sync.resourceId);
|
|
1867
|
+
try {
|
|
1868
|
+
import_node_fs4.default.rmSync(syncJsonPath(cwd, id), { force: true });
|
|
1869
|
+
} catch {
|
|
1870
|
+
}
|
|
1871
|
+
jsonResponse(res, 200, { ok: true, deleted: true });
|
|
1872
|
+
} catch (err) {
|
|
1873
|
+
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
1874
|
+
}
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1497
1877
|
const sessionMatch = url2.pathname.match(/^\/api\/sessions\/([^/]+)$/);
|
|
1498
1878
|
if (sessionMatch) {
|
|
1499
1879
|
const id = decodeURIComponent(sessionMatch[1]);
|
|
@@ -1596,7 +1976,7 @@ async function startDeckServer(opts = {}) {
|
|
|
1596
1976
|
res.end("Forbidden");
|
|
1597
1977
|
return;
|
|
1598
1978
|
}
|
|
1599
|
-
const filePath =
|
|
1979
|
+
const filePath = import_node_path4.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", relative);
|
|
1600
1980
|
if (serveStatic(res, filePath)) return;
|
|
1601
1981
|
res.writeHead(404);
|
|
1602
1982
|
res.end("Not found");
|
|
@@ -1609,25 +1989,25 @@ async function startDeckServer(opts = {}) {
|
|
|
1609
1989
|
res.end("Forbidden");
|
|
1610
1990
|
return;
|
|
1611
1991
|
}
|
|
1612
|
-
const filePath =
|
|
1613
|
-
if (!
|
|
1992
|
+
const filePath = import_node_path4.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", relative);
|
|
1993
|
+
if (!import_node_fs4.default.existsSync(filePath) || !import_node_fs4.default.statSync(filePath).isFile()) {
|
|
1614
1994
|
res.writeHead(404);
|
|
1615
1995
|
res.end("Not found");
|
|
1616
1996
|
return;
|
|
1617
1997
|
}
|
|
1618
|
-
const ext =
|
|
1998
|
+
const ext = import_node_path4.default.extname(filePath).toLowerCase();
|
|
1619
1999
|
const mime = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
1620
|
-
const filename =
|
|
2000
|
+
const filename = import_node_path4.default.basename(filePath);
|
|
1621
2001
|
res.writeHead(200, {
|
|
1622
2002
|
"Content-Type": mime,
|
|
1623
2003
|
"Content-Disposition": `attachment; filename="${filename}"`,
|
|
1624
2004
|
"Cache-Control": "no-cache"
|
|
1625
2005
|
});
|
|
1626
|
-
|
|
2006
|
+
import_node_fs4.default.createReadStream(filePath).pipe(res);
|
|
1627
2007
|
return;
|
|
1628
2008
|
}
|
|
1629
2009
|
if (url2.pathname !== "/") {
|
|
1630
|
-
const staticPath =
|
|
2010
|
+
const staticPath = import_node_path4.default.join(clientDir, url2.pathname);
|
|
1631
2011
|
if (serveStatic(res, staticPath)) return;
|
|
1632
2012
|
}
|
|
1633
2013
|
serveIndex(res, clientDir);
|
|
@@ -1726,13 +2106,13 @@ function runServeCli(argv) {
|
|
|
1726
2106
|
process.exit(1);
|
|
1727
2107
|
});
|
|
1728
2108
|
}
|
|
1729
|
-
var import_node_http,
|
|
2109
|
+
var import_node_http, import_node_fs4, import_node_path4, import_ws, DEFAULT_PORT, MAX_PORT_SCAN, MIME_TYPES, pendingFeedback, lastRenderError, wss;
|
|
1730
2110
|
var init_deck_serve = __esm({
|
|
1731
2111
|
"src/server/deck-serve.ts"() {
|
|
1732
2112
|
"use strict";
|
|
1733
2113
|
import_node_http = __toESM(require("node:http"));
|
|
1734
|
-
|
|
1735
|
-
|
|
2114
|
+
import_node_fs4 = __toESM(require("node:fs"));
|
|
2115
|
+
import_node_path4 = __toESM(require("node:path"));
|
|
1736
2116
|
import_ws = require("ws");
|
|
1737
2117
|
init_launch_kit_paths();
|
|
1738
2118
|
init_deck_lockfile();
|
|
@@ -1740,6 +2120,7 @@ var init_deck_serve = __esm({
|
|
|
1740
2120
|
init_blast_radius_render();
|
|
1741
2121
|
init_contract_generator();
|
|
1742
2122
|
init_rich_html_render();
|
|
2123
|
+
init_mcp_client();
|
|
1743
2124
|
DEFAULT_PORT = 52829;
|
|
1744
2125
|
MAX_PORT_SCAN = 3;
|
|
1745
2126
|
MIME_TYPES = {
|
|
@@ -1825,15 +2206,15 @@ async function handleTool(name, args) {
|
|
|
1825
2206
|
const baseUrl = `/deck-files/${sessionEncoded}`;
|
|
1826
2207
|
const html = generateBlastRadiusHtml(block.manifest, baseUrl);
|
|
1827
2208
|
const report = generateBlastRadiusReport(block.manifest);
|
|
1828
|
-
const dir = (0,
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
2209
|
+
const dir = (0, import_node_path5.join)(projectRoot, LAUNCHSECURE_DIR, "deck-files", session);
|
|
2210
|
+
import_node_fs5.default.mkdirSync(dir, { recursive: true });
|
|
2211
|
+
import_node_fs5.default.writeFileSync((0, import_node_path5.join)(dir, "blast-radius.html"), html);
|
|
2212
|
+
import_node_fs5.default.writeFileSync((0, import_node_path5.join)(dir, "blast-radius-report.md"), report);
|
|
2213
|
+
import_node_fs5.default.writeFileSync((0, import_node_path5.join)(dir, "blast-radius-manifest.json"), JSON.stringify(block.manifest, null, 2));
|
|
1833
2214
|
const contractData = generateContract(block.manifest);
|
|
1834
2215
|
const contractMd = contractToMarkdown(contractData);
|
|
1835
|
-
|
|
1836
|
-
|
|
2216
|
+
import_node_fs5.default.writeFileSync((0, import_node_path5.join)(dir, "contract.json"), JSON.stringify(contractData, null, 2));
|
|
2217
|
+
import_node_fs5.default.writeFileSync((0, import_node_path5.join)(dir, "contract.md"), contractMd);
|
|
1837
2218
|
block.type = "iframe";
|
|
1838
2219
|
block.src = `${baseUrl}/blast-radius.html`;
|
|
1839
2220
|
delete block.manifest;
|
|
@@ -1860,9 +2241,9 @@ async function handleTool(name, args) {
|
|
|
1860
2241
|
const sessionEncoded = encodeURIComponent(session);
|
|
1861
2242
|
const baseUrl = `/deck-files/${sessionEncoded}`;
|
|
1862
2243
|
const filename = `${slugify(block.label)}.html`;
|
|
1863
|
-
const dir = (0,
|
|
1864
|
-
|
|
1865
|
-
|
|
2244
|
+
const dir = (0, import_node_path5.join)(projectRoot, LAUNCHSECURE_DIR, "deck-files", session);
|
|
2245
|
+
import_node_fs5.default.mkdirSync(dir, { recursive: true });
|
|
2246
|
+
import_node_fs5.default.writeFileSync((0, import_node_path5.join)(dir, filename), html);
|
|
1866
2247
|
block.type = "iframe";
|
|
1867
2248
|
block.src = `${baseUrl}/${filename}`;
|
|
1868
2249
|
delete block.content;
|
|
@@ -1956,11 +2337,11 @@ async function handleTool(name, args) {
|
|
|
1956
2337
|
}));
|
|
1957
2338
|
}
|
|
1958
2339
|
try {
|
|
1959
|
-
const logDir = (0,
|
|
1960
|
-
(0,
|
|
1961
|
-
const logPath = (0,
|
|
1962
|
-
const out = (0,
|
|
1963
|
-
const err = (0,
|
|
2340
|
+
const logDir = (0, import_node_path5.join)((0, import_node_os2.homedir)(), LAUNCHSECURE_DIR);
|
|
2341
|
+
(0, import_node_fs6.mkdirSync)(logDir, { recursive: true });
|
|
2342
|
+
const logPath = (0, import_node_path5.join)(logDir, "launch-deck.log");
|
|
2343
|
+
const out = (0, import_node_fs6.openSync)(logPath, "a");
|
|
2344
|
+
const err = (0, import_node_fs6.openSync)(logPath, "a");
|
|
1964
2345
|
const entryPath = process.argv[1];
|
|
1965
2346
|
const config = loadDeckConfig(projectRoot);
|
|
1966
2347
|
const resolvedPort = args.port ?? config.port;
|
|
@@ -2016,21 +2397,21 @@ async function handleTool(name, args) {
|
|
|
2016
2397
|
}
|
|
2017
2398
|
case "generate_contract": {
|
|
2018
2399
|
const session = args.session;
|
|
2019
|
-
const dir = (0,
|
|
2020
|
-
const manifestPath = (0,
|
|
2021
|
-
if (!
|
|
2400
|
+
const dir = (0, import_node_path5.join)(projectRoot, LAUNCHSECURE_DIR, "deck-files", session);
|
|
2401
|
+
const manifestPath = (0, import_node_path5.join)(dir, "blast-radius-manifest.json");
|
|
2402
|
+
if (!import_node_fs5.default.existsSync(manifestPath)) {
|
|
2022
2403
|
return text(JSON.stringify({
|
|
2023
2404
|
error: `No blast radius manifest found for session "${session}". Push a blast-radius block first.`,
|
|
2024
2405
|
hint: "Use the deck tool with a blast-radius block type to create a session."
|
|
2025
2406
|
}));
|
|
2026
2407
|
}
|
|
2027
2408
|
try {
|
|
2028
|
-
const raw =
|
|
2409
|
+
const raw = import_node_fs5.default.readFileSync(manifestPath, "utf-8");
|
|
2029
2410
|
const manifest = JSON.parse(raw);
|
|
2030
2411
|
const contract = generateContract(manifest);
|
|
2031
2412
|
const markdown = contractToMarkdown(contract);
|
|
2032
|
-
|
|
2033
|
-
|
|
2413
|
+
import_node_fs5.default.writeFileSync((0, import_node_path5.join)(dir, "contract.json"), JSON.stringify(contract, null, 2));
|
|
2414
|
+
import_node_fs5.default.writeFileSync((0, import_node_path5.join)(dir, "contract.md"), markdown);
|
|
2034
2415
|
return text(JSON.stringify(contract));
|
|
2035
2416
|
} catch (err) {
|
|
2036
2417
|
return text(JSON.stringify({ error: `Failed to generate contract: ${err}` }));
|
|
@@ -2121,15 +2502,15 @@ function startDeckMcpServer() {
|
|
|
2121
2502
|
process.exit(0);
|
|
2122
2503
|
});
|
|
2123
2504
|
}
|
|
2124
|
-
var import_node_http2,
|
|
2505
|
+
var import_node_http2, import_node_fs5, import_node_path5, import_node_child_process2, import_node_fs6, import_node_os2, SERVER_INFO, TOOLS;
|
|
2125
2506
|
var init_deck_mcp = __esm({
|
|
2126
2507
|
"src/server/deck-mcp.ts"() {
|
|
2127
2508
|
"use strict";
|
|
2128
2509
|
import_node_http2 = __toESM(require("node:http"));
|
|
2129
|
-
|
|
2130
|
-
|
|
2510
|
+
import_node_fs5 = __toESM(require("node:fs"));
|
|
2511
|
+
import_node_path5 = require("node:path");
|
|
2131
2512
|
import_node_child_process2 = require("node:child_process");
|
|
2132
|
-
|
|
2513
|
+
import_node_fs6 = require("node:fs");
|
|
2133
2514
|
import_node_os2 = require("node:os");
|
|
2134
2515
|
init_launch_kit_paths();
|
|
2135
2516
|
init_deck_lockfile();
|