@hasna/accounts 0.1.8 → 0.1.10

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.
Files changed (2) hide show
  1. package/dist/cli.js +802 -117
  2. package/package.json +2 -1
package/dist/cli.js CHANGED
@@ -992,7 +992,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
992
992
  this._exitCallback = (err) => {
993
993
  if (err.code !== "commander.executeSubCommandAsync") {
994
994
  throw err;
995
- } else {}
995
+ }
996
996
  };
997
997
  }
998
998
  return this;
@@ -4307,7 +4307,7 @@ var require_config = __commonJS((exports) => {
4307
4307
  };
4308
4308
  var filePromises = {};
4309
4309
  var fileIntercept = {};
4310
- var readFile = (path, options) => {
4310
+ var readFile2 = (path, options) => {
4311
4311
  if (fileIntercept[path] !== undefined) {
4312
4312
  return fileIntercept[path];
4313
4313
  }
@@ -4330,10 +4330,10 @@ var require_config = __commonJS((exports) => {
4330
4330
  resolvedConfigFilepath = node_path.join(homeDir, configFilepath.slice(2));
4331
4331
  }
4332
4332
  const parsedFiles = await Promise.all([
4333
- readFile(resolvedConfigFilepath, {
4333
+ readFile2(resolvedConfigFilepath, {
4334
4334
  ignoreCache: init.ignoreCache
4335
4335
  }).then(parseIni).then(getConfigData).catch(swallowError$1),
4336
- readFile(resolvedFilepath, {
4336
+ readFile2(resolvedFilepath, {
4337
4337
  ignoreCache: init.ignoreCache
4338
4338
  }).then(parseIni).catch(swallowError$1)
4339
4339
  ]);
@@ -4344,7 +4344,7 @@ var require_config = __commonJS((exports) => {
4344
4344
  };
4345
4345
  var getSsoSessionData = (data) => Object.entries(data).filter(([key]) => key.startsWith(types2.IniSectionType.SSO_SESSION + CONFIG_PREFIX_SEPARATOR)).reduce((acc, [key, value]) => ({ ...acc, [key.substring(key.indexOf(CONFIG_PREFIX_SEPARATOR) + 1)]: value }), {});
4346
4346
  var swallowError = () => ({});
4347
- var loadSsoSessionData = async (init = {}) => readFile(init.configFilepath ?? getConfigFilepath()).then(parseIni).then(getSsoSessionData).catch(swallowError);
4347
+ var loadSsoSessionData = async (init = {}) => readFile2(init.configFilepath ?? getConfigFilepath()).then(parseIni).then(getSsoSessionData).catch(swallowError);
4348
4348
  var mergeConfigFiles = (...files) => {
4349
4349
  const merged = {};
4350
4350
  for (const file of files) {
@@ -4711,7 +4711,7 @@ var require_config = __commonJS((exports) => {
4711
4711
  exports.nodeFipsConfigSelectors = nodeFipsConfigSelectors;
4712
4712
  exports.numberSelector = numberSelector;
4713
4713
  exports.parseKnownFiles = parseKnownFiles;
4714
- exports.readFile = readFile;
4714
+ exports.readFile = readFile2;
4715
4715
  exports.resolveCustomEndpointsConfig = resolveCustomEndpointsConfig;
4716
4716
  exports.resolveDefaultsModeConfig = resolveDefaultsModeConfig;
4717
4717
  exports.resolveEndpointsConfig = resolveEndpointsConfig;
@@ -5760,19 +5760,19 @@ var require_serde = __commonJS((exports) => {
5760
5760
  };
5761
5761
  var strictParseDouble = (value) => {
5762
5762
  if (typeof value == "string") {
5763
- return expectNumber(parseNumber(value));
5763
+ return expectNumber(parseNumber2(value));
5764
5764
  }
5765
5765
  return expectNumber(value);
5766
5766
  };
5767
5767
  var strictParseFloat = strictParseDouble;
5768
5768
  var strictParseFloat32 = (value) => {
5769
5769
  if (typeof value == "string") {
5770
- return expectFloat32(parseNumber(value));
5770
+ return expectFloat32(parseNumber2(value));
5771
5771
  }
5772
5772
  return expectFloat32(value);
5773
5773
  };
5774
5774
  var NUMBER_REGEX = /(-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)|(-?Infinity)|(NaN)/g;
5775
- var parseNumber = (value) => {
5775
+ var parseNumber2 = (value) => {
5776
5776
  const matches = value.match(NUMBER_REGEX);
5777
5777
  if (matches === null || matches[0].length !== value.length) {
5778
5778
  throw new TypeError(`Expected real number, got implicit NaN`);
@@ -5807,26 +5807,26 @@ var require_serde = __commonJS((exports) => {
5807
5807
  };
5808
5808
  var strictParseLong = (value) => {
5809
5809
  if (typeof value === "string") {
5810
- return expectLong(parseNumber(value));
5810
+ return expectLong(parseNumber2(value));
5811
5811
  }
5812
5812
  return expectLong(value);
5813
5813
  };
5814
5814
  var strictParseInt = strictParseLong;
5815
5815
  var strictParseInt32 = (value) => {
5816
5816
  if (typeof value === "string") {
5817
- return expectInt32(parseNumber(value));
5817
+ return expectInt32(parseNumber2(value));
5818
5818
  }
5819
5819
  return expectInt32(value);
5820
5820
  };
5821
5821
  var strictParseShort = (value) => {
5822
5822
  if (typeof value === "string") {
5823
- return expectShort(parseNumber(value));
5823
+ return expectShort(parseNumber2(value));
5824
5824
  }
5825
5825
  return expectShort(value);
5826
5826
  };
5827
5827
  var strictParseByte = (value) => {
5828
5828
  if (typeof value === "string") {
5829
- return expectByte(parseNumber(value));
5829
+ return expectByte(parseNumber2(value));
5830
5830
  }
5831
5831
  return expectByte(value);
5832
5832
  };
@@ -12259,7 +12259,7 @@ var require_es5 = __commonJS((exports, module) => {
12259
12259
 
12260
12260
  // node_modules/@aws-sdk/core/dist-cjs/submodules/client/index.js
12261
12261
  var require_client2 = __commonJS((exports) => {
12262
- var __dirname = "/home/hasna/workspace/hasna/opensource/open-accounts/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
12262
+ var __dirname = "/tmp/hasna-events-refresh-1781608411540/open-accounts/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
12263
12263
  var retry = require_retry();
12264
12264
  var protocols = require_protocols();
12265
12265
  var lambdaInvokeStore = require_invoke_store();
@@ -14153,8 +14153,8 @@ ${serde.toHex(hashedRequest)}`;
14153
14153
  throw new Error("Resolved credential object is not valid");
14154
14154
  }
14155
14155
  }
14156
- formatDate(now) {
14157
- const longDate = iso8601(now).replace(/[\-:]/g, "");
14156
+ formatDate(now2) {
14157
+ const longDate = iso8601(now2).replace(/[\-:]/g, "");
14158
14158
  return {
14159
14159
  longDate,
14160
14160
  shortDate: longDate.slice(0, 8)
@@ -19955,8 +19955,8 @@ var require_s3 = __commonJS((exports) => {
19955
19955
  delete this.data[key];
19956
19956
  }
19957
19957
  async purgeExpired() {
19958
- const now = Date.now();
19959
- if (this.lastPurgeTime + S3ExpressIdentityCache.EXPIRED_CREDENTIAL_PURGE_INTERVAL_MS > now) {
19958
+ const now2 = Date.now();
19959
+ if (this.lastPurgeTime + S3ExpressIdentityCache.EXPIRED_CREDENTIAL_PURGE_INTERVAL_MS > now2) {
19960
19960
  return;
19961
19961
  }
19962
19962
  for (const key in this.data) {
@@ -19964,7 +19964,7 @@ var require_s3 = __commonJS((exports) => {
19964
19964
  if (!entry.isRefreshing) {
19965
19965
  const credential = await entry.identity;
19966
19966
  if (credential.expiration) {
19967
- if (credential.expiration.getTime() < now) {
19967
+ if (credential.expiration.getTime() < now2) {
19968
19968
  delete this.data[key];
19969
19969
  }
19970
19970
  }
@@ -30963,11 +30963,11 @@ var require_dist_cjs15 = __commonJS((exports) => {
30963
30963
  throw new config.TokenProviderError(`Value not present for '${key}' in SSO Token${forRefresh ? ". Cannot refresh" : ""}. ${REFRESH_MESSAGE}`, false);
30964
30964
  }
30965
30965
  };
30966
- var { writeFile } = node_fs.promises;
30966
+ var { writeFile: writeFile2 } = node_fs.promises;
30967
30967
  var writeSSOTokenToFile = (id, ssoToken) => {
30968
30968
  const tokenFilepath = config.getSSOTokenFilepath(id);
30969
30969
  const tokenString = JSON.stringify(ssoToken, null, 2);
30970
- return writeFile(tokenFilepath, tokenString);
30970
+ return writeFile2(tokenFilepath, tokenString);
30971
30971
  };
30972
30972
  var lastRefreshAttemptTime = new Date(0);
30973
30973
  var fromSso = (init = {}) => async ({ callerClientConfig } = {}) => {
@@ -32364,9 +32364,9 @@ var require_dist_cjs17 = __commonJS((exports) => {
32364
32364
  throw new config.CredentialsProviderError(`Failed to load a token for session ${this.loginSession}, please re-authenticate using aws login`, { tryNextLink: false, logger: this.logger });
32365
32365
  }
32366
32366
  const accessToken = token.accessToken;
32367
- const now = Date.now();
32367
+ const now2 = Date.now();
32368
32368
  const expiryTime = new Date(accessToken.expiresAt).getTime();
32369
- const timeUntilExpiry = expiryTime - now;
32369
+ const timeUntilExpiry = expiryTime - now2;
32370
32370
  if (timeUntilExpiry <= LoginCredentialsFetcher.REFRESH_THRESHOLD) {
32371
32371
  return this.refresh(token);
32372
32372
  }
@@ -36797,9 +36797,9 @@ var require_dist_cjs22 = __commonJS((exports) => {
36797
36797
 
36798
36798
  // src/cli.ts
36799
36799
  import { spawnSync as spawnSync2 } from "node:child_process";
36800
- import { existsSync as existsSync11, readFileSync as readFileSync7 } from "node:fs";
36801
- import { homedir as homedir5 } from "node:os";
36802
- import { dirname as dirname5, join as join11 } from "node:path";
36800
+ import { existsSync as existsSync12, readFileSync as readFileSync7 } from "node:fs";
36801
+ import { homedir as homedir6 } from "node:os";
36802
+ import { dirname as dirname5, join as join12 } from "node:path";
36803
36803
  import { fileURLToPath } from "node:url";
36804
36804
 
36805
36805
  // node_modules/commander/esm.mjs
@@ -36818,6 +36818,690 @@ var {
36818
36818
  Help
36819
36819
  } = import__.default;
36820
36820
 
36821
+ // node_modules/@hasna/events/dist/commander.js
36822
+ import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
36823
+ import { existsSync } from "fs";
36824
+ import { homedir } from "os";
36825
+ import { join } from "path";
36826
+ import { createHmac, timingSafeEqual } from "crypto";
36827
+ import { randomUUID } from "crypto";
36828
+ import { spawn } from "child_process";
36829
+ import { randomUUID as randomUUID2 } from "crypto";
36830
+ function getPathValue(input, path) {
36831
+ return path.split(".").reduce((value, part) => {
36832
+ if (value && typeof value === "object" && part in value) {
36833
+ return value[part];
36834
+ }
36835
+ return;
36836
+ }, input);
36837
+ }
36838
+ function wildcardToRegExp(pattern) {
36839
+ const escaped = pattern.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".*");
36840
+ return new RegExp(`^${escaped}$`);
36841
+ }
36842
+ function matchString(value, matcher) {
36843
+ if (matcher === undefined)
36844
+ return true;
36845
+ if (value === undefined)
36846
+ return false;
36847
+ const matchers = Array.isArray(matcher) ? matcher : [matcher];
36848
+ return matchers.some((item) => wildcardToRegExp(item).test(value));
36849
+ }
36850
+ function matchRecord(input, matcher) {
36851
+ if (!matcher)
36852
+ return true;
36853
+ return Object.entries(matcher).every(([path, expected]) => {
36854
+ const actual = getPathValue(input, path);
36855
+ if (typeof expected === "string" || Array.isArray(expected)) {
36856
+ return matchString(actual === undefined ? undefined : String(actual), expected);
36857
+ }
36858
+ return actual === expected;
36859
+ });
36860
+ }
36861
+ function eventMatchesFilter(event, filter) {
36862
+ return matchString(event.source, filter.source) && matchString(event.type, filter.type) && matchString(event.subject, filter.subject) && matchString(event.severity, filter.severity) && matchRecord(event.data, filter.data) && matchRecord(event.metadata, filter.metadata);
36863
+ }
36864
+ function channelMatchesEvent(channel, event) {
36865
+ if (!channel.enabled)
36866
+ return false;
36867
+ if (!channel.filters || channel.filters.length === 0)
36868
+ return true;
36869
+ return channel.filters.some((filter) => eventMatchesFilter(event, filter));
36870
+ }
36871
+ var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
36872
+ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
36873
+ function getEventsDataDir(override) {
36874
+ return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
36875
+ }
36876
+
36877
+ class JsonEventsStore {
36878
+ dataDir;
36879
+ channelsPath;
36880
+ eventsPath;
36881
+ deliveriesPath;
36882
+ constructor(dataDir = getEventsDataDir()) {
36883
+ this.dataDir = dataDir;
36884
+ this.channelsPath = join(dataDir, "channels.json");
36885
+ this.eventsPath = join(dataDir, "events.json");
36886
+ this.deliveriesPath = join(dataDir, "deliveries.json");
36887
+ }
36888
+ async init() {
36889
+ await mkdir(this.dataDir, { recursive: true, mode: 448 });
36890
+ await chmod(this.dataDir, 448).catch(() => {
36891
+ return;
36892
+ });
36893
+ await this.ensureArrayFile(this.channelsPath);
36894
+ await this.ensureArrayFile(this.eventsPath);
36895
+ await this.ensureArrayFile(this.deliveriesPath);
36896
+ }
36897
+ async addChannel(channel) {
36898
+ await this.init();
36899
+ const channels = await this.readJson(this.channelsPath, []);
36900
+ const index = channels.findIndex((item) => item.id === channel.id);
36901
+ if (index >= 0) {
36902
+ channels[index] = { ...channel, createdAt: channels[index].createdAt, updatedAt: new Date().toISOString() };
36903
+ } else {
36904
+ channels.push(channel);
36905
+ }
36906
+ await this.writeJson(this.channelsPath, channels);
36907
+ return index >= 0 ? channels[index] : channel;
36908
+ }
36909
+ async listChannels() {
36910
+ await this.init();
36911
+ return this.readJson(this.channelsPath, []);
36912
+ }
36913
+ async getChannel(id) {
36914
+ const channels = await this.listChannels();
36915
+ return channels.find((channel) => channel.id === id);
36916
+ }
36917
+ async removeChannel(id) {
36918
+ await this.init();
36919
+ const channels = await this.readJson(this.channelsPath, []);
36920
+ const next = channels.filter((channel) => channel.id !== id);
36921
+ await this.writeJson(this.channelsPath, next);
36922
+ return next.length !== channels.length;
36923
+ }
36924
+ async appendEvent(event) {
36925
+ await this.init();
36926
+ const events = await this.readJson(this.eventsPath, []);
36927
+ events.push(event);
36928
+ await this.writeJson(this.eventsPath, events);
36929
+ return event;
36930
+ }
36931
+ async listEvents() {
36932
+ await this.init();
36933
+ return this.readJson(this.eventsPath, []);
36934
+ }
36935
+ async findEventByIdentity(identity) {
36936
+ const events = await this.listEvents();
36937
+ return events.find((event) => identity.id !== undefined && event.id === identity.id || identity.dedupeKey !== undefined && event.dedupeKey === identity.dedupeKey);
36938
+ }
36939
+ async appendDelivery(result) {
36940
+ await this.init();
36941
+ const deliveries = await this.readJson(this.deliveriesPath, []);
36942
+ deliveries.push(result);
36943
+ await this.writeJson(this.deliveriesPath, deliveries);
36944
+ return result;
36945
+ }
36946
+ async listDeliveries() {
36947
+ await this.init();
36948
+ return this.readJson(this.deliveriesPath, []);
36949
+ }
36950
+ async exportData() {
36951
+ return {
36952
+ channels: await this.listChannels(),
36953
+ events: await this.listEvents(),
36954
+ deliveries: await this.listDeliveries()
36955
+ };
36956
+ }
36957
+ async ensureArrayFile(path) {
36958
+ if (!existsSync(path)) {
36959
+ await writeFile(path, `[]
36960
+ `, { encoding: "utf-8", mode: 384 });
36961
+ }
36962
+ await chmod(path, 384).catch(() => {
36963
+ return;
36964
+ });
36965
+ }
36966
+ async readJson(path, fallback) {
36967
+ try {
36968
+ const raw = await readFile(path, "utf-8");
36969
+ if (!raw.trim())
36970
+ return fallback;
36971
+ return JSON.parse(raw);
36972
+ } catch (error) {
36973
+ if (error.code === "ENOENT")
36974
+ return fallback;
36975
+ throw error;
36976
+ }
36977
+ }
36978
+ async writeJson(path, value) {
36979
+ const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
36980
+ await writeFile(tempPath, `${JSON.stringify(value, null, 2)}
36981
+ `, { encoding: "utf-8", mode: 384 });
36982
+ await rename(tempPath, path);
36983
+ await chmod(path, 384).catch(() => {
36984
+ return;
36985
+ });
36986
+ }
36987
+ }
36988
+ var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
36989
+ function buildSignatureBase(timestamp, body) {
36990
+ return `${timestamp}.${body}`;
36991
+ }
36992
+ function signPayload(secret, timestamp, body) {
36993
+ const digest = createHmac("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
36994
+ return `sha256=${digest}`;
36995
+ }
36996
+ function now() {
36997
+ return new Date().toISOString();
36998
+ }
36999
+ function truncate(value, max = 4096) {
37000
+ return value.length > max ? `${value.slice(0, max)}...` : value;
37001
+ }
37002
+ function buildWebhookRequest(event, channel) {
37003
+ if (!channel.webhook)
37004
+ throw new Error(`Channel ${channel.id} has no webhook config`);
37005
+ const body = JSON.stringify(event);
37006
+ const timestamp = event.time;
37007
+ const headers = {
37008
+ "Content-Type": "application/json",
37009
+ "User-Agent": "@hasna/events",
37010
+ "X-Hasna-Event-Id": event.id,
37011
+ "X-Hasna-Event-Type": event.type,
37012
+ "X-Hasna-Timestamp": timestamp,
37013
+ ...channel.webhook.headers
37014
+ };
37015
+ if (channel.webhook.secret) {
37016
+ headers["X-Hasna-Signature"] = signPayload(channel.webhook.secret, timestamp, body);
37017
+ }
37018
+ return { body, headers };
37019
+ }
37020
+ async function dispatchWebhook(event, channel, options = {}) {
37021
+ if (!channel.webhook)
37022
+ throw new Error(`Channel ${channel.id} has no webhook config`);
37023
+ const startedAt = now();
37024
+ const { body, headers } = buildWebhookRequest(event, channel);
37025
+ const controller = new AbortController;
37026
+ const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
37027
+ try {
37028
+ const response = await (options.fetchImpl ?? fetch)(channel.webhook.url, {
37029
+ method: "POST",
37030
+ headers,
37031
+ body,
37032
+ signal: controller.signal
37033
+ });
37034
+ const responseBody = truncate(await response.text());
37035
+ return {
37036
+ attempt: 1,
37037
+ status: response.ok ? "success" : "failed",
37038
+ startedAt,
37039
+ completedAt: now(),
37040
+ responseStatus: response.status,
37041
+ responseBody,
37042
+ error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
37043
+ };
37044
+ } catch (error) {
37045
+ return {
37046
+ attempt: 1,
37047
+ status: "failed",
37048
+ startedAt,
37049
+ completedAt: now(),
37050
+ error: error instanceof Error ? error.message : String(error)
37051
+ };
37052
+ } finally {
37053
+ clearTimeout(timeout);
37054
+ }
37055
+ }
37056
+ async function dispatchCommand(event, channel) {
37057
+ if (!channel.command)
37058
+ throw new Error(`Channel ${channel.id} has no command config`);
37059
+ const startedAt = now();
37060
+ const eventJson = JSON.stringify(event);
37061
+ const env = {
37062
+ ...process.env,
37063
+ ...channel.command.env,
37064
+ HASNA_CHANNEL_ID: channel.id,
37065
+ HASNA_EVENT_ID: event.id,
37066
+ HASNA_EVENT_TYPE: event.type,
37067
+ HASNA_EVENT_SOURCE: event.source,
37068
+ HASNA_EVENT_SUBJECT: event.subject ?? "",
37069
+ HASNA_EVENT_SEVERITY: event.severity,
37070
+ HASNA_EVENT_TIME: event.time,
37071
+ HASNA_EVENT_DEDUPE_KEY: event.dedupeKey ?? "",
37072
+ HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
37073
+ HASNA_EVENT_JSON: eventJson
37074
+ };
37075
+ return new Promise((resolve) => {
37076
+ const child = spawn(channel.command.command, channel.command.args ?? [], {
37077
+ cwd: channel.command.cwd,
37078
+ env,
37079
+ stdio: ["pipe", "pipe", "pipe"]
37080
+ });
37081
+ let stdout = "";
37082
+ let stderr = "";
37083
+ const timeout = setTimeout(() => child.kill("SIGTERM"), channel.command.timeoutMs ?? 15000);
37084
+ child.stdin.end(eventJson);
37085
+ child.stdout.on("data", (chunk) => {
37086
+ stdout += chunk.toString();
37087
+ });
37088
+ child.stderr.on("data", (chunk) => {
37089
+ stderr += chunk.toString();
37090
+ });
37091
+ child.on("error", (error) => {
37092
+ clearTimeout(timeout);
37093
+ resolve({
37094
+ attempt: 1,
37095
+ status: "failed",
37096
+ startedAt,
37097
+ completedAt: now(),
37098
+ stdout: truncate(stdout),
37099
+ stderr: truncate(stderr),
37100
+ error: error.message
37101
+ });
37102
+ });
37103
+ child.on("close", (code, signal) => {
37104
+ clearTimeout(timeout);
37105
+ const success = code === 0;
37106
+ resolve({
37107
+ attempt: 1,
37108
+ status: success ? "success" : "failed",
37109
+ startedAt,
37110
+ completedAt: now(),
37111
+ stdout: truncate(stdout),
37112
+ stderr: truncate(stderr),
37113
+ error: success ? undefined : `Command exited with ${signal ? `signal ${signal}` : `code ${code}`}`
37114
+ });
37115
+ });
37116
+ });
37117
+ }
37118
+ async function dispatchChannel(event, channel, options = {}) {
37119
+ if (channel.transport === "webhook")
37120
+ return dispatchWebhook(event, channel, options);
37121
+ if (channel.transport === "command")
37122
+ return dispatchCommand(event, channel);
37123
+ return {
37124
+ attempt: 1,
37125
+ status: "skipped",
37126
+ startedAt: now(),
37127
+ completedAt: now(),
37128
+ error: `Unsupported transport: ${channel.transport}`
37129
+ };
37130
+ }
37131
+ function createDeliveryResult(event, channel, attempts) {
37132
+ const status = attempts.some((attempt) => attempt.status === "success") ? "success" : attempts.every((attempt) => attempt.status === "skipped") ? "skipped" : "failed";
37133
+ return {
37134
+ id: randomUUID(),
37135
+ eventId: event.id,
37136
+ channelId: channel.id,
37137
+ transport: channel.transport,
37138
+ status,
37139
+ attempts,
37140
+ createdAt: attempts[0]?.startedAt ?? now(),
37141
+ completedAt: attempts.at(-1)?.completedAt ?? now()
37142
+ };
37143
+ }
37144
+ function createEvent(input) {
37145
+ return {
37146
+ id: input.id ?? randomUUID2(),
37147
+ source: input.source,
37148
+ type: input.type,
37149
+ time: normalizeTime(input.time),
37150
+ subject: input.subject,
37151
+ severity: input.severity ?? "info",
37152
+ data: input.data ?? {},
37153
+ message: input.message,
37154
+ dedupeKey: input.dedupeKey,
37155
+ schemaVersion: input.schemaVersion ?? "1.0",
37156
+ metadata: input.metadata ?? {}
37157
+ };
37158
+ }
37159
+
37160
+ class EventsClient {
37161
+ store;
37162
+ redactors;
37163
+ transportOptions;
37164
+ constructor(options = {}) {
37165
+ this.store = options.store ?? new JsonEventsStore(options.dataDir);
37166
+ this.redactors = options.redactors ?? [];
37167
+ this.transportOptions = { fetchImpl: options.fetchImpl };
37168
+ }
37169
+ async addChannel(input) {
37170
+ const timestamp = new Date().toISOString();
37171
+ return this.store.addChannel({
37172
+ ...input,
37173
+ createdAt: input.createdAt ?? timestamp,
37174
+ updatedAt: input.updatedAt ?? timestamp
37175
+ });
37176
+ }
37177
+ async listChannels() {
37178
+ return this.store.listChannels();
37179
+ }
37180
+ async removeChannel(id) {
37181
+ return this.store.removeChannel(id);
37182
+ }
37183
+ async emit(input, options = {}) {
37184
+ const event = options.redactSensitiveData === false ? createEvent(input) : redactSensitiveKeys(createEvent(input));
37185
+ if (options.dedupe !== false) {
37186
+ const existing = await this.store.findEventByIdentity({ id: input.id, dedupeKey: event.dedupeKey });
37187
+ if (existing) {
37188
+ return { event: existing, deliveries: [], deduped: true };
37189
+ }
37190
+ }
37191
+ await this.store.appendEvent(event);
37192
+ const deliveries = options.deliver === false ? [] : await this.deliver(event);
37193
+ return { event, deliveries, deduped: false };
37194
+ }
37195
+ async listEvents() {
37196
+ return this.store.listEvents();
37197
+ }
37198
+ async listDeliveries() {
37199
+ return this.store.listDeliveries();
37200
+ }
37201
+ async deliver(event) {
37202
+ const channels = await this.store.listChannels();
37203
+ const selected = channels.filter((channel) => channelMatchesEvent(channel, event));
37204
+ const deliveries = [];
37205
+ for (const channel of selected) {
37206
+ const eventForChannel = await this.applyRedaction(event, channel);
37207
+ const result = await this.deliverWithRetry(eventForChannel, channel);
37208
+ await this.store.appendDelivery(result);
37209
+ deliveries.push(result);
37210
+ }
37211
+ return deliveries;
37212
+ }
37213
+ async testChannel(id, input = {}) {
37214
+ const channel = await this.store.getChannel(id);
37215
+ if (!channel)
37216
+ throw new Error(`Channel not found: ${id}`);
37217
+ const event = createEvent({
37218
+ source: input.source ?? "hasna.events",
37219
+ type: input.type ?? "events.test",
37220
+ subject: input.subject ?? id,
37221
+ severity: input.severity ?? "info",
37222
+ data: input.data ?? { test: true },
37223
+ message: input.message ?? "Hasna events test delivery",
37224
+ dedupeKey: input.dedupeKey,
37225
+ schemaVersion: input.schemaVersion,
37226
+ metadata: input.metadata,
37227
+ time: input.time,
37228
+ id: input.id
37229
+ });
37230
+ const eventForChannel = await this.applyRedaction(event, channel);
37231
+ const result = await this.deliverWithRetry(eventForChannel, channel);
37232
+ await this.store.appendDelivery(result);
37233
+ return result;
37234
+ }
37235
+ async replay(options = {}) {
37236
+ const events = (await this.store.listEvents()).filter((event) => {
37237
+ if (options.eventId && event.id !== options.eventId)
37238
+ return false;
37239
+ if (options.source && event.source !== options.source)
37240
+ return false;
37241
+ if (options.type && event.type !== options.type)
37242
+ return false;
37243
+ return true;
37244
+ });
37245
+ if (options.dryRun)
37246
+ return { events, deliveries: [] };
37247
+ const deliveries = [];
37248
+ for (const event of events) {
37249
+ deliveries.push(...await this.deliver(event));
37250
+ }
37251
+ return { events, deliveries };
37252
+ }
37253
+ async applyRedaction(event, channel) {
37254
+ let next = redactPaths(event, channel.redact?.paths ?? [], channel.redact?.replacement ?? "[REDACTED]");
37255
+ for (const redactor of this.redactors) {
37256
+ next = await redactor(next, channel);
37257
+ }
37258
+ return next;
37259
+ }
37260
+ async deliverWithRetry(event, channel) {
37261
+ const policy = normalizeRetryPolicy(channel.retry);
37262
+ const attempts = [];
37263
+ for (let index = 0;index < policy.maxAttempts; index += 1) {
37264
+ const attempt = await dispatchChannel(event, channel, this.transportOptions);
37265
+ attempt.attempt = index + 1;
37266
+ if (attempt.status === "failed" && index + 1 < policy.maxAttempts) {
37267
+ attempt.nextBackoffMs = Math.round(policy.backoffMs * policy.multiplier ** index);
37268
+ }
37269
+ attempts.push(attempt);
37270
+ if (attempt.status !== "failed")
37271
+ break;
37272
+ if (attempt.nextBackoffMs)
37273
+ await Bun.sleep(attempt.nextBackoffMs);
37274
+ }
37275
+ return createDeliveryResult(event, channel, attempts);
37276
+ }
37277
+ }
37278
+ function redactPaths(event, paths, replacement = "[REDACTED]") {
37279
+ if (paths.length === 0)
37280
+ return event;
37281
+ const copy = structuredClone(event);
37282
+ for (const path of paths) {
37283
+ setPath(copy, path, replacement);
37284
+ }
37285
+ return copy;
37286
+ }
37287
+ function sanitizeChannelForOutput(channel) {
37288
+ const copy = structuredClone(channel);
37289
+ if (copy.webhook?.secret)
37290
+ copy.webhook.secret = "[REDACTED]";
37291
+ if (copy.command?.env) {
37292
+ copy.command.env = Object.fromEntries(Object.entries(copy.command.env).map(([key, value]) => [key, shouldRedactKey(key) ? "[REDACTED]" : value]));
37293
+ }
37294
+ return copy;
37295
+ }
37296
+ function sanitizeChannelsForOutput(channels) {
37297
+ return channels.map(sanitizeChannelForOutput);
37298
+ }
37299
+ function redactSensitiveKeys(event, replacement = "[REDACTED]") {
37300
+ return redactValue(event, replacement);
37301
+ }
37302
+ function shouldRedactKey(key) {
37303
+ return /secret|token|password|api[_-]?key|authorization/i.test(key);
37304
+ }
37305
+ function redactValue(value, replacement) {
37306
+ if (Array.isArray(value))
37307
+ return value.map((item) => redactValue(item, replacement));
37308
+ if (!value || typeof value !== "object")
37309
+ return value;
37310
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [
37311
+ key,
37312
+ shouldRedactKey(key) ? replacement : redactValue(item, replacement)
37313
+ ]));
37314
+ }
37315
+ function setPath(input, path, replacement) {
37316
+ const parts = path.split(".");
37317
+ let cursor = input;
37318
+ for (const part of parts.slice(0, -1)) {
37319
+ const next = cursor[part];
37320
+ if (!next || typeof next !== "object")
37321
+ return;
37322
+ cursor = next;
37323
+ }
37324
+ const last = parts.at(-1);
37325
+ if (last && last in cursor)
37326
+ cursor[last] = replacement;
37327
+ }
37328
+ function normalizeTime(value) {
37329
+ if (!value)
37330
+ return new Date().toISOString();
37331
+ return value instanceof Date ? value.toISOString() : value;
37332
+ }
37333
+ function normalizeRetryPolicy(policy) {
37334
+ return {
37335
+ maxAttempts: Math.max(1, policy?.maxAttempts ?? 1),
37336
+ backoffMs: Math.max(0, policy?.backoffMs ?? 250),
37337
+ multiplier: Math.max(1, policy?.multiplier ?? 2)
37338
+ };
37339
+ }
37340
+ function parseJsonObject(value, fallback) {
37341
+ if (!value)
37342
+ return fallback;
37343
+ const parsed = JSON.parse(value);
37344
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
37345
+ throw new Error("Expected a JSON object");
37346
+ }
37347
+ return parsed;
37348
+ }
37349
+ function parseHeaders(values) {
37350
+ if (!values?.length)
37351
+ return;
37352
+ const headers = {};
37353
+ for (const value of values) {
37354
+ const separator = value.indexOf("=");
37355
+ if (separator === -1)
37356
+ throw new Error(`Invalid header, expected name=value: ${value}`);
37357
+ headers[value.slice(0, separator)] = value.slice(separator + 1);
37358
+ }
37359
+ return headers;
37360
+ }
37361
+ function parseFilter(options) {
37362
+ const filter2 = {};
37363
+ if (options.source)
37364
+ filter2.source = options.source;
37365
+ if (options.type)
37366
+ filter2.type = options.type;
37367
+ if (options.subject)
37368
+ filter2.subject = options.subject;
37369
+ if (options.severity)
37370
+ filter2.severity = options.severity;
37371
+ return Object.keys(filter2).length > 0 ? [filter2] : undefined;
37372
+ }
37373
+ function createClient(options) {
37374
+ if (options.createClient)
37375
+ return options.createClient();
37376
+ return new EventsClient({ store: new JsonEventsStore(options.dataDir) });
37377
+ }
37378
+ function print(value, json, text) {
37379
+ if (json)
37380
+ console.log(JSON.stringify(value, null, 2));
37381
+ else
37382
+ console.log(text);
37383
+ }
37384
+ function hasJsonOption(options) {
37385
+ return Boolean(options?.json || options?.opts?.().json || options?.optsWithGlobals?.().json || options?.parent?.opts?.().json || options?.parent?.optsWithGlobals?.().json);
37386
+ }
37387
+ function wantsJson(actionOptions, command) {
37388
+ return hasJsonOption(actionOptions) || hasJsonOption(command);
37389
+ }
37390
+ function registerWebhookCommands(program2, options) {
37391
+ const webhooks = program2.command(options.webhooksCommandName ?? "webhooks").description("Manage Hasna event webhook subscriptions");
37392
+ webhooks.command("add").description("Add or replace a webhook or command subscription").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Subscription/channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions, command) => {
37393
+ const timestamp = new Date().toISOString();
37394
+ const channel = {
37395
+ id: actionOptions.id,
37396
+ name: actionOptions.name,
37397
+ enabled: !actionOptions.disabled,
37398
+ transport: actionOptions.transport,
37399
+ filters: parseFilter(actionOptions),
37400
+ retry: actionOptions.retryAttempts || actionOptions.retryBackoffMs ? { maxAttempts: actionOptions.retryAttempts, backoffMs: actionOptions.retryBackoffMs } : undefined,
37401
+ redact: actionOptions.redact?.length ? { paths: actionOptions.redact } : undefined,
37402
+ createdAt: timestamp,
37403
+ updatedAt: timestamp
37404
+ };
37405
+ if (actionOptions.transport === "webhook") {
37406
+ channel.webhook = { url: target, secret: actionOptions.secret, headers: parseHeaders(actionOptions.header), timeoutMs: actionOptions.timeoutMs };
37407
+ } else if (actionOptions.transport === "command") {
37408
+ channel.command = { command: target, args: actionOptions.arg ?? [], timeoutMs: actionOptions.timeoutMs };
37409
+ } else {
37410
+ throw new Error(`Transport ${actionOptions.transport} is reserved for future use and cannot be added yet`);
37411
+ }
37412
+ const saved = await createClient(options).addChannel(channel);
37413
+ print(sanitizeChannelForOutput(saved), wantsJson(actionOptions, command), `Added ${saved.transport} channel ${saved.id}`);
37414
+ });
37415
+ webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
37416
+ const channels = await createClient(options).listChannels();
37417
+ if (wantsJson(actionOptions, command)) {
37418
+ console.log(JSON.stringify(sanitizeChannelsForOutput(channels), null, 2));
37419
+ return;
37420
+ }
37421
+ if (!channels.length) {
37422
+ console.log("No channels configured.");
37423
+ return;
37424
+ }
37425
+ for (const channel of channels) {
37426
+ console.log(`${channel.id} ${channel.enabled ? "enabled" : "disabled"} ${channel.transport} ${channel.webhook?.url ?? channel.command?.command ?? channel.transport}`);
37427
+ }
37428
+ });
37429
+ webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
37430
+ const removed = await createClient(options).removeChannel(id);
37431
+ print({ removed }, wantsJson(actionOptions, command), removed ? `Removed ${id}` : `Channel not found: ${id}`);
37432
+ });
37433
+ webhooks.command("test").description("Send a test event to one subscription").argument("<id>", "Subscription/channel identifier").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
37434
+ const result = await createClient(options).testChannel(id, {
37435
+ source: options.source,
37436
+ type: actionOptions.type,
37437
+ subject: actionOptions.subject ?? id,
37438
+ message: actionOptions.message,
37439
+ data: parseJsonObject(actionOptions.data, { test: true })
37440
+ });
37441
+ print(result, wantsJson(actionOptions, command), `${result.status}: ${result.channelId}`);
37442
+ });
37443
+ return webhooks;
37444
+ }
37445
+ function registerEventCommands(program2, options) {
37446
+ const events = program2.command(options.eventsCommandName ?? "events").description("Emit, list, and replay Hasna events");
37447
+ events.command("emit").description("Emit an event from this app").argument("<type>", "Event type").option("--source <source>", "Event source override").option("--subject <subject>", "Event subject").option("--severity <severity>", "Event severity", "info").option("--message <message>", "Event message").option("--dedupe-key <key>", "Dedupe key").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("--no-deliver", "Record without delivering").option("--no-dedupe", "Allow duplicate id/dedupeKey events").option("-j, --json", "Print JSON output", false).action(async (type, actionOptions, command) => {
37448
+ const result = await createClient(options).emit({
37449
+ source: actionOptions.source ?? options.source,
37450
+ type,
37451
+ subject: actionOptions.subject,
37452
+ severity: actionOptions.severity,
37453
+ message: actionOptions.message,
37454
+ dedupeKey: actionOptions.dedupeKey,
37455
+ data: parseJsonObject(actionOptions.data, {}),
37456
+ metadata: parseJsonObject(actionOptions.metadata, {})
37457
+ }, { deliver: actionOptions.deliver, dedupe: actionOptions.dedupe });
37458
+ print(result, wantsJson(actionOptions, command), `${result.deduped ? "Deduped" : "Emitted"} ${result.event.id} to ${result.deliveries.length} channel(s)`);
37459
+ });
37460
+ events.command("list").description("List recorded events").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--limit <n>", "Limit results", parseNumber).option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
37461
+ let rows = await createClient(options).listEvents();
37462
+ if (actionOptions.source)
37463
+ rows = rows.filter((event) => event.source === actionOptions.source);
37464
+ if (actionOptions.type)
37465
+ rows = rows.filter((event) => event.type === actionOptions.type);
37466
+ if (actionOptions.limit)
37467
+ rows = rows.slice(-actionOptions.limit);
37468
+ if (wantsJson(actionOptions, command)) {
37469
+ console.log(JSON.stringify(rows, null, 2));
37470
+ return;
37471
+ }
37472
+ if (!rows.length) {
37473
+ console.log("No events recorded.");
37474
+ return;
37475
+ }
37476
+ for (const event of rows)
37477
+ console.log(`${event.time} ${event.id} ${event.source} ${event.type} ${event.severity}`);
37478
+ });
37479
+ events.command("replay").description("Replay recorded events").option("--id <id>", "Replay one event id").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--dry-run", "Preview without delivery", false).option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
37480
+ const result = await createClient(options).replay({
37481
+ eventId: actionOptions.id,
37482
+ source: actionOptions.source,
37483
+ type: actionOptions.type,
37484
+ dryRun: actionOptions.dryRun
37485
+ });
37486
+ print(result, wantsJson(actionOptions, command), `Replayed ${result.events.length} event(s), ${result.deliveries.length} delivery result(s)`);
37487
+ });
37488
+ return events;
37489
+ }
37490
+ function registerEventsCommands(program2, options) {
37491
+ registerWebhookCommands(program2, options);
37492
+ registerEventCommands(program2, options);
37493
+ }
37494
+ function parseNumber(value) {
37495
+ const parsed = Number(value);
37496
+ if (!Number.isFinite(parsed))
37497
+ throw new Error(`Expected a number, got ${value}`);
37498
+ return parsed;
37499
+ }
37500
+ function collectValues(value, previous) {
37501
+ previous.push(value);
37502
+ return previous;
37503
+ }
37504
+
36821
37505
  // node_modules/chalk/source/vendor/ansi-styles/index.js
36822
37506
  var ANSI_BACKGROUND_OFFSET = 10;
36823
37507
  var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
@@ -41321,20 +42005,20 @@ class AccountsError extends Error {
41321
42005
  }
41322
42006
 
41323
42007
  // src/lib/tools.ts
41324
- import { homedir as homedir2 } from "node:os";
41325
- import { join as join2 } from "node:path";
42008
+ import { homedir as homedir3 } from "node:os";
42009
+ import { join as join3 } from "node:path";
41326
42010
 
41327
42011
  // src/storage.ts
41328
- import { homedir } from "node:os";
42012
+ import { homedir as homedir2 } from "node:os";
41329
42013
  import { hostname } from "node:os";
41330
- import { join } from "node:path";
41331
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "node:fs";
42014
+ import { join as join2 } from "node:path";
42015
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "node:fs";
41332
42016
 
41333
42017
  // src/lib/safe-path.ts
41334
- import { existsSync, lstatSync, mkdirSync, realpathSync } from "node:fs";
42018
+ import { existsSync as existsSync2, lstatSync, mkdirSync, realpathSync } from "node:fs";
41335
42019
  import { dirname, resolve } from "node:path";
41336
42020
  function throwIfSymlink(path, label) {
41337
- if (existsSync(path) && lstatSync(path).isSymbolicLink()) {
42021
+ if (existsSync2(path) && lstatSync(path).isSymbolicLink()) {
41338
42022
  throw new AccountsError(`${label}: ${path}`);
41339
42023
  }
41340
42024
  }
@@ -41370,11 +42054,11 @@ function assertDirChainSafe(targetFile, mustStayUnder) {
41370
42054
  function assertSafeWritePath(filePath, opts) {
41371
42055
  const absFile = resolve(filePath);
41372
42056
  const parent = dirname(absFile);
41373
- if (!existsSync(parent))
42057
+ if (!existsSync2(parent))
41374
42058
  mkdirSync(parent, { recursive: true });
41375
42059
  throwIfSymlink(absFile, "refusing to write through symlink");
41376
42060
  assertDirChainSafe(absFile, opts?.mustStayUnder);
41377
- const resolved = realpathSync(existsSync(absFile) ? absFile : parent);
42061
+ const resolved = realpathSync(existsSync2(absFile) ? absFile : parent);
41378
42062
  if (opts?.mustStayUnder) {
41379
42063
  const base = realpathSync(resolve(opts.mustStayUnder));
41380
42064
  if (resolved !== base && !resolved.startsWith(base + "/")) {
@@ -41416,21 +42100,21 @@ function accountsHome() {
41416
42100
  const override = process.env.ACCOUNTS_HOME;
41417
42101
  if (override && override.trim())
41418
42102
  return validateEnvPath(override, "ACCOUNTS_HOME");
41419
- return join(homedir(), ".hasna", "accounts");
42103
+ return join2(homedir2(), ".hasna", "accounts");
41420
42104
  }
41421
42105
  function storePath() {
41422
42106
  const override = process.env.ACCOUNTS_STORE_PATH;
41423
42107
  if (override && override.trim())
41424
42108
  return validateEnvPath(override, "ACCOUNTS_STORE_PATH");
41425
- return join(accountsHome(), "accounts.json");
42109
+ return join2(accountsHome(), "accounts.json");
41426
42110
  }
41427
42111
  function profilesDir() {
41428
- return join(accountsHome(), "profiles");
42112
+ return join2(accountsHome(), "profiles");
41429
42113
  }
41430
42114
  var EMPTY_STORE = { version: 1, current: {}, applied: {}, profiles: [], tools: [] };
41431
42115
  function loadStore() {
41432
42116
  const path = storePath();
41433
- if (!existsSync2(path))
42117
+ if (!existsSync3(path))
41434
42118
  return structuredClone(EMPTY_STORE);
41435
42119
  let raw;
41436
42120
  try {
@@ -41468,7 +42152,7 @@ function loadStore() {
41468
42152
  function saveStore(store) {
41469
42153
  const path = storePath();
41470
42154
  assertSafeWritePath(path, { mustStayUnder: accountsHome() });
41471
- mkdirSync2(join(path, ".."), { recursive: true });
42155
+ mkdirSync2(join2(path, ".."), { recursive: true });
41472
42156
  writeFileSync(path, JSON.stringify(store, null, 2) + `
41473
42157
  `, { mode: 384 });
41474
42158
  }
@@ -41616,7 +42300,7 @@ var BUILTIN_TOOLS = [
41616
42300
  id: "claude",
41617
42301
  label: "Claude Code",
41618
42302
  envVar: "CLAUDE_CONFIG_DIR",
41619
- defaultDir: join2(homedir2(), ".claude"),
42303
+ defaultDir: join3(homedir3(), ".claude"),
41620
42304
  bin: "claude",
41621
42305
  loginHint: "run /login inside Claude, then /exit when done",
41622
42306
  resumeArgs: ["--continue"],
@@ -41627,7 +42311,7 @@ var BUILTIN_TOOLS = [
41627
42311
  id: "codex",
41628
42312
  label: "Codex CLI",
41629
42313
  envVar: "CODEX_HOME",
41630
- defaultDir: join2(homedir2(), ".codex"),
42314
+ defaultDir: join3(homedir3(), ".codex"),
41631
42315
  bin: "codex",
41632
42316
  loginArgs: ["login"],
41633
42317
  loginHint: "complete the Codex login flow for this CODEX_HOME",
@@ -41637,7 +42321,7 @@ var BUILTIN_TOOLS = [
41637
42321
  id: "takumi",
41638
42322
  label: "Takumi",
41639
42323
  envVar: "TAKUMI_CONFIG_DIR",
41640
- defaultDir: join2(homedir2(), ".takumi"),
42324
+ defaultDir: join3(homedir3(), ".takumi"),
41641
42325
  bin: "takumi",
41642
42326
  loginHint: "complete Takumi auth in this TAKUMI_CONFIG_DIR",
41643
42327
  resumeArgs: ["--continue"],
@@ -41648,7 +42332,7 @@ var BUILTIN_TOOLS = [
41648
42332
  id: "gemini",
41649
42333
  label: "Gemini CLI",
41650
42334
  envVar: "GEMINI_CONFIG_DIR",
41651
- defaultDir: join2(homedir2(), ".gemini"),
42335
+ defaultDir: join3(homedir3(), ".gemini"),
41652
42336
  bin: "gemini",
41653
42337
  loginHint: "complete Gemini auth in this GEMINI_CONFIG_DIR"
41654
42338
  },
@@ -41660,7 +42344,7 @@ var BUILTIN_TOOLS = [
41660
42344
  XDG_CONFIG_HOME: "{profileDir}/xdg-config",
41661
42345
  XDG_DATA_HOME: "{profileDir}/xdg-data"
41662
42346
  },
41663
- defaultDir: join2(homedir2(), ".config", "opencode"),
42347
+ defaultDir: join3(homedir3(), ".config", "opencode"),
41664
42348
  bin: "opencode",
41665
42349
  loginArgs: ["auth", "login"],
41666
42350
  loginHint: "complete opencode auth login for this isolated config/data root",
@@ -41670,7 +42354,7 @@ var BUILTIN_TOOLS = [
41670
42354
  id: "cursor",
41671
42355
  label: "Cursor Agent",
41672
42356
  envVar: "CURSOR_CONFIG_DIR",
41673
- defaultDir: join2(homedir2(), ".cursor"),
42357
+ defaultDir: join3(homedir3(), ".cursor"),
41674
42358
  bin: "cursor-agent",
41675
42359
  loginArgs: ["login"],
41676
42360
  loginHint: "complete cursor-agent login for this CURSOR_CONFIG_DIR"
@@ -41679,7 +42363,7 @@ var BUILTIN_TOOLS = [
41679
42363
  id: "pi",
41680
42364
  label: "Pi Coding Agent",
41681
42365
  envVar: "PI_CODING_AGENT_HOME",
41682
- defaultDir: join2(homedir2(), ".pi"),
42366
+ defaultDir: join3(homedir3(), ".pi"),
41683
42367
  bin: "pi",
41684
42368
  loginHint: "complete Pi coding agent auth in this PI_CODING_AGENT_HOME"
41685
42369
  },
@@ -41687,7 +42371,7 @@ var BUILTIN_TOOLS = [
41687
42371
  id: "hermes",
41688
42372
  label: "Hermes",
41689
42373
  envVar: "HERMES_HOME",
41690
- defaultDir: join2(homedir2(), ".hermes"),
42374
+ defaultDir: join3(homedir3(), ".hermes"),
41691
42375
  bin: "hermes",
41692
42376
  loginHint: "complete Hermes auth in this HERMES_HOME"
41693
42377
  },
@@ -41695,7 +42379,7 @@ var BUILTIN_TOOLS = [
41695
42379
  id: "kimi",
41696
42380
  label: "Kimi Code",
41697
42381
  envVar: "KIMI_CODE_HOME",
41698
- defaultDir: join2(homedir2(), ".kimi-code"),
42382
+ defaultDir: join3(homedir3(), ".kimi-code"),
41699
42383
  bin: "kimi",
41700
42384
  loginArgs: ["login"],
41701
42385
  loginHint: "complete kimi login for this KIMI_CODE_HOME"
@@ -41704,7 +42388,7 @@ var BUILTIN_TOOLS = [
41704
42388
  id: "grok",
41705
42389
  label: "Grok Build",
41706
42390
  envVar: "HOME",
41707
- defaultDir: join2(homedir2(), ".grok"),
42391
+ defaultDir: join3(homedir3(), ".grok"),
41708
42392
  bin: "grok",
41709
42393
  loginArgs: ["login"],
41710
42394
  loginHint: "complete grok login in this process-scoped HOME; prefer launch/shell over exporting HOME globally"
@@ -41765,19 +42449,19 @@ function removeCustomTool(id) {
41765
42449
  }
41766
42450
 
41767
42451
  // src/lib/profiles.ts
41768
- import { homedir as homedir3 } from "node:os";
41769
- import { isAbsolute, join as join4, resolve as resolve2 } from "node:path";
41770
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, rmSync } from "node:fs";
42452
+ import { homedir as homedir4 } from "node:os";
42453
+ import { isAbsolute, join as join5, resolve as resolve2 } from "node:path";
42454
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, rmSync } from "node:fs";
41771
42455
 
41772
42456
  // src/lib/detect.ts
41773
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
41774
- import { dirname as dirname2, join as join3 } from "node:path";
42457
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
42458
+ import { dirname as dirname2, join as join4 } from "node:path";
41775
42459
  function detectEmail(dir, tool) {
41776
42460
  if (!tool.accountFile || !tool.emailPath)
41777
42461
  return;
41778
- const candidates = [join3(dir, tool.accountFile)];
42462
+ const candidates = [join4(dir, tool.accountFile)];
41779
42463
  if (dir === tool.defaultDir)
41780
- candidates.push(join3(dirname2(dir), tool.accountFile));
42464
+ candidates.push(join4(dirname2(dir), tool.accountFile));
41781
42465
  for (const file of candidates) {
41782
42466
  const email = readEmail(file, tool.emailPath);
41783
42467
  if (email)
@@ -41786,7 +42470,7 @@ function detectEmail(dir, tool) {
41786
42470
  return;
41787
42471
  }
41788
42472
  function readEmail(file, path) {
41789
- if (!existsSync3(file))
42473
+ if (!existsSync4(file))
41790
42474
  return;
41791
42475
  let cursor;
41792
42476
  try {
@@ -41811,9 +42495,9 @@ function nowIso() {
41811
42495
  function expandPath(p) {
41812
42496
  let out = p;
41813
42497
  if (out === "~")
41814
- out = homedir3();
42498
+ out = homedir4();
41815
42499
  else if (out.startsWith("~/"))
41816
- out = join4(homedir3(), out.slice(2));
42500
+ out = join5(homedir4(), out.slice(2));
41817
42501
  return isAbsolute(out) ? out : resolve2(process.cwd(), out);
41818
42502
  }
41819
42503
  function listProfiles(toolId) {
@@ -41847,7 +42531,7 @@ function addProfile(opts) {
41847
42531
  if (store.profiles.some((p) => p.name === name && p.tool === toolId)) {
41848
42532
  throw new AccountsError(`a ${toolId} profile named "${name}" already exists`);
41849
42533
  }
41850
- const dir = opts.dir ? expandPath(opts.dir) : join4(profilesDir(), toolId, name);
42534
+ const dir = opts.dir ? expandPath(opts.dir) : join5(profilesDir(), toolId, name);
41851
42535
  if (store.profiles.some((p) => p.dir === dir)) {
41852
42536
  throw new AccountsError(`a profile already uses config dir ${dir}`);
41853
42537
  }
@@ -41889,7 +42573,7 @@ function removeProfile(name, opts = {}) {
41889
42573
  if (options.purge) {
41890
42574
  const managed = profile.dir.startsWith(profilesDir());
41891
42575
  const isDefault = profile.dir === getTool(profile.tool).defaultDir;
41892
- if (managed && !isDefault && existsSync4(profile.dir)) {
42576
+ if (managed && !isDefault && existsSync5(profile.dir)) {
41893
42577
  rmSync(profile.dir, { recursive: true, force: true });
41894
42578
  purged = true;
41895
42579
  } else {
@@ -41988,12 +42672,12 @@ function currentProfile(toolId) {
41988
42672
  }
41989
42673
 
41990
42674
  // src/lib/claude-auth.ts
41991
- import { copyFileSync, existsSync as existsSync5, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync3, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
41992
- import { dirname as dirname4, join as join6 } from "node:path";
42675
+ import { copyFileSync, existsSync as existsSync6, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync3, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
42676
+ import { dirname as dirname4, join as join7 } from "node:path";
41993
42677
 
41994
42678
  // src/lib/claude-layout.ts
41995
- import { homedir as homedir4 } from "node:os";
41996
- import { dirname as dirname3, join as join5 } from "node:path";
42679
+ import { homedir as homedir5 } from "node:os";
42680
+ import { dirname as dirname3, join as join6 } from "node:path";
41997
42681
  var CLAUDE_KEYCHAIN_SERVICE = "Claude Code-credentials";
41998
42682
  var ACCOUNTS_AUTH_DIR = ".accounts-auth";
41999
42683
  var OAUTH_SNAPSHOT = "oauth-account.json";
@@ -42001,36 +42685,36 @@ var CREDENTIALS_SNAPSHOT = "credentials.json";
42001
42685
  var KEYCHAIN_SNAPSHOT = "keychain.json";
42002
42686
  function liveClaudeBase() {
42003
42687
  const testBase = process.env.ACCOUNTS_TEST_LIVE_DIR;
42004
- return testBase && testBase.trim() ? testBase : homedir4();
42688
+ return testBase && testBase.trim() ? testBase : homedir5();
42005
42689
  }
42006
42690
  function liveClaudePaths() {
42007
42691
  const base = liveClaudeBase();
42008
- const configDir = join5(base, ".claude");
42692
+ const configDir = join6(base, ".claude");
42009
42693
  return {
42010
42694
  configDir,
42011
- homeJson: join5(base, ".claude.json"),
42012
- credentialsFile: join5(configDir, ".credentials.json")
42695
+ homeJson: join6(base, ".claude.json"),
42696
+ credentialsFile: join6(configDir, ".credentials.json")
42013
42697
  };
42014
42698
  }
42015
42699
  function profileAccountJsonPaths(profileDir, tool) {
42016
42700
  if (!tool.accountFile)
42017
42701
  return [];
42018
- const paths = [join5(profileDir, tool.accountFile)];
42702
+ const paths = [join6(profileDir, tool.accountFile)];
42019
42703
  if (profileDir === tool.defaultDir)
42020
- paths.push(join5(dirname3(profileDir), tool.accountFile));
42704
+ paths.push(join6(dirname3(profileDir), tool.accountFile));
42021
42705
  return paths;
42022
42706
  }
42023
42707
  function profileAuthDir(profileDir) {
42024
- return join5(profileDir, ACCOUNTS_AUTH_DIR);
42708
+ return join6(profileDir, ACCOUNTS_AUTH_DIR);
42025
42709
  }
42026
42710
  function profileOAuthSnapshot(profileDir) {
42027
- return join5(profileAuthDir(profileDir), OAUTH_SNAPSHOT);
42711
+ return join6(profileAuthDir(profileDir), OAUTH_SNAPSHOT);
42028
42712
  }
42029
42713
  function profileCredentialsSnapshot(profileDir) {
42030
- return join5(profileAuthDir(profileDir), CREDENTIALS_SNAPSHOT);
42714
+ return join6(profileAuthDir(profileDir), CREDENTIALS_SNAPSHOT);
42031
42715
  }
42032
42716
  function profileKeychainSnapshot(profileDir) {
42033
- return join5(profileAuthDir(profileDir), KEYCHAIN_SNAPSHOT);
42717
+ return join6(profileAuthDir(profileDir), KEYCHAIN_SNAPSHOT);
42034
42718
  }
42035
42719
 
42036
42720
  // src/lib/keychain.ts
@@ -42095,7 +42779,7 @@ function writeClaudeKeychain(cred) {
42095
42779
 
42096
42780
  // src/lib/claude-auth.ts
42097
42781
  function readJsonFile(path) {
42098
- if (!existsSync5(path))
42782
+ if (!existsSync6(path))
42099
42783
  return;
42100
42784
  try {
42101
42785
  return JSON.parse(readFileSync3(path, "utf8"));
@@ -42122,7 +42806,7 @@ function findOAuthSource(paths) {
42122
42806
  return;
42123
42807
  }
42124
42808
  function snapshotIsStale(sourcePath, snapshotPath) {
42125
- if (!existsSync5(snapshotPath))
42809
+ if (!existsSync6(snapshotPath))
42126
42810
  return true;
42127
42811
  try {
42128
42812
  return statSync(sourcePath).mtimeMs > statSync(snapshotPath).mtimeMs;
@@ -42161,13 +42845,13 @@ function liveOAuthEmail() {
42161
42845
  }
42162
42846
  function snapshotLiveAuthToProfile(profileDir, _tool) {
42163
42847
  const authDir = profileAuthDir(profileDir);
42164
- assertSafeWritePath(join6(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
42848
+ assertSafeWritePath(join7(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
42165
42849
  mkdirSync4(authDir, { recursive: true });
42166
42850
  const live = liveClaudePaths();
42167
42851
  const oauth = readOAuthFromPaths([live.homeJson]);
42168
42852
  if (oauth)
42169
42853
  writeJsonFile(profileOAuthSnapshot(profileDir), { oauthAccount: oauth }, profileDir);
42170
- if (existsSync5(live.credentialsFile)) {
42854
+ if (existsSync6(live.credentialsFile)) {
42171
42855
  const dest = profileCredentialsSnapshot(profileDir);
42172
42856
  assertSafeWritePath(dest, { mustStayUnder: profileDir });
42173
42857
  copyFileSync(live.credentialsFile, dest);
@@ -42180,16 +42864,16 @@ function snapshotLiveAuthToProfile(profileDir, _tool) {
42180
42864
  }
42181
42865
  function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
42182
42866
  const authDir = profileAuthDir(profileDir);
42183
- assertSafeWritePath(join6(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
42867
+ assertSafeWritePath(join7(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
42184
42868
  mkdirSync4(authDir, { recursive: true });
42185
42869
  const oauthSource = findOAuthSource(profileAccountJsonPaths(profileDir, tool));
42186
42870
  const oauthSnap = profileOAuthSnapshot(profileDir);
42187
42871
  if (oauthSource && (opts.overwrite || snapshotIsStale(oauthSource.path, oauthSnap))) {
42188
42872
  writeJsonFile(oauthSnap, { oauthAccount: oauthSource.oauth }, profileDir);
42189
42873
  }
42190
- const credFile = join6(profileDir, ".credentials.json");
42874
+ const credFile = join7(profileDir, ".credentials.json");
42191
42875
  const credSnap = profileCredentialsSnapshot(profileDir);
42192
- if (existsSync5(credFile) && (opts.overwrite || snapshotIsStale(credFile, credSnap))) {
42876
+ if (existsSync6(credFile) && (opts.overwrite || snapshotIsStale(credFile, credSnap))) {
42193
42877
  assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
42194
42878
  copyFileSync(credFile, credSnap);
42195
42879
  }
@@ -42214,12 +42898,12 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
42214
42898
  assertSafeWritePath(live.homeJson, { mustStayUnder: liveRoot });
42215
42899
  mergeOAuthInto([live.homeJson], oauth, false, liveRoot);
42216
42900
  const credSnap = profileCredentialsSnapshot(profileDir);
42217
- if (existsSync5(credSnap)) {
42901
+ if (existsSync6(credSnap)) {
42218
42902
  assertSafeWritePath(live.credentialsFile, { mustStayUnder: liveRoot });
42219
42903
  assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
42220
42904
  copyFileSync(credSnap, live.credentialsFile);
42221
42905
  writeFileSync2(live.credentialsFile, readFileSync3(live.credentialsFile), { mode: 384 });
42222
- } else if (existsSync5(live.credentialsFile)) {
42906
+ } else if (existsSync6(live.credentialsFile)) {
42223
42907
  if (!lstatSync2(live.credentialsFile).isSymbolicLink())
42224
42908
  unlinkSync(live.credentialsFile);
42225
42909
  }
@@ -42241,14 +42925,14 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
42241
42925
  }
42242
42926
  }
42243
42927
  function hasAuthSnapshot(profileDir) {
42244
- return existsSync5(profileOAuthSnapshot(profileDir)) || existsSync5(profileCredentialsSnapshot(profileDir)) || existsSync5(profileKeychainSnapshot(profileDir));
42928
+ return existsSync6(profileOAuthSnapshot(profileDir)) || existsSync6(profileCredentialsSnapshot(profileDir)) || existsSync6(profileKeychainSnapshot(profileDir));
42245
42929
  }
42246
42930
 
42247
42931
  // src/lib/apply-lock.ts
42248
- import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync5, openSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
42249
- import { join as join7 } from "node:path";
42932
+ import { closeSync, existsSync as existsSync7, mkdirSync as mkdirSync5, openSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
42933
+ import { join as join8 } from "node:path";
42250
42934
  function lockPath() {
42251
- return join7(accountsHome(), ".apply.lock");
42935
+ return join8(accountsHome(), ".apply.lock");
42252
42936
  }
42253
42937
  function withApplyLock(fn) {
42254
42938
  const home = accountsHome();
@@ -42273,7 +42957,7 @@ function withApplyLock(fn) {
42273
42957
  if (fd !== undefined) {
42274
42958
  closeSync(fd);
42275
42959
  try {
42276
- if (existsSync6(path))
42960
+ if (existsSync7(path))
42277
42961
  unlinkSync2(path);
42278
42962
  } catch {}
42279
42963
  }
@@ -42319,7 +43003,7 @@ function applyProfileUnlocked(name, toolId) {
42319
43003
 
42320
43004
  // src/lib/agents.ts
42321
43005
  import { spawnSync } from "node:child_process";
42322
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
43006
+ import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
42323
43007
  import { platform as platform2 } from "node:os";
42324
43008
  function extractJsonArray(raw) {
42325
43009
  const text = raw.replace(/\r/g, "");
@@ -42446,7 +43130,7 @@ function listAgentsAcrossProfiles(opts = {}) {
42446
43130
  const registered = listProfiles(toolId);
42447
43131
  const entries = [...registered];
42448
43132
  const defaultDir = opts.defaultDir ?? tool.defaultDir;
42449
- if (defaultDir && !registered.some((p) => p.dir === defaultDir) && existsSync7(defaultDir)) {
43133
+ if (defaultDir && !registered.some((p) => p.dir === defaultDir) && existsSync8(defaultDir)) {
42450
43134
  entries.unshift({ name: "(default)", tool: toolId, dir: defaultDir });
42451
43135
  }
42452
43136
  const wanted = entries.filter((p) => !opts.profile || p.name === opts.profile || opts.profile === "default" && p.name === "(default)");
@@ -42496,19 +43180,19 @@ function listAgentsAcrossProfiles(opts = {}) {
42496
43180
  }
42497
43181
 
42498
43182
  // src/lib/import-profile.ts
42499
- import { cpSync, existsSync as existsSync8 } from "node:fs";
42500
- import { join as join8 } from "node:path";
43183
+ import { cpSync, existsSync as existsSync9 } from "node:fs";
43184
+ import { join as join9 } from "node:path";
42501
43185
  function importProfile(opts) {
42502
43186
  const toolId = opts.tool ?? DEFAULT_TOOL;
42503
43187
  const tool = getTool(toolId);
42504
43188
  const name = opts.name ?? "main";
42505
43189
  const sourceDir = opts.dir ? expandPath(opts.dir) : tool.defaultDir;
42506
- if (!existsSync8(sourceDir)) {
43190
+ if (!existsSync9(sourceDir)) {
42507
43191
  throw new AccountsError(`config dir does not exist: ${sourceDir}`);
42508
43192
  }
42509
43193
  if (opts.copy) {
42510
- const targetDir = join8(profilesDir(), toolId, name);
42511
- if (existsSync8(targetDir)) {
43194
+ const targetDir = join9(profilesDir(), toolId, name);
43195
+ if (existsSync9(targetDir)) {
42512
43196
  throw new AccountsError(`managed copy target already exists: ${targetDir}`);
42513
43197
  }
42514
43198
  cpSync(sourceDir, targetDir, { recursive: true });
@@ -42592,8 +43276,8 @@ async function pickProfile(opts = {}) {
42592
43276
  }
42593
43277
 
42594
43278
  // src/lib/hook.ts
42595
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
42596
- import { join as join9 } from "node:path";
43279
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
43280
+ import { join as join10 } from "node:path";
42597
43281
  var HOOK_FILE = "claude-hook.sh";
42598
43282
  var MARKER = "# accounts-claude-hook";
42599
43283
  var NAME_PATTERN = "^[a-z0-9][a-z0-9-]*$";
@@ -42601,7 +43285,7 @@ function shellQuotePath(path) {
42601
43285
  return `'${path.replace(/'/g, `'\\''`)}'`;
42602
43286
  }
42603
43287
  function hookPath() {
42604
- return join9(accountsHome(), HOOK_FILE);
43288
+ return join10(accountsHome(), HOOK_FILE);
42605
43289
  }
42606
43290
  function hookScript() {
42607
43291
  const quotedHook = shellQuotePath(hookPath());
@@ -42632,13 +43316,13 @@ claude() {
42632
43316
  function installHook() {
42633
43317
  const path = hookPath();
42634
43318
  mkdirSync6(accountsHome(), { recursive: true });
42635
- const created = !existsSync9(path);
43319
+ const created = !existsSync10(path);
42636
43320
  writeFileSync4(path, hookScript(), { mode: 493 });
42637
43321
  return { path, created };
42638
43322
  }
42639
43323
  function uninstallHook() {
42640
43324
  const path = hookPath();
42641
- if (!existsSync9(path))
43325
+ if (!existsSync10(path))
42642
43326
  return false;
42643
43327
  const content = readFileSync5(path, "utf8");
42644
43328
  if (!content.includes(MARKER))
@@ -42730,24 +43414,24 @@ function switchProfile(name, opts = {}) {
42730
43414
  }
42731
43415
 
42732
43416
  // src/lib/supervisor.ts
42733
- import { spawn } from "node:child_process";
43417
+ import { spawn as spawn2 } from "node:child_process";
42734
43418
  import { createHash } from "node:crypto";
42735
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync6, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
43419
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync6, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
42736
43420
  import { createConnection, createServer } from "node:net";
42737
- import { basename, join as join10 } from "node:path";
43421
+ import { basename, join as join11 } from "node:path";
42738
43422
  var STATE_SUFFIX = ".json";
42739
43423
  function supervisorDir() {
42740
- return join10(accountsHome(), "supervisors");
43424
+ return join11(accountsHome(), "supervisors");
42741
43425
  }
42742
43426
  function supervisorStatePath(toolId) {
42743
- return join10(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
43427
+ return join11(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
42744
43428
  }
42745
43429
  function supervisorSocketPath(toolId) {
42746
43430
  if (process.platform === "win32") {
42747
43431
  const hash = createHash("sha1").update(accountsHome()).digest("hex").slice(0, 12);
42748
43432
  return `\\\\.\\pipe\\hasna-accounts-${hash}-${toolId}`;
42749
43433
  }
42750
- return join10(supervisorDir(), `${toolId}.sock`);
43434
+ return join11(supervisorDir(), `${toolId}.sock`);
42751
43435
  }
42752
43436
  function nowIso2() {
42753
43437
  return new Date().toISOString();
@@ -42761,7 +43445,7 @@ function parseState(raw) {
42761
43445
  }
42762
43446
  function readSupervisorState(toolId) {
42763
43447
  const path = supervisorStatePath(toolId);
42764
- if (!existsSync10(path))
43448
+ if (!existsSync11(path))
42765
43449
  return;
42766
43450
  try {
42767
43451
  return parseState(readFileSync6(path, "utf8"));
@@ -42771,7 +43455,7 @@ function readSupervisorState(toolId) {
42771
43455
  }
42772
43456
  function listSupervisorStates() {
42773
43457
  const dir = supervisorDir();
42774
- if (!existsSync10(dir))
43458
+ if (!existsSync11(dir))
42775
43459
  return [];
42776
43460
  return readdirSync(dir).filter((name) => name.endsWith(STATE_SUFFIX)).map((name) => basename(name, STATE_SUFFIX)).map((toolId) => readSupervisorState(toolId)).filter((state) => state !== undefined);
42777
43461
  }
@@ -42994,7 +43678,7 @@ async function runSupervisedTool(initialProfile, tool, initialArgs = [], opts =
42994
43678
  useProfile(profile.name, tool.id);
42995
43679
  const env2 = profileEnv(profile, tool);
42996
43680
  log(`accounts supervisor: starting ${tool.bin} for ${profile.name}`);
42997
- const proc = spawn(tool.bin, childArgs, {
43681
+ const proc = spawn2(tool.bin, childArgs, {
42998
43682
  stdio: opts.stdio ?? "inherit",
42999
43683
  env: { ...process.env, ...env2, ACCOUNTS_SUPERVISOR: "1", ACCOUNTS_ACTIVE: profile.name },
43000
43684
  detached: process.platform !== "win32"
@@ -43178,7 +43862,7 @@ program2.command("show").argument("<name>", "profile name").description("show fu
43178
43862
  console.log(` tool: ${p.tool} (${getTool(p.tool).label})`);
43179
43863
  console.log(` active: ${active ? source_default.green("yes") : source_default.dim("no")}`);
43180
43864
  console.log(` applied: ${isApplied ? source_default.magenta("yes") : source_default.dim("no")}`);
43181
- console.log(` config dir: ${p.dir}${existsSync11(p.dir) ? "" : source_default.red(" [missing]")}`);
43865
+ console.log(` config dir: ${p.dir}${existsSync12(p.dir) ? "" : source_default.red(" [missing]")}`);
43182
43866
  console.log(` email: ${p.email ?? source_default.dim("(none)")}`);
43183
43867
  console.log(` created: ${p.createdAt}`);
43184
43868
  if (p.lastUsedAt)
@@ -43316,7 +44000,7 @@ program2.command("switch").argument("<name>", "profile name").argument("[args...
43316
44000
  }
43317
44001
  }));
43318
44002
  var hook = program2.command("hook").description("install a shell wrapper for claude");
43319
- hook.command("install").description(`write ${join11(accountsHome(), "claude-hook.sh")}`).action(action(() => {
44003
+ hook.command("install").description(`write ${join12(accountsHome(), "claude-hook.sh")}`).action(action(() => {
43320
44004
  const { path, created } = installHook();
43321
44005
  console.log(source_default.green(created ? `✓ installed hook at ${path}` : `✓ updated hook at ${path}`));
43322
44006
  console.log(source_default.dim(` add to ~/.zshrc: ${shellSnippet()}`));
@@ -43541,7 +44225,7 @@ tools.command("add").argument("<id>", "tool id, e.g. cursor").description("regis
43541
44225
  label: opts.label,
43542
44226
  envVar: opts.envVar,
43543
44227
  bin: opts.bin,
43544
- defaultDir: opts.defaultDir ? expandPath(opts.defaultDir) : join11(homedir5(), `.${id}`),
44228
+ defaultDir: opts.defaultDir ? expandPath(opts.defaultDir) : join12(homedir6(), `.${id}`),
43545
44229
  ...Object.keys(extraEnv).length > 0 ? { extraEnv } : {},
43546
44230
  ...opts.loginArg ? { loginArgs: opts.loginArg } : {},
43547
44231
  ...opts.resumeArg ? { resumeArgs: opts.resumeArg } : {},
@@ -43562,7 +44246,7 @@ program2.command("doctor").description("check the store and profile dirs for pro
43562
44246
  const profiles = listProfiles();
43563
44247
  let problems = 0;
43564
44248
  for (const p of profiles) {
43565
- const missing = !existsSync11(p.dir);
44249
+ const missing = !existsSync12(p.dir);
43566
44250
  const noEmail = !p.email;
43567
44251
  if (missing) {
43568
44252
  console.log(source_default.red(` ✗ ${p.name}: config dir missing (${p.dir})`));
@@ -43606,12 +44290,13 @@ ${problems} problem(s) found.`));
43606
44290
  console.log(source_default.green(`
43607
44291
  healthy.`));
43608
44292
  }));
44293
+ registerEventsCommands(program2, { source: "accounts" });
43609
44294
  program2.parseAsync(process.argv);
43610
44295
  function getVersion() {
43611
44296
  try {
43612
44297
  const here = dirname5(fileURLToPath(import.meta.url));
43613
- for (const candidate of [join11(here, "..", "package.json"), join11(here, "package.json")]) {
43614
- if (existsSync11(candidate)) {
44298
+ for (const candidate of [join12(here, "..", "package.json"), join12(here, "package.json")]) {
44299
+ if (existsSync12(candidate)) {
43615
44300
  const pkg = JSON.parse(readFileSync7(candidate, "utf8"));
43616
44301
  if (pkg.version)
43617
44302
  return pkg.version;