@silicaclaw/cli 2026.3.19-6 → 2026.3.19-7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## v1.0 beta - 2026-03-19
4
4
 
5
- ### 2026.3.19-6
5
+ ### 2026.3.19-7
6
6
 
7
7
  - local-console UI polish:
8
8
  - sidebar spacing, collapsed rail behavior, footer version card, and topbar shell now align more closely with OpenClaw
package/VERSION CHANGED
@@ -1 +1 @@
1
- v2026.3.19-6
1
+ v2026.3.19-7
@@ -0,0 +1,473 @@
1
+ import { appTemplate } from "./template.js";
2
+ import { createI18n } from "./i18n.js";
3
+ import { createNetworkController } from "./network.js";
4
+ import { createOverviewController } from "./overview.js";
5
+ import { createProfileController } from "./profile.js";
6
+ import { createShellController } from "./shell.js";
7
+ import { createSocialController } from "./social.js";
8
+ import { bindAppEvents } from "./events.js";
9
+ import { TRANSLATIONS } from "./translations.js";
10
+ import {
11
+ ago,
12
+ describeCurrentMode,
13
+ escapeHtml,
14
+ field,
15
+ formatMessageBody,
16
+ messageSendReasonText,
17
+ normalizeTagsInput,
18
+ parseCsv,
19
+ parseTags,
20
+ resolveThemeMode,
21
+ shortId,
22
+ toPrettyJson,
23
+ } from "./utils.js";
24
+
25
+ const root = document.getElementById("app-root");
26
+ if (!root) {
27
+ throw new Error("Missing root element: app-root");
28
+ }
29
+ root.innerHTML = appTemplate;
30
+
31
+ const i18n = createI18n(TRANSLATIONS);
32
+ const DEFAULT_LOCALE = i18n.DEFAULT_LOCALE;
33
+ const t = i18n.t;
34
+ let currentLocale = i18n.getCurrentLocale();
35
+ function setLocale(locale) {
36
+ currentLocale = i18n.setLocale(locale);
37
+ }
38
+ function applyStaticTranslations() {
39
+ const setText = (selector, text, index = 0) => {
40
+ const nodes = document.querySelectorAll(selector);
41
+ if (nodes[index]) nodes[index].textContent = text;
42
+ };
43
+ document.title = t('meta.title');
44
+ document.getElementById('metaDescription').setAttribute('content', t('meta.description'));
45
+ document.getElementById('ogTitle').setAttribute('content', t('meta.socialTitle'));
46
+ document.getElementById('ogDescription').setAttribute('content', t('meta.socialDescription'));
47
+ document.getElementById('twitterTitle').setAttribute('content', t('meta.socialTitle'));
48
+ document.getElementById('twitterDescription').setAttribute('content', t('meta.socialDescription'));
49
+ setText('.brand p', t('common.localConsole'));
50
+ document.querySelectorAll('.advanced-panel summary').forEach((summary) => {
51
+ summary.setAttribute('data-i18n-closed-label', t('labels.show'));
52
+ summary.setAttribute('data-i18n-open-label', t('labels.hide'));
53
+ });
54
+ setText('.sidebar-nav__label', t('common.control'));
55
+ setText('[data-tab="overview"] .tab-title', t('pageMeta.overview.title'));
56
+ setText('[data-tab="overview"] .tab-copy', t('labels.overviewTabCopy'));
57
+ setText('[data-tab="agent"] .tab-title', t('pageMeta.agent.title'));
58
+ setText('[data-tab="agent"] .tab-copy', t('labels.agentTabCopy'));
59
+ setText('[data-tab="chat"] .tab-title', t('pageMeta.chat.title'));
60
+ setText('[data-tab="chat"] .tab-copy', t('labels.chatTabCopy'));
61
+ setText('[data-tab="skills"] .tab-title', t('pageMeta.skills.title'));
62
+ setText('[data-tab="skills"] .tab-copy', t('labels.skillsTabCopy'));
63
+ setText('[data-tab="profile"] .tab-title', t('pageMeta.profile.title'));
64
+ setText('[data-tab="profile"] .tab-copy', t('labels.profileTabCopy'));
65
+ setText('[data-tab="network"] .tab-title', t('pageMeta.network.title'));
66
+ setText('[data-tab="network"] .tab-copy', t('labels.networkTabCopy'));
67
+ setText('[data-tab="social"] .tab-title', t('pageMeta.social.title'));
68
+ setText('[data-tab="social"] .tab-copy', t('labels.socialTabCopy'));
69
+ document.getElementById('sidebarToggleBtn').title = t('labels.collapseSidebar');
70
+ document.getElementById('sidebarToggleBtn').setAttribute('aria-label', t('labels.collapseSidebar'));
71
+ document.querySelector('.sidebar-version').title = t('common.version');
72
+ setText('.sidebar-version__label', t('common.version'));
73
+ document.getElementById('integrationStatusBar').textContent = t('social.barStatus', {
74
+ connected: '-',
75
+ mode: '-',
76
+ public: '-',
77
+ });
78
+ setText('.dashboard-header__breadcrumb-current', t('pageMeta.overview.title'));
79
+ document.getElementById('pageBreadcrumb').textContent = t('pageMeta.overview.title');
80
+ document.getElementById('pageHeroTitle').textContent = t('pageMeta.overview.title');
81
+ document.getElementById('pageHeroBody').textContent = t('pageMeta.overview.body');
82
+ document.getElementById('focusModeBtn').title = t('labels.toggleFocusMode');
83
+ document.getElementById('focusModeBtn').setAttribute('aria-label', t('labels.toggleFocusMode'));
84
+ document.getElementById('themeModeGroup').setAttribute('aria-label', t('labels.colorMode'));
85
+ document.querySelector('[data-theme-choice="dark"]').title = t('labels.dark');
86
+ document.querySelector('[data-theme-choice="dark"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.dark')}`);
87
+ document.querySelector('[data-theme-choice="light"]').title = t('labels.light');
88
+ document.querySelector('[data-theme-choice="light"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.light')}`);
89
+ document.querySelector('[data-theme-choice="system"]').title = t('labels.system');
90
+ document.querySelector('[data-theme-choice="system"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.system')}`);
91
+ document.getElementById('agentBannerEyebrow').textContent = t('pageMeta.agent.title');
92
+ document.getElementById('agentBannerTitle').textContent = t('hints.agentBannerTitle');
93
+ document.getElementById('agentBannerBody').textContent = t('hints.agentBannerBody');
94
+ document.getElementById('agentBannerDiscoveryLabel').textContent = t('hints.agentBannerDiscovery');
95
+ document.getElementById('agentBannerSourceLabel').textContent = t('hints.agentBannerSource');
96
+ document.getElementById('agentListTitle').textContent = t('labels.discoveredAgents');
97
+ document.getElementById('agentsCountHint').textContent = t('overview.agentsZero');
98
+ document.getElementById('agentListHint').textContent = t('hints.agentListHint');
99
+ document.getElementById('onlyOnlineToggleLabel').textContent = t('labels.onlyShowOnline');
100
+ document.getElementById('agentSnapshotTitle').textContent = t('labels.nodeSnapshot');
101
+ document.getElementById('chatBannerEyebrow').textContent = t('pageMeta.chat.title');
102
+ document.getElementById('chatBannerTitle').textContent = t('hints.chatBannerTitle');
103
+ document.getElementById('chatBannerBody').textContent = t('hints.chatBannerBody');
104
+ document.getElementById('chatBannerFeedLabel').textContent = t('hints.chatBannerFeed');
105
+ document.getElementById('chatComposerTitle').textContent = t('actions.sendPublicMessage');
106
+ document.getElementById('chatFeedHint').textContent = t('hints.chatFeedHint');
107
+ document.getElementById('overviewGuideTitle').textContent = t('overview.guideTitle');
108
+ document.getElementById('overviewGuideBody').textContent = t('overview.guideBody');
109
+ document.getElementById('overviewStepProfileEyebrow').textContent = t('overview.stepLabel', { step: '1' });
110
+ document.getElementById('overviewStepProfileTitle').textContent = t('overview.stepProfileTitle');
111
+ document.getElementById('overviewStepProfileBody').textContent = t('overview.stepProfileBody');
112
+ document.getElementById('overviewStepProfileBtn').textContent = t('actions.editProfile');
113
+ document.getElementById('overviewStepPublicEyebrow').textContent = t('overview.stepLabel', { step: '2' });
114
+ document.getElementById('overviewStepPublicTitle').textContent = t('overview.stepPublicTitle');
115
+ document.getElementById('overviewStepPublicBody').textContent = t('overview.stepPublicBody');
116
+ document.getElementById('overviewStepPublicBtn').textContent = t('actions.editProfile');
117
+ document.getElementById('overviewStepBroadcastEyebrow').textContent = t('overview.stepLabel', { step: '3' });
118
+ document.getElementById('overviewStepBroadcastTitle').textContent = t('overview.stepBroadcastTitle');
119
+ document.getElementById('overviewStepBroadcastBody').textContent = t('overview.stepBroadcastBody');
120
+ document.getElementById('overviewStepBroadcastBtn').textContent = t('actions.broadcastNow');
121
+ document.getElementById('homeMissionEyebrow').textContent = t('hints.homeMissionEyebrow');
122
+ document.getElementById('homeBriefTitle').textContent = t('hints.homeBriefTitle');
123
+ document.getElementById('homeOpenAgentBtn').textContent = t('actions.openAgent');
124
+ document.getElementById('homeOpenSocialBtn').textContent = t('pageMeta.social.title');
125
+ document.getElementById('homeBroadcastNowBtn').textContent = t('actions.broadcastNow');
126
+ document.getElementById('homeOpenNetworkBtn').textContent = t('actions.openNetwork');
127
+ document.getElementById('overviewSnapshotHint').textContent = t('hints.overviewSnapshotHint');
128
+ document.getElementById('socialMessageTitle').textContent = t('overview.messageTitle');
129
+ document.getElementById('socialMessageHint').textContent = t('overview.messageHint');
130
+ setText('#view-profile .section-header__eyebrow', t('labels.profileEyebrow'));
131
+ document.getElementById('profileBannerTitle').textContent = t('hints.profileBannerTitle');
132
+ document.getElementById('profileBannerBody').textContent = t('hints.profileBannerBody');
133
+ document.getElementById('profileBannerPublishingLabel').textContent = t('hints.profileBannerPublishing');
134
+ document.getElementById('profileBannerPublishingValue').textContent = t('hints.profileBannerPublishingValue');
135
+ setText('#view-profile .title-sm', t('labels.publicProfileEditor'), 0);
136
+ setText('#view-profile label', t('labels.displayName'), 0);
137
+ setText('#view-profile .row > div:nth-child(2) label', t('labels.avatarUrl'));
138
+ setText('#view-profile div > label + textarea', t('labels.bio'));
139
+ setText('#view-profile div > label + input[name="tags"]', t('labels.tagsCommaSeparated'));
140
+ document.querySelector('#view-profile input[name="display_name"]').setAttribute('placeholder', t('placeholders.agentName'));
141
+ document.querySelector('#view-profile input[name="avatar_url"]').setAttribute('placeholder', 'https://...');
142
+ document.querySelector('#view-profile textarea[name="bio"]').setAttribute('placeholder', t('placeholders.bioSummary'));
143
+ document.querySelector('#view-profile input[name="tags"]').setAttribute('placeholder', t('placeholders.tags'));
144
+ document.querySelector('#view-profile input[name="display_name"]').nextElementSibling.textContent = t('hints.discoverabilityRecommendation');
145
+ document.querySelector('#view-profile input[name="avatar_url"]').nextElementSibling.textContent = t('hints.avatarOptional');
146
+ document.querySelector('#view-profile input[name="tags"]').nextElementSibling.textContent = t('hints.tagsLimit');
147
+ document.getElementById('publishLaunchTitle').textContent = t('labels.goPublic');
148
+ document.getElementById('publishLaunchBody').textContent = t('hints.goPublicBody');
149
+ document.getElementById('publishToggleLabel').textContent = t('labels.publicEnabled');
150
+ document.getElementById('publishLaunchHint').textContent = t('hints.publicEnabledHint');
151
+ document.getElementById('profileNextStepTitle').textContent = t('hints.nextStepTitle');
152
+ document.getElementById('profileNextStepBody').textContent = t('hints.nextStepBody');
153
+ document.getElementById('profileNextStepBtn').textContent = t('actions.goToOverview');
154
+ document.getElementById('profileNextStepDismissBtn').textContent = t('actions.dismiss');
155
+ setText('#view-profile .title-sm', t('labels.livePreview'), 1);
156
+ setText('#view-profile .profile-meta h4', t('labels.publicCard'), 0);
157
+ setText('#view-profile .profile-meta h4', t('labels.publishStatus'), 1);
158
+ setText('#view-profile .profile-meta h4', t('labels.publicProfilePreview'), 2);
159
+ setText('#view-profile .profile-meta .field-hint', t('hints.signedPublicProfileHint'));
160
+ setText('#view-network .section-header__eyebrow', t('labels.networkEyebrow'));
161
+ document.getElementById('networkBannerTitle').textContent = t('hints.networkBannerTitle');
162
+ document.getElementById('networkBannerBody').textContent = t('hints.networkBannerBody');
163
+ document.getElementById('networkBannerPurposeLabel').textContent = t('hints.networkBannerPurpose');
164
+ document.getElementById('networkBannerPurposeValue').textContent = t('hints.networkBannerPurposeValue');
165
+ document.getElementById('networkConnectionTitle').textContent = t('labels.connectionSummary');
166
+ document.getElementById('networkQuickActionsTitle').textContent = t('labels.quickActions');
167
+ setText('#view-network .network-actions-card .field-hint', t('hints.useTheseFirst'));
168
+ document.getElementById('networkBroadcastHint').textContent = t('hints.broadcastControlHint');
169
+ document.getElementById('networkAdvancedActionsSummary').textContent = t('labels.advancedActions');
170
+ document.getElementById('networkDiagnosticsSummary').textContent = t('labels.diagnostics');
171
+ document.getElementById('networkRuntimeComponentsTitle').textContent = t('labels.runtimeComponents');
172
+ document.getElementById('networkPeerInventoryTitle').textContent = t('labels.peerInventory');
173
+ document.getElementById('networkPeerDiscoveryStatsTitle').textContent = t('labels.peerDiscoveryStats');
174
+ document.getElementById('networkRecentDiscoveryEventsTitle').textContent = t('labels.recentDiscoveryEvents');
175
+ document.getElementById('networkDiscoverySnapshotTitle').textContent = t('labels.discoverySnapshot');
176
+ document.getElementById('networkLogsTitle').textContent = t('labels.logs');
177
+ setText('#view-network label[for="logLevelFilter"]', t('labels.category'));
178
+ document.querySelector('#logLevelFilter option[value="all"]').textContent = t('labels.all');
179
+ document.querySelector('#logLevelFilter option[value="info"]').textContent = t('labels.info');
180
+ document.querySelector('#logLevelFilter option[value="warn"]').textContent = t('labels.warn');
181
+ document.querySelector('#logLevelFilter option[value="error"]').textContent = t('labels.error');
182
+ document.getElementById('networkConfigSnapshotTitle').textContent = t('labels.configSnapshot');
183
+ document.getElementById('networkStatsSnapshotTitle').textContent = t('labels.statsSnapshot');
184
+ setText('#view-social .section-header__eyebrow', t('labels.socialEyebrow'));
185
+ document.getElementById('socialBannerTitle').textContent = t('hints.socialBannerTitle');
186
+ document.getElementById('socialBannerBody').textContent = t('hints.socialBannerBody');
187
+ document.getElementById('socialBannerOpenClawLabel').textContent = t('hints.socialBannerOpenClaw');
188
+ document.getElementById('socialBannerOpenClawValue').textContent = t('hints.socialBannerOpenClawValue');
189
+ document.getElementById('skillsBannerEyebrow').textContent = t('labels.skillsEyebrow');
190
+ document.getElementById('skillsBannerTitle').textContent = t('hints.skillsBannerTitle');
191
+ document.getElementById('skillsBannerBody').textContent = t('hints.skillsBannerBody');
192
+ document.getElementById('skillsBannerRuntimeLabel').textContent = t('hints.skillsBannerRuntime');
193
+ document.getElementById('skillsFeaturedTitle').textContent = t('labels.skillsFeatured');
194
+ document.getElementById('skillsFeaturedHint').textContent = t('hints.skillsFeaturedHint');
195
+ document.getElementById('skillsBundledTitle').textContent = t('labels.skillsBundled');
196
+ document.getElementById('skillsBundledHint').textContent = t('hints.skillsBundledHint');
197
+ document.getElementById('skillsInstalledTitle').textContent = t('labels.skillsInstalled');
198
+ document.getElementById('skillsInstalledHint').textContent = t('hints.skillsInstalledHint');
199
+ document.getElementById('skillsInstallBtn').textContent = t('actions.learnOpenClawSkill');
200
+ document.getElementById('socialIntegrationTitle').textContent = t('labels.integrationStatus');
201
+ document.querySelector('#socialStatusLine').textContent = t('hints.checkingIntegration');
202
+ document.getElementById('socialRuntimeSummaryTitle').textContent = t('labels.whatIsActive');
203
+ document.getElementById('socialBridgeTitle').textContent = t('labels.identityBinding');
204
+ document.getElementById('socialOwnerDeliveryTitle').textContent = t('labels.ownerDelivery');
205
+ document.getElementById('socialSkillLearningTitle').textContent = t('labels.openclawSkillLearning');
206
+ document.getElementById('socialGovernanceTitle').textContent = t('labels.messageGovernance');
207
+ document.getElementById('socialModerationTitle').textContent = t('labels.recentModeration');
208
+ document.getElementById('socialAdvancedSummary').textContent = t('labels.advancedNetworkDetails');
209
+ document.getElementById('socialSourceRuntimeSummary').textContent = t('labels.sourceRuntimeTemplate');
210
+ document.getElementById('socialSourceParsedTitle').textContent = t('labels.sourceParsedFrontmatter');
211
+ document.getElementById('socialRuntimeSummaryInnerTitle').textContent = t('labels.runtimeSummary');
212
+ document.getElementById('socialTemplatePreviewTitle').textContent = t('labels.exportTemplatePreview');
213
+ document.getElementById('socialActionsTitle').textContent = t('labels.actionsTitle');
214
+ setText('label[for="socialModeSelect"]', t('labels.networkModeRuntime'));
215
+ renderSocialModeHint('-', '-', false, false);
216
+ setSocialModePendingState(false);
217
+ document.getElementById('socialProfileVisibilityHint').textContent = t('hints.profileVisibilityManaged');
218
+ document.getElementById('socialGovernanceHint').textContent = t('hints.messageGovernanceHint');
219
+ document.getElementById('openclawSkillHint').textContent = t('hints.openclawSkillHint');
220
+ document.getElementById('openclawSkillInstallBtn').textContent = t('actions.learnOpenClawSkill');
221
+ setText('.hero-meta-item .label', t('labels.mode'), 0);
222
+ setText('.hero-meta-item .label', t('labels.adapter'), 1);
223
+ setText('.hero-meta-item .label', t('labels.relay'), 2);
224
+ setText('.hero-meta-item .label', t('labels.room'), 3);
225
+ document.getElementById('publicDiscoveryHint').innerHTML = t('hints.publicDiscoverySwitch');
226
+ document.getElementById('clearDiscoveryCacheBtn').textContent = t('actions.clearDiscoveryCache');
227
+ document.getElementById('socialMessageTitle').textContent = t('overview.messageTitle');
228
+ document.getElementById('socialMessageMeta').textContent = t('overview.messageMetaInitial');
229
+ document.getElementById('socialMessageHint').textContent = t('overview.messageHint');
230
+ document.getElementById('socialMessageInput').placeholder = t('actions.sendPublicMessage');
231
+ document.getElementById('socialMessageSendBtn').textContent = t('actions.sendPublicMessage');
232
+ document.getElementById('socialMessageRefreshBtn').textContent = t('actions.refreshInbox');
233
+ document.getElementById('saveGovernanceBtn').textContent = t('actions.saveGovernance');
234
+ document.getElementById('socialMessageTopicLabel').textContent = t('overview.messageTopicLabel');
235
+ document.getElementById('socialMessageFilterLabel').textContent = t('overview.messageFilterLabel');
236
+ document.querySelector('#socialMessageTopicSelect option[value="global"]').textContent = t('labels.globalTopic');
237
+ document.querySelector('#socialMessageFilterSelect option[value="all"]').textContent = t('overview.messageFilterAll');
238
+ document.querySelector('#socialMessageFilterSelect option[value="self"]').textContent = t('overview.messageFilterSelf');
239
+ document.querySelector('#socialMessageFilterSelect option[value="remote"]').textContent = t('overview.messageFilterRemote');
240
+ document.querySelector('label[for="governanceSendLimitInput"]').textContent = t('labels.sendLimit');
241
+ document.querySelector('label[for="governanceSendWindowInput"]').textContent = t('labels.sendWindowSeconds');
242
+ document.querySelector('label[for="governanceReceiveLimitInput"]').textContent = t('labels.receiveLimit');
243
+ document.querySelector('label[for="governanceReceiveWindowInput"]').textContent = t('labels.receiveWindowSeconds');
244
+ document.querySelector('label[for="governanceDuplicateWindowInput"]').textContent = t('labels.duplicateWindowSeconds');
245
+ document.querySelector('label[for="governanceBlockedAgentsInput"]').textContent = t('labels.blockedAgentIds');
246
+ document.querySelector('label[for="governanceBlockedTermsInput"]').textContent = t('labels.blockedTerms');
247
+ document.getElementById('startBroadcastBtn').textContent = t('actions.startBroadcast');
248
+ document.getElementById('stopBroadcastBtn').textContent = t('actions.stopBroadcast');
249
+ document.getElementById('quickGlobalPreviewBtn').textContent = t('actions.enablePreview');
250
+ document.getElementById('refreshLogsBtn').textContent = t('actions.refreshLogs');
251
+ document.getElementById('socialExportBtn').textContent = t('actions.exportTemplate');
252
+ document.getElementById('socialCopyBtn').textContent = t('actions.copyTemplate');
253
+ document.getElementById('socialDownloadBtn').textContent = t('actions.downloadTemplate');
254
+ document.getElementById('socialModeApplyBtn').textContent = t('actions.applyRuntimeMode');
255
+ document.querySelector('#socialModeSelect option[value="local"]').textContent = t('labels.modeLocalOption');
256
+ document.querySelector('#socialModeSelect option[value="lan"]').textContent = t('labels.modeLanOption');
257
+ document.querySelector('#socialModeSelect option[value="global-preview"]').textContent = t('labels.modeGlobalPreviewOption');
258
+ document.getElementById('copyPublicProfilePreviewBtn').textContent = t('actions.copyPublicProfilePreview');
259
+ document.getElementById('saveProfileBtn').textContent = t('actions.saveProfile');
260
+ document.getElementById('refreshProfileBtn').textContent = t('common.reload');
261
+ document.getElementById('profileFeedback').textContent = t('common.ready');
262
+ document.getElementById('networkFeedback').textContent = t('common.ready');
263
+ document.getElementById('socialFeedback').textContent = t('common.ready');
264
+ document.getElementById('socialGovernanceFeedback').textContent = t('common.ready');
265
+ document.getElementById('openclawSkillFeedback').textContent = t('common.ready');
266
+ document.getElementById('socialMessageFeedback').textContent = t('common.ready');
267
+ }
268
+ const shell = createShellController({ resolveThemeMode, t });
269
+ const {
270
+ applyTheme,
271
+ flashButton,
272
+ hydrateCachedShell,
273
+ peerStatusText,
274
+ pulseOverviewBroadcastStep,
275
+ renderSocialModeHint,
276
+ setFeedback,
277
+ setProfileNextStepVisible,
278
+ setSocialModePendingState,
279
+ toast,
280
+ writeUiCache,
281
+ } = shell;
282
+ setLocale(currentLocale);
283
+ applyStaticTranslations();
284
+
285
+ let activeTab = 'overview';
286
+ let logsCache = [];
287
+ let socialMessagesCache = [];
288
+ let logLevelFilter = 'all';
289
+ let socialTemplate = '';
290
+ let socialModeDirty = false;
291
+ let socialModePending = '';
292
+ let visibleRemotePublicCount = 0;
293
+ let socialMessageFilter = 'all';
294
+ let socialMessageGovernance = null;
295
+ let overviewMode = 'lan';
296
+ let onlyShowOnline = false;
297
+ let agentsPage = 1;
298
+ const AGENTS_PAGE_SIZE = 10;
299
+ const pageMeta = TRANSLATIONS[currentLocale].pageMeta || TRANSLATIONS[DEFAULT_LOCALE].pageMeta;
300
+
301
+ async function api(path, options = {}) {
302
+ const res = await fetch(path, { headers: { 'Content-Type': 'application/json' }, ...options });
303
+ const json = await res.json().catch(() => null);
304
+ if (!res.ok || !json || !json.ok) {
305
+ throw new Error(json?.error?.message || t('common.requestFailed', { status: String(res.status) }));
306
+ }
307
+ return json;
308
+ }
309
+
310
+ const profileController = createProfileController({
311
+ api,
312
+ field,
313
+ normalizeTagsInput,
314
+ parseTags,
315
+ setFeedback,
316
+ setProfileNextStepVisible,
317
+ t,
318
+ toast,
319
+ toPrettyJson,
320
+ });
321
+ const refreshProfile = profileController.refreshProfile;
322
+ const refreshPublicProfilePreview = profileController.refreshPublicProfilePreview;
323
+ const overviewController = createOverviewController({
324
+ ago,
325
+ api,
326
+ describeCurrentMode,
327
+ escapeHtml,
328
+ shortId,
329
+ t,
330
+ writeUiCache,
331
+ });
332
+ const networkController = createNetworkController({
333
+ ago,
334
+ api,
335
+ describeCurrentMode,
336
+ peerStatusText,
337
+ shortId,
338
+ t,
339
+ toPrettyJson,
340
+ writeUiCache,
341
+ });
342
+ const socialController = createSocialController({
343
+ api,
344
+ escapeHtml,
345
+ formatMessageBody,
346
+ getActiveTab: () => activeTab,
347
+ getLogLevelFilter: () => logLevelFilter,
348
+ getLogsCache: () => logsCache,
349
+ getSocialMessageFilter: () => socialMessageFilter,
350
+ getSocialMessageGovernance: () => socialMessageGovernance,
351
+ getSocialMessagesCache: () => socialMessagesCache,
352
+ getSocialModeDirty: () => socialModeDirty,
353
+ getSocialModePending: () => socialModePending,
354
+ getSocialTemplate: () => socialTemplate,
355
+ getVisibleRemotePublicCount: () => visibleRemotePublicCount,
356
+ renderSocialModeHint,
357
+ setLogLevelFilter: (value) => { logLevelFilter = value; },
358
+ setLogsCache: (value) => { logsCache = value; },
359
+ setSocialMessageGovernance: (value) => { socialMessageGovernance = value; },
360
+ setSocialMessagesCache: (value) => { socialMessagesCache = value; },
361
+ setSocialModePendingState,
362
+ setSocialTemplate: (value) => { socialTemplate = value; },
363
+ shortId,
364
+ t,
365
+ toPrettyJson,
366
+ writeUiCache,
367
+ });
368
+
369
+ function switchTab(tab) {
370
+ if (activeTab === 'profile' && tab !== 'profile' && profileController.isDirty() && !profileController.isSaving()) {
371
+ const ok = window.confirm(t('validation.leaveConfirm'));
372
+ if (!ok) {
373
+ return;
374
+ }
375
+ }
376
+ activeTab = tab;
377
+ document.querySelectorAll('.tab').forEach((b) => b.classList.toggle('active', b.dataset.tab === tab));
378
+ ['overview', 'agent', 'chat', 'skills', 'profile', 'network', 'social'].forEach((k) => {
379
+ document.getElementById(`view-${k}`).classList.toggle('active', k === tab);
380
+ });
381
+ const meta = pageMeta[tab] || pageMeta.overview;
382
+ document.getElementById('pageBreadcrumb').textContent = meta.title;
383
+ document.getElementById('pageHeroTitle').textContent = meta.title;
384
+ document.getElementById('pageHeroBody').textContent = meta.body;
385
+ document.getElementById('integrationStatusBar')?.classList.toggle('hidden', tab !== 'overview');
386
+ document.querySelector('.page-hero')?.classList.toggle('hidden', tab !== 'overview');
387
+ document.getElementById('publicDiscoveryHint')?.classList.toggle('hidden', tab !== 'overview');
388
+ if (tab === 'profile' && !profileController.isDirty() && !profileController.isSaving()) {
389
+ refreshProfile().catch(() => {});
390
+ }
391
+ }
392
+
393
+ async function refreshOverview() {
394
+ await overviewController.refreshOverview({
395
+ getAgentsPage: () => agentsPage,
396
+ getOnlyShowOnline: () => onlyShowOnline,
397
+ onPageChange: (page) => { agentsPage = page; },
398
+ setOverviewMode: (mode) => { overviewMode = mode; },
399
+ setVisibleRemotePublicCount: (count) => { visibleRemotePublicCount = count; },
400
+ });
401
+ }
402
+
403
+ const renderSocialMessages = socialController.renderSocialMessages;
404
+ const refreshMessages = socialController.refreshMessages;
405
+
406
+ const refreshNetwork = networkController.refreshNetwork;
407
+ const refreshPeers = networkController.refreshPeers;
408
+ const refreshDiscovery = networkController.refreshDiscovery;
409
+
410
+ const refreshSocial = socialController.refreshSocial;
411
+ const exportSocialTemplate = socialController.exportSocialTemplate;
412
+ const renderLogs = socialController.renderLogs;
413
+ const refreshLogs = socialController.refreshLogs;
414
+ const refreshSkills = socialController.refreshSkills;
415
+
416
+ async function refreshAll() {
417
+ const tasks = [refreshOverview(), refreshNetwork(), refreshSocial(), refreshSkills(), refreshPublicProfilePreview(), refreshMessages()];
418
+ if (activeTab === 'network') {
419
+ tasks.push(refreshPeers(), refreshDiscovery(), refreshLogs());
420
+ }
421
+ const shouldRefreshProfile = !(activeTab === 'profile' && profileController.isDirty());
422
+ if (shouldRefreshProfile) {
423
+ tasks.push(refreshProfile());
424
+ }
425
+ const results = await Promise.allSettled(tasks);
426
+ const firstError = results.find((result) => result.status === 'rejected');
427
+ if (firstError && firstError.status === 'rejected') {
428
+ setFeedback('networkFeedback', firstError.reason instanceof Error ? firstError.reason.message : t('common.unknownError'), 'error');
429
+ }
430
+ }
431
+
432
+ bindAppEvents({
433
+ api,
434
+ applyTheme,
435
+ exportSocialTemplate,
436
+ flashButton,
437
+ messageSendReasonText,
438
+ parseCsv,
439
+ profileController,
440
+ pulseOverviewBroadcastStep,
441
+ refreshAll,
442
+ refreshLogs,
443
+ refreshMessages,
444
+ refreshNetwork,
445
+ refreshOverview,
446
+ refreshSkills,
447
+ refreshSocial,
448
+ renderLogs,
449
+ renderSocialMessages,
450
+ renderSocialModeHint,
451
+ setFeedback,
452
+ setOnlyShowOnline: (value) => { onlyShowOnline = value; },
453
+ setProfileNextStepVisible,
454
+ setSocialMessageFilter: (value) => { socialMessageFilter = value; },
455
+ setSocialModeDirty: (value) => { socialModeDirty = value; },
456
+ setSocialModePending: (value) => { socialModePending = value; },
457
+ setSocialModePendingState,
458
+ shouldWarnBeforeUnload: () => (profileController.isDirty() && !profileController.isSaving()) || socialModeDirty,
459
+ socialController,
460
+ switchTab,
461
+ t,
462
+ toast,
463
+ getSocialTemplate: () => socialTemplate,
464
+ setAgentsPage: (value) => { agentsPage = value; },
465
+ getSocialMessagesCache: () => socialMessagesCache,
466
+ toPrettyJson,
467
+ });
468
+
469
+ applyTheme(localStorage.getItem('silicaclaw_theme_mode') || 'dark');
470
+ hydrateCachedShell();
471
+ refreshAll();
472
+ exportSocialTemplate().catch(() => {});
473
+ setInterval(refreshAll, 4000);