Official
claude
Claude Code agent provider: runs the Claude Code CLI headless for each account.
The app opens the listing; nothing installs until an agent in your Plugins workspace has read the files and you enable the plugin. In a terminal: cvg install convergence/claude@0.2.0
Permissions in 0.2.0
Files
tools.test.ts5.5 KB
// Ported from the Rust plugin's tools.rs tests.
import assert from "node:assert/strict";
import { contentAs, required, test } from "./testing.ts";
import {
diffsFromInput,
kindOf,
pluginTool,
resultContent,
resultText,
startContent,
titleOf,
toolCall,
planFromTodos,
locationsOf,
} from "./tools.ts";
test("a workflow call is titled by its meta and shows its script", () => {
const script =
"export const meta = {\n name: 'review',\n description: \"Check the auth changes\",\n phases: [{ title: 'Find' }],\n}\nphase('Find')\n";
const input = { script };
assert.equal(titleOf("Workflow", input), "Workflow review: Check the auth changes");
assert.deepEqual(startContent("Workflow", input), [{ type: "text", text: script }]);
const resumed = { scriptPath: "/c/workflows/scripts/probe-wf_47a42fba-b24.js", resumeFromRunId: "wf_47a42fba-b24" };
assert.equal(titleOf("Workflow", resumed), "Workflow probe");
// `name` inside the description is not the name.
assert.equal(
titleOf("Workflow", { script: "export const meta = { description: 'rename: x', name: \"real\" }" }),
"Workflow real: rename: x",
);
assert.equal(titleOf("Workflow", {}), "Workflow");
});
test("a path tool is titled by its path alone", () => {
assert.equal(titleOf("Read", { file_path: "/w/a.rs" }), "/w/a.rs");
assert.equal(titleOf("Edit", { file_path: "/w/a.rs", old_string: "x" }), "/w/a.rs");
assert.equal(titleOf("Unknown", { path: "/w/a.rs" }), "Unknown /w/a.rs");
assert.equal(titleOf("Read", {}), "Read");
});
test("tools are classified by name", () => {
assert.equal(kindOf("Read"), "read");
assert.equal(kindOf("MultiEdit"), "edit");
assert.equal(kindOf("Bash"), "execute");
assert.equal(kindOf("Glob"), "search");
assert.equal(kindOf("WebSearch"), "fetch");
assert.equal(kindOf("Task"), "task");
assert.equal(kindOf("Agent"), "task", "the current CLI calls the subagent tool Agent");
assert.equal(kindOf("mcp__pencil__get_screenshot"), "other");
});
test("a subagent call is titled by its description", () => {
const input = { description: "Search the tests", prompt: "find them", subagent_type: "Explore" };
assert.equal(titleOf("Agent", input), "Search the tests");
assert.equal(titleOf("Task", input), "Search the tests");
assert.equal(titleOf("Agent", { prompt: "\n look for the parser\nthen stop" }), "look for the parser");
assert.equal(titleOf("Agent", {}), "Agent");
assert.equal(titleOf("SendMessage", { to: "a12", message: "keep going\nplease" }), "Message: keep going");
assert.equal(titleOf("SendMessage", { to: "a12", summary: "Resume", message: "long" }), "Message: Resume");
assert.equal(titleOf("SendMessage", { to: "a12" }), "Message to a12");
assert.equal(titleOf("SendMessage", {}), "SendMessage");
});
test("a plugin tool is titled by its own name", () => {
assert.equal(titleOf("mcp__convergence__now", {}), "now");
assert.equal(titleOf("mcp__convergence__execute", { code: "return 1" }), "execute");
assert.equal(titleOf("mcp__convergence__open", { path: "/w/a.rs" }), "open /w/a.rs");
assert.equal(titleOf("mcp__pencil__get_screenshot", {}), "mcp__pencil__get_screenshot");
assert.equal(pluginTool("mcp__convergence__now"), "now");
assert.equal(pluginTool("mcp__convergencex__now"), null);
const call = toolCall("toolu_1", "mcp__convergence__execute", { code: "return 1" }, "pending");
assert.equal(call.title, "execute");
assert.deepEqual(call.input, { code: "return 1" }, "the code stays visible");
});
test("edit input becomes a unified diff", () => {
const content = diffsFromInput("Edit", { file_path: "/tmp/a.txt", old_string: "one\n", new_string: "two\n" });
assert.equal(content[0].type, "diff");
assert.equal(content[0].path, "/tmp/a.txt");
assert.equal(content[0].newText, undefined);
assert.match(required(content[0].diff), /-one/);
assert.match(required(content[0].diff), /\+two/);
const multi = diffsFromInput("MultiEdit", {
file_path: "/a",
edits: [
{ old_string: "a\n", new_string: "b\n" },
{ old_string: "c\n", new_string: "d\n" },
],
});
assert.equal(required(required(contentAs(multi[0], "diff").diff).match(/^@@/gm)).length, 2);
});
test("write input becomes a whole file snapshot", () => {
const content = diffsFromInput("Write", { file_path: "/tmp/a.txt", content: "hello\n" });
assert.equal(contentAs(content[0], "diff").newText, "hello\n");
assert.equal(contentAs(content[0], "diff").diff, undefined);
});
test("a bash result becomes a terminal", () => {
const content = resultContent("Bash", { command: "ls -l" }, "a\n", { stdout: "a\n", exitCode: 2 });
assert.deepEqual(content, [{ type: "terminal", command: "ls -l", output: "a\n", exitCode: 2 }]);
assert.deepEqual(startContent("Bash", { command: "ls" }), [{ type: "terminal", command: "ls", output: "" }]);
});
test("tool result content flattens blocks", () => {
assert.equal(resultText("plain"), "plain");
assert.equal(
resultText([
{ type: "text", text: "a" },
{ type: "text", text: "b" },
]),
"ab",
);
assert.equal(resultText([{ type: "image" }]), "[image]");
assert.equal(resultText(null), "");
});
test("todos become a plan, and a path with an offset a located line", () => {
assert.deepEqual(planFromTodos({ todos: [{ content: "one", status: "in_progress" }, { activeForm: "two" }] }), {
entries: [
{ content: "one", status: "in_progress" },
{ content: "two", status: "pending" },
],
});
assert.deepEqual(locationsOf({ file_path: "/a", offset: 12 }), [{ path: "/a", line: 12 }]);
});Versions
| Version | Published | Plugin API | Size | Permissions | Status |
|---|---|---|---|---|---|
| 0.2.0latest | Oct 5, 2026 | >=2 <3 | 128.7 KB | 4 permissions | Listed |
No comments yet.