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
files.ts2.6 KB
// Best-effort reads of Claude's records through the scoped broker service.
// Missing and ungranted files retain the original null/empty semantics.
import * as Effect from "effect/Effect";
import * as wire from "./wire.ts";
import { Fs } from "convergence/effect";
const quiet = Effect.fnUntraced(function* <A, E extends { readonly _tag: string; readonly message: string }, R>(
effect: Effect.Effect<A, E, R>,
) {
return yield* effect.pipe(
// Claude's own files are optional: unreadable history is absent history.
Effect.catch((error) =>
Effect.sync(() => {
if (error._tag === "PermissionNotGranted") console.debug(`claude: ${error.message}`);
return null;
}),
),
);
});
export function apiFiles() {
return {
text: Effect.fn("Claude.files.text")(function* (path: string) {
return yield* quiet((yield* Fs).read(path));
}),
bytes: Effect.fn("Claude.files.bytes")(function* (path: string) {
return yield* quiet((yield* Fs).read(path, { encoding: "binary" }));
}),
list: Effect.fn("Claude.files.list")(function* (path: string) {
return yield* quiet((yield* Fs).list(path));
}),
stat: Effect.fn("Claude.files.stat")(function* (path: string) {
return yield* quiet((yield* Fs).stat(path));
}),
};
}
export type Files = ReturnType<typeof apiFiles>;
export const readJson = Effect.fn("Claude.readJson")(function* (files: Files, path: string) {
const text = yield* files.text(path);
if (text === null) return null;
try {
const value: unknown = JSON.parse(text);
return value;
} catch {
return null;
}
});
export const readLines = Effect.fn("Claude.readLines")(function* (files: Files, path: string) {
const text = yield* files.text(path);
return text === null ? [] : parseLines(text);
});
export function parseLines(text: string): wire.Record[] {
const out: wire.Record[] = [];
for (const line of text.split("\n")) {
if (!line.trim()) continue;
try {
out.push(wire.record.parse(JSON.parse(line)));
} catch {
/* A partially written or invalid record waits for a later read. */
}
}
return out;
}
export function join(...parts: (string | null | undefined)[]) {
return parts
.filter((part) => part !== "" && part !== null && part !== undefined)
.map((part, at) => (at === 0 ? String(part).replace(/\/+$/, "") : String(part).replace(/^\/+|\/+$/g, "")))
.join("/");
}
export const mapLimit = Effect.fn("Claude.mapLimit")(function* <A, B, E, R>(
items: A[],
limit: number,
work: (item: A, at: number) => Effect.Effect<B, E, R>,
) {
return yield* Effect.forEach(items, work, { concurrency: limit });
});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.