@launchsecure/launch-kit 0.0.39 → 0.0.41
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-Dd6IotOZ.css +1 -0
- package/dist/chart-client/index.html +2 -2
- package/dist/client/assets/index-DE0uje6k.css +32 -0
- package/dist/client/index.html +2 -2
- package/dist/council-client/assets/index-CGYusOCK.css +1 -0
- package/dist/council-client/assets/{index-jjBWyhry.js → index-DkTFX53U.js} +1 -1
- package/dist/council-client/index.html +2 -2
- package/dist/deck-client/assets/_baseUniq-mvYvzeEJ.js +1 -0
- package/dist/deck-client/assets/arc-CX4ylnp2.js +1 -0
- package/dist/deck-client/assets/architectureDiagram-Q4EWVU46-BkR-5IRK.js +36 -0
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-CwAGy9lU.js → blockDiagram-DXYQGD6D-DVNQht7c.js} +2 -2
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-L_g_SS21.js → c4Diagram-AHTNJAMY-Cbq1rlG8.js} +2 -2
- package/dist/deck-client/assets/channel-B9GC-CLn.js +1 -0
- package/dist/deck-client/assets/chunk-4BX2VUAB-D58Co4lU.js +1 -0
- package/dist/deck-client/assets/{chunk-4TB4RGXK-Bk0FUbxU.js → chunk-4TB4RGXK-BYvhTm3d.js} +1 -1
- package/dist/deck-client/assets/chunk-55IACEB6-oWukUhYg.js +1 -0
- package/dist/deck-client/assets/chunk-EDXVE4YY-Cm58kVnZ.js +1 -0
- package/dist/deck-client/assets/{chunk-FMBD7UC4-DqOvWr1k.js → chunk-FMBD7UC4-Dg-i7kzi.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-1Kd7yK5u.js → chunk-OYMX7WX6-C72wigPl.js} +1 -1
- package/dist/deck-client/assets/chunk-QZHKN3VN-CLgeuAKw.js +1 -0
- package/dist/deck-client/assets/chunk-YZCP3GAM-HDDlJ5oI.js +1 -0
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CFBvYQ9j.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CFBvYQ9j.js +1 -0
- package/dist/deck-client/assets/clone-n-WQlAGe.js +1 -0
- package/dist/deck-client/assets/cose-bilkent-S5V4N54A-CUXQKg2M.js +1 -0
- package/dist/deck-client/assets/dagre-KV5264BT-C5M-fVDc.js +4 -0
- package/dist/deck-client/assets/diagram-5BDNPKRD-CcVsQ0S8.js +10 -0
- package/dist/deck-client/assets/diagram-G4DWMVQ6-DJswXyep.js +24 -0
- package/dist/deck-client/assets/diagram-MMDJMWI5-CGT76fm1.js +43 -0
- package/dist/deck-client/assets/diagram-TYMM5635-BBsYUNN6.js +24 -0
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-aiv9GZnL.js → erDiagram-SMLLAGMA-DKWYEHQS.js} +2 -2
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-C6Fhvtsy.js → flowDiagram-DWJPFMVM-DLuDYIKT.js} +2 -2
- package/dist/deck-client/assets/ganttDiagram-T4ZO3ILL-B19b6Qtj.js +292 -0
- package/dist/deck-client/assets/gitGraphDiagram-UUTBAWPF-BYLAfYVS.js +106 -0
- package/dist/deck-client/assets/graph-CfzQUfPh.js +1 -0
- package/dist/deck-client/assets/index-DlwdTgE_.js +892 -0
- package/dist/deck-client/assets/index-evAPhGvM.css +1 -0
- package/dist/deck-client/assets/infoDiagram-42DDH7IO-Dp3mUA9c.js +2 -0
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-BwCUmUVt.js → ishikawaDiagram-UXIWVN3A-BhrNX_jI.js} +5 -5
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-C6qoqJmJ.js → journeyDiagram-VCZTEJTY-B5lJI492.js} +2 -2
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-Dz1Tt3sA.js → kanban-definition-6JOO6SKY-D9-lmhQf.js} +2 -2
- package/dist/deck-client/assets/layout-CfIe_Su8.js +1 -0
- package/dist/deck-client/assets/linear-09ZFRoh_.js +1 -0
- package/dist/deck-client/assets/mermaid.core-BaQyIOvj.js +309 -0
- package/dist/deck-client/assets/min-CYwCzYaL.js +1 -0
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-CfXcK1qH.js → mindmap-definition-QFDTVHPH-CouFxf6C.js} +2 -2
- package/dist/deck-client/assets/pieDiagram-DEJITSTG-DMB1ufC0.js +30 -0
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-CXwvZ1i1.js → quadrantDiagram-34T5L4WZ-CBiOKudN.js} +2 -2
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-Cl6xm0fR.js → requirementDiagram-MS252O5E-BMc3GJkx.js} +2 -2
- package/dist/deck-client/assets/sankeyDiagram-XADWPNL6-CxACUncm.js +10 -0
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-BC1MYBn6.js → sequenceDiagram-FGHM5R23-Ch-P3Mzc.js} +2 -2
- package/dist/deck-client/assets/stateDiagram-FHFEXIEX-Cy8n7Yzk.js +1 -0
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-C14VKCzi.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-DKnITsD4.js → timeline-definition-GMOUNBTQ-C2V4sSkm.js} +2 -2
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-BdajXRrh.js → vennDiagram-DHZGUBPP-YOqt4VbE.js} +2 -2
- package/dist/deck-client/assets/wardley-RL74JXVD-Bxo5x40D.js +162 -0
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-B2hDCDl2.js → wardleyDiagram-NUSXRM2D-DW9SOqbx.js} +2 -2
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CvnYFs51.js → xychartDiagram-5P7HB3ND-D-rZvZOL.js} +2 -2
- package/dist/deck-client/index.html +2 -2
- package/dist/server/beacon-monitor-entry.js +106 -24
- package/dist/server/chart-serve.js +544 -247
- package/dist/server/cli.js +1016 -324
- package/dist/server/council-entry.js +23 -4
- package/dist/server/council-serve.js +22 -3
- package/dist/server/deck-mcp-entry.js +523 -125
- package/dist/server/deck-serve.js +326 -40
- package/dist/server/graph-mcp-entry.js +1160 -357
- package/dist/server/init-entry.js +17 -7
- package/dist/server/orbit-entry.js +91 -7
- package/dist/server/recall-entry.js +94 -12
- package/dist/server/rover-entry.js +1 -1
- package/package.json +1 -1
- package/scaffolds/ls-marketplace/plugins/kit/skills/comms/SKILL.md +34 -1
- package/scaffolds/ls-marketplace/plugins/kit/skills/gen-test/SKILL.md +126 -0
- package/scaffolds/statusline/statusline-mcp.sh +68 -19
- package/scaffolds/statusline/statusline-wrapper.sh +12 -9
- package/dist/chart-client/assets/index-ysGpLeOW.css +0 -1
- package/dist/client/assets/index-CMN3tlGP.css +0 -32
- package/dist/council-client/assets/index-ChmNX6bZ.css +0 -1
- package/dist/deck-client/assets/_baseUniq-DOrnEQMI.js +0 -1
- package/dist/deck-client/assets/arc-DOWK7V3m.js +0 -1
- package/dist/deck-client/assets/architectureDiagram-Q4EWVU46-DPhzvk7q.js +0 -36
- package/dist/deck-client/assets/channel-DqiACUUq.js +0 -1
- package/dist/deck-client/assets/chunk-4BX2VUAB-RKm0LXpu.js +0 -1
- package/dist/deck-client/assets/chunk-55IACEB6-Cl3hja-M.js +0 -1
- package/dist/deck-client/assets/chunk-EDXVE4YY-CNIMQCV2.js +0 -1
- package/dist/deck-client/assets/chunk-QZHKN3VN-6_kraYpP.js +0 -1
- package/dist/deck-client/assets/chunk-YZCP3GAM-FgAwIWlo.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-D23cq2C3.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-D23cq2C3.js +0 -1
- package/dist/deck-client/assets/clone-C7jSigGq.js +0 -1
- package/dist/deck-client/assets/cose-bilkent-S5V4N54A-CigVnnPr.js +0 -1
- package/dist/deck-client/assets/dagre-KV5264BT-DHZXTktX.js +0 -4
- package/dist/deck-client/assets/diagram-5BDNPKRD-H5k0eauU.js +0 -10
- package/dist/deck-client/assets/diagram-G4DWMVQ6-Bg3dFhSY.js +0 -24
- package/dist/deck-client/assets/diagram-MMDJMWI5-CQLC410N.js +0 -43
- package/dist/deck-client/assets/diagram-TYMM5635-DFTCHVkP.js +0 -24
- package/dist/deck-client/assets/ganttDiagram-T4ZO3ILL-DSaGMPM4.js +0 -292
- package/dist/deck-client/assets/gitGraphDiagram-UUTBAWPF-DMjL2Vix.js +0 -106
- package/dist/deck-client/assets/graph-B7Vn5lkK.js +0 -1
- package/dist/deck-client/assets/index-BD36e-tD.js +0 -1196
- package/dist/deck-client/assets/index-CGbNOpk9.css +0 -1
- package/dist/deck-client/assets/infoDiagram-42DDH7IO-mNi4iygG.js +0 -2
- package/dist/deck-client/assets/layout-CZTyRhOG.js +0 -1
- package/dist/deck-client/assets/linear--7n7iEvd.js +0 -1
- package/dist/deck-client/assets/min-Bh130DN8.js +0 -1
- package/dist/deck-client/assets/pieDiagram-DEJITSTG-DjVHLAVw.js +0 -30
- package/dist/deck-client/assets/sankeyDiagram-XADWPNL6-BOH9sLyh.js +0 -10
- package/dist/deck-client/assets/stateDiagram-FHFEXIEX-kNp9bv8K.js +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-hRsAFc2t.js +0 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-BL802-su.js +0 -162
- /package/dist/chart-client/assets/{index-BlsuXuQ1.js → index-CrYM1-ac.js} +0 -0
- /package/dist/client/assets/{index-BA7BHBWT.js → index-BoIjawzY.js} +0 -0
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var deck_serve_exports = {};
|
|
32
32
|
__export(deck_serve_exports, {
|
|
33
33
|
broadcastToClients: () => broadcastToClients,
|
|
34
|
+
buildSharePayload: () => buildSharePayload,
|
|
34
35
|
consumeRenderError: () => consumeRenderError,
|
|
35
36
|
createFeedbackWaiter: () => createFeedbackWaiter,
|
|
36
37
|
resolveFeedback: () => resolveFeedback,
|
|
@@ -1227,7 +1228,7 @@ function readCredFile(repoRoot) {
|
|
|
1227
1228
|
var _config = null;
|
|
1228
1229
|
var _requestId = 0;
|
|
1229
1230
|
var _sessionId = null;
|
|
1230
|
-
function
|
|
1231
|
+
function mcpConfigForProfile(projectRoot, name) {
|
|
1231
1232
|
let cred;
|
|
1232
1233
|
try {
|
|
1233
1234
|
cred = readCredFile(projectRoot);
|
|
@@ -1237,7 +1238,7 @@ function mcpConfigFromCourse(projectRoot) {
|
|
|
1237
1238
|
if (!cred) return null;
|
|
1238
1239
|
const nested = toNested(cred);
|
|
1239
1240
|
if (!nested) return null;
|
|
1240
|
-
const profile = nested.profiles[
|
|
1241
|
+
const profile = nested.profiles[name];
|
|
1241
1242
|
if (!profile?.pat || !profile.serverUrl || !profile.orgSlug || !profile.projectSlug) {
|
|
1242
1243
|
return null;
|
|
1243
1244
|
}
|
|
@@ -1250,6 +1251,37 @@ function mcpConfigFromCourse(projectRoot) {
|
|
|
1250
1251
|
}
|
|
1251
1252
|
};
|
|
1252
1253
|
}
|
|
1254
|
+
function mcpConfigFromCourse(projectRoot) {
|
|
1255
|
+
let cred;
|
|
1256
|
+
try {
|
|
1257
|
+
cred = readCredFile(projectRoot);
|
|
1258
|
+
} catch {
|
|
1259
|
+
return null;
|
|
1260
|
+
}
|
|
1261
|
+
if (!cred) return null;
|
|
1262
|
+
const nested = toNested(cred);
|
|
1263
|
+
if (!nested) return null;
|
|
1264
|
+
return mcpConfigForProfile(projectRoot, nested.active);
|
|
1265
|
+
}
|
|
1266
|
+
function listCourses(projectRoot) {
|
|
1267
|
+
let cred;
|
|
1268
|
+
try {
|
|
1269
|
+
cred = readCredFile(projectRoot);
|
|
1270
|
+
} catch {
|
|
1271
|
+
return [];
|
|
1272
|
+
}
|
|
1273
|
+
if (!cred) return [];
|
|
1274
|
+
const nested = toNested(cred);
|
|
1275
|
+
if (!nested) return [];
|
|
1276
|
+
return Object.entries(nested.profiles).map(([name, p]) => ({
|
|
1277
|
+
name,
|
|
1278
|
+
org: p.orgSlug ?? "",
|
|
1279
|
+
project: p.projectSlug ?? "",
|
|
1280
|
+
serverUrl: p.serverUrl ?? "",
|
|
1281
|
+
active: name === nested.active,
|
|
1282
|
+
usable: Boolean(p.pat && p.serverUrl && p.orgSlug && p.projectSlug)
|
|
1283
|
+
}));
|
|
1284
|
+
}
|
|
1253
1285
|
function loadMcpConfig(projectRoot) {
|
|
1254
1286
|
if (_config) return _config;
|
|
1255
1287
|
const fromCourse = mcpConfigFromCourse(projectRoot);
|
|
@@ -1276,6 +1308,24 @@ function loadMcpConfig(projectRoot) {
|
|
|
1276
1308
|
};
|
|
1277
1309
|
return _config;
|
|
1278
1310
|
}
|
|
1311
|
+
var _overrideLock = Promise.resolve();
|
|
1312
|
+
function withMcpConfig(override, fn) {
|
|
1313
|
+
const run = async () => {
|
|
1314
|
+
const prevConfig = _config;
|
|
1315
|
+
const prevSession = _sessionId;
|
|
1316
|
+
_config = override;
|
|
1317
|
+
_sessionId = null;
|
|
1318
|
+
try {
|
|
1319
|
+
return await fn();
|
|
1320
|
+
} finally {
|
|
1321
|
+
_config = prevConfig;
|
|
1322
|
+
_sessionId = prevSession;
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
const result = _overrideLock.then(run, run);
|
|
1326
|
+
_overrideLock = result.then(() => void 0, () => void 0);
|
|
1327
|
+
return result;
|
|
1328
|
+
}
|
|
1279
1329
|
function parseSSE(text) {
|
|
1280
1330
|
const lines = text.split("\n");
|
|
1281
1331
|
for (const line of lines) {
|
|
@@ -1350,7 +1400,13 @@ async function callTool(toolName, args) {
|
|
|
1350
1400
|
}
|
|
1351
1401
|
const textContent = result.result?.content?.[0]?.text;
|
|
1352
1402
|
if (!textContent) return null;
|
|
1353
|
-
|
|
1403
|
+
try {
|
|
1404
|
+
return JSON.parse(textContent);
|
|
1405
|
+
} catch {
|
|
1406
|
+
const match = textContent.match(/──+\s*Error\s*──+\s*\n([\s\S]*?)(?:\n\n──|$)/i);
|
|
1407
|
+
const message = (match?.[1] ?? textContent).trim();
|
|
1408
|
+
throw new Error(message || "MCP tool returned an unparseable response");
|
|
1409
|
+
}
|
|
1354
1410
|
}
|
|
1355
1411
|
async function writeDeck(input) {
|
|
1356
1412
|
const result = await callTool("communication_write", {
|
|
@@ -1359,6 +1415,7 @@ async function writeDeck(input) {
|
|
|
1359
1415
|
resource_type: "deck",
|
|
1360
1416
|
fields: {
|
|
1361
1417
|
deckHtml: input.html,
|
|
1418
|
+
deckBlocks: input.blocks,
|
|
1362
1419
|
sessionId: input.sessionId,
|
|
1363
1420
|
blockCount: input.blockCount,
|
|
1364
1421
|
sharedFrom: "launch-deck"
|
|
@@ -1373,6 +1430,7 @@ async function updateDeck(commentId, input) {
|
|
|
1373
1430
|
body: input.body,
|
|
1374
1431
|
fields: {
|
|
1375
1432
|
deckHtml: input.html,
|
|
1433
|
+
deckBlocks: input.blocks,
|
|
1376
1434
|
sessionId: input.sessionId,
|
|
1377
1435
|
blockCount: input.blockCount,
|
|
1378
1436
|
sharedFrom: "launch-deck"
|
|
@@ -1383,6 +1441,31 @@ async function updateDeck(commentId, input) {
|
|
|
1383
1441
|
async function deleteDeck(commentId) {
|
|
1384
1442
|
await callTool("communication_delete", { comment_id: commentId });
|
|
1385
1443
|
}
|
|
1444
|
+
function currentMcpOrigin() {
|
|
1445
|
+
const config = _config;
|
|
1446
|
+
if (!config) throw new Error("MCP config not loaded \u2014 call loadMcpConfig first");
|
|
1447
|
+
return new URL(config.url).origin;
|
|
1448
|
+
}
|
|
1449
|
+
async function createDeckShareLink(commentId) {
|
|
1450
|
+
const result = await callTool("deck_share_link", {
|
|
1451
|
+
comment_id: commentId,
|
|
1452
|
+
action: "create"
|
|
1453
|
+
});
|
|
1454
|
+
const token = result.link.token;
|
|
1455
|
+
return {
|
|
1456
|
+
linkId: result.link.id,
|
|
1457
|
+
token,
|
|
1458
|
+
shareUrl: `${currentMcpOrigin()}/s/deck/${token}`,
|
|
1459
|
+
reused: Boolean(result.reused)
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
async function revokeDeckShareLink(commentId, linkId) {
|
|
1463
|
+
await callTool("deck_share_link", {
|
|
1464
|
+
comment_id: commentId,
|
|
1465
|
+
action: "revoke",
|
|
1466
|
+
link_id: linkId
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1386
1469
|
|
|
1387
1470
|
// src/server/deck-serve.ts
|
|
1388
1471
|
var DEFAULT_PORT = 52829;
|
|
@@ -1447,7 +1530,9 @@ function listPersistedSessions(cwd) {
|
|
|
1447
1530
|
createdAt: persisted.createdAt,
|
|
1448
1531
|
updatedAt: persisted.updatedAt,
|
|
1449
1532
|
shared: Boolean(sync),
|
|
1450
|
-
stale: Boolean(sync) && persisted.version > (sync?.version ?? 0)
|
|
1533
|
+
stale: Boolean(sync) && persisted.version > (sync?.version ?? 0),
|
|
1534
|
+
shareUrl: sync?.publicShareUrl,
|
|
1535
|
+
course: sync?.course
|
|
1451
1536
|
});
|
|
1452
1537
|
}
|
|
1453
1538
|
sessions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
@@ -1475,6 +1560,24 @@ function readSyncRecord(cwd, session) {
|
|
|
1475
1560
|
function writeSyncRecord(cwd, session, rec) {
|
|
1476
1561
|
import_node_fs4.default.writeFileSync(syncJsonPath(cwd, session), JSON.stringify(rec, null, 2));
|
|
1477
1562
|
}
|
|
1563
|
+
function resolveShareConfig(cwd, course) {
|
|
1564
|
+
if (course) {
|
|
1565
|
+
const override = mcpConfigForProfile(cwd, course);
|
|
1566
|
+
if (!override) {
|
|
1567
|
+
return { error: `Course "${course}" is not a usable profile in .launch-secure.cred.config (missing pat/serverUrl/orgSlug/projectSlug?).` };
|
|
1568
|
+
}
|
|
1569
|
+
return { override };
|
|
1570
|
+
}
|
|
1571
|
+
try {
|
|
1572
|
+
loadMcpConfig(cwd);
|
|
1573
|
+
} catch (err) {
|
|
1574
|
+
return { error: `Cloud sharing needs an active LaunchSecure course (.launch-secure.cred.config) or a "launch-secure" entry in .mcp.json: ${String(err)}` };
|
|
1575
|
+
}
|
|
1576
|
+
return { override: null };
|
|
1577
|
+
}
|
|
1578
|
+
function runWithShareConfig(override, fn) {
|
|
1579
|
+
return override ? withMcpConfig(override, fn) : fn();
|
|
1580
|
+
}
|
|
1478
1581
|
function escHtml2(s) {
|
|
1479
1582
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1480
1583
|
}
|
|
@@ -1491,31 +1594,49 @@ function readIframeArtifact(cwd, src) {
|
|
|
1491
1594
|
return null;
|
|
1492
1595
|
}
|
|
1493
1596
|
}
|
|
1494
|
-
function renderShareSection(cwd, block) {
|
|
1495
|
-
const label = block?.label ? `<h2 class="db-title">${escHtml2(String(block.label))}</h2>` : "";
|
|
1597
|
+
function renderShareSection(cwd, block, showLabel = true) {
|
|
1598
|
+
const label = showLabel && block?.label ? `<h2 class="db-title">${escHtml2(String(block.label))}</h2>` : "";
|
|
1496
1599
|
switch (block?.type) {
|
|
1497
1600
|
case "iframe": {
|
|
1498
1601
|
const doc = readIframeArtifact(cwd, block.src) ?? "<p>(missing artifact)</p>";
|
|
1499
|
-
return
|
|
1602
|
+
return `${label}<iframe class="db-frame" sandbox="allow-scripts allow-popups" srcdoc="${escAttr(doc)}"></iframe>`;
|
|
1500
1603
|
}
|
|
1501
1604
|
case "rich-html":
|
|
1502
1605
|
case "html":
|
|
1503
|
-
return
|
|
1606
|
+
return `${label}<div class="db-html">${typeof block.content === "string" ? block.content : ""}</div>`;
|
|
1504
1607
|
case "markdown":
|
|
1505
|
-
return
|
|
1608
|
+
return `${label}<div class="db-md" data-md="${escAttr(typeof block.content === "string" ? block.content : "")}"></div>`;
|
|
1506
1609
|
case "mermaid":
|
|
1507
|
-
|
|
1610
|
+
if (typeof block.renderedSvg === "string" && block.renderedSvg.trim()) {
|
|
1611
|
+
return `${label}<div class="mermaid-svg">${block.renderedSvg}</div>`;
|
|
1612
|
+
}
|
|
1613
|
+
return `${label}<pre class="mermaid">${escHtml2(typeof block.content === "string" ? block.content : "")}</pre>`;
|
|
1508
1614
|
case "options": {
|
|
1509
1615
|
const opts = Array.isArray(block.options) ? block.options : [];
|
|
1510
|
-
const
|
|
1511
|
-
(o) => `<
|
|
1616
|
+
const cards = opts.map(
|
|
1617
|
+
(o) => `<div class="db-option"><div class="db-option-label">${escHtml2(String(o?.label ?? o?.id ?? ""))}</div>${o?.description ? `<div class="db-option-desc">${escHtml2(String(o.description))}</div>` : ""}${o?.preview ? `<pre class="db-option-pre">${escHtml2(String(o.preview))}</pre>` : ""}</div>`
|
|
1512
1618
|
).join("");
|
|
1513
|
-
return
|
|
1619
|
+
return `${label}<div class="db-options">${cards}</div>`;
|
|
1514
1620
|
}
|
|
1515
1621
|
default:
|
|
1516
|
-
return
|
|
1622
|
+
return label;
|
|
1517
1623
|
}
|
|
1518
1624
|
}
|
|
1625
|
+
function buildSharePayload(cwd, session, blocks, svgByIndex = {}) {
|
|
1626
|
+
const enriched = blocks.map((b, i) => {
|
|
1627
|
+
const svg = svgByIndex[String(i)];
|
|
1628
|
+
return b?.type === "mermaid" && typeof svg === "string" && svg.trim() ? { ...b, renderedSvg: svg } : b;
|
|
1629
|
+
});
|
|
1630
|
+
const html = buildShareHtml(cwd, session, enriched);
|
|
1631
|
+
const cloudBlocks = enriched.map((b) => {
|
|
1632
|
+
if (b?.type === "iframe" && typeof b.src === "string") {
|
|
1633
|
+
const content = readIframeArtifact(cwd, b.src);
|
|
1634
|
+
return content ? { ...b, content } : b;
|
|
1635
|
+
}
|
|
1636
|
+
return b;
|
|
1637
|
+
});
|
|
1638
|
+
return { html, cloudBlocks };
|
|
1639
|
+
}
|
|
1519
1640
|
function buildShareHtml(cwd, session, blocks) {
|
|
1520
1641
|
if (blocks.length === 1) {
|
|
1521
1642
|
const only = blocks[0];
|
|
@@ -1525,30 +1646,61 @@ function buildShareHtml(cwd, session, blocks) {
|
|
|
1525
1646
|
}
|
|
1526
1647
|
}
|
|
1527
1648
|
const list = blocks;
|
|
1528
|
-
const
|
|
1649
|
+
const multi = list.length > 1;
|
|
1650
|
+
const tabBar = multi ? `<nav class="deck-tabs">${list.map(
|
|
1651
|
+
(b, i) => `<button class="deck-tab${i === 0 ? " active" : ""}" data-tab-btn="${i}">${escHtml2(String(b?.label ?? `Tab ${i + 1}`))}</button>`
|
|
1652
|
+
).join("")}</nav>` : "";
|
|
1653
|
+
const sections = list.map(
|
|
1654
|
+
(b, i) => `<section class="db" data-tab="${i}"${multi && i > 0 ? " hidden" : ""}>${renderShareSection(cwd, b, !multi)}</section>`
|
|
1655
|
+
).join("\n");
|
|
1529
1656
|
const hasMd = list.some((b) => b?.type === "markdown");
|
|
1530
|
-
const
|
|
1657
|
+
const hasUnrenderedMermaid = list.some(
|
|
1658
|
+
(b) => b?.type === "mermaid" && !(typeof b?.renderedSvg === "string" && b.renderedSvg.trim())
|
|
1659
|
+
);
|
|
1531
1660
|
return `<!DOCTYPE html>
|
|
1532
1661
|
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1533
1662
|
<title>${escHtml2(session)}</title>
|
|
1663
|
+
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,100..1000&display=swap" rel="stylesheet">
|
|
1534
1664
|
<style>
|
|
1535
|
-
body { margin:0; font-family:
|
|
1665
|
+
body { margin:0; font-family: 'DM Sans', system-ui, sans-serif; background:#0b0e14; color:#e6e9ef; }
|
|
1536
1666
|
.db { padding:20px 24px; border-bottom:1px solid #1e2433; }
|
|
1537
1667
|
.db-title { font-size:13px; font-weight:600; margin:0 0 12px; color:#9aa4b2; text-transform:uppercase; letter-spacing:.05em; }
|
|
1538
1668
|
.db-frame { width:100%; height:70vh; border:0; border-radius:8px; background:#fff; }
|
|
1539
1669
|
.db-html { background:#fff; color:#111; border-radius:8px; padding:16px; overflow:auto; }
|
|
1540
1670
|
ul { line-height:1.7; }
|
|
1541
|
-
|
|
1671
|
+
/* The embedded SVG is dark-themed (captured from the deck client); keep its
|
|
1672
|
+
backdrop transparent so it sits on the dark page, matching the in-app
|
|
1673
|
+
DeckView \u2014 not a white card. The CDN-source fallback also renders dark. */
|
|
1674
|
+
.mermaid { background:transparent; border-radius:8px; padding:16px; }
|
|
1675
|
+
.mermaid-svg { background:transparent; border-radius:8px; padding:16px; overflow:auto; }
|
|
1676
|
+
.mermaid-svg svg { max-width:100%; height:auto; }
|
|
1677
|
+
.db-options { display:grid; gap:12px; grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); }
|
|
1678
|
+
.db-option { border:2px solid #1e2433; border-radius:8px; padding:16px; }
|
|
1679
|
+
.db-option-label { font-size:14px; font-weight:600; color:#e6e9ef; }
|
|
1680
|
+
.db-option-desc { margin-top:4px; font-size:12px; color:#9aa4b2; }
|
|
1681
|
+
.db-option-pre { margin-top:8px; padding:8px; border-radius:6px; background:#11151f; font-size:12px; overflow:auto; }
|
|
1682
|
+
.deck-tabs { position:sticky; top:0; z-index:5; display:flex; flex-wrap:wrap; gap:2px; background:#0b0e14; border-bottom:1px solid #1e2433; padding:0 16px; }
|
|
1683
|
+
.deck-tab { appearance:none; border:0; background:transparent; color:#9aa4b2; font:inherit; font-size:13px; font-weight:500; padding:12px 16px; cursor:pointer; border-bottom:2px solid transparent; }
|
|
1684
|
+
.deck-tab:hover { color:#e6e9ef; }
|
|
1685
|
+
.deck-tab.active { color:#c084fc; border-bottom-color:#c084fc; }
|
|
1686
|
+
.db[hidden] { display:none; }
|
|
1542
1687
|
</style></head>
|
|
1543
1688
|
<body>
|
|
1689
|
+
${tabBar}
|
|
1544
1690
|
${sections}
|
|
1691
|
+
${multi ? `<script>(function(){var b=[].slice.call(document.querySelectorAll('[data-tab-btn]')),s=[].slice.call(document.querySelectorAll('[data-tab]'));b.forEach(function(x){x.addEventListener('click',function(){var i=x.getAttribute('data-tab-btn');s.forEach(function(y){y.hidden=y.getAttribute('data-tab')!==i;});b.forEach(function(z){z.classList.toggle('active',z===x);});});});})();</script>` : ""}
|
|
1545
1692
|
${hasMd ? `<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
1546
1693
|
<script>document.querySelectorAll('.db-md').forEach(function(el){try{el.innerHTML=marked.parse(el.dataset.md||'')}catch(e){el.textContent=el.dataset.md||''}});</script>` : ""}
|
|
1547
|
-
${
|
|
1694
|
+
${hasUnrenderedMermaid ? `<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';mermaid.initialize({startOnLoad:true,theme:document.documentElement.classList.contains('light')?'default':'dark',securityLevel:'loose',fontFamily:"'DM Sans', system-ui, sans-serif"});</script>` : ""}
|
|
1548
1695
|
</body></html>`;
|
|
1549
1696
|
}
|
|
1550
1697
|
var pendingFeedback = /* @__PURE__ */ new Map();
|
|
1551
1698
|
var lastRenderError = null;
|
|
1699
|
+
var activeSession = null;
|
|
1700
|
+
var discussSessions = [];
|
|
1701
|
+
function broadcastDiscuss() {
|
|
1702
|
+
broadcastToClients({ type: "discuss_session", sessions: discussSessions.map((d) => d.id) });
|
|
1703
|
+
}
|
|
1552
1704
|
function consumeRenderError() {
|
|
1553
1705
|
const err = lastRenderError;
|
|
1554
1706
|
lastRenderError = null;
|
|
@@ -1685,6 +1837,10 @@ async function startDeckServer(opts = {}) {
|
|
|
1685
1837
|
jsonResponse(res, 200, { config: cfg });
|
|
1686
1838
|
return;
|
|
1687
1839
|
}
|
|
1840
|
+
if (req.method === "GET" && url2.pathname === "/api/deck/courses") {
|
|
1841
|
+
jsonResponse(res, 200, { courses: listCourses(cwd) });
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1688
1844
|
if (req.method === "POST" && url2.pathname === "/api/deck/config") {
|
|
1689
1845
|
try {
|
|
1690
1846
|
const body = JSON.parse(await readBody(req));
|
|
@@ -1783,40 +1939,128 @@ async function startDeckServer(opts = {}) {
|
|
|
1783
1939
|
jsonResponse(res, 404, { ok: false, error: "session not found" });
|
|
1784
1940
|
return;
|
|
1785
1941
|
}
|
|
1942
|
+
let course;
|
|
1943
|
+
let svgByIndex = {};
|
|
1944
|
+
let publicLink = false;
|
|
1786
1945
|
try {
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1946
|
+
const raw = await readBody(req);
|
|
1947
|
+
if (raw.trim()) {
|
|
1948
|
+
const parsed = JSON.parse(raw);
|
|
1949
|
+
course = parsed.course?.trim() || void 0;
|
|
1950
|
+
if (parsed.svgByIndex && typeof parsed.svgByIndex === "object") svgByIndex = parsed.svgByIndex;
|
|
1951
|
+
publicLink = parsed.publicLink === true;
|
|
1952
|
+
}
|
|
1953
|
+
} catch {
|
|
1954
|
+
}
|
|
1955
|
+
const cfg = resolveShareConfig(cwd, course);
|
|
1956
|
+
if ("error" in cfg) {
|
|
1957
|
+
jsonResponse(res, 400, { ok: false, error: cfg.error });
|
|
1793
1958
|
return;
|
|
1794
1959
|
}
|
|
1960
|
+
const { override } = cfg;
|
|
1795
1961
|
try {
|
|
1796
1962
|
const blocks = Array.isArray(persisted.blocks) ? persisted.blocks : [];
|
|
1797
|
-
const html =
|
|
1963
|
+
const { html, cloudBlocks } = buildSharePayload(cwd, id, blocks, svgByIndex);
|
|
1798
1964
|
const types = blocks.map((b) => b?.type).filter(Boolean);
|
|
1799
1965
|
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.`;
|
|
1800
|
-
const input = { title: id, body, html, sessionId: id, blockCount: blocks.length };
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1966
|
+
const input = { title: id, body, html, blocks: cloudBlocks, sessionId: id, blockCount: blocks.length };
|
|
1967
|
+
const existingSync = readSyncRecord(cwd, id);
|
|
1968
|
+
const doShare = async () => {
|
|
1969
|
+
if (existingSync?.resourceId) {
|
|
1970
|
+
try {
|
|
1971
|
+
const { id: rid2 } = await updateDeck(existingSync.resourceId, input);
|
|
1972
|
+
return { resourceId: rid2, updated: true };
|
|
1973
|
+
} catch {
|
|
1974
|
+
const { id: rid2 } = await writeDeck(input);
|
|
1975
|
+
return { resourceId: rid2, updated: false };
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
const { id: rid } = await writeDeck(input);
|
|
1979
|
+
return { resourceId: rid, updated: false };
|
|
1980
|
+
};
|
|
1981
|
+
const result = await runWithShareConfig(override, async () => {
|
|
1982
|
+
const shared = await doShare();
|
|
1983
|
+
let link = null;
|
|
1984
|
+
let linkError;
|
|
1985
|
+
if (publicLink) {
|
|
1986
|
+
try {
|
|
1987
|
+
const minted = await createDeckShareLink(shared.resourceId);
|
|
1988
|
+
link = { shareUrl: minted.shareUrl, linkId: minted.linkId };
|
|
1989
|
+
} catch (err) {
|
|
1990
|
+
linkError = err instanceof Error ? err.message : String(err);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
return { shared, link, linkError };
|
|
1994
|
+
});
|
|
1995
|
+
if (publicLink && result.linkError && !result.shared.updated) {
|
|
1805
1996
|
try {
|
|
1806
|
-
(
|
|
1807
|
-
updated = true;
|
|
1997
|
+
await runWithShareConfig(override, () => deleteDeck(result.shared.resourceId));
|
|
1808
1998
|
} catch {
|
|
1809
|
-
({ id: resourceId } = await writeDeck(input));
|
|
1810
1999
|
}
|
|
1811
|
-
|
|
1812
|
-
|
|
2000
|
+
jsonResponse(res, 200, {
|
|
2001
|
+
ok: false,
|
|
2002
|
+
error: `Couldn't create the public link, so the deck wasn't shared: ${result.linkError}`
|
|
2003
|
+
});
|
|
2004
|
+
return;
|
|
1813
2005
|
}
|
|
2006
|
+
const publicShareUrl = result.link?.shareUrl ?? existingSync?.publicShareUrl;
|
|
2007
|
+
const publicLinkId = result.link?.linkId ?? existingSync?.publicLinkId;
|
|
1814
2008
|
writeSyncRecord(cwd, id, {
|
|
1815
|
-
resourceId,
|
|
2009
|
+
resourceId: result.shared.resourceId,
|
|
1816
2010
|
sharedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1817
|
-
version: persisted.version
|
|
2011
|
+
version: persisted.version,
|
|
2012
|
+
course,
|
|
2013
|
+
...publicShareUrl ? { publicShareUrl } : {},
|
|
2014
|
+
...publicLinkId ? { publicLinkId } : {}
|
|
2015
|
+
});
|
|
2016
|
+
jsonResponse(res, 200, {
|
|
2017
|
+
ok: true,
|
|
2018
|
+
resourceId: result.shared.resourceId,
|
|
2019
|
+
updated: result.shared.updated,
|
|
2020
|
+
course,
|
|
2021
|
+
shareUrl: publicShareUrl ?? null,
|
|
2022
|
+
...result.linkError ? { linkWarning: result.linkError } : {}
|
|
1818
2023
|
});
|
|
1819
|
-
|
|
2024
|
+
} catch (err) {
|
|
2025
|
+
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
2026
|
+
}
|
|
2027
|
+
return;
|
|
2028
|
+
}
|
|
2029
|
+
const publicLinkMatch = url2.pathname.match(/^\/api\/sessions\/([^/]+)\/public-link$/);
|
|
2030
|
+
if (publicLinkMatch && (req.method === "POST" || req.method === "DELETE")) {
|
|
2031
|
+
const id = decodeURIComponent(publicLinkMatch[1]);
|
|
2032
|
+
const sync = readSyncRecord(cwd, id);
|
|
2033
|
+
if (!sync?.resourceId) {
|
|
2034
|
+
jsonResponse(res, 409, { ok: false, error: "Share this deck to the cloud first, then create a public link." });
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
const cfg = resolveShareConfig(cwd, sync.course);
|
|
2038
|
+
if ("error" in cfg) {
|
|
2039
|
+
jsonResponse(res, 400, { ok: false, error: cfg.error });
|
|
2040
|
+
return;
|
|
2041
|
+
}
|
|
2042
|
+
const { override } = cfg;
|
|
2043
|
+
if (req.method === "DELETE") {
|
|
2044
|
+
if (!sync.publicLinkId) {
|
|
2045
|
+
if (sync.publicShareUrl) {
|
|
2046
|
+
writeSyncRecord(cwd, id, { ...sync, publicShareUrl: void 0, publicLinkId: void 0 });
|
|
2047
|
+
}
|
|
2048
|
+
jsonResponse(res, 200, { ok: true, revoked: false });
|
|
2049
|
+
return;
|
|
2050
|
+
}
|
|
2051
|
+
try {
|
|
2052
|
+
await runWithShareConfig(override, () => revokeDeckShareLink(sync.resourceId, sync.publicLinkId));
|
|
2053
|
+
writeSyncRecord(cwd, id, { ...sync, publicShareUrl: void 0, publicLinkId: void 0 });
|
|
2054
|
+
jsonResponse(res, 200, { ok: true, revoked: true });
|
|
2055
|
+
} catch (err) {
|
|
2056
|
+
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
2057
|
+
}
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
try {
|
|
2061
|
+
const minted = await runWithShareConfig(override, () => createDeckShareLink(sync.resourceId));
|
|
2062
|
+
writeSyncRecord(cwd, id, { ...sync, publicShareUrl: minted.shareUrl, publicLinkId: minted.linkId });
|
|
2063
|
+
jsonResponse(res, 200, { ok: true, shareUrl: minted.shareUrl });
|
|
1820
2064
|
} catch (err) {
|
|
1821
2065
|
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
1822
2066
|
}
|
|
@@ -1844,7 +2088,16 @@ async function startDeckServer(opts = {}) {
|
|
|
1844
2088
|
}
|
|
1845
2089
|
jsonResponse(res, 200, { ok: true, deleted: true });
|
|
1846
2090
|
} catch (err) {
|
|
1847
|
-
|
|
2091
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2092
|
+
if (/not\s*found/i.test(msg)) {
|
|
2093
|
+
try {
|
|
2094
|
+
import_node_fs4.default.rmSync(syncJsonPath(cwd, id), { force: true });
|
|
2095
|
+
} catch {
|
|
2096
|
+
}
|
|
2097
|
+
jsonResponse(res, 200, { ok: true, deleted: false, reason: "already removed" });
|
|
2098
|
+
return;
|
|
2099
|
+
}
|
|
2100
|
+
jsonResponse(res, 500, { ok: false, error: msg });
|
|
1848
2101
|
}
|
|
1849
2102
|
return;
|
|
1850
2103
|
}
|
|
@@ -1935,6 +2188,10 @@ async function startDeckServer(opts = {}) {
|
|
|
1935
2188
|
deletePersistedSession(cwd, session);
|
|
1936
2189
|
} catch {
|
|
1937
2190
|
}
|
|
2191
|
+
const beforePins = discussSessions.length;
|
|
2192
|
+
discussSessions = session === "all" ? [] : discussSessions.filter((d) => d.id !== session);
|
|
2193
|
+
if (discussSessions.length !== beforePins) broadcastDiscuss();
|
|
2194
|
+
if (session === "all" || activeSession?.id === session) activeSession = null;
|
|
1938
2195
|
jsonResponse(res, 200, { ok: true });
|
|
1939
2196
|
return;
|
|
1940
2197
|
}
|
|
@@ -1943,6 +2200,16 @@ async function startDeckServer(opts = {}) {
|
|
|
1943
2200
|
jsonResponse(res, 200, err ?? null);
|
|
1944
2201
|
return;
|
|
1945
2202
|
}
|
|
2203
|
+
if (req.method === "GET" && url2.pathname === "/api/active-session") {
|
|
2204
|
+
jsonResponse(res, 200, {
|
|
2205
|
+
discuss: discussSessions.map((d) => d.id),
|
|
2206
|
+
// ordered = pin number
|
|
2207
|
+
active: activeSession?.id ?? null,
|
|
2208
|
+
focused: activeSession?.focused ?? false,
|
|
2209
|
+
activeAt: activeSession?.at ?? null
|
|
2210
|
+
});
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
1946
2213
|
if (req.method === "GET" && url2.pathname.startsWith("/deck-files/")) {
|
|
1947
2214
|
const relative = decodeURIComponent(url2.pathname.slice("/deck-files/".length));
|
|
1948
2215
|
if (relative.includes("..") || relative.startsWith("/")) {
|
|
@@ -2015,6 +2282,24 @@ async function startDeckServer(opts = {}) {
|
|
|
2015
2282
|
source: msg.source ?? ""
|
|
2016
2283
|
};
|
|
2017
2284
|
}
|
|
2285
|
+
if (msg.type === "active_session" && msg.session) {
|
|
2286
|
+
activeSession = {
|
|
2287
|
+
id: msg.session,
|
|
2288
|
+
focused: msg.focused ?? false,
|
|
2289
|
+
at: Date.now()
|
|
2290
|
+
};
|
|
2291
|
+
}
|
|
2292
|
+
if (msg.type === "discuss_session" && msg.session) {
|
|
2293
|
+
const id = msg.session;
|
|
2294
|
+
const idx = discussSessions.findIndex((d) => d.id === id);
|
|
2295
|
+
if (idx >= 0) discussSessions.splice(idx, 1);
|
|
2296
|
+
else discussSessions.push({ id, at: Date.now() });
|
|
2297
|
+
broadcastDiscuss();
|
|
2298
|
+
}
|
|
2299
|
+
if (msg.type === "discuss_clear_all") {
|
|
2300
|
+
discussSessions = [];
|
|
2301
|
+
broadcastDiscuss();
|
|
2302
|
+
}
|
|
2018
2303
|
} catch {
|
|
2019
2304
|
}
|
|
2020
2305
|
});
|
|
@@ -2083,6 +2368,7 @@ function runServeCli(argv) {
|
|
|
2083
2368
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2084
2369
|
0 && (module.exports = {
|
|
2085
2370
|
broadcastToClients,
|
|
2371
|
+
buildSharePayload,
|
|
2086
2372
|
consumeRenderError,
|
|
2087
2373
|
createFeedbackWaiter,
|
|
2088
2374
|
resolveFeedback,
|