@merittdev/horus 0.15.2 → 0.16.0

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/index.cjs +1265 -618
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -8167,27 +8167,27 @@ var require_bson = __commonJS({
8167
8167
  return new _Long(lowBits, highBits, unsigned);
8168
8168
  }
8169
8169
  static fromInt(value, unsigned) {
8170
- let obj, cachedObj, cache;
8170
+ let obj, cachedObj, cache2;
8171
8171
  if (unsigned) {
8172
8172
  value >>>= 0;
8173
- if (cache = 0 <= value && value < 256) {
8173
+ if (cache2 = 0 <= value && value < 256) {
8174
8174
  cachedObj = UINT_CACHE[value];
8175
8175
  if (cachedObj)
8176
8176
  return cachedObj;
8177
8177
  }
8178
8178
  obj = _Long.fromBits(value, (value | 0) < 0 ? -1 : 0, true);
8179
- if (cache)
8179
+ if (cache2)
8180
8180
  UINT_CACHE[value] = obj;
8181
8181
  return obj;
8182
8182
  } else {
8183
8183
  value |= 0;
8184
- if (cache = -128 <= value && value < 128) {
8184
+ if (cache2 = -128 <= value && value < 128) {
8185
8185
  cachedObj = INT_CACHE[value];
8186
8186
  if (cachedObj)
8187
8187
  return cachedObj;
8188
8188
  }
8189
8189
  obj = _Long.fromBits(value, value < 0 ? -1 : 0, false);
8190
- if (cache)
8190
+ if (cache2)
8191
8191
  INT_CACHE[value] = obj;
8192
8192
  return obj;
8193
8193
  }
@@ -14538,10 +14538,10 @@ var require_utils = __commonJS({
14538
14538
  function squashError(_error) {
14539
14539
  return;
14540
14540
  }
14541
- var randomBytes = (size2) => {
14541
+ var randomBytes2 = (size2) => {
14542
14542
  return Promise.resolve(crypto.getRandomValues(new Uint8Array(size2)));
14543
14543
  };
14544
- exports2.randomBytes = randomBytes;
14544
+ exports2.randomBytes = randomBytes2;
14545
14545
  async function once(ee3, name2, options) {
14546
14546
  options?.signal?.throwIfAborted();
14547
14547
  const { promise, resolve: resolve13, reject } = promiseWithResolvers();
@@ -23435,9 +23435,9 @@ var require_client_metadata = __commonJS({
23435
23435
  throw new error_1.MongoInvalidArgumentError("Unable to include driverInfo name and version, metadata cannot exceed 512 bytes");
23436
23436
  }
23437
23437
  let runtimeInfo = getRuntimeInfo();
23438
- for (const { platform: platform2 = "" } of driverInfoList) {
23439
- if (platform2.length > 0) {
23440
- runtimeInfo = `${runtimeInfo}|${platform2}`;
23438
+ for (const { platform: platform3 = "" } of driverInfoList) {
23439
+ if (platform3.length > 0) {
23440
+ runtimeInfo = `${runtimeInfo}|${platform3}`;
23441
23441
  }
23442
23442
  }
23443
23443
  if (!metadataDocument.ifItFitsItSits("platform", runtimeInfo)) {
@@ -34620,8 +34620,8 @@ var require_callback_workflow = __commonJS({
34620
34620
  /**
34621
34621
  * Instantiate the callback workflow.
34622
34622
  */
34623
- constructor(cache, callback) {
34624
- this.cache = cache;
34623
+ constructor(cache2, callback) {
34624
+ this.cache = cache2;
34625
34625
  this.callback = this.withLock(callback);
34626
34626
  this.lastExecutionTime = Date.now() - THROTTLE_MS;
34627
34627
  }
@@ -34731,8 +34731,8 @@ var require_automated_callback_workflow = __commonJS({
34731
34731
  /**
34732
34732
  * Instantiate the human callback workflow.
34733
34733
  */
34734
- constructor(cache, callback) {
34735
- super(cache, callback);
34734
+ constructor(cache2, callback) {
34735
+ super(cache2, callback);
34736
34736
  }
34737
34737
  /**
34738
34738
  * Execute the OIDC callback workflow.
@@ -35068,8 +35068,8 @@ var require_human_callback_workflow = __commonJS({
35068
35068
  /**
35069
35069
  * Instantiate the human callback workflow.
35070
35070
  */
35071
- constructor(cache, callback) {
35072
- super(cache, callback);
35071
+ constructor(cache2, callback) {
35072
+ super(cache2, callback);
35073
35073
  }
35074
35074
  /**
35075
35075
  * Execute the OIDC human callback workflow.
@@ -40701,7 +40701,7 @@ var require_utils4 = __commonJS({
40701
40701
  var nodeCrypto = require("crypto");
40702
40702
  module2.exports = {
40703
40703
  postgresMd5PasswordHash,
40704
- randomBytes,
40704
+ randomBytes: randomBytes2,
40705
40705
  deriveKey,
40706
40706
  sha256: sha2562,
40707
40707
  hashByName,
@@ -40711,7 +40711,7 @@ var require_utils4 = __commonJS({
40711
40711
  var webCrypto = nodeCrypto.webcrypto || globalThis.crypto;
40712
40712
  var subtleCrypto = webCrypto.subtle;
40713
40713
  var textEncoder = new TextEncoder();
40714
- function randomBytes(length) {
40714
+ function randomBytes2(length) {
40715
40715
  return webCrypto.getRandomValues(Buffer.alloc(length));
40716
40716
  }
40717
40717
  async function md52(string3) {
@@ -65880,7 +65880,7 @@ init_cjs_shims();
65880
65880
 
65881
65881
  // ../../packages/core/src/version.ts
65882
65882
  init_cjs_shims();
65883
- var HORUS_VERSION = true ? "0.15.2" : "dev";
65883
+ var HORUS_VERSION = true ? "0.16.0" : "dev";
65884
65884
  var PINNED_SOURCE_VERSION = "2.0.2";
65885
65885
 
65886
65886
  // ../../packages/core/src/evidence.ts
@@ -69976,47 +69976,375 @@ function createJiti(id, opts = {}) {
69976
69976
  }
69977
69977
 
69978
69978
  // ../../packages/core/src/config.ts
69979
- var import_node_path2 = require("path");
69980
- var import_node_fs2 = require("fs");
69979
+ var import_node_path3 = require("path");
69980
+ var import_node_fs3 = require("fs");
69981
69981
  var import_node_url = require("url");
69982
69982
 
69983
69983
  // ../../packages/core/src/discovery.ts
69984
69984
  init_cjs_shims();
69985
+ var import_node_fs2 = require("fs");
69986
+ var import_node_path2 = require("path");
69987
+ var import_node_os2 = require("os");
69988
+
69989
+ // ../../packages/core/src/secrets.ts
69990
+ init_cjs_shims();
69991
+ var import_node_crypto = require("crypto");
69992
+ var import_node_child_process = require("child_process");
69985
69993
  var import_node_fs = require("fs");
69986
- var import_node_path = require("path");
69987
69994
  var import_node_os = require("os");
69995
+ var import_node_path = require("path");
69996
+ var MasterKeyUnavailableError = class extends Error {
69997
+ constructor(message) {
69998
+ super(message);
69999
+ this.name = "MasterKeyUnavailableError";
70000
+ }
70001
+ };
70002
+ function isEncryptedSecret(v4) {
70003
+ if (typeof v4 !== "object" || v4 === null) return false;
70004
+ const o5 = v4;
70005
+ return o5["v"] === 1 && o5["alg"] === "aes-256-gcm" && typeof o5["kid"] === "string" && typeof o5["iv"] === "string" && typeof o5["ct"] === "string" && typeof o5["tag"] === "string";
70006
+ }
70007
+ var ENV_VAR = "HORUS_SECRET_KEY";
70008
+ var KEY_SERVICE = "horus";
70009
+ var KEY_ACCOUNT = "master-key";
70010
+ var KEY_LABEL = "Horus connector-secret master key";
70011
+ var KDF_SALT = Buffer.from("horus.secret.kdf.v1");
70012
+ var KEY_BYTES = 32;
70013
+ var IV_BYTES = 12;
70014
+ var CMD_TIMEOUT_MS = 4e3;
70015
+ var cachedKey = null;
70016
+ var cachedSource = null;
70017
+ function fingerprint(key) {
70018
+ return (0, import_node_crypto.createHash)("sha256").update(key).digest("hex").slice(0, 16);
70019
+ }
70020
+ function keyFromEnvValue(value) {
70021
+ const trimmed = value.trim();
70022
+ try {
70023
+ const decoded = Buffer.from(trimmed, "base64");
70024
+ if (decoded.length === KEY_BYTES && decoded.toString("base64") === trimmed) {
70025
+ return decoded;
70026
+ }
70027
+ } catch {
70028
+ }
70029
+ return (0, import_node_crypto.scryptSync)(trimmed, KDF_SALT, KEY_BYTES);
70030
+ }
70031
+ function keyringDir() {
70032
+ return (0, import_node_path.join)((0, import_node_os.homedir)(), ".horus", "keyring");
70033
+ }
70034
+ function keyFilePath() {
70035
+ return (0, import_node_path.join)(keyringDir(), "master.key");
70036
+ }
70037
+ function dpapiBlobPath() {
70038
+ return (0, import_node_path.join)(keyringDir(), "master.key.dpapi");
70039
+ }
70040
+ function macKeychainGet() {
70041
+ try {
70042
+ const out2 = (0, import_node_child_process.execFileSync)(
70043
+ "security",
70044
+ ["find-generic-password", "-s", KEY_SERVICE, "-a", KEY_ACCOUNT, "-w"],
70045
+ { stdio: ["ignore", "pipe", "ignore"], timeout: CMD_TIMEOUT_MS }
70046
+ );
70047
+ const v4 = out2.toString("utf8").trim();
70048
+ return v4.length > 0 ? v4 : null;
70049
+ } catch {
70050
+ return null;
70051
+ }
70052
+ }
70053
+ function macKeychainSet(b64) {
70054
+ try {
70055
+ (0, import_node_child_process.execFileSync)(
70056
+ "security",
70057
+ [
70058
+ "add-generic-password",
70059
+ "-U",
70060
+ // update if it already exists
70061
+ "-s",
70062
+ KEY_SERVICE,
70063
+ "-a",
70064
+ KEY_ACCOUNT,
70065
+ "-l",
70066
+ KEY_LABEL,
70067
+ "-w",
70068
+ b64
70069
+ ],
70070
+ { stdio: "ignore", timeout: CMD_TIMEOUT_MS }
70071
+ );
70072
+ return true;
70073
+ } catch {
70074
+ return false;
70075
+ }
70076
+ }
70077
+ function linuxKeychainGet() {
70078
+ try {
70079
+ const out2 = (0, import_node_child_process.execFileSync)(
70080
+ "secret-tool",
70081
+ ["lookup", "service", KEY_SERVICE, "account", KEY_ACCOUNT],
70082
+ { stdio: ["ignore", "pipe", "ignore"], timeout: CMD_TIMEOUT_MS }
70083
+ );
70084
+ const v4 = out2.toString("utf8").trim();
70085
+ return v4.length > 0 ? v4 : null;
70086
+ } catch {
70087
+ return null;
70088
+ }
70089
+ }
70090
+ function linuxKeychainSet(b64) {
70091
+ try {
70092
+ (0, import_node_child_process.execFileSync)(
70093
+ "secret-tool",
70094
+ ["store", "--label", KEY_LABEL, "service", KEY_SERVICE, "account", KEY_ACCOUNT],
70095
+ { input: b64, stdio: ["pipe", "ignore", "ignore"], timeout: CMD_TIMEOUT_MS }
70096
+ );
70097
+ return true;
70098
+ } catch {
70099
+ return false;
70100
+ }
70101
+ }
70102
+ function powershellBin() {
70103
+ for (const bin of ["powershell", "pwsh"]) {
70104
+ try {
70105
+ (0, import_node_child_process.execFileSync)(bin, ["-NoProfile", "-Command", "$PSVersionTable.PSVersion.Major"], {
70106
+ stdio: "ignore",
70107
+ timeout: CMD_TIMEOUT_MS
70108
+ });
70109
+ return bin;
70110
+ } catch {
70111
+ }
70112
+ }
70113
+ return null;
70114
+ }
70115
+ function winKeychainGet() {
70116
+ const ps = powershellBin();
70117
+ const blob = dpapiBlobPath();
70118
+ if (!ps || !(0, import_node_fs.existsSync)(blob)) return null;
70119
+ const script = `
70120
+ $enc = Get-Content -Path $env:HORUS_DPAPI_BLOB -Raw
70121
+ $sec = ConvertTo-SecureString $enc
70122
+ $ptr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
70123
+ try { [Console]::Out.Write([Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr)) }
70124
+ finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr) }`;
70125
+ try {
70126
+ const out2 = (0, import_node_child_process.execFileSync)(ps, ["-NoProfile", "-NonInteractive", "-Command", script], {
70127
+ stdio: ["ignore", "pipe", "ignore"],
70128
+ timeout: CMD_TIMEOUT_MS,
70129
+ env: { ...process.env, HORUS_DPAPI_BLOB: blob }
70130
+ });
70131
+ const v4 = out2.toString("utf8").trim();
70132
+ return v4.length > 0 ? v4 : null;
70133
+ } catch {
70134
+ return null;
70135
+ }
70136
+ }
70137
+ function winKeychainSet(b64) {
70138
+ const ps = powershellBin();
70139
+ if (!ps) return false;
70140
+ (0, import_node_fs.mkdirSync)(keyringDir(), { recursive: true });
70141
+ const blob = dpapiBlobPath();
70142
+ const script = `
70143
+ $sec = ConvertTo-SecureString $env:HORUS_DPAPI_KEY -AsPlainText -Force
70144
+ $enc = ConvertFrom-SecureString $sec
70145
+ Set-Content -Path $env:HORUS_DPAPI_BLOB -Value $enc -NoNewline`;
70146
+ try {
70147
+ (0, import_node_child_process.execFileSync)(ps, ["-NoProfile", "-NonInteractive", "-Command", script], {
70148
+ stdio: "ignore",
70149
+ timeout: CMD_TIMEOUT_MS,
70150
+ env: { ...process.env, HORUS_DPAPI_KEY: b64, HORUS_DPAPI_BLOB: blob }
70151
+ });
70152
+ return true;
70153
+ } catch {
70154
+ return false;
70155
+ }
70156
+ }
70157
+ function osKeychainGet() {
70158
+ switch ((0, import_node_os.platform)()) {
70159
+ case "darwin":
70160
+ return macKeychainGet();
70161
+ case "linux":
70162
+ return linuxKeychainGet();
70163
+ case "win32":
70164
+ return winKeychainGet();
70165
+ default:
70166
+ return null;
70167
+ }
70168
+ }
70169
+ function osKeychainSet(b64) {
70170
+ switch ((0, import_node_os.platform)()) {
70171
+ case "darwin":
70172
+ return macKeychainSet(b64);
70173
+ case "linux":
70174
+ return linuxKeychainSet(b64);
70175
+ case "win32":
70176
+ return winKeychainSet(b64);
70177
+ default:
70178
+ return false;
70179
+ }
70180
+ }
70181
+ function keyFileGet() {
70182
+ const p5 = keyFilePath();
70183
+ if (!(0, import_node_fs.existsSync)(p5)) return null;
70184
+ try {
70185
+ const v4 = (0, import_node_fs.readFileSync)(p5, "utf8").trim();
70186
+ return v4.length > 0 ? v4 : null;
70187
+ } catch {
70188
+ return null;
70189
+ }
70190
+ }
70191
+ function keyFileSet(b64) {
70192
+ try {
70193
+ (0, import_node_fs.mkdirSync)(keyringDir(), { recursive: true });
70194
+ const p5 = keyFilePath();
70195
+ (0, import_node_fs.writeFileSync)(p5, b64 + "\n", { mode: 384 });
70196
+ (0, import_node_fs.chmodSync)(p5, 384);
70197
+ return true;
70198
+ } catch {
70199
+ return false;
70200
+ }
70201
+ }
70202
+ function cache(key, source) {
70203
+ cachedKey = key;
70204
+ cachedSource = source;
70205
+ return { key, source };
70206
+ }
70207
+ function resolveExistingKey() {
70208
+ if (cachedKey && cachedSource) return { key: cachedKey, source: cachedSource };
70209
+ const envVal = process.env[ENV_VAR];
70210
+ if (envVal && envVal.trim().length > 0) {
70211
+ return cache(keyFromEnvValue(envVal), "env");
70212
+ }
70213
+ const fromKeychain = osKeychainGet();
70214
+ if (fromKeychain) {
70215
+ const key = Buffer.from(fromKeychain, "base64");
70216
+ if (key.length === KEY_BYTES) return cache(key, "keychain");
70217
+ }
70218
+ const fromFile = keyFileGet();
70219
+ if (fromFile) {
70220
+ const key = Buffer.from(fromFile, "base64");
70221
+ if (key.length === KEY_BYTES) return cache(key, "file");
70222
+ }
70223
+ return null;
70224
+ }
70225
+ function getMasterKeyForRead() {
70226
+ return resolveExistingKey()?.key ?? null;
70227
+ }
70228
+ function ensureMasterKey() {
70229
+ const existing = resolveExistingKey();
70230
+ if (existing) return { key: existing.key, source: existing.source };
70231
+ const key = (0, import_node_crypto.randomBytes)(KEY_BYTES);
70232
+ const b64 = key.toString("base64");
70233
+ if (osKeychainSet(b64)) {
70234
+ cache(key, "generated-keychain");
70235
+ return { key, source: "generated-keychain" };
70236
+ }
70237
+ if (keyFileSet(b64)) {
70238
+ cache(key, "generated-file");
70239
+ return {
70240
+ key,
70241
+ source: "generated-file",
70242
+ warning: `No OS keychain available \u2014 stored the master key at ${keyFilePath()} (mode 0600).
70243
+ It is in your home directory (never the repo), but is protected only by file permissions.
70244
+ For stronger isolation set ${ENV_VAR} to a passphrase, or run on a host with a keyring.`
70245
+ };
70246
+ }
70247
+ throw new MasterKeyUnavailableError(
70248
+ `Could not persist a master key (no keychain and ${keyFilePath()} is not writable). Set ${ENV_VAR} to a passphrase and retry.`
70249
+ );
70250
+ }
70251
+ function masterKeyStatus() {
70252
+ const existing = resolveExistingKey();
70253
+ if (!existing) {
70254
+ return {
70255
+ available: false,
70256
+ detail: `no master key yet \u2014 one is created on first \`horus connect\` (keychain, or ${ENV_VAR}).`
70257
+ };
70258
+ }
70259
+ const detail = {
70260
+ env: `${ENV_VAR} environment variable`,
70261
+ keychain: osKeychainLabel(),
70262
+ file: `key file ${keyFilePath()} (0600 fallback)`,
70263
+ "generated-keychain": osKeychainLabel(),
70264
+ "generated-file": `key file ${keyFilePath()} (0600 fallback)`
70265
+ };
70266
+ return { available: true, source: existing.source, detail: detail[existing.source] };
70267
+ }
70268
+ function osKeychainLabel() {
70269
+ switch ((0, import_node_os.platform)()) {
70270
+ case "darwin":
70271
+ return "macOS Keychain";
70272
+ case "linux":
70273
+ return "libsecret keyring (secret-tool)";
70274
+ case "win32":
70275
+ return "Windows DPAPI (user-scoped)";
70276
+ default:
70277
+ return "OS keychain";
70278
+ }
70279
+ }
70280
+ function encryptSecret(plaintext, key) {
70281
+ const k3 = key ?? ensureMasterKey().key;
70282
+ const iv = (0, import_node_crypto.randomBytes)(IV_BYTES);
70283
+ const cipher = (0, import_node_crypto.createCipheriv)("aes-256-gcm", k3, iv);
70284
+ const ct2 = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
70285
+ const tag = cipher.getAuthTag();
70286
+ return {
70287
+ v: 1,
70288
+ alg: "aes-256-gcm",
70289
+ kid: fingerprint(k3),
70290
+ iv: iv.toString("base64"),
70291
+ ct: ct2.toString("base64"),
70292
+ tag: tag.toString("base64")
70293
+ };
70294
+ }
70295
+ function decryptSecret(blob, key) {
70296
+ const k3 = key ?? getMasterKeyForRead();
70297
+ if (!k3) {
70298
+ throw new MasterKeyUnavailableError(
70299
+ `Cannot decrypt: master key not found (set ${ENV_VAR} or restore the OS keychain entry).`
70300
+ );
70301
+ }
70302
+ if (blob.kid !== fingerprint(k3)) {
70303
+ throw new Error(
70304
+ `Encrypted secret was sealed with a different master key (key fingerprint mismatch). Re-run \`horus connect\` to re-encrypt, or restore the original key.`
70305
+ );
70306
+ }
70307
+ const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-gcm", k3, Buffer.from(blob.iv, "base64"));
70308
+ decipher.setAuthTag(Buffer.from(blob.tag, "base64"));
70309
+ return Buffer.concat([
70310
+ decipher.update(Buffer.from(blob.ct, "base64")),
70311
+ decipher.final()
70312
+ ]).toString("utf8");
70313
+ }
70314
+
70315
+ // ../../packages/core/src/discovery.ts
69988
70316
  var HORUS_DIR = ".horus";
69989
70317
  var LOCAL_CONFIG_FILE = "config.json";
69990
70318
  function localConfigPath(root) {
69991
- return (0, import_node_path.join)(root, HORUS_DIR, LOCAL_CONFIG_FILE);
70319
+ return (0, import_node_path2.join)(root, HORUS_DIR, LOCAL_CONFIG_FILE);
69992
70320
  }
69993
70321
  function discoverLocalConfig(start2) {
69994
- let dir = (0, import_node_path.resolve)(start2);
70322
+ let dir = (0, import_node_path2.resolve)(start2);
69995
70323
  for (; ; ) {
69996
70324
  const candidate = localConfigPath(dir);
69997
- if ((0, import_node_fs.existsSync)(candidate)) return candidate;
69998
- const parent = (0, import_node_path.dirname)(dir);
70325
+ if ((0, import_node_fs2.existsSync)(candidate)) return candidate;
70326
+ const parent = (0, import_node_path2.dirname)(dir);
69999
70327
  if (parent === dir) return null;
70000
70328
  dir = parent;
70001
70329
  }
70002
70330
  }
70003
70331
  function findRepoRoot(start2) {
70004
- let dir = (0, import_node_path.resolve)(start2);
70332
+ let dir = (0, import_node_path2.resolve)(start2);
70005
70333
  for (; ; ) {
70006
- if ((0, import_node_fs.existsSync)((0, import_node_path.join)(dir, ".git"))) return dir;
70007
- const parent = (0, import_node_path.dirname)(dir);
70334
+ if ((0, import_node_fs2.existsSync)((0, import_node_path2.join)(dir, ".git"))) return dir;
70335
+ const parent = (0, import_node_path2.dirname)(dir);
70008
70336
  if (parent === dir) return null;
70009
70337
  dir = parent;
70010
70338
  }
70011
70339
  }
70012
70340
  function registryPath() {
70013
- return (0, import_node_path.join)((0, import_node_os.homedir)(), HORUS_DIR, "registry.json");
70341
+ return (0, import_node_path2.join)((0, import_node_os2.homedir)(), HORUS_DIR, "registry.json");
70014
70342
  }
70015
70343
  function readRegistry() {
70016
70344
  const p5 = registryPath();
70017
- if (!(0, import_node_fs.existsSync)(p5)) return { projects: {} };
70345
+ if (!(0, import_node_fs2.existsSync)(p5)) return { projects: {} };
70018
70346
  try {
70019
- const parsed = JSON.parse((0, import_node_fs.readFileSync)(p5, "utf8"));
70347
+ const parsed = JSON.parse((0, import_node_fs2.readFileSync)(p5, "utf8"));
70020
70348
  return { projects: parsed.projects ?? {} };
70021
70349
  } catch {
70022
70350
  return { projects: {} };
@@ -70024,8 +70352,8 @@ function readRegistry() {
70024
70352
  }
70025
70353
  function writeRegistry(reg) {
70026
70354
  const p5 = registryPath();
70027
- (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(p5), { recursive: true });
70028
- (0, import_node_fs.writeFileSync)(p5, JSON.stringify(reg, null, 2) + "\n");
70355
+ (0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(p5), { recursive: true });
70356
+ (0, import_node_fs2.writeFileSync)(p5, JSON.stringify(reg, null, 2) + "\n");
70029
70357
  }
70030
70358
  function registerProject(name2, root, configPath) {
70031
70359
  const reg = readRegistry();
@@ -70036,72 +70364,97 @@ function lookupProject(name2) {
70036
70364
  return readRegistry().projects[name2] ?? null;
70037
70365
  }
70038
70366
  function writeLocalConfig(root, file) {
70039
- const dir = (0, import_node_path.join)(root, HORUS_DIR);
70040
- (0, import_node_fs.mkdirSync)(dir, { recursive: true });
70041
- const p5 = (0, import_node_path.join)(dir, LOCAL_CONFIG_FILE);
70042
- (0, import_node_fs.writeFileSync)(p5, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
70043
- (0, import_node_fs.chmodSync)(p5, 384);
70367
+ const dir = (0, import_node_path2.join)(root, HORUS_DIR);
70368
+ (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
70369
+ const p5 = (0, import_node_path2.join)(dir, LOCAL_CONFIG_FILE);
70370
+ (0, import_node_fs2.writeFileSync)(p5, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
70371
+ (0, import_node_fs2.chmodSync)(p5, 384);
70044
70372
  return p5;
70045
70373
  }
70046
- function ensureCredentialGitignore(root) {
70047
- const dir = (0, import_node_path.join)(root, HORUS_DIR);
70048
- (0, import_node_fs.mkdirSync)(dir, { recursive: true });
70049
- const gitignorePath = (0, import_node_path.join)(dir, ".gitignore");
70050
- const entry2 = "config.json";
70051
- if ((0, import_node_fs.existsSync)(gitignorePath)) {
70052
- const existing = (0, import_node_fs.readFileSync)(gitignorePath, "utf8");
70053
- if (existing.split("\n").some((l2) => l2.trim() === entry2)) return;
70054
- (0, import_node_fs.writeFileSync)(gitignorePath, existing.trimEnd() + "\n" + entry2 + "\n");
70055
- } else {
70056
- (0, import_node_fs.writeFileSync)(gitignorePath, entry2 + "\n");
70057
- }
70058
- }
70059
70374
  function readLocalConfig(path) {
70060
- return JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
70375
+ return JSON.parse((0, import_node_fs2.readFileSync)(path, "utf8"));
70061
70376
  }
70062
70377
  var LOCAL_SECRETS_FILE = "secrets.local.json";
70063
70378
  function localSecretsPath(root) {
70064
- return (0, import_node_path.join)(root, HORUS_DIR, LOCAL_SECRETS_FILE);
70379
+ return (0, import_node_path2.join)(root, HORUS_DIR, LOCAL_SECRETS_FILE);
70065
70380
  }
70066
70381
  function readLocalSecrets(root) {
70067
70382
  const p5 = localSecretsPath(root);
70068
- if (!(0, import_node_fs.existsSync)(p5)) return {};
70383
+ if (!(0, import_node_fs2.existsSync)(p5)) return {};
70069
70384
  try {
70070
- return JSON.parse((0, import_node_fs.readFileSync)(p5, "utf8"));
70385
+ return JSON.parse((0, import_node_fs2.readFileSync)(p5, "utf8"));
70071
70386
  } catch {
70072
70387
  return {};
70073
70388
  }
70074
70389
  }
70075
70390
  function writeLocalSecrets(root, secrets) {
70076
- const dir = (0, import_node_path.join)(root, HORUS_DIR);
70077
- (0, import_node_fs.mkdirSync)(dir, { recursive: true });
70391
+ const dir = (0, import_node_path2.join)(root, HORUS_DIR);
70392
+ (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
70078
70393
  const p5 = localSecretsPath(root);
70079
- (0, import_node_fs.writeFileSync)(p5, JSON.stringify(secrets, null, 2) + "\n", { mode: 384 });
70080
- (0, import_node_fs.chmodSync)(p5, 384);
70081
- const gitignorePath = (0, import_node_path.join)(dir, ".gitignore");
70394
+ (0, import_node_fs2.writeFileSync)(p5, JSON.stringify(secrets, null, 2) + "\n", { mode: 384 });
70395
+ (0, import_node_fs2.chmodSync)(p5, 384);
70396
+ const gitignorePath = (0, import_node_path2.join)(dir, ".gitignore");
70082
70397
  const entry2 = LOCAL_SECRETS_FILE;
70083
- if ((0, import_node_fs.existsSync)(gitignorePath)) {
70084
- const existing = (0, import_node_fs.readFileSync)(gitignorePath, "utf8");
70398
+ if ((0, import_node_fs2.existsSync)(gitignorePath)) {
70399
+ const existing = (0, import_node_fs2.readFileSync)(gitignorePath, "utf8");
70085
70400
  if (!existing.split("\n").some((l2) => l2.trim() === entry2)) {
70086
- (0, import_node_fs.writeFileSync)(gitignorePath, existing.trimEnd() + "\n" + entry2 + "\n");
70401
+ (0, import_node_fs2.writeFileSync)(gitignorePath, existing.trimEnd() + "\n" + entry2 + "\n");
70087
70402
  }
70088
70403
  } else {
70089
- (0, import_node_fs.writeFileSync)(gitignorePath, entry2 + "\n");
70404
+ (0, import_node_fs2.writeFileSync)(gitignorePath, entry2 + "\n");
70090
70405
  }
70091
70406
  return p5;
70092
70407
  }
70408
+ function writeConnectorSecret(root, envName, connector, field, plaintext, key) {
70409
+ const secrets = readLocalSecrets(root);
70410
+ const blob = encryptSecret(plaintext, key);
70411
+ const byEnv = secrets.connectors ??= {};
70412
+ const byConnector = byEnv[envName] ??= {};
70413
+ const byField = byConnector[connector] ??= {};
70414
+ byField[field] = blob;
70415
+ writeLocalSecrets(root, secrets);
70416
+ ensureProjectGitignore(root);
70417
+ }
70418
+ function decryptConnectorSecrets(root) {
70419
+ const out2 = { values: {}, warnings: [] };
70420
+ const stored = readLocalSecrets(root).connectors;
70421
+ if (!stored) return out2;
70422
+ for (const [env, byConnector] of Object.entries(stored)) {
70423
+ for (const [connector, byField] of Object.entries(byConnector)) {
70424
+ for (const [field, blob] of Object.entries(byField)) {
70425
+ if (!isEncryptedSecret(blob)) continue;
70426
+ try {
70427
+ const plain = decryptSecret(blob);
70428
+ const e = out2.values[env] ??= {};
70429
+ const c4 = e[connector] ??= {};
70430
+ c4[field] = plain;
70431
+ } catch (err2) {
70432
+ const reason = err2 instanceof MasterKeyUnavailableError ? "no master key" : err2.message;
70433
+ out2.warnings.push(`${env}/${connector}.${field}: ${reason}`);
70434
+ }
70435
+ }
70436
+ }
70437
+ }
70438
+ return out2;
70439
+ }
70440
+ function isHorusGitignored(root) {
70441
+ if (!(0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, ".git"))) return true;
70442
+ const gitignorePath = (0, import_node_path2.join)(root, ".gitignore");
70443
+ if (!(0, import_node_fs2.existsSync)(gitignorePath)) return false;
70444
+ return (0, import_node_fs2.readFileSync)(gitignorePath, "utf8").split("\n").map((l2) => l2.trim()).some((l2) => l2 === ".horus" || l2 === ".horus/" || l2 === "/.horus" || l2 === "/.horus/");
70445
+ }
70093
70446
  function ensureProjectGitignore(root) {
70094
- if (!(0, import_node_fs.existsSync)((0, import_node_path.join)(root, ".git"))) return;
70095
- const gitignorePath = (0, import_node_path.join)(root, ".gitignore");
70447
+ if (!(0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, ".git"))) return;
70448
+ const gitignorePath = (0, import_node_path2.join)(root, ".gitignore");
70096
70449
  const entry2 = ".horus/";
70097
- if (!(0, import_node_fs.existsSync)(gitignorePath)) {
70098
- (0, import_node_fs.writeFileSync)(gitignorePath, entry2 + "\n");
70450
+ if (!(0, import_node_fs2.existsSync)(gitignorePath)) {
70451
+ (0, import_node_fs2.writeFileSync)(gitignorePath, entry2 + "\n");
70099
70452
  return;
70100
70453
  }
70101
- const existing = (0, import_node_fs.readFileSync)(gitignorePath, "utf8");
70454
+ const existing = (0, import_node_fs2.readFileSync)(gitignorePath, "utf8");
70102
70455
  const alreadyIgnored = existing.split("\n").map((l2) => l2.trim()).some((l2) => l2 === ".horus" || l2 === ".horus/" || l2 === "/.horus" || l2 === "/.horus/");
70103
70456
  if (alreadyIgnored) return;
70104
- (0, import_node_fs.writeFileSync)(gitignorePath, existing.trimEnd() + "\n" + entry2 + "\n");
70457
+ (0, import_node_fs2.writeFileSync)(gitignorePath, existing.trimEnd() + "\n" + entry2 + "\n");
70105
70458
  }
70106
70459
  function patchLocalConnector(configPath, connectorType, patch, envName) {
70107
70460
  const file = readLocalConfig(configPath);
@@ -70366,6 +70719,35 @@ function resolveAiSettings(config2) {
70366
70719
  if (ai?.anthropic?.model !== void 0) out2.model = ai.anthropic.model;
70367
70720
  return out2;
70368
70721
  }
70722
+ var CONNECTOR_SECRET_FIELDS = {
70723
+ elasticsearch: ["username", "password"],
70724
+ mongodb: ["url"],
70725
+ postgres: ["url"],
70726
+ sentry: ["authToken"],
70727
+ axiom: ["token"],
70728
+ grafana: ["username", "password"],
70729
+ redis: ["url"]
70730
+ };
70731
+ function findPlaintextConnectorSecrets(project) {
70732
+ const out2 = [];
70733
+ const envs = project?.environments;
70734
+ if (!Array.isArray(envs)) return out2;
70735
+ for (const env of envs) {
70736
+ const envName = env["name"] ?? "(unnamed)";
70737
+ const connectors = env["connectors"];
70738
+ if (!connectors || typeof connectors !== "object") continue;
70739
+ for (const [connector, cfg] of Object.entries(connectors)) {
70740
+ if (!cfg || typeof cfg !== "object") continue;
70741
+ for (const field of CONNECTOR_SECRET_FIELDS[connector] ?? []) {
70742
+ const val = cfg[field];
70743
+ if (typeof val === "string" && val.length > 0) {
70744
+ out2.push(`${envName}/${connector}.${field}`);
70745
+ }
70746
+ }
70747
+ }
70748
+ }
70749
+ return out2;
70750
+ }
70369
70751
  function listEnvironments(config2) {
70370
70752
  const out2 = [];
70371
70753
  for (const p5 of config2.projects) {
@@ -70392,9 +70774,9 @@ function resolveEnvironment(config2, opts) {
70392
70774
  project = p5;
70393
70775
  } else {
70394
70776
  const cwd = opts?.cwd ?? process.cwd();
70395
- const root = findRepoRoot(cwd) ?? (0, import_node_path2.resolve)(cwd);
70777
+ const root = findRepoRoot(cwd) ?? (0, import_node_path3.resolve)(cwd);
70396
70778
  const matches = config2.projects.filter(
70397
- (p5) => p5.repositories.some((r) => (0, import_node_path2.resolve)(r.path) === root)
70779
+ (p5) => p5.repositories.some((r) => (0, import_node_path3.resolve)(r.path) === root)
70398
70780
  );
70399
70781
  const inferred = matches[0];
70400
70782
  if (matches.length === 1 && inferred !== void 0) {
@@ -70572,15 +70954,41 @@ ${details}`);
70572
70954
  }
70573
70955
  return parsed.data;
70574
70956
  }
70957
+ function hydrateConnectorSecrets(project, root) {
70958
+ const decrypted = decryptConnectorSecrets(root);
70959
+ for (const w4 of decrypted.warnings) {
70960
+ process.stderr.write(`horus: skipped encrypted connector secret (${w4})
70961
+ `);
70962
+ }
70963
+ if (Object.keys(decrypted.values).length === 0) return;
70964
+ const envs = project?.environments;
70965
+ if (!Array.isArray(envs)) return;
70966
+ for (const env of envs) {
70967
+ const envName = env["name"];
70968
+ if (!envName) continue;
70969
+ const byConnector = decrypted.values[envName];
70970
+ if (!byConnector) continue;
70971
+ const connectors = env["connectors"];
70972
+ if (!connectors || typeof connectors !== "object") continue;
70973
+ for (const [connector, fields] of Object.entries(byConnector)) {
70974
+ const target = connectors[connector];
70975
+ if (!target || typeof target !== "object") continue;
70976
+ for (const [field, value] of Object.entries(fields)) {
70977
+ target[field] = value;
70978
+ }
70979
+ }
70980
+ }
70981
+ }
70575
70982
  async function loadConfigFile(target) {
70576
70983
  if (target.endsWith(".json")) {
70577
70984
  const file = readLocalConfig(target);
70578
- const root = (0, import_node_path2.dirname)((0, import_node_path2.dirname)(target));
70985
+ const root = (0, import_node_path3.dirname)((0, import_node_path3.dirname)(target));
70579
70986
  const secrets = readLocalSecrets(root);
70580
70987
  let ai = file.ai;
70581
70988
  if (secrets.anthropic?.apiKey) {
70582
70989
  ai = { ...ai ?? {}, anthropic: { ...ai?.anthropic ?? {}, apiKey: secrets.anthropic.apiKey } };
70583
70990
  }
70991
+ hydrateConnectorSecrets(file.project, root);
70584
70992
  const raw = {
70585
70993
  projects: file.project ? [file.project] : [],
70586
70994
  database: file.database ?? {
@@ -70622,7 +71030,7 @@ async function loadConfig(configPath, opts) {
70622
71030
  const cwd = opts?.cwd ?? process.cwd();
70623
71031
  let target;
70624
71032
  if (configPath) {
70625
- target = (0, import_node_path2.resolve)(configPath);
71033
+ target = (0, import_node_path3.resolve)(configPath);
70626
71034
  } else if (opts?.name) {
70627
71035
  const entry2 = lookupProject(opts.name);
70628
71036
  if (entry2 === null) {
@@ -70636,16 +71044,16 @@ async function loadConfig(configPath, opts) {
70636
71044
  if (discovered) {
70637
71045
  target = discovered;
70638
71046
  } else if (process.env["HORUS_CONFIG"]) {
70639
- target = (0, import_node_path2.resolve)(process.env["HORUS_CONFIG"]);
71047
+ target = (0, import_node_path3.resolve)(process.env["HORUS_CONFIG"]);
70640
71048
  } else {
70641
- const jsPath = (0, import_node_path2.resolve)(cwd, "config/horus.config.js");
70642
- const tsPath = (0, import_node_path2.resolve)(cwd, "config/horus.config.ts");
70643
- if (!(0, import_node_fs2.existsSync)(jsPath) && !(0, import_node_fs2.existsSync)(tsPath)) {
71049
+ const jsPath = (0, import_node_path3.resolve)(cwd, "config/horus.config.js");
71050
+ const tsPath = (0, import_node_path3.resolve)(cwd, "config/horus.config.ts");
71051
+ if (!(0, import_node_fs3.existsSync)(jsPath) && !(0, import_node_fs3.existsSync)(tsPath)) {
70644
71052
  throw new Error(
70645
71053
  `No Horus config found for ${cwd}. Run \`horus index\` in this repo to set it up, or pass --config <path> / --name <project>.`
70646
71054
  );
70647
71055
  }
70648
- target = (0, import_node_fs2.existsSync)(jsPath) ? jsPath : tsPath;
71056
+ target = (0, import_node_fs3.existsSync)(jsPath) ? jsPath : tsPath;
70649
71057
  }
70650
71058
  }
70651
71059
  return loadConfigFile(target);
@@ -70653,11 +71061,11 @@ async function loadConfig(configPath, opts) {
70653
71061
 
70654
71062
  // ../../packages/core/src/git.ts
70655
71063
  init_cjs_shims();
70656
- var import_node_child_process = require("child_process");
71064
+ var import_node_child_process2 = require("child_process");
70657
71065
  function collectLocalChanges(opts) {
70658
71066
  const cwd = opts?.cwd ?? process.cwd();
70659
71067
  const baseRef = opts?.baseRef ?? "HEAD~1";
70660
- const gitCheck = (0, import_node_child_process.spawnSync)("git", ["rev-parse", "--git-dir"], {
71068
+ const gitCheck = (0, import_node_child_process2.spawnSync)("git", ["rev-parse", "--git-dir"], {
70661
71069
  cwd,
70662
71070
  encoding: "utf8",
70663
71071
  stdio: ["ignore", "pipe", "pipe"]
@@ -70666,14 +71074,14 @@ function collectLocalChanges(opts) {
70666
71074
  return { kind: "no-git-repo", cwd };
70667
71075
  }
70668
71076
  const changedFiles = parseDiff(
70669
- (0, import_node_child_process.spawnSync)("git", ["diff", "--name-status", `${baseRef}..HEAD`], {
71077
+ (0, import_node_child_process2.spawnSync)("git", ["diff", "--name-status", `${baseRef}..HEAD`], {
70670
71078
  cwd,
70671
71079
  encoding: "utf8",
70672
71080
  stdio: ["ignore", "pipe", "pipe"]
70673
71081
  }).stdout ?? ""
70674
71082
  );
70675
71083
  const commits = parseLog(
70676
- (0, import_node_child_process.spawnSync)("git", ["log", "--oneline", `${baseRef}..HEAD`], {
71084
+ (0, import_node_child_process2.spawnSync)("git", ["log", "--oneline", `${baseRef}..HEAD`], {
70677
71085
  cwd,
70678
71086
  encoding: "utf8",
70679
71087
  stdio: ["ignore", "pipe", "pipe"]
@@ -70682,7 +71090,7 @@ function collectLocalChanges(opts) {
70682
71090
  return { kind: "local-changes", baseRef, changedFiles, commits };
70683
71091
  }
70684
71092
  function runGit(args2, cwd) {
70685
- const res = (0, import_node_child_process.spawnSync)("git", args2, {
71093
+ const res = (0, import_node_child_process2.spawnSync)("git", args2, {
70686
71094
  cwd: cwd ?? process.cwd(),
70687
71095
  encoding: "utf8",
70688
71096
  stdio: ["ignore", "pipe", "pipe"]
@@ -70698,7 +71106,7 @@ function getCurrentBranch(cwd) {
70698
71106
  return runGit(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
70699
71107
  }
70700
71108
  function isWorkingTreeDirty(cwd) {
70701
- const res = (0, import_node_child_process.spawnSync)("git", ["status", "--porcelain"], {
71109
+ const res = (0, import_node_child_process2.spawnSync)("git", ["status", "--porcelain"], {
70702
71110
  cwd: cwd ?? process.cwd(),
70703
71111
  encoding: "utf8",
70704
71112
  stdio: ["ignore", "pipe", "pipe"]
@@ -70833,18 +71241,18 @@ function redactOrDrop(input) {
70833
71241
 
70834
71242
  // ../../packages/cli/src/lib/update-notifier.ts
70835
71243
  init_cjs_shims();
70836
- var import_node_fs5 = require("fs");
70837
- var import_node_path5 = require("path");
70838
- var import_node_os3 = require("os");
71244
+ var import_node_fs6 = require("fs");
71245
+ var import_node_path6 = require("path");
71246
+ var import_node_os4 = require("os");
70839
71247
  var import_picocolors2 = __toESM(require_picocolors(), 1);
70840
71248
 
70841
71249
  // ../../packages/cli/src/commands/update.ts
70842
71250
  init_cjs_shims();
70843
- var import_node_fs4 = require("fs");
70844
- var import_node_path4 = require("path");
70845
- var import_node_os2 = require("os");
70846
- var import_node_crypto = require("crypto");
70847
- var import_node_child_process4 = require("child_process");
71251
+ var import_node_fs5 = require("fs");
71252
+ var import_node_path5 = require("path");
71253
+ var import_node_os3 = require("os");
71254
+ var import_node_crypto2 = require("crypto");
71255
+ var import_node_child_process5 = require("child_process");
70848
71256
  var import_node_util3 = require("util");
70849
71257
  var import_picocolors = __toESM(require_picocolors(), 1);
70850
71258
 
@@ -71082,12 +71490,12 @@ var SourceHttpClient = class {
71082
71490
 
71083
71491
  // ../../packages/connectors/src/source/lifecycle.ts
71084
71492
  init_cjs_shims();
71085
- var import_node_child_process2 = require("child_process");
71493
+ var import_node_child_process3 = require("child_process");
71086
71494
  var import_node_util = require("util");
71087
- var import_node_fs3 = require("fs");
71088
- var import_node_path3 = require("path");
71495
+ var import_node_fs4 = require("fs");
71496
+ var import_node_path4 = require("path");
71089
71497
  var import_node_net = require("net");
71090
- var exec = (0, import_node_util.promisify)(import_node_child_process2.execFile);
71498
+ var exec = (0, import_node_util.promisify)(import_node_child_process3.execFile);
71091
71499
  var SOURCE_BINARY = "horus-source";
71092
71500
  async function resolveSourceBin() {
71093
71501
  try {
@@ -71129,12 +71537,12 @@ async function assertSourceVersionPinned() {
71129
71537
  }
71130
71538
  }
71131
71539
  function isAnalyzed(root) {
71132
- return (0, import_node_fs3.existsSync)((0, import_node_path3.join)(root, ".horus", "source"));
71540
+ return (0, import_node_fs4.existsSync)((0, import_node_path4.join)(root, ".horus", "source"));
71133
71541
  }
71134
71542
  var CURRENT_STORE_BACKEND = (process.env["HORUS_SOURCE_STORAGE_BACKEND"] ?? "sqlite").trim().toLowerCase();
71135
71543
  function readSourceMeta(root) {
71136
71544
  try {
71137
- const raw = (0, import_node_fs3.readFileSync)((0, import_node_path3.join)(root, ".horus", "source", "meta.json"), "utf8");
71545
+ const raw = (0, import_node_fs4.readFileSync)((0, import_node_path4.join)(root, ".horus", "source", "meta.json"), "utf8");
71138
71546
  const j3 = JSON.parse(raw);
71139
71547
  const stats = j3["stats"] ?? void 0;
71140
71548
  return {
@@ -71154,7 +71562,7 @@ function metaHasEmbeddings(meta) {
71154
71562
  }
71155
71563
  function indexNeedsReanalyze(root) {
71156
71564
  if (!isAnalyzed(root)) return null;
71157
- if (CURRENT_STORE_BACKEND !== "kuzu" && (0, import_node_fs3.existsSync)((0, import_node_path3.join)(root, ".horus", "source", "kuzu"))) {
71565
+ if (CURRENT_STORE_BACKEND !== "kuzu" && (0, import_node_fs4.existsSync)((0, import_node_path4.join)(root, ".horus", "source", "kuzu"))) {
71158
71566
  return "legacy K\xF9zuDB store present";
71159
71567
  }
71160
71568
  const meta = readSourceMeta(root);
@@ -71188,20 +71596,20 @@ async function analyzeRepo(root) {
71188
71596
  }
71189
71597
  }
71190
71598
  function readSourceHostUrl(root) {
71191
- const p5 = (0, import_node_path3.join)(root, ".horus", "source", "host.json");
71192
- if (!(0, import_node_fs3.existsSync)(p5)) return null;
71599
+ const p5 = (0, import_node_path4.join)(root, ".horus", "source", "host.json");
71600
+ if (!(0, import_node_fs4.existsSync)(p5)) return null;
71193
71601
  try {
71194
- const j3 = JSON.parse((0, import_node_fs3.readFileSync)(p5, "utf8"));
71602
+ const j3 = JSON.parse((0, import_node_fs4.readFileSync)(p5, "utf8"));
71195
71603
  return typeof j3.host_url === "string" ? j3.host_url : null;
71196
71604
  } catch {
71197
71605
  return null;
71198
71606
  }
71199
71607
  }
71200
71608
  function readSourceHostPid(root) {
71201
- const p5 = (0, import_node_path3.join)(root, ".horus", "source", "host.json");
71202
- if (!(0, import_node_fs3.existsSync)(p5)) return null;
71609
+ const p5 = (0, import_node_path4.join)(root, ".horus", "source", "host.json");
71610
+ if (!(0, import_node_fs4.existsSync)(p5)) return null;
71203
71611
  try {
71204
- const j3 = JSON.parse((0, import_node_fs3.readFileSync)(p5, "utf8"));
71612
+ const j3 = JSON.parse((0, import_node_fs4.readFileSync)(p5, "utf8"));
71205
71613
  if (typeof j3.pid !== "number" || !Number.isInteger(j3.pid) || j3.pid <= 0) return null;
71206
71614
  return {
71207
71615
  pid: j3.pid,
@@ -71250,19 +71658,19 @@ async function findFreePort(start2 = 8420, end = 8520) {
71250
71658
  }
71251
71659
  var SPAWNED_HOST_FILE = "spawned-host.json";
71252
71660
  function readSpawnedHost(root) {
71253
- const p5 = (0, import_node_path3.join)(root, ".horus", SPAWNED_HOST_FILE);
71254
- if (!(0, import_node_fs3.existsSync)(p5)) return null;
71661
+ const p5 = (0, import_node_path4.join)(root, ".horus", SPAWNED_HOST_FILE);
71662
+ if (!(0, import_node_fs4.existsSync)(p5)) return null;
71255
71663
  try {
71256
- return JSON.parse((0, import_node_fs3.readFileSync)(p5, "utf8"));
71664
+ return JSON.parse((0, import_node_fs4.readFileSync)(p5, "utf8"));
71257
71665
  } catch {
71258
71666
  return null;
71259
71667
  }
71260
71668
  }
71261
71669
  function startHost(root, port) {
71262
- (0, import_node_fs3.mkdirSync)((0, import_node_path3.join)(root, ".horus"), { recursive: true });
71263
- const logPath = (0, import_node_path3.join)(root, ".horus", "source-host.log");
71264
- const fd = (0, import_node_fs3.openSync)(logPath, "a");
71265
- const child = (0, import_node_child_process2.spawn)(SOURCE_BINARY, ["host", "--port", String(port)], {
71670
+ (0, import_node_fs4.mkdirSync)((0, import_node_path4.join)(root, ".horus"), { recursive: true });
71671
+ const logPath = (0, import_node_path4.join)(root, ".horus", "source-host.log");
71672
+ const fd = (0, import_node_fs4.openSync)(logPath, "a");
71673
+ const child = (0, import_node_child_process3.spawn)(SOURCE_BINARY, ["host", "--port", String(port)], {
71266
71674
  cwd: root,
71267
71675
  detached: true,
71268
71676
  stdio: ["ignore", fd, fd]
@@ -71281,14 +71689,14 @@ function startHost(root, port) {
71281
71689
  root,
71282
71690
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
71283
71691
  };
71284
- (0, import_node_fs3.writeFileSync)((0, import_node_path3.join)(root, ".horus", SPAWNED_HOST_FILE), JSON.stringify(record2, null, 2) + "\n");
71692
+ (0, import_node_fs4.writeFileSync)((0, import_node_path4.join)(root, ".horus", SPAWNED_HOST_FILE), JSON.stringify(record2, null, 2) + "\n");
71285
71693
  }
71286
71694
  child.unref();
71287
71695
  }
71288
71696
  function removeSpawnedHostRecord(root) {
71289
- const p5 = (0, import_node_path3.join)(root, ".horus", SPAWNED_HOST_FILE);
71697
+ const p5 = (0, import_node_path4.join)(root, ".horus", SPAWNED_HOST_FILE);
71290
71698
  try {
71291
- (0, import_node_fs3.unlinkSync)(p5);
71699
+ (0, import_node_fs4.unlinkSync)(p5);
71292
71700
  } catch {
71293
71701
  }
71294
71702
  }
@@ -71329,8 +71737,8 @@ function reconcileSpawnedHost(root, actualPort) {
71329
71737
  const port = backend && Number.isFinite(backend.port) && backend.port > 0 ? backend.port : actualPort;
71330
71738
  if (spawned.pid === pid && spawned.port === port) return;
71331
71739
  const updated = { ...spawned, pid, port };
71332
- (0, import_node_fs3.writeFileSync)(
71333
- (0, import_node_path3.join)(root, ".horus", SPAWNED_HOST_FILE),
71740
+ (0, import_node_fs4.writeFileSync)(
71741
+ (0, import_node_path4.join)(root, ".horus", SPAWNED_HOST_FILE),
71334
71742
  JSON.stringify(updated, null, 2) + "\n"
71335
71743
  );
71336
71744
  } catch {
@@ -71340,7 +71748,7 @@ async function waitForOwnHost(root, requestedUrl, timeoutMs = 45e3) {
71340
71748
  const deadline = Date.now() + timeoutMs;
71341
71749
  const servesThisRepo = async (url) => {
71342
71750
  const served = await fetchHostRepoPath(url);
71343
- return served === null || (0, import_node_path3.resolve)(served) === (0, import_node_path3.resolve)(root);
71751
+ return served === null || (0, import_node_path4.resolve)(served) === (0, import_node_path4.resolve)(root);
71344
71752
  };
71345
71753
  while (Date.now() < deadline) {
71346
71754
  const candidates = [];
@@ -75160,9 +75568,9 @@ init_cjs_shims();
75160
75568
 
75161
75569
  // ../../packages/connectors/src/git/provider.ts
75162
75570
  init_cjs_shims();
75163
- var import_node_child_process3 = require("child_process");
75571
+ var import_node_child_process4 = require("child_process");
75164
75572
  var import_node_util2 = require("util");
75165
- var exec2 = (0, import_node_util2.promisify)(import_node_child_process3.execFile);
75573
+ var exec2 = (0, import_node_util2.promisify)(import_node_child_process4.execFile);
75166
75574
  function parseGitLog(stdout) {
75167
75575
  const commits = [];
75168
75576
  if (!stdout.trim()) return commits;
@@ -75420,7 +75828,7 @@ async function redisServerStatus(renv) {
75420
75828
  }
75421
75829
 
75422
75830
  // ../../packages/cli/src/commands/update.ts
75423
- var execFileAsync = (0, import_node_util3.promisify)(import_node_child_process4.execFile);
75831
+ var execFileAsync = (0, import_node_util3.promisify)(import_node_child_process5.execFile);
75424
75832
  async function ensureBackendPinned(write) {
75425
75833
  let installed = null;
75426
75834
  try {
@@ -75479,13 +75887,13 @@ async function fetchLatestRelease(_fetch = fetch) {
75479
75887
  return res.json();
75480
75888
  }
75481
75889
  function sha256hex(buf) {
75482
- return (0, import_node_crypto.createHash)("sha256").update(buf).digest("hex");
75890
+ return (0, import_node_crypto2.createHash)("sha256").update(buf).digest("hex");
75483
75891
  }
75484
75892
  function resolveBinaryPath() {
75485
75893
  const raw = process.argv[1];
75486
75894
  if (!raw) throw new Error("Cannot determine binary path from process.argv[1]");
75487
75895
  try {
75488
- return (0, import_node_fs4.realpathSync)(raw);
75896
+ return (0, import_node_fs5.realpathSync)(raw);
75489
75897
  } catch {
75490
75898
  return raw;
75491
75899
  }
@@ -75571,37 +75979,37 @@ ${import_picocolors.default.bold("Horus update")}
75571
75979
  write(` ${import_picocolors.default.red("\u2717")} ${e.message}`);
75572
75980
  return 1;
75573
75981
  }
75574
- if (!(0, import_node_fs4.existsSync)(binaryPath)) {
75982
+ if (!(0, import_node_fs5.existsSync)(binaryPath)) {
75575
75983
  write(` ${import_picocolors.default.red("\u2717")} Binary not found at ${binaryPath}`);
75576
75984
  return 1;
75577
75985
  }
75578
- const tmpPath = (0, import_node_path4.join)((0, import_node_os2.tmpdir)(), `horus-update-${tag}-${process.pid}`);
75986
+ const tmpPath = (0, import_node_path5.join)((0, import_node_os3.tmpdir)(), `horus-update-${tag}-${process.pid}`);
75579
75987
  const backupPath = `${binaryPath}.bak`;
75580
75988
  try {
75581
- (0, import_node_fs4.writeFileSync)(tmpPath, binBuf, { mode: 493 });
75989
+ (0, import_node_fs5.writeFileSync)(tmpPath, binBuf, { mode: 493 });
75582
75990
  } catch (e) {
75583
75991
  write(` ${import_picocolors.default.red("\u2717")} Could not write to temp dir: ${e.message}`);
75584
75992
  return 1;
75585
75993
  }
75586
75994
  try {
75587
- (0, import_node_fs4.renameSync)(binaryPath, backupPath);
75995
+ (0, import_node_fs5.renameSync)(binaryPath, backupPath);
75588
75996
  try {
75589
- (0, import_node_fs4.renameSync)(tmpPath, binaryPath);
75590
- (0, import_node_fs4.chmodSync)(binaryPath, 493);
75997
+ (0, import_node_fs5.renameSync)(tmpPath, binaryPath);
75998
+ (0, import_node_fs5.chmodSync)(binaryPath, 493);
75591
75999
  } catch (e) {
75592
76000
  try {
75593
- (0, import_node_fs4.renameSync)(backupPath, binaryPath);
76001
+ (0, import_node_fs5.renameSync)(backupPath, binaryPath);
75594
76002
  } catch {
75595
76003
  }
75596
76004
  throw e;
75597
76005
  }
75598
76006
  try {
75599
- (0, import_node_fs4.unlinkSync)(backupPath);
76007
+ (0, import_node_fs5.unlinkSync)(backupPath);
75600
76008
  } catch {
75601
76009
  }
75602
76010
  } catch (e) {
75603
76011
  try {
75604
- (0, import_node_fs4.unlinkSync)(tmpPath);
76012
+ (0, import_node_fs5.unlinkSync)(tmpPath);
75605
76013
  } catch {
75606
76014
  }
75607
76015
  const msg = e.message ?? String(e);
@@ -75623,7 +76031,7 @@ ${import_picocolors.default.bold("Horus update")}
75623
76031
  }
75624
76032
 
75625
76033
  // ../../packages/cli/src/lib/update-notifier.ts
75626
- var CACHE_PATH = (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".horus", "update-check.json");
76034
+ var CACHE_PATH = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".horus", "update-check.json");
75627
76035
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
75628
76036
  var RELEASES_API2 = "https://api.github.com/repos/meritt-dev/horus/releases/latest";
75629
76037
  var FETCH_TIMEOUT_MS = 2500;
@@ -75639,7 +76047,7 @@ function formatHint(latest, current) {
75639
76047
  }
75640
76048
  function readCache(path) {
75641
76049
  try {
75642
- const j3 = JSON.parse((0, import_node_fs5.readFileSync)(path, "utf8"));
76050
+ const j3 = JSON.parse((0, import_node_fs6.readFileSync)(path, "utf8"));
75643
76051
  if (typeof j3["latest"] === "string" && typeof j3["lastCheckMs"] === "number") {
75644
76052
  return { latest: j3["latest"], lastCheckMs: j3["lastCheckMs"] };
75645
76053
  }
@@ -75647,22 +76055,22 @@ function readCache(path) {
75647
76055
  }
75648
76056
  return null;
75649
76057
  }
75650
- function writeCache(path, cache) {
76058
+ function writeCache(path, cache2) {
75651
76059
  try {
75652
- (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(path), { recursive: true });
75653
- (0, import_node_fs5.writeFileSync)(path, JSON.stringify(cache) + "\n", "utf8");
76060
+ (0, import_node_fs6.mkdirSync)((0, import_node_path6.dirname)(path), { recursive: true });
76061
+ (0, import_node_fs6.writeFileSync)(path, JSON.stringify(cache2) + "\n", "utf8");
75654
76062
  } catch {
75655
76063
  }
75656
76064
  }
75657
- function decideNotification(cache, current, nowMs) {
76065
+ function decideNotification(cache2, current, nowMs) {
75658
76066
  let hint = null;
75659
- if (cache && cache.latest) {
76067
+ if (cache2 && cache2.latest) {
75660
76068
  try {
75661
- if (isNewer(cache.latest, current)) hint = formatHint(cache.latest, current);
76069
+ if (isNewer(cache2.latest, current)) hint = formatHint(cache2.latest, current);
75662
76070
  } catch {
75663
76071
  }
75664
76072
  }
75665
- const refreshDue = cache === null || nowMs - cache.lastCheckMs > CHECK_INTERVAL_MS;
76073
+ const refreshDue = cache2 === null || nowMs - cache2.lastCheckMs > CHECK_INTERVAL_MS;
75666
76074
  return { hint, refreshDue };
75667
76075
  }
75668
76076
  async function refresh(path, nowMs) {
@@ -75688,8 +76096,8 @@ function maybeNotifyUpdate() {
75688
76096
  try {
75689
76097
  if (isSuppressed()) return;
75690
76098
  const nowMs = Date.now();
75691
- const cache = readCache(CACHE_PATH);
75692
- const { hint, refreshDue } = decideNotification(cache, HORUS_VERSION, nowMs);
76099
+ const cache2 = readCache(CACHE_PATH);
76100
+ const { hint, refreshDue } = decideNotification(cache2, HORUS_VERSION, nowMs);
75693
76101
  if (hint) process.stderr.write(hint);
75694
76102
  if (refreshDue) void refresh(CACHE_PATH, nowMs);
75695
76103
  } catch {
@@ -75698,9 +76106,9 @@ function maybeNotifyUpdate() {
75698
76106
 
75699
76107
  // ../../packages/cli/src/lib/feedback-nudge.ts
75700
76108
  init_cjs_shims();
75701
- var import_node_fs10 = require("fs");
75702
- var import_node_path11 = require("path");
75703
- var import_node_os7 = require("os");
76109
+ var import_node_fs11 = require("fs");
76110
+ var import_node_path12 = require("path");
76111
+ var import_node_os8 = require("os");
75704
76112
  var import_picocolors5 = __toESM(require_picocolors(), 1);
75705
76113
 
75706
76114
  // ../../packages/db/src/index.ts
@@ -76751,7 +77159,7 @@ function sql(strings, ...params) {
76751
77159
  return new SQL([new StringChunk(str3)]);
76752
77160
  }
76753
77161
  sql2.raw = raw;
76754
- function join20(chunks, separator) {
77162
+ function join21(chunks, separator) {
76755
77163
  const result = [];
76756
77164
  for (const [i3, chunk] of chunks.entries()) {
76757
77165
  if (i3 > 0 && separator !== void 0) {
@@ -76761,7 +77169,7 @@ function sql(strings, ...params) {
76761
77169
  }
76762
77170
  return new SQL(result);
76763
77171
  }
76764
- sql2.join = join20;
77172
+ sql2.join = join21;
76765
77173
  function identifier(value) {
76766
77174
  return new Name(value);
76767
77175
  }
@@ -80352,7 +80760,7 @@ var PgSelectQueryBuilderBase = class extends TypedQueryBuilder {
80352
80760
  return (table, on2) => {
80353
80761
  const baseTableName = this.tableName;
80354
80762
  const tableName = getTableLikeName(table);
80355
- if (typeof tableName === "string" && this.config.joins?.some((join20) => join20.alias === tableName)) {
80763
+ if (typeof tableName === "string" && this.config.joins?.some((join21) => join21.alias === tableName)) {
80356
80764
  throw new Error(`Alias "${tableName}" is already used in this query`);
80357
80765
  }
80358
80766
  if (!this.isPartialSelect) {
@@ -81364,7 +81772,7 @@ var PgUpdateBase = class extends QueryPromise {
81364
81772
  createJoin(joinType) {
81365
81773
  return (table, on2) => {
81366
81774
  const tableName = getTableLikeName(table);
81367
- if (typeof tableName === "string" && this.config.joins.some((join20) => join20.alias === tableName)) {
81775
+ if (typeof tableName === "string" && this.config.joins.some((join21) => join21.alias === tableName)) {
81368
81776
  throw new Error(`Alias "${tableName}" is already used in this query`);
81369
81777
  }
81370
81778
  if (typeof on2 === "function") {
@@ -81460,10 +81868,10 @@ var PgUpdateBase = class extends QueryPromise {
81460
81868
  const fromFields = this.getTableLikeFields(this.config.from);
81461
81869
  fields[tableName] = fromFields;
81462
81870
  }
81463
- for (const join20 of this.config.joins) {
81464
- const tableName2 = getTableLikeName(join20.table);
81465
- if (typeof tableName2 === "string" && !is(join20.table, SQL)) {
81466
- const fromFields = this.getTableLikeFields(join20.table);
81871
+ for (const join21 of this.config.joins) {
81872
+ const tableName2 = getTableLikeName(join21.table);
81873
+ if (typeof tableName2 === "string" && !is(join21.table, SQL)) {
81874
+ const fromFields = this.getTableLikeFields(join21.table);
81467
81875
  fields[tableName2] = fromFields;
81468
81876
  }
81469
81877
  }
@@ -90456,9 +90864,9 @@ function drizzle2(...params) {
90456
90864
  })(drizzle2 || (drizzle2 = {}));
90457
90865
 
90458
90866
  // ../../packages/db/src/client.ts
90459
- var import_node_os4 = require("os");
90460
- var import_node_path6 = require("path");
90461
- var import_node_fs6 = require("fs");
90867
+ var import_node_os5 = require("os");
90868
+ var import_node_path7 = require("path");
90869
+ var import_node_fs7 = require("fs");
90462
90870
  var import_node_url2 = require("url");
90463
90871
 
90464
90872
  // ../../packages/db/src/guard.ts
@@ -90659,8 +91067,8 @@ function createDb(url, opts) {
90659
91067
  return { db, sql: sql2 };
90660
91068
  }
90661
91069
  function localDbPath() {
90662
- const dir = process.env["HORUS_DB_DIR"] || (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".horus");
90663
- return (0, import_node_path6.join)(dir, "horus.db");
91070
+ const dir = process.env["HORUS_DB_DIR"] || (0, import_node_path7.join)((0, import_node_os5.homedir)(), ".horus");
91071
+ return (0, import_node_path7.join)(dir, "horus.db");
90664
91072
  }
90665
91073
  var DEFAULT_LOCAL_PG_URL = "postgresql://horus:horus@localhost:5433/horus";
90666
91074
  function shouldUseEmbeddedDb(url) {
@@ -90719,7 +91127,7 @@ async function applyEmbeddedMigrations(client) {
90719
91127
  async function createLocalDb(opts) {
90720
91128
  const dataDir = opts?.path ?? localDbPath();
90721
91129
  try {
90722
- (0, import_node_fs6.mkdirSync)(dataDir.replace(/[^/]+$/, ""), { recursive: true });
91130
+ (0, import_node_fs7.mkdirSync)(dataDir.replace(/[^/]+$/, ""), { recursive: true });
90723
91131
  } catch {
90724
91132
  }
90725
91133
  assertEmbeddedAssetsPresent();
@@ -90752,20 +91160,20 @@ async function acquireDbLock(dataDir) {
90752
91160
  };
90753
91161
  for (; ; ) {
90754
91162
  try {
90755
- const fd = (0, import_node_fs6.openSync)(lockPath, "wx");
90756
- (0, import_node_fs6.writeSync)(fd, `${process.pid} ${Date.now()}`);
90757
- (0, import_node_fs6.closeSync)(fd);
91163
+ const fd = (0, import_node_fs7.openSync)(lockPath, "wx");
91164
+ (0, import_node_fs7.writeSync)(fd, `${process.pid} ${Date.now()}`);
91165
+ (0, import_node_fs7.closeSync)(fd);
90758
91166
  return () => {
90759
91167
  try {
90760
- (0, import_node_fs6.unlinkSync)(lockPath);
91168
+ (0, import_node_fs7.unlinkSync)(lockPath);
90761
91169
  } catch {
90762
91170
  }
90763
91171
  };
90764
91172
  } catch (e) {
90765
91173
  if (e.code !== "EEXIST") return noop3;
90766
91174
  try {
90767
- if (Date.now() - (0, import_node_fs6.statSync)(lockPath).mtimeMs > STALE_MS) {
90768
- (0, import_node_fs6.unlinkSync)(lockPath);
91175
+ if (Date.now() - (0, import_node_fs7.statSync)(lockPath).mtimeMs > STALE_MS) {
91176
+ (0, import_node_fs7.unlinkSync)(lockPath);
90769
91177
  continue;
90770
91178
  }
90771
91179
  } catch {
@@ -90779,9 +91187,9 @@ async function acquireDbLock(dataDir) {
90779
91187
  var EMBEDDED_PGLITE_ASSETS = ["pglite.wasm", "pglite.data", "initdb.wasm"];
90780
91188
  function assertEmbeddedAssetsPresent() {
90781
91189
  if (false) return;
90782
- const selfDir = (0, import_node_path6.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
91190
+ const selfDir = (0, import_node_path7.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
90783
91191
  for (const asset of EMBEDDED_PGLITE_ASSETS) {
90784
- if (!(0, import_node_fs6.existsSync)((0, import_node_path6.join)(selfDir, asset))) {
91192
+ if (!(0, import_node_fs7.existsSync)((0, import_node_path7.join)(selfDir, asset))) {
90785
91193
  throw new Error(
90786
91194
  `HORUS_DB_UNAVAILABLE: embedded database asset missing (${asset}). This build does not ship local persistence \u2014 install via npm or Homebrew, or set DATABASE_URL.`
90787
91195
  );
@@ -90931,21 +91339,21 @@ init_cjs_shims();
90931
91339
 
90932
91340
  // ../../node_modules/.pnpm/drizzle-orm@0.38.4_@electric-sql+pglite@0.5.3_@types+pg@8.20.0_pg@8.22.0_postgres@3.4.9/node_modules/drizzle-orm/migrator.js
90933
91341
  init_cjs_shims();
90934
- var import_node_crypto2 = __toESM(require("crypto"), 1);
90935
- var import_node_fs7 = __toESM(require("fs"), 1);
91342
+ var import_node_crypto3 = __toESM(require("crypto"), 1);
91343
+ var import_node_fs8 = __toESM(require("fs"), 1);
90936
91344
  function readMigrationFiles(config2) {
90937
91345
  const migrationFolderTo = config2.migrationsFolder;
90938
91346
  const migrationQueries = [];
90939
91347
  const journalPath = `${migrationFolderTo}/meta/_journal.json`;
90940
- if (!import_node_fs7.default.existsSync(journalPath)) {
91348
+ if (!import_node_fs8.default.existsSync(journalPath)) {
90941
91349
  throw new Error(`Can't find meta/_journal.json file`);
90942
91350
  }
90943
- const journalAsString = import_node_fs7.default.readFileSync(`${migrationFolderTo}/meta/_journal.json`).toString();
91351
+ const journalAsString = import_node_fs8.default.readFileSync(`${migrationFolderTo}/meta/_journal.json`).toString();
90944
91352
  const journal = JSON.parse(journalAsString);
90945
91353
  for (const journalEntry of journal.entries) {
90946
91354
  const migrationPath = `${migrationFolderTo}/${journalEntry.tag}.sql`;
90947
91355
  try {
90948
- const query = import_node_fs7.default.readFileSync(`${migrationFolderTo}/${journalEntry.tag}.sql`).toString();
91356
+ const query = import_node_fs8.default.readFileSync(`${migrationFolderTo}/${journalEntry.tag}.sql`).toString();
90949
91357
  const result = query.split("--> statement-breakpoint").map((it2) => {
90950
91358
  return it2;
90951
91359
  });
@@ -90953,7 +91361,7 @@ function readMigrationFiles(config2) {
90953
91361
  sql: result,
90954
91362
  bps: journalEntry.breakpoints,
90955
91363
  folderMillis: journalEntry.when,
90956
- hash: import_node_crypto2.default.createHash("sha256").update(query).digest("hex")
91364
+ hash: import_node_crypto3.default.createHash("sha256").update(query).digest("hex")
90957
91365
  });
90958
91366
  } catch {
90959
91367
  throw new Error(`No file ${migrationPath} found in ${migrationFolderTo} folder`);
@@ -90970,8 +91378,8 @@ async function migrate(db, config2) {
90970
91378
 
90971
91379
  // ../../packages/db/src/migrate.ts
90972
91380
  var import_node_url3 = require("url");
90973
- var import_node_path7 = require("path");
90974
- var migrationsFolder = (0, import_node_path7.resolve)((0, import_node_path7.dirname)((0, import_node_url3.fileURLToPath)(importMetaUrl)), "../drizzle");
91381
+ var import_node_path8 = require("path");
91382
+ var migrationsFolder = (0, import_node_path8.resolve)((0, import_node_path8.dirname)((0, import_node_url3.fileURLToPath)(importMetaUrl)), "../drizzle");
90975
91383
  async function runMigrations(url) {
90976
91384
  assertLocalDatabaseUrl(url);
90977
91385
  const sql2 = src_default(url, { max: 1, onnotice: () => {
@@ -90983,7 +91391,7 @@ async function runMigrations(url) {
90983
91391
  }
90984
91392
  }
90985
91393
  var entry = process.argv[1];
90986
- var invokedDirectly = entry !== void 0 && (0, import_node_url3.fileURLToPath)(importMetaUrl) === (0, import_node_path7.resolve)(entry) && (0, import_node_path7.basename)(entry).replace(/\.[cm]?[jt]s$/, "") === "migrate";
91394
+ var invokedDirectly = entry !== void 0 && (0, import_node_url3.fileURLToPath)(importMetaUrl) === (0, import_node_path8.resolve)(entry) && (0, import_node_path8.basename)(entry).replace(/\.[cm]?[jt]s$/, "") === "migrate";
90987
91395
  if (invokedDirectly) {
90988
91396
  const url = process.env.DATABASE_URL ?? "postgresql://horus:horus@localhost:5433/horus";
90989
91397
  runMigrations(url).then(() => {
@@ -91053,43 +91461,43 @@ var import_picocolors3 = __toESM(require_picocolors(), 1);
91053
91461
 
91054
91462
  // ../../packages/cli/src/lib/telemetry/client.ts
91055
91463
  init_cjs_shims();
91056
- var import_node_crypto4 = require("crypto");
91057
- var import_node_os6 = require("os");
91464
+ var import_node_crypto5 = require("crypto");
91465
+ var import_node_os7 = require("os");
91058
91466
 
91059
91467
  // ../../packages/cli/src/lib/telemetry/consent.ts
91060
91468
  init_cjs_shims();
91061
91469
 
91062
91470
  // ../../packages/cli/src/lib/telemetry/store.ts
91063
91471
  init_cjs_shims();
91064
- var import_node_fs8 = require("fs");
91065
- var import_node_crypto3 = require("crypto");
91472
+ var import_node_fs9 = require("fs");
91473
+ var import_node_crypto4 = require("crypto");
91066
91474
 
91067
91475
  // ../../packages/cli/src/lib/cloud/paths.ts
91068
91476
  init_cjs_shims();
91069
- var import_node_path8 = require("path");
91070
- var import_node_os5 = require("os");
91477
+ var import_node_path9 = require("path");
91478
+ var import_node_os6 = require("os");
91071
91479
  var CLOUD_CONFIG_FILE = "cloud.json";
91072
91480
  var AUTH_FILE = "auth.json";
91073
91481
  function cloudConfigPath(root) {
91074
- return (0, import_node_path8.join)(root, HORUS_DIR, CLOUD_CONFIG_FILE);
91482
+ return (0, import_node_path9.join)(root, HORUS_DIR, CLOUD_CONFIG_FILE);
91075
91483
  }
91076
91484
  function horusHome() {
91077
- return process.env.HORUS_HOME ?? (0, import_node_path8.join)((0, import_node_os5.homedir)(), HORUS_DIR);
91485
+ return process.env.HORUS_HOME ?? (0, import_node_path9.join)((0, import_node_os6.homedir)(), HORUS_DIR);
91078
91486
  }
91079
91487
  function authPath() {
91080
- return (0, import_node_path8.join)(horusHome(), AUTH_FILE);
91488
+ return (0, import_node_path9.join)(horusHome(), AUTH_FILE);
91081
91489
  }
91082
91490
 
91083
91491
  // ../../packages/cli/src/lib/telemetry/paths.ts
91084
91492
  init_cjs_shims();
91085
- var import_node_path9 = require("path");
91493
+ var import_node_path10 = require("path");
91086
91494
  var TELEMETRY_FILE = "telemetry.json";
91087
91495
  var TELEMETRY_QUEUE_DIR = "telemetry-queue";
91088
91496
  function telemetryPath() {
91089
- return (0, import_node_path9.join)(horusHome(), TELEMETRY_FILE);
91497
+ return (0, import_node_path10.join)(horusHome(), TELEMETRY_FILE);
91090
91498
  }
91091
91499
  function telemetryQueueDir() {
91092
- return (0, import_node_path9.join)(horusHome(), TELEMETRY_QUEUE_DIR);
91500
+ return (0, import_node_path10.join)(horusHome(), TELEMETRY_QUEUE_DIR);
91093
91501
  }
91094
91502
 
91095
91503
  // ../../packages/cli/src/lib/telemetry/store.ts
@@ -91097,7 +91505,7 @@ var TELEMETRY_SCHEMA_VERSION = 1;
91097
91505
  function nowIso() {
91098
91506
  return (/* @__PURE__ */ new Date()).toISOString();
91099
91507
  }
91100
- function defaultTelemetryState(installId = (0, import_node_crypto3.randomUUID)()) {
91508
+ function defaultTelemetryState(installId = (0, import_node_crypto4.randomUUID)()) {
91101
91509
  const now = nowIso();
91102
91510
  return {
91103
91511
  schemaVersion: TELEMETRY_SCHEMA_VERSION,
@@ -91131,29 +91539,29 @@ function coerce2(raw) {
91131
91539
  }
91132
91540
  function readTelemetryState() {
91133
91541
  const p5 = telemetryPath();
91134
- if (!(0, import_node_fs8.existsSync)(p5)) return null;
91542
+ if (!(0, import_node_fs9.existsSync)(p5)) return null;
91135
91543
  try {
91136
- return coerce2(JSON.parse((0, import_node_fs8.readFileSync)(p5, "utf8")));
91544
+ return coerce2(JSON.parse((0, import_node_fs9.readFileSync)(p5, "utf8")));
91137
91545
  } catch {
91138
91546
  return null;
91139
91547
  }
91140
91548
  }
91141
91549
  function writeTelemetryState(state) {
91142
- (0, import_node_fs8.mkdirSync)(horusHome(), { recursive: true });
91550
+ (0, import_node_fs9.mkdirSync)(horusHome(), { recursive: true });
91143
91551
  const p5 = telemetryPath();
91144
91552
  const tmp = `${p5}.${process.pid}.tmp`;
91145
- (0, import_node_fs8.writeFileSync)(tmp, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
91553
+ (0, import_node_fs9.writeFileSync)(tmp, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
91146
91554
  try {
91147
- (0, import_node_fs8.renameSync)(tmp, p5);
91555
+ (0, import_node_fs9.renameSync)(tmp, p5);
91148
91556
  } catch (err2) {
91149
91557
  try {
91150
- (0, import_node_fs8.rmSync)(tmp);
91558
+ (0, import_node_fs9.rmSync)(tmp);
91151
91559
  } catch {
91152
91560
  }
91153
91561
  throw err2;
91154
91562
  }
91155
91563
  try {
91156
- (0, import_node_fs8.chmodSync)(p5, 384);
91564
+ (0, import_node_fs9.chmodSync)(p5, 384);
91157
91565
  } catch {
91158
91566
  }
91159
91567
  }
@@ -91173,7 +91581,7 @@ function updateTelemetryState(mutate) {
91173
91581
  }
91174
91582
  function deleteTelemetryState() {
91175
91583
  const p5 = telemetryPath();
91176
- if ((0, import_node_fs8.existsSync)(p5)) (0, import_node_fs8.rmSync)(p5);
91584
+ if ((0, import_node_fs9.existsSync)(p5)) (0, import_node_fs9.rmSync)(p5);
91177
91585
  }
91178
91586
 
91179
91587
  // ../../packages/cli/src/lib/telemetry/consent.ts
@@ -91251,32 +91659,32 @@ function isContentSharingEnabled(env = process.env) {
91251
91659
 
91252
91660
  // ../../packages/cli/src/lib/telemetry/spool.ts
91253
91661
  init_cjs_shims();
91254
- var import_node_fs9 = require("fs");
91255
- var import_node_path10 = require("path");
91662
+ var import_node_fs10 = require("fs");
91663
+ var import_node_path11 = require("path");
91256
91664
  var SPOOL_FILE = "events.jsonl";
91257
91665
  var MAX_SPOOL_BYTES = 256 * 1024;
91258
91666
  function spoolFilePath() {
91259
- return (0, import_node_path10.join)(telemetryQueueDir(), SPOOL_FILE);
91667
+ return (0, import_node_path11.join)(telemetryQueueDir(), SPOOL_FILE);
91260
91668
  }
91261
91669
  function spoolEvent(event) {
91262
91670
  try {
91263
- (0, import_node_fs9.mkdirSync)(telemetryQueueDir(), { recursive: true });
91671
+ (0, import_node_fs10.mkdirSync)(telemetryQueueDir(), { recursive: true });
91264
91672
  const file = spoolFilePath();
91265
91673
  let size2 = 0;
91266
91674
  try {
91267
- size2 = (0, import_node_fs9.statSync)(file).size;
91675
+ size2 = (0, import_node_fs10.statSync)(file).size;
91268
91676
  } catch {
91269
91677
  }
91270
91678
  if (size2 >= MAX_SPOOL_BYTES) return;
91271
- (0, import_node_fs9.appendFileSync)(file, JSON.stringify(event) + "\n", { mode: 384 });
91679
+ (0, import_node_fs10.appendFileSync)(file, JSON.stringify(event) + "\n", { mode: 384 });
91272
91680
  } catch {
91273
91681
  }
91274
91682
  }
91275
91683
  function readSpooledEvents() {
91276
91684
  try {
91277
91685
  const file = spoolFilePath();
91278
- if (!(0, import_node_fs9.existsSync)(file)) return [];
91279
- return (0, import_node_fs9.readFileSync)(file, "utf8").split("\n").filter((line2) => line2.trim().length > 0).map((line2) => {
91686
+ if (!(0, import_node_fs10.existsSync)(file)) return [];
91687
+ return (0, import_node_fs10.readFileSync)(file, "utf8").split("\n").filter((line2) => line2.trim().length > 0).map((line2) => {
91280
91688
  try {
91281
91689
  return JSON.parse(line2);
91282
91690
  } catch {
@@ -91290,7 +91698,7 @@ function readSpooledEvents() {
91290
91698
  function clearSpool() {
91291
91699
  try {
91292
91700
  const file = spoolFilePath();
91293
- if ((0, import_node_fs9.existsSync)(file)) (0, import_node_fs9.rmSync)(file);
91701
+ if ((0, import_node_fs10.existsSync)(file)) (0, import_node_fs10.rmSync)(file);
91294
91702
  } catch {
91295
91703
  }
91296
91704
  }
@@ -91316,7 +91724,7 @@ function extractFlagNames(argv) {
91316
91724
  // ../../packages/cli/src/lib/telemetry/client.ts
91317
91725
  var sessionId = null;
91318
91726
  function getSessionId() {
91319
- if (!sessionId) sessionId = (0, import_node_crypto4.randomUUID)();
91727
+ if (!sessionId) sessionId = (0, import_node_crypto5.randomUUID)();
91320
91728
  return sessionId;
91321
91729
  }
91322
91730
  function track(input) {
@@ -91333,8 +91741,8 @@ function track(input) {
91333
91741
  installId: state.installId,
91334
91742
  sessionId: getSessionId(),
91335
91743
  cliVersion: HORUS_VERSION,
91336
- os: (0, import_node_os6.platform)(),
91337
- arch: (0, import_node_os6.arch)(),
91744
+ os: (0, import_node_os7.platform)(),
91745
+ arch: (0, import_node_os7.arch)(),
91338
91746
  ...input
91339
91747
  };
91340
91748
  spoolEvent(event);
@@ -91484,7 +91892,7 @@ async function runFeedback(investigationId, opts = {}) {
91484
91892
  }
91485
91893
 
91486
91894
  // ../../packages/cli/src/lib/feedback-nudge.ts
91487
- var STATE_PATH = (0, import_node_path11.join)((0, import_node_os7.homedir)(), ".horus", "feedback-nudge.json");
91895
+ var STATE_PATH = (0, import_node_path12.join)((0, import_node_os8.homedir)(), ".horus", "feedback-nudge.json");
91488
91896
  var MIN_AGE_MS = 2 * 60 * 60 * 1e3;
91489
91897
  var RATE_LIMIT_MS = 20 * 60 * 60 * 1e3;
91490
91898
  var MAX_REMEMBERED = 50;
@@ -91500,7 +91908,7 @@ function isSuppressed2(env = process.env, isTTY = Boolean(process.stdin.isTTY &&
91500
91908
  }
91501
91909
  function readState(path = STATE_PATH) {
91502
91910
  try {
91503
- const j3 = JSON.parse((0, import_node_fs10.readFileSync)(path, "utf8"));
91911
+ const j3 = JSON.parse((0, import_node_fs11.readFileSync)(path, "utf8"));
91504
91912
  const lastPromptMs = typeof j3["lastPromptMs"] === "number" ? j3["lastPromptMs"] : 0;
91505
91913
  const promptedIds = Array.isArray(j3["promptedIds"]) ? j3["promptedIds"].filter((x4) => typeof x4 === "string") : [];
91506
91914
  return { lastPromptMs, promptedIds };
@@ -91510,12 +91918,12 @@ function readState(path = STATE_PATH) {
91510
91918
  }
91511
91919
  function writeState(state, path = STATE_PATH) {
91512
91920
  try {
91513
- (0, import_node_fs10.mkdirSync)((0, import_node_path11.dirname)(path), { recursive: true });
91921
+ (0, import_node_fs11.mkdirSync)((0, import_node_path12.dirname)(path), { recursive: true });
91514
91922
  const trimmed = {
91515
91923
  lastPromptMs: state.lastPromptMs,
91516
91924
  promptedIds: state.promptedIds.slice(-MAX_REMEMBERED)
91517
91925
  };
91518
- (0, import_node_fs10.writeFileSync)(path, JSON.stringify(trimmed) + "\n", "utf8");
91926
+ (0, import_node_fs11.writeFileSync)(path, JSON.stringify(trimmed) + "\n", "utf8");
91519
91927
  } catch {
91520
91928
  }
91521
91929
  }
@@ -94396,7 +94804,7 @@ init_cjs_shims();
94396
94804
 
94397
94805
  // ../../packages/engine/src/memory-detect.ts
94398
94806
  init_cjs_shims();
94399
- var import_node_crypto5 = require("crypto");
94807
+ var import_node_crypto6 = require("crypto");
94400
94808
 
94401
94809
  // ../../packages/engine/src/memory-store.ts
94402
94810
  init_cjs_shims();
@@ -94482,7 +94890,7 @@ function sharedNonGenericTags(a2, b5) {
94482
94890
  }
94483
94891
  function recurrenceEdgeId(idA, idB) {
94484
94892
  const [lo, hi] = idA <= idB ? [idA, idB] : [idB, idA];
94485
- const h3 = (0, import_node_crypto5.createHash)("sha256").update(`recurs-with\0${lo}\0${hi}`).digest("hex");
94893
+ const h3 = (0, import_node_crypto6.createHash)("sha256").update(`recurs-with\0${lo}\0${hi}`).digest("hex");
94486
94894
  return `lnk_recurs_${h3.slice(0, 32)}`;
94487
94895
  }
94488
94896
  function normalizeCause(s5) {
@@ -95518,9 +95926,9 @@ function computeWeightedEvidenceConfidence(evidence2, ambientEvidenceIds) {
95518
95926
 
95519
95927
  // ../../packages/engine/src/git-collector.ts
95520
95928
  init_cjs_shims();
95521
- var import_node_child_process5 = require("child_process");
95929
+ var import_node_child_process6 = require("child_process");
95522
95930
  var import_node_util4 = require("util");
95523
- var exec3 = (0, import_node_util4.promisify)(import_node_child_process5.execFile);
95931
+ var exec3 = (0, import_node_util4.promisify)(import_node_child_process6.execFile);
95524
95932
  var DEFAULT_MAX_COMMITS = 50;
95525
95933
  var DEFAULT_MAX_FILES = 100;
95526
95934
  var DEFAULT_MAX_BYTES = 5e4;
@@ -96398,6 +96806,13 @@ function isNoiseCommit(commit) {
96398
96806
  return true;
96399
96807
  }
96400
96808
  if (/pre-commit.*autoupdate/i.test(subject) || /\[pre-commit\.ci\]/i.test(subject)) return true;
96809
+ if (/^(docs|style|test|ci)(\([^)]*\))?[:!]/i.test(subject)) return true;
96810
+ if (/\b(reformat|whitespace|prettier|eslint)\b/i.test(subject)) return true;
96811
+ if (/\bcode\s*(style|formatting)\b/i.test(subject)) return true;
96812
+ if (/\bclean\s*up\b[^.]*\bformat/i.test(subject)) return true;
96813
+ if (/\b(documentation|docs|readme)\b/i.test(subject) && !/\b(endpoint|api|service|handler|controller|component|module|feature|migration|schema|query|cache|queue|webhook|sdk|cli|route)\b/i.test(subject)) {
96814
+ return true;
96815
+ }
96401
96816
  return false;
96402
96817
  }
96403
96818
  function seedTouchedByRelevantChange(recentChanges, seedFile) {
@@ -96409,6 +96824,26 @@ function seedTouchedByRelevantChange(recentChanges, seedFile) {
96409
96824
  (c4) => !isNoiseCommit(c4) && c4.files.some(matchesSeed)
96410
96825
  );
96411
96826
  }
96827
+ function seedTouchingCommitFocus(recentChanges, seedFile) {
96828
+ if (recentChanges === void 0 || seedFile === void 0) return null;
96829
+ if (recentChanges.degenerate) return null;
96830
+ const matchesSeed = (f5) => f5 === seedFile || seedFile.endsWith(f5) || f5.endsWith(seedFile);
96831
+ let min = null;
96832
+ for (const c4 of recentChanges.commits) {
96833
+ if (isNoiseCommit(c4)) continue;
96834
+ if (!c4.files.some(matchesSeed)) continue;
96835
+ const n4 = c4.files.length;
96836
+ if (min === null || n4 < min) min = n4;
96837
+ }
96838
+ return min;
96839
+ }
96840
+ function regressionSeedTouchedScore(focus) {
96841
+ if (focus === null) return 0.18;
96842
+ if (focus <= 4) return 0.45;
96843
+ if (focus <= 8) return 0.38;
96844
+ if (focus <= 14) return 0.3;
96845
+ return 0.2;
96846
+ }
96412
96847
  function formatRegressionCitation(recentChanges, changes, seedFile) {
96413
96848
  const matchesSeed = (f5) => seedFile === void 0 || f5 === seedFile || seedFile.endsWith(f5) || f5.endsWith(seedFile);
96414
96849
  const all = (recentChanges?.commits ?? []).filter((c4) => !isNoiseCommit(c4));
@@ -97747,7 +98182,11 @@ async function investigate(input, deps) {
97747
98182
  category: "deployment-regression",
97748
98183
  sourceEvidenceIds: [changeEvId, ...seedEv ? [seedEv.id] : []],
97749
98184
  // A regression NOT backed by a seed-touching commit must not score like one that is.
97750
- baseScore: clamp015((seedInChanges ? 0.45 : 0.18) + (queueHits.length > 0 ? 0.05 : 0)),
98185
+ // HOR-451: scale the seed-touched prior by commit focus — a broad/diffuse commit that merely
98186
+ // touched the seed no longer outranks an evidence-backed runtime cause.
98187
+ baseScore: clamp015(
98188
+ (seedInChanges ? regressionSeedTouchedScore(seedTouchingCommitFocus(recentChanges, top?.filePath)) : 0.18) + (queueHits.length > 0 ? 0.05 : 0)
98189
+ ),
97751
98190
  metadata: { blastRadius }
97752
98191
  });
97753
98192
  }
@@ -97786,32 +98225,31 @@ async function investigate(input, deps) {
97786
98225
  const raiser = bySeed ? top.name : lead.raiserName || top.name;
97787
98226
  const depClause = bySeed ? "" : `, a dependency of ${top.name}`;
97788
98227
  const calleePenalty = bySeed ? 0 : 0.18;
97789
- let title;
97790
- let baseScore;
97791
- if (tier === SEV_ERROR) {
97792
- title = bySeed ? `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) is raised by ${raiser} \u2014 the likely failure${msgClause}` : `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) surfaces on ${raiser}${depClause}${msgClause}`;
97793
- baseScore = clamp015(0.6 + volumeBoost - calleePenalty);
97794
- } else if (tier === SEV_WARN) {
97795
- title = `Warning ${lead.code} (${lead.count}x in Elasticsearch) ${bySeed ? "is raised by" : "surfaces on"} ${raiser}${depClause}${msgClause}`;
97796
- baseScore = clamp015(0.42 + volumeBoost - calleePenalty);
97797
- } else {
97798
- title = `Diagnostic signal ${lead.code} (${lead.count}x in Elasticsearch) is logged by ${raiser}${depClause} \u2014 informational, not an error${msgClause}`;
97799
- baseScore = clamp015(0.3 + volumeBoost - calleePenalty);
97800
- }
97801
- causeInputs.push({
97802
- id: "cause:seed-emitted-error",
97803
- title: title.slice(0, 220),
97804
- category: "error-correlation",
97805
- sourceEvidenceIds,
97806
- baseScore,
97807
- metadata: {
97808
- blastRadius,
97809
- seedEmitted: true,
97810
- code: lead.code,
97811
- count: lead.count,
97812
- severity: tier === SEV_ERROR ? "error" : tier === SEV_WARN ? "warn" : "info"
98228
+ if (tier === SEV_ERROR || tier === SEV_WARN) {
98229
+ let title;
98230
+ let baseScore;
98231
+ if (tier === SEV_ERROR) {
98232
+ title = bySeed ? `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) is raised by ${raiser} \u2014 the likely failure${msgClause}` : `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) surfaces on ${raiser}${depClause}${msgClause}`;
98233
+ baseScore = clamp015(0.6 + volumeBoost - calleePenalty);
98234
+ } else {
98235
+ title = `Warning ${lead.code} (${lead.count}x in Elasticsearch) ${bySeed ? "is raised by" : "surfaces on"} ${raiser}${depClause}${msgClause}`;
98236
+ baseScore = clamp015(0.42 + volumeBoost - calleePenalty);
97813
98237
  }
97814
- });
98238
+ causeInputs.push({
98239
+ id: "cause:seed-emitted-error",
98240
+ title: title.slice(0, 220),
98241
+ category: "error-correlation",
98242
+ sourceEvidenceIds,
98243
+ baseScore,
98244
+ metadata: {
98245
+ blastRadius,
98246
+ seedEmitted: true,
98247
+ code: lead.code,
98248
+ count: lead.count,
98249
+ severity: tier === SEV_ERROR ? "error" : "warn"
98250
+ }
98251
+ });
98252
+ }
97815
98253
  }
97816
98254
  }
97817
98255
  if (top && seedEv && ctx && code && !sourceImpactHint) {
@@ -98938,7 +99376,7 @@ function blastRadiusToJSON(r) {
98938
99376
 
98939
99377
  // ../../packages/engine/src/memory-recall.ts
98940
99378
  init_cjs_shims();
98941
- var import_node_crypto6 = require("crypto");
99379
+ var import_node_crypto7 = require("crypto");
98942
99380
  var FRESHNESS_HALF_LIFE_DAYS = 30;
98943
99381
  var NO_ANCHOR_DECAY = 0.5;
98944
99382
  var STALE_RANK_FACTOR = 0.5;
@@ -98958,7 +99396,7 @@ function recallCodeProviderFromCodeProvider(code) {
98958
99396
  };
98959
99397
  }
98960
99398
  function hashNodeContent(content) {
98961
- return "sha256:" + (0, import_node_crypto6.createHash)("sha256").update(content, "utf8").digest("hex");
99399
+ return "sha256:" + (0, import_node_crypto7.createHash)("sha256").update(content, "utf8").digest("hex");
98962
99400
  }
98963
99401
  function clamp016(n4) {
98964
99402
  if (!Number.isFinite(n4)) return 0;
@@ -101561,7 +101999,7 @@ function renderReport2(top, ctx, impact, flows, siblings) {
101561
101999
 
101562
102000
  // ../../packages/cli/src/commands/index-repo.ts
101563
102001
  init_cjs_shims();
101564
- var import_node_path17 = require("path");
102002
+ var import_node_path18 = require("path");
101565
102003
  var import_picocolors9 = __toESM(require_picocolors(), 1);
101566
102004
 
101567
102005
  // ../../packages/knowledge/src/index.ts
@@ -101770,7 +102208,7 @@ var KnowledgeManifestSchema = external_exports.object({
101770
102208
 
101771
102209
  // ../../packages/knowledge/src/layout.ts
101772
102210
  init_cjs_shims();
101773
- var import_node_path12 = require("path");
102211
+ var import_node_path13 = require("path");
101774
102212
  var HORUS_DIR2 = ".horus";
101775
102213
  var KNOWLEDGE_DIR = "index";
101776
102214
  var KNOWLEDGE_FILES = {
@@ -101785,37 +102223,37 @@ var KNOWLEDGE_FILES = {
101785
102223
  db: "index.db"
101786
102224
  };
101787
102225
  function knowledgeDir(root) {
101788
- return (0, import_node_path12.join)(root, HORUS_DIR2, KNOWLEDGE_DIR);
102226
+ return (0, import_node_path13.join)(root, HORUS_DIR2, KNOWLEDGE_DIR);
101789
102227
  }
101790
102228
  function knowledgePath(root, file) {
101791
- return (0, import_node_path12.join)(knowledgeDir(root), KNOWLEDGE_FILES[file]);
102229
+ return (0, import_node_path13.join)(knowledgeDir(root), KNOWLEDGE_FILES[file]);
101792
102230
  }
101793
102231
 
101794
102232
  // ../../packages/knowledge/src/store.ts
101795
102233
  init_cjs_shims();
101796
- var import_node_crypto7 = require("crypto");
101797
- var import_node_fs11 = require("fs");
101798
- var import_node_path13 = require("path");
102234
+ var import_node_crypto8 = require("crypto");
102235
+ var import_node_fs12 = require("fs");
102236
+ var import_node_path14 = require("path");
101799
102237
  function readJson(path) {
101800
- return JSON.parse((0, import_node_fs11.readFileSync)(path, "utf8"));
102238
+ return JSON.parse((0, import_node_fs12.readFileSync)(path, "utf8"));
101801
102239
  }
101802
102240
  function writeJson(path, value) {
101803
- (0, import_node_fs11.mkdirSync)((0, import_node_path13.dirname)(path), { recursive: true });
101804
- (0, import_node_fs11.writeFileSync)(path, JSON.stringify(value, null, 2) + "\n");
102241
+ (0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
102242
+ (0, import_node_fs12.writeFileSync)(path, JSON.stringify(value, null, 2) + "\n");
101805
102243
  }
101806
102244
  function createJsonKnowledgeStore(root) {
101807
102245
  const manifestPath = knowledgePath(root, "manifest");
101808
102246
  const basePath = knowledgePath(root, "knowledgeBase");
101809
102247
  return {
101810
102248
  exists() {
101811
- return (0, import_node_fs11.existsSync)(basePath);
102249
+ return (0, import_node_fs12.existsSync)(basePath);
101812
102250
  },
101813
102251
  readManifest() {
101814
- if (!(0, import_node_fs11.existsSync)(manifestPath)) return null;
102252
+ if (!(0, import_node_fs12.existsSync)(manifestPath)) return null;
101815
102253
  return KnowledgeManifestSchema.parse(readJson(manifestPath));
101816
102254
  },
101817
102255
  readSnapshot() {
101818
- if (!(0, import_node_fs11.existsSync)(basePath)) return null;
102256
+ if (!(0, import_node_fs12.existsSync)(basePath)) return null;
101819
102257
  return KnowledgeSnapshotSchema.parse(readJson(basePath));
101820
102258
  },
101821
102259
  write(snapshot, opts = {}) {
@@ -101823,9 +102261,9 @@ function createJsonKnowledgeStore(root) {
101823
102261
  const counts = {};
101824
102262
  for (const cat of KNOWLEDGE_CATEGORIES) counts[cat] = parsed[cat].length;
101825
102263
  const snapshotJson = JSON.stringify(parsed, null, 2) + "\n";
101826
- const contentHash = (0, import_node_crypto7.createHash)("sha256").update(snapshotJson).digest("hex");
101827
- (0, import_node_fs11.mkdirSync)((0, import_node_path13.dirname)(basePath), { recursive: true });
101828
- (0, import_node_fs11.writeFileSync)(basePath, snapshotJson);
102264
+ const contentHash = (0, import_node_crypto8.createHash)("sha256").update(snapshotJson).digest("hex");
102265
+ (0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(basePath), { recursive: true });
102266
+ (0, import_node_fs12.writeFileSync)(basePath, snapshotJson);
101829
102267
  writeJson(knowledgePath(root, "contracts"), {
101830
102268
  operations: parsed.operations,
101831
102269
  types: parsed.types,
@@ -101911,9 +102349,9 @@ function searchSnapshot(snapshot, query, opts = {}) {
101911
102349
 
101912
102350
  // ../../packages/knowledge/src/import/index.ts
101913
102351
  init_cjs_shims();
101914
- var import_node_crypto8 = require("crypto");
101915
- var import_node_fs12 = require("fs");
101916
- var import_node_path14 = require("path");
102352
+ var import_node_crypto9 = require("crypto");
102353
+ var import_node_fs13 = require("fs");
102354
+ var import_node_path15 = require("path");
101917
102355
 
101918
102356
  // ../../packages/knowledge/src/import/maison-safqa.ts
101919
102357
  init_cjs_shims();
@@ -102151,8 +102589,8 @@ function importMaisonSafqaKnowledgeBase(raw, opts = {}) {
102151
102589
  // ../../packages/knowledge/src/import/index.ts
102152
102590
  function importKnowledgeBaseFile(filePath, opts = {}) {
102153
102591
  const source = opts.source ?? MAISON_SAFQA_SOURCE;
102154
- const content = (0, import_node_fs12.readFileSync)(filePath, "utf8");
102155
- const contentHash = (0, import_node_crypto8.createHash)("sha256").update(content).digest("hex");
102592
+ const content = (0, import_node_fs13.readFileSync)(filePath, "utf8");
102593
+ const contentHash = (0, import_node_crypto9.createHash)("sha256").update(content).digest("hex");
102156
102594
  let raw;
102157
102595
  try {
102158
102596
  raw = JSON.parse(content);
@@ -102171,7 +102609,7 @@ function importKnowledgeBaseFile(filePath, opts = {}) {
102171
102609
  generator: { tool: source, version: result.kbVersion ?? void 0 },
102172
102610
  sourceIntelligence: { tool: source },
102173
102611
  extraFiles: [
102174
- { name: `${source}:${(0, import_node_path14.basename)(filePath)}`, category: "import-source", contentHash }
102612
+ { name: `${source}:${(0, import_node_path15.basename)(filePath)}`, category: "import-source", contentHash }
102175
102613
  ]
102176
102614
  });
102177
102615
  }
@@ -102180,8 +102618,8 @@ function importKnowledgeBaseFile(filePath, opts = {}) {
102180
102618
 
102181
102619
  // ../../packages/knowledge/src/build/project-landscape.ts
102182
102620
  init_cjs_shims();
102183
- var import_node_fs13 = require("fs");
102184
- var import_node_path15 = require("path");
102621
+ var import_node_fs14 = require("fs");
102622
+ var import_node_path16 = require("path");
102185
102623
 
102186
102624
  // ../../packages/knowledge/src/build/source-graph.ts
102187
102625
  init_cjs_shims();
@@ -102381,14 +102819,14 @@ function deriveExternalIntegrations(profiles) {
102381
102819
  // ../../packages/knowledge/src/build/project-landscape.ts
102382
102820
  function readPackageJson(repoPath) {
102383
102821
  try {
102384
- return JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path15.join)(repoPath, "package.json"), "utf8"));
102822
+ return JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path16.join)(repoPath, "package.json"), "utf8"));
102385
102823
  } catch {
102386
102824
  return null;
102387
102825
  }
102388
102826
  }
102389
102827
  function readText(repoPath, file) {
102390
102828
  try {
102391
- return (0, import_node_fs13.readFileSync)((0, import_node_path15.join)(repoPath, file), "utf8");
102829
+ return (0, import_node_fs14.readFileSync)((0, import_node_path16.join)(repoPath, file), "utf8");
102392
102830
  } catch {
102393
102831
  return null;
102394
102832
  }
@@ -102941,27 +103379,27 @@ function extractQueueGraph(input) {
102941
103379
  }
102942
103380
  }
102943
103381
  const producers = [];
102944
- for (const pc59 of input.producerClasses) {
102945
- const loopVarEnums = loopVarEnumsFor(pc59.content);
102946
- for (const m5 of pc59.content.matchAll(INJECT_QUEUE_RE)) {
103382
+ for (const pc60 of input.producerClasses) {
103383
+ const loopVarEnums = loopVarEnumsFor(pc60.content);
103384
+ for (const m5 of pc60.content.matchAll(INJECT_QUEUE_RE)) {
102947
103385
  const queue = m5[1] ?? "";
102948
- if (queue) producers.push({ queue, symbol: pc59.name, file: pc59.filePath });
103386
+ if (queue) producers.push({ queue, symbol: pc60.name, file: pc60.filePath });
102949
103387
  }
102950
- for (const m5 of pc59.content.matchAll(NEW_BULL_RE)) {
103388
+ for (const m5 of pc60.content.matchAll(NEW_BULL_RE)) {
102951
103389
  if (m5[2] !== "Queue") continue;
102952
103390
  const queues2 = resolveArg(m5[3] ?? "", constMap, enums, loopVarEnums);
102953
103391
  for (const queue of queues2) {
102954
103392
  producers.push({
102955
103393
  queue,
102956
- symbol: (m5[1] ?? pc59.name) || baseName(pc59.filePath),
102957
- file: pc59.filePath
103394
+ symbol: (m5[1] ?? pc60.name) || baseName(pc60.filePath),
103395
+ file: pc60.filePath
102958
103396
  });
102959
103397
  }
102960
103398
  }
102961
- for (const m5 of pc59.content.matchAll(QUEUE_NAME_CONST_RE)) {
103399
+ for (const m5 of pc60.content.matchAll(QUEUE_NAME_CONST_RE)) {
102962
103400
  const ident = m5[1] ?? "";
102963
103401
  const queue = m5[2] ?? "";
102964
- if (queue) producers.push({ queue, symbol: ident || baseName(pc59.filePath), file: pc59.filePath });
103402
+ if (queue) producers.push({ queue, symbol: ident || baseName(pc60.filePath), file: pc60.filePath });
102965
103403
  }
102966
103404
  }
102967
103405
  const workers = [];
@@ -103261,7 +103699,7 @@ async function stitch(client, db, opts = {}) {
103261
103699
 
103262
103700
  // ../../packages/cli/src/lib/ensure-host.ts
103263
103701
  init_cjs_shims();
103264
- var import_node_path16 = require("path");
103702
+ var import_node_path17 = require("path");
103265
103703
  var import_picocolors8 = __toESM(require_picocolors(), 1);
103266
103704
  function parseHostPort(hostUrl) {
103267
103705
  try {
@@ -103290,7 +103728,7 @@ function ensureHostReasonHint(reason) {
103290
103728
  async function verifyHostServesRepo(hostUrl, root) {
103291
103729
  const served = await fetchHostRepoPath(hostUrl);
103292
103730
  if (served === null) return "unknown";
103293
- return (0, import_node_path16.resolve)(served) === (0, import_node_path16.resolve)(root) ? "match" : "foreign";
103731
+ return (0, import_node_path17.resolve)(served) === (0, import_node_path17.resolve)(root) ? "match" : "foreign";
103294
103732
  }
103295
103733
  async function ensureOwnSourceHost(root, opts = {}) {
103296
103734
  const ownUrl = readSourceHostUrl(root);
@@ -103400,16 +103838,16 @@ async function stitchQueueMap(hostUrl, dbUrl, label) {
103400
103838
  async function hostServesRepo(hostUrl, root) {
103401
103839
  try {
103402
103840
  const info2 = await new SourceHttpClient({ baseUrl: hostUrl }).hostInfo();
103403
- return (0, import_node_path17.resolve)(info2.repoPath) === (0, import_node_path17.resolve)(root);
103841
+ return (0, import_node_path18.resolve)(info2.repoPath) === (0, import_node_path18.resolve)(root);
103404
103842
  } catch {
103405
103843
  return true;
103406
103844
  }
103407
103845
  }
103408
103846
  function findConfiguredRepo(config2, root) {
103409
- const target = (0, import_node_path17.resolve)(root);
103847
+ const target = (0, import_node_path18.resolve)(root);
103410
103848
  for (const p5 of config2.projects) {
103411
103849
  for (const r of p5.repositories) {
103412
- if ((0, import_node_path17.resolve)(r.path) === target) {
103850
+ if ((0, import_node_path18.resolve)(r.path) === target) {
103413
103851
  const hostUrl = r.source?.hostUrl;
103414
103852
  return { project: p5.name, ...hostUrl ? { hostUrl } : {} };
103415
103853
  }
@@ -103471,7 +103909,7 @@ async function buildKnowledgeIndex(root, config2, label, configuredProject, opts
103471
103909
  const gitSha = getHeadSha(root) ?? void 0;
103472
103910
  const branch = getCurrentBranch(root) ?? void 0;
103473
103911
  if (opts.importKb) {
103474
- const res = importKnowledgeBaseFile((0, import_node_path17.resolve)(opts.importKb), { root, project: label });
103912
+ const res = importKnowledgeBaseFile((0, import_node_path18.resolve)(opts.importKb), { root, project: label });
103475
103913
  const total = res.manifest ? Object.values(res.manifest.counts).reduce((a2, b5) => a2 + b5, 0) : 0;
103476
103914
  console.log(import_picocolors9.default.dim(` project knowledge: imported ${total} item(s) from ${opts.importKb}`));
103477
103915
  if (res.warnings.length) console.log(import_picocolors9.default.dim(` (${res.warnings.length} import warning(s))`));
@@ -103486,12 +103924,12 @@ async function buildKnowledgeIndex(root, config2, label, configuredProject, opts
103486
103924
  const repos = [];
103487
103925
  if (config2 && configuredProject) {
103488
103926
  const proj = config2.projects.find((p5) => p5.name === configuredProject);
103489
- for (const r of proj?.repositories ?? []) repos.push({ name: r.name, path: (0, import_node_path17.resolve)(r.path) });
103927
+ for (const r of proj?.repositories ?? []) repos.push({ name: r.name, path: (0, import_node_path18.resolve)(r.path) });
103490
103928
  }
103491
103929
  if (repos.length === 0) repos.push({ name: label, path: root });
103492
103930
  let sourceGraph;
103493
103931
  if (hostUrl) {
103494
- const graphRepo = repos.find((r) => (0, import_node_path17.resolve)(r.path) === (0, import_node_path17.resolve)(root))?.name ?? label;
103932
+ const graphRepo = repos.find((r) => (0, import_node_path18.resolve)(r.path) === (0, import_node_path18.resolve)(root))?.name ?? label;
103495
103933
  try {
103496
103934
  const extract = await extractSourceGraph(hostUrl, graphRepo);
103497
103935
  if (extract) sourceGraph = extract;
@@ -103551,7 +103989,7 @@ async function runIndex(opts) {
103551
103989
  }
103552
103990
  }
103553
103991
  const isConfigured = configuredProject !== null;
103554
- const name2 = opts.name ?? configuredProject ?? (0, import_node_path17.basename)(root);
103992
+ const name2 = opts.name ?? configuredProject ?? (0, import_node_path18.basename)(root);
103555
103993
  const label = configuredProject ?? name2;
103556
103994
  let hostUrl;
103557
103995
  let spawned = false;
@@ -103698,8 +104136,8 @@ async function runIndex(opts) {
103698
104136
 
103699
104137
  // ../../packages/cli/src/commands/knowledge.ts
103700
104138
  init_cjs_shims();
103701
- var import_node_fs14 = require("fs");
103702
- var import_node_crypto9 = require("crypto");
104139
+ var import_node_fs15 = require("fs");
104140
+ var import_node_crypto10 = require("crypto");
103703
104141
  var import_picocolors10 = __toESM(require_picocolors(), 1);
103704
104142
  function resolveRoot(opts) {
103705
104143
  if (opts.root) return opts.root;
@@ -103967,7 +104405,7 @@ function runKnowledgeValidate(opts = {}) {
103967
104405
  if (manifest && snapshot) {
103968
104406
  const recorded = manifest.files.find((f5) => f5.name === "knowledge-base.json")?.contentHash;
103969
104407
  if (recorded) {
103970
- const actual = (0, import_node_crypto9.createHash)("sha256").update((0, import_node_fs14.readFileSync)(knowledgePath(root, "knowledgeBase"), "utf8")).digest("hex");
104408
+ const actual = (0, import_node_crypto10.createHash)("sha256").update((0, import_node_fs15.readFileSync)(knowledgePath(root, "knowledgeBase"), "utf8")).digest("hex");
103971
104409
  if (actual !== recorded) {
103972
104410
  issues.push("knowledge-base.json content hash does not match the manifest (file modified after write)");
103973
104411
  }
@@ -114301,12 +114739,12 @@ var import_picocolors11 = __toESM(require_picocolors(), 1);
114301
114739
 
114302
114740
  // ../../packages/cli/src/lib/open-url.ts
114303
114741
  init_cjs_shims();
114304
- var import_node_child_process6 = require("child_process");
114742
+ var import_node_child_process7 = require("child_process");
114305
114743
  function openBrowser(url) {
114306
114744
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
114307
114745
  const args2 = process.platform === "win32" ? ["/c", "start", "", url] : [url];
114308
114746
  try {
114309
- (0, import_node_child_process6.execFile)(cmd, args2, () => {
114747
+ (0, import_node_child_process7.execFile)(cmd, args2, () => {
114310
114748
  });
114311
114749
  } catch {
114312
114750
  }
@@ -114694,8 +115132,8 @@ async function runMcpServer(opts = {}) {
114694
115132
 
114695
115133
  // ../../packages/cli/src/commands/knowledge-cloud.ts
114696
115134
  init_cjs_shims();
114697
- var import_node_fs17 = require("fs");
114698
- var import_node_path19 = require("path");
115135
+ var import_node_fs18 = require("fs");
115136
+ var import_node_path20 = require("path");
114699
115137
  var import_picocolors13 = __toESM(require_picocolors(), 1);
114700
115138
 
114701
115139
  // ../../packages/cli/src/lib/cloud/session.ts
@@ -114919,12 +115357,12 @@ var CloudClient = class {
114919
115357
 
114920
115358
  // ../../packages/cli/src/lib/cloud/auth-store.ts
114921
115359
  init_cjs_shims();
114922
- var import_node_fs15 = require("fs");
115360
+ var import_node_fs16 = require("fs");
114923
115361
  function readAuth() {
114924
115362
  const p5 = authPath();
114925
- if (!(0, import_node_fs15.existsSync)(p5)) return null;
115363
+ if (!(0, import_node_fs16.existsSync)(p5)) return null;
114926
115364
  try {
114927
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(p5, "utf8"));
115365
+ const parsed = JSON.parse((0, import_node_fs16.readFileSync)(p5, "utf8"));
114928
115366
  if (!parsed.token || !parsed.apiBaseUrl || !parsed.account) return null;
114929
115367
  return parsed;
114930
115368
  } catch {
@@ -114932,17 +115370,17 @@ function readAuth() {
114932
115370
  }
114933
115371
  }
114934
115372
  function writeAuth(state) {
114935
- (0, import_node_fs15.mkdirSync)(horusHome(), { recursive: true });
115373
+ (0, import_node_fs16.mkdirSync)(horusHome(), { recursive: true });
114936
115374
  const p5 = authPath();
114937
- (0, import_node_fs15.writeFileSync)(p5, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
115375
+ (0, import_node_fs16.writeFileSync)(p5, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
114938
115376
  try {
114939
- (0, import_node_fs15.chmodSync)(p5, 384);
115377
+ (0, import_node_fs16.chmodSync)(p5, 384);
114940
115378
  } catch {
114941
115379
  }
114942
115380
  }
114943
115381
  function clearAuth() {
114944
115382
  const p5 = authPath();
114945
- if ((0, import_node_fs15.existsSync)(p5)) (0, import_node_fs15.rmSync)(p5);
115383
+ if ((0, import_node_fs16.existsSync)(p5)) (0, import_node_fs16.rmSync)(p5);
114946
115384
  }
114947
115385
 
114948
115386
  // ../../packages/cli/src/lib/cloud/session.ts
@@ -114960,13 +115398,13 @@ function authedClient() {
114960
115398
 
114961
115399
  // ../../packages/cli/src/lib/cloud/context-store.ts
114962
115400
  init_cjs_shims();
114963
- var import_node_fs16 = require("fs");
114964
- var import_node_path18 = require("path");
115401
+ var import_node_fs17 = require("fs");
115402
+ var import_node_path19 = require("path");
114965
115403
  function readCloudConfig(root) {
114966
115404
  const p5 = cloudConfigPath(root);
114967
- if (!(0, import_node_fs16.existsSync)(p5)) return null;
115405
+ if (!(0, import_node_fs17.existsSync)(p5)) return null;
114968
115406
  try {
114969
- const parsed = JSON.parse((0, import_node_fs16.readFileSync)(p5, "utf8"));
115407
+ const parsed = JSON.parse((0, import_node_fs17.readFileSync)(p5, "utf8"));
114970
115408
  if (parsed.context !== "local" && parsed.context !== "cloud") return null;
114971
115409
  return parsed;
114972
115410
  } catch {
@@ -114975,12 +115413,12 @@ function readCloudConfig(root) {
114975
115413
  }
114976
115414
  function writeCloudConfig(root, cfg) {
114977
115415
  const p5 = cloudConfigPath(root);
114978
- (0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(p5), { recursive: true });
114979
- (0, import_node_fs16.writeFileSync)(p5, JSON.stringify(cfg, null, 2) + "\n");
115416
+ (0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(p5), { recursive: true });
115417
+ (0, import_node_fs17.writeFileSync)(p5, JSON.stringify(cfg, null, 2) + "\n");
114980
115418
  }
114981
115419
  function clearCloudConfig(root) {
114982
115420
  const p5 = cloudConfigPath(root);
114983
- if ((0, import_node_fs16.existsSync)(p5)) (0, import_node_fs16.rmSync)(p5);
115421
+ if ((0, import_node_fs17.existsSync)(p5)) (0, import_node_fs17.rmSync)(p5);
114984
115422
  }
114985
115423
  function isCloudActive(cfg) {
114986
115424
  return !!cfg && cfg.context === "cloud" && !!cfg.project;
@@ -115176,10 +115614,10 @@ function reportCloudError(err2) {
115176
115614
 
115177
115615
  // ../../packages/cli/src/commands/knowledge-cloud.ts
115178
115616
  function readKnowledgeRedactConfig(root) {
115179
- const configPath = (0, import_node_path19.join)(root, ".horus", "config.json");
115180
- if (!(0, import_node_fs17.existsSync)(configPath)) return {};
115617
+ const configPath = (0, import_node_path20.join)(root, ".horus", "config.json");
115618
+ if (!(0, import_node_fs18.existsSync)(configPath)) return {};
115181
115619
  try {
115182
- const raw = JSON.parse((0, import_node_fs17.readFileSync)(configPath, "utf8"));
115620
+ const raw = JSON.parse((0, import_node_fs18.readFileSync)(configPath, "utf8"));
115183
115621
  const redact = raw["knowledge"]?.["redact"];
115184
115622
  return { dropProvenancePaths: !!redact?.dropProvenancePaths, summariesOnly: !!redact?.summariesOnly };
115185
115623
  } catch {
@@ -116600,12 +117038,12 @@ async function listCloudInvestigations(client, cfg) {
116600
117038
 
116601
117039
  // ../../packages/cli/src/lib/freshness.ts
116602
117040
  init_cjs_shims();
116603
- var import_node_child_process7 = require("child_process");
116604
- var import_node_fs18 = require("fs");
116605
- var import_node_path20 = require("path");
117041
+ var import_node_child_process8 = require("child_process");
117042
+ var import_node_fs19 = require("fs");
117043
+ var import_node_path21 = require("path");
116606
117044
  var import_node_util5 = require("util");
116607
117045
  var import_picocolors15 = __toESM(require_picocolors(), 1);
116608
- var execFileAsync2 = (0, import_node_util5.promisify)(import_node_child_process7.execFile);
117046
+ var execFileAsync2 = (0, import_node_util5.promisify)(import_node_child_process8.execFile);
116609
117047
  async function commitsSince(repoRoot, sinceIso) {
116610
117048
  try {
116611
117049
  const { stdout } = await execFileAsync2(
@@ -116623,7 +117061,7 @@ var RUNTIME_SOURCES = /* @__PURE__ */ new Set(["logs", "metrics", "state", "queu
116623
117061
  var STALE_INDEX_MS = 7 * 24 * 60 * 60 * 1e3;
116624
117062
  function readIndexMeta(repoRoot) {
116625
117063
  try {
116626
- const raw = (0, import_node_fs18.readFileSync)((0, import_node_path20.join)(repoRoot, ".horus", "source", "meta.json"), "utf8");
117064
+ const raw = (0, import_node_fs19.readFileSync)((0, import_node_path21.join)(repoRoot, ".horus", "source", "meta.json"), "utf8");
116627
117065
  const j3 = JSON.parse(raw);
116628
117066
  return {
116629
117067
  lastIndexedAt: typeof j3.last_indexed_at === "string" ? j3.last_indexed_at : void 0,
@@ -116710,9 +117148,9 @@ function renderFreshness(f5) {
116710
117148
  // ../../packages/cli/src/lib/investigation-runner.ts
116711
117149
  init_cjs_shims();
116712
117150
  var import_picocolors16 = __toESM(require_picocolors(), 1);
116713
- var import_node_fs19 = require("fs");
116714
- var import_node_path21 = require("path");
116715
- var import_node_os8 = require("os");
117151
+ var import_node_fs20 = require("fs");
117152
+ var import_node_path22 = require("path");
117153
+ var import_node_os9 = require("os");
116716
117154
 
116717
117155
  // ../../packages/eval/src/index.ts
116718
117156
  init_cjs_shims();
@@ -117245,7 +117683,7 @@ function loadReranker() {
117245
117683
  const flag = process.env.HORUS_RERANK;
117246
117684
  if (!flag || flag === "0" || flag.toLowerCase() === "false") return void 0;
117247
117685
  try {
117248
- const blob = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path21.join)((0, import_node_os8.homedir)(), ".horus", "reranker.json"), "utf8"));
117686
+ const blob = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path22.join)((0, import_node_os9.homedir)(), ".horus", "reranker.json"), "utf8"));
117249
117687
  if (!isRerankerModel(blob)) return void 0;
117250
117688
  if ((blob.holdout?.delta ?? 0) <= 0) return void 0;
117251
117689
  return (causes) => applyReranker(blob, causes);
@@ -118626,8 +119064,8 @@ async function runOwner(query, opts) {
118626
119064
 
118627
119065
  // ../../packages/cli/src/commands/postmortem.ts
118628
119066
  init_cjs_shims();
118629
- var import_node_fs20 = require("fs");
118630
- var import_node_path22 = require("path");
119067
+ var import_node_fs21 = require("fs");
119068
+ var import_node_path23 = require("path");
118631
119069
  var import_picocolors30 = __toESM(require_picocolors(), 1);
118632
119070
  async function runPostmortem(id, opts) {
118633
119071
  const log = opts.write ?? ((line2) => console.log(line2));
@@ -118738,14 +119176,14 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
118738
119176
  }
118739
119177
  }
118740
119178
  if (opts.output) {
118741
- const outputPath = (0, import_node_path22.resolve)(opts.output);
118742
- if ((0, import_node_fs20.existsSync)(outputPath) && !opts.force) {
119179
+ const outputPath = (0, import_node_path23.resolve)(opts.output);
119180
+ if ((0, import_node_fs21.existsSync)(outputPath) && !opts.force) {
118743
119181
  log(import_picocolors30.default.red("\u2717") + " " + outputPath + " already exists");
118744
119182
  log(import_picocolors30.default.dim(" pass --force to overwrite"));
118745
119183
  return 1;
118746
119184
  }
118747
119185
  try {
118748
- (0, import_node_fs20.writeFileSync)(outputPath, content, "utf8");
119186
+ (0, import_node_fs21.writeFileSync)(outputPath, content, "utf8");
118749
119187
  } catch (err2) {
118750
119188
  log(import_picocolors30.default.red("\u2717 Could not write " + outputPath + ": ") + err2.message);
118751
119189
  return 1;
@@ -121143,12 +121581,12 @@ async function runState(opts) {
121143
121581
  // ../../packages/cli/src/commands/init.ts
121144
121582
  init_cjs_shims();
121145
121583
  var import_picocolors39 = __toESM(require_picocolors(), 1);
121146
- var import_node_path23 = require("path");
121584
+ var import_node_path24 = require("path");
121147
121585
  async function runInit(opts) {
121148
121586
  try {
121149
121587
  const cwd = process.cwd();
121150
- const root = opts.path ? (0, import_node_path23.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
121151
- const name2 = opts.name ?? (0, import_node_path23.basename)(root);
121588
+ const root = opts.path ? (0, import_node_path24.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
121589
+ const name2 = opts.name ?? (0, import_node_path24.basename)(root);
121152
121590
  const envName = opts.env ?? "production";
121153
121591
  const repo = { name: name2, path: root };
121154
121592
  if (opts.source) repo["source"] = { hostUrl: opts.source };
@@ -121338,7 +121776,6 @@ async function runSetup(opts) {
121338
121776
  // ../../packages/cli/src/commands/connect.ts
121339
121777
  init_cjs_shims();
121340
121778
  var import_node_readline = require("readline");
121341
- var import_node_child_process9 = require("child_process");
121342
121779
  var import_picocolors44 = __toESM(require_picocolors(), 1);
121343
121780
 
121344
121781
  // ../../packages/cli/src/lib/tty-selector.ts
@@ -121663,10 +122100,10 @@ async function selectSearch(opts) {
121663
122100
 
121664
122101
  // ../../packages/cli/src/commands/connect-ai.ts
121665
122102
  init_cjs_shims();
121666
- var import_node_child_process8 = require("child_process");
122103
+ var import_node_child_process9 = require("child_process");
121667
122104
  var import_picocolors43 = __toESM(require_picocolors(), 1);
121668
122105
  function cliInstalled(id) {
121669
- const r = (0, import_node_child_process8.spawnSync)(id, ["--version"], { stdio: "ignore", timeout: 2e3 });
122106
+ const r = (0, import_node_child_process9.spawnSync)(id, ["--version"], { stdio: "ignore", timeout: 2e3 });
121670
122107
  return !r.error;
121671
122108
  }
121672
122109
  async function probeAnthropic(apiKey) {
@@ -121816,7 +122253,7 @@ async function runConnect(type, opts) {
121816
122253
  }
121817
122254
  const connectorType = type;
121818
122255
  try {
121819
- const cwd = process.cwd();
122256
+ const cwd = opts.cwd ?? process.cwd();
121820
122257
  const root = findRepoRoot(cwd) ?? cwd;
121821
122258
  const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
121822
122259
  const filled = await fillInteractive(connectorType, opts);
@@ -121858,22 +122295,45 @@ ${import_picocolors44.default.red(`\u2717 Could not reach ${connectorType}:`)} $
121858
122295
  ${import_picocolors44.default.green("\u2713")} ${connectorType} reachable ${import_picocolors44.default.dim(`(${probeResult.detail})`)}`
121859
122296
  );
121860
122297
  }
121861
- const hasLiteralCredentials = filled.url !== void 0 || filled.password !== void 0 || filled.username !== void 0 || filled.authToken !== void 0 || filled.token !== void 0;
121862
- if (hasLiteralCredentials) {
121863
- if (isGitTracked(configPath, root)) {
121864
- console.error(
121865
- import_picocolors44.default.red(".horus/config.json is already tracked by Git.") + "\nStoring credentials here would expose them in the repository.\n" + import_picocolors44.default.dim(
121866
- " Option A \u2014 remove from Git index then re-run:\n git rm --cached .horus/config.json\n horus connect " + type + " ...\n\n Option B \u2014 keep credentials in the environment and reference them:\n export ES_URL=https://...\n export ES_USERNAME=...\n export ES_PASSWORD=...\n Then edit .horus/config.json manually to use urlEnv/usernameEnv/passwordEnv."
121867
- )
121868
- );
122298
+ const envName = resolveEnvName(configPath, filled.env);
122299
+ const secretFields = CONNECTOR_SECRET_FIELDS[connectorType] ?? [];
122300
+ const nonSecretPatch = {};
122301
+ const secretPatch = [];
122302
+ for (const [k3, v4] of Object.entries(patch)) {
122303
+ if (secretFields.includes(k3) && typeof v4 === "string" && v4.length > 0) {
122304
+ secretPatch.push([k3, v4]);
122305
+ } else {
122306
+ nonSecretPatch[k3] = v4;
122307
+ }
122308
+ }
122309
+ ensureProjectGitignore(root);
122310
+ if (secretPatch.length > 0) {
122311
+ let keyResult;
122312
+ try {
122313
+ keyResult = ensureMasterKey();
122314
+ } catch (err2) {
122315
+ console.error(import_picocolors44.default.red(err2.message));
121869
122316
  return 1;
121870
122317
  }
121871
- ensureCredentialGitignore(root);
122318
+ for (const [field, value] of secretPatch) {
122319
+ writeConnectorSecret(root, envName, connectorType, field, value, keyResult.key);
122320
+ }
122321
+ if (keyResult.warning) console.warn(import_picocolors44.default.yellow(`
122322
+ \u26A0 ${keyResult.warning}`));
121872
122323
  }
121873
- patchLocalConnector(configPath, connectorType, patch, filled.env);
122324
+ patchLocalConnector(configPath, connectorType, nonSecretPatch, envName);
121874
122325
  console.log(
121875
122326
  `${import_picocolors44.default.green("\u2713")} ${import_picocolors44.default.bold(connectorType)} connector saved \u2192 ${import_picocolors44.default.dim(configPath)}`
121876
122327
  );
122328
+ if (secretPatch.length > 0) {
122329
+ const n4 = secretPatch.length;
122330
+ console.log(
122331
+ import_picocolors44.default.dim(
122332
+ ` ${n4} secret${n4 > 1 ? "s" : ""} encrypted \u2192 ${localSecretsPath(root)}
122333
+ master key: ${masterKeyStatus().detail}`
122334
+ )
122335
+ );
122336
+ }
121877
122337
  printSummary(connectorType, filled);
121878
122338
  console.log(import_picocolors44.default.dim(`
121879
122339
  run: horus investigate "<hint>"`));
@@ -122337,16 +122797,19 @@ function printSummary(type, opts) {
122337
122797
  }
122338
122798
  if (lines.length > 0) console.log(import_picocolors44.default.dim(lines.join("\n")));
122339
122799
  }
122340
- function isGitTracked(filePath, cwd) {
122341
- try {
122342
- (0, import_node_child_process9.execFileSync)("git", ["ls-files", "--error-unmatch", filePath], {
122343
- cwd,
122344
- stdio: "pipe"
122345
- });
122346
- return true;
122347
- } catch {
122348
- return false;
122800
+ function resolveEnvName(configPath, requested) {
122801
+ const file = readLocalConfig(configPath);
122802
+ const project = file.project;
122803
+ const envs = project?.environments ?? [];
122804
+ if (requested) {
122805
+ if (!envs.some((e) => e.name === requested)) {
122806
+ throw new Error(`Environment "${requested}" not found in config.`);
122807
+ }
122808
+ return requested;
122349
122809
  }
122810
+ const first = envs[0]?.name;
122811
+ if (!first) throw new Error("No environments found in config.");
122812
+ return first;
122350
122813
  }
122351
122814
  async function discoverEsIndices(url, username, password) {
122352
122815
  if (!url) return [];
@@ -122531,15 +122994,157 @@ function redactUrl(raw) {
122531
122994
  }
122532
122995
  }
122533
122996
 
122997
+ // ../../packages/cli/src/commands/secrets.ts
122998
+ init_cjs_shims();
122999
+ var import_node_fs22 = require("fs");
123000
+ var import_picocolors45 = __toESM(require_picocolors(), 1);
123001
+ function locate(cwd = process.cwd()) {
123002
+ const root = findRepoRoot(cwd) ?? cwd;
123003
+ const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
123004
+ return { root, configPath, exists: (0, import_node_fs22.existsSync)(configPath) };
123005
+ }
123006
+ function countStoredSecrets(root) {
123007
+ const stored = readLocalSecrets(root).connectors;
123008
+ if (!stored) return 0;
123009
+ let n4 = 0;
123010
+ for (const byConnector of Object.values(stored)) {
123011
+ for (const byField of Object.values(byConnector)) {
123012
+ n4 += Object.keys(byField).length;
123013
+ }
123014
+ }
123015
+ return n4;
123016
+ }
123017
+ function runSecretsStatus(opts = {}) {
123018
+ const { root, configPath, exists: exists2 } = locate(opts.cwd);
123019
+ const key = masterKeyStatus();
123020
+ console.log(import_picocolors45.default.bold("\nMaster key"));
123021
+ console.log(
123022
+ key.available ? ` ${import_picocolors45.default.green("\u25CF")} ${key.detail}` : ` ${import_picocolors45.default.dim("\u25CB")} ${key.detail}`
123023
+ );
123024
+ const stored = countStoredSecrets(root);
123025
+ console.log(import_picocolors45.default.bold("\nEncrypted secrets"));
123026
+ console.log(` ${stored} stored \u2192 ${import_picocolors45.default.dim(localSecretsPath(root))}`);
123027
+ if (stored > 0) {
123028
+ const { warnings } = decryptConnectorSecrets(root);
123029
+ if (warnings.length > 0) {
123030
+ console.log(import_picocolors45.default.yellow(` \u26A0 ${warnings.length} cannot be decrypted with the current key:`));
123031
+ for (const w4 of warnings) console.log(import_picocolors45.default.dim(` - ${w4}`));
123032
+ } else {
123033
+ console.log(import_picocolors45.default.dim(" all decrypt cleanly with the current key"));
123034
+ }
123035
+ }
123036
+ console.log(import_picocolors45.default.bold("\nPlaintext in config.json"));
123037
+ if (!exists2) {
123038
+ console.log(import_picocolors45.default.dim(" no .horus/config.json found"));
123039
+ } else {
123040
+ const plaintext = findPlaintextConnectorSecrets(readLocalConfig(configPath).project);
123041
+ if (plaintext.length === 0) {
123042
+ console.log(` ${import_picocolors45.default.green("\u2713")} none \u2014 config carries no credentials`);
123043
+ } else {
123044
+ console.log(import_picocolors45.default.yellow(` \u26A0 ${plaintext.length} plaintext secret(s) \u2014 run \`horus secrets migrate\`:`));
123045
+ for (const p5 of plaintext) console.log(import_picocolors45.default.dim(` - ${p5}`));
123046
+ }
123047
+ }
123048
+ console.log(import_picocolors45.default.bold("\nGitignore"));
123049
+ console.log(
123050
+ isHorusGitignored(root) ? ` ${import_picocolors45.default.green("\u2713")} .horus/ is gitignored` : import_picocolors45.default.yellow(" \u26A0 .horus/ is NOT gitignored \u2014 run `horus secrets migrate` or add `.horus/` to .gitignore")
123051
+ );
123052
+ console.log("");
123053
+ return 0;
123054
+ }
123055
+ function runSecretsMigrate(opts = {}) {
123056
+ const { root, configPath, exists: exists2 } = locate(opts.cwd);
123057
+ if (!exists2) {
123058
+ console.error(import_picocolors45.default.red(`No .horus/config.json found at ${configPath}.`));
123059
+ console.error(import_picocolors45.default.dim(" Run `horus index` in this repo first."));
123060
+ return 1;
123061
+ }
123062
+ const file = readLocalConfig(configPath);
123063
+ const plaintext = findPlaintextConnectorSecrets(file.project);
123064
+ ensureProjectGitignore(root);
123065
+ if (plaintext.length === 0) {
123066
+ console.log(`${import_picocolors45.default.green("\u2713")} No plaintext connector secrets in config.json \u2014 nothing to migrate.`);
123067
+ if (!isHorusGitignored(root)) {
123068
+ console.log(import_picocolors45.default.dim(" Ensured `.horus/` is gitignored."));
123069
+ }
123070
+ return 0;
123071
+ }
123072
+ if (opts.dryRun) {
123073
+ console.log(import_picocolors45.default.bold(`Would migrate ${plaintext.length} plaintext secret(s) \u2192 encrypted store:`));
123074
+ for (const p5 of plaintext) console.log(import_picocolors45.default.dim(` - ${p5}`));
123075
+ console.log(import_picocolors45.default.dim("\n Re-run without --dry-run to apply."));
123076
+ return 0;
123077
+ }
123078
+ let keyResult;
123079
+ try {
123080
+ keyResult = ensureMasterKey();
123081
+ } catch (err2) {
123082
+ console.error(import_picocolors45.default.red(err2.message));
123083
+ return 1;
123084
+ }
123085
+ const project = file.project;
123086
+ let migrated = 0;
123087
+ for (const env of project?.environments ?? []) {
123088
+ const envName = env["name"];
123089
+ const connectors = env["connectors"];
123090
+ if (!envName || !connectors) continue;
123091
+ for (const [connector, cfg] of Object.entries(connectors)) {
123092
+ if (!cfg || typeof cfg !== "object") continue;
123093
+ for (const field of CONNECTOR_SECRET_FIELDS[connector] ?? []) {
123094
+ const val = cfg[field];
123095
+ if (typeof val === "string" && val.length > 0) {
123096
+ writeConnectorSecret(root, envName, connector, field, val, keyResult.key);
123097
+ delete cfg[field];
123098
+ migrated++;
123099
+ }
123100
+ }
123101
+ }
123102
+ }
123103
+ writeLocalConfig(root, file);
123104
+ console.log(`${import_picocolors45.default.green("\u2713")} Migrated ${migrated} secret(s) \u2192 ${import_picocolors45.default.dim(localSecretsPath(root))}`);
123105
+ console.log(import_picocolors45.default.dim(` master key: ${masterKeyStatus().detail}`));
123106
+ console.log(import_picocolors45.default.dim(" config.json now carries no credentials."));
123107
+ if (keyResult.warning) console.warn(import_picocolors45.default.yellow(`
123108
+ \u26A0 ${keyResult.warning}`));
123109
+ console.log(
123110
+ import_picocolors45.default.dim(
123111
+ "\n If config.json was ever committed, scrub the old secret from history:\n git rm --cached .horus/config.json # if tracked\n # then rotate the exposed credential at its provider."
123112
+ )
123113
+ );
123114
+ return 0;
123115
+ }
123116
+ function runSecretsKey(opts = {}) {
123117
+ const status = masterKeyStatus();
123118
+ if (!status.available) {
123119
+ console.log(import_picocolors45.default.dim("No master key yet \u2014 created on first `horus connect` or `horus secrets migrate`."));
123120
+ return 0;
123121
+ }
123122
+ console.log(`Master key source: ${status.detail}`);
123123
+ if (!opts.show) {
123124
+ console.log(import_picocolors45.default.dim(" Pass --show to print the key (base64) for CI use (HORUS_SECRET_KEY)."));
123125
+ return 0;
123126
+ }
123127
+ const key = getMasterKeyForRead();
123128
+ if (!key) {
123129
+ console.error(import_picocolors45.default.red("Could not read the master key."));
123130
+ return 1;
123131
+ }
123132
+ console.warn(import_picocolors45.default.yellow("\u26A0 Treat this as a credential. Anyone with it can decrypt your connector secrets."));
123133
+ console.log(`
123134
+ export HORUS_SECRET_KEY=${key.toString("base64")}
123135
+ `);
123136
+ return 0;
123137
+ }
123138
+
122534
123139
  // ../../packages/cli/src/commands/stop.ts
122535
123140
  init_cjs_shims();
122536
123141
  var import_node_child_process10 = require("child_process");
122537
- var import_node_fs21 = require("fs");
123142
+ var import_node_fs23 = require("fs");
122538
123143
  var import_node_util6 = require("util");
122539
- var import_node_path24 = require("path");
122540
- var import_picocolors45 = __toESM(require_picocolors(), 1);
123144
+ var import_node_path25 = require("path");
123145
+ var import_picocolors46 = __toESM(require_picocolors(), 1);
122541
123146
  var execFileAsync3 = (0, import_node_util6.promisify)(import_node_child_process10.execFile);
122542
- var unlinkAsync = (0, import_node_util6.promisify)(import_node_fs21.unlink);
123147
+ var unlinkAsync = (0, import_node_util6.promisify)(import_node_fs23.unlink);
122543
123148
  var SPAWNED_HOST_FILE2 = "spawned-host.json";
122544
123149
  var START_TIME_TOLERANCE_S = 60;
122545
123150
  var STOP_WAIT_MS = 5e3;
@@ -122555,19 +123160,19 @@ async function runStop(opts) {
122555
123160
  const root = findRepoRoot(cwd) ?? cwd;
122556
123161
  const hostUrl = readSourceHostUrl(root);
122557
123162
  if (!hostUrl) {
122558
- console.log(import_picocolors45.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
123163
+ console.log(import_picocolors46.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
122559
123164
  return 0;
122560
123165
  }
122561
123166
  return await stopHost(root, hostUrl);
122562
123167
  } catch (err2) {
122563
- console.error(import_picocolors45.default.red(err2.message));
123168
+ console.error(import_picocolors46.default.red(err2.message));
122564
123169
  return 1;
122565
123170
  }
122566
123171
  }
122567
123172
  async function stopHost(root, hostUrl) {
122568
123173
  const port = extractPort(hostUrl);
122569
123174
  if (port === null) {
122570
- console.error(import_picocolors45.default.red(`Cannot determine port from host URL: ${hostUrl}`));
123175
+ console.error(import_picocolors46.default.red(`Cannot determine port from host URL: ${hostUrl}`));
122571
123176
  return 1;
122572
123177
  }
122573
123178
  const healthy = await isHostHealthy(hostUrl);
@@ -122577,12 +123182,12 @@ async function stopHost(root, hostUrl) {
122577
123182
  if (!wrapperAlive) {
122578
123183
  const res = await stopBackendServerPid(root, port);
122579
123184
  if (res === "failed") return 1;
122580
- if (res !== "stopped") console.log(import_picocolors45.default.dim(`Host ${hostUrl} is already stopped.`));
123185
+ if (res !== "stopped") console.log(import_picocolors46.default.dim(`Host ${hostUrl} is already stopped.`));
122581
123186
  await cleanupSpawnedRecord(root);
122582
123187
  return 0;
122583
123188
  }
122584
123189
  console.log(
122585
- import_picocolors45.default.dim(
123190
+ import_picocolors46.default.dim(
122586
123191
  `Host ${hostUrl} is unreachable but pid ${owned.pid} is still running \u2014 terminating a stuck host.`
122587
123192
  )
122588
123193
  );
@@ -122590,7 +123195,7 @@ async function stopHost(root, hostUrl) {
122590
123195
  const spawned = readSpawnedHost(root);
122591
123196
  if (spawned === null) {
122592
123197
  console.error(
122593
- import_picocolors45.default.red(
123198
+ import_picocolors46.default.red(
122594
123199
  `No ownership record found (.horus/${SPAWNED_HOST_FILE2} absent). Horus will not stop a host it did not spawn.`
122595
123200
  )
122596
123201
  );
@@ -122598,12 +123203,12 @@ async function stopHost(root, hostUrl) {
122598
123203
  }
122599
123204
  const recordError = validateSpawnedRecord(spawned);
122600
123205
  if (recordError !== null) {
122601
- console.error(import_picocolors45.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
123206
+ console.error(import_picocolors46.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
122602
123207
  return 1;
122603
123208
  }
122604
123209
  if (spawned.port !== port) {
122605
123210
  console.error(
122606
- import_picocolors45.default.red(
123211
+ import_picocolors46.default.red(
122607
123212
  `Ownership record port (${spawned.port}) does not match host URL port (${port}). Record may be stale.`
122608
123213
  )
122609
123214
  );
@@ -122611,7 +123216,7 @@ async function stopHost(root, hostUrl) {
122611
123216
  }
122612
123217
  if (spawned.root !== root) {
122613
123218
  console.error(
122614
- import_picocolors45.default.red(
123219
+ import_picocolors46.default.red(
122615
123220
  `Ownership record root (${spawned.root}) does not match resolved root (${root}). Record may be stale.`
122616
123221
  )
122617
123222
  );
@@ -122622,14 +123227,14 @@ async function stopHost(root, hostUrl) {
122622
123227
  const res = await stopBackendServerPid(root, port);
122623
123228
  if (res === "failed") return 1;
122624
123229
  if (res !== "stopped") {
122625
- console.log(import_picocolors45.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
123230
+ console.log(import_picocolors46.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
122626
123231
  }
122627
123232
  await cleanupSpawnedRecord(root);
122628
123233
  return 0;
122629
123234
  }
122630
123235
  if (!isOwnHostProcess(spawned.pid, port, root, info2.args)) {
122631
123236
  console.error(
122632
- import_picocolors45.default.red(
123237
+ import_picocolors46.default.red(
122633
123238
  `Pid ${spawned.pid} args do not match "horus-source host --port ${port}". Got: "${info2.args.slice(0, 120)}". Aborting for safety.`
122634
123239
  )
122635
123240
  );
@@ -122638,12 +123243,12 @@ async function stopHost(root, hostUrl) {
122638
123243
  const startTs = new Date(spawned.startedAt).getTime();
122639
123244
  const recordedAgeS = Math.round((Date.now() - startTs) / 1e3);
122640
123245
  if (!Number.isFinite(info2.etimeSeconds)) {
122641
- console.error(import_picocolors45.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
123246
+ console.error(import_picocolors46.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
122642
123247
  return 1;
122643
123248
  }
122644
123249
  if (Math.abs(info2.etimeSeconds - recordedAgeS) > START_TIME_TOLERANCE_S) {
122645
123250
  console.error(
122646
- import_picocolors45.default.red(
123251
+ import_picocolors46.default.red(
122647
123252
  `Pid ${spawned.pid} age mismatch: record says ~${recordedAgeS}s, process reports ${info2.etimeSeconds}s elapsed. Possible PID reuse \u2014 aborting for safety.`
122648
123253
  )
122649
123254
  );
@@ -122653,17 +123258,17 @@ async function stopHost(root, hostUrl) {
122653
123258
  try {
122654
123259
  terminated = await terminatePid(spawned.pid);
122655
123260
  } catch (err2) {
122656
- console.error(import_picocolors45.default.red(`Failed to signal pid ${spawned.pid}: ${err2.message}`));
123261
+ console.error(import_picocolors46.default.red(`Failed to signal pid ${spawned.pid}: ${err2.message}`));
122657
123262
  return 1;
122658
123263
  }
122659
123264
  if (!terminated) {
122660
123265
  console.error(
122661
- import_picocolors45.default.red(`Host pid ${spawned.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
123266
+ import_picocolors46.default.red(`Host pid ${spawned.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
122662
123267
  );
122663
123268
  return 1;
122664
123269
  }
122665
123270
  console.log(
122666
- `${import_picocolors45.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors45.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
123271
+ `${import_picocolors46.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors46.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
122667
123272
  );
122668
123273
  if (await stopBackendServerPid(root, port) === "failed") return 1;
122669
123274
  await cleanupSpawnedRecord(root);
@@ -122681,11 +123286,11 @@ function isOwnHostProcess(pid, port, root, args2) {
122681
123286
  if (hostArgvRegex(port).test(args2)) return true;
122682
123287
  if (!hostArgvAnyPortRegex().test(args2)) return false;
122683
123288
  const rec = readSourceHostPid(root);
122684
- return rec !== null && rec.pid === pid && Number.isFinite(rec.port) && rec.port === port && !!rec.repoPath && (0, import_node_path24.resolve)(rec.repoPath) === (0, import_node_path24.resolve)(root);
123289
+ return rec !== null && rec.pid === pid && Number.isFinite(rec.port) && rec.port === port && !!rec.repoPath && (0, import_node_path25.resolve)(rec.repoPath) === (0, import_node_path25.resolve)(root);
122685
123290
  }
122686
123291
  async function cleanupSpawnedRecord(root) {
122687
123292
  try {
122688
- await unlinkAsync((0, import_node_path24.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
123293
+ await unlinkAsync((0, import_node_path25.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
122689
123294
  } catch {
122690
123295
  }
122691
123296
  }
@@ -122698,7 +123303,7 @@ async function stopBackendServerPid(root, port) {
122698
123303
  if (info2 === null) return "none";
122699
123304
  if (!isOwnHostProcess(rec.pid, port, root, info2.args)) {
122700
123305
  console.log(
122701
- import_picocolors45.default.dim(
123306
+ import_picocolors46.default.dim(
122702
123307
  `Host pid ${rec.pid} is now an unrelated process (stale source/host.json / PID reuse) \u2014 host already gone.`
122703
123308
  )
122704
123309
  );
@@ -122708,17 +123313,17 @@ async function stopBackendServerPid(root, port) {
122708
123313
  try {
122709
123314
  terminated = await terminatePid(rec.pid);
122710
123315
  } catch (err2) {
122711
- console.error(import_picocolors45.default.red(`Failed to signal pid ${rec.pid}: ${err2.message}`));
123316
+ console.error(import_picocolors46.default.red(`Failed to signal pid ${rec.pid}: ${err2.message}`));
122712
123317
  return "failed";
122713
123318
  }
122714
123319
  if (!terminated) {
122715
123320
  console.error(
122716
- import_picocolors45.default.red(`Host pid ${rec.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
123321
+ import_picocolors46.default.red(`Host pid ${rec.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
122717
123322
  );
122718
123323
  return "failed";
122719
123324
  }
122720
123325
  console.log(
122721
- `${import_picocolors45.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors45.default.dim(`(pid ${rec.pid}, port ${port})`) + ` for ${root}`
123326
+ `${import_picocolors46.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors46.default.dim(`(pid ${rec.pid}, port ${port})`) + ` for ${root}`
122722
123327
  );
122723
123328
  return "stopped";
122724
123329
  }
@@ -122726,7 +123331,7 @@ async function stopAll() {
122726
123331
  const registry2 = readRegistry();
122727
123332
  const projects2 = Object.entries(registry2.projects);
122728
123333
  if (projects2.length === 0) {
122729
- console.log(import_picocolors45.default.dim("No registered projects."));
123334
+ console.log(import_picocolors46.default.dim("No registered projects."));
122730
123335
  return 0;
122731
123336
  }
122732
123337
  let stopped = 0;
@@ -122738,17 +123343,17 @@ async function stopAll() {
122738
123343
  if (!healthy && readSpawnedHost(entry2.root) === null && readSourceHostPid(entry2.root) === null) {
122739
123344
  continue;
122740
123345
  }
122741
- console.log(` Stopping ${import_picocolors45.default.bold(name2)} ${import_picocolors45.default.dim(`(${hostUrl})`)}`);
123346
+ console.log(` Stopping ${import_picocolors46.default.bold(name2)} ${import_picocolors46.default.dim(`(${hostUrl})`)}`);
122742
123347
  const code = await stopHost(entry2.root, hostUrl);
122743
123348
  if (code === 0) stopped++;
122744
123349
  else failed++;
122745
123350
  }
122746
123351
  if (stopped === 0 && failed === 0) {
122747
- console.log(import_picocolors45.default.dim("No running source-intelligence hosts found."));
123352
+ console.log(import_picocolors46.default.dim("No running source-intelligence hosts found."));
122748
123353
  } else {
122749
123354
  console.log(
122750
123355
  `
122751
- Stopped ${stopped} host(s)${failed > 0 ? import_picocolors45.default.red(`, ${failed} failed`) : ""}.`
123356
+ Stopped ${stopped} host(s)${failed > 0 ? import_picocolors46.default.red(`, ${failed} failed`) : ""}.`
122752
123357
  );
122753
123358
  }
122754
123359
  return failed > 0 ? 1 : 0;
@@ -122836,7 +123441,7 @@ function extractPort(hostUrl) {
122836
123441
 
122837
123442
  // ../../packages/cli/src/commands/hosts.ts
122838
123443
  init_cjs_shims();
122839
- var import_picocolors46 = __toESM(require_picocolors(), 1);
123444
+ var import_picocolors47 = __toESM(require_picocolors(), 1);
122840
123445
 
122841
123446
  // ../../packages/cli/src/lib/host-reaper.ts
122842
123447
  init_cjs_shims();
@@ -122941,14 +123546,14 @@ async function runHosts(opts = {}) {
122941
123546
  for (const row of rows) {
122942
123547
  if (row.hostUrl === null) continue;
122943
123548
  printedAny = true;
122944
- const status = row.live ? import_picocolors46.default.green("\u25CF running") : import_picocolors46.default.red("\u25CF stopped");
123549
+ const status = row.live ? import_picocolors47.default.green("\u25CF running") : import_picocolors47.default.red("\u25CF stopped");
122945
123550
  const port = row.port ?? "?";
122946
123551
  console.log(
122947
- ` ${status} ${import_picocolors46.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors46.default.dim(row.root)}`
123552
+ ` ${status} ${import_picocolors47.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors47.default.dim(row.root)}`
122948
123553
  );
122949
123554
  }
122950
123555
  const noHost = rows.filter((r) => r.hostUrl === null);
122951
- for (const row of noHost) console.log(` ${import_picocolors46.default.dim("\u25CB no host")} ${import_picocolors46.default.dim(row.name)}`);
123556
+ for (const row of noHost) console.log(` ${import_picocolors47.default.dim("\u25CB no host")} ${import_picocolors47.default.dim(row.name)}`);
122952
123557
  if (printedAny || noHost.length > 0) console.log("");
122953
123558
  const claimedPids = /* @__PURE__ */ new Set();
122954
123559
  for (const [, entry2] of projects2) {
@@ -122961,37 +123566,37 @@ async function runHosts(opts = {}) {
122961
123566
  let reapFailed = 0;
122962
123567
  if (orphans.length > 0) {
122963
123568
  console.log(
122964
- import_picocolors46.default.yellow(` \u26A0 ${orphans.length} orphaned source host(s) \u2014 no registered repo owns them:`)
123569
+ import_picocolors47.default.yellow(` \u26A0 ${orphans.length} orphaned source host(s) \u2014 no registered repo owns them:`)
122965
123570
  );
122966
- for (const o5 of orphans) console.log(import_picocolors46.default.dim(` pid ${o5.pid} port ${o5.port}`));
123571
+ for (const o5 of orphans) console.log(import_picocolors47.default.dim(` pid ${o5.pid} port ${o5.port}`));
122967
123572
  if (opts.reap) {
122968
123573
  let reaped = 0;
122969
123574
  for (const o5 of orphans) {
122970
123575
  if (await reapPid(o5.pid)) {
122971
123576
  reaped++;
122972
- console.log(` ${import_picocolors46.default.green("\u2713")} reaped pid ${o5.pid} ${import_picocolors46.default.dim(`(port ${o5.port})`)}`);
123577
+ console.log(` ${import_picocolors47.default.green("\u2713")} reaped pid ${o5.pid} ${import_picocolors47.default.dim(`(port ${o5.port})`)}`);
122973
123578
  } else {
122974
123579
  reapFailed++;
122975
- console.log(import_picocolors46.default.red(` \u2717 could not stop pid ${o5.pid} (port ${o5.port})`));
123580
+ console.log(import_picocolors47.default.red(` \u2717 could not stop pid ${o5.pid} (port ${o5.port})`));
122976
123581
  }
122977
123582
  }
122978
- console.log(import_picocolors46.default.dim(` Reaped ${reaped}/${orphans.length} orphan(s).`));
123583
+ console.log(import_picocolors47.default.dim(` Reaped ${reaped}/${orphans.length} orphan(s).`));
122979
123584
  } else {
122980
- console.log(import_picocolors46.default.dim(" Run `horus hosts --reap` to stop them."));
123585
+ console.log(import_picocolors47.default.dim(" Run `horus hosts --reap` to stop them."));
122981
123586
  }
122982
123587
  console.log("");
122983
123588
  }
122984
123589
  if (projects2.length === 0 && orphans.length === 0) {
122985
- console.log(import_picocolors46.default.dim("No registered projects. Run `horus index` in a repo first."));
123590
+ console.log(import_picocolors47.default.dim("No registered projects. Run `horus index` in a repo first."));
122986
123591
  return 0;
122987
123592
  }
122988
123593
  if (!printedAny && orphans.length === 0) {
122989
- console.log(import_picocolors46.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
123594
+ console.log(import_picocolors47.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
122990
123595
  return 0;
122991
123596
  }
122992
123597
  const running = countDistinctLiveHosts(rows);
122993
123598
  console.log(
122994
- import_picocolors46.default.dim(
123599
+ import_picocolors47.default.dim(
122995
123600
  `${running} running${orphans.length ? ` \xB7 ${orphans.length} orphan(s)` : ""} \xB7 horus hosts --reap to clear orphans \xB7 horus stop --all to stop everything`
122996
123601
  )
122997
123602
  );
@@ -123008,7 +123613,7 @@ function extractPort2(hostUrl) {
123008
123613
 
123009
123614
  // ../../packages/cli/src/commands/doctor.ts
123010
123615
  init_cjs_shims();
123011
- var import_picocolors47 = __toESM(require_picocolors(), 1);
123616
+ var import_picocolors48 = __toESM(require_picocolors(), 1);
123012
123617
  var DEFAULT_DB_URL4 = "postgresql://horus:horus@localhost:5433/horus";
123013
123618
  var CONNECTOR_CHECKS = {
123014
123619
  // Elasticsearch (runtime logs)
@@ -123125,9 +123730,9 @@ var CONNECTOR_CHECKS = {
123125
123730
  };
123126
123731
  var DOCTOR_CONNECTOR_KEYS = Object.keys(CONNECTOR_CHECKS);
123127
123732
  function mark2(status) {
123128
- if (status === "pass") return import_picocolors47.default.green("\u2713");
123129
- if (status === "warn") return import_picocolors47.default.yellow("~");
123130
- return import_picocolors47.default.red("\u2717");
123733
+ if (status === "pass") return import_picocolors48.default.green("\u2713");
123734
+ if (status === "warn") return import_picocolors48.default.yellow("~");
123735
+ return import_picocolors48.default.red("\u2717");
123131
123736
  }
123132
123737
  async function runDoctor(opts) {
123133
123738
  const cwd = opts?.cwd ?? process.cwd();
@@ -123191,6 +123796,38 @@ async function runDoctor(opts) {
123191
123796
  next: "run `horus init` then `horus index` to set up source intelligence"
123192
123797
  });
123193
123798
  }
123799
+ {
123800
+ if (repoRoot && !isHorusGitignored(repoRoot)) {
123801
+ checks.push({
123802
+ label: "Secrets gitignore",
123803
+ status: "warn",
123804
+ detail: ".horus/ is NOT gitignored \u2014 credentials could be committed",
123805
+ next: "run `horus secrets migrate` (also hardens .gitignore), or add `.horus/` to .gitignore"
123806
+ });
123807
+ } else if (repoRoot) {
123808
+ checks.push({ label: "Secrets gitignore", status: "pass", detail: ".horus/ is gitignored" });
123809
+ }
123810
+ if (configPath) {
123811
+ try {
123812
+ const plaintext = findPlaintextConnectorSecrets(readLocalConfig(configPath).project);
123813
+ if (plaintext.length > 0) {
123814
+ checks.push({
123815
+ label: "Secret storage",
123816
+ status: "warn",
123817
+ detail: `${plaintext.length} plaintext credential(s) in config.json: ${plaintext.join(", ")}`,
123818
+ next: "run `horus secrets migrate` to encrypt them and strip config.json"
123819
+ });
123820
+ } else {
123821
+ checks.push({
123822
+ label: "Secret storage",
123823
+ status: "pass",
123824
+ detail: "no plaintext credentials in config.json"
123825
+ });
123826
+ }
123827
+ } catch {
123828
+ }
123829
+ }
123830
+ }
123194
123831
  {
123195
123832
  const dbChecker = opts?._dbCheck ?? checkDatabase;
123196
123833
  let dbUrl = process.env["DATABASE_URL"] ?? DEFAULT_DB_URL4;
@@ -123267,15 +123904,15 @@ async function runDoctor(opts) {
123267
123904
  write(JSON.stringify(output, null, 2));
123268
123905
  return hasFailure ? 1 : 0;
123269
123906
  }
123270
- write(import_picocolors47.default.bold("\nHorus readiness check\n"));
123907
+ write(import_picocolors48.default.bold("\nHorus readiness check\n"));
123271
123908
  for (const check2 of checks) {
123272
- write(` ${mark2(check2.status)} ${import_picocolors47.default.bold(check2.label.padEnd(26))} ${import_picocolors47.default.dim(check2.detail)}`);
123909
+ write(` ${mark2(check2.status)} ${import_picocolors48.default.bold(check2.label.padEnd(26))} ${import_picocolors48.default.dim(check2.detail)}`);
123273
123910
  if (check2.next) {
123274
- write(` ${import_picocolors47.default.dim("\u2192 " + check2.next)}`);
123911
+ write(` ${import_picocolors48.default.dim("\u2192 " + check2.next)}`);
123275
123912
  }
123276
123913
  }
123277
123914
  write("");
123278
- write(import_picocolors47.default.dim(" Hit a bug or a missing capability? Report it: horus report"));
123915
+ write(import_picocolors48.default.dim(" Hit a bug or a missing capability? Report it: horus report"));
123279
123916
  write("");
123280
123917
  return hasFailure ? 1 : 0;
123281
123918
  }
@@ -123283,16 +123920,16 @@ async function runDoctor(opts) {
123283
123920
  // ../../packages/cli/src/commands/providers-doctor.ts
123284
123921
  init_cjs_shims();
123285
123922
  var import_node_child_process12 = require("child_process");
123286
- var import_picocolors48 = __toESM(require_picocolors(), 1);
123923
+ var import_picocolors49 = __toESM(require_picocolors(), 1);
123287
123924
  function statusMark(status) {
123288
- if (status === "ready") return import_picocolors48.default.green("\u2713");
123289
- if (status === "installed") return import_picocolors48.default.yellow("~");
123290
- return import_picocolors48.default.red("\u2717");
123925
+ if (status === "ready") return import_picocolors49.default.green("\u2713");
123926
+ if (status === "installed") return import_picocolors49.default.yellow("~");
123927
+ return import_picocolors49.default.red("\u2717");
123291
123928
  }
123292
123929
  function statusLabel(status) {
123293
- if (status === "ready") return import_picocolors48.default.green("ready");
123294
- if (status === "installed") return import_picocolors48.default.yellow("installed (not configured)");
123295
- return import_picocolors48.default.dim("not found on PATH");
123930
+ if (status === "ready") return import_picocolors49.default.green("ready");
123931
+ if (status === "installed") return import_picocolors49.default.yellow("installed (not configured)");
123932
+ return import_picocolors49.default.dim("not found on PATH");
123296
123933
  }
123297
123934
  function detectBinary(id) {
123298
123935
  const result = (0, import_node_child_process12.spawnSync)(id, ["--version"], { stdio: "pipe", timeout: 2e3 });
@@ -123309,7 +123946,7 @@ async function runProvidersDoctorCommand(opts) {
123309
123946
  const registry2 = opts?.registry ?? DEFAULT_LOCAL_PROVIDER_REGISTRY;
123310
123947
  const write = opts?.write ?? ((line2) => console.log(line2));
123311
123948
  const results = buildProviderResults(registry2, opts?._detect);
123312
- write(import_picocolors48.default.bold("\nLocal AI providers\n"));
123949
+ write(import_picocolors49.default.bold("\nLocal AI providers\n"));
123313
123950
  for (const result of results) {
123314
123951
  const descriptor = registry2.get(result.id);
123315
123952
  const name2 = descriptor?.displayName ?? result.id;
@@ -123317,11 +123954,11 @@ async function runProvidersDoctorCommand(opts) {
123317
123954
  ` ${statusMark(result.status)} ${result.id.padEnd(8)} ${name2.padEnd(22)} ${statusLabel(result.status)}`
123318
123955
  );
123319
123956
  if (result.status !== "ready" && result.detail) {
123320
- write(` ${import_picocolors48.default.dim("\u2192 " + result.detail)}`);
123957
+ write(` ${import_picocolors49.default.dim("\u2192 " + result.detail)}`);
123321
123958
  }
123322
123959
  }
123323
123960
  write("");
123324
- write(import_picocolors48.default.bold("Cloud AI providers\n"));
123961
+ write(import_picocolors49.default.bold("Cloud AI providers\n"));
123325
123962
  let source = null;
123326
123963
  if (opts?._anthropicKey !== void 0) {
123327
123964
  source = opts._anthropicKey ? "env" : null;
@@ -123336,18 +123973,18 @@ async function runProvidersDoctorCommand(opts) {
123336
123973
  }
123337
123974
  if (source === "config") {
123338
123975
  write(
123339
- ` ${import_picocolors48.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors48.default.green("configured (local .horus config)")}`
123976
+ ` ${import_picocolors49.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.green("configured (local .horus config)")}`
123340
123977
  );
123341
123978
  } else if (source === "env") {
123342
123979
  write(
123343
- ` ${import_picocolors48.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors48.default.green("configured (ANTHROPIC_API_KEY env)")}`
123980
+ ` ${import_picocolors49.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.green("configured (ANTHROPIC_API_KEY env)")}`
123344
123981
  );
123345
123982
  } else {
123346
123983
  write(
123347
- ` ${import_picocolors48.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors48.default.dim("not configured")}`
123984
+ ` ${import_picocolors49.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.dim("not configured")}`
123348
123985
  );
123349
123986
  write(
123350
- ` ${import_picocolors48.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
123987
+ ` ${import_picocolors49.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
123351
123988
  );
123352
123989
  }
123353
123990
  write("");
@@ -123356,9 +123993,9 @@ async function runProvidersDoctorCommand(opts) {
123356
123993
 
123357
123994
  // ../../packages/cli/src/commands/generate-config.ts
123358
123995
  init_cjs_shims();
123359
- var import_node_fs22 = require("fs");
123360
- var import_node_path25 = require("path");
123361
- var import_picocolors49 = __toESM(require_picocolors(), 1);
123996
+ var import_node_fs24 = require("fs");
123997
+ var import_node_path26 = require("path");
123998
+ var import_picocolors50 = __toESM(require_picocolors(), 1);
123362
123999
  function configTemplate(name2, repoPath) {
123363
124000
  return `export default {
123364
124001
  database: {
@@ -123406,39 +124043,39 @@ async function runGenerateConfig(opts) {
123406
124043
  const defaults2 = localConfigPath2 != null ? projectDefaults(localConfigPath2) : null;
123407
124044
  const hasLocalConfig = defaults2 != null;
123408
124045
  const defaultOut = hasLocalConfig ? "horus.config.example.js" : "horus.config.js";
123409
- const outPath = (0, import_node_path25.resolve)(cwd, opts.out ?? defaultOut);
124046
+ const outPath = (0, import_node_path26.resolve)(cwd, opts.out ?? defaultOut);
123410
124047
  const name2 = opts.name ?? defaults2?.name ?? "my-project";
123411
124048
  const repoPath = opts.repo ?? defaults2?.repoPath ?? `/path/to/${name2}`;
123412
- if ((0, import_node_fs22.existsSync)(outPath) && !opts.force) {
123413
- log(`${import_picocolors49.default.red("\u2717")} ${outPath} already exists`);
123414
- log(import_picocolors49.default.dim(" pass --force to overwrite"));
124049
+ if ((0, import_node_fs24.existsSync)(outPath) && !opts.force) {
124050
+ log(`${import_picocolors50.default.red("\u2717")} ${outPath} already exists`);
124051
+ log(import_picocolors50.default.dim(" pass --force to overwrite"));
123415
124052
  return 1;
123416
124053
  }
123417
124054
  try {
123418
- (0, import_node_fs22.mkdirSync)((0, import_node_path25.dirname)(outPath), { recursive: true });
123419
- (0, import_node_fs22.writeFileSync)(outPath, configTemplate(name2, repoPath), "utf8");
124055
+ (0, import_node_fs24.mkdirSync)((0, import_node_path26.dirname)(outPath), { recursive: true });
124056
+ (0, import_node_fs24.writeFileSync)(outPath, configTemplate(name2, repoPath), "utf8");
123420
124057
  } catch (err2) {
123421
- log(`${import_picocolors49.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
124058
+ log(`${import_picocolors50.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
123422
124059
  return 1;
123423
124060
  }
123424
- log(`${import_picocolors49.default.green("\u2713")} Created ${outPath}`);
123425
- log(import_picocolors49.default.dim(` project: ${name2}`));
123426
- log(import_picocolors49.default.dim(` repo: ${repoPath}`));
124061
+ log(`${import_picocolors50.default.green("\u2713")} Created ${outPath}`);
124062
+ log(import_picocolors50.default.dim(` project: ${name2}`));
124063
+ log(import_picocolors50.default.dim(` repo: ${repoPath}`));
123427
124064
  if (hasLocalConfig && localConfigPath2 != null) {
123428
124065
  log("");
123429
- log(import_picocolors49.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
124066
+ log(import_picocolors50.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
123430
124067
  log(" \u2022 .horus/config.json \u2014 project config used by `horus investigate` from this repo");
123431
124068
  log(" \u2022 horus.config.js \u2014 standalone/global config used with `horus doctor --config <path>`");
123432
- log(import_picocolors49.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
124069
+ log(import_picocolors50.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
123433
124070
  } else {
123434
- log(import_picocolors49.default.dim(` next: horus doctor --config ${outPath}`));
124071
+ log(import_picocolors50.default.dim(` next: horus doctor --config ${outPath}`));
123435
124072
  }
123436
124073
  return 0;
123437
124074
  }
123438
124075
 
123439
124076
  // ../../packages/cli/src/commands/readiness.ts
123440
124077
  init_cjs_shims();
123441
- var import_picocolors50 = __toESM(require_picocolors(), 1);
124078
+ var import_picocolors51 = __toESM(require_picocolors(), 1);
123442
124079
  var READINESS_AI_CONTRACT = `Provide a clearly separated AI readiness summary with:
123443
124080
 
123444
124081
  Overall assessment
@@ -123461,9 +124098,9 @@ Confidence / gaps
123461
124098
  - Which checks Horus could verify vs. which require manual confirmation`;
123462
124099
  var DEFAULT_DB_URL5 = "postgresql://horus:horus@localhost:5433/horus";
123463
124100
  function mark3(status) {
123464
- if (status === "pass") return import_picocolors50.default.green("\u2713");
123465
- if (status === "warn") return import_picocolors50.default.yellow("~");
123466
- return import_picocolors50.default.red("\u2717");
124101
+ if (status === "pass") return import_picocolors51.default.green("\u2713");
124102
+ if (status === "warn") return import_picocolors51.default.yellow("~");
124103
+ return import_picocolors51.default.red("\u2717");
123467
124104
  }
123468
124105
  async function runReadiness(opts) {
123469
124106
  const cwd = opts?.cwd ?? process.cwd();
@@ -123668,20 +124305,20 @@ async function runReadiness(opts) {
123668
124305
  }
123669
124306
  const blockingChecks = checks.filter((c4) => c4.blocking);
123670
124307
  const optionalChecks = checks.filter((c4) => !c4.blocking);
123671
- write(import_picocolors50.default.bold("\nHorus release readiness\n"));
123672
- write(import_picocolors50.default.bold(" Blocking"));
124308
+ write(import_picocolors51.default.bold("\nHorus release readiness\n"));
124309
+ write(import_picocolors51.default.bold(" Blocking"));
123673
124310
  for (const check2 of blockingChecks) {
123674
- write(` ${mark3(check2.status)} ${import_picocolors50.default.bold(check2.label.padEnd(22))} ${import_picocolors50.default.dim(check2.detail)}`);
124311
+ write(` ${mark3(check2.status)} ${import_picocolors51.default.bold(check2.label.padEnd(22))} ${import_picocolors51.default.dim(check2.detail)}`);
123675
124312
  if (check2.next) {
123676
- write(` ${import_picocolors50.default.dim("\u2192 " + check2.next)}`);
124313
+ write(` ${import_picocolors51.default.dim("\u2192 " + check2.next)}`);
123677
124314
  }
123678
124315
  }
123679
124316
  write("");
123680
- write(import_picocolors50.default.bold(" Optional"));
124317
+ write(import_picocolors51.default.bold(" Optional"));
123681
124318
  for (const check2 of optionalChecks) {
123682
- write(` ${mark3(check2.status)} ${import_picocolors50.default.bold(check2.label.padEnd(22))} ${import_picocolors50.default.dim(check2.detail)}`);
124319
+ write(` ${mark3(check2.status)} ${import_picocolors51.default.bold(check2.label.padEnd(22))} ${import_picocolors51.default.dim(check2.detail)}`);
123683
124320
  if (check2.next) {
123684
- write(` ${import_picocolors50.default.dim("\u2192 " + check2.next)}`);
124321
+ write(` ${import_picocolors51.default.dim("\u2192 " + check2.next)}`);
123685
124322
  }
123686
124323
  }
123687
124324
  write("");
@@ -123689,21 +124326,21 @@ async function runReadiness(opts) {
123689
124326
  const optionalWarns = optionalChecks.filter((c4) => c4.status === "warn").length;
123690
124327
  if (blockingFails.length === 0) {
123691
124328
  if (optionalWarns === 0) {
123692
- write(import_picocolors50.default.green(" Ready for demo/release."));
124329
+ write(import_picocolors51.default.green(" Ready for demo/release."));
123693
124330
  } else {
123694
124331
  write(
123695
- import_picocolors50.default.yellow(
124332
+ import_picocolors51.default.yellow(
123696
124333
  ` Ready for a basic demo. ${optionalWarns} optional item(s) not configured \u2014 investigation evidence will be limited.`
123697
124334
  )
123698
124335
  );
123699
124336
  }
123700
124337
  } else {
123701
124338
  write(
123702
- import_picocolors50.default.red(
124339
+ import_picocolors51.default.red(
123703
124340
  ` Not ready. ${blockingFails.length} blocking item(s) must be resolved before demo/release.`
123704
124341
  )
123705
124342
  );
123706
- write(import_picocolors50.default.dim(" Re-run `horus readiness` after resolving the items above."));
124343
+ write(import_picocolors51.default.dim(" Re-run `horus readiness` after resolving the items above."));
123707
124344
  }
123708
124345
  write("");
123709
124346
  if (opts?.ai) {
@@ -123718,7 +124355,7 @@ async function runReadiness(opts) {
123718
124355
  });
123719
124356
  console.log("\n" + renderInterpretation(result));
123720
124357
  if (!result.ok) {
123721
- console.error(import_picocolors50.default.yellow(`[ai] ${result.warning}`));
124358
+ console.error(import_picocolors51.default.yellow(`[ai] ${result.warning}`));
123722
124359
  }
123723
124360
  }
123724
124361
  return blockingFails.length > 0 ? 1 : 0;
@@ -123726,33 +124363,33 @@ async function runReadiness(opts) {
123726
124363
 
123727
124364
  // ../../packages/cli/src/commands/skill.ts
123728
124365
  init_cjs_shims();
123729
- var import_node_fs23 = require("fs");
123730
- var import_node_path26 = require("path");
123731
- var import_node_os9 = require("os");
124366
+ var import_node_fs25 = require("fs");
124367
+ var import_node_path27 = require("path");
124368
+ var import_node_os10 = require("os");
123732
124369
  var import_promises3 = require("readline/promises");
123733
- var import_picocolors51 = __toESM(require_picocolors(), 1);
124370
+ var import_picocolors52 = __toESM(require_picocolors(), 1);
123734
124371
  var SUPPORTED_TARGETS = ["claude", "codex", "gemini", "cursor", "generic"];
123735
124372
  function isValidTarget(target) {
123736
124373
  return SUPPORTED_TARGETS.includes(target);
123737
124374
  }
123738
124375
  function getLegacyClaudeSkillPath(opts) {
123739
- const base2 = opts.global ? (0, import_node_os9.homedir)() : opts.cwd ?? process.cwd();
123740
- return (0, import_node_path26.join)(base2, ".claude", "skills", "horus.md");
124376
+ const base2 = opts.global ? (0, import_node_os10.homedir)() : opts.cwd ?? process.cwd();
124377
+ return (0, import_node_path27.join)(base2, ".claude", "skills", "horus.md");
123741
124378
  }
123742
124379
  function getSkillInstallPath(target, opts) {
123743
- const base2 = opts.global ? (0, import_node_os9.homedir)() : opts.cwd ?? process.cwd();
124380
+ const base2 = opts.global ? (0, import_node_os10.homedir)() : opts.cwd ?? process.cwd();
123744
124381
  switch (target) {
123745
124382
  case "claude":
123746
- return (0, import_node_path26.join)(base2, ".claude", "skills", "horus", "SKILL.md");
124383
+ return (0, import_node_path27.join)(base2, ".claude", "skills", "horus", "SKILL.md");
123747
124384
  case "gemini":
123748
- return opts.global ? (0, import_node_path26.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path26.join)(base2, "GEMINI.md");
124385
+ return opts.global ? (0, import_node_path27.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path27.join)(base2, "GEMINI.md");
123749
124386
  case "cursor":
123750
- return opts.global ? (0, import_node_path26.join)(base2, ".cursorrules") : (0, import_node_path26.join)(base2, ".cursor", "rules", "horus.mdc");
124387
+ return opts.global ? (0, import_node_path27.join)(base2, ".cursorrules") : (0, import_node_path27.join)(base2, ".cursor", "rules", "horus.mdc");
123751
124388
  case "codex":
123752
- return opts.global ? (0, import_node_path26.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path26.join)(base2, "AGENTS.md");
124389
+ return opts.global ? (0, import_node_path27.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path27.join)(base2, "AGENTS.md");
123753
124390
  case "generic":
123754
124391
  default:
123755
- return (0, import_node_path26.join)(base2, ".horus", "skills", `horus-${target}.md`);
124392
+ return (0, import_node_path27.join)(base2, ".horus", "skills", `horus-${target}.md`);
123756
124393
  }
123757
124394
  }
123758
124395
  var BASE_SKILL = `# Horus Grounded Investigation Skill
@@ -124069,66 +124706,66 @@ async function confirm(message) {
124069
124706
  async function runSkillInstall(target, opts) {
124070
124707
  const log = opts.write ?? ((line2) => console.log(line2));
124071
124708
  if (!isValidTarget(target)) {
124072
- log(`${import_picocolors51.default.red("\u2717")} Unknown target: ${import_picocolors51.default.bold(target)}`);
124073
- log(import_picocolors51.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
124709
+ log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
124710
+ log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
124074
124711
  return 1;
124075
124712
  }
124076
124713
  const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
124077
124714
  const content = generateSkillContent(target);
124078
124715
  if (target === "claude") {
124079
124716
  const legacyPath = getLegacyClaudeSkillPath({ global: opts.global, cwd: opts.cwd });
124080
- if ((0, import_node_fs23.existsSync)(legacyPath)) {
124717
+ if ((0, import_node_fs25.existsSync)(legacyPath)) {
124081
124718
  if (!opts.force) {
124082
124719
  const confirmed = await (opts.confirm ?? confirm)(
124083
124720
  `Found old flat skill file at ${legacyPath}. Replace it with the new directory layout?`
124084
124721
  );
124085
124722
  if (!confirmed) {
124086
- log(`${import_picocolors51.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
124087
- log(import_picocolors51.default.dim(" Pass --force to replace without prompting."));
124723
+ log(`${import_picocolors52.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
124724
+ log(import_picocolors52.default.dim(" Pass --force to replace without prompting."));
124088
124725
  return 1;
124089
124726
  }
124090
124727
  }
124091
124728
  try {
124092
- (0, import_node_fs23.rmSync)(legacyPath);
124093
- log(`${import_picocolors51.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
124729
+ (0, import_node_fs25.rmSync)(legacyPath);
124730
+ log(`${import_picocolors52.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
124094
124731
  } catch (err2) {
124095
- log(`${import_picocolors51.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err2.message}`);
124732
+ log(`${import_picocolors52.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err2.message}`);
124096
124733
  return 1;
124097
124734
  }
124098
124735
  }
124099
124736
  }
124100
- if ((0, import_node_fs23.existsSync)(outPath) && !opts.force) {
124101
- log(`${import_picocolors51.default.red("\u2717")} ${outPath} already exists`);
124102
- log(import_picocolors51.default.dim(" pass --force to overwrite"));
124737
+ if ((0, import_node_fs25.existsSync)(outPath) && !opts.force) {
124738
+ log(`${import_picocolors52.default.red("\u2717")} ${outPath} already exists`);
124739
+ log(import_picocolors52.default.dim(" pass --force to overwrite"));
124103
124740
  return 1;
124104
124741
  }
124105
124742
  try {
124106
- (0, import_node_fs23.mkdirSync)((0, import_node_path26.dirname)(outPath), { recursive: true });
124107
- (0, import_node_fs23.writeFileSync)(outPath, content, "utf8");
124743
+ (0, import_node_fs25.mkdirSync)((0, import_node_path27.dirname)(outPath), { recursive: true });
124744
+ (0, import_node_fs25.writeFileSync)(outPath, content, "utf8");
124108
124745
  } catch (err2) {
124109
- log(`${import_picocolors51.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
124746
+ log(`${import_picocolors52.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
124110
124747
  return 1;
124111
124748
  }
124112
- log(`${import_picocolors51.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
124749
+ log(`${import_picocolors52.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
124113
124750
  if (target === "claude") {
124114
- log(import_picocolors51.default.dim(" Claude Code will load this skill automatically."));
124115
- log(import_picocolors51.default.dim(" Invoke it with: /horus"));
124751
+ log(import_picocolors52.default.dim(" Claude Code will load this skill automatically."));
124752
+ log(import_picocolors52.default.dim(" Invoke it with: /horus"));
124116
124753
  } else if (target === "gemini") {
124117
- log(import_picocolors51.default.dim(" Gemini CLI will load this context file automatically."));
124754
+ log(import_picocolors52.default.dim(" Gemini CLI will load this context file automatically."));
124118
124755
  } else if (target === "cursor") {
124119
- log(import_picocolors51.default.dim(" Cursor will load this rule automatically."));
124756
+ log(import_picocolors52.default.dim(" Cursor will load this rule automatically."));
124120
124757
  } else if (target === "codex") {
124121
- log(import_picocolors51.default.dim(" Codex CLI will load this file automatically."));
124758
+ log(import_picocolors52.default.dim(" Codex CLI will load this file automatically."));
124122
124759
  } else {
124123
- log(import_picocolors51.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
124760
+ log(import_picocolors52.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
124124
124761
  }
124125
124762
  return 0;
124126
124763
  }
124127
124764
  async function runSkillPrint(target, opts) {
124128
124765
  const log = opts.write ?? ((line2) => console.log(line2));
124129
124766
  if (!isValidTarget(target)) {
124130
- log(`${import_picocolors51.default.red("\u2717")} Unknown target: ${import_picocolors51.default.bold(target)}`);
124131
- log(import_picocolors51.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
124767
+ log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
124768
+ log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
124132
124769
  return 1;
124133
124770
  }
124134
124771
  process.stdout.write(generateSkillContent(target));
@@ -124137,8 +124774,8 @@ async function runSkillPrint(target, opts) {
124137
124774
  async function runSkillPath(target, opts) {
124138
124775
  const log = opts.write ?? ((line2) => console.log(line2));
124139
124776
  if (!isValidTarget(target)) {
124140
- log(`${import_picocolors51.default.red("\u2717")} Unknown target: ${import_picocolors51.default.bold(target)}`);
124141
- log(import_picocolors51.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
124777
+ log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
124778
+ log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
124142
124779
  return 1;
124143
124780
  }
124144
124781
  const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
@@ -124148,7 +124785,7 @@ async function runSkillPath(target, opts) {
124148
124785
 
124149
124786
  // ../../packages/cli/src/commands/login.ts
124150
124787
  init_cjs_shims();
124151
- var import_picocolors52 = __toESM(require_picocolors(), 1);
124788
+ var import_picocolors53 = __toESM(require_picocolors(), 1);
124152
124789
  var sleep2 = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
124153
124790
  async function loginWithToken(apiBaseUrl, token) {
124154
124791
  const client = new CloudClient(apiBaseUrl, token);
@@ -124164,19 +124801,19 @@ async function loginWithToken(apiBaseUrl, token) {
124164
124801
  }
124165
124802
  });
124166
124803
  console.log(
124167
- `${import_picocolors52.default.green("\u2713")} Logged in as ${import_picocolors52.default.bold(me3.user.primaryEmail)}. Run ${import_picocolors52.default.bold("horus cloud link")} to connect this repo.`
124804
+ `${import_picocolors53.default.green("\u2713")} Logged in as ${import_picocolors53.default.bold(me3.user.primaryEmail)}. Run ${import_picocolors53.default.bold("horus cloud link")} to connect this repo.`
124168
124805
  );
124169
124806
  return 0;
124170
124807
  } catch (err2) {
124171
124808
  if (err2 instanceof CloudOfflineError) {
124172
- console.error(import_picocolors52.default.red(err2.message));
124809
+ console.error(import_picocolors53.default.red(err2.message));
124173
124810
  return 1;
124174
124811
  }
124175
124812
  if (err2 instanceof CloudError && err2.status === 401) {
124176
- console.error(import_picocolors52.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
124813
+ console.error(import_picocolors53.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
124177
124814
  return 1;
124178
124815
  }
124179
- console.error(import_picocolors52.default.red(`Login failed: ${err2.message}`));
124816
+ console.error(import_picocolors53.default.red(`Login failed: ${err2.message}`));
124180
124817
  return 1;
124181
124818
  }
124182
124819
  }
@@ -124187,19 +124824,19 @@ async function loginWithBrowser(apiBaseUrl) {
124187
124824
  session = await client.startCliSession();
124188
124825
  } catch (err2) {
124189
124826
  if (err2 instanceof CloudOfflineError) {
124190
- console.error(import_picocolors52.default.red(err2.message));
124827
+ console.error(import_picocolors53.default.red(err2.message));
124191
124828
  return 1;
124192
124829
  }
124193
- console.error(import_picocolors52.default.red(`Could not start login: ${err2.message}`));
124830
+ console.error(import_picocolors53.default.red(`Could not start login: ${err2.message}`));
124194
124831
  return 1;
124195
124832
  }
124196
124833
  console.log("");
124197
124834
  console.log(` To sign in, open this URL in your browser:`);
124198
- console.log(` ${import_picocolors52.default.cyan(import_picocolors52.default.bold(session.verificationUri))}`);
124835
+ console.log(` ${import_picocolors53.default.cyan(import_picocolors53.default.bold(session.verificationUri))}`);
124199
124836
  console.log("");
124200
- console.log(` and enter the code: ${import_picocolors52.default.bold(session.userCode)}`);
124837
+ console.log(` and enter the code: ${import_picocolors53.default.bold(session.userCode)}`);
124201
124838
  console.log("");
124202
- console.log(import_picocolors52.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
124839
+ console.log(import_picocolors53.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
124203
124840
  openBrowser(session.verificationUriComplete);
124204
124841
  const deadline = Date.now() + session.expiresIn * 1e3;
124205
124842
  let intervalMs = Math.max(session.interval, 1) * 1e3;
@@ -124210,7 +124847,7 @@ async function loginWithBrowser(apiBaseUrl) {
124210
124847
  poll = await client.pollCliSession(session.deviceCode);
124211
124848
  } catch (err2) {
124212
124849
  if (err2 instanceof CloudOfflineError) {
124213
- console.error(import_picocolors52.default.red(`
124850
+ console.error(import_picocolors53.default.red(`
124214
124851
  ${err2.message}`));
124215
124852
  return 1;
124216
124853
  }
@@ -124223,14 +124860,14 @@ ${err2.message}`));
124223
124860
  intervalMs += 2e3;
124224
124861
  break;
124225
124862
  case "denied":
124226
- console.error(import_picocolors52.default.red("\nLogin was denied in the browser."));
124863
+ console.error(import_picocolors53.default.red("\nLogin was denied in the browser."));
124227
124864
  return 1;
124228
124865
  case "expired":
124229
- console.error(import_picocolors52.default.red("\nThis login request expired. Run `horus login` again."));
124866
+ console.error(import_picocolors53.default.red("\nThis login request expired. Run `horus login` again."));
124230
124867
  return 1;
124231
124868
  case "approved":
124232
124869
  if (!poll.token || !poll.account) {
124233
- console.error(import_picocolors52.default.red("\nLogin approved but no token was returned. Try again."));
124870
+ console.error(import_picocolors53.default.red("\nLogin approved but no token was returned. Try again."));
124234
124871
  return 1;
124235
124872
  }
124236
124873
  writeAuth({
@@ -124240,12 +124877,12 @@ ${err2.message}`));
124240
124877
  });
124241
124878
  console.log(
124242
124879
  `
124243
- ${import_picocolors52.default.green("\u2713")} Logged in as ${import_picocolors52.default.bold(poll.account.email)}. Run ${import_picocolors52.default.bold("horus cloud link")} to connect this repo.`
124880
+ ${import_picocolors53.default.green("\u2713")} Logged in as ${import_picocolors53.default.bold(poll.account.email)}. Run ${import_picocolors53.default.bold("horus cloud link")} to connect this repo.`
124244
124881
  );
124245
124882
  return 0;
124246
124883
  }
124247
124884
  }
124248
- console.error(import_picocolors52.default.red("\nTimed out waiting for approval. Run `horus login` again."));
124885
+ console.error(import_picocolors53.default.red("\nTimed out waiting for approval. Run `horus login` again."));
124249
124886
  return 1;
124250
124887
  }
124251
124888
  async function runLogin(opts = {}) {
@@ -124259,7 +124896,7 @@ async function runLogin(opts = {}) {
124259
124896
  async function runLogout() {
124260
124897
  const auth = readAuth();
124261
124898
  if (!auth) {
124262
- console.log(import_picocolors52.default.dim("Not logged in."));
124899
+ console.log(import_picocolors53.default.dim("Not logged in."));
124263
124900
  return 0;
124264
124901
  }
124265
124902
  const session = authedClient();
@@ -124273,13 +124910,13 @@ async function runLogout() {
124273
124910
  }
124274
124911
  }
124275
124912
  clearAuth();
124276
- console.log(`${import_picocolors52.default.green("\u2713")} Logged out. Local mode still works.`);
124913
+ console.log(`${import_picocolors53.default.green("\u2713")} Logged out. Local mode still works.`);
124277
124914
  return 0;
124278
124915
  }
124279
124916
 
124280
124917
  // ../../packages/cli/src/commands/cloud.ts
124281
124918
  init_cjs_shims();
124282
- var import_picocolors53 = __toESM(require_picocolors(), 1);
124919
+ var import_picocolors54 = __toESM(require_picocolors(), 1);
124283
124920
  var import_promises4 = require("readline/promises");
124284
124921
 
124285
124922
  // ../../packages/cli/src/lib/cloud/git.ts
@@ -124324,7 +124961,7 @@ async function runCloudLink(opts = {}) {
124324
124961
  const root = repoRootOrCwd(opts.cwd);
124325
124962
  const session = authedClient();
124326
124963
  if (!session) {
124327
- console.error(import_picocolors53.default.red(`Not logged in. Run ${import_picocolors53.default.bold("horus login")} first.`));
124964
+ console.error(import_picocolors54.default.red(`Not logged in. Run ${import_picocolors54.default.bold("horus login")} first.`));
124328
124965
  return 1;
124329
124966
  }
124330
124967
  let ctx;
@@ -124334,7 +124971,7 @@ async function runCloudLink(opts = {}) {
124334
124971
  return reportCloudError(err2);
124335
124972
  }
124336
124973
  const remote = detectGitRemote(root);
124337
- if (remote) console.log(import_picocolors53.default.dim(`Detected git remote: ${remote.remoteUrl}`));
124974
+ if (remote) console.log(import_picocolors54.default.dim(`Detected git remote: ${remote.remoteUrl}`));
124338
124975
  let resolved = null;
124339
124976
  let target = opts.project;
124340
124977
  if (!target) {
@@ -124350,7 +124987,7 @@ async function runCloudLink(opts = {}) {
124350
124987
  const org = ctx.organizations.find((o5) => o5.id === match.organizationId);
124351
124988
  if (ws && org) {
124352
124989
  target = `${org.slug}/${ws.slug}/${match.slug}`;
124353
- console.log(import_picocolors53.default.dim(`Matched existing project by remote: ${import_picocolors53.default.bold(target)}`));
124990
+ console.log(import_picocolors54.default.dim(`Matched existing project by remote: ${import_picocolors54.default.bold(target)}`));
124354
124991
  }
124355
124992
  }
124356
124993
  }
@@ -124359,8 +124996,8 @@ async function runCloudLink(opts = {}) {
124359
124996
  if (created === "aborted") return 1;
124360
124997
  if (!created) {
124361
124998
  console.error(
124362
- import_picocolors53.default.red("No project to link.") + `
124363
- Run ${import_picocolors53.default.bold("horus cloud link")} in a TTY to create one, pass ${import_picocolors53.default.bold("--project <org/workspace/project>")}, or create a project at ${import_picocolors53.default.bold("https://cloud.horus.sh")}.`
124999
+ import_picocolors54.default.red("No project to link.") + `
125000
+ Run ${import_picocolors54.default.bold("horus cloud link")} in a TTY to create one, pass ${import_picocolors54.default.bold("--project <org/workspace/project>")}, or create a project at ${import_picocolors54.default.bold("https://cloud.horus.sh")}.`
124364
125001
  );
124365
125002
  return 1;
124366
125003
  }
@@ -124370,8 +125007,8 @@ async function runCloudLink(opts = {}) {
124370
125007
  resolved = resolveTriple(ctx, target);
124371
125008
  if (!resolved) {
124372
125009
  console.error(
124373
- import_picocolors53.default.red(`You don't have access to ${import_picocolors53.default.bold(target)}.`) + `
124374
- Run ${import_picocolors53.default.bold("horus context list")} to see available projects.`
125010
+ import_picocolors54.default.red(`You don't have access to ${import_picocolors54.default.bold(target)}.`) + `
125011
+ Run ${import_picocolors54.default.bold("horus context list")} to see available projects.`
124375
125012
  );
124376
125013
  return 1;
124377
125014
  }
@@ -124384,10 +125021,10 @@ async function runCloudLink(opts = {}) {
124384
125021
  project: resolved.project
124385
125022
  });
124386
125023
  console.log(
124387
- `${import_picocolors53.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors53.default.bold(label)} ${import_picocolors53.default.dim("(cloud)")}.`
125024
+ `${import_picocolors54.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors54.default.bold(label)} ${import_picocolors54.default.dim("(cloud)")}.`
124388
125025
  );
124389
125026
  console.log(
124390
- import_picocolors53.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors53.default.bold("horus context use local")} to switch back.`)
125027
+ import_picocolors54.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors54.default.bold("horus context use local")} to switch back.`)
124391
125028
  );
124392
125029
  return 0;
124393
125030
  }
@@ -124395,11 +125032,11 @@ async function runCloudUnlink(opts = {}) {
124395
125032
  const root = repoRootOrCwd(opts.cwd);
124396
125033
  const cfg = readCloudConfig(root);
124397
125034
  if (!cfg || cfg.context !== "cloud") {
124398
- console.log(import_picocolors53.default.dim("This repo isn't linked to a cloud project."));
125035
+ console.log(import_picocolors54.default.dim("This repo isn't linked to a cloud project."));
124399
125036
  return 0;
124400
125037
  }
124401
125038
  clearCloudConfig(root);
124402
- console.log(`${import_picocolors53.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors53.default.bold("local")} mode.`);
125039
+ console.log(`${import_picocolors54.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors54.default.bold("local")} mode.`);
124403
125040
  return 0;
124404
125041
  }
124405
125042
  async function runCloudStatus(opts = {}) {
@@ -124407,18 +125044,18 @@ async function runCloudStatus(opts = {}) {
124407
125044
  const cfg = readCloudConfig(root);
124408
125045
  const session = authedClient();
124409
125046
  if (!isCloudActive(cfg) || !cfg?.project) {
124410
- console.log(`${import_picocolors53.default.bold("Context:")} local`);
124411
- console.log(`${import_picocolors53.default.bold("Storage:")} local Postgres (~/.horus)`);
125047
+ console.log(`${import_picocolors54.default.bold("Context:")} local`);
125048
+ console.log(`${import_picocolors54.default.bold("Storage:")} local Postgres (~/.horus)`);
124412
125049
  console.log(
124413
- import_picocolors53.default.dim(`Tip: ${import_picocolors53.default.bold("horus login")} then ${import_picocolors53.default.bold("horus cloud link")} to share investigations with your team.`)
125050
+ import_picocolors54.default.dim(`Tip: ${import_picocolors54.default.bold("horus login")} then ${import_picocolors54.default.bold("horus cloud link")} to share investigations with your team.`)
124414
125051
  );
124415
125052
  return 0;
124416
125053
  }
124417
125054
  const triple = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
124418
- console.log(`${import_picocolors53.default.bold("Context:")} ${triple} ${import_picocolors53.default.dim("(cloud)")}`);
125055
+ console.log(`${import_picocolors54.default.bold("Context:")} ${triple} ${import_picocolors54.default.dim("(cloud)")}`);
124419
125056
  let projectLine = `${cfg.project.slug}`;
124420
125057
  let metaLines = [];
124421
- let account = import_picocolors53.default.dim("not logged in");
125058
+ let account = import_picocolors54.default.dim("not logged in");
124422
125059
  if (session) {
124423
125060
  account = session.auth.account.email;
124424
125061
  try {
@@ -124433,9 +125070,9 @@ async function runCloudStatus(opts = {}) {
124433
125070
  } catch {
124434
125071
  }
124435
125072
  }
124436
- console.log(`${import_picocolors53.default.bold("Project:")} ${projectLine}`);
125073
+ console.log(`${import_picocolors54.default.bold("Project:")} ${projectLine}`);
124437
125074
  for (const line2 of metaLines) console.log(line2);
124438
- console.log(`${import_picocolors53.default.bold("Account:")} ${account}`);
125075
+ console.log(`${import_picocolors54.default.bold("Account:")} ${account}`);
124439
125076
  return 0;
124440
125077
  }
124441
125078
  async function runCloudSync(opts = {}) {
@@ -124443,13 +125080,13 @@ async function runCloudSync(opts = {}) {
124443
125080
  const cfg = readCloudConfig(root);
124444
125081
  if (!isCloudActive(cfg) || !cfg.project) {
124445
125082
  console.error(
124446
- import_picocolors53.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors53.default.bold("horus cloud link")} first.`
125083
+ import_picocolors54.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors54.default.bold("horus cloud link")} first.`
124447
125084
  );
124448
125085
  return 1;
124449
125086
  }
124450
125087
  const session = authedClient();
124451
125088
  if (!session) {
124452
- console.error(import_picocolors53.default.red(`Not logged in. Run ${import_picocolors53.default.bold("horus login")} first.`));
125089
+ console.error(import_picocolors54.default.red(`Not logged in. Run ${import_picocolors54.default.bold("horus login")} first.`));
124453
125090
  return 1;
124454
125091
  }
124455
125092
  const { db, sql: sql2 } = await openDb(await resolveDbUrl(opts.config));
@@ -124467,26 +125104,26 @@ async function runCloudSync(opts = {}) {
124467
125104
  const target = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
124468
125105
  if (uploadable.length === 0) {
124469
125106
  console.log(
124470
- import_picocolors53.default.dim(
125107
+ import_picocolors54.default.dim(
124471
125108
  `No local investigations with reports to upload.` + (skippedNoReport ? ` (${skippedNoReport} without a report skipped)` : "")
124472
125109
  )
124473
125110
  );
124474
125111
  return 0;
124475
125112
  }
124476
- console.log(import_picocolors53.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors53.default.dim("(cloud)")}:`));
125113
+ console.log(import_picocolors54.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors54.default.dim("(cloud)")}:`));
124477
125114
  for (const c4 of uploadable.slice(0, 20)) {
124478
- console.log(` ${import_picocolors53.default.dim(c4.id.slice(0, 8))} ${(c4.title ?? "untitled").slice(0, 70)}`);
125115
+ console.log(` ${import_picocolors54.default.dim(c4.id.slice(0, 8))} ${(c4.title ?? "untitled").slice(0, 70)}`);
124479
125116
  }
124480
- if (uploadable.length > 20) console.log(import_picocolors53.default.dim(` \u2026and ${uploadable.length - 20} more`));
124481
- if (skippedNoReport) console.log(import_picocolors53.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
125117
+ if (uploadable.length > 20) console.log(import_picocolors54.default.dim(` \u2026and ${uploadable.length - 20} more`));
125118
+ if (skippedNoReport) console.log(import_picocolors54.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
124482
125119
  if (opts.dryRun) {
124483
- console.log(import_picocolors53.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
125120
+ console.log(import_picocolors54.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
124484
125121
  return 0;
124485
125122
  }
124486
125123
  if (!opts.yes) {
124487
125124
  if (!process.stdin.isTTY) {
124488
125125
  console.error(
124489
- import_picocolors53.default.yellow(`Re-run with ${import_picocolors53.default.bold("--yes")} to upload, or ${import_picocolors53.default.bold("--dry-run")} to preview only.`)
125126
+ import_picocolors54.default.yellow(`Re-run with ${import_picocolors54.default.bold("--yes")} to upload, or ${import_picocolors54.default.bold("--dry-run")} to preview only.`)
124490
125127
  );
124491
125128
  return 1;
124492
125129
  }
@@ -124494,7 +125131,7 @@ async function runCloudSync(opts = {}) {
124494
125131
  try {
124495
125132
  const answer = (await rl.question(`Upload ${uploadable.length} investigation(s) to ${target}? (y/N) `)).trim().toLowerCase();
124496
125133
  if (answer !== "y" && answer !== "yes") {
124497
- console.log(import_picocolors53.default.dim("Aborted. Nothing uploaded."));
125134
+ console.log(import_picocolors54.default.dim("Aborted. Nothing uploaded."));
124498
125135
  return 0;
124499
125136
  }
124500
125137
  } finally {
@@ -124507,18 +125144,18 @@ async function runCloudSync(opts = {}) {
124507
125144
  try {
124508
125145
  const refs = await uploadInvestigationToCloud(session.client, cfg, c4.report, { db });
124509
125146
  created++;
124510
- console.log(`${import_picocolors53.default.green("\u2713")} ${import_picocolors53.default.dim(c4.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
125147
+ console.log(`${import_picocolors54.default.green("\u2713")} ${import_picocolors54.default.dim(c4.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
124511
125148
  } catch (err2) {
124512
125149
  failed++;
124513
- console.error(`${import_picocolors53.default.red("\u2717")} ${import_picocolors53.default.dim(c4.id.slice(0, 8))} ${err2.message}`);
125150
+ console.error(`${import_picocolors54.default.red("\u2717")} ${import_picocolors54.default.dim(c4.id.slice(0, 8))} ${err2.message}`);
124514
125151
  }
124515
125152
  }
124516
125153
  console.log("");
124517
125154
  console.log(
124518
- `${import_picocolors53.default.bold("Sync complete:")} ${import_picocolors53.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors53.default.red(`${failed} failed`) : "0 failed") + "."
125155
+ `${import_picocolors54.default.bold("Sync complete:")} ${import_picocolors54.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors54.default.red(`${failed} failed`) : "0 failed") + "."
124519
125156
  );
124520
125157
  console.log(
124521
- import_picocolors53.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
125158
+ import_picocolors54.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
124522
125159
  );
124523
125160
  return failed > 0 ? 1 : 0;
124524
125161
  } finally {
@@ -124529,8 +125166,8 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
124529
125166
  if (!process.stdin.isTTY && !yes) return null;
124530
125167
  if (ctx.organizations.length === 0) {
124531
125168
  console.error(
124532
- import_picocolors53.default.red("You're not a member of any organization yet.") + `
124533
- Create one at ${import_picocolors53.default.bold("https://cloud.horus.sh")} first.`
125169
+ import_picocolors54.default.red("You're not a member of any organization yet.") + `
125170
+ Create one at ${import_picocolors54.default.bold("https://cloud.horus.sh")} first.`
124534
125171
  );
124535
125172
  return null;
124536
125173
  }
@@ -124555,9 +125192,9 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
124555
125192
  const wsName = await ask2("New workspace name", repoName || "default");
124556
125193
  const ws = await client.createWorkspace(org.id, { name: wsName });
124557
125194
  workspace = { id: ws.id, slug: ws.slug };
124558
- console.log(import_picocolors53.default.dim(`Created workspace ${import_picocolors53.default.bold(ws.slug)}.`));
125195
+ console.log(import_picocolors54.default.dim(`Created workspace ${import_picocolors54.default.bold(ws.slug)}.`));
124559
125196
  } else {
124560
- console.log(`Workspaces in ${import_picocolors53.default.bold(org.slug)}:`);
125197
+ console.log(`Workspaces in ${import_picocolors54.default.bold(org.slug)}:`);
124561
125198
  orgWorkspaces.forEach((w4, i3) => console.log(` ${i3 + 1}) ${w4.slug}`));
124562
125199
  console.log(` ${orgWorkspaces.length + 1}) + create a new workspace`);
124563
125200
  const pick2 = Number(await ask2("Workspace number", "1"));
@@ -124565,7 +125202,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
124565
125202
  const wsName = await ask2("New workspace name", repoName || "default");
124566
125203
  const ws = await client.createWorkspace(org.id, { name: wsName });
124567
125204
  workspace = { id: ws.id, slug: ws.slug };
124568
- console.log(import_picocolors53.default.dim(`Created workspace ${import_picocolors53.default.bold(ws.slug)}.`));
125205
+ console.log(import_picocolors54.default.dim(`Created workspace ${import_picocolors54.default.bold(ws.slug)}.`));
124569
125206
  } else {
124570
125207
  const chosen = orgWorkspaces[pick2 - 1] ?? orgWorkspaces[0];
124571
125208
  workspace = { id: chosen.id, slug: chosen.slug };
@@ -124577,7 +125214,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
124577
125214
  remoteUrl: remote?.remoteUrl,
124578
125215
  provider: remote ? inferProvider(remote.remoteUrl) : void 0
124579
125216
  });
124580
- console.log(import_picocolors53.default.dim(`Created project ${import_picocolors53.default.bold(project.slug)}.`));
125217
+ console.log(import_picocolors54.default.dim(`Created project ${import_picocolors54.default.bold(project.slug)}.`));
124581
125218
  return {
124582
125219
  organization: { id: org.id, slug: org.slug },
124583
125220
  workspace,
@@ -124593,8 +125230,8 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
124593
125230
 
124594
125231
  // ../../packages/cli/src/commands/telemetry.ts
124595
125232
  init_cjs_shims();
124596
- var import_picocolors55 = __toESM(require_picocolors(), 1);
124597
- var import_node_crypto10 = require("crypto");
125233
+ var import_picocolors56 = __toESM(require_picocolors(), 1);
125234
+ var import_node_crypto11 = require("crypto");
124598
125235
 
124599
125236
  // ../../packages/cli/src/lib/telemetry/transport.ts
124600
125237
  init_cjs_shims();
@@ -124654,7 +125291,7 @@ async function deleteRemoteTelemetry(installId, opts = {}) {
124654
125291
 
124655
125292
  // ../../packages/cli/src/lib/telemetry/notice.ts
124656
125293
  init_cjs_shims();
124657
- var import_picocolors54 = __toESM(require_picocolors(), 1);
125294
+ var import_picocolors55 = __toESM(require_picocolors(), 1);
124658
125295
  var PRIVACY_URL = "https://horus.sh/privacy";
124659
125296
  var SUPPRESS_FIRST_TOKEN = /* @__PURE__ */ new Set(["telemetry", "help"]);
124660
125297
  var SUPPRESS_FLAGS = /* @__PURE__ */ new Set(["-V", "--version", "-h", "--help"]);
@@ -124666,11 +125303,11 @@ function shouldSuppressFor(argv) {
124666
125303
  return firstToken != null && SUPPRESS_FIRST_TOKEN.has(firstToken);
124667
125304
  }
124668
125305
  function banner() {
124669
- const b5 = import_picocolors54.default.bold;
124670
- const dim = import_picocolors54.default.dim;
125306
+ const b5 = import_picocolors55.default.bold;
125307
+ const dim = import_picocolors55.default.dim;
124671
125308
  return [
124672
125309
  "",
124673
- import_picocolors54.default.cyan(b5("Horus collects anonymous usage data to improve the tool.")),
125310
+ import_picocolors55.default.cyan(b5("Horus collects anonymous usage data to improve the tool.")),
124674
125311
  dim(" \u2022 On by default: command names, timings, success/failure, and where the"),
124675
125312
  dim(" engine ran out of evidence. No file contents, queries, or secrets."),
124676
125313
  dim(" \u2022 Off by default: your investigation inputs/outputs (opt in to help train"),
@@ -124678,7 +125315,7 @@ function banner() {
124678
125315
  dim(" \u2022 If you use Horus Cloud, linked investigations sync to your workspace."),
124679
125316
  "",
124680
125317
  ` ${dim("Opt out anytime:")} ${b5("horus telemetry disable")} ${dim("\xB7")} ${b5("HORUS_TELEMETRY=0")} ${dim("\xB7")} ${b5("DO_NOT_TRACK=1")}`,
124681
- ` ${dim("Details:")} ${import_picocolors54.default.underline(PRIVACY_URL)}`,
125318
+ ` ${dim("Details:")} ${import_picocolors55.default.underline(PRIVACY_URL)}`,
124682
125319
  ""
124683
125320
  ].join("\n");
124684
125321
  }
@@ -124701,45 +125338,45 @@ function maybeShowFirstRunNotice(argv = process.argv) {
124701
125338
 
124702
125339
  // ../../packages/cli/src/commands/telemetry.ts
124703
125340
  function onOff(enabled) {
124704
- return enabled ? import_picocolors55.default.green("on") : import_picocolors55.default.dim("off");
125341
+ return enabled ? import_picocolors56.default.green("on") : import_picocolors56.default.dim("off");
124705
125342
  }
124706
125343
  function warnIfEnvOverrides() {
124707
125344
  const decision = resolveConsent();
124708
125345
  if (decision.forcedOff) {
124709
125346
  console.log(
124710
- import_picocolors55.default.yellow(
125347
+ import_picocolors56.default.yellow(
124711
125348
  `
124712
125349
  Note: telemetry is currently forced off by your environment (${decision.reason}).`
124713
125350
  )
124714
125351
  );
124715
- console.log(import_picocolors55.default.dim("Your saved preference will apply once that override is removed."));
125352
+ console.log(import_picocolors56.default.dim("Your saved preference will apply once that override is removed."));
124716
125353
  } else if (decision.source === "ci") {
124717
125354
  console.log(
124718
- import_picocolors55.default.yellow("\nNote: CI environment detected \u2014 telemetry stays off here regardless.")
125355
+ import_picocolors56.default.yellow("\nNote: CI environment detected \u2014 telemetry stays off here regardless.")
124719
125356
  );
124720
125357
  }
124721
125358
  }
124722
125359
  async function runTelemetryStatus() {
124723
125360
  const state = readTelemetryState();
124724
125361
  const decision = resolveConsent({ state });
124725
- console.log(import_picocolors55.default.bold("Horus telemetry"));
125362
+ console.log(import_picocolors56.default.bold("Horus telemetry"));
124726
125363
  console.log(
124727
- ` Usage metadata (Tier A): ${onOff(decision.tierA)} ${import_picocolors55.default.dim(`[${decision.source}]`)}`
125364
+ ` Usage metadata (Tier A): ${onOff(decision.tierA)} ${import_picocolors56.default.dim(`[${decision.source}]`)}`
124728
125365
  );
124729
125366
  console.log(` Content sharing (Tier B): ${onOff(decision.tierB)}`);
124730
- console.log(import_picocolors55.default.dim(` Reason: ${decision.reason}`));
125367
+ console.log(import_picocolors56.default.dim(` Reason: ${decision.reason}`));
124731
125368
  if (state) {
124732
- console.log(import_picocolors55.default.dim(` Install ID: ${state.installId}`));
125369
+ console.log(import_picocolors56.default.dim(` Install ID: ${state.installId}`));
124733
125370
  console.log(
124734
- import_picocolors55.default.dim(
125371
+ import_picocolors56.default.dim(
124735
125372
  ` Saved: Tier A ${state.tierA.enabled ? "on" : "off"}, Tier B ${state.tierB.enabled ? "on" : "off"}`
124736
125373
  )
124737
125374
  );
124738
125375
  } else {
124739
- console.log(import_picocolors55.default.dim(" No saved preference yet (defaults apply)."));
125376
+ console.log(import_picocolors56.default.dim(" No saved preference yet (defaults apply)."));
124740
125377
  }
124741
- console.log(import_picocolors55.default.dim(` Config: ${telemetryPath()}`));
124742
- console.log(import_picocolors55.default.dim(` Privacy: ${PRIVACY_URL}`));
125378
+ console.log(import_picocolors56.default.dim(` Config: ${telemetryPath()}`));
125379
+ console.log(import_picocolors56.default.dim(` Privacy: ${PRIVACY_URL}`));
124743
125380
  if (!state || decision.source === "env" || decision.source === "ci") {
124744
125381
  warnIfEnvOverrides();
124745
125382
  }
@@ -124750,7 +125387,7 @@ async function runTelemetryEnable() {
124750
125387
  s5.tierA.enabled = true;
124751
125388
  if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
124752
125389
  });
124753
- console.log(import_picocolors55.default.green("Anonymous usage metadata (Tier A) is now ON. Thank you!"));
125390
+ console.log(import_picocolors56.default.green("Anonymous usage metadata (Tier A) is now ON. Thank you!"));
124754
125391
  warnIfEnvOverrides();
124755
125392
  return 0;
124756
125393
  }
@@ -124760,7 +125397,7 @@ async function runTelemetryDisable() {
124760
125397
  s5.tierB.enabled = false;
124761
125398
  if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
124762
125399
  });
124763
- console.log(import_picocolors55.default.yellow("All telemetry is now OFF (Tier A and Tier B)."));
125400
+ console.log(import_picocolors56.default.yellow("All telemetry is now OFF (Tier A and Tier B)."));
124764
125401
  return 0;
124765
125402
  }
124766
125403
  async function runTelemetryEnableContent() {
@@ -124771,10 +125408,10 @@ async function runTelemetryEnableContent() {
124771
125408
  if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
124772
125409
  });
124773
125410
  console.log(
124774
- import_picocolors55.default.green("Content sharing (Tier B) is now ON \u2014 redacted inputs/outputs help improve Horus.")
125411
+ import_picocolors56.default.green("Content sharing (Tier B) is now ON \u2014 redacted inputs/outputs help improve Horus.")
124775
125412
  );
124776
- console.log(import_picocolors55.default.dim("Content is scrubbed of secrets/PII before it ever leaves your machine."));
124777
- console.log(import_picocolors55.default.dim(`What this means: ${PRIVACY_URL}`));
125413
+ console.log(import_picocolors56.default.dim("Content is scrubbed of secrets/PII before it ever leaves your machine."));
125414
+ console.log(import_picocolors56.default.dim(`What this means: ${PRIVACY_URL}`));
124778
125415
  warnIfEnvOverrides();
124779
125416
  return 0;
124780
125417
  }
@@ -124782,16 +125419,16 @@ async function runTelemetryDisableContent() {
124782
125419
  updateTelemetryState((s5) => {
124783
125420
  s5.tierB.enabled = false;
124784
125421
  });
124785
- console.log(import_picocolors55.default.yellow("Content sharing (Tier B) is now OFF. Usage metadata is unchanged."));
125422
+ console.log(import_picocolors56.default.yellow("Content sharing (Tier B) is now OFF. Usage metadata is unchanged."));
124786
125423
  return 0;
124787
125424
  }
124788
125425
  async function runTelemetryResetId() {
124789
- const next = (0, import_node_crypto10.randomUUID)();
125426
+ const next = (0, import_node_crypto11.randomUUID)();
124790
125427
  updateTelemetryState((s5) => {
124791
125428
  s5.installId = next;
124792
125429
  });
124793
- console.log(import_picocolors55.default.green("Install ID reset."));
124794
- console.log(import_picocolors55.default.dim(` New install ID: ${next}`));
125430
+ console.log(import_picocolors56.default.green("Install ID reset."));
125431
+ console.log(import_picocolors56.default.dim(` New install ID: ${next}`));
124795
125432
  return 0;
124796
125433
  }
124797
125434
  async function runTelemetryDelete() {
@@ -124799,9 +125436,9 @@ async function runTelemetryDelete() {
124799
125436
  if (installId) await deleteRemoteTelemetry(installId);
124800
125437
  deleteTelemetryState();
124801
125438
  clearSpool();
124802
- console.log(import_picocolors55.default.green("Telemetry deleted \u2014 local state cleared and a server purge requested."));
125439
+ console.log(import_picocolors56.default.green("Telemetry deleted \u2014 local state cleared and a server purge requested."));
124803
125440
  console.log(
124804
- import_picocolors55.default.dim(
125441
+ import_picocolors56.default.dim(
124805
125442
  "Next run will treat this as a fresh install and re-show the notice. If the purge could not reach the server (offline), re-run this command when back online."
124806
125443
  )
124807
125444
  );
@@ -124845,8 +125482,8 @@ function installCommandTelemetry(program2) {
124845
125482
  // ../../packages/cli/src/commands/eval.ts
124846
125483
  init_cjs_shims();
124847
125484
  var import_promises5 = require("fs/promises");
124848
- var import_node_path27 = require("path");
124849
- var import_picocolors56 = __toESM(require_picocolors(), 1);
125485
+ var import_node_path28 = require("path");
125486
+ var import_picocolors57 = __toESM(require_picocolors(), 1);
124850
125487
  function resolveProject2(config2, repo) {
124851
125488
  let project;
124852
125489
  try {
@@ -124854,7 +125491,7 @@ function resolveProject2(config2, repo) {
124854
125491
  } catch {
124855
125492
  }
124856
125493
  if (!project) {
124857
- console.error(import_picocolors56.default.red("Could not resolve a project \u2014 pass --repo <name> or run inside a repo."));
125494
+ console.error(import_picocolors57.default.red("Could not resolve a project \u2014 pass --repo <name> or run inside a repo."));
124858
125495
  return null;
124859
125496
  }
124860
125497
  return project;
@@ -124863,7 +125500,7 @@ function readSlice(opts) {
124863
125500
  let source;
124864
125501
  if (opts.source !== void 0) {
124865
125502
  if (!isOutcomeSource(opts.source)) {
124866
- console.error(import_picocolors56.default.red(`Unknown --source "${opts.source}" (one of: feedback, confirm).`));
125503
+ console.error(import_picocolors57.default.red(`Unknown --source "${opts.source}" (one of: feedback, confirm).`));
124867
125504
  return null;
124868
125505
  }
124869
125506
  source = opts.source;
@@ -124871,7 +125508,7 @@ function readSlice(opts) {
124871
125508
  let since;
124872
125509
  if (opts.days !== void 0) {
124873
125510
  if (!Number.isFinite(opts.days) || opts.days <= 0) {
124874
- console.error(import_picocolors56.default.red("--days must be a positive number."));
125511
+ console.error(import_picocolors57.default.red("--days must be a positive number."));
124875
125512
  return null;
124876
125513
  }
124877
125514
  since = new Date(Date.now() - opts.days * 24 * 60 * 60 * 1e3);
@@ -124895,7 +125532,7 @@ async function runEvalBuild(opts) {
124895
125532
  const project = resolveProject2(config2, opts.repo);
124896
125533
  if (!project) return 1;
124897
125534
  const version3 = opts.version ?? CORPUS_VERSION;
124898
- const outDir = opts.out ? (0, import_node_path27.isAbsolute)(opts.out) ? opts.out : (0, import_node_path27.resolve)(process.cwd(), opts.out) : (0, import_node_path27.join)(process.cwd(), ".horus", "eval");
125535
+ const outDir = opts.out ? (0, import_node_path28.isAbsolute)(opts.out) ? opts.out : (0, import_node_path28.resolve)(process.cwd(), opts.out) : (0, import_node_path28.join)(process.cwd(), ".horus", "eval");
124899
125536
  const { db, sql: sql2 } = await openDb(config2.database.url);
124900
125537
  try {
124901
125538
  const labels = await listOutcomeLabels(db, {
@@ -124911,34 +125548,34 @@ async function runEvalBuild(opts) {
124911
125548
  const build = buildCorpus(labels, resolveReport);
124912
125549
  const artifact = serializeCorpus(build, version3);
124913
125550
  await (0, import_promises5.mkdir)(outDir, { recursive: true });
124914
- const corpusPath = (0, import_node_path27.join)(outDir, artifact.filename);
124915
- const manifestPath = (0, import_node_path27.join)(outDir, `corpus-${version3}.manifest.json`);
125551
+ const corpusPath = (0, import_node_path28.join)(outDir, artifact.filename);
125552
+ const manifestPath = (0, import_node_path28.join)(outDir, `corpus-${version3}.manifest.json`);
124916
125553
  const manifest = { ...artifact.manifest, generatedAt: (/* @__PURE__ */ new Date()).toISOString(), project };
124917
125554
  await (0, import_promises5.writeFile)(corpusPath, artifact.jsonl, "utf8");
124918
125555
  await (0, import_promises5.writeFile)(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
124919
125556
  if (opts.json) {
124920
125557
  console.log(JSON.stringify({ project, corpusPath, manifestPath, manifest }, null, 2));
124921
125558
  } else {
124922
- console.log(import_picocolors56.default.bold(`Eval corpus \u2014 ${project}`));
125559
+ console.log(import_picocolors57.default.bold(`Eval corpus \u2014 ${project}`));
124923
125560
  console.log(
124924
- ` Rows: ${import_picocolors56.default.green(String(build.rows.length))} ` + import_picocolors56.default.dim(
125561
+ ` Rows: ${import_picocolors57.default.green(String(build.rows.length))} ` + import_picocolors57.default.dim(
124925
125562
  `(evaluated ${build.evaluated}, quarantined ${build.quarantined.length}, unjoinable ${build.unjoinable.length})`
124926
125563
  )
124927
125564
  );
124928
125565
  console.log(
124929
- import_picocolors56.default.dim(
125566
+ import_picocolors57.default.dim(
124930
125567
  ` Class balance: ${build.classBalance.yes} yes, ${build.classBalance.partly} partly, ${build.classBalance.no} no \xB7 source: ${build.bySource.feedback} feedback, ${build.bySource.confirm} confirm`
124931
125568
  )
124932
125569
  );
124933
- console.log(` Corpus: ${import_picocolors56.default.cyan(corpusPath)}`);
124934
- console.log(` Manifest: ${import_picocolors56.default.cyan(manifestPath)}`);
125570
+ console.log(` Corpus: ${import_picocolors57.default.cyan(corpusPath)}`);
125571
+ console.log(` Manifest: ${import_picocolors57.default.cyan(manifestPath)}`);
124935
125572
  }
124936
125573
  return 0;
124937
125574
  } finally {
124938
125575
  await sql2.end();
124939
125576
  }
124940
125577
  } catch (err2) {
124941
- console.error(import_picocolors56.default.red(err2.message));
125578
+ console.error(import_picocolors57.default.red(err2.message));
124942
125579
  return 1;
124943
125580
  }
124944
125581
  }
@@ -124968,31 +125605,31 @@ async function runEvalBaseline(opts) {
124968
125605
  console.log(JSON.stringify({ project, baseline, separation }, null, 2));
124969
125606
  } else {
124970
125607
  const pct2 = (n4) => `${(n4 * 100).toFixed(0)}%`;
124971
- console.log(import_picocolors56.default.bold(`Eval baseline \u2014 ${project}`));
125608
+ console.log(import_picocolors57.default.bold(`Eval baseline \u2014 ${project}`));
124972
125609
  if (baseline.n === 0) {
124973
125610
  console.log(
124974
- import_picocolors56.default.dim(
125611
+ import_picocolors57.default.dim(
124975
125612
  "No outcome labels yet. Leave feedback (`horus feedback`) or confirm an investigation (`horus memory confirm`) to seed the eval set."
124976
125613
  )
124977
125614
  );
124978
125615
  } else {
124979
125616
  console.log(
124980
- ` Strict hit-rate: ${import_picocolors56.default.green(pct2(baseline.strictHitRate))} ` + import_picocolors56.default.dim(`(weighted ${pct2(baseline.weightedHitRate)}) over ${baseline.n} investigation(s)`)
125617
+ ` Strict hit-rate: ${import_picocolors57.default.green(pct2(baseline.strictHitRate))} ` + import_picocolors57.default.dim(`(weighted ${pct2(baseline.weightedHitRate)}) over ${baseline.n} investigation(s)`)
124981
125618
  );
124982
125619
  console.log(
124983
- ` Class balance: ${import_picocolors56.default.green(`${baseline.classBalance.yes} yes`)}, ${import_picocolors56.default.yellow(`${baseline.classBalance.partly} partly`)}, ${import_picocolors56.default.red(`${baseline.classBalance.no} no`)} \xB7 ` + import_picocolors56.default.dim(`source: ${baseline.bySource.feedback} feedback, ${baseline.bySource.confirm} confirm`)
125620
+ ` Class balance: ${import_picocolors57.default.green(`${baseline.classBalance.yes} yes`)}, ${import_picocolors57.default.yellow(`${baseline.classBalance.partly} partly`)}, ${import_picocolors57.default.red(`${baseline.classBalance.no} no`)} \xB7 ` + import_picocolors57.default.dim(`source: ${baseline.bySource.feedback} feedback, ${baseline.bySource.confirm} confirm`)
124984
125621
  );
124985
125622
  if (separation.factors.length === 0) {
124986
125623
  console.log(
124987
- import_picocolors56.default.dim(
125624
+ import_picocolors57.default.dim(
124988
125625
  ` Feature separation: no discriminative sample yet (needs feedback rows with yes AND no verdicts and a ranked cause).`
124989
125626
  )
124990
125627
  );
124991
125628
  } else {
124992
- console.log(import_picocolors56.default.dim(` Feature separation (yes vs no, ${separation.evaluated} row(s)):`));
125629
+ console.log(import_picocolors57.default.dim(` Feature separation (yes vs no, ${separation.evaluated} row(s)):`));
124993
125630
  for (const f5 of separation.factors.slice(0, 10)) {
124994
125631
  console.log(
124995
- import_picocolors56.default.dim(
125632
+ import_picocolors57.default.dim(
124996
125633
  ` ${f5.factor}: \u0394 ${f5.separation.toFixed(3)} (yes ${f5.meanYes.toFixed(3)} vs no ${f5.meanNo.toFixed(3)}, effect ${f5.effectSize.toFixed(2)})`
124997
125634
  )
124998
125635
  );
@@ -125005,7 +125642,7 @@ async function runEvalBaseline(opts) {
125005
125642
  await sql2.end();
125006
125643
  }
125007
125644
  } catch (err2) {
125008
- console.error(import_picocolors56.default.red(err2.message));
125645
+ console.error(import_picocolors57.default.red(err2.message));
125009
125646
  return 1;
125010
125647
  }
125011
125648
  }
@@ -125013,10 +125650,10 @@ async function runEvalBaseline(opts) {
125013
125650
  // ../../packages/cli/src/commands/train.ts
125014
125651
  init_cjs_shims();
125015
125652
  var import_promises6 = require("fs/promises");
125016
- var import_node_path28 = require("path");
125017
- var import_node_os10 = require("os");
125018
- var import_picocolors57 = __toESM(require_picocolors(), 1);
125019
- var RERANKER_MODEL_PATH = (0, import_node_path28.join)((0, import_node_os10.homedir)(), ".horus", "reranker.json");
125653
+ var import_node_path29 = require("path");
125654
+ var import_node_os11 = require("os");
125655
+ var import_picocolors58 = __toESM(require_picocolors(), 1);
125656
+ var RERANKER_MODEL_PATH = (0, import_node_path29.join)((0, import_node_os11.homedir)(), ".horus", "reranker.json");
125020
125657
  function candidatesFromReport(blob) {
125021
125658
  if (blob === null || typeof blob !== "object") return null;
125022
125659
  const causes = blob.suspectedCauses;
@@ -125030,7 +125667,7 @@ async function runTrain(opts) {
125030
125667
  let source;
125031
125668
  if (opts.source !== void 0) {
125032
125669
  if (!isOutcomeSource(opts.source)) {
125033
- console.error(import_picocolors57.default.red(`Unknown --source "${opts.source}" (one of: feedback, confirm).`));
125670
+ console.error(import_picocolors58.default.red(`Unknown --source "${opts.source}" (one of: feedback, confirm).`));
125034
125671
  return 1;
125035
125672
  }
125036
125673
  source = opts.source;
@@ -125038,7 +125675,7 @@ async function runTrain(opts) {
125038
125675
  let since;
125039
125676
  if (opts.days !== void 0) {
125040
125677
  if (!Number.isFinite(opts.days) || opts.days <= 0) {
125041
- console.error(import_picocolors57.default.red("--days must be a positive number."));
125678
+ console.error(import_picocolors58.default.red("--days must be a positive number."));
125042
125679
  return 1;
125043
125680
  }
125044
125681
  since = new Date(Date.now() - opts.days * 24 * 60 * 60 * 1e3);
@@ -125074,7 +125711,7 @@ async function runTrain(opts) {
125074
125711
  await sql2.end();
125075
125712
  }
125076
125713
  } catch (err2) {
125077
- console.error(import_picocolors57.default.red(`Could not read the local corpus: ${err2.message}`));
125714
+ console.error(import_picocolors58.default.red(`Could not read the local corpus: ${err2.message}`));
125078
125715
  return 1;
125079
125716
  }
125080
125717
  const split = holdoutSplit(investigations2);
@@ -125082,48 +125719,48 @@ async function runTrain(opts) {
125082
125719
  if (!result.ok) {
125083
125720
  if (result.reason === "insufficient-corpus") {
125084
125721
  console.log(
125085
- import_picocolors57.default.yellow(
125722
+ import_picocolors58.default.yellow(
125086
125723
  `Not enough labeled investigations to train yet (have ${result.labeledInvestigations} with a known-correct cause; need \u2265${MIN_TRAIN_INVESTIGATIONS}).`
125087
125724
  )
125088
125725
  );
125089
- console.log(import_picocolors57.default.dim(" Keep labeling outcomes with `horus feedback` \u2014 the reranker trains once the corpus is large enough."));
125726
+ console.log(import_picocolors58.default.dim(" Keep labeling outcomes with `horus feedback` \u2014 the reranker trains once the corpus is large enough."));
125090
125727
  } else {
125091
- console.log(import_picocolors57.default.yellow(`Cannot train a meaningful model yet: ${result.detail}.`));
125728
+ console.log(import_picocolors58.default.yellow(`Cannot train a meaningful model yet: ${result.detail}.`));
125092
125729
  }
125093
125730
  return 0;
125094
125731
  }
125095
125732
  const { baselineHitRate, rerankedHitRate, delta, n: n4 } = result.holdout;
125096
- console.log(import_picocolors57.default.bold("\nReranker training (local, per-tenant)\n"));
125733
+ console.log(import_picocolors58.default.bold("\nReranker training (local, per-tenant)\n"));
125097
125734
  console.log(` Holdout investigations: ${n4}`);
125098
125735
  console.log(` Baseline top-1 hit-rate: ${pct(baselineHitRate)}`);
125099
125736
  console.log(` Reranked top-1 hit-rate: ${pct(rerankedHitRate)}`);
125100
125737
  console.log(` Delta: ${delta >= 0 ? "+" : ""}${pct(delta)}`);
125101
125738
  console.log("");
125102
125739
  if (delta <= 0) {
125103
- console.log(import_picocolors57.default.yellow(" The reranker did NOT beat the deterministic baseline \u2014 not saving a model."));
125104
- console.log(import_picocolors57.default.dim(" Horus stays on its hand-tuned ranking. Re-run as more labels accumulate."));
125740
+ console.log(import_picocolors58.default.yellow(" The reranker did NOT beat the deterministic baseline \u2014 not saving a model."));
125741
+ console.log(import_picocolors58.default.dim(" Horus stays on its hand-tuned ranking. Re-run as more labels accumulate."));
125105
125742
  return 0;
125106
125743
  }
125107
125744
  try {
125108
- await (0, import_promises6.mkdir)((0, import_node_path28.join)((0, import_node_os10.homedir)(), ".horus"), { recursive: true });
125745
+ await (0, import_promises6.mkdir)((0, import_node_path29.join)((0, import_node_os11.homedir)(), ".horus"), { recursive: true });
125109
125746
  const { ok: _ok, ...model } = result;
125110
125747
  void _ok;
125111
125748
  await (0, import_promises6.writeFile)(RERANKER_MODEL_PATH, JSON.stringify(model, null, 2) + "\n", "utf8");
125112
125749
  } catch (err2) {
125113
- console.error(import_picocolors57.default.red(`Trained, but could not write the model: ${err2.message}`));
125750
+ console.error(import_picocolors58.default.red(`Trained, but could not write the model: ${err2.message}`));
125114
125751
  return 1;
125115
125752
  }
125116
- console.log(import_picocolors57.default.green(` \u2713 Reranker beats baseline by +${pct(delta)} \u2014 saved to ${RERANKER_MODEL_PATH}`));
125117
- console.log(import_picocolors57.default.dim(" It ships OFF by default. Enable it with `HORUS_RERANK=1 horus investigate \u2026`."));
125753
+ console.log(import_picocolors58.default.green(` \u2713 Reranker beats baseline by +${pct(delta)} \u2014 saved to ${RERANKER_MODEL_PATH}`));
125754
+ console.log(import_picocolors58.default.dim(" It ships OFF by default. Enable it with `HORUS_RERANK=1 horus investigate \u2026`."));
125118
125755
  return 0;
125119
125756
  }
125120
125757
 
125121
125758
  // ../../packages/cli/src/lib/report-crash.ts
125122
125759
  init_cjs_shims();
125123
- var import_picocolors58 = __toESM(require_picocolors(), 1);
125760
+ var import_picocolors59 = __toESM(require_picocolors(), 1);
125124
125761
  function reportCrash(err2, log = console.error) {
125125
125762
  log(err2);
125126
- log(import_picocolors58.default.dim("\n Looks like a Horus bug or a missing capability? Report it: horus report"));
125763
+ log(import_picocolors59.default.dim("\n Looks like a Horus bug or a missing capability? Report it: horus report"));
125127
125764
  }
125128
125765
 
125129
125766
  // ../../packages/cli/src/index.ts
@@ -125211,6 +125848,16 @@ Examples:
125211
125848
  });
125212
125849
  }
125213
125850
  );
125851
+ const secrets = program2.command("secrets").description("Manage encrypted connector credentials (.horus/secrets.local.json) \u2014 HOR-452");
125852
+ secrets.command("status").description("Show the master key source, stored secrets, plaintext in config, and gitignore state").action(() => {
125853
+ process.exitCode = runSecretsStatus();
125854
+ });
125855
+ secrets.command("migrate").description("Move plaintext connector secrets out of config.json into the encrypted store").option("--dry-run", "list what would be migrated without changing anything").action((opts) => {
125856
+ process.exitCode = runSecretsMigrate({ dryRun: opts.dryRun });
125857
+ });
125858
+ secrets.command("key").description("Show the master key source; --show prints it (base64) for CI (HORUS_SECRET_KEY)").option("--show", "print the master key (treat as a credential)").action((opts) => {
125859
+ process.exitCode = runSecretsKey({ show: opts.show });
125860
+ });
125214
125861
  program2.command("stop").description("Stop the source-intelligence host for the current repo (or --all to stop every host)").option("--all", "stop all registered source-intelligence hosts").action(async (opts) => {
125215
125862
  process.exitCode = await runStop(opts);
125216
125863
  });