@chrysb/alphaclaw 0.9.10 → 0.9.12
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/lib/public/dist/app.bundle.js +1383 -1383
- package/lib/public/js/components/welcome/use-welcome.js +37 -8
- package/lib/public/js/lib/model-config.js +2 -2
- package/lib/server/constants.js +9 -3
- package/lib/server/gateway.js +119 -8
- package/lib/server/init/register-server-routes.js +1 -0
- package/lib/server/init/runtime-init.js +2 -0
- package/lib/server/model-catalog-bootstrap.json +4443 -0
- package/lib/server/model-catalog-cache.js +40 -27
- package/lib/server/onboarding/index.js +2 -9
- package/lib/server/onboarding/openclaw.js +18 -4
- package/lib/server/openclaw-runtime-env.js +55 -0
- package/lib/server/routes/models.js +2 -0
- package/lib/server/usage-tracker-config.js +28 -3
- package/lib/server.js +4 -0
- package/package.json +3 -7
- package/patches/openclaw+2026.4.21.patch +0 -13
- package/scripts/apply-openclaw-patches.js +0 -99
|
@@ -5,6 +5,8 @@ const { getCommandOutputCandidates } = require("./utils/command-output");
|
|
|
5
5
|
|
|
6
6
|
const kModelCatalogCacheVersion = 1;
|
|
7
7
|
const kModelCatalogRefreshBackoffMs = 30 * 1000;
|
|
8
|
+
const kModelCatalogLoadTimeoutMs = 120 * 1000;
|
|
9
|
+
const kModelCatalogBootstrapSource = "bootstrap";
|
|
8
10
|
const kDefaultCachePath = path.join(ALPHACLAW_DIR, "cache", "model-catalog.json");
|
|
9
11
|
|
|
10
12
|
const createResponse = ({
|
|
@@ -77,6 +79,7 @@ const createModelCatalogCache = ({
|
|
|
77
79
|
parseJsonFromNoisyOutput = () => ({}),
|
|
78
80
|
normalizeOnboardingModels = (items) => items,
|
|
79
81
|
readOpenclawVersion = () => null,
|
|
82
|
+
shouldStartDynamicRefresh = () => true,
|
|
80
83
|
fallbackModels = kFallbackOnboardingModels,
|
|
81
84
|
cachePath = kDefaultCachePath,
|
|
82
85
|
refreshBackoffMs = kModelCatalogRefreshBackoffMs,
|
|
@@ -117,6 +120,14 @@ const createModelCatalogCache = ({
|
|
|
117
120
|
|
|
118
121
|
const isRefreshPending = () => !!refreshPromise || !!retryTimer;
|
|
119
122
|
|
|
123
|
+
const canStartDynamicRefresh = () => {
|
|
124
|
+
try {
|
|
125
|
+
return shouldStartDynamicRefresh() !== false;
|
|
126
|
+
} catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
120
131
|
const setCacheEntry = (entry, { fresh = false } = {}) => {
|
|
121
132
|
memoryCache = entry;
|
|
122
133
|
cacheLoaded = true;
|
|
@@ -162,7 +173,7 @@ const createModelCatalogCache = ({
|
|
|
162
173
|
try {
|
|
163
174
|
const output = await shellCmd("openclaw models list --all --json", {
|
|
164
175
|
env: gatewayEnv(),
|
|
165
|
-
timeout:
|
|
176
|
+
timeout: kModelCatalogLoadTimeoutMs,
|
|
166
177
|
});
|
|
167
178
|
models = parseCatalogModelsFromOutput({
|
|
168
179
|
rawOutput: output,
|
|
@@ -205,21 +216,27 @@ const createModelCatalogCache = ({
|
|
|
205
216
|
};
|
|
206
217
|
|
|
207
218
|
const scheduleRetry = () => {
|
|
208
|
-
if (!
|
|
219
|
+
if (!canStartDynamicRefresh()) {
|
|
220
|
+
clearRetryTimer();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (retryTimer) return;
|
|
209
224
|
const delayMs = Math.max(backoffUntilMs - now(), 0);
|
|
210
225
|
retryTimer = setTimeoutFn(() => {
|
|
211
226
|
retryTimer = null;
|
|
212
|
-
if (!
|
|
227
|
+
if (!canStartDynamicRefresh()) return;
|
|
228
|
+
if (refreshPromise) return;
|
|
229
|
+
if (memoryCache && !cacheIsStale) return;
|
|
213
230
|
void startBackgroundRefresh();
|
|
214
231
|
}, delayMs);
|
|
215
232
|
if (typeof retryTimer?.unref === "function") retryTimer.unref();
|
|
216
233
|
};
|
|
217
234
|
|
|
218
235
|
const handleRefreshFailure = (err) => {
|
|
236
|
+
backoffUntilMs = now() + refreshBackoffMs;
|
|
237
|
+
scheduleRetry();
|
|
219
238
|
if (memoryCache) {
|
|
220
239
|
cacheIsStale = true;
|
|
221
|
-
backoffUntilMs = now() + refreshBackoffMs;
|
|
222
|
-
scheduleRetry();
|
|
223
240
|
logger.error?.(
|
|
224
241
|
`[models] Failed to refresh cached models: ${err.message || String(err)}`,
|
|
225
242
|
);
|
|
@@ -231,8 +248,11 @@ const createModelCatalogCache = ({
|
|
|
231
248
|
};
|
|
232
249
|
|
|
233
250
|
const startBackgroundRefresh = () => {
|
|
251
|
+
if (!canStartDynamicRefresh()) {
|
|
252
|
+
clearRetryTimer();
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
234
255
|
readDiskCache();
|
|
235
|
-
if (!memoryCache) return null;
|
|
236
256
|
if (refreshPromise) return refreshPromise;
|
|
237
257
|
if (retryTimer) return null;
|
|
238
258
|
if (backoffUntilMs > now()) {
|
|
@@ -279,34 +299,25 @@ const createModelCatalogCache = ({
|
|
|
279
299
|
});
|
|
280
300
|
}
|
|
281
301
|
if (memoryCache) {
|
|
282
|
-
startBackgroundRefresh();
|
|
302
|
+
const didStartRefresh = !!startBackgroundRefresh();
|
|
283
303
|
return createResponse({
|
|
284
304
|
source: "cache",
|
|
285
305
|
fetchedAt: memoryCache.fetchedAt,
|
|
286
306
|
stale: true,
|
|
287
|
-
refreshing:
|
|
307
|
+
refreshing:
|
|
308
|
+
canStartDynamicRefresh() && (didStartRefresh || isRefreshPending()),
|
|
288
309
|
models: memoryCache.models,
|
|
289
310
|
});
|
|
290
311
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
} catch (err) {
|
|
301
|
-
handleRefreshFailure(err);
|
|
302
|
-
return createResponse({
|
|
303
|
-
source: "fallback",
|
|
304
|
-
fetchedAt: null,
|
|
305
|
-
stale: false,
|
|
306
|
-
refreshing: false,
|
|
307
|
-
models: fallbackModels,
|
|
308
|
-
});
|
|
309
|
-
}
|
|
312
|
+
const didStartRefresh = !!startBackgroundRefresh();
|
|
313
|
+
return createResponse({
|
|
314
|
+
source: kModelCatalogBootstrapSource,
|
|
315
|
+
fetchedAt: null,
|
|
316
|
+
stale: true,
|
|
317
|
+
refreshing:
|
|
318
|
+
canStartDynamicRefresh() && (didStartRefresh || isRefreshPending()),
|
|
319
|
+
models: fallbackModels,
|
|
320
|
+
});
|
|
310
321
|
},
|
|
311
322
|
|
|
312
323
|
markStale() {
|
|
@@ -326,5 +337,7 @@ module.exports = {
|
|
|
326
337
|
normalizeCacheEntry,
|
|
327
338
|
kModelCatalogCacheVersion,
|
|
328
339
|
kModelCatalogRefreshBackoffMs,
|
|
340
|
+
kModelCatalogLoadTimeoutMs,
|
|
341
|
+
kModelCatalogBootstrapSource,
|
|
329
342
|
kDefaultCachePath,
|
|
330
343
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
-
const { kSetupDir
|
|
2
|
+
const { kSetupDir } = require("../constants");
|
|
3
3
|
const {
|
|
4
4
|
resolveConfigIncludes,
|
|
5
5
|
resolveImportedConfigPaths,
|
|
@@ -491,14 +491,7 @@ const createOnboardingService = ({
|
|
|
491
491
|
await shellCmd(
|
|
492
492
|
`openclaw onboard ${onboardArgs.map((a) => `"${a}"`).join(" ")}`,
|
|
493
493
|
{
|
|
494
|
-
env:
|
|
495
|
-
...process.env,
|
|
496
|
-
HOME: kRootDir,
|
|
497
|
-
OPENCLAW_HOME: kRootDir,
|
|
498
|
-
OPENCLAW_CONFIG_PATH: `${OPENCLAW_DIR}/openclaw.json`,
|
|
499
|
-
OPENCLAW_STATE_DIR: OPENCLAW_DIR,
|
|
500
|
-
XDG_CONFIG_HOME: OPENCLAW_DIR,
|
|
501
|
-
},
|
|
494
|
+
env: gatewayEnv(),
|
|
502
495
|
timeout: 120000,
|
|
503
496
|
},
|
|
504
497
|
);
|
|
@@ -162,7 +162,10 @@ const getSafeImportedDmPolicy = (channelConfig = {}) => {
|
|
|
162
162
|
return channelConfig?.dmPolicy || "pairing";
|
|
163
163
|
};
|
|
164
164
|
|
|
165
|
-
const applyFreshOnboardingChannels = ({
|
|
165
|
+
const applyFreshOnboardingChannels = ({
|
|
166
|
+
cfg,
|
|
167
|
+
varMap,
|
|
168
|
+
}) => {
|
|
166
169
|
if (varMap.TELEGRAM_BOT_TOKEN) {
|
|
167
170
|
cfg.channels.telegram = {
|
|
168
171
|
enabled: true,
|
|
@@ -214,11 +217,18 @@ const applyFreshOnboardingChannels = ({ cfg, varMap }) => {
|
|
|
214
217
|
ensureUsageTrackerPluginEntry(cfg);
|
|
215
218
|
};
|
|
216
219
|
|
|
217
|
-
const writeSanitizedOpenclawConfig = ({
|
|
220
|
+
const writeSanitizedOpenclawConfig = ({
|
|
221
|
+
fs,
|
|
222
|
+
openclawDir,
|
|
223
|
+
varMap,
|
|
224
|
+
}) => {
|
|
218
225
|
const configPath = `${openclawDir}/openclaw.json`;
|
|
219
226
|
const cfg = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
220
227
|
ensureManagedConfigShell(cfg);
|
|
221
|
-
applyFreshOnboardingChannels({
|
|
228
|
+
applyFreshOnboardingChannels({
|
|
229
|
+
cfg,
|
|
230
|
+
varMap,
|
|
231
|
+
});
|
|
222
232
|
|
|
223
233
|
let content = JSON.stringify(cfg, null, 2);
|
|
224
234
|
const replacements = buildSecretReplacements(varMap, process.env);
|
|
@@ -239,7 +249,11 @@ const writeSanitizedOpenclawConfig = ({ fs, openclawDir, varMap }) => {
|
|
|
239
249
|
console.log("[onboard] Config sanitized");
|
|
240
250
|
};
|
|
241
251
|
|
|
242
|
-
const writeManagedImportOpenclawConfig = ({
|
|
252
|
+
const writeManagedImportOpenclawConfig = ({
|
|
253
|
+
fs,
|
|
254
|
+
openclawDir,
|
|
255
|
+
varMap,
|
|
256
|
+
}) => {
|
|
243
257
|
const configPath = `${openclawDir}/openclaw.json`;
|
|
244
258
|
const cfg = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
245
259
|
ensureManagedConfigShell(cfg);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { kRootDir } = require("./constants");
|
|
4
|
+
|
|
5
|
+
const kDefaultOpenclawCompileCacheDir = path.join(
|
|
6
|
+
kRootDir,
|
|
7
|
+
"cache",
|
|
8
|
+
"openclaw-compile-cache",
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const normalizeEnvValue = (value) => String(value || "").trim();
|
|
12
|
+
|
|
13
|
+
const resolveOpenclawCompileCacheDir = (env = process.env) =>
|
|
14
|
+
normalizeEnvValue(env.NODE_COMPILE_CACHE) || kDefaultOpenclawCompileCacheDir;
|
|
15
|
+
|
|
16
|
+
const resolveOpenclawNoRespawn = (env = process.env) =>
|
|
17
|
+
normalizeEnvValue(env.OPENCLAW_NO_RESPAWN) || "1";
|
|
18
|
+
|
|
19
|
+
const withOpenclawStartupEnv = (env = process.env) => ({
|
|
20
|
+
...env,
|
|
21
|
+
NODE_COMPILE_CACHE: resolveOpenclawCompileCacheDir(env),
|
|
22
|
+
OPENCLAW_NO_RESPAWN: resolveOpenclawNoRespawn(env),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const ensureOpenclawStartupEnv = ({
|
|
26
|
+
fsModule = fs,
|
|
27
|
+
env = process.env,
|
|
28
|
+
logger = console,
|
|
29
|
+
} = {}) => {
|
|
30
|
+
const nextEnv = withOpenclawStartupEnv(env);
|
|
31
|
+
try {
|
|
32
|
+
fsModule.mkdirSync(nextEnv.NODE_COMPILE_CACHE, { recursive: true });
|
|
33
|
+
} catch (err) {
|
|
34
|
+
logger?.warn?.(
|
|
35
|
+
`[alphaclaw] OpenClaw compile cache directory unavailable: ${err.message}`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!normalizeEnvValue(env.NODE_COMPILE_CACHE)) {
|
|
40
|
+
env.NODE_COMPILE_CACHE = nextEnv.NODE_COMPILE_CACHE;
|
|
41
|
+
}
|
|
42
|
+
if (!normalizeEnvValue(env.OPENCLAW_NO_RESPAWN)) {
|
|
43
|
+
env.OPENCLAW_NO_RESPAWN = nextEnv.OPENCLAW_NO_RESPAWN;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return nextEnv;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
kDefaultOpenclawCompileCacheDir,
|
|
51
|
+
ensureOpenclawStartupEnv,
|
|
52
|
+
resolveOpenclawCompileCacheDir,
|
|
53
|
+
resolveOpenclawNoRespawn,
|
|
54
|
+
withOpenclawStartupEnv,
|
|
55
|
+
};
|
|
@@ -32,6 +32,7 @@ const registerModelRoutes = ({
|
|
|
32
32
|
parseJsonFromNoisyOutput,
|
|
33
33
|
normalizeOnboardingModels,
|
|
34
34
|
readOpenclawVersion,
|
|
35
|
+
isOnboarded = () => true,
|
|
35
36
|
authProfiles,
|
|
36
37
|
readEnvFile,
|
|
37
38
|
writeEnvFile,
|
|
@@ -42,6 +43,7 @@ const registerModelRoutes = ({
|
|
|
42
43
|
parseJsonFromNoisyOutput,
|
|
43
44
|
normalizeOnboardingModels,
|
|
44
45
|
readOpenclawVersion,
|
|
46
|
+
shouldStartDynamicRefresh: isOnboarded,
|
|
45
47
|
fallbackModels: kFallbackOnboardingModels,
|
|
46
48
|
}),
|
|
47
49
|
}) => {
|
|
@@ -7,6 +7,7 @@ const kUsageTrackerPluginPath = path.resolve(
|
|
|
7
7
|
"plugin",
|
|
8
8
|
"usage-tracker",
|
|
9
9
|
);
|
|
10
|
+
const kConversationAccessHookPolicyKey = "allowConversationAccess";
|
|
10
11
|
|
|
11
12
|
const ensurePluginsShell = (cfg = {}) => {
|
|
12
13
|
if (!cfg.plugins || typeof cfg.plugins !== "object") cfg.plugins = {};
|
|
@@ -29,19 +30,43 @@ const ensurePluginAllowed = ({ cfg = {}, pluginKey = "" }) => {
|
|
|
29
30
|
}
|
|
30
31
|
};
|
|
31
32
|
|
|
33
|
+
const buildUsageTrackerHookPolicy = ({ existingHooks = {} } = {}) => {
|
|
34
|
+
const hooks = {};
|
|
35
|
+
if (typeof existingHooks.allowPromptInjection === "boolean") {
|
|
36
|
+
hooks.allowPromptInjection = existingHooks.allowPromptInjection;
|
|
37
|
+
}
|
|
38
|
+
hooks[kConversationAccessHookPolicyKey] = true;
|
|
39
|
+
return hooks;
|
|
40
|
+
};
|
|
41
|
+
|
|
32
42
|
const ensureUsageTrackerPluginEntry = (cfg = {}) => {
|
|
33
43
|
const before = JSON.stringify(cfg);
|
|
34
44
|
ensurePluginAllowed({ cfg, pluginKey: "usage-tracker" });
|
|
35
45
|
if (!cfg.plugins.load.paths.includes(kUsageTrackerPluginPath)) {
|
|
36
46
|
cfg.plugins.load.paths.push(kUsageTrackerPluginPath);
|
|
37
47
|
}
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
const existingEntry =
|
|
49
|
+
cfg.plugins.entries["usage-tracker"] &&
|
|
40
50
|
typeof cfg.plugins.entries["usage-tracker"] === "object"
|
|
41
51
|
? cfg.plugins.entries["usage-tracker"]
|
|
42
|
-
: {}
|
|
52
|
+
: {};
|
|
53
|
+
const existingHooks =
|
|
54
|
+
existingEntry.hooks && typeof existingEntry.hooks === "object"
|
|
55
|
+
? existingEntry.hooks
|
|
56
|
+
: {};
|
|
57
|
+
const hooks = buildUsageTrackerHookPolicy({
|
|
58
|
+
existingHooks,
|
|
59
|
+
});
|
|
60
|
+
const nextEntry = {
|
|
61
|
+
...existingEntry,
|
|
43
62
|
enabled: true,
|
|
44
63
|
};
|
|
64
|
+
if (Object.keys(hooks).length > 0) {
|
|
65
|
+
nextEntry.hooks = hooks;
|
|
66
|
+
} else {
|
|
67
|
+
delete nextEntry.hooks;
|
|
68
|
+
}
|
|
69
|
+
cfg.plugins.entries["usage-tracker"] = nextEntry;
|
|
45
70
|
return JSON.stringify(cfg) !== before;
|
|
46
71
|
};
|
|
47
72
|
|
package/lib/server.js
CHANGED
|
@@ -141,12 +141,16 @@ const {
|
|
|
141
141
|
const {
|
|
142
142
|
ensureManagedExecDefaults,
|
|
143
143
|
} = require("./server/exec-defaults-config");
|
|
144
|
+
const {
|
|
145
|
+
ensureOpenclawStartupEnv,
|
|
146
|
+
} = require("./server/openclaw-runtime-env");
|
|
144
147
|
|
|
145
148
|
const { PORT, kTrustProxyHops, SETUP_API_PREFIXES } = constants;
|
|
146
149
|
|
|
147
150
|
initializeServerRuntime({
|
|
148
151
|
fs,
|
|
149
152
|
constants,
|
|
153
|
+
ensureOpenclawStartupEnv,
|
|
150
154
|
startEnvWatcher,
|
|
151
155
|
attachGatewaySignalHandlers,
|
|
152
156
|
cleanupStaleImportTempDirs,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrysb/alphaclaw",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -19,14 +19,11 @@
|
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"bin/",
|
|
22
|
-
"lib/"
|
|
23
|
-
"patches/",
|
|
24
|
-
"scripts/apply-openclaw-patches.js"
|
|
22
|
+
"lib/"
|
|
25
23
|
],
|
|
26
24
|
"scripts": {
|
|
27
25
|
"start": "node bin/alphaclaw.js start",
|
|
28
26
|
"build:ui": "node scripts/build-ui.mjs",
|
|
29
|
-
"postinstall": "node ./scripts/apply-openclaw-patches.js",
|
|
30
27
|
"test": "vitest run",
|
|
31
28
|
"test:watch": "vitest",
|
|
32
29
|
"test:watchdog": "vitest run tests/server/watchdog.test.js tests/server/watchdog-db.test.js tests/server/routes-watchdog.test.js",
|
|
@@ -36,8 +33,7 @@
|
|
|
36
33
|
"dependencies": {
|
|
37
34
|
"express": "^4.21.0",
|
|
38
35
|
"http-proxy": "^1.18.1",
|
|
39
|
-
"openclaw": "2026.4.
|
|
40
|
-
"patch-package": "^8.0.1",
|
|
36
|
+
"openclaw": "2026.4.24",
|
|
41
37
|
"ws": "^8.19.0"
|
|
42
38
|
},
|
|
43
39
|
"devDependencies": {
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
diff --git a/node_modules/openclaw/dist/server.impl-DLF59fRo.js b/node_modules/openclaw/dist/server.impl-DLF59fRo.js
|
|
2
|
-
index d6b4a5c..4e76dd9 100644
|
|
3
|
-
--- a/node_modules/openclaw/dist/server.impl-DLF59fRo.js
|
|
4
|
-
+++ b/node_modules/openclaw/dist/server.impl-DLF59fRo.js
|
|
5
|
-
@@ -22187,7 +22187,7 @@ function attachGatewayWsMessageHandler(params) {
|
|
6
|
-
close(1008, truncateCloseReason(authMessage));
|
|
7
|
-
};
|
|
8
|
-
const clearUnboundScopes = () => {
|
|
9
|
-
- if (scopes.length > 0) {
|
|
10
|
-
+ if (scopes.length > 0 && !sharedAuthOk) {
|
|
11
|
-
scopes = [];
|
|
12
|
-
connectParams.scopes = scopes;
|
|
13
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* patch-package resolves paths relative to the npm/yarn project root (where the
|
|
3
|
-
* lockfile lives). When this package's postinstall runs, process.cwd() is often
|
|
4
|
-
* this package directory, so a plain `patch-package` call treats that as the
|
|
5
|
-
* app root and looks for ./node_modules/openclaw under it — but openclaw is
|
|
6
|
-
* usually hoisted to the consumer's top-level node_modules.
|
|
7
|
-
*
|
|
8
|
-
* This script finds the real install root (directory containing a lockfile) and
|
|
9
|
-
* runs patch-package there with --patch-dir pointing at our bundled patches/.
|
|
10
|
-
*/
|
|
11
|
-
const { spawnSync } = require("child_process");
|
|
12
|
-
const fs = require("fs");
|
|
13
|
-
const path = require("path");
|
|
14
|
-
|
|
15
|
-
const kAlphaclawRoot = path.join(__dirname, "..");
|
|
16
|
-
|
|
17
|
-
const findProjectRootFromOpenclawDir = (openclawDir) => {
|
|
18
|
-
let dir = path.resolve(openclawDir);
|
|
19
|
-
for (let i = 0; i < 30; i += 1) {
|
|
20
|
-
if (
|
|
21
|
-
fs.existsSync(path.join(dir, "package-lock.json")) ||
|
|
22
|
-
fs.existsSync(path.join(dir, "yarn.lock")) ||
|
|
23
|
-
fs.existsSync(path.join(dir, "pnpm-lock.yaml"))
|
|
24
|
-
) {
|
|
25
|
-
return dir;
|
|
26
|
-
}
|
|
27
|
-
const parent = path.dirname(dir);
|
|
28
|
-
if (parent === dir) break;
|
|
29
|
-
dir = parent;
|
|
30
|
-
}
|
|
31
|
-
return path.dirname(path.dirname(openclawDir));
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const main = () => {
|
|
35
|
-
const patchesDir = path.join(kAlphaclawRoot, "patches");
|
|
36
|
-
if (!fs.existsSync(patchesDir)) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const hasPatch = fs
|
|
40
|
-
.readdirSync(patchesDir)
|
|
41
|
-
.some((name) => name.endsWith(".patch"));
|
|
42
|
-
if (!hasPatch) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
let openclawMainPath;
|
|
47
|
-
try {
|
|
48
|
-
openclawMainPath = require.resolve("openclaw", { paths: [kAlphaclawRoot] });
|
|
49
|
-
} catch {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const openclawDir = (() => {
|
|
54
|
-
let dir = path.dirname(openclawMainPath);
|
|
55
|
-
for (let i = 0; i < 8; i += 1) {
|
|
56
|
-
const pkgPath = path.join(dir, "package.json");
|
|
57
|
-
if (fs.existsSync(pkgPath)) {
|
|
58
|
-
try {
|
|
59
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
60
|
-
if (pkg.name === "openclaw") return dir;
|
|
61
|
-
} catch {
|
|
62
|
-
/* continue */
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const parent = path.dirname(dir);
|
|
66
|
-
if (parent === dir) break;
|
|
67
|
-
dir = parent;
|
|
68
|
-
}
|
|
69
|
-
return path.dirname(path.dirname(openclawMainPath));
|
|
70
|
-
})();
|
|
71
|
-
const projectRoot = findProjectRootFromOpenclawDir(openclawDir);
|
|
72
|
-
|
|
73
|
-
let relPatchDir = path.relative(projectRoot, patchesDir);
|
|
74
|
-
if (relPatchDir.startsWith("..") || path.isAbsolute(relPatchDir)) {
|
|
75
|
-
console.error(
|
|
76
|
-
"[@chrysb/alphaclaw] patch-package: could not resolve patch dir relative to project root",
|
|
77
|
-
);
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
80
|
-
relPatchDir = relPatchDir.split(path.sep).join("/");
|
|
81
|
-
|
|
82
|
-
const patchPackageMain = require.resolve("patch-package/dist/index.js", {
|
|
83
|
-
paths: [kAlphaclawRoot],
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const result = spawnSync(
|
|
87
|
-
process.execPath,
|
|
88
|
-
[patchPackageMain, "--patch-dir", relPatchDir],
|
|
89
|
-
{ cwd: projectRoot, stdio: "inherit", env: process.env },
|
|
90
|
-
);
|
|
91
|
-
if (result.error) {
|
|
92
|
-
throw result.error;
|
|
93
|
-
}
|
|
94
|
-
if (result.status !== 0 && result.status !== null) {
|
|
95
|
-
process.exit(result.status);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
main();
|