@forgehive/forge-cli 0.2.13 → 0.3.0

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 (84) hide show
  1. package/dist/runner.js +15 -7
  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.d.ts +35 -0
  22. package/dist/tasks/task/describe.js +130 -0
  23. package/dist/tasks/task/download.js +63 -59
  24. package/dist/tasks/task/fingerprint.d.ts +26 -0
  25. package/dist/tasks/task/fingerprint.js +87 -0
  26. package/dist/tasks/task/list.d.ts +12 -0
  27. package/dist/tasks/task/list.js +46 -0
  28. package/dist/tasks/task/publish.js +72 -68
  29. package/dist/tasks/task/remove.js +24 -20
  30. package/dist/tasks/task/replay.js +94 -90
  31. package/dist/tasks/task/run.js +84 -79
  32. package/dist/test/setup.d.ts +0 -0
  33. package/dist/test/setup.js +14 -0
  34. package/dist/test/tasks/create.test.js +6 -5
  35. package/dist/utils/taskAnalysis.d.ts +21 -0
  36. package/dist/utils/taskAnalysis.js +380 -0
  37. package/forge.json +20 -0
  38. package/jest.config.js +2 -1
  39. package/logs/task:fingerprint.log +10 -0
  40. package/package.json +8 -8
  41. package/specs/fingerprint.md +380 -0
  42. package/src/runner.ts +14 -5
  43. package/src/tasks/README.md +13 -13
  44. package/src/tasks/auth/add.ts +3 -3
  45. package/src/tasks/auth/list.ts +3 -3
  46. package/src/tasks/auth/load.ts +3 -3
  47. package/src/tasks/auth/loadCurrent.ts +3 -3
  48. package/src/tasks/auth/remove.ts +3 -3
  49. package/src/tasks/auth/switch.ts +3 -3
  50. package/src/tasks/bundle/README.md +7 -7
  51. package/src/tasks/bundle/create.ts +4 -4
  52. package/src/tasks/bundle/fingerprint.ts +218 -0
  53. package/src/tasks/bundle/load.ts +4 -4
  54. package/src/tasks/bundle/zip.ts +3 -3
  55. package/src/tasks/conf/info.ts +3 -3
  56. package/src/tasks/conf/load.ts +3 -3
  57. package/src/tasks/fixture/download.ts +3 -3
  58. package/src/tasks/init.ts +3 -3
  59. package/src/tasks/runner/bundle.ts +3 -3
  60. package/src/tasks/runner/create.ts +3 -3
  61. package/src/tasks/runner/remove.ts +3 -3
  62. package/src/tasks/task/createTask.ts +10 -7
  63. package/src/tasks/task/describe.ts +148 -0
  64. package/src/tasks/task/download.ts +3 -3
  65. package/src/tasks/task/fingerprint.ts +107 -0
  66. package/src/tasks/task/list.ts +58 -0
  67. package/src/tasks/task/publish.ts +3 -3
  68. package/src/tasks/task/remove.ts +3 -3
  69. package/src/tasks/task/replay.ts +3 -3
  70. package/src/tasks/task/run.ts +5 -4
  71. package/src/test/setup.ts +14 -0
  72. package/src/test/tasks/create.test.ts +9 -9
  73. package/src/utils/taskAnalysis.ts +419 -0
  74. package/dist/taskAdapter.d.ts +0 -34
  75. package/dist/taskAdapter.js +0 -85
  76. package/dist/templates/README.md +0 -23
  77. package/dist/templates/task.hbs +0 -27
  78. package/dist/test/utils.d.ts +0 -2
  79. package/dist/test/utils.js +0 -17
  80. package/logs/auth:list.log +0 -4
  81. package/logs/auth:load.log +0 -2
  82. package/logs/auth:loadCurrent.log +0 -1
  83. package/logs/conf:info.log +0 -2
  84. package/logs/runner:create.log +0 -4
@@ -0,0 +1,419 @@
1
+ import * as ts from 'typescript'
2
+
3
+ interface TaskLocation {
4
+ file: string
5
+ line: number
6
+ column: number
7
+ }
8
+
9
+ interface SchemaProperty {
10
+ type: string
11
+ optional?: boolean
12
+ default?: string
13
+ }
14
+
15
+ interface InputSchema {
16
+ type: string
17
+ properties: Record<string, SchemaProperty>
18
+ }
19
+
20
+ interface OutputType {
21
+ type: string
22
+ properties?: Record<string, SchemaProperty>
23
+ }
24
+
25
+ interface TaskFingerprint {
26
+ name: string
27
+ description?: string
28
+ location: TaskLocation
29
+ inputSchema: InputSchema
30
+ outputType: OutputType
31
+ boundaries: string[]
32
+ hash: string
33
+ }
34
+
35
+ // Simplified interface for filesystem output (excludes name, location, hash)
36
+ export interface TaskFingerprintOutput {
37
+ description?: string
38
+ inputSchema: InputSchema
39
+ outputType: OutputType
40
+ boundaries: string[]
41
+ }
42
+
43
+ // Hash generation function
44
+ function generateHash(input: string): string {
45
+ let hash = 0
46
+ for (let i = 0; i < input.length; i++) {
47
+ const char = input.charCodeAt(i)
48
+ hash = ((hash << 5) - hash) + char
49
+ hash = hash & hash // Convert to 32-bit integer
50
+ }
51
+ return Math.abs(hash).toString(36)
52
+ }
53
+
54
+ // TypeScript AST analysis function
55
+ function extractTaskFingerprints(sourceCode: string, filePath: string): TaskFingerprint[] {
56
+ const sourceFile = ts.createSourceFile(
57
+ filePath,
58
+ sourceCode,
59
+ ts.ScriptTarget.Latest,
60
+ true
61
+ )
62
+
63
+ const fingerprints: TaskFingerprint[] = []
64
+ let schemaNode: ts.Expression | null = null
65
+ let boundariesNode: ts.Expression | null = null
66
+
67
+ // First pass: find schema and boundaries variable declarations
68
+ function findVariables(node: ts.Node): void {
69
+ if (ts.isVariableStatement(node)) {
70
+ node.declarationList.declarations.forEach(decl => {
71
+ if (ts.isIdentifier(decl.name)) {
72
+ if (decl.name.text === 'schema' && decl.initializer) {
73
+ schemaNode = decl.initializer
74
+ } else if (decl.name.text === 'boundaries' && decl.initializer) {
75
+ boundariesNode = decl.initializer
76
+ }
77
+ }
78
+ })
79
+ }
80
+ ts.forEachChild(node, findVariables)
81
+ }
82
+
83
+ // Second pass: find createTask calls
84
+ function findCreateTask(node: ts.Node): void {
85
+ // Look for createTask calls
86
+ if (ts.isCallExpression(node) &&
87
+ ts.isIdentifier(node.expression) &&
88
+ node.expression.text === 'createTask') {
89
+
90
+ const taskName = extractTaskName(node, sourceFile)
91
+ if (taskName) {
92
+ const fingerprint = analyzeCreateTaskCall(node, sourceFile, filePath, taskName, schemaNode, boundariesNode)
93
+ if (fingerprint) {
94
+ fingerprints.push(fingerprint)
95
+ }
96
+ }
97
+ }
98
+
99
+ // Look for exported createTask assignments
100
+ if (ts.isVariableStatement(node) && node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) {
101
+ node.declarationList.declarations.forEach(decl => {
102
+ if (ts.isVariableDeclaration(decl) &&
103
+ decl.initializer &&
104
+ ts.isCallExpression(decl.initializer) &&
105
+ ts.isIdentifier(decl.initializer.expression) &&
106
+ decl.initializer.expression.text === 'createTask') {
107
+
108
+ const taskName = ts.isIdentifier(decl.name) ? decl.name.text : 'unknown'
109
+ const fingerprint = analyzeCreateTaskCall(decl.initializer, sourceFile, filePath, taskName, schemaNode, boundariesNode)
110
+ if (fingerprint) {
111
+ fingerprints.push(fingerprint)
112
+ }
113
+ }
114
+ })
115
+ }
116
+
117
+ ts.forEachChild(node, findCreateTask)
118
+ }
119
+
120
+ // Execute both passes
121
+ findVariables(sourceFile)
122
+ findCreateTask(sourceFile)
123
+
124
+ return fingerprints
125
+ }
126
+
127
+ function extractTaskName(node: ts.CallExpression, _sourceFile: ts.SourceFile): string | null {
128
+ // Try to find the task name from variable assignment or export
129
+ let parent = node.parent
130
+ while (parent) {
131
+ if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
132
+ return parent.name.text
133
+ }
134
+ parent = parent.parent
135
+ }
136
+ return null
137
+ }
138
+
139
+ function analyzeCreateTaskCall(
140
+ node: ts.CallExpression,
141
+ sourceFile: ts.SourceFile,
142
+ filePath: string,
143
+ taskName: string,
144
+ schemaNode: ts.Expression | null = null,
145
+ boundariesNode: ts.Expression | null = null
146
+ ): TaskFingerprint | null {
147
+ try {
148
+ const position = sourceFile.getLineAndCharacterOfPosition(node.getStart())
149
+ const args = node.arguments
150
+
151
+ // Use pre-found schema or fall back to argument analysis
152
+ let inputSchema: InputSchema = { type: 'object', properties: {} }
153
+ if (schemaNode) {
154
+ inputSchema = analyzeSchemaArg(schemaNode, sourceFile)
155
+ } else if (args[0]) {
156
+ inputSchema = analyzeSchemaArg(args[0], sourceFile)
157
+ }
158
+
159
+ // Use pre-found boundaries or fall back to argument analysis - simplified to just names
160
+ let boundaries: string[] = []
161
+ if (boundariesNode) {
162
+ boundaries = analyzeBoundariesArg(boundariesNode, sourceFile)
163
+ } else if (args[1]) {
164
+ boundaries = analyzeBoundariesArg(args[1], sourceFile)
165
+ }
166
+
167
+ // Extract function output type with better detection
168
+ let outputType: OutputType = { type: 'unknown' }
169
+ const functionArg = args[2]
170
+
171
+ if (functionArg) {
172
+ if (ts.isFunctionExpression(functionArg) || ts.isArrowFunction(functionArg)) {
173
+ // Better return type extraction
174
+ if (functionArg.type) {
175
+ const typeString = cleanTypeString(functionArg.type.getText(sourceFile))
176
+ outputType = { type: typeString }
177
+ } else {
178
+ // Try to infer from return statements with better object analysis
179
+ outputType = inferDetailedReturnType(functionArg, sourceFile)
180
+ }
181
+ }
182
+ }
183
+
184
+ // Generate hash from task signature
185
+ const hashInput = `${taskName}:${JSON.stringify(inputSchema)}:${JSON.stringify(boundaries)}`
186
+ const hash = generateHash(hashInput)
187
+
188
+ return {
189
+ name: taskName,
190
+ location: {
191
+ file: filePath,
192
+ line: position.line + 1,
193
+ column: position.character + 1
194
+ },
195
+ inputSchema,
196
+ outputType,
197
+ boundaries,
198
+ hash
199
+ }
200
+ } catch (error) {
201
+ console.warn(`Failed to analyze createTask call for ${taskName}:`, error)
202
+ return null
203
+ }
204
+ }
205
+
206
+ // Enhanced return type inference with detailed object analysis
207
+ function inferDetailedReturnType(func: ts.FunctionExpression | ts.ArrowFunction, _sourceFile: ts.SourceFile): OutputType {
208
+ let returnType: OutputType = { type: 'unknown' }
209
+
210
+ function visitReturnStatements(node: ts.Node): void {
211
+ if (ts.isReturnStatement(node) && node.expression) {
212
+ if (ts.isObjectLiteralExpression(node.expression)) {
213
+ // Analyze object literal properties
214
+ const properties: Record<string, SchemaProperty> = {}
215
+ node.expression.properties.forEach(prop => {
216
+ if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
217
+ // Handle explicit property assignments: { propName: value }
218
+ const propName = prop.name.text
219
+ let propType = 'unknown'
220
+
221
+ // Try to infer property type from the initializer
222
+ if (ts.isStringLiteral(prop.initializer)) {
223
+ propType = 'string'
224
+ } else if (ts.isNumericLiteral(prop.initializer)) {
225
+ propType = 'number'
226
+ } else if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword ||
227
+ prop.initializer.kind === ts.SyntaxKind.FalseKeyword) {
228
+ propType = 'boolean'
229
+ } else if (ts.isIdentifier(prop.initializer)) {
230
+ // Variable reference - try to infer from name
231
+ const varName = prop.initializer.text
232
+ propType = inferTypeFromVariableName(varName)
233
+ } else if (ts.isPropertyAccessExpression(prop.initializer)) {
234
+ // Property access like response.handler
235
+ propType = 'unknown'
236
+ }
237
+
238
+ properties[propName] = { type: propType }
239
+ } else if (ts.isShorthandPropertyAssignment(prop)) {
240
+ // Handle shorthand properties: { propName } (equivalent to { propName: propName })
241
+ const propName = prop.name.text
242
+ const propType = inferTypeFromVariableName(propName)
243
+ properties[propName] = { type: propType }
244
+ }
245
+ })
246
+
247
+ if (Object.keys(properties).length > 0) {
248
+ returnType = {
249
+ type: 'object',
250
+ properties
251
+ }
252
+ } else {
253
+ returnType = { type: 'object' }
254
+ }
255
+ } else if (ts.isStringLiteral(node.expression)) {
256
+ returnType = { type: 'string' }
257
+ } else if (ts.isNumericLiteral(node.expression)) {
258
+ returnType = { type: 'number' }
259
+ } else if (node.expression.kind === ts.SyntaxKind.TrueKeyword ||
260
+ node.expression.kind === ts.SyntaxKind.FalseKeyword) {
261
+ returnType = { type: 'boolean' }
262
+ } else if (ts.isIdentifier(node.expression)) {
263
+ // Single variable return
264
+ const varType = inferTypeFromVariableName(node.expression.text)
265
+ returnType = { type: varType }
266
+ }
267
+ }
268
+ ts.forEachChild(node, visitReturnStatements)
269
+ }
270
+
271
+ if (func.body) {
272
+ visitReturnStatements(func.body)
273
+ }
274
+
275
+ return returnType
276
+ }
277
+
278
+ // Helper function to infer types from variable names
279
+ function inferTypeFromVariableName(varName: string): string {
280
+ // Common patterns for type inference based on variable names
281
+ if (varName.includes('path') || varName.includes('Path') ||
282
+ varName.includes('name') || varName.includes('Name') ||
283
+ varName.includes('descriptor') || varName.includes('Descriptor') ||
284
+ varName.includes('fileName') || varName.includes('handler') ||
285
+ varName.includes('url') || varName.includes('id') ||
286
+ varName.includes('uuid') || varName.includes('token')) {
287
+ return 'string'
288
+ } else if (varName.includes('count') || varName.includes('Count') ||
289
+ varName.includes('size') || varName.includes('Size') ||
290
+ varName.includes('length') || varName.includes('Length') ||
291
+ varName.includes('index') || varName.includes('Index')) {
292
+ return 'number'
293
+ } else if (varName.includes('is') || varName.includes('has') ||
294
+ varName.includes('can') || varName.includes('should') ||
295
+ varName.includes('enabled') || varName.includes('success')) {
296
+ return 'boolean'
297
+ } else if (varName.includes('config') || varName.includes('Config') ||
298
+ varName.includes('options') || varName.includes('Options') ||
299
+ varName.includes('data') || varName.includes('result') ||
300
+ varName.includes('response') || varName.includes('error')) {
301
+ return 'unknown'
302
+ }
303
+
304
+ return 'unknown'
305
+ }
306
+
307
+ // Clean up type strings (remove Promise wrappers for boundaries)
308
+ function cleanTypeString(typeString: string): string {
309
+ // Remove Promise wrapper for boundary functions
310
+ const promiseMatch = typeString.match(/Promise<(.+)>/)
311
+ if (promiseMatch) {
312
+ return promiseMatch[1]
313
+ }
314
+ return typeString
315
+ }
316
+
317
+ function analyzeSchemaArg(node: ts.Expression, sourceFile: ts.SourceFile): InputSchema {
318
+ // Handle variable references (e.g., when schema is defined as const schema = ...)
319
+ if (ts.isIdentifier(node) && node.text === 'schema') {
320
+ // This case is now handled by pre-finding the schema node
321
+ return { type: 'object', properties: {} }
322
+ }
323
+
324
+ // Handle direct Schema constructor calls
325
+ if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === 'Schema') {
326
+ const arg = node.arguments?.[0]
327
+ if (arg && ts.isObjectLiteralExpression(arg)) {
328
+ const properties: Record<string, SchemaProperty> = {}
329
+ arg.properties.forEach(prop => {
330
+ if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
331
+ const propName = prop.name.text
332
+ const propValue = analyzeSchemaProp(prop.initializer, sourceFile)
333
+ properties[propName] = propValue
334
+ }
335
+ })
336
+ return { type: 'object', properties }
337
+ }
338
+ }
339
+ return { type: 'object', properties: {} }
340
+ }
341
+
342
+ // Enhanced schema property analysis
343
+ function analyzeSchemaProp(node: ts.Expression, _sourceFile: ts.SourceFile): SchemaProperty {
344
+ // Analyze Schema.string(), Schema.number(), etc.
345
+ if (ts.isCallExpression(node)) {
346
+ if (ts.isPropertyAccessExpression(node.expression) &&
347
+ ts.isIdentifier(node.expression.expression) &&
348
+ node.expression.expression.text === 'Schema') {
349
+
350
+ const methodName = node.expression.name.text
351
+ let baseType: SchemaProperty = { type: getSchemaTypeFromMethod(methodName) }
352
+
353
+ // Check for chained methods like .optional() or .default()
354
+ let current = node
355
+ while (current.parent && ts.isCallExpression(current.parent)) {
356
+ current = current.parent
357
+ if (ts.isPropertyAccessExpression(current.expression)) {
358
+ const chainedMethod = current.expression.name.text
359
+ if (chainedMethod === 'optional') {
360
+ baseType = { ...baseType, optional: true }
361
+ } else if (chainedMethod === 'default' && current.arguments[0]) {
362
+ baseType = { ...baseType, default: current.arguments[0].getText() }
363
+ }
364
+ }
365
+ }
366
+
367
+ return baseType
368
+ }
369
+ }
370
+ return { type: 'unknown' }
371
+ }
372
+
373
+ function getSchemaTypeFromMethod(methodName: string): string {
374
+ const typeMap: Record<string, string> = {
375
+ string: 'string',
376
+ number: 'number',
377
+ boolean: 'boolean',
378
+ array: 'array',
379
+ object: 'object'
380
+ }
381
+ return typeMap[methodName] || 'unknown'
382
+ }
383
+
384
+ function analyzeBoundariesArg(node: ts.Expression, _sourceFile: ts.SourceFile): string[] {
385
+ const boundaries: string[] = []
386
+
387
+ // Handle variable references (e.g., when boundaries is defined as const boundaries = ...)
388
+ if (ts.isIdentifier(node) && node.text === 'boundaries') {
389
+ // This case is now handled by pre-finding the boundaries node
390
+ return []
391
+ }
392
+
393
+ if (ts.isObjectLiteralExpression(node)) {
394
+ node.properties.forEach(prop => {
395
+ if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
396
+ const boundaryName = prop.name.text
397
+ boundaries.push(boundaryName)
398
+ }
399
+ })
400
+ }
401
+
402
+ return boundaries
403
+ }
404
+
405
+ // Export the core analysis function for reuse
406
+ export function analyzeTaskFile(sourceCode: string, filePath: string, _expectedTaskName?: string): TaskFingerprintOutput | null {
407
+ const taskFingerprint = extractTaskFingerprints(sourceCode, filePath)[0]
408
+ if (!taskFingerprint) {
409
+ return null
410
+ }
411
+
412
+ // Return simplified output without name, location, hash
413
+ return {
414
+ description: taskFingerprint.description,
415
+ inputSchema: taskFingerprint.inputSchema,
416
+ outputType: taskFingerprint.outputType,
417
+ boundaries: taskFingerprint.boundaries
418
+ }
419
+ }
@@ -1,34 +0,0 @@
1
- import { TaskInstanceType, BaseFunction, Boundaries, ExecutionRecord, ReplayConfig } from '@forgehive/task';
2
- import { SchemaDescription } from '@forgehive/schema';
3
- /**
4
- * TaskAdapter wraps a TaskInstanceType to make it compatible with Runner
5
- * by handling boundary type issues
6
- */
7
- export declare class TaskAdapter<F extends BaseFunction, B extends Boundaries> {
8
- private task;
9
- constructor(task: TaskInstanceType<F, B>);
10
- get version(): string;
11
- getDescription(): string | undefined;
12
- describe(): SchemaDescription;
13
- run(argv?: Parameters<F>[0]): Promise<ReturnType<F>>;
14
- safeReplay(executionLog: ExecutionRecord<any, any, any>, config: ReplayConfig<any>): Promise<[ReturnType<F> | null, Error | null, ExecutionRecord<Parameters<F>[0], ReturnType<F>, B>]>;
15
- getMode(): import("@forgehive/task").Mode;
16
- setMode(mode: string): void;
17
- validate(argv?: any): any;
18
- isValid(argv?: any): boolean;
19
- addListener(fn: any): void;
20
- removeListener(): void;
21
- emit(data: any): void;
22
- asBoundary(): (args: Parameters<F>[0]) => Promise<ReturnType<F>>;
23
- getBoundaries(): import("@forgehive/task").WrappedBoundaries<B>;
24
- setBoundariesData(data: any): void;
25
- getBondariesData(): Record<string, unknown>;
26
- mockBoundary(name: any, mockFn: any): any;
27
- resetMock(name: any): any;
28
- resetMocks(): void;
29
- safeRun(argv?: Parameters<F>[0]): Promise<[ReturnType<F> | null, Error | null, ExecutionRecord<Parameters<F>[0], ReturnType<F>, B>]>;
30
- }
31
- /**
32
- * Helper function to adapt a task instance for Runner compatibility
33
- */
34
- export declare function adaptTask<F extends BaseFunction, B extends Boundaries>(task: TaskInstanceType<F, B>): TaskInstanceType;
@@ -1,85 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TaskAdapter = void 0;
4
- exports.adaptTask = adaptTask;
5
- /**
6
- * TaskAdapter wraps a TaskInstanceType to make it compatible with Runner
7
- * by handling boundary type issues
8
- */
9
- class TaskAdapter {
10
- constructor(task) {
11
- this.task = task;
12
- }
13
- // Forward all required methods to the underlying task
14
- get version() {
15
- return this.task.version;
16
- }
17
- getDescription() {
18
- return this.task.getDescription();
19
- }
20
- describe() {
21
- return this.task.describe();
22
- }
23
- async run(argv) {
24
- return this.task.run(argv);
25
- }
26
- // This is the problematic method with boundary type incompatibilities
27
- // Our implementation uses type assertions to make it compatible
28
- async safeReplay(executionLog, config) {
29
- // Type assertion to bridge the boundary type gap
30
- return this.task.safeReplay(executionLog, config);
31
- }
32
- // Forward other methods as needed
33
- getMode() {
34
- return this.task.getMode();
35
- }
36
- setMode(mode) {
37
- return this.task.setMode(mode);
38
- }
39
- validate(argv) {
40
- return this.task.validate(argv);
41
- }
42
- isValid(argv) {
43
- return this.task.isValid(argv);
44
- }
45
- addListener(fn) {
46
- return this.task.addListener(fn);
47
- }
48
- removeListener() {
49
- return this.task.removeListener();
50
- }
51
- emit(data) {
52
- return this.task.emit(data);
53
- }
54
- asBoundary() {
55
- return this.task.asBoundary();
56
- }
57
- getBoundaries() {
58
- return this.task.getBoundaries();
59
- }
60
- setBoundariesData(data) {
61
- return this.task.setBoundariesData(data);
62
- }
63
- getBondariesData() {
64
- return this.task.getBondariesData();
65
- }
66
- mockBoundary(name, mockFn) {
67
- return this.task.mockBoundary(name, mockFn);
68
- }
69
- resetMock(name) {
70
- return this.task.resetMock(name);
71
- }
72
- resetMocks() {
73
- return this.task.resetMocks();
74
- }
75
- async safeRun(argv) {
76
- return this.task.safeRun(argv);
77
- }
78
- }
79
- exports.TaskAdapter = TaskAdapter;
80
- /**
81
- * Helper function to adapt a task instance for Runner compatibility
82
- */
83
- function adaptTask(task) {
84
- return new TaskAdapter(task);
85
- }
@@ -1,23 +0,0 @@
1
- # Templates Directory
2
-
3
- This directory contains Handlebars templates used by the CLI to generate files.
4
-
5
- ## Templates
6
-
7
- - `task.hbs`: Template for generating new tasks
8
-
9
- ## Important Note
10
-
11
- These templates are copied to the `dist/templates` directory during the build process.
12
- This ensures that the templates are available when the CLI is installed and used in production.
13
-
14
- The build script in `package.json` includes a step to copy these templates:
15
-
16
- ```json
17
- "scripts": {
18
- "build": "tsc && npm run copy-templates",
19
- "copy-templates": "mkdir -p dist/templates && cp -r src/templates/* dist/templates/"
20
- }
21
- ```
22
-
23
- If you add new templates, make sure they are properly copied to the dist folder.
@@ -1,27 +0,0 @@
1
- // TASK: {{ taskName }}
2
- // Run this task with:
3
- // shadow-cli {{ taskDescriptor }}
4
-
5
- import { createTask } from '@shadow/task'
6
- import { Schema } from '@shadow/schema'
7
-
8
- const schema = new Schema({
9
- // Add your schema definitions here
10
- // example: myParam: Schema.string()
11
- })
12
-
13
- const boundaries = {
14
- // Add your boundary functions here
15
- // example: readFile: async (path: string) => fs.readFile(path, 'utf-8')
16
- }
17
-
18
- export const {{ taskName }} = createTask(
19
- schema,
20
- boundaries,
21
- async function (argv, boundaryFns) {
22
- // Your task implementation goes here
23
- const status = { status: 'Ok' }
24
-
25
- return status
26
- }
27
- )
@@ -1,2 +0,0 @@
1
- import { type WrappedBoundaryFunction } from '@forgehive/task';
2
- export declare const createBoundaryMock: () => WrappedBoundaryFunction;
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createBoundaryMock = void 0;
4
- const createBoundaryMock = () => {
5
- const mockFn = jest.fn().mockResolvedValue(undefined);
6
- const boundaryMock = mockFn;
7
- // Add required methods to satisfy the interface
8
- boundaryMock.getTape = jest.fn().mockReturnValue([]);
9
- boundaryMock.setTape = jest.fn();
10
- boundaryMock.getMode = jest.fn().mockReturnValue('proxy');
11
- boundaryMock.setMode = jest.fn();
12
- boundaryMock.startRun = jest.fn();
13
- boundaryMock.stopRun = jest.fn();
14
- boundaryMock.getRunData = jest.fn().mockReturnValue([]);
15
- return boundaryMock;
16
- };
17
- exports.createBoundaryMock = createBoundaryMock;
@@ -1,4 +0,0 @@
1
- {"name":"auth:list","type":"success","input":{},"output":{"status":"Ok","profiles":[{"name":"local","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:4000"},{"name":"localNext","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:3000"}],"default":"localNext"},"boundaries":{"loadProfiles":[{"input":[{}],"output":{"default":"localNext","profiles":[{"name":"local","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:4000"},{"name":"localNext","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:3000"}]}},{"input":[{}],"output":{"default":"localNext","profiles":[{"name":"local","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:4000"},{"name":"localNext","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:3000"}]}}]}}
2
- {"name":"auth:list","type":"success","input":{},"output":{"status":"Ok","default":"localNext"},"boundaries":{"loadProfiles":[{"input":[{}],"output":{"default":"localNext","profiles":[{"name":"local","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:4000"},{"name":"localNext","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:3000"}]}}]}}
3
- {"name":"auth:list","type":"success","input":{},"output":{"default":"localNext"},"boundaries":{"loadProfiles":[{"input":[{}],"output":{"default":"localNext","profiles":[{"name":"local","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:4000"},{"name":"localNext","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:3000"}]}}]}}
4
- {"name":"auth:list","type":"success","input":{},"output":{"default":"localNext"},"boundaries":{"loadProfiles":[{"input":[{}],"output":{"default":"localNext","profiles":[{"name":"local","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:4000"},{"name":"localNext","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:3000"}]}}]}}
@@ -1,2 +0,0 @@
1
- {"name":"auth:load","type":"error","input":{},"error":"ENOENT: no such file or directory, open '/Users/danielzavaladlvega/.forge/profiles.json'","boundaries":{"ensureBuildsFolder":[{"input":[],"output":"/Users/danielzavaladlvega/.forge"},{"input":[],"output":"/Users/danielzavaladlvega/.forge"}]}}
2
- {"name":"auth:load","type":"success","input":{},"output":{"profiles":[]},"boundaries":{"ensureBuildsFolder":[{"input":[],"output":"/Users/danielzavaladlvega/.forge"}]}}
@@ -1 +0,0 @@
1
- {"name":"auth:loadCurrent","type":"success","input":{},"output":{"name":"local","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:4000"},"boundaries":{"loadProfiles":[{"input":[{}],"output":{"default":"local","profiles":[{"name":"local","apiKey":"b4b5a766fcd7dc2d059e8f96a57c8edd","apiSecret":"2900246cb8bebcbeaadbe6348477592f42d62788d13fd4067588438bc11bf116","url":"http://localhost:4000"}]}}]}}
@@ -1,2 +0,0 @@
1
- {"name":"conf:info","type":"error","input":{},"error":"ENOENT: no such file or directory, open '/Users/package.json'","boundaries":{"readFile":[{"input":["/Users/package.json"],"error":"ENOENT: no such file or directory, open '/Users/package.json'"},{"input":["/Users/package.json"],"error":"ENOENT: no such file or directory, open '/Users/package.json'"}],"loadCurrentProfile":[]}}
2
- {"name":"conf:info","type":"error","input":{"name":"foobar"},"error":"ENOENT: no such file or directory, open '/Users/package.json'","boundaries":{"readFile":[{"input":["/Users/package.json"],"error":"ENOENT: no such file or directory, open '/Users/package.json'"}],"loadCurrentProfile":[]}}
@@ -1,4 +0,0 @@
1
- {"name":"runner:create","type":"success","input":{},"output":{"status":"Ok"},"boundaries":{}}
2
- {"name":"runner:create","type":"success","input":{"runnerName":"inventory"},"output":{},"boundaries":{"loadConf":[{"input":[{}],"output":{"project":{"name":"forge-cli"},"paths":{"logs":"logs/","tasks":"src/tasks/","runners":"src/runners/","fixtures":"src/tests/fixtures","tests":"src/tests/"},"infra":{"region":"us-west-2","bucket":""},"tasks":{"bundle:create":{"path":"src/tasks/bundle/create.ts","handler":"create"},"bundle:load":{"path":"src/tasks/bundle/load.ts","handler":"load"},"task:run":{"path":"src/tasks/task/run.ts","handler":"run"},"task:remove":{"path":"src/tasks/task/remove.ts","handler":"remove"},"conf:info":{"path":"src/tasks/conf/info.ts","handler":"info"},"runner:create":{"path":"src/tasks/runner/create.ts","handler":"create"}},"runners":{}}},{"input":[{}],"output":{"project":{"name":"forge-cli"},"paths":{"logs":"logs/","tasks":"src/tasks/","runners":"src/runners/","fixtures":"src/tests/fixtures","tests":"src/tests/"},"infra":{"region":"us-west-2","bucket":""},"tasks":{"bundle:create":{"path":"src/tasks/bundle/create.ts","handler":"create"},"bundle:load":{"path":"src/tasks/bundle/load.ts","handler":"load"},"task:run":{"path":"src/tasks/task/run.ts","handler":"run"},"task:remove":{"path":"src/tasks/task/remove.ts","handler":"remove"},"conf:info":{"path":"src/tasks/conf/info.ts","handler":"info"},"runner:create":{"path":"src/tasks/runner/create.ts","handler":"create"}},"runners":{}}}],"getCwd":[{"input":[],"output":"/Users/danielzavaladlvega/forgehive/mono/apps/cli"},{"input":[],"output":"/Users/danielzavaladlvega/forgehive/mono/apps/cli"}],"persistRunner":[],"persistConf":[]}}
3
- {"name":"runner:create","type":"success","input":{"runnerName":"inventory"},"output":{},"boundaries":{"loadConf":[{"input":[{}],"output":{"project":{"name":"forge-cli"},"paths":{"logs":"logs/","tasks":"src/tasks/","runners":"src/runners/","fixtures":"src/tests/fixtures","tests":"src/tests/"},"infra":{"region":"us-west-2","bucket":""},"tasks":{"bundle:create":{"path":"src/tasks/bundle/create.ts","handler":"create"},"bundle:load":{"path":"src/tasks/bundle/load.ts","handler":"load"},"task:run":{"path":"src/tasks/task/run.ts","handler":"run"},"task:remove":{"path":"src/tasks/task/remove.ts","handler":"remove"},"conf:info":{"path":"src/tasks/conf/info.ts","handler":"info"},"runner:create":{"path":"src/tasks/runner/create.ts","handler":"create"}},"runners":{}}}],"getCwd":[{"input":[],"output":"/Users/danielzavaladlvega/forgehive/mono/apps/cli"}],"persistRunner":[],"persistConf":[]}}
4
- {"name":"runner:create","type":"error","input":{},"error":"Invalid input on: runnerName: Required","boundaries":{"loadConf":[],"getCwd":[],"persistRunner":[],"persistConf":[]}}