Official
acp
ACP agents from the ACP registry (Gemini, Cursor, Droid, Kilo, pi, ...), Oh My Pi, and your own entries (custom.json in the plugin's data folder). Agents are discovered at runtime.
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/acp@0.2.0
Permissions in 0.2.0
Take care. This plugin asks for permissions that can do anything your account can. The app asks you to hold Enable for two seconds or to type the plugin's name before it turns on.
Files
files.test.ts2.2 KB
import { test } from "node:test";
import assert from "node:assert/strict";
import { contain, parentOf, sliceLines } from "./files.ts";
// The `fs/*` bridge must refuse a path outside the session's workspace
// however it is spelled; the broker refuses the rest (symlinks out of the
// open workspaces).
test("the file bridge stays inside the workspace", () => {
const workspace = "/tmp/root/project";
// Inside: absolute, relative, and a file that does not exist yet.
assert.equal(contain(workspace, "/tmp/root/project/src/main.rs"), "/tmp/root/project/src/main.rs");
assert.equal(contain(workspace, "src/main.rs"), "/tmp/root/project/src/main.rs");
assert.equal(contain(workspace, "./src/new/deep.rs"), "/tmp/root/project/src/new/deep.rs");
assert.equal(contain(`${workspace}/`, "src/../src/a.rs"), "/tmp/root/project/src/a.rs");
// Outside, by absolute path and by climbing out with `..`.
assert.throws(() => contain(workspace, "/tmp/root/secret.txt"), /outside the workspace/);
assert.throws(() => contain(workspace, "../secret.txt"), /outside the workspace/);
assert.throws(() => contain(workspace, "/tmp/root/project/src/../../secret.txt"), /outside the workspace/);
assert.throws(() => contain(workspace, "/etc/passwd"), /outside the workspace/);
// A sibling that shares the prefix is not inside.
assert.throws(() => contain(workspace, "/tmp/root/project-other/a"), /outside the workspace/);
// No workspace, no files.
assert.throws(() => contain("", "/a"), /no workspace/);
});
test("Windows paths are compared by segment, the drive in any case", () => {
assert.equal(contain("C:\\w\\p", "src\\a.rs"), "C:/w/p/src/a.rs");
assert.equal(contain("C:\\w\\p", "c:\\w\\p\\b.rs"), "c:/w/p/b.rs");
assert.throws(() => contain("C:\\w\\p", "D:\\x"), /outside/);
});
test("text slices honour line and limit", () => {
assert.equal(sliceLines("a\nb\nc\n", undefined, undefined), "a\nb\nc\n");
assert.equal(sliceLines("a\nb\nc\n", 2, undefined), "b\nc");
assert.equal(sliceLines("a\nb\nc\n", 1, 2), "a\nb");
assert.equal(sliceLines("a\r\nb\r\n", 1, 1), "a");
});
test("the parent of a path", () => {
assert.equal(parentOf("/w/a/b.rs"), "/w/a");
assert.equal(parentOf("/b.rs"), "/");
});Versions
| Version | Published | Plugin API | Size | Permissions | Status |
|---|---|---|---|---|---|
| 0.2.0latest | Oct 5, 2026 | >=2 <3 | 94.9 KB | 6 permissions | Listed |
No comments yet.