@gmickel/gno 0.3.5 → 0.5.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 +74 -7
- package/package.json +30 -1
- package/src/cli/commands/ask.ts +12 -187
- package/src/cli/commands/embed.ts +10 -4
- package/src/cli/commands/models/pull.ts +9 -4
- package/src/cli/commands/serve.ts +19 -0
- package/src/cli/commands/vsearch.ts +5 -2
- package/src/cli/program.ts +28 -0
- package/src/config/types.ts +11 -6
- package/src/llm/registry.ts +3 -1
- package/src/mcp/tools/vsearch.ts +5 -2
- package/src/pipeline/answer.ts +224 -0
- package/src/pipeline/contextual.ts +57 -0
- package/src/pipeline/expansion.ts +49 -31
- package/src/pipeline/explain.ts +11 -3
- package/src/pipeline/fusion.ts +20 -9
- package/src/pipeline/hybrid.ts +57 -40
- package/src/pipeline/index.ts +7 -0
- package/src/pipeline/rerank.ts +55 -27
- package/src/pipeline/types.ts +0 -3
- package/src/pipeline/vsearch.ts +3 -2
- package/src/serve/CLAUDE.md +91 -0
- package/src/serve/bunfig.toml +2 -0
- package/src/serve/context.ts +181 -0
- package/src/serve/index.ts +7 -0
- package/src/serve/public/app.tsx +56 -0
- package/src/serve/public/components/ai-elements/code-block.tsx +176 -0
- package/src/serve/public/components/ai-elements/conversation.tsx +98 -0
- package/src/serve/public/components/ai-elements/inline-citation.tsx +285 -0
- package/src/serve/public/components/ai-elements/loader.tsx +96 -0
- package/src/serve/public/components/ai-elements/message.tsx +443 -0
- package/src/serve/public/components/ai-elements/prompt-input.tsx +1421 -0
- package/src/serve/public/components/ai-elements/sources.tsx +75 -0
- package/src/serve/public/components/ai-elements/suggestion.tsx +51 -0
- package/src/serve/public/components/preset-selector.tsx +403 -0
- package/src/serve/public/components/ui/badge.tsx +46 -0
- package/src/serve/public/components/ui/button-group.tsx +82 -0
- package/src/serve/public/components/ui/button.tsx +62 -0
- package/src/serve/public/components/ui/card.tsx +92 -0
- package/src/serve/public/components/ui/carousel.tsx +244 -0
- package/src/serve/public/components/ui/collapsible.tsx +31 -0
- package/src/serve/public/components/ui/command.tsx +181 -0
- package/src/serve/public/components/ui/dialog.tsx +141 -0
- package/src/serve/public/components/ui/dropdown-menu.tsx +255 -0
- package/src/serve/public/components/ui/hover-card.tsx +42 -0
- package/src/serve/public/components/ui/input-group.tsx +167 -0
- package/src/serve/public/components/ui/input.tsx +21 -0
- package/src/serve/public/components/ui/progress.tsx +28 -0
- package/src/serve/public/components/ui/scroll-area.tsx +56 -0
- package/src/serve/public/components/ui/select.tsx +188 -0
- package/src/serve/public/components/ui/separator.tsx +26 -0
- package/src/serve/public/components/ui/table.tsx +114 -0
- package/src/serve/public/components/ui/textarea.tsx +18 -0
- package/src/serve/public/components/ui/tooltip.tsx +59 -0
- package/src/serve/public/globals.css +226 -0
- package/src/serve/public/hooks/use-api.ts +112 -0
- package/src/serve/public/index.html +13 -0
- package/src/serve/public/pages/Ask.tsx +442 -0
- package/src/serve/public/pages/Browse.tsx +270 -0
- package/src/serve/public/pages/Dashboard.tsx +202 -0
- package/src/serve/public/pages/DocView.tsx +302 -0
- package/src/serve/public/pages/Search.tsx +335 -0
- package/src/serve/routes/api.ts +763 -0
- package/src/serve/server.ts +249 -0
- package/src/store/migrations/002-documents-fts.ts +40 -0
- package/src/store/migrations/index.ts +2 -1
- package/src/store/sqlite/adapter.ts +216 -33
- package/src/store/sqlite/fts5-snowball.ts +144 -0
- package/src/store/types.ts +33 -3
- package/src/store/vector/stats.ts +3 -0
- package/src/store/vector/types.ts +1 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fts5-snowball extension loader.
|
|
3
|
+
*
|
|
4
|
+
* Loads vendored fts5-snowball extension for multilingual FTS5 stemming.
|
|
5
|
+
* Pattern mirrors sqlite-vec loader.
|
|
6
|
+
*
|
|
7
|
+
* @module src/store/sqlite/fts5-snowball
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Database } from 'bun:sqlite';
|
|
11
|
+
// node:fs: existsSync for sync file checks at load time
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
13
|
+
// node:path: join for cross-platform paths
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
// node:process: arch/platform detection (no Bun equivalent)
|
|
16
|
+
import { arch, platform } from 'node:process';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
|
|
19
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
// Types
|
|
21
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Result of attempting to load fts5-snowball.
|
|
25
|
+
*/
|
|
26
|
+
export interface Fts5SnowballLoadResult {
|
|
27
|
+
loaded: boolean;
|
|
28
|
+
error?: string;
|
|
29
|
+
path?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
33
|
+
// Platform Detection
|
|
34
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
function getPlatformDir(): string | null {
|
|
37
|
+
const os = platform === 'win32' ? 'windows' : platform;
|
|
38
|
+
const archName = arch === 'arm64' ? 'arm64' : 'x64';
|
|
39
|
+
|
|
40
|
+
if (os === 'darwin') {
|
|
41
|
+
return `darwin-${archName}`;
|
|
42
|
+
}
|
|
43
|
+
if (os === 'linux' && archName === 'x64') {
|
|
44
|
+
return 'linux-x64';
|
|
45
|
+
}
|
|
46
|
+
if (os === 'windows' && archName === 'x64') {
|
|
47
|
+
return 'windows-x64';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getExtensionSuffix(): string {
|
|
54
|
+
if (platform === 'win32') {
|
|
55
|
+
return 'dll';
|
|
56
|
+
}
|
|
57
|
+
if (platform === 'darwin') {
|
|
58
|
+
return 'dylib';
|
|
59
|
+
}
|
|
60
|
+
return 'so';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
// Path Resolution
|
|
65
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get path to vendored fts5-snowball extension.
|
|
69
|
+
* Returns null if not available for this platform.
|
|
70
|
+
*/
|
|
71
|
+
export function getExtensionPath(): string | null {
|
|
72
|
+
const platformDir = getPlatformDir();
|
|
73
|
+
if (!platformDir) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const suffix = getExtensionSuffix();
|
|
78
|
+
const filename = `fts5stemmer.${suffix}`;
|
|
79
|
+
|
|
80
|
+
// Resolve relative to this module (ESM-safe)
|
|
81
|
+
const thisDir = fileURLToPath(new URL('.', import.meta.url));
|
|
82
|
+
const vendorPath = join(
|
|
83
|
+
thisDir,
|
|
84
|
+
'..',
|
|
85
|
+
'..',
|
|
86
|
+
'..',
|
|
87
|
+
'vendor',
|
|
88
|
+
'fts5-snowball',
|
|
89
|
+
platformDir,
|
|
90
|
+
filename
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (existsSync(vendorPath)) {
|
|
94
|
+
return vendorPath;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
101
|
+
// Extension Loading
|
|
102
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Load fts5-snowball extension into database.
|
|
106
|
+
*
|
|
107
|
+
* Must be called after Database.setCustomSQLite() on macOS.
|
|
108
|
+
* Safe to call multiple times - extension load is idempotent.
|
|
109
|
+
*
|
|
110
|
+
* @param db - Open database connection
|
|
111
|
+
* @returns Load result with success/error info
|
|
112
|
+
*/
|
|
113
|
+
export function loadFts5Snowball(db: Database): Fts5SnowballLoadResult {
|
|
114
|
+
const path = getExtensionPath();
|
|
115
|
+
|
|
116
|
+
if (!path) {
|
|
117
|
+
const platformDir = getPlatformDir();
|
|
118
|
+
return {
|
|
119
|
+
loaded: false,
|
|
120
|
+
error: platformDir
|
|
121
|
+
? `fts5-snowball binary not found for ${platformDir}`
|
|
122
|
+
: `fts5-snowball not available for ${platform}-${arch}`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
db.loadExtension(path);
|
|
128
|
+
return { loaded: true, path };
|
|
129
|
+
} catch (e) {
|
|
130
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
131
|
+
return {
|
|
132
|
+
loaded: false,
|
|
133
|
+
error: message,
|
|
134
|
+
path,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Check if fts5-snowball is available for this platform.
|
|
141
|
+
*/
|
|
142
|
+
export function isAvailable(): boolean {
|
|
143
|
+
return getExtensionPath() !== null;
|
|
144
|
+
}
|
package/src/store/types.ts
CHANGED
|
@@ -18,6 +18,7 @@ export type StoreErrorCode =
|
|
|
18
18
|
| 'CONSTRAINT_VIOLATION'
|
|
19
19
|
| 'MIGRATION_FAILED'
|
|
20
20
|
| 'CONNECTION_FAILED'
|
|
21
|
+
| 'EXTENSION_LOAD_FAILED'
|
|
21
22
|
| 'QUERY_FAILED'
|
|
22
23
|
| 'TRANSACTION_FAILED'
|
|
23
24
|
| 'INVALID_INPUT'
|
|
@@ -195,7 +196,11 @@ export interface FtsSearchOptions {
|
|
|
195
196
|
limit?: number;
|
|
196
197
|
/** Filter by collection */
|
|
197
198
|
collection?: string;
|
|
198
|
-
/**
|
|
199
|
+
/**
|
|
200
|
+
* Language hint (reserved for future use).
|
|
201
|
+
* Note: FTS5 snowball tokenizer is language-aware at index time,
|
|
202
|
+
* so runtime language filtering is not currently implemented.
|
|
203
|
+
*/
|
|
199
204
|
language?: string;
|
|
200
205
|
/** Include snippet with highlights */
|
|
201
206
|
snippet?: boolean;
|
|
@@ -399,6 +404,16 @@ export interface StorePort {
|
|
|
399
404
|
*/
|
|
400
405
|
listDocuments(collection?: string): Promise<StoreResult<DocumentRow[]>>;
|
|
401
406
|
|
|
407
|
+
/**
|
|
408
|
+
* List documents with pagination support.
|
|
409
|
+
* Returns documents and total count for efficient browsing.
|
|
410
|
+
*/
|
|
411
|
+
listDocumentsPaginated(options: {
|
|
412
|
+
collection?: string;
|
|
413
|
+
limit: number;
|
|
414
|
+
offset: number;
|
|
415
|
+
}): Promise<StoreResult<{ documents: DocumentRow[]; total: number }>>;
|
|
416
|
+
|
|
402
417
|
/**
|
|
403
418
|
* Mark documents as inactive (soft delete).
|
|
404
419
|
* Returns count of affected documents.
|
|
@@ -459,7 +474,7 @@ export interface StorePort {
|
|
|
459
474
|
// ─────────────────────────────────────────────────────────────────────────
|
|
460
475
|
|
|
461
476
|
/**
|
|
462
|
-
* Search
|
|
477
|
+
* Search documents using FTS5 (document-level).
|
|
463
478
|
*/
|
|
464
479
|
searchFts(
|
|
465
480
|
query: string,
|
|
@@ -467,8 +482,23 @@ export interface StorePort {
|
|
|
467
482
|
): Promise<StoreResult<FtsResult[]>>;
|
|
468
483
|
|
|
469
484
|
/**
|
|
485
|
+
* Sync a document to documents_fts for full-text search.
|
|
486
|
+
* Must be called after document and content are both upserted.
|
|
487
|
+
*/
|
|
488
|
+
syncDocumentFts(
|
|
489
|
+
collection: string,
|
|
490
|
+
relPath: string
|
|
491
|
+
): Promise<StoreResult<void>>;
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Rebuild entire documents_fts index from scratch.
|
|
495
|
+
* Use after migration or for recovery. Returns count of indexed docs.
|
|
496
|
+
*/
|
|
497
|
+
rebuildAllDocumentsFts(): Promise<StoreResult<number>>;
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* @deprecated Use syncDocumentFts for document-level FTS.
|
|
470
501
|
* Rebuild FTS index for a mirror hash.
|
|
471
|
-
* Called after upserting chunks.
|
|
472
502
|
*/
|
|
473
503
|
rebuildFtsForHash(mirrorHash: string): Promise<StoreResult<void>>;
|
|
474
504
|
|
|
@@ -78,9 +78,11 @@ export function createVectorStatsPort(db: Database): VectorStatsPort {
|
|
|
78
78
|
|
|
79
79
|
// Seek pagination: use cursor to avoid skipping items as backlog shrinks
|
|
80
80
|
// Query structure changes based on whether we have a cursor
|
|
81
|
+
// Include document title for contextual embedding
|
|
81
82
|
const sql = after
|
|
82
83
|
? `
|
|
83
84
|
SELECT c.mirror_hash as mirrorHash, c.seq, c.text,
|
|
85
|
+
(SELECT d.title FROM documents d WHERE d.mirror_hash = c.mirror_hash AND d.active = 1 LIMIT 1) as title,
|
|
84
86
|
CASE
|
|
85
87
|
WHEN NOT EXISTS (
|
|
86
88
|
SELECT 1 FROM content_vectors v
|
|
@@ -108,6 +110,7 @@ export function createVectorStatsPort(db: Database): VectorStatsPort {
|
|
|
108
110
|
`
|
|
109
111
|
: `
|
|
110
112
|
SELECT c.mirror_hash as mirrorHash, c.seq, c.text,
|
|
113
|
+
(SELECT d.title FROM documents d WHERE d.mirror_hash = c.mirror_hash AND d.active = 1 LIMIT 1) as title,
|
|
111
114
|
CASE
|
|
112
115
|
WHEN NOT EXISTS (
|
|
113
116
|
SELECT 1 FROM content_vectors v
|