@forgehive/forge-cli 0.3.6 → 0.3.8

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/forge.json CHANGED
@@ -5,6 +5,7 @@
5
5
  "paths": {
6
6
  "logs": "logs/",
7
7
  "fixtures": "fixtures",
8
+ "fingerprints": "fingerprints/",
8
9
  "tasks": "src/tasks/",
9
10
  "runners": "src/runners/",
10
11
  "tests": "src/tests/"
@@ -0,0 +1 @@
1
+ {"input":{"filePath":"/Users/danielzavaladlvega/forgehive/forge-mono-repo/apps/sample-project/src/tasks/test/errors.ts"},"boundaries":{"getCwd":[],"loadConf":[],"readFile":[],"writeFile":[],"ensureFingerprintsFolder":[]},"metadata":{"environment":"cli"},"metrics":[],"type":"error","error":"Invalid input on: descriptorName: Required"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgehive/forge-cli",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "TypeScript CLI application",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -10,11 +10,11 @@
10
10
  "publishConfig": {
11
11
  "access": "public",
12
12
  "dependencies": {
13
- "@forgehive/hive-sdk": "^0.1.1",
14
- "@forgehive/record-tape": "^0.2.4",
15
- "@forgehive/runner": "^0.2.4",
13
+ "@forgehive/hive-sdk": "^0.1.2",
14
+ "@forgehive/record-tape": "^0.2.5",
15
+ "@forgehive/runner": "^0.2.5",
16
16
  "@forgehive/schema": "^0.1.4",
17
- "@forgehive/task": "^0.2.4",
17
+ "@forgehive/task": "^0.2.5",
18
18
  "esbuild": "^0.25.0",
19
19
  "handlebars": "^4.7.8",
20
20
  "minimist": "^1.2.8"
@@ -27,11 +27,11 @@
27
27
  "esbuild": "^0.25.0",
28
28
  "handlebars": "^4.7.8",
29
29
  "minimist": "^1.2.8",
30
- "@forgehive/record-tape": "0.2.4",
30
+ "@forgehive/hive-sdk": "0.1.2",
31
+ "@forgehive/record-tape": "0.2.5",
31
32
  "@forgehive/schema": "0.1.4",
32
- "@forgehive/task": "0.2.4",
33
- "@forgehive/hive-sdk": "0.1.1",
34
- "@forgehive/runner": "0.2.4"
33
+ "@forgehive/runner": "0.2.5",
34
+ "@forgehive/task": "0.2.5"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/archiver": "^6.0.3",
@@ -64,25 +64,65 @@ interface TaskFingerprint {
64
64
  type: string
65
65
  properties: Record<string, any>
66
66
  }
67
- outputType: string
68
- boundaries: Record<string, {
69
- inputTypes: string[]
70
- outputType: string
71
- signature: string
72
- }>
73
- functionSource: string
67
+ outputType: {
68
+ type: string
69
+ properties?: Record<string, any>
70
+ elementType?: OutputType
71
+ }
72
+ boundaries: BoundaryFingerprint[]
74
73
  hash: string
75
- metadata: {
76
- extractedAt: string
77
- version: string
74
+ }
75
+
76
+ interface BoundaryFingerprint {
77
+ name: string
78
+ input: SchemaProperty[]
79
+ output: OutputType
80
+ errors: FingerprintError[]
81
+ }
82
+
83
+ interface OutputType {
84
+ type: string
85
+ properties?: Record<string, SchemaProperty>
86
+ elementType?: OutputType
87
+ }
88
+
89
+ interface FingerprintError {
90
+ type: 'parsing' | 'analysis' | 'boundary' | 'schema'
91
+ message: string
92
+ location?: {
93
+ file: string
94
+ line?: number
95
+ column?: number
78
96
  }
79
97
  }
98
+
99
+ interface SchemaProperty {
100
+ name?: string
101
+ type: string
102
+ optional?: boolean
103
+ default?: string
104
+ properties?: Record<string, SchemaProperty>
105
+ }
80
106
  ```
81
107
 
82
- #### FingerprintResult
108
+ #### TaskFingerprintOutput
83
109
  ```typescript
110
+ interface TaskFingerprintOutput {
111
+ description?: string
112
+ inputSchema: InputSchema
113
+ outputType: OutputType
114
+ boundaries: BoundaryFingerprint[]
115
+ errors: FingerprintError[]
116
+ analysisMetadata: {
117
+ timestamp: string
118
+ filePath: string
119
+ success: boolean
120
+ analysisVersion: string
121
+ }
122
+ }
123
+
84
124
  interface FingerprintResult {
85
- tasks: TaskFingerprint[]
125
+ tasks: TaskFingerprintOutput[]
86
126
  buildInfo: {
87
127
  entryPoint: string
88
128
  outputFile: string
@@ -137,16 +177,57 @@ export const taskName = createTask(schema, boundaries, fn)
137
177
  - Generate JSON Schema-compatible output
138
178
 
139
179
  #### Boundary Analysis
140
- - Extract function signatures from boundary object
141
- - Parse parameter types and return types
180
+ - Extract function signatures from boundary object as detailed objects
181
+ - Parse parameter types into structured SchemaProperty arrays
182
+ - Parse return types with support for complex object structures
142
183
  - Handle async functions and Promise return types
143
- - Truncate function source for readability (200 chars max)
184
+ - Collect runtime errors from throw statements in boundary functions
185
+ - Each boundary becomes a BoundaryFingerprint with name, input, output, and errors
144
186
 
145
187
  #### Return Type Analysis
146
188
  - Extract TypeScript return type annotations
147
189
  - Parse Promise wrapper types
148
190
  - Infer types from return statements when annotations missing
149
191
  - Handle complex object return types
192
+ - Support for array element type detection with `elementType` property
193
+
194
+ #### Array Element Type Detection
195
+ The system now provides enhanced array type analysis:
196
+
197
+ **TypeScript Annotation Parsing**:
198
+ ```typescript
199
+ // Boundary function with array return type
200
+ getPortfolio: async (userUUID: string): Promise<{ symbol: string, quantity: number, price: number }[]>
201
+ ```
202
+
203
+ **Generated Fingerprint**:
204
+ ```json
205
+ {
206
+ "type": "array",
207
+ "elementType": {
208
+ "type": "object",
209
+ "properties": {
210
+ "symbol": { "type": "string" },
211
+ "quantity": { "type": "number" },
212
+ "price": { "type": "number" }
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ **Supported Array Patterns**:
219
+ - `T[]` format: `{ symbol: string, quantity: number }[]`
220
+ - `Array<T>` format: `Array<{ symbol: string, quantity: number }>`
221
+ - Complex nested objects within arrays
222
+ - Propagation from boundary types to task output types
223
+
224
+ #### Error Collection
225
+ - **Boundary Errors**: Detect `throw` statements in boundary functions
226
+ - **Main Function Errors**: Detect `throw` statements in the main task function
227
+ - **Parsing Errors**: Capture TypeScript AST parsing failures
228
+ - **Schema Errors**: Capture schema analysis failures
229
+ - **Location Tracking**: Include precise line and column information for each error
230
+ - **Error Types**: Categorize errors as 'parsing', 'analysis', 'boundary', or 'schema'
150
231
 
151
232
  ### 4. Hash Generation Algorithm
152
233
 
@@ -193,43 +274,137 @@ const boundaries = {
193
274
 
194
275
  ```json
195
276
  {
196
- "tasks": [
197
- {
198
- "name": "getPrice",
199
- "description": "Fetches stock price for a given ticker",
200
- "location": {
201
- "file": "src/tasks/price.ts",
202
- "line": 15,
203
- "column": 23
204
- },
205
- "inputSchema": {
206
- "type": "object",
207
- "properties": {
208
- "ticker": { "type": "string" }
277
+ "taskFingerprint": {
278
+ "description": "Test task with intentional runtime errors for error collection testing",
279
+ "inputSchema": {
280
+ "type": "object",
281
+ "properties": {
282
+ "userId": { "type": "string" }
283
+ }
284
+ },
285
+ "outputType": {
286
+ "type": "object",
287
+ "properties": {
288
+ "user": { "type": "object" },
289
+ "profile": { "type": "string" },
290
+ "lastLogin": { "type": "string" },
291
+ "processed": { "type": "boolean" },
292
+ "portfolio": {
293
+ "type": "array",
294
+ "elementType": {
295
+ "type": "object",
296
+ "properties": {
297
+ "symbol": { "type": "string" },
298
+ "quantity": { "type": "number" },
299
+ "price": { "type": "number" }
300
+ }
301
+ }
209
302
  }
303
+ }
304
+ },
305
+ "boundaries": [
306
+ {
307
+ "name": "getUserById",
308
+ "input": [
309
+ {
310
+ "type": "object",
311
+ "properties": {
312
+ "userId": { "type": "string" }
313
+ },
314
+ "name": "input"
315
+ }
316
+ ],
317
+ "output": { "type": "User | null" },
318
+ "errors": []
210
319
  },
211
- "outputType": "Promise<{ ticker: string, price: number }>",
212
- "boundaries": {
213
- "fetchStockPrice": {
214
- "inputTypes": ["string"],
215
- "outputType": "Promise<{ price: number }>",
216
- "signature": "async (ticker: string): Promise<{ price: number }> => {...}"
217
- }
320
+ {
321
+ "name": "getPortfolio",
322
+ "input": [
323
+ {
324
+ "type": "string",
325
+ "name": "userUUID"
326
+ }
327
+ ],
328
+ "output": {
329
+ "type": "array",
330
+ "elementType": {
331
+ "type": "object",
332
+ "properties": {
333
+ "symbol": { "type": "string" },
334
+ "quantity": { "type": "number" },
335
+ "price": { "type": "number" }
336
+ }
337
+ }
338
+ },
339
+ "errors": [
340
+ {
341
+ "type": "boundary",
342
+ "message": "Boundary function throws: User not found",
343
+ "location": {
344
+ "file": "/path/to/tasks/stock/getPortfolio.ts",
345
+ "line": 19,
346
+ "column": 7
347
+ }
348
+ }
349
+ ]
218
350
  },
219
- "functionSource": "async function ({ ticker }, { fetchStockPrice }) { ... }",
220
- "hash": "abc123def",
221
- "metadata": {
222
- "extractedAt": "2025-01-01T12:00:00.000Z",
223
- "version": "1.0.0"
351
+ {
352
+ "name": "fetchUserProfile",
353
+ "input": [
354
+ {
355
+ "type": "object",
356
+ "properties": {
357
+ "userId": { "type": "string" }
358
+ },
359
+ "name": "input"
360
+ }
361
+ ],
362
+ "output": {
363
+ "type": "object",
364
+ "properties": {
365
+ "profile": { "type": "string" },
366
+ "lastLogin": { "type": "string" }
367
+ }
368
+ },
369
+ "errors": [
370
+ {
371
+ "type": "boundary",
372
+ "message": "Boundary function throws: API temporarily unavailable",
373
+ "location": {
374
+ "file": "/path/to/tasks/test/errors.ts",
375
+ "line": 40,
376
+ "column": 7
377
+ }
378
+ },
379
+ {
380
+ "type": "boundary",
381
+ "message": "Boundary function throws: External API authentication failed",
382
+ "location": {
383
+ "file": "/path/to/tasks/test/errors.ts",
384
+ "line": 44,
385
+ "column": 7
386
+ }
387
+ }
388
+ ]
224
389
  }
390
+ ],
391
+ "errors": [
392
+ {
393
+ "type": "analysis",
394
+ "message": "Main task function throws: User with ID ${userId} not found",
395
+ "location": {
396
+ "file": "/path/to/tasks/test/errors.ts",
397
+ "line": 65,
398
+ "column": 7
399
+ }
400
+ }
401
+ ],
402
+ "analysisMetadata": {
403
+ "timestamp": "2025-01-18T12:40:18.033Z",
404
+ "filePath": "/path/to/tasks/test/errors.ts",
405
+ "success": true,
406
+ "analysisVersion": "1.0.0"
225
407
  }
226
- ],
227
- "buildInfo": {
228
- "entryPoint": "src/index.ts",
229
- "outputFile": "dist/bundle.js",
230
- "fingerprintsFile": "dist/bundle.fingerprints.json",
231
- "totalTasks": 5,
232
- "buildTimestamp": "2025-01-01T12:00:00.000Z"
233
408
  }
234
409
  }
235
410
  ```
@@ -291,6 +466,42 @@ console.log(`Generated ${result.taskFingerprints?.totalTasks} task fingerprints`
291
466
 
292
467
  ## Error Handling
293
468
 
469
+ ### Runtime Error Collection
470
+ The fingerprinting system now collects runtime errors from task code:
471
+
472
+ #### Error Types Collected
473
+ 1. **Boundary Errors** (`type: "boundary"`): Thrown errors in boundary functions
474
+ - Detects `throw new Error(...)` statements in boundary function bodies
475
+ - Captures error messages from string literals and template expressions
476
+ - Includes precise line and column location information
477
+
478
+ 2. **Main Function Errors** (`type: "analysis"`): Thrown errors in main task functions
479
+ - Detects `throw new Error(...)` statements in the main task function
480
+ - Supports template literal error messages like `\`User with ID ${userId} not found\``
481
+ - Provides exact source code location
482
+
483
+ 3. **Parsing Errors** (`type: "parsing"`): TypeScript AST parsing failures
484
+ - Occurs when TypeScript compiler cannot parse source code
485
+ - Includes error stack traces and detailed error information
486
+
487
+ 4. **Schema Errors** (`type: "schema"`): Schema analysis failures
488
+ - Captures errors during Schema object analysis
489
+ - Reports issues with malformed schema definitions
490
+
491
+ #### Error Location Tracking
492
+ All errors include detailed location information:
493
+ ```typescript
494
+ {
495
+ type: "analysis",
496
+ message: "Main task function throws: User with ID ${userId} not found",
497
+ location: {
498
+ file: "/path/to/task/file.ts",
499
+ line: 65, // 1-based line number
500
+ column: 7 // 1-based column number
501
+ }
502
+ }
503
+ ```
504
+
294
505
  ### Plugin Error Scenarios
295
506
  1. **TypeScript Parsing Errors**: Log warning, continue processing other files
296
507
  2. **Invalid createTask Calls**: Skip malformed calls, log warnings
@@ -301,6 +512,7 @@ console.log(`Generated ${result.taskFingerprints?.totalTasks} task fingerprints`
301
512
  - If TypeScript analysis fails, include raw source code snippets
302
513
  - Provide partial fingerprints when complete type information unavailable
303
514
  - Continue build process even if fingerprint generation fails
515
+ - Error collection continues even when main analysis partially fails
304
516
 
305
517
  ## Performance Considerations
306
518
 
@@ -363,18 +575,70 @@ export const testTask = createTask(
363
575
 
364
576
  ## Implementation Checklist
365
577
 
366
- - [ ] Implement `taskFingerprintPlugin` esbuild plugin
367
- - [ ] Create TypeScript AST analysis functions
368
- - [ ] Implement schema extraction logic
369
- - [ ] Implement boundary analysis logic
370
- - [ ] Implement return type extraction
371
- - [ ] Create hash generation function
372
- - [ ] Implement enhanced bundle task
373
- - [ ] Add error handling and logging
374
- - [ ] Write comprehensive tests
375
- - [ ] Create CLI integration
376
- - [ ] Generate documentation
377
- - [ ] Performance optimization
378
- - [ ] Add configuration validation
578
+ ### Core Fingerprinting System
579
+ - [x] Implement `taskFingerprintPlugin` esbuild plugin
580
+ - [x] Create TypeScript AST analysis functions
581
+ - [x] Implement schema extraction logic
582
+ - [x] Implement boundary analysis logic
583
+ - [x] Implement return type extraction
584
+ - [x] Create hash generation function
585
+ - [x] Implement enhanced bundle task
586
+ - [x] Create CLI integration
587
+
588
+ ### Enhanced Boundary Analysis
589
+ - [x] Convert boundaries from string arrays to detailed objects
590
+ - [x] Implement detailed boundary input/output type analysis
591
+ - [x] Add support for complex object structure detection
592
+ - [x] Enhance property access expression analysis (e.g., result1.result)
593
+ - [x] Add schema optional property detection with chained methods
594
+ - [x] Implement array element type detection with `elementType` support
595
+ - [x] Add support for complex array-of-objects type patterns
596
+ - [x] Enable type propagation from boundary arrays to task output arrays
597
+
598
+ ### Runtime Error Collection System
599
+ - [x] Implement boundary error detection (throw statements in boundary functions)
600
+ - [x] Implement main task function error detection (throw statements in main function)
601
+ - [x] Add support for template literal error messages
602
+ - [x] Implement precise error location tracking (line and column numbers)
603
+ - [x] Create structured error categorization (parsing, analysis, boundary, schema)
604
+ - [x] Fix error duplication issues with deduplication logic
605
+ - [x] Clean up error format (remove details object, consistent location format)
606
+
607
+ ### Error Handling and Metadata
608
+ - [x] Add comprehensive error handling and logging
609
+ - [x] Implement TaskFingerprintOutput interface with errors and metadata
610
+ - [x] Add analysisMetadata with timestamp, success status, and version
611
+ - [x] Implement graceful degradation for partial analysis failures
612
+
613
+ ### Storage and Configuration
614
+ - [x] Update fingerprint storage to use project fingerprints folder
615
+ - [x] Add fingerprints path configuration support
616
+ - [x] Implement ensureFingerprintsFolder boundary
617
+ - [x] Update file naming conventions for consistency
618
+
619
+ ### Documentation and Specification
620
+ - [x] Generate comprehensive specification documentation
621
+ - [x] Update core interfaces to reflect enhanced structure
622
+ - [x] Document error collection features and examples
623
+ - [x] Add implementation plan documentation
624
+
625
+ ### Testing and Integration
626
+ - [ ] Write comprehensive unit tests for error collection
627
+ - [ ] Write integration tests for enhanced fingerprinting workflow
628
+ - [ ] Test error scenarios and edge cases
629
+ - [ ] Performance testing and optimization
630
+ - [ ] Add configuration validation tests
631
+
632
+ ### Publish Integration
633
+ - [x] Integrate fingerprint generation into publish workflow
634
+ - [x] Add fingerprint data to publish payload
635
+ - [x] Implement error handling for fingerprint failures in publish
636
+ - [x] Add fingerprint status reporting in publish results
637
+
638
+ ### Future Enhancements (Planned)
639
+ - [ ] Implement watch mode for incremental updates
640
+ - [ ] Create fingerprint comparison and diff tools
641
+ - [ ] Add IDE integration and language service plugin
642
+ - [ ] Add fingerprint validation and consistency checks
379
643
 
380
644
  This specification provides a complete blueprint for implementing a sophisticated task fingerprinting system that operates at build time and provides comprehensive type introspection capabilities for TypeScript tasks.
package/src/runner.ts CHANGED
@@ -133,9 +133,15 @@ runner.setHandler(async (data: ParsedArgs): Promise<unknown> => {
133
133
  cache
134
134
  })
135
135
  } else if (taskName === 'task:run') {
136
+ const { input, ...restArgs } = args as { input?: string }
137
+
138
+ // If --input is provided, parse it as JSON and use that
139
+ // Otherwise, use the regular arguments spread from minimist
140
+ const taskArgs = input ? JSON.parse(input) : restArgs
141
+
136
142
  result = await task.run({
137
143
  descriptorName: action,
138
- args
144
+ args: taskArgs
139
145
  })
140
146
  } else if (taskName === 'fixture:download') {
141
147
  const { uuid } = args as { uuid: string }
@@ -160,6 +166,10 @@ runner.setHandler(async (data: ParsedArgs): Promise<unknown> => {
160
166
  })
161
167
  } else {
162
168
  result = await task.run(args)
169
+
170
+ if (taskName === 'info') {
171
+ silent = true
172
+ }
163
173
  }
164
174
 
165
175
  if (taskName === 'task:describe' || taskName === 'task:list') {
@@ -7,7 +7,6 @@ import { Schema } from '@forgehive/schema'
7
7
  import esbuild from 'esbuild'
8
8
  import fs from 'fs/promises'
9
9
  import path from 'path'
10
- import os from 'os'
11
10
 
12
11
  import { load as loadConf } from '../conf/load'
13
12
  import { analyzeTaskFile, TaskFingerprintOutput } from '../../utils/taskAnalysis'
@@ -22,7 +21,9 @@ interface TaskFingerprint {
22
21
  }
23
22
  inputSchema: TaskFingerprintOutput['inputSchema']
24
23
  outputType: TaskFingerprintOutput['outputType']
25
- boundaries: string[]
24
+ boundaries: TaskFingerprintOutput['boundaries']
25
+ errors: TaskFingerprintOutput['errors']
26
+ analysisMetadata: TaskFingerprintOutput['analysisMetadata']
26
27
  hash: string
27
28
  }
28
29
 
@@ -59,14 +60,14 @@ const boundaries = {
59
60
  writeFile: async (filePath: string, content: string): Promise<void> => {
60
61
  return fs.writeFile(filePath, content)
61
62
  },
62
- ensureForgeFolder: async (): Promise<string> => {
63
- const forgePath = path.join(os.homedir(), '.forge')
63
+ ensureFingerprintsFolder: async (cwd: string, conf: { paths?: { fingerprints?: string } }): Promise<string> => {
64
+ const fingerprintsPath = path.join(cwd, conf.paths?.fingerprints || 'fingerprints/')
64
65
  try {
65
- await fs.access(forgePath)
66
+ await fs.access(fingerprintsPath)
66
67
  } catch {
67
- await fs.mkdir(forgePath, { recursive: true })
68
+ await fs.mkdir(fingerprintsPath, { recursive: true })
68
69
  }
69
- return forgePath
70
+ return fingerprintsPath
70
71
  }
71
72
  }
72
73
 
@@ -96,6 +97,8 @@ function taskFingerprintPlugin(): esbuild.Plugin {
96
97
  inputSchema: taskFingerprint.inputSchema,
97
98
  outputType: taskFingerprint.outputType,
98
99
  boundaries: taskFingerprint.boundaries,
100
+ errors: taskFingerprint.errors,
101
+ analysisMetadata: taskFingerprint.analysisMetadata,
99
102
  hash: 'generated-hash'
100
103
  }
101
104
  fingerprints.push(fullFingerprint)
@@ -121,7 +124,7 @@ export const fingerprint = createTask({
121
124
  loadConf,
122
125
  readFile,
123
126
  writeFile,
124
- ensureForgeFolder
127
+ ensureFingerprintsFolder
125
128
  }) {
126
129
  // If filePath is provided, analyze that file directly and return JSON
127
130
  if (filePath) {
@@ -133,9 +136,23 @@ export const fingerprint = createTask({
133
136
  throw new Error('Could not extract fingerprint from task file: ' + filePath)
134
137
  }
135
138
 
136
- return {
139
+ // Write fingerprint to file for consistency
140
+ const cwd = await getCwd()
141
+ const forgeJson = await loadConf({})
142
+ const fingerprintsPath = await ensureFingerprintsFolder(cwd, forgeJson)
143
+ const fingerprintFile = path.join(fingerprintsPath, `${descriptorName}.fingerprint.json`)
144
+
145
+ const analysis = {
137
146
  taskFingerprint: fingerprintOutput
138
147
  }
148
+
149
+ await writeFile(fingerprintFile, JSON.stringify(analysis, null, 2))
150
+ console.log(`Fingerprint saved to: ${fingerprintFile}`)
151
+
152
+ return {
153
+ taskFingerprint: fingerprintOutput,
154
+ fingerprintFile
155
+ }
139
156
  }
140
157
 
141
158
  // Original bundle logic when no filePath is provided
@@ -149,9 +166,9 @@ export const fingerprint = createTask({
149
166
  }
150
167
 
151
168
  const entryPoint = path.join(cwd, taskDescriptor.path)
152
- const forgePath = await ensureForgeFolder()
153
- const outputFile = path.join(forgePath, `${descriptorName}.js`)
154
- const fingerprintsFile = path.join(forgePath, `${descriptorName}.fingerprints.json`)
169
+ const fingerprintsPath = await ensureFingerprintsFolder(cwd, forgeJson)
170
+ const outputFile = path.join(fingerprintsPath, `${descriptorName}.js`)
171
+ const fingerprintsFile = path.join(fingerprintsPath, `${descriptorName}.fingerprints.json`)
155
172
 
156
173
  console.log(`Generating bundle with fingerprints for task: ${descriptorName}`)
157
174
  console.log(`Entry point: ${entryPoint}`)
@@ -177,7 +194,9 @@ export const fingerprint = createTask({
177
194
  description: fp.description,
178
195
  inputSchema: fp.inputSchema,
179
196
  outputType: fp.outputType,
180
- boundaries: fp.boundaries
197
+ boundaries: fp.boundaries,
198
+ errors: fp.errors, // Preserve errors from analyzeTaskFile
199
+ analysisMetadata: fp.analysisMetadata // Preserve metadata from analyzeTaskFile
181
200
  }))
182
201
 
183
202
  // Create fingerprint result