total-recall-brain 3.41.3 → 3.41.4
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 +10 -1
- package/frontend/dist/assets/{index-DFenQQEQ.js → index-CRzjQLu7.js} +77 -72
- package/frontend/dist/index.html +1 -1
- package/package.json +7 -5
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +48 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/login-projections.mjs +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/mesh-secrets.mjs +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/routes/secrets.mjs +5 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-carriers.mjs +76 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-prune.mjs +37 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +53 -17
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +12 -12
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +12 -12
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +23 -8
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +6 -2
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +23 -8
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +23 -10
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/grants.mjs +7 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +61 -38
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/leader-election.mjs +57 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +220 -36
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/server/routes/mesh.mjs +7 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +65 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +59 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +534 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +139 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +2849 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +376 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +37 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adapters/dsh.mjs +446 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +398 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +152 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +82 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +90 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +415 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/tracker.mjs +133 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +233 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +32 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +845 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/BRICK.md +64 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/index.mjs +250 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +344 -14
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +2917 -140
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +223 -5
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +129 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +355 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +375 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +35 -22
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +947 -323
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +23 -8
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +5 -1
- package/src/cli/config.mjs +3 -0
- package/src/cli/connect.mjs +12 -116
- package/src/cli/harness.mjs +0 -1
- package/src/cli/plugin/create.mjs +56 -3
- package/src/cli/plugin/index.mjs +15 -3
- package/src/cli/plugin/monetization.mjs +232 -12
- package/src/cli/preflight.mjs +161 -0
- package/src/core/cli-commands.mjs +2 -0
- package/src/core/context-compiler.mjs +8 -1
- package/src/core/default-plugins.mjs +1 -1
- package/src/core/meta-harness.mjs +16 -38
- package/src/core/plugin-dependencies.mjs +6 -1
- package/src/core/preflight-gate.mjs +77 -0
- package/src/core/preflight-receipt.mjs +123 -0
- package/src/core/runtime.mjs +0 -3
- package/src/core/surface.mjs +38 -1
|
@@ -1,534 +1,1158 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* OpenWiki — Knowledge Graph & Multi-Repo Documentation Wiki
|
|
3
|
+
* Bespoke Card Face: Deep Slate & Knowledge Amber Interface.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* and bootstrap verification without template wrappers or terminal dumps.
|
|
5
|
+
* Exposes live hub discovery, markdown file inspection, upstream release surveillance,
|
|
6
|
+
* and structured fleet propagation controls. Operates without mock data or boilerplate sinks.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const DASH = '\u2014';
|
|
10
|
-
|
|
11
|
-
function escapeHtml(str) {
|
|
12
|
-
if (str === null || str === undefined) return '';
|
|
13
|
-
return String(str).replace(/[&<>"']/g, c => ({
|
|
14
|
-
'&': '&',
|
|
15
|
-
'<': '<',
|
|
16
|
-
'>': '>',
|
|
17
|
-
'"': '"',
|
|
18
|
-
"'": '''
|
|
19
|
-
}[c]));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
9
|
export class OpenWikiCard extends HTMLElement {
|
|
10
|
+
static get screens() {
|
|
11
|
+
return [
|
|
12
|
+
{ id: 'hubs', label: 'Hubs' },
|
|
13
|
+
{ id: 'config', label: 'Configuration' },
|
|
14
|
+
{ id: 'refresh', label: 'Fleet Refresh' },
|
|
15
|
+
{ id: 'upstream', label: 'Upstream Watcher' }
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get screens() {
|
|
20
|
+
return OpenWikiCard.screens;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
23
|
constructor() {
|
|
24
24
|
super();
|
|
25
|
+
this.activeScreen = 'hubs';
|
|
25
26
|
this.hubs = [];
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
27
|
+
this.loading = false;
|
|
28
|
+
this.statusText = 'READY';
|
|
28
29
|
this.targetPath = 'openwiki';
|
|
29
|
-
this.dryRun =
|
|
30
|
-
this.
|
|
31
|
-
this.
|
|
32
|
-
this.
|
|
30
|
+
this.dryRun = false;
|
|
31
|
+
this.executionResult = null;
|
|
32
|
+
this.errorMessage = null;
|
|
33
|
+
this.lastRefreshedAt = null;
|
|
34
|
+
this.upstream = null;
|
|
35
|
+
this.config = {
|
|
36
|
+
provider: 'openrouter',
|
|
37
|
+
model: 'deepseek/deepseek-v4.1-flash',
|
|
38
|
+
fallback_model: 'qwen/qwen-2.5-coder-32b-instruct',
|
|
39
|
+
max_tokens: 4096,
|
|
40
|
+
timeout_ms: 300000
|
|
41
|
+
};
|
|
42
|
+
this.refreshReports = [];
|
|
43
|
+
this.refreshCounts = null;
|
|
44
|
+
this._boundOnScreenChange = this.handleExternalScreenChange.bind(this);
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
connectedCallback() {
|
|
36
48
|
if (!this.shadowRoot) {
|
|
37
49
|
this.attachShadow({ mode: 'open' });
|
|
38
50
|
}
|
|
51
|
+
this.addEventListener('tr:screen-change', this._boundOnScreenChange);
|
|
52
|
+
this.addEventListener('plugin-show-screen', this._boundOnScreenChange);
|
|
39
53
|
this.render();
|
|
40
54
|
this.refreshHubs();
|
|
55
|
+
this.loadConfig();
|
|
41
56
|
}
|
|
42
57
|
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
disconnectedCallback() {
|
|
59
|
+
this.removeEventListener('tr:screen-change', this._boundOnScreenChange);
|
|
60
|
+
this.removeEventListener('plugin-show-screen', this._boundOnScreenChange);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
handleExternalScreenChange(event) {
|
|
64
|
+
const screenId = event.detail?.screen || event.detail?.screenId || event.detail?.id;
|
|
65
|
+
if (screenId && OpenWikiCard.screens.some((s) => s.id === screenId)) {
|
|
66
|
+
this.setScreen(screenId);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setScreen(id) {
|
|
71
|
+
if (this.activeScreen === id) return;
|
|
72
|
+
this.activeScreen = id;
|
|
73
|
+
this.errorMessage = null;
|
|
74
|
+
this.render();
|
|
75
|
+
if (typeof this.host?.screenChanged === 'function') {
|
|
76
|
+
try {
|
|
77
|
+
this.host.screenChanged({ screen: id });
|
|
78
|
+
} catch {
|
|
79
|
+
// Host screenChanged callback optional
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (id === 'refresh' && (!this.refreshReports || this.refreshReports.length === 0)) {
|
|
83
|
+
this.loadRefreshReport();
|
|
84
|
+
} else if (id === 'config') {
|
|
85
|
+
this.loadConfig();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async loadConfig() {
|
|
45
90
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} else if (Array.isArray(res)) {
|
|
53
|
-
parsed = res;
|
|
54
|
-
}
|
|
55
|
-
} else if (typeof res === 'string' && res.trim().startsWith('{')) {
|
|
56
|
-
const json = JSON.parse(res);
|
|
57
|
-
parsed = Array.isArray(json.hubs) ? json.hubs : [];
|
|
58
|
-
this.totalLines = json.total_lines || 0;
|
|
91
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
92
|
+
const res = await this.host.run('config', ['show', '--json']);
|
|
93
|
+
if (res?.config) {
|
|
94
|
+
this.config = res.config;
|
|
95
|
+
this.render();
|
|
96
|
+
}
|
|
59
97
|
}
|
|
98
|
+
} catch {
|
|
99
|
+
// Retain active config defaults if host call fails
|
|
100
|
+
}
|
|
101
|
+
}
|
|
60
102
|
|
|
61
|
-
|
|
103
|
+
async setConfigValue(key, value) {
|
|
104
|
+
this.loading = true;
|
|
105
|
+
this.errorMessage = null;
|
|
106
|
+
this.render();
|
|
107
|
+
try {
|
|
108
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
109
|
+
const res = await this.host.run('config', ['set', key, String(value), '--json']);
|
|
110
|
+
if (res?.config) {
|
|
111
|
+
this.config = res.config;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} catch (err) {
|
|
115
|
+
this.errorMessage = err.message || `Failed to update ${key}`;
|
|
116
|
+
} finally {
|
|
117
|
+
this.loading = false;
|
|
62
118
|
this.render();
|
|
63
|
-
}
|
|
64
|
-
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async resetConfig() {
|
|
123
|
+
this.loading = true;
|
|
124
|
+
this.errorMessage = null;
|
|
125
|
+
this.render();
|
|
126
|
+
try {
|
|
127
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
128
|
+
const res = await this.host.run('config', ['reset', '--json']);
|
|
129
|
+
if (res?.config) {
|
|
130
|
+
this.config = res.config;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} catch (err) {
|
|
134
|
+
this.errorMessage = err.message || 'Failed to reset configuration';
|
|
135
|
+
} finally {
|
|
136
|
+
this.loading = false;
|
|
65
137
|
this.render();
|
|
66
138
|
}
|
|
67
139
|
}
|
|
68
140
|
|
|
69
|
-
async
|
|
70
|
-
|
|
71
|
-
this.
|
|
72
|
-
this.lastResult = null;
|
|
141
|
+
async refreshHubs() {
|
|
142
|
+
this.loading = true;
|
|
143
|
+
this.errorMessage = null;
|
|
73
144
|
this.render();
|
|
74
145
|
|
|
75
146
|
try {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
147
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
148
|
+
const res = await this.host.run('hubs', ['--json']);
|
|
149
|
+
if (res && Array.isArray(res.hubs)) {
|
|
150
|
+
this.hubs = res.hubs;
|
|
151
|
+
this.statusText = 'SYNCHRONIZED';
|
|
152
|
+
} else {
|
|
153
|
+
this.hubs = [];
|
|
154
|
+
this.statusText = 'UNINDEXED';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const statusRes = await this.host.run('status', ['--json']);
|
|
159
|
+
if (statusRes?.upstream) {
|
|
160
|
+
this.upstream = statusRes.upstream;
|
|
161
|
+
}
|
|
162
|
+
} catch {
|
|
163
|
+
// Upstream metadata optional
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
this.statusText = 'DISCONNECTED';
|
|
167
|
+
}
|
|
168
|
+
this.lastRefreshedAt = new Date().toLocaleTimeString();
|
|
169
|
+
} catch (err) {
|
|
170
|
+
this.statusText = 'ERROR';
|
|
171
|
+
this.errorMessage = err.message || 'Hub synchronization failure';
|
|
172
|
+
this.hubs = [];
|
|
173
|
+
} finally {
|
|
174
|
+
this.loading = false;
|
|
175
|
+
this.render();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async loadRefreshReport() {
|
|
180
|
+
this.loading = true;
|
|
181
|
+
this.errorMessage = null;
|
|
182
|
+
this.render();
|
|
183
|
+
try {
|
|
184
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
185
|
+
const res = await this.host.run('refresh', ['--json']);
|
|
186
|
+
if (res) {
|
|
187
|
+
this.refreshReports = Array.isArray(res.reports) ? res.reports : [];
|
|
188
|
+
this.refreshCounts = res.counts || null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
87
191
|
} catch (err) {
|
|
88
|
-
this.
|
|
89
|
-
ok: false,
|
|
90
|
-
message: err instanceof Error ? err.message : 'Ingestion failed'
|
|
91
|
-
};
|
|
192
|
+
this.errorMessage = err.message || 'Fleet status check failure';
|
|
92
193
|
} finally {
|
|
93
|
-
this.
|
|
194
|
+
this.loading = false;
|
|
94
195
|
this.render();
|
|
95
196
|
}
|
|
96
197
|
}
|
|
97
198
|
|
|
98
|
-
async
|
|
99
|
-
if (
|
|
100
|
-
this.
|
|
101
|
-
this.
|
|
199
|
+
async executeFleetRefresh() {
|
|
200
|
+
if (this.loading) return;
|
|
201
|
+
this.loading = true;
|
|
202
|
+
this.executionResult = null;
|
|
203
|
+
this.errorMessage = null;
|
|
102
204
|
this.render();
|
|
103
205
|
|
|
104
206
|
try {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
207
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
208
|
+
const res = await this.host.run('refresh', ['--apply', '--json']);
|
|
209
|
+
this.executionResult = {
|
|
210
|
+
action: 'fleet-refresh',
|
|
211
|
+
target: 'all-registered-projects',
|
|
212
|
+
details: res && typeof res === 'object' ? res : { message: String(res || 'Completed') },
|
|
213
|
+
timestamp: new Date().toLocaleTimeString()
|
|
214
|
+
};
|
|
215
|
+
if (res?.reports) {
|
|
216
|
+
this.refreshReports = res.reports;
|
|
217
|
+
this.refreshCounts = res.counts;
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
throw new Error('Host execution context unavailable');
|
|
221
|
+
}
|
|
112
222
|
} catch (err) {
|
|
113
|
-
this.
|
|
114
|
-
ok: false,
|
|
115
|
-
message: err instanceof Error ? err.message : 'Bootstrap failed'
|
|
116
|
-
};
|
|
223
|
+
this.errorMessage = err.message || 'Fleet refresh execution failure';
|
|
117
224
|
} finally {
|
|
118
|
-
this.
|
|
225
|
+
this.loading = false;
|
|
119
226
|
this.render();
|
|
120
227
|
}
|
|
121
228
|
}
|
|
122
229
|
|
|
230
|
+
async executeIngest() {
|
|
231
|
+
if (this.loading) return;
|
|
232
|
+
this.loading = true;
|
|
233
|
+
this.executionResult = null;
|
|
234
|
+
this.errorMessage = null;
|
|
235
|
+
this.render();
|
|
236
|
+
|
|
237
|
+
const args = [this.targetPath || 'openwiki'];
|
|
238
|
+
if (this.dryRun) args.push('--dry-run');
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
242
|
+
const res = await this.host.run('ingest', args);
|
|
243
|
+
this.executionResult = {
|
|
244
|
+
action: 'ingest',
|
|
245
|
+
target: this.targetPath,
|
|
246
|
+
dryRun: this.dryRun,
|
|
247
|
+
details: res && typeof res === 'object' ? res : { message: String(res || 'Completed') },
|
|
248
|
+
timestamp: new Date().toLocaleTimeString()
|
|
249
|
+
};
|
|
250
|
+
} else {
|
|
251
|
+
throw new Error('Host execution context unavailable');
|
|
252
|
+
}
|
|
253
|
+
} catch (err) {
|
|
254
|
+
this.errorMessage = err.message || 'Ingestion cycle failure';
|
|
255
|
+
} finally {
|
|
256
|
+
this.loading = false;
|
|
257
|
+
this.refreshHubs();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async executeBootstrap() {
|
|
262
|
+
if (this.loading) return;
|
|
263
|
+
this.loading = true;
|
|
264
|
+
this.executionResult = null;
|
|
265
|
+
this.errorMessage = null;
|
|
266
|
+
this.render();
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
270
|
+
const res = await this.host.run('bootstrap', ['--brain', '.', '--json']);
|
|
271
|
+
this.executionResult = {
|
|
272
|
+
action: 'bootstrap',
|
|
273
|
+
details: res && typeof res === 'object' ? res : { message: String(res || 'Completed') },
|
|
274
|
+
timestamp: new Date().toLocaleTimeString()
|
|
275
|
+
};
|
|
276
|
+
} else {
|
|
277
|
+
throw new Error('Host execution context unavailable');
|
|
278
|
+
}
|
|
279
|
+
} catch (err) {
|
|
280
|
+
this.errorMessage = err.message || 'Bootstrap procedure failure';
|
|
281
|
+
} finally {
|
|
282
|
+
this.loading = false;
|
|
283
|
+
this.refreshHubs();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async executeWatch() {
|
|
288
|
+
if (this.loading) return;
|
|
289
|
+
this.loading = true;
|
|
290
|
+
this.executionResult = null;
|
|
291
|
+
this.errorMessage = null;
|
|
292
|
+
this.render();
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
296
|
+
const res = await this.host.run('watch', ['--json']);
|
|
297
|
+
this.executionResult = {
|
|
298
|
+
action: 'watch',
|
|
299
|
+
details: res && typeof res === 'object' ? res : { message: String(res || 'Completed') },
|
|
300
|
+
timestamp: new Date().toLocaleTimeString()
|
|
301
|
+
};
|
|
302
|
+
if (res?.status) {
|
|
303
|
+
this.upstream = {
|
|
304
|
+
recordedVersion: res.status.currentVersion,
|
|
305
|
+
latestVersion: res.status.latestVersion
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
} else {
|
|
309
|
+
throw new Error('Host execution context unavailable');
|
|
310
|
+
}
|
|
311
|
+
} catch (err) {
|
|
312
|
+
this.errorMessage = err.message || 'Upstream surveillance failure';
|
|
313
|
+
} finally {
|
|
314
|
+
this.loading = false;
|
|
315
|
+
this.refreshHubs();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async executePropagate() {
|
|
320
|
+
if (this.loading) return;
|
|
321
|
+
this.loading = true;
|
|
322
|
+
this.executionResult = null;
|
|
323
|
+
this.errorMessage = null;
|
|
324
|
+
this.render();
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
if (this.host && typeof this.host.run === 'function') {
|
|
328
|
+
const res = await this.host.run('propagate', ['--json']);
|
|
329
|
+
this.executionResult = {
|
|
330
|
+
action: 'propagate',
|
|
331
|
+
details: res && typeof res === 'object' ? res : { message: String(res || 'Completed') },
|
|
332
|
+
timestamp: new Date().toLocaleTimeString()
|
|
333
|
+
};
|
|
334
|
+
} else {
|
|
335
|
+
throw new Error('Host execution context unavailable');
|
|
336
|
+
}
|
|
337
|
+
} catch (err) {
|
|
338
|
+
this.errorMessage = err.message || 'Fleet propagation failure';
|
|
339
|
+
} finally {
|
|
340
|
+
this.loading = false;
|
|
341
|
+
this.refreshHubs();
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
123
345
|
render() {
|
|
124
|
-
|
|
125
|
-
|
|
346
|
+
if (!this.shadowRoot) return;
|
|
347
|
+
|
|
348
|
+
const countText = this.hubs.length ? `${this.hubs.length} Hubs` : '—';
|
|
349
|
+
const totalLines = this.hubs.reduce((acc, h) => acc + (h.lines || 0), 0);
|
|
350
|
+
const linesText = this.hubs.length ? `${totalLines.toLocaleString()} Lines` : '—';
|
|
351
|
+
const upstreamText = this.upstream?.latestVersion ? `v${this.upstream.latestVersion}` : 'Tracking';
|
|
126
352
|
|
|
127
|
-
|
|
353
|
+
this.shadowRoot.innerHTML = `
|
|
128
354
|
<style>
|
|
129
355
|
:host {
|
|
356
|
+
display: block;
|
|
357
|
+
box-sizing: border-box;
|
|
130
358
|
--face-bg: #0f172a;
|
|
131
359
|
--face-surface: #1e293b;
|
|
132
|
-
--face-
|
|
360
|
+
--face-surface-subtle: #334155;
|
|
361
|
+
--face-border: #475569;
|
|
133
362
|
--face-text: #f8fafc;
|
|
134
|
-
--face-muted: #94a3b8;
|
|
135
|
-
--face-
|
|
136
|
-
--face-
|
|
137
|
-
--face-accent: #facc15;
|
|
363
|
+
--face-text-muted: #94a3b8;
|
|
364
|
+
--face-accent: #f59e0b;
|
|
365
|
+
--face-accent-hover: #d97706;
|
|
138
366
|
--face-ok: #10b981;
|
|
139
|
-
--face-warn: #f59e0b;
|
|
140
367
|
--face-danger: #ef4444;
|
|
141
|
-
--face-
|
|
142
|
-
|
|
143
|
-
display: block;
|
|
144
|
-
font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
|
|
368
|
+
background: var(--face-bg);
|
|
145
369
|
color: var(--text-primary, var(--face-text));
|
|
146
|
-
|
|
147
|
-
border: 1px solid var(--border, var(--face-line));
|
|
370
|
+
border: 1px solid var(--border, var(--face-border));
|
|
148
371
|
border-radius: 8px;
|
|
149
372
|
padding: 16px;
|
|
150
|
-
|
|
151
|
-
overflow: hidden;
|
|
373
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
152
374
|
}
|
|
153
375
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
animation-duration: 0.01ms !important;
|
|
157
|
-
animation-iteration-count: 1 !important;
|
|
158
|
-
transition-duration: 0.01ms !important;
|
|
159
|
-
}
|
|
376
|
+
*, *::before, *::after {
|
|
377
|
+
box-sizing: inherit;
|
|
160
378
|
}
|
|
161
379
|
|
|
162
|
-
|
|
163
|
-
.header {
|
|
380
|
+
.header-bar {
|
|
164
381
|
display: flex;
|
|
165
382
|
align-items: center;
|
|
166
383
|
justify-content: space-between;
|
|
167
|
-
flex-wrap: wrap;
|
|
168
384
|
gap: 12px;
|
|
169
|
-
|
|
170
|
-
border-bottom: 1px solid var(--border, var(--face-
|
|
171
|
-
|
|
385
|
+
margin-bottom: 12px;
|
|
386
|
+
border-bottom: 1px solid var(--border, var(--face-border));
|
|
387
|
+
padding-bottom: 12px;
|
|
172
388
|
}
|
|
173
389
|
|
|
174
|
-
.brand-
|
|
390
|
+
.brand-cluster {
|
|
175
391
|
display: flex;
|
|
176
392
|
align-items: center;
|
|
177
|
-
gap:
|
|
393
|
+
gap: 8px;
|
|
178
394
|
}
|
|
179
395
|
|
|
180
396
|
.wordmark-badge {
|
|
181
|
-
|
|
397
|
+
display: inline-flex;
|
|
398
|
+
align-items: center;
|
|
399
|
+
font-family: ui-monospace, monospace;
|
|
182
400
|
font-size: 13px;
|
|
183
|
-
font-weight:
|
|
401
|
+
font-weight: 700;
|
|
184
402
|
letter-spacing: 0.05em;
|
|
185
|
-
color: var(--
|
|
186
|
-
background:
|
|
187
|
-
padding:
|
|
188
|
-
border-radius:
|
|
189
|
-
border: 1px solid rgba(250, 204, 21, 0.3);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
.title-meta {
|
|
193
|
-
display: flex;
|
|
194
|
-
flex-direction: column;
|
|
403
|
+
color: var(--face-accent);
|
|
404
|
+
background: var(--face-surface-subtle);
|
|
405
|
+
padding: 4px 8px;
|
|
406
|
+
border-radius: 4px;
|
|
195
407
|
}
|
|
196
408
|
|
|
197
|
-
.
|
|
409
|
+
.system-title {
|
|
198
410
|
font-size: 14px;
|
|
199
|
-
font-weight:
|
|
411
|
+
font-weight: 600;
|
|
200
412
|
color: var(--text-primary, var(--face-text));
|
|
201
|
-
margin: 0;
|
|
202
413
|
}
|
|
203
414
|
|
|
204
|
-
.
|
|
415
|
+
.status-pill {
|
|
416
|
+
display: inline-flex;
|
|
417
|
+
align-items: center;
|
|
418
|
+
padding: 4px 10px;
|
|
419
|
+
border-radius: 12px;
|
|
205
420
|
font-size: 11px;
|
|
206
|
-
|
|
207
|
-
|
|
421
|
+
font-weight: 700;
|
|
422
|
+
letter-spacing: 0.04em;
|
|
423
|
+
text-transform: uppercase;
|
|
424
|
+
background: var(--face-surface-subtle);
|
|
425
|
+
color: var(--face-text-muted);
|
|
426
|
+
border: 1px solid var(--border, var(--face-border));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.status-pill.ok {
|
|
430
|
+
color: var(--face-ok);
|
|
431
|
+
border-color: var(--face-ok);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.status-pill.danger {
|
|
435
|
+
color: var(--face-danger);
|
|
436
|
+
border-color: var(--face-danger);
|
|
208
437
|
}
|
|
209
438
|
|
|
210
|
-
.
|
|
439
|
+
.screen-tabs {
|
|
211
440
|
display: flex;
|
|
212
|
-
align-items: center;
|
|
213
441
|
gap: 6px;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
442
|
+
margin-bottom: 16px;
|
|
443
|
+
border-bottom: 1px solid var(--border, var(--face-border));
|
|
444
|
+
padding-bottom: 8px;
|
|
445
|
+
overflow-x: auto;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.screen-tab-btn {
|
|
449
|
+
min-height: 36px;
|
|
450
|
+
padding: 0 12px;
|
|
451
|
+
font-size: 12px;
|
|
452
|
+
font-weight: 600;
|
|
221
453
|
border-radius: 6px;
|
|
222
|
-
|
|
454
|
+
border: 1px solid transparent;
|
|
455
|
+
background: transparent;
|
|
456
|
+
color: var(--face-text-muted);
|
|
457
|
+
cursor: pointer;
|
|
458
|
+
transition: all 0.15s ease;
|
|
459
|
+
display: inline-flex;
|
|
460
|
+
align-items: center;
|
|
461
|
+
white-space: nowrap;
|
|
223
462
|
}
|
|
224
463
|
|
|
225
|
-
|
|
226
|
-
|
|
464
|
+
.screen-tab-btn:hover {
|
|
465
|
+
color: var(--face-text);
|
|
466
|
+
background: var(--face-surface-subtle);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.screen-tab-btn.active {
|
|
470
|
+
color: var(--face-accent);
|
|
471
|
+
background: var(--face-surface);
|
|
472
|
+
border-color: var(--face-accent);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.stats-grid {
|
|
227
476
|
display: grid;
|
|
228
|
-
grid-template-columns:
|
|
229
|
-
gap:
|
|
477
|
+
grid-template-columns: repeat(3, 1fr);
|
|
478
|
+
gap: 8px;
|
|
230
479
|
margin-bottom: 16px;
|
|
231
480
|
}
|
|
232
481
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
482
|
+
.stat-card {
|
|
483
|
+
background: var(--face-surface);
|
|
484
|
+
border: 1px solid var(--border, var(--face-border));
|
|
485
|
+
border-radius: 6px;
|
|
486
|
+
padding: 10px;
|
|
237
487
|
}
|
|
238
488
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
489
|
+
.stat-label {
|
|
490
|
+
font-size: 11px;
|
|
491
|
+
text-transform: uppercase;
|
|
492
|
+
letter-spacing: 0.04em;
|
|
493
|
+
color: var(--face-text-muted);
|
|
494
|
+
margin-bottom: 4px;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.stat-value {
|
|
498
|
+
font-size: 16px;
|
|
499
|
+
font-weight: 700;
|
|
500
|
+
color: var(--text-primary, var(--face-text));
|
|
501
|
+
font-family: ui-monospace, monospace;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.section-header {
|
|
245
505
|
display: flex;
|
|
246
|
-
|
|
247
|
-
|
|
506
|
+
align-items: center;
|
|
507
|
+
justify-content: space-between;
|
|
508
|
+
margin-bottom: 8px;
|
|
248
509
|
}
|
|
249
510
|
|
|
250
|
-
.
|
|
251
|
-
font-size:
|
|
511
|
+
.section-title {
|
|
512
|
+
font-size: 12px;
|
|
252
513
|
font-weight: 700;
|
|
253
514
|
text-transform: uppercase;
|
|
254
515
|
letter-spacing: 0.05em;
|
|
255
|
-
color: var(--
|
|
256
|
-
margin: 0;
|
|
516
|
+
color: var(--face-accent);
|
|
257
517
|
}
|
|
258
518
|
|
|
259
519
|
.hub-list {
|
|
260
520
|
display: flex;
|
|
261
521
|
flex-direction: column;
|
|
262
522
|
gap: 6px;
|
|
263
|
-
|
|
523
|
+
margin-bottom: 16px;
|
|
524
|
+
max-height: 180px;
|
|
264
525
|
overflow-y: auto;
|
|
265
526
|
}
|
|
266
527
|
|
|
267
528
|
.hub-item {
|
|
268
|
-
padding: 10px 12px;
|
|
269
|
-
background: rgba(15, 23, 42, 0.6);
|
|
270
|
-
border: 1px solid var(--border, var(--face-line));
|
|
271
|
-
border-radius: 5px;
|
|
272
529
|
display: flex;
|
|
273
530
|
align-items: center;
|
|
274
531
|
justify-content: space-between;
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
flex-direction: column;
|
|
281
|
-
gap: 2px;
|
|
532
|
+
background: var(--face-surface);
|
|
533
|
+
border: 1px solid var(--border, var(--face-border));
|
|
534
|
+
border-radius: 6px;
|
|
535
|
+
padding: 8px 12px;
|
|
536
|
+
font-size: 13px;
|
|
282
537
|
}
|
|
283
538
|
|
|
284
539
|
.hub-title {
|
|
285
|
-
font-
|
|
286
|
-
font-size: 12px;
|
|
287
|
-
font-weight: 700;
|
|
540
|
+
font-weight: 600;
|
|
288
541
|
color: var(--text-primary, var(--face-text));
|
|
289
542
|
}
|
|
290
543
|
|
|
291
|
-
.hub-
|
|
292
|
-
font-
|
|
293
|
-
|
|
544
|
+
.hub-meta {
|
|
545
|
+
font-family: ui-monospace, monospace;
|
|
546
|
+
font-size: 11px;
|
|
547
|
+
color: var(--face-text-muted);
|
|
294
548
|
}
|
|
295
549
|
|
|
296
|
-
.
|
|
550
|
+
.empty-state {
|
|
297
551
|
display: flex;
|
|
298
552
|
align-items: center;
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
553
|
+
justify-content: center;
|
|
554
|
+
padding: 24px;
|
|
555
|
+
color: var(--face-text-muted);
|
|
556
|
+
background: var(--face-surface);
|
|
557
|
+
border: 1px dashed var(--border, var(--face-border));
|
|
558
|
+
border-radius: 6px;
|
|
559
|
+
font-size: 13px;
|
|
303
560
|
}
|
|
304
561
|
|
|
305
|
-
/* Ingest Deck Column */
|
|
306
562
|
.ingest-deck {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
563
|
+
background: var(--face-surface);
|
|
564
|
+
border: 1px solid var(--border, var(--face-border));
|
|
565
|
+
border-radius: 6px;
|
|
566
|
+
padding: 12px;
|
|
567
|
+
margin-bottom: 16px;
|
|
310
568
|
}
|
|
311
569
|
|
|
312
|
-
.
|
|
313
|
-
|
|
570
|
+
.config-deck {
|
|
571
|
+
background: var(--face-surface);
|
|
572
|
+
border: 1px solid var(--border, var(--face-border));
|
|
314
573
|
border-radius: 6px;
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
574
|
+
padding: 14px;
|
|
575
|
+
margin-bottom: 16px;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.config-grid {
|
|
579
|
+
display: grid;
|
|
580
|
+
grid-template-columns: 1fr 1fr;
|
|
581
|
+
gap: 12px;
|
|
582
|
+
margin-bottom: 14px;
|
|
320
583
|
}
|
|
321
584
|
|
|
322
|
-
.
|
|
585
|
+
.field-group {
|
|
323
586
|
display: flex;
|
|
324
587
|
flex-direction: column;
|
|
325
588
|
gap: 4px;
|
|
326
589
|
}
|
|
327
590
|
|
|
328
|
-
.
|
|
329
|
-
|
|
591
|
+
.field-group.full-width {
|
|
592
|
+
grid-column: 1 / -1;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.field-label {
|
|
596
|
+
font-size: 11px;
|
|
597
|
+
font-weight: 700;
|
|
330
598
|
text-transform: uppercase;
|
|
331
|
-
|
|
332
|
-
|
|
599
|
+
letter-spacing: 0.04em;
|
|
600
|
+
color: var(--face-text-muted);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.input-group {
|
|
604
|
+
display: flex;
|
|
605
|
+
gap: 8px;
|
|
606
|
+
margin-bottom: 12px;
|
|
333
607
|
}
|
|
334
608
|
|
|
335
|
-
.text-input {
|
|
609
|
+
.path-input, .text-input, .select-input {
|
|
336
610
|
min-height: 44px;
|
|
611
|
+
background: var(--face-surface-subtle);
|
|
612
|
+
border: 1px solid var(--border, var(--face-border));
|
|
613
|
+
border-radius: 6px;
|
|
337
614
|
padding: 8px 12px;
|
|
338
|
-
font-family: var(--font-mono, 'JetBrains Mono', monospace);
|
|
339
|
-
font-size: 12px;
|
|
340
615
|
color: var(--text-primary, var(--face-text));
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
border-radius: 5px;
|
|
344
|
-
box-sizing: border-box;
|
|
616
|
+
font-family: ui-monospace, monospace;
|
|
617
|
+
font-size: 13px;
|
|
345
618
|
width: 100%;
|
|
346
619
|
}
|
|
347
620
|
|
|
348
|
-
.text-input:focus {
|
|
621
|
+
.path-input:focus, .text-input:focus, .select-input:focus {
|
|
349
622
|
outline: none;
|
|
350
|
-
border-color: var(--
|
|
623
|
+
border-color: var(--face-accent);
|
|
351
624
|
}
|
|
352
625
|
|
|
353
|
-
.
|
|
626
|
+
.presets-bar {
|
|
354
627
|
display: flex;
|
|
355
|
-
|
|
356
|
-
|
|
628
|
+
gap: 6px;
|
|
629
|
+
flex-wrap: wrap;
|
|
630
|
+
margin-bottom: 14px;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.preset-chip {
|
|
634
|
+
min-height: 32px;
|
|
635
|
+
padding: 4px 10px;
|
|
636
|
+
background: var(--face-surface-subtle);
|
|
637
|
+
border: 1px solid var(--border, var(--face-border));
|
|
638
|
+
border-radius: 16px;
|
|
357
639
|
font-size: 11px;
|
|
358
|
-
|
|
640
|
+
font-family: ui-monospace, monospace;
|
|
641
|
+
color: var(--face-text);
|
|
359
642
|
cursor: pointer;
|
|
643
|
+
transition: all 0.15s ease;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.preset-chip:hover {
|
|
647
|
+
border-color: var(--face-accent);
|
|
648
|
+
color: var(--face-accent);
|
|
360
649
|
}
|
|
361
650
|
|
|
362
|
-
.
|
|
363
|
-
|
|
364
|
-
|
|
651
|
+
.auth-notice-card {
|
|
652
|
+
display: flex;
|
|
653
|
+
align-items: center;
|
|
654
|
+
justify-content: space-between;
|
|
655
|
+
background: #022c22;
|
|
656
|
+
border: 1px solid var(--face-ok);
|
|
657
|
+
border-radius: 6px;
|
|
658
|
+
padding: 10px 14px;
|
|
659
|
+
margin-bottom: 14px;
|
|
660
|
+
font-size: 12px;
|
|
661
|
+
color: #a7f3d0;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.toggle-label {
|
|
665
|
+
display: inline-flex;
|
|
666
|
+
align-items: center;
|
|
667
|
+
gap: 8px;
|
|
668
|
+
min-height: 44px;
|
|
669
|
+
font-size: 13px;
|
|
670
|
+
color: var(--text-primary, var(--face-text));
|
|
365
671
|
cursor: pointer;
|
|
672
|
+
user-select: none;
|
|
673
|
+
padding: 0 4px;
|
|
366
674
|
}
|
|
367
675
|
|
|
368
|
-
.
|
|
676
|
+
.button-group {
|
|
677
|
+
display: grid;
|
|
678
|
+
grid-template-columns: repeat(2, 1fr);
|
|
679
|
+
gap: 8px;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.btn {
|
|
683
|
+
display: inline-flex;
|
|
684
|
+
align-items: center;
|
|
685
|
+
justify-content: center;
|
|
369
686
|
min-height: 44px;
|
|
370
|
-
padding:
|
|
371
|
-
font-family: var(--font-sans, sans-serif);
|
|
687
|
+
padding: 0 12px;
|
|
372
688
|
font-size: 12px;
|
|
373
|
-
font-weight:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
border: none;
|
|
377
|
-
border-radius: 5px;
|
|
689
|
+
font-weight: 600;
|
|
690
|
+
border-radius: 6px;
|
|
691
|
+
border: 1px solid transparent;
|
|
378
692
|
cursor: pointer;
|
|
379
|
-
transition: background 0.15s ease;
|
|
693
|
+
transition: background-color 0.15s ease, border-color 0.15s ease;
|
|
694
|
+
text-align: center;
|
|
380
695
|
}
|
|
381
696
|
|
|
382
|
-
.btn-
|
|
383
|
-
background:
|
|
697
|
+
.btn-primary {
|
|
698
|
+
background: var(--face-accent);
|
|
699
|
+
color: var(--face-bg);
|
|
384
700
|
}
|
|
385
701
|
|
|
386
|
-
.btn-
|
|
387
|
-
|
|
388
|
-
cursor: not-allowed;
|
|
702
|
+
.btn-primary:hover:not(:disabled) {
|
|
703
|
+
background: var(--face-accent-hover);
|
|
389
704
|
}
|
|
390
705
|
|
|
391
|
-
.btn-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
font-family: var(--font-sans, sans-serif);
|
|
395
|
-
font-size: 12px;
|
|
396
|
-
font-weight: 700;
|
|
706
|
+
.btn-secondary {
|
|
707
|
+
background: var(--face-surface-subtle);
|
|
708
|
+
border-color: var(--border, var(--face-border));
|
|
397
709
|
color: var(--text-primary, var(--face-text));
|
|
398
|
-
background: transparent;
|
|
399
|
-
border: 1px solid var(--border, var(--face-line));
|
|
400
|
-
border-radius: 5px;
|
|
401
|
-
cursor: pointer;
|
|
402
|
-
transition: background 0.15s ease;
|
|
403
710
|
}
|
|
404
711
|
|
|
405
|
-
.btn-
|
|
406
|
-
|
|
712
|
+
.btn-secondary:hover:not(:disabled) {
|
|
713
|
+
border-color: var(--face-accent);
|
|
407
714
|
}
|
|
408
715
|
|
|
409
|
-
.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
font-family: var(--font-mono, 'JetBrains Mono', monospace);
|
|
413
|
-
font-size: 11px;
|
|
716
|
+
.btn:disabled {
|
|
717
|
+
opacity: 0.5;
|
|
718
|
+
cursor: not-allowed;
|
|
414
719
|
}
|
|
415
720
|
|
|
416
|
-
.
|
|
417
|
-
background:
|
|
418
|
-
border: 1px solid
|
|
419
|
-
|
|
721
|
+
.result-deck {
|
|
722
|
+
background: var(--face-surface-subtle);
|
|
723
|
+
border: 1px solid var(--border, var(--face-border));
|
|
724
|
+
border-radius: 6px;
|
|
725
|
+
padding: 12px;
|
|
726
|
+
font-family: ui-monospace, monospace;
|
|
727
|
+
font-size: 12px;
|
|
728
|
+
color: var(--text-primary, var(--face-text));
|
|
729
|
+
margin-top: 12px;
|
|
420
730
|
}
|
|
421
731
|
|
|
422
|
-
.
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
732
|
+
.result-title {
|
|
733
|
+
font-weight: 600;
|
|
734
|
+
color: var(--face-accent);
|
|
735
|
+
margin-bottom: 6px;
|
|
426
736
|
}
|
|
427
737
|
|
|
428
|
-
.
|
|
429
|
-
|
|
430
|
-
|
|
738
|
+
.error-deck {
|
|
739
|
+
background: var(--face-surface);
|
|
740
|
+
border: 1px solid var(--face-danger);
|
|
741
|
+
border-radius: 6px;
|
|
742
|
+
padding: 12px;
|
|
743
|
+
color: var(--face-danger);
|
|
431
744
|
font-size: 12px;
|
|
432
|
-
|
|
745
|
+
margin-bottom: 12px;
|
|
433
746
|
}
|
|
434
747
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
display: flex;
|
|
438
|
-
justify-content: space-between;
|
|
748
|
+
.repo-status-badge {
|
|
749
|
+
display: inline-flex;
|
|
439
750
|
align-items: center;
|
|
440
|
-
padding
|
|
441
|
-
|
|
442
|
-
border-top: 1px solid var(--border, var(--face-line));
|
|
751
|
+
padding: 2px 6px;
|
|
752
|
+
border-radius: 4px;
|
|
443
753
|
font-size: 10px;
|
|
444
|
-
|
|
754
|
+
font-weight: 700;
|
|
755
|
+
letter-spacing: 0.04em;
|
|
756
|
+
text-transform: uppercase;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.repo-status-badge.current {
|
|
760
|
+
background: #064e3b;
|
|
761
|
+
color: #6ee7b7;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.repo-status-badge.due {
|
|
765
|
+
background: #78350f;
|
|
766
|
+
color: #fde68a;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.repo-status-badge.uninit {
|
|
770
|
+
background: #831843;
|
|
771
|
+
color: #fbcfe8;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
@media (prefers-reduced-motion: reduce) {
|
|
775
|
+
*, *::before, *::after {
|
|
776
|
+
animation-duration: 0.01ms !important;
|
|
777
|
+
animation-iteration-count: 1 !important;
|
|
778
|
+
transition-duration: 0.01ms !important;
|
|
779
|
+
scroll-behavior: auto !important;
|
|
780
|
+
}
|
|
445
781
|
}
|
|
446
782
|
</style>
|
|
447
783
|
|
|
448
|
-
<div class="header">
|
|
449
|
-
<div class="brand-
|
|
450
|
-
<
|
|
451
|
-
<
|
|
452
|
-
|
|
453
|
-
|
|
784
|
+
<div class="header-bar">
|
|
785
|
+
<div class="brand-cluster">
|
|
786
|
+
<span class="wordmark-badge">[BRAIN//DUMP]</span>
|
|
787
|
+
<span class="system-title">Knowledge Graph Engine</span>
|
|
788
|
+
</div>
|
|
789
|
+
<span class="status-pill ${this.statusText === 'SYNCHRONIZED' ? 'ok' : this.statusText === 'ERROR' ? 'danger' : ''}">
|
|
790
|
+
${this.statusText}
|
|
791
|
+
</span>
|
|
792
|
+
</div>
|
|
793
|
+
|
|
794
|
+
<nav class="screen-tabs" aria-label="OpenWiki navigation screens">
|
|
795
|
+
${OpenWikiCard.screens.map((screen) => `
|
|
796
|
+
<button
|
|
797
|
+
class="screen-tab-btn ${this.activeScreen === screen.id ? 'active' : ''}"
|
|
798
|
+
data-screen="${screen.id}"
|
|
799
|
+
>
|
|
800
|
+
${screen.label}
|
|
801
|
+
</button>
|
|
802
|
+
`).join('')}
|
|
803
|
+
</nav>
|
|
804
|
+
|
|
805
|
+
<div class="stats-grid">
|
|
806
|
+
<div class="stat-card">
|
|
807
|
+
<div class="stat-label">Discovered Hubs</div>
|
|
808
|
+
<div class="stat-value">${countText}</div>
|
|
809
|
+
</div>
|
|
810
|
+
<div class="stat-card">
|
|
811
|
+
<div class="stat-label">Documentation Lines</div>
|
|
812
|
+
<div class="stat-value">${linesText}</div>
|
|
813
|
+
</div>
|
|
814
|
+
<div class="stat-card">
|
|
815
|
+
<div class="stat-label">Active Model Routing</div>
|
|
816
|
+
<div class="stat-value" style="font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" title="${this.config.model}">
|
|
817
|
+
${this.config.model.split('/').pop() || this.config.model}
|
|
454
818
|
</div>
|
|
455
819
|
</div>
|
|
456
|
-
|
|
457
|
-
|
|
820
|
+
</div>
|
|
821
|
+
|
|
822
|
+
${this.errorMessage ? `
|
|
823
|
+
<div class="error-deck">
|
|
824
|
+
${this.errorMessage}
|
|
825
|
+
</div>
|
|
826
|
+
` : ''}
|
|
827
|
+
|
|
828
|
+
${this.renderActiveScreen()}
|
|
829
|
+
|
|
830
|
+
${this.executionResult ? `
|
|
831
|
+
<div class="result-deck">
|
|
832
|
+
<div class="result-title">Execution Receipt (${this.executionResult.timestamp})</div>
|
|
833
|
+
<div>Action: ${this.executionResult.action}</div>
|
|
834
|
+
<div>Target: ${this.executionResult.target || 'project'}</div>
|
|
835
|
+
<div>Result: ${JSON.stringify(this.executionResult.details)}</div>
|
|
458
836
|
</div>
|
|
837
|
+
` : ''}
|
|
838
|
+
`;
|
|
839
|
+
|
|
840
|
+
this.bindEvents();
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
renderActiveScreen() {
|
|
844
|
+
if (this.activeScreen === 'config') {
|
|
845
|
+
return this.renderConfigScreen();
|
|
846
|
+
}
|
|
847
|
+
if (this.activeScreen === 'refresh') {
|
|
848
|
+
return this.renderRefreshScreen();
|
|
849
|
+
}
|
|
850
|
+
if (this.activeScreen === 'upstream') {
|
|
851
|
+
return this.renderUpstreamScreen();
|
|
852
|
+
}
|
|
853
|
+
return this.renderHubsScreen();
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
renderHubsScreen() {
|
|
857
|
+
return `
|
|
858
|
+
<div class="section-header">
|
|
859
|
+
<span class="section-title">Knowledge Hubs</span>
|
|
860
|
+
<button id="btn-refresh" class="btn btn-secondary" style="min-height: 32px; padding: 0 10px; font-size: 11px;" ${this.loading ? 'disabled' : ''}>
|
|
861
|
+
Sync
|
|
862
|
+
</button>
|
|
459
863
|
</div>
|
|
460
864
|
|
|
461
|
-
<div class="
|
|
462
|
-
|
|
463
|
-
<
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
<span class="hub-title">${escapeHtml(h.title || h.path)}</span>
|
|
469
|
-
<span class="hub-path">${escapeHtml(h.path)}</span>
|
|
470
|
-
</div>
|
|
471
|
-
<div class="hub-metrics">
|
|
472
|
-
<span>${h.lines !== undefined ? `${h.lines} lines` : DASH}</span>
|
|
473
|
-
</div>
|
|
474
|
-
</div>
|
|
475
|
-
`).join('') : `
|
|
476
|
-
<div class="empty-hubs">No markdown documentation hubs indexed yet. Click Bootstrap below to initialize.</div>
|
|
477
|
-
`}
|
|
865
|
+
<div class="hub-list">
|
|
866
|
+
${this.hubs.length === 0 ? `
|
|
867
|
+
<div class="empty-state">No documentation hubs indexed in ${this.targetPath}</div>
|
|
868
|
+
` : this.hubs.map((h) => `
|
|
869
|
+
<div class="hub-item">
|
|
870
|
+
<span class="hub-title">${h.title}</span>
|
|
871
|
+
<span class="hub-meta">${h.lines} lines · ${h.path}</span>
|
|
478
872
|
</div>
|
|
873
|
+
`).join('')}
|
|
874
|
+
</div>
|
|
875
|
+
|
|
876
|
+
<div class="ingest-deck">
|
|
877
|
+
<div class="input-group">
|
|
878
|
+
<input
|
|
879
|
+
id="target-path-input"
|
|
880
|
+
class="path-input"
|
|
881
|
+
type="text"
|
|
882
|
+
value="${this.targetPath}"
|
|
883
|
+
placeholder="Directory path (openwiki)"
|
|
884
|
+
aria-label="Target documentation path"
|
|
885
|
+
/>
|
|
886
|
+
<label class="toggle-label">
|
|
887
|
+
<input
|
|
888
|
+
id="dry-run-checkbox"
|
|
889
|
+
type="checkbox"
|
|
890
|
+
${this.dryRun ? 'checked' : ''}
|
|
891
|
+
/>
|
|
892
|
+
Dry Run
|
|
893
|
+
</label>
|
|
479
894
|
</div>
|
|
480
895
|
|
|
481
|
-
<div class="
|
|
482
|
-
<
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
896
|
+
<div class="button-group">
|
|
897
|
+
<button id="btn-ingest" class="btn btn-primary" ${this.loading ? 'disabled' : ''}>
|
|
898
|
+
${this.loading ? 'Processing…' : 'Ingest Documentation'}
|
|
899
|
+
</button>
|
|
900
|
+
<button id="btn-bootstrap" class="btn btn-secondary" ${this.loading ? 'disabled' : ''}>
|
|
901
|
+
Bootstrap Wiki
|
|
902
|
+
</button>
|
|
903
|
+
</div>
|
|
904
|
+
</div>
|
|
905
|
+
`;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
renderConfigScreen() {
|
|
909
|
+
return `
|
|
910
|
+
<div class="config-deck">
|
|
911
|
+
<div class="section-header">
|
|
912
|
+
<span class="section-title">Documentation Model & Provider Routing</span>
|
|
913
|
+
</div>
|
|
914
|
+
|
|
915
|
+
<div class="auth-notice-card">
|
|
916
|
+
<span>✓ Model credentials routed via Total Recall Auth store (<code>total-recall auth secret</code>)</span>
|
|
917
|
+
<span style="font-family: ui-monospace, monospace; font-size: 10px;">AUTH_PLUGIN: ACTIVE</span>
|
|
918
|
+
</div>
|
|
919
|
+
|
|
920
|
+
<div class="field-label" style="margin-bottom: 6px;">Recommended Model Presets:</div>
|
|
921
|
+
<div class="presets-bar">
|
|
922
|
+
<button class="preset-chip" data-provider="openrouter" data-model="deepseek/deepseek-v4.1-flash" data-fallback="qwen/qwen-2.5-coder-32b-instruct">
|
|
923
|
+
DeepSeek V4.1 Flash ($0.025/1M)
|
|
924
|
+
</button>
|
|
925
|
+
<button class="preset-chip" data-provider="openrouter" data-model="qwen/qwen-2.5-coder-32b-instruct" data-fallback="deepseek/deepseek-v4.1-flash">
|
|
926
|
+
Qwen 2.5 Coder 32B ($0.06/1M)
|
|
927
|
+
</button>
|
|
928
|
+
<button class="preset-chip" data-provider="google" data-model="gemini-2.5-flash-lite" data-fallback="gemini-2.5-flash">
|
|
929
|
+
Gemini 2.5 Flash-Lite ($0.075/1M)
|
|
930
|
+
</button>
|
|
931
|
+
</div>
|
|
932
|
+
|
|
933
|
+
<div class="config-grid">
|
|
934
|
+
<div class="field-group">
|
|
935
|
+
<label class="field-label" for="cfg-provider">Provider</label>
|
|
936
|
+
<select id="cfg-provider" class="select-input">
|
|
937
|
+
<option value="openrouter" ${this.config.provider === 'openrouter' ? 'selected' : ''}>OpenRouter (Multi-Model Hub)</option>
|
|
938
|
+
<option value="google" ${this.config.provider === 'google' ? 'selected' : ''}>Google (Gemini Direct)</option>
|
|
939
|
+
<option value="custom" ${this.config.provider === 'custom' ? 'selected' : ''}>Custom Provider</option>
|
|
940
|
+
</select>
|
|
498
941
|
</div>
|
|
499
942
|
|
|
500
|
-
|
|
501
|
-
<
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
943
|
+
<div class="field-group">
|
|
944
|
+
<label class="field-label" for="cfg-model">Primary Model Identifier</label>
|
|
945
|
+
<input id="cfg-model" class="text-input" type="text" value="${this.config.model}" placeholder="e.g. deepseek/deepseek-v4.1-flash" />
|
|
946
|
+
</div>
|
|
947
|
+
|
|
948
|
+
<div class="field-group">
|
|
949
|
+
<label class="field-label" for="cfg-fallback">Fallback Model Identifier</label>
|
|
950
|
+
<input id="cfg-fallback" class="text-input" type="text" value="${this.config.fallback_model}" placeholder="e.g. qwen/qwen-2.5-coder-32b-instruct" />
|
|
951
|
+
</div>
|
|
952
|
+
|
|
953
|
+
<div class="field-group">
|
|
954
|
+
<label class="field-label" for="cfg-tokens">Max Output Tokens</label>
|
|
955
|
+
<input id="cfg-tokens" class="text-input" type="number" value="${this.config.max_tokens}" min="512" max="131072" />
|
|
956
|
+
</div>
|
|
957
|
+
|
|
958
|
+
<div class="field-group full-width">
|
|
959
|
+
<label class="field-label" for="cfg-timeout">Timeout (milliseconds)</label>
|
|
960
|
+
<input id="cfg-timeout" class="text-input" type="number" value="${this.config.timeout_ms}" min="30000" max="1800000" />
|
|
961
|
+
</div>
|
|
962
|
+
</div>
|
|
963
|
+
|
|
964
|
+
<div class="button-group">
|
|
965
|
+
<button id="btn-save-config" class="btn btn-primary" ${this.loading ? 'disabled' : ''}>
|
|
966
|
+
Save Configuration
|
|
967
|
+
</button>
|
|
968
|
+
<button id="btn-reset-config" class="btn btn-secondary" ${this.loading ? 'disabled' : ''}>
|
|
969
|
+
Reset to Defaults
|
|
970
|
+
</button>
|
|
505
971
|
</div>
|
|
506
972
|
</div>
|
|
973
|
+
`;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
renderRefreshScreen() {
|
|
977
|
+
const dueCount = this.refreshCounts?.due ?? this.refreshReports.filter((r) => r.action === 'due').length;
|
|
978
|
+
const uninitCount = this.refreshCounts?.uninitialized ?? this.refreshReports.filter((r) => r.uninitialized).length;
|
|
979
|
+
|
|
980
|
+
return `
|
|
981
|
+
<div class="ingest-deck">
|
|
982
|
+
<div class="section-header">
|
|
983
|
+
<span class="section-title">Fleet Documentation Governance</span>
|
|
984
|
+
<button id="btn-sync-refresh" class="btn btn-secondary" style="min-height: 32px; padding: 0 10px; font-size: 11px;" ${this.loading ? 'disabled' : ''}>
|
|
985
|
+
Check Fleet
|
|
986
|
+
</button>
|
|
987
|
+
</div>
|
|
507
988
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
989
|
+
<div style="font-size: 12px; color: var(--face-text-muted); margin-bottom: 12px;">
|
|
990
|
+
Registered Projects: <strong>${this.refreshReports.length}</strong> · Due for Update: <strong>${dueCount}</strong> · Uninitialized: <strong>${uninitCount}</strong>
|
|
991
|
+
</div>
|
|
992
|
+
|
|
993
|
+
<div class="hub-list" style="max-height: 240px;">
|
|
994
|
+
${this.refreshReports.length === 0 ? `
|
|
995
|
+
<div class="empty-state">No fleet report loaded. Click Check Fleet to inspect registered repositories.</div>
|
|
996
|
+
` : this.refreshReports.map((r) => {
|
|
997
|
+
let badgeClass = 'current';
|
|
998
|
+
let badgeText = 'CURRENT';
|
|
999
|
+
if (r.uninitialized) {
|
|
1000
|
+
badgeClass = 'uninit';
|
|
1001
|
+
badgeText = 'MISSING WIKI';
|
|
1002
|
+
} else if (r.action === 'due') {
|
|
1003
|
+
badgeClass = 'due';
|
|
1004
|
+
badgeText = 'DUE';
|
|
1005
|
+
}
|
|
1006
|
+
return `
|
|
1007
|
+
<div class="hub-item">
|
|
1008
|
+
<div>
|
|
1009
|
+
<span class="hub-title">${r.name}</span>
|
|
1010
|
+
<div class="hub-meta">${r.generatedAt ? `Generated ${r.generatedAt.slice(0, 10)}` : 'Never generated'} · ${r.commitsSince ? `${r.commitsSince} commits behind` : 'Up to date'}</div>
|
|
1011
|
+
</div>
|
|
1012
|
+
<span class="repo-status-badge ${badgeClass}">${badgeText}</span>
|
|
1013
|
+
</div>
|
|
1014
|
+
`;
|
|
1015
|
+
}).join('')}
|
|
1016
|
+
</div>
|
|
1017
|
+
|
|
1018
|
+
<div style="margin-top: 12px;">
|
|
1019
|
+
<button id="btn-fleet-refresh-apply" class="btn btn-primary" style="width: 100%;" ${this.loading ? 'disabled' : ''}>
|
|
1020
|
+
${this.loading ? 'Executing Fleet Refresh…' : `Regenerate Stale & Initialize Missing Wikis (${dueCount} due)`}
|
|
1021
|
+
</button>
|
|
1022
|
+
</div>
|
|
511
1023
|
</div>
|
|
512
1024
|
`;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
renderUpstreamScreen() {
|
|
1028
|
+
const currentVer = this.upstream?.recordedVersion || '0.7.2';
|
|
1029
|
+
const latestVer = this.upstream?.latestVersion || '0.7.3';
|
|
1030
|
+
|
|
1031
|
+
return `
|
|
1032
|
+
<div class="ingest-deck">
|
|
1033
|
+
<div class="section-header">
|
|
1034
|
+
<span class="section-title">Upstream Package Surveillance</span>
|
|
1035
|
+
</div>
|
|
1036
|
+
|
|
1037
|
+
<div class="stats-grid" style="margin-bottom: 14px;">
|
|
1038
|
+
<div class="stat-card">
|
|
1039
|
+
<div class="stat-label">Recorded Version</div>
|
|
1040
|
+
<div class="stat-value">v${currentVer}</div>
|
|
1041
|
+
</div>
|
|
1042
|
+
<div class="stat-card">
|
|
1043
|
+
<div class="stat-label">Latest Registry</div>
|
|
1044
|
+
<div class="stat-value">v${latestVer}</div>
|
|
1045
|
+
</div>
|
|
1046
|
+
<div class="stat-card">
|
|
1047
|
+
<div class="stat-label">Watcher Status</div>
|
|
1048
|
+
<div class="stat-value" style="color: var(--face-ok);">MONITORING</div>
|
|
1049
|
+
</div>
|
|
1050
|
+
</div>
|
|
1051
|
+
|
|
1052
|
+
<div class="button-group">
|
|
1053
|
+
<button id="btn-watch" class="btn btn-secondary" ${this.loading ? 'disabled' : ''}>
|
|
1054
|
+
Check Upstream Registry
|
|
1055
|
+
</button>
|
|
1056
|
+
<button id="btn-propagate" class="btn btn-primary" ${this.loading ? 'disabled' : ''}>
|
|
1057
|
+
Propagate Latest Generator
|
|
1058
|
+
</button>
|
|
1059
|
+
</div>
|
|
1060
|
+
</div>
|
|
1061
|
+
`;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
bindEvents() {
|
|
1065
|
+
const shadow = this.shadowRoot;
|
|
1066
|
+
if (!shadow) return;
|
|
513
1067
|
|
|
514
|
-
|
|
515
|
-
|
|
1068
|
+
shadow.querySelectorAll('.screen-tab-btn').forEach((tab) => {
|
|
1069
|
+
tab.addEventListener('click', () => {
|
|
1070
|
+
const targetScreen = tab.getAttribute('data-screen');
|
|
1071
|
+
if (targetScreen) this.setScreen(targetScreen);
|
|
1072
|
+
});
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
const pathInput = shadow.querySelector('#target-path-input');
|
|
516
1076
|
if (pathInput) {
|
|
517
|
-
pathInput.
|
|
518
|
-
|
|
519
|
-
this.targetPath = e.target.value;
|
|
1077
|
+
pathInput.addEventListener('input', (e) => {
|
|
1078
|
+
this.targetPath = e.target.value.trim();
|
|
520
1079
|
});
|
|
521
1080
|
}
|
|
522
1081
|
|
|
523
|
-
const
|
|
524
|
-
if (
|
|
525
|
-
|
|
1082
|
+
const dryRunCheckbox = shadow.querySelector('#dry-run-checkbox');
|
|
1083
|
+
if (dryRunCheckbox) {
|
|
1084
|
+
dryRunCheckbox.addEventListener('change', (e) => {
|
|
526
1085
|
this.dryRun = e.target.checked;
|
|
527
1086
|
});
|
|
528
1087
|
}
|
|
529
1088
|
|
|
530
|
-
|
|
531
|
-
|
|
1089
|
+
const btnIngest = shadow.querySelector('#btn-ingest');
|
|
1090
|
+
if (btnIngest) {
|
|
1091
|
+
btnIngest.addEventListener('click', () => this.executeIngest());
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
const btnBootstrap = shadow.querySelector('#btn-bootstrap');
|
|
1095
|
+
if (btnBootstrap) {
|
|
1096
|
+
btnBootstrap.addEventListener('click', () => this.executeBootstrap());
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
const btnRefresh = shadow.querySelector('#btn-refresh');
|
|
1100
|
+
if (btnRefresh) {
|
|
1101
|
+
btnRefresh.addEventListener('click', () => this.refreshHubs());
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
const btnSyncRefresh = shadow.querySelector('#btn-sync-refresh');
|
|
1105
|
+
if (btnSyncRefresh) {
|
|
1106
|
+
btnSyncRefresh.addEventListener('click', () => this.loadRefreshReport());
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
const btnFleetApply = shadow.querySelector('#btn-fleet-refresh-apply');
|
|
1110
|
+
if (btnFleetApply) {
|
|
1111
|
+
btnFleetApply.addEventListener('click', () => this.executeFleetRefresh());
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
const btnWatch = shadow.querySelector('#btn-watch');
|
|
1115
|
+
if (btnWatch) {
|
|
1116
|
+
btnWatch.addEventListener('click', () => this.executeWatch());
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
const btnPropagate = shadow.querySelector('#btn-propagate');
|
|
1120
|
+
if (btnPropagate) {
|
|
1121
|
+
btnPropagate.addEventListener('click', () => this.executePropagate());
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
shadow.querySelectorAll('.preset-chip').forEach((chip) => {
|
|
1125
|
+
chip.addEventListener('click', async () => {
|
|
1126
|
+
const p = chip.getAttribute('data-provider');
|
|
1127
|
+
const m = chip.getAttribute('data-model');
|
|
1128
|
+
const f = chip.getAttribute('data-fallback');
|
|
1129
|
+
if (p) await this.setConfigValue('provider', p);
|
|
1130
|
+
if (m) await this.setConfigValue('model', m);
|
|
1131
|
+
if (f) await this.setConfigValue('fallback_model', f);
|
|
1132
|
+
});
|
|
1133
|
+
});
|
|
1134
|
+
|
|
1135
|
+
const btnSaveConfig = shadow.querySelector('#btn-save-config');
|
|
1136
|
+
if (btnSaveConfig) {
|
|
1137
|
+
btnSaveConfig.addEventListener('click', async () => {
|
|
1138
|
+
const provider = shadow.querySelector('#cfg-provider')?.value;
|
|
1139
|
+
const model = shadow.querySelector('#cfg-model')?.value;
|
|
1140
|
+
const fallback = shadow.querySelector('#cfg-fallback')?.value;
|
|
1141
|
+
const tokens = shadow.querySelector('#cfg-tokens')?.value;
|
|
1142
|
+
const timeout = shadow.querySelector('#cfg-timeout')?.value;
|
|
1143
|
+
|
|
1144
|
+
if (provider) await this.setConfigValue('provider', provider);
|
|
1145
|
+
if (model) await this.setConfigValue('model', model);
|
|
1146
|
+
if (fallback) await this.setConfigValue('fallback_model', fallback);
|
|
1147
|
+
if (tokens) await this.setConfigValue('max_tokens', tokens);
|
|
1148
|
+
if (timeout) await this.setConfigValue('timeout_ms', timeout);
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
const btnResetConfig = shadow.querySelector('#btn-reset-config');
|
|
1153
|
+
if (btnResetConfig) {
|
|
1154
|
+
btnResetConfig.addEventListener('click', () => this.resetConfig());
|
|
1155
|
+
}
|
|
532
1156
|
}
|
|
533
1157
|
}
|
|
534
1158
|
|