@geminilight/mindos 0.5.70 โ†’ 0.6.1

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 (42) hide show
  1. package/app/app/api/ask/route.ts +124 -92
  2. package/app/app/api/mcp/agents/route.ts +53 -2
  3. package/app/app/api/mcp/status/route.ts +1 -1
  4. package/app/app/api/skills/route.ts +10 -114
  5. package/app/components/ActivityBar.tsx +3 -4
  6. package/app/components/CreateSpaceModal.tsx +31 -6
  7. package/app/components/FileTree.tsx +33 -2
  8. package/app/components/GuideCard.tsx +197 -131
  9. package/app/components/HomeContent.tsx +85 -18
  10. package/app/components/SidebarLayout.tsx +13 -0
  11. package/app/components/SpaceInitToast.tsx +173 -0
  12. package/app/components/agents/AgentDetailContent.tsx +32 -17
  13. package/app/components/agents/AgentsContentPage.tsx +2 -1
  14. package/app/components/agents/AgentsOverviewSection.tsx +1 -14
  15. package/app/components/agents/agents-content-model.ts +16 -8
  16. package/app/components/ask/AskContent.tsx +137 -50
  17. package/app/components/ask/MentionPopover.tsx +16 -8
  18. package/app/components/ask/SlashCommandPopover.tsx +62 -0
  19. package/app/components/settings/KnowledgeTab.tsx +61 -0
  20. package/app/components/walkthrough/steps.ts +11 -6
  21. package/app/hooks/useMention.ts +14 -6
  22. package/app/hooks/useSlashCommand.ts +114 -0
  23. package/app/lib/actions.ts +79 -2
  24. package/app/lib/agent/index.ts +1 -1
  25. package/app/lib/agent/prompt.ts +2 -0
  26. package/app/lib/agent/tools.ts +106 -0
  27. package/app/lib/core/create-space.ts +11 -4
  28. package/app/lib/core/index.ts +1 -1
  29. package/app/lib/i18n-en.ts +51 -46
  30. package/app/lib/i18n-zh.ts +50 -45
  31. package/app/lib/mcp-agents.ts +8 -0
  32. package/app/lib/pdf-extract.ts +33 -0
  33. package/app/lib/pi-integration/extensions.ts +68 -0
  34. package/app/lib/pi-integration/mcporter.ts +219 -0
  35. package/app/lib/pi-integration/session-store.ts +62 -0
  36. package/app/lib/pi-integration/skills.ts +116 -0
  37. package/app/lib/settings.ts +1 -1
  38. package/app/next-env.d.ts +1 -1
  39. package/app/next.config.ts +1 -1
  40. package/app/package.json +2 -0
  41. package/mcp/src/index.ts +29 -0
  42. package/package.json +1 -1
@@ -0,0 +1,114 @@
1
+ 'use client';
2
+
3
+ import { useState, useCallback, useEffect, useRef } from 'react';
4
+ import type { SkillInfo } from '@/components/settings/types';
5
+
6
+ export interface SlashItem {
7
+ type: 'skill';
8
+ name: string;
9
+ description: string;
10
+ }
11
+
12
+ function safeFetchSkills(): Promise<SkillInfo[]> {
13
+ return fetch('/api/skills')
14
+ .then((r) => (r.ok ? r.json() : { skills: [] }))
15
+ .then((data) => (Array.isArray(data?.skills) ? data.skills : []))
16
+ .catch(() => [] as SkillInfo[]);
17
+ }
18
+
19
+ export function useSlashCommand() {
20
+ const [allSkills, setAllSkills] = useState<SkillInfo[]>([]);
21
+ const [slashQuery, setSlashQuery] = useState<string | null>(null);
22
+ const [slashResults, setSlashResults] = useState<SlashItem[]>([]);
23
+ const [slashIndex, setSlashIndex] = useState(0);
24
+ const loaded = useRef(false);
25
+
26
+ const loadSkills = useCallback(async () => {
27
+ const skills = await safeFetchSkills();
28
+ setAllSkills(skills.filter((s) => s.enabled));
29
+ loaded.current = true;
30
+ }, []);
31
+
32
+ useEffect(() => {
33
+ loadSkills();
34
+ const handler = () => loadSkills();
35
+ window.addEventListener('mindos:skills-changed', handler);
36
+ return () => window.removeEventListener('mindos:skills-changed', handler);
37
+ }, [loadSkills]);
38
+
39
+ const updateSlashFromInput = useCallback(
40
+ (val: string, cursorPos: number) => {
41
+ const before = val.slice(0, cursorPos);
42
+ const slashIdx = before.lastIndexOf('/');
43
+
44
+ if (slashIdx === -1) {
45
+ setSlashQuery(null);
46
+ return;
47
+ }
48
+
49
+ // `/` must be at line start or preceded by whitespace
50
+ if (slashIdx > 0 && before[slashIdx - 1] !== ' ' && before[slashIdx - 1] !== '\n') {
51
+ setSlashQuery(null);
52
+ return;
53
+ }
54
+
55
+ // No space in the typed query โ€” slash commands are single tokens
56
+ const query = before.slice(slashIdx + 1);
57
+ if (query.includes(' ')) {
58
+ setSlashQuery(null);
59
+ return;
60
+ }
61
+
62
+ if (!loaded.current) {
63
+ loadSkills();
64
+ setSlashQuery(null);
65
+ return;
66
+ }
67
+
68
+ const q = query.toLowerCase();
69
+ const items: SlashItem[] = allSkills
70
+ .filter((s) => s.name.toLowerCase().includes(q) || s.description.toLowerCase().includes(q))
71
+ .slice(0, 20)
72
+ .map((s) => ({ type: 'skill', name: s.name, description: s.description }));
73
+
74
+ if (items.length === 0) {
75
+ setSlashQuery(null);
76
+ setSlashResults([]);
77
+ setSlashIndex(0);
78
+ return;
79
+ }
80
+
81
+ setSlashQuery(query);
82
+ setSlashResults(items);
83
+ setSlashIndex(0);
84
+ },
85
+ [allSkills, loadSkills],
86
+ );
87
+
88
+ const navigateSlash = useCallback(
89
+ (direction: 'up' | 'down') => {
90
+ if (slashResults.length === 0) return;
91
+ if (direction === 'down') {
92
+ setSlashIndex((i) => Math.min(i + 1, slashResults.length - 1));
93
+ } else {
94
+ setSlashIndex((i) => Math.max(i - 1, 0));
95
+ }
96
+ },
97
+ [slashResults.length],
98
+ );
99
+
100
+ const resetSlash = useCallback(() => {
101
+ setSlashQuery(null);
102
+ setSlashResults([]);
103
+ setSlashIndex(0);
104
+ }, []);
105
+
106
+ return {
107
+ slashQuery,
108
+ slashResults,
109
+ slashIndex,
110
+ updateSlashFromInput,
111
+ navigateSlash,
112
+ resetSlash,
113
+ };
114
+ }
@@ -1,7 +1,10 @@
1
1
  'use server';
2
2
 
3
- import { createFile, deleteFile, deleteDirectory, convertToSpace, renameFile, renameSpace, getMindRoot, invalidateCache } from '@/lib/fs';
4
- import { createSpaceFilesystem } from '@/lib/core/create-space';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { createFile, deleteFile, deleteDirectory, convertToSpace, renameFile, renameSpace, getMindRoot, invalidateCache, collectAllFiles } from '@/lib/fs';
6
+ import { createSpaceFilesystem, generateReadmeTemplate } from '@/lib/core/create-space';
7
+ import { INSTRUCTION_TEMPLATE, cleanDirName } from '@/lib/core/space-scaffold';
5
8
  import { revalidatePath } from 'next/cache';
6
9
 
7
10
  export async function createFileAction(dirPath: string, fileName: string): Promise<{ success: boolean; filePath?: string; error?: string }> {
@@ -112,3 +115,77 @@ export async function createSpaceAction(
112
115
  return { success: false, error: msg };
113
116
  }
114
117
  }
118
+
119
+ /**
120
+ * Revert AI-generated space content back to scaffold templates.
121
+ * Called when user discards AI initialization from SpaceInitToast.
122
+ */
123
+ export async function revertSpaceInitAction(
124
+ spacePath: string,
125
+ name: string,
126
+ description: string,
127
+ ): Promise<{ success: boolean; error?: string }> {
128
+ try {
129
+ const mindRoot = getMindRoot();
130
+ const absDir = path.resolve(mindRoot, spacePath);
131
+ if (!absDir.startsWith(mindRoot)) {
132
+ return { success: false, error: 'Invalid path' };
133
+ }
134
+
135
+ const readmePath = path.join(absDir, 'README.md');
136
+ const instructionPath = path.join(absDir, 'INSTRUCTION.md');
137
+
138
+ const readmeContent = generateReadmeTemplate(spacePath, name, description);
139
+ fs.writeFileSync(readmePath, readmeContent, 'utf-8');
140
+
141
+ const dirName = cleanDirName(name);
142
+ fs.writeFileSync(instructionPath, INSTRUCTION_TEMPLATE(dirName), 'utf-8');
143
+
144
+ invalidateCache();
145
+ revalidatePath('/', 'layout');
146
+ return { success: true };
147
+ } catch (err) {
148
+ return { success: false, error: err instanceof Error ? err.message : 'Failed to revert' };
149
+ }
150
+ }
151
+
152
+ const EXAMPLE_PREFIX = '๐Ÿงช_example_';
153
+
154
+ export async function scanExampleFilesAction(): Promise<{ files: string[] }> {
155
+ const all = collectAllFiles();
156
+ const examples = all.filter(f => path.basename(f).startsWith(EXAMPLE_PREFIX));
157
+ return { files: examples };
158
+ }
159
+
160
+ export async function cleanupExamplesAction(): Promise<{ success: boolean; deleted: number; error?: string }> {
161
+ try {
162
+ const { files } = await scanExampleFilesAction();
163
+ if (files.length === 0) return { success: true, deleted: 0 };
164
+
165
+ const root = getMindRoot();
166
+ for (const relPath of files) {
167
+ const absPath = path.resolve(root, relPath);
168
+ if (absPath.startsWith(root) && fs.existsSync(absPath)) {
169
+ fs.unlinkSync(absPath);
170
+ }
171
+ }
172
+
173
+ // Clean up empty directories left behind
174
+ const dirs = new Set(files.map(f => path.dirname(path.resolve(root, f))));
175
+ const sortedDirs = [...dirs].sort((a, b) => b.length - a.length);
176
+ for (const dir of sortedDirs) {
177
+ try {
178
+ if (dir.startsWith(root) && dir !== root) {
179
+ const entries = fs.readdirSync(dir);
180
+ if (entries.length === 0) fs.rmdirSync(dir);
181
+ }
182
+ } catch { /* directory not empty or already removed */ }
183
+ }
184
+
185
+ invalidateCache();
186
+ revalidatePath('/', 'layout');
187
+ return { success: true, deleted: files.length };
188
+ } catch (err) {
189
+ return { success: false, deleted: 0, error: err instanceof Error ? err.message : 'Failed to cleanup' };
190
+ }
191
+ }
@@ -1,5 +1,5 @@
1
1
  export { getModelConfig } from './model';
2
- export { knowledgeBaseTools, WRITE_TOOLS, truncate } from './tools';
2
+ export { getRequestScopedTools, knowledgeBaseTools, WRITE_TOOLS, truncate } from './tools';
3
3
  export { AGENT_SYSTEM_PROMPT } from './prompt';
4
4
  export {
5
5
  estimateTokens, estimateStringTokens, getContextLimit, needsCompact,
@@ -27,6 +27,8 @@ Persona: Methodical, strictly objective, execution-oriented. Zero fluff. Never u
27
27
 
28
28
  - **Auto-loaded**: Configs, instructions, and SKILL.md are already in your context. Do not search for them unless explicitly asked.
29
29
  - **Uploaded Files**: Local files attached by the user appear in the "โš ๏ธ USER-UPLOADED FILES" section below. Use this content directly. Do NOT use tools to read/search them.
30
+ - **Skills**: Use the list_skills and load_skill tools to discover available skills on demand.
31
+ - **MCP**: The MindOS MCP server is built-in. Use list_mcp_tools and call_mcp_tool to inspect and invoke additional MCP tools configured in ~/.mindos/mcp.json.
30
32
 
31
33
  ## Output
32
34
 
@@ -1,3 +1,4 @@
1
+ import path from 'path';
1
2
  import { Type, type Static } from '@sinclair/typebox';
2
3
  import type { AgentTool, AgentToolResult } from '@mariozechner/pi-agent-core';
3
4
  import {
@@ -6,6 +7,8 @@ import {
6
7
  deleteFile, renameFile, moveFile, findBacklinks, gitLog, gitShowFile, appendCsvRow,
7
8
  getMindRoot,
8
9
  } from '@/lib/fs';
10
+ import { readSkillContentByName, scanSkillDirs } from '@/lib/pi-integration/skills';
11
+ import { callMcporterTool, createMcporterAgentTools, listMcporterServers, listMcporterTools } from '@/lib/pi-integration/mcporter';
9
12
 
10
13
  // Max chars per file to avoid token overflow (~100k chars โ‰ˆ ~25k tokens)
11
14
  const MAX_FILE_CHARS = 20_000;
@@ -146,6 +149,22 @@ const CsvAppendParams = Type.Object({
146
149
  row: Type.Array(Type.String(), { description: 'Array of cell values for the new row' }),
147
150
  });
148
151
 
152
+ const ListSkillsParams = Type.Object({});
153
+
154
+ const LoadSkillParams = Type.Object({
155
+ name: Type.String({ description: 'Skill name, e.g. "mindos" or "context7"' }),
156
+ });
157
+
158
+ const ListMcpToolsParams = Type.Object({
159
+ server: Type.Optional(Type.String({ description: 'Optional MCP server name. Omit to list discovered servers only.' })),
160
+ });
161
+
162
+ const CallMcpToolParams = Type.Object({
163
+ server: Type.String({ description: 'MCP server name discovered via list_mcp_tools' }),
164
+ tool: Type.String({ description: 'Exact MCP tool name to invoke' }),
165
+ arguments_json: Type.Optional(Type.String({ description: 'Optional JSON object string of tool arguments. Example: {"query":"react hooks"}' })),
166
+ });
167
+
149
168
  // โ”€โ”€โ”€ Tool Definitions (AgentTool interface) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
150
169
 
151
170
  // Write-operation tool names โ€” used by beforeToolCall for write-protection
@@ -154,6 +173,28 @@ export const WRITE_TOOLS = new Set([
154
173
  'update_section', 'edit_lines', 'delete_file', 'rename_file', 'move_file', 'append_csv',
155
174
  ]);
156
175
 
176
+ export async function getRequestScopedTools(): Promise<AgentTool<any>[]> {
177
+ try {
178
+ const result = await listMcporterServers();
179
+ const okServers = (result.servers ?? []).filter((server) => server.status === 'ok');
180
+ if (okServers.length === 0) return knowledgeBaseTools;
181
+
182
+ const detailedServers = await Promise.all(okServers.map(async (server) => {
183
+ try {
184
+ return await listMcporterTools(server.name);
185
+ } catch {
186
+ return server;
187
+ }
188
+ }));
189
+
190
+ const dynamicMcpTools = createMcporterAgentTools(detailedServers);
191
+ if (dynamicMcpTools.length === 0) return knowledgeBaseTools;
192
+ return [...knowledgeBaseTools, ...dynamicMcpTools];
193
+ } catch {
194
+ return knowledgeBaseTools;
195
+ }
196
+ }
197
+
157
198
  export const knowledgeBaseTools: AgentTool<any>[] = [
158
199
  {
159
200
  name: 'list_files',
@@ -251,6 +292,71 @@ export const knowledgeBaseTools: AgentTool<any>[] = [
251
292
  }),
252
293
  },
253
294
 
295
+ {
296
+ name: 'list_skills',
297
+ label: 'List Skills',
298
+ description: 'List available MindOS skills discovered from app/data/skills, skills, {mindRoot}/.skills, and ~/.mindos/skills. Use this before load_skill when you need a skill by name.',
299
+ parameters: ListSkillsParams,
300
+ execute: safeExecute(async () => {
301
+ const projectRoot = process.env.MINDOS_PROJECT_ROOT || path.resolve(process.cwd(), '..');
302
+ const skills = scanSkillDirs({ projectRoot, mindRoot: getMindRoot() });
303
+ if (skills.length === 0) return textResult('No skills found.');
304
+ return textResult(skills.map((skill) => `- **${skill.name}** [${skill.origin}]${skill.enabled ? '' : ' (disabled)'} โ€” ${skill.description || 'No description'}\n Path: ${skill.path}`).join('\n'));
305
+ }),
306
+ },
307
+
308
+ {
309
+ name: 'load_skill',
310
+ label: 'Load Skill',
311
+ description: 'Load the full content of a specific skill by name. Use list_skills first if you do not know the exact skill name.',
312
+ parameters: LoadSkillParams,
313
+ execute: safeExecute(async (_id, params: Static<typeof LoadSkillParams>) => {
314
+ const projectRoot = process.env.MINDOS_PROJECT_ROOT || path.resolve(process.cwd(), '..');
315
+ const content = readSkillContentByName(params.name, { projectRoot, mindRoot: getMindRoot() });
316
+ if (!content) return textResult(`Skill not found: ${params.name}`);
317
+ return textResult(truncate(content));
318
+ }),
319
+ },
320
+
321
+ {
322
+ name: 'list_mcp_tools',
323
+ label: 'List MCP Tools',
324
+ description: 'List MCP servers configured in ~/.mindos/mcp.json. Without `server`, lists discovered servers and their health. With `server`, lists that server\'s tools and JSON schemas.',
325
+ parameters: ListMcpToolsParams,
326
+ execute: safeExecute(async (_id, params: Static<typeof ListMcpToolsParams>) => {
327
+ if (!params.server) {
328
+ const result = await listMcporterServers();
329
+ if (!result.servers || result.servers.length === 0) return textResult('No external MCP servers configured. The MindOS built-in MCP server is always available.');
330
+ return textResult(result.servers.map((server) => `- **${server.name}** โ€” status: ${server.status}${server.transport ? ` | transport: ${server.transport}` : ''}${server.error ? ` | error: ${server.error}` : ''}`).join('\n'));
331
+ }
332
+
333
+ const server = await listMcporterTools(params.server);
334
+ if (!server.tools || server.tools.length === 0) {
335
+ return textResult(`No tools found for MCP server: ${params.server}`);
336
+ }
337
+ return textResult(server.tools.map((tool) => `## ${tool.name}\n${tool.description || 'No description'}\n\nSchema:\n${JSON.stringify(tool.inputSchema ?? {}, null, 2)}`).join('\n\n'));
338
+ }),
339
+ },
340
+
341
+ {
342
+ name: 'call_mcp_tool',
343
+ label: 'Call MCP Tool',
344
+ description: 'Call a specific MCP tool by server and tool name. Pass `arguments_json` as a JSON object string. Use list_mcp_tools first to discover names and schemas.',
345
+ parameters: CallMcpToolParams,
346
+ execute: safeExecute(async (_id, params: Static<typeof CallMcpToolParams>) => {
347
+ let parsedArgs: Record<string, unknown> = {};
348
+ if (params.arguments_json?.trim()) {
349
+ try {
350
+ parsedArgs = JSON.parse(params.arguments_json) as Record<string, unknown>;
351
+ } catch (error) {
352
+ return textResult(`Invalid arguments_json. Expected a JSON object string. Error: ${formatToolError(error)}`);
353
+ }
354
+ }
355
+ const output = await callMcporterTool(params.server, params.tool, parsedArgs);
356
+ return textResult(output || '(empty MCP response)');
357
+ }),
358
+ },
359
+
254
360
  {
255
361
  name: 'web_search',
256
362
  label: 'Web Search',
@@ -1,6 +1,16 @@
1
1
  import { MindOSError, ErrorCodes } from '@/lib/errors';
2
2
  import { createFile } from './fs-ops';
3
3
 
4
+ /**
5
+ * Generate the template README.md content for a new space.
6
+ * Extracted so both createSpaceFilesystem and revert can produce identical content.
7
+ */
8
+ export function generateReadmeTemplate(fullPath: string, name: string, description: string): string {
9
+ const cleanName = name.replace(/^[\p{Emoji_Presentation}\p{Extended_Pictographic}\s]+/u, '') || name;
10
+ const desc = description.trim() || '(Describe the purpose and usage of this space.)';
11
+ return `# ${cleanName}\n\n${desc}\n\n## ๐Ÿ“ Structure\n\n\`\`\`bash\n${fullPath}/\nโ”œโ”€โ”€ INSTRUCTION.md\nโ”œโ”€โ”€ README.md\nโ””โ”€โ”€ (your files here)\n\`\`\`\n\n## ๐Ÿ’ก Usage\n\n(Add usage guidelines for this space.)\n`;
12
+ }
13
+
4
14
  /**
5
15
  * Create a Mind Space on disk: `{fullPath}/README.md` plus scaffold from {@link createFile} / scaffoldIfNewSpace.
6
16
  * Caller must invalidate app file-tree cache (e.g. `invalidateCache()` in `lib/fs.ts`).
@@ -26,10 +36,7 @@ export function createSpaceFilesystem(
26
36
 
27
37
  const prefix = cleanParent ? `${cleanParent}/` : '';
28
38
  const fullPath = `${prefix}${trimmed}`;
29
-
30
- const cleanName = trimmed.replace(/^[\p{Emoji_Presentation}\p{Extended_Pictographic}\s]+/u, '') || trimmed;
31
- const desc = description.trim() || '(Describe the purpose and usage of this space.)';
32
- const readmeContent = `# ${cleanName}\n\n${desc}\n\n## ๐Ÿ“ Structure\n\n\`\`\`bash\n${fullPath}/\nโ”œโ”€โ”€ INSTRUCTION.md\nโ”œโ”€โ”€ README.md\nโ””โ”€โ”€ (your files here)\n\`\`\`\n\n## ๐Ÿ’ก Usage\n\n(Add usage guidelines for this space.)\n`;
39
+ const readmeContent = generateReadmeTemplate(fullPath, trimmed, description);
33
40
 
34
41
  createFile(mindRoot, `${fullPath}/README.md`, readmeContent);
35
42
  return { path: fullPath };
@@ -61,7 +61,7 @@ export { findBacklinks } from './backlinks';
61
61
  export { isGitRepo, gitLog, gitShowFile } from './git';
62
62
 
63
63
  // Mind Space
64
- export { createSpaceFilesystem } from './create-space';
64
+ export { createSpaceFilesystem, generateReadmeTemplate } from './create-space';
65
65
  export { summarizeTopLevelSpaces } from './list-spaces';
66
66
  export type { MindSpaceSummary } from './list-spaces';
67
67
 
@@ -28,6 +28,11 @@ export const en = {
28
28
  aiInit: 'AI initialize content',
29
29
  aiInitHint: 'AI will generate README and INSTRUCTION for this space',
30
30
  aiInitNoKey: 'Configure an API key in Settings โ†’ AI to enable',
31
+ aiInitGenerating: (name: string) => `Generating content for ${name}`,
32
+ aiInitReady: (name: string) => `${name} ready`,
33
+ aiInitReview: 'Review',
34
+ aiInitDiscard: 'Discard',
35
+ aiInitReverted: (name: string) => `${name} reverted to template`,
31
36
  createSpace: 'Create',
32
37
  cancelCreate: 'Cancel',
33
38
  continueEditing: 'Continue editing',
@@ -53,6 +58,9 @@ export const en = {
53
58
  hoursAgo: (n: number) => `${n}h ago`,
54
59
  daysAgo: (n: number) => `${n}d ago`,
55
60
  },
61
+ cleanupExamples: (n: number) => `${n} example file${n > 1 ? 's' : ''} from the template can be removed`,
62
+ cleanupExamplesButton: 'Clean up',
63
+ cleanupExamplesDone: 'Example files removed',
56
64
  },
57
65
  sidebar: {
58
66
  files: 'Spaces',
@@ -97,7 +105,7 @@ export const en = {
97
105
  },
98
106
  ask: {
99
107
  title: 'MindOS Agent',
100
- placeholder: 'Ask a question... or type @ to attach a file',
108
+ placeholder: 'Ask a question... @ files, / skills',
101
109
  emptyPrompt: 'Ask anything about your knowledge base',
102
110
  send: 'send',
103
111
  newlineHint: 'new line',
@@ -105,7 +113,9 @@ export const en = {
105
113
  panelComposerFooter: 'Resize height',
106
114
  panelComposerResetHint: 'Double-click to reset height',
107
115
  panelComposerKeyboard: 'Arrow keys adjust height; Home/End min/max',
108
- attachFile: 'attach file',
116
+ attachFile: 'Context',
117
+ uploadedFiles: 'Uploaded',
118
+ skillsHint: 'skills',
109
119
  attachCurrent: 'attach current file',
110
120
  stopTitle: 'Stop',
111
121
  connecting: 'Thinking with your mind...',
@@ -351,6 +361,9 @@ export const en = {
351
361
  enabledUnit: (n: number) => `${n} enabled`,
352
362
  agentCount: (n: number) => `${n} agent${n !== 1 ? 's' : ''}`,
353
363
  runtimeActive: 'Active',
364
+ riskMcpStopped: 'MCP server is not running.',
365
+ riskDetected: (n: number) => `${n} detected agent(s) need configuration.`,
366
+ riskSkillsDisabled: 'All skills are disabled.',
354
367
  },
355
368
  mcp: {
356
369
  title: 'MCP Connections',
@@ -384,6 +397,7 @@ export const en = {
384
397
  riskMcpStopped: 'MCP server is not running.',
385
398
  riskDetected: (n: number) => `${n} detected agent(s) need configuration.`,
386
399
  riskNotFound: (n: number) => `${n} agent(s) not found on this machine.`,
400
+ riskSkillsDisabled: 'All skills are disabled.',
387
401
  bulkReconnectFiltered: 'Reconnect all',
388
402
  bulkRunning: 'Running reconnect...',
389
403
  bulkSummary: (ok: number, failed: number) => `Reconnected ${ok}, failed ${failed}.`,
@@ -792,6 +806,15 @@ export const en = {
792
806
  authTokenResetConfirm: 'Regenerate token? All existing MCP clients will need to update their config.',
793
807
  authTokenMcpPort: 'MCP port',
794
808
  restartWalkthrough: 'Restart walkthrough',
809
+ showHiddenFiles: 'Show hidden files',
810
+ showHiddenFilesHint: 'Display dot-prefixed folders (.agents, .claude, .mindos, etc.) in the file tree.',
811
+ cleanupExamples: 'Clean up example files',
812
+ cleanupExamplesHint: 'Remove all template example files (๐Ÿงช_example_*) from your knowledge base.',
813
+ cleanupExamplesButton: 'Clean up',
814
+ cleanupExamplesNone: 'No example files found',
815
+ cleanupExamplesConfirm: (n: number) => `Delete ${n} example file${n > 1 ? 's' : ''}? This cannot be undone.`,
816
+ cleanupExamplesDone: (n: number) => `Removed ${n} example file${n > 1 ? 's' : ''}`,
817
+ cleanupExamplesScanning: 'Scanning...',
795
818
  },
796
819
  sync: {
797
820
  emptyTitle: 'Cross-device Sync',
@@ -1143,50 +1166,36 @@ export const en = {
1143
1166
  welcomeLinkMCP: 'MCP Settings',
1144
1167
  },
1145
1168
  guide: {
1146
- title: 'Get Started with MindOS',
1169
+ title: 'Quick Start',
1147
1170
  showGuide: 'Show getting started guide',
1148
1171
  close: 'Close',
1149
1172
  skip: 'Skip',
1150
- kb: {
1151
- title: 'Explore your knowledge base',
1152
- cta: 'Start',
1153
- fullDesc: 'Your knowledge base has 6 areas โ€” try clicking one:',
1154
- dirs: {
1155
- profile: 'Who you are, preferences, goals',
1156
- notes: 'Daily capture: ideas, meetings, todos',
1157
- connections: 'Your network of people',
1158
- workflows: 'Reusable process SOPs',
1159
- resources: 'Structured data: product lists, tool lists',
1160
- projects: 'Project plans and progress',
1161
- },
1162
- instructionHint: 'Click INSTRUCTION.md to see how AI agents behave.',
1163
- emptyDesc: 'Your knowledge base has 3 core files:',
1164
- emptyFiles: {
1165
- instruction: 'INSTRUCTION.md โ€” Rules that all AI agents follow',
1166
- readme: 'README.md โ€” Directory index and navigation',
1167
- config: 'CONFIG.json โ€” Machine-readable preferences',
1168
- },
1169
- emptyHint: 'Create your own folder structure anytime.',
1170
- progress: (n: number) => `Browsed ${n}/1 file`,
1171
- done: 'Done',
1173
+ import: {
1174
+ title: 'Import your files',
1175
+ cta: 'Import',
1176
+ desc: 'Upload your resume, project docs, or notes โ€” anything you want AI agents to know about you.',
1177
+ button: 'Import Files',
1172
1178
  },
1173
1179
  ai: {
1174
- title: 'Chat with AI',
1175
- cta: 'Start',
1176
- prompt: 'Read my knowledge base and help me write a self-introduction into Profile.',
1180
+ title: 'See AI read your content',
1181
+ cta: 'Try it',
1182
+ desc: 'Your files are in the knowledge base. Ask MindOS Agent what it learned:',
1183
+ prompt: 'Introduce me based on my knowledge base โ€” who am I and what am I working on?',
1177
1184
  promptEmpty: 'Help me design a knowledge base folder structure that fits my needs',
1178
1185
  },
1179
- sync: {
1180
- title: 'Sync Notes',
1181
- optional: 'Optional',
1182
- cta: 'Configure',
1186
+ agent: {
1187
+ title: 'Try in another Agent',
1188
+ cta: 'Copy prompt',
1189
+ desc: 'Open Cursor, Claude Code, or any MCP-connected Agent and paste this:',
1190
+ copyPrompt: 'Read my MindOS knowledge base and summarize my background, then suggest what I should focus on next.',
1191
+ copy: 'Copy',
1192
+ copied: 'Copied!',
1183
1193
  },
1184
1194
  done: {
1185
1195
  title: "You're all set!",
1186
1196
  titleFinal: "You've mastered MindOS essentials!",
1187
1197
  steps: [
1188
- { hint: 'Next: try saving an article โ†’', prompt: 'Help me save the key points from this article into MindOS.' },
1189
- { hint: 'Next: try using your KB in another Agent โ†’', prompt: 'Help me start coding based on the plan in MindOS.' },
1198
+ { hint: 'Next: try saving an article into your KB โ†’', prompt: 'Help me save the key points from this article into MindOS.' },
1190
1199
  { hint: 'Next: try turning experience into a reusable SOP โ†’', prompt: 'Help me distill this conversation into a reusable workflow in MindOS.' },
1191
1200
  ],
1192
1201
  },
@@ -1267,24 +1276,20 @@ prompt: "Here's my resume, read it and organize my info into MindOS.",
1267
1276
  exploreCta: 'Explore what you can do โ†’',
1268
1277
  steps: [
1269
1278
  {
1270
- title: 'Navigation',
1271
- body: 'This is your Activity Bar โ€” switch between Files, Search, Plugins, and Agents from here.',
1272
- },
1273
- {
1274
- title: 'Your Knowledge Base',
1275
- body: 'Browse and organize your notes, profiles, and projects in the file panel.',
1279
+ title: 'Your Project Memory',
1280
+ body: 'Organize projects, SOPs, and preferences in Spaces. Everything is local-first and under your control.',
1276
1281
  },
1277
1282
  {
1278
- title: 'Ask AI',
1279
- body: 'Chat with an AI that knows your entire knowledge base. Press โŒ˜/ anytime.',
1283
+ title: 'AI That Already Knows You',
1284
+ body: 'MindOS Agent reads your entire knowledge base automatically. Ask about your projects โ€” no need to re-explain anything.',
1280
1285
  },
1281
1286
  {
1282
- title: 'Quick Search',
1283
- body: 'Find any file instantly with โŒ˜K โ€” search across all your notes.',
1287
+ title: 'Connect Any Agent',
1288
+ body: 'Link Cursor, Claude Code, or Windsurf via MCP โ€” they all share the same project memory.',
1284
1289
  },
1285
1290
  {
1286
- title: 'Settings',
1287
- body: 'Configure AI providers, MCP connections, sync, and appearance here.',
1291
+ title: 'Echo โ€” Growth Compounds',
1292
+ body: 'About you, daily reflections, growth tracking โ€” MindOS helps you accumulate cognitive compound interest over time.',
1288
1293
  },
1289
1294
  ],
1290
1295
  },