@forgehive/forge-cli 0.1.7 → 0.2.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 (51) hide show
  1. package/dist/runner.js +57 -2
  2. package/dist/tasks/auth/add.d.ts +16 -0
  3. package/dist/tasks/auth/add.js +50 -0
  4. package/dist/tasks/auth/list.d.ts +14 -0
  5. package/dist/tasks/auth/list.js +31 -0
  6. package/dist/tasks/auth/load.d.ts +6 -0
  7. package/dist/tasks/auth/load.js +44 -0
  8. package/dist/tasks/auth/loadCurrent.d.ts +6 -0
  9. package/dist/tasks/auth/loadCurrent.js +24 -0
  10. package/dist/tasks/auth/remove.d.ts +13 -0
  11. package/dist/tasks/auth/remove.js +56 -0
  12. package/dist/tasks/auth/switch.d.ts +12 -0
  13. package/dist/tasks/auth/switch.js +43 -0
  14. package/dist/tasks/conf/info.d.ts +7 -0
  15. package/dist/tasks/conf/info.js +13 -8
  16. package/dist/tasks/runner/bundle.d.ts +18 -0
  17. package/dist/tasks/runner/bundle.js +71 -0
  18. package/dist/tasks/runner/create.d.ts +21 -0
  19. package/dist/tasks/runner/create.js +97 -0
  20. package/dist/tasks/runner/remove.d.ts +18 -0
  21. package/dist/tasks/runner/remove.js +58 -0
  22. package/dist/tasks/task/createTask.js +4 -0
  23. package/dist/tasks/task/download.d.ts +58 -0
  24. package/dist/tasks/task/download.js +153 -0
  25. package/dist/tasks/task/publish.d.ts +41 -0
  26. package/dist/tasks/task/publish.js +106 -0
  27. package/dist/tasks/types.d.ts +10 -0
  28. package/dist/test/tasks/create.test.js +4 -0
  29. package/forge.json +44 -0
  30. package/logs/auth:list.log +4 -0
  31. package/logs/auth:load.log +2 -0
  32. package/logs/auth:loadCurrent.log +1 -0
  33. package/logs/conf:info.log +1 -2
  34. package/logs/runner:create.log +3 -0
  35. package/package.json +3 -2
  36. package/src/runner.ts +60 -2
  37. package/src/tasks/auth/add.ts +57 -0
  38. package/src/tasks/auth/list.ts +43 -0
  39. package/src/tasks/auth/load.ts +51 -0
  40. package/src/tasks/auth/loadCurrent.ts +35 -0
  41. package/src/tasks/auth/remove.ts +66 -0
  42. package/src/tasks/auth/switch.ts +53 -0
  43. package/src/tasks/conf/info.ts +16 -8
  44. package/src/tasks/runner/bundle.ts +79 -0
  45. package/src/tasks/runner/create.ts +121 -0
  46. package/src/tasks/runner/remove.ts +74 -0
  47. package/src/tasks/task/createTask.ts +4 -0
  48. package/src/tasks/task/download.ts +192 -0
  49. package/src/tasks/task/publish.ts +135 -0
  50. package/src/tasks/types.ts +12 -0
  51. package/src/test/tasks/create.test.ts +4 -0
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ // TASK: create
3
+ // Run this task with:
4
+ // forge task:run runner:create --runnerName <runner-name>
5
+ // forge task:run runner:create --runnerName inventory
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.create = void 0;
11
+ const task_1 = require("@forgehive/task");
12
+ const schema_1 = require("@forgehive/schema");
13
+ const handlebars_1 = __importDefault(require("handlebars"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const promises_1 = __importDefault(require("fs/promises"));
16
+ const camelCase_1 = require("../../utils/camelCase");
17
+ const load_1 = require("../conf/load");
18
+ // Define the template content directly in the code
19
+ const RUNNER_TEMPLATE = `// RUNNER: {{ runnerName }}
20
+ import { Runner } from '@forgehive/runner'
21
+
22
+ // Import your tasks here
23
+ // import { EXAMPLE_TASK } from '../../tasks/MODULE/TASK'
24
+
25
+ const {{ runnerName }}Runner = new Runner()
26
+
27
+ // Load your tasks here
28
+ // runner.load('MODULE:TASK', EXAMPLE_TASK)
29
+
30
+ export { {{ runnerName }}Runner }
31
+ `;
32
+ const schema = new schema_1.Schema({
33
+ runnerName: schema_1.Schema.string()
34
+ });
35
+ const boundaries = {
36
+ // Load boundaries
37
+ loadConf: load_1.load.asBoundary(),
38
+ getCwd: async () => {
39
+ return process.cwd();
40
+ },
41
+ // Persist boundaries
42
+ persistRunner: async (runnerPath, runnerName, content) => {
43
+ const folderPath = path_1.default.join(runnerPath, runnerName);
44
+ const filePath = path_1.default.join(folderPath, 'index.ts');
45
+ let err;
46
+ try {
47
+ await promises_1.default.stat(folderPath);
48
+ }
49
+ catch (e) {
50
+ err = e;
51
+ }
52
+ if (err === undefined) {
53
+ throw new Error(`Runner folder '${folderPath}' already exists.`);
54
+ }
55
+ await promises_1.default.mkdir(folderPath, { recursive: true });
56
+ await promises_1.default.writeFile(filePath, content, 'utf-8');
57
+ return {
58
+ path: filePath.toString()
59
+ };
60
+ },
61
+ persistConf: async (forge, cwd) => {
62
+ const forgePath = path_1.default.join(cwd, 'forge.json');
63
+ await promises_1.default.writeFile(forgePath, JSON.stringify(forge, null, 2));
64
+ }
65
+ };
66
+ exports.create = (0, task_1.createTask)(schema, boundaries, async function ({ runnerName }, { persistRunner, loadConf, persistConf, getCwd }) {
67
+ const formattedName = (0, camelCase_1.camelCase)(runnerName);
68
+ const cwd = await getCwd();
69
+ const forge = await loadConf({});
70
+ const runnerPath = forge.paths.runners;
71
+ console.log(`
72
+ ==================================================
73
+ Starting runner creation!
74
+ Creating runner: ${formattedName}
75
+ Into: ${runnerPath}${formattedName}/index.ts
76
+ ==================================================
77
+ `);
78
+ const comp = handlebars_1.default.compile(RUNNER_TEMPLATE);
79
+ const content = comp({
80
+ runnerName: formattedName
81
+ });
82
+ await persistRunner(runnerPath, formattedName, content);
83
+ if (forge.runners === undefined) {
84
+ forge.runners = {};
85
+ }
86
+ // Create runner descriptor
87
+ const runnerDescriptor = {
88
+ path: `${runnerPath}${formattedName}/index.ts`,
89
+ version: '0.0.1'
90
+ };
91
+ forge.runners[formattedName] = runnerDescriptor;
92
+ await persistConf(forge, cwd);
93
+ return {
94
+ runnerPath: `${runnerPath}/${formattedName}`,
95
+ runnerName: formattedName
96
+ };
97
+ });
@@ -0,0 +1,18 @@
1
+ import { type ForgeConf } from '../types';
2
+ export declare const remove: import("@forgehive/task").TaskInstanceType<(argv: {
3
+ runnerName: string;
4
+ }, boundaries: import("@forgehive/task").WrappedBoundaries<{
5
+ loadConf: (args: {}) => Promise<Promise<ForgeConf>>;
6
+ getCwd: () => Promise<string>;
7
+ removeRunner: (runnerPath: string) => Promise<void>;
8
+ persistConf: (forge: ForgeConf, cwd: string) => Promise<void>;
9
+ }>) => Promise<{
10
+ status: string;
11
+ message: string;
12
+ runnerName: string;
13
+ }>, {
14
+ loadConf: (args: {}) => Promise<Promise<ForgeConf>>;
15
+ getCwd: () => Promise<string>;
16
+ removeRunner: (runnerPath: string) => Promise<void>;
17
+ persistConf: (forge: ForgeConf, cwd: string) => Promise<void>;
18
+ }>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ // TASK: remove
3
+ // Run this task with:
4
+ // forge task:run runner:remove --runnerName <runner-name>
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.remove = void 0;
10
+ const task_1 = require("@forgehive/task");
11
+ const schema_1 = require("@forgehive/schema");
12
+ const path_1 = __importDefault(require("path"));
13
+ const promises_1 = __importDefault(require("fs/promises"));
14
+ const camelCase_1 = require("../../utils/camelCase");
15
+ const load_1 = require("../conf/load");
16
+ const schema = new schema_1.Schema({
17
+ runnerName: schema_1.Schema.string()
18
+ });
19
+ const boundaries = {
20
+ // Load boundaries
21
+ loadConf: load_1.load.asBoundary(),
22
+ getCwd: async () => {
23
+ return process.cwd();
24
+ },
25
+ // File system operations
26
+ removeRunner: async (runnerPath) => {
27
+ await promises_1.default.rm(runnerPath, { recursive: true, force: true });
28
+ },
29
+ // Configuration operations
30
+ persistConf: async (forge, cwd) => {
31
+ const forgePath = path_1.default.join(cwd, 'forge.json');
32
+ await promises_1.default.writeFile(forgePath, JSON.stringify(forge, null, 2));
33
+ }
34
+ };
35
+ exports.remove = (0, task_1.createTask)(schema, boundaries, async function ({ runnerName }, { loadConf, getCwd, removeRunner, persistConf }) {
36
+ const formattedName = (0, camelCase_1.camelCase)(runnerName);
37
+ const cwd = await getCwd();
38
+ const forge = await loadConf({});
39
+ if (!forge.runners || !forge.runners[formattedName]) {
40
+ throw new Error(`Runner '${formattedName}' not found in forge.json configuration`);
41
+ }
42
+ const runnerConfig = forge.runners[formattedName];
43
+ const runnerFolder = path_1.default.join(cwd, path_1.default.dirname(runnerConfig.path));
44
+ console.log(`
45
+ ==================================================
46
+ Removing runner: ${formattedName}
47
+ Path: ${runnerFolder}
48
+ ==================================================
49
+ `);
50
+ await removeRunner(runnerFolder);
51
+ delete forge.runners[formattedName];
52
+ await persistConf(forge, cwd);
53
+ return {
54
+ status: 'success',
55
+ message: `Runner '${formattedName}' successfully removed`,
56
+ runnerName: formattedName
57
+ };
58
+ });
@@ -20,6 +20,8 @@ const TASK_TEMPLATE = `// TASK: {{ taskName }}
20
20
  import { createTask } from '@forgehive/task'
21
21
  import { Schema } from '@forgehive/schema'
22
22
 
23
+ const description = 'Add task description here'
24
+
23
25
  const schema = new Schema({
24
26
  // Add your schema definitions here
25
27
  // example: myParam: Schema.string()
@@ -42,6 +44,8 @@ export const {{ taskName }} = createTask(
42
44
  return status
43
45
  }
44
46
  )
47
+
48
+ {{ taskName }}.setDescription(description)
45
49
  `;
46
50
  const schema = new schema_1.Schema({
47
51
  descriptorName: schema_1.Schema.string()
@@ -0,0 +1,58 @@
1
+ import { Profile, type ForgeConf } from '../types';
2
+ export declare const download: import("@forgehive/task").TaskInstanceType<(argv: {
3
+ descriptorName: string;
4
+ uuid: string;
5
+ }, boundaries: import("@forgehive/task").WrappedBoundaries<{
6
+ loadCurrentProfile: (args: {}) => Promise<Promise<Profile>>;
7
+ downloadTask: (uuid: string, profile: Profile) => Promise<any>;
8
+ loadConf: (args: {}) => Promise<Promise<ForgeConf>>;
9
+ getCwd: () => Promise<string>;
10
+ parseTaskName: (taskDescriptor: string) => Promise<{
11
+ descriptor: string;
12
+ taskName: string;
13
+ fileName: string;
14
+ dir?: string;
15
+ }>;
16
+ persistTask: (dir: string, fileName: string, content: string, cwd: string) => Promise<{
17
+ path: string;
18
+ }>;
19
+ persistConf: (forge: ForgeConf, cwd: string) => Promise<void>;
20
+ checkTaskExists: (dir: string, fileName: string) => Promise<boolean>;
21
+ }>) => Promise<{
22
+ error: string;
23
+ taskPath: string;
24
+ descriptor: string;
25
+ message?: undefined;
26
+ fileName?: undefined;
27
+ handler?: undefined;
28
+ } | {
29
+ error: string;
30
+ message: string;
31
+ taskPath: string;
32
+ descriptor: string;
33
+ fileName?: undefined;
34
+ handler?: undefined;
35
+ } | {
36
+ taskPath: string;
37
+ fileName: string;
38
+ descriptor: string;
39
+ handler: any;
40
+ error?: undefined;
41
+ message?: undefined;
42
+ }>, {
43
+ loadCurrentProfile: (args: {}) => Promise<Promise<Profile>>;
44
+ downloadTask: (uuid: string, profile: Profile) => Promise<any>;
45
+ loadConf: (args: {}) => Promise<Promise<ForgeConf>>;
46
+ getCwd: () => Promise<string>;
47
+ parseTaskName: (taskDescriptor: string) => Promise<{
48
+ descriptor: string;
49
+ taskName: string;
50
+ fileName: string;
51
+ dir?: string;
52
+ }>;
53
+ persistTask: (dir: string, fileName: string, content: string, cwd: string) => Promise<{
54
+ path: string;
55
+ }>;
56
+ persistConf: (forge: ForgeConf, cwd: string) => Promise<void>;
57
+ checkTaskExists: (dir: string, fileName: string) => Promise<boolean>;
58
+ }>;
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ // TASK: download
3
+ // Run this task with:
4
+ // forge task:run task:download --descriptorName [name] --uuid [task-uuid]
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.download = void 0;
10
+ const task_1 = require("@forgehive/task");
11
+ const schema_1 = require("@forgehive/schema");
12
+ const axios_1 = __importDefault(require("axios"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const promises_1 = __importDefault(require("fs/promises"));
15
+ const camelCase_1 = require("../../utils/camelCase");
16
+ const load_1 = require("../conf/load");
17
+ const loadCurrent_1 = require("../auth/loadCurrent");
18
+ const schema = new schema_1.Schema({
19
+ descriptorName: schema_1.Schema.string(),
20
+ uuid: schema_1.Schema.string()
21
+ });
22
+ const boundaries = {
23
+ loadCurrentProfile: loadCurrent_1.loadCurrent.asBoundary(),
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ downloadTask: async (uuid, profile) => {
26
+ const downloadUrl = `${profile.url}/api/tasks/download`;
27
+ console.log(`Downloading task from ${downloadUrl}...`);
28
+ const authToken = `${profile.apiKey}:${profile.apiSecret}`;
29
+ const response = await axios_1.default.post(downloadUrl, { uuid }, {
30
+ headers: {
31
+ Authorization: `Bearer ${authToken}`,
32
+ 'Content-Type': 'application/json'
33
+ }
34
+ });
35
+ return response.data;
36
+ },
37
+ loadConf: load_1.load.asBoundary(),
38
+ getCwd: async () => {
39
+ return process.cwd();
40
+ },
41
+ parseTaskName: async (taskDescriptor) => {
42
+ const res = taskDescriptor.split(':');
43
+ if (res.length === 1) {
44
+ return {
45
+ descriptor: `${(0, camelCase_1.camelCase)(res[0])}`,
46
+ taskName: `${(0, camelCase_1.camelCase)(res[0])}`,
47
+ fileName: `${(0, camelCase_1.camelCase)(res[0])}.ts`
48
+ };
49
+ }
50
+ return {
51
+ dir: res[0],
52
+ descriptor: `${res[0]}:${(0, camelCase_1.camelCase)(res[1])}`,
53
+ taskName: `${(0, camelCase_1.camelCase)(res[1])}`,
54
+ fileName: `${(0, camelCase_1.camelCase)(res[1])}.ts`
55
+ };
56
+ },
57
+ persistTask: async (dir, fileName, content, cwd) => {
58
+ const dirPath = path_1.default.resolve(cwd, dir);
59
+ const taskPath = path_1.default.resolve(dirPath, fileName);
60
+ await promises_1.default.mkdir(dirPath, { recursive: true });
61
+ await promises_1.default.writeFile(taskPath, content, 'utf-8');
62
+ return {
63
+ path: taskPath.toString()
64
+ };
65
+ },
66
+ persistConf: async (forge, cwd) => {
67
+ const forgePath = path_1.default.join(cwd, 'forge.json');
68
+ await promises_1.default.writeFile(forgePath, JSON.stringify(forge, null, 2));
69
+ },
70
+ checkTaskExists: async (dir, fileName) => {
71
+ const taskPath = path_1.default.resolve(dir, fileName);
72
+ try {
73
+ await promises_1.default.access(taskPath);
74
+ return true;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ };
81
+ exports.download = (0, task_1.createTask)(schema, boundaries, async function ({ descriptorName, uuid }, { downloadTask, getCwd, parseTaskName, persistTask, loadConf, persistConf, checkTaskExists, loadCurrentProfile }) {
82
+ console.log(`Attempting to download task with descriptor: ${descriptorName} and uuid: ${uuid}`);
83
+ // Parse descriptor name to get task details
84
+ const { taskName, fileName, descriptor, dir } = await parseTaskName(descriptorName);
85
+ const profile = await loadCurrentProfile({});
86
+ const cwd = await getCwd();
87
+ const forge = await loadConf({});
88
+ let taskPath = forge.paths.tasks;
89
+ if (dir !== undefined) {
90
+ taskPath = path_1.default.join(taskPath, dir);
91
+ }
92
+ // Check if task already exists
93
+ const taskExists = await checkTaskExists(taskPath, fileName);
94
+ if (taskExists) {
95
+ console.log(`Task ${descriptor} already exists at ${taskPath}/${fileName}`);
96
+ return {
97
+ error: 'Task already exists',
98
+ taskPath: `${taskPath}/${fileName}`,
99
+ descriptor
100
+ };
101
+ }
102
+ // Download from hive api server
103
+ let response;
104
+ try {
105
+ response = await downloadTask(uuid, profile);
106
+ }
107
+ catch (e) {
108
+ const error = e;
109
+ console.error('Error downloading task:', error.message, error.status);
110
+ if (error.status === 404) {
111
+ return {
112
+ error: 'Task not found',
113
+ taskPath: `${taskPath}/${fileName}`,
114
+ descriptor
115
+ };
116
+ }
117
+ return {
118
+ error: 'Failed to download task',
119
+ message: error.message,
120
+ taskPath: `${taskPath}/${fileName}`,
121
+ descriptor
122
+ };
123
+ }
124
+ console.log(`
125
+ ==================================================
126
+ Starting task download!
127
+ Creating: ${taskName}
128
+ Dir: ${dir ?? ''}
129
+ Into: ${taskPath}
130
+ ==================================================
131
+ `);
132
+ console.log('Writing task file:', taskPath, fileName);
133
+ console.log('Handler:', response.handler);
134
+ console.log('Source code:', response.sourceCode);
135
+ // Persist task with cwd
136
+ await persistTask(taskPath, fileName, response.sourceCode, cwd);
137
+ // Update forge.json with the new task
138
+ if (forge.tasks === undefined) {
139
+ forge.tasks = {};
140
+ }
141
+ forge.tasks[descriptor] = {
142
+ path: `${taskPath}/${fileName}`,
143
+ handler: response.handler
144
+ };
145
+ console.log('Forge:', forge);
146
+ await persistConf(forge, cwd);
147
+ return {
148
+ taskPath,
149
+ fileName,
150
+ descriptor,
151
+ handler: response.handler
152
+ };
153
+ });
@@ -0,0 +1,41 @@
1
+ import { Profile } from '../types';
2
+ export declare const publish: import("@forgehive/task").TaskInstanceType<(argv: {
3
+ descriptorName: string;
4
+ }, boundaries: import("@forgehive/task").WrappedBoundaries<{
5
+ getCwd: () => Promise<string>;
6
+ loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
7
+ loadCurrentProfile: (args: {}) => Promise<Promise<Profile>>;
8
+ bundleCreate: (args: {
9
+ entryPoint: string;
10
+ outputFile: string;
11
+ }) => Promise<Promise<{
12
+ outputFile: string;
13
+ }>>;
14
+ bundleLoad: (args: {
15
+ bundlePath: string;
16
+ }) => Promise<Promise<any>>;
17
+ readFileUtf8: (filePath: string) => Promise<string>;
18
+ readFileBinary: (filePath: string) => Promise<Buffer>;
19
+ publishTask: (data: any, profile: Profile) => Promise<any>;
20
+ ensureBuildsFolder: () => Promise<string>;
21
+ }>) => Promise<{
22
+ descriptor: import("../types").TaskDescriptor;
23
+ publishResponse: any;
24
+ }>, {
25
+ getCwd: () => Promise<string>;
26
+ loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
27
+ loadCurrentProfile: (args: {}) => Promise<Promise<Profile>>;
28
+ bundleCreate: (args: {
29
+ entryPoint: string;
30
+ outputFile: string;
31
+ }) => Promise<Promise<{
32
+ outputFile: string;
33
+ }>>;
34
+ bundleLoad: (args: {
35
+ bundlePath: string;
36
+ }) => Promise<Promise<any>>;
37
+ readFileUtf8: (filePath: string) => Promise<string>;
38
+ readFileBinary: (filePath: string) => Promise<Buffer>;
39
+ publishTask: (data: any, profile: Profile) => Promise<any>;
40
+ ensureBuildsFolder: () => Promise<string>;
41
+ }>;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ // TASK: publish
3
+ // Run this task with:
4
+ // forge task:run task:publish --descriptorMame task-name
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.publish = void 0;
10
+ const task_1 = require("@forgehive/task");
11
+ const schema_1 = require("@forgehive/schema");
12
+ const axios_1 = __importDefault(require("axios"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const promises_1 = __importDefault(require("fs/promises"));
15
+ const os_1 = __importDefault(require("os"));
16
+ const load_1 = require("../conf/load");
17
+ const create_1 = require("../bundle/create");
18
+ const load_2 = require("../bundle/load");
19
+ const loadCurrent_1 = require("../auth/loadCurrent");
20
+ const schema = new schema_1.Schema({
21
+ descriptorName: schema_1.Schema.string()
22
+ });
23
+ const boundaries = {
24
+ getCwd: async () => {
25
+ return process.cwd();
26
+ },
27
+ loadConf: load_1.load.asBoundary(),
28
+ loadCurrentProfile: loadCurrent_1.loadCurrent.asBoundary(),
29
+ bundleCreate: create_1.create.asBoundary(),
30
+ bundleLoad: load_2.load.asBoundary(),
31
+ readFileUtf8: async (filePath) => {
32
+ return promises_1.default.readFile(filePath, 'utf-8');
33
+ },
34
+ readFileBinary: async (filePath) => {
35
+ return promises_1.default.readFile(filePath);
36
+ },
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ publishTask: async (data, profile) => {
39
+ const publishUrl = `${profile.url}/api/tasks/publish`;
40
+ console.log(`Publishing task to ${publishUrl}...`);
41
+ const authToken = `${profile.apiKey}:${profile.apiSecret}`;
42
+ const response = await axios_1.default.post(publishUrl, data, {
43
+ headers: {
44
+ Authorization: `Bearer ${authToken}`,
45
+ 'Content-Type': 'application/json'
46
+ }
47
+ });
48
+ return response.data;
49
+ },
50
+ ensureBuildsFolder: async () => {
51
+ const buildsPath = path_1.default.join(os_1.default.homedir(), '.forge', 'builds');
52
+ try {
53
+ await promises_1.default.access(buildsPath);
54
+ }
55
+ catch {
56
+ await promises_1.default.mkdir(buildsPath, { recursive: true });
57
+ }
58
+ return buildsPath;
59
+ }
60
+ };
61
+ exports.publish = (0, task_1.createTask)(schema, boundaries, async function ({ descriptorName }, { getCwd, ensureBuildsFolder, loadConf, bundleCreate, bundleLoad, readFileUtf8, readFileBinary, publishTask, loadCurrentProfile }) {
62
+ const cwd = await getCwd();
63
+ const forgeJson = await loadConf({});
64
+ const profile = await loadCurrentProfile({});
65
+ const taskDescriptor = forgeJson.tasks[descriptorName];
66
+ const projectName = forgeJson.project.name;
67
+ if (taskDescriptor === undefined) {
68
+ throw new Error('Task is not defined on forge.json');
69
+ }
70
+ const entryPoint = path_1.default.join(cwd, taskDescriptor.path);
71
+ const buildsPath = await ensureBuildsFolder();
72
+ const outputFile = path_1.default.join(buildsPath, `${descriptorName}.js`);
73
+ console.log('entryPoint:', entryPoint);
74
+ console.log('buildsPath:', buildsPath);
75
+ console.log('outputFile:', outputFile);
76
+ // Bundle the task
77
+ await bundleCreate({
78
+ entryPoint,
79
+ outputFile
80
+ });
81
+ // Load the bundled task
82
+ const bundle = await bundleLoad({
83
+ bundlePath: outputFile
84
+ });
85
+ // Get the task handler
86
+ const task = bundle[taskDescriptor.handler];
87
+ const description = task.getDescription() ?? '';
88
+ const schema = task.getSchema() || new schema_1.Schema({});
89
+ const schemaDescriptor = schema.describe();
90
+ // Read the task file content and bundle
91
+ const sourceCode = await readFileUtf8(entryPoint);
92
+ const bundleContent = await readFileBinary(outputFile);
93
+ const data = {
94
+ ...taskDescriptor,
95
+ taskName: descriptorName,
96
+ projectName,
97
+ description,
98
+ schemaDescriptor: JSON.stringify(schemaDescriptor),
99
+ sourceCode,
100
+ bundle: bundleContent.toString('base64')
101
+ };
102
+ // Publish to hive api server
103
+ const response = await publishTask(data, profile);
104
+ console.log('Publish response:', response);
105
+ return { descriptor: taskDescriptor, publishResponse: response };
106
+ });
@@ -35,3 +35,13 @@ export interface TaskName {
35
35
  fileName: string;
36
36
  dir?: string;
37
37
  }
38
+ export interface Profile {
39
+ name: string;
40
+ apiKey: string;
41
+ apiSecret: string;
42
+ url: string;
43
+ }
44
+ export interface Profiles {
45
+ default: string;
46
+ profiles: Profile[];
47
+ }
@@ -15,6 +15,8 @@ const expectedContent = `// TASK: newTask
15
15
  import { createTask } from '@forgehive/task'
16
16
  import { Schema } from '@forgehive/schema'
17
17
 
18
+ const description = 'Add task description here'
19
+
18
20
  const schema = new Schema({
19
21
  // Add your schema definitions here
20
22
  // example: myParam: Schema.string()
@@ -37,6 +39,8 @@ export const newTask = createTask(
37
39
  return status
38
40
  }
39
41
  )
42
+
43
+ newTask.setDescription(description)
40
44
  `;
41
45
  describe('Create task', () => {
42
46
  let volume;
package/forge.json CHANGED
@@ -33,6 +33,50 @@
33
33
  "conf:info": {
34
34
  "path": "src/tasks/conf/info.ts",
35
35
  "handler": "info"
36
+ },
37
+ "runner:create": {
38
+ "path": "src/tasks/runner/create.ts",
39
+ "handler": "create"
40
+ },
41
+ "runner:remove": {
42
+ "path": "src/tasks/runner/remove.ts",
43
+ "handler": "remove"
44
+ },
45
+ "runner:bundle": {
46
+ "path": "src/tasks/runner/bundle.ts",
47
+ "handler": "bundle"
48
+ },
49
+ "task:publish": {
50
+ "path": "src/tasks/task/publish.ts",
51
+ "handler": "publish"
52
+ },
53
+ "task:download": {
54
+ "path": "src/tasks/task/download.ts",
55
+ "handler": "download"
56
+ },
57
+ "auth:add": {
58
+ "path": "src/tasks/auth/add.ts",
59
+ "handler": "add"
60
+ },
61
+ "auth:load": {
62
+ "path": "src/tasks/auth/load.ts",
63
+ "handler": "load"
64
+ },
65
+ "auth:loadCurrent": {
66
+ "path": "src/tasks/auth/loadCurrent.ts",
67
+ "handler": "loadCurrent"
68
+ },
69
+ "auth:switch": {
70
+ "path": "src/tasks/auth/switch.ts",
71
+ "handler": "switchProfile"
72
+ },
73
+ "auth:list": {
74
+ "path": "src/tasks/auth/list.ts",
75
+ "handler": "list"
76
+ },
77
+ "auth:remove": {
78
+ "path": "src/tasks/auth/remove.ts",
79
+ "handler": "remove"
36
80
  }
37
81
  },
38
82
  "runners": {}
@@ -0,0 +1,4 @@
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"}]}}]}}
@@ -0,0 +1,2 @@
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"}]}}
@@ -0,0 +1 @@
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"}]}}]}}