mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:20:43 +00:00
fix(cli): keep update completion refresh lightweight
This commit is contained in:
@@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- CLI/update: keep the automatic post-update completion refresh on the core-command tree so it no longer stages bundled plugin runtime deps before the Gateway restart path, avoiding `.24` update hangs and 1006 disconnect cascades. Fixes #72665. Thanks @sakalaboator and @He-Pin.
|
||||
- Agents/Bedrock: stop heartbeat runs from persisting blank user transcript turns and repair existing blank user text messages before replay, preventing AWS Bedrock `ContentBlock` blank-text validation failures. Fixes #72640 and #72622. Thanks @goldzulu.
|
||||
- LM Studio: allow interactive onboarding to leave the API key blank for unauthenticated local servers, using local synthetic auth while clearing stale LM Studio auth profiles. Fixes #66937. Thanks @olamedia.
|
||||
- Process/Windows: decode command stdout and stderr from raw bytes with console-codepage awareness, while preserving valid UTF-8 output and multibyte characters split across chunks. Fixes #50519. Thanks @iready, @kevinten10, @zhangyongjie1997, @knightplat-blip, @heiqishi666, and @slepybear.
|
||||
|
||||
@@ -87,9 +87,10 @@ The Gateway core auto-updater (when enabled via config) reuses this same update
|
||||
For package-manager installs, `openclaw update` resolves the target package
|
||||
version before invoking the package manager. Even when the installed version
|
||||
already matches the target, the command refreshes the global package install,
|
||||
then runs plugin sync, completion refresh, and restart work. This keeps packaged
|
||||
sidecars and channel-owned plugin records aligned with the installed OpenClaw
|
||||
build.
|
||||
then runs plugin sync, a core-command completion refresh, and restart work. This
|
||||
keeps packaged sidecars and channel-owned plugin records aligned with the
|
||||
installed OpenClaw build while leaving full plugin-command completion rebuilds to
|
||||
explicit `openclaw completion --write-state` runs.
|
||||
|
||||
## Git checkout flow
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "./completion-fish.js";
|
||||
import {
|
||||
COMPLETION_SHELLS,
|
||||
COMPLETION_SKIP_PLUGIN_COMMANDS_ENV,
|
||||
installCompletion,
|
||||
isCompletionShell,
|
||||
resolveCompletionCachePath,
|
||||
@@ -106,10 +107,12 @@ export function registerCompletionCli(program: Command) {
|
||||
// Eagerly register all subcommands except completion itself to build the full tree.
|
||||
await registerSubcommandsForCompletion(program);
|
||||
|
||||
const { registerPluginCliCommandsFromValidatedConfig } = await import("../plugins/cli.js");
|
||||
await registerPluginCliCommandsFromValidatedConfig(program, undefined, undefined, {
|
||||
mode: "eager",
|
||||
});
|
||||
if (process.env[COMPLETION_SKIP_PLUGIN_COMMANDS_ENV] !== "1") {
|
||||
const { registerPluginCliCommandsFromValidatedConfig } = await import("../plugins/cli.js");
|
||||
await registerPluginCliCommandsFromValidatedConfig(program, undefined, undefined, {
|
||||
mode: "eager",
|
||||
});
|
||||
}
|
||||
|
||||
if (options.writeState) {
|
||||
const writeShells = options.shell ? [shell] : [...COMPLETION_SHELLS];
|
||||
|
||||
@@ -106,4 +106,35 @@ describe("completion-cli write-state", () => {
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
await fs.rm(homeDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("can skip plugin command registration for update-triggered cache writes", async () => {
|
||||
const [{ COMPLETION_SKIP_PLUGIN_COMMANDS_ENV }, { registerCompletionCli }] = await Promise.all([
|
||||
import("./completion-runtime.js"),
|
||||
import("./completion-cli.js"),
|
||||
]);
|
||||
const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-completion-state-"));
|
||||
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-completion-home-"));
|
||||
|
||||
process.env.OPENCLAW_STATE_DIR = stateDir;
|
||||
process.env.HOME = homeDir;
|
||||
process.env[COMPLETION_SKIP_PLUGIN_COMMANDS_ENV] = "1";
|
||||
|
||||
try {
|
||||
const program = new Command();
|
||||
program.name("openclaw");
|
||||
registerCompletionCli(program);
|
||||
|
||||
await program.parseAsync(["completion", "--write-state"], { from: "user" });
|
||||
|
||||
expect(registerSubCliByNameMock).toHaveBeenCalledWith(program, "qa");
|
||||
expect(registerPluginCliCommandsFromValidatedConfigMock).not.toHaveBeenCalled();
|
||||
expect(await fs.readdir(path.join(stateDir, "completions"))).toEqual(
|
||||
expect.arrayContaining(["openclaw.bash", "openclaw.fish", "openclaw.ps1", "openclaw.zsh"]),
|
||||
);
|
||||
} finally {
|
||||
delete process.env[COMPLETION_SKIP_PLUGIN_COMMANDS_ENV];
|
||||
await fs.rm(stateDir, { recursive: true, force: true });
|
||||
await fs.rm(homeDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import { pathExists } from "../utils.js";
|
||||
|
||||
export const COMPLETION_SHELLS = ["zsh", "bash", "powershell", "fish"] as const;
|
||||
export type CompletionShell = (typeof COMPLETION_SHELLS)[number];
|
||||
export const COMPLETION_SKIP_PLUGIN_COMMANDS_ENV = "OPENCLAW_COMPLETION_SKIP_PLUGIN_COMMANDS";
|
||||
|
||||
export function isCompletionShell(value: string): value is CompletionShell {
|
||||
return COMPLETION_SHELLS.includes(value as CompletionShell);
|
||||
|
||||
@@ -540,7 +540,12 @@ describe("update-cli", () => {
|
||||
expect(spawnSync).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
[path.join(root, "openclaw.mjs"), "completion", "--write-state"],
|
||||
expect.objectContaining({ timeout: 30_000 }),
|
||||
expect.objectContaining({
|
||||
env: expect.objectContaining({
|
||||
OPENCLAW_COMPLETION_SKIP_PLUGIN_COMMANDS: "1",
|
||||
}),
|
||||
timeout: 30_000,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { defaultRuntime } from "../../runtime.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import { theme } from "../../terminal/theme.js";
|
||||
import { pathExists } from "../../utils.js";
|
||||
import { COMPLETION_SKIP_PLUGIN_COMMANDS_ENV } from "../completion-runtime.js";
|
||||
|
||||
export type UpdateCommandOptions = {
|
||||
json?: boolean;
|
||||
@@ -268,7 +269,10 @@ export async function tryWriteCompletionCache(root: string, jsonMode: boolean):
|
||||
|
||||
const result = spawnSync(resolveNodeRunner(), [binPath, "completion", "--write-state"], {
|
||||
cwd: root,
|
||||
env: process.env,
|
||||
env: {
|
||||
...process.env,
|
||||
[COMPLETION_SKIP_PLUGIN_COMMANDS_ENV]: "1",
|
||||
},
|
||||
encoding: "utf-8",
|
||||
timeout: COMPLETION_CACHE_WRITE_TIMEOUT_MS,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user