ec-web 0.0.27 → 0.0.29-test.0

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.
@@ -62,6 +62,8 @@
62
62
  'basicSettings.closeConfirm': '存在未保存的修改,仍要关闭吗?',
63
63
  'basicSettings.configSnapshots': '配置快照',
64
64
  'basicSettings.configSnapshotsHelp': '保存运行时配置快照,便于排查问题;快照可能包含敏感上下文。',
65
+ 'basicSettings.restartRecovery': '启动失败后自动修复',
66
+ 'basicSettings.restartRecoveryHelp': '仅控制 restart-monitor 在启动失败且旧版本回滚无效后的 Claude 自动修复;不负责 daemon 崩溃后的常驻拉起,也不影响 EC Web 健康监控。',
65
67
  'basicSettings.connection': '连接与凭证',
66
68
  'basicSettings.controlIdentity': '控制身份',
67
69
  'basicSettings.daemonAid': 'Daemon AID',
@@ -90,8 +92,6 @@
90
92
  'basicSettings.fallbackHelp': '按顺序尝试,最多三个;每个备选模型可单独设置推理强度。',
91
93
  'basicSettings.fallbackLimit': '最多只能配置三个备选模型。',
92
94
  'basicSettings.fallbackModels': '备选模型',
93
- 'basicSettings.fullaccessEnabled': '允许 Fullaccess',
94
- 'basicSettings.fullaccessHelp': '允许可信 Daemon Owner 使用 /fa 或 /fullaccess,并启用 fullaccess Trigger。此权限可直接访问宿主环境。',
95
95
  'basicSettings.geminiLocation': 'Vertex 区域',
96
96
  'basicSettings.geminiLocationHelp': '使用 Vertex AI 时的 Google Cloud 区域,例如 us-central1。',
97
97
  'basicSettings.geminiMode': '运行模式',
@@ -121,7 +121,7 @@
121
121
  'basicSettings.maxRetryDelayMs': '重试最大延迟(毫秒)',
122
122
  'basicSettings.maxRetryDelayMsHelp': '自动重试之间允许等待的最大延迟。',
123
123
  'basicSettings.mentionMode': '@ 处理模式',
124
- 'basicSettings.mentionModeHelp': '控制群聊中是否必须通过 @ 提及当前 Agent 才处理消息。',
124
+ 'basicSettings.mentionModeHelp': '控制群聊消息响应:全部、仅被 @,或按上下文自动判断。',
125
125
  'basicSettings.menuTokenRequired': '要求 Menu Token',
126
126
  'basicSettings.menuTokenRequiredHelp': '要求远程菜单请求携带有效 Menu Token,避免未授权调用。',
127
127
  'basicSettings.minEvolVersion': '最低客户端版本',
@@ -264,6 +264,8 @@
264
264
  'basicSettings.closeConfirm': 'There are unsaved changes. Close anyway?',
265
265
  'basicSettings.configSnapshots': 'Configuration snapshots',
266
266
  'basicSettings.configSnapshotsHelp': 'Save runtime configuration snapshots for troubleshooting; snapshots may contain sensitive context.',
267
+ 'basicSettings.restartRecovery': 'Auto-repair after startup failure',
268
+ 'basicSettings.restartRecoveryHelp': 'Controls Claude self-heal only after restart-monitor cannot start the daemon and rollback has failed; it does not add a daemon crash watchdog or affect EC Web health monitoring.',
267
269
  'basicSettings.connection': 'Connection & credentials',
268
270
  'basicSettings.controlIdentity': 'Control identity',
269
271
  'basicSettings.daemonAid': 'Daemon AID',
@@ -292,8 +294,6 @@
292
294
  'basicSettings.fallbackHelp': 'Tried in order, up to three; each may use a separate effort.',
293
295
  'basicSettings.fallbackLimit': 'At most three fallback models can be configured.',
294
296
  'basicSettings.fallbackModels': 'Fallback models',
295
- 'basicSettings.fullaccessEnabled': 'Allow Fullaccess',
296
- 'basicSettings.fullaccessHelp': 'Allows trusted Daemon Owners to use /fa or /fullaccess and enables fullaccess Triggers. This grants host-level access.',
297
297
  'basicSettings.geminiLocation': 'Vertex location',
298
298
  'basicSettings.geminiLocationHelp': 'Google Cloud region used with Vertex AI, for example us-central1.',
299
299
  'basicSettings.geminiMode': 'Run mode',
@@ -323,7 +323,7 @@
323
323
  'basicSettings.maxRetryDelayMs': 'Maximum retry delay (ms)',
324
324
  'basicSettings.maxRetryDelayMsHelp': 'Maximum delay allowed between automatic retries.',
325
325
  'basicSettings.mentionMode': '@ mention mode',
326
- 'basicSettings.mentionModeHelp': 'Controls whether group messages must mention this Agent with @ before processing.',
326
+ 'basicSettings.mentionModeHelp': 'Choose all group messages, mentions only, or automatic context-based attention.',
327
327
  'basicSettings.menuTokenRequired': 'Require Menu Token',
328
328
  'basicSettings.menuTokenRequiredHelp': 'Require a valid Menu Token on remote menu requests to prevent unauthorized calls.',
329
329
  'basicSettings.minEvolVersion': 'Minimum client version',
@@ -756,7 +756,7 @@
756
756
  const chatMode = getFileValue('defaults', 'config.chatMode') || 'interactive';
757
757
  const body = scalarField({ file: 'defaults', path: 'responseMode', label: t('basicSettings.responseMode'), type: 'select', options: ['single-session'], value: getFileValue('defaults', 'responseMode'), help: t('basicSettings.responseModeHelp') }) +
758
758
  scalarField({ file: 'defaults', path: 'config.chatMode', label: t('basicSettings.chatMode'), type: 'select', options: ['interactive', 'proactive'], value: chatMode, help: t('basicSettings.chatModeHelp') }) +
759
- scalarField({ file: 'defaults', path: 'config.mentionMode', label: t('basicSettings.mentionMode'), type: 'select', options: ['disabled', 'mention-only'], value: getFileValue('defaults', 'config.mentionMode'), help: t('basicSettings.mentionModeHelp') }) +
759
+ scalarField({ file: 'defaults', path: 'config.mentionMode', label: t('basicSettings.mentionMode'), type: 'select', options: ['disabled', 'mention-only', 'auto'], value: getFileValue('defaults', 'config.mentionMode'), help: t('basicSettings.mentionModeHelp') }) +
760
760
  scalarField({ file: 'defaults', path: 'config.show_activities', label: t('basicSettings.showActivities'), type: 'select', options: ['all', 'text', 'none'], value: getFileValue('defaults', 'config.show_activities'), help: t('basicSettings.showActivitiesHelp') });
761
761
  const proactive = chatMode === 'proactive'
762
762
  ? section(t('basicSettings.proactiveDetails'), t('basicSettings.proactiveOnly'), formGrid(
@@ -827,7 +827,7 @@
827
827
  function renderIdentity() {
828
828
  const daemon = buildFilePreview('daemon');
829
829
  const aid = daemon.aid || t('basicSettings.notSet');
830
- return panelIntro(t('basicSettings.tabs.identity'), t('basicSettings.identityIntro')) + section(t('basicSettings.controlIdentity'), t('basicSettings.readonly'), `<div class="basic-settings-form-grid"><div class="basic-settings-field" data-bs-field data-file="daemon" data-path="aid"><div class="basic-settings-field-label"><span>${htmlEscape(t('basicSettings.daemonAid'))}<span class="basic-settings-path">aid</span></span></div><div class="basic-settings-readonly"><code>${htmlEscape(aid)}</code></div></div>${scalarField({ file: 'daemon', path: 'aun.defaultAidDomain', label: t('basicSettings.defaultAidDomain'), value: getFileValue('daemon', 'aun.defaultAidDomain'), placeholder: 'agentid.cn', help: t('basicSettings.defaultAidDomainHelp') })}</div>`) + section(t('basicSettings.accessControl'), t('basicSettings.daemonScope'), `<div class="basic-settings-form-grid"><div class="basic-settings-field full" data-bs-field data-file="daemon" data-path="owners">${fieldLabel(t('basicSettings.daemonOwners'), 'owners[]', t('basicSettings.ownerHelp'), null)}${ownersMarkup(daemon)}</div>${scalarField({ file: 'daemon', path: 'aun.minEvolVersion', label: t('basicSettings.minEvolVersion'), value: getFileValue('daemon', 'aun.minEvolVersion'), placeholder: '1.6.0', help: t('basicSettings.minEvolVersionHelp') })}${scalarField({ file: 'daemon', path: 'aun.menuTokenRequired', label: t('basicSettings.menuTokenRequired'), type: 'boolean', value: getFileValue('daemon', 'aun.menuTokenRequired'), help: t('basicSettings.menuTokenRequiredHelp') })}${scalarField({ file: 'daemon', path: 'aun.defaultEncrypt', label: t('basicSettings.defaultEncrypt'), type: 'boolean', value: getFileValue('daemon', 'aun.defaultEncrypt') })}${scalarField({ file: 'daemon', path: 'fullaccess.enabled', label: t('basicSettings.fullaccessEnabled'), type: 'boolean', value: daemon.fullaccess?.enabled ?? true, help: t('basicSettings.fullaccessHelp') })}</div>`);
830
+ return panelIntro(t('basicSettings.tabs.identity'), t('basicSettings.identityIntro')) + section(t('basicSettings.controlIdentity'), t('basicSettings.readonly'), `<div class="basic-settings-form-grid"><div class="basic-settings-field" data-bs-field data-file="daemon" data-path="aid"><div class="basic-settings-field-label"><span>${htmlEscape(t('basicSettings.daemonAid'))}<span class="basic-settings-path">aid</span></span></div><div class="basic-settings-readonly"><code>${htmlEscape(aid)}</code></div></div>${scalarField({ file: 'daemon', path: 'aun.defaultAidDomain', label: t('basicSettings.defaultAidDomain'), value: getFileValue('daemon', 'aun.defaultAidDomain'), placeholder: 'agentid.cn', help: t('basicSettings.defaultAidDomainHelp') })}</div>`) + section(t('basicSettings.accessControl'), t('basicSettings.daemonScope'), `<div class="basic-settings-form-grid"><div class="basic-settings-field full" data-bs-field data-file="daemon" data-path="owners">${fieldLabel(t('basicSettings.daemonOwners'), 'owners[]', t('basicSettings.ownerHelp'), null)}${ownersMarkup(daemon)}</div>${scalarField({ file: 'daemon', path: 'aun.minEvolVersion', label: t('basicSettings.minEvolVersion'), value: getFileValue('daemon', 'aun.minEvolVersion'), placeholder: '1.6.0', help: t('basicSettings.minEvolVersionHelp') })}${scalarField({ file: 'daemon', path: 'aun.menuTokenRequired', label: t('basicSettings.menuTokenRequired'), type: 'boolean', value: getFileValue('daemon', 'aun.menuTokenRequired'), help: t('basicSettings.menuTokenRequiredHelp') })}${scalarField({ file: 'daemon', path: 'aun.defaultEncrypt', label: t('basicSettings.defaultEncrypt'), type: 'boolean', value: getFileValue('daemon', 'aun.defaultEncrypt') })}</div>`);
831
831
  }
832
832
 
833
833
  function renderRuntime() {
@@ -846,7 +846,8 @@
846
846
  scalarField({ file: 'daemon', path: 'idleMonitor.enabled', label: t('basicSettings.idleEnabled'), type: 'boolean', value: getFileValue('daemon', 'idleMonitor.enabled'), help: t('basicSettings.idleEnabledHelp') }) +
847
847
  scalarField({ file: 'daemon', path: 'idleMonitor.timeout', label: t('basicSettings.idleTimeout'), type: 'number', value: getFileValue('daemon', 'idleMonitor.timeout'), placeholder: '120' }) +
848
848
  scalarField({ file: 'daemon', path: 'idleMonitor.apiRetryTimeout', label: t('basicSettings.apiRetryTimeout'), type: 'number', value: getFileValue('daemon', 'idleMonitor.apiRetryTimeout'), placeholder: t('basicSettings.inheritTimeout') }) +
849
- scalarField({ file: 'daemon', path: 'idleMonitor.maxExecutionTime', label: t('basicSettings.maxExecutionTime'), type: 'number', value: getFileValue('daemon', 'idleMonitor.maxExecutionTime'), placeholder: '0' }),
849
+ scalarField({ file: 'daemon', path: 'idleMonitor.maxExecutionTime', label: t('basicSettings.maxExecutionTime'), type: 'number', value: getFileValue('daemon', 'idleMonitor.maxExecutionTime'), placeholder: '0' }) +
850
+ scalarField({ file: 'daemon', path: 'restartRecovery.enabled', label: t('basicSettings.restartRecovery'), type: 'boolean', value: getFileValue('daemon', 'restartRecovery.enabled') ?? false, help: t('basicSettings.restartRecoveryHelp') }),
850
851
  )) + section(t('basicSettings.logsDiagnostics'), t('basicSettings.daemonScope'), formGrid(
851
852
  scalarField({ file: 'daemon', path: 'debug.logLevel', label: t('basicSettings.logLevel'), type: 'select', options: ['DEBUG', 'INFO', 'WARN', 'ERROR'], value: debug.logLevel }) +
852
853
  scalarField({ file: 'daemon', path: 'configSnapshots', label: t('basicSettings.configSnapshots'), type: 'boolean', value: getFileValue('daemon', 'configSnapshots'), help: t('basicSettings.configSnapshotsHelp') }) +
@@ -22,7 +22,7 @@
22
22
  </head>
23
23
  <body>
24
24
  <!-- 配对页 -->
25
- <div id="pair-page" class="pair-page">
25
+ <div id="pair-page" class="pair-page" style="display:none">
26
26
  <div class="pair-box">
27
27
  <h1 data-i18n="pair.title">EC Web</h1>
28
28
  <p class="pair-hint" data-i18n="pair.hint">输入终端显示的 6 位配对码</p>
@@ -35,7 +35,9 @@
35
35
  <!-- 主面板 -->
36
36
  <div id="app" class="app" style="display:none">
37
37
  <header class="topbar">
38
+ <button id="mobile-menu-btn" class="mobile-menu-btn" type="button" data-i18n-aria-label="navigation.open" aria-controls="mobile-nav-drawer" aria-expanded="false">☰</button>
38
39
  <span class="brand">EC Web</span>
40
+ <span id="mobile-page-title" class="mobile-page-title" aria-live="polite"></span>
39
41
  <nav class="tabs">
40
42
  <button class="tab active" data-view="agents" data-i18n="tab.agents">Agents</button>
41
43
  <button class="tab" data-view="msg" data-i18n="tab.messages">Messages</button>
@@ -48,8 +50,8 @@
48
50
  <button class="tab" data-view="roleManagement" data-i18n="tab.roleManagement">Roles</button>
49
51
 
50
52
  </nav>
51
- <span style="flex:1"></span>
52
- <span class="build-ts" style="font-size:10px;color:var(--dim)" data-i18n-title="common.buildTime" title="构建时间">2026-09-24 11:34</span>
53
+ <span class="topbar-spacer" aria-hidden="true"></span>
54
+ <span class="build-ts" style="font-size:10px;color:var(--dim)" data-i18n-title="common.buildTime" title="构建时间">2026-10-08 07:48</span>
53
55
  <span id="conn-status" class="conn-status" data-i18n="status.connecting">连接中…</span>
54
56
  <button id="lang-btn" class="theme-btn" data-i18n-title="language.buttonTitle" title="切换语言">🌐</button>
55
57
  <button id="theme-btn" class="theme-btn" data-i18n-title="theme.buttonTitle" title="主题">🌗</button>
@@ -57,13 +59,31 @@
57
59
  <button id="logout-btn" class="logout-btn" data-i18n="action.logout" data-i18n-title="pair.logoutTitle" title="退出配对">退出</button>
58
60
  </header>
59
61
 
62
+ <div id="mobile-nav-backdrop" class="mobile-nav-backdrop" hidden></div>
63
+ <aside id="mobile-nav-drawer" class="mobile-nav-drawer" aria-hidden="true" data-i18n-aria-label="navigation.pages" aria-label="页面导航">
64
+ <div class="mobile-nav-head">
65
+ <strong>EC Web</strong>
66
+ <button id="mobile-nav-close" class="icon-btn" type="button" data-i18n-aria-label="navigation.close" aria-label="关闭导航">×</button>
67
+ </div>
68
+ <nav class="mobile-nav-list" data-i18n-aria-label="navigation.pages" aria-label="页面导航"></nav>
69
+ <div class="mobile-nav-tools">
70
+ <button type="button" data-mobile-tool="lang" class="mobile-nav-tool"><span aria-hidden="true">🌐</span><span data-i18n="language.buttonTitle">切换语言</span></button>
71
+ <button type="button" data-mobile-tool="theme" class="mobile-nav-tool"><span aria-hidden="true">🌗</span><span data-mobile-theme-label>主题:浅色模式</span></button>
72
+ <button type="button" data-mobile-tool="settings" class="mobile-nav-tool"><span aria-hidden="true">⚙️</span><span data-i18n="basicSettings.open">基础设置</span></button>
73
+ <button type="button" data-mobile-tool="logout" class="mobile-nav-tool"><span aria-hidden="true">↪</span><span data-i18n="action.logout">退出</span></button>
74
+ </div>
75
+ </aside>
76
+
60
77
  <main class="content">
61
78
  <section id="view-agents" class="view active"></section>
62
79
  <section id="view-msg" class="view">
63
80
  <div class="msg-layout">
64
- <div id="msg-aids" class="msg-col msg-aids"></div>
65
- <div id="msg-peers" class="msg-col msg-peers"></div>
66
- <div id="msg-stream" class="msg-col msg-stream"></div>
81
+ <div id="msg-mobile-controls" class="msg-mobile-controls" data-i18n-aria-label="messages.mobile.selection" aria-label="消息选择"></div>
82
+ <div class="msg-columns">
83
+ <div id="msg-aids" class="msg-col msg-aids"></div>
84
+ <div id="msg-peers" class="msg-col msg-peers"></div>
85
+ <div id="msg-stream" class="msg-col msg-stream"></div>
86
+ </div>
67
87
  </div>
68
88
  </section>
69
89
  <section id="view-session" class="view">
@@ -83,11 +103,11 @@
83
103
  <section id="view-logs" class="view">
84
104
  <div class="log-layout">
85
105
  <div class="log-toolbar">
86
- <label class="log-control">
106
+ <label class="log-control log-primary-control">
87
107
  <span class="visually-hidden" data-i18n="logs.source">日志源</span>
88
108
  <select id="log-source"></select>
89
109
  </label>
90
- <label class="log-control">
110
+ <label class="log-control log-primary-control">
91
111
  <span class="visually-hidden" data-i18n="logs.level">级别</span>
92
112
  <select id="log-level">
93
113
  <option value="all" data-i18n="logs.level.all">全部级别</option>
@@ -98,17 +118,17 @@
98
118
  <option value="other" data-i18n="logs.level.other">其他</option>
99
119
  </select>
100
120
  </label>
101
- <label class="log-control">
121
+ <label class="log-control log-secondary-control">
102
122
  <span class="visually-hidden" data-i18n="logs.module">模块</span>
103
123
  <select id="log-module">
104
124
  <option value="all" data-i18n="logs.module.all">全部模块</option>
105
125
  </select>
106
126
  </label>
107
- <label class="log-search">
127
+ <label class="log-search log-primary-control">
108
128
  <span class="visually-hidden" data-i18n="logs.search">搜索</span>
109
129
  <input id="log-search" type="search" data-i18n="logs.searchPlaceholder" placeholder="筛选当前日志">
110
130
  </label>
111
- <label class="log-control log-limit-control">
131
+ <label class="log-control log-secondary-control log-limit-control">
112
132
  <span class="visually-hidden" data-i18n="logs.lines">行数</span>
113
133
  <select id="log-limit">
114
134
  <option value="500" data-i18n="logs.lines.500" selected>500 行</option>
@@ -116,10 +136,11 @@
116
136
  <option value="2000" data-i18n="logs.lines.2000">2000 行</option>
117
137
  </select>
118
138
  </label>
119
- <label class="log-follow">
139
+ <label class="log-follow log-primary-control">
120
140
  <input id="log-follow" type="checkbox" checked>
121
141
  <span data-i18n="logs.follow">跟随尾部</span>
122
142
  </label>
143
+ <button id="log-more-filters" class="log-more-filters" type="button" aria-expanded="false">更多筛选</button>
123
144
  </div>
124
145
  <div class="log-stream" id="log-stream"><div class="empty" data-i18n="common.loading">加载中…</div></div>
125
146
  <div class="log-meta">