Skip to content

Commit c620265

Browse files
committed
fix(cli): limit plugin bulk channel sync
1 parent a328099 commit c620265

4 files changed

Lines changed: 59 additions & 11 deletions

File tree

src/cli/plugins-cli.update.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ describe("plugins cli update", () => {
979979
expect(updateParams.pluginIds).toEqual(["codex"]);
980980
expect(updateParams.syncOfficialPluginInstalls).toBeUndefined();
981981
expect(updateParams.updateChannel).toBeUndefined();
982+
expect(updateParams.officialPluginUpdateChannel).toBeUndefined();
982983
});
983984

984985
it("syncs official catalog specs with beta channel context for update --all", async () => {
@@ -1001,7 +1002,8 @@ describe("plugins cli update", () => {
10011002
const updateParams = expectSingleCallParams(updateNpmInstalledPlugins);
10021003
expect(updateParams.pluginIds).toEqual(["codex"]);
10031004
expect(updateParams.syncOfficialPluginInstalls).toBe(true);
1004-
expect(updateParams.updateChannel).toBe("beta");
1005+
expect(updateParams.officialPluginUpdateChannel).toBe("beta");
1006+
expect(updateParams.updateChannel).toBeUndefined();
10051007
});
10061008

10071009
it("writes updated config when updater reports changes", async () => {

src/cli/plugins-update-command.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ export async function runPluginUpdateCommand(params: {
261261
pluginIds: pluginSelection.pluginIds,
262262
specOverrides: pluginSelection.specOverrides,
263263
dryRun: params.opts.dryRun,
264-
updateChannel: params.opts.all
264+
officialPluginUpdateChannel: params.opts.all
265265
? (normalizeUpdateChannel(cfg.update?.channel) ?? undefined)
266266
: undefined,
267267
syncOfficialPluginInstalls: params.opts.all ? true : undefined,

src/plugins/update.test.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ const tempDirs: string[] = [];
4242

4343
vi.mock("./install.js", () => ({
4444
installPluginFromNpmSpec: (...args: unknown[]) => installPluginFromNpmSpecMock(...args),
45-
resolvePluginInstallDir: (pluginId: string, extensionsDir = "/tmp") =>
46-
`${extensionsDir}/${pluginId}`,
45+
resolvePluginInstallDir: (pluginId: string, extensionsDir = "/tmp") => {
46+
const separator = process.platform === "win32" ? "\\" : "/";
47+
return `${extensionsDir.replace(/[\\/]+$/, "")}${separator}${pluginId}`;
48+
},
4749
PLUGIN_INSTALL_ERROR_CODE: {
4850
NPM_PACKAGE_NOT_FOUND: "npm_package_not_found",
4951
},
@@ -1079,6 +1081,45 @@ describe("updateNpmInstalledPlugins", () => {
10791081
);
10801082
});
10811083

1084+
it("does not apply official beta-channel sync to third-party npm specs", async () => {
1085+
const installPath = createInstalledPackageDir({
1086+
name: "@martian-engineering/lossless-claw",
1087+
version: "0.9.0",
1088+
});
1089+
mockNpmViewMetadata({
1090+
name: "@martian-engineering/lossless-claw",
1091+
version: "0.9.1",
1092+
});
1093+
installPluginFromNpmSpecMock.mockResolvedValue(
1094+
createSuccessfulNpmUpdateResult({
1095+
pluginId: "lossless-claw",
1096+
targetDir: installPath,
1097+
version: "0.9.1",
1098+
npmResolution: {
1099+
name: "@martian-engineering/lossless-claw",
1100+
version: "0.9.1",
1101+
resolvedSpec: "@martian-engineering/[email protected]",
1102+
},
1103+
}),
1104+
);
1105+
1106+
await updateNpmInstalledPlugins({
1107+
config: createNpmInstallConfig({
1108+
pluginId: "lossless-claw",
1109+
spec: "@martian-engineering/lossless-claw",
1110+
installPath,
1111+
resolvedName: "@martian-engineering/lossless-claw",
1112+
resolvedSpec: "@martian-engineering/[email protected]",
1113+
resolvedVersion: "0.9.0",
1114+
}),
1115+
pluginIds: ["lossless-claw"],
1116+
syncOfficialPluginInstalls: true,
1117+
officialPluginUpdateChannel: "beta",
1118+
});
1119+
1120+
expect(npmInstallCall()?.spec).toBe("@martian-engineering/lossless-claw");
1121+
});
1122+
10821123
it("does not skip trusted official default updates when latest resolves to the installed prerelease", async () => {
10831124
const installPath = createInstalledPackageDir({
10841125
name: "@openclaw/acpx",
@@ -3906,10 +3947,11 @@ describe("updateNpmInstalledPlugins", () => {
39063947
pluginIds: ["demo"],
39073948
});
39083949

3909-
expect(npmInstallCall()?.extensionsDir).toBe(extensionsDir);
3910-
expect(clawHubInstallCall()?.extensionsDir).toBe(extensionsDir);
3911-
expect(marketplaceInstallCall()?.extensionsDir).toBe(extensionsDir);
3912-
expect(gitInstallCall()?.extensionsDir).toBe(extensionsDir);
3950+
const expectedExtensionsDir = path.resolve(extensionsDir);
3951+
expect(npmInstallCall()?.extensionsDir).toBe(expectedExtensionsDir);
3952+
expect(clawHubInstallCall()?.extensionsDir).toBe(expectedExtensionsDir);
3953+
expect(marketplaceInstallCall()?.extensionsDir).toBe(expectedExtensionsDir);
3954+
expect(gitInstallCall()?.extensionsDir).toBe(expectedExtensionsDir);
39133955
});
39143956
});
39153957

src/plugins/update.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,7 @@ export async function updateNpmInstalledPlugins(params: {
12381238
timeoutMs?: number;
12391239
dryRun?: boolean;
12401240
updateChannel?: UpdateChannel;
1241+
officialPluginUpdateChannel?: UpdateChannel;
12411242
dangerouslyForceUnsafeInstall?: boolean;
12421243
specOverrides?: Record<string, string>;
12431244
onIntegrityDrift?: (params: PluginUpdateIntegrityDriftParams) => boolean | Promise<boolean>;
@@ -1314,6 +1315,7 @@ export async function updateNpmInstalledPlugins(params: {
13141315
const officialClawHubSpec = params.syncOfficialPluginInstalls
13151316
? resolveTrustedSourceLinkedOfficialClawHubSpec({ pluginId, record })
13161317
: undefined;
1318+
const officialSyncUpdateChannel = params.officialPluginUpdateChannel ?? params.updateChannel;
13171319

13181320
if (normalizedPluginConfig) {
13191321
const enableState = resolveEffectiveEnableState({
@@ -1347,15 +1349,15 @@ export async function updateNpmInstalledPlugins(params: {
13471349
record,
13481350
specOverride: params.specOverrides?.[pluginId],
13491351
officialSpecOverride: officialNpmSpec,
1350-
updateChannel: params.updateChannel,
1352+
updateChannel: officialNpmSpec ? officialSyncUpdateChannel : params.updateChannel,
13511353
})
13521354
: undefined;
13531355
const clawhubSpecs =
13541356
record.source === "clawhub"
13551357
? resolveClawHubUpdateSpecs({
13561358
record,
13571359
officialSpecOverride: officialClawHubSpec,
1358-
updateChannel: params.updateChannel,
1360+
updateChannel: officialClawHubSpec ? officialSyncUpdateChannel : params.updateChannel,
13591361
})
13601362
: undefined;
13611363
const effectiveSpec =
@@ -1377,7 +1379,9 @@ export async function updateNpmInstalledPlugins(params: {
13771379
record,
13781380
effectiveClawHubSpec: effectiveSpec,
13791381
recordClawHubSpec: recordSpec,
1380-
updateChannel: params.updateChannel,
1382+
updateChannel: params.syncOfficialPluginInstalls
1383+
? officialSyncUpdateChannel
1384+
: params.updateChannel,
13811385
})
13821386
: null;
13831387
let officialNpmFallbackInstallSpec = officialNpmFallbackSpecs?.installSpec;

0 commit comments

Comments
 (0)