@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/dist/runner.js CHANGED
@@ -115,9 +115,13 @@ runner.setHandler(async (data) => {
115
115
  });
116
116
  }
117
117
  else if (taskName === 'task:run') {
118
+ const { input, ...restArgs } = args;
119
+ // If --input is provided, parse it as JSON and use that
120
+ // Otherwise, use the regular arguments spread from minimist
121
+ const taskArgs = input ? JSON.parse(input) : restArgs;
118
122
  result = await task.run({
119
123
  descriptorName: action,
120
- args
124
+ args: taskArgs
121
125
  });
122
126
  }
123
127
  else if (taskName === 'fixture:download') {
@@ -144,6 +148,9 @@ runner.setHandler(async (data) => {
144
148
  }
145
149
  else {
146
150
  result = await task.run(args);
151
+ if (taskName === 'info') {
152
+ silent = true;
153
+ }
147
154
  }
148
155
  if (taskName === 'task:describe' || taskName === 'task:list') {
149
156
  silent = true;
@@ -7,9 +7,14 @@ export declare const fingerprint: import("@forgehive/task").TaskInstanceType<(ar
7
7
  loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
8
8
  readFile: (filePath: string) => Promise<string>;
9
9
  writeFile: (filePath: string, content: string) => Promise<void>;
10
- ensureForgeFolder: () => Promise<string>;
10
+ ensureFingerprintsFolder: (cwd: string, conf: {
11
+ paths?: {
12
+ fingerprints?: string;
13
+ };
14
+ }) => Promise<string>;
11
15
  }>) => Promise<{
12
16
  taskFingerprint: TaskFingerprintOutput;
17
+ fingerprintFile: string;
13
18
  outputFile?: undefined;
14
19
  fingerprintsFile?: undefined;
15
20
  taskFingerprints?: undefined;
@@ -27,10 +32,15 @@ export declare const fingerprint: import("@forgehive/task").TaskInstanceType<(ar
27
32
  }[];
28
33
  };
29
34
  taskFingerprint?: undefined;
35
+ fingerprintFile?: undefined;
30
36
  }>, {
31
37
  getCwd: () => Promise<string>;
32
38
  loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
33
39
  readFile: (filePath: string) => Promise<string>;
34
40
  writeFile: (filePath: string, content: string) => Promise<void>;
35
- ensureForgeFolder: () => Promise<string>;
41
+ ensureFingerprintsFolder: (cwd: string, conf: {
42
+ paths?: {
43
+ fingerprints?: string;
44
+ };
45
+ }) => Promise<string>;
36
46
  }>;
@@ -12,7 +12,6 @@ const schema_1 = require("@forgehive/schema");
12
12
  const esbuild_1 = __importDefault(require("esbuild"));
13
13
  const promises_1 = __importDefault(require("fs/promises"));
14
14
  const path_1 = __importDefault(require("path"));
15
- const os_1 = __importDefault(require("os"));
16
15
  const load_1 = require("../conf/load");
17
16
  const taskAnalysis_1 = require("../../utils/taskAnalysis");
18
17
  const description = 'Generate task bundle with comprehensive fingerprinting and type extraction';
@@ -31,15 +30,15 @@ const boundaries = {
31
30
  writeFile: async (filePath, content) => {
32
31
  return promises_1.default.writeFile(filePath, content);
33
32
  },
34
- ensureForgeFolder: async () => {
35
- const forgePath = path_1.default.join(os_1.default.homedir(), '.forge');
33
+ ensureFingerprintsFolder: async (cwd, conf) => {
34
+ const fingerprintsPath = path_1.default.join(cwd, conf.paths?.fingerprints || 'fingerprints/');
36
35
  try {
37
- await promises_1.default.access(forgePath);
36
+ await promises_1.default.access(fingerprintsPath);
38
37
  }
39
38
  catch {
40
- await promises_1.default.mkdir(forgePath, { recursive: true });
39
+ await promises_1.default.mkdir(fingerprintsPath, { recursive: true });
41
40
  }
42
- return forgePath;
41
+ return fingerprintsPath;
43
42
  }
44
43
  };
45
44
  // esbuild plugin for fingerprinting
@@ -66,6 +65,8 @@ function taskFingerprintPlugin() {
66
65
  inputSchema: taskFingerprint.inputSchema,
67
66
  outputType: taskFingerprint.outputType,
68
67
  boundaries: taskFingerprint.boundaries,
68
+ errors: taskFingerprint.errors,
69
+ analysisMetadata: taskFingerprint.analysisMetadata,
69
70
  hash: 'generated-hash'
70
71
  };
71
72
  fingerprints.push(fullFingerprint);
@@ -83,7 +84,7 @@ function taskFingerprintPlugin() {
83
84
  exports.fingerprint = (0, task_1.createTask)({
84
85
  schema,
85
86
  boundaries,
86
- fn: async function ({ descriptorName, filePath }, { getCwd, loadConf, readFile, writeFile, ensureForgeFolder }) {
87
+ fn: async function ({ descriptorName, filePath }, { getCwd, loadConf, readFile, writeFile, ensureFingerprintsFolder }) {
87
88
  // If filePath is provided, analyze that file directly and return JSON
88
89
  if (filePath) {
89
90
  console.log(`Analyzing task file: ${filePath}`);
@@ -92,9 +93,20 @@ exports.fingerprint = (0, task_1.createTask)({
92
93
  if (!fingerprintOutput) {
93
94
  throw new Error('Could not extract fingerprint from task file: ' + filePath);
94
95
  }
95
- return {
96
+ // Write fingerprint to file for consistency
97
+ const cwd = await getCwd();
98
+ const forgeJson = await loadConf({});
99
+ const fingerprintsPath = await ensureFingerprintsFolder(cwd, forgeJson);
100
+ const fingerprintFile = path_1.default.join(fingerprintsPath, `${descriptorName}.fingerprint.json`);
101
+ const analysis = {
96
102
  taskFingerprint: fingerprintOutput
97
103
  };
104
+ await writeFile(fingerprintFile, JSON.stringify(analysis, null, 2));
105
+ console.log(`Fingerprint saved to: ${fingerprintFile}`);
106
+ return {
107
+ taskFingerprint: fingerprintOutput,
108
+ fingerprintFile
109
+ };
98
110
  }
99
111
  // Original bundle logic when no filePath is provided
100
112
  const cwd = await getCwd();
@@ -104,9 +116,9 @@ exports.fingerprint = (0, task_1.createTask)({
104
116
  throw new Error(`Task "${descriptorName}" is not defined in forge.json`);
105
117
  }
106
118
  const entryPoint = path_1.default.join(cwd, taskDescriptor.path);
107
- const forgePath = await ensureForgeFolder();
108
- const outputFile = path_1.default.join(forgePath, `${descriptorName}.js`);
109
- const fingerprintsFile = path_1.default.join(forgePath, `${descriptorName}.fingerprints.json`);
119
+ const fingerprintsPath = await ensureFingerprintsFolder(cwd, forgeJson);
120
+ const outputFile = path_1.default.join(fingerprintsPath, `${descriptorName}.js`);
121
+ const fingerprintsFile = path_1.default.join(fingerprintsPath, `${descriptorName}.fingerprints.json`);
110
122
  console.log(`Generating bundle with fingerprints for task: ${descriptorName}`);
111
123
  console.log(`Entry point: ${entryPoint}`);
112
124
  console.log(`Output: ${outputFile}`);
@@ -128,7 +140,9 @@ exports.fingerprint = (0, task_1.createTask)({
128
140
  description: fp.description,
129
141
  inputSchema: fp.inputSchema,
130
142
  outputType: fp.outputType,
131
- boundaries: fp.boundaries
143
+ boundaries: fp.boundaries,
144
+ errors: fp.errors, // Preserve errors from analyzeTaskFile
145
+ analysisMetadata: fp.analysisMetadata // Preserve metadata from analyzeTaskFile
132
146
  }));
133
147
  // Create fingerprint result
134
148
  const fingerprintResult = {
@@ -1,10 +1,21 @@
1
1
  export declare const info: import("@forgehive/task").TaskInstanceType<(argv: {}, boundaries: import("@forgehive/task").WrappedBoundaries<{
2
2
  readFile: (filePath: string) => Promise<string>;
3
+ loadConfig: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
3
4
  loadCurrentProfile: (args: {}) => Promise<Promise<import("../types").Profile>>;
4
5
  }>) => Promise<{
5
6
  version: any;
6
- profile: {};
7
+ profile: {
8
+ name: string;
9
+ url: string;
10
+ apiKey: string;
11
+ } | null;
12
+ paths: {
13
+ logs: string;
14
+ fixtures: string;
15
+ fingerprints: string;
16
+ };
7
17
  }>, {
8
18
  readFile: (filePath: string) => Promise<string>;
19
+ loadConfig: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
9
20
  loadCurrentProfile: (args: {}) => Promise<Promise<import("../types").Profile>>;
10
21
  }>;
@@ -42,34 +42,58 @@ const schema_1 = require("@forgehive/schema");
42
42
  const fs = __importStar(require("fs"));
43
43
  const path = __importStar(require("path"));
44
44
  const loadCurrent_1 = require("../auth/loadCurrent");
45
+ const load_1 = require("../conf/load");
45
46
  const schema = new schema_1.Schema({});
46
47
  const boundaries = {
47
48
  readFile: async (filePath) => fs.promises.readFile(filePath, 'utf-8'),
49
+ loadConfig: load_1.load.asBoundary(),
48
50
  loadCurrentProfile: loadCurrent_1.loadCurrent.asBoundary()
49
51
  };
50
52
  exports.info = (0, task_1.createTask)({
51
53
  schema,
52
54
  boundaries,
53
- fn: async function (_argv, { loadCurrentProfile, readFile }) {
55
+ fn: async function (_argv, { loadCurrentProfile, loadConfig, readFile }) {
54
56
  const packageJsonPath = path.join(__dirname, '../../../package.json');
55
57
  const packageJsonContent = await readFile(packageJsonPath);
56
58
  const packageJson = JSON.parse(packageJsonContent);
57
- const info = {
58
- version: packageJson.version,
59
- profile: {}
60
- };
59
+ const config = await loadConfig({});
60
+ // Display human-friendly information
61
+ console.log('===============================================');
62
+ console.log('============ Forge CLI Information ============');
63
+ console.log();
64
+ console.log(`Version: ${packageJson.version}`);
65
+ console.log();
66
+ console.log('Configuration Paths:');
67
+ console.log(` Logs: ${config.paths.logs}`);
68
+ console.log(` Fixtures: ${config.paths.fixtures}`);
69
+ console.log(` Fingerprints: ${config.paths.fingerprints}`);
70
+ console.log();
61
71
  let profile;
62
72
  try {
63
73
  profile = await loadCurrentProfile({});
64
- info.profile = {
65
- name: profile.name,
66
- url: profile.url,
67
- apiKey: profile.apiKey
68
- };
74
+ console.log('Current Profile:');
75
+ console.log(` Name: ${profile.name}`);
76
+ console.log(` URL: ${profile.url}`);
77
+ console.log(` API Key: ${profile.apiKey}`);
69
78
  }
70
79
  catch (error) {
71
- console.log('No default profile set. Please run forge task:run auth:add to create a profile.');
80
+ console.log('Current Profile: No default profile set');
81
+ console.log(' Run "forge task:run auth:add" to create a profile.');
72
82
  }
73
- return info;
83
+ console.log();
84
+ console.log('===============================================');
85
+ return {
86
+ version: packageJson.version,
87
+ profile: profile ? {
88
+ name: profile.name,
89
+ url: profile.url,
90
+ apiKey: profile.apiKey
91
+ } : null,
92
+ paths: {
93
+ logs: config.paths.logs,
94
+ fixtures: config.paths.fixtures,
95
+ fingerprints: config.paths.fingerprints
96
+ }
97
+ };
74
98
  }
75
99
  });
@@ -35,6 +35,7 @@ exports.init = (0, task_1.createTask)({
35
35
  paths: {
36
36
  logs: 'logs/',
37
37
  fixtures: 'fixtures/',
38
+ fingerprints: 'fingerprints/',
38
39
  tasks: 'src/tasks/',
39
40
  runners: 'src/runners/',
40
41
  tests: 'src/tests/'
@@ -1,15 +1,36 @@
1
- import { TaskFingerprintOutput } from '../../utils/taskAnalysis';
2
1
  export declare const fingerprint: import("@forgehive/task").TaskInstanceType<(argv: {
3
2
  descriptorName: string;
4
3
  }, boundaries: import("@forgehive/task").WrappedBoundaries<{
5
4
  getCwd: () => Promise<string>;
6
5
  loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
7
- readFile: (filePath: string) => Promise<string>;
8
- writeFile: (filePath: string, content: string) => Promise<void>;
9
- ensureForgeFolder: () => Promise<string>;
6
+ bundleFingerprint: (args: {
7
+ descriptorName: string;
8
+ filePath?: string | undefined;
9
+ }) => Promise<Promise<{
10
+ taskFingerprint: import("../../utils/taskAnalysis").TaskFingerprintOutput;
11
+ fingerprintFile: string;
12
+ outputFile?: undefined;
13
+ fingerprintsFile?: undefined;
14
+ taskFingerprints?: undefined;
15
+ } | {
16
+ outputFile: string;
17
+ fingerprintsFile: string;
18
+ taskFingerprints: {
19
+ totalTasks: number;
20
+ tasks: {
21
+ name: string;
22
+ inputType: string;
23
+ outputType: string;
24
+ boundaryCount: number;
25
+ hash: string;
26
+ }[];
27
+ };
28
+ taskFingerprint?: undefined;
29
+ fingerprintFile?: undefined;
30
+ }>>;
10
31
  }>) => Promise<{
11
32
  taskName: string;
12
- fingerprint: TaskFingerprintOutput;
33
+ fingerprint: import("../../utils/taskAnalysis").TaskFingerprintOutput;
13
34
  fingerprintFile: string;
14
35
  analysis: {
15
36
  inputSchemaProps: string[];
@@ -20,7 +41,29 @@ export declare const fingerprint: import("@forgehive/task").TaskInstanceType<(ar
20
41
  }>, {
21
42
  getCwd: () => Promise<string>;
22
43
  loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
23
- readFile: (filePath: string) => Promise<string>;
24
- writeFile: (filePath: string, content: string) => Promise<void>;
25
- ensureForgeFolder: () => Promise<string>;
44
+ bundleFingerprint: (args: {
45
+ descriptorName: string;
46
+ filePath?: string | undefined;
47
+ }) => Promise<Promise<{
48
+ taskFingerprint: import("../../utils/taskAnalysis").TaskFingerprintOutput;
49
+ fingerprintFile: string;
50
+ outputFile?: undefined;
51
+ fingerprintsFile?: undefined;
52
+ taskFingerprints?: undefined;
53
+ } | {
54
+ outputFile: string;
55
+ fingerprintsFile: string;
56
+ taskFingerprints: {
57
+ totalTasks: number;
58
+ tasks: {
59
+ name: string;
60
+ inputType: string;
61
+ outputType: string;
62
+ boundaryCount: number;
63
+ hash: string;
64
+ }[];
65
+ };
66
+ taskFingerprint?: undefined;
67
+ fingerprintFile?: undefined;
68
+ }>>;
26
69
  }>;
@@ -9,11 +9,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.fingerprint = void 0;
10
10
  const task_1 = require("@forgehive/task");
11
11
  const schema_1 = require("@forgehive/schema");
12
- const promises_1 = __importDefault(require("fs/promises"));
13
12
  const path_1 = __importDefault(require("path"));
14
- const os_1 = __importDefault(require("os"));
15
13
  const load_1 = require("../conf/load");
16
- const taskAnalysis_1 = require("../../utils/taskAnalysis");
14
+ const fingerprint_1 = require("../bundle/fingerprint");
17
15
  const description = 'Analyze a specific task and generate detailed fingerprint without bundling';
18
16
  const schema = new schema_1.Schema({
19
17
  descriptorName: schema_1.Schema.string()
@@ -23,27 +21,12 @@ const boundaries = {
23
21
  return process.cwd();
24
22
  },
25
23
  loadConf: load_1.load.asBoundary(),
26
- readFile: async (filePath) => {
27
- return promises_1.default.readFile(filePath, 'utf-8');
28
- },
29
- writeFile: async (filePath, content) => {
30
- return promises_1.default.writeFile(filePath, content);
31
- },
32
- ensureForgeFolder: async () => {
33
- const forgePath = path_1.default.join(os_1.default.homedir(), '.forge');
34
- try {
35
- await promises_1.default.access(forgePath);
36
- }
37
- catch {
38
- await promises_1.default.mkdir(forgePath, { recursive: true });
39
- }
40
- return forgePath;
41
- }
24
+ bundleFingerprint: fingerprint_1.fingerprint.asBoundary()
42
25
  };
43
26
  exports.fingerprint = (0, task_1.createTask)({
44
27
  schema,
45
28
  boundaries,
46
- fn: async function ({ descriptorName }, { getCwd, loadConf, readFile, writeFile, ensureForgeFolder }) {
29
+ fn: async function ({ descriptorName }, { getCwd, loadConf, bundleFingerprint }) {
47
30
  const cwd = await getCwd();
48
31
  const forgeJson = await loadConf({});
49
32
  const taskDescriptor = forgeJson.tasks[descriptorName];
@@ -51,30 +34,24 @@ exports.fingerprint = (0, task_1.createTask)({
51
34
  throw new Error(`Task "${descriptorName}" is not defined in forge.json`);
52
35
  }
53
36
  const filePath = path_1.default.join(cwd, taskDescriptor.path);
54
- const forgePath = await ensureForgeFolder();
55
- const fingerprintFile = path_1.default.join(forgePath, `${descriptorName}.task-fingerprint.json`);
56
37
  console.log(`Analyzing task: ${descriptorName}`);
57
38
  console.log(`Task file: ${filePath}`);
58
- // Read and analyze the task file using the utility function
59
- const sourceCode = await readFile(filePath);
60
- const taskFingerprint = (0, taskAnalysis_1.analyzeTaskFile)(sourceCode, filePath);
39
+ // Use bundle:fingerprint with filePath to analyze the task file directly
40
+ const result = await bundleFingerprint({
41
+ descriptorName,
42
+ filePath
43
+ });
44
+ const taskFingerprint = result.taskFingerprint;
61
45
  if (!taskFingerprint) {
62
- throw new Error('Could not extract fingerprint from task file: ' + filePath);
46
+ throw new Error('Could not extract fingerprint from task file');
63
47
  }
64
- // Create analysis result - clean output without extra fields
65
- const analysis = {
66
- taskFingerprint
67
- };
68
- // Write fingerprint to file
69
- await writeFile(fingerprintFile, JSON.stringify(analysis, null, 2));
70
48
  console.log('Task fingerprint generated successfully');
71
49
  console.log(`Input properties: ${Object.keys(taskFingerprint.inputSchema.properties).join(', ')}`);
72
- console.log(`Boundaries: ${taskFingerprint.boundaries.join(', ')}`);
73
- console.log(`Fingerprint saved to: ${fingerprintFile}`);
50
+ console.log(`Boundaries: ${taskFingerprint.boundaries.map(b => b.name).join(', ')}`);
74
51
  return {
75
52
  taskName: descriptorName,
76
53
  fingerprint: taskFingerprint,
77
- fingerprintFile,
54
+ fingerprintFile: result.fingerprintFile,
78
55
  analysis: {
79
56
  inputSchemaProps: Object.keys(taskFingerprint.inputSchema.properties),
80
57
  boundaryCount: taskFingerprint.boundaries.length,
@@ -1,4 +1,5 @@
1
1
  import { Profile } from '../types';
2
+ import { TaskFingerprintOutput } from '../../utils/taskAnalysis';
2
3
  export declare const publish: import("@forgehive/task").TaskInstanceType<(argv: {
3
4
  descriptorName: string;
4
5
  }, boundaries: import("@forgehive/task").WrappedBoundaries<{
@@ -19,14 +20,42 @@ export declare const publish: import("@forgehive/task").TaskInstanceType<(argv:
19
20
  input: string;
20
21
  output: string;
21
22
  }) => Promise<Promise<unknown>>;
23
+ bundleFingerprint: (args: {
24
+ descriptorName: string;
25
+ filePath?: string | undefined;
26
+ }) => Promise<Promise<{
27
+ taskFingerprint: TaskFingerprintOutput;
28
+ fingerprintFile: string;
29
+ outputFile?: undefined;
30
+ fingerprintsFile?: undefined;
31
+ taskFingerprints?: undefined;
32
+ } | {
33
+ outputFile: string;
34
+ fingerprintsFile: string;
35
+ taskFingerprints: {
36
+ totalTasks: number;
37
+ tasks: {
38
+ name: string;
39
+ inputType: string;
40
+ outputType: string;
41
+ boundaryCount: number;
42
+ hash: string;
43
+ }[];
44
+ };
45
+ taskFingerprint?: undefined;
46
+ fingerprintFile?: undefined;
47
+ }>>;
22
48
  readFileUtf8: (filePath: string) => Promise<string>;
23
49
  readFileBinary: (filePath: string) => Promise<Buffer>;
24
- publishTask: (data: any, profile: Profile) => Promise<any>;
25
- uploadBundleWithPresignedUrl: (presignedUrl: string, bundleContent: Buffer) => Promise<any>;
50
+ publishTask: (data: Record<string, unknown>, profile: Profile) => Promise<{
51
+ bundleUploadUrl?: string;
52
+ }>;
53
+ uploadBundleWithPresignedUrl: (presignedUrl: string, bundleContent: Buffer) => Promise<boolean>;
26
54
  ensureBuildsFolder: () => Promise<string>;
27
55
  }>) => Promise<{
28
56
  descriptor: import("../types").TaskDescriptor;
29
57
  publish: boolean;
58
+ fingerprint: boolean;
30
59
  }>, {
31
60
  getCwd: () => Promise<string>;
32
61
  loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
@@ -45,9 +74,36 @@ export declare const publish: import("@forgehive/task").TaskInstanceType<(argv:
45
74
  input: string;
46
75
  output: string;
47
76
  }) => Promise<Promise<unknown>>;
77
+ bundleFingerprint: (args: {
78
+ descriptorName: string;
79
+ filePath?: string | undefined;
80
+ }) => Promise<Promise<{
81
+ taskFingerprint: TaskFingerprintOutput;
82
+ fingerprintFile: string;
83
+ outputFile?: undefined;
84
+ fingerprintsFile?: undefined;
85
+ taskFingerprints?: undefined;
86
+ } | {
87
+ outputFile: string;
88
+ fingerprintsFile: string;
89
+ taskFingerprints: {
90
+ totalTasks: number;
91
+ tasks: {
92
+ name: string;
93
+ inputType: string;
94
+ outputType: string;
95
+ boundaryCount: number;
96
+ hash: string;
97
+ }[];
98
+ };
99
+ taskFingerprint?: undefined;
100
+ fingerprintFile?: undefined;
101
+ }>>;
48
102
  readFileUtf8: (filePath: string) => Promise<string>;
49
103
  readFileBinary: (filePath: string) => Promise<Buffer>;
50
- publishTask: (data: any, profile: Profile) => Promise<any>;
51
- uploadBundleWithPresignedUrl: (presignedUrl: string, bundleContent: Buffer) => Promise<any>;
104
+ publishTask: (data: Record<string, unknown>, profile: Profile) => Promise<{
105
+ bundleUploadUrl?: string;
106
+ }>;
107
+ uploadBundleWithPresignedUrl: (presignedUrl: string, bundleContent: Buffer) => Promise<boolean>;
52
108
  ensureBuildsFolder: () => Promise<string>;
53
109
  }>;
@@ -17,6 +17,7 @@ const load_1 = require("../conf/load");
17
17
  const create_1 = require("../bundle/create");
18
18
  const load_2 = require("../bundle/load");
19
19
  const zip_1 = require("../bundle/zip");
20
+ const fingerprint_1 = require("../bundle/fingerprint");
20
21
  const loadCurrent_1 = require("../auth/loadCurrent");
21
22
  const schema = new schema_1.Schema({
22
23
  descriptorName: schema_1.Schema.string()
@@ -30,13 +31,13 @@ const boundaries = {
30
31
  bundleCreate: create_1.create.asBoundary(),
31
32
  bundleLoad: load_2.load.asBoundary(),
32
33
  bundleZip: zip_1.zip.asBoundary(),
34
+ bundleFingerprint: fingerprint_1.fingerprint.asBoundary(),
33
35
  readFileUtf8: async (filePath) => {
34
36
  return promises_1.default.readFile(filePath, 'utf-8');
35
37
  },
36
38
  readFileBinary: async (filePath) => {
37
39
  return promises_1.default.readFile(filePath);
38
40
  },
39
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
41
  publishTask: async (data, profile) => {
41
42
  const publishUrl = `${profile.url}/api/tasks/publish`;
42
43
  const authToken = `${profile.apiKey}:${profile.apiSecret}`;
@@ -48,16 +49,17 @@ const boundaries = {
48
49
  }
49
50
  });
50
51
  return response.data;
51
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
52
  }
53
53
  catch (error) {
54
- if (error.response?.data?.error.includes('Bundle size')) {
55
- throw new Error('Bundle size exceeds the maximum allowed size of 25MB');
54
+ if (error && typeof error === 'object' && 'response' in error) {
55
+ const axiosError = error;
56
+ if (axiosError.response?.data?.error?.includes('Bundle size')) {
57
+ throw new Error('Bundle size exceeds the maximum allowed size of 25MB');
58
+ }
56
59
  }
57
60
  throw new Error('Failed to publish task source code and metadata');
58
61
  }
59
62
  },
60
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
63
  uploadBundleWithPresignedUrl: async (presignedUrl, bundleContent) => {
62
64
  const response = await axios_1.default.put(presignedUrl, bundleContent, {
63
65
  headers: {
@@ -80,7 +82,7 @@ const boundaries = {
80
82
  exports.publish = (0, task_1.createTask)({
81
83
  schema,
82
84
  boundaries,
83
- fn: async function ({ descriptorName }, { getCwd, ensureBuildsFolder, loadConf, bundleCreate, bundleLoad, bundleZip, readFileUtf8, readFileBinary, publishTask, loadCurrentProfile, uploadBundleWithPresignedUrl }) {
85
+ fn: async function ({ descriptorName }, { getCwd, ensureBuildsFolder, loadConf, bundleCreate, bundleLoad, bundleZip, bundleFingerprint, readFileUtf8, readFileBinary, publishTask, loadCurrentProfile, uploadBundleWithPresignedUrl }) {
84
86
  const cwd = await getCwd();
85
87
  const forgeJson = await loadConf({});
86
88
  const profile = await loadCurrentProfile({});
@@ -106,6 +108,24 @@ exports.publish = (0, task_1.createTask)({
106
108
  output: zipFile
107
109
  });
108
110
  console.log('Bundle zipped...');
111
+ // Generate task fingerprint
112
+ console.log('Generating task fingerprint...');
113
+ let taskFingerprintData = null;
114
+ try {
115
+ const fingerprintResult = await bundleFingerprint({
116
+ descriptorName,
117
+ filePath: entryPoint
118
+ });
119
+ // Bundle fingerprint returns the fingerprint data directly
120
+ if (fingerprintResult.taskFingerprint) {
121
+ taskFingerprintData = fingerprintResult.taskFingerprint;
122
+ console.log('Task fingerprint generated successfully');
123
+ }
124
+ }
125
+ catch (error) {
126
+ console.warn('Failed to generate task fingerprint:', error instanceof Error ? error.message : String(error));
127
+ console.warn('Publishing without fingerprint data...');
128
+ }
109
129
  // Load the bundled task
110
130
  const bundle = await bundleLoad({
111
131
  bundlePath: outputFile
@@ -133,7 +153,8 @@ exports.publish = (0, task_1.createTask)({
133
153
  schemaDescriptor: JSON.stringify(schemaDescriptor),
134
154
  boundaries,
135
155
  sourceCode,
136
- bundleSize
156
+ bundleSize,
157
+ ...(taskFingerprintData && { fingerprint: taskFingerprintData })
137
158
  };
138
159
  // Publish metadata to hive api server
139
160
  console.log(`Publishing metadata and source code to ${profile.url}...`);
@@ -144,7 +165,8 @@ exports.publish = (0, task_1.createTask)({
144
165
  await uploadBundleWithPresignedUrl(publishResponse.bundleUploadUrl, bundleContent);
145
166
  return {
146
167
  descriptor: taskDescriptor,
147
- publish: true
168
+ publish: true,
169
+ fingerprint: taskFingerprintData !== null
148
170
  };
149
171
  }
150
172
  else {
@@ -24,6 +24,7 @@ export interface ForgeConf {
24
24
  tasks: string;
25
25
  runners: string;
26
26
  fixtures: string;
27
+ fingerprints: string;
27
28
  tests: string;
28
29
  };
29
30
  infra: Infra;
@@ -1,7 +1,9 @@
1
1
  interface SchemaProperty {
2
+ name?: string;
2
3
  type: string;
3
4
  optional?: boolean;
4
5
  default?: string;
6
+ properties?: Record<string, SchemaProperty>;
5
7
  }
6
8
  interface InputSchema {
7
9
  type: string;
@@ -10,12 +12,36 @@ interface InputSchema {
10
12
  interface OutputType {
11
13
  type: string;
12
14
  properties?: Record<string, SchemaProperty>;
15
+ elementType?: OutputType;
16
+ }
17
+ export interface FingerprintError {
18
+ type: 'parsing' | 'analysis' | 'boundary' | 'schema';
19
+ message: string;
20
+ location?: {
21
+ file: string;
22
+ line?: number;
23
+ column?: number;
24
+ };
25
+ details?: Record<string, unknown>;
26
+ }
27
+ interface BoundaryFingerprint {
28
+ name: string;
29
+ input: SchemaProperty[];
30
+ output: OutputType;
31
+ errors: FingerprintError[];
13
32
  }
14
33
  export interface TaskFingerprintOutput {
15
34
  description?: string;
16
35
  inputSchema: InputSchema;
17
36
  outputType: OutputType;
18
- boundaries: string[];
37
+ boundaries: BoundaryFingerprint[];
38
+ errors: FingerprintError[];
39
+ analysisMetadata: {
40
+ timestamp: string;
41
+ filePath: string;
42
+ success: boolean;
43
+ analysisVersion: string;
44
+ };
19
45
  }
20
46
  export declare function analyzeTaskFile(sourceCode: string, filePath: string, _expectedTaskName?: string): TaskFingerprintOutput | null;
21
47
  export {};