@datasynx/agentic-ai-cartography 2.5.0 → 2.6.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.
package/dist/index.cjs CHANGED
@@ -149,6 +149,7 @@ __export(src_exports, {
149
149
  diffTopology: () => diffTopology,
150
150
  edgesToConnections: () => edgesToConnections,
151
151
  enrichCosts: () => enrichCosts,
152
+ entitiesToYaml: () => entitiesToYaml,
152
153
  evaluateCheck: () => evaluateCheck,
153
154
  evaluateRule: () => evaluateRule,
154
155
  evidenceLine: () => evidenceLine,
@@ -278,6 +279,7 @@ __export(src_exports, {
278
279
  startApi: () => startApi,
279
280
  stripSensitive: () => stripSensitive,
280
281
  timingSafeEqual: () => timingSafeEqual,
282
+ toBackstageEntities: () => toBackstageEntities,
281
283
  validateScanner: () => validateScanner,
282
284
  vscodeDeeplink: () => vscodeDeeplink,
283
285
  zodToJsonSchema: () => zodToJsonSchema
@@ -4690,6 +4692,9 @@ var SqliteQueryBackend = class {
4690
4692
  node(ctx, id, sessionId) {
4691
4693
  return this.db.getNode(this.resolveSession(ctx, sessionId), id);
4692
4694
  }
4695
+ edges(ctx, sessionId) {
4696
+ return this.db.getEdges(this.resolveSession(ctx, sessionId));
4697
+ }
4693
4698
  dependencies(ctx, id, q, sessionId) {
4694
4699
  const sid = this.resolveSession(ctx, sessionId);
4695
4700
  return this.db.getDependencies(sid, id, {
@@ -5932,7 +5937,7 @@ async function resolveNlQuery(db, sessionId, search, raw, opts) {
5932
5937
 
5933
5938
  // src/mcp/server.ts
5934
5939
  var SERVER_NAME = "cartography";
5935
- var SERVER_VERSION = "2.5.0";
5940
+ var SERVER_VERSION = "2.6.0";
5936
5941
  var SERVICE_TYPES = NODE_TYPE_GROUPS.web;
5937
5942
  var DATA_TYPES = NODE_TYPE_GROUPS.data;
5938
5943
  var lexicalSearch = async (db, sessionId, query, opts) => db.searchNodes(sessionId, query, { types: opts.types, limit: opts.limit }).map((node) => ({ node }));
@@ -7465,6 +7470,54 @@ function headerValue(req, name) {
7465
7470
  return v;
7466
7471
  }
7467
7472
 
7473
+ // src/backstage.ts
7474
+ var COMPONENT_TYPES = ["web_service", "container", "pod"];
7475
+ function sanitize(id) {
7476
+ return id.replace(/[^a-zA-Z0-9_]/g, "_");
7477
+ }
7478
+ function toBackstageEntities(nodes, edges, opts = {}) {
7479
+ const owner = opts.org ?? "unknown";
7480
+ return nodes.map((node) => {
7481
+ const kind = COMPONENT_TYPES.includes(node.type) ? "Component" : node.type === "api_endpoint" ? "API" : "Resource";
7482
+ const dependsOn = edges.filter((e) => e.sourceId === node.id).map((e) => `resource:default/${sanitize(e.targetId)}`);
7483
+ return {
7484
+ apiVersion: "backstage.io/v1alpha1",
7485
+ kind,
7486
+ metadata: {
7487
+ name: sanitize(node.id),
7488
+ annotations: {
7489
+ "cartography/discovered-at": node.discoveredAt,
7490
+ "cartography/confidence": String(node.confidence)
7491
+ }
7492
+ },
7493
+ spec: {
7494
+ type: node.type,
7495
+ lifecycle: "production",
7496
+ owner: node.owner ?? owner,
7497
+ ...dependsOn.length > 0 ? { dependsOn } : {}
7498
+ }
7499
+ };
7500
+ });
7501
+ }
7502
+ function entitiesToYaml(entities) {
7503
+ return entities.map((e) => {
7504
+ const lines = [
7505
+ `apiVersion: ${e.apiVersion}`,
7506
+ `kind: ${e.kind}`,
7507
+ `metadata:`,
7508
+ ` name: ${e.metadata.name}`,
7509
+ ` annotations:`,
7510
+ ...Object.entries(e.metadata.annotations).map(([k, v]) => ` ${k}: "${v}"`),
7511
+ `spec:`,
7512
+ ` type: ${e.spec.type}`,
7513
+ ` lifecycle: ${e.spec.lifecycle}`,
7514
+ ` owner: ${e.spec.owner}`,
7515
+ ...e.spec.dependsOn && e.spec.dependsOn.length > 0 ? [" dependsOn:", ...e.spec.dependsOn.map((d) => ` - ${d}`)] : []
7516
+ ];
7517
+ return lines.join("\n");
7518
+ }).join("\n---\n");
7519
+ }
7520
+
7468
7521
  // src/api/schemas.ts
7469
7522
  var import_zod8 = require("zod");
7470
7523
  var DIRECTIONS = ["downstream", "upstream", "both"];
@@ -7600,6 +7653,21 @@ var ErrorResponse = import_zod8.z.object({
7600
7653
  error: import_zod8.z.string(),
7601
7654
  code: import_zod8.z.string().optional()
7602
7655
  });
7656
+ var BackstageEntitySchema = import_zod8.z.object({
7657
+ apiVersion: import_zod8.z.literal("backstage.io/v1alpha1"),
7658
+ kind: import_zod8.z.enum(["Component", "API", "Resource"]),
7659
+ metadata: import_zod8.z.object({
7660
+ name: import_zod8.z.string(),
7661
+ annotations: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.string())
7662
+ }),
7663
+ spec: import_zod8.z.object({
7664
+ type: import_zod8.z.string(),
7665
+ lifecycle: import_zod8.z.string(),
7666
+ owner: import_zod8.z.string(),
7667
+ dependsOn: import_zod8.z.array(import_zod8.z.string()).optional()
7668
+ })
7669
+ });
7670
+ var BackstageCatalogResponse = import_zod8.z.object({ entities: import_zod8.z.array(BackstageEntitySchema) });
7603
7671
  var API_SCHEMAS = {
7604
7672
  Node: NodeSchema2,
7605
7673
  Edge: EdgeSchema2,
@@ -7611,10 +7679,13 @@ var API_SCHEMAS = {
7611
7679
  Session: SessionSchema,
7612
7680
  Sessions: SessionsResponse,
7613
7681
  Health: HealthResponse,
7614
- Error: ErrorResponse
7682
+ Error: ErrorResponse,
7683
+ BackstageEntity: BackstageEntitySchema,
7684
+ BackstageCatalog: BackstageCatalogResponse
7615
7685
  };
7616
7686
 
7617
7687
  // src/api/rest.ts
7688
+ var BACKSTAGE_NODE_CAP = 1e3;
7618
7689
  function toApiNode(n) {
7619
7690
  const out = { id: n.id, type: n.type, name: n.name, confidence: n.confidence, tags: n.tags };
7620
7691
  if (n.domain !== void 0) out["domain"] = n.domain;
@@ -7749,6 +7820,14 @@ function handleHealth(ctx, d) {
7749
7820
  const h = d.backend.health(ctx);
7750
7821
  return ok(validateOut(HealthResponse, { status: "ok", version: d.version, store: h.store, sessions: h.sessions }));
7751
7822
  }
7823
+ function handleBackstageCatalog(ctx, d) {
7824
+ return guard(() => {
7825
+ const page = d.backend.nodes(ctx, { limit: BACKSTAGE_NODE_CAP });
7826
+ const edges = d.backend.edges(ctx);
7827
+ const entities = toBackstageEntities(page.nodes, edges, { org: ctx.tenant });
7828
+ return ok(validateOut(BackstageCatalogResponse, { entities }));
7829
+ });
7830
+ }
7752
7831
 
7753
7832
  // src/api/openapi.ts
7754
7833
  function defOf(schema) {
@@ -7905,6 +7984,13 @@ function buildOpenApiDocument(opts) {
7905
7984
  parameters: [TENANT_PARAM],
7906
7985
  responses: { "200": ok2("Sessions", "Sessions"), ...errorResponses() }
7907
7986
  }
7987
+ },
7988
+ "/v1/backstage/catalog": {
7989
+ get: {
7990
+ summary: "The tenant topology as Backstage catalog entities (live data source, 4.6)",
7991
+ parameters: [SESSION_PARAM, TENANT_PARAM],
7992
+ responses: { "200": ok2("BackstageCatalog", "Backstage catalog entities"), ...errorResponses() }
7993
+ }
7908
7994
  }
7909
7995
  }
7910
7996
  };
@@ -8419,6 +8505,8 @@ function dispatchRest(ctx, path, url, deps) {
8419
8505
  return handleDiff(ctx, url, deps);
8420
8506
  case "/v1/sessions":
8421
8507
  return handleSessions(ctx, deps);
8508
+ case "/v1/backstage/catalog":
8509
+ return handleBackstageCatalog(ctx, deps);
8422
8510
  default: {
8423
8511
  const m = DEPENDENCIES_RE.exec(path);
8424
8512
  if (m) return handleDependencies(ctx, decodeURIComponent(m[1]), url, deps);
@@ -9925,7 +10013,7 @@ var MERMAID_CLASSES = {
9925
10013
  saas_tool: "fill:#2a1a2a,stroke:#9a3a9a,color:#daf",
9926
10014
  unknown: "fill:#2a2a2a,stroke:#5a5a5a,color:#aaa"
9927
10015
  };
9928
- function sanitize(id) {
10016
+ function sanitize2(id) {
9929
10017
  return id.replace(/[^a-zA-Z0-9_]/g, "_");
9930
10018
  }
9931
10019
  function nodeLabel(node) {
@@ -9967,14 +10055,14 @@ function generateTopologyMermaid(nodes, edges) {
9967
10055
  const label = LAYER_LABELS[layerKey] ?? layerKey;
9968
10056
  lines.push(` subgraph ${layerKey}["${label}"]`);
9969
10057
  for (const node of layerNodes) {
9970
- lines.push(` ${sanitize(node.id)}${nodeLabel(node)}:::${node.type.replace(/_/g, "")}`);
10058
+ lines.push(` ${sanitize2(node.id)}${nodeLabel(node)}:::${node.type.replace(/_/g, "")}`);
9971
10059
  }
9972
10060
  lines.push(" end");
9973
10061
  lines.push("");
9974
10062
  }
9975
10063
  for (const edge of edges) {
9976
- const src = sanitize(edge.sourceId);
9977
- const tgt = sanitize(edge.targetId);
10064
+ const src = sanitize2(edge.sourceId);
10065
+ const tgt = sanitize2(edge.targetId);
9978
10066
  const label = EDGE_LABELS[edge.relationship] ?? edge.relationship;
9979
10067
  const arrow = edge.confidence < 0.6 ? `-. "${label}" .->` : `-->|"${label}"|`;
9980
10068
  lines.push(` ${src} ${arrow} ${tgt}`);
@@ -10000,12 +10088,12 @@ function generateDependencyMermaid(nodes, edges) {
10000
10088
  }
10001
10089
  lines.push("");
10002
10090
  for (const node of usedNodes) {
10003
- lines.push(` ${sanitize(node.id)}${nodeLabel(node)}:::${node.type.replace(/_/g, "")}`);
10091
+ lines.push(` ${sanitize2(node.id)}${nodeLabel(node)}:::${node.type.replace(/_/g, "")}`);
10004
10092
  }
10005
10093
  lines.push("");
10006
10094
  for (const edge of depEdges) {
10007
10095
  const label = EDGE_LABELS[edge.relationship] ?? edge.relationship;
10008
- lines.push(` ${sanitize(edge.sourceId)} -->|"${label}"| ${sanitize(edge.targetId)}`);
10096
+ lines.push(` ${sanitize2(edge.sourceId)} -->|"${label}"| ${sanitize2(edge.targetId)}`);
10009
10097
  }
10010
10098
  return lines.join("\n");
10011
10099
  }
@@ -10056,44 +10144,21 @@ function generateDiffMermaid(diff) {
10056
10144
  ensureEndpoint(e.targetId);
10057
10145
  }
10058
10146
  for (const { node, cls, suffix } of entries.values()) {
10059
- lines.push(` ${sanitize(node.id)}${diffNodeLabel(node, suffix)}:::${cls}`);
10147
+ lines.push(` ${sanitize2(node.id)}${diffNodeLabel(node, suffix)}:::${cls}`);
10060
10148
  }
10061
10149
  lines.push("");
10062
10150
  for (const e of diff.edges.added) {
10063
10151
  const label = EDGE_LABELS[e.relationship] ?? e.relationship;
10064
- lines.push(` ${sanitize(e.sourceId)} ==>|"+ ${label}"| ${sanitize(e.targetId)}`);
10152
+ lines.push(` ${sanitize2(e.sourceId)} ==>|"+ ${label}"| ${sanitize2(e.targetId)}`);
10065
10153
  }
10066
10154
  for (const e of diff.edges.removed) {
10067
10155
  const label = EDGE_LABELS[e.relationship] ?? e.relationship;
10068
- lines.push(` ${sanitize(e.sourceId)} -.->|"- ${label}"| ${sanitize(e.targetId)}`);
10156
+ lines.push(` ${sanitize2(e.sourceId)} -.->|"- ${label}"| ${sanitize2(e.targetId)}`);
10069
10157
  }
10070
10158
  return lines.join("\n");
10071
10159
  }
10072
10160
  function exportBackstageYAML(nodes, edges, org) {
10073
- const owner = org ?? "unknown";
10074
- const docs = [];
10075
- for (const node of nodes) {
10076
- const isComponent = ["web_service", "container", "pod"].includes(node.type);
10077
- const isAPI = node.type === "api_endpoint";
10078
- const kind = isComponent ? "Component" : isAPI ? "API" : "Resource";
10079
- const deps = edges.filter((e) => e.sourceId === node.id).map((e) => ` - resource:default/${sanitize(e.targetId)}`);
10080
- const doc = [
10081
- `apiVersion: backstage.io/v1alpha1`,
10082
- `kind: ${kind}`,
10083
- `metadata:`,
10084
- ` name: ${sanitize(node.id)}`,
10085
- ` annotations:`,
10086
- ` cartography/discovered-at: "${node.discoveredAt}"`,
10087
- ` cartography/confidence: "${node.confidence}"`,
10088
- `spec:`,
10089
- ` type: ${node.type}`,
10090
- ` lifecycle: production`,
10091
- ` owner: ${node.owner ?? owner}`,
10092
- ...deps.length > 0 ? [" dependsOn:", ...deps] : []
10093
- ].join("\n");
10094
- docs.push(doc);
10095
- }
10096
- return docs.join("\n---\n");
10161
+ return entitiesToYaml(toBackstageEntities(nodes, edges, org !== void 0 ? { org } : {}));
10097
10162
  }
10098
10163
  function exportJSON(db, sessionId) {
10099
10164
  const nodes = db.getNodes(sessionId);
@@ -11898,6 +11963,7 @@ function checkClaudePrerequisites() {
11898
11963
  diffTopology,
11899
11964
  edgesToConnections,
11900
11965
  enrichCosts,
11966
+ entitiesToYaml,
11901
11967
  evaluateCheck,
11902
11968
  evaluateRule,
11903
11969
  evidenceLine,
@@ -12027,6 +12093,7 @@ function checkClaudePrerequisites() {
12027
12093
  startApi,
12028
12094
  stripSensitive,
12029
12095
  timingSafeEqual,
12096
+ toBackstageEntities,
12030
12097
  validateScanner,
12031
12098
  vscodeDeeplink,
12032
12099
  zodToJsonSchema