total-recall-brain 3.46.2 → 3.47.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/total-recall.mjs +5 -0
- package/frontend/dist/assets/index-CpsWeV4X.css +1 -0
- package/frontend/dist/assets/{index-D1goIPjC.js → index-poecbHSl.js} +100 -100
- package/frontend/dist/brand/total-recall-lockup-transparent.png +0 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/dist/sw.js +1 -1
- package/frontend/src/App.tsx +15 -81
- package/frontend/src/components/DashboardOverview.tsx +164 -0
- package/frontend/src/components/brand/BrandMark.tsx +8 -6
- package/frontend/src/components/plugins/PluginWorkspace.tsx +112 -57
- package/frontend/src/components/workspace/PluginHome.tsx +3 -3
- package/frontend/src/index.css +43 -11
- package/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +30 -5
- package/scaffold/.agent/skills/total-recall/plugins/auth/skills/auth/SKILL.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +494 -79
- package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +33 -8
- package/scaffold/.agent/skills/total-recall/plugins/automations/skills/automations/SKILL.md +29 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/dream-consolidation.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +31 -4
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/skills/code-quality/SKILL.md +27 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +17 -3
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +24 -4
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/skills/embeddings/SKILL.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/git/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +300 -58
- package/scaffold/.agent/skills/total-recall/plugins/git/skills/git/SKILL.md +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +5 -33
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/git-fleet-ops.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/git-publish.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +47 -14
- package/scaffold/.agent/skills/total-recall/plugins/mesh/skills/mesh/SKILL.md +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +6 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +5 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +28 -9
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +7 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-selection.mjs +59 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +9 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +50 -6
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/session-controls.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +175 -17
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +242 -31
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/skills/openwiki/SKILL.md +32 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +41 -15
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +29 -22
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +20 -33
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/lint.mjs +42 -49
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/markdown-links.mjs +112 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +219 -65
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +21 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +51 -2
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +22 -5
- package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +169 -37
- package/scaffold/.agent/skills/total-recall/plugins/ssss/skills/ssss/SKILL.md +30 -0
- package/src/cli/context.mjs +6 -2
- package/src/cli/plugin/create.mjs +2 -1
- package/src/cli/plugin/monetization.mjs +66 -32
- package/src/cli/plugin/search.mjs +25 -3
- package/src/cli/preflight.mjs +40 -6
- package/src/core/context-compactor.mjs +2 -0
- package/src/core/gate-mode.mjs +13 -24
- package/src/core/plugin-distribution.mjs +35 -1
- package/src/core/preflight-gate.mjs +28 -8
- package/src/core/preflight-receipt.mjs +11 -0
- package/src/server/routes/vault.mjs +1 -0
- package/frontend/dist/assets/index-BRYE1jmv.css +0 -1
|
@@ -1,126 +1,514 @@
|
|
|
1
1
|
const template = document.createElement('template');
|
|
2
2
|
template.innerHTML = `
|
|
3
3
|
<style>
|
|
4
|
-
:host {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
4
|
+
:host {
|
|
5
|
+
display: block;
|
|
6
|
+
color: var(--color-text, #edf6f0);
|
|
7
|
+
font: 400 0.9rem/1.5 var(--typography-body-font-family, system-ui, -apple-system, sans-serif);
|
|
8
|
+
}
|
|
9
|
+
* { box-sizing: border-box; }
|
|
10
|
+
main {
|
|
11
|
+
background: linear-gradient(180deg, rgba(13, 25, 20, 0.96) 0%, rgba(9, 17, 14, 0.98) 100%);
|
|
12
|
+
border: 1px solid rgba(100, 227, 164, 0.22);
|
|
13
|
+
border-radius: 14px;
|
|
14
|
+
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.36);
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
}
|
|
17
|
+
.stats-strip {
|
|
18
|
+
display: grid;
|
|
19
|
+
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
|
|
20
|
+
gap: 12px;
|
|
21
|
+
padding: 16px clamp(14px, 3vw, 24px);
|
|
22
|
+
background: rgba(16, 33, 26, 0.55);
|
|
23
|
+
border-block-end: 1px solid rgba(100, 227, 164, 0.14);
|
|
24
|
+
}
|
|
25
|
+
.stat-card {
|
|
26
|
+
background: rgba(20, 38, 30, 0.72);
|
|
27
|
+
border: 1px solid rgba(100, 227, 164, 0.16);
|
|
28
|
+
border-radius: 10px;
|
|
29
|
+
padding: 12px 14px;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
gap: 4px;
|
|
33
|
+
}
|
|
34
|
+
.stat-label {
|
|
35
|
+
font-size: 0.72rem;
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
letter-spacing: 0.08em;
|
|
38
|
+
text-transform: uppercase;
|
|
39
|
+
color: var(--color-muted, #9ec0ac);
|
|
40
|
+
}
|
|
41
|
+
.stat-value {
|
|
42
|
+
font-size: 1.35rem;
|
|
43
|
+
font-weight: 700;
|
|
44
|
+
letter-spacing: -0.02em;
|
|
45
|
+
color: #f0fdf4;
|
|
46
|
+
font-variant-numeric: tabular-nums;
|
|
47
|
+
}
|
|
48
|
+
.stat-sub {
|
|
49
|
+
font-size: 0.78rem;
|
|
50
|
+
color: var(--color-muted, #9ec0ac);
|
|
51
|
+
}
|
|
52
|
+
nav {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-wrap: wrap;
|
|
55
|
+
align-items: center;
|
|
56
|
+
gap: 6px;
|
|
57
|
+
padding: 12px clamp(14px, 3vw, 24px);
|
|
58
|
+
border-block-end: 1px solid rgba(100, 227, 164, 0.16);
|
|
59
|
+
background: rgba(11, 22, 17, 0.75);
|
|
60
|
+
}
|
|
61
|
+
.body {
|
|
62
|
+
padding: clamp(16px, 3vw, 24px);
|
|
63
|
+
}
|
|
64
|
+
h2, h3, p { margin: 0; }
|
|
65
|
+
h2 { font-size: 1.08rem; font-weight: 650; }
|
|
66
|
+
.muted, th { color: var(--color-muted, #9ec0ac); }
|
|
67
|
+
button, input, select { font: inherit; color: inherit; }
|
|
68
|
+
button {
|
|
69
|
+
min-height: 38px;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
padding: 0 13px;
|
|
72
|
+
background: rgba(25, 45, 36, 0.9);
|
|
73
|
+
border: 1px solid rgba(100, 227, 164, 0.24);
|
|
74
|
+
border-radius: 8px;
|
|
75
|
+
font-weight: 500;
|
|
76
|
+
transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
|
|
77
|
+
}
|
|
78
|
+
button:hover:not(:disabled) {
|
|
79
|
+
background: rgba(34, 62, 49, 0.95);
|
|
80
|
+
border-color: rgba(100, 227, 164, 0.45);
|
|
81
|
+
}
|
|
82
|
+
button:disabled { opacity: 0.6; cursor: wait; }
|
|
83
|
+
button.primary {
|
|
84
|
+
background: rgba(16, 185, 129, 0.18);
|
|
85
|
+
border-color: rgba(52, 211, 153, 0.55);
|
|
86
|
+
color: #6ee7b7;
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
}
|
|
89
|
+
button.primary:hover:not(:disabled) {
|
|
90
|
+
background: rgba(16, 185, 129, 0.28);
|
|
91
|
+
}
|
|
92
|
+
button.danger {
|
|
93
|
+
color: #fca5a5;
|
|
94
|
+
border-color: rgba(248, 113, 113, 0.28);
|
|
95
|
+
background: rgba(127, 29, 29, 0.18);
|
|
96
|
+
}
|
|
97
|
+
button.danger:hover:not(:disabled) {
|
|
98
|
+
border-color: rgba(248, 113, 113, 0.55);
|
|
99
|
+
background: rgba(127, 29, 29, 0.34);
|
|
100
|
+
}
|
|
101
|
+
nav button[data-view] {
|
|
102
|
+
background: transparent;
|
|
103
|
+
border: 1px solid transparent;
|
|
104
|
+
border-radius: 8px;
|
|
105
|
+
color: var(--color-muted, #9ec0ac);
|
|
106
|
+
padding: 0 14px;
|
|
107
|
+
}
|
|
108
|
+
nav button[data-view][aria-pressed="true"] {
|
|
109
|
+
color: #6ee7b7;
|
|
110
|
+
background: rgba(16, 185, 129, 0.14);
|
|
111
|
+
border-color: rgba(52, 211, 153, 0.36);
|
|
112
|
+
font-weight: 600;
|
|
113
|
+
}
|
|
114
|
+
nav #refresh {
|
|
115
|
+
margin-inline-start: auto;
|
|
116
|
+
font-size: 0.84rem;
|
|
117
|
+
}
|
|
118
|
+
button:focus-visible, input:focus-visible, select:focus-visible {
|
|
119
|
+
outline: 2px solid #34d399;
|
|
120
|
+
outline-offset: 2px;
|
|
121
|
+
}
|
|
122
|
+
.tools {
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
justify-content: space-between;
|
|
126
|
+
gap: 12px;
|
|
127
|
+
flex-wrap: wrap;
|
|
128
|
+
margin-bottom: 14px;
|
|
129
|
+
}
|
|
130
|
+
.filters {
|
|
131
|
+
display: flex;
|
|
132
|
+
align-items: center;
|
|
133
|
+
gap: 10px;
|
|
134
|
+
flex-wrap: wrap;
|
|
135
|
+
}
|
|
136
|
+
label {
|
|
137
|
+
display: flex;
|
|
138
|
+
flex-wrap: wrap;
|
|
139
|
+
align-items: center;
|
|
140
|
+
gap: 8px;
|
|
141
|
+
font-size: 0.84rem;
|
|
142
|
+
color: var(--color-muted, #9ec0ac);
|
|
143
|
+
}
|
|
144
|
+
input, select {
|
|
145
|
+
background: rgba(16, 30, 25, 0.9);
|
|
146
|
+
border: 1px solid rgba(100, 227, 164, 0.24);
|
|
147
|
+
border-radius: 8px;
|
|
148
|
+
min-height: 38px;
|
|
149
|
+
padding: 6px 11px;
|
|
150
|
+
max-width: 100%;
|
|
151
|
+
color: #edf6f0;
|
|
152
|
+
}
|
|
153
|
+
.count-pill {
|
|
154
|
+
display: inline-flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
padding: 4px 10px;
|
|
157
|
+
border-radius: 999px;
|
|
158
|
+
font-size: 0.8rem;
|
|
159
|
+
font-weight: 600;
|
|
160
|
+
background: rgba(16, 185, 129, 0.12);
|
|
161
|
+
border: 1px solid rgba(52, 211, 153, 0.25);
|
|
162
|
+
color: #a7f3d0;
|
|
163
|
+
}
|
|
164
|
+
.table {
|
|
165
|
+
overflow: auto;
|
|
166
|
+
max-height: 460px;
|
|
167
|
+
border: 1px solid rgba(100, 227, 164, 0.16);
|
|
168
|
+
border-radius: 10px;
|
|
169
|
+
background: rgba(10, 19, 15, 0.65);
|
|
170
|
+
}
|
|
171
|
+
table {
|
|
172
|
+
width: 100%;
|
|
173
|
+
border-collapse: collapse;
|
|
174
|
+
text-align: start;
|
|
175
|
+
}
|
|
176
|
+
th, td {
|
|
177
|
+
padding: 11px 14px;
|
|
178
|
+
text-align: start;
|
|
179
|
+
border-block-end: 1px solid rgba(100, 227, 164, 0.11);
|
|
180
|
+
vertical-align: middle;
|
|
181
|
+
}
|
|
182
|
+
tbody tr:hover {
|
|
183
|
+
background: rgba(16, 185, 129, 0.05);
|
|
184
|
+
}
|
|
185
|
+
tbody tr:last-child td {
|
|
186
|
+
border-block-end: none;
|
|
187
|
+
}
|
|
188
|
+
th {
|
|
189
|
+
position: sticky;
|
|
190
|
+
top: 0;
|
|
191
|
+
z-index: 1;
|
|
192
|
+
background: rgba(17, 33, 27, 0.98);
|
|
193
|
+
font-size: 0.72rem;
|
|
194
|
+
font-weight: 700;
|
|
195
|
+
letter-spacing: 0.07em;
|
|
196
|
+
text-transform: uppercase;
|
|
197
|
+
border-block-end: 1px solid rgba(100, 227, 164, 0.22);
|
|
198
|
+
}
|
|
199
|
+
td { overflow-wrap: anywhere; }
|
|
200
|
+
.key-name {
|
|
201
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
202
|
+
font-size: 0.84rem;
|
|
203
|
+
font-weight: 600;
|
|
204
|
+
color: #f0fdf4;
|
|
205
|
+
}
|
|
206
|
+
.key-label {
|
|
207
|
+
display: block;
|
|
208
|
+
font-size: 0.78rem;
|
|
209
|
+
color: var(--color-muted, #9ec0ac);
|
|
210
|
+
margin-top: 2px;
|
|
211
|
+
}
|
|
212
|
+
.chip-list {
|
|
213
|
+
display: flex;
|
|
214
|
+
flex-wrap: wrap;
|
|
215
|
+
gap: 5px;
|
|
216
|
+
}
|
|
217
|
+
.chip {
|
|
218
|
+
display: inline-flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
padding: 2px 8px;
|
|
221
|
+
border-radius: 6px;
|
|
222
|
+
font-size: 0.76rem;
|
|
223
|
+
background: rgba(148, 163, 184, 0.12);
|
|
224
|
+
border: 1px solid rgba(148, 163, 184, 0.22);
|
|
225
|
+
color: #cbd5e1;
|
|
226
|
+
}
|
|
227
|
+
.pill {
|
|
228
|
+
display: inline-flex;
|
|
229
|
+
align-items: center;
|
|
230
|
+
gap: 6px;
|
|
231
|
+
padding: 3px 9px;
|
|
232
|
+
border-radius: 999px;
|
|
233
|
+
font-size: 0.76rem;
|
|
234
|
+
font-weight: 600;
|
|
235
|
+
white-space: nowrap;
|
|
236
|
+
}
|
|
237
|
+
.pill-ready {
|
|
238
|
+
background: rgba(16, 185, 129, 0.14);
|
|
239
|
+
border: 1px solid rgba(52, 211, 153, 0.34);
|
|
240
|
+
color: #6ee7b7;
|
|
241
|
+
}
|
|
242
|
+
.pill-warn {
|
|
243
|
+
background: rgba(245, 158, 11, 0.14);
|
|
244
|
+
border: 1px solid rgba(251, 191, 36, 0.34);
|
|
245
|
+
color: #fcd34d;
|
|
246
|
+
}
|
|
247
|
+
.pill-muted {
|
|
248
|
+
background: rgba(148, 163, 184, 0.1);
|
|
249
|
+
border: 1px solid rgba(148, 163, 184, 0.22);
|
|
250
|
+
color: #94a3b8;
|
|
251
|
+
}
|
|
252
|
+
.pill-info {
|
|
253
|
+
background: rgba(56, 189, 248, 0.12);
|
|
254
|
+
border: 1px solid rgba(56, 189, 248, 0.3);
|
|
255
|
+
color: #7dd3fc;
|
|
256
|
+
}
|
|
257
|
+
td.actions {
|
|
258
|
+
white-space: nowrap;
|
|
259
|
+
text-align: end;
|
|
260
|
+
}
|
|
261
|
+
td.actions button {
|
|
262
|
+
min-height: 32px;
|
|
263
|
+
padding: 0 10px;
|
|
264
|
+
font-size: 0.8rem;
|
|
265
|
+
}
|
|
266
|
+
td.actions button + button { margin-inline-start: 6px; }
|
|
267
|
+
.signin-grid {
|
|
268
|
+
display: grid;
|
|
269
|
+
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
|
|
270
|
+
gap: 12px;
|
|
271
|
+
margin-bottom: 18px;
|
|
272
|
+
}
|
|
273
|
+
.signin-card {
|
|
274
|
+
background: rgba(18, 35, 28, 0.68);
|
|
275
|
+
border: 1px solid rgba(100, 227, 164, 0.18);
|
|
276
|
+
border-radius: 10px;
|
|
277
|
+
padding: 14px 16px;
|
|
278
|
+
display: flex;
|
|
279
|
+
flex-direction: column;
|
|
280
|
+
gap: 6px;
|
|
281
|
+
}
|
|
282
|
+
.signin-card dt {
|
|
283
|
+
font-size: 0.78rem;
|
|
284
|
+
color: var(--color-muted, #9ec0ac);
|
|
285
|
+
text-transform: uppercase;
|
|
286
|
+
letter-spacing: 0.06em;
|
|
287
|
+
font-weight: 600;
|
|
288
|
+
}
|
|
289
|
+
.signin-card dd {
|
|
290
|
+
margin: 0;
|
|
291
|
+
font-size: 1.05rem;
|
|
292
|
+
font-weight: 650;
|
|
293
|
+
color: #f0fdf4;
|
|
294
|
+
}
|
|
295
|
+
.audit-panel {
|
|
296
|
+
background: rgba(16, 33, 26, 0.62);
|
|
297
|
+
border: 1px solid rgba(100, 227, 164, 0.22);
|
|
298
|
+
border-radius: 10px;
|
|
299
|
+
padding: 16px 18px;
|
|
300
|
+
display: flex;
|
|
301
|
+
flex-wrap: wrap;
|
|
302
|
+
align-items: center;
|
|
303
|
+
justify-content: space-between;
|
|
304
|
+
gap: 14px;
|
|
305
|
+
}
|
|
306
|
+
.audit-copy p { margin-top: 4px; font-size: 0.85rem; }
|
|
307
|
+
dialog {
|
|
308
|
+
color: inherit;
|
|
309
|
+
background: #0d1a14;
|
|
310
|
+
border: 1px solid rgba(100, 227, 164, 0.35);
|
|
311
|
+
border-radius: 14px;
|
|
312
|
+
padding: 22px;
|
|
313
|
+
width: min(480px, calc(100% - 26px));
|
|
314
|
+
max-height: calc(100% - 26px);
|
|
315
|
+
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
|
|
316
|
+
}
|
|
317
|
+
dialog::backdrop {
|
|
318
|
+
background: rgba(4, 9, 7, 0.78);
|
|
319
|
+
backdrop-filter: blur(4px);
|
|
320
|
+
}
|
|
321
|
+
dialog label { display: grid; margin: 12px 0; color: #edf6f0; }
|
|
322
|
+
dialog .tools { margin: 16px 0 0; }
|
|
323
|
+
.state-ready { color: #6ee7b7; font-weight: 600; }
|
|
324
|
+
.state-attention { color: #fcd34d; font-weight: 600; }
|
|
325
|
+
[role="alert"] { color: #fca5a5; }
|
|
326
|
+
#audit-result { margin: 10px 0 0; font-size: 0.88rem; }
|
|
327
|
+
[hidden] { display: none !important; }
|
|
45
328
|
</style>
|
|
46
|
-
<main aria-
|
|
47
|
-
<
|
|
48
|
-
<div
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
329
|
+
<main aria-label="Auth & Secrets">
|
|
330
|
+
<section class="stats-strip" aria-label="Access summary">
|
|
331
|
+
<div class="stat-card">
|
|
332
|
+
<span class="stat-label">Stored Secrets</span>
|
|
333
|
+
<span class="stat-value" id="stat-secrets">—</span>
|
|
334
|
+
<span class="stat-sub" id="stat-secrets-sub">Loading encrypted store…</span>
|
|
335
|
+
</div>
|
|
336
|
+
<div class="stat-card">
|
|
337
|
+
<span class="stat-label">Accessible Brains</span>
|
|
338
|
+
<span class="stat-value" id="stat-brains">—</span>
|
|
339
|
+
<span class="stat-sub" id="stat-brains-sub">Global & project scopes</span>
|
|
340
|
+
</div>
|
|
341
|
+
<div class="stat-card">
|
|
342
|
+
<span class="stat-label">Mesh Machines</span>
|
|
343
|
+
<span class="stat-value" id="stat-machines">—</span>
|
|
344
|
+
<span class="stat-sub" id="stat-machines-sub">Checking fleet status…</span>
|
|
345
|
+
</div>
|
|
346
|
+
<div class="stat-card">
|
|
347
|
+
<span class="stat-label">Auth Posture</span>
|
|
348
|
+
<span class="stat-value" id="stat-posture">—</span>
|
|
349
|
+
<span class="stat-sub" id="stat-posture-sub">Passkeys, OAuth & session</span>
|
|
350
|
+
</div>
|
|
351
|
+
</section>
|
|
52
352
|
<nav aria-label="Auth views">
|
|
53
353
|
<button type="button" data-view="secrets" aria-pressed="true">Secrets</button>
|
|
54
354
|
<button type="button" data-view="brains" aria-pressed="false">Brains</button>
|
|
55
355
|
<button type="button" data-view="machines" aria-pressed="false">Machines</button>
|
|
56
356
|
<button type="button" data-view="sign-in" aria-pressed="false">Sign-in & audit</button>
|
|
357
|
+
<button type="button" id="refresh">Refresh</button>
|
|
57
358
|
</nav>
|
|
58
359
|
<section class="body" id="inventory" aria-label="Inventory">
|
|
59
360
|
<div class="tools">
|
|
60
|
-
<
|
|
61
|
-
<
|
|
62
|
-
|
|
361
|
+
<span class="count-pill" id="summary" role="status">Loading…</span>
|
|
362
|
+
<div class="filters">
|
|
363
|
+
<label id="repo-filter-label" hidden>Repository<select id="repo-filter"></select></label>
|
|
364
|
+
<label id="search-label">Search<input type="search" id="search" placeholder="Key, provider, repo…" autocomplete="off"></label>
|
|
365
|
+
</div>
|
|
63
366
|
</div>
|
|
64
367
|
<p id="problem" role="alert" hidden></p>
|
|
65
|
-
<p id="receipt" role="status" hidden></p>
|
|
368
|
+
<p id="receipt" role="status" class="state-ready" style="margin-bottom:10px" hidden></p>
|
|
66
369
|
<div class="table" id="table" role="region" aria-label="Inventory results" tabindex="0" hidden></div>
|
|
67
370
|
</section>
|
|
68
371
|
<section class="body" id="sign-in" aria-label="Sign-in and audit" hidden>
|
|
69
|
-
<dl aria-live="polite">
|
|
70
|
-
<div><dt>Registered passkeys</dt><dd id="passkeys">Checking…</dd></div>
|
|
71
|
-
<div><dt>Google sign-in
|
|
72
|
-
<div><dt>
|
|
372
|
+
<dl class="signin-grid" aria-live="polite">
|
|
373
|
+
<div class="signin-card"><dt>Registered passkeys</dt><dd id="passkeys">Checking…</dd></div>
|
|
374
|
+
<div class="signin-card"><dt>Google sign-in</dt><dd id="google">Checking…</dd></div>
|
|
375
|
+
<div class="signin-card"><dt>Session signing</dt><dd id="session">Checking…</dd></div>
|
|
73
376
|
</dl>
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
377
|
+
<div class="audit-panel">
|
|
378
|
+
<div class="audit-copy">
|
|
379
|
+
<h2>Security baseline</h2>
|
|
380
|
+
<p class="muted">Inspect file permissions, encrypted key health, and host session configuration.</p>
|
|
381
|
+
<p id="audit-result" role="status"></p>
|
|
382
|
+
</div>
|
|
383
|
+
<button type="button" class="primary" id="audit">Run baseline audit</button>
|
|
384
|
+
</div>
|
|
77
385
|
</section>
|
|
78
386
|
<dialog id="credential-dialog" aria-labelledby="credential-heading">
|
|
79
|
-
<h2 id="credential-heading"
|
|
80
|
-
<p id="credential-key"></p>
|
|
387
|
+
<h2 id="credential-heading">Edit credential</h2>
|
|
388
|
+
<p class="muted" id="credential-key" style="margin-top:4px;font-family:monospace"></p>
|
|
81
389
|
<div id="credential-fields">
|
|
82
390
|
<label>Label<input id="credential-label" maxlength="120" autocomplete="off"></label>
|
|
83
391
|
<label>Repository binding<input id="credential-repo" maxlength="256" list="registered-repositories" autocomplete="off"></label>
|
|
84
392
|
<datalist id="registered-repositories"></datalist>
|
|
85
393
|
<button type="button" id="credential-clear-repo">Clear binding</button>
|
|
86
|
-
<p class="muted" id="binding-status"></p>
|
|
394
|
+
<p class="muted" id="binding-status" style="margin-top:6px;font-size:0.82rem"></p>
|
|
87
395
|
<label>Replacement value<input type="password" id="credential-value" maxlength="16384" autocomplete="new-password"></label>
|
|
88
396
|
</div>
|
|
89
397
|
<div id="delete-fields" hidden>
|
|
90
|
-
<p>Remove this credential from this host’s encrypted store. Enter its name to confirm.</p>
|
|
398
|
+
<p style="margin-top:10px">Remove this credential from this host’s encrypted store. Enter its name to confirm.</p>
|
|
91
399
|
<label>Credential name<input id="credential-confirm" maxlength="256" autocomplete="off"></label>
|
|
92
400
|
</div>
|
|
93
401
|
<p id="credential-error" role="alert" hidden></p>
|
|
94
402
|
<div class="tools">
|
|
95
403
|
<button type="button" id="credential-close">Cancel</button>
|
|
96
404
|
<button type="button" id="credential-replace">Replace value</button>
|
|
97
|
-
<button type="button" id="credential-save">Save details</button>
|
|
405
|
+
<button type="button" class="primary" id="credential-save">Save details</button>
|
|
98
406
|
</div>
|
|
99
407
|
</dialog>
|
|
100
408
|
</main>
|
|
101
409
|
`;
|
|
102
410
|
|
|
103
411
|
const count = value => Number.isSafeInteger(value) && value >= 0;
|
|
104
|
-
const words = values => Array.isArray(values) && values.length ? values.join(', ') : 'Unbound';
|
|
105
412
|
const date = value => typeof value === 'string' && Number.isFinite(Date.parse(value))
|
|
106
413
|
? new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(new Date(value)) : 'Unscheduled';
|
|
107
414
|
const state = (value, positive, negative) => value === true ? positive : value === false ? negative : 'Unreported';
|
|
108
415
|
|
|
416
|
+
const makePill = (text, tone) => {
|
|
417
|
+
const span = document.createElement('span');
|
|
418
|
+
span.className = `pill pill-${tone}`;
|
|
419
|
+
span.textContent = text;
|
|
420
|
+
return span;
|
|
421
|
+
};
|
|
422
|
+
|
|
109
423
|
const views = {
|
|
110
424
|
secrets: {
|
|
111
425
|
name: 'credentials', headers: ['Credential', 'Provider', 'Bound repositories', 'Storage', 'Rotation'],
|
|
112
|
-
row: item => [item.label ? `${item.key} · ${item.label}` : item.key, item.provider_name || 'Unassigned',
|
|
426
|
+
row: item => [item.label ? `${item.key} · ${item.label}` : item.key, item.provider_name || 'Unassigned',
|
|
427
|
+
Array.isArray(item.repos) && item.repos.length ? item.repos.join(', ') : 'Unbound',
|
|
113
428
|
state(item.set, 'Stored', 'Empty'), item.rotation_overdue ? 'Overdue' : date(item.next_rotate_due)],
|
|
429
|
+
renderCells(entry, item) {
|
|
430
|
+
const keyCell = entry.insertCell();
|
|
431
|
+
const keySpan = document.createElement('span');
|
|
432
|
+
keySpan.className = 'key-name';
|
|
433
|
+
keySpan.textContent = item.key;
|
|
434
|
+
keyCell.append(keySpan);
|
|
435
|
+
if (item.label) {
|
|
436
|
+
const labelSpan = document.createElement('span');
|
|
437
|
+
labelSpan.className = 'key-label';
|
|
438
|
+
labelSpan.textContent = item.label;
|
|
439
|
+
keyCell.append(labelSpan);
|
|
440
|
+
}
|
|
441
|
+
const providerCell = entry.insertCell();
|
|
442
|
+
providerCell.append(makePill(item.provider_name || 'Unassigned', item.provider_name ? 'info' : 'muted'));
|
|
443
|
+
|
|
444
|
+
const repoCell = entry.insertCell();
|
|
445
|
+
if (Array.isArray(item.repos) && item.repos.length) {
|
|
446
|
+
const list = document.createElement('div');
|
|
447
|
+
list.className = 'chip-list';
|
|
448
|
+
for (const repo of item.repos) {
|
|
449
|
+
const chip = document.createElement('span');
|
|
450
|
+
chip.className = 'chip';
|
|
451
|
+
chip.textContent = repo;
|
|
452
|
+
list.append(chip);
|
|
453
|
+
}
|
|
454
|
+
repoCell.append(list);
|
|
455
|
+
} else {
|
|
456
|
+
repoCell.append(makePill('Unbound', 'muted'));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const storageCell = entry.insertCell();
|
|
460
|
+
const stored = state(item.set, 'Stored', 'Empty');
|
|
461
|
+
storageCell.append(makePill(stored, stored === 'Stored' ? 'ready' : 'muted'));
|
|
462
|
+
|
|
463
|
+
const rotCell = entry.insertCell();
|
|
464
|
+
if (item.rotation_overdue) rotCell.append(makePill('Overdue', 'warn'));
|
|
465
|
+
else rotCell.append(makePill(date(item.next_rotate_due), item.next_rotate_due ? 'info' : 'muted'));
|
|
466
|
+
},
|
|
114
467
|
},
|
|
115
468
|
brains: {
|
|
116
469
|
name: 'brains', headers: ['Brain', 'Layer', 'Memory nodes', 'State'],
|
|
117
470
|
row: item => [item.name, item.layer, count(item.node_count) ? String(item.node_count) : 'Unreported',
|
|
118
471
|
state(item.exists, 'Present', 'Unavailable')],
|
|
472
|
+
renderCells(entry, item) {
|
|
473
|
+
const nameCell = entry.insertCell();
|
|
474
|
+
const nameSpan = document.createElement('span');
|
|
475
|
+
nameSpan.className = 'key-name';
|
|
476
|
+
nameSpan.textContent = item.name;
|
|
477
|
+
nameCell.append(nameSpan);
|
|
478
|
+
|
|
479
|
+
const layerCell = entry.insertCell();
|
|
480
|
+
layerCell.append(makePill(item.layer || 'project', item.layer === 'global' ? 'info' : 'muted'));
|
|
481
|
+
|
|
482
|
+
const nodesCell = entry.insertCell();
|
|
483
|
+
nodesCell.textContent = count(item.node_count) ? String(item.node_count) : 'Unreported';
|
|
484
|
+
|
|
485
|
+
const stateCell = entry.insertCell();
|
|
486
|
+
const present = state(item.exists, 'Present', 'Unavailable');
|
|
487
|
+
stateCell.append(makePill(present, present === 'Present' ? 'ready' : 'warn'));
|
|
488
|
+
},
|
|
119
489
|
},
|
|
120
490
|
machines: {
|
|
121
491
|
name: 'machines', headers: ['Machine', 'OS', 'Role', 'Mesh state'],
|
|
122
492
|
row: item => [item.self ? item.hostname + ' (this host)' : item.hostname, item.os || 'Unreported',
|
|
123
493
|
item.role || 'Unassigned', item.vault_only ? 'Registered' : state(item.online, 'Online', 'Offline')],
|
|
494
|
+
renderCells(entry, item) {
|
|
495
|
+
const hostCell = entry.insertCell();
|
|
496
|
+
const hostSpan = document.createElement('span');
|
|
497
|
+
hostSpan.className = 'key-name';
|
|
498
|
+
hostSpan.textContent = item.hostname || 'Unknown';
|
|
499
|
+
hostCell.append(hostSpan);
|
|
500
|
+
if (item.self) {
|
|
501
|
+
hostCell.append(document.createTextNode(' '));
|
|
502
|
+
hostCell.append(makePill('this host', 'info'));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
entry.insertCell().textContent = item.os || 'Unreported';
|
|
506
|
+
entry.insertCell().append(makePill(item.role || 'Unassigned', item.role ? 'info' : 'muted'));
|
|
507
|
+
|
|
508
|
+
const meshStatus = item.vault_only ? 'Registered' : state(item.online, 'Online', 'Offline');
|
|
509
|
+
const tone = meshStatus === 'Online' ? 'ready' : meshStatus === 'Registered' ? 'info' : 'muted';
|
|
510
|
+
entry.insertCell().append(makePill(meshStatus, tone));
|
|
511
|
+
},
|
|
124
512
|
},
|
|
125
513
|
};
|
|
126
514
|
|
|
@@ -177,7 +565,30 @@ class AuthHome extends HTMLElement {
|
|
|
177
565
|
.map(([key, labels]) => [key, [...labels][0]]));
|
|
178
566
|
}
|
|
179
567
|
|
|
568
|
+
updateSummaryCards() {
|
|
569
|
+
const secrets = this.inventory.secrets?.rows;
|
|
570
|
+
if (Array.isArray(secrets)) {
|
|
571
|
+
const stored = secrets.filter(s => s.set === true).length;
|
|
572
|
+
const overdue = secrets.filter(s => s.rotation_overdue).length;
|
|
573
|
+
this.field('stat-secrets').textContent = `${stored} / ${secrets.length}`;
|
|
574
|
+
this.field('stat-secrets-sub').textContent = overdue > 0 ? `${overdue} rotation overdue` : 'All rotations current';
|
|
575
|
+
}
|
|
576
|
+
const brains = this.inventory.brains?.rows;
|
|
577
|
+
if (Array.isArray(brains)) {
|
|
578
|
+
const present = brains.filter(b => b.exists === true).length;
|
|
579
|
+
this.field('stat-brains').textContent = String(present);
|
|
580
|
+
this.field('stat-brains-sub').textContent = `${brains.length} total configured`;
|
|
581
|
+
}
|
|
582
|
+
const machines = this.inventory.machines?.rows;
|
|
583
|
+
if (Array.isArray(machines)) {
|
|
584
|
+
const online = machines.filter(m => m.online === true).length;
|
|
585
|
+
this.field('stat-machines').textContent = `${online} / ${machines.length}`;
|
|
586
|
+
this.field('stat-machines-sub').textContent = `${machines.filter(m => m.vault_only).length} vault-only`;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
180
590
|
renderInventory() {
|
|
591
|
+
this.updateSummaryCards();
|
|
181
592
|
const signing = this.activeView === 'sign-in';
|
|
182
593
|
this.field('sign-in').hidden = !signing;
|
|
183
594
|
this.field('inventory').hidden = signing;
|
|
@@ -214,9 +625,10 @@ class AuthHome extends HTMLElement {
|
|
|
214
625
|
const rows = result.rows.flatMap(item => {
|
|
215
626
|
const repos = credentials ? repoLabels(item) : [];
|
|
216
627
|
if (credentials && repoFilter.value && !repos.includes(repoFilter.value)) return [];
|
|
217
|
-
const
|
|
628
|
+
const shaped = credentials ? { ...item, repos } : item;
|
|
629
|
+
const values = view.row(shaped);
|
|
218
630
|
const searchText = values.concat(credentials ? item.repos || [] : []).join(' ').toLocaleLowerCase();
|
|
219
|
-
return searchText.includes(query) ? [{ item
|
|
631
|
+
return searchText.includes(query) ? [{ item: shaped }] : [];
|
|
220
632
|
});
|
|
221
633
|
summary.textContent = rows.length === result.rows.length
|
|
222
634
|
? `${result.rows.length} ${view.name}` : `${rows.length} of ${result.rows.length} ${view.name}`;
|
|
@@ -232,20 +644,16 @@ class AuthHome extends HTMLElement {
|
|
|
232
644
|
heading.append(cell);
|
|
233
645
|
}
|
|
234
646
|
const body = table.createTBody();
|
|
235
|
-
for (const { item
|
|
647
|
+
for (const { item } of rows) {
|
|
236
648
|
const entry = body.insertRow();
|
|
237
|
-
|
|
238
|
-
const cell = entry.insertCell();
|
|
239
|
-
cell.textContent = value ?? 'Unreported';
|
|
240
|
-
if (['Stored', 'Online', 'Present'].includes(value)) cell.className = 'state-ready';
|
|
241
|
-
if (['Overdue', 'Offline', 'Empty'].includes(value)) cell.className = 'state-attention';
|
|
242
|
-
}
|
|
649
|
+
view.renderCells(entry, item);
|
|
243
650
|
if (canEdit) {
|
|
244
651
|
const actions = entry.insertCell();
|
|
245
652
|
actions.className = 'actions';
|
|
246
|
-
for (const [action, label] of [['edit', 'Edit'], ['delete', 'Delete']]) {
|
|
653
|
+
for (const [action, label, cls] of [['edit', 'Edit', ''], ['delete', 'Delete', 'danger']]) {
|
|
247
654
|
const button = document.createElement('button');
|
|
248
655
|
button.type = 'button';
|
|
656
|
+
if (cls) button.className = cls;
|
|
249
657
|
button.textContent = label;
|
|
250
658
|
button.setAttribute('aria-label', `${label} ${item.key}`);
|
|
251
659
|
button.addEventListener('click', () => this.openCredential(item, action));
|
|
@@ -267,7 +675,9 @@ class AuthHome extends HTMLElement {
|
|
|
267
675
|
this.field('credential-fields').hidden = deleting;
|
|
268
676
|
this.field('delete-fields').hidden = !deleting;
|
|
269
677
|
this.field('credential-replace').hidden = deleting;
|
|
270
|
-
this.field('credential-save')
|
|
678
|
+
const saveBtn = this.field('credential-save');
|
|
679
|
+
saveBtn.textContent = deleting ? 'Delete credential' : 'Save details';
|
|
680
|
+
saveBtn.className = deleting ? 'danger' : 'primary';
|
|
271
681
|
this.field('credential-label').value = item.label || '';
|
|
272
682
|
this.field('credential-repo').value = (item.repos || []).length <= 1 ? item.repos?.[0] || '' : '';
|
|
273
683
|
this.field('registered-repositories').replaceChildren(
|
|
@@ -345,10 +755,15 @@ class AuthHome extends HTMLElement {
|
|
|
345
755
|
]);
|
|
346
756
|
const providers = status.status === 'fulfilled' ? status.value : null;
|
|
347
757
|
const registered = providers?.passkey?.registered_count;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
758
|
+
const passkeyLabel = count(registered) ? String(registered) : 'Unavailable';
|
|
759
|
+
const googleLabel = state(providers?.google_oauth2?.configured, 'Configured', 'Needs setup');
|
|
760
|
+
const sessionLabel = state(session.status === 'fulfilled' && session.value
|
|
351
761
|
? session.value.session_secret_configured : null, 'Configured', 'Needs setup');
|
|
762
|
+
this.field('passkeys').textContent = passkeyLabel;
|
|
763
|
+
this.field('google').textContent = googleLabel;
|
|
764
|
+
this.field('session').textContent = sessionLabel;
|
|
765
|
+
this.field('stat-posture').textContent = sessionLabel === 'Configured' ? 'Secured' : 'Action needed';
|
|
766
|
+
this.field('stat-posture-sub').textContent = `${passkeyLabel} passkeys · Google ${googleLabel}`;
|
|
352
767
|
}
|
|
353
768
|
|
|
354
769
|
async audit() {
|