mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 14:01:24 +08:00
Compare commits
18 Commits
codex/fix-
...
v2026.4.29
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c0879a462 | ||
|
|
f677c8c201 | ||
|
|
bd739cf851 | ||
|
|
328782f5f3 | ||
|
|
41ab6dda15 | ||
|
|
ff4526d78b | ||
|
|
aa728d0c29 | ||
|
|
456350c5f4 | ||
|
|
ed42f6ae49 | ||
|
|
2077855627 | ||
|
|
0f40bbe4a4 | ||
|
|
3adce23d89 | ||
|
|
a898a8e926 | ||
|
|
eb250c1e59 | ||
|
|
21521cd19c | ||
|
|
5a6e2f1270 | ||
|
|
255d5b3b9a | ||
|
|
f6086965f0 |
@@ -13,6 +13,8 @@ Docs: https://docs.openclaw.ai
|
||||
- Channel fixes cluster around Slack Block Kit limits, Telegram proxy/webhook/polling/send resilience, Discord startup/rate-limit handling, WhatsApp delivery/liveness, and Microsoft Teams/Matrix/Feishu edge cases. Thanks @slackapi, @SymbolStar, @djgeorg3, @TinyTb, @dseravalli, @nklock, and @alex-xuweilong.
|
||||
- Security and operations add OpenGrep scanning, sharper GHSA triage policy, safer exec/pairing/owner-scope handling, Docker/onboarding automation, and web-fetch IPv6 ULA opt-in for trusted proxy stacks. Thanks @jesse-merhi, @pgondhi987, @mmaps, @jinjimz, and @jeffrey701.
|
||||
|
||||
## 2026.4.29
|
||||
|
||||
### Changes
|
||||
|
||||
- Agents/commitments: add opt-in inferred follow-up commitments with hidden batched extraction, per-agent/per-channel scoping, heartbeat delivery, CLI management, a simple `commitments.enabled`/`commitments.maxPerDay` config, and heartbeat-interval due-time clamping so magical check-ins do not echo immediately. (#74189) Thanks @vignesh07.
|
||||
|
||||
@@ -65,8 +65,8 @@ android {
|
||||
applicationId = "ai.openclaw.app"
|
||||
minSdk = 31
|
||||
targetSdk = 36
|
||||
versionCode = 2026042700
|
||||
versionName = "2026.4.27"
|
||||
versionCode = 2026042900
|
||||
versionName = "2026.4.29"
|
||||
ndk {
|
||||
// Support all major ABIs — native libs are tiny (~47 KB per ABI)
|
||||
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# OpenClaw iOS Changelog
|
||||
|
||||
## 2026.4.29 - 2026-04-29
|
||||
|
||||
Maintenance update for the current OpenClaw development release.
|
||||
|
||||
## 2026.4.27 - 2026-04-27
|
||||
|
||||
Maintenance update for the current OpenClaw development release.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Source of truth: apps/ios/version.json
|
||||
// Generated by scripts/ios-sync-versioning.ts.
|
||||
|
||||
OPENCLAW_IOS_VERSION = 2026.4.27
|
||||
OPENCLAW_MARKETING_VERSION = 2026.4.27
|
||||
OPENCLAW_IOS_VERSION = 2026.4.29
|
||||
OPENCLAW_MARKETING_VERSION = 2026.4.29
|
||||
OPENCLAW_BUILD_VERSION = 1
|
||||
|
||||
#include? "../build/Version.xcconfig"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "2026.4.27"
|
||||
"version": "2026.4.29"
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.4.27</string>
|
||||
<string>2026.4.29</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2026042700</string>
|
||||
<string>2026042900</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>OpenClaw</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
c3bcb3a3da46bbbe15a7798869911cab109df950ee51c79fd86c96bb809dfdf1 config-baseline.json
|
||||
d4b34f6fd2c39132bf4feff4be5ddfd226fa52c4596d6bdc438031456dde18d4 config-baseline.json
|
||||
8f573caa7f4cf01ae9d4805d3d14e1ba6772f651f6da182baaf2b469592749a4 config-baseline.core.json
|
||||
92712871defa92eeda8161b516db85574681f2b70678b940508a808b987aeae2 config-baseline.channel.json
|
||||
aca3215b7382af82b5060d73c631a7f82661c6e99193fa5eb1c5b4b499fb657b config-baseline.plugin.json
|
||||
6005cf9f6e8c9f25ef97207b5eee29ae0e506cf910cdeca77fc9894ad1755b1f config-baseline.plugin.json
|
||||
|
||||
@@ -120,10 +120,12 @@ const codexAppServerApprovalPolicySchema = z.enum([
|
||||
]);
|
||||
const codexAppServerSandboxSchema = z.enum(["read-only", "workspace-write", "danger-full-access"]);
|
||||
const codexAppServerApprovalsReviewerSchema = z.enum(["user", "auto_review", "guardian_subagent"]);
|
||||
const codexAppServerServiceTierSchema = z.preprocess(
|
||||
(value) => (value === null ? null : resolveServiceTier(value)),
|
||||
z.enum(["fast", "flex"]).nullable().optional(),
|
||||
);
|
||||
const codexAppServerServiceTierSchema = z
|
||||
.preprocess(
|
||||
(value) => (value === null ? null : resolveServiceTier(value)),
|
||||
z.enum(["fast", "flex"]).nullable().optional(),
|
||||
)
|
||||
.optional();
|
||||
|
||||
const codexPluginConfigSchema = z
|
||||
.object({
|
||||
|
||||
@@ -451,6 +451,8 @@ vi.mock("openclaw/plugin-sdk/error-runtime", async () => {
|
||||
|
||||
vi.mock(buildDiscordSourceModuleId("accounts.js"), () => ({
|
||||
resolveDiscordAccount: resolveDiscordAccountMock,
|
||||
resolveDiscordAccountAllowFrom: () => undefined,
|
||||
resolveDiscordAccountDmPolicy: () => undefined,
|
||||
}));
|
||||
|
||||
vi.mock(buildDiscordSourceModuleId("probe.js"), () => ({
|
||||
|
||||
@@ -18,6 +18,7 @@ let buildGoogleGenerativeAiParams: typeof import("./transport-stream.js").buildG
|
||||
let createGoogleGenerativeAiTransportStreamFn: typeof import("./transport-stream.js").createGoogleGenerativeAiTransportStreamFn;
|
||||
let createGoogleVertexTransportStreamFn: typeof import("./transport-stream.js").createGoogleVertexTransportStreamFn;
|
||||
let hasGoogleVertexAuthorizedUserAdcSync: typeof import("./vertex-adc.js").hasGoogleVertexAuthorizedUserAdcSync;
|
||||
let resetGoogleVertexAuthorizedUserTokenCacheForTest: typeof import("./vertex-adc.js").resetGoogleVertexAuthorizedUserTokenCacheForTest;
|
||||
|
||||
const MODEL_PROVIDER_REQUEST_TRANSPORT_SYMBOL = Symbol.for(
|
||||
"openclaw.modelProviderRequestTransport",
|
||||
@@ -91,13 +92,15 @@ describe("google transport stream", () => {
|
||||
createGoogleGenerativeAiTransportStreamFn,
|
||||
createGoogleVertexTransportStreamFn,
|
||||
} = await import("./transport-stream.js"));
|
||||
({ hasGoogleVertexAuthorizedUserAdcSync } = await import("./vertex-adc.js"));
|
||||
({ hasGoogleVertexAuthorizedUserAdcSync, resetGoogleVertexAuthorizedUserTokenCacheForTest } =
|
||||
await import("./vertex-adc.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
buildGuardedModelFetchMock.mockReset();
|
||||
guardedFetchMock.mockReset();
|
||||
buildGuardedModelFetchMock.mockReturnValue(guardedFetchMock);
|
||||
resetGoogleVertexAuthorizedUserTokenCacheForTest();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -377,7 +380,7 @@ describe("google transport stream", () => {
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
vi.stubEnv("GOOGLE_APPLICATION_CREDENTIALS", undefined);
|
||||
vi.stubEnv("GOOGLE_APPLICATION_CREDENTIALS", "");
|
||||
vi.stubEnv("HOME", homeDir);
|
||||
vi.stubEnv("APPDATA", appDataDir);
|
||||
vi.stubEnv("GOOGLE_CLOUD_PROJECT", "vertex-project");
|
||||
|
||||
@@ -22,6 +22,10 @@ const GOOGLE_OAUTH_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
||||
|
||||
let cachedGoogleVertexAuthorizedUserToken: GoogleVertexAuthorizedUserToken | undefined;
|
||||
|
||||
export function resetGoogleVertexAuthorizedUserTokenCacheForTest(): void {
|
||||
cachedGoogleVertexAuthorizedUserToken = undefined;
|
||||
}
|
||||
|
||||
function normalizeOptionalString(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openclaw",
|
||||
"version": "2026.4.27",
|
||||
"version": "2026.4.29-beta.1",
|
||||
"description": "Multi-channel AI gateway with extensible messaging integrations",
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/openclaw/openclaw#readme",
|
||||
|
||||
@@ -56,6 +56,7 @@ export function createWorkspaceBootstrapSmokeEnv(env, homeDir, overrides = {}) {
|
||||
OPENCLAW_HOME: homeDir,
|
||||
OPENCLAW_NO_ONBOARD: "1",
|
||||
OPENCLAW_SUPPRESS_NOTES: "1",
|
||||
OPENCLAW_DISABLE_BUNDLED_PLUGINS: "1",
|
||||
OPENCLAW_DISABLE_BUNDLED_ENTRY_SOURCE_FALLBACK: "1",
|
||||
AWS_EC2_METADATA_DISABLED: "true",
|
||||
AWS_SHARED_CREDENTIALS_FILE: join(homeDir, ".aws", "credentials"),
|
||||
@@ -135,8 +136,9 @@ export function runInstalledWorkspaceBootstrapSmoke(params) {
|
||||
const workspaceDir = join(homeDir, ".openclaw", "workspace");
|
||||
const missingFiles = collectMissingBootstrapWorkspaceFiles(workspaceDir);
|
||||
if (missingFiles.length > 0) {
|
||||
const outputDetails = combinedOutput.length > 0 ? `\nCommand output:\n${combinedOutput}` : "";
|
||||
throw new Error(
|
||||
`installed workspace bootstrap did not create required files in ${workspaceDir}: ${missingFiles.join(", ")}`,
|
||||
`installed workspace bootstrap did not create required files in ${workspaceDir}: ${missingFiles.join(", ")}${outputDetails}`,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -522,8 +522,12 @@ function runPackedTaskRegistryControlRuntimeSmoke(packageRoot: string): void {
|
||||
if (!existsSync(runtimePath)) {
|
||||
throw new Error("release-check: packed task-registry control runtime is missing.");
|
||||
}
|
||||
const runtimeImportExpression = [
|
||||
`(0, Function)("specifier", "return " + "im" + "port(specifier)")`,
|
||||
`(${JSON.stringify(pathToFileURL(runtimePath).href)})`,
|
||||
].join("");
|
||||
const source = `
|
||||
const runtime = await import(${JSON.stringify(pathToFileURL(runtimePath).href)});
|
||||
const runtime = await ${runtimeImportExpression};
|
||||
if (typeof runtime.getAcpSessionManager !== "function") {
|
||||
throw new Error("missing getAcpSessionManager export");
|
||||
}
|
||||
|
||||
@@ -33,6 +33,26 @@ vi.mock("../tts/tts.js", () => ({
|
||||
}));
|
||||
|
||||
const mockGetGlobalHookRunner = vi.mocked(getGlobalHookRunner);
|
||||
const hookRunnerGlobalStateKey = Symbol.for("openclaw.plugins.hook-runner-global-state");
|
||||
|
||||
type HookRunnerGlobalStateForTest = {
|
||||
hookRunner: unknown;
|
||||
registry: unknown;
|
||||
};
|
||||
|
||||
function setHookRunnerForTest(hookRunner: unknown): void {
|
||||
mockGetGlobalHookRunner.mockReturnValue(hookRunner as never);
|
||||
const globalStore = globalThis as Record<PropertyKey, unknown>;
|
||||
const state = (globalStore[hookRunnerGlobalStateKey] as
|
||||
| HookRunnerGlobalStateForTest
|
||||
| undefined) ?? {
|
||||
hookRunner: null,
|
||||
registry: null,
|
||||
};
|
||||
state.hookRunner = hookRunner;
|
||||
state.registry = null;
|
||||
globalStore[hookRunnerGlobalStateKey] = state;
|
||||
}
|
||||
|
||||
function createSessionFile(params?: { history?: Array<{ role: "user"; content: string }> }) {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-cli-hooks-"));
|
||||
@@ -127,6 +147,7 @@ describe("runCliAgent reliability", () => {
|
||||
afterEach(() => {
|
||||
replyRunTesting.resetReplyRunRegistry();
|
||||
mockGetGlobalHookRunner.mockReset();
|
||||
setHookRunnerForTest(null);
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
@@ -217,7 +238,7 @@ describe("runCliAgent reliability", () => {
|
||||
runLlmOutput: vi.fn(async () => undefined),
|
||||
runAgentEnd: vi.fn(async () => undefined),
|
||||
};
|
||||
mockGetGlobalHookRunner.mockReturnValue(hookRunner as never);
|
||||
setHookRunnerForTest(hookRunner);
|
||||
supervisorSpawnMock.mockClear();
|
||||
supervisorSpawnMock.mockResolvedValueOnce(
|
||||
createManagedRun({
|
||||
@@ -472,7 +493,7 @@ describe("runCliAgent reliability", () => {
|
||||
runLlmOutput: vi.fn(async () => undefined),
|
||||
runAgentEnd: vi.fn(async () => undefined),
|
||||
};
|
||||
mockGetGlobalHookRunner.mockReturnValue(hookRunner as never);
|
||||
setHookRunnerForTest(hookRunner);
|
||||
const { dir, sessionFile } = createSessionFile();
|
||||
|
||||
supervisorSpawnMock.mockResolvedValueOnce(
|
||||
@@ -572,7 +593,7 @@ describe("runCliAgent reliability", () => {
|
||||
runLlmOutput: vi.fn(async () => undefined),
|
||||
runAgentEnd: vi.fn(async () => undefined),
|
||||
};
|
||||
mockGetGlobalHookRunner.mockReturnValue(hookRunner as never);
|
||||
setHookRunnerForTest(hookRunner);
|
||||
|
||||
supervisorSpawnMock.mockResolvedValueOnce(
|
||||
createManagedRun({
|
||||
@@ -600,7 +621,7 @@ describe("runCliAgent reliability", () => {
|
||||
runLlmOutput: vi.fn(async () => undefined),
|
||||
runAgentEnd: vi.fn(async () => undefined),
|
||||
};
|
||||
mockGetGlobalHookRunner.mockReturnValue(hookRunner as never);
|
||||
setHookRunnerForTest(hookRunner);
|
||||
|
||||
supervisorSpawnMock.mockResolvedValueOnce(
|
||||
createManagedRun({
|
||||
@@ -644,7 +665,7 @@ describe("runCliAgent reliability", () => {
|
||||
runLlmOutput: vi.fn(async () => undefined),
|
||||
runAgentEnd: vi.fn(async () => undefined),
|
||||
};
|
||||
mockGetGlobalHookRunner.mockReturnValue(hookRunner as never);
|
||||
setHookRunnerForTest(hookRunner);
|
||||
const { dir, sessionFile } = createSessionFile({
|
||||
history: Array.from({ length: MAX_CLI_SESSION_HISTORY_MESSAGES + 5 }, (_, index) => ({
|
||||
role: "user" as const,
|
||||
@@ -725,7 +746,7 @@ describe("runCliAgent reliability", () => {
|
||||
runLlmOutput: vi.fn(async () => undefined),
|
||||
runAgentEnd: vi.fn(async () => undefined),
|
||||
};
|
||||
mockGetGlobalHookRunner.mockReturnValue(hookRunner as never);
|
||||
setHookRunnerForTest(hookRunner);
|
||||
const historySpy = vi.spyOn(sessionHistoryModule, "loadCliSessionHistoryMessages");
|
||||
|
||||
supervisorSpawnMock.mockResolvedValueOnce(
|
||||
@@ -791,7 +812,7 @@ describe("runCliAgent reliability", () => {
|
||||
runBeforePromptBuild: vi.fn(async () => ({ prependContext: "hook context" })),
|
||||
runBeforeAgentStart: vi.fn(async () => undefined),
|
||||
};
|
||||
mockGetGlobalHookRunner.mockReturnValue(hookRunner as never);
|
||||
setHookRunnerForTest(hookRunner);
|
||||
|
||||
try {
|
||||
const context = await prepareCliRunContext({
|
||||
|
||||
@@ -247,9 +247,14 @@ describe("buildWorkspaceSkillSnapshot", () => {
|
||||
);
|
||||
|
||||
// We should only have loaded a small subset.
|
||||
expect(snapshot.skills.length).toBeLessThanOrEqual(5);
|
||||
expect(snapshot.prompt).toContain("repo-skill-00");
|
||||
expect(snapshot.prompt).not.toContain("repo-skill-07");
|
||||
const skillNames = snapshot.skills.map((skill) => skill.name);
|
||||
expect(skillNames.length).toBeGreaterThan(0);
|
||||
expect(skillNames.length).toBeLessThanOrEqual(5);
|
||||
expect(new Set(skillNames).size).toBe(skillNames.length);
|
||||
for (const name of skillNames) {
|
||||
expect(name).toMatch(/^repo-skill-\d{2}$/);
|
||||
expect(snapshot.prompt).toContain(name);
|
||||
}
|
||||
});
|
||||
|
||||
it("skips skills whose SKILL.md exceeds maxSkillFileBytes", async () => {
|
||||
|
||||
@@ -147,6 +147,15 @@ export const cliCommandCatalog: readonly CliCommandCatalogEntry[] = [
|
||||
policy: { ensureCliPath: false, networkProxy: "bypass" },
|
||||
route: { id: "sessions" },
|
||||
},
|
||||
{
|
||||
commandPath: ["commitments"],
|
||||
policy: {
|
||||
ensureCliPath: false,
|
||||
routeConfigGuard: "when-suppressed",
|
||||
loadPlugins: "never",
|
||||
networkProxy: "bypass",
|
||||
},
|
||||
},
|
||||
{
|
||||
commandPath: ["agents", "list"],
|
||||
// Text and JSON output are derived from config plus read-only channel
|
||||
|
||||
@@ -121,7 +121,7 @@ const coreEntrySpecs: readonly CommandGroupDescriptorSpec<
|
||||
...withProgramOnlySpecs(
|
||||
defineImportedProgramCommandGroupSpecs([
|
||||
{
|
||||
commandNames: ["status", "health", "sessions", "tasks"],
|
||||
commandNames: ["status", "health", "sessions", "commitments", "tasks"],
|
||||
loadModule: () => import("./register.status-health-sessions.js"),
|
||||
exportName: "registerStatusHealthSessionsCommands",
|
||||
},
|
||||
|
||||
@@ -32,6 +32,7 @@ vi.mock("./register.status-health-sessions.js", () => ({
|
||||
program.command("status");
|
||||
program.command("health");
|
||||
program.command("sessions");
|
||||
program.command("commitments");
|
||||
const tasks = program.command("tasks");
|
||||
tasks.command("show");
|
||||
},
|
||||
@@ -86,6 +87,7 @@ describe("command-registry", () => {
|
||||
expect(names).toContain("backup");
|
||||
expect(names).toContain("mcp");
|
||||
expect(names).toContain("sessions");
|
||||
expect(names).toContain("commitments");
|
||||
expect(names).toContain("tasks");
|
||||
expect(names).not.toContain("agent");
|
||||
expect(names).not.toContain("crestodian");
|
||||
@@ -159,9 +161,22 @@ describe("command-registry", () => {
|
||||
expect(names).toContain("status");
|
||||
expect(names).toContain("health");
|
||||
expect(names).toContain("sessions");
|
||||
expect(names).toContain("commitments");
|
||||
expect(names).toContain("tasks");
|
||||
});
|
||||
|
||||
it("can eagerly register the status/session command group repeatedly for completion", async () => {
|
||||
const program = createProgram();
|
||||
|
||||
for (const name of ["status", "health", "sessions", "commitments", "tasks"]) {
|
||||
await expect(registerCoreCliByName(program, testProgramContext, name)).resolves.toBe(true);
|
||||
}
|
||||
|
||||
const names = namesOf(program);
|
||||
expect(names.filter((name) => name === "commitments")).toHaveLength(1);
|
||||
expect(names.filter((name) => name === "tasks")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("replaces placeholders when loading a grouped entry by secondary command name", async () => {
|
||||
const program = createProgram();
|
||||
registerCoreCliCommands(program, testProgramContext, ["node", "openclaw", "doctor"]);
|
||||
|
||||
@@ -95,6 +95,11 @@ const coreCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
description: "List stored conversation sessions",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "commitments",
|
||||
description: "List and manage inferred follow-up commitments",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "tasks",
|
||||
description: "Inspect durable background task state",
|
||||
|
||||
@@ -29102,6 +29102,6 @@ export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = {
|
||||
tags: ["advanced", "url-secret"],
|
||||
},
|
||||
},
|
||||
version: "2026.4.27",
|
||||
version: "2026.4.29-beta.1",
|
||||
generatedAt: "2026-03-22T21:17:33.302Z",
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildCliRespawnPlan,
|
||||
EXPERIMENTAL_WARNING_FLAG,
|
||||
@@ -7,26 +7,11 @@ import {
|
||||
resolveCliRespawnCommand,
|
||||
} from "./entry.respawn.js";
|
||||
|
||||
const shouldSkipRespawnForArgvMock = vi.hoisted(() => vi.fn(() => false));
|
||||
const isTruthyEnvValueMock = vi.hoisted(() =>
|
||||
vi.fn((value: string | undefined) => value === "1" || value === "true"),
|
||||
);
|
||||
|
||||
vi.mock("./cli/respawn-policy.js", () => ({
|
||||
shouldSkipRespawnForArgv: shouldSkipRespawnForArgvMock,
|
||||
}));
|
||||
|
||||
vi.mock("./infra/env.js", () => ({
|
||||
isTruthyEnvValue: isTruthyEnvValueMock,
|
||||
}));
|
||||
|
||||
describe("buildCliRespawnPlan", () => {
|
||||
it("returns null when respawn policy skips the argv", () => {
|
||||
shouldSkipRespawnForArgvMock.mockReturnValueOnce(true);
|
||||
|
||||
expect(
|
||||
buildCliRespawnPlan({
|
||||
argv: ["node", "openclaw", "status"],
|
||||
argv: ["node", "openclaw", "--help"],
|
||||
env: {},
|
||||
execArgv: [],
|
||||
autoNodeExtraCaCerts: "/etc/ssl/certs/ca-certificates.crt",
|
||||
|
||||
@@ -35,6 +35,7 @@ const EXPECTED_BUNDLED_STARTUP_PLUGIN_IDS = [
|
||||
"diagnostics-otel",
|
||||
"diagnostics-prometheus",
|
||||
"diffs",
|
||||
"file-transfer",
|
||||
"google-meet",
|
||||
"llm-task",
|
||||
"lobster",
|
||||
@@ -52,6 +53,7 @@ const EXPECTED_EMPTY_CONFIG_GATEWAY_STARTUP_PLUGIN_IDS = [
|
||||
"bonjour",
|
||||
"browser",
|
||||
"device-pair",
|
||||
"file-transfer",
|
||||
"memory-core",
|
||||
"phone-control",
|
||||
"talk-voice",
|
||||
|
||||
@@ -72,6 +72,10 @@ describe("collectAppcastSparkleVersionErrors", () => {
|
||||
});
|
||||
|
||||
describe("packed CLI smoke", () => {
|
||||
it("keeps generated dynamic imports opaque to tsx's source lexer", () => {
|
||||
expect(readFileSync("scripts/release-check.ts", "utf8")).not.toContain("import(");
|
||||
});
|
||||
|
||||
it("keeps the expected packaged CLI smoke command list", () => {
|
||||
expect(PACKED_CLI_SMOKE_COMMANDS).toEqual([
|
||||
["--help"],
|
||||
@@ -172,6 +176,7 @@ describe("workspace bootstrap smoke", () => {
|
||||
TMPDIR: "/tmp/original-tmp",
|
||||
OPENCLAW_NO_ONBOARD: "1",
|
||||
OPENCLAW_SUPPRESS_NOTES: "1",
|
||||
OPENCLAW_DISABLE_BUNDLED_PLUGINS: "1",
|
||||
OPENCLAW_DISABLE_BUNDLED_ENTRY_SOURCE_FALLBACK: "1",
|
||||
AWS_EC2_METADATA_DISABLED: "true",
|
||||
AWS_SHARED_CREDENTIALS_FILE: "/tmp/bootstrap-home/.aws/credentials",
|
||||
|
||||
@@ -591,10 +591,11 @@ export function syncUrlWithTab(host: SettingsHost, tab: Tab, replace: boolean) {
|
||||
}
|
||||
|
||||
export function syncUrlWithSessionKey(host: SettingsHost, sessionKey: string, replace: boolean) {
|
||||
if (typeof window === "undefined") {
|
||||
const href = typeof window === "undefined" ? undefined : window.location?.href;
|
||||
if (!href) {
|
||||
return;
|
||||
}
|
||||
const url = new URL(window.location.href);
|
||||
const url = new URL(href);
|
||||
url.searchParams.set("session", sessionKey);
|
||||
updateBrowserHistory(url, replace);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user