@datasynx/agentic-ai-cartography 2.2.0 → 2.3.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
@@ -45,7 +45,10 @@ __export(src_exports, {
45
45
  DriftConfigSchema: () => DriftConfigSchema,
46
46
  INGEST_SCHEMA_VERSION: () => INGEST_SCHEMA_VERSION,
47
47
  IngestEnvelopeSchema: () => IngestEnvelopeSchema,
48
+ InvalidTenantError: () => InvalidTenantError,
49
+ LOOPBACK_HOSTS: () => LOOPBACK_HOSTS2,
48
50
  MCP_BIN: () => MCP_BIN,
51
+ NotFoundError: () => NotFoundError,
49
52
  PACKAGE_NAME: () => PACKAGE_NAME,
50
53
  PERSONAL: () => PERSONAL,
51
54
  PORT_MAP: () => PORT_MAP,
@@ -56,26 +59,33 @@ __export(src_exports, {
56
59
  RuleCheckSchema: () => RuleCheckSchema,
57
60
  RulesetSchema: () => RulesetSchema,
58
61
  SCAN_ARG_PATTERNS: () => SCAN_ARG_PATTERNS,
62
+ SDL: () => SDL,
59
63
  SEVERITY_WEIGHT: () => SEVERITY_WEIGHT,
60
64
  SHARING_LEVELS: () => SHARING_LEVELS,
61
65
  ScannerRegistry: () => ScannerRegistry,
62
66
  ScannerShape: () => ScannerShape,
63
67
  SharingLevelSchema: () => SharingLevelSchema,
68
+ SqliteQueryBackend: () => SqliteQueryBackend,
64
69
  SqliteStoreBackend: () => SqliteStoreBackend,
65
70
  StdoutSink: () => StdoutSink,
71
+ TENANT_HEADER: () => TENANT_HEADER,
66
72
  VectorStore: () => VectorStore,
67
73
  WebhookSink: () => WebhookSink,
68
74
  applyInstall: () => applyInstall,
69
75
  applySharingLevel: () => applySharingLevel,
70
76
  assertReadOnly: () => assertReadOnly,
77
+ assertSafeBind: () => assertSafeBind,
71
78
  assertSafeScanArg: () => assertSafeScanArg,
72
79
  assignColors: () => assignColors,
80
+ bearerToken: () => bearerToken,
73
81
  bookmarksScanner: () => bookmarksScanner,
74
82
  buildCartographyToolHandlers: () => buildCartographyToolHandlers,
75
83
  buildMapData: () => buildMapData,
84
+ buildOpenApiDocument: () => buildOpenApiDocument,
76
85
  buildReport: () => buildReport,
77
86
  buildSinks: () => buildSinks,
78
87
  centralDbFromEnv: () => centralDbFromEnv,
88
+ checkBearer: () => checkBearer,
79
89
  checkPrerequisites: () => checkPrerequisites,
80
90
  checkReadOnly: () => checkReadOnly,
81
91
  clampText: () => clampText,
@@ -103,10 +113,12 @@ __export(src_exports, {
103
113
  createOpenAIProvider: () => createOpenAIProvider,
104
114
  createScanRunner: () => createScanRunner,
105
115
  createSemanticSearch: () => createSemanticSearch,
116
+ createSqliteQueryBackend: () => createSqliteQueryBackend,
106
117
  currentOs: () => currentOs,
107
118
  cursorDeeplink: () => cursorDeeplink,
108
119
  databasesScanner: () => databasesScanner,
109
120
  deepMerge: () => deepMerge,
121
+ defaultAllowedHosts: () => defaultAllowedHosts,
110
122
  defaultConfig: () => defaultConfig,
111
123
  defaultContext: () => defaultContext,
112
124
  defaultProviderRegistry: () => defaultProviderRegistry,
@@ -123,6 +135,7 @@ __export(src_exports, {
123
135
  evaluateCheck: () => evaluateCheck,
124
136
  evaluateRule: () => evaluateRule,
125
137
  evidenceLine: () => evidenceLine,
138
+ executeGraphql: () => executeGraphql,
126
139
  executeNlQuery: () => executeNlQuery,
127
140
  exportAll: () => exportAll,
128
141
  exportBackstageYAML: () => exportBackstageYAML,
@@ -143,6 +156,7 @@ __export(src_exports, {
143
156
  getRuleset: () => getRuleset,
144
157
  globalId: () => globalId,
145
158
  groupByDomain: () => groupByDomain,
159
+ handleGraphqlGet: () => handleGraphqlGet,
146
160
  hexCorners: () => hexCorners,
147
161
  hexDistance: () => hexDistance,
148
162
  hexNeighbors: () => hexNeighbors,
@@ -153,6 +167,7 @@ __export(src_exports, {
153
167
  hostname: () => hostname,
154
168
  ingestEnvelope: () => ingestEnvelope,
155
169
  installedAppsScanner: () => installedAppsScanner,
170
+ isLoopbackHost: () => isLoopbackHost,
156
171
  isPersonalHost: () => isPersonalHost,
157
172
  isReadOnlyCommand: () => isReadOnlyCommand,
158
173
  isRemembered: () => isRemembered,
@@ -181,6 +196,7 @@ __export(src_exports, {
181
196
  normalizeTenant: () => normalizeTenant,
182
197
  orgKeyPath: () => orgKeyPath,
183
198
  osUser: () => osUser,
199
+ parseApiArgs: () => parseApiArgs,
184
200
  parseComposeDeps: () => parseComposeDeps,
185
201
  parseConfig: () => parseConfig,
186
202
  parseConnectionString: () => parseConnectionString,
@@ -206,10 +222,12 @@ __export(src_exports, {
206
222
  resolveEffectiveLevel: () => resolveEffectiveLevel,
207
223
  resolveNlQuery: () => resolveNlQuery,
208
224
  resolveSharingLevel: () => resolveSharingLevel,
225
+ resolveTenant: () => resolveTenant,
209
226
  revalidateAnonymized: () => revalidateAnonymized,
210
227
  reversalKey: () => reversalKey,
211
228
  reversePseudonym: () => reversePseudonym,
212
229
  rotateOrgKey: () => rotateOrgKey,
230
+ runApi: () => runApi,
213
231
  runDiscovery: () => runDiscovery,
214
232
  runDrift: () => runDrift,
215
233
  runHttp: () => runHttp,
@@ -232,9 +250,12 @@ __export(src_exports, {
232
250
  shareHash: () => shareHash,
233
251
  splitSegments: () => splitSegments,
234
252
  stableStringify: () => stableStringify,
253
+ startApi: () => startApi,
235
254
  stripSensitive: () => stripSensitive,
255
+ timingSafeEqual: () => timingSafeEqual,
236
256
  validateScanner: () => validateScanner,
237
- vscodeDeeplink: () => vscodeDeeplink
257
+ vscodeDeeplink: () => vscodeDeeplink,
258
+ zodToJsonSchema: () => zodToJsonSchema
238
259
  });
239
260
  module.exports = __toCommonJS(src_exports);
240
261
 
@@ -370,6 +391,8 @@ var DOMAIN_PALETTE = [
370
391
  "#5eead4"
371
392
  ];
372
393
  var DRIFT_FIELDS = ["type", "name", "domain", "subDomain", "qualityScore", "metadata", "tags", "owner", "cost"];
394
+ var ANOMALY_KINDS = ["orphan", "shadow-it"];
395
+ var ANOMALY_SEVERITIES = ["low", "medium", "high"];
373
396
  var DEFAULT_ANOMALY_THRESHOLDS = {
374
397
  orphanWeakDegree: 1,
375
398
  shadowConfidence: 0.4,
@@ -1515,8 +1538,8 @@ var cloudGcpScanner = {
1515
1538
  allowedCommands: ["gcloud"],
1516
1539
  detect: (ctx) => Boolean((ctx.commandExists ?? commandExists)("gcloud")),
1517
1540
  async scan(ctx) {
1518
- const { project } = parseScanHint(ctx.hint);
1519
- const pf = project ? ` --project ${project}` : "";
1541
+ const { project: project2 } = parseScanHint(ctx.hint);
1542
+ const pf = project2 ? ` --project ${project2}` : "";
1520
1543
  const runG = createScanRunner((c) => ctx.run(c, { timeout: 2e4 }), { threshold: 3 });
1521
1544
  const nodes = [];
1522
1545
  const edges = [];
@@ -2204,9 +2227,9 @@ async function buildCartographyToolHandlers(db, sessionId, opts = {}) {
2204
2227
  tool("scan_gcp_resources", "Scan Google Cloud Platform via gcloud CLI \u2014 100% readonly (list, describe)", {
2205
2228
  project: import_zod2.z.string().regex(SCAN_ARG_PATTERNS["gcp-project"], "invalid GCP project id").optional().describe("GCP Project ID \u2014 default: current gcloud project")
2206
2229
  }, async (args) => {
2207
- const project = args["project"];
2208
- if (project) assertSafeScanArg("gcp-project", project);
2209
- return runScannerTool(cloudGcpScanner, project ? `project=${project}` : "");
2230
+ const project2 = args["project"];
2231
+ if (project2) assertSafeScanArg("gcp-project", project2);
2232
+ return runScannerTool(cloudGcpScanner, project2 ? `project=${project2}` : "");
2210
2233
  }, { annotations: READ_SCAN }),
2211
2234
  tool("scan_azure_resources", "Scan Azure infrastructure via az CLI \u2014 100% readonly (list, show)", {
2212
2235
  subscription: import_zod2.z.string().regex(SCAN_ARG_PATTERNS["azure-subscription"], "invalid Azure subscription id").optional().describe("Azure Subscription ID"),
@@ -2358,14 +2381,14 @@ async function buildCartographyToolHandlers(db, sessionId, opts = {}) {
2358
2381
  "neon"
2359
2382
  ];
2360
2383
  const found = [];
2361
- const notFound = [];
2384
+ const notFound2 = [];
2362
2385
  for (const t of knownTools) {
2363
2386
  const r = commandExists(t);
2364
2387
  if (r) found.push(`${t}: ${r}`);
2365
- else notFound.push(t);
2388
+ else notFound2.push(t);
2366
2389
  }
2367
2390
  results["TOOLS_FOUND"] = found.join("\n") || "(none found)";
2368
- results["TOOLS_NOT_FOUND"] = notFound.join(", ");
2391
+ results["TOOLS_NOT_FOUND"] = notFound2.join(", ");
2369
2392
  if (hint) {
2370
2393
  const terms = hint.split(/[\s,]+/).filter(Boolean);
2371
2394
  const hintResults = [];
@@ -4502,6 +4525,86 @@ var SqliteStoreBackend = class {
4502
4525
  }
4503
4526
  };
4504
4527
 
4528
+ // src/store/query.ts
4529
+ var NotFoundError = class extends Error {
4530
+ constructor(message) {
4531
+ super(message);
4532
+ this.name = "NotFoundError";
4533
+ }
4534
+ };
4535
+ var MAX_NODE_LIMIT = 1e3;
4536
+ var MAX_DEPTH = 64;
4537
+ function clamp(value, min, max) {
4538
+ return Math.floor(Math.max(min, Math.min(value, max)));
4539
+ }
4540
+ var SqliteQueryBackend = class {
4541
+ constructor(db, defaultSession = "latest") {
4542
+ this.db = db;
4543
+ this.defaultSession = defaultSession;
4544
+ }
4545
+ /**
4546
+ * Resolve the session id for a request, scoped to `ctx.tenant`. An explicit id must
4547
+ * belong to the tenant or it resolves to undefined (cross-tenant isolation); else the
4548
+ * newest `discover` session for the tenant. Mirrors `resolveSession` in the MCP server.
4549
+ */
4550
+ resolveSession(ctx, sessionId) {
4551
+ const requested = sessionId ?? (this.defaultSession === "latest" ? void 0 : this.defaultSession);
4552
+ if (requested) {
4553
+ const s = this.db.getSession(requested);
4554
+ if (s && s.tenant === ctx.tenant) return s.id;
4555
+ throw new NotFoundError(`session not found`);
4556
+ }
4557
+ const latest = this.db.getLatestSession("discover", ctx.tenant) ?? this.db.getLatestSession(void 0, ctx.tenant);
4558
+ if (!latest) throw new NotFoundError(`no session available`);
4559
+ return latest.id;
4560
+ }
4561
+ summary(ctx, sessionId) {
4562
+ return this.db.getGraphSummary(this.resolveSession(ctx, sessionId));
4563
+ }
4564
+ nodes(ctx, q, sessionId) {
4565
+ const sid = this.resolveSession(ctx, sessionId);
4566
+ const limit = clamp(q.limit ?? 100, 1, MAX_NODE_LIMIT);
4567
+ const offset = Math.floor(Math.max(0, q.offset ?? 0));
4568
+ const total = this.db.getNodeCount(sid);
4569
+ if (q.search) {
4570
+ const nodes2 = this.db.searchNodes(sid, q.search, { ...q.types ? { types: q.types } : {}, limit });
4571
+ return { nodes: nodes2, total: nodes2.length, limit, offset: 0 };
4572
+ }
4573
+ const nodes = this.db.getNodes(sid, { limit, offset });
4574
+ return { nodes, total, limit, offset };
4575
+ }
4576
+ node(ctx, id, sessionId) {
4577
+ return this.db.getNode(this.resolveSession(ctx, sessionId), id);
4578
+ }
4579
+ dependencies(ctx, id, q, sessionId) {
4580
+ const sid = this.resolveSession(ctx, sessionId);
4581
+ return this.db.getDependencies(sid, id, {
4582
+ direction: q.direction ?? "downstream",
4583
+ maxDepth: clamp(q.maxDepth ?? 8, 1, MAX_DEPTH)
4584
+ });
4585
+ }
4586
+ diff(ctx, base, current) {
4587
+ for (const id of [base, current]) {
4588
+ const s = this.db.getSession(id);
4589
+ if (!s || s.tenant !== ctx.tenant) throw new NotFoundError(`session not found`);
4590
+ }
4591
+ try {
4592
+ return this.db.diffSessions(base, current);
4593
+ } catch (err) {
4594
+ throw new NotFoundError(err instanceof Error ? err.message : "diff failed");
4595
+ }
4596
+ }
4597
+ sessions(ctx) {
4598
+ return this.db.getSessions(ctx.tenant);
4599
+ }
4600
+ health(ctx) {
4601
+ return { store: "sqlite", sessions: this.db.getSessions(ctx.tenant).length };
4602
+ }
4603
+ };
4604
+ function createSqliteQueryBackend(db, defaultSession = "latest") {
4605
+ return new SqliteQueryBackend(db, defaultSession);
4606
+ }
4607
+
4505
4608
  // src/central/merge.ts
4506
4609
  function computeIdentity(org, node) {
4507
4610
  return {
@@ -5532,7 +5635,7 @@ async function resolveNlQuery(db, sessionId, search, raw, opts) {
5532
5635
 
5533
5636
  // src/mcp/server.ts
5534
5637
  var SERVER_NAME = "cartography";
5535
- var SERVER_VERSION = "2.2.0";
5638
+ var SERVER_VERSION = "2.3.0";
5536
5639
  var SERVICE_TYPES = NODE_TYPE_GROUPS.web;
5537
5640
  var DATA_TYPES = NODE_TYPE_GROUPS.data;
5538
5641
  var lexicalSearch = async (db, sessionId, query, opts) => db.searchNodes(sessionId, query, { types: opts.types, limit: opts.limit }).map((node) => ({ node }));
@@ -6033,6 +6136,50 @@ var import_node_crypto5 = require("crypto");
6033
6136
  var import_node_http = __toESM(require("http"), 1);
6034
6137
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
6035
6138
  var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
6139
+
6140
+ // src/api/auth.ts
6141
+ var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
6142
+ function isLoopbackHost(host2) {
6143
+ return LOOPBACK_HOSTS2.has(host2);
6144
+ }
6145
+ function timingSafeEqual(a, b) {
6146
+ if (a.length !== b.length) return false;
6147
+ let diff = 0;
6148
+ for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
6149
+ return diff === 0;
6150
+ }
6151
+ function bearerToken(header) {
6152
+ if (!header) return void 0;
6153
+ const trimmed = header.trim();
6154
+ if (trimmed.length < 7 || trimmed.slice(0, 6).toLowerCase() !== "bearer") return void 0;
6155
+ const rest = trimmed.slice(6);
6156
+ if (!/^\s/.test(rest)) return void 0;
6157
+ const token = rest.trimStart();
6158
+ return token.length > 0 ? token : void 0;
6159
+ }
6160
+ function checkBearer(authorizationHeader, token) {
6161
+ if (!token) return true;
6162
+ const provided = bearerToken(authorizationHeader);
6163
+ return provided !== void 0 && timingSafeEqual(provided, token);
6164
+ }
6165
+ function assertSafeBind(opts) {
6166
+ if (isLoopbackHost(opts.host)) return;
6167
+ if (opts.allowedHosts === void 0) {
6168
+ throw new Error(
6169
+ `Refusing to bind a non-loopback host (${opts.host}) without an explicit allowedHosts allowlist. Pass { allowedHosts: ['your.public.host:port'] } to opt in, or bind 127.0.0.1 for local-only use.`
6170
+ );
6171
+ }
6172
+ if (!opts.token) {
6173
+ throw new Error(
6174
+ `Refusing to bind a non-loopback host (${opts.host}) without an auth token. Pass { token } (or --token / CARTOGRAPHY_HTTP_TOKEN) so requests must carry 'Authorization: Bearer <token>'.`
6175
+ );
6176
+ }
6177
+ }
6178
+ function defaultAllowedHosts(host2, port) {
6179
+ return [`${host2}:${port}`, `localhost:${port}`, `127.0.0.1:${port}`];
6180
+ }
6181
+
6182
+ // src/mcp/transports.ts
6036
6183
  async function runStdio(server) {
6037
6184
  const transport = new import_stdio.StdioServerTransport();
6038
6185
  await server.connect(transport);
@@ -6061,17 +6208,6 @@ async function readCappedBody(req, cap) {
6061
6208
  return { overflow: false, value: void 0 };
6062
6209
  }
6063
6210
  }
6064
- function timingSafeEqual(a, b) {
6065
- if (a.length !== b.length) return false;
6066
- let diff = 0;
6067
- for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
6068
- return diff === 0;
6069
- }
6070
- function bearerToken(header) {
6071
- if (!header) return void 0;
6072
- const m = /^Bearer\s+(.+)$/i.exec(header.trim());
6073
- return m ? m[1] : void 0;
6074
- }
6075
6211
  async function readJsonBody(req) {
6076
6212
  const chunks = [];
6077
6213
  for await (const chunk of req) chunks.push(chunk);
@@ -6082,22 +6218,11 @@ async function readJsonBody(req) {
6082
6218
  return void 0;
6083
6219
  }
6084
6220
  }
6085
- var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
6086
6221
  async function runHttp(factory, opts = {}) {
6087
6222
  const host2 = opts.host ?? "127.0.0.1";
6088
6223
  const port = opts.port ?? 3737;
6089
- const isLoopback = LOOPBACK_HOSTS2.has(host2);
6090
- if (!isLoopback && opts.allowedHosts === void 0) {
6091
- throw new Error(
6092
- `Refusing to bind a non-loopback host (${host2}) without an explicit allowedHosts allowlist. Pass { allowedHosts: ['your.public.host:port'] } to opt in, or bind 127.0.0.1 for local-only use.`
6093
- );
6094
- }
6095
- if (!isLoopback && !opts.token) {
6096
- throw new Error(
6097
- `Refusing to bind a non-loopback host (${host2}) without an auth token. Pass { token } (or --token / CARTOGRAPHY_HTTP_TOKEN) so requests must carry 'Authorization: Bearer <token>'.`
6098
- );
6099
- }
6100
- const allowedHosts = opts.allowedHosts ?? [`${host2}:${port}`, `localhost:${port}`, `127.0.0.1:${port}`];
6224
+ assertSafeBind({ host: host2, port, ...opts.allowedHosts ? { allowedHosts: opts.allowedHosts } : {}, ...opts.token ? { token: opts.token } : {} });
6225
+ const allowedHosts = opts.allowedHosts ?? defaultAllowedHosts(host2, port);
6101
6226
  const token = opts.token;
6102
6227
  const transports = /* @__PURE__ */ new Map();
6103
6228
  const httpServer = import_node_http.default.createServer(async (req, res) => {
@@ -6108,12 +6233,9 @@ async function runHttp(factory, opts = {}) {
6108
6233
  res.writeHead(404, { "content-type": "application/json" }).end('{"error":"not found"}');
6109
6234
  return;
6110
6235
  }
6111
- if (token) {
6112
- const provided = bearerToken(req.headers["authorization"]);
6113
- if (!provided || !timingSafeEqual(provided, token)) {
6114
- res.writeHead(401, { "content-type": "application/json", "www-authenticate": "Bearer" }).end('{"error":"unauthorized"}');
6115
- return;
6116
- }
6236
+ if (!checkBearer(req.headers["authorization"], token)) {
6237
+ res.writeHead(401, { "content-type": "application/json", "www-authenticate": "Bearer" }).end('{"error":"unauthorized"}');
6238
+ return;
6117
6239
  }
6118
6240
  if (isIngest) {
6119
6241
  const hostHeader = (req.headers["host"] ?? "").toLowerCase();
@@ -6167,7 +6289,7 @@ async function runHttp(factory, opts = {}) {
6167
6289
  if (!res.headersSent) res.writeHead(500, { "content-type": "application/json" }).end('{"error":"internal error"}');
6168
6290
  }
6169
6291
  });
6170
- await new Promise((resolve2) => httpServer.listen(port, host2, resolve2));
6292
+ await new Promise((resolve3) => httpServer.listen(port, host2, resolve3));
6171
6293
  return httpServer;
6172
6294
  }
6173
6295
 
@@ -6349,8 +6471,8 @@ async function createSemanticSearch(db, embedder, opts = {}) {
6349
6471
  return lexicalSearch2();
6350
6472
  }
6351
6473
  const store = new VectorStore(db, provider);
6352
- const ok = await store.init();
6353
- if (!ok) {
6474
+ const ok3 = await store.init();
6475
+ if (!ok3) {
6354
6476
  log2?.("semantic search: vector store unavailable (sqlite-vec not installed or failed to load) \u2014 using lexical search");
6355
6477
  return lexicalSearch2();
6356
6478
  }
@@ -6959,6 +7081,1038 @@ function localDiscoveryFn(registry, plugins) {
6959
7081
  };
6960
7082
  }
6961
7083
 
7084
+ // src/api/server.ts
7085
+ var import_node_http2 = __toESM(require("http"), 1);
7086
+
7087
+ // src/api/tenant.ts
7088
+ var TENANT_HEADER = "x-cartograph-tenant";
7089
+ var InvalidTenantError = class extends Error {
7090
+ constructor() {
7091
+ super("invalid tenant");
7092
+ this.name = "InvalidTenantError";
7093
+ }
7094
+ };
7095
+ function resolveTenant(req, url, opts = {}) {
7096
+ const headerName = (opts.header ?? TENANT_HEADER).toLowerCase();
7097
+ const raw = headerValue(req, headerName) ?? url.searchParams.get("tenant") ?? void 0;
7098
+ if (raw === void 0 || raw === "") {
7099
+ return { tenant: opts.defaultTenant ?? DEFAULT_TENANT };
7100
+ }
7101
+ if (raw.trim().length > 128) {
7102
+ throw new InvalidTenantError();
7103
+ }
7104
+ const normalized = normalizeTenant(raw);
7105
+ if (normalized === DEFAULT_TENANT && raw.trim() !== DEFAULT_TENANT) {
7106
+ throw new InvalidTenantError();
7107
+ }
7108
+ return { tenant: normalized };
7109
+ }
7110
+ function headerValue(req, name) {
7111
+ const v = req.headers[name];
7112
+ if (Array.isArray(v)) return v[0];
7113
+ return v;
7114
+ }
7115
+
7116
+ // src/api/schemas.ts
7117
+ var import_zod8 = require("zod");
7118
+ var DIRECTIONS = ["downstream", "upstream", "both"];
7119
+ var CostSchema = import_zod8.z.object({
7120
+ amount: import_zod8.z.number(),
7121
+ currency: import_zod8.z.string(),
7122
+ period: import_zod8.z.enum(COST_PERIODS),
7123
+ source: import_zod8.z.string().optional()
7124
+ });
7125
+ var NodeSchema2 = import_zod8.z.object({
7126
+ id: import_zod8.z.string(),
7127
+ type: import_zod8.z.string(),
7128
+ name: import_zod8.z.string(),
7129
+ confidence: import_zod8.z.number(),
7130
+ domain: import_zod8.z.string().optional(),
7131
+ subDomain: import_zod8.z.string().optional(),
7132
+ qualityScore: import_zod8.z.number().optional(),
7133
+ owner: import_zod8.z.string().optional(),
7134
+ cost: CostSchema.optional(),
7135
+ tags: import_zod8.z.array(import_zod8.z.string())
7136
+ });
7137
+ var EdgeSchema2 = import_zod8.z.object({
7138
+ sourceId: import_zod8.z.string(),
7139
+ targetId: import_zod8.z.string(),
7140
+ relationship: import_zod8.z.string(),
7141
+ confidence: import_zod8.z.number(),
7142
+ evidence: import_zod8.z.string()
7143
+ });
7144
+ var AnomalySchema = import_zod8.z.object({
7145
+ nodeId: import_zod8.z.string(),
7146
+ kind: import_zod8.z.enum(ANOMALY_KINDS),
7147
+ severity: import_zod8.z.enum(ANOMALY_SEVERITIES),
7148
+ reason: import_zod8.z.string()
7149
+ });
7150
+ var TopConnectedSchema = import_zod8.z.object({
7151
+ id: import_zod8.z.string(),
7152
+ name: import_zod8.z.string(),
7153
+ type: import_zod8.z.string(),
7154
+ degree: import_zod8.z.number().int()
7155
+ });
7156
+ var CostByDomainSchema = import_zod8.z.object({
7157
+ domain: import_zod8.z.string(),
7158
+ currency: import_zod8.z.string(),
7159
+ period: import_zod8.z.string(),
7160
+ total: import_zod8.z.number(),
7161
+ nodes: import_zod8.z.number().int()
7162
+ });
7163
+ var CostByOwnerSchema = import_zod8.z.object({
7164
+ owner: import_zod8.z.string(),
7165
+ currency: import_zod8.z.string(),
7166
+ period: import_zod8.z.string(),
7167
+ total: import_zod8.z.number(),
7168
+ nodes: import_zod8.z.number().int()
7169
+ });
7170
+ var SummaryResponse = import_zod8.z.object({
7171
+ sessionId: import_zod8.z.string(),
7172
+ totals: import_zod8.z.object({ nodes: import_zod8.z.number().int(), edges: import_zod8.z.number().int() }),
7173
+ nodesByType: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.number().int()),
7174
+ nodesByDomain: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.number().int()),
7175
+ edgesByRelationship: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.number().int()),
7176
+ topConnected: import_zod8.z.array(TopConnectedSchema),
7177
+ anomalies: import_zod8.z.array(AnomalySchema),
7178
+ contributors: import_zod8.z.number().int(),
7179
+ costByDomain: import_zod8.z.array(CostByDomainSchema),
7180
+ costByOwner: import_zod8.z.array(CostByOwnerSchema),
7181
+ costCoverage: import_zod8.z.object({ withCost: import_zod8.z.number().int(), total: import_zod8.z.number().int() })
7182
+ });
7183
+ var NodesResponse = import_zod8.z.object({
7184
+ nodes: import_zod8.z.array(NodeSchema2),
7185
+ total: import_zod8.z.number().int(),
7186
+ limit: import_zod8.z.number().int(),
7187
+ offset: import_zod8.z.number().int()
7188
+ });
7189
+ var DependencyNodeSchema = NodeSchema2.extend({ depth: import_zod8.z.number().int() });
7190
+ var DependenciesResponse = import_zod8.z.object({
7191
+ root: NodeSchema2.optional(),
7192
+ direction: import_zod8.z.enum(DIRECTIONS),
7193
+ maxDepth: import_zod8.z.number().int(),
7194
+ nodes: import_zod8.z.array(DependencyNodeSchema),
7195
+ edges: import_zod8.z.array(EdgeSchema2)
7196
+ });
7197
+ var SessionEndpointSchema = import_zod8.z.object({
7198
+ sessionId: import_zod8.z.string(),
7199
+ startedAt: import_zod8.z.string(),
7200
+ nodeCount: import_zod8.z.number().int(),
7201
+ edgeCount: import_zod8.z.number().int()
7202
+ });
7203
+ var NodeChangeSchema = import_zod8.z.object({
7204
+ id: import_zod8.z.string(),
7205
+ changedFields: import_zod8.z.array(import_zod8.z.string()),
7206
+ confidenceDelta: import_zod8.z.number()
7207
+ });
7208
+ var DiffResponse = import_zod8.z.object({
7209
+ base: SessionEndpointSchema,
7210
+ current: SessionEndpointSchema,
7211
+ summary: import_zod8.z.object({
7212
+ nodesAdded: import_zod8.z.number().int(),
7213
+ nodesRemoved: import_zod8.z.number().int(),
7214
+ nodesChanged: import_zod8.z.number().int(),
7215
+ edgesAdded: import_zod8.z.number().int(),
7216
+ edgesRemoved: import_zod8.z.number().int()
7217
+ }),
7218
+ nodes: import_zod8.z.object({
7219
+ added: import_zod8.z.array(NodeSchema2),
7220
+ removed: import_zod8.z.array(NodeSchema2),
7221
+ changed: import_zod8.z.array(NodeChangeSchema),
7222
+ unchanged: import_zod8.z.number().int()
7223
+ }),
7224
+ edges: import_zod8.z.object({
7225
+ added: import_zod8.z.array(EdgeSchema2),
7226
+ removed: import_zod8.z.array(EdgeSchema2),
7227
+ unchanged: import_zod8.z.number().int()
7228
+ }),
7229
+ anomalies: import_zod8.z.object({ added: import_zod8.z.array(AnomalySchema) })
7230
+ });
7231
+ var SessionSchema = import_zod8.z.object({
7232
+ id: import_zod8.z.string(),
7233
+ mode: import_zod8.z.literal("discover"),
7234
+ startedAt: import_zod8.z.string(),
7235
+ completedAt: import_zod8.z.string().optional(),
7236
+ name: import_zod8.z.string().optional(),
7237
+ tenant: import_zod8.z.string(),
7238
+ lastScannedAt: import_zod8.z.string().optional()
7239
+ });
7240
+ var SessionsResponse = import_zod8.z.object({ sessions: import_zod8.z.array(SessionSchema) });
7241
+ var HealthResponse = import_zod8.z.object({
7242
+ status: import_zod8.z.literal("ok"),
7243
+ version: import_zod8.z.string(),
7244
+ store: import_zod8.z.literal("sqlite"),
7245
+ sessions: import_zod8.z.number().int()
7246
+ });
7247
+ var ErrorResponse = import_zod8.z.object({
7248
+ error: import_zod8.z.string(),
7249
+ code: import_zod8.z.string().optional()
7250
+ });
7251
+ var API_SCHEMAS = {
7252
+ Node: NodeSchema2,
7253
+ Edge: EdgeSchema2,
7254
+ Anomaly: AnomalySchema,
7255
+ Summary: SummaryResponse,
7256
+ Nodes: NodesResponse,
7257
+ Dependencies: DependenciesResponse,
7258
+ Diff: DiffResponse,
7259
+ Session: SessionSchema,
7260
+ Sessions: SessionsResponse,
7261
+ Health: HealthResponse,
7262
+ Error: ErrorResponse
7263
+ };
7264
+
7265
+ // src/api/rest.ts
7266
+ function toApiNode(n) {
7267
+ const out = { id: n.id, type: n.type, name: n.name, confidence: n.confidence, tags: n.tags };
7268
+ if (n.domain !== void 0) out["domain"] = n.domain;
7269
+ if (n.subDomain !== void 0) out["subDomain"] = n.subDomain;
7270
+ if (n.qualityScore !== void 0) out["qualityScore"] = n.qualityScore;
7271
+ if (n.owner !== void 0) out["owner"] = n.owner;
7272
+ if (n.cost !== void 0) out["cost"] = n.cost;
7273
+ return out;
7274
+ }
7275
+ function toApiEdge(e) {
7276
+ return { sourceId: e.sourceId, targetId: e.targetId, relationship: e.relationship, confidence: e.confidence, evidence: e.evidence };
7277
+ }
7278
+ function toApiSession(s) {
7279
+ const out = { id: s.id, mode: s.mode, startedAt: s.startedAt, tenant: s.tenant };
7280
+ if (s.completedAt !== void 0) out["completedAt"] = s.completedAt;
7281
+ if (s.name !== void 0) out["name"] = s.name;
7282
+ if (s.lastScannedAt !== void 0) out["lastScannedAt"] = s.lastScannedAt;
7283
+ return out;
7284
+ }
7285
+ function toApiAnomaly(a) {
7286
+ return { nodeId: a.nodeId, kind: a.kind, severity: a.severity, reason: a.reason };
7287
+ }
7288
+ function projectDependencies(r) {
7289
+ return {
7290
+ ...r.root ? { root: toApiNode(r.root) } : {},
7291
+ direction: r.direction,
7292
+ maxDepth: r.maxDepth,
7293
+ nodes: r.nodes.map((n) => ({ ...toApiNode(n), depth: n.depth })),
7294
+ edges: r.edges.map(toApiEdge)
7295
+ };
7296
+ }
7297
+ function projectDiff(diff) {
7298
+ return {
7299
+ base: { sessionId: diff.base.sessionId, startedAt: diff.base.startedAt, nodeCount: diff.base.nodeCount, edgeCount: diff.base.edgeCount },
7300
+ current: { sessionId: diff.current.sessionId, startedAt: diff.current.startedAt, nodeCount: diff.current.nodeCount, edgeCount: diff.current.edgeCount },
7301
+ summary: diff.summary,
7302
+ nodes: {
7303
+ added: diff.nodes.added.map(toApiNode),
7304
+ removed: diff.nodes.removed.map(toApiNode),
7305
+ changed: diff.nodes.changed.map((c) => ({ id: c.id, changedFields: c.changedFields, confidenceDelta: c.confidenceDelta })),
7306
+ unchanged: diff.nodes.unchanged
7307
+ },
7308
+ edges: {
7309
+ added: diff.edges.added.map(toApiEdge),
7310
+ removed: diff.edges.removed.map(toApiEdge),
7311
+ unchanged: diff.edges.unchanged
7312
+ },
7313
+ anomalies: { added: diff.anomalies.added.map(toApiAnomaly) }
7314
+ };
7315
+ }
7316
+ function ok(body) {
7317
+ return { status: 200, body };
7318
+ }
7319
+ function badRequest(error) {
7320
+ return { status: 400, body: { error } };
7321
+ }
7322
+ function notFound(error = "not found") {
7323
+ return { status: 404, body: { error } };
7324
+ }
7325
+ function guard(fn) {
7326
+ try {
7327
+ return fn();
7328
+ } catch (err) {
7329
+ if (err instanceof NotFoundError) return notFound(err.message);
7330
+ throw err;
7331
+ }
7332
+ }
7333
+ function validateOut(schema, body) {
7334
+ if (process.env["NODE_ENV"] !== "production") {
7335
+ const r = schema.safeParse(body);
7336
+ if (!r.success) throw new Error(`API response failed its own schema contract: ${r.error.message}`);
7337
+ }
7338
+ return body;
7339
+ }
7340
+ function intParam(url, name) {
7341
+ const raw = url.searchParams.get(name);
7342
+ if (raw === null || raw.trim() === "") return void 0;
7343
+ const n = Number(raw);
7344
+ return Number.isInteger(n) ? n : void 0;
7345
+ }
7346
+ function sessionParam(url) {
7347
+ return url.searchParams.get("session") ?? void 0;
7348
+ }
7349
+ function handleSummary(ctx, url, d) {
7350
+ return guard(() => ok(validateOut(SummaryResponse, d.backend.summary(ctx, sessionParam(url)))));
7351
+ }
7352
+ function handleNodes(ctx, url, d) {
7353
+ return guard(() => {
7354
+ const search = url.searchParams.get("search") ?? void 0;
7355
+ const typesRaw = url.searchParams.get("types");
7356
+ const types = typesRaw ? typesRaw.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
7357
+ const limit = intParam(url, "limit");
7358
+ const offset = intParam(url, "offset");
7359
+ const r = d.backend.nodes(
7360
+ ctx,
7361
+ { ...search ? { search } : {}, ...types ? { types } : {}, ...limit !== void 0 ? { limit } : {}, ...offset !== void 0 ? { offset } : {} },
7362
+ sessionParam(url)
7363
+ );
7364
+ return ok(validateOut(NodesResponse, { nodes: r.nodes.map(toApiNode), total: r.total, limit: r.limit, offset: r.offset }));
7365
+ });
7366
+ }
7367
+ function handleDependencies(ctx, id, url, d) {
7368
+ const directionRaw = url.searchParams.get("direction");
7369
+ if (directionRaw !== null && !DIRECTIONS.includes(directionRaw)) {
7370
+ return badRequest(`direction must be one of ${DIRECTIONS.join(", ")}`);
7371
+ }
7372
+ return guard(() => {
7373
+ const direction = directionRaw ?? void 0;
7374
+ const maxDepth = intParam(url, "maxDepth");
7375
+ const r = d.backend.dependencies(
7376
+ ctx,
7377
+ id,
7378
+ { ...direction ? { direction } : {}, ...maxDepth !== void 0 ? { maxDepth } : {} },
7379
+ sessionParam(url)
7380
+ );
7381
+ return ok(validateOut(DependenciesResponse, projectDependencies(r)));
7382
+ });
7383
+ }
7384
+ function handleDiff(ctx, url, d) {
7385
+ const base = url.searchParams.get("base");
7386
+ const current = url.searchParams.get("current");
7387
+ if (!base || !current) return badRequest("both `base` and `current` query params are required");
7388
+ return guard(() => {
7389
+ const diff = d.backend.diff(ctx, base, current);
7390
+ return ok(validateOut(DiffResponse, projectDiff(diff)));
7391
+ });
7392
+ }
7393
+ function handleSessions(ctx, d) {
7394
+ return guard(() => ok(validateOut(SessionsResponse, { sessions: d.backend.sessions(ctx).map(toApiSession) })));
7395
+ }
7396
+ function handleHealth(ctx, d) {
7397
+ const h = d.backend.health(ctx);
7398
+ return ok(validateOut(HealthResponse, { status: "ok", version: d.version, store: h.store, sessions: h.sessions }));
7399
+ }
7400
+
7401
+ // src/api/openapi.ts
7402
+ function defOf(schema) {
7403
+ return schema.def ?? {};
7404
+ }
7405
+ function unwrapOptional(schema) {
7406
+ const def = defOf(schema);
7407
+ if ((def.type === "optional" || def.type === "nullable") && def.innerType) {
7408
+ return { inner: def.innerType, optional: true };
7409
+ }
7410
+ return { inner: schema, optional: false };
7411
+ }
7412
+ function zodToJsonSchema(schema) {
7413
+ const def = defOf(schema);
7414
+ switch (def.type) {
7415
+ case "string":
7416
+ return { type: "string" };
7417
+ case "number": {
7418
+ const isInt = (def.checks ?? []).some((c) => c._zod?.def?.check === "number_format");
7419
+ return { type: isInt ? "integer" : "number" };
7420
+ }
7421
+ case "boolean":
7422
+ return { type: "boolean" };
7423
+ case "literal": {
7424
+ const values = def.values ?? [];
7425
+ return values.length === 1 ? { const: values[0] } : { enum: values };
7426
+ }
7427
+ case "enum":
7428
+ return { type: "string", enum: Object.values(def.entries ?? {}) };
7429
+ case "array":
7430
+ return { type: "array", items: def.element ? zodToJsonSchema(def.element) : {} };
7431
+ case "record":
7432
+ return { type: "object", additionalProperties: def.valueType ? zodToJsonSchema(def.valueType) : true };
7433
+ case "optional":
7434
+ case "nullable":
7435
+ return def.innerType ? zodToJsonSchema(def.innerType) : {};
7436
+ case "object": {
7437
+ const shape = def.shape ?? {};
7438
+ const properties = {};
7439
+ const required = [];
7440
+ for (const key of Object.keys(shape)) {
7441
+ const { inner, optional } = unwrapOptional(shape[key]);
7442
+ properties[key] = zodToJsonSchema(inner);
7443
+ if (!optional) required.push(key);
7444
+ }
7445
+ return { type: "object", properties, required, additionalProperties: false };
7446
+ }
7447
+ default:
7448
+ throw new Error(`zodToJsonSchema: unsupported zod construct "${def.type ?? "unknown"}". Extend src/api/openapi.ts.`);
7449
+ }
7450
+ }
7451
+ var TENANT_PARAM = {
7452
+ name: "tenant",
7453
+ in: "query",
7454
+ required: false,
7455
+ description: 'Tenant/org scope (also accepted via the X-Cartograph-Tenant header). Defaults to "local".',
7456
+ schema: { type: "string" }
7457
+ };
7458
+ var SESSION_PARAM = {
7459
+ name: "session",
7460
+ in: "query",
7461
+ required: false,
7462
+ description: "Session id to query, or omit for the latest discovery session.",
7463
+ schema: { type: "string" }
7464
+ };
7465
+ function errorResponses() {
7466
+ const err = { description: "Error", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } };
7467
+ return { "400": { ...err, description: "Bad request" }, "401": { ...err, description: "Unauthorized" }, "404": { ...err, description: "Not found" } };
7468
+ }
7469
+ function ok2(ref, description) {
7470
+ return { description, content: { "application/json": { schema: { $ref: `#/components/schemas/${ref}` } } } };
7471
+ }
7472
+ function buildOpenApiDocument(opts) {
7473
+ const schemas = {};
7474
+ for (const [name, schema] of Object.entries(API_SCHEMAS)) {
7475
+ schemas[name] = zodToJsonSchema(schema);
7476
+ }
7477
+ return {
7478
+ openapi: "3.1.0",
7479
+ info: {
7480
+ title: "Cartograph API",
7481
+ version: opts.version,
7482
+ description: "Read-only REST API over the discovered infrastructure/agentic-AI topology. Every endpoint is tenant-scoped and bearer-authenticated."
7483
+ },
7484
+ servers: [{ url: "/" }],
7485
+ security: [{ bearerAuth: [] }],
7486
+ components: {
7487
+ securitySchemes: { bearerAuth: { type: "http", scheme: "bearer" } },
7488
+ schemas
7489
+ },
7490
+ paths: {
7491
+ "/v1/health": {
7492
+ get: {
7493
+ summary: "Liveness + store/coverage probe",
7494
+ security: [],
7495
+ responses: { "200": ok2("Health", "Service health") }
7496
+ }
7497
+ },
7498
+ "/v1/openapi.json": {
7499
+ get: {
7500
+ summary: "This OpenAPI document",
7501
+ security: [],
7502
+ responses: { "200": { description: "OpenAPI 3.1 document", content: { "application/json": { schema: { type: "object" } } } } }
7503
+ }
7504
+ },
7505
+ "/v1/summary": {
7506
+ get: {
7507
+ summary: "Low-token topology aggregate for the resolved session",
7508
+ parameters: [SESSION_PARAM, TENANT_PARAM],
7509
+ responses: { "200": ok2("Summary", "Topology summary"), ...errorResponses() }
7510
+ }
7511
+ },
7512
+ "/v1/nodes": {
7513
+ get: {
7514
+ summary: "List/search/paginate nodes",
7515
+ parameters: [
7516
+ { name: "search", in: "query", required: false, description: "Lexical/semantic search anchor.", schema: { type: "string" } },
7517
+ { name: "types", in: "query", required: false, description: "Comma-separated node-type filter.", schema: { type: "string" } },
7518
+ { name: "limit", in: "query", required: false, description: "Page size (default 100, max 1000).", schema: { type: "integer" } },
7519
+ { name: "offset", in: "query", required: false, description: "Page offset (ignored for search).", schema: { type: "integer" } },
7520
+ SESSION_PARAM,
7521
+ TENANT_PARAM
7522
+ ],
7523
+ responses: { "200": ok2("Nodes", "A page of nodes"), ...errorResponses() }
7524
+ }
7525
+ },
7526
+ "/v1/nodes/{id}/dependencies": {
7527
+ get: {
7528
+ summary: "Dependency traversal from a node",
7529
+ parameters: [
7530
+ { name: "id", in: "path", required: true, description: 'Node id ("{type}:{id}").', schema: { type: "string" } },
7531
+ { name: "direction", in: "query", required: false, description: "downstream | upstream | both (default downstream).", schema: { type: "string", enum: ["downstream", "upstream", "both"] } },
7532
+ { name: "maxDepth", in: "query", required: false, description: "Traversal depth (default 8, max 64).", schema: { type: "integer" } },
7533
+ SESSION_PARAM,
7534
+ TENANT_PARAM
7535
+ ],
7536
+ responses: { "200": ok2("Dependencies", "Traversal result"), ...errorResponses() }
7537
+ }
7538
+ },
7539
+ "/v1/diff": {
7540
+ get: {
7541
+ summary: "Compare two sessions (drift)",
7542
+ parameters: [
7543
+ { name: "base", in: "query", required: true, description: "Base session id.", schema: { type: "string" } },
7544
+ { name: "current", in: "query", required: true, description: "Current session id.", schema: { type: "string" } },
7545
+ TENANT_PARAM
7546
+ ],
7547
+ responses: { "200": ok2("Diff", "Topology delta"), ...errorResponses() }
7548
+ }
7549
+ },
7550
+ "/v1/sessions": {
7551
+ get: {
7552
+ summary: "List discovery sessions for the tenant",
7553
+ parameters: [TENANT_PARAM],
7554
+ responses: { "200": ok2("Sessions", "Sessions"), ...errorResponses() }
7555
+ }
7556
+ }
7557
+ }
7558
+ };
7559
+ }
7560
+
7561
+ // src/api/graphql.ts
7562
+ var SDL = `# Cartograph read-only GraphQL API (4.2). Mirrors the REST surface.
7563
+ schema { query: Query }
7564
+
7565
+ type Query {
7566
+ summary(session: String): Summary
7567
+ nodes(search: String, types: [String!], limit: Int, offset: Int, session: String): NodeConnection
7568
+ node(id: String!, session: String): Node
7569
+ dependencies(id: String!, direction: Direction, maxDepth: Int, session: String): Dependencies
7570
+ diff(base: String!, current: String!): Diff
7571
+ sessions: [Session!]!
7572
+ }
7573
+
7574
+ enum Direction { downstream upstream both }
7575
+
7576
+ type Totals { nodes: Int! edges: Int! }
7577
+ type Count { key: String! value: Int! }
7578
+ type TopConnected { id: String! name: String! type: String! degree: Int! }
7579
+ type Anomaly { nodeId: String! kind: String! severity: String! reason: String! }
7580
+ type Cost { amount: Float! currency: String! period: String! source: String }
7581
+ type CostRollup { key: String! currency: String! period: String! total: Float! nodes: Int! }
7582
+ type CostCoverage { withCost: Int! total: Int! }
7583
+
7584
+ type Node {
7585
+ id: String! type: String! name: String! confidence: Float!
7586
+ domain: String subDomain: String qualityScore: Float owner: String cost: Cost tags: [String!]!
7587
+ }
7588
+ type DependencyNode {
7589
+ id: String! type: String! name: String! confidence: Float!
7590
+ domain: String subDomain: String qualityScore: Float owner: String cost: Cost tags: [String!]! depth: Int!
7591
+ }
7592
+ type Edge { sourceId: String! targetId: String! relationship: String! confidence: Float! evidence: String! }
7593
+
7594
+ type Summary {
7595
+ sessionId: String!
7596
+ totals: Totals!
7597
+ topConnected: [TopConnected!]!
7598
+ anomalies: [Anomaly!]!
7599
+ contributors: Int!
7600
+ costByDomain: [CostRollup!]!
7601
+ costByOwner: [CostRollup!]!
7602
+ costCoverage: CostCoverage!
7603
+ }
7604
+
7605
+ type NodeConnection { nodes: [Node!]! total: Int! limit: Int! offset: Int! }
7606
+ type Dependencies { root: Node direction: Direction! maxDepth: Int! nodes: [DependencyNode!]! edges: [Edge!]! }
7607
+
7608
+ type SessionEndpoint { sessionId: String! startedAt: String! nodeCount: Int! edgeCount: Int! }
7609
+ type DiffSummary { nodesAdded: Int! nodesRemoved: Int! nodesChanged: Int! edgesAdded: Int! edgesRemoved: Int! }
7610
+ type NodeChange { id: String! changedFields: [String!]! confidenceDelta: Float! }
7611
+ type DiffNodes { added: [Node!]! removed: [Node!]! changed: [NodeChange!]! unchanged: Int! }
7612
+ type DiffEdges { added: [Edge!]! removed: [Edge!]! unchanged: Int! }
7613
+ type DiffAnomalies { added: [Anomaly!]! }
7614
+ type Diff {
7615
+ base: SessionEndpoint! current: SessionEndpoint! summary: DiffSummary!
7616
+ nodes: DiffNodes! edges: DiffEdges! anomalies: DiffAnomalies!
7617
+ }
7618
+
7619
+ type Session { id: String! mode: String! startedAt: String! completedAt: String name: String tenant: String! lastScannedAt: String }
7620
+ `;
7621
+ var resolvers = {
7622
+ summary: (ctx, args, backend) => backend.summary(ctx, str(args["session"])),
7623
+ nodes: (ctx, args, backend) => {
7624
+ const r = backend.nodes(
7625
+ ctx,
7626
+ {
7627
+ ...str(args["search"]) ? { search: str(args["search"]) } : {},
7628
+ ...Array.isArray(args["types"]) ? { types: args["types"].map(String) } : {},
7629
+ ...num(args["limit"]) !== void 0 ? { limit: num(args["limit"]) } : {},
7630
+ ...num(args["offset"]) !== void 0 ? { offset: num(args["offset"]) } : {}
7631
+ },
7632
+ str(args["session"])
7633
+ );
7634
+ return { nodes: r.nodes.map(toApiNode), total: r.total, limit: r.limit, offset: r.offset };
7635
+ },
7636
+ node: (ctx, args, backend) => {
7637
+ const n = backend.node(ctx, String(args["id"]), str(args["session"]));
7638
+ return n ? toApiNode(n) : null;
7639
+ },
7640
+ dependencies: (ctx, args, backend) => {
7641
+ const r = backend.dependencies(
7642
+ ctx,
7643
+ String(args["id"]),
7644
+ {
7645
+ ...str(args["direction"]) ? { direction: str(args["direction"]) } : {},
7646
+ ...num(args["maxDepth"]) !== void 0 ? { maxDepth: num(args["maxDepth"]) } : {}
7647
+ },
7648
+ str(args["session"])
7649
+ );
7650
+ return projectDependencies(r);
7651
+ },
7652
+ diff: (ctx, args, backend) => projectDiff(backend.diff(ctx, String(args["base"]), String(args["current"]))),
7653
+ sessions: (ctx, _args, backend) => backend.sessions(ctx).map(toApiSession)
7654
+ };
7655
+ function str(v) {
7656
+ return typeof v === "string" ? v : void 0;
7657
+ }
7658
+ function num(v) {
7659
+ return typeof v === "number" && Number.isInteger(v) ? v : void 0;
7660
+ }
7661
+ var NAME_RE = /[_A-Za-z][_0-9A-Za-z]*/y;
7662
+ function tokenize2(src) {
7663
+ const tokens = [];
7664
+ let i = 0;
7665
+ while (i < src.length) {
7666
+ const c = src[i];
7667
+ if (/\s|,/.test(c)) {
7668
+ i++;
7669
+ continue;
7670
+ }
7671
+ if (c === "#") {
7672
+ while (i < src.length && src[i] !== "\n") i++;
7673
+ continue;
7674
+ }
7675
+ if ("{}()[]:!$".includes(c)) {
7676
+ tokens.push(c);
7677
+ i++;
7678
+ continue;
7679
+ }
7680
+ if (c === '"') {
7681
+ let j = i + 1;
7682
+ let s = "";
7683
+ while (j < src.length && src[j] !== '"') {
7684
+ s += src[j];
7685
+ j++;
7686
+ }
7687
+ tokens.push(JSON.stringify(s));
7688
+ i = j + 1;
7689
+ continue;
7690
+ }
7691
+ NAME_RE.lastIndex = i;
7692
+ const m = NAME_RE.exec(src);
7693
+ if (m && m.index === i) {
7694
+ tokens.push(m[0]);
7695
+ i = NAME_RE.lastIndex;
7696
+ continue;
7697
+ }
7698
+ const numMatch = /-?\d+(\.\d+)?/y;
7699
+ numMatch.lastIndex = i;
7700
+ const nm = numMatch.exec(src);
7701
+ if (nm && nm.index === i) {
7702
+ tokens.push(nm[0]);
7703
+ i = numMatch.lastIndex;
7704
+ continue;
7705
+ }
7706
+ throw new Error(`unexpected character '${c}'`);
7707
+ }
7708
+ return tokens;
7709
+ }
7710
+ var MAX_SELECTION_DEPTH = 32;
7711
+ var Parser = class {
7712
+ constructor(tokens, variables) {
7713
+ this.tokens = tokens;
7714
+ this.variables = variables;
7715
+ }
7716
+ pos = 0;
7717
+ depth = 0;
7718
+ peek() {
7719
+ return this.tokens[this.pos];
7720
+ }
7721
+ next() {
7722
+ return this.tokens[this.pos++];
7723
+ }
7724
+ expect(tok) {
7725
+ if (this.tokens[this.pos] !== tok) throw new Error(`expected '${tok}', got '${this.tokens[this.pos] ?? "<eof>"}'`);
7726
+ this.pos++;
7727
+ }
7728
+ parseDocument() {
7729
+ if (this.peek() === "mutation" || this.peek() === "subscription") {
7730
+ throw new Error("only query operations are supported (read-only API)");
7731
+ }
7732
+ if (this.peek() === "query") {
7733
+ this.next();
7734
+ if (this.peek() && this.peek() !== "{" && this.peek() !== "(") this.next();
7735
+ if (this.peek() === "(") this.skipBalanced("(", ")");
7736
+ }
7737
+ this.expect("{");
7738
+ const selections = this.parseSelectionSet();
7739
+ return selections;
7740
+ }
7741
+ skipBalanced(open, close) {
7742
+ this.expect(open);
7743
+ let depth = 1;
7744
+ while (depth > 0) {
7745
+ const t = this.next();
7746
+ if (t === void 0) throw new Error("unbalanced");
7747
+ if (t === open) depth++;
7748
+ else if (t === close) depth--;
7749
+ }
7750
+ }
7751
+ parseSelectionSet() {
7752
+ if (++this.depth > MAX_SELECTION_DEPTH) throw new Error(`selection set nested deeper than ${MAX_SELECTION_DEPTH}`);
7753
+ const out = [];
7754
+ while (this.peek() !== "}") {
7755
+ if (this.peek() === void 0) throw new Error("unexpected end of selection set");
7756
+ out.push(this.parseSelection());
7757
+ }
7758
+ this.expect("}");
7759
+ this.depth--;
7760
+ return out;
7761
+ }
7762
+ parseSelection() {
7763
+ let name = this.next();
7764
+ const alias = name;
7765
+ if (this.peek() === ":") {
7766
+ this.next();
7767
+ name = this.next();
7768
+ }
7769
+ const args = {};
7770
+ if (this.peek() === "(") {
7771
+ this.next();
7772
+ while (this.peek() !== ")") {
7773
+ const argName = this.next();
7774
+ this.expect(":");
7775
+ args[argName] = this.parseValue();
7776
+ }
7777
+ this.expect(")");
7778
+ }
7779
+ let selections = [];
7780
+ if (this.peek() === "{") {
7781
+ this.next();
7782
+ selections = this.parseSelectionSet();
7783
+ }
7784
+ return { name, alias, args, selections };
7785
+ }
7786
+ parseValue() {
7787
+ const t = this.next();
7788
+ if (t === "$") {
7789
+ const v = this.next();
7790
+ return this.variables[v];
7791
+ }
7792
+ if (t === "[") {
7793
+ const arr = [];
7794
+ while (this.peek() !== "]") arr.push(this.parseValue());
7795
+ this.expect("]");
7796
+ return arr;
7797
+ }
7798
+ if (t.startsWith('"')) return JSON.parse(t);
7799
+ if (t === "true") return true;
7800
+ if (t === "false") return false;
7801
+ if (t === "null") return null;
7802
+ if (/^-?\d+(\.\d+)?$/.test(t)) return Number(t);
7803
+ return t;
7804
+ }
7805
+ };
7806
+ function project(value, selections) {
7807
+ if (value === null || value === void 0) return null;
7808
+ if (selections.length === 0) return value;
7809
+ if (Array.isArray(value)) return value.map((v) => project(v, selections));
7810
+ if (typeof value !== "object") return value;
7811
+ const obj = value;
7812
+ const out = {};
7813
+ for (const sel of selections) {
7814
+ if (sel.name === "__typename") {
7815
+ out[sel.alias] = void 0;
7816
+ continue;
7817
+ }
7818
+ out[sel.alias] = project(obj[sel.name], sel.selections);
7819
+ }
7820
+ return out;
7821
+ }
7822
+ function introspectionSchema() {
7823
+ const names = [...SDL.matchAll(/^(?:type|enum)\s+([_A-Za-z][_0-9A-Za-z]*)/gm)].map((m) => m[1]);
7824
+ const types = names.map((name) => ({ name, kind: /^[A-Z]/.test(name) ? "OBJECT" : "SCALAR" }));
7825
+ return {
7826
+ __schema: {
7827
+ queryType: { name: "Query" },
7828
+ mutationType: null,
7829
+ subscriptionType: null,
7830
+ types,
7831
+ directives: []
7832
+ }
7833
+ };
7834
+ }
7835
+ async function executeGraphql(ctx, body, deps) {
7836
+ const req = body ?? {};
7837
+ if (typeof req.query !== "string" || req.query.trim() === "") {
7838
+ return { errors: [{ message: "missing query" }] };
7839
+ }
7840
+ const variables = typeof req.variables === "object" && req.variables !== null ? req.variables : {};
7841
+ let selections;
7842
+ try {
7843
+ selections = new Parser(tokenize2(req.query), variables).parseDocument();
7844
+ } catch (err) {
7845
+ return { errors: [{ message: `syntax error: ${err instanceof Error ? err.message : String(err)}` }] };
7846
+ }
7847
+ const data = {};
7848
+ const errors = [];
7849
+ for (const sel of selections) {
7850
+ try {
7851
+ if (sel.name === "__schema") {
7852
+ data[sel.alias] = project(introspectionSchema()["__schema"], sel.selections);
7853
+ continue;
7854
+ }
7855
+ if (sel.name === "__typename") {
7856
+ data[sel.alias] = "Query";
7857
+ continue;
7858
+ }
7859
+ const resolver = resolvers[sel.name];
7860
+ if (!resolver) {
7861
+ errors.push({ message: `Cannot query field "${sel.name}" on type "Query"` });
7862
+ continue;
7863
+ }
7864
+ const resolved = resolver(ctx, sel.args, deps.backend);
7865
+ data[sel.alias] = project(resolved, sel.selections);
7866
+ } catch (err) {
7867
+ errors.push({ message: err instanceof Error ? err.message : String(err) });
7868
+ }
7869
+ }
7870
+ return errors.length > 0 ? { data, errors } : { data };
7871
+ }
7872
+ function handleGraphqlGet() {
7873
+ return { status: 200, body: SDL };
7874
+ }
7875
+
7876
+ // src/api/server.ts
7877
+ var DEPENDENCIES_RE = /^\/v1\/nodes\/(.+)\/dependencies$/;
7878
+ var MAX_GRAPHQL_BYTES = 1024 * 1024;
7879
+ function send(res, status, body, headers = {}) {
7880
+ res.writeHead(status, { "content-type": "application/json", ...headers }).end(JSON.stringify(body));
7881
+ }
7882
+ async function readBody(req, cap) {
7883
+ const chunks = [];
7884
+ let total = 0;
7885
+ let overflow = false;
7886
+ for await (const chunk of req) {
7887
+ if (overflow) continue;
7888
+ const buf = chunk;
7889
+ total += buf.length;
7890
+ if (total > cap) {
7891
+ overflow = true;
7892
+ chunks.length = 0;
7893
+ continue;
7894
+ }
7895
+ chunks.push(buf);
7896
+ }
7897
+ if (overflow) return { overflow: true, value: void 0 };
7898
+ if (chunks.length === 0) return { overflow: false, value: void 0 };
7899
+ try {
7900
+ return { overflow: false, value: JSON.parse(Buffer.concat(chunks).toString("utf8")) };
7901
+ } catch {
7902
+ return { overflow: false, value: void 0 };
7903
+ }
7904
+ }
7905
+ async function runApi(opts) {
7906
+ const host2 = opts.host ?? "127.0.0.1";
7907
+ const requestedPort = opts.port ?? 3737;
7908
+ const token = opts.token;
7909
+ const graphqlEnabled = opts.graphql !== false;
7910
+ const defaultTenant = opts.tenant?.defaultTenant ?? DEFAULT_TENANT;
7911
+ const log2 = opts.log ?? (() => {
7912
+ });
7913
+ const restDeps = { backend: opts.backend, version: opts.version };
7914
+ const openApiDoc = buildOpenApiDocument({ version: opts.version });
7915
+ const allowedOrigins = opts.allowedOrigins ?? [];
7916
+ assertSafeBind({ host: host2, port: requestedPort, ...opts.allowedHosts ? { allowedHosts: opts.allowedHosts } : {}, ...token ? { token } : {} });
7917
+ let allowedHosts = opts.allowedHosts ?? [];
7918
+ const corsHeaders = (req) => {
7919
+ const origin = req.headers["origin"];
7920
+ if (typeof origin === "string" && allowedOrigins.includes(origin)) {
7921
+ return {
7922
+ "access-control-allow-origin": origin,
7923
+ "vary": "Origin",
7924
+ "access-control-allow-methods": "GET, POST, OPTIONS",
7925
+ "access-control-allow-headers": "authorization, content-type, x-cartograph-tenant"
7926
+ };
7927
+ }
7928
+ return {};
7929
+ };
7930
+ const server = import_node_http2.default.createServer((req, res) => {
7931
+ const started = Date.now();
7932
+ let tenantLabel = "-";
7933
+ const finish = (status) => {
7934
+ log2(`[cartography-api] ${req.method ?? "-"} ${req.url ?? "-"} ${status} ${Date.now() - started}ms tenant=${tenantLabel}`);
7935
+ };
7936
+ void (async () => {
7937
+ try {
7938
+ const url = new URL(req.url ?? "/", `http://${req.headers["host"] ?? host2}`);
7939
+ const path = url.pathname;
7940
+ const cors = corsHeaders(req);
7941
+ if (req.method === "OPTIONS") {
7942
+ res.writeHead(204, cors).end();
7943
+ finish(204);
7944
+ return;
7945
+ }
7946
+ const hostHeader = (req.headers["host"] ?? "").toLowerCase();
7947
+ if (!allowedHosts.some((h) => h.toLowerCase() === hostHeader)) {
7948
+ send(res, 403, { error: "host not allowed" }, cors);
7949
+ finish(403);
7950
+ return;
7951
+ }
7952
+ if (path === "/v1/openapi.json" && req.method === "GET") {
7953
+ send(res, 200, openApiDoc, cors);
7954
+ finish(200);
7955
+ return;
7956
+ }
7957
+ if (path === "/v1/health") {
7958
+ if (req.method !== "GET") {
7959
+ send(res, 405, { error: "method not allowed" }, { allow: "GET", ...cors });
7960
+ finish(405);
7961
+ return;
7962
+ }
7963
+ tenantLabel = defaultTenant;
7964
+ const r = handleHealth({ tenant: defaultTenant }, restDeps);
7965
+ send(res, r.status, r.body, cors);
7966
+ finish(r.status);
7967
+ return;
7968
+ }
7969
+ if (!checkBearer(req.headers["authorization"], token)) {
7970
+ send(res, 401, { error: "unauthorized" }, { "www-authenticate": "Bearer", ...cors });
7971
+ finish(401);
7972
+ return;
7973
+ }
7974
+ let ctx;
7975
+ try {
7976
+ ctx = resolveTenant(req, url, opts.tenant ?? {});
7977
+ tenantLabel = ctx.tenant;
7978
+ } catch (err) {
7979
+ if (err instanceof InvalidTenantError) {
7980
+ send(res, 400, { error: "invalid tenant" }, cors);
7981
+ finish(400);
7982
+ return;
7983
+ }
7984
+ throw err;
7985
+ }
7986
+ if (graphqlEnabled && path === "/graphql") {
7987
+ if (req.method === "GET") {
7988
+ const g = handleGraphqlGet();
7989
+ res.writeHead(g.status, { "content-type": "text/plain; charset=utf-8", ...cors }).end(g.body);
7990
+ finish(g.status);
7991
+ return;
7992
+ }
7993
+ if (req.method === "POST") {
7994
+ const { overflow, value } = await readBody(req, MAX_GRAPHQL_BYTES);
7995
+ if (overflow) {
7996
+ send(res, 413, { error: "payload too large" }, cors);
7997
+ finish(413);
7998
+ return;
7999
+ }
8000
+ const result = await executeGraphql(ctx, value, { backend: opts.backend });
8001
+ send(res, 200, result, cors);
8002
+ finish(200);
8003
+ return;
8004
+ }
8005
+ send(res, 405, { error: "method not allowed" }, { allow: "GET, POST", ...cors });
8006
+ finish(405);
8007
+ return;
8008
+ }
8009
+ if (path.startsWith("/v1/")) {
8010
+ if (req.method !== "GET") {
8011
+ send(res, 405, { error: "method not allowed" }, { allow: "GET", ...cors });
8012
+ finish(405);
8013
+ return;
8014
+ }
8015
+ const result = dispatchRest(ctx, path, url, restDeps);
8016
+ if (result) {
8017
+ send(res, result.status, result.body, cors);
8018
+ finish(result.status);
8019
+ return;
8020
+ }
8021
+ }
8022
+ send(res, 404, { error: "not found" }, cors);
8023
+ finish(404);
8024
+ } catch (err) {
8025
+ process.stderr.write(`[cartography-api] request failed: ${err instanceof Error ? err.message : String(err)}
8026
+ `);
8027
+ if (!res.headersSent) send(res, 500, { error: "internal error" });
8028
+ finish(500);
8029
+ }
8030
+ })();
8031
+ });
8032
+ await new Promise((resolve3) => server.listen(requestedPort, host2, resolve3));
8033
+ const actualPort = server.address().port;
8034
+ if (allowedHosts.length === 0) allowedHosts = defaultAllowedHosts(host2, actualPort);
8035
+ return server;
8036
+ }
8037
+ function dispatchRest(ctx, path, url, deps) {
8038
+ switch (path) {
8039
+ case "/v1/summary":
8040
+ return handleSummary(ctx, url, deps);
8041
+ case "/v1/nodes":
8042
+ return handleNodes(ctx, url, deps);
8043
+ case "/v1/diff":
8044
+ return handleDiff(ctx, url, deps);
8045
+ case "/v1/sessions":
8046
+ return handleSessions(ctx, deps);
8047
+ default: {
8048
+ const m = DEPENDENCIES_RE.exec(path);
8049
+ if (m) return handleDependencies(ctx, decodeURIComponent(m[1]), url, deps);
8050
+ return void 0;
8051
+ }
8052
+ }
8053
+ }
8054
+
8055
+ // src/api/start.ts
8056
+ var import_node_fs5 = require("fs");
8057
+ var import_node_path5 = require("path");
8058
+ var import_node_url = require("url");
8059
+ var import_meta = {};
8060
+ function readVersion() {
8061
+ try {
8062
+ const dir = import_meta.dirname ?? (0, import_node_path5.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
8063
+ return JSON.parse((0, import_node_fs5.readFileSync)((0, import_node_path5.resolve)(dir, "..", "package.json"), "utf-8")).version ?? "0.0.0";
8064
+ } catch {
8065
+ return "0.0.0";
8066
+ }
8067
+ }
8068
+ function parseApiArgs(argv) {
8069
+ const opts = {};
8070
+ for (let i = 0; i < argv.length; i++) {
8071
+ const a = argv[i];
8072
+ if (a === "--http") continue;
8073
+ else if (a === "--no-graphql") opts.graphql = false;
8074
+ else if (a === "--port") opts.port = Number(argv[++i]);
8075
+ else if (a === "--host") opts.host = argv[++i];
8076
+ else if (a === "--allowed-hosts") opts.allowedHosts = splitList(argv[++i]);
8077
+ else if (a === "--allowed-origins") opts.allowedOrigins = splitList(argv[++i]);
8078
+ else if (a === "--token") opts.token = argv[++i];
8079
+ else if (a === "--db") opts.dbPath = argv[++i];
8080
+ else if (a === "--session") opts.session = argv[++i];
8081
+ else if (a === "--tenant" || a === "--org") opts.tenant = argv[++i];
8082
+ else if (a === "--help" || a === "-h") opts.help = true;
8083
+ }
8084
+ return opts;
8085
+ }
8086
+ function splitList(raw) {
8087
+ return (raw ?? "").split(",").map((s) => s.trim()).filter(Boolean);
8088
+ }
8089
+ async function startApi(opts = {}) {
8090
+ const log2 = opts.log ?? ((m) => process.stderr.write(m + "\n"));
8091
+ const db = new CartographyDB(opts.dbPath ?? defaultConfig().dbPath);
8092
+ const backend = createSqliteQueryBackend(db, opts.session ?? "latest");
8093
+ const token = opts.token ?? process.env["CARTOGRAPHY_HTTP_TOKEN"];
8094
+ const host2 = opts.host ?? "127.0.0.1";
8095
+ const port = opts.port ?? 3737;
8096
+ const version = readVersion();
8097
+ const server = await runApi({
8098
+ host: host2,
8099
+ port,
8100
+ backend,
8101
+ version,
8102
+ ...opts.allowedHosts ? { allowedHosts: opts.allowedHosts } : {},
8103
+ ...opts.allowedOrigins ? { allowedOrigins: opts.allowedOrigins } : {},
8104
+ ...token ? { token } : {},
8105
+ ...opts.graphql === false ? { graphql: false } : {},
8106
+ ...opts.tenant ? { tenant: { defaultTenant: normalizeTenant(opts.tenant) } } : {},
8107
+ log: log2
8108
+ });
8109
+ const graphqlNote = opts.graphql === false ? " [REST only]" : " + /graphql";
8110
+ log2(
8111
+ `Cartograph API (REST${graphqlNote}) on http://${host2}:${port}/v1${token ? " (auth: bearer token required)" : ""} (tenant: ${normalizeTenant(opts.tenant)})`
8112
+ );
8113
+ return server;
8114
+ }
8115
+
6962
8116
  // src/installer/format.ts
6963
8117
  var import_smol_toml = require("smol-toml");
6964
8118
  var import_yaml = require("yaml");
@@ -7031,8 +8185,8 @@ function defaultServerEntry(opts = {}) {
7031
8185
  }
7032
8186
 
7033
8187
  // src/installer/install.ts
7034
- var import_node_fs5 = require("fs");
7035
- var import_node_path5 = require("path");
8188
+ var import_node_fs6 = require("fs");
8189
+ var import_node_path6 = require("path");
7036
8190
  var import_node_os4 = require("os");
7037
8191
  function currentOs() {
7038
8192
  if (process.platform === "win32") return "win";
@@ -7047,8 +8201,8 @@ function planInstall(spec, ctx, opts) {
7047
8201
  if (!path) {
7048
8202
  throw new Error(`${spec.label} does not support the "${ctx.scope}" scope.`);
7049
8203
  }
7050
- const fileExists = (0, import_node_fs5.existsSync)(path);
7051
- const before = fileExists ? (0, import_node_fs5.readFileSync)(path, "utf8") : "";
8204
+ const fileExists = (0, import_node_fs6.existsSync)(path);
8205
+ const before = fileExists ? (0, import_node_fs6.readFileSync)(path, "utf8") : "";
7052
8206
  const existing = parseConfig(before, spec.format);
7053
8207
  const merged = spec.apply(existing, opts.serverName ?? DEFAULT_SERVER_NAME, opts.entry);
7054
8208
  const after = serializeConfig(merged, spec.format);
@@ -7065,8 +8219,8 @@ function planInstall(spec, ctx, opts) {
7065
8219
  };
7066
8220
  }
7067
8221
  function applyInstall(plan) {
7068
- (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(plan.path), { recursive: true });
7069
- (0, import_node_fs5.writeFileSync)(plan.path, plan.after, "utf8");
8222
+ (0, import_node_fs6.mkdirSync)((0, import_node_path6.dirname)(plan.path), { recursive: true });
8223
+ (0, import_node_fs6.writeFileSync)(plan.path, plan.after, "utf8");
7070
8224
  }
7071
8225
  function renderDiff(before, after) {
7072
8226
  if (before === after) return " (no changes)";
@@ -7086,7 +8240,7 @@ function renderDiff(before, after) {
7086
8240
  }
7087
8241
 
7088
8242
  // src/installer/registry.ts
7089
- var import_node_path6 = require("path");
8243
+ var import_node_path7 = require("path");
7090
8244
  function jsonKeyedClient(args) {
7091
8245
  return {
7092
8246
  id: args.id,
@@ -7101,31 +8255,31 @@ var claudeCode = jsonKeyedClient({
7101
8255
  id: "claude-code",
7102
8256
  label: "Claude Code",
7103
8257
  key: "mcpServers",
7104
- globalPath: (ctx) => (0, import_node_path6.join)(ctx.home, ".claude.json"),
7105
- projectPath: (ctx) => (0, import_node_path6.join)(ctx.cwd, ".mcp.json")
8258
+ globalPath: (ctx) => (0, import_node_path7.join)(ctx.home, ".claude.json"),
8259
+ projectPath: (ctx) => (0, import_node_path7.join)(ctx.cwd, ".mcp.json")
7106
8260
  });
7107
8261
  var cursor = jsonKeyedClient({
7108
8262
  id: "cursor",
7109
8263
  label: "Cursor",
7110
8264
  key: "mcpServers",
7111
- globalPath: (ctx) => (0, import_node_path6.join)(ctx.home, ".cursor", "mcp.json"),
7112
- projectPath: (ctx) => (0, import_node_path6.join)(ctx.cwd, ".cursor", "mcp.json")
8265
+ globalPath: (ctx) => (0, import_node_path7.join)(ctx.home, ".cursor", "mcp.json"),
8266
+ projectPath: (ctx) => (0, import_node_path7.join)(ctx.cwd, ".cursor", "mcp.json")
7113
8267
  });
7114
8268
  function vscodeServerObject(entry) {
7115
8269
  if (entry.url) return { type: "http", url: entry.url, ...entry.env ? { env: entry.env } : {} };
7116
8270
  return { type: "stdio", command: entry.command, args: entry.args ?? [], ...entry.env ? { env: entry.env } : {} };
7117
8271
  }
7118
8272
  function vscodeUserDir(ctx) {
7119
- if (ctx.os === "win") return (0, import_node_path6.join)(ctx.env.APPDATA ?? (0, import_node_path6.join)(ctx.home, "AppData", "Roaming"), "Code", "User");
7120
- if (ctx.os === "mac") return (0, import_node_path6.join)(ctx.home, "Library", "Application Support", "Code", "User");
7121
- return (0, import_node_path6.join)(ctx.home, ".config", "Code", "User");
8273
+ if (ctx.os === "win") return (0, import_node_path7.join)(ctx.env.APPDATA ?? (0, import_node_path7.join)(ctx.home, "AppData", "Roaming"), "Code", "User");
8274
+ if (ctx.os === "mac") return (0, import_node_path7.join)(ctx.home, "Library", "Application Support", "Code", "User");
8275
+ return (0, import_node_path7.join)(ctx.home, ".config", "Code", "User");
7122
8276
  }
7123
8277
  var vscode = {
7124
8278
  id: "vscode",
7125
8279
  label: "VS Code (Copilot)",
7126
8280
  format: "json",
7127
8281
  note: "Uses the `servers` key (not `mcpServers`) \u2014 the most common copy-paste mistake.",
7128
- path: (ctx) => ctx.scope === "project" ? (0, import_node_path6.join)(ctx.cwd, ".vscode", "mcp.json") : (0, import_node_path6.join)(vscodeUserDir(ctx), "mcp.json"),
8282
+ path: (ctx) => ctx.scope === "project" ? (0, import_node_path7.join)(ctx.cwd, ".vscode", "mcp.json") : (0, import_node_path7.join)(vscodeUserDir(ctx), "mcp.json"),
7129
8283
  apply: (existing, name, entry) => deepMerge(existing, { servers: { [name]: vscodeServerObject(entry) } })
7130
8284
  };
7131
8285
  var codex = {
@@ -7133,17 +8287,17 @@ var codex = {
7133
8287
  label: "Codex CLI",
7134
8288
  format: "toml",
7135
8289
  note: 'Project scope only loads in "trusted" projects.',
7136
- path: (ctx) => ctx.scope === "project" ? (0, import_node_path6.join)(ctx.cwd, ".codex", "config.toml") : (0, import_node_path6.join)(ctx.home, ".codex", "config.toml"),
8290
+ path: (ctx) => ctx.scope === "project" ? (0, import_node_path7.join)(ctx.cwd, ".codex", "config.toml") : (0, import_node_path7.join)(ctx.home, ".codex", "config.toml"),
7137
8291
  apply: (existing, name, entry) => deepMerge(existing, { mcp_servers: { [name]: mcpServerObject(entry) } })
7138
8292
  };
7139
8293
  var windsurf = jsonKeyedClient({
7140
8294
  id: "windsurf",
7141
8295
  label: "Windsurf",
7142
8296
  key: "mcpServers",
7143
- globalPath: (ctx) => (0, import_node_path6.join)(ctx.home, ".codeium", "windsurf", "mcp_config.json")
8297
+ globalPath: (ctx) => (0, import_node_path7.join)(ctx.home, ".codeium", "windsurf", "mcp_config.json")
7144
8298
  });
7145
8299
  function codeGlobalStorage(ctx, extensionId) {
7146
- return (0, import_node_path6.join)(vscodeUserDir(ctx), "globalStorage", extensionId, "settings", "cline_mcp_settings.json");
8300
+ return (0, import_node_path7.join)(vscodeUserDir(ctx), "globalStorage", extensionId, "settings", "cline_mcp_settings.json");
7147
8301
  }
7148
8302
  var cline = {
7149
8303
  id: "cline",
@@ -7158,7 +8312,7 @@ var roo = {
7158
8312
  label: "Roo Code",
7159
8313
  format: "json",
7160
8314
  note: "Project .roo/mcp.json takes precedence over the global settings.",
7161
- path: (ctx) => ctx.scope === "project" ? (0, import_node_path6.join)(ctx.cwd, ".roo", "mcp.json") : codeGlobalStorage(ctx, "rooveterinaryinc.roo-cline"),
8315
+ path: (ctx) => ctx.scope === "project" ? (0, import_node_path7.join)(ctx.cwd, ".roo", "mcp.json") : codeGlobalStorage(ctx, "rooveterinaryinc.roo-cline"),
7162
8316
  apply: (existing, name, entry) => deepMerge(existing, { mcpServers: { [name]: mcpServerObject(entry) } })
7163
8317
  };
7164
8318
  var zed = {
@@ -7167,9 +8321,9 @@ var zed = {
7167
8321
  format: "json",
7168
8322
  note: 'Manual servers need "source": "custom"; remote uses an mcp-remote bridge.',
7169
8323
  path: (ctx) => {
7170
- if (ctx.scope === "project") return (0, import_node_path6.join)(ctx.cwd, ".zed", "settings.json");
7171
- if (ctx.os === "win") return (0, import_node_path6.join)(ctx.env.APPDATA ?? (0, import_node_path6.join)(ctx.home, "AppData", "Roaming"), "Zed", "settings.json");
7172
- return (0, import_node_path6.join)(ctx.home, ".config", "zed", "settings.json");
8324
+ if (ctx.scope === "project") return (0, import_node_path7.join)(ctx.cwd, ".zed", "settings.json");
8325
+ if (ctx.os === "win") return (0, import_node_path7.join)(ctx.env.APPDATA ?? (0, import_node_path7.join)(ctx.home, "AppData", "Roaming"), "Zed", "settings.json");
8326
+ return (0, import_node_path7.join)(ctx.home, ".config", "zed", "settings.json");
7173
8327
  },
7174
8328
  apply: (existing, name, entry) => {
7175
8329
  const inner = entry.url ? { source: "custom", url: entry.url } : { source: "custom", command: entry.command, args: entry.args ?? [], ...entry.env ? { env: entry.env } : {} };
@@ -7180,14 +8334,14 @@ var junie = {
7180
8334
  id: "junie",
7181
8335
  label: "JetBrains / Junie",
7182
8336
  format: "json",
7183
- path: (ctx) => ctx.scope === "project" ? (0, import_node_path6.join)(ctx.cwd, ".junie", "mcp", "mcp.json") : (0, import_node_path6.join)(ctx.home, ".junie", "mcp", "mcp.json"),
8337
+ path: (ctx) => ctx.scope === "project" ? (0, import_node_path7.join)(ctx.cwd, ".junie", "mcp", "mcp.json") : (0, import_node_path7.join)(ctx.home, ".junie", "mcp", "mcp.json"),
7184
8338
  apply: (existing, name, entry) => deepMerge(existing, { mcpServers: { [name]: mcpServerObject(entry) } })
7185
8339
  };
7186
8340
  var gemini = {
7187
8341
  id: "gemini",
7188
8342
  label: "Gemini CLI",
7189
8343
  format: "json",
7190
- path: (ctx) => ctx.scope === "project" ? (0, import_node_path6.join)(ctx.cwd, ".gemini", "settings.json") : (0, import_node_path6.join)(ctx.home, ".gemini", "settings.json"),
8344
+ path: (ctx) => ctx.scope === "project" ? (0, import_node_path7.join)(ctx.cwd, ".gemini", "settings.json") : (0, import_node_path7.join)(ctx.home, ".gemini", "settings.json"),
7191
8345
  apply: (existing, name, entry) => {
7192
8346
  const inner = entry.url ? { httpUrl: entry.url, ...entry.env ? { env: entry.env } : {} } : mcpServerObject(entry);
7193
8347
  return deepMerge(existing, { mcpServers: { [name]: inner } });
@@ -7199,8 +8353,8 @@ var goose = {
7199
8353
  format: "yaml",
7200
8354
  note: "Verify the extension shape against current Goose docs; built-ins are left untouched.",
7201
8355
  path: (ctx) => {
7202
- if (ctx.os === "win") return (0, import_node_path6.join)(ctx.env.APPDATA ?? (0, import_node_path6.join)(ctx.home, "AppData", "Roaming"), "Block", "goose", "config", "config.yaml");
7203
- return (0, import_node_path6.join)(ctx.home, ".config", "goose", "config.yaml");
8356
+ if (ctx.os === "win") return (0, import_node_path7.join)(ctx.env.APPDATA ?? (0, import_node_path7.join)(ctx.home, "AppData", "Roaming"), "Block", "goose", "config", "config.yaml");
8357
+ return (0, import_node_path7.join)(ctx.home, ".config", "goose", "config.yaml");
7204
8358
  },
7205
8359
  apply: (existing, name, entry) => {
7206
8360
  const inner = entry.url ? { name, type: "streamable_http", enabled: true, uri: entry.url, ...entry.env ? { env: entry.env } : {} } : { name, type: "stdio", enabled: true, command: entry.command, args: entry.args ?? [], ...entry.env ? { env: entry.env } : {} };
@@ -7215,7 +8369,7 @@ var openhands = {
7215
8369
  label: "OpenHands",
7216
8370
  format: "toml",
7217
8371
  note: "SHTTP is preferred; SSE is legacy. Only api_key is supported (no arbitrary headers).",
7218
- path: (ctx) => ctx.scope === "project" ? (0, import_node_path6.join)(ctx.cwd, "config.toml") : (0, import_node_path6.join)(ctx.home, ".openhands", "config.toml"),
8372
+ path: (ctx) => ctx.scope === "project" ? (0, import_node_path7.join)(ctx.cwd, "config.toml") : (0, import_node_path7.join)(ctx.home, ".openhands", "config.toml"),
7219
8373
  apply: (existing, name, entry) => {
7220
8374
  const mcp = isObj(existing.mcp) ? { ...existing.mcp } : {};
7221
8375
  const key = entry.url ? "shttp_servers" : "stdio_servers";
@@ -7236,9 +8390,9 @@ var claudeDesktop = {
7236
8390
  note: "One-click install is also available via the .mcpb bundle (npm run build:mcpb).",
7237
8391
  path: (ctx) => {
7238
8392
  if (ctx.scope === "project") return void 0;
7239
- if (ctx.os === "win") return (0, import_node_path6.join)(ctx.env.APPDATA ?? (0, import_node_path6.join)(ctx.home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
7240
- if (ctx.os === "mac") return (0, import_node_path6.join)(ctx.home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
7241
- return (0, import_node_path6.join)(ctx.home, ".config", "Claude", "claude_desktop_config.json");
8393
+ if (ctx.os === "win") return (0, import_node_path7.join)(ctx.env.APPDATA ?? (0, import_node_path7.join)(ctx.home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
8394
+ if (ctx.os === "mac") return (0, import_node_path7.join)(ctx.home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
8395
+ return (0, import_node_path7.join)(ctx.home, ".config", "Claude", "claude_desktop_config.json");
7242
8396
  },
7243
8397
  apply: (existing, name, entry) => deepMerge(existing, { mcpServers: { [name]: mcpServerObject(entry) } })
7244
8398
  };
@@ -7439,13 +8593,13 @@ function createClaudeProvider() {
7439
8593
  }
7440
8594
 
7441
8595
  // src/providers/shell.ts
7442
- var import_zod8 = require("zod");
8596
+ var import_zod9 = require("zod");
7443
8597
  function createBashTool() {
7444
8598
  const shell = IS_WIN ? "powershell" : "posix";
7445
8599
  return {
7446
8600
  name: "Bash",
7447
8601
  description: "Run a read-only shell command (inspect ports, processes, config). Mutating or destructive commands are blocked by the read-only allowlist.",
7448
- inputShape: { command: import_zod8.z.string().describe("The read-only shell command to run") },
8602
+ inputShape: { command: import_zod9.z.string().describe("The read-only shell command to run") },
7449
8603
  annotations: { readOnlyHint: true, openWorldHint: true },
7450
8604
  handler: async (args) => {
7451
8605
  const command = String(args["command"] ?? "").trim();
@@ -7914,8 +9068,8 @@ Use ask_user when you need context from the user.`;
7914
9068
  }
7915
9069
 
7916
9070
  // src/cost.ts
7917
- var import_node_fs6 = require("fs");
7918
- var import_node_path7 = require("path");
9071
+ var import_node_fs7 = require("fs");
9072
+ var import_node_path8 = require("path");
7919
9073
  function splitCsvLine(line) {
7920
9074
  const out = [];
7921
9075
  let cur = "";
@@ -7993,7 +9147,7 @@ var CsvCostSource = class {
7993
9147
  }
7994
9148
  id;
7995
9149
  async fetch() {
7996
- const text = (0, import_node_fs6.readFileSync)((0, import_node_path7.resolve)(this.opts.filePath), "utf-8");
9150
+ const text = (0, import_node_fs7.readFileSync)((0, import_node_path8.resolve)(this.opts.filePath), "utf-8");
7997
9151
  const records = parseCostCsv(text);
7998
9152
  const match = this.opts.match ?? "nodeId";
7999
9153
  const out = /* @__PURE__ */ new Map();
@@ -8024,19 +9178,19 @@ async function enrichCosts(db, sessionId, source) {
8024
9178
  let matched = 0;
8025
9179
  const unmatchedIds = [];
8026
9180
  for (const [nodeId, rec] of records) {
8027
- const ok = db.enrichNodeAttribution(sessionId, nodeId, {
9181
+ const ok3 = db.enrichNodeAttribution(sessionId, nodeId, {
8028
9182
  owner: rec.owner ?? void 0,
8029
9183
  cost: rec.cost ?? void 0
8030
9184
  });
8031
- if (ok) matched++;
9185
+ if (ok3) matched++;
8032
9186
  else unmatchedIds.push(nodeId);
8033
9187
  }
8034
9188
  return { source: source.id, total: records.size, matched, unmatched: unmatchedIds.length, unmatchedIds };
8035
9189
  }
8036
9190
 
8037
9191
  // src/exporter.ts
8038
- var import_node_fs7 = require("fs");
8039
- var import_node_path8 = require("path");
9192
+ var import_node_fs8 = require("fs");
9193
+ var import_node_path9 = require("path");
8040
9194
 
8041
9195
  // src/hex.ts
8042
9196
  function hexToPixel(q, r, size) {
@@ -8135,10 +9289,10 @@ function assignColors(domains) {
8135
9289
  return result;
8136
9290
  }
8137
9291
  function shadeVariant(hex, amount) {
8138
- const num = parseInt(hex.replace("#", ""), 16);
8139
- const r = Math.min(255, (num >> 16) + amount);
8140
- const g = Math.min(255, (num >> 8 & 255) + amount);
8141
- const b = Math.min(255, (num & 255) + amount);
9292
+ const num2 = parseInt(hex.replace("#", ""), 16);
9293
+ const r = Math.min(255, (num2 >> 16) + amount);
9294
+ const g = Math.min(255, (num2 >> 8 & 255) + amount);
9295
+ const b = Math.min(255, (num2 & 255) + amount);
8142
9296
  return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
8143
9297
  }
8144
9298
  function groupByDomain(assets) {
@@ -9728,28 +10882,28 @@ function exportComplianceReport(report, format) {
9728
10882
  return lines.join("\n");
9729
10883
  }
9730
10884
  function exportAll(db, sessionId, outputDir, formats = ["mermaid", "json", "yaml", "html", "map", "discovery"]) {
9731
- (0, import_node_fs7.mkdirSync)(outputDir, { recursive: true });
10885
+ (0, import_node_fs8.mkdirSync)(outputDir, { recursive: true });
9732
10886
  const nodes = db.getNodes(sessionId);
9733
10887
  const edges = db.getEdges(sessionId);
9734
- const jgfPath = (0, import_node_path8.join)(outputDir, "cartography-graph.jgf.json");
9735
- (0, import_node_fs7.writeFileSync)(jgfPath, exportJGF(nodes, edges));
10888
+ const jgfPath = (0, import_node_path9.join)(outputDir, "cartography-graph.jgf.json");
10889
+ (0, import_node_fs8.writeFileSync)(jgfPath, exportJGF(nodes, edges));
9736
10890
  if (formats.includes("mermaid")) {
9737
- (0, import_node_fs7.writeFileSync)((0, import_node_path8.join)(outputDir, "topology.mermaid"), generateTopologyMermaid(nodes, edges));
9738
- (0, import_node_fs7.writeFileSync)((0, import_node_path8.join)(outputDir, "dependencies.mermaid"), generateDependencyMermaid(nodes, edges));
10891
+ (0, import_node_fs8.writeFileSync)((0, import_node_path9.join)(outputDir, "topology.mermaid"), generateTopologyMermaid(nodes, edges));
10892
+ (0, import_node_fs8.writeFileSync)((0, import_node_path9.join)(outputDir, "dependencies.mermaid"), generateDependencyMermaid(nodes, edges));
9739
10893
  }
9740
10894
  if (formats.includes("json")) {
9741
- (0, import_node_fs7.writeFileSync)((0, import_node_path8.join)(outputDir, "catalog.json"), exportJSON(db, sessionId));
10895
+ (0, import_node_fs8.writeFileSync)((0, import_node_path9.join)(outputDir, "catalog.json"), exportJSON(db, sessionId));
9742
10896
  }
9743
10897
  if (formats.includes("yaml")) {
9744
- (0, import_node_fs7.writeFileSync)((0, import_node_path8.join)(outputDir, "catalog-info.yaml"), exportBackstageYAML(nodes, edges));
10898
+ (0, import_node_fs8.writeFileSync)((0, import_node_path9.join)(outputDir, "catalog-info.yaml"), exportBackstageYAML(nodes, edges));
9745
10899
  }
9746
10900
  if (formats.includes("html") || formats.includes("map") || formats.includes("discovery")) {
9747
- (0, import_node_fs7.writeFileSync)((0, import_node_path8.join)(outputDir, "discovery.html"), exportDiscoveryApp(nodes, edges));
10901
+ (0, import_node_fs8.writeFileSync)((0, import_node_path9.join)(outputDir, "discovery.html"), exportDiscoveryApp(nodes, edges));
9748
10902
  }
9749
10903
  if (formats.includes("cost")) {
9750
10904
  const summary = db.getGraphSummary(sessionId);
9751
- (0, import_node_fs7.writeFileSync)((0, import_node_path8.join)(outputDir, "cost-by-domain.csv"), exportCostCSV(summary));
9752
- (0, import_node_fs7.writeFileSync)((0, import_node_path8.join)(outputDir, "cost-summary.json"), exportCostSummary(summary));
10905
+ (0, import_node_fs8.writeFileSync)((0, import_node_path9.join)(outputDir, "cost-by-domain.csv"), exportCostCSV(summary));
10906
+ (0, import_node_fs8.writeFileSync)((0, import_node_path9.join)(outputDir, "cost-summary.json"), exportCostSummary(summary));
9753
10907
  }
9754
10908
  }
9755
10909
 
@@ -9781,7 +10935,7 @@ function formatComplianceText(report) {
9781
10935
  }
9782
10936
 
9783
10937
  // src/config.ts
9784
- var import_node_fs8 = require("fs");
10938
+ var import_node_fs9 = require("fs");
9785
10939
  var ConfigError = class extends Error {
9786
10940
  constructor(message) {
9787
10941
  super(message);
@@ -9806,7 +10960,7 @@ function loadConfig(path) {
9806
10960
  function readConfigFile(path) {
9807
10961
  let raw;
9808
10962
  try {
9809
- raw = (0, import_node_fs8.readFileSync)(path, "utf-8");
10963
+ raw = (0, import_node_fs9.readFileSync)(path, "utf-8");
9810
10964
  } catch (err) {
9811
10965
  throw new ConfigError(
9812
10966
  `Cannot read config file ${path}: ${err instanceof Error ? err.message : String(err)}`
@@ -10067,7 +11221,7 @@ async function pushDeltas(config, items, opts = {}) {
10067
11221
  sentHashes.push(...batch.map((b) => b.contentHash));
10068
11222
  continue;
10069
11223
  }
10070
- let ok = false;
11224
+ let ok3 = false;
10071
11225
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
10072
11226
  const controller = new AbortController();
10073
11227
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -10086,7 +11240,7 @@ async function pushDeltas(config, items, opts = {}) {
10086
11240
  const elapsed = Date.now() - startedAt;
10087
11241
  if (res.ok) {
10088
11242
  log2(`pushed ${batch.length} item(s) \u2192 ${safeUrl} [${res.status}] ${elapsed}ms (attempt ${attempt + 1})`);
10089
- ok = true;
11243
+ ok3 = true;
10090
11244
  break;
10091
11245
  }
10092
11246
  if (res.status >= 400 && res.status < 500) {
@@ -10105,7 +11259,7 @@ async function pushDeltas(config, items, opts = {}) {
10105
11259
  await sleep(base + Math.floor(Math.random() * 100));
10106
11260
  }
10107
11261
  }
10108
- if (ok) {
11262
+ if (ok3) {
10109
11263
  sent += batch.length;
10110
11264
  sentHashes.push(...batch.map((b) => b.contentHash));
10111
11265
  } else {
@@ -10164,14 +11318,14 @@ function runSyncClassify(db, sessionId, config, opts = {}) {
10164
11318
 
10165
11319
  // src/preflight.ts
10166
11320
  var import_node_child_process2 = require("child_process");
10167
- var import_node_fs9 = require("fs");
10168
- var import_node_path9 = require("path");
11321
+ var import_node_fs10 = require("fs");
11322
+ var import_node_path10 = require("path");
10169
11323
  function isOAuthLoggedIn() {
10170
11324
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "/tmp";
10171
- const credFile = (0, import_node_path9.join)(home, ".claude", ".credentials.json");
10172
- if (!(0, import_node_fs9.existsSync)(credFile)) return false;
11325
+ const credFile = (0, import_node_path10.join)(home, ".claude", ".credentials.json");
11326
+ if (!(0, import_node_fs10.existsSync)(credFile)) return false;
10173
11327
  try {
10174
- const creds = JSON.parse((0, import_node_fs9.readFileSync)(credFile, "utf8"));
11328
+ const creds = JSON.parse((0, import_node_fs10.readFileSync)(credFile, "utf8"));
10175
11329
  const oauth = creds["claudeAiOauth"];
10176
11330
  return typeof oauth?.["accessToken"] === "string" && oauth["accessToken"].length > 0;
10177
11331
  } catch {
@@ -10238,7 +11392,10 @@ function checkClaudePrerequisites() {
10238
11392
  DriftConfigSchema,
10239
11393
  INGEST_SCHEMA_VERSION,
10240
11394
  IngestEnvelopeSchema,
11395
+ InvalidTenantError,
11396
+ LOOPBACK_HOSTS,
10241
11397
  MCP_BIN,
11398
+ NotFoundError,
10242
11399
  PACKAGE_NAME,
10243
11400
  PERSONAL,
10244
11401
  PORT_MAP,
@@ -10249,26 +11406,33 @@ function checkClaudePrerequisites() {
10249
11406
  RuleCheckSchema,
10250
11407
  RulesetSchema,
10251
11408
  SCAN_ARG_PATTERNS,
11409
+ SDL,
10252
11410
  SEVERITY_WEIGHT,
10253
11411
  SHARING_LEVELS,
10254
11412
  ScannerRegistry,
10255
11413
  ScannerShape,
10256
11414
  SharingLevelSchema,
11415
+ SqliteQueryBackend,
10257
11416
  SqliteStoreBackend,
10258
11417
  StdoutSink,
11418
+ TENANT_HEADER,
10259
11419
  VectorStore,
10260
11420
  WebhookSink,
10261
11421
  applyInstall,
10262
11422
  applySharingLevel,
10263
11423
  assertReadOnly,
11424
+ assertSafeBind,
10264
11425
  assertSafeScanArg,
10265
11426
  assignColors,
11427
+ bearerToken,
10266
11428
  bookmarksScanner,
10267
11429
  buildCartographyToolHandlers,
10268
11430
  buildMapData,
11431
+ buildOpenApiDocument,
10269
11432
  buildReport,
10270
11433
  buildSinks,
10271
11434
  centralDbFromEnv,
11435
+ checkBearer,
10272
11436
  checkPrerequisites,
10273
11437
  checkReadOnly,
10274
11438
  clampText,
@@ -10296,10 +11460,12 @@ function checkClaudePrerequisites() {
10296
11460
  createOpenAIProvider,
10297
11461
  createScanRunner,
10298
11462
  createSemanticSearch,
11463
+ createSqliteQueryBackend,
10299
11464
  currentOs,
10300
11465
  cursorDeeplink,
10301
11466
  databasesScanner,
10302
11467
  deepMerge,
11468
+ defaultAllowedHosts,
10303
11469
  defaultConfig,
10304
11470
  defaultContext,
10305
11471
  defaultProviderRegistry,
@@ -10316,6 +11482,7 @@ function checkClaudePrerequisites() {
10316
11482
  evaluateCheck,
10317
11483
  evaluateRule,
10318
11484
  evidenceLine,
11485
+ executeGraphql,
10319
11486
  executeNlQuery,
10320
11487
  exportAll,
10321
11488
  exportBackstageYAML,
@@ -10336,6 +11503,7 @@ function checkClaudePrerequisites() {
10336
11503
  getRuleset,
10337
11504
  globalId,
10338
11505
  groupByDomain,
11506
+ handleGraphqlGet,
10339
11507
  hexCorners,
10340
11508
  hexDistance,
10341
11509
  hexNeighbors,
@@ -10346,6 +11514,7 @@ function checkClaudePrerequisites() {
10346
11514
  hostname,
10347
11515
  ingestEnvelope,
10348
11516
  installedAppsScanner,
11517
+ isLoopbackHost,
10349
11518
  isPersonalHost,
10350
11519
  isReadOnlyCommand,
10351
11520
  isRemembered,
@@ -10374,6 +11543,7 @@ function checkClaudePrerequisites() {
10374
11543
  normalizeTenant,
10375
11544
  orgKeyPath,
10376
11545
  osUser,
11546
+ parseApiArgs,
10377
11547
  parseComposeDeps,
10378
11548
  parseConfig,
10379
11549
  parseConnectionString,
@@ -10399,10 +11569,12 @@ function checkClaudePrerequisites() {
10399
11569
  resolveEffectiveLevel,
10400
11570
  resolveNlQuery,
10401
11571
  resolveSharingLevel,
11572
+ resolveTenant,
10402
11573
  revalidateAnonymized,
10403
11574
  reversalKey,
10404
11575
  reversePseudonym,
10405
11576
  rotateOrgKey,
11577
+ runApi,
10406
11578
  runDiscovery,
10407
11579
  runDrift,
10408
11580
  runHttp,
@@ -10425,8 +11597,11 @@ function checkClaudePrerequisites() {
10425
11597
  shareHash,
10426
11598
  splitSegments,
10427
11599
  stableStringify,
11600
+ startApi,
10428
11601
  stripSensitive,
11602
+ timingSafeEqual,
10429
11603
  validateScanner,
10430
- vscodeDeeplink
11604
+ vscodeDeeplink,
11605
+ zodToJsonSchema
10431
11606
  });
10432
11607
  //# sourceMappingURL=index.cjs.map