@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
@@ -5,11 +5,13 @@
5
5
  * @module src/cli/commands/multi-get
6
6
  */
7
7
 
8
- import { minimatch } from 'minimatch';
9
- import type { DocumentRow, StorePort, StoreResult } from '../../store/types';
10
- import type { ParsedRef } from './ref-parser';
11
- import { isGlobPattern, parseRef, splitRefs } from './ref-parser';
12
- import { initStore } from './shared';
8
+ import { minimatch } from "minimatch";
9
+
10
+ import type { DocumentRow, StorePort, StoreResult } from "../../store/types";
11
+ import type { ParsedRef } from "./ref-parser";
12
+
13
+ import { isGlobPattern, parseRef, splitRefs } from "./ref-parser";
14
+ import { initStore } from "./shared";
13
15
 
14
16
  // ─────────────────────────────────────────────────────────────────────────────
15
17
  // Types
@@ -46,7 +48,7 @@ export interface MultiGetDocument {
46
48
 
47
49
  export interface SkippedDoc {
48
50
  ref: string;
49
- reason: 'not_found' | 'conversion_error' | 'invalid_ref';
51
+ reason: "not_found" | "conversion_error" | "invalid_ref";
50
52
  }
51
53
 
52
54
  export interface MultiGetResponse {
@@ -73,11 +75,11 @@ function lookupDocument(
73
75
  parsed: ParsedRef
74
76
  ): Promise<StoreResult<DocumentRow | null>> {
75
77
  switch (parsed.type) {
76
- case 'docid':
78
+ case "docid":
77
79
  return store.getDocumentByDocid(parsed.value);
78
- case 'uri':
80
+ case "uri":
79
81
  return store.getDocumentByUri(parsed.value);
80
- case 'collPath':
82
+ case "collPath":
81
83
  if (!(parsed.collection && parsed.relPath)) {
82
84
  return Promise.resolve({ ok: true as const, value: null });
83
85
  }
@@ -109,7 +111,7 @@ async function expandGlobs(
109
111
  continue;
110
112
  }
111
113
 
112
- const slashIdx = ref.indexOf('/');
114
+ const slashIdx = ref.indexOf("/");
113
115
  if (slashIdx === -1) {
114
116
  invalidRefs.push(ref);
115
117
  continue;
@@ -145,8 +147,8 @@ function truncateContent(
145
147
  return { content, truncated: false };
146
148
  }
147
149
 
148
- const lines = content.split('\n');
149
- let accumulated = '';
150
+ const lines = content.split("\n");
151
+ let accumulated = "";
150
152
  let byteLen = 0;
151
153
 
152
154
  for (const line of lines) {
@@ -184,31 +186,31 @@ async function fetchSingleDocument(
184
186
  ctx.seen.add(ref);
185
187
 
186
188
  const parsed = parseRef(ref);
187
- if ('error' in parsed) {
188
- ctx.skipped.push({ ref, reason: 'invalid_ref' });
189
+ if ("error" in parsed) {
190
+ ctx.skipped.push({ ref, reason: "invalid_ref" });
189
191
  return;
190
192
  }
191
193
 
192
194
  const docResult = await lookupDocument(ctx.store, parsed);
193
195
  if (!docResult.ok) {
194
- ctx.skipped.push({ ref, reason: 'not_found' });
196
+ ctx.skipped.push({ ref, reason: "not_found" });
195
197
  return;
196
198
  }
197
199
 
198
200
  const doc = docResult.value;
199
201
  if (!doc?.active) {
200
- ctx.skipped.push({ ref, reason: 'not_found' });
202
+ ctx.skipped.push({ ref, reason: "not_found" });
201
203
  return;
202
204
  }
203
205
 
204
206
  if (!doc.mirrorHash) {
205
- ctx.skipped.push({ ref, reason: 'conversion_error' });
207
+ ctx.skipped.push({ ref, reason: "conversion_error" });
206
208
  return;
207
209
  }
208
210
 
209
211
  const contentResult = await ctx.store.getContent(doc.mirrorHash);
210
212
  if (!contentResult.ok || contentResult.value === null) {
211
- ctx.skipped.push({ ref, reason: 'conversion_error' });
213
+ ctx.skipped.push({ ref, reason: "conversion_error" });
212
214
  return;
213
215
  }
214
216
 
@@ -224,7 +226,7 @@ async function fetchSingleDocument(
224
226
  title: doc.title ?? undefined,
225
227
  content,
226
228
  truncated: truncated || undefined,
227
- totalLines: content.split('\n').length,
229
+ totalLines: content.split("\n").length,
228
230
  source: {
229
231
  absPath: coll ? `${coll.path}/${doc.relPath}` : undefined,
230
232
  relPath: doc.relPath,
@@ -270,7 +272,7 @@ export async function multiGet(
270
272
 
271
273
  // Track invalid refs as skipped
272
274
  for (const ref of invalidRefs) {
273
- ctx.skipped.push({ ref, reason: 'invalid_ref' });
275
+ ctx.skipped.push({ ref, reason: "invalid_ref" });
274
276
  }
275
277
 
276
278
  for (const ref of expandedRefs) {
@@ -302,9 +304,9 @@ export async function multiGet(
302
304
 
303
305
  function addLineNumbers(text: string, startLine = 1): string {
304
306
  return text
305
- .split('\n')
307
+ .split("\n")
306
308
  .map((line, i) => `${startLine + i}: ${line}`)
307
- .join('\n');
309
+ .join("\n");
308
310
  }
309
311
 
310
312
  function formatContent(content: string, lineNumbers: boolean): string {
@@ -316,10 +318,10 @@ function formatMarkdown(
316
318
  options: MultiGetCommandOptions
317
319
  ): string {
318
320
  const lines: string[] = [];
319
- lines.push('# Multi-Get Results');
320
- lines.push('');
321
+ lines.push("# Multi-Get Results");
322
+ lines.push("");
321
323
  lines.push(`*${data.meta.returned} of ${data.meta.requested} documents*`);
322
- lines.push('');
324
+ lines.push("");
323
325
 
324
326
  for (const doc of data.documents) {
325
327
  lines.push(`## ${doc.title || doc.source.relPath}`);
@@ -327,21 +329,21 @@ function formatMarkdown(
327
329
  if (doc.truncated) {
328
330
  lines.push(`- **Truncated**: yes (max ${data.meta.maxBytes} bytes)`);
329
331
  }
330
- lines.push('');
331
- lines.push('```');
332
+ lines.push("");
333
+ lines.push("```");
332
334
  lines.push(formatContent(doc.content, Boolean(options.lineNumbers)));
333
- lines.push('```');
334
- lines.push('');
335
+ lines.push("```");
336
+ lines.push("");
335
337
  }
336
338
 
337
339
  if (data.skipped.length > 0) {
338
- lines.push('## Skipped');
340
+ lines.push("## Skipped");
339
341
  for (const s of data.skipped) {
340
342
  lines.push(`- ${s.ref}: ${s.reason}`);
341
343
  }
342
344
  }
343
345
 
344
- return lines.join('\n');
346
+ return lines.join("\n");
345
347
  }
346
348
 
347
349
  function formatTerminal(
@@ -353,17 +355,17 @@ function formatTerminal(
353
355
  for (const doc of data.documents) {
354
356
  lines.push(`=== ${doc.uri} ===`);
355
357
  lines.push(formatContent(doc.content, Boolean(options.lineNumbers)));
356
- lines.push('');
358
+ lines.push("");
357
359
  }
358
360
 
359
361
  if (data.skipped.length > 0) {
360
- lines.push(`Skipped: ${data.skipped.map((s) => s.ref).join(', ')}`);
362
+ lines.push(`Skipped: ${data.skipped.map((s) => s.ref).join(", ")}`);
361
363
  }
362
364
 
363
365
  lines.push(
364
366
  `${data.meta.returned}/${data.meta.requested} documents retrieved`
365
367
  );
366
- return lines.join('\n');
368
+ return lines.join("\n");
367
369
  }
368
370
 
369
371
  /**
@@ -376,7 +378,7 @@ export function formatMultiGet(
376
378
  if (!result.success) {
377
379
  if (options.json) {
378
380
  return JSON.stringify({
379
- error: { code: 'MULTI_GET_FAILED', message: result.error },
381
+ error: { code: "MULTI_GET_FAILED", message: result.error },
380
382
  });
381
383
  }
382
384
  return `Error: ${result.error}`;
@@ -389,7 +391,7 @@ export function formatMultiGet(
389
391
  }
390
392
 
391
393
  if (options.files) {
392
- return data.documents.map((d) => `${d.docid},${d.uri}`).join('\n');
394
+ return data.documents.map((d) => `${d.docid},${d.uri}`).join("\n");
393
395
  }
394
396
 
395
397
  if (options.md) {
@@ -5,26 +5,27 @@
5
5
  * @module src/cli/commands/query
6
6
  */
7
7
 
8
- import { LlmAdapter } from '../../llm/nodeLlamaCpp/adapter';
9
- import { resolveDownloadPolicy } from '../../llm/policy';
10
- import { getActivePreset } from '../../llm/registry';
11
8
  import type {
12
9
  EmbeddingPort,
13
10
  GenerationPort,
14
11
  RerankPort,
15
- } from '../../llm/types';
16
- import { type HybridSearchDeps, searchHybrid } from '../../pipeline/hybrid';
17
- import type { HybridSearchOptions, SearchResults } from '../../pipeline/types';
12
+ } from "../../llm/types";
13
+ import type { HybridSearchOptions, SearchResults } from "../../pipeline/types";
14
+
15
+ import { LlmAdapter } from "../../llm/nodeLlamaCpp/adapter";
16
+ import { resolveDownloadPolicy } from "../../llm/policy";
17
+ import { getActivePreset } from "../../llm/registry";
18
+ import { type HybridSearchDeps, searchHybrid } from "../../pipeline/hybrid";
18
19
  import {
19
20
  createVectorIndexPort,
20
21
  type VectorIndexPort,
21
- } from '../../store/vector';
22
- import { getGlobals } from '../program';
22
+ } from "../../store/vector";
23
+ import { getGlobals } from "../program";
23
24
  import {
24
25
  createProgressRenderer,
25
26
  createThrottledProgressRenderer,
26
- } from '../progress';
27
- import { initStore } from './shared';
27
+ } from "../progress";
28
+ import { initStore } from "./shared";
28
29
 
29
30
  // ─────────────────────────────────────────────────────────────────────────────
30
31
  // Types
@@ -52,7 +53,7 @@ export type QueryCommandOptions = HybridSearchOptions & {
52
53
  };
53
54
 
54
55
  export interface QueryFormatOptions {
55
- format: 'terminal' | 'json' | 'files' | 'csv' | 'md' | 'xml';
56
+ format: "terminal" | "json" | "files" | "csv" | "md" | "xml";
56
57
  full?: boolean;
57
58
  lineNumbers?: boolean;
58
59
  }
@@ -68,7 +69,7 @@ export type QueryResult =
68
69
  /**
69
70
  * Execute gno query command.
70
71
  */
71
- // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: CLI orchestration with multiple output formats
72
+ // oxlint-disable-next-line max-lines-per-function -- CLI orchestration with multiple output formats
72
73
  export async function query(
73
74
  queryText: string,
74
75
  options: QueryCommandOptions = {}
@@ -113,7 +114,7 @@ export async function query(
113
114
  const embedResult = await llm.createEmbeddingPort(embedUri, {
114
115
  policy,
115
116
  onProgress: downloadProgress
116
- ? (progress) => downloadProgress('embed', progress)
117
+ ? (progress) => downloadProgress("embed", progress)
117
118
  : undefined,
118
119
  });
119
120
  if (embedResult.ok) {
@@ -126,7 +127,7 @@ export async function query(
126
127
  const genResult = await llm.createGenerationPort(genUri, {
127
128
  policy,
128
129
  onProgress: downloadProgress
129
- ? (progress) => downloadProgress('gen', progress)
130
+ ? (progress) => downloadProgress("gen", progress)
130
131
  : undefined,
131
132
  });
132
133
  if (genResult.ok) {
@@ -140,7 +141,7 @@ export async function query(
140
141
  const rerankResult = await llm.createRerankPort(rerankUri, {
141
142
  policy,
142
143
  onProgress: downloadProgress
143
- ? (progress) => downloadProgress('rerank', progress)
144
+ ? (progress) => downloadProgress("rerank", progress)
144
145
  : undefined,
145
146
  });
146
147
  if (rerankResult.ok) {
@@ -150,7 +151,7 @@ export async function query(
150
151
 
151
152
  // Clear progress line if shown
152
153
  if (showProgress && downloadProgress) {
153
- process.stderr.write('\n');
154
+ process.stderr.write("\n");
154
155
  }
155
156
 
156
157
  // Create vector index (optional)
@@ -223,7 +224,7 @@ function outputExplainToStderr(data: SearchResults): void {
223
224
  const {
224
225
  formatExplain,
225
226
  formatResultExplain,
226
- } = require('../../pipeline/explain');
227
+ } = require("../../pipeline/explain");
227
228
  process.stderr.write(`${formatExplain(explain.lines)}\n`);
228
229
  process.stderr.write(`${formatResultExplain(explain.results)}\n`);
229
230
  }
@@ -237,9 +238,9 @@ export function formatQuery(
237
238
  options: QueryFormatOptions
238
239
  ): string {
239
240
  if (!result.success) {
240
- return options.format === 'json'
241
+ return options.format === "json"
241
242
  ? JSON.stringify({
242
- error: { code: 'QUERY_FAILED', message: result.error },
243
+ error: { code: "QUERY_FAILED", message: result.error },
243
244
  })
244
245
  : `Error: ${result.error}`;
245
246
  }
@@ -249,7 +250,7 @@ export function formatQuery(
249
250
 
250
251
  // Use shared formatter for consistent output
251
252
  // Dynamic import to keep module loading fast
252
- const { formatSearchResults } = require('../format/search-results');
253
+ const { formatSearchResults } = require("../format/search-results");
253
254
  return formatSearchResults(result.data, {
254
255
  format: options.format,
255
256
  full: options.full,
@@ -9,7 +9,7 @@
9
9
  // Types
10
10
  // ─────────────────────────────────────────────────────────────────────────────
11
11
 
12
- export type RefType = 'docid' | 'uri' | 'collPath';
12
+ export type RefType = "docid" | "uri" | "collPath";
13
13
 
14
14
  export interface ParsedRef {
15
15
  type: RefType;
@@ -45,14 +45,14 @@ const GLOB_PATTERN = /[*?[\]]/;
45
45
  */
46
46
  export function parseRef(ref: string): ParseRefResult {
47
47
  // 1. DocID: starts with #, validate pattern
48
- if (ref.startsWith('#')) {
49
- if (ref.includes(':')) {
50
- return { error: 'Docid refs cannot have :line suffix' };
48
+ if (ref.startsWith("#")) {
49
+ if (ref.includes(":")) {
50
+ return { error: "Docid refs cannot have :line suffix" };
51
51
  }
52
52
  if (!DOCID_PATTERN.test(ref)) {
53
53
  return { error: `Invalid docid format: ${ref}` };
54
54
  }
55
- return { type: 'docid', value: ref };
55
+ return { type: "docid", value: ref };
56
56
  }
57
57
 
58
58
  // 2. Parse optional :line suffix for URI and collPath
@@ -69,19 +69,19 @@ export function parseRef(ref: string): ParseRefResult {
69
69
  }
70
70
 
71
71
  // 3. URI: starts with gno://
72
- if (baseRef.startsWith('gno://')) {
73
- return { type: 'uri', value: baseRef, line };
72
+ if (baseRef.startsWith("gno://")) {
73
+ return { type: "uri", value: baseRef, line };
74
74
  }
75
75
 
76
76
  // 4. Collection/path: must contain /
77
- const slashIdx = baseRef.indexOf('/');
77
+ const slashIdx = baseRef.indexOf("/");
78
78
  if (slashIdx === -1) {
79
79
  return { error: `Invalid ref format (missing /): ${ref}` };
80
80
  }
81
81
  const collection = baseRef.slice(0, slashIdx);
82
82
  const relPath = baseRef.slice(slashIdx + 1);
83
83
 
84
- return { type: 'collPath', value: baseRef, collection, relPath, line };
84
+ return { type: "collPath", value: baseRef, collection, relPath, line };
85
85
  }
86
86
 
87
87
  /**
@@ -90,7 +90,7 @@ export function parseRef(ref: string): ParseRefResult {
90
90
  export function splitRefs(refs: string[]): string[] {
91
91
  const result: string[] = [];
92
92
  for (const r of refs) {
93
- for (const part of r.split(',')) {
93
+ for (const part of r.split(",")) {
94
94
  const trimmed = part.trim();
95
95
  if (trimmed) {
96
96
  result.push(trimmed);
@@ -5,13 +5,14 @@
5
5
  */
6
6
 
7
7
  // node:fs/promises: rm and stat for recursive directory deletion (no Bun equivalent)
8
- import { rm, stat } from 'node:fs/promises';
8
+ import { rm, stat } from "node:fs/promises";
9
9
  // node:os: homedir for platform-agnostic home directory (no Bun equivalent)
10
- import { homedir } from 'node:os';
10
+ import { homedir } from "node:os";
11
11
  // node:path: path manipulation utilities (no Bun equivalent)
12
- import { isAbsolute, normalize, sep } from 'node:path';
13
- import { resolveDirs } from '../../app/constants';
14
- import { CliError } from '../errors';
12
+ import { isAbsolute, normalize, sep } from "node:path";
13
+
14
+ import { resolveDirs } from "../../app/constants";
15
+ import { CliError } from "../errors";
15
16
 
16
17
  interface ResetOptions {
17
18
  confirm?: boolean;
@@ -21,7 +22,7 @@ interface ResetOptions {
21
22
 
22
23
  interface DirResult {
23
24
  path: string;
24
- status: 'deleted' | 'missing' | 'kept';
25
+ status: "deleted" | "missing" | "kept";
25
26
  error?: string;
26
27
  }
27
28
 
@@ -32,12 +33,12 @@ interface ResetResult {
32
33
 
33
34
  // Forbidden paths that should never be deleted
34
35
  const FORBIDDEN_PATHS = new Set([
35
- '/',
36
- '/Users',
37
- '/home',
38
- '/var',
39
- '/etc',
40
- '/tmp',
36
+ "/",
37
+ "/Users",
38
+ "/home",
39
+ "/var",
40
+ "/etc",
41
+ "/tmp",
41
42
  ]);
42
43
 
43
44
  /**
@@ -49,7 +50,7 @@ function assertSafePath(path: string, label: string): void {
49
50
 
50
51
  // Must be absolute
51
52
  if (!isAbsolute(normalized)) {
52
- throw new CliError('VALIDATION', `${label} path must be absolute: ${path}`);
53
+ throw new CliError("VALIDATION", `${label} path must be absolute: ${path}`);
53
54
  }
54
55
 
55
56
  // Must not be a forbidden system path
@@ -57,14 +58,14 @@ function assertSafePath(path: string, label: string): void {
57
58
  FORBIDDEN_PATHS.has(normalized) ||
58
59
  FORBIDDEN_PATHS.has(`${normalized}${sep}`)
59
60
  ) {
60
- throw new CliError('VALIDATION', `Refusing to delete system path: ${path}`);
61
+ throw new CliError("VALIDATION", `Refusing to delete system path: ${path}`);
61
62
  }
62
63
 
63
64
  // Must be under home directory (for user safety)
64
65
  const home = homedir();
65
66
  if (!normalized.startsWith(home + sep) && normalized !== home) {
66
67
  throw new CliError(
67
- 'VALIDATION',
68
+ "VALIDATION",
68
69
  `${label} path must be under home directory: ${path}`
69
70
  );
70
71
  }
@@ -72,7 +73,7 @@ function assertSafePath(path: string, label: string): void {
72
73
  // Must not be home directory itself
73
74
  if (normalized === home || normalized === home + sep) {
74
75
  throw new CliError(
75
- 'VALIDATION',
76
+ "VALIDATION",
76
77
  `Refusing to delete home directory: ${path}`
77
78
  );
78
79
  }
@@ -84,8 +85,8 @@ function assertSafePath(path: string, label: string): void {
84
85
  export async function reset(options: ResetOptions): Promise<ResetResult> {
85
86
  if (!options.confirm) {
86
87
  throw new CliError(
87
- 'VALIDATION',
88
- 'Reset requires --confirm or --yes flag to prevent accidental data loss'
88
+ "VALIDATION",
89
+ "Reset requires --confirm or --yes flag to prevent accidental data loss"
89
90
  );
90
91
  }
91
92
 
@@ -94,12 +95,12 @@ export async function reset(options: ResetOptions): Promise<ResetResult> {
94
95
  const errors: string[] = [];
95
96
 
96
97
  // Validate all paths before deleting anything
97
- assertSafePath(dirs.data, 'Data');
98
+ assertSafePath(dirs.data, "Data");
98
99
  if (!options.keepConfig) {
99
- assertSafePath(dirs.config, 'Config');
100
+ assertSafePath(dirs.config, "Config");
100
101
  }
101
102
  if (!options.keepCache) {
102
- assertSafePath(dirs.cache, 'Cache');
103
+ assertSafePath(dirs.cache, "Cache");
103
104
  }
104
105
 
105
106
  // Delete data directory (always, contains index DB)
@@ -107,14 +108,14 @@ export async function reset(options: ResetOptions): Promise<ResetResult> {
107
108
 
108
109
  // Delete config unless --keep-config
109
110
  if (options.keepConfig) {
110
- results.push({ path: dirs.config, status: 'kept' });
111
+ results.push({ path: dirs.config, status: "kept" });
111
112
  } else {
112
113
  results.push(await rmDir(dirs.config));
113
114
  }
114
115
 
115
116
  // Delete cache unless --keep-cache
116
117
  if (options.keepCache) {
117
- results.push({ path: dirs.cache, status: 'kept' });
118
+ results.push({ path: dirs.cache, status: "kept" });
118
119
  } else {
119
120
  results.push(await rmDir(dirs.cache));
120
121
  }
@@ -127,7 +128,7 @@ export async function reset(options: ResetOptions): Promise<ResetResult> {
127
128
  }
128
129
 
129
130
  if (errors.length > 0) {
130
- throw new CliError('RUNTIME', `Reset failed:\n${errors.join('\n')}`);
131
+ throw new CliError("RUNTIME", `Reset failed:\n${errors.join("\n")}`);
131
132
  }
132
133
 
133
134
  return { results, errors };
@@ -139,18 +140,18 @@ async function rmDir(path: string): Promise<DirResult> {
139
140
  await stat(path);
140
141
  } catch (e) {
141
142
  const err = e as NodeJS.ErrnoException;
142
- if (err.code === 'ENOENT') {
143
- return { path, status: 'missing' };
143
+ if (err.code === "ENOENT") {
144
+ return { path, status: "missing" };
144
145
  }
145
- return { path, status: 'missing', error: err.message };
146
+ return { path, status: "missing", error: err.message };
146
147
  }
147
148
 
148
149
  try {
149
150
  await rm(path, { recursive: true, force: true });
150
- return { path, status: 'deleted' };
151
+ return { path, status: "deleted" };
151
152
  } catch (e) {
152
153
  const err = e as NodeJS.ErrnoException;
153
- return { path, status: 'missing', error: err.message };
154
+ return { path, status: "missing", error: err.message };
154
155
  }
155
156
  }
156
157
 
@@ -158,34 +159,34 @@ async function rmDir(path: string): Promise<DirResult> {
158
159
  * Format reset result for terminal output.
159
160
  */
160
161
  export function formatReset(result: ResetResult): string {
161
- const deleted = result.results.filter((r) => r.status === 'deleted');
162
- const missing = result.results.filter((r) => r.status === 'missing');
163
- const kept = result.results.filter((r) => r.status === 'kept');
162
+ const deleted = result.results.filter((r) => r.status === "deleted");
163
+ const missing = result.results.filter((r) => r.status === "missing");
164
+ const kept = result.results.filter((r) => r.status === "kept");
164
165
 
165
- const lines: string[] = ['GNO reset complete.', ''];
166
+ const lines: string[] = ["GNO reset complete.", ""];
166
167
 
167
168
  if (deleted.length > 0) {
168
- lines.push('Deleted:');
169
+ lines.push("Deleted:");
169
170
  for (const r of deleted) {
170
171
  lines.push(` ${r.path}`);
171
172
  }
172
173
  }
173
174
 
174
175
  if (missing.length > 0) {
175
- lines.push('');
176
- lines.push('Already missing:');
176
+ lines.push("");
177
+ lines.push("Already missing:");
177
178
  for (const r of missing) {
178
179
  lines.push(` ${r.path}`);
179
180
  }
180
181
  }
181
182
 
182
183
  if (kept.length > 0) {
183
- lines.push('');
184
- lines.push('Kept:');
184
+ lines.push("");
185
+ lines.push("Kept:");
185
186
  for (const r of kept) {
186
187
  lines.push(` ${r.path}`);
187
188
  }
188
189
  }
189
190
 
190
- return lines.join('\n');
191
+ return lines.join("\n");
191
192
  }
@@ -5,13 +5,14 @@
5
5
  * @module src/cli/commands/search
6
6
  */
7
7
 
8
- import { searchBm25 } from '../../pipeline/search';
9
- import type { SearchOptions, SearchResults } from '../../pipeline/types';
8
+ import type { SearchOptions, SearchResults } from "../../pipeline/types";
9
+
10
+ import { searchBm25 } from "../../pipeline/search";
10
11
  import {
11
12
  type FormatOptions,
12
13
  formatSearchResults,
13
- } from '../format/search-results';
14
- import { initStore } from './shared';
14
+ } from "../format/search-results";
15
+ import { initStore } from "./shared";
15
16
 
16
17
  // ─────────────────────────────────────────────────────────────────────────────
17
18
  // Types
@@ -71,7 +72,7 @@ export async function search(
71
72
 
72
73
  if (!result.ok) {
73
74
  // Map INVALID_INPUT to validation error for proper exit code
74
- const isValidation = result.error.code === 'INVALID_INPUT';
75
+ const isValidation = result.error.code === "INVALID_INPUT";
75
76
  return {
76
77
  success: false,
77
78
  error: result.error.message,
@@ -92,23 +93,23 @@ export async function search(
92
93
  /**
93
94
  * Get output format from options.
94
95
  */
95
- function getFormatType(options: SearchCommandOptions): FormatOptions['format'] {
96
+ function getFormatType(options: SearchCommandOptions): FormatOptions["format"] {
96
97
  if (options.json) {
97
- return 'json';
98
+ return "json";
98
99
  }
99
100
  if (options.files) {
100
- return 'files';
101
+ return "files";
101
102
  }
102
103
  if (options.csv) {
103
- return 'csv';
104
+ return "csv";
104
105
  }
105
106
  if (options.md) {
106
- return 'md';
107
+ return "md";
107
108
  }
108
109
  if (options.xml) {
109
- return 'xml';
110
+ return "xml";
110
111
  }
111
- return 'terminal';
112
+ return "terminal";
112
113
  }
113
114
 
114
115
  /**
@@ -121,7 +122,7 @@ export function formatSearch(
121
122
  if (!result.success) {
122
123
  return options.json
123
124
  ? JSON.stringify({
124
- error: { code: 'QUERY_FAILED', message: result.error },
125
+ error: { code: "QUERY_FAILED", message: result.error },
125
126
  })
126
127
  : `Error: ${result.error}`;
127
128
  }