@forgehive/forge-cli 0.2.14 → 0.3.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 (67) hide show
  1. package/dist/runner.js +3 -1
  2. package/dist/tasks/auth/add.js +23 -19
  3. package/dist/tasks/auth/list.js +20 -16
  4. package/dist/tasks/auth/load.js +19 -15
  5. package/dist/tasks/auth/loadCurrent.js +13 -9
  6. package/dist/tasks/auth/remove.js +30 -26
  7. package/dist/tasks/auth/switch.js +19 -15
  8. package/dist/tasks/bundle/create.js +16 -12
  9. package/dist/tasks/bundle/fingerprint.d.ts +36 -0
  10. package/dist/tasks/bundle/fingerprint.js +164 -0
  11. package/dist/tasks/bundle/load.js +9 -5
  12. package/dist/tasks/bundle/zip.js +49 -45
  13. package/dist/tasks/conf/info.js +23 -19
  14. package/dist/tasks/conf/load.js +8 -4
  15. package/dist/tasks/fixture/download.js +40 -36
  16. package/dist/tasks/init.js +35 -31
  17. package/dist/tasks/runner/bundle.js +34 -30
  18. package/dist/tasks/runner/create.js +28 -24
  19. package/dist/tasks/runner/remove.js +22 -18
  20. package/dist/tasks/task/createTask.js +35 -28
  21. package/dist/tasks/task/describe.js +85 -81
  22. package/dist/tasks/task/download.js +63 -59
  23. package/dist/tasks/task/fingerprint.d.ts +26 -0
  24. package/dist/tasks/task/fingerprint.js +87 -0
  25. package/dist/tasks/task/list.js +27 -23
  26. package/dist/tasks/task/publish.js +72 -68
  27. package/dist/tasks/task/remove.js +24 -20
  28. package/dist/tasks/task/replay.js +94 -90
  29. package/dist/tasks/task/run.js +78 -79
  30. package/dist/test/tasks/create.test.js +6 -5
  31. package/dist/utils/taskAnalysis.d.ts +21 -0
  32. package/dist/utils/taskAnalysis.js +380 -0
  33. package/forge.json +12 -0
  34. package/logs/task:fingerprint.log +10 -0
  35. package/package.json +7 -7
  36. package/specs/fingerprint.md +380 -0
  37. package/src/runner.ts +3 -1
  38. package/src/tasks/README.md +13 -13
  39. package/src/tasks/auth/add.ts +3 -3
  40. package/src/tasks/auth/list.ts +3 -3
  41. package/src/tasks/auth/load.ts +3 -3
  42. package/src/tasks/auth/loadCurrent.ts +3 -3
  43. package/src/tasks/auth/remove.ts +3 -3
  44. package/src/tasks/auth/switch.ts +3 -3
  45. package/src/tasks/bundle/README.md +7 -7
  46. package/src/tasks/bundle/create.ts +4 -4
  47. package/src/tasks/bundle/fingerprint.ts +218 -0
  48. package/src/tasks/bundle/load.ts +4 -4
  49. package/src/tasks/bundle/zip.ts +3 -3
  50. package/src/tasks/conf/info.ts +3 -3
  51. package/src/tasks/conf/load.ts +3 -3
  52. package/src/tasks/fixture/download.ts +3 -3
  53. package/src/tasks/init.ts +3 -3
  54. package/src/tasks/runner/bundle.ts +3 -3
  55. package/src/tasks/runner/create.ts +3 -3
  56. package/src/tasks/runner/remove.ts +3 -3
  57. package/src/tasks/task/createTask.ts +10 -7
  58. package/src/tasks/task/describe.ts +3 -3
  59. package/src/tasks/task/download.ts +3 -3
  60. package/src/tasks/task/fingerprint.ts +107 -0
  61. package/src/tasks/task/list.ts +3 -3
  62. package/src/tasks/task/publish.ts +3 -3
  63. package/src/tasks/task/remove.ts +3 -3
  64. package/src/tasks/task/replay.ts +3 -3
  65. package/src/tasks/task/run.ts +12 -18
  66. package/src/test/tasks/create.test.ts +9 -9
  67. package/src/utils/taskAnalysis.ts +419 -0
@@ -0,0 +1,218 @@
1
+ // TASK: fingerprint
2
+ // Run this task with:
3
+ // forge task:run bundle:fingerprint --descriptorName task-name
4
+
5
+ import { createTask } from '@forgehive/task'
6
+ import { Schema } from '@forgehive/schema'
7
+ import esbuild from 'esbuild'
8
+ import fs from 'fs/promises'
9
+ import path from 'path'
10
+ import os from 'os'
11
+
12
+ import { load as loadConf } from '../conf/load'
13
+ import { analyzeTaskFile, TaskFingerprintOutput } from '../../utils/taskAnalysis'
14
+
15
+ interface TaskFingerprint {
16
+ name: string
17
+ description?: string
18
+ location: {
19
+ file: string
20
+ line: number
21
+ column: number
22
+ }
23
+ inputSchema: TaskFingerprintOutput['inputSchema']
24
+ outputType: TaskFingerprintOutput['outputType']
25
+ boundaries: string[]
26
+ hash: string
27
+ }
28
+
29
+ interface EsbuildResultWithFingerprints extends esbuild.BuildResult {
30
+ fingerprints?: TaskFingerprint[]
31
+ }
32
+
33
+ interface FingerprintResult {
34
+ tasks: TaskFingerprintOutput[]
35
+ buildInfo: {
36
+ entryPoint: string
37
+ outputFile: string
38
+ fingerprintsFile?: string
39
+ totalTasks: number
40
+ buildTimestamp: string
41
+ }
42
+ }
43
+
44
+ const description = 'Generate task bundle with comprehensive fingerprinting and type extraction'
45
+
46
+ const schema = new Schema({
47
+ descriptorName: Schema.string(),
48
+ filePath: Schema.string().optional()
49
+ })
50
+
51
+ const boundaries = {
52
+ getCwd: async (): Promise<string> => {
53
+ return process.cwd()
54
+ },
55
+ loadConf: loadConf.asBoundary(),
56
+ readFile: async (filePath: string): Promise<string> => {
57
+ return fs.readFile(filePath, 'utf-8')
58
+ },
59
+ writeFile: async (filePath: string, content: string): Promise<void> => {
60
+ return fs.writeFile(filePath, content)
61
+ },
62
+ ensureForgeFolder: async (): Promise<string> => {
63
+ const forgePath = path.join(os.homedir(), '.forge')
64
+ try {
65
+ await fs.access(forgePath)
66
+ } catch {
67
+ await fs.mkdir(forgePath, { recursive: true })
68
+ }
69
+ return forgePath
70
+ }
71
+ }
72
+
73
+ // esbuild plugin for fingerprinting
74
+ function taskFingerprintPlugin(): esbuild.Plugin {
75
+ return {
76
+ name: 'task-fingerprint',
77
+ setup(build): void {
78
+ const fingerprints: TaskFingerprint[] = []
79
+
80
+ build.onLoad({ filter: /\.ts$/ }, async (args) => {
81
+ const sourceCode = await fs.readFile(args.path, 'utf-8')
82
+
83
+ // Only analyze files that contain createTask
84
+ if (sourceCode.includes('createTask')) {
85
+ const taskFingerprint = analyzeTaskFile(sourceCode, args.path)
86
+ if (taskFingerprint) {
87
+ // Convert to full TaskFingerprint for plugin compatibility
88
+ const fullFingerprint: TaskFingerprint = {
89
+ name: path.basename(args.path, '.ts'),
90
+ description: taskFingerprint.description,
91
+ location: {
92
+ file: args.path,
93
+ line: 1,
94
+ column: 1
95
+ },
96
+ inputSchema: taskFingerprint.inputSchema,
97
+ outputType: taskFingerprint.outputType,
98
+ boundaries: taskFingerprint.boundaries,
99
+ hash: 'generated-hash'
100
+ }
101
+ fingerprints.push(fullFingerprint)
102
+ }
103
+ }
104
+
105
+ return null // Let esbuild handle the file normally
106
+ })
107
+
108
+ build.onEnd((result): void => {
109
+ // Store fingerprints for later use
110
+ (result as EsbuildResultWithFingerprints).fingerprints = fingerprints
111
+ })
112
+ }
113
+ }
114
+ }
115
+
116
+ export const fingerprint = createTask({
117
+ schema,
118
+ boundaries,
119
+ fn: async function ({ descriptorName, filePath }, {
120
+ getCwd,
121
+ loadConf,
122
+ readFile,
123
+ writeFile,
124
+ ensureForgeFolder
125
+ }) {
126
+ // If filePath is provided, analyze that file directly and return JSON
127
+ if (filePath) {
128
+ console.log(`Analyzing task file: ${filePath}`)
129
+ const sourceCode = await readFile(filePath)
130
+ const fingerprintOutput = analyzeTaskFile(sourceCode, filePath)
131
+
132
+ if (!fingerprintOutput) {
133
+ throw new Error('Could not extract fingerprint from task file: ' + filePath)
134
+ }
135
+
136
+ return {
137
+ taskFingerprint: fingerprintOutput
138
+ }
139
+ }
140
+
141
+ // Original bundle logic when no filePath is provided
142
+ const cwd = await getCwd()
143
+ const forgeJson = await loadConf({})
144
+
145
+ const taskDescriptor = forgeJson.tasks[descriptorName as keyof typeof forgeJson.tasks]
146
+
147
+ if (taskDescriptor === undefined) {
148
+ throw new Error(`Task "${descriptorName}" is not defined in forge.json`)
149
+ }
150
+
151
+ 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`)
155
+
156
+ console.log(`Generating bundle with fingerprints for task: ${descriptorName}`)
157
+ console.log(`Entry point: ${entryPoint}`)
158
+ console.log(`Output: ${outputFile}`)
159
+
160
+ // Build with fingerprinting plugin
161
+ const result = await esbuild.build({
162
+ entryPoints: [entryPoint],
163
+ outfile: outputFile,
164
+ bundle: true,
165
+ minify: true,
166
+ platform: 'node',
167
+ sourcemap: true,
168
+ plugins: [taskFingerprintPlugin()],
169
+ metafile: true
170
+ })
171
+
172
+ // Extract fingerprints from build result
173
+ const taskFingerprints = (result as EsbuildResultWithFingerprints).fingerprints || []
174
+
175
+ // Convert to simplified output format (remove name, location, hash)
176
+ const simplifiedFingerprints: TaskFingerprintOutput[] = taskFingerprints.map((fp: TaskFingerprint) => ({
177
+ description: fp.description,
178
+ inputSchema: fp.inputSchema,
179
+ outputType: fp.outputType,
180
+ boundaries: fp.boundaries
181
+ }))
182
+
183
+ // Create fingerprint result
184
+ const fingerprintResult: FingerprintResult = {
185
+ tasks: simplifiedFingerprints,
186
+ buildInfo: {
187
+ entryPoint,
188
+ outputFile,
189
+ fingerprintsFile,
190
+ totalTasks: simplifiedFingerprints.length,
191
+ buildTimestamp: new Date().toISOString()
192
+ }
193
+ }
194
+
195
+ // Write fingerprints to file
196
+ await writeFile(fingerprintsFile, JSON.stringify(fingerprintResult, null, 2))
197
+
198
+ console.log(`Generated ${taskFingerprints.length} task fingerprints`)
199
+ console.log(`Fingerprints saved to: ${fingerprintsFile}`)
200
+
201
+ return {
202
+ outputFile,
203
+ fingerprintsFile,
204
+ taskFingerprints: {
205
+ totalTasks: taskFingerprints.length,
206
+ tasks: taskFingerprints.map((fp: TaskFingerprint) => ({
207
+ name: fp.name,
208
+ inputType: fp.inputSchema.type,
209
+ outputType: fp.outputType.type,
210
+ boundaryCount: fp.boundaries.length,
211
+ hash: fp.hash
212
+ }))
213
+ }
214
+ }
215
+ }
216
+ })
217
+
218
+ fingerprint.setDescription(description)
@@ -1,6 +1,6 @@
1
1
  // TASK: load
2
2
  // Run this task with:
3
- // shadow-cli bundle:load
3
+ // forge task:run bundle:load
4
4
 
5
5
  import { createTask } from '@forgehive/task'
6
6
  import { Schema } from '@forgehive/schema'
@@ -11,13 +11,13 @@ const schema = new Schema({
11
11
 
12
12
  const boundaries = {}
13
13
 
14
- export const load = createTask(
14
+ export const load = createTask({
15
15
  schema,
16
16
  boundaries,
17
- async function ({ bundlePath }) {
17
+ fn: async function ({ bundlePath }) {
18
18
  // Dynamically import the bundle from the specified path
19
19
  const bundle = await import(bundlePath)
20
20
 
21
21
  return bundle
22
22
  }
23
- )
23
+ })
@@ -41,10 +41,10 @@ export const bytesToMB = (bytes: number): string => {
41
41
  return `${MB.toFixed(2)} MB`
42
42
  }
43
43
 
44
- export const zip = createTask(
44
+ export const zip = createTask({
45
45
  schema,
46
46
  boundaries,
47
- async function ({ dir, input, output }, { createWriteStream, createArchiver, resolvePathDir, fileExists }) {
47
+ fn: async function ({ dir, input, output }, { createWriteStream, createArchiver, resolvePathDir, fileExists }) {
48
48
  const outputPath = await resolvePathDir(dir, output)
49
49
  const inputPath = await resolvePathDir(dir, input)
50
50
  const inputMapPath = inputPath + '.map'
@@ -104,6 +104,6 @@ export const zip = createTask(
104
104
  archive.finalize()
105
105
  })
106
106
  }
107
- )
107
+ })
108
108
 
109
109
  zip.setDescription(description)
@@ -16,10 +16,10 @@ const boundaries = {
16
16
  loadCurrentProfile: loadCurrentProfile.asBoundary()
17
17
  }
18
18
 
19
- export const info = createTask(
19
+ export const info = createTask({
20
20
  schema,
21
21
  boundaries,
22
- async function (_argv, { loadCurrentProfile, readFile }) {
22
+ fn: async function (_argv, { loadCurrentProfile, readFile }) {
23
23
  const packageJsonPath = path.join(__dirname, '../../../package.json')
24
24
 
25
25
  const packageJsonContent = await readFile(packageJsonPath)
@@ -45,4 +45,4 @@ export const info = createTask(
45
45
 
46
46
  return info
47
47
  }
48
- )
48
+ })
@@ -14,13 +14,13 @@ const boundaries = {
14
14
  }
15
15
  }
16
16
 
17
- export const load = createTask(
17
+ export const load = createTask({
18
18
  schema,
19
19
  boundaries,
20
- async function (_, { readFile }) {
20
+ fn: async function (_, { readFile }) {
21
21
  const forgePath = path.join(process.cwd(), 'forge.json')
22
22
 
23
23
  const content = await readFile(forgePath)
24
24
  return JSON.parse(content) as ForgeConf
25
25
  }
26
- )
26
+ })
@@ -62,10 +62,10 @@ const boundaries = {
62
62
  }
63
63
  }
64
64
 
65
- export const download = createTask(
65
+ export const download = createTask({
66
66
  schema,
67
67
  boundaries,
68
- async function ({ uuid }, {
68
+ fn: async function ({ uuid }, {
69
69
  downloadFixture,
70
70
  getCwd,
71
71
  persistFixture,
@@ -131,6 +131,6 @@ forge task:replay ${taskName} --path ${shortPath}
131
131
  shortPath: shortPath
132
132
  }
133
133
  }
134
- )
134
+ })
135
135
 
136
136
  download.setDescription(description)
package/src/tasks/init.ts CHANGED
@@ -20,10 +20,10 @@ const boundaries = {
20
20
  }
21
21
 
22
22
  // Create a task with type inference from schema and boundaries
23
- export const init = createTask(
23
+ export const init = createTask({
24
24
  schema,
25
25
  boundaries,
26
- async function (argv, { saveFile, getCwd }) {
26
+ fn: async function (argv, { saveFile, getCwd }) {
27
27
  // Handle the dryRun flag
28
28
  const isDryRun = Boolean(argv.dryRun)
29
29
 
@@ -60,4 +60,4 @@ export const init = createTask(
60
60
 
61
61
  return config
62
62
  }
63
- )
63
+ })
@@ -29,10 +29,10 @@ const boundaries = {
29
29
  }
30
30
  }
31
31
 
32
- export const bundle = createTask(
32
+ export const bundle = createTask({
33
33
  schema,
34
34
  boundaries,
35
- async function ({ runnerName, targetPath }, { loadConf, getCwd, ensureDir }) {
35
+ fn: async function ({ runnerName, targetPath }, { loadConf, getCwd, ensureDir }) {
36
36
  // Load forge configuration
37
37
  const forge: ForgeConf = await loadConf({})
38
38
  const cwd = await getCwd()
@@ -76,4 +76,4 @@ export const bundle = createTask(
76
76
  outputFile: path.join(targetPath, `${runnerName}.js`)
77
77
  }
78
78
  }
79
- )
79
+ })
@@ -69,10 +69,10 @@ const boundaries = {
69
69
  }
70
70
  }
71
71
 
72
- export const create = createTask(
72
+ export const create = createTask({
73
73
  schema,
74
74
  boundaries,
75
- async function ({ runnerName }, {
75
+ fn: async function ({ runnerName }, {
76
76
  persistRunner,
77
77
  loadConf,
78
78
  persistConf,
@@ -118,4 +118,4 @@ export const create = createTask(
118
118
  runnerName: formattedName
119
119
  }
120
120
  }
121
- )
121
+ })
@@ -32,10 +32,10 @@ const boundaries = {
32
32
  }
33
33
  }
34
34
 
35
- export const remove = createTask(
35
+ export const remove = createTask({
36
36
  schema,
37
37
  boundaries,
38
- async function ({ runnerName }, {
38
+ fn: async function ({ runnerName }, {
39
39
  loadConf,
40
40
  getCwd,
41
41
  removeRunner,
@@ -71,4 +71,4 @@ export const remove = createTask(
71
71
  runnerName: formattedName
72
72
  }
73
73
  }
74
- )
74
+ })
@@ -18,6 +18,7 @@ const TASK_TEMPLATE = `// TASK: {{ taskName }}
18
18
  import { createTask } from '@forgehive/task'
19
19
  import { Schema } from '@forgehive/schema'
20
20
 
21
+ const name = '{{ taskDescriptor }}'
21
22
  const description = 'Add task description here'
22
23
 
23
24
  const schema = new Schema({
@@ -30,10 +31,12 @@ const boundaries = {
30
31
  // example: readFile: async (path: string) => fs.readFile(path, 'utf-8')
31
32
  }
32
33
 
33
- export const {{ taskName }} = createTask(
34
+ export const {{ taskName }} = createTask({
35
+ name,
36
+ description,
34
37
  schema,
35
38
  boundaries,
36
- async function (argv, boundaries) {
39
+ fn: async function (argv, boundaries) {
37
40
  console.log('input:', argv)
38
41
  console.log('boundaries:', boundaries)
39
42
  // Your task implementation goes here
@@ -41,9 +44,8 @@ export const {{ taskName }} = createTask(
41
44
 
42
45
  return status
43
46
  }
44
- )
47
+ })
45
48
 
46
- {{ taskName }}.setDescription(description)
47
49
  `
48
50
 
49
51
  const schema = new Schema({
@@ -107,10 +109,10 @@ const boundaries = {
107
109
  }
108
110
  }
109
111
 
110
- export const createTaskCommand = createTask(
112
+ export const createTaskCommand = createTask({
111
113
  schema,
112
114
  boundaries,
113
- async function ({ descriptorName }, {
115
+ fn: async function ({ descriptorName }, {
114
116
  loadTemplate,
115
117
  persistTask,
116
118
  loadConf,
@@ -132,6 +134,7 @@ export const createTaskCommand = createTask(
132
134
  ==================================================
133
135
  Starting task creation!
134
136
  Creating: ${taskName}
137
+ Descriptor: ${descriptor}
135
138
  Dir: ${dir ?? ''}
136
139
  Into: ${taskPath}
137
140
  ==================================================
@@ -159,4 +162,4 @@ export const createTaskCommand = createTask(
159
162
 
160
163
  return { taskPath, fileName }
161
164
  }
162
- )
165
+ })
@@ -36,10 +36,10 @@ const boundaries = {
36
36
  }
37
37
  }
38
38
 
39
- export const describe = createTask(
39
+ export const describe = createTask({
40
40
  schema,
41
41
  boundaries,
42
- async function ({ descriptorName }, {
42
+ fn: async function ({ descriptorName }, {
43
43
  loadConf,
44
44
  bundleCreate,
45
45
  bundleLoad,
@@ -143,6 +143,6 @@ export const describe = createTask(
143
143
  boundaries: taskBoundaries ? Object.keys(taskBoundaries) : []
144
144
  }
145
145
  }
146
- )
146
+ })
147
147
 
148
148
  describe.setDescription(description)
@@ -90,10 +90,10 @@ const boundaries = {
90
90
  }
91
91
  }
92
92
 
93
- export const download = createTask(
93
+ export const download = createTask({
94
94
  schema,
95
95
  boundaries,
96
- async function ({ descriptorName, uuid }, {
96
+ fn: async function ({ descriptorName, uuid }, {
97
97
  downloadTask,
98
98
  getCwd,
99
99
  parseTaskName,
@@ -189,4 +189,4 @@ export const download = createTask(
189
189
  handler: response.handler
190
190
  }
191
191
  }
192
- )
192
+ })
@@ -0,0 +1,107 @@
1
+ // TASK: fingerprint
2
+ // Run this task with:
3
+ // forge task:run task:fingerprint --descriptorName task-name
4
+
5
+ import { createTask } from '@forgehive/task'
6
+ import { Schema } from '@forgehive/schema'
7
+ import fs from 'fs/promises'
8
+ import path from 'path'
9
+ import os from 'os'
10
+
11
+ import { load as loadConf } from '../conf/load'
12
+ import { analyzeTaskFile, TaskFingerprintOutput } from '../../utils/taskAnalysis'
13
+
14
+ interface FingerprintAnalysis {
15
+ taskFingerprint: TaskFingerprintOutput
16
+ }
17
+
18
+ const description = 'Analyze a specific task and generate detailed fingerprint without bundling'
19
+
20
+ const schema = new Schema({
21
+ descriptorName: Schema.string()
22
+ })
23
+
24
+ const boundaries = {
25
+ getCwd: async (): Promise<string> => {
26
+ return process.cwd()
27
+ },
28
+ loadConf: loadConf.asBoundary(),
29
+ readFile: async (filePath: string): Promise<string> => {
30
+ return fs.readFile(filePath, 'utf-8')
31
+ },
32
+ writeFile: async (filePath: string, content: string): Promise<void> => {
33
+ return fs.writeFile(filePath, content)
34
+ },
35
+ ensureForgeFolder: async (): Promise<string> => {
36
+ const forgePath = path.join(os.homedir(), '.forge')
37
+ try {
38
+ await fs.access(forgePath)
39
+ } catch {
40
+ await fs.mkdir(forgePath, { recursive: true })
41
+ }
42
+ return forgePath
43
+ }
44
+ }
45
+
46
+ export const fingerprint = createTask({
47
+ schema,
48
+ boundaries,
49
+ fn: async function ({ descriptorName }, {
50
+ getCwd,
51
+ loadConf,
52
+ readFile,
53
+ writeFile,
54
+ ensureForgeFolder
55
+ }) {
56
+ const cwd = await getCwd()
57
+ const forgeJson = await loadConf({})
58
+
59
+ const taskDescriptor = forgeJson.tasks[descriptorName as keyof typeof forgeJson.tasks]
60
+
61
+ if (taskDescriptor === undefined) {
62
+ throw new Error(`Task "${descriptorName}" is not defined in forge.json`)
63
+ }
64
+
65
+ const filePath = path.join(cwd, taskDescriptor.path)
66
+ const forgePath = await ensureForgeFolder()
67
+ const fingerprintFile = path.join(forgePath, `${descriptorName}.task-fingerprint.json`)
68
+
69
+ console.log(`Analyzing task: ${descriptorName}`)
70
+ console.log(`Task file: ${filePath}`)
71
+
72
+ // Read and analyze the task file using the utility function
73
+ const sourceCode = await readFile(filePath)
74
+ const taskFingerprint = analyzeTaskFile(sourceCode, filePath)
75
+
76
+ if (!taskFingerprint) {
77
+ throw new Error('Could not extract fingerprint from task file: ' + filePath)
78
+ }
79
+
80
+ // Create analysis result - clean output without extra fields
81
+ const analysis: FingerprintAnalysis = {
82
+ taskFingerprint
83
+ }
84
+
85
+ // Write fingerprint to file
86
+ await writeFile(fingerprintFile, JSON.stringify(analysis, null, 2))
87
+
88
+ console.log('Task fingerprint generated successfully')
89
+ console.log(`Input properties: ${Object.keys(taskFingerprint.inputSchema.properties).join(', ')}`)
90
+ console.log(`Boundaries: ${taskFingerprint.boundaries.join(', ')}`)
91
+ console.log(`Fingerprint saved to: ${fingerprintFile}`)
92
+
93
+ return {
94
+ taskName: descriptorName,
95
+ fingerprint: taskFingerprint,
96
+ fingerprintFile,
97
+ analysis: {
98
+ inputSchemaProps: Object.keys(taskFingerprint.inputSchema.properties),
99
+ boundaryCount: taskFingerprint.boundaries.length,
100
+ hasDescription: !!taskFingerprint.description,
101
+ outputType: taskFingerprint.outputType.type
102
+ }
103
+ }
104
+ }
105
+ })
106
+
107
+ fingerprint.setDescription(description)
@@ -18,10 +18,10 @@ const boundaries = {
18
18
  loadConf: loadConf.asBoundary()
19
19
  }
20
20
 
21
- export const list = createTask(
21
+ export const list = createTask({
22
22
  schema,
23
23
  boundaries,
24
- async function (argv, { loadConf }) {
24
+ fn: async function (argv, { loadConf }) {
25
25
  // Load forge configuration
26
26
  const forge: ForgeConf = await loadConf({})
27
27
 
@@ -53,6 +53,6 @@ export const list = createTask(
53
53
  taskCount: taskNames.length
54
54
  }
55
55
  }
56
- )
56
+ })
57
57
 
58
58
  list.setDescription(description)
@@ -81,10 +81,10 @@ const boundaries = {
81
81
  }
82
82
  }
83
83
 
84
- export const publish = createTask(
84
+ export const publish = createTask({
85
85
  schema,
86
86
  boundaries,
87
- async function ({ descriptorName }, {
87
+ fn: async function ({ descriptorName }, {
88
88
  getCwd,
89
89
  ensureBuildsFolder,
90
90
  loadConf,
@@ -184,4 +184,4 @@ export const publish = createTask(
184
184
  throw new Error('Bundle upload failed')
185
185
  }
186
186
  }
187
- )
187
+ })
@@ -25,10 +25,10 @@ const boundaries = {
25
25
  }
26
26
  }
27
27
 
28
- export const remove = createTask(
28
+ export const remove = createTask({
29
29
  schema,
30
30
  boundaries,
31
- async function ({ descriptorName }, { loadConf, persistConf, deleteFile }) {
31
+ fn: async function ({ descriptorName }, { loadConf, persistConf, deleteFile }) {
32
32
  // Load shadow configuration
33
33
  const forge: ForgeConf = await loadConf({})
34
34
 
@@ -61,4 +61,4 @@ export const remove = createTask(
61
61
  message: `Task '${descriptorName}' has been successfully removed`
62
62
  }
63
63
  }
64
- )
64
+ })
@@ -96,10 +96,10 @@ const boundaries = {
96
96
  }
97
97
  }
98
98
 
99
- export const replay = createTask(
99
+ export const replay = createTask({
100
100
  schema,
101
101
  boundaries,
102
- async function ({ descriptorName, path: fixturePath, cache }, { readFixture, loadConf, loadCurrentProfile, bundleCreate, bundleLoad, ensureBuildsFolder, verifyLogFolder, sendLogToAPI }) {
102
+ fn: async function ({ descriptorName, path: fixturePath, cache }, { readFixture, loadConf, loadCurrentProfile, bundleCreate, bundleLoad, ensureBuildsFolder, verifyLogFolder, sendLogToAPI }) {
103
103
  console.log('Input descriptorName:', descriptorName)
104
104
  console.log('Input path:', fixturePath)
105
105
  console.log('Input cache:', cache)
@@ -215,6 +215,6 @@ export const replay = createTask(
215
215
 
216
216
  return result
217
217
  }
218
- )
218
+ })
219
219
 
220
220
  replay.setDescription(description)