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

  • Provide agents agents.provideMediumAdds agents to the app.Provide the Claude Code agent and pass its tool calls to plugin tools
  • Run named programs processMediumStarts the listed programs.Run the Claude Code CLI (sessions, sign-in, `claude update`), and ask the npm installation that owns it about a newer versionPrograms: claudenpm
  • Read files fs.readMediumReads files in the listed places.Read Claude Code's sessions, settings and skills (in ~/.claude, other accounts' ~/.claude-* folders, the shared skills and the folder you choose in Settings), the project's .claude folder, the administrator's skill policy, and once, what the previous provider keptPlaces: ~/.claude/**~/.claude*/**~/.agents/skills/**the open workspaceits own data folder/Library/Application Support/ClaudeCode/managed-settings.json/etc/claude-code/managed-settings.json${settings.configDir}
  • Environment variables envMediumReads the listed environment variables.Find Claude Code's configuration directory, and the launch settings you set in CLAUDE_* variables (extra arguments, MCP servers, setting sources, appended system prompt, extra folders)Variables: HOMECLAUDE_CONFIG_DIRCLAUDE_EXTRA_ARGSCLAUDE_MCP_CONFIGCLAUDE_STRICT_MCP_CONFIGCLAUDE_SETTING_SOURCESCLAUDE_APPEND_SYSTEM_PROMPTCLAUDE_ADD_DIRS

Files

limits.test.ts7.4 KB
// Ported from the Rust plugin's limits.rs tests.
import assert from "node:assert/strict";
import { objectOf } from "./wire.ts";
import { required, test } from "./testing.ts";
import { fromRateLimitInfo, fromUsageResponse, recoveryFromRateLimitInfo } from "./limits.ts";

test("a stream event reports fractions and epoch seconds", () => {
  const limits = fromRateLimitInfo({
    status: "allowed_warning",
    rateLimitType: "five_hour",
    utilization: 0.825,
    resetsAt: 1789000000,
    unifiedWindows: {
      five_hour: { utilization: 0.825, resetsAt: 1789000000 },
      seven_day: { utilization: 0.1, resetsAt: 1789500000 },
    },
  });
  const windows = required(required(limits).windows);
  assert.equal(windows.length, 2);
  assert.equal(windows[0].id, "five_hour");
  assert.equal(windows[0].label, "5 hours");
  assert.ok(Math.abs(windows[0].usedPercent - 82.5) < 1e-9);
  assert.equal(windows[0].windowMinutes, 300);
  assert.equal(windows[0].resetsAt, new Date(1789000000 * 1000).toISOString());
  assert.equal(windows[1].windowMinutes, 10080);
  assert.equal(windows[0].blocked, false);
  assert.equal(required(limits?.recovery).availability, "allowed");
  assert.equal(objectOf(required(limits)).resetCredits, undefined);
});

test("only the rejected window is blocked and paid overage unblocks it", () => {
  const rejected = {
    status: "rejected",
    rateLimitType: "seven_day",
    utilization: 1.0,
    unifiedWindows: { five_hour: { utilization: 0.2, resetsAt: 1 }, seven_day: { utilization: 1.0, resetsAt: 2 } },
  };
  const limits = fromRateLimitInfo(rejected);
  assert.equal(required(required(limits).windows)[0].blocked, false, "the 5 hour window still has room");
  assert.equal(required(required(limits).windows)[1].blocked, true);
  assert.equal(
    required(required(fromRateLimitInfo({ ...rejected, isUsingOverage: true })).windows)[1].blocked,
    false,
    "extra usage keeps the account working",
  );
});

test("a limiting window outside the unified set still reports", () => {
  const limits = fromRateLimitInfo({
    status: "rejected",
    rateLimitType: "seven_day_opus",
    utilization: 1.2,
    resetsAt: 1789000000,
  });
  const windows = required(required(limits).windows);
  assert.equal(windows[0].id, "seven_day_opus");
  assert.equal(windows[0].label, "7 days (Opus)");
  assert.ok(Math.abs(windows[0].usedPercent - 120) < 1e-9);
  assert.equal(windows[0].blocked, true);
  const available = required(fromRateLimitInfo({ status: "allowed" }));
  assert.deepEqual(available.windows, []);
  assert.equal(required(available.recovery).availability, "allowed", "availability does not require meters");
});

test("the usage response reports percentages and ISO timestamps", () => {
  const limits = fromUsageResponse({
    rate_limits_available: true,
    rate_limits: {
      five_hour: { utilization: 42.0, resets_at: "2026-09-16T10:00:00Z" },
      seven_day: { utilization: 3.5, resets_at: null },
      model_scoped: [{ display_name: "Opus 5", utilization: 12.0, resets_at: null }],
    },
  });
  assert.deepEqual(
    required(limits.windows).map((window) => window.id),
    ["five_hour", "seven_day", "seven_day_opus_5"],
  );
  assert.ok(Math.abs(required(limits.windows)[0].usedPercent - 42) < 1e-9, "a percentage must not be scaled again");
  assert.equal(required(limits.windows)[0].resetsAt, "2026-09-16T10:00:00.000Z");
  assert.equal(required(limits.windows)[2].label, "7 days (Opus 5)");
  assert.equal(required(limits.windows)[2].windowMinutes, 10080);
  assert.equal(required(limits.recovery).availability, "unknown");
  assert.equal(
    required(fromUsageResponse({ rate_limits_available: false, rate_limits: null }).recovery).availability,
    "unsupported",
  );
});

test("an undocumented window is left out unless it is the one blocking", () => {
  const usage = required(
    fromUsageResponse({
      rate_limits: {
        five_hour: { utilization: 9, resets_at: "2026-10-04T20:00:00Z" },
        iguana_necktie: { utilization: 0, resets_at: "2026-11-05T00:00:00Z" },
        overage: { utilization: 0 },
      },
    }),
  );
  assert.deepEqual(
    required(usage.windows).map((window) => window.label),
    ["5 hours", "Extra Usage"],
  );
  const blocking = required(
    fromRateLimitInfo({ status: "rejected", rateLimitType: "iguana_necktie", utilization: 1, resetsAt: 1789000000 }),
  );
  assert.deepEqual(
    required(blocking.windows).map((window) => [window.label, window.blocked]),
    [["Other limit", true]],
  );
});

test("native rejection, grace, overage and credits-required are distinct from meters", () => {
  for (const info of [
    { status: "allowed", utilization: 1.0 },
    { status: "allowed_warning", utilization: 1.1, rateLimitGraceActive: true },
    { status: "rejected", overageStatus: "allowed" },
    { status: "rejected", rateLimitGraceActive: true, overageStatus: "allowed_warning" },
    { status: "rejected", overageInUse: true },
  ])
    assert.equal(recoveryFromRateLimitInfo(info).availability, "allowed", JSON.stringify(info));
  assert.equal(recoveryFromRateLimitInfo({ utilization: 1.0, rateLimitGraceActive: true }).availability, "unknown");
  assert.equal(
    recoveryFromRateLimitInfo({ status: "rejected", rateLimitGraceActive: true }).availability,
    "blocked",
    "grace can persist after hard exhaustion",
  );
  const credits = recoveryFromRateLimitInfo({
    status: "rejected",
    errorCode: "credits_required",
    resetsAt: 1791200000,
    isUsingOverage: true,
  });
  assert.equal(credits.availability, "blocked");
  assert.equal(credits.resetsAt, undefined, "credits-required rejection is not a timed recovery promise");
  assert.equal(
    recoveryFromRateLimitInfo({ status: "rejected" }).identity,
    undefined,
    "the decoder cannot invent an account",
  );
});

test("reset evidence comes from the responsible window, with missing relevant deadlines preserved", () => {
  const info = {
    status: "rejected",
    rateLimitType: "seven_day",
    unifiedWindows: {
      five_hour: { utilization: 1, resetsAt: 1791200000 },
      seven_day: { utilization: 1, resetsAt: 1791300000 },
    },
  };
  assert.equal(recoveryFromRateLimitInfo(info).resetsAt, new Date(1791300000 * 1000).toISOString());
  assert.equal(
    recoveryFromRateLimitInfo({ ...info, unifiedWindows: { five_hour: info.unifiedWindows.five_hour } }).resetsAt,
    undefined,
  );
  assert.equal(recoveryFromRateLimitInfo({ ...info, overageStatus: "rejected" }).resetsAt, undefined);
  assert.equal(
    recoveryFromRateLimitInfo({ ...info, overageStatus: "rejected", overageResetsAt: 1791400000 }).resetsAt,
    new Date(1791400000 * 1000).toISOString(),
  );
});

test("a fresh get_usage observation is unknown or unsupported, never rounded permission", () => {
  for (const raw of [
    null,
    {},
    { rate_limits: { five_hour: { utilization: 0 } } },
    { rate_limits: { five_hour: { utilization: 100 } } },
  ]) {
    const limits = fromUsageResponse(raw, "native-identity");
    const recovery = required(limits.recovery);
    assert.equal(recovery.availability, "unknown");
    assert.equal(recovery.identity, "native-identity");
    assert.equal(recovery.resetsAt, undefined);
    assert.equal(recovery.source, "claude/get_usage");
    assert.ok(Number.isFinite(Date.parse(recovery.observedAt)));
  }
  assert.equal(required(fromUsageResponse({ rate_limits_available: false }).recovery).availability, "unsupported");
  assert.equal(required(fromUsageResponse({}).recovery).identity, undefined);
});

Versions

VersionPublishedPlugin APISizePermissionsStatus
0.2.0latestOct 5, 2026>=2 <3128.7 KB4 permissionsListed

Reviews and comments

0 threads · 0 reviews

No comments yet.