veryfront 0.1.83 → 0.1.84

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 (45) hide show
  1. package/esm/cli/commands/knowledge/command.d.ts +10 -13
  2. package/esm/cli/commands/knowledge/command.d.ts.map +1 -1
  3. package/esm/cli/commands/knowledge/command.js +294 -110
  4. package/esm/cli/commands/knowledge/parser-source.d.ts.map +1 -1
  5. package/esm/cli/commands/knowledge/parser-source.js +52 -0
  6. package/esm/cli/commands/knowledge/result.d.ts +54 -0
  7. package/esm/cli/commands/knowledge/result.d.ts.map +1 -0
  8. package/esm/cli/commands/knowledge/result.js +22 -0
  9. package/esm/cli/commands/knowledge/source-policy.d.ts +11 -0
  10. package/esm/cli/commands/knowledge/source-policy.d.ts.map +1 -0
  11. package/esm/cli/commands/knowledge/source-policy.js +135 -0
  12. package/esm/deno.js +1 -1
  13. package/esm/src/jobs/index.d.ts +1 -1
  14. package/esm/src/jobs/index.d.ts.map +1 -1
  15. package/esm/src/jobs/index.js +1 -1
  16. package/esm/src/jobs/schemas.d.ts +1104 -185
  17. package/esm/src/jobs/schemas.d.ts.map +1 -1
  18. package/esm/src/jobs/schemas.js +81 -8
  19. package/esm/src/proxy/error-response.d.ts +7 -0
  20. package/esm/src/proxy/error-response.d.ts.map +1 -0
  21. package/esm/src/proxy/error-response.js +26 -0
  22. package/esm/src/proxy/handler.d.ts.map +1 -1
  23. package/esm/src/proxy/handler.js +25 -0
  24. package/esm/src/proxy/main.js +2 -23
  25. package/esm/src/transforms/esm/http-cache-helpers.d.ts.map +1 -1
  26. package/esm/src/transforms/esm/http-cache-helpers.js +7 -1
  27. package/esm/src/transforms/import-rewriter/strategies/bare-strategy.d.ts.map +1 -1
  28. package/esm/src/transforms/import-rewriter/strategies/bare-strategy.js +11 -8
  29. package/esm/src/transforms/shared/package-specifier.d.ts +7 -0
  30. package/esm/src/transforms/shared/package-specifier.d.ts.map +1 -0
  31. package/esm/src/transforms/shared/package-specifier.js +19 -0
  32. package/package.json +1 -1
  33. package/src/cli/commands/knowledge/command.ts +375 -139
  34. package/src/cli/commands/knowledge/parser-source.ts +52 -0
  35. package/src/cli/commands/knowledge/result.ts +88 -0
  36. package/src/cli/commands/knowledge/source-policy.ts +164 -0
  37. package/src/deno.js +1 -1
  38. package/src/src/jobs/index.ts +16 -0
  39. package/src/src/jobs/schemas.ts +105 -8
  40. package/src/src/proxy/error-response.ts +33 -0
  41. package/src/src/proxy/handler.ts +43 -0
  42. package/src/src/proxy/main.ts +2 -27
  43. package/src/src/transforms/esm/http-cache-helpers.ts +12 -1
  44. package/src/src/transforms/import-rewriter/strategies/bare-strategy.ts +11 -12
  45. package/src/src/transforms/shared/package-specifier.ts +29 -0
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import { type ApiClient } from "../../shared/config.js";
3
3
  import type { ParsedArgs } from "../../shared/types.js";
4
4
  import { type Logger } from "../../../src/utils/index.js";
5
+ import { type KnowledgeIngestFailedFileResult, type KnowledgeIngestFileResult, type KnowledgeIngestSkippedFileResult } from "./result.js";
5
6
  export interface KnowledgeParserResult {
6
7
  success: true;
7
8
  source_path: string;
@@ -16,17 +17,6 @@ export interface KnowledgeParserResult {
16
17
  stats: Record<string, unknown>;
17
18
  warnings: string[];
18
19
  }
19
- export interface KnowledgeIngestFileResult {
20
- source: string;
21
- localSourcePath: string;
22
- outputPath: string;
23
- remotePath: string;
24
- slug: string;
25
- sourceType: string;
26
- summary: string;
27
- stats: Record<string, unknown>;
28
- warnings: string[];
29
- }
30
20
  type KnowledgeSource = {
31
21
  kind: "local";
32
22
  input: string;
@@ -37,6 +27,10 @@ type KnowledgeSource = {
37
27
  uploadPath: string;
38
28
  localPath: string;
39
29
  };
30
+ export interface KnowledgeSourceCollection {
31
+ sources: KnowledgeSource[];
32
+ skipped: KnowledgeIngestSkippedFileResult[];
33
+ }
40
34
  type DownloadResult = {
41
35
  uploadPath: string;
42
36
  localPath: string;
@@ -135,7 +129,7 @@ export declare function collectKnowledgeSources(options: Pick<KnowledgeIngestOpt
135
129
  client: ApiClient;
136
130
  projectSlug: string;
137
131
  downloadUploads: (uploadPaths: string[]) => Promise<DownloadResult[]>;
138
- }): Promise<KnowledgeSource[]>;
132
+ }): Promise<KnowledgeSourceCollection>;
139
133
  export declare function ingestResolvedSources(sources: KnowledgeSource[], options: KnowledgeIngestOptions, deps: {
140
134
  client: ApiClient;
141
135
  projectSlug: string;
@@ -145,7 +139,10 @@ export declare function ingestResolvedSources(sources: KnowledgeSource[], option
145
139
  path: string;
146
140
  }>;
147
141
  eventLogger?: Logger | null;
148
- }): Promise<KnowledgeIngestFileResult[]>;
142
+ }): Promise<{
143
+ ingested: KnowledgeIngestFileResult[];
144
+ failed: KnowledgeIngestFailedFileResult[];
145
+ }>;
149
146
  export declare function knowledgeCommand(args: ParsedArgs): Promise<void>;
150
147
  export {};
151
148
  //# sourceMappingURL=command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/knowledge/command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/knowledge/command.ts"],"names":[],"mappings":"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"}
@@ -10,21 +10,8 @@ import { putRemoteFileFromLocal } from "../files/command.js";
10
10
  import { knowledgeIngestPythonSource } from "./parser-source.js";
11
11
  import { createJobUserLogger, serverLogger } from "../../../src/utils/index.js";
12
12
  import { writeJobResultIfConfigured } from "../../utils/write-job-result.js";
13
- const SUPPORTED_EXTENSIONS = new Set([
14
- ".pdf",
15
- ".csv",
16
- ".tsv",
17
- ".docx",
18
- ".xlsx",
19
- ".xls",
20
- ".pptx",
21
- ".html",
22
- ".htm",
23
- ".txt",
24
- ".json",
25
- ".md",
26
- ".mdx",
27
- ]);
13
+ import { classifyKnowledgeDirectoryPath, classifyKnowledgeSourcePath } from "./source-policy.js";
14
+ import { buildKnowledgeIngestJobResult, } from "./result.js";
28
15
  const knowledgeJobLogger = serverLogger.component("knowledge-ingest");
29
16
  const KnowledgeIngestArgsSchema = z.object({
30
17
  projectSlug: z.string().optional(),
@@ -149,6 +136,15 @@ export function formatKnowledgeUploadSource(uploadPath) {
149
136
  ? normalizedPath
150
137
  : `uploads/${normalizedPath}`;
151
138
  }
139
+ function resolveExplicitUploadPath(inputPath) {
140
+ const normalizedInput = normalizeKnowledgeInputPath(inputPath);
141
+ const displayInput = inputPath.replace(/\\/g, "/");
142
+ const uploadPath = normalizeProjectUploadPath(inputPath);
143
+ if (!uploadPath || normalizedInput.endsWith("/")) {
144
+ throw new Error(`Directory upload references require --path <prefix> --all: ${displayInput}`);
145
+ }
146
+ return uploadPath;
147
+ }
152
148
  export function isLikelyLocalPath(value) {
153
149
  return value.startsWith("/") || value.startsWith("./") || value.startsWith("../") ||
154
150
  /^[A-Za-z]:[\\/]/.test(value);
@@ -159,9 +155,6 @@ function isProjectUploadReference(value) {
159
155
  const normalizedValue = normalize(value).replace(/\\/g, "/").replace(/^\/+/, "");
160
156
  return normalizedValue === "uploads" || normalizedValue.startsWith("uploads/");
161
157
  }
162
- function isSupportedKnowledgeFile(path) {
163
- return SUPPORTED_EXTENSIONS.has(extname(path).toLowerCase());
164
- }
165
158
  function slugify(value) {
166
159
  return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "document";
167
160
  }
@@ -171,32 +164,108 @@ function defaultOutputRoot() {
171
164
  export function resolveKnowledgeDownloadOutputDir(outputDir) {
172
165
  return join(outputDir, ".uploads");
173
166
  }
167
+ function createSkippedKnowledgeSource(input) {
168
+ return {
169
+ source: input.source,
170
+ localSourcePath: input.localSourcePath ?? null,
171
+ message: input.message,
172
+ reason: input.reason,
173
+ };
174
+ }
175
+ function createFailedKnowledgeSource(input) {
176
+ return {
177
+ source: input.source,
178
+ localSourcePath: input.localSourcePath,
179
+ message: input.message,
180
+ reason: input.reason,
181
+ };
182
+ }
183
+ function classifySourceOrSkip(input) {
184
+ const decision = classifyKnowledgeSourcePath(input.source);
185
+ if (decision.kind === "ingest") {
186
+ return null;
187
+ }
188
+ return createSkippedKnowledgeSource({
189
+ source: input.source,
190
+ localSourcePath: input.localSourcePath,
191
+ message: decision.message,
192
+ reason: decision.reason,
193
+ });
194
+ }
195
+ function classifyDirectoryOrSkip(input) {
196
+ const decision = classifyKnowledgeDirectoryPath(input.source);
197
+ if (decision.kind === "ingest") {
198
+ return null;
199
+ }
200
+ return createSkippedKnowledgeSource({
201
+ source: input.source,
202
+ localSourcePath: null,
203
+ message: decision.message,
204
+ reason: decision.reason,
205
+ });
206
+ }
174
207
  async function collectLocalFiles(root, recursive) {
175
208
  const fs = createFileSystem();
176
209
  const stat = await fs.stat(root);
177
- if (stat.isFile)
178
- return isSupportedKnowledgeFile(root) ? [root] : [];
179
- if (!stat.isDirectory)
180
- return [];
181
- const files = [];
210
+ if (stat.isFile) {
211
+ const skipped = classifySourceOrSkip({ source: root, localSourcePath: root });
212
+ return skipped == null
213
+ ? {
214
+ sources: [{ kind: "local", input: root, localPath: root }],
215
+ skipped: [],
216
+ }
217
+ : {
218
+ sources: [],
219
+ skipped: [skipped],
220
+ };
221
+ }
222
+ if (!stat.isDirectory) {
223
+ return { sources: [], skipped: [] };
224
+ }
225
+ const skippedRootDirectory = classifyDirectoryOrSkip({ source: root });
226
+ if (skippedRootDirectory != null) {
227
+ return {
228
+ sources: [],
229
+ skipped: [skippedRootDirectory],
230
+ };
231
+ }
232
+ const collection = {
233
+ sources: [],
234
+ skipped: [],
235
+ };
182
236
  async function walk(dir) {
183
237
  for await (const entry of fs.readDir(dir)) {
184
238
  const entryPath = join(dir, entry.name);
185
239
  if (entry.isDirectory) {
240
+ const skipped = classifyDirectoryOrSkip({ source: entryPath });
241
+ if (skipped != null) {
242
+ collection.skipped.push(skipped);
243
+ continue;
244
+ }
186
245
  if (recursive)
187
246
  await walk(entryPath);
188
247
  continue;
189
248
  }
190
- if (entry.isFile && isSupportedKnowledgeFile(entryPath)) {
191
- files.push(entryPath);
249
+ if (!entry.isFile) {
250
+ continue;
251
+ }
252
+ const skipped = classifySourceOrSkip({ source: entryPath, localSourcePath: entryPath });
253
+ if (skipped != null) {
254
+ collection.skipped.push(skipped);
255
+ continue;
192
256
  }
257
+ collection.sources.push({ kind: "local", input: root, localPath: entryPath });
193
258
  }
194
259
  }
195
260
  await walk(root);
196
- return files.sort();
261
+ collection.sources.sort((left, right) => left.localPath.localeCompare(right.localPath));
262
+ collection.skipped.sort((left, right) => left.source.localeCompare(right.source));
263
+ return collection;
197
264
  }
198
265
  function buildSourceReference(source) {
199
- return source.kind === "upload" ? formatKnowledgeUploadSource(source.uploadPath) : source.input;
266
+ return source.kind === "upload"
267
+ ? formatKnowledgeUploadSource(source.uploadPath)
268
+ : source.localPath;
200
269
  }
201
270
  function buildSuggestedSlug(source, index) {
202
271
  const normalized = normalize(source.kind === "upload" ? source.uploadPath : source.localPath).replace(/\\/g, "/");
@@ -259,35 +328,44 @@ export async function runKnowledgeParser(input) {
259
328
  const outputJsonPath = `${tempDir}/output.json`;
260
329
  const scriptPath = `${tempDir}/ingest_document_to_knowledge.py`;
261
330
  try {
262
- await dntShim.Deno.writeTextFile(inputJsonPath, JSON.stringify({
263
- file_path: input.filePath,
264
- output_dir: input.outputDir,
265
- description: input.description,
266
- slug: input.slug,
267
- source_reference: input.sourceReference,
268
- }));
269
- await dntShim.Deno.writeTextFile(scriptPath, knowledgeIngestPythonSource);
270
- let result;
271
331
  try {
272
- result = await new dntShim.Deno.Command("python3", {
273
- args: [scriptPath, "--input-json", inputJsonPath, "--output-json", outputJsonPath],
274
- ...(input.env ? { env: input.env } : {}),
275
- stdout: "piped",
276
- stderr: "piped",
277
- }).output();
332
+ await dntShim.Deno.writeTextFile(inputJsonPath, JSON.stringify({
333
+ file_path: input.filePath,
334
+ output_dir: input.outputDir,
335
+ description: input.description,
336
+ slug: input.slug,
337
+ source_reference: input.sourceReference,
338
+ }));
339
+ await dntShim.Deno.writeTextFile(scriptPath, knowledgeIngestPythonSource);
340
+ let result;
341
+ try {
342
+ result = await new dntShim.Deno.Command("python3", {
343
+ args: [scriptPath, "--input-json", inputJsonPath, "--output-json", outputJsonPath],
344
+ ...(input.env ? { env: input.env } : {}),
345
+ stdout: "piped",
346
+ stderr: "piped",
347
+ }).output();
348
+ }
349
+ catch (error) {
350
+ if (error instanceof dntShim.Deno.errors.NotFound) {
351
+ throw new Error("python3 is required. Install python3 and the supported parser packages, or run the command inside the Veryfront sandbox.");
352
+ }
353
+ throw error;
354
+ }
355
+ if (result.code !== 0) {
356
+ const stderr = new TextDecoder().decode(result.stderr).trim();
357
+ throw new Error(stderr || "parser exited unsuccessfully");
358
+ }
359
+ const raw = await dntShim.Deno.readTextFile(outputJsonPath);
360
+ return JSON.parse(raw);
278
361
  }
279
362
  catch (error) {
280
- if (error instanceof dntShim.Deno.errors.NotFound) {
281
- throw new Error("knowledge ingest requires python3. Install python3 and the supported parser packages, or run the command inside the Veryfront sandbox.");
363
+ if (error instanceof Error && error.message.startsWith("knowledge ingest parser failed")) {
364
+ throw error;
282
365
  }
283
- throw error;
366
+ const message = error instanceof Error ? error.message : String(error);
367
+ throw new Error(`knowledge ingest parser failed: ${message}`);
284
368
  }
285
- if (result.code !== 0) {
286
- const stderr = new TextDecoder().decode(result.stderr).trim();
287
- throw new Error(`knowledge ingest parser failed${stderr ? `: ${stderr}` : ""}`);
288
- }
289
- const raw = await dntShim.Deno.readTextFile(outputJsonPath);
290
- return JSON.parse(raw);
291
369
  }
292
370
  finally {
293
371
  await dntShim.Deno.remove(tempDir, { recursive: true }).catch(() => undefined);
@@ -298,21 +376,27 @@ export async function collectKnowledgeSources(options, deps) {
298
376
  if (options.sources.length > 0) {
299
377
  const explicitSources = [];
300
378
  const uploadTargets = [];
379
+ const skipped = [];
301
380
  for (const input of options.sources) {
302
381
  if (!isProjectUploadReference(input) && await fs.exists(input)) {
303
- const localFiles = await collectLocalFiles(input, options.recursive);
304
- if (!localFiles.length)
305
- throw new Error(`No supported files found at ${input}`);
382
+ const collection = await collectLocalFiles(input, options.recursive);
306
383
  explicitSources.push({
307
384
  kind: "local",
308
- sources: localFiles.map((localPath) => ({ kind: "local", input, localPath })),
385
+ collection,
309
386
  });
310
387
  continue;
311
388
  }
312
389
  if (isLikelyLocalPath(input)) {
313
390
  throw new Error(`Local file not found: ${input}`);
314
391
  }
315
- const uploadPath = normalizeProjectUploadPath(input);
392
+ const uploadPath = resolveExplicitUploadPath(input);
393
+ const skippedUpload = classifySourceOrSkip({
394
+ source: formatKnowledgeUploadSource(uploadPath),
395
+ });
396
+ if (skippedUpload != null) {
397
+ skipped.push(skippedUpload);
398
+ continue;
399
+ }
316
400
  explicitSources.push({ kind: "upload", input, uploadPath });
317
401
  uploadTargets.push(uploadPath);
318
402
  }
@@ -326,7 +410,14 @@ export async function collectKnowledgeSources(options, deps) {
326
410
  const resolvedSources = [];
327
411
  for (const source of explicitSources) {
328
412
  if (source.kind === "local") {
329
- resolvedSources.push(...source.sources);
413
+ for (const localSource of source.collection.sources) {
414
+ resolvedSources.push({
415
+ kind: "local",
416
+ input: localSource.input,
417
+ localPath: localSource.localPath,
418
+ });
419
+ }
420
+ skipped.push(...source.collection.skipped);
330
421
  continue;
331
422
  }
332
423
  const matchingDownloads = downloadsByPath.get(source.uploadPath);
@@ -341,16 +432,16 @@ export async function collectKnowledgeSources(options, deps) {
341
432
  localPath: download.localPath,
342
433
  });
343
434
  }
344
- return resolvedSources;
435
+ return {
436
+ sources: resolvedSources,
437
+ skipped,
438
+ };
345
439
  }
346
440
  if (!options.path || !options.all) {
347
441
  throw new Error("Provide one or more source paths or use --path with --all.");
348
442
  }
349
443
  if (!isProjectUploadReference(options.path) && await fs.exists(options.path)) {
350
- const localFiles = await collectLocalFiles(options.path, options.recursive);
351
- if (!localFiles.length)
352
- throw new Error(`No supported files found under ${options.path}`);
353
- return localFiles.map((localPath) => ({ kind: "local", input: options.path, localPath }));
444
+ return collectLocalFiles(options.path, options.recursive);
354
445
  }
355
446
  const displayUploadPrefix = normalizeKnowledgeInputPath(options.path);
356
447
  const uploadPrefix = normalizeProjectUploadPath(options.path);
@@ -360,74 +451,131 @@ export async function collectKnowledgeSources(options, deps) {
360
451
  limit: 100,
361
452
  });
362
453
  let uploads = await listUploadsForPrefix(uploadPrefix || undefined);
454
+ let skipped = uploads.flatMap((item) => {
455
+ if (item.type === "folder") {
456
+ return [];
457
+ }
458
+ const skippedUpload = classifySourceOrSkip({
459
+ source: formatKnowledgeUploadSource(item.path),
460
+ });
461
+ return skippedUpload == null ? [] : [skippedUpload];
462
+ });
363
463
  let uploadTargets = uploads
364
- .filter((item) => item.type !== "folder" && isSupportedKnowledgeFile(item.path))
365
- .map((item) => item.path);
464
+ .filter((item) => item.type !== "folder")
465
+ .map((item) => item.path)
466
+ .filter((uploadPath) => classifySourceOrSkip({ source: formatKnowledgeUploadSource(uploadPath) }) == null);
366
467
  if (!uploadTargets.length && uploadPrefix && !uploadPrefix.endsWith("/")) {
367
468
  uploads = await listUploadsForPrefix(`${uploadPrefix}/`);
469
+ skipped = uploads.flatMap((item) => {
470
+ if (item.type === "folder") {
471
+ return [];
472
+ }
473
+ const skippedUpload = classifySourceOrSkip({
474
+ source: formatKnowledgeUploadSource(item.path),
475
+ });
476
+ return skippedUpload == null ? [] : [skippedUpload];
477
+ });
368
478
  uploadTargets = uploads
369
- .filter((item) => item.type !== "folder" && isSupportedKnowledgeFile(item.path))
370
- .map((item) => item.path);
479
+ .filter((item) => item.type !== "folder")
480
+ .map((item) => item.path)
481
+ .filter((uploadPath) => classifySourceOrSkip({ source: formatKnowledgeUploadSource(uploadPath) }) == null);
371
482
  }
372
- if (!uploadTargets.length) {
483
+ if (!uploadTargets.length && skipped.length === 0) {
373
484
  throw new Error(`No supported uploads found under ${displayUploadPrefix}`);
374
485
  }
375
486
  const downloads = await deps.downloadUploads(uploadTargets);
376
- return downloads.map((download) => ({
377
- kind: "upload",
378
- input: options.path,
379
- uploadPath: download.uploadPath,
380
- localPath: download.localPath,
381
- }));
487
+ return {
488
+ sources: downloads.map((download) => ({
489
+ kind: "upload",
490
+ input: options.path,
491
+ uploadPath: download.uploadPath,
492
+ localPath: download.localPath,
493
+ })),
494
+ skipped,
495
+ };
382
496
  }
383
497
  export async function ingestResolvedSources(sources, options, deps) {
384
498
  if (options.slug && sources.length !== 1) {
385
499
  throw new Error("--slug can only be used with a single explicit source.");
386
500
  }
387
501
  const slugs = options.slug ? [options.slug] : ensureUniqueSlugs(sources);
388
- const results = [];
389
- for (const [index, source] of sources.entries()) {
390
- deps.eventLogger?.info("Processing knowledge source", {
391
- phase: "file_processing",
502
+ const ingested = [];
503
+ const failed = [];
504
+ const recordSourceFailure = (source, sourceReference, index, message, reason) => {
505
+ deps.eventLogger?.error("Knowledge source failed", {
506
+ phase: "file_failed",
392
507
  progress_current: index + 1,
393
508
  progress_total: sources.length,
394
509
  source_name: buildKnowledgeSourceName(source),
510
+ error: message,
395
511
  });
396
- const parser = await deps.runParser({
397
- filePath: source.localPath,
398
- outputDir: deps.outputDir,
399
- description: options.description,
400
- slug: slugs[index],
401
- sourceReference: buildSourceReference(source),
402
- });
403
- const remotePath = deriveKnowledgeRemotePath(parser.sandbox_output_path, deps.outputDir, options.knowledgePath);
404
- const uploaded = await deps.uploadKnowledgeFile(remotePath, parser.sandbox_output_path);
405
- deps.eventLogger?.info("Knowledge source ingested", {
406
- phase: "file_completed",
512
+ failed.push(createFailedKnowledgeSource({
513
+ source: sourceReference,
514
+ localSourcePath: source.localPath,
515
+ message,
516
+ reason,
517
+ }));
518
+ };
519
+ for (const [index, source] of sources.entries()) {
520
+ const sourceReference = buildSourceReference(source);
521
+ deps.eventLogger?.info("Processing knowledge source", {
522
+ phase: "file_processing",
407
523
  progress_current: index + 1,
408
524
  progress_total: sources.length,
409
525
  source_name: buildKnowledgeSourceName(source),
410
- remote_path: uploaded.path,
411
- warning_count: parser.warnings.length,
412
526
  });
413
- if (parser.warnings.length > 0) {
414
- deps.eventLogger?.warn("Knowledge source emitted warnings", {
415
- phase: "file_warning",
527
+ let parser;
528
+ try {
529
+ parser = await deps.runParser({
530
+ filePath: source.localPath,
531
+ outputDir: deps.outputDir,
532
+ description: options.description,
533
+ slug: slugs[index],
534
+ sourceReference,
535
+ });
536
+ }
537
+ catch (error) {
538
+ const message = error instanceof Error ? error.message : String(error);
539
+ recordSourceFailure(source, sourceReference, index, message, "parser_error");
540
+ continue;
541
+ }
542
+ try {
543
+ const remotePath = deriveKnowledgeRemotePath(parser.sandbox_output_path, deps.outputDir, options.knowledgePath);
544
+ const uploaded = await deps.uploadKnowledgeFile(remotePath, parser.sandbox_output_path);
545
+ deps.eventLogger?.info("Knowledge source ingested", {
546
+ phase: "file_completed",
416
547
  progress_current: index + 1,
417
548
  progress_total: sources.length,
418
549
  source_name: buildKnowledgeSourceName(source),
550
+ remote_path: uploaded.path,
419
551
  warning_count: parser.warnings.length,
420
552
  });
553
+ if (parser.warnings.length > 0) {
554
+ deps.eventLogger?.warn("Knowledge source emitted warnings", {
555
+ phase: "file_warning",
556
+ progress_current: index + 1,
557
+ progress_total: sources.length,
558
+ source_name: buildKnowledgeSourceName(source),
559
+ warning_count: parser.warnings.length,
560
+ });
561
+ }
562
+ ingested.push(createKnowledgeIngestResult({
563
+ source: sourceReference,
564
+ localSourcePath: source.localPath,
565
+ outputPath: parser.sandbox_output_path,
566
+ remotePath: uploaded.path,
567
+ parser,
568
+ }));
569
+ }
570
+ catch (error) {
571
+ const message = error instanceof Error ? error.message : String(error);
572
+ recordSourceFailure(source, sourceReference, index, message, "upload_error");
421
573
  }
422
- results.push(createKnowledgeIngestResult({
423
- source: buildSourceReference(source),
424
- localSourcePath: source.localPath,
425
- outputPath: parser.sandbox_output_path,
426
- remotePath: uploaded.path,
427
- parser,
428
- }));
429
574
  }
430
- return results;
575
+ return {
576
+ ingested,
577
+ failed,
578
+ };
431
579
  }
432
580
  export async function knowledgeCommand(args) {
433
581
  const subcommand = typeof args._[1] === "string" ? args._[1] : undefined;
@@ -452,20 +600,33 @@ export async function knowledgeCommand(args) {
452
600
  const downloadOutputDir = resolveKnowledgeDownloadOutputDir(outputDir);
453
601
  const eventLogger = createKnowledgeIngestEventLogger();
454
602
  try {
603
+ const sourceMode = options.path ? "path_prefix" : "explicit_sources";
455
604
  eventLogger?.info("Starting knowledge ingest", {
456
605
  phase: "started",
457
- mode: options.path ? "path_prefix" : "explicit_sources",
606
+ mode: sourceMode,
458
607
  });
459
- const sources = await collectKnowledgeSources(options, {
608
+ const collection = await collectKnowledgeSources(options, {
460
609
  client,
461
610
  projectSlug: config.projectSlug,
462
611
  downloadUploads: (uploadPaths) => Promise.all(uploadPaths.map((uploadPath) => downloadUploadToFile(client, config.projectSlug, uploadPath, downloadOutputDir))),
463
612
  });
613
+ const requestedCount = collection.sources.length + collection.skipped.length;
614
+ if (requestedCount === 0) {
615
+ throw new Error("No supported knowledge sources were found.");
616
+ }
464
617
  eventLogger?.info("Resolved knowledge sources", {
465
618
  phase: "sources_resolved",
466
- progress_total: sources.length,
619
+ progress_total: requestedCount,
620
+ ingestable_count: collection.sources.length,
621
+ skipped_count: collection.skipped.length,
467
622
  });
468
- const results = await ingestResolvedSources(sources, options, {
623
+ if (collection.skipped.length > 0) {
624
+ eventLogger?.warn("Skipped knowledge sources", {
625
+ phase: "sources_skipped",
626
+ skipped_count: collection.skipped.length,
627
+ });
628
+ }
629
+ const results = await ingestResolvedSources(collection.sources, options, {
469
630
  client,
470
631
  projectSlug: config.projectSlug,
471
632
  outputDir,
@@ -473,22 +634,45 @@ export async function knowledgeCommand(args) {
473
634
  eventLogger,
474
635
  uploadKnowledgeFile: (remotePath, localPath) => putRemoteFileFromLocal(client, config.projectSlug, remotePath, localPath),
475
636
  });
637
+ const jobResult = buildKnowledgeIngestJobResult({
638
+ requestedCount,
639
+ sourceMode,
640
+ knowledgePath: options.knowledgePath,
641
+ ingested: results.ingested,
642
+ skipped: collection.skipped,
643
+ failed: results.failed,
644
+ });
476
645
  eventLogger?.info("Completed knowledge ingest", {
477
646
  phase: "completed",
478
- progress_current: results.length,
479
- progress_total: results.length,
647
+ progress_current: requestedCount,
648
+ progress_total: requestedCount,
649
+ ingested_count: jobResult.summary.ingested_count,
650
+ skipped_count: jobResult.summary.skipped_count,
651
+ failed_count: jobResult.summary.failed_count,
480
652
  });
481
- await writeJobResultIfConfigured(results);
653
+ await writeJobResultIfConfigured(jobResult);
482
654
  if (options.json) {
483
- printJson(results);
655
+ printJson(jobResult);
484
656
  return;
485
657
  }
486
- for (const result of results) {
658
+ for (const result of jobResult.ingested) {
487
659
  if (!options.quiet) {
488
660
  cliLogger.info(`Ingested ${result.source} -> ${result.remotePath}`);
489
661
  cliLogger.info(` ${result.summary}`);
490
662
  }
491
663
  }
664
+ for (const skipped of jobResult.skipped) {
665
+ if (!options.quiet) {
666
+ cliLogger.warn(`Skipped ${skipped.source}`);
667
+ cliLogger.warn(` ${skipped.message}`);
668
+ }
669
+ }
670
+ for (const failure of jobResult.failed) {
671
+ if (!options.quiet) {
672
+ cliLogger.error(`Failed ${failure.source}`);
673
+ cliLogger.error(` ${failure.message}`);
674
+ }
675
+ }
492
676
  }
493
677
  catch (error) {
494
678
  eventLogger?.error("Knowledge ingest failed", {
@@ -1 +1 @@
1
- {"version":3,"file":"parser-source.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/knowledge/parser-source.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,QAugBvC,CAAC"}
1
+ {"version":3,"file":"parser-source.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/knowledge/parser-source.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,QA2jBvC,CAAC"}