@geminilight/mindos 0.5.19 → 0.5.21

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 (39) hide show
  1. package/app/app/api/ask/route.ts +308 -172
  2. package/app/app/api/file/route.ts +35 -11
  3. package/app/app/api/skills/route.ts +22 -3
  4. package/app/components/SettingsModal.tsx +52 -58
  5. package/app/components/Sidebar.tsx +21 -1
  6. package/app/components/settings/AiTab.tsx +4 -25
  7. package/app/components/settings/AppearanceTab.tsx +31 -13
  8. package/app/components/settings/KnowledgeTab.tsx +13 -28
  9. package/app/components/settings/McpAgentInstall.tsx +227 -0
  10. package/app/components/settings/McpServerStatus.tsx +172 -0
  11. package/app/components/settings/McpSkillsSection.tsx +583 -0
  12. package/app/components/settings/McpTab.tsx +16 -728
  13. package/app/components/settings/PluginsTab.tsx +4 -27
  14. package/app/components/settings/Primitives.tsx +69 -0
  15. package/app/components/settings/ShortcutsTab.tsx +2 -4
  16. package/app/components/settings/SyncTab.tsx +8 -24
  17. package/app/components/settings/types.ts +116 -2
  18. package/app/lib/agent/context.ts +151 -87
  19. package/app/lib/agent/index.ts +4 -3
  20. package/app/lib/agent/model.ts +76 -10
  21. package/app/lib/agent/stream-consumer.ts +73 -77
  22. package/app/lib/agent/to-agent-messages.ts +106 -0
  23. package/app/lib/agent/tools.ts +260 -266
  24. package/app/lib/i18n-en.ts +480 -0
  25. package/app/lib/i18n-zh.ts +505 -0
  26. package/app/lib/i18n.ts +4 -947
  27. package/app/next-env.d.ts +1 -1
  28. package/app/next.config.ts +7 -0
  29. package/app/package-lock.json +3258 -3093
  30. package/app/package.json +6 -3
  31. package/bin/cli.js +140 -5
  32. package/package.json +4 -1
  33. package/scripts/setup.js +13 -0
  34. package/skills/mindos/SKILL.md +10 -168
  35. package/skills/mindos-zh/SKILL.md +14 -172
  36. package/templates/skill-rules/en/skill-rules.md +222 -0
  37. package/templates/skill-rules/en/user-rules.md +20 -0
  38. package/templates/skill-rules/zh/skill-rules.md +222 -0
  39. package/templates/skill-rules/zh/user-rules.md +20 -0
@@ -2,12 +2,8 @@
2
2
 
3
3
  import { Puzzle } from 'lucide-react';
4
4
  import { getAllRenderers, setRendererEnabled } from '@/lib/renderers/registry';
5
-
6
- interface PluginsTabProps {
7
- pluginStates: Record<string, boolean>;
8
- setPluginStates: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
9
- t: any;
10
- }
5
+ import { Toggle } from './Primitives';
6
+ import type { PluginsTabProps } from './types';
11
7
 
12
8
  export function PluginsTab({ pluginStates, setPluginStates, t }: PluginsTabProps) {
13
9
  return (
@@ -58,28 +54,9 @@ export function PluginsTab({ pluginStates, setPluginStates, t }: PluginsTabProps
58
54
  </div>
59
55
 
60
56
  {isCore ? (
61
- <span
62
- className="shrink-0 w-9 h-5 rounded-full bg-amber-600 relative cursor-not-allowed opacity-60"
63
- title={t.settings.plugins.coreHint ?? 'Core renderer — always enabled'}
64
- >
65
- <span className="absolute top-[3px] left-[18px] w-3.5 h-3.5 rounded-full shadow-sm bg-white" />
66
- </span>
57
+ <Toggle checked={true} disabled />
67
58
  ) : (
68
- <button
69
- onClick={() => {
70
- const next = !enabled;
71
- setRendererEnabled(renderer.id, next);
72
- setPluginStates(s => ({ ...s, [renderer.id]: next }));
73
- }}
74
- role="switch"
75
- aria-checked={enabled}
76
- className={`shrink-0 w-9 h-5 rounded-full transition-colors relative ${enabled ? 'bg-amber-600' : 'bg-muted border border-border'}`}
77
- title={enabled ? t.settings.plugins.enabled : t.settings.plugins.disabled}
78
- >
79
- <span
80
- className={`absolute top-[3px] w-3.5 h-3.5 rounded-full shadow-sm transition-all ${enabled ? 'left-[18px] bg-white' : 'left-[3px] bg-muted-foreground/50'}`}
81
- />
82
- </button>
59
+ <Toggle checked={enabled} onChange={(next) => { setRendererEnabled(renderer.id, next); setPluginStates(s => ({ ...s, [renderer.id]: next })); }} title={enabled ? t.settings.plugins.enabled : t.settings.plugins.disabled} />
83
60
  )}
84
61
  </div>
85
62
  </div>
@@ -39,6 +39,50 @@ export function EnvBadge({ overridden }: { overridden: boolean }) {
39
39
  );
40
40
  }
41
41
 
42
+ /**
43
+ * 🟢 MINOR #6: Toggle component with aria accessibility
44
+ * @param {boolean} checked - Toggle state
45
+ * @param {function} onChange - Called when toggle state changes (if no onClick provided)
46
+ * @param {string} size - 'sm' (h-4 w-7) or 'md' (h-5 w-9)
47
+ * @param {boolean} disabled - Disable toggle
48
+ * @param {string} title - Tooltip text
49
+ * @param {function} onClick - Custom click handler (takes priority over onChange). Call onChange directly if needed.
50
+ *
51
+ * Usage:
52
+ * - Basic: `<Toggle checked={x} onChange={setX} />`
53
+ * - With custom handler: `<Toggle checked={x} onClick={(e) => { e.stopPropagation(); await save(); }} />`
54
+ * - In lists: Use `onClick` to prevent event bubbling; manually call `onChange` for state sync
55
+ */
56
+ export function Toggle({ checked, onChange, size = 'md', disabled, title, onClick }: {
57
+ checked: boolean;
58
+ onChange?: (checked: boolean) => void;
59
+ size?: 'sm' | 'md';
60
+ disabled?: boolean;
61
+ title?: string;
62
+ onClick?: (e: React.MouseEvent) => void;
63
+ }) {
64
+ const sm = size === 'sm';
65
+ return (
66
+ <button
67
+ type="button"
68
+ role="switch"
69
+ aria-checked={checked}
70
+ disabled={disabled}
71
+ title={title}
72
+ onClick={onClick ?? (() => onChange?.(!checked))}
73
+ className={`relative inline-flex shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-60 ${
74
+ sm ? 'h-4 w-7' : 'h-5 w-9'
75
+ } ${checked ? 'bg-amber-500' : 'bg-muted'}`}
76
+ >
77
+ <span
78
+ className={`pointer-events-none inline-block rounded-full bg-white shadow-sm transition-transform ${
79
+ sm ? 'h-3 w-3' : 'h-4 w-4'
80
+ } ${checked ? (sm ? 'translate-x-3' : 'translate-x-4') : 'translate-x-0'}`}
81
+ />
82
+ </button>
83
+ );
84
+ }
85
+
42
86
  export function ApiKeyInput({ value, onChange, placeholder, disabled }: {
43
87
  value: string;
44
88
  onChange: (v: string) => void;
@@ -58,3 +102,28 @@ export function ApiKeyInput({ value, onChange, placeholder, disabled }: {
58
102
  />
59
103
  );
60
104
  }
105
+
106
+ /**
107
+ * 💡 SUGGESTION #10: Unified primary button primitive for amber actions
108
+ * Replaces inline `style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}` pattern
109
+ */
110
+ export function PrimaryButton({ children, disabled, onClick, type = 'button', className = '', ...props }: {
111
+ children: React.ReactNode;
112
+ disabled?: boolean;
113
+ onClick?: () => void;
114
+ type?: 'button' | 'submit';
115
+ className?: string;
116
+ } & React.ButtonHTMLAttributes<HTMLButtonElement>) {
117
+ return (
118
+ <button
119
+ type={type}
120
+ onClick={onClick}
121
+ disabled={disabled}
122
+ className={`px-4 py-2 text-sm font-medium rounded-lg transition-colors disabled:opacity-40 disabled:cursor-not-allowed ${className}`}
123
+ style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}
124
+ {...props}
125
+ >
126
+ {children}
127
+ </button>
128
+ );
129
+ }
@@ -1,13 +1,11 @@
1
1
  'use client';
2
2
 
3
- interface ShortcutsTabProps {
4
- t: any;
5
- }
3
+ import type { ShortcutsTabProps } from './types';
6
4
 
7
5
  export function ShortcutsTab({ t }: ShortcutsTabProps) {
8
6
  return (
9
7
  <div className="space-y-1">
10
- {t.shortcuts.map((s: { description: string; keys: string[] }, i: number) => (
8
+ {t.shortcuts.map((s: { readonly description: string; readonly keys: readonly string[] }, i: number) => (
11
9
  <div key={i} className="flex items-center justify-between py-2.5 border-b border-border last:border-0">
12
10
  <span className="text-sm text-foreground">{s.description}</span>
13
11
  <div className="flex items-center gap-1">
@@ -2,26 +2,12 @@
2
2
 
3
3
  import { useState, useEffect, useCallback } from 'react';
4
4
  import { RefreshCw, AlertCircle, CheckCircle2, Loader2, GitBranch, ExternalLink, Eye, EyeOff } from 'lucide-react';
5
- import { SectionLabel } from './Primitives';
5
+ import { SectionLabel, PrimaryButton } from './Primitives';
6
6
  import { apiFetch } from '@/lib/api';
7
+ import type { SyncStatus, SyncTabProps } from './types';
8
+ import type { Messages } from '@/lib/i18n';
7
9
 
8
- export interface SyncStatus {
9
- enabled: boolean;
10
- provider?: string;
11
- remote?: string;
12
- branch?: string;
13
- lastSync?: string | null;
14
- lastPull?: string | null;
15
- unpushed?: string;
16
- conflicts?: Array<{ file: string; time: string }>;
17
- lastError?: string | null;
18
- autoCommitInterval?: number;
19
- autoPullInterval?: number;
20
- }
21
-
22
- interface SyncTabProps {
23
- t: any;
24
- }
10
+ export { SyncStatus }; // Re-export for backward compatibility
25
11
 
26
12
  export function timeAgo(iso: string | null | undefined): string {
27
13
  if (!iso) return 'never';
@@ -40,7 +26,7 @@ function isValidGitUrl(url: string): 'https' | 'ssh' | false {
40
26
  return false;
41
27
  }
42
28
 
43
- function SyncEmptyState({ t, onInitComplete }: { t: any; onInitComplete: () => void }) {
29
+ function SyncEmptyState({ t, onInitComplete }: { t: Messages; onInitComplete: () => void }) {
44
30
  const syncT = t.settings?.sync;
45
31
 
46
32
  const [remoteUrl, setRemoteUrl] = useState('');
@@ -169,18 +155,16 @@ function SyncEmptyState({ t, onInitComplete }: { t: any; onInitComplete: () => v
169
155
  </div>
170
156
 
171
157
  {/* Connect button */}
172
- <button
173
- type="button"
158
+ <PrimaryButton
174
159
  onClick={handleConnect}
175
160
  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: 'var(--amber-foreground)' }}
161
+ className="flex items-center gap-2"
178
162
  >
179
163
  {connecting && <Loader2 size={14} className="animate-spin" />}
180
164
  {connecting
181
165
  ? (syncT?.connecting ?? 'Connecting...')
182
166
  : (syncT?.connectButton ?? 'Connect & Start Sync')}
183
- </button>
167
+ </PrimaryButton>
184
168
 
185
169
  {/* Error */}
186
170
  {error && (
@@ -1,4 +1,5 @@
1
- import type { Locale } from '@/lib/i18n';
1
+ import type { Locale, Messages } from '@/lib/i18n';
2
+ import type React from 'react';
2
3
 
3
4
  export interface ProviderConfig {
4
5
  apiKey: string;
@@ -32,7 +33,7 @@ export interface SettingsData {
32
33
  envValues?: Record<string, string>;
33
34
  }
34
35
 
35
- export type Tab = 'ai' | 'appearance' | 'knowledge' | 'mcp' | 'plugins' | 'shortcuts' | 'sync';
36
+ export type Tab = 'ai' | 'appearance' | 'knowledge' | 'mcp' | 'plugins' | 'sync';
36
37
 
37
38
  export const CONTENT_WIDTHS = [
38
39
  { value: '680px', label: 'Narrow (680px)' },
@@ -47,3 +48,116 @@ export const FONTS = [
47
48
  { value: 'geist', label: 'Geist', style: { fontFamily: 'var(--font-geist-sans), sans-serif' } },
48
49
  { value: 'ibm-plex-mono', label: 'IBM Plex Mono (mono)', style: { fontFamily: "'IBM Plex Mono', monospace" } },
49
50
  ];
51
+
52
+ /* ── MCP Types ────────────────────────────────────────────────── */
53
+
54
+ export interface McpStatus {
55
+ running: boolean;
56
+ transport: string;
57
+ endpoint: string;
58
+ port: number;
59
+ toolCount: number;
60
+ authConfigured: boolean;
61
+ }
62
+
63
+ export interface AgentInfo {
64
+ key: string;
65
+ name: string;
66
+ present: boolean;
67
+ installed: boolean;
68
+ scope?: string;
69
+ transport?: string;
70
+ configPath?: string;
71
+ hasProjectScope: boolean;
72
+ hasGlobalScope: boolean;
73
+ preferredTransport: 'stdio' | 'http';
74
+ // Snippet generation fields
75
+ format: 'json' | 'toml';
76
+ configKey: string;
77
+ globalNestedKey?: string;
78
+ globalPath: string;
79
+ projectPath?: string | null;
80
+ }
81
+
82
+ export interface SkillInfo {
83
+ name: string;
84
+ description: string;
85
+ path: string;
86
+ source: 'builtin' | 'user';
87
+ enabled: boolean;
88
+ editable: boolean;
89
+ }
90
+
91
+ /** 🟢 MINOR #7: Moved from SyncTab.tsx for consistency */
92
+ export interface SyncStatus {
93
+ enabled: boolean;
94
+ provider?: string;
95
+ remote?: string;
96
+ branch?: string;
97
+ lastSync?: string | null;
98
+ lastPull?: string | null;
99
+ unpushed?: string;
100
+ conflicts?: Array<{ file: string; time: string }>;
101
+ lastError?: string | null;
102
+ autoCommitInterval?: number;
103
+ autoPullInterval?: number;
104
+ }
105
+
106
+ export interface McpTabProps {
107
+ t: Messages;
108
+ }
109
+
110
+ export interface AppearanceTabProps {
111
+ font: string;
112
+ setFont: (v: string) => void;
113
+ contentWidth: string;
114
+ setContentWidth: (v: string) => void;
115
+ dark: boolean;
116
+ setDark: (v: boolean) => void;
117
+ locale: Locale;
118
+ setLocale: (v: Locale) => void;
119
+ t: Messages;
120
+ }
121
+
122
+ export interface AiTabProps {
123
+ data: SettingsData;
124
+ updateAi: (patch: Partial<AiSettings>) => void;
125
+ updateAgent: (patch: Partial<AgentSettings>) => void;
126
+ t: Messages;
127
+ }
128
+
129
+ export interface KnowledgeTabProps {
130
+ data: SettingsData;
131
+ setData: React.Dispatch<React.SetStateAction<SettingsData | null>>;
132
+ t: Messages;
133
+ }
134
+
135
+ export interface PluginsTabProps {
136
+ pluginStates: Record<string, boolean>;
137
+ setPluginStates: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
138
+ t: Messages;
139
+ }
140
+
141
+ export interface SyncTabProps {
142
+ t: Messages;
143
+ }
144
+
145
+ export interface McpServerStatusProps {
146
+ status: McpStatus | null;
147
+ agents: AgentInfo[];
148
+ t: Messages;
149
+ }
150
+
151
+ export interface McpAgentInstallProps {
152
+ agents: AgentInfo[];
153
+ t: Messages;
154
+ onRefresh: () => void;
155
+ }
156
+
157
+ export interface McpSkillsSectionProps {
158
+ t: Messages;
159
+ }
160
+
161
+ export interface ShortcutsTabProps {
162
+ t: Messages;
163
+ }