@chrysb/alphaclaw 0.8.7-beta.0 → 0.8.7-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/bin/alphaclaw.js +110 -7
- package/lib/server/alphaclaw-runtime.js +180 -0
- package/lib/server/alphaclaw-version.js +7 -1
- package/lib/server/openclaw-runtime.js +260 -0
- package/lib/server/pending-alphaclaw-update.js +10 -11
- package/lib/server/pending-openclaw-update.js +11 -11
- package/package.json +1 -1
package/bin/alphaclaw.js
CHANGED
|
@@ -16,9 +16,19 @@ const {
|
|
|
16
16
|
const {
|
|
17
17
|
applyPendingAlphaclawUpdate,
|
|
18
18
|
} = require("../lib/server/pending-alphaclaw-update");
|
|
19
|
+
const {
|
|
20
|
+
getManagedAlphaclawCliPath,
|
|
21
|
+
getManagedAlphaclawRuntimeDir,
|
|
22
|
+
syncManagedAlphaclawRuntimeWithBundled,
|
|
23
|
+
} = require("../lib/server/alphaclaw-runtime");
|
|
19
24
|
const {
|
|
20
25
|
applyPendingOpenclawUpdate,
|
|
21
26
|
} = require("../lib/server/pending-openclaw-update");
|
|
27
|
+
const {
|
|
28
|
+
getManagedOpenclawRuntimeDir,
|
|
29
|
+
prependManagedOpenclawBinToPath,
|
|
30
|
+
syncManagedOpenclawRuntimeWithBundled,
|
|
31
|
+
} = require("../lib/server/openclaw-runtime");
|
|
22
32
|
|
|
23
33
|
const kUsageTrackerPluginPath = path.resolve(
|
|
24
34
|
__dirname,
|
|
@@ -168,10 +178,89 @@ if (portFlag) {
|
|
|
168
178
|
process.env.PORT = portFlag;
|
|
169
179
|
}
|
|
170
180
|
|
|
181
|
+
const kManagedAlphaclawRuntimeEnvFlag = "ALPHACLAW_MANAGED_RUNTIME_ACTIVE";
|
|
182
|
+
const shouldBootstrapManagedAlphaclawRuntime =
|
|
183
|
+
command === "start" &&
|
|
184
|
+
process.env[kManagedAlphaclawRuntimeEnvFlag] !== "1";
|
|
185
|
+
|
|
171
186
|
// ---------------------------------------------------------------------------
|
|
172
187
|
// 2. Create directory structure
|
|
173
188
|
// ---------------------------------------------------------------------------
|
|
174
189
|
|
|
190
|
+
if (shouldBootstrapManagedAlphaclawRuntime) {
|
|
191
|
+
const { spawn } = require("child_process");
|
|
192
|
+
const managedAlphaclawRuntimeDir = getManagedAlphaclawRuntimeDir({ rootDir });
|
|
193
|
+
const pendingUpdateMarker = path.join(rootDir, ".alphaclaw-update-pending");
|
|
194
|
+
if (fs.existsSync(pendingUpdateMarker)) {
|
|
195
|
+
applyPendingAlphaclawUpdate({
|
|
196
|
+
execSyncImpl: execSync,
|
|
197
|
+
fsModule: fs,
|
|
198
|
+
installDir: managedAlphaclawRuntimeDir,
|
|
199
|
+
logger: console,
|
|
200
|
+
markerPath: pendingUpdateMarker,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
syncManagedAlphaclawRuntimeWithBundled({
|
|
205
|
+
execSyncImpl: execSync,
|
|
206
|
+
fsModule: fs,
|
|
207
|
+
logger: console,
|
|
208
|
+
runtimeDir: managedAlphaclawRuntimeDir,
|
|
209
|
+
});
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.log(
|
|
212
|
+
`[alphaclaw] Could not sync managed AlphaClaw runtime from bundled install: ${error.message}`,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const managedAlphaclawCliPath = getManagedAlphaclawCliPath({
|
|
217
|
+
runtimeDir: managedAlphaclawRuntimeDir,
|
|
218
|
+
});
|
|
219
|
+
if (!fs.existsSync(managedAlphaclawCliPath)) {
|
|
220
|
+
console.error(
|
|
221
|
+
`[alphaclaw] Managed AlphaClaw runtime missing CLI at ${managedAlphaclawCliPath}`,
|
|
222
|
+
);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const runtimeChild = spawn(
|
|
227
|
+
process.argv[0],
|
|
228
|
+
[managedAlphaclawCliPath, ...process.argv.slice(2)],
|
|
229
|
+
{
|
|
230
|
+
stdio: "inherit",
|
|
231
|
+
env: {
|
|
232
|
+
...process.env,
|
|
233
|
+
[kManagedAlphaclawRuntimeEnvFlag]: "1",
|
|
234
|
+
ALPHACLAW_BOOTSTRAP_CLI_PATH: __filename,
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const forwardSignal = (signal) => {
|
|
240
|
+
if (runtimeChild.exitCode === null && !runtimeChild.killed) {
|
|
241
|
+
runtimeChild.kill(signal);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
process.on("SIGTERM", () => forwardSignal("SIGTERM"));
|
|
246
|
+
process.on("SIGINT", () => forwardSignal("SIGINT"));
|
|
247
|
+
|
|
248
|
+
runtimeChild.on("error", (error) => {
|
|
249
|
+
console.error(
|
|
250
|
+
`[alphaclaw] Managed AlphaClaw runtime launch failed: ${error.message}`,
|
|
251
|
+
);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
runtimeChild.on("exit", (code, signal) => {
|
|
256
|
+
if (signal) {
|
|
257
|
+
process.kill(process.pid, signal);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
process.exit(Number.isInteger(code) ? code : 0);
|
|
261
|
+
});
|
|
262
|
+
} else {
|
|
263
|
+
|
|
175
264
|
const openclawDir = path.join(rootDir, ".openclaw");
|
|
176
265
|
fs.mkdirSync(openclawDir, { recursive: true });
|
|
177
266
|
const { hourlyGitSyncPath } = migrateManagedInternalFiles({
|
|
@@ -206,21 +295,34 @@ if (fs.existsSync(pendingUpdateMarker)) {
|
|
|
206
295
|
}
|
|
207
296
|
|
|
208
297
|
const pendingOpenclawUpdateMarker = path.join(rootDir, ".openclaw-update-pending");
|
|
298
|
+
const managedOpenclawRuntimeDir = getManagedOpenclawRuntimeDir({ rootDir });
|
|
209
299
|
if (fs.existsSync(pendingOpenclawUpdateMarker)) {
|
|
210
|
-
const alphaPkgRoot = path.resolve(__dirname, "..");
|
|
211
|
-
const nmIndex = alphaPkgRoot.lastIndexOf(
|
|
212
|
-
`${path.sep}node_modules${path.sep}`,
|
|
213
|
-
);
|
|
214
|
-
const installDir =
|
|
215
|
-
nmIndex >= 0 ? alphaPkgRoot.slice(0, nmIndex) : alphaPkgRoot;
|
|
216
300
|
applyPendingOpenclawUpdate({
|
|
217
301
|
execSyncImpl: execSync,
|
|
218
302
|
fsModule: fs,
|
|
219
|
-
installDir,
|
|
303
|
+
installDir: managedOpenclawRuntimeDir,
|
|
220
304
|
logger: console,
|
|
221
305
|
markerPath: pendingOpenclawUpdateMarker,
|
|
222
306
|
});
|
|
223
307
|
}
|
|
308
|
+
try {
|
|
309
|
+
syncManagedOpenclawRuntimeWithBundled({
|
|
310
|
+
execSyncImpl: execSync,
|
|
311
|
+
fsModule: fs,
|
|
312
|
+
logger: console,
|
|
313
|
+
runtimeDir: managedOpenclawRuntimeDir,
|
|
314
|
+
});
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.log(
|
|
317
|
+
`[alphaclaw] Could not sync managed OpenClaw runtime from bundled install: ${error.message}`,
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
prependManagedOpenclawBinToPath({
|
|
321
|
+
env: process.env,
|
|
322
|
+
fsModule: fs,
|
|
323
|
+
logger: console,
|
|
324
|
+
runtimeDir: managedOpenclawRuntimeDir,
|
|
325
|
+
});
|
|
224
326
|
|
|
225
327
|
// ---------------------------------------------------------------------------
|
|
226
328
|
// 3. Symlink ~/.openclaw -> <root>/.openclaw
|
|
@@ -934,3 +1036,4 @@ try {
|
|
|
934
1036
|
|
|
935
1037
|
console.log("[alphaclaw] Setup complete -- starting server");
|
|
936
1038
|
require("../lib/server.js");
|
|
1039
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
const { kRootDir } = require("./constants");
|
|
5
|
+
const { compareVersionParts } = require("./helpers");
|
|
6
|
+
|
|
7
|
+
const getManagedAlphaclawRuntimeDir = ({ rootDir = kRootDir } = {}) =>
|
|
8
|
+
path.join(rootDir, ".alphaclaw-runtime");
|
|
9
|
+
|
|
10
|
+
const getManagedAlphaclawCliPath = ({ runtimeDir } = {}) =>
|
|
11
|
+
path.join(
|
|
12
|
+
runtimeDir || getManagedAlphaclawRuntimeDir(),
|
|
13
|
+
"node_modules",
|
|
14
|
+
"@chrysb",
|
|
15
|
+
"alphaclaw",
|
|
16
|
+
"bin",
|
|
17
|
+
"alphaclaw.js",
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const getManagedAlphaclawPackageJsonPath = ({ runtimeDir } = {}) =>
|
|
21
|
+
path.join(
|
|
22
|
+
runtimeDir || getManagedAlphaclawRuntimeDir(),
|
|
23
|
+
"node_modules",
|
|
24
|
+
"@chrysb",
|
|
25
|
+
"alphaclaw",
|
|
26
|
+
"package.json",
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const ensureManagedAlphaclawRuntimeProject = ({
|
|
30
|
+
fsModule = fs,
|
|
31
|
+
runtimeDir,
|
|
32
|
+
} = {}) => {
|
|
33
|
+
const resolvedRuntimeDir = runtimeDir || getManagedAlphaclawRuntimeDir();
|
|
34
|
+
const packageJsonPath = path.join(resolvedRuntimeDir, "package.json");
|
|
35
|
+
fsModule.mkdirSync(resolvedRuntimeDir, { recursive: true });
|
|
36
|
+
if (!fsModule.existsSync(packageJsonPath)) {
|
|
37
|
+
fsModule.writeFileSync(
|
|
38
|
+
packageJsonPath,
|
|
39
|
+
JSON.stringify(
|
|
40
|
+
{
|
|
41
|
+
name: "alphaclaw-runtime",
|
|
42
|
+
private: true,
|
|
43
|
+
},
|
|
44
|
+
null,
|
|
45
|
+
2,
|
|
46
|
+
),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
runtimeDir: resolvedRuntimeDir,
|
|
51
|
+
packageJsonPath,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const readManagedAlphaclawRuntimeVersion = ({
|
|
56
|
+
fsModule = fs,
|
|
57
|
+
runtimeDir,
|
|
58
|
+
} = {}) => {
|
|
59
|
+
try {
|
|
60
|
+
const pkg = JSON.parse(
|
|
61
|
+
fsModule.readFileSync(
|
|
62
|
+
getManagedAlphaclawPackageJsonPath({ runtimeDir }),
|
|
63
|
+
"utf8",
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
return String(pkg?.version || "").trim() || null;
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const readBundledAlphaclawVersion = ({
|
|
73
|
+
fsModule = fs,
|
|
74
|
+
packageJsonPath = path.resolve(__dirname, "..", "..", "package.json"),
|
|
75
|
+
} = {}) => {
|
|
76
|
+
try {
|
|
77
|
+
const pkg = JSON.parse(fsModule.readFileSync(packageJsonPath, "utf8"));
|
|
78
|
+
return String(pkg?.version || "").trim() || null;
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const shellQuote = (value) =>
|
|
85
|
+
`'${String(value || "").replace(/'/g, `'\"'\"'`)}'`;
|
|
86
|
+
|
|
87
|
+
const installManagedAlphaclawRuntime = ({
|
|
88
|
+
execSyncImpl,
|
|
89
|
+
fsModule = fs,
|
|
90
|
+
runtimeDir,
|
|
91
|
+
spec,
|
|
92
|
+
} = {}) => {
|
|
93
|
+
const normalizedSpec =
|
|
94
|
+
String(spec || "").trim() || "@chrysb/alphaclaw@latest";
|
|
95
|
+
ensureManagedAlphaclawRuntimeProject({
|
|
96
|
+
fsModule,
|
|
97
|
+
runtimeDir,
|
|
98
|
+
});
|
|
99
|
+
execSyncImpl(
|
|
100
|
+
`npm install ${shellQuote(normalizedSpec)} --omit=dev --no-save --save=false --package-lock=false --prefer-online`,
|
|
101
|
+
{
|
|
102
|
+
cwd: runtimeDir,
|
|
103
|
+
stdio: "inherit",
|
|
104
|
+
timeout: 180000,
|
|
105
|
+
},
|
|
106
|
+
);
|
|
107
|
+
return {
|
|
108
|
+
spec: normalizedSpec,
|
|
109
|
+
version: readManagedAlphaclawRuntimeVersion({
|
|
110
|
+
fsModule,
|
|
111
|
+
runtimeDir,
|
|
112
|
+
}),
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const syncManagedAlphaclawRuntimeWithBundled = ({
|
|
117
|
+
execSyncImpl,
|
|
118
|
+
fsModule = fs,
|
|
119
|
+
logger = console,
|
|
120
|
+
runtimeDir,
|
|
121
|
+
packageJsonPath,
|
|
122
|
+
} = {}) => {
|
|
123
|
+
const bundledVersion = readBundledAlphaclawVersion({
|
|
124
|
+
fsModule,
|
|
125
|
+
packageJsonPath,
|
|
126
|
+
});
|
|
127
|
+
if (!bundledVersion) {
|
|
128
|
+
return {
|
|
129
|
+
checked: false,
|
|
130
|
+
synced: false,
|
|
131
|
+
bundledVersion: null,
|
|
132
|
+
runtimeVersion: readManagedAlphaclawRuntimeVersion({
|
|
133
|
+
fsModule,
|
|
134
|
+
runtimeDir,
|
|
135
|
+
}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const runtimeVersion = readManagedAlphaclawRuntimeVersion({
|
|
140
|
+
fsModule,
|
|
141
|
+
runtimeDir,
|
|
142
|
+
});
|
|
143
|
+
if (runtimeVersion && compareVersionParts(runtimeVersion, bundledVersion) >= 0) {
|
|
144
|
+
return {
|
|
145
|
+
checked: true,
|
|
146
|
+
synced: false,
|
|
147
|
+
bundledVersion,
|
|
148
|
+
runtimeVersion,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
logger.log(
|
|
153
|
+
runtimeVersion
|
|
154
|
+
? `[alphaclaw] Managed AlphaClaw runtime ${runtimeVersion} is older than bundled ${bundledVersion}; syncing runtime...`
|
|
155
|
+
: `[alphaclaw] Managed AlphaClaw runtime missing; seeding bundled AlphaClaw ${bundledVersion}...`,
|
|
156
|
+
);
|
|
157
|
+
const installResult = installManagedAlphaclawRuntime({
|
|
158
|
+
execSyncImpl,
|
|
159
|
+
fsModule,
|
|
160
|
+
runtimeDir,
|
|
161
|
+
spec: `@chrysb/alphaclaw@${bundledVersion}`,
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
checked: true,
|
|
165
|
+
synced: true,
|
|
166
|
+
bundledVersion,
|
|
167
|
+
runtimeVersion: installResult.version || bundledVersion,
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
module.exports = {
|
|
172
|
+
ensureManagedAlphaclawRuntimeProject,
|
|
173
|
+
getManagedAlphaclawCliPath,
|
|
174
|
+
getManagedAlphaclawPackageJsonPath,
|
|
175
|
+
getManagedAlphaclawRuntimeDir,
|
|
176
|
+
installManagedAlphaclawRuntime,
|
|
177
|
+
readBundledAlphaclawVersion,
|
|
178
|
+
readManagedAlphaclawRuntimeVersion,
|
|
179
|
+
syncManagedAlphaclawRuntimeWithBundled,
|
|
180
|
+
};
|
|
@@ -126,9 +126,15 @@ const createAlphaclawVersionService = () => {
|
|
|
126
126
|
// On bare metal / Mac / Linux, spawn a replacement process then exit.
|
|
127
127
|
console.log("[alphaclaw] Spawning new process and exiting...");
|
|
128
128
|
const { spawn } = require("child_process");
|
|
129
|
-
const
|
|
129
|
+
const nextEnv = { ...process.env };
|
|
130
|
+
delete nextEnv.ALPHACLAW_MANAGED_RUNTIME_ACTIVE;
|
|
131
|
+
const bootstrapCliPath =
|
|
132
|
+
String(process.env.ALPHACLAW_BOOTSTRAP_CLI_PATH || "").trim() ||
|
|
133
|
+
process.argv[1];
|
|
134
|
+
const child = spawn(process.argv[0], [bootstrapCliPath, ...process.argv.slice(2)], {
|
|
130
135
|
detached: true,
|
|
131
136
|
stdio: "inherit",
|
|
137
|
+
env: nextEnv,
|
|
132
138
|
});
|
|
133
139
|
child.unref();
|
|
134
140
|
process.exit(0);
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
const { kRootDir } = require("./constants");
|
|
5
|
+
const {
|
|
6
|
+
compareVersionParts,
|
|
7
|
+
normalizeOpenclawVersion,
|
|
8
|
+
} = require("./helpers");
|
|
9
|
+
|
|
10
|
+
const getManagedOpenclawRuntimeDir = ({ rootDir = kRootDir } = {}) =>
|
|
11
|
+
path.join(rootDir, ".openclaw-runtime");
|
|
12
|
+
|
|
13
|
+
const getManagedOpenclawBinDir = ({ runtimeDir } = {}) =>
|
|
14
|
+
path.join(
|
|
15
|
+
runtimeDir || getManagedOpenclawRuntimeDir(),
|
|
16
|
+
"node_modules",
|
|
17
|
+
".bin",
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const getManagedOpenclawBinPath = ({ runtimeDir } = {}) =>
|
|
21
|
+
path.join(getManagedOpenclawBinDir({ runtimeDir }), "openclaw");
|
|
22
|
+
|
|
23
|
+
const getManagedOpenclawPackageJsonPath = ({ runtimeDir } = {}) =>
|
|
24
|
+
path.join(
|
|
25
|
+
runtimeDir || getManagedOpenclawRuntimeDir(),
|
|
26
|
+
"node_modules",
|
|
27
|
+
"openclaw",
|
|
28
|
+
"package.json",
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const ensureManagedOpenclawRuntimeProject = ({
|
|
32
|
+
fsModule = fs,
|
|
33
|
+
runtimeDir,
|
|
34
|
+
} = {}) => {
|
|
35
|
+
const resolvedRuntimeDir = runtimeDir || getManagedOpenclawRuntimeDir();
|
|
36
|
+
const packageJsonPath = path.join(resolvedRuntimeDir, "package.json");
|
|
37
|
+
fsModule.mkdirSync(resolvedRuntimeDir, { recursive: true });
|
|
38
|
+
if (!fsModule.existsSync(packageJsonPath)) {
|
|
39
|
+
fsModule.writeFileSync(
|
|
40
|
+
packageJsonPath,
|
|
41
|
+
JSON.stringify(
|
|
42
|
+
{
|
|
43
|
+
name: "alphaclaw-openclaw-runtime",
|
|
44
|
+
private: true,
|
|
45
|
+
},
|
|
46
|
+
null,
|
|
47
|
+
2,
|
|
48
|
+
),
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
runtimeDir: resolvedRuntimeDir,
|
|
53
|
+
packageJsonPath,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const readManagedOpenclawRuntimeVersion = ({
|
|
58
|
+
fsModule = fs,
|
|
59
|
+
runtimeDir,
|
|
60
|
+
} = {}) => {
|
|
61
|
+
try {
|
|
62
|
+
const pkg = JSON.parse(
|
|
63
|
+
fsModule.readFileSync(
|
|
64
|
+
getManagedOpenclawPackageJsonPath({ runtimeDir }),
|
|
65
|
+
"utf8",
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
return normalizeOpenclawVersion(pkg?.version || "");
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const readBundledOpenclawVersion = ({
|
|
75
|
+
fsModule = fs,
|
|
76
|
+
resolveImpl = require.resolve,
|
|
77
|
+
} = {}) => {
|
|
78
|
+
try {
|
|
79
|
+
const pkgPath = resolveImpl("openclaw/package.json");
|
|
80
|
+
const pkg = JSON.parse(fsModule.readFileSync(pkgPath, "utf8"));
|
|
81
|
+
return normalizeOpenclawVersion(pkg?.version || "");
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const shellQuote = (value) =>
|
|
88
|
+
`'${String(value || "").replace(/'/g, `'\"'\"'`)}'`;
|
|
89
|
+
|
|
90
|
+
const applyManagedOpenclawPatch = ({
|
|
91
|
+
execSyncImpl,
|
|
92
|
+
fsModule = fs,
|
|
93
|
+
logger = console,
|
|
94
|
+
runtimeDir,
|
|
95
|
+
version,
|
|
96
|
+
alphaclawRoot = path.resolve(__dirname, "..", ".."),
|
|
97
|
+
} = {}) => {
|
|
98
|
+
const normalizedVersion = normalizeOpenclawVersion(version);
|
|
99
|
+
if (!normalizedVersion) return false;
|
|
100
|
+
const patchesDir = path.join(alphaclawRoot, "patches");
|
|
101
|
+
const patchFileName = `openclaw+${normalizedVersion}.patch`;
|
|
102
|
+
const patchFilePath = path.join(patchesDir, patchFileName);
|
|
103
|
+
if (!fsModule.existsSync(patchFilePath)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const runtimePatchDirName = ".alphaclaw-patches";
|
|
108
|
+
const runtimePatchDirPath = path.join(runtimeDir, runtimePatchDirName);
|
|
109
|
+
try {
|
|
110
|
+
if (fsModule.existsSync(runtimePatchDirPath)) {
|
|
111
|
+
fsModule.rmSync(runtimePatchDirPath, { recursive: true, force: true });
|
|
112
|
+
}
|
|
113
|
+
} catch {}
|
|
114
|
+
fsModule.symlinkSync(patchesDir, runtimePatchDirPath);
|
|
115
|
+
|
|
116
|
+
const patchPackageMain = require.resolve("patch-package/dist/index.js", {
|
|
117
|
+
paths: [alphaclawRoot],
|
|
118
|
+
});
|
|
119
|
+
logger.log(
|
|
120
|
+
`[alphaclaw] Applying bundled OpenClaw patch for ${normalizedVersion}...`,
|
|
121
|
+
);
|
|
122
|
+
execSyncImpl(
|
|
123
|
+
`${shellQuote(process.execPath)} ${shellQuote(patchPackageMain)} --patch-dir ${shellQuote(runtimePatchDirName)}`,
|
|
124
|
+
{
|
|
125
|
+
cwd: runtimeDir,
|
|
126
|
+
stdio: "inherit",
|
|
127
|
+
timeout: 120000,
|
|
128
|
+
},
|
|
129
|
+
);
|
|
130
|
+
return true;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const installManagedOpenclawRuntime = ({
|
|
134
|
+
execSyncImpl,
|
|
135
|
+
fsModule = fs,
|
|
136
|
+
logger = console,
|
|
137
|
+
runtimeDir,
|
|
138
|
+
spec,
|
|
139
|
+
alphaclawRoot,
|
|
140
|
+
} = {}) => {
|
|
141
|
+
const normalizedSpec = String(spec || "").trim() || "openclaw@latest";
|
|
142
|
+
ensureManagedOpenclawRuntimeProject({
|
|
143
|
+
fsModule,
|
|
144
|
+
runtimeDir,
|
|
145
|
+
});
|
|
146
|
+
execSyncImpl(
|
|
147
|
+
`npm install ${shellQuote(normalizedSpec)} --omit=dev --no-save --save=false --package-lock=false --prefer-online`,
|
|
148
|
+
{
|
|
149
|
+
cwd: runtimeDir,
|
|
150
|
+
stdio: "inherit",
|
|
151
|
+
timeout: 180000,
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
const installedVersion = readManagedOpenclawRuntimeVersion({
|
|
155
|
+
fsModule,
|
|
156
|
+
runtimeDir,
|
|
157
|
+
});
|
|
158
|
+
applyManagedOpenclawPatch({
|
|
159
|
+
execSyncImpl,
|
|
160
|
+
fsModule,
|
|
161
|
+
logger,
|
|
162
|
+
runtimeDir,
|
|
163
|
+
version: installedVersion,
|
|
164
|
+
alphaclawRoot,
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
spec: normalizedSpec,
|
|
168
|
+
version: installedVersion,
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const syncManagedOpenclawRuntimeWithBundled = ({
|
|
173
|
+
execSyncImpl,
|
|
174
|
+
fsModule = fs,
|
|
175
|
+
logger = console,
|
|
176
|
+
runtimeDir,
|
|
177
|
+
resolveImpl,
|
|
178
|
+
alphaclawRoot,
|
|
179
|
+
} = {}) => {
|
|
180
|
+
const bundledVersion = readBundledOpenclawVersion({
|
|
181
|
+
fsModule,
|
|
182
|
+
resolveImpl,
|
|
183
|
+
});
|
|
184
|
+
if (!bundledVersion) {
|
|
185
|
+
return {
|
|
186
|
+
checked: false,
|
|
187
|
+
synced: false,
|
|
188
|
+
bundledVersion: null,
|
|
189
|
+
runtimeVersion: readManagedOpenclawRuntimeVersion({ fsModule, runtimeDir }),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const runtimeVersion = readManagedOpenclawRuntimeVersion({
|
|
194
|
+
fsModule,
|
|
195
|
+
runtimeDir,
|
|
196
|
+
});
|
|
197
|
+
if (runtimeVersion && compareVersionParts(runtimeVersion, bundledVersion) >= 0) {
|
|
198
|
+
return {
|
|
199
|
+
checked: true,
|
|
200
|
+
synced: false,
|
|
201
|
+
bundledVersion,
|
|
202
|
+
runtimeVersion,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
logger.log(
|
|
207
|
+
runtimeVersion
|
|
208
|
+
? `[alphaclaw] Managed OpenClaw runtime ${runtimeVersion} is older than bundled ${bundledVersion}; syncing runtime...`
|
|
209
|
+
: `[alphaclaw] Managed OpenClaw runtime missing; seeding bundled OpenClaw ${bundledVersion}...`,
|
|
210
|
+
);
|
|
211
|
+
const installResult = installManagedOpenclawRuntime({
|
|
212
|
+
execSyncImpl,
|
|
213
|
+
fsModule,
|
|
214
|
+
logger,
|
|
215
|
+
runtimeDir,
|
|
216
|
+
spec: `openclaw@${bundledVersion}`,
|
|
217
|
+
alphaclawRoot,
|
|
218
|
+
});
|
|
219
|
+
return {
|
|
220
|
+
checked: true,
|
|
221
|
+
synced: true,
|
|
222
|
+
bundledVersion,
|
|
223
|
+
runtimeVersion: installResult.version || bundledVersion,
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const prependManagedOpenclawBinToPath = ({
|
|
228
|
+
env = process.env,
|
|
229
|
+
fsModule = fs,
|
|
230
|
+
logger = console,
|
|
231
|
+
runtimeDir,
|
|
232
|
+
} = {}) => {
|
|
233
|
+
const resolvedRuntimeDir = runtimeDir || getManagedOpenclawRuntimeDir();
|
|
234
|
+
const binDir = getManagedOpenclawBinDir({ runtimeDir: resolvedRuntimeDir });
|
|
235
|
+
const binPath = getManagedOpenclawBinPath({ runtimeDir: resolvedRuntimeDir });
|
|
236
|
+
if (!fsModule.existsSync(binPath)) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
const currentEntries = String(env.PATH || "")
|
|
240
|
+
.split(path.delimiter)
|
|
241
|
+
.filter(Boolean);
|
|
242
|
+
const nextEntries = [binDir, ...currentEntries.filter((entry) => entry !== binDir)];
|
|
243
|
+
env.PATH = nextEntries.join(path.delimiter);
|
|
244
|
+
logger.log(`[alphaclaw] Using managed OpenClaw runtime from ${resolvedRuntimeDir}`);
|
|
245
|
+
return true;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
module.exports = {
|
|
249
|
+
applyManagedOpenclawPatch,
|
|
250
|
+
ensureManagedOpenclawRuntimeProject,
|
|
251
|
+
getManagedOpenclawBinDir,
|
|
252
|
+
getManagedOpenclawBinPath,
|
|
253
|
+
getManagedOpenclawPackageJsonPath,
|
|
254
|
+
getManagedOpenclawRuntimeDir,
|
|
255
|
+
installManagedOpenclawRuntime,
|
|
256
|
+
prependManagedOpenclawBinToPath,
|
|
257
|
+
readBundledOpenclawVersion,
|
|
258
|
+
readManagedOpenclawRuntimeVersion,
|
|
259
|
+
syncManagedOpenclawRuntimeWithBundled,
|
|
260
|
+
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
const {
|
|
2
|
+
installManagedAlphaclawRuntime,
|
|
3
|
+
} = require("./alphaclaw-runtime");
|
|
4
|
+
|
|
1
5
|
const buildPendingAlphaclawInstallSpec = (marker = {}) => {
|
|
2
6
|
const explicitSpec = String(marker?.spec || "").trim();
|
|
3
7
|
if (explicitSpec) {
|
|
@@ -7,9 +11,6 @@ const buildPendingAlphaclawInstallSpec = (marker = {}) => {
|
|
|
7
11
|
return `@chrysb/alphaclaw@${targetVersion}`;
|
|
8
12
|
};
|
|
9
13
|
|
|
10
|
-
const shellQuote = (value) =>
|
|
11
|
-
`'${String(value || "").replace(/'/g, `'\"'\"'`)}'`;
|
|
12
|
-
|
|
13
14
|
const applyPendingAlphaclawUpdate = ({
|
|
14
15
|
execSyncImpl,
|
|
15
16
|
fsModule,
|
|
@@ -36,14 +37,12 @@ const applyPendingAlphaclawUpdate = ({
|
|
|
36
37
|
logger.log(`[alphaclaw] Pending update detected, installing ${spec}...`);
|
|
37
38
|
|
|
38
39
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
);
|
|
40
|
+
installManagedAlphaclawRuntime({
|
|
41
|
+
execSyncImpl,
|
|
42
|
+
fsModule,
|
|
43
|
+
runtimeDir: installDir,
|
|
44
|
+
spec,
|
|
45
|
+
});
|
|
47
46
|
fsModule.unlinkSync(markerPath);
|
|
48
47
|
logger.log("[alphaclaw] Update applied successfully");
|
|
49
48
|
return {
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
const {
|
|
2
|
+
installManagedOpenclawRuntime,
|
|
3
|
+
} = require("./openclaw-runtime");
|
|
4
|
+
|
|
1
5
|
const buildPendingOpenclawInstallSpec = (marker = {}) => {
|
|
2
6
|
const explicitSpec = String(marker?.spec || "").trim();
|
|
3
7
|
if (explicitSpec) {
|
|
@@ -7,9 +11,6 @@ const buildPendingOpenclawInstallSpec = (marker = {}) => {
|
|
|
7
11
|
return `openclaw@${targetVersion}`;
|
|
8
12
|
};
|
|
9
13
|
|
|
10
|
-
const shellQuote = (value) =>
|
|
11
|
-
`'${String(value || "").replace(/'/g, `'\"'\"'`)}'`;
|
|
12
|
-
|
|
13
14
|
const applyPendingOpenclawUpdate = ({
|
|
14
15
|
execSyncImpl,
|
|
15
16
|
fsModule,
|
|
@@ -36,14 +37,13 @@ const applyPendingOpenclawUpdate = ({
|
|
|
36
37
|
logger.log(`[alphaclaw] Pending OpenClaw update detected, installing ${spec}...`);
|
|
37
38
|
|
|
38
39
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
40
|
+
installManagedOpenclawRuntime({
|
|
41
|
+
execSyncImpl,
|
|
42
|
+
fsModule,
|
|
43
|
+
logger,
|
|
44
|
+
runtimeDir: installDir,
|
|
45
|
+
spec,
|
|
46
|
+
});
|
|
47
47
|
fsModule.unlinkSync(markerPath);
|
|
48
48
|
logger.log("[alphaclaw] OpenClaw update applied successfully");
|
|
49
49
|
return {
|