@gmickel/gno 0.9.3 → 0.9.5
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/README.md +6 -6
- package/assets/skill/SKILL.md +172 -40
- package/package.json +7 -2
- package/src/cli/run.ts +34 -0
- package/src/config/types.ts +4 -4
- package/src/llm/registry.ts +1 -1
- package/src/pipeline/answer.ts +13 -10
- package/src/pipeline/search.ts +5 -1
package/README.md
CHANGED
|
@@ -332,14 +332,14 @@ Models auto-download on first use to `~/.cache/gno/models/`.
|
|
|
332
332
|
|
|
333
333
|
### Model Presets
|
|
334
334
|
|
|
335
|
-
| Preset | Disk | Best For
|
|
336
|
-
| :--------- | :----- |
|
|
337
|
-
| `slim` | ~1GB | Fast,
|
|
338
|
-
| `balanced` | ~2GB |
|
|
339
|
-
| `quality` | ~2.5GB | Best answers
|
|
335
|
+
| Preset | Disk | Best For |
|
|
336
|
+
| :--------- | :----- | :--------------------------- |
|
|
337
|
+
| `slim` | ~1GB | Fast, good quality (default) |
|
|
338
|
+
| `balanced` | ~2GB | Slightly larger model |
|
|
339
|
+
| `quality` | ~2.5GB | Best answers |
|
|
340
340
|
|
|
341
341
|
```bash
|
|
342
|
-
gno models use
|
|
342
|
+
gno models use slim
|
|
343
343
|
gno models pull --all # Optional: pre-download models (auto-downloads on first use)
|
|
344
344
|
```
|
|
345
345
|
|
package/assets/skill/SKILL.md
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gno
|
|
3
|
-
description: Search local documents, files, notes, and knowledge bases.
|
|
3
|
+
description: Search local documents, files, notes, and knowledge bases. Index directories, search with BM25/vector/hybrid, get AI answers with citations. Use when user wants to search files, find documents, query notes, look up information in local folders, index a directory, set up document search, build a knowledge base, needs RAG/semantic search, or wants to start a local web UI for their docs.
|
|
4
4
|
allowed-tools: Bash(gno:*), Read
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# GNO - Local
|
|
7
|
+
# GNO - Local Knowledge Engine
|
|
8
8
|
|
|
9
|
-
Fast local semantic search for your documents. Index once, search instantly.
|
|
9
|
+
Fast local semantic search for your documents. Index once, search instantly. No cloud, no API keys.
|
|
10
10
|
|
|
11
|
-
**Role**:
|
|
12
|
-
**Goal**:
|
|
11
|
+
**Role**: Document search and knowledge retrieval assistant
|
|
12
|
+
**Goal**: Help users index, search, query, and get answers from their local documents
|
|
13
13
|
|
|
14
14
|
## When to Use This Skill
|
|
15
15
|
|
|
16
16
|
- User asks to **search files, documents, or notes**
|
|
17
17
|
- User wants to **find information** in local folders
|
|
18
18
|
- User needs to **index a directory** for searching
|
|
19
|
-
- User mentions **PDFs, markdown, docs** they want to search
|
|
19
|
+
- User mentions **PDFs, markdown, Word docs, code** they want to search
|
|
20
20
|
- User asks about **knowledge base** or **RAG** setup
|
|
21
21
|
- User wants **semantic/vector search** over their files
|
|
22
22
|
- User needs to **set up MCP** for document access
|
|
23
|
+
- User wants a **web UI** to browse/search documents
|
|
24
|
+
- User asks to **get AI answers** from their documents
|
|
23
25
|
|
|
24
26
|
## Quick Start
|
|
25
27
|
|
|
@@ -39,6 +41,52 @@ gno search "your query"
|
|
|
39
41
|
|
|
40
42
|
## Core Commands
|
|
41
43
|
|
|
44
|
+
### Search Commands
|
|
45
|
+
|
|
46
|
+
| Command | Description |
|
|
47
|
+
| --------------------- | ------------------------------------------- |
|
|
48
|
+
| `gno search <query>` | BM25 keyword search (fast, exact terms) |
|
|
49
|
+
| `gno vsearch <query>` | Vector semantic search (meaning-based) |
|
|
50
|
+
| `gno query <query>` | Hybrid search (BM25 + vector + rerank) |
|
|
51
|
+
| `gno ask <question>` | Get AI answer with citations from your docs |
|
|
52
|
+
|
|
53
|
+
### Search Options
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Limit results
|
|
57
|
+
gno search "api" -n 10
|
|
58
|
+
|
|
59
|
+
# Filter by collection
|
|
60
|
+
gno query "auth" --collection work
|
|
61
|
+
|
|
62
|
+
# Search modes (for query/ask)
|
|
63
|
+
gno query "topic" --fast # ~0.7s, skip expansion/rerank
|
|
64
|
+
gno query "topic" # ~2-3s, default with rerank
|
|
65
|
+
gno query "topic" --thorough # ~5-8s, full pipeline
|
|
66
|
+
|
|
67
|
+
# Get AI answer
|
|
68
|
+
gno ask "how does auth work" --answer
|
|
69
|
+
|
|
70
|
+
# Output formats
|
|
71
|
+
gno search "test" --json # JSON for parsing
|
|
72
|
+
gno search "test" --files # URIs for piping
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Document Retrieval
|
|
76
|
+
|
|
77
|
+
| Command | Description |
|
|
78
|
+
| ------------------------- | ---------------------------- |
|
|
79
|
+
| `gno get <ref>` | Get document by URI or docid |
|
|
80
|
+
| `gno multi-get <refs...>` | Get multiple documents |
|
|
81
|
+
| `gno ls [scope]` | List indexed documents |
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
gno get gno://work/readme.md
|
|
85
|
+
gno get "#a1b2c3d4" --line-numbers
|
|
86
|
+
gno ls notes
|
|
87
|
+
gno ls --json
|
|
88
|
+
```
|
|
89
|
+
|
|
42
90
|
### Indexing
|
|
43
91
|
|
|
44
92
|
| Command | Description |
|
|
@@ -47,62 +95,146 @@ gno search "your query"
|
|
|
47
95
|
| `gno collection add <path> --name <name>` | Add folder to index |
|
|
48
96
|
| `gno index` | Full index (ingest + embed) |
|
|
49
97
|
| `gno update` | Sync files without embedding |
|
|
98
|
+
| `gno embed` | Generate embeddings only |
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
gno init
|
|
102
|
+
gno collection add ~/notes --name notes --pattern "**/*.md"
|
|
103
|
+
gno index
|
|
104
|
+
gno index --collection notes # Single collection
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Model Management
|
|
108
|
+
|
|
109
|
+
| Command | Description |
|
|
110
|
+
| ------------------ | ------------------------------------- |
|
|
111
|
+
| `gno models list` | Show available model presets |
|
|
112
|
+
| `gno models use` | Switch preset (slim/balanced/quality) |
|
|
113
|
+
| `gno models pull` | Download models |
|
|
114
|
+
| `gno models clear` | Remove cached models |
|
|
115
|
+
| `gno models path` | Show model cache directory |
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
gno models use slim # Default, fast (~1GB)
|
|
119
|
+
gno models use balanced # Larger model (~2GB)
|
|
120
|
+
gno models use quality # Best answers (~2.5GB)
|
|
121
|
+
gno models pull --all
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Context Hints
|
|
50
125
|
|
|
51
|
-
|
|
126
|
+
| Command | Description |
|
|
127
|
+
| -------------------------------- | ---------------------- |
|
|
128
|
+
| `gno context add <scope> "text"` | Add context for scope |
|
|
129
|
+
| `gno context list` | List all contexts |
|
|
130
|
+
| `gno context check` | Validate configuration |
|
|
131
|
+
| `gno context rm <scope>` | Remove a context |
|
|
52
132
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
| `gno query <query>` | Hybrid search (BM25 + vector + rerank) |
|
|
58
|
-
| `gno ask <question>` | AI-powered Q&A with citations |
|
|
133
|
+
```bash
|
|
134
|
+
gno context add "/" "Corporate knowledge base"
|
|
135
|
+
gno context add "work:" "Work documents and contracts"
|
|
136
|
+
```
|
|
59
137
|
|
|
60
|
-
###
|
|
138
|
+
### Web UI
|
|
61
139
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
140
|
+
| Command | Description |
|
|
141
|
+
| ------------------- | ------------------------ |
|
|
142
|
+
| `gno serve` | Start web UI (port 3000) |
|
|
143
|
+
| `gno serve -p 8080` | Custom port |
|
|
66
144
|
|
|
67
|
-
|
|
145
|
+
Features: Dashboard, search, browse, document editor, AI Q&A with citations.
|
|
68
146
|
|
|
69
|
-
###
|
|
147
|
+
### MCP Server
|
|
148
|
+
|
|
149
|
+
| Command | Description |
|
|
150
|
+
| ------------------- | ------------------------------- |
|
|
151
|
+
| `gno mcp` | Start MCP server (stdio) |
|
|
152
|
+
| `gno mcp install` | Install for Claude Desktop, etc |
|
|
153
|
+
| `gno mcp uninstall` | Remove MCP configuration |
|
|
154
|
+
| `gno mcp status` | Show installation status |
|
|
70
155
|
|
|
71
156
|
```bash
|
|
72
|
-
|
|
73
|
-
gno
|
|
157
|
+
gno mcp install --target claude-desktop
|
|
158
|
+
gno mcp install --target cursor
|
|
159
|
+
gno mcp install --target claude-code --scope project
|
|
160
|
+
```
|
|
74
161
|
|
|
75
|
-
|
|
76
|
-
gno vsearch "how to cancel contract"
|
|
162
|
+
### Skill Management
|
|
77
163
|
|
|
78
|
-
|
|
79
|
-
|
|
164
|
+
| Command | Description |
|
|
165
|
+
| --------------------- | --------------------------- |
|
|
166
|
+
| `gno skill install` | Install skill for AI agents |
|
|
167
|
+
| `gno skill uninstall` | Remove skill |
|
|
168
|
+
| `gno skill show` | Preview skill files |
|
|
169
|
+
| `gno skill paths` | Show installation paths |
|
|
80
170
|
|
|
81
|
-
|
|
82
|
-
gno
|
|
171
|
+
```bash
|
|
172
|
+
gno skill install --target claude --scope project
|
|
173
|
+
gno skill install --target codex --scope user
|
|
83
174
|
```
|
|
84
175
|
|
|
85
|
-
###
|
|
176
|
+
### Admin Commands
|
|
177
|
+
|
|
178
|
+
| Command | Description |
|
|
179
|
+
| ---------------- | ----------------------------- |
|
|
180
|
+
| `gno status` | Show index status |
|
|
181
|
+
| `gno doctor` | Check system health |
|
|
182
|
+
| `gno cleanup` | Remove orphaned data |
|
|
183
|
+
| `gno reset` | Delete all data (use caution) |
|
|
184
|
+
| `gno completion` | Shell tab completion |
|
|
86
185
|
|
|
87
186
|
```bash
|
|
88
|
-
|
|
89
|
-
gno
|
|
187
|
+
gno status --json
|
|
188
|
+
gno doctor
|
|
189
|
+
gno completion install
|
|
190
|
+
```
|
|
90
191
|
|
|
91
|
-
|
|
92
|
-
gno get "#a1b2c3d4" --line-numbers
|
|
192
|
+
## Global Flags
|
|
93
193
|
|
|
94
|
-
# List documents
|
|
95
|
-
gno ls docs
|
|
96
194
|
```
|
|
195
|
+
--index <name> Use alternate index (default: "default")
|
|
196
|
+
--config <path> Override config file path
|
|
197
|
+
--no-color Disable colored output
|
|
198
|
+
--no-pager Disable automatic paging
|
|
199
|
+
--verbose Enable verbose logging
|
|
200
|
+
--yes Non-interactive mode
|
|
201
|
+
--offline Use cached models only
|
|
202
|
+
--json JSON output (where supported)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Common Patterns
|
|
97
206
|
|
|
98
|
-
###
|
|
207
|
+
### Search & Get Full Content
|
|
99
208
|
|
|
100
209
|
```bash
|
|
101
|
-
#
|
|
102
|
-
gno search "api" --
|
|
210
|
+
# Find documents, get full content
|
|
211
|
+
gno search "api design" --files | head -1 | cut -d, -f3 | xargs gno get
|
|
103
212
|
|
|
104
|
-
#
|
|
105
|
-
gno
|
|
213
|
+
# JSON pipeline
|
|
214
|
+
gno query "auth" --json | jq -r '.results[0].uri' | xargs gno get
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### AI-Powered Q&A
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Get answer with sources
|
|
221
|
+
gno ask "what are the deployment steps" --answer
|
|
222
|
+
|
|
223
|
+
# Show all retrieved sources
|
|
224
|
+
gno ask "summarize the auth discussion" --answer --show-sources
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Scripting
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Check if indexed
|
|
231
|
+
gno status --json | jq '.healthy'
|
|
232
|
+
|
|
233
|
+
# List all URIs
|
|
234
|
+
gno ls --files
|
|
235
|
+
|
|
236
|
+
# Batch get
|
|
237
|
+
gno multi-get abc123 def456 ghi789 --max-bytes 10000
|
|
106
238
|
```
|
|
107
239
|
|
|
108
240
|
## Reference
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gmickel/gno",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"description": "Local semantic search for your documents. Index Markdown, PDF, and Office files with hybrid BM25 + vector search.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"embeddings",
|
|
@@ -48,6 +48,9 @@
|
|
|
48
48
|
"test:coverage": "bun test --coverage",
|
|
49
49
|
"test:coverage:html": "bun test --coverage --html",
|
|
50
50
|
"test:fixtures": "bun scripts/generate-test-fixtures.ts",
|
|
51
|
+
"evals": "bun scripts/update-eval-scores.ts",
|
|
52
|
+
"eval": "bun --bun evalite",
|
|
53
|
+
"eval:watch": "bun --bun evalite watch",
|
|
51
54
|
"reset": "bun run src/index.ts reset --confirm",
|
|
52
55
|
"docs:verify": "bun run scripts/docs-verify.ts",
|
|
53
56
|
"website:install": "cd website && bundle install",
|
|
@@ -110,6 +113,7 @@
|
|
|
110
113
|
"zod": "^4.3.4"
|
|
111
114
|
},
|
|
112
115
|
"devDependencies": {
|
|
116
|
+
"@ai-sdk/openai": "^3.0.2",
|
|
113
117
|
"@biomejs/biome": "2.3.10",
|
|
114
118
|
"@tailwindcss/cli": "^4.1.18",
|
|
115
119
|
"@types/bun": "latest",
|
|
@@ -126,7 +130,8 @@
|
|
|
126
130
|
"oxlint-tsgolint": "^0.10.1",
|
|
127
131
|
"pdf-lib": "^1.17.1",
|
|
128
132
|
"pptxgenjs": "^4.0.1",
|
|
129
|
-
"ultracite": "7.0.4"
|
|
133
|
+
"ultracite": "7.0.4",
|
|
134
|
+
"vitest": "^4.0.16"
|
|
130
135
|
},
|
|
131
136
|
"peerDependencies": {
|
|
132
137
|
"typescript": "^5"
|
package/src/cli/run.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { CommanderError } from "commander";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
9
11
|
|
|
10
12
|
import { CLI_NAME, PRODUCT_NAME } from "../app/constants";
|
|
11
13
|
import { CliError, exitCodeFor, formatErrorForOutput } from "./errors";
|
|
@@ -54,6 +56,32 @@ function isKnownValueFlag(arg: string): boolean {
|
|
|
54
56
|
return false;
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Check if --skill flag is present in argv (before end-of-options marker).
|
|
61
|
+
*/
|
|
62
|
+
function argvWantsSkill(argv: string[]): boolean {
|
|
63
|
+
for (const arg of argv) {
|
|
64
|
+
if (arg === "--") {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
if (arg === "--skill") {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Output SKILL.md content for agent discovery.
|
|
76
|
+
* Clean output with no extra text (suitable for piping/parsing).
|
|
77
|
+
*/
|
|
78
|
+
async function printSkillFile(): Promise<void> {
|
|
79
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
80
|
+
const skillPath = join(__dirname, "../../assets/skill/SKILL.md");
|
|
81
|
+
const content = await Bun.file(skillPath).text();
|
|
82
|
+
process.stdout.write(content);
|
|
83
|
+
}
|
|
84
|
+
|
|
57
85
|
/**
|
|
58
86
|
* Check if argv has no subcommand (only known global flags).
|
|
59
87
|
* Returns true for: gno, gno --json, gno --quiet --verbose
|
|
@@ -146,6 +174,12 @@ export async function runCli(argv: string[]): Promise<number> {
|
|
|
146
174
|
|
|
147
175
|
const isJson = argvWantsJson(argv);
|
|
148
176
|
|
|
177
|
+
// Handle --skill flag: output SKILL.md for agent discovery
|
|
178
|
+
if (argvWantsSkill(argv)) {
|
|
179
|
+
await printSkillFile();
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
|
|
149
183
|
// Handle "no subcommand" case before Commander (avoids full help display)
|
|
150
184
|
if (hasNoSubcommand(argv)) {
|
|
151
185
|
printConciseHelp({ json: isJson });
|
package/src/config/types.ts
CHANGED
|
@@ -176,7 +176,7 @@ export type ModelPreset = z.infer<typeof ModelPresetSchema>;
|
|
|
176
176
|
export const DEFAULT_MODEL_PRESETS: ModelPreset[] = [
|
|
177
177
|
{
|
|
178
178
|
id: "slim",
|
|
179
|
-
name: "Slim (
|
|
179
|
+
name: "Slim (Default, ~1GB)",
|
|
180
180
|
embed: "hf:gpustack/bge-m3-GGUF/bge-m3-Q4_K_M.gguf",
|
|
181
181
|
rerank:
|
|
182
182
|
"hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/qwen3-reranker-0.6b-q8_0.gguf",
|
|
@@ -184,11 +184,11 @@ export const DEFAULT_MODEL_PRESETS: ModelPreset[] = [
|
|
|
184
184
|
},
|
|
185
185
|
{
|
|
186
186
|
id: "balanced",
|
|
187
|
-
name: "Balanced (
|
|
187
|
+
name: "Balanced (~2GB)",
|
|
188
188
|
embed: "hf:gpustack/bge-m3-GGUF/bge-m3-Q4_K_M.gguf",
|
|
189
189
|
rerank:
|
|
190
190
|
"hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/qwen3-reranker-0.6b-q8_0.gguf",
|
|
191
|
-
gen: "hf:
|
|
191
|
+
gen: "hf:bartowski/Qwen2.5-3B-Instruct-GGUF/Qwen2.5-3B-Instruct-Q4_K_M.gguf",
|
|
192
192
|
},
|
|
193
193
|
{
|
|
194
194
|
id: "quality",
|
|
@@ -202,7 +202,7 @@ export const DEFAULT_MODEL_PRESETS: ModelPreset[] = [
|
|
|
202
202
|
|
|
203
203
|
export const ModelConfigSchema = z.object({
|
|
204
204
|
/** Active preset ID */
|
|
205
|
-
activePreset: z.string().default("
|
|
205
|
+
activePreset: z.string().default("slim"),
|
|
206
206
|
/** Model presets */
|
|
207
207
|
presets: z.array(ModelPresetSchema).default(DEFAULT_MODEL_PRESETS),
|
|
208
208
|
/** Model load timeout in ms */
|
package/src/llm/registry.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { DEFAULT_MODEL_PRESETS } from "../config/types";
|
|
|
19
19
|
*/
|
|
20
20
|
export function getModelConfig(config: Config): ModelConfig {
|
|
21
21
|
return {
|
|
22
|
-
activePreset: config.models?.activePreset ?? "
|
|
22
|
+
activePreset: config.models?.activePreset ?? "slim",
|
|
23
23
|
presets: config.models?.presets?.length
|
|
24
24
|
? config.models.presets
|
|
25
25
|
: DEFAULT_MODEL_PRESETS,
|
package/src/pipeline/answer.ts
CHANGED
|
@@ -13,21 +13,24 @@ import type { Citation, SearchResult } from "./types";
|
|
|
13
13
|
// Constants
|
|
14
14
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
15
|
|
|
16
|
-
const ANSWER_PROMPT = `
|
|
16
|
+
const ANSWER_PROMPT = `Answer the question using ONLY the context blocks below. Cite sources with [1], [2], etc.
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
4) Do not cite sources you did not use. Do not invent citation numbers.
|
|
18
|
+
Example:
|
|
19
|
+
Q: What is the capital of France?
|
|
20
|
+
Context:
|
|
21
|
+
[1] France is a country in Western Europe. Paris is the capital and largest city.
|
|
22
|
+
[2] The Eiffel Tower, built in 1889, is located in Paris.
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
Answer: Paris is the capital of France [1]. It is home to the Eiffel Tower [2].
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
Q: {query}
|
|
29
|
+
|
|
30
|
+
Context:
|
|
28
31
|
{context}
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
Answer:`;
|
|
31
34
|
|
|
32
35
|
/** Abstention message when LLM cannot ground answer */
|
|
33
36
|
export const ABSTENTION_MESSAGE =
|
package/src/pipeline/search.ts
CHANGED
|
@@ -223,7 +223,11 @@ export async function searchBm25(
|
|
|
223
223
|
|
|
224
224
|
// For --full, fetch full content and build results
|
|
225
225
|
if (options.full) {
|
|
226
|
-
|
|
226
|
+
// Sort by raw BM25 score (smaller = better) before building results
|
|
227
|
+
const sortedEntries = [...bestByDocid.values()].sort(
|
|
228
|
+
(a, b) => a.score - b.score
|
|
229
|
+
);
|
|
230
|
+
for (const { fts, chunk } of sortedEntries) {
|
|
227
231
|
let fullContent: string | undefined;
|
|
228
232
|
if (fts.mirrorHash) {
|
|
229
233
|
const contentResult = await store.getContent(fts.mirrorHash);
|