@launchsecure/launch-kit 0.0.38 → 0.0.40

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 (101) hide show
  1. package/dist/beacon/beacon.mjs +308 -298
  2. package/dist/beacon/beacon.mjs.map +1 -1
  3. package/dist/beacon/beacon.umd.js +6 -6
  4. package/dist/beacon/beacon.umd.js.map +1 -1
  5. package/dist/beacon/types/internal/screenshot.d.ts.map +1 -1
  6. package/dist/chart-client/assets/index-CWJFFDPu.css +1 -0
  7. package/dist/chart-client/index.html +2 -2
  8. package/dist/client/assets/index-CTzFcfGV.css +32 -0
  9. package/dist/client/index.html +2 -2
  10. package/dist/council-client/assets/index-ArgRc5mN.css +1 -0
  11. package/dist/council-client/index.html +2 -2
  12. package/dist/deck-client/assets/{_baseUniq-CgW32Gdk.js → _baseUniq-BZP7n41F.js} +1 -1
  13. package/dist/deck-client/assets/{arc-D-Mg9gvM.js → arc-31biU3Az.js} +1 -1
  14. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-CdTsXsgl.js → architectureDiagram-Q4EWVU46-DHg6Ss--.js} +1 -1
  15. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-mwTneYyB.js → blockDiagram-DXYQGD6D-CUdblaWk.js} +1 -1
  16. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-C4R8IbjO.js → c4Diagram-AHTNJAMY-MfAO5lak.js} +1 -1
  17. package/dist/deck-client/assets/channel-BBkRLdnC.js +1 -0
  18. package/dist/deck-client/assets/{chunk-4BX2VUAB-ZWuRIUwb.js → chunk-4BX2VUAB-DQ1MrGgN.js} +1 -1
  19. package/dist/deck-client/assets/{chunk-4TB4RGXK-PNHX10sF.js → chunk-4TB4RGXK-BUJtZ7jO.js} +1 -1
  20. package/dist/deck-client/assets/{chunk-55IACEB6-CD9MUgPr.js → chunk-55IACEB6-BdSnXB6g.js} +1 -1
  21. package/dist/deck-client/assets/{chunk-EDXVE4YY-C_CpORb3.js → chunk-EDXVE4YY-94yZIUI8.js} +1 -1
  22. package/dist/deck-client/assets/{chunk-FMBD7UC4-Bg5RoVC-.js → chunk-FMBD7UC4-PnZ9v6ey.js} +1 -1
  23. package/dist/deck-client/assets/{chunk-OYMX7WX6-DhTwgQwd.js → chunk-OYMX7WX6-DXrWNOsV.js} +1 -1
  24. package/dist/deck-client/assets/{chunk-QZHKN3VN-C5VLMaFa.js → chunk-QZHKN3VN-CsIGIDKX.js} +1 -1
  25. package/dist/deck-client/assets/{chunk-YZCP3GAM-NAGHy4Sr.js → chunk-YZCP3GAM-DVkBO9tn.js} +1 -1
  26. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-DFCaeF-7.js +1 -0
  27. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-DFCaeF-7.js +1 -0
  28. package/dist/deck-client/assets/clone-GCEVRScB.js +1 -0
  29. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-CpUczjZk.js → cose-bilkent-S5V4N54A-m126Oh3b.js} +1 -1
  30. package/dist/deck-client/assets/{dagre-KV5264BT-BOvb07MG.js → dagre-KV5264BT-C2aig8U5.js} +1 -1
  31. package/dist/deck-client/assets/{diagram-5BDNPKRD-BPxwTiC-.js → diagram-5BDNPKRD-CKpoRfGn.js} +1 -1
  32. package/dist/deck-client/assets/{diagram-G4DWMVQ6-Dz_gsHgx.js → diagram-G4DWMVQ6-Cjh115Ep.js} +1 -1
  33. package/dist/deck-client/assets/{diagram-MMDJMWI5-B7z-oVTW.js → diagram-MMDJMWI5-DKlBv_2L.js} +1 -1
  34. package/dist/deck-client/assets/{diagram-TYMM5635-CAIAglLQ.js → diagram-TYMM5635-CdBh4cEn.js} +1 -1
  35. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-BiViTWF3.js → erDiagram-SMLLAGMA-56pn_93p.js} +1 -1
  36. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-DYVemp0H.js → flowDiagram-DWJPFMVM-BtV3M5xJ.js} +1 -1
  37. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-Chc1Iyu1.js → ganttDiagram-T4ZO3ILL-DTIsC6Zg.js} +1 -1
  38. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-B7eFgaj5.js → gitGraphDiagram-UUTBAWPF-CJYeyCLe.js} +1 -1
  39. package/dist/deck-client/assets/{graph-CKaIoNwb.js → graph-BDvMu1Ss.js} +1 -1
  40. package/dist/deck-client/assets/index-D4eSxcBn.css +1 -0
  41. package/dist/deck-client/assets/{index-BRawc7RA.js → index-QnGVE9PZ.js} +83 -83
  42. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-BxsVq7vO.js → infoDiagram-42DDH7IO-BWyKJnpW.js} +1 -1
  43. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DAM7vPwa.js → ishikawaDiagram-UXIWVN3A-DXYkdO3T.js} +1 -1
  44. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-Xe20Nf7R.js → journeyDiagram-VCZTEJTY-C2zBr-J5.js} +1 -1
  45. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-DS8YguzB.js → kanban-definition-6JOO6SKY-CdoYLS4Z.js} +1 -1
  46. package/dist/deck-client/assets/{layout-DKMBpzR-.js → layout-vOnxnCQU.js} +1 -1
  47. package/dist/deck-client/assets/{linear-DTNtBg5h.js → linear-B0J0WCGz.js} +1 -1
  48. package/dist/deck-client/assets/{min-C4DrxCcA.js → min-B0AXlT9L.js} +1 -1
  49. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-B4nEtsw5.js → mindmap-definition-QFDTVHPH-oAybLedr.js} +1 -1
  50. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-BzHdGNu5.js → pieDiagram-DEJITSTG-BjHyHxGk.js} +1 -1
  51. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-CaX0SD4-.js → quadrantDiagram-34T5L4WZ-dtluDZXs.js} +1 -1
  52. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-QeG4p2ni.js → requirementDiagram-MS252O5E-Cq8l7bOl.js} +1 -1
  53. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BoAwgAj-.js → sankeyDiagram-XADWPNL6-C1Vih91z.js} +1 -1
  54. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-Dn4pYYgu.js → sequenceDiagram-FGHM5R23-CYkd7oQK.js} +1 -1
  55. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-Is6KRmQV.js → stateDiagram-FHFEXIEX-CtyG8wBK.js} +1 -1
  56. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BLyKWfcN.js +1 -0
  57. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-v64IZGuY.js → timeline-definition-GMOUNBTQ-DZIxSyd1.js} +1 -1
  58. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-noh9eouF.js → vennDiagram-DHZGUBPP-Ct4JVRDM.js} +1 -1
  59. package/dist/deck-client/assets/{wardley-RL74JXVD-cJ_1is2S.js → wardley-RL74JXVD-V29ycxOW.js} +1 -1
  60. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-DxR4j737.js → wardleyDiagram-NUSXRM2D-D-Ua6Cmi.js} +1 -1
  61. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-B26vodaL.js → xychartDiagram-5P7HB3ND-BPCOuRVl.js} +1 -1
  62. package/dist/deck-client/index.html +2 -2
  63. package/dist/server/beacon-monitor-entry.js +106 -24
  64. package/dist/server/chart-serve.js +544 -247
  65. package/dist/server/cli.js +743 -324
  66. package/dist/server/council-entry.js +16 -3
  67. package/dist/server/council-serve.js +15 -2
  68. package/dist/server/deck-mcp-entry.js +270 -108
  69. package/dist/server/deck-serve.js +101 -23
  70. package/dist/server/fb-wizard.js +0 -0
  71. package/dist/server/graph-mcp-entry.js +866 -357
  72. package/dist/server/init-entry.js +152 -25
  73. package/dist/server/orbit-entry.js +91 -7
  74. package/dist/server/radar-docker-init-entry.js +0 -0
  75. package/dist/server/radar-entrypoint-entry.js +0 -0
  76. package/dist/server/radar-teardown-entry.js +0 -0
  77. package/dist/server/recall-entry.js +94 -12
  78. package/dist/server/rover-entry.js +44 -1
  79. package/package.json +23 -22
  80. package/scaffolds/ls-marketplace/plugins/kit/commands/activate-statusline.md +8 -7
  81. package/scaffolds/ls-marketplace/plugins/kit/commands/deactivate-statusline.md +2 -2
  82. package/scaffolds/ls-marketplace/plugins/kit/skills/comms/SKILL.md +88 -0
  83. package/scaffolds/ls-marketplace/plugins/kit/skills/project-info/SKILL.md +88 -0
  84. package/scaffolds/ls-marketplace/plugins/kit/skills/slides/SKILL.md +118 -0
  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/scaffolds/statusline/statusline-base.sh +20 -0
  88. package/scaffolds/statusline/statusline-mcp.sh +68 -19
  89. package/scaffolds/statusline/statusline-wrapper.sh +12 -9
  90. package/dist/chart-client/assets/index-B6rR0CWx.css +0 -1
  91. package/dist/client/assets/index-D6uX1lQe.css +0 -32
  92. package/dist/council-client/assets/index-CleYLarJ.css +0 -1
  93. package/dist/deck-client/assets/channel-CuSee7GO.js +0 -1
  94. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-_kTisqzs.js +0 -1
  95. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-_kTisqzs.js +0 -1
  96. package/dist/deck-client/assets/clone-kb3zkY60.js +0 -1
  97. package/dist/deck-client/assets/index-55P73aS_.css +0 -1
  98. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-Cy45Ttqq.js +0 -1
  99. /package/dist/chart-client/assets/{index-C_xCi3gW.js → index-Dzlj-oCj.js} +0 -0
  100. /package/dist/client/assets/{index-CRecYFUA.js → index-tTg_ezUF.js} +0 -0
  101. /package/dist/council-client/assets/{index-DO-Vn15O.js → index-B1v46vTE.js} +0 -0
@@ -274,6 +274,11 @@ function writeScripts() {
274
274
  fs4.writeFileSync(WRAPPER_PATH, readScaffold("statusline-wrapper.sh"), { mode: 493 });
275
275
  fs4.writeFileSync(CHIP_PATH, readScaffold("statusline-mcp.sh"), { mode: 493 });
276
276
  }
277
+ function writeBaseScript() {
278
+ fs4.mkdirSync(LK_DIR, { recursive: true });
279
+ fs4.writeFileSync(BASE_PATH, readScaffold("statusline-base.sh"), { mode: 493 });
280
+ return `bash ${BASE_PATH}`;
281
+ }
277
282
  function wrapperCommand(opts) {
278
283
  const env = [];
279
284
  if (opts.show) env.push(`LK_STATUSLINE_SHOW=${opts.show}`);
@@ -282,10 +287,7 @@ function wrapperCommand(opts) {
282
287
  return `${prefix}bash ${WRAPPER_PATH}`;
283
288
  }
284
289
  function activateStatusline(opts = {}) {
285
- const settings = readSettings();
286
- if (!settings) {
287
- return { ok: false, outcome: "no-settings", message: `no ~/.claude/settings.json \u2014 nothing to wrap` };
288
- }
290
+ const settings = readSettings() ?? {};
289
291
  const currentCmd = settings.statusLine?.command;
290
292
  const alreadyWrapped = typeof currentCmd === "string" && currentCmd.includes(WRAPPER_PATH);
291
293
  if (alreadyWrapped) {
@@ -304,20 +306,22 @@ function activateStatusline(opts = {}) {
304
306
  }
305
307
  return { ok: true, outcome: "refreshed", message: "statusline already wrapped \u2014 refreshed chip scripts only" };
306
308
  }
307
- if (!currentCmd) {
308
- return { ok: false, outcome: "no-statusline", message: "no statusLine.command in ~/.claude/settings.json \u2014 launch-kit only extends an existing statusline" };
309
- }
310
309
  writeScripts();
310
+ const scaffolded = !currentCmd;
311
+ const original = scaffolded ? { type: "command", command: writeBaseScript() } : settings.statusLine;
311
312
  const wrapped = {
312
313
  ...settings,
313
314
  statusLine: { type: "command", command: wrapperCommand(opts) },
314
- [ORIGINAL_KEY]: settings.statusLine
315
+ [ORIGINAL_KEY]: original
315
316
  };
316
317
  writeSettings(wrapped);
317
318
  const modeParts = [];
318
319
  if (opts.show) modeParts.push(`chips: ${opts.show}`);
319
320
  if (opts.compact) modeParts.push("compact mode");
320
321
  const modeDesc = modeParts.length > 0 ? ` (${modeParts.join(", ")})` : "";
322
+ if (scaffolded) {
323
+ return { ok: true, outcome: "scaffolded", message: `no statusline found \u2014 scaffolded Claude Code's default base line and wrapped it with chips${modeDesc}; base stashed under ${ORIGINAL_KEY}` };
324
+ }
321
325
  return { ok: true, outcome: "activated", message: `wrapped statusLine.command${modeDesc}; original stashed under ${ORIGINAL_KEY}` };
322
326
  }
323
327
  function deactivateStatusline() {
@@ -327,18 +331,26 @@ function deactivateStatusline() {
327
331
  if (!original) {
328
332
  return { ok: false, outcome: "not-active", message: `no ${ORIGINAL_KEY} in settings.json \u2014 statusline isn't wrapped by launch-kit` };
329
333
  }
330
- const restored = { ...settings, statusLine: original };
334
+ const wasScaffolded = original.command?.includes(BASE_PATH) ?? false;
335
+ const restored = { ...settings };
336
+ if (wasScaffolded) delete restored.statusLine;
337
+ else restored.statusLine = original;
331
338
  delete restored[ORIGINAL_KEY];
332
339
  writeSettings(restored);
333
- for (const p of [WRAPPER_PATH, CHIP_PATH]) {
340
+ const toRemove = wasScaffolded ? [WRAPPER_PATH, CHIP_PATH, BASE_PATH] : [WRAPPER_PATH, CHIP_PATH];
341
+ for (const p of toRemove) {
334
342
  try {
335
343
  fs4.unlinkSync(p);
336
344
  } catch {
337
345
  }
338
346
  }
339
- return { ok: true, outcome: "deactivated", message: "restored original statusLine.command" };
347
+ return {
348
+ ok: true,
349
+ outcome: "deactivated",
350
+ message: wasScaffolded ? "removed launch-kit statusline and scaffolded base line \u2014 back to no statusline" : "restored original statusLine.command"
351
+ };
340
352
  }
341
- var fs4, path4, import_node_os, LK_DIR, WRAPPER_PATH, CHIP_PATH, SETTINGS_PATH, ORIGINAL_KEY;
353
+ var fs4, path4, import_node_os, LK_DIR, WRAPPER_PATH, CHIP_PATH, BASE_PATH, SETTINGS_PATH, ORIGINAL_KEY;
342
354
  var init_statusline_install = __esm({
343
355
  "src/server/statusline-install.ts"() {
344
356
  "use strict";
@@ -348,6 +360,7 @@ var init_statusline_install = __esm({
348
360
  LK_DIR = path4.join((0, import_node_os.homedir)(), ".launchsecure");
349
361
  WRAPPER_PATH = path4.join(LK_DIR, "statusline-wrapper.sh");
350
362
  CHIP_PATH = path4.join(LK_DIR, "statusline-mcp.sh");
363
+ BASE_PATH = path4.join(LK_DIR, "statusline-base.sh");
351
364
  SETTINGS_PATH = path4.join((0, import_node_os.homedir)(), ".claude", "settings.json");
352
365
  ORIGINAL_KEY = "_launchKitStatuslineOriginal";
353
366
  }
@@ -1621,6 +1634,7 @@ var ALL_STEP_IDS = [
1621
1634
  "migrate-safety",
1622
1635
  "ls-marketplace",
1623
1636
  "recall-hook",
1637
+ "project-info",
1624
1638
  "statusline"
1625
1639
  ];
1626
1640
  var PRESETS = {
@@ -1628,6 +1642,7 @@ var PRESETS = {
1628
1642
  refresh: ["resolve", "clone", "install", "onboard", "recall"]
1629
1643
  };
1630
1644
  var LAUNCH_KIT_PKG = "@launchsecure/launch-kit";
1645
+ var LAUNCH_KIT_PKG_LATEST = `${LAUNCH_KIT_PKG}@latest`;
1631
1646
  var LAUNCH_KIT_TOOLS_GUIDE_STATIC_HEAD = `
1632
1647
  Wired in Claude Code (.mcp.json):
1633
1648
  launch-secure \u2014 LS API: work items, comms, secrets, members, board
@@ -1698,6 +1713,7 @@ var KNOWN_BOOL_FLAGS = /* @__PURE__ */ new Set([
1698
1713
  "--no-migrate-safety",
1699
1714
  "--no-ls-marketplace",
1700
1715
  "--no-recall-hook",
1716
+ "--no-project-info",
1701
1717
  "--refresh-scaffolds",
1702
1718
  "--quiet",
1703
1719
  "--force",
@@ -1731,6 +1747,7 @@ function parseArgs(argv) {
1731
1747
  noMigrateSafety: false,
1732
1748
  noLsMarketplace: false,
1733
1749
  noRecallHook: false,
1750
+ noProjectInfo: false,
1734
1751
  refreshScaffolds: false,
1735
1752
  quiet: false,
1736
1753
  force: false,
@@ -1775,6 +1792,10 @@ function parseArgs(argv) {
1775
1792
  args.noRecallHook = true;
1776
1793
  continue;
1777
1794
  }
1795
+ if (raw === "--no-project-info") {
1796
+ args.noProjectInfo = true;
1797
+ continue;
1798
+ }
1778
1799
  if (raw === "--refresh-scaffolds") {
1779
1800
  args.refreshScaffolds = true;
1780
1801
  continue;
@@ -1909,6 +1930,8 @@ Options:
1909
1930
  --no-migrate-safety Skip refreshing the migrate-safety scaffold.
1910
1931
  --no-ls-marketplace Skip refreshing the launch-secure marketplace.
1911
1932
  --no-recall-hook Skip refreshing the recall-hook scaffold.
1933
+ --no-project-info Skip wiring the gitignored CLAUDE.md-imported
1934
+ project-info snapshot (/kit:project-info refreshes it).
1912
1935
  --refresh-scaffolds Force-overwrite migrate-safety files (default is to
1913
1936
  preserve user edits). Use this to pull updates
1914
1937
  published to @launchsecure/launch-kit.
@@ -1944,8 +1967,8 @@ Subcommands:
1944
1967
  Env resolved from --env \u2192 $LS_ENV \u2192 server-side project default \u2192
1945
1968
  single-env auto-pick. See \`launch-kit secrets --help\`.
1946
1969
  statusline activate Wrap ~/.claude/settings.json's statusLine.command so MCP daemon
1947
- chips (recall, chart, deck, council) get appended. Refuses to
1948
- create one if none exists \u2014 additive only.
1970
+ chips (recall, chart, deck, council) get appended. If no
1971
+ statusline exists, scaffolds Claude Code's default base line first.
1949
1972
  statusline deactivate Restore the original statusLine.command and remove kit scripts.
1950
1973
 
1951
1974
  Usage:
@@ -2016,7 +2039,7 @@ Options:
2016
2039
 
2017
2040
  Step selection (one-command flow \u2014 compose over the preset):
2018
2041
  Steps: resolve, clone, cred, mcp, gitignore, install, onboard, recall,
2019
- migrate-safety, ls-marketplace, recall-hook, statusline
2042
+ migrate-safety, ls-marketplace, recall-hook, project-info, statusline
2020
2043
  --preset=<name> init (everything) or refresh (skips resolve/clone/
2021
2044
  install/onboard/recall). Default: init. \`init\` and
2022
2045
  \`refresh\` subcommands just select this.
@@ -2322,19 +2345,19 @@ function buildLaunchKitMcpEntries(cfg) {
2322
2345
  },
2323
2346
  "launch-chart": {
2324
2347
  command: "npx",
2325
- args: ["-y", "-p", LAUNCH_KIT_PKG, "launch-chart"]
2348
+ args: ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-chart"]
2326
2349
  },
2327
2350
  "launch-deck": {
2328
2351
  command: "npx",
2329
- args: ["-y", "-p", LAUNCH_KIT_PKG, "launch-deck"]
2352
+ args: ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-deck"]
2330
2353
  },
2331
2354
  "launch-orbit": {
2332
2355
  command: "npx",
2333
- args: ["-y", "-p", LAUNCH_KIT_PKG, "launch-orbit", "mcp"]
2356
+ args: ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-orbit", "mcp"]
2334
2357
  },
2335
2358
  "launch-recall": {
2336
2359
  command: "npx",
2337
- args: ["-y", "-p", LAUNCH_KIT_PKG, "launch-recall", "mcp"]
2360
+ args: ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-recall", "mcp"]
2338
2361
  }
2339
2362
  };
2340
2363
  }
@@ -2354,6 +2377,18 @@ function mergeMcpEntry(existing, ours) {
2354
2377
  }
2355
2378
  return merged;
2356
2379
  }
2380
+ function pinLaunchKitLatest(servers) {
2381
+ const fixed = [];
2382
+ for (const [name, entry] of Object.entries(servers)) {
2383
+ if (entry.command !== "npx" || !Array.isArray(entry.args)) continue;
2384
+ const i = entry.args.indexOf(LAUNCH_KIT_PKG);
2385
+ if (i !== -1) {
2386
+ entry.args[i] = LAUNCH_KIT_PKG_LATEST;
2387
+ fixed.push(name);
2388
+ }
2389
+ }
2390
+ return fixed;
2391
+ }
2357
2392
  function mergeMcpFile(targetDir, launchKitEntries) {
2358
2393
  const p = path5.join(targetDir, ".mcp.json");
2359
2394
  const hadExisting = fs5.existsSync(p);
@@ -2379,12 +2414,14 @@ function mergeMcpFile(targetDir, launchKitEntries) {
2379
2414
  merged.mcpServers[name] = entry;
2380
2415
  }
2381
2416
  }
2417
+ const pinned = pinLaunchKitLatest(merged.mcpServers);
2382
2418
  if (DRY_RUN) {
2383
2419
  const action = hadExisting && existingServerCount > 0 ? "would merge into" : "would write";
2384
- dryNote(`${action} .mcp.json \u2014 overwriting [${overwrites.join(", ") || "none"}], adding [${additions.join(", ") || "none"}]`);
2420
+ dryNote(`${action} .mcp.json \u2014 overwriting [${overwrites.join(", ") || "none"}], adding [${additions.join(", ") || "none"}], pinning @latest on [${pinned.join(", ") || "none"}]`);
2385
2421
  return { status: "skipped", summary: "(dry-run)" };
2386
2422
  }
2387
2423
  fs5.writeFileSync(p, JSON.stringify(merged, null, 2) + "\n", "utf-8");
2424
+ if (pinned.length > 0) info(`pinned @latest on ${pinned.length} launch-kit MCP entr${pinned.length === 1 ? "y" : "ies"}: ${pinned.join(", ")}`);
2388
2425
  const verb = hadExisting && existingServerCount > 0 ? "merged" : "wrote";
2389
2426
  ok(`${verb === "merged" ? "merged into" : "wrote"} .mcp.json (${Object.keys(launchKitEntries).length} launch-kit entries)`);
2390
2427
  const total = Object.keys(launchKitEntries).length;
@@ -2470,14 +2507,14 @@ function runRecallInit(repoDir) {
2470
2507
  const recallEntry = path5.resolve(__dirname, "recall-entry.js");
2471
2508
  const useSibling = fs5.existsSync(recallEntry);
2472
2509
  const cmd = useSibling ? process.execPath : "npx";
2473
- const args = useSibling ? [recallEntry, "init"] : ["-y", "-p", LAUNCH_KIT_PKG, "launch-recall", "init"];
2510
+ const args = useSibling ? [recallEntry, "init"] : ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-recall", "init"];
2474
2511
  if (DRY_RUN) {
2475
2512
  dryNote(`would run launch-recall init: ${cmd} ${args.join(" ")} (cwd: ${repoDir})`);
2476
2513
  return;
2477
2514
  }
2478
2515
  const res = (0, import_node_child_process3.spawnSync)(cmd, args, { cwd: repoDir, stdio: "inherit" });
2479
2516
  if (res.status !== 0) {
2480
- info(`\u26A0 launch-recall init failed (exit ${res.status}). Main onboarding is complete \u2014 you can retry later: cd ${path5.basename(repoDir)} && npx -y -p ${LAUNCH_KIT_PKG} launch-recall init`);
2517
+ info(`\u26A0 launch-recall init failed (exit ${res.status}). Main onboarding is complete \u2014 you can retry later: cd ${path5.basename(repoDir)} && npx -y -p ${LAUNCH_KIT_PKG_LATEST} launch-recall init`);
2481
2518
  return;
2482
2519
  }
2483
2520
  ok(`launch-recall ready (shadow git initialized)`);
@@ -2768,7 +2805,7 @@ function wireRecallHook(targetDir) {
2768
2805
  }
2769
2806
  function tryActivateStatusline() {
2770
2807
  if (DRY_RUN) {
2771
- dryNote(`would wrap ~/.claude/settings.json statusLine.command with launch-kit's MCP chip wrapper (skips silently if no statusline configured)`);
2808
+ dryNote(`would wrap ~/.claude/settings.json statusLine.command with launch-kit's MCP chip wrapper (scaffolds Claude Code's default base line first if none is configured)`);
2772
2809
  return { status: "skipped", summary: "(dry-run)" };
2773
2810
  }
2774
2811
  const res = activateStatusline();
@@ -2776,6 +2813,10 @@ function tryActivateStatusline() {
2776
2813
  ok(`statusline wrapped \u2014 MCP chips will render alongside your existing statusline next session`);
2777
2814
  return { status: "ok", summary: "wrapped \u2014 MCP chips render next session" };
2778
2815
  }
2816
+ if (res.ok && res.outcome === "scaffolded") {
2817
+ ok(`no statusline found \u2014 scaffolded Claude Code's default base line; MCP chips render alongside it next session`);
2818
+ return { status: "ok", summary: "scaffolded default base line + chips" };
2819
+ }
2779
2820
  if (res.ok && res.outcome === "refreshed") {
2780
2821
  info(`statusline already wrapped \u2014 refreshed chip scripts`);
2781
2822
  return { status: "ok", summary: "chip scripts refreshed" };
@@ -2834,8 +2875,8 @@ async function main2() {
2834
2875
  if (action === "activate") res = activateStatusline2({ show: showArg, compact: compactArg });
2835
2876
  else if (action === "deactivate") res = deactivateStatusline2();
2836
2877
  else fail3(`Unknown statusline action: "${action}". Supported: activate, deactivate.`);
2837
- if (res.ok) ok(`statusline ${res.outcome} \u2014 ${res.message}`);
2838
- else info(`statusline ${res.outcome} \u2014 ${res.message}`);
2878
+ const mark = res.ok ? "\u2713" : "\u2717";
2879
+ console.log(`[launch-kit] ${mark} statusline ${res.outcome} \u2014 ${res.message}`);
2839
2880
  return;
2840
2881
  }
2841
2882
  if (subcommand === "secrets") {
@@ -2913,6 +2954,7 @@ function resolveEnabledSteps(args) {
2913
2954
  if (args.noMigrateSafety) enabled.delete("migrate-safety");
2914
2955
  if (args.noLsMarketplace) enabled.delete("ls-marketplace");
2915
2956
  if (args.noRecallHook) enabled.delete("recall-hook");
2957
+ if (args.noProjectInfo) enabled.delete("project-info");
2916
2958
  return enabled;
2917
2959
  }
2918
2960
  async function stepResolve(ctx) {
@@ -3142,6 +3184,90 @@ function stepStatusline(_ctx) {
3142
3184
  const slR = tryActivateStatusline();
3143
3185
  if (slR) phase("statusline", slR);
3144
3186
  }
3187
+ var PROJECT_INFO_REL = ".claude/launch-kit/project-info.md";
3188
+ function ensureClaudeMdImport(targetDir) {
3189
+ const p = path5.join(targetDir, "CLAUDE.md");
3190
+ const importLine = `@${PROJECT_INFO_REL}`;
3191
+ const block = `<!-- launch-kit:project-info \u2014 generated import; safe to move, keep the line -->
3192
+ ${importLine}
3193
+ <!-- /launch-kit:project-info -->
3194
+ `;
3195
+ if (fs5.existsSync(p)) {
3196
+ const content = fs5.readFileSync(p, "utf-8");
3197
+ if (content.includes(importLine)) return "in-sync";
3198
+ if (DRY_RUN) {
3199
+ dryNote(`would add ${importLine} import to CLAUDE.md`);
3200
+ return "added";
3201
+ }
3202
+ fs5.writeFileSync(p, content + (content.endsWith("\n") ? "" : "\n") + "\n" + block, "utf-8");
3203
+ return "added";
3204
+ }
3205
+ if (DRY_RUN) {
3206
+ dryNote(`would create CLAUDE.md with ${importLine} import`);
3207
+ return "created";
3208
+ }
3209
+ fs5.writeFileSync(p, `# CLAUDE.md
3210
+
3211
+ ${block}`, "utf-8");
3212
+ return "created";
3213
+ }
3214
+ function renderProjectInfoSkeleton(ctx) {
3215
+ const cfg = ctx.cfg;
3216
+ const projectName = ctx.resolved?.projectName ?? cfg.projectSlug;
3217
+ const repo = ctx.resolved?.repositoryUrl ?? "\u2014";
3218
+ const todo = "_Not populated yet \u2014 run `/kit:project-info` in Claude Code._";
3219
+ return [
3220
+ `# Project Info \u2014 ${projectName}`,
3221
+ ``,
3222
+ `<!-- launch-kit:generated \u2014 local, git-ignored snapshot. NOT a source of truth. -->`,
3223
+ `> Wired by \`launch-kit\` init. This is a **local, git-ignored snapshot** of`,
3224
+ `> project facts so Claude doesn't re-query them every session. Members,`,
3225
+ `> providers, and environments are filled from LaunchSecure by the`,
3226
+ `> \`/kit:project-info\` skill \u2014 run it to populate or refresh. Treat as a`,
3227
+ `> cache: it can go stale, so re-run after team/provider/env changes.`,
3228
+ ``,
3229
+ `## Identity`,
3230
+ `- **Org:** ${cfg.orgSlug}`,
3231
+ `- **Project:** ${projectName} (\`${cfg.projectSlug}\`)`,
3232
+ `- **Server:** ${cfg.serverUrl}`,
3233
+ `- **Course:** ${ctx.courseName ?? "\u2014"}`,
3234
+ `- **Repo:** ${repo}`,
3235
+ ``,
3236
+ `## Members`,
3237
+ todo,
3238
+ ``,
3239
+ `## Providers / integrations`,
3240
+ todo,
3241
+ ``,
3242
+ `## Environments`,
3243
+ todo,
3244
+ ``
3245
+ ].join("\n");
3246
+ }
3247
+ function stepProjectInfo(ctx) {
3248
+ if (!ctx.cfg) {
3249
+ phase("project-info", { status: "skipped", summary: "no cred resolved" });
3250
+ return;
3251
+ }
3252
+ ensureGitignoreLine(ctx.targetDir, PROJECT_INFO_REL);
3253
+ const importResult = ensureClaudeMdImport(ctx.targetDir);
3254
+ const dest = path5.join(ctx.targetDir, PROJECT_INFO_REL);
3255
+ const existed = fs5.existsSync(dest);
3256
+ if (!existed) {
3257
+ if (DRY_RUN) {
3258
+ dryNote(`would write ${PROJECT_INFO_REL} identity skeleton`);
3259
+ } else {
3260
+ fs5.mkdirSync(path5.dirname(dest), { recursive: true });
3261
+ fs5.writeFileSync(dest, renderProjectInfoSkeleton(ctx), "utf-8");
3262
+ ok(`wrote ${PROJECT_INFO_REL}`);
3263
+ }
3264
+ }
3265
+ const summary = existed ? `kept file \xB7 CLAUDE.md ${importResult} \xB7 /kit:project-info to refresh` : `wrote skeleton \xB7 CLAUDE.md ${importResult} \xB7 /kit:project-info to populate`;
3266
+ phase("project-info", {
3267
+ status: existed && importResult === "in-sync" ? "in-sync" : "ok",
3268
+ summary
3269
+ });
3270
+ }
3145
3271
  var STEPS = [
3146
3272
  { id: "resolve", run: stepResolve },
3147
3273
  { id: "clone", requires: ["resolve"], run: stepClone },
@@ -3154,6 +3280,7 @@ var STEPS = [
3154
3280
  { id: "migrate-safety", run: stepMigrateSafety },
3155
3281
  { id: "ls-marketplace", run: stepLsMarketplace },
3156
3282
  { id: "recall-hook", run: stepRecallHook },
3283
+ { id: "project-info", requires: ["cred"], run: stepProjectInfo },
3157
3284
  { id: "statusline", run: stepStatusline }
3158
3285
  ];
3159
3286
  function buildCtx(args, enabled) {
@@ -1385,7 +1385,7 @@ function rewriteEnvFile(filePath, rewrites) {
1385
1385
  const out = lines.map((line) => {
1386
1386
  const m = LINE_RE.exec(line);
1387
1387
  if (!m) return line;
1388
- const [, indent, key, sep, rawValue] = m;
1388
+ const [, indent, key, sep2, rawValue] = m;
1389
1389
  if (!(key in rewrites)) return line;
1390
1390
  touched.add(key);
1391
1391
  const { quote, inner } = stripQuotes2(rawValue);
@@ -1396,7 +1396,7 @@ function rewriteEnvFile(filePath, rewrites) {
1396
1396
  return line;
1397
1397
  }
1398
1398
  result.changed.push(key);
1399
- return `${indent}${key}${sep}${quote}${next2}${quote}`;
1399
+ return `${indent}${key}${sep2}${quote}${next2}${quote}`;
1400
1400
  });
1401
1401
  for (const key of Object.keys(rewrites)) {
1402
1402
  if (!touched.has(key)) result.missing.push(key);
@@ -3060,10 +3060,93 @@ var init_orbit_mcp = __esm({
3060
3060
  });
3061
3061
 
3062
3062
  // src/server/orbit-entry.ts
3063
- var import_node_fs13 = require("node:fs");
3064
- var import_node_path10 = require("node:path");
3063
+ var import_node_fs14 = require("node:fs");
3064
+ var import_node_path11 = require("node:path");
3065
3065
  init_orchestrator();
3066
3066
  init_logger();
3067
+
3068
+ // src/server/prune-npx-cache.ts
3069
+ var import_node_fs13 = require("node:fs");
3070
+ var import_node_os5 = require("node:os");
3071
+ var import_node_path10 = require("node:path");
3072
+ var import_node_util = require("node:util");
3073
+ var PKG = "@launchsecure/launch-kit";
3074
+ var readFileAsync = (0, import_node_util.promisify)(import_node_fs13.readFile);
3075
+ var readdirAsync = (0, import_node_util.promisify)(import_node_fs13.readdir);
3076
+ var rmAsync = (0, import_node_util.promisify)(import_node_fs13.rm);
3077
+ var realpathAsync = (0, import_node_util.promisify)(import_node_fs13.realpath);
3078
+ function npxCacheRoot() {
3079
+ const cache = process.env.npm_config_cache;
3080
+ if (cache && cache.trim()) return (0, import_node_path10.join)(cache, "_npx");
3081
+ if (process.platform === "win32") {
3082
+ const localAppData = process.env.LOCALAPPDATA;
3083
+ if (localAppData) return (0, import_node_path10.join)(localAppData, "npm-cache", "_npx");
3084
+ }
3085
+ return (0, import_node_path10.join)((0, import_node_os5.homedir)(), ".npm", "_npx");
3086
+ }
3087
+ function ownVersion() {
3088
+ let dir = __dirname;
3089
+ for (let i = 0; i < 8; i++) {
3090
+ try {
3091
+ const pkg = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path10.join)(dir, "package.json"), "utf8"));
3092
+ if (pkg && pkg.name === PKG) return typeof pkg.version === "string" ? pkg.version : null;
3093
+ } catch {
3094
+ }
3095
+ const parent = (0, import_node_path10.dirname)(dir);
3096
+ if (parent === dir) break;
3097
+ dir = parent;
3098
+ }
3099
+ return null;
3100
+ }
3101
+ async function pruneStaleNpxCache() {
3102
+ try {
3103
+ const version = ownVersion();
3104
+ if (!version) return;
3105
+ const root = npxCacheRoot();
3106
+ let hashes;
3107
+ try {
3108
+ hashes = await readdirAsync(root);
3109
+ } catch {
3110
+ return;
3111
+ }
3112
+ const selfPath = await realpathAsync(process.argv[1] || __dirname).catch(() => __dirname);
3113
+ let reaped = 0;
3114
+ for (const hash of hashes) {
3115
+ const dir = (0, import_node_path10.join)(root, hash);
3116
+ if (selfPath === dir || selfPath.startsWith(dir + import_node_path10.sep)) continue;
3117
+ let ver;
3118
+ try {
3119
+ const lkPkg = JSON.parse(
3120
+ await readFileAsync((0, import_node_path10.join)(dir, "node_modules", PKG, "package.json"), "utf8")
3121
+ );
3122
+ ver = lkPkg.version;
3123
+ } catch {
3124
+ continue;
3125
+ }
3126
+ if (ver === version) continue;
3127
+ try {
3128
+ const top = JSON.parse(await readFileAsync((0, import_node_path10.join)(dir, "package.json"), "utf8"));
3129
+ const spec = top?.dependencies?.[PKG];
3130
+ if (typeof spec === "string" && spec.startsWith("file:")) continue;
3131
+ } catch {
3132
+ }
3133
+ try {
3134
+ await rmAsync(dir, { recursive: true, force: true });
3135
+ reaped++;
3136
+ } catch {
3137
+ }
3138
+ }
3139
+ if (reaped > 0) {
3140
+ process.stderr.write(
3141
+ `[launch-kit] npx-cache: reaped ${reaped} stale copy(ies), kept v${version}
3142
+ `
3143
+ );
3144
+ }
3145
+ } catch {
3146
+ }
3147
+ }
3148
+
3149
+ // src/server/orbit-entry.ts
3067
3150
  function parseFlags(argv) {
3068
3151
  const positional = [];
3069
3152
  const flags = { emitCd: false, noBackup: false, skipGates: [], deep: false, all: false, json: false, force: false };
@@ -3099,6 +3182,7 @@ function parseFlags(argv) {
3099
3182
  return { positional, flags };
3100
3183
  }
3101
3184
  async function main() {
3185
+ void pruneStaleNpxCache();
3102
3186
  const argv = process.argv.slice(2);
3103
3187
  const subcommand = argv[0];
3104
3188
  if (!subcommand || subcommand === "mcp") {
@@ -3328,8 +3412,8 @@ function formatRollup(reports) {
3328
3412
  return out.join("\n") + "\n";
3329
3413
  }
3330
3414
  function runInit(projectRoot) {
3331
- const path = (0, import_node_path10.join)(projectRoot, "orbit.json");
3332
- if ((0, import_node_fs13.existsSync)(path)) {
3415
+ const path = (0, import_node_path11.join)(projectRoot, "orbit.json");
3416
+ if ((0, import_node_fs14.existsSync)(path)) {
3333
3417
  process.stderr.write(`[launch-orbit] orbit.json already exists at ${path}
3334
3418
  `);
3335
3419
  process.exit(1);
@@ -3384,7 +3468,7 @@ function runInit(projectRoot) {
3384
3468
  full: { resources: ["db", "ports"] }
3385
3469
  }
3386
3470
  };
3387
- (0, import_node_fs13.writeFileSync)(path, JSON.stringify(starter, null, 2) + "\n", "utf-8");
3471
+ (0, import_node_fs14.writeFileSync)(path, JSON.stringify(starter, null, 2) + "\n", "utf-8");
3388
3472
  process.stdout.write(`\u2713 wrote ${path}
3389
3473
  `);
3390
3474
  }
File without changes
File without changes
File without changes