@dollhousemcp/mcp-server 2.0.16 → 2.0.18
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/CHANGELOG.md +12 -0
- package/README.md.backup +18 -0
- package/dist/elements/BaseElement.d.ts +1 -0
- package/dist/elements/BaseElement.d.ts.map +1 -1
- package/dist/elements/BaseElement.js +7 -1
- package/dist/elements/agents/AgentManager.js +2 -2
- package/dist/elements/base/BaseElementManager.d.ts.map +1 -1
- package/dist/elements/base/BaseElementManager.js +17 -1
- package/dist/elements/base/ElementFileOperations.js +2 -2
- package/dist/elements/ensembles/EnsembleManager.js +3 -3
- package/dist/elements/memories/MemoryManager.d.ts.map +1 -1
- package/dist/elements/memories/MemoryManager.js +14 -3
- package/dist/elements/skills/SkillManager.js +2 -2
- package/dist/elements/templates/TemplateManager.js +2 -2
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +3 -3
- package/dist/handlers/ElementCRUDHandler.d.ts.map +1 -1
- package/dist/handlers/ElementCRUDHandler.js +3 -2
- package/dist/handlers/element-crud/createElement.d.ts.map +1 -1
- package/dist/handlers/element-crud/createElement.js +6 -2
- package/dist/handlers/element-crud/editElement.d.ts.map +1 -1
- package/dist/handlers/element-crud/editElement.js +6 -2
- package/dist/handlers/element-crud/helpers.d.ts +2 -0
- package/dist/handlers/element-crud/helpers.d.ts.map +1 -1
- package/dist/handlers/element-crud/helpers.js +21 -2
- package/dist/handlers/mcp-aql/IntrospectionResolver.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/IntrospectionResolver.js +34 -7
- package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts +1 -0
- package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/MCPAQLHandler.js +50 -14
- package/dist/handlers/mcp-aql/OperationSchema.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/OperationSchema.js +3 -2
- package/dist/handlers/mcp-aql/evaluatePermission.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/evaluatePermission.js +2 -1
- package/dist/handlers/mcp-aql/policies/ElementPolicies.d.ts +17 -1
- package/dist/handlers/mcp-aql/policies/ElementPolicies.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/policies/ElementPolicies.js +88 -4
- package/dist/handlers/strategies/AgentActivationStrategy.d.ts.map +1 -1
- package/dist/handlers/strategies/AgentActivationStrategy.js +5 -1
- package/dist/handlers/strategies/BaseActivationStrategy.d.ts +1 -0
- package/dist/handlers/strategies/BaseActivationStrategy.d.ts.map +1 -1
- package/dist/handlers/strategies/BaseActivationStrategy.js +15 -1
- package/dist/handlers/strategies/EnsembleActivationStrategy.d.ts.map +1 -1
- package/dist/handlers/strategies/EnsembleActivationStrategy.js +5 -1
- package/dist/handlers/strategies/MemoryActivationStrategy.d.ts.map +1 -1
- package/dist/handlers/strategies/MemoryActivationStrategy.js +5 -1
- package/dist/handlers/strategies/PersonaActivationStrategy.d.ts.map +1 -1
- package/dist/handlers/strategies/PersonaActivationStrategy.js +5 -1
- package/dist/handlers/strategies/SkillActivationStrategy.d.ts.map +1 -1
- package/dist/handlers/strategies/SkillActivationStrategy.js +5 -1
- package/dist/handlers/strategies/TemplateActivationStrategy.d.ts.map +1 -1
- package/dist/handlers/strategies/TemplateActivationStrategy.js +7 -2
- package/dist/persona/PersonaElement.js +2 -2
- package/dist/services/SerializationService.d.ts.map +1 -1
- package/dist/services/SerializationService.js +7 -1
- package/dist/types/elements/IElement.d.ts +9 -0
- package/dist/types/elements/IElement.d.ts.map +1 -1
- package/dist/types/elements/IElement.js +1 -1
- package/dist/utils/permissionHooks.d.ts +39 -3
- package/dist/utils/permissionHooks.d.ts.map +1 -1
- package/dist/utils/permissionHooks.js +651 -74
- package/dist/web/public/permissions.css +190 -2
- package/dist/web/public/permissions.js +209 -56
- package/dist/web/public/setup.js +452 -108
- package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
- package/dist/web/routes/permissionRoutes.js +108 -17
- package/dist/web/routes/setupRoutes.d.ts +1 -0
- package/dist/web/routes/setupRoutes.d.ts.map +1 -1
- package/dist/web/routes/setupRoutes.js +128 -42
- package/package.json +3 -1
- package/scripts/pretooluse-dollhouse.sh +39 -1
- package/scripts/pretooluse-vscode.sh +163 -0
- package/scripts/pretooluse-windsurf.sh +166 -4
- package/server.json +2 -2
|
@@ -355,9 +355,10 @@
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
.perm-feed--modal {
|
|
358
|
-
height:
|
|
358
|
+
height: 100%;
|
|
359
359
|
max-height: none;
|
|
360
360
|
min-height: 0;
|
|
361
|
+
overflow: auto;
|
|
361
362
|
}
|
|
362
363
|
|
|
363
364
|
.perm-feed-empty {
|
|
@@ -398,6 +399,16 @@
|
|
|
398
399
|
.perm-selected-grid {
|
|
399
400
|
grid-template-columns: 1fr;
|
|
400
401
|
}
|
|
402
|
+
|
|
403
|
+
.perm-audit-summary-row {
|
|
404
|
+
grid-template-columns: 1fr;
|
|
405
|
+
gap: 0.45rem;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.perm-audit-detail-row {
|
|
409
|
+
grid-template-columns: 1fr;
|
|
410
|
+
gap: 0.25rem;
|
|
411
|
+
}
|
|
401
412
|
}
|
|
402
413
|
|
|
403
414
|
.perm-feed-tool {
|
|
@@ -420,6 +431,133 @@
|
|
|
420
431
|
width: min(82rem, 100%);
|
|
421
432
|
}
|
|
422
433
|
|
|
434
|
+
.perm-audit-modal .modal-body {
|
|
435
|
+
display: flex;
|
|
436
|
+
min-height: 0;
|
|
437
|
+
padding: 0;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.perm-audit-modal .modal-meta {
|
|
441
|
+
row-gap: 0.35rem;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.perm-audit-modal .perm-feed--modal {
|
|
445
|
+
padding: 0.875rem 1rem 1rem;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.perm-audit-entry {
|
|
449
|
+
border: 1px solid var(--ink-100, #e2e8f0);
|
|
450
|
+
border-radius: 0.75rem;
|
|
451
|
+
background: var(--paper-strong, #fff);
|
|
452
|
+
margin-bottom: 0.75rem;
|
|
453
|
+
overflow: hidden;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.perm-audit-entry:last-child {
|
|
457
|
+
margin-bottom: 0;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.perm-audit-entry[open] {
|
|
461
|
+
box-shadow: 0 10px 24px color-mix(in srgb, var(--ink-900, #0f172a) 10%, transparent);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.perm-audit-summary-row {
|
|
465
|
+
display: grid;
|
|
466
|
+
grid-template-columns: minmax(6rem, auto) auto minmax(9rem, auto) minmax(0, 1fr);
|
|
467
|
+
gap: 0.75rem;
|
|
468
|
+
align-items: center;
|
|
469
|
+
padding: 0.875rem 1rem;
|
|
470
|
+
cursor: pointer;
|
|
471
|
+
list-style: none;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.perm-audit-summary-row::-webkit-details-marker {
|
|
475
|
+
display: none;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.perm-audit-summary-row:hover {
|
|
479
|
+
background: var(--ink-50, #f8fafc);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.perm-audit-time-group {
|
|
483
|
+
display: flex;
|
|
484
|
+
flex-direction: column;
|
|
485
|
+
gap: 0.15rem;
|
|
486
|
+
min-width: 0;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.perm-audit-time {
|
|
490
|
+
color: var(--ink-800, #1e293b);
|
|
491
|
+
font-size: 0.82rem;
|
|
492
|
+
font-weight: 700;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.perm-audit-date {
|
|
496
|
+
color: var(--ink-500, #64748b);
|
|
497
|
+
font-size: 0.72rem;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.perm-audit-tool {
|
|
501
|
+
color: var(--ink-800, #1e293b);
|
|
502
|
+
font-weight: 700;
|
|
503
|
+
min-width: 0;
|
|
504
|
+
overflow-wrap: anywhere;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.perm-audit-context {
|
|
508
|
+
color: var(--ink-600, #475569);
|
|
509
|
+
min-width: 0;
|
|
510
|
+
overflow-wrap: anywhere;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.perm-audit-entry-body {
|
|
514
|
+
border-top: 1px solid var(--ink-100, #e2e8f0);
|
|
515
|
+
padding: 0.95rem 1rem 1rem;
|
|
516
|
+
background: color-mix(in srgb, var(--paper-base, #f8fafc) 82%, white);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.perm-audit-reason-block {
|
|
520
|
+
margin-bottom: 0.85rem;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.perm-audit-reason-text {
|
|
524
|
+
margin: 0.3rem 0 0;
|
|
525
|
+
color: var(--ink-700, #334155);
|
|
526
|
+
line-height: 1.55;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.perm-audit-detail-list {
|
|
530
|
+
display: grid;
|
|
531
|
+
gap: 0.625rem;
|
|
532
|
+
margin: 0;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.perm-audit-detail-row {
|
|
536
|
+
display: grid;
|
|
537
|
+
grid-template-columns: minmax(8rem, 11rem) minmax(0, 1fr);
|
|
538
|
+
gap: 0.75rem;
|
|
539
|
+
align-items: start;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.perm-audit-meta-label {
|
|
543
|
+
color: var(--ink-500, #64748b);
|
|
544
|
+
font-family: var(--font-mono, 'IBM Plex Mono', monospace);
|
|
545
|
+
font-size: 0.74rem;
|
|
546
|
+
text-transform: uppercase;
|
|
547
|
+
letter-spacing: 0.05em;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.perm-audit-meta-value {
|
|
551
|
+
margin: 0;
|
|
552
|
+
color: var(--ink-800, #1e293b);
|
|
553
|
+
overflow-wrap: anywhere;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.perm-audit-detail-value--mono {
|
|
557
|
+
font-family: var(--font-mono, 'IBM Plex Mono', monospace);
|
|
558
|
+
font-size: 0.82rem;
|
|
559
|
+
}
|
|
560
|
+
|
|
423
561
|
/* ── Source Elements ───────────────────────────────────────── */
|
|
424
562
|
|
|
425
563
|
.perm-source-list {
|
|
@@ -464,6 +602,29 @@
|
|
|
464
602
|
overflow-wrap: anywhere;
|
|
465
603
|
}
|
|
466
604
|
|
|
605
|
+
.perm-source-warning {
|
|
606
|
+
display: inline-flex;
|
|
607
|
+
align-items: center;
|
|
608
|
+
padding: 0.125rem 0.375rem;
|
|
609
|
+
border-radius: 999px;
|
|
610
|
+
background: color-mix(in srgb, #f59e0b 16%, white);
|
|
611
|
+
color: #431407;
|
|
612
|
+
font-size: 0.6875rem;
|
|
613
|
+
font-weight: 700;
|
|
614
|
+
text-transform: uppercase;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
.perm-inline-warning {
|
|
618
|
+
margin-top: 0.5rem;
|
|
619
|
+
padding: 0.625rem 0.75rem;
|
|
620
|
+
border: 1px solid color-mix(in srgb, #f59e0b 35%, white);
|
|
621
|
+
border-radius: 0.75rem;
|
|
622
|
+
background: color-mix(in srgb, #f59e0b 10%, white);
|
|
623
|
+
color: #431407;
|
|
624
|
+
font-size: 0.8125rem;
|
|
625
|
+
line-height: 1.45;
|
|
626
|
+
}
|
|
627
|
+
|
|
467
628
|
/* ── Dark Mode ─────────────────────────────────────────────── */
|
|
468
629
|
|
|
469
630
|
[data-theme="dark"] .perm-status-bar,
|
|
@@ -527,7 +688,10 @@
|
|
|
527
688
|
[data-theme="dark"] .perm-selected-title,
|
|
528
689
|
[data-theme="dark"] .perm-feed-tool,
|
|
529
690
|
[data-theme="dark"] .perm-pattern-text,
|
|
530
|
-
[data-theme="dark"] .perm-source-name
|
|
691
|
+
[data-theme="dark"] .perm-source-name,
|
|
692
|
+
[data-theme="dark"] .perm-audit-time,
|
|
693
|
+
[data-theme="dark"] .perm-audit-tool,
|
|
694
|
+
[data-theme="dark"] .perm-audit-meta-value {
|
|
531
695
|
color: var(--ink-200, #e2e8f0);
|
|
532
696
|
}
|
|
533
697
|
|
|
@@ -537,6 +701,20 @@
|
|
|
537
701
|
background: color-mix(in srgb, var(--paper) 36%, var(--surface-1));
|
|
538
702
|
}
|
|
539
703
|
|
|
704
|
+
[data-theme="dark"] .perm-audit-entry {
|
|
705
|
+
background: color-mix(in srgb, var(--paper) 22%, var(--surface-1));
|
|
706
|
+
border-color: color-mix(in srgb, var(--line) 88%, transparent);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
[data-theme="dark"] .perm-audit-summary-row:hover {
|
|
710
|
+
background: color-mix(in srgb, var(--surface-2) 72%, var(--paper-strong));
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
[data-theme="dark"] .perm-audit-entry-body {
|
|
714
|
+
background: color-mix(in srgb, var(--surface-1) 82%, var(--paper-strong));
|
|
715
|
+
border-color: color-mix(in srgb, var(--line) 92%, transparent);
|
|
716
|
+
}
|
|
717
|
+
|
|
540
718
|
[data-theme="dark"] .perm-source-item,
|
|
541
719
|
[data-theme="dark"] .perm-pattern-item,
|
|
542
720
|
[data-theme="dark"] .perm-feed-row {
|
|
@@ -548,6 +726,16 @@
|
|
|
548
726
|
background: color-mix(in srgb, var(--surface-2) 72%, var(--paper-strong));
|
|
549
727
|
}
|
|
550
728
|
|
|
729
|
+
[data-theme="dark"] .perm-audit-context,
|
|
730
|
+
[data-theme="dark"] .perm-audit-reason-text {
|
|
731
|
+
color: var(--ink-300, #cbd5e1);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
[data-theme="dark"] .perm-audit-date,
|
|
735
|
+
[data-theme="dark"] .perm-audit-meta-label {
|
|
736
|
+
color: var(--ink-500, #7b93a7);
|
|
737
|
+
}
|
|
738
|
+
|
|
551
739
|
[data-theme="dark"] .perm-source-type {
|
|
552
740
|
background: color-mix(in srgb, var(--surface-2) 90%, var(--paper-strong));
|
|
553
741
|
color: var(--ink-900, #dce6f2);
|
|
@@ -152,12 +152,18 @@
|
|
|
152
152
|
hasElements ? `${data.activeElementCount} elements` : 'No ensemble';
|
|
153
153
|
}
|
|
154
154
|
if (hookDot && hookLabel) {
|
|
155
|
-
const
|
|
155
|
+
const hasExternalRules = (data.denyPatterns?.length || 0)
|
|
156
156
|
+ (data.allowPatterns?.length || 0)
|
|
157
157
|
+ (data.confirmPatterns?.length || 0) > 0;
|
|
158
|
-
|
|
158
|
+
const hasAnyRules = (data.denyRules?.length || 0)
|
|
159
|
+
+ (data.allowRules?.length || 0)
|
|
160
|
+
+ (data.confirmRules?.length || 0) > 0;
|
|
161
|
+
if (!hasAnyRules) {
|
|
159
162
|
hookDot.dataset.status = 'inactive';
|
|
160
163
|
hookLabel.textContent = 'No policies';
|
|
164
|
+
} else if (!hasExternalRules) {
|
|
165
|
+
hookDot.dataset.status = 'active';
|
|
166
|
+
hookLabel.textContent = 'MCP-AQL policies active';
|
|
161
167
|
} else if (data.permissionPromptActive) {
|
|
162
168
|
hookDot.dataset.status = 'active';
|
|
163
169
|
hookLabel.textContent = 'Prompt tool active';
|
|
@@ -175,9 +181,9 @@
|
|
|
175
181
|
}
|
|
176
182
|
|
|
177
183
|
function renderSummaryStats(data) {
|
|
178
|
-
setText('perm-stat-deny-count',
|
|
179
|
-
setText('perm-stat-allow-count',
|
|
180
|
-
setText('perm-stat-confirm-count',
|
|
184
|
+
setText('perm-stat-deny-count', getAggregateRules(data, 'denyRules').length);
|
|
185
|
+
setText('perm-stat-allow-count', getAggregateRules(data, 'allowRules').length);
|
|
186
|
+
setText('perm-stat-confirm-count', getAggregateRules(data, 'confirmRules').length);
|
|
181
187
|
setText('perm-stat-decisions', data.recentDecisions?.length || 0);
|
|
182
188
|
|
|
183
189
|
// Decision breakdown
|
|
@@ -211,16 +217,14 @@
|
|
|
211
217
|
const selectedSessionId = selectedData?.sessionId;
|
|
212
218
|
if (elements.length === 0) {
|
|
213
219
|
list.innerHTML = '<li class="perm-pattern-empty">No active elements with policies</li>';
|
|
220
|
+
renderInvalidPolicySummary('perm-all-invalid-policy-summary', []);
|
|
214
221
|
return;
|
|
215
222
|
}
|
|
216
223
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
${el.description ? `<span style="color:var(--ink-400);font-size:0.75rem;margin-left:auto">${esc(el.description)}</span>` : ''}
|
|
222
|
-
</li>
|
|
223
|
-
`).join('');
|
|
224
|
+
renderInvalidPolicySummary('perm-all-invalid-policy-summary', elements);
|
|
225
|
+
list.innerHTML = elements.map(el =>
|
|
226
|
+
renderPolicySourceItem(el, elementMatchesSelected(el, selectedSessionId) ? ' perm-source-item--selected' : '')
|
|
227
|
+
).join('');
|
|
224
228
|
}
|
|
225
229
|
|
|
226
230
|
function renderSelectedSessionDetail(selectedData) {
|
|
@@ -261,31 +265,26 @@
|
|
|
261
265
|
}
|
|
262
266
|
|
|
263
267
|
const elements = selectedData.elements || [];
|
|
268
|
+
renderInvalidPolicySummary('perm-selected-invalid-policy-summary', elements);
|
|
264
269
|
sourceList.innerHTML = elements.length === 0
|
|
265
270
|
? '<li class="perm-pattern-empty">No policy-bearing elements found for this session</li>'
|
|
266
|
-
: elements.map(el =>
|
|
267
|
-
<li class="perm-source-item perm-source-item--detail">
|
|
268
|
-
<span class="perm-source-type">${esc(el.type)}</span>
|
|
269
|
-
<span class="perm-source-name">${esc(el.element_name || el.name || '')}</span>
|
|
270
|
-
${el.description ? `<span style="color:var(--ink-400);font-size:0.75rem;margin-left:auto">${esc(el.description)}</span>` : ''}
|
|
271
|
-
</li>
|
|
272
|
-
`).join('');
|
|
271
|
+
: elements.map(el => renderPolicySourceItem(el, ' perm-source-item--detail')).join('');
|
|
273
272
|
|
|
274
|
-
renderPatternList('perm-selected-deny-list', selectedData.
|
|
275
|
-
renderPatternList('perm-selected-allow-list', selectedData.
|
|
276
|
-
renderPatternList('perm-selected-confirm-list', selectedData.
|
|
273
|
+
renderPatternList('perm-selected-deny-list', selectedData.denyRules || [], 'deny');
|
|
274
|
+
renderPatternList('perm-selected-allow-list', selectedData.allowRules || [], 'allow');
|
|
275
|
+
renderPatternList('perm-selected-confirm-list', selectedData.confirmRules || [], 'confirm');
|
|
277
276
|
}
|
|
278
277
|
|
|
279
278
|
function renderDenyPatterns(data) {
|
|
280
|
-
renderPatternList('perm-deny-list',
|
|
279
|
+
renderPatternList('perm-deny-list', getAggregateRules(data, 'denyRules'), 'deny');
|
|
281
280
|
}
|
|
282
281
|
|
|
283
282
|
function renderAllowPatterns(data) {
|
|
284
|
-
renderPatternList('perm-allow-list',
|
|
283
|
+
renderPatternList('perm-allow-list', getAggregateRules(data, 'allowRules'), 'allow');
|
|
285
284
|
}
|
|
286
285
|
|
|
287
286
|
function renderConfirmPatterns(data) {
|
|
288
|
-
renderPatternList('perm-confirm-list',
|
|
287
|
+
renderPatternList('perm-confirm-list', getAggregateRules(data, 'confirmRules'), 'confirm');
|
|
289
288
|
}
|
|
290
289
|
|
|
291
290
|
function renderPatternList(elementId, patterns, type) {
|
|
@@ -293,7 +292,7 @@
|
|
|
293
292
|
if (!list) return;
|
|
294
293
|
|
|
295
294
|
if (patterns.length === 0) {
|
|
296
|
-
list.innerHTML = `<li class="perm-pattern-empty">No ${type}
|
|
295
|
+
list.innerHTML = `<li class="perm-pattern-empty">No ${type} rules active</li>`;
|
|
297
296
|
return;
|
|
298
297
|
}
|
|
299
298
|
|
|
@@ -325,29 +324,152 @@
|
|
|
325
324
|
if (latestId === lastDecisionId) return; // no change
|
|
326
325
|
lastDecisionId = latestId;
|
|
327
326
|
|
|
328
|
-
const html = decisions.map(
|
|
329
|
-
const time = new Date(d.timestamp).toLocaleTimeString();
|
|
330
|
-
const toolDisplay = d.tool_name === 'Bash'
|
|
331
|
-
? `Bash: ${esc(truncate(d.command || '', 60))}`
|
|
332
|
-
: esc(d.tool_name);
|
|
333
|
-
|
|
334
|
-
return `
|
|
335
|
-
<div class="perm-feed-row">
|
|
336
|
-
<span class="perm-feed-time">${time}</span>
|
|
337
|
-
<span class="perm-feed-decision perm-feed-decision--${d.decision}">${d.decision.toUpperCase()}</span>
|
|
338
|
-
<span class="perm-feed-tool" title="${esc(d.command || d.tool_name)}">${toolDisplay}</span>
|
|
339
|
-
<span class="perm-feed-reason" title="${esc(d.reason || '')}">${esc(d.reason || '')}</span>
|
|
340
|
-
</div>
|
|
341
|
-
`;
|
|
342
|
-
}).join('');
|
|
327
|
+
const html = decisions.map(renderCompactDecisionRow).join('');
|
|
343
328
|
|
|
344
329
|
feed.innerHTML = html;
|
|
345
|
-
if (modalFeed) modalFeed.innerHTML =
|
|
330
|
+
if (modalFeed) modalFeed.innerHTML = renderAuditModal(decisions);
|
|
346
331
|
if (modalCount) {
|
|
347
332
|
modalCount.textContent = `${decisions.length} captured ${decisions.length === 1 ? 'entry' : 'entries'}`;
|
|
348
333
|
}
|
|
349
334
|
}
|
|
350
335
|
|
|
336
|
+
function renderCompactDecisionRow(decision) {
|
|
337
|
+
const toolDisplay = decision.tool_name === 'Bash'
|
|
338
|
+
? `Bash: ${esc(truncate(decision.command || '', 60))}`
|
|
339
|
+
: esc(decision.tool_name);
|
|
340
|
+
|
|
341
|
+
return `
|
|
342
|
+
<div class="perm-feed-row">
|
|
343
|
+
<span class="perm-feed-time">${esc(formatShortTime(decision.timestamp))}</span>
|
|
344
|
+
<span class="perm-feed-decision perm-feed-decision--${decision.decision}">${esc(getDecisionLabel(decision.decision))}</span>
|
|
345
|
+
<span class="perm-feed-tool" title="${esc(decision.command || decision.tool_name)}">${toolDisplay}</span>
|
|
346
|
+
<span class="perm-feed-reason" title="${esc(decision.reason || '')}">${esc(decision.reason || '')}</span>
|
|
347
|
+
</div>
|
|
348
|
+
`;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function renderAuditModal(decisions) {
|
|
352
|
+
if (!decisions || decisions.length === 0) {
|
|
353
|
+
return '<div class="perm-feed-empty">No permission decisions yet. Waiting for tool calls...</div>';
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return decisions.map(renderAuditDecisionEntry).join('');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function renderAuditDecisionEntry(decision) {
|
|
360
|
+
const compactContext = getCompactContext(decision);
|
|
361
|
+
const detailRows = Array.isArray(decision.details) ? decision.details : [];
|
|
362
|
+
const reasonBlock = decision.reason
|
|
363
|
+
? `
|
|
364
|
+
<div class="perm-audit-reason-block">
|
|
365
|
+
<div class="perm-audit-meta-label">Reason</div>
|
|
366
|
+
<p class="perm-audit-reason-text">${esc(decision.reason)}</p>
|
|
367
|
+
</div>
|
|
368
|
+
`
|
|
369
|
+
: '';
|
|
370
|
+
const detailList = detailRows.length > 0
|
|
371
|
+
? `
|
|
372
|
+
<dl class="perm-audit-detail-list">
|
|
373
|
+
${detailRows.map(detail => `
|
|
374
|
+
<div class="perm-audit-detail-row">
|
|
375
|
+
<dt class="perm-audit-meta-label">${esc(detail.label)}</dt>
|
|
376
|
+
<dd class="perm-audit-meta-value${detail.monospace ? ' perm-audit-detail-value--mono' : ''}">${esc(detail.value)}</dd>
|
|
377
|
+
</div>
|
|
378
|
+
`).join('')}
|
|
379
|
+
<div class="perm-audit-detail-row">
|
|
380
|
+
<dt class="perm-audit-meta-label">Exact Time</dt>
|
|
381
|
+
<dd class="perm-audit-meta-value perm-audit-detail-value--mono">${esc(formatExactTimestamp(decision.timestamp))}</dd>
|
|
382
|
+
</div>
|
|
383
|
+
</dl>
|
|
384
|
+
`
|
|
385
|
+
: `
|
|
386
|
+
<dl class="perm-audit-detail-list">
|
|
387
|
+
<div class="perm-audit-detail-row">
|
|
388
|
+
<dt class="perm-audit-meta-label">Exact Time</dt>
|
|
389
|
+
<dd class="perm-audit-meta-value perm-audit-detail-value--mono">${esc(formatExactTimestamp(decision.timestamp))}</dd>
|
|
390
|
+
</div>
|
|
391
|
+
</dl>
|
|
392
|
+
`;
|
|
393
|
+
|
|
394
|
+
return `
|
|
395
|
+
<details class="perm-audit-entry">
|
|
396
|
+
<summary class="perm-audit-summary-row">
|
|
397
|
+
<span class="perm-audit-time-group">
|
|
398
|
+
<span class="perm-audit-time">${esc(formatShortTime(decision.timestamp))}</span>
|
|
399
|
+
<span class="perm-audit-date">${esc(formatShortDate(decision.timestamp))}</span>
|
|
400
|
+
</span>
|
|
401
|
+
<span class="perm-feed-decision perm-feed-decision--${decision.decision}">${esc(getDecisionLabel(decision.decision))}</span>
|
|
402
|
+
<span class="perm-audit-tool">${esc(decision.tool_name)}</span>
|
|
403
|
+
<span class="perm-audit-context">${esc(compactContext)}</span>
|
|
404
|
+
</summary>
|
|
405
|
+
<div class="perm-audit-entry-body">
|
|
406
|
+
${reasonBlock}
|
|
407
|
+
${detailList}
|
|
408
|
+
</div>
|
|
409
|
+
</details>
|
|
410
|
+
`;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function formatShortTime(timestamp) {
|
|
414
|
+
return new Date(timestamp).toLocaleTimeString([], {
|
|
415
|
+
hour: 'numeric',
|
|
416
|
+
minute: '2-digit',
|
|
417
|
+
second: '2-digit',
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function formatShortDate(timestamp) {
|
|
422
|
+
return new Date(timestamp).toLocaleDateString([], {
|
|
423
|
+
month: 'short',
|
|
424
|
+
day: 'numeric',
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function formatExactTimestamp(timestamp) {
|
|
429
|
+
const date = new Date(timestamp);
|
|
430
|
+
return date.toLocaleString([], {
|
|
431
|
+
year: 'numeric',
|
|
432
|
+
month: 'short',
|
|
433
|
+
day: 'numeric',
|
|
434
|
+
hour: 'numeric',
|
|
435
|
+
minute: '2-digit',
|
|
436
|
+
second: '2-digit',
|
|
437
|
+
timeZoneName: 'short',
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function getDecisionLabel(decision) {
|
|
442
|
+
return String(decision || '').toUpperCase();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function getCompactContext(decision) {
|
|
446
|
+
if (decision.targetLabel && decision.target) {
|
|
447
|
+
return `${decision.targetLabel}: ${truncate(decision.target, 96)}`;
|
|
448
|
+
}
|
|
449
|
+
if (decision.command) {
|
|
450
|
+
return truncate(decision.command, 96);
|
|
451
|
+
}
|
|
452
|
+
return decision.reason || 'No extra context captured';
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function renderPolicySourceItem(el, extraClass = '') {
|
|
456
|
+
const invalidBadge = el.invalidGatekeeperPolicy
|
|
457
|
+
? `<span class="perm-source-warning" title="${esc(el.invalidGatekeeperMessage || '')}">policy invalid</span>`
|
|
458
|
+
: '';
|
|
459
|
+
const description = el.description
|
|
460
|
+
? `<span style="color:var(--ink-400);font-size:0.75rem;margin-left:auto">${esc(el.description)}</span>`
|
|
461
|
+
: '';
|
|
462
|
+
|
|
463
|
+
return `
|
|
464
|
+
<li class="perm-source-item${extraClass}">
|
|
465
|
+
<span class="perm-source-type">${esc(el.type)}</span>
|
|
466
|
+
<span class="perm-source-name">${esc(el.element_name || el.name || '')}</span>
|
|
467
|
+
${invalidBadge}
|
|
468
|
+
${description}
|
|
469
|
+
</li>
|
|
470
|
+
`;
|
|
471
|
+
}
|
|
472
|
+
|
|
351
473
|
function deriveSelectedSessionData(aggregateData, sessionId) {
|
|
352
474
|
if (!sessionId) return null;
|
|
353
475
|
|
|
@@ -359,16 +481,18 @@
|
|
|
359
481
|
sessionId: sessionId,
|
|
360
482
|
activeElementCount: elements.length,
|
|
361
483
|
hasAllowlist: elements.some(function (element) {
|
|
362
|
-
return Array.isArray(element.
|
|
484
|
+
return Array.isArray(element.allowRules) && element.allowRules.length > 0;
|
|
363
485
|
}),
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
486
|
+
denyRules: flattenElementPatterns(elements, 'denyRules'),
|
|
487
|
+
allowRules: flattenElementPatterns(elements, 'allowRules'),
|
|
488
|
+
confirmRules: flattenElementPatterns(elements, 'confirmRules'),
|
|
367
489
|
elements: elements.map(function (element) {
|
|
368
490
|
return {
|
|
369
491
|
type: element.type,
|
|
370
492
|
element_name: element.element_name,
|
|
371
493
|
description: element.description,
|
|
494
|
+
invalidGatekeeperPolicy: !!element.invalidGatekeeperPolicy,
|
|
495
|
+
invalidGatekeeperMessage: element.invalidGatekeeperMessage,
|
|
372
496
|
};
|
|
373
497
|
}),
|
|
374
498
|
permissionPromptActive: !!aggregateData?.permissionPromptActive,
|
|
@@ -388,6 +512,12 @@
|
|
|
388
512
|
return Array.from(new Set(combined.concat(perElement)));
|
|
389
513
|
}
|
|
390
514
|
|
|
515
|
+
function getAggregateRules(data, key) {
|
|
516
|
+
const combined = Array.isArray(data && data[key]) ? data[key] : [];
|
|
517
|
+
const perElement = flattenElementPatterns((data && data.elements) || [], key);
|
|
518
|
+
return Array.from(new Set(combined.concat(perElement)));
|
|
519
|
+
}
|
|
520
|
+
|
|
391
521
|
// ── Dashboard HTML ─────────────────────────────────────────
|
|
392
522
|
|
|
393
523
|
function buildDashboardHTML() {
|
|
@@ -448,15 +578,15 @@
|
|
|
448
578
|
<div class="perm-stat-grid">
|
|
449
579
|
<div class="perm-stat">
|
|
450
580
|
<div class="perm-stat-value perm-stat-value--deny" id="perm-stat-deny-count">0</div>
|
|
451
|
-
<div class="perm-stat-label">Deny
|
|
581
|
+
<div class="perm-stat-label">Deny Rules</div>
|
|
452
582
|
</div>
|
|
453
583
|
<div class="perm-stat">
|
|
454
584
|
<div class="perm-stat-value perm-stat-value--allow" id="perm-stat-allow-count">0</div>
|
|
455
|
-
<div class="perm-stat-label">Allow
|
|
585
|
+
<div class="perm-stat-label">Allow Rules</div>
|
|
456
586
|
</div>
|
|
457
587
|
<div class="perm-stat">
|
|
458
588
|
<div class="perm-stat-value perm-stat-value--ask" id="perm-stat-confirm-count">0</div>
|
|
459
|
-
<div class="perm-stat-label">Confirm
|
|
589
|
+
<div class="perm-stat-label">Confirm Rules</div>
|
|
460
590
|
</div>
|
|
461
591
|
<div class="perm-stat">
|
|
462
592
|
<div class="perm-stat-value" id="perm-stat-decisions">0</div>
|
|
@@ -489,6 +619,7 @@
|
|
|
489
619
|
<div>
|
|
490
620
|
<div class="perm-selected-title" id="perm-selected-title">Selected Session</div>
|
|
491
621
|
<div class="perm-selected-subtitle" id="perm-selected-subtitle"></div>
|
|
622
|
+
<div class="perm-inline-warning" id="perm-selected-invalid-policy-summary" hidden></div>
|
|
492
623
|
</div>
|
|
493
624
|
<span class="perm-selected-badge" id="perm-selected-badge" hidden>Persisted Policy State (Debug Info)</span>
|
|
494
625
|
</div>
|
|
@@ -501,19 +632,19 @@
|
|
|
501
632
|
</ul>
|
|
502
633
|
</div>
|
|
503
634
|
<div class="perm-selected-panel">
|
|
504
|
-
<h4 class="perm-selected-panel-title">Deny
|
|
635
|
+
<h4 class="perm-selected-panel-title">Deny Rules</h4>
|
|
505
636
|
<ul class="perm-pattern-list" id="perm-selected-deny-list">
|
|
506
637
|
<li class="perm-pattern-empty">Loading...</li>
|
|
507
638
|
</ul>
|
|
508
639
|
</div>
|
|
509
640
|
<div class="perm-selected-panel">
|
|
510
|
-
<h4 class="perm-selected-panel-title">Allow
|
|
641
|
+
<h4 class="perm-selected-panel-title">Allow Rules</h4>
|
|
511
642
|
<ul class="perm-pattern-list" id="perm-selected-allow-list">
|
|
512
643
|
<li class="perm-pattern-empty">Loading...</li>
|
|
513
644
|
</ul>
|
|
514
645
|
</div>
|
|
515
646
|
<div class="perm-selected-panel">
|
|
516
|
-
<h4 class="perm-selected-panel-title">Confirm
|
|
647
|
+
<h4 class="perm-selected-panel-title">Confirm Rules</h4>
|
|
517
648
|
<ul class="perm-pattern-list" id="perm-selected-confirm-list">
|
|
518
649
|
<li class="perm-pattern-empty">Loading...</li>
|
|
519
650
|
</ul>
|
|
@@ -531,7 +662,8 @@
|
|
|
531
662
|
<div class="perm-selected-header perm-selected-header--compact">
|
|
532
663
|
<div>
|
|
533
664
|
<div class="perm-selected-title">All Sessions</div>
|
|
534
|
-
<div class="perm-selected-subtitle">${esc('Aggregate policy state across all live and persisted sessions.
|
|
665
|
+
<div class="perm-selected-subtitle">${esc('Aggregate policy state across all live and persisted sessions. Rules shown here include both Dollhouse operation policies and external tool restrictions.')}${dataAdvisoryPlaceholder()}</div>
|
|
666
|
+
<div class="perm-inline-warning" id="perm-all-invalid-policy-summary" hidden></div>
|
|
535
667
|
</div>
|
|
536
668
|
</div>
|
|
537
669
|
|
|
@@ -543,19 +675,19 @@
|
|
|
543
675
|
</ul>
|
|
544
676
|
</div>
|
|
545
677
|
<div class="perm-selected-panel">
|
|
546
|
-
<h4 class="perm-selected-panel-title">Deny
|
|
678
|
+
<h4 class="perm-selected-panel-title">Deny Rules</h4>
|
|
547
679
|
<ul class="perm-pattern-list" id="perm-deny-list">
|
|
548
680
|
<li class="perm-pattern-empty">Loading...</li>
|
|
549
681
|
</ul>
|
|
550
682
|
</div>
|
|
551
683
|
<div class="perm-selected-panel">
|
|
552
|
-
<h4 class="perm-selected-panel-title">Allow
|
|
684
|
+
<h4 class="perm-selected-panel-title">Allow Rules</h4>
|
|
553
685
|
<ul class="perm-pattern-list" id="perm-allow-list">
|
|
554
686
|
<li class="perm-pattern-empty">Loading...</li>
|
|
555
687
|
</ul>
|
|
556
688
|
</div>
|
|
557
689
|
<div class="perm-selected-panel">
|
|
558
|
-
<h4 class="perm-selected-panel-title">Confirm
|
|
690
|
+
<h4 class="perm-selected-panel-title">Confirm Rules</h4>
|
|
559
691
|
<ul class="perm-pattern-list" id="perm-confirm-list">
|
|
560
692
|
<li class="perm-pattern-empty">Loading...</li>
|
|
561
693
|
</ul>
|
|
@@ -685,4 +817,25 @@
|
|
|
685
817
|
return '<span id="perm-all-sessions-advisory" class="perm-inline-advisory" hidden></span>';
|
|
686
818
|
}
|
|
687
819
|
|
|
820
|
+
function renderInvalidPolicySummary(elementId, elements) {
|
|
821
|
+
const banner = document.getElementById(elementId);
|
|
822
|
+
if (!banner) return;
|
|
823
|
+
|
|
824
|
+
const invalid = (elements || []).filter(function (element) {
|
|
825
|
+
return !!element.invalidGatekeeperPolicy;
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
if (invalid.length === 0) {
|
|
829
|
+
banner.hidden = true;
|
|
830
|
+
banner.textContent = '';
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
const names = invalid.map(function (element) {
|
|
835
|
+
return element.element_name || element.name || 'unknown';
|
|
836
|
+
});
|
|
837
|
+
banner.hidden = false;
|
|
838
|
+
banner.textContent = `${invalid.length} active element${invalid.length === 1 ? '' : 's'} ha${invalid.length === 1 ? 's' : 've'} malformed gatekeeper policy. These elements remain active, but that policy is not being enforced: ${names.join(', ')}`;
|
|
839
|
+
}
|
|
840
|
+
|
|
688
841
|
})();
|