Official

palette

Built-in command palette (⌘⇧P) and chat search (⌘P).

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/palette@0.2.0

Permissions in 0.2.0

  • Run other plugins' commands commands.runHighRuns commands of other plugins.Run the command you pick, whichever plugin it belongs to
  • Read chats chats.readMediumReads your transcripts and chat lists.Search your chats by title and workspace, and open the one you pick
  • Show panels ui.slotsLowShows views in the listed parts of the window.Hold the palette, which opens over the windowSlots: title

Files

model.test.ts5.4 KB
// Preserve the palette matching, ranking, and navigation assertions.
// These tests import the pure model directly, using the same cases as the JavaScript suite.
import assert from "node:assert/strict";
import test from "node:test";

import { RECENT_LIMIT, commandLabel, fuzzy, modeOf, move, rankChats, rankCommands, remember, window } from "./model.ts";

const command = (
  id: string,
  title: string,
  extra: { category?: string; enabled?: boolean; registered?: boolean } = {},
) => ({ id, title, category: extra.category, enabled: true, registered: true, ...extra });

test("fuzzy matches every character in order, whatever the case", () => {
  assert.ok(fuzzy("nc", "New Chat"));
  assert.ok(fuzzy("NEWCH", "new chat"));
  assert.equal(fuzzy("cn", "New Chat"), null, "order counts");
  assert.equal(fuzzy("xyz", "New Chat"), null);
  assert.deepEqual(fuzzy("", "anything"), { score: 0, positions: [] });
  // A word start that leads nowhere does not hide a match.
  assert.ok(fuzzy("ta", "xtay t"));
  // Letters strewn through the text are no match.
  assert.equal(fuzzy("git", "Divergence: Quit Divergence"), null);
});

test("word starts, runs and prefixes score higher", () => {
  const score = (query: string, text: string) => {
    const match = fuzzy(query, text);
    assert.ok(match);
    return match.score;
  };
  assert.ok(score("nc", "New Chat") > score("nc", "income"), "word starts beat letters inside words");
  assert.ok(score("new", "New Chat") > score("new", "Renew Chat"), "a prefix beats a match inside");
  assert.ok(score("chat", "Chat") > score("chat", "Chat with a very long title"), "the shorter text wins a tie");
  const match = fuzzy("nc", "New Chat");
  assert.ok(match);
  assert.deepEqual(match.positions, [0, 4]);
});

test("commands: hidden when their when is false or their plugin does not run", () => {
  const commands = [
    command("a.one", "Open", { category: "Alpha" }),
    command("b.two", "Open Later", { enabled: false }),
    command("c.three", "Open Other", { registered: false }),
  ];
  assert.deepEqual(
    rankCommands(commands, "open").map((r) => r.command.id),
    ["a.one"],
  );
  assert.deepEqual(
    rankCommands(commands, "").map((r) => r.command.id),
    ["a.one"],
  );
});

test("commands: fuzzy on the title and the category, recently run first", () => {
  const commands = [
    command("git.toggle", "Show Source Control", { category: "Git" }),
    command("sidebar.newChat", "New Chat", { category: "Sidebar" }),
    command("chat.switchNext", "Switch to the Previous Chat", { category: "Chat" }),
    command("kernel.quit", "Quit Divergence", { category: "Divergence" }),
  ];
  assert.deepEqual(
    rankCommands(commands, "git").map((r) => r.command.id),
    ["git.toggle"],
    "the category is searched",
  );
  assert.equal(rankCommands(commands, "new chat")[0].command.id, "sidebar.newChat");
  // With no query: recent first, then by label.
  const listed = rankCommands(commands, "", ["kernel.quit", "chat.switchNext"]).map((r) => r.command.id);
  assert.deepEqual(listed, ["kernel.quit", "chat.switchNext", "git.toggle", "sidebar.newChat"]);
  // A recent command wins a close match.
  const ranked = rankCommands([command("a.x", "Toggle A"), command("b.x", "Toggle B")], "toggle", ["b.x"]);
  assert.equal(ranked[0].command.id, "b.x");
  assert.equal(commandLabel(commands[0]), "Git: Show Source Control");
  assert.equal(commandLabel({ title: "Plain" }), "Plain");
});

test("chats: by title and workspace, newest first, archived ones never", () => {
  const workspaces = { w1: { name: "nexus" }, w2: { name: "landing" } };
  const chats = [
    { id: "a", title: "Fix the palette", workspaceId: "w1", updatedAt: "2026-09-20" },
    { id: "b", title: "Hero section", workspaceId: "w2", updatedAt: "2026-09-25" },
    { id: "c", title: "Old palette notes", workspaceId: "w1", updatedAt: "2026-09-01", archived: true },
  ];
  assert.deepEqual(
    rankChats(chats, workspaces, "").map((r) => r.chat.id),
    ["b", "a"],
  );
  assert.deepEqual(
    rankChats(chats, workspaces, "palette").map((r) => r.chat.id),
    ["a"],
  );
  assert.deepEqual(
    rankChats(chats, workspaces, "landing").map((r) => r.chat.id),
    ["b"],
    "the workspace name is searched",
  );
  assert.deepEqual(rankChats(chats, workspaces, "zzz"), []);
});

test("the chat search switches mode by prefix", () => {
  const providers = [
    { plugin: "files", id: "files", prefix: "@" },
    { plugin: "x", id: "long", prefix: "@@" },
  ];
  assert.deepEqual(modeOf("> new", providers), { mode: "commands", query: "new" });
  const mode = modeOf("@@deep", providers);
  assert.equal(mode.mode, "provider");
  assert.ok(mode.mode === "provider");
  assert.equal(mode.provider.id, "long", "the longest prefix wins");
  assert.deepEqual(modeOf("@main.rs", providers), { mode: "provider", provider: providers[0], query: "main.rs" });
  assert.deepEqual(modeOf("hello", providers), { mode: "chats", query: "hello" });
});

test("the selection wraps and stays in sight; recent commands are bounded", () => {
  assert.equal(move(0, 3, -1), 2);
  assert.equal(move(2, 3, 1), 0);
  assert.equal(move(0, 0, 1), 0);
  assert.deepEqual(window(5, 3, 12), { from: 0, to: 5 });
  assert.deepEqual(window(40, 30, 12), { from: 24, to: 36 });
  assert.deepEqual(window(40, 39, 12), { from: 28, to: 40 });
  let recent: string[] = [];
  for (let i = 0; i < RECENT_LIMIT + 5; i++) recent = remember(recent, `c${i}`);
  assert.equal(recent.length, RECENT_LIMIT);
  assert.equal(remember(recent, recent[3])[0], recent[3]);
});

Versions

VersionPublishedPlugin APISizePermissionsStatus
0.2.0latestOct 5, 2026>=2 <311.2 KB3 permissionsListed

Reviews and comments

0 threads · 0 reviews

No comments yet.