@forgehive/forge-cli 0.3.5 → 0.3.7
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 +3 -0
- package/dist/tasks/bundle/fingerprint.d.ts +12 -2
- package/dist/tasks/bundle/fingerprint.js +26 -12
- package/dist/tasks/conf/info.d.ts +12 -1
- package/dist/tasks/conf/info.js +36 -12
- package/dist/tasks/init.js +1 -0
- package/dist/tasks/task/fingerprint.d.ts +51 -8
- package/dist/tasks/task/fingerprint.js +12 -35
- package/dist/tasks/task/publish.d.ts +60 -4
- package/dist/tasks/task/publish.js +30 -8
- package/dist/tasks/types.d.ts +1 -0
- package/dist/utils/taskAnalysis.d.ts +27 -1
- package/dist/utils/taskAnalysis.js +760 -107
- package/forge.json +1 -0
- package/logs/bundle:fingerprint.log +1 -0
- package/package.json +10 -10
- package/specs/fingerprint.md +324 -60
- package/src/runner.ts +4 -0
- package/src/tasks/bundle/fingerprint.ts +32 -13
- package/src/tasks/conf/info.ts +36 -10
- package/src/tasks/init.ts +1 -0
- package/src/tasks/task/fingerprint.ts +13 -42
- package/src/tasks/task/publish.ts +35 -10
- package/src/tasks/types.ts +1 -0
- package/src/utils/taskAnalysis.ts +833 -118
package/dist/runner.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
const
|
|
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(
|
|
36
|
+
await promises_1.default.access(fingerprintsPath);
|
|
38
37
|
}
|
|
39
38
|
catch {
|
|
40
|
-
await promises_1.default.mkdir(
|
|
39
|
+
await promises_1.default.mkdir(fingerprintsPath, { recursive: true });
|
|
41
40
|
}
|
|
42
|
-
return
|
|
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,
|
|
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
|
-
|
|
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
|
|
108
|
-
const outputFile = path_1.default.join(
|
|
109
|
-
const fingerprintsFile = path_1.default.join(
|
|
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
|
}>;
|
package/dist/tasks/conf/info.js
CHANGED
|
@@ -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
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
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
|
-
|
|
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
|
});
|
package/dist/tasks/init.js
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
//
|
|
59
|
-
const
|
|
60
|
-
|
|
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
|
|
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:
|
|
25
|
-
|
|
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:
|
|
51
|
-
|
|
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
|
|
55
|
-
|
|
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 {
|
package/dist/tasks/types.d.ts
CHANGED
|
@@ -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:
|
|
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 {};
|