@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.
- package/README.md +4 -0
- package/README_zh.md +4 -0
- package/app/app/api/ask/route.ts +12 -0
- package/app/app/api/changes/route.ts +7 -1
- package/app/app/api/file/route.ts +9 -0
- package/app/app/api/mcp/agents/route.ts +27 -1
- package/app/app/api/mcp/install-skill/route.ts +9 -24
- package/app/app/api/skills/route.ts +18 -2
- package/app/app/api/tree-version/route.ts +8 -0
- package/app/app/layout.tsx +1 -0
- package/app/app/page.tsx +1 -2
- package/app/app/view/[...path]/ViewPageClient.tsx +0 -1
- 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 +44 -14
- 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 +2 -1
- package/app/components/RightAskPanel.tsx +1 -1
- package/app/components/SearchModal.tsx +10 -2
- package/app/components/SidebarLayout.tsx +36 -10
- package/app/components/ThemeToggle.tsx +1 -1
- package/app/components/agents/AgentDetailContent.tsx +454 -59
- package/app/components/agents/AgentsContentPage.tsx +89 -20
- package/app/components/agents/AgentsMcpSection.tsx +513 -85
- package/app/components/agents/AgentsOverviewSection.tsx +418 -59
- package/app/components/agents/AgentsPrimitives.tsx +335 -0
- package/app/components/agents/AgentsSkillsSection.tsx +746 -105
- package/app/components/agents/SkillDetailPopover.tsx +416 -0
- package/app/components/agents/agents-content-model.ts +308 -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 +89 -13
- package/app/components/changes/ChangesContentPage.tsx +134 -51
- 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 +22 -128
- package/app/components/panels/AgentsPanelAgentDetail.tsx +7 -6
- package/app/components/panels/AgentsPanelAgentGroups.tsx +8 -13
- package/app/components/panels/AgentsPanelAgentListRow.tsx +39 -16
- package/app/components/panels/AgentsPanelHubNav.tsx +12 -12
- package/app/components/panels/EchoPanel.tsx +8 -10
- package/app/components/panels/PanelNavRow.tsx +9 -2
- package/app/components/panels/PluginsPanel.tsx +5 -5
- package/app/components/renderers/agent-inspector/AgentInspectorRenderer.tsx +30 -8
- package/app/components/renderers/agent-inspector/manifest.ts +5 -3
- package/app/components/renderers/config/manifest.ts +1 -0
- package/app/components/renderers/csv/manifest.ts +1 -0
- 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 +6 -5
- 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 +7 -4
- package/app/hooks/useMention.ts +25 -8
- package/app/lib/agent/log.ts +15 -18
- 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/content-changes.ts +148 -8
- package/app/lib/core/index.ts +11 -0
- package/app/lib/fs.ts +16 -1
- package/app/lib/i18n-en.ts +317 -36
- package/app/lib/i18n-zh.ts +316 -35
- package/app/lib/mcp-agents.ts +273 -2
- package/app/lib/renderers/index.ts +1 -2
- package/app/lib/renderers/registry.ts +10 -0
- package/app/lib/types.ts +2 -0
- package/app/next-env.d.ts +1 -1
- package/bin/lib/mcp-agents.js +38 -13
- package/package.json +1 -1
- package/scripts/migrate-agent-audit-log.js +170 -0
- package/scripts/migrate-agent-diff.js +146 -0
- package/scripts/setup.js +12 -17
- package/skills/plugin-core-builtin-migration/SKILL.md +178 -0
- package/app/components/renderers/diff/DiffRenderer.tsx +0 -311
- 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
|
|
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:
|
|
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
|
-
|
|
23
|
+
detailHref,
|
|
19
24
|
onInstallAgent,
|
|
20
25
|
copy,
|
|
21
26
|
}: {
|
|
22
27
|
agent: AgentInfo;
|
|
23
28
|
agentStatus: AgentsPanelAgentListStatus;
|
|
24
29
|
selected?: boolean;
|
|
25
|
-
|
|
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
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
<
|
|
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
|
-
</
|
|
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
|
-
|
|
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=
|
|
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 ?
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
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
|
|
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 {
|
|
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 =
|
|
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 ?
|
|
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
|
|
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
|
|
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
|
-
//
|
|
9
|
+
// Primary format:
|
|
10
|
+
// {
|
|
11
|
+
// "version": 1,
|
|
12
|
+
// "events": [{ "ts": "...", "tool": "mindos_write_file", "params": {}, "result": "ok" }]
|
|
13
|
+
// }
|
|
10
14
|
//
|
|
11
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
12
|
-
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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
|
|
211
|
+
<p className="text-xs text-[var(--amber)]">
|
|
212
212
|
New token generated. Copy it now — it won'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}
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 ?? '中文'}
|