@geminilight/mindos 0.5.9 → 0.5.10
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 +1 -1
- package/app/app/api/skills/route.ts +1 -1
- package/app/app/globals.css +10 -2
- package/app/app/login/page.tsx +1 -1
- package/app/app/view/[...path]/ViewPageClient.tsx +6 -1
- package/app/app/view/[...path]/not-found.tsx +1 -1
- package/app/components/AskModal.tsx +4 -4
- package/app/components/Breadcrumb.tsx +2 -2
- package/app/components/DirView.tsx +6 -6
- package/app/components/FileTree.tsx +2 -2
- package/app/components/HomeContent.tsx +7 -7
- package/app/components/OnboardingView.tsx +1 -1
- package/app/components/SearchModal.tsx +1 -1
- package/app/components/SettingsModal.tsx +2 -2
- package/app/components/SetupWizard.tsx +1 -1400
- package/app/components/Sidebar.tsx +4 -4
- package/app/components/SidebarLayout.tsx +9 -0
- package/app/components/SyncStatusBar.tsx +3 -3
- package/app/components/TableOfContents.tsx +1 -1
- package/app/components/UpdateBanner.tsx +1 -1
- package/app/components/ask/FileChip.tsx +1 -1
- package/app/components/ask/MentionPopover.tsx +4 -4
- package/app/components/ask/MessageList.tsx +1 -1
- package/app/components/ask/SessionHistory.tsx +2 -2
- package/app/components/renderers/config/ConfigRenderer.tsx +1 -1
- package/app/components/renderers/csv/BoardView.tsx +2 -2
- package/app/components/renderers/csv/ConfigPanel.tsx +5 -5
- package/app/components/renderers/csv/GalleryView.tsx +1 -1
- package/app/components/renderers/graph/GraphRenderer.tsx +1 -1
- package/app/components/renderers/summary/SummaryRenderer.tsx +1 -1
- package/app/components/renderers/workflow/WorkflowRenderer.tsx +2 -2
- package/app/components/settings/KnowledgeTab.tsx +1 -1
- package/app/components/settings/McpTab.tsx +27 -23
- package/app/components/settings/PluginsTab.tsx +4 -4
- package/app/components/settings/Primitives.tsx +1 -1
- package/app/components/settings/SyncTab.tsx +8 -8
- package/app/components/setup/StepAI.tsx +67 -0
- package/app/components/setup/StepAgents.tsx +237 -0
- package/app/components/setup/StepDots.tsx +39 -0
- package/app/components/setup/StepKB.tsx +237 -0
- package/app/components/setup/StepPorts.tsx +121 -0
- package/app/components/setup/StepReview.tsx +211 -0
- package/app/components/setup/StepSecurity.tsx +78 -0
- package/app/components/setup/constants.tsx +13 -0
- package/app/components/setup/index.tsx +464 -0
- package/app/components/setup/types.ts +53 -0
- package/app/lib/i18n.ts +4 -4
- package/package.json +1 -1
- package/skills/project-wiki/SKILL.md +92 -63
package/README.md
CHANGED
|
@@ -417,7 +417,7 @@ MindOS/
|
|
|
417
417
|
~/.mindos/ # User data directory (outside project, never committed)
|
|
418
418
|
├── config.json # All configuration (AI keys, port, auth token, sync settings)
|
|
419
419
|
├── sync-state.json # Sync state (last sync time, conflicts)
|
|
420
|
-
└──
|
|
420
|
+
└── mind/ # Your private knowledge base (default: ~/MindOS/mind, customizable on onboard)
|
|
421
421
|
```
|
|
422
422
|
|
|
423
423
|
---
|
|
@@ -9,7 +9,7 @@ const PROJECT_ROOT = path.resolve(process.cwd(), '..');
|
|
|
9
9
|
|
|
10
10
|
function getMindRoot(): string {
|
|
11
11
|
const s = readSettings();
|
|
12
|
-
return s.mindRoot || process.env.MIND_ROOT || path.join(os.homedir(), 'MindOS');
|
|
12
|
+
return s.mindRoot || process.env.MIND_ROOT || path.join(os.homedir(), 'MindOS', 'mind');
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
interface SkillInfo {
|
package/app/app/globals.css
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
--color-destructive: var(--destructive);
|
|
29
29
|
--color-success: var(--success);
|
|
30
30
|
--color-error: var(--error);
|
|
31
|
+
--color-amber-foreground: var(--amber-foreground);
|
|
31
32
|
--color-accent-foreground: var(--accent-foreground);
|
|
32
33
|
--color-accent: var(--accent);
|
|
33
34
|
--color-muted-foreground: var(--muted-foreground);
|
|
@@ -65,7 +66,7 @@ body {
|
|
|
65
66
|
--secondary: #e8e4db;
|
|
66
67
|
--secondary-foreground: #1c1a17;
|
|
67
68
|
--muted: #e8e4db;
|
|
68
|
-
--muted-foreground: #
|
|
69
|
+
--muted-foreground: #685f52;
|
|
69
70
|
--accent: #d9d3c6;
|
|
70
71
|
--accent-foreground: #1c1a17;
|
|
71
72
|
--destructive: oklch(0.58 0.22 27);
|
|
@@ -75,6 +76,7 @@ body {
|
|
|
75
76
|
--radius: 0.5rem;
|
|
76
77
|
--amber: #c8873a;
|
|
77
78
|
--amber-dim: rgba(200, 135, 58, 0.12);
|
|
79
|
+
--amber-foreground: #131210;
|
|
78
80
|
--success: #7aad80;
|
|
79
81
|
--error: #c85050;
|
|
80
82
|
--sidebar: #ede9e1;
|
|
@@ -108,6 +110,7 @@ body {
|
|
|
108
110
|
--ring: var(--amber);
|
|
109
111
|
--amber: #d4954a;
|
|
110
112
|
--amber-dim: rgba(212, 149, 74, 0.12);
|
|
113
|
+
--amber-foreground: #131210;
|
|
111
114
|
--success: #7aad80;
|
|
112
115
|
--error: #c85050;
|
|
113
116
|
--sidebar: #1c1a17;
|
|
@@ -282,6 +285,11 @@ body {
|
|
|
282
285
|
-webkit-backdrop-filter: blur(8px);
|
|
283
286
|
}
|
|
284
287
|
|
|
288
|
+
/* Micro type scale: text-2xs = 10px (between nothing and text-xs 12px) */
|
|
289
|
+
@layer utilities {
|
|
290
|
+
.text-2xs { font-size: 10px; line-height: 1.4; }
|
|
291
|
+
}
|
|
292
|
+
|
|
285
293
|
/* Hide scrollbar but keep scroll functionality */
|
|
286
294
|
.scrollbar-none { -ms-overflow-style: none; scrollbar-width: none; }
|
|
287
295
|
.scrollbar-none::-webkit-scrollbar { display: none; }
|
|
@@ -341,7 +349,7 @@ a:focus-visible,
|
|
|
341
349
|
/* Selection */
|
|
342
350
|
.wysiwyg-editor ::selection {
|
|
343
351
|
background: var(--amber);
|
|
344
|
-
color:
|
|
352
|
+
color: var(--amber-foreground);
|
|
345
353
|
opacity: 0.35;
|
|
346
354
|
}
|
|
347
355
|
|
package/app/app/login/page.tsx
CHANGED
|
@@ -101,7 +101,7 @@ function LoginForm() {
|
|
|
101
101
|
<button
|
|
102
102
|
type="submit"
|
|
103
103
|
disabled={loading || !password}
|
|
104
|
-
className="w-full flex items-center justify-center gap-2 py-2 px-4 rounded-lg text-sm font-medium transition-opacity disabled:opacity-50 disabled:cursor-not-allowed mt-2 bg-[var(--amber)] text-[
|
|
104
|
+
className="w-full flex items-center justify-center gap-2 py-2 px-4 rounded-lg text-sm font-medium transition-opacity disabled:opacity-50 disabled:cursor-not-allowed mt-2 bg-[var(--amber)] text-[var(--amber-foreground)]"
|
|
105
105
|
>
|
|
106
106
|
{loading ? (
|
|
107
107
|
<Loader2 size={14} className="animate-spin" />
|
|
@@ -118,6 +118,11 @@ export default function ViewPageClient({
|
|
|
118
118
|
setSaveError('Please enter a file name');
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
|
+
// Reject path traversal and illegal filename characters
|
|
122
|
+
if (/[/\\:*?"<>|]/.test(trimmed) || trimmed.includes('..')) {
|
|
123
|
+
setSaveError('File name contains invalid characters');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
121
126
|
if (!createDraftAction) {
|
|
122
127
|
setSaveError('Draft save is not available');
|
|
123
128
|
return;
|
|
@@ -283,7 +288,7 @@ export default function ViewPageClient({
|
|
|
283
288
|
onClick={isDraft && showSaveAs ? handleConfirmDraftSave : handleSave}
|
|
284
289
|
disabled={isPending}
|
|
285
290
|
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium disabled:opacity-50 font-display"
|
|
286
|
-
style={{ background: 'var(--amber)', color: '
|
|
291
|
+
style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}
|
|
287
292
|
>
|
|
288
293
|
{isPending ? <Loader2 size={13} className="animate-spin" /> : <Save size={13} />}
|
|
289
294
|
<span className="hidden sm:inline">Save</span>
|
|
@@ -69,7 +69,7 @@ export default function ViewNotFound() {
|
|
|
69
69
|
onClick={handleCreate}
|
|
70
70
|
disabled={creating}
|
|
71
71
|
className="flex items-center gap-2 px-4 py-2.5 text-sm font-medium rounded-lg transition-colors disabled:opacity-50"
|
|
72
|
-
style={{ background: 'var(--amber)', color: '
|
|
72
|
+
style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}
|
|
73
73
|
>
|
|
74
74
|
<FilePlus size={14} />
|
|
75
75
|
{creating
|
|
@@ -289,7 +289,7 @@ export default function AskModal({ open, onClose, currentFile }: AskModalProps)
|
|
|
289
289
|
{/* Attached file chips */}
|
|
290
290
|
{attachedFiles.length > 0 && (
|
|
291
291
|
<div className="px-4 pt-2.5 pb-1">
|
|
292
|
-
<div className="text-
|
|
292
|
+
<div className="text-xs text-muted-foreground/70 mb-1.5">Knowledge Base Context</div>
|
|
293
293
|
<div className="flex flex-wrap gap-1.5">
|
|
294
294
|
{attachedFiles.map(f => (
|
|
295
295
|
<FileChip key={f} path={f} onRemove={() => setAttachedFiles(prev => prev.filter(x => x !== f))} />
|
|
@@ -300,7 +300,7 @@ export default function AskModal({ open, onClose, currentFile }: AskModalProps)
|
|
|
300
300
|
|
|
301
301
|
{upload.localAttachments.length > 0 && (
|
|
302
302
|
<div className="px-4 pb-1">
|
|
303
|
-
<div className="text-
|
|
303
|
+
<div className="text-xs text-muted-foreground/70 mb-1.5">Uploaded Files</div>
|
|
304
304
|
<div className="flex flex-wrap gap-1.5">
|
|
305
305
|
{upload.localAttachments.map((f, idx) => (
|
|
306
306
|
<FileChip key={`${f.name}-${idx}`} path={f.name} variant="upload" onRemove={() => upload.removeAttachment(idx)} />
|
|
@@ -371,7 +371,7 @@ export default function AskModal({ open, onClose, currentFile }: AskModalProps)
|
|
|
371
371
|
<StopCircle size={15} />
|
|
372
372
|
</button>
|
|
373
373
|
) : (
|
|
374
|
-
<button type="submit" disabled={!input.trim()} className="p-1.5 rounded-md disabled:opacity-40 disabled:cursor-not-allowed transition-opacity shrink-0" style={{ background: 'var(--amber)', color: '
|
|
374
|
+
<button type="submit" disabled={!input.trim()} className="p-1.5 rounded-md disabled:opacity-40 disabled:cursor-not-allowed transition-opacity shrink-0" style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}>
|
|
375
375
|
<Send size={14} />
|
|
376
376
|
</button>
|
|
377
377
|
)}
|
|
@@ -384,7 +384,7 @@ export default function AskModal({ open, onClose, currentFile }: AskModalProps)
|
|
|
384
384
|
<span><kbd className="font-mono">@</kbd> {t.ask.attachFile}</span>
|
|
385
385
|
<span className="inline-flex items-center gap-1">
|
|
386
386
|
<span>Agent steps</span>
|
|
387
|
-
<select value={maxSteps} onChange={(e) => setMaxSteps(Number(e.target.value))} disabled={isLoading} className="bg-transparent border border-border rounded px-1.5 py-0.5 text-
|
|
387
|
+
<select value={maxSteps} onChange={(e) => setMaxSteps(Number(e.target.value))} disabled={isLoading} className="bg-transparent border border-border rounded px-1.5 py-0.5 text-xs text-foreground">
|
|
388
388
|
<option value={10}>10</option>
|
|
389
389
|
<option value={20}>20</option>
|
|
390
390
|
<option value={30}>30</option>
|
|
@@ -5,8 +5,8 @@ import { ChevronRight, Home, FileText, Table, Folder } from 'lucide-react';
|
|
|
5
5
|
|
|
6
6
|
function FileTypeIcon({ name }: { name: string }) {
|
|
7
7
|
const ext = name.includes('.') ? name.slice(name.lastIndexOf('.')).toLowerCase() : '';
|
|
8
|
-
if (ext === '.csv') return <Table size={13} className="text-
|
|
9
|
-
if (ext) return <FileText size={13} className="text-
|
|
8
|
+
if (ext === '.csv') return <Table size={13} className="text-success shrink-0" />;
|
|
9
|
+
if (ext) return <FileText size={13} className="text-muted-foreground shrink-0" />;
|
|
10
10
|
return <Folder size={13} className="text-yellow-400 shrink-0" />;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -15,14 +15,14 @@ interface DirViewProps {
|
|
|
15
15
|
|
|
16
16
|
function FileIcon({ node }: { node: FileNode }) {
|
|
17
17
|
if (node.type === 'directory') return <Folder size={16} className="text-yellow-400 shrink-0" />;
|
|
18
|
-
if (node.extension === '.csv') return <Table size={16} className="text-
|
|
19
|
-
return <FileText size={16} className="text-
|
|
18
|
+
if (node.extension === '.csv') return <Table size={16} className="text-success shrink-0" />;
|
|
19
|
+
return <FileText size={16} className="text-muted-foreground shrink-0" />;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function FileIconLarge({ node }: { node: FileNode }) {
|
|
23
23
|
if (node.type === 'directory') return <FolderOpen size={28} className="text-yellow-400" />;
|
|
24
|
-
if (node.extension === '.csv') return <Table size={28} className="text-
|
|
25
|
-
return <FileText size={28} className="text-
|
|
24
|
+
if (node.extension === '.csv') return <Table size={28} className="text-success" />;
|
|
25
|
+
return <FileText size={28} className="text-muted-foreground" />;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function countFiles(node: FileNode): number {
|
|
@@ -125,10 +125,10 @@ export default function DirView({ dirPath, entries }: DirViewProps) {
|
|
|
125
125
|
{entry.name}
|
|
126
126
|
</span>
|
|
127
127
|
{entry.type === 'directory' && (
|
|
128
|
-
<span className="text-
|
|
128
|
+
<span className="text-2xs text-muted-foreground">{t.dirView.fileCount(fileCounts.get(entry.path) ?? 0)}</span>
|
|
129
129
|
)}
|
|
130
130
|
{entry.type === 'file' && entry.mtime && (
|
|
131
|
-
<span className="text-
|
|
131
|
+
<span className="text-2xs text-muted-foreground font-display" suppressHydrationWarning>
|
|
132
132
|
{formatTime(entry.mtime)}
|
|
133
133
|
</span>
|
|
134
134
|
)}
|
|
@@ -16,8 +16,8 @@ interface FileTreeProps {
|
|
|
16
16
|
|
|
17
17
|
function getIcon(node: FileNode) {
|
|
18
18
|
if (node.type === 'directory') return null;
|
|
19
|
-
if (node.extension === '.csv') return <Table size={14} className="text-
|
|
20
|
-
return <FileText size={14} className="text-
|
|
19
|
+
if (node.extension === '.csv') return <Table size={14} className="text-success shrink-0" />;
|
|
20
|
+
return <FileText size={14} className="text-muted-foreground shrink-0" />;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function getCurrentFilePath(pathname: string): string {
|
|
@@ -102,7 +102,7 @@ export default function HomeContent({ recent, existingFiles }: { recent: RecentF
|
|
|
102
102
|
{suggestions[suggestionIdx]}
|
|
103
103
|
</span>
|
|
104
104
|
<kbd
|
|
105
|
-
className="hidden sm:inline-flex items-center gap-0.5 px-2 py-0.5 rounded text-
|
|
105
|
+
className="hidden sm:inline-flex items-center gap-0.5 px-2 py-0.5 rounded text-xs font-mono font-medium"
|
|
106
106
|
style={{ background: 'var(--amber-dim)', color: 'var(--amber)' }}
|
|
107
107
|
>
|
|
108
108
|
⌘/
|
|
@@ -118,7 +118,7 @@ export default function HomeContent({ recent, existingFiles }: { recent: RecentF
|
|
|
118
118
|
>
|
|
119
119
|
<Search size={14} />
|
|
120
120
|
<span className="hidden sm:inline">{t.home.shortcuts.searchFiles}</span>
|
|
121
|
-
<kbd className="hidden sm:inline-flex items-center px-1.5 py-0.5 rounded text-
|
|
121
|
+
<kbd className="hidden sm:inline-flex items-center px-1.5 py-0.5 rounded text-2xs font-mono" style={{ background: 'var(--muted)' }}>
|
|
122
122
|
⌘K
|
|
123
123
|
</kbd>
|
|
124
124
|
</button>
|
|
@@ -189,17 +189,17 @@ export default function HomeContent({ recent, existingFiles }: { recent: RecentF
|
|
|
189
189
|
{r.name}
|
|
190
190
|
</span>
|
|
191
191
|
</div>
|
|
192
|
-
<p className="text-
|
|
192
|
+
<p className="text-xs leading-relaxed line-clamp-2" style={{ color: 'var(--muted-foreground)' }}>
|
|
193
193
|
{r.description}
|
|
194
194
|
</p>
|
|
195
195
|
{hintId === r.id ? (
|
|
196
|
-
<p className="text-
|
|
196
|
+
<p className="text-2xs animate-in" style={{ color: 'var(--amber)' }} role="status">
|
|
197
197
|
{(t.home.createToActivate ?? 'Create {file} to activate').replace('{file}', entryPath ?? '')}
|
|
198
198
|
</p>
|
|
199
199
|
) : (
|
|
200
200
|
<div className="flex flex-wrap gap-1">
|
|
201
201
|
{r.tags.slice(0, 3).map(tag => (
|
|
202
|
-
<span key={tag} className="text-
|
|
202
|
+
<span key={tag} className="text-2xs px-1.5 py-0.5 rounded-full" style={{ background: 'var(--muted)', color: 'var(--muted-foreground)' }}>
|
|
203
203
|
{tag}
|
|
204
204
|
</span>
|
|
205
205
|
))}
|
|
@@ -222,12 +222,12 @@ export default function HomeContent({ recent, existingFiles }: { recent: RecentF
|
|
|
222
222
|
{r.name}
|
|
223
223
|
</span>
|
|
224
224
|
</div>
|
|
225
|
-
<p className="text-
|
|
225
|
+
<p className="text-xs leading-relaxed line-clamp-2" style={{ color: 'var(--muted-foreground)' }}>
|
|
226
226
|
{r.description}
|
|
227
227
|
</p>
|
|
228
228
|
<div className="flex flex-wrap gap-1">
|
|
229
229
|
{r.tags.slice(0, 3).map(tag => (
|
|
230
|
-
<span key={tag} className="text-
|
|
230
|
+
<span key={tag} className="text-2xs px-1.5 py-0.5 rounded-full" style={{ background: 'var(--muted)', color: 'var(--muted-foreground)' }}>
|
|
231
231
|
{tag}
|
|
232
232
|
</span>
|
|
233
233
|
))}
|
|
@@ -110,7 +110,7 @@ export default function OnboardingView() {
|
|
|
110
110
|
|
|
111
111
|
{/* Directory preview */}
|
|
112
112
|
<div
|
|
113
|
-
className="w-full rounded-lg px-3 py-2 text-
|
|
113
|
+
className="w-full rounded-lg px-3 py-2 text-xs leading-relaxed font-display"
|
|
114
114
|
style={{
|
|
115
115
|
background: 'var(--muted)',
|
|
116
116
|
color: 'var(--muted-foreground)',
|
|
@@ -158,7 +158,7 @@ export default function SearchModal({ open, onClose }: SearchModalProps) {
|
|
|
158
158
|
`}
|
|
159
159
|
>
|
|
160
160
|
{ext === '.csv'
|
|
161
|
-
? <Table size={14} className="text-
|
|
161
|
+
? <Table size={14} className="text-success shrink-0 mt-0.5" />
|
|
162
162
|
: <FileText size={14} className="text-muted-foreground shrink-0 mt-0.5" />
|
|
163
163
|
}
|
|
164
164
|
<div className="min-w-0 flex-1">
|
|
@@ -234,7 +234,7 @@ export default function SettingsModal({ open, onClose, initialTab }: SettingsMod
|
|
|
234
234
|
)}
|
|
235
235
|
<div className="flex items-center gap-1.5 text-xs">
|
|
236
236
|
{status === 'saved' && (
|
|
237
|
-
<><CheckCircle2 size={13} className="text-
|
|
237
|
+
<><CheckCircle2 size={13} className="text-success" /><span className="text-success">{t.settings.saved}</span></>
|
|
238
238
|
)}
|
|
239
239
|
{status === 'error' && (
|
|
240
240
|
<><AlertCircle size={13} className="text-destructive" /><span className="text-destructive">{t.settings.saveFailed}</span></>
|
|
@@ -245,7 +245,7 @@ export default function SettingsModal({ open, onClose, initialTab }: SettingsMod
|
|
|
245
245
|
onClick={handleSave}
|
|
246
246
|
disabled={saving || !data}
|
|
247
247
|
className="flex items-center gap-1.5 px-4 py-1.5 text-sm rounded-lg disabled:opacity-40 disabled:cursor-not-allowed transition-opacity"
|
|
248
|
-
style={{ background: 'var(--amber)', color: '
|
|
248
|
+
style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}
|
|
249
249
|
>
|
|
250
250
|
{saving ? <Loader2 size={13} className="animate-spin" /> : <Save size={13} />}
|
|
251
251
|
{t.settings.save}
|