@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.
Files changed (86) hide show
  1. package/README.md +4 -0
  2. package/README_zh.md +4 -0
  3. package/app/app/api/ask/route.ts +12 -0
  4. package/app/app/api/file/route.ts +9 -0
  5. package/app/app/api/mcp/agents/route.ts +27 -1
  6. package/app/app/api/skills/route.ts +18 -2
  7. package/app/app/api/tree-version/route.ts +8 -0
  8. package/app/components/ActivityBar.tsx +2 -2
  9. package/app/components/Backlinks.tsx +5 -5
  10. package/app/components/CreateSpaceModal.tsx +3 -2
  11. package/app/components/DirPicker.tsx +1 -1
  12. package/app/components/DirView.tsx +2 -3
  13. package/app/components/EditorWrapper.tsx +3 -3
  14. package/app/components/FileTree.tsx +25 -10
  15. package/app/components/GuideCard.tsx +4 -4
  16. package/app/components/HomeContent.tsx +6 -11
  17. package/app/components/MarkdownView.tsx +2 -2
  18. package/app/components/OnboardingView.tsx +1 -1
  19. package/app/components/Panel.tsx +1 -1
  20. package/app/components/RightAgentDetailPanel.tsx +1 -1
  21. package/app/components/RightAskPanel.tsx +1 -1
  22. package/app/components/SearchModal.tsx +10 -2
  23. package/app/components/SidebarLayout.tsx +35 -10
  24. package/app/components/ThemeToggle.tsx +1 -1
  25. package/app/components/agents/AgentDetailContent.tsx +454 -59
  26. package/app/components/agents/AgentsContentPage.tsx +70 -5
  27. package/app/components/agents/AgentsMcpSection.tsx +474 -159
  28. package/app/components/agents/AgentsOverviewSection.tsx +418 -59
  29. package/app/components/agents/AgentsPrimitives.tsx +335 -0
  30. package/app/components/agents/AgentsSkillsSection.tsx +739 -121
  31. package/app/components/agents/SkillDetailPopover.tsx +416 -0
  32. package/app/components/agents/agents-content-model.ts +292 -10
  33. package/app/components/ask/AskContent.tsx +34 -5
  34. package/app/components/ask/FileChip.tsx +1 -0
  35. package/app/components/ask/MentionPopover.tsx +13 -1
  36. package/app/components/ask/MessageList.tsx +5 -7
  37. package/app/components/ask/ToolCallBlock.tsx +4 -4
  38. package/app/components/changes/ChangesBanner.tsx +1 -2
  39. package/app/components/echo/EchoHero.tsx +10 -24
  40. package/app/components/echo/EchoInsightCollapsible.tsx +52 -43
  41. package/app/components/echo/EchoPageSections.tsx +13 -9
  42. package/app/components/echo/EchoSegmentNav.tsx +14 -11
  43. package/app/components/echo/EchoSegmentPageClient.tsx +64 -43
  44. package/app/components/explore/ExploreContent.tsx +3 -7
  45. package/app/components/explore/UseCaseCard.tsx +4 -15
  46. package/app/components/panels/AgentsPanel.tsx +12 -104
  47. package/app/components/panels/AgentsPanelAgentDetail.tsx +2 -2
  48. package/app/components/panels/AgentsPanelAgentGroups.tsx +3 -7
  49. package/app/components/panels/AgentsPanelAgentListRow.tsx +9 -11
  50. package/app/components/panels/EchoPanel.tsx +8 -10
  51. package/app/components/panels/PanelNavRow.tsx +9 -2
  52. package/app/components/panels/PluginsPanel.tsx +2 -2
  53. package/app/components/renderers/agent-inspector/AgentInspectorRenderer.tsx +30 -8
  54. package/app/components/renderers/agent-inspector/manifest.ts +3 -3
  55. package/app/components/renderers/todo/manifest.ts +1 -0
  56. package/app/components/settings/AiTab.tsx +3 -3
  57. package/app/components/settings/AppearanceTab.tsx +2 -2
  58. package/app/components/settings/KnowledgeTab.tsx +3 -3
  59. package/app/components/settings/McpAgentInstall.tsx +3 -6
  60. package/app/components/settings/McpSkillCreateForm.tsx +2 -3
  61. package/app/components/settings/McpSkillRow.tsx +2 -3
  62. package/app/components/settings/McpSkillsSection.tsx +2 -2
  63. package/app/components/settings/McpTab.tsx +12 -13
  64. package/app/components/settings/MonitoringTab.tsx +13 -13
  65. package/app/components/settings/PluginsTab.tsx +2 -2
  66. package/app/components/settings/Primitives.tsx +3 -4
  67. package/app/components/settings/SettingsContent.tsx +3 -3
  68. package/app/components/settings/SyncTab.tsx +11 -17
  69. package/app/components/settings/UpdateTab.tsx +18 -21
  70. package/app/components/settings/types.ts +14 -0
  71. package/app/components/setup/StepKB.tsx +1 -1
  72. package/app/hooks/useMcpData.tsx +4 -2
  73. package/app/hooks/useMention.ts +25 -8
  74. package/app/lib/agent/log.ts +15 -18
  75. package/app/lib/agent/prompt.ts +17 -29
  76. package/app/lib/agent/stream-consumer.ts +3 -0
  77. package/app/lib/agent/to-agent-messages.ts +6 -4
  78. package/app/lib/core/agent-audit-log.ts +280 -0
  79. package/app/lib/core/index.ts +11 -0
  80. package/app/lib/fs.ts +9 -0
  81. package/app/lib/i18n-en.ts +259 -33
  82. package/app/lib/i18n-zh.ts +258 -32
  83. package/app/lib/mcp-agents.ts +231 -2
  84. package/app/lib/types.ts +2 -0
  85. package/package.json +1 -1
  86. package/scripts/migrate-agent-audit-log.js +170 -0
@@ -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
- dailyEchoTitle: '每日回响',
253
- pastYouTitle: '历史的你',
254
- intentGrowthTitle: '心向生长',
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
- '以后这里会列出路径、链接或标题里「绕回你」的笔记,点开即读。文库聚合尚在接入;若想现在就着「与我相关」整理或深聊,可用下方按钮打开 MindOS Agent。',
284
+ '路径、链接或标题指向你的笔记会浮现在这里,点击即可打开编辑。现在也可以用下方按钮打开 Agent 聊聊。',
281
285
  snapshotContinuedTitle: '草稿与未收口',
282
286
  snapshotContinuedBody:
283
- '这里将汇集未命名草稿、写到一半的稿,以及待办里尚未勾上的项。列表能力正在接入;两栏结构先帮你建立心理预期。',
284
- snapshotDailyTitle: '今天,从一小行开始',
287
+ '未命名草稿、写到一半的稿、待办里尚未勾上的项,接入文库后会汇集在此。',
288
+ snapshotDailyTitle: '从一行开始',
285
289
  snapshotDailyBody:
286
- '下方「今日一行」写在浏览器本机,离手即存。回响不必写成文章——一行就够,需要展开时再找 Agent。',
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: '在 MindOS Agent 中继续',
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
- pastYouDisabledHint: '正在连接时间与文库,稍后在此轻点即可抽读旧笔记片段。',
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: '在同一页面管理连接、技能和单 Agent 状态。',
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
- successRate7d: '7 天成功率',
345
- topSkills: '已启用技能',
346
- failedAgents: '失败最多 Agent',
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
- capabilityGroups: '能力分组',
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: '无需离开内容页即可查看该 Agent 详情。',
423
- detailNotFound: '未找到该 Agent,可能已卸载或重命名。',
648
+ detailSubtitle: '',
649
+ detailNotFound: '未找到该 Agent,可能已移除或重命名。',
424
650
  },
425
651
  shortcutPanel: {
426
652
  title: '快捷键',
@@ -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 = config[agent.key];
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.5.64",
3
+ "version": "0.5.66",
4
4
  "description": "MindOS — Human-Agent Collaborative Mind System. Local-first knowledge base that syncs your mind to all AI Agents via MCP.",
5
5
  "keywords": [
6
6
  "mindos",