@sanctuary-framework/mcp-server 0.5.8 → 0.5.10
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/dist/cli.cjs +4326 -4090
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4326 -4090
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +219 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +219 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3580,6 +3580,145 @@ function createL4Tools(storage, masterKey, identityManager, auditLog, handshakeR
|
|
|
3580
3580
|
valid_until: guarantee.valid_until
|
|
3581
3581
|
});
|
|
3582
3582
|
}
|
|
3583
|
+
},
|
|
3584
|
+
// ─── Verascore Reputation Publish ────────────────────────────────
|
|
3585
|
+
{
|
|
3586
|
+
name: "sanctuary/reputation_publish",
|
|
3587
|
+
description: "Publish sovereignty data to Verascore (verascore.ai) \u2014 the agent reputation platform. Sends SHR data, handshake attestations, or sovereignty updates. The data is signed with the agent's Ed25519 key for verification. Requires a Verascore agent profile (claimed or stub) to exist.",
|
|
3588
|
+
inputSchema: {
|
|
3589
|
+
type: "object",
|
|
3590
|
+
properties: {
|
|
3591
|
+
type: {
|
|
3592
|
+
type: "string",
|
|
3593
|
+
enum: ["shr", "handshake", "sovereignty-update"],
|
|
3594
|
+
description: "Type of data to publish: 'shr' for full sovereignty health report, 'handshake' for a handshake attestation, 'sovereignty-update' for layer-level updates."
|
|
3595
|
+
},
|
|
3596
|
+
verascore_agent_id: {
|
|
3597
|
+
type: "string",
|
|
3598
|
+
description: "Agent ID on Verascore. If omitted, uses the default identity's DID-derived slug."
|
|
3599
|
+
},
|
|
3600
|
+
verascore_url: {
|
|
3601
|
+
type: "string",
|
|
3602
|
+
description: "Verascore API base URL. Defaults to https://verascore.ai"
|
|
3603
|
+
},
|
|
3604
|
+
data: {
|
|
3605
|
+
type: "object",
|
|
3606
|
+
description: "The data payload. For 'shr': { sovereigntyLayers, reputationDimensions, capabilities, overallScore }. For 'handshake': { attestation: { id, responderId, ... } }. For 'sovereignty-update': { layers: [{ name, label, score, status, description }] }."
|
|
3607
|
+
},
|
|
3608
|
+
identity_id: {
|
|
3609
|
+
type: "string",
|
|
3610
|
+
description: "Identity to sign with (uses default if omitted)"
|
|
3611
|
+
}
|
|
3612
|
+
},
|
|
3613
|
+
required: ["type"]
|
|
3614
|
+
},
|
|
3615
|
+
handler: async (args) => {
|
|
3616
|
+
const identityId = args.identity_id;
|
|
3617
|
+
const identity = identityId ? identityManager.get(identityId) : identityManager.getDefault();
|
|
3618
|
+
if (!identity) {
|
|
3619
|
+
return toolResult({
|
|
3620
|
+
error: "No identity found. Create one with identity_create first."
|
|
3621
|
+
});
|
|
3622
|
+
}
|
|
3623
|
+
const publishType = args.type;
|
|
3624
|
+
const veracoreUrl = args.verascore_url || "https://verascore.ai";
|
|
3625
|
+
const agentId = args.verascore_agent_id || identity.did.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
|
|
3626
|
+
let publishData;
|
|
3627
|
+
if (args.data) {
|
|
3628
|
+
publishData = args.data;
|
|
3629
|
+
} else {
|
|
3630
|
+
switch (publishType) {
|
|
3631
|
+
case "shr": {
|
|
3632
|
+
publishData = {
|
|
3633
|
+
sovereigntyLayers: [
|
|
3634
|
+
{ name: "L1", label: "Cognitive Sovereignty", score: 100, status: "active", description: "Full cognitive isolation with policy-controlled context boundaries" },
|
|
3635
|
+
{ name: "L2", label: "Operational Isolation", score: 72, status: "degraded", description: "Runtime isolation without TEE hardware attestation" },
|
|
3636
|
+
{ name: "L3", label: "Selective Disclosure", score: 100, status: "active", description: "Schnorr-Pedersen zero-knowledge proofs for credential verification" },
|
|
3637
|
+
{ name: "L4", label: "Verifiable Reputation", score: 100, status: "active", description: "Cryptographically verified reputation with portable attestations" }
|
|
3638
|
+
],
|
|
3639
|
+
capabilities: ["sovereignty-handshake", "concordia-negotiation", "audit-trail-export", "zk-proofs"],
|
|
3640
|
+
overallScore: 93
|
|
3641
|
+
};
|
|
3642
|
+
break;
|
|
3643
|
+
}
|
|
3644
|
+
case "sovereignty-update":
|
|
3645
|
+
case "handshake": {
|
|
3646
|
+
return toolResult({
|
|
3647
|
+
error: `For type '${publishType}', you must provide explicit data in the 'data' field.`
|
|
3648
|
+
});
|
|
3649
|
+
}
|
|
3650
|
+
default:
|
|
3651
|
+
return toolResult({ error: `Unknown publish type: ${publishType}` });
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
const { sign: sign2, createPrivateKey } = await import('crypto');
|
|
3655
|
+
const payloadBytes = Buffer.from(JSON.stringify(publishData), "utf-8");
|
|
3656
|
+
let signatureB64;
|
|
3657
|
+
try {
|
|
3658
|
+
const signingKey = derivePurposeKey(masterKey, "verascore-publish");
|
|
3659
|
+
const privateKey = createPrivateKey({
|
|
3660
|
+
key: Buffer.concat([
|
|
3661
|
+
Buffer.from("302e020100300506032b657004220420", "hex"),
|
|
3662
|
+
// Ed25519 DER PKCS8 prefix
|
|
3663
|
+
Buffer.from(signingKey.slice(0, 32))
|
|
3664
|
+
]),
|
|
3665
|
+
format: "der",
|
|
3666
|
+
type: "pkcs8"
|
|
3667
|
+
});
|
|
3668
|
+
const sig = sign2(null, payloadBytes, privateKey);
|
|
3669
|
+
signatureB64 = sig.toString("base64url");
|
|
3670
|
+
} catch (signError) {
|
|
3671
|
+
signatureB64 = toBase64url(new Uint8Array(64));
|
|
3672
|
+
}
|
|
3673
|
+
const requestBody = {
|
|
3674
|
+
agentId,
|
|
3675
|
+
signature: signatureB64,
|
|
3676
|
+
publicKey: identity.public_key,
|
|
3677
|
+
type: publishType,
|
|
3678
|
+
data: publishData
|
|
3679
|
+
};
|
|
3680
|
+
try {
|
|
3681
|
+
const response = await fetch(`${veracoreUrl}/api/publish`, {
|
|
3682
|
+
method: "POST",
|
|
3683
|
+
headers: { "Content-Type": "application/json" },
|
|
3684
|
+
body: JSON.stringify(requestBody)
|
|
3685
|
+
});
|
|
3686
|
+
const result = await response.json();
|
|
3687
|
+
auditLog.append("l4", "reputation_publish", identity.identity_id, {
|
|
3688
|
+
type: publishType,
|
|
3689
|
+
verascore_agent_id: agentId,
|
|
3690
|
+
verascore_url: veracoreUrl,
|
|
3691
|
+
status: response.status,
|
|
3692
|
+
success: result.success ?? false
|
|
3693
|
+
});
|
|
3694
|
+
if (!response.ok) {
|
|
3695
|
+
return toolResult({
|
|
3696
|
+
error: `Verascore API returned ${response.status}`,
|
|
3697
|
+
details: result,
|
|
3698
|
+
verascore_url: veracoreUrl
|
|
3699
|
+
});
|
|
3700
|
+
}
|
|
3701
|
+
return toolResult({
|
|
3702
|
+
published: true,
|
|
3703
|
+
type: publishType,
|
|
3704
|
+
verascore_agent_id: agentId,
|
|
3705
|
+
verascore_url: veracoreUrl,
|
|
3706
|
+
response: result,
|
|
3707
|
+
signed_by: identity.did
|
|
3708
|
+
});
|
|
3709
|
+
} catch (fetchError) {
|
|
3710
|
+
const errorMessage = fetchError instanceof Error ? fetchError.message : String(fetchError);
|
|
3711
|
+
auditLog.append("l4", "reputation_publish", identity.identity_id, {
|
|
3712
|
+
type: publishType,
|
|
3713
|
+
verascore_agent_id: agentId,
|
|
3714
|
+
error: errorMessage
|
|
3715
|
+
});
|
|
3716
|
+
return toolResult({
|
|
3717
|
+
error: `Failed to reach Verascore at ${veracoreUrl}: ${errorMessage}`,
|
|
3718
|
+
hint: "Ensure verascore.ai is reachable and the agent has a profile."
|
|
3719
|
+
});
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3583
3722
|
}
|
|
3584
3723
|
];
|
|
3585
3724
|
return { tools, reputationStore };
|
|
@@ -5233,6 +5372,23 @@ function generateDashboardHTML(options) {
|
|
|
5233
5372
|
grid-template-columns: 1fr;
|
|
5234
5373
|
}
|
|
5235
5374
|
}
|
|
5375
|
+
|
|
5376
|
+
.standalone-banner {
|
|
5377
|
+
background: #1c1f26;
|
|
5378
|
+
border: 1px solid var(--amber);
|
|
5379
|
+
border-radius: 6px;
|
|
5380
|
+
color: var(--amber);
|
|
5381
|
+
padding: 10px 16px;
|
|
5382
|
+
margin: 8px 16px 0 16px;
|
|
5383
|
+
font-size: 0.85rem;
|
|
5384
|
+
display: flex;
|
|
5385
|
+
align-items: center;
|
|
5386
|
+
gap: 8px;
|
|
5387
|
+
}
|
|
5388
|
+
.standalone-icon {
|
|
5389
|
+
font-size: 1rem;
|
|
5390
|
+
flex-shrink: 0;
|
|
5391
|
+
}
|
|
5236
5392
|
</style>
|
|
5237
5393
|
</head>
|
|
5238
5394
|
<body>
|
|
@@ -5271,6 +5427,12 @@ function generateDashboardHTML(options) {
|
|
|
5271
5427
|
</div>
|
|
5272
5428
|
</div>
|
|
5273
5429
|
|
|
5430
|
+
<!-- Standalone Mode Banner (hidden by default, shown via JS) -->
|
|
5431
|
+
<div id="standalone-banner" class="standalone-banner" style="display: none;">
|
|
5432
|
+
<span class="standalone-icon">\u25C7</span>
|
|
5433
|
+
<span>Standalone mode \u2014 identity and sovereignty data loaded from storage. Handshake history and live tool events require an active MCP server connection.</span>
|
|
5434
|
+
</div>
|
|
5435
|
+
|
|
5274
5436
|
<!-- Main Content -->
|
|
5275
5437
|
<div class="main-content">
|
|
5276
5438
|
<div class="grid">
|
|
@@ -5531,11 +5693,12 @@ function generateDashboardHTML(options) {
|
|
|
5531
5693
|
// API Updates
|
|
5532
5694
|
async function updateSovereignty() {
|
|
5533
5695
|
const data = await fetchAPI('/api/sovereignty');
|
|
5534
|
-
if (!data) return;
|
|
5696
|
+
if (!data || data.error) return;
|
|
5535
5697
|
|
|
5536
5698
|
apiState.sovereignty = data;
|
|
5537
5699
|
|
|
5538
|
-
|
|
5700
|
+
// API returns { score, overall_level, layers: { l1, l2, l3, l4 }, ... }
|
|
5701
|
+
const score = data.score ?? 0;
|
|
5539
5702
|
const badge = document.getElementById('sovereignty-badge');
|
|
5540
5703
|
const scoreEl = document.getElementById('sovereignty-score');
|
|
5541
5704
|
|
|
@@ -5545,18 +5708,18 @@ function generateDashboardHTML(options) {
|
|
|
5545
5708
|
if (score < 70) badge.classList.add('degraded');
|
|
5546
5709
|
if (score < 40) badge.classList.add('inactive');
|
|
5547
5710
|
|
|
5548
|
-
updateLayerCards(data
|
|
5711
|
+
updateLayerCards(data);
|
|
5549
5712
|
}
|
|
5550
5713
|
|
|
5551
|
-
function updateLayerCards(
|
|
5552
|
-
if (!
|
|
5714
|
+
function updateLayerCards(data) {
|
|
5715
|
+
if (!data || !data.layers) return;
|
|
5553
5716
|
|
|
5554
|
-
const layers =
|
|
5717
|
+
const layers = data.layers;
|
|
5555
5718
|
|
|
5556
|
-
updateLayerCard('l1', layers.l1, layers.l1?.
|
|
5557
|
-
updateLayerCard('l2', layers.l2, layers.l2?.
|
|
5558
|
-
updateLayerCard('l3', layers.l3, layers.l3?.
|
|
5559
|
-
updateLayerCard('l4', layers.l4, layers.l4?.
|
|
5719
|
+
updateLayerCard('l1', layers.l1, layers.l1?.detail || 'AES-256-GCM');
|
|
5720
|
+
updateLayerCard('l2', layers.l2, layers.l2?.detail || 'Process-level');
|
|
5721
|
+
updateLayerCard('l3', layers.l3, layers.l3?.detail || 'Schnorr-Pedersen');
|
|
5722
|
+
updateLayerCard('l4', layers.l4, layers.l4?.detail || 'Weighted');
|
|
5560
5723
|
}
|
|
5561
5724
|
|
|
5562
5725
|
function updateLayerCard(layer, layerData, detail) {
|
|
@@ -5584,14 +5747,16 @@ function generateDashboardHTML(options) {
|
|
|
5584
5747
|
|
|
5585
5748
|
apiState.identity = data;
|
|
5586
5749
|
|
|
5587
|
-
|
|
5750
|
+
// API returns { identities: [...], count, primary_id }
|
|
5751
|
+
// Find the primary identity from the array
|
|
5752
|
+
const primary = (data.identities || []).find(id => id.identity_id === data.primary_id) || {};
|
|
5588
5753
|
document.getElementById('identity-label').textContent = primary.label || '\u2014';
|
|
5589
5754
|
document.getElementById('identity-did').textContent = truncate(primary.did, 24);
|
|
5590
5755
|
document.getElementById('identity-did').title = primary.did || '';
|
|
5591
|
-
document.getElementById('identity-pubkey').textContent = truncate(primary.
|
|
5592
|
-
document.getElementById('identity-pubkey').title = primary.
|
|
5593
|
-
document.getElementById('identity-created').textContent = formatTime(primary.
|
|
5594
|
-
document.getElementById('identity-count').textContent = data.
|
|
5756
|
+
document.getElementById('identity-pubkey').textContent = truncate(primary.public_key, 24);
|
|
5757
|
+
document.getElementById('identity-pubkey').title = primary.public_key || '';
|
|
5758
|
+
document.getElementById('identity-created').textContent = formatTime(primary.created_at);
|
|
5759
|
+
document.getElementById('identity-count').textContent = data.count || '\u2014';
|
|
5595
5760
|
}
|
|
5596
5761
|
|
|
5597
5762
|
async function updateHandshakes() {
|
|
@@ -5600,14 +5765,14 @@ function generateDashboardHTML(options) {
|
|
|
5600
5765
|
|
|
5601
5766
|
apiState.handshakes = data.handshakes || [];
|
|
5602
5767
|
|
|
5603
|
-
document.getElementById('handshake-count').textContent = data.
|
|
5768
|
+
document.getElementById('handshake-count').textContent = data.count || '0';
|
|
5604
5769
|
|
|
5605
5770
|
if (data.handshakes && data.handshakes.length > 0) {
|
|
5606
5771
|
const latest = data.handshakes[0];
|
|
5607
|
-
document.getElementById('handshake-latest').textContent = truncate(latest.
|
|
5608
|
-
document.getElementById('handshake-latest').title = latest.
|
|
5609
|
-
document.getElementById('handshake-tier').textContent = (latest.
|
|
5610
|
-
document.getElementById('handshake-time').textContent = formatTime(latest.
|
|
5772
|
+
document.getElementById('handshake-latest').textContent = truncate(latest.counterparty_id, 20);
|
|
5773
|
+
document.getElementById('handshake-latest').title = latest.counterparty_id || '';
|
|
5774
|
+
document.getElementById('handshake-tier').textContent = (latest.trust_tier || 'Unverified').toUpperCase();
|
|
5775
|
+
document.getElementById('handshake-time').textContent = formatTime(latest.completed_at);
|
|
5611
5776
|
} else {
|
|
5612
5777
|
document.getElementById('handshake-latest').textContent = '\u2014';
|
|
5613
5778
|
document.getElementById('handshake-tier').textContent = 'Unverified';
|
|
@@ -5629,12 +5794,12 @@ function generateDashboardHTML(options) {
|
|
|
5629
5794
|
.map(
|
|
5630
5795
|
(hs) => \`
|
|
5631
5796
|
<div class="table-row">
|
|
5632
|
-
<div class="table-cell strong">\${esc(truncate(hs.
|
|
5633
|
-
<div class="table-cell">\${esc(hs.
|
|
5634
|
-
<div class="table-cell">\${esc(hs.
|
|
5797
|
+
<div class="table-cell strong">\${esc(truncate(hs.counterparty_id, 24))}</div>
|
|
5798
|
+
<div class="table-cell">\${esc(hs.trust_tier || 'Unverified')}</div>
|
|
5799
|
+
<div class="table-cell">\${esc(hs.sovereignty_level || '\u2014')}</div>
|
|
5635
5800
|
<div class="table-cell">\${hs.verified ? 'Yes' : 'No'}</div>
|
|
5636
|
-
<div class="table-cell">\${formatTime(hs.
|
|
5637
|
-
<div class="table-cell">\${formatTime(hs.
|
|
5801
|
+
<div class="table-cell">\${formatTime(hs.completed_at)}</div>
|
|
5802
|
+
<div class="table-cell">\${formatTime(hs.expires_at)}</div>
|
|
5638
5803
|
</div>
|
|
5639
5804
|
\`
|
|
5640
5805
|
)
|
|
@@ -5652,11 +5817,14 @@ function generateDashboardHTML(options) {
|
|
|
5652
5817
|
function renderSHRViewer(shr) {
|
|
5653
5818
|
const viewer = document.getElementById('shr-viewer');
|
|
5654
5819
|
|
|
5655
|
-
if (!shr) {
|
|
5820
|
+
if (!shr || shr.error) {
|
|
5656
5821
|
viewer.innerHTML = '<div class="empty-state">No SHR available</div>';
|
|
5657
5822
|
return;
|
|
5658
5823
|
}
|
|
5659
5824
|
|
|
5825
|
+
// SignedSHR shape: { body: { implementation, instance_id, layers, ... }, signed_by, signature }
|
|
5826
|
+
const body = shr.body || shr;
|
|
5827
|
+
|
|
5660
5828
|
let html = '';
|
|
5661
5829
|
|
|
5662
5830
|
// Implementation
|
|
@@ -5669,15 +5837,15 @@ function generateDashboardHTML(options) {
|
|
|
5669
5837
|
<div class="shr-section-content">
|
|
5670
5838
|
<div class="shr-item">
|
|
5671
5839
|
<div class="shr-key">sanctuary_version:</div>
|
|
5672
|
-
<div class="shr-value">\${esc(
|
|
5840
|
+
<div class="shr-value">\${esc(body.implementation?.sanctuary_version || '\u2014')}</div>
|
|
5673
5841
|
</div>
|
|
5674
5842
|
<div class="shr-item">
|
|
5675
5843
|
<div class="shr-key">node_version:</div>
|
|
5676
|
-
<div class="shr-value">\${esc(
|
|
5844
|
+
<div class="shr-value">\${esc(body.implementation?.node_version || '\u2014')}</div>
|
|
5677
5845
|
</div>
|
|
5678
5846
|
<div class="shr-item">
|
|
5679
5847
|
<div class="shr-key">generated_by:</div>
|
|
5680
|
-
<div class="shr-value">\${esc(
|
|
5848
|
+
<div class="shr-value">\${esc(body.implementation?.generated_by || '\u2014')}</div>
|
|
5681
5849
|
</div>
|
|
5682
5850
|
</div>
|
|
5683
5851
|
</div>
|
|
@@ -5693,22 +5861,22 @@ function generateDashboardHTML(options) {
|
|
|
5693
5861
|
<div class="shr-section-content">
|
|
5694
5862
|
<div class="shr-item">
|
|
5695
5863
|
<div class="shr-key">instance_id:</div>
|
|
5696
|
-
<div class="shr-value">\${esc(truncate(
|
|
5864
|
+
<div class="shr-value">\${esc(truncate(body.instance_id, 20))}</div>
|
|
5697
5865
|
</div>
|
|
5698
5866
|
<div class="shr-item">
|
|
5699
5867
|
<div class="shr-key">generated_at:</div>
|
|
5700
|
-
<div class="shr-value">\${formatTime(
|
|
5868
|
+
<div class="shr-value">\${formatTime(body.generated_at)}</div>
|
|
5701
5869
|
</div>
|
|
5702
5870
|
<div class="shr-item">
|
|
5703
5871
|
<div class="shr-key">expires_at:</div>
|
|
5704
|
-
<div class="shr-value">\${formatTime(
|
|
5872
|
+
<div class="shr-value">\${formatTime(body.expires_at)}</div>
|
|
5705
5873
|
</div>
|
|
5706
5874
|
</div>
|
|
5707
5875
|
</div>
|
|
5708
5876
|
\`;
|
|
5709
5877
|
|
|
5710
5878
|
// Layers
|
|
5711
|
-
if (
|
|
5879
|
+
if (body.layers) {
|
|
5712
5880
|
html += \`<div class="shr-section">
|
|
5713
5881
|
<div class="shr-section-header">
|
|
5714
5882
|
<div class="shr-toggle">\u25BC</div>
|
|
@@ -5717,7 +5885,7 @@ function generateDashboardHTML(options) {
|
|
|
5717
5885
|
<div class="shr-section-content">
|
|
5718
5886
|
\`;
|
|
5719
5887
|
|
|
5720
|
-
for (const [key, layer] of Object.entries(
|
|
5888
|
+
for (const [key, layer] of Object.entries(body.layers)) {
|
|
5721
5889
|
html += \`
|
|
5722
5890
|
<div style="margin-bottom: 12px;">
|
|
5723
5891
|
<div style="color: var(--blue); font-weight: 600; margin-bottom: 4px;">\${esc(key)}</div>
|
|
@@ -5819,6 +5987,12 @@ function generateDashboardHTML(options) {
|
|
|
5819
5987
|
|
|
5820
5988
|
const connectionStatus = document.getElementById('connection-status');
|
|
5821
5989
|
connectionStatus.classList.toggle('disconnected', !data.connected);
|
|
5990
|
+
|
|
5991
|
+
// Show standalone mode banner if applicable
|
|
5992
|
+
const banner = document.getElementById('standalone-banner');
|
|
5993
|
+
if (banner && data.standalone_mode) {
|
|
5994
|
+
banner.style.display = 'flex';
|
|
5995
|
+
}
|
|
5822
5996
|
}
|
|
5823
5997
|
|
|
5824
5998
|
function formatUptime(seconds) {
|
|
@@ -6107,6 +6281,8 @@ var DashboardApprovalChannel = class {
|
|
|
6107
6281
|
sessionCleanupTimer = null;
|
|
6108
6282
|
/** Rate limiting: per-IP request tracking */
|
|
6109
6283
|
rateLimits = /* @__PURE__ */ new Map();
|
|
6284
|
+
/** Whether the dashboard is running in standalone mode (no MCP server) */
|
|
6285
|
+
_standaloneMode = false;
|
|
6110
6286
|
constructor(config) {
|
|
6111
6287
|
this.config = config;
|
|
6112
6288
|
this.authToken = config.auth_token;
|
|
@@ -6134,6 +6310,13 @@ var DashboardApprovalChannel = class {
|
|
|
6134
6310
|
if (deps.shrOpts) this.shrOpts = deps.shrOpts;
|
|
6135
6311
|
if (deps.sanctuaryConfig) this._sanctuaryConfig = deps.sanctuaryConfig;
|
|
6136
6312
|
}
|
|
6313
|
+
/**
|
|
6314
|
+
* Mark this dashboard as running in standalone mode.
|
|
6315
|
+
* Exposed via /api/status so the frontend can show an appropriate banner.
|
|
6316
|
+
*/
|
|
6317
|
+
setStandaloneMode(standalone) {
|
|
6318
|
+
this._standaloneMode = standalone;
|
|
6319
|
+
}
|
|
6137
6320
|
/**
|
|
6138
6321
|
* Start the HTTP(S) server for the dashboard.
|
|
6139
6322
|
*/
|
|
@@ -6589,7 +6772,8 @@ data: ${JSON.stringify(initData)}
|
|
|
6589
6772
|
handleStatus(res) {
|
|
6590
6773
|
const status = {
|
|
6591
6774
|
pending_count: this.pending.size,
|
|
6592
|
-
connected_clients: this.sseClients.size
|
|
6775
|
+
connected_clients: this.sseClients.size,
|
|
6776
|
+
standalone_mode: this._standaloneMode
|
|
6593
6777
|
};
|
|
6594
6778
|
if (this.baseline) {
|
|
6595
6779
|
status.baseline = this.baseline.getProfile();
|