@datasynx/agentic-ai-cartography 2.8.0 → 2.9.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 +1 -1
- package/dist/{chunk-5D5ZZEZM.js → chunk-LRUWWHMQ.js} +2 -2
- package/dist/{chunk-5D5ZZEZM.js.map → chunk-LRUWWHMQ.js.map} +1 -1
- package/dist/{chunk-TBPGFEMQ.js → chunk-W4Q3TXHR.js} +162 -2
- package/dist/chunk-W4Q3TXHR.js.map +1 -0
- package/dist/cli.js +4 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +164 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +163 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp-bin.js +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/chunk-TBPGFEMQ.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -137,6 +137,7 @@ __export(src_exports, {
|
|
|
137
137
|
createSqliteQueryBackend: () => createSqliteQueryBackend,
|
|
138
138
|
currentOs: () => currentOs,
|
|
139
139
|
cursorDeeplink: () => cursorDeeplink,
|
|
140
|
+
dashboardHtml: () => dashboardHtml,
|
|
140
141
|
databasesScanner: () => databasesScanner,
|
|
141
142
|
deepMerge: () => deepMerge,
|
|
142
143
|
defaultAllowedHosts: () => defaultAllowedHosts,
|
|
@@ -6135,7 +6136,7 @@ async function resolveNlQuery(db, sessionId, search, raw, opts) {
|
|
|
6135
6136
|
|
|
6136
6137
|
// src/mcp/server.ts
|
|
6137
6138
|
var SERVER_NAME = "cartography";
|
|
6138
|
-
var SERVER_VERSION = "2.
|
|
6139
|
+
var SERVER_VERSION = "2.9.0";
|
|
6139
6140
|
var SERVICE_TYPES = NODE_TYPE_GROUPS.web;
|
|
6140
6141
|
var DATA_TYPES = NODE_TYPE_GROUPS.data;
|
|
6141
6142
|
var lexicalSearch = async (db, sessionId, query, opts) => db.searchNodes(sessionId, query, { types: opts.types, limit: opts.limit }).map((node) => ({ node }));
|
|
@@ -8520,6 +8521,156 @@ function handleGraphqlGet() {
|
|
|
8520
8521
|
return { status: 200, body: SDL };
|
|
8521
8522
|
}
|
|
8522
8523
|
|
|
8524
|
+
// src/web/dashboard.ts
|
|
8525
|
+
var STYLE = `
|
|
8526
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
8527
|
+
:root{--bg:#0f1419;--panel:#161b22;--line:#2d333b;--fg:#e6edf3;--dim:#8b949e;--accent:#3b82f6;--ok:#3fb950;--warn:#d29922;--crit:#f85149}
|
|
8528
|
+
body{font:13px/1.5 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--fg);height:100vh;display:flex;flex-direction:column;overflow:hidden}
|
|
8529
|
+
header{display:flex;align-items:center;gap:12px;padding:8px 14px;border-bottom:1px solid var(--line);background:var(--panel)}
|
|
8530
|
+
header h1{font-size:15px;font-weight:600;letter-spacing:.3px}
|
|
8531
|
+
header .ver{color:var(--dim);font-size:11px}
|
|
8532
|
+
header .spacer{flex:1}
|
|
8533
|
+
header input{background:var(--bg);border:1px solid var(--line);color:var(--fg);border-radius:6px;padding:5px 8px;font-size:12px;width:200px}
|
|
8534
|
+
header input:focus{outline:none;border-color:var(--accent)}
|
|
8535
|
+
header button{background:var(--accent);border:none;color:#fff;border-radius:6px;padding:6px 12px;font-size:12px;cursor:pointer}
|
|
8536
|
+
main{flex:1;display:grid;grid-template-columns:300px 1fr 320px;overflow:hidden}
|
|
8537
|
+
.col{overflow:auto;padding:12px;border-right:1px solid var(--line)}
|
|
8538
|
+
.col:last-child{border-right:none;border-left:1px solid var(--line)}
|
|
8539
|
+
.card{background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:10px 12px;margin-bottom:10px}
|
|
8540
|
+
.card h2{font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--dim);margin-bottom:8px}
|
|
8541
|
+
.stat{display:flex;justify-content:space-between;padding:2px 0}
|
|
8542
|
+
.stat b{font-variant-numeric:tabular-nums}
|
|
8543
|
+
.bar{height:4px;border-radius:2px;background:var(--accent);margin-top:2px}
|
|
8544
|
+
#search{width:100%;background:var(--bg);border:1px solid var(--line);color:var(--fg);border-radius:6px;padding:6px 8px;margin-bottom:8px}
|
|
8545
|
+
.node-item{padding:6px 8px;border-radius:6px;cursor:pointer;border:1px solid transparent}
|
|
8546
|
+
.node-item:hover{background:var(--panel)}
|
|
8547
|
+
.node-item.sel{background:var(--panel);border-color:var(--accent)}
|
|
8548
|
+
.node-item .t{color:var(--dim);font-size:11px}
|
|
8549
|
+
#center{position:relative;padding:0}
|
|
8550
|
+
#graph{display:block;width:100%;height:100%;background:radial-gradient(circle at 50% 40%,#11161d,#0d1117)}
|
|
8551
|
+
#empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--dim);text-align:center;padding:20px}
|
|
8552
|
+
.kv{display:flex;justify-content:space-between;gap:8px;padding:3px 0;border-bottom:1px solid var(--line)}
|
|
8553
|
+
.kv span:first-child{color:var(--dim)}
|
|
8554
|
+
.kv span:last-child{text-align:right;word-break:break-all}
|
|
8555
|
+
.chip{display:inline-block;background:var(--bg);border:1px solid var(--line);border-radius:10px;padding:1px 8px;font-size:11px;margin:2px 2px 0 0}
|
|
8556
|
+
.sev-high,.sev-critical{color:var(--crit)} .sev-medium,.sev-warning{color:var(--warn)} .sev-low,.sev-info{color:var(--dim)}
|
|
8557
|
+
#toast{position:fixed;bottom:14px;left:50%;transform:translateX(-50%);background:var(--crit);color:#fff;padding:8px 14px;border-radius:6px;font-size:12px;opacity:0;transition:opacity .2s;pointer-events:none}
|
|
8558
|
+
#toast.show{opacity:1}
|
|
8559
|
+
`;
|
|
8560
|
+
var SCRIPT = String.raw`
|
|
8561
|
+
const $=(s)=>document.querySelector(s), api=(p)=>{
|
|
8562
|
+
const h={accept:'application/json'};
|
|
8563
|
+
const t=sessionStorage.getItem('cartograph_token'); if(t) h.authorization='Bearer '+t;
|
|
8564
|
+
const tn=sessionStorage.getItem('cartograph_tenant'); if(tn) h['x-cartograph-tenant']=tn;
|
|
8565
|
+
return fetch(p,{headers:h}).then(async r=>{ if(!r.ok){ const e=new Error('http '+r.status); e.status=r.status; throw e; } return r.json(); });
|
|
8566
|
+
};
|
|
8567
|
+
function toast(m){ const t=$('#toast'); t.textContent=m; t.classList.add('show'); setTimeout(()=>t.classList.remove('show'),2600); }
|
|
8568
|
+
let NODES=[], SELECTED=null;
|
|
8569
|
+
|
|
8570
|
+
async function boot(){
|
|
8571
|
+
try{
|
|
8572
|
+
const s=await api('/v1/summary'); renderSummary(s);
|
|
8573
|
+
const n=await api('/v1/nodes?limit=1000'); NODES=n.nodes; renderList(NODES);
|
|
8574
|
+
}catch(e){
|
|
8575
|
+
if(e.status===401){ toast('Unauthorized — enter a bearer token and Reload.'); }
|
|
8576
|
+
else if(e.status===404){ const em=$('#empty'); em.textContent='No discovery session yet. Run a scan, then Reload.'; em.style.display='flex'; }
|
|
8577
|
+
else toast('Failed to load: '+e.message);
|
|
8578
|
+
}
|
|
8579
|
+
}
|
|
8580
|
+
function renderSummary(s){
|
|
8581
|
+
const max=Math.max(1,...Object.values(s.nodesByType));
|
|
8582
|
+
const types=Object.entries(s.nodesByType).sort((a,b)=>b[1]-a[1]).slice(0,12)
|
|
8583
|
+
.map(([k,v])=>'<div class="stat"><span>'+esc(k)+'</span><b>'+v+'</b></div><div class="bar" style="width:'+(v/max*100)+'%"></div>').join('');
|
|
8584
|
+
const anom=(s.anomalies||[]).slice(0,12).map(a=>'<div class="stat"><span class="sev-'+a.severity+'">'+esc(a.kind)+'</span><span class="t">'+esc(a.nodeId)+'</span></div>').join('') || '<div class="t">none</div>';
|
|
8585
|
+
$('#summary').innerHTML=
|
|
8586
|
+
'<div class="card"><h2>Totals</h2><div class="stat"><span>Nodes</span><b>'+s.totals.nodes+'</b></div><div class="stat"><span>Edges</span><b>'+s.totals.edges+'</b></div>'+(s.contributors!=null?'<div class="stat"><span>Contributors</span><b>'+s.contributors+'</b></div>':'')+'</div>'+
|
|
8587
|
+
'<div class="card"><h2>Nodes by type</h2>'+types+'</div>'+
|
|
8588
|
+
'<div class="card"><h2>Anomalies</h2>'+anom+'</div>';
|
|
8589
|
+
}
|
|
8590
|
+
function renderList(nodes){
|
|
8591
|
+
$('#list').innerHTML=nodes.map(n=>'<div class="node-item" data-id="'+esc(n.id)+'"><div>'+esc(n.name)+'</div><div class="t">'+esc(n.type)+'</div></div>').join('')||'<div class="t">no nodes</div>';
|
|
8592
|
+
$('#list').querySelectorAll('.node-item').forEach(el=>el.onclick=()=>select(el.dataset.id));
|
|
8593
|
+
}
|
|
8594
|
+
function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,c=>({'&':'&','<':'<','>':'>','"':'"'}[c])); }
|
|
8595
|
+
|
|
8596
|
+
async function select(id){
|
|
8597
|
+
SELECTED=id;
|
|
8598
|
+
$('#list').querySelectorAll('.node-item').forEach(el=>el.classList.toggle('sel',el.dataset.id===id));
|
|
8599
|
+
const node=NODES.find(n=>n.id===id);
|
|
8600
|
+
try{
|
|
8601
|
+
const dep=await api('/v1/nodes/'+encodeURIComponent(id)+'/dependencies?direction=both&maxDepth=2');
|
|
8602
|
+
renderDetail(node,dep); drawGraph(id,dep);
|
|
8603
|
+
}catch(e){ toast('drill-down failed: '+e.message); }
|
|
8604
|
+
}
|
|
8605
|
+
function renderDetail(node,dep){
|
|
8606
|
+
if(!node){ $('#detail').innerHTML='<div class="t">node not in current page</div>'; return; }
|
|
8607
|
+
const fields=[['id',node.id],['type',node.type],['name',node.name],['confidence',node.confidence],['domain',node.domain],['owner',node.owner]]
|
|
8608
|
+
.filter(([,v])=>v!=null).map(([k,v])=>'<div class="kv"><span>'+k+'</span><span>'+esc(v)+'</span></div>').join('');
|
|
8609
|
+
const tags=(node.tags||[]).map(t=>'<span class="chip">'+esc(t)+'</span>').join('');
|
|
8610
|
+
const edges=(dep.edges||[]).map(e=>'<div class="kv"><span>'+esc(e.relationship)+'</span><span>'+esc(e.sourceId===node.id?('→ '+e.targetId):('← '+e.sourceId))+'</span></div>').join('')||'<div class="t">no dependencies</div>';
|
|
8611
|
+
$('#detail').innerHTML='<div class="card"><h2>Node</h2>'+fields+(tags?'<div style="margin-top:6px">'+tags+'</div>':'')+'</div><div class="card"><h2>Dependencies ('+(dep.nodes?dep.nodes.length:0)+')</h2>'+edges+'</div>';
|
|
8612
|
+
}
|
|
8613
|
+
|
|
8614
|
+
const cv=()=>$('#graph'), ctx=()=>cv().getContext('2d');
|
|
8615
|
+
function drawGraph(rootId,dep){
|
|
8616
|
+
$('#empty').style.display='none';
|
|
8617
|
+
const c=cv(); const dpr=window.devicePixelRatio||1; const w=c.clientWidth,h=c.clientHeight;
|
|
8618
|
+
c.width=w*dpr; c.height=h*dpr; const g=ctx(); g.setTransform(dpr,0,0,dpr,0,0); g.clearRect(0,0,w,h);
|
|
8619
|
+
const nodes=dep.nodes||[]; const cx=w/2,cy=h/2;
|
|
8620
|
+
// root at center; others on a circle, radius by depth.
|
|
8621
|
+
const pos={}; pos[rootId]={x:cx,y:cy};
|
|
8622
|
+
const others=nodes.filter(n=>n.id!==rootId);
|
|
8623
|
+
others.forEach((n,i)=>{ const a=(i/Math.max(1,others.length))*Math.PI*2; const r=90+(n.depth||1)*70; pos[n.id]={x:cx+Math.cos(a)*r,y:cy+Math.sin(a)*r}; });
|
|
8624
|
+
// edges
|
|
8625
|
+
g.strokeStyle='#30363d'; g.lineWidth=1.2;
|
|
8626
|
+
(dep.edges||[]).forEach(e=>{ const a=pos[e.sourceId],b=pos[e.targetId]; if(a&&b){ g.beginPath(); g.moveTo(a.x,a.y); g.lineTo(b.x,b.y); g.stroke(); } });
|
|
8627
|
+
// nodes
|
|
8628
|
+
const byId={}; nodes.forEach(n=>byId[n.id]=n);
|
|
8629
|
+
Object.entries(pos).forEach(([id,p])=>{ const n=byId[id]; const root=id===rootId;
|
|
8630
|
+
g.beginPath(); g.arc(p.x,p.y,root?13:8,0,Math.PI*2);
|
|
8631
|
+
g.fillStyle=root?'#3b82f6':'#21262d'; g.fill(); g.lineWidth=root?2:1; g.strokeStyle=root?'#60a5fa':'#484f58'; g.stroke();
|
|
8632
|
+
g.fillStyle='#c9d1d9'; g.font=(root?'600 12px':'11px')+' ui-sans-serif'; g.textAlign='center';
|
|
8633
|
+
g.fillText((n&&n.name?n.name:id).slice(0,22),p.x,p.y-(root?20:14));
|
|
8634
|
+
});
|
|
8635
|
+
}
|
|
8636
|
+
|
|
8637
|
+
document.addEventListener('DOMContentLoaded',()=>{
|
|
8638
|
+
const t=sessionStorage.getItem('cartograph_token'); if(t)$('#token').value=t;
|
|
8639
|
+
const tn=sessionStorage.getItem('cartograph_tenant'); if(tn)$('#tenant').value=tn;
|
|
8640
|
+
$('#reload').onclick=()=>{ sessionStorage.setItem('cartograph_token',$('#token').value.trim()); sessionStorage.setItem('cartograph_tenant',$('#tenant').value.trim()); boot(); };
|
|
8641
|
+
$('#search').oninput=(e)=>{ const q=e.target.value.toLowerCase(); renderList(NODES.filter(n=>n.name.toLowerCase().includes(q)||n.id.toLowerCase().includes(q)||n.type.toLowerCase().includes(q))); };
|
|
8642
|
+
boot();
|
|
8643
|
+
});
|
|
8644
|
+
`;
|
|
8645
|
+
function dashboardHtml(opts = {}) {
|
|
8646
|
+
const version = opts.version ?? "";
|
|
8647
|
+
return `<!DOCTYPE html>
|
|
8648
|
+
<html lang="en"><head>
|
|
8649
|
+
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
8650
|
+
<title>Cartograph dashboard</title>
|
|
8651
|
+
<style>${STYLE}</style>
|
|
8652
|
+
</head><body>
|
|
8653
|
+
<header>
|
|
8654
|
+
<h1>Cartograph</h1><span class="ver">${version ? `v${version}` : ""}</span>
|
|
8655
|
+
<span class="spacer"></span>
|
|
8656
|
+
<input id="tenant" placeholder="tenant (optional)" autocomplete="off">
|
|
8657
|
+
<input id="token" type="password" placeholder="bearer token" autocomplete="off">
|
|
8658
|
+
<button id="reload">Reload</button>
|
|
8659
|
+
</header>
|
|
8660
|
+
<main>
|
|
8661
|
+
<div class="col"><div id="summary"></div></div>
|
|
8662
|
+
<div class="col" id="center"><canvas id="graph"></canvas><div id="empty">Select a node to explore its dependencies.</div></div>
|
|
8663
|
+
<div class="col">
|
|
8664
|
+
<input id="search" placeholder="Search nodes\u2026" autocomplete="off">
|
|
8665
|
+
<div id="list"></div>
|
|
8666
|
+
<div id="detail"></div>
|
|
8667
|
+
</div>
|
|
8668
|
+
</main>
|
|
8669
|
+
<div id="toast"></div>
|
|
8670
|
+
<script>${SCRIPT}</script>
|
|
8671
|
+
</body></html>`;
|
|
8672
|
+
}
|
|
8673
|
+
|
|
8523
8674
|
// src/api/server.ts
|
|
8524
8675
|
var DEPENDENCIES_RE = /^\/v1\/nodes\/(.+)\/dependencies$/;
|
|
8525
8676
|
var MAX_GRAPHQL_BYTES = 1024 * 1024;
|
|
@@ -8561,6 +8712,8 @@ async function runApi(opts) {
|
|
|
8561
8712
|
});
|
|
8562
8713
|
const restDeps = { backend: opts.backend, version: opts.version };
|
|
8563
8714
|
const openApiDoc = buildOpenApiDocument({ version: opts.version });
|
|
8715
|
+
const dashboardEnabled = opts.dashboard !== false;
|
|
8716
|
+
const dashboardPage = dashboardEnabled ? dashboardHtml({ version: opts.version }) : "";
|
|
8564
8717
|
const allowedOrigins = opts.allowedOrigins ?? [];
|
|
8565
8718
|
assertSafeBind({ host: host2, port: requestedPort, ...opts.allowedHosts ? { allowedHosts: opts.allowedHosts } : {}, ...token ? { token } : {} });
|
|
8566
8719
|
let allowedHosts = opts.allowedHosts ?? [];
|
|
@@ -8603,6 +8756,11 @@ async function runApi(opts) {
|
|
|
8603
8756
|
finish(200);
|
|
8604
8757
|
return;
|
|
8605
8758
|
}
|
|
8759
|
+
if (dashboardEnabled && (path === "/" || path === "/app") && req.method === "GET") {
|
|
8760
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8", ...cors }).end(dashboardPage);
|
|
8761
|
+
finish(200);
|
|
8762
|
+
return;
|
|
8763
|
+
}
|
|
8606
8764
|
if (path === "/v1/health") {
|
|
8607
8765
|
if (req.method !== "GET") {
|
|
8608
8766
|
send(res, 405, { error: "method not allowed" }, { allow: "GET", ...cors });
|
|
@@ -8767,6 +8925,7 @@ function parseApiArgs(argv) {
|
|
|
8767
8925
|
const a = argv[i];
|
|
8768
8926
|
if (a === "--http") continue;
|
|
8769
8927
|
else if (a === "--no-graphql") opts.graphql = false;
|
|
8928
|
+
else if (a === "--no-dashboard") opts.dashboard = false;
|
|
8770
8929
|
else if (a === "--port") opts.port = Number(argv[++i]);
|
|
8771
8930
|
else if (a === "--host") opts.host = argv[++i];
|
|
8772
8931
|
else if (a === "--allowed-hosts") opts.allowedHosts = splitList(argv[++i]);
|
|
@@ -8802,12 +8961,14 @@ async function startApi(opts = {}) {
|
|
|
8802
8961
|
...opts.allowedOrigins ? { allowedOrigins: opts.allowedOrigins } : {},
|
|
8803
8962
|
...token ? { token } : {},
|
|
8804
8963
|
...opts.graphql === false ? { graphql: false } : {},
|
|
8964
|
+
...opts.dashboard === false ? { dashboard: false } : {},
|
|
8805
8965
|
...opts.tenant ? { tenant: { defaultTenant: normalizeTenant(opts.tenant) } } : {},
|
|
8806
8966
|
log: log2
|
|
8807
8967
|
});
|
|
8808
8968
|
const graphqlNote = opts.graphql === false ? " [REST only]" : " + /graphql";
|
|
8969
|
+
const dashNote = opts.dashboard === false ? "" : ` \xB7 dashboard http://${host2}:${port}/`;
|
|
8809
8970
|
log2(
|
|
8810
|
-
`Cartograph API (REST${graphqlNote}) on http://${host2}:${port}/v1${token ? " (auth: bearer token required)" : ""} (tenant: ${normalizeTenant(opts.tenant)})`
|
|
8971
|
+
`Cartograph API (REST${graphqlNote}) on http://${host2}:${port}/v1${token ? " (auth: bearer token required)" : ""} (tenant: ${normalizeTenant(opts.tenant)})${dashNote}`
|
|
8811
8972
|
);
|
|
8812
8973
|
return server;
|
|
8813
8974
|
}
|
|
@@ -12160,6 +12321,7 @@ function checkClaudePrerequisites() {
|
|
|
12160
12321
|
createSqliteQueryBackend,
|
|
12161
12322
|
currentOs,
|
|
12162
12323
|
cursorDeeplink,
|
|
12324
|
+
dashboardHtml,
|
|
12163
12325
|
databasesScanner,
|
|
12164
12326
|
deepMerge,
|
|
12165
12327
|
defaultAllowedHosts,
|