@gmickel/gno 0.7.0 → 0.8.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 (209) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -50
  3. package/THIRD_PARTY_NOTICES.md +22 -0
  4. package/assets/screenshots/webui-ask-answer.png +0 -0
  5. package/assets/screenshots/webui-collections.png +0 -0
  6. package/assets/screenshots/webui-editor.png +0 -0
  7. package/assets/screenshots/webui-home.png +0 -0
  8. package/assets/skill/SKILL.md +12 -12
  9. package/assets/skill/cli-reference.md +59 -57
  10. package/assets/skill/examples.md +8 -7
  11. package/assets/skill/mcp-reference.md +8 -4
  12. package/package.json +31 -24
  13. package/src/app/constants.ts +43 -42
  14. package/src/cli/colors.ts +1 -1
  15. package/src/cli/commands/ask.ts +44 -43
  16. package/src/cli/commands/cleanup.ts +9 -8
  17. package/src/cli/commands/collection/add.ts +12 -12
  18. package/src/cli/commands/collection/index.ts +4 -4
  19. package/src/cli/commands/collection/list.ts +26 -25
  20. package/src/cli/commands/collection/remove.ts +10 -10
  21. package/src/cli/commands/collection/rename.ts +10 -10
  22. package/src/cli/commands/context/add.ts +1 -1
  23. package/src/cli/commands/context/check.ts +17 -17
  24. package/src/cli/commands/context/index.ts +4 -4
  25. package/src/cli/commands/context/list.ts +11 -11
  26. package/src/cli/commands/context/rm.ts +1 -1
  27. package/src/cli/commands/doctor.ts +86 -84
  28. package/src/cli/commands/embed.ts +30 -28
  29. package/src/cli/commands/get.ts +27 -26
  30. package/src/cli/commands/index-cmd.ts +9 -9
  31. package/src/cli/commands/index.ts +16 -16
  32. package/src/cli/commands/init.ts +13 -12
  33. package/src/cli/commands/ls.ts +20 -19
  34. package/src/cli/commands/mcp/config.ts +30 -28
  35. package/src/cli/commands/mcp/index.ts +4 -4
  36. package/src/cli/commands/mcp/install.ts +17 -17
  37. package/src/cli/commands/mcp/paths.ts +133 -133
  38. package/src/cli/commands/mcp/status.ts +21 -21
  39. package/src/cli/commands/mcp/uninstall.ts +13 -13
  40. package/src/cli/commands/mcp.ts +2 -2
  41. package/src/cli/commands/models/clear.ts +12 -11
  42. package/src/cli/commands/models/index.ts +5 -5
  43. package/src/cli/commands/models/list.ts +31 -30
  44. package/src/cli/commands/models/path.ts +1 -1
  45. package/src/cli/commands/models/pull.ts +19 -18
  46. package/src/cli/commands/models/use.ts +4 -4
  47. package/src/cli/commands/multi-get.ts +38 -36
  48. package/src/cli/commands/query.ts +21 -20
  49. package/src/cli/commands/ref-parser.ts +10 -10
  50. package/src/cli/commands/reset.ts +40 -39
  51. package/src/cli/commands/search.ts +14 -13
  52. package/src/cli/commands/serve.ts +4 -4
  53. package/src/cli/commands/shared.ts +11 -10
  54. package/src/cli/commands/skill/index.ts +5 -5
  55. package/src/cli/commands/skill/install.ts +18 -17
  56. package/src/cli/commands/skill/paths-cmd.ts +11 -10
  57. package/src/cli/commands/skill/paths.ts +23 -23
  58. package/src/cli/commands/skill/show.ts +13 -12
  59. package/src/cli/commands/skill/uninstall.ts +16 -15
  60. package/src/cli/commands/status.ts +25 -24
  61. package/src/cli/commands/update.ts +3 -3
  62. package/src/cli/commands/vsearch.ts +17 -16
  63. package/src/cli/context.ts +5 -5
  64. package/src/cli/errors.ts +3 -3
  65. package/src/cli/format/search-results.ts +37 -37
  66. package/src/cli/options.ts +43 -43
  67. package/src/cli/program.ts +455 -459
  68. package/src/cli/progress.ts +1 -1
  69. package/src/cli/run.ts +24 -23
  70. package/src/collection/add.ts +9 -8
  71. package/src/collection/index.ts +3 -3
  72. package/src/collection/remove.ts +7 -6
  73. package/src/collection/types.ts +6 -6
  74. package/src/config/defaults.ts +1 -1
  75. package/src/config/index.ts +5 -5
  76. package/src/config/loader.ts +19 -18
  77. package/src/config/paths.ts +9 -8
  78. package/src/config/saver.ts +14 -13
  79. package/src/config/types.ts +53 -52
  80. package/src/converters/adapters/markitdownTs/adapter.ts +21 -19
  81. package/src/converters/adapters/officeparser/adapter.ts +18 -16
  82. package/src/converters/canonicalize.ts +12 -12
  83. package/src/converters/errors.ts +26 -22
  84. package/src/converters/index.ts +8 -8
  85. package/src/converters/mime.ts +25 -25
  86. package/src/converters/native/markdown.ts +10 -9
  87. package/src/converters/native/plaintext.ts +8 -7
  88. package/src/converters/path.ts +2 -2
  89. package/src/converters/pipeline.ts +11 -10
  90. package/src/converters/registry.ts +8 -8
  91. package/src/converters/types.ts +14 -14
  92. package/src/converters/versions.ts +4 -4
  93. package/src/index.ts +4 -4
  94. package/src/ingestion/chunker.ts +10 -9
  95. package/src/ingestion/index.ts +6 -6
  96. package/src/ingestion/language.ts +62 -62
  97. package/src/ingestion/sync.ts +50 -49
  98. package/src/ingestion/types.ts +10 -10
  99. package/src/ingestion/walker.ts +14 -13
  100. package/src/llm/cache.ts +51 -49
  101. package/src/llm/errors.ts +40 -36
  102. package/src/llm/index.ts +9 -9
  103. package/src/llm/lockfile.ts +6 -6
  104. package/src/llm/nodeLlamaCpp/adapter.ts +13 -12
  105. package/src/llm/nodeLlamaCpp/embedding.ts +9 -8
  106. package/src/llm/nodeLlamaCpp/generation.ts +7 -6
  107. package/src/llm/nodeLlamaCpp/lifecycle.ts +11 -10
  108. package/src/llm/nodeLlamaCpp/rerank.ts +6 -5
  109. package/src/llm/policy.ts +5 -5
  110. package/src/llm/registry.ts +6 -5
  111. package/src/llm/types.ts +2 -2
  112. package/src/mcp/resources/index.ts +15 -13
  113. package/src/mcp/server.ts +25 -23
  114. package/src/mcp/tools/get.ts +25 -23
  115. package/src/mcp/tools/index.ts +32 -29
  116. package/src/mcp/tools/multi-get.ts +34 -32
  117. package/src/mcp/tools/query.ts +29 -27
  118. package/src/mcp/tools/search.ts +14 -12
  119. package/src/mcp/tools/status.ts +12 -11
  120. package/src/mcp/tools/vsearch.ts +26 -24
  121. package/src/pipeline/answer.ts +9 -9
  122. package/src/pipeline/chunk-lookup.ts +1 -1
  123. package/src/pipeline/contextual.ts +4 -4
  124. package/src/pipeline/expansion.ts +23 -21
  125. package/src/pipeline/explain.ts +21 -21
  126. package/src/pipeline/fusion.ts +9 -9
  127. package/src/pipeline/hybrid.ts +41 -42
  128. package/src/pipeline/index.ts +10 -10
  129. package/src/pipeline/query-language.ts +39 -39
  130. package/src/pipeline/rerank.ts +8 -7
  131. package/src/pipeline/search.ts +22 -22
  132. package/src/pipeline/types.ts +8 -8
  133. package/src/pipeline/vsearch.ts +21 -24
  134. package/src/serve/CLAUDE.md +21 -15
  135. package/src/serve/config-sync.ts +9 -8
  136. package/src/serve/context.ts +19 -18
  137. package/src/serve/index.ts +1 -1
  138. package/src/serve/jobs.ts +7 -7
  139. package/src/serve/public/app.tsx +79 -25
  140. package/src/serve/public/components/AddCollectionDialog.tsx +382 -0
  141. package/src/serve/public/components/CaptureButton.tsx +60 -0
  142. package/src/serve/public/components/CaptureModal.tsx +365 -0
  143. package/src/serve/public/components/IndexingProgress.tsx +333 -0
  144. package/src/serve/public/components/ShortcutHelpModal.tsx +106 -0
  145. package/src/serve/public/components/ai-elements/code-block.tsx +42 -32
  146. package/src/serve/public/components/ai-elements/conversation.tsx +16 -14
  147. package/src/serve/public/components/ai-elements/inline-citation.tsx +33 -32
  148. package/src/serve/public/components/ai-elements/loader.tsx +5 -4
  149. package/src/serve/public/components/ai-elements/message.tsx +39 -37
  150. package/src/serve/public/components/ai-elements/prompt-input.tsx +97 -95
  151. package/src/serve/public/components/ai-elements/sources.tsx +12 -10
  152. package/src/serve/public/components/ai-elements/suggestion.tsx +10 -9
  153. package/src/serve/public/components/editor/CodeMirrorEditor.tsx +142 -0
  154. package/src/serve/public/components/editor/MarkdownPreview.tsx +311 -0
  155. package/src/serve/public/components/editor/index.ts +6 -0
  156. package/src/serve/public/components/preset-selector.tsx +29 -28
  157. package/src/serve/public/components/ui/badge.tsx +13 -12
  158. package/src/serve/public/components/ui/button-group.tsx +13 -12
  159. package/src/serve/public/components/ui/button.tsx +23 -22
  160. package/src/serve/public/components/ui/card.tsx +16 -16
  161. package/src/serve/public/components/ui/carousel.tsx +36 -35
  162. package/src/serve/public/components/ui/collapsible.tsx +1 -1
  163. package/src/serve/public/components/ui/command.tsx +17 -15
  164. package/src/serve/public/components/ui/dialog.tsx +13 -12
  165. package/src/serve/public/components/ui/dropdown-menu.tsx +13 -12
  166. package/src/serve/public/components/ui/hover-card.tsx +6 -5
  167. package/src/serve/public/components/ui/input-group.tsx +45 -43
  168. package/src/serve/public/components/ui/input.tsx +6 -6
  169. package/src/serve/public/components/ui/progress.tsx +5 -4
  170. package/src/serve/public/components/ui/scroll-area.tsx +11 -10
  171. package/src/serve/public/components/ui/select.tsx +19 -18
  172. package/src/serve/public/components/ui/separator.tsx +6 -5
  173. package/src/serve/public/components/ui/table.tsx +18 -18
  174. package/src/serve/public/components/ui/textarea.tsx +4 -4
  175. package/src/serve/public/components/ui/tooltip.tsx +5 -4
  176. package/src/serve/public/globals.css +27 -4
  177. package/src/serve/public/hooks/use-api.ts +8 -8
  178. package/src/serve/public/hooks/useCaptureModal.tsx +83 -0
  179. package/src/serve/public/hooks/useKeyboardShortcuts.ts +85 -0
  180. package/src/serve/public/index.html +4 -4
  181. package/src/serve/public/lib/utils.ts +6 -0
  182. package/src/serve/public/pages/Ask.tsx +27 -26
  183. package/src/serve/public/pages/Browse.tsx +28 -27
  184. package/src/serve/public/pages/Collections.tsx +439 -0
  185. package/src/serve/public/pages/Dashboard.tsx +166 -40
  186. package/src/serve/public/pages/DocView.tsx +258 -73
  187. package/src/serve/public/pages/DocumentEditor.tsx +510 -0
  188. package/src/serve/public/pages/Search.tsx +80 -58
  189. package/src/serve/routes/api.ts +272 -155
  190. package/src/serve/security.ts +4 -4
  191. package/src/serve/server.ts +66 -48
  192. package/src/store/index.ts +5 -5
  193. package/src/store/migrations/001-initial.ts +24 -23
  194. package/src/store/migrations/002-documents-fts.ts +7 -6
  195. package/src/store/migrations/index.ts +4 -4
  196. package/src/store/migrations/runner.ts +17 -15
  197. package/src/store/sqlite/adapter.ts +123 -121
  198. package/src/store/sqlite/fts5-snowball.ts +24 -23
  199. package/src/store/sqlite/index.ts +1 -1
  200. package/src/store/sqlite/setup.ts +12 -12
  201. package/src/store/sqlite/types.ts +4 -4
  202. package/src/store/types.ts +19 -19
  203. package/src/store/vector/index.ts +3 -3
  204. package/src/store/vector/sqlite-vec.ts +23 -20
  205. package/src/store/vector/stats.ts +10 -8
  206. package/src/store/vector/types.ts +2 -2
  207. package/vendor/fts5-snowball/README.md +6 -6
  208. package/assets/screenshots/webui-ask-answer.jpg +0 -0
  209. package/assets/screenshots/webui-home.jpg +0 -0
@@ -1,22 +1,36 @@
1
1
  import {
2
2
  BookOpen,
3
+ CheckCircle2Icon,
3
4
  Database,
5
+ FolderIcon,
4
6
  Layers,
7
+ Loader2Icon,
5
8
  MessageSquare,
9
+ PenIcon,
10
+ RefreshCwIcon,
6
11
  Search,
7
12
  Sparkles,
8
- } from 'lucide-react';
9
- import { useEffect, useState } from 'react';
10
- import { PresetSelector } from '../components/preset-selector';
11
- import { Badge } from '../components/ui/badge';
12
- import { Button } from '../components/ui/button';
13
+ } from "lucide-react";
14
+ import { useCallback, useEffect, useState } from "react";
15
+
16
+ import { CaptureButton } from "../components/CaptureButton";
17
+ import { IndexingProgress } from "../components/IndexingProgress";
18
+ import { PresetSelector } from "../components/preset-selector";
19
+ import { Badge } from "../components/ui/badge";
20
+ import { Button } from "../components/ui/button";
13
21
  import {
14
22
  Card,
15
23
  CardContent,
16
24
  CardDescription,
17
25
  CardHeader,
18
- } from '../components/ui/card';
19
- import { apiFetch } from '../hooks/use-api';
26
+ } from "../components/ui/card";
27
+ import { apiFetch } from "../hooks/use-api";
28
+ import { useCaptureModal } from "../hooks/useCaptureModal";
29
+ import { modKey } from "../hooks/useKeyboardShortcuts";
30
+
31
+ interface SyncResponse {
32
+ jobId: string;
33
+ }
20
34
 
21
35
  interface PageProps {
22
36
  navigate: (to: string | number) => void;
@@ -40,16 +54,48 @@ interface StatusData {
40
54
  export default function Dashboard({ navigate }: PageProps) {
41
55
  const [status, setStatus] = useState<StatusData | null>(null);
42
56
  const [error, setError] = useState<string | null>(null);
57
+ const [syncing, setSyncing] = useState(false);
58
+ const [syncJobId, setSyncJobId] = useState<string | null>(null);
59
+ const { openCapture } = useCaptureModal();
60
+
61
+ const loadStatus = useCallback(async () => {
62
+ const { data, error: err } = await apiFetch<StatusData>("/api/status");
63
+ if (err) {
64
+ setError(err);
65
+ } else {
66
+ setStatus(data);
67
+ setError(null);
68
+ }
69
+ }, []);
43
70
 
44
71
  useEffect(() => {
45
- apiFetch<StatusData>('/api/status').then(({ data, error }) => {
46
- if (error) {
47
- setError(error);
48
- } else {
49
- setStatus(data);
50
- }
72
+ void loadStatus();
73
+ }, [loadStatus]);
74
+
75
+ const handleSync = async () => {
76
+ setSyncing(true);
77
+ setSyncJobId(null);
78
+
79
+ const { data, error: err } = await apiFetch<SyncResponse>("/api/sync", {
80
+ method: "POST",
51
81
  });
52
- }, []);
82
+
83
+ if (err) {
84
+ setSyncing(false);
85
+ setError(err);
86
+ return;
87
+ }
88
+
89
+ if (data?.jobId) {
90
+ setSyncJobId(data.jobId);
91
+ }
92
+ };
93
+
94
+ const handleSyncComplete = () => {
95
+ setSyncing(false);
96
+ setSyncJobId(null);
97
+ void loadStatus();
98
+ };
53
99
 
54
100
  return (
55
101
  <div className="min-h-screen">
@@ -64,11 +110,40 @@ export default function Dashboard({ navigate }: PageProps) {
64
110
  GNO
65
111
  </h1>
66
112
  </div>
67
- <PresetSelector />
113
+ <div className="flex items-center gap-3">
114
+ <Button
115
+ disabled={syncing}
116
+ onClick={handleSync}
117
+ size="sm"
118
+ variant="outline"
119
+ >
120
+ {syncing ? (
121
+ <Loader2Icon className="mr-1.5 size-4 animate-spin" />
122
+ ) : (
123
+ <RefreshCwIcon className="mr-1.5 size-4" />
124
+ )}
125
+ {syncing ? "Syncing..." : "Update All"}
126
+ </Button>
127
+ <PresetSelector />
128
+ </div>
68
129
  </div>
69
130
  <p className="text-lg text-muted-foreground">
70
131
  Your Local Knowledge Index
71
132
  </p>
133
+
134
+ {/* Sync progress */}
135
+ {syncJobId && (
136
+ <div className="mt-4 rounded-lg border border-border/50 bg-background/50 p-4">
137
+ <IndexingProgress
138
+ jobId={syncJobId}
139
+ onComplete={handleSyncComplete}
140
+ onError={() => {
141
+ setSyncing(false);
142
+ setSyncJobId(null);
143
+ }}
144
+ />
145
+ </div>
146
+ )}
72
147
  </div>
73
148
  </header>
74
149
 
@@ -77,7 +152,7 @@ export default function Dashboard({ navigate }: PageProps) {
77
152
  <nav className="mb-10 flex gap-4">
78
153
  <Button
79
154
  className="gap-2"
80
- onClick={() => navigate('/search')}
155
+ onClick={() => navigate("/search")}
81
156
  size="lg"
82
157
  >
83
158
  <Search className="size-4" />
@@ -85,7 +160,7 @@ export default function Dashboard({ navigate }: PageProps) {
85
160
  </Button>
86
161
  <Button
87
162
  className="gap-2"
88
- onClick={() => navigate('/ask')}
163
+ onClick={() => navigate("/ask")}
89
164
  size="lg"
90
165
  variant="secondary"
91
166
  >
@@ -94,7 +169,7 @@ export default function Dashboard({ navigate }: PageProps) {
94
169
  </Button>
95
170
  <Button
96
171
  className="gap-2"
97
- onClick={() => navigate('/browse')}
172
+ onClick={() => navigate("/browse")}
98
173
  size="lg"
99
174
  variant="outline"
100
175
  >
@@ -112,22 +187,27 @@ export default function Dashboard({ navigate }: PageProps) {
112
187
 
113
188
  {/* Stats Grid */}
114
189
  {status && (
115
- <div className="mb-10 grid animate-fade-in gap-6 opacity-0 md:grid-cols-3">
116
- <Card className="group transition-colors hover:border-primary/50">
117
- <CardHeader className="pb-2">
118
- <CardDescription className="flex items-center gap-2">
190
+ <div className="mb-10 grid animate-fade-in gap-6 opacity-0 md:grid-cols-4">
191
+ {/* Hero Documents Card */}
192
+ <Card className="group relative overflow-hidden border-primary/30 bg-gradient-to-br from-primary/10 via-primary/5 to-transparent transition-all duration-300 hover:border-primary/50 hover:shadow-[0_0_30px_-10px_hsl(var(--primary)/0.3)]">
193
+ <div className="pointer-events-none absolute -top-12 -right-12 size-32 rounded-full bg-primary/10 blur-2xl" />
194
+ <CardHeader className="relative pb-2">
195
+ <CardDescription className="flex items-center gap-2 text-primary/80">
119
196
  <Database className="size-4" />
120
197
  Documents
121
198
  </CardDescription>
122
199
  </CardHeader>
123
- <CardContent>
124
- <div className="font-bold text-4xl tracking-tight">
200
+ <CardContent className="relative">
201
+ <div className="font-bold text-5xl tracking-tight text-primary">
125
202
  {status.totalDocuments.toLocaleString()}
126
203
  </div>
204
+ <p className="mt-1 text-muted-foreground text-sm">
205
+ indexed files
206
+ </p>
127
207
  </CardContent>
128
208
  </Card>
129
209
 
130
- <Card className="group stagger-1 animate-fade-in opacity-0 transition-colors hover:border-primary/50">
210
+ <Card className="group stagger-1 animate-fade-in opacity-0 transition-all duration-200 hover:-translate-y-0.5 hover:border-primary/50 hover:shadow-lg">
131
211
  <CardHeader className="pb-2">
132
212
  <CardDescription className="flex items-center gap-2">
133
213
  <Layers className="size-4" />
@@ -141,17 +221,48 @@ export default function Dashboard({ navigate }: PageProps) {
141
221
  </CardContent>
142
222
  </Card>
143
223
 
144
- <Card className="group stagger-2 animate-fade-in opacity-0 transition-colors hover:border-primary/50">
224
+ <Card className="group stagger-2 animate-fade-in opacity-0 transition-all duration-200 hover:-translate-y-0.5 hover:border-primary/50 hover:shadow-lg">
145
225
  <CardHeader className="pb-2">
146
- <CardDescription>Status</CardDescription>
226
+ <CardDescription className="flex items-center gap-2">
227
+ <FolderIcon className="size-4" />
228
+ Collections
229
+ </CardDescription>
147
230
  </CardHeader>
148
231
  <CardContent>
149
- <Badge
150
- className="px-3 py-1 text-lg"
151
- variant={status.healthy ? 'default' : 'secondary'}
152
- >
153
- {status.healthy ? '● Healthy' : '○ Degraded'}
154
- </Badge>
232
+ <div className="flex items-center gap-2">
233
+ <span className="font-bold text-4xl tracking-tight">
234
+ {status.collections.length}
235
+ </span>
236
+ {status.healthy && (
237
+ <CheckCircle2Icon className="size-5 text-green-500" />
238
+ )}
239
+ </div>
240
+ </CardContent>
241
+ </Card>
242
+
243
+ {/* Quick Capture Card */}
244
+ <Card
245
+ className="group stagger-3 animate-fade-in cursor-pointer opacity-0 transition-all duration-200 hover:-translate-y-0.5 hover:border-secondary/50 hover:bg-secondary/5 hover:shadow-lg"
246
+ onClick={openCapture}
247
+ >
248
+ <CardHeader className="pb-2">
249
+ <CardDescription className="flex items-center gap-2">
250
+ <PenIcon className="size-4" />
251
+ Quick Capture
252
+ </CardDescription>
253
+ </CardHeader>
254
+ <CardContent>
255
+ <div className="flex items-center justify-between">
256
+ <span className="font-medium text-lg transition-colors group-hover:text-secondary">
257
+ New Note
258
+ </span>
259
+ <Badge
260
+ className="font-mono text-xs transition-colors group-hover:border-secondary/50 group-hover:text-secondary"
261
+ variant="outline"
262
+ >
263
+ {modKey}N
264
+ </Badge>
265
+ </div>
155
266
  </CardContent>
156
267
  </Card>
157
268
  </div>
@@ -174,12 +285,22 @@ export default function Dashboard({ navigate }: PageProps) {
174
285
  style={{ animationDelay: `${0.4 + i * 0.1}s` }}
175
286
  >
176
287
  <CardContent className="flex items-center justify-between py-4">
177
- <div>
178
- <div className="font-medium text-lg transition-colors group-hover:text-primary">
179
- {c.name}
180
- </div>
181
- <div className="font-mono text-muted-foreground text-sm">
182
- {c.path}
288
+ <div className="flex items-center gap-3">
289
+ {/* Health indicator */}
290
+ {syncing ? (
291
+ <Loader2Icon className="size-4 animate-spin text-amber-500" />
292
+ ) : c.embeddedCount >= c.chunkCount ? (
293
+ <CheckCircle2Icon className="size-4 text-green-500" />
294
+ ) : (
295
+ <div className="size-4 rounded-full border-2 border-amber-500" />
296
+ )}
297
+ <div>
298
+ <div className="font-medium text-lg transition-colors group-hover:text-primary">
299
+ {c.name}
300
+ </div>
301
+ <div className="font-mono text-muted-foreground text-sm">
302
+ {c.path}
303
+ </div>
183
304
  </div>
184
305
  </div>
185
306
  <div className="text-right">
@@ -187,7 +308,9 @@ export default function Dashboard({ navigate }: PageProps) {
187
308
  {c.documentCount.toLocaleString()} docs
188
309
  </div>
189
310
  <div className="text-muted-foreground text-sm">
190
- {c.chunkCount.toLocaleString()} chunks
311
+ {c.embeddedCount === c.chunkCount
312
+ ? `${c.chunkCount.toLocaleString()} chunks`
313
+ : `${c.embeddedCount}/${c.chunkCount} embedded`}
191
314
  </div>
192
315
  </div>
193
316
  </CardContent>
@@ -197,6 +320,9 @@ export default function Dashboard({ navigate }: PageProps) {
197
320
  </section>
198
321
  )}
199
322
  </main>
323
+
324
+ {/* Floating Action Button */}
325
+ <CaptureButton onClick={openCapture} />
200
326
  </div>
201
327
  );
202
328
  }