@launchsecure/launch-kit 0.0.40 → 0.0.42
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-B1v46vTE.js → index-DkTFX53U.js} +1 -1
- package/dist/council-client/index.html +2 -2
- package/dist/deck-client/assets/_baseUniq-BrhDuG3C.js +1 -0
- package/dist/deck-client/assets/arc-DXtPHMhw.js +1 -0
- package/dist/deck-client/assets/architectureDiagram-Q4EWVU46-Cs9IdLQQ.js +36 -0
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-CUdblaWk.js → blockDiagram-DXYQGD6D--wpvoBAt.js} +2 -2
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-MfAO5lak.js → c4Diagram-AHTNJAMY-BNIKE8-Z.js} +2 -2
- package/dist/deck-client/assets/channel-Bb5wIjTD.js +1 -0
- package/dist/deck-client/assets/chunk-4BX2VUAB-Bz3EWmUo.js +1 -0
- package/dist/deck-client/assets/{chunk-4TB4RGXK-BUJtZ7jO.js → chunk-4TB4RGXK-D55BBvVZ.js} +1 -1
- package/dist/deck-client/assets/chunk-55IACEB6-BzjEcoTi.js +1 -0
- package/dist/deck-client/assets/chunk-EDXVE4YY-CH1vs4Lu.js +1 -0
- package/dist/deck-client/assets/{chunk-FMBD7UC4-PnZ9v6ey.js → chunk-FMBD7UC4-CVRnaGM0.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-DXrWNOsV.js → chunk-OYMX7WX6-BCTV_aEZ.js} +1 -1
- package/dist/deck-client/assets/chunk-QZHKN3VN-BqM8r4ee.js +1 -0
- package/dist/deck-client/assets/chunk-YZCP3GAM-Rhbb691A.js +1 -0
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CN-ZYMbT.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CN-ZYMbT.js +1 -0
- package/dist/deck-client/assets/clone-D6e7poKG.js +1 -0
- package/dist/deck-client/assets/cose-bilkent-S5V4N54A-fWyBR9Nn.js +1 -0
- package/dist/deck-client/assets/dagre-KV5264BT-Ds0Sqext.js +4 -0
- package/dist/deck-client/assets/diagram-5BDNPKRD-BGz_X007.js +10 -0
- package/dist/deck-client/assets/diagram-G4DWMVQ6-C78jeb-r.js +24 -0
- package/dist/deck-client/assets/diagram-MMDJMWI5-BdoHW8mF.js +43 -0
- package/dist/deck-client/assets/diagram-TYMM5635-C8i9zc-U.js +24 -0
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-56pn_93p.js → erDiagram-SMLLAGMA-DplAZ-yG.js} +2 -2
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-BtV3M5xJ.js → flowDiagram-DWJPFMVM-F3N9yTAB.js} +2 -2
- package/dist/deck-client/assets/ganttDiagram-T4ZO3ILL-DebdM4S5.js +292 -0
- package/dist/deck-client/assets/gitGraphDiagram-UUTBAWPF-htCk0oPz.js +106 -0
- package/dist/deck-client/assets/graph-Dtxc2PT4.js +1 -0
- package/dist/deck-client/assets/index-CwAiam97.js +892 -0
- package/dist/deck-client/assets/index-evAPhGvM.css +1 -0
- package/dist/deck-client/assets/infoDiagram-42DDH7IO-gTxegviJ.js +2 -0
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DXYkdO3T.js → ishikawaDiagram-UXIWVN3A-DYSEsfUK.js} +5 -5
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-C2zBr-J5.js → journeyDiagram-VCZTEJTY-DgVc1q4D.js} +2 -2
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-CdoYLS4Z.js → kanban-definition-6JOO6SKY-DcOf3i9N.js} +2 -2
- package/dist/deck-client/assets/layout-CHP9HIw4.js +1 -0
- package/dist/deck-client/assets/linear-XjVb7x4Q.js +1 -0
- package/dist/deck-client/assets/mermaid.core-bouKOnsR.js +309 -0
- package/dist/deck-client/assets/min-Jl4GV9DB.js +1 -0
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-oAybLedr.js → mindmap-definition-QFDTVHPH-FXXf4cJx.js} +2 -2
- package/dist/deck-client/assets/pieDiagram-DEJITSTG-Dl4plCTi.js +30 -0
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-dtluDZXs.js → quadrantDiagram-34T5L4WZ-BeOEeelg.js} +2 -2
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-Cq8l7bOl.js → requirementDiagram-MS252O5E-CBh1jchM.js} +2 -2
- package/dist/deck-client/assets/sankeyDiagram-XADWPNL6-BK6gG-ub.js +10 -0
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-CYkd7oQK.js → sequenceDiagram-FGHM5R23-BtQwzsF5.js} +2 -2
- package/dist/deck-client/assets/stateDiagram-FHFEXIEX--kLQOi8R.js +1 -0
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CHEPjgB0.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-DZIxSyd1.js → timeline-definition-GMOUNBTQ-CQ_-CLh7.js} +2 -2
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-Ct4JVRDM.js → vennDiagram-DHZGUBPP-DBhKYAFT.js} +2 -2
- package/dist/deck-client/assets/{wardley-RL74JXVD-V29ycxOW.js → wardley-RL74JXVD-DLKe29q9.js} +3 -3
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-D-Ua6Cmi.js → wardleyDiagram-NUSXRM2D-Brb8ezsV.js} +2 -2
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-BPCOuRVl.js → xychartDiagram-5P7HB3ND-LogZ0Az9.js} +2 -2
- package/dist/deck-client/index.html +2 -2
- package/dist/server/cli.js +488 -215
- package/dist/server/council-entry.js +7 -1
- package/dist/server/council-serve.js +7 -1
- package/dist/server/deck-mcp-entry.js +423 -50
- package/dist/server/deck-serve.js +350 -48
- package/dist/server/graph-mcp-entry.js +331 -37
- package/dist/server/init-entry.js +17 -7
- 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/dist/chart-client/assets/index-CWJFFDPu.css +0 -1
- package/dist/client/assets/index-CTzFcfGV.css +0 -32
- package/dist/council-client/assets/index-ArgRc5mN.css +0 -1
- package/dist/deck-client/assets/_baseUniq-BZP7n41F.js +0 -1
- package/dist/deck-client/assets/arc-31biU3Az.js +0 -1
- package/dist/deck-client/assets/architectureDiagram-Q4EWVU46-DHg6Ss--.js +0 -36
- package/dist/deck-client/assets/channel-BBkRLdnC.js +0 -1
- package/dist/deck-client/assets/chunk-4BX2VUAB-DQ1MrGgN.js +0 -1
- package/dist/deck-client/assets/chunk-55IACEB6-BdSnXB6g.js +0 -1
- package/dist/deck-client/assets/chunk-EDXVE4YY-94yZIUI8.js +0 -1
- package/dist/deck-client/assets/chunk-QZHKN3VN-CsIGIDKX.js +0 -1
- package/dist/deck-client/assets/chunk-YZCP3GAM-DVkBO9tn.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-DFCaeF-7.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-DFCaeF-7.js +0 -1
- package/dist/deck-client/assets/clone-GCEVRScB.js +0 -1
- package/dist/deck-client/assets/cose-bilkent-S5V4N54A-m126Oh3b.js +0 -1
- package/dist/deck-client/assets/dagre-KV5264BT-C2aig8U5.js +0 -4
- package/dist/deck-client/assets/diagram-5BDNPKRD-CKpoRfGn.js +0 -10
- package/dist/deck-client/assets/diagram-G4DWMVQ6-Cjh115Ep.js +0 -24
- package/dist/deck-client/assets/diagram-MMDJMWI5-DKlBv_2L.js +0 -43
- package/dist/deck-client/assets/diagram-TYMM5635-CdBh4cEn.js +0 -24
- package/dist/deck-client/assets/ganttDiagram-T4ZO3ILL-DTIsC6Zg.js +0 -292
- package/dist/deck-client/assets/gitGraphDiagram-UUTBAWPF-CJYeyCLe.js +0 -106
- package/dist/deck-client/assets/graph-BDvMu1Ss.js +0 -1
- package/dist/deck-client/assets/index-D4eSxcBn.css +0 -1
- package/dist/deck-client/assets/index-QnGVE9PZ.js +0 -1196
- package/dist/deck-client/assets/infoDiagram-42DDH7IO-BWyKJnpW.js +0 -2
- package/dist/deck-client/assets/layout-vOnxnCQU.js +0 -1
- package/dist/deck-client/assets/linear-B0J0WCGz.js +0 -1
- package/dist/deck-client/assets/min-B0AXlT9L.js +0 -1
- package/dist/deck-client/assets/pieDiagram-DEJITSTG-BjHyHxGk.js +0 -30
- package/dist/deck-client/assets/sankeyDiagram-XADWPNL6-C1Vih91z.js +0 -10
- package/dist/deck-client/assets/stateDiagram-FHFEXIEX-CtyG8wBK.js +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BLyKWfcN.js +0 -1
- /package/dist/chart-client/assets/{index-Dzlj-oCj.js → index-CrYM1-ac.js} +0 -0
- /package/dist/client/assets/{index-tTg_ezUF.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,
|
|
@@ -1399,7 +1400,13 @@ async function callTool(toolName, args) {
|
|
|
1399
1400
|
}
|
|
1400
1401
|
const textContent = result.result?.content?.[0]?.text;
|
|
1401
1402
|
if (!textContent) return null;
|
|
1402
|
-
|
|
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
|
+
}
|
|
1403
1410
|
}
|
|
1404
1411
|
async function writeDeck(input) {
|
|
1405
1412
|
const result = await callTool("communication_write", {
|
|
@@ -1408,6 +1415,7 @@ async function writeDeck(input) {
|
|
|
1408
1415
|
resource_type: "deck",
|
|
1409
1416
|
fields: {
|
|
1410
1417
|
deckHtml: input.html,
|
|
1418
|
+
deckBlocks: input.blocks,
|
|
1411
1419
|
sessionId: input.sessionId,
|
|
1412
1420
|
blockCount: input.blockCount,
|
|
1413
1421
|
sharedFrom: "launch-deck"
|
|
@@ -1422,6 +1430,7 @@ async function updateDeck(commentId, input) {
|
|
|
1422
1430
|
body: input.body,
|
|
1423
1431
|
fields: {
|
|
1424
1432
|
deckHtml: input.html,
|
|
1433
|
+
deckBlocks: input.blocks,
|
|
1425
1434
|
sessionId: input.sessionId,
|
|
1426
1435
|
blockCount: input.blockCount,
|
|
1427
1436
|
sharedFrom: "launch-deck"
|
|
@@ -1432,6 +1441,49 @@ async function updateDeck(commentId, input) {
|
|
|
1432
1441
|
async function deleteDeck(commentId) {
|
|
1433
1442
|
await callTool("communication_delete", { comment_id: commentId });
|
|
1434
1443
|
}
|
|
1444
|
+
function authorLabel(c) {
|
|
1445
|
+
return c.author?.name || c.author?.email || "unknown";
|
|
1446
|
+
}
|
|
1447
|
+
async function readCloudDeck(commentId) {
|
|
1448
|
+
const result = await callTool("communication_read", {
|
|
1449
|
+
resource_type: "deck",
|
|
1450
|
+
limit: 50
|
|
1451
|
+
});
|
|
1452
|
+
const deck = result?.comments?.find((c) => c.id === commentId);
|
|
1453
|
+
if (!deck) return null;
|
|
1454
|
+
return {
|
|
1455
|
+
id: deck.id,
|
|
1456
|
+
title: deck.title ?? "(untitled deck)",
|
|
1457
|
+
author: authorLabel(deck),
|
|
1458
|
+
html: typeof deck.fields?.deckHtml === "string" ? deck.fields.deckHtml : null,
|
|
1459
|
+
blocks: Array.isArray(deck.fields?.deckBlocks) && deck.fields.deckBlocks.length > 0 ? deck.fields.deckBlocks : null
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
function currentMcpOrigin() {
|
|
1463
|
+
const config = _config;
|
|
1464
|
+
if (!config) throw new Error("MCP config not loaded \u2014 call loadMcpConfig first");
|
|
1465
|
+
return new URL(config.url).origin;
|
|
1466
|
+
}
|
|
1467
|
+
async function createDeckShareLink(commentId) {
|
|
1468
|
+
const result = await callTool("deck_share_link", {
|
|
1469
|
+
comment_id: commentId,
|
|
1470
|
+
action: "create"
|
|
1471
|
+
});
|
|
1472
|
+
const token = result.link.token;
|
|
1473
|
+
return {
|
|
1474
|
+
linkId: result.link.id,
|
|
1475
|
+
token,
|
|
1476
|
+
shareUrl: `${currentMcpOrigin()}/s/deck/${token}`,
|
|
1477
|
+
reused: Boolean(result.reused)
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
async function revokeDeckShareLink(commentId, linkId) {
|
|
1481
|
+
await callTool("deck_share_link", {
|
|
1482
|
+
comment_id: commentId,
|
|
1483
|
+
action: "revoke",
|
|
1484
|
+
link_id: linkId
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1435
1487
|
|
|
1436
1488
|
// src/server/deck-serve.ts
|
|
1437
1489
|
var DEFAULT_PORT = 52829;
|
|
@@ -1453,6 +1505,10 @@ function sessionDir(cwd, session) {
|
|
|
1453
1505
|
function sessionJsonPath(cwd, session) {
|
|
1454
1506
|
return import_node_path4.default.join(sessionDir(cwd, session), "session.json");
|
|
1455
1507
|
}
|
|
1508
|
+
function sessionIdFromCloud(title, fallbackId) {
|
|
1509
|
+
const slug = title.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
|
|
1510
|
+
return slug || `deck-${fallbackId.slice(0, 8)}`;
|
|
1511
|
+
}
|
|
1456
1512
|
function readPersistedSession(cwd, session) {
|
|
1457
1513
|
try {
|
|
1458
1514
|
const raw = import_node_fs4.default.readFileSync(sessionJsonPath(cwd, session), "utf-8");
|
|
@@ -1496,7 +1552,11 @@ function listPersistedSessions(cwd) {
|
|
|
1496
1552
|
createdAt: persisted.createdAt,
|
|
1497
1553
|
updatedAt: persisted.updatedAt,
|
|
1498
1554
|
shared: Boolean(sync),
|
|
1499
|
-
stale: Boolean(sync) && persisted.version > (sync?.version ?? 0)
|
|
1555
|
+
stale: Boolean(sync) && persisted.version > (sync?.version ?? 0),
|
|
1556
|
+
shareUrl: sync?.publicShareUrl,
|
|
1557
|
+
course: sync?.course,
|
|
1558
|
+
watching: sync?.watching,
|
|
1559
|
+
watchedFrom: sync?.watchedFrom
|
|
1500
1560
|
});
|
|
1501
1561
|
}
|
|
1502
1562
|
sessions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
@@ -1524,6 +1584,24 @@ function readSyncRecord(cwd, session) {
|
|
|
1524
1584
|
function writeSyncRecord(cwd, session, rec) {
|
|
1525
1585
|
import_node_fs4.default.writeFileSync(syncJsonPath(cwd, session), JSON.stringify(rec, null, 2));
|
|
1526
1586
|
}
|
|
1587
|
+
function resolveShareConfig(cwd, course) {
|
|
1588
|
+
if (course) {
|
|
1589
|
+
const override = mcpConfigForProfile(cwd, course);
|
|
1590
|
+
if (!override) {
|
|
1591
|
+
return { error: `Course "${course}" is not a usable profile in .launch-secure.cred.config (missing pat/serverUrl/orgSlug/projectSlug?).` };
|
|
1592
|
+
}
|
|
1593
|
+
return { override };
|
|
1594
|
+
}
|
|
1595
|
+
try {
|
|
1596
|
+
loadMcpConfig(cwd);
|
|
1597
|
+
} catch (err) {
|
|
1598
|
+
return { error: `Cloud sharing needs an active LaunchSecure course (.launch-secure.cred.config) or a "launch-secure" entry in .mcp.json: ${String(err)}` };
|
|
1599
|
+
}
|
|
1600
|
+
return { override: null };
|
|
1601
|
+
}
|
|
1602
|
+
function runWithShareConfig(override, fn) {
|
|
1603
|
+
return override ? withMcpConfig(override, fn) : fn();
|
|
1604
|
+
}
|
|
1527
1605
|
function escHtml2(s) {
|
|
1528
1606
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1529
1607
|
}
|
|
@@ -1540,31 +1618,49 @@ function readIframeArtifact(cwd, src) {
|
|
|
1540
1618
|
return null;
|
|
1541
1619
|
}
|
|
1542
1620
|
}
|
|
1543
|
-
function renderShareSection(cwd, block) {
|
|
1544
|
-
const label = block?.label ? `<h2 class="db-title">${escHtml2(String(block.label))}</h2>` : "";
|
|
1621
|
+
function renderShareSection(cwd, block, showLabel = true) {
|
|
1622
|
+
const label = showLabel && block?.label ? `<h2 class="db-title">${escHtml2(String(block.label))}</h2>` : "";
|
|
1545
1623
|
switch (block?.type) {
|
|
1546
1624
|
case "iframe": {
|
|
1547
1625
|
const doc = readIframeArtifact(cwd, block.src) ?? "<p>(missing artifact)</p>";
|
|
1548
|
-
return
|
|
1626
|
+
return `${label}<iframe class="db-frame" sandbox="allow-scripts allow-popups" srcdoc="${escAttr(doc)}"></iframe>`;
|
|
1549
1627
|
}
|
|
1550
1628
|
case "rich-html":
|
|
1551
1629
|
case "html":
|
|
1552
|
-
return
|
|
1630
|
+
return `${label}<div class="db-html">${typeof block.content === "string" ? block.content : ""}</div>`;
|
|
1553
1631
|
case "markdown":
|
|
1554
|
-
return
|
|
1632
|
+
return `${label}<div class="db-md" data-md="${escAttr(typeof block.content === "string" ? block.content : "")}"></div>`;
|
|
1555
1633
|
case "mermaid":
|
|
1556
|
-
|
|
1634
|
+
if (typeof block.renderedSvg === "string" && block.renderedSvg.trim()) {
|
|
1635
|
+
return `${label}<div class="mermaid-svg">${block.renderedSvg}</div>`;
|
|
1636
|
+
}
|
|
1637
|
+
return `${label}<pre class="mermaid">${escHtml2(typeof block.content === "string" ? block.content : "")}</pre>`;
|
|
1557
1638
|
case "options": {
|
|
1558
1639
|
const opts = Array.isArray(block.options) ? block.options : [];
|
|
1559
|
-
const
|
|
1560
|
-
(o) => `<
|
|
1640
|
+
const cards = opts.map(
|
|
1641
|
+
(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>`
|
|
1561
1642
|
).join("");
|
|
1562
|
-
return
|
|
1643
|
+
return `${label}<div class="db-options">${cards}</div>`;
|
|
1563
1644
|
}
|
|
1564
1645
|
default:
|
|
1565
|
-
return
|
|
1646
|
+
return label;
|
|
1566
1647
|
}
|
|
1567
1648
|
}
|
|
1649
|
+
function buildSharePayload(cwd, session, blocks, svgByIndex = {}) {
|
|
1650
|
+
const enriched = blocks.map((b, i) => {
|
|
1651
|
+
const svg = svgByIndex[String(i)];
|
|
1652
|
+
return b?.type === "mermaid" && typeof svg === "string" && svg.trim() ? { ...b, renderedSvg: svg } : b;
|
|
1653
|
+
});
|
|
1654
|
+
const html = buildShareHtml(cwd, session, enriched);
|
|
1655
|
+
const cloudBlocks = enriched.map((b) => {
|
|
1656
|
+
if (b?.type === "iframe" && typeof b.src === "string") {
|
|
1657
|
+
const content = readIframeArtifact(cwd, b.src);
|
|
1658
|
+
return content ? { ...b, content } : b;
|
|
1659
|
+
}
|
|
1660
|
+
return b;
|
|
1661
|
+
});
|
|
1662
|
+
return { html, cloudBlocks };
|
|
1663
|
+
}
|
|
1568
1664
|
function buildShareHtml(cwd, session, blocks) {
|
|
1569
1665
|
if (blocks.length === 1) {
|
|
1570
1666
|
const only = blocks[0];
|
|
@@ -1574,30 +1670,61 @@ function buildShareHtml(cwd, session, blocks) {
|
|
|
1574
1670
|
}
|
|
1575
1671
|
}
|
|
1576
1672
|
const list = blocks;
|
|
1577
|
-
const
|
|
1673
|
+
const multi = list.length > 1;
|
|
1674
|
+
const tabBar = multi ? `<nav class="deck-tabs">${list.map(
|
|
1675
|
+
(b, i) => `<button class="deck-tab${i === 0 ? " active" : ""}" data-tab-btn="${i}">${escHtml2(String(b?.label ?? `Tab ${i + 1}`))}</button>`
|
|
1676
|
+
).join("")}</nav>` : "";
|
|
1677
|
+
const sections = list.map(
|
|
1678
|
+
(b, i) => `<section class="db" data-tab="${i}"${multi && i > 0 ? " hidden" : ""}>${renderShareSection(cwd, b, !multi)}</section>`
|
|
1679
|
+
).join("\n");
|
|
1578
1680
|
const hasMd = list.some((b) => b?.type === "markdown");
|
|
1579
|
-
const
|
|
1681
|
+
const hasUnrenderedMermaid = list.some(
|
|
1682
|
+
(b) => b?.type === "mermaid" && !(typeof b?.renderedSvg === "string" && b.renderedSvg.trim())
|
|
1683
|
+
);
|
|
1580
1684
|
return `<!DOCTYPE html>
|
|
1581
1685
|
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1582
1686
|
<title>${escHtml2(session)}</title>
|
|
1687
|
+
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,100..1000&display=swap" rel="stylesheet">
|
|
1583
1688
|
<style>
|
|
1584
|
-
body { margin:0; font-family:
|
|
1689
|
+
body { margin:0; font-family: 'DM Sans', system-ui, sans-serif; background:#0b0e14; color:#e6e9ef; }
|
|
1585
1690
|
.db { padding:20px 24px; border-bottom:1px solid #1e2433; }
|
|
1586
1691
|
.db-title { font-size:13px; font-weight:600; margin:0 0 12px; color:#9aa4b2; text-transform:uppercase; letter-spacing:.05em; }
|
|
1587
1692
|
.db-frame { width:100%; height:70vh; border:0; border-radius:8px; background:#fff; }
|
|
1588
1693
|
.db-html { background:#fff; color:#111; border-radius:8px; padding:16px; overflow:auto; }
|
|
1589
1694
|
ul { line-height:1.7; }
|
|
1590
|
-
|
|
1695
|
+
/* The embedded SVG is dark-themed (captured from the deck client); keep its
|
|
1696
|
+
backdrop transparent so it sits on the dark page, matching the in-app
|
|
1697
|
+
DeckView \u2014 not a white card. The CDN-source fallback also renders dark. */
|
|
1698
|
+
.mermaid { background:transparent; border-radius:8px; padding:16px; }
|
|
1699
|
+
.mermaid-svg { background:transparent; border-radius:8px; padding:16px; overflow:auto; }
|
|
1700
|
+
.mermaid-svg svg { max-width:100%; height:auto; }
|
|
1701
|
+
.db-options { display:grid; gap:12px; grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); }
|
|
1702
|
+
.db-option { border:2px solid #1e2433; border-radius:8px; padding:16px; }
|
|
1703
|
+
.db-option-label { font-size:14px; font-weight:600; color:#e6e9ef; }
|
|
1704
|
+
.db-option-desc { margin-top:4px; font-size:12px; color:#9aa4b2; }
|
|
1705
|
+
.db-option-pre { margin-top:8px; padding:8px; border-radius:6px; background:#11151f; font-size:12px; overflow:auto; }
|
|
1706
|
+
.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; }
|
|
1707
|
+
.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; }
|
|
1708
|
+
.deck-tab:hover { color:#e6e9ef; }
|
|
1709
|
+
.deck-tab.active { color:#c084fc; border-bottom-color:#c084fc; }
|
|
1710
|
+
.db[hidden] { display:none; }
|
|
1591
1711
|
</style></head>
|
|
1592
1712
|
<body>
|
|
1713
|
+
${tabBar}
|
|
1593
1714
|
${sections}
|
|
1715
|
+
${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>` : ""}
|
|
1594
1716
|
${hasMd ? `<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
1595
1717
|
<script>document.querySelectorAll('.db-md').forEach(function(el){try{el.innerHTML=marked.parse(el.dataset.md||'')}catch(e){el.textContent=el.dataset.md||''}});</script>` : ""}
|
|
1596
|
-
${
|
|
1718
|
+
${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>` : ""}
|
|
1597
1719
|
</body></html>`;
|
|
1598
1720
|
}
|
|
1599
1721
|
var pendingFeedback = /* @__PURE__ */ new Map();
|
|
1600
1722
|
var lastRenderError = null;
|
|
1723
|
+
var activeSession = null;
|
|
1724
|
+
var discussSessions = [];
|
|
1725
|
+
function broadcastDiscuss() {
|
|
1726
|
+
broadcastToClients({ type: "discuss_session", sessions: discussSessions.map((d) => d.id) });
|
|
1727
|
+
}
|
|
1601
1728
|
function consumeRenderError() {
|
|
1602
1729
|
const err = lastRenderError;
|
|
1603
1730
|
lastRenderError = null;
|
|
@@ -1828,6 +1955,74 @@ async function startDeckServer(opts = {}) {
|
|
|
1828
1955
|
jsonResponse(res, 200, { sessions: listPersistedSessions(cwd) });
|
|
1829
1956
|
return;
|
|
1830
1957
|
}
|
|
1958
|
+
const pullMatch = url2.pathname.match(/^\/api\/cloud-decks\/([^/]+)\/pull$/);
|
|
1959
|
+
if (pullMatch && req.method === "POST") {
|
|
1960
|
+
const deckId = decodeURIComponent(pullMatch[1]);
|
|
1961
|
+
let course;
|
|
1962
|
+
try {
|
|
1963
|
+
const raw = await readBody(req);
|
|
1964
|
+
if (raw.trim()) {
|
|
1965
|
+
const parsed = JSON.parse(raw);
|
|
1966
|
+
course = parsed.course?.trim() || void 0;
|
|
1967
|
+
}
|
|
1968
|
+
} catch {
|
|
1969
|
+
}
|
|
1970
|
+
const cfg = resolveShareConfig(cwd, course);
|
|
1971
|
+
if ("error" in cfg) {
|
|
1972
|
+
jsonResponse(res, 400, { ok: false, error: cfg.error });
|
|
1973
|
+
return;
|
|
1974
|
+
}
|
|
1975
|
+
try {
|
|
1976
|
+
const deck = await runWithShareConfig(cfg.override, () => readCloudDeck(deckId));
|
|
1977
|
+
if (!deck) {
|
|
1978
|
+
jsonResponse(res, 404, { ok: false, error: `No shared deck "${deckId}" in this course.` });
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
if (!deck.html && !deck.blocks) {
|
|
1982
|
+
jsonResponse(res, 422, { ok: false, error: "That deck carries no viewable content (no deckHtml or deckBlocks)." });
|
|
1983
|
+
return;
|
|
1984
|
+
}
|
|
1985
|
+
const session = sessionIdFromCloud(deck.title, deck.id);
|
|
1986
|
+
const sessionEncoded = encodeURIComponent(session);
|
|
1987
|
+
let blocks;
|
|
1988
|
+
if (deck.html) {
|
|
1989
|
+
const dir = sessionDir(cwd, session);
|
|
1990
|
+
import_node_fs4.default.mkdirSync(dir, { recursive: true });
|
|
1991
|
+
import_node_fs4.default.writeFileSync(import_node_path4.default.join(dir, "imported.html"), deck.html);
|
|
1992
|
+
blocks = [{ type: "iframe", label: deck.title, src: `/deck-files/${sessionEncoded}/imported.html` }];
|
|
1993
|
+
} else {
|
|
1994
|
+
blocks = deck.blocks;
|
|
1995
|
+
}
|
|
1996
|
+
const persisted = writePersistedSession(cwd, session, { mode: "show", blocks });
|
|
1997
|
+
writeSyncRecord(cwd, session, {
|
|
1998
|
+
resourceId: deck.id,
|
|
1999
|
+
sharedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2000
|
+
version: persisted.version,
|
|
2001
|
+
course,
|
|
2002
|
+
watching: true,
|
|
2003
|
+
watchedFrom: deck.author
|
|
2004
|
+
});
|
|
2005
|
+
broadcastToClients({
|
|
2006
|
+
type: "session",
|
|
2007
|
+
session,
|
|
2008
|
+
mode: "show",
|
|
2009
|
+
blocks,
|
|
2010
|
+
version: persisted.version
|
|
2011
|
+
});
|
|
2012
|
+
jsonResponse(res, 200, {
|
|
2013
|
+
ok: true,
|
|
2014
|
+
session,
|
|
2015
|
+
deckId: deck.id,
|
|
2016
|
+
title: deck.title,
|
|
2017
|
+
author: deck.author,
|
|
2018
|
+
blockCount: blocks.length,
|
|
2019
|
+
course
|
|
2020
|
+
});
|
|
2021
|
+
} catch (err) {
|
|
2022
|
+
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
2023
|
+
}
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
1831
2026
|
const shareMatch = url2.pathname.match(/^\/api\/sessions\/([^/]+)\/share$/);
|
|
1832
2027
|
if (shareMatch && req.method === "POST") {
|
|
1833
2028
|
const id = decodeURIComponent(shareMatch[1]);
|
|
@@ -1837,45 +2032,35 @@ async function startDeckServer(opts = {}) {
|
|
|
1837
2032
|
return;
|
|
1838
2033
|
}
|
|
1839
2034
|
let course;
|
|
2035
|
+
let svgByIndex = {};
|
|
2036
|
+
let publicLink = false;
|
|
1840
2037
|
try {
|
|
1841
2038
|
const raw = await readBody(req);
|
|
1842
2039
|
if (raw.trim()) {
|
|
1843
|
-
|
|
2040
|
+
const parsed = JSON.parse(raw);
|
|
2041
|
+
course = parsed.course?.trim() || void 0;
|
|
2042
|
+
if (parsed.svgByIndex && typeof parsed.svgByIndex === "object") svgByIndex = parsed.svgByIndex;
|
|
2043
|
+
publicLink = parsed.publicLink === true;
|
|
1844
2044
|
}
|
|
1845
2045
|
} catch {
|
|
1846
2046
|
}
|
|
1847
|
-
|
|
1848
|
-
if (
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
jsonResponse(res, 400, {
|
|
1852
|
-
ok: false,
|
|
1853
|
-
error: `Course "${course}" is not a usable profile in .launch-secure.cred.config (missing pat/serverUrl/orgSlug/projectSlug?).`
|
|
1854
|
-
});
|
|
1855
|
-
return;
|
|
1856
|
-
}
|
|
1857
|
-
} else {
|
|
1858
|
-
try {
|
|
1859
|
-
loadMcpConfig(cwd);
|
|
1860
|
-
} catch (err) {
|
|
1861
|
-
jsonResponse(res, 400, {
|
|
1862
|
-
ok: false,
|
|
1863
|
-
error: `Cloud sharing needs an active LaunchSecure course (.launch-secure.cred.config) or a "launch-secure" entry in .mcp.json: ${String(err)}`
|
|
1864
|
-
});
|
|
1865
|
-
return;
|
|
1866
|
-
}
|
|
2047
|
+
const cfg = resolveShareConfig(cwd, course);
|
|
2048
|
+
if ("error" in cfg) {
|
|
2049
|
+
jsonResponse(res, 400, { ok: false, error: cfg.error });
|
|
2050
|
+
return;
|
|
1867
2051
|
}
|
|
2052
|
+
const { override } = cfg;
|
|
1868
2053
|
try {
|
|
1869
2054
|
const blocks = Array.isArray(persisted.blocks) ? persisted.blocks : [];
|
|
1870
|
-
const html =
|
|
2055
|
+
const { html, cloudBlocks } = buildSharePayload(cwd, id, blocks, svgByIndex);
|
|
1871
2056
|
const types = blocks.map((b) => b?.type).filter(Boolean);
|
|
1872
2057
|
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.`;
|
|
1873
|
-
const input = { title: id, body, html, sessionId: id, blockCount: blocks.length };
|
|
1874
|
-
const
|
|
2058
|
+
const input = { title: id, body, html, blocks: cloudBlocks, sessionId: id, blockCount: blocks.length };
|
|
2059
|
+
const existingSync = readSyncRecord(cwd, id);
|
|
1875
2060
|
const doShare = async () => {
|
|
1876
|
-
if (
|
|
2061
|
+
if (existingSync?.resourceId) {
|
|
1877
2062
|
try {
|
|
1878
|
-
const { id: rid2 } = await updateDeck(
|
|
2063
|
+
const { id: rid2 } = await updateDeck(existingSync.resourceId, input);
|
|
1879
2064
|
return { resourceId: rid2, updated: true };
|
|
1880
2065
|
} catch {
|
|
1881
2066
|
const { id: rid2 } = await writeDeck(input);
|
|
@@ -1885,14 +2070,89 @@ async function startDeckServer(opts = {}) {
|
|
|
1885
2070
|
const { id: rid } = await writeDeck(input);
|
|
1886
2071
|
return { resourceId: rid, updated: false };
|
|
1887
2072
|
};
|
|
1888
|
-
const
|
|
2073
|
+
const result = await runWithShareConfig(override, async () => {
|
|
2074
|
+
const shared = await doShare();
|
|
2075
|
+
let link = null;
|
|
2076
|
+
let linkError;
|
|
2077
|
+
if (publicLink) {
|
|
2078
|
+
try {
|
|
2079
|
+
const minted = await createDeckShareLink(shared.resourceId);
|
|
2080
|
+
link = { shareUrl: minted.shareUrl, linkId: minted.linkId };
|
|
2081
|
+
} catch (err) {
|
|
2082
|
+
linkError = err instanceof Error ? err.message : String(err);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
return { shared, link, linkError };
|
|
2086
|
+
});
|
|
2087
|
+
if (publicLink && result.linkError && !result.shared.updated) {
|
|
2088
|
+
try {
|
|
2089
|
+
await runWithShareConfig(override, () => deleteDeck(result.shared.resourceId));
|
|
2090
|
+
} catch {
|
|
2091
|
+
}
|
|
2092
|
+
jsonResponse(res, 200, {
|
|
2093
|
+
ok: false,
|
|
2094
|
+
error: `Couldn't create the public link, so the deck wasn't shared: ${result.linkError}`
|
|
2095
|
+
});
|
|
2096
|
+
return;
|
|
2097
|
+
}
|
|
2098
|
+
const publicShareUrl = result.link?.shareUrl ?? existingSync?.publicShareUrl;
|
|
2099
|
+
const publicLinkId = result.link?.linkId ?? existingSync?.publicLinkId;
|
|
1889
2100
|
writeSyncRecord(cwd, id, {
|
|
1890
|
-
resourceId,
|
|
2101
|
+
resourceId: result.shared.resourceId,
|
|
1891
2102
|
sharedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1892
2103
|
version: persisted.version,
|
|
1893
|
-
course
|
|
2104
|
+
course,
|
|
2105
|
+
...publicShareUrl ? { publicShareUrl } : {},
|
|
2106
|
+
...publicLinkId ? { publicLinkId } : {}
|
|
2107
|
+
});
|
|
2108
|
+
jsonResponse(res, 200, {
|
|
2109
|
+
ok: true,
|
|
2110
|
+
resourceId: result.shared.resourceId,
|
|
2111
|
+
updated: result.shared.updated,
|
|
2112
|
+
course,
|
|
2113
|
+
shareUrl: publicShareUrl ?? null,
|
|
2114
|
+
...result.linkError ? { linkWarning: result.linkError } : {}
|
|
1894
2115
|
});
|
|
1895
|
-
|
|
2116
|
+
} catch (err) {
|
|
2117
|
+
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
2118
|
+
}
|
|
2119
|
+
return;
|
|
2120
|
+
}
|
|
2121
|
+
const publicLinkMatch = url2.pathname.match(/^\/api\/sessions\/([^/]+)\/public-link$/);
|
|
2122
|
+
if (publicLinkMatch && (req.method === "POST" || req.method === "DELETE")) {
|
|
2123
|
+
const id = decodeURIComponent(publicLinkMatch[1]);
|
|
2124
|
+
const sync = readSyncRecord(cwd, id);
|
|
2125
|
+
if (!sync?.resourceId) {
|
|
2126
|
+
jsonResponse(res, 409, { ok: false, error: "Share this deck to the cloud first, then create a public link." });
|
|
2127
|
+
return;
|
|
2128
|
+
}
|
|
2129
|
+
const cfg = resolveShareConfig(cwd, sync.course);
|
|
2130
|
+
if ("error" in cfg) {
|
|
2131
|
+
jsonResponse(res, 400, { ok: false, error: cfg.error });
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
const { override } = cfg;
|
|
2135
|
+
if (req.method === "DELETE") {
|
|
2136
|
+
if (!sync.publicLinkId) {
|
|
2137
|
+
if (sync.publicShareUrl) {
|
|
2138
|
+
writeSyncRecord(cwd, id, { ...sync, publicShareUrl: void 0, publicLinkId: void 0 });
|
|
2139
|
+
}
|
|
2140
|
+
jsonResponse(res, 200, { ok: true, revoked: false });
|
|
2141
|
+
return;
|
|
2142
|
+
}
|
|
2143
|
+
try {
|
|
2144
|
+
await runWithShareConfig(override, () => revokeDeckShareLink(sync.resourceId, sync.publicLinkId));
|
|
2145
|
+
writeSyncRecord(cwd, id, { ...sync, publicShareUrl: void 0, publicLinkId: void 0 });
|
|
2146
|
+
jsonResponse(res, 200, { ok: true, revoked: true });
|
|
2147
|
+
} catch (err) {
|
|
2148
|
+
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
2149
|
+
}
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
try {
|
|
2153
|
+
const minted = await runWithShareConfig(override, () => createDeckShareLink(sync.resourceId));
|
|
2154
|
+
writeSyncRecord(cwd, id, { ...sync, publicShareUrl: minted.shareUrl, publicLinkId: minted.linkId });
|
|
2155
|
+
jsonResponse(res, 200, { ok: true, shareUrl: minted.shareUrl });
|
|
1896
2156
|
} catch (err) {
|
|
1897
2157
|
jsonResponse(res, 500, { ok: false, error: String(err) });
|
|
1898
2158
|
}
|
|
@@ -1920,7 +2180,16 @@ async function startDeckServer(opts = {}) {
|
|
|
1920
2180
|
}
|
|
1921
2181
|
jsonResponse(res, 200, { ok: true, deleted: true });
|
|
1922
2182
|
} catch (err) {
|
|
1923
|
-
|
|
2183
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2184
|
+
if (/not\s*found/i.test(msg)) {
|
|
2185
|
+
try {
|
|
2186
|
+
import_node_fs4.default.rmSync(syncJsonPath(cwd, id), { force: true });
|
|
2187
|
+
} catch {
|
|
2188
|
+
}
|
|
2189
|
+
jsonResponse(res, 200, { ok: true, deleted: false, reason: "already removed" });
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
2192
|
+
jsonResponse(res, 500, { ok: false, error: msg });
|
|
1924
2193
|
}
|
|
1925
2194
|
return;
|
|
1926
2195
|
}
|
|
@@ -2011,6 +2280,10 @@ async function startDeckServer(opts = {}) {
|
|
|
2011
2280
|
deletePersistedSession(cwd, session);
|
|
2012
2281
|
} catch {
|
|
2013
2282
|
}
|
|
2283
|
+
const beforePins = discussSessions.length;
|
|
2284
|
+
discussSessions = session === "all" ? [] : discussSessions.filter((d) => d.id !== session);
|
|
2285
|
+
if (discussSessions.length !== beforePins) broadcastDiscuss();
|
|
2286
|
+
if (session === "all" || activeSession?.id === session) activeSession = null;
|
|
2014
2287
|
jsonResponse(res, 200, { ok: true });
|
|
2015
2288
|
return;
|
|
2016
2289
|
}
|
|
@@ -2019,6 +2292,16 @@ async function startDeckServer(opts = {}) {
|
|
|
2019
2292
|
jsonResponse(res, 200, err ?? null);
|
|
2020
2293
|
return;
|
|
2021
2294
|
}
|
|
2295
|
+
if (req.method === "GET" && url2.pathname === "/api/active-session") {
|
|
2296
|
+
jsonResponse(res, 200, {
|
|
2297
|
+
discuss: discussSessions.map((d) => d.id),
|
|
2298
|
+
// ordered = pin number
|
|
2299
|
+
active: activeSession?.id ?? null,
|
|
2300
|
+
focused: activeSession?.focused ?? false,
|
|
2301
|
+
activeAt: activeSession?.at ?? null
|
|
2302
|
+
});
|
|
2303
|
+
return;
|
|
2304
|
+
}
|
|
2022
2305
|
if (req.method === "GET" && url2.pathname.startsWith("/deck-files/")) {
|
|
2023
2306
|
const relative = decodeURIComponent(url2.pathname.slice("/deck-files/".length));
|
|
2024
2307
|
if (relative.includes("..") || relative.startsWith("/")) {
|
|
@@ -2091,6 +2374,24 @@ async function startDeckServer(opts = {}) {
|
|
|
2091
2374
|
source: msg.source ?? ""
|
|
2092
2375
|
};
|
|
2093
2376
|
}
|
|
2377
|
+
if (msg.type === "active_session" && msg.session) {
|
|
2378
|
+
activeSession = {
|
|
2379
|
+
id: msg.session,
|
|
2380
|
+
focused: msg.focused ?? false,
|
|
2381
|
+
at: Date.now()
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
if (msg.type === "discuss_session" && msg.session) {
|
|
2385
|
+
const id = msg.session;
|
|
2386
|
+
const idx = discussSessions.findIndex((d) => d.id === id);
|
|
2387
|
+
if (idx >= 0) discussSessions.splice(idx, 1);
|
|
2388
|
+
else discussSessions.push({ id, at: Date.now() });
|
|
2389
|
+
broadcastDiscuss();
|
|
2390
|
+
}
|
|
2391
|
+
if (msg.type === "discuss_clear_all") {
|
|
2392
|
+
discussSessions = [];
|
|
2393
|
+
broadcastDiscuss();
|
|
2394
|
+
}
|
|
2094
2395
|
} catch {
|
|
2095
2396
|
}
|
|
2096
2397
|
});
|
|
@@ -2159,6 +2460,7 @@ function runServeCli(argv) {
|
|
|
2159
2460
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2160
2461
|
0 && (module.exports = {
|
|
2161
2462
|
broadcastToClients,
|
|
2463
|
+
buildSharePayload,
|
|
2162
2464
|
consumeRenderError,
|
|
2163
2465
|
createFeedbackWaiter,
|
|
2164
2466
|
resolveFeedback,
|