@sanctuary-framework/mcp-server 0.5.5 → 0.5.6
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 +1919 -1352
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1919 -1352
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1920 -1351
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +96 -1
- package/dist/index.d.ts +96 -1
- package/dist/index.js +1918 -1352
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3635,6 +3635,8 @@ var DEFAULT_POLICY = {
|
|
|
3635
3635
|
"handshake_respond",
|
|
3636
3636
|
"handshake_complete",
|
|
3637
3637
|
"handshake_status",
|
|
3638
|
+
"handshake_exchange",
|
|
3639
|
+
"handshake_verify_attestation",
|
|
3638
3640
|
"reputation_query_weighted",
|
|
3639
3641
|
"federation_peers",
|
|
3640
3642
|
"federation_trust_evaluate",
|
|
@@ -3804,6 +3806,8 @@ tier3_always_allow:
|
|
|
3804
3806
|
- handshake_respond
|
|
3805
3807
|
- handshake_complete
|
|
3806
3808
|
- handshake_status
|
|
3809
|
+
- handshake_exchange
|
|
3810
|
+
- handshake_verify_attestation
|
|
3807
3811
|
- reputation_query_weighted
|
|
3808
3812
|
- federation_peers
|
|
3809
3813
|
- federation_trust_evaluate
|
|
@@ -4065,174 +4069,255 @@ function generateLoginHTML(options) {
|
|
|
4065
4069
|
return `<!DOCTYPE html>
|
|
4066
4070
|
<html lang="en">
|
|
4067
4071
|
<head>
|
|
4068
|
-
<meta charset="
|
|
4069
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
4070
|
-
<title>Sanctuary
|
|
4071
|
-
<
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4072
|
+
<meta charset="UTF-8">
|
|
4073
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4074
|
+
<title>Sanctuary Dashboard</title>
|
|
4075
|
+
<style>
|
|
4076
|
+
:root {
|
|
4077
|
+
--bg: #0d1117;
|
|
4078
|
+
--surface: #161b22;
|
|
4079
|
+
--border: #30363d;
|
|
4080
|
+
--text-primary: #e6edf3;
|
|
4081
|
+
--text-secondary: #8b949e;
|
|
4082
|
+
--green: #3fb950;
|
|
4083
|
+
--amber: #d29922;
|
|
4084
|
+
--red: #f85149;
|
|
4085
|
+
--blue: #58a6ff;
|
|
4086
|
+
}
|
|
4087
|
+
|
|
4088
|
+
* {
|
|
4089
|
+
margin: 0;
|
|
4090
|
+
padding: 0;
|
|
4091
|
+
box-sizing: border-box;
|
|
4092
|
+
}
|
|
4093
|
+
|
|
4094
|
+
body {
|
|
4095
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
4096
|
+
background-color: var(--bg);
|
|
4097
|
+
color: var(--text-primary);
|
|
4098
|
+
min-height: 100vh;
|
|
4099
|
+
display: flex;
|
|
4100
|
+
align-items: center;
|
|
4101
|
+
justify-content: center;
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
.login-container {
|
|
4105
|
+
width: 100%;
|
|
4106
|
+
max-width: 400px;
|
|
4107
|
+
padding: 20px;
|
|
4108
|
+
}
|
|
4109
|
+
|
|
4110
|
+
.login-card {
|
|
4111
|
+
background-color: var(--surface);
|
|
4112
|
+
border: 1px solid var(--border);
|
|
4113
|
+
border-radius: 8px;
|
|
4114
|
+
padding: 40px 32px;
|
|
4115
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
4116
|
+
}
|
|
4117
|
+
|
|
4118
|
+
.login-header {
|
|
4119
|
+
display: flex;
|
|
4120
|
+
align-items: center;
|
|
4121
|
+
gap: 12px;
|
|
4122
|
+
margin-bottom: 32px;
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4125
|
+
.logo {
|
|
4126
|
+
font-size: 24px;
|
|
4127
|
+
font-weight: 700;
|
|
4128
|
+
color: var(--blue);
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
.logo-text {
|
|
4132
|
+
display: flex;
|
|
4133
|
+
flex-direction: column;
|
|
4134
|
+
}
|
|
4135
|
+
|
|
4136
|
+
.logo-text .title {
|
|
4137
|
+
font-size: 18px;
|
|
4138
|
+
font-weight: 600;
|
|
4139
|
+
letter-spacing: -0.5px;
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4142
|
+
.logo-text .version {
|
|
4143
|
+
font-size: 12px;
|
|
4144
|
+
color: var(--text-secondary);
|
|
4145
|
+
margin-top: 2px;
|
|
4146
|
+
}
|
|
4147
|
+
|
|
4148
|
+
.form-group {
|
|
4149
|
+
margin-bottom: 24px;
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
label {
|
|
4153
|
+
display: block;
|
|
4154
|
+
font-size: 14px;
|
|
4155
|
+
font-weight: 500;
|
|
4156
|
+
margin-bottom: 8px;
|
|
4157
|
+
color: var(--text-primary);
|
|
4158
|
+
}
|
|
4159
|
+
|
|
4160
|
+
input[type="text"],
|
|
4161
|
+
input[type="password"] {
|
|
4162
|
+
width: 100%;
|
|
4163
|
+
padding: 10px 12px;
|
|
4164
|
+
background-color: var(--bg);
|
|
4165
|
+
border: 1px solid var(--border);
|
|
4166
|
+
border-radius: 6px;
|
|
4167
|
+
color: var(--text-primary);
|
|
4168
|
+
font-size: 14px;
|
|
4169
|
+
font-family: 'JetBrains Mono', monospace;
|
|
4170
|
+
transition: border-color 0.2s;
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
input[type="text"]:focus,
|
|
4174
|
+
input[type="password"]:focus {
|
|
4175
|
+
outline: none;
|
|
4176
|
+
border-color: var(--blue);
|
|
4177
|
+
box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.1);
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
.error-message {
|
|
4181
|
+
display: none;
|
|
4182
|
+
background-color: rgba(248, 81, 73, 0.1);
|
|
4183
|
+
border: 1px solid var(--red);
|
|
4184
|
+
color: #ff9999;
|
|
4185
|
+
padding: 12px;
|
|
4186
|
+
border-radius: 6px;
|
|
4187
|
+
font-size: 13px;
|
|
4188
|
+
margin-bottom: 20px;
|
|
4189
|
+
}
|
|
4190
|
+
|
|
4191
|
+
.error-message.show {
|
|
4192
|
+
display: block;
|
|
4193
|
+
}
|
|
4194
|
+
|
|
4195
|
+
button {
|
|
4196
|
+
width: 100%;
|
|
4197
|
+
padding: 10px 16px;
|
|
4198
|
+
background-color: var(--blue);
|
|
4199
|
+
color: var(--bg);
|
|
4200
|
+
border: none;
|
|
4201
|
+
border-radius: 6px;
|
|
4202
|
+
font-size: 14px;
|
|
4203
|
+
font-weight: 600;
|
|
4204
|
+
cursor: pointer;
|
|
4205
|
+
transition: background-color 0.2s;
|
|
4206
|
+
}
|
|
4207
|
+
|
|
4208
|
+
button:hover {
|
|
4209
|
+
background-color: #79c0ff;
|
|
4210
|
+
}
|
|
4211
|
+
|
|
4212
|
+
button:active {
|
|
4213
|
+
background-color: #4184e4;
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4216
|
+
button:disabled {
|
|
4217
|
+
background-color: var(--text-secondary);
|
|
4218
|
+
cursor: not-allowed;
|
|
4219
|
+
opacity: 0.5;
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
.info-text {
|
|
4223
|
+
font-size: 12px;
|
|
4224
|
+
color: var(--text-secondary);
|
|
4225
|
+
margin-top: 16px;
|
|
4226
|
+
text-align: center;
|
|
4227
|
+
}
|
|
4228
|
+
</style>
|
|
4182
4229
|
</head>
|
|
4183
4230
|
<body>
|
|
4184
|
-
<div class="login-container">
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4231
|
+
<div class="login-container">
|
|
4232
|
+
<div class="login-card">
|
|
4233
|
+
<div class="login-header">
|
|
4234
|
+
<div class="logo">\u25C6</div>
|
|
4235
|
+
<div class="logo-text">
|
|
4236
|
+
<div class="title">SANCTUARY</div>
|
|
4237
|
+
<div class="version">v${options.serverVersion}</div>
|
|
4238
|
+
</div>
|
|
4239
|
+
</div>
|
|
4240
|
+
|
|
4241
|
+
<div id="error-message" class="error-message"></div>
|
|
4242
|
+
|
|
4243
|
+
<form id="login-form">
|
|
4244
|
+
<div class="form-group">
|
|
4245
|
+
<label for="auth-token">Bearer Token</label>
|
|
4246
|
+
<input
|
|
4247
|
+
type="text"
|
|
4248
|
+
id="auth-token"
|
|
4249
|
+
name="token"
|
|
4250
|
+
placeholder="Paste your session token..."
|
|
4251
|
+
autocomplete="off"
|
|
4252
|
+
spellcheck="false"
|
|
4253
|
+
required
|
|
4254
|
+
/>
|
|
4255
|
+
</div>
|
|
4256
|
+
|
|
4257
|
+
<button type="submit" id="login-button">Open Dashboard</button>
|
|
4258
|
+
</form>
|
|
4259
|
+
|
|
4260
|
+
<div class="info-text">
|
|
4261
|
+
Session tokens expire after 1 hour of inactivity
|
|
4262
|
+
</div>
|
|
4263
|
+
</div>
|
|
4197
4264
|
</div>
|
|
4198
|
-
|
|
4199
|
-
<script>
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4265
|
+
|
|
4266
|
+
<script>
|
|
4267
|
+
const loginForm = document.getElementById('login-form');
|
|
4268
|
+
const authTokenInput = document.getElementById('auth-token');
|
|
4269
|
+
const errorMessage = document.getElementById('error-message');
|
|
4270
|
+
const loginButton = document.getElementById('login-button');
|
|
4271
|
+
|
|
4272
|
+
loginForm.addEventListener('submit', async (e) => {
|
|
4273
|
+
e.preventDefault();
|
|
4274
|
+
const token = authTokenInput.value.trim();
|
|
4275
|
+
|
|
4276
|
+
if (!token) {
|
|
4277
|
+
showError('Token is required');
|
|
4278
|
+
return;
|
|
4279
|
+
}
|
|
4280
|
+
|
|
4281
|
+
loginButton.disabled = true;
|
|
4282
|
+
loginButton.textContent = 'Verifying...';
|
|
4283
|
+
errorMessage.classList.remove('show');
|
|
4284
|
+
|
|
4285
|
+
try {
|
|
4286
|
+
const response = await fetch('/auth/session', {
|
|
4287
|
+
method: 'POST',
|
|
4288
|
+
headers: {
|
|
4289
|
+
'Content-Type': 'application/json',
|
|
4290
|
+
'Authorization': 'Bearer ' + token,
|
|
4291
|
+
},
|
|
4292
|
+
body: JSON.stringify({ token }),
|
|
4293
|
+
});
|
|
4294
|
+
|
|
4295
|
+
if (response.ok) {
|
|
4296
|
+
const data = await response.json();
|
|
4297
|
+
sessionStorage.setItem('authToken', token);
|
|
4298
|
+
window.location.href = '/dashboard';
|
|
4299
|
+
} else if (response.status === 401) {
|
|
4300
|
+
showError('Invalid token. Please check and try again.');
|
|
4301
|
+
} else {
|
|
4302
|
+
showError('Authentication failed. Please try again.');
|
|
4303
|
+
}
|
|
4304
|
+
} catch (err) {
|
|
4305
|
+
showError('Connection error. Please check your network.');
|
|
4306
|
+
} finally {
|
|
4307
|
+
loginButton.disabled = false;
|
|
4308
|
+
loginButton.textContent = 'Open Dashboard';
|
|
4309
|
+
}
|
|
4213
4310
|
});
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
'; path=/; SameSite=Strict; max-age=' + maxAge;
|
|
4225
|
-
// Reload to enter the dashboard
|
|
4226
|
-
window.location.reload();
|
|
4227
|
-
} catch (err) {
|
|
4228
|
-
errEl.textContent = err.message || 'Authentication failed. Check your token.';
|
|
4229
|
-
errEl.style.display = 'block';
|
|
4230
|
-
btn.disabled = false;
|
|
4231
|
-
btn.textContent = 'Open Dashboard';
|
|
4232
|
-
}
|
|
4233
|
-
return false;
|
|
4234
|
-
}
|
|
4235
|
-
</script>
|
|
4311
|
+
|
|
4312
|
+
function showError(message) {
|
|
4313
|
+
errorMessage.textContent = message;
|
|
4314
|
+
errorMessage.classList.add('show');
|
|
4315
|
+
}
|
|
4316
|
+
|
|
4317
|
+
authTokenInput.addEventListener('input', () => {
|
|
4318
|
+
errorMessage.classList.remove('show');
|
|
4319
|
+
});
|
|
4320
|
+
</script>
|
|
4236
4321
|
</body>
|
|
4237
4322
|
</html>`;
|
|
4238
4323
|
}
|
|
@@ -4240,1412 +4325,1648 @@ function generateDashboardHTML(options) {
|
|
|
4240
4325
|
return `<!DOCTYPE html>
|
|
4241
4326
|
<html lang="en">
|
|
4242
4327
|
<head>
|
|
4243
|
-
<meta charset="
|
|
4244
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
4245
|
-
<title>Sanctuary
|
|
4246
|
-
<
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4328
|
+
<meta charset="UTF-8">
|
|
4329
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4330
|
+
<title>Sanctuary Dashboard</title>
|
|
4331
|
+
<style>
|
|
4332
|
+
:root {
|
|
4333
|
+
--bg: #0d1117;
|
|
4334
|
+
--surface: #161b22;
|
|
4335
|
+
--border: #30363d;
|
|
4336
|
+
--text-primary: #e6edf3;
|
|
4337
|
+
--text-secondary: #8b949e;
|
|
4338
|
+
--green: #3fb950;
|
|
4339
|
+
--amber: #d29922;
|
|
4340
|
+
--red: #f85149;
|
|
4341
|
+
--blue: #58a6ff;
|
|
4342
|
+
--success: #3fb950;
|
|
4343
|
+
--warning: #d29922;
|
|
4344
|
+
--error: #f85149;
|
|
4345
|
+
--muted: #21262d;
|
|
4346
|
+
}
|
|
4347
|
+
|
|
4348
|
+
* {
|
|
4349
|
+
margin: 0;
|
|
4350
|
+
padding: 0;
|
|
4351
|
+
box-sizing: border-box;
|
|
4352
|
+
}
|
|
4353
|
+
|
|
4354
|
+
html, body {
|
|
4355
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
4356
|
+
background-color: var(--bg);
|
|
4357
|
+
color: var(--text-primary);
|
|
4358
|
+
height: 100%;
|
|
4359
|
+
overflow: hidden;
|
|
4360
|
+
}
|
|
4361
|
+
|
|
4362
|
+
body {
|
|
4363
|
+
display: flex;
|
|
4364
|
+
flex-direction: column;
|
|
4365
|
+
}
|
|
4366
|
+
|
|
4367
|
+
/* Status Bar */
|
|
4368
|
+
.status-bar {
|
|
4369
|
+
position: fixed;
|
|
4370
|
+
top: 0;
|
|
4371
|
+
left: 0;
|
|
4372
|
+
right: 0;
|
|
4373
|
+
height: 56px;
|
|
4374
|
+
background-color: var(--surface);
|
|
4375
|
+
border-bottom: 1px solid var(--border);
|
|
4376
|
+
display: flex;
|
|
4377
|
+
align-items: center;
|
|
4378
|
+
padding: 0 24px;
|
|
4379
|
+
gap: 24px;
|
|
4380
|
+
z-index: 100;
|
|
4381
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
4382
|
+
}
|
|
4383
|
+
|
|
4384
|
+
.status-bar-left {
|
|
4385
|
+
display: flex;
|
|
4386
|
+
align-items: center;
|
|
4387
|
+
gap: 12px;
|
|
4388
|
+
flex: 0 0 auto;
|
|
4389
|
+
}
|
|
4268
4390
|
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
body {
|
|
4276
|
-
font-family: var(--sans);
|
|
4277
|
-
background: var(--bg);
|
|
4278
|
-
color: var(--text-primary);
|
|
4279
|
-
display: flex;
|
|
4280
|
-
flex-direction: column;
|
|
4281
|
-
}
|
|
4282
|
-
|
|
4283
|
-
/* \u2500\u2500 Top Status Bar (fixed) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
4391
|
+
.logo-icon {
|
|
4392
|
+
font-size: 20px;
|
|
4393
|
+
color: var(--blue);
|
|
4394
|
+
font-weight: 700;
|
|
4395
|
+
}
|
|
4284
4396
|
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
right: 0;
|
|
4290
|
-
height: 56px;
|
|
4291
|
-
background: var(--surface);
|
|
4292
|
-
border-bottom: 1px solid var(--border);
|
|
4293
|
-
display: flex;
|
|
4294
|
-
align-items: center;
|
|
4295
|
-
padding: 0 20px;
|
|
4296
|
-
gap: 24px;
|
|
4297
|
-
z-index: 1000;
|
|
4298
|
-
}
|
|
4397
|
+
.logo-info {
|
|
4398
|
+
display: flex;
|
|
4399
|
+
flex-direction: column;
|
|
4400
|
+
}
|
|
4299
4401
|
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4402
|
+
.logo-title {
|
|
4403
|
+
font-size: 13px;
|
|
4404
|
+
font-weight: 600;
|
|
4405
|
+
line-height: 1;
|
|
4406
|
+
color: var(--text-primary);
|
|
4407
|
+
}
|
|
4306
4408
|
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
}
|
|
4409
|
+
.logo-version {
|
|
4410
|
+
font-size: 11px;
|
|
4411
|
+
color: var(--text-secondary);
|
|
4412
|
+
margin-top: 2px;
|
|
4413
|
+
}
|
|
4313
4414
|
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4415
|
+
.status-bar-center {
|
|
4416
|
+
flex: 1;
|
|
4417
|
+
display: flex;
|
|
4418
|
+
justify-content: center;
|
|
4419
|
+
}
|
|
4317
4420
|
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4421
|
+
.sovereignty-badge {
|
|
4422
|
+
display: flex;
|
|
4423
|
+
align-items: center;
|
|
4424
|
+
gap: 8px;
|
|
4425
|
+
padding: 8px 16px;
|
|
4426
|
+
background-color: rgba(63, 185, 80, 0.1);
|
|
4427
|
+
border: 1px solid rgba(63, 185, 80, 0.3);
|
|
4428
|
+
border-radius: 6px;
|
|
4429
|
+
font-size: 13px;
|
|
4430
|
+
font-weight: 500;
|
|
4431
|
+
}
|
|
4323
4432
|
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
justify-content: center;
|
|
4329
|
-
}
|
|
4330
|
-
|
|
4331
|
-
.sovereignty-badge {
|
|
4332
|
-
display: flex;
|
|
4333
|
-
align-items: center;
|
|
4334
|
-
gap: 8px;
|
|
4335
|
-
padding: 6px 12px;
|
|
4336
|
-
background: rgba(88, 166, 255, 0.1);
|
|
4337
|
-
border: 1px solid var(--blue);
|
|
4338
|
-
border-radius: 20px;
|
|
4339
|
-
font-size: 13px;
|
|
4340
|
-
font-weight: 600;
|
|
4341
|
-
}
|
|
4433
|
+
.sovereignty-badge.degraded {
|
|
4434
|
+
background-color: rgba(210, 153, 34, 0.1);
|
|
4435
|
+
border-color: rgba(210, 153, 34, 0.3);
|
|
4436
|
+
}
|
|
4342
4437
|
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
width: 28px;
|
|
4348
|
-
height: 28px;
|
|
4349
|
-
border-radius: 50%;
|
|
4350
|
-
font-family: var(--mono);
|
|
4351
|
-
font-weight: 700;
|
|
4352
|
-
font-size: 12px;
|
|
4353
|
-
background: var(--blue);
|
|
4354
|
-
color: var(--bg);
|
|
4355
|
-
}
|
|
4438
|
+
.sovereignty-badge.inactive {
|
|
4439
|
+
background-color: rgba(248, 81, 73, 0.1);
|
|
4440
|
+
border-color: rgba(248, 81, 73, 0.3);
|
|
4441
|
+
}
|
|
4356
4442
|
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4443
|
+
.sovereignty-score {
|
|
4444
|
+
font-weight: 700;
|
|
4445
|
+
color: var(--green);
|
|
4446
|
+
}
|
|
4360
4447
|
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4448
|
+
.sovereignty-badge.degraded .sovereignty-score {
|
|
4449
|
+
color: var(--amber);
|
|
4450
|
+
}
|
|
4364
4451
|
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4452
|
+
.sovereignty-badge.inactive .sovereignty-score {
|
|
4453
|
+
color: var(--red);
|
|
4454
|
+
}
|
|
4368
4455
|
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4456
|
+
.status-bar-right {
|
|
4457
|
+
display: flex;
|
|
4458
|
+
align-items: center;
|
|
4459
|
+
gap: 16px;
|
|
4460
|
+
flex: 0 0 auto;
|
|
4461
|
+
}
|
|
4375
4462
|
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
}
|
|
4463
|
+
.status-item {
|
|
4464
|
+
display: flex;
|
|
4465
|
+
align-items: center;
|
|
4466
|
+
gap: 6px;
|
|
4467
|
+
font-size: 12px;
|
|
4468
|
+
color: var(--text-secondary);
|
|
4469
|
+
}
|
|
4384
4470
|
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4471
|
+
.status-item strong {
|
|
4472
|
+
color: var(--text-primary);
|
|
4473
|
+
font-weight: 500;
|
|
4474
|
+
}
|
|
4389
4475
|
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
font-family: var(--mono);
|
|
4397
|
-
}
|
|
4476
|
+
.status-dot {
|
|
4477
|
+
width: 8px;
|
|
4478
|
+
height: 8px;
|
|
4479
|
+
border-radius: 50%;
|
|
4480
|
+
background-color: var(--green);
|
|
4481
|
+
}
|
|
4398
4482
|
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
border-radius: 50%;
|
|
4403
|
-
background: var(--green);
|
|
4404
|
-
animation: pulse 2s ease-in-out infinite;
|
|
4405
|
-
}
|
|
4483
|
+
.status-dot.disconnected {
|
|
4484
|
+
background-color: var(--red);
|
|
4485
|
+
}
|
|
4406
4486
|
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4487
|
+
.pending-badge {
|
|
4488
|
+
display: flex;
|
|
4489
|
+
align-items: center;
|
|
4490
|
+
gap: 6px;
|
|
4491
|
+
padding: 4px 8px;
|
|
4492
|
+
background-color: var(--blue);
|
|
4493
|
+
color: var(--bg);
|
|
4494
|
+
border-radius: 4px;
|
|
4495
|
+
font-size: 11px;
|
|
4496
|
+
font-weight: 600;
|
|
4497
|
+
cursor: pointer;
|
|
4498
|
+
}
|
|
4411
4499
|
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4500
|
+
/* Main Content */
|
|
4501
|
+
.main-content {
|
|
4502
|
+
flex: 1;
|
|
4503
|
+
margin-top: 56px;
|
|
4504
|
+
overflow-y: auto;
|
|
4505
|
+
padding: 24px;
|
|
4506
|
+
}
|
|
4416
4507
|
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
min-width: 24px;
|
|
4422
|
-
height: 24px;
|
|
4423
|
-
padding: 0 6px;
|
|
4424
|
-
background: var(--red);
|
|
4425
|
-
color: white;
|
|
4426
|
-
border-radius: 12px;
|
|
4427
|
-
font-size: 11px;
|
|
4428
|
-
font-weight: 700;
|
|
4429
|
-
animation: pulse 1s ease-in-out infinite;
|
|
4430
|
-
}
|
|
4508
|
+
.grid {
|
|
4509
|
+
display: grid;
|
|
4510
|
+
gap: 20px;
|
|
4511
|
+
}
|
|
4431
4512
|
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4513
|
+
/* Row 1: Sovereignty Layers */
|
|
4514
|
+
.sovereignty-layers {
|
|
4515
|
+
display: grid;
|
|
4516
|
+
grid-template-columns: repeat(4, 1fr);
|
|
4517
|
+
gap: 16px;
|
|
4518
|
+
}
|
|
4435
4519
|
|
|
4436
|
-
|
|
4520
|
+
.layer-card {
|
|
4521
|
+
background-color: var(--surface);
|
|
4522
|
+
border: 1px solid var(--border);
|
|
4523
|
+
border-radius: 8px;
|
|
4524
|
+
padding: 20px;
|
|
4525
|
+
display: flex;
|
|
4526
|
+
flex-direction: column;
|
|
4527
|
+
gap: 12px;
|
|
4528
|
+
}
|
|
4437
4529
|
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
overflow: hidden;
|
|
4443
|
-
}
|
|
4530
|
+
.layer-card.degraded {
|
|
4531
|
+
border-color: var(--amber);
|
|
4532
|
+
background-color: rgba(210, 153, 34, 0.05);
|
|
4533
|
+
}
|
|
4444
4534
|
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
border-right: 1px solid var(--border);
|
|
4450
|
-
overflow: hidden;
|
|
4451
|
-
}
|
|
4535
|
+
.layer-card.inactive {
|
|
4536
|
+
border-color: var(--red);
|
|
4537
|
+
background-color: rgba(248, 81, 73, 0.05);
|
|
4538
|
+
}
|
|
4452
4539
|
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
font-weight: 600;
|
|
4461
|
-
text-transform: uppercase;
|
|
4462
|
-
letter-spacing: 0.5px;
|
|
4463
|
-
color: var(--text-secondary);
|
|
4464
|
-
}
|
|
4540
|
+
.layer-name {
|
|
4541
|
+
font-size: 12px;
|
|
4542
|
+
font-weight: 600;
|
|
4543
|
+
color: var(--text-secondary);
|
|
4544
|
+
text-transform: uppercase;
|
|
4545
|
+
letter-spacing: 0.5px;
|
|
4546
|
+
}
|
|
4465
4547
|
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
}
|
|
4548
|
+
.layer-title {
|
|
4549
|
+
font-size: 14px;
|
|
4550
|
+
font-weight: 600;
|
|
4551
|
+
color: var(--text-primary);
|
|
4552
|
+
}
|
|
4472
4553
|
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4554
|
+
.layer-status {
|
|
4555
|
+
display: inline-flex;
|
|
4556
|
+
align-items: center;
|
|
4557
|
+
gap: 6px;
|
|
4558
|
+
padding: 4px 8px;
|
|
4559
|
+
background-color: rgba(63, 185, 80, 0.15);
|
|
4560
|
+
color: var(--green);
|
|
4561
|
+
border-radius: 4px;
|
|
4562
|
+
font-size: 11px;
|
|
4563
|
+
font-weight: 600;
|
|
4564
|
+
width: fit-content;
|
|
4565
|
+
}
|
|
4478
4566
|
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
font-family: var(--mono);
|
|
4484
|
-
cursor: pointer;
|
|
4485
|
-
transition: background 0.15s;
|
|
4486
|
-
display: flex;
|
|
4487
|
-
align-items: flex-start;
|
|
4488
|
-
gap: 10px;
|
|
4489
|
-
}
|
|
4567
|
+
.layer-card.degraded .layer-status {
|
|
4568
|
+
background-color: rgba(210, 153, 34, 0.15);
|
|
4569
|
+
color: var(--amber);
|
|
4570
|
+
}
|
|
4490
4571
|
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4572
|
+
.layer-card.inactive .layer-status {
|
|
4573
|
+
background-color: rgba(248, 81, 73, 0.15);
|
|
4574
|
+
color: var(--red);
|
|
4575
|
+
}
|
|
4494
4576
|
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4577
|
+
.layer-detail {
|
|
4578
|
+
font-size: 12px;
|
|
4579
|
+
color: var(--text-secondary);
|
|
4580
|
+
font-family: 'JetBrains Mono', monospace;
|
|
4581
|
+
padding: 8px;
|
|
4582
|
+
background-color: var(--bg);
|
|
4583
|
+
border-radius: 4px;
|
|
4584
|
+
border-left: 2px solid var(--blue);
|
|
4585
|
+
}
|
|
4503
4586
|
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4587
|
+
/* Row 2: Info Cards */
|
|
4588
|
+
.info-cards {
|
|
4589
|
+
display: grid;
|
|
4590
|
+
grid-template-columns: repeat(3, 1fr);
|
|
4591
|
+
gap: 16px;
|
|
4592
|
+
}
|
|
4508
4593
|
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4594
|
+
.info-card {
|
|
4595
|
+
background-color: var(--surface);
|
|
4596
|
+
border: 1px solid var(--border);
|
|
4597
|
+
border-radius: 8px;
|
|
4598
|
+
padding: 20px;
|
|
4599
|
+
}
|
|
4514
4600
|
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4601
|
+
.card-header {
|
|
4602
|
+
font-size: 12px;
|
|
4603
|
+
font-weight: 600;
|
|
4604
|
+
color: var(--text-secondary);
|
|
4605
|
+
text-transform: uppercase;
|
|
4606
|
+
letter-spacing: 0.5px;
|
|
4607
|
+
margin-bottom: 16px;
|
|
4608
|
+
}
|
|
4521
4609
|
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
font-weight: 700;
|
|
4530
|
-
border-radius: 3px;
|
|
4531
|
-
text-transform: uppercase;
|
|
4532
|
-
flex: 0 0 auto;
|
|
4533
|
-
}
|
|
4610
|
+
.card-row {
|
|
4611
|
+
display: flex;
|
|
4612
|
+
justify-content: space-between;
|
|
4613
|
+
align-items: center;
|
|
4614
|
+
margin-bottom: 12px;
|
|
4615
|
+
font-size: 13px;
|
|
4616
|
+
}
|
|
4534
4617
|
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
}
|
|
4618
|
+
.card-row:last-child {
|
|
4619
|
+
margin-bottom: 0;
|
|
4620
|
+
}
|
|
4539
4621
|
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
}
|
|
4622
|
+
.card-label {
|
|
4623
|
+
color: var(--text-secondary);
|
|
4624
|
+
}
|
|
4544
4625
|
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4626
|
+
.card-value {
|
|
4627
|
+
color: var(--text-primary);
|
|
4628
|
+
font-family: 'JetBrains Mono', monospace;
|
|
4629
|
+
font-weight: 500;
|
|
4630
|
+
}
|
|
4549
4631
|
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4632
|
+
.identity-badge {
|
|
4633
|
+
display: inline-flex;
|
|
4634
|
+
align-items: center;
|
|
4635
|
+
gap: 4px;
|
|
4636
|
+
padding: 2px 6px;
|
|
4637
|
+
background-color: rgba(88, 166, 255, 0.15);
|
|
4638
|
+
color: var(--blue);
|
|
4639
|
+
border-radius: 3px;
|
|
4640
|
+
font-size: 10px;
|
|
4641
|
+
font-weight: 600;
|
|
4642
|
+
text-transform: uppercase;
|
|
4643
|
+
}
|
|
4554
4644
|
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4645
|
+
.trust-tier-badge {
|
|
4646
|
+
display: inline-flex;
|
|
4647
|
+
align-items: center;
|
|
4648
|
+
gap: 4px;
|
|
4649
|
+
padding: 2px 6px;
|
|
4650
|
+
background-color: rgba(63, 185, 80, 0.15);
|
|
4651
|
+
color: var(--green);
|
|
4652
|
+
border-radius: 3px;
|
|
4653
|
+
font-size: 10px;
|
|
4654
|
+
font-weight: 600;
|
|
4655
|
+
}
|
|
4558
4656
|
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4657
|
+
.truncated {
|
|
4658
|
+
max-width: 200px;
|
|
4659
|
+
overflow: hidden;
|
|
4660
|
+
text-overflow: ellipsis;
|
|
4661
|
+
white-space: nowrap;
|
|
4662
|
+
}
|
|
4562
4663
|
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4664
|
+
/* Row 3: SHR & Activity */
|
|
4665
|
+
.main-panels {
|
|
4666
|
+
display: grid;
|
|
4667
|
+
grid-template-columns: 1fr 1fr;
|
|
4668
|
+
gap: 16px;
|
|
4669
|
+
min-height: 400px;
|
|
4670
|
+
}
|
|
4568
4671
|
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4672
|
+
.panel {
|
|
4673
|
+
background-color: var(--surface);
|
|
4674
|
+
border: 1px solid var(--border);
|
|
4675
|
+
border-radius: 8px;
|
|
4676
|
+
display: flex;
|
|
4677
|
+
flex-direction: column;
|
|
4678
|
+
overflow: hidden;
|
|
4679
|
+
}
|
|
4577
4680
|
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
}
|
|
4681
|
+
.panel-header {
|
|
4682
|
+
padding: 16px 20px;
|
|
4683
|
+
border-bottom: 1px solid var(--border);
|
|
4684
|
+
display: flex;
|
|
4685
|
+
justify-content: space-between;
|
|
4686
|
+
align-items: center;
|
|
4687
|
+
}
|
|
4586
4688
|
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4689
|
+
.panel-title {
|
|
4690
|
+
font-size: 14px;
|
|
4691
|
+
font-weight: 600;
|
|
4692
|
+
color: var(--text-primary);
|
|
4693
|
+
}
|
|
4591
4694
|
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4695
|
+
.panel-action {
|
|
4696
|
+
background: none;
|
|
4697
|
+
border: none;
|
|
4698
|
+
color: var(--blue);
|
|
4699
|
+
cursor: pointer;
|
|
4700
|
+
font-size: 12px;
|
|
4701
|
+
padding: 0;
|
|
4702
|
+
font-weight: 500;
|
|
4703
|
+
transition: color 0.2s;
|
|
4704
|
+
}
|
|
4595
4705
|
|
|
4596
|
-
|
|
4706
|
+
.panel-action:hover {
|
|
4707
|
+
color: #79c0ff;
|
|
4708
|
+
}
|
|
4597
4709
|
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
overflow: hidden;
|
|
4604
|
-
}
|
|
4710
|
+
.panel-content {
|
|
4711
|
+
flex: 1;
|
|
4712
|
+
overflow-y: auto;
|
|
4713
|
+
padding: 20px;
|
|
4714
|
+
}
|
|
4605
4715
|
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
color: var(--text-secondary);
|
|
4614
|
-
display: flex;
|
|
4615
|
-
align-items: center;
|
|
4616
|
-
gap: 8px;
|
|
4617
|
-
}
|
|
4716
|
+
/* SHR Viewer */
|
|
4717
|
+
.shr-json {
|
|
4718
|
+
font-family: 'JetBrains Mono', monospace;
|
|
4719
|
+
font-size: 12px;
|
|
4720
|
+
line-height: 1.6;
|
|
4721
|
+
color: var(--text-secondary);
|
|
4722
|
+
}
|
|
4618
4723
|
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
padding: 16px 16px;
|
|
4623
|
-
display: grid;
|
|
4624
|
-
grid-template-columns: 1fr 1fr;
|
|
4625
|
-
gap: 12px;
|
|
4626
|
-
}
|
|
4724
|
+
.shr-section {
|
|
4725
|
+
margin-bottom: 12px;
|
|
4726
|
+
}
|
|
4627
4727
|
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4728
|
+
.shr-section-header {
|
|
4729
|
+
display: flex;
|
|
4730
|
+
align-items: center;
|
|
4731
|
+
gap: 8px;
|
|
4732
|
+
cursor: pointer;
|
|
4733
|
+
font-weight: 600;
|
|
4734
|
+
color: var(--text-primary);
|
|
4735
|
+
padding: 8px;
|
|
4736
|
+
background-color: var(--bg);
|
|
4737
|
+
border-radius: 4px;
|
|
4738
|
+
user-select: none;
|
|
4739
|
+
}
|
|
4637
4740
|
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4741
|
+
.shr-section-header:hover {
|
|
4742
|
+
background-color: var(--muted);
|
|
4743
|
+
}
|
|
4641
4744
|
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4745
|
+
.shr-toggle {
|
|
4746
|
+
width: 16px;
|
|
4747
|
+
height: 16px;
|
|
4748
|
+
display: flex;
|
|
4749
|
+
align-items: center;
|
|
4750
|
+
justify-content: center;
|
|
4751
|
+
font-size: 10px;
|
|
4752
|
+
transition: transform 0.2s;
|
|
4753
|
+
}
|
|
4649
4754
|
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
gap: 6px;
|
|
4654
|
-
font-size: 12px;
|
|
4655
|
-
font-weight: 600;
|
|
4656
|
-
}
|
|
4755
|
+
.shr-section.collapsed .shr-toggle {
|
|
4756
|
+
transform: rotate(-90deg);
|
|
4757
|
+
}
|
|
4657
4758
|
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4759
|
+
.shr-section-content {
|
|
4760
|
+
padding: 8px 16px;
|
|
4761
|
+
background-color: rgba(0, 0, 0, 0.2);
|
|
4762
|
+
border-radius: 4px;
|
|
4763
|
+
margin-top: 4px;
|
|
4764
|
+
}
|
|
4661
4765
|
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4766
|
+
.shr-section.collapsed .shr-section-content {
|
|
4767
|
+
display: none;
|
|
4768
|
+
}
|
|
4665
4769
|
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
margin-top: 4px;
|
|
4671
|
-
}
|
|
4770
|
+
.shr-item {
|
|
4771
|
+
display: flex;
|
|
4772
|
+
margin-bottom: 4px;
|
|
4773
|
+
}
|
|
4672
4774
|
|
|
4673
|
-
|
|
4775
|
+
.shr-key {
|
|
4776
|
+
color: var(--blue);
|
|
4777
|
+
margin-right: 8px;
|
|
4778
|
+
min-width: 120px;
|
|
4779
|
+
}
|
|
4674
4780
|
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
bottom: 0;
|
|
4680
|
-
width: 0;
|
|
4681
|
-
background: var(--surface);
|
|
4682
|
-
border-left: 1px solid var(--border);
|
|
4683
|
-
z-index: 999;
|
|
4684
|
-
overflow-y: auto;
|
|
4685
|
-
transition: width 0.3s ease-out;
|
|
4686
|
-
display: flex;
|
|
4687
|
-
flex-direction: column;
|
|
4688
|
-
}
|
|
4781
|
+
.shr-value {
|
|
4782
|
+
color: var(--green);
|
|
4783
|
+
word-break: break-all;
|
|
4784
|
+
}
|
|
4689
4785
|
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4786
|
+
/* Activity Feed */
|
|
4787
|
+
.activity-feed {
|
|
4788
|
+
display: flex;
|
|
4789
|
+
flex-direction: column;
|
|
4790
|
+
gap: 12px;
|
|
4791
|
+
}
|
|
4693
4792
|
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4793
|
+
.activity-item {
|
|
4794
|
+
padding: 12px;
|
|
4795
|
+
background-color: var(--bg);
|
|
4796
|
+
border-left: 2px solid var(--border);
|
|
4797
|
+
border-radius: 4px;
|
|
4798
|
+
font-size: 12px;
|
|
4699
4799
|
}
|
|
4700
|
-
}
|
|
4701
4800
|
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
display: flex;
|
|
4706
|
-
align-items: center;
|
|
4707
|
-
justify-content: space-between;
|
|
4708
|
-
flex: 0 0 auto;
|
|
4709
|
-
}
|
|
4801
|
+
.activity-item.tool-call {
|
|
4802
|
+
border-left-color: var(--blue);
|
|
4803
|
+
}
|
|
4710
4804
|
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
text-transform: uppercase;
|
|
4715
|
-
letter-spacing: 0.5px;
|
|
4716
|
-
color: var(--text-primary);
|
|
4717
|
-
}
|
|
4805
|
+
.activity-item.context-gate {
|
|
4806
|
+
border-left-color: var(--amber);
|
|
4807
|
+
}
|
|
4718
4808
|
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
color: var(--text-secondary);
|
|
4723
|
-
cursor: pointer;
|
|
4724
|
-
font-size: 18px;
|
|
4725
|
-
padding: 0;
|
|
4726
|
-
display: flex;
|
|
4727
|
-
align-items: center;
|
|
4728
|
-
justify-content: center;
|
|
4729
|
-
}
|
|
4809
|
+
.activity-item.injection {
|
|
4810
|
+
border-left-color: var(--red);
|
|
4811
|
+
}
|
|
4730
4812
|
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4813
|
+
.activity-item.protection {
|
|
4814
|
+
border-left-color: var(--green);
|
|
4815
|
+
}
|
|
4734
4816
|
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4817
|
+
.activity-type {
|
|
4818
|
+
font-weight: 600;
|
|
4819
|
+
color: var(--text-primary);
|
|
4820
|
+
margin-bottom: 4px;
|
|
4821
|
+
text-transform: uppercase;
|
|
4822
|
+
font-size: 11px;
|
|
4823
|
+
letter-spacing: 0.5px;
|
|
4824
|
+
}
|
|
4739
4825
|
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
}
|
|
4826
|
+
.activity-content {
|
|
4827
|
+
color: var(--text-secondary);
|
|
4828
|
+
font-family: 'JetBrains Mono', monospace;
|
|
4829
|
+
margin-bottom: 4px;
|
|
4830
|
+
word-break: break-all;
|
|
4831
|
+
}
|
|
4747
4832
|
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
}
|
|
4833
|
+
.activity-time {
|
|
4834
|
+
font-size: 11px;
|
|
4835
|
+
color: var(--text-secondary);
|
|
4836
|
+
}
|
|
4753
4837
|
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4838
|
+
.empty-state {
|
|
4839
|
+
display: flex;
|
|
4840
|
+
align-items: center;
|
|
4841
|
+
justify-content: center;
|
|
4842
|
+
height: 100%;
|
|
4843
|
+
color: var(--text-secondary);
|
|
4844
|
+
font-size: 13px;
|
|
4845
|
+
}
|
|
4761
4846
|
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
font-weight: 700;
|
|
4770
|
-
border-radius: 3px;
|
|
4771
|
-
text-transform: uppercase;
|
|
4772
|
-
color: white;
|
|
4773
|
-
}
|
|
4847
|
+
/* Row 4: Handshake History */
|
|
4848
|
+
.handshake-table {
|
|
4849
|
+
background-color: var(--surface);
|
|
4850
|
+
border: 1px solid var(--border);
|
|
4851
|
+
border-radius: 8px;
|
|
4852
|
+
overflow: hidden;
|
|
4853
|
+
}
|
|
4774
4854
|
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4855
|
+
.table-header {
|
|
4856
|
+
display: grid;
|
|
4857
|
+
grid-template-columns: 2fr 1fr 1fr 1fr 1.5fr 1.5fr;
|
|
4858
|
+
gap: 16px;
|
|
4859
|
+
padding: 16px 20px;
|
|
4860
|
+
border-bottom: 1px solid var(--border);
|
|
4861
|
+
background-color: var(--bg);
|
|
4862
|
+
font-size: 12px;
|
|
4863
|
+
font-weight: 600;
|
|
4864
|
+
color: var(--text-secondary);
|
|
4865
|
+
text-transform: uppercase;
|
|
4866
|
+
letter-spacing: 0.5px;
|
|
4867
|
+
}
|
|
4778
4868
|
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4869
|
+
.table-rows {
|
|
4870
|
+
max-height: 300px;
|
|
4871
|
+
overflow-y: auto;
|
|
4872
|
+
}
|
|
4782
4873
|
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4874
|
+
.table-row {
|
|
4875
|
+
display: grid;
|
|
4876
|
+
grid-template-columns: 2fr 1fr 1fr 1fr 1.5fr 1.5fr;
|
|
4877
|
+
gap: 16px;
|
|
4878
|
+
padding: 14px 20px;
|
|
4879
|
+
border-bottom: 1px solid var(--border);
|
|
4880
|
+
align-items: center;
|
|
4881
|
+
font-size: 12px;
|
|
4882
|
+
cursor: pointer;
|
|
4883
|
+
transition: background-color 0.2s;
|
|
4884
|
+
}
|
|
4787
4885
|
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
gap: 6px;
|
|
4792
|
-
font-size: 11px;
|
|
4793
|
-
font-family: var(--mono);
|
|
4794
|
-
color: var(--text-secondary);
|
|
4795
|
-
}
|
|
4886
|
+
.table-row:hover {
|
|
4887
|
+
background-color: var(--bg);
|
|
4888
|
+
}
|
|
4796
4889
|
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
background: rgba(48, 54, 61, 0.8);
|
|
4801
|
-
border-radius: 2px;
|
|
4802
|
-
overflow: hidden;
|
|
4803
|
-
}
|
|
4890
|
+
.table-row:last-child {
|
|
4891
|
+
border-bottom: none;
|
|
4892
|
+
}
|
|
4804
4893
|
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
}
|
|
4894
|
+
.table-cell {
|
|
4895
|
+
color: var(--text-secondary);
|
|
4896
|
+
font-family: 'JetBrains Mono', monospace;
|
|
4897
|
+
}
|
|
4810
4898
|
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4899
|
+
.table-cell.strong {
|
|
4900
|
+
color: var(--text-primary);
|
|
4901
|
+
font-weight: 500;
|
|
4902
|
+
}
|
|
4814
4903
|
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4904
|
+
.table-empty {
|
|
4905
|
+
padding: 40px 20px;
|
|
4906
|
+
text-align: center;
|
|
4907
|
+
color: var(--text-secondary);
|
|
4908
|
+
font-size: 13px;
|
|
4909
|
+
}
|
|
4819
4910
|
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4911
|
+
/* Pending Overlay */
|
|
4912
|
+
.pending-overlay {
|
|
4913
|
+
position: fixed;
|
|
4914
|
+
top: 0;
|
|
4915
|
+
right: -400px;
|
|
4916
|
+
width: 400px;
|
|
4917
|
+
height: 100vh;
|
|
4918
|
+
background-color: var(--surface);
|
|
4919
|
+
border-left: 1px solid var(--border);
|
|
4920
|
+
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.3);
|
|
4921
|
+
z-index: 200;
|
|
4922
|
+
transition: right 0.3s ease;
|
|
4923
|
+
display: flex;
|
|
4924
|
+
flex-direction: column;
|
|
4925
|
+
overflow-y: auto;
|
|
4926
|
+
}
|
|
4831
4927
|
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
}
|
|
4928
|
+
.pending-overlay.show {
|
|
4929
|
+
right: 0;
|
|
4930
|
+
}
|
|
4836
4931
|
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4932
|
+
.pending-header {
|
|
4933
|
+
padding: 16px 20px;
|
|
4934
|
+
border-bottom: 1px solid var(--border);
|
|
4935
|
+
font-weight: 600;
|
|
4936
|
+
color: var(--text-primary);
|
|
4937
|
+
}
|
|
4840
4938
|
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4939
|
+
.pending-items {
|
|
4940
|
+
flex: 1;
|
|
4941
|
+
overflow-y: auto;
|
|
4942
|
+
padding: 16px;
|
|
4943
|
+
}
|
|
4845
4944
|
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4945
|
+
.pending-item {
|
|
4946
|
+
background-color: var(--bg);
|
|
4947
|
+
border: 1px solid var(--border);
|
|
4948
|
+
border-radius: 6px;
|
|
4949
|
+
padding: 16px;
|
|
4950
|
+
margin-bottom: 12px;
|
|
4951
|
+
}
|
|
4849
4952
|
|
|
4850
|
-
|
|
4953
|
+
.pending-title {
|
|
4954
|
+
font-weight: 600;
|
|
4955
|
+
color: var(--text-primary);
|
|
4956
|
+
margin-bottom: 8px;
|
|
4957
|
+
word-break: break-word;
|
|
4958
|
+
}
|
|
4851
4959
|
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
border-top: 1px solid var(--border);
|
|
4859
|
-
max-height: 240px;
|
|
4860
|
-
z-index: 500;
|
|
4861
|
-
display: flex;
|
|
4862
|
-
flex-direction: column;
|
|
4863
|
-
transition: max-height 0.3s ease-out;
|
|
4864
|
-
}
|
|
4960
|
+
.pending-countdown {
|
|
4961
|
+
font-size: 12px;
|
|
4962
|
+
color: var(--amber);
|
|
4963
|
+
margin-bottom: 12px;
|
|
4964
|
+
font-weight: 500;
|
|
4965
|
+
}
|
|
4865
4966
|
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4967
|
+
.pending-actions {
|
|
4968
|
+
display: flex;
|
|
4969
|
+
gap: 8px;
|
|
4970
|
+
}
|
|
4869
4971
|
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
color: var(--text-secondary);
|
|
4881
|
-
flex: 0 0 auto;
|
|
4882
|
-
}
|
|
4972
|
+
.pending-btn {
|
|
4973
|
+
flex: 1;
|
|
4974
|
+
padding: 8px 12px;
|
|
4975
|
+
border: none;
|
|
4976
|
+
border-radius: 4px;
|
|
4977
|
+
font-size: 12px;
|
|
4978
|
+
font-weight: 600;
|
|
4979
|
+
cursor: pointer;
|
|
4980
|
+
transition: background-color 0.2s;
|
|
4981
|
+
}
|
|
4883
4982
|
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4983
|
+
.pending-approve {
|
|
4984
|
+
background-color: var(--green);
|
|
4985
|
+
color: var(--bg);
|
|
4986
|
+
}
|
|
4887
4987
|
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4988
|
+
.pending-approve:hover {
|
|
4989
|
+
background-color: #3fa040;
|
|
4990
|
+
}
|
|
4891
4991
|
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
display: flex;
|
|
4897
|
-
flex-direction: column;
|
|
4898
|
-
gap: 10px;
|
|
4899
|
-
}
|
|
4992
|
+
.pending-deny {
|
|
4993
|
+
background-color: var(--red);
|
|
4994
|
+
color: var(--bg);
|
|
4995
|
+
}
|
|
4900
4996
|
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
border-left: 2px solid var(--red);
|
|
4905
|
-
border-radius: 4px;
|
|
4906
|
-
font-size: 11px;
|
|
4907
|
-
color: var(--text-secondary);
|
|
4908
|
-
}
|
|
4997
|
+
.pending-deny:hover {
|
|
4998
|
+
background-color: #e03c3c;
|
|
4999
|
+
}
|
|
4909
5000
|
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
5001
|
+
/* Threat Panel */
|
|
5002
|
+
.threat-panel {
|
|
5003
|
+
background-color: var(--surface);
|
|
5004
|
+
border: 1px solid var(--border);
|
|
5005
|
+
border-radius: 8px;
|
|
5006
|
+
margin-top: 20px;
|
|
5007
|
+
overflow: hidden;
|
|
5008
|
+
}
|
|
4915
5009
|
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
5010
|
+
.threat-header {
|
|
5011
|
+
padding: 16px 20px;
|
|
5012
|
+
border-bottom: 1px solid var(--border);
|
|
5013
|
+
display: flex;
|
|
5014
|
+
justify-content: space-between;
|
|
5015
|
+
align-items: center;
|
|
5016
|
+
cursor: pointer;
|
|
5017
|
+
user-select: none;
|
|
5018
|
+
}
|
|
4922
5019
|
|
|
4923
|
-
|
|
5020
|
+
.threat-title {
|
|
5021
|
+
font-weight: 600;
|
|
5022
|
+
color: var(--text-primary);
|
|
5023
|
+
}
|
|
4924
5024
|
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
5025
|
+
.threat-toggle {
|
|
5026
|
+
font-size: 10px;
|
|
5027
|
+
color: var(--text-secondary);
|
|
5028
|
+
transition: transform 0.2s;
|
|
5029
|
+
}
|
|
4928
5030
|
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
5031
|
+
.threat-panel.collapsed .threat-toggle {
|
|
5032
|
+
transform: rotate(-90deg);
|
|
5033
|
+
}
|
|
4932
5034
|
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
5035
|
+
.threat-content {
|
|
5036
|
+
padding: 16px 20px;
|
|
5037
|
+
max-height: 300px;
|
|
5038
|
+
overflow-y: auto;
|
|
5039
|
+
}
|
|
4937
5040
|
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
5041
|
+
.threat-panel.collapsed .threat-content {
|
|
5042
|
+
display: none;
|
|
5043
|
+
}
|
|
4941
5044
|
|
|
4942
|
-
|
|
5045
|
+
.threat-alert {
|
|
5046
|
+
background-color: rgba(248, 81, 73, 0.1);
|
|
5047
|
+
border: 1px solid var(--red);
|
|
5048
|
+
border-radius: 4px;
|
|
5049
|
+
padding: 12px;
|
|
5050
|
+
margin-bottom: 8px;
|
|
5051
|
+
font-size: 12px;
|
|
5052
|
+
}
|
|
4943
5053
|
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
display: none;
|
|
5054
|
+
.threat-alert:last-child {
|
|
5055
|
+
margin-bottom: 0;
|
|
4947
5056
|
}
|
|
4948
5057
|
|
|
4949
|
-
.
|
|
4950
|
-
|
|
5058
|
+
.threat-type {
|
|
5059
|
+
font-weight: 600;
|
|
5060
|
+
color: var(--red);
|
|
5061
|
+
margin-bottom: 4px;
|
|
5062
|
+
text-transform: uppercase;
|
|
5063
|
+
font-size: 10px;
|
|
5064
|
+
letter-spacing: 0.5px;
|
|
4951
5065
|
}
|
|
4952
|
-
}
|
|
4953
5066
|
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
padding: 0 12px;
|
|
4957
|
-
gap: 12px;
|
|
4958
|
-
height: 48px;
|
|
5067
|
+
.threat-message {
|
|
5068
|
+
color: var(--text-secondary);
|
|
4959
5069
|
}
|
|
4960
5070
|
|
|
4961
|
-
|
|
4962
|
-
|
|
5071
|
+
/* Scrollbar */
|
|
5072
|
+
::-webkit-scrollbar {
|
|
5073
|
+
width: 8px;
|
|
4963
5074
|
}
|
|
4964
5075
|
|
|
4965
|
-
|
|
4966
|
-
|
|
5076
|
+
::-webkit-scrollbar-track {
|
|
5077
|
+
background-color: transparent;
|
|
4967
5078
|
}
|
|
4968
5079
|
|
|
4969
|
-
|
|
4970
|
-
|
|
5080
|
+
::-webkit-scrollbar-thumb {
|
|
5081
|
+
background-color: var(--border);
|
|
5082
|
+
border-radius: 4px;
|
|
4971
5083
|
}
|
|
4972
5084
|
|
|
4973
|
-
|
|
4974
|
-
|
|
5085
|
+
::-webkit-scrollbar-thumb:hover {
|
|
5086
|
+
background-color: var(--text-secondary);
|
|
4975
5087
|
}
|
|
4976
5088
|
|
|
4977
|
-
|
|
4978
|
-
|
|
5089
|
+
/* Responsive */
|
|
5090
|
+
@media (max-width: 1400px) {
|
|
5091
|
+
.sovereignty-layers {
|
|
5092
|
+
grid-template-columns: repeat(2, 1fr);
|
|
5093
|
+
}
|
|
5094
|
+
|
|
5095
|
+
.main-panels {
|
|
5096
|
+
grid-template-columns: 1fr;
|
|
5097
|
+
}
|
|
5098
|
+
|
|
5099
|
+
.pending-overlay {
|
|
5100
|
+
width: 100%;
|
|
5101
|
+
right: -100%;
|
|
5102
|
+
}
|
|
4979
5103
|
}
|
|
4980
5104
|
|
|
4981
|
-
|
|
4982
|
-
|
|
5105
|
+
@media (max-width: 768px) {
|
|
5106
|
+
.status-bar {
|
|
5107
|
+
flex-wrap: wrap;
|
|
5108
|
+
height: auto;
|
|
5109
|
+
padding: 12px;
|
|
5110
|
+
gap: 12px;
|
|
5111
|
+
}
|
|
5112
|
+
|
|
5113
|
+
.status-bar-center {
|
|
5114
|
+
order: 3;
|
|
5115
|
+
flex-basis: 100%;
|
|
5116
|
+
}
|
|
5117
|
+
|
|
5118
|
+
.main-content {
|
|
5119
|
+
margin-top: auto;
|
|
5120
|
+
}
|
|
5121
|
+
|
|
5122
|
+
.info-cards {
|
|
5123
|
+
grid-template-columns: 1fr;
|
|
5124
|
+
}
|
|
5125
|
+
|
|
5126
|
+
.table-header,
|
|
5127
|
+
.table-row {
|
|
5128
|
+
grid-template-columns: 1fr;
|
|
5129
|
+
}
|
|
4983
5130
|
}
|
|
4984
|
-
|
|
4985
|
-
</style>
|
|
5131
|
+
</style>
|
|
4986
5132
|
</head>
|
|
4987
5133
|
<body>
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
<div class="status-bar">
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
<div class="status-bar-center">
|
|
4996
|
-
<div class="sovereignty-badge">
|
|
4997
|
-
<div class="sovereignty-score" id="sovereigntyScore">85</div>
|
|
4998
|
-
<span>Sovereignty Health</span>
|
|
4999
|
-
</div>
|
|
5000
|
-
</div>
|
|
5001
|
-
<div class="status-bar-right">
|
|
5002
|
-
<div class="protections-indicator">
|
|
5003
|
-
<span class="count" id="activeProtections">6</span>/6 protections
|
|
5004
|
-
</div>
|
|
5005
|
-
<div class="uptime">
|
|
5006
|
-
<span id="uptimeText">\u2014</span>
|
|
5007
|
-
</div>
|
|
5008
|
-
<div class="status-dot" id="statusDot"></div>
|
|
5009
|
-
<div class="pending-badge hidden" id="pendingBadge">0</div>
|
|
5010
|
-
</div>
|
|
5011
|
-
</div>
|
|
5012
|
-
|
|
5013
|
-
<!-- Main Layout -->
|
|
5014
|
-
<div class="main-container">
|
|
5015
|
-
<!-- Activity Feed -->
|
|
5016
|
-
<div class="activity-feed">
|
|
5017
|
-
<div class="feed-header">
|
|
5018
|
-
<div class="feed-header-dot"></div>
|
|
5019
|
-
Live Activity
|
|
5020
|
-
</div>
|
|
5021
|
-
<div class="activity-list" id="activityList">
|
|
5022
|
-
<div class="activity-empty">
|
|
5023
|
-
<div class="activity-empty-icon">\u2192</div>
|
|
5024
|
-
<div class="activity-empty-text">Waiting for activity...</div>
|
|
5134
|
+
<!-- Status Bar -->
|
|
5135
|
+
<div class="status-bar">
|
|
5136
|
+
<div class="status-bar-left">
|
|
5137
|
+
<div class="logo-icon">\u25C6</div>
|
|
5138
|
+
<div class="logo-info">
|
|
5139
|
+
<div class="logo-title">SANCTUARY</div>
|
|
5140
|
+
<div class="logo-version">v${options.serverVersion}</div>
|
|
5025
5141
|
</div>
|
|
5026
5142
|
</div>
|
|
5027
|
-
</div>
|
|
5028
5143
|
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5144
|
+
<div class="status-bar-center">
|
|
5145
|
+
<div id="sovereignty-badge" class="sovereignty-badge">
|
|
5146
|
+
<span>Sovereignty Health:</span>
|
|
5147
|
+
<span class="sovereignty-score" id="sovereignty-score">\u2014</span>
|
|
5148
|
+
<span>/ 100</span>
|
|
5149
|
+
</div>
|
|
5033
5150
|
</div>
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
<
|
|
5038
|
-
<
|
|
5039
|
-
<div class="protection-card-stat" id="encryptionStat">Ed25519</div>
|
|
5151
|
+
|
|
5152
|
+
<div class="status-bar-right">
|
|
5153
|
+
<div class="status-item">
|
|
5154
|
+
<strong id="protections-count">\u2014</strong>
|
|
5155
|
+
<span>Protections</span>
|
|
5040
5156
|
</div>
|
|
5157
|
+
<div class="status-item">
|
|
5158
|
+
<strong id="uptime-value">\u2014</strong>
|
|
5159
|
+
<span>Uptime</span>
|
|
5160
|
+
</div>
|
|
5161
|
+
<div class="status-dot" id="connection-status"></div>
|
|
5162
|
+
<div id="pending-item-badge" class="pending-badge" style="display: none;">
|
|
5163
|
+
<span>\u23F3</span>
|
|
5164
|
+
<span id="pending-count">0</span>
|
|
5165
|
+
</div>
|
|
5166
|
+
</div>
|
|
5167
|
+
</div>
|
|
5041
5168
|
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5169
|
+
<!-- Main Content -->
|
|
5170
|
+
<div class="main-content">
|
|
5171
|
+
<div class="grid">
|
|
5172
|
+
<!-- Row 1: Sovereignty Layers -->
|
|
5173
|
+
<div class="sovereignty-layers" id="sovereignty-layers">
|
|
5174
|
+
<div class="layer-card" data-layer="l1">
|
|
5175
|
+
<div class="layer-name">Layer 1</div>
|
|
5176
|
+
<div class="layer-title">Cognitive Sovereignty</div>
|
|
5177
|
+
<div class="layer-status"><span>\u25CF</span> <span id="l1-status">\u2014</span></div>
|
|
5178
|
+
<div class="layer-detail" id="l1-detail">Loading...</div>
|
|
5179
|
+
</div>
|
|
5180
|
+
<div class="layer-card" data-layer="l2">
|
|
5181
|
+
<div class="layer-name">Layer 2</div>
|
|
5182
|
+
<div class="layer-title">Operational Isolation</div>
|
|
5183
|
+
<div class="layer-status"><span>\u25CF</span> <span id="l2-status">\u2014</span></div>
|
|
5184
|
+
<div class="layer-detail" id="l2-detail">Loading...</div>
|
|
5185
|
+
</div>
|
|
5186
|
+
<div class="layer-card" data-layer="l3">
|
|
5187
|
+
<div class="layer-name">Layer 3</div>
|
|
5188
|
+
<div class="layer-title">Selective Disclosure</div>
|
|
5189
|
+
<div class="layer-status"><span>\u25CF</span> <span id="l3-status">\u2014</span></div>
|
|
5190
|
+
<div class="layer-detail" id="l3-detail">Loading...</div>
|
|
5191
|
+
</div>
|
|
5192
|
+
<div class="layer-card" data-layer="l4">
|
|
5193
|
+
<div class="layer-name">Layer 4</div>
|
|
5194
|
+
<div class="layer-title">Verifiable Reputation</div>
|
|
5195
|
+
<div class="layer-status"><span>\u25CF</span> <span id="l4-status">\u2014</span></div>
|
|
5196
|
+
<div class="layer-detail" id="l4-detail">Loading...</div>
|
|
5197
|
+
</div>
|
|
5047
5198
|
</div>
|
|
5048
5199
|
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
<div class="
|
|
5052
|
-
|
|
5053
|
-
|
|
5200
|
+
<!-- Row 2: Info Cards -->
|
|
5201
|
+
<div class="info-cards">
|
|
5202
|
+
<div class="info-card">
|
|
5203
|
+
<div class="card-header">Identity</div>
|
|
5204
|
+
<div class="card-row">
|
|
5205
|
+
<span class="card-label">Primary</span>
|
|
5206
|
+
<span class="card-value" id="identity-label">\u2014</span>
|
|
5207
|
+
</div>
|
|
5208
|
+
<div class="card-row">
|
|
5209
|
+
<span class="card-label">DID</span>
|
|
5210
|
+
<span class="card-value truncated" id="identity-did" title="">\u2014</span>
|
|
5211
|
+
</div>
|
|
5212
|
+
<div class="card-row">
|
|
5213
|
+
<span class="card-label">Public Key</span>
|
|
5214
|
+
<span class="card-value truncated" id="identity-pubkey" title="">\u2014</span>
|
|
5215
|
+
</div>
|
|
5216
|
+
<div class="card-row">
|
|
5217
|
+
<span class="card-label">Type</span>
|
|
5218
|
+
<span class="identity-badge">Ed25519</span>
|
|
5219
|
+
</div>
|
|
5220
|
+
<div class="card-row">
|
|
5221
|
+
<span class="card-label">Created</span>
|
|
5222
|
+
<span class="card-value" id="identity-created">\u2014</span>
|
|
5223
|
+
</div>
|
|
5224
|
+
<div class="card-row">
|
|
5225
|
+
<span class="card-label">Identities</span>
|
|
5226
|
+
<span class="card-value" id="identity-count">\u2014</span>
|
|
5227
|
+
</div>
|
|
5228
|
+
</div>
|
|
5229
|
+
|
|
5230
|
+
<div class="info-card">
|
|
5231
|
+
<div class="card-header">Handshakes</div>
|
|
5232
|
+
<div class="card-row">
|
|
5233
|
+
<span class="card-label">Total</span>
|
|
5234
|
+
<span class="card-value" id="handshake-count">\u2014</span>
|
|
5235
|
+
</div>
|
|
5236
|
+
<div class="card-row">
|
|
5237
|
+
<span class="card-label">Latest Peer</span>
|
|
5238
|
+
<span class="card-value truncated" id="handshake-latest">\u2014</span>
|
|
5239
|
+
</div>
|
|
5240
|
+
<div class="card-row">
|
|
5241
|
+
<span class="card-label">Trust Tier</span>
|
|
5242
|
+
<span class="trust-tier-badge" id="handshake-tier">Unverified</span>
|
|
5243
|
+
</div>
|
|
5244
|
+
<div class="card-row">
|
|
5245
|
+
<span class="card-label">Timestamp</span>
|
|
5246
|
+
<span class="card-value" id="handshake-time">\u2014</span>
|
|
5247
|
+
</div>
|
|
5248
|
+
</div>
|
|
5249
|
+
|
|
5250
|
+
<div class="info-card">
|
|
5251
|
+
<div class="card-header">Reputation</div>
|
|
5252
|
+
<div class="card-row">
|
|
5253
|
+
<span class="card-label">Weighted Score</span>
|
|
5254
|
+
<span class="card-value" id="reputation-score">\u2014</span>
|
|
5255
|
+
</div>
|
|
5256
|
+
<div class="card-row">
|
|
5257
|
+
<span class="card-label">Attestations</span>
|
|
5258
|
+
<span class="card-value" id="reputation-attestations">\u2014</span>
|
|
5259
|
+
</div>
|
|
5260
|
+
<div class="card-row">
|
|
5261
|
+
<span class="card-label">Verified Sovereign</span>
|
|
5262
|
+
<span class="card-value" id="reputation-verified">\u2014</span>
|
|
5263
|
+
</div>
|
|
5264
|
+
<div class="card-row">
|
|
5265
|
+
<span class="card-label">Verified Degraded</span>
|
|
5266
|
+
<span class="card-value" id="reputation-degraded">\u2014</span>
|
|
5267
|
+
</div>
|
|
5268
|
+
<div class="card-row">
|
|
5269
|
+
<span class="card-label">Unverified</span>
|
|
5270
|
+
<span class="card-value" id="reputation-unverified">\u2014</span>
|
|
5271
|
+
</div>
|
|
5272
|
+
</div>
|
|
5054
5273
|
</div>
|
|
5055
5274
|
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
<div class="
|
|
5059
|
-
|
|
5060
|
-
|
|
5275
|
+
<!-- Row 3: SHR & Activity -->
|
|
5276
|
+
<div class="main-panels">
|
|
5277
|
+
<div class="panel">
|
|
5278
|
+
<div class="panel-header">
|
|
5279
|
+
<div class="panel-title">Sovereignty Health Report</div>
|
|
5280
|
+
<button class="panel-action" id="copy-shr-btn">Copy JSON</button>
|
|
5281
|
+
</div>
|
|
5282
|
+
<div class="panel-content">
|
|
5283
|
+
<div class="shr-json" id="shr-viewer">
|
|
5284
|
+
<div class="empty-state">Loading SHR...</div>
|
|
5285
|
+
</div>
|
|
5286
|
+
</div>
|
|
5287
|
+
</div>
|
|
5288
|
+
|
|
5289
|
+
<div class="panel">
|
|
5290
|
+
<div class="panel-header">
|
|
5291
|
+
<div class="panel-title">Activity Feed</div>
|
|
5292
|
+
</div>
|
|
5293
|
+
<div class="panel-content">
|
|
5294
|
+
<div id="activity-feed" class="activity-feed">
|
|
5295
|
+
<div class="empty-state">Waiting for activity...</div>
|
|
5296
|
+
</div>
|
|
5297
|
+
</div>
|
|
5298
|
+
</div>
|
|
5061
5299
|
</div>
|
|
5062
5300
|
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
<div class="
|
|
5066
|
-
|
|
5067
|
-
|
|
5301
|
+
<!-- Row 4: Handshake History -->
|
|
5302
|
+
<div class="handshake-table">
|
|
5303
|
+
<div class="table-header">
|
|
5304
|
+
<div>Counterparty</div>
|
|
5305
|
+
<div>Trust Tier</div>
|
|
5306
|
+
<div>Sovereignty</div>
|
|
5307
|
+
<div>Verified</div>
|
|
5308
|
+
<div>Completed</div>
|
|
5309
|
+
<div>Expires</div>
|
|
5310
|
+
</div>
|
|
5311
|
+
<div class="table-rows" id="handshake-table">
|
|
5312
|
+
<div class="table-empty">No handshakes completed yet</div>
|
|
5313
|
+
</div>
|
|
5068
5314
|
</div>
|
|
5069
5315
|
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
<div class="
|
|
5073
|
-
|
|
5074
|
-
|
|
5316
|
+
<!-- Threat Panel -->
|
|
5317
|
+
<div class="threat-panel collapsed">
|
|
5318
|
+
<div class="threat-header">
|
|
5319
|
+
<div class="threat-title">Security Threats</div>
|
|
5320
|
+
<div class="threat-toggle">\u25B6</div>
|
|
5321
|
+
</div>
|
|
5322
|
+
<div class="threat-content" id="threat-alerts">
|
|
5323
|
+
<div class="empty-state">No threats detected</div>
|
|
5324
|
+
</div>
|
|
5075
5325
|
</div>
|
|
5076
5326
|
</div>
|
|
5077
5327
|
</div>
|
|
5078
|
-
</div>
|
|
5079
5328
|
|
|
5080
|
-
<!-- Pending
|
|
5081
|
-
<div class="pending-overlay" id="
|
|
5082
|
-
|
|
5083
|
-
<div class="pending-
|
|
5084
|
-
<button class="pending-overlay-close" onclick="closePendingOverlay()">\xD7</button>
|
|
5329
|
+
<!-- Pending Overlay -->
|
|
5330
|
+
<div class="pending-overlay" id="pending-overlay">
|
|
5331
|
+
<div class="pending-header">Pending Approvals</div>
|
|
5332
|
+
<div class="pending-items" id="pending-items"></div>
|
|
5085
5333
|
</div>
|
|
5086
|
-
<div class="pending-list" id="pendingList"></div>
|
|
5087
|
-
</div>
|
|
5088
|
-
|
|
5089
|
-
<!-- Threat Panel (collapsible footer) -->
|
|
5090
|
-
<div class="threat-panel collapsed" id="threatPanel">
|
|
5091
|
-
<div class="threat-header" onclick="toggleThreatPanel()">
|
|
5092
|
-
<span class="threat-icon">\u26A0</span>
|
|
5093
|
-
Recent Threats
|
|
5094
|
-
<span id="threatCount" style="margin-left: auto; color: var(--red); font-weight: 700;">0</span>
|
|
5095
|
-
</div>
|
|
5096
|
-
<div class="threat-content" id="threatContent">
|
|
5097
|
-
<div class="threat-empty">No threats detected</div>
|
|
5098
|
-
</div>
|
|
5099
|
-
</div>
|
|
5100
5334
|
|
|
5101
|
-
<script>
|
|
5102
|
-
|
|
5103
|
-
|
|
5335
|
+
<script>
|
|
5336
|
+
// Constants
|
|
5337
|
+
const AUTH_TOKEN = '${options.authToken || ""}' || sessionStorage.getItem('authToken') || '';
|
|
5338
|
+
const TIMEOUT_SECONDS = ${options.timeoutSeconds};
|
|
5339
|
+
const API_BASE = '';
|
|
5340
|
+
|
|
5341
|
+
// State
|
|
5342
|
+
let apiState = {
|
|
5343
|
+
sovereignty: null,
|
|
5344
|
+
identity: null,
|
|
5345
|
+
handshakes: [],
|
|
5346
|
+
shr: null,
|
|
5347
|
+
status: null,
|
|
5348
|
+
};
|
|
5104
5349
|
|
|
5105
|
-
|
|
5350
|
+
let pendingRequests = new Map();
|
|
5351
|
+
let activityLog = [];
|
|
5352
|
+
const maxActivityItems = 50;
|
|
5106
5353
|
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5354
|
+
// Helpers
|
|
5355
|
+
function esc(text) {
|
|
5356
|
+
if (!text) return '';
|
|
5357
|
+
const div = document.createElement('div');
|
|
5358
|
+
div.textContent = text;
|
|
5359
|
+
return div.innerHTML;
|
|
5360
|
+
}
|
|
5361
|
+
|
|
5362
|
+
function formatTime(isoString) {
|
|
5363
|
+
if (!isoString) return '\u2014';
|
|
5364
|
+
const date = new Date(isoString);
|
|
5365
|
+
return date.toLocaleString('en-US', {
|
|
5366
|
+
month: 'short',
|
|
5367
|
+
day: 'numeric',
|
|
5368
|
+
hour: '2-digit',
|
|
5369
|
+
minute: '2-digit',
|
|
5370
|
+
});
|
|
5371
|
+
}
|
|
5113
5372
|
|
|
5114
|
-
|
|
5373
|
+
function truncate(str, len = 16) {
|
|
5374
|
+
if (!str) return '\u2014';
|
|
5375
|
+
if (str.length <= len) return str;
|
|
5376
|
+
return str.slice(0, len) + '...';
|
|
5377
|
+
}
|
|
5115
5378
|
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
let threatCount = 0;
|
|
5121
|
-
const pendingRequests = new Map();
|
|
5122
|
-
const activityItems = [];
|
|
5123
|
-
const threatItems = [];
|
|
5124
|
-
let sovereigntyScore = 85;
|
|
5125
|
-
let sessionRenewalTimer = null;
|
|
5379
|
+
function calculateSovereigntyScore(shr) {
|
|
5380
|
+
if (!shr || !shr.layers) return 0;
|
|
5381
|
+
const layers = shr.layers;
|
|
5382
|
+
let score = 100;
|
|
5126
5383
|
|
|
5127
|
-
|
|
5384
|
+
if (layers.l1?.status === 'degraded') score -= 20;
|
|
5385
|
+
if (layers.l1?.status === 'inactive') score -= 35;
|
|
5386
|
+
if (layers.l2?.status === 'degraded') score -= 15;
|
|
5387
|
+
if (layers.l2?.status === 'inactive') score -= 25;
|
|
5388
|
+
if (layers.l3?.status === 'degraded') score -= 15;
|
|
5389
|
+
if (layers.l3?.status === 'inactive') score -= 25;
|
|
5390
|
+
if (layers.l4?.status === 'degraded') score -= 10;
|
|
5391
|
+
if (layers.l4?.status === 'inactive') score -= 20;
|
|
5128
5392
|
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
if (AUTH_TOKEN) h['Authorization'] = 'Bearer ' + AUTH_TOKEN;
|
|
5132
|
-
return h;
|
|
5133
|
-
}
|
|
5393
|
+
return Math.max(0, Math.min(100, score));
|
|
5394
|
+
}
|
|
5134
5395
|
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5396
|
+
async function fetchAPI(endpoint) {
|
|
5397
|
+
try {
|
|
5398
|
+
const response = await fetch(API_BASE + endpoint, {
|
|
5399
|
+
headers: {
|
|
5400
|
+
'Authorization': 'Bearer ' + AUTH_TOKEN,
|
|
5401
|
+
},
|
|
5402
|
+
});
|
|
5140
5403
|
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5404
|
+
if (response.status === 401) {
|
|
5405
|
+
redirectToLogin();
|
|
5406
|
+
return null;
|
|
5407
|
+
}
|
|
5145
5408
|
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
// Schedule renewal at 80% of TTL
|
|
5157
|
-
if (sessionRenewalTimer) clearTimeout(sessionRenewalTimer);
|
|
5158
|
-
sessionRenewalTimer = setTimeout(function() {
|
|
5159
|
-
exchangeSession().then(function() { reconnectSSE(); });
|
|
5160
|
-
}, ttl * 800);
|
|
5161
|
-
} else if (resp.status === 401) {
|
|
5162
|
-
// Token invalid or expired \u2014 show non-destructive re-login overlay
|
|
5163
|
-
showSessionExpired();
|
|
5164
|
-
}
|
|
5165
|
-
} catch (e) {
|
|
5166
|
-
// Network error \u2014 retry in 30s
|
|
5167
|
-
if (sessionRenewalTimer) clearTimeout(sessionRenewalTimer);
|
|
5168
|
-
sessionRenewalTimer = setTimeout(function() {
|
|
5169
|
-
exchangeSession().then(function() { reconnectSSE(); });
|
|
5170
|
-
}, 30000);
|
|
5171
|
-
}
|
|
5172
|
-
}
|
|
5173
|
-
|
|
5174
|
-
function showSessionExpired() {
|
|
5175
|
-
// Clear stored token
|
|
5176
|
-
try { sessionStorage.removeItem('sanctuary_token'); } catch(_) {}
|
|
5177
|
-
// Redirect to login page
|
|
5178
|
-
document.cookie = 'sanctuary_session=; path=/; max-age=0';
|
|
5179
|
-
window.location.reload();
|
|
5180
|
-
}
|
|
5181
|
-
|
|
5182
|
-
// \u2500\u2500 UI Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5183
|
-
|
|
5184
|
-
function esc(s) {
|
|
5185
|
-
const d = document.createElement('div');
|
|
5186
|
-
d.textContent = String(s || '');
|
|
5187
|
-
return d.innerHTML;
|
|
5188
|
-
}
|
|
5189
|
-
|
|
5190
|
-
function closePendingOverlay() {
|
|
5191
|
-
document.getElementById('pendingOverlay').classList.remove('active');
|
|
5192
|
-
}
|
|
5193
|
-
|
|
5194
|
-
function toggleThreatPanel() {
|
|
5195
|
-
document.getElementById('threatPanel').classList.toggle('collapsed');
|
|
5196
|
-
}
|
|
5197
|
-
|
|
5198
|
-
function updateUptime() {
|
|
5199
|
-
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
|
5200
|
-
const hours = Math.floor(elapsed / 3600);
|
|
5201
|
-
const mins = Math.floor((elapsed % 3600) / 60);
|
|
5202
|
-
const secs = elapsed % 60;
|
|
5203
|
-
let uptimeStr = '';
|
|
5204
|
-
if (hours > 0) uptimeStr += hours + 'h ';
|
|
5205
|
-
if (mins > 0) uptimeStr += mins + 'm ';
|
|
5206
|
-
uptimeStr += secs + 's';
|
|
5207
|
-
document.getElementById('uptimeText').textContent = uptimeStr;
|
|
5208
|
-
}
|
|
5209
|
-
|
|
5210
|
-
// \u2500\u2500 Sovereignty Score \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5211
|
-
|
|
5212
|
-
function updateSovereigntyScore(score) {
|
|
5213
|
-
sovereigntyScore = Math.min(100, Math.max(0, score || 85));
|
|
5214
|
-
const badge = document.getElementById('sovereigntyScore');
|
|
5215
|
-
badge.textContent = sovereigntyScore;
|
|
5216
|
-
badge.className = 'sovereignty-score';
|
|
5217
|
-
if (sovereigntyScore >= 80) {
|
|
5218
|
-
badge.classList.add('high');
|
|
5219
|
-
} else if (sovereigntyScore >= 50) {
|
|
5220
|
-
badge.classList.add('medium');
|
|
5221
|
-
} else {
|
|
5222
|
-
badge.classList.add('low');
|
|
5409
|
+
if (!response.ok) {
|
|
5410
|
+
console.error('API Error:', response.status);
|
|
5411
|
+
return null;
|
|
5412
|
+
}
|
|
5413
|
+
|
|
5414
|
+
return await response.json();
|
|
5415
|
+
} catch (err) {
|
|
5416
|
+
console.error('Fetch error:', err);
|
|
5417
|
+
return null;
|
|
5418
|
+
}
|
|
5223
5419
|
}
|
|
5224
|
-
}
|
|
5225
5420
|
|
|
5226
|
-
|
|
5421
|
+
function redirectToLogin() {
|
|
5422
|
+
sessionStorage.removeItem('authToken');
|
|
5423
|
+
window.location.href = '/';
|
|
5424
|
+
}
|
|
5227
5425
|
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
tool,
|
|
5233
|
-
outcome,
|
|
5234
|
-
detail,
|
|
5235
|
-
hasInjection,
|
|
5236
|
-
isContextGated
|
|
5237
|
-
} = data;
|
|
5238
|
-
|
|
5239
|
-
const item = {
|
|
5240
|
-
id: 'activity-' + activityCount++,
|
|
5241
|
-
timestamp: timestamp || new Date().toISOString(),
|
|
5242
|
-
tier: tier || 1,
|
|
5243
|
-
tool: tool || 'unknown_tool',
|
|
5244
|
-
outcome: outcome || 'executed',
|
|
5245
|
-
detail: detail || '',
|
|
5246
|
-
hasInjection: !!hasInjection,
|
|
5247
|
-
isContextGated: !!isContextGated
|
|
5248
|
-
};
|
|
5426
|
+
// API Updates
|
|
5427
|
+
async function updateSovereignty() {
|
|
5428
|
+
const data = await fetchAPI('/api/sovereignty');
|
|
5429
|
+
if (!data) return;
|
|
5249
5430
|
|
|
5250
|
-
|
|
5251
|
-
if (activityItems.length > MAX_ACTIVITY_ITEMS) {
|
|
5252
|
-
activityItems.pop();
|
|
5253
|
-
}
|
|
5431
|
+
apiState.sovereignty = data;
|
|
5254
5432
|
|
|
5255
|
-
|
|
5256
|
-
|
|
5433
|
+
const score = calculateSovereigntyScore(data.shr);
|
|
5434
|
+
const badge = document.getElementById('sovereignty-badge');
|
|
5435
|
+
const scoreEl = document.getElementById('sovereignty-score');
|
|
5257
5436
|
|
|
5258
|
-
|
|
5259
|
-
const list = document.getElementById('activityList');
|
|
5437
|
+
scoreEl.textContent = score;
|
|
5260
5438
|
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5439
|
+
badge.classList.remove('degraded', 'inactive');
|
|
5440
|
+
if (score < 70) badge.classList.add('degraded');
|
|
5441
|
+
if (score < 40) badge.classList.add('inactive');
|
|
5442
|
+
|
|
5443
|
+
updateLayerCards(data.shr);
|
|
5264
5444
|
}
|
|
5265
5445
|
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
const tr = document.createElement('div');
|
|
5269
|
-
tr.className = 'activity-item';
|
|
5270
|
-
tr.id = item.id;
|
|
5271
|
-
|
|
5272
|
-
const time = new Date(item.timestamp);
|
|
5273
|
-
const timeStr = time.toLocaleTimeString();
|
|
5274
|
-
|
|
5275
|
-
const tierClass = 't' + item.tier;
|
|
5276
|
-
const outcomeClass = item.outcome === 'denied' ? 'outcome denied' : 'outcome';
|
|
5277
|
-
|
|
5278
|
-
let icon = '\u25CF';
|
|
5279
|
-
if (item.isContextGated) icon = '\u{1F3AF}';
|
|
5280
|
-
else if (item.hasInjection) icon = '\u26A0';
|
|
5281
|
-
else if (item.outcome === 'denied') icon = '\u2717';
|
|
5282
|
-
else icon = '\u2713';
|
|
5283
|
-
|
|
5284
|
-
tr.innerHTML =
|
|
5285
|
-
'<div class="activity-item-icon">' + esc(icon) + '</div>' +
|
|
5286
|
-
'<div class="activity-item-content">' +
|
|
5287
|
-
'<div class="activity-time">' + esc(timeStr) + '</div>' +
|
|
5288
|
-
'<div class="activity-main">' +
|
|
5289
|
-
'<span class="activity-tier ' + tierClass + '">T' + item.tier + '</span>' +
|
|
5290
|
-
'<span class="activity-tool">' + esc(item.tool) + '</span>' +
|
|
5291
|
-
'<span class="activity-outcome ' + (outcomeClass === 'outcome denied' ? 'denied' : '') + '">' + (item.outcome === 'denied' ? '\u2717 denied' : '\u2713 allowed') + '</span>' +
|
|
5292
|
-
'</div>' +
|
|
5293
|
-
'<div class="activity-detail">' + esc(item.detail) + '</div>' +
|
|
5294
|
-
'</div>' +
|
|
5295
|
-
'';
|
|
5296
|
-
|
|
5297
|
-
tr.addEventListener('click', () => {
|
|
5298
|
-
tr.classList.toggle('expanded');
|
|
5299
|
-
});
|
|
5446
|
+
function updateLayerCards(shr) {
|
|
5447
|
+
if (!shr || !shr.layers) return;
|
|
5300
5448
|
|
|
5301
|
-
|
|
5302
|
-
}
|
|
5303
|
-
}
|
|
5449
|
+
const layers = shr.layers;
|
|
5304
5450
|
|
|
5305
|
-
|
|
5451
|
+
updateLayerCard('l1', layers.l1, layers.l1?.encryption || 'AES-256-GCM');
|
|
5452
|
+
updateLayerCard('l2', layers.l2, layers.l2?.isolation_type || 'Process-level');
|
|
5453
|
+
updateLayerCard('l3', layers.l3, layers.l3?.proof_system || 'Schnorr-Pedersen');
|
|
5454
|
+
updateLayerCard('l4', layers.l4, layers.l4?.reputation_mode || 'Weighted');
|
|
5455
|
+
}
|
|
5306
5456
|
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
request_id,
|
|
5310
|
-
operation,
|
|
5311
|
-
tier,
|
|
5312
|
-
reason,
|
|
5313
|
-
context,
|
|
5314
|
-
timestamp
|
|
5315
|
-
} = data;
|
|
5316
|
-
|
|
5317
|
-
const pending = {
|
|
5318
|
-
id: request_id,
|
|
5319
|
-
operation: operation || 'unknown',
|
|
5320
|
-
tier: tier || 1,
|
|
5321
|
-
reason: reason || '',
|
|
5322
|
-
context: context || {},
|
|
5323
|
-
timestamp: timestamp || new Date().toISOString(),
|
|
5324
|
-
remaining: TIMEOUT_SECONDS
|
|
5325
|
-
};
|
|
5457
|
+
function updateLayerCard(layer, layerData, detail) {
|
|
5458
|
+
if (!layerData) return;
|
|
5326
5459
|
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
}
|
|
5460
|
+
const card = document.querySelector(\`[data-layer="\${layer}"]\`);
|
|
5461
|
+
if (!card) return;
|
|
5330
5462
|
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
updatePendingUI();
|
|
5334
|
-
}
|
|
5463
|
+
const status = layerData.status || 'inactive';
|
|
5464
|
+
card.classList.remove('degraded', 'inactive');
|
|
5335
5465
|
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5466
|
+
if (status === 'degraded') {
|
|
5467
|
+
card.classList.add('degraded');
|
|
5468
|
+
} else if (status === 'inactive') {
|
|
5469
|
+
card.classList.add('inactive');
|
|
5470
|
+
}
|
|
5339
5471
|
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
badge.textContent = count;
|
|
5343
|
-
document.getElementById('pendingOverlay').classList.add('active');
|
|
5344
|
-
} else {
|
|
5345
|
-
badge.classList.add('hidden');
|
|
5346
|
-
document.getElementById('pendingOverlay').classList.remove('active');
|
|
5472
|
+
document.getElementById(\`\${layer}-status\`).textContent = status.toUpperCase();
|
|
5473
|
+
document.getElementById(\`\${layer}-detail\`).textContent = detail;
|
|
5347
5474
|
}
|
|
5348
5475
|
|
|
5349
|
-
|
|
5350
|
-
|
|
5476
|
+
async function updateIdentity() {
|
|
5477
|
+
const data = await fetchAPI('/api/identity');
|
|
5478
|
+
if (!data) return;
|
|
5351
5479
|
|
|
5352
|
-
|
|
5353
|
-
const list = document.getElementById('pendingList');
|
|
5354
|
-
list.innerHTML = '';
|
|
5480
|
+
apiState.identity = data;
|
|
5355
5481
|
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5482
|
+
const primary = data.primary || {};
|
|
5483
|
+
document.getElementById('identity-label').textContent = primary.label || '\u2014';
|
|
5484
|
+
document.getElementById('identity-did').textContent = truncate(primary.did, 24);
|
|
5485
|
+
document.getElementById('identity-did').title = primary.did || '';
|
|
5486
|
+
document.getElementById('identity-pubkey').textContent = truncate(primary.publicKey, 24);
|
|
5487
|
+
document.getElementById('identity-pubkey').title = primary.publicKey || '';
|
|
5488
|
+
document.getElementById('identity-created').textContent = formatTime(primary.createdAt);
|
|
5489
|
+
document.getElementById('identity-count').textContent = data.identities?.length || '\u2014';
|
|
5490
|
+
}
|
|
5359
5491
|
|
|
5360
|
-
|
|
5361
|
-
const
|
|
5362
|
-
|
|
5363
|
-
const isUrgent = req.remaining <= 30;
|
|
5492
|
+
async function updateHandshakes() {
|
|
5493
|
+
const data = await fetchAPI('/api/handshakes');
|
|
5494
|
+
if (!data) return;
|
|
5364
5495
|
|
|
5365
|
-
|
|
5366
|
-
'<div class="pending-item-header">' +
|
|
5367
|
-
'<div class="pending-item-op">' + esc(req.operation) + '</div>' +
|
|
5368
|
-
'<div class="pending-item-tier ' + tierClass + '">T' + tier + '</div>' +
|
|
5369
|
-
'</div>' +
|
|
5370
|
-
'<div class="pending-item-reason">' + esc(req.reason) + '</div>' +
|
|
5371
|
-
'<div class="pending-item-timer ' + (isUrgent ? 'urgent' : '') + '">' +
|
|
5372
|
-
'<div class="pending-item-timer-bar">' +
|
|
5373
|
-
'<div class="pending-item-timer-fill" style="width: ' + pct + '%"></div>' +
|
|
5374
|
-
'</div>' +
|
|
5375
|
-
'<span id="timer-' + id + '">' + req.remaining + 's</span>' +
|
|
5376
|
-
'</div>' +
|
|
5377
|
-
'<div class="pending-item-actions">' +
|
|
5378
|
-
'<button class="btn btn-approve" onclick="handleApprove('' + id + '')">Approve</button>' +
|
|
5379
|
-
'<button class="btn btn-deny" onclick="handleDeny('' + id + '')">Deny</button>' +
|
|
5380
|
-
'</div>' +
|
|
5381
|
-
'';
|
|
5496
|
+
apiState.handshakes = data.handshakes || [];
|
|
5382
5497
|
|
|
5383
|
-
|
|
5384
|
-
}
|
|
5385
|
-
}
|
|
5498
|
+
document.getElementById('handshake-count').textContent = data.handshakes?.length || '0';
|
|
5386
5499
|
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5500
|
+
if (data.handshakes && data.handshakes.length > 0) {
|
|
5501
|
+
const latest = data.handshakes[0];
|
|
5502
|
+
document.getElementById('handshake-latest').textContent = truncate(latest.counterpartyId, 20);
|
|
5503
|
+
document.getElementById('handshake-latest').title = latest.counterpartyId || '';
|
|
5504
|
+
document.getElementById('handshake-tier').textContent = (latest.trustTier || 'Unverified').toUpperCase();
|
|
5505
|
+
document.getElementById('handshake-time').textContent = formatTime(latest.completedAt);
|
|
5506
|
+
} else {
|
|
5507
|
+
document.getElementById('handshake-latest').textContent = '\u2014';
|
|
5508
|
+
document.getElementById('handshake-tier').textContent = 'Unverified';
|
|
5509
|
+
document.getElementById('handshake-time').textContent = '\u2014';
|
|
5510
|
+
}
|
|
5392
5511
|
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
removePendingRequest(id);
|
|
5396
|
-
}).catch(() => {});
|
|
5397
|
-
};
|
|
5512
|
+
updateHandshakeTable(data.handshakes || []);
|
|
5513
|
+
}
|
|
5398
5514
|
|
|
5399
|
-
|
|
5515
|
+
function updateHandshakeTable(handshakes) {
|
|
5516
|
+
const table = document.getElementById('handshake-table');
|
|
5400
5517
|
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
type,
|
|
5406
|
-
details
|
|
5407
|
-
} = data;
|
|
5408
|
-
|
|
5409
|
-
const threat = {
|
|
5410
|
-
id: 'threat-' + threatCount++,
|
|
5411
|
-
timestamp: timestamp || new Date().toISOString(),
|
|
5412
|
-
severity: severity || 'medium',
|
|
5413
|
-
type: type || 'unknown',
|
|
5414
|
-
details: details || ''
|
|
5415
|
-
};
|
|
5518
|
+
if (!handshakes || handshakes.length === 0) {
|
|
5519
|
+
table.innerHTML = '<div class="table-empty">No handshakes completed yet</div>';
|
|
5520
|
+
return;
|
|
5521
|
+
}
|
|
5416
5522
|
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5523
|
+
table.innerHTML = handshakes
|
|
5524
|
+
.map(
|
|
5525
|
+
(hs) => \`
|
|
5526
|
+
<div class="table-row">
|
|
5527
|
+
<div class="table-cell strong">\${esc(truncate(hs.counterpartyId, 24))}</div>
|
|
5528
|
+
<div class="table-cell">\${esc(hs.trustTier || 'Unverified')}</div>
|
|
5529
|
+
<div class="table-cell">\${esc(hs.sovereigntyLevel || '\u2014')}</div>
|
|
5530
|
+
<div class="table-cell">\${hs.verified ? 'Yes' : 'No'}</div>
|
|
5531
|
+
<div class="table-cell">\${formatTime(hs.completedAt)}</div>
|
|
5532
|
+
<div class="table-cell">\${formatTime(hs.expiresAt)}</div>
|
|
5533
|
+
</div>
|
|
5534
|
+
\`
|
|
5535
|
+
)
|
|
5536
|
+
.join('');
|
|
5420
5537
|
}
|
|
5421
5538
|
|
|
5422
|
-
|
|
5423
|
-
|
|
5539
|
+
async function updateSHR() {
|
|
5540
|
+
const data = await fetchAPI('/api/shr');
|
|
5541
|
+
if (!data) return;
|
|
5542
|
+
|
|
5543
|
+
apiState.shr = data;
|
|
5544
|
+
renderSHRViewer(data);
|
|
5424
5545
|
}
|
|
5425
5546
|
|
|
5426
|
-
|
|
5427
|
-
|
|
5547
|
+
function renderSHRViewer(shr) {
|
|
5548
|
+
const viewer = document.getElementById('shr-viewer');
|
|
5428
5549
|
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5550
|
+
if (!shr) {
|
|
5551
|
+
viewer.innerHTML = '<div class="empty-state">No SHR available</div>';
|
|
5552
|
+
return;
|
|
5553
|
+
}
|
|
5432
5554
|
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5555
|
+
let html = '';
|
|
5556
|
+
|
|
5557
|
+
// Implementation
|
|
5558
|
+
html += \`
|
|
5559
|
+
<div class="shr-section">
|
|
5560
|
+
<div class="shr-section-header">
|
|
5561
|
+
<div class="shr-toggle">\u25BC</div>
|
|
5562
|
+
<div>Implementation</div>
|
|
5563
|
+
</div>
|
|
5564
|
+
<div class="shr-section-content">
|
|
5565
|
+
<div class="shr-item">
|
|
5566
|
+
<div class="shr-key">sanctuary_version:</div>
|
|
5567
|
+
<div class="shr-value">\${esc(shr.implementation?.sanctuary_version || '\u2014')}</div>
|
|
5568
|
+
</div>
|
|
5569
|
+
<div class="shr-item">
|
|
5570
|
+
<div class="shr-key">node_version:</div>
|
|
5571
|
+
<div class="shr-value">\${esc(shr.implementation?.node_version || '\u2014')}</div>
|
|
5572
|
+
</div>
|
|
5573
|
+
<div class="shr-item">
|
|
5574
|
+
<div class="shr-key">generated_by:</div>
|
|
5575
|
+
<div class="shr-value">\${esc(shr.implementation?.generated_by || '\u2014')}</div>
|
|
5576
|
+
</div>
|
|
5577
|
+
</div>
|
|
5578
|
+
</div>
|
|
5579
|
+
\`;
|
|
5580
|
+
|
|
5581
|
+
// Metadata
|
|
5582
|
+
html += \`
|
|
5583
|
+
<div class="shr-section">
|
|
5584
|
+
<div class="shr-section-header">
|
|
5585
|
+
<div class="shr-toggle">\u25BC</div>
|
|
5586
|
+
<div>Metadata</div>
|
|
5587
|
+
</div>
|
|
5588
|
+
<div class="shr-section-content">
|
|
5589
|
+
<div class="shr-item">
|
|
5590
|
+
<div class="shr-key">instance_id:</div>
|
|
5591
|
+
<div class="shr-value">\${esc(truncate(shr.instance_id, 20))}</div>
|
|
5592
|
+
</div>
|
|
5593
|
+
<div class="shr-item">
|
|
5594
|
+
<div class="shr-key">generated_at:</div>
|
|
5595
|
+
<div class="shr-value">\${formatTime(shr.generated_at)}</div>
|
|
5596
|
+
</div>
|
|
5597
|
+
<div class="shr-item">
|
|
5598
|
+
<div class="shr-key">expires_at:</div>
|
|
5599
|
+
<div class="shr-value">\${formatTime(shr.expires_at)}</div>
|
|
5600
|
+
</div>
|
|
5601
|
+
</div>
|
|
5602
|
+
</div>
|
|
5603
|
+
\`;
|
|
5604
|
+
|
|
5605
|
+
// Layers
|
|
5606
|
+
if (shr.layers) {
|
|
5607
|
+
html += \`<div class="shr-section">
|
|
5608
|
+
<div class="shr-section-header">
|
|
5609
|
+
<div class="shr-toggle">\u25BC</div>
|
|
5610
|
+
<div>Layers</div>
|
|
5611
|
+
</div>
|
|
5612
|
+
<div class="shr-section-content">
|
|
5613
|
+
\`;
|
|
5614
|
+
|
|
5615
|
+
for (const [key, layer] of Object.entries(shr.layers)) {
|
|
5616
|
+
html += \`
|
|
5617
|
+
<div style="margin-bottom: 12px;">
|
|
5618
|
+
<div style="color: var(--blue); font-weight: 600; margin-bottom: 4px;">\${esc(key)}</div>
|
|
5619
|
+
<div style="padding-left: 12px;">
|
|
5620
|
+
\`;
|
|
5621
|
+
|
|
5622
|
+
for (const [lkey, lvalue] of Object.entries(layer || {})) {
|
|
5623
|
+
const displayValue =
|
|
5624
|
+
typeof lvalue === 'boolean'
|
|
5625
|
+
? lvalue
|
|
5626
|
+
? 'true'
|
|
5627
|
+
: 'false'
|
|
5628
|
+
: esc(String(lvalue));
|
|
5629
|
+
html += \`
|
|
5630
|
+
<div class="shr-item">
|
|
5631
|
+
<div class="shr-key">\${esc(lkey)}:</div>
|
|
5632
|
+
<div class="shr-value">\${displayValue}</div>
|
|
5633
|
+
</div>
|
|
5634
|
+
\`;
|
|
5635
|
+
}
|
|
5438
5636
|
|
|
5439
|
-
|
|
5440
|
-
|
|
5637
|
+
html += \`
|
|
5638
|
+
</div>
|
|
5639
|
+
</div>
|
|
5640
|
+
\`;
|
|
5641
|
+
}
|
|
5441
5642
|
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5643
|
+
html += \`
|
|
5644
|
+
</div>
|
|
5645
|
+
</div>
|
|
5646
|
+
\`;
|
|
5647
|
+
}
|
|
5648
|
+
|
|
5649
|
+
// Capabilities
|
|
5650
|
+
if (shr.capabilities) {
|
|
5651
|
+
html += \`
|
|
5652
|
+
<div class="shr-section">
|
|
5653
|
+
<div class="shr-section-header">
|
|
5654
|
+
<div class="shr-toggle">\u25BC</div>
|
|
5655
|
+
<div>Capabilities</div>
|
|
5656
|
+
</div>
|
|
5657
|
+
<div class="shr-section-content">
|
|
5658
|
+
\`;
|
|
5659
|
+
|
|
5660
|
+
for (const [key, value] of Object.entries(shr.capabilities)) {
|
|
5661
|
+
const displayValue = value ? 'true' : 'false';
|
|
5662
|
+
html += \`
|
|
5663
|
+
<div class="shr-item">
|
|
5664
|
+
<div class="shr-key">\${esc(key)}:</div>
|
|
5665
|
+
<div class="shr-value">\${displayValue}</div>
|
|
5666
|
+
</div>
|
|
5667
|
+
\`;
|
|
5668
|
+
}
|
|
5669
|
+
|
|
5670
|
+
html += \`
|
|
5671
|
+
</div>
|
|
5672
|
+
</div>
|
|
5673
|
+
\`;
|
|
5674
|
+
}
|
|
5675
|
+
|
|
5676
|
+
// Signature
|
|
5677
|
+
html += \`
|
|
5678
|
+
<div class="shr-section">
|
|
5679
|
+
<div class="shr-section-header">
|
|
5680
|
+
<div class="shr-toggle">\u25BC</div>
|
|
5681
|
+
<div>Signature</div>
|
|
5682
|
+
</div>
|
|
5683
|
+
<div class="shr-section-content">
|
|
5684
|
+
<div class="shr-item">
|
|
5685
|
+
<div class="shr-key">signed_by:</div>
|
|
5686
|
+
<div class="shr-value">\${esc(truncate(shr.signed_by, 20))}</div>
|
|
5687
|
+
</div>
|
|
5688
|
+
<div class="shr-item">
|
|
5689
|
+
<div class="shr-key">signature:</div>
|
|
5690
|
+
<div class="shr-value">\${esc(truncate(shr.signature, 32))}</div>
|
|
5691
|
+
</div>
|
|
5692
|
+
</div>
|
|
5693
|
+
</div>
|
|
5694
|
+
\`;
|
|
5695
|
+
|
|
5696
|
+
viewer.innerHTML = html;
|
|
5697
|
+
|
|
5698
|
+
// Add collapse functionality
|
|
5699
|
+
document.querySelectorAll('.shr-section-header').forEach((header) => {
|
|
5700
|
+
header.addEventListener('click', () => {
|
|
5701
|
+
header.closest('.shr-section').classList.toggle('collapsed');
|
|
5702
|
+
});
|
|
5703
|
+
});
|
|
5454
5704
|
}
|
|
5455
|
-
}
|
|
5456
5705
|
|
|
5457
|
-
|
|
5706
|
+
async function updateStatus() {
|
|
5707
|
+
const data = await fetchAPI('/api/status');
|
|
5708
|
+
if (!data) return;
|
|
5458
5709
|
|
|
5459
|
-
|
|
5460
|
-
if (evtSource) evtSource.close();
|
|
5461
|
-
connect();
|
|
5462
|
-
}
|
|
5710
|
+
apiState.status = data;
|
|
5463
5711
|
|
|
5464
|
-
|
|
5465
|
-
|
|
5712
|
+
document.getElementById('protections-count').textContent = data.protectionsCount || '0';
|
|
5713
|
+
document.getElementById('uptime-value').textContent = formatUptime(data.uptime);
|
|
5466
5714
|
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
}
|
|
5715
|
+
const connectionStatus = document.getElementById('connection-status');
|
|
5716
|
+
connectionStatus.classList.toggle('disconnected', !data.connected);
|
|
5717
|
+
}
|
|
5470
5718
|
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5719
|
+
function formatUptime(seconds) {
|
|
5720
|
+
if (!seconds) return '\u2014';
|
|
5721
|
+
const hours = Math.floor(seconds / 3600);
|
|
5722
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
5723
|
+
if (hours > 0) return \`\${hours}h \${minutes}m\`;
|
|
5724
|
+
return \`\${minutes}m\`;
|
|
5725
|
+
}
|
|
5474
5726
|
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
}
|
|
5483
|
-
if (data.pending) {
|
|
5484
|
-
data.pending.forEach(addPendingRequest);
|
|
5485
|
-
}
|
|
5486
|
-
});
|
|
5727
|
+
// SSE Setup
|
|
5728
|
+
function setupSSE() {
|
|
5729
|
+
const eventSource = new EventSource(API_BASE + '/api/events', {
|
|
5730
|
+
headers: {
|
|
5731
|
+
'Authorization': 'Bearer ' + AUTH_TOKEN,
|
|
5732
|
+
},
|
|
5733
|
+
});
|
|
5487
5734
|
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
});
|
|
5735
|
+
eventSource.addEventListener('init', (e) => {
|
|
5736
|
+
console.log('Connected to SSE');
|
|
5737
|
+
});
|
|
5492
5738
|
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
});
|
|
5739
|
+
eventSource.addEventListener('sovereignty-update', () => {
|
|
5740
|
+
updateSovereignty();
|
|
5741
|
+
});
|
|
5497
5742
|
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
addActivityItem({
|
|
5501
|
-
timestamp: data.timestamp,
|
|
5502
|
-
tier: data.tier || 1,
|
|
5503
|
-
tool: data.tool || 'unknown',
|
|
5504
|
-
outcome: data.outcome || 'executed',
|
|
5505
|
-
detail: data.detail || ''
|
|
5743
|
+
eventSource.addEventListener('handshake-update', () => {
|
|
5744
|
+
updateHandshakes();
|
|
5506
5745
|
});
|
|
5507
|
-
});
|
|
5508
5746
|
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
isContextGated: true
|
|
5747
|
+
eventSource.addEventListener('tool-call', (e) => {
|
|
5748
|
+
const data = JSON.parse(e.data);
|
|
5749
|
+
addActivityItem({
|
|
5750
|
+
type: 'tool-call',
|
|
5751
|
+
title: 'Tool Call',
|
|
5752
|
+
content: data.toolName,
|
|
5753
|
+
timestamp: new Date().toISOString(),
|
|
5754
|
+
});
|
|
5518
5755
|
});
|
|
5519
|
-
});
|
|
5520
5756
|
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
hasInjection: true
|
|
5757
|
+
eventSource.addEventListener('context-gate-decision', (e) => {
|
|
5758
|
+
const data = JSON.parse(e.data);
|
|
5759
|
+
addActivityItem({
|
|
5760
|
+
type: 'context-gate',
|
|
5761
|
+
title: 'Context Gate',
|
|
5762
|
+
content: data.decision,
|
|
5763
|
+
timestamp: new Date().toISOString(),
|
|
5764
|
+
});
|
|
5530
5765
|
});
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5766
|
+
|
|
5767
|
+
eventSource.addEventListener('injection-alert', (e) => {
|
|
5768
|
+
const data = JSON.parse(e.data);
|
|
5769
|
+
addActivityItem({
|
|
5770
|
+
type: 'injection',
|
|
5771
|
+
title: 'Injection Alert',
|
|
5772
|
+
content: data.pattern,
|
|
5773
|
+
timestamp: new Date().toISOString(),
|
|
5774
|
+
});
|
|
5775
|
+
addThreatAlert(data);
|
|
5536
5776
|
});
|
|
5537
|
-
});
|
|
5538
5777
|
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5778
|
+
eventSource.addEventListener('pending-request', (e) => {
|
|
5779
|
+
const data = JSON.parse(e.data);
|
|
5780
|
+
addPendingRequest(data);
|
|
5781
|
+
});
|
|
5543
5782
|
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5783
|
+
eventSource.addEventListener('request-resolved', (e) => {
|
|
5784
|
+
const data = JSON.parse(e.data);
|
|
5785
|
+
removePendingRequest(data.requestId);
|
|
5786
|
+
});
|
|
5548
5787
|
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5788
|
+
eventSource.onerror = () => {
|
|
5789
|
+
console.error('SSE error');
|
|
5790
|
+
setTimeout(setupSSE, 5000);
|
|
5791
|
+
};
|
|
5792
|
+
}
|
|
5554
5793
|
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5794
|
+
// Activity Feed
|
|
5795
|
+
function addActivityItem(item) {
|
|
5796
|
+
activityLog.unshift(item);
|
|
5797
|
+
if (activityLog.length > maxActivityItems) {
|
|
5798
|
+
activityLog.pop();
|
|
5799
|
+
}
|
|
5559
5800
|
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5801
|
+
const feed = document.getElementById('activity-feed');
|
|
5802
|
+
const html = \`
|
|
5803
|
+
<div class="activity-item \${item.type}">
|
|
5804
|
+
<div class="activity-type">\${esc(item.title)}</div>
|
|
5805
|
+
<div class="activity-content">\${esc(item.content)}</div>
|
|
5806
|
+
<div class="activity-time">\${formatTime(item.timestamp)}</div>
|
|
5807
|
+
</div>
|
|
5808
|
+
\`;
|
|
5567
5809
|
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
const el = document.getElementById('encryptionStatus');
|
|
5578
|
-
el.className = 'protection-card-status ' + (status.encryption ? 'active' : 'inactive');
|
|
5579
|
-
el.textContent = status.encryption ? '\u2713 Active' : '\u2717 Inactive';
|
|
5580
|
-
}
|
|
5581
|
-
if (status.approval_gate !== undefined) {
|
|
5582
|
-
const el = document.getElementById('approvalStatus');
|
|
5583
|
-
el.className = 'protection-card-status ' + (status.approval_gate ? 'active' : 'inactive');
|
|
5584
|
-
el.textContent = status.approval_gate ? '\u2713 Active' : '\u2717 Inactive';
|
|
5585
|
-
}
|
|
5586
|
-
if (status.context_gating !== undefined) {
|
|
5587
|
-
const el = document.getElementById('contextStatus');
|
|
5588
|
-
el.className = 'protection-card-status ' + (status.context_gating ? 'active' : 'inactive');
|
|
5589
|
-
el.textContent = status.context_gating ? '\u2713 Active' : '\u2717 Inactive';
|
|
5590
|
-
}
|
|
5591
|
-
if (status.injection_detection !== undefined) {
|
|
5592
|
-
const el = document.getElementById('injectionStatus');
|
|
5593
|
-
el.className = 'protection-card-status ' + (status.injection_detection ? 'active' : 'inactive');
|
|
5594
|
-
el.textContent = status.injection_detection ? '\u2713 Active' : '\u2717 Inactive';
|
|
5810
|
+
if (feed.querySelector('.empty-state')) {
|
|
5811
|
+
feed.innerHTML = '';
|
|
5812
|
+
}
|
|
5813
|
+
|
|
5814
|
+
feed.insertAdjacentHTML('afterbegin', html);
|
|
5815
|
+
|
|
5816
|
+
if (feed.children.length > maxActivityItems) {
|
|
5817
|
+
feed.lastChild.remove();
|
|
5818
|
+
}
|
|
5595
5819
|
}
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5820
|
+
|
|
5821
|
+
// Pending Requests
|
|
5822
|
+
function addPendingRequest(request) {
|
|
5823
|
+
pendingRequests.set(request.requestId, {
|
|
5824
|
+
id: request.requestId,
|
|
5825
|
+
title: request.title,
|
|
5826
|
+
details: request.details,
|
|
5827
|
+
expiresAt: new Date(Date.now() + TIMEOUT_SECONDS * 1000),
|
|
5828
|
+
});
|
|
5829
|
+
|
|
5830
|
+
updatePendingDisplay();
|
|
5600
5831
|
}
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5832
|
+
|
|
5833
|
+
function removePendingRequest(requestId) {
|
|
5834
|
+
pendingRequests.delete(requestId);
|
|
5835
|
+
updatePendingDisplay();
|
|
5605
5836
|
}
|
|
5606
|
-
}
|
|
5607
5837
|
|
|
5608
|
-
|
|
5838
|
+
function updatePendingDisplay() {
|
|
5839
|
+
const badge = document.getElementById('pending-item-badge');
|
|
5840
|
+
const count = pendingRequests.size;
|
|
5841
|
+
|
|
5842
|
+
if (count > 0) {
|
|
5843
|
+
document.getElementById('pending-count').textContent = count;
|
|
5844
|
+
badge.style.display = 'flex';
|
|
5845
|
+
} else {
|
|
5846
|
+
badge.style.display = 'none';
|
|
5847
|
+
}
|
|
5848
|
+
|
|
5849
|
+
const overlay = document.getElementById('pending-overlay');
|
|
5850
|
+
const items = document.getElementById('pending-items');
|
|
5851
|
+
|
|
5852
|
+
if (count === 0) {
|
|
5853
|
+
items.innerHTML = '';
|
|
5854
|
+
overlay.classList.remove('show');
|
|
5855
|
+
return;
|
|
5856
|
+
}
|
|
5857
|
+
|
|
5858
|
+
let html = '';
|
|
5859
|
+
for (const req of pendingRequests.values()) {
|
|
5860
|
+
const remaining = Math.max(0, Math.floor((req.expiresAt - Date.now()) / 1000));
|
|
5861
|
+
html += \`
|
|
5862
|
+
<div class="pending-item">
|
|
5863
|
+
<div class="pending-title">\${esc(req.title)}</div>
|
|
5864
|
+
<div class="pending-countdown">Expires in \${remaining}s</div>
|
|
5865
|
+
<div class="pending-actions">
|
|
5866
|
+
<button class="pending-btn pending-approve" data-id="\${req.id}">Approve</button>
|
|
5867
|
+
<button class="pending-btn pending-deny" data-id="\${req.id}">Deny</button>
|
|
5868
|
+
</div>
|
|
5869
|
+
</div>
|
|
5870
|
+
\`;
|
|
5871
|
+
}
|
|
5872
|
+
|
|
5873
|
+
items.innerHTML = html;
|
|
5874
|
+
|
|
5875
|
+
document.querySelectorAll('.pending-approve').forEach((btn) => {
|
|
5876
|
+
btn.addEventListener('click', async () => {
|
|
5877
|
+
const id = btn.getAttribute('data-id');
|
|
5878
|
+
await fetchAPI(\`/api/approve/\${id}\`);
|
|
5879
|
+
});
|
|
5880
|
+
});
|
|
5609
5881
|
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5882
|
+
document.querySelectorAll('.pending-deny').forEach((btn) => {
|
|
5883
|
+
btn.addEventListener('click', async () => {
|
|
5884
|
+
const id = btn.getAttribute('data-id');
|
|
5885
|
+
await fetchAPI(\`/api/deny/\${id}\`);
|
|
5886
|
+
});
|
|
5887
|
+
});
|
|
5615
5888
|
}
|
|
5616
|
-
connect();
|
|
5617
5889
|
|
|
5618
|
-
//
|
|
5619
|
-
|
|
5620
|
-
|
|
5890
|
+
// Threat Panel
|
|
5891
|
+
function addThreatAlert(alert) {
|
|
5892
|
+
const panel = document.querySelector('.threat-panel');
|
|
5893
|
+
const content = document.getElementById('threat-alerts');
|
|
5621
5894
|
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
for (const [id, req] of pendingRequests) {
|
|
5625
|
-
req.remaining = Math.max(0, req.remaining - 1);
|
|
5626
|
-
const el = document.getElementById('timer-' + id);
|
|
5627
|
-
if (el) {
|
|
5628
|
-
el.textContent = req.remaining + 's';
|
|
5629
|
-
}
|
|
5895
|
+
if (content.querySelector('.empty-state')) {
|
|
5896
|
+
content.innerHTML = '';
|
|
5630
5897
|
}
|
|
5631
|
-
}, 1000);
|
|
5632
5898
|
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
const
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5899
|
+
panel.classList.remove('collapsed');
|
|
5900
|
+
|
|
5901
|
+
const html = \`
|
|
5902
|
+
<div class="threat-alert">
|
|
5903
|
+
<div class="threat-type">\${esc(alert.type || 'Injection Alert')}</div>
|
|
5904
|
+
<div class="threat-message">\${esc(alert.message || alert.pattern || '\u2014')}</div>
|
|
5905
|
+
</div>
|
|
5906
|
+
\`;
|
|
5907
|
+
|
|
5908
|
+
content.insertAdjacentHTML('afterbegin', html);
|
|
5909
|
+
|
|
5910
|
+
const alerts = content.querySelectorAll('.threat-alert');
|
|
5911
|
+
if (alerts.length > 10) {
|
|
5912
|
+
alerts[alerts.length - 1].remove();
|
|
5640
5913
|
}
|
|
5641
|
-
} catch (e) {
|
|
5642
|
-
// Ignore
|
|
5643
5914
|
}
|
|
5644
|
-
})();
|
|
5645
5915
|
|
|
5646
|
-
|
|
5647
|
-
|
|
5916
|
+
// Threat Panel Toggle
|
|
5917
|
+
document.querySelector('.threat-header').addEventListener('click', () => {
|
|
5918
|
+
document.querySelector('.threat-panel').classList.toggle('collapsed');
|
|
5919
|
+
});
|
|
5920
|
+
|
|
5921
|
+
// SHR Copy Button
|
|
5922
|
+
document.getElementById('copy-shr-btn').addEventListener('click', async () => {
|
|
5923
|
+
if (!apiState.shr) return;
|
|
5924
|
+
|
|
5925
|
+
const json = JSON.stringify(apiState.shr, null, 2);
|
|
5926
|
+
try {
|
|
5927
|
+
await navigator.clipboard.writeText(json);
|
|
5928
|
+
const btn = document.getElementById('copy-shr-btn');
|
|
5929
|
+
const original = btn.textContent;
|
|
5930
|
+
btn.textContent = 'Copied!';
|
|
5931
|
+
setTimeout(() => {
|
|
5932
|
+
btn.textContent = original;
|
|
5933
|
+
}, 2000);
|
|
5934
|
+
} catch (err) {
|
|
5935
|
+
console.error('Copy failed:', err);
|
|
5936
|
+
}
|
|
5937
|
+
});
|
|
5938
|
+
|
|
5939
|
+
// Pending Overlay Toggle
|
|
5940
|
+
document.getElementById('pending-item-badge').addEventListener('click', () => {
|
|
5941
|
+
document.getElementById('pending-overlay').classList.toggle('show');
|
|
5942
|
+
});
|
|
5943
|
+
|
|
5944
|
+
// Initialize
|
|
5945
|
+
async function initialize() {
|
|
5946
|
+
if (!AUTH_TOKEN) {
|
|
5947
|
+
redirectToLogin();
|
|
5948
|
+
return;
|
|
5949
|
+
}
|
|
5950
|
+
|
|
5951
|
+
// Initial data fetch
|
|
5952
|
+
await Promise.all([
|
|
5953
|
+
updateSovereignty(),
|
|
5954
|
+
updateIdentity(),
|
|
5955
|
+
updateHandshakes(),
|
|
5956
|
+
updateSHR(),
|
|
5957
|
+
updateStatus(),
|
|
5958
|
+
]);
|
|
5959
|
+
|
|
5960
|
+
// Setup SSE for real-time updates
|
|
5961
|
+
setupSSE();
|
|
5962
|
+
|
|
5963
|
+
// Refresh status periodically
|
|
5964
|
+
setInterval(updateStatus, 30000);
|
|
5965
|
+
}
|
|
5648
5966
|
|
|
5967
|
+
// Start
|
|
5968
|
+
initialize();
|
|
5969
|
+
</script>
|
|
5649
5970
|
</body>
|
|
5650
5971
|
</html>`;
|
|
5651
5972
|
}
|
|
@@ -8077,6 +8398,154 @@ function deriveTrustTier(level) {
|
|
|
8077
8398
|
}
|
|
8078
8399
|
}
|
|
8079
8400
|
|
|
8401
|
+
// src/handshake/attestation.ts
|
|
8402
|
+
init_encoding();
|
|
8403
|
+
init_encoding();
|
|
8404
|
+
var ATTESTATION_VERSION = "1.0";
|
|
8405
|
+
function deriveTrustTier2(level) {
|
|
8406
|
+
switch (level) {
|
|
8407
|
+
case "full":
|
|
8408
|
+
return "verified-sovereign";
|
|
8409
|
+
case "degraded":
|
|
8410
|
+
return "verified-degraded";
|
|
8411
|
+
default:
|
|
8412
|
+
return "unverified";
|
|
8413
|
+
}
|
|
8414
|
+
}
|
|
8415
|
+
function generateAttestation(opts) {
|
|
8416
|
+
const {
|
|
8417
|
+
attesterSHR,
|
|
8418
|
+
subjectSHR,
|
|
8419
|
+
verificationResult,
|
|
8420
|
+
mutual = false,
|
|
8421
|
+
identityManager,
|
|
8422
|
+
masterKey,
|
|
8423
|
+
identityId
|
|
8424
|
+
} = opts;
|
|
8425
|
+
const identity = identityId ? identityManager.get(identityId) : identityManager.getDefault();
|
|
8426
|
+
if (!identity) {
|
|
8427
|
+
return { error: "No identity available for signing attestation" };
|
|
8428
|
+
}
|
|
8429
|
+
const now = /* @__PURE__ */ new Date();
|
|
8430
|
+
const attesterExpiry = new Date(attesterSHR.body.expires_at);
|
|
8431
|
+
const subjectExpiry = new Date(subjectSHR.body.expires_at);
|
|
8432
|
+
const earliestExpiry = attesterExpiry < subjectExpiry ? attesterExpiry : subjectExpiry;
|
|
8433
|
+
const sovereigntyLevel = verificationResult.valid ? verificationResult.sovereignty_level : "unverified";
|
|
8434
|
+
const body = {
|
|
8435
|
+
attestation_version: ATTESTATION_VERSION,
|
|
8436
|
+
attester_id: attesterSHR.body.instance_id,
|
|
8437
|
+
subject_id: subjectSHR.body.instance_id,
|
|
8438
|
+
attester_shr: attesterSHR,
|
|
8439
|
+
subject_shr: subjectSHR,
|
|
8440
|
+
verification: {
|
|
8441
|
+
subject_shr_valid: verificationResult.valid,
|
|
8442
|
+
subject_sovereignty_level: sovereigntyLevel,
|
|
8443
|
+
subject_trust_tier: deriveTrustTier2(sovereigntyLevel),
|
|
8444
|
+
mutual,
|
|
8445
|
+
errors: verificationResult.errors,
|
|
8446
|
+
warnings: verificationResult.warnings
|
|
8447
|
+
},
|
|
8448
|
+
attested_at: now.toISOString(),
|
|
8449
|
+
expires_at: earliestExpiry.toISOString()
|
|
8450
|
+
};
|
|
8451
|
+
const canonical = JSON.stringify(deepSortKeys(body));
|
|
8452
|
+
const payload = stringToBytes(canonical);
|
|
8453
|
+
const encryptionKey = derivePurposeKey(masterKey, "identity-encryption");
|
|
8454
|
+
const signatureBytes = sign(
|
|
8455
|
+
payload,
|
|
8456
|
+
identity.encrypted_private_key,
|
|
8457
|
+
encryptionKey
|
|
8458
|
+
);
|
|
8459
|
+
const summary = generateSummary(body);
|
|
8460
|
+
return {
|
|
8461
|
+
body,
|
|
8462
|
+
signed_by: identity.public_key,
|
|
8463
|
+
signature: toBase64url(signatureBytes),
|
|
8464
|
+
summary
|
|
8465
|
+
};
|
|
8466
|
+
}
|
|
8467
|
+
function layerLine(label, status) {
|
|
8468
|
+
const icon = status === "active" ? "\u2713" : status === "degraded" ? "~" : "x";
|
|
8469
|
+
return ` ${icon} ${label}: ${status}`;
|
|
8470
|
+
}
|
|
8471
|
+
function generateSummary(body) {
|
|
8472
|
+
const v = body.verification;
|
|
8473
|
+
const sLayers = body.subject_shr.body.layers;
|
|
8474
|
+
const aLayers = body.attester_shr.body.layers;
|
|
8475
|
+
const tierLabel = v.subject_trust_tier === "verified-sovereign" ? "Verified Sovereign" : v.subject_trust_tier === "verified-degraded" ? "Verified (Degraded)" : "Unverified";
|
|
8476
|
+
const lines = [
|
|
8477
|
+
`--- Sovereignty Attestation ---`,
|
|
8478
|
+
``,
|
|
8479
|
+
`Attester: ${body.attester_id.slice(0, 16)}...`,
|
|
8480
|
+
`Subject: ${body.subject_id.slice(0, 16)}...`,
|
|
8481
|
+
`Result: ${tierLabel}`,
|
|
8482
|
+
``,
|
|
8483
|
+
`Subject Sovereignty Posture:`,
|
|
8484
|
+
layerLine("L1 Cognitive Sovereignty", sLayers.l1.status),
|
|
8485
|
+
layerLine("L2 Operational Isolation", sLayers.l2.status),
|
|
8486
|
+
layerLine("L3 Selective Disclosure", sLayers.l3.status),
|
|
8487
|
+
layerLine("L4 Verifiable Reputation", sLayers.l4.status),
|
|
8488
|
+
``,
|
|
8489
|
+
`Attester Sovereignty Posture:`,
|
|
8490
|
+
layerLine("L1 Cognitive Sovereignty", aLayers.l1.status),
|
|
8491
|
+
layerLine("L2 Operational Isolation", aLayers.l2.status),
|
|
8492
|
+
layerLine("L3 Selective Disclosure", aLayers.l3.status),
|
|
8493
|
+
layerLine("L4 Verifiable Reputation", aLayers.l4.status),
|
|
8494
|
+
``,
|
|
8495
|
+
`Mutual: ${v.mutual ? "Yes" : "One-sided"}`,
|
|
8496
|
+
`Attested: ${body.attested_at}`,
|
|
8497
|
+
`Expires: ${body.expires_at}`,
|
|
8498
|
+
`Signature: ${body.attestation_version} / Ed25519`
|
|
8499
|
+
];
|
|
8500
|
+
if (v.warnings.length > 0) {
|
|
8501
|
+
lines.push(``, `Warnings: ${v.warnings.join("; ")}`);
|
|
8502
|
+
}
|
|
8503
|
+
if (v.errors.length > 0) {
|
|
8504
|
+
lines.push(``, `Errors: ${v.errors.join("; ")}`);
|
|
8505
|
+
}
|
|
8506
|
+
lines.push(``, `--- Verify: compare signed_by against attester's known public key ---`);
|
|
8507
|
+
return lines.join("\n");
|
|
8508
|
+
}
|
|
8509
|
+
function verifyAttestation(attestation, now) {
|
|
8510
|
+
const errors = [];
|
|
8511
|
+
const currentTime = now ?? /* @__PURE__ */ new Date();
|
|
8512
|
+
if (attestation.body.attestation_version !== ATTESTATION_VERSION) {
|
|
8513
|
+
errors.push(
|
|
8514
|
+
`Unsupported attestation version: ${attestation.body.attestation_version}`
|
|
8515
|
+
);
|
|
8516
|
+
}
|
|
8517
|
+
if (!attestation.body.attester_id || !attestation.body.subject_id) {
|
|
8518
|
+
errors.push("Missing attester_id or subject_id");
|
|
8519
|
+
}
|
|
8520
|
+
if (!attestation.body.attester_shr || !attestation.body.subject_shr) {
|
|
8521
|
+
errors.push("Missing attester or subject SHR");
|
|
8522
|
+
}
|
|
8523
|
+
const expired = new Date(attestation.body.expires_at) <= currentTime;
|
|
8524
|
+
if (expired) {
|
|
8525
|
+
errors.push("Attestation has expired");
|
|
8526
|
+
}
|
|
8527
|
+
try {
|
|
8528
|
+
const publicKey = fromBase64url(attestation.signed_by);
|
|
8529
|
+
const canonical = JSON.stringify(deepSortKeys(attestation.body));
|
|
8530
|
+
const payload = stringToBytes(canonical);
|
|
8531
|
+
const signatureBytes = fromBase64url(attestation.signature);
|
|
8532
|
+
const signatureValid = verify(payload, signatureBytes, publicKey);
|
|
8533
|
+
if (!signatureValid) {
|
|
8534
|
+
errors.push("Attestation signature is invalid");
|
|
8535
|
+
}
|
|
8536
|
+
} catch (e) {
|
|
8537
|
+
errors.push(`Signature verification error: ${e.message}`);
|
|
8538
|
+
}
|
|
8539
|
+
return {
|
|
8540
|
+
valid: errors.length === 0,
|
|
8541
|
+
errors,
|
|
8542
|
+
attester_id: attestation.body.attester_id ?? "unknown",
|
|
8543
|
+
subject_id: attestation.body.subject_id ?? "unknown",
|
|
8544
|
+
trust_tier: errors.length === 0 ? attestation.body.verification.subject_trust_tier : "unverified",
|
|
8545
|
+
expired
|
|
8546
|
+
};
|
|
8547
|
+
}
|
|
8548
|
+
|
|
8080
8549
|
// src/handshake/tools.ts
|
|
8081
8550
|
function createHandshakeTools(config, identityManager, masterKey, auditLog) {
|
|
8082
8551
|
const sessions = /* @__PURE__ */ new Map();
|
|
@@ -8262,6 +8731,103 @@ function createHandshakeTools(config, identityManager, masterKey, auditLog) {
|
|
|
8262
8731
|
result: session.result ?? null
|
|
8263
8732
|
});
|
|
8264
8733
|
}
|
|
8734
|
+
},
|
|
8735
|
+
// ─── Streamlined Exchange ─────────────────────────────────────────
|
|
8736
|
+
{
|
|
8737
|
+
name: "sanctuary/handshake_exchange",
|
|
8738
|
+
description: "One-shot sovereignty exchange. Accepts a counterparty's signed SHR, verifies it, generates our SHR, and produces a signed attestation artifact \u2014 all in a single call. Returns a shareable attestation with human-readable summary. Use this instead of the 4-step handshake protocol when you want a quick, portable sovereignty verification (e.g., for social posting or async exchanges).",
|
|
8739
|
+
inputSchema: {
|
|
8740
|
+
type: "object",
|
|
8741
|
+
properties: {
|
|
8742
|
+
counterparty_shr: {
|
|
8743
|
+
type: "object",
|
|
8744
|
+
description: "The counterparty's signed SHR (SignedSHR object with body, signed_by, signature)."
|
|
8745
|
+
},
|
|
8746
|
+
identity_id: {
|
|
8747
|
+
type: "string",
|
|
8748
|
+
description: "Identity to use for the exchange. Defaults to primary identity."
|
|
8749
|
+
}
|
|
8750
|
+
},
|
|
8751
|
+
required: ["counterparty_shr"]
|
|
8752
|
+
},
|
|
8753
|
+
handler: async (args) => {
|
|
8754
|
+
const counterpartySHR = args.counterparty_shr;
|
|
8755
|
+
const ourSHR = generateSHR(args.identity_id, shrOpts);
|
|
8756
|
+
if (typeof ourSHR === "string") {
|
|
8757
|
+
return toolResult({ error: ourSHR });
|
|
8758
|
+
}
|
|
8759
|
+
const verificationResult = verifySHR(counterpartySHR);
|
|
8760
|
+
const attestation = generateAttestation({
|
|
8761
|
+
attesterSHR: ourSHR,
|
|
8762
|
+
subjectSHR: counterpartySHR,
|
|
8763
|
+
verificationResult,
|
|
8764
|
+
mutual: false,
|
|
8765
|
+
identityManager,
|
|
8766
|
+
masterKey,
|
|
8767
|
+
identityId: args.identity_id
|
|
8768
|
+
});
|
|
8769
|
+
if ("error" in attestation) {
|
|
8770
|
+
auditLog.append("l4", "handshake_exchange", ourSHR.body.instance_id, void 0, "failure");
|
|
8771
|
+
return toolResult({ error: attestation.error });
|
|
8772
|
+
}
|
|
8773
|
+
if (verificationResult.valid) {
|
|
8774
|
+
const sovereigntyLevel = verificationResult.sovereignty_level;
|
|
8775
|
+
const trustTier = sovereigntyLevel === "full" ? "verified-sovereign" : sovereigntyLevel === "degraded" ? "verified-degraded" : "unverified";
|
|
8776
|
+
handshakeResults.set(verificationResult.counterparty_id, {
|
|
8777
|
+
counterparty_id: verificationResult.counterparty_id,
|
|
8778
|
+
counterparty_shr: counterpartySHR,
|
|
8779
|
+
verified: true,
|
|
8780
|
+
sovereignty_level: sovereigntyLevel,
|
|
8781
|
+
trust_tier: trustTier,
|
|
8782
|
+
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8783
|
+
expires_at: verificationResult.expires_at,
|
|
8784
|
+
errors: []
|
|
8785
|
+
});
|
|
8786
|
+
}
|
|
8787
|
+
auditLog.append("l4", "handshake_exchange", ourSHR.body.instance_id);
|
|
8788
|
+
return toolResult({
|
|
8789
|
+
attestation,
|
|
8790
|
+
our_shr: ourSHR,
|
|
8791
|
+
verification: {
|
|
8792
|
+
counterparty_valid: verificationResult.valid,
|
|
8793
|
+
counterparty_sovereignty: verificationResult.sovereignty_level,
|
|
8794
|
+
counterparty_id: verificationResult.counterparty_id,
|
|
8795
|
+
errors: verificationResult.errors,
|
|
8796
|
+
warnings: verificationResult.warnings
|
|
8797
|
+
},
|
|
8798
|
+
instructions: "The 'attestation' object is a signed, portable sovereignty verification artifact. Share it with the counterparty or post attestation.summary publicly. The counterparty can verify the attestation signature using your public key. Our SHR is included so the counterparty can perform their own verification of us.",
|
|
8799
|
+
_content_trust: "external"
|
|
8800
|
+
});
|
|
8801
|
+
}
|
|
8802
|
+
},
|
|
8803
|
+
{
|
|
8804
|
+
name: "sanctuary/handshake_verify_attestation",
|
|
8805
|
+
description: "Verify a signed attestation artifact from another agent. Checks the Ed25519 signature, temporal validity, and structural integrity.",
|
|
8806
|
+
inputSchema: {
|
|
8807
|
+
type: "object",
|
|
8808
|
+
properties: {
|
|
8809
|
+
attestation: {
|
|
8810
|
+
type: "object",
|
|
8811
|
+
description: "The SignedAttestation object to verify (body, signed_by, signature, summary)."
|
|
8812
|
+
}
|
|
8813
|
+
},
|
|
8814
|
+
required: ["attestation"]
|
|
8815
|
+
},
|
|
8816
|
+
handler: async (args) => {
|
|
8817
|
+
const attestation = args.attestation;
|
|
8818
|
+
const result = verifyAttestation(attestation);
|
|
8819
|
+
auditLog.append(
|
|
8820
|
+
"l4",
|
|
8821
|
+
"handshake_verify_attestation",
|
|
8822
|
+
result.attester_id,
|
|
8823
|
+
void 0,
|
|
8824
|
+
result.valid ? "success" : "failure"
|
|
8825
|
+
);
|
|
8826
|
+
return toolResult({
|
|
8827
|
+
...result,
|
|
8828
|
+
_content_trust: "external"
|
|
8829
|
+
});
|
|
8830
|
+
}
|
|
8265
8831
|
}
|
|
8266
8832
|
];
|
|
8267
8833
|
return { tools, handshakeResults };
|
|
@@ -12219,6 +12785,6 @@ async function createSanctuaryServer(options) {
|
|
|
12219
12785
|
return { server, config };
|
|
12220
12786
|
}
|
|
12221
12787
|
|
|
12222
|
-
export { ApprovalGate, AuditLog, AutoApproveChannel, BaselineTracker, TEMPLATES as CONTEXT_GATE_TEMPLATES, CallbackApprovalChannel, CommitmentStore, ContextGateEnforcer, ContextGatePolicyStore, DashboardApprovalChannel, FederationRegistry, FilesystemStorage, InjectionDetector, MemoryStorage, PolicyStore, ReputationStore, StateStore, StderrApprovalChannel, TIER_WEIGHTS, WebhookApprovalChannel, canonicalize, classifyField, completeHandshake, computeWeightedScore, createBridgeCommitment, createPedersenCommitment, createProofOfKnowledge, createRangeProof, createSanctuaryServer, evaluateField, filterContext, generateSHR, getTemplate, initiateHandshake, listTemplateIds, loadConfig, loadPrincipalPolicy, recommendPolicy, resolveTier, respondToHandshake, signPayload, tierDistribution, verifyBridgeCommitment, verifyCompletion, verifyPedersenCommitment, verifyProofOfKnowledge, verifyRangeProof, verifySHR, verifySignature };
|
|
12788
|
+
export { ATTESTATION_VERSION, ApprovalGate, AuditLog, AutoApproveChannel, BaselineTracker, TEMPLATES as CONTEXT_GATE_TEMPLATES, CallbackApprovalChannel, CommitmentStore, ContextGateEnforcer, ContextGatePolicyStore, DashboardApprovalChannel, FederationRegistry, FilesystemStorage, InjectionDetector, MemoryStorage, PolicyStore, ReputationStore, StateStore, StderrApprovalChannel, TIER_WEIGHTS, WebhookApprovalChannel, canonicalize, classifyField, completeHandshake, computeWeightedScore, createBridgeCommitment, createPedersenCommitment, createProofOfKnowledge, createRangeProof, createSanctuaryServer, evaluateField, filterContext, generateAttestation, generateSHR, getTemplate, initiateHandshake, listTemplateIds, loadConfig, loadPrincipalPolicy, recommendPolicy, resolveTier, respondToHandshake, signPayload, tierDistribution, verifyAttestation, verifyBridgeCommitment, verifyCompletion, verifyPedersenCommitment, verifyProofOfKnowledge, verifyRangeProof, verifySHR, verifySignature };
|
|
12223
12789
|
//# sourceMappingURL=index.js.map
|
|
12224
12790
|
//# sourceMappingURL=index.js.map
|