@dollhousemcp/mcp-server 2.0.17 → 2.0.19
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 +10 -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/ElementFileOperations.js +2 -2
- package/dist/elements/ensembles/EnsembleManager.js +3 -3
- package/dist/elements/memories/MemoryManager.js +2 -2
- 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 +30 -0
- package/dist/handlers/ElementCRUDHandler.d.ts.map +1 -1
- package/dist/handlers/ElementCRUDHandler.js +142 -2
- package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts +4 -0
- package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/MCPAQLHandler.js +132 -14
- package/dist/handlers/mcp-aql/OperationRouter.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/OperationRouter.js +6 -1
- package/dist/handlers/mcp-aql/OperationSchema.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/OperationSchema.js +17 -1
- package/dist/handlers/mcp-aql/policies/AgentToolPolicyTranslator.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/policies/AgentToolPolicyTranslator.js +2 -1
- package/dist/handlers/mcp-aql/policies/ElementPolicies.d.ts +9 -1
- package/dist/handlers/mcp-aql/policies/ElementPolicies.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/policies/ElementPolicies.js +64 -4
- package/dist/handlers/mcp-aql/policies/OperationPolicies.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/policies/OperationPolicies.js +6 -1
- package/dist/handlers/mcp-aql/policies/ToolClassification.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/policies/ToolClassification.js +2 -1
- 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/server/tools/MCPAQLTools.js +2 -1
- 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/web/console/IngestRoutes.d.ts +6 -0
- package/dist/web/console/IngestRoutes.d.ts.map +1 -1
- package/dist/web/console/IngestRoutes.js +38 -9
- package/dist/web/console/LeaderElection.d.ts +39 -0
- package/dist/web/console/LeaderElection.d.ts.map +1 -1
- package/dist/web/console/LeaderElection.js +147 -29
- package/dist/web/console/LeaderForwardingSink.d.ts.map +1 -1
- package/dist/web/console/LeaderForwardingSink.js +5 -1
- package/dist/web/console/PromotionManager.d.ts.map +1 -1
- package/dist/web/console/PromotionManager.js +3 -11
- package/dist/web/public/app.js +62 -1
- package/dist/web/public/index.html +19 -17
- package/dist/web/public/permissions.css +190 -2
- package/dist/web/public/permissions.js +171 -30
- package/dist/web/public/sessions.js +111 -0
- package/dist/web/public/setup.js +131 -60
- package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
- package/dist/web/routes/permissionRoutes.js +77 -5
- package/dist/web/routes/setupRoutes.d.ts.map +1 -1
- package/dist/web/routes/setupRoutes.js +16 -2
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +12 -10
- package/package.json +1 -1
- package/scripts/pretooluse-dollhouse.sh +39 -1
- package/server.json +2 -2
package/dist/web/public/app.js
CHANGED
|
@@ -1978,12 +1978,70 @@ globalThis.DollhouseConsoleUI.clearBanner = function(bannerId) {
|
|
|
1978
1978
|
|
|
1979
1979
|
const TAB_KEY = 'dollhousemcp-active-tab';
|
|
1980
1980
|
const SETUP_SEEN_KEY = 'dollhousemcp-setup-seen';
|
|
1981
|
+
const FORCED_RELOAD_KEY = 'dollhousemcp-last-forced-reload';
|
|
1981
1982
|
// Server version injected at request time — used to show Setup tab once per version
|
|
1982
1983
|
// so upgraders automatically see it on each new release (not just first-ever visit).
|
|
1983
1984
|
// Validate format (semver-like) before trusting the value; malformed falls back to
|
|
1984
1985
|
// 'unknown' which safely triggers setup on every load rather than silently skipping.
|
|
1985
1986
|
const _rawVersion = document.querySelector('meta[name="dollhouse-server-version"]')?.content || '';
|
|
1986
1987
|
const currentServerVersion = /^\d+\.\d+\.\d+/.test(_rawVersion) ? _rawVersion : 'unknown';
|
|
1988
|
+
const _rawAssetVersion = document.querySelector('meta[name="dollhouse-console-asset-version"]')?.content || '';
|
|
1989
|
+
const currentAssetVersion = /^\d+\.\d+\.\d+/.test(_rawAssetVersion) ? _rawAssetVersion : currentServerVersion;
|
|
1990
|
+
let forcedReloadInFlight = false;
|
|
1991
|
+
|
|
1992
|
+
function normalizeReloadVersion(version) {
|
|
1993
|
+
return typeof version === 'string' && /^\d+\.\d+\.\d+/.test(version)
|
|
1994
|
+
? version
|
|
1995
|
+
: (currentAssetVersion || currentServerVersion || 'unknown');
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
function shouldThrottleForcedReload(targetVersion) {
|
|
1999
|
+
try {
|
|
2000
|
+
const raw = sessionStorage.getItem(FORCED_RELOAD_KEY);
|
|
2001
|
+
if (!raw) return false;
|
|
2002
|
+
const parsed = JSON.parse(raw);
|
|
2003
|
+
return parsed
|
|
2004
|
+
&& parsed.version === targetVersion
|
|
2005
|
+
&& typeof parsed.at === 'number'
|
|
2006
|
+
&& Date.now() - parsed.at < 60_000;
|
|
2007
|
+
} catch {
|
|
2008
|
+
return false;
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
function rememberForcedReload(targetVersion, reason) {
|
|
2013
|
+
try {
|
|
2014
|
+
sessionStorage.setItem(FORCED_RELOAD_KEY, JSON.stringify({
|
|
2015
|
+
version: targetVersion,
|
|
2016
|
+
reason: reason || 'manual',
|
|
2017
|
+
at: Date.now(),
|
|
2018
|
+
}));
|
|
2019
|
+
} catch {
|
|
2020
|
+
// Ignore storage failures — reload still proceeds.
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
function buildCacheBustedConsoleUrl(targetVersion, reason) {
|
|
2025
|
+
const url = new URL(globalThis.location.href);
|
|
2026
|
+
url.searchParams.set('dollhouse_bust', targetVersion + '-' + Date.now());
|
|
2027
|
+
url.searchParams.set('dollhouse_asset_version', targetVersion);
|
|
2028
|
+
if (reason) {
|
|
2029
|
+
url.searchParams.set('dollhouse_reload_reason', reason);
|
|
2030
|
+
}
|
|
2031
|
+
return url.toString();
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
function forceConsoleReload(reason, targetVersion) {
|
|
2035
|
+
const normalizedTargetVersion = normalizeReloadVersion(targetVersion);
|
|
2036
|
+
if (forcedReloadInFlight || shouldThrottleForcedReload(normalizedTargetVersion)) {
|
|
2037
|
+
return false;
|
|
2038
|
+
}
|
|
2039
|
+
forcedReloadInFlight = true;
|
|
2040
|
+
rememberForcedReload(normalizedTargetVersion, reason);
|
|
2041
|
+
const reloadUrl = buildCacheBustedConsoleUrl(normalizedTargetVersion, reason);
|
|
2042
|
+
globalThis.location.replace(reloadUrl);
|
|
2043
|
+
return true;
|
|
2044
|
+
}
|
|
1987
2045
|
|
|
1988
2046
|
// Determine which tab to show on load:
|
|
1989
2047
|
// 1. URL hash (deep link)
|
|
@@ -2022,6 +2080,9 @@ globalThis.DollhouseConsoleUI.clearBanner = function(bannerId) {
|
|
|
2022
2080
|
// Expose for other scripts (logs.js, metrics.js, permissions.js)
|
|
2023
2081
|
globalThis.DollhouseConsole = globalThis.DollhouseConsole || {};
|
|
2024
2082
|
globalThis.DollhouseConsole.getUrlParams = () => getTabAndParams().params;
|
|
2083
|
+
globalThis.DollhouseConsole.currentServerVersion = currentServerVersion;
|
|
2084
|
+
globalThis.DollhouseConsole.currentAssetVersion = currentAssetVersion;
|
|
2085
|
+
globalThis.DollhouseConsole.forceReload = forceConsoleReload;
|
|
2025
2086
|
|
|
2026
2087
|
/**
|
|
2027
2088
|
* Apply URL params to the portfolio tab.
|
|
@@ -2175,7 +2236,7 @@ globalThis.DollhouseConsoleUI.clearBanner = function(bannerId) {
|
|
|
2175
2236
|
toast.innerHTML = 'Console session token changed\u2009\u2014\u2009'
|
|
2176
2237
|
+ '<button style="background:#fff;color:#b91c1c;border:none;padding:6px 16px;'
|
|
2177
2238
|
+ 'border-radius:4px;cursor:pointer;font-weight:600;font-size:14px"'
|
|
2178
|
-
+ ' onclick="
|
|
2239
|
+
+ ' onclick="window.DollhouseConsole.forceReload(\'session-expired\')">Reload</button>';
|
|
2179
2240
|
document.body.appendChild(toast);
|
|
2180
2241
|
});
|
|
2181
2242
|
|
|
@@ -14,14 +14,16 @@
|
|
|
14
14
|
<meta name="dollhouse-console-token" content="{{CONSOLE_TOKEN}}">
|
|
15
15
|
<!-- Server version — injected at request time for version-aware UI behaviour (e.g. setup-seen per version). -->
|
|
16
16
|
<meta name="dollhouse-server-version" content="{{DOLLHOUSE_VERSION}}">
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
<link rel="stylesheet" href="
|
|
20
|
-
<link rel="stylesheet" href="
|
|
21
|
-
<link rel="stylesheet" href="
|
|
22
|
-
<link rel="stylesheet" href="
|
|
23
|
-
<link rel="stylesheet" href="
|
|
24
|
-
<link rel="stylesheet" href="
|
|
17
|
+
<!-- Asset version — injected at request time for cache-busting local CSS/JS/img files. -->
|
|
18
|
+
<meta name="dollhouse-console-asset-version" content="{{DOLLHOUSE_ASSET_VERSION}}">
|
|
19
|
+
<link rel="stylesheet" href="fonts.css?v={{DOLLHOUSE_ASSET_VERSION}}">
|
|
20
|
+
<link rel="stylesheet" href="styles.css?v={{DOLLHOUSE_ASSET_VERSION}}">
|
|
21
|
+
<link rel="stylesheet" href="logs.css?v={{DOLLHOUSE_ASSET_VERSION}}">
|
|
22
|
+
<link rel="stylesheet" href="metrics.css?v={{DOLLHOUSE_ASSET_VERSION}}">
|
|
23
|
+
<link rel="stylesheet" href="permissions.css?v={{DOLLHOUSE_ASSET_VERSION}}">
|
|
24
|
+
<link rel="stylesheet" href="sessions.css?v={{DOLLHOUSE_ASSET_VERSION}}">
|
|
25
|
+
<link rel="stylesheet" href="setup.css?v={{DOLLHOUSE_ASSET_VERSION}}">
|
|
26
|
+
<link rel="stylesheet" href="security.css?v={{DOLLHOUSE_ASSET_VERSION}}">
|
|
25
27
|
<!-- uPlot for metrics time-series charts -->
|
|
26
28
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uplot@1.6.30/dist/uPlot.min.css" integrity="sha384-IfV0B7MIOYuO95kO9G5ySKPz/85zqFNOAs8iy4tkK5zd9izhJAB8b7lHrwYqqmYE" crossorigin="anonymous">
|
|
27
29
|
</head>
|
|
@@ -31,7 +33,7 @@
|
|
|
31
33
|
|
|
32
34
|
<header class="site-header">
|
|
33
35
|
<div class="header-brand">
|
|
34
|
-
<img src="dollhouse-logo.png" alt="DollhouseMCP" class="header-logo" width="32" height="32">
|
|
36
|
+
<img src="dollhouse-logo.png?v={{DOLLHOUSE_ASSET_VERSION}}" alt="DollhouseMCP" class="header-logo" width="32" height="32">
|
|
35
37
|
<div class="header-brand-text">
|
|
36
38
|
<h1 class="site-title">DollhouseMCP</h1>
|
|
37
39
|
<p class="site-tagline">Management Console</p>
|
|
@@ -598,13 +600,13 @@ npm install @dollhousemcp/mcp-server</code></pre>
|
|
|
598
600
|
<script src="https://cdn.jsdelivr.net/npm/uplot@1.6.30/dist/uPlot.iife.min.js" integrity="sha384-1NEYi76CBpge3gahk4+X4M4JzdOV3WYq84RnByqYdAd5SdvJBTNCPFh/nsoHfN6i" crossorigin="anonymous"></script>
|
|
599
601
|
<!-- Console auth helper must load first — it reads the token meta tag and
|
|
600
602
|
exposes window.DollhouseAuth for all subsequent scripts (#1780). -->
|
|
601
|
-
<script src="consoleAuth.js"></script>
|
|
602
|
-
<script src="setup.js"></script>
|
|
603
|
-
<script src="app.js"></script>
|
|
604
|
-
<script src="logs.js"></script>
|
|
605
|
-
<script src="metrics.js"></script>
|
|
606
|
-
<script src="permissions.js"></script>
|
|
607
|
-
<script src="sessions.js"></script>
|
|
608
|
-
<script src="security.js"></script>
|
|
603
|
+
<script src="consoleAuth.js?v={{DOLLHOUSE_ASSET_VERSION}}"></script>
|
|
604
|
+
<script src="setup.js?v={{DOLLHOUSE_ASSET_VERSION}}"></script>
|
|
605
|
+
<script src="app.js?v={{DOLLHOUSE_ASSET_VERSION}}"></script>
|
|
606
|
+
<script src="logs.js?v={{DOLLHOUSE_ASSET_VERSION}}"></script>
|
|
607
|
+
<script src="metrics.js?v={{DOLLHOUSE_ASSET_VERSION}}"></script>
|
|
608
|
+
<script src="permissions.js?v={{DOLLHOUSE_ASSET_VERSION}}"></script>
|
|
609
|
+
<script src="sessions.js?v={{DOLLHOUSE_ASSET_VERSION}}"></script>
|
|
610
|
+
<script src="security.js?v={{DOLLHOUSE_ASSET_VERSION}}"></script>
|
|
609
611
|
</body>
|
|
610
612
|
</html>
|
|
@@ -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);
|
|
@@ -217,16 +217,14 @@
|
|
|
217
217
|
const selectedSessionId = selectedData?.sessionId;
|
|
218
218
|
if (elements.length === 0) {
|
|
219
219
|
list.innerHTML = '<li class="perm-pattern-empty">No active elements with policies</li>';
|
|
220
|
+
renderInvalidPolicySummary('perm-all-invalid-policy-summary', []);
|
|
220
221
|
return;
|
|
221
222
|
}
|
|
222
223
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
${el.description ? `<span style="color:var(--ink-400);font-size:0.75rem;margin-left:auto">${esc(el.description)}</span>` : ''}
|
|
228
|
-
</li>
|
|
229
|
-
`).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('');
|
|
230
228
|
}
|
|
231
229
|
|
|
232
230
|
function renderSelectedSessionDetail(selectedData) {
|
|
@@ -267,15 +265,10 @@
|
|
|
267
265
|
}
|
|
268
266
|
|
|
269
267
|
const elements = selectedData.elements || [];
|
|
268
|
+
renderInvalidPolicySummary('perm-selected-invalid-policy-summary', elements);
|
|
270
269
|
sourceList.innerHTML = elements.length === 0
|
|
271
270
|
? '<li class="perm-pattern-empty">No policy-bearing elements found for this session</li>'
|
|
272
|
-
: elements.map(el =>
|
|
273
|
-
<li class="perm-source-item perm-source-item--detail">
|
|
274
|
-
<span class="perm-source-type">${esc(el.type)}</span>
|
|
275
|
-
<span class="perm-source-name">${esc(el.element_name || el.name || '')}</span>
|
|
276
|
-
${el.description ? `<span style="color:var(--ink-400);font-size:0.75rem;margin-left:auto">${esc(el.description)}</span>` : ''}
|
|
277
|
-
</li>
|
|
278
|
-
`).join('');
|
|
271
|
+
: elements.map(el => renderPolicySourceItem(el, ' perm-source-item--detail')).join('');
|
|
279
272
|
|
|
280
273
|
renderPatternList('perm-selected-deny-list', selectedData.denyRules || [], 'deny');
|
|
281
274
|
renderPatternList('perm-selected-allow-list', selectedData.allowRules || [], 'allow');
|
|
@@ -331,29 +324,152 @@
|
|
|
331
324
|
if (latestId === lastDecisionId) return; // no change
|
|
332
325
|
lastDecisionId = latestId;
|
|
333
326
|
|
|
334
|
-
const html = decisions.map(
|
|
335
|
-
const time = new Date(d.timestamp).toLocaleTimeString();
|
|
336
|
-
const toolDisplay = d.tool_name === 'Bash'
|
|
337
|
-
? `Bash: ${esc(truncate(d.command || '', 60))}`
|
|
338
|
-
: esc(d.tool_name);
|
|
339
|
-
|
|
340
|
-
return `
|
|
341
|
-
<div class="perm-feed-row">
|
|
342
|
-
<span class="perm-feed-time">${time}</span>
|
|
343
|
-
<span class="perm-feed-decision perm-feed-decision--${d.decision}">${d.decision.toUpperCase()}</span>
|
|
344
|
-
<span class="perm-feed-tool" title="${esc(d.command || d.tool_name)}">${toolDisplay}</span>
|
|
345
|
-
<span class="perm-feed-reason" title="${esc(d.reason || '')}">${esc(d.reason || '')}</span>
|
|
346
|
-
</div>
|
|
347
|
-
`;
|
|
348
|
-
}).join('');
|
|
327
|
+
const html = decisions.map(renderCompactDecisionRow).join('');
|
|
349
328
|
|
|
350
329
|
feed.innerHTML = html;
|
|
351
|
-
if (modalFeed) modalFeed.innerHTML =
|
|
330
|
+
if (modalFeed) modalFeed.innerHTML = renderAuditModal(decisions);
|
|
352
331
|
if (modalCount) {
|
|
353
332
|
modalCount.textContent = `${decisions.length} captured ${decisions.length === 1 ? 'entry' : 'entries'}`;
|
|
354
333
|
}
|
|
355
334
|
}
|
|
356
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
|
+
|
|
357
473
|
function deriveSelectedSessionData(aggregateData, sessionId) {
|
|
358
474
|
if (!sessionId) return null;
|
|
359
475
|
|
|
@@ -375,6 +491,8 @@
|
|
|
375
491
|
type: element.type,
|
|
376
492
|
element_name: element.element_name,
|
|
377
493
|
description: element.description,
|
|
494
|
+
invalidGatekeeperPolicy: !!element.invalidGatekeeperPolicy,
|
|
495
|
+
invalidGatekeeperMessage: element.invalidGatekeeperMessage,
|
|
378
496
|
};
|
|
379
497
|
}),
|
|
380
498
|
permissionPromptActive: !!aggregateData?.permissionPromptActive,
|
|
@@ -501,6 +619,7 @@
|
|
|
501
619
|
<div>
|
|
502
620
|
<div class="perm-selected-title" id="perm-selected-title">Selected Session</div>
|
|
503
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>
|
|
504
623
|
</div>
|
|
505
624
|
<span class="perm-selected-badge" id="perm-selected-badge" hidden>Persisted Policy State (Debug Info)</span>
|
|
506
625
|
</div>
|
|
@@ -544,6 +663,7 @@
|
|
|
544
663
|
<div>
|
|
545
664
|
<div class="perm-selected-title">All Sessions</div>
|
|
546
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>
|
|
547
667
|
</div>
|
|
548
668
|
</div>
|
|
549
669
|
|
|
@@ -697,4 +817,25 @@
|
|
|
697
817
|
return '<span id="perm-all-sessions-advisory" class="perm-inline-advisory" hidden></span>';
|
|
698
818
|
}
|
|
699
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
|
+
|
|
700
841
|
})();
|