mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 21:51:39 +00:00
* feat(gateway): stream node.invoke progress with idle timeouts and cancel * feat(node-host): opt-in approval-gated claude cli agent run command * feat(agents): run node-placed claude-cli turns through streaming node invoke * feat(anthropic): continue claude catalog sessions on advertising nodes * docs(nodes): document paired-node claude agent runs and continuation * chore(plugin-sdk): admit spawn-invocation helper into surface budget * fix(nodes): harden streaming invoke and node run policy from review findings * test(node-host): prove multi-token tool-policy argv fails closed * fix(nodes): allowlist cancel event for apps and break node-host type cycle * chore(protocol): regenerate Swift gateway models for node invoke progress * chore(node-host): drop test-only export surface flagged by deadcode ratchet * style(node-host): merge invoke-types imports * refactor(nodes): split node agent run modules to satisfy the LOC ratchet * chore(protocol): regenerate android gateway models and sync export baseline * chore(plugin-sdk): admit spawn-invocation helper and inherited deprecated drift into surface budget * chore(plugin-sdk): tolerate inherited agent-core deprecated export * fix(anthropic): drop node param parser orphaned by upstream catalog split * ci: sync unused-export baseline with healed main * test(agents): adopt renamed cli backend prepare helper * style(node-host): format claude run spawn invocation * ci: retrigger checks * chore(plugin-sdk): pin surface budgets to healed-base counts * fix(protocol): restore untyped lazy validators after upstream style change
80 lines
2.3 KiB
TypeScript
80 lines
2.3 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
get: vi.fn(),
|
|
invoke: vi.fn(),
|
|
getRuntimeConfig: vi.fn(() => ({})),
|
|
isNodeCommandAllowed: vi.fn(),
|
|
resolveNodeCommandAllowlist: vi.fn(() => new Set<string>()),
|
|
}));
|
|
|
|
vi.mock("./server-plugin-fallback-context.js", () => ({
|
|
getFallbackGatewayContext: () => ({
|
|
getRuntimeConfig: mocks.getRuntimeConfig,
|
|
nodeRegistry: { get: mocks.get, invoke: mocks.invoke },
|
|
}),
|
|
}));
|
|
|
|
vi.mock("./node-command-policy.js", () => ({
|
|
isNodeCommandAllowed: mocks.isNodeCommandAllowed,
|
|
resolveNodeCommandAllowlist: mocks.resolveNodeCommandAllowlist,
|
|
}));
|
|
|
|
import { invokeNodeClaudeCliRun } from "./node-agent-cli-runtime.js";
|
|
|
|
describe("invokeNodeClaudeCliRun", () => {
|
|
beforeEach(() => {
|
|
mocks.get.mockReset();
|
|
mocks.invoke.mockReset();
|
|
mocks.getRuntimeConfig.mockClear();
|
|
mocks.resolveNodeCommandAllowlist.mockClear();
|
|
mocks.isNodeCommandAllowed.mockReset();
|
|
mocks.get.mockReturnValue({
|
|
connId: "conn-1",
|
|
nodeId: "node-1",
|
|
commands: ["agent.cli.claude.run.v1"],
|
|
});
|
|
});
|
|
|
|
it("fails closed when Gateway node command policy denies the agent run", async () => {
|
|
mocks.isNodeCommandAllowed.mockReturnValue({ ok: false, reason: "denyCommands" });
|
|
|
|
await expect(
|
|
invokeNodeClaudeCliRun({
|
|
nodeId: "node-1",
|
|
argv: ["-p"],
|
|
stdin: "hello",
|
|
timeoutMs: 10_000,
|
|
idleTimeoutMs: 1_000,
|
|
onProgress: () => {},
|
|
}),
|
|
).resolves.toEqual({
|
|
ok: false,
|
|
error: {
|
|
code: "PERMISSION_DENIED",
|
|
message:
|
|
"paired-node Claude CLI agent runs are blocked by node command policy (denyCommands)",
|
|
},
|
|
});
|
|
expect(mocks.invoke).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("dispatches only after the command policy allows the advertised command", async () => {
|
|
mocks.isNodeCommandAllowed.mockReturnValue({ ok: true });
|
|
mocks.invoke.mockResolvedValue({ ok: true });
|
|
|
|
await expect(
|
|
invokeNodeClaudeCliRun({
|
|
nodeId: "node-1",
|
|
argv: ["-p"],
|
|
stdin: "hello",
|
|
timeoutMs: 10_000,
|
|
idleTimeoutMs: 1_000,
|
|
onProgress: () => {},
|
|
}),
|
|
).resolves.toEqual({ ok: true });
|
|
expect(mocks.resolveNodeCommandAllowlist).toHaveBeenCalledOnce();
|
|
expect(mocks.invoke).toHaveBeenCalledOnce();
|
|
});
|
|
});
|