@fairfox/polly 0.73.1 → 0.74.0

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.
@@ -667,7 +667,7 @@ function detectProjectConfig(projectRoot) {
667
667
  var init_project_detector = () => {};
668
668
 
669
669
  // tools/visualize/src/cli.ts
670
- import * as fs6 from "node:fs";
670
+ import * as fs7 from "node:fs";
671
671
  import * as path6 from "node:path";
672
672
 
673
673
  // tools/analysis/src/extract/architecture.ts
@@ -4590,6 +4590,122 @@ async function analyzeArchitecture(options) {
4590
4590
  return analyzer.analyze();
4591
4591
  }
4592
4592
 
4593
+ // src/shared/lib/derive-document-id.ts
4594
+ import {
4595
+ interpretAsDocumentId
4596
+ } from "@automerge/automerge-repo/slim";
4597
+ import nacl from "tweetnacl";
4598
+ var DOC_ID_DOMAIN = "polly/meshState/v1";
4599
+ var keyEncoder = new TextEncoder;
4600
+ function deriveDocumentId(key) {
4601
+ const digest = nacl.hash(keyEncoder.encode(`${DOC_ID_DOMAIN}:${key}`));
4602
+ const bytes = digest.slice(0, 16);
4603
+ return interpretAsDocumentId(bytes);
4604
+ }
4605
+
4606
+ // tools/visualize/src/mesh-snapshot.ts
4607
+ import * as fs5 from "node:fs";
4608
+
4609
+ class MeshSnapshotError extends Error {
4610
+ constructor(message) {
4611
+ super(message);
4612
+ this.name = "MeshSnapshotError";
4613
+ }
4614
+ }
4615
+ function isObject(value) {
4616
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4617
+ }
4618
+ function requireStringArray(value, path5) {
4619
+ if (!Array.isArray(value) || value.some((v) => typeof v !== "string")) {
4620
+ throw new MeshSnapshotError(`${path5} must be an array of strings`);
4621
+ }
4622
+ return value;
4623
+ }
4624
+ function validateHandle(value, path5) {
4625
+ if (!isObject(value)) {
4626
+ throw new MeshSnapshotError(`${path5} must be an object`);
4627
+ }
4628
+ if (typeof value["docSynchronizerExists"] !== "boolean") {
4629
+ throw new MeshSnapshotError(`${path5}.docSynchronizerExists must be a boolean`);
4630
+ }
4631
+ const knowsPeer = value["docSynchronizerKnowsPeer"];
4632
+ if (knowsPeer !== undefined && typeof knowsPeer !== "boolean") {
4633
+ throw new MeshSnapshotError(`${path5}.docSynchronizerKnowsPeer must be a boolean or absent`);
4634
+ }
4635
+ const status = value["peerDocumentStatus"];
4636
+ if (status !== undefined && typeof status !== "string") {
4637
+ throw new MeshSnapshotError(`${path5}.peerDocumentStatus must be a string or absent`);
4638
+ }
4639
+ return value;
4640
+ }
4641
+ function validatePeer(value, path5) {
4642
+ if (!isObject(value)) {
4643
+ throw new MeshSnapshotError(`${path5} must be an object`);
4644
+ }
4645
+ if (typeof value["peerId"] !== "string") {
4646
+ throw new MeshSnapshotError(`${path5}.peerId must be a string`);
4647
+ }
4648
+ const slot = value["slot"];
4649
+ if (slot !== undefined && slot !== null) {
4650
+ if (!isObject(slot)) {
4651
+ throw new MeshSnapshotError(`${path5}.slot must be an object or absent`);
4652
+ }
4653
+ const handles = slot["handles"];
4654
+ if (!isObject(handles)) {
4655
+ throw new MeshSnapshotError(`${path5}.slot.handles must be an object`);
4656
+ }
4657
+ for (const [docId, handle] of Object.entries(handles)) {
4658
+ validateHandle(handle, `${path5}.slot.handles[${docId}]`);
4659
+ }
4660
+ }
4661
+ return value;
4662
+ }
4663
+ function validateMeshSnapshot(data) {
4664
+ if (!isObject(data)) {
4665
+ throw new MeshSnapshotError("snapshot must be a JSON object");
4666
+ }
4667
+ if (typeof data["localPeerId"] !== "string") {
4668
+ throw new MeshSnapshotError("snapshot.localPeerId must be a string");
4669
+ }
4670
+ requireStringArray(data["knownPeerIds"], "snapshot.knownPeerIds");
4671
+ requireStringArray(data["presentPeerIds"], "snapshot.presentPeerIds");
4672
+ const peers = data["peers"];
4673
+ if (!Array.isArray(peers)) {
4674
+ throw new MeshSnapshotError("snapshot.peers must be an array");
4675
+ }
4676
+ peers.forEach((peer, i) => {
4677
+ validatePeer(peer, `snapshot.peers[${i}]`);
4678
+ });
4679
+ return data;
4680
+ }
4681
+ function loadMeshSnapshot(filePath) {
4682
+ let raw;
4683
+ try {
4684
+ raw = fs5.readFileSync(filePath, "utf-8");
4685
+ } catch (error) {
4686
+ const reason = error instanceof Error ? error.message : String(error);
4687
+ throw new MeshSnapshotError(`cannot read snapshot file '${filePath}': ${reason}`);
4688
+ }
4689
+ let parsed;
4690
+ try {
4691
+ parsed = JSON.parse(raw);
4692
+ } catch (error) {
4693
+ const reason = error instanceof Error ? error.message : String(error);
4694
+ throw new MeshSnapshotError(`snapshot file '${filePath}' is not valid JSON: ${reason}`);
4695
+ }
4696
+ return validateMeshSnapshot(parsed);
4697
+ }
4698
+ function collectSnapshotPeerIds(snapshot) {
4699
+ const ids = new Set([snapshot.localPeerId]);
4700
+ for (const id of snapshot.knownPeerIds)
4701
+ ids.add(id);
4702
+ for (const id of snapshot.presentPeerIds)
4703
+ ids.add(id);
4704
+ for (const peer of snapshot.peers)
4705
+ ids.add(peer.peerId);
4706
+ return [...ids];
4707
+ }
4708
+
4593
4709
  // tools/visualize/src/types/structurizr.ts
4594
4710
  var DEFAULT_COLORS = {
4595
4711
  messageHandler: "#1168bd",
@@ -4690,6 +4806,46 @@ var DEFAULT_RELATIONSHIP_STYLES = {
4690
4806
  color: DEFAULT_COLORS.database
4691
4807
  }
4692
4808
  };
4809
+ var MESH_OVERLAY_ELEMENT_STYLES = {
4810
+ "Mesh Peer": {
4811
+ shape: "Person",
4812
+ background: "#495057",
4813
+ color: DEFAULT_COLORS.textLight
4814
+ },
4815
+ "Local Mesh Peer": {
4816
+ shape: "Person",
4817
+ background: DEFAULT_COLORS.messageHandler,
4818
+ color: DEFAULT_COLORS.textLight
4819
+ },
4820
+ "Snapshot Document": {
4821
+ shape: "Cylinder",
4822
+ background: "#adb5bd",
4823
+ color: DEFAULT_COLORS.textDark,
4824
+ border: "Dashed"
4825
+ }
4826
+ };
4827
+ var MESH_OVERLAY_RELATIONSHIP_STYLES = {
4828
+ "sync:has": {
4829
+ color: "#2f9e44",
4830
+ style: "Solid",
4831
+ thickness: 3
4832
+ },
4833
+ "sync:wants": {
4834
+ color: "#f08c00",
4835
+ style: "Dashed",
4836
+ thickness: 2
4837
+ },
4838
+ "sync:unavailable": {
4839
+ color: "#e03131",
4840
+ style: "Dashed",
4841
+ thickness: 2
4842
+ },
4843
+ "sync:unknown": {
4844
+ color: "#868e96",
4845
+ style: "Dotted",
4846
+ thickness: 2
4847
+ }
4848
+ };
4693
4849
  var DEFAULT_THEME = "https://static.structurizr.com/themes/default/theme.json";
4694
4850
 
4695
4851
  // tools/visualize/src/codegen/structurizr.ts
@@ -4715,10 +4871,18 @@ var MESH_TRANSPORT_NODES = [
4715
4871
  description: "The rendezvous server peers exchange WebRTC offers through"
4716
4872
  }
4717
4873
  ];
4874
+ function syncStatusOf(handle) {
4875
+ const status = handle.peerDocumentStatus;
4876
+ if (status === "has" || status === "wants" || status === "unavailable") {
4877
+ return status;
4878
+ }
4879
+ return "unknown";
4880
+ }
4718
4881
 
4719
4882
  class StructurizrDSLGenerator {
4720
4883
  analysis;
4721
4884
  options;
4885
+ overlayPlanCache;
4722
4886
  constructor(analysis, options = {}) {
4723
4887
  this.analysis = analysis;
4724
4888
  this.options = {
@@ -4737,10 +4901,12 @@ class StructurizrDSLGenerator {
4737
4901
  theme: options.styles?.theme || DEFAULT_THEME,
4738
4902
  elements: {
4739
4903
  ...DEFAULT_ELEMENT_STYLES,
4904
+ ...options.snapshot ? MESH_OVERLAY_ELEMENT_STYLES : {},
4740
4905
  ...options.styles?.elements
4741
4906
  },
4742
4907
  relationships: {
4743
4908
  ...DEFAULT_RELATIONSHIP_STYLES,
4909
+ ...options.snapshot ? MESH_OVERLAY_RELATIONSHIP_STYLES : {},
4744
4910
  ...options.styles?.relationships
4745
4911
  }
4746
4912
  }
@@ -4774,6 +4940,9 @@ class StructurizrDSLGenerator {
4774
4940
  const parts = [];
4775
4941
  parts.push(" model {");
4776
4942
  parts.push(this.generatePeople());
4943
+ const meshPeers = this.generateMeshPeers();
4944
+ if (meshPeers)
4945
+ parts.push(meshPeers);
4777
4946
  parts.push(this.generateExternalSystems());
4778
4947
  parts.push(this.generateMainSystem());
4779
4948
  if (this.options.deploymentNodes && this.options.deploymentNodes.length > 0) {
@@ -4814,6 +4983,9 @@ class StructurizrDSLGenerator {
4814
4983
  const meshDocs = this.generateMeshDocuments();
4815
4984
  if (meshDocs)
4816
4985
  parts.push(meshDocs);
4986
+ const snapshotDocs = this.generateSnapshotOnlyDocuments();
4987
+ if (snapshotDocs)
4988
+ parts.push(snapshotDocs);
4817
4989
  const meshTransport = this.generateMeshTransport();
4818
4990
  if (meshTransport)
4819
4991
  parts.push(meshTransport);
@@ -5202,6 +5374,7 @@ class StructurizrDSLGenerator {
5202
5374
  parts.push(...this.generateExternalAPIRelationships());
5203
5375
  parts.push(...this.generateMeshRelationships());
5204
5376
  parts.push(...this.generateMeshTransportRelationships());
5377
+ parts.push(...this.generateMeshOverlayRelationships());
5205
5378
  return parts.join(`
5206
5379
  `);
5207
5380
  }
@@ -5268,6 +5441,130 @@ class StructurizrDSLGenerator {
5268
5441
  }
5269
5442
  return parts;
5270
5443
  }
5444
+ getOverlayPlan() {
5445
+ const snapshot = this.options.snapshot;
5446
+ if (!snapshot)
5447
+ return;
5448
+ if (!this.overlayPlanCache) {
5449
+ this.overlayPlanCache = this.buildOverlayPlan(snapshot);
5450
+ }
5451
+ return this.overlayPlanCache;
5452
+ }
5453
+ buildOverlayPlan(snapshot) {
5454
+ const docIdToNode = this.buildDocIdNodeMap();
5455
+ const { peers, peerDslById } = this.buildOverlayPeers(snapshot);
5456
+ const { edges, snapshotOnlyDocs } = this.buildOverlayEdges(snapshot, docIdToNode, peerDslById);
5457
+ return { peers, edges, snapshotOnlyDocs };
5458
+ }
5459
+ buildDocIdNodeMap() {
5460
+ const docIdToNode = new Map;
5461
+ const seenKeys = new Set;
5462
+ for (const sig of this.analysis.meshOrPeerSignals ?? []) {
5463
+ if (seenKeys.has(sig.key))
5464
+ continue;
5465
+ seenKeys.add(sig.key);
5466
+ docIdToNode.set(String(deriveDocumentId(sig.key)), this.meshDocId(sig.key));
5467
+ }
5468
+ return docIdToNode;
5469
+ }
5470
+ buildOverlayPeers(snapshot) {
5471
+ const peers = [];
5472
+ const peerDslById = new Map;
5473
+ const usedPeerIds = new Set;
5474
+ for (const peerId of collectSnapshotPeerIds(snapshot)) {
5475
+ const base = `peer_${this.toId(peerId)}`;
5476
+ let id = base;
5477
+ let suffix = 2;
5478
+ while (usedPeerIds.has(id))
5479
+ id = `${base}_${suffix++}`;
5480
+ usedPeerIds.add(id);
5481
+ peerDslById.set(peerId, id);
5482
+ peers.push({ id, peerId, isLocal: peerId === snapshot.localPeerId });
5483
+ }
5484
+ return { peers, peerDslById };
5485
+ }
5486
+ buildOverlayEdges(snapshot, docIdToNode, peerDslById) {
5487
+ const edges = [];
5488
+ const snapshotOnlyDocs = [];
5489
+ const snapshotOnlyById = new Map;
5490
+ for (const peer of snapshot.peers) {
5491
+ const handles = peer.slot?.handles;
5492
+ const fromId = peerDslById.get(peer.peerId);
5493
+ if (!handles || !fromId)
5494
+ continue;
5495
+ for (const [docId, handle] of Object.entries(handles)) {
5496
+ const nodeId = this.resolveOverlayDocNode(docId, docIdToNode, snapshotOnlyById, snapshotOnlyDocs);
5497
+ const status = syncStatusOf(handle);
5498
+ edges.push({
5499
+ fromId,
5500
+ toRef: `extension.${nodeId}`,
5501
+ status,
5502
+ label: this.overlayEdgeLabel(status, handle)
5503
+ });
5504
+ }
5505
+ }
5506
+ return { edges, snapshotOnlyDocs };
5507
+ }
5508
+ resolveOverlayDocNode(docId, docIdToNode, snapshotOnlyById, snapshotOnlyDocs) {
5509
+ const staticNode = docIdToNode.get(docId);
5510
+ if (staticNode)
5511
+ return staticNode;
5512
+ const existing = snapshotOnlyById.get(docId);
5513
+ if (existing)
5514
+ return existing;
5515
+ const nodeId = `mesh_doc_${this.toId(docId)}`;
5516
+ snapshotOnlyById.set(docId, nodeId);
5517
+ snapshotOnlyDocs.push({ id: nodeId, docId });
5518
+ return nodeId;
5519
+ }
5520
+ overlayEdgeLabel(status, handle) {
5521
+ if (!handle.docSynchronizerExists)
5522
+ return `${status} · no synchronizer`;
5523
+ if (handle.docSynchronizerKnowsPeer === false)
5524
+ return `${status} · peer not added`;
5525
+ return status;
5526
+ }
5527
+ generateMeshPeers() {
5528
+ const plan = this.getOverlayPlan();
5529
+ if (!plan || plan.peers.length === 0)
5530
+ return "";
5531
+ const parts = [];
5532
+ for (const peer of plan.peers) {
5533
+ const tag = peer.isLocal ? "Local Mesh Peer" : "Mesh Peer";
5534
+ const description = peer.isLocal ? "Local mesh peer (this node)" : "Runtime mesh peer";
5535
+ parts.push(` ${peer.id} = person "${this.escape(peer.peerId)}" "${description}" {`);
5536
+ parts.push(` tags "${tag}"`);
5537
+ parts.push(" }");
5538
+ }
5539
+ return parts.join(`
5540
+ `);
5541
+ }
5542
+ generateSnapshotOnlyDocuments() {
5543
+ const plan = this.getOverlayPlan();
5544
+ if (!plan || plan.snapshotOnlyDocs.length === 0)
5545
+ return "";
5546
+ const parts = [];
5547
+ for (const doc of plan.snapshotOnlyDocs) {
5548
+ const description = `Mesh document seen only in the runtime snapshot — docId ${doc.docId}`;
5549
+ parts.push(` ${doc.id} = container "${this.escape(doc.docId)}" "${this.escape(description)}" "snapshot" {`);
5550
+ parts.push(' tags "Snapshot Document"');
5551
+ parts.push(" }");
5552
+ }
5553
+ return parts.join(`
5554
+ `);
5555
+ }
5556
+ generateMeshOverlayRelationships() {
5557
+ const plan = this.getOverlayPlan();
5558
+ if (!plan)
5559
+ return [];
5560
+ const parts = [];
5561
+ for (const edge of plan.edges) {
5562
+ parts.push(` ${edge.fromId} -> ${edge.toRef} "${this.escape(edge.label)}" {`);
5563
+ parts.push(` tags "sync:${edge.status}"`);
5564
+ parts.push(" }");
5565
+ }
5566
+ return parts;
5567
+ }
5271
5568
  generateUserRelationships() {
5272
5569
  const parts = [];
5273
5570
  const uiContexts = ["popup", "options", "devtools"];
@@ -6015,7 +6312,7 @@ function generateStructurizrDSL(analysis, options) {
6015
6312
 
6016
6313
  // tools/visualize/src/runner/export.ts
6017
6314
  import { spawn } from "node:child_process";
6018
- import * as fs5 from "node:fs";
6315
+ import * as fs6 from "node:fs";
6019
6316
  import * as path5 from "node:path";
6020
6317
 
6021
6318
  class DiagramExporter {
@@ -6023,15 +6320,15 @@ class DiagramExporter {
6023
6320
  static DEFAULT_TIMEOUT = 120000;
6024
6321
  async export(options) {
6025
6322
  const { dslPath, outputDir, timeout = DiagramExporter.DEFAULT_TIMEOUT } = options;
6026
- if (!fs5.existsSync(dslPath)) {
6323
+ if (!fs6.existsSync(dslPath)) {
6027
6324
  return {
6028
6325
  success: false,
6029
6326
  siteDir: "",
6030
6327
  error: `DSL file not found: ${dslPath}`
6031
6328
  };
6032
6329
  }
6033
- if (!fs5.existsSync(outputDir)) {
6034
- fs5.mkdirSync(outputDir, { recursive: true });
6330
+ if (!fs6.existsSync(outputDir)) {
6331
+ fs6.mkdirSync(outputDir, { recursive: true });
6035
6332
  }
6036
6333
  const dockerAvailable = await this.isDockerAvailable();
6037
6334
  if (!dockerAvailable) {
@@ -6179,7 +6476,7 @@ async function main() {
6179
6476
  switch (command) {
6180
6477
  case "--generate":
6181
6478
  case "generate":
6182
- await generateCommand();
6479
+ await generateCommand(args.slice(1));
6183
6480
  break;
6184
6481
  case "--export":
6185
6482
  case "export":
@@ -6196,22 +6493,64 @@ async function main() {
6196
6493
  showHelp();
6197
6494
  break;
6198
6495
  default:
6199
- await generateCommand();
6496
+ await generateCommand(args);
6200
6497
  }
6201
6498
  }
6202
- async function generateCommand() {
6499
+ async function generateCommand(args) {
6203
6500
  console.log(color(`
6204
6501
  \uD83D\uDCCA Analyzing architecture...
6205
6502
  `, COLORS.blue));
6206
6503
  try {
6504
+ const { snapshotPath } = parseGenerateArgs(args);
6505
+ const snapshot = snapshotPath ? loadAndReportSnapshot(snapshotPath) : undefined;
6207
6506
  const { tsConfigPath, projectRoot } = findAndDisplayProjectConfig();
6208
6507
  const analysis = await analyzeAndDisplayResults(tsConfigPath, projectRoot);
6209
- const dslPath = generateAndWriteDSL(analysis);
6508
+ const dslPath = generateAndWriteDSL(analysis, snapshot);
6210
6509
  displayNextSteps(dslPath);
6211
6510
  } catch (_error) {
6212
6511
  process.exit(1);
6213
6512
  }
6214
6513
  }
6514
+ function parseGenerateArgs(args) {
6515
+ const result = {};
6516
+ for (let i = 0;i < args.length; i++) {
6517
+ const arg = args[i];
6518
+ if (arg === "--snapshot") {
6519
+ const next = args[i + 1];
6520
+ if (!next || next.startsWith("--")) {
6521
+ console.log(color(`
6522
+ ✗ --snapshot requires a file path
6523
+ `, COLORS.red));
6524
+ process.exit(1);
6525
+ }
6526
+ result.snapshotPath = next;
6527
+ i++;
6528
+ } else if (arg?.startsWith("--snapshot=")) {
6529
+ result.snapshotPath = arg.slice("--snapshot=".length);
6530
+ }
6531
+ }
6532
+ return result;
6533
+ }
6534
+ function loadAndReportSnapshot(snapshotPath) {
6535
+ let snapshot;
6536
+ try {
6537
+ snapshot = loadMeshSnapshot(snapshotPath);
6538
+ } catch (error) {
6539
+ const message = error instanceof MeshSnapshotError ? error.message : String(error);
6540
+ console.log(color(`
6541
+ ✗ Snapshot error: ${message}
6542
+ `, COLORS.red));
6543
+ process.exit(1);
6544
+ }
6545
+ const isEmpty = snapshot.knownPeerIds.length === 0 && snapshot.presentPeerIds.length === 0 && snapshot.peers.length === 0;
6546
+ if (isEmpty) {
6547
+ console.log(color("⚠ Snapshot has no peers — generating the static diagram only.", COLORS.yellow));
6548
+ return;
6549
+ }
6550
+ const peerCount = collectSnapshotPeerIds(snapshot).length;
6551
+ console.log(color(`✓ Loaded runtime snapshot: ${peerCount} peer(s)`, COLORS.green));
6552
+ return snapshot;
6553
+ }
6215
6554
  function findAndDisplayProjectConfig() {
6216
6555
  const tsConfigPath = findTsConfig();
6217
6556
  if (!tsConfigPath) {
@@ -6227,7 +6566,7 @@ function findAndDisplayProjectConfig() {
6227
6566
  return { tsConfigPath, projectRoot };
6228
6567
  }
6229
6568
  function displayProjectType(projectRoot) {
6230
- const hasManifest = fs6.existsSync(path6.join(projectRoot, "manifest.json"));
6569
+ const hasManifest = fs7.existsSync(path6.join(projectRoot, "manifest.json"));
6231
6570
  const projectType = hasManifest ? "Chrome Extension" : "Detecting from project structure...";
6232
6571
  console.log(color(` Type: ${projectType}`, COLORS.gray));
6233
6572
  }
@@ -6261,7 +6600,7 @@ function displayArchitectureSummary(analysis) {
6261
6600
  }
6262
6601
  }
6263
6602
  }
6264
- function generateAndWriteDSL(analysis) {
6603
+ function generateAndWriteDSL(analysis, snapshot) {
6265
6604
  console.log(color(`
6266
6605
  \uD83D\uDCDD Generating Structurizr DSL...
6267
6606
  `, COLORS.blue));
@@ -6269,14 +6608,15 @@ function generateAndWriteDSL(analysis) {
6269
6608
  const dsl = generateStructurizrDSL(analysis, {
6270
6609
  includeDynamicDiagrams: true,
6271
6610
  includeComponentDiagrams: true,
6272
- componentDiagramContexts: contextTypes.length > 0 ? contextTypes : ["background"]
6611
+ componentDiagramContexts: contextTypes.length > 0 ? contextTypes : ["background"],
6612
+ snapshot
6273
6613
  });
6274
6614
  const outputDir = path6.join(process.cwd(), "docs");
6275
- if (!fs6.existsSync(outputDir)) {
6276
- fs6.mkdirSync(outputDir, { recursive: true });
6615
+ if (!fs7.existsSync(outputDir)) {
6616
+ fs7.mkdirSync(outputDir, { recursive: true });
6277
6617
  }
6278
6618
  const dslPath = path6.join(outputDir, "architecture.dsl");
6279
- fs6.writeFileSync(dslPath, dsl, "utf-8");
6619
+ fs7.writeFileSync(dslPath, dsl, "utf-8");
6280
6620
  return dslPath;
6281
6621
  }
6282
6622
  function displayNextSteps(dslPath) {
@@ -6312,7 +6652,7 @@ async function exportCommand(_args) {
6312
6652
  `, COLORS.blue));
6313
6653
  try {
6314
6654
  const dslPath = path6.join(process.cwd(), "docs", "architecture.dsl");
6315
- if (!fs6.existsSync(dslPath)) {
6655
+ if (!fs7.existsSync(dslPath)) {
6316
6656
  process.exit(1);
6317
6657
  }
6318
6658
  const outputDir = path6.join(process.cwd(), "docs", "site");
@@ -6350,7 +6690,7 @@ async function serveCommand(args) {
6350
6690
  try {
6351
6691
  const siteDir = path6.join(process.cwd(), "docs", "site");
6352
6692
  const indexPath = path6.join(siteDir, "index.html");
6353
- if (!fs6.existsSync(indexPath)) {
6693
+ if (!fs7.existsSync(indexPath)) {
6354
6694
  process.exit(1);
6355
6695
  }
6356
6696
  const portArg = args.find((arg) => arg.startsWith("--port="));
@@ -6367,7 +6707,7 @@ async function serveCommand(args) {
6367
6707
  fetch(req) {
6368
6708
  const url = new URL(req.url);
6369
6709
  const filePath = path6.join(siteDir, url.pathname === "/" ? "index.html" : url.pathname);
6370
- if (fs6.existsSync(filePath) && fs6.statSync(filePath).isFile()) {
6710
+ if (fs7.existsSync(filePath) && fs7.statSync(filePath).isFile()) {
6371
6711
  const file = BunGlobal.file(filePath);
6372
6712
  return new Response(file);
6373
6713
  }
@@ -6411,6 +6751,10 @@ ${color("Commands:", COLORS.blue)}
6411
6751
  ${color("bun visualize --generate", COLORS.green)}
6412
6752
  Analyze codebase and generate Structurizr DSL
6413
6753
 
6754
+ ${color("bun visualize generate --snapshot <path>", COLORS.green)}
6755
+ Overlay a captured MeshClientPeerStateSnapshot — runtime mesh peers
6756
+ and sync-state-coloured replication edges — onto the diagram
6757
+
6414
6758
  ${color("bun visualize --export", COLORS.green)}
6415
6759
  Generate static HTML site with interactive diagrams (requires Docker)
6416
6760
 
@@ -6447,7 +6791,7 @@ function findTsConfig() {
6447
6791
  path6.join(process.cwd(), "..", "tsconfig.json")
6448
6792
  ];
6449
6793
  for (const loc of locations) {
6450
- if (fs6.existsSync(loc)) {
6794
+ if (fs7.existsSync(loc)) {
6451
6795
  return loc;
6452
6796
  }
6453
6797
  }
@@ -6456,7 +6800,7 @@ function findTsConfig() {
6456
6800
  function findProjectRoot() {
6457
6801
  const locations = [process.cwd(), path6.join(process.cwd(), "..")];
6458
6802
  for (const loc of locations) {
6459
- if (fs6.existsSync(path6.join(loc, "manifest.json")) || fs6.existsSync(path6.join(loc, "package.json")) || fs6.existsSync(path6.join(loc, "tsconfig.json"))) {
6803
+ if (fs7.existsSync(path6.join(loc, "manifest.json")) || fs7.existsSync(path6.join(loc, "package.json")) || fs7.existsSync(path6.join(loc, "tsconfig.json"))) {
6460
6804
  return loc;
6461
6805
  }
6462
6806
  }
@@ -6466,4 +6810,4 @@ main().catch((_error) => {
6466
6810
  process.exit(1);
6467
6811
  });
6468
6812
 
6469
- //# debugId=2FC255DE0B3BC47C64756E2164756E21
6813
+ //# debugId=4CFC761842CDF97B64756E2164756E21