agim-cli 1.2.2 → 1.2.17
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/README.md +18 -5
- package/README.zh-CN.md +20 -7
- package/dist/cli.js +42 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/commands/builtin.d.ts.map +1 -1
- package/dist/core/commands/builtin.js +2 -0
- package/dist/core/commands/builtin.js.map +1 -1
- package/dist/core/commands/router.js +1 -1
- package/dist/core/commands/router.js.map +1 -1
- package/dist/core/commands/web.d.ts +3 -0
- package/dist/core/commands/web.d.ts.map +1 -0
- package/dist/core/commands/web.js +28 -0
- package/dist/core/commands/web.js.map +1 -0
- package/dist/core/intent.d.ts +11 -2
- package/dist/core/intent.d.ts.map +1 -1
- package/dist/core/intent.js +26 -4
- package/dist/core/intent.js.map +1 -1
- package/dist/core/memory.js.map +1 -1
- package/dist/core/render-router.d.ts.map +1 -1
- package/dist/core/render-router.js +3 -2
- package/dist/core/render-router.js.map +1 -1
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +8 -1
- package/dist/core/router.js.map +1 -1
- package/dist/core/types.d.ts +3 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/plugins/agents/acp/acp-client.d.ts.map +1 -1
- package/dist/plugins/agents/acp/acp-client.js +7 -0
- package/dist/plugins/agents/acp/acp-client.js.map +1 -1
- package/dist/plugins/agents/acp/discovery.d.ts.map +1 -1
- package/dist/plugins/agents/acp/discovery.js +4 -0
- package/dist/plugins/agents/acp/discovery.js.map +1 -1
- package/dist/plugins/agents/acp/url-guard.d.ts +44 -0
- package/dist/plugins/agents/acp/url-guard.d.ts.map +1 -0
- package/dist/plugins/agents/acp/url-guard.js +109 -0
- package/dist/plugins/agents/acp/url-guard.js.map +1 -0
- package/dist/web/env-mask.d.ts +21 -0
- package/dist/web/env-mask.d.ts.map +1 -0
- package/dist/web/env-mask.js +44 -0
- package/dist/web/env-mask.js.map +1 -0
- package/dist/web/public/assets/a2a-Dk2fSs33.js +7 -0
- package/dist/web/public/assets/a2a-Dk2fSs33.js.map +1 -0
- package/dist/web/public/assets/activity-eiIPshcV.js +7 -0
- package/dist/web/public/assets/activity-eiIPshcV.js.map +1 -0
- package/dist/web/public/assets/admins-DlbQYdW_.js +12 -0
- package/dist/web/public/assets/admins-DlbQYdW_.js.map +1 -0
- package/dist/web/public/assets/agents-BMI1WbZj.js +12 -0
- package/dist/web/public/assets/agents-BMI1WbZj.js.map +1 -0
- package/dist/web/public/assets/approvals-DlXS_sKD.js +10 -0
- package/dist/web/public/assets/approvals-DlXS_sKD.js.map +1 -0
- package/dist/web/public/assets/audit-C8I8xC_6.js +2 -0
- package/dist/web/public/assets/audit-C8I8xC_6.js.map +1 -0
- package/dist/web/public/assets/bgjobs-PFYinH7D.js +7 -0
- package/dist/web/public/assets/bgjobs-PFYinH7D.js.map +1 -0
- package/dist/web/public/assets/brain-DEEJttEL.js +7 -0
- package/dist/web/public/assets/brain-DEEJttEL.js.map +1 -0
- package/dist/web/public/assets/briefcase-BlMy8gI6.js +7 -0
- package/dist/web/public/assets/briefcase-BlMy8gI6.js.map +1 -0
- package/dist/web/public/assets/browser-ponyfill-BOcGq8h9.js +3 -0
- package/dist/web/public/assets/browser-ponyfill-BOcGq8h9.js.map +1 -0
- package/dist/web/public/assets/chevron-right-DmABPvoA.js +7 -0
- package/dist/web/public/assets/chevron-right-DmABPvoA.js.map +1 -0
- package/dist/web/public/assets/circle-check-C0Qpg1vL.js +7 -0
- package/dist/web/public/assets/circle-check-C0Qpg1vL.js.map +1 -0
- package/dist/web/public/assets/circle-check-big-C8LG3beV.js +7 -0
- package/dist/web/public/assets/circle-check-big-C8LG3beV.js.map +1 -0
- package/dist/web/public/assets/circle-x-D_cRHcHK.js +7 -0
- package/dist/web/public/assets/circle-x-D_cRHcHK.js.map +1 -0
- package/dist/web/public/assets/confirm-dialog-Baz_xFle.js +2 -0
- package/dist/web/public/assets/confirm-dialog-Baz_xFle.js.map +1 -0
- package/dist/web/public/assets/data-table--I_ktDF4.js +17 -0
- package/dist/web/public/assets/data-table--I_ktDF4.js.map +1 -0
- package/dist/web/public/assets/dialog-DZpoEskO.js +6 -0
- package/dist/web/public/assets/dialog-DZpoEskO.js.map +1 -0
- package/dist/web/public/assets/download-DbFGHwZ5.js +7 -0
- package/dist/web/public/assets/download-DbFGHwZ5.js.map +1 -0
- package/dist/web/public/assets/email-BB1Hq8eE.js +7 -0
- package/dist/web/public/assets/email-BB1Hq8eE.js.map +1 -0
- package/dist/web/public/assets/empty-state-DXNa90pP.js +2 -0
- package/dist/web/public/assets/empty-state-DXNa90pP.js.map +1 -0
- package/dist/web/public/assets/env-Bqrb9XkC.js +2 -0
- package/dist/web/public/assets/env-Bqrb9XkC.js.map +1 -0
- package/dist/web/public/assets/external-link-nhnJN0qg.js +7 -0
- package/dist/web/public/assets/external-link-nhnJN0qg.js.map +1 -0
- package/dist/web/public/assets/eye-IKkn_oUo.js +12 -0
- package/dist/web/public/assets/eye-IKkn_oUo.js.map +1 -0
- package/dist/web/public/assets/facts-C7Qy9vTw.js +2 -0
- package/dist/web/public/assets/facts-C7Qy9vTw.js.map +1 -0
- package/dist/web/public/assets/health-CMRdeNEW.js +2 -0
- package/dist/web/public/assets/health-CMRdeNEW.js.map +1 -0
- package/dist/web/public/assets/hot-Bh5Nrc7i.js +17 -0
- package/dist/web/public/assets/hot-Bh5Nrc7i.js.map +1 -0
- package/dist/web/public/assets/index-CpGWCLE5.js +166 -0
- package/dist/web/public/assets/index-CpGWCLE5.js.map +1 -0
- package/dist/web/public/assets/index-GpceOxum.css +1 -0
- package/dist/web/public/assets/installed-FYLkPij2.js +7 -0
- package/dist/web/public/assets/installed-FYLkPij2.js.map +1 -0
- package/dist/web/public/assets/jobs-BmqLUzHp.js +2 -0
- package/dist/web/public/assets/jobs-BmqLUzHp.js.map +1 -0
- package/dist/web/public/assets/layout-9Gp_myEd.js +2 -0
- package/dist/web/public/assets/layout-9Gp_myEd.js.map +1 -0
- package/dist/web/public/assets/layout-BZaHqf69.js +2 -0
- package/dist/web/public/assets/layout-BZaHqf69.js.map +1 -0
- package/dist/web/public/assets/layout-CXsUyEpG.js +2 -0
- package/dist/web/public/assets/layout-CXsUyEpG.js.map +1 -0
- package/dist/web/public/assets/layout-DFxtpNut.js +2 -0
- package/dist/web/public/assets/layout-DFxtpNut.js.map +1 -0
- package/dist/web/public/assets/layout-d8qxPKQk.js +2 -0
- package/dist/web/public/assets/layout-d8qxPKQk.js.map +1 -0
- package/dist/web/public/assets/loader-circle-JaKY-xMt.js +7 -0
- package/dist/web/public/assets/loader-circle-JaKY-xMt.js.map +1 -0
- package/dist/web/public/assets/map-pin-hFFSWZ3B.js +7 -0
- package/dist/web/public/assets/map-pin-hFFSWZ3B.js.map +1 -0
- package/dist/web/public/assets/memos-EhjMUvVZ.js +12 -0
- package/dist/web/public/assets/memos-EhjMUvVZ.js.map +1 -0
- package/dist/web/public/assets/messengers-BRV1IVGX.js +7 -0
- package/dist/web/public/assets/messengers-BRV1IVGX.js.map +1 -0
- package/dist/web/public/assets/network-DtCI2ZUU.js +7 -0
- package/dist/web/public/assets/network-DtCI2ZUU.js.map +1 -0
- package/dist/web/public/assets/outbox-CxUbMp6o.js +7 -0
- package/dist/web/public/assets/outbox-CxUbMp6o.js.map +1 -0
- package/dist/web/public/assets/pagination-CkZY8YNa.js +17 -0
- package/dist/web/public/assets/pagination-CkZY8YNa.js.map +1 -0
- package/dist/web/public/assets/persona-B6TFMSnI.js +2 -0
- package/dist/web/public/assets/persona-B6TFMSnI.js.map +1 -0
- package/dist/web/public/assets/play-BxRcWaH5.js +7 -0
- package/dist/web/public/assets/play-BxRcWaH5.js.map +1 -0
- package/dist/web/public/assets/policy-ndE1Y8zD.js +2 -0
- package/dist/web/public/assets/policy-ndE1Y8zD.js.map +1 -0
- package/dist/web/public/assets/react-C9F3QeMB.js +33 -0
- package/dist/web/public/assets/react-C9F3QeMB.js.map +1 -0
- package/dist/web/public/assets/refresh-ccw-Bx817_KW.js +7 -0
- package/dist/web/public/assets/refresh-ccw-Bx817_KW.js.map +1 -0
- package/dist/web/public/assets/reminders-XynkGQc5.js +17 -0
- package/dist/web/public/assets/reminders-XynkGQc5.js.map +1 -0
- package/dist/web/public/assets/save-CqMcATrh.js +7 -0
- package/dist/web/public/assets/save-CqMcATrh.js.map +1 -0
- package/dist/web/public/assets/schedules-VM02w_Om.js +7 -0
- package/dist/web/public/assets/schedules-VM02w_Om.js.map +1 -0
- package/dist/web/public/assets/search-Ba-e1t1P.js +7 -0
- package/dist/web/public/assets/search-Ba-e1t1P.js.map +1 -0
- package/dist/web/public/assets/service-C-wnwJ-b.js +7 -0
- package/dist/web/public/assets/service-C-wnwJ-b.js.map +1 -0
- package/dist/web/public/assets/status-badge-CsdJ6k8Q.js +2 -0
- package/dist/web/public/assets/status-badge-CsdJ6k8Q.js.map +1 -0
- package/dist/web/public/assets/subtasks-mGRKpF0G.js +7 -0
- package/dist/web/public/assets/subtasks-mGRKpF0G.js.map +1 -0
- package/dist/web/public/assets/table-vmLMgj6_.js +2 -0
- package/dist/web/public/assets/table-vmLMgj6_.js.map +1 -0
- package/dist/web/public/assets/topn-nu66Fotx.js +7 -0
- package/dist/web/public/assets/topn-nu66Fotx.js.map +1 -0
- package/dist/web/public/assets/trash-2-ZIitN_U3.js +7 -0
- package/dist/web/public/assets/trash-2-ZIitN_U3.js.map +1 -0
- package/dist/web/public/assets/use-event-stream-BGeFcayX.js +2 -0
- package/dist/web/public/assets/use-event-stream-BGeFcayX.js.map +1 -0
- package/dist/web/public/assets/use-memory-DgEqHEca.js +2 -0
- package/dist/web/public/assets/use-memory-DgEqHEca.js.map +1 -0
- package/dist/web/public/assets/use-observability-CQev_A8e.js +2 -0
- package/dist/web/public/assets/use-observability-CQev_A8e.js.map +1 -0
- package/dist/web/public/assets/use-settings-CU-UcrVD.js +2 -0
- package/dist/web/public/assets/use-settings-CU-UcrVD.js.map +1 -0
- package/dist/web/public/assets/use-skills-Dr77CXLA.js +2 -0
- package/dist/web/public/assets/use-skills-Dr77CXLA.js.map +1 -0
- package/dist/web/public/assets/use-workspace-PNv9Z4de.js +2 -0
- package/dist/web/public/assets/use-workspace-PNv9Z4de.js.map +1 -0
- package/dist/web/public/assets/useQuery-BTyugXYV.js +2 -0
- package/dist/web/public/assets/useQuery-BTyugXYV.js.map +1 -0
- package/dist/web/public/assets/vector-w-Ea3pg6.js +2 -0
- package/dist/web/public/assets/vector-w-Ea3pg6.js.map +1 -0
- package/dist/web/public/assets/viewer-DKA7QP9U.js +12 -0
- package/dist/web/public/assets/viewer-DKA7QP9U.js.map +1 -0
- package/dist/web/public/assets/workspace-DVLZca7t.js +17 -0
- package/dist/web/public/assets/workspace-DVLZca7t.js.map +1 -0
- package/dist/web/public/assets/workspaces-DYZsMmY-.js +7 -0
- package/dist/web/public/assets/workspaces-DYZsMmY-.js.map +1 -0
- package/dist/web/public/assets/x-Ru3rHT82.js +7 -0
- package/dist/web/public/assets/x-Ru3rHT82.js.map +1 -0
- package/dist/web/public/favicon.svg +4 -0
- package/dist/web/public/index.html +37 -928
- package/dist/web/public/manifest.webmanifest +19 -0
- package/dist/web/public/tasks.html +307 -5
- package/dist/web/public/vendor/chart.umd.min.js +20 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +640 -60
- package/dist/web/server.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Agim",
|
|
3
|
+
"short_name": "Agim",
|
|
4
|
+
"description": "agim — multi-agent gateway console",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"scope": "/",
|
|
7
|
+
"display": "standalone",
|
|
8
|
+
"orientation": "any",
|
|
9
|
+
"theme_color": "#4f46e5",
|
|
10
|
+
"background_color": "#f7f8fa",
|
|
11
|
+
"icons": [
|
|
12
|
+
{
|
|
13
|
+
"src": "/favicon.svg",
|
|
14
|
+
"sizes": "any",
|
|
15
|
+
"type": "image/svg+xml",
|
|
16
|
+
"purpose": "any maskable"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -233,6 +233,22 @@
|
|
|
233
233
|
// ── v1.2 Cost & Health tab ──
|
|
234
234
|
tabsCost: '💰 Cost & Health',
|
|
235
235
|
tabsMemory: '🧠 Memory',
|
|
236
|
+
tabsSkills: '🛠 Skills',
|
|
237
|
+
skillsH2: '🛠 Installed Skills',
|
|
238
|
+
skillsIntro: 'Read-only inventory of skills installed for claude-code / opencode on this host. Click a row for the full description. To install a new skill, send <code>/find-skills</code> in IM, or browse the skillhub.cn hot list below.',
|
|
239
|
+
skillsSearchPh: 'Search (name / description)',
|
|
240
|
+
skillsCatAll: 'All categories',
|
|
241
|
+
skillsRemoteH2: 'Hot on skillhub.cn',
|
|
242
|
+
skillsRemoteOpen: 'Open skillhub.cn ↗',
|
|
243
|
+
skillsRemoteIntro: 'Live top-50 hot downloads from skillhub.cn (5-min cache). Click any entry for the description + install instructions. agim never auto-runs installs — you copy the command and paste into shell or IM.',
|
|
244
|
+
skillsRemoteCached: 'cache hit',
|
|
245
|
+
skillsRemoteStale: 'upstream down, serving cached',
|
|
246
|
+
skillsCol: 'slug',
|
|
247
|
+
skillsName: 'name / description',
|
|
248
|
+
skillsStars: '⭐ stars',
|
|
249
|
+
skillsInstalls: '⬇ installs',
|
|
250
|
+
skillsHowInstall: 'Install (pick one; agim never auto-runs)',
|
|
251
|
+
skillsHostHint: 'The first two require skillhub CLI on the host. See docs/skills.md or skillhub.cn.',
|
|
236
252
|
costH2: '💰 Cost & Health',
|
|
237
253
|
costWindow: 'Window',
|
|
238
254
|
costDays1: '1 day',
|
|
@@ -507,6 +523,22 @@
|
|
|
507
523
|
// ── v1.2 Cost & Health tab ──
|
|
508
524
|
tabsCost: '💰 成本与健康',
|
|
509
525
|
tabsMemory: '🧠 记忆',
|
|
526
|
+
tabsSkills: '🛠 技能',
|
|
527
|
+
skillsH2: '🛠 已安装的技能',
|
|
528
|
+
skillsIntro: '本机已安装的 claude / opencode skills 索引。点击行查看完整描述。要安装新 skill 请在 IM 里发 <code>/find-skills</code>,或浏览下方 skillhub.cn 热门榜。',
|
|
529
|
+
skillsSearchPh: '搜索(名称 / 描述)',
|
|
530
|
+
skillsCatAll: '所有类别',
|
|
531
|
+
skillsRemoteH2: 'skillhub.cn 热门',
|
|
532
|
+
skillsRemoteOpen: '前往 skillhub.cn ↗',
|
|
533
|
+
skillsRemoteIntro: '实时拉取 skillhub.cn top 50 热门下载(5 分钟缓存)。点击任意条目查看描述 + 安装命令。agim 不会自动跑安装——命令复制后由你贴去 shell 或 IM 触发。',
|
|
534
|
+
skillsRemoteCached: '缓存命中',
|
|
535
|
+
skillsRemoteStale: '上游不可达,用旧数据',
|
|
536
|
+
skillsCol: 'slug',
|
|
537
|
+
skillsName: '名称 / 描述',
|
|
538
|
+
skillsStars: '⭐ stars',
|
|
539
|
+
skillsInstalls: '⬇ installs',
|
|
540
|
+
skillsHowInstall: '安装方式(任选一个;agim 不会自动跑)',
|
|
541
|
+
skillsHostHint: '前两条要先在 host 上跑 skillhub install.sh。详见 docs/skills.md 或 skillhub.cn。',
|
|
510
542
|
costH2: '💰 成本与健康',
|
|
511
543
|
costWindow: '窗口',
|
|
512
544
|
costDays1: '1 天',
|
|
@@ -912,6 +944,7 @@
|
|
|
912
944
|
<button type="button" class="tab" data-tab="a2a" id="tab-a2a">A2A</button>
|
|
913
945
|
<button type="button" class="tab" data-tab="cost" id="tab-cost">💰 Cost & Health</button>
|
|
914
946
|
<button type="button" class="tab" data-tab="memory" id="tab-memory">🧠 Memory</button>
|
|
947
|
+
<button type="button" class="tab" data-tab="skills" id="tab-skills">🛠 Skills</button>
|
|
915
948
|
</div>
|
|
916
949
|
|
|
917
950
|
<section id="jobs-pane">
|
|
@@ -1286,6 +1319,43 @@
|
|
|
1286
1319
|
<p class="muted" id="mem-facts-status" style="margin-top:6px;font-size:12px"></p>
|
|
1287
1320
|
</div>
|
|
1288
1321
|
</section>
|
|
1322
|
+
|
|
1323
|
+
<!-- v1.2.3 — Skills browser: read-only inventory of installed claude /
|
|
1324
|
+
opencode skills + a remote "hot on skillhub.cn" panel. -->
|
|
1325
|
+
<section id="skills-pane" hidden>
|
|
1326
|
+
<h2 style="margin-top:0" data-i18n="skillsH2">🛠 已安装的 Skills</h2>
|
|
1327
|
+
<p class="muted" style="margin-top:-4px;margin-bottom:12px;font-size:13px" data-i18n="skillsIntro">
|
|
1328
|
+
本机已安装的 claude / opencode skills 索引。点击行查看完整描述。
|
|
1329
|
+
要安装新 skill 请在 IM 里发 <code>/find-skills</code>,或浏览下方 skillhub.cn 热门榜。
|
|
1330
|
+
</p>
|
|
1331
|
+
<div class="toolbar" style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:12px">
|
|
1332
|
+
<input type="text" id="skills-search" placeholder="搜索(名称 / 描述)" data-i18n-attr="placeholder:skillsSearchPh" style="width:240px;font-size:13px" />
|
|
1333
|
+
<select id="skills-cat-filter" style="font-size:13px;min-width:160px">
|
|
1334
|
+
<option value="" data-i18n="skillsCatAll">所有类别</option>
|
|
1335
|
+
</select>
|
|
1336
|
+
<button type="button" id="btn-skills-refresh" data-i18n="refresh">刷新</button>
|
|
1337
|
+
<span id="skills-stats" class="muted" style="font-size:12px;margin-left:8px"></span>
|
|
1338
|
+
</div>
|
|
1339
|
+
<div id="skills-list">…</div>
|
|
1340
|
+
|
|
1341
|
+
<!-- Remote: skillhub.cn hot showcase -->
|
|
1342
|
+
<div style="margin-top:32px;border-top:1px solid var(--border,#d0d7de);padding-top:16px">
|
|
1343
|
+
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px;margin-bottom:6px">
|
|
1344
|
+
<h2 style="margin:0">🔥 <span data-i18n="skillsRemoteH2">skillhub.cn 热门</span>
|
|
1345
|
+
<span id="skills-remote-meta" class="muted" style="font-weight:400;font-size:12px"></span>
|
|
1346
|
+
</h2>
|
|
1347
|
+
<div>
|
|
1348
|
+
<a href="https://skillhub.cn" target="_blank" rel="noopener" class="btn" data-i18n="skillsRemoteOpen">前往 skillhub.cn ↗</a>
|
|
1349
|
+
<button type="button" id="btn-skills-remote-refresh" class="btn" data-i18n="refresh" style="margin-left:6px">刷新</button>
|
|
1350
|
+
</div>
|
|
1351
|
+
</div>
|
|
1352
|
+
<p class="muted" style="font-size:12px;margin:0 0 12px" data-i18n="skillsRemoteIntro">
|
|
1353
|
+
实时拉取 skillhub.cn top 50 热门下载(5 分钟缓存)。点击任意条目查看描述。
|
|
1354
|
+
安装提示见弹窗末端 — 用 skillhub CLI 或在 IM 里告诉 agent 通过 skillhub 安装。
|
|
1355
|
+
</p>
|
|
1356
|
+
<div id="skills-remote-list"><p class="muted">…</p></div>
|
|
1357
|
+
</div>
|
|
1358
|
+
</section>
|
|
1289
1359
|
</main>
|
|
1290
1360
|
|
|
1291
1361
|
<div class="modal-bg" id="modal-bg">
|
|
@@ -1319,6 +1389,7 @@
|
|
|
1319
1389
|
document.getElementById('tab-a2a').textContent = T.tabsA2A;
|
|
1320
1390
|
if (T.tabsCost) document.getElementById('tab-cost').textContent = T.tabsCost;
|
|
1321
1391
|
if (T.tabsMemory) document.getElementById('tab-memory').textContent = T.tabsMemory;
|
|
1392
|
+
if (T.tabsSkills) document.getElementById('tab-skills').textContent = T.tabsSkills;
|
|
1322
1393
|
document.getElementById('hdr-outbox').textContent = T.tabsOutbox;
|
|
1323
1394
|
document.getElementById('hdr-a2a').textContent = T.tabsA2A;
|
|
1324
1395
|
|
|
@@ -1420,6 +1491,7 @@
|
|
|
1420
1491
|
document.getElementById('a2a-pane').hidden = tab !== 'a2a';
|
|
1421
1492
|
document.getElementById('cost-pane').hidden = tab !== 'cost';
|
|
1422
1493
|
document.getElementById('memory-pane').hidden = tab !== 'memory';
|
|
1494
|
+
document.getElementById('skills-pane').hidden = tab !== 'skills';
|
|
1423
1495
|
// Lazy-load on first activation; auto-refresh hooks below kick in too.
|
|
1424
1496
|
if (tab === 'schedules') loadSchedules();
|
|
1425
1497
|
if (tab === 'background') { ensureBgRootsLoaded().then(loadBgjobs); }
|
|
@@ -1439,6 +1511,7 @@
|
|
|
1439
1511
|
checkMemoryEnabledThen(() => { loadMemVecConfig(); loadMemVecStatus(); });
|
|
1440
1512
|
}
|
|
1441
1513
|
if (tab !== 'memory') stopMemVecPolling();
|
|
1514
|
+
if (tab === 'skills') loadSkills();
|
|
1442
1515
|
// Pause/resume auto-refresh so hidden tabs don't poll.
|
|
1443
1516
|
setupBgAutoRefresh();
|
|
1444
1517
|
setupApprovalsAutoRefresh();
|
|
@@ -2747,14 +2820,19 @@
|
|
|
2747
2820
|
function ensureChartJs() {
|
|
2748
2821
|
if (window.Chart) return Promise.resolve();
|
|
2749
2822
|
if (costChartJsLoaded) return costChartJsLoaded;
|
|
2750
|
-
|
|
2823
|
+
// v1.2.3 — try the vendored copy first (no CDN dependency, works in
|
|
2824
|
+
// CN where jsdelivr is often blocked). Fall back to jsdelivr if the
|
|
2825
|
+
// vendor file is missing (e.g. dev hot-reload before build copied it).
|
|
2826
|
+
const tryLoad = (src) => new Promise((resolve, reject) => {
|
|
2751
2827
|
const s = document.createElement('script');
|
|
2752
|
-
s.src =
|
|
2828
|
+
s.src = src;
|
|
2753
2829
|
s.crossOrigin = 'anonymous';
|
|
2754
2830
|
s.onload = () => resolve();
|
|
2755
|
-
s.onerror = () => reject(new Error('
|
|
2831
|
+
s.onerror = () => reject(new Error('failed: ' + src));
|
|
2756
2832
|
document.head.appendChild(s);
|
|
2757
2833
|
});
|
|
2834
|
+
costChartJsLoaded = tryLoad('/vendor/chart.umd.min.js')
|
|
2835
|
+
.catch(() => tryLoad('https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.min.js'));
|
|
2758
2836
|
return costChartJsLoaded;
|
|
2759
2837
|
}
|
|
2760
2838
|
|
|
@@ -2772,8 +2850,22 @@
|
|
|
2772
2850
|
const data = await api('/api/health/summary?days=' + days);
|
|
2773
2851
|
renderCostKpis(data);
|
|
2774
2852
|
renderCostRange(data);
|
|
2775
|
-
|
|
2776
|
-
|
|
2853
|
+
let chartLoadErr = null;
|
|
2854
|
+
await ensureChartJs().catch((e) => { chartLoadErr = e; });
|
|
2855
|
+
if (chartLoadErr) {
|
|
2856
|
+
// Visible hint when both the vendored copy AND CDN fail
|
|
2857
|
+
// (cached browser, blocked CDN, etc). Without this, the chart
|
|
2858
|
+
// area is empty + silent.
|
|
2859
|
+
const c = document.getElementById('cost-trend');
|
|
2860
|
+
if (c && c.parentElement) {
|
|
2861
|
+
c.parentElement.innerHTML = `<p style="color:#d00;font-size:12px">
|
|
2862
|
+
chart.js 加载失败:${escapeHtmlSafe(String(chartLoadErr.message || chartLoadErr))}
|
|
2863
|
+
(检查 /vendor/chart.umd.min.js 是否存在,或浏览器是否屏蔽了 jsdelivr)
|
|
2864
|
+
</p>`;
|
|
2865
|
+
}
|
|
2866
|
+
} else {
|
|
2867
|
+
renderCostTrend(data);
|
|
2868
|
+
}
|
|
2777
2869
|
} catch (err) {
|
|
2778
2870
|
document.getElementById('cost-kpi').innerHTML = '<div class="error">加载失败: ' + (err.message || err) + '</div>';
|
|
2779
2871
|
}
|
|
@@ -3415,6 +3507,216 @@
|
|
|
3415
3507
|
}
|
|
3416
3508
|
});
|
|
3417
3509
|
|
|
3510
|
+
// ============================================
|
|
3511
|
+
// v1.2.3 — Skills tab
|
|
3512
|
+
// ============================================
|
|
3513
|
+
let skillsCache = null; // {total, byCategory, skills}
|
|
3514
|
+
async function loadSkills() {
|
|
3515
|
+
const listEl = document.getElementById('skills-list');
|
|
3516
|
+
if (listEl) listEl.innerHTML = '<p class="muted">' + (T.loading || 'Loading…') + '</p>';
|
|
3517
|
+
try {
|
|
3518
|
+
const data = await api('/api/skills');
|
|
3519
|
+
skillsCache = data;
|
|
3520
|
+
renderSkillsCatFilter(data);
|
|
3521
|
+
renderSkills();
|
|
3522
|
+
const stats = document.getElementById('skills-stats');
|
|
3523
|
+
if (stats) {
|
|
3524
|
+
const cats = Object.keys(data.byCategory || {}).length;
|
|
3525
|
+
stats.textContent = `· ${data.total} skills · ${cats} categories`;
|
|
3526
|
+
}
|
|
3527
|
+
} catch (err) {
|
|
3528
|
+
if (listEl) listEl.innerHTML = '<p style="color:#d00">' + escapeHtmlSafe(String(err.message || err)) + '</p>';
|
|
3529
|
+
}
|
|
3530
|
+
// Kick off remote hot panel in parallel — fire-and-forget; its own
|
|
3531
|
+
// error rendering is in loadSkillsRemote.
|
|
3532
|
+
loadSkillsRemote();
|
|
3533
|
+
}
|
|
3534
|
+
function renderSkillsCatFilter(data) {
|
|
3535
|
+
const sel = document.getElementById('skills-cat-filter');
|
|
3536
|
+
if (!sel) return;
|
|
3537
|
+
const prev = sel.value;
|
|
3538
|
+
// Keep first option (all), append discovered categories
|
|
3539
|
+
const allOpt = sel.options[0];
|
|
3540
|
+
sel.innerHTML = '';
|
|
3541
|
+
sel.appendChild(allOpt);
|
|
3542
|
+
const cats = Object.keys(data.byCategory || {}).sort();
|
|
3543
|
+
for (const c of cats) {
|
|
3544
|
+
const o = document.createElement('option');
|
|
3545
|
+
o.value = c;
|
|
3546
|
+
o.textContent = `${c} (${data.byCategory[c]})`;
|
|
3547
|
+
sel.appendChild(o);
|
|
3548
|
+
}
|
|
3549
|
+
sel.value = prev;
|
|
3550
|
+
}
|
|
3551
|
+
function renderSkills() {
|
|
3552
|
+
if (!skillsCache) return;
|
|
3553
|
+
const listEl = document.getElementById('skills-list');
|
|
3554
|
+
if (!listEl) return;
|
|
3555
|
+
const q = (document.getElementById('skills-search')?.value || '').toLowerCase().trim();
|
|
3556
|
+
const cat = document.getElementById('skills-cat-filter')?.value || '';
|
|
3557
|
+
const filtered = skillsCache.skills.filter(s => {
|
|
3558
|
+
if (cat && s.category !== cat) return false;
|
|
3559
|
+
if (!q) return true;
|
|
3560
|
+
return s.slug.toLowerCase().includes(q)
|
|
3561
|
+
|| (s.name || '').toLowerCase().includes(q)
|
|
3562
|
+
|| (s.description || '').toLowerCase().includes(q);
|
|
3563
|
+
});
|
|
3564
|
+
if (filtered.length === 0) {
|
|
3565
|
+
listEl.innerHTML = '<p class="muted">(no skills match)</p>';
|
|
3566
|
+
return;
|
|
3567
|
+
}
|
|
3568
|
+
// Group by category for clearer scan
|
|
3569
|
+
const byCat = {};
|
|
3570
|
+
for (const s of filtered) {
|
|
3571
|
+
if (!byCat[s.category]) byCat[s.category] = [];
|
|
3572
|
+
byCat[s.category].push(s);
|
|
3573
|
+
}
|
|
3574
|
+
const html = [];
|
|
3575
|
+
for (const cat of Object.keys(byCat).sort()) {
|
|
3576
|
+
html.push(`<h3 style="margin:18px 0 8px;font-size:14px;color:var(--muted,#656d76)">${escapeHtmlSafe(cat)} <span style="font-weight:400">(${byCat[cat].length})</span></h3>`);
|
|
3577
|
+
html.push('<table class="data-table"><tbody>');
|
|
3578
|
+
for (const s of byCat[cat]) {
|
|
3579
|
+
const agentBadge = s.agents.map(a => `<span style="display:inline-block;padding:1px 6px;margin-right:4px;border-radius:3px;background:${a==='claude'?'#fde68a':'#bfdbfe'};font-size:11px;color:#1f2328">${a}</span>`).join('');
|
|
3580
|
+
const descPreview = (s.description || '').slice(0, 140) + ((s.description || '').length > 140 ? '…' : '');
|
|
3581
|
+
html.push(`<tr style="cursor:pointer" data-skill="${escapeHtmlSafe(s.slug)}">
|
|
3582
|
+
<td style="width:240px;vertical-align:top"><code>${escapeHtmlSafe(s.slug)}</code></td>
|
|
3583
|
+
<td style="width:120px;vertical-align:top">${agentBadge}</td>
|
|
3584
|
+
<td style="vertical-align:top;color:var(--muted,#656d76)">${escapeHtmlSafe(descPreview)}</td>
|
|
3585
|
+
</tr>`);
|
|
3586
|
+
}
|
|
3587
|
+
html.push('</tbody></table>');
|
|
3588
|
+
}
|
|
3589
|
+
listEl.innerHTML = html.join('');
|
|
3590
|
+
listEl.querySelectorAll('[data-skill]').forEach(tr => {
|
|
3591
|
+
tr.addEventListener('click', () => openSkillModal(tr.getAttribute('data-skill')));
|
|
3592
|
+
});
|
|
3593
|
+
}
|
|
3594
|
+
async function openSkillModal(slug) {
|
|
3595
|
+
const m = document.getElementById('modal');
|
|
3596
|
+
const bg = document.getElementById('modal-bg');
|
|
3597
|
+
m.innerHTML = `<p class="muted">Loading ${escapeHtmlSafe(slug)}…</p>`;
|
|
3598
|
+
bg.classList.add('show');
|
|
3599
|
+
try {
|
|
3600
|
+
const data = await api('/api/skills/' + encodeURIComponent(slug));
|
|
3601
|
+
// Render the SKILL.md content. Strip the frontmatter block, then
|
|
3602
|
+
// run through marked() if available, otherwise plain <pre>.
|
|
3603
|
+
let body = data.content || '';
|
|
3604
|
+
if (body.startsWith('---')) {
|
|
3605
|
+
const end = body.indexOf('\n---', 3);
|
|
3606
|
+
if (end >= 0) body = body.slice(end + 4).trimStart();
|
|
3607
|
+
}
|
|
3608
|
+
const rendered = (window.marked && typeof marked.parse === 'function')
|
|
3609
|
+
? marked.parse(body)
|
|
3610
|
+
: `<pre style="white-space:pre-wrap;font-size:12px">${escapeHtmlSafe(body)}</pre>`;
|
|
3611
|
+
const agentBadge = data.agents.map(a => `<span style="display:inline-block;padding:1px 6px;margin-right:4px;border-radius:3px;background:${a==='claude'?'#fde68a':'#bfdbfe'};font-size:11px;color:#1f2328">${a}</span>`).join('');
|
|
3612
|
+
m.innerHTML = `
|
|
3613
|
+
<div style="display:flex;justify-content:space-between;align-items:start;margin-bottom:8px">
|
|
3614
|
+
<h2 style="margin:0"><code>${escapeHtmlSafe(data.slug)}</code></h2>
|
|
3615
|
+
<button type="button" class="btn" onclick="document.getElementById('modal-bg').classList.remove('show')">${T.close || 'Close'}</button>
|
|
3616
|
+
</div>
|
|
3617
|
+
<p class="muted" style="font-size:12px;margin:0 0 8px">
|
|
3618
|
+
${agentBadge} · <strong>${escapeHtmlSafe(data.category)}</strong>
|
|
3619
|
+
· <code style="font-size:11px">${escapeHtmlSafe(data.path)}</code>
|
|
3620
|
+
</p>
|
|
3621
|
+
<p style="margin:0 0 16px"><strong>${escapeHtmlSafe(data.name)}</strong> — ${escapeHtmlSafe(data.description)}</p>
|
|
3622
|
+
<div class="markdown-body" style="border-top:1px solid var(--border,#d0d7de);padding-top:12px;max-height:60vh;overflow-y:auto">${rendered}</div>
|
|
3623
|
+
`;
|
|
3624
|
+
} catch (err) {
|
|
3625
|
+
m.innerHTML = `<p style="color:#d00">${escapeHtmlSafe(String(err.message || err))}</p>
|
|
3626
|
+
<button type="button" class="btn" onclick="document.getElementById('modal-bg').classList.remove('show')">${T.close || 'Close'}</button>`;
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
document.getElementById('skills-search')?.addEventListener('input', renderSkills);
|
|
3630
|
+
document.getElementById('skills-cat-filter')?.addEventListener('change', renderSkills);
|
|
3631
|
+
document.getElementById('btn-skills-refresh')?.addEventListener('click', loadSkills);
|
|
3632
|
+
|
|
3633
|
+
// ─── skillhub.cn remote hot ───
|
|
3634
|
+
async function loadSkillsRemote() {
|
|
3635
|
+
const listEl = document.getElementById('skills-remote-list');
|
|
3636
|
+
const metaEl = document.getElementById('skills-remote-meta');
|
|
3637
|
+
if (listEl) listEl.innerHTML = '<p class="muted">' + (T.loading || 'Loading…') + '</p>';
|
|
3638
|
+
try {
|
|
3639
|
+
const data = await api('/api/skills/remote/hot');
|
|
3640
|
+
const skills = (data && data.skills) || [];
|
|
3641
|
+
if (metaEl) {
|
|
3642
|
+
const cacheStr = data.cached
|
|
3643
|
+
? ` · ${T.skillsRemoteCached || '缓存命中'}`
|
|
3644
|
+
: '';
|
|
3645
|
+
const staleStr = data.stale ? ` · ⚠️ ${T.skillsRemoteStale || '上游不可达,用旧数据'}` : '';
|
|
3646
|
+
metaEl.textContent = `(${skills.length}${cacheStr}${staleStr})`;
|
|
3647
|
+
}
|
|
3648
|
+
const html = ['<table class="data-table"><thead><tr>',
|
|
3649
|
+
`<th style="width:200px">${T.skillsCol || 'slug'}</th>`,
|
|
3650
|
+
`<th>${T.skillsName || '名称 / 描述'}</th>`,
|
|
3651
|
+
`<th style="width:100px;text-align:right">${T.skillsStars || '⭐ stars'}</th>`,
|
|
3652
|
+
`<th style="width:110px;text-align:right">${T.skillsInstalls || '⬇ installs'}</th>`,
|
|
3653
|
+
'</tr></thead><tbody>'];
|
|
3654
|
+
for (const s of skills) {
|
|
3655
|
+
const desc = (s.description || '').replace(/\n+/g, ' ').slice(0, 150);
|
|
3656
|
+
const more = (s.description || '').length > 150 ? '…' : '';
|
|
3657
|
+
html.push(`<tr style="cursor:pointer" data-remote-slug="${escapeHtmlSafe(s.slug)}">
|
|
3658
|
+
<td style="vertical-align:top"><code>${escapeHtmlSafe(s.slug)}</code><div class="muted" style="font-size:11px">${escapeHtmlSafe(s.category||'')}</div></td>
|
|
3659
|
+
<td style="vertical-align:top">
|
|
3660
|
+
<div><strong>${escapeHtmlSafe(s.name||s.slug)}</strong> <span class="muted" style="font-size:11px">v${escapeHtmlSafe(s.version||'?')}</span></div>
|
|
3661
|
+
<div class="muted" style="font-size:12px;margin-top:2px">${escapeHtmlSafe(desc)}${more}</div>
|
|
3662
|
+
</td>
|
|
3663
|
+
<td style="vertical-align:top;text-align:right">${(s.stars||0).toLocaleString()}</td>
|
|
3664
|
+
<td style="vertical-align:top;text-align:right">${(s.installs||0).toLocaleString()}</td>
|
|
3665
|
+
</tr>`);
|
|
3666
|
+
}
|
|
3667
|
+
html.push('</tbody></table>');
|
|
3668
|
+
if (skills.length === 0) listEl.innerHTML = '<p class="muted">(empty)</p>';
|
|
3669
|
+
else listEl.innerHTML = html.join('');
|
|
3670
|
+
listEl.querySelectorAll('[data-remote-slug]').forEach(tr => {
|
|
3671
|
+
tr.addEventListener('click', () => openRemoteSkillModal(tr.getAttribute('data-remote-slug'), skills));
|
|
3672
|
+
});
|
|
3673
|
+
} catch (err) {
|
|
3674
|
+
if (listEl) listEl.innerHTML = '<p style="color:#d00">' + escapeHtmlSafe(String(err.message || err)) + '</p>';
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
function openRemoteSkillModal(slug, skills) {
|
|
3678
|
+
const s = skills.find(x => x.slug === slug);
|
|
3679
|
+
if (!s) return;
|
|
3680
|
+
const m = document.getElementById('modal');
|
|
3681
|
+
const bg = document.getElementById('modal-bg');
|
|
3682
|
+
const desc = escapeHtmlSafe(s.description || '');
|
|
3683
|
+
// Three install paths the user can pick. We never auto-execute —
|
|
3684
|
+
// operator's choice to copy + paste into shell or forward to agent.
|
|
3685
|
+
const installCmds = [
|
|
3686
|
+
{ label: 'CLI (host)', cmd: 'skillhub install ' + s.slug },
|
|
3687
|
+
{ label: 'CLI dry-run', cmd: 'skillhub search ' + s.slug },
|
|
3688
|
+
{ label: 'IM 让 agent 安装', cmd: '请用 skillhub 安装 ' + s.slug + ' 技能' },
|
|
3689
|
+
];
|
|
3690
|
+
const cmdRows = installCmds.map(c =>
|
|
3691
|
+
`<div style="margin-top:6px"><span class="muted" style="font-size:11px;display:inline-block;width:130px">${escapeHtmlSafe(c.label)}</span>
|
|
3692
|
+
<code style="font-size:12px">${escapeHtmlSafe(c.cmd)}</code>
|
|
3693
|
+
<button type="button" class="btn" style="font-size:11px;padding:1px 6px;margin-left:6px" onclick="navigator.clipboard.writeText('${c.cmd.replace(/'/g,"\\'")}').then(()=>{this.textContent='✓'; setTimeout(()=>{this.textContent='复制';},1500);})">复制</button>
|
|
3694
|
+
</div>`).join('');
|
|
3695
|
+
m.innerHTML = `
|
|
3696
|
+
<div style="display:flex;justify-content:space-between;align-items:start;margin-bottom:8px">
|
|
3697
|
+
<h2 style="margin:0">${escapeHtmlSafe(s.name || s.slug)} <span class="muted" style="font-size:13px;font-weight:400">v${escapeHtmlSafe(s.version || '?')}</span></h2>
|
|
3698
|
+
<button type="button" class="btn" onclick="document.getElementById('modal-bg').classList.remove('show')">${T.close || 'Close'}</button>
|
|
3699
|
+
</div>
|
|
3700
|
+
<p class="muted" style="font-size:12px;margin:0 0 10px">
|
|
3701
|
+
<code>${escapeHtmlSafe(s.slug)}</code>
|
|
3702
|
+
${s.category ? ' · ' + escapeHtmlSafe(s.category) : ''}
|
|
3703
|
+
· ⭐ ${(s.stars||0).toLocaleString()}
|
|
3704
|
+
· ⬇ ${(s.installs||0).toLocaleString()} installs
|
|
3705
|
+
· ${(s.downloads||0).toLocaleString()} downloads
|
|
3706
|
+
</p>
|
|
3707
|
+
<div style="white-space:pre-wrap;border-top:1px solid var(--border,#d0d7de);padding-top:10px;font-size:13px">${desc}</div>
|
|
3708
|
+
<div style="margin-top:14px;padding-top:10px;border-top:1px solid var(--border,#d0d7de)">
|
|
3709
|
+
<strong style="font-size:13px">${T.skillsHowInstall || '安装方式(任选一个;agim 不会自动跑)'}</strong>
|
|
3710
|
+
${cmdRows}
|
|
3711
|
+
<p class="muted" style="font-size:11px;margin-top:8px">
|
|
3712
|
+
${T.skillsHostHint || '前两条要先在 host 上跑 skillhub install.sh。详见 docs/memory-and-vector.md 或 skillhub.cn。'}
|
|
3713
|
+
</p>
|
|
3714
|
+
</div>
|
|
3715
|
+
`;
|
|
3716
|
+
bg.classList.add('show');
|
|
3717
|
+
}
|
|
3718
|
+
document.getElementById('btn-skills-remote-refresh')?.addEventListener('click', loadSkillsRemote);
|
|
3719
|
+
|
|
3418
3720
|
// Initial load
|
|
3419
3721
|
loadJobs();
|
|
3420
3722
|
</script>
|