@gmickel/gno 0.7.0 → 0.8.1

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.
Files changed (209) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -50
  3. package/THIRD_PARTY_NOTICES.md +22 -0
  4. package/assets/screenshots/webui-ask-answer.png +0 -0
  5. package/assets/screenshots/webui-collections.png +0 -0
  6. package/assets/screenshots/webui-editor.png +0 -0
  7. package/assets/screenshots/webui-home.png +0 -0
  8. package/assets/skill/SKILL.md +12 -12
  9. package/assets/skill/cli-reference.md +59 -57
  10. package/assets/skill/examples.md +8 -7
  11. package/assets/skill/mcp-reference.md +8 -4
  12. package/package.json +31 -24
  13. package/src/app/constants.ts +43 -42
  14. package/src/cli/colors.ts +1 -1
  15. package/src/cli/commands/ask.ts +44 -43
  16. package/src/cli/commands/cleanup.ts +9 -8
  17. package/src/cli/commands/collection/add.ts +12 -12
  18. package/src/cli/commands/collection/index.ts +4 -4
  19. package/src/cli/commands/collection/list.ts +26 -25
  20. package/src/cli/commands/collection/remove.ts +10 -10
  21. package/src/cli/commands/collection/rename.ts +10 -10
  22. package/src/cli/commands/context/add.ts +1 -1
  23. package/src/cli/commands/context/check.ts +17 -17
  24. package/src/cli/commands/context/index.ts +4 -4
  25. package/src/cli/commands/context/list.ts +11 -11
  26. package/src/cli/commands/context/rm.ts +1 -1
  27. package/src/cli/commands/doctor.ts +86 -84
  28. package/src/cli/commands/embed.ts +30 -28
  29. package/src/cli/commands/get.ts +27 -26
  30. package/src/cli/commands/index-cmd.ts +9 -9
  31. package/src/cli/commands/index.ts +16 -16
  32. package/src/cli/commands/init.ts +13 -12
  33. package/src/cli/commands/ls.ts +20 -19
  34. package/src/cli/commands/mcp/config.ts +30 -28
  35. package/src/cli/commands/mcp/index.ts +4 -4
  36. package/src/cli/commands/mcp/install.ts +17 -17
  37. package/src/cli/commands/mcp/paths.ts +133 -133
  38. package/src/cli/commands/mcp/status.ts +21 -21
  39. package/src/cli/commands/mcp/uninstall.ts +13 -13
  40. package/src/cli/commands/mcp.ts +2 -2
  41. package/src/cli/commands/models/clear.ts +12 -11
  42. package/src/cli/commands/models/index.ts +5 -5
  43. package/src/cli/commands/models/list.ts +31 -30
  44. package/src/cli/commands/models/path.ts +1 -1
  45. package/src/cli/commands/models/pull.ts +19 -18
  46. package/src/cli/commands/models/use.ts +4 -4
  47. package/src/cli/commands/multi-get.ts +38 -36
  48. package/src/cli/commands/query.ts +21 -20
  49. package/src/cli/commands/ref-parser.ts +10 -10
  50. package/src/cli/commands/reset.ts +40 -39
  51. package/src/cli/commands/search.ts +14 -13
  52. package/src/cli/commands/serve.ts +4 -4
  53. package/src/cli/commands/shared.ts +11 -10
  54. package/src/cli/commands/skill/index.ts +5 -5
  55. package/src/cli/commands/skill/install.ts +18 -17
  56. package/src/cli/commands/skill/paths-cmd.ts +11 -10
  57. package/src/cli/commands/skill/paths.ts +23 -23
  58. package/src/cli/commands/skill/show.ts +13 -12
  59. package/src/cli/commands/skill/uninstall.ts +16 -15
  60. package/src/cli/commands/status.ts +25 -24
  61. package/src/cli/commands/update.ts +3 -3
  62. package/src/cli/commands/vsearch.ts +17 -16
  63. package/src/cli/context.ts +5 -5
  64. package/src/cli/errors.ts +3 -3
  65. package/src/cli/format/search-results.ts +37 -37
  66. package/src/cli/options.ts +43 -43
  67. package/src/cli/program.ts +455 -459
  68. package/src/cli/progress.ts +1 -1
  69. package/src/cli/run.ts +24 -23
  70. package/src/collection/add.ts +9 -8
  71. package/src/collection/index.ts +3 -3
  72. package/src/collection/remove.ts +7 -6
  73. package/src/collection/types.ts +6 -6
  74. package/src/config/defaults.ts +1 -1
  75. package/src/config/index.ts +5 -5
  76. package/src/config/loader.ts +19 -18
  77. package/src/config/paths.ts +9 -8
  78. package/src/config/saver.ts +14 -13
  79. package/src/config/types.ts +53 -52
  80. package/src/converters/adapters/markitdownTs/adapter.ts +21 -19
  81. package/src/converters/adapters/officeparser/adapter.ts +18 -16
  82. package/src/converters/canonicalize.ts +12 -12
  83. package/src/converters/errors.ts +26 -22
  84. package/src/converters/index.ts +8 -8
  85. package/src/converters/mime.ts +25 -25
  86. package/src/converters/native/markdown.ts +10 -9
  87. package/src/converters/native/plaintext.ts +8 -7
  88. package/src/converters/path.ts +2 -2
  89. package/src/converters/pipeline.ts +11 -10
  90. package/src/converters/registry.ts +8 -8
  91. package/src/converters/types.ts +14 -14
  92. package/src/converters/versions.ts +4 -4
  93. package/src/index.ts +4 -4
  94. package/src/ingestion/chunker.ts +10 -9
  95. package/src/ingestion/index.ts +6 -6
  96. package/src/ingestion/language.ts +62 -62
  97. package/src/ingestion/sync.ts +50 -49
  98. package/src/ingestion/types.ts +10 -10
  99. package/src/ingestion/walker.ts +14 -13
  100. package/src/llm/cache.ts +51 -49
  101. package/src/llm/errors.ts +40 -36
  102. package/src/llm/index.ts +9 -9
  103. package/src/llm/lockfile.ts +6 -6
  104. package/src/llm/nodeLlamaCpp/adapter.ts +13 -12
  105. package/src/llm/nodeLlamaCpp/embedding.ts +9 -8
  106. package/src/llm/nodeLlamaCpp/generation.ts +7 -6
  107. package/src/llm/nodeLlamaCpp/lifecycle.ts +11 -10
  108. package/src/llm/nodeLlamaCpp/rerank.ts +6 -5
  109. package/src/llm/policy.ts +5 -5
  110. package/src/llm/registry.ts +6 -5
  111. package/src/llm/types.ts +2 -2
  112. package/src/mcp/resources/index.ts +15 -13
  113. package/src/mcp/server.ts +25 -23
  114. package/src/mcp/tools/get.ts +25 -23
  115. package/src/mcp/tools/index.ts +32 -29
  116. package/src/mcp/tools/multi-get.ts +34 -32
  117. package/src/mcp/tools/query.ts +29 -27
  118. package/src/mcp/tools/search.ts +14 -12
  119. package/src/mcp/tools/status.ts +12 -11
  120. package/src/mcp/tools/vsearch.ts +26 -24
  121. package/src/pipeline/answer.ts +9 -9
  122. package/src/pipeline/chunk-lookup.ts +1 -1
  123. package/src/pipeline/contextual.ts +4 -4
  124. package/src/pipeline/expansion.ts +23 -21
  125. package/src/pipeline/explain.ts +21 -21
  126. package/src/pipeline/fusion.ts +9 -9
  127. package/src/pipeline/hybrid.ts +41 -42
  128. package/src/pipeline/index.ts +10 -10
  129. package/src/pipeline/query-language.ts +39 -39
  130. package/src/pipeline/rerank.ts +8 -7
  131. package/src/pipeline/search.ts +22 -22
  132. package/src/pipeline/types.ts +8 -8
  133. package/src/pipeline/vsearch.ts +21 -24
  134. package/src/serve/CLAUDE.md +21 -15
  135. package/src/serve/config-sync.ts +9 -8
  136. package/src/serve/context.ts +19 -18
  137. package/src/serve/index.ts +1 -1
  138. package/src/serve/jobs.ts +7 -7
  139. package/src/serve/public/app.tsx +79 -25
  140. package/src/serve/public/components/AddCollectionDialog.tsx +382 -0
  141. package/src/serve/public/components/CaptureButton.tsx +60 -0
  142. package/src/serve/public/components/CaptureModal.tsx +365 -0
  143. package/src/serve/public/components/IndexingProgress.tsx +333 -0
  144. package/src/serve/public/components/ShortcutHelpModal.tsx +106 -0
  145. package/src/serve/public/components/ai-elements/code-block.tsx +42 -32
  146. package/src/serve/public/components/ai-elements/conversation.tsx +16 -14
  147. package/src/serve/public/components/ai-elements/inline-citation.tsx +33 -32
  148. package/src/serve/public/components/ai-elements/loader.tsx +5 -4
  149. package/src/serve/public/components/ai-elements/message.tsx +39 -37
  150. package/src/serve/public/components/ai-elements/prompt-input.tsx +97 -95
  151. package/src/serve/public/components/ai-elements/sources.tsx +12 -10
  152. package/src/serve/public/components/ai-elements/suggestion.tsx +10 -9
  153. package/src/serve/public/components/editor/CodeMirrorEditor.tsx +142 -0
  154. package/src/serve/public/components/editor/MarkdownPreview.tsx +311 -0
  155. package/src/serve/public/components/editor/index.ts +6 -0
  156. package/src/serve/public/components/preset-selector.tsx +29 -28
  157. package/src/serve/public/components/ui/badge.tsx +13 -12
  158. package/src/serve/public/components/ui/button-group.tsx +13 -12
  159. package/src/serve/public/components/ui/button.tsx +23 -22
  160. package/src/serve/public/components/ui/card.tsx +16 -16
  161. package/src/serve/public/components/ui/carousel.tsx +36 -35
  162. package/src/serve/public/components/ui/collapsible.tsx +1 -1
  163. package/src/serve/public/components/ui/command.tsx +17 -15
  164. package/src/serve/public/components/ui/dialog.tsx +13 -12
  165. package/src/serve/public/components/ui/dropdown-menu.tsx +13 -12
  166. package/src/serve/public/components/ui/hover-card.tsx +6 -5
  167. package/src/serve/public/components/ui/input-group.tsx +45 -43
  168. package/src/serve/public/components/ui/input.tsx +6 -6
  169. package/src/serve/public/components/ui/progress.tsx +5 -4
  170. package/src/serve/public/components/ui/scroll-area.tsx +11 -10
  171. package/src/serve/public/components/ui/select.tsx +19 -18
  172. package/src/serve/public/components/ui/separator.tsx +6 -5
  173. package/src/serve/public/components/ui/table.tsx +18 -18
  174. package/src/serve/public/components/ui/textarea.tsx +4 -4
  175. package/src/serve/public/components/ui/tooltip.tsx +5 -4
  176. package/src/serve/public/globals.css +27 -4
  177. package/src/serve/public/hooks/use-api.ts +8 -8
  178. package/src/serve/public/hooks/useCaptureModal.tsx +83 -0
  179. package/src/serve/public/hooks/useKeyboardShortcuts.ts +85 -0
  180. package/src/serve/public/index.html +4 -4
  181. package/src/serve/public/lib/utils.ts +6 -0
  182. package/src/serve/public/pages/Ask.tsx +27 -26
  183. package/src/serve/public/pages/Browse.tsx +28 -27
  184. package/src/serve/public/pages/Collections.tsx +439 -0
  185. package/src/serve/public/pages/Dashboard.tsx +166 -40
  186. package/src/serve/public/pages/DocView.tsx +258 -73
  187. package/src/serve/public/pages/DocumentEditor.tsx +510 -0
  188. package/src/serve/public/pages/Search.tsx +80 -58
  189. package/src/serve/routes/api.ts +272 -155
  190. package/src/serve/security.ts +4 -4
  191. package/src/serve/server.ts +66 -48
  192. package/src/store/index.ts +5 -5
  193. package/src/store/migrations/001-initial.ts +24 -23
  194. package/src/store/migrations/002-documents-fts.ts +7 -6
  195. package/src/store/migrations/index.ts +4 -4
  196. package/src/store/migrations/runner.ts +17 -15
  197. package/src/store/sqlite/adapter.ts +123 -121
  198. package/src/store/sqlite/fts5-snowball.ts +24 -23
  199. package/src/store/sqlite/index.ts +1 -1
  200. package/src/store/sqlite/setup.ts +12 -12
  201. package/src/store/sqlite/types.ts +4 -4
  202. package/src/store/types.ts +19 -19
  203. package/src/store/vector/index.ts +3 -3
  204. package/src/store/vector/sqlite-vec.ts +23 -20
  205. package/src/store/vector/stats.ts +10 -8
  206. package/src/store/vector/types.ts +2 -2
  207. package/vendor/fts5-snowball/README.md +6 -6
  208. package/assets/screenshots/webui-ask-answer.jpg +0 -0
  209. package/assets/screenshots/webui-home.jpg +0 -0
package/src/llm/cache.ts CHANGED
@@ -6,13 +6,23 @@
6
6
  */
7
7
 
8
8
  // node:crypto: createHash for safe lock filenames
9
- import { createHash } from 'node:crypto';
10
- import { mkdir, open, readFile, rename, rm, stat } from 'node:fs/promises';
9
+ import { createHash } from "node:crypto";
10
+ import { mkdir, open, readFile, rename, rm, stat } from "node:fs/promises";
11
11
  // node:path: join for path construction, isAbsolute for cross-platform path detection
12
- import { isAbsolute, join } from 'node:path';
12
+ import { isAbsolute, join } from "node:path";
13
13
  // node:url: fileURLToPath for proper file:// URL handling
14
- import { fileURLToPath } from 'node:url';
15
- import { getModelsCachePath } from '../app/constants';
14
+ import { fileURLToPath } from "node:url";
15
+
16
+ import type { DownloadPolicy } from "./policy";
17
+ import type {
18
+ DownloadProgress,
19
+ LlmResult,
20
+ ModelCacheEntry,
21
+ ModelType,
22
+ ProgressCallback,
23
+ } from "./types";
24
+
25
+ import { getModelsCachePath } from "../app/constants";
16
26
  import {
17
27
  autoDownloadDisabledError,
18
28
  downloadFailedError,
@@ -20,16 +30,8 @@ import {
20
30
  lockFailedError,
21
31
  modelNotCachedError,
22
32
  modelNotFoundError,
23
- } from './errors';
24
- import { getLockPath, getManifestLockPath, withLock } from './lockfile';
25
- import type { DownloadPolicy } from './policy';
26
- import type {
27
- DownloadProgress,
28
- LlmResult,
29
- ModelCacheEntry,
30
- ModelType,
31
- ProgressCallback,
32
- } from './types';
33
+ } from "./errors";
34
+ import { getLockPath, getManifestLockPath, withLock } from "./lockfile";
33
35
 
34
36
  // ─────────────────────────────────────────────────────────────────────────────
35
37
  // URI Parsing
@@ -41,14 +43,14 @@ const HF_PATH_PATTERN = /^([^/]+)\/([^/]+)\/(.+\.gguf)$/;
41
43
 
42
44
  export type ParsedModelUri =
43
45
  | {
44
- scheme: 'hf';
46
+ scheme: "hf";
45
47
  org: string;
46
48
  repo: string;
47
49
  file: string;
48
50
  quantization?: string;
49
51
  }
50
52
  | {
51
- scheme: 'file';
53
+ scheme: "file";
52
54
  file: string;
53
55
  };
54
56
 
@@ -69,7 +71,7 @@ export function parseModelUri(
69
71
  uri: string
70
72
  ): { ok: true; value: ParsedModelUri } | { ok: false; error: string } {
71
73
  // Handle hf: scheme
72
- if (uri.startsWith('hf:')) {
74
+ if (uri.startsWith("hf:")) {
73
75
  const rest = uri.slice(3);
74
76
 
75
77
  // Check for quantization shorthand: hf:org/repo:Q4_K_M
@@ -81,10 +83,10 @@ export function parseModelUri(
81
83
  return {
82
84
  ok: true,
83
85
  value: {
84
- scheme: 'hf',
86
+ scheme: "hf",
85
87
  org,
86
88
  repo,
87
- file: '', // Will be resolved by node-llama-cpp
89
+ file: "", // Will be resolved by node-llama-cpp
88
90
  quantization: quant,
89
91
  },
90
92
  };
@@ -100,7 +102,7 @@ export function parseModelUri(
100
102
  return {
101
103
  ok: true,
102
104
  value: {
103
- scheme: 'hf',
105
+ scheme: "hf",
104
106
  org,
105
107
  repo,
106
108
  file,
@@ -113,12 +115,12 @@ export function parseModelUri(
113
115
  }
114
116
 
115
117
  // Handle file:// URLs (proper file URLs like file:///C:/path or file:///path)
116
- if (uri.startsWith('file://')) {
118
+ if (uri.startsWith("file://")) {
117
119
  try {
118
120
  const filePath = fileURLToPath(new URL(uri));
119
121
  return {
120
122
  ok: true,
121
- value: { scheme: 'file', file: filePath },
123
+ value: { scheme: "file", file: filePath },
122
124
  };
123
125
  } catch {
124
126
  return { ok: false, error: `Invalid file URL: ${uri}` };
@@ -126,14 +128,14 @@ export function parseModelUri(
126
128
  }
127
129
 
128
130
  // Handle simplified file: scheme (file:/path or file:C:\path)
129
- if (uri.startsWith('file:')) {
131
+ if (uri.startsWith("file:")) {
130
132
  const path = uri.slice(5);
131
133
  if (!path) {
132
- return { ok: false, error: 'Empty file path' };
134
+ return { ok: false, error: "Empty file path" };
133
135
  }
134
136
  return {
135
137
  ok: true,
136
- value: { scheme: 'file', file: path },
138
+ value: { scheme: "file", file: path },
137
139
  };
138
140
  }
139
141
 
@@ -141,7 +143,7 @@ export function parseModelUri(
141
143
  if (isAbsolute(uri)) {
142
144
  return {
143
145
  ok: true,
144
- value: { scheme: 'file', file: uri },
146
+ value: { scheme: "file", file: uri },
145
147
  };
146
148
  }
147
149
 
@@ -152,7 +154,7 @@ export function parseModelUri(
152
154
  * Convert parsed URI back to node-llama-cpp format.
153
155
  */
154
156
  export function toNodeLlamaCppUri(parsed: ParsedModelUri): string {
155
- if (parsed.scheme === 'file') {
157
+ if (parsed.scheme === "file") {
156
158
  return parsed.file;
157
159
  }
158
160
 
@@ -168,11 +170,11 @@ export function toNodeLlamaCppUri(parsed: ParsedModelUri): string {
168
170
  // ─────────────────────────────────────────────────────────────────────────────
169
171
 
170
172
  interface Manifest {
171
- version: '1.0';
173
+ version: "1.0";
172
174
  models: ModelCacheEntry[];
173
175
  }
174
176
 
175
- const MANIFEST_VERSION = '1.0' as const;
177
+ const MANIFEST_VERSION = "1.0" as const;
176
178
 
177
179
  // ─────────────────────────────────────────────────────────────────────────────
178
180
  // ModelCache
@@ -185,7 +187,7 @@ export class ModelCache {
185
187
 
186
188
  constructor(cacheDir?: string) {
187
189
  this.dir = cacheDir ?? getModelsCachePath();
188
- this.manifestPath = join(this.dir, 'manifest.json');
190
+ this.manifestPath = join(this.dir, "manifest.json");
189
191
  }
190
192
 
191
193
  /**
@@ -199,7 +201,7 @@ export class ModelCache {
199
201
  }
200
202
 
201
203
  // Local files: verify existence
202
- if (parsed.value.scheme === 'file') {
204
+ if (parsed.value.scheme === "file") {
203
205
  const exists = await this.fileExists(parsed.value.file);
204
206
  if (!exists) {
205
207
  return {
@@ -238,7 +240,7 @@ export class ModelCache {
238
240
  }
239
241
 
240
242
  // Local files: just verify
241
- if (parsed.value.scheme === 'file') {
243
+ if (parsed.value.scheme === "file") {
242
244
  const exists = await this.fileExists(parsed.value.file);
243
245
  if (!exists) {
244
246
  return {
@@ -266,7 +268,7 @@ export class ModelCache {
266
268
  }
267
269
 
268
270
  try {
269
- const { resolveModelFile } = await import('node-llama-cpp');
271
+ const { resolveModelFile } = await import("node-llama-cpp");
270
272
 
271
273
  // Convert to node-llama-cpp format (handles quantization shorthand)
272
274
  // node-llama-cpp needs hf: prefix to identify HuggingFace models
@@ -279,11 +281,11 @@ export class ModelCache {
279
281
  // Type-safe check for download progress status
280
282
  if (
281
283
  status &&
282
- typeof status === 'object' &&
283
- 'type' in status &&
284
- status.type === 'download' &&
285
- 'downloadedSize' in status &&
286
- 'totalSize' in status
284
+ typeof status === "object" &&
285
+ "type" in status &&
286
+ status.type === "download" &&
287
+ "downloadedSize" in status &&
288
+ "totalSize" in status
287
289
  ) {
288
290
  const s = status as {
289
291
  downloadedSize: number;
@@ -340,7 +342,7 @@ export class ModelCache {
340
342
  }
341
343
 
342
344
  // Local files: just verify existence (no download needed)
343
- if (parsed.value.scheme === 'file') {
345
+ if (parsed.value.scheme === "file") {
344
346
  const exists = await this.fileExists(parsed.value.file);
345
347
  if (!exists) {
346
348
  return {
@@ -366,9 +368,9 @@ export class ModelCache {
366
368
  // Acquire lock for download (prevents concurrent downloads of same model)
367
369
  // Use hash for lock filename to avoid collisions and path issues
368
370
  await mkdir(this.dir, { recursive: true });
369
- const lockName = createHash('sha256')
371
+ const lockName = createHash("sha256")
370
372
  .update(uri)
371
- .digest('hex')
373
+ .digest("hex")
372
374
  .slice(0, 32);
373
375
  const lockPath = getLockPath(join(this.dir, lockName));
374
376
 
@@ -409,7 +411,7 @@ export class ModelCache {
409
411
  async getCachedPath(uri: string): Promise<string | null> {
410
412
  // Handle file: URIs directly (check filesystem, not manifest)
411
413
  const parsed = parseModelUri(uri);
412
- if (parsed.ok && parsed.value.scheme === 'file') {
414
+ if (parsed.ok && parsed.value.scheme === "file") {
413
415
  const exists = await this.fileExists(parsed.value.file);
414
416
  return exists ? parsed.value.file : null;
415
417
  }
@@ -505,7 +507,7 @@ export class ModelCache {
505
507
  */
506
508
  private async readManifestFromDisk(): Promise<Manifest> {
507
509
  try {
508
- const content = await readFile(this.manifestPath, 'utf-8');
510
+ const content = await readFile(this.manifestPath, "utf-8");
509
511
  return JSON.parse(content) as Manifest;
510
512
  } catch {
511
513
  // No manifest or invalid - create empty
@@ -539,7 +541,7 @@ export class ModelCache {
539
541
  });
540
542
 
541
543
  if (result === null) {
542
- throw new Error('Failed to acquire manifest lock');
544
+ throw new Error("Failed to acquire manifest lock");
543
545
  }
544
546
  }
545
547
 
@@ -553,7 +555,7 @@ export class ModelCache {
553
555
  const content = JSON.stringify(manifest, null, 2);
554
556
 
555
557
  // Write to temp file with fsync
556
- const fh = await open(tmpPath, 'w');
558
+ const fh = await open(tmpPath, "w");
557
559
  try {
558
560
  await fh.writeFile(content);
559
561
  await fh.sync();
@@ -565,9 +567,9 @@ export class ModelCache {
565
567
  await rename(tmpPath, this.manifestPath);
566
568
 
567
569
  // Fsync parent directory for rename durability (best-effort, not supported on Windows)
568
- if (process.platform !== 'win32') {
570
+ if (process.platform !== "win32") {
569
571
  try {
570
- const dirFh = await open(this.dir, 'r');
572
+ const dirFh = await open(this.dir, "r");
571
573
  try {
572
574
  await dirFh.sync();
573
575
  } finally {
@@ -603,7 +605,7 @@ export class ModelCache {
603
605
  type,
604
606
  path: modelPath,
605
607
  size,
606
- checksum: '', // TODO: compute SHA-256 for large files
608
+ checksum: "", // TODO: compute SHA-256 for large files
607
609
  cachedAt: new Date().toISOString(),
608
610
  });
609
611
  });
package/src/llm/errors.ts CHANGED
@@ -10,17 +10,17 @@
10
10
  // ─────────────────────────────────────────────────────────────────────────────
11
11
 
12
12
  export type LlmErrorCode =
13
- | 'MODEL_NOT_FOUND'
14
- | 'MODEL_NOT_CACHED'
15
- | 'MODEL_DOWNLOAD_FAILED'
16
- | 'MODEL_LOAD_FAILED'
17
- | 'MODEL_CORRUPTED'
18
- | 'INFERENCE_FAILED'
19
- | 'TIMEOUT'
20
- | 'OUT_OF_MEMORY'
21
- | 'INVALID_URI'
22
- | 'LOCK_FAILED'
23
- | 'AUTO_DOWNLOAD_DISABLED';
13
+ | "MODEL_NOT_FOUND"
14
+ | "MODEL_NOT_CACHED"
15
+ | "MODEL_DOWNLOAD_FAILED"
16
+ | "MODEL_LOAD_FAILED"
17
+ | "MODEL_CORRUPTED"
18
+ | "INFERENCE_FAILED"
19
+ | "TIMEOUT"
20
+ | "OUT_OF_MEMORY"
21
+ | "INVALID_URI"
22
+ | "LOCK_FAILED"
23
+ | "AUTO_DOWNLOAD_DISABLED";
24
24
 
25
25
  export interface LlmError {
26
26
  code: LlmErrorCode;
@@ -59,19 +59,23 @@ function normalizeCause(
59
59
  return { name: cause.name, message };
60
60
  }
61
61
 
62
- if (typeof cause === 'string') {
62
+ if (typeof cause === "string") {
63
63
  return cause.length > MAX_CAUSE_LENGTH
64
64
  ? `${cause.slice(0, MAX_CAUSE_LENGTH)}...`
65
65
  : cause;
66
66
  }
67
67
 
68
68
  try {
69
- const str = String(cause);
69
+ // Handle objects with custom toString, otherwise use JSON
70
+ const str =
71
+ typeof cause === "object" && cause !== null
72
+ ? JSON.stringify(cause)
73
+ : String(cause as string | number | boolean);
70
74
  return str.length > MAX_CAUSE_LENGTH
71
75
  ? `${str.slice(0, MAX_CAUSE_LENGTH)}...`
72
76
  : str;
73
77
  } catch {
74
- return '[unserializable cause]';
78
+ return "[unserializable cause]";
75
79
  }
76
80
  }
77
81
 
@@ -80,7 +84,7 @@ function normalizeCause(
80
84
  */
81
85
  export function llmError(
82
86
  code: LlmErrorCode,
83
- opts: Omit<LlmError, 'code'>
87
+ opts: Omit<LlmError, "code">
84
88
  ): LlmError {
85
89
  return {
86
90
  code,
@@ -94,10 +98,10 @@ export function llmError(
94
98
  */
95
99
  export function isRetryable(code: LlmErrorCode): boolean {
96
100
  return [
97
- 'MODEL_DOWNLOAD_FAILED',
98
- 'TIMEOUT',
99
- 'INFERENCE_FAILED',
100
- 'LOCK_FAILED',
101
+ "MODEL_DOWNLOAD_FAILED",
102
+ "TIMEOUT",
103
+ "INFERENCE_FAILED",
104
+ "LOCK_FAILED",
101
105
  ].includes(code);
102
106
  }
103
107
 
@@ -106,7 +110,7 @@ export function isRetryable(code: LlmErrorCode): boolean {
106
110
  // ─────────────────────────────────────────────────────────────────────────────
107
111
 
108
112
  export function modelNotFoundError(uri: string, details?: string): LlmError {
109
- return llmError('MODEL_NOT_FOUND', {
113
+ return llmError("MODEL_NOT_FOUND", {
110
114
  message: details
111
115
  ? `Model not found: ${details}`
112
116
  : `Model not found: ${uri}`,
@@ -117,9 +121,9 @@ export function modelNotFoundError(uri: string, details?: string): LlmError {
117
121
 
118
122
  export function modelNotCachedError(
119
123
  uri: string,
120
- modelType: 'embed' | 'rerank' | 'gen'
124
+ modelType: "embed" | "rerank" | "gen"
121
125
  ): LlmError {
122
- return llmError('MODEL_NOT_CACHED', {
126
+ return llmError("MODEL_NOT_CACHED", {
123
127
  message: `${modelType} model not cached`,
124
128
  modelUri: uri,
125
129
  retryable: false,
@@ -128,7 +132,7 @@ export function modelNotCachedError(
128
132
  }
129
133
 
130
134
  export function downloadFailedError(uri: string, cause?: unknown): LlmError {
131
- return llmError('MODEL_DOWNLOAD_FAILED', {
135
+ return llmError("MODEL_DOWNLOAD_FAILED", {
132
136
  message: `Failed to download model: ${uri}`,
133
137
  modelUri: uri,
134
138
  retryable: true,
@@ -137,27 +141,27 @@ export function downloadFailedError(uri: string, cause?: unknown): LlmError {
137
141
  }
138
142
 
139
143
  export function loadFailedError(uri: string, cause?: unknown): LlmError {
140
- return llmError('MODEL_LOAD_FAILED', {
144
+ return llmError("MODEL_LOAD_FAILED", {
141
145
  message: `Failed to load model: ${uri}`,
142
146
  modelUri: uri,
143
147
  retryable: false,
144
148
  cause,
145
- suggestion: 'Run: gno doctor',
149
+ suggestion: "Run: gno doctor",
146
150
  });
147
151
  }
148
152
 
149
153
  export function corruptedError(uri: string, cause?: unknown): LlmError {
150
- return llmError('MODEL_CORRUPTED', {
154
+ return llmError("MODEL_CORRUPTED", {
151
155
  message: `Model file corrupted: ${uri}`,
152
156
  modelUri: uri,
153
157
  retryable: false,
154
158
  cause,
155
- suggestion: 'Run: gno models clear && gno models pull',
159
+ suggestion: "Run: gno models clear && gno models pull",
156
160
  });
157
161
  }
158
162
 
159
163
  export function inferenceFailedError(uri: string, cause?: unknown): LlmError {
160
- return llmError('INFERENCE_FAILED', {
164
+ return llmError("INFERENCE_FAILED", {
161
165
  message: `Inference failed for model: ${uri}`,
162
166
  modelUri: uri,
163
167
  retryable: true,
@@ -167,10 +171,10 @@ export function inferenceFailedError(uri: string, cause?: unknown): LlmError {
167
171
 
168
172
  export function timeoutError(
169
173
  uri: string,
170
- operation: 'load' | 'inference',
174
+ operation: "load" | "inference",
171
175
  timeoutMs: number
172
176
  ): LlmError {
173
- return llmError('TIMEOUT', {
177
+ return llmError("TIMEOUT", {
174
178
  message: `${operation} timed out after ${timeoutMs}ms`,
175
179
  modelUri: uri,
176
180
  retryable: true,
@@ -178,17 +182,17 @@ export function timeoutError(
178
182
  }
179
183
 
180
184
  export function outOfMemoryError(uri: string, cause?: unknown): LlmError {
181
- return llmError('OUT_OF_MEMORY', {
185
+ return llmError("OUT_OF_MEMORY", {
182
186
  message: `Out of memory loading model: ${uri}`,
183
187
  modelUri: uri,
184
188
  retryable: false,
185
189
  cause,
186
- suggestion: 'Try a smaller quantization (Q4_K_M) or close other apps',
190
+ suggestion: "Try a smaller quantization (Q4_K_M) or close other apps",
187
191
  });
188
192
  }
189
193
 
190
194
  export function invalidUriError(uri: string, details: string): LlmError {
191
- return llmError('INVALID_URI', {
195
+ return llmError("INVALID_URI", {
192
196
  message: `Invalid model URI: ${details}`,
193
197
  modelUri: uri,
194
198
  retryable: false,
@@ -196,16 +200,16 @@ export function invalidUriError(uri: string, details: string): LlmError {
196
200
  }
197
201
 
198
202
  export function lockFailedError(uri: string): LlmError {
199
- return llmError('LOCK_FAILED', {
203
+ return llmError("LOCK_FAILED", {
200
204
  message: `Failed to acquire lock for model download: ${uri}`,
201
205
  modelUri: uri,
202
206
  retryable: true,
203
- suggestion: 'Another process may be downloading. Wait and retry.',
207
+ suggestion: "Another process may be downloading. Wait and retry.",
204
208
  });
205
209
  }
206
210
 
207
211
  export function autoDownloadDisabledError(uri: string): LlmError {
208
- return llmError('AUTO_DOWNLOAD_DISABLED', {
212
+ return llmError("AUTO_DOWNLOAD_DISABLED", {
209
213
  message: `Model not cached and auto-download disabled: ${uri}`,
210
214
  modelUri: uri,
211
215
  retryable: false,
package/src/llm/index.ts CHANGED
@@ -5,12 +5,12 @@
5
5
  */
6
6
 
7
7
  // Re-export config types (source of truth in config/types.ts)
8
- export type { ModelConfig, ModelPreset } from '../config/types';
9
- export type { ParsedModelUri } from './cache';
8
+ export type { ModelConfig, ModelPreset } from "../config/types";
9
+ export type { ParsedModelUri } from "./cache";
10
10
  // Cache
11
- export { ModelCache, parseModelUri, toNodeLlamaCppUri } from './cache';
11
+ export { ModelCache, parseModelUri, toNodeLlamaCppUri } from "./cache";
12
12
  // Errors
13
- export type { LlmError, LlmErrorCode } from './errors';
13
+ export type { LlmError, LlmErrorCode } from "./errors";
14
14
  export {
15
15
  corruptedError,
16
16
  downloadFailedError,
@@ -23,15 +23,15 @@ export {
23
23
  modelNotFoundError,
24
24
  outOfMemoryError,
25
25
  timeoutError,
26
- } from './errors';
26
+ } from "./errors";
27
27
  // Adapter
28
- export { createLlmAdapter, LlmAdapter } from './nodeLlamaCpp/adapter';
28
+ export { createLlmAdapter, LlmAdapter } from "./nodeLlamaCpp/adapter";
29
29
  // Lifecycle
30
30
  export {
31
31
  getModelManager,
32
32
  ModelManager,
33
33
  resetModelManager,
34
- } from './nodeLlamaCpp/lifecycle';
34
+ } from "./nodeLlamaCpp/lifecycle";
35
35
  // Registry
36
36
  export {
37
37
  getActivePreset,
@@ -39,7 +39,7 @@ export {
39
39
  getPreset,
40
40
  listPresets,
41
41
  resolveModelUri,
42
- } from './registry';
42
+ } from "./registry";
43
43
  // Types
44
44
  export type {
45
45
  DownloadProgress,
@@ -55,4 +55,4 @@ export type {
55
55
  ProgressCallback,
56
56
  RerankPort,
57
57
  RerankScore,
58
- } from './types';
58
+ } from "./types";
@@ -5,11 +5,11 @@
5
5
  * @module src/llm/lockfile
6
6
  */
7
7
 
8
- import { open, rename, rm, stat } from 'node:fs/promises';
8
+ import { open, rename, rm, stat } from "node:fs/promises";
9
9
  // node:os: hostname and user for lock ownership
10
- import { hostname, userInfo } from 'node:os';
10
+ import { hostname, userInfo } from "node:os";
11
11
  // node:path: join for manifest lock path
12
- import { join } from 'node:path';
12
+ import { join } from "node:path";
13
13
 
14
14
  // ─────────────────────────────────────────────────────────────────────────────
15
15
  // Constants
@@ -101,7 +101,7 @@ async function createLockExclusive(
101
101
  const content = JSON.stringify(meta, null, 2);
102
102
 
103
103
  // Create lock file with O_EXCL - fails if exists
104
- const fh = await open(lockPath, 'wx');
104
+ const fh = await open(lockPath, "wx");
105
105
  try {
106
106
  await fh.writeFile(content);
107
107
  await fh.sync();
@@ -147,7 +147,7 @@ export async function acquireLock(
147
147
  };
148
148
  } catch (e) {
149
149
  // EEXIST means lock exists
150
- if (e && typeof e === 'object' && 'code' in e && e.code === 'EEXIST') {
150
+ if (e && typeof e === "object" && "code" in e && e.code === "EEXIST") {
151
151
  // Check if stale
152
152
  const stale = await isLockStale(lockPath, ttlMs);
153
153
 
@@ -212,5 +212,5 @@ export function getLockPath(modelPath: string): string {
212
212
  * Get the manifest lock path for a cache directory.
213
213
  */
214
214
  export function getManifestLockPath(cacheDir: string): string {
215
- return join(cacheDir, 'manifest.lock');
215
+ return join(cacheDir, "manifest.lock");
216
216
  }
@@ -5,21 +5,22 @@
5
5
  * @module src/llm/nodeLlamaCpp/adapter
6
6
  */
7
7
 
8
- import type { Config } from '../../config/types';
9
- import { ModelCache } from '../cache';
10
- import type { DownloadPolicy } from '../policy';
11
- import { getActivePreset, getModelConfig } from '../registry';
8
+ import type { Config } from "../../config/types";
9
+ import type { DownloadPolicy } from "../policy";
12
10
  import type {
13
11
  EmbeddingPort,
14
12
  GenerationPort,
15
13
  LlmResult,
16
14
  ProgressCallback,
17
15
  RerankPort,
18
- } from '../types';
19
- import { NodeLlamaCppEmbedding } from './embedding';
20
- import { NodeLlamaCppGeneration } from './generation';
21
- import { getModelManager, type ModelManager } from './lifecycle';
22
- import { NodeLlamaCppRerank } from './rerank';
16
+ } from "../types";
17
+
18
+ import { ModelCache } from "../cache";
19
+ import { getActivePreset, getModelConfig } from "../registry";
20
+ import { NodeLlamaCppEmbedding } from "./embedding";
21
+ import { NodeLlamaCppGeneration } from "./generation";
22
+ import { getModelManager, type ModelManager } from "./lifecycle";
23
+ import { NodeLlamaCppRerank } from "./rerank";
23
24
 
24
25
  // ─────────────────────────────────────────────────────────────────────────────
25
26
  // Types
@@ -66,7 +67,7 @@ export class LlmAdapter {
66
67
  // Ensure model is available (downloads if policy allows)
67
68
  const resolved = await this.cache.ensureModel(
68
69
  uri,
69
- 'embed',
70
+ "embed",
70
71
  policy,
71
72
  options?.onProgress
72
73
  );
@@ -95,7 +96,7 @@ export class LlmAdapter {
95
96
  // Ensure model is available (downloads if policy allows)
96
97
  const resolved = await this.cache.ensureModel(
97
98
  uri,
98
- 'gen',
99
+ "gen",
99
100
  policy,
100
101
  options?.onProgress
101
102
  );
@@ -124,7 +125,7 @@ export class LlmAdapter {
124
125
  // Ensure model is available (downloads if policy allows)
125
126
  const resolved = await this.cache.ensureModel(
126
127
  uri,
127
- 'rerank',
128
+ "rerank",
128
129
  policy,
129
130
  options?.onProgress
130
131
  );