@geminilight/mindos 0.3.0 → 0.5.0
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/app/app/api/mcp/agents/route.ts +72 -0
- package/app/app/api/mcp/install/route.ts +95 -0
- package/app/app/api/mcp/status/route.ts +47 -0
- package/app/app/api/setup/check-port/route.ts +41 -0
- package/app/app/api/skills/route.ts +208 -0
- package/app/app/api/sync/route.ts +54 -3
- package/app/app/api/update-check/route.ts +52 -0
- package/app/app/globals.css +12 -0
- package/app/app/layout.tsx +4 -2
- package/app/app/login/page.tsx +20 -13
- package/app/app/page.tsx +19 -2
- package/app/app/setup/page.tsx +2 -0
- package/app/app/view/[...path]/ViewPageClient.tsx +47 -21
- package/app/app/view/[...path]/loading.tsx +1 -1
- package/app/app/view/[...path]/not-found.tsx +101 -0
- package/app/components/AskFab.tsx +1 -1
- package/app/components/AskModal.tsx +1 -1
- package/app/components/Backlinks.tsx +1 -1
- package/app/components/Breadcrumb.tsx +13 -3
- package/app/components/CsvView.tsx +5 -6
- package/app/components/DirView.tsx +42 -21
- package/app/components/FindInPage.tsx +211 -0
- package/app/components/HomeContent.tsx +97 -44
- package/app/components/JsonView.tsx +1 -2
- package/app/components/MarkdownEditor.tsx +1 -2
- package/app/components/OnboardingView.tsx +6 -7
- package/app/components/SettingsModal.tsx +5 -2
- package/app/components/SetupWizard.tsx +499 -172
- package/app/components/Sidebar.tsx +1 -1
- package/app/components/UpdateBanner.tsx +101 -0
- package/app/components/renderers/{AgentInspectorRenderer.tsx → agent-inspector/AgentInspectorRenderer.tsx} +13 -11
- package/app/components/renderers/agent-inspector/manifest.ts +14 -0
- package/app/components/renderers/{BacklinksRenderer.tsx → backlinks/BacklinksRenderer.tsx} +6 -6
- package/app/components/renderers/backlinks/manifest.ts +14 -0
- package/app/components/renderers/config/manifest.ts +14 -0
- package/app/components/renderers/csv/BoardView.tsx +12 -12
- package/app/components/renderers/csv/ConfigPanel.tsx +7 -8
- package/app/components/renderers/{CsvRenderer.tsx → csv/CsvRenderer.tsx} +8 -9
- package/app/components/renderers/csv/GalleryView.tsx +3 -3
- package/app/components/renderers/csv/TableView.tsx +4 -5
- package/app/components/renderers/csv/manifest.ts +14 -0
- package/app/components/renderers/{DiffRenderer.tsx → diff/DiffRenderer.tsx} +10 -9
- package/app/components/renderers/diff/manifest.ts +14 -0
- package/app/components/renderers/{GraphRenderer.tsx → graph/GraphRenderer.tsx} +4 -5
- package/app/components/renderers/graph/manifest.ts +14 -0
- package/app/components/renderers/{SummaryRenderer.tsx → summary/SummaryRenderer.tsx} +6 -6
- package/app/components/renderers/summary/manifest.ts +14 -0
- package/app/components/renderers/{TimelineRenderer.tsx → timeline/TimelineRenderer.tsx} +6 -6
- package/app/components/renderers/timeline/manifest.ts +14 -0
- package/app/components/renderers/{TodoRenderer.tsx → todo/TodoRenderer.tsx} +2 -2
- package/app/components/renderers/todo/manifest.ts +14 -0
- package/app/components/renderers/{WorkflowRenderer.tsx → workflow/WorkflowRenderer.tsx} +13 -13
- package/app/components/renderers/workflow/manifest.ts +14 -0
- package/app/components/settings/McpTab.tsx +549 -0
- package/app/components/settings/SyncTab.tsx +139 -50
- package/app/components/settings/types.ts +1 -1
- package/app/data/pages/home.png +0 -0
- package/app/lib/i18n.ts +226 -19
- package/app/lib/renderers/index.ts +20 -89
- package/app/lib/renderers/registry.ts +4 -1
- package/app/lib/settings.ts +3 -0
- package/app/package.json +1 -0
- package/app/types/semver.d.ts +8 -0
- package/bin/cli.js +137 -24
- package/bin/lib/build.js +53 -18
- package/bin/lib/colors.js +3 -1
- package/bin/lib/config.js +4 -0
- package/bin/lib/constants.js +2 -0
- package/bin/lib/debug.js +10 -0
- package/bin/lib/mcp-install.js +4 -1
- package/bin/lib/port.js +8 -2
- package/bin/lib/startup.js +21 -20
- package/bin/lib/stop.js +41 -3
- package/bin/lib/sync.js +65 -53
- package/bin/lib/update-check.js +94 -0
- package/bin/lib/utils.js +2 -2
- package/package.json +1 -1
- package/scripts/gen-renderer-index.js +57 -0
- package/scripts/setup.js +205 -10
- /package/app/components/renderers/{ConfigRenderer.tsx → config/ConfigRenderer.tsx} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useCallback } from 'react';
|
|
4
|
-
import { RefreshCw, AlertCircle, CheckCircle2, Loader2, GitBranch,
|
|
4
|
+
import { RefreshCw, AlertCircle, CheckCircle2, Loader2, GitBranch, ExternalLink, Eye, EyeOff } from 'lucide-react';
|
|
5
5
|
import { SectionLabel } from './Primitives';
|
|
6
6
|
import { apiFetch } from '@/lib/api';
|
|
7
7
|
|
|
@@ -32,35 +32,53 @@ export function timeAgo(iso: string | null | undefined): string {
|
|
|
32
32
|
return `${Math.floor(diff / 86400000)}d ago`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
/* ──
|
|
35
|
+
/* ── Empty state — GUI sync init form ─────────────────────────── */
|
|
36
36
|
|
|
37
|
-
function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
setCopied(true);
|
|
42
|
-
setTimeout(() => setCopied(false), 2000);
|
|
43
|
-
};
|
|
44
|
-
return (
|
|
45
|
-
<button
|
|
46
|
-
type="button"
|
|
47
|
-
onClick={handleCopy}
|
|
48
|
-
className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors shrink-0"
|
|
49
|
-
title="Copy command"
|
|
50
|
-
>
|
|
51
|
-
{copied ? <Check size={12} className="text-green-500" /> : <Copy size={12} />}
|
|
52
|
-
</button>
|
|
53
|
-
);
|
|
37
|
+
function isValidGitUrl(url: string): 'https' | 'ssh' | false {
|
|
38
|
+
if (/^https:\/\/.+/.test(url)) return 'https';
|
|
39
|
+
if (/^git@[\w.-]+:.+/.test(url)) return 'ssh';
|
|
40
|
+
return false;
|
|
54
41
|
}
|
|
55
42
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
function SyncEmptyState({ t }: { t: any }) {
|
|
43
|
+
function SyncEmptyState({ t, onInitComplete }: { t: any; onInitComplete: () => void }) {
|
|
59
44
|
const syncT = t.settings?.sync;
|
|
60
|
-
|
|
45
|
+
|
|
46
|
+
const [remoteUrl, setRemoteUrl] = useState('');
|
|
47
|
+
const [token, setToken] = useState('');
|
|
48
|
+
const [branch, setBranch] = useState('main');
|
|
49
|
+
const [showToken, setShowToken] = useState(false);
|
|
50
|
+
const [connecting, setConnecting] = useState(false);
|
|
51
|
+
const [error, setError] = useState('');
|
|
52
|
+
|
|
53
|
+
const urlType = remoteUrl.trim() ? isValidGitUrl(remoteUrl.trim()) : null;
|
|
54
|
+
const isValid = urlType === 'https' || urlType === 'ssh';
|
|
55
|
+
const showTokenField = urlType === 'https';
|
|
56
|
+
|
|
57
|
+
const handleConnect = async () => {
|
|
58
|
+
setConnecting(true);
|
|
59
|
+
setError('');
|
|
60
|
+
try {
|
|
61
|
+
await apiFetch('/api/sync', {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: { 'Content-Type': 'application/json' },
|
|
64
|
+
body: JSON.stringify({
|
|
65
|
+
action: 'init',
|
|
66
|
+
remote: remoteUrl.trim(),
|
|
67
|
+
token: token.trim() || undefined,
|
|
68
|
+
branch: branch.trim() || 'main',
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
onInitComplete();
|
|
72
|
+
} catch (err: unknown) {
|
|
73
|
+
const msg = err instanceof Error ? err.message : 'Connection failed';
|
|
74
|
+
setError(msg);
|
|
75
|
+
} finally {
|
|
76
|
+
setConnecting(false);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
61
79
|
|
|
62
80
|
return (
|
|
63
|
-
<div className="space-y-
|
|
81
|
+
<div className="space-y-5">
|
|
64
82
|
{/* Header */}
|
|
65
83
|
<div className="flex items-center gap-3">
|
|
66
84
|
<div className="w-9 h-9 rounded-lg bg-muted flex items-center justify-center shrink-0">
|
|
@@ -76,33 +94,104 @@ function SyncEmptyState({ t }: { t: any }) {
|
|
|
76
94
|
</div>
|
|
77
95
|
</div>
|
|
78
96
|
|
|
79
|
-
{/*
|
|
80
|
-
<div className="space-y-
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
{/* Git Remote URL */}
|
|
98
|
+
<div className="space-y-1.5">
|
|
99
|
+
<label className="text-xs font-medium text-foreground block">
|
|
100
|
+
{syncT?.remoteUrl ?? 'Git Remote URL'}
|
|
101
|
+
</label>
|
|
102
|
+
<input
|
|
103
|
+
type="text"
|
|
104
|
+
value={remoteUrl}
|
|
105
|
+
onChange={e => { setRemoteUrl(e.target.value); setError(''); }}
|
|
106
|
+
placeholder="https://github.com/user/my-mind.git"
|
|
107
|
+
className="w-full px-3 py-2 text-sm rounded-lg border bg-transparent font-mono text-xs transition-colors focus:outline-none focus:ring-1"
|
|
108
|
+
style={{
|
|
109
|
+
borderColor: remoteUrl.trim() && !isValid ? 'var(--destructive, red)' : 'var(--border)',
|
|
110
|
+
color: 'var(--foreground)',
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
{remoteUrl.trim() && !isValid && (
|
|
114
|
+
<p className="text-[11px]" style={{ color: 'var(--destructive, red)' }}>
|
|
115
|
+
{syncT?.invalidUrl ?? 'Invalid Git URL — use HTTPS (https://...) or SSH (git@...)'}
|
|
116
|
+
</p>
|
|
117
|
+
)}
|
|
118
|
+
{urlType === 'ssh' && (
|
|
119
|
+
<p className="text-[11px] text-muted-foreground flex items-center gap-1">
|
|
120
|
+
<AlertCircle size={11} className="shrink-0" />
|
|
121
|
+
{syncT?.sshHint ?? 'SSH URLs require SSH key configured on this machine. HTTPS with token recommended.'}
|
|
122
|
+
</p>
|
|
123
|
+
)}
|
|
102
124
|
</div>
|
|
103
125
|
|
|
126
|
+
{/* Access Token (HTTPS only) */}
|
|
127
|
+
{showTokenField && (
|
|
128
|
+
<div className="space-y-1.5">
|
|
129
|
+
<label className="text-xs font-medium text-foreground block">
|
|
130
|
+
{syncT?.accessToken ?? 'Access Token'}{' '}
|
|
131
|
+
<span className="text-muted-foreground font-normal">{syncT?.optional ?? '(optional, for private repos)'}</span>
|
|
132
|
+
</label>
|
|
133
|
+
<div className="relative">
|
|
134
|
+
<input
|
|
135
|
+
type={showToken ? 'text' : 'password'}
|
|
136
|
+
value={token}
|
|
137
|
+
onChange={e => setToken(e.target.value)}
|
|
138
|
+
placeholder="ghp_xxxxxxxxxxxx"
|
|
139
|
+
className="w-full px-3 py-2 pr-9 text-sm rounded-lg border bg-transparent font-mono text-xs transition-colors focus:outline-none focus:ring-1"
|
|
140
|
+
style={{ borderColor: 'var(--border)', color: 'var(--foreground)' }}
|
|
141
|
+
/>
|
|
142
|
+
<button
|
|
143
|
+
type="button"
|
|
144
|
+
onClick={() => setShowToken(!showToken)}
|
|
145
|
+
className="absolute right-2 top-1/2 -translate-y-1/2 p-0.5 rounded hover:bg-muted text-muted-foreground transition-colors"
|
|
146
|
+
>
|
|
147
|
+
{showToken ? <EyeOff size={14} /> : <Eye size={14} />}
|
|
148
|
+
</button>
|
|
149
|
+
</div>
|
|
150
|
+
<p className="text-[11px] text-muted-foreground">
|
|
151
|
+
{syncT?.tokenHint ?? 'GitHub: Settings → Developer settings → Personal access tokens → repo scope'}
|
|
152
|
+
</p>
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
|
|
156
|
+
{/* Branch */}
|
|
157
|
+
<div className="space-y-1.5">
|
|
158
|
+
<label className="text-xs font-medium text-foreground block">
|
|
159
|
+
{syncT?.branchLabel ?? 'Branch'}
|
|
160
|
+
</label>
|
|
161
|
+
<input
|
|
162
|
+
type="text"
|
|
163
|
+
value={branch}
|
|
164
|
+
onChange={e => setBranch(e.target.value)}
|
|
165
|
+
placeholder="main"
|
|
166
|
+
className="w-full max-w-[200px] px-3 py-2 text-sm rounded-lg border bg-transparent font-mono text-xs transition-colors focus:outline-none focus:ring-1"
|
|
167
|
+
style={{ borderColor: 'var(--border)', color: 'var(--foreground)' }}
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{/* Connect button */}
|
|
172
|
+
<button
|
|
173
|
+
type="button"
|
|
174
|
+
onClick={handleConnect}
|
|
175
|
+
disabled={!isValid || connecting}
|
|
176
|
+
className="flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
|
|
177
|
+
style={{ background: 'var(--amber)', color: '#131210' }}
|
|
178
|
+
>
|
|
179
|
+
{connecting && <Loader2 size={14} className="animate-spin" />}
|
|
180
|
+
{connecting
|
|
181
|
+
? (syncT?.connecting ?? 'Connecting...')
|
|
182
|
+
: (syncT?.connectButton ?? 'Connect & Start Sync')}
|
|
183
|
+
</button>
|
|
184
|
+
|
|
185
|
+
{/* Error */}
|
|
186
|
+
{error && (
|
|
187
|
+
<div className="flex items-start gap-2 text-xs p-3 rounded-lg" role="alert" aria-live="polite" style={{ background: 'rgba(239,68,68,0.1)', color: 'var(--destructive, red)' }}>
|
|
188
|
+
<AlertCircle size={13} className="shrink-0 mt-0.5" />
|
|
189
|
+
<span>{error}</span>
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
|
|
104
193
|
{/* Features */}
|
|
105
|
-
<div className="grid grid-cols-2 gap-2 text-[11px] text-muted-foreground">
|
|
194
|
+
<div className="grid grid-cols-2 gap-2 text-[11px] text-muted-foreground pt-2">
|
|
106
195
|
{[
|
|
107
196
|
syncT?.featureAutoCommit ?? 'Auto-commit on save',
|
|
108
197
|
syncT?.featureAutoPull ?? 'Auto-pull from remote',
|
|
@@ -190,7 +279,7 @@ export function SyncTab({ t }: SyncTabProps) {
|
|
|
190
279
|
}
|
|
191
280
|
|
|
192
281
|
if (!status || !status.enabled) {
|
|
193
|
-
return <SyncEmptyState t={t} />;
|
|
282
|
+
return <SyncEmptyState t={t} onInitComplete={fetchStatus} />;
|
|
194
283
|
}
|
|
195
284
|
|
|
196
285
|
const conflicts = status.conflicts || [];
|
|
@@ -256,7 +345,7 @@ export function SyncTab({ t }: SyncTabProps) {
|
|
|
256
345
|
|
|
257
346
|
{/* Message */}
|
|
258
347
|
{message && (
|
|
259
|
-
<div className="flex items-center gap-1.5 text-xs">
|
|
348
|
+
<div className="flex items-center gap-1.5 text-xs" role="status" aria-live="polite">
|
|
260
349
|
{message.type === 'success' ? (
|
|
261
350
|
<><CheckCircle2 size={13} className="text-green-500" /><span className="text-green-500">{message.text}</span></>
|
|
262
351
|
) : (
|
|
@@ -24,7 +24,7 @@ export interface SettingsData {
|
|
|
24
24
|
envValues?: Record<string, string>;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export type Tab = 'ai' | 'appearance' | 'knowledge' | 'plugins' | 'shortcuts' | 'sync';
|
|
27
|
+
export type Tab = 'ai' | 'appearance' | 'knowledge' | 'mcp' | 'plugins' | 'shortcuts' | 'sync';
|
|
28
28
|
|
|
29
29
|
export const CONTENT_WIDTHS = [
|
|
30
30
|
{ value: '680px', label: 'Narrow (680px)' },
|
package/app/data/pages/home.png
CHANGED
|
Binary file
|
package/app/lib/i18n.ts
CHANGED
|
@@ -16,6 +16,7 @@ export const messages = {
|
|
|
16
16
|
plugins: 'Plugins',
|
|
17
17
|
showMore: 'Show more',
|
|
18
18
|
showLess: 'Show less',
|
|
19
|
+
createToActivate: 'Create {file} to activate',
|
|
19
20
|
shortcuts: {
|
|
20
21
|
searchFiles: 'Search files',
|
|
21
22
|
askAI: 'Ask AI',
|
|
@@ -96,10 +97,16 @@ export const messages = {
|
|
|
96
97
|
listView: 'List view',
|
|
97
98
|
emptyFolder: 'This folder is empty.',
|
|
98
99
|
fileCount: (n: number) => `${n} files`,
|
|
100
|
+
newFile: 'New file',
|
|
101
|
+
},
|
|
102
|
+
findInPage: {
|
|
103
|
+
placeholder: 'Find in document…',
|
|
104
|
+
matchCount: (current: number, total: number) => `${current} of ${total}`,
|
|
105
|
+
noResults: 'No results',
|
|
99
106
|
},
|
|
100
107
|
settings: {
|
|
101
108
|
title: 'Settings',
|
|
102
|
-
tabs: { ai: 'AI', appearance: 'Appearance', knowledge: 'Knowledge Base', sync: 'Sync', plugins: 'Plugins', shortcuts: 'Shortcuts' },
|
|
109
|
+
tabs: { ai: 'AI', appearance: 'Appearance', knowledge: 'Knowledge Base', sync: 'Sync', mcp: 'MCP', plugins: 'Plugins', shortcuts: 'Shortcuts' },
|
|
103
110
|
ai: {
|
|
104
111
|
provider: 'Provider',
|
|
105
112
|
model: 'Model',
|
|
@@ -144,14 +151,19 @@ export const messages = {
|
|
|
144
151
|
sync: {
|
|
145
152
|
emptyTitle: 'Cross-device Sync',
|
|
146
153
|
emptyDesc: 'Automatically sync your knowledge base across devices via Git.',
|
|
147
|
-
emptyStepsTitle: 'Setup',
|
|
148
|
-
emptyStep1: 'Create a private Git repo (GitHub, GitLab, etc.) or use an existing one.',
|
|
149
|
-
emptyStep2: 'Run this command in your terminal:',
|
|
150
|
-
emptyStep3: 'Follow the prompts to connect your repo. Sync starts automatically.',
|
|
151
154
|
featureAutoCommit: 'Auto-commit on save',
|
|
152
155
|
featureAutoPull: 'Auto-pull from remote',
|
|
153
156
|
featureConflict: 'Conflict detection',
|
|
154
157
|
featureMultiDevice: 'Works across devices',
|
|
158
|
+
remoteUrl: 'Git Remote URL',
|
|
159
|
+
invalidUrl: 'Invalid Git URL — use HTTPS (https://...) or SSH (git@...)',
|
|
160
|
+
sshHint: 'SSH URLs require SSH key configured on this machine. HTTPS with token recommended.',
|
|
161
|
+
accessToken: 'Access Token',
|
|
162
|
+
optional: '(optional, for private repos)',
|
|
163
|
+
tokenHint: 'GitHub: Settings → Developer settings → Personal access tokens → repo scope',
|
|
164
|
+
branchLabel: 'Branch',
|
|
165
|
+
connectButton: 'Connect & Start Sync',
|
|
166
|
+
connecting: 'Connecting...',
|
|
155
167
|
},
|
|
156
168
|
plugins: {
|
|
157
169
|
title: 'Installed Renderers',
|
|
@@ -162,6 +174,54 @@ export const messages = {
|
|
|
162
174
|
noPlugins: 'No renderers installed.',
|
|
163
175
|
comingSoon: 'Plugin marketplace coming soon.',
|
|
164
176
|
},
|
|
177
|
+
mcp: {
|
|
178
|
+
serverTitle: 'MindOS MCP Server',
|
|
179
|
+
status: 'Status',
|
|
180
|
+
running: 'Running',
|
|
181
|
+
stopped: 'Stopped',
|
|
182
|
+
transport: 'Transport',
|
|
183
|
+
endpoint: 'Endpoint',
|
|
184
|
+
tools: 'Tools',
|
|
185
|
+
toolsRegistered: (n: number) => `${n} registered`,
|
|
186
|
+
auth: 'Auth',
|
|
187
|
+
authSet: 'Token set',
|
|
188
|
+
authNotSet: 'No token',
|
|
189
|
+
copyEndpoint: 'Copy Endpoint',
|
|
190
|
+
copyConfig: 'Copy Config',
|
|
191
|
+
copied: 'Copied!',
|
|
192
|
+
agentsTitle: 'Agent Configuration',
|
|
193
|
+
agent: 'Agent',
|
|
194
|
+
scope: 'Scope',
|
|
195
|
+
project: 'Project',
|
|
196
|
+
global: 'Global',
|
|
197
|
+
installed: 'Installed',
|
|
198
|
+
notInstalled: 'Not installed',
|
|
199
|
+
transportStdio: 'stdio (recommended)',
|
|
200
|
+
transportHttp: 'http',
|
|
201
|
+
httpUrl: 'MCP URL',
|
|
202
|
+
httpToken: 'Auth Token',
|
|
203
|
+
installSelected: 'Install Selected',
|
|
204
|
+
installing: 'Installing...',
|
|
205
|
+
installSuccess: (n: number) => `${n} agent(s) configured`,
|
|
206
|
+
installFailed: 'Install failed',
|
|
207
|
+
portLabel: 'MCP Port',
|
|
208
|
+
portHint: 'Changes require server restart',
|
|
209
|
+
skillsTitle: 'Skills',
|
|
210
|
+
skillAutoLoaded: 'Auto-loaded on every request',
|
|
211
|
+
skillSource: 'Source',
|
|
212
|
+
skillBuiltin: 'Built-in',
|
|
213
|
+
skillUser: 'Custom',
|
|
214
|
+
addSkill: '+ Add Skill',
|
|
215
|
+
deleteSkill: 'Delete',
|
|
216
|
+
editSkill: 'Edit',
|
|
217
|
+
saveSkill: 'Save',
|
|
218
|
+
cancelSkill: 'Cancel',
|
|
219
|
+
skillName: 'Name',
|
|
220
|
+
skillDesc: 'Description',
|
|
221
|
+
skillContent: 'Content',
|
|
222
|
+
skillNameConflict: 'A skill with this name already exists',
|
|
223
|
+
skillDeleteConfirm: (name: string) => `Delete skill "${name}"? This cannot be undone.`,
|
|
224
|
+
},
|
|
165
225
|
save: 'Save',
|
|
166
226
|
saved: 'Saved',
|
|
167
227
|
saveFailed: 'Save failed',
|
|
@@ -186,8 +246,32 @@ export const messages = {
|
|
|
186
246
|
{ keys: ['Esc'], description: 'Cancel edit / close modal' },
|
|
187
247
|
{ keys: ['@'], description: 'Attach file in Ask AI' },
|
|
188
248
|
],
|
|
249
|
+
login: {
|
|
250
|
+
tagline: 'You think here, Agents act there.',
|
|
251
|
+
subtitle: 'Enter your password to continue',
|
|
252
|
+
passwordLabel: 'Password',
|
|
253
|
+
passwordPlaceholder: 'Enter password',
|
|
254
|
+
signIn: 'Sign in',
|
|
255
|
+
signingIn: 'Signing in…',
|
|
256
|
+
incorrectPassword: 'Incorrect password. Please try again.',
|
|
257
|
+
connectionError: 'Connection error. Please try again.',
|
|
258
|
+
},
|
|
259
|
+
notFound: {
|
|
260
|
+
title: 'File not found',
|
|
261
|
+
description: 'This file does not exist in your knowledge base.',
|
|
262
|
+
createButton: 'Create this file',
|
|
263
|
+
creating: 'Creating...',
|
|
264
|
+
goToParent: 'Go to parent folder',
|
|
265
|
+
goHome: 'Home',
|
|
266
|
+
},
|
|
267
|
+
updateBanner: {
|
|
268
|
+
newVersion: (latest: string, current: string) => `MindOS v${latest} available (current: v${current})`,
|
|
269
|
+
runUpdate: 'Run',
|
|
270
|
+
orSee: 'or',
|
|
271
|
+
releaseNotes: 'view release notes',
|
|
272
|
+
},
|
|
189
273
|
setup: {
|
|
190
|
-
stepTitles: ['Knowledge Base', 'AI Provider', 'Ports', 'Security', 'Review'],
|
|
274
|
+
stepTitles: ['Knowledge Base', 'AI Provider', 'Ports', 'Security', 'Agent Tools', 'Review'],
|
|
191
275
|
// Step 1
|
|
192
276
|
kbPath: 'Knowledge base path',
|
|
193
277
|
kbPathHint: 'Absolute path to your notes directory.',
|
|
@@ -207,6 +291,11 @@ export const messages = {
|
|
|
207
291
|
mcpPort: 'MCP server port',
|
|
208
292
|
portHint: 'Valid range: 1024–65535',
|
|
209
293
|
portRestartWarning: 'Port changes take effect after server restart.',
|
|
294
|
+
portInUse: (p: number) => `Port ${p} is already in use.`,
|
|
295
|
+
portSuggest: (p: number) => `Use ${p}`,
|
|
296
|
+
portChecking: 'Checking…',
|
|
297
|
+
portConflict: 'Web UI and MCP ports must be different.',
|
|
298
|
+
portVerifyHint: 'Click outside each field to verify, or wait for auto-check.',
|
|
210
299
|
// Step 4
|
|
211
300
|
authToken: 'Auth Token',
|
|
212
301
|
authTokenHint: 'Bearer token for MCP / API clients. Auto-generated.',
|
|
@@ -217,16 +306,30 @@ export const messages = {
|
|
|
217
306
|
copiedToken: 'Copied!',
|
|
218
307
|
webPassword: 'Web UI Password',
|
|
219
308
|
webPasswordHint: 'Optional. Protect browser access with a password.',
|
|
220
|
-
// Step 5
|
|
221
|
-
|
|
309
|
+
// Step 5 — Agent Tools
|
|
310
|
+
agentToolsTitle: 'Agent Tools',
|
|
311
|
+
agentToolsHint: 'Select AI agents to configure with MindOS MCP. Agents marked "not installed" can be configured now — they will work once you install the app.',
|
|
312
|
+
agentTransport: 'Transport',
|
|
313
|
+
agentScope: 'Scope',
|
|
314
|
+
agentToolsLoading: 'Loading agents…',
|
|
315
|
+
agentToolsEmpty: 'No supported agents detected.',
|
|
316
|
+
agentNoneSelected: 'No agents selected — you can configure later in Settings → MCP.',
|
|
317
|
+
agentNotInstalled: 'not installed',
|
|
318
|
+
agentStatusOk: 'configured',
|
|
319
|
+
agentStatusError: 'failed',
|
|
320
|
+
agentInstalling: 'Configuring…',
|
|
321
|
+
// Step 2 — AI skip card
|
|
322
|
+
aiSkipTitle: 'Skip for now',
|
|
323
|
+
aiSkipDesc: 'You can add an API key later in Settings → AI.',
|
|
324
|
+
// Step 6 — Review
|
|
222
325
|
reviewHint: 'Verify your settings before completing setup.',
|
|
223
|
-
|
|
326
|
+
reviewInstallResults: 'Agent configuration results:',
|
|
327
|
+
portAvailable: 'Available',
|
|
224
328
|
portChanged: 'Port changed — please restart the server for it to take effect.',
|
|
225
329
|
// Buttons
|
|
226
330
|
back: 'Back',
|
|
227
331
|
next: 'Next',
|
|
228
332
|
complete: 'Complete Setup',
|
|
229
|
-
skip: 'Skip',
|
|
230
333
|
// Status
|
|
231
334
|
completing: 'Saving...',
|
|
232
335
|
completeDone: 'Setup complete!',
|
|
@@ -248,6 +351,7 @@ export const messages = {
|
|
|
248
351
|
plugins: '插件',
|
|
249
352
|
showMore: '查看更多',
|
|
250
353
|
showLess: '收起',
|
|
354
|
+
createToActivate: '创建 {file} 以启用此插件',
|
|
251
355
|
shortcuts: {
|
|
252
356
|
searchFiles: '搜索文件',
|
|
253
357
|
askAI: '问 AI',
|
|
@@ -328,10 +432,16 @@ export const messages = {
|
|
|
328
432
|
listView: '列表视图',
|
|
329
433
|
emptyFolder: '此目录为空。',
|
|
330
434
|
fileCount: (n: number) => `${n} 个文件`,
|
|
435
|
+
newFile: '新建文件',
|
|
436
|
+
},
|
|
437
|
+
findInPage: {
|
|
438
|
+
placeholder: '在文档中查找…',
|
|
439
|
+
matchCount: (current: number, total: number) => `${current} / ${total}`,
|
|
440
|
+
noResults: '无结果',
|
|
331
441
|
},
|
|
332
442
|
settings: {
|
|
333
443
|
title: '设置',
|
|
334
|
-
tabs: { ai: 'AI', appearance: '外观', knowledge: '知识库', sync: '同步', plugins: '插件', shortcuts: '快捷键' },
|
|
444
|
+
tabs: { ai: 'AI', appearance: '外观', knowledge: '知识库', sync: '同步', mcp: 'MCP', plugins: '插件', shortcuts: '快捷键' },
|
|
335
445
|
ai: {
|
|
336
446
|
provider: '服务商',
|
|
337
447
|
model: '模型',
|
|
@@ -376,14 +486,19 @@ export const messages = {
|
|
|
376
486
|
sync: {
|
|
377
487
|
emptyTitle: '跨设备同步',
|
|
378
488
|
emptyDesc: '通过 Git 自动同步知识库到所有设备。',
|
|
379
|
-
emptyStepsTitle: '配置步骤',
|
|
380
|
-
emptyStep1: '创建一个私有 Git 仓库(GitHub、GitLab 等),或使用现有仓库。',
|
|
381
|
-
emptyStep2: '在终端中运行以下命令:',
|
|
382
|
-
emptyStep3: '按照提示连接仓库,同步将自动开始。',
|
|
383
489
|
featureAutoCommit: '保存时自动提交',
|
|
384
490
|
featureAutoPull: '自动拉取远程更新',
|
|
385
491
|
featureConflict: '冲突检测',
|
|
386
492
|
featureMultiDevice: '多设备同步',
|
|
493
|
+
remoteUrl: 'Git 远程仓库 URL',
|
|
494
|
+
invalidUrl: '无效的 Git URL — 请使用 HTTPS (https://...) 或 SSH (git@...) 格式',
|
|
495
|
+
sshHint: 'SSH URL 需要在本机配置 SSH 密钥。推荐使用 HTTPS + Token。',
|
|
496
|
+
accessToken: '访问令牌',
|
|
497
|
+
optional: '(可选,私有仓库需要)',
|
|
498
|
+
tokenHint: 'GitHub: Settings → Developer settings → Personal access tokens → repo scope',
|
|
499
|
+
branchLabel: '分支',
|
|
500
|
+
connectButton: '连接并开始同步',
|
|
501
|
+
connecting: '连接中...',
|
|
387
502
|
},
|
|
388
503
|
plugins: {
|
|
389
504
|
title: '已安装渲染器',
|
|
@@ -394,6 +509,54 @@ export const messages = {
|
|
|
394
509
|
noPlugins: '暂无渲染器。',
|
|
395
510
|
comingSoon: '插件市场即将上线。',
|
|
396
511
|
},
|
|
512
|
+
mcp: {
|
|
513
|
+
serverTitle: 'MindOS MCP 服务',
|
|
514
|
+
status: '状态',
|
|
515
|
+
running: '运行中',
|
|
516
|
+
stopped: '已停止',
|
|
517
|
+
transport: '传输方式',
|
|
518
|
+
endpoint: '端点',
|
|
519
|
+
tools: '工具',
|
|
520
|
+
toolsRegistered: (n: number) => `已注册 ${n} 个`,
|
|
521
|
+
auth: '认证',
|
|
522
|
+
authSet: '已设置 Token',
|
|
523
|
+
authNotSet: '未设置',
|
|
524
|
+
copyEndpoint: '复制端点',
|
|
525
|
+
copyConfig: '复制配置',
|
|
526
|
+
copied: '已复制!',
|
|
527
|
+
agentsTitle: 'Agent 配置',
|
|
528
|
+
agent: 'Agent',
|
|
529
|
+
scope: '范围',
|
|
530
|
+
project: '项目',
|
|
531
|
+
global: '全局',
|
|
532
|
+
installed: '已安装',
|
|
533
|
+
notInstalled: '未安装',
|
|
534
|
+
transportStdio: 'stdio(推荐)',
|
|
535
|
+
transportHttp: 'http',
|
|
536
|
+
httpUrl: 'MCP URL',
|
|
537
|
+
httpToken: '认证 Token',
|
|
538
|
+
installSelected: '安装选中',
|
|
539
|
+
installing: '安装中...',
|
|
540
|
+
installSuccess: (n: number) => `已配置 ${n} 个 agent`,
|
|
541
|
+
installFailed: '安装失败',
|
|
542
|
+
portLabel: 'MCP 端口',
|
|
543
|
+
portHint: '修改后需重启服务',
|
|
544
|
+
skillsTitle: 'Skills',
|
|
545
|
+
skillAutoLoaded: '每次请求自动加载',
|
|
546
|
+
skillSource: '来源',
|
|
547
|
+
skillBuiltin: '内置',
|
|
548
|
+
skillUser: '自定义',
|
|
549
|
+
addSkill: '+ 添加 Skill',
|
|
550
|
+
deleteSkill: '删除',
|
|
551
|
+
editSkill: '编辑',
|
|
552
|
+
saveSkill: '保存',
|
|
553
|
+
cancelSkill: '取消',
|
|
554
|
+
skillName: '名称',
|
|
555
|
+
skillDesc: '描述',
|
|
556
|
+
skillContent: '内容',
|
|
557
|
+
skillNameConflict: '同名 skill 已存在',
|
|
558
|
+
skillDeleteConfirm: (name: string) => `确定删除「${name}」?此操作不可撤销。`,
|
|
559
|
+
},
|
|
397
560
|
save: '保存',
|
|
398
561
|
saved: '已保存',
|
|
399
562
|
saveFailed: '保存失败',
|
|
@@ -418,8 +581,32 @@ export const messages = {
|
|
|
418
581
|
{ keys: ['Esc'], description: '取消编辑 / 关闭弹窗' },
|
|
419
582
|
{ keys: ['@'], description: '在 AI 对话中添加附件' },
|
|
420
583
|
],
|
|
584
|
+
login: {
|
|
585
|
+
tagline: '人类在此思考,Agent 依此行动。',
|
|
586
|
+
subtitle: '请输入密码以继续',
|
|
587
|
+
passwordLabel: '密码',
|
|
588
|
+
passwordPlaceholder: '输入密码',
|
|
589
|
+
signIn: '登录',
|
|
590
|
+
signingIn: '登录中…',
|
|
591
|
+
incorrectPassword: '密码错误,请重试。',
|
|
592
|
+
connectionError: '连接错误,请重试。',
|
|
593
|
+
},
|
|
594
|
+
notFound: {
|
|
595
|
+
title: '文件未找到',
|
|
596
|
+
description: '该文件不存在于你的知识库中。',
|
|
597
|
+
createButton: '创建此文件',
|
|
598
|
+
creating: '创建中...',
|
|
599
|
+
goToParent: '返回上级目录',
|
|
600
|
+
goHome: '首页',
|
|
601
|
+
},
|
|
602
|
+
updateBanner: {
|
|
603
|
+
newVersion: (latest: string, current: string) => `MindOS v${latest} 可用(当前 v${current})`,
|
|
604
|
+
runUpdate: '终端运行',
|
|
605
|
+
orSee: '或',
|
|
606
|
+
releaseNotes: '查看更新说明',
|
|
607
|
+
},
|
|
421
608
|
setup: {
|
|
422
|
-
stepTitles: ['知识库', 'AI 服务商', '端口', '安全', '确认'],
|
|
609
|
+
stepTitles: ['知识库', 'AI 服务商', '端口', '安全', 'Agent 工具', '确认'],
|
|
423
610
|
// Step 1
|
|
424
611
|
kbPath: '知识库路径',
|
|
425
612
|
kbPathHint: '笔记目录的绝对路径。',
|
|
@@ -439,6 +626,11 @@ export const messages = {
|
|
|
439
626
|
mcpPort: 'MCP 服务端口',
|
|
440
627
|
portHint: '有效范围:1024–65535',
|
|
441
628
|
portRestartWarning: '端口修改需重启服务后生效。',
|
|
629
|
+
portInUse: (p: number) => `端口 ${p} 已被占用。`,
|
|
630
|
+
portSuggest: (p: number) => `使用 ${p}`,
|
|
631
|
+
portChecking: '检测中…',
|
|
632
|
+
portConflict: 'Web UI 端口和 MCP 端口不能相同。',
|
|
633
|
+
portVerifyHint: '点击输入框外部验证,或等待自动检测。',
|
|
442
634
|
// Step 4
|
|
443
635
|
authToken: 'Auth Token',
|
|
444
636
|
authTokenHint: 'MCP / API 客户端使用的 Bearer Token,自动生成。',
|
|
@@ -449,10 +641,25 @@ export const messages = {
|
|
|
449
641
|
copiedToken: '已复制!',
|
|
450
642
|
webPassword: '网页访问密码',
|
|
451
643
|
webPasswordHint: '可选。设置后浏览器访问需要登录。',
|
|
452
|
-
// Step 5
|
|
453
|
-
|
|
644
|
+
// Step 5 — Agent Tools
|
|
645
|
+
agentToolsTitle: 'Agent 工具',
|
|
646
|
+
agentToolsHint: '选择要与 MindOS MCP 配置的 AI Agent。标注「未安装」的 agent 可以先行配置,安装应用后即可生效。',
|
|
647
|
+
agentTransport: '传输方式',
|
|
648
|
+
agentScope: '范围',
|
|
649
|
+
agentToolsLoading: '正在加载 Agent…',
|
|
650
|
+
agentToolsEmpty: '未检测到受支持的 Agent。',
|
|
651
|
+
agentNoneSelected: '未选择 agent — 可稍后在 设置 → MCP 中配置。',
|
|
652
|
+
agentNotInstalled: '未安装',
|
|
653
|
+
agentStatusOk: '已配置',
|
|
654
|
+
agentStatusError: '失败',
|
|
655
|
+
agentInstalling: '配置中…',
|
|
656
|
+
// Step 2 — AI skip card
|
|
657
|
+
aiSkipTitle: '暂时跳过',
|
|
658
|
+
aiSkipDesc: '稍后可在 设置 → AI 中添加 API 密钥。',
|
|
659
|
+
// Step 6 — Review
|
|
454
660
|
reviewHint: '完成设置前请确认以下信息。',
|
|
455
|
-
|
|
661
|
+
reviewInstallResults: 'Agent 配置结果:',
|
|
662
|
+
portAvailable: '可用',
|
|
456
663
|
portChanged: '端口已变更 — 请重启服务以使其生效。',
|
|
457
664
|
// Buttons
|
|
458
665
|
back: '上一步',
|