@datasynx/agentic-ai-cartography 2.6.0 → 2.7.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/api-bin.js +2 -2
- package/dist/{chunk-X3UWUX3G.js → chunk-HLWNO3RF.js} +70 -6
- package/dist/chunk-HLWNO3RF.js.map +1 -0
- package/dist/{chunk-PQ7Q6MI5.js → chunk-TBPGFEMQ.js} +2 -2
- package/dist/{chunk-GA4427LB.js → chunk-YVV6NIT2.js} +11 -1
- package/dist/chunk-YVV6NIT2.js.map +1 -0
- package/dist/cli.js +24 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +70 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -3
- package/dist/index.d.ts +61 -3
- package/dist/index.js +67 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-bin.js +2 -2
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/chunk-GA4427LB.js.map +0 -1
- package/dist/chunk-X3UWUX3G.js.map +0 -1
- /package/dist/{chunk-PQ7Q6MI5.js.map → chunk-TBPGFEMQ.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,7 @@ __export(src_exports, {
|
|
|
45
45
|
CredentialConfigSchema: () => CredentialConfigSchema,
|
|
46
46
|
CsvCostSource: () => CsvCostSource,
|
|
47
47
|
DEFAULT_ANOMALY_THRESHOLDS: () => DEFAULT_ANOMALY_THRESHOLDS,
|
|
48
|
+
DEFAULT_INGEST_QUOTA: () => DEFAULT_INGEST_QUOTA,
|
|
48
49
|
DEFAULT_SERVER_NAME: () => DEFAULT_SERVER_NAME,
|
|
49
50
|
DEFAULT_TENANT: () => DEFAULT_TENANT,
|
|
50
51
|
DriftConfigSchema: () => DriftConfigSchema,
|
|
@@ -66,10 +67,12 @@ __export(src_exports, {
|
|
|
66
67
|
ProviderRegistry: () => ProviderRegistry,
|
|
67
68
|
RELATION_TO_DIRECTION: () => RELATION_TO_DIRECTION,
|
|
68
69
|
ROLES: () => ROLES,
|
|
70
|
+
RateLimiter: () => RateLimiter,
|
|
69
71
|
RoleSchema: () => RoleSchema,
|
|
70
72
|
RuleCheckSchema: () => RuleCheckSchema,
|
|
71
73
|
RulesetSchema: () => RulesetSchema,
|
|
72
74
|
SCAN_ARG_PATTERNS: () => SCAN_ARG_PATTERNS,
|
|
75
|
+
SCHEMA_VERSION: () => SCHEMA_VERSION,
|
|
73
76
|
SDL: () => SDL,
|
|
74
77
|
SEVERITY_WEIGHT: () => SEVERITY_WEIGHT,
|
|
75
78
|
SHARING_LEVELS: () => SHARING_LEVELS,
|
|
@@ -2850,6 +2853,7 @@ function newAnomalies(base, current) {
|
|
|
2850
2853
|
|
|
2851
2854
|
// src/db.ts
|
|
2852
2855
|
var DEFAULT_TENANT = "local";
|
|
2856
|
+
var SCHEMA_VERSION = 15;
|
|
2853
2857
|
function normalizeTenant(raw) {
|
|
2854
2858
|
if (raw == null) return DEFAULT_TENANT;
|
|
2855
2859
|
const cleaned = sanitizeUntrusted(String(raw)).trim().slice(0, 128);
|
|
@@ -4254,6 +4258,14 @@ var CartographyDB = class {
|
|
|
4254
4258
|
}
|
|
4255
4259
|
return rows.length;
|
|
4256
4260
|
}
|
|
4261
|
+
/**
|
|
4262
|
+
* Retention/compaction (4.7): delete audit events older than `olderThan` (ISO 8601).
|
|
4263
|
+
* The audit trail grows unbounded on a busy collector; this bounds it without touching
|
|
4264
|
+
* sessions/nodes/edges. Returns the number of events removed.
|
|
4265
|
+
*/
|
|
4266
|
+
pruneEventsOlderThan(olderThan) {
|
|
4267
|
+
return this.db.prepare("DELETE FROM activity_events WHERE timestamp < ?").run(olderThan).changes;
|
|
4268
|
+
}
|
|
4257
4269
|
// ── Graph queries (read-only context layer) ─────────────────────────────────
|
|
4258
4270
|
/** Fetch a single node by id within a session. */
|
|
4259
4271
|
getNode(sessionId, nodeId) {
|
|
@@ -4945,7 +4957,7 @@ var ContributorSchema = import_zod5.z.object({
|
|
|
4945
4957
|
});
|
|
4946
4958
|
var IngestEnvelopeSchema = import_zod5.z.object({
|
|
4947
4959
|
schemaVersion: import_zod5.z.literal(INGEST_SCHEMA_VERSION),
|
|
4948
|
-
org: import_zod5.z.string().min(1).optional(),
|
|
4960
|
+
org: import_zod5.z.string().min(1).max(128).optional(),
|
|
4949
4961
|
items: import_zod5.z.array(import_zod5.z.object({
|
|
4950
4962
|
contentHash: import_zod5.z.string(),
|
|
4951
4963
|
kind: import_zod5.z.enum(["node", "edge"]),
|
|
@@ -5033,6 +5045,7 @@ function ingestEnvelope(store, envelope, opts = {}) {
|
|
|
5033
5045
|
|
|
5034
5046
|
// src/central/server.ts
|
|
5035
5047
|
function createIngestHandler(store, opts = {}) {
|
|
5048
|
+
const quota = opts.quota;
|
|
5036
5049
|
return (body) => {
|
|
5037
5050
|
const parsed = IngestEnvelopeSchema.safeParse(body);
|
|
5038
5051
|
if (!parsed.success) {
|
|
@@ -5040,6 +5053,14 @@ function createIngestHandler(store, opts = {}) {
|
|
|
5040
5053
|
logWarn("ingest: rejected invalid envelope", { issues });
|
|
5041
5054
|
return { status: 400, body: { error: "invalid envelope", issues } };
|
|
5042
5055
|
}
|
|
5056
|
+
if (quota) {
|
|
5057
|
+
const org = normalizeTenant(parsed.data.org ?? opts.defaultOrg);
|
|
5058
|
+
const decision = quota.take(org);
|
|
5059
|
+
if (!decision.allowed) {
|
|
5060
|
+
logWarn("ingest: rate limited", { org, retryAfterSec: decision.retryAfterSec });
|
|
5061
|
+
return { status: 429, body: { error: "too many requests" }, headers: { "retry-after": String(decision.retryAfterSec) } };
|
|
5062
|
+
}
|
|
5063
|
+
}
|
|
5043
5064
|
try {
|
|
5044
5065
|
const result = ingestEnvelope(store, parsed.data, opts);
|
|
5045
5066
|
return { status: 200, body: result };
|
|
@@ -5050,6 +5071,39 @@ function createIngestHandler(store, opts = {}) {
|
|
|
5050
5071
|
};
|
|
5051
5072
|
}
|
|
5052
5073
|
|
|
5074
|
+
// src/central/quota.ts
|
|
5075
|
+
var DEFAULT_INGEST_QUOTA = { capacity: 120, refillMs: 6e4 };
|
|
5076
|
+
var MAX_KEYS = 1e4;
|
|
5077
|
+
var RateLimiter = class {
|
|
5078
|
+
constructor(cfg = DEFAULT_INGEST_QUOTA, now = () => Date.now()) {
|
|
5079
|
+
this.cfg = cfg;
|
|
5080
|
+
this.now = now;
|
|
5081
|
+
}
|
|
5082
|
+
buckets = /* @__PURE__ */ new Map();
|
|
5083
|
+
/** Consume one token for `key`. Returns whether the request is allowed (+ Retry-After when not). */
|
|
5084
|
+
take(key) {
|
|
5085
|
+
const t = this.now();
|
|
5086
|
+
const ratePerMs = this.cfg.capacity / this.cfg.refillMs;
|
|
5087
|
+
let b = this.buckets.get(key);
|
|
5088
|
+
if (!b) {
|
|
5089
|
+
if (this.buckets.size >= MAX_KEYS) {
|
|
5090
|
+
const oldest = this.buckets.keys().next().value;
|
|
5091
|
+
if (oldest !== void 0) this.buckets.delete(oldest);
|
|
5092
|
+
}
|
|
5093
|
+
b = { tokens: this.cfg.capacity, last: t };
|
|
5094
|
+
this.buckets.set(key, b);
|
|
5095
|
+
}
|
|
5096
|
+
b.tokens = Math.min(this.cfg.capacity, b.tokens + Math.max(0, t - b.last) * ratePerMs);
|
|
5097
|
+
b.last = t;
|
|
5098
|
+
if (b.tokens >= 1) {
|
|
5099
|
+
b.tokens -= 1;
|
|
5100
|
+
return { allowed: true, retryAfterSec: 0 };
|
|
5101
|
+
}
|
|
5102
|
+
const waitMs = (1 - b.tokens) / ratePerMs;
|
|
5103
|
+
return { allowed: false, retryAfterSec: Math.max(1, Math.ceil(waitMs / 1e3)) };
|
|
5104
|
+
}
|
|
5105
|
+
};
|
|
5106
|
+
|
|
5053
5107
|
// src/scanners/bookmarks.ts
|
|
5054
5108
|
var PERSONAL = [
|
|
5055
5109
|
"facebook.",
|
|
@@ -5937,7 +5991,7 @@ async function resolveNlQuery(db, sessionId, search, raw, opts) {
|
|
|
5937
5991
|
|
|
5938
5992
|
// src/mcp/server.ts
|
|
5939
5993
|
var SERVER_NAME = "cartography";
|
|
5940
|
-
var SERVER_VERSION = "2.
|
|
5994
|
+
var SERVER_VERSION = "2.7.0";
|
|
5941
5995
|
var SERVICE_TYPES = NODE_TYPE_GROUPS.web;
|
|
5942
5996
|
var DATA_TYPES = NODE_TYPE_GROUPS.data;
|
|
5943
5997
|
var lexicalSearch = async (db, sessionId, query, opts) => db.searchNodes(sessionId, query, { types: opts.types, limit: opts.limit }).map((node) => ({ node }));
|
|
@@ -6580,6 +6634,16 @@ async function runHttp(factory, opts = {}) {
|
|
|
6580
6634
|
const httpServer = import_node_http.default.createServer(async (req, res) => {
|
|
6581
6635
|
try {
|
|
6582
6636
|
const url = req.url ?? "";
|
|
6637
|
+
const probePath = new URL(url || "/", "http://probe").pathname;
|
|
6638
|
+
if (probePath === "/healthz") {
|
|
6639
|
+
res.writeHead(200, { "content-type": "application/json" }).end('{"status":"ok"}');
|
|
6640
|
+
return;
|
|
6641
|
+
}
|
|
6642
|
+
if (probePath === "/readyz") {
|
|
6643
|
+
const r = opts.readiness ? opts.readiness() : { ready: true };
|
|
6644
|
+
res.writeHead(r.ready ? 200 : 503, { "content-type": "application/json" }).end(JSON.stringify({ status: r.ready ? "ready" : "unready" }));
|
|
6645
|
+
return;
|
|
6646
|
+
}
|
|
6583
6647
|
const isIngest = url.startsWith("/ingest") && opts.onIngest !== void 0;
|
|
6584
6648
|
if (!url.startsWith("/mcp") && !isIngest) {
|
|
6585
6649
|
res.writeHead(404, { "content-type": "application/json" }).end('{"error":"not found"}');
|
|
@@ -6607,7 +6671,7 @@ async function runHttp(factory, opts = {}) {
|
|
|
6607
6671
|
return;
|
|
6608
6672
|
}
|
|
6609
6673
|
const out = onIngest(value);
|
|
6610
|
-
res.writeHead(out.status, { "content-type": "application/json" }).end(JSON.stringify(out.body));
|
|
6674
|
+
res.writeHead(out.status, { "content-type": "application/json", ...out.headers ?? {} }).end(JSON.stringify(out.body));
|
|
6611
6675
|
return;
|
|
6612
6676
|
}
|
|
6613
6677
|
const sessionId = req.headers["mcp-session-id"];
|
|
@@ -11859,6 +11923,7 @@ function checkClaudePrerequisites() {
|
|
|
11859
11923
|
CredentialConfigSchema,
|
|
11860
11924
|
CsvCostSource,
|
|
11861
11925
|
DEFAULT_ANOMALY_THRESHOLDS,
|
|
11926
|
+
DEFAULT_INGEST_QUOTA,
|
|
11862
11927
|
DEFAULT_SERVER_NAME,
|
|
11863
11928
|
DEFAULT_TENANT,
|
|
11864
11929
|
DriftConfigSchema,
|
|
@@ -11880,10 +11945,12 @@ function checkClaudePrerequisites() {
|
|
|
11880
11945
|
ProviderRegistry,
|
|
11881
11946
|
RELATION_TO_DIRECTION,
|
|
11882
11947
|
ROLES,
|
|
11948
|
+
RateLimiter,
|
|
11883
11949
|
RoleSchema,
|
|
11884
11950
|
RuleCheckSchema,
|
|
11885
11951
|
RulesetSchema,
|
|
11886
11952
|
SCAN_ARG_PATTERNS,
|
|
11953
|
+
SCHEMA_VERSION,
|
|
11887
11954
|
SDL,
|
|
11888
11955
|
SEVERITY_WEIGHT,
|
|
11889
11956
|
SHARING_LEVELS,
|