mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
fix(update): sync skills after binary upgrades
This commit is contained in:
@@ -142,6 +142,7 @@ export default defineCommand({
|
||||
`\n${color.green(`\u2713 Update complete: ${currentVersion} \u2192 ${newVer}`)}\n`,
|
||||
);
|
||||
writeUpdateState(newVer);
|
||||
updateAgentSkill(color);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const reinstall =
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, beforeEach, expect, test, vi } from "vite-plus/test";
|
||||
|
||||
const runtimeMocks = vi.hoisted(() => ({
|
||||
performBinaryUpdate: vi.fn(),
|
||||
}));
|
||||
|
||||
const childProcessMocks = vi.hoisted(() => ({
|
||||
execSync: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("bailian-cli-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("bailian-cli-runtime")>();
|
||||
return { ...actual, performBinaryUpdate: runtimeMocks.performBinaryUpdate };
|
||||
});
|
||||
|
||||
vi.mock("child_process", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("child_process")>();
|
||||
return { ...actual, execSync: childProcessMocks.execSync };
|
||||
});
|
||||
|
||||
import updateCommand from "../src/commands/update.ts";
|
||||
|
||||
let configDir: string;
|
||||
let previousConfigDir: string | undefined;
|
||||
let previousInstallMethod: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
configDir = mkdtempSync(join(tmpdir(), "bl-update-binary-"));
|
||||
previousConfigDir = process.env.BAILIAN_CONFIG_DIR;
|
||||
previousInstallMethod = process.env.BAILIAN_INSTALL_METHOD;
|
||||
process.env.BAILIAN_CONFIG_DIR = configDir;
|
||||
process.env.BAILIAN_INSTALL_METHOD = "binary";
|
||||
runtimeMocks.performBinaryUpdate.mockResolvedValue("1.15.0");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (previousConfigDir === undefined) delete process.env.BAILIAN_CONFIG_DIR;
|
||||
else process.env.BAILIAN_CONFIG_DIR = previousConfigDir;
|
||||
if (previousInstallMethod === undefined) delete process.env.BAILIAN_INSTALL_METHOD;
|
||||
else process.env.BAILIAN_INSTALL_METHOD = previousInstallMethod;
|
||||
rmSync(configDir, { recursive: true, force: true });
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test("binary bl update syncs bailian skills after the CLI update succeeds", async () => {
|
||||
await updateCommand.run({
|
||||
identity: {
|
||||
binName: "bl",
|
||||
clientName: "bailian-cli",
|
||||
npmPackage: "bailian-cli",
|
||||
version: "1.14.3",
|
||||
},
|
||||
flags: { to: "1.15.0" },
|
||||
settings: {},
|
||||
} as never);
|
||||
|
||||
expect(runtimeMocks.performBinaryUpdate).toHaveBeenCalledWith("1.15.0");
|
||||
expect(childProcessMocks.execSync).toHaveBeenCalledWith("bl skill init", { stdio: "inherit" });
|
||||
});
|
||||
@@ -209,6 +209,25 @@ function errorMessage(err: unknown): string {
|
||||
return String(err);
|
||||
}
|
||||
|
||||
async function syncAgentSkillsAfterUpdate(
|
||||
dim: string,
|
||||
green: string,
|
||||
yellow: string,
|
||||
reset: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
process.stderr.write(` ${dim}Syncing agent skill...${reset}\n`);
|
||||
const { execSync } = await import("child_process");
|
||||
execSync("bl skill init", { stdio: "inherit" });
|
||||
process.stderr.write(` ${green}\u2713 Agent skill updated.${reset}\n\n`);
|
||||
} catch (error) {
|
||||
process.stderr.write(
|
||||
` ${yellow}\u26a0 Agent skill sync failed: ${errorMessage(error)}${reset}\n`,
|
||||
);
|
||||
process.stderr.write(` ${yellow} Run manually: bl skill init${reset}\n\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform auto-update for npm or binary installs.
|
||||
* Returns true if update succeeded, false otherwise.
|
||||
@@ -256,6 +275,7 @@ export async function performAutoUpdate(
|
||||
writeState({ lastChecked: Date.now(), latestVersion: newVer });
|
||||
process.stderr.write(` ${green}✓ Update complete: ${currentVersion} → ${newVer}${reset}\n`);
|
||||
process.stderr.write(` ${dim}Run ${cyan}bl --version${reset}${dim} to verify.${reset}\n\n`);
|
||||
await syncAgentSkillsAfterUpdate(dim, green, yellow, reset);
|
||||
pendingNotification = null;
|
||||
return true;
|
||||
} catch (err) {
|
||||
@@ -297,14 +317,7 @@ export async function performAutoUpdate(
|
||||
);
|
||||
process.stderr.write(` ${dim}Run ${cyan}bl --version${reset}${dim} to verify.${reset}\n\n`);
|
||||
|
||||
try {
|
||||
process.stderr.write(` ${dim}Syncing agent skill...${reset}\n`);
|
||||
execSync(`bl skill init`, { stdio: "inherit" });
|
||||
process.stderr.write(` ${green}✓ Agent skill updated.${reset}\n\n`);
|
||||
} catch (err) {
|
||||
process.stderr.write(` ${yellow}⚠ Agent skill sync failed: ${errorMessage(err)}${reset}\n`);
|
||||
process.stderr.write(` ${yellow} Run manually: bl skill init${reset}\n\n`);
|
||||
}
|
||||
await syncAgentSkillsAfterUpdate(dim, green, yellow, reset);
|
||||
|
||||
pendingNotification = null;
|
||||
return true;
|
||||
|
||||
@@ -1,13 +1,58 @@
|
||||
import { expect, test } from "vite-plus/test";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, beforeEach, expect, test, vi } from "vite-plus/test";
|
||||
|
||||
const binaryUpdateMocks = vi.hoisted(() => ({
|
||||
performBinaryUpdate: vi.fn(),
|
||||
}));
|
||||
|
||||
const childProcessMocks = vi.hoisted(() => ({
|
||||
execSync: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../src/utils/binary-update.ts", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../src/utils/binary-update.ts")>();
|
||||
return { ...actual, performBinaryUpdate: binaryUpdateMocks.performBinaryUpdate };
|
||||
});
|
||||
|
||||
vi.mock("child_process", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("child_process")>();
|
||||
return { ...actual, execSync: childProcessMocks.execSync };
|
||||
});
|
||||
|
||||
import {
|
||||
compareVersion,
|
||||
isMajorUpgrade,
|
||||
isNewerVersion,
|
||||
isPrerelease,
|
||||
parseVersion,
|
||||
performAutoUpdate,
|
||||
shouldAutoUpdate,
|
||||
} from "../src/utils/update-checker.ts";
|
||||
|
||||
let configDir: string;
|
||||
let previousConfigDir: string | undefined;
|
||||
let previousInstallMethod: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
configDir = mkdtempSync(join(tmpdir(), "bl-auto-update-binary-"));
|
||||
previousConfigDir = process.env.BAILIAN_CONFIG_DIR;
|
||||
previousInstallMethod = process.env.BAILIAN_INSTALL_METHOD;
|
||||
process.env.BAILIAN_CONFIG_DIR = configDir;
|
||||
process.env.BAILIAN_INSTALL_METHOD = "binary";
|
||||
binaryUpdateMocks.performBinaryUpdate.mockResolvedValue("2.0.0");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (previousConfigDir === undefined) delete process.env.BAILIAN_CONFIG_DIR;
|
||||
else process.env.BAILIAN_CONFIG_DIR = previousConfigDir;
|
||||
if (previousInstallMethod === undefined) delete process.env.BAILIAN_INSTALL_METHOD;
|
||||
else process.env.BAILIAN_INSTALL_METHOD = previousInstallMethod;
|
||||
rmSync(configDir, { recursive: true, force: true });
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test("parseVersion strips pre-release and build metadata", () => {
|
||||
expect(parseVersion("1.4.2")).toEqual([1, 4, 2]);
|
||||
expect(parseVersion("2.0.0-beta.1")).toEqual([2, 0, 0]);
|
||||
@@ -124,3 +169,11 @@ test("shouldAutoUpdate only targets stable releases with a significant gap", ()
|
||||
// Same core, release over its pre-release: notify only (no major gap).
|
||||
expect(shouldAutoUpdate("1.4.2", "1.4.2-beta.1")).toBe(false);
|
||||
});
|
||||
|
||||
test("binary auto-update syncs bailian skills after the CLI update succeeds", async () => {
|
||||
const updated = await performAutoUpdate("1.14.3", "2.0.0");
|
||||
|
||||
expect(updated).toBe(true);
|
||||
expect(binaryUpdateMocks.performBinaryUpdate).toHaveBeenCalledWith("2.0.0");
|
||||
expect(childProcessMocks.execSync).toHaveBeenCalledWith("bl skill init", { stdio: "inherit" });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user