@pipelab/core-node 1.0.0-beta.0 → 1.0.0-beta.10
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 +80 -0
- package/dist/index.d.mts +36 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +204 -56
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/scratch/simulate-updates.ts +118 -0
- package/src/config.ts +10 -15
- package/src/context.ts +8 -2
- 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/index.ts +1 -0
- package/src/plugins-registry.ts +25 -20
- package/src/runner.ts +28 -22
- package/src/server.ts +4 -2
- package/src/utils/fs-extras.ts +10 -1
- package/src/utils/github.ts +119 -0
- package/src/utils/remote.ts +133 -49
- package/src/utils.ts +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2,13 +2,13 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import path, { delimiter, dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
3
|
import { homedir, platform, tmpdir } from "node:os";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
-
import fs, { createWriteStream, existsSync } from "node:fs";
|
|
5
|
+
import fs, { createWriteStream, existsSync, readdirSync, statSync } from "node:fs";
|
|
6
6
|
import { WebSocket, WebSocketServer as WebSocketServer$1 } from "ws";
|
|
7
7
|
import http from "node:http";
|
|
8
8
|
import { nanoid } from "nanoid";
|
|
9
9
|
import { SubscriptionRequiredError, WebSocketError, appSettingsMigrator, configRegistry, fileRepoMigrations, isRequired, isSupabaseAvailable, isWebSocketRequestMessage, processGraph, savedFileMigrator, supabase, useLogger, usePlugins } from "@pipelab/shared";
|
|
10
10
|
import { getUiDevServerMissingWarning, uiDevPort, websocketPort } from "@pipelab/constants";
|
|
11
|
-
import fs$1, { access, chmod, cp, mkdir, mkdtemp, readFile, readdir, realpath, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
11
|
+
import fs$1, { access, chmod, cp, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
12
12
|
import { execa } from "execa";
|
|
13
13
|
import tar from "tar";
|
|
14
14
|
import yauzl from "yauzl";
|
|
@@ -55,14 +55,16 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
55
55
|
//#region src/context.ts
|
|
56
56
|
const _dirname = typeof __dirname !== "undefined" ? __dirname : typeof import.meta !== "undefined" && import.meta.url ? dirname(fileURLToPath(import.meta.url)) : process.cwd();
|
|
57
57
|
const isDev = process.env.NODE_ENV === "development";
|
|
58
|
-
const getDefaultUserDataPath = () => {
|
|
59
|
-
|
|
58
|
+
const getDefaultUserDataPath = (env) => {
|
|
59
|
+
const base = (() => {
|
|
60
60
|
switch (platform()) {
|
|
61
61
|
case "win32": return process.env.APPDATA || join(homedir(), "AppData", "Roaming");
|
|
62
62
|
case "darwin": return join(homedir(), "Library", "Application Support");
|
|
63
63
|
default: return process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
64
64
|
}
|
|
65
|
-
})()
|
|
65
|
+
})();
|
|
66
|
+
const mode = env ?? (isDev ? "dev" : "prod");
|
|
67
|
+
return join(base, "@pipelab", mode === "dev" ? "app-dev" : mode === "beta" ? "app-beta" : "app");
|
|
66
68
|
};
|
|
67
69
|
/**
|
|
68
70
|
* Finds the monorepo root by looking for pnpm-workspace.yaml.
|
|
@@ -78,8 +80,10 @@ function findProjectRoot(startDir) {
|
|
|
78
80
|
const projectRoot = findProjectRoot(_dirname);
|
|
79
81
|
var PipelabContext = class {
|
|
80
82
|
userDataPath;
|
|
83
|
+
releaseTag;
|
|
81
84
|
constructor(options) {
|
|
82
85
|
this.userDataPath = options.userDataPath;
|
|
86
|
+
this.releaseTag = options.releaseTag || "latest";
|
|
83
87
|
}
|
|
84
88
|
getPackagesPath(...subpaths) {
|
|
85
89
|
return join(this.userDataPath, "packages", ...subpaths);
|
|
@@ -628,25 +632,24 @@ const setupConfigFile = async (name, options) => {
|
|
|
628
632
|
}
|
|
629
633
|
let json = void 0;
|
|
630
634
|
try {
|
|
631
|
-
json = await migrator.migrate(originalJson, {
|
|
635
|
+
json = await migrator.migrate(originalJson, {
|
|
636
|
+
debug: false,
|
|
637
|
+
onStep: async (state, version) => {
|
|
638
|
+
const parsedPath = path.parse(filesPath);
|
|
639
|
+
const versionedPath = path.join(parsedPath.dir, `${parsedPath.name}.v${version}.json`);
|
|
640
|
+
try {
|
|
641
|
+
await fs$1.writeFile(versionedPath, JSON.stringify(state));
|
|
642
|
+
logger().info(`Intermediate backup created for ${name} at ${versionedPath}`);
|
|
643
|
+
} catch (e) {
|
|
644
|
+
logger().error(`Failed to create intermediate backup for ${name} at v${version}:`, e);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
});
|
|
632
648
|
} catch (e) {
|
|
633
649
|
logger().error(`Error migrating config ${name}:`, e);
|
|
634
650
|
json = migrator.defaultValue;
|
|
635
651
|
}
|
|
636
|
-
|
|
637
|
-
const newVersion = json?.version;
|
|
638
|
-
if (originalVersion !== newVersion && content !== void 0) {
|
|
639
|
-
const parsedPath = path.parse(filesPath);
|
|
640
|
-
const versionSuffix = originalVersion || "unknown";
|
|
641
|
-
const backupPath = path.join(parsedPath.dir, `${parsedPath.name}.${versionSuffix}.bak`);
|
|
642
|
-
try {
|
|
643
|
-
await fs$1.copyFile(filesPath, backupPath);
|
|
644
|
-
logger().info(`Backup created for ${name} at ${backupPath} (version ${versionSuffix})`);
|
|
645
|
-
} catch (e) {
|
|
646
|
-
logger().error(`Failed to create backup for ${name}:`, e);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
if (originalVersion !== newVersion || content === void 0) try {
|
|
652
|
+
if (originalJson?.version !== json?.version || content === void 0) try {
|
|
650
653
|
await fs$1.writeFile(filesPath, JSON.stringify(json));
|
|
651
654
|
} catch (e) {
|
|
652
655
|
logger().error(`Error saving migrated config ${name}:`, e);
|
|
@@ -8832,9 +8835,13 @@ const sendStartupReady = () => {
|
|
|
8832
8835
|
};
|
|
8833
8836
|
async function serveCommand(options, version, _dirname) {
|
|
8834
8837
|
if (!options.userData) throw new Error("userDataPath is required for serveCommand");
|
|
8835
|
-
const
|
|
8838
|
+
const releaseTag = version.includes("beta") ? "beta" : "latest";
|
|
8839
|
+
const context = new PipelabContext({
|
|
8840
|
+
userDataPath: options.userData,
|
|
8841
|
+
releaseTag
|
|
8842
|
+
});
|
|
8836
8843
|
let rawAssetFolder;
|
|
8837
|
-
if (!isDev) rawAssetFolder = await fetchPipelabAsset("@pipelab/ui",
|
|
8844
|
+
if (!isDev) rawAssetFolder = await fetchPipelabAsset("@pipelab/ui", releaseTag, { context });
|
|
8838
8845
|
const server = http$1.createServer(async (request, response) => {
|
|
8839
8846
|
if (isDev) {
|
|
8840
8847
|
response.writeHead(200, { "Content-Type": "text/html" });
|
|
@@ -8874,6 +8881,25 @@ async function serveCommand(options, version, _dirname) {
|
|
|
8874
8881
|
//#region src/utils/remote.ts
|
|
8875
8882
|
const DEFAULT_NODE_VERSION = "24.14.1";
|
|
8876
8883
|
const DEFAULT_PNPM_VERSION = "10.12.0";
|
|
8884
|
+
function isPackageComplete(packageDir) {
|
|
8885
|
+
return existsSync(join(packageDir, "package.json"));
|
|
8886
|
+
}
|
|
8887
|
+
function isNodeJSComplete(nodePath) {
|
|
8888
|
+
try {
|
|
8889
|
+
return existsSync(nodePath) && statSync(nodePath).size > 0;
|
|
8890
|
+
} catch {
|
|
8891
|
+
return false;
|
|
8892
|
+
}
|
|
8893
|
+
}
|
|
8894
|
+
function isDependenciesInstalledSync(packageDir) {
|
|
8895
|
+
const nodeModulesPath = join(packageDir, "node_modules");
|
|
8896
|
+
if (!existsSync(nodeModulesPath)) return false;
|
|
8897
|
+
try {
|
|
8898
|
+
return readdirSync(nodeModulesPath).length > 0;
|
|
8899
|
+
} catch {
|
|
8900
|
+
return false;
|
|
8901
|
+
}
|
|
8902
|
+
}
|
|
8877
8903
|
/**
|
|
8878
8904
|
* In-memory lock to prevent concurrent operations on the same resource (e.g., downloading Node.js).
|
|
8879
8905
|
*/
|
|
@@ -8938,15 +8964,35 @@ async function fetchPackage(packageName, versionOrRange, options) {
|
|
|
8938
8964
|
}
|
|
8939
8965
|
const cachePath = join(ctx.userDataPath, "cache", "pacote");
|
|
8940
8966
|
const packageDir = join(baseDir, resolvedVersion);
|
|
8941
|
-
if (
|
|
8967
|
+
if (options?.installDeps ? isPackageComplete(packageDir) && isDependenciesInstalledSync(packageDir) : isPackageComplete(packageDir)) return {
|
|
8942
8968
|
packageDir,
|
|
8943
8969
|
resolvedVersion
|
|
8944
8970
|
};
|
|
8945
8971
|
return withLock(`package:${packageName}:${resolvedVersion}`, async () => {
|
|
8946
|
-
if (!
|
|
8972
|
+
if (!isPackageComplete(packageDir)) {
|
|
8947
8973
|
console.log(`[Fetcher] ${packageName}@${resolvedVersion}: Downloading to ${packageDir}...`);
|
|
8948
|
-
|
|
8949
|
-
await
|
|
8974
|
+
const tempDir = join(baseDir, `.tmp-${resolvedVersion}-${Math.random().toString(36).slice(2)}`);
|
|
8975
|
+
await mkdir(tempDir, { recursive: true });
|
|
8976
|
+
try {
|
|
8977
|
+
await pacote.extract(`${packageName}@${resolvedVersion}`, tempDir, { cache: cachePath });
|
|
8978
|
+
await resolveEntryPoint(tempDir, packageName);
|
|
8979
|
+
if (existsSync(packageDir)) await rm(packageDir, {
|
|
8980
|
+
recursive: true,
|
|
8981
|
+
force: true
|
|
8982
|
+
}).catch(() => {});
|
|
8983
|
+
try {
|
|
8984
|
+
await rename(tempDir, packageDir);
|
|
8985
|
+
} catch (err) {
|
|
8986
|
+
if (isPackageComplete(packageDir)) console.log(`[Fetcher] Destination ${packageDir} already exists and is valid.`);
|
|
8987
|
+
else throw err;
|
|
8988
|
+
}
|
|
8989
|
+
} catch (err) {
|
|
8990
|
+
await rm(tempDir, {
|
|
8991
|
+
recursive: true,
|
|
8992
|
+
force: true
|
|
8993
|
+
}).catch(() => {});
|
|
8994
|
+
throw err;
|
|
8995
|
+
}
|
|
8950
8996
|
}
|
|
8951
8997
|
const entryPoint = await resolveEntryPoint(packageDir, packageName);
|
|
8952
8998
|
if (options?.installDeps) await installDependencies(packageDir, packageName, options);
|
|
@@ -8991,9 +9037,9 @@ async function ensureNodeJS(context, version = DEFAULT_NODE_VERSION) {
|
|
|
8991
9037
|
const isWindows = process.platform === "win32";
|
|
8992
9038
|
const nodeDir = context.getThirdPartyPath("node", version);
|
|
8993
9039
|
const finalNodePath = join(nodeDir, isWindows ? "node.exe" : "bin/node");
|
|
8994
|
-
if (
|
|
9040
|
+
if (isNodeJSComplete(finalNodePath)) return finalNodePath;
|
|
8995
9041
|
return withLock(`node:${version}`, async () => {
|
|
8996
|
-
if (
|
|
9042
|
+
if (isNodeJSComplete(finalNodePath)) return finalNodePath;
|
|
8997
9043
|
const arch = process.arch === "x64" ? "x64" : process.arch === "arm64" ? "arm64" : "x86";
|
|
8998
9044
|
const platform = isWindows ? "win" : process.platform === "darwin" ? "osx" : "linux";
|
|
8999
9045
|
const extension = isWindows ? "zip" : "tar.gz";
|
|
@@ -9013,17 +9059,33 @@ async function ensureNodeJS(context, version = DEFAULT_NODE_VERSION) {
|
|
|
9013
9059
|
const nodeSubDir = (await readdir(extractTempDir)).find((entry) => entry.startsWith(`node-v${version}`));
|
|
9014
9060
|
if (!nodeSubDir) throw new Error(`Could not find extracted Node.js directory`);
|
|
9015
9061
|
const sourceDir = join(extractTempDir, nodeSubDir);
|
|
9016
|
-
|
|
9017
|
-
await
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9062
|
+
const parentDir = dirname(nodeDir);
|
|
9063
|
+
await mkdir(parentDir, { recursive: true });
|
|
9064
|
+
const tempNodeDir = join(parentDir, `.tmp-node-${version}-${Math.random().toString(36).slice(2)}`);
|
|
9065
|
+
await mkdir(tempNodeDir, { recursive: true });
|
|
9066
|
+
try {
|
|
9067
|
+
await cp(sourceDir, tempNodeDir, { recursive: true });
|
|
9068
|
+
if (!isWindows) await chmod(join(tempNodeDir, "bin/node"), 493).catch(() => {});
|
|
9069
|
+
if (existsSync(nodeDir)) await rm(nodeDir, {
|
|
9070
|
+
recursive: true,
|
|
9071
|
+
force: true
|
|
9072
|
+
}).catch(() => {});
|
|
9073
|
+
try {
|
|
9074
|
+
await rename(tempNodeDir, nodeDir);
|
|
9075
|
+
} catch (err) {
|
|
9076
|
+
if (isNodeJSComplete(finalNodePath)) console.log(`[Fetcher] Node.js directory already exists and is valid.`);
|
|
9077
|
+
else throw err;
|
|
9078
|
+
}
|
|
9079
|
+
} finally {
|
|
9080
|
+
await rm(tempNodeDir, {
|
|
9081
|
+
recursive: true,
|
|
9082
|
+
force: true
|
|
9083
|
+
}).catch(() => {});
|
|
9084
|
+
await rm(tempDir, {
|
|
9085
|
+
recursive: true,
|
|
9086
|
+
force: true
|
|
9087
|
+
}).catch(() => {});
|
|
9088
|
+
}
|
|
9027
9089
|
return finalNodePath;
|
|
9028
9090
|
});
|
|
9029
9091
|
}
|
|
@@ -9042,21 +9104,36 @@ async function ensurePNPM(context, version = DEFAULT_PNPM_VERSION) {
|
|
|
9042
9104
|
}
|
|
9043
9105
|
async function installDependencies(packageDir, packageName, options) {
|
|
9044
9106
|
const nodeModulesPath = join(packageDir, "node_modules");
|
|
9045
|
-
if (
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
|
|
9107
|
+
if (isDependenciesInstalledSync(packageDir)) {
|
|
9108
|
+
console.log(`[Fetcher] ${packageName}: Dependencies already installed, skipping.`);
|
|
9109
|
+
return;
|
|
9110
|
+
}
|
|
9111
|
+
const tempDir = `${packageDir}.tmp-deps-${Math.random().toString(36).slice(2)}`;
|
|
9112
|
+
await mkdir(tempDir, { recursive: true });
|
|
9049
9113
|
try {
|
|
9050
|
-
|
|
9114
|
+
await cp(join(packageDir, "package.json"), join(tempDir, "package.json"));
|
|
9115
|
+
console.log(`[Fetcher] ${packageName}: Ensuring dependencies are installed...`);
|
|
9116
|
+
const { all } = await runPnpm(tempDir, {
|
|
9051
9117
|
signal: options.signal,
|
|
9052
9118
|
context: options.context
|
|
9053
9119
|
});
|
|
9054
9120
|
if (all) console.log(`[Fetcher] ${packageName}: Installation trace:\n${all}`);
|
|
9121
|
+
const tempNodeModules = join(tempDir, "node_modules");
|
|
9122
|
+
if (existsSync(nodeModulesPath)) await rm(nodeModulesPath, {
|
|
9123
|
+
recursive: true,
|
|
9124
|
+
force: true
|
|
9125
|
+
}).catch(() => {});
|
|
9126
|
+
await rename(tempNodeModules, nodeModulesPath);
|
|
9055
9127
|
console.log(`[Fetcher] ${packageName}: Dependencies installed successfully.`);
|
|
9056
9128
|
} catch (err) {
|
|
9057
9129
|
console.error(`[Fetcher] ${packageName}: CRITICAL ERROR during dependency installation: ${err.message}`);
|
|
9058
9130
|
if (err.all) console.error(`[Fetcher] ${packageName}: Error details:\n${err.all}`);
|
|
9059
9131
|
throw new Error(`Failed to install dependencies for ${packageName}. See logs for details.`);
|
|
9132
|
+
} finally {
|
|
9133
|
+
await rm(tempDir, {
|
|
9134
|
+
recursive: true,
|
|
9135
|
+
force: true
|
|
9136
|
+
}).catch(() => {});
|
|
9060
9137
|
}
|
|
9061
9138
|
}
|
|
9062
9139
|
async function fetchPipelabAsset(packageName, versionOrRange, options) {
|
|
@@ -9069,7 +9146,7 @@ async function fetchPipelabAsset(packageName, versionOrRange, options) {
|
|
|
9069
9146
|
}
|
|
9070
9147
|
async function fetchPipelabPlugin(pluginName, versionOrRange, options) {
|
|
9071
9148
|
const { packageDir, isLocal, entryPoint } = await fetchPackage(pluginName, versionOrRange, {
|
|
9072
|
-
installDeps:
|
|
9149
|
+
installDeps: false,
|
|
9073
9150
|
...options
|
|
9074
9151
|
});
|
|
9075
9152
|
let finalEntryPoint = entryPoint;
|
|
@@ -9343,9 +9420,9 @@ const DEFAULT_PLUGIN_IDS = [
|
|
|
9343
9420
|
];
|
|
9344
9421
|
const loadPipelabPlugin = async (id, options) => {
|
|
9345
9422
|
try {
|
|
9346
|
-
const { packageDir, entryPoint } = await fetchPipelabPlugin(`@pipelab/plugin-${id}`,
|
|
9423
|
+
const { packageDir, entryPoint } = await fetchPipelabPlugin(`@pipelab/plugin-${id}`, options.context.releaseTag, {
|
|
9347
9424
|
context: options.context,
|
|
9348
|
-
installDeps:
|
|
9425
|
+
installDeps: false
|
|
9349
9426
|
});
|
|
9350
9427
|
console.log(`[Plugins] [${id}] Attempting to import from: ${entryPoint}`);
|
|
9351
9428
|
if (!existsSync(entryPoint)) {
|
|
@@ -9365,15 +9442,28 @@ const loadPipelabPlugin = async (id, options) => {
|
|
|
9365
9442
|
}
|
|
9366
9443
|
};
|
|
9367
9444
|
const builtInPlugins = async (options) => {
|
|
9368
|
-
console.log("[Plugins]
|
|
9445
|
+
console.log("[Plugins] Starting background plugin loading...");
|
|
9369
9446
|
sendStartupProgress("Preparing environment...");
|
|
9370
9447
|
await Promise.all([ensureNodeJS(options.context), ensurePNPM(options.context)]);
|
|
9371
|
-
const
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9448
|
+
const { usePlugins } = await import("@pipelab/shared");
|
|
9449
|
+
const { registerPlugins } = usePlugins();
|
|
9450
|
+
const { webSocketServer } = await import("./index.mjs");
|
|
9451
|
+
(async () => {
|
|
9452
|
+
for (const id of DEFAULT_PLUGIN_IDS) {
|
|
9453
|
+
sendStartupProgress(`Loading plugin: ${id}`);
|
|
9454
|
+
const plugin = await loadPipelabPlugin(id, options);
|
|
9455
|
+
if (plugin) {
|
|
9456
|
+
registerPlugins([plugin]);
|
|
9457
|
+
webSocketServer.broadcast("plugin:loaded", { plugin });
|
|
9458
|
+
}
|
|
9459
|
+
}
|
|
9460
|
+
console.log("[Plugins] All default plugins loaded.");
|
|
9461
|
+
sendStartupProgress("All plugins loaded.");
|
|
9462
|
+
setTimeout(() => {
|
|
9463
|
+
webSocketServer.broadcast("startup:progress", { type: "ready" });
|
|
9464
|
+
}, 2e3);
|
|
9465
|
+
})();
|
|
9466
|
+
return [];
|
|
9377
9467
|
};
|
|
9378
9468
|
//#endregion
|
|
9379
9469
|
//#region src/utils.ts
|
|
@@ -10268,7 +10358,7 @@ const registerAllHandlers = async (options) => {
|
|
|
10268
10358
|
registerAuthHandlers(context);
|
|
10269
10359
|
registerSystemHandlers(options);
|
|
10270
10360
|
const { registerPlugins } = usePlugins();
|
|
10271
|
-
|
|
10361
|
+
builtInPlugins({ context });
|
|
10272
10362
|
};
|
|
10273
10363
|
//#endregion
|
|
10274
10364
|
//#region ../../node_modules/klona/dist/index.mjs
|
|
@@ -52607,6 +52697,64 @@ async function runPipelineCommand(file, options, version) {
|
|
|
52607
52697
|
}
|
|
52608
52698
|
}
|
|
52609
52699
|
//#endregion
|
|
52610
|
-
|
|
52700
|
+
//#region src/utils/github.ts
|
|
52701
|
+
/**
|
|
52702
|
+
* Fetches all releases for a specific package from GitHub.
|
|
52703
|
+
* Tags are expected to follow the pattern "{packageName}@{version}"
|
|
52704
|
+
*/
|
|
52705
|
+
async function fetchPackageReleases(packageName, options = {}) {
|
|
52706
|
+
const { repo = "CynToolkit/pipelab", allowPrerelease = false } = options;
|
|
52707
|
+
const url = `https://api.github.com/repos/${repo}/releases`;
|
|
52708
|
+
console.log(`[GitHub] Fetching releases for ${packageName} from ${url}...`);
|
|
52709
|
+
try {
|
|
52710
|
+
const response = await fetch(url, { headers: {
|
|
52711
|
+
"User-Agent": "Pipelab-Desktop-Updater",
|
|
52712
|
+
Accept: "application/vnd.github.v3+json"
|
|
52713
|
+
} });
|
|
52714
|
+
if (!response.ok) throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
52715
|
+
return (await response.json()).filter((r) => r.tag_name.startsWith(`${packageName}@`)).filter((r) => allowPrerelease || !r.prerelease);
|
|
52716
|
+
} catch (error) {
|
|
52717
|
+
console.error(`[GitHub] Failed to fetch releases for ${packageName}:`, error);
|
|
52718
|
+
return [];
|
|
52719
|
+
}
|
|
52720
|
+
}
|
|
52721
|
+
/**
|
|
52722
|
+
* Fetches the latest release for a specific package.
|
|
52723
|
+
* Supports PIPELAB_OVERRIDE_RELEASE environment variable.
|
|
52724
|
+
*/
|
|
52725
|
+
async function fetchLatestPackageRelease(packageName, options = {}) {
|
|
52726
|
+
const releases = await fetchPackageReleases(packageName, options);
|
|
52727
|
+
if (releases.length === 0) return null;
|
|
52728
|
+
const override = process.env.PIPELAB_OVERRIDE_RELEASE;
|
|
52729
|
+
if (override) {
|
|
52730
|
+
const targetTag = override.includes("@") ? override : `${packageName}@${override}`;
|
|
52731
|
+
const release = releases.find((r) => r.tag_name === targetTag);
|
|
52732
|
+
if (release) {
|
|
52733
|
+
console.log(`[GitHub] Using release override from PIPELAB_OVERRIDE_RELEASE: ${release.tag_name}`);
|
|
52734
|
+
return release;
|
|
52735
|
+
}
|
|
52736
|
+
console.warn(`[GitHub] Override release ${override} not found for package ${packageName}`);
|
|
52737
|
+
}
|
|
52738
|
+
const getVersion = (tagName) => tagName.split("@").pop() || "0.0.0";
|
|
52739
|
+
releases.sort((a, b) => {
|
|
52740
|
+
const vA = getVersion(a.tag_name);
|
|
52741
|
+
const vB = getVersion(b.tag_name);
|
|
52742
|
+
if (semver.valid(vA) && semver.valid(vB)) return semver.rcompare(vA, vB);
|
|
52743
|
+
return new Date(b.published_at).getTime() - new Date(a.published_at).getTime();
|
|
52744
|
+
});
|
|
52745
|
+
return releases[0];
|
|
52746
|
+
}
|
|
52747
|
+
/**
|
|
52748
|
+
* Fetches all releases from GitHub and finds the latest one that matches the Pipelab Desktop app tag.
|
|
52749
|
+
* This ensures we don't accidentally pick a package release (e.g. @pipelab/shared) as the "latest".
|
|
52750
|
+
*/
|
|
52751
|
+
async function fetchLatestDesktopRelease(options = {}) {
|
|
52752
|
+
const latest = await fetchLatestPackageRelease("@pipelab/app", options);
|
|
52753
|
+
if (latest) console.log(`[GitHub] Found latest desktop release: ${latest.tag_name} (${latest.prerelease ? "pre-release" : "stable"})`);
|
|
52754
|
+
else console.warn(`[GitHub] No desktop releases found`);
|
|
52755
|
+
return latest;
|
|
52756
|
+
}
|
|
52757
|
+
//#endregion
|
|
52758
|
+
export { BuildHistoryStorage, DEFAULT_NODE_VERSION, DEFAULT_PNPM_VERSION, PipelabContext, WebSocketServer, builtInPlugins, downloadFile, ensure, ensureNodeJS, ensurePNPM, executeGraphWithHistory, extractTarGz, extractZip, fetchLatestDesktopRelease, fetchLatestPackageRelease, fetchPackage, fetchPackageReleases, fetchPipelabAsset, fetchPipelabCli, fetchPipelabPlugin, generateTempFolder, getDefaultUserDataPath, getFinalPlugins, getFolderSize, getMigrator, handleActionExecute, handleConditionExecute, isDev, loadPipelabPlugin, projectRoot, registerAgentsHandlers, registerAllHandlers, registerConfigHandlers, registerEngineHandlers, registerFsHandlers, registerHistoryHandlers, registerMigrationHandlers, registerShellHandlers, runPipelineCommand, runPnpm, runWithLiveLogs, sendStartupProgress, sendStartupReady, serveCommand, setupConfigFile, useAPI, usePluginAPI, webSocketServer, zipFolder };
|
|
52611
52759
|
|
|
52612
52760
|
//# sourceMappingURL=index.mjs.map
|