@forgehive/forge-cli 0.3.12 → 0.3.14
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 -2
- package/dist/tasks/docs/download.d.ts +8 -3
- package/dist/tasks/docs/download.js +57 -20
- package/dist/tasks/task/run.d.ts +4 -2
- package/dist/tasks/task/run.js +28 -7
- package/logs/task:list.log +1 -0
- package/logs/test:guidance.log +1 -0
- package/logs/test:uuid.log +1 -0
- package/logs/test:uuidCheck.log +1 -0
- package/package.json +9 -9
- package/src/runner.ts +3 -2
- package/src/tasks/docs/download.ts +67 -20
- package/src/tasks/task/run.ts +35 -7
package/dist/runner.js
CHANGED
|
@@ -163,9 +163,10 @@ runner.setHandler(async (data) => {
|
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
165
|
else if (taskName === 'docs:download') {
|
|
166
|
-
const { path } = args;
|
|
166
|
+
const { path, logs } = args;
|
|
167
167
|
result = await task.run({
|
|
168
|
-
path
|
|
168
|
+
path,
|
|
169
|
+
logs
|
|
169
170
|
});
|
|
170
171
|
}
|
|
171
172
|
else if (taskName === 'project:create') {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const download: import("@forgehive/task").TaskInstanceType<(argv: {
|
|
2
2
|
path?: string | undefined;
|
|
3
|
+
logs?: boolean | undefined;
|
|
3
4
|
}, boundaries: import("@forgehive/task").WrappedBoundaries<{
|
|
4
5
|
fetchFile: (url: string) => Promise<string>;
|
|
5
6
|
getCurrentWorkingDirectory: () => Promise<string>;
|
|
@@ -8,9 +9,13 @@ export declare const download: import("@forgehive/task").TaskInstanceType<(argv:
|
|
|
8
9
|
checkFileExists: (filePath: string) => Promise<boolean>;
|
|
9
10
|
}>) => Promise<{
|
|
10
11
|
success: boolean;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
downloads: {
|
|
13
|
+
type: string;
|
|
14
|
+
filePath: string;
|
|
15
|
+
targetPath: string;
|
|
16
|
+
size: number;
|
|
17
|
+
}[];
|
|
18
|
+
totalFiles: number;
|
|
14
19
|
}>, {
|
|
15
20
|
fetchFile: (url: string) => Promise<string>;
|
|
16
21
|
getCurrentWorkingDirectory: () => Promise<string>;
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
// Run this task with:
|
|
4
4
|
// forge task:run docs:download
|
|
5
5
|
// forge task:run docs:download --path="custom/path/forge.md"
|
|
6
|
+
// forge task:run docs:download --logs
|
|
7
|
+
// forge task:run docs:download --logs --path="custom/path/forge.md"
|
|
6
8
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
9
|
if (k2 === undefined) k2 = k;
|
|
8
10
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -45,10 +47,12 @@ const task_1 = require("@forgehive/task");
|
|
|
45
47
|
const schema_1 = require("@forgehive/schema");
|
|
46
48
|
const path_1 = __importDefault(require("path"));
|
|
47
49
|
const name = 'docs:download';
|
|
48
|
-
const description = 'Download
|
|
50
|
+
const description = 'Download ForgeHive LLM guides from GitHub to local project';
|
|
49
51
|
const LLM_GUIDE_URL = 'https://raw.githubusercontent.com/forge-and-hive/forge-mono-repo/refs/heads/main/docs/llm.md';
|
|
52
|
+
const LLM_HIVE_LOGGING_URL = 'https://raw.githubusercontent.com/forge-and-hive/forge-mono-repo/refs/heads/main/docs/llm-hive-logging.md';
|
|
50
53
|
const schema = new schema_1.Schema({
|
|
51
|
-
path: schema_1.Schema.string().optional()
|
|
54
|
+
path: schema_1.Schema.string().optional(),
|
|
55
|
+
logs: schema_1.Schema.boolean().optional()
|
|
52
56
|
});
|
|
53
57
|
const boundaries = {
|
|
54
58
|
fetchFile: async (url) => {
|
|
@@ -85,30 +89,63 @@ exports.download = (0, task_1.createTask)({
|
|
|
85
89
|
description,
|
|
86
90
|
schema,
|
|
87
91
|
boundaries,
|
|
88
|
-
fn: async function ({ path: customPath }, { fetchFile, getCurrentWorkingDirectory, createDirectory, writeFile, checkFileExists }) {
|
|
89
|
-
// Determine the target path
|
|
90
|
-
const targetPath = customPath || 'docs/forge.md';
|
|
92
|
+
fn: async function ({ path: customPath, logs }, { fetchFile, getCurrentWorkingDirectory, createDirectory, writeFile, checkFileExists }) {
|
|
91
93
|
const cwd = await getCurrentWorkingDirectory();
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
const results = [];
|
|
95
|
+
// Download main LLM guide
|
|
96
|
+
const mainTargetPath = customPath || 'docs/forge.md';
|
|
97
|
+
const mainFullPath = path_1.default.resolve(cwd, mainTargetPath);
|
|
98
|
+
const mainDirPath = path_1.default.dirname(mainFullPath);
|
|
99
|
+
console.log(`Downloading ForgeHive LLM guide to: ${mainTargetPath}`);
|
|
95
100
|
// Check if file already exists
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
console.log(`Warning: File already exists at ${
|
|
101
|
+
const mainFileExists = await checkFileExists(mainFullPath);
|
|
102
|
+
if (mainFileExists) {
|
|
103
|
+
console.log(`Warning: File already exists at ${mainTargetPath}. It will be overwritten.`);
|
|
99
104
|
}
|
|
100
|
-
// Download the
|
|
101
|
-
const
|
|
105
|
+
// Download the main guide content
|
|
106
|
+
const mainContent = await fetchFile(LLM_GUIDE_URL);
|
|
102
107
|
// Create directory if it doesn't exist
|
|
103
|
-
await createDirectory(
|
|
104
|
-
// Write the file
|
|
105
|
-
await writeFile(
|
|
106
|
-
console.log(`✅ Successfully downloaded ForgeHive LLM guide to ${
|
|
108
|
+
await createDirectory(mainDirPath);
|
|
109
|
+
// Write the main guide file
|
|
110
|
+
await writeFile(mainFullPath, mainContent);
|
|
111
|
+
console.log(`✅ Successfully downloaded ForgeHive LLM guide to ${mainTargetPath}`);
|
|
112
|
+
results.push({
|
|
113
|
+
type: 'main',
|
|
114
|
+
filePath: mainFullPath,
|
|
115
|
+
targetPath: mainTargetPath,
|
|
116
|
+
size: mainContent.length
|
|
117
|
+
});
|
|
118
|
+
// Download Hive logging guide if --logs flag is provided
|
|
119
|
+
if (logs) {
|
|
120
|
+
const logsTargetPath = customPath
|
|
121
|
+
? path_1.default.join(path_1.default.dirname(customPath), 'hive-logging.md')
|
|
122
|
+
: 'docs/hive-logging.md';
|
|
123
|
+
const logsFullPath = path_1.default.resolve(cwd, logsTargetPath);
|
|
124
|
+
const logsDirPath = path_1.default.dirname(logsFullPath);
|
|
125
|
+
console.log(`Downloading Hive Logging guide to: ${logsTargetPath}`);
|
|
126
|
+
// Check if logs file already exists
|
|
127
|
+
const logsFileExists = await checkFileExists(logsFullPath);
|
|
128
|
+
if (logsFileExists) {
|
|
129
|
+
console.log(`Warning: File already exists at ${logsTargetPath}. It will be overwritten.`);
|
|
130
|
+
}
|
|
131
|
+
// Download the logs guide content
|
|
132
|
+
const logsContent = await fetchFile(LLM_HIVE_LOGGING_URL);
|
|
133
|
+
// Create directory if it doesn't exist
|
|
134
|
+
await createDirectory(logsDirPath);
|
|
135
|
+
// Write the logs guide file
|
|
136
|
+
await writeFile(logsFullPath, logsContent);
|
|
137
|
+
console.log(`✅ Successfully downloaded Hive Logging guide to ${logsTargetPath}`);
|
|
138
|
+
results.push({
|
|
139
|
+
type: 'logs',
|
|
140
|
+
filePath: logsFullPath,
|
|
141
|
+
targetPath: logsTargetPath,
|
|
142
|
+
size: logsContent.length
|
|
143
|
+
});
|
|
144
|
+
}
|
|
107
145
|
return {
|
|
108
146
|
success: true,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
size: content.length
|
|
147
|
+
downloads: results,
|
|
148
|
+
totalFiles: results.length
|
|
112
149
|
};
|
|
113
150
|
}
|
|
114
151
|
});
|
package/dist/tasks/task/run.d.ts
CHANGED
|
@@ -17,10 +17,11 @@ export declare const run: import("@forgehive/task").TaskInstanceType<(argv: {
|
|
|
17
17
|
}) => Promise<Promise<any>>;
|
|
18
18
|
ensureLogFolder: (logsPath: string) => Promise<void>;
|
|
19
19
|
ensureBuildsFolder: () => Promise<string>;
|
|
20
|
-
sendLogToAPI: (profile: Profile, projectName: string, record: ExecutionRecord, taskUuid?: string) => Promise<{
|
|
20
|
+
sendLogToAPI: (profile: Profile, projectName: string, record: ExecutionRecord, taskUuid?: string, projectUuid?: string) => Promise<{
|
|
21
21
|
success: boolean;
|
|
22
22
|
logUuid?: string;
|
|
23
23
|
taskUuid?: string;
|
|
24
|
+
skipRemoteLog?: boolean;
|
|
24
25
|
}>;
|
|
25
26
|
}>) => Promise<any>, {
|
|
26
27
|
loadConf: (args: {}) => Promise<Promise<ForgeConf>>;
|
|
@@ -36,9 +37,10 @@ export declare const run: import("@forgehive/task").TaskInstanceType<(argv: {
|
|
|
36
37
|
}) => Promise<Promise<any>>;
|
|
37
38
|
ensureLogFolder: (logsPath: string) => Promise<void>;
|
|
38
39
|
ensureBuildsFolder: () => Promise<string>;
|
|
39
|
-
sendLogToAPI: (profile: Profile, projectName: string, record: ExecutionRecord, taskUuid?: string) => Promise<{
|
|
40
|
+
sendLogToAPI: (profile: Profile, projectName: string, record: ExecutionRecord, taskUuid?: string, projectUuid?: string) => Promise<{
|
|
40
41
|
success: boolean;
|
|
41
42
|
logUuid?: string;
|
|
42
43
|
taskUuid?: string;
|
|
44
|
+
skipRemoteLog?: boolean;
|
|
43
45
|
}>;
|
|
44
46
|
}>;
|
package/dist/tasks/task/run.js
CHANGED
|
@@ -50,10 +50,27 @@ const boundaries = {
|
|
|
50
50
|
}
|
|
51
51
|
return buildsPath;
|
|
52
52
|
},
|
|
53
|
-
sendLogToAPI: async (profile, projectName, record, taskUuid) => {
|
|
53
|
+
sendLogToAPI: async (profile, projectName, record, taskUuid, projectUuid) => {
|
|
54
|
+
// Check if we have required UUIDs for the new endpoint
|
|
55
|
+
if (!projectUuid || !taskUuid) {
|
|
56
|
+
console.log('===============================================');
|
|
57
|
+
console.log('⚠️ Remote logging skipped - missing UUIDs');
|
|
58
|
+
console.log('');
|
|
59
|
+
console.log('To enable remote logging with enhanced features:');
|
|
60
|
+
if (!projectUuid) {
|
|
61
|
+
console.log('• Use "forge project:create" to create a new project, or');
|
|
62
|
+
console.log('• Use "forge project:link" to connect to an existing project');
|
|
63
|
+
}
|
|
64
|
+
if (!taskUuid) {
|
|
65
|
+
console.log('• Use "forge project:sync" to get the task to have UUID');
|
|
66
|
+
}
|
|
67
|
+
console.log('===============================================');
|
|
68
|
+
return { success: true, skipRemoteLog: true };
|
|
69
|
+
}
|
|
54
70
|
try {
|
|
55
71
|
const config = {
|
|
56
72
|
projectName,
|
|
73
|
+
projectUuid,
|
|
57
74
|
apiKey: profile.apiKey,
|
|
58
75
|
apiSecret: profile.apiSecret,
|
|
59
76
|
host: profile.url,
|
|
@@ -62,10 +79,13 @@ const boundaries = {
|
|
|
62
79
|
}
|
|
63
80
|
};
|
|
64
81
|
const client = new hive_sdk_1.HiveLogClient(config);
|
|
65
|
-
|
|
82
|
+
console.log('Sending execution log to Hive...');
|
|
83
|
+
const result = await client.sendLogByUuid(record, taskUuid);
|
|
66
84
|
if (result === 'success' || (typeof result === 'object' && 'uuid' in result)) {
|
|
67
85
|
console.log('===============================================');
|
|
68
|
-
console.log('Log sent to
|
|
86
|
+
console.log('✅ Log sent to Hive successfully');
|
|
87
|
+
console.log(` Profile: ${profile.name}`);
|
|
88
|
+
console.log(` Host: ${profile.url}`);
|
|
69
89
|
if (typeof result === 'object' && result && 'uuid' in result) {
|
|
70
90
|
const logResponse = result;
|
|
71
91
|
return { success: true, logUuid: logResponse.uuid, taskUuid };
|
|
@@ -73,12 +93,12 @@ const boundaries = {
|
|
|
73
93
|
return { success: true, taskUuid };
|
|
74
94
|
}
|
|
75
95
|
else {
|
|
76
|
-
console.error('Failed to send log to
|
|
96
|
+
console.error('❌ Failed to send log to Hive:', profile.url);
|
|
77
97
|
return { success: false };
|
|
78
98
|
}
|
|
79
99
|
}
|
|
80
100
|
catch (e) {
|
|
81
|
-
console.error('Failed to send log to
|
|
101
|
+
console.error('❌ Failed to send log to Hive:', profile.url);
|
|
82
102
|
const error = e;
|
|
83
103
|
console.error('Error:', error.message);
|
|
84
104
|
return { success: false };
|
|
@@ -93,6 +113,7 @@ exports.run = (0, task_1.createTask)({
|
|
|
93
113
|
const forge = await loadConf({});
|
|
94
114
|
const taskDescriptor = forge.tasks[descriptorName];
|
|
95
115
|
const projectName = forge.project.name;
|
|
116
|
+
const projectUuid = forge.project.uuid;
|
|
96
117
|
const taskUuid = taskDescriptor?.uuid;
|
|
97
118
|
if (taskDescriptor === undefined) {
|
|
98
119
|
throw new Error('Task is not defined on forge.json');
|
|
@@ -154,8 +175,8 @@ exports.run = (0, task_1.createTask)({
|
|
|
154
175
|
await tape.save();
|
|
155
176
|
if (profile) {
|
|
156
177
|
try {
|
|
157
|
-
const logResult = await sendLogToAPI(profile, projectName, logItem, taskUuid);
|
|
158
|
-
if (logResult.success && taskUuid) {
|
|
178
|
+
const logResult = await sendLogToAPI(profile, projectName, logItem, taskUuid, projectUuid);
|
|
179
|
+
if (logResult.success && !logResult.skipRemoteLog && taskUuid) {
|
|
159
180
|
console.log(`🔗 View execution logs: ${profile.url}/tasks/${taskUuid}?tab=logs`);
|
|
160
181
|
}
|
|
161
182
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"input":{},"boundaries":{"loadConf":[{"input":[{}],"output":{"project":{"name":"forge-cli"},"paths":{"logs":"logs/","fixtures":"fixtures","fingerprints":"fingerprints/","tasks":"src/tasks/","runners":"src/runners/","tests":"src/tests/"},"infra":{"region":"us-west-2","bucket":""},"tasks":{"task:createTask":{"path":"src/tasks/task/createTask.ts","handler":"createTask"},"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"},"runner:remove":{"path":"src/tasks/runner/remove.ts","handler":"remove"},"runner:bundle":{"path":"src/tasks/runner/bundle.ts","handler":"bundle"},"task:publish":{"path":"src/tasks/task/publish.ts","handler":"publish"},"task:download":{"path":"src/tasks/task/download.ts","handler":"download"},"auth:add":{"path":"src/tasks/auth/add.ts","handler":"add"},"auth:load":{"path":"src/tasks/auth/load.ts","handler":"load"},"auth:loadCurrent":{"path":"src/tasks/auth/loadCurrent.ts","handler":"loadCurrent"},"auth:switch":{"path":"src/tasks/auth/switch.ts","handler":"switchProfile"},"auth:list":{"path":"src/tasks/auth/list.ts","handler":"list"},"auth:remove":{"path":"src/tasks/auth/remove.ts","handler":"remove"},"task:replay":{"path":"src/tasks/task/replay.ts","handler":"replay"},"fixture:download":{"path":"src/tasks/fixture/download.ts","handler":"download"},"bundle:zip":{"path":"src/tasks/bundle/zip.ts","handler":"zip"},"task:list":{"path":"src/tasks/task/list.ts","handler":"list"},"task:describe":{"path":"src/tasks/task/describe.ts","handler":"describe"},"task:fingerprint":{"path":"src/tasks/task/fingerprint.ts","handler":"fingerprint"},"bundle:fingerprint":{"path":"src/tasks/bundle/fingerprint.ts","handler":"fingerprint"},"task:invoke":{"path":"src/tasks/task/invoke.ts","handler":"invoke"},"docs:download":{"path":"src/tasks/docs/download.ts","handler":"download"},"project:create":{"path":"src/tasks/project/create.ts","handler":"create"},"project:link":{"path":"src/tasks/project/link.ts","handler":"link","uuid":"cb9f82e1-d397-46d9-9f0d-2b0e3becbfa1"},"project:unlink":{"path":"src/tasks/project/unlink.ts","handler":"unlink","uuid":"414d37de-793c-4d01-899d-69515f5e0948"}},"runners":{}},"timing":{"startTime":1755627445111,"endTime":1755627445112,"duration":1}}]},"metadata":{"environment":"cli"},"metrics":[],"type":"success","output":{"taskCount":29},"timing":{"startTime":1755627445111,"endTime":1755627445112,"duration":1}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"input":{},"boundaries":{},"taskName":"test:guidance","metadata":{"environment":"cli"},"metrics":[],"type":"success","output":{},"timing":{"startTime":1755627427045,"endTime":1755627427045,"duration":0}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"uuid":"0198bfeb-69c0-77e8-882b-a76dcb9300f9","input":{},"boundaries":{},"taskName":"test:uuid","metadata":{"environment":"cli"},"metrics":[],"type":"success","output":{},"timing":{"startTime":1755566533056,"endTime":1755566533057,"duration":1}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"input":{},"boundaries":{},"taskName":"test:uuidCheck","metadata":{"environment":"cli"},"metrics":[],"type":"success","output":{},"timing":{"startTime":1755567492456,"endTime":1755567492456,"duration":0}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgehive/forge-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"description": "TypeScript CLI application",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@forgehive/hive-sdk": "^0.1.
|
|
14
|
-
"@forgehive/record-tape": "^0.2.
|
|
15
|
-
"@forgehive/runner": "^0.2.
|
|
13
|
+
"@forgehive/hive-sdk": "^0.1.4",
|
|
14
|
+
"@forgehive/record-tape": "^0.2.6",
|
|
15
|
+
"@forgehive/runner": "^0.2.6",
|
|
16
16
|
"@forgehive/schema": "^0.1.4",
|
|
17
|
-
"@forgehive/task": "^0.2.
|
|
17
|
+
"@forgehive/task": "^0.2.6",
|
|
18
18
|
"esbuild": "^0.25.0",
|
|
19
19
|
"handlebars": "^4.7.8",
|
|
20
20
|
"minimist": "^1.2.8",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"minimist": "^1.2.8",
|
|
31
31
|
"typescript": "^5.3.3",
|
|
32
32
|
"uuid": "^11.1.0",
|
|
33
|
-
"@forgehive/
|
|
34
|
-
"@forgehive/
|
|
35
|
-
"@forgehive/runner": "0.2.5",
|
|
33
|
+
"@forgehive/record-tape": "0.2.6",
|
|
34
|
+
"@forgehive/hive-sdk": "0.1.4",
|
|
36
35
|
"@forgehive/schema": "0.1.4",
|
|
37
|
-
"@forgehive/
|
|
36
|
+
"@forgehive/runner": "0.2.6",
|
|
37
|
+
"@forgehive/task": "0.2.6"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/archiver": "^6.0.3",
|
package/src/runner.ts
CHANGED
|
@@ -184,10 +184,11 @@ runner.setHandler(async (data: ParsedArgs): Promise<unknown> => {
|
|
|
184
184
|
profileName: String(action)
|
|
185
185
|
})
|
|
186
186
|
} else if (taskName === 'docs:download') {
|
|
187
|
-
const { path } = args as { path?: string }
|
|
187
|
+
const { path, logs } = args as { path?: string, logs?: boolean }
|
|
188
188
|
|
|
189
189
|
result = await task.run({
|
|
190
|
-
path
|
|
190
|
+
path,
|
|
191
|
+
logs
|
|
191
192
|
})
|
|
192
193
|
} else if (taskName === 'project:create') {
|
|
193
194
|
const { projectName, description } = args as { projectName?: string, description?: string }
|
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
// Run this task with:
|
|
3
3
|
// forge task:run docs:download
|
|
4
4
|
// forge task:run docs:download --path="custom/path/forge.md"
|
|
5
|
+
// forge task:run docs:download --logs
|
|
6
|
+
// forge task:run docs:download --logs --path="custom/path/forge.md"
|
|
5
7
|
|
|
6
8
|
import { createTask } from '@forgehive/task'
|
|
7
9
|
import { Schema } from '@forgehive/schema'
|
|
8
10
|
import path from 'path'
|
|
9
11
|
|
|
10
12
|
const name = 'docs:download'
|
|
11
|
-
const description = 'Download
|
|
13
|
+
const description = 'Download ForgeHive LLM guides from GitHub to local project'
|
|
12
14
|
|
|
13
15
|
const LLM_GUIDE_URL = 'https://raw.githubusercontent.com/forge-and-hive/forge-mono-repo/refs/heads/main/docs/llm.md'
|
|
16
|
+
const LLM_HIVE_LOGGING_URL = 'https://raw.githubusercontent.com/forge-and-hive/forge-mono-repo/refs/heads/main/docs/llm-hive-logging.md'
|
|
14
17
|
|
|
15
18
|
const schema = new Schema({
|
|
16
|
-
path: Schema.string().optional()
|
|
19
|
+
path: Schema.string().optional(),
|
|
20
|
+
logs: Schema.boolean().optional()
|
|
17
21
|
})
|
|
18
22
|
|
|
19
23
|
const boundaries = {
|
|
@@ -51,37 +55,80 @@ export const download = createTask({
|
|
|
51
55
|
description,
|
|
52
56
|
schema,
|
|
53
57
|
boundaries,
|
|
54
|
-
fn: async function ({ path: customPath }, { fetchFile, getCurrentWorkingDirectory, createDirectory, writeFile, checkFileExists }) {
|
|
55
|
-
// Determine the target path
|
|
56
|
-
const targetPath = customPath || 'docs/forge.md'
|
|
58
|
+
fn: async function ({ path: customPath, logs }, { fetchFile, getCurrentWorkingDirectory, createDirectory, writeFile, checkFileExists }) {
|
|
57
59
|
const cwd = await getCurrentWorkingDirectory()
|
|
58
|
-
const
|
|
59
|
-
const dirPath = path.dirname(fullPath)
|
|
60
|
+
const results = []
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
// Download main LLM guide
|
|
63
|
+
const mainTargetPath = customPath || 'docs/forge.md'
|
|
64
|
+
const mainFullPath = path.resolve(cwd, mainTargetPath)
|
|
65
|
+
const mainDirPath = path.dirname(mainFullPath)
|
|
66
|
+
|
|
67
|
+
console.log(`Downloading ForgeHive LLM guide to: ${mainTargetPath}`)
|
|
62
68
|
|
|
63
69
|
// Check if file already exists
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
-
console.log(`Warning: File already exists at ${
|
|
70
|
+
const mainFileExists = await checkFileExists(mainFullPath)
|
|
71
|
+
if (mainFileExists) {
|
|
72
|
+
console.log(`Warning: File already exists at ${mainTargetPath}. It will be overwritten.`)
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
// Download the
|
|
70
|
-
const
|
|
75
|
+
// Download the main guide content
|
|
76
|
+
const mainContent = await fetchFile(LLM_GUIDE_URL)
|
|
71
77
|
|
|
72
78
|
// Create directory if it doesn't exist
|
|
73
|
-
await createDirectory(
|
|
79
|
+
await createDirectory(mainDirPath)
|
|
80
|
+
|
|
81
|
+
// Write the main guide file
|
|
82
|
+
await writeFile(mainFullPath, mainContent)
|
|
83
|
+
|
|
84
|
+
console.log(`✅ Successfully downloaded ForgeHive LLM guide to ${mainTargetPath}`)
|
|
85
|
+
|
|
86
|
+
results.push({
|
|
87
|
+
type: 'main',
|
|
88
|
+
filePath: mainFullPath,
|
|
89
|
+
targetPath: mainTargetPath,
|
|
90
|
+
size: mainContent.length
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Download Hive logging guide if --logs flag is provided
|
|
94
|
+
if (logs) {
|
|
95
|
+
const logsTargetPath = customPath
|
|
96
|
+
? path.join(path.dirname(customPath), 'hive-logging.md')
|
|
97
|
+
: 'docs/hive-logging.md'
|
|
98
|
+
const logsFullPath = path.resolve(cwd, logsTargetPath)
|
|
99
|
+
const logsDirPath = path.dirname(logsFullPath)
|
|
100
|
+
|
|
101
|
+
console.log(`Downloading Hive Logging guide to: ${logsTargetPath}`)
|
|
74
102
|
|
|
75
|
-
|
|
76
|
-
|
|
103
|
+
// Check if logs file already exists
|
|
104
|
+
const logsFileExists = await checkFileExists(logsFullPath)
|
|
105
|
+
if (logsFileExists) {
|
|
106
|
+
console.log(`Warning: File already exists at ${logsTargetPath}. It will be overwritten.`)
|
|
107
|
+
}
|
|
77
108
|
|
|
78
|
-
|
|
109
|
+
// Download the logs guide content
|
|
110
|
+
const logsContent = await fetchFile(LLM_HIVE_LOGGING_URL)
|
|
111
|
+
|
|
112
|
+
// Create directory if it doesn't exist
|
|
113
|
+
await createDirectory(logsDirPath)
|
|
114
|
+
|
|
115
|
+
// Write the logs guide file
|
|
116
|
+
await writeFile(logsFullPath, logsContent)
|
|
117
|
+
|
|
118
|
+
console.log(`✅ Successfully downloaded Hive Logging guide to ${logsTargetPath}`)
|
|
119
|
+
|
|
120
|
+
results.push({
|
|
121
|
+
type: 'logs',
|
|
122
|
+
filePath: logsFullPath,
|
|
123
|
+
targetPath: logsTargetPath,
|
|
124
|
+
size: logsContent.length
|
|
125
|
+
})
|
|
126
|
+
}
|
|
79
127
|
|
|
80
128
|
return {
|
|
81
129
|
success: true,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
size: content.length
|
|
130
|
+
downloads: results,
|
|
131
|
+
totalFiles: results.length
|
|
85
132
|
}
|
|
86
133
|
}
|
|
87
134
|
})
|
package/src/tasks/task/run.ts
CHANGED
|
@@ -49,10 +49,34 @@ const boundaries = {
|
|
|
49
49
|
|
|
50
50
|
return buildsPath
|
|
51
51
|
},
|
|
52
|
-
sendLogToAPI: async (
|
|
52
|
+
sendLogToAPI: async (
|
|
53
|
+
profile: Profile,
|
|
54
|
+
projectName: string,
|
|
55
|
+
record: ExecutionRecord,
|
|
56
|
+
taskUuid?: string,
|
|
57
|
+
projectUuid?: string
|
|
58
|
+
): Promise<{ success: boolean; logUuid?: string; taskUuid?: string; skipRemoteLog?: boolean }> => {
|
|
59
|
+
// Check if we have required UUIDs for the new endpoint
|
|
60
|
+
if (!projectUuid || !taskUuid) {
|
|
61
|
+
console.log('===============================================')
|
|
62
|
+
console.log('⚠️ Remote logging skipped - missing UUIDs')
|
|
63
|
+
console.log('')
|
|
64
|
+
console.log('To enable remote logging with enhanced features:')
|
|
65
|
+
if (!projectUuid) {
|
|
66
|
+
console.log('• Use "forge project:create" to create a new project, or')
|
|
67
|
+
console.log('• Use "forge project:link" to connect to an existing project')
|
|
68
|
+
}
|
|
69
|
+
if (!taskUuid) {
|
|
70
|
+
console.log('• Use "forge project:sync" to get the task to have UUID')
|
|
71
|
+
}
|
|
72
|
+
console.log('===============================================')
|
|
73
|
+
return { success: true, skipRemoteLog: true }
|
|
74
|
+
}
|
|
75
|
+
|
|
53
76
|
try {
|
|
54
77
|
const config = {
|
|
55
78
|
projectName,
|
|
79
|
+
projectUuid,
|
|
56
80
|
apiKey: profile.apiKey,
|
|
57
81
|
apiSecret: profile.apiSecret,
|
|
58
82
|
host: profile.url,
|
|
@@ -62,11 +86,14 @@ const boundaries = {
|
|
|
62
86
|
}
|
|
63
87
|
|
|
64
88
|
const client = new HiveLogClient(config)
|
|
65
|
-
|
|
89
|
+
console.log('Sending execution log to Hive...')
|
|
90
|
+
const result = await client.sendLogByUuid(record, taskUuid)
|
|
66
91
|
|
|
67
92
|
if (result === 'success' || (typeof result === 'object' && 'uuid' in result)) {
|
|
68
93
|
console.log('===============================================')
|
|
69
|
-
console.log('Log sent to
|
|
94
|
+
console.log('✅ Log sent to Hive successfully')
|
|
95
|
+
console.log(` Profile: ${profile.name}`)
|
|
96
|
+
console.log(` Host: ${profile.url}`)
|
|
70
97
|
|
|
71
98
|
if (typeof result === 'object' && result && 'uuid' in result) {
|
|
72
99
|
const logResponse = result as { uuid: string }
|
|
@@ -75,11 +102,11 @@ const boundaries = {
|
|
|
75
102
|
|
|
76
103
|
return { success: true, taskUuid }
|
|
77
104
|
} else {
|
|
78
|
-
console.error('Failed to send log to
|
|
105
|
+
console.error('❌ Failed to send log to Hive:', profile.url)
|
|
79
106
|
return { success: false }
|
|
80
107
|
}
|
|
81
108
|
} catch (e) {
|
|
82
|
-
console.error('Failed to send log to
|
|
109
|
+
console.error('❌ Failed to send log to Hive:', profile.url)
|
|
83
110
|
const error = e as Error
|
|
84
111
|
console.error('Error:', error.message)
|
|
85
112
|
return { success: false }
|
|
@@ -103,6 +130,7 @@ export const run = createTask({
|
|
|
103
130
|
const forge: ForgeConf = await loadConf({})
|
|
104
131
|
const taskDescriptor = forge.tasks[descriptorName as keyof typeof forge.tasks]
|
|
105
132
|
const projectName = forge.project.name
|
|
133
|
+
const projectUuid = forge.project.uuid
|
|
106
134
|
const taskUuid = taskDescriptor?.uuid
|
|
107
135
|
|
|
108
136
|
if (taskDescriptor === undefined) {
|
|
@@ -176,9 +204,9 @@ export const run = createTask({
|
|
|
176
204
|
|
|
177
205
|
if (profile) {
|
|
178
206
|
try {
|
|
179
|
-
const logResult = await sendLogToAPI(profile, projectName, logItem, taskUuid)
|
|
207
|
+
const logResult = await sendLogToAPI(profile, projectName, logItem, taskUuid, projectUuid)
|
|
180
208
|
|
|
181
|
-
if (logResult.success && taskUuid) {
|
|
209
|
+
if (logResult.success && !logResult.skipRemoteLog && taskUuid) {
|
|
182
210
|
console.log(`🔗 View execution logs: ${profile.url}/tasks/${taskUuid}?tab=logs`)
|
|
183
211
|
}
|
|
184
212
|
} catch (e) {
|