@gmickel/gno 0.25.2 → 0.27.0
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 +5 -3
- package/assets/skill/SKILL.md +5 -0
- package/assets/skill/cli-reference.md +8 -6
- package/package.json +1 -1
- package/src/cli/commands/get.ts +21 -0
- package/src/cli/commands/skill/install.ts +2 -2
- package/src/cli/commands/skill/paths.ts +26 -4
- package/src/cli/commands/skill/uninstall.ts +2 -2
- package/src/cli/program.ts +18 -12
- package/src/core/document-capabilities.ts +113 -0
- package/src/mcp/tools/get.ts +10 -0
- package/src/mcp/tools/index.ts +434 -110
- package/src/sdk/documents.ts +12 -0
- package/src/serve/doc-events.ts +69 -0
- package/src/serve/public/app.tsx +81 -24
- package/src/serve/public/components/CaptureModal.tsx +138 -3
- package/src/serve/public/components/QuickSwitcher.tsx +248 -0
- package/src/serve/public/components/ShortcutHelpModal.tsx +1 -0
- package/src/serve/public/components/ai-elements/code-block.tsx +74 -26
- package/src/serve/public/components/editor/CodeMirrorEditor.tsx +51 -0
- package/src/serve/public/components/ui/command.tsx +2 -2
- package/src/serve/public/hooks/use-doc-events.ts +34 -0
- package/src/serve/public/hooks/useCaptureModal.tsx +12 -3
- package/src/serve/public/hooks/useKeyboardShortcuts.ts +2 -2
- package/src/serve/public/lib/deep-links.ts +68 -0
- package/src/serve/public/lib/document-availability.ts +22 -0
- package/src/serve/public/lib/local-history.ts +44 -0
- package/src/serve/public/lib/wiki-link.ts +36 -0
- package/src/serve/public/pages/Browse.tsx +11 -0
- package/src/serve/public/pages/Dashboard.tsx +2 -2
- package/src/serve/public/pages/DocView.tsx +241 -18
- package/src/serve/public/pages/DocumentEditor.tsx +399 -9
- package/src/serve/public/pages/Search.tsx +20 -1
- package/src/serve/routes/api.ts +359 -28
- package/src/serve/server.ts +48 -1
- package/src/serve/watch-service.ts +149 -0
package/src/mcp/tools/index.ts
CHANGED
|
@@ -51,92 +51,284 @@ export function normalizeTagFilters(tags?: string[]): string[] | undefined {
|
|
|
51
51
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
52
52
|
|
|
53
53
|
const searchInputSchema = z.object({
|
|
54
|
-
query: z
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
query: z
|
|
55
|
+
.string()
|
|
56
|
+
.min(1, "Query cannot be empty")
|
|
57
|
+
.describe("Search query text"),
|
|
58
|
+
collection: z
|
|
59
|
+
.string()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe("Filter to a single collection name"),
|
|
62
|
+
limit: z
|
|
63
|
+
.number()
|
|
64
|
+
.int()
|
|
65
|
+
.min(1)
|
|
66
|
+
.max(100)
|
|
67
|
+
.default(5)
|
|
68
|
+
.describe("Max results to return"),
|
|
69
|
+
minScore: z
|
|
70
|
+
.number()
|
|
71
|
+
.min(0)
|
|
72
|
+
.max(1)
|
|
73
|
+
.optional()
|
|
74
|
+
.describe("Minimum relevance score (0-1). Omit to return all matches"),
|
|
75
|
+
lang: z
|
|
76
|
+
.string()
|
|
77
|
+
.optional()
|
|
78
|
+
.describe(
|
|
79
|
+
"BCP-47 language hint for tokenization (e.g. 'en', 'de'). Auto-detected if omitted"
|
|
80
|
+
),
|
|
81
|
+
intent: z
|
|
82
|
+
.string()
|
|
83
|
+
.optional()
|
|
84
|
+
.describe(
|
|
85
|
+
"Disambiguating context for ambiguous queries (e.g. 'programming language' when query is 'python')"
|
|
86
|
+
),
|
|
87
|
+
exclude: z
|
|
88
|
+
.array(z.string())
|
|
89
|
+
.optional()
|
|
90
|
+
.describe("Exclude documents containing any of these terms"),
|
|
91
|
+
since: z
|
|
92
|
+
.string()
|
|
93
|
+
.optional()
|
|
94
|
+
.describe(
|
|
95
|
+
"Only docs modified after this date (ISO format: 2026-03-01 or 2026-03-01T00:00:00)"
|
|
96
|
+
),
|
|
97
|
+
until: z
|
|
98
|
+
.string()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe("Only docs modified before this date (ISO format)"),
|
|
101
|
+
categories: z
|
|
102
|
+
.array(z.string())
|
|
103
|
+
.optional()
|
|
104
|
+
.describe("Require category match (from document frontmatter)"),
|
|
105
|
+
author: z
|
|
106
|
+
.string()
|
|
107
|
+
.optional()
|
|
108
|
+
.describe("Filter by author (case-insensitive substring match)"),
|
|
109
|
+
tagsAll: z
|
|
110
|
+
.array(z.string())
|
|
111
|
+
.optional()
|
|
112
|
+
.describe("Require ALL of these tags (AND filter)"),
|
|
113
|
+
tagsAny: z
|
|
114
|
+
.array(z.string())
|
|
115
|
+
.optional()
|
|
116
|
+
.describe("Require ANY of these tags (OR filter)"),
|
|
67
117
|
});
|
|
68
118
|
|
|
69
119
|
const captureInputSchema = z.object({
|
|
70
|
-
collection: z
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
120
|
+
collection: z
|
|
121
|
+
.string()
|
|
122
|
+
.min(1, "Collection cannot be empty")
|
|
123
|
+
.describe("Target collection name (must already exist)"),
|
|
124
|
+
content: z.string().describe("Document content (markdown or plain text)"),
|
|
125
|
+
title: z
|
|
126
|
+
.string()
|
|
127
|
+
.optional()
|
|
128
|
+
.describe("Document title. Auto-derived from content if omitted"),
|
|
129
|
+
path: z
|
|
130
|
+
.string()
|
|
131
|
+
.optional()
|
|
132
|
+
.describe(
|
|
133
|
+
"Relative path within collection (e.g. 'notes/meeting.md'). Auto-generated from title if omitted"
|
|
134
|
+
),
|
|
135
|
+
overwrite: z
|
|
136
|
+
.boolean()
|
|
137
|
+
.default(false)
|
|
138
|
+
.describe("Overwrite if file already exists at path"),
|
|
139
|
+
tags: z
|
|
140
|
+
.array(z.string())
|
|
141
|
+
.optional()
|
|
142
|
+
.describe("Tags to apply to the new document"),
|
|
76
143
|
});
|
|
77
144
|
|
|
78
145
|
const addCollectionInputSchema = z.object({
|
|
79
|
-
path: z
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
146
|
+
path: z
|
|
147
|
+
.string()
|
|
148
|
+
.min(1, "Path cannot be empty")
|
|
149
|
+
.describe("Absolute path to the directory to index"),
|
|
150
|
+
name: z
|
|
151
|
+
.string()
|
|
152
|
+
.optional()
|
|
153
|
+
.describe("Collection name. Auto-derived from directory name if omitted"),
|
|
154
|
+
pattern: z
|
|
155
|
+
.string()
|
|
156
|
+
.optional()
|
|
157
|
+
.describe(
|
|
158
|
+
"Glob pattern for files to include (default: '**/*'). E.g. '**/*.md' for markdown only"
|
|
159
|
+
),
|
|
160
|
+
include: z
|
|
161
|
+
.array(z.string())
|
|
162
|
+
.optional()
|
|
163
|
+
.describe("Extension allowlist (e.g. ['.md', '.pdf', '.docx'])"),
|
|
164
|
+
exclude: z
|
|
165
|
+
.array(z.string())
|
|
166
|
+
.optional()
|
|
167
|
+
.describe("Glob patterns to exclude (default: ['.git', 'node_modules'])"),
|
|
168
|
+
gitPull: z
|
|
169
|
+
.boolean()
|
|
170
|
+
.default(false)
|
|
171
|
+
.describe("Run git pull before indexing (if collection is a git repo)"),
|
|
85
172
|
});
|
|
86
173
|
|
|
87
174
|
const syncInputSchema = z.object({
|
|
88
|
-
collection: z
|
|
89
|
-
|
|
90
|
-
|
|
175
|
+
collection: z
|
|
176
|
+
.string()
|
|
177
|
+
.optional()
|
|
178
|
+
.describe("Collection name to sync. Omit to sync all collections"),
|
|
179
|
+
gitPull: z.boolean().default(false).describe("Run git pull before syncing"),
|
|
180
|
+
runUpdateCmd: z
|
|
181
|
+
.boolean()
|
|
182
|
+
.default(false)
|
|
183
|
+
.describe("Run the collection's configured update command before syncing"),
|
|
91
184
|
});
|
|
92
185
|
|
|
93
186
|
const embedInputSchema = z.object({});
|
|
94
187
|
|
|
95
188
|
const indexInputSchema = z.object({
|
|
96
|
-
collection: z
|
|
97
|
-
|
|
189
|
+
collection: z
|
|
190
|
+
.string()
|
|
191
|
+
.optional()
|
|
192
|
+
.describe("Collection name to index. Omit to index all collections"),
|
|
193
|
+
gitPull: z.boolean().default(false).describe("Run git pull before indexing"),
|
|
98
194
|
});
|
|
99
195
|
|
|
100
196
|
const removeCollectionInputSchema = z.object({
|
|
101
|
-
collection: z
|
|
197
|
+
collection: z
|
|
198
|
+
.string()
|
|
199
|
+
.min(1, "Collection cannot be empty")
|
|
200
|
+
.describe("Collection name to remove"),
|
|
102
201
|
});
|
|
103
202
|
|
|
104
203
|
const vsearchInputSchema = z.object({
|
|
105
|
-
query: z
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
204
|
+
query: z
|
|
205
|
+
.string()
|
|
206
|
+
.min(1, "Query cannot be empty")
|
|
207
|
+
.describe("Search query text (matched by semantic meaning, not keywords)"),
|
|
208
|
+
collection: z
|
|
209
|
+
.string()
|
|
210
|
+
.optional()
|
|
211
|
+
.describe("Filter to a single collection name"),
|
|
212
|
+
limit: z
|
|
213
|
+
.number()
|
|
214
|
+
.int()
|
|
215
|
+
.min(1)
|
|
216
|
+
.max(100)
|
|
217
|
+
.default(5)
|
|
218
|
+
.describe("Max results to return"),
|
|
219
|
+
minScore: z
|
|
220
|
+
.number()
|
|
221
|
+
.min(0)
|
|
222
|
+
.max(1)
|
|
223
|
+
.optional()
|
|
224
|
+
.describe("Minimum similarity score (0-1)"),
|
|
225
|
+
lang: z
|
|
226
|
+
.string()
|
|
227
|
+
.optional()
|
|
228
|
+
.describe("BCP-47 language hint (e.g. 'en', 'de')"),
|
|
229
|
+
intent: z
|
|
230
|
+
.string()
|
|
231
|
+
.optional()
|
|
232
|
+
.describe("Disambiguating context for the query"),
|
|
233
|
+
exclude: z
|
|
234
|
+
.array(z.string())
|
|
235
|
+
.optional()
|
|
236
|
+
.describe("Exclude documents containing any of these terms"),
|
|
237
|
+
since: z
|
|
238
|
+
.string()
|
|
239
|
+
.optional()
|
|
240
|
+
.describe("Only docs modified after this date (ISO format)"),
|
|
241
|
+
until: z
|
|
242
|
+
.string()
|
|
243
|
+
.optional()
|
|
244
|
+
.describe("Only docs modified before this date (ISO format)"),
|
|
245
|
+
categories: z.array(z.string()).optional().describe("Require category match"),
|
|
246
|
+
author: z
|
|
247
|
+
.string()
|
|
248
|
+
.optional()
|
|
249
|
+
.describe("Filter by author (case-insensitive substring)"),
|
|
250
|
+
tagsAll: z.array(z.string()).optional().describe("Require ALL of these tags"),
|
|
251
|
+
tagsAny: z.array(z.string()).optional().describe("Require ANY of these tags"),
|
|
118
252
|
});
|
|
119
253
|
|
|
120
254
|
const queryModeInputSchema = z.object({
|
|
121
|
-
mode: z
|
|
122
|
-
|
|
255
|
+
mode: z
|
|
256
|
+
.enum(["term", "intent", "hyde"])
|
|
257
|
+
.describe(
|
|
258
|
+
"Retrieval strategy: 'term' (keyword match), 'intent' (disambiguation), 'hyde' (hypothetical document for semantic matching)"
|
|
259
|
+
),
|
|
260
|
+
text: z
|
|
261
|
+
.string()
|
|
262
|
+
.trim()
|
|
263
|
+
.min(1, "Query mode text cannot be empty")
|
|
264
|
+
.describe("Text for this query mode"),
|
|
123
265
|
});
|
|
124
266
|
|
|
125
267
|
export const queryInputSchema = z.object({
|
|
126
|
-
query: z
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
268
|
+
query: z
|
|
269
|
+
.string()
|
|
270
|
+
.min(1, "Query cannot be empty")
|
|
271
|
+
.describe("Search query text"),
|
|
272
|
+
collection: z
|
|
273
|
+
.string()
|
|
274
|
+
.optional()
|
|
275
|
+
.describe("Filter to a single collection name"),
|
|
276
|
+
limit: z
|
|
277
|
+
.number()
|
|
278
|
+
.int()
|
|
279
|
+
.min(1)
|
|
280
|
+
.max(100)
|
|
281
|
+
.default(5)
|
|
282
|
+
.describe("Max results to return"),
|
|
283
|
+
minScore: z
|
|
284
|
+
.number()
|
|
285
|
+
.min(0)
|
|
286
|
+
.max(1)
|
|
287
|
+
.optional()
|
|
288
|
+
.describe("Minimum relevance score (0-1)"),
|
|
289
|
+
lang: z
|
|
290
|
+
.string()
|
|
291
|
+
.optional()
|
|
292
|
+
.describe(
|
|
293
|
+
"BCP-47 language hint (e.g. 'en', 'de'). Auto-detected if omitted"
|
|
294
|
+
),
|
|
295
|
+
intent: z
|
|
296
|
+
.string()
|
|
297
|
+
.optional()
|
|
298
|
+
.describe(
|
|
299
|
+
"Disambiguating context (e.g. 'programming language' when query is 'python')"
|
|
300
|
+
),
|
|
301
|
+
candidateLimit: z
|
|
302
|
+
.number()
|
|
303
|
+
.int()
|
|
304
|
+
.min(1)
|
|
305
|
+
.max(100)
|
|
306
|
+
.optional()
|
|
307
|
+
.describe(
|
|
308
|
+
"Max candidates passed to reranking stage (higher = better recall, slower)"
|
|
309
|
+
),
|
|
310
|
+
exclude: z
|
|
311
|
+
.array(z.string())
|
|
312
|
+
.optional()
|
|
313
|
+
.describe("Exclude documents containing any of these terms"),
|
|
314
|
+
since: z
|
|
315
|
+
.string()
|
|
316
|
+
.optional()
|
|
317
|
+
.describe("Only docs modified after this date (ISO format)"),
|
|
318
|
+
until: z
|
|
319
|
+
.string()
|
|
320
|
+
.optional()
|
|
321
|
+
.describe("Only docs modified before this date (ISO format)"),
|
|
322
|
+
categories: z.array(z.string()).optional().describe("Require category match"),
|
|
323
|
+
author: z
|
|
324
|
+
.string()
|
|
325
|
+
.optional()
|
|
326
|
+
.describe("Filter by author (case-insensitive substring)"),
|
|
138
327
|
queryModes: z
|
|
139
328
|
.array(queryModeInputSchema)
|
|
329
|
+
.describe(
|
|
330
|
+
"Structured query modes to combine multiple retrieval strategies. Max one 'hyde' entry."
|
|
331
|
+
)
|
|
140
332
|
.superRefine((entries, ctx) => {
|
|
141
333
|
const hydeCount = entries.filter((entry) => entry.mode === "hyde").length;
|
|
142
334
|
if (hydeCount > 1) {
|
|
@@ -147,68 +339,200 @@ export const queryInputSchema = z.object({
|
|
|
147
339
|
}
|
|
148
340
|
})
|
|
149
341
|
.optional(),
|
|
150
|
-
fast: z
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
342
|
+
fast: z
|
|
343
|
+
.boolean()
|
|
344
|
+
.default(false)
|
|
345
|
+
.describe("Skip expansion and reranking (~0.7s). Use for quick lookups"),
|
|
346
|
+
thorough: z
|
|
347
|
+
.boolean()
|
|
348
|
+
.default(false)
|
|
349
|
+
.describe(
|
|
350
|
+
"Enable query expansion for best recall (~5-8s). Use when default returns no results"
|
|
351
|
+
),
|
|
352
|
+
expand: z
|
|
353
|
+
.boolean()
|
|
354
|
+
.optional()
|
|
355
|
+
.describe("Override: enable/disable query expansion"),
|
|
356
|
+
rerank: z
|
|
357
|
+
.boolean()
|
|
358
|
+
.optional()
|
|
359
|
+
.describe("Override: enable/disable cross-encoder reranking"),
|
|
360
|
+
tagsAll: z.array(z.string()).optional().describe("Require ALL of these tags"),
|
|
361
|
+
tagsAny: z.array(z.string()).optional().describe("Require ANY of these tags"),
|
|
156
362
|
});
|
|
157
363
|
|
|
158
364
|
const getInputSchema = z.object({
|
|
159
|
-
ref: z
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
365
|
+
ref: z
|
|
366
|
+
.string()
|
|
367
|
+
.min(1, "Reference cannot be empty")
|
|
368
|
+
.describe(
|
|
369
|
+
"Document reference: URI (gno://collection/path), docid (#abc123), or collection/path"
|
|
370
|
+
),
|
|
371
|
+
fromLine: z
|
|
372
|
+
.number()
|
|
373
|
+
.int()
|
|
374
|
+
.min(1)
|
|
375
|
+
.optional()
|
|
376
|
+
.describe("Start reading from this line number"),
|
|
377
|
+
lineCount: z
|
|
378
|
+
.number()
|
|
379
|
+
.int()
|
|
380
|
+
.min(1)
|
|
381
|
+
.optional()
|
|
382
|
+
.describe("Number of lines to return (from fromLine)"),
|
|
383
|
+
lineNumbers: z
|
|
384
|
+
.boolean()
|
|
385
|
+
.default(true)
|
|
386
|
+
.describe("Include line numbers in output"),
|
|
163
387
|
});
|
|
164
388
|
|
|
165
389
|
const multiGetInputSchema = z.object({
|
|
166
|
-
refs: z
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
390
|
+
refs: z
|
|
391
|
+
.array(z.string())
|
|
392
|
+
.min(1)
|
|
393
|
+
.optional()
|
|
394
|
+
.describe("Array of document references (URIs or docids)"),
|
|
395
|
+
pattern: z
|
|
396
|
+
.string()
|
|
397
|
+
.optional()
|
|
398
|
+
.describe("Glob pattern to match documents (e.g. 'work/**/*.md')"),
|
|
399
|
+
maxBytes: z
|
|
400
|
+
.number()
|
|
401
|
+
.int()
|
|
402
|
+
.min(1)
|
|
403
|
+
.default(10_240)
|
|
404
|
+
.describe("Max bytes per document (truncates longer docs)"),
|
|
405
|
+
lineNumbers: z
|
|
406
|
+
.boolean()
|
|
407
|
+
.default(true)
|
|
408
|
+
.describe("Include line numbers in output"),
|
|
170
409
|
});
|
|
171
410
|
|
|
172
411
|
const statusInputSchema = z.object({});
|
|
173
412
|
|
|
174
413
|
const jobStatusInputSchema = z.object({
|
|
175
|
-
jobId: z
|
|
414
|
+
jobId: z
|
|
415
|
+
.string()
|
|
416
|
+
.min(1, "Job ID cannot be empty")
|
|
417
|
+
.describe("Job ID returned by async operations (embed, index)"),
|
|
176
418
|
});
|
|
177
419
|
|
|
178
420
|
const listJobsInputSchema = z.object({
|
|
179
|
-
limit: z
|
|
421
|
+
limit: z
|
|
422
|
+
.number()
|
|
423
|
+
.int()
|
|
424
|
+
.min(1)
|
|
425
|
+
.max(100)
|
|
426
|
+
.default(10)
|
|
427
|
+
.describe("Max jobs to return"),
|
|
180
428
|
});
|
|
181
429
|
|
|
182
430
|
const listTagsInputSchema = z.object({
|
|
183
|
-
collection: z
|
|
184
|
-
|
|
431
|
+
collection: z
|
|
432
|
+
.string()
|
|
433
|
+
.optional()
|
|
434
|
+
.describe("Filter tags to a single collection"),
|
|
435
|
+
prefix: z
|
|
436
|
+
.string()
|
|
437
|
+
.optional()
|
|
438
|
+
.describe("Filter tags by prefix (e.g. 'project/' for hierarchical tags)"),
|
|
185
439
|
});
|
|
186
440
|
|
|
187
441
|
const linksInputSchema = z.object({
|
|
188
|
-
ref: z
|
|
189
|
-
|
|
442
|
+
ref: z
|
|
443
|
+
.string()
|
|
444
|
+
.trim()
|
|
445
|
+
.min(1, "Reference cannot be empty")
|
|
446
|
+
.describe("Document reference (URI, docid, or collection/path)"),
|
|
447
|
+
type: z
|
|
448
|
+
.enum(["wiki", "markdown"])
|
|
449
|
+
.optional()
|
|
450
|
+
.describe(
|
|
451
|
+
"Filter by link type: 'wiki' ([[links]]) or 'markdown' ([links](url))"
|
|
452
|
+
),
|
|
190
453
|
});
|
|
191
454
|
|
|
192
455
|
const backlinksInputSchema = z.object({
|
|
193
|
-
ref: z
|
|
194
|
-
|
|
456
|
+
ref: z
|
|
457
|
+
.string()
|
|
458
|
+
.trim()
|
|
459
|
+
.min(1, "Reference cannot be empty")
|
|
460
|
+
.describe("Document reference to find backlinks for"),
|
|
461
|
+
collection: z
|
|
462
|
+
.string()
|
|
463
|
+
.trim()
|
|
464
|
+
.optional()
|
|
465
|
+
.describe("Filter backlinks to a single collection"),
|
|
195
466
|
});
|
|
196
467
|
|
|
197
468
|
const similarInputSchema = z.object({
|
|
198
|
-
ref: z
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
469
|
+
ref: z
|
|
470
|
+
.string()
|
|
471
|
+
.trim()
|
|
472
|
+
.min(1, "Reference cannot be empty")
|
|
473
|
+
.describe("Document reference to find similar docs for"),
|
|
474
|
+
limit: z
|
|
475
|
+
.number()
|
|
476
|
+
.int()
|
|
477
|
+
.min(1)
|
|
478
|
+
.max(50)
|
|
479
|
+
.default(5)
|
|
480
|
+
.describe("Max similar documents to return"),
|
|
481
|
+
threshold: z
|
|
482
|
+
.number()
|
|
483
|
+
.min(0)
|
|
484
|
+
.max(1)
|
|
485
|
+
.optional()
|
|
486
|
+
.describe("Minimum similarity score (0-1, default: 0.7)"),
|
|
487
|
+
crossCollection: z
|
|
488
|
+
.boolean()
|
|
489
|
+
.default(false)
|
|
490
|
+
.describe(
|
|
491
|
+
"Search across all collections (not just the document's own collection)"
|
|
492
|
+
),
|
|
202
493
|
});
|
|
203
494
|
|
|
204
495
|
const graphInputSchema = z.object({
|
|
205
|
-
collection: z
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
496
|
+
collection: z
|
|
497
|
+
.string()
|
|
498
|
+
.trim()
|
|
499
|
+
.optional()
|
|
500
|
+
.describe("Filter graph to a single collection"),
|
|
501
|
+
limit: z
|
|
502
|
+
.number()
|
|
503
|
+
.int()
|
|
504
|
+
.min(1)
|
|
505
|
+
.max(5000)
|
|
506
|
+
.default(2000)
|
|
507
|
+
.describe("Max nodes in graph"),
|
|
508
|
+
edgeLimit: z
|
|
509
|
+
.number()
|
|
510
|
+
.int()
|
|
511
|
+
.min(1)
|
|
512
|
+
.max(50000)
|
|
513
|
+
.default(10000)
|
|
514
|
+
.describe("Max edges in graph"),
|
|
515
|
+
includeSimilar: z
|
|
516
|
+
.boolean()
|
|
517
|
+
.default(false)
|
|
518
|
+
.describe("Include vector-similarity edges (not just wiki/markdown links)"),
|
|
519
|
+
threshold: z
|
|
520
|
+
.number()
|
|
521
|
+
.min(0)
|
|
522
|
+
.max(1)
|
|
523
|
+
.default(0.7)
|
|
524
|
+
.describe("Similarity threshold for similar edges (0-1)"),
|
|
525
|
+
linkedOnly: z
|
|
526
|
+
.boolean()
|
|
527
|
+
.default(true)
|
|
528
|
+
.describe("Exclude isolated nodes (no links)"),
|
|
529
|
+
similarTopK: z
|
|
530
|
+
.number()
|
|
531
|
+
.int()
|
|
532
|
+
.min(1)
|
|
533
|
+
.max(20)
|
|
534
|
+
.default(5)
|
|
535
|
+
.describe("Max similar docs per node when includeSimilar=true"),
|
|
212
536
|
});
|
|
213
537
|
|
|
214
538
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -323,77 +647,77 @@ export function registerTools(server: McpServer, ctx: ToolContext): void {
|
|
|
323
647
|
// Tool IDs use underscores (MCP pattern: ^[a-zA-Z0-9_-]{1,64}$)
|
|
324
648
|
server.tool(
|
|
325
649
|
"gno_search",
|
|
326
|
-
"BM25
|
|
650
|
+
"BM25 keyword search. Instant, best for exact terms. Use gno_query for better quality.",
|
|
327
651
|
searchInputSchema.shape,
|
|
328
652
|
(args) => handleSearch(args, ctx)
|
|
329
653
|
);
|
|
330
654
|
|
|
331
655
|
server.tool(
|
|
332
656
|
"gno_vsearch",
|
|
333
|
-
"Vector
|
|
657
|
+
"Vector semantic search. Finds conceptually similar docs even with different wording. Use gno_query for best results.",
|
|
334
658
|
vsearchInputSchema.shape,
|
|
335
659
|
(args) => handleVsearch(args, ctx)
|
|
336
660
|
);
|
|
337
661
|
|
|
338
662
|
server.tool(
|
|
339
663
|
"gno_query",
|
|
340
|
-
"Hybrid search
|
|
664
|
+
"Hybrid search (BM25 + vector + reranking). Best quality, recommended default. Use fast=true for speed, thorough=true for best recall.",
|
|
341
665
|
queryInputSchema.shape,
|
|
342
666
|
(args) => handleQuery(args, ctx)
|
|
343
667
|
);
|
|
344
668
|
|
|
345
669
|
server.tool(
|
|
346
670
|
"gno_get",
|
|
347
|
-
"Retrieve a single document by URI, docid, or collection/path",
|
|
671
|
+
"Retrieve a single document's full content by URI (gno://collection/path), docid (#abc123), or collection/path.",
|
|
348
672
|
getInputSchema.shape,
|
|
349
673
|
(args) => handleGet(args, ctx)
|
|
350
674
|
);
|
|
351
675
|
|
|
352
676
|
server.tool(
|
|
353
677
|
"gno_multi_get",
|
|
354
|
-
"Retrieve multiple documents by refs or glob pattern",
|
|
678
|
+
"Retrieve multiple documents by refs array or glob pattern. Use maxBytes to control truncation.",
|
|
355
679
|
multiGetInputSchema.shape,
|
|
356
680
|
(args) => handleMultiGet(args, ctx)
|
|
357
681
|
);
|
|
358
682
|
|
|
359
683
|
server.tool(
|
|
360
684
|
"gno_status",
|
|
361
|
-
"Get index
|
|
685
|
+
"Get index health: collection count, document count, chunk count, embedding backlog, and per-collection stats.",
|
|
362
686
|
statusInputSchema.shape,
|
|
363
687
|
(args) => handleStatus(args, ctx)
|
|
364
688
|
);
|
|
365
689
|
|
|
366
690
|
server.tool(
|
|
367
691
|
"gno_list_tags",
|
|
368
|
-
"List tags with document counts",
|
|
692
|
+
"List all tags with document counts. Use prefix to filter hierarchical tags (e.g. 'project/').",
|
|
369
693
|
listTagsInputSchema.shape,
|
|
370
694
|
(args) => handleListTags(args, ctx)
|
|
371
695
|
);
|
|
372
696
|
|
|
373
697
|
server.tool(
|
|
374
698
|
"gno_links",
|
|
375
|
-
"Get outgoing links from a document",
|
|
699
|
+
"Get outgoing wiki ([[links]]) and markdown links from a document.",
|
|
376
700
|
linksInputSchema.shape,
|
|
377
701
|
(args) => handleLinks(args, ctx)
|
|
378
702
|
);
|
|
379
703
|
|
|
380
704
|
server.tool(
|
|
381
705
|
"gno_backlinks",
|
|
382
|
-
"
|
|
706
|
+
"Find all documents that link TO a given document (incoming references).",
|
|
383
707
|
backlinksInputSchema.shape,
|
|
384
708
|
(args) => handleBacklinks(args, ctx)
|
|
385
709
|
);
|
|
386
710
|
|
|
387
711
|
server.tool(
|
|
388
712
|
"gno_similar",
|
|
389
|
-
"Find semantically similar documents using vector embeddings",
|
|
713
|
+
"Find semantically similar documents using vector embeddings. Requires embeddings to exist for source document.",
|
|
390
714
|
similarInputSchema.shape,
|
|
391
715
|
(args) => handleSimilar(args, ctx)
|
|
392
716
|
);
|
|
393
717
|
|
|
394
718
|
server.tool(
|
|
395
719
|
"gno_graph",
|
|
396
|
-
"Get knowledge graph of document connections (
|
|
720
|
+
"Get knowledge graph of document connections (wiki links, markdown links, optional similarity edges).",
|
|
397
721
|
graphInputSchema.shape,
|
|
398
722
|
(args) => handleGraph(args, ctx)
|
|
399
723
|
);
|
|
@@ -401,42 +725,42 @@ export function registerTools(server: McpServer, ctx: ToolContext): void {
|
|
|
401
725
|
if (ctx.enableWrite) {
|
|
402
726
|
server.tool(
|
|
403
727
|
"gno_capture",
|
|
404
|
-
"Create a new document",
|
|
728
|
+
"Create a new document in a collection. Writes to disk. Does NOT auto-embed; run gno_index after to make it searchable via vector search.",
|
|
405
729
|
captureInputSchema.shape,
|
|
406
730
|
(args) => handleCapture(args, ctx)
|
|
407
731
|
);
|
|
408
732
|
|
|
409
733
|
server.tool(
|
|
410
734
|
"gno_add_collection",
|
|
411
|
-
"Add a collection and start indexing",
|
|
735
|
+
"Add a directory as a new collection and start indexing. Returns a job ID for tracking.",
|
|
412
736
|
addCollectionInputSchema.shape,
|
|
413
737
|
(args) => handleAddCollection(args, ctx)
|
|
414
738
|
);
|
|
415
739
|
|
|
416
740
|
server.tool(
|
|
417
741
|
"gno_sync",
|
|
418
|
-
"Sync
|
|
742
|
+
"Sync files from disk into the index (FTS only, no embeddings). Does NOT auto-embed; run gno_embed after if vector search needed.",
|
|
419
743
|
syncInputSchema.shape,
|
|
420
744
|
(args) => handleSync(args, ctx)
|
|
421
745
|
);
|
|
422
746
|
|
|
423
747
|
server.tool(
|
|
424
748
|
"gno_embed",
|
|
425
|
-
"Generate embeddings for unembedded chunks",
|
|
749
|
+
"Generate vector embeddings for all unembedded chunks. Async: returns a job ID. Poll with gno_job_status.",
|
|
426
750
|
embedInputSchema.shape,
|
|
427
751
|
(args) => handleEmbed(args, ctx)
|
|
428
752
|
);
|
|
429
753
|
|
|
430
754
|
server.tool(
|
|
431
755
|
"gno_index",
|
|
432
|
-
"Full index: sync files + generate embeddings",
|
|
756
|
+
"Full index: sync files from disk + generate embeddings. Async: returns a job ID. Poll with gno_job_status.",
|
|
433
757
|
indexInputSchema.shape,
|
|
434
758
|
(args) => handleIndex(args, ctx)
|
|
435
759
|
);
|
|
436
760
|
|
|
437
761
|
server.tool(
|
|
438
762
|
"gno_remove_collection",
|
|
439
|
-
"Remove a collection from config",
|
|
763
|
+
"Remove a collection from config and delete its indexed data.",
|
|
440
764
|
removeCollectionInputSchema.shape,
|
|
441
765
|
(args) => handleRemoveCollection(args, ctx)
|
|
442
766
|
);
|
|
@@ -444,14 +768,14 @@ export function registerTools(server: McpServer, ctx: ToolContext): void {
|
|
|
444
768
|
|
|
445
769
|
server.tool(
|
|
446
770
|
"gno_job_status",
|
|
447
|
-
"
|
|
771
|
+
"Check status of an async job (embed, index). Returns progress percentage and completion state.",
|
|
448
772
|
jobStatusInputSchema.shape,
|
|
449
773
|
(args) => handleJobStatus(args, ctx)
|
|
450
774
|
);
|
|
451
775
|
|
|
452
776
|
server.tool(
|
|
453
777
|
"gno_list_jobs",
|
|
454
|
-
"List active and
|
|
778
|
+
"List active and recently completed async jobs with their status and progress.",
|
|
455
779
|
listJobsInputSchema.shape,
|
|
456
780
|
(args) => handleListJobs(args, ctx)
|
|
457
781
|
);
|