@launchsecure/launch-kit 0.0.30 → 0.0.32

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.
Files changed (106) hide show
  1. package/dist/beacon/beacon.mjs +1027 -929
  2. package/dist/beacon/beacon.mjs.map +1 -1
  3. package/dist/beacon/beacon.umd.js +9 -9
  4. package/dist/beacon/beacon.umd.js.map +1 -1
  5. package/dist/beacon/types/internal/pick-mode-overlay.d.ts.map +1 -1
  6. package/dist/beacon/types/internal/picker.d.ts.map +1 -1
  7. package/dist/beacon/types/internal/pin-popover.d.ts.map +1 -1
  8. package/dist/beacon/types/internal/screenshot.d.ts +19 -1
  9. package/dist/beacon/types/internal/screenshot.d.ts.map +1 -1
  10. package/dist/beacon/types/internal/selector.d.ts.map +1 -1
  11. package/dist/beacon/types/plugins/domEle.d.ts.map +1 -1
  12. package/dist/chart-client/assets/{index-CJ4mgRRF.css → index-CDIhdgWg.css} +1 -1
  13. package/dist/chart-client/index.html +2 -2
  14. package/dist/client/assets/{index-DI5qSR_w.css → index-CfW4n40I.css} +1 -1
  15. package/dist/client/index.html +2 -2
  16. package/dist/council-client/assets/{index-C_-vAM9L.css → index-CZim6x1u.css} +1 -1
  17. package/dist/council-client/index.html +2 -2
  18. package/dist/deck-client/assets/{_baseUniq-DCt2IMRR.js → _baseUniq-C7GsHvgg.js} +1 -1
  19. package/dist/deck-client/assets/{arc-h-ifqmNR.js → arc-CSrZRINY.js} +1 -1
  20. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-C9dITSPv.js → architectureDiagram-Q4EWVU46-zoB-G17J.js} +1 -1
  21. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-BHuJT34t.js → blockDiagram-DXYQGD6D-BRjjtYH6.js} +1 -1
  22. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CpvMGtDG.js → c4Diagram-AHTNJAMY-C3D3sd2U.js} +1 -1
  23. package/dist/deck-client/assets/channel-8ReQnQfH.js +1 -0
  24. package/dist/deck-client/assets/{chunk-4BX2VUAB-B6md1VIm.js → chunk-4BX2VUAB-DhpDMOPO.js} +1 -1
  25. package/dist/deck-client/assets/{chunk-4TB4RGXK-BmEnX8ik.js → chunk-4TB4RGXK-BIRgPXRl.js} +1 -1
  26. package/dist/deck-client/assets/{chunk-55IACEB6-BZPUyZAZ.js → chunk-55IACEB6-BF24dwDZ.js} +1 -1
  27. package/dist/deck-client/assets/{chunk-EDXVE4YY-BWwNUK-l.js → chunk-EDXVE4YY-CW75Y61B.js} +1 -1
  28. package/dist/deck-client/assets/{chunk-FMBD7UC4-o7gSppGI.js → chunk-FMBD7UC4-B5-oyL79.js} +1 -1
  29. package/dist/deck-client/assets/{chunk-OYMX7WX6-C4KoTL5p.js → chunk-OYMX7WX6-BB2bHe_Q.js} +1 -1
  30. package/dist/deck-client/assets/{chunk-QZHKN3VN-jkf68sDs.js → chunk-QZHKN3VN-D80eZO4B.js} +1 -1
  31. package/dist/deck-client/assets/{chunk-YZCP3GAM-Cd4yBE7o.js → chunk-YZCP3GAM-Dz9787p_.js} +1 -1
  32. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-cRxTeGkK.js +1 -0
  33. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-cRxTeGkK.js +1 -0
  34. package/dist/deck-client/assets/clone-LSHZ3K6R.js +1 -0
  35. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-DeGFUgAV.js → cose-bilkent-S5V4N54A-MQjiZLcL.js} +1 -1
  36. package/dist/deck-client/assets/{dagre-KV5264BT-ekcYJuUV.js → dagre-KV5264BT-DG4EcLpJ.js} +1 -1
  37. package/dist/deck-client/assets/{diagram-5BDNPKRD-YHPk4rV2.js → diagram-5BDNPKRD-1n7hM3Gc.js} +1 -1
  38. package/dist/deck-client/assets/{diagram-G4DWMVQ6-DM-JCd_B.js → diagram-G4DWMVQ6-CYMarncV.js} +1 -1
  39. package/dist/deck-client/assets/{diagram-MMDJMWI5-l5FK1ybk.js → diagram-MMDJMWI5-DSisoipe.js} +1 -1
  40. package/dist/deck-client/assets/{diagram-TYMM5635-CIN4_1-j.js → diagram-TYMM5635-Btnq49OJ.js} +1 -1
  41. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-MyinSkEl.js → erDiagram-SMLLAGMA-Cu2Hb_Tz.js} +1 -1
  42. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-Dk8nn42x.js → flowDiagram-DWJPFMVM-CGJzUzsO.js} +1 -1
  43. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-BU1ihicu.js → ganttDiagram-T4ZO3ILL-D9sqGUBT.js} +1 -1
  44. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-BjsTL13C.js → gitGraphDiagram-UUTBAWPF-C0QwX2od.js} +1 -1
  45. package/dist/deck-client/assets/{graph-DJmh-xi7.js → graph-CcBjOQCl.js} +1 -1
  46. package/dist/deck-client/assets/index-0arwoc0z.js +1195 -0
  47. package/dist/deck-client/assets/index-6sdqbm2o.js +2 -0
  48. package/dist/deck-client/assets/{index-DsIZ3LqL.css → index-BlTlhxFW.css} +1 -1
  49. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-Dxvy_RB4.js → infoDiagram-42DDH7IO-DTimhhhS.js} +1 -1
  50. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DPOaNF1l.js → ishikawaDiagram-UXIWVN3A-DxOxg_B4.js} +1 -1
  51. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-DMew3K5c.js → journeyDiagram-VCZTEJTY-Bpq0qa4j.js} +1 -1
  52. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-csciJFuk.js → kanban-definition-6JOO6SKY-aTIrpcVO.js} +1 -1
  53. package/dist/deck-client/assets/{layout-Dg4yyms2.js → layout-DqglLR2E.js} +1 -1
  54. package/dist/deck-client/assets/{linear-BA3zU6gq.js → linear-D5GxehPc.js} +1 -1
  55. package/dist/deck-client/assets/{min-lz-Ird-p.js → min-DXLfSREq.js} +1 -1
  56. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-CCEN8OQV.js → mindmap-definition-QFDTVHPH-mO5Vys7I.js} +1 -1
  57. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-DM6n1HY7.js → pieDiagram-DEJITSTG-Dm0gzdAr.js} +1 -1
  58. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-_ULoR66n.js → quadrantDiagram-34T5L4WZ-Daq7j3qD.js} +1 -1
  59. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-BuwJs7Tn.js → requirementDiagram-MS252O5E-CmwV95um.js} +1 -1
  60. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BEsuzkW4.js → sankeyDiagram-XADWPNL6-BOYl3Nkf.js} +1 -1
  61. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-CP2H0YWf.js → sequenceDiagram-FGHM5R23-BuUjhIcW.js} +1 -1
  62. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-B5Gw_NNL.js → stateDiagram-FHFEXIEX-LUZ_uwio.js} +1 -1
  63. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CnnRwE5D.js +1 -0
  64. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-DsoYydQa.js → timeline-definition-GMOUNBTQ-CDUxCCAW.js} +1 -1
  65. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-Dz8JT_ob.js → vennDiagram-DHZGUBPP-BRb24Tf7.js} +1 -1
  66. package/dist/deck-client/assets/{wardley-RL74JXVD-DGHQ_Ijv.js → wardley-RL74JXVD-B0BYyVBY.js} +1 -1
  67. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-DN1LJMB1.js → wardleyDiagram-NUSXRM2D-BLGlYrQz.js} +1 -1
  68. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-nb0oSfrQ.js → xychartDiagram-5P7HB3ND-De31MSnk.js} +1 -1
  69. package/dist/deck-client/index.html +2 -2
  70. package/dist/server/cli.js +666 -12
  71. package/dist/server/council-entry.js +0 -0
  72. package/dist/server/deck-mcp-entry.js +224 -61
  73. package/dist/server/deck-serve.js +195 -41
  74. package/dist/server/fb-wizard.js +0 -0
  75. package/dist/server/graph-mcp-entry.js +666 -12
  76. package/dist/server/init-entry.js +231 -82
  77. package/package.json +23 -21
  78. package/scaffolds/ls-marketplace/plugins/kit/skills/analyse/SKILL.md +180 -0
  79. package/scaffolds/ls-marketplace/plugins/kit/skills/{blast-radius.md → blast-radius/SKILL.md} +28 -12
  80. package/scaffolds/ls-marketplace/plugins/kit/skills/{debug.md → debug/SKILL.md} +2 -9
  81. package/scaffolds/ls-marketplace/plugins/kit/skills/diagram/SKILL.md +174 -0
  82. package/scaffolds/ls-marketplace/plugins/kit/skills/{prototype.md → prototype/SKILL.md} +21 -1
  83. package/scaffolds/ls-marketplace/plugins/kit/skills/recovery/SKILL.md +95 -0
  84. package/scaffolds/ls-marketplace/plugins/kit/skills/{wireframe.md → wireframe/SKILL.md} +21 -1
  85. package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +0 -0
  86. package/scaffolds/recall-hook/scripts/ensure-recall.sh +0 -0
  87. package/dist/deck-client/assets/channel-2PZVMiXf.js +0 -1
  88. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-Bt8xBAof.js +0 -1
  89. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-Bt8xBAof.js +0 -1
  90. package/dist/deck-client/assets/clone-BHQryoDl.js +0 -1
  91. package/dist/deck-client/assets/index-KsShfCV-.js +0 -476
  92. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-4T4wMDXr.js +0 -1
  93. package/scaffolds/ls-marketplace/plugins/kit/skills/diagram.md +0 -134
  94. package/scaffolds/ls-marketplace/plugins/kit/skills/recall.md +0 -83
  95. /package/dist/chart-client/assets/{index-Ccy-DpI-.js → index-B__ARB8k.js} +0 -0
  96. /package/dist/client/assets/{index-Dp0_okva.js → index-h8kMzVtG.js} +0 -0
  97. /package/dist/council-client/assets/{index-Dt4zWKSj.js → index-CWaDcsFR.js} +0 -0
  98. /package/scaffolds/ls-marketplace/plugins/kit/skills/{beacon-array.md → beacon-array/SKILL.md} +0 -0
  99. /package/scaffolds/ls-marketplace/plugins/kit/skills/{beacon-clear.md → beacon-clear/SKILL.md} +0 -0
  100. /package/scaffolds/ls-marketplace/plugins/kit/skills/{beacon-pulse.md → beacon-pulse/SKILL.md} +0 -0
  101. /package/scaffolds/ls-marketplace/plugins/kit/skills/{beacon-scan.md → beacon-scan/SKILL.md} +0 -0
  102. /package/scaffolds/ls-marketplace/plugins/kit/skills/{brief.md → brief/SKILL.md} +0 -0
  103. /package/scaffolds/ls-marketplace/plugins/kit/skills/{course.md → course/SKILL.md} +0 -0
  104. /package/scaffolds/ls-marketplace/plugins/kit/skills/{deploy-check.md → deploy-check/SKILL.md} +0 -0
  105. /package/scaffolds/ls-marketplace/plugins/kit/skills/{orbit.md → orbit/SKILL.md} +0 -0
  106. /package/scaffolds/ls-marketplace/plugins/kit/skills/{show-mcp-status.md → show-mcp-status/SKILL.md} +0 -0
File without changes
@@ -914,6 +914,31 @@ function renderRichHtml(opts) {
914
914
  }
915
915
  return opts.content;
916
916
  }
917
+ function renderWiredBody(body) {
918
+ return `<style>
919
+ :host {
920
+ display: block;
921
+ padding: 24px;
922
+ font-family: 'Gloria Hallelujah', 'DM Sans', system-ui, sans-serif;
923
+ color: var(--page-fg, currentColor);
924
+ }
925
+ *, *::before, *::after { box-sizing: border-box; }
926
+ h1, h2, h3, h4 { font-family: 'Gloria Hallelujah', cursive; margin: 0.5em 0; }
927
+ a { color: var(--page-accent, #7c3aed); }
928
+ .row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin: 8px 0; }
929
+ .col { display: flex; flex-direction: column; gap: 12px; align-items: stretch; }
930
+ .card { padding: 16px; }
931
+ wired-button, wired-card, wired-checkbox, wired-radio, wired-toggle,
932
+ wired-input, wired-textarea, wired-search-input, wired-combo, wired-item,
933
+ wired-listbox, wired-link, wired-tabs, wired-tab, wired-fab,
934
+ wired-icon-button, wired-divider, wired-progress, wired-slider,
935
+ wired-calendar, wired-dialog {
936
+ color: inherit;
937
+ background: transparent;
938
+ }
939
+ </style>
940
+ ${body}`;
941
+ }
917
942
  function themeResolverScript(initial) {
918
943
  return `<script>
919
944
  (function () {
@@ -1183,6 +1208,67 @@ __export(deck_serve_exports, {
1183
1208
  runServeCli: () => runServeCli,
1184
1209
  startDeckServer: () => startDeckServer
1185
1210
  });
1211
+ function sessionDir(cwd, session) {
1212
+ return import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", session);
1213
+ }
1214
+ function sessionJsonPath(cwd, session) {
1215
+ return import_node_path3.default.join(sessionDir(cwd, session), "session.json");
1216
+ }
1217
+ function readPersistedSession(cwd, session) {
1218
+ try {
1219
+ const raw = import_node_fs3.default.readFileSync(sessionJsonPath(cwd, session), "utf-8");
1220
+ return JSON.parse(raw);
1221
+ } catch {
1222
+ return null;
1223
+ }
1224
+ }
1225
+ function writePersistedSession(cwd, session, payload) {
1226
+ const dir = sessionDir(cwd, session);
1227
+ import_node_fs3.default.mkdirSync(dir, { recursive: true });
1228
+ const existing = readPersistedSession(cwd, session);
1229
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1230
+ const next = {
1231
+ id: session,
1232
+ mode: payload.mode,
1233
+ prompt: payload.prompt,
1234
+ blocks: payload.blocks,
1235
+ version: existing ? existing.version + 1 : 1,
1236
+ createdAt: existing?.createdAt ?? now,
1237
+ updatedAt: now
1238
+ };
1239
+ import_node_fs3.default.writeFileSync(sessionJsonPath(cwd, session), JSON.stringify(next, null, 2));
1240
+ return next;
1241
+ }
1242
+ function listPersistedSessions(cwd) {
1243
+ const base = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1244
+ if (!import_node_fs3.default.existsSync(base)) return [];
1245
+ const entries = import_node_fs3.default.readdirSync(base, { withFileTypes: true });
1246
+ const sessions = [];
1247
+ for (const entry of entries) {
1248
+ if (!entry.isDirectory()) continue;
1249
+ const persisted = readPersistedSession(cwd, entry.name);
1250
+ if (!persisted) continue;
1251
+ sessions.push({
1252
+ id: persisted.id,
1253
+ mode: persisted.mode,
1254
+ blockCount: Array.isArray(persisted.blocks) ? persisted.blocks.length : 0,
1255
+ version: persisted.version,
1256
+ createdAt: persisted.createdAt,
1257
+ updatedAt: persisted.updatedAt
1258
+ });
1259
+ }
1260
+ sessions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
1261
+ return sessions;
1262
+ }
1263
+ function deletePersistedSession(cwd, session) {
1264
+ const base = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1265
+ if (session === "all") {
1266
+ if (import_node_fs3.default.existsSync(base)) import_node_fs3.default.rmSync(base, { recursive: true, force: true });
1267
+ return;
1268
+ }
1269
+ const dir = sessionDir(cwd, session);
1270
+ if (import_node_fs3.default.existsSync(dir)) import_node_fs3.default.rmSync(dir, { recursive: true, force: true });
1271
+ }
1186
1272
  function consumeRenderError() {
1187
1273
  const err = lastRenderError;
1188
1274
  lastRenderError = null;
@@ -1226,6 +1312,13 @@ function serveStatic(res, filePath) {
1226
1312
  import_node_fs3.default.createReadStream(filePath).pipe(res);
1227
1313
  return true;
1228
1314
  }
1315
+ function resolveClientDir() {
1316
+ const sibling = import_node_path3.default.join(__dirname, "..", "deck-client");
1317
+ if (import_node_fs3.default.existsSync(import_node_path3.default.join(sibling, "assets"))) return sibling;
1318
+ const devDist = import_node_path3.default.join(__dirname, "..", "..", "dist", "deck-client");
1319
+ if (import_node_fs3.default.existsSync(import_node_path3.default.join(devDist, "assets"))) return devDist;
1320
+ return sibling;
1321
+ }
1229
1322
  function serveIndex(res, clientDir) {
1230
1323
  const indexPath = import_node_path3.default.join(clientDir, "index.html");
1231
1324
  if (!import_node_fs3.default.existsSync(indexPath)) {
@@ -1290,7 +1383,7 @@ async function startDeckServer(opts = {}) {
1290
1383
  }
1291
1384
  return { port: existing.port, url: existing.url };
1292
1385
  }
1293
- const clientDir = opts.clientDir ?? import_node_path3.default.join(__dirname, "..", "deck-client");
1386
+ const clientDir = opts.clientDir ?? resolveClientDir();
1294
1387
  const server = import_node_http.default.createServer(async (req, res) => {
1295
1388
  try {
1296
1389
  const url2 = new URL(req.url ?? "/", `http://${req.headers.host}`);
@@ -1349,39 +1442,78 @@ async function startDeckServer(opts = {}) {
1349
1442
  }
1350
1443
  }
1351
1444
  if (block.type === "rich-html" && block.content) {
1352
- try {
1353
- const html = renderRichHtml({
1354
- framework: block.framework ?? "raw",
1355
- content: block.content,
1356
- theme: block.theme,
1357
- title: block.label
1358
- });
1359
- const sessionEncoded = encodeURIComponent(body.session);
1360
- const baseUrl = `/deck-files/${sessionEncoded}`;
1361
- const filename = `${slugify(block.label)}.html`;
1362
- const dir = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
1363
- import_node_fs3.default.mkdirSync(dir, { recursive: true });
1364
- import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, filename), html);
1365
- block.type = "iframe";
1366
- block.src = `${baseUrl}/${filename}`;
1367
- delete block.content;
1368
- delete block.framework;
1369
- delete block.theme;
1370
- } catch (err) {
1371
- console.error("Failed to generate rich-html:", err);
1445
+ const framework = block.framework ?? "raw";
1446
+ if (framework === "wired") {
1447
+ try {
1448
+ block.content = renderWiredBody(block.content);
1449
+ } catch (err) {
1450
+ console.error("Failed to render wired body:", err);
1451
+ }
1452
+ } else {
1453
+ try {
1454
+ const html = renderRichHtml({
1455
+ framework,
1456
+ content: block.content,
1457
+ theme: block.theme,
1458
+ title: block.label
1459
+ });
1460
+ const sessionEncoded = encodeURIComponent(body.session);
1461
+ const baseUrl = `/deck-files/${sessionEncoded}`;
1462
+ const filename = `${slugify(block.label)}.html`;
1463
+ const dir = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
1464
+ import_node_fs3.default.mkdirSync(dir, { recursive: true });
1465
+ import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, filename), html);
1466
+ block.type = "iframe";
1467
+ block.src = `${baseUrl}/${filename}`;
1468
+ delete block.content;
1469
+ delete block.framework;
1470
+ delete block.theme;
1471
+ } catch (err) {
1472
+ console.error("Failed to generate rich-html:", err);
1473
+ }
1372
1474
  }
1373
1475
  }
1374
1476
  }
1477
+ const persisted = writePersistedSession(cwd, body.session, {
1478
+ mode: body.mode,
1479
+ prompt: body.prompt,
1480
+ blocks: body.blocks
1481
+ });
1375
1482
  broadcastToClients({
1376
1483
  type: "session",
1377
1484
  session: body.session,
1378
1485
  mode: body.mode,
1379
1486
  blocks: body.blocks,
1380
- prompt: body.prompt
1487
+ prompt: body.prompt,
1488
+ version: persisted.version
1381
1489
  });
1382
- jsonResponse(res, 200, { ok: true });
1490
+ jsonResponse(res, 200, { ok: true, version: persisted.version });
1383
1491
  return;
1384
1492
  }
1493
+ if (req.method === "GET" && url2.pathname === "/api/sessions") {
1494
+ jsonResponse(res, 200, { sessions: listPersistedSessions(cwd) });
1495
+ return;
1496
+ }
1497
+ const sessionMatch = url2.pathname.match(/^\/api\/sessions\/([^/]+)$/);
1498
+ if (sessionMatch) {
1499
+ const id = decodeURIComponent(sessionMatch[1]);
1500
+ if (req.method === "GET") {
1501
+ const persisted = readPersistedSession(cwd, id);
1502
+ if (!persisted) {
1503
+ jsonResponse(res, 404, { error: "not found" });
1504
+ return;
1505
+ }
1506
+ jsonResponse(res, 200, persisted);
1507
+ return;
1508
+ }
1509
+ if (req.method === "DELETE") {
1510
+ broadcastToClients({ type: "clear_session", session: id });
1511
+ resolveFeedback(id, { comment: "", closed: true });
1512
+ deletePersistedSession(cwd, id);
1513
+ jsonResponse(res, 200, { ok: true });
1514
+ return;
1515
+ }
1516
+ }
1385
1517
  if (req.method === "POST" && url2.pathname === "/api/await-feedback") {
1386
1518
  const { session } = JSON.parse(await readBody(req));
1387
1519
  try {
@@ -1392,6 +1524,45 @@ async function startDeckServer(opts = {}) {
1392
1524
  }
1393
1525
  return;
1394
1526
  }
1527
+ if (req.method === "POST" && url2.pathname === "/api/feedback") {
1528
+ try {
1529
+ const payload = JSON.parse(await readBody(req));
1530
+ const sessionId = payload.context?.sessionId;
1531
+ if (!sessionId) {
1532
+ jsonResponse(res, 400, { ok: false, error: "context.sessionId is required" });
1533
+ return;
1534
+ }
1535
+ const verdictMap = {
1536
+ bug: "blocker",
1537
+ idea: "iterate",
1538
+ ux: "note",
1539
+ a11y: "approve"
1540
+ };
1541
+ const domEle = payload.plugins?.domEle;
1542
+ const domSS = payload.plugins?.domSS;
1543
+ const picks = Array.isArray(domEle?.pins) ? domEle.pins.filter((p) => p && typeof p.selector === "string").map((p) => ({
1544
+ selector: p.selector,
1545
+ ...p.note ? { note: p.note } : {},
1546
+ ...p.boundingRect ? { rect: p.boundingRect } : {}
1547
+ })) : [];
1548
+ const response = {
1549
+ comment: payload.description ?? "",
1550
+ selections: payload.context?.selections,
1551
+ verdict: payload.severity ? verdictMap[payload.severity] : void 0,
1552
+ picks: picks.length > 0 ? picks : void 0,
1553
+ screenshot: typeof domSS?.dataUrl === "string" ? domSS.dataUrl : void 0
1554
+ };
1555
+ const resolved = resolveFeedback(sessionId, response);
1556
+ if (!resolved) {
1557
+ jsonResponse(res, 409, { ok: false, error: `no pending await_feedback for session "${sessionId}"` });
1558
+ return;
1559
+ }
1560
+ jsonResponse(res, 200, { ok: true });
1561
+ } catch (err) {
1562
+ jsonResponse(res, 400, { ok: false, error: String(err) });
1563
+ }
1564
+ return;
1565
+ }
1395
1566
  if (req.method === "POST" && url2.pathname === "/api/clear-session") {
1396
1567
  const { session } = JSON.parse(await readBody(req));
1397
1568
  broadcastToClients({
@@ -1407,17 +1578,7 @@ async function startDeckServer(opts = {}) {
1407
1578
  resolveFeedback(session, { comment: "", closed: true });
1408
1579
  }
1409
1580
  try {
1410
- const deckFilesBase = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1411
- if (session === "all") {
1412
- if (import_node_fs3.default.existsSync(deckFilesBase)) {
1413
- import_node_fs3.default.rmSync(deckFilesBase, { recursive: true, force: true });
1414
- }
1415
- } else {
1416
- const sessionDir = import_node_path3.default.join(deckFilesBase, session);
1417
- if (import_node_fs3.default.existsSync(sessionDir)) {
1418
- import_node_fs3.default.rmSync(sessionDir, { recursive: true, force: true });
1419
- }
1420
- }
1581
+ deletePersistedSession(cwd, session);
1421
1582
  } catch {
1422
1583
  }
1423
1584
  jsonResponse(res, 200, { ok: true });
@@ -1532,13 +1693,6 @@ async function startDeckServer(opts = {}) {
1532
1693
  waiter.reject(new Error("LaunchDeck server shutting down"));
1533
1694
  pendingFeedback.delete(id);
1534
1695
  }
1535
- try {
1536
- const deckFilesBase = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1537
- if (import_node_fs3.default.existsSync(deckFilesBase)) {
1538
- import_node_fs3.default.rmSync(deckFilesBase, { recursive: true, force: true });
1539
- }
1540
- } catch {
1541
- }
1542
1696
  clearLock(cwd);
1543
1697
  server.close();
1544
1698
  };
@@ -1688,26 +1842,35 @@ async function handleTool(name, args) {
1688
1842
  }
1689
1843
  }
1690
1844
  if (block.type === "rich-html" && block.content) {
1691
- try {
1692
- const html = renderRichHtml({
1693
- framework: block.framework ?? "raw",
1694
- content: block.content,
1695
- theme: block.theme,
1696
- title: block.label
1697
- });
1698
- const sessionEncoded = encodeURIComponent(session);
1699
- const baseUrl = `/deck-files/${sessionEncoded}`;
1700
- const filename = `${slugify(block.label)}.html`;
1701
- const dir = (0, import_node_path4.join)(projectRoot, LAUNCHSECURE_DIR, "deck-files", session);
1702
- import_node_fs4.default.mkdirSync(dir, { recursive: true });
1703
- import_node_fs4.default.writeFileSync((0, import_node_path4.join)(dir, filename), html);
1704
- block.type = "iframe";
1705
- block.src = `${baseUrl}/${filename}`;
1706
- delete block.content;
1707
- delete block.framework;
1708
- delete block.theme;
1709
- } catch (err) {
1710
- return text(JSON.stringify({ error: `Failed to generate rich-html: ${err}` }));
1845
+ const framework = block.framework ?? "raw";
1846
+ if (framework === "wired") {
1847
+ try {
1848
+ block.content = renderWiredBody(block.content);
1849
+ } catch (err) {
1850
+ return text(JSON.stringify({ error: `Failed to render wired body: ${err}` }));
1851
+ }
1852
+ } else {
1853
+ try {
1854
+ const html = renderRichHtml({
1855
+ framework,
1856
+ content: block.content,
1857
+ theme: block.theme,
1858
+ title: block.label
1859
+ });
1860
+ const sessionEncoded = encodeURIComponent(session);
1861
+ const baseUrl = `/deck-files/${sessionEncoded}`;
1862
+ const filename = `${slugify(block.label)}.html`;
1863
+ const dir = (0, import_node_path4.join)(projectRoot, LAUNCHSECURE_DIR, "deck-files", session);
1864
+ import_node_fs4.default.mkdirSync(dir, { recursive: true });
1865
+ import_node_fs4.default.writeFileSync((0, import_node_path4.join)(dir, filename), html);
1866
+ block.type = "iframe";
1867
+ block.src = `${baseUrl}/${filename}`;
1868
+ delete block.content;
1869
+ delete block.framework;
1870
+ delete block.theme;
1871
+ } catch (err) {
1872
+ return text(JSON.stringify({ error: `Failed to generate rich-html: ${err}` }));
1873
+ }
1711
1874
  }
1712
1875
  }
1713
1876
  }
@@ -904,6 +904,31 @@ function renderRichHtml(opts) {
904
904
  }
905
905
  return opts.content;
906
906
  }
907
+ function renderWiredBody(body) {
908
+ return `<style>
909
+ :host {
910
+ display: block;
911
+ padding: 24px;
912
+ font-family: 'Gloria Hallelujah', 'DM Sans', system-ui, sans-serif;
913
+ color: var(--page-fg, currentColor);
914
+ }
915
+ *, *::before, *::after { box-sizing: border-box; }
916
+ h1, h2, h3, h4 { font-family: 'Gloria Hallelujah', cursive; margin: 0.5em 0; }
917
+ a { color: var(--page-accent, #7c3aed); }
918
+ .row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin: 8px 0; }
919
+ .col { display: flex; flex-direction: column; gap: 12px; align-items: stretch; }
920
+ .card { padding: 16px; }
921
+ wired-button, wired-card, wired-checkbox, wired-radio, wired-toggle,
922
+ wired-input, wired-textarea, wired-search-input, wired-combo, wired-item,
923
+ wired-listbox, wired-link, wired-tabs, wired-tab, wired-fab,
924
+ wired-icon-button, wired-divider, wired-progress, wired-slider,
925
+ wired-calendar, wired-dialog {
926
+ color: inherit;
927
+ background: transparent;
928
+ }
929
+ </style>
930
+ ${body}`;
931
+ }
907
932
  function themeResolverScript(initial) {
908
933
  return `<script>
909
934
  (function () {
@@ -1163,6 +1188,67 @@ var MIME_TYPES = {
1163
1188
  ".woff": "font/woff",
1164
1189
  ".woff2": "font/woff2"
1165
1190
  };
1191
+ function sessionDir(cwd, session) {
1192
+ return import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", session);
1193
+ }
1194
+ function sessionJsonPath(cwd, session) {
1195
+ return import_node_path3.default.join(sessionDir(cwd, session), "session.json");
1196
+ }
1197
+ function readPersistedSession(cwd, session) {
1198
+ try {
1199
+ const raw = import_node_fs3.default.readFileSync(sessionJsonPath(cwd, session), "utf-8");
1200
+ return JSON.parse(raw);
1201
+ } catch {
1202
+ return null;
1203
+ }
1204
+ }
1205
+ function writePersistedSession(cwd, session, payload) {
1206
+ const dir = sessionDir(cwd, session);
1207
+ import_node_fs3.default.mkdirSync(dir, { recursive: true });
1208
+ const existing = readPersistedSession(cwd, session);
1209
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1210
+ const next = {
1211
+ id: session,
1212
+ mode: payload.mode,
1213
+ prompt: payload.prompt,
1214
+ blocks: payload.blocks,
1215
+ version: existing ? existing.version + 1 : 1,
1216
+ createdAt: existing?.createdAt ?? now,
1217
+ updatedAt: now
1218
+ };
1219
+ import_node_fs3.default.writeFileSync(sessionJsonPath(cwd, session), JSON.stringify(next, null, 2));
1220
+ return next;
1221
+ }
1222
+ function listPersistedSessions(cwd) {
1223
+ const base = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1224
+ if (!import_node_fs3.default.existsSync(base)) return [];
1225
+ const entries = import_node_fs3.default.readdirSync(base, { withFileTypes: true });
1226
+ const sessions = [];
1227
+ for (const entry of entries) {
1228
+ if (!entry.isDirectory()) continue;
1229
+ const persisted = readPersistedSession(cwd, entry.name);
1230
+ if (!persisted) continue;
1231
+ sessions.push({
1232
+ id: persisted.id,
1233
+ mode: persisted.mode,
1234
+ blockCount: Array.isArray(persisted.blocks) ? persisted.blocks.length : 0,
1235
+ version: persisted.version,
1236
+ createdAt: persisted.createdAt,
1237
+ updatedAt: persisted.updatedAt
1238
+ });
1239
+ }
1240
+ sessions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
1241
+ return sessions;
1242
+ }
1243
+ function deletePersistedSession(cwd, session) {
1244
+ const base = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1245
+ if (session === "all") {
1246
+ if (import_node_fs3.default.existsSync(base)) import_node_fs3.default.rmSync(base, { recursive: true, force: true });
1247
+ return;
1248
+ }
1249
+ const dir = sessionDir(cwd, session);
1250
+ if (import_node_fs3.default.existsSync(dir)) import_node_fs3.default.rmSync(dir, { recursive: true, force: true });
1251
+ }
1166
1252
  var pendingFeedback = /* @__PURE__ */ new Map();
1167
1253
  var lastRenderError = null;
1168
1254
  function consumeRenderError() {
@@ -1209,6 +1295,13 @@ function serveStatic(res, filePath) {
1209
1295
  import_node_fs3.default.createReadStream(filePath).pipe(res);
1210
1296
  return true;
1211
1297
  }
1298
+ function resolveClientDir() {
1299
+ const sibling = import_node_path3.default.join(__dirname, "..", "deck-client");
1300
+ if (import_node_fs3.default.existsSync(import_node_path3.default.join(sibling, "assets"))) return sibling;
1301
+ const devDist = import_node_path3.default.join(__dirname, "..", "..", "dist", "deck-client");
1302
+ if (import_node_fs3.default.existsSync(import_node_path3.default.join(devDist, "assets"))) return devDist;
1303
+ return sibling;
1304
+ }
1212
1305
  function serveIndex(res, clientDir) {
1213
1306
  const indexPath = import_node_path3.default.join(clientDir, "index.html");
1214
1307
  if (!import_node_fs3.default.existsSync(indexPath)) {
@@ -1273,7 +1366,7 @@ async function startDeckServer(opts = {}) {
1273
1366
  }
1274
1367
  return { port: existing.port, url: existing.url };
1275
1368
  }
1276
- const clientDir = opts.clientDir ?? import_node_path3.default.join(__dirname, "..", "deck-client");
1369
+ const clientDir = opts.clientDir ?? resolveClientDir();
1277
1370
  const server = import_node_http.default.createServer(async (req, res) => {
1278
1371
  try {
1279
1372
  const url2 = new URL(req.url ?? "/", `http://${req.headers.host}`);
@@ -1332,39 +1425,78 @@ async function startDeckServer(opts = {}) {
1332
1425
  }
1333
1426
  }
1334
1427
  if (block.type === "rich-html" && block.content) {
1335
- try {
1336
- const html = renderRichHtml({
1337
- framework: block.framework ?? "raw",
1338
- content: block.content,
1339
- theme: block.theme,
1340
- title: block.label
1341
- });
1342
- const sessionEncoded = encodeURIComponent(body.session);
1343
- const baseUrl = `/deck-files/${sessionEncoded}`;
1344
- const filename = `${slugify(block.label)}.html`;
1345
- const dir = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
1346
- import_node_fs3.default.mkdirSync(dir, { recursive: true });
1347
- import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, filename), html);
1348
- block.type = "iframe";
1349
- block.src = `${baseUrl}/${filename}`;
1350
- delete block.content;
1351
- delete block.framework;
1352
- delete block.theme;
1353
- } catch (err) {
1354
- console.error("Failed to generate rich-html:", err);
1428
+ const framework = block.framework ?? "raw";
1429
+ if (framework === "wired") {
1430
+ try {
1431
+ block.content = renderWiredBody(block.content);
1432
+ } catch (err) {
1433
+ console.error("Failed to render wired body:", err);
1434
+ }
1435
+ } else {
1436
+ try {
1437
+ const html = renderRichHtml({
1438
+ framework,
1439
+ content: block.content,
1440
+ theme: block.theme,
1441
+ title: block.label
1442
+ });
1443
+ const sessionEncoded = encodeURIComponent(body.session);
1444
+ const baseUrl = `/deck-files/${sessionEncoded}`;
1445
+ const filename = `${slugify(block.label)}.html`;
1446
+ const dir = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files", body.session);
1447
+ import_node_fs3.default.mkdirSync(dir, { recursive: true });
1448
+ import_node_fs3.default.writeFileSync(import_node_path3.default.join(dir, filename), html);
1449
+ block.type = "iframe";
1450
+ block.src = `${baseUrl}/${filename}`;
1451
+ delete block.content;
1452
+ delete block.framework;
1453
+ delete block.theme;
1454
+ } catch (err) {
1455
+ console.error("Failed to generate rich-html:", err);
1456
+ }
1355
1457
  }
1356
1458
  }
1357
1459
  }
1460
+ const persisted = writePersistedSession(cwd, body.session, {
1461
+ mode: body.mode,
1462
+ prompt: body.prompt,
1463
+ blocks: body.blocks
1464
+ });
1358
1465
  broadcastToClients({
1359
1466
  type: "session",
1360
1467
  session: body.session,
1361
1468
  mode: body.mode,
1362
1469
  blocks: body.blocks,
1363
- prompt: body.prompt
1470
+ prompt: body.prompt,
1471
+ version: persisted.version
1364
1472
  });
1365
- jsonResponse(res, 200, { ok: true });
1473
+ jsonResponse(res, 200, { ok: true, version: persisted.version });
1474
+ return;
1475
+ }
1476
+ if (req.method === "GET" && url2.pathname === "/api/sessions") {
1477
+ jsonResponse(res, 200, { sessions: listPersistedSessions(cwd) });
1366
1478
  return;
1367
1479
  }
1480
+ const sessionMatch = url2.pathname.match(/^\/api\/sessions\/([^/]+)$/);
1481
+ if (sessionMatch) {
1482
+ const id = decodeURIComponent(sessionMatch[1]);
1483
+ if (req.method === "GET") {
1484
+ const persisted = readPersistedSession(cwd, id);
1485
+ if (!persisted) {
1486
+ jsonResponse(res, 404, { error: "not found" });
1487
+ return;
1488
+ }
1489
+ jsonResponse(res, 200, persisted);
1490
+ return;
1491
+ }
1492
+ if (req.method === "DELETE") {
1493
+ broadcastToClients({ type: "clear_session", session: id });
1494
+ resolveFeedback(id, { comment: "", closed: true });
1495
+ deletePersistedSession(cwd, id);
1496
+ jsonResponse(res, 200, { ok: true });
1497
+ return;
1498
+ }
1499
+ }
1368
1500
  if (req.method === "POST" && url2.pathname === "/api/await-feedback") {
1369
1501
  const { session } = JSON.parse(await readBody(req));
1370
1502
  try {
@@ -1375,6 +1507,45 @@ async function startDeckServer(opts = {}) {
1375
1507
  }
1376
1508
  return;
1377
1509
  }
1510
+ if (req.method === "POST" && url2.pathname === "/api/feedback") {
1511
+ try {
1512
+ const payload = JSON.parse(await readBody(req));
1513
+ const sessionId = payload.context?.sessionId;
1514
+ if (!sessionId) {
1515
+ jsonResponse(res, 400, { ok: false, error: "context.sessionId is required" });
1516
+ return;
1517
+ }
1518
+ const verdictMap = {
1519
+ bug: "blocker",
1520
+ idea: "iterate",
1521
+ ux: "note",
1522
+ a11y: "approve"
1523
+ };
1524
+ const domEle = payload.plugins?.domEle;
1525
+ const domSS = payload.plugins?.domSS;
1526
+ const picks = Array.isArray(domEle?.pins) ? domEle.pins.filter((p) => p && typeof p.selector === "string").map((p) => ({
1527
+ selector: p.selector,
1528
+ ...p.note ? { note: p.note } : {},
1529
+ ...p.boundingRect ? { rect: p.boundingRect } : {}
1530
+ })) : [];
1531
+ const response = {
1532
+ comment: payload.description ?? "",
1533
+ selections: payload.context?.selections,
1534
+ verdict: payload.severity ? verdictMap[payload.severity] : void 0,
1535
+ picks: picks.length > 0 ? picks : void 0,
1536
+ screenshot: typeof domSS?.dataUrl === "string" ? domSS.dataUrl : void 0
1537
+ };
1538
+ const resolved = resolveFeedback(sessionId, response);
1539
+ if (!resolved) {
1540
+ jsonResponse(res, 409, { ok: false, error: `no pending await_feedback for session "${sessionId}"` });
1541
+ return;
1542
+ }
1543
+ jsonResponse(res, 200, { ok: true });
1544
+ } catch (err) {
1545
+ jsonResponse(res, 400, { ok: false, error: String(err) });
1546
+ }
1547
+ return;
1548
+ }
1378
1549
  if (req.method === "POST" && url2.pathname === "/api/clear-session") {
1379
1550
  const { session } = JSON.parse(await readBody(req));
1380
1551
  broadcastToClients({
@@ -1390,17 +1561,7 @@ async function startDeckServer(opts = {}) {
1390
1561
  resolveFeedback(session, { comment: "", closed: true });
1391
1562
  }
1392
1563
  try {
1393
- const deckFilesBase = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1394
- if (session === "all") {
1395
- if (import_node_fs3.default.existsSync(deckFilesBase)) {
1396
- import_node_fs3.default.rmSync(deckFilesBase, { recursive: true, force: true });
1397
- }
1398
- } else {
1399
- const sessionDir = import_node_path3.default.join(deckFilesBase, session);
1400
- if (import_node_fs3.default.existsSync(sessionDir)) {
1401
- import_node_fs3.default.rmSync(sessionDir, { recursive: true, force: true });
1402
- }
1403
- }
1564
+ deletePersistedSession(cwd, session);
1404
1565
  } catch {
1405
1566
  }
1406
1567
  jsonResponse(res, 200, { ok: true });
@@ -1515,13 +1676,6 @@ async function startDeckServer(opts = {}) {
1515
1676
  waiter.reject(new Error("LaunchDeck server shutting down"));
1516
1677
  pendingFeedback.delete(id);
1517
1678
  }
1518
- try {
1519
- const deckFilesBase = import_node_path3.default.join(cwd, LAUNCHSECURE_DIR, "deck-files");
1520
- if (import_node_fs3.default.existsSync(deckFilesBase)) {
1521
- import_node_fs3.default.rmSync(deckFilesBase, { recursive: true, force: true });
1522
- }
1523
- } catch {
1524
- }
1525
1679
  clearLock(cwd);
1526
1680
  server.close();
1527
1681
  };
File without changes