mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 22:44:16 +00:00
refactor(acp): extract install hint resolver
This commit is contained in:
@@ -331,7 +331,7 @@ Then verify backend health:
|
||||
|
||||
### acpx command and version configuration
|
||||
|
||||
By default, `@openclaw/acpx` uses the plugin-local pinned binary:
|
||||
By default, the acpx plugin (published as `@openclaw/acpx`) uses the plugin-local pinned binary:
|
||||
|
||||
1. Command defaults to `extensions/acpx/node_modules/.bin/acpx`.
|
||||
2. Expected version defaults to the extension pin.
|
||||
|
||||
56
src/auto-reply/reply/commands-acp/install-hints.test.ts
Normal file
56
src/auto-reply/reply/commands-acp/install-hints.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import { resolveAcpInstallCommandHint, resolveConfiguredAcpBackendId } from "./install-hints.js";
|
||||
|
||||
const originalCwd = process.cwd();
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
function withAcpConfig(acp: OpenClawConfig["acp"]): OpenClawConfig {
|
||||
return { acp } as OpenClawConfig;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
process.chdir(originalCwd);
|
||||
for (const dir of tempDirs.splice(0)) {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe("ACP install hints", () => {
|
||||
it("prefers explicit runtime install command", () => {
|
||||
const cfg = withAcpConfig({
|
||||
runtime: { installCommand: "pnpm openclaw plugins install acpx" },
|
||||
});
|
||||
expect(resolveAcpInstallCommandHint(cfg)).toBe("pnpm openclaw plugins install acpx");
|
||||
});
|
||||
|
||||
it("uses local acpx extension path when present", () => {
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "acp-install-hint-"));
|
||||
tempDirs.push(tempRoot);
|
||||
fs.mkdirSync(path.join(tempRoot, "extensions", "acpx"), { recursive: true });
|
||||
process.chdir(tempRoot);
|
||||
|
||||
const cfg = withAcpConfig({ backend: "acpx" });
|
||||
const hint = resolveAcpInstallCommandHint(cfg);
|
||||
expect(hint).toContain("openclaw plugins install ");
|
||||
expect(hint).toContain(path.join("extensions", "acpx"));
|
||||
});
|
||||
|
||||
it("falls back to npm install hint for acpx when local extension is absent", () => {
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "acp-install-hint-"));
|
||||
tempDirs.push(tempRoot);
|
||||
process.chdir(tempRoot);
|
||||
|
||||
const cfg = withAcpConfig({ backend: "acpx" });
|
||||
expect(resolveAcpInstallCommandHint(cfg)).toBe("openclaw plugins install acpx");
|
||||
});
|
||||
|
||||
it("returns generic plugin hint for non-acpx backend", () => {
|
||||
const cfg = withAcpConfig({ backend: "custom-backend" });
|
||||
expect(resolveConfiguredAcpBackendId(cfg)).toBe("custom-backend");
|
||||
expect(resolveAcpInstallCommandHint(cfg)).toContain('ACP backend "custom-backend"');
|
||||
});
|
||||
});
|
||||
23
src/auto-reply/reply/commands-acp/install-hints.ts
Normal file
23
src/auto-reply/reply/commands-acp/install-hints.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
|
||||
export function resolveConfiguredAcpBackendId(cfg: OpenClawConfig): string {
|
||||
return cfg.acp?.backend?.trim() || "acpx";
|
||||
}
|
||||
|
||||
export function resolveAcpInstallCommandHint(cfg: OpenClawConfig): string {
|
||||
const configured = cfg.acp?.runtime?.installCommand?.trim();
|
||||
if (configured) {
|
||||
return configured;
|
||||
}
|
||||
const backendId = resolveConfiguredAcpBackendId(cfg).toLowerCase();
|
||||
if (backendId === "acpx") {
|
||||
const localPath = path.resolve(process.cwd(), "extensions/acpx");
|
||||
if (existsSync(localPath)) {
|
||||
return `openclaw plugins install ${localPath}`;
|
||||
}
|
||||
return "openclaw plugins install acpx";
|
||||
}
|
||||
return `Install and enable the plugin that provides ACP backend "${backendId}".`;
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { toAcpRuntimeErrorText } from "../../../acp/runtime/error-text.js";
|
||||
import type { AcpRuntimeError } from "../../../acp/runtime/errors.js";
|
||||
import type { AcpRuntimeSessionMode } from "../../../acp/runtime/types.js";
|
||||
import { DISCORD_THREAD_BINDING_CHANNEL } from "../../../channels/thread-bindings-policy.js";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import type { AcpSessionRuntimeOptions } from "../../../config/sessions/types.js";
|
||||
import { normalizeAgentId } from "../../../routing/session-key.js";
|
||||
import type { CommandHandlerResult, HandleCommandsParams } from "../commands-types.js";
|
||||
import { resolveAcpCommandChannel, resolveAcpCommandThreadId } from "./context.js";
|
||||
export { resolveAcpInstallCommandHint, resolveConfiguredAcpBackendId } from "./install-hints.js";
|
||||
|
||||
export const COMMAND = "/acp";
|
||||
export const ACP_SPAWN_USAGE =
|
||||
@@ -404,26 +402,6 @@ export function resolveAcpHelpText(): string {
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
export function resolveConfiguredAcpBackendId(cfg: OpenClawConfig): string {
|
||||
return cfg.acp?.backend?.trim() || "acpx";
|
||||
}
|
||||
|
||||
export function resolveAcpInstallCommandHint(cfg: OpenClawConfig): string {
|
||||
const configured = cfg.acp?.runtime?.installCommand?.trim();
|
||||
if (configured) {
|
||||
return configured;
|
||||
}
|
||||
const backendId = resolveConfiguredAcpBackendId(cfg).toLowerCase();
|
||||
if (backendId === "acpx") {
|
||||
const localPath = path.resolve(process.cwd(), "extensions/acpx");
|
||||
if (existsSync(localPath)) {
|
||||
return `openclaw plugins install ${localPath}`;
|
||||
}
|
||||
return "openclaw plugins install acpx";
|
||||
}
|
||||
return `Install and enable the plugin that provides ACP backend "${backendId}".`;
|
||||
}
|
||||
|
||||
export function formatRuntimeOptionsText(options: AcpSessionRuntimeOptions): string {
|
||||
const extras = options.backendExtras
|
||||
? Object.entries(options.backendExtras)
|
||||
|
||||
Reference in New Issue
Block a user