@chrysb/alphaclaw 0.9.29 → 0.9.31
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/README.md +1 -1
- package/bin/alphaclaw.js +34 -0
- package/lib/node-runtime.js +38 -0
- package/lib/public/dist/app.bundle.js +795 -793
- package/lib/public/js/components/gateway.js +7 -2
- package/lib/public/js/components/models-tab/model-picker.js +5 -2
- package/lib/public/js/components/models-tab/use-models.js +4 -1
- package/lib/public/js/components/nodes-tab/setup-wizard/index.js +3 -1
- package/lib/public/js/components/welcome/use-welcome.js +4 -1
- package/lib/public/js/lib/model-config.js +49 -2
- package/lib/public/js/lib/thinking-levels.js +1 -0
- package/lib/server/agents/shared.js +2 -0
- package/lib/server/auth-profiles.js +8 -1
- package/lib/server/codex-runtime-config.js +51 -0
- package/lib/server/constants.js +18 -0
- package/lib/server/cost-utils.js +18 -0
- package/lib/server/helpers.js +18 -2
- package/lib/server/init/register-server-routes.js +2 -0
- package/lib/server/model-catalog-cache.js +2 -2
- package/lib/server/onboarding/openclaw.js +4 -0
- package/lib/server/onboarding/validation.js +3 -0
- package/lib/server/openclaw-codex-migration.js +61 -17
- package/lib/server/openclaw-thinking.js +33 -27
- package/lib/server/openclaw-version.js +7 -0
- package/lib/server/plugin-config.js +22 -0
- package/lib/server/routes/models.js +4 -0
- package/lib/server/startup.js +13 -0
- package/lib/server/usage-tracker-config.js +3 -21
- package/lib/server/watchdog.js +43 -0
- package/lib/server/webhooks.js +71 -2
- package/package.json +3 -3
|
@@ -10,6 +10,7 @@ const {
|
|
|
10
10
|
} = require("./constants");
|
|
11
11
|
const { normalizeOpenclawVersion } = require("./helpers");
|
|
12
12
|
const { parseJsonObjectFromNoisyOutput } = require("./utils/json");
|
|
13
|
+
const { assertSupportedNodeVersion } = require("../node-runtime");
|
|
13
14
|
|
|
14
15
|
const createOpenclawVersionService = ({
|
|
15
16
|
gatewayEnv,
|
|
@@ -124,6 +125,12 @@ const createOpenclawVersionService = ({
|
|
|
124
125
|
// Copying individual files (cp -af) avoids the rename syscall entirely.
|
|
125
126
|
const installLatestOpenclaw = () =>
|
|
126
127
|
new Promise((resolve, reject) => {
|
|
128
|
+
try {
|
|
129
|
+
assertSupportedNodeVersion();
|
|
130
|
+
} catch (error) {
|
|
131
|
+
reject(error);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
127
134
|
const installDir = findInstallDir();
|
|
128
135
|
const tmpDir = fs.mkdtempSync(
|
|
129
136
|
path.join(os.tmpdir(), "openclaw-update-"),
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const ensurePluginsShell = (cfg = {}) => {
|
|
2
|
+
if (!cfg.plugins || typeof cfg.plugins !== "object") cfg.plugins = {};
|
|
3
|
+
if (!Array.isArray(cfg.plugins.allow)) cfg.plugins.allow = [];
|
|
4
|
+
if (!cfg.plugins.load || typeof cfg.plugins.load !== "object") {
|
|
5
|
+
cfg.plugins.load = {};
|
|
6
|
+
}
|
|
7
|
+
if (!Array.isArray(cfg.plugins.load.paths)) cfg.plugins.load.paths = [];
|
|
8
|
+
if (!cfg.plugins.entries || typeof cfg.plugins.entries !== "object") {
|
|
9
|
+
cfg.plugins.entries = {};
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const ensurePluginAllowed = ({ cfg = {}, pluginKey = "" }) => {
|
|
14
|
+
const normalizedPluginKey = String(pluginKey || "").trim();
|
|
15
|
+
if (!normalizedPluginKey) return;
|
|
16
|
+
ensurePluginsShell(cfg);
|
|
17
|
+
if (!cfg.plugins.allow.includes(normalizedPluginKey)) {
|
|
18
|
+
cfg.plugins.allow.push(normalizedPluginKey);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports = { ensurePluginsShell, ensurePluginAllowed };
|
|
@@ -197,8 +197,12 @@ const registerModelRoutes = ({
|
|
|
197
197
|
typeof cfg.agents?.defaults?.thinkingDefault === "string"
|
|
198
198
|
? cfg.agents.defaults.thinkingDefault.trim()
|
|
199
199
|
: null;
|
|
200
|
+
const agentRuntime = String(
|
|
201
|
+
cfg.agents?.defaults?.models?.[modelKey]?.agentRuntime?.id || "",
|
|
202
|
+
).trim();
|
|
200
203
|
const { levels, modelDefault } = await resolveThinkingOptionsForModel({
|
|
201
204
|
modelKey,
|
|
205
|
+
agentRuntime,
|
|
202
206
|
});
|
|
203
207
|
const inheritedDefault = globalThinkingDefault || modelDefault || "off";
|
|
204
208
|
return res.json({
|
package/lib/server/startup.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const runOnboardedBootSequence = ({
|
|
2
2
|
ensureManagedExecDefaults,
|
|
3
3
|
ensureUsageTrackerPluginConfig,
|
|
4
|
+
ensureWebhookMappingIds,
|
|
4
5
|
doSyncPromptFiles,
|
|
5
6
|
reloadEnv,
|
|
6
7
|
syncChannelConfig,
|
|
@@ -25,6 +26,18 @@ const runOnboardedBootSequence = ({
|
|
|
25
26
|
`[alphaclaw] Failed to ensure usage-tracker plugin config on boot: ${error.message}`,
|
|
26
27
|
);
|
|
27
28
|
}
|
|
29
|
+
try {
|
|
30
|
+
const result = ensureWebhookMappingIds();
|
|
31
|
+
if (result?.changed) {
|
|
32
|
+
console.log(
|
|
33
|
+
`[alphaclaw] Added IDs to webhook mappings: ${result.updatedIds.join(", ")}`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(
|
|
38
|
+
`[alphaclaw] Failed to ensure webhook mapping IDs on boot: ${error.message}`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
28
41
|
doSyncPromptFiles();
|
|
29
42
|
reloadEnv();
|
|
30
43
|
syncChannelConfig(readEnvFile());
|
|
@@ -3,6 +3,8 @@ const { readOpenclawConfig, writeOpenclawConfig } = require("./openclaw-config")
|
|
|
3
3
|
const {
|
|
4
4
|
migrateLegacyTelegramStreamingConfig,
|
|
5
5
|
} = require("./openclaw-config-migrations");
|
|
6
|
+
const { ensureCodexRuntimePlugin } = require("./codex-runtime-config");
|
|
7
|
+
const { ensurePluginsShell, ensurePluginAllowed } = require("./plugin-config");
|
|
6
8
|
|
|
7
9
|
const kUsageTrackerPluginPath = path.resolve(
|
|
8
10
|
__dirname,
|
|
@@ -14,27 +16,6 @@ const kConversationAccessHookPolicyKey = "allowConversationAccess";
|
|
|
14
16
|
const kChannelPluginIds = ["telegram", "discord", "slack", "whatsapp"];
|
|
15
17
|
const kDefaultDiscordGroupPolicy = "disabled";
|
|
16
18
|
|
|
17
|
-
const ensurePluginsShell = (cfg = {}) => {
|
|
18
|
-
if (!cfg.plugins || typeof cfg.plugins !== "object") cfg.plugins = {};
|
|
19
|
-
if (!Array.isArray(cfg.plugins.allow)) cfg.plugins.allow = [];
|
|
20
|
-
if (!cfg.plugins.load || typeof cfg.plugins.load !== "object") {
|
|
21
|
-
cfg.plugins.load = {};
|
|
22
|
-
}
|
|
23
|
-
if (!Array.isArray(cfg.plugins.load.paths)) cfg.plugins.load.paths = [];
|
|
24
|
-
if (!cfg.plugins.entries || typeof cfg.plugins.entries !== "object") {
|
|
25
|
-
cfg.plugins.entries = {};
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const ensurePluginAllowed = ({ cfg = {}, pluginKey = "" }) => {
|
|
30
|
-
const normalizedPluginKey = String(pluginKey || "").trim();
|
|
31
|
-
if (!normalizedPluginKey) return;
|
|
32
|
-
ensurePluginsShell(cfg);
|
|
33
|
-
if (!cfg.plugins.allow.includes(normalizedPluginKey)) {
|
|
34
|
-
cfg.plugins.allow.push(normalizedPluginKey);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
19
|
const buildUsageTrackerHookPolicy = ({ existingHooks = {} } = {}) => {
|
|
39
20
|
const hooks = {};
|
|
40
21
|
if (typeof existingHooks.allowPromptInjection === "boolean") {
|
|
@@ -115,6 +96,7 @@ const reconcileEnabledChannelPlugins = (cfg = {}) => {
|
|
|
115
96
|
|
|
116
97
|
const reconcileManagedPluginConfig = (cfg = {}) => {
|
|
117
98
|
let changed = ensureUsageTrackerPluginEntry(cfg);
|
|
99
|
+
if (ensureCodexRuntimePlugin(cfg)) changed = true;
|
|
118
100
|
if (reconcileEnabledChannelPlugins(cfg)) changed = true;
|
|
119
101
|
if (reconcileDiscordGroupPolicy(cfg)) changed = true;
|
|
120
102
|
return changed;
|
package/lib/server/watchdog.js
CHANGED
|
@@ -63,6 +63,7 @@ const createWatchdog = ({
|
|
|
63
63
|
pendingRecoveryNoticeSource: "",
|
|
64
64
|
awaitingAutoRepairRecovery: false,
|
|
65
65
|
startupConsecutiveHealthFailures: 0,
|
|
66
|
+
configurationErrorActive: false,
|
|
66
67
|
};
|
|
67
68
|
let healthTimer = null;
|
|
68
69
|
let bootstrapHealthTimer = null;
|
|
@@ -90,6 +91,7 @@ const createWatchdog = ({
|
|
|
90
91
|
|
|
91
92
|
const scheduleDegradedHealthCheck = () => {
|
|
92
93
|
if (degradedHealthTimer) return;
|
|
94
|
+
if (state.configurationErrorActive) return;
|
|
93
95
|
if (state.health !== "degraded" || state.lifecycle !== "running") return;
|
|
94
96
|
degradedHealthTimer = setTimeout(async () => {
|
|
95
97
|
degradedHealthTimer = null;
|
|
@@ -380,6 +382,9 @@ const createWatchdog = ({
|
|
|
380
382
|
};
|
|
381
383
|
|
|
382
384
|
const runRepair = async ({ source, correlationId, force = false }) => {
|
|
385
|
+
if (state.configurationErrorActive && !force) {
|
|
386
|
+
return { ok: false, skipped: true, reason: "configuration_error" };
|
|
387
|
+
}
|
|
383
388
|
if (!force && !state.autoRepair) {
|
|
384
389
|
return { ok: false, skipped: true, reason: "auto_repair_disabled" };
|
|
385
390
|
}
|
|
@@ -389,10 +394,16 @@ const createWatchdog = ({
|
|
|
389
394
|
if (state.operationInProgress) {
|
|
390
395
|
return { ok: false, skipped: true, reason: "operation_in_progress" };
|
|
391
396
|
}
|
|
397
|
+
if (force) {
|
|
398
|
+
state.configurationErrorActive = false;
|
|
399
|
+
}
|
|
392
400
|
|
|
393
401
|
state.operationInProgress = true;
|
|
394
402
|
try {
|
|
395
403
|
const result = await clawCmd("doctor --fix --yes", { quiet: true });
|
|
404
|
+
if (state.configurationErrorActive && !force) {
|
|
405
|
+
return { ok: false, skipped: true, reason: "configuration_error" };
|
|
406
|
+
}
|
|
396
407
|
const ok = !!result?.ok;
|
|
397
408
|
logEvent("repair", source, ok ? "ok" : "failed", result, correlationId);
|
|
398
409
|
if (ok) {
|
|
@@ -484,6 +495,7 @@ const createWatchdog = ({
|
|
|
484
495
|
source = "health_timer",
|
|
485
496
|
allowAutoRepair = true,
|
|
486
497
|
} = {}) => {
|
|
498
|
+
if (state.configurationErrorActive) return false;
|
|
487
499
|
if (
|
|
488
500
|
state.expectedRestartInProgress &&
|
|
489
501
|
Date.now() >= state.expectedRestartUntilMs
|
|
@@ -495,6 +507,9 @@ const createWatchdog = ({
|
|
|
495
507
|
const correlationId = createCorrelationId();
|
|
496
508
|
state.lastHealthCheckAt = new Date().toISOString();
|
|
497
509
|
const parsed = await probeGatewayHealth();
|
|
510
|
+
// The gateway may exit with EX_CONFIG while a probe is in flight. Keep the
|
|
511
|
+
// latched configuration-error state from being overwritten by that result.
|
|
512
|
+
if (state.configurationErrorActive) return false;
|
|
498
513
|
const staleAfterRestart =
|
|
499
514
|
gatewayStartedAtAtStart != null &&
|
|
500
515
|
state.gatewayStartedAt != null &&
|
|
@@ -727,6 +742,33 @@ const createWatchdog = ({
|
|
|
727
742
|
return;
|
|
728
743
|
}
|
|
729
744
|
|
|
745
|
+
if (code === 78) {
|
|
746
|
+
state.configurationErrorActive = true;
|
|
747
|
+
state.lifecycle = "configuration_error";
|
|
748
|
+
state.health = "unhealthy";
|
|
749
|
+
state.uptimeStartedAt = null;
|
|
750
|
+
state.crashRecoveryActive = false;
|
|
751
|
+
state.startupConsecutiveHealthFailures = 0;
|
|
752
|
+
logEvent(
|
|
753
|
+
"config_error",
|
|
754
|
+
"exit_event",
|
|
755
|
+
"failed",
|
|
756
|
+
{ code, signal: signal ?? null, stderrTail },
|
|
757
|
+
correlationId,
|
|
758
|
+
);
|
|
759
|
+
void notifyOncePerIncident(
|
|
760
|
+
"gateway_config_error",
|
|
761
|
+
[
|
|
762
|
+
"🐺 *AlphaClaw Watchdog*",
|
|
763
|
+
withViewLogsSuffix("🔴 Gateway configuration invalid"),
|
|
764
|
+
"OpenClaw stopped with `EX_CONFIG`; automatic restart is paused.",
|
|
765
|
+
].join("\n"),
|
|
766
|
+
correlationId,
|
|
767
|
+
"config_error",
|
|
768
|
+
);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
|
|
730
772
|
state.lifecycle = "crashed";
|
|
731
773
|
state.health = "unhealthy";
|
|
732
774
|
state.uptimeStartedAt = null;
|
|
@@ -787,6 +829,7 @@ const createWatchdog = ({
|
|
|
787
829
|
|
|
788
830
|
const onGatewayLaunch = ({ startedAt = Date.now(), pid = null } = {}) => {
|
|
789
831
|
clearDegradedHealthCheckTimer();
|
|
832
|
+
state.configurationErrorActive = false;
|
|
790
833
|
state.lifecycle = "running";
|
|
791
834
|
state.health = "unknown";
|
|
792
835
|
state.startupConsecutiveHealthFailures = 0;
|
package/lib/server/webhooks.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
+
const {
|
|
3
|
+
readOpenclawConfig,
|
|
4
|
+
resolveOpenclawConfigPath,
|
|
5
|
+
} = require("./openclaw-config");
|
|
2
6
|
|
|
3
7
|
const kNamePattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4
8
|
const kTransformsDir = "hooks/transforms";
|
|
@@ -12,11 +16,16 @@ const kManagedWebhookConfigs = [
|
|
|
12
16
|
];
|
|
13
17
|
|
|
14
18
|
const getConfigPath = ({ OPENCLAW_DIR }) =>
|
|
15
|
-
|
|
19
|
+
resolveOpenclawConfigPath({ openclawDir: OPENCLAW_DIR });
|
|
16
20
|
|
|
17
21
|
const readConfig = ({ fs, constants }) => {
|
|
18
22
|
const configPath = getConfigPath(constants);
|
|
19
|
-
const cfg =
|
|
23
|
+
const cfg = readOpenclawConfig({
|
|
24
|
+
fsModule: fs,
|
|
25
|
+
openclawDir: constants.OPENCLAW_DIR,
|
|
26
|
+
fallback: null,
|
|
27
|
+
});
|
|
28
|
+
if (!cfg) throw new Error("Could not read openclaw.json");
|
|
20
29
|
return { cfg, configPath };
|
|
21
30
|
};
|
|
22
31
|
|
|
@@ -78,6 +87,32 @@ const ensureHooksRoot = (cfg) => {
|
|
|
78
87
|
|
|
79
88
|
const getMappingHookName = (mapping) =>
|
|
80
89
|
String(mapping?.match?.path || "").trim();
|
|
90
|
+
const normalizeMappingIdPart = (value) =>
|
|
91
|
+
String(value || "")
|
|
92
|
+
.trim()
|
|
93
|
+
.toLowerCase()
|
|
94
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
95
|
+
.replace(/-+/g, "-")
|
|
96
|
+
.replace(/^-|-$/g, "");
|
|
97
|
+
const getMappingIdBase = (mapping, index) => {
|
|
98
|
+
const hookPath = normalizeMappingIdPart(getMappingHookName(mapping));
|
|
99
|
+
if (hookPath) return hookPath;
|
|
100
|
+
const name = normalizeMappingIdPart(mapping?.name);
|
|
101
|
+
if (name) return name;
|
|
102
|
+
const source = normalizeMappingIdPart(mapping?.match?.source);
|
|
103
|
+
if (source) return `source-${source}`;
|
|
104
|
+
return `mapping-${index + 1}`;
|
|
105
|
+
};
|
|
106
|
+
const reserveUniqueMappingId = (baseId, usedIds) => {
|
|
107
|
+
let candidate = baseId;
|
|
108
|
+
let suffix = 2;
|
|
109
|
+
while (usedIds.has(candidate)) {
|
|
110
|
+
candidate = `${baseId}-${suffix}`;
|
|
111
|
+
suffix += 1;
|
|
112
|
+
}
|
|
113
|
+
usedIds.add(candidate);
|
|
114
|
+
return candidate;
|
|
115
|
+
};
|
|
81
116
|
const isWebhookMapping = (mapping) => !!getMappingHookName(mapping);
|
|
82
117
|
const findMappingIndexByName = (mappings, name) =>
|
|
83
118
|
mappings.findIndex((mapping) => getMappingHookName(mapping) === name);
|
|
@@ -142,6 +177,35 @@ const normalizeMappingTransformModules = (mappings) => {
|
|
|
142
177
|
return changed;
|
|
143
178
|
};
|
|
144
179
|
|
|
180
|
+
const ensureWebhookMappingIds = ({ fs, constants }) => {
|
|
181
|
+
const { cfg, configPath } = readConfig({ fs, constants });
|
|
182
|
+
const mappings = Array.isArray(cfg?.hooks?.mappings)
|
|
183
|
+
? cfg.hooks.mappings
|
|
184
|
+
: [];
|
|
185
|
+
const usedIds = new Set(
|
|
186
|
+
mappings
|
|
187
|
+
.map((mapping) => String(mapping?.id || "").trim())
|
|
188
|
+
.filter(Boolean),
|
|
189
|
+
);
|
|
190
|
+
const updatedIds = [];
|
|
191
|
+
for (const [index, mapping] of mappings.entries()) {
|
|
192
|
+
if (!mapping || typeof mapping !== "object" || Array.isArray(mapping)) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (String(mapping?.id || "").trim()) continue;
|
|
196
|
+
const id = reserveUniqueMappingId(
|
|
197
|
+
getMappingIdBase(mapping, index),
|
|
198
|
+
usedIds,
|
|
199
|
+
);
|
|
200
|
+
mapping.id = id;
|
|
201
|
+
updatedIds.push(id);
|
|
202
|
+
}
|
|
203
|
+
if (updatedIds.length > 0) {
|
|
204
|
+
writeConfig({ fs, configPath, cfg });
|
|
205
|
+
}
|
|
206
|
+
return { changed: updatedIds.length > 0, updatedIds };
|
|
207
|
+
};
|
|
208
|
+
|
|
145
209
|
const buildDefaultTransformSource = (name) => {
|
|
146
210
|
return [
|
|
147
211
|
"export default async function transform(payload, context) {",
|
|
@@ -188,6 +252,7 @@ const ensureWebhookMapping = ({ cfg, name, mapping = {} }) => {
|
|
|
188
252
|
const normalizedModulesChanged = normalizeMappingTransformModules(mappings);
|
|
189
253
|
const index = findMappingIndexByName(mappings, webhookName);
|
|
190
254
|
const defaults = {
|
|
255
|
+
id: webhookName,
|
|
191
256
|
match: { path: webhookName },
|
|
192
257
|
action: "agent",
|
|
193
258
|
name: webhookName,
|
|
@@ -198,6 +263,7 @@ const ensureWebhookMapping = ({ cfg, name, mapping = {} }) => {
|
|
|
198
263
|
mappings.push({
|
|
199
264
|
...defaults,
|
|
200
265
|
...mapping,
|
|
266
|
+
id: webhookName,
|
|
201
267
|
match: { ...defaults.match, ...(mapping.match || {}) },
|
|
202
268
|
transform: { ...defaults.transform, ...(mapping.transform || {}) },
|
|
203
269
|
});
|
|
@@ -207,6 +273,7 @@ const ensureWebhookMapping = ({ cfg, name, mapping = {} }) => {
|
|
|
207
273
|
const next = {
|
|
208
274
|
...current,
|
|
209
275
|
...mapping,
|
|
276
|
+
id: webhookName,
|
|
210
277
|
match: {
|
|
211
278
|
...(current.match || {}),
|
|
212
279
|
...(mapping.match || {}),
|
|
@@ -436,6 +503,7 @@ const updateWebhookDestination = ({ fs, constants, name, destination = null }) =
|
|
|
436
503
|
});
|
|
437
504
|
const next = {
|
|
438
505
|
...current,
|
|
506
|
+
id: webhookName,
|
|
439
507
|
deliver: true,
|
|
440
508
|
channel:
|
|
441
509
|
String(normalizedDestination?.channel || "").trim() ||
|
|
@@ -499,6 +567,7 @@ const deleteWebhook = ({ fs, constants, name, deleteTransformDir = false }) => {
|
|
|
499
567
|
};
|
|
500
568
|
|
|
501
569
|
module.exports = {
|
|
570
|
+
ensureWebhookMappingIds,
|
|
502
571
|
listWebhooks,
|
|
503
572
|
getWebhookDetail,
|
|
504
573
|
createWebhook,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrysb/alphaclaw",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.31",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"express": "^4.21.0",
|
|
35
35
|
"http-proxy": "^1.18.1",
|
|
36
|
-
"openclaw": "2026.
|
|
36
|
+
"openclaw": "2026.7.1",
|
|
37
37
|
"ws": "^8.19.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
@@ -51,6 +51,6 @@
|
|
|
51
51
|
"wouter-preact": "^3.7.1"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
|
-
"node": ">=22.
|
|
54
|
+
"node": ">=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0"
|
|
55
55
|
}
|
|
56
56
|
}
|