@monoes/monomindcli 2.0.0 → 2.0.2
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/.claude/helpers/token-tracker.cjs +10 -0
- package/README.md +11 -12
- package/dist/src/browser/dashboard/server.d.ts.map +1 -1
- package/dist/src/browser/dashboard/server.js +71 -12
- package/dist/src/browser/dashboard/server.js.map +1 -1
- package/dist/src/browser/dashboard/ui.html +4 -4
- package/dist/src/commands/browse-workflow.js +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -7
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp-tools/coherence/types.d.ts +18 -18
- package/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +12 -12
- package/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
- package/dist/src/orgrt/bus.d.ts +23 -0
- package/dist/src/orgrt/bus.d.ts.map +1 -0
- package/dist/src/orgrt/bus.js +64 -0
- package/dist/src/orgrt/bus.js.map +1 -0
- package/dist/src/orgrt/daemon.d.ts +41 -0
- package/dist/src/orgrt/daemon.d.ts.map +1 -0
- package/dist/src/orgrt/daemon.js +101 -0
- package/dist/src/orgrt/daemon.js.map +1 -0
- package/dist/src/orgrt/forwarder.d.ts +11 -0
- package/dist/src/orgrt/forwarder.d.ts.map +1 -0
- package/dist/src/orgrt/forwarder.js +37 -0
- package/dist/src/orgrt/forwarder.js.map +1 -0
- package/dist/src/orgrt/mailbox.d.ts +25 -0
- package/dist/src/orgrt/mailbox.d.ts.map +1 -0
- package/dist/src/orgrt/mailbox.js +39 -0
- package/dist/src/orgrt/mailbox.js.map +1 -0
- package/dist/src/orgrt/policy.d.ts +24 -0
- package/dist/src/orgrt/policy.d.ts.map +1 -0
- package/dist/src/orgrt/policy.js +86 -0
- package/dist/src/orgrt/policy.js.map +1 -0
- package/dist/src/orgrt/provider.d.ts +9 -0
- package/dist/src/orgrt/provider.d.ts.map +1 -0
- package/dist/src/orgrt/provider.js +54 -0
- package/dist/src/orgrt/provider.js.map +1 -0
- package/dist/src/orgrt/session.d.ts +23 -0
- package/dist/src/orgrt/session.d.ts.map +1 -0
- package/dist/src/orgrt/session.js +78 -0
- package/dist/src/orgrt/session.js.map +1 -0
- package/dist/src/orgrt/types.d.ts +847 -0
- package/dist/src/orgrt/types.d.ts.map +1 -0
- package/dist/src/orgrt/types.js +51 -0
- package/dist/src/orgrt/types.js.map +1 -0
- package/dist/src/parser.d.ts.map +1 -1
- package/dist/src/parser.js +31 -5
- package/dist/src/parser.js.map +1 -1
- package/dist/src/ui/collector.mjs +69 -44
- package/dist/src/ui/dashboard.html +112 -25
- package/dist/src/ui/orgs.html +54 -0
- package/dist/src/ui/server.mjs +87 -12
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/scripts/setup-ipfs-registry.md +14 -15
- package/dist/src/consensus/vote-signer.d.ts +0 -36
- package/dist/src/consensus/vote-signer.d.ts.map +0 -1
- package/dist/src/consensus/vote-signer.js +0 -88
- package/dist/src/consensus/vote-signer.js.map +0 -1
|
@@ -2663,6 +2663,7 @@ function switchProject(path) {
|
|
|
2663
2663
|
// Reset Monograph cache so it reloads for the new project
|
|
2664
2664
|
_mgLoaded = false;
|
|
2665
2665
|
_mgGraph = null;
|
|
2666
|
+
window._mgRealTotals = null;
|
|
2666
2667
|
document.getElementById('sb-proj').textContent = path.split('/').filter(Boolean).pop() || '—';
|
|
2667
2668
|
document.getElementById('sb-path').textContent = path;
|
|
2668
2669
|
_showNavProjectCtx(path);
|
|
@@ -3174,9 +3175,10 @@ async function loadStatusStrip() {
|
|
|
3174
3175
|
const strip = document.getElementById('status-strip');
|
|
3175
3176
|
if (!strip || !DIR) return;
|
|
3176
3177
|
try {
|
|
3177
|
-
const [statusRes, memRes] = await Promise.allSettled([
|
|
3178
|
+
const [statusRes, memRes, metricsRes] = await Promise.allSettled([
|
|
3178
3179
|
apiFetch('/api/status?dir=' + enc(DIR)),
|
|
3179
3180
|
apiFetch('/api/memory/stats?dir=' + enc(DIR)),
|
|
3181
|
+
apiFetch('/api/section?name=metrics&dir=' + enc(DIR)),
|
|
3180
3182
|
]);
|
|
3181
3183
|
const checks = statusRes.status === 'fulfilled'
|
|
3182
3184
|
? (Array.isArray(statusRes.value) ? statusRes.value : (statusRes.value?.checks || []))
|
|
@@ -3193,15 +3195,27 @@ async function loadStatusStrip() {
|
|
|
3193
3195
|
pills.push(`<span class="ss-pill ${cls}">${esc(c.name || c.label || c.key || '?')}</span>`);
|
|
3194
3196
|
});
|
|
3195
3197
|
|
|
3196
|
-
// HNSW status
|
|
3197
|
-
const hnswOn = mem.hnsw === true || mem.hnswEnabled === true || mem.hnsw_enabled === true;
|
|
3198
|
-
pills.push(`<span class="ss-pill ${hnswOn ? 'on' : ''}">HNSW ${hnswOn ? 'ON' : 'OFF'}</span>`);
|
|
3199
|
-
|
|
3200
3198
|
// Patterns count
|
|
3201
3199
|
if (mem.patterns != null) {
|
|
3202
3200
|
pills.push(`<span class="ss-pill">PATTERNS ${Number(mem.patterns).toLocaleString()}</span>`);
|
|
3203
3201
|
}
|
|
3204
3202
|
|
|
3203
|
+
// Worker freshness (metrics.workers = [{name, exists, ageMs}])
|
|
3204
|
+
const metricsSec = metricsRes.status === 'fulfilled'
|
|
3205
|
+
? (metricsRes.value?.metrics || metricsRes.value || {})
|
|
3206
|
+
: {};
|
|
3207
|
+
const workers = Array.isArray(metricsSec.workers) ? metricsSec.workers : [];
|
|
3208
|
+
const fmtAge = ms => ms < 3600e3 ? Math.round(ms / 60e3) + 'm'
|
|
3209
|
+
: ms < 86400e3 ? Math.round(ms / 3600e3) + 'h'
|
|
3210
|
+
: Math.round(ms / 86400e3) + 'd';
|
|
3211
|
+
workers.forEach(w => {
|
|
3212
|
+
if (!w || !w.name) return;
|
|
3213
|
+
const fresh = w.exists && typeof w.ageMs === 'number' && w.ageMs < 12 * 3600e3;
|
|
3214
|
+
const cls = !w.exists ? '' : (fresh ? 'on' : 'warn');
|
|
3215
|
+
const ageTxt = !w.exists ? 'missing' : (typeof w.ageMs === 'number' ? fmtAge(w.ageMs) : '?');
|
|
3216
|
+
pills.push(`<span class="ss-pill ${cls}" title="worker ${esc(w.name)}: ${esc(ageTxt)}">⚙ ${esc(w.name)}</span>`);
|
|
3217
|
+
});
|
|
3218
|
+
|
|
3205
3219
|
// Chunks count
|
|
3206
3220
|
if (mem.chunks != null) {
|
|
3207
3221
|
pills.push(`<span class="ss-pill">CHUNKS ${Number(mem.chunks).toLocaleString()}</span>`);
|
|
@@ -3506,8 +3520,20 @@ async function loadMemUsagePeriod(btn, period) {
|
|
|
3506
3520
|
}
|
|
3507
3521
|
|
|
3508
3522
|
const totalCost = typeof s.todayCost === 'number' ? s.todayCost : (typeof s.cost === 'number' ? s.cost : null);
|
|
3509
|
-
|
|
3510
|
-
|
|
3523
|
+
// Cache efficiency = cacheRead / (cacheRead + input), capped at 100%.
|
|
3524
|
+
// (The old cacheTokens/totalTokensIn math exceeded 100% because cache
|
|
3525
|
+
// reads are not included in the input-token total.)
|
|
3526
|
+
const cacheEff = s.cacheTokens
|
|
3527
|
+
? Math.min(100, Math.round(s.cacheTokens / (s.cacheTokens + (Number(s.totalTokensIn) || 0)) * 100))
|
|
3528
|
+
: null;
|
|
3529
|
+
|
|
3530
|
+
// Projects rows sometimes arrive without a usable name — fall back to
|
|
3531
|
+
// the directory basename, then 'unknown'.
|
|
3532
|
+
const projRows = projects.map(p => {
|
|
3533
|
+
const raw = (p.project && p.project !== '?') ? p.project : (p.name && p.name !== '?' ? p.name : '');
|
|
3534
|
+
const base = String(p.dir || p.path || '').split('/').filter(Boolean).pop() || '';
|
|
3535
|
+
return Object.assign({}, p, { project: raw || base || 'unknown' });
|
|
3536
|
+
});
|
|
3511
3537
|
|
|
3512
3538
|
content.innerHTML = `
|
|
3513
3539
|
<!-- Overview stats -->
|
|
@@ -3536,8 +3562,8 @@ async function loadMemUsagePeriod(btn, period) {
|
|
|
3536
3562
|
<div style="margin-bottom:14px">${barChart(mcps, 'count', 'server', 'oklch(70% 0.18 60)', 8)}</div>` : ''}
|
|
3537
3563
|
|
|
3538
3564
|
<!-- Projects -->
|
|
3539
|
-
${
|
|
3540
|
-
<div style="margin-bottom:14px">${barChart(
|
|
3565
|
+
${projRows.length ? `<div class="m-group-title" style="margin-bottom:6px">Projects</div>
|
|
3566
|
+
<div style="margin-bottom:14px">${barChart(projRows, 'cost', 'project', 'oklch(65% 0.15 150)', 5)}</div>` : ''}
|
|
3541
3567
|
|
|
3542
3568
|
<!-- Fallback: session breakdown table if no breakdown data -->
|
|
3543
3569
|
${!models.length && !tools.length && rows.length ? `
|
|
@@ -6274,7 +6300,6 @@ const _v2AvatarKnown = new Set([
|
|
|
6274
6300
|
'quorum-manager','consensus-coordinator','perf-analyzer','benchmarker',
|
|
6275
6301
|
'task-orchestrator','memory-coordinator','load-balancer','resource-allocator',
|
|
6276
6302
|
'pr-manager','code-review-swarm','issue-tracker','release-manager','repo-architect',
|
|
6277
|
-
'workflow-automation','sparc-coord','sparc-coder','specification','pseudocode',
|
|
6278
6303
|
'architecture','refinement','backend-dev','frontend-developer','mobile-dev',
|
|
6279
6304
|
'ml-developer','cicd-engineer','system-architect','ai-engineer','model-qa',
|
|
6280
6305
|
'data-engineer','analytics-reporter','experiment-tracker','data-consolidator',
|
|
@@ -8227,7 +8252,7 @@ function v2RenderOrgConfig() {
|
|
|
8227
8252
|
const rc = d.run_config || {};
|
|
8228
8253
|
const gov = (d.governance && typeof d.governance === 'object') ? d.governance : { policy: d.governance || 'auto' };
|
|
8229
8254
|
const topos = ['hierarchical','hierarchical-mesh','mesh','star','ring','adaptive','hybrid'];
|
|
8230
|
-
const modes = ['daemon','once','scheduled'];
|
|
8255
|
+
const modes = [{ v: 'daemon', l: 'persistent (daemon)' }, { v: 'once', l: 'once' }, { v: 'scheduled', l: 'scheduled' }];
|
|
8231
8256
|
const statuses = ['active','paused','archived'];
|
|
8232
8257
|
const govPolicies = ['auto','board','strict'];
|
|
8233
8258
|
const inp = (id,val,type,extra) => '<input class="filter-input" id="'+id+'" type="'+(type||'text')+'" value="'+esc(String(val??''))+'" '+(extra||'')+' style="width:100%;box-sizing:border-box">';
|
|
@@ -8239,7 +8264,7 @@ function v2RenderOrgConfig() {
|
|
|
8239
8264
|
fld('Name', inp('oc-name', d.name||'','text','readonly style="opacity:0.5"'))
|
|
8240
8265
|
+fld('Status', sel('oc-status', statuses, d.status||'active'))
|
|
8241
8266
|
+'<div style="grid-column:1/-1">'+fld('Goal', '<textarea id="oc-goal" class="filter-input" rows="3" style="width:100%;box-sizing:border-box;resize:vertical;line-height:1.5">'+esc(d.goal||'')+'</textarea>')+'</div>'
|
|
8242
|
-
+fld('Mode',
|
|
8267
|
+
+fld('Mode', '<select class="filter-input" id="oc-mode" style="width:100%;box-sizing:border-box;cursor:pointer">'+modes.map(o=>'<option value="'+esc(o.v)+'"'+((d.mode||'daemon')===o.v?' selected':'')+'>'+esc(o.l)+'</option>').join('')+'</select>')
|
|
8243
8268
|
+fld('Topology', sel('oc-topology', topos, d.topology||'hierarchical'))
|
|
8244
8269
|
+'<div style="grid-column:1/-1">'+fld('Schedule', inp('oc-schedule', d.schedule||''))+'</div>'
|
|
8245
8270
|
)
|
|
@@ -9144,7 +9169,6 @@ const _MASTERMIND_SKILLS = [
|
|
|
9144
9169
|
'/monomind:repeat','monomind:review','monomind:understand','monomind:adr',
|
|
9145
9170
|
'/monomind:budget','monomind:graph-status','monomind:loops','monomind:swarm',
|
|
9146
9171
|
'/swarm:development','swarm:analysis','swarm:testing','swarm:optimization',
|
|
9147
|
-
'/sparc:architect','sparc:code','sparc:tdd','sparc:reviewer','sparc:security-review',
|
|
9148
9172
|
'/github:pr-manager','github:issue-tracker','github:release-manager',
|
|
9149
9173
|
];
|
|
9150
9174
|
window._allSkills = _MASTERMIND_SKILLS;
|
|
@@ -11871,8 +11895,16 @@ function renderMgOverview() {
|
|
|
11871
11895
|
const E = g.edges.length;
|
|
11872
11896
|
const avgDeg = N > 0 ? ((2 * E) / N).toFixed(1) : '0';
|
|
11873
11897
|
const typeSet = new Set(g.nodes.map(n => n.type || n.kind || 'unknown'));
|
|
11874
|
-
|
|
11875
|
-
|
|
11898
|
+
// The graph fetch is capped at 2000 nodes — prefer real totals from the
|
|
11899
|
+
// monograph report (set by mgLoadReport) and relabel honestly when capped.
|
|
11900
|
+
const _capped = N >= 2000 || E >= 2000;
|
|
11901
|
+
const _rt = window._mgRealTotals || null;
|
|
11902
|
+
const _nEl = document.getElementById('mg-stat-nodes');
|
|
11903
|
+
const _eEl = document.getElementById('mg-stat-edges');
|
|
11904
|
+
_nEl.textContent = (_rt && _rt.nodes) ? Number(_rt.nodes).toLocaleString() : N;
|
|
11905
|
+
_eEl.textContent = (_rt && _rt.edges) ? Number(_rt.edges).toLocaleString() : E;
|
|
11906
|
+
if (_nEl.previousElementSibling) _nEl.previousElementSibling.textContent = ((_rt && _rt.nodes) || !_capped) ? 'Nodes' : 'Nodes (top 2000)';
|
|
11907
|
+
if (_eEl.previousElementSibling) _eEl.previousElementSibling.textContent = ((_rt && _rt.edges) || !_capped) ? 'Edges' : 'Edges (top 2000)';
|
|
11876
11908
|
document.getElementById('mg-stat-avgdeg').textContent = avgDeg;
|
|
11877
11909
|
document.getElementById('mg-stat-types').textContent = typeSet.size;
|
|
11878
11910
|
|
|
@@ -11918,7 +11950,14 @@ function renderMgOverview() {
|
|
|
11918
11950
|
else {
|
|
11919
11951
|
const show = dead.slice(0, 12);
|
|
11920
11952
|
deadEl.innerHTML = `<table class="mg-table"><thead><tr><th>Name</th><th>Type</th></tr></thead><tbody>` +
|
|
11921
|
-
show.map(n =>
|
|
11953
|
+
show.map(n => {
|
|
11954
|
+
// Prefer a real name; if the label is just a generic type word
|
|
11955
|
+
// (e.g. "function"), fall back to the qualified id/path instead.
|
|
11956
|
+
const raw = n.label || n.name || '';
|
|
11957
|
+
const generic = !raw || /^(function|method|class|node|unknown|anonymous)$/i.test(String(raw).trim());
|
|
11958
|
+
const display = generic ? (n.id || n.name || raw || '') : raw;
|
|
11959
|
+
return `<tr><td title="${esc(n.id||n.name||n.label)}">${esc(mgShortLabel(display))}</td><td>${esc(n.type||n.kind||'')}</td></tr>`;
|
|
11960
|
+
}).join('') +
|
|
11922
11961
|
(dead.length > 12 ? `<tr><td colspan="2" style="color:var(--text-xs);font-size:11px">…and ${dead.length-12} more</td></tr>` : '') +
|
|
11923
11962
|
`</tbody></table>`;
|
|
11924
11963
|
}
|
|
@@ -12820,6 +12859,18 @@ async function mgLoadReport() {
|
|
|
12820
12859
|
// Extract markdown from JSON envelope {exists, report, stats}
|
|
12821
12860
|
const markdown = (data && data.report) ? data.report : (typeof data === 'string' ? data : JSON.stringify(data, null, 2));
|
|
12822
12861
|
const stats = (data && data.stats) || {};
|
|
12862
|
+
// Real graph totals — the overview cards otherwise show the capped fetch size
|
|
12863
|
+
const _mdN = (String(markdown).match(/\*\*Nodes\*\*:\s*([\d,]+)/i) || [])[1];
|
|
12864
|
+
const _mdE = (String(markdown).match(/\*\*Edges\*\*:\s*([\d,]+)/i) || [])[1];
|
|
12865
|
+
const _totN = stats.nodes || (_mdN ? Number(_mdN.replace(/,/g, '')) : null);
|
|
12866
|
+
const _totE = stats.edges || (_mdE ? Number(_mdE.replace(/,/g, '')) : null);
|
|
12867
|
+
if (_totN || _totE) {
|
|
12868
|
+
window._mgRealTotals = { nodes: _totN, edges: _totE };
|
|
12869
|
+
const nEl = document.getElementById('mg-stat-nodes');
|
|
12870
|
+
const eEl = document.getElementById('mg-stat-edges');
|
|
12871
|
+
if (_totN && nEl) { nEl.textContent = Number(_totN).toLocaleString(); if (nEl.previousElementSibling) nEl.previousElementSibling.textContent = 'Nodes'; }
|
|
12872
|
+
if (_totE && eEl) { eEl.textContent = Number(_totE).toLocaleString(); if (eEl.previousElementSibling) eEl.previousElementSibling.textContent = 'Edges'; }
|
|
12873
|
+
}
|
|
12823
12874
|
mgRenderReport(markdown, el, stats);
|
|
12824
12875
|
} catch (err) {
|
|
12825
12876
|
el.innerHTML = `<div style="color:var(--red);font-size:12px">Error: ${esc(String(err))}</div>`;
|
|
@@ -13156,7 +13207,7 @@ function mgWikiFindRelated(nodeId) {
|
|
|
13156
13207
|
}
|
|
13157
13208
|
|
|
13158
13209
|
function mgWikiRefresh() {
|
|
13159
|
-
_mgLoaded = false; _mgGraph = null;
|
|
13210
|
+
_mgLoaded = false; _mgGraph = null; window._mgRealTotals = null;
|
|
13160
13211
|
document.getElementById('mg-wiki-list').innerHTML = '<div class="loading-txt">Loading…</div>';
|
|
13161
13212
|
loadMonograph();
|
|
13162
13213
|
}
|
|
@@ -13383,7 +13434,7 @@ async function selectSwarmRun(idx) {
|
|
|
13383
13434
|
detail.innerHTML =
|
|
13384
13435
|
'<div style="margin-bottom:10px">' +
|
|
13385
13436
|
'<div style="font-size:13px;font-weight:600;color:var(--text-hi)">' + esc((run.swarmId || run.id || '—').toString().slice(0, 14)) + '</div>' +
|
|
13386
|
-
'<div style="font-size:11px;color:var(--text-lo);margin-top:3px">' + esc(run.topology || '—') + ' · ' + esc(run.consensus
|
|
13437
|
+
'<div style="font-size:11px;color:var(--text-lo);margin-top:3px">' + esc(run.topology || '—') + ' · ' + (run.consensus ? esc(run.consensus) + ' vote-threshold' : '—') + ' · ' + (run.agentCount || 0) + ' agents</div>' +
|
|
13387
13438
|
'</div>' +
|
|
13388
13439
|
'<canvas id="swarm-topo-canvas" style="width:100%;max-width:380px;height:190px;display:block;border:1px solid var(--border);border-radius:6px;margin-bottom:12px"></canvas>' +
|
|
13389
13440
|
'<div id="swarm-agent-list" style="margin-bottom:10px"></div>' +
|
|
@@ -13545,25 +13596,40 @@ function _renderChunks(list) {
|
|
|
13545
13596
|
grid.innerHTML = '<div class="empty">No chunks indexed.<br><span style="font-size:11px;color:var(--text-xs)">Run /monomind:understand to build the index.</span></div>';
|
|
13546
13597
|
return;
|
|
13547
13598
|
}
|
|
13548
|
-
|
|
13599
|
+
// Keep the rendered slice around so button handlers can look chunks up by
|
|
13600
|
+
// index — interpolating chunk content into onclick attributes broke (and
|
|
13601
|
+
// leaked markup) whenever the text contained quotes.
|
|
13602
|
+
const shown = list.slice(0, 200);
|
|
13603
|
+
window._chunksShown = shown;
|
|
13604
|
+
grid.innerHTML = shown.map((c, i) => {
|
|
13549
13605
|
const src = (c.source || c.file || '').split('/').slice(-2).join('/');
|
|
13550
13606
|
const excerpt = (c.content || c.text || c.body || '').slice(0, 220);
|
|
13551
13607
|
const ns = c.namespace || c.type || '';
|
|
13552
|
-
const chunkId = JSON.stringify(c.id || c.path || c.source || '');
|
|
13553
|
-
const chunkContent = JSON.stringify(c.content || c.text || c.body || '');
|
|
13554
|
-
const chunkSrc = JSON.stringify(src);
|
|
13555
13608
|
return '<div class="chunk-card" data-search="' + esc((src + ' ' + excerpt + ' ' + ns).toLowerCase()) + '">' +
|
|
13556
13609
|
'<div class="chunk-src">' + esc(src || '—') + '</div>' +
|
|
13557
13610
|
'<div class="chunk-excerpt">' + esc(excerpt) + '</div>' +
|
|
13558
13611
|
'<div class="chunk-footer">' +
|
|
13559
13612
|
(ns ? '<span class="chunk-ns">' + esc(ns) + '</span>' : '') +
|
|
13560
|
-
'<button class="btn" style="margin-left:auto;font-size:10px;padding:1px 7px" onclick="
|
|
13561
|
-
'<button class="btn" style="font-size:10px;padding:1px 7px;color:var(--red);border-color:var(--red)" onclick="
|
|
13613
|
+
'<button class="btn" style="margin-left:auto;font-size:10px;padding:1px 7px" onclick="openChunkEditAt(' + i + ')">✎ Edit</button>' +
|
|
13614
|
+
'<button class="btn" style="font-size:10px;padding:1px 7px;color:var(--red);border-color:var(--red)" onclick="deleteChunkAt(' + i + ')">✕</button>' +
|
|
13562
13615
|
'</div>' +
|
|
13563
13616
|
'</div>';
|
|
13564
13617
|
}).join('');
|
|
13565
13618
|
}
|
|
13566
13619
|
|
|
13620
|
+
function openChunkEditAt(i) {
|
|
13621
|
+
const c = (window._chunksShown || [])[i];
|
|
13622
|
+
if (!c) return;
|
|
13623
|
+
const src = (c.source || c.file || '').split('/').slice(-2).join('/');
|
|
13624
|
+
openChunkEdit(c.id || c.path || c.source || '', c.content || c.text || c.body || '', src);
|
|
13625
|
+
}
|
|
13626
|
+
|
|
13627
|
+
function deleteChunkAt(i) {
|
|
13628
|
+
const c = (window._chunksShown || [])[i];
|
|
13629
|
+
if (!c) return;
|
|
13630
|
+
deleteChunk(c.id || c.path || c.source || '');
|
|
13631
|
+
}
|
|
13632
|
+
|
|
13567
13633
|
function openChunkEdit(id, content, srcLabel) {
|
|
13568
13634
|
_editChunkId = id;
|
|
13569
13635
|
document.getElementById('chunk-modal-title').textContent = 'Edit Chunk';
|
|
@@ -13665,7 +13731,28 @@ async function loadAgentGraphTab() {
|
|
|
13665
13731
|
if (bar) bar.innerHTML = '<div class="loading-txt">Loading…</div>';
|
|
13666
13732
|
try {
|
|
13667
13733
|
const data = await apiFetch('/api/graph?dir=' + enc(DIR));
|
|
13668
|
-
|
|
13734
|
+
// /api/graph returns {nodes, edges} — session nodes + agenttype nodes.
|
|
13735
|
+
// Transform into the summary/sessions shape this tab renders.
|
|
13736
|
+
const nodes = Array.isArray(data && data.nodes) ? data.nodes : [];
|
|
13737
|
+
const sessNodes = nodes.filter(n => n.type === 'session').sort((a, b) => (b.mtime || 0) - (a.mtime || 0));
|
|
13738
|
+
const agNodes = nodes.filter(n => n.type === 'agenttype');
|
|
13739
|
+
const sessions = sessNodes.map(n => ({
|
|
13740
|
+
id: n.id,
|
|
13741
|
+
turns: n.turns || 0,
|
|
13742
|
+
spawnCount: Object.values(n.agentSpawns || {}).reduce((a, b) => a + b, 0),
|
|
13743
|
+
toolCount: n.totalTools || 0,
|
|
13744
|
+
tools: n.toolCounts || {},
|
|
13745
|
+
agentTypes: n.agentSpawns || {},
|
|
13746
|
+
cost: n.cost,
|
|
13747
|
+
}));
|
|
13748
|
+
_agData = {
|
|
13749
|
+
sessions,
|
|
13750
|
+
sessionCount: sessions.length,
|
|
13751
|
+
agentTypes: agNodes.length,
|
|
13752
|
+
totalSpawns: agNodes.reduce((a, n) => a + (n.totalSpawns || 0), 0),
|
|
13753
|
+
totalToolCalls: sessions.reduce((a, s) => a + (s.toolCount || 0), 0),
|
|
13754
|
+
totalCost: sessions.reduce((a, s) => a + (Number(s.cost) || 0), 0),
|
|
13755
|
+
};
|
|
13669
13756
|
_renderAgSummary();
|
|
13670
13757
|
_renderAgSessList();
|
|
13671
13758
|
} catch (e) {
|
package/dist/src/ui/orgs.html
CHANGED
|
@@ -841,6 +841,15 @@ html, body {
|
|
|
841
841
|
<div class="meta-cell-value" id="meta-created" style="font-size:10px;color:var(--muted)">—</div>
|
|
842
842
|
</div>
|
|
843
843
|
</div>
|
|
844
|
+
|
|
845
|
+
<!-- Audit Coverage card (populated from /api/org-coverage; hidden when no coverage.json) -->
|
|
846
|
+
<div id="audit-coverage-card" style="display:none; background:var(--bg-panel); border:1px solid var(--border); border-radius:3px; padding:10px 14px;">
|
|
847
|
+
<div class="meta-cell-label" style="display:flex; align-items:center; gap:8px;">
|
|
848
|
+
AUDIT COVERAGE
|
|
849
|
+
<span id="acov-summary" style="letter-spacing:1px; color:var(--muted)"></span>
|
|
850
|
+
</div>
|
|
851
|
+
<div id="acov-areas" style="display:flex; flex-wrap:wrap; gap:6px; margin-top:2px;"></div>
|
|
852
|
+
</div>
|
|
844
853
|
<div id="chart-svg-wrap">
|
|
845
854
|
<svg id="org-chart-svg" viewBox="0 0 720 320">
|
|
846
855
|
<defs>
|
|
@@ -1203,6 +1212,51 @@ async function selectOrg(name) {
|
|
|
1203
1212
|
}
|
|
1204
1213
|
|
|
1205
1214
|
renderTab(currentTab);
|
|
1215
|
+
loadAuditCoverage(listOrg);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// ── Audit Coverage card (reads .monomind/audit/coverage.json via /api/org-coverage) ──
|
|
1219
|
+
async function loadAuditCoverage(listOrg) {
|
|
1220
|
+
const card = document.getElementById('audit-coverage-card');
|
|
1221
|
+
card.style.display = 'none';
|
|
1222
|
+
const esc = s => String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
|
1223
|
+
try {
|
|
1224
|
+
const dir = listOrg.projectDir || window._orgDir;
|
|
1225
|
+
const url = '/api/org-coverage' + (dir ? `?dir=${encodeURIComponent(dir)}` : '');
|
|
1226
|
+
const r = await fetch(url);
|
|
1227
|
+
if (!r.ok) return; // 404 = no coverage.json — keep card hidden
|
|
1228
|
+
const cov = await r.json();
|
|
1229
|
+
const areas = cov.areas && typeof cov.areas === 'object' ? cov.areas : {};
|
|
1230
|
+
const names = Object.keys(areas);
|
|
1231
|
+
if (!names.length) return;
|
|
1232
|
+
|
|
1233
|
+
const summ = [];
|
|
1234
|
+
if (cov.areas_converged != null && cov.areas_total != null) summ.push(`${cov.areas_converged}/${cov.areas_total} CONVERGED`);
|
|
1235
|
+
if (cov.current_area) summ.push(`NOW: ${String(cov.current_area).toUpperCase()}`);
|
|
1236
|
+
document.getElementById('acov-summary').textContent = summ.join(' · ');
|
|
1237
|
+
|
|
1238
|
+
const verdictColor = v => {
|
|
1239
|
+
const s = String(v || '').toUpperCase();
|
|
1240
|
+
if (s.includes('CONVERGE') || s.includes('KEEP') || s.includes('PASS') || s.includes('DONE')) return 'var(--green, oklch(68% 0.2 150))';
|
|
1241
|
+
if (s.includes('ITERATE') || s.includes('WARN')) return 'oklch(78% 0.18 80)';
|
|
1242
|
+
if (s.includes('FAIL') || s.includes('REJECT')) return 'var(--red, oklch(62% 0.22 25))';
|
|
1243
|
+
return 'var(--muted, oklch(55% 0.02 186))';
|
|
1244
|
+
};
|
|
1245
|
+
document.getElementById('acov-areas').innerHTML = names.map(name => {
|
|
1246
|
+
const a = areas[name] || {};
|
|
1247
|
+
const verdict = a.verdict || a.status || '—';
|
|
1248
|
+
const value = a.value_delivered || a.valueDelivered || null;
|
|
1249
|
+
const c = verdictColor(verdict);
|
|
1250
|
+
return `<span style="display:inline-flex; align-items:center; gap:5px; font-size:9px; font-family:var(--mono);
|
|
1251
|
+
border:1px solid var(--border); border-radius:3px; padding:2px 7px; color:var(--text);"
|
|
1252
|
+
title="${esc(value || verdict)}">
|
|
1253
|
+
${esc(name)}
|
|
1254
|
+
<span style="color:${c}; letter-spacing:1px;">${esc(String(verdict).toUpperCase())}</span>
|
|
1255
|
+
${value ? `<span style="color:var(--dim); max-width:180px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${esc(value)}</span>` : ''}
|
|
1256
|
+
</span>`;
|
|
1257
|
+
}).join('');
|
|
1258
|
+
card.style.display = '';
|
|
1259
|
+
} catch (_) { /* keep hidden */ }
|
|
1206
1260
|
}
|
|
1207
1261
|
|
|
1208
1262
|
function updateHeader(listOrg, data) {
|
package/dist/src/ui/server.mjs
CHANGED
|
@@ -171,11 +171,12 @@ function pathToSections(filename) {
|
|
|
171
171
|
if (f.includes('registry') || f.includes('registrations')) return ['agents'];
|
|
172
172
|
if (f.includes('route') || f.includes('worker-dispatch')) return ['hooks'];
|
|
173
173
|
if (f.includes('chunk') || f.includes('skills')) return ['knowledge'];
|
|
174
|
-
if (f.includes('memory
|
|
175
|
-
f.includes('monovector.db') || f.includes('ranked-context') ||
|
|
174
|
+
if (f.includes('auto-memory-store') || f.includes('episodes.jsonl') ||
|
|
176
175
|
(f.includes('/memory/') && f.endsWith('.md'))) return ['memory', 'sessions'];
|
|
177
176
|
if (f.includes('palace') || f.includes('drawers') || f.includes('identity')) return ['memory', 'sessions'];
|
|
178
|
-
if (f.includes('
|
|
177
|
+
if (f.includes('consolidation')) return ['metrics', 'memory'];
|
|
178
|
+
if (f.includes('ddd') || f.includes('audit') || f.includes('codebase-map') ||
|
|
179
|
+
f.includes('security-audit') || f.includes('performance')) return ['metrics'];
|
|
179
180
|
if (f.endsWith('.jsonl') || f.includes('sessions')) return ['sessions'];
|
|
180
181
|
return ['sessions', 'swarm', 'agents', 'tokens', 'hooks'];
|
|
181
182
|
}
|
|
@@ -1403,7 +1404,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
|
|
|
1403
1404
|
const adrs = [];
|
|
1404
1405
|
for (const { path: adrDir, group } of adrDirs) {
|
|
1405
1406
|
if (!fs.existsSync(adrDir)) continue;
|
|
1406
|
-
|
|
1407
|
+
// Skip AppleDouble junk ('._*') — exFAT volumes litter these and they aren't real ADRs
|
|
1408
|
+
const files = fs.readdirSync(adrDir).filter(f => f.endsWith('.md') && !f.startsWith('._') && f !== 'README.md' && f !== 'v3-adrs.md' && f !== 'SECURITY-REVIEW-SUMMARY.md');
|
|
1407
1409
|
for (const fname of files.sort()) {
|
|
1408
1410
|
const resolvedGroup = /^ADR-G/i.test(fname) ? 'guidance' : 'implementation';
|
|
1409
1411
|
try {
|
|
@@ -1621,10 +1623,26 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
|
|
|
1621
1623
|
});
|
|
1622
1624
|
}
|
|
1623
1625
|
|
|
1624
|
-
//
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1626
|
+
// Real v2 memory sources: auto-memory pattern store + episodic log
|
|
1627
|
+
let patterns = 0, patternsUpdated = null;
|
|
1628
|
+
try {
|
|
1629
|
+
const store = JSON.parse(fs.readFileSync(path.join(d, '.monomind', 'data', 'auto-memory-store.json'), 'utf8'));
|
|
1630
|
+
if (Array.isArray(store)) {
|
|
1631
|
+
patterns = store.length;
|
|
1632
|
+
for (const e of store) {
|
|
1633
|
+
if (e && typeof e.ts === 'number' && (!patternsUpdated || e.ts > patternsUpdated)) patternsUpdated = e.ts;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
} catch {}
|
|
1637
|
+
|
|
1638
|
+
let episodes = 0, lastEpisode = null;
|
|
1639
|
+
try {
|
|
1640
|
+
const lines = fs.readFileSync(path.join(d, '.monomind', 'episodic', 'episodes.jsonl'), 'utf8').split('\n').filter(Boolean);
|
|
1641
|
+
episodes = lines.length;
|
|
1642
|
+
if (lines.length) {
|
|
1643
|
+
try { const last = JSON.parse(lines[lines.length - 1]); lastEpisode = last.ts || last.timestamp || null; } catch {}
|
|
1644
|
+
}
|
|
1645
|
+
} catch {}
|
|
1628
1646
|
|
|
1629
1647
|
const stats = {
|
|
1630
1648
|
total,
|
|
@@ -1633,9 +1651,15 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
|
|
|
1633
1651
|
ns: Object.keys(byType).length,
|
|
1634
1652
|
size,
|
|
1635
1653
|
byType,
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1654
|
+
patterns,
|
|
1655
|
+
patternsUpdated,
|
|
1656
|
+
episodes,
|
|
1657
|
+
lastEpisode,
|
|
1658
|
+
memoryFiles: total,
|
|
1659
|
+
// Legacy keys (v1 backends removed in v2) — kept false for frontend backward-safety
|
|
1660
|
+
hnsw: false,
|
|
1661
|
+
agentdb: false,
|
|
1662
|
+
rvf: false,
|
|
1639
1663
|
lastWrite,
|
|
1640
1664
|
memDir,
|
|
1641
1665
|
};
|
|
@@ -3476,7 +3500,9 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
3476
3500
|
if (req.method === 'GET' && url.startsWith('/api/token-usage')) {
|
|
3477
3501
|
try {
|
|
3478
3502
|
const qs = new URL(req.url, 'http://localhost').searchParams;
|
|
3479
|
-
|
|
3503
|
+
// Frontend sends ?range=..., older callers use ?period=... — accept both
|
|
3504
|
+
const _periodRaw = qs.get('period') || qs.get('range');
|
|
3505
|
+
const period = ['today','week','30days','month'].includes(_periodRaw) ? _periodRaw : 'today';
|
|
3480
3506
|
const dir = path.resolve(qs.get('dir') || projectDir || process.cwd());
|
|
3481
3507
|
const trackerPath = path.join(dir, '.claude', 'helpers', 'token-tracker.cjs');
|
|
3482
3508
|
const fallback = () => {
|
|
@@ -5625,6 +5651,33 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
5625
5651
|
return;
|
|
5626
5652
|
}
|
|
5627
5653
|
|
|
5654
|
+
// ------------------------------------------------- GET /api/playbooks
|
|
5655
|
+
// List playbook definitions from <dir>/.monomind/playbooks/*.json.
|
|
5656
|
+
// (Previously only POST was registered, so GET /api/playbooks?dir=... fell
|
|
5657
|
+
// through to the 404 handler.)
|
|
5658
|
+
if (req.method === 'GET' && url === '/api/playbooks') {
|
|
5659
|
+
try {
|
|
5660
|
+
const qp = new URL(req.url, 'http://localhost').searchParams;
|
|
5661
|
+
const dir = qp.get('dir') || projectDir || process.cwd();
|
|
5662
|
+
const playbookDir = path.join(path.resolve(dir), '.monomind', 'playbooks');
|
|
5663
|
+
const result = [];
|
|
5664
|
+
if (fs.existsSync(playbookDir)) {
|
|
5665
|
+
const files = fs.readdirSync(playbookDir).filter(f => f.endsWith('.json') && !f.startsWith('._'));
|
|
5666
|
+
for (const file of files) {
|
|
5667
|
+
try {
|
|
5668
|
+
const fpath = path.join(playbookDir, file);
|
|
5669
|
+
const def = JSON.parse(fs.readFileSync(fpath, 'utf8'));
|
|
5670
|
+
const stat = fs.statSync(fpath);
|
|
5671
|
+
result.push({ ...def, id: def.id || file.replace('.json', ''), file, modifiedAt: stat.mtimeMs });
|
|
5672
|
+
} catch (_) {}
|
|
5673
|
+
}
|
|
5674
|
+
}
|
|
5675
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-cache' });
|
|
5676
|
+
res.end(JSON.stringify(result));
|
|
5677
|
+
} catch (e) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: e.message })); }
|
|
5678
|
+
return;
|
|
5679
|
+
}
|
|
5680
|
+
|
|
5628
5681
|
// ------------------------------------------------- POST /api/playbooks
|
|
5629
5682
|
// Save a playbook definition to .monomind/playbooks/<id>.json
|
|
5630
5683
|
if (req.method === 'POST' && url === '/api/playbooks') {
|
|
@@ -5685,6 +5738,28 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
5685
5738
|
return;
|
|
5686
5739
|
}
|
|
5687
5740
|
|
|
5741
|
+
// ------------------------------------------------- GET /api/org-coverage
|
|
5742
|
+
// Audit coverage report written by the audit loop to .monomind/audit/coverage.json
|
|
5743
|
+
if (req.method === 'GET' && url === '/api/org-coverage') {
|
|
5744
|
+
try {
|
|
5745
|
+
const qp = new URL(req.url, 'http://localhost').searchParams;
|
|
5746
|
+
const dir = path.resolve(qp.get('dir') || projectDir || process.cwd());
|
|
5747
|
+
const covPath = path.join(dir, '.monomind', 'audit', 'coverage.json');
|
|
5748
|
+
if (!fs.existsSync(covPath)) {
|
|
5749
|
+
res.writeHead(404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
5750
|
+
res.end('{}');
|
|
5751
|
+
return;
|
|
5752
|
+
}
|
|
5753
|
+
const coverage = JSON.parse(fs.readFileSync(covPath, 'utf8'));
|
|
5754
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-cache' });
|
|
5755
|
+
res.end(JSON.stringify(coverage));
|
|
5756
|
+
} catch (e) {
|
|
5757
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
5758
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
5759
|
+
}
|
|
5760
|
+
return;
|
|
5761
|
+
}
|
|
5762
|
+
|
|
5688
5763
|
// ------------------------------------------------- GET /api/workflow-runs
|
|
5689
5764
|
if (req.method === 'GET' && url === '/api/workflow-runs') {
|
|
5690
5765
|
// Reads from ~/.monomind/browse-runs.json written by the monobrowse dashboard server.
|