@ijfw/memory-server 1.3.0 → 1.4.1
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 +67 -0
- package/fixtures/team/book.json +47 -0
- package/fixtures/team/business.json +47 -0
- package/fixtures/team/content.json +47 -0
- package/fixtures/team/design.json +47 -0
- package/fixtures/team/mixed.json +59 -0
- package/fixtures/team/research.json +47 -0
- package/fixtures/team/software.json +47 -0
- package/package.json +1 -9
- package/src/.registry-meta-key.pem +3 -0
- package/src/active-extension-writer.js +142 -0
- package/src/blackboard.js +360 -0
- package/src/cli-run.js +91 -0
- package/src/codex-agents.js +177 -0
- package/src/compute/extract.js +3 -0
- package/src/compute/fts5.js +4 -4
- package/src/compute/graph-lock.js +0 -2
- package/src/compute/migrations/003-tier-semantic.js +3 -3
- package/src/compute/runner.js +44 -15
- package/src/compute/schema.sql +1 -1
- package/src/cross-orchestrator-cli.js +974 -13
- package/src/cross-orchestrator.js +9 -1
- package/src/dashboard-client.html +353 -1
- package/src/dashboard-server.js +318 -2
- package/src/design-intelligence.js +721 -0
- package/src/dispatch/colon-syntax.js +31 -3
- package/src/dispatch/domain-manifest.js +251 -0
- package/src/dispatch/extension.js +637 -0
- package/src/dispatch/override.js +221 -0
- package/src/dispatch-planner.js +1 -0
- package/src/dream/runner.mjs +3 -3
- package/src/extension-installer.js +1269 -0
- package/src/extension-manifest-schema.js +301 -0
- package/src/extension-permission-check.mjs +79 -0
- package/src/extension-registry.js +619 -0
- package/src/extension-signer.js +905 -0
- package/src/gate-result-formatter.js +95 -0
- package/src/gate-result-schema.js +274 -0
- package/src/gate-result.js +195 -0
- package/src/intent-router.js +2 -0
- package/src/lib/npm-view.js +1 -0
- package/src/memory/fts5.js +3 -3
- package/src/memory/migrations/002-tier-semantic.js +2 -2
- package/src/memory/staleness.js +1 -1
- package/src/memory/tier-promotion.js +6 -6
- package/src/memory/tokenize.js +1 -1
- package/src/memory-feedback.js +372 -0
- package/src/override-manifest-schema.js +146 -0
- package/src/override-resolver.js +699 -0
- package/src/override-use-registry.js +307 -0
- package/src/overrides/presets/academic.md +101 -0
- package/src/overrides/presets/book.md +87 -0
- package/src/overrides/presets/campaign.md +95 -0
- package/src/overrides/presets/screenplay.md +99 -0
- package/src/recovery/checkpoint.js +191 -0
- package/src/redactor.js +2 -0
- package/src/runtime-mediator.js +207 -0
- package/src/sandbox.js +17 -3
- package/src/server.js +94 -2
- package/src/swarm/dispatch-prompt.js +154 -0
- package/src/swarm/planner.js +399 -0
- package/src/swarm/review.js +136 -0
- package/src/swarm/worktree.js +239 -0
- package/src/team/generator.js +119 -0
- package/src/team/schemas.js +341 -0
- package/src/trident/dispatch.js +47 -0
- package/src/update-check.js +1 -1
- package/src/vectors.js +7 -8
|
@@ -182,6 +182,14 @@ function spawnCli(pick, request, timeoutMs, signal = null, env = process.env) {
|
|
|
182
182
|
// Listen for external abort (runAc).
|
|
183
183
|
if (signal) signal.addEventListener('abort', killAndAbort, { once: true });
|
|
184
184
|
|
|
185
|
+
// CLI children can exit before consuming stdin (for example auth failures,
|
|
186
|
+
// startup validation, or commands that reject piped input). Treat pipe
|
|
187
|
+
// errors as child stderr/exit evidence, not uncaught process exceptions.
|
|
188
|
+
proc.stdin.on('error', (err) => {
|
|
189
|
+
if (err?.code && !stderr.includes(err.code)) stderr += `${stderr ? '\n' : ''}stdin ${err.code}`;
|
|
190
|
+
});
|
|
191
|
+
proc.stdout.on('error', () => {});
|
|
192
|
+
proc.stderr.on('error', () => {});
|
|
185
193
|
proc.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
|
|
186
194
|
proc.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
|
|
187
195
|
// Single-settlement guard: error + close can both fire on spawn failure.
|
|
@@ -200,7 +208,7 @@ function spawnCli(pick, request, timeoutMs, signal = null, env = process.env) {
|
|
|
200
208
|
try {
|
|
201
209
|
const flushed = proc.stdin.write(request);
|
|
202
210
|
if (flushed) {
|
|
203
|
-
proc.stdin.end();
|
|
211
|
+
try { proc.stdin.end(); } catch { /* stdin may close before end */ }
|
|
204
212
|
} else {
|
|
205
213
|
proc.stdin.once('drain', () => { try { proc.stdin.end(); } catch { /* */ } });
|
|
206
214
|
}
|
|
@@ -143,6 +143,15 @@ tr:hover td{background:var(--surface)}
|
|
|
143
143
|
.empty{text-align:center;padding:40px 20px;color:var(--fg-dim)}
|
|
144
144
|
.empty-icon{font-size:32px;margin-bottom:10px;opacity:.4}
|
|
145
145
|
|
|
146
|
+
/* Extension events */
|
|
147
|
+
.evt-row{display:flex;gap:8px;padding:5px 0;border-bottom:1px solid var(--border);align-items:flex-start}
|
|
148
|
+
.evt-row:last-child{border-bottom:none}
|
|
149
|
+
.evt-ts{color:var(--fg-dim);white-space:nowrap;font-size:11px;min-width:80px}
|
|
150
|
+
.evt-badge{display:inline-block;padding:1px 6px;border-radius:3px;font-size:10px;font-weight:700;white-space:nowrap}
|
|
151
|
+
.evt-allow{background:rgba(46,204,113,0.15);color:var(--success)}
|
|
152
|
+
.evt-deny{background:rgba(239,68,68,0.15);color:var(--danger)}
|
|
153
|
+
.evt-body{flex:1;color:var(--fg);font-size:11px;word-break:break-all}
|
|
154
|
+
|
|
146
155
|
/* Memory tree */
|
|
147
156
|
.mem-layout{display:flex;gap:0;height:calc(100vh - 180px);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}
|
|
148
157
|
.mem-l{width:300px;flex-shrink:0;border-right:1px solid var(--border);display:flex;flex-direction:column;background:var(--bg-elevated)}
|
|
@@ -228,6 +237,7 @@ tr:hover td{background:var(--surface)}
|
|
|
228
237
|
|
|
229
238
|
<div class="sb-group-label"><span>Audits</span></div>
|
|
230
239
|
<button class="sb-item" data-section="trident"><span class="sb-icon">▲</span><span class="sb-label">Cross-AI Reviews</span></button>
|
|
240
|
+
<button class="sb-item" data-section="extensions"><span class="sb-icon">⚙</span><span class="sb-label">Extensions</span></button>
|
|
231
241
|
|
|
232
242
|
<div class="sb-group-label"><span>Settings</span></div>
|
|
233
243
|
<button class="sb-item" data-section="subs"><span class="sb-icon">⚗</span><span class="sb-label">Settings</span></button>
|
|
@@ -562,6 +572,49 @@ tr:hover td{background:var(--surface)}
|
|
|
562
572
|
</div>
|
|
563
573
|
</div>
|
|
564
574
|
|
|
575
|
+
<!-- ======== EXTENSIONS (W3/t15 + B9) ======== -->
|
|
576
|
+
<div class="section" data-section="extensions">
|
|
577
|
+
<!-- Sub-section: Installed -->
|
|
578
|
+
<div class="card">
|
|
579
|
+
<div class="ctitle"><span id="ext-count">Extensions</span></div>
|
|
580
|
+
<div id="extensions-content">
|
|
581
|
+
<div class="empty">
|
|
582
|
+
<div class="empty-icon">⚙</div>
|
|
583
|
+
<p>Loading extensions...</p>
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
</div>
|
|
587
|
+
|
|
588
|
+
<!-- Sub-section: Active extension -->
|
|
589
|
+
<div class="card">
|
|
590
|
+
<div class="ctitle">Active Extension</div>
|
|
591
|
+
<div id="ext-active-content">
|
|
592
|
+
<div class="empty"><p style="font-size:13px">Loading...</p></div>
|
|
593
|
+
</div>
|
|
594
|
+
</div>
|
|
595
|
+
|
|
596
|
+
<!-- Sub-section: Permission events -->
|
|
597
|
+
<div class="card">
|
|
598
|
+
<div class="ctitle" style="justify-content:space-between">
|
|
599
|
+
<span>Permission Events <span id="ext-events-live" style="display:none"><span class="pulse"></span></span></span>
|
|
600
|
+
<span style="display:flex;gap:8px;align-items:center">
|
|
601
|
+
<select id="ext-evt-filter-ext" class="btn-g" style="padding:3px 8px;font-size:11px" aria-label="Filter by extension">
|
|
602
|
+
<option value="">All extensions</option>
|
|
603
|
+
</select>
|
|
604
|
+
<select id="ext-evt-filter-denied" class="btn-g" style="padding:3px 8px;font-size:11px" aria-label="Filter by outcome">
|
|
605
|
+
<option value="">All outcomes</option>
|
|
606
|
+
<option value="true">Denied only</option>
|
|
607
|
+
<option value="false">Allowed only</option>
|
|
608
|
+
</select>
|
|
609
|
+
<button class="btn-g" id="ext-evt-clear" style="font-size:11px" aria-label="Clear events">Clear</button>
|
|
610
|
+
</span>
|
|
611
|
+
</div>
|
|
612
|
+
<div id="ext-events-content" style="max-height:320px;overflow-y:auto;font-size:12px;font-family:ui-monospace,monospace">
|
|
613
|
+
<div class="empty"><p>No permission events yet.</p></div>
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
</div>
|
|
617
|
+
|
|
565
618
|
<!-- ======== SUBSCRIPTIONS ======== -->
|
|
566
619
|
<div class="section" data-section="subs">
|
|
567
620
|
<div class="sgrid">
|
|
@@ -626,7 +679,7 @@ tr:hover td{background:var(--surface)}
|
|
|
626
679
|
// ====== LUCIDE ICONS (vendored, ISC license, https://lucide.dev) ======
|
|
627
680
|
const ICONS = {"activity":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\"/></svg>","bar-chart-2":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 21v-6\"/><path d=\"M12 21V3\"/><path d=\"M19 21V9\"/></svg>","clock":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 6v6l4 2\"/></svg>","credit-card":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"20\" height=\"14\" x=\"2\" y=\"5\" rx=\"2\"/><line x1=\"2\" x2=\"22\" y1=\"10\" y2=\"10\"/></svg>","dollar-sign":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" x2=\"12\" y1=\"2\" y2=\"22\"/><path d=\"M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6\"/></svg>","file-text":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8l6 6v12a2 2 0 0 1-2 2z\"/><path d=\"M14 2v6h6\"/><path d=\"M10 9H8\"/><path d=\"M16 13H8\"/><path d=\"M16 17H8\"/></svg>","folder-open":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\"/></svg>","folder":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\"/></svg>","home":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8\"/><path d=\"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\"/></svg>","layers":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z\"/><path d=\"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12\"/><path d=\"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17\"/></svg>","search":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m21 21-4.34-4.34\"/><circle cx=\"11\" cy=\"11\" r=\"8\"/></svg>","settings":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>","shield":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\"/></svg>","trending-up":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M16 7h6v6\"/><path d=\"m22 7-8.5 8.5-5-5L2 17\"/></svg>","users":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\"/><path d=\"M16 3.128a4 4 0 0 1 0 7.744\"/><path d=\"M22 21v-2a4 4 0 0 0-3-3.87\"/><circle cx=\"9\" cy=\"7\" r=\"4\"/></svg>","zap":"<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\"/></svg>"};
|
|
628
681
|
|
|
629
|
-
var ICON_MAP = {today:'home',live:'activity',window:'clock',spend:'dollar-sign',models:'layers',activity:'bar-chart-2',trend:'trending-up',memsearch:'search',sessions:'clock',handoffs:'file-text',allprojects:'folder',trident:'shield',subs:'credit-card',accounts:'users',display:'settings'};
|
|
682
|
+
var ICON_MAP = {today:'home',live:'activity',window:'clock',spend:'dollar-sign',models:'layers',activity:'bar-chart-2',trend:'trending-up',memsearch:'search',sessions:'clock',handoffs:'file-text',allprojects:'folder',trident:'shield',extensions:'package',subs:'credit-card',accounts:'users',display:'settings'};
|
|
630
683
|
|
|
631
684
|
document.querySelectorAll('.sb-icon').forEach(function(el) {
|
|
632
685
|
var sec = el.closest('.sb-item');
|
|
@@ -1161,6 +1214,302 @@ async function loadBlockUsage() {
|
|
|
1161
1214
|
} catch(e) {}
|
|
1162
1215
|
}
|
|
1163
1216
|
|
|
1217
|
+
// ====== EXTENSIONS (W3/t15) ======
|
|
1218
|
+
function _extScopeChipColor(scope) {
|
|
1219
|
+
// project = accent, org = surface, user = dim
|
|
1220
|
+
if (scope === 'project') return 'background:rgba(94,106,210,0.18);color:var(--accent)';
|
|
1221
|
+
if (scope === 'org') return 'background:var(--surface);color:var(--fg)';
|
|
1222
|
+
return 'background:var(--surface);color:var(--fg-dim)';
|
|
1223
|
+
}
|
|
1224
|
+
function _extVerdictChipColor(v) {
|
|
1225
|
+
var u = String(v || '').toUpperCase();
|
|
1226
|
+
if (u === 'PASS') return 'background:rgba(60,170,90,0.18);color:#3caa5a';
|
|
1227
|
+
if (u === 'CONDITIONAL') return 'background:rgba(220,180,60,0.18);color:#caa030';
|
|
1228
|
+
if (u === 'WARN') return 'background:rgba(220,180,60,0.18);color:#caa030';
|
|
1229
|
+
if (u === 'FLAG') return 'background:rgba(220,120,60,0.18);color:#c87038';
|
|
1230
|
+
if (u === 'FAIL') return 'background:rgba(220,60,60,0.18);color:#c84040';
|
|
1231
|
+
return 'background:var(--surface);color:var(--fg-dim)';
|
|
1232
|
+
}
|
|
1233
|
+
function _extChip(text, style) {
|
|
1234
|
+
var span = document.createElement('span');
|
|
1235
|
+
span.className = 'chip';
|
|
1236
|
+
span.setAttribute('style', style);
|
|
1237
|
+
span.textContent = text;
|
|
1238
|
+
return span;
|
|
1239
|
+
}
|
|
1240
|
+
function _extEmpty(content, msg, subMsg) {
|
|
1241
|
+
while (content.firstChild) content.removeChild(content.firstChild);
|
|
1242
|
+
var wrap = document.createElement('div');
|
|
1243
|
+
wrap.className = 'empty';
|
|
1244
|
+
var icon = document.createElement('div');
|
|
1245
|
+
icon.className = 'empty-icon';
|
|
1246
|
+
icon.textContent = '⚙'; // gear
|
|
1247
|
+
var p1 = document.createElement('p');
|
|
1248
|
+
p1.textContent = msg;
|
|
1249
|
+
var p2 = document.createElement('p');
|
|
1250
|
+
p2.setAttribute('style', 'margin-top:8px;font-size:12px;color:var(--fg-dim)');
|
|
1251
|
+
p2.textContent = subMsg;
|
|
1252
|
+
wrap.appendChild(icon);
|
|
1253
|
+
wrap.appendChild(p1);
|
|
1254
|
+
wrap.appendChild(p2);
|
|
1255
|
+
content.appendChild(wrap);
|
|
1256
|
+
}
|
|
1257
|
+
async function loadExtensions() {
|
|
1258
|
+
var content = document.getElementById('extensions-content');
|
|
1259
|
+
var countEl = document.getElementById('ext-count');
|
|
1260
|
+
if (!content) return;
|
|
1261
|
+
try {
|
|
1262
|
+
var r = await fetch('/api/extensions/health');
|
|
1263
|
+
var d = await r.json();
|
|
1264
|
+
var exts = Array.isArray(d.extensions) ? d.extensions : [];
|
|
1265
|
+
var staleCount = exts.filter(function(e) { return e.status === 'stale'; }).length;
|
|
1266
|
+
|
|
1267
|
+
if (countEl) {
|
|
1268
|
+
countEl.textContent = exts.length === 0
|
|
1269
|
+
? 'Extensions'
|
|
1270
|
+
: 'Extensions (' + exts.length + ' installed' + (staleCount ? ', ' + staleCount + ' stale' : '') + ')';
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
if (exts.length === 0) {
|
|
1274
|
+
_extEmpty(content, 'No extensions installed.',
|
|
1275
|
+
'Install with `ijfw extension install <source>`. Extensions ship overrides, skills, and integrations.');
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
while (content.firstChild) content.removeChild(content.firstChild);
|
|
1280
|
+
|
|
1281
|
+
if (staleCount > 0) {
|
|
1282
|
+
var banner = document.createElement('div');
|
|
1283
|
+
banner.setAttribute('style', 'padding:8px 12px;margin-bottom:12px;background:rgba(220,120,60,0.08);border-left:3px solid #c87038;border-radius:4px;font-size:13px');
|
|
1284
|
+
banner.textContent = '⚠ ' + staleCount + ' extension' + (staleCount === 1 ? '' : 's') +
|
|
1285
|
+
' marked stale -- scope dir is missing. Run `ijfw extension reinstall` or remove the entry.';
|
|
1286
|
+
content.appendChild(banner);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
var table = document.createElement('table');
|
|
1290
|
+
table.setAttribute('aria-label', 'Installed extensions');
|
|
1291
|
+
var thead = document.createElement('thead');
|
|
1292
|
+
var trh = document.createElement('tr');
|
|
1293
|
+
['Name','Version','Scope','Last Trident','Status'].forEach(function(h) {
|
|
1294
|
+
var th = document.createElement('th');
|
|
1295
|
+
th.textContent = h;
|
|
1296
|
+
trh.appendChild(th);
|
|
1297
|
+
});
|
|
1298
|
+
thead.appendChild(trh);
|
|
1299
|
+
table.appendChild(thead);
|
|
1300
|
+
|
|
1301
|
+
var tbody = document.createElement('tbody');
|
|
1302
|
+
exts.forEach(function(e) {
|
|
1303
|
+
var tr = document.createElement('tr');
|
|
1304
|
+
var tdName = document.createElement('td');
|
|
1305
|
+
var strong = document.createElement('strong');
|
|
1306
|
+
strong.textContent = e.name || '';
|
|
1307
|
+
tdName.appendChild(strong);
|
|
1308
|
+
tr.appendChild(tdName);
|
|
1309
|
+
|
|
1310
|
+
var tdVer = document.createElement('td');
|
|
1311
|
+
tdVer.textContent = e.version || '';
|
|
1312
|
+
tr.appendChild(tdVer);
|
|
1313
|
+
|
|
1314
|
+
var tdScope = document.createElement('td');
|
|
1315
|
+
tdScope.appendChild(_extChip(e.scope || 'unknown', _extScopeChipColor(e.scope)));
|
|
1316
|
+
tr.appendChild(tdScope);
|
|
1317
|
+
|
|
1318
|
+
var tdVerdict = document.createElement('td');
|
|
1319
|
+
var verdict = e.last_trident_verdict;
|
|
1320
|
+
tdVerdict.appendChild(_extChip(verdict == null ? '--' : String(verdict),
|
|
1321
|
+
_extVerdictChipColor(verdict)));
|
|
1322
|
+
tr.appendChild(tdVerdict);
|
|
1323
|
+
|
|
1324
|
+
var tdStatus = document.createElement('td');
|
|
1325
|
+
if (e.status === 'stale') {
|
|
1326
|
+
var staleChip = _extChip('stale', 'background:rgba(220,120,60,0.18);color:#c87038');
|
|
1327
|
+
staleChip.title = 'scope dir missing';
|
|
1328
|
+
tdStatus.appendChild(staleChip);
|
|
1329
|
+
} else {
|
|
1330
|
+
tdStatus.appendChild(_extChip('active', 'background:rgba(60,170,90,0.18);color:#3caa5a'));
|
|
1331
|
+
}
|
|
1332
|
+
tr.appendChild(tdStatus);
|
|
1333
|
+
|
|
1334
|
+
tbody.appendChild(tr);
|
|
1335
|
+
});
|
|
1336
|
+
table.appendChild(tbody);
|
|
1337
|
+
content.appendChild(table);
|
|
1338
|
+
} catch (err) {
|
|
1339
|
+
if (countEl) countEl.textContent = 'Extensions';
|
|
1340
|
+
_extEmpty(content, 'No extensions installed.',
|
|
1341
|
+
'Registry unavailable -- this is normal before the first install.');
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// ====== ACTIVE EXTENSION LOADER (B9) ======
|
|
1346
|
+
async function loadExtensionActive() {
|
|
1347
|
+
var el = document.getElementById('ext-active-content');
|
|
1348
|
+
if (!el) return;
|
|
1349
|
+
try {
|
|
1350
|
+
var r = await fetch('/api/extensions/active');
|
|
1351
|
+
var d = await r.json();
|
|
1352
|
+
while (el.firstChild) el.removeChild(el.firstChild);
|
|
1353
|
+
if (!d.active) {
|
|
1354
|
+
var p = document.createElement('p');
|
|
1355
|
+
p.setAttribute('style', 'font-size:13px;color:var(--fg-dim);padding:4px 0');
|
|
1356
|
+
p.textContent = 'None — bundled IJFW context active';
|
|
1357
|
+
el.appendChild(p);
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
var a = d.active;
|
|
1361
|
+
var wrap = document.createElement('div');
|
|
1362
|
+
wrap.setAttribute('style', 'font-size:13px');
|
|
1363
|
+
var nameRow = document.createElement('div');
|
|
1364
|
+
nameRow.setAttribute('style', 'margin-bottom:6px');
|
|
1365
|
+
var strong = document.createElement('strong');
|
|
1366
|
+
strong.textContent = a.name || 'unknown';
|
|
1367
|
+
nameRow.appendChild(strong);
|
|
1368
|
+
if (a.scope) {
|
|
1369
|
+
var sc = document.createElement('span');
|
|
1370
|
+
sc.setAttribute('style', 'margin-left:8px;font-size:11px;color:var(--fg-dim)');
|
|
1371
|
+
sc.textContent = '(' + a.scope + ')';
|
|
1372
|
+
nameRow.appendChild(sc);
|
|
1373
|
+
}
|
|
1374
|
+
wrap.appendChild(nameRow);
|
|
1375
|
+
if (a.permissions) {
|
|
1376
|
+
var permsEl = document.createElement('div');
|
|
1377
|
+
permsEl.setAttribute('style', 'font-size:12px;color:var(--fg-dim)');
|
|
1378
|
+
var reads = (a.permissions.reads || []).join(', ') || 'none';
|
|
1379
|
+
var writes = (a.permissions.writes || []).join(', ') || 'none';
|
|
1380
|
+
permsEl.innerHTML = '<b style="color:var(--fg)">reads:</b> ' + reads + ' <b style="color:var(--fg)">writes:</b> ' + writes;
|
|
1381
|
+
wrap.appendChild(permsEl);
|
|
1382
|
+
}
|
|
1383
|
+
el.appendChild(wrap);
|
|
1384
|
+
} catch (err) {
|
|
1385
|
+
if (el) { while (el.firstChild) el.removeChild(el.firstChild); }
|
|
1386
|
+
var errP = document.createElement('p');
|
|
1387
|
+
errP.setAttribute('style', 'font-size:12px;color:var(--fg-dim)');
|
|
1388
|
+
errP.textContent = 'Could not load active extension state.';
|
|
1389
|
+
if (el) el.appendChild(errP);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
// ====== PERMISSION EVENTS LOADER (B9) ======
|
|
1394
|
+
var _evtSource = null;
|
|
1395
|
+
var _evtRows = [];
|
|
1396
|
+
var _evtExtensions = new Set();
|
|
1397
|
+
|
|
1398
|
+
function _renderEvtRows() {
|
|
1399
|
+
var el = document.getElementById('ext-events-content');
|
|
1400
|
+
if (!el) return;
|
|
1401
|
+
var filterExt = (document.getElementById('ext-evt-filter-ext') || {}).value || '';
|
|
1402
|
+
var filterDenied = (document.getElementById('ext-evt-filter-denied') || {}).value || '';
|
|
1403
|
+
var visible = _evtRows.filter(function(e) {
|
|
1404
|
+
if (filterExt && e.extension !== filterExt) return false;
|
|
1405
|
+
if (filterDenied === 'true' && e.allowed !== false) return false;
|
|
1406
|
+
if (filterDenied === 'false' && e.allowed === false) return false;
|
|
1407
|
+
return true;
|
|
1408
|
+
});
|
|
1409
|
+
while (el.firstChild) el.removeChild(el.firstChild);
|
|
1410
|
+
if (visible.length === 0) {
|
|
1411
|
+
var empty = document.createElement('div');
|
|
1412
|
+
empty.className = 'empty';
|
|
1413
|
+
var ep = document.createElement('p');
|
|
1414
|
+
ep.textContent = 'No permission events match the current filters.';
|
|
1415
|
+
empty.appendChild(ep);
|
|
1416
|
+
el.appendChild(empty);
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
var frag = document.createDocumentFragment();
|
|
1420
|
+
visible.slice(-200).forEach(function(e) {
|
|
1421
|
+
var row = document.createElement('div');
|
|
1422
|
+
row.className = 'evt-row';
|
|
1423
|
+
var ts = document.createElement('span');
|
|
1424
|
+
ts.className = 'evt-ts';
|
|
1425
|
+
ts.textContent = e.ts ? new Date(e.ts).toLocaleTimeString() : '';
|
|
1426
|
+
row.appendChild(ts);
|
|
1427
|
+
var badge = document.createElement('span');
|
|
1428
|
+
badge.className = 'evt-badge ' + (e.allowed === false ? 'evt-deny' : 'evt-allow');
|
|
1429
|
+
badge.textContent = e.allowed === false ? 'DENY' : 'ALLOW';
|
|
1430
|
+
row.appendChild(badge);
|
|
1431
|
+
var body = document.createElement('span');
|
|
1432
|
+
body.className = 'evt-body';
|
|
1433
|
+
body.textContent = (e.extension || '') + ' → ' + (e.tool || e.action || '') + (e.target ? ':' + e.target : '');
|
|
1434
|
+
row.appendChild(body);
|
|
1435
|
+
frag.appendChild(row);
|
|
1436
|
+
});
|
|
1437
|
+
el.appendChild(frag);
|
|
1438
|
+
el.scrollTop = el.scrollHeight;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
function _addEvtRow(obj) {
|
|
1442
|
+
_evtRows.push(obj);
|
|
1443
|
+
if (obj.extension) {
|
|
1444
|
+
_evtExtensions.add(obj.extension);
|
|
1445
|
+
// Rebuild extension filter options
|
|
1446
|
+
var sel = document.getElementById('ext-evt-filter-ext');
|
|
1447
|
+
if (sel) {
|
|
1448
|
+
var existing = new Set(Array.from(sel.options).map(function(o) { return o.value; }));
|
|
1449
|
+
_evtExtensions.forEach(function(name) {
|
|
1450
|
+
if (!existing.has(name)) {
|
|
1451
|
+
var opt = document.createElement('option');
|
|
1452
|
+
opt.value = name; opt.textContent = name;
|
|
1453
|
+
sel.appendChild(opt);
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
function loadExtensionEvents() {
|
|
1461
|
+
var liveEl = document.getElementById('ext-events-live');
|
|
1462
|
+
|
|
1463
|
+
// Close any previous SSE connection.
|
|
1464
|
+
if (_evtSource) { try { _evtSource.close(); } catch {} _evtSource = null; }
|
|
1465
|
+
if (liveEl) liveEl.style.display = 'none';
|
|
1466
|
+
|
|
1467
|
+
// Pre-load current tail via JSON (no SSE until section is active).
|
|
1468
|
+
fetch('/api/extensions/events?limit=200')
|
|
1469
|
+
.then(function(r) { return r.json(); })
|
|
1470
|
+
.then(function(arr) {
|
|
1471
|
+
if (!Array.isArray(arr)) return;
|
|
1472
|
+
_evtRows = [];
|
|
1473
|
+
arr.forEach(_addEvtRow);
|
|
1474
|
+
_renderEvtRows();
|
|
1475
|
+
// Open SSE for live updates.
|
|
1476
|
+
try {
|
|
1477
|
+
_evtSource = new EventSource('/api/extensions/events?limit=1');
|
|
1478
|
+
_evtSource.onopen = function() { if (liveEl) liveEl.style.display = ''; };
|
|
1479
|
+
_evtSource.onmessage = function(e) {
|
|
1480
|
+
try {
|
|
1481
|
+
var obj = JSON.parse(e.data);
|
|
1482
|
+
if (obj && typeof obj === 'object' && !obj.showing) {
|
|
1483
|
+
_addEvtRow(obj);
|
|
1484
|
+
_renderEvtRows();
|
|
1485
|
+
}
|
|
1486
|
+
} catch {}
|
|
1487
|
+
};
|
|
1488
|
+
_evtSource.onerror = function() { if (liveEl) liveEl.style.display = 'none'; };
|
|
1489
|
+
} catch {}
|
|
1490
|
+
})
|
|
1491
|
+
.catch(function() {
|
|
1492
|
+
var el = document.getElementById('ext-events-content');
|
|
1493
|
+
if (!el) return;
|
|
1494
|
+
while (el.firstChild) el.removeChild(el.firstChild);
|
|
1495
|
+
var p = document.createElement('p');
|
|
1496
|
+
p.setAttribute('style', 'font-size:12px;color:var(--fg-dim);padding:8px 0');
|
|
1497
|
+
p.textContent = 'Permission events unavailable.';
|
|
1498
|
+
el.appendChild(p);
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
// Wire filter controls.
|
|
1502
|
+
var filterExt = document.getElementById('ext-evt-filter-ext');
|
|
1503
|
+
var filterDenied = document.getElementById('ext-evt-filter-denied');
|
|
1504
|
+
var clearBtn = document.getElementById('ext-evt-clear');
|
|
1505
|
+
if (filterExt) filterExt.onchange = _renderEvtRows;
|
|
1506
|
+
if (filterDenied) filterDenied.onchange = _renderEvtRows;
|
|
1507
|
+
if (clearBtn) clearBtn.onclick = function() {
|
|
1508
|
+
_evtRows = [];
|
|
1509
|
+
_renderEvtRows();
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1164
1513
|
// ====== RUN ALL LOADERS ======
|
|
1165
1514
|
document.addEventListener('DOMContentLoaded', function() {
|
|
1166
1515
|
loadCostToday();
|
|
@@ -1174,6 +1523,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
1174
1523
|
loadConfig();
|
|
1175
1524
|
loadTrendSparkline();
|
|
1176
1525
|
loadBlockUsage();
|
|
1526
|
+
loadExtensions();
|
|
1527
|
+
loadExtensionActive();
|
|
1528
|
+
loadExtensionEvents();
|
|
1177
1529
|
});
|
|
1178
1530
|
</script>
|
|
1179
1531
|
</body>
|