@hasna/accounts 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -9
- package/dist/cli.js +493 -13
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +411 -8
- package/dist/lib/supervisor.d.ts +69 -0
- package/dist/lib/supervisor.d.ts.map +1 -0
- package/dist/lib/tools.d.ts.map +1 -1
- package/dist/mcp.js +168 -5
- package/package.json +5 -1
package/dist/cli.js
CHANGED
|
@@ -2082,9 +2082,9 @@ var require_commander = __commonJS((exports) => {
|
|
|
2082
2082
|
|
|
2083
2083
|
// src/cli.ts
|
|
2084
2084
|
import { spawnSync } from "node:child_process";
|
|
2085
|
-
import { existsSync as
|
|
2085
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6 } from "node:fs";
|
|
2086
2086
|
import { homedir as homedir5 } from "node:os";
|
|
2087
|
-
import { dirname as dirname5, join as
|
|
2087
|
+
import { dirname as dirname5, join as join11 } from "node:path";
|
|
2088
2088
|
import { fileURLToPath } from "node:url";
|
|
2089
2089
|
|
|
2090
2090
|
// node_modules/commander/esm.mjs
|
|
@@ -6760,6 +6760,25 @@ var BUILTIN_TOOLS = [
|
|
|
6760
6760
|
loginHint: "complete the Codex login flow for this CODEX_HOME",
|
|
6761
6761
|
resumeArgs: ["resume", "--last"]
|
|
6762
6762
|
},
|
|
6763
|
+
{
|
|
6764
|
+
id: "takumi",
|
|
6765
|
+
label: "Takumi",
|
|
6766
|
+
envVar: "TAKUMI_CONFIG_DIR",
|
|
6767
|
+
defaultDir: join2(homedir2(), ".takumi"),
|
|
6768
|
+
bin: "takumi",
|
|
6769
|
+
loginHint: "complete Takumi auth in this TAKUMI_CONFIG_DIR",
|
|
6770
|
+
resumeArgs: ["--continue"],
|
|
6771
|
+
accountFile: ".claude.json",
|
|
6772
|
+
emailPath: ["oauthAccount", "emailAddress"]
|
|
6773
|
+
},
|
|
6774
|
+
{
|
|
6775
|
+
id: "gemini",
|
|
6776
|
+
label: "Gemini CLI",
|
|
6777
|
+
envVar: "GEMINI_CONFIG_DIR",
|
|
6778
|
+
defaultDir: join2(homedir2(), ".gemini"),
|
|
6779
|
+
bin: "gemini",
|
|
6780
|
+
loginHint: "complete Gemini auth in this GEMINI_CONFIG_DIR"
|
|
6781
|
+
},
|
|
6763
6782
|
{
|
|
6764
6783
|
id: "opencode",
|
|
6765
6784
|
label: "opencode",
|
|
@@ -6783,6 +6802,22 @@ var BUILTIN_TOOLS = [
|
|
|
6783
6802
|
loginArgs: ["login"],
|
|
6784
6803
|
loginHint: "complete cursor-agent login for this CURSOR_CONFIG_DIR"
|
|
6785
6804
|
},
|
|
6805
|
+
{
|
|
6806
|
+
id: "pi",
|
|
6807
|
+
label: "Pi Coding Agent",
|
|
6808
|
+
envVar: "PI_CODING_AGENT_HOME",
|
|
6809
|
+
defaultDir: join2(homedir2(), ".pi"),
|
|
6810
|
+
bin: "pi",
|
|
6811
|
+
loginHint: "complete Pi coding agent auth in this PI_CODING_AGENT_HOME"
|
|
6812
|
+
},
|
|
6813
|
+
{
|
|
6814
|
+
id: "hermes",
|
|
6815
|
+
label: "Hermes",
|
|
6816
|
+
envVar: "HERMES_HOME",
|
|
6817
|
+
defaultDir: join2(homedir2(), ".hermes"),
|
|
6818
|
+
bin: "hermes",
|
|
6819
|
+
loginHint: "complete Hermes auth in this HERMES_HOME"
|
|
6820
|
+
},
|
|
6786
6821
|
{
|
|
6787
6822
|
id: "kimi",
|
|
6788
6823
|
label: "Kimi Code",
|
|
@@ -7623,6 +7658,367 @@ function switchProfile(name, opts = {}) {
|
|
|
7623
7658
|
};
|
|
7624
7659
|
}
|
|
7625
7660
|
|
|
7661
|
+
// src/lib/supervisor.ts
|
|
7662
|
+
import { spawn } from "node:child_process";
|
|
7663
|
+
import { createHash } from "node:crypto";
|
|
7664
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync5, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
7665
|
+
import { createConnection, createServer } from "node:net";
|
|
7666
|
+
import { basename, join as join10 } from "node:path";
|
|
7667
|
+
var STATE_SUFFIX = ".json";
|
|
7668
|
+
function supervisorDir() {
|
|
7669
|
+
return join10(accountsHome(), "supervisors");
|
|
7670
|
+
}
|
|
7671
|
+
function supervisorStatePath(toolId) {
|
|
7672
|
+
return join10(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
|
|
7673
|
+
}
|
|
7674
|
+
function supervisorSocketPath(toolId) {
|
|
7675
|
+
if (process.platform === "win32") {
|
|
7676
|
+
const hash = createHash("sha1").update(accountsHome()).digest("hex").slice(0, 12);
|
|
7677
|
+
return `\\\\.\\pipe\\hasna-accounts-${hash}-${toolId}`;
|
|
7678
|
+
}
|
|
7679
|
+
return join10(supervisorDir(), `${toolId}.sock`);
|
|
7680
|
+
}
|
|
7681
|
+
function nowIso2() {
|
|
7682
|
+
return new Date().toISOString();
|
|
7683
|
+
}
|
|
7684
|
+
function parseState(raw) {
|
|
7685
|
+
const data = JSON.parse(raw);
|
|
7686
|
+
if (data.version !== 1 || typeof data.tool !== "string" || typeof data.profile !== "string" || typeof data.pid !== "number" || typeof data.socketPath !== "string" || !Array.isArray(data.command)) {
|
|
7687
|
+
return;
|
|
7688
|
+
}
|
|
7689
|
+
return data;
|
|
7690
|
+
}
|
|
7691
|
+
function readSupervisorState(toolId) {
|
|
7692
|
+
const path = supervisorStatePath(toolId);
|
|
7693
|
+
if (!existsSync9(path))
|
|
7694
|
+
return;
|
|
7695
|
+
try {
|
|
7696
|
+
return parseState(readFileSync5(path, "utf8"));
|
|
7697
|
+
} catch {
|
|
7698
|
+
return;
|
|
7699
|
+
}
|
|
7700
|
+
}
|
|
7701
|
+
function listSupervisorStates() {
|
|
7702
|
+
const dir = supervisorDir();
|
|
7703
|
+
if (!existsSync9(dir))
|
|
7704
|
+
return [];
|
|
7705
|
+
return readdirSync(dir).filter((name) => name.endsWith(STATE_SUFFIX)).map((name) => basename(name, STATE_SUFFIX)).map((toolId) => readSupervisorState(toolId)).filter((state) => state !== undefined);
|
|
7706
|
+
}
|
|
7707
|
+
function writeSupervisorState(state) {
|
|
7708
|
+
mkdirSync7(supervisorDir(), { recursive: true });
|
|
7709
|
+
writeFileSync5(supervisorStatePath(state.tool), JSON.stringify(state, null, 2) + `
|
|
7710
|
+
`, { mode: 384 });
|
|
7711
|
+
}
|
|
7712
|
+
function removeSupervisorFiles(toolId) {
|
|
7713
|
+
rmSync2(supervisorStatePath(toolId), { force: true });
|
|
7714
|
+
if (process.platform !== "win32")
|
|
7715
|
+
rmSync2(supervisorSocketPath(toolId), { force: true });
|
|
7716
|
+
}
|
|
7717
|
+
function processAlive(pid) {
|
|
7718
|
+
try {
|
|
7719
|
+
process.kill(pid, 0);
|
|
7720
|
+
return true;
|
|
7721
|
+
} catch {
|
|
7722
|
+
return false;
|
|
7723
|
+
}
|
|
7724
|
+
}
|
|
7725
|
+
function knownTool(id) {
|
|
7726
|
+
try {
|
|
7727
|
+
return getTool(id);
|
|
7728
|
+
} catch {
|
|
7729
|
+
return;
|
|
7730
|
+
}
|
|
7731
|
+
}
|
|
7732
|
+
function resolveSupervisorLaunch(target, opts = {}) {
|
|
7733
|
+
const targetTool = knownTool(target);
|
|
7734
|
+
if (opts.profile) {
|
|
7735
|
+
const profile2 = getProfile(opts.profile, opts.tool ?? targetTool?.id);
|
|
7736
|
+
if (targetTool && profile2.tool !== targetTool.id) {
|
|
7737
|
+
throw new AccountsError(`profile "${profile2.name}" belongs to ${profile2.tool}, not ${targetTool.id}`);
|
|
7738
|
+
}
|
|
7739
|
+
return { profile: profile2, tool: getTool(profile2.tool), targetKind: targetTool ? "tool" : "profile" };
|
|
7740
|
+
}
|
|
7741
|
+
if (targetTool && !opts.tool) {
|
|
7742
|
+
const profile2 = currentProfile(targetTool.id) ?? appliedProfile(targetTool.id);
|
|
7743
|
+
if (!profile2) {
|
|
7744
|
+
throw new AccountsError(`no active ${targetTool.label} profile. Run \`accounts use <name> --tool ${targetTool.id}\` or pass --profile.`);
|
|
7745
|
+
}
|
|
7746
|
+
return { profile: profile2, tool: targetTool, targetKind: "tool" };
|
|
7747
|
+
}
|
|
7748
|
+
const profile = getProfile(target, opts.tool);
|
|
7749
|
+
return { profile, tool: getTool(profile.tool), targetKind: "profile" };
|
|
7750
|
+
}
|
|
7751
|
+
function exitCode(code, signal) {
|
|
7752
|
+
if (code !== null)
|
|
7753
|
+
return code;
|
|
7754
|
+
if (signal === "SIGINT")
|
|
7755
|
+
return 130;
|
|
7756
|
+
if (signal === "SIGTERM")
|
|
7757
|
+
return 143;
|
|
7758
|
+
return signal ? 1 : 0;
|
|
7759
|
+
}
|
|
7760
|
+
function killChildProcess(child, signal) {
|
|
7761
|
+
if (!child.pid)
|
|
7762
|
+
return;
|
|
7763
|
+
if (process.platform !== "win32") {
|
|
7764
|
+
try {
|
|
7765
|
+
process.kill(-child.pid, signal);
|
|
7766
|
+
return;
|
|
7767
|
+
} catch {}
|
|
7768
|
+
}
|
|
7769
|
+
child.kill(signal);
|
|
7770
|
+
}
|
|
7771
|
+
function wait(ms) {
|
|
7772
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
7773
|
+
}
|
|
7774
|
+
async function listen(server, socketPath) {
|
|
7775
|
+
await new Promise((resolve3, reject) => {
|
|
7776
|
+
const onError = (err) => {
|
|
7777
|
+
server.off("listening", onListening);
|
|
7778
|
+
reject(err);
|
|
7779
|
+
};
|
|
7780
|
+
const onListening = () => {
|
|
7781
|
+
server.off("error", onError);
|
|
7782
|
+
resolve3();
|
|
7783
|
+
};
|
|
7784
|
+
server.once("error", onError);
|
|
7785
|
+
server.once("listening", onListening);
|
|
7786
|
+
server.listen(socketPath);
|
|
7787
|
+
});
|
|
7788
|
+
}
|
|
7789
|
+
async function sendSupervisorRequest(toolId, request, opts = {}) {
|
|
7790
|
+
const timeoutMs = opts.timeoutMs ?? 1500;
|
|
7791
|
+
const socketPath = supervisorSocketPath(toolId);
|
|
7792
|
+
return await new Promise((resolve3, reject) => {
|
|
7793
|
+
const socket = createConnection(socketPath);
|
|
7794
|
+
let buffer = "";
|
|
7795
|
+
let settled = false;
|
|
7796
|
+
const finish = (value) => {
|
|
7797
|
+
if (settled)
|
|
7798
|
+
return;
|
|
7799
|
+
settled = true;
|
|
7800
|
+
clearTimeout(timer);
|
|
7801
|
+
socket.destroy();
|
|
7802
|
+
resolve3(value);
|
|
7803
|
+
};
|
|
7804
|
+
const fail = (err) => {
|
|
7805
|
+
if (settled)
|
|
7806
|
+
return;
|
|
7807
|
+
settled = true;
|
|
7808
|
+
clearTimeout(timer);
|
|
7809
|
+
socket.destroy();
|
|
7810
|
+
if (opts.allowMissing && (err.code === "ENOENT" || err.code === "ECONNREFUSED")) {
|
|
7811
|
+
resolve3(undefined);
|
|
7812
|
+
} else {
|
|
7813
|
+
reject(new AccountsError(`could not contact accounts supervisor for ${toolId}: ${err.message}`));
|
|
7814
|
+
}
|
|
7815
|
+
};
|
|
7816
|
+
const timer = setTimeout(() => {
|
|
7817
|
+
fail(Object.assign(new Error(`timed out after ${timeoutMs}ms`), { code: "ETIMEDOUT" }));
|
|
7818
|
+
}, timeoutMs);
|
|
7819
|
+
socket.setEncoding("utf8");
|
|
7820
|
+
socket.once("connect", () => {
|
|
7821
|
+
socket.write(JSON.stringify(request) + `
|
|
7822
|
+
`);
|
|
7823
|
+
});
|
|
7824
|
+
socket.once("error", fail);
|
|
7825
|
+
socket.on("data", (chunk) => {
|
|
7826
|
+
buffer += chunk;
|
|
7827
|
+
const newline = buffer.indexOf(`
|
|
7828
|
+
`);
|
|
7829
|
+
if (newline === -1)
|
|
7830
|
+
return;
|
|
7831
|
+
try {
|
|
7832
|
+
finish(JSON.parse(buffer.slice(0, newline)));
|
|
7833
|
+
} catch (err) {
|
|
7834
|
+
fail(err);
|
|
7835
|
+
}
|
|
7836
|
+
});
|
|
7837
|
+
socket.once("end", () => {
|
|
7838
|
+
if (!settled)
|
|
7839
|
+
fail(new Error("connection closed without a response"));
|
|
7840
|
+
});
|
|
7841
|
+
});
|
|
7842
|
+
}
|
|
7843
|
+
async function runSupervisedTool(initialProfile, tool, initialArgs = [], opts = {}) {
|
|
7844
|
+
const socketPath = supervisorSocketPath(tool.id);
|
|
7845
|
+
const existing = readSupervisorState(tool.id);
|
|
7846
|
+
if (existing && processAlive(existing.pid)) {
|
|
7847
|
+
throw new AccountsError(`an accounts supervisor for ${tool.label} is already running (pid ${existing.pid})`);
|
|
7848
|
+
}
|
|
7849
|
+
removeSupervisorFiles(tool.id);
|
|
7850
|
+
mkdirSync7(supervisorDir(), { recursive: true });
|
|
7851
|
+
const startedAt = nowIso2();
|
|
7852
|
+
const restartDelayMs = opts.restartDelayMs ?? 350;
|
|
7853
|
+
const log = opts.log ?? (() => {
|
|
7854
|
+
return;
|
|
7855
|
+
});
|
|
7856
|
+
const server = createServer();
|
|
7857
|
+
let profile = initialProfile;
|
|
7858
|
+
let childArgs = initialArgs;
|
|
7859
|
+
let child;
|
|
7860
|
+
let stopping = false;
|
|
7861
|
+
let restarting = false;
|
|
7862
|
+
let settled = false;
|
|
7863
|
+
const state = () => ({
|
|
7864
|
+
version: 1,
|
|
7865
|
+
tool: tool.id,
|
|
7866
|
+
profile: profile.name,
|
|
7867
|
+
pid: process.pid,
|
|
7868
|
+
...child?.pid ? { childPid: child.pid } : {},
|
|
7869
|
+
socketPath,
|
|
7870
|
+
command: [tool.bin, ...childArgs],
|
|
7871
|
+
startedAt,
|
|
7872
|
+
updatedAt: nowIso2()
|
|
7873
|
+
});
|
|
7874
|
+
const persist = () => writeSupervisorState(state());
|
|
7875
|
+
const stopChild = async () => {
|
|
7876
|
+
const target = child;
|
|
7877
|
+
if (!target || target.exitCode !== null)
|
|
7878
|
+
return;
|
|
7879
|
+
await new Promise((resolve3) => {
|
|
7880
|
+
let done2 = false;
|
|
7881
|
+
const finish = () => {
|
|
7882
|
+
if (done2)
|
|
7883
|
+
return;
|
|
7884
|
+
done2 = true;
|
|
7885
|
+
clearTimeout(killTimer);
|
|
7886
|
+
resolve3();
|
|
7887
|
+
};
|
|
7888
|
+
const killTimer = setTimeout(() => {
|
|
7889
|
+
try {
|
|
7890
|
+
killChildProcess(target, "SIGKILL");
|
|
7891
|
+
} catch {
|
|
7892
|
+
finish();
|
|
7893
|
+
}
|
|
7894
|
+
}, 2500);
|
|
7895
|
+
target.once("exit", finish);
|
|
7896
|
+
try {
|
|
7897
|
+
killChildProcess(target, "SIGTERM");
|
|
7898
|
+
} catch {
|
|
7899
|
+
finish();
|
|
7900
|
+
}
|
|
7901
|
+
});
|
|
7902
|
+
};
|
|
7903
|
+
const cleanup = () => {
|
|
7904
|
+
server.close();
|
|
7905
|
+
removeSupervisorFiles(tool.id);
|
|
7906
|
+
process.off("SIGINT", onSigint);
|
|
7907
|
+
process.off("SIGTERM", onSigterm);
|
|
7908
|
+
};
|
|
7909
|
+
let resolveRun;
|
|
7910
|
+
const done = new Promise((resolve3) => {
|
|
7911
|
+
resolveRun = resolve3;
|
|
7912
|
+
});
|
|
7913
|
+
const finishRun = (code) => {
|
|
7914
|
+
if (settled)
|
|
7915
|
+
return;
|
|
7916
|
+
settled = true;
|
|
7917
|
+
cleanup();
|
|
7918
|
+
resolveRun(code);
|
|
7919
|
+
};
|
|
7920
|
+
const startChild = (nextProfile, nextArgs) => {
|
|
7921
|
+
profile = nextProfile;
|
|
7922
|
+
childArgs = nextArgs;
|
|
7923
|
+
useProfile(profile.name, tool.id);
|
|
7924
|
+
const env2 = profileEnv(profile, tool);
|
|
7925
|
+
log(`accounts supervisor: starting ${tool.bin} for ${profile.name}`);
|
|
7926
|
+
const proc = spawn(tool.bin, childArgs, {
|
|
7927
|
+
stdio: opts.stdio ?? "inherit",
|
|
7928
|
+
env: { ...process.env, ...env2, ACCOUNTS_SUPERVISOR: "1", ACCOUNTS_ACTIVE: profile.name },
|
|
7929
|
+
detached: process.platform !== "win32"
|
|
7930
|
+
});
|
|
7931
|
+
child = proc;
|
|
7932
|
+
persist();
|
|
7933
|
+
proc.once("error", (err) => {
|
|
7934
|
+
log(`accounts supervisor: failed to start ${tool.bin}: ${err.message}`);
|
|
7935
|
+
if (!restarting && !stopping)
|
|
7936
|
+
finishRun(1);
|
|
7937
|
+
});
|
|
7938
|
+
proc.once("exit", (code, signal) => {
|
|
7939
|
+
if (child === proc)
|
|
7940
|
+
child = undefined;
|
|
7941
|
+
persist();
|
|
7942
|
+
if (restarting || stopping)
|
|
7943
|
+
return;
|
|
7944
|
+
finishRun(exitCode(code, signal));
|
|
7945
|
+
});
|
|
7946
|
+
};
|
|
7947
|
+
const restartWith = async (result) => {
|
|
7948
|
+
restarting = true;
|
|
7949
|
+
try {
|
|
7950
|
+
await wait(restartDelayMs);
|
|
7951
|
+
await stopChild();
|
|
7952
|
+
startChild(getProfile(result.profile.name, tool.id), result.command.slice(1));
|
|
7953
|
+
} finally {
|
|
7954
|
+
restarting = false;
|
|
7955
|
+
}
|
|
7956
|
+
};
|
|
7957
|
+
const shutdown = async (code) => {
|
|
7958
|
+
if (stopping)
|
|
7959
|
+
return;
|
|
7960
|
+
stopping = true;
|
|
7961
|
+
await stopChild();
|
|
7962
|
+
finishRun(code);
|
|
7963
|
+
};
|
|
7964
|
+
const handleRequest = async (request) => {
|
|
7965
|
+
if (request.type === "status")
|
|
7966
|
+
return { ok: true, state: state() };
|
|
7967
|
+
if (request.type === "stop") {
|
|
7968
|
+
setTimeout(() => void shutdown(0), 25);
|
|
7969
|
+
return { ok: true, stopping: true, state: state() };
|
|
7970
|
+
}
|
|
7971
|
+
if (request.type !== "switch_profile")
|
|
7972
|
+
return { ok: false, error: "unknown supervisor request" };
|
|
7973
|
+
if (request.tool && request.tool !== tool.id) {
|
|
7974
|
+
return { ok: false, error: `this supervisor runs ${tool.id}, not ${request.tool}` };
|
|
7975
|
+
}
|
|
7976
|
+
try {
|
|
7977
|
+
const result = switchProfile(request.name, {
|
|
7978
|
+
tool: tool.id,
|
|
7979
|
+
mode: request.mode ?? "auto",
|
|
7980
|
+
resume: request.resume ?? true,
|
|
7981
|
+
args: request.args ?? []
|
|
7982
|
+
});
|
|
7983
|
+
log(`accounts supervisor: switching ${tool.id} to ${result.profile.name}`);
|
|
7984
|
+
setTimeout(() => void restartWith(result), 0);
|
|
7985
|
+
return { ok: true, queued: true, result, state: state(), restartDelayMs };
|
|
7986
|
+
} catch (err) {
|
|
7987
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
7988
|
+
}
|
|
7989
|
+
};
|
|
7990
|
+
server.on("connection", (socket) => {
|
|
7991
|
+
socket.setEncoding("utf8");
|
|
7992
|
+
let buffer = "";
|
|
7993
|
+
socket.on("data", (chunk) => {
|
|
7994
|
+
buffer += chunk;
|
|
7995
|
+
const newline = buffer.indexOf(`
|
|
7996
|
+
`);
|
|
7997
|
+
if (newline === -1)
|
|
7998
|
+
return;
|
|
7999
|
+
const line = buffer.slice(0, newline);
|
|
8000
|
+
buffer = buffer.slice(newline + 1);
|
|
8001
|
+
(async () => {
|
|
8002
|
+
let response;
|
|
8003
|
+
try {
|
|
8004
|
+
response = await handleRequest(JSON.parse(line));
|
|
8005
|
+
} catch (err) {
|
|
8006
|
+
response = { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
8007
|
+
}
|
|
8008
|
+
socket.end(JSON.stringify(response) + `
|
|
8009
|
+
`);
|
|
8010
|
+
})();
|
|
8011
|
+
});
|
|
8012
|
+
});
|
|
8013
|
+
const onSigint = () => void shutdown(130);
|
|
8014
|
+
const onSigterm = () => void shutdown(143);
|
|
8015
|
+
process.once("SIGINT", onSigint);
|
|
8016
|
+
process.once("SIGTERM", onSigterm);
|
|
8017
|
+
await listen(server, socketPath);
|
|
8018
|
+
startChild(profile, childArgs);
|
|
8019
|
+
return await done;
|
|
8020
|
+
}
|
|
8021
|
+
|
|
7626
8022
|
// src/cli.ts
|
|
7627
8023
|
var program2 = new Command;
|
|
7628
8024
|
function die(message) {
|
|
@@ -7632,7 +8028,11 @@ function die(message) {
|
|
|
7632
8028
|
function action(fn) {
|
|
7633
8029
|
return (...args) => {
|
|
7634
8030
|
try {
|
|
7635
|
-
fn(...args)
|
|
8031
|
+
Promise.resolve(fn(...args)).catch((err) => {
|
|
8032
|
+
if (err instanceof AccountsError)
|
|
8033
|
+
die(err.message);
|
|
8034
|
+
throw err;
|
|
8035
|
+
});
|
|
7636
8036
|
} catch (err) {
|
|
7637
8037
|
if (err instanceof AccountsError)
|
|
7638
8038
|
die(err.message);
|
|
@@ -7685,7 +8085,7 @@ program2.command("show").argument("<name>", "profile name").description("show fu
|
|
|
7685
8085
|
console.log(` tool: ${p.tool} (${getTool(p.tool).label})`);
|
|
7686
8086
|
console.log(` active: ${active ? source_default.green("yes") : source_default.dim("no")}`);
|
|
7687
8087
|
console.log(` applied: ${isApplied ? source_default.magenta("yes") : source_default.dim("no")}`);
|
|
7688
|
-
console.log(` config dir: ${p.dir}${
|
|
8088
|
+
console.log(` config dir: ${p.dir}${existsSync10(p.dir) ? "" : source_default.red(" [missing]")}`);
|
|
7689
8089
|
console.log(` email: ${p.email ?? source_default.dim("(none)")}`);
|
|
7690
8090
|
console.log(` created: ${p.createdAt}`);
|
|
7691
8091
|
if (p.lastUsedAt)
|
|
@@ -7778,7 +8178,27 @@ program2.command("applied").argument("[tool]", "tool id (default: claude)").desc
|
|
|
7778
8178
|
die(`no applied profile for "${tool}". Run \`accounts apply <name>\` first.`);
|
|
7779
8179
|
console.log(p.name);
|
|
7780
8180
|
}));
|
|
7781
|
-
program2.command("switch").argument("<name>", "profile name").argument("[args...]", "extra args passed when printing/launching the tool").description("switch to a profile and print a restart/resume command; use --launch to run it").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--mode <mode>", "switch mode: auto, apply, env, active", "auto").option("--resume", "include the tool's resume/continue args in the handoff command").option("--launch", "launch the tool after switching").option("--json", "output JSON").action(action((name, args, opts) => {
|
|
8181
|
+
program2.command("switch").argument("<name>", "profile name").argument("[args...]", "extra args passed when printing/launching the tool").description("switch to a profile and print a restart/resume command; use --launch to run it").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--mode <mode>", "switch mode: auto, apply, env, active", "auto").option("--resume", "include the tool's resume/continue args in the handoff command").option("--launch", "launch the tool after switching").option("--supervisor", "ask a running accounts supervisor to restart the tool").option("--json", "output JSON").action(action(async (name, args, opts) => {
|
|
8182
|
+
if (opts.supervisor && opts.launch)
|
|
8183
|
+
die("--supervisor and --launch cannot be used together");
|
|
8184
|
+
if (opts.supervisor) {
|
|
8185
|
+
const profile = getProfile(name, opts.tool);
|
|
8186
|
+
const response = await sendSupervisorRequest(profile.tool, { type: "switch_profile", name: profile.name, tool: profile.tool, mode: opts.mode, resume: opts.resume ?? true, args }, { allowMissing: true });
|
|
8187
|
+
if (!response) {
|
|
8188
|
+
die(`no running accounts supervisor for ${getTool(profile.tool).label}. Start one with \`accounts run ${profile.tool}\`.`);
|
|
8189
|
+
}
|
|
8190
|
+
if (!response.ok)
|
|
8191
|
+
die(response.error);
|
|
8192
|
+
if (opts.json) {
|
|
8193
|
+
console.log(JSON.stringify(response, null, 2));
|
|
8194
|
+
} else if ("queued" in response) {
|
|
8195
|
+
console.log(source_default.green(`✓ queued supervisor switch to ${source_default.bold(response.result.profile.name)}`));
|
|
8196
|
+
console.log(source_default.dim(` ${response.state.command.join(" ")} will restart in ${response.restartDelayMs}ms`));
|
|
8197
|
+
} else {
|
|
8198
|
+
console.log(source_default.green("✓ supervisor responded"));
|
|
8199
|
+
}
|
|
8200
|
+
return;
|
|
8201
|
+
}
|
|
7782
8202
|
const result = switchProfile(name, { tool: opts.tool, mode: opts.mode, resume: opts.resume, args });
|
|
7783
8203
|
if (opts.json) {
|
|
7784
8204
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -7803,7 +8223,7 @@ program2.command("switch").argument("<name>", "profile name").argument("[args...
|
|
|
7803
8223
|
}
|
|
7804
8224
|
}));
|
|
7805
8225
|
var hook = program2.command("hook").description("install a shell wrapper for claude");
|
|
7806
|
-
hook.command("install").description(`write ${
|
|
8226
|
+
hook.command("install").description(`write ${join11(accountsHome(), "claude-hook.sh")}`).action(action(() => {
|
|
7807
8227
|
const { path, created } = installHook();
|
|
7808
8228
|
console.log(source_default.green(created ? `✓ installed hook at ${path}` : `✓ updated hook at ${path}`));
|
|
7809
8229
|
console.log(source_default.dim(` add to ~/.zshrc: ${shellSnippet()}`));
|
|
@@ -7825,7 +8245,7 @@ program2.command("env").argument("[name]", "profile name (defaults to the active
|
|
|
7825
8245
|
const tool = getTool(profile.tool);
|
|
7826
8246
|
console.log(formatExportLines(profileEnv(profile, tool)));
|
|
7827
8247
|
}));
|
|
7828
|
-
program2.command("launch").
|
|
8248
|
+
program2.command("launch").argument("<name>", "profile name").argument("[args...]", "extra args passed to the tool binary").description("launch the tool's binary with the profile's config dir active").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").action(action((name, args, opts) => {
|
|
7829
8249
|
const profile = getProfile(name, opts.tool);
|
|
7830
8250
|
const tool = getTool(profile.tool);
|
|
7831
8251
|
const env2 = profileEnv(profile, tool);
|
|
@@ -7839,6 +8259,65 @@ program2.command("launch").alias("run").argument("<name>", "profile name").argum
|
|
|
7839
8259
|
die(`failed to launch ${tool.bin}: ${res.error.message}`);
|
|
7840
8260
|
process.exit(res.status ?? 0);
|
|
7841
8261
|
}));
|
|
8262
|
+
program2.command("run").argument("<target>", "tool id to supervise (claude, codex, opencode...) or a profile name").argument("[args...]", "extra args passed to the tool binary").description("run a tool under the accounts supervisor so MCP can switch/restart it").option("-p, --profile <name>", "profile to run when target is a tool id").option("-t, --tool <tool>", "tool when target is a profile name").option("--resume", "start with the tool's resume/continue args").action(action(async (target, args, opts) => {
|
|
8263
|
+
const plan = resolveSupervisorLaunch(target, { profile: opts.profile, tool: opts.tool });
|
|
8264
|
+
const runArgs = [...opts.resume ? plan.tool.resumeArgs ?? [] : [], ...args];
|
|
8265
|
+
console.error(source_default.green(`✓ accounts supervisor running ${plan.tool.label} as ${source_default.bold(plan.profile.name)}`));
|
|
8266
|
+
console.error(source_default.dim(` control: accounts supervisor status ${plan.tool.id}`));
|
|
8267
|
+
console.error(source_default.dim(` switch: accounts switch <profile> --tool ${plan.tool.id} --supervisor`));
|
|
8268
|
+
const code = await runSupervisedTool(plan.profile, plan.tool, runArgs, {
|
|
8269
|
+
log: (message) => console.error(source_default.dim(message))
|
|
8270
|
+
});
|
|
8271
|
+
process.exit(code);
|
|
8272
|
+
}));
|
|
8273
|
+
var supervisor = program2.command("supervisor").description("inspect and control accounts-run supervisors");
|
|
8274
|
+
supervisor.command("status").argument("[tool]", "tool id").description("show running supervisor state").option("--json", "output JSON").action(action(async (toolId, opts) => {
|
|
8275
|
+
const state = toolId ? readSupervisorState(toolId) : undefined;
|
|
8276
|
+
const states = toolId ? state ? [state] : [] : listSupervisorStates();
|
|
8277
|
+
const live = [];
|
|
8278
|
+
for (const state2 of states) {
|
|
8279
|
+
const response = await sendSupervisorRequest(state2.tool, { type: "status" }, { allowMissing: true });
|
|
8280
|
+
live.push(response?.ok && "state" in response ? response.state : { ...state2, stale: true });
|
|
8281
|
+
}
|
|
8282
|
+
if (opts.json) {
|
|
8283
|
+
console.log(JSON.stringify(live, null, 2));
|
|
8284
|
+
return;
|
|
8285
|
+
}
|
|
8286
|
+
if (live.length === 0) {
|
|
8287
|
+
console.log(source_default.dim("no accounts supervisors running"));
|
|
8288
|
+
return;
|
|
8289
|
+
}
|
|
8290
|
+
for (const state2 of live) {
|
|
8291
|
+
const stale = "stale" in state2 ? source_default.yellow(" stale") : "";
|
|
8292
|
+
const child = state2.childPid ? ` child:${state2.childPid}` : "";
|
|
8293
|
+
console.log(`${source_default.cyan(state2.tool.padEnd(10))} ${source_default.bold(state2.profile)} pid:${state2.pid}${child}${stale}`);
|
|
8294
|
+
console.log(source_default.dim(` ${state2.command.join(" ")}`));
|
|
8295
|
+
}
|
|
8296
|
+
}));
|
|
8297
|
+
supervisor.command("switch").argument("<name>", "profile name").argument("[args...]", "extra args passed after resume/continue args").description("switch a running supervisor to another profile").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--mode <mode>", "switch mode: auto, apply, env, active", "auto").option("--no-resume", "restart without the tool's resume/continue args").option("--json", "output JSON").action(action(async (name, args, opts) => {
|
|
8298
|
+
const profile = getProfile(name, opts.tool);
|
|
8299
|
+
const response = await sendSupervisorRequest(profile.tool, { type: "switch_profile", name: profile.name, tool: profile.tool, mode: opts.mode, resume: opts.resume !== false, args }, { allowMissing: true });
|
|
8300
|
+
if (!response)
|
|
8301
|
+
die(`no running accounts supervisor for ${getTool(profile.tool).label}`);
|
|
8302
|
+
if (!response.ok)
|
|
8303
|
+
die(response.error);
|
|
8304
|
+
if (opts.json) {
|
|
8305
|
+
console.log(JSON.stringify(response, null, 2));
|
|
8306
|
+
return;
|
|
8307
|
+
}
|
|
8308
|
+
if ("queued" in response) {
|
|
8309
|
+
console.log(source_default.green(`✓ queued supervisor switch to ${source_default.bold(response.result.profile.name)}`));
|
|
8310
|
+
console.log(source_default.dim(` restart command: ${response.result.commandLine}`));
|
|
8311
|
+
}
|
|
8312
|
+
}));
|
|
8313
|
+
supervisor.command("stop").argument("<tool>", "tool id").description("stop a running supervisor and its child process").action(action(async (toolId) => {
|
|
8314
|
+
const response = await sendSupervisorRequest(toolId, { type: "stop" }, { allowMissing: true });
|
|
8315
|
+
if (!response)
|
|
8316
|
+
die(`no running accounts supervisor for ${toolId}`);
|
|
8317
|
+
if (!response.ok)
|
|
8318
|
+
die(response.error);
|
|
8319
|
+
console.log(source_default.green(`✓ stopping ${toolId} supervisor`));
|
|
8320
|
+
}));
|
|
7842
8321
|
program2.command("shell").argument("<name>", "profile name").description("open a subshell with the profile's config dir active").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").action(action((name, opts) => {
|
|
7843
8322
|
const profile = getProfile(name, opts.tool);
|
|
7844
8323
|
const tool = getTool(profile.tool);
|
|
@@ -7901,7 +8380,7 @@ tools.command("list", { isDefault: true }).description("list supported tools (bu
|
|
|
7901
8380
|
console.log(`${source_default.cyan(t.id.padEnd(10))} ${t.label.padEnd(16)} ${source_default.dim(envNames)} → ${source_default.dim(t.defaultDir)} ${tag}`);
|
|
7902
8381
|
}
|
|
7903
8382
|
}));
|
|
7904
|
-
tools.command("add").argument("<id>", "tool id, e.g. cursor").description("register a custom tool/app so profiles can target it").requiredOption("--label <label>", 'display name, e.g. "Cursor"').requiredOption("--env-var <VAR>", "env var that points the tool at its config dir").requiredOption("--bin <bin>", "binary to launch").option("--default-dir <path>", "default config dir (default: ~/.<id>)").option("--extra-env <VAR=VALUE...>", "additional env var templates; supports {profileDir}, {profileName}, {toolId}").option("--login-arg <arg...>", "arguments for `accounts login <profile> --tool <id>`").option("--account-file <file>", "file inside the config dir holding the email").option("--email-path <path>", "dot-path to the email inside that file (e.g. account.email)").action(action((id, opts) => {
|
|
8383
|
+
tools.command("add").argument("<id>", "tool id, e.g. cursor").description("register a custom tool/app so profiles can target it").requiredOption("--label <label>", 'display name, e.g. "Cursor"').requiredOption("--env-var <VAR>", "env var that points the tool at its config dir").requiredOption("--bin <bin>", "binary to launch").option("--default-dir <path>", "default config dir (default: ~/.<id>)").option("--extra-env <VAR=VALUE...>", "additional env var templates; supports {profileDir}, {profileName}, {toolId}").option("--login-arg <arg...>", "arguments for `accounts login <profile> --tool <id>`").option("--resume-arg <arg...>", "arguments for supervised resume/restart, e.g. --continue").option("--account-file <file>", "file inside the config dir holding the email").option("--email-path <path>", "dot-path to the email inside that file (e.g. account.email)").action(action((id, opts) => {
|
|
7905
8384
|
const extraEnv = {};
|
|
7906
8385
|
for (const entry of opts.extraEnv ?? []) {
|
|
7907
8386
|
const idx = entry.indexOf("=");
|
|
@@ -7914,9 +8393,10 @@ tools.command("add").argument("<id>", "tool id, e.g. cursor").description("regis
|
|
|
7914
8393
|
label: opts.label,
|
|
7915
8394
|
envVar: opts.envVar,
|
|
7916
8395
|
bin: opts.bin,
|
|
7917
|
-
defaultDir: opts.defaultDir ? expandPath(opts.defaultDir) :
|
|
8396
|
+
defaultDir: opts.defaultDir ? expandPath(opts.defaultDir) : join11(homedir5(), `.${id}`),
|
|
7918
8397
|
...Object.keys(extraEnv).length > 0 ? { extraEnv } : {},
|
|
7919
8398
|
...opts.loginArg ? { loginArgs: opts.loginArg } : {},
|
|
8399
|
+
...opts.resumeArg ? { resumeArgs: opts.resumeArg } : {},
|
|
7920
8400
|
...opts.accountFile ? { accountFile: opts.accountFile } : {},
|
|
7921
8401
|
...opts.emailPath ? { emailPath: opts.emailPath.split(".") } : {}
|
|
7922
8402
|
};
|
|
@@ -7934,7 +8414,7 @@ program2.command("doctor").description("check the store and profile dirs for pro
|
|
|
7934
8414
|
const profiles = listProfiles();
|
|
7935
8415
|
let problems = 0;
|
|
7936
8416
|
for (const p of profiles) {
|
|
7937
|
-
const missing = !
|
|
8417
|
+
const missing = !existsSync10(p.dir);
|
|
7938
8418
|
const noEmail = !p.email;
|
|
7939
8419
|
if (missing) {
|
|
7940
8420
|
console.log(source_default.red(` ✗ ${p.name}: config dir missing (${p.dir})`));
|
|
@@ -7982,9 +8462,9 @@ program2.parseAsync(process.argv);
|
|
|
7982
8462
|
function getVersion() {
|
|
7983
8463
|
try {
|
|
7984
8464
|
const here = dirname5(fileURLToPath(import.meta.url));
|
|
7985
|
-
for (const candidate of [
|
|
7986
|
-
if (
|
|
7987
|
-
const pkg = JSON.parse(
|
|
8465
|
+
for (const candidate of [join11(here, "..", "package.json"), join11(here, "package.json")]) {
|
|
8466
|
+
if (existsSync10(candidate)) {
|
|
8467
|
+
const pkg = JSON.parse(readFileSync6(candidate, "utf8"));
|
|
7988
8468
|
if (pkg.version)
|
|
7989
8469
|
return pkg.version;
|
|
7990
8470
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export { finalizeLogin } from "./lib/login.js";
|
|
|
12
12
|
export type { FinalizeLoginResult } from "./lib/login.js";
|
|
13
13
|
export { switchProfile } from "./lib/switch.js";
|
|
14
14
|
export type { SwitchMode, SwitchOptions, SwitchResult } from "./lib/switch.js";
|
|
15
|
+
export { listSupervisorStates, readSupervisorState, resolveSupervisorLaunch, runSupervisedTool, sendSupervisorRequest, supervisorDir, supervisorSocketPath, supervisorStatePath, } from "./lib/supervisor.js";
|
|
16
|
+
export type { RunSupervisorOptions, SupervisorClientOptions, SupervisorLaunchPlan, SupervisorRequest, SupervisorResponse, SupervisorState, } from "./lib/supervisor.js";
|
|
15
17
|
export { pickProfile } from "./lib/pick.js";
|
|
16
18
|
export type { PickOptions, PickResult } from "./lib/pick.js";
|
|
17
19
|
export { installHook, uninstallHook, hookPath, hookScript, shellSnippet } from "./lib/hook.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,aAAa,EACb,YAAY,EACZ,OAAO,EACP,SAAS,EACT,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,UAAU,EACV,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/F,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,EACzB,eAAe,EACf,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,aAAa,EACb,YAAY,EACZ,OAAO,EACP,SAAS,EACT,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,UAAU,EACV,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/F,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,EACzB,eAAe,EACf,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|