@geminilight/mindos 0.5.49 → 0.5.50

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.
@@ -0,0 +1,12 @@
1
+ import { redirect } from 'next/navigation';
2
+ import { readSettings } from '@/lib/settings';
3
+ import HelpContent from '@/components/help/HelpContent';
4
+
5
+ export const dynamic = 'force-dynamic';
6
+
7
+ export default function HelpPage() {
8
+ const settings = readSettings();
9
+ if (settings.setupPending) redirect('/setup');
10
+
11
+ return <HelpContent />;
12
+ }
@@ -0,0 +1,229 @@
1
+ 'use client';
2
+
3
+ import { useState, useMemo, useCallback } from 'react';
4
+ import { BookOpen, Rocket, Brain, Keyboard, HelpCircle, Bot, ChevronDown, Copy, Check } from 'lucide-react';
5
+ import { useLocale } from '@/lib/LocaleContext';
6
+
7
+ /* ── Collapsible Section ── */
8
+ function Section({ icon, title, defaultOpen = false, children }: {
9
+ icon: React.ReactNode;
10
+ title: string;
11
+ defaultOpen?: boolean;
12
+ children: React.ReactNode;
13
+ }) {
14
+ const [open, setOpen] = useState(defaultOpen);
15
+
16
+ return (
17
+ <div className="bg-card border border-border rounded-lg overflow-hidden">
18
+ <button
19
+ onClick={() => setOpen(v => !v)}
20
+ className="w-full flex items-center gap-3 px-5 py-4 text-left hover:bg-muted/50 transition-colors focus-visible:ring-2 focus-visible:ring-ring"
21
+ aria-expanded={open}
22
+ >
23
+ <span className="text-[var(--amber)]">{icon}</span>
24
+ <span className="text-base font-medium font-display text-foreground flex-1">{title}</span>
25
+ <ChevronDown size={16} className={`text-muted-foreground transition-transform duration-200 ${open ? 'rotate-180' : ''}`} />
26
+ </button>
27
+ {open && (
28
+ <div className="px-5 pb-5 pt-0">
29
+ <div className="border-t border-border pt-4">
30
+ {children}
31
+ </div>
32
+ </div>
33
+ )}
34
+ </div>
35
+ );
36
+ }
37
+
38
+ /* ── Step Card ── */
39
+ function StepCard({ step, title, desc }: { step: number; title: string; desc: string }) {
40
+ return (
41
+ <div className="flex gap-4 items-start">
42
+ <div className="shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold font-mono" style={{ background: 'var(--amber-dim)', color: 'var(--amber)' }}>
43
+ {step}
44
+ </div>
45
+ <div className="min-w-0">
46
+ <p className="text-sm font-medium text-foreground">{title}</p>
47
+ <p className="text-sm text-muted-foreground mt-0.5">{desc}</p>
48
+ </div>
49
+ </div>
50
+ );
51
+ }
52
+
53
+ /* ── Copyable Prompt Block ── */
54
+ function PromptBlock({ text, copyLabel }: { text: string; copyLabel: string }) {
55
+ const [copied, setCopied] = useState(false);
56
+
57
+ const handleCopy = useCallback(() => {
58
+ const clean = text.replace(/^[""]|[""]$/g, '');
59
+ navigator.clipboard.writeText(clean).then(() => {
60
+ setCopied(true);
61
+ setTimeout(() => setCopied(false), 1500);
62
+ });
63
+ }, [text]);
64
+
65
+ return (
66
+ <div className="group/prompt mt-2 flex items-start gap-2 bg-background border border-border rounded-md px-3 py-2">
67
+ <p className="flex-1 text-xs font-mono leading-relaxed" style={{ color: 'var(--amber)' }}>{text}</p>
68
+ <button
69
+ onClick={handleCopy}
70
+ className="shrink-0 p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors opacity-0 group-hover/prompt:opacity-100 focus-visible:opacity-100"
71
+ aria-label={copyLabel}
72
+ title={copyLabel}
73
+ >
74
+ {copied ? <Check size={13} className="text-success" /> : <Copy size={13} />}
75
+ </button>
76
+ </div>
77
+ );
78
+ }
79
+
80
+ /* ── FAQ Item ── */
81
+ function FaqItem({ q, a }: { q: string; a: string }) {
82
+ const [open, setOpen] = useState(false);
83
+
84
+ return (
85
+ <div className="border-b border-border last:border-b-0">
86
+ <button
87
+ onClick={() => setOpen(v => !v)}
88
+ className="w-full flex items-center justify-between py-3 text-left focus-visible:ring-2 focus-visible:ring-ring"
89
+ aria-expanded={open}
90
+ >
91
+ <span className="text-sm font-medium text-foreground pr-4">{q}</span>
92
+ <ChevronDown size={14} className={`shrink-0 text-muted-foreground transition-transform duration-200 ${open ? 'rotate-180' : ''}`} />
93
+ </button>
94
+ {open && (
95
+ <p className="text-sm text-muted-foreground pb-3 leading-relaxed">{a}</p>
96
+ )}
97
+ </div>
98
+ );
99
+ }
100
+
101
+ /* ── Shortcut Row ── */
102
+ function ShortcutRow({ keys, label }: { keys: string; label: string }) {
103
+ return (
104
+ <div className="flex items-center justify-between py-1.5">
105
+ <span className="text-sm text-foreground">{label}</span>
106
+ <div className="flex items-center gap-1">
107
+ {keys.split(' ').map((key, i) => (
108
+ <kbd
109
+ key={i}
110
+ className="px-1.5 py-0.5 text-xs rounded border border-border bg-muted text-muted-foreground font-mono min-w-[24px] text-center"
111
+ >
112
+ {key}
113
+ </kbd>
114
+ ))}
115
+ </div>
116
+ </div>
117
+ );
118
+ }
119
+
120
+ /* ── Main Component ── */
121
+ export default function HelpContent() {
122
+ const { t } = useLocale();
123
+ const h = t.help;
124
+
125
+ const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.userAgent);
126
+ const mod = isMac ? '⌘' : 'Ctrl';
127
+
128
+ const shortcuts = useMemo(() => [
129
+ { keys: `${mod} K`, label: h.shortcuts.search },
130
+ { keys: `${mod} /`, label: h.shortcuts.askAI },
131
+ { keys: `${mod} ,`, label: h.shortcuts.settings },
132
+ { keys: `${mod} ?`, label: h.shortcuts.shortcutPanel },
133
+ { keys: 'E', label: h.shortcuts.editFile },
134
+ { keys: `${mod} S`, label: h.shortcuts.save },
135
+ { keys: 'Esc', label: h.shortcuts.closePanel },
136
+ { keys: '@', label: h.shortcuts.attachFile },
137
+ ], [mod, h.shortcuts]);
138
+
139
+ return (
140
+ <div className="content-width px-4 md:px-6 py-8 md:py-12">
141
+ {/* ── Header ── */}
142
+ <div className="mb-8">
143
+ <div className="flex items-center gap-2 mb-1">
144
+ <div className="w-1 h-6 rounded-full" style={{ background: 'var(--amber)' }} />
145
+ <h1 className="text-2xl font-bold font-display text-foreground">{h.title}</h1>
146
+ </div>
147
+ <p className="text-muted-foreground text-sm ml-3 mt-1">{h.subtitle}</p>
148
+ </div>
149
+
150
+ {/* ── Sections ── */}
151
+ <div className="space-y-3">
152
+ {/* 1. What is MindOS */}
153
+ <Section icon={<BookOpen size={18} />} title={h.whatIs.title} defaultOpen>
154
+ <p className="text-sm text-muted-foreground leading-relaxed">{h.whatIs.body}</p>
155
+ </Section>
156
+
157
+ {/* 2. Core Concepts */}
158
+ <Section icon={<Brain size={18} />} title={h.concepts.title} defaultOpen>
159
+ <div className="space-y-4">
160
+ <div>
161
+ <p className="text-sm font-medium text-foreground">{h.concepts.spaceTitle}</p>
162
+ <p className="text-sm text-muted-foreground mt-0.5">{h.concepts.spaceDesc}</p>
163
+ </div>
164
+ <div>
165
+ <p className="text-sm font-medium text-foreground">{h.concepts.instructionTitle}</p>
166
+ <p className="text-sm text-muted-foreground mt-0.5">{h.concepts.instructionDesc}</p>
167
+ </div>
168
+ <div>
169
+ <p className="text-sm font-medium text-foreground">{h.concepts.skillTitle}</p>
170
+ <p className="text-sm text-muted-foreground mt-0.5">{h.concepts.skillDesc}</p>
171
+ </div>
172
+ </div>
173
+ </Section>
174
+
175
+ {/* 3. Quick Start */}
176
+ <Section icon={<Rocket size={18} />} title={h.quickStart.title} defaultOpen>
177
+ <div className="space-y-4">
178
+ <StepCard step={1} title={h.quickStart.step1Title} desc={h.quickStart.step1Desc} />
179
+ <StepCard step={2} title={h.quickStart.step2Title} desc={h.quickStart.step2Desc} />
180
+ <StepCard step={3} title={h.quickStart.step3Title} desc={h.quickStart.step3Desc} />
181
+ </div>
182
+ </Section>
183
+
184
+ {/* 4. Using MindOS with AI Agents */}
185
+ <Section icon={<Bot size={18} />} title={h.agentUsage.title} defaultOpen>
186
+ <p className="text-sm text-muted-foreground leading-relaxed mb-4">{h.agentUsage.intro}</p>
187
+
188
+ <div className="space-y-3">
189
+ {h.agentUsage.scenarios.map((sc, i) => {
190
+ const prompts = sc.prompt.split('\n');
191
+ return (
192
+ <div key={i} className="bg-muted/50 rounded-md px-4 py-3">
193
+ <div className="flex items-center gap-2">
194
+ <span className="text-base leading-none" role="img" suppressHydrationWarning>{sc.emoji}</span>
195
+ <p className="text-sm font-medium text-foreground">{sc.title}</p>
196
+ </div>
197
+ <p className="text-sm text-muted-foreground mt-1">{sc.desc}</p>
198
+ {prompts.map((p, j) => (
199
+ <PromptBlock key={j} text={p} copyLabel={h.agentUsage.copy} />
200
+ ))}
201
+ </div>
202
+ );
203
+ })}
204
+ </div>
205
+
206
+ <p className="text-xs text-muted-foreground mt-4">{h.agentUsage.hint}</p>
207
+ </Section>
208
+
209
+ {/* 5. Keyboard Shortcuts */}
210
+ <Section icon={<Keyboard size={18} />} title={h.shortcutsTitle}>
211
+ <div className="space-y-0">
212
+ {shortcuts.map((s) => (
213
+ <ShortcutRow key={s.keys} keys={s.keys} label={s.label} />
214
+ ))}
215
+ </div>
216
+ </Section>
217
+
218
+ {/* 6. FAQ */}
219
+ <Section icon={<HelpCircle size={18} />} title={h.faq.title}>
220
+ <div>
221
+ {h.faq.items.map((item, i) => (
222
+ <FaqItem key={i} q={item.q} a={item.a} />
223
+ ))}
224
+ </div>
225
+ </Section>
226
+ </div>
227
+ </div>
228
+ );
229
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminilight/mindos",
3
- "version": "0.5.49",
3
+ "version": "0.5.50",
4
4
  "description": "MindOS — Human-Agent Collaborative Mind System. Local-first knowledge base that syncs your mind to all AI Agents via MCP.",
5
5
  "keywords": [
6
6
  "mindos",