@gmickel/gno 1.2.0 → 1.3.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 +1 -1
- package/assets/skill/SKILL.md +3 -0
- package/assets/skill/cli-reference.md +5 -0
- package/assets/skill/examples.md +2 -0
- package/package.json +1 -1
- package/src/app/constants.ts +64 -8
- package/src/cli/commands/embed.ts +6 -2
- package/src/cli/commands/get.ts +15 -5
- package/src/cli/commands/index-cmd.ts +4 -0
- package/src/cli/commands/multi-get.ts +62 -1
- package/src/cli/commands/query.ts +8 -2
- package/src/cli/commands/search.ts +8 -2
- package/src/cli/commands/shared.ts +18 -1
- package/src/cli/commands/status.ts +4 -2
- package/src/cli/commands/update.ts +6 -1
- package/src/cli/commands/vsearch.ts +8 -2
- package/src/cli/format/search-results.ts +1 -1
- package/src/cli/program.ts +22 -1
- package/src/ingestion/chunker.ts +6 -0
- package/src/llm/cache.ts +162 -28
- package/src/llm/errors.ts +32 -0
- package/src/llm/lockfile.ts +49 -4
- package/src/llm/nodeLlamaCpp/embedding.ts +69 -3
- package/src/llm/nodeLlamaCpp/lifecycle.ts +60 -4
- package/src/mcp/resources/index.ts +13 -4
- package/src/mcp/server.ts +2 -0
- package/src/mcp/tools/get.ts +7 -2
- package/src/mcp/tools/multi-get.ts +2 -2
- package/src/mcp/tools/query.ts +2 -1
- package/src/mcp/tools/search.ts +2 -1
- package/src/mcp/tools/vsearch.ts +2 -1
- package/src/pipeline/explain.ts +12 -2
- package/src/pipeline/hybrid.ts +9 -1
- package/src/pipeline/search.ts +16 -7
- package/src/pipeline/types.ts +2 -0
- package/src/pipeline/vsearch.ts +29 -15
- package/src/publish/export-service.ts +27 -2
- package/src/sdk/client.ts +83 -28
- package/src/store/content-batch.ts +38 -0
- package/src/store/sqlite/adapter.ts +38 -2
- package/src/store/types.ts +8 -0
- package/src/store/vector/sqlite-vec.ts +10 -4
- package/src/store/vector/types.ts +2 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { StorePort, StoreResult } from "./types";
|
|
2
|
+
|
|
3
|
+
import { err, ok } from "./types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Load content in batch when the store supports it.
|
|
7
|
+
* Falls back to sequential reads for lightweight test doubles.
|
|
8
|
+
*/
|
|
9
|
+
export async function getContentBatch(
|
|
10
|
+
store: StorePort,
|
|
11
|
+
mirrorHashes: string[]
|
|
12
|
+
): Promise<StoreResult<Map<string, string>>> {
|
|
13
|
+
const uniqueHashes = [...new Set(mirrorHashes)];
|
|
14
|
+
if (uniqueHashes.length === 0) {
|
|
15
|
+
return ok(new Map());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (store.getContentBatch) {
|
|
19
|
+
return store.getContentBatch(uniqueHashes);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const contentByHash = new Map<string, string>();
|
|
23
|
+
for (const mirrorHash of uniqueHashes) {
|
|
24
|
+
const contentResult = await store.getContent(mirrorHash);
|
|
25
|
+
if (!contentResult.ok) {
|
|
26
|
+
return err(
|
|
27
|
+
"QUERY_FAILED",
|
|
28
|
+
contentResult.error.message,
|
|
29
|
+
contentResult.error.cause
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (contentResult.value !== null) {
|
|
33
|
+
contentByHash.set(mirrorHash, contentResult.value);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return ok(contentByHash);
|
|
38
|
+
}
|
|
@@ -42,7 +42,7 @@ import type {
|
|
|
42
42
|
} from "../types";
|
|
43
43
|
import type { SqliteDbProvider } from "./types";
|
|
44
44
|
|
|
45
|
-
import { buildUri, deriveDocid } from "../../app/constants";
|
|
45
|
+
import { buildUri, deriveDocid, stripUriIndex } from "../../app/constants";
|
|
46
46
|
import { normalizeWikiName, stripWikiMdExt } from "../../core/links";
|
|
47
47
|
import { migrations, runMigrations } from "../migrations";
|
|
48
48
|
import { err, ok } from "../types";
|
|
@@ -675,9 +675,10 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
675
675
|
): Promise<StoreResult<DocumentRow | null>> {
|
|
676
676
|
try {
|
|
677
677
|
const db = this.ensureOpen();
|
|
678
|
+
const canonicalUri = stripUriIndex(uri);
|
|
678
679
|
const row = db
|
|
679
680
|
.query<DbDocumentRow, [string]>("SELECT * FROM documents WHERE uri = ?")
|
|
680
|
-
.get(
|
|
681
|
+
.get(canonicalUri);
|
|
681
682
|
|
|
682
683
|
return ok(row ? mapDocumentRow(row) : null);
|
|
683
684
|
} catch (cause) {
|
|
@@ -1048,6 +1049,41 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
1048
1049
|
}
|
|
1049
1050
|
}
|
|
1050
1051
|
|
|
1052
|
+
async getContentBatch(
|
|
1053
|
+
mirrorHashes: string[]
|
|
1054
|
+
): Promise<StoreResult<Map<string, string>>> {
|
|
1055
|
+
try {
|
|
1056
|
+
const db = this.ensureOpen();
|
|
1057
|
+
|
|
1058
|
+
if (mirrorHashes.length === 0) {
|
|
1059
|
+
return ok(new Map());
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
interface DbContentRow {
|
|
1063
|
+
mirror_hash: string;
|
|
1064
|
+
markdown: string;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
const placeholders = mirrorHashes.map(() => "?").join(", ");
|
|
1068
|
+
const rows = db
|
|
1069
|
+
.query<DbContentRow, string[]>(
|
|
1070
|
+
`SELECT mirror_hash, markdown FROM content
|
|
1071
|
+
WHERE mirror_hash IN (${placeholders})`
|
|
1072
|
+
)
|
|
1073
|
+
.all(...mirrorHashes);
|
|
1074
|
+
|
|
1075
|
+
return ok(
|
|
1076
|
+
new Map(rows.map((row) => [row.mirror_hash, row.markdown] as const))
|
|
1077
|
+
);
|
|
1078
|
+
} catch (cause) {
|
|
1079
|
+
return err(
|
|
1080
|
+
"QUERY_FAILED",
|
|
1081
|
+
cause instanceof Error ? cause.message : "Failed to get content batch",
|
|
1082
|
+
cause
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1051
1087
|
// ─────────────────────────────────────────────────────────────────────────
|
|
1052
1088
|
// Chunks
|
|
1053
1089
|
// ─────────────────────────────────────────────────────────────────────────
|
package/src/store/types.ts
CHANGED
|
@@ -694,6 +694,14 @@ export interface StorePort {
|
|
|
694
694
|
*/
|
|
695
695
|
getContent(mirrorHash: string): Promise<StoreResult<string | null>>;
|
|
696
696
|
|
|
697
|
+
/**
|
|
698
|
+
* Batch fetch markdown content for multiple mirror hashes.
|
|
699
|
+
* Returns a map of mirrorHash -> markdown for hashes that exist.
|
|
700
|
+
*/
|
|
701
|
+
getContentBatch?(
|
|
702
|
+
mirrorHashes: string[]
|
|
703
|
+
): Promise<StoreResult<Map<string, string>>>;
|
|
704
|
+
|
|
697
705
|
// ─────────────────────────────────────────────────────────────────────────
|
|
698
706
|
// Chunks
|
|
699
707
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -66,6 +66,14 @@ export interface VectorIndexOptions {
|
|
|
66
66
|
distanceMetric?: "cosine" | "l2";
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
const SQLITE_VEC_GUIDANCE =
|
|
70
|
+
"Run `gno doctor` for sqlite-vec diagnostics. On macOS, verify Homebrew SQLite/sqlite-vec installation and see TROUBLESHOOTING.md.";
|
|
71
|
+
|
|
72
|
+
function formatUnavailableMessage(loadError?: string): string {
|
|
73
|
+
const reason = loadError ? ` Reason: ${loadError}` : "";
|
|
74
|
+
return `Vector search requires sqlite-vec. Embeddings are stored, but KNN search is disabled.${reason} ${SQLITE_VEC_GUIDANCE}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
69
77
|
/**
|
|
70
78
|
* Create a VectorIndexPort for a specific model.
|
|
71
79
|
* sqlite-vec is optional - storage works without it, search disabled.
|
|
@@ -147,6 +155,7 @@ export async function createVectorIndexPort(
|
|
|
147
155
|
model,
|
|
148
156
|
dimensions,
|
|
149
157
|
loadError,
|
|
158
|
+
guidance: searchAvailable ? undefined : SQLITE_VEC_GUIDANCE,
|
|
150
159
|
get vecDirty() {
|
|
151
160
|
return vecDirty;
|
|
152
161
|
},
|
|
@@ -235,10 +244,7 @@ export async function createVectorIndexPort(
|
|
|
235
244
|
): Promise<StoreResult<VectorSearchResult[]>> {
|
|
236
245
|
if (!(searchAvailable && searchStmt)) {
|
|
237
246
|
return Promise.resolve(
|
|
238
|
-
err(
|
|
239
|
-
"VEC_SEARCH_UNAVAILABLE",
|
|
240
|
-
"Vector search requires sqlite-vec. Embeddings stored but KNN search disabled."
|
|
241
|
-
)
|
|
247
|
+
err("VEC_SEARCH_UNAVAILABLE", formatUnavailableMessage(loadError))
|
|
242
248
|
);
|
|
243
249
|
}
|
|
244
250
|
|
|
@@ -60,6 +60,8 @@ export interface VectorIndexPort {
|
|
|
60
60
|
readonly dimensions: number;
|
|
61
61
|
/** Error message if sqlite-vec failed to load (for diagnostics) */
|
|
62
62
|
readonly loadError?: string;
|
|
63
|
+
/** User-facing recovery guidance when search is unavailable */
|
|
64
|
+
readonly guidance?: string;
|
|
63
65
|
/** True if vec0 inserts failed during this session (needs sync) */
|
|
64
66
|
vecDirty: boolean;
|
|
65
67
|
|