@geminilight/mindos 0.6.29 → 0.6.31

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 (110) hide show
  1. package/README.md +10 -4
  2. package/README_zh.md +10 -4
  3. package/app/app/api/acp/config/route.ts +82 -0
  4. package/app/app/api/acp/detect/route.ts +71 -48
  5. package/app/app/api/acp/install/route.ts +51 -0
  6. package/app/app/api/acp/session/route.ts +141 -11
  7. package/app/app/api/ask/route.ts +126 -18
  8. package/app/app/api/export/route.ts +105 -0
  9. package/app/app/api/workflows/route.ts +156 -0
  10. package/app/app/globals.css +2 -2
  11. package/app/app/page.tsx +7 -2
  12. package/app/app/trash/page.tsx +7 -0
  13. package/app/app/view/[...path]/ViewPageClient.tsx +234 -2
  14. package/app/components/ActivityBar.tsx +12 -4
  15. package/app/components/AskModal.tsx +4 -1
  16. package/app/components/ExportModal.tsx +220 -0
  17. package/app/components/FileTree.tsx +42 -11
  18. package/app/components/HomeContent.tsx +92 -20
  19. package/app/components/MarkdownView.tsx +45 -10
  20. package/app/components/Panel.tsx +1 -0
  21. package/app/components/RightAskPanel.tsx +5 -1
  22. package/app/components/Sidebar.tsx +10 -1
  23. package/app/components/SidebarLayout.tsx +6 -0
  24. package/app/components/TrashPageClient.tsx +263 -0
  25. package/app/components/agents/AgentDetailContent.tsx +263 -47
  26. package/app/components/agents/AgentsContentPage.tsx +11 -0
  27. package/app/components/agents/AgentsPanelA2aTab.tsx +285 -46
  28. package/app/components/agents/AgentsPanelSessionsTab.tsx +166 -0
  29. package/app/components/agents/agents-content-model.ts +2 -2
  30. package/app/components/ask/AgentSelectorCapsule.tsx +218 -0
  31. package/app/components/ask/AskContent.tsx +197 -239
  32. package/app/components/ask/FileChip.tsx +82 -17
  33. package/app/components/ask/MentionPopover.tsx +21 -3
  34. package/app/components/ask/MessageList.tsx +30 -9
  35. package/app/components/ask/SlashCommandPopover.tsx +21 -3
  36. package/app/components/ask/ToolCallBlock.tsx +102 -18
  37. package/app/components/changes/ChangesContentPage.tsx +58 -14
  38. package/app/components/explore/ExploreContent.tsx +4 -7
  39. package/app/components/explore/UseCaseCard.tsx +18 -1
  40. package/app/components/explore/use-cases.generated.ts +76 -0
  41. package/app/components/explore/use-cases.yaml +185 -0
  42. package/app/components/panels/AgentsPanel.tsx +1 -0
  43. package/app/components/panels/AgentsPanelHubNav.tsx +9 -2
  44. package/app/components/panels/DiscoverPanel.tsx +1 -1
  45. package/app/components/panels/WorkflowsPanel.tsx +206 -0
  46. package/app/components/renderers/workflow-yaml/StepEditor.tsx +164 -0
  47. package/app/components/renderers/workflow-yaml/WorkflowEditor.tsx +211 -0
  48. package/app/components/renderers/workflow-yaml/WorkflowRunner.tsx +269 -0
  49. package/app/components/renderers/workflow-yaml/WorkflowYamlRenderer.tsx +126 -0
  50. package/app/components/renderers/workflow-yaml/execution.ts +229 -0
  51. package/app/components/renderers/workflow-yaml/index.ts +6 -0
  52. package/app/components/renderers/workflow-yaml/manifest.ts +21 -0
  53. package/app/components/renderers/workflow-yaml/parser.ts +172 -0
  54. package/app/components/renderers/workflow-yaml/selectors.tsx +574 -0
  55. package/app/components/renderers/workflow-yaml/serializer.ts +56 -0
  56. package/app/components/renderers/workflow-yaml/types.ts +46 -0
  57. package/app/components/settings/AiTab.tsx +191 -174
  58. package/app/components/settings/AppearanceTab.tsx +168 -77
  59. package/app/components/settings/KnowledgeTab.tsx +131 -136
  60. package/app/components/settings/McpTab.tsx +11 -11
  61. package/app/components/settings/Primitives.tsx +60 -0
  62. package/app/components/settings/SettingsContent.tsx +15 -8
  63. package/app/components/settings/SyncTab.tsx +12 -12
  64. package/app/components/settings/UninstallTab.tsx +8 -18
  65. package/app/components/settings/UpdateTab.tsx +82 -82
  66. package/app/components/settings/types.ts +17 -8
  67. package/app/hooks/useAcpConfig.ts +96 -0
  68. package/app/hooks/useAcpDetection.ts +69 -14
  69. package/app/hooks/useAcpRegistry.ts +46 -11
  70. package/app/hooks/useAskModal.ts +12 -5
  71. package/app/hooks/useAskPanel.ts +8 -5
  72. package/app/hooks/useAskSession.ts +19 -2
  73. package/app/hooks/useImageUpload.ts +152 -0
  74. package/app/lib/acp/acp-tools.ts +3 -1
  75. package/app/lib/acp/agent-descriptors.ts +274 -0
  76. package/app/lib/acp/bridge.ts +6 -0
  77. package/app/lib/acp/index.ts +20 -4
  78. package/app/lib/acp/registry.ts +74 -7
  79. package/app/lib/acp/session.ts +490 -28
  80. package/app/lib/acp/subprocess.ts +307 -21
  81. package/app/lib/acp/types.ts +158 -20
  82. package/app/lib/actions.ts +57 -3
  83. package/app/lib/agent/model.ts +18 -3
  84. package/app/lib/agent/stream-consumer.ts +18 -0
  85. package/app/lib/agent/to-agent-messages.ts +25 -2
  86. package/app/lib/agent/tools.ts +56 -9
  87. package/app/lib/core/export.ts +116 -0
  88. package/app/lib/core/trash.ts +241 -0
  89. package/app/lib/fs.ts +47 -0
  90. package/app/lib/hooks/usePinnedFiles.ts +90 -0
  91. package/app/lib/i18n/generated/explore-i18n.generated.ts +138 -0
  92. package/app/lib/i18n/index.ts +3 -0
  93. package/app/lib/i18n/modules/knowledge.ts +124 -6
  94. package/app/lib/i18n/modules/navigation.ts +2 -0
  95. package/app/lib/i18n/modules/onboarding.ts +2 -134
  96. package/app/lib/i18n/modules/panels.ts +146 -2
  97. package/app/lib/i18n/modules/settings.ts +12 -0
  98. package/app/lib/pi-integration/skills.ts +21 -6
  99. package/app/lib/renderers/index.ts +2 -2
  100. package/app/lib/settings.ts +10 -0
  101. package/app/lib/types.ts +12 -1
  102. package/app/next-env.d.ts +1 -1
  103. package/app/package.json +11 -3
  104. package/app/scripts/generate-explore.ts +145 -0
  105. package/package.json +1 -1
  106. package/templates/en/.mindos/workflows/Sprint Release.flow.yaml +130 -0
  107. package/templates/zh/.mindos/workflows//345/221/250/350/277/255/344/273/243/346/243/200/346/237/245.flow.yaml +84 -0
  108. package/app/components/explore/use-cases.ts +0 -58
  109. package/app/components/renderers/workflow/WorkflowRenderer.tsx +0 -409
  110. package/app/components/renderers/workflow/manifest.ts +0 -14
@@ -0,0 +1,241 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ // ─── Types ───────────────────────────────────────────────────────────────────
5
+
6
+ export interface TrashMeta {
7
+ id: string;
8
+ originalPath: string;
9
+ deletedAt: string;
10
+ expiresAt: string;
11
+ fileName: string;
12
+ isDirectory: boolean;
13
+ }
14
+
15
+ const TRASH_DIR = '.trash';
16
+ const META_DIR = '.trash-meta';
17
+ const EXPIRY_DAYS = 30;
18
+
19
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
20
+
21
+ function siblingDir(mindRoot: string, name: string): string {
22
+ return path.join(path.dirname(mindRoot), name);
23
+ }
24
+
25
+ function trashRoot(mindRoot: string): string {
26
+ return siblingDir(mindRoot, TRASH_DIR);
27
+ }
28
+
29
+ function metaRoot(mindRoot: string): string {
30
+ return siblingDir(mindRoot, META_DIR);
31
+ }
32
+
33
+ function ensureDirs(mindRoot: string): void {
34
+ fs.mkdirSync(trashRoot(mindRoot), { recursive: true });
35
+ fs.mkdirSync(metaRoot(mindRoot), { recursive: true });
36
+ }
37
+
38
+ /** Sanitize filename for use as trash ID — strip all unsafe characters */
39
+ function generateId(fileName: string): string {
40
+ const safe = fileName.replace(/[^a-zA-Z0-9._\-\u4e00-\u9fff]/g, '_');
41
+ return `${Date.now()}_${safe}`;
42
+ }
43
+
44
+ function writeMeta(mindRoot: string, meta: TrashMeta): void {
45
+ const metaPath = path.join(metaRoot(mindRoot), `${meta.id}.json`);
46
+ fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2), 'utf-8');
47
+ }
48
+
49
+ function readMeta(mindRoot: string, id: string): TrashMeta | null {
50
+ const metaPath = path.join(metaRoot(mindRoot), `${id}.json`);
51
+ if (!fs.existsSync(metaPath)) return null;
52
+ try {
53
+ return JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ function deleteMeta(mindRoot: string, id: string): void {
60
+ const metaPath = path.join(metaRoot(mindRoot), `${id}.json`);
61
+ try { fs.unlinkSync(metaPath); } catch { /* already gone */ }
62
+ }
63
+
64
+ /**
65
+ * Move a file or directory safely, handling cross-filesystem (EXDEV) errors.
66
+ * Tries atomic rename first, falls back to copy+delete.
67
+ */
68
+ function safeMove(src: string, dest: string, isDir: boolean): void {
69
+ if (isDir) {
70
+ // Directories always use copy+delete (rename doesn't work for dirs across fs)
71
+ fs.cpSync(src, dest, { recursive: true });
72
+ fs.rmSync(src, { recursive: true, force: true });
73
+ } else {
74
+ try {
75
+ fs.renameSync(src, dest);
76
+ } catch (err: unknown) {
77
+ const e = err as NodeJS.ErrnoException;
78
+ if (e.code === 'EXDEV') {
79
+ // Cross-device: fallback to copy+delete
80
+ fs.copyFileSync(src, dest);
81
+ fs.unlinkSync(src);
82
+ } else {
83
+ throw err;
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ // ─── Core Operations ─────────────────────────────────────────────────────────
90
+
91
+ export function moveToTrash(mindRoot: string, filePath: string): TrashMeta {
92
+ ensureDirs(mindRoot);
93
+ const src = path.join(mindRoot, filePath);
94
+ if (!fs.existsSync(src)) throw new Error(`File not found: ${filePath}`);
95
+
96
+ const isDir = fs.statSync(src).isDirectory();
97
+ const fileName = path.basename(filePath);
98
+ const id = generateId(fileName);
99
+ const dest = path.join(trashRoot(mindRoot), id);
100
+
101
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
102
+ safeMove(src, dest, isDir);
103
+
104
+ const now = new Date();
105
+ const meta: TrashMeta = {
106
+ id,
107
+ originalPath: filePath,
108
+ deletedAt: now.toISOString(),
109
+ expiresAt: new Date(now.getTime() + EXPIRY_DAYS * 86400000).toISOString(),
110
+ fileName,
111
+ isDirectory: isDir,
112
+ };
113
+ writeMeta(mindRoot, meta);
114
+ return meta;
115
+ }
116
+
117
+ export function restoreFromTrash(mindRoot: string, trashId: string, overwrite = false): { restoredPath: string } {
118
+ const meta = readMeta(mindRoot, trashId);
119
+ if (!meta) throw new Error('Item not found in trash');
120
+
121
+ const trashPath = path.join(trashRoot(mindRoot), trashId);
122
+ if (!fs.existsSync(trashPath)) throw new Error('Trash file missing from disk');
123
+
124
+ const dest = path.join(mindRoot, meta.originalPath);
125
+
126
+ // Check for conflicts
127
+ if (fs.existsSync(dest) && !overwrite) {
128
+ throw Object.assign(new Error('Restore conflict: file exists at original location'), { code: 'RESTORE_CONFLICT' });
129
+ }
130
+
131
+ // Ensure parent directory exists
132
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
133
+
134
+ if (meta.isDirectory) {
135
+ if (overwrite && fs.existsSync(dest)) {
136
+ fs.rmSync(dest, { recursive: true, force: true });
137
+ }
138
+ } else {
139
+ if (overwrite && fs.existsSync(dest)) {
140
+ fs.unlinkSync(dest);
141
+ }
142
+ }
143
+
144
+ safeMove(trashPath, dest, meta.isDirectory);
145
+ deleteMeta(mindRoot, trashId);
146
+ return { restoredPath: meta.originalPath };
147
+ }
148
+
149
+ export function restoreAsCopy(mindRoot: string, trashId: string): { restoredPath: string } {
150
+ const meta = readMeta(mindRoot, trashId);
151
+ if (!meta) throw new Error('Item not found in trash');
152
+
153
+ const trashPath = path.join(trashRoot(mindRoot), trashId);
154
+ if (!fs.existsSync(trashPath)) throw new Error('Trash file missing from disk');
155
+
156
+ // Generate a unique copy name
157
+ const dir = path.dirname(meta.originalPath);
158
+ const ext = path.extname(meta.fileName);
159
+ const base = path.basename(meta.fileName, ext);
160
+ let copyPath = path.join(dir, `${base} (copy)${ext}`);
161
+ let counter = 2;
162
+ while (fs.existsSync(path.join(mindRoot, copyPath))) {
163
+ copyPath = path.join(dir, `${base} (copy ${counter})${ext}`);
164
+ counter++;
165
+ }
166
+
167
+ const dest = path.join(mindRoot, copyPath);
168
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
169
+ safeMove(trashPath, dest, meta.isDirectory);
170
+
171
+ deleteMeta(mindRoot, trashId);
172
+ return { restoredPath: copyPath };
173
+ }
174
+
175
+ export function permanentlyDelete(mindRoot: string, trashId: string): void {
176
+ const trashPath = path.join(trashRoot(mindRoot), trashId);
177
+ try {
178
+ if (fs.existsSync(trashPath)) {
179
+ const stat = fs.statSync(trashPath);
180
+ if (stat.isDirectory()) {
181
+ fs.rmSync(trashPath, { recursive: true, force: true });
182
+ } else {
183
+ fs.unlinkSync(trashPath);
184
+ }
185
+ }
186
+ } catch { /* file already gone */ }
187
+ deleteMeta(mindRoot, trashId);
188
+ }
189
+
190
+ export function listTrash(mindRoot: string): TrashMeta[] {
191
+ ensureDirs(mindRoot);
192
+ const metaDir = metaRoot(mindRoot);
193
+ let files: string[];
194
+ try {
195
+ files = fs.readdirSync(metaDir).filter(f => f.endsWith('.json'));
196
+ } catch {
197
+ return [];
198
+ }
199
+ const items: TrashMeta[] = [];
200
+
201
+ for (const file of files) {
202
+ try {
203
+ const meta = JSON.parse(fs.readFileSync(path.join(metaDir, file), 'utf-8')) as TrashMeta;
204
+ // Verify the trash file still exists on disk
205
+ const trashPath = path.join(trashRoot(mindRoot), meta.id);
206
+ if (fs.existsSync(trashPath)) {
207
+ items.push(meta);
208
+ } else {
209
+ // Clean up orphaned metadata
210
+ try { fs.unlinkSync(path.join(metaDir, file)); } catch { /* race ok */ }
211
+ }
212
+ } catch {
213
+ // Skip corrupt metadata files
214
+ }
215
+ }
216
+
217
+ // Sort by deletion time, newest first
218
+ items.sort((a, b) => new Date(b.deletedAt).getTime() - new Date(a.deletedAt).getTime());
219
+ return items;
220
+ }
221
+
222
+ export function emptyTrash(mindRoot: string): number {
223
+ const items = listTrash(mindRoot);
224
+ for (const item of items) {
225
+ permanentlyDelete(mindRoot, item.id);
226
+ }
227
+ return items.length;
228
+ }
229
+
230
+ export function purgeExpired(mindRoot: string): number {
231
+ const items = listTrash(mindRoot);
232
+ const now = Date.now();
233
+ let count = 0;
234
+ for (const item of items) {
235
+ if (new Date(item.expiresAt).getTime() <= now) {
236
+ permanentlyDelete(mindRoot, item.id);
237
+ count++;
238
+ }
239
+ }
240
+ return count;
241
+ }
package/app/lib/fs.ts CHANGED
@@ -601,6 +601,53 @@ export type { BacklinkEntry } from './core/types';
601
601
  export type { MindSpaceSummary } from './core';
602
602
  export type { ContentChangeEvent, ContentChangeInput, ContentChangeSummary, ContentChangeSource } from './core';
603
603
 
604
+ // ─── Public API: Trash (delegated to @mindos/core/trash) ────────────────────
605
+
606
+ import {
607
+ moveToTrash as coreMoveToTrash,
608
+ restoreFromTrash as coreRestoreFromTrash,
609
+ restoreAsCopy as coreRestoreAsCopy,
610
+ permanentlyDelete as corePermanentlyDelete,
611
+ listTrash as coreListTrash,
612
+ emptyTrash as coreEmptyTrash,
613
+ purgeExpired as corePurgeExpired,
614
+ } from './core/trash';
615
+ export type { TrashMeta } from './core/trash';
616
+
617
+ export function moveToTrashFile(filePath: string) {
618
+ const result = coreMoveToTrash(getMindRoot(), filePath);
619
+ invalidateCache();
620
+ return result;
621
+ }
622
+
623
+ export function restoreFromTrash(trashId: string, overwrite = false) {
624
+ const result = coreRestoreFromTrash(getMindRoot(), trashId, overwrite);
625
+ invalidateCache();
626
+ return result;
627
+ }
628
+
629
+ export function restoreAsCopy(trashId: string) {
630
+ const result = coreRestoreAsCopy(getMindRoot(), trashId);
631
+ invalidateCache();
632
+ return result;
633
+ }
634
+
635
+ export function permanentlyDeleteFromTrash(trashId: string) {
636
+ corePermanentlyDelete(getMindRoot(), trashId);
637
+ }
638
+
639
+ export function listTrash() {
640
+ return coreListTrash(getMindRoot());
641
+ }
642
+
643
+ export function emptyTrashAll() {
644
+ return coreEmptyTrash(getMindRoot());
645
+ }
646
+
647
+ export function purgeExpiredTrash() {
648
+ return corePurgeExpired(getMindRoot());
649
+ }
650
+
604
651
  export function findBacklinks(targetPath: string): BacklinkEntry[] {
605
652
  const { allFiles } = ensureCache();
606
653
  return coreFindBacklinks(getMindRoot(), targetPath, allFiles);
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+
3
+ import { useSyncExternalStore, useCallback } from 'react';
4
+
5
+ const STORAGE_KEY = 'mindos-pinned-files';
6
+ const EVENT_KEY = 'mindos:pins-changed';
7
+
8
+ function getSnapshot(): string[] {
9
+ if (typeof window === 'undefined') return [];
10
+ try {
11
+ const raw = localStorage.getItem(STORAGE_KEY);
12
+ return raw ? JSON.parse(raw) : [];
13
+ } catch {
14
+ return [];
15
+ }
16
+ }
17
+
18
+ function getServerSnapshot(): string[] {
19
+ return [];
20
+ }
21
+
22
+ // Lazy init — avoid calling getSnapshot() at module load time during SSR
23
+ let cachedPins: string[] = [];
24
+ let initialized = false;
25
+
26
+ function ensureInit(): void {
27
+ if (!initialized && typeof window !== 'undefined') {
28
+ cachedPins = getSnapshot();
29
+ initialized = true;
30
+ }
31
+ }
32
+
33
+ function subscribe(callback: () => void): () => void {
34
+ ensureInit();
35
+ const onStorage = (e: StorageEvent) => {
36
+ if (e.key === STORAGE_KEY) {
37
+ cachedPins = getSnapshot();
38
+ callback();
39
+ }
40
+ };
41
+ const onCustom = () => {
42
+ cachedPins = getSnapshot();
43
+ callback();
44
+ };
45
+ window.addEventListener('storage', onStorage);
46
+ window.addEventListener(EVENT_KEY, onCustom);
47
+ return () => {
48
+ window.removeEventListener('storage', onStorage);
49
+ window.removeEventListener(EVENT_KEY, onCustom);
50
+ };
51
+ }
52
+
53
+ function writePins(pins: string[]): void {
54
+ cachedPins = pins;
55
+ try {
56
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(pins));
57
+ } catch {
58
+ // localStorage unavailable (private browsing, quota exceeded) — memory only
59
+ }
60
+ window.dispatchEvent(new Event(EVENT_KEY));
61
+ }
62
+
63
+ export function usePinnedFiles() {
64
+ ensureInit();
65
+ const pins = useSyncExternalStore(subscribe, () => cachedPins, getServerSnapshot);
66
+
67
+ const isPinned = useCallback((path: string) => pins.includes(path), [pins]);
68
+
69
+ const togglePin = useCallback((path: string) => {
70
+ const current = getSnapshot();
71
+ const idx = current.indexOf(path);
72
+ if (idx >= 0) {
73
+ current.splice(idx, 1);
74
+ } else {
75
+ current.unshift(path); // newest pin at top
76
+ }
77
+ writePins(current);
78
+ }, []);
79
+
80
+ const reorderPins = useCallback((newOrder: string[]) => {
81
+ writePins(newOrder);
82
+ }, []);
83
+
84
+ const removePin = useCallback((path: string) => {
85
+ const current = getSnapshot();
86
+ writePins(current.filter(p => p !== path));
87
+ }, []);
88
+
89
+ return { pinnedFiles: pins, isPinned, togglePin, reorderPins, removePin };
90
+ }
@@ -0,0 +1,138 @@
1
+ // ⚠️ AUTO-GENERATED — DO NOT EDIT. Source: components/explore/use-cases.yaml
2
+ // Run `npm run generate` to regenerate.
3
+
4
+ export const exploreEn = {
5
+ "title": "Explore Use Cases",
6
+ "subtitle": "Discover what you can do with MindOS — pick a scenario and try it now.",
7
+ "tryIt": "Try it",
8
+ "all": "All",
9
+ "byCapability": "By Capability",
10
+ "byScenario": "By Scenario",
11
+ "categories": {
12
+ "knowledge-management": "Knowledge Management",
13
+ "memory-sync": "Memory Sync",
14
+ "auto-execute": "Auto Execute",
15
+ "experience-evolution": "Experience Evolution",
16
+ "human-insights": "Human Insights",
17
+ "audit-control": "Audit & Control"
18
+ },
19
+ "scenarios": {
20
+ "first-day": "First Day",
21
+ "daily": "Daily Work",
22
+ "project": "Project Work",
23
+ "advanced": "Advanced"
24
+ },
25
+ "c1": {
26
+ "title": "Inject Your Identity",
27
+ "desc": "Tell all AI agents who you are — preferences, tech stack, communication style — in one shot.",
28
+ "prompt": "Here's my resume, read it and organize my info into MindOS."
29
+ },
30
+ "c2": {
31
+ "title": "Save Information",
32
+ "desc": "Archive articles, meeting notes, or web pages into your knowledge base with one prompt.",
33
+ "prompt": "Help me save the key points from this article into MindOS."
34
+ },
35
+ "c3": {
36
+ "title": "Cross-Agent Handoff",
37
+ "desc": "Start a plan in MindOS, continue coding in Claude Code, refine in Cursor — zero context loss.",
38
+ "prompt": "Help me start coding based on the plan in MindOS."
39
+ },
40
+ "c4": {
41
+ "title": "Experience → SOP",
42
+ "desc": "Turn hard-won debugging sessions into reusable workflows that prevent future mistakes.",
43
+ "prompt": "Help me distill this conversation into a reusable workflow in MindOS."
44
+ },
45
+ "c5": {
46
+ "title": "Capture Ideas on the Go",
47
+ "desc": "Jot down an inspiration on your phone — MindOS archives, decomposes, and assigns to agents.",
48
+ "prompt": "Help me organize this idea into MindOS and break it into actionable sub-tasks."
49
+ },
50
+ "c6": {
51
+ "title": "Project Cold Start",
52
+ "desc": "Spin up a new project in 4 minutes — your profile and SOPs guide the scaffolding automatically.",
53
+ "prompt": "Help me start a new project following the Startup SOP in MindOS."
54
+ },
55
+ "c7": {
56
+ "title": "Research & Archive",
57
+ "desc": "Let agents research competitors or topics for you, then file structured results in your KB.",
58
+ "prompt": "Help me research X, Y, Z products and save results to the MindOS product library."
59
+ },
60
+ "c8": {
61
+ "title": "Network Management",
62
+ "desc": "Log conversations with contacts, auto-generate follow-up TODOs, and keep full context.",
63
+ "prompt": "I met with someone today — update MindOS Connections and create follow-up TODOs."
64
+ },
65
+ "c9": {
66
+ "title": "Audit & Correct",
67
+ "desc": "Review what agents know about you, fix mistakes in one place, and all agents update instantly.",
68
+ "prompt": "Check my MindOS Profile for accuracy and correct any errors."
69
+ }
70
+ } as const;
71
+
72
+ export const exploreZh = {
73
+ "title": "探索使用场景",
74
+ "subtitle": "发现 MindOS 能帮你做什么 — 选一个场景,立即体验。",
75
+ "tryIt": "试一试",
76
+ "all": "全部",
77
+ "byCapability": "按能力",
78
+ "byScenario": "按场景",
79
+ "categories": {
80
+ "knowledge-management": "知识管理",
81
+ "memory-sync": "记忆同步",
82
+ "auto-execute": "自动执行",
83
+ "experience-evolution": "经验进化",
84
+ "human-insights": "人类洞察",
85
+ "audit-control": "审计纠错"
86
+ },
87
+ "scenarios": {
88
+ "first-day": "初次使用",
89
+ "daily": "日常工作",
90
+ "project": "项目协作",
91
+ "advanced": "高级"
92
+ },
93
+ "c1": {
94
+ "title": "注入身份",
95
+ "desc": "让所有 AI Agent 一次认识你 — 偏好、技术栈、沟通风格。",
96
+ "prompt": "这是我的简历,读一下,把我的信息整理到 MindOS 里。"
97
+ },
98
+ "c2": {
99
+ "title": "注入信息",
100
+ "desc": "一句话归档文章、会议纪要或网页到知识库,全局可搜。",
101
+ "prompt": "帮我把这篇文章的要点整理到 MindOS 里。"
102
+ },
103
+ "c3": {
104
+ "title": "跨 Agent 切换",
105
+ "desc": "在 MindOS 写方案,在 Claude Code 写代码,在 Cursor 优化 — 零重复。",
106
+ "prompt": "帮我按 MindOS 里的 XXX 方案开始写代码。"
107
+ },
108
+ "c4": {
109
+ "title": "经验→SOP",
110
+ "desc": "把踩坑经验沉淀为可复用的工作流,下次 3 分钟搞定。",
111
+ "prompt": "帮我把这次对话的经验沉淀到 MindOS,形成可复用的工作流。"
112
+ },
113
+ "c5": {
114
+ "title": "手机记灵感",
115
+ "desc": "随手记下灵感,MindOS 自动归档、拆任务、多 Agent 接力执行。",
116
+ "prompt": "帮我把这个想法整理到 MindOS,拆解成可执行的子任务。"
117
+ },
118
+ "c6": {
119
+ "title": "项目冷启动",
120
+ "desc": "4 分钟搭建新项目 — Profile 和 SOP 自动引导脚手架。",
121
+ "prompt": "帮我按 MindOS 里的 Startup SOP 启动一个新项目。"
122
+ },
123
+ "c7": {
124
+ "title": "调研入库",
125
+ "desc": "让 Agent 替你跑腿调研竞品或话题,结果结构化入库。",
126
+ "prompt": "帮我调研 X、Y、Z 这几个产品,结果写入 MindOS 产品库。"
127
+ },
128
+ "c8": {
129
+ "title": "人脉管理",
130
+ "desc": "记录对话、自动生成跟进待办,每个联系人都有完整上下文。",
131
+ "prompt": "我今天和 XXX 聊了这些内容,帮我更新到 MindOS 并生成跟进待办。"
132
+ },
133
+ "c9": {
134
+ "title": "审计纠偏",
135
+ "desc": "审查 Agent 记了什么,一处修正,全局生效。",
136
+ "prompt": "帮我检查 MindOS Profile 里的技术栈偏好是否正确,有错误帮我修正。"
137
+ }
138
+ } as const;
@@ -7,6 +7,7 @@ import { panelsEn, panelsZh } from './modules/panels';
7
7
  import { settingsEn, settingsZh } from './modules/settings';
8
8
  import { onboardingEn, onboardingZh } from './modules/onboarding';
9
9
  import { featuresEn, featuresZh } from './modules/features';
10
+ import { exploreEn, exploreZh } from './generated/explore-i18n.generated';
10
11
 
11
12
  export const en = {
12
13
  ...commonEn,
@@ -17,6 +18,7 @@ export const en = {
17
18
  ...settingsEn,
18
19
  ...onboardingEn,
19
20
  ...featuresEn,
21
+ explore: exploreEn,
20
22
  } as const;
21
23
 
22
24
  export const zh: Widen<typeof en> = {
@@ -28,6 +30,7 @@ export const zh: Widen<typeof en> = {
28
30
  ...settingsZh,
29
31
  ...onboardingZh,
30
32
  ...featuresZh,
33
+ explore: exploreZh,
31
34
  };
32
35
 
33
36
  export type Locale = 'en' | 'zh';