@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.
- package/LICENSE +21 -0
- package/README.md +90 -50
- package/THIRD_PARTY_NOTICES.md +22 -0
- package/assets/screenshots/webui-ask-answer.png +0 -0
- package/assets/screenshots/webui-collections.png +0 -0
- package/assets/screenshots/webui-editor.png +0 -0
- package/assets/screenshots/webui-home.png +0 -0
- package/assets/skill/SKILL.md +12 -12
- package/assets/skill/cli-reference.md +59 -57
- package/assets/skill/examples.md +8 -7
- package/assets/skill/mcp-reference.md +8 -4
- package/package.json +32 -25
- package/src/app/constants.ts +43 -42
- package/src/cli/colors.ts +1 -1
- package/src/cli/commands/ask.ts +44 -43
- package/src/cli/commands/cleanup.ts +9 -8
- package/src/cli/commands/collection/add.ts +12 -12
- package/src/cli/commands/collection/index.ts +4 -4
- package/src/cli/commands/collection/list.ts +26 -25
- package/src/cli/commands/collection/remove.ts +10 -10
- package/src/cli/commands/collection/rename.ts +10 -10
- package/src/cli/commands/context/add.ts +1 -1
- package/src/cli/commands/context/check.ts +17 -17
- package/src/cli/commands/context/index.ts +4 -4
- package/src/cli/commands/context/list.ts +11 -11
- package/src/cli/commands/context/rm.ts +1 -1
- package/src/cli/commands/doctor.ts +86 -84
- package/src/cli/commands/embed.ts +30 -28
- package/src/cli/commands/get.ts +27 -26
- package/src/cli/commands/index-cmd.ts +9 -9
- package/src/cli/commands/index.ts +16 -16
- package/src/cli/commands/init.ts +13 -12
- package/src/cli/commands/ls.ts +20 -19
- package/src/cli/commands/mcp/config.ts +30 -28
- package/src/cli/commands/mcp/index.ts +4 -4
- package/src/cli/commands/mcp/install.ts +17 -17
- package/src/cli/commands/mcp/paths.ts +133 -133
- package/src/cli/commands/mcp/status.ts +21 -21
- package/src/cli/commands/mcp/uninstall.ts +13 -13
- package/src/cli/commands/mcp.ts +2 -2
- package/src/cli/commands/models/clear.ts +12 -11
- package/src/cli/commands/models/index.ts +5 -5
- package/src/cli/commands/models/list.ts +31 -30
- package/src/cli/commands/models/path.ts +1 -1
- package/src/cli/commands/models/pull.ts +19 -18
- package/src/cli/commands/models/use.ts +4 -4
- package/src/cli/commands/multi-get.ts +38 -36
- package/src/cli/commands/query.ts +21 -20
- package/src/cli/commands/ref-parser.ts +10 -10
- package/src/cli/commands/reset.ts +40 -39
- package/src/cli/commands/search.ts +14 -13
- package/src/cli/commands/serve.ts +4 -4
- package/src/cli/commands/shared.ts +11 -10
- package/src/cli/commands/skill/index.ts +5 -5
- package/src/cli/commands/skill/install.ts +18 -17
- package/src/cli/commands/skill/paths-cmd.ts +11 -10
- package/src/cli/commands/skill/paths.ts +23 -23
- package/src/cli/commands/skill/show.ts +13 -12
- package/src/cli/commands/skill/uninstall.ts +16 -15
- package/src/cli/commands/status.ts +25 -24
- package/src/cli/commands/update.ts +3 -3
- package/src/cli/commands/vsearch.ts +17 -16
- package/src/cli/context.ts +5 -5
- package/src/cli/errors.ts +3 -3
- package/src/cli/format/search-results.ts +37 -37
- package/src/cli/options.ts +43 -43
- package/src/cli/program.ts +455 -459
- package/src/cli/progress.ts +1 -1
- package/src/cli/run.ts +24 -23
- package/src/collection/add.ts +9 -8
- package/src/collection/index.ts +3 -3
- package/src/collection/remove.ts +7 -6
- package/src/collection/types.ts +6 -6
- package/src/config/defaults.ts +1 -1
- package/src/config/index.ts +5 -5
- package/src/config/loader.ts +19 -18
- package/src/config/paths.ts +9 -8
- package/src/config/saver.ts +14 -13
- package/src/config/types.ts +53 -52
- package/src/converters/adapters/markitdownTs/adapter.ts +21 -19
- package/src/converters/adapters/officeparser/adapter.ts +18 -16
- package/src/converters/canonicalize.ts +12 -12
- package/src/converters/errors.ts +26 -22
- package/src/converters/index.ts +8 -8
- package/src/converters/mime.ts +25 -25
- package/src/converters/native/markdown.ts +10 -9
- package/src/converters/native/plaintext.ts +8 -7
- package/src/converters/path.ts +2 -2
- package/src/converters/pipeline.ts +11 -10
- package/src/converters/registry.ts +8 -8
- package/src/converters/types.ts +14 -14
- package/src/converters/versions.ts +4 -4
- package/src/index.ts +4 -4
- package/src/ingestion/chunker.ts +10 -9
- package/src/ingestion/index.ts +6 -6
- package/src/ingestion/language.ts +62 -62
- package/src/ingestion/sync.ts +50 -49
- package/src/ingestion/types.ts +10 -10
- package/src/ingestion/walker.ts +14 -13
- package/src/llm/cache.ts +51 -49
- package/src/llm/errors.ts +40 -36
- package/src/llm/index.ts +9 -9
- package/src/llm/lockfile.ts +6 -6
- package/src/llm/nodeLlamaCpp/adapter.ts +13 -12
- package/src/llm/nodeLlamaCpp/embedding.ts +9 -8
- package/src/llm/nodeLlamaCpp/generation.ts +7 -6
- package/src/llm/nodeLlamaCpp/lifecycle.ts +11 -10
- package/src/llm/nodeLlamaCpp/rerank.ts +6 -5
- package/src/llm/policy.ts +5 -5
- package/src/llm/registry.ts +6 -5
- package/src/llm/types.ts +2 -2
- package/src/mcp/resources/index.ts +15 -13
- package/src/mcp/server.ts +25 -23
- package/src/mcp/tools/get.ts +25 -23
- package/src/mcp/tools/index.ts +32 -29
- package/src/mcp/tools/multi-get.ts +34 -32
- package/src/mcp/tools/query.ts +29 -27
- package/src/mcp/tools/search.ts +14 -12
- package/src/mcp/tools/status.ts +12 -11
- package/src/mcp/tools/vsearch.ts +26 -24
- package/src/pipeline/answer.ts +9 -9
- package/src/pipeline/chunk-lookup.ts +1 -1
- package/src/pipeline/contextual.ts +4 -4
- package/src/pipeline/expansion.ts +23 -21
- package/src/pipeline/explain.ts +21 -21
- package/src/pipeline/fusion.ts +9 -9
- package/src/pipeline/hybrid.ts +41 -42
- package/src/pipeline/index.ts +10 -10
- package/src/pipeline/query-language.ts +39 -39
- package/src/pipeline/rerank.ts +8 -7
- package/src/pipeline/search.ts +22 -22
- package/src/pipeline/types.ts +8 -8
- package/src/pipeline/vsearch.ts +21 -24
- package/src/serve/CLAUDE.md +21 -15
- package/src/serve/config-sync.ts +9 -8
- package/src/serve/context.ts +19 -18
- package/src/serve/index.ts +1 -1
- package/src/serve/jobs.ts +7 -7
- package/src/serve/public/app.tsx +79 -25
- package/src/serve/public/components/AddCollectionDialog.tsx +382 -0
- package/src/serve/public/components/CaptureButton.tsx +60 -0
- package/src/serve/public/components/CaptureModal.tsx +365 -0
- package/src/serve/public/components/IndexingProgress.tsx +333 -0
- package/src/serve/public/components/ShortcutHelpModal.tsx +106 -0
- package/src/serve/public/components/ai-elements/code-block.tsx +42 -32
- package/src/serve/public/components/ai-elements/conversation.tsx +16 -14
- package/src/serve/public/components/ai-elements/inline-citation.tsx +33 -32
- package/src/serve/public/components/ai-elements/loader.tsx +5 -4
- package/src/serve/public/components/ai-elements/message.tsx +39 -37
- package/src/serve/public/components/ai-elements/prompt-input.tsx +97 -95
- package/src/serve/public/components/ai-elements/sources.tsx +12 -10
- package/src/serve/public/components/ai-elements/suggestion.tsx +10 -9
- package/src/serve/public/components/editor/CodeMirrorEditor.tsx +142 -0
- package/src/serve/public/components/editor/MarkdownPreview.tsx +311 -0
- package/src/serve/public/components/editor/index.ts +6 -0
- package/src/serve/public/components/preset-selector.tsx +29 -28
- package/src/serve/public/components/ui/badge.tsx +13 -12
- package/src/serve/public/components/ui/button-group.tsx +13 -12
- package/src/serve/public/components/ui/button.tsx +23 -22
- package/src/serve/public/components/ui/card.tsx +16 -16
- package/src/serve/public/components/ui/carousel.tsx +36 -35
- package/src/serve/public/components/ui/collapsible.tsx +1 -1
- package/src/serve/public/components/ui/command.tsx +17 -15
- package/src/serve/public/components/ui/dialog.tsx +13 -12
- package/src/serve/public/components/ui/dropdown-menu.tsx +13 -12
- package/src/serve/public/components/ui/hover-card.tsx +6 -5
- package/src/serve/public/components/ui/input-group.tsx +45 -43
- package/src/serve/public/components/ui/input.tsx +6 -6
- package/src/serve/public/components/ui/progress.tsx +5 -4
- package/src/serve/public/components/ui/scroll-area.tsx +11 -10
- package/src/serve/public/components/ui/select.tsx +19 -18
- package/src/serve/public/components/ui/separator.tsx +6 -5
- package/src/serve/public/components/ui/table.tsx +18 -18
- package/src/serve/public/components/ui/textarea.tsx +4 -4
- package/src/serve/public/components/ui/tooltip.tsx +5 -4
- package/src/serve/public/globals.css +27 -4
- package/src/serve/public/hooks/use-api.ts +8 -8
- package/src/serve/public/hooks/useCaptureModal.tsx +83 -0
- package/src/serve/public/hooks/useKeyboardShortcuts.ts +85 -0
- package/src/serve/public/index.html +4 -4
- package/src/serve/public/lib/utils.ts +6 -0
- package/src/serve/public/pages/Ask.tsx +27 -26
- package/src/serve/public/pages/Browse.tsx +28 -27
- package/src/serve/public/pages/Collections.tsx +439 -0
- package/src/serve/public/pages/Dashboard.tsx +166 -40
- package/src/serve/public/pages/DocView.tsx +258 -73
- package/src/serve/public/pages/DocumentEditor.tsx +510 -0
- package/src/serve/public/pages/Search.tsx +80 -58
- package/src/serve/routes/api.ts +272 -155
- package/src/serve/security.ts +4 -4
- package/src/serve/server.ts +66 -48
- package/src/store/index.ts +5 -5
- package/src/store/migrations/001-initial.ts +24 -23
- package/src/store/migrations/002-documents-fts.ts +7 -6
- package/src/store/migrations/index.ts +4 -4
- package/src/store/migrations/runner.ts +17 -15
- package/src/store/sqlite/adapter.ts +123 -121
- package/src/store/sqlite/fts5-snowball.ts +24 -23
- package/src/store/sqlite/index.ts +1 -1
- package/src/store/sqlite/setup.ts +12 -12
- package/src/store/sqlite/types.ts +4 -4
- package/src/store/types.ts +19 -19
- package/src/store/vector/index.ts +3 -3
- package/src/store/vector/sqlite-vec.ts +23 -20
- package/src/store/vector/stats.ts +10 -8
- package/src/store/vector/types.ts +2 -2
- package/vendor/fts5-snowball/README.md +6 -6
- package/assets/screenshots/webui-ask-answer.jpg +0 -0
- 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
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
import {
|
|
12
|
-
|
|
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:
|
|
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
|
|
78
|
+
case "docid":
|
|
77
79
|
return store.getDocumentByDocid(parsed.value);
|
|
78
|
-
case
|
|
80
|
+
case "uri":
|
|
79
81
|
return store.getDocumentByUri(parsed.value);
|
|
80
|
-
case
|
|
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(
|
|
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 (
|
|
188
|
-
ctx.skipped.push({ ref, reason:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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(
|
|
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:
|
|
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(
|
|
307
|
+
.split("\n")
|
|
306
308
|
.map((line, i) => `${startLine + i}: ${line}`)
|
|
307
|
-
.join(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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:
|
|
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(
|
|
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
|
|
16
|
-
import {
|
|
17
|
-
|
|
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
|
|
22
|
-
import { getGlobals } from
|
|
22
|
+
} from "../../store/vector";
|
|
23
|
+
import { getGlobals } from "../program";
|
|
23
24
|
import {
|
|
24
25
|
createProgressRenderer,
|
|
25
26
|
createThrottledProgressRenderer,
|
|
26
|
-
} from
|
|
27
|
-
import { initStore } from
|
|
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:
|
|
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
|
-
//
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 ===
|
|
241
|
+
return options.format === "json"
|
|
241
242
|
? JSON.stringify({
|
|
242
|
-
error: { code:
|
|
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(
|
|
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 =
|
|
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:
|
|
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:
|
|
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(
|
|
73
|
-
return { type:
|
|
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:
|
|
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
|
|
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
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
11
|
// node:path: path manipulation utilities (no Bun equivalent)
|
|
12
|
-
import { isAbsolute, normalize, sep } from
|
|
13
|
-
|
|
14
|
-
import {
|
|
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:
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
88
|
-
|
|
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,
|
|
98
|
+
assertSafePath(dirs.data, "Data");
|
|
98
99
|
if (!options.keepConfig) {
|
|
99
|
-
assertSafePath(dirs.config,
|
|
100
|
+
assertSafePath(dirs.config, "Config");
|
|
100
101
|
}
|
|
101
102
|
if (!options.keepCache) {
|
|
102
|
-
assertSafePath(dirs.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:
|
|
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:
|
|
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(
|
|
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 ===
|
|
143
|
-
return { path, status:
|
|
143
|
+
if (err.code === "ENOENT") {
|
|
144
|
+
return { path, status: "missing" };
|
|
144
145
|
}
|
|
145
|
-
return { path, status:
|
|
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:
|
|
151
|
+
return { path, status: "deleted" };
|
|
151
152
|
} catch (e) {
|
|
152
153
|
const err = e as NodeJS.ErrnoException;
|
|
153
|
-
return { path, status:
|
|
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 ===
|
|
162
|
-
const missing = result.results.filter((r) => r.status ===
|
|
163
|
-
const kept = result.results.filter((r) => r.status ===
|
|
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[] = [
|
|
166
|
+
const lines: string[] = ["GNO reset complete.", ""];
|
|
166
167
|
|
|
167
168
|
if (deleted.length > 0) {
|
|
168
|
-
lines.push(
|
|
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(
|
|
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(
|
|
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(
|
|
191
|
+
return lines.join("\n");
|
|
191
192
|
}
|
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
* @module src/cli/commands/search
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
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
|
|
14
|
-
import { initStore } from
|
|
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 ===
|
|
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[
|
|
96
|
+
function getFormatType(options: SearchCommandOptions): FormatOptions["format"] {
|
|
96
97
|
if (options.json) {
|
|
97
|
-
return
|
|
98
|
+
return "json";
|
|
98
99
|
}
|
|
99
100
|
if (options.files) {
|
|
100
|
-
return
|
|
101
|
+
return "files";
|
|
101
102
|
}
|
|
102
103
|
if (options.csv) {
|
|
103
|
-
return
|
|
104
|
+
return "csv";
|
|
104
105
|
}
|
|
105
106
|
if (options.md) {
|
|
106
|
-
return
|
|
107
|
+
return "md";
|
|
107
108
|
}
|
|
108
109
|
if (options.xml) {
|
|
109
|
-
return
|
|
110
|
+
return "xml";
|
|
110
111
|
}
|
|
111
|
-
return
|
|
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:
|
|
125
|
+
error: { code: "QUERY_FAILED", message: result.error },
|
|
125
126
|
})
|
|
126
127
|
: `Error: ${result.error}`;
|
|
127
128
|
}
|