@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/index.js
CHANGED
|
@@ -4177,6 +4177,25 @@ var BUILTIN_TOOLS = [
|
|
|
4177
4177
|
loginHint: "complete the Codex login flow for this CODEX_HOME",
|
|
4178
4178
|
resumeArgs: ["resume", "--last"]
|
|
4179
4179
|
},
|
|
4180
|
+
{
|
|
4181
|
+
id: "takumi",
|
|
4182
|
+
label: "Takumi",
|
|
4183
|
+
envVar: "TAKUMI_CONFIG_DIR",
|
|
4184
|
+
defaultDir: join2(homedir2(), ".takumi"),
|
|
4185
|
+
bin: "takumi",
|
|
4186
|
+
loginHint: "complete Takumi auth in this TAKUMI_CONFIG_DIR",
|
|
4187
|
+
resumeArgs: ["--continue"],
|
|
4188
|
+
accountFile: ".claude.json",
|
|
4189
|
+
emailPath: ["oauthAccount", "emailAddress"]
|
|
4190
|
+
},
|
|
4191
|
+
{
|
|
4192
|
+
id: "gemini",
|
|
4193
|
+
label: "Gemini CLI",
|
|
4194
|
+
envVar: "GEMINI_CONFIG_DIR",
|
|
4195
|
+
defaultDir: join2(homedir2(), ".gemini"),
|
|
4196
|
+
bin: "gemini",
|
|
4197
|
+
loginHint: "complete Gemini auth in this GEMINI_CONFIG_DIR"
|
|
4198
|
+
},
|
|
4180
4199
|
{
|
|
4181
4200
|
id: "opencode",
|
|
4182
4201
|
label: "opencode",
|
|
@@ -4200,6 +4219,22 @@ var BUILTIN_TOOLS = [
|
|
|
4200
4219
|
loginArgs: ["login"],
|
|
4201
4220
|
loginHint: "complete cursor-agent login for this CURSOR_CONFIG_DIR"
|
|
4202
4221
|
},
|
|
4222
|
+
{
|
|
4223
|
+
id: "pi",
|
|
4224
|
+
label: "Pi Coding Agent",
|
|
4225
|
+
envVar: "PI_CODING_AGENT_HOME",
|
|
4226
|
+
defaultDir: join2(homedir2(), ".pi"),
|
|
4227
|
+
bin: "pi",
|
|
4228
|
+
loginHint: "complete Pi coding agent auth in this PI_CODING_AGENT_HOME"
|
|
4229
|
+
},
|
|
4230
|
+
{
|
|
4231
|
+
id: "hermes",
|
|
4232
|
+
label: "Hermes",
|
|
4233
|
+
envVar: "HERMES_HOME",
|
|
4234
|
+
defaultDir: join2(homedir2(), ".hermes"),
|
|
4235
|
+
bin: "hermes",
|
|
4236
|
+
loginHint: "complete Hermes auth in this HERMES_HOME"
|
|
4237
|
+
},
|
|
4203
4238
|
{
|
|
4204
4239
|
id: "kimi",
|
|
4205
4240
|
label: "Kimi Code",
|
|
@@ -4938,6 +4973,366 @@ function switchProfile(name, opts = {}) {
|
|
|
4938
4973
|
message
|
|
4939
4974
|
};
|
|
4940
4975
|
}
|
|
4976
|
+
// src/lib/supervisor.ts
|
|
4977
|
+
import { spawn } from "node:child_process";
|
|
4978
|
+
import { createHash } from "node:crypto";
|
|
4979
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync4, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
4980
|
+
import { createConnection, createServer } from "node:net";
|
|
4981
|
+
import { basename, join as join9 } from "node:path";
|
|
4982
|
+
var STATE_SUFFIX = ".json";
|
|
4983
|
+
function supervisorDir() {
|
|
4984
|
+
return join9(accountsHome(), "supervisors");
|
|
4985
|
+
}
|
|
4986
|
+
function supervisorStatePath(toolId) {
|
|
4987
|
+
return join9(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
|
|
4988
|
+
}
|
|
4989
|
+
function supervisorSocketPath(toolId) {
|
|
4990
|
+
if (process.platform === "win32") {
|
|
4991
|
+
const hash = createHash("sha1").update(accountsHome()).digest("hex").slice(0, 12);
|
|
4992
|
+
return `\\\\.\\pipe\\hasna-accounts-${hash}-${toolId}`;
|
|
4993
|
+
}
|
|
4994
|
+
return join9(supervisorDir(), `${toolId}.sock`);
|
|
4995
|
+
}
|
|
4996
|
+
function nowIso2() {
|
|
4997
|
+
return new Date().toISOString();
|
|
4998
|
+
}
|
|
4999
|
+
function parseState(raw) {
|
|
5000
|
+
const data = JSON.parse(raw);
|
|
5001
|
+
if (data.version !== 1 || typeof data.tool !== "string" || typeof data.profile !== "string" || typeof data.pid !== "number" || typeof data.socketPath !== "string" || !Array.isArray(data.command)) {
|
|
5002
|
+
return;
|
|
5003
|
+
}
|
|
5004
|
+
return data;
|
|
5005
|
+
}
|
|
5006
|
+
function readSupervisorState(toolId) {
|
|
5007
|
+
const path = supervisorStatePath(toolId);
|
|
5008
|
+
if (!existsSync8(path))
|
|
5009
|
+
return;
|
|
5010
|
+
try {
|
|
5011
|
+
return parseState(readFileSync4(path, "utf8"));
|
|
5012
|
+
} catch {
|
|
5013
|
+
return;
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
function listSupervisorStates() {
|
|
5017
|
+
const dir = supervisorDir();
|
|
5018
|
+
if (!existsSync8(dir))
|
|
5019
|
+
return [];
|
|
5020
|
+
return readdirSync(dir).filter((name) => name.endsWith(STATE_SUFFIX)).map((name) => basename(name, STATE_SUFFIX)).map((toolId) => readSupervisorState(toolId)).filter((state) => state !== undefined);
|
|
5021
|
+
}
|
|
5022
|
+
function writeSupervisorState(state) {
|
|
5023
|
+
mkdirSync6(supervisorDir(), { recursive: true });
|
|
5024
|
+
writeFileSync4(supervisorStatePath(state.tool), JSON.stringify(state, null, 2) + `
|
|
5025
|
+
`, { mode: 384 });
|
|
5026
|
+
}
|
|
5027
|
+
function removeSupervisorFiles(toolId) {
|
|
5028
|
+
rmSync2(supervisorStatePath(toolId), { force: true });
|
|
5029
|
+
if (process.platform !== "win32")
|
|
5030
|
+
rmSync2(supervisorSocketPath(toolId), { force: true });
|
|
5031
|
+
}
|
|
5032
|
+
function processAlive(pid) {
|
|
5033
|
+
try {
|
|
5034
|
+
process.kill(pid, 0);
|
|
5035
|
+
return true;
|
|
5036
|
+
} catch {
|
|
5037
|
+
return false;
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
function knownTool(id) {
|
|
5041
|
+
try {
|
|
5042
|
+
return getTool(id);
|
|
5043
|
+
} catch {
|
|
5044
|
+
return;
|
|
5045
|
+
}
|
|
5046
|
+
}
|
|
5047
|
+
function resolveSupervisorLaunch(target, opts = {}) {
|
|
5048
|
+
const targetTool = knownTool(target);
|
|
5049
|
+
if (opts.profile) {
|
|
5050
|
+
const profile2 = getProfile(opts.profile, opts.tool ?? targetTool?.id);
|
|
5051
|
+
if (targetTool && profile2.tool !== targetTool.id) {
|
|
5052
|
+
throw new AccountsError(`profile "${profile2.name}" belongs to ${profile2.tool}, not ${targetTool.id}`);
|
|
5053
|
+
}
|
|
5054
|
+
return { profile: profile2, tool: getTool(profile2.tool), targetKind: targetTool ? "tool" : "profile" };
|
|
5055
|
+
}
|
|
5056
|
+
if (targetTool && !opts.tool) {
|
|
5057
|
+
const profile2 = currentProfile(targetTool.id) ?? appliedProfile(targetTool.id);
|
|
5058
|
+
if (!profile2) {
|
|
5059
|
+
throw new AccountsError(`no active ${targetTool.label} profile. Run \`accounts use <name> --tool ${targetTool.id}\` or pass --profile.`);
|
|
5060
|
+
}
|
|
5061
|
+
return { profile: profile2, tool: targetTool, targetKind: "tool" };
|
|
5062
|
+
}
|
|
5063
|
+
const profile = getProfile(target, opts.tool);
|
|
5064
|
+
return { profile, tool: getTool(profile.tool), targetKind: "profile" };
|
|
5065
|
+
}
|
|
5066
|
+
function exitCode(code, signal) {
|
|
5067
|
+
if (code !== null)
|
|
5068
|
+
return code;
|
|
5069
|
+
if (signal === "SIGINT")
|
|
5070
|
+
return 130;
|
|
5071
|
+
if (signal === "SIGTERM")
|
|
5072
|
+
return 143;
|
|
5073
|
+
return signal ? 1 : 0;
|
|
5074
|
+
}
|
|
5075
|
+
function killChildProcess(child, signal) {
|
|
5076
|
+
if (!child.pid)
|
|
5077
|
+
return;
|
|
5078
|
+
if (process.platform !== "win32") {
|
|
5079
|
+
try {
|
|
5080
|
+
process.kill(-child.pid, signal);
|
|
5081
|
+
return;
|
|
5082
|
+
} catch {}
|
|
5083
|
+
}
|
|
5084
|
+
child.kill(signal);
|
|
5085
|
+
}
|
|
5086
|
+
function wait(ms) {
|
|
5087
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
5088
|
+
}
|
|
5089
|
+
async function listen(server, socketPath) {
|
|
5090
|
+
await new Promise((resolve3, reject) => {
|
|
5091
|
+
const onError = (err) => {
|
|
5092
|
+
server.off("listening", onListening);
|
|
5093
|
+
reject(err);
|
|
5094
|
+
};
|
|
5095
|
+
const onListening = () => {
|
|
5096
|
+
server.off("error", onError);
|
|
5097
|
+
resolve3();
|
|
5098
|
+
};
|
|
5099
|
+
server.once("error", onError);
|
|
5100
|
+
server.once("listening", onListening);
|
|
5101
|
+
server.listen(socketPath);
|
|
5102
|
+
});
|
|
5103
|
+
}
|
|
5104
|
+
async function sendSupervisorRequest(toolId, request, opts = {}) {
|
|
5105
|
+
const timeoutMs = opts.timeoutMs ?? 1500;
|
|
5106
|
+
const socketPath = supervisorSocketPath(toolId);
|
|
5107
|
+
return await new Promise((resolve3, reject) => {
|
|
5108
|
+
const socket = createConnection(socketPath);
|
|
5109
|
+
let buffer = "";
|
|
5110
|
+
let settled = false;
|
|
5111
|
+
const finish = (value) => {
|
|
5112
|
+
if (settled)
|
|
5113
|
+
return;
|
|
5114
|
+
settled = true;
|
|
5115
|
+
clearTimeout(timer);
|
|
5116
|
+
socket.destroy();
|
|
5117
|
+
resolve3(value);
|
|
5118
|
+
};
|
|
5119
|
+
const fail = (err) => {
|
|
5120
|
+
if (settled)
|
|
5121
|
+
return;
|
|
5122
|
+
settled = true;
|
|
5123
|
+
clearTimeout(timer);
|
|
5124
|
+
socket.destroy();
|
|
5125
|
+
if (opts.allowMissing && (err.code === "ENOENT" || err.code === "ECONNREFUSED")) {
|
|
5126
|
+
resolve3(undefined);
|
|
5127
|
+
} else {
|
|
5128
|
+
reject(new AccountsError(`could not contact accounts supervisor for ${toolId}: ${err.message}`));
|
|
5129
|
+
}
|
|
5130
|
+
};
|
|
5131
|
+
const timer = setTimeout(() => {
|
|
5132
|
+
fail(Object.assign(new Error(`timed out after ${timeoutMs}ms`), { code: "ETIMEDOUT" }));
|
|
5133
|
+
}, timeoutMs);
|
|
5134
|
+
socket.setEncoding("utf8");
|
|
5135
|
+
socket.once("connect", () => {
|
|
5136
|
+
socket.write(JSON.stringify(request) + `
|
|
5137
|
+
`);
|
|
5138
|
+
});
|
|
5139
|
+
socket.once("error", fail);
|
|
5140
|
+
socket.on("data", (chunk) => {
|
|
5141
|
+
buffer += chunk;
|
|
5142
|
+
const newline = buffer.indexOf(`
|
|
5143
|
+
`);
|
|
5144
|
+
if (newline === -1)
|
|
5145
|
+
return;
|
|
5146
|
+
try {
|
|
5147
|
+
finish(JSON.parse(buffer.slice(0, newline)));
|
|
5148
|
+
} catch (err) {
|
|
5149
|
+
fail(err);
|
|
5150
|
+
}
|
|
5151
|
+
});
|
|
5152
|
+
socket.once("end", () => {
|
|
5153
|
+
if (!settled)
|
|
5154
|
+
fail(new Error("connection closed without a response"));
|
|
5155
|
+
});
|
|
5156
|
+
});
|
|
5157
|
+
}
|
|
5158
|
+
async function runSupervisedTool(initialProfile, tool, initialArgs = [], opts = {}) {
|
|
5159
|
+
const socketPath = supervisorSocketPath(tool.id);
|
|
5160
|
+
const existing = readSupervisorState(tool.id);
|
|
5161
|
+
if (existing && processAlive(existing.pid)) {
|
|
5162
|
+
throw new AccountsError(`an accounts supervisor for ${tool.label} is already running (pid ${existing.pid})`);
|
|
5163
|
+
}
|
|
5164
|
+
removeSupervisorFiles(tool.id);
|
|
5165
|
+
mkdirSync6(supervisorDir(), { recursive: true });
|
|
5166
|
+
const startedAt = nowIso2();
|
|
5167
|
+
const restartDelayMs = opts.restartDelayMs ?? 350;
|
|
5168
|
+
const log = opts.log ?? (() => {
|
|
5169
|
+
return;
|
|
5170
|
+
});
|
|
5171
|
+
const server = createServer();
|
|
5172
|
+
let profile = initialProfile;
|
|
5173
|
+
let childArgs = initialArgs;
|
|
5174
|
+
let child;
|
|
5175
|
+
let stopping = false;
|
|
5176
|
+
let restarting = false;
|
|
5177
|
+
let settled = false;
|
|
5178
|
+
const state = () => ({
|
|
5179
|
+
version: 1,
|
|
5180
|
+
tool: tool.id,
|
|
5181
|
+
profile: profile.name,
|
|
5182
|
+
pid: process.pid,
|
|
5183
|
+
...child?.pid ? { childPid: child.pid } : {},
|
|
5184
|
+
socketPath,
|
|
5185
|
+
command: [tool.bin, ...childArgs],
|
|
5186
|
+
startedAt,
|
|
5187
|
+
updatedAt: nowIso2()
|
|
5188
|
+
});
|
|
5189
|
+
const persist = () => writeSupervisorState(state());
|
|
5190
|
+
const stopChild = async () => {
|
|
5191
|
+
const target = child;
|
|
5192
|
+
if (!target || target.exitCode !== null)
|
|
5193
|
+
return;
|
|
5194
|
+
await new Promise((resolve3) => {
|
|
5195
|
+
let done2 = false;
|
|
5196
|
+
const finish = () => {
|
|
5197
|
+
if (done2)
|
|
5198
|
+
return;
|
|
5199
|
+
done2 = true;
|
|
5200
|
+
clearTimeout(killTimer);
|
|
5201
|
+
resolve3();
|
|
5202
|
+
};
|
|
5203
|
+
const killTimer = setTimeout(() => {
|
|
5204
|
+
try {
|
|
5205
|
+
killChildProcess(target, "SIGKILL");
|
|
5206
|
+
} catch {
|
|
5207
|
+
finish();
|
|
5208
|
+
}
|
|
5209
|
+
}, 2500);
|
|
5210
|
+
target.once("exit", finish);
|
|
5211
|
+
try {
|
|
5212
|
+
killChildProcess(target, "SIGTERM");
|
|
5213
|
+
} catch {
|
|
5214
|
+
finish();
|
|
5215
|
+
}
|
|
5216
|
+
});
|
|
5217
|
+
};
|
|
5218
|
+
const cleanup = () => {
|
|
5219
|
+
server.close();
|
|
5220
|
+
removeSupervisorFiles(tool.id);
|
|
5221
|
+
process.off("SIGINT", onSigint);
|
|
5222
|
+
process.off("SIGTERM", onSigterm);
|
|
5223
|
+
};
|
|
5224
|
+
let resolveRun;
|
|
5225
|
+
const done = new Promise((resolve3) => {
|
|
5226
|
+
resolveRun = resolve3;
|
|
5227
|
+
});
|
|
5228
|
+
const finishRun = (code) => {
|
|
5229
|
+
if (settled)
|
|
5230
|
+
return;
|
|
5231
|
+
settled = true;
|
|
5232
|
+
cleanup();
|
|
5233
|
+
resolveRun(code);
|
|
5234
|
+
};
|
|
5235
|
+
const startChild = (nextProfile, nextArgs) => {
|
|
5236
|
+
profile = nextProfile;
|
|
5237
|
+
childArgs = nextArgs;
|
|
5238
|
+
useProfile(profile.name, tool.id);
|
|
5239
|
+
const env = profileEnv(profile, tool);
|
|
5240
|
+
log(`accounts supervisor: starting ${tool.bin} for ${profile.name}`);
|
|
5241
|
+
const proc = spawn(tool.bin, childArgs, {
|
|
5242
|
+
stdio: opts.stdio ?? "inherit",
|
|
5243
|
+
env: { ...process.env, ...env, ACCOUNTS_SUPERVISOR: "1", ACCOUNTS_ACTIVE: profile.name },
|
|
5244
|
+
detached: process.platform !== "win32"
|
|
5245
|
+
});
|
|
5246
|
+
child = proc;
|
|
5247
|
+
persist();
|
|
5248
|
+
proc.once("error", (err) => {
|
|
5249
|
+
log(`accounts supervisor: failed to start ${tool.bin}: ${err.message}`);
|
|
5250
|
+
if (!restarting && !stopping)
|
|
5251
|
+
finishRun(1);
|
|
5252
|
+
});
|
|
5253
|
+
proc.once("exit", (code, signal) => {
|
|
5254
|
+
if (child === proc)
|
|
5255
|
+
child = undefined;
|
|
5256
|
+
persist();
|
|
5257
|
+
if (restarting || stopping)
|
|
5258
|
+
return;
|
|
5259
|
+
finishRun(exitCode(code, signal));
|
|
5260
|
+
});
|
|
5261
|
+
};
|
|
5262
|
+
const restartWith = async (result) => {
|
|
5263
|
+
restarting = true;
|
|
5264
|
+
try {
|
|
5265
|
+
await wait(restartDelayMs);
|
|
5266
|
+
await stopChild();
|
|
5267
|
+
startChild(getProfile(result.profile.name, tool.id), result.command.slice(1));
|
|
5268
|
+
} finally {
|
|
5269
|
+
restarting = false;
|
|
5270
|
+
}
|
|
5271
|
+
};
|
|
5272
|
+
const shutdown = async (code) => {
|
|
5273
|
+
if (stopping)
|
|
5274
|
+
return;
|
|
5275
|
+
stopping = true;
|
|
5276
|
+
await stopChild();
|
|
5277
|
+
finishRun(code);
|
|
5278
|
+
};
|
|
5279
|
+
const handleRequest = async (request) => {
|
|
5280
|
+
if (request.type === "status")
|
|
5281
|
+
return { ok: true, state: state() };
|
|
5282
|
+
if (request.type === "stop") {
|
|
5283
|
+
setTimeout(() => void shutdown(0), 25);
|
|
5284
|
+
return { ok: true, stopping: true, state: state() };
|
|
5285
|
+
}
|
|
5286
|
+
if (request.type !== "switch_profile")
|
|
5287
|
+
return { ok: false, error: "unknown supervisor request" };
|
|
5288
|
+
if (request.tool && request.tool !== tool.id) {
|
|
5289
|
+
return { ok: false, error: `this supervisor runs ${tool.id}, not ${request.tool}` };
|
|
5290
|
+
}
|
|
5291
|
+
try {
|
|
5292
|
+
const result = switchProfile(request.name, {
|
|
5293
|
+
tool: tool.id,
|
|
5294
|
+
mode: request.mode ?? "auto",
|
|
5295
|
+
resume: request.resume ?? true,
|
|
5296
|
+
args: request.args ?? []
|
|
5297
|
+
});
|
|
5298
|
+
log(`accounts supervisor: switching ${tool.id} to ${result.profile.name}`);
|
|
5299
|
+
setTimeout(() => void restartWith(result), 0);
|
|
5300
|
+
return { ok: true, queued: true, result, state: state(), restartDelayMs };
|
|
5301
|
+
} catch (err) {
|
|
5302
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
5303
|
+
}
|
|
5304
|
+
};
|
|
5305
|
+
server.on("connection", (socket) => {
|
|
5306
|
+
socket.setEncoding("utf8");
|
|
5307
|
+
let buffer = "";
|
|
5308
|
+
socket.on("data", (chunk) => {
|
|
5309
|
+
buffer += chunk;
|
|
5310
|
+
const newline = buffer.indexOf(`
|
|
5311
|
+
`);
|
|
5312
|
+
if (newline === -1)
|
|
5313
|
+
return;
|
|
5314
|
+
const line = buffer.slice(0, newline);
|
|
5315
|
+
buffer = buffer.slice(newline + 1);
|
|
5316
|
+
(async () => {
|
|
5317
|
+
let response;
|
|
5318
|
+
try {
|
|
5319
|
+
response = await handleRequest(JSON.parse(line));
|
|
5320
|
+
} catch (err) {
|
|
5321
|
+
response = { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
5322
|
+
}
|
|
5323
|
+
socket.end(JSON.stringify(response) + `
|
|
5324
|
+
`);
|
|
5325
|
+
})();
|
|
5326
|
+
});
|
|
5327
|
+
});
|
|
5328
|
+
const onSigint = () => void shutdown(130);
|
|
5329
|
+
const onSigterm = () => void shutdown(143);
|
|
5330
|
+
process.once("SIGINT", onSigint);
|
|
5331
|
+
process.once("SIGTERM", onSigterm);
|
|
5332
|
+
await listen(server, socketPath);
|
|
5333
|
+
startChild(profile, childArgs);
|
|
5334
|
+
return await done;
|
|
5335
|
+
}
|
|
4941
5336
|
// src/lib/pick.ts
|
|
4942
5337
|
import * as readline from "node:readline/promises";
|
|
4943
5338
|
import { stdin as input, stdout as output } from "node:process";
|
|
@@ -4971,8 +5366,8 @@ async function pickProfile(opts = {}) {
|
|
|
4971
5366
|
return { profile, mode };
|
|
4972
5367
|
}
|
|
4973
5368
|
// src/lib/hook.ts
|
|
4974
|
-
import { existsSync as
|
|
4975
|
-
import { join as
|
|
5369
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
5370
|
+
import { join as join10 } from "node:path";
|
|
4976
5371
|
var HOOK_FILE = "claude-hook.sh";
|
|
4977
5372
|
var MARKER = "# accounts-claude-hook";
|
|
4978
5373
|
var NAME_PATTERN = "^[a-z0-9][a-z0-9-]*$";
|
|
@@ -4980,7 +5375,7 @@ function shellQuotePath(path) {
|
|
|
4980
5375
|
return `'${path.replace(/'/g, `'\\''`)}'`;
|
|
4981
5376
|
}
|
|
4982
5377
|
function hookPath() {
|
|
4983
|
-
return
|
|
5378
|
+
return join10(accountsHome(), HOOK_FILE);
|
|
4984
5379
|
}
|
|
4985
5380
|
function hookScript() {
|
|
4986
5381
|
const quotedHook = shellQuotePath(hookPath());
|
|
@@ -5010,16 +5405,16 @@ claude() {
|
|
|
5010
5405
|
}
|
|
5011
5406
|
function installHook() {
|
|
5012
5407
|
const path = hookPath();
|
|
5013
|
-
|
|
5014
|
-
const created = !
|
|
5015
|
-
|
|
5408
|
+
mkdirSync7(accountsHome(), { recursive: true });
|
|
5409
|
+
const created = !existsSync9(path);
|
|
5410
|
+
writeFileSync5(path, hookScript(), { mode: 493 });
|
|
5016
5411
|
return { path, created };
|
|
5017
5412
|
}
|
|
5018
5413
|
function uninstallHook() {
|
|
5019
5414
|
const path = hookPath();
|
|
5020
|
-
if (!
|
|
5415
|
+
if (!existsSync9(path))
|
|
5021
5416
|
return false;
|
|
5022
|
-
const content =
|
|
5417
|
+
const content = readFileSync5(path, "utf8");
|
|
5023
5418
|
if (!content.includes(MARKER))
|
|
5024
5419
|
return false;
|
|
5025
5420
|
unlinkSync3(path);
|
|
@@ -5038,17 +5433,24 @@ export {
|
|
|
5038
5433
|
uninstallHook,
|
|
5039
5434
|
toolDefSchema,
|
|
5040
5435
|
switchProfile,
|
|
5436
|
+
supervisorStatePath,
|
|
5437
|
+
supervisorSocketPath,
|
|
5438
|
+
supervisorDir,
|
|
5041
5439
|
storeSchema,
|
|
5042
5440
|
storePath,
|
|
5043
5441
|
snapshotLiveAuthToProfile,
|
|
5044
5442
|
snapshotClaudeAuthToProfile,
|
|
5045
5443
|
shellSnippet,
|
|
5444
|
+
sendSupervisorRequest,
|
|
5046
5445
|
saveStore,
|
|
5446
|
+
runSupervisedTool,
|
|
5047
5447
|
restoreClaudeAuthFromProfile,
|
|
5448
|
+
resolveSupervisorLaunch,
|
|
5048
5449
|
renameProfile,
|
|
5049
5450
|
removeProfile,
|
|
5050
5451
|
removeCustomTool,
|
|
5051
5452
|
redetectEmail,
|
|
5453
|
+
readSupervisorState,
|
|
5052
5454
|
readClaudeKeychain,
|
|
5053
5455
|
profilesDir,
|
|
5054
5456
|
profileSchema,
|
|
@@ -5058,6 +5460,7 @@ export {
|
|
|
5058
5460
|
pickProfile,
|
|
5059
5461
|
loadStore,
|
|
5060
5462
|
listTools,
|
|
5463
|
+
listSupervisorStates,
|
|
5061
5464
|
listProfiles,
|
|
5062
5465
|
keychainSupported,
|
|
5063
5466
|
isSafeProfileName,
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type StdioOptions } from "node:child_process";
|
|
2
|
+
import type { Profile, ToolDef } from "../types.js";
|
|
3
|
+
import { type SwitchMode, type SwitchResult } from "./switch.js";
|
|
4
|
+
export interface SupervisorState {
|
|
5
|
+
version: 1;
|
|
6
|
+
tool: string;
|
|
7
|
+
profile: string;
|
|
8
|
+
pid: number;
|
|
9
|
+
childPid?: number;
|
|
10
|
+
socketPath: string;
|
|
11
|
+
command: string[];
|
|
12
|
+
startedAt: string;
|
|
13
|
+
updatedAt: string;
|
|
14
|
+
}
|
|
15
|
+
export type SupervisorRequest = {
|
|
16
|
+
type: "status";
|
|
17
|
+
} | {
|
|
18
|
+
type: "switch_profile";
|
|
19
|
+
name: string;
|
|
20
|
+
tool?: string;
|
|
21
|
+
mode?: SwitchMode;
|
|
22
|
+
resume?: boolean;
|
|
23
|
+
args?: string[];
|
|
24
|
+
} | {
|
|
25
|
+
type: "stop";
|
|
26
|
+
};
|
|
27
|
+
export type SupervisorResponse = {
|
|
28
|
+
ok: true;
|
|
29
|
+
state: SupervisorState;
|
|
30
|
+
} | {
|
|
31
|
+
ok: true;
|
|
32
|
+
queued: true;
|
|
33
|
+
result: SwitchResult;
|
|
34
|
+
state: SupervisorState;
|
|
35
|
+
restartDelayMs: number;
|
|
36
|
+
} | {
|
|
37
|
+
ok: true;
|
|
38
|
+
stopping: true;
|
|
39
|
+
state: SupervisorState;
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
error: string;
|
|
43
|
+
};
|
|
44
|
+
export interface SupervisorLaunchPlan {
|
|
45
|
+
profile: Profile;
|
|
46
|
+
tool: ToolDef;
|
|
47
|
+
targetKind: "tool" | "profile";
|
|
48
|
+
}
|
|
49
|
+
export interface RunSupervisorOptions {
|
|
50
|
+
stdio?: StdioOptions;
|
|
51
|
+
restartDelayMs?: number;
|
|
52
|
+
log?: (message: string) => void;
|
|
53
|
+
}
|
|
54
|
+
export interface SupervisorClientOptions {
|
|
55
|
+
timeoutMs?: number;
|
|
56
|
+
allowMissing?: boolean;
|
|
57
|
+
}
|
|
58
|
+
export declare function supervisorDir(): string;
|
|
59
|
+
export declare function supervisorStatePath(toolId: string): string;
|
|
60
|
+
export declare function supervisorSocketPath(toolId: string): string;
|
|
61
|
+
export declare function readSupervisorState(toolId: string): SupervisorState | undefined;
|
|
62
|
+
export declare function listSupervisorStates(): SupervisorState[];
|
|
63
|
+
export declare function resolveSupervisorLaunch(target: string, opts?: {
|
|
64
|
+
profile?: string;
|
|
65
|
+
tool?: string;
|
|
66
|
+
}): SupervisorLaunchPlan;
|
|
67
|
+
export declare function sendSupervisorRequest(toolId: string, request: SupervisorRequest, opts?: SupervisorClientOptions): Promise<SupervisorResponse | undefined>;
|
|
68
|
+
export declare function runSupervisedTool(initialProfile: Profile, tool: ToolDef, initialArgs?: string[], opts?: RunSupervisorOptions): Promise<number>;
|
|
69
|
+
//# sourceMappingURL=supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../src/lib/supervisor.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/lib/tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAgC,MAAM,aAAa,CAAC;AAGzE;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/lib/tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAgC,MAAM,aAAa,CAAC;AAGzE;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,OAAO,EAkGlC,CAAC;AAEF,eAAO,MAAM,YAAY,WAAW,CAAC;AAIrC,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,oFAAoF;AACpF,wBAAgB,SAAS,IAAI,OAAO,EAAE,CAMrC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAS3C;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAanD;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAWjD"}
|