Official
terminal
Built-in integrated terminal (JavaScript UI plugin).
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/terminal@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
state.test.ts2.5 KB
// Test workspace isolation, saved session selection, and terminal pane identity.
// Session removal must choose a neighbour in the same workspace, even with interleaved sessions.
import assert from "node:assert/strict";
import test from "node:test";
import type { Terminal, Workspace } from "convergence";
import { activeTerminal, forWorkspace, nextTerminal, pathsByWorkspace, terminalInPane } from "./state.ts";
const terminal = (id: string, workspaceId: string | null = "w1"): Terminal => ({
id,
title: id,
userTitle: null,
cwd: "/",
workspaceId,
running: true,
exitCode: null,
});
test("terminals stay scoped to their workspace", () => {
assert.deepEqual(
forWorkspace([terminal("a"), terminal("b", "w2"), terminal("c")], "w1").map(({ id }) => id),
["a", "c"],
);
});
test("active session uses its saved choice, then the last workspace session", () => {
const terminals = [terminal("a"), terminal("b"), terminal("other", "w2")];
assert.equal(activeTerminal({ terminals, activeByWorkspace: { w1: "a" } }, "w1")?.id, "a");
assert.equal(activeTerminal({ terminals, activeByWorkspace: {} }, "w1")?.id, "b");
assert.equal(activeTerminal({ terminals, activeByWorkspace: {} }, "missing"), null);
assert.equal(activeTerminal({ terminals, activeByWorkspace: { w1: "other" } }, "w1")?.id, "b");
assert.equal(activeTerminal({ terminals, activeByWorkspace: { w1: "deleted" } }, "w1")?.id, "b");
assert.equal(activeTerminal({ terminals, activeByWorkspace: { w1: null } }, "w1")?.id, "b");
});
test("pane session and workspace paths are derived from host state", () => {
assert.equal(terminalInPane({ kind: "terminal", path: "term-1" }), "term-1");
assert.equal(terminalInPane({ kind: "file", path: "a.ts" }), null);
assert.equal(terminalInPane(null), null);
assert.equal(terminalInPane("nope"), null);
const workspaces: Workspace[] = [{ id: "w1", name: "one", path: "/one", position: 0 }];
assert.deepEqual(pathsByWorkspace(workspaces), { w1: "/one" });
});
test("closing chooses the next workspace session, then its previous one", () => {
const first = terminal("first");
const middle = terminal("middle");
const last = terminal("last");
const terminals = [first, terminal("other", "w2"), middle, last];
assert.equal(nextTerminal(terminals, first)?.id, "middle");
assert.equal(nextTerminal(terminals, middle)?.id, "last");
assert.equal(nextTerminal(terminals, last)?.id, "middle");
assert.equal(nextTerminal([first, terminal("other", "w2")], first), null);
});Versions
| Version | Published | Plugin API | Size | Permissions | Status |
|---|---|---|---|---|---|
| 0.2.0latest | Oct 5, 2026 | >=2 <3 | 8.7 KB | 3 permissions | Listed |
No comments yet.