@pipelab/core-node 1.0.0-beta.1 → 1.0.0-beta.2
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/.oxfmtrc.json +3 -0
- package/CHANGELOG.md +9 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +25 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/handler-func.ts +6 -6
- package/src/handlers/build-history.ts +6 -8
- package/src/handlers/history.ts +6 -8
- package/src/handlers/index.ts +2 -2
- package/src/plugins-registry.ts +23 -17
- package/src/runner.ts +28 -22
- package/src/server.ts +1 -1
- package/src/utils/fs-extras.ts +10 -1
- package/src/utils/github.ts +10 -6
- package/src/utils/remote.ts +25 -24
- package/src/utils.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipelab/core-node",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The Pipelab automation engine for Node.js",
|
|
6
6
|
"license": "FSL-1.1-MIT",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"access": "public"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@supabase/supabase-js": "2.99.3",
|
|
29
30
|
"adm-zip": "0.5.16",
|
|
30
31
|
"archiver": "7.0.1",
|
|
31
32
|
"check-disk-space": "3.4.0",
|
|
@@ -39,9 +40,8 @@
|
|
|
39
40
|
"type-fest": "4.39.0",
|
|
40
41
|
"ws": "8.18.3",
|
|
41
42
|
"yauzl": "2.10.0",
|
|
42
|
-
"@
|
|
43
|
-
"@pipelab/
|
|
44
|
-
"@pipelab/shared": "1.0.0-beta.0"
|
|
43
|
+
"@pipelab/constants": "1.0.0-beta.1",
|
|
44
|
+
"@pipelab/shared": "1.0.0-beta.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/adm-zip": "0.5.7",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"@types/yauzl": "2.10.3",
|
|
55
55
|
"tsdown": "0.21.2",
|
|
56
56
|
"typescript": "^5.0.0",
|
|
57
|
-
"@pipelab/tsconfig": "1.0.0-beta.
|
|
57
|
+
"@pipelab/tsconfig": "1.0.0-beta.1"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "tsdown",
|
package/src/handler-func.ts
CHANGED
|
@@ -53,9 +53,9 @@ export const handleConditionExecute = async (
|
|
|
53
53
|
.find((plugin) => plugin.id === pluginId)
|
|
54
54
|
?.nodes.find((node: any) => node.node.id === nodeId) as
|
|
55
55
|
| {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
node: Condition;
|
|
57
|
+
runner: ConditionRunner<any>;
|
|
58
|
+
}
|
|
59
59
|
| undefined;
|
|
60
60
|
|
|
61
61
|
if (!node) {
|
|
@@ -136,9 +136,9 @@ export const handleActionExecute = async (
|
|
|
136
136
|
.find((plugin) => plugin.id === pluginId)
|
|
137
137
|
?.nodes.find((node: any) => node.node.id === nodeId) as
|
|
138
138
|
| {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
node: Action;
|
|
140
|
+
runner: ActionRunner<any>;
|
|
141
|
+
}
|
|
142
142
|
| undefined;
|
|
143
143
|
|
|
144
144
|
if (!node) {
|
|
@@ -93,17 +93,13 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
|
|
|
93
93
|
|
|
94
94
|
// 2. Filter by maxEntries (sort by date first to keep the newest)
|
|
95
95
|
if (maxEntries > 0 && entries.length > maxEntries) {
|
|
96
|
-
entries = entries
|
|
97
|
-
.sort((a, b) => b.createdAt - a.createdAt)
|
|
98
|
-
.slice(0, maxEntries);
|
|
96
|
+
entries = entries.sort((a, b) => b.createdAt - a.createdAt).slice(0, maxEntries);
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
if (entries.length < originalCount) {
|
|
102
100
|
this.logger
|
|
103
101
|
.logger()
|
|
104
|
-
.info(
|
|
105
|
-
`[${pipelineId}] Pruned ${originalCount - entries.length} history entries.`,
|
|
106
|
-
);
|
|
102
|
+
.info(`[${pipelineId}] Pruned ${originalCount - entries.length} history entries.`);
|
|
107
103
|
await this.savePipelineHistory(pipelineId, entries);
|
|
108
104
|
}
|
|
109
105
|
}
|
|
@@ -271,8 +267,10 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
|
|
|
271
267
|
await unlink(pipelinePath);
|
|
272
268
|
this.logger.logger().info(`Cleared history for pipeline "${pipelineId}"`);
|
|
273
269
|
} catch (error: any) {
|
|
274
|
-
if (error.code ===
|
|
275
|
-
this.logger
|
|
270
|
+
if (error.code === "ENOENT") {
|
|
271
|
+
this.logger
|
|
272
|
+
.logger()
|
|
273
|
+
.warn(`No history file found for pipeline "${pipelineId}". Nothing to clear.`);
|
|
276
274
|
return;
|
|
277
275
|
}
|
|
278
276
|
this.logger.logger().error(`Failed to clear history for pipeline "${pipelineId}":`, error);
|
package/src/handlers/history.ts
CHANGED
|
@@ -127,8 +127,7 @@ export const registerHistoryHandlers = (context: PipelabContext) => {
|
|
|
127
127
|
type: "end",
|
|
128
128
|
data: {
|
|
129
129
|
type: "error",
|
|
130
|
-
ipcError:
|
|
131
|
-
error instanceof Error ? error.message : "Failed to get build history entries",
|
|
130
|
+
ipcError: error instanceof Error ? error.message : "Failed to get build history entries",
|
|
132
131
|
},
|
|
133
132
|
});
|
|
134
133
|
}
|
|
@@ -158,8 +157,7 @@ export const registerHistoryHandlers = (context: PipelabContext) => {
|
|
|
158
157
|
type: "end",
|
|
159
158
|
data: {
|
|
160
159
|
type: "error",
|
|
161
|
-
ipcError:
|
|
162
|
-
error instanceof Error ? error.message : "Failed to update build history entry",
|
|
160
|
+
ipcError: error instanceof Error ? error.message : "Failed to update build history entry",
|
|
163
161
|
},
|
|
164
162
|
});
|
|
165
163
|
}
|
|
@@ -189,8 +187,7 @@ export const registerHistoryHandlers = (context: PipelabContext) => {
|
|
|
189
187
|
type: "end",
|
|
190
188
|
data: {
|
|
191
189
|
type: "error",
|
|
192
|
-
ipcError:
|
|
193
|
-
error instanceof Error ? error.message : "Failed to delete build history entry",
|
|
190
|
+
ipcError: error instanceof Error ? error.message : "Failed to delete build history entry",
|
|
194
191
|
},
|
|
195
192
|
});
|
|
196
193
|
}
|
|
@@ -250,7 +247,8 @@ export const registerHistoryHandlers = (context: PipelabContext) => {
|
|
|
250
247
|
type: "end",
|
|
251
248
|
data: {
|
|
252
249
|
type: "error",
|
|
253
|
-
ipcError:
|
|
250
|
+
ipcError:
|
|
251
|
+
error instanceof Error ? error.message : "Failed to clear build history for pipeline",
|
|
254
252
|
},
|
|
255
253
|
});
|
|
256
254
|
}
|
|
@@ -290,7 +288,7 @@ export const registerHistoryHandlers = (context: PipelabContext) => {
|
|
|
290
288
|
handle("build-history:configure", async (_, { send, value }) => {
|
|
291
289
|
try {
|
|
292
290
|
logger().info("Updating build history configuration:", value.config);
|
|
293
|
-
|
|
291
|
+
|
|
294
292
|
const settings = await setupConfigFile<AppConfig>("settings", { context });
|
|
295
293
|
const currentConfig = await settings.getConfig();
|
|
296
294
|
|
package/src/handlers/index.ts
CHANGED
|
@@ -26,10 +26,10 @@ export const registerAllHandlers = async (options: {
|
|
|
26
26
|
registerSystemHandlers(options);
|
|
27
27
|
|
|
28
28
|
const { registerPlugins } = usePlugins();
|
|
29
|
-
|
|
29
|
+
// Execute in the background! The plugins will be dynamically registered and broadcasted to the UI.
|
|
30
|
+
builtInPlugins({
|
|
30
31
|
context,
|
|
31
32
|
});
|
|
32
|
-
registerPlugins(plugins as any);
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export { registerShellHandlers } from "./shell";
|
package/src/plugins-registry.ts
CHANGED
|
@@ -25,7 +25,7 @@ export const loadPipelabPlugin = async (id: string, options: { context: PipelabC
|
|
|
25
25
|
const packageName = `@pipelab/plugin-${id}`;
|
|
26
26
|
const { packageDir, entryPoint } = await fetchPipelabPlugin(packageName, "latest", {
|
|
27
27
|
context: options.context,
|
|
28
|
-
installDeps:
|
|
28
|
+
installDeps: false,
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
console.log(`[Plugins] [${id}] Attempting to import from: ${entryPoint}`);
|
|
@@ -34,7 +34,7 @@ export const loadPipelabPlugin = async (id: string, options: { context: PipelabC
|
|
|
34
34
|
try {
|
|
35
35
|
const files = await readdir(packageDir, { recursive: true });
|
|
36
36
|
console.log(`[Plugins] [${id}] Directory contents:`, files);
|
|
37
|
-
} catch (e) {
|
|
37
|
+
} catch (e) {}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const pluginModule = await import(pathToFileURL(entryPoint).href);
|
|
@@ -52,27 +52,33 @@ export const loadPipelabPlugin = async (id: string, options: { context: PipelabC
|
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
export const builtInPlugins = async (options: { context: PipelabContext }) => {
|
|
55
|
-
console.log("[Plugins]
|
|
55
|
+
console.log("[Plugins] Starting background plugin loading...");
|
|
56
56
|
|
|
57
57
|
// Pre-ensure Node.js and PNPM once in parallel so plugins don't have to wait for them
|
|
58
58
|
sendStartupProgress("Preparing environment...");
|
|
59
|
-
await Promise.all([
|
|
60
|
-
ensureNodeJS(options.context),
|
|
61
|
-
ensurePNPM(options.context),
|
|
62
|
-
]);
|
|
59
|
+
await Promise.all([ensureNodeJS(options.context), ensurePNPM(options.context)]);
|
|
63
60
|
|
|
64
|
-
const
|
|
61
|
+
const { usePlugins } = await import("@pipelab/shared");
|
|
62
|
+
const { registerPlugins } = usePlugins();
|
|
63
|
+
const { webSocketServer } = await import("./index");
|
|
64
|
+
|
|
65
|
+
// Load plugins asynchronously in the background
|
|
66
|
+
Promise.allSettled(
|
|
65
67
|
DEFAULT_PLUGIN_IDS.map(async (id) => {
|
|
66
68
|
sendStartupProgress(`Loading plugin: ${id}`);
|
|
67
|
-
|
|
69
|
+
const plugin = await loadPipelabPlugin(id, options);
|
|
70
|
+
if (plugin) {
|
|
71
|
+
registerPlugins([plugin]);
|
|
72
|
+
webSocketServer.broadcast("plugin:loaded", { plugin });
|
|
73
|
+
}
|
|
68
74
|
}),
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
).then(() => {
|
|
76
|
+
console.log("[Plugins] All default plugins loaded.");
|
|
77
|
+
sendStartupProgress("All plugins loaded.");
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
webSocketServer.broadcast("startup:progress", { type: "done" });
|
|
80
|
+
}, 2000);
|
|
81
|
+
});
|
|
74
82
|
|
|
75
|
-
|
|
76
|
-
console.log(`[Plugins] Successfully loaded ${filtered.length} default plugins`);
|
|
77
|
-
return filtered;
|
|
83
|
+
return [];
|
|
78
84
|
};
|
package/src/runner.ts
CHANGED
|
@@ -79,10 +79,7 @@ export async function runPipelineCommand(file: string, options: RunOptions, vers
|
|
|
79
79
|
const cloudRunId = process.env.CLOUD_RUN_ID;
|
|
80
80
|
if (options.cloud && cloudRunId) {
|
|
81
81
|
const { createClient } = await import("@supabase/supabase-js");
|
|
82
|
-
supabase = createClient(
|
|
83
|
-
process.env.SUPABASE_URL!,
|
|
84
|
-
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
|
85
|
-
);
|
|
82
|
+
supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);
|
|
86
83
|
console.log(`Cloud mode enabled. Streaming logs for run: ${cloudRunId}`);
|
|
87
84
|
}
|
|
88
85
|
|
|
@@ -97,23 +94,29 @@ export async function runPipelineCommand(file: string, options: RunOptions, vers
|
|
|
97
94
|
onNodeEnter: (node) => {
|
|
98
95
|
console.log(`[ENTER] ${node.name} (${node.uid})`);
|
|
99
96
|
if (supabase) {
|
|
100
|
-
supabase
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
97
|
+
supabase
|
|
98
|
+
.from("cloud_run_logs")
|
|
99
|
+
.insert({
|
|
100
|
+
run_id: cloudRunId,
|
|
101
|
+
message: `[ENTER] ${node.name} (${node.uid})`,
|
|
102
|
+
node_uid: node.uid,
|
|
103
|
+
type: "node-enter",
|
|
104
|
+
})
|
|
105
|
+
.then();
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
onNodeExit: (node) => {
|
|
109
109
|
console.log(`[EXIT] ${node.name} (${node.uid})`);
|
|
110
110
|
if (supabase) {
|
|
111
|
-
supabase
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
supabase
|
|
112
|
+
.from("cloud_run_logs")
|
|
113
|
+
.insert({
|
|
114
|
+
run_id: cloudRunId,
|
|
115
|
+
message: `[EXIT] ${node.name} (${node.uid})`,
|
|
116
|
+
node_uid: node.uid,
|
|
117
|
+
type: "node-exit",
|
|
118
|
+
})
|
|
119
|
+
.then();
|
|
117
120
|
}
|
|
118
121
|
},
|
|
119
122
|
onLog: (data, node) => {
|
|
@@ -121,12 +124,15 @@ export async function runPipelineCommand(file: string, options: RunOptions, vers
|
|
|
121
124
|
const message = data.data.message.join(" ");
|
|
122
125
|
console.log(`[LOG] ${message}`);
|
|
123
126
|
if (supabase) {
|
|
124
|
-
supabase
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
supabase
|
|
128
|
+
.from("cloud_run_logs")
|
|
129
|
+
.insert({
|
|
130
|
+
run_id: cloudRunId,
|
|
131
|
+
message: message,
|
|
132
|
+
node_uid: node?.uid,
|
|
133
|
+
type: "log",
|
|
134
|
+
})
|
|
135
|
+
.then();
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
138
|
},
|
package/src/server.ts
CHANGED
|
@@ -66,7 +66,7 @@ export async function serveCommand(options: ServeOptions, version: string, _dirn
|
|
|
66
66
|
response.writeHead(404, { "Content-Type": "text/plain" });
|
|
67
67
|
response.end(
|
|
68
68
|
`Error: UI directory not found at ${rawAssetFolder}.\n` +
|
|
69
|
-
|
|
69
|
+
"Please run 'pnpm build' in apps/ui to generate the distribution.",
|
|
70
70
|
);
|
|
71
71
|
return;
|
|
72
72
|
}
|
package/src/utils/fs-extras.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { mkdir, createWriteStream, createReadStream } from "node:fs";
|
|
2
2
|
import { execa, Options, Subprocess } from "execa";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
mkdir as mkdirP,
|
|
5
|
+
access,
|
|
6
|
+
writeFile,
|
|
7
|
+
realpath,
|
|
8
|
+
mkdtemp,
|
|
9
|
+
chmod,
|
|
10
|
+
stat,
|
|
11
|
+
readdir,
|
|
12
|
+
} from "node:fs/promises";
|
|
4
13
|
import { join, dirname } from "node:path";
|
|
5
14
|
import { tmpdir } from "node:os";
|
|
6
15
|
import tar from "tar";
|
package/src/utils/github.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface FetchReleaseOptions {
|
|
|
22
22
|
*/
|
|
23
23
|
export async function fetchPackageReleases(
|
|
24
24
|
packageName: string,
|
|
25
|
-
options: FetchReleaseOptions = {}
|
|
25
|
+
options: FetchReleaseOptions = {},
|
|
26
26
|
): Promise<GitHubRelease[]> {
|
|
27
27
|
const { repo = "CynToolkit/pipelab", allowPrerelease = false } = options;
|
|
28
28
|
const url = `https://api.github.com/repos/${repo}/releases`;
|
|
@@ -61,7 +61,7 @@ export async function fetchPackageReleases(
|
|
|
61
61
|
*/
|
|
62
62
|
export async function fetchLatestPackageRelease(
|
|
63
63
|
packageName: string,
|
|
64
|
-
options: FetchReleaseOptions = {}
|
|
64
|
+
options: FetchReleaseOptions = {},
|
|
65
65
|
): Promise<GitHubRelease | null> {
|
|
66
66
|
const releases = await fetchPackageReleases(packageName, options);
|
|
67
67
|
|
|
@@ -75,7 +75,9 @@ export async function fetchLatestPackageRelease(
|
|
|
75
75
|
const targetTag = override.includes("@") ? override : `${packageName}@${override}`;
|
|
76
76
|
const release = releases.find((r) => r.tag_name === targetTag);
|
|
77
77
|
if (release) {
|
|
78
|
-
console.log(
|
|
78
|
+
console.log(
|
|
79
|
+
`[GitHub] Using release override from PIPELAB_OVERRIDE_RELEASE: ${release.tag_name}`,
|
|
80
|
+
);
|
|
79
81
|
return release;
|
|
80
82
|
}
|
|
81
83
|
console.warn(`[GitHub] Override release ${override} not found for package ${packageName}`);
|
|
@@ -101,12 +103,14 @@ export async function fetchLatestPackageRelease(
|
|
|
101
103
|
* This ensures we don't accidentally pick a package release (e.g. @pipelab/shared) as the "latest".
|
|
102
104
|
*/
|
|
103
105
|
export async function fetchLatestDesktopRelease(
|
|
104
|
-
options: FetchReleaseOptions = {}
|
|
106
|
+
options: FetchReleaseOptions = {},
|
|
105
107
|
): Promise<GitHubRelease | null> {
|
|
106
108
|
const latest = await fetchLatestPackageRelease("@pipelab/app", options);
|
|
107
|
-
|
|
109
|
+
|
|
108
110
|
if (latest) {
|
|
109
|
-
console.log(
|
|
111
|
+
console.log(
|
|
112
|
+
`[GitHub] Found latest desktop release: ${latest.tag_name} (${latest.prerelease ? "pre-release" : "stable"})`,
|
|
113
|
+
);
|
|
110
114
|
} else {
|
|
111
115
|
console.warn(`[GitHub] No desktop releases found`);
|
|
112
116
|
}
|
package/src/utils/remote.ts
CHANGED
|
@@ -94,7 +94,9 @@ export async function fetchPackage(
|
|
|
94
94
|
const foundVersion = packument["dist-tags"]?.[range] || semver.maxSatisfying(versions, range);
|
|
95
95
|
|
|
96
96
|
if (!foundVersion) {
|
|
97
|
-
throw new Error(
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Package ${packageName}@${range} not found on npm (available tags: ${Object.keys(packument["dist-tags"] || {}).join(", ")})`,
|
|
99
|
+
);
|
|
98
100
|
}
|
|
99
101
|
resolvedVersion = foundVersion;
|
|
100
102
|
console.log(`[Fetcher] ${packageName}: Resolved to v${resolvedVersion} via npm`);
|
|
@@ -150,7 +152,13 @@ export async function runPnpm(
|
|
|
150
152
|
},
|
|
151
153
|
) {
|
|
152
154
|
const {
|
|
153
|
-
args = [
|
|
155
|
+
args = [
|
|
156
|
+
"install",
|
|
157
|
+
"--prod",
|
|
158
|
+
"--no-lockfile",
|
|
159
|
+
"--prefer-offline",
|
|
160
|
+
"--no-verify-store-integrity",
|
|
161
|
+
],
|
|
154
162
|
extraEnv = {},
|
|
155
163
|
signal,
|
|
156
164
|
context: ctx,
|
|
@@ -183,10 +191,7 @@ export async function runPnpm(
|
|
|
183
191
|
/**
|
|
184
192
|
* Installs a specific version of Node.js if not already present.
|
|
185
193
|
*/
|
|
186
|
-
export async function ensureNodeJS(
|
|
187
|
-
context: PipelabContext,
|
|
188
|
-
version = DEFAULT_NODE_VERSION,
|
|
189
|
-
) {
|
|
194
|
+
export async function ensureNodeJS(context: PipelabContext, version = DEFAULT_NODE_VERSION) {
|
|
190
195
|
const isWindows = process.platform === "win32";
|
|
191
196
|
const nodeDir = context.getThirdPartyPath("node", version);
|
|
192
197
|
const finalNodePath = join(nodeDir, isWindows ? "node.exe" : "bin/node");
|
|
@@ -234,7 +239,7 @@ export async function ensureNodeJS(
|
|
|
234
239
|
await cp(sourceDir, nodeDir, { recursive: true });
|
|
235
240
|
await rm(tempDir, { recursive: true, force: true });
|
|
236
241
|
|
|
237
|
-
if (!isWindows) await chmod(finalNodePath, 0o755).catch(() => {
|
|
242
|
+
if (!isWindows) await chmod(finalNodePath, 0o755).catch(() => {});
|
|
238
243
|
return finalNodePath;
|
|
239
244
|
});
|
|
240
245
|
}
|
|
@@ -242,10 +247,7 @@ export async function ensureNodeJS(
|
|
|
242
247
|
/**
|
|
243
248
|
* Installs the PNPM package from npm if not already present.
|
|
244
249
|
*/
|
|
245
|
-
export async function ensurePNPM(
|
|
246
|
-
context: PipelabContext,
|
|
247
|
-
version = DEFAULT_PNPM_VERSION,
|
|
248
|
-
) {
|
|
250
|
+
export async function ensurePNPM(context: PipelabContext, version = DEFAULT_PNPM_VERSION) {
|
|
249
251
|
const pnpmDir = context.getPackagesPath("pnpm", version);
|
|
250
252
|
const pnpmPath = join(pnpmDir, "bin", "pnpm.cjs");
|
|
251
253
|
|
|
@@ -271,7 +273,12 @@ async function installDependencies(packageDir: string, packageName: string, opti
|
|
|
271
273
|
try {
|
|
272
274
|
const files = await readdir(nodeModulesPath);
|
|
273
275
|
if (files.length === 0) {
|
|
274
|
-
console.warn(
|
|
276
|
+
console.warn(
|
|
277
|
+
`[Fetcher] ${packageName}: node_modules exists but is empty. Re-installing...`,
|
|
278
|
+
);
|
|
279
|
+
} else {
|
|
280
|
+
console.log(`[Fetcher] ${packageName}: Dependencies already installed, skipping.`);
|
|
281
|
+
return;
|
|
275
282
|
}
|
|
276
283
|
} catch (e) {
|
|
277
284
|
// Continue to install if readdir fails
|
|
@@ -316,17 +323,14 @@ export async function fetchPipelabPlugin(
|
|
|
316
323
|
options: FetchOptions,
|
|
317
324
|
): Promise<{ packageDir: string; entryPoint: string; isLocal: boolean }> {
|
|
318
325
|
const { packageDir, isLocal, entryPoint } = await fetchPackage(pluginName, versionOrRange, {
|
|
319
|
-
installDeps:
|
|
326
|
+
installDeps: false,
|
|
320
327
|
...options,
|
|
321
328
|
});
|
|
322
329
|
|
|
323
330
|
// Default entry point if not provided by fetchPackage
|
|
324
331
|
let finalEntryPoint = entryPoint;
|
|
325
332
|
if (!finalEntryPoint) {
|
|
326
|
-
const patterns = [
|
|
327
|
-
join(packageDir, "dist", "index.mjs"),
|
|
328
|
-
join(packageDir, "index.mjs"),
|
|
329
|
-
];
|
|
333
|
+
const patterns = [join(packageDir, "dist", "index.mjs"), join(packageDir, "index.mjs")];
|
|
330
334
|
finalEntryPoint = patterns.find((p) => existsSync(p)) || patterns[0];
|
|
331
335
|
}
|
|
332
336
|
|
|
@@ -346,10 +350,7 @@ export async function fetchPipelabCli(
|
|
|
346
350
|
// Default entry point for CLI if not provided
|
|
347
351
|
let finalEntryPoint = entryPoint;
|
|
348
352
|
if (!finalEntryPoint) {
|
|
349
|
-
const patterns = [
|
|
350
|
-
join(packageDir, "dist", "index.mjs"),
|
|
351
|
-
join(packageDir, "index.mjs"),
|
|
352
|
-
];
|
|
353
|
+
const patterns = [join(packageDir, "dist", "index.mjs"), join(packageDir, "index.mjs")];
|
|
353
354
|
finalEntryPoint = patterns.find((p) => existsSync(p)) || patterns[0];
|
|
354
355
|
}
|
|
355
356
|
|
|
@@ -387,7 +388,7 @@ async function tryResolveMonorepoPackage(
|
|
|
387
388
|
typeof pkg.bin === "string"
|
|
388
389
|
? pkg.bin
|
|
389
390
|
: pkg.bin?.[packageName.replace("@pipelab/", "")] ||
|
|
390
|
-
|
|
391
|
+
(pkg.bin ? pkg.bin[Object.keys(pkg.bin)[0]] : undefined);
|
|
391
392
|
|
|
392
393
|
// In dev, we prefer the "main" field if it points to TS, or a hardcoded src/index.ts
|
|
393
394
|
const tsSource = join(packageDir, "src", "index.ts");
|
|
@@ -434,11 +435,11 @@ async function crawlMonorepoPackages(): Promise<Record<string, string>> {
|
|
|
434
435
|
if (pkg.name) {
|
|
435
436
|
cache[pkg.name] = join(fullDir, entry.name);
|
|
436
437
|
}
|
|
437
|
-
} catch (e) {
|
|
438
|
+
} catch (e) {}
|
|
438
439
|
}
|
|
439
440
|
}
|
|
440
441
|
}
|
|
441
|
-
} catch (e) {
|
|
442
|
+
} catch (e) {}
|
|
442
443
|
}
|
|
443
444
|
return cache;
|
|
444
445
|
}
|
package/src/utils.ts
CHANGED
|
@@ -256,7 +256,7 @@ export const executeGraphWithHistory = async ({
|
|
|
256
256
|
// Don't await, let it run in the background
|
|
257
257
|
buildHistoryStorage.applyRetentionPolicy();
|
|
258
258
|
}
|
|
259
|
-
|
|
259
|
+
|
|
260
260
|
if (shouldCleanup) {
|
|
261
261
|
try {
|
|
262
262
|
await rm(sandboxPath, { recursive: true, force: true });
|