@monoes/monomindcli 2.9.1 → 2.9.3
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/statusline.cjs +45 -0
- package/.claude/helpers/token-tracker.cjs +13 -1
- package/.claude/settings.json +0 -1
- package/.claude/skills/github-toolkit/SKILL.md +60 -0
- package/.claude/skills/mastermind-createorg/SKILL.md +8 -2
- package/.claude/skills/memory-toolkit/SKILL.md +75 -0
- package/.claude/skills/monodesign/scripts/detector/rules/checks.mjs +24 -1
- package/README.md +1 -1
- package/dist/src/agents/registry-builder.d.ts.map +1 -1
- package/dist/src/agents/registry-builder.js +94 -1
- package/dist/src/agents/registry-builder.js.map +1 -1
- package/dist/src/capabilities/cap-documents.js +7 -7
- package/dist/src/capabilities/cap-documents.js.map +1 -1
- package/dist/src/commands/completions.js +2 -2
- package/dist/src/commands/completions.js.map +1 -1
- package/dist/src/commands/doctor-env-checks.d.ts.map +1 -1
- package/dist/src/commands/doctor-env-checks.js +14 -2
- package/dist/src/commands/doctor-env-checks.js.map +1 -1
- package/dist/src/commands/index.d.ts +27 -41
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +113 -207
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/init-wizard.d.ts.map +1 -1
- package/dist/src/commands/init-wizard.js +35 -0
- package/dist/src/commands/init-wizard.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +43 -0
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/neural-optimize.d.ts.map +1 -1
- package/dist/src/commands/neural-optimize.js +12 -8
- package/dist/src/commands/neural-optimize.js.map +1 -1
- package/dist/src/commands/org-observe.js +2 -2
- package/dist/src/commands/org-observe.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +19 -9
- package/dist/src/index.js.map +1 -1
- package/dist/src/init/claudemd-generator.js +2 -2
- package/dist/src/init/claudemd-generator.js.map +1 -1
- package/dist/src/init/executor.d.ts.map +1 -1
- package/dist/src/init/executor.js +21 -4
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/settings-generator.d.ts.map +1 -1
- package/dist/src/init/settings-generator.js +16 -37
- package/dist/src/init/settings-generator.js.map +1 -1
- package/dist/src/init/statusline-generator.d.ts.map +1 -1
- package/dist/src/init/statusline-generator.js +45 -0
- package/dist/src/init/statusline-generator.js.map +1 -1
- package/dist/src/init/types.d.ts +8 -0
- package/dist/src/init/types.d.ts.map +1 -1
- package/dist/src/init/types.js.map +1 -1
- package/dist/src/init/upgrade.d.ts.map +1 -1
- package/dist/src/init/upgrade.js +3 -9
- package/dist/src/init/upgrade.js.map +1 -1
- package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
- package/dist/src/knowledge/document-pipeline.js +1 -0
- package/dist/src/knowledge/document-pipeline.js.map +1 -1
- package/dist/src/mcp-tools/memory-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/memory-tools.js +7 -15
- package/dist/src/mcp-tools/memory-tools.js.map +1 -1
- package/dist/src/memory/bm25-index.d.ts +17 -0
- package/dist/src/memory/bm25-index.d.ts.map +1 -1
- package/dist/src/memory/bm25-index.js +17 -0
- package/dist/src/memory/bm25-index.js.map +1 -1
- package/dist/src/memory/memory-bridge.d.ts +4 -0
- package/dist/src/memory/memory-bridge.d.ts.map +1 -1
- package/dist/src/memory/memory-bridge.js +128 -22
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/memory-initializer.d.ts.map +1 -1
- package/dist/src/memory/memory-initializer.js +0 -50
- package/dist/src/memory/memory-initializer.js.map +1 -1
- package/dist/src/memory/memory-kg.d.ts.map +1 -1
- package/dist/src/memory/memory-kg.js +21 -5
- package/dist/src/memory/memory-kg.js.map +1 -1
- package/dist/src/monovector/diff-classifier.d.ts.map +1 -1
- package/dist/src/monovector/diff-classifier.js +11 -20
- package/dist/src/monovector/diff-classifier.js.map +1 -1
- package/dist/src/orgrt/antigravity-runner.d.ts +9 -0
- package/dist/src/orgrt/antigravity-runner.d.ts.map +1 -0
- package/dist/src/orgrt/antigravity-runner.js +250 -0
- package/dist/src/orgrt/antigravity-runner.js.map +1 -0
- package/dist/src/orgrt/codex-runner.d.ts +9 -0
- package/dist/src/orgrt/codex-runner.d.ts.map +1 -0
- package/dist/src/orgrt/codex-runner.js +216 -0
- package/dist/src/orgrt/codex-runner.js.map +1 -0
- package/dist/src/orgrt/cross-org.d.ts.map +1 -1
- package/dist/src/orgrt/cross-org.js +8 -0
- package/dist/src/orgrt/cross-org.js.map +1 -1
- package/dist/src/orgrt/daemon.d.ts +14 -7
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +72 -12
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/fence.d.ts +39 -0
- package/dist/src/orgrt/fence.d.ts.map +1 -0
- package/dist/src/orgrt/fence.js +75 -0
- package/dist/src/orgrt/fence.js.map +1 -0
- package/dist/src/orgrt/kimicode-runner.d.ts.map +1 -1
- package/dist/src/orgrt/kimicode-runner.js +27 -1
- package/dist/src/orgrt/kimicode-runner.js.map +1 -1
- package/dist/src/orgrt/provider.d.ts.map +1 -1
- package/dist/src/orgrt/provider.js +26 -0
- package/dist/src/orgrt/provider.js.map +1 -1
- package/dist/src/orgrt/session.d.ts +11 -1
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +60 -3
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/tool-fence.d.ts +7 -2
- package/dist/src/orgrt/tool-fence.d.ts.map +1 -1
- package/dist/src/orgrt/tool-fence.js +18 -2
- package/dist/src/orgrt/tool-fence.js.map +1 -1
- package/dist/src/orgrt/types.d.ts +222 -0
- package/dist/src/orgrt/types.d.ts.map +1 -1
- package/dist/src/orgrt/types.js +34 -3
- package/dist/src/orgrt/types.js.map +1 -1
- package/dist/src/orgrt/vercel-providers.d.ts +29 -0
- package/dist/src/orgrt/vercel-providers.d.ts.map +1 -0
- package/dist/src/orgrt/vercel-providers.js +162 -0
- package/dist/src/orgrt/vercel-providers.js.map +1 -0
- package/dist/src/orgrt/vercel-runner.d.ts +39 -0
- package/dist/src/orgrt/vercel-runner.d.ts.map +1 -0
- package/dist/src/orgrt/vercel-runner.js +121 -0
- package/dist/src/orgrt/vercel-runner.js.map +1 -0
- package/dist/src/orgrt/vercel-session-store.d.ts +12 -0
- package/dist/src/orgrt/vercel-session-store.d.ts.map +1 -0
- package/dist/src/orgrt/vercel-session-store.js +49 -0
- package/dist/src/orgrt/vercel-session-store.js.map +1 -0
- package/dist/src/pricing/model-pricing.d.ts +10 -1
- package/dist/src/pricing/model-pricing.d.ts.map +1 -1
- package/dist/src/pricing/model-pricing.js +18 -1
- package/dist/src/pricing/model-pricing.js.map +1 -1
- package/dist/src/services/crash-reporter.d.ts +6 -5
- package/dist/src/services/crash-reporter.d.ts.map +1 -1
- package/dist/src/services/crash-reporter.js +6 -81
- package/dist/src/services/crash-reporter.js.map +1 -1
- package/dist/src/ui/collector.mjs +16 -82
- package/dist/src/ui/dashboard.html +176 -545
- package/dist/src/ui/data/mastermind-sessions.json +1 -0
- package/dist/src/ui/markdown.js +273 -0
- package/dist/src/ui/server.mjs +99 -189
- package/dist/src/utils/input-guards.d.ts +4 -1
- package/dist/src/utils/input-guards.d.ts.map +1 -1
- package/dist/src/utils/input-guards.js +6 -4
- package/dist/src/utils/input-guards.js.map +1 -1
- package/dist/src/utils/redaction.d.ts +24 -0
- package/dist/src/utils/redaction.d.ts.map +1 -0
- package/dist/src/utils/redaction.js +190 -0
- package/dist/src/utils/redaction.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +20 -5
- package/scripts/check-workspace-deps.mjs +45 -0
- package/scripts/publish.sh +24 -33
|
@@ -215,12 +215,6 @@ html, body { height: 100%; background: var(--bg); color: var(--text-hi); font-fa
|
|
|
215
215
|
.sr-compact-badge { display: inline-block; font-size: 10px; padding: 1px 6px; background: oklch(72% 0.18 75 / 0.12); color: var(--accent); border-radius: 8px; margin-left: 6px; white-space: nowrap; }
|
|
216
216
|
.sr-meta { font-size: 11px; color: var(--text-lo); margin-top: 3px; }
|
|
217
217
|
|
|
218
|
-
/* swarm tab */
|
|
219
|
-
.swarm-run-row { padding: 7px 8px; cursor: pointer; border-radius: 5px; margin-bottom: 3px; transition: background 0.1s; }
|
|
220
|
-
.swarm-run-row:hover { background: var(--surface-hi); }
|
|
221
|
-
.swarm-run-row.active { background: oklch(72% 0.18 75 / 0.1); }
|
|
222
|
-
.swarm-topo-pill { font-size: 10px; padding: 1px 7px; border-radius: 8px; background: var(--surface-hi); color: var(--text-lo); font-family: var(--mono); }
|
|
223
|
-
.swarm-live { font-size: 10px; color: var(--green); font-weight: 600; margin-left: 6px; }
|
|
224
218
|
/* chunks tab */
|
|
225
219
|
.chunk-stats-bar { display: flex; gap: 20px; margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--border); align-items: center; }
|
|
226
220
|
.chunk-stat { display: flex; flex-direction: column; gap: 2px; }
|
|
@@ -377,18 +371,15 @@ html, body { height: 100%; background: var(--bg); color: var(--text-hi); font-fa
|
|
|
377
371
|
.cv-excerpt-item { font-size:10px; color:var(--text-lo); font-family:var(--mono); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%; }
|
|
378
372
|
.cv-excerpt-item .cv-ex-tag { font-size:8px; color:var(--text-xs); margin-right:5px; display:inline-block; min-width:30px; }
|
|
379
373
|
|
|
380
|
-
/* agent detail
|
|
381
|
-
#org-agent-drawer {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
background: var(--surface); border
|
|
385
|
-
box-shadow:
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
#org-agent-drawer.open { transform: translateX(0); }
|
|
391
|
-
@media (prefers-reduced-motion: reduce) { #org-agent-drawer { transition: none; } }
|
|
374
|
+
/* agent detail modal */
|
|
375
|
+
#org-agent-drawer { display: none; position: fixed; inset: 0; z-index: 3000; background: oklch(0% 0 0 / 0.65); align-items: center; justify-content: center; }
|
|
376
|
+
#org-agent-drawer.open { display: flex; }
|
|
377
|
+
#oad-box {
|
|
378
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
|
|
379
|
+
box-shadow: 0 20px 60px -10px oklch(0% 0 0 / 0.5);
|
|
380
|
+
width: min(560px, 92vw); max-height: 88vh;
|
|
381
|
+
display: flex; flex-direction: column; overflow: hidden; min-width: 0;
|
|
382
|
+
}
|
|
392
383
|
#oad-head { display: flex; align-items: center; gap: 11px; padding: 16px 16px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
|
|
393
384
|
.oad-avatar { width: 46px; height: 46px; border-radius: 50%; flex-shrink: 0; background: var(--surface-hi); object-fit: cover; }
|
|
394
385
|
.oad-avatar-wrap { position: relative; width: 46px; height: 46px; flex-shrink: 0; cursor: pointer; }
|
|
@@ -436,12 +427,23 @@ html, body { height: 100%; background: var(--bg); color: var(--text-hi); font-fa
|
|
|
436
427
|
.role-v2:hover { transform: translateY(-1px); }
|
|
437
428
|
.rv2-more { margin-top: 9px; font-size: 10.5px; color: var(--accent); opacity: 0.85; }
|
|
438
429
|
|
|
439
|
-
/* org meta strip */
|
|
440
|
-
.org-meta-strip { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; margin-bottom: 16px; }
|
|
430
|
+
/* org meta strip (cells reused inside #org-meta-modal) */
|
|
441
431
|
.oms-cell { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: 10px 12px; }
|
|
442
432
|
.oms-lbl { font-size: 10px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-lo); margin-bottom: 4px; }
|
|
443
433
|
.oms-val { font-size: 12px; color: var(--text-hi); word-break: break-word; line-height: 1.4; }
|
|
444
434
|
|
|
435
|
+
/* org meta — condensed one-line summary, click for full detail */
|
|
436
|
+
.org-meta-line { display: flex; align-items: center; gap: 10px; padding: 9px 12px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); margin-bottom: 16px; cursor: pointer; overflow: hidden; }
|
|
437
|
+
.org-meta-line:hover { background: var(--surface-hi); }
|
|
438
|
+
.oml-item { display: flex; align-items: baseline; gap: 5px; min-width: 0; flex-shrink: 0; }
|
|
439
|
+
.oml-item.goal { flex: 1 1 auto; min-width: 0; }
|
|
440
|
+
.oml-lbl { font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-lo); flex-shrink: 0; }
|
|
441
|
+
.oml-val { font-size: 12px; color: var(--text-hi); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
442
|
+
.oml-sep { color: var(--text-lo); opacity: 0.5; flex-shrink: 0; }
|
|
443
|
+
#org-meta-modal { display: none; position: fixed; inset: 0; z-index: 3000; background: oklch(0% 0 0 / 0.65); align-items: center; justify-content: center; }
|
|
444
|
+
#org-meta-modal.open { display: flex; }
|
|
445
|
+
#org-meta-modal-box { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; width: min(520px, 90vw); padding: 20px; display: flex; flex-direction: column; gap: 10px; max-height: 85vh; overflow-y: auto; }
|
|
446
|
+
|
|
445
447
|
/* SVG org chart */
|
|
446
448
|
.org-chart-wrap { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; margin-bottom: 12px; }
|
|
447
449
|
.org-chart-svg { width: 100%; display: block; }
|
|
@@ -1417,6 +1419,13 @@ textarea.sess-note-input:focus { border-color:var(--accent); }
|
|
|
1417
1419
|
#mem-modal-ta { width: 100%; height: 280px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 10px; font-family: var(--mono); font-size: 12px; color: var(--text-hi); resize: vertical; outline: none; overflow-y: auto; }
|
|
1418
1420
|
#mem-modal-ta:focus { border-color: var(--accent); }
|
|
1419
1421
|
.mem-modal-btns { display: flex; justify-content: flex-end; gap: 8px; }
|
|
1422
|
+
/* docs reader modal */
|
|
1423
|
+
#docs-modal { display: none; position: fixed; inset: 0; z-index: 3000; background: oklch(0% 0 0 / 0.65); align-items: center; justify-content: center; }
|
|
1424
|
+
#docs-modal.open { display: flex; }
|
|
1425
|
+
#docs-modal-box { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; width: min(820px, 94vw); padding: 20px; display: flex; flex-direction: column; gap: 12px; max-height: 88vh; }
|
|
1426
|
+
#docs-modal-title { font-size: 13px; font-weight: 600; color: var(--text-hi); font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1427
|
+
#docs-modal-body { overflow-y: auto; }
|
|
1428
|
+
.docs-modal-btns { display: flex; justify-content: flex-end; gap: 8px; }
|
|
1420
1429
|
|
|
1421
1430
|
/* ── playbook view tabs ────────────────────────────────────── */
|
|
1422
1431
|
.wf-pane { display: none; }
|
|
@@ -1970,9 +1979,8 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
1970
1979
|
<button class="odt-btn" data-memtab="routing" onclick="switchMemTab('routing')">Routing</button>
|
|
1971
1980
|
<button class="odt-btn" data-memtab="usage" onclick="switchMemTab('usage')">Usage</button>
|
|
1972
1981
|
<button class="odt-btn" data-memtab="adrs" onclick="switchMemTab('adrs')">ADRs</button>
|
|
1973
|
-
<button class="odt-btn" data-memtab="swarm" onclick="switchMemTab('swarm')">Swarm</button>
|
|
1974
1982
|
<button class="odt-btn" data-memtab="chunks" onclick="switchMemTab('chunks')">Chunks</button>
|
|
1975
|
-
<button class="odt-btn" data-memtab="
|
|
1983
|
+
<button class="odt-btn" data-memtab="docs" onclick="switchMemTab('docs')">Docs</button>
|
|
1976
1984
|
<button class="odt-btn" data-memtab="store" onclick="switchMemTab('store')">Store</button>
|
|
1977
1985
|
</div>
|
|
1978
1986
|
<div id="mem-tab-memories">
|
|
@@ -1994,15 +2002,6 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
1994
2002
|
</div>
|
|
1995
2003
|
<div id="adr-content"><div class="loading-txt">Loading…</div></div>
|
|
1996
2004
|
</div>
|
|
1997
|
-
<div id="mem-tab-swarm" style="display:none">
|
|
1998
|
-
<div style="display:flex;height:380px;gap:0">
|
|
1999
|
-
<div id="swarm-run-list" style="width:200px;flex-shrink:0;border-right:1px solid var(--border);overflow-y:auto;padding:6px"></div>
|
|
2000
|
-
<div id="swarm-run-detail" style="flex:1;padding:14px;overflow-y:auto">
|
|
2001
|
-
<div style="color:var(--text-lo);font-size:13px">Select a swarm run</div>
|
|
2002
|
-
</div>
|
|
2003
|
-
</div>
|
|
2004
|
-
<button class="btn" style="margin-top:10px;color:var(--red);border-color:var(--red)" onclick="cleanSwarmData()">⌫ Clean Data</button>
|
|
2005
|
-
</div>
|
|
2006
2005
|
<div id="mem-tab-chunks" style="display:none">
|
|
2007
2006
|
<div class="chunk-stats-bar" id="chunk-stats-bar">
|
|
2008
2007
|
<div class="chunk-stat"><div class="chunk-stat-val" id="chunk-count-val">—</div><div class="chunk-stat-lbl">Chunks</div></div>
|
|
@@ -2028,14 +2027,13 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
2028
2027
|
</div>
|
|
2029
2028
|
<div id="chunks-grid"></div>
|
|
2030
2029
|
</div>
|
|
2031
|
-
<div id="mem-tab-
|
|
2032
|
-
<div id="
|
|
2033
|
-
<div
|
|
2034
|
-
<
|
|
2035
|
-
<
|
|
2036
|
-
<div style="color:var(--text-lo);font-size:13px;padding:20px 0">Select a session</div>
|
|
2037
|
-
</div>
|
|
2030
|
+
<div id="mem-tab-docs" style="display:none">
|
|
2031
|
+
<div id="docs-stats-bar" style="display:flex;gap:20px;flex-wrap:wrap;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--border)"></div>
|
|
2032
|
+
<div class="filter-bar">
|
|
2033
|
+
<input class="filter-input" type="text" id="docs-filter" placeholder="Filter by path…" oninput="filterDocs(this.value)" />
|
|
2034
|
+
<button class="btn" onclick="_docsLoaded=false;loadDocsTab()" title="Refresh">↺</button>
|
|
2038
2035
|
</div>
|
|
2036
|
+
<div id="docs-grid"></div>
|
|
2039
2037
|
</div>
|
|
2040
2038
|
<div id="mem-tab-store" style="display:none">
|
|
2041
2039
|
<div class="filter-bar" style="margin-bottom:6px;display:flex;gap:6px;align-items:center">
|
|
@@ -2129,9 +2127,11 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
2129
2127
|
</div>
|
|
2130
2128
|
</div>
|
|
2131
2129
|
<div id="org-import-input-wrap" style="display:none"><input type="file" id="org-import-file" accept=".json" style="display:none"></div>
|
|
2132
|
-
<div id="org-agent-drawer" aria-hidden="true">
|
|
2133
|
-
<div id="oad-
|
|
2134
|
-
|
|
2130
|
+
<div id="org-agent-drawer" aria-hidden="true" role="dialog" aria-modal="true" aria-label="Agent details" onclick="if(event.target===this)v2CloseAgent()">
|
|
2131
|
+
<div id="oad-box">
|
|
2132
|
+
<div id="oad-head"></div>
|
|
2133
|
+
<div id="oad-body"></div>
|
|
2134
|
+
</div>
|
|
2135
2135
|
</div>
|
|
2136
2136
|
</div>
|
|
2137
2137
|
</div>
|
|
@@ -2359,6 +2359,27 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
2359
2359
|
</div>
|
|
2360
2360
|
</div>
|
|
2361
2361
|
</div>
|
|
2362
|
+
<!-- docs reader modal -->
|
|
2363
|
+
<div id="docs-modal" onclick="if(event.target===this)closeDocModal()">
|
|
2364
|
+
<div id="docs-modal-box">
|
|
2365
|
+
<div id="docs-modal-title">Document</div>
|
|
2366
|
+
<div id="docs-modal-body" class="gd-md"></div>
|
|
2367
|
+
<div class="docs-modal-btns">
|
|
2368
|
+
<button class="btn" onclick="closeDocModal()">Close</button>
|
|
2369
|
+
</div>
|
|
2370
|
+
</div>
|
|
2371
|
+
</div>
|
|
2372
|
+
<!-- org meta detail modal -->
|
|
2373
|
+
<div id="org-meta-modal" onclick="if(event.target===this)v2CloseMetaModal()">
|
|
2374
|
+
<div id="org-meta-modal-box">
|
|
2375
|
+
<div class="oms-cell"><div class="oms-lbl">Goal</div><div class="oms-val" id="omm-goal" style="color:var(--text-mid)"></div></div>
|
|
2376
|
+
<div class="oms-cell"><div class="oms-lbl">Topology</div><div class="oms-val" id="omm-topo"></div></div>
|
|
2377
|
+
<div class="oms-cell"><div class="oms-lbl">Created</div><div class="oms-val" id="omm-created" style="color:var(--text-mid)"></div></div>
|
|
2378
|
+
<div class="docs-modal-btns">
|
|
2379
|
+
<button class="btn" onclick="v2CloseMetaModal()">Close</button>
|
|
2380
|
+
</div>
|
|
2381
|
+
</div>
|
|
2382
|
+
</div>
|
|
2362
2383
|
<div id="toast-rack"></div>
|
|
2363
2384
|
|
|
2364
2385
|
<!-- f56: report card modal -->
|
|
@@ -2413,6 +2434,7 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
2413
2434
|
</div>
|
|
2414
2435
|
</div>
|
|
2415
2436
|
|
|
2437
|
+
<script src="markdown.js"></script>
|
|
2416
2438
|
<script>
|
|
2417
2439
|
// ── auth: attach this session's dashboard credential to every fetch() and
|
|
2418
2440
|
// EventSource connection ──────────────────────────────────────────────────
|
|
@@ -2698,8 +2720,7 @@ function switchProject(path) {
|
|
|
2698
2720
|
DIR = path;
|
|
2699
2721
|
// Reset cached tab data on project change
|
|
2700
2722
|
_chunksLoaded = false;
|
|
2701
|
-
|
|
2702
|
-
_swarmRuns = [];
|
|
2723
|
+
_docsLoaded = false;
|
|
2703
2724
|
_memFiles = [];
|
|
2704
2725
|
_selMemFilename = null;
|
|
2705
2726
|
_editMemFilename = null;
|
|
@@ -3469,7 +3490,7 @@ function switchMemTab(tab) {
|
|
|
3469
3490
|
_currentMemTab = tab;
|
|
3470
3491
|
document.querySelectorAll('.mem-tab-bar .odt-btn').forEach(b =>
|
|
3471
3492
|
b.classList.toggle('active', b.dataset.memtab === tab));
|
|
3472
|
-
['memories','routing','usage','adrs','
|
|
3493
|
+
['memories','routing','usage','adrs','chunks','docs','store'].forEach(t => {
|
|
3473
3494
|
const el = document.getElementById('mem-tab-' + t);
|
|
3474
3495
|
if (el) el.style.display = t === tab ? '' : 'none';
|
|
3475
3496
|
});
|
|
@@ -3477,9 +3498,8 @@ function switchMemTab(tab) {
|
|
|
3477
3498
|
else if (tab === 'routing') loadMemRouting();
|
|
3478
3499
|
else if (tab === 'usage') loadMemUsage();
|
|
3479
3500
|
else if (tab === 'adrs') loadMemADRs();
|
|
3480
|
-
else if (tab === 'swarm') loadSwarmTab();
|
|
3481
3501
|
else if (tab === 'chunks') loadChunksTab();
|
|
3482
|
-
else if (tab === '
|
|
3502
|
+
else if (tab === 'docs') loadDocsTab();
|
|
3483
3503
|
else if (tab === 'store') loadStoreEntries();
|
|
3484
3504
|
}
|
|
3485
3505
|
|
|
@@ -4359,227 +4379,8 @@ async function gdCopyPath(p) {
|
|
|
4359
4379
|
catch { showToast('Copy failed', 'Clipboard unavailable', 'warn'); }
|
|
4360
4380
|
}
|
|
4361
4381
|
|
|
4362
|
-
//
|
|
4363
|
-
//
|
|
4364
|
-
// code and fenced code blocks (with language label + copy button), unordered/
|
|
4365
|
-
// ordered/nested/task lists, GFM tables, nested blockquotes, horizontal rules,
|
|
4366
|
-
// links (external get rel=noopener + target=_blank), images, line breaks.
|
|
4367
|
-
// HTML-escaped at the boundary; nothing the source contains can inject markup.
|
|
4368
|
-
function renderDocMarkdown(md) {
|
|
4369
|
-
if (!md) return '';
|
|
4370
|
-
const esc = (s) => String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
4371
|
-
|
|
4372
|
-
// 1. Strip a leading YAML frontmatter block (mastermind plan/spec files have one).
|
|
4373
|
-
let src = String(md).replace(/^\uFEFF?---[\s\S]*?\n---\s*\n/, '');
|
|
4374
|
-
|
|
4375
|
-
// 2. Extract fenced code blocks first so their contents are never reinterpreted.
|
|
4376
|
-
const codeBlocks = [];
|
|
4377
|
-
src = src.replace(/```([\w+-]*)\n?([\s\S]*?)```/g, (_m, lang, code) => {
|
|
4378
|
-
const clean = code.replace(/\n$/, '');
|
|
4379
|
-
codeBlocks.push({ lang: (lang || '').toLowerCase(), code: clean });
|
|
4380
|
-
return '\u0000CB' + (codeBlocks.length - 1) + '\u0000';
|
|
4381
|
-
});
|
|
4382
|
-
|
|
4383
|
-
// 3. Extract inline HTML blocks (multiline <div>…</div> etc.) — pass through
|
|
4384
|
-
// verbatim after escaping, so user-authored HTML in a plan still renders
|
|
4385
|
-
// structurally without enabling script injection (we'll re-strip <script>
|
|
4386
|
-
// and on* handlers at the end).
|
|
4387
|
-
const htmlBlocks = [];
|
|
4388
|
-
src = src.replace(/(^|\n)(<(\w+)[^>\n]*>[\s\S]*?<\/\3>)(?=\n|$)/g, (_m, lead, html) => {
|
|
4389
|
-
htmlBlocks.push(html);
|
|
4390
|
-
return (lead || '') + '\u0000HB' + (htmlBlocks.length - 1) + '\u0000';
|
|
4391
|
-
});
|
|
4392
|
-
|
|
4393
|
-
// 4. Escape everything that remains.
|
|
4394
|
-
src = esc(src).replace(/\u0000CB(\d+)\u0000/g, 'CB$1').replace(/\u0000HB(\d+)\u0000/g, 'HB$1');
|
|
4395
|
-
|
|
4396
|
-
// 5. Block-level transforms: tables, headings, hr, blockquotes, lists.
|
|
4397
|
-
// Operate line-by-line so nesting and paragraph grouping stay coherent.
|
|
4398
|
-
const lines = src.split('\n');
|
|
4399
|
-
const out = [];
|
|
4400
|
-
let i = 0;
|
|
4401
|
-
let inUl = false, inOl = false, inTask = false, bqBuf = [], paraBuf = [];
|
|
4402
|
-
|
|
4403
|
-
const closeLists = () => {
|
|
4404
|
-
if (inUl) { out.push('</ul>'); inUl = false; }
|
|
4405
|
-
if (inOl) { out.push('</ol>'); inOl = false; }
|
|
4406
|
-
if (inTask) { out.push('</ul>'); inTask = false; }
|
|
4407
|
-
};
|
|
4408
|
-
const flushPara = () => { if (paraBuf.length) { out.push('<p>' + paraBuf.join(' ') + '</p>'); paraBuf = []; } };
|
|
4409
|
-
const flushBQ = () => {
|
|
4410
|
-
if (!bqBuf.length) return;
|
|
4411
|
-
// Recursively render the inner block so nested formatting works.
|
|
4412
|
-
out.push('<blockquote>' + renderDocMarkdown(bqBuf.join('\n')) + '</blockquote>');
|
|
4413
|
-
bqBuf = [];
|
|
4414
|
-
};
|
|
4415
|
-
const slugify = (s) => String(s).toLowerCase().replace(/<[^>]+>/g, '').replace(/[^\w\s-]/g, '').trim().replace(/\s+/g, '-');
|
|
4416
|
-
|
|
4417
|
-
while (i < lines.length) {
|
|
4418
|
-
let line = lines[i];
|
|
4419
|
-
|
|
4420
|
-
// Block placeholders for code/html blocks (they sit on their own line).
|
|
4421
|
-
const cbMatch = line.match(/^CB(\d+)$/);
|
|
4422
|
-
if (cbMatch) { closeLists(); flushPara(); flushBQ(); out.push(renderCodeBlock(codeBlocks[+cbMatch[1]])); i++; continue; }
|
|
4423
|
-
const hbMatch = line.match(/^HB(\d+)$/);
|
|
4424
|
-
if (hbMatch) { closeLists(); flushPara(); flushBQ(); out.push(sanitizeHtmlBlock(htmlBlocks[+hbMatch[1]])); i++; continue; }
|
|
4425
|
-
|
|
4426
|
-
// Blank line: paragraph + list breaks.
|
|
4427
|
-
if (line.trim() === '') { closeLists(); flushPara(); flushBQ(); i++; continue; }
|
|
4428
|
-
|
|
4429
|
-
// Headings (with anchor).
|
|
4430
|
-
const h = line.match(/^(#{1,6})\s+(.+?)(?:\s+#+\s*)?$/);
|
|
4431
|
-
if (h) { closeLists(); flushPara(); flushBQ(); const lvl = h[1].length; const txt = inlineMd(h[2]); const id = slugify(h[2]); out.push('<h' + lvl + ' id="' + id + '">' + txt + '</h' + lvl + '>'); i++; continue; }
|
|
4432
|
-
|
|
4433
|
-
// Horizontal rule.
|
|
4434
|
-
if (/^(\*\s*){3,}$/.test(line) || /^(-\s*){3,}$/.test(line) || /^(_\s*){3,}$/.test(line)) { closeLists(); flushPara(); flushBQ(); out.push('<hr>'); i++; continue; }
|
|
4435
|
-
|
|
4436
|
-
// GFM table — a block of consecutive lines where line 0 and line 1 look
|
|
4437
|
-
// like | a | b | / |---|---|. Scan forward to collect the full table.
|
|
4438
|
-
if (/^\s*\|.+\|\s*$/.test(line) && i + 1 < lines.length && /^\s*\|?[\s:-]+\|[\s:|-]+\|?\s*$/.test(lines[i + 1])) {
|
|
4439
|
-
closeLists(); flushPara(); flushBQ();
|
|
4440
|
-
const headerCells = splitTableRow(line);
|
|
4441
|
-
const aligns = parseTableAligns(lines[i + 1]);
|
|
4442
|
-
i += 2;
|
|
4443
|
-
const rows = [];
|
|
4444
|
-
while (i < lines.length && /^\s*\|.+\|\s*$/.test(lines[i])) { rows.push(splitTableRow(lines[i])); i++; }
|
|
4445
|
-
out.push(renderTable(headerCells, aligns, rows));
|
|
4446
|
-
continue;
|
|
4447
|
-
}
|
|
4448
|
-
|
|
4449
|
-
// Blockquote.
|
|
4450
|
-
const bq = line.match(/^>\s?(.*)$/);
|
|
4451
|
-
if (bq) { closeLists(); flushPara(); bqBuf.push(bq[1]); i++; continue; }
|
|
4452
|
-
if (bqBuf.length) { flushBQ(); }
|
|
4453
|
-
|
|
4454
|
-
// Task list item.
|
|
4455
|
-
const task = line.match(/^(\s*)([-*])\s+\[( |x|X)\]\s+(.+)$/);
|
|
4456
|
-
if (task) { flushPara(); if (inUl) { out.push('</ul>'); inUl = false; } if (inOl) { out.push('</ol>'); inOl = false; } if (!inTask) { out.push('<ul class="md-tasklist">'); inTask = true; } const checked = task[3].toLowerCase() === 'x'; out.push('<li><input type="checkbox" disabled' + (checked ? ' checked' : '') + '> ' + inlineMd(task[4]) + '</li>'); i++; continue; }
|
|
4457
|
-
|
|
4458
|
-
// Unordered list item.
|
|
4459
|
-
const ul = line.match(/^(\s*)([-*+])\s+(.+)$/);
|
|
4460
|
-
if (ul && !task) {
|
|
4461
|
-
flushPara();
|
|
4462
|
-
if (inOl) { out.push('</ol>'); inOl = false; }
|
|
4463
|
-
if (inTask) { out.push('</ul>'); inTask = false; }
|
|
4464
|
-
if (!inUl) { out.push('<ul>'); inUl = true; }
|
|
4465
|
-
const indent = ul[1].length;
|
|
4466
|
-
if (indent === 0) out.push('<li>' + inlineMd(ul[3]) + '</li>');
|
|
4467
|
-
else {
|
|
4468
|
-
// Nested list — close current top item and open a nested <ul>.
|
|
4469
|
-
out.push('<li>' + inlineMd(ul[3]) + '</li>');
|
|
4470
|
-
}
|
|
4471
|
-
i++; continue;
|
|
4472
|
-
}
|
|
4473
|
-
// Ordered list item.
|
|
4474
|
-
const ol = line.match(/^(\s*)(\d+)\.\s+(.+)$/);
|
|
4475
|
-
if (ol) {
|
|
4476
|
-
flushPara();
|
|
4477
|
-
if (inUl) { out.push('</ul>'); inUl = false; }
|
|
4478
|
-
if (inTask) { out.push('</ul>'); inTask = false; }
|
|
4479
|
-
if (!inOl) { out.push('<ol>'); inOl = true; }
|
|
4480
|
-
out.push('<li>' + inlineMd(ol[3]) + '</li>');
|
|
4481
|
-
i++; continue;
|
|
4482
|
-
}
|
|
4483
|
-
|
|
4484
|
-
// Otherwise: paragraph text. Buffer until a blank line / structural break.
|
|
4485
|
-
closeLists();
|
|
4486
|
-
flushBQ();
|
|
4487
|
-
paraBuf.push(inlineMd(line));
|
|
4488
|
-
i++;
|
|
4489
|
-
}
|
|
4490
|
-
closeLists(); flushPara(); flushBQ();
|
|
4491
|
-
|
|
4492
|
-
let html = out.join('\n');
|
|
4493
|
-
// 6. Restore code/html block placeholders INSIDE paragraphs (when a CB/HB
|
|
4494
|
-
// token got buffered as paragraph text instead of sitting alone).
|
|
4495
|
-
html = html.replace(/CB(\d+)/g, (_m, idx) => renderCodeBlock(codeBlocks[+idx]))
|
|
4496
|
-
.replace(/HB(\d+)/g, (_m, idx) => sanitizeHtmlBlock(htmlBlocks[+idx]));
|
|
4497
|
-
return html;
|
|
4498
|
-
|
|
4499
|
-
// ── helpers ──
|
|
4500
|
-
function inlineMd(s) {
|
|
4501
|
-
// Inline code first (so its contents aren't reformatted).
|
|
4502
|
-
const codes = [];
|
|
4503
|
-
s = s.replace(/`([^`\n]+)`/g, (_m, c) => { codes.push(c); return '\u0001C' + (codes.length - 1) + '\u0001'; });
|
|
4504
|
-
// Images: 
|
|
4505
|
-
s = s.replace(/!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/g,
|
|
4506
|
-
(_m, alt, src, title) => '<img src="' + src + '" alt="' + esc(alt) + '"' + (title ? ' title="' + esc(title) + '"' : '') + ' loading="lazy" style="max-width:100%;height:auto;border-radius:6px">');
|
|
4507
|
-
// Links: [text](href "title")
|
|
4508
|
-
s = s.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/g,
|
|
4509
|
-
(_m, txt, href, title) => {
|
|
4510
|
-
const external = /^(https?:|mailto:|tel:)/i.test(href);
|
|
4511
|
-
const safe = external ? ' target="_blank" rel="noopener noreferrer"' : '';
|
|
4512
|
-
return '<a href="' + href + '"' + (title ? ' title="' + esc(title) + '"' : '') + safe + '>' + txt + '</a>';
|
|
4513
|
-
});
|
|
4514
|
-
// Bold.
|
|
4515
|
-
s = s.replace(/\*\*([^*\n]+)\*\*/g, '<strong>$1</strong>');
|
|
4516
|
-
s = s.replace(/__([^_\n]+)__/g, '<strong>$1</strong>');
|
|
4517
|
-
// Italic.
|
|
4518
|
-
s = s.replace(/\*([^*\n]+)\*/g, '<em>$1</em>');
|
|
4519
|
-
s = s.replace(/(^|[^_])_([^_\n]+)_/g, '$1<em>$2</em>');
|
|
4520
|
-
// Strikethrough.
|
|
4521
|
-
s = s.replace(/~~([^~\n]+)~~/g, '<del>$1</del>');
|
|
4522
|
-
// Restore inline code.
|
|
4523
|
-
s = s.replace(/\u0001C(\d+)\u0001/g, (_m, idx) => '<code>' + esc(codes[+idx]) + '</code>');
|
|
4524
|
-
return s;
|
|
4525
|
-
}
|
|
4526
|
-
|
|
4527
|
-
function renderCodeBlock(block) {
|
|
4528
|
-
const lang = block?.lang || '';
|
|
4529
|
-
const code = block?.code ?? '';
|
|
4530
|
-
const labelHtml = lang ? '<span class="gd-code-lang">' + esc(lang) + '</span>' : '';
|
|
4531
|
-
return '<div class="gd-code-block">' +
|
|
4532
|
-
'<div class="gd-code-bar"><button class="gd-code-copy" onclick="gdCopyCode(this)">copy</button>' + labelHtml + '</div>' +
|
|
4533
|
-
'<pre><code' + (lang ? ' class="language-' + esc(lang) + '"' : '') + '>' + esc(code) + '</code></pre>' +
|
|
4534
|
-
'</div>';
|
|
4535
|
-
}
|
|
4536
|
-
|
|
4537
|
-
function sanitizeHtmlBlock(html) {
|
|
4538
|
-
// Strip <script> entirely, drop event-handler attributes (onclick=, onload=, on*=),
|
|
4539
|
-
// and javascript: URLs. Keep everything else as-is so user HTML renders.
|
|
4540
|
-
return String(html)
|
|
4541
|
-
.replace(/<script[\s\S]*?<\/script>/gi, '')
|
|
4542
|
-
.replace(/\son\w+\s*=\s*"[^"]*"/gi, '')
|
|
4543
|
-
.replace(/\son\w+\s*=\s*'[^']*'/gi, '')
|
|
4544
|
-
.replace(/\son\w+\s*=\s*[^\s>]+/gi, '')
|
|
4545
|
-
.replace(/(href|src)\s*=\s*"javascript:[^"]*"/gi, '$1="#"');
|
|
4546
|
-
}
|
|
4547
|
-
|
|
4548
|
-
function splitTableRow(line) {
|
|
4549
|
-
return line.trim().replace(/^\||\|$/g, '').split('|').map(c => c.trim());
|
|
4550
|
-
}
|
|
4551
|
-
function parseTableAligns(line) {
|
|
4552
|
-
return splitTableRow(line).map(cell => {
|
|
4553
|
-
if (/^:\s*-+:$/.test(cell)) return 'center';
|
|
4554
|
-
if (/^-*:$/.test(cell)) return 'left';
|
|
4555
|
-
if (/^-+:$/.test(cell)) return 'right';
|
|
4556
|
-
return null;
|
|
4557
|
-
});
|
|
4558
|
-
}
|
|
4559
|
-
function renderTable(headerCells, aligns, rows) {
|
|
4560
|
-
const alignAttr = (i) => aligns[i] ? ' style="text-align:' + aligns[i] + '"' : '';
|
|
4561
|
-
let html = '<div class="gd-table-wrap"><table><thead><tr>';
|
|
4562
|
-
headerCells.forEach((c, i) => { html += '<th' + alignAttr(i) + '>' + inlineMd(c) + '</th>'; });
|
|
4563
|
-
html += '</tr></thead><tbody>';
|
|
4564
|
-
for (const r of rows) {
|
|
4565
|
-
html += '<tr>';
|
|
4566
|
-
r.forEach((c, i) => { html += '<td' + alignAttr(i) + '>' + inlineMd(c) + '</td>'; });
|
|
4567
|
-
html += '</tr>';
|
|
4568
|
-
}
|
|
4569
|
-
html += '</tbody></table></div>';
|
|
4570
|
-
return html;
|
|
4571
|
-
}
|
|
4572
|
-
}
|
|
4573
|
-
|
|
4574
|
-
function gdCopyCode(btn) {
|
|
4575
|
-
const codeEl = btn.closest('.gd-code-block')?.querySelector('code');
|
|
4576
|
-
if (!codeEl) return;
|
|
4577
|
-
const text = codeEl.textContent;
|
|
4578
|
-
navigator.clipboard.writeText(text).then(
|
|
4579
|
-
() => { const old = btn.textContent; btn.textContent = 'copied'; setTimeout(() => { btn.textContent = old; }, 1200); },
|
|
4580
|
-
() => { btn.textContent = 'failed'; },
|
|
4581
|
-
);
|
|
4582
|
-
}
|
|
4382
|
+
// renderDocMarkdown() and gdCopyCode() moved to markdown.js (#124) — loaded via
|
|
4383
|
+
// <script src="markdown.js"> above; both remain plain globals.
|
|
4583
4384
|
|
|
4584
4385
|
let _hiEntries = [];
|
|
4585
4386
|
let _hiTab = 'pending';
|
|
@@ -6122,6 +5923,23 @@ function v2ToggleChartExpand(open) {
|
|
|
6122
5923
|
}
|
|
6123
5924
|
}
|
|
6124
5925
|
|
|
5926
|
+
// Recomputed from _v2OrgData at click time (not cached) so the modal never
|
|
5927
|
+
// shows a stale goal/topology/created after switching orgs.
|
|
5928
|
+
function v2OpenMetaModal() {
|
|
5929
|
+
const d = _v2OrgData;
|
|
5930
|
+
if (!d) return;
|
|
5931
|
+
const goalText = d.goal || '—';
|
|
5932
|
+
const topo = (d.topology || 'hierarchical').toLowerCase();
|
|
5933
|
+
const created = d.created_at ? new Date(d.created_at).toLocaleDateString('en', {month:'short',day:'numeric',year:'numeric'}) : '—';
|
|
5934
|
+
document.getElementById('omm-goal').textContent = goalText;
|
|
5935
|
+
document.getElementById('omm-topo').textContent = topo;
|
|
5936
|
+
document.getElementById('omm-created').textContent = created;
|
|
5937
|
+
document.getElementById('org-meta-modal').classList.add('open');
|
|
5938
|
+
}
|
|
5939
|
+
function v2CloseMetaModal() {
|
|
5940
|
+
document.getElementById('org-meta-modal').classList.remove('open');
|
|
5941
|
+
}
|
|
5942
|
+
|
|
6125
5943
|
function v2RenderOrgChart() {
|
|
6126
5944
|
if (!_v2SelOrg) return;
|
|
6127
5945
|
const d = _v2OrgData;
|
|
@@ -6180,6 +5998,11 @@ function v2RenderOrgChart() {
|
|
|
6180
5998
|
// a node center) or edge-column bubbles clip against the chart border.
|
|
6181
5999
|
const PAD_X = (_v2ChartExpanded || _crowded) ? Math.max(R + 20, 78) : R + 20;
|
|
6182
6000
|
const PAD_Y = (_v2ChartExpanded || _crowded) ? R + 96 : R + 24;
|
|
6001
|
+
// Space a node's label needs below its center before the viewBox clips it:
|
|
6002
|
+
// the label rect is y=(R+14-11), height=26 when a subtype line is present,
|
|
6003
|
+
// so its bottom edge sits at R+29 — plus a small cushion so labels never
|
|
6004
|
+
// sit flush against the chart's bottom edge.
|
|
6005
|
+
const LBL_BELOW = R + 29 + 8;
|
|
6183
6006
|
const roleIds = new Set(roles.map(r => r.id));
|
|
6184
6007
|
// all leaders at depth 0 (supports co-lead orgs)
|
|
6185
6008
|
const leaders = roles.filter(_v2OrgIsLeader);
|
|
@@ -6205,7 +6028,7 @@ function v2RenderOrgChart() {
|
|
|
6205
6028
|
pos[r.id] = { x, y: subY };
|
|
6206
6029
|
});
|
|
6207
6030
|
const _hasBothRows = leaders.length > 0 && subs.length > 0;
|
|
6208
|
-
_layoutH = _hasBothRows ? PAD_Y + 220 +
|
|
6031
|
+
_layoutH = _hasBothRows ? PAD_Y + 220 + LBL_BELOW : PAD_Y + LBL_BELOW;
|
|
6209
6032
|
};
|
|
6210
6033
|
|
|
6211
6034
|
if (!roles.length) {
|
|
@@ -6222,7 +6045,7 @@ function v2RenderOrgChart() {
|
|
|
6222
6045
|
const a = (2 * Math.PI * i / n) - Math.PI / 2;
|
|
6223
6046
|
pos[r.id] = { x: cx + rad * Math.cos(a), y: cy + rad * Math.sin(a) };
|
|
6224
6047
|
});
|
|
6225
|
-
_layoutH = Math.round(cy + rad +
|
|
6048
|
+
_layoutH = Math.round(cy + rad + LBL_BELOW);
|
|
6226
6049
|
} else if (topo === 'ring' || topo === 'pipeline') {
|
|
6227
6050
|
// linear sequence
|
|
6228
6051
|
const usableW = W - PAD_X * 2;
|
|
@@ -6261,7 +6084,7 @@ function v2RenderOrgChart() {
|
|
|
6261
6084
|
roles.forEach(r => layerOf[depth[r.id]].push(r));
|
|
6262
6085
|
|
|
6263
6086
|
const LAYER_H = 110;
|
|
6264
|
-
_layoutH = PAD_Y + maxDepth * LAYER_H +
|
|
6087
|
+
_layoutH = PAD_Y + maxDepth * LAYER_H + LBL_BELOW; // bottom row center + label space
|
|
6265
6088
|
|
|
6266
6089
|
for (let d2 = 0; d2 <= maxDepth; d2++) {
|
|
6267
6090
|
const layer = layerOf[d2];
|
|
@@ -6297,7 +6120,7 @@ function v2RenderOrgChart() {
|
|
|
6297
6120
|
});
|
|
6298
6121
|
const rows = Math.ceil(seq.length / perRow);
|
|
6299
6122
|
W = PAD_X * 2 + (perRow - 1) * COL_W;
|
|
6300
|
-
_layoutH = PAD_Y + (rows - 1) * ROW_H +
|
|
6123
|
+
_layoutH = PAD_Y + (rows - 1) * ROW_H + LBL_BELOW;
|
|
6301
6124
|
}
|
|
6302
6125
|
}
|
|
6303
6126
|
|
|
@@ -6406,10 +6229,12 @@ function v2RenderOrgChart() {
|
|
|
6406
6229
|
// ── assemble HTML ─────────────────────────────────────
|
|
6407
6230
|
// Expanded view: the chart owns the space — meta cards stay in the tab.
|
|
6408
6231
|
pane.innerHTML = `
|
|
6409
|
-
${_v2ChartExpanded ? '' : `<div class="org-meta-
|
|
6410
|
-
<
|
|
6411
|
-
<
|
|
6412
|
-
<
|
|
6232
|
+
${_v2ChartExpanded ? '' : `<div class="org-meta-line" onclick="v2OpenMetaModal()" title="Click for full details">
|
|
6233
|
+
<span class="oml-item goal"><span class="oml-lbl">Goal</span><span class="oml-val">${esc(goalText)}</span></span>
|
|
6234
|
+
<span class="oml-sep">·</span>
|
|
6235
|
+
<span class="oml-item"><span class="oml-lbl">Topology</span><span class="oml-val">${esc(topo)}</span></span>
|
|
6236
|
+
<span class="oml-sep">·</span>
|
|
6237
|
+
<span class="oml-item"><span class="oml-lbl">Created</span><span class="oml-val">${esc(created)}</span></span>
|
|
6413
6238
|
</div>`}
|
|
6414
6239
|
<div class="org-chart-wrap">
|
|
6415
6240
|
${_v2ChartExpanded ? '' : `<button class="v2-chart-expand" onclick="v2ToggleChartExpand(true)" title="Expand chart to full page" aria-label="Expand chart to full page">⛶</button>`}
|
|
@@ -8998,7 +8823,12 @@ function _ofMdToHtml(md) {
|
|
|
8998
8823
|
.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, function(_m, alt, url) {
|
|
8999
8824
|
return '<img src="'+String(url).replace(/"/g,'"')+'" alt="'+String(alt).replace(/"/g,'"')+'" loading="lazy" style="max-width:100%;border-radius:4px;margin:8px 0;display:block">';
|
|
9000
8825
|
})
|
|
9001
|
-
.replace(/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
8826
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, function(_m, txt, url) {
|
|
8827
|
+
// #124: previously interpolated the href raw ('<a href="$2" ...>') — a
|
|
8828
|
+
// URL containing a `"` could break out of the attribute. Matches the
|
|
8829
|
+
// quote-escaping the image handler right above already does.
|
|
8830
|
+
return '<a href="'+String(url).replace(/"/g,'"')+'" style="color:var(--accent);text-decoration:underline" target="_blank" rel="noopener">'+txt+'</a>';
|
|
8831
|
+
})
|
|
9002
8832
|
.replace(/\n\n+/g,'</p><p style="margin:0 0 8px">')
|
|
9003
8833
|
.replace(/^(?!<[hupoli]|<pre|<hr)(.+)$/gm, '$1')
|
|
9004
8834
|
.replace(/\n/g,'<br>');
|
|
@@ -10068,7 +9898,7 @@ document.addEventListener('keydown', e => {
|
|
|
10068
9898
|
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
|
10069
9899
|
if (document.getElementById('cmd-palette').classList.contains('open')) return;
|
|
10070
9900
|
|
|
10071
|
-
if (e.key === 'Escape') { closeDetail(); closeCmdPalette(); closeShortcutHelp(); closeMastermind(); closeBudgetModal(); if (document.getElementById('app').classList.contains('ambient')) toggleAmbient(); }
|
|
9901
|
+
if (e.key === 'Escape') { closeDetail(); closeCmdPalette(); closeShortcutHelp(); closeMastermind(); closeBudgetModal(); closeDocModal(); v2CloseAgent(); v2CloseMetaModal(); if (document.getElementById('app').classList.contains('ambient')) toggleAmbient(); }
|
|
10072
9902
|
if (e.key === '?') { e.preventDefault(); openShortcutHelp(); return; }
|
|
10073
9903
|
if (e.key === 'm' || e.key === 'M') { e.preventDefault(); openMastermind(); return; }
|
|
10074
9904
|
const _vkeys = { '1':'now','2':'sessions','3':'projects','4':'loops','5':'tokens','6':'memory','7':'orgs','8':'monograph','9':'global' };
|
|
@@ -13763,28 +13593,28 @@ async function loadStoreEntries() {
|
|
|
13763
13593
|
if (ns) url += '&namespace=' + encodeURIComponent(ns);
|
|
13764
13594
|
const data = await apiFetch(url);
|
|
13765
13595
|
const entries = data.entries || [];
|
|
13766
|
-
if (!entries.length) { grid.innerHTML = '<div class="empty">No entries' + (ns ? ' in namespace "' +
|
|
13596
|
+
if (!entries.length) { grid.innerHTML = '<div class="empty">No entries' + (ns ? ' in namespace "' + esc(ns) + '"' : '') + '</div>'; return; }
|
|
13767
13597
|
let html = '<table class="tbl" style="width:100%;font-size:12px"><thead><tr><th>Key</th><th>Namespace</th><th>Content</th><th>Tags</th><th>Updated</th><th></th></tr></thead><tbody>';
|
|
13768
13598
|
for (const e of entries) {
|
|
13769
|
-
const preview =
|
|
13770
|
-
const tags = (e.tags || []).map(t => '<span style="background:var(--bg-hi);padding:1px 4px;border-radius:3px;font-size:10px">' +
|
|
13599
|
+
const preview = esc((e.content || '').slice(0, 80)) + (e.content?.length > 80 ? '…' : '');
|
|
13600
|
+
const tags = (e.tags || []).map(t => '<span style="background:var(--bg-hi);padding:1px 4px;border-radius:3px;font-size:10px">' + esc(t) + '</span>').join(' ');
|
|
13771
13601
|
const updated = e.updatedAt ? new Date(e.updatedAt).toLocaleDateString() : '';
|
|
13772
13602
|
const emb = e.hasEmbedding ? ' title="Has embedding"' : '';
|
|
13773
13603
|
html += '<tr>';
|
|
13774
|
-
html += '<td style="font-weight:500;white-space:nowrap"' + emb + '>' + (e.hasEmbedding ? '◉ ' : '') +
|
|
13775
|
-
html += '<td style="color:var(--text-lo)">' +
|
|
13604
|
+
html += '<td style="font-weight:500;white-space:nowrap"' + emb + '>' + (e.hasEmbedding ? '◉ ' : '') + esc(e.key) + '</td>';
|
|
13605
|
+
html += '<td style="color:var(--text-lo)">' + esc(e.namespace) + '</td>';
|
|
13776
13606
|
html += '<td style="max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + preview + '</td>';
|
|
13777
13607
|
html += '<td>' + tags + '</td>';
|
|
13778
13608
|
html += '<td style="color:var(--text-lo);white-space:nowrap">' + updated + '</td>';
|
|
13779
|
-
html += '<td style="white-space:nowrap"><button class="btn" style="font-size:10px;padding:1px 6px" onclick="viewStoreEntry(\'' +
|
|
13780
|
-
html += ' <button class="btn" style="font-size:10px;padding:1px 6px;color:var(--red);border-color:var(--red)" onclick="deleteStoreEntry(\'' +
|
|
13609
|
+
html += '<td style="white-space:nowrap"><button class="btn" style="font-size:10px;padding:1px 6px" onclick="viewStoreEntry(\'' + esc(e.key) + '\',\'' + esc(e.namespace) + '\')">View</button>';
|
|
13610
|
+
html += ' <button class="btn" style="font-size:10px;padding:1px 6px;color:var(--red);border-color:var(--red)" onclick="deleteStoreEntry(\'' + esc(e.id || '') + '\',\'' + esc(e.key) + '\',\'' + esc(e.namespace) + '\')">Del</button></td>';
|
|
13781
13611
|
html += '</tr>';
|
|
13782
13612
|
}
|
|
13783
13613
|
html += '</tbody></table>';
|
|
13784
13614
|
grid.innerHTML = html;
|
|
13785
13615
|
_storeLoaded = true;
|
|
13786
13616
|
} catch (e) {
|
|
13787
|
-
grid.innerHTML = '<div class="empty" style="color:var(--red)">Error: ' +
|
|
13617
|
+
grid.innerHTML = '<div class="empty" style="color:var(--red)">Error: ' + esc(e.message) + '</div>';
|
|
13788
13618
|
}
|
|
13789
13619
|
}
|
|
13790
13620
|
|
|
@@ -13801,20 +13631,20 @@ async function storeSearch() {
|
|
|
13801
13631
|
if (ns) url += '&namespace=' + encodeURIComponent(ns);
|
|
13802
13632
|
const data = await apiFetch(url);
|
|
13803
13633
|
const results = data.results || [];
|
|
13804
|
-
if (!results.length) { res.innerHTML = '<div class="empty">No results for "' +
|
|
13634
|
+
if (!results.length) { res.innerHTML = '<div class="empty">No results for "' + esc(q) + '"</div>'; return true; }
|
|
13805
13635
|
let html = '<div class="m-group-title" style="margin-bottom:4px">Search results (' + results.length + ') <span style="font-size:10px;color:var(--text-xs);font-weight:400">' + (data.searchMethod || '') + ', ' + (data.searchTime || 0) + 'ms</span></div>';
|
|
13806
13636
|
html += '<table class="tbl" style="width:100%;font-size:12px"><thead><tr><th>Key</th><th>Score</th><th>NS</th><th>Content</th></tr></thead><tbody>';
|
|
13807
13637
|
for (const r of results) {
|
|
13808
|
-
const preview =
|
|
13809
|
-
html += '<tr><td style="font-weight:500">' +
|
|
13638
|
+
const preview = esc((r.content || '').slice(0, 100)) + (r.content?.length > 100 ? '…' : '');
|
|
13639
|
+
html += '<tr><td style="font-weight:500">' + esc(r.key) + '</td>';
|
|
13810
13640
|
html += '<td style="color:var(--text-lo)">' + (r.score?.toFixed(3) || '') + '</td>';
|
|
13811
|
-
html += '<td style="color:var(--text-lo)">' +
|
|
13641
|
+
html += '<td style="color:var(--text-lo)">' + esc(r.namespace) + '</td>';
|
|
13812
13642
|
html += '<td style="max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + preview + '</td></tr>';
|
|
13813
13643
|
}
|
|
13814
13644
|
html += '</tbody></table>';
|
|
13815
13645
|
res.innerHTML = html;
|
|
13816
13646
|
} catch (e) {
|
|
13817
|
-
res.innerHTML = '<div class="empty" style="color:var(--red)">Search error: ' +
|
|
13647
|
+
res.innerHTML = '<div class="empty" style="color:var(--red)">Search error: ' + esc(e.message) + '</div>';
|
|
13818
13648
|
}
|
|
13819
13649
|
return true;
|
|
13820
13650
|
}
|
|
@@ -13865,167 +13695,6 @@ function openStoreNewModal() {
|
|
|
13865
13695
|
}).catch(e => showToast('Error', e.message, 'err'));
|
|
13866
13696
|
}
|
|
13867
13697
|
|
|
13868
|
-
// ── swarm memory tab ───────────────────────────────────────
|
|
13869
|
-
let _swarmRuns = [];
|
|
13870
|
-
|
|
13871
|
-
async function loadSwarmTab() {
|
|
13872
|
-
const list = document.getElementById('swarm-run-list');
|
|
13873
|
-
if (!list) return;
|
|
13874
|
-
list.innerHTML = '<div class="loading-txt" style="padding:8px">Loading…</div>';
|
|
13875
|
-
try {
|
|
13876
|
-
const data = await apiFetch('/api/swarm-history?dir=' + enc(DIR));
|
|
13877
|
-
_swarmRuns = Array.isArray(data) ? data : (data.runs || data.history || []);
|
|
13878
|
-
_renderSwarmRunList();
|
|
13879
|
-
} catch (e) {
|
|
13880
|
-
list.innerHTML = '<div class="empty" style="padding:8px">Failed: ' + esc(e.message) + '</div>';
|
|
13881
|
-
}
|
|
13882
|
-
}
|
|
13883
|
-
|
|
13884
|
-
function _renderSwarmRunList() {
|
|
13885
|
-
const list = document.getElementById('swarm-run-list');
|
|
13886
|
-
if (!_swarmRuns.length) {
|
|
13887
|
-
list.innerHTML = '<div style="padding:8px;color:var(--text-lo);font-size:12px">No swarm runs found</div>';
|
|
13888
|
-
return;
|
|
13889
|
-
}
|
|
13890
|
-
list.innerHTML = _swarmRuns.map((r, i) => {
|
|
13891
|
-
const topo = r.topology || 'hierarchical';
|
|
13892
|
-
const live = r.status === 'running' || r.active;
|
|
13893
|
-
return '<div class="swarm-run-row" onclick="selectSwarmRun(' + i + ')">' +
|
|
13894
|
-
'<div style="display:flex;align-items:center;gap:5px">' +
|
|
13895
|
-
'<span class="swarm-topo-pill">' + esc(topo) + '</span>' +
|
|
13896
|
-
(live ? '<span class="swarm-live">⬤ LIVE</span>' : '') +
|
|
13897
|
-
'</div>' +
|
|
13898
|
-
'<div style="font-size:11px;color:var(--text-lo);margin-top:2px">' + (r.agentCount || 0) + ' agents · ' + relTime(r.startedAt || r.created_at) + '</div>' +
|
|
13899
|
-
'</div>';
|
|
13900
|
-
}).join('');
|
|
13901
|
-
}
|
|
13902
|
-
|
|
13903
|
-
async function selectSwarmRun(idx) {
|
|
13904
|
-
const run = _swarmRuns[idx];
|
|
13905
|
-
if (!run) return;
|
|
13906
|
-
document.querySelectorAll('.swarm-run-row').forEach((el, i) => el.classList.toggle('active', i === idx));
|
|
13907
|
-
const detail = document.getElementById('swarm-run-detail');
|
|
13908
|
-
if (!detail) return;
|
|
13909
|
-
detail.innerHTML =
|
|
13910
|
-
'<div style="margin-bottom:10px">' +
|
|
13911
|
-
'<div style="font-size:13px;font-weight:600;color:var(--text-hi)">' + esc((run.swarmId || run.id || '—').toString().slice(0, 14)) + '</div>' +
|
|
13912
|
-
'<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>' +
|
|
13913
|
-
'</div>' +
|
|
13914
|
-
'<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>' +
|
|
13915
|
-
'<div id="swarm-agent-list" style="margin-bottom:10px"></div>' +
|
|
13916
|
-
'<div id="swarm-event-log" style="font-size:11px;font-family:var(--mono);max-height:150px;overflow-y:auto"></div>';
|
|
13917
|
-
_drawSwarmTopology(run);
|
|
13918
|
-
_renderSwarmAgents(run);
|
|
13919
|
-
_loadSwarmEvents(run.swarmId || run.id);
|
|
13920
|
-
}
|
|
13921
|
-
|
|
13922
|
-
function _drawSwarmTopology(run) {
|
|
13923
|
-
const canvas = document.getElementById('swarm-topo-canvas');
|
|
13924
|
-
if (!canvas) return;
|
|
13925
|
-
const dpr = window.devicePixelRatio || 1;
|
|
13926
|
-
const W = canvas.offsetWidth || 380, H = 190;
|
|
13927
|
-
canvas.width = W * dpr; canvas.height = H * dpr;
|
|
13928
|
-
canvas.style.width = W + 'px'; canvas.style.height = H + 'px';
|
|
13929
|
-
const ctx = canvas.getContext('2d');
|
|
13930
|
-
ctx.scale(dpr, dpr);
|
|
13931
|
-
const agents = run.agents || Array.from({ length: Math.min(run.agentCount || 4, 12) }, (_, i) => ({ id: 'agent-' + i, type: 'worker' }));
|
|
13932
|
-
const n = agents.length;
|
|
13933
|
-
if (!n) return;
|
|
13934
|
-
const topo = (run.topology || 'hierarchical').toLowerCase();
|
|
13935
|
-
const cx = W / 2, cy = H / 2;
|
|
13936
|
-
const pos = [];
|
|
13937
|
-
if (topo.includes('hierarchical') || topo.includes('centralized')) {
|
|
13938
|
-
pos.push({ x: cx, y: 28 });
|
|
13939
|
-
const workers = agents.slice(1);
|
|
13940
|
-
workers.forEach((_, i) => {
|
|
13941
|
-
const spread = Math.min(W * 0.42, 160);
|
|
13942
|
-
const x = cx + (workers.length > 1 ? (i / (workers.length - 1) - 0.5) * spread * 2 : 0);
|
|
13943
|
-
pos.push({ x: x, y: H - 32 });
|
|
13944
|
-
});
|
|
13945
|
-
} else {
|
|
13946
|
-
agents.forEach((_, i) => {
|
|
13947
|
-
const a = (i / n) * Math.PI * 2 - Math.PI / 2;
|
|
13948
|
-
const r = Math.min(W, H) * 0.36;
|
|
13949
|
-
pos.push({ x: cx + Math.cos(a) * r, y: cy + Math.sin(a) * r });
|
|
13950
|
-
});
|
|
13951
|
-
}
|
|
13952
|
-
ctx.strokeStyle = 'oklch(40% 0.006 75 / 0.35)'; ctx.lineWidth = 1;
|
|
13953
|
-
if (topo.includes('hierarchical') || topo.includes('centralized')) {
|
|
13954
|
-
for (let i = 1; i < pos.length; i++) {
|
|
13955
|
-
ctx.beginPath(); ctx.moveTo(pos[0].x, pos[0].y); ctx.lineTo(pos[i].x, pos[i].y); ctx.stroke();
|
|
13956
|
-
}
|
|
13957
|
-
} else {
|
|
13958
|
-
let drawn = 0;
|
|
13959
|
-
for (let i = 0; i < n && drawn < 30; i++)
|
|
13960
|
-
for (let j = i + 1; j < n && drawn < 30; j++, drawn++) {
|
|
13961
|
-
ctx.beginPath(); ctx.moveTo(pos[i].x, pos[i].y); ctx.lineTo(pos[j].x, pos[j].y); ctx.stroke();
|
|
13962
|
-
}
|
|
13963
|
-
}
|
|
13964
|
-
agents.forEach((ag, i) => {
|
|
13965
|
-
const { x, y } = pos[i];
|
|
13966
|
-
const isQ = i === 0 && (topo.includes('hierarchical') || topo.includes('centralized'));
|
|
13967
|
-
const r = isQ ? 9 : 5;
|
|
13968
|
-
ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2);
|
|
13969
|
-
ctx.fillStyle = isQ ? 'oklch(72% 0.18 75)' : 'oklch(52% 0.008 75)';
|
|
13970
|
-
ctx.fill();
|
|
13971
|
-
ctx.fillStyle = isQ ? 'oklch(11% 0.009 55)' : 'oklch(90% 0.005 75)';
|
|
13972
|
-
ctx.font = isQ ? 'bold 9px sans-serif' : '8px sans-serif';
|
|
13973
|
-
ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
|
|
13974
|
-
ctx.fillText(isQ ? 'Q' : String(i), x, y);
|
|
13975
|
-
if (!isQ) {
|
|
13976
|
-
ctx.fillStyle = 'oklch(50% 0.006 75)';
|
|
13977
|
-
ctx.font = '9px sans-serif';
|
|
13978
|
-
ctx.fillText((ag.type || '').slice(0, 5), x, y + 14);
|
|
13979
|
-
}
|
|
13980
|
-
});
|
|
13981
|
-
}
|
|
13982
|
-
|
|
13983
|
-
function _renderSwarmAgents(run) {
|
|
13984
|
-
const el = document.getElementById('swarm-agent-list');
|
|
13985
|
-
if (!el) return;
|
|
13986
|
-
const agents = run.agents || [];
|
|
13987
|
-
if (!agents.length) { el.innerHTML = ''; return; }
|
|
13988
|
-
el.innerHTML = '<div class="m-group-title" style="margin-bottom:4px">Agents</div>' +
|
|
13989
|
-
agents.slice(0, 15).map(a =>
|
|
13990
|
-
'<div style="display:flex;gap:10px;padding:3px 0;font-size:11px;border-bottom:1px solid var(--border)">' +
|
|
13991
|
-
'<span style="color:var(--text-lo);font-family:var(--mono);min-width:70px">' + esc((a.id || '').toString().slice(0, 10)) + '</span>' +
|
|
13992
|
-
'<span style="color:var(--text-hi)">' + esc(a.type || a.role || 'worker') + '</span>' +
|
|
13993
|
-
'<span style="margin-left:auto;color:var(--text-xs)">' + esc(a.status || '—') + '</span>' +
|
|
13994
|
-
'</div>'
|
|
13995
|
-
).join('');
|
|
13996
|
-
}
|
|
13997
|
-
|
|
13998
|
-
async function _loadSwarmEvents(swarmId) {
|
|
13999
|
-
if (!swarmId) return;
|
|
14000
|
-
const el = document.getElementById('swarm-event-log');
|
|
14001
|
-
if (!el) return;
|
|
14002
|
-
try {
|
|
14003
|
-
const data = await apiFetch('/api/swarm-events?agentId=' + enc(swarmId) + '&dir=' + enc(DIR));
|
|
14004
|
-
const events = Array.isArray(data) ? data : (data.events || []);
|
|
14005
|
-
if (!events.length) { el.innerHTML = ''; return; }
|
|
14006
|
-
el.innerHTML = '<div class="m-group-title" style="margin-bottom:3px">Events</div>' +
|
|
14007
|
-
events.slice(-40).map(e =>
|
|
14008
|
-
'<div style="color:var(--text-lo);padding:2px 0;border-bottom:1px solid var(--border)">' +
|
|
14009
|
-
esc(relTime(e.ts || e.timestamp)) + ' <span style="color:var(--text-mid)">' + esc(e.type || e.kind || '?') + '</span> ' +
|
|
14010
|
-
esc((e.message || e.data || '').toString().slice(0, 70)) +
|
|
14011
|
-
'</div>'
|
|
14012
|
-
).join('');
|
|
14013
|
-
el.scrollTop = el.scrollHeight;
|
|
14014
|
-
} catch (_) {}
|
|
14015
|
-
}
|
|
14016
|
-
|
|
14017
|
-
async function cleanSwarmData() {
|
|
14018
|
-
if (!confirm('Delete all swarm run data? This cannot be undone.')) return;
|
|
14019
|
-
try {
|
|
14020
|
-
await fetch('/api/swarm-clean?dir=' + enc(DIR), { method: 'DELETE' });
|
|
14021
|
-
showToast('Cleaned', 'Swarm data deleted', 'ok');
|
|
14022
|
-
_swarmRuns = [];
|
|
14023
|
-
_renderSwarmRunList();
|
|
14024
|
-
const detail = document.getElementById('swarm-run-detail');
|
|
14025
|
-
if (detail) detail.innerHTML = '<div style="color:var(--text-lo);font-size:13px">Select a swarm run</div>';
|
|
14026
|
-
} catch (e) { showToast('Error', e.message, 'err'); }
|
|
14027
|
-
}
|
|
14028
|
-
|
|
14029
13698
|
// ── chunks memory tab ──────────────────────────────────────
|
|
14030
13699
|
let _chunks = [], _chunksLoaded = false, _editChunkId = null;
|
|
14031
13700
|
|
|
@@ -14244,113 +13913,75 @@ async function deleteChunk(id) {
|
|
|
14244
13913
|
} catch (e) { showToast('Error', e.message, 'err'); }
|
|
14245
13914
|
}
|
|
14246
13915
|
|
|
14247
|
-
// ──
|
|
14248
|
-
let
|
|
13916
|
+
// ── docs memory tab ─────────────────────────────────────────
|
|
13917
|
+
let _docsFiles = [], _docsLoaded = false;
|
|
14249
13918
|
|
|
14250
|
-
async function
|
|
14251
|
-
if (
|
|
14252
|
-
const bar = document.getElementById('
|
|
13919
|
+
async function loadDocsTab() {
|
|
13920
|
+
if (_docsLoaded) { _renderDocs(); return; }
|
|
13921
|
+
const bar = document.getElementById('docs-stats-bar');
|
|
13922
|
+
const grid = document.getElementById('docs-grid');
|
|
14253
13923
|
if (bar) bar.innerHTML = '<div class="loading-txt">Loading…</div>';
|
|
14254
13924
|
try {
|
|
14255
|
-
const data = await apiFetch('/api/
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
|
|
14259
|
-
const sessNodes = nodes.filter(n => n.type === 'session').sort((a, b) => (b.mtime || 0) - (a.mtime || 0));
|
|
14260
|
-
const agNodes = nodes.filter(n => n.type === 'agenttype');
|
|
14261
|
-
const sessions = sessNodes.map(n => ({
|
|
14262
|
-
id: n.id,
|
|
14263
|
-
turns: n.turns || 0,
|
|
14264
|
-
spawnCount: Object.values(n.agentSpawns || {}).reduce((a, b) => a + b, 0),
|
|
14265
|
-
toolCount: n.totalTools || 0,
|
|
14266
|
-
tools: n.toolCounts || {},
|
|
14267
|
-
agentTypes: n.agentSpawns || {},
|
|
14268
|
-
cost: n.cost,
|
|
14269
|
-
}));
|
|
14270
|
-
_agData = {
|
|
14271
|
-
sessions,
|
|
14272
|
-
sessionCount: sessions.length,
|
|
14273
|
-
agentTypes: agNodes.length,
|
|
14274
|
-
totalSpawns: agNodes.reduce((a, n) => a + (n.totalSpawns || 0), 0),
|
|
14275
|
-
totalToolCalls: sessions.reduce((a, s) => a + (s.toolCount || 0), 0),
|
|
14276
|
-
totalCost: sessions.reduce((a, s) => a + (Number(s.cost) || 0), 0),
|
|
14277
|
-
};
|
|
14278
|
-
_renderAgSummary();
|
|
14279
|
-
_renderAgSessList();
|
|
13925
|
+
const data = await apiFetch('/api/docs?dir=' + enc(DIR));
|
|
13926
|
+
_docsFiles = Array.isArray(data && data.files) ? data.files : [];
|
|
13927
|
+
_docsLoaded = true;
|
|
13928
|
+
_renderDocs();
|
|
14280
13929
|
} catch (e) {
|
|
13930
|
+
if (grid) grid.innerHTML = '';
|
|
14281
13931
|
if (bar) bar.innerHTML = '<div class="empty">Failed: ' + esc(e.message) + '</div>';
|
|
14282
13932
|
}
|
|
14283
13933
|
}
|
|
14284
13934
|
|
|
14285
|
-
function
|
|
14286
|
-
const
|
|
14287
|
-
|
|
14288
|
-
|
|
14289
|
-
const stats = [
|
|
14290
|
-
{ l: 'Sessions', v: d.sessionCount != null ? d.sessionCount : (d.sessions && d.sessions.length != null ? d.sessions.length : '—') },
|
|
14291
|
-
{ l: 'Agent Types', v: d.agentTypes != null ? d.agentTypes : '—' },
|
|
14292
|
-
{ l: 'Spawns', v: d.totalSpawns != null ? d.totalSpawns : '—' },
|
|
14293
|
-
{ l: 'Tool Calls', v: d.totalToolCalls != null ? Number(d.totalToolCalls).toLocaleString() : '—' },
|
|
14294
|
-
{ l: 'Total Cost', v: d.totalCost != null ? '$' + Number(d.totalCost).toFixed(3) : '—' },
|
|
14295
|
-
];
|
|
14296
|
-
el.innerHTML = stats.map(s =>
|
|
13935
|
+
function _renderDocs() {
|
|
13936
|
+
const bar = document.getElementById('docs-stats-bar');
|
|
13937
|
+
const grid = document.getElementById('docs-grid');
|
|
13938
|
+
if (bar) bar.innerHTML =
|
|
14297
13939
|
'<div>' +
|
|
14298
|
-
'<div style="font-size:10px;color:var(--text-lo);text-transform:uppercase;letter-spacing:0.07em">
|
|
14299
|
-
'<div style="font-size:16px;font-weight:700;color:var(--text-hi);font-family:var(--mono)">' +
|
|
14300
|
-
'</div>'
|
|
14301
|
-
|
|
13940
|
+
'<div style="font-size:10px;color:var(--text-lo);text-transform:uppercase;letter-spacing:0.07em">Markdown Files</div>' +
|
|
13941
|
+
'<div style="font-size:16px;font-weight:700;color:var(--text-hi);font-family:var(--mono)">' + _docsFiles.length + '</div>' +
|
|
13942
|
+
'</div>';
|
|
13943
|
+
if (!grid) return;
|
|
13944
|
+
if (!_docsFiles.length) {
|
|
13945
|
+
grid.innerHTML = '<div class="empty">No markdown files found.</div>';
|
|
13946
|
+
return;
|
|
13947
|
+
}
|
|
13948
|
+
grid.innerHTML = _docsFiles.map(f => {
|
|
13949
|
+
const sizeKb = ((f.size || 0) / 1024).toFixed(1) + ' KB';
|
|
13950
|
+
return '<div class="chunk-card" style="cursor:pointer" data-search="' + esc(f.path.toLowerCase()) + '" onclick="openDocModal(' + JSON.stringify(f.path).replace(/"/g, '"') + ')">' +
|
|
13951
|
+
'<div class="chunk-src">' + esc(f.path) + '</div>' +
|
|
13952
|
+
'<div class="chunk-footer" style="margin-top:3px">' +
|
|
13953
|
+
'<span class="chunk-ns">' + esc(sizeKb) + '</span>' +
|
|
13954
|
+
'<span style="font-size:11px;color:var(--text-lo)">' + esc(relTime(f.mtime)) + '</span>' +
|
|
13955
|
+
'</div>' +
|
|
13956
|
+
'</div>';
|
|
13957
|
+
}).join('');
|
|
14302
13958
|
}
|
|
14303
13959
|
|
|
14304
|
-
function
|
|
14305
|
-
const
|
|
14306
|
-
|
|
14307
|
-
|
|
14308
|
-
|
|
14309
|
-
el.innerHTML = sessions.map((s, i) =>
|
|
14310
|
-
'<div class="sess-row" style="margin-bottom:4px" onclick="selectAgSession(' + i + ')">' +
|
|
14311
|
-
'<div class="sr-top">' +
|
|
14312
|
-
'<div class="sr-prompt" style="font-size:11px">' + esc((s.id || s.file || '').slice(-16)) + '</div>' +
|
|
14313
|
-
'</div>' +
|
|
14314
|
-
'<div style="font-size:10px;color:var(--text-lo);margin-top:1px">' + (s.spawnCount || 0) + ' spawns · ' + (s.toolCount || 0) + ' tools</div>' +
|
|
14315
|
-
'</div>'
|
|
14316
|
-
).join('');
|
|
13960
|
+
function filterDocs(q) {
|
|
13961
|
+
const lq = q.toLowerCase();
|
|
13962
|
+
document.querySelectorAll('#docs-grid .chunk-card').forEach(el => {
|
|
13963
|
+
el.style.display = (!lq || (el.dataset.search || '').includes(lq)) ? '' : 'none';
|
|
13964
|
+
});
|
|
14317
13965
|
}
|
|
14318
13966
|
|
|
14319
|
-
function
|
|
14320
|
-
const
|
|
14321
|
-
|
|
14322
|
-
document.
|
|
14323
|
-
|
|
14324
|
-
|
|
14325
|
-
|
|
14326
|
-
|
|
14327
|
-
|
|
14328
|
-
|
|
14329
|
-
|
|
14330
|
-
|
|
14331
|
-
|
|
14332
|
-
|
|
14333
|
-
|
|
14334
|
-
|
|
14335
|
-
|
|
14336
|
-
|
|
14337
|
-
agArr.map(function(entry) {
|
|
14338
|
-
var type = entry[0], count = entry[1];
|
|
14339
|
-
return '<div style="display:flex;align-items:center;gap:8px;padding:3px 0;font-size:12px">' +
|
|
14340
|
-
'<div style="width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-hi)">' + esc(type) + '</div>' +
|
|
14341
|
-
'<div style="flex:1;height:7px;background:var(--border);border-radius:2px;overflow:hidden"><div style="width:' + Math.round(count/maxAg*100) + '%;height:100%;background:var(--accent);border-radius:2px"></div></div>' +
|
|
14342
|
-
'<div style="width:22px;text-align:right;color:var(--text-lo);font-size:11px;font-family:var(--mono)">' + count + '</div>' +
|
|
14343
|
-
'</div>';
|
|
14344
|
-
}).join('') : '') +
|
|
14345
|
-
(toolArr.length ? '<div class="m-group-title" style="margin-bottom:5px;margin-top:14px">Top Tools</div>' +
|
|
14346
|
-
toolArr.map(function(entry) {
|
|
14347
|
-
var tool = entry[0], count = entry[1];
|
|
14348
|
-
return '<div style="display:flex;align-items:center;gap:8px;padding:3px 0;font-size:12px">' +
|
|
14349
|
-
'<div style="width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-hi);font-family:var(--mono);font-size:11px">' + esc(tool) + '</div>' +
|
|
14350
|
-
'<div style="flex:1;height:7px;background:var(--border);border-radius:2px;overflow:hidden"><div style="width:' + Math.round(count/maxTool*100) + '%;height:100%;background:oklch(62% 0.12 195);border-radius:2px"></div></div>' +
|
|
14351
|
-
'<div style="width:22px;text-align:right;color:var(--text-lo);font-size:11px;font-family:var(--mono)">' + count + '</div>' +
|
|
14352
|
-
'</div>';
|
|
14353
|
-
}).join('') : '');
|
|
13967
|
+
async function openDocModal(relPath) {
|
|
13968
|
+
const modal = document.getElementById('docs-modal');
|
|
13969
|
+
const title = document.getElementById('docs-modal-title');
|
|
13970
|
+
const body = document.getElementById('docs-modal-body');
|
|
13971
|
+
title.textContent = relPath;
|
|
13972
|
+
body.innerHTML = '<div class="loading-txt">Loading…</div>';
|
|
13973
|
+
modal.classList.add('open');
|
|
13974
|
+
try {
|
|
13975
|
+
const data = await apiFetch('/api/doc-read?dir=' + enc(DIR) + '&path=' + enc(relPath));
|
|
13976
|
+
body.innerHTML = data && data.body ? renderDocMarkdown(data.body) : '<div class="empty">Empty document</div>';
|
|
13977
|
+
body.scrollTop = 0;
|
|
13978
|
+
} catch (e) {
|
|
13979
|
+
body.innerHTML = '<div class="empty">Failed to load: ' + esc(e.message) + '</div>';
|
|
13980
|
+
}
|
|
13981
|
+
}
|
|
13982
|
+
|
|
13983
|
+
function closeDocModal() {
|
|
13984
|
+
document.getElementById('docs-modal').classList.remove('open');
|
|
14354
13985
|
}
|
|
14355
13986
|
|
|
14356
13987
|
// ── Mastermind overlay ─────────────────────────────────────
|