tagword-codeagent 1.1.6__py3-none-any.whl

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.
Files changed (173) hide show
  1. codeagent/__init__.py +10 -0
  2. codeagent/__main__.py +13 -0
  3. codeagent/cli/__init__.py +13 -0
  4. codeagent/cli/entrypoint.py +161 -0
  5. codeagent/cli/main.py +979 -0
  6. codeagent/core/__init__.py +2 -0
  7. codeagent/core/attachments.py +342 -0
  8. codeagent/core/audio_models.py +50 -0
  9. codeagent/core/bootstrap.py +178 -0
  10. codeagent/core/default_presets.py +159 -0
  11. codeagent/core/env.py +106 -0
  12. codeagent/core/folder_picker.py +151 -0
  13. codeagent/core/image_understanding.py +90 -0
  14. codeagent/core/models.py +6 -0
  15. codeagent/core/paths.py +238 -0
  16. codeagent/core/pricing.py +107 -0
  17. codeagent/core/process_ports.py +258 -0
  18. codeagent/core/seed_bridge.py +21 -0
  19. codeagent/core/settings.py +98 -0
  20. codeagent/core/speech_synth.py +330 -0
  21. codeagent/core/team_config.py +247 -0
  22. codeagent/core/team_manager.py +245 -0
  23. codeagent/core/token_counter.py +41 -0
  24. codeagent/core/tts_voices.py +103 -0
  25. codeagent/core/usage_billing.py +72 -0
  26. codeagent/core/vision_models.py +93 -0
  27. codeagent/memory/diary.py +144 -0
  28. codeagent/persona_defaults/README.md +12 -0
  29. codeagent/persona_defaults/agent.md +352 -0
  30. codeagent/persona_defaults/identity.md +29 -0
  31. codeagent/persona_defaults/memory.md +4 -0
  32. codeagent/persona_defaults/skills.md +325 -0
  33. codeagent/persona_defaults/soul.md +38 -0
  34. codeagent/persona_defaults/tools.md +41 -0
  35. codeagent/persona_defaults/user.md +18 -0
  36. codeagent/runtime/__init__.py +11 -0
  37. codeagent/runtime/agent_context.py +6 -0
  38. codeagent/runtime/agent_runtime.py +21 -0
  39. codeagent/runtime/compact_prompt.py +9 -0
  40. codeagent/runtime/compact_state.py +40 -0
  41. codeagent/runtime/llm_worker.py +132 -0
  42. codeagent/runtime/orchestrator.py +161 -0
  43. codeagent/runtime/prompt_enrichment.py +324 -0
  44. codeagent/runtime/session_manager.py +30 -0
  45. codeagent/runtime/task_split.py +38 -0
  46. codeagent/runtime/turn_loop.py +13 -0
  47. codeagent/runtime/worker.py +48 -0
  48. codeagent/server/__init__.py +505 -0
  49. codeagent/server/app_factory.py +1292 -0
  50. codeagent/server/attachment_api.py +261 -0
  51. codeagent/server/hub.py +175 -0
  52. codeagent/server/icon.png +0 -0
  53. codeagent/server/self_healing.py +143 -0
  54. codeagent/server/team_engine.py +243 -0
  55. codeagent/server/tts_api.py +51 -0
  56. codeagent/server/webui_api_app.py +3180 -0
  57. codeagent/skills/__init__.py +2 -0
  58. codeagent/skills/select.py +144 -0
  59. codeagent/tools/__init__.py +6 -0
  60. codeagent/tools/agent_tools.py +10 -0
  61. codeagent/web/__init__.py +1 -0
  62. codeagent/web/__pycache__/__init__.cpython-313.pyc +0 -0
  63. codeagent/web/__pycache__/app.cpython-313.pyc +0 -0
  64. codeagent/web/__pycache__/auth_impl.cpython-313.pyc +0 -0
  65. codeagent/web/auth_impl.py +326 -0
  66. codeagent/web/static/00-marked.min.js +6 -0
  67. codeagent/web/static/00-mermaid.min.js +2314 -0
  68. codeagent/web/static/00-purify.min.js +3 -0
  69. codeagent/web/static/00-storage.js +83 -0
  70. codeagent/web/static/00-utils.js +51 -0
  71. codeagent/web/static/01-theme.css +96 -0
  72. codeagent/web/static/01a-scroll.js +86 -0
  73. codeagent/web/static/01b-think.js +62 -0
  74. codeagent/web/static/01c-session-identity.js +81 -0
  75. codeagent/web/static/01c-session-thinking.js +61 -0
  76. codeagent/web/static/01c-session-tree-menus.js +349 -0
  77. codeagent/web/static/01c-session-tree.js +531 -0
  78. codeagent/web/static/01c-session-utilities.js +83 -0
  79. codeagent/web/static/01c-vision-model.js +132 -0
  80. codeagent/web/static/01d-image-gen-model.js +84 -0
  81. codeagent/web/static/01e-audio-model.js +97 -0
  82. codeagent/web/static/01f-compose-ui.js +88 -0
  83. codeagent/web/static/01g-tts-settings.js +128 -0
  84. codeagent/web/static/01h-music-model.js +85 -0
  85. codeagent/web/static/01i-model-stack.js +291 -0
  86. codeagent/web/static/01j-video-gen-model.js +85 -0
  87. codeagent/web/static/01k-model-stack-bootstrap.js +66 -0
  88. codeagent/web/static/01k-model-stack-state.js +209 -0
  89. codeagent/web/static/01q-inflight.js +195 -0
  90. codeagent/web/static/02-reset.css +22 -0
  91. codeagent/web/static/02-session-ui.js +201 -0
  92. codeagent/web/static/03-layout-p1.css +2 -0
  93. codeagent/web/static/03-layout-p2.css +2 -0
  94. codeagent/web/static/03a-links-stream.js +88 -0
  95. codeagent/web/static/03b-stream-text.js +119 -0
  96. codeagent/web/static/03c-render-bubble.js +520 -0
  97. codeagent/web/static/03d-agent-bubble.js +126 -0
  98. codeagent/web/static/03e-tool-trace.js +182 -0
  99. codeagent/web/static/03f-timeline.js +54 -0
  100. codeagent/web/static/03g-bubble-tts.js +292 -0
  101. codeagent/web/static/04-components-p1.css +1 -0
  102. codeagent/web/static/04-components-p2b.css +1 -0
  103. codeagent/web/static/04-components-p3.css +2 -0
  104. codeagent/web/static/04-components-p4.css +1 -0
  105. codeagent/web/static/04-components-p5.css +1 -0
  106. codeagent/web/static/04-components-p6.css +58 -0
  107. codeagent/web/static/04-components-p7.css +4 -0
  108. codeagent/web/static/04-components-p8.css +1 -0
  109. codeagent/web/static/04-components-p9.css +1 -0
  110. codeagent/web/static/04-ws-connect.js +351 -0
  111. codeagent/web/static/04-ws-helpers.js +116 -0
  112. codeagent/web/static/05-chat-p1.css +1058 -0
  113. codeagent/web/static/05-chat-p2.css +1 -0
  114. codeagent/web/static/05-chat-p3.css +295 -0
  115. codeagent/web/static/05a-session-history.js +176 -0
  116. codeagent/web/static/05b-session-list.js +114 -0
  117. codeagent/web/static/05c-dialog.js +123 -0
  118. codeagent/web/static/05d-project-create.js +172 -0
  119. codeagent/web/static/05e-project-remote.js +143 -0
  120. codeagent/web/static/06-chat.js +552 -0
  121. codeagent/web/static/06-utilities.css +181 -0
  122. codeagent/web/static/06b-attachments.js +304 -0
  123. codeagent/web/static/06c-camera.js +488 -0
  124. codeagent/web/static/07-activity-bar.css +127 -0
  125. codeagent/web/static/09-git-p1.css +1 -0
  126. codeagent/web/static/09-git-p2.css +1 -0
  127. codeagent/web/static/09a-init-bind.js +110 -0
  128. codeagent/web/static/09b-panel-toggle.js +80 -0
  129. codeagent/web/static/09c-api-refresh.js +100 -0
  130. codeagent/web/static/09d-status-log.js +80 -0
  131. codeagent/web/static/09e-commit.js +80 -0
  132. codeagent/web/static/09f-remote.js +93 -0
  133. codeagent/web/static/11a-cron-parse.js +117 -0
  134. codeagent/web/static/11b-cron-panel.js +100 -0
  135. codeagent/web/static/11c-cron-card.js +133 -0
  136. codeagent/web/static/11d-cron-form.js +105 -0
  137. codeagent/web/static/11e-env-config.js +168 -0
  138. codeagent/web/static/11f-env-llm-a-state.js +136 -0
  139. codeagent/web/static/11f-env-llm-b-form.js +409 -0
  140. codeagent/web/static/11f-env-llm-c-board.js +322 -0
  141. codeagent/web/static/11g-env-paths-git.js +973 -0
  142. codeagent/web/static/11h-env-mcp-a-state.js +161 -0
  143. codeagent/web/static/11h-env-mcp-b-form.js +229 -0
  144. codeagent/web/static/11h-env-mcp-c-board.js +565 -0
  145. codeagent/web/static/12-plugins.js +127 -0
  146. codeagent/web/static/13a-skills.js +156 -0
  147. codeagent/web/static/13a-todo-utils.js +140 -0
  148. codeagent/web/static/13b-todo-fetch.js +106 -0
  149. codeagent/web/static/13b-tools.js +127 -0
  150. codeagent/web/static/13c-todo-crud.js +92 -0
  151. codeagent/web/static/14-activity-bar.js +177 -0
  152. codeagent/web/static/15-plans.css +194 -0
  153. codeagent/web/static/15-plans.js +219 -0
  154. codeagent/web/static/16-mobile.css +612 -0
  155. codeagent/web/static/16-mobile.js +178 -0
  156. codeagent/web/static/17-preset-ux.css +287 -0
  157. codeagent/web/static/18-agent-mgr.css +616 -0
  158. codeagent/web/static/18-agent-mgr.js +204 -0
  159. codeagent/web/static/24-health-dashboard.js +68 -0
  160. codeagent/web/static/99-brand-polish.css +152 -0
  161. codeagent/web/static/body.html +824 -0
  162. codeagent/web/static/setup/setup_form.html +171 -0
  163. codeagent/web/static/setup/setup_head.html +100 -0
  164. codeagent/web/static/setup/setup_tail.html +264 -0
  165. codeagent/web/static/setup/setup_test.html +38 -0
  166. codeagent/web/web_login.html +265 -0
  167. codeagent/web/webui.html +35 -0
  168. tagword_codeagent-1.1.6.dist-info/METADATA +273 -0
  169. tagword_codeagent-1.1.6.dist-info/RECORD +173 -0
  170. tagword_codeagent-1.1.6.dist-info/WHEEL +5 -0
  171. tagword_codeagent-1.1.6.dist-info/entry_points.txt +3 -0
  172. tagword_codeagent-1.1.6.dist-info/licenses/LICENSE +21 -0
  173. tagword_codeagent-1.1.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,204 @@
1
+ /* ================================================================
2
+ * 18-agent-mgr.js — 单 Agent 配置页(v2)
3
+ *
4
+ * 简化版:去掉多 Agent 列表/搜索/创建/删除/切换,
5
+ * 直接展示当前 Agent 的详情 + 编辑能力(描述/系统提示/工具)。
6
+ * Skills/SysPrompt MD/外部集成由 13a-skills.js / 13b-tools.js 管理。
7
+ * ================================================================ */
8
+
9
+ // ── 头像色板 ──
10
+ var _AVATAR_COLORS = [
11
+ 'default','blue','teal','pink','amber','cyan','rose','violet','emerald','orange'
12
+ ];
13
+
14
+ function _avatarColor(agentId) {
15
+ if (!agentId) return 'default';
16
+ var idx = 0;
17
+ for (var i = 0; i < agentId.length; i++) idx = (idx * 31 + agentId.charCodeAt(i)) % _AVATAR_COLORS.length;
18
+ return _AVATAR_COLORS[idx];
19
+ }
20
+
21
+ function _agentMgrApi(path, options) {
22
+ return fetch(apiUrl(path), options || {}).then(function(r){
23
+ if (!r.ok) return r.json().then(function(e){ throw new Error(e.detail || '请求失败') });
24
+ return r.json();
25
+ });
26
+ }
27
+
28
+ // ── 渲染当前 Agent 详情 ──
29
+ function renderCurrentAgent() {
30
+ var aid = typeof agentId !== 'undefined' ? agentId : 'default';
31
+ _agentMgrApi('/api/ui/agents/' + encodeURIComponent(aid))
32
+ .then(function(data) {
33
+ var a = data.agent;
34
+ if (!a) { _setStatus('error', '未找到 Agent: ' + aid); return; }
35
+ _renderAgentDetail(a);
36
+ // 加载技能和 MD 文件
37
+ if (typeof loadSkills === 'function') loadSkills(a.id);
38
+ if (typeof loadMdFiles === 'function') setTimeout(function(){ loadMdFiles(a.id); }, 50);
39
+ })
40
+ .catch(function(err) {
41
+ _setStatus('error', '加载 Agent 失败: ' + err.message);
42
+ });
43
+ }
44
+
45
+ function _renderAgentDetail(a) {
46
+ var color = _avatarColor(a.id);
47
+ var name = a.name || a.id;
48
+ var firstChar = name.charAt(0).toUpperCase();
49
+ var isActive = a.id === (typeof agentId !== 'undefined' ? agentId : 'default');
50
+ var tools = a.tools && a.tools.acquired && a.tools.acquired.allow ? a.tools.acquired.allow : [];
51
+
52
+ document.getElementById('agentDetailTitle').textContent = 'Agent 配置: ' + (a.name || a.id);
53
+
54
+ // 描述
55
+ var descHtml = '<span class="agent-detail__desc-text">' + escHtml(a.description || '') + '</span>'
56
+ + '<button class="btn btn--ghost btn--sm agent-detail__desc-edit-btn" onclick="_editDescription(\'' + escAttr(a.id) + '\')">✎</button>';
57
+
58
+ // 工具
59
+ var toolsHtml;
60
+ if (!a.tools_configured) {
61
+ toolsHtml = '<span class="agent-detail__tool-none agent-detail__tool-none--unrestricted">未限制(全部工具开放)</span>'
62
+ + '<button class="btn btn--ghost btn--sm agent-detail__tool-edit-btn" onclick="_startEditTools(\'' + escAttr(a.id) + '\')">✎ 编辑</button>';
63
+ } else if (tools.length === 0) {
64
+ toolsHtml = '<span class="agent-detail__tool-none">仅基础工具</span>'
65
+ + '<button class="btn btn--ghost btn--sm agent-detail__tool-edit-btn" onclick="_startEditTools(\'' + escAttr(a.id) + '\')">✎ 编辑</button>';
66
+ } else {
67
+ toolsHtml = '<div class="agent-detail__tools">' + tools.map(function(t){
68
+ return '<span class="agent-detail__tool-tag">' + escHtml(t) + '</span>';
69
+ }).join('') + '</div>'
70
+ + '<button class="btn btn--ghost btn--sm agent-detail__tool-edit-btn" onclick="_startEditTools(\'' + escAttr(a.id) + '\')">✎ 编辑</button>';
71
+ }
72
+
73
+ var html = ''
74
+ + '<div class="agent-detail">'
75
+ // Hero
76
+ + '<div class="agent-detail__hero">'
77
+ + '<div class="agent-card__avatar agent-card__avatar--' + color + '">' + escHtml(firstChar) + '</div>'
78
+ + '<div class="agent-detail__hero-info">'
79
+ + '<div class="agent-detail__hero-name">' + escHtml(name) + '</div>'
80
+ + '<div class="agent-detail__hero-id">' + escHtml(a.id) + '</div>'
81
+ + '<div class="agent-detail__hero-desc" id="agentDetailDesc">' + descHtml + '</div>'
82
+ + '<div class="agent-detail__hero-status' + (isActive ? ' agent-detail__hero-status--active' : '') + '">'
83
+ + (isActive ? '🟢 当前活跃' : '⚪ 未激活') + '</div>'
84
+ + '</div></div>'
85
+ // Grid
86
+ + '<div class="agent-detail__grid">'
87
+ + '<div class="agent-detail__card" id="agentToolsCard" style="grid-column:1/-1">'
88
+ + '<div class="agent-detail__card-title">已启用工具' + (a.tools_configured ? ' (' + tools.length + ')' : '') + '</div>'
89
+ + '<div id="agentToolsContent">' + toolsHtml + '</div>'
90
+ + '</div></div>'
91
+ + '</div>';
92
+
93
+ document.getElementById('agentDetailContent').innerHTML = html;
94
+ }
95
+
96
+ // ── 编辑工具 ──
97
+ function _startEditTools(agentId) {
98
+ var contentEl = document.getElementById('agentToolsContent');
99
+ if (!contentEl) return;
100
+ contentEl.innerHTML = '<div class="agent-loading"><div class="agent-loading__spinner"></div><span>加载工具列表...</span></div>';
101
+
102
+ fetch(apiUrl('/api/ui/tools/available'))
103
+ .then(function(r){ return r.json(); })
104
+ .then(function(data){
105
+ var allTools = data.tools || [];
106
+ return fetch(apiUrl('/api/ui/agents/' + encodeURIComponent(agentId)))
107
+ .then(function(r){ return r.json(); })
108
+ .then(function(d){
109
+ var a = d.agent;
110
+ var allowed = a.tools && a.tools.acquired && a.tools.acquired.allow ? a.tools.acquired.allow : [];
111
+ return {allTools: allTools, allowed: allowed, agentId: agentId};
112
+ });
113
+ })
114
+ .then(function(ctx){
115
+ var html = '<div class="agent-tool-edit">';
116
+ ctx.allTools.forEach(function(t){
117
+ var checked = ctx.allowed.indexOf(t) >= 0 ? ' checked' : '';
118
+ html += '<label class="checkbox-label"><input type="checkbox" class="agent-tool-cb" value="' + escAttr(t) + '"' + checked + '> ' + escHtml(t) + '</label>';
119
+ });
120
+ html += '</div>'
121
+ + '<div class="agent-detail__tool-actions">'
122
+ + '<button class="btn btn--primary btn--sm" onclick="_saveTools(\'' + escAttr(ctx.agentId) + '\')">💾 保存</button>'
123
+ + '<button class="btn btn--ghost btn--sm" onclick="renderCurrentAgent()">取消</button>'
124
+ + '</div>';
125
+ contentEl.innerHTML = html;
126
+ })
127
+ .catch(function(err){
128
+ contentEl.innerHTML = '<span class="agent-detail__tool-none">加载失败: ' + escHtml(err.message) + '</span>'
129
+ + '<button class="btn btn--ghost btn--sm" onclick="renderCurrentAgent()">返回</button>';
130
+ });
131
+ }
132
+
133
+ function _saveTools(agentId) {
134
+ var checked = [];
135
+ document.querySelectorAll('#agentToolsContent .agent-tool-cb:checked').forEach(function(cb){
136
+ checked.push(cb.value);
137
+ });
138
+ var toolsData = { acquired: { allow: checked } };
139
+
140
+ fetch(apiUrl('/api/ui/agents/' + encodeURIComponent(agentId)), {
141
+ method: 'PUT',
142
+ headers: {'Content-Type': 'application/json'},
143
+ body: JSON.stringify({ tools: toolsData })
144
+ })
145
+ .then(function(r){ return r.json(); })
146
+ .then(function(){
147
+ _setStatus('ok', '工具已更新');
148
+ renderCurrentAgent();
149
+ })
150
+ .catch(function(err){
151
+ _setStatus('error', '保存失败: ' + err.message);
152
+ });
153
+ }
154
+
155
+ // ── 编辑描述 ──
156
+ function _editDescription(agentId) {
157
+ var descEl = document.getElementById('agentDetailDesc');
158
+ if (!descEl) return;
159
+ var current = descEl.textContent.replace('✎', '').trim();
160
+ descEl.innerHTML = '<input type="text" class="input agent-detail__desc-input" id="inpAgentDesc" value="' + escAttr(current) + '" placeholder="一句话描述这个 Agent 的用途" />'
161
+ + '<button class="btn btn--primary btn--sm" onclick="_saveDescription(\'' + escAttr(agentId) + '\')">保存</button>'
162
+ + '<button class="btn btn--ghost btn--sm" onclick="renderCurrentAgent()">取消</button>';
163
+ var inp = document.getElementById('inpAgentDesc');
164
+ if (inp) { inp.focus(); inp.select(); }
165
+ }
166
+
167
+ function _saveDescription(agentId) {
168
+ var desc = document.getElementById('inpAgentDesc') ? document.getElementById('inpAgentDesc').value.trim() : '';
169
+ fetch(apiUrl('/api/ui/agents/' + encodeURIComponent(agentId)), {
170
+ method: 'PUT',
171
+ headers: {'Content-Type': 'application/json'},
172
+ body: JSON.stringify({ description: desc })
173
+ })
174
+ .then(function(r){ return r.json(); })
175
+ .then(function(){
176
+ _setStatus('ok', '描述已更新');
177
+ renderCurrentAgent();
178
+ })
179
+ .catch(function(err){
180
+ _setStatus('error', '保存失败: ' + err.message);
181
+ });
182
+ }
183
+
184
+ // ── 状态提示 ──
185
+ function _setStatus(type, msg) {
186
+ var el = document.getElementById('agentStatus');
187
+ if (!el) return;
188
+ el.textContent = msg;
189
+ el.className = 'status-line status-line--' + type;
190
+ if (type === 'ok') {
191
+ setTimeout(function(){ el.textContent = ''; el.className = 'status-line'; }, 3000);
192
+ }
193
+ }
194
+
195
+ // ── 初始化 ──
196
+ function initAgentMgr() {
197
+ renderCurrentAgent();
198
+ }
199
+
200
+ if (document.readyState === 'loading') {
201
+ document.addEventListener('DOMContentLoaded', initAgentMgr);
202
+ } else {
203
+ initAgentMgr();
204
+ }
@@ -0,0 +1,68 @@
1
+ // 健康看板 — Agent 心跳/状态/运行一览
2
+
3
+ function _healthApi(path) {
4
+ return fetch(apiUrl(path)).then(function(r){
5
+ if (!r.ok) throw new Error('请求失败');
6
+ return r.json();
7
+ });
8
+ }
9
+
10
+ function _loadHealthDashboard() {
11
+ _healthApi('/api/ui/health/status').then(function(data){
12
+ _renderHealthStatus(data);
13
+ }).catch(function(err){
14
+ document.getElementById('healthContent').innerHTML = '<div class="health__error">加载失败: ' + err.message + '</div>';
15
+ });
16
+
17
+ _healthApi('/api/ui/runs').then(function(data){
18
+ _renderHealthRuns(data.runs || []);
19
+ }).catch(function(){});
20
+ }
21
+
22
+ function _renderHealthStatus(status) {
23
+ var el = document.getElementById('healthContent');
24
+ var statusBadge = status.status === 'alive' ? '🟢' : (status.status === 'stuck' ? '🔴' : '⚪');
25
+ var html = '<div class="health-section"><h3>Agent 状态</h3>'
26
+ + '<div class="health-grid">'
27
+ + '<div class="health-card"><div class="health-card__label">状态</div><div class="health-card__value">' + statusBadge + ' ' + status.status + '</div></div>'
28
+ + '<div class="health-card"><div class="health-card__label">PID</div><div class="health-card__value">' + (status.process_id || '-') + '</div></div>'
29
+ + '<div class="health-card"><div class="health-card__label">心跳</div><div class="health-card__value">' + (status.elapsed_seconds ? status.elapsed_seconds + 's 前' : '-') + '</div></div>'
30
+ + '</div></div>';
31
+ el.innerHTML = html;
32
+ }
33
+
34
+ function _renderHealthRuns(runs) {
35
+ var html = '<div class="health-section"><h3>运行记录 (' + runs.length + ')</h3><div class="health-runs">';
36
+ if (runs.length === 0) {
37
+ html += '<div class="text-dim">暂无运行记录</div>';
38
+ } else {
39
+ runs.slice(0, 10).forEach(function(r){
40
+ var time = r.created_at ? new Date(r.created_at * 1000).toLocaleString() : '';
41
+ var icon = r.status === 'done' ? '✅' : (r.status === 'failed' ? '❌' : (r.status === 'running' ? '🔄' : '⏳'));
42
+ html += '<div class="health-run"><span class="health-run__icon">' + icon + '</span>'
43
+ + '<span class="health-run__id">' + escHtml(r.id) + '</span>'
44
+ + '<span class="health-run__status">' + escHtml(r.status) + '</span>'
45
+ + '<span class="health-run__time">' + escHtml(time) + '</span></div>';
46
+ });
47
+ }
48
+ html += '</div></div>';
49
+ document.getElementById('healthContent').innerHTML += html;
50
+ }
51
+
52
+ // ── 挂在 stats 页面上 ──
53
+ function initHealthDashboard() {
54
+ // 如果 stats 页面已有内容,追加到后面
55
+ var statsContent = document.getElementById('statsContent');
56
+ if (!statsContent) return;
57
+ statsContent.innerHTML = '<div id="healthContent"></div>';
58
+ _loadHealthDashboard();
59
+
60
+ // 每 30 秒刷新
61
+ setInterval(_loadHealthDashboard, 30000);
62
+ }
63
+
64
+ if (document.readyState === 'loading') {
65
+ document.addEventListener('DOMContentLoaded', initHealthDashboard);
66
+ } else {
67
+ initHealthDashboard();
68
+ }
@@ -0,0 +1,152 @@
1
+ /* ================================================================
2
+ * 99-brand-polish — shell gradient, icon treatment, topbar mark
3
+ * (loads after theme/layout; uses --accent from 01-theme.css)
4
+ * ================================================================ */
5
+
6
+ .app {
7
+ position: relative;
8
+ background: var(--bg);
9
+ background-image:
10
+ radial-gradient(1200px 600px at 0% 0%, var(--accent-softer, rgba(79, 70, 229, 0.06)) 0%, transparent 55%),
11
+ radial-gradient(900px 500px at 100% 10%, rgba(99, 102, 241, 0.07) 0%, transparent 50%),
12
+ radial-gradient(600px 400px at 50% 100%, var(--accent-softer) 0%, transparent 45%);
13
+ }
14
+
15
+ .workspace {
16
+ position: relative;
17
+ }
18
+
19
+ .topbar {
20
+ background: linear-gradient(180deg, var(--bg-panel) 0%, color-mix(in srgb, var(--bg-panel) 96%, var(--bg)) 100%);
21
+ box-shadow: 0 1px 0 color-mix(in srgb, var(--accent) 8%, transparent);
22
+ z-index: 160;
23
+ }
24
+
25
+ .topbar::before {
26
+ content: "";
27
+ position: absolute;
28
+ left: 0;
29
+ top: 0;
30
+ bottom: 0;
31
+ width: 3px;
32
+ background: linear-gradient(180deg, var(--accent) 0%, color-mix(in srgb, var(--accent) 40%, transparent) 100%);
33
+ border-radius: 0 2px 2px 0;
34
+ opacity: 0.85;
35
+ pointer-events: none;
36
+ }
37
+
38
+ .topbar__mark {
39
+ display: flex;
40
+ align-items: center;
41
+ flex-shrink: 0;
42
+ margin-right: var(--sp-2);
43
+ }
44
+
45
+ .topbar__mark img {
46
+ width: 24px;
47
+ height: 24px;
48
+ border-radius: 6px;
49
+ object-fit: contain;
50
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--border) 80%, transparent), var(--shadow-xs);
51
+ background: var(--bg-panel);
52
+ padding: 1px;
53
+ }
54
+
55
+ /* Activity bar: app mark */
56
+ .activity-bar__brand {
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ padding: var(--sp-2) 0 var(--sp-1);
61
+ border-bottom: 1px solid var(--divider);
62
+ flex-shrink: 0;
63
+ }
64
+
65
+ .activity-bar__logo {
66
+ width: 30px;
67
+ height: 30px;
68
+ border-radius: 8px;
69
+ object-fit: contain;
70
+ background: linear-gradient(145deg, #fff 0%, var(--bg-subtle) 100%);
71
+ padding: 2px;
72
+ box-shadow:
73
+ 0 0 0 1px color-mix(in srgb, var(--accent) 18%, var(--border)),
74
+ 0 2px 8px color-mix(in srgb, var(--accent) 12%, transparent);
75
+ }
76
+
77
+ @media (prefers-color-scheme: dark) {
78
+ .activity-bar__logo {
79
+ background: linear-gradient(145deg, var(--bg-subtle) 0%, #0a0a0c 100%);
80
+ box-shadow:
81
+ 0 0 0 1px color-mix(in srgb, var(--accent) 25%, var(--border)),
82
+ 0 2px 10px rgba(0, 0, 0, 0.35);
83
+ }
84
+ }
85
+
86
+ /* Sidebar brand block */
87
+ .brand {
88
+ position: relative;
89
+ overflow: hidden;
90
+ }
91
+
92
+ .brand::after {
93
+ content: "";
94
+ position: absolute;
95
+ inset: 0;
96
+ border-radius: inherit;
97
+ background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 6%, transparent) 0%, transparent 60%);
98
+ pointer-events: none;
99
+ opacity: 0.9;
100
+ }
101
+
102
+ .brand__logo {
103
+ position: relative;
104
+ z-index: 1;
105
+ width: 36px;
106
+ height: 36px;
107
+ border-radius: 10px;
108
+ padding: 3px;
109
+ background: linear-gradient(160deg, #fff, var(--bg-subtle));
110
+ box-shadow:
111
+ 0 0 0 1px color-mix(in srgb, var(--accent) 15%, var(--border-strong)),
112
+ var(--shadow-sm);
113
+ }
114
+
115
+ .brand__text {
116
+ position: relative;
117
+ z-index: 1;
118
+ }
119
+
120
+ @media (prefers-color-scheme: dark) {
121
+ .brand__logo {
122
+ background: linear-gradient(160deg, var(--bg-hover), var(--bg-panel));
123
+ box-shadow:
124
+ 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent),
125
+ var(--shadow-sm);
126
+ }
127
+ }
128
+
129
+ .brand__name {
130
+ font-weight: 700;
131
+ letter-spacing: -0.02em;
132
+ }
133
+
134
+ @supports (-webkit-background-clip: text) {
135
+ .brand__name {
136
+ background: linear-gradient(90deg, var(--text) 0%, color-mix(in srgb, var(--accent) 65%, var(--text)) 125%);
137
+ -webkit-background-clip: text;
138
+ background-clip: text;
139
+ color: transparent;
140
+ }
141
+ }
142
+
143
+ @media (prefers-color-scheme: dark) {
144
+ @supports (-webkit-background-clip: text) {
145
+ .brand__name {
146
+ background: linear-gradient(90deg, var(--text) 0%, var(--accent-hover) 130%);
147
+ -webkit-background-clip: text;
148
+ background-clip: text;
149
+ color: transparent;
150
+ }
151
+ }
152
+ }