monomind 2.0.3 → 2.1.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/README.md +74 -92
- package/package.json +11 -7
- package/packages/@monomind/cli/.claude/helpers/control-start.cjs +13 -20
- package/packages/@monomind/cli/.claude/helpers/event-logger.cjs +109 -6
- package/packages/@monomind/cli/.claude/helpers/graphify-freshen.cjs +19 -17
- package/packages/@monomind/cli/.claude/helpers/handlers/agent-start-handler.cjs +60 -28
- package/packages/@monomind/cli/.claude/helpers/handlers/capture-handler.cjs +99 -28
- package/packages/@monomind/cli/.claude/helpers/handlers/edit-handler.cjs +27 -9
- package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +18 -9
- package/packages/@monomind/cli/.claude/helpers/handlers/loops-status-handler.cjs +1 -1
- package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +33 -4
- package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +75 -45
- package/packages/@monomind/cli/.claude/helpers/handlers/session-restore-handler.cjs +0 -12
- package/packages/@monomind/cli/.claude/helpers/handlers/task-handler.cjs +53 -22
- package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +75 -4
- package/packages/@monomind/cli/.claude/helpers/intelligence.cjs +94 -15
- package/packages/@monomind/cli/.claude/helpers/session.cjs +6 -1
- package/packages/@monomind/cli/.claude/helpers/statusline.cjs +10 -10
- package/packages/@monomind/cli/.claude/helpers/token-tracker.cjs +3 -3
- package/packages/@monomind/cli/.claude/helpers/utils/agent-registrations.cjs +41 -0
- package/packages/@monomind/cli/.claude/helpers/utils/fs-helpers.cjs +183 -0
- package/packages/@monomind/cli/.claude/helpers/utils/micro-agents.cjs +10 -6
- package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +73 -2
- package/packages/@monomind/cli/.claude/helpers/utils/telemetry.cjs +35 -19
- package/packages/@monomind/cli/README.md +74 -92
- package/packages/@monomind/cli/bin/cli.js +10 -1
- package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/commands/agent-ops.js +9 -15
- package/packages/@monomind/cli/dist/src/commands/browse.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/cleanup.js +20 -4
- package/packages/@monomind/cli/dist/src/commands/completions.js +66 -261
- package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +5 -0
- package/packages/@monomind/cli/dist/src/commands/doctor.js +7 -2
- package/packages/@monomind/cli/dist/src/commands/hooks-workers.js +7 -0
- package/packages/@monomind/cli/dist/src/commands/index.js +3 -0
- package/packages/@monomind/cli/dist/src/commands/mcp.js +11 -6
- package/packages/@monomind/cli/dist/src/commands/memory-admin.js +12 -6
- package/packages/@monomind/cli/dist/src/commands/memory-transfer.js +6 -13
- package/packages/@monomind/cli/dist/src/commands/monograph.js +3 -3
- package/packages/@monomind/cli/dist/src/commands/org.d.ts +3 -1
- package/packages/@monomind/cli/dist/src/commands/org.js +321 -127
- package/packages/@monomind/cli/dist/src/commands/platforms.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/start.js +142 -37
- package/packages/@monomind/cli/dist/src/commands/tokens.js +21 -3
- package/packages/@monomind/cli/dist/src/config-adapter.js +37 -17
- package/packages/@monomind/cli/dist/src/index.js +64 -28
- package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +44 -11
- package/packages/@monomind/cli/dist/src/init/executor.js +93 -55
- package/packages/@monomind/cli/dist/src/mcp-client.d.ts +8 -3
- package/packages/@monomind/cli/dist/src/mcp-client.js +37 -3
- package/packages/@monomind/cli/dist/src/mcp-server.js +8 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.d.ts +20 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.js +10 -5
- package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.d.ts +8 -8
- package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +31 -31
- package/packages/@monomind/cli/dist/src/mcp-tools/github-tools.js +30 -8
- package/packages/@monomind/cli/dist/src/mcp-tools/graphify-tools.js +11 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +56 -35
- package/packages/@monomind/cli/dist/src/mcp-tools/knowledge-tools.js +9 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-compat.js +56 -14
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +88 -41
- package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +36 -36
- package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +6 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +4 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/types.d.ts +20 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/types.js +36 -1
- package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/memory/hnsw-operations.d.ts +13 -1
- package/packages/@monomind/cli/dist/src/memory/hnsw-operations.js +66 -14
- package/packages/@monomind/cli/dist/src/memory/intelligence.js +99 -3
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +7 -0
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +20 -0
- package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/orgrt/broker.d.ts +26 -0
- package/packages/@monomind/cli/dist/src/orgrt/broker.js +73 -0
- package/packages/@monomind/cli/dist/src/orgrt/bus.d.ts +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/bus.js +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +46 -0
- package/packages/@monomind/cli/dist/src/orgrt/daemon.js +201 -18
- package/packages/@monomind/cli/dist/src/orgrt/forwarder.d.ts +10 -5
- package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +138 -8
- package/packages/@monomind/cli/dist/src/orgrt/inbox.d.ts +11 -0
- package/packages/@monomind/cli/dist/src/orgrt/inbox.js +56 -0
- package/packages/@monomind/cli/dist/src/orgrt/policy.d.ts +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/policy.js +58 -5
- package/packages/@monomind/cli/dist/src/orgrt/provider.js +1 -0
- package/packages/@monomind/cli/dist/src/orgrt/scheduler.d.ts +13 -0
- package/packages/@monomind/cli/dist/src/orgrt/scheduler.js +48 -0
- package/packages/@monomind/cli/dist/src/orgrt/server.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/orgrt/server.js +39 -0
- package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +10 -1
- package/packages/@monomind/cli/dist/src/orgrt/session.js +24 -1
- package/packages/@monomind/cli/dist/src/orgrt/test-loop.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/orgrt/test-loop.js +108 -0
- package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +52 -52
- package/packages/@monomind/cli/dist/src/output.d.ts +29 -29
- package/packages/@monomind/cli/dist/src/output.js +22 -7
- package/packages/@monomind/cli/dist/src/parser.d.ts +32 -0
- package/packages/@monomind/cli/dist/src/parser.js +130 -5
- package/packages/@monomind/cli/dist/src/routing/embed-worker.js +13 -1
- package/packages/@monomind/cli/dist/src/routing/route-layer-factory.js +31 -0
- package/packages/@monomind/cli/dist/src/services/config-file-manager.d.ts +21 -0
- package/packages/@monomind/cli/dist/src/services/config-file-manager.js +60 -7
- package/packages/@monomind/cli/dist/src/services/crash-reporter.js +2 -1
- package/packages/@monomind/cli/dist/src/types.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/ui/dashboard.html +243 -49
- package/packages/@monomind/cli/dist/src/ui/orgs-files.js +192 -0
- package/packages/@monomind/cli/dist/src/ui/orgs.html +79 -11
- package/packages/@monomind/cli/dist/src/ui/server.mjs +346 -139
- package/packages/@monomind/cli/dist/src/utils/input-guards.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/utils/input-guards.js +39 -5
- package/packages/@monomind/cli/package.json +15 -15
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// packages/@monomind/cli/dist/src/ui/orgs-files.js
|
|
2
|
+
// Files tab + diff-view feature, split out of orgs.html to keep that file under
|
|
3
|
+
// the CLAUDE.md 500-line guideline. Loaded as a classic <script> right where this
|
|
4
|
+
// code used to live inline — shares the same global scope as orgs.html's main
|
|
5
|
+
// script (chatSessions, orgSessionMatch, esc, currentTab, loadChatSessions,
|
|
6
|
+
// viewArtifact are all defined there and referenced here by closure).
|
|
7
|
+
|
|
8
|
+
// ── Files tab: every asset produced by this org, grouped by path with full
|
|
9
|
+
// version history (not deduped) so successive writes to the same file can be
|
|
10
|
+
// diffed against each other, latest-touched file first ──
|
|
11
|
+
let filesGroups = [];
|
|
12
|
+
|
|
13
|
+
function collectOrgArtifacts() {
|
|
14
|
+
const bySessions = chatSessions.filter(orgSessionMatch);
|
|
15
|
+
const byPath = new Map(); // path -> [{ art, ts, from }]
|
|
16
|
+
bySessions.forEach(s => (s.events || []).forEach(ev => {
|
|
17
|
+
if (ev.type !== 'org:artifact') return;
|
|
18
|
+
const art = ev.artifact || (ev.path ? { path: ev.path, label: ev.label, mimeType: ev.mimeType } : null);
|
|
19
|
+
if (!art || !art.path) return;
|
|
20
|
+
if (!byPath.has(art.path)) byPath.set(art.path, []);
|
|
21
|
+
byPath.get(art.path).push({ art, ts: ev.ts || 0, from: ev.from || '' });
|
|
22
|
+
}));
|
|
23
|
+
const groups = [];
|
|
24
|
+
byPath.forEach((versions, path) => {
|
|
25
|
+
versions.sort((a, b) => a.ts - b.ts);
|
|
26
|
+
groups.push({ path, versions, latest: versions[versions.length - 1] });
|
|
27
|
+
});
|
|
28
|
+
groups.sort((a, b) => b.latest.ts - a.latest.ts);
|
|
29
|
+
return groups;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function mkFileCard(group) {
|
|
33
|
+
const { art, ts, from } = group.latest;
|
|
34
|
+
const el = document.createElement('div');
|
|
35
|
+
el.className = 'file-card';
|
|
36
|
+
const isText = (art.mimeType || '').startsWith('text/') || (art.mimeType || '') === 'application/json';
|
|
37
|
+
const labelRaw = art.label || (art.path || 'file').split('/').pop();
|
|
38
|
+
const timeStr = ts ? new Date(ts).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '';
|
|
39
|
+
const meta = [from, art.path ? art.path.split('/').slice(-3).join('/') : null, timeStr].filter(Boolean).join(' · ');
|
|
40
|
+
const vBadge = group.versions.length > 1 ? `<span class="fc-vbadge">${group.versions.length}v</span>` : '';
|
|
41
|
+
const diffable = group.versions.filter(v => typeof v.art.content === 'string').length >= 2;
|
|
42
|
+
el.innerHTML = `
|
|
43
|
+
<div class="fc-icon">📄</div>
|
|
44
|
+
<div class="fc-body">
|
|
45
|
+
<div class="fc-name">${esc(labelRaw)} ${vBadge}</div>
|
|
46
|
+
<div class="fc-meta">${esc(meta)}</div>
|
|
47
|
+
</div>
|
|
48
|
+
${diffable ? `<button class="fc-diff" onclick="openDiffPanel(${JSON.stringify(art.path)})">Diff</button>` : ''}
|
|
49
|
+
${isText && art.path
|
|
50
|
+
? `<button class="fc-view" onclick="viewArtifact(${JSON.stringify(art.path)},${JSON.stringify(labelRaw)})">View</button>`
|
|
51
|
+
: `<span class="fc-binary">Binary</span>`}
|
|
52
|
+
`;
|
|
53
|
+
return el;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function paintFilesGrid() {
|
|
57
|
+
const grid = document.getElementById('files-grid');
|
|
58
|
+
const empty = document.getElementById('files-empty');
|
|
59
|
+
if (!grid) return;
|
|
60
|
+
filesGroups = collectOrgArtifacts();
|
|
61
|
+
renderFilesGridFromGroups();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Re-renders the grid from the current in-memory `filesGroups` — no rescan.
|
|
65
|
+
* Split out of paintFilesGrid() so applyArtifactEvent() can repaint after an
|
|
66
|
+
* O(groups) incremental update instead of forcing a full O(all-events) rescan. */
|
|
67
|
+
function renderFilesGridFromGroups() {
|
|
68
|
+
const grid = document.getElementById('files-grid');
|
|
69
|
+
const empty = document.getElementById('files-empty');
|
|
70
|
+
if (!grid) return;
|
|
71
|
+
grid.innerHTML = '';
|
|
72
|
+
if (!filesGroups.length) { if (empty) empty.style.display = 'block'; return; }
|
|
73
|
+
if (empty) empty.style.display = 'none';
|
|
74
|
+
filesGroups.forEach(group => grid.appendChild(mkFileCard(group)));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Incrementally folds a single new org:artifact event into `filesGroups` —
|
|
78
|
+
* O(groups) to re-sort by latest-touched, not O(all sessions' all events)
|
|
79
|
+
* like collectOrgArtifacts(). Mirrors collectOrgArtifacts()'s grouping rules. */
|
|
80
|
+
function applyArtifactEvent(ev) {
|
|
81
|
+
const art = ev.artifact || (ev.path ? { path: ev.path, label: ev.label, mimeType: ev.mimeType } : null);
|
|
82
|
+
if (!art || !art.path) return;
|
|
83
|
+
const entry = { art, ts: ev.ts || 0, from: ev.from || '' };
|
|
84
|
+
let group = filesGroups.find(g => g.path === art.path);
|
|
85
|
+
if (!group) {
|
|
86
|
+
group = { path: art.path, versions: [], latest: entry };
|
|
87
|
+
filesGroups.push(group);
|
|
88
|
+
}
|
|
89
|
+
group.versions.push(entry);
|
|
90
|
+
group.versions.sort((a, b) => a.ts - b.ts);
|
|
91
|
+
group.latest = group.versions[group.versions.length - 1];
|
|
92
|
+
filesGroups.sort((a, b) => b.latest.ts - a.latest.ts);
|
|
93
|
+
renderFilesGridFromGroups();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function renderFilesTab() {
|
|
97
|
+
paintFilesGrid(); // paint immediately with whatever's cached
|
|
98
|
+
loadChatSessions().then(() => { if (currentTab === 'files') paintFilesGrid(); });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── Diff view: compare two captured versions of the same file ──
|
|
102
|
+
window.openDiffPanel = function(path) {
|
|
103
|
+
const group = filesGroups.find(g => g.path === path);
|
|
104
|
+
if (!group) return;
|
|
105
|
+
const versions = group.versions.filter(v => typeof v.art.content === 'string');
|
|
106
|
+
if (versions.length < 2) return;
|
|
107
|
+
const label = group.latest.art.label || path.split('/').pop();
|
|
108
|
+
renderDiffPanel(label, versions);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
function renderDiffPanel(label, versions) {
|
|
112
|
+
let panel = document.getElementById('artifact-panel');
|
|
113
|
+
if (!panel) {
|
|
114
|
+
panel = document.createElement('div');
|
|
115
|
+
panel.id = 'artifact-panel';
|
|
116
|
+
panel.style.cssText = 'position:fixed;top:0;right:0;width:640px;height:100vh;background:#0a0a14;border-left:1px solid #333;z-index:1000;display:flex;flex-direction:column;overflow:hidden';
|
|
117
|
+
document.body.appendChild(panel);
|
|
118
|
+
}
|
|
119
|
+
const optLabel = v => `${new Date(v.ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })} · ${esc(v.from || '?')}`;
|
|
120
|
+
const opts = versions.map((v, i) => `<option value="${i}">${optLabel(v)}</option>`).join('');
|
|
121
|
+
panel.innerHTML = `
|
|
122
|
+
<div style="padding:12px 14px;border-bottom:1px solid #1a1a2a;display:flex;align-items:center;gap:10px">
|
|
123
|
+
<span style="font-size:13px;font-weight:700;color:#ccc;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(label)} — diff</span>
|
|
124
|
+
<button onclick="document.getElementById('artifact-panel').remove()" style="background:none;border:none;color:#888;font-size:16px;cursor:pointer">✕</button>
|
|
125
|
+
</div>
|
|
126
|
+
<div style="padding:8px 14px;border-bottom:1px solid #1a1a2a;display:flex;gap:8px;align-items:center;font-size:10px;color:#888">
|
|
127
|
+
<select id="diff-from" style="background:#151520;color:#ccc;border:1px solid #333;border-radius:3px;padding:2px 6px;font-size:10px">${opts}</select>
|
|
128
|
+
<span>→</span>
|
|
129
|
+
<select id="diff-to" style="background:#151520;color:#ccc;border:1px solid #333;border-radius:3px;padding:2px 6px;font-size:10px">${opts}</select>
|
|
130
|
+
</div>
|
|
131
|
+
<div id="diff-body" style="flex:1;overflow:auto;font-size:11px;line-height:1.6;font-family:var(--mono,ui-monospace,monospace)"></div>
|
|
132
|
+
`;
|
|
133
|
+
panel.style.display = 'flex';
|
|
134
|
+
const fromSel = document.getElementById('diff-from');
|
|
135
|
+
const toSel = document.getElementById('diff-to');
|
|
136
|
+
fromSel.value = String(versions.length - 2);
|
|
137
|
+
toSel.value = String(versions.length - 1);
|
|
138
|
+
const recompute = () => renderDiffBody(versions[Number(fromSel.value)].art.content, versions[Number(toSel.value)].art.content);
|
|
139
|
+
fromSel.onchange = recompute;
|
|
140
|
+
toSel.onchange = recompute;
|
|
141
|
+
recompute();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function renderDiffBody(oldText, newText) {
|
|
145
|
+
const body = document.getElementById('diff-body');
|
|
146
|
+
if (!body) return;
|
|
147
|
+
if (oldText === newText) {
|
|
148
|
+
body.innerHTML = '<div style="padding:14px;color:#666">No differences between these two versions.</div>';
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const rows = diffLines(oldText, newText);
|
|
152
|
+
if (!rows) {
|
|
153
|
+
body.innerHTML = '<div style="padding:14px;color:#666">File too large to diff line-by-line.</div>';
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
body.innerHTML = rows.map(r => {
|
|
157
|
+
const style = r.type === 'add' ? 'background:#0d2818;color:#7ee787'
|
|
158
|
+
: r.type === 'del' ? 'background:#2d0d10;color:#ffa198' : 'color:#8b949e';
|
|
159
|
+
const prefix = r.type === 'add' ? '+' : r.type === 'del' ? '-' : ' ';
|
|
160
|
+
return `<div style="${style};padding:1px 12px;white-space:pre-wrap;word-break:break-word">${esc(prefix + ' ' + r.text)}</div>`;
|
|
161
|
+
}).join('');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Line-level LCS diff. Returns null (caller shows a fallback message) rather
|
|
165
|
+
* than hanging the tab if both files are unexpectedly huge — the O(n*m) DP
|
|
166
|
+
* table would otherwise blow past what's reasonable to allocate client-side.
|
|
167
|
+
* Bounds n and m individually, not just their product: a lopsided pair (e.g.
|
|
168
|
+
* n=1, m=4000000 — one huge file diffed against a near-empty one) passes the
|
|
169
|
+
* product check but still allocates a 4M-row DP table, one row per line of A. */
|
|
170
|
+
function diffLines(a, b) {
|
|
171
|
+
const A = a.split('\n'), B = b.split('\n');
|
|
172
|
+
const n = A.length, m = B.length;
|
|
173
|
+
const DIFF_MAX_LINES = 20000;
|
|
174
|
+
if (n > DIFF_MAX_LINES || m > DIFF_MAX_LINES || n * m > 4000000) return null;
|
|
175
|
+
const dp = new Array(n + 1);
|
|
176
|
+
for (let i = 0; i <= n; i++) dp[i] = new Int32Array(m + 1);
|
|
177
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
178
|
+
for (let j = m - 1; j >= 0; j--) {
|
|
179
|
+
dp[i][j] = A[i] === B[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const out = [];
|
|
183
|
+
let i = 0, j = 0;
|
|
184
|
+
while (i < n && j < m) {
|
|
185
|
+
if (A[i] === B[j]) { out.push({ type: 'ctx', text: A[i] }); i++; j++; }
|
|
186
|
+
else if (dp[i + 1][j] >= dp[i][j + 1]) { out.push({ type: 'del', text: A[i] }); i++; }
|
|
187
|
+
else { out.push({ type: 'add', text: B[j] }); j++; }
|
|
188
|
+
}
|
|
189
|
+
while (i < n) { out.push({ type: 'del', text: A[i] }); i++; }
|
|
190
|
+
while (j < m) { out.push({ type: 'add', text: B[j] }); j++; }
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
@@ -383,6 +383,46 @@ html, body {
|
|
|
383
383
|
content: '—'; color: oklch(36% 0.008 186 / 0.5); flex-shrink: 0; margin-top: 1px;
|
|
384
384
|
}
|
|
385
385
|
|
|
386
|
+
/* ── Files tab ──────────────────────────────────────────────────── */
|
|
387
|
+
#files-pane { padding: 20px; }
|
|
388
|
+
.files-grid {
|
|
389
|
+
display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
390
|
+
gap: 10px;
|
|
391
|
+
}
|
|
392
|
+
.file-card {
|
|
393
|
+
background: var(--bg-panel);
|
|
394
|
+
border: 1px solid var(--border); border-radius: 3px;
|
|
395
|
+
padding: 10px 12px;
|
|
396
|
+
display: flex; align-items: center; gap: 10px;
|
|
397
|
+
transition: border-color 0.12s;
|
|
398
|
+
}
|
|
399
|
+
.file-card:hover { border-color: var(--teal-dim); }
|
|
400
|
+
.fc-icon { font-size: 18px; flex-shrink: 0; }
|
|
401
|
+
.fc-body { flex: 1; min-width: 0; }
|
|
402
|
+
.fc-name {
|
|
403
|
+
font-size: 12px; color: var(--text); font-weight: 500;
|
|
404
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
405
|
+
}
|
|
406
|
+
.fc-meta {
|
|
407
|
+
font-size: 9px; color: var(--dim); margin-top: 2px;
|
|
408
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
409
|
+
}
|
|
410
|
+
.fc-view {
|
|
411
|
+
flex-shrink: 0; background: #1a3a5a; color: #5d9fd9; border: 1px solid #2980b944;
|
|
412
|
+
border-radius: 4px; padding: 4px 10px; font-size: 10px; font-weight: 700; cursor: pointer;
|
|
413
|
+
}
|
|
414
|
+
.fc-view:hover { background: #204a70; }
|
|
415
|
+
.fc-diff {
|
|
416
|
+
flex-shrink: 0; background: #2a1a3a; color: #b98dd9; border: 1px solid #8e44ad44;
|
|
417
|
+
border-radius: 4px; padding: 4px 10px; font-size: 10px; font-weight: 700; cursor: pointer;
|
|
418
|
+
}
|
|
419
|
+
.fc-diff:hover { background: #3a2050; }
|
|
420
|
+
.fc-vbadge {
|
|
421
|
+
font-size: 8px; font-weight: 700; color: var(--dim); border: 1px solid var(--border);
|
|
422
|
+
border-radius: 2px; padding: 1px 5px; margin-left: 4px; letter-spacing: 0.5px;
|
|
423
|
+
}
|
|
424
|
+
.fc-binary { flex-shrink: 0; font-size: 9px; color: var(--dim); }
|
|
425
|
+
|
|
386
426
|
/* ── Activity / event log ───────────────────────────────────────── */
|
|
387
427
|
#activity-pane { padding: 20px; }
|
|
388
428
|
#activity-log { display: flex; flex-direction: column; gap: 0; }
|
|
@@ -819,6 +859,7 @@ html, body {
|
|
|
819
859
|
<button class="tab-btn" onclick="switchTab('roles')">ROLES</button>
|
|
820
860
|
<button class="tab-btn" onclick="switchTab('activity')">ACTIVITY</button>
|
|
821
861
|
<button class="tab-btn" onclick="switchTab('health')">HEALTH</button>
|
|
862
|
+
<button class="tab-btn" onclick="switchTab('files')">FILES</button>
|
|
822
863
|
<button class="tab-btn" onclick="switchTab('chat')">CHAT</button>
|
|
823
864
|
</div>
|
|
824
865
|
|
|
@@ -937,6 +978,14 @@ html, body {
|
|
|
937
978
|
</div>
|
|
938
979
|
</div>
|
|
939
980
|
|
|
981
|
+
<!-- Files tab: every asset any agent in this org has produced, across all runs -->
|
|
982
|
+
<div class="tab-pane" id="tab-files">
|
|
983
|
+
<div id="files-pane">
|
|
984
|
+
<div id="files-empty" class="act-empty" style="display:none">No files produced yet.</div>
|
|
985
|
+
<div id="files-grid" class="files-grid"></div>
|
|
986
|
+
</div>
|
|
987
|
+
</div>
|
|
988
|
+
|
|
940
989
|
<!-- Chat tab -->
|
|
941
990
|
<div class="tab-pane" id="tab-chat">
|
|
942
991
|
<div id="chat-pane">
|
|
@@ -1081,9 +1130,19 @@ window.switchTab = function(tab) {
|
|
|
1081
1130
|
const mainBody = document.getElementById('main-body');
|
|
1082
1131
|
if (mainBody) mainBody.classList.toggle('chat-active', tab === 'chat');
|
|
1083
1132
|
if (tab === 'chat') renderChatTab();
|
|
1133
|
+
else if (tab === 'files') renderFilesTab();
|
|
1084
1134
|
else if (orgDetailData) renderTab(tab);
|
|
1085
1135
|
};
|
|
1086
1136
|
|
|
1137
|
+
// Files tab + diff view — extracted to orgs-files.js to keep this file under
|
|
1138
|
+
// the CLAUDE.md 500-line-per-file guideline. Loaded as a classic script below,
|
|
1139
|
+
// sharing this script's global scope (function declarations here call into it,
|
|
1140
|
+
// e.g. renderFilesTab() from renderTab() above and applyArtifactEvent() from
|
|
1141
|
+
// handleMmEvent() below).
|
|
1142
|
+
</script>
|
|
1143
|
+
<script src="orgs-files.js"></script>
|
|
1144
|
+
<script>
|
|
1145
|
+
|
|
1087
1146
|
// ── Render all orgs in sidebar ────────────────────────────────────
|
|
1088
1147
|
function renderSidebar() {
|
|
1089
1148
|
const list = document.getElementById('sb-list');
|
|
@@ -1689,8 +1748,13 @@ function orgSessionMatch(s) {
|
|
|
1689
1748
|
const orgLc = selectedOrg.toLowerCase();
|
|
1690
1749
|
const prompt = (s.prompt || '').toLowerCase();
|
|
1691
1750
|
if (prompt.includes('running org: ' + orgLc) || prompt.includes('org: ' + orgLc)) return true;
|
|
1692
|
-
//
|
|
1693
|
-
|
|
1751
|
+
// Only genuine org-run events (org:comms, org:artifact, org:start, ...) count.
|
|
1752
|
+
// agent:bash / agent:edit / etc. also carry an `org` field (ambient "which
|
|
1753
|
+
// org was active while this Claude Code session ran" tagging) — matching on
|
|
1754
|
+
// those too would pull an unrelated dev session's entire tool-call history
|
|
1755
|
+
// into this org's Chat/Files tabs whenever that org happened to be running
|
|
1756
|
+
// at the same time.
|
|
1757
|
+
return (s.events || []).some(ev => (ev.type || '').startsWith('org:') && (ev.org || '').toLowerCase() === orgLc);
|
|
1694
1758
|
}
|
|
1695
1759
|
|
|
1696
1760
|
function populateChatSelect() {
|
|
@@ -1834,21 +1898,21 @@ function appendChatEvent(ev, animate) {
|
|
|
1834
1898
|
} else if (ev.type === 'agent:spawn') {
|
|
1835
1899
|
const col = dc(ev.domain);
|
|
1836
1900
|
const name = ev.agentType || ev.from || ev.agent || 'agent';
|
|
1837
|
-
el = mkAgent(name, `spawned: ${
|
|
1901
|
+
el = mkAgent(name, `spawned: ${ev.task||'task'}`, ts, col, 'spawn');
|
|
1838
1902
|
} else if (ev.type === 'agent:complete') {
|
|
1839
1903
|
const name = ev.agentType || ev.role || ev.from || 'agent';
|
|
1840
1904
|
const result = (ev.result || '').slice(0, 300);
|
|
1841
1905
|
const cost = ev.cost_usd ? ` · $${parseFloat(ev.cost_usd).toFixed(4)}` : '';
|
|
1842
1906
|
const tools = ev.toolCalls?.length ? ` · ${ev.toolCalls.slice(0,4).join(', ')}` : '';
|
|
1843
|
-
el = mkAgent(name, `${
|
|
1907
|
+
el = mkAgent(name, `${result || 'done'}${tools}${cost}`, ts, dc(ev.domain), 'complete');
|
|
1844
1908
|
} else if (ev.type === 'org:comms') {
|
|
1845
|
-
el = mkIntercom(ev.from || 'boss', ev.to || 'agent',
|
|
1909
|
+
el = mkIntercom(ev.from || 'boss', ev.to || 'agent', ev.msg || ev.message || '', ts);
|
|
1846
1910
|
} else if (ev.type === 'agent:message') {
|
|
1847
|
-
el = mkAgent(ev.agent||'agent',
|
|
1911
|
+
el = mkAgent(ev.agent||'agent', ev.text||'', ts, dc(ev.domain), null);
|
|
1848
1912
|
} else if (ev.type === 'intercom') {
|
|
1849
|
-
el = mkIntercom(ev.from, ev.to,
|
|
1913
|
+
el = mkIntercom(ev.from, ev.to, ev.msg||'', ts);
|
|
1850
1914
|
} else if (ev.type === 'user:message') {
|
|
1851
|
-
el = mkUser(
|
|
1915
|
+
el = mkUser(ev.text||ev.msg||'', ts);
|
|
1852
1916
|
} else if (ev.type === 'loop:start') {
|
|
1853
1917
|
el = mkSys(`🔁 Loop: ${esc(ev.command||'')} (${ev.repeat||'?'} runs)`, ts);
|
|
1854
1918
|
} else if (ev.type === 'loop:complete') {
|
|
@@ -1876,13 +1940,13 @@ function mkAgent(name, text, ts, color, typeTag) {
|
|
|
1876
1940
|
el.className = 'cmsg cagent';
|
|
1877
1941
|
const tagStyle = color ? `style="border-color:${color}44;color:${color}"` : '';
|
|
1878
1942
|
const ttag = typeTag ? `<span class="cevtype">${esc(typeTag)}</span>` : '';
|
|
1879
|
-
el.innerHTML = `<div class="cmsg-meta"><span class="ctag" ${tagStyle}>${esc(name)}</span>${ttag}<span class="cts">${ts}</span></div><div class="cbubble">${text}</div>`;
|
|
1943
|
+
el.innerHTML = `<div class="cmsg-meta"><span class="ctag" ${tagStyle}>${esc(name)}</span>${ttag}<span class="cts">${ts}</span></div><div class="cbubble">${esc(text)}</div>`;
|
|
1880
1944
|
return el;
|
|
1881
1945
|
}
|
|
1882
1946
|
function mkIntercom(from, to, text, ts) {
|
|
1883
1947
|
const el = document.createElement('div');
|
|
1884
1948
|
el.className = 'cmsg cic';
|
|
1885
|
-
el.innerHTML = `<div class="cmsg-meta"><span class="ctag sender">${esc(from||'?')}</span><span class="cic-arrow">→</span><span class="ctag receiver">${esc(to||'?')}</span><span class="cevtype">intercom</span><span class="cts">${ts}</span></div><div class="cbubble">${text}</div>`;
|
|
1949
|
+
el.innerHTML = `<div class="cmsg-meta"><span class="ctag sender">${esc(from||'?')}</span><span class="cic-arrow">→</span><span class="ctag receiver">${esc(to||'?')}</span><span class="cevtype">intercom</span><span class="cts">${ts}</span></div><div class="cbubble">${esc(text)}</div>`;
|
|
1886
1950
|
return el;
|
|
1887
1951
|
}
|
|
1888
1952
|
function mkArtifact(art, ts) {
|
|
@@ -1901,7 +1965,7 @@ function mkArtifact(art, ts) {
|
|
|
1901
1965
|
function mkUser(text, ts) {
|
|
1902
1966
|
const el = document.createElement('div');
|
|
1903
1967
|
el.className = 'cmsg cuser';
|
|
1904
|
-
el.innerHTML = `<div class="cmsg-meta" style="justify-content:flex-end"><span class="cts">${ts}</span><span class="ctag" style="border-color:oklch(68% 0.18 250 / 0.35);color:oklch(68% 0.14 250)">you</span></div><div class="cbubble">${text}</div>`;
|
|
1968
|
+
el.innerHTML = `<div class="cmsg-meta" style="justify-content:flex-end"><span class="cts">${ts}</span><span class="ctag" style="border-color:oklch(68% 0.18 250 / 0.35);color:oklch(68% 0.14 250)">you</span></div><div class="cbubble">${esc(text)}</div>`;
|
|
1905
1969
|
return el;
|
|
1906
1970
|
}
|
|
1907
1971
|
|
|
@@ -2042,6 +2106,10 @@ function handleMmEvent(ev) {
|
|
|
2042
2106
|
appendChatEvent(ev, true);
|
|
2043
2107
|
chatScrollFeed();
|
|
2044
2108
|
}
|
|
2109
|
+
// Live-update the Files tab when a new asset lands while it's open — incremental,
|
|
2110
|
+
// not a rescan of every session's every event (that's collectOrgArtifacts()'s job,
|
|
2111
|
+
// reserved for tab-open / initial load in renderFilesTab()).
|
|
2112
|
+
if (ev.type === 'org:artifact' && currentTab === 'files') applyArtifactEvent(ev);
|
|
2045
2113
|
}
|
|
2046
2114
|
}
|
|
2047
2115
|
|