@gmickel/gno 0.13.2 → 0.14.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmickel/gno",
3
- "version": "0.13.2",
3
+ "version": "0.14.1",
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",
@@ -56,6 +56,8 @@ export interface EmbedOptions {
56
56
  yes?: boolean;
57
57
  /** Output as JSON */
58
58
  json?: boolean;
59
+ /** Verbose error logging */
60
+ verbose?: boolean;
59
61
  }
60
62
 
61
63
  export type EmbedResult =
@@ -104,6 +106,7 @@ interface BatchContext {
104
106
  force: boolean;
105
107
  showProgress: boolean;
106
108
  totalToEmbed: number;
109
+ verbose: boolean;
107
110
  }
108
111
 
109
112
  type BatchResult =
@@ -150,6 +153,11 @@ async function processBatches(ctx: BatchContext): Promise<BatchResult> {
150
153
  batch.map((b) => formatDocForEmbedding(b.text, b.title ?? undefined))
151
154
  );
152
155
  if (!batchEmbedResult.ok) {
156
+ if (ctx.verbose) {
157
+ process.stderr.write(
158
+ `\n[embed] Batch failed: ${batchEmbedResult.error.message}\n`
159
+ );
160
+ }
153
161
  errors += batch.length;
154
162
  continue;
155
163
  }
@@ -157,6 +165,11 @@ async function processBatches(ctx: BatchContext): Promise<BatchResult> {
157
165
  // Validate batch/embedding count match
158
166
  const embeddings = batchEmbedResult.value;
159
167
  if (embeddings.length !== batch.length) {
168
+ if (ctx.verbose) {
169
+ process.stderr.write(
170
+ `\n[embed] Count mismatch: got ${embeddings.length}, expected ${batch.length}\n`
171
+ );
172
+ }
160
173
  errors += batch.length;
161
174
  continue;
162
175
  }
@@ -171,6 +184,11 @@ async function processBatches(ctx: BatchContext): Promise<BatchResult> {
171
184
 
172
185
  const storeResult = await ctx.vectorIndex.upsertVectors(vectors);
173
186
  if (!storeResult.ok) {
187
+ if (ctx.verbose) {
188
+ process.stderr.write(
189
+ `\n[embed] Store failed: ${storeResult.error.message}\n`
190
+ );
191
+ }
174
192
  errors += batch.length;
175
193
  continue;
176
194
  }
@@ -366,6 +384,7 @@ export async function embed(options: EmbedOptions = {}): Promise<EmbedResult> {
366
384
  force,
367
385
  showProgress: !options.json,
368
386
  totalToEmbed,
387
+ verbose: options.verbose ?? false,
369
388
  });
370
389
 
371
390
  if (!result.ok) {
@@ -71,6 +71,7 @@ export async function index(options: IndexOptions = {}): Promise<IndexResult> {
71
71
  const { embed } = await import("./embed");
72
72
  const result = await embed({
73
73
  configPath: options.configPath,
74
+ verbose: options.verbose,
74
75
  });
75
76
  if (result.success) {
76
77
  embedResult = {
@@ -1278,6 +1278,7 @@ function wireManagementCommands(program: Command): void {
1278
1278
  dryRun: Boolean(cmdOpts.dryRun),
1279
1279
  yes: globals.yes,
1280
1280
  json: format === "json",
1281
+ verbose: globals.verbose,
1281
1282
  };
1282
1283
  const result = await embed(opts);
1283
1284
 
@@ -19,6 +19,8 @@ import {
19
19
 
20
20
  import type { SkippedEntry, WalkConfig, WalkEntry, WalkerPort } from "./types";
21
21
 
22
+ import { SUPPORTED_EXTENSIONS } from "../converters/mime";
23
+
22
24
  /**
23
25
  * Regex to detect dangerous patterns with parent directory traversal.
24
26
  * Matches ".." at start, after "/", or after "\" (Windows).
@@ -108,18 +110,20 @@ function matchesExclude(relPath: string, excludes: string[]): boolean {
108
110
  /**
109
111
  * Check if a file extension matches the include list.
110
112
  * Include list contains extensions like ".md" or "md" (normalized).
113
+ * When include is empty, falls back to SUPPORTED_EXTENSIONS to avoid
114
+ * walking files that can't be converted.
111
115
  */
112
116
  function matchesInclude(relPath: string, include: string[]): boolean {
113
- if (include.length === 0) {
114
- return true;
115
- }
116
-
117
117
  const ext = extname(relPath).toLowerCase();
118
118
  if (!ext) {
119
119
  return false;
120
120
  }
121
121
 
122
- return include.some((inc) => {
122
+ // Fallback to supported extensions when no explicit include list
123
+ const effectiveInclude =
124
+ include.length === 0 ? SUPPORTED_EXTENSIONS : include;
125
+
126
+ return effectiveInclude.some((inc) => {
123
127
  const normalizedInc = inc.startsWith(".")
124
128
  ? inc.toLowerCase()
125
129
  : `.${inc.toLowerCase()}`;