@gmickel/gno 0.7.0 → 0.8.2

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 +32 -25
  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,12 +1,13 @@
1
- import { ArrowLeft, FileText, Search as SearchIcon, Zap } from 'lucide-react';
2
- import { useEffect, useState } from 'react';
3
- import { Loader } from '../components/ai-elements/loader';
4
- import { Badge } from '../components/ui/badge';
5
- import { Button } from '../components/ui/button';
6
- import { ButtonGroup } from '../components/ui/button-group';
7
- import { Card, CardContent } from '../components/ui/card';
8
- import { Input } from '../components/ui/input';
9
- import { apiFetch } from '../hooks/use-api';
1
+ import { ArrowLeft, FileText, Search as SearchIcon, Zap } from "lucide-react";
2
+ import { useEffect, useState } from "react";
3
+
4
+ import { Loader } from "../components/ai-elements/loader";
5
+ import { Badge } from "../components/ui/badge";
6
+ import { Button } from "../components/ui/button";
7
+ import { ButtonGroup } from "../components/ui/button-group";
8
+ import { Card, CardContent } from "../components/ui/card";
9
+ import { Input } from "../components/ui/input";
10
+ import { apiFetch } from "../hooks/use-api";
10
11
 
11
12
  /**
12
13
  * Render snippet with <mark> tags as highlighted spans.
@@ -18,7 +19,7 @@ function renderSnippet(snippet: string): React.ReactNode {
18
19
  let key = 0;
19
20
 
20
21
  while (remaining.length > 0) {
21
- const markStart = remaining.indexOf('<mark>');
22
+ const markStart = remaining.indexOf("<mark>");
22
23
  if (markStart === -1) {
23
24
  parts.push(remaining);
24
25
  break;
@@ -28,7 +29,7 @@ function renderSnippet(snippet: string): React.ReactNode {
28
29
  parts.push(remaining.slice(0, markStart));
29
30
  }
30
31
 
31
- const markEnd = remaining.indexOf('</mark>', markStart);
32
+ const markEnd = remaining.indexOf("</mark>", markStart);
32
33
  if (markEnd === -1) {
33
34
  parts.push(remaining.slice(markStart));
34
35
  break;
@@ -84,13 +85,13 @@ interface Capabilities {
84
85
  answer: boolean;
85
86
  }
86
87
 
87
- type SearchMode = 'bm25' | 'hybrid';
88
+ type SearchMode = "bm25" | "hybrid";
88
89
 
89
90
  export default function Search({ navigate }: PageProps) {
90
- const [query, setQuery] = useState('');
91
- const [mode, setMode] = useState<SearchMode>('bm25');
91
+ const [query, setQuery] = useState("");
92
+ const [mode, setMode] = useState<SearchMode>("bm25");
92
93
  const [results, setResults] = useState<SearchResult[]>([]);
93
- const [meta, setMeta] = useState<SearchResponse['meta'] | null>(null);
94
+ const [meta, setMeta] = useState<SearchResponse["meta"] | null>(null);
94
95
  const [loading, setLoading] = useState(false);
95
96
  const [error, setError] = useState<string | null>(null);
96
97
  const [searched, setSearched] = useState(false);
@@ -99,16 +100,16 @@ export default function Search({ navigate }: PageProps) {
99
100
  // Fetch capabilities on mount
100
101
  useEffect(() => {
101
102
  async function fetchCapabilities() {
102
- const { data } = await apiFetch<Capabilities>('/api/capabilities');
103
+ const { data } = await apiFetch<Capabilities>("/api/capabilities");
103
104
  if (data) {
104
105
  setCapabilities(data);
105
106
  // Auto-select hybrid if available
106
107
  if (data.hybrid) {
107
- setMode('hybrid');
108
+ setMode("hybrid");
108
109
  }
109
110
  }
110
111
  }
111
- fetchCapabilities();
112
+ void fetchCapabilities();
112
113
  }, []);
113
114
 
114
115
  const handleSearch = async (e: React.FormEvent) => {
@@ -122,10 +123,10 @@ export default function Search({ navigate }: PageProps) {
122
123
  setSearched(true);
123
124
 
124
125
  // Use /api/query for hybrid, /api/search for bm25
125
- const endpoint = mode === 'hybrid' ? '/api/query' : '/api/search';
126
+ const endpoint = mode === "hybrid" ? "/api/query" : "/api/search";
126
127
 
127
128
  const { data, error } = await apiFetch<SearchResponse>(endpoint, {
128
- method: 'POST',
129
+ method: "POST",
129
130
  body: JSON.stringify({ query, limit: 20 }),
130
131
  });
131
132
 
@@ -163,23 +164,27 @@ export default function Search({ navigate }: PageProps) {
163
164
  <main className="mx-auto max-w-4xl p-8">
164
165
  {/* Search Form */}
165
166
  <form className="mb-8" onSubmit={handleSearch}>
166
- <div className="relative">
167
- <SearchIcon className="absolute top-1/2 left-4 size-5 -translate-y-1/2 text-muted-foreground" />
168
- <Input
169
- className="border-border bg-card py-6 pr-4 pl-12 text-lg focus:border-primary"
170
- onChange={(e) => setQuery(e.target.value)}
171
- placeholder="Search your documents..."
172
- type="text"
173
- value={query}
174
- />
175
- <Button
176
- className="absolute top-1/2 right-2 -translate-y-1/2"
177
- disabled={loading || !query.trim()}
178
- size="sm"
179
- type="submit"
180
- >
181
- {loading ? <Loader size={16} /> : 'Search'}
182
- </Button>
167
+ <div className="group relative">
168
+ {/* Gradient border effect on focus */}
169
+ <div className="pointer-events-none absolute -inset-[1px] rounded-lg bg-gradient-to-r from-primary/50 via-primary to-primary/50 opacity-0 blur-sm transition-opacity duration-300 group-focus-within:opacity-100" />
170
+ <div className="relative">
171
+ <SearchIcon className="absolute top-1/2 left-4 size-5 -translate-y-1/2 text-muted-foreground transition-colors duration-200 group-focus-within:text-primary" />
172
+ <Input
173
+ className="border-border/50 bg-card py-6 pr-4 pl-12 text-lg transition-all duration-200 focus:border-primary focus:bg-card/80 focus:shadow-[0_0_20px_-5px_hsl(var(--primary)/0.3)]"
174
+ onChange={(e) => setQuery(e.target.value)}
175
+ placeholder="Search your documents..."
176
+ type="text"
177
+ value={query}
178
+ />
179
+ <Button
180
+ className="absolute top-1/2 right-2 -translate-y-1/2"
181
+ disabled={loading || !query.trim()}
182
+ size="sm"
183
+ type="submit"
184
+ >
185
+ {loading ? <Loader size={16} /> : "Search"}
186
+ </Button>
187
+ </div>
183
188
  </div>
184
189
 
185
190
  {/* Mode selector */}
@@ -188,42 +193,42 @@ export default function Search({ navigate }: PageProps) {
188
193
  <ButtonGroup>
189
194
  <Button
190
195
  className={
191
- mode === 'bm25'
192
- ? 'bg-primary text-primary-foreground hover:bg-primary/90'
193
- : ''
196
+ mode === "bm25"
197
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
198
+ : ""
194
199
  }
195
- onClick={() => setMode('bm25')}
200
+ onClick={() => setMode("bm25")}
196
201
  size="sm"
197
202
  type="button"
198
- variant={mode === 'bm25' ? 'default' : 'outline'}
203
+ variant={mode === "bm25" ? "default" : "outline"}
199
204
  >
200
205
  BM25
201
206
  </Button>
202
207
  <Button
203
208
  className={
204
- mode === 'hybrid'
205
- ? 'bg-primary text-primary-foreground hover:bg-primary/90'
206
- : ''
209
+ mode === "hybrid"
210
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
211
+ : ""
207
212
  }
208
213
  disabled={!hybridAvailable}
209
- onClick={() => setMode('hybrid')}
214
+ onClick={() => setMode("hybrid")}
210
215
  size="sm"
211
216
  title={
212
217
  hybridAvailable
213
- ? 'Hybrid search with vector + reranking'
214
- : 'Hybrid search not available (no embedding model)'
218
+ ? "Hybrid search with vector + reranking"
219
+ : "Hybrid search not available (no embedding model)"
215
220
  }
216
221
  type="button"
217
- variant={mode === 'hybrid' ? 'default' : 'outline'}
222
+ variant={mode === "hybrid" ? "default" : "outline"}
218
223
  >
219
224
  <Zap className="mr-1 size-3" />
220
225
  Hybrid
221
226
  </Button>
222
227
  </ButtonGroup>
223
228
  <span className="text-muted-foreground/70 text-xs">
224
- {mode === 'bm25'
225
- ? 'Keyword-based full-text search'
226
- : 'BM25 + vector + query expansion + reranking'}
229
+ {mode === "bm25"
230
+ ? "Keyword-based full-text search"
231
+ : "BM25 + vector + query expansion + reranking"}
227
232
  </span>
228
233
  </div>
229
234
  </form>
@@ -246,11 +251,28 @@ export default function Search({ navigate }: PageProps) {
246
251
  {/* Empty state */}
247
252
  {!loading && searched && results.length === 0 && !error && (
248
253
  <div className="py-20 text-center">
249
- <FileText className="mx-auto mb-4 size-12 text-muted-foreground" />
250
- <h3 className="mb-2 font-medium text-lg">No results found</h3>
251
- <p className="text-muted-foreground">
252
- Try adjusting your search terms
254
+ <div className="relative mx-auto mb-6 size-20">
255
+ <div className="absolute inset-0 animate-pulse rounded-full bg-primary/10" />
256
+ <div className="absolute inset-2 rounded-full bg-card" />
257
+ <FileText className="absolute inset-0 m-auto size-8 text-muted-foreground" />
258
+ </div>
259
+ <h3 className="mb-2 font-semibold text-xl">No matches found</h3>
260
+ <p className="mx-auto mb-6 max-w-sm text-muted-foreground">
261
+ We couldn't find any documents matching "{query}". Try different
262
+ keywords or check your spelling.
253
263
  </p>
264
+ <div className="flex justify-center gap-3">
265
+ <Button onClick={() => setQuery("")} size="sm" variant="outline">
266
+ Clear search
267
+ </Button>
268
+ <Button
269
+ onClick={() => setMode(mode === "bm25" ? "hybrid" : "bm25")}
270
+ size="sm"
271
+ variant="ghost"
272
+ >
273
+ Try {mode === "bm25" ? "hybrid" : "keyword"} mode
274
+ </Button>
275
+ </div>
254
276
  </div>
255
277
  )}
256
278
 
@@ -259,7 +281,7 @@ export default function Search({ navigate }: PageProps) {
259
281
  <div className="space-y-4">
260
282
  <div className="mb-6 flex items-center justify-between">
261
283
  <p className="text-muted-foreground text-sm">
262
- {results.length} result{results.length !== 1 ? 's' : ''}
284
+ {results.length} result{results.length !== 1 ? "s" : ""}
263
285
  </p>
264
286
  {meta && (
265
287
  <div className="flex items-center gap-2">
@@ -302,7 +324,7 @@ export default function Search({ navigate }: PageProps) {
302
324
  <CardContent className="py-4">
303
325
  <div className="mb-2 flex items-start justify-between gap-4">
304
326
  <h3 className="font-medium text-primary underline-offset-2 group-hover:underline">
305
- {r.title || r.uri.split('/').pop()}
327
+ {r.title || r.uri.split("/").pop()}
306
328
  </h3>
307
329
  <Badge
308
330
  className="shrink-0 font-mono text-xs"