@kage-core/kage-graph-mcp 3.0.0 → 3.1.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/cli.js +10 -0
- package/dist/daemon.js +1 -1
- package/dist/okf.js +97 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -489,7 +489,17 @@ async function main() {
|
|
|
489
489
|
console.log(` … and ${packets.length - 20} more`);
|
|
490
490
|
return;
|
|
491
491
|
}
|
|
492
|
+
if (sub === "view") {
|
|
493
|
+
(0, okf_js_1.migratePacketsToOkf)(project, { includePending: args.includes("--pending") });
|
|
494
|
+
const concepts = (0, okf_js_1.loadOkfConcepts)((0, okf_js_1.okfBundleDir)(project), { projectDir: project });
|
|
495
|
+
const out = (0, node_path_1.join)((0, okf_js_1.okfBundleDir)(project), "viewer.html");
|
|
496
|
+
(0, node_fs_1.writeFileSync)(out, (0, okf_js_1.okfViewerHtml)(concepts, { title: (0, node_path_1.basename)(project) }), "utf8");
|
|
497
|
+
console.log(`OKF viewer: ${concepts.length} concept(s) — a self-contained page, no server, no giant URL.`);
|
|
498
|
+
console.log(`Open it: open ${out}`);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
492
501
|
console.log("kage okf — Open Knowledge Format is Kage's standard memory format.");
|
|
502
|
+
console.log(" kage okf view [--project <dir>] view your memory as a clean OKF bundle (self-contained page)");
|
|
493
503
|
console.log(" kage okf migrate [--project <dir>] [--pending] packets → OKF bundle (.agent_memory/okf)");
|
|
494
504
|
console.log(" kage okf lint [<dir|file>] [--project <dir>] check OKF conformance");
|
|
495
505
|
console.log(" kage okf import [<dir>] [--project <dir>] [--json] read an OKF bundle back into packets");
|
package/dist/daemon.js
CHANGED
|
@@ -823,7 +823,7 @@ async function startViewer(projectDir, options = {}) {
|
|
|
823
823
|
res.end((0, node_fs_1.readFileSync)(filePath));
|
|
824
824
|
});
|
|
825
825
|
await new Promise((resolveListen) => server.listen(port, host, resolveListen));
|
|
826
|
-
console.log(`Kage viewer
|
|
826
|
+
console.log(`Kage viewer → http://${host}:${port}/`);
|
|
827
827
|
process.on("SIGTERM", () => {
|
|
828
828
|
liveFeed.close();
|
|
829
829
|
server.close(() => process.exit(0));
|
package/dist/okf.js
CHANGED
|
@@ -25,6 +25,7 @@ exports.okfConceptFileName = okfConceptFileName;
|
|
|
25
25
|
exports.okfBundleDir = okfBundleDir;
|
|
26
26
|
exports.migratePacketsToOkf = migratePacketsToOkf;
|
|
27
27
|
exports.loadOkfConcepts = loadOkfConcepts;
|
|
28
|
+
exports.okfViewerHtml = okfViewerHtml;
|
|
28
29
|
exports.lintOkfBundle = lintOkfBundle;
|
|
29
30
|
const node_crypto_1 = require("node:crypto");
|
|
30
31
|
const node_fs_1 = require("node:fs");
|
|
@@ -368,6 +369,102 @@ function loadOkfConcepts(dir, opts = {}) {
|
|
|
368
369
|
}
|
|
369
370
|
return out;
|
|
370
371
|
}
|
|
372
|
+
// A clean, self-contained OKF bundle viewer — one HTML file with the concepts
|
|
373
|
+
// inlined, so it opens directly in a browser (no server, no giant URL). Renders
|
|
374
|
+
// concepts as filterable cards with their OKF type, resource, and verification
|
|
375
|
+
// status; click for the body. This is the "view your memory as an OKF bundle"
|
|
376
|
+
// experience, and it works on ANY OKF bundle, not just Kage's.
|
|
377
|
+
function okfViewerHtml(concepts, opts = {}) {
|
|
378
|
+
const rows = concepts.map((p) => ({
|
|
379
|
+
t: okfType(p.type),
|
|
380
|
+
title: p.title,
|
|
381
|
+
desc: p.summary || "",
|
|
382
|
+
resource: p.paths?.[0] || "",
|
|
383
|
+
tags: p.tags || [],
|
|
384
|
+
v: okfVerifiedStatus(p),
|
|
385
|
+
body: p.body || "",
|
|
386
|
+
updated: (p.updated_at || "").slice(0, 10),
|
|
387
|
+
}));
|
|
388
|
+
const data = JSON.stringify(rows).replace(/<\/(script)/gi, "<\\/$1");
|
|
389
|
+
const title = (opts.title || "Kage").replace(/[<>&"]/g, "");
|
|
390
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8">
|
|
391
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
392
|
+
<title>OKF bundle — ${title}</title>
|
|
393
|
+
<style>
|
|
394
|
+
:root{--g:#1f9d57;--ink:#16201a;--mut:#5b665e;--line:#e3e6e0;--paper:#fff;--bg:#f7f8f6;--code:#0c110d}
|
|
395
|
+
*{box-sizing:border-box}body{margin:0;font:15px/1.5 -apple-system,Segoe UI,Inter,sans-serif;color:var(--ink);background:var(--bg)}
|
|
396
|
+
header{padding:26px 24px 18px;border-bottom:1px solid var(--line);background:var(--paper)}
|
|
397
|
+
.wrap{max-width:1120px;margin:0 auto}
|
|
398
|
+
.brand{display:flex;align-items:center;gap:9px;font-weight:600;font-size:13px;color:var(--mut)}
|
|
399
|
+
.brand .dot{width:17px;height:17px;border-radius:5px;border:1.5px solid var(--g);position:relative}
|
|
400
|
+
.brand .dot::after{content:"";position:absolute;inset:4px;border-radius:50%;background:var(--g);opacity:.5}
|
|
401
|
+
h1{margin:10px 0 2px;font-size:22px}
|
|
402
|
+
.stats{color:var(--mut);font-size:13.5px}.stats b{color:var(--ink)}
|
|
403
|
+
.controls{max-width:1120px;margin:16px auto 0;padding:0 24px;display:flex;flex-wrap:wrap;gap:10px;align-items:center}
|
|
404
|
+
#q{flex:1;min-width:200px;padding:9px 13px;border:1px solid var(--line);border-radius:9px;font-size:14px;background:var(--paper);color:var(--ink)}
|
|
405
|
+
#chips{display:flex;flex-wrap:wrap;gap:7px}
|
|
406
|
+
.chip{padding:6px 11px;border:1px solid var(--line);border-radius:999px;background:var(--paper);color:var(--mut);font-size:12.5px;cursor:pointer}
|
|
407
|
+
.chip.on{border-color:var(--g);color:var(--g);font-weight:600}
|
|
408
|
+
main#grid{max-width:1120px;margin:18px auto 60px;padding:0 24px;display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px}
|
|
409
|
+
.card{padding:15px 16px;border:1px solid var(--line);border-radius:12px;background:var(--paper);cursor:pointer;transition:border-color .12s}
|
|
410
|
+
.card:hover{border-color:var(--g)}
|
|
411
|
+
.meta{display:flex;align-items:center;gap:8px}
|
|
412
|
+
.badge{font:600 10.5px/1 ui-monospace,monospace;text-transform:uppercase;letter-spacing:.05em;color:var(--g);background:rgba(31,157,87,.1);padding:4px 7px;border-radius:5px}
|
|
413
|
+
.pill{margin-left:auto;font:600 11px/1 ui-monospace,monospace;padding:3px 8px;border-radius:999px}
|
|
414
|
+
.pill.ok{color:#0c7a4d;background:rgba(12,122,77,.12)}.pill.warn{color:#9a6b08;background:rgba(154,107,8,.14)}.pill.dim{color:var(--mut);background:rgba(0,0,0,.05)}
|
|
415
|
+
.ti{margin-top:9px;font-weight:600;font-size:15px;line-height:1.3}
|
|
416
|
+
.res{margin-top:6px;font:12px/1.4 ui-monospace,monospace;color:#155e9c;word-break:break-all}
|
|
417
|
+
.ds{margin-top:7px;color:var(--mut);font-size:13px}
|
|
418
|
+
.empty{color:var(--mut);padding:50px;text-align:center;grid-column:1/-1}
|
|
419
|
+
.detail{position:fixed;top:0;right:0;width:min(560px,93vw);height:100vh;overflow:auto;background:var(--paper);border-left:1px solid var(--line);box-shadow:-8px 0 34px rgba(0,0,0,.1);padding:24px 26px 60px;z-index:10}
|
|
420
|
+
.detail.hidden{display:none}
|
|
421
|
+
.detail .x{position:absolute;top:13px;right:16px;border:0;background:none;font-size:25px;color:var(--mut);cursor:pointer;line-height:1}
|
|
422
|
+
.detail h2{margin:12px 0 4px;font-size:19px}
|
|
423
|
+
.tags{margin-top:10px;display:flex;flex-wrap:wrap;gap:6px}.tags span{font:11px/1 ui-monospace,monospace;color:var(--mut);background:rgba(0,0,0,.05);padding:4px 7px;border-radius:5px}
|
|
424
|
+
.detail pre{margin-top:16px;padding:14px 15px;background:var(--code);color:#c7cfc4;border-radius:10px;white-space:pre-wrap;font:12.5px/1.7 ui-monospace,monospace}
|
|
425
|
+
.upd{font:11px/1 ui-monospace,monospace;color:var(--mut)}
|
|
426
|
+
@media (prefers-color-scheme:dark){:root{--ink:#e7ebe4;--mut:#9aa49c;--line:#2a2f2a;--bg:#0e110e}body{background:var(--bg)}header,.card,#q,.chip,.detail{background:#161a16}.badge{background:rgba(31,157,87,.16)}.pill.dim{background:rgba(255,255,255,.07)}.tags span{background:rgba(255,255,255,.07)}}
|
|
427
|
+
</style></head><body>
|
|
428
|
+
<header><div class="wrap">
|
|
429
|
+
<div class="brand"><span class="dot"></span> Open Knowledge Format · viewed with Kage</div>
|
|
430
|
+
<h1>${title} — memory bundle</h1>
|
|
431
|
+
<div class="stats"><b id="n">0</b> concepts · <b id="nv">0</b> verified · <b id="nd">0</b> need attention</div>
|
|
432
|
+
</div></header>
|
|
433
|
+
<div class="controls"><input id="q" placeholder="Search concepts…" autocomplete="off"><div id="chips"></div></div>
|
|
434
|
+
<main id="grid"></main>
|
|
435
|
+
<div id="detail" class="detail hidden"></div>
|
|
436
|
+
<script>
|
|
437
|
+
var C=${data};
|
|
438
|
+
(function(){
|
|
439
|
+
var grid=document.getElementById('grid'),q=document.getElementById('q'),chips=document.getElementById('chips'),detail=document.getElementById('detail'),active='all';
|
|
440
|
+
function esc(s){return String(s==null?'':s).replace(/[&<>"]/g,function(m){return {'&':'&','<':'<','>':'>','"':'"'}[m];});}
|
|
441
|
+
function vClass(v){return v==='fresh'||v==='verified'?'ok':(v==='drifted'||v==='stale'?'warn':'dim');}
|
|
442
|
+
var nv=0,nd=0;C.forEach(function(c){if(c.v==='fresh'||c.v==='verified')nv++;if(c.v==='drifted'||c.v==='stale')nd++;});
|
|
443
|
+
document.getElementById('n').textContent=C.length;document.getElementById('nv').textContent=nv;document.getElementById('nd').textContent=nd;
|
|
444
|
+
var types={};C.forEach(function(c){types[c.t]=(types[c.t]||0)+1;});
|
|
445
|
+
function mkChip(label,key){var b=document.createElement('button');b.className='chip'+(key==='all'?' on':'');b.textContent=label;b.onclick=function(){active=key;[].forEach.call(chips.children,function(x){x.classList.remove('on');});b.classList.add('on');render();};chips.appendChild(b);}
|
|
446
|
+
mkChip('All '+C.length,'all');Object.keys(types).sort().forEach(function(t){mkChip(t+' '+types[t],t);});
|
|
447
|
+
q.oninput=render;
|
|
448
|
+
function render(){var term=q.value.toLowerCase();grid.innerHTML='';var shown=0;
|
|
449
|
+
C.forEach(function(c){
|
|
450
|
+
if(active!=='all'&&c.t!==active)return;
|
|
451
|
+
if(term&&(c.title+' '+c.desc+' '+c.resource+' '+c.tags.join(' ')).toLowerCase().indexOf(term)<0)return;
|
|
452
|
+
shown++;var card=document.createElement('div');card.className='card';
|
|
453
|
+
card.innerHTML='<div class="meta"><span class="badge">'+esc(c.t)+'</span><span class="pill '+vClass(c.v)+'">'+esc(c.v)+'</span></div><div class="ti">'+esc(c.title)+'</div>'+(c.resource?'<div class="res">'+esc(c.resource)+'</div>':'')+'<div class="ds">'+esc(c.desc.slice(0,150))+'</div>';
|
|
454
|
+
card.onclick=function(){show(c);};grid.appendChild(card);
|
|
455
|
+
});
|
|
456
|
+
if(!shown)grid.innerHTML='<div class="empty">No concepts match.</div>';
|
|
457
|
+
}
|
|
458
|
+
function show(c){
|
|
459
|
+
detail.innerHTML='<button class="x" aria-label="Close" onclick="document.getElementById(\\'detail\\').classList.add(\\'hidden\\')">×</button><div class="meta"><span class="badge">'+esc(c.t)+'</span><span class="pill '+vClass(c.v)+'">'+esc(c.v)+'</span>'+(c.updated?'<span class="upd" style="margin-left:8px">'+esc(c.updated)+'</span>':'')+'</div><h2>'+esc(c.title)+'</h2>'+(c.resource?'<div class="res">resource · '+esc(c.resource)+'</div>':'')+(c.tags.length?'<div class="tags">'+c.tags.map(function(t){return '<span>'+esc(t)+'</span>';}).join('')+'</div>':'')+'<pre>'+esc(c.body)+'</pre>';
|
|
460
|
+
detail.classList.remove('hidden');
|
|
461
|
+
}
|
|
462
|
+
document.addEventListener('keydown',function(e){if(e.key==='Escape')detail.classList.add('hidden');});
|
|
463
|
+
render();
|
|
464
|
+
})();
|
|
465
|
+
</script></body></html>
|
|
466
|
+
`;
|
|
467
|
+
}
|
|
371
468
|
function lintOkfBundle(dir) {
|
|
372
469
|
const failures = [];
|
|
373
470
|
let files = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kage-core/kage-graph-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Verified memory for coding agents, stored as a Google Open Knowledge Format (OKF) bundle and checked against your code. The verification layer OKF leaves out. MCP server, no account, no API key.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|