@datasynx/agentic-ai-cartography 2.7.0 → 2.8.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/{chunk-HLWNO3RF.js → chunk-5D5ZZEZM.js} +174 -15
- package/dist/chunk-5D5ZZEZM.js.map +1 -0
- package/dist/cli.js +15 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +159 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -10
- package/dist/index.d.ts +99 -10
- package/dist/index.js +157 -12
- package/dist/index.js.map +1 -1
- package/dist/mcp-bin.js +1 -1
- package/package.json +3 -2
- package/server.json +2 -2
- package/dist/chunk-HLWNO3RF.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -49,6 +49,7 @@ __export(src_exports, {
|
|
|
49
49
|
DEFAULT_SERVER_NAME: () => DEFAULT_SERVER_NAME,
|
|
50
50
|
DEFAULT_TENANT: () => DEFAULT_TENANT,
|
|
51
51
|
DriftConfigSchema: () => DriftConfigSchema,
|
|
52
|
+
GraphStoreBackend: () => GraphStoreBackend,
|
|
52
53
|
INGEST_SCHEMA_VERSION: () => INGEST_SCHEMA_VERSION,
|
|
53
54
|
IngestEnvelopeSchema: () => IngestEnvelopeSchema,
|
|
54
55
|
InvalidTenantError: () => InvalidTenantError,
|
|
@@ -220,6 +221,7 @@ __export(src_exports, {
|
|
|
220
221
|
nodesToAssets: () => nodesToAssets,
|
|
221
222
|
normalizeId: () => normalizeId,
|
|
222
223
|
normalizeTenant: () => normalizeTenant,
|
|
224
|
+
openStoreBackend: () => openStoreBackend,
|
|
223
225
|
orgKeyPath: () => orgKeyPath,
|
|
224
226
|
osUser: () => osUser,
|
|
225
227
|
parseApiArgs: () => parseApiArgs,
|
|
@@ -4653,6 +4655,148 @@ var SqliteStoreBackend = class {
|
|
|
4653
4655
|
}
|
|
4654
4656
|
};
|
|
4655
4657
|
|
|
4658
|
+
// src/store/graph.ts
|
|
4659
|
+
function toNum(v) {
|
|
4660
|
+
if (typeof v === "number") return v;
|
|
4661
|
+
if (v && typeof v === "object" && "toNumber" in v && typeof v.toNumber === "function") {
|
|
4662
|
+
return v.toNumber();
|
|
4663
|
+
}
|
|
4664
|
+
return Number(v ?? 0);
|
|
4665
|
+
}
|
|
4666
|
+
var GraphStoreBackend = class {
|
|
4667
|
+
constructor(driver) {
|
|
4668
|
+
this.driver = driver;
|
|
4669
|
+
}
|
|
4670
|
+
async run(cypher, params) {
|
|
4671
|
+
const session = this.driver.session();
|
|
4672
|
+
try {
|
|
4673
|
+
return await session.run(cypher, params);
|
|
4674
|
+
} finally {
|
|
4675
|
+
await session.close();
|
|
4676
|
+
}
|
|
4677
|
+
}
|
|
4678
|
+
async upsertNode(org, node, identity, contributor) {
|
|
4679
|
+
const res = await this.run(
|
|
4680
|
+
`MERGE (n:Node {org: $org, globalId: $globalId})
|
|
4681
|
+
ON CREATE SET n._created = true
|
|
4682
|
+
ON MATCH SET n._created = false
|
|
4683
|
+
SET n.id = $id, n.contentHash = $contentHash, n.type = $type, n.name = $name,
|
|
4684
|
+
n.domain = $domain, n.owner = $owner,
|
|
4685
|
+
n.confidence = CASE WHEN n.confidence IS NULL OR $confidence > n.confidence THEN $confidence ELSE n.confidence END
|
|
4686
|
+
MERGE (c:Contributor {org: $org, globalId: $globalId, machineId: $machineId})
|
|
4687
|
+
SET c.hostname = $hostname, c.user = $user, c.at = $at,
|
|
4688
|
+
c.confidence = CASE WHEN c.confidence IS NULL OR $contribConfidence > c.confidence THEN $contribConfidence ELSE c.confidence END
|
|
4689
|
+
RETURN n._created AS created`,
|
|
4690
|
+
{
|
|
4691
|
+
org,
|
|
4692
|
+
globalId: identity.globalId,
|
|
4693
|
+
contentHash: identity.contentHash,
|
|
4694
|
+
id: node.id,
|
|
4695
|
+
type: node.type,
|
|
4696
|
+
name: node.name,
|
|
4697
|
+
domain: node.domain ?? null,
|
|
4698
|
+
owner: node.owner ?? null,
|
|
4699
|
+
confidence: node.confidence,
|
|
4700
|
+
machineId: contributor.machineId,
|
|
4701
|
+
hostname: contributor.hostname,
|
|
4702
|
+
user: contributor.user,
|
|
4703
|
+
at: contributor.at,
|
|
4704
|
+
contribConfidence: contributor.confidence
|
|
4705
|
+
}
|
|
4706
|
+
);
|
|
4707
|
+
return res.records[0]?.get("created") === true ? "created" : "merged";
|
|
4708
|
+
}
|
|
4709
|
+
async insertEdge(org, edge) {
|
|
4710
|
+
await this.run(
|
|
4711
|
+
`MATCH (s:Node {org: $org, id: $source})
|
|
4712
|
+
MATCH (t:Node {org: $org, id: $target})
|
|
4713
|
+
MERGE (s)-[r:DEPENDS {relationship: $rel}]->(t)
|
|
4714
|
+
SET r.evidence = $evidence, r.confidence = $confidence`,
|
|
4715
|
+
{ org, source: edge.sourceId, target: edge.targetId, rel: edge.relationship, evidence: edge.evidence, confidence: edge.confidence }
|
|
4716
|
+
);
|
|
4717
|
+
}
|
|
4718
|
+
async getSummary(org) {
|
|
4719
|
+
const totals = await this.run(
|
|
4720
|
+
`MATCH (n:Node {org: $org})
|
|
4721
|
+
OPTIONAL MATCH (n)-[r:DEPENDS]->(:Node {org: $org})
|
|
4722
|
+
RETURN count(DISTINCT n) AS nodes, count(r) AS edges`,
|
|
4723
|
+
{ org }
|
|
4724
|
+
);
|
|
4725
|
+
const byType = await this.run(`MATCH (n:Node {org: $org}) RETURN n.type AS k, count(*) AS c`, { org });
|
|
4726
|
+
const byDomain = await this.run(`MATCH (n:Node {org: $org}) RETURN coalesce(n.domain, '(none)') AS k, count(*) AS c`, { org });
|
|
4727
|
+
const byRel = await this.run(`MATCH (:Node {org: $org})-[r:DEPENDS]->(:Node {org: $org}) RETURN r.relationship AS k, count(*) AS c`, { org });
|
|
4728
|
+
const top = await this.run(
|
|
4729
|
+
`MATCH (n:Node {org: $org})
|
|
4730
|
+
OPTIONAL MATCH (n)-[r:DEPENDS]-(:Node {org: $org})
|
|
4731
|
+
RETURN n.id AS id, n.name AS name, n.type AS type, count(r) AS degree
|
|
4732
|
+
ORDER BY degree DESC, id ASC LIMIT 10`,
|
|
4733
|
+
{ org }
|
|
4734
|
+
);
|
|
4735
|
+
const contrib = await this.run(`MATCH (c:Contributor {org: $org}) RETURN count(DISTINCT c.machineId) AS contributors`, { org });
|
|
4736
|
+
const counts = (r) => {
|
|
4737
|
+
const out = {};
|
|
4738
|
+
for (const rec of r.records) out[String(rec.get("k"))] = toNum(rec.get("c"));
|
|
4739
|
+
return out;
|
|
4740
|
+
};
|
|
4741
|
+
return {
|
|
4742
|
+
org,
|
|
4743
|
+
totals: { nodes: toNum(totals.records[0]?.get("nodes")), edges: toNum(totals.records[0]?.get("edges")) },
|
|
4744
|
+
nodesByType: counts(byType),
|
|
4745
|
+
nodesByDomain: counts(byDomain),
|
|
4746
|
+
edgesByRelationship: counts(byRel),
|
|
4747
|
+
topConnected: top.records.map((rec) => ({
|
|
4748
|
+
id: String(rec.get("id")),
|
|
4749
|
+
name: String(rec.get("name")),
|
|
4750
|
+
type: String(rec.get("type")),
|
|
4751
|
+
degree: toNum(rec.get("degree"))
|
|
4752
|
+
})),
|
|
4753
|
+
contributors: toNum(contrib.records[0]?.get("contributors"))
|
|
4754
|
+
};
|
|
4755
|
+
}
|
|
4756
|
+
async getContributors(globalId2) {
|
|
4757
|
+
const res = await this.run(
|
|
4758
|
+
`MATCH (c:Contributor {globalId: $globalId})
|
|
4759
|
+
RETURN c.machineId AS machineId, c.hostname AS hostname, c.user AS user, c.org AS org, c.at AS at, c.confidence AS confidence`,
|
|
4760
|
+
{ globalId: globalId2 }
|
|
4761
|
+
);
|
|
4762
|
+
return res.records.map((rec) => ({
|
|
4763
|
+
machineId: String(rec.get("machineId")),
|
|
4764
|
+
hostname: String(rec.get("hostname")),
|
|
4765
|
+
user: String(rec.get("user")),
|
|
4766
|
+
organization: rec.get("org") != null ? String(rec.get("org")) : void 0,
|
|
4767
|
+
at: String(rec.get("at")),
|
|
4768
|
+
confidence: toNum(rec.get("confidence"))
|
|
4769
|
+
}));
|
|
4770
|
+
}
|
|
4771
|
+
async close() {
|
|
4772
|
+
await this.driver.close();
|
|
4773
|
+
}
|
|
4774
|
+
};
|
|
4775
|
+
|
|
4776
|
+
// src/store/index.ts
|
|
4777
|
+
async function defaultNeo4jDriver(url, user, password) {
|
|
4778
|
+
const mod = await import("neo4j-driver");
|
|
4779
|
+
return mod.default.driver(url, mod.default.auth.basic(user, password));
|
|
4780
|
+
}
|
|
4781
|
+
async function openStoreBackend(db, opts = {}) {
|
|
4782
|
+
if (opts.backend === "graph" && opts.graphUrl) {
|
|
4783
|
+
try {
|
|
4784
|
+
const make = opts.driverFactory ?? defaultNeo4jDriver;
|
|
4785
|
+
const driver = await make(opts.graphUrl, opts.graphUser ?? "neo4j", opts.graphPassword ?? "");
|
|
4786
|
+
if (driver.verifyConnectivity) await driver.verifyConnectivity();
|
|
4787
|
+
logInfo("central store: graph backend active", { host: stripSensitive(opts.graphUrl) });
|
|
4788
|
+
return new GraphStoreBackend(driver);
|
|
4789
|
+
} catch (err) {
|
|
4790
|
+
logWarn("central store: graph backend unavailable \u2014 falling back to SQLite", {
|
|
4791
|
+
host: stripSensitive(opts.graphUrl),
|
|
4792
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
4793
|
+
});
|
|
4794
|
+
return new SqliteStoreBackend(db);
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
return new SqliteStoreBackend(db);
|
|
4798
|
+
}
|
|
4799
|
+
|
|
4656
4800
|
// src/store/query.ts
|
|
4657
4801
|
var NotFoundError = class extends Error {
|
|
4658
4802
|
constructor(message) {
|
|
@@ -4967,9 +5111,9 @@ var IngestEnvelopeSchema = import_zod5.z.object({
|
|
|
4967
5111
|
contributor: ContributorSchema.optional(),
|
|
4968
5112
|
anonymizationLevel: import_zod5.z.enum(["none", "anonymized", "full"]).optional()
|
|
4969
5113
|
});
|
|
4970
|
-
function ingestEnvelope(store, envelope, opts = {}) {
|
|
5114
|
+
async function ingestEnvelope(store, envelope, opts = {}) {
|
|
4971
5115
|
const anonMode = opts.anonMode ?? "reject";
|
|
4972
|
-
const org = envelope.org ?? opts.defaultOrg
|
|
5116
|
+
const org = normalizeTenant(envelope.org ?? opts.defaultOrg);
|
|
4973
5117
|
const level = envelope.anonymizationLevel ?? "anonymized";
|
|
4974
5118
|
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
4975
5119
|
const contributor = {
|
|
@@ -5020,7 +5164,7 @@ function ingestEnvelope(store, envelope, opts = {}) {
|
|
|
5020
5164
|
}
|
|
5021
5165
|
const safe = check.node;
|
|
5022
5166
|
const identity = computeIdentity(org, safe);
|
|
5023
|
-
const outcome = store.upsertNode(org, safe, identity, { ...contributor, confidence: safe.confidence });
|
|
5167
|
+
const outcome = await store.upsertNode(org, safe, identity, { ...contributor, confidence: safe.confidence });
|
|
5024
5168
|
accepted += 1;
|
|
5025
5169
|
if (outcome === "merged") merged += 1;
|
|
5026
5170
|
acceptedNodeIds.add(safe.id);
|
|
@@ -5036,7 +5180,7 @@ function ingestEnvelope(store, envelope, opts = {}) {
|
|
|
5036
5180
|
if (acceptedNodeIds.size > 0 && (!acceptedNodeIds.has(edge.sourceId) || !acceptedNodeIds.has(edge.targetId))) {
|
|
5037
5181
|
continue;
|
|
5038
5182
|
}
|
|
5039
|
-
store.insertEdge(org, edge);
|
|
5183
|
+
await store.insertEdge(org, edge);
|
|
5040
5184
|
edges += 1;
|
|
5041
5185
|
}
|
|
5042
5186
|
logInfo("ingest", { org, accepted, merged, rejected, edges, violations, level, anonMode });
|
|
@@ -5046,7 +5190,7 @@ function ingestEnvelope(store, envelope, opts = {}) {
|
|
|
5046
5190
|
// src/central/server.ts
|
|
5047
5191
|
function createIngestHandler(store, opts = {}) {
|
|
5048
5192
|
const quota = opts.quota;
|
|
5049
|
-
return (body) => {
|
|
5193
|
+
return async (body) => {
|
|
5050
5194
|
const parsed = IngestEnvelopeSchema.safeParse(body);
|
|
5051
5195
|
if (!parsed.success) {
|
|
5052
5196
|
const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
|
|
@@ -5062,7 +5206,7 @@ function createIngestHandler(store, opts = {}) {
|
|
|
5062
5206
|
}
|
|
5063
5207
|
}
|
|
5064
5208
|
try {
|
|
5065
|
-
const result = ingestEnvelope(store, parsed.data, opts);
|
|
5209
|
+
const result = await ingestEnvelope(store, parsed.data, opts);
|
|
5066
5210
|
return { status: 200, body: result };
|
|
5067
5211
|
} catch (err) {
|
|
5068
5212
|
logWarn("ingest: failed", { error: err instanceof Error ? err.message : String(err) });
|
|
@@ -5991,7 +6135,7 @@ async function resolveNlQuery(db, sessionId, search, raw, opts) {
|
|
|
5991
6135
|
|
|
5992
6136
|
// src/mcp/server.ts
|
|
5993
6137
|
var SERVER_NAME = "cartography";
|
|
5994
|
-
var SERVER_VERSION = "2.
|
|
6138
|
+
var SERVER_VERSION = "2.8.0";
|
|
5995
6139
|
var SERVICE_TYPES = NODE_TYPE_GROUPS.web;
|
|
5996
6140
|
var DATA_TYPES = NODE_TYPE_GROUPS.data;
|
|
5997
6141
|
var lexicalSearch = async (db, sessionId, query, opts) => db.searchNodes(sessionId, query, { types: opts.types, limit: opts.limit }).map((node) => ({ node }));
|
|
@@ -6066,9 +6210,10 @@ function createMcpServer(opts = {}) {
|
|
|
6066
6210
|
"graph-summary",
|
|
6067
6211
|
"cartography://graph/summary",
|
|
6068
6212
|
{ title: "Topology summary", description: "Low-token aggregate index of the whole landscape \u2014 read this first.", mimeType: "text/markdown" },
|
|
6069
|
-
(uri) => {
|
|
6213
|
+
async (uri) => {
|
|
6070
6214
|
if (org !== void 0) {
|
|
6071
|
-
|
|
6215
|
+
const s = opts.orgSummary ? await opts.orgSummary(org) : db.getOrgSummary(org);
|
|
6216
|
+
return { contents: [{ uri: uri.href, mimeType: "text/markdown", text: summaryText(s) }] };
|
|
6072
6217
|
}
|
|
6073
6218
|
const sid = resolveSession();
|
|
6074
6219
|
if (!sid) return { contents: [{ uri: uri.href, mimeType: "text/markdown", text: "No discovery session found. Run discovery first." }] };
|
|
@@ -6143,8 +6288,8 @@ function createMcpServer(opts = {}) {
|
|
|
6143
6288
|
server.registerTool(
|
|
6144
6289
|
"get_summary",
|
|
6145
6290
|
{ title: "Get topology summary", description: "Low-token overview of the whole landscape (counts, types, domains, most-connected, anomalies).", inputSchema: {}, annotations: readOnly },
|
|
6146
|
-
() => {
|
|
6147
|
-
if (org !== void 0) return json(db.getOrgSummary(org));
|
|
6291
|
+
async () => {
|
|
6292
|
+
if (org !== void 0) return json(opts.orgSummary ? await opts.orgSummary(org) : db.getOrgSummary(org));
|
|
6148
6293
|
const sid = resolveSession();
|
|
6149
6294
|
if (!sid) return json({ error: "No discovery session found." });
|
|
6150
6295
|
return json(db.getGraphSummary(sid));
|
|
@@ -6670,7 +6815,7 @@ async function runHttp(factory, opts = {}) {
|
|
|
6670
6815
|
res.writeHead(413, { "content-type": "application/json" }).end('{"error":"payload too large"}');
|
|
6671
6816
|
return;
|
|
6672
6817
|
}
|
|
6673
|
-
const out = onIngest(value);
|
|
6818
|
+
const out = await onIngest(value);
|
|
6674
6819
|
res.writeHead(out.status, { "content-type": "application/json", ...out.headers ?? {} }).end(JSON.stringify(out.body));
|
|
6675
6820
|
return;
|
|
6676
6821
|
}
|
|
@@ -11927,6 +12072,7 @@ function checkClaudePrerequisites() {
|
|
|
11927
12072
|
DEFAULT_SERVER_NAME,
|
|
11928
12073
|
DEFAULT_TENANT,
|
|
11929
12074
|
DriftConfigSchema,
|
|
12075
|
+
GraphStoreBackend,
|
|
11930
12076
|
INGEST_SCHEMA_VERSION,
|
|
11931
12077
|
IngestEnvelopeSchema,
|
|
11932
12078
|
InvalidTenantError,
|
|
@@ -12098,6 +12244,7 @@ function checkClaudePrerequisites() {
|
|
|
12098
12244
|
nodesToAssets,
|
|
12099
12245
|
normalizeId,
|
|
12100
12246
|
normalizeTenant,
|
|
12247
|
+
openStoreBackend,
|
|
12101
12248
|
orgKeyPath,
|
|
12102
12249
|
osUser,
|
|
12103
12250
|
parseApiArgs,
|