@geminilight/mindos 0.5.64 → 0.5.66
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 +4 -0
- package/README_zh.md +4 -0
- package/app/app/api/ask/route.ts +12 -0
- package/app/app/api/file/route.ts +9 -0
- package/app/app/api/mcp/agents/route.ts +27 -1
- package/app/app/api/skills/route.ts +18 -2
- package/app/app/api/tree-version/route.ts +8 -0
- package/app/components/ActivityBar.tsx +2 -2
- package/app/components/Backlinks.tsx +5 -5
- package/app/components/CreateSpaceModal.tsx +3 -2
- package/app/components/DirPicker.tsx +1 -1
- package/app/components/DirView.tsx +2 -3
- package/app/components/EditorWrapper.tsx +3 -3
- package/app/components/FileTree.tsx +25 -10
- package/app/components/GuideCard.tsx +4 -4
- package/app/components/HomeContent.tsx +6 -11
- package/app/components/MarkdownView.tsx +2 -2
- package/app/components/OnboardingView.tsx +1 -1
- package/app/components/Panel.tsx +1 -1
- package/app/components/RightAgentDetailPanel.tsx +1 -1
- package/app/components/RightAskPanel.tsx +1 -1
- package/app/components/SearchModal.tsx +10 -2
- package/app/components/SidebarLayout.tsx +35 -10
- package/app/components/ThemeToggle.tsx +1 -1
- package/app/components/agents/AgentDetailContent.tsx +454 -59
- package/app/components/agents/AgentsContentPage.tsx +70 -5
- package/app/components/agents/AgentsMcpSection.tsx +474 -159
- package/app/components/agents/AgentsOverviewSection.tsx +418 -59
- package/app/components/agents/AgentsPrimitives.tsx +335 -0
- package/app/components/agents/AgentsSkillsSection.tsx +739 -121
- package/app/components/agents/SkillDetailPopover.tsx +416 -0
- package/app/components/agents/agents-content-model.ts +292 -10
- package/app/components/ask/AskContent.tsx +34 -5
- package/app/components/ask/FileChip.tsx +1 -0
- package/app/components/ask/MentionPopover.tsx +13 -1
- package/app/components/ask/MessageList.tsx +5 -7
- package/app/components/ask/ToolCallBlock.tsx +4 -4
- package/app/components/changes/ChangesBanner.tsx +1 -2
- package/app/components/echo/EchoHero.tsx +10 -24
- package/app/components/echo/EchoInsightCollapsible.tsx +52 -43
- package/app/components/echo/EchoPageSections.tsx +13 -9
- package/app/components/echo/EchoSegmentNav.tsx +14 -11
- package/app/components/echo/EchoSegmentPageClient.tsx +64 -43
- package/app/components/explore/ExploreContent.tsx +3 -7
- package/app/components/explore/UseCaseCard.tsx +4 -15
- package/app/components/panels/AgentsPanel.tsx +12 -104
- package/app/components/panels/AgentsPanelAgentDetail.tsx +2 -2
- package/app/components/panels/AgentsPanelAgentGroups.tsx +3 -7
- package/app/components/panels/AgentsPanelAgentListRow.tsx +9 -11
- package/app/components/panels/EchoPanel.tsx +8 -10
- package/app/components/panels/PanelNavRow.tsx +9 -2
- package/app/components/panels/PluginsPanel.tsx +2 -2
- package/app/components/renderers/agent-inspector/AgentInspectorRenderer.tsx +30 -8
- package/app/components/renderers/agent-inspector/manifest.ts +3 -3
- package/app/components/renderers/todo/manifest.ts +1 -0
- package/app/components/settings/AiTab.tsx +3 -3
- package/app/components/settings/AppearanceTab.tsx +2 -2
- package/app/components/settings/KnowledgeTab.tsx +3 -3
- package/app/components/settings/McpAgentInstall.tsx +3 -6
- package/app/components/settings/McpSkillCreateForm.tsx +2 -3
- package/app/components/settings/McpSkillRow.tsx +2 -3
- package/app/components/settings/McpSkillsSection.tsx +2 -2
- package/app/components/settings/McpTab.tsx +12 -13
- package/app/components/settings/MonitoringTab.tsx +13 -13
- package/app/components/settings/PluginsTab.tsx +2 -2
- package/app/components/settings/Primitives.tsx +3 -4
- package/app/components/settings/SettingsContent.tsx +3 -3
- package/app/components/settings/SyncTab.tsx +11 -17
- package/app/components/settings/UpdateTab.tsx +18 -21
- package/app/components/settings/types.ts +14 -0
- package/app/components/setup/StepKB.tsx +1 -1
- package/app/hooks/useMcpData.tsx +4 -2
- package/app/hooks/useMention.ts +25 -8
- package/app/lib/agent/log.ts +15 -18
- package/app/lib/agent/prompt.ts +17 -29
- package/app/lib/agent/stream-consumer.ts +3 -0
- package/app/lib/agent/to-agent-messages.ts +6 -4
- package/app/lib/core/agent-audit-log.ts +280 -0
- package/app/lib/core/index.ts +11 -0
- package/app/lib/fs.ts +9 -0
- package/app/lib/i18n-en.ts +259 -33
- package/app/lib/i18n-zh.ts +258 -32
- package/app/lib/mcp-agents.ts +231 -2
- package/app/lib/types.ts +2 -0
- package/package.json +1 -1
- package/scripts/migrate-agent-audit-log.js +170 -0
package/app/lib/i18n-zh.ts
CHANGED
|
@@ -247,11 +247,16 @@ export const zh = {
|
|
|
247
247
|
},
|
|
248
248
|
echo: {
|
|
249
249
|
title: '回响',
|
|
250
|
-
aboutYouTitle: '
|
|
250
|
+
aboutYouTitle: '关于你',
|
|
251
|
+
aboutYouDesc: '指向你的笔记与线索',
|
|
251
252
|
continuedTitle: '未完待续',
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
continuedDesc: '草稿与未收口的事',
|
|
254
|
+
dailyEchoTitle: '今日',
|
|
255
|
+
dailyDesc: '一行就够',
|
|
256
|
+
pastYouTitle: '往昔',
|
|
257
|
+
pastYouDesc: '瞥见另一个时间点的自己',
|
|
258
|
+
intentGrowthTitle: '生长',
|
|
259
|
+
growthDesc: '你正在推进的方向',
|
|
255
260
|
},
|
|
256
261
|
discover: {
|
|
257
262
|
title: '探索',
|
|
@@ -269,27 +274,26 @@ export const zh = {
|
|
|
269
274
|
},
|
|
270
275
|
},
|
|
271
276
|
echoPages: {
|
|
272
|
-
breadcrumbNav: '面包屑导航',
|
|
273
277
|
parent: '回响',
|
|
274
278
|
heroKicker: '回响',
|
|
275
279
|
segmentNavAria: '回响模块',
|
|
276
280
|
snapshotBadge: '本地 · 私密',
|
|
277
281
|
factsHeading: '所见',
|
|
278
|
-
snapshotAboutYouTitle: '
|
|
282
|
+
snapshotAboutYouTitle: '线索在此汇聚',
|
|
279
283
|
snapshotAboutYouBody:
|
|
280
|
-
'
|
|
284
|
+
'路径、链接或标题指向你的笔记会浮现在这里,点击即可打开编辑。现在也可以用下方按钮打开 Agent 聊聊。',
|
|
281
285
|
snapshotContinuedTitle: '草稿与未收口',
|
|
282
286
|
snapshotContinuedBody:
|
|
283
|
-
'
|
|
284
|
-
snapshotDailyTitle: '
|
|
287
|
+
'未命名草稿、写到一半的稿、待办里尚未勾上的项,接入文库后会汇集在此。',
|
|
288
|
+
snapshotDailyTitle: '从一行开始',
|
|
285
289
|
snapshotDailyBody:
|
|
286
|
-
'
|
|
287
|
-
snapshotPastYouTitle: '
|
|
290
|
+
'离手即存,写在浏览器本机。一行就够——想展开时再找 Agent。',
|
|
291
|
+
snapshotPastYouTitle: '温和地一瞥',
|
|
288
292
|
snapshotPastYouBody:
|
|
289
|
-
'
|
|
293
|
+
'从时间轴里随机浮出一篇旧笔记片段,让你瞥见那时的自己。即将上线。',
|
|
290
294
|
snapshotGrowthTitle: '意图落在这里',
|
|
291
295
|
snapshotGrowthBody:
|
|
292
|
-
'
|
|
296
|
+
'写一句此刻最想推进的方向。它只保存在本机,可随时间改写。',
|
|
293
297
|
insightTitle: '见解',
|
|
294
298
|
insightShow: '展开见解',
|
|
295
299
|
insightHide: '收起见解',
|
|
@@ -300,30 +304,42 @@ export const zh = {
|
|
|
300
304
|
insightGenerating: '生成中…',
|
|
301
305
|
insightErrorPrefix: '生成失败:',
|
|
302
306
|
insightRetry: '重试',
|
|
303
|
-
continueAgent: '在
|
|
307
|
+
continueAgent: '在 Agent 中展开',
|
|
304
308
|
continuedDrafts: '草稿',
|
|
305
309
|
continuedTodos: '未收口',
|
|
306
310
|
subEmptyHint: '接入文库后,条目会出现在对应分组里。',
|
|
307
311
|
dailyLineLabel: '今日一行',
|
|
308
312
|
dailyLinePlaceholder: '写下一行轻量的文字…',
|
|
309
313
|
dailySavedNote: '已保存在本机浏览器;仅本设备可见。',
|
|
314
|
+
savedFlash: '已保存',
|
|
310
315
|
dailyAskPrefill: (line: string) =>
|
|
311
316
|
`回响 / 每日 — 围绕这一行帮我展开:\n\n${line.trim() || '(空行)'}`,
|
|
312
317
|
pastYouDrawLabel: '往日一瞥',
|
|
313
318
|
pastYouAnother: '再抽一笔',
|
|
314
|
-
|
|
319
|
+
pastYouComingSoon: '即将推出',
|
|
320
|
+
pastYouDisabledHint: '时间轴采样即将上线——届时轻点即可抽读旧笔记片段。',
|
|
315
321
|
growthIntentLabel: '当前意图',
|
|
316
322
|
growthIntentPlaceholder: '写下你正在推进的方向…',
|
|
317
323
|
growthSavedNote: '已保存在本机。',
|
|
318
|
-
aboutYouLead: '
|
|
319
|
-
continuedLead: '
|
|
320
|
-
dailyLead: '
|
|
321
|
-
pastYouLead: '
|
|
322
|
-
growthLead: '
|
|
324
|
+
aboutYouLead: '无需翻找,与你相关的笔记自然浮现。',
|
|
325
|
+
continuedLead: '草稿、待办、写到一半的念头。',
|
|
326
|
+
dailyLead: '一行就够。想展开时再找 Agent。',
|
|
327
|
+
pastYouLead: '温和地瞥见另一个时间点的自己。',
|
|
328
|
+
growthLead: '你正在推进的方向,以及它如何缓慢漂移。',
|
|
323
329
|
},
|
|
324
330
|
agentsContent: {
|
|
325
331
|
title: 'Agents',
|
|
326
|
-
subtitle: '
|
|
332
|
+
subtitle: '连接、技能与状态,一目了然。',
|
|
333
|
+
workspacePulse: {
|
|
334
|
+
title: '工作区脉搏',
|
|
335
|
+
connected: '已连接',
|
|
336
|
+
detected: '已检测',
|
|
337
|
+
notFound: '未找到',
|
|
338
|
+
risk: '风险',
|
|
339
|
+
enabledSkills: '已启用',
|
|
340
|
+
healthy: '正常',
|
|
341
|
+
needsAttention: (n: number) => `${n} 个问题`,
|
|
342
|
+
},
|
|
327
343
|
navOverview: '总览',
|
|
328
344
|
navMcp: 'MCP',
|
|
329
345
|
navSkills: 'Skills',
|
|
@@ -338,24 +354,69 @@ export const zh = {
|
|
|
338
354
|
connected: '已连接',
|
|
339
355
|
detected: '已检测',
|
|
340
356
|
notFound: '未找到',
|
|
341
|
-
riskQueue: '
|
|
342
|
-
noRisk: '
|
|
343
|
-
usagePulse: '
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
357
|
+
riskQueue: '待处理',
|
|
358
|
+
noRisk: '一切正常,暂无问题。',
|
|
359
|
+
usagePulse: '全部 Agent',
|
|
360
|
+
nextAction: '建议操作',
|
|
361
|
+
nextActionHint: '优先重连已检测的 Agent,再启用所需技能。',
|
|
362
|
+
riskLevelError: '异常',
|
|
363
|
+
riskLevelWarn: '注意',
|
|
347
364
|
na: '暂无',
|
|
365
|
+
colAgent: 'Agent',
|
|
366
|
+
colStatus: '状态',
|
|
367
|
+
colMcp: 'MCP',
|
|
368
|
+
colSkills: '技能',
|
|
369
|
+
colMode: '模式',
|
|
370
|
+
colRuntime: '运行时',
|
|
371
|
+
pulseMcp: 'MCP',
|
|
372
|
+
pulseTools: '工具数',
|
|
373
|
+
mcpOffline: '离线',
|
|
374
|
+
toolsUnit: (n: number) => `${n} 个工具`,
|
|
375
|
+
enabledUnit: (n: number) => `${n} 已启用`,
|
|
376
|
+
agentCount: (n: number) => `${n} 个 Agent`,
|
|
377
|
+
runtimeActive: '活跃',
|
|
348
378
|
},
|
|
349
379
|
mcp: {
|
|
350
|
-
title: 'MCP
|
|
380
|
+
title: 'MCP 连接',
|
|
351
381
|
refresh: '刷新',
|
|
352
|
-
connectionGraph: '
|
|
382
|
+
connectionGraph: '跨 Agent 服务器连接',
|
|
353
383
|
tabs: {
|
|
354
384
|
manage: '管理',
|
|
355
385
|
topology: '图谱',
|
|
386
|
+
byAgent: '按 Agent 查看',
|
|
387
|
+
byServer: '按 MCP Server 查看',
|
|
356
388
|
},
|
|
357
389
|
searchPlaceholder: '搜索 Agent...',
|
|
390
|
+
installMindos: '安装 MindOS MCP',
|
|
391
|
+
installed: '已安装',
|
|
392
|
+
mcpServerLabel: 'MCP Server',
|
|
393
|
+
searchServersPlaceholder: '搜索 MCP server...',
|
|
394
|
+
serverAgentCount: (n: number) => `${n} 个 Agent`,
|
|
358
395
|
emptyState: '当前筛选条件下没有匹配的 Agent。',
|
|
396
|
+
resultCount: (n: number) => `${n} 个 Agent`,
|
|
397
|
+
filteredSummaryTitle: '筛选结果状态摘要',
|
|
398
|
+
filteredConnected: (n: number) => `已连接:${n}`,
|
|
399
|
+
filteredDetected: (n: number) => `已检测:${n}`,
|
|
400
|
+
filteredNotFound: (n: number) => `未找到:${n}`,
|
|
401
|
+
crossAgentServersTitle: 'MCP 服务器',
|
|
402
|
+
crossAgentServersEmpty: '暂未检测到 MCP 服务器。',
|
|
403
|
+
crossAgentServerAgents: (names: string) => `使用者:${names}`,
|
|
404
|
+
configVisibilityTitle: '配置信息',
|
|
405
|
+
hiddenRootDetected: (n: number, total: number) => `隐藏目录:${n}/${total}`,
|
|
406
|
+
runtimeSignalDetected: (n: number, total: number) => `运行信号:${n}/${total}`,
|
|
407
|
+
riskQueueTitle: '待处理',
|
|
408
|
+
riskMcpStopped: 'MCP 服务未运行。',
|
|
409
|
+
riskDetected: (n: number) => `${n} 个已检测 Agent 待配置。`,
|
|
410
|
+
riskNotFound: (n: number) => `${n} 个 Agent 未在本机检测到。`,
|
|
411
|
+
bulkReconnectFiltered: '全部重连',
|
|
412
|
+
bulkRunning: '正在批量重连...',
|
|
413
|
+
bulkSummary: (ok: number, failed: number) => `重连成功 ${ok} 个,失败 ${failed} 个。`,
|
|
414
|
+
transportFilters: {
|
|
415
|
+
all: '全部传输',
|
|
416
|
+
stdio: 'stdio',
|
|
417
|
+
http: 'http',
|
|
418
|
+
other: '其他',
|
|
419
|
+
},
|
|
359
420
|
filters: {
|
|
360
421
|
all: '全部',
|
|
361
422
|
connected: '已连接',
|
|
@@ -374,18 +435,93 @@ export const zh = {
|
|
|
374
435
|
testConnection: '测试连接',
|
|
375
436
|
reconnect: '重连',
|
|
376
437
|
},
|
|
438
|
+
addAgent: '添加',
|
|
439
|
+
removeFromServer: '移除',
|
|
440
|
+
confirmRemoveTitle: '从服务器移除?',
|
|
441
|
+
confirmRemoveMessage: (agent: string, server: string) => `将"${agent}"从"${server}"移除?需编辑 Agent 配置文件完成操作。`,
|
|
442
|
+
cancel: '取消',
|
|
443
|
+
noAvailableAgents: '所有 Agent 均已添加。',
|
|
444
|
+
manualRemoveHint: '已标记移除,请编辑 Agent 配置文件完成操作。',
|
|
445
|
+
reconnectAllInServer: '全部重连',
|
|
446
|
+
reconnectAllRunning: '正在重连...',
|
|
447
|
+
reconnectAllDone: (ok: number, failed: number) => `完成:${ok} 已重连${failed > 0 ? `,${failed} 失败` : ''}。`,
|
|
448
|
+
serverTransport: (t: string) => `传输:${t}`,
|
|
377
449
|
},
|
|
378
450
|
skills: {
|
|
379
451
|
title: 'Skills',
|
|
380
|
-
|
|
452
|
+
summaryTitle: '技能状态',
|
|
453
|
+
summaryEnabled: (n: number) => `已启用:${n}`,
|
|
454
|
+
summaryDisabled: (n: number) => `已禁用:${n}`,
|
|
455
|
+
summaryAttention: (n: number) => `需关注:${n}`,
|
|
456
|
+
crossAgentSkillsTitle: '已安装技能',
|
|
457
|
+
crossAgentSkillsEmpty: '暂未检测到已安装技能。',
|
|
458
|
+
crossAgentSkillAgents: (names: string) => `安装于:${names}`,
|
|
459
|
+
capabilityGroups: '跨 Agent 技能管理',
|
|
460
|
+
registrySummaryTitle: '技能注册表',
|
|
461
|
+
registryUniversal: (n: number) => `Universal:${n}`,
|
|
462
|
+
registryAdditional: (n: number) => `Additional:${n}`,
|
|
463
|
+
registryUnsupported: (n: number) => `Unsupported:${n}`,
|
|
464
|
+
registryHiddenRoots: (n: number, total: number) => `隐藏目录:${n}/${total}`,
|
|
381
465
|
tabs: {
|
|
382
466
|
manage: '管理',
|
|
383
467
|
matrix: '矩阵',
|
|
468
|
+
bySkill: '按 Skill 查看',
|
|
469
|
+
byAgent: '按 Agent 查看',
|
|
384
470
|
},
|
|
385
471
|
searchPlaceholder: '搜索技能...',
|
|
472
|
+
agentSkillMode: 'Skill 模式',
|
|
473
|
+
agentMcpServers: 'MCP Servers',
|
|
474
|
+
agentNativeSkills: '原生 Skills',
|
|
475
|
+
agentMindosSkills: 'MindOS Skills',
|
|
476
|
+
noAgentsYet: '尚未检测到任何 Agent。',
|
|
477
|
+
moreSkills: (n: number) => `另有 ${n} 个`,
|
|
386
478
|
sourceAll: '全部',
|
|
387
479
|
sourceBuiltin: '内置',
|
|
388
480
|
sourceUser: '自定义',
|
|
481
|
+
sourceNative: '原生',
|
|
482
|
+
summaryNative: (n: number) => `原生:${n}`,
|
|
483
|
+
statusAll: '全部状态',
|
|
484
|
+
statusEnabled: '已启用',
|
|
485
|
+
statusDisabled: '已禁用',
|
|
486
|
+
statusAttention: '需关注',
|
|
487
|
+
capabilityAll: '全部能力',
|
|
488
|
+
bulkEnableFiltered: '全部启用',
|
|
489
|
+
bulkDisableFiltered: '全部停用',
|
|
490
|
+
bulkRunning: '正在应用变更...',
|
|
491
|
+
bulkNoChanges: '当前无需变更。',
|
|
492
|
+
bulkAllSucceeded: (n: number) => `已更新 ${n} 个技能。`,
|
|
493
|
+
bulkPartialFailed: (ok: number, failed: number) => `已更新 ${ok} 个,失败 ${failed} 个。`,
|
|
494
|
+
resultCount: (n: number) => `${n} 个技能`,
|
|
495
|
+
matrixAgentFocusLabel: 'Agent 聚焦',
|
|
496
|
+
matrixAgentFocusAll: '全部 Agent',
|
|
497
|
+
matrixColumnSkill: '技能',
|
|
498
|
+
matrixEnabled: '已启用',
|
|
499
|
+
matrixDisabled: '已禁用',
|
|
500
|
+
matrixUnsupported: '不支持',
|
|
501
|
+
matrixNoAgents: '当前无可用于矩阵的 Agent。',
|
|
502
|
+
noSkillsMatchFilter: '当前筛选条件下无技能。',
|
|
503
|
+
matrixEmpty: '当前筛选条件下无技能。',
|
|
504
|
+
addAgentToSkill: '添加',
|
|
505
|
+
removeAgentFromSkill: '移除',
|
|
506
|
+
confirmRemoveAgentTitle: '从技能移除?',
|
|
507
|
+
confirmRemoveAgentMessage: (agent: string, skill: string) => `将"${agent}"从"${skill}"移除?需编辑 Agent 配置文件完成操作。`,
|
|
508
|
+
cancelSkillAction: '取消',
|
|
509
|
+
noAvailableAgentsForSkill: '所有 Agent 均已拥有此技能。',
|
|
510
|
+
manualSkillHint: '已标记,请编辑 Agent 配置文件完成操作。',
|
|
511
|
+
skillDescription: '描述',
|
|
512
|
+
skillNoDescription: '暂无描述。',
|
|
513
|
+
skillDeleteAction: '删除',
|
|
514
|
+
confirmDeleteSkillTitle: '删除技能?',
|
|
515
|
+
confirmDeleteSkillMessage: (name: string) => `确认永久删除技能"${name}"?此操作不可撤销。`,
|
|
516
|
+
skillDeleted: '技能已删除。',
|
|
517
|
+
skillDeleteFailed: '删除技能失败。',
|
|
518
|
+
copyInstallCmd: '复制安装命令',
|
|
519
|
+
installCmdCopied: '已复制!',
|
|
520
|
+
skillAgentCount: (n: number) => `${n} 个 Agent`,
|
|
521
|
+
quickStatsMcp: (n: number) => `${n} MCP`,
|
|
522
|
+
quickStatsSkills: (n: number) => `${n} 技能`,
|
|
523
|
+
showAllNative: (n: number) => `展开全部 ${n} 项`,
|
|
524
|
+
collapseNative: '收起',
|
|
389
525
|
emptyGroup: '该分组暂无技能。',
|
|
390
526
|
groupLabels: {
|
|
391
527
|
research: '研究',
|
|
@@ -394,12 +530,46 @@ export const zh = {
|
|
|
394
530
|
ops: '运维',
|
|
395
531
|
memory: '记忆',
|
|
396
532
|
},
|
|
533
|
+
skillPopover: {
|
|
534
|
+
close: '关闭',
|
|
535
|
+
source: '来源',
|
|
536
|
+
sourceBuiltin: '内置',
|
|
537
|
+
sourceUser: '自定义',
|
|
538
|
+
sourceNative: '原生',
|
|
539
|
+
capability: '能力类型',
|
|
540
|
+
path: '文件路径',
|
|
541
|
+
enabled: '已启用',
|
|
542
|
+
disabled: '已禁用',
|
|
543
|
+
agents: 'Agent',
|
|
544
|
+
noAgents: '暂无 Agent 拥有此技能。',
|
|
545
|
+
content: '技能内容',
|
|
546
|
+
loading: '加载中…',
|
|
547
|
+
loadFailed: '加载技能内容失败。',
|
|
548
|
+
retry: '重试',
|
|
549
|
+
copyContent: '复制',
|
|
550
|
+
copied: '已复制!',
|
|
551
|
+
noDescription: '暂无描述。',
|
|
552
|
+
deleteSkill: '删除',
|
|
553
|
+
confirmDeleteTitle: '删除技能?',
|
|
554
|
+
confirmDeleteMessage: (name: string) => `确认永久删除技能"${name}"?此操作不可撤销。`,
|
|
555
|
+
confirmDeleteAction: '删除',
|
|
556
|
+
cancelAction: '取消',
|
|
557
|
+
deleted: '技能已删除。',
|
|
558
|
+
deleteFailed: '删除技能失败。',
|
|
559
|
+
},
|
|
397
560
|
},
|
|
398
561
|
detail: {
|
|
562
|
+
healthStripTitle: '状态',
|
|
563
|
+
healthConnected: '已连接',
|
|
564
|
+
healthInstalled: 'MCP 已安装',
|
|
565
|
+
healthRuntimeSignals: '运行信号',
|
|
566
|
+
healthConfiguredServers: '已配置 servers',
|
|
567
|
+
healthInstalledSkills: '原生已安装 skills',
|
|
399
568
|
identity: '身份',
|
|
400
569
|
connection: '连接',
|
|
401
570
|
capabilities: '能力画像',
|
|
402
571
|
skillAssignments: '技能分配',
|
|
572
|
+
runtimeSignals: '运行与配置信号',
|
|
403
573
|
recentActivity: '最近活动',
|
|
404
574
|
spaceReach: '空间触达',
|
|
405
575
|
agentKey: 'Agent Key',
|
|
@@ -413,14 +583,70 @@ export const zh = {
|
|
|
413
583
|
projectScope: '项目范围',
|
|
414
584
|
globalScope: '全局范围',
|
|
415
585
|
format: '配置格式',
|
|
586
|
+
skillMode: 'Skill 模式',
|
|
587
|
+
hiddenRoot: '隐藏目录路径',
|
|
588
|
+
hiddenRootPresent: '隐藏目录',
|
|
589
|
+
conversationSignal: '对话',
|
|
590
|
+
usageSignal: '用量',
|
|
591
|
+
lastActivityAt: '最近活跃',
|
|
592
|
+
skillsAll: '全部 Skills',
|
|
593
|
+
skillsEnabled: '已启用 Skills',
|
|
594
|
+
skillsSourceBuiltin: '内置',
|
|
595
|
+
skillsSourceUser: '自定义',
|
|
596
|
+
skillsSearchPlaceholder: '搜索全部已配置 Skills...',
|
|
597
|
+
skillsFilterAll: '全部',
|
|
598
|
+
skillsFilterBuiltin: '内置',
|
|
599
|
+
skillsFilterUser: '自定义',
|
|
600
|
+
skillEnable: '启用',
|
|
601
|
+
skillDisable: '禁用',
|
|
602
|
+
skillEdit: '编辑',
|
|
603
|
+
skillSave: '保存',
|
|
604
|
+
skillCancel: '取消',
|
|
605
|
+
skillActionLoading: '处理中...',
|
|
606
|
+
skillReadFailed: '读取 Skill 内容失败。',
|
|
607
|
+
skillSaveFailed: '保存 Skill 内容失败。',
|
|
608
|
+
mcpManagement: 'MCP 管理',
|
|
609
|
+
mcpInstalled: '已安装',
|
|
610
|
+
mcpScope: '当前范围',
|
|
611
|
+
mcpConfigPath: '配置路径',
|
|
612
|
+
mcpTargetScope: '目标范围',
|
|
613
|
+
mcpTargetTransport: '目标传输',
|
|
614
|
+
mcpScopeProject: '项目',
|
|
615
|
+
mcpScopeGlobal: '全局',
|
|
616
|
+
mcpCopySnippet: '复制片段',
|
|
617
|
+
mcpCopied: '已复制',
|
|
618
|
+
mcpRefresh: '刷新状态',
|
|
619
|
+
mcpReconnect: '应用 MCP 配置',
|
|
620
|
+
mcpApplying: '正在应用 MCP 配置...',
|
|
621
|
+
mcpApplySuccess: 'MCP 配置已应用。',
|
|
622
|
+
mcpApplyFailed: '应用 MCP 配置失败。',
|
|
623
|
+
nativeInstalledSkills: '已安装技能',
|
|
624
|
+
nativeInstalledSkillsCount: (n: number) => `检测到 ${n} 个`,
|
|
625
|
+
nativeInstalledSkillsEmpty: '暂未检测到已安装技能。',
|
|
626
|
+
nativeInstalledSkillsMore: (n: number) => `另有 ${n} 个`,
|
|
627
|
+
configuredMcpServers: 'MCP 服务器',
|
|
628
|
+
configuredMcpServersCount: (n: number) => `检测到 ${n} 个`,
|
|
629
|
+
configuredMcpServersEmpty: '暂未配置 MCP 服务器。',
|
|
630
|
+
configuredMcpServersMore: (n: number) => `另有 ${n} 个`,
|
|
416
631
|
yes: '是',
|
|
417
632
|
no: '否',
|
|
418
633
|
noSkills: '暂无启用技能。',
|
|
419
634
|
noActivity: '暂无活动记录。',
|
|
420
635
|
noSpaceReach: '暂无空间触达数据。',
|
|
636
|
+
skillDelete: '删除',
|
|
637
|
+
skillDeleteConfirm: (name: string) => `确认删除技能"${name}"?此操作不可撤销。`,
|
|
638
|
+
skillDeleteSuccess: '技能已删除。',
|
|
639
|
+
skillDeleteFailed: '删除技能失败。',
|
|
640
|
+
mcpServerAdd: '添加 MCP 服务器',
|
|
641
|
+
mcpServerRemove: '移除',
|
|
642
|
+
mcpServerRemoveConfirm: (name: string) => `从该 Agent 移除"${name}"?需编辑配置文件完成操作。`,
|
|
643
|
+
mcpServerHint: '已标记,请编辑 Agent 配置文件完成操作。',
|
|
644
|
+
mcpReconnectAll: '全部重连',
|
|
645
|
+
mcpReconnectAllRunning: '正在重连...',
|
|
646
|
+
mcpReconnectAllDone: (ok: number, failed: number) => `已重连 ${ok}${failed > 0 ? `,失败 ${failed}` : ''}。`,
|
|
421
647
|
},
|
|
422
|
-
detailSubtitle: '
|
|
423
|
-
detailNotFound: '未找到该 Agent
|
|
648
|
+
detailSubtitle: '',
|
|
649
|
+
detailNotFound: '未找到该 Agent,可能已移除或重命名。',
|
|
424
650
|
},
|
|
425
651
|
shortcutPanel: {
|
|
426
652
|
title: '快捷键',
|
package/app/lib/mcp-agents.ts
CHANGED
|
@@ -257,6 +257,233 @@ export const SKILL_AGENT_REGISTRY: Record<string, SkillAgentRegistration> = {
|
|
|
257
257
|
'codex': { mode: 'universal' },
|
|
258
258
|
};
|
|
259
259
|
|
|
260
|
+
export interface SkillWorkspaceProfile {
|
|
261
|
+
mode: SkillInstallMode;
|
|
262
|
+
skillAgentName?: string;
|
|
263
|
+
workspacePath: string;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export interface AgentRuntimeSignals {
|
|
267
|
+
hiddenRootPath: string;
|
|
268
|
+
hiddenRootPresent: boolean;
|
|
269
|
+
conversationSignal: boolean;
|
|
270
|
+
usageSignal: boolean;
|
|
271
|
+
lastActivityAt?: string;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export interface AgentConfiguredMcpServers {
|
|
275
|
+
servers: string[];
|
|
276
|
+
sources: string[];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export interface AgentInstalledSkills {
|
|
280
|
+
skills: string[];
|
|
281
|
+
sourcePath: string;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function resolveHiddenRootPath(agent: AgentDef): string {
|
|
285
|
+
const dirs = agent.presenceDirs ?? [];
|
|
286
|
+
for (const entry of dirs) {
|
|
287
|
+
const abs = expandHome(entry);
|
|
288
|
+
if (!fs.existsSync(abs)) continue;
|
|
289
|
+
try {
|
|
290
|
+
const stat = fs.statSync(abs);
|
|
291
|
+
if (stat.isDirectory()) return abs;
|
|
292
|
+
if (stat.isFile()) return path.dirname(abs);
|
|
293
|
+
} catch {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return path.dirname(expandHome(agent.global));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function readDirectoryEntries(dir: string): fs.Dirent[] {
|
|
301
|
+
try {
|
|
302
|
+
return fs.readdirSync(dir, { withFileTypes: true });
|
|
303
|
+
} catch {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function detectSignalsFromName(name: string): { conversation: boolean; usage: boolean } {
|
|
309
|
+
const lowered = name.toLowerCase();
|
|
310
|
+
return {
|
|
311
|
+
conversation: /(session|history|conversation|chat|transcript)/.test(lowered),
|
|
312
|
+
usage: /(usage|token|cost|billing|metric|analytics)/.test(lowered),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function readNestedRecord(obj: Record<string, unknown>, nestedPath: string): Record<string, unknown> | null {
|
|
317
|
+
const parts = nestedPath.split('.').filter(Boolean);
|
|
318
|
+
let current: unknown = obj;
|
|
319
|
+
for (const part of parts) {
|
|
320
|
+
if (!current || typeof current !== 'object') return null;
|
|
321
|
+
current = (current as Record<string, unknown>)[part];
|
|
322
|
+
}
|
|
323
|
+
if (!current || typeof current !== 'object') return null;
|
|
324
|
+
return current as Record<string, unknown>;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function parseJsonServerNames(content: string, configKey: string, globalNestedKey?: string): string[] {
|
|
328
|
+
try {
|
|
329
|
+
const config = parseJsonc(content) as Record<string, unknown>;
|
|
330
|
+
const section = globalNestedKey
|
|
331
|
+
? readNestedRecord(config, globalNestedKey)
|
|
332
|
+
: (config[configKey] as unknown);
|
|
333
|
+
if (!section || typeof section !== 'object') return [];
|
|
334
|
+
return Object.keys(section as Record<string, unknown>);
|
|
335
|
+
} catch {
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function parseTomlServerNames(content: string, sectionKey: string): string[] {
|
|
341
|
+
const names = new Set<string>();
|
|
342
|
+
const lines = content.split('\n');
|
|
343
|
+
let inRootSection = false;
|
|
344
|
+
const sectionPrefix = `${sectionKey}.`;
|
|
345
|
+
for (const line of lines) {
|
|
346
|
+
const trimmed = line.trim();
|
|
347
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
348
|
+
if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
|
|
349
|
+
const section = trimmed.slice(1, -1).trim();
|
|
350
|
+
inRootSection = section === sectionKey;
|
|
351
|
+
if (section.startsWith(sectionPrefix)) {
|
|
352
|
+
const name = section.slice(sectionPrefix.length).split('.')[0]?.trim();
|
|
353
|
+
if (name) names.add(name);
|
|
354
|
+
}
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if (!inRootSection) continue;
|
|
358
|
+
const kv = trimmed.match(/^([a-zA-Z0-9_-]+)\s*=\s*/);
|
|
359
|
+
if (!kv) continue;
|
|
360
|
+
const name = kv[1]?.trim();
|
|
361
|
+
if (name) names.add(name);
|
|
362
|
+
}
|
|
363
|
+
return [...names];
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function resolveSkillWorkspaceProfile(agentKey: string): SkillWorkspaceProfile {
|
|
367
|
+
const registration = SKILL_AGENT_REGISTRY[agentKey] ?? { mode: 'unsupported' as const };
|
|
368
|
+
if (registration.mode === 'universal') {
|
|
369
|
+
return { mode: registration.mode, workspacePath: expandHome('~/.agents/skills') };
|
|
370
|
+
}
|
|
371
|
+
const agent = MCP_AGENTS[agentKey];
|
|
372
|
+
const root = agent ? resolveHiddenRootPath(agent) : expandHome('~/.agents');
|
|
373
|
+
const workspacePath = path.join(root, 'skills');
|
|
374
|
+
return {
|
|
375
|
+
mode: registration.mode,
|
|
376
|
+
skillAgentName: registration.skillAgentName,
|
|
377
|
+
workspacePath,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export function detectAgentConfiguredMcpServers(agentKey: string): AgentConfiguredMcpServers {
|
|
382
|
+
const agent = MCP_AGENTS[agentKey];
|
|
383
|
+
if (!agent) return { servers: [], sources: [] };
|
|
384
|
+
const serverSet = new Set<string>();
|
|
385
|
+
const sources: string[] = [];
|
|
386
|
+
for (const [scopeType, cfgPath] of [['global', agent.global], ['project', agent.project]] as Array<[string, string | null]>) {
|
|
387
|
+
if (!cfgPath) continue;
|
|
388
|
+
const absPath = expandHome(cfgPath);
|
|
389
|
+
if (!fs.existsSync(absPath)) continue;
|
|
390
|
+
try {
|
|
391
|
+
const content = fs.readFileSync(absPath, 'utf-8');
|
|
392
|
+
const nestedPath = scopeType === 'global' ? agent.globalNestedKey : undefined;
|
|
393
|
+
const names =
|
|
394
|
+
agent.format === 'toml'
|
|
395
|
+
? parseTomlServerNames(content, agent.key)
|
|
396
|
+
: parseJsonServerNames(content, agent.key, nestedPath);
|
|
397
|
+
for (const name of names) serverSet.add(name);
|
|
398
|
+
sources.push(`${scopeType}:${cfgPath}`);
|
|
399
|
+
} catch {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
servers: [...serverSet].sort((a, b) => a.localeCompare(b)),
|
|
405
|
+
sources,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export function detectAgentInstalledSkills(agentKey: string): AgentInstalledSkills {
|
|
410
|
+
const profile = resolveSkillWorkspaceProfile(agentKey);
|
|
411
|
+
const sourcePath = profile.workspacePath;
|
|
412
|
+
if (!fs.existsSync(sourcePath)) return { skills: [], sourcePath };
|
|
413
|
+
let entries: fs.Dirent[] = [];
|
|
414
|
+
try {
|
|
415
|
+
entries = fs.readdirSync(sourcePath, { withFileTypes: true });
|
|
416
|
+
} catch {
|
|
417
|
+
return { skills: [], sourcePath };
|
|
418
|
+
}
|
|
419
|
+
const skills = entries
|
|
420
|
+
.filter((entry) => (entry.isDirectory() || entry.isSymbolicLink()) && !entry.name.startsWith('.'))
|
|
421
|
+
.map((entry) => entry.name)
|
|
422
|
+
.sort((a, b) => a.localeCompare(b));
|
|
423
|
+
return { skills, sourcePath };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export function detectAgentRuntimeSignals(agentKey: string): AgentRuntimeSignals {
|
|
427
|
+
const agent = MCP_AGENTS[agentKey];
|
|
428
|
+
if (!agent) {
|
|
429
|
+
return {
|
|
430
|
+
hiddenRootPath: '',
|
|
431
|
+
hiddenRootPresent: false,
|
|
432
|
+
conversationSignal: false,
|
|
433
|
+
usageSignal: false,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
const hiddenRootPath = resolveHiddenRootPath(agent);
|
|
437
|
+
if (!fs.existsSync(hiddenRootPath)) {
|
|
438
|
+
return {
|
|
439
|
+
hiddenRootPath,
|
|
440
|
+
hiddenRootPresent: false,
|
|
441
|
+
conversationSignal: false,
|
|
442
|
+
usageSignal: false,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const maxDepth = 3;
|
|
447
|
+
const maxEntries = 300;
|
|
448
|
+
let scanned = 0;
|
|
449
|
+
let conversationSignal = false;
|
|
450
|
+
let usageSignal = false;
|
|
451
|
+
let latestMtime = 0;
|
|
452
|
+
const queue: Array<{ dir: string; depth: number }> = [{ dir: hiddenRootPath, depth: 0 }];
|
|
453
|
+
|
|
454
|
+
while (queue.length > 0 && scanned < maxEntries) {
|
|
455
|
+
const current = queue.shift();
|
|
456
|
+
if (!current) break;
|
|
457
|
+
const entries = readDirectoryEntries(current.dir);
|
|
458
|
+
for (const entry of entries) {
|
|
459
|
+
if (scanned >= maxEntries) break;
|
|
460
|
+
scanned += 1;
|
|
461
|
+
if (entry.name === 'node_modules' || entry.name === '.git') continue;
|
|
462
|
+
const fullPath = path.join(current.dir, entry.name);
|
|
463
|
+
try {
|
|
464
|
+
const stat = fs.statSync(fullPath);
|
|
465
|
+
if (stat.mtimeMs > latestMtime) latestMtime = stat.mtimeMs;
|
|
466
|
+
const signals = detectSignalsFromName(entry.name);
|
|
467
|
+
if (signals.conversation) conversationSignal = true;
|
|
468
|
+
if (signals.usage) usageSignal = true;
|
|
469
|
+
if (entry.isDirectory() && current.depth < maxDepth) {
|
|
470
|
+
queue.push({ dir: fullPath, depth: current.depth + 1 });
|
|
471
|
+
}
|
|
472
|
+
} catch {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return {
|
|
479
|
+
hiddenRootPath,
|
|
480
|
+
hiddenRootPresent: true,
|
|
481
|
+
conversationSignal,
|
|
482
|
+
usageSignal,
|
|
483
|
+
lastActivityAt: latestMtime > 0 ? new Date(latestMtime).toISOString() : undefined,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
260
487
|
/* ── MindOS MCP Install Detection ──────────────────────────────────────── */
|
|
261
488
|
|
|
262
489
|
export function detectInstalled(agentKey: string): { installed: boolean; scope?: string; transport?: string; configPath?: string } {
|
|
@@ -280,9 +507,11 @@ export function detectInstalled(agentKey: string): { installed: boolean; scope?:
|
|
|
280
507
|
} else {
|
|
281
508
|
// JSON format (default)
|
|
282
509
|
const config = parseJsonc(content);
|
|
283
|
-
const servers =
|
|
510
|
+
const servers = scopeType === 'global' && agent.globalNestedKey
|
|
511
|
+
? readNestedRecord(config as Record<string, unknown>, agent.globalNestedKey)
|
|
512
|
+
: (config[agent.key] as Record<string, unknown> | undefined);
|
|
284
513
|
if (servers?.mindos) {
|
|
285
|
-
const entry = servers.mindos
|
|
514
|
+
const entry = servers.mindos as Record<string, unknown>;
|
|
286
515
|
const transport = entry.type === 'stdio' ? 'stdio' : entry.url ? 'http' : 'unknown';
|
|
287
516
|
return { installed: true, scope: scopeType, transport, configPath: cfgPath };
|
|
288
517
|
}
|
package/app/lib/types.ts
CHANGED
|
@@ -37,6 +37,8 @@ export type MessagePart = TextPart | ToolCallPart | ReasoningPart;
|
|
|
37
37
|
export interface Message {
|
|
38
38
|
role: 'user' | 'assistant';
|
|
39
39
|
content: string;
|
|
40
|
+
/** Unix timestamp in milliseconds when this message was created */
|
|
41
|
+
timestamp?: number;
|
|
40
42
|
/** Structured parts for assistant messages (tool calls + text segments) */
|
|
41
43
|
parts?: MessagePart[];
|
|
42
44
|
}
|
package/package.json
CHANGED