@geminilight/mindos 0.5.63 → 0.5.65

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 (104) 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/changes/route.ts +7 -1
  5. package/app/app/api/file/route.ts +9 -0
  6. package/app/app/api/mcp/agents/route.ts +27 -1
  7. package/app/app/api/mcp/install-skill/route.ts +9 -24
  8. package/app/app/api/skills/route.ts +18 -2
  9. package/app/app/api/tree-version/route.ts +8 -0
  10. package/app/app/layout.tsx +1 -0
  11. package/app/app/page.tsx +1 -2
  12. package/app/app/view/[...path]/ViewPageClient.tsx +0 -1
  13. package/app/components/ActivityBar.tsx +2 -2
  14. package/app/components/Backlinks.tsx +5 -5
  15. package/app/components/CreateSpaceModal.tsx +3 -2
  16. package/app/components/DirPicker.tsx +1 -1
  17. package/app/components/DirView.tsx +2 -3
  18. package/app/components/EditorWrapper.tsx +3 -3
  19. package/app/components/FileTree.tsx +25 -10
  20. package/app/components/GuideCard.tsx +4 -4
  21. package/app/components/HomeContent.tsx +44 -14
  22. package/app/components/MarkdownView.tsx +2 -2
  23. package/app/components/OnboardingView.tsx +1 -1
  24. package/app/components/Panel.tsx +1 -1
  25. package/app/components/RightAgentDetailPanel.tsx +2 -1
  26. package/app/components/RightAskPanel.tsx +1 -1
  27. package/app/components/SearchModal.tsx +10 -2
  28. package/app/components/SidebarLayout.tsx +36 -10
  29. package/app/components/ThemeToggle.tsx +1 -1
  30. package/app/components/agents/AgentDetailContent.tsx +454 -59
  31. package/app/components/agents/AgentsContentPage.tsx +89 -20
  32. package/app/components/agents/AgentsMcpSection.tsx +513 -85
  33. package/app/components/agents/AgentsOverviewSection.tsx +418 -59
  34. package/app/components/agents/AgentsPrimitives.tsx +335 -0
  35. package/app/components/agents/AgentsSkillsSection.tsx +746 -105
  36. package/app/components/agents/SkillDetailPopover.tsx +416 -0
  37. package/app/components/agents/agents-content-model.ts +308 -10
  38. package/app/components/ask/AskContent.tsx +34 -5
  39. package/app/components/ask/FileChip.tsx +1 -0
  40. package/app/components/ask/MentionPopover.tsx +13 -1
  41. package/app/components/ask/MessageList.tsx +5 -7
  42. package/app/components/ask/ToolCallBlock.tsx +4 -4
  43. package/app/components/changes/ChangesBanner.tsx +89 -13
  44. package/app/components/changes/ChangesContentPage.tsx +134 -51
  45. package/app/components/echo/EchoHero.tsx +10 -24
  46. package/app/components/echo/EchoInsightCollapsible.tsx +52 -43
  47. package/app/components/echo/EchoPageSections.tsx +13 -9
  48. package/app/components/echo/EchoSegmentNav.tsx +14 -11
  49. package/app/components/echo/EchoSegmentPageClient.tsx +64 -43
  50. package/app/components/explore/ExploreContent.tsx +3 -7
  51. package/app/components/explore/UseCaseCard.tsx +4 -15
  52. package/app/components/panels/AgentsPanel.tsx +22 -128
  53. package/app/components/panels/AgentsPanelAgentDetail.tsx +7 -6
  54. package/app/components/panels/AgentsPanelAgentGroups.tsx +8 -13
  55. package/app/components/panels/AgentsPanelAgentListRow.tsx +39 -16
  56. package/app/components/panels/AgentsPanelHubNav.tsx +12 -12
  57. package/app/components/panels/EchoPanel.tsx +8 -10
  58. package/app/components/panels/PanelNavRow.tsx +9 -2
  59. package/app/components/panels/PluginsPanel.tsx +5 -5
  60. package/app/components/renderers/agent-inspector/AgentInspectorRenderer.tsx +30 -8
  61. package/app/components/renderers/agent-inspector/manifest.ts +5 -3
  62. package/app/components/renderers/config/manifest.ts +1 -0
  63. package/app/components/renderers/csv/manifest.ts +1 -0
  64. package/app/components/renderers/todo/manifest.ts +1 -0
  65. package/app/components/settings/AiTab.tsx +3 -3
  66. package/app/components/settings/AppearanceTab.tsx +2 -2
  67. package/app/components/settings/KnowledgeTab.tsx +3 -3
  68. package/app/components/settings/McpAgentInstall.tsx +3 -6
  69. package/app/components/settings/McpSkillCreateForm.tsx +2 -3
  70. package/app/components/settings/McpSkillRow.tsx +2 -3
  71. package/app/components/settings/McpSkillsSection.tsx +2 -2
  72. package/app/components/settings/McpTab.tsx +12 -13
  73. package/app/components/settings/MonitoringTab.tsx +13 -13
  74. package/app/components/settings/PluginsTab.tsx +6 -5
  75. package/app/components/settings/Primitives.tsx +3 -4
  76. package/app/components/settings/SettingsContent.tsx +3 -3
  77. package/app/components/settings/SyncTab.tsx +11 -17
  78. package/app/components/settings/UpdateTab.tsx +18 -21
  79. package/app/components/settings/types.ts +14 -0
  80. package/app/components/setup/StepKB.tsx +1 -1
  81. package/app/hooks/useMcpData.tsx +7 -4
  82. package/app/hooks/useMention.ts +25 -8
  83. package/app/lib/agent/log.ts +15 -18
  84. package/app/lib/agent/stream-consumer.ts +3 -0
  85. package/app/lib/agent/to-agent-messages.ts +6 -4
  86. package/app/lib/core/agent-audit-log.ts +280 -0
  87. package/app/lib/core/content-changes.ts +148 -8
  88. package/app/lib/core/index.ts +11 -0
  89. package/app/lib/fs.ts +16 -1
  90. package/app/lib/i18n-en.ts +317 -36
  91. package/app/lib/i18n-zh.ts +316 -35
  92. package/app/lib/mcp-agents.ts +273 -2
  93. package/app/lib/renderers/index.ts +1 -2
  94. package/app/lib/renderers/registry.ts +10 -0
  95. package/app/lib/types.ts +2 -0
  96. package/app/next-env.d.ts +1 -1
  97. package/bin/lib/mcp-agents.js +38 -13
  98. package/package.json +1 -1
  99. package/scripts/migrate-agent-audit-log.js +170 -0
  100. package/scripts/migrate-agent-diff.js +146 -0
  101. package/scripts/setup.js +12 -17
  102. package/skills/plugin-core-builtin-migration/SKILL.md +178 -0
  103. package/app/components/renderers/diff/DiffRenderer.tsx +0 -311
  104. package/app/components/renderers/diff/manifest.ts +0 -14
@@ -1,34 +1,36 @@
1
1
  'use client';
2
2
 
3
3
  import { useState } from 'react';
4
- import { ChevronRight, Loader2 } from 'lucide-react';
4
+ import Link from 'next/link';
5
+ import { Check, ChevronRight, Loader2, RotateCw } from 'lucide-react';
5
6
  import type { AgentInfo } from '../settings/types';
7
+ import { AgentAvatar } from '../agents/AgentsPrimitives';
6
8
 
7
9
  export type AgentsPanelAgentListStatus = 'connected' | 'detected' | 'notFound';
8
10
 
9
11
  export interface AgentsPanelAgentListRowCopy {
10
12
  installing: string;
11
- install: (name: string) => string;
13
+ install: string;
14
+ installSuccess: string;
15
+ installFailed: string;
16
+ retryInstall: string;
12
17
  }
13
18
 
14
19
  export default function AgentsPanelAgentListRow({
15
20
  agent,
16
21
  agentStatus,
17
22
  selected = false,
18
- onOpenDetail,
23
+ detailHref,
19
24
  onInstallAgent,
20
25
  copy,
21
26
  }: {
22
27
  agent: AgentInfo;
23
28
  agentStatus: AgentsPanelAgentListStatus;
24
29
  selected?: boolean;
25
- onOpenDetail: () => void;
30
+ detailHref: string;
26
31
  onInstallAgent: (key: string) => Promise<boolean>;
27
32
  copy: AgentsPanelAgentListRowCopy;
28
33
  }) {
29
- const dot =
30
- agentStatus === 'connected' ? 'bg-emerald-500' : agentStatus === 'detected' ? 'bg-amber-500' : 'bg-zinc-400';
31
-
32
34
  return (
33
35
  <div
34
36
  className={`
@@ -38,12 +40,11 @@ export default function AgentsPanelAgentListRow({
38
40
  : 'border-border/70 bg-card/50 hover:border-border hover:bg-muted/25'}
39
41
  `}
40
42
  >
41
- <button
42
- type="button"
43
- onClick={onOpenDetail}
44
- className="flex flex-1 min-w-0 items-center gap-2.5 text-left rounded-xl pl-3 pr-2 py-2.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
43
+ <Link
44
+ href={detailHref}
45
+ className="flex flex-1 min-w-0 items-center gap-2.5 text-left rounded-xl pl-2.5 pr-2 py-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
45
46
  >
46
- <span className={`w-2 h-2 rounded-full shrink-0 ring-2 ring-background ${dot}`} />
47
+ <AgentAvatar name={agent.name} status={agentStatus} size="sm" />
47
48
  <span className="text-sm font-medium text-foreground truncate leading-tight">{agent.name}</span>
48
49
  {agentStatus === 'connected' && agent.transport && (
49
50
  <span className="text-2xs font-mono tabular-nums px-1.5 py-0.5 rounded-md bg-muted/90 text-muted-foreground shrink-0 border border-border/50">
@@ -56,7 +57,7 @@ export default function AgentsPanelAgentListRow({
56
57
  className={`shrink-0 transition-opacity duration-150 ${selected ? 'text-[var(--amber)] opacity-90' : 'text-muted-foreground/45 group-hover:text-muted-foreground/80'}`}
57
58
  aria-hidden
58
59
  />
59
- </button>
60
+ </Link>
60
61
 
61
62
  {agentStatus === 'detected' && (
62
63
  <div className="pr-2 py-2 shrink-0">
@@ -79,23 +80,45 @@ function AgentInstallButton({
79
80
  copy: AgentsPanelAgentListRowCopy;
80
81
  }) {
81
82
  const [installing, setInstalling] = useState(false);
83
+ const [installState, setInstallState] = useState<'idle' | 'success' | 'error'>('idle');
82
84
 
83
85
  const handleInstall = async (e: React.MouseEvent) => {
84
86
  e.stopPropagation();
87
+ if (installing) return;
85
88
  setInstalling(true);
86
- await onInstallAgent(agentKey);
89
+ setInstallState('idle');
90
+ const ok = await onInstallAgent(agentKey);
87
91
  setInstalling(false);
92
+ setInstallState(ok ? 'success' : 'error');
88
93
  };
89
94
 
95
+ const isError = installState === 'error';
96
+ const isSuccess = installState === 'success';
97
+ const label = installing
98
+ ? copy.installing
99
+ : isSuccess
100
+ ? copy.installSuccess
101
+ : isError
102
+ ? copy.retryInstall
103
+ : copy.install;
104
+
90
105
  return (
91
106
  <button
92
107
  type="button"
93
108
  onClick={handleInstall}
94
109
  disabled={installing}
95
- className="flex items-center gap-1 px-2 py-1.5 text-2xs rounded-lg font-medium text-[var(--amber-foreground)] disabled:opacity-50 transition-colors shrink-0 bg-[var(--amber)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
110
+ className={`flex items-center gap-1 px-2 py-1.5 text-2xs rounded-lg font-medium text-white disabled:opacity-50 transition-colors shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${
111
+ isError ? 'bg-error hover:bg-error/90' : isSuccess ? 'bg-success hover:bg-success/90' : 'bg-[var(--amber)] hover:bg-[var(--amber)]/90'
112
+ }`}
113
+ aria-label={`${agentName} ${label}`}
96
114
  >
97
115
  {installing ? <Loader2 size={10} className="animate-spin" /> : null}
98
- {installing ? copy.installing : copy.install(agentName)}
116
+ {!installing && isSuccess ? <Check size={10} /> : null}
117
+ {!installing && isError ? <RotateCw size={10} /> : null}
118
+ {label}
119
+ <span className="sr-only" aria-live="polite">
120
+ {isError ? copy.installFailed : ''}
121
+ </span>
99
122
  </button>
100
123
  );
101
124
  }
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { type RefObject } from 'react';
3
+ import { usePathname, useSearchParams } from 'next/navigation';
4
4
  import { LayoutDashboard, Server, Zap } from 'lucide-react';
5
5
  import { PanelNavRow } from './PanelNavRow';
6
6
 
@@ -13,35 +13,35 @@ type HubCopy = {
13
13
  export function AgentsPanelHubNav({
14
14
  copy,
15
15
  connectedCount,
16
- overviewRef,
17
- skillsRef,
18
- scrollTo,
19
- openAdvancedConfig,
20
16
  }: {
21
17
  copy: HubCopy;
22
18
  connectedCount: number;
23
- overviewRef: RefObject<HTMLDivElement | null>;
24
- skillsRef: RefObject<HTMLDivElement | null>;
25
- scrollTo: (el: HTMLElement | null) => void;
26
- openAdvancedConfig: () => void;
27
19
  }) {
20
+ const pathname = usePathname();
21
+ const searchParams = useSearchParams();
22
+ const tab = searchParams.get('tab');
23
+ const inAgentsRoute = pathname === '/agents';
24
+
28
25
  return (
29
26
  <div className="py-2">
30
27
  <PanelNavRow
31
28
  icon={<LayoutDashboard size={14} className="text-[var(--amber)]" />}
32
29
  title={copy.navOverview}
33
30
  badge={<span className="text-2xs tabular-nums text-muted-foreground">{connectedCount}</span>}
34
- onClick={() => scrollTo(overviewRef.current)}
31
+ href="/agents"
32
+ active={inAgentsRoute && (tab === null || tab === 'overview')}
35
33
  />
36
34
  <PanelNavRow
37
35
  icon={<Server size={14} className="text-muted-foreground" />}
38
36
  title={copy.navMcp}
39
- onClick={openAdvancedConfig}
37
+ href="/agents?tab=mcp"
38
+ active={inAgentsRoute && tab === 'mcp'}
40
39
  />
41
40
  <PanelNavRow
42
41
  icon={<Zap size={14} className="text-muted-foreground" />}
43
42
  title={copy.navSkills}
44
- onClick={() => scrollTo(skillsRef.current)}
43
+ href="/agents?tab=skills"
44
+ active={inAgentsRoute && tab === 'skills'}
45
45
  />
46
46
  </div>
47
47
  );
@@ -19,27 +19,25 @@ export default function EchoPanel({ active, maximized, onMaximize }: EchoPanelPr
19
19
  const e = t.panels.echo;
20
20
  const pathname = usePathname() ?? '';
21
21
 
22
- const rowBySegment: Record<EchoSegment, { icon: ReactNode; title: string }> = {
23
- 'about-you': { icon: <UserRound size={14} />, title: e.aboutYouTitle },
24
- continued: { icon: <Bookmark size={14} />, title: e.continuedTitle },
25
- daily: { icon: <Sun size={14} />, title: e.dailyEchoTitle },
26
- 'past-you': { icon: <History size={14} />, title: e.pastYouTitle },
27
- growth: { icon: <Brain size={14} />, title: e.intentGrowthTitle },
22
+ const rowBySegment: Record<EchoSegment, { icon: ReactNode; title: string; subtitle: string }> = {
23
+ 'about-you': { icon: <UserRound size={14} />, title: e.aboutYouTitle, subtitle: e.aboutYouDesc },
24
+ continued: { icon: <Bookmark size={14} />, title: e.continuedTitle, subtitle: e.continuedDesc },
25
+ daily: { icon: <Sun size={14} />, title: e.dailyEchoTitle, subtitle: e.dailyDesc },
26
+ 'past-you': { icon: <History size={14} />, title: e.pastYouTitle, subtitle: e.pastYouDesc },
27
+ growth: { icon: <Brain size={14} />, title: e.intentGrowthTitle, subtitle: e.growthDesc },
28
28
  };
29
29
 
30
30
  return (
31
31
  <div className={`flex flex-col h-full ${active ? '' : 'hidden'}`}>
32
32
  <PanelHeader title={e.title} maximized={maximized} onMaximize={onMaximize} />
33
33
  <div className="flex-1 overflow-y-auto min-h-0">
34
- <div className="flex flex-col py-1">
34
+ <div className="flex flex-col gap-0.5 py-1.5">
35
35
  {ECHO_SEGMENT_ORDER.map((segment) => {
36
36
  const row = rowBySegment[segment];
37
37
  const href = ECHO_SEGMENT_HREF[segment];
38
38
  const isActive = pathname === href || pathname.startsWith(`${href}/`);
39
39
  return (
40
- <div key={segment} className="border-b border-border/60 last:border-b-0">
41
- <PanelNavRow href={href} icon={row.icon} title={row.title} active={isActive} />
42
- </div>
40
+ <PanelNavRow key={segment} href={href} icon={row.icon} title={row.title} subtitle={row.subtitle} active={isActive} />
43
41
  );
44
42
  })}
45
43
  </div>
@@ -5,10 +5,11 @@ import Link from 'next/link';
5
5
  import { ChevronRight } from 'lucide-react';
6
6
  import { cn } from '@/lib/utils';
7
7
 
8
- /** Row matching Discover panel nav: icon tile, title, optional badge, chevron. */
8
+ /** Row matching Discover panel nav: icon tile, title, optional subtitle, optional badge, chevron. */
9
9
  export function PanelNavRow({
10
10
  icon,
11
11
  title,
12
+ subtitle,
12
13
  badge,
13
14
  href,
14
15
  onClick,
@@ -16,6 +17,7 @@ export function PanelNavRow({
16
17
  }: {
17
18
  icon: ReactNode;
18
19
  title: string;
20
+ subtitle?: string;
19
21
  badge?: React.ReactNode;
20
22
  href?: string;
21
23
  onClick?: () => void;
@@ -25,7 +27,12 @@ export function PanelNavRow({
25
27
  const content = (
26
28
  <>
27
29
  <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-muted">{icon}</span>
28
- <span className="flex-1 text-left text-sm font-medium text-foreground">{title}</span>
30
+ <span className="flex-1 min-w-0">
31
+ <span className="block text-left text-sm font-medium text-foreground truncate">{title}</span>
32
+ {subtitle ? (
33
+ <span className="block text-left text-2xs text-muted-foreground truncate">{subtitle}</span>
34
+ ) : null}
35
+ </span>
29
36
  {badge}
30
37
  <ChevronRight size={14} className="shrink-0 text-muted-foreground" />
31
38
  </>
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useState, useEffect, useCallback, useRef } from 'react';
4
4
  import { useRouter } from 'next/navigation';
5
- import { getAllRenderers, isRendererEnabled, setRendererEnabled, loadDisabledState } from '@/lib/renderers/registry';
5
+ import { getPluginRenderers, isRendererEnabled, setRendererEnabled, loadDisabledState } from '@/lib/renderers/registry';
6
6
  import { Toggle } from '../settings/Primitives';
7
7
  import PanelHeader from './PanelHeader';
8
8
  import { useLocale } from '@/lib/LocaleContext';
@@ -32,7 +32,7 @@ export default function PluginsPanel({ active, maximized, onMaximize }: PluginsP
32
32
  useEffect(() => {
33
33
  if (!mounted || fetchedRef.current) return;
34
34
  fetchedRef.current = true;
35
- const entryPaths = getAllRenderers()
35
+ const entryPaths = getPluginRenderers()
36
36
  .map(r => r.entryPath)
37
37
  .filter((p): p is string => !!p);
38
38
  if (entryPaths.length === 0) return;
@@ -47,7 +47,7 @@ export default function PluginsPanel({ active, maximized, onMaximize }: PluginsP
47
47
  .catch(() => {});
48
48
  }, [mounted]);
49
49
 
50
- const renderers = mounted ? getAllRenderers() : [];
50
+ const renderers = mounted ? getPluginRenderers() : [];
51
51
  const enabledCount = mounted ? renderers.filter(r => isRendererEnabled(r.id)).length : 0;
52
52
 
53
53
  const handleToggle = useCallback((id: string, enabled: boolean) => {
@@ -142,12 +142,12 @@ export default function PluginsPanel({ active, maximized, onMaximize }: PluginsP
142
142
  </span>
143
143
  ))}
144
144
  {r.entryPath && enabled && !fileExists && (
145
- <span className="text-2xs" style={{ color: 'var(--amber)' }}>
145
+ <span className="text-2xs text-[var(--amber)]">
146
146
  {(p.createFile ?? 'Create {file}').replace('{file}', r.entryPath)}
147
147
  </span>
148
148
  )}
149
149
  {canOpen && (
150
- <span className="text-2xs" style={{ color: 'var(--amber)' }}>
150
+ <span className="text-2xs text-[var(--amber)]">
151
151
  → {r.entryPath}
152
152
  </span>
153
153
  )}
@@ -6,13 +6,13 @@ import { Terminal, FileEdit, FilePlus, Trash2, Search, Clock, ChevronDown, Alert
6
6
  import type { RendererContext } from '@/lib/renderers/registry';
7
7
 
8
8
  // ─── Log entry format ─────────────────────────────────────────────────────────
9
- // Each entry is a fenced JSON block in the markdown:
9
+ // Primary format:
10
+ // {
11
+ // "version": 1,
12
+ // "events": [{ "ts": "...", "tool": "mindos_write_file", "params": {}, "result": "ok" }]
13
+ // }
10
14
  //
11
- // ```agent-op
12
- // { "ts": "2025-01-15T10:30:00Z", "tool": "mindos_write_file",
13
- // "params": { "path": "...", "content": "..." },
14
- // "result": "ok" | "error", "message": "..." }
15
- // ```
15
+ // Legacy format (still supported for compatibility): JSON Lines.
16
16
 
17
17
  interface AgentOp {
18
18
  ts: string;
@@ -22,9 +22,14 @@ interface AgentOp {
22
22
  message?: string;
23
23
  }
24
24
 
25
+ interface AgentAuditState {
26
+ version?: number;
27
+ events?: AgentOp[];
28
+ }
29
+
25
30
  // ─── Parser ───────────────────────────────────────────────────────────────────
26
31
 
27
- function parseOps(content: string): AgentOp[] {
32
+ function parseJsonLines(content: string): AgentOp[] {
28
33
  const ops: AgentOp[] = [];
29
34
 
30
35
  // JSON Lines format: each line is a JSON object
@@ -36,6 +41,23 @@ function parseOps(content: string): AgentOp[] {
36
41
  if (op.tool && op.ts) ops.push(op);
37
42
  } catch { /* skip non-JSON lines */ }
38
43
  }
44
+ return ops;
45
+ }
46
+
47
+ function parseOps(content: string): AgentOp[] {
48
+ // New format: JSON object with events array.
49
+ try {
50
+ const parsed = JSON.parse(content) as AgentAuditState;
51
+ if (Array.isArray(parsed.events)) {
52
+ return parsed.events
53
+ .filter((op) => Boolean(op?.tool) && Boolean(op?.ts))
54
+ .sort((a, b) => new Date(b.ts).getTime() - new Date(a.ts).getTime());
55
+ }
56
+ } catch {
57
+ // Fallback to legacy JSONL.
58
+ }
59
+
60
+ const ops = parseJsonLines(content);
39
61
 
40
62
  // newest first
41
63
  return ops.sort((a, b) => new Date(b.ts).getTime() - new Date(a.ts).getTime());
@@ -236,7 +258,7 @@ export function AgentInspectorRenderer({ content }: RendererContext) {
236
258
  <Terminal size={28} style={{ margin: '0 auto 10px', opacity: 0.3 }} />
237
259
  <p>No agent operations logged yet.</p>
238
260
  <p style={{ marginTop: 6, opacity: 0.6, fontSize: 11 }}>
239
- Agent writes appear here as <code style={{ background: 'var(--muted)', padding: '1px 5px', borderRadius: 4 }}>```agent-op</code> blocks.
261
+ Agent writes appear here from <code style={{ background: 'var(--muted)', padding: '1px 5px', borderRadius: 4 }}>.mindos/agent-audit-log.json</code>.
240
262
  </p>
241
263
  </div>
242
264
  );
@@ -3,12 +3,14 @@ import type { RendererDefinition } from '@/lib/renderers/registry';
3
3
  export const manifest: RendererDefinition = {
4
4
  id: 'agent-inspector',
5
5
  name: 'Agent Inspector',
6
- description: 'Visualizes agent tool-call logs as a filterable timeline. Auto-activates on .agent-log.json (JSON Lines format).',
6
+ description: 'Visualizes agent tool-call logs as a filterable timeline. Auto-activates on .mindos/agent-audit-log.json and supports legacy .agent-log.json.',
7
7
  author: 'MindOS',
8
8
  icon: '🔍',
9
9
  tags: ['agent', 'inspector', 'log', 'mcp', 'tools'],
10
10
  builtin: true,
11
- entryPath: '.agent-log.json',
12
- match: ({ filePath }) => /\.agent-log\.json$/i.test(filePath),
11
+ core: true,
12
+ appBuiltinFeature: true,
13
+ entryPath: '.mindos/agent-audit-log.json',
14
+ match: ({ filePath }) => /(^|\/)\.mindos\/agent-audit-log\.json$/i.test(filePath) || /\.agent-log\.json$/i.test(filePath),
13
15
  load: () => import('./AgentInspectorRenderer').then(m => ({ default: m.AgentInspectorRenderer })),
14
16
  };
@@ -9,6 +9,7 @@ export const manifest: RendererDefinition = {
9
9
  tags: ['config', 'json', 'settings', 'schema'],
10
10
  builtin: true,
11
11
  core: true,
12
+ appBuiltinFeature: true,
12
13
  entryPath: 'CONFIG.json',
13
14
  match: ({ filePath, extension }) => extension === 'json' && /(^|\/)CONFIG\.json$/i.test(filePath),
14
15
  load: () => import('./ConfigRenderer').then(m => ({ default: m.ConfigRenderer })),
@@ -9,6 +9,7 @@ export const manifest: RendererDefinition = {
9
9
  tags: ['csv', 'table', 'gallery', 'board', 'data'],
10
10
  builtin: true,
11
11
  core: true,
12
+ appBuiltinFeature: true,
12
13
  entryPath: 'Resources/Products.csv',
13
14
  match: ({ extension, filePath }) => extension === 'csv' && !/\bTODO\b/i.test(filePath),
14
15
  load: () => import('./CsvRenderer').then(m => ({ default: m.CsvRenderer })),
@@ -9,6 +9,7 @@ export const manifest: RendererDefinition = {
9
9
  tags: ['productivity', 'tasks', 'markdown'],
10
10
  builtin: true,
11
11
  core: true,
12
+ appBuiltinFeature: true,
12
13
  entryPath: 'TODO.md',
13
14
  match: ({ filePath }) => /\bTODO\b.*\.(md|csv)$/i.test(filePath),
14
15
  load: () => import('./TodoRenderer').then(m => ({ default: m.TodoRenderer })),
@@ -121,7 +121,7 @@ export function AiTab({ data, updateAi, updateAgent, t }: AiTabProps) {
121
121
  type="button"
122
122
  disabled={disabled}
123
123
  onClick={() => handleTestKey(providerName)}
124
- className="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-md border border-border text-muted-foreground hover:text-foreground hover:border-foreground/20 transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
124
+ className="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-lg border border-border text-muted-foreground hover:text-foreground hover:border-foreground/20 transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
125
125
  >
126
126
  {result.state === 'testing' ? (
127
127
  <>
@@ -143,7 +143,7 @@ export function AiTab({ data, updateAi, updateAgent, t }: AiTabProps) {
143
143
  };
144
144
 
145
145
  return (
146
- <div className="space-y-5">
146
+ <div className="space-y-6">
147
147
  <Field label={<>{t.settings.ai.provider} <EnvBadge overridden={env.AI_PROVIDER} /></>}>
148
148
  <Select
149
149
  value={provider}
@@ -214,7 +214,7 @@ export function AiTab({ data, updateAi, updateAgent, t }: AiTabProps) {
214
214
  )}
215
215
 
216
216
  {Object.values(env).some(Boolean) && (
217
- <div className="flex items-start gap-2 text-xs text-amber-500/80 bg-amber-500/8 border border-amber-500/20 rounded-lg px-3 py-2.5">
217
+ <div className="flex items-start gap-2 text-xs text-[var(--amber)] bg-[var(--amber-subtle)] border border-[var(--amber)]/20 rounded-lg px-3 py-2.5">
218
218
  <AlertCircle size={13} className="shrink-0 mt-0.5" />
219
219
  <span>{t.settings.ai.envHint}</span>
220
220
  </div>
@@ -67,7 +67,7 @@ export function AppearanceTab({ font, setFont, contentWidth, setContentWidth, da
67
67
  onClick={() => setFont(f.value)}
68
68
  className={`px-3 py-1.5 text-xs rounded-lg border transition-all ${
69
69
  font === f.value
70
- ? 'border-amber-500 bg-amber-500/10 text-foreground font-medium shadow-sm'
70
+ ? 'border-[var(--amber)] bg-[var(--amber-subtle)] text-foreground font-medium shadow-sm'
71
71
  : 'border-border text-muted-foreground hover:text-foreground hover:bg-muted'
72
72
  }`}
73
73
  style={{ fontFamily: f.style.fontFamily }}
@@ -94,7 +94,7 @@ export function AppearanceTab({ font, setFont, contentWidth, setContentWidth, da
94
94
  onClick={() => setContentWidth(w.value)}
95
95
  className={`px-3 py-1.5 text-xs rounded-lg border transition-all ${
96
96
  contentWidth === w.value
97
- ? 'border-amber-500 bg-amber-500/10 text-foreground font-medium shadow-sm'
97
+ ? 'border-[var(--amber)] bg-[var(--amber-subtle)] text-foreground font-medium shadow-sm'
98
98
  : 'border-border text-muted-foreground hover:text-foreground hover:bg-muted'
99
99
  }`}
100
100
  >
@@ -116,7 +116,7 @@ export function KnowledgeTab({ data, setData, t }: KnowledgeTabProps) {
116
116
  }
117
117
 
118
118
  return (
119
- <div className="space-y-5">
119
+ <div className="space-y-6">
120
120
  <SectionLabel>Knowledge Base</SectionLabel>
121
121
 
122
122
  <Field
@@ -208,7 +208,7 @@ export function KnowledgeTab({ data, setData, t }: KnowledgeTabProps) {
208
208
  )}
209
209
  </div>
210
210
  {revealedToken && (
211
- <p className="text-xs text-amber-500">
211
+ <p className="text-xs text-[var(--amber)]">
212
212
  New token generated. Copy it now — it won&apos;t be shown in full again.
213
213
  </p>
214
214
  )}
@@ -221,7 +221,7 @@ export function KnowledgeTab({ data, setData, t }: KnowledgeTabProps) {
221
221
  <SectionLabel>{t.guide?.title ?? 'Getting Started'}</SectionLabel>
222
222
  <div className="flex items-center justify-between py-2">
223
223
  <div className="flex items-center gap-2">
224
- <Sparkles size={14} style={{ color: 'var(--amber)' }} />
224
+ <Sparkles size={14} className="text-[var(--amber)]" />
225
225
  <div>
226
226
  <div className="text-sm text-foreground">{t.guide?.showGuide ?? 'Show getting started guide'}</div>
227
227
  </div>
@@ -94,8 +94,7 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
94
94
  style={{ accentColor: 'var(--amber)' }}
95
95
  />
96
96
  <span className="w-28 shrink-0 text-xs">{agent.name}</span>
97
- <span className="text-2xs px-1.5 py-0.5 rounded font-mono"
98
- style={{ background: 'rgba(100,100,120,0.08)' }}>
97
+ <span className="text-2xs px-1.5 py-0.5 rounded font-mono bg-muted">
99
98
  {getEffectiveTransport(agent)}
100
99
  </span>
101
100
  {agent.installed ? (
@@ -131,8 +130,7 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
131
130
  onClick={() => setSelected(new Set(
132
131
  agents.filter(a => !a.installed && a.present).map(a => a.key)
133
132
  ))}
134
- className="px-2.5 py-1 rounded-md border transition-colors hover:bg-muted/50"
135
- style={{ borderColor: 'var(--amber)', color: 'var(--amber)' }}>
133
+ className="px-2.5 py-1 rounded-md border border-[var(--amber)] text-[var(--amber)] transition-colors hover:bg-muted/50">
136
134
  {m?.selectDetected ?? 'Select Detected'}
137
135
  </button>
138
136
  <button type="button"
@@ -205,8 +203,7 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
205
203
  <button
206
204
  onClick={handleInstall}
207
205
  disabled={selected.size === 0 || installing}
208
- className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-lg transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
209
- style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}
206
+ className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-lg transition-colors disabled:opacity-40 disabled:cursor-not-allowed bg-[var(--amber)] text-[var(--amber-foreground)]"
210
207
  >
211
208
  {installing && <Loader2 size={12} className="animate-spin" />}
212
209
  {installing ? (m?.installing ?? 'Installing...') : (m?.installSelected ?? 'Install Selected')}
@@ -129,7 +129,7 @@ export default function SkillCreateForm({ onSave, onCancel, saving, error, m }:
129
129
  onClick={() => handleTemplateChange(tmpl)}
130
130
  className={`px-2.5 py-1 text-xs transition-colors ${i > 0 ? 'border-l border-border' : ''} ${
131
131
  selectedTemplate === tmpl
132
- ? 'bg-amber-500/15 text-amber-600 font-medium'
132
+ ? 'bg-[var(--amber-subtle)] text-[var(--amber)] font-medium'
133
133
  : 'text-muted-foreground hover:bg-muted'
134
134
  }`}
135
135
  >
@@ -160,8 +160,7 @@ export default function SkillCreateForm({ onSave, onCancel, saving, error, m }:
160
160
  <button
161
161
  onClick={() => onSave(newName.trim(), newContent || getTemplate(newName.trim() || 'my-skill'))}
162
162
  disabled={!newName.trim() || saving}
163
- className="flex items-center gap-1 px-2.5 py-1 text-xs rounded-md disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
164
- style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}
163
+ className="flex items-center gap-1 px-2.5 py-1 text-xs rounded-md disabled:opacity-40 disabled:cursor-not-allowed transition-colors bg-[var(--amber)] text-[var(--amber-foreground)]"
165
164
  >
166
165
  {saving && <Loader2 size={10} className="animate-spin" />}
167
166
  {m?.saveSkill ?? 'Save'}
@@ -51,7 +51,7 @@ export default function SkillRow({
51
51
  {expanded ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
52
52
  <span className="text-xs font-medium flex-1">{skill.name}</span>
53
53
  <span className={`text-2xs px-1.5 py-0.5 rounded ${
54
- skill.source === 'builtin' ? 'bg-blue-500/15 text-blue-500' : 'bg-purple-500/15 text-purple-500'
54
+ skill.source === 'builtin' ? 'bg-muted text-muted-foreground' : 'bg-[var(--amber-subtle)] text-[var(--amber)]'
55
55
  }`}>
56
56
  {skill.source === 'builtin' ? (m?.skillBuiltin ?? 'Built-in') : (m?.skillUser ?? 'Custom')}
57
57
  </span>
@@ -106,8 +106,7 @@ export default function SkillRow({
106
106
  <button
107
107
  onClick={() => onEditSave(skill.name)}
108
108
  disabled={saving}
109
- className="flex items-center gap-1 px-2.5 py-1 text-xs rounded-md disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
110
- style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}
109
+ className="flex items-center gap-1 px-2.5 py-1 text-xs rounded-md disabled:opacity-40 disabled:cursor-not-allowed transition-colors bg-[var(--amber)] text-[var(--amber-foreground)]"
111
110
  >
112
111
  {saving && <Loader2 size={10} className="animate-spin" />}
113
112
  {m?.saveSkill ?? 'Save'}
@@ -239,7 +239,7 @@ export default function SkillsSection({ t }: McpSkillsSectionProps) {
239
239
  onClick={() => handleLangSwitch('en')}
240
240
  disabled={switchingLang}
241
241
  className={`px-2.5 py-1 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${
242
- currentLang === 'en' ? 'bg-amber-500/15 text-amber-600 font-medium' : 'text-muted-foreground hover:bg-muted'
242
+ currentLang === 'en' ? 'bg-[var(--amber-subtle)] text-[var(--amber)] font-medium' : 'text-muted-foreground hover:bg-muted'
243
243
  }`}
244
244
  >
245
245
  {m?.skillLangEn ?? 'English'}
@@ -248,7 +248,7 @@ export default function SkillsSection({ t }: McpSkillsSectionProps) {
248
248
  onClick={() => handleLangSwitch('zh')}
249
249
  disabled={switchingLang}
250
250
  className={`px-2.5 py-1 text-xs transition-colors disabled:opacity-50 disabled:cursor-not-allowed border-l border-border ${
251
- currentLang === 'zh' ? 'bg-amber-500/15 text-amber-600 font-medium' : 'text-muted-foreground hover:bg-muted'
251
+ currentLang === 'zh' ? 'bg-[var(--amber-subtle)] text-[var(--amber)] font-medium' : 'text-muted-foreground hover:bg-muted'
252
252
  }`}
253
253
  >
254
254
  {m?.skillLangZh ?? '中文'}