prepare_package_tgz() { if [ -n "$PACKAGE_TGZ" ]; then if [ ! -f "$PACKAGE_TGZ" ]; then echo"OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ does not exist: $PACKAGE_TGZ" >&2
exit 1 fi
PACKAGE_TGZ="$(cd "$(dirname "$PACKAGE_TGZ")" && pwd)/$(basename "$PACKAGE_TGZ")"
return 0 fi
if [ "$HOST_BUILD" != "0" ]; then echo"Building host package artifacts..."
run_logged bundled-channel-deps-host-build pnpm build else echo"Skipping host build (OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0)" fi
run_channel_scenario() {
local channel="$1"
local dep_sentinel="$2"
local run_log
run_log="$(mktemp "${TMPDIR:-/tmp}/openclaw-bundled-channel-deps-$channel.XXXXXX")"
command -v openclaw >/dev/null
package_root="$(npm root -g)/openclaw"
test -d "$package_root/dist/extensions/telegram"
test -d "$package_root/dist/extensions/discord"
test -d "$package_root/dist/extensions/slack"
test -d "$package_root/dist/extensions/feishu"
test -d "$package_root/dist/extensions/memory-lancedb"
find_external_dep_package() {
local dep_path="$1"
find "$(stage_root)" -maxdepth 12 -path "*/node_modules/$dep_path/package.json" -type f -print -quit 2>/dev/null || true
}
assert_package_dep_absent() {
local channel="$1"
local dep_path="$2" for candidate in \ "$package_root/dist/extensions/$channel/node_modules/$dep_path/package.json" \ "$package_root/dist/extensions/node_modules/$dep_path/package.json" \ "$package_root/node_modules/$dep_path/package.json"; do if [ -f "$candidate" ]; then echo"packaged install should not mutate package tree for $channel: $candidate" >&2
exit 1 fi done
}
if [ -d "$package_root/dist/extensions/$CHANNEL/node_modules" ]; then echo"$CHANNEL runtime deps should not be preinstalled in package" >&2
find "$package_root/dist/extensions/$CHANNEL/node_modules" -maxdepth 2 -type f | head -20 >&2 || true
exit 1 fi
start_gateway() {
local log_file="$1"
local skip_sidecars="${2:-0}"
: >"$log_file" if [ "$skip_sidecars" = "1" ]; then
OPENCLAW_SKIP_CHANNELS=1 OPENCLAW_SKIP_PROVIDERS=1 \
openclaw gateway --port "$PORT" --bind loopback --allow-unconfigured >"$log_file" 2>&1 & else
openclaw gateway --port "$PORT" --bind loopback --allow-unconfigured >"$log_file" 2>&1 & fi
gateway_pid="$!"
# Cold bundled dependency staging can exceed 60s under 10-way Docker aggregate load. for _ in $(seq 1 1200); do if grep -Eq "listening on ws://|\\[gateway\\] ready \\(""$log_file"; then
return 0 fi if ! kill -0 "$gateway_pid" 2>/dev/null; then echo"gateway exited unexpectedly" >&2 cat"$log_file" >&2
exit 1 fi
sleep 0.25 done
echo"timed out waiting for gateway" >&2 cat"$log_file" >&2
exit 1
}
wait_for_gateway_health() {
local log_file="${1:-}" if [ -n "${gateway_pid:-}" ] && kill -0 "$gateway_pid" 2>/dev/null; then
return 0 fi echo"gateway process exited after ready marker" >&2 if [ -n "$log_file" ]; then cat"$log_file" >&2 fi
return 1
}
assert_channel_status() {
local channel="$1" if [ "$channel" = "memory-lancedb" ]; then echo"memory-lancedb plugin activation verified by dependency sentinel"
return 0 fi
local out="/tmp/openclaw-channel-status-$channel.json"
local err="/tmp/openclaw-channel-status-$channel.err" for _ in $(seq 1 12); do if openclaw gateway call channels.status \
--url "ws://127.0.0.1:$PORT" \
--token "$TOKEN" \
--timeout 10000 \
--json \
--params '{"probe":false}' >"$out" 2>"$err"; then
break fi
sleep 2 done if [ ! -s "$out" ]; then if grep -Eq "\\[gateway\\] ready \\(.*\\b$channel\\b" /tmp/openclaw-"$channel"-*.log 2>/dev/null; then echo"$channel channel plugin visible in gateway ready log"
return 0 fi cat"$err" >&2 || true
return 1 fi
node - <<'NODE'"$out""$channel"
const fs = require("node:fs");
const raw = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
const payload = raw.result ?? raw.data ?? raw;
const channel = process.argv[3];
const dump = () => JSON.stringify(raw, null, 2).slice(0, 4000);
const hasChannelMeta = Array.isArray(payload.channelMeta)
? payload.channelMeta.some((entry) => entry?.id === channel)
: Boolean(payload.channelMeta?.[channel]); if (!hasChannelMeta) {
throw new Error(`missing channelMeta.${channel}\n${dump()}`);
} if (!payload.channels || !payload.channels[channel]) {
throw new Error(`missing channels.${channel}\n${dump()}`);
}
const accounts = payload.channelAccounts?.[channel]; if (!Array.isArray(accounts) || accounts.length === 0) {
throw new Error(`missing channelAccounts.${channel}\n${dump()}`);
}
console.log(`${channel} channel plugin visible`);
NODE
}
assert_installed_once() {
local log_file="$1"
local channel="$2"
local dep_path="$3"
local count
count="$(grep -Ec "\\[plugins\\] $channel installed bundled runtime deps( in [0-9]+ms)?:" "$log_file" || true)" if [ "$count" -eq 1 ]; then
return 0 fi if [ "$count" -eq 0 ] && [ -n "$(find_external_dep_package "$dep_path")" ]; then
return 0 fi echo"expected one runtime deps install log or staged dependency sentinel for $channel, got $count log lines" >&2 cat"$log_file" >&2
find "$(stage_root)" -maxdepth 12 -type f | sort | head -120 >&2 || true
exit 1
}
assert_not_installed() {
local log_file="$1"
local channel="$2" if grep -Eq "\\[plugins\\] $channel installed bundled runtime deps( in [0-9]+ms)?:""$log_file"; then echo"expected no runtime deps reinstall for $channel" >&2 cat"$log_file" >&2
exit 1 fi
}
assert_dep_sentinel() {
local channel="$1"
local dep_path="$2"
local sentinel
sentinel="$(find_external_dep_package "$dep_path")" if [ -z "$sentinel" ]; then echo"missing external dependency sentinel for $channel: $dep_path" >&2
find "$(stage_root)" -maxdepth 12 -type f | sort | head -120 >&2 || true
exit 1 fi
assert_package_dep_absent "$channel""$dep_path"
}
assert_no_dep_sentinel() {
local channel="$1"
local dep_path="$2"
assert_package_dep_absent "$channel""$dep_path" if [ -n "$(find_external_dep_package "$dep_path")" ]; then echo"external dependency sentinel should be absent before activation for $channel: $dep_path" >&2
exit 1 fi
}
assert_no_install_stage() {
local channel="$1"
local stage="$package_root/dist/extensions/$channel/.openclaw-install-stage" if [ -e "$stage" ]; then echo"install stage should be cleaned after activation for $channel" >&2
find "$stage" -maxdepth 4 -type f | sort | head -80 >&2 || true
exit 1 fi
}
# Cold bundled dependency staging can exceed 60s under 10-way Docker aggregate load. for _ in $(seq 1 1200); do if grep -Eq "listening on ws://|\\[gateway\\] ready \\(""$log_file"; then
return 0 fi if ! kill -0 "$gateway_pid" 2>/dev/null; then echo"gateway exited unexpectedly" >&2 cat"$log_file" >&2
exit 1 fi
sleep 0.25 done
echo"timed out waiting for gateway" >&2 cat"$log_file" >&2
exit 1
}
wait_for_slack_provider_start() { for _ in $(seq 1 180); do if grep -Eq "\\[slack\\] \\[default\\] starting provider|An API error occurred: invalid_auth|\\[plugins\\] slack installed bundled runtime deps|\\[gateway\\] ready \\(.*\\bslack\\b" /tmp/openclaw-root-owned-gateway.log; then
return 0 fi
sleep 1 done echo"timed out waiting for slack provider startup" >&2 cat /tmp/openclaw-root-owned-gateway.log >&2
exit 1
}
root="$(package_root)" for channel in "${!SETUP_ENTRY_DEP_SENTINELS[@]}"; do
dep_sentinel="${SETUP_ENTRY_DEP_SENTINELS[$channel]}"
test -d "$root/dist/extensions/$channel" if [ -d "$root/dist/extensions/$channel/node_modules" ]; then echo"$channel runtime deps should not be preinstalled in package" >&2
find "$root/dist/extensions/$channel/node_modules" -maxdepth 3 -type f | head -40 >&2 || true
exit 1 fi if [ -f "$root/node_modules/$dep_sentinel/package.json" ]; then echo"$dep_sentinel should not be installed at package root before setup-entry load" >&2
exit 1 fi done
echo"Probing real bundled setup entries before channel configuration..."
(
cd "$root"
node --input-type=module - <<'NODE' import fs from "node:fs"; import path from "node:path"; import { pathToFileURL } from "node:url";
const root = process.cwd();
const distDir = path.join(root, "dist");
const bundledPath = fs
.readdirSync(distDir)
.filter((entry) => /^bundled-[A-Za-z0-9_-]+\.js$/.test(entry))
.map((entry) => path.join(distDir, entry))
.find((entry) => fs.readFileSync(entry, "utf8").includes("src/channels/plugins/bundled.ts")); if (!bundledPath) {
throw new Error("missing packaged bundled channel loader artifact");
}
const bundled = await import(pathToFileURL(bundledPath));
const setupPluginLoader = Object.values(bundled).find(
(value) => typeof value === "function" && value.name === "getBundledChannelSetupPlugin",
); if (!setupPluginLoader) {
throw new Error("missing packaged getBundledChannelSetupPlugin export");
} for (const channel of ["feishu", "whatsapp"]) {
const plugin = setupPluginLoader(channel); if (!plugin) {
throw new Error(`${channel} setup plugin did not load pre-config`);
} if (plugin.id !== channel) {
throw new Error(`${channel} setup plugin id mismatch: ${plugin.id}`);
}
console.log(`${channel} setup plugin loaded pre-config`);
}
NODE
)
for channel in "${!SETUP_ENTRY_DEP_SENTINELS[@]}"; do
dep_sentinel="${SETUP_ENTRY_DEP_SENTINELS[$channel]}" if [ -e "$root/dist/extensions/$channel/node_modules/$dep_sentinel/package.json" ]; then echo"setup-entry discovery installed $channel deps into bundled plugin tree before channel configuration" >&2
exit 1 fi if find "$OPENCLAW_PLUGIN_STAGE_DIR" -maxdepth 12 -path "*/node_modules/$dep_sentinel/package.json" -type f | grep -q .; then echo"setup-entry discovery installed $channel external staged deps before channel configuration" >&2
find "$OPENCLAW_PLUGIN_STAGE_DIR" -maxdepth 12 -type f | sort | head -160 >&2 || true
exit 1 fi done
echo"Running packaged guided WhatsApp setup; runtime deps should be staged before finalize..."
OPENCLAW_PACKAGE_ROOT="$root" node --input-type=module - <<'NODE' import path from "node:path"; import { readdir } from "node:fs/promises"; import { pathToFileURL } from "node:url";
const root = process.env.OPENCLAW_PACKAGE_ROOT; if (!root) {
throw new Error("missing OPENCLAW_PACKAGE_ROOT");
}
const distDir = path.join(root, "dist");
const onboardChannelFiles = (await readdir(distDir))
.filter((entry) => /^onboard-channels-.*\.js$/.test(entry))
.sort();
let setupChannels; for (const entry of onboardChannelFiles) {
const module = await import(pathToFileURL(path.join(distDir, entry))); if (typeof module.setupChannels === "function") {
setupChannels = module.setupChannels;
break;
}
} if (!setupChannels) {
throw new Error(
`could not find packaged setupChannels export in ${JSON.stringify(onboardChannelFiles)}`,
);
}
if (!result.channels?.whatsapp) {
throw new Error(`WhatsApp setup did not write channel config: ${JSON.stringify(result)}`);
}
console.log("packaged guided WhatsApp setup completed");
NODE
if [ -e "$root/dist/extensions/whatsapp/node_modules/@whiskeysockets/baileys/package.json" ]; then echo"expected guided WhatsApp setup deps to be installed externally, not into bundled plugin tree" >&2
exit 1 fi if ! find "$OPENCLAW_PLUGIN_STAGE_DIR" -maxdepth 12 -path "*/node_modules/@whiskeysockets/baileys/package.json" -type f | grep -q .; then echo"guided WhatsApp setup did not stage @whiskeysockets/baileys before finalize" >&2
find "$OPENCLAW_PLUGIN_STAGE_DIR" -maxdepth 12 -type f | sort | head -160 >&2 || true
exit 1 fi
echo"Configuring setup-entry channels; doctor should now install bundled runtime deps externally..."
node - <<'NODE'
const fs = require("node:fs");
const path = require("node:path");
openclaw doctor --non-interactive >/tmp/openclaw-setup-entry-doctor.log 2>&1
for channel in "${!SETUP_ENTRY_DEP_SENTINELS[@]}"; do
dep_sentinel="${SETUP_ENTRY_DEP_SENTINELS[$channel]}" if [ -e "$root/dist/extensions/$channel/node_modules/$dep_sentinel/package.json" ]; then echo"expected configured $channel deps to be installed externally, not into bundled plugin tree" >&2
exit 1 fi if ! find "$OPENCLAW_PLUGIN_STAGE_DIR" -maxdepth 12 -path "*/node_modules/$dep_sentinel/package.json" -type f | grep -q .; then echo"missing external staged dependency sentinel for configured $channel: $dep_sentinel" >&2 cat /tmp/openclaw-setup-entry-doctor.log >&2
find "$OPENCLAW_PLUGIN_STAGE_DIR" -maxdepth 12 -type f | sort | head -160 >&2 || true
exit 1 fi done
echo"bundled channel setup-entry runtime deps Docker E2E passed"
EOF then cat"$run_log" rm -f "$run_log"
exit 1 fi
cat"$run_log" rm -f "$run_log"
}
run_disabled_config_scenario() {
local run_log
run_log="$(mktemp "${TMPDIR:-/tmp}/openclaw-bundled-channel-disabled-config.XXXXXX")"
assert_dep_absent_everywhere() {
local channel="$1"
local dep_path="$2"
local root="$3" for candidate in \ "$root/dist/extensions/$channel/node_modules/$dep_path/package.json" \ "$root/dist/extensions/node_modules/$dep_path/package.json" \ "$root/node_modules/$dep_path/package.json"; do if [ -f "$candidate" ]; then echo"disabled $channel unexpectedly installed $dep_path at $candidate" >&2
exit 1 fi done
if ! openclaw doctor --non-interactive >/tmp/openclaw-disabled-config-doctor.log 2>&1; then echo"doctor failed for disabled-config runtime deps smoke" >&2 cat /tmp/openclaw-disabled-config-doctor.log >&2
exit 1 fi
if grep -Eq "(used by .*\\b(telegram|slack|discord)\\b|\\[plugins\\] (telegram|slack|discord) installed bundled runtime deps( in [0-9]+ms)?:)" /tmp/openclaw-disabled-config-doctor.log; then echo"doctor installed runtime deps for an explicitly disabled channel/plugin" >&2 cat /tmp/openclaw-disabled-config-doctor.log >&2
exit 1 fi
echo"bundled channel disabled-config runtime deps Docker E2E passed"
EOF then cat"$run_log" rm -f "$run_log"
exit 1 fi
cat"$run_log" rm -f "$run_log"
}
run_update_scenario() {
local run_log
run_log="$(mktemp "${TMPDIR:-/tmp}/openclaw-bundled-channel-update.XXXXXX")"
assert_dep_sentinel() {
local channel="$1"
local dep_path="$2"
local root
local sentinel
root="$(package_root)"
sentinel="$(find_external_dep_package "$dep_path")" if [ -z "$sentinel" ]; then echo"missing external dependency sentinel for $channel: $dep_path" >&2
find "$(stage_root)" -maxdepth 12 -type f | sort | head -120 >&2 || true
exit 1 fi
assert_no_package_dep_available "$channel""$dep_path""$root"
}
assert_no_dep_sentinel() {
local channel="$1"
local dep_path="$2"
local root
root="$(package_root)"
assert_no_package_dep_available "$channel""$dep_path""$root" if [ -n "$(find_external_dep_package "$dep_path")" ]; then echo"external dependency sentinel should be absent before repair for $channel: $dep_path" >&2
exit 1 fi
}
assert_no_package_dep_available() {
local channel="$1"
local dep_path="$2"
local root="$3" for candidate in \ "$root/dist/extensions/$channel/node_modules/$dep_path/package.json" \ "$root/dist/extensions/node_modules/$dep_path/package.json" \ "$root/node_modules/$dep_path/package.json"; do if [ -f "$candidate" ]; then echo"packaged install should not mutate package tree for $channel: $candidate" >&2
exit 1 fi done
}
assert_dep_available() {
local channel="$1"
local dep_path="$2"
local root
local sentinel
root="$(package_root)"
sentinel="$(find_external_dep_package "$dep_path")" if [ -n "$sentinel" ]; then
assert_no_package_dep_available "$channel""$dep_path""$root"
return 0 fi echo"missing dependency sentinel for $channel: $dep_path" >&2
find "$root/dist/extensions/$channel" -maxdepth 3 -type f | sort | head -80 >&2 || true
find "$root/node_modules" -maxdepth 3 -path "*/$dep_path/package.json" -type f -print >&2 || true
find "$(stage_root)" -maxdepth 12 -type f | sort | head -120 >&2 || true
exit 1
}
assert_no_dep_available() {
local channel="$1"
local dep_path="$2"
local root
root="$(package_root)"
assert_no_package_dep_available "$channel""$dep_path""$root" if [ -n "$(find_external_dep_package "$dep_path")" ]; then echo"dependency sentinel should be absent before repair for $channel: $dep_path" >&2
exit 1 fi
}
remove_runtime_dep() {
local channel="$1"
local dep_path="$2"
local root
root="$(package_root)" rm -rf "$root/dist/extensions/$channel/node_modules" rm -rf "$root/dist/extensions/node_modules/$dep_path" rm -rf "$root/node_modules/$dep_path" rm -rf "$(stage_root)"
}
assert_update_ok() {
local json_file="$1"
local expected_before="$2"
node - <<'NODE'"$json_file""$expected_before""$candidate_version"
const fs = require("node:fs");
const payload = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
const expectedBefore = process.argv[3];
const expectedAfter = process.argv[4]; if (payload.status !== "ok") {
throw new Error(`expected update status ok, got ${JSON.stringify(payload.status)}`);
} if (expectedBefore && (payload.before?.version ?? null) !== expectedBefore) {
throw new Error(
`expected before.version ${expectedBefore}, got ${JSON.stringify(payload.before?.version)}`,
);
} if ((payload.after?.version ?? null) !== expectedAfter) {
throw new Error(
`expected after.version ${expectedAfter}, got ${JSON.stringify(payload.after?.version)}`,
);
}
const steps = Array.isArray(payload.steps) ? payload.steps : [];
const doctor = steps.find((step) => step?.name === "openclaw doctor"); if (!doctor) {
throw new Error("missing openclaw doctor step");
} if (Number(doctor.exitCode ?? 1) !== 0) {
throw new Error(`openclaw doctor step failed: ${JSON.stringify(doctor)}`);
}
NODE
}
run_update_and_capture() {
local label="$1"
local out_file="$2"
set +e
openclaw update --tag "$update_target" --yes --json >"$out_file" 2>"/tmp/openclaw-$label-update.stderr"
local status=$?
set -e if [ "$status" -ne 0 ]; then echo"openclaw update failed for $label with exit code $status" >&2 cat"$out_file" >&2 || true cat"/tmp/openclaw-$label-update.stderr" >&2 || true
exit "$status" fi
}
should_run_update_target() {
local target="$1"
case ",$UPDATE_TARGETS," in
*",all,"* | *",$target,"*) return 0 ;;
*) return 1 ;;
esac
}
echo"Installing current candidate as update baseline..." echo"Update targets: $UPDATE_TARGETS"
npm install -g "$package_tgz" --no-fund --no-audit >/tmp/openclaw-update-baseline-install.log 2>&1
command -v openclaw >/dev/null
baseline_root="$(package_root)"
test -d "$baseline_root/dist/extensions/telegram"
test -d "$baseline_root/dist/extensions/feishu"
test -d "$baseline_root/dist/extensions/acpx"
if should_run_update_target telegram; then echo"Replicating configured Telegram missing-runtime state..."
write_config telegram
assert_no_dep_available telegram grammy
set +e
openclaw doctor --non-interactive >/tmp/openclaw-baseline-doctor.log 2>&1
baseline_doctor_status=$?
set -e echo"baseline doctor exited with $baseline_doctor_status"
remove_runtime_dep telegram grammy
assert_no_dep_available telegram grammy
echo"Updating from baseline to current candidate; candidate doctor must repair Telegram deps..."
run_update_and_capture telegram /tmp/openclaw-update-telegram.json cat /tmp/openclaw-update-telegram.json
assert_update_ok /tmp/openclaw-update-telegram.json "$candidate_version"
assert_dep_available telegram grammy
echo"Mutating installed package: remove Telegram deps, then update-mode doctor repairs them..."
remove_runtime_dep telegram grammy
assert_no_dep_available telegram grammy if ! OPENCLAW_UPDATE_IN_PROGRESS=1 openclaw doctor --non-interactive >/tmp/openclaw-update-mode-doctor.log 2>&1; then echo"update-mode doctor failed while repairing Telegram deps" >&2 cat /tmp/openclaw-update-mode-doctor.log >&2
exit 1 fi
assert_dep_available telegram grammy fi
if should_run_update_target discord; then echo"Mutating config to Discord and rerunning same-version update path..."
write_config discord
remove_runtime_dep discord discord-api-types
assert_no_dep_available discord discord-api-types
run_update_and_capture discord /tmp/openclaw-update-discord.json cat /tmp/openclaw-update-discord.json
assert_update_ok /tmp/openclaw-update-discord.json "$candidate_version"
assert_dep_available discord discord-api-types fi
if should_run_update_target slack; then echo"Mutating config to Slack and rerunning same-version update path..."
write_config slack
remove_runtime_dep slack @slack/web-api
assert_no_dep_available slack @slack/web-api
run_update_and_capture slack /tmp/openclaw-update-slack.json cat /tmp/openclaw-update-slack.json
assert_update_ok /tmp/openclaw-update-slack.json "$candidate_version"
assert_dep_available slack @slack/web-api fi
if should_run_update_target feishu; then echo"Mutating config to Feishu and rerunning same-version update path..."
write_config feishu
remove_runtime_dep feishu @larksuiteoapi/node-sdk
assert_no_dep_available feishu @larksuiteoapi/node-sdk
run_update_and_capture feishu /tmp/openclaw-update-feishu.json cat /tmp/openclaw-update-feishu.json
assert_update_ok /tmp/openclaw-update-feishu.json "$candidate_version"
assert_dep_available feishu @larksuiteoapi/node-sdk fi
if should_run_update_target memory-lancedb; then echo"Mutating config to memory-lancedb and rerunning same-version update path..."
write_config memory-lancedb
remove_runtime_dep memory-lancedb @lancedb/lancedb
assert_no_dep_available memory-lancedb @lancedb/lancedb
run_update_and_capture memory-lancedb /tmp/openclaw-update-memory-lancedb.json cat /tmp/openclaw-update-memory-lancedb.json
assert_update_ok /tmp/openclaw-update-memory-lancedb.json "$candidate_version"
assert_dep_available memory-lancedb @lancedb/lancedb fi
if should_run_update_target acpx; then echo"Removing ACPX runtime package and rerunning same-version update path..."
remove_runtime_dep acpx acpx
assert_no_dep_available acpx acpx
run_update_and_capture acpx /tmp/openclaw-update-acpx.json cat /tmp/openclaw-update-acpx.json
assert_update_ok /tmp/openclaw-update-acpx.json "$candidate_version"
assert_dep_available acpx acpx fi
echo"bundled channel runtime deps Docker update E2E passed"
EOF then cat"$run_log" rm -f "$run_log"
exit 1 fi
cat"$run_log" rm -f "$run_log"
}
run_load_failure_scenario() {
local run_log
run_log="$(mktemp "${TMPDIR:-/tmp}/openclaw-bundled-channel-load-failure.XXXXXX")"
echo"Running bundled channel load-failure isolation Docker E2E..." if ! timeout "$DOCKER_RUN_TIMEOUT" docker run --rm \
-e COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \ "${PACKAGE_DOCKER_ARGS[@]}" \
-i "$IMAGE_NAME" bash -s >"$run_log" 2>&1 <<'EOF'
set -euo pipefail
const id = "load-failure-alpha"; for (let i = 0; i < 2; i += 1) { for (const [name, fn] of oneArgExports) {
try {
fn(id);
} catch (error) {
const message = error instanceof Error ? error.message : String(error); if (message.includes("synthetic")) {
throw new Error(`bundled export ${name} leaked synthetic load failure: ${message}`);
}
}
}
}
const counts = {
plugin: globalThis.__loadFailurePlugin,
setup: globalThis.__loadFailureSetup,
secrets: globalThis.__loadFailureSecrets,
setupSecrets: globalThis.__loadFailureSetupSecrets,
}; for (const [key, value] of Object.entries({
plugin: counts.plugin,
setup: counts.setup,
setupSecrets: counts.setupSecrets,
})) { if (value !== 1) {
throw new Error(`expected ${key} failure to be cached after one load, got ${value}`);
}
} if (counts.secrets !== undefined && counts.secrets !== 1) {
throw new Error(`expected secrets failure to be cached after one load when exercised, got ${counts.secrets}`);
}
console.log("synthetic bundled channel load failures were isolated and cached");
NODE
)
echo"bundled channel load-failure isolation Docker E2E passed"
EOF then cat"$run_log" rm -f "$run_log"
exit 1 fi
cat"$run_log" rm -f "$run_log"
}
if [ "$RUN_CHANNEL_SCENARIOS" != "0" ]; then
IFS=',' read -r -a CHANNEL_SCENARIOS <<<"${OPENCLAW_BUNDLED_CHANNELS:-${CHANNEL_ONLY:-telegram,discord,slack,feishu,memory-lancedb}}" for channel_scenario in "${CHANNEL_SCENARIOS[@]}"; do
channel_scenario="${channel_scenario//[[:space:]]/}"
[ -n "$channel_scenario" ] || continue
case "$channel_scenario" in
telegram) run_channel_scenario telegram grammy ;;
discord) run_channel_scenario discord discord-api-types ;;
slack) run_channel_scenario slack @slack/web-api ;;
feishu) run_channel_scenario feishu @larksuiteoapi/node-sdk ;;
memory-lancedb) run_channel_scenario memory-lancedb @lancedb/lancedb ;;
*) echo"Unsupported OPENCLAW_BUNDLED_CHANNELS entry: $channel_scenario" >&2
exit 1
;;
esac done fi if [ "$RUN_UPDATE_SCENARIO" != "0" ]; then
run_update_scenario fi if [ "$RUN_ROOT_OWNED_SCENARIO" != "0" ]; then
run_root_owned_global_scenario fi if [ "$RUN_SETUP_ENTRY_SCENARIO" != "0" ]; then
run_setup_entry_scenario fi if [ "$RUN_DISABLED_CONFIG_SCENARIO" != "0" ]; then
run_disabled_config_scenario fi if [ "$RUN_LOAD_FAILURE_SCENARIO" != "0" ]; then
run_load_failure_scenario fi
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.38 Sekunden
(vorverarbeitet am 2026-04-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.