mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(plugins): keep OpenCode Go bundled (#120985)
* fix(plugins): keep OpenCode Go bundled * fix(plugins): mark OpenCode Go dist bundled * fix(docs): show OpenCode Go as bundled * fix(release): defer bundled plugin publication
This commit is contained in:
committed by
GitHub
parent
8b0735e89f
commit
c092900e3c
@@ -51,7 +51,7 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
## Core npm package
|
||||
|
||||
54 plugins
|
||||
55 plugins
|
||||
|
||||
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
|
||||
|
||||
@@ -131,6 +131,8 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
- **[openai](/plugins/reference/openai)** (`@openclaw/openai-provider`) - included in OpenClaw. Adds OpenAI model provider support to OpenClaw.
|
||||
|
||||
- **[opencode-go](/plugins/reference/opencode-go)** (`@openclaw/opencode-go-provider`) - included in OpenClaw. Adds OpenCode Go model provider support to OpenClaw.
|
||||
|
||||
- **[openrouter](/plugins/reference/openrouter)** (`@openclaw/openrouter-provider`) - included in OpenClaw. Adds OpenRouter model provider support to OpenClaw.
|
||||
|
||||
- **[policy](/plugins/reference/policy)** (`@openclaw/policy`) - included in OpenClaw. Adds policy-backed doctor checks for workspace conformance.
|
||||
@@ -163,7 +165,7 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
## Official external packages
|
||||
|
||||
91 plugins
|
||||
90 plugins
|
||||
|
||||
- **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management.
|
||||
|
||||
@@ -279,8 +281,6 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
- **[opencode](/plugins/reference/opencode)** (`@openclaw/opencode-provider`) - npm; ClawHub: `clawhub:@openclaw/opencode-provider`. Adds OpenCode model provider support to OpenClaw.
|
||||
|
||||
- **[opencode-go](/plugins/reference/opencode-go)** (`@openclaw/opencode-go-provider`) - npm; ClawHub: `clawhub:@openclaw/opencode-go-provider`. Adds OpenCode Go model provider support to OpenClaw.
|
||||
|
||||
- **[openshell](/plugins/reference/openshell)** (`@openclaw/openshell-sandbox`) - npm; ClawHub. OpenClaw sandbox backend for the NVIDIA OpenShell CLI with mirrored local workspaces and SSH command execution.
|
||||
|
||||
- **[parallel](/tools/parallel-search)** (`@openclaw/parallel-plugin`) - npm; ClawHub: `clawhub:@openclaw/parallel-plugin`. Adds web search provider support.
|
||||
|
||||
@@ -12,7 +12,7 @@ Adds OpenCode Go model provider support to OpenClaw.
|
||||
## Distribution
|
||||
|
||||
- Package: `@openclaw/opencode-go-provider`
|
||||
- Install route: npm; ClawHub: `clawhub:@openclaw/opencode-go-provider`
|
||||
- Install route: included in OpenClaw
|
||||
|
||||
## Surface
|
||||
|
||||
|
||||
@@ -9,24 +9,21 @@ title: "OpenCode Go"
|
||||
OpenCode Go is the Go catalog inside [OpenCode](/providers/opencode). It shares
|
||||
the `OPENCODE_API_KEY` credential with the Zen catalog, but keeps its own
|
||||
runtime provider id (`opencode-go`) so upstream per-model routing stays
|
||||
correct. OpenClaw provides it as the official external
|
||||
`@openclaw/opencode-go-provider` plugin.
|
||||
correct. OpenCode Go is bundled in the OpenClaw package for this release, so
|
||||
onboarding and configuration are sufficient; no separate plugin install is
|
||||
required.
|
||||
|
||||
| Property | Value |
|
||||
| ---------------- | -------------------------------------------------- |
|
||||
| Runtime provider | `opencode-go` |
|
||||
| Plugin | `@openclaw/opencode-go-provider` |
|
||||
| Plugin | Bundled (`opencode-go`) |
|
||||
| Auth | `OPENCODE_API_KEY` (alias: `OPENCODE_ZEN_API_KEY`) |
|
||||
| Parent setup | [OpenCode](/providers/opencode) |
|
||||
|
||||
## Getting started
|
||||
|
||||
Install the official plugin and restart the Gateway:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/opencode-go-provider
|
||||
openclaw gateway restart
|
||||
```
|
||||
OpenCode Go is already included with OpenClaw for this release. Continue with
|
||||
interactive onboarding or pass the shared OpenCode API key directly.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Interactive">
|
||||
|
||||
@@ -55,11 +55,9 @@ one OpenCode setup.
|
||||
**Best for:** the OpenCode-hosted Kimi, GLM, MiniMax, Qwen, and DeepSeek lineup.
|
||||
|
||||
<Steps>
|
||||
<Step title="Install the Go catalog plugin">
|
||||
```bash
|
||||
openclaw plugins install @openclaw/opencode-go-provider
|
||||
openclaw gateway restart
|
||||
```
|
||||
<Step title="Use the bundled Go catalog">
|
||||
OpenCode Go is included with OpenClaw for this release, so no separate
|
||||
plugin installation or Gateway restart is required.
|
||||
</Step>
|
||||
<Step title="Run onboarding">
|
||||
```bash
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
Official OpenClaw provider plugin for the OpenCode Go model catalog.
|
||||
|
||||
Install from OpenClaw:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/opencode-go-provider
|
||||
openclaw gateway restart
|
||||
```
|
||||
OpenCode Go is bundled with OpenClaw for this release; no separate plugin
|
||||
installation is required.
|
||||
|
||||
Configure `OPENCODE_API_KEY` or `OPENCODE_ZEN_API_KEY`, then select an
|
||||
`opencode-go/...` model.
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.8.1",
|
||||
"bundledDist": false
|
||||
"bundledDist": true
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
|
||||
@@ -307,7 +307,6 @@
|
||||
"!dist/extensions/nostr/**",
|
||||
"!dist/extensions/novita/**",
|
||||
"!dist/extensions/opencode/**",
|
||||
"!dist/extensions/opencode-go/**",
|
||||
"!dist/extensions/parallel/**",
|
||||
"!dist/extensions/perplexity/**",
|
||||
"!dist/extensions/qianfan/**",
|
||||
|
||||
@@ -334,6 +334,10 @@ function resolveInstallRoute(packageJson, status) {
|
||||
return "source checkout only";
|
||||
}
|
||||
if (status === "core") {
|
||||
// Explicit bundle ownership describes the current install surface; release flags may stage future publication.
|
||||
if (packageJson.openclaw?.build?.bundledDist === true) {
|
||||
return "included in OpenClaw";
|
||||
}
|
||||
const release = packageJson.openclaw?.release;
|
||||
if (release?.publishToClawHub === true || release?.publishToNpm === true) {
|
||||
return `included in OpenClaw; ${resolveInstallRoute(packageJson, "external")}`;
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
collectChangedExtensionIdsFromPaths,
|
||||
collectPublishablePluginPackageErrors,
|
||||
collectRequiredLatestDependencies,
|
||||
isPluginExternalPublicationDeferred,
|
||||
assertPluginReleaseVersionFloors,
|
||||
parsePluginReleaseArgs,
|
||||
resolvePublishablePluginVersion,
|
||||
@@ -45,6 +46,7 @@ type PluginPackageJson = {
|
||||
minGatewayVersion?: string;
|
||||
};
|
||||
build?: {
|
||||
bundledDist?: boolean;
|
||||
openclawVersion?: string;
|
||||
pluginSdkVersion?: string;
|
||||
};
|
||||
@@ -283,6 +285,9 @@ export function collectClawHubPublishablePluginPackages(
|
||||
if (hasSelectedPackageNames && !selectedPackageNames.has(packageName)) {
|
||||
continue;
|
||||
}
|
||||
if (isPluginExternalPublicationDeferred(packageJson)) {
|
||||
continue;
|
||||
}
|
||||
if (packageJson.openclaw?.release?.publishToClawHub !== true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type PluginPackageJson = {
|
||||
minGatewayVersion?: string;
|
||||
};
|
||||
build?: {
|
||||
bundledDist?: boolean;
|
||||
openclawVersion?: string;
|
||||
pluginSdkVersion?: string;
|
||||
};
|
||||
@@ -45,6 +46,13 @@ type PluginPackageJson = {
|
||||
};
|
||||
};
|
||||
|
||||
/** Explicit core ownership defers staged external publication until the plugin is externalized. */
|
||||
export function isPluginExternalPublicationDeferred(packageJson: {
|
||||
openclaw?: { build?: { bundledDist?: unknown } };
|
||||
}): boolean {
|
||||
return packageJson.openclaw?.build?.bundledDist === true;
|
||||
}
|
||||
|
||||
export type RequiredLatestDependency = {
|
||||
packageName: string;
|
||||
version: string;
|
||||
@@ -430,6 +438,9 @@ export function collectPublishablePluginPackages(
|
||||
if (hasSelectedPackageNames && !selectedPackageNames.has(packageName)) {
|
||||
continue;
|
||||
}
|
||||
if (isPluginExternalPublicationDeferred(packageJson)) {
|
||||
continue;
|
||||
}
|
||||
if (packageJson.openclaw?.release?.publishToNpm !== true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,41 @@ function writeProviderPlugin(rootDir: string): void {
|
||||
);
|
||||
}
|
||||
|
||||
function writeBundledOpenCodeGoPlugin(bundledPluginsDir: string): void {
|
||||
const pluginDir = path.join(bundledPluginsDir, "opencode-go");
|
||||
fs.mkdirSync(pluginDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(pluginDir, "index.js"), "export default {};\n", "utf8");
|
||||
fs.writeFileSync(
|
||||
path.join(pluginDir, "package.json"),
|
||||
JSON.stringify({
|
||||
name: "@openclaw/opencode-go-provider",
|
||||
version: "2026.8.1",
|
||||
openclaw: {
|
||||
extensions: ["./index.js"],
|
||||
install: {
|
||||
clawhubSpec: "clawhub:@openclaw/opencode-go-provider",
|
||||
npmSpec: "@openclaw/opencode-go-provider",
|
||||
defaultChoice: "npm",
|
||||
},
|
||||
build: { openclawVersion: "2026.8.1" },
|
||||
release: { publishToClawHub: true, publishToNpm: true },
|
||||
},
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(pluginDir, "openclaw.plugin.json"),
|
||||
JSON.stringify({
|
||||
id: "opencode-go",
|
||||
activation: { onStartup: false },
|
||||
enabledByDefault: true,
|
||||
providers: ["opencode-go"],
|
||||
configSchema: { type: "object", additionalProperties: false, properties: {} },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
}
|
||||
|
||||
describe("configured plugin install health for explicit load paths", () => {
|
||||
it("does not install a provider plugin already present at a configured load path", async () => {
|
||||
const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-load-path-provider-"));
|
||||
@@ -80,4 +115,53 @@ describe("configured plugin install health for explicit load paths", () => {
|
||||
warnings: [],
|
||||
});
|
||||
});
|
||||
|
||||
it("discovers packaged OpenCode Go before configured-plugin repair", async () => {
|
||||
const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-bundled-opencode-go-"));
|
||||
tempDirs.push(rootDir);
|
||||
const homeDir = path.join(rootDir, "home");
|
||||
const stateDir = path.join(rootDir, "state");
|
||||
const configPath = path.join(stateDir, "openclaw.json");
|
||||
const bundledPluginsDir = path.join(rootDir, "dist", "extensions");
|
||||
fs.mkdirSync(homeDir, { recursive: true });
|
||||
fs.mkdirSync(stateDir, { recursive: true });
|
||||
writeBundledOpenCodeGoPlugin(bundledPluginsDir);
|
||||
|
||||
const cfg = {
|
||||
auth: {
|
||||
profiles: {
|
||||
"opencode-go:default": { provider: "opencode-go", mode: "api_key" as const },
|
||||
},
|
||||
},
|
||||
};
|
||||
fs.writeFileSync(configPath, `${JSON.stringify(cfg)}\n`, "utf8");
|
||||
const env = {
|
||||
HOME: homeDir,
|
||||
USERPROFILE: homeDir,
|
||||
OPENCLAW_HOME: homeDir,
|
||||
OPENCLAW_STATE_DIR: stateDir,
|
||||
OPENCLAW_CONFIG_PATH: configPath,
|
||||
OPENCLAW_BUNDLED_PLUGINS_DIR: bundledPluginsDir,
|
||||
OPENCLAW_DISABLE_BUNDLED_SOURCE_OVERLAYS: "1",
|
||||
OPENCLAW_TEST_TRUST_BUNDLED_PLUGINS_DIR: "1",
|
||||
NPM_CONFIG_REGISTRY: "http://127.0.0.1:9",
|
||||
npm_config_registry: "http://127.0.0.1:9",
|
||||
XDG_CONFIG_HOME: path.join(rootDir, "xdg-config"),
|
||||
VITEST: "true",
|
||||
};
|
||||
const snapshot = loadManifestMetadataSnapshot({ config: cfg, env });
|
||||
expect(snapshot.plugins).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ id: "opencode-go", origin: "bundled" })]),
|
||||
);
|
||||
|
||||
const issues = await detectConfiguredPluginInstallHealthIssues({ cfg, env });
|
||||
expect(issues).toStrictEqual([]);
|
||||
|
||||
const repair = await repairMissingConfiguredPluginInstalls({ cfg, env });
|
||||
expect(repair).toStrictEqual({
|
||||
changes: [],
|
||||
records: {},
|
||||
warnings: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -540,6 +540,28 @@ describe("collectPluginReleasePlan", () => {
|
||||
});
|
||||
|
||||
describe("collectPublishablePluginPackages", () => {
|
||||
it("defers explicitly bundled plugins from npm and ClawHub release plans", () => {
|
||||
const repoDir = makeTempRepoRoot(tempDirs, "openclaw-plugin-npm-release-");
|
||||
mkdirSync(join(repoDir, "extensions", "demo-plugin"), { recursive: true });
|
||||
writePluginReadme(repoDir, "demo-plugin");
|
||||
writeJsonFile(join(repoDir, "extensions", "demo-plugin", "package.json"), {
|
||||
name: "@openclaw/demo-plugin",
|
||||
version: "2026.4.10",
|
||||
type: "module",
|
||||
repository: { type: "git", url: OPENCLAW_PLUGIN_NPM_REPOSITORY_URL },
|
||||
openclaw: {
|
||||
extensions: ["./index.ts"],
|
||||
...externalPluginContract("2026.4.10"),
|
||||
build: { openclawVersion: "2026.4.10", bundledDist: true },
|
||||
install: { npmSpec: "@openclaw/demo-plugin" },
|
||||
release: { publishToClawHub: true, publishToNpm: true },
|
||||
},
|
||||
});
|
||||
|
||||
expect(collectPublishablePluginPackages(repoDir)).toStrictEqual([]);
|
||||
expect(collectClawHubPublishablePluginPackages(repoDir)).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it("keeps publishable plugin dist trees out of the core npm package unless bundled", () => {
|
||||
const corePackageRuntimePluginIds = new Set(["discord"]);
|
||||
const rootPackage = JSON.parse(readFileSync("package.json", "utf8")) as {
|
||||
|
||||
@@ -356,7 +356,6 @@ describe("bundled plugin build entries", () => {
|
||||
"mistral",
|
||||
"novita",
|
||||
"opencode",
|
||||
"opencode-go",
|
||||
"xiaomi",
|
||||
]) {
|
||||
expect(artifacts).not.toContain(`dist/extensions/${pluginId}/index.js`);
|
||||
@@ -365,6 +364,18 @@ describe("bundled plugin build entries", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps OpenCode Go bundled until its companion artifact is available", () => {
|
||||
const artifacts = listBundledPluginPackArtifacts();
|
||||
|
||||
expect(artifacts).toEqual(
|
||||
expect.arrayContaining([
|
||||
"dist/extensions/opencode-go/index.js",
|
||||
"dist/extensions/opencode-go/openclaw.plugin.json",
|
||||
"dist/extensions/opencode-go/package.json",
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("excludes the externalized Vydra provider from bundled artifacts", () => {
|
||||
const artifacts = listBundledPluginPackArtifacts();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user