@launchsecure/launch-kit 0.0.26 → 0.0.28

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 (123) hide show
  1. package/dist/beacon/beacon.mjs +1003 -440
  2. package/dist/beacon/beacon.mjs.map +1 -1
  3. package/dist/beacon/beacon.umd.js +45 -24
  4. package/dist/beacon/beacon.umd.js.map +1 -1
  5. package/dist/beacon/types/capture/events.d.ts +20 -0
  6. package/dist/beacon/types/capture/events.d.ts.map +1 -0
  7. package/dist/beacon/types/element.d.ts +1 -0
  8. package/dist/beacon/types/element.d.ts.map +1 -1
  9. package/dist/beacon/types/index.d.ts +2 -1
  10. package/dist/beacon/types/index.d.ts.map +1 -1
  11. package/dist/beacon/types/monitor/dom.d.ts +13 -0
  12. package/dist/beacon/types/monitor/dom.d.ts.map +1 -0
  13. package/dist/beacon/types/monitor/index.d.ts +19 -0
  14. package/dist/beacon/types/monitor/index.d.ts.map +1 -0
  15. package/dist/beacon/types/monitor/network.d.ts +12 -0
  16. package/dist/beacon/types/monitor/network.d.ts.map +1 -0
  17. package/dist/beacon/types/monitor/transport.d.ts +27 -0
  18. package/dist/beacon/types/monitor/transport.d.ts.map +1 -0
  19. package/dist/beacon/types/monitor/types.d.ts +117 -0
  20. package/dist/beacon/types/monitor/types.d.ts.map +1 -0
  21. package/dist/beacon/types/types.d.ts +10 -0
  22. package/dist/beacon/types/types.d.ts.map +1 -1
  23. package/dist/beacon/types/ui/drawer.d.ts +3 -1
  24. package/dist/beacon/types/ui/drawer.d.ts.map +1 -1
  25. package/dist/beacon/types/ui/monitor-panel.d.ts +19 -0
  26. package/dist/beacon/types/ui/monitor-panel.d.ts.map +1 -0
  27. package/dist/chart-client/assets/index-CJ4mgRRF.css +1 -0
  28. package/dist/chart-client/assets/{index-Bk1hawjD.js → index-Ccy-DpI-.js} +46 -42
  29. package/dist/chart-client/index.html +2 -2
  30. package/dist/client/assets/index-DI5qSR_w.css +32 -0
  31. package/dist/client/assets/index-Dp0_okva.js +294 -0
  32. package/dist/client/index.html +2 -2
  33. package/dist/council-client/assets/index-C_-vAM9L.css +1 -0
  34. package/dist/council-client/index.html +2 -2
  35. package/dist/deck-client/assets/{_baseUniq-C2xT_eYu.js → _baseUniq-W2JQDmje.js} +1 -1
  36. package/dist/deck-client/assets/{arc-CmVL9pGd.js → arc-DIBWAId9.js} +1 -1
  37. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-BSFgdjve.js → architectureDiagram-Q4EWVU46-CAIRMvJK.js} +1 -1
  38. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-DuLzscvP.js → blockDiagram-DXYQGD6D-BeNaNiOi.js} +1 -1
  39. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CfCJB8eY.js → c4Diagram-AHTNJAMY-B9Ozi62h.js} +1 -1
  40. package/dist/deck-client/assets/channel-CRdozqbp.js +1 -0
  41. package/dist/deck-client/assets/{chunk-4BX2VUAB-DxmLYTWZ.js → chunk-4BX2VUAB-D7AZ47dt.js} +1 -1
  42. package/dist/deck-client/assets/{chunk-4TB4RGXK-CCnf7GFE.js → chunk-4TB4RGXK-DnVnNPcI.js} +1 -1
  43. package/dist/deck-client/assets/{chunk-55IACEB6-Db9DApcj.js → chunk-55IACEB6-UKYs-YNd.js} +1 -1
  44. package/dist/deck-client/assets/{chunk-EDXVE4YY-DmYDq8ZI.js → chunk-EDXVE4YY-D43b-SKn.js} +1 -1
  45. package/dist/deck-client/assets/{chunk-FMBD7UC4-BGhUlF20.js → chunk-FMBD7UC4-QzBAoyyW.js} +1 -1
  46. package/dist/deck-client/assets/{chunk-OYMX7WX6-CpEnicQZ.js → chunk-OYMX7WX6-Cjif4r6W.js} +1 -1
  47. package/dist/deck-client/assets/{chunk-QZHKN3VN-Doa7LKwf.js → chunk-QZHKN3VN-CqLDirEI.js} +1 -1
  48. package/dist/deck-client/assets/{chunk-YZCP3GAM-CpkIlH6V.js → chunk-YZCP3GAM-_FQvmMs4.js} +1 -1
  49. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-lIZMp57W.js +1 -0
  50. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-lIZMp57W.js +1 -0
  51. package/dist/deck-client/assets/clone-BtWeSTyJ.js +1 -0
  52. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-Bkh8Bfcb.js → cose-bilkent-S5V4N54A-rfrocesE.js} +1 -1
  53. package/dist/deck-client/assets/{dagre-KV5264BT-Bp0XpTgH.js → dagre-KV5264BT-Bv_7DJat.js} +1 -1
  54. package/dist/deck-client/assets/{diagram-5BDNPKRD-ZHiyGYPQ.js → diagram-5BDNPKRD-4F1414G5.js} +1 -1
  55. package/dist/deck-client/assets/{diagram-G4DWMVQ6-BW-Q8_H5.js → diagram-G4DWMVQ6-C4-Pszqm.js} +1 -1
  56. package/dist/deck-client/assets/{diagram-MMDJMWI5-6I3LTafu.js → diagram-MMDJMWI5-B647TIx9.js} +1 -1
  57. package/dist/deck-client/assets/{diagram-TYMM5635-CyM5YK28.js → diagram-TYMM5635-BFAqpezd.js} +1 -1
  58. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-CjNxVJHk.js → erDiagram-SMLLAGMA-BfBfrJOC.js} +1 -1
  59. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-BDQHuAJR.js → flowDiagram-DWJPFMVM-DX9YAYes.js} +1 -1
  60. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-B7MnkpbP.js → ganttDiagram-T4ZO3ILL-DCuiy7wF.js} +1 -1
  61. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-C9dZAcYD.js → gitGraphDiagram-UUTBAWPF-CGp1IXUh.js} +1 -1
  62. package/dist/deck-client/assets/{graph-CjdBnzUy.js → graph-B7g8aoxv.js} +1 -1
  63. package/dist/deck-client/assets/{index-DeIVPW63.js → index-Dg1r-WSN.js} +3 -3
  64. package/dist/deck-client/assets/index-DsIZ3LqL.css +1 -0
  65. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-C7d3iRC3.js → infoDiagram-42DDH7IO-L3fahMkF.js} +1 -1
  66. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-BcYGKj09.js → ishikawaDiagram-UXIWVN3A-aS_EjWBZ.js} +1 -1
  67. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-DqFlRrOL.js → journeyDiagram-VCZTEJTY-djTSQZF9.js} +1 -1
  68. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-BJhPp1NR.js → kanban-definition-6JOO6SKY-CcTHo4CM.js} +1 -1
  69. package/dist/deck-client/assets/{layout-DIeS6GvK.js → layout-mEJiadb7.js} +1 -1
  70. package/dist/deck-client/assets/{linear-He_yJy5H.js → linear-XgTKqyRu.js} +1 -1
  71. package/dist/deck-client/assets/{min-DQ6Kx06t.js → min-Ct9jZdpd.js} +1 -1
  72. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-sQ62L8T2.js → mindmap-definition-QFDTVHPH-BaFxCGNU.js} +1 -1
  73. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-BqCWmU2K.js → pieDiagram-DEJITSTG-CIbYYjtw.js} +1 -1
  74. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-rQ1TJOoe.js → quadrantDiagram-34T5L4WZ-D9EtCOvh.js} +1 -1
  75. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-BO2MPBOM.js → requirementDiagram-MS252O5E-xeni9eVG.js} +1 -1
  76. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BgsHEVex.js → sankeyDiagram-XADWPNL6-LYeknz9h.js} +1 -1
  77. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-B3j1yMLU.js → sequenceDiagram-FGHM5R23-RDbsKFZf.js} +1 -1
  78. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-C8jFlZou.js → stateDiagram-FHFEXIEX-BH1Zjglk.js} +1 -1
  79. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BrV78NDR.js +1 -0
  80. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-tM-qo4Zk.js → timeline-definition-GMOUNBTQ-IFXxKptt.js} +1 -1
  81. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-B0-6kOEu.js → vennDiagram-DHZGUBPP-D-sLkQs9.js} +1 -1
  82. package/dist/deck-client/assets/{wardley-RL74JXVD-HpBk07P-.js → wardley-RL74JXVD-C010F8l4.js} +1 -1
  83. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-BkA1NLDE.js → wardleyDiagram-NUSXRM2D-BTjjuDU3.js} +1 -1
  84. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CEKGSuI-.js → xychartDiagram-5P7HB3ND-AYbv92n-.js} +1 -1
  85. package/dist/deck-client/index.html +2 -2
  86. package/dist/server/beacon-monitor-entry.js +353 -0
  87. package/dist/server/chart-serve.js +3836 -3750
  88. package/dist/server/cli.js +8789 -8219
  89. package/dist/server/council-entry.js +17 -5
  90. package/dist/server/council-serve.js +8 -3
  91. package/dist/server/course-entry.js +246 -0
  92. package/dist/server/deck-mcp-entry.js +24 -12
  93. package/dist/server/deck-serve.js +11 -8
  94. package/dist/server/graph-mcp-entry.js +5005 -4865
  95. package/dist/server/init-entry.js +939 -0
  96. package/dist/server/orbit-entry.js +2435 -0
  97. package/dist/server/parse-worker-entry.js +4721 -0
  98. package/dist/server/recall-entry.js +356 -18
  99. package/package.json +11 -4
  100. package/scaffolds/ls-marketplace/.claude-plugin/marketplace.json +15 -0
  101. package/scaffolds/ls-marketplace/plugins/ls/.claude-plugin/plugin.json +28 -0
  102. package/scaffolds/ls-marketplace/plugins/ls/commands/activate-beacon.md +216 -0
  103. package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-array.md +92 -0
  104. package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-clear.md +68 -0
  105. package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-pulse.md +80 -0
  106. package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-scan.md +62 -0
  107. package/scaffolds/ls-marketplace/plugins/ls/commands/show-mcp-status.md +109 -0
  108. package/scaffolds/ls-marketplace/plugins/ls/commands/standup.md +177 -0
  109. package/scaffolds/migrate-safety/.github/workflows/backup-on-migration.yml +72 -0
  110. package/scaffolds/migrate-safety/docs/migrations-runbook.md +172 -0
  111. package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +294 -0
  112. package/scaffolds/recall-hook/scripts/ensure-recall.sh +69 -0
  113. package/dist/chart-client/assets/index-DpaGa3bY.css +0 -1
  114. package/dist/client/assets/index-Bfel4OQ5.css +0 -32
  115. package/dist/client/assets/index-eC-WuUWB.js +0 -291
  116. package/dist/council-client/assets/index-P5kMsT5a.css +0 -1
  117. package/dist/deck-client/assets/channel-B4aNO8ZB.js +0 -1
  118. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-BHTI0yWz.js +0 -1
  119. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-BHTI0yWz.js +0 -1
  120. package/dist/deck-client/assets/clone-HduFm7qU.js +0 -1
  121. package/dist/deck-client/assets/index-LKZDAS9S.css +0 -1
  122. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BoqepHW0.js +0 -1
  123. /package/dist/council-client/assets/{index-Cs_MVXHf.js → index-Dt4zWKSj.js} +0 -0
@@ -122,8 +122,8 @@ function loadConfig(workTree) {
122
122
  return { config: { ...DEFAULT_CONFIG }, source: "defaults", path: configPath };
123
123
  }
124
124
  try {
125
- const text = fs.readFileSync(configPath, "utf8");
126
- const raw = JSON.parse(text);
125
+ const text2 = fs.readFileSync(configPath, "utf8");
126
+ const raw = JSON.parse(text2);
127
127
  return { config: mergeConfig(raw), source: "file", path: configPath };
128
128
  } catch (err) {
129
129
  process.stderr.write(
@@ -259,14 +259,346 @@ var init_init = __esm({
259
259
  }
260
260
  });
261
261
 
262
+ // src/server/recall-mcp.ts
263
+ var recall_mcp_exports = {};
264
+ __export(recall_mcp_exports, {
265
+ startRecallMcpServer: () => startRecallMcpServer
266
+ });
267
+ function isPidAlive(pid) {
268
+ try {
269
+ process.kill(pid, 0);
270
+ return true;
271
+ } catch (err) {
272
+ const code = err.code;
273
+ if (code === "ESRCH") return false;
274
+ if (code === "EPERM") return true;
275
+ return false;
276
+ }
277
+ }
278
+ function pidFilePath(recallDir) {
279
+ return `${recallDir}/watch.pid`;
280
+ }
281
+ function existingWatcherPid() {
282
+ const { recallDir } = resolveRecallPaths();
283
+ const pf = pidFilePath(recallDir);
284
+ if (!(0, import_node_fs.existsSync)(pf)) return null;
285
+ const pid = Number((0, import_node_fs.readFileSync)(pf, "utf-8").trim());
286
+ if (!Number.isFinite(pid) || pid <= 0) return null;
287
+ return isPidAlive(pid) ? pid : null;
288
+ }
289
+ function ensureWatcher() {
290
+ const { gitDir, workTree } = resolveRecallPaths();
291
+ if (!(0, import_node_fs.existsSync)(gitDir)) {
292
+ process.stderr.write(
293
+ `[launch-recall mcp] shadow repo missing at ${gitDir} \u2014 run \`launch-recall init\` first. MCP tools will still serve read-only queries, but nothing will be captured.
294
+ `
295
+ );
296
+ return;
297
+ }
298
+ const existing = existingWatcherPid();
299
+ if (existing !== null) {
300
+ process.stderr.write(
301
+ `[launch-recall mcp] external watcher detected (pid ${existing}) \u2014 serving tools only, not spawning a sibling
302
+ `
303
+ );
304
+ return;
305
+ }
306
+ const entry = process.argv[1];
307
+ if (!entry) {
308
+ process.stderr.write(`[launch-recall mcp] cannot resolve entry path from argv \u2014 watcher not spawned
309
+ `);
310
+ return;
311
+ }
312
+ childWatcher = (0, import_node_child_process2.spawn)(process.execPath, [entry, "watch"], {
313
+ cwd: workTree,
314
+ stdio: ["ignore", "ignore", "inherit"],
315
+ detached: false
316
+ });
317
+ process.stderr.write(`[launch-recall mcp] spawned watcher (pid ${childWatcher.pid}) in ${workTree}
318
+ `);
319
+ childWatcher.on("exit", (code, sig) => {
320
+ process.stderr.write(`[launch-recall mcp] child watcher exited (code=${code} sig=${sig})
321
+ `);
322
+ childWatcher = null;
323
+ });
324
+ }
325
+ function killChildWatcher() {
326
+ if (childWatcher && !childWatcher.killed) {
327
+ try {
328
+ childWatcher.kill("SIGTERM");
329
+ } catch {
330
+ }
331
+ }
332
+ }
333
+ function text(payload) {
334
+ const t = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2);
335
+ return { content: [{ type: "text", text: t }] };
336
+ }
337
+ async function handleTool(name, args) {
338
+ switch (name) {
339
+ case "recall.doctor":
340
+ return text(doctorTool());
341
+ case "recall.report":
342
+ return text(reportTool());
343
+ case "recall.status":
344
+ return text(statusTool());
345
+ case "recall.history": {
346
+ const path7 = String(args.path ?? "");
347
+ if (!path7) return text({ error: "path is required" });
348
+ const limit = typeof args.limit === "number" && args.limit > 0 ? Math.floor(args.limit) : 50;
349
+ return text(historyTool(path7, limit));
350
+ }
351
+ default:
352
+ return text({ error: `unknown tool: ${name}` });
353
+ }
354
+ }
355
+ function doctorTool() {
356
+ const { gitDir, recallDir } = resolveRecallPaths();
357
+ const checks = [];
358
+ const shadowOk = (0, import_node_fs.existsSync)(gitDir);
359
+ checks.push({
360
+ name: "shadow_repo",
361
+ ok: shadowOk,
362
+ detail: shadowOk ? gitDir : `missing \u2014 run \`launch-recall init\``
363
+ });
364
+ const pid = existingWatcherPid();
365
+ checks.push({
366
+ name: "watcher_alive",
367
+ ok: pid !== null,
368
+ detail: pid !== null ? `pid ${pid}` : `no live pid in ${pidFilePath(recallDir)}`
369
+ });
370
+ let recentOk = false;
371
+ let recentDetail = "no snapshots yet";
372
+ if (shadowOk) {
373
+ try {
374
+ const out = (0, import_node_child_process2.execFileSync)("git", [`--git-dir=${gitDir}`, "log", "-1", "--format=%aI"], {
375
+ encoding: "utf-8",
376
+ stdio: ["ignore", "pipe", "pipe"]
377
+ }).trim();
378
+ if (out) {
379
+ const ageHours = (Date.now() - new Date(out).getTime()) / 36e5;
380
+ recentOk = ageHours < 24;
381
+ recentDetail = `${out} (${ageHours.toFixed(1)}h ago)`;
382
+ }
383
+ } catch {
384
+ }
385
+ }
386
+ checks.push({ name: "recent_snapshot", ok: recentOk, detail: recentDetail });
387
+ return { ok: checks.every((c) => c.ok), checks };
388
+ }
389
+ function reportTool() {
390
+ const { gitDir, recallDir, workTree } = resolveRecallPaths();
391
+ if (!(0, import_node_fs.existsSync)(gitDir)) return { error: "shadow repo not initialised" };
392
+ let totalSnapshots = 0;
393
+ try {
394
+ const out = (0, import_node_child_process2.execFileSync)("git", [`--git-dir=${gitDir}`, "rev-list", "--count", "HEAD"], {
395
+ encoding: "utf-8",
396
+ stdio: ["ignore", "pipe", "pipe"]
397
+ }).trim();
398
+ totalSnapshots = Number(out) || 0;
399
+ } catch {
400
+ }
401
+ let shadowSizeBytes = 0;
402
+ try {
403
+ const out = (0, import_node_child_process2.execFileSync)("du", ["-sk", recallDir], { encoding: "utf-8" }).trim();
404
+ const kb = Number(out.split(/\s+/)[0]);
405
+ if (Number.isFinite(kb)) shadowSizeBytes = kb * 1024;
406
+ } catch {
407
+ }
408
+ const recentSnapshots = [];
409
+ let lastSnapshot = null;
410
+ try {
411
+ const out = (0, import_node_child_process2.execFileSync)(
412
+ "git",
413
+ [`--git-dir=${gitDir}`, "log", "-10", "--format=%H|%aI|%s"],
414
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
415
+ );
416
+ for (const line of out.split("\n").filter(Boolean)) {
417
+ const [sha, ts, ...rest] = line.split("|");
418
+ recentSnapshots.push({ sha, ts, message: rest.join("|") });
419
+ }
420
+ if (recentSnapshots.length > 0) lastSnapshot = recentSnapshots[0].ts;
421
+ } catch {
422
+ }
423
+ let config = null;
424
+ const cfgPath = `${workTree}/.launch-recall.json`;
425
+ if ((0, import_node_fs.existsSync)(cfgPath)) {
426
+ try {
427
+ config = JSON.parse((0, import_node_fs.readFileSync)(cfgPath, "utf-8"));
428
+ } catch {
429
+ }
430
+ }
431
+ return { totalSnapshots, shadowSizeBytes, lastSnapshot, recentSnapshots, config, workTree };
432
+ }
433
+ function historyTool(path7, limit) {
434
+ const { gitDir, workTree } = resolveRecallPaths();
435
+ if (!(0, import_node_fs.existsSync)(gitDir)) return { error: "shadow repo not initialised", path: path7, snapshots: [] };
436
+ const rel = path7.startsWith("/") ? path7.replace(`${workTree}/`, "").replace(/^\/+/, "") : path7;
437
+ const snapshots = [];
438
+ try {
439
+ const out = (0, import_node_child_process2.execFileSync)(
440
+ "git",
441
+ [`--git-dir=${gitDir}`, `--work-tree=${workTree}`, "log", `-${limit}`, "--format=%H|%aI|%s", "--", rel],
442
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
443
+ );
444
+ for (const line of out.split("\n").filter(Boolean)) {
445
+ const [sha, ts, ...rest] = line.split("|");
446
+ snapshots.push({ sha, ts, message: rest.join("|") });
447
+ }
448
+ } catch {
449
+ }
450
+ return { path: rel, snapshots };
451
+ }
452
+ function statusTool() {
453
+ const { gitDir, workTree } = resolveRecallPaths();
454
+ const pid = existingWatcherPid();
455
+ let lastSnapshotAt = null;
456
+ if ((0, import_node_fs.existsSync)(gitDir)) {
457
+ try {
458
+ lastSnapshotAt = (0, import_node_child_process2.execFileSync)("git", [`--git-dir=${gitDir}`, "log", "-1", "--format=%aI"], {
459
+ encoding: "utf-8",
460
+ stdio: ["ignore", "pipe", "pipe"]
461
+ }).trim() || null;
462
+ } catch {
463
+ }
464
+ }
465
+ return {
466
+ running: pid !== null,
467
+ pid,
468
+ lastSnapshotAt,
469
+ watchTree: workTree,
470
+ shadowRepo: gitDir
471
+ };
472
+ }
473
+ function send(msg) {
474
+ process.stdout.write(JSON.stringify(msg) + "\n");
475
+ }
476
+ function sendResponse(id, result) {
477
+ send({ jsonrpc: "2.0", id, result });
478
+ }
479
+ function sendError(id, code, message) {
480
+ send({ jsonrpc: "2.0", id, error: { code, message } });
481
+ }
482
+ async function handleMessage(parsed) {
483
+ const id = parsed.id;
484
+ const method = parsed.method;
485
+ const params = parsed.params ?? {};
486
+ switch (method) {
487
+ case "initialize":
488
+ sendResponse(id ?? null, {
489
+ protocolVersion: "2024-11-05",
490
+ capabilities: { tools: {} },
491
+ serverInfo: SERVER_INFO
492
+ });
493
+ break;
494
+ case "notifications/initialized":
495
+ break;
496
+ case "tools/list":
497
+ sendResponse(id ?? null, { tools: TOOLS });
498
+ break;
499
+ case "tools/call": {
500
+ const toolName = params.name;
501
+ const toolArgs = params.arguments ?? {};
502
+ try {
503
+ const result = await handleTool(toolName, toolArgs);
504
+ sendResponse(id ?? null, result);
505
+ } catch (err) {
506
+ sendError(id ?? null, -32603, `Tool error: ${err.message}`);
507
+ }
508
+ break;
509
+ }
510
+ case "ping":
511
+ sendResponse(id ?? null, {});
512
+ break;
513
+ default:
514
+ if (id !== void 0) sendError(id ?? null, -32601, `Method not found: ${method}`);
515
+ }
516
+ }
517
+ function startRecallMcpServer() {
518
+ process.stderr.write("[launch-recall mcp] starting on stdio\n");
519
+ ensureWatcher();
520
+ const teardown = () => {
521
+ killChildWatcher();
522
+ process.exit(0);
523
+ };
524
+ process.on("SIGTERM", teardown);
525
+ process.on("SIGINT", teardown);
526
+ process.on("exit", killChildWatcher);
527
+ process.stdin.setEncoding("utf-8");
528
+ let buffer = "";
529
+ process.stdin.on("data", (chunk) => {
530
+ buffer += chunk;
531
+ const lines = buffer.split("\n");
532
+ buffer = lines.pop() || "";
533
+ for (const line of lines) {
534
+ const trimmed = line.trim();
535
+ if (!trimmed) continue;
536
+ try {
537
+ handleMessage(JSON.parse(trimmed)).catch((err) => {
538
+ process.stderr.write(`[launch-recall mcp] message error: ${err}
539
+ `);
540
+ });
541
+ } catch (err) {
542
+ process.stderr.write(`[launch-recall mcp] parse error: ${err}
543
+ `);
544
+ }
545
+ }
546
+ });
547
+ process.stdin.on("end", () => {
548
+ process.stderr.write("[launch-recall mcp] stdin closed, exiting\n");
549
+ teardown();
550
+ });
551
+ void import_node_fs.statSync;
552
+ }
553
+ var import_node_child_process2, import_node_fs, SERVER_INFO, TOOLS, childWatcher;
554
+ var init_recall_mcp = __esm({
555
+ "src/server/recall-mcp.ts"() {
556
+ "use strict";
557
+ import_node_child_process2 = require("node:child_process");
558
+ import_node_fs = require("node:fs");
559
+ init_paths();
560
+ SERVER_INFO = { name: "launch-recall", version: "0.0.1" };
561
+ TOOLS = [
562
+ {
563
+ name: "recall.doctor",
564
+ description: "Health check on the launch-recall watcher and its shadow repo.\n\nReturns: { ok, checks: [{ name, ok, detail }] }. Names: shadow_repo (exists + valid), watcher_alive (pid file points at live pid), recent_snapshot (any snapshot within 24h).",
565
+ inputSchema: { type: "object", properties: {} }
566
+ },
567
+ {
568
+ name: "recall.report",
569
+ description: "Project-wide details on what recall has captured.\n\nReturns: { totalSnapshots, shadowSizeBytes, lastSnapshot, recentSnapshots: [{ sha, ts, message }], config: { debounce, ignore, retention } }. recentSnapshots is the last 10.",
570
+ inputSchema: { type: "object", properties: {} }
571
+ },
572
+ {
573
+ name: "recall.history",
574
+ description: "Snapshot history for a specific file or directory. Path is relative to the project root (or an absolute path under it).\n\nReturns: { path, snapshots: [{ sha, ts, message }] }. Empty array if the path was never captured (e.g. ignored, or simply has no churn).",
575
+ inputSchema: {
576
+ type: "object",
577
+ properties: {
578
+ path: { type: "string", description: "File or directory to query." },
579
+ limit: { type: "number", description: "Max snapshots to return (default 50)." }
580
+ },
581
+ required: ["path"]
582
+ }
583
+ },
584
+ {
585
+ name: "recall.status",
586
+ description: "Quick liveness + last-snapshot info. Cheaper than recall.doctor \u2014 no historical inspection.\n\nReturns: { running, pid, lastSnapshotAt, watchTree }.",
587
+ inputSchema: { type: "object", properties: {} }
588
+ }
589
+ ];
590
+ childWatcher = null;
591
+ }
592
+ });
593
+
262
594
  // src/server/recall/stop.ts
263
595
  var stop_exports = {};
264
596
  __export(stop_exports, {
265
- pidFilePath: () => pidFilePath,
597
+ pidFilePath: () => pidFilePath2,
266
598
  runStop: () => runStop,
267
599
  stopWatcher: () => stopWatcher
268
600
  });
269
- function pidFilePath(recallDir) {
601
+ function pidFilePath2(recallDir) {
270
602
  return path4.join(recallDir, "watch.pid");
271
603
  }
272
604
  function isAlive(pid) {
@@ -285,7 +617,7 @@ function sleep(ms) {
285
617
  }
286
618
  async function stopWatcher(quiet = false) {
287
619
  const { recallDir } = resolveRecallPaths();
288
- const pf = pidFilePath(recallDir);
620
+ const pf = pidFilePath2(recallDir);
289
621
  if (!fs3.existsSync(pf)) {
290
622
  if (!quiet) process.stderr.write(`[launch-recall] no PID file at ${pf}
291
623
  `);
@@ -353,7 +685,7 @@ var watch_exports = {};
353
685
  __export(watch_exports, {
354
686
  runWatch: () => runWatch
355
687
  });
356
- function isPidAlive(pid) {
688
+ function isPidAlive2(pid) {
357
689
  try {
358
690
  process.kill(pid, 0);
359
691
  return true;
@@ -385,10 +717,10 @@ async function runWatch(args) {
385
717
  log(`not initialised \u2014 run: launch-recall init`);
386
718
  process.exit(1);
387
719
  }
388
- const pf = pidFilePath(recallDir);
720
+ const pf = pidFilePath2(recallDir);
389
721
  if (fs4.existsSync(pf)) {
390
722
  const existing = Number(fs4.readFileSync(pf, "utf8").trim());
391
- if (Number.isFinite(existing) && isPidAlive(existing)) {
723
+ if (Number.isFinite(existing) && isPidAlive2(existing)) {
392
724
  log(`watcher already running (pid ${existing}) \u2014 run \`launch-recall stop\` first`);
393
725
  process.exit(1);
394
726
  }
@@ -426,7 +758,7 @@ async function runWatch(args) {
426
758
  return;
427
759
  }
428
760
  busy = true;
429
- const add = (0, import_node_child_process2.spawn)("git", addArgs, { env, stdio: "ignore" });
761
+ const add = (0, import_node_child_process3.spawn)("git", addArgs, { env, stdio: "ignore" });
430
762
  add.on("exit", (addCode) => {
431
763
  if (addCode !== 0) {
432
764
  busy = false;
@@ -436,7 +768,7 @@ async function runWatch(args) {
436
768
  }
437
769
  return;
438
770
  }
439
- const check = (0, import_node_child_process2.spawn)("git", ["diff", "--cached", "--quiet"], { env, stdio: "ignore" });
771
+ const check = (0, import_node_child_process3.spawn)("git", ["diff", "--cached", "--quiet"], { env, stdio: "ignore" });
440
772
  check.on("exit", (checkCode) => {
441
773
  if (checkCode === 0) {
442
774
  busy = false;
@@ -446,7 +778,7 @@ async function runWatch(args) {
446
778
  }
447
779
  return;
448
780
  }
449
- const commit = (0, import_node_child_process2.spawn)(
781
+ const commit = (0, import_node_child_process3.spawn)(
450
782
  "git",
451
783
  ["commit", "-q", "-m", `snap ${stamp()}`],
452
784
  { env, stdio: "ignore" }
@@ -492,13 +824,13 @@ async function runWatch(args) {
492
824
  process.exit(1);
493
825
  }
494
826
  }
495
- var fs4, fsp, import_node_child_process2;
827
+ var fs4, fsp, import_node_child_process3;
496
828
  var init_watch = __esm({
497
829
  "src/server/recall/watch.ts"() {
498
830
  "use strict";
499
831
  fs4 = __toESM(require("node:fs"));
500
832
  fsp = __toESM(require("node:fs/promises"));
501
- import_node_child_process2 = require("node:child_process");
833
+ import_node_child_process3 = require("node:child_process");
502
834
  init_git();
503
835
  init_paths();
504
836
  init_config();
@@ -930,8 +1262,8 @@ function promptYesNo(question) {
930
1262
  }
931
1263
  function removeGitignoreLine(gitignorePath) {
932
1264
  if (!fs10.existsSync(gitignorePath)) return "no-file";
933
- const text = fs10.readFileSync(gitignorePath, "utf8");
934
- const lines = text.split(/\r?\n/);
1265
+ const text2 = fs10.readFileSync(gitignorePath, "utf8");
1266
+ const lines = text2.split(/\r?\n/);
935
1267
  const matches = (l) => {
936
1268
  const t = l.trim();
937
1269
  return t === `/${RECALL_DIR_NAME}/` || t === `${RECALL_DIR_NAME}/` || t === RECALL_DIR_NAME || t === `/${RECALL_DIR_NAME}` || t === `${RECALL_DIR_NAME}/**`;
@@ -946,15 +1278,15 @@ async function runUninstall(args) {
946
1278
  const { workTree, recallDir } = resolveRecallPaths();
947
1279
  const configPath = path6.join(workTree, CONFIG_FILENAME);
948
1280
  const gitignorePath = path6.join(workTree, ".gitignore");
949
- const pf = pidFilePath(recallDir);
1281
+ const pf = pidFilePath2(recallDir);
950
1282
  const watcherRunning = fs10.existsSync(pf);
951
1283
  const shadowPresent = fs10.existsSync(recallDir);
952
1284
  const configPresent = fs10.existsSync(configPath);
953
1285
  const shadowSize = shadowPresent ? dirSizeBytes(recallDir) : 0;
954
1286
  let gitignoreHasLine = false;
955
1287
  if (fs10.existsSync(gitignorePath)) {
956
- const text = fs10.readFileSync(gitignorePath, "utf8");
957
- gitignoreHasLine = text.split(/\r?\n/).some((l) => {
1288
+ const text2 = fs10.readFileSync(gitignorePath, "utf8");
1289
+ gitignoreHasLine = text2.split(/\r?\n/).some((l) => {
958
1290
  const t = l.trim();
959
1291
  return t === `/${RECALL_DIR_NAME}/` || t === `${RECALL_DIR_NAME}/` || t === RECALL_DIR_NAME || t === `/${RECALL_DIR_NAME}` || t === `${RECALL_DIR_NAME}/**`;
960
1292
  });
@@ -1034,6 +1366,7 @@ function printUsage() {
1034
1366
  " init create .recall/repo.git + gitignore entry + default config",
1035
1367
  " watch [--debounce <ms>] foreground watcher (defaults from .launch-recall.json)",
1036
1368
  " stop terminate the running watcher",
1369
+ " mcp stdio MCP server (spawns watcher as child)",
1037
1370
  " log [path] show shadow history (passthrough to git log)",
1038
1371
  " restore <path> [--at <ref>] extract a file from a snapshot",
1039
1372
  " forget [--keep-last N] [--max-age 30d] [--dry-run]",
@@ -1059,6 +1392,11 @@ async function main() {
1059
1392
  await runInit2(argv.slice(1));
1060
1393
  return;
1061
1394
  }
1395
+ case "mcp": {
1396
+ const { startRecallMcpServer: startRecallMcpServer2 } = await Promise.resolve().then(() => (init_recall_mcp(), recall_mcp_exports));
1397
+ startRecallMcpServer2();
1398
+ return;
1399
+ }
1062
1400
  case "watch": {
1063
1401
  const { runWatch: runWatch2 } = await Promise.resolve().then(() => (init_watch(), watch_exports));
1064
1402
  await runWatch2(argv.slice(1));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchsecure/launch-kit",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "LaunchSecure toolkit — launch-pod (pipeline), launch-chart (project graph MCP), launch-deck (visual playground MCP), launch-kit-beacon (feedback Web Component), launch-recall (file-watcher backup).",
5
5
  "license": "MIT",
6
6
  "author": "LaunchSecure - AutomateWithUs",
@@ -47,20 +47,26 @@
47
47
  "access": "public"
48
48
  },
49
49
  "bin": {
50
+ "launch-kit": "./dist/server/init-entry.js",
50
51
  "launch-pod": "./dist/server/cli.js",
51
52
  "launch-chart": "./dist/server/graph-mcp-entry.js",
52
53
  "launch-deck": "./dist/server/deck-mcp-entry.js",
53
- "launch-recall": "./dist/server/recall-entry.js"
54
+ "launch-recall": "./dist/server/recall-entry.js",
55
+ "launch-orbit": "./dist/server/orbit-entry.js",
56
+ "launch-course": "./dist/server/course-entry.js",
57
+ "launch-beacon": "./dist/server/beacon-monitor-entry.js"
54
58
  },
55
59
  "files": [
56
60
  "dist",
57
- "prompts"
61
+ "prompts",
62
+ "scaffolds"
58
63
  ],
59
64
  "dependencies": {
60
65
  "cacheable-lookup": "^7.0.0",
61
66
  "cloudflared": "^0.7.1",
62
67
  "html-to-image": "^1.11.13",
63
68
  "node-pty": "^1.2.0-beta.12",
69
+ "pg": "^8.13.0",
64
70
  "tree-sitter": "^0.21.1",
65
71
  "tree-sitter-typescript": "^0.23.2",
66
72
  "typescript": "^5.5.0",
@@ -70,6 +76,7 @@
70
76
  },
71
77
  "devDependencies": {
72
78
  "@types/node": "^20.0.0",
79
+ "@types/pg": "^8.11.10",
73
80
  "@types/react": "^18.3.12",
74
81
  "@types/react-dom": "^18.3.1",
75
82
  "@types/ws": "^8.5.10",
@@ -105,7 +112,7 @@
105
112
  "build:council-client": "vite build --config vite.council.config.ts",
106
113
  "build:client": "vite build",
107
114
  "build:chart-client": "vite build --config vite.chart.config.ts",
108
- "build:server": "esbuild src/server/cli.ts src/server/fb-wizard.ts src/server/graph-mcp-entry.ts src/server/chart-serve.ts src/server/deck-mcp-entry.ts src/server/deck-serve.ts src/server/council-entry.ts src/server/council-serve.ts src/server/recall-entry.ts --bundle --platform=node --target=node18 --outdir=dist/server --external:node-pty --external:ws --external:typescript --external:web-tree-sitter --external:tree-sitter-typescript --external:cloudflared && rm -rf dist/server/public && cp -r ../claude-code-web/src/public dist/server/public && rm -rf dist/server/graph/queries && mkdir -p dist/server/graph && cp -r src/server/graph/queries dist/server/graph/queries",
115
+ "build:server": "esbuild src/server/cli.ts src/server/fb-wizard.ts src/server/graph-mcp-entry.ts src/server/chart-serve.ts src/server/deck-mcp-entry.ts src/server/deck-serve.ts src/server/council-entry.ts src/server/council-serve.ts src/server/recall-entry.ts src/server/init-entry.ts src/server/orbit-entry.ts src/server/course-entry.ts src/server/beacon-monitor-entry.ts src/server/parse-worker-entry.ts --bundle --platform=node --target=node18 --outdir=dist/server --external:node-pty --external:ws --external:typescript --external:web-tree-sitter --external:tree-sitter-typescript --external:cloudflared --external:pg --external:pg-native && rm -rf dist/server/public && cp -r ../claude-code-web/src/public dist/server/public && rm -rf dist/server/graph/queries && mkdir -p dist/server/graph && cp -r src/server/graph/queries dist/server/graph/queries",
109
116
  "dev:client": "vite",
110
117
  "dev:chart": "pnpm build:server && pnpm build:chart-client && node dist/server/graph-mcp-entry.js serve",
111
118
  "dev:server": "pnpm build:server && node dist/server/cli.js",
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "launchsecure",
3
+ "description": "LaunchSecure plugins for Claude Code — in-app feedback widget activation, and future LS-namespaced workflows. Distributed locally via launch-kit init today; the same catalog will move to github.com/launchsecure/claude-plugins for centralized updates.",
4
+ "owner": {
5
+ "name": "LaunchSecure — AutomateWithUs",
6
+ "email": "hello@automatewith.us"
7
+ },
8
+ "plugins": [
9
+ {
10
+ "name": "ls",
11
+ "source": "./plugins/ls",
12
+ "description": "LS-namespaced slash commands. Exposes /ls:activate-beacon to wire the launch-kit-beacon in-app feedback widget into the current project."
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "ls",
3
+ "version": "0.1.0",
4
+ "description": "LaunchSecure commands for Claude Code — in-app feedback widget activation, daily standups posted to the Comm Hub, and future LS-namespaced workflows.",
5
+ "author": {
6
+ "name": "LaunchSecure — AutomateWithUs",
7
+ "url": "https://automatewith.us"
8
+ },
9
+ "repository": "https://github.com/launchsecure/launchsecure-v2",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "launchsecure",
13
+ "launch-kit",
14
+ "launch-kit-beacon",
15
+ "feedback",
16
+ "standup",
17
+ "daily-update"
18
+ ],
19
+ "commands": [
20
+ "./commands/activate-beacon.md",
21
+ "./commands/standup.md",
22
+ "./commands/show-mcp-status.md",
23
+ "./commands/beacon-scan.md",
24
+ "./commands/beacon-pulse.md",
25
+ "./commands/beacon-array.md",
26
+ "./commands/beacon-clear.md"
27
+ ]
28
+ }