fix: stage ACP and Codex runtime deps

This commit is contained in:
Peter Steinberger
2026-04-21 08:46:14 +01:00
parent 6a4a60fe25
commit 047acaa176
16 changed files with 162 additions and 5 deletions

View File

@@ -16,6 +16,10 @@
"type": "string",
"minLength": 1
},
"probeAgent": {
"type": "string",
"minLength": 1
},
"permissionMode": {
"type": "string",
"enum": ["approve-all", "approve-reads", "deny-all"]
@@ -87,6 +91,11 @@
"label": "State Directory",
"help": "Directory used for embedded ACP session state and persistence."
},
"probeAgent": {
"label": "Health Probe Agent",
"help": "Agent id used for the embedded ACP runtime health probe. Defaults to Codex when unset.",
"advanced": true
},
"permissionMode": {
"label": "Permission Mode",
"help": "Default permission policy for embedded ACP runtime prompts."

View File

@@ -12,6 +12,9 @@
"openclaw": {
"extensions": [
"./index.ts"
]
],
"bundle": {
"stageRuntimeDependencies": true
}
}
}

View File

@@ -25,6 +25,7 @@ declare module "acpx/runtime" {
cwd: string;
sessionStore: AcpSessionStore;
agentRegistry: AcpAgentRegistry;
probeAgent?: string;
mcpServers?: unknown;
permissionMode?: unknown;
nonInteractivePermissions?: unknown;

View File

@@ -26,6 +26,7 @@ export type AcpxMcpServer = {
export type AcpxPluginConfig = {
cwd?: string;
stateDir?: string;
probeAgent?: string;
permissionMode?: AcpxPermissionMode;
nonInteractivePermissions?: AcpxNonInteractivePermissionPolicy;
pluginToolsMcpBridge?: boolean;
@@ -39,6 +40,7 @@ export type AcpxPluginConfig = {
export type ResolvedAcpxPluginConfig = {
cwd: string;
stateDir: string;
probeAgent?: string;
permissionMode: AcpxPermissionMode;
nonInteractivePermissions: AcpxNonInteractivePermissionPolicy;
pluginToolsMcpBridge: boolean;
@@ -77,6 +79,7 @@ const McpServerConfigSchema = z.object({
export const AcpxPluginConfigSchema = z.strictObject({
cwd: nonEmptyTrimmedString("cwd must be a non-empty string").optional(),
stateDir: nonEmptyTrimmedString("stateDir must be a non-empty string").optional(),
probeAgent: nonEmptyTrimmedString("probeAgent must be a non-empty string").optional(),
permissionMode: z
.enum(ACPX_PERMISSION_MODES, {
error: `permissionMode must be one of: ${ACPX_PERMISSION_MODES.join(", ")}`,

View File

@@ -30,6 +30,17 @@ describe("embedded acpx plugin config", () => {
expect(resolved.timeoutSeconds).toBe(300);
});
it("keeps explicit probeAgent config", () => {
const resolved = resolveAcpxPluginConfig({
rawConfig: {
probeAgent: "claude",
},
workspaceDir: "/tmp/openclaw-acpx",
});
expect(resolved.probeAgent).toBe("claude");
});
it("accepts agent command overrides", () => {
const resolved = resolveAcpxPluginConfig({
rawConfig: {
@@ -74,6 +85,7 @@ describe("embedded acpx plugin config", () => {
properties: expect.objectContaining({
cwd: expect.any(Object),
stateDir: expect.any(Object),
probeAgent: expect.any(Object),
timeoutSeconds: expect.objectContaining({
default: 120,
}),

View File

@@ -219,6 +219,7 @@ export function resolveAcpxPluginConfig(params: {
return {
cwd,
stateDir,
probeAgent: normalized.probeAgent,
permissionMode: normalized.permissionMode ?? DEFAULT_PERMISSION_MODE,
nonInteractivePermissions:
normalized.nonInteractivePermissions ?? DEFAULT_NON_INTERACTIVE_POLICY,

View File

@@ -0,0 +1,22 @@
import fs from "node:fs";
import { describe, expect, it } from "vitest";
type AcpxPackageManifest = {
dependencies?: Record<string, string>;
openclaw?: {
bundle?: {
stageRuntimeDependencies?: boolean;
};
};
};
describe("acpx package manifest", () => {
it("opts into staging bundled runtime dependencies", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
) as AcpxPackageManifest;
expect(packageJson.dependencies?.acpx).toBeDefined();
expect(packageJson.openclaw?.bundle?.stageRuntimeDependencies).toBe(true);
});
});

View File

@@ -48,6 +48,7 @@ function createDefaultRuntime(params: AcpxRuntimeFactoryParams): AcpxRuntimeLike
agentRegistry: createAgentRegistry({
overrides: params.pluginConfig.agents,
}),
probeAgent: params.pluginConfig.probeAgent,
mcpServers: toAcpMcpServers(params.pluginConfig.mcpServers),
permissionMode: params.pluginConfig.permissionMode,
nonInteractivePermissions: params.pluginConfig.nonInteractivePermissions,

View File

@@ -14,6 +14,9 @@
"openclaw": {
"extensions": [
"./index.ts"
]
],
"bundle": {
"stageRuntimeDependencies": true
}
}
}

View File

@@ -0,0 +1,22 @@
import fs from "node:fs";
import { describe, expect, it } from "vitest";
type CodexPackageManifest = {
dependencies?: Record<string, string>;
openclaw?: {
bundle?: {
stageRuntimeDependencies?: boolean;
};
};
};
describe("codex package manifest", () => {
it("opts into staging bundled runtime dependencies", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
) as CodexPackageManifest;
expect(packageJson.dependencies?.["@mariozechner/pi-coding-agent"]).toBeDefined();
expect(packageJson.openclaw?.bundle?.stageRuntimeDependencies).toBe(true);
});
});