@merittdev/horus 0.8.17 → 0.8.19

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 (3) hide show
  1. package/README.md +11 -9
  2. package/dist/index.cjs +1153 -702
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -43846,7 +43846,7 @@ var require_pg_pool = __commonJS({
43846
43846
  function throwOnDoubleRelease() {
43847
43847
  throw new Error("Release called on client which has already been released to the pool.");
43848
43848
  }
43849
- function promisify6(Promise2, callback) {
43849
+ function promisify8(Promise2, callback) {
43850
43850
  if (callback) {
43851
43851
  return { callback, result: void 0 };
43852
43852
  }
@@ -43984,7 +43984,7 @@ var require_pg_pool = __commonJS({
43984
43984
  const err2 = new Error("Cannot use a pool after calling end on the pool");
43985
43985
  return cb ? cb(err2) : this.Promise.reject(err2);
43986
43986
  }
43987
- const response = promisify6(this.Promise, cb);
43987
+ const response = promisify8(this.Promise, cb);
43988
43988
  const result = response.result;
43989
43989
  if (this._isFull() || this._idle.length) {
43990
43990
  if (this._idle.length) {
@@ -44169,7 +44169,7 @@ var require_pg_pool = __commonJS({
44169
44169
  }
44170
44170
  query(text2, values2, cb) {
44171
44171
  if (typeof text2 === "function") {
44172
- const response2 = promisify6(this.Promise, text2);
44172
+ const response2 = promisify8(this.Promise, text2);
44173
44173
  setImmediate(function() {
44174
44174
  return response2.callback(new Error("Passing a function as the first parameter to pool.query is not supported"));
44175
44175
  });
@@ -44179,7 +44179,7 @@ var require_pg_pool = __commonJS({
44179
44179
  cb = values2;
44180
44180
  values2 = void 0;
44181
44181
  }
44182
- const response = promisify6(this.Promise, cb);
44182
+ const response = promisify8(this.Promise, cb);
44183
44183
  cb = response.callback;
44184
44184
  this.connect((err2, client) => {
44185
44185
  if (err2) {
@@ -44224,7 +44224,7 @@ var require_pg_pool = __commonJS({
44224
44224
  return cb ? cb(err2) : this.Promise.reject(err2);
44225
44225
  }
44226
44226
  this.ending = true;
44227
- const promised = promisify6(this.Promise, cb);
44227
+ const promised = promisify8(this.Promise, cb);
44228
44228
  this._endCallback = promised.callback;
44229
44229
  this._pulseQueue();
44230
44230
  return promised.result;
@@ -65880,8 +65880,8 @@ init_cjs_shims();
65880
65880
 
65881
65881
  // ../../packages/core/src/version.ts
65882
65882
  init_cjs_shims();
65883
- var HORUS_VERSION = true ? "0.8.17" : "dev";
65884
- var PINNED_SOURCE_VERSION = "1.5.3";
65883
+ var HORUS_VERSION = true ? "0.8.19" : "dev";
65884
+ var PINNED_SOURCE_VERSION = "1.5.5";
65885
65885
 
65886
65886
  // ../../packages/core/src/evidence.ts
65887
65887
  init_cjs_shims();
@@ -71008,11 +71008,22 @@ function isAnalyzed(root) {
71008
71008
  async function analyzeRepo(root) {
71009
71009
  const bin = await resolveSourceBin();
71010
71010
  if (!bin) throw new Error("horus-source not found on PATH. Install it: curl -fsSL https://horus.sh/install.sh | bash");
71011
- await exec(bin, ["analyze", "."], {
71012
- cwd: root,
71013
- timeout: 9e5,
71014
- maxBuffer: 64 * 1024 * 1024
71015
- });
71011
+ try {
71012
+ await exec(bin, ["analyze", "."], {
71013
+ cwd: root,
71014
+ timeout: 9e5,
71015
+ maxBuffer: 64 * 1024 * 1024
71016
+ });
71017
+ } catch (err2) {
71018
+ const e = err2;
71019
+ const tail = (e.stderr ?? "").trim().slice(-800);
71020
+ if (e.killed || e.signal === "SIGTERM" || e.code === "ETIMEDOUT") {
71021
+ throw new Error(
71022
+ `horus-source analyze timed out after 900s (large repo / slow embeddings phase)` + (tail ? ` \u2014 last output: ${tail}` : "")
71023
+ );
71024
+ }
71025
+ throw new Error(tail ? `horus-source analyze failed: ${tail}` : e.message ?? "horus-source analyze failed");
71026
+ }
71016
71027
  }
71017
71028
  function readSourceHostUrl(root) {
71018
71029
  const p5 = (0, import_node_path3.join)(root, ".horus", "source", "host.json");
@@ -71105,6 +71116,34 @@ function removeSpawnedHostRecord(root) {
71105
71116
  } catch {
71106
71117
  }
71107
71118
  }
71119
+ async function killSpawnedHost(root) {
71120
+ const pids = /* @__PURE__ */ new Set();
71121
+ const spawned = readSpawnedHost(root);
71122
+ if (spawned?.pid) pids.add(spawned.pid);
71123
+ const backend = readSourceHostPid(root);
71124
+ if (backend?.pid) pids.add(backend.pid);
71125
+ for (const pid of pids) {
71126
+ for (const signal of ["SIGTERM", "SIGKILL"]) {
71127
+ try {
71128
+ process.kill(pid, signal);
71129
+ } catch {
71130
+ break;
71131
+ }
71132
+ let dead = false;
71133
+ for (let i3 = 0; i3 < 15; i3 += 1) {
71134
+ await new Promise((r) => setTimeout(r, 200));
71135
+ try {
71136
+ process.kill(pid, 0);
71137
+ } catch {
71138
+ dead = true;
71139
+ break;
71140
+ }
71141
+ }
71142
+ if (dead) break;
71143
+ }
71144
+ }
71145
+ removeSpawnedHostRecord(root);
71146
+ }
71108
71147
  function reconcileSpawnedHostPid(root, port) {
71109
71148
  try {
71110
71149
  const backend = readSourceHostPid(root);
@@ -75560,7 +75599,7 @@ function sql(strings, ...params) {
75560
75599
  return new SQL([new StringChunk(str3)]);
75561
75600
  }
75562
75601
  sql2.raw = raw;
75563
- function join14(chunks, separator) {
75602
+ function join15(chunks, separator) {
75564
75603
  const result = [];
75565
75604
  for (const [i3, chunk] of chunks.entries()) {
75566
75605
  if (i3 > 0 && separator !== void 0) {
@@ -75570,7 +75609,7 @@ function sql(strings, ...params) {
75570
75609
  }
75571
75610
  return new SQL(result);
75572
75611
  }
75573
- sql2.join = join14;
75612
+ sql2.join = join15;
75574
75613
  function identifier(value) {
75575
75614
  return new Name(value);
75576
75615
  }
@@ -79161,7 +79200,7 @@ var PgSelectQueryBuilderBase = class extends TypedQueryBuilder {
79161
79200
  return (table, on2) => {
79162
79201
  const baseTableName = this.tableName;
79163
79202
  const tableName = getTableLikeName(table);
79164
- if (typeof tableName === "string" && this.config.joins?.some((join14) => join14.alias === tableName)) {
79203
+ if (typeof tableName === "string" && this.config.joins?.some((join15) => join15.alias === tableName)) {
79165
79204
  throw new Error(`Alias "${tableName}" is already used in this query`);
79166
79205
  }
79167
79206
  if (!this.isPartialSelect) {
@@ -80173,7 +80212,7 @@ var PgUpdateBase = class extends QueryPromise {
80173
80212
  createJoin(joinType) {
80174
80213
  return (table, on2) => {
80175
80214
  const tableName = getTableLikeName(table);
80176
- if (typeof tableName === "string" && this.config.joins.some((join14) => join14.alias === tableName)) {
80215
+ if (typeof tableName === "string" && this.config.joins.some((join15) => join15.alias === tableName)) {
80177
80216
  throw new Error(`Alias "${tableName}" is already used in this query`);
80178
80217
  }
80179
80218
  if (typeof on2 === "function") {
@@ -80269,10 +80308,10 @@ var PgUpdateBase = class extends QueryPromise {
80269
80308
  const fromFields = this.getTableLikeFields(this.config.from);
80270
80309
  fields[tableName] = fromFields;
80271
80310
  }
80272
- for (const join14 of this.config.joins) {
80273
- const tableName2 = getTableLikeName(join14.table);
80274
- if (typeof tableName2 === "string" && !is(join14.table, SQL)) {
80275
- const fromFields = this.getTableLikeFields(join14.table);
80311
+ for (const join15 of this.config.joins) {
80312
+ const tableName2 = getTableLikeName(join15.table);
80313
+ if (typeof tableName2 === "string" && !is(join15.table, SQL)) {
80314
+ const fromFields = this.getTableLikeFields(join15.table);
80276
80315
  fields[tableName2] = fromFields;
80277
80316
  }
80278
80317
  }
@@ -90401,6 +90440,10 @@ function reportToMarkdown(r) {
90401
90440
 
90402
90441
  // ../../packages/engine/src/ownership.ts
90403
90442
  init_cjs_shims();
90443
+ var BOT_AUTHOR_RE = /\[bot\]|^(?:github-actions|dependabot|renovate(?:-bot)?|greenkeeper|snyk-bot|mergify|codecov|semantic-release-bot|allcontributors)\b/i;
90444
+ function isBotAuthor(author) {
90445
+ return BOT_AUTHOR_RE.test((author ?? "").trim());
90446
+ }
90404
90447
  var CODE_EXTENSIONS = /* @__PURE__ */ new Set([
90405
90448
  "ts",
90406
90449
  "tsx",
@@ -90507,10 +90550,12 @@ async function estimateOwnership(query, deps) {
90507
90550
  };
90508
90551
  }
90509
90552
  const contributors = await gitFileContributors(deps.repoPath, file);
90510
- const total = contributors.reduce((n4, c4) => n4 + c4.commits, 0);
90511
- const lead = contributors[0] ?? null;
90553
+ const humans = contributors.filter((c4) => !isBotAuthor(c4.author));
90554
+ const ranked = humans.length > 0 ? humans : contributors;
90555
+ const total = ranked.reduce((n4, c4) => n4 + c4.commits, 0);
90556
+ const lead = ranked[0] ?? null;
90512
90557
  const maintainerShare = total > 0 && lead !== null ? lead.commits / total : 0;
90513
- const byRecent = [...contributors].sort(
90558
+ const byRecent = [...ranked].sort(
90514
90559
  (a2, b5) => b5.lastDate < a2.lastDate ? -1 : b5.lastDate > a2.lastDate ? 1 : 0
90515
90560
  );
90516
90561
  const mostActiveRecent = byRecent[0]?.author ?? null;
@@ -91250,6 +91295,30 @@ function factorRequestContext(sourceEvidenceIds, graph, request) {
91250
91295
  reason: `Cause directly implicates the investigated service (${request.service})`
91251
91296
  };
91252
91297
  }
91298
+ function factorIncidentHistory(sourceEvidenceIds, graph, priorIncidents) {
91299
+ if (priorIncidents.size === 0) return null;
91300
+ const idSet = new Set(sourceEvidenceIds);
91301
+ const codeNodes = graph.nodes.filter(
91302
+ (n4) => (n4.type === "symbol" || n4.type === "file") && n4.evidenceIds.some((eid) => idSet.has(eid))
91303
+ );
91304
+ const matched = [];
91305
+ let totalPrior = 0;
91306
+ for (const n4 of codeNodes) {
91307
+ const count = priorIncidents.get(n4.id);
91308
+ if (count && count > 0) {
91309
+ matched.push(n4);
91310
+ totalPrior += count;
91311
+ }
91312
+ }
91313
+ if (matched.length === 0) return null;
91314
+ const delta = +Math.min(matched.length * 0.04, 0.1).toFixed(3);
91315
+ const names = matched.slice(0, 3).map((n4) => n4.label);
91316
+ return {
91317
+ factor: "incident-history",
91318
+ delta,
91319
+ reason: `Implicated code has a prior-incident history (${totalPrior} prior investigation(s) on ${names.join(", ")}${matched.length > 3 ? ", \u2026" : ""})`
91320
+ };
91321
+ }
91253
91322
  function scoreCause(input, ctx) {
91254
91323
  const now = ctx.now ?? (/* @__PURE__ */ new Date()).toISOString();
91255
91324
  const idSet = new Set(input.sourceEvidenceIds);
@@ -91263,7 +91332,8 @@ function scoreCause(input, ctx) {
91263
91332
  factorSignalStrength(attached),
91264
91333
  factorFindingUncertainty(input.sourceEvidenceIds, ctx.findings ?? []),
91265
91334
  ctx.providerReliability ? factorProviderReliability(attached, ctx.providerReliability) : null,
91266
- ctx.request ? factorRequestContext(input.sourceEvidenceIds, ctx.graph, ctx.request) : null
91335
+ ctx.request ? factorRequestContext(input.sourceEvidenceIds, ctx.graph, ctx.request) : null,
91336
+ ctx.priorIncidents ? factorIncidentHistory(input.sourceEvidenceIds, ctx.graph, ctx.priorIncidents) : null
91267
91337
  ];
91268
91338
  const explanations = rawFactors.filter((f5) => f5 !== null);
91269
91339
  const totalDelta = explanations.reduce((sum, e) => sum + e.delta, 0);
@@ -92005,6 +92075,11 @@ function scoreSeed(s5, index2, hintTokens, changedFiles, hintHasCode) {
92005
92075
  if (/(^|\/)(tests?|__tests__|spec)\//i.test(s5.filePath) || /(\.|_)(test|spec)\.[jt]sx?$/i.test(s5.filePath) || /(^|\/)test_[^/]*\.py$/i.test(s5.filePath) || /_test\.py$/i.test(s5.filePath)) {
92006
92076
  score -= 4;
92007
92077
  }
92078
+ if (/(^|\/)(examples?|samples?|demos?|fixtures?|sandbox|playground|docs|docs_src|tutorials?)(\/|$)/i.test(
92079
+ s5.filePath
92080
+ )) {
92081
+ score -= 4;
92082
+ }
92008
92083
  score += Math.max(0, 5 - index2) * (hintHasCode ? 0.8 : 0.1);
92009
92084
  if (s5.score !== void 0) score += s5.score * (hintHasCode ? 8 : 1.5);
92010
92085
  if (/\.[jt]sx?$/i.test(s5.name)) score -= 5;
@@ -92020,13 +92095,24 @@ function scoreSeed(s5, index2, hintTokens, changedFiles, hintHasCode) {
92020
92095
  }
92021
92096
  return score;
92022
92097
  }
92098
+ function isDeprioritizedSeedPath(filePath) {
92099
+ return /(^|\/)(tests?|__tests__|spec)\//i.test(filePath) || /(\.|_)(test|spec)\.[jt]sx?$/i.test(filePath) || /(^|\/)test_[^/]*\.py$/i.test(filePath) || /_test\.py$/i.test(filePath) || /(^|\/)(examples?|samples?|demos?|fixtures?|sandbox|playground|docs|docs_src|tutorials?)(\/|$)/i.test(
92100
+ filePath
92101
+ );
92102
+ }
92023
92103
  function rankSeeds(seeds, hintTokens, changedFiles, hintHasCode) {
92024
- return seeds.map((symbol, i3) => ({
92104
+ const scored = seeds.map((symbol, i3) => ({
92025
92105
  symbol,
92026
92106
  score: scoreSeed(symbol, i3, hintTokens, changedFiles, hintHasCode),
92027
92107
  role: seedRole(symbol),
92028
- i: i3
92029
- })).sort((a2, b5) => b5.score === a2.score ? a2.i - b5.i : b5.score - a2.score).map(({ symbol, score, role }) => ({ symbol, score, role }));
92108
+ i: i3,
92109
+ deprio: isDeprioritizedSeedPath(symbol.filePath)
92110
+ }));
92111
+ const hasReal = scored.some((s5) => !s5.deprio);
92112
+ if (hasReal) {
92113
+ for (const s5 of scored) if (s5.deprio) s5.score -= 1e3;
92114
+ }
92115
+ return scored.sort((a2, b5) => b5.score === a2.score ? a2.i - b5.i : b5.score - a2.score).map(({ symbol, score, role }) => ({ symbol, score, role }));
92030
92116
  }
92031
92117
 
92032
92118
  // ../../packages/engine/src/normalize.ts
@@ -92681,12 +92767,12 @@ async function investigate(input, deps) {
92681
92767
  const fp = (s5.filePath ?? "").replace(/^\.?\/+/, "");
92682
92768
  return fp === scopePrefix || fp.startsWith(scopePrefix + "/");
92683
92769
  };
92684
- const seedSearchLimit = scopePrefix ? 25 : 5;
92685
- const rawSeeds = code ? (await code.searchSymbols(hint, seedSearchLimit)).filter(inScope).slice(0, 5) : [];
92770
+ const seedSearchLimit = scopePrefix ? 30 : 20;
92771
+ const rawSeeds = code ? (await code.searchSymbols(hint, seedSearchLimit)).filter(inScope) : [];
92686
92772
  const hintTokens = [...new Set(tokenize(hint))];
92687
92773
  const hintHasCode = /\b(?=[A-Z0-9_]*[0-9_])[A-Z][A-Z0-9_]{3,}\b/.test(hint);
92688
92774
  const ranked = rankSeeds(rawSeeds, hintTokens, changedFilePaths, hintHasCode);
92689
- let seeds = ranked.map((r) => r.symbol);
92775
+ let seeds = ranked.map((r) => r.symbol).slice(0, 5);
92690
92776
  let top = seeds[0];
92691
92777
  if (top && code && isTypeLikeName(top.name)) {
92692
92778
  const base2 = executableBaseName(top.name);
@@ -93481,11 +93567,12 @@ async function investigate(input, deps) {
93481
93567
  const causeChains = buildCauseChains(validated, evidence2, graph, label);
93482
93568
  const findings2 = [];
93483
93569
  if (top && seedEv) {
93570
+ const seedConfidence = seedIsLowConfidence ? Math.min(0.4, top.score ?? 0.3) : Math.min(0.95, Math.max(0.5, top.score ?? 0.75));
93484
93571
  findings2.push({
93485
93572
  kind: "observation",
93486
93573
  title: `Seed resolves to ${label} at ${seedLoc}`,
93487
93574
  detail: top.signature ?? void 0,
93488
- confidence: 1,
93575
+ confidence: +seedConfidence.toFixed(2),
93489
93576
  evidenceIds: [seedEv.id]
93490
93577
  });
93491
93578
  }
@@ -93867,12 +93954,31 @@ async function investigate(input, deps) {
93867
93954
  ...deps.queue != null ? { queue: 0.9 } : {},
93868
93955
  ...deps.metrics != null ? { metrics: 0.75 } : {}
93869
93956
  };
93957
+ const priorIncidents = /* @__PURE__ */ new Map();
93958
+ try {
93959
+ const priors = await listInvestigationsWithReports(deps.db, 50);
93960
+ for (const row of priors) {
93961
+ const rep = row.report;
93962
+ if (!rep || !Array.isArray(rep.evidence) || rep.evidence.length === 0) continue;
93963
+ if (typeof rep.confidence === "number" && rep.confidence < 0.5) continue;
93964
+ const priorGraph = buildGraph(rep.evidence);
93965
+ const seen = /* @__PURE__ */ new Set();
93966
+ for (const n4 of priorGraph.nodes) {
93967
+ if ((n4.type === "symbol" || n4.type === "file") && !seen.has(n4.id)) {
93968
+ seen.add(n4.id);
93969
+ priorIncidents.set(n4.id, (priorIncidents.get(n4.id) ?? 0) + 1);
93970
+ }
93971
+ }
93972
+ }
93973
+ } catch {
93974
+ }
93870
93975
  const rankedCauses = rankCauses(causeInputs, {
93871
93976
  evidence: evidence2,
93872
93977
  graph,
93873
93978
  findings: findings2,
93874
93979
  providerReliability,
93875
- request: { hint: input.hint, service: input.service }
93980
+ request: { hint: input.hint, service: input.service },
93981
+ ...priorIncidents.size > 0 ? { priorIncidents } : {}
93876
93982
  });
93877
93983
  const evidenceConfidence = computeWeightedEvidenceConfidence(
93878
93984
  evidence2,
@@ -94442,8 +94548,53 @@ var EXTERNAL_MARKERS = [
94442
94548
  "postgres",
94443
94549
  "mariadb",
94444
94550
  "mysql2",
94445
- "mssql"
94551
+ "mssql",
94552
+ // Python async DB drivers (HOR-379): the markers above missed several backends real Python
94553
+ // DB libs implement (e.g. `databases` caught sqlalchemy/postgres/psycopg but missed asyncpg,
94554
+ // aiomysql/asyncmy, aiopg, aiosqlite). Their names don't substring-match the sync drivers, so
94555
+ // they need explicit markers. 'sqlite' also covers sqlite3/aiosqlite.
94556
+ "sqlite",
94557
+ "asyncpg",
94558
+ "aiomysql",
94559
+ "asyncmy",
94560
+ "aiopg",
94561
+ "pymysql"
94446
94562
  ];
94563
+ var TESTY_TOKENS = /* @__PURE__ */ new Set([
94564
+ "test",
94565
+ "tests",
94566
+ "spec",
94567
+ "specs",
94568
+ "example",
94569
+ "examples",
94570
+ "sample",
94571
+ "samples",
94572
+ "demo",
94573
+ "demos",
94574
+ "docs",
94575
+ "doc",
94576
+ "tutorial",
94577
+ "tutorials",
94578
+ "fixture",
94579
+ "fixtures",
94580
+ "e2e"
94581
+ ]);
94582
+ function isTestyCommunity(name2) {
94583
+ return name2.toLowerCase().split(/[+\s/_.-]+/).some((t2) => TESTY_TOKENS.has(t2));
94584
+ }
94585
+ function cleanSubsystemName(name2) {
94586
+ let n4 = name2.replace(/^[_.]+/, "").trim();
94587
+ const parts2 = n4.split("+");
94588
+ if (parts2.length === 2) {
94589
+ const [a2, b5] = parts2;
94590
+ if (a2 && b5 && a2.toLowerCase() === b5.toLowerCase()) n4 = a2;
94591
+ }
94592
+ return n4 || name2;
94593
+ }
94594
+ var TEST_EXAMPLE_PATH_RE = /(^|\/)(tests?|__tests__|examples?|samples?|demos?|docs|docs_src|tutorials?|fixtures?|spec|specs)(\/|$)/i;
94595
+ function isTestOrExamplePath(p5) {
94596
+ return TEST_EXAMPLE_PATH_RE.test(p5);
94597
+ }
94447
94598
  async function discoverArchitecture(deps) {
94448
94599
  const nodeStats = await (async () => {
94449
94600
  try {
@@ -94463,10 +94614,17 @@ async function discoverArchitecture(deps) {
94463
94614
  const result = await deps.code.cypher(
94464
94615
  'MATCH (m)-[r:CodeRelation]->(c:Community) WHERE r.rel_type = "member_of" RETURN c.name, count(m) ORDER BY count(m) DESC'
94465
94616
  );
94466
- return result.rows.slice(0, 12).map((row) => ({
94467
- name: String(row[0] ?? ""),
94617
+ const rows = result.rows.map((row) => ({
94618
+ name: cleanSubsystemName(String(row[0] ?? "")),
94468
94619
  members: Number(row[1] ?? 0)
94469
94620
  }));
94621
+ rows.sort((a2, b5) => {
94622
+ const at4 = isTestyCommunity(a2.name) ? 1 : 0;
94623
+ const bt2 = isTestyCommunity(b5.name) ? 1 : 0;
94624
+ if (at4 !== bt2) return at4 - bt2;
94625
+ return b5.members - a2.members;
94626
+ });
94627
+ return rows.slice(0, 12);
94470
94628
  } catch {
94471
94629
  return [];
94472
94630
  }
@@ -94478,20 +94636,22 @@ async function discoverArchitecture(deps) {
94478
94636
  for (const edge of edges) {
94479
94637
  const key = edge.queueName;
94480
94638
  if (!byQueue.has(key)) {
94481
- byQueue.set(key, { producers: /* @__PURE__ */ new Set(), workers: /* @__PURE__ */ new Set() });
94639
+ byQueue.set(key, { producers: /* @__PURE__ */ new Map(), workers: /* @__PURE__ */ new Map() });
94482
94640
  }
94483
94641
  const entry2 = byQueue.get(key);
94484
94642
  if (edge.producerSymbol != null && edge.producerSymbol !== "") {
94485
- entry2.producers.add(edge.producerSymbol);
94643
+ const file = edge.producerFile ?? null;
94644
+ entry2.producers.set(`${edge.producerSymbol}\0${file ?? ""}`, { symbol: edge.producerSymbol, file });
94486
94645
  }
94487
94646
  if (edge.workerSymbol != null && edge.workerSymbol !== "") {
94488
- entry2.workers.add(edge.workerSymbol);
94647
+ const file = edge.workerFile ?? null;
94648
+ entry2.workers.set(`${edge.workerSymbol}\0${file ?? ""}`, { symbol: edge.workerSymbol, file });
94489
94649
  }
94490
94650
  }
94491
94651
  return Array.from(byQueue.entries()).map(([queueName, { producers, workers }]) => ({
94492
94652
  queueName,
94493
- producers: Array.from(producers),
94494
- workers: Array.from(workers)
94653
+ producers: Array.from(producers.values()),
94654
+ workers: Array.from(workers.values())
94495
94655
  }));
94496
94656
  } catch {
94497
94657
  return [];
@@ -94527,16 +94687,20 @@ async function discoverArchitecture(deps) {
94527
94687
  return 0;
94528
94688
  }
94529
94689
  })();
94690
+ const ownPackage = deps.project?.toLowerCase();
94530
94691
  const externalSystems = await (async () => {
94531
94692
  try {
94532
94693
  const results = await Promise.all(
94533
94694
  EXTERNAL_MARKERS.map(async (marker) => {
94695
+ if (ownPackage && marker.toLowerCase() === ownPackage) {
94696
+ return { name: marker, files: 0 };
94697
+ }
94534
94698
  try {
94535
94699
  const result = await deps.code.cypher(
94536
- `MATCH (n:File) WHERE n.content CONTAINS "${marker}" RETURN count(n)`
94700
+ `MATCH (n:File) WHERE n.content CONTAINS "${marker}" RETURN n.file_path LIMIT 500`
94537
94701
  );
94538
- const count = Number(result.rows[0]?.[0] ?? 0);
94539
- return { name: marker, files: count };
94702
+ const files = result.rows.map((r) => String(r[0] ?? "")).filter((p5) => p5 !== "" && !isTestOrExamplePath(p5)).length;
94703
+ return { name: marker, files };
94540
94704
  } catch {
94541
94705
  return { name: marker, files: 0 };
94542
94706
  }
@@ -94563,6 +94727,10 @@ async function discoverArchitecture(deps) {
94563
94727
 
94564
94728
  // ../../packages/engine/src/render-architecture.ts
94565
94729
  init_cjs_shims();
94730
+ function fmtEndpoints(endpoints2) {
94731
+ if (endpoints2.length === 0) return "(unknown)";
94732
+ return endpoints2.map((e) => e.file ? `${e.symbol} (${e.file.split("/").pop()})` : e.symbol).join(", ");
94733
+ }
94566
94734
  function renderArchitecture(m5) {
94567
94735
  const lines = [];
94568
94736
  lines.push("# Architecture (discovered)");
@@ -94574,7 +94742,8 @@ function renderArchitecture(m5) {
94574
94742
  lines.push("(none)");
94575
94743
  } else {
94576
94744
  for (const s5 of m5.subsystems) {
94577
- lines.push(`- ${s5.name} \u2014 ${s5.members} members`);
94745
+ const tag = isTestyCommunity(s5.name) ? " (tests)" : "";
94746
+ lines.push(`- ${s5.name} \u2014 ${s5.members} members${tag}`);
94578
94747
  }
94579
94748
  }
94580
94749
  lines.push("");
@@ -94583,9 +94752,7 @@ function renderArchitecture(m5) {
94583
94752
  lines.push("(none)");
94584
94753
  } else {
94585
94754
  for (const b5 of m5.asyncBoundaries) {
94586
- const producers = b5.producers.length > 0 ? b5.producers.join(", ") : "(unknown)";
94587
- const workers = b5.workers.length > 0 ? b5.workers.join(", ") : "(unknown)";
94588
- lines.push(`- ${b5.queueName}: ${producers} -> ${workers}`);
94755
+ lines.push(`- ${b5.queueName}: ${fmtEndpoints(b5.producers)} -> ${fmtEndpoints(b5.workers)}`);
94589
94756
  }
94590
94757
  }
94591
94758
  lines.push("");
@@ -95750,7 +95917,7 @@ function filterArchitecture(architecture, tokens) {
95750
95917
  ...architecture,
95751
95918
  subsystems: architecture.subsystems.filter((s5) => matchesArea(s5.name, tokens)),
95752
95919
  asyncBoundaries: architecture.asyncBoundaries.filter(
95753
- (b5) => matchesArea(b5.queueName, tokens) || b5.producers.some((p5) => matchesArea(p5, tokens)) || b5.workers.some((w4) => matchesArea(w4, tokens))
95920
+ (b5) => matchesArea(b5.queueName, tokens) || b5.producers.some((p5) => matchesArea(p5.symbol, tokens)) || b5.workers.some((w4) => matchesArea(w4.symbol, tokens))
95754
95921
  ),
95755
95922
  keyFlows: architecture.keyFlows.filter((f5) => matchesArea(f5, tokens)),
95756
95923
  externalSystems: architecture.externalSystems.filter((e) => matchesArea(e.name, tokens))
@@ -95864,9 +96031,8 @@ function renderOnboarding(g4) {
95864
96031
  if (g4.architecture.asyncBoundaries.length > 0) {
95865
96032
  lines.push("Async boundaries:");
95866
96033
  for (const b5 of g4.architecture.asyncBoundaries) {
95867
- const producers = b5.producers.length > 0 ? b5.producers.join(", ") : "(unknown)";
95868
- const workers = b5.workers.length > 0 ? b5.workers.join(", ") : "(unknown)";
95869
- lines.push(`- ${b5.queueName}: ${producers} -> ${workers}`);
96034
+ const fmt = (xs) => xs.length > 0 ? xs.map((x4) => x4.file ? `${x4.symbol} (${x4.file.split("/").pop()})` : x4.symbol).join(", ") : "(unknown)";
96035
+ lines.push(`- ${b5.queueName}: ${fmt(b5.producers)} -> ${fmt(b5.workers)}`);
95870
96036
  }
95871
96037
  } else {
95872
96038
  lines.push("No async boundaries detected.");
@@ -97212,27 +97378,27 @@ function extractQueueGraph(input) {
97212
97378
  }
97213
97379
  }
97214
97380
  const producers = [];
97215
- for (const pc49 of input.producerClasses) {
97216
- const loopVarEnums = loopVarEnumsFor(pc49.content);
97217
- for (const m5 of pc49.content.matchAll(INJECT_QUEUE_RE)) {
97381
+ for (const pc50 of input.producerClasses) {
97382
+ const loopVarEnums = loopVarEnumsFor(pc50.content);
97383
+ for (const m5 of pc50.content.matchAll(INJECT_QUEUE_RE)) {
97218
97384
  const queue = m5[1] ?? "";
97219
- if (queue) producers.push({ queue, symbol: pc49.name, file: pc49.filePath });
97385
+ if (queue) producers.push({ queue, symbol: pc50.name, file: pc50.filePath });
97220
97386
  }
97221
- for (const m5 of pc49.content.matchAll(NEW_BULL_RE)) {
97387
+ for (const m5 of pc50.content.matchAll(NEW_BULL_RE)) {
97222
97388
  if (m5[2] !== "Queue") continue;
97223
97389
  const queues2 = resolveArg(m5[3] ?? "", constMap, enums, loopVarEnums);
97224
97390
  for (const queue of queues2) {
97225
97391
  producers.push({
97226
97392
  queue,
97227
- symbol: (m5[1] ?? pc49.name) || baseName(pc49.filePath),
97228
- file: pc49.filePath
97393
+ symbol: (m5[1] ?? pc50.name) || baseName(pc50.filePath),
97394
+ file: pc50.filePath
97229
97395
  });
97230
97396
  }
97231
97397
  }
97232
- for (const m5 of pc49.content.matchAll(QUEUE_NAME_CONST_RE)) {
97398
+ for (const m5 of pc50.content.matchAll(QUEUE_NAME_CONST_RE)) {
97233
97399
  const ident = m5[1] ?? "";
97234
97400
  const queue = m5[2] ?? "";
97235
- if (queue) producers.push({ queue, symbol: ident || baseName(pc49.filePath), file: pc49.filePath });
97401
+ if (queue) producers.push({ queue, symbol: ident || baseName(pc50.filePath), file: pc50.filePath });
97236
97402
  }
97237
97403
  }
97238
97404
  const workers = [];
@@ -97299,6 +97465,60 @@ function extractQueueGraph(input) {
97299
97465
  }
97300
97466
  return { queues, producers, workers, edges };
97301
97467
  }
97468
+ var CELERY_TASK_DEF_RE = /@(?:[\w]+\.)*(?:shared_task|db_periodic_task|periodic_task|db_task|task)\b[^\n]*(?:\n[ \t]*@[^\n]*)*\n[ \t]*(?:async[ \t]+)?def[ \t]+(\w+)/g;
97469
+ var CELERY_ENQUEUE_RE = /([A-Za-z_]\w*)\s*\.\s*(?:delay|apply_async|schedule)\s*\(/g;
97470
+ function extractCeleryQueueGraph(nodes) {
97471
+ const producers = [];
97472
+ const workers = [];
97473
+ const FILE_NODE_RE = /\.(py|pyi|js|jsx|ts|tsx|mjs|cjs)$/i;
97474
+ for (const n4 of nodes) {
97475
+ for (const m5 of n4.content.matchAll(CELERY_TASK_DEF_RE)) {
97476
+ const task = m5[1];
97477
+ if (task) workers.push({ queue: task, symbol: task, file: n4.filePath });
97478
+ }
97479
+ if (FILE_NODE_RE.test(n4.name)) continue;
97480
+ for (const m5 of n4.content.matchAll(CELERY_ENQUEUE_RE)) {
97481
+ const task = m5[1];
97482
+ if (task) producers.push({ queue: task, symbol: n4.name || baseName(n4.filePath), file: n4.filePath });
97483
+ }
97484
+ }
97485
+ const taskQueues = new Set(workers.map((w4) => w4.queue));
97486
+ const queues = [...taskQueues].sort();
97487
+ const edges = [];
97488
+ for (const q2 of queues) {
97489
+ const P5 = dedupeBySymbolFile(producers.filter((p5) => p5.queue === q2));
97490
+ const W5 = dedupeBySymbolFile(workers.filter((w4) => w4.queue === q2));
97491
+ if (P5.length) {
97492
+ for (const p5 of P5) {
97493
+ for (const w4 of W5) {
97494
+ edges.push({
97495
+ queueName: q2,
97496
+ producerSymbol: p5.symbol,
97497
+ producerFile: p5.file,
97498
+ workerSymbol: w4.symbol,
97499
+ workerFile: w4.file
97500
+ });
97501
+ }
97502
+ }
97503
+ } else {
97504
+ for (const w4 of W5) {
97505
+ edges.push({
97506
+ queueName: q2,
97507
+ producerSymbol: null,
97508
+ producerFile: null,
97509
+ workerSymbol: w4.symbol,
97510
+ workerFile: w4.file
97511
+ });
97512
+ }
97513
+ }
97514
+ }
97515
+ return {
97516
+ queues,
97517
+ producers: producers.filter((p5) => taskQueues.has(p5.queue)),
97518
+ workers,
97519
+ edges
97520
+ };
97521
+ }
97302
97522
  function dedupeBySymbolFile(rows) {
97303
97523
  const seen = /* @__PURE__ */ new Set();
97304
97524
  const out2 = [];
@@ -97332,7 +97552,16 @@ async function stitch(client, db, opts = {}) {
97332
97552
  content: String(r[2] ?? "")
97333
97553
  }));
97334
97554
  const graph = extractQueueGraph({ producerClasses, workerFiles });
97335
- const edges = graph.edges.map((e) => ({
97555
+ const celeryRows = (await client.cypher(
97556
+ 'MATCH (n) WHERE n.content CONTAINS ".delay(" OR n.content CONTAINS ".apply_async(" OR n.content CONTAINS ".schedule(" OR n.content CONTAINS "@shared_task" OR n.content CONTAINS "@task" OR n.content CONTAINS ".task" OR n.content CONTAINS "periodic_task" OR n.content CONTAINS "db_task" RETURN n.name, n.file_path, n.content'
97557
+ )).rows;
97558
+ const celeryNodes = celeryRows.map((r) => ({
97559
+ name: String(r[0] ?? ""),
97560
+ filePath: String(r[1] ?? ""),
97561
+ content: String(r[2] ?? "")
97562
+ }));
97563
+ const celery = extractCeleryQueueGraph(celeryNodes);
97564
+ const edges = [...graph.edges, ...celery.edges].map((e) => ({
97336
97565
  queueName: e.queueName,
97337
97566
  producerSymbol: e.producerSymbol,
97338
97567
  producerFile: e.producerFile,
@@ -97343,9 +97572,9 @@ async function stitch(client, db, opts = {}) {
97343
97572
  }));
97344
97573
  await replaceQueueEdges(db, edges, { project: opts.project });
97345
97574
  return {
97346
- queues: graph.queues.length,
97347
- producers: graph.producers.length,
97348
- workers: graph.workers.length,
97575
+ queues: graph.queues.length + celery.queues.length,
97576
+ producers: graph.producers.length + celery.producers.length,
97577
+ workers: graph.workers.length + celery.workers.length,
97349
97578
  edges: edges.length
97350
97579
  };
97351
97580
  }
@@ -97533,6 +97762,7 @@ async function runIndex(opts) {
97533
97762
  console.log(import_picocolors3.default.dim(" already analyzed"));
97534
97763
  }
97535
97764
  const priorPort = parseHostPort(configuredHost ?? "") ?? parseHostPort(readSourceHostUrl(root) ?? "");
97765
+ await killSpawnedHost(root);
97536
97766
  const MAX_PORT_ATTEMPTS = 4;
97537
97767
  let started = false;
97538
97768
  for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS && !started; attempt += 1) {
@@ -97557,7 +97787,7 @@ async function runIndex(opts) {
97557
97787
  reconcileSpawnedHostPid(root, port);
97558
97788
  started = true;
97559
97789
  } else {
97560
- removeSpawnedHostRecord(root);
97790
+ await killSpawnedHost(root);
97561
97791
  }
97562
97792
  }
97563
97793
  if (!started) {
@@ -110080,7 +110310,7 @@ function formatAge(ms) {
110080
110310
 
110081
110311
  // ../../packages/cli/src/commands/investigate.ts
110082
110312
  init_cjs_shims();
110083
- var import_picocolors10 = __toESM(require_picocolors(), 1);
110313
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
110084
110314
 
110085
110315
  // ../../packages/cli/src/lib/cloud/investigation-sync.ts
110086
110316
  init_cjs_shims();
@@ -110498,9 +110728,110 @@ async function maybePromptFeedback(opts) {
110498
110728
  }
110499
110729
  }
110500
110730
 
110501
- // ../../packages/cli/src/lib/investigation-runner.ts
110731
+ // ../../packages/cli/src/lib/freshness.ts
110502
110732
  init_cjs_shims();
110733
+ var import_node_child_process5 = require("child_process");
110734
+ var import_node_fs15 = require("fs");
110735
+ var import_node_path16 = require("path");
110736
+ var import_node_util4 = require("util");
110503
110737
  var import_picocolors9 = __toESM(require_picocolors(), 1);
110738
+ var execFileAsync = (0, import_node_util4.promisify)(import_node_child_process5.execFile);
110739
+ async function commitsSince(repoRoot, sinceIso) {
110740
+ try {
110741
+ const { stdout } = await execFileAsync(
110742
+ "git",
110743
+ ["-C", repoRoot, "rev-list", "--count", `--since=${sinceIso}`, "HEAD"],
110744
+ { timeout: 5e3 }
110745
+ );
110746
+ const n4 = parseInt(stdout.trim(), 10);
110747
+ return Number.isFinite(n4) ? n4 : null;
110748
+ } catch {
110749
+ return null;
110750
+ }
110751
+ }
110752
+ var RUNTIME_SOURCES = /* @__PURE__ */ new Set(["logs", "metrics", "state", "queue"]);
110753
+ var STALE_INDEX_MS = 7 * 24 * 60 * 60 * 1e3;
110754
+ function readIndexMeta(repoRoot) {
110755
+ try {
110756
+ const raw = (0, import_node_fs15.readFileSync)((0, import_node_path16.join)(repoRoot, ".horus", "source", "meta.json"), "utf8");
110757
+ const j3 = JSON.parse(raw);
110758
+ return {
110759
+ lastIndexedAt: typeof j3.last_indexed_at === "string" ? j3.last_indexed_at : void 0,
110760
+ version: typeof j3.version === "string" ? j3.version : void 0,
110761
+ stats: j3.stats ?? void 0
110762
+ };
110763
+ } catch {
110764
+ return null;
110765
+ }
110766
+ }
110767
+ function humanAge(ms) {
110768
+ const s5 = Math.max(0, Math.floor(ms / 1e3));
110769
+ if (s5 < 60) return `${s5}s`;
110770
+ const m5 = Math.floor(s5 / 60);
110771
+ if (m5 < 60) return `${m5}m`;
110772
+ const h3 = Math.floor(m5 / 60);
110773
+ if (h3 < 24) return `${h3}h`;
110774
+ return `${Math.floor(h3 / 24)}d`;
110775
+ }
110776
+ function computeFreshness(opts) {
110777
+ const now = Date.parse(opts.nowIso);
110778
+ const meta = opts.meta !== void 0 ? opts.meta : readIndexMeta(opts.repoRoot);
110779
+ const commitsSinceIndex = opts.commitsSinceIndex ?? null;
110780
+ const caveats = [];
110781
+ let indexAgeMs = null;
110782
+ let indexAgeLabel = "index age unknown";
110783
+ let indexStale = false;
110784
+ const indexedAt = meta?.lastIndexedAt ? Date.parse(meta.lastIndexedAt) : NaN;
110785
+ if (!Number.isNaN(indexedAt)) {
110786
+ indexAgeMs = Math.max(0, now - indexedAt);
110787
+ indexAgeLabel = `indexed ${humanAge(indexAgeMs)} ago`;
110788
+ indexStale = indexAgeMs > STALE_INDEX_MS;
110789
+ if (indexStale) {
110790
+ caveats.push(
110791
+ `code index is ${humanAge(indexAgeMs)} old \u2014 re-run \`horus index\` so analysis reflects current code`
110792
+ );
110793
+ }
110794
+ } else {
110795
+ caveats.push("code index age unknown (no .horus/source/meta.json) \u2014 freshness unverified");
110796
+ }
110797
+ if (typeof commitsSinceIndex === "number" && commitsSinceIndex > 0) {
110798
+ caveats.push(
110799
+ `${commitsSinceIndex} commit(s) since the last index \u2014 re-run \`horus index\` so analysis reflects current code`
110800
+ );
110801
+ }
110802
+ const runtime = opts.evidence.filter((e) => e.source && RUNTIME_SOURCES.has(e.source));
110803
+ const runtimeSources = [...new Set(runtime.map((e) => e.source))].sort();
110804
+ const stamps = runtime.map((e) => e.timestamp ? Date.parse(e.timestamp) : NaN).filter((n4) => !Number.isNaN(n4)).sort((a2, b5) => a2 - b5);
110805
+ const runtimeWindow = stamps.length > 0 ? { fromIso: new Date(stamps[0]).toISOString(), toIso: new Date(stamps[stamps.length - 1]).toISOString() } : null;
110806
+ if (runtime.length === 0) {
110807
+ caveats.push(
110808
+ "no runtime evidence \u2014 source-only investigation; connect logs/metrics/queues for deeper grounding"
110809
+ );
110810
+ }
110811
+ return {
110812
+ indexAgeMs,
110813
+ indexAgeLabel,
110814
+ indexStale,
110815
+ commitsSinceIndex,
110816
+ runtimeWindow,
110817
+ runtimeSources,
110818
+ caveats
110819
+ };
110820
+ }
110821
+ function renderFreshness(f5) {
110822
+ const lines = [];
110823
+ const behind = f5.commitsSinceIndex && f5.commitsSinceIndex > 0 ? ` (${f5.commitsSinceIndex} behind)` : "";
110824
+ const label = f5.indexAgeLabel + behind;
110825
+ const idx = f5.indexStale || behind ? import_picocolors9.default.yellow(label) : label;
110826
+ const runtime = f5.runtimeWindow !== null ? `runtime ${f5.runtimeWindow.fromIso.slice(0, 10)}\u2192${f5.runtimeWindow.toIso.slice(0, 10)}` + (f5.runtimeSources.length ? ` (${f5.runtimeSources.join(", ")})` : "") : "no runtime window";
110827
+ lines.push(import_picocolors9.default.dim(`Freshness: code ${idx} \xB7 ${runtime}`));
110828
+ for (const c4 of f5.caveats) lines.push(import_picocolors9.default.yellow(` \u26A0 ${c4}`));
110829
+ return lines.join("\n");
110830
+ }
110831
+
110832
+ // ../../packages/cli/src/lib/investigation-runner.ts
110833
+ init_cjs_shims();
110834
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
110504
110835
  async function buildInvestigationContext(renv, opts) {
110505
110836
  const log = opts.log ?? ((l2) => console.error(l2));
110506
110837
  const code = codeForEnv(renv);
@@ -110512,20 +110843,20 @@ async function buildInvestigationContext(renv, opts) {
110512
110843
  const sourceUrl = renv.repositories[0]?.sourceHostUrl;
110513
110844
  let health = await code.health();
110514
110845
  if (!health.ok && sourceUrl) {
110515
- log(import_picocolors9.default.yellow(`Source-intelligence host unreachable (${sourceUrl}) \u2014 attempting to start it\u2026`));
110846
+ log(import_picocolors10.default.yellow(`Source-intelligence host unreachable (${sourceUrl}) \u2014 attempting to start it\u2026`));
110516
110847
  const healed = await ensureSourceHost(renv.path, sourceUrl);
110517
110848
  if (healed.ok) {
110518
- log(import_picocolors9.default.green(`Source-intelligence host is up at ${healed.hostUrl}.`));
110849
+ log(import_picocolors10.default.green(`Source-intelligence host is up at ${healed.hostUrl}.`));
110519
110850
  health = await code.health();
110520
110851
  } else {
110521
- log(import_picocolors9.default.dim(` ${ensureHostReasonHint(healed.reason)}`));
110852
+ log(import_picocolors10.default.dim(` ${ensureHostReasonHint(healed.reason)}`));
110522
110853
  }
110523
110854
  }
110524
110855
  const runtimeOnly = !health.ok;
110525
110856
  if (runtimeOnly) {
110526
110857
  log(
110527
- import_picocolors9.default.yellow(
110528
- `Proceeding in runtime-only mode \u2014 no source intelligence. Run ${import_picocolors9.default.bold("horus index")} for a full (code-aware) investigation.`
110858
+ import_picocolors10.default.yellow(
110859
+ `Proceeding in runtime-only mode \u2014 no source intelligence. Run ${import_picocolors10.default.bold("horus index")} for a full (code-aware) investigation.`
110529
110860
  )
110530
110861
  );
110531
110862
  }
@@ -110680,37 +111011,37 @@ function renderStoredAIJudgment(judgment, write = (l2) => console.log(l2)) {
110680
111011
  const sep = "\u2500".repeat(60);
110681
111012
  write(`
110682
111013
  ${sep}`);
110683
- write(import_picocolors10.default.bold("AI Judgment") + import_picocolors10.default.dim(` (confidence: ${(judgment.confidence * 100).toFixed(0)}%, provider: ${judgment.provider})`));
111014
+ write(import_picocolors11.default.bold("AI Judgment") + import_picocolors11.default.dim(` (confidence: ${(judgment.confidence * 100).toFixed(0)}%, provider: ${judgment.provider})`));
110684
111015
  write(sep);
110685
111016
  if (judgment.hypothesisJudgments && judgment.hypothesisJudgments.length > 0) {
110686
- write(import_picocolors10.default.bold("Hypothesis verdicts:"));
111017
+ write(import_picocolors11.default.bold("Hypothesis verdicts:"));
110687
111018
  for (const j3 of judgment.hypothesisJudgments) {
110688
- const verdictColor = j3.verdict === "supported" ? import_picocolors10.default.green : j3.verdict === "weakened" ? import_picocolors10.default.yellow : j3.verdict === "eliminated" ? import_picocolors10.default.red : import_picocolors10.default.dim;
110689
- write(` ${verdictColor(`[${j3.verdict}]`)} ${j3.category}` + import_picocolors10.default.dim(` (${(j3.confidence * 100).toFixed(0)}%)`));
110690
- write(import_picocolors10.default.dim(` ${j3.rationale}`));
111019
+ const verdictColor = j3.verdict === "supported" ? import_picocolors11.default.green : j3.verdict === "weakened" ? import_picocolors11.default.yellow : j3.verdict === "eliminated" ? import_picocolors11.default.red : import_picocolors11.default.dim;
111020
+ write(` ${verdictColor(`[${j3.verdict}]`)} ${j3.category}` + import_picocolors11.default.dim(` (${(j3.confidence * 100).toFixed(0)}%)`));
111021
+ write(import_picocolors11.default.dim(` ${j3.rationale}`));
110691
111022
  }
110692
111023
  write("");
110693
111024
  }
110694
111025
  if (judgment.rootCauseAssessment) {
110695
111026
  const rca = judgment.rootCauseAssessment;
110696
- const uncertaintyColor = rca.uncertainty === "low" ? import_picocolors10.default.green : rca.uncertainty === "medium" ? import_picocolors10.default.yellow : import_picocolors10.default.red;
110697
- write(import_picocolors10.default.bold("Root cause assessment:") + import_picocolors10.default.dim(` uncertainty: ${uncertaintyColor(rca.uncertainty)}`));
111027
+ const uncertaintyColor = rca.uncertainty === "low" ? import_picocolors11.default.green : rca.uncertainty === "medium" ? import_picocolors11.default.yellow : import_picocolors11.default.red;
111028
+ write(import_picocolors11.default.bold("Root cause assessment:") + import_picocolors11.default.dim(` uncertainty: ${uncertaintyColor(rca.uncertainty)}`));
110698
111029
  write(rca.summary);
110699
111030
  if (rca.citedEvidenceIds.length > 0) {
110700
- write(import_picocolors10.default.dim(` Cited: ${rca.citedEvidenceIds.join(", ")}`));
111031
+ write(import_picocolors11.default.dim(` Cited: ${rca.citedEvidenceIds.join(", ")}`));
110701
111032
  }
110702
111033
  write("");
110703
111034
  }
110704
- write(import_picocolors10.default.bold("What:") + " " + judgment.what);
110705
- write(import_picocolors10.default.bold("Why:") + " " + judgment.why);
111035
+ write(import_picocolors11.default.bold("What:") + " " + judgment.what);
111036
+ write(import_picocolors11.default.bold("Why:") + " " + judgment.why);
110706
111037
  if (judgment.whereNext.length > 0) {
110707
- write(import_picocolors10.default.bold("Next steps:"));
111038
+ write(import_picocolors11.default.bold("Next steps:"));
110708
111039
  for (const step of judgment.whereNext) {
110709
111040
  write(` \u2022 ${step}`);
110710
111041
  }
110711
111042
  }
110712
111043
  if (judgment.citations.length > 0) {
110713
- write(import_picocolors10.default.dim(`
111044
+ write(import_picocolors11.default.dim(`
110714
111045
  Cited evidence: ${judgment.citations.map((c4) => c4.evidenceId).join(", ")}`));
110715
111046
  }
110716
111047
  }
@@ -110736,7 +111067,7 @@ async function runInvestigate(hint, opts) {
110736
111067
  try {
110737
111068
  renv = resolveEnvironment(config2, { project: projectName, env: opts.env });
110738
111069
  } catch (err2) {
110739
- console.error(import_picocolors10.default.red(err2.message));
111070
+ console.error(import_picocolors11.default.red(err2.message));
110740
111071
  return 1;
110741
111072
  }
110742
111073
  const repoRoot = repoRootOrCwd(renv.path);
@@ -110745,8 +111076,8 @@ async function runInvestigate(hint, opts) {
110745
111076
  const cloudSession = cloudActive ? authedClient() : null;
110746
111077
  if (cloudActive && !cloudSession) {
110747
111078
  console.error(
110748
- import_picocolors10.default.yellow(
110749
- `This repo is linked to Horus Cloud but you are not logged in \u2014 running locally only. Run ${import_picocolors10.default.bold("horus login")} to also sync results to the cloud.`
111079
+ import_picocolors11.default.yellow(
111080
+ `This repo is linked to Horus Cloud but you are not logged in \u2014 running locally only. Run ${import_picocolors11.default.bold("horus login")} to also sync results to the cloud.`
110750
111081
  )
110751
111082
  );
110752
111083
  }
@@ -110757,7 +111088,7 @@ async function runInvestigate(hint, opts) {
110757
111088
  ...opts.service !== void 0 ? { service: opts.service } : {}
110758
111089
  });
110759
111090
  } catch (err2) {
110760
- console.error(import_picocolors10.default.red(err2.message));
111091
+ console.error(import_picocolors11.default.red(err2.message));
110761
111092
  return 1;
110762
111093
  }
110763
111094
  try {
@@ -110774,8 +111105,24 @@ async function runInvestigate(hint, opts) {
110774
111105
  );
110775
111106
  const db = ctx.dbHandle.db;
110776
111107
  const format = opts.json ? "json" : opts.format ?? "text";
110777
- const rendered = format === "json" ? reportToJSON(report) : format === "markdown" || format === "md" ? reportToMarkdown(report) : renderReport(report);
110778
- console.log(rendered);
111108
+ const fmeta = readIndexMeta(repoRoot);
111109
+ const commitsSinceIndex = fmeta?.lastIndexedAt ? await commitsSince(repoRoot, fmeta.lastIndexedAt) : null;
111110
+ const freshness = computeFreshness({
111111
+ repoRoot,
111112
+ evidence: report.evidence,
111113
+ nowIso: (/* @__PURE__ */ new Date()).toISOString(),
111114
+ meta: fmeta,
111115
+ commitsSinceIndex
111116
+ });
111117
+ if (format === "json") {
111118
+ const obj = JSON.parse(reportToJSON(report));
111119
+ obj.freshness = freshness;
111120
+ console.log(JSON.stringify(obj, null, 2));
111121
+ } else {
111122
+ console.log(format === "markdown" || format === "md" ? reportToMarkdown(report) : renderReport(report));
111123
+ console.log("");
111124
+ console.log(renderFreshness(freshness));
111125
+ }
110779
111126
  if (opts.ai && format !== "json") {
110780
111127
  const ai = resolveAiSettings(config2);
110781
111128
  const model = opts.aiModel ?? ai.model ?? "claude-opus-4-8";
@@ -110783,7 +111130,7 @@ async function runInvestigate(hint, opts) {
110783
111130
  model,
110784
111131
  ...ai.anthropicApiKey !== void 0 ? { apiKey: ai.anthropicApiKey } : {}
110785
111132
  });
110786
- console.log(import_picocolors10.default.dim(`[ai] model: ${model}`));
111133
+ console.log(import_picocolors11.default.dim(`[ai] model: ${model}`));
110787
111134
  const narrativeInput = buildNarrativeInput(report);
110788
111135
  const { output, fromProvider, degraded, validationErrors } = await renderNarrative(
110789
111136
  narrativeInput,
@@ -110799,24 +111146,24 @@ async function runInvestigate(hint, opts) {
110799
111146
  renderStoredAIJudgment(stored);
110800
111147
  } else if (degraded) {
110801
111148
  if (validationErrors && validationErrors.length > 0) {
110802
- console.error(import_picocolors10.default.yellow(`[ai] structured validation incomplete \u2014 showing raw AI narrative`));
111149
+ console.error(import_picocolors11.default.yellow(`[ai] structured validation incomplete \u2014 showing raw AI narrative`));
110803
111150
  }
110804
111151
  console.log("");
110805
- console.log(import_picocolors10.default.dim("\u2500".repeat(60)));
110806
- console.log(import_picocolors10.default.bold("AI narrative ") + import_picocolors10.default.yellow("(unstructured \u2014 not validated)"));
111152
+ console.log(import_picocolors11.default.dim("\u2500".repeat(60)));
111153
+ console.log(import_picocolors11.default.bold("AI narrative ") + import_picocolors11.default.yellow("(unstructured \u2014 not validated)"));
110807
111154
  if (output.what?.trim()) {
110808
- console.log(import_picocolors10.default.bold("\nWhat:"), output.what.trim());
111155
+ console.log(import_picocolors11.default.bold("\nWhat:"), output.what.trim());
110809
111156
  }
110810
111157
  if (output.why?.trim()) {
110811
- console.log(import_picocolors10.default.bold("\nWhy:"), output.why.trim());
111158
+ console.log(import_picocolors11.default.bold("\nWhy:"), output.why.trim());
110812
111159
  }
110813
111160
  if (output.whereNext.length > 0) {
110814
- console.log(import_picocolors10.default.bold("\nNext:"));
111161
+ console.log(import_picocolors11.default.bold("\nNext:"));
110815
111162
  for (const a2 of output.whereNext) console.log(` - ${a2}`);
110816
111163
  }
110817
111164
  } else {
110818
111165
  const reason = classifyAIFailure(validationErrors?.[0]);
110819
- console.error(import_picocolors10.default.yellow(`[ai] fallback to deterministic \u2014 ${reason}`));
111166
+ console.error(import_picocolors11.default.yellow(`[ai] fallback to deterministic \u2014 ${reason}`));
110820
111167
  }
110821
111168
  }
110822
111169
  track({
@@ -110847,7 +111194,7 @@ async function runInvestigate(hint, opts) {
110847
111194
  if (cloudActive && cloudSession && cloudCfg) {
110848
111195
  try {
110849
111196
  const refs = await uploadInvestigationToCloud(cloudSession.client, cloudCfg, report);
110850
- const cloudNote = import_picocolors10.default.dim(`[cloud] investigation saved: ${refs.investigationId}`);
111197
+ const cloudNote = import_picocolors11.default.dim(`[cloud] investigation saved: ${refs.investigationId}`);
110851
111198
  if (format === "json") console.error(cloudNote);
110852
111199
  else console.log(cloudNote);
110853
111200
  } catch (err2) {
@@ -110857,16 +111204,16 @@ async function runInvestigate(hint, opts) {
110857
111204
  if (format !== "json") {
110858
111205
  if (report.persisted === false) {
110859
111206
  console.error(
110860
- import_picocolors10.default.yellow(`
111207
+ import_picocolors11.default.yellow(`
110861
111208
  \u26A0 Results were not saved \u2014 the investigation database was unreachable.`)
110862
111209
  );
110863
111210
  console.error(
110864
- import_picocolors10.default.dim(
111211
+ import_picocolors11.default.dim(
110865
111212
  ` This report is display-only; \`horus ask\` won't find it. Start the database and re-run to persist.`
110866
111213
  )
110867
111214
  );
110868
111215
  } else {
110869
- console.log(import_picocolors10.default.dim(`
111216
+ console.log(import_picocolors11.default.dim(`
110870
111217
  Ask a follow-up: horus ask ${report.id} "<question>"`));
110871
111218
  }
110872
111219
  await maybePromptFeedback({
@@ -110880,15 +111227,15 @@ Ask a follow-up: horus ask ${report.id} "<question>"`));
110880
111227
  return 0;
110881
111228
  } catch (err2) {
110882
111229
  const msg = err2?.message || String(err2);
110883
- console.error(import_picocolors10.default.red(msg.trim() ? msg : "Investigation failed (unknown error)."));
110884
- if (process.env.HORUS_DEBUG) console.error(import_picocolors10.default.dim(err2?.stack ?? String(err2)));
111230
+ console.error(import_picocolors11.default.red(msg.trim() ? msg : "Investigation failed (unknown error)."));
111231
+ if (process.env.HORUS_DEBUG) console.error(import_picocolors11.default.dim(err2?.stack ?? String(err2)));
110885
111232
  return 1;
110886
111233
  }
110887
111234
  }
110888
111235
 
110889
111236
  // ../../packages/cli/src/commands/watch.ts
110890
111237
  init_cjs_shims();
110891
- var import_picocolors11 = __toESM(require_picocolors(), 1);
111238
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
110892
111239
  function detectNewSentryIncidents(issues, seen) {
110893
111240
  const fresh = [];
110894
111241
  for (const issue2 of issues) {
@@ -110970,21 +111317,21 @@ async function runWatch(opts) {
110970
111317
  try {
110971
111318
  renv = resolveEnvironment(config2, { project: opts.project, env: opts.env });
110972
111319
  } catch (err2) {
110973
- console.error(import_picocolors11.default.red(err2.message));
111320
+ console.error(import_picocolors12.default.red(err2.message));
110974
111321
  return 1;
110975
111322
  }
110976
111323
  let ctx;
110977
111324
  try {
110978
111325
  ctx = await buildInvestigationContext(renv, { databaseUrl: config2.database.url });
110979
111326
  } catch (err2) {
110980
- console.error(import_picocolors11.default.red(err2.message));
111327
+ console.error(import_picocolors12.default.red(err2.message));
110981
111328
  return 1;
110982
111329
  }
110983
111330
  const requested = opts.source ?? "auto";
110984
111331
  const source = resolveSource(requested, ctx);
110985
111332
  if (source === null) {
110986
111333
  console.error(
110987
- import_picocolors11.default.red(
111334
+ import_picocolors12.default.red(
110988
111335
  requested === "auto" ? `No Sentry or Elasticsearch connector configured for "${renv.project}" / "${renv.env}".` : `No ${requested} connector configured for "${renv.project}" / "${renv.env}".`
110989
111336
  )
110990
111337
  );
@@ -110994,7 +111341,7 @@ async function runWatch(opts) {
110994
111341
  const intervalSec = Math.max(1, Number(opts.interval) || 60);
110995
111342
  const seen = /* @__PURE__ */ new Set();
110996
111343
  console.error(
110997
- import_picocolors11.default.dim(
111344
+ import_picocolors12.default.dim(
110998
111345
  `[watch] source: ${source} \xB7 project: ${renv.project} \xB7 env: ${renv.env}` + (opts.once ? " \xB7 mode: once" : ` \xB7 interval: ${intervalSec}s`)
110999
111346
  )
111000
111347
  );
@@ -111003,24 +111350,24 @@ async function runWatch(opts) {
111003
111350
  try {
111004
111351
  incidents = source === "sentry" ? await pollSentry(ctx.sentry, seen) : await pollElasticsearch(ctx.logs, seen, ctx.service);
111005
111352
  } catch (err2) {
111006
- console.error(import_picocolors11.default.yellow(`[watch] poll failed \u2014 ${err2.message}`));
111353
+ console.error(import_picocolors12.default.yellow(`[watch] poll failed \u2014 ${err2.message}`));
111007
111354
  return;
111008
111355
  }
111009
111356
  if (incidents.length === 0) {
111010
- console.error(import_picocolors11.default.dim(`[watch] no new incidents`));
111357
+ console.error(import_picocolors12.default.dim(`[watch] no new incidents`));
111011
111358
  return;
111012
111359
  }
111013
111360
  for (const incident of incidents) {
111014
111361
  try {
111015
111362
  const report = await runOneInvestigation({ hint: incident.hint }, ctx);
111016
111363
  const { cause, confidence } = headlineFor(report);
111017
- const persisted = report.persisted === false ? import_picocolors11.default.yellow(" (not persisted)") : "";
111364
+ const persisted = report.persisted === false ? import_picocolors12.default.yellow(" (not persisted)") : "";
111018
111365
  console.log(
111019
- `${import_picocolors11.default.bold("\u25CF")} ${incident.hint} ${import_picocolors11.default.dim("\u2192")} ${cause} ${import_picocolors11.default.dim(`(${(confidence * 100).toFixed(0)}%)`)} ${import_picocolors11.default.dim(`id: ${report.id}`)}${persisted}`
111366
+ `${import_picocolors12.default.bold("\u25CF")} ${incident.hint} ${import_picocolors12.default.dim("\u2192")} ${cause} ${import_picocolors12.default.dim(`(${(confidence * 100).toFixed(0)}%)`)} ${import_picocolors12.default.dim(`id: ${report.id}`)}${persisted}`
111020
111367
  );
111021
111368
  } catch (err2) {
111022
111369
  console.error(
111023
- import_picocolors11.default.yellow(`[watch] investigation failed for "${incident.ref}" \u2014 ${err2.message}`)
111370
+ import_picocolors12.default.yellow(`[watch] investigation failed for "${incident.ref}" \u2014 ${err2.message}`)
111024
111371
  );
111025
111372
  }
111026
111373
  }
@@ -111035,7 +111382,7 @@ async function runWatch(opts) {
111035
111382
  const onSignal = () => {
111036
111383
  if (stopping) return;
111037
111384
  stopping = true;
111038
- console.error(import_picocolors11.default.dim(`
111385
+ console.error(import_picocolors12.default.dim(`
111039
111386
  [watch] shutting down\u2026`));
111040
111387
  if (wake) wake();
111041
111388
  };
@@ -111062,7 +111409,7 @@ async function runWatch(opts) {
111062
111409
 
111063
111410
  // ../../packages/cli/src/commands/changes.ts
111064
111411
  init_cjs_shims();
111065
- var import_picocolors12 = __toESM(require_picocolors(), 1);
111412
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
111066
111413
  var CHANGES_AI_CONTRACT = `Provide a clearly separated AI change-impact review with:
111067
111414
 
111068
111415
  Highest-risk changes
@@ -111087,7 +111434,7 @@ async function runChanges(base2, compare, opts) {
111087
111434
  const health = await code.health();
111088
111435
  if (!health.ok) {
111089
111436
  console.error(
111090
- import_picocolors12.default.red("Source-intelligence host unreachable \u2014 run: horus index")
111437
+ import_picocolors13.default.red("Source-intelligence host unreachable \u2014 run: horus index")
111091
111438
  );
111092
111439
  return 1;
111093
111440
  }
@@ -111109,20 +111456,20 @@ async function runChanges(base2, compare, opts) {
111109
111456
  });
111110
111457
  console.log("\n" + renderInterpretation(result));
111111
111458
  if (!result.ok) {
111112
- console.error(import_picocolors12.default.yellow(`[ai] ${result.warning}`));
111459
+ console.error(import_picocolors13.default.yellow(`[ai] ${result.warning}`));
111113
111460
  }
111114
111461
  }
111115
111462
  }
111116
111463
  return 0;
111117
111464
  } catch (err2) {
111118
- console.error(import_picocolors12.default.red(err2.message));
111465
+ console.error(import_picocolors13.default.red(err2.message));
111119
111466
  return 1;
111120
111467
  }
111121
111468
  }
111122
111469
 
111123
111470
  // ../../packages/cli/src/commands/timeline.ts
111124
111471
  init_cjs_shims();
111125
- var import_picocolors13 = __toESM(require_picocolors(), 1);
111472
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
111126
111473
  var DEFAULT_SINCE = "7 days ago";
111127
111474
  function resolveTimelineWindow(opts) {
111128
111475
  const usingDefault = !opts.all && opts.since === void 0;
@@ -111152,7 +111499,7 @@ async function runTimeline(service, opts) {
111152
111499
  try {
111153
111500
  renv = resolveEnvironment(config2, { project: opts.repo });
111154
111501
  } catch (err2) {
111155
- console.error(import_picocolors13.default.red(err2.message));
111502
+ console.error(import_picocolors14.default.red(err2.message));
111156
111503
  return 1;
111157
111504
  }
111158
111505
  const { code } = createConnectors(config2);
@@ -111167,9 +111514,9 @@ async function runTimeline(service, opts) {
111167
111514
  console.log(renderChangeTimeline(t2));
111168
111515
  if (usingDefaultWindow) {
111169
111516
  console.log(
111170
- import_picocolors13.default.dim(
111517
+ import_picocolors14.default.dim(
111171
111518
  `
111172
- Showing the last 7 days (default). Widen with ${import_picocolors13.default.bold('--since "30 days ago"')}, pin a range with ${import_picocolors13.default.bold("--since <when> --until <when>")}, or see everything with ${import_picocolors13.default.bold("--all")}.`
111519
+ Showing the last 7 days (default). Widen with ${import_picocolors14.default.bold('--since "30 days ago"')}, pin a range with ${import_picocolors14.default.bold("--since <when> --until <when>")}, or see everything with ${import_picocolors14.default.bold("--all")}.`
111173
111520
  )
111174
111521
  );
111175
111522
  }
@@ -111186,21 +111533,26 @@ async function runTimeline(service, opts) {
111186
111533
  });
111187
111534
  console.log("\n" + renderInterpretation(result));
111188
111535
  if (!result.ok) {
111189
- console.error(import_picocolors13.default.yellow(`[ai] ${result.warning}`));
111536
+ console.error(import_picocolors14.default.yellow(`[ai] ${result.warning}`));
111190
111537
  }
111191
111538
  }
111192
111539
  }
111193
111540
  return 0;
111194
111541
  } catch (err2) {
111195
- console.error(import_picocolors13.default.red(err2.message));
111542
+ console.error(import_picocolors14.default.red(err2.message));
111196
111543
  return 1;
111197
111544
  }
111198
111545
  }
111199
111546
 
111200
111547
  // ../../packages/cli/src/commands/what-changed.ts
111201
111548
  init_cjs_shims();
111202
- var import_picocolors14 = __toESM(require_picocolors(), 1);
111549
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
111203
111550
  var DEFAULT_SINCE2 = "7 days ago";
111551
+ function looksLikeGitRef(s5) {
111552
+ const t2 = s5.trim();
111553
+ if (/\s/.test(t2) || /^\d{4}-\d{2}-\d{2}/.test(t2)) return false;
111554
+ return /[~^]/.test(t2) || /^HEAD\b/.test(t2) || /^[0-9a-f]{7,40}$/i.test(t2) || /^v?\d+\.\d+/.test(t2);
111555
+ }
111204
111556
  var WHAT_CHANGED_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
111205
111557
 
111206
111558
  Evidence used
@@ -111223,11 +111575,18 @@ async function runWhatChanged(service, opts) {
111223
111575
  try {
111224
111576
  renv = resolveEnvironment(config2, { project: opts.repo });
111225
111577
  } catch (err2) {
111226
- console.error(import_picocolors14.default.red(err2.message));
111578
+ console.error(import_picocolors15.default.red(err2.message));
111227
111579
  return 1;
111228
111580
  }
111229
111581
  const { code } = createConnectors(config2);
111230
111582
  const since = opts.since ?? DEFAULT_SINCE2;
111583
+ if (opts.since !== void 0 && looksLikeGitRef(opts.since) && !await resolvesToCommit(renv.path, opts.since)) {
111584
+ console.error(
111585
+ import_picocolors15.default.yellow(
111586
+ `Warning: --since "${opts.since}" does not resolve to a commit (shallow clone or unknown ref?); it will be treated as a date filter and likely return no commits.`
111587
+ )
111588
+ );
111589
+ }
111231
111590
  const r = await whatChanged(
111232
111591
  { repoPath: renv.path, since, until: opts.until, service },
111233
111592
  { code }
@@ -111246,7 +111605,7 @@ async function runWhatChanged(service, opts) {
111246
111605
  });
111247
111606
  console.log("\n" + renderInterpretation(result));
111248
111607
  if (!result.ok) {
111249
- console.error(import_picocolors14.default.yellow(`[ai] ${result.warning}`));
111608
+ console.error(import_picocolors15.default.yellow(`[ai] ${result.warning}`));
111250
111609
  }
111251
111610
  }
111252
111611
  if (opts.push) {
@@ -111254,19 +111613,19 @@ async function runWhatChanged(service, opts) {
111254
111613
  }
111255
111614
  return 0;
111256
111615
  } catch (err2) {
111257
- console.error(import_picocolors14.default.red(err2.message));
111616
+ console.error(import_picocolors15.default.red(err2.message));
111258
111617
  return 1;
111259
111618
  }
111260
111619
  }
111261
111620
  async function pushChangeReport(r, repoCwd) {
111262
111621
  const session = authedClient();
111263
111622
  if (!session) {
111264
- console.error(import_picocolors14.default.yellow("[cloud] not logged in \u2014 run `horus login` to push reports."));
111623
+ console.error(import_picocolors15.default.yellow("[cloud] not logged in \u2014 run `horus login` to push reports."));
111265
111624
  return;
111266
111625
  }
111267
111626
  const cfg = readCloudConfig(repoRootOrCwd(repoCwd));
111268
111627
  if (!isCloudActive(cfg)) {
111269
- console.error(import_picocolors14.default.yellow("[cloud] repo not linked \u2014 run `horus cloud link` to push reports."));
111628
+ console.error(import_picocolors15.default.yellow("[cloud] repo not linked \u2014 run `horus cloud link` to push reports."));
111270
111629
  return;
111271
111630
  }
111272
111631
  const projectId = cfg.project?.id;
@@ -111312,15 +111671,15 @@ async function pushChangeReport(r, repoCwd) {
111312
111671
  queueTopologyTouched: r.queueTopology.touched,
111313
111672
  payload
111314
111673
  });
111315
- console.error(import_picocolors14.default.dim("[cloud] pushed change report."));
111674
+ console.error(import_picocolors15.default.dim("[cloud] pushed change report."));
111316
111675
  } catch (err2) {
111317
- console.error(import_picocolors14.default.yellow(`[cloud] push failed: ${err2.message}`));
111676
+ console.error(import_picocolors15.default.yellow(`[cloud] push failed: ${err2.message}`));
111318
111677
  }
111319
111678
  }
111320
111679
 
111321
111680
  // ../../packages/cli/src/commands/architecture.ts
111322
111681
  init_cjs_shims();
111323
- var import_picocolors15 = __toESM(require_picocolors(), 1);
111682
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
111324
111683
  var ARCHITECTURE_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
111325
111684
 
111326
111685
  System summary
@@ -111349,7 +111708,7 @@ async function runArchitecture(opts) {
111349
111708
  const health = await code.health();
111350
111709
  if (!health.ok) {
111351
111710
  console.error(
111352
- import_picocolors15.default.red("Source-intelligence host unreachable \u2014 run: horus index")
111711
+ import_picocolors16.default.red("Source-intelligence host unreachable \u2014 run: horus index")
111353
111712
  );
111354
111713
  return 1;
111355
111714
  }
@@ -111377,7 +111736,7 @@ async function runArchitecture(opts) {
111377
111736
  });
111378
111737
  console.log("\n" + renderInterpretation(result));
111379
111738
  if (!result.ok) {
111380
- console.error(import_picocolors15.default.yellow(`[ai] ${result.warning}`));
111739
+ console.error(import_picocolors16.default.yellow(`[ai] ${result.warning}`));
111381
111740
  }
111382
111741
  }
111383
111742
  }
@@ -111386,14 +111745,14 @@ async function runArchitecture(opts) {
111386
111745
  }
111387
111746
  return 0;
111388
111747
  } catch (err2) {
111389
- console.error(import_picocolors15.default.red(err2.message));
111748
+ console.error(import_picocolors16.default.red(err2.message));
111390
111749
  return 1;
111391
111750
  }
111392
111751
  }
111393
111752
 
111394
111753
  // ../../packages/cli/src/commands/blast-radius.ts
111395
111754
  init_cjs_shims();
111396
- var import_picocolors16 = __toESM(require_picocolors(), 1);
111755
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
111397
111756
  var BLAST_RADIUS_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
111398
111757
 
111399
111758
  Evidence used
@@ -111420,7 +111779,7 @@ async function runBlastRadius(query, opts) {
111420
111779
  const { code } = createConnectors(config2);
111421
111780
  const health = await code.health();
111422
111781
  if (!health.ok) {
111423
- console.error(import_picocolors16.default.red("Source-intelligence host unreachable \u2014 run: horus index"));
111782
+ console.error(import_picocolors17.default.red("Source-intelligence host unreachable \u2014 run: horus index"));
111424
111783
  return 1;
111425
111784
  }
111426
111785
  let project;
@@ -111433,12 +111792,12 @@ async function runBlastRadius(query, opts) {
111433
111792
  const r = await analyzeBlastRadius(query, { code, db, project }, opts.depth ?? 3);
111434
111793
  if (!r) {
111435
111794
  console.log(`No symbol found for: ${query}`);
111436
- console.log(import_picocolors16.default.dim(` Tip: use an exact class or function name, e.g. "MyService"`));
111795
+ console.log(import_picocolors17.default.dim(` Tip: use an exact class or function name, e.g. "MyService"`));
111437
111796
  return 1;
111438
111797
  }
111439
111798
  if (r.seed.name.toLowerCase() !== query.toLowerCase()) {
111440
111799
  console.log(
111441
- import_picocolors16.default.yellow(` No exact match for "${query}"`) + import_picocolors16.default.dim(` \u2014 showing closest: "${r.seed.name}" (fuzzy match)`)
111800
+ import_picocolors17.default.yellow(` No exact match for "${query}"`) + import_picocolors17.default.dim(` \u2014 showing closest: "${r.seed.name}" (fuzzy match)`)
111442
111801
  );
111443
111802
  }
111444
111803
  if (opts.json) {
@@ -111458,7 +111817,7 @@ async function runBlastRadius(query, opts) {
111458
111817
  });
111459
111818
  console.log("\n" + renderInterpretation(result));
111460
111819
  if (!result.ok) {
111461
- console.error(import_picocolors16.default.yellow(`[ai] ${result.warning}`));
111820
+ console.error(import_picocolors17.default.yellow(`[ai] ${result.warning}`));
111462
111821
  }
111463
111822
  }
111464
111823
  }
@@ -111467,28 +111826,28 @@ async function runBlastRadius(query, opts) {
111467
111826
  }
111468
111827
  return 0;
111469
111828
  } catch (err2) {
111470
- console.error(import_picocolors16.default.red(err2.message));
111829
+ console.error(import_picocolors17.default.red(err2.message));
111471
111830
  return 1;
111472
111831
  }
111473
111832
  }
111474
111833
 
111475
111834
  // ../../packages/cli/src/commands/repos.ts
111476
111835
  init_cjs_shims();
111477
- var import_picocolors17 = __toESM(require_picocolors(), 1);
111836
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
111478
111837
  async function runRepos(opts) {
111479
111838
  const config2 = await loadConfig(opts.config);
111480
111839
  const providers = repoProviders(config2);
111481
111840
  if (providers.length === 0) {
111482
- console.log(import_picocolors17.default.dim("No repositories configured."));
111841
+ console.log(import_picocolors18.default.dim("No repositories configured."));
111483
111842
  return 0;
111484
111843
  }
111485
111844
  const health = await reposHealth(providers);
111486
111845
  for (const h3 of health) {
111487
- const dot = h3.reachable ? import_picocolors17.default.green("\u25CF") : import_picocolors17.default.red("\u25CF");
111488
- const name2 = import_picocolors17.default.bold(h3.repo.padEnd(20));
111489
- const hostUrl = import_picocolors17.default.cyan(h3.hostUrl.padEnd(30));
111490
- const path = import_picocolors17.default.dim(h3.path);
111491
- const detail = h3.detail ? import_picocolors17.default.dim(`(${h3.detail})`) : "";
111846
+ const dot = h3.reachable ? import_picocolors18.default.green("\u25CF") : import_picocolors18.default.red("\u25CF");
111847
+ const name2 = import_picocolors18.default.bold(h3.repo.padEnd(20));
111848
+ const hostUrl = import_picocolors18.default.cyan(h3.hostUrl.padEnd(30));
111849
+ const path = import_picocolors18.default.dim(h3.path);
111850
+ const detail = h3.detail ? import_picocolors18.default.dim(`(${h3.detail})`) : "";
111492
111851
  console.log(` ${dot} ${name2} ${hostUrl} ${path} ${detail}`);
111493
111852
  }
111494
111853
  return 0;
@@ -111496,7 +111855,7 @@ async function runRepos(opts) {
111496
111855
 
111497
111856
  // ../../packages/cli/src/commands/search.ts
111498
111857
  init_cjs_shims();
111499
- var import_picocolors18 = __toESM(require_picocolors(), 1);
111858
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
111500
111859
  async function runSearch(query, opts) {
111501
111860
  const config2 = await loadConfig(opts.config);
111502
111861
  const providers = repoProviders(config2);
@@ -111507,16 +111866,16 @@ async function runSearch(query, opts) {
111507
111866
  }
111508
111867
  let totalMatches = 0;
111509
111868
  for (const result of results) {
111510
- const statusDot = result.reachable ? import_picocolors18.default.green("\u25CF") : import_picocolors18.default.red("\u25CF");
111869
+ const statusDot = result.reachable ? import_picocolors19.default.green("\u25CF") : import_picocolors19.default.red("\u25CF");
111511
111870
  console.log("");
111512
- console.log(`${statusDot} ${import_picocolors18.default.bold("## " + result.repo)} ${import_picocolors18.default.dim(result.hostUrl)}`);
111871
+ console.log(`${statusDot} ${import_picocolors19.default.bold("## " + result.repo)} ${import_picocolors19.default.dim(result.hostUrl)}`);
111513
111872
  if (!result.reachable) {
111514
- console.log(import_picocolors18.default.dim(" (unreachable)"));
111873
+ console.log(import_picocolors19.default.dim(" (unreachable)"));
111515
111874
  } else if (result.symbols.length === 0) {
111516
- console.log(import_picocolors18.default.dim(" (no matches)"));
111875
+ console.log(import_picocolors19.default.dim(" (no matches)"));
111517
111876
  } else {
111518
111877
  for (const sym of result.symbols) {
111519
- console.log(` - ${import_picocolors18.default.bold(sym.name)} ${import_picocolors18.default.dim(sym.filePath)}`);
111878
+ console.log(` - ${import_picocolors19.default.bold(sym.name)} ${import_picocolors19.default.dim(sym.filePath)}`);
111520
111879
  }
111521
111880
  totalMatches += result.symbols.length;
111522
111881
  }
@@ -111524,7 +111883,7 @@ async function runSearch(query, opts) {
111524
111883
  console.log("");
111525
111884
  const reachableCount = results.filter((r) => r.reachable).length;
111526
111885
  console.log(
111527
- import_picocolors18.default.dim(
111886
+ import_picocolors19.default.dim(
111528
111887
  `${totalMatches} match(es) across ${reachableCount}/${results.length} reachable repo(s) for query: "${query}"`
111529
111888
  )
111530
111889
  );
@@ -111533,7 +111892,7 @@ async function runSearch(query, opts) {
111533
111892
 
111534
111893
  // ../../packages/cli/src/commands/investigations.ts
111535
111894
  init_cjs_shims();
111536
- var import_picocolors19 = __toESM(require_picocolors(), 1);
111895
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
111537
111896
 
111538
111897
  // ../../packages/cli/src/lib/format.ts
111539
111898
  init_cjs_shims();
@@ -111576,8 +111935,8 @@ async function runInvestigations(opts) {
111576
111935
  const session = authedClient();
111577
111936
  if (!session) {
111578
111937
  console.error(
111579
- import_picocolors19.default.red(
111580
- `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors19.default.bold("horus login")} first.`
111938
+ import_picocolors20.default.red(
111939
+ `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors20.default.bold("horus login")} first.`
111581
111940
  )
111582
111941
  );
111583
111942
  return 1;
@@ -111618,18 +111977,18 @@ async function runInvestigations(opts) {
111618
111977
 
111619
111978
  // ../../packages/cli/src/commands/replay.ts
111620
111979
  init_cjs_shims();
111621
- var import_picocolors20 = __toESM(require_picocolors(), 1);
111980
+ var import_picocolors21 = __toESM(require_picocolors(), 1);
111622
111981
  async function runReplay(id, opts) {
111623
111982
  const { db, sql: sql2 } = await openDb(await resolveDbUrl(opts.config));
111624
111983
  try {
111625
111984
  const row = await getInvestigation(db, id);
111626
111985
  if (!row) {
111627
- console.error(import_picocolors20.default.red("No investigation found: " + id));
111986
+ console.error(import_picocolors21.default.red("No investigation found: " + id));
111628
111987
  return 1;
111629
111988
  }
111630
111989
  if (!row.report) {
111631
111990
  console.error(
111632
- import_picocolors20.default.red(
111991
+ import_picocolors21.default.red(
111633
111992
  "Investigation " + id + " has no stored report (run a newer investigation)."
111634
111993
  )
111635
111994
  );
@@ -111642,7 +112001,7 @@ async function runReplay(id, opts) {
111642
112001
  if (opts.ai && fmt !== "json") {
111643
112002
  if (report.aiJudgment && !opts.refreshAi) {
111644
112003
  renderStoredAIJudgment(report.aiJudgment);
111645
- console.log(import_picocolors20.default.dim("[ai] Stored judgment replayed. Use --refresh-ai to regenerate."));
112004
+ console.log(import_picocolors21.default.dim("[ai] Stored judgment replayed. Use --refresh-ai to regenerate."));
111646
112005
  } else {
111647
112006
  const narrativeInput = buildNarrativeInput(report);
111648
112007
  const { provider } = await buildNarrativeProvider({
@@ -111655,17 +112014,17 @@ async function runReplay(id, opts) {
111655
112014
  );
111656
112015
  if (!fromProvider && degraded) {
111657
112016
  if (validationErrors?.length) {
111658
- console.error(import_picocolors20.default.yellow("[ai] structured validation incomplete \u2014 showing raw AI narrative"));
112017
+ console.error(import_picocolors21.default.yellow("[ai] structured validation incomplete \u2014 showing raw AI narrative"));
111659
112018
  }
111660
112019
  console.log("");
111661
- console.log(import_picocolors20.default.dim("\u2500".repeat(60)));
111662
- console.log(import_picocolors20.default.bold("AI narrative ") + import_picocolors20.default.yellow("(unstructured \u2014 not validated)"));
111663
- if (output.what?.trim()) console.log(import_picocolors20.default.bold("\nWhat:"), output.what.trim());
111664
- if (output.why?.trim()) console.log(import_picocolors20.default.bold("\nWhy:"), output.why.trim());
112020
+ console.log(import_picocolors21.default.dim("\u2500".repeat(60)));
112021
+ console.log(import_picocolors21.default.bold("AI narrative ") + import_picocolors21.default.yellow("(unstructured \u2014 not validated)"));
112022
+ if (output.what?.trim()) console.log(import_picocolors21.default.bold("\nWhat:"), output.what.trim());
112023
+ if (output.why?.trim()) console.log(import_picocolors21.default.bold("\nWhy:"), output.why.trim());
111665
112024
  } else if (!fromProvider) {
111666
- console.error(import_picocolors20.default.yellow("[ai] Provider unavailable \u2014 deterministic output shown above."));
112025
+ console.error(import_picocolors21.default.yellow("[ai] Provider unavailable \u2014 deterministic output shown above."));
111667
112026
  if (validationErrors?.length) {
111668
- console.error(import_picocolors20.default.dim(` ${validationErrors[0]}`));
112027
+ console.error(import_picocolors21.default.dim(` ${validationErrors[0]}`));
111669
112028
  }
111670
112029
  } else {
111671
112030
  const stored = narrativeOutputToStoredJudgment(output, "anthropic");
@@ -111686,7 +112045,7 @@ async function runReplay(id, opts) {
111686
112045
 
111687
112046
  // ../../packages/cli/src/commands/owner.ts
111688
112047
  init_cjs_shims();
111689
- var import_picocolors21 = __toESM(require_picocolors(), 1);
112048
+ var import_picocolors22 = __toESM(require_picocolors(), 1);
111690
112049
  async function runOwner(query, opts) {
111691
112050
  try {
111692
112051
  const config2 = await loadConfig(opts.config);
@@ -111694,7 +112053,7 @@ async function runOwner(query, opts) {
111694
112053
  try {
111695
112054
  renv = resolveEnvironment(config2, { project: opts.repo });
111696
112055
  } catch (err2) {
111697
- console.error(import_picocolors21.default.red(err2.message));
112056
+ console.error(import_picocolors22.default.red(err2.message));
111698
112057
  return 1;
111699
112058
  }
111700
112059
  const code = codeForRepo(config2, renv.project);
@@ -111702,16 +112061,16 @@ async function runOwner(query, opts) {
111702
112061
  console.log(opts.json ? ownershipToJSON(o5) : renderOwnership(o5));
111703
112062
  return 0;
111704
112063
  } catch (err2) {
111705
- console.error(import_picocolors21.default.red(err2.message));
112064
+ console.error(import_picocolors22.default.red(err2.message));
111706
112065
  return 1;
111707
112066
  }
111708
112067
  }
111709
112068
 
111710
112069
  // ../../packages/cli/src/commands/postmortem.ts
111711
112070
  init_cjs_shims();
111712
- var import_node_fs15 = require("fs");
111713
- var import_node_path16 = require("path");
111714
- var import_picocolors22 = __toESM(require_picocolors(), 1);
112071
+ var import_node_fs16 = require("fs");
112072
+ var import_node_path17 = require("path");
112073
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
111715
112074
  async function runPostmortem(id, opts) {
111716
112075
  const log = opts.write ?? ((line2) => console.log(line2));
111717
112076
  let sql2;
@@ -111725,11 +112084,11 @@ async function runPostmortem(id, opts) {
111725
112084
  const { db } = conn;
111726
112085
  const row = await getInvestigation(db, id);
111727
112086
  if (!row) {
111728
- log(import_picocolors22.default.red("No investigation found: " + id));
112087
+ log(import_picocolors23.default.red("No investigation found: " + id));
111729
112088
  return 1;
111730
112089
  }
111731
112090
  if (!row.report) {
111732
- log(import_picocolors22.default.red("Investigation " + id + " has no stored report."));
112091
+ log(import_picocolors23.default.red("Investigation " + id + " has no stored report."));
111733
112092
  return 1;
111734
112093
  }
111735
112094
  report = migrateReport(row.report);
@@ -111821,25 +112180,25 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
111821
112180
  }
111822
112181
  }
111823
112182
  if (opts.output) {
111824
- const outputPath = (0, import_node_path16.resolve)(opts.output);
111825
- if ((0, import_node_fs15.existsSync)(outputPath) && !opts.force) {
111826
- log(import_picocolors22.default.red("\u2717") + " " + outputPath + " already exists");
111827
- log(import_picocolors22.default.dim(" pass --force to overwrite"));
112183
+ const outputPath = (0, import_node_path17.resolve)(opts.output);
112184
+ if ((0, import_node_fs16.existsSync)(outputPath) && !opts.force) {
112185
+ log(import_picocolors23.default.red("\u2717") + " " + outputPath + " already exists");
112186
+ log(import_picocolors23.default.dim(" pass --force to overwrite"));
111828
112187
  return 1;
111829
112188
  }
111830
112189
  try {
111831
- (0, import_node_fs15.writeFileSync)(outputPath, content, "utf8");
112190
+ (0, import_node_fs16.writeFileSync)(outputPath, content, "utf8");
111832
112191
  } catch (err2) {
111833
- log(import_picocolors22.default.red("\u2717 Could not write " + outputPath + ": ") + err2.message);
112192
+ log(import_picocolors23.default.red("\u2717 Could not write " + outputPath + ": ") + err2.message);
111834
112193
  return 1;
111835
112194
  }
111836
- log(import_picocolors22.default.green("\u2713") + " Saved postmortem to " + outputPath);
112195
+ log(import_picocolors23.default.green("\u2713") + " Saved postmortem to " + outputPath);
111837
112196
  } else {
111838
112197
  log(content);
111839
112198
  }
111840
112199
  } catch (err2) {
111841
112200
  const message = err2 instanceof Error ? err2.message : String(err2);
111842
- log(import_picocolors22.default.red("postmortem failed: " + message));
112201
+ log(import_picocolors23.default.red("postmortem failed: " + message));
111843
112202
  return 1;
111844
112203
  } finally {
111845
112204
  if (sql2) {
@@ -111851,7 +112210,7 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
111851
112210
 
111852
112211
  // ../../packages/cli/src/commands/score.ts
111853
112212
  init_cjs_shims();
111854
- var import_picocolors23 = __toESM(require_picocolors(), 1);
112213
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
111855
112214
  var SCORE_AI_CONTRACT = `Provide a clearly separated AI score explanation with:
111856
112215
 
111857
112216
  Why this scored this way
@@ -111870,11 +112229,11 @@ async function runScore(id, opts) {
111870
112229
  try {
111871
112230
  const row = await getInvestigation(db, id);
111872
112231
  if (!row) {
111873
- console.error(import_picocolors23.default.red("No investigation found: " + id));
112232
+ console.error(import_picocolors24.default.red("No investigation found: " + id));
111874
112233
  return 1;
111875
112234
  }
111876
112235
  if (!row.report) {
111877
- console.error(import_picocolors23.default.red("Investigation " + id + " has no stored report."));
112236
+ console.error(import_picocolors24.default.red("Investigation " + id + " has no stored report."));
111878
112237
  return 1;
111879
112238
  }
111880
112239
  const s5 = scoreInvestigation(migrateReport(row.report));
@@ -111895,7 +112254,7 @@ async function runScore(id, opts) {
111895
112254
  });
111896
112255
  console.log("\n" + renderInterpretation(result));
111897
112256
  if (!result.ok) {
111898
- console.error(import_picocolors23.default.yellow(`[ai] ${result.warning}`));
112257
+ console.error(import_picocolors24.default.yellow(`[ai] ${result.warning}`));
111899
112258
  }
111900
112259
  }
111901
112260
  }
@@ -111935,7 +112294,7 @@ async function runScores(opts) {
111935
112294
 
111936
112295
  // ../../packages/cli/src/commands/ask.ts
111937
112296
  init_cjs_shims();
111938
- var import_picocolors24 = __toESM(require_picocolors(), 1);
112297
+ var import_picocolors25 = __toESM(require_picocolors(), 1);
111939
112298
  function renderAnswer(report, directive, opts) {
111940
112299
  const answer = answerQuestion(report, directive);
111941
112300
  if (answer) {
@@ -111947,13 +112306,13 @@ function renderAnswer(report, directive, opts) {
111947
112306
  if (!opts.json && report.aiJudgment) {
111948
112307
  const j3 = report.aiJudgment;
111949
112308
  console.log("");
111950
- console.log(import_picocolors24.default.dim("\u2500".repeat(60)));
111951
- console.log(import_picocolors24.default.dim(`Stored AI judgment (${j3.provider}, ${j3.generatedAt}):`));
112309
+ console.log(import_picocolors25.default.dim("\u2500".repeat(60)));
112310
+ console.log(import_picocolors25.default.dim(`Stored AI judgment (${j3.provider}, ${j3.generatedAt}):`));
111952
112311
  if (j3.rootCauseAssessment) {
111953
- console.log(import_picocolors24.default.bold("Root cause (AI):"), j3.rootCauseAssessment.summary);
111954
- console.log(import_picocolors24.default.dim(`Uncertainty: ${j3.rootCauseAssessment.uncertainty}`));
112312
+ console.log(import_picocolors25.default.bold("Root cause (AI):"), j3.rootCauseAssessment.summary);
112313
+ console.log(import_picocolors25.default.dim(`Uncertainty: ${j3.rootCauseAssessment.uncertainty}`));
111955
112314
  } else {
111956
- console.log(import_picocolors24.default.bold("AI Why:"), j3.why);
112315
+ console.log(import_picocolors25.default.bold("AI Why:"), j3.why);
111957
112316
  }
111958
112317
  }
111959
112318
  return 0;
@@ -111982,8 +112341,8 @@ async function runAsk(id, directive, opts) {
111982
112341
  const session = authedClient();
111983
112342
  if (!session) {
111984
112343
  console.error(
111985
- import_picocolors24.default.red(
111986
- `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors24.default.bold("horus login")} first.`
112344
+ import_picocolors25.default.red(
112345
+ `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors25.default.bold("horus login")} first.`
111987
112346
  )
111988
112347
  );
111989
112348
  return 1;
@@ -111992,15 +112351,15 @@ async function runAsk(id, directive, opts) {
111992
112351
  const report = await fetchInvestigationReportFromCloud(session.client, cloudCfg, id);
111993
112352
  if (report) return renderAnswer(report, directive, opts);
111994
112353
  console.error(
111995
- import_picocolors24.default.red(
111996
- `Investigation ${id} has no saved report locally or in Horus Cloud. Run ${import_picocolors24.default.bold("horus investigate")} first.`
112354
+ import_picocolors25.default.red(
112355
+ `Investigation ${id} has no saved report locally or in Horus Cloud. Run ${import_picocolors25.default.bold("horus investigate")} first.`
111997
112356
  )
111998
112357
  );
111999
112358
  return 1;
112000
112359
  } catch (err2) {
112001
112360
  if (err2 instanceof CloudError && err2.status === 404) {
112002
112361
  console.error(
112003
- import_picocolors24.default.red(
112362
+ import_picocolors25.default.red(
112004
112363
  `No investigation found for "${id}" locally or in Horus Cloud. Use the id printed at the top of \`horus investigate\` output.`
112005
112364
  )
112006
112365
  );
@@ -112014,21 +112373,21 @@ async function runAsk(id, directive, opts) {
112014
112373
  case "found":
112015
112374
  return renderAnswer(local.report, directive, opts);
112016
112375
  case "no-report":
112017
- console.error(import_picocolors24.default.red("Investigation " + id + " has no stored report."));
112376
+ console.error(import_picocolors25.default.red("Investigation " + id + " has no stored report."));
112018
112377
  return 1;
112019
112378
  case "error":
112020
- console.error(import_picocolors24.default.red(local.message));
112379
+ console.error(import_picocolors25.default.red(local.message));
112021
112380
  return 1;
112022
112381
  case "not-found":
112023
112382
  default:
112024
- console.error(import_picocolors24.default.red("No investigation found: " + id));
112383
+ console.error(import_picocolors25.default.red("No investigation found: " + id));
112025
112384
  return 1;
112026
112385
  }
112027
112386
  }
112028
112387
 
112029
112388
  // ../../packages/cli/src/commands/onboard.ts
112030
112389
  init_cjs_shims();
112031
- var import_picocolors25 = __toESM(require_picocolors(), 1);
112390
+ var import_picocolors26 = __toESM(require_picocolors(), 1);
112032
112391
  var ONBOARD_AI_CONTRACT = `Provide a clearly separated AI onboarding guide with:
112033
112392
 
112034
112393
  Start here
@@ -112056,7 +112415,7 @@ async function runOnboard(area, opts) {
112056
112415
  try {
112057
112416
  renv = resolveEnvironment(config2, { project: opts.repo });
112058
112417
  } catch (err2) {
112059
- console.error(import_picocolors25.default.red(err2.message));
112418
+ console.error(import_picocolors26.default.red(err2.message));
112060
112419
  return 1;
112061
112420
  }
112062
112421
  const repo = { name: renv.project, path: renv.path };
@@ -112064,7 +112423,7 @@ async function runOnboard(area, opts) {
112064
112423
  const health = await code.health();
112065
112424
  if (!health.ok) {
112066
112425
  console.error(
112067
- import_picocolors25.default.red("Source-intelligence host unreachable \u2014 run: horus index")
112426
+ import_picocolors26.default.red("Source-intelligence host unreachable \u2014 run: horus index")
112068
112427
  );
112069
112428
  return 1;
112070
112429
  }
@@ -112091,7 +112450,7 @@ async function runOnboard(area, opts) {
112091
112450
  });
112092
112451
  console.log("\n" + renderInterpretation(result));
112093
112452
  if (!result.ok) {
112094
- console.error(import_picocolors25.default.yellow(`[ai] ${result.warning}`));
112453
+ console.error(import_picocolors26.default.yellow(`[ai] ${result.warning}`));
112095
112454
  }
112096
112455
  }
112097
112456
  }
@@ -112100,14 +112459,14 @@ async function runOnboard(area, opts) {
112100
112459
  }
112101
112460
  return 0;
112102
112461
  } catch (err2) {
112103
- console.error(import_picocolors25.default.red(err2.message));
112462
+ console.error(import_picocolors26.default.red(err2.message));
112104
112463
  return 1;
112105
112464
  }
112106
112465
  }
112107
112466
 
112108
112467
  // ../../packages/cli/src/commands/simulate.ts
112109
112468
  init_cjs_shims();
112110
- var import_picocolors26 = __toESM(require_picocolors(), 1);
112469
+ var import_picocolors27 = __toESM(require_picocolors(), 1);
112111
112470
  async function runSimulate(scenarioId, opts) {
112112
112471
  try {
112113
112472
  if (scenarioId === void 0) {
@@ -112117,7 +112476,7 @@ async function runSimulate(scenarioId, opts) {
112117
112476
  const scenario = getScenario(scenarioId);
112118
112477
  if (scenario === null) {
112119
112478
  console.error(
112120
- import_picocolors26.default.red(
112479
+ import_picocolors27.default.red(
112121
112480
  `Unknown scenario: "${scenarioId}". Run horus simulate to list available scenarios.`
112122
112481
  )
112123
112482
  );
@@ -112128,14 +112487,14 @@ async function runSimulate(scenarioId, opts) {
112128
112487
  try {
112129
112488
  renv = resolveEnvironment(config2, { project: opts.repo });
112130
112489
  } catch (err2) {
112131
- console.error(import_picocolors26.default.red(err2.message));
112490
+ console.error(import_picocolors27.default.red(err2.message));
112132
112491
  return 1;
112133
112492
  }
112134
112493
  const code = codeForRepo(config2, renv.project);
112135
112494
  const health = await code.health();
112136
112495
  if (!health.ok) {
112137
112496
  console.error(
112138
- import_picocolors26.default.red("Source-intelligence host unreachable \u2014 run: horus index")
112497
+ import_picocolors27.default.red("Source-intelligence host unreachable \u2014 run: horus index")
112139
112498
  );
112140
112499
  return 1;
112141
112500
  }
@@ -112152,14 +112511,14 @@ async function runSimulate(scenarioId, opts) {
112152
112511
  }
112153
112512
  return 0;
112154
112513
  } catch (err2) {
112155
- console.error(import_picocolors26.default.red(err2.message));
112514
+ console.error(import_picocolors27.default.red(err2.message));
112156
112515
  return 1;
112157
112516
  }
112158
112517
  }
112159
112518
 
112160
112519
  // ../../packages/cli/src/commands/logs.ts
112161
112520
  init_cjs_shims();
112162
- var import_picocolors27 = __toESM(require_picocolors(), 1);
112521
+ var import_picocolors28 = __toESM(require_picocolors(), 1);
112163
112522
  var LOGS_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
112164
112523
 
112165
112524
  Evidence used
@@ -112205,9 +112564,9 @@ function parseWhere(raw) {
112205
112564
  }
112206
112565
  var whereLabel = (where) => where.map((w4) => `${w4.field}=${w4.value}`).join(", ");
112207
112566
  function levelColor(level, text2) {
112208
- if (level === "error" || level === "fatal") return import_picocolors27.default.red(text2);
112209
- if (level === "warn") return import_picocolors27.default.yellow(text2);
112210
- return import_picocolors27.default.dim(text2);
112567
+ if (level === "error" || level === "fatal") return import_picocolors28.default.red(text2);
112568
+ if (level === "warn") return import_picocolors28.default.yellow(text2);
112569
+ return import_picocolors28.default.dim(text2);
112211
112570
  }
112212
112571
  function matchServiceLabel(requested, candidates) {
112213
112572
  if (candidates.includes(requested)) return { kind: "unique", matched: requested };
@@ -112223,7 +112582,7 @@ async function runLogs(service, opts) {
112223
112582
  try {
112224
112583
  where = parseWhere(opts.where);
112225
112584
  } catch (err2) {
112226
- console.error(import_picocolors27.default.red(err2.message));
112585
+ console.error(import_picocolors28.default.red(err2.message));
112227
112586
  return 1;
112228
112587
  }
112229
112588
  const hasWhere = where.length > 0;
@@ -112233,13 +112592,13 @@ async function runLogs(service, opts) {
112233
112592
  try {
112234
112593
  renv = resolveEnvironment(config2, { project: opts.project, env: opts.env });
112235
112594
  } catch (err2) {
112236
- console.error(import_picocolors27.default.red(err2.message));
112595
+ console.error(import_picocolors28.default.red(err2.message));
112237
112596
  return 1;
112238
112597
  }
112239
112598
  const logs = logsForEnv(renv);
112240
112599
  if (logs === null) {
112241
112600
  console.error(
112242
- import_picocolors27.default.red(
112601
+ import_picocolors28.default.red(
112243
112602
  `No Elasticsearch connector configured for ${renv.project}/${renv.env} (set ES_URL / ES_USERNAME / ES_PASSWORD)`
112244
112603
  )
112245
112604
  );
@@ -112247,7 +112606,7 @@ async function runLogs(service, opts) {
112247
112606
  }
112248
112607
  const health = await logs.health();
112249
112608
  if (!health.ok) {
112250
- console.error(import_picocolors27.default.red(`Elasticsearch unreachable: ${health.detail}`));
112609
+ console.error(import_picocolors28.default.red(`Elasticsearch unreachable: ${health.detail}`));
112251
112610
  return 1;
112252
112611
  }
112253
112612
  const resolvedService = service ?? renv.connectors.elasticsearch?.serviceName;
@@ -112260,21 +112619,21 @@ async function runLogs(service, opts) {
112260
112619
  requiresEventCode: aggregatesEventCode
112261
112620
  });
112262
112621
  for (const w4 of compat.issues.filter((i3) => i3.severity === "warning")) {
112263
- console.warn(import_picocolors27.default.yellow(`[warn] ${w4.field}: ${w4.message}`));
112622
+ console.warn(import_picocolors28.default.yellow(`[warn] ${w4.field}: ${w4.message}`));
112264
112623
  }
112265
112624
  const errors2 = compat.issues.filter((i3) => i3.severity === "error");
112266
112625
  if (errors2.length > 0) {
112267
- console.error(import_picocolors27.default.red("Elasticsearch field mapping is incompatible with the index:"));
112626
+ console.error(import_picocolors28.default.red("Elasticsearch field mapping is incompatible with the index:"));
112268
112627
  for (const e of errors2) {
112269
- console.error(import_picocolors27.default.red(` ${e.field}: ${e.message}`));
112628
+ console.error(import_picocolors28.default.red(` ${e.field}: ${e.message}`));
112270
112629
  }
112271
112630
  console.error(
112272
- import_picocolors27.default.dim("Fix fields.* overrides in your connector config or choose the correct preset.")
112631
+ import_picocolors28.default.dim("Fix fields.* overrides in your connector config or choose the correct preset.")
112273
112632
  );
112274
112633
  return 1;
112275
112634
  }
112276
112635
  } catch {
112277
- console.warn(import_picocolors27.default.dim("[warn] Elasticsearch compatibility check unavailable \u2014 proceeding."));
112636
+ console.warn(import_picocolors28.default.dim("[warn] Elasticsearch compatibility check unavailable \u2014 proceeding."));
112278
112637
  }
112279
112638
  const from = sinceToIso(opts.since) ?? new Date(Date.now() - 7 * 864e5).toISOString();
112280
112639
  const fromDisplay = from.slice(0, 16).replace("T", " ");
@@ -112330,12 +112689,12 @@ async function runLogs(service, opts) {
112330
112689
  return 0;
112331
112690
  }
112332
112691
  console.error(
112333
- import_picocolors27.default.dim(
112692
+ import_picocolors28.default.dim(
112334
112693
  `logs: ${renv.project}/${renv.env}` + (resolvedService ? ` \xB7 service ${resolvedService}` : "") + ` \xB7 from ${fromDisplay} UTC \xB7 level ${rawLevel ?? "all"}` + (hasWhere ? ` \xB7 where ${whereLabel(where)}` : "") + (opts.grep ? ` \xB7 grep "${opts.grep}"` : "") + (rawLevel === "error" && !hasWhere ? " (error+ only \u2014 use --all-levels for info/debug)" : "")
112335
112694
  )
112336
112695
  );
112337
112696
  if (records.length === 0) {
112338
- console.log(import_picocolors27.default.dim("No logs matched."));
112697
+ console.log(import_picocolors28.default.dim("No logs matched."));
112339
112698
  return 0;
112340
112699
  }
112341
112700
  for (const r of records) {
@@ -112345,12 +112704,12 @@ async function runLogs(service, opts) {
112345
112704
  const line2 = `${ts} ${lvl} ${comp} ${r.message.slice(0, 120)}`;
112346
112705
  console.log(levelColor(r.level, line2));
112347
112706
  for (const { key, value } of extractContextFields(r)) {
112348
- console.log(import_picocolors27.default.dim(` ${key}: ${value.slice(0, 200)}`));
112707
+ console.log(import_picocolors28.default.dim(` ${key}: ${value.slice(0, 200)}`));
112349
112708
  }
112350
112709
  }
112351
112710
  if (truncated) {
112352
112711
  console.error(
112353
- import_picocolors27.default.yellow(
112712
+ import_picocolors28.default.yellow(
112354
112713
  `[warn] showing the first ${limit} record(s) \u2014 results may be truncated. Narrow with --where/--since/--level or raise --limit (max 1000).`
112355
112714
  )
112356
112715
  );
@@ -112393,22 +112752,22 @@ async function runLogs(service, opts) {
112393
112752
  return 0;
112394
112753
  }
112395
112754
  console.log(
112396
- import_picocolors27.default.bold(`Top ${field}`) + import_picocolors27.default.dim(
112755
+ import_picocolors28.default.bold(`Top ${field}`) + import_picocolors28.default.dim(
112397
112756
  ` \u2014 ${renv.project}/${renv.env}` + (resolvedService ? ` \xB7 service ${resolvedService}` : "") + (opts.grep ? ` \xB7 grep "${opts.grep}"` : "") + (hasWhere ? ` \xB7 where ${whereLabel(where)}` : "")
112398
112757
  )
112399
112758
  );
112400
- console.log(import_picocolors27.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
112759
+ console.log(import_picocolors28.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
112401
112760
  console.log("");
112402
112761
  if (buckets.length === 0) {
112403
- console.log(import_picocolors27.default.dim(` No error logs with field "${field}" in the window.`));
112404
- console.log(import_picocolors27.default.dim(` Tip: ensure "${field}" is an aggregatable (keyword) field.`));
112762
+ console.log(import_picocolors28.default.dim(` No error logs with field "${field}" in the window.`));
112763
+ console.log(import_picocolors28.default.dim(` Tip: ensure "${field}" is an aggregatable (keyword) field.`));
112405
112764
  return 0;
112406
112765
  }
112407
112766
  for (const b5 of buckets) {
112408
- console.log(` ${import_picocolors27.default.red(String(b5.count).padStart(6))} ${b5.key}`);
112767
+ console.log(` ${import_picocolors28.default.red(String(b5.count).padStart(6))} ${b5.key}`);
112409
112768
  }
112410
112769
  console.log("");
112411
- console.log(import_picocolors27.default.dim(` ${buckets.length} distinct ${field} value(s) shown (top by error count).`));
112770
+ console.log(import_picocolors28.default.dim(` ${buckets.length} distinct ${field} value(s) shown (top by error count).`));
112412
112771
  return 0;
112413
112772
  }
112414
112773
  let analysis = await logs.analyzeErrors({
@@ -112478,46 +112837,46 @@ async function runLogs(service, opts) {
112478
112837
  return 0;
112479
112838
  }
112480
112839
  console.log(
112481
- import_picocolors27.default.bold(`Error analysis`) + import_picocolors27.default.dim(
112840
+ import_picocolors28.default.bold(`Error analysis`) + import_picocolors28.default.dim(
112482
112841
  ` \u2014 ${renv.project}/${renv.env}` + (scopeService ? ` \xB7 service ${scopeService}` : "") + (opts.grep ? ` \xB7 grep "${opts.grep}"` : "") + (hasWhere ? ` \xB7 where ${whereLabel(where)}` : "")
112483
112842
  )
112484
112843
  );
112485
- console.log(import_picocolors27.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
112844
+ console.log(import_picocolors28.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
112486
112845
  if (broadeningNote) {
112487
- console.log(import_picocolors27.default.yellow(` ${broadeningNote}`));
112846
+ console.log(import_picocolors28.default.yellow(` ${broadeningNote}`));
112488
112847
  }
112489
112848
  console.log(
112490
- ` ${analysis.totalErrors} error(s) \xB7 ${analysis.signatures.length} signature(s) \xB7 ${import_picocolors27.default.yellow(String(analysis.newSignatures.length))} new`
112849
+ ` ${analysis.totalErrors} error(s) \xB7 ${analysis.signatures.length} signature(s) \xB7 ${import_picocolors28.default.yellow(String(analysis.newSignatures.length))} new`
112491
112850
  );
112492
112851
  console.log("");
112493
112852
  if (analysis.signatures.length === 0) {
112494
- console.log(import_picocolors27.default.dim(" No error-level logs in the window."));
112853
+ console.log(import_picocolors28.default.dim(" No error-level logs in the window."));
112495
112854
  console.log(
112496
- import_picocolors27.default.dim(
112855
+ import_picocolors28.default.dim(
112497
112856
  ` Searched: ${scopeService ? `service "${scopeService}"` : "all services"} \xB7 index: ${indexPattern} \xB7 from: ${fromDisplay} UTC`
112498
112857
  )
112499
112858
  );
112500
- console.log(import_picocolors27.default.dim(` Tip: use --since to widen the window (e.g. --since 30d).`));
112859
+ console.log(import_picocolors28.default.dim(` Tip: use --since to widen the window (e.g. --since 30d).`));
112501
112860
  return 0;
112502
112861
  }
112503
112862
  for (const s5 of analysis.signatures) {
112504
112863
  const tags = [];
112505
- if (s5.isNew) tags.push(import_picocolors27.default.red("NEW"));
112864
+ if (s5.isNew) tags.push(import_picocolors28.default.red("NEW"));
112506
112865
  else if (s5.ratio !== void 0 && Number.isFinite(s5.ratio) && s5.ratio >= 1.5) {
112507
- tags.push(import_picocolors27.default.yellow(`spike x${s5.ratio.toFixed(1)}`));
112866
+ tags.push(import_picocolors28.default.yellow(`spike x${s5.ratio.toFixed(1)}`));
112508
112867
  }
112509
- const svc = s5.services.length > 0 ? import_picocolors27.default.dim(` \xB7 ${s5.services.slice(0, 3).join(", ")}`) : "";
112868
+ const svc = s5.services.length > 0 ? import_picocolors28.default.dim(` \xB7 ${s5.services.slice(0, 3).join(", ")}`) : "";
112510
112869
  const tagStr = tags.length > 0 ? ` [${tags.join(", ")}]` : "";
112511
112870
  console.log(
112512
- ` ${import_picocolors27.default.red(String(s5.count).padStart(6))} ${import_picocolors27.default.bold(s5.key.padEnd(14).slice(0, 14))} ` + import_picocolors27.default.dim(`first ${shortTs(s5.firstSeen)} \xB7 last ${shortTs(s5.lastSeen)}`) + svc + tagStr
112871
+ ` ${import_picocolors28.default.red(String(s5.count).padStart(6))} ${import_picocolors28.default.bold(s5.key.padEnd(14).slice(0, 14))} ` + import_picocolors28.default.dim(`first ${shortTs(s5.firstSeen)} \xB7 last ${shortTs(s5.lastSeen)}`) + svc + tagStr
112513
112872
  );
112514
112873
  }
112515
112874
  if (analysis.affectedServices.length > 0) {
112516
112875
  console.log("");
112517
- console.log(` ${import_picocolors27.default.bold("Affected services:")} ${analysis.affectedServices.join(", ")}`);
112876
+ console.log(` ${import_picocolors28.default.bold("Affected services:")} ${analysis.affectedServices.join(", ")}`);
112518
112877
  }
112519
112878
  console.log("");
112520
- console.log(import_picocolors27.default.dim(" (use --raw to see individual log lines)"));
112879
+ console.log(import_picocolors28.default.dim(" (use --raw to see individual log lines)"));
112521
112880
  if (opts.ai) {
112522
112881
  const result = await renderAiInterpretation({
112523
112882
  command: "logs",
@@ -112536,19 +112895,19 @@ async function runLogs(service, opts) {
112536
112895
  });
112537
112896
  console.log("\n" + renderInterpretation(result));
112538
112897
  if (!result.ok) {
112539
- console.error(import_picocolors27.default.yellow(`[ai] ${result.warning}`));
112898
+ console.error(import_picocolors28.default.yellow(`[ai] ${result.warning}`));
112540
112899
  }
112541
112900
  }
112542
112901
  return 0;
112543
112902
  } catch (err2) {
112544
- console.error(import_picocolors27.default.red(err2.message));
112903
+ console.error(import_picocolors28.default.red(err2.message));
112545
112904
  return 1;
112546
112905
  }
112547
112906
  }
112548
112907
 
112549
112908
  // ../../packages/cli/src/commands/metrics.ts
112550
112909
  init_cjs_shims();
112551
- var import_picocolors28 = __toESM(require_picocolors(), 1);
112910
+ var import_picocolors29 = __toESM(require_picocolors(), 1);
112552
112911
  var METRICS_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
112553
112912
 
112554
112913
  Evidence used
@@ -112593,10 +112952,10 @@ function anomalyColor(anomaly) {
112593
112952
  case "latency-spike":
112594
112953
  case "error-rate-change":
112595
112954
  case "throughput-drop":
112596
- return import_picocolors28.default.red;
112955
+ return import_picocolors29.default.red;
112597
112956
  case "queue-growth":
112598
112957
  case "change":
112599
- return import_picocolors28.default.yellow;
112958
+ return import_picocolors29.default.yellow;
112600
112959
  default:
112601
112960
  return (s5) => s5;
112602
112961
  }
@@ -112623,7 +112982,7 @@ async function runMetrics(hint, opts) {
112623
112982
  const metrics = metricsProviderFromConfig(config2);
112624
112983
  if (metrics === null) {
112625
112984
  console.error(
112626
- import_picocolors28.default.red(
112985
+ import_picocolors29.default.red(
112627
112986
  "Grafana not configured \u2014 set GRAFANA_URL + GRAFANA_USER + GRAFANA_PASSWORD"
112628
112987
  )
112629
112988
  );
@@ -112631,7 +112990,7 @@ async function runMetrics(hint, opts) {
112631
112990
  }
112632
112991
  const health = await metrics.health();
112633
112992
  if (!health.ok) {
112634
- console.error(import_picocolors28.default.red(`Grafana unreachable: ${health.detail}`));
112993
+ console.error(import_picocolors29.default.red(`Grafana unreachable: ${health.detail}`));
112635
112994
  return 1;
112636
112995
  }
112637
112996
  const stepNum = opts.step !== void 0 ? Number(opts.step) : void 0;
@@ -112660,14 +113019,14 @@ async function runMetrics(hint, opts) {
112660
113019
  return 0;
112661
113020
  }
112662
113021
  if (series.length === 0) {
112663
- console.log(import_picocolors28.default.dim("No series returned."));
113022
+ console.log(import_picocolors29.default.dim("No series returned."));
112664
113023
  return 0;
112665
113024
  }
112666
113025
  for (const s5 of series) {
112667
113026
  const summary = summarize(s5);
112668
113027
  const label = labelStr(s5.labels);
112669
113028
  console.log(
112670
- ` ${import_picocolors28.default.cyan(label || "(no labels)")} last=${import_picocolors28.default.bold(fmtNum(summary.last))} avg=${fmtNum(summary.avg)}`
113029
+ ` ${import_picocolors29.default.cyan(label || "(no labels)")} last=${import_picocolors29.default.bold(fmtNum(summary.last))} avg=${fmtNum(summary.avg)}`
112671
113030
  );
112672
113031
  }
112673
113032
  return 0;
@@ -112682,36 +113041,36 @@ async function runMetrics(hint, opts) {
112682
113041
  if (findings2.length === 0) {
112683
113042
  if (hint !== void 0) {
112684
113043
  const tokens = extractHintTokens(hint);
112685
- console.log(import_picocolors28.default.dim(`No panels matched hint "${hint}".`));
113044
+ console.log(import_picocolors29.default.dim(`No panels matched hint "${hint}".`));
112686
113045
  if (tokens.length > 0) {
112687
- console.log(import_picocolors28.default.dim(` Searched for panels containing: ${tokens.join(", ")}`));
113046
+ console.log(import_picocolors29.default.dim(` Searched for panels containing: ${tokens.join(", ")}`));
112688
113047
  }
112689
113048
  console.log(
112690
- import_picocolors28.default.dim(
112691
- ` Tip: run ${import_picocolors28.default.bold("horus metrics")} (no hint) to see all available panels, then use a panel title or keyword directly.`
113049
+ import_picocolors29.default.dim(
113050
+ ` Tip: run ${import_picocolors29.default.bold("horus metrics")} (no hint) to see all available panels, then use a panel title or keyword directly.`
112692
113051
  )
112693
113052
  );
112694
113053
  } else {
112695
- console.log(import_picocolors28.default.dim("No panels found in configured Grafana dashboards."));
113054
+ console.log(import_picocolors29.default.dim("No panels found in configured Grafana dashboards."));
112696
113055
  }
112697
113056
  return 0;
112698
113057
  }
112699
113058
  const hintSuffix = hint !== void 0 ? ` (hint: "${hint}")` : "";
112700
113059
  const matchSources = hint !== void 0 ? [...new Set(findings2.map((f5) => f5.matchSource).filter(Boolean))] : [];
112701
- const matchSuffix = matchSources.length > 0 ? import_picocolors28.default.dim(` [matched via ${matchSources.join(", ")}]`) : "";
113060
+ const matchSuffix = matchSources.length > 0 ? import_picocolors29.default.dim(` [matched via ${matchSources.join(", ")}]`) : "";
112702
113061
  console.log(
112703
- import_picocolors28.default.bold(
113062
+ import_picocolors29.default.bold(
112704
113063
  `Grafana metrics${hintSuffix} \u2014 ${findings2.length} series across panels`
112705
113064
  ) + matchSuffix
112706
113065
  );
112707
113066
  console.log(
112708
- import_picocolors28.default.dim(
113067
+ import_picocolors29.default.dim(
112709
113068
  ` window: ${new Date(from * 1e3).toISOString()} \u2013 ${new Date(to * 1e3).toISOString()}`
112710
113069
  )
112711
113070
  );
112712
113071
  console.log("");
112713
113072
  if (flagged.length === 0) {
112714
- console.log(import_picocolors28.default.green(" No anomalies detected."));
113073
+ console.log(import_picocolors29.default.green(" No anomalies detected."));
112715
113074
  } else {
112716
113075
  for (const f5 of flagged) {
112717
113076
  const color = anomalyColor(f5.anomaly);
@@ -112720,14 +113079,14 @@ async function runMetrics(hint, opts) {
112720
113079
  const lblStr = labelStr(f5.labels);
112721
113080
  console.log(
112722
113081
  color(
112723
- ` ${label.padEnd(22)} ${f5.panelTitle.padEnd(40).slice(0, 40)} ${fmtNum(f5.baselineAvg)} -> ${fmtNum(f5.currentAvg)} (${ratioStr})` + (lblStr !== "" ? ` ${import_picocolors28.default.dim(lblStr)}` : "")
113082
+ ` ${label.padEnd(22)} ${f5.panelTitle.padEnd(40).slice(0, 40)} ${fmtNum(f5.baselineAvg)} -> ${fmtNum(f5.currentAvg)} (${ratioStr})` + (lblStr !== "" ? ` ${import_picocolors29.default.dim(lblStr)}` : "")
112724
113083
  )
112725
113084
  );
112726
113085
  }
112727
113086
  }
112728
113087
  if (ok.length > 0) {
112729
113088
  console.log("");
112730
- console.log(import_picocolors28.default.dim(` ${ok.length} panel series with no anomaly.`));
113089
+ console.log(import_picocolors29.default.dim(` ${ok.length} panel series with no anomaly.`));
112731
113090
  }
112732
113091
  if (opts.ai) {
112733
113092
  const result = await renderAiInterpretation({
@@ -112742,19 +113101,19 @@ async function runMetrics(hint, opts) {
112742
113101
  });
112743
113102
  console.log("\n" + renderInterpretation(result));
112744
113103
  if (!result.ok) {
112745
- console.error(import_picocolors28.default.yellow(`[ai] ${result.warning}`));
113104
+ console.error(import_picocolors29.default.yellow(`[ai] ${result.warning}`));
112746
113105
  }
112747
113106
  }
112748
113107
  return 0;
112749
113108
  } catch (err2) {
112750
- console.error(import_picocolors28.default.red(err2.message));
113109
+ console.error(import_picocolors29.default.red(err2.message));
112751
113110
  return 1;
112752
113111
  }
112753
113112
  }
112754
113113
 
112755
113114
  // ../../packages/cli/src/commands/state.ts
112756
113115
  init_cjs_shims();
112757
- var import_picocolors29 = __toESM(require_picocolors(), 1);
113116
+ var import_picocolors30 = __toESM(require_picocolors(), 1);
112758
113117
  var STATE_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
112759
113118
 
112760
113119
  Evidence used
@@ -112780,13 +113139,13 @@ async function runState(opts) {
112780
113139
  try {
112781
113140
  renv = resolveEnvironment(config2, { project: opts.project, env: opts.env });
112782
113141
  } catch (err2) {
112783
- console.error(import_picocolors29.default.red(err2.message));
113142
+ console.error(import_picocolors30.default.red(err2.message));
112784
113143
  return 1;
112785
113144
  }
112786
113145
  const mongo = mongoForEnv(renv);
112787
113146
  if (mongo === null) {
112788
113147
  console.error(
112789
- import_picocolors29.default.red(
113148
+ import_picocolors30.default.red(
112790
113149
  `No MongoDB connector configured for ${renv.project}/${renv.env} (set the project's Mongo URL env var).`
112791
113150
  )
112792
113151
  );
@@ -112794,7 +113153,7 @@ async function runState(opts) {
112794
113153
  }
112795
113154
  const health = await mongo.health();
112796
113155
  if (!health.ok) {
112797
- console.error(import_picocolors29.default.red(`MongoDB unreachable: ${health.detail}`));
113156
+ console.error(import_picocolors30.default.red(`MongoDB unreachable: ${health.detail}`));
112798
113157
  await mongo.close();
112799
113158
  return 1;
112800
113159
  }
@@ -112820,38 +113179,38 @@ async function runState(opts) {
112820
113179
  );
112821
113180
  return 0;
112822
113181
  }
112823
- const discoveryNote = analysis.autoDiscovered ? import_picocolors29.default.dim(` (${analysis.collections.length} collections, auto-discovered)`) : "";
113182
+ const discoveryNote = analysis.autoDiscovered ? import_picocolors30.default.dim(` (${analysis.collections.length} collections, auto-discovered)`) : "";
112824
113183
  console.log(
112825
- import_picocolors29.default.bold("State analysis") + import_picocolors29.default.dim(` \u2014 ${renv.project}/${renv.env} \xB7 db ${analysis.database}`) + discoveryNote
113184
+ import_picocolors30.default.bold("State analysis") + import_picocolors30.default.dim(` \u2014 ${renv.project}/${renv.env} \xB7 db ${analysis.database}`) + discoveryNote
112826
113185
  );
112827
113186
  console.log("");
112828
113187
  let signals = 0;
112829
113188
  for (const c4 of analysis.collections) {
112830
113189
  const flags2 = [];
112831
113190
  if (c4.isStale === true) {
112832
- flags2.push(import_picocolors29.default.yellow(`stale (last ${c4.dateField}, ~${Math.round(c4.ageHours ?? 0)}h)`));
113191
+ flags2.push(import_picocolors30.default.yellow(`stale (last ${c4.dateField}, ~${Math.round(c4.ageHours ?? 0)}h)`));
112833
113192
  }
112834
113193
  for (const a2 of c4.anomalies) {
112835
- flags2.push(import_picocolors29.default.red(`${a2.count}\xD7 "${a2.value}"`));
113194
+ flags2.push(import_picocolors30.default.red(`${a2.count}\xD7 "${a2.value}"`));
112836
113195
  signals += 1;
112837
113196
  }
112838
113197
  if (c4.isStale === true) signals += 1;
112839
- const head = ` ${import_picocolors29.default.bold(c4.collection.padEnd(18).slice(0, 18))} ${import_picocolors29.default.dim(String(c4.count).padStart(8) + " docs")}`;
112840
- console.log(flags2.length > 0 ? `${head} ${flags2.join(" ")}` : import_picocolors29.default.dim(head));
113198
+ const head = ` ${import_picocolors30.default.bold(c4.collection.padEnd(18).slice(0, 18))} ${import_picocolors30.default.dim(String(c4.count).padStart(8) + " docs")}`;
113199
+ console.log(flags2.length > 0 ? `${head} ${flags2.join(" ")}` : import_picocolors30.default.dim(head));
112841
113200
  }
112842
113201
  console.log("");
112843
113202
  if (analysis.collections.length === 0) {
112844
113203
  console.log(
112845
- import_picocolors29.default.yellow(" No collections discovered in this database.") + import_picocolors29.default.dim(" Verify the database name in your MongoDB connector config.")
113204
+ import_picocolors30.default.yellow(" No collections discovered in this database.") + import_picocolors30.default.dim(" Verify the database name in your MongoDB connector config.")
112846
113205
  );
112847
113206
  } else {
112848
113207
  const scope = analysis.autoDiscovered ? "collection(s)" : "allowlisted collection(s)";
112849
113208
  console.log(
112850
- signals > 0 ? ` ${import_picocolors29.default.bold(String(signals))} state signal(s) across ${analysis.collections.length} ${scope}` : import_picocolors29.default.dim(` No state anomalies across ${analysis.collections.length} ${scope}.`)
113209
+ signals > 0 ? ` ${import_picocolors30.default.bold(String(signals))} state signal(s) across ${analysis.collections.length} ${scope}` : import_picocolors30.default.dim(` No state anomalies across ${analysis.collections.length} ${scope}.`)
112851
113210
  );
112852
113211
  if (analysis.autoDiscovered) {
112853
113212
  console.log(
112854
- import_picocolors29.default.dim(
113213
+ import_picocolors30.default.dim(
112855
113214
  ` Tip: add a "collections" list to your MongoDB connector config to restrict analysis.`
112856
113215
  )
112857
113216
  );
@@ -112869,7 +113228,7 @@ async function runState(opts) {
112869
113228
  });
112870
113229
  console.log("\n" + renderInterpretation(result));
112871
113230
  if (!result.ok) {
112872
- console.error(import_picocolors29.default.yellow(`[ai] ${result.warning}`));
113231
+ console.error(import_picocolors30.default.yellow(`[ai] ${result.warning}`));
112873
113232
  }
112874
113233
  }
112875
113234
  return 0;
@@ -112877,20 +113236,20 @@ async function runState(opts) {
112877
113236
  await mongo.close();
112878
113237
  }
112879
113238
  } catch (err2) {
112880
- console.error(import_picocolors29.default.red(err2.message));
113239
+ console.error(import_picocolors30.default.red(err2.message));
112881
113240
  return 1;
112882
113241
  }
112883
113242
  }
112884
113243
 
112885
113244
  // ../../packages/cli/src/commands/init.ts
112886
113245
  init_cjs_shims();
112887
- var import_picocolors30 = __toESM(require_picocolors(), 1);
112888
- var import_node_path17 = require("path");
113246
+ var import_picocolors31 = __toESM(require_picocolors(), 1);
113247
+ var import_node_path18 = require("path");
112889
113248
  async function runInit(opts) {
112890
113249
  try {
112891
113250
  const cwd = process.cwd();
112892
- const root = opts.path ? (0, import_node_path17.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
112893
- const name2 = opts.name ?? (0, import_node_path17.basename)(root);
113251
+ const root = opts.path ? (0, import_node_path18.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
113252
+ const name2 = opts.name ?? (0, import_node_path18.basename)(root);
112894
113253
  const envName = opts.env ?? "production";
112895
113254
  const repo = { name: name2, path: root };
112896
113255
  if (opts.source) repo["source"] = { hostUrl: opts.source };
@@ -112905,65 +113264,65 @@ async function runInit(opts) {
112905
113264
  const configPath = writeLocalConfig(root, file);
112906
113265
  registerProject(name2, root, configPath);
112907
113266
  ensureProjectGitignore(root);
112908
- console.log(`${import_picocolors30.default.green("\u2713")} Initialized Horus project ${import_picocolors30.default.bold(name2)}`);
112909
- console.log(import_picocolors30.default.dim(` config: ${configPath}`));
112910
- console.log(import_picocolors30.default.dim(` registered: horus investigate --name ${name2} "<hint>"`));
113267
+ console.log(`${import_picocolors31.default.green("\u2713")} Initialized Horus project ${import_picocolors31.default.bold(name2)}`);
113268
+ console.log(import_picocolors31.default.dim(` config: ${configPath}`));
113269
+ console.log(import_picocolors31.default.dim(` registered: horus investigate --name ${name2} "<hint>"`));
112911
113270
  if (!opts.source) {
112912
113271
  console.log(
112913
- import_picocolors30.default.dim(" no source-intelligence host set \u2014 run `horus index` to analyze + host, or pass --source <url>")
113272
+ import_picocolors31.default.dim(" no source-intelligence host set \u2014 run `horus index` to analyze + host, or pass --source <url>")
112914
113273
  );
112915
113274
  }
112916
113275
  console.log(
112917
- import_picocolors30.default.dim(" add runtime connectors (elasticsearch/mongodb/grafana) to .horus/config.json")
113276
+ import_picocolors31.default.dim(" add runtime connectors (elasticsearch/mongodb/grafana) to .horus/config.json")
112918
113277
  );
112919
113278
  console.log(
112920
- import_picocolors30.default.dim(" .horus/ is gitignored \u2014 local config and runtime state stay out of version control")
113279
+ import_picocolors31.default.dim(" .horus/ is gitignored \u2014 local config and runtime state stay out of version control")
112921
113280
  );
112922
113281
  return 0;
112923
113282
  } catch (err2) {
112924
- console.error(import_picocolors30.default.red(err2.message));
113283
+ console.error(import_picocolors31.default.red(err2.message));
112925
113284
  return 1;
112926
113285
  }
112927
113286
  }
112928
113287
 
112929
113288
  // ../../packages/cli/src/commands/projects.ts
112930
113289
  init_cjs_shims();
112931
- var import_picocolors31 = __toESM(require_picocolors(), 1);
113290
+ var import_picocolors32 = __toESM(require_picocolors(), 1);
112932
113291
  async function runProjects() {
112933
113292
  const reg = readRegistry();
112934
113293
  const names = Object.keys(reg.projects).sort();
112935
113294
  if (names.length === 0) {
112936
113295
  console.log(
112937
- import_picocolors31.default.dim("No registered projects. Run `horus index` (or `horus init`) inside a repo.")
113296
+ import_picocolors32.default.dim("No registered projects. Run `horus index` (or `horus init`) inside a repo.")
112938
113297
  );
112939
113298
  return 0;
112940
113299
  }
112941
- console.log(import_picocolors31.default.bold("Registered Horus projects"));
113300
+ console.log(import_picocolors32.default.bold("Registered Horus projects"));
112942
113301
  console.log("");
112943
113302
  for (const name2 of names) {
112944
113303
  const entry2 = reg.projects[name2];
112945
113304
  if (entry2 === void 0) continue;
112946
- console.log(` ${import_picocolors31.default.bold(name2.padEnd(22))} ${import_picocolors31.default.dim(entry2.root)}`);
113305
+ console.log(` ${import_picocolors32.default.bold(name2.padEnd(22))} ${import_picocolors32.default.dim(entry2.root)}`);
112947
113306
  }
112948
113307
  console.log("");
112949
- console.log(import_picocolors31.default.dim(' horus investigate --name <name> "<hint>"'));
113308
+ console.log(import_picocolors32.default.dim(' horus investigate --name <name> "<hint>"'));
112950
113309
  return 0;
112951
113310
  }
112952
113311
 
112953
113312
  // ../../packages/cli/src/commands/setup.ts
112954
113313
  init_cjs_shims();
112955
- var import_picocolors32 = __toESM(require_picocolors(), 1);
113314
+ var import_picocolors33 = __toESM(require_picocolors(), 1);
112956
113315
  var DEFAULT_DB_URL3 = "postgresql://horus:horus@localhost:5433/horus";
112957
113316
  async function runSetup(opts) {
112958
113317
  const write = opts.write ?? ((line2) => console.log(line2));
112959
113318
  let ok = true;
112960
- write(import_picocolors32.default.bold("\nHorus setup\n"));
113319
+ write(import_picocolors33.default.bold("\nHorus setup\n"));
112961
113320
  const backendVersion = await getSourceVersion();
112962
113321
  if (backendVersion === null) {
112963
113322
  ok = false;
112964
- write(` ${import_picocolors32.default.red("\u25CF")} Horus source-intelligence backend not found`);
113323
+ write(` ${import_picocolors33.default.red("\u25CF")} Horus source-intelligence backend not found`);
112965
113324
  write(
112966
- import_picocolors32.default.dim(
113325
+ import_picocolors33.default.dim(
112967
113326
  ` install it (Python 3.11+ required):
112968
113327
  curl -fsSL https://horus.sh/install.sh | bash
112969
113328
  ensure ~/.local/bin is on your PATH`
@@ -112972,17 +113331,17 @@ async function runSetup(opts) {
112972
113331
  } else if (backendVersion !== PINNED_SOURCE_VERSION) {
112973
113332
  ok = false;
112974
113333
  write(
112975
- ` ${import_picocolors32.default.yellow("\u25CF")} Horus source-intelligence backend version mismatch` + import_picocolors32.default.dim(` (installed: ${backendVersion}, required: ${PINNED_SOURCE_VERSION})`)
113334
+ ` ${import_picocolors33.default.yellow("\u25CF")} Horus source-intelligence backend version mismatch` + import_picocolors33.default.dim(` (installed: ${backendVersion}, required: ${PINNED_SOURCE_VERSION})`)
112976
113335
  );
112977
113336
  write(
112978
- import_picocolors32.default.dim(
113337
+ import_picocolors33.default.dim(
112979
113338
  ` update it:
112980
113339
  horus update`
112981
113340
  )
112982
113341
  );
112983
113342
  } else {
112984
113343
  write(
112985
- ` ${import_picocolors32.default.green("\u25CF")} Horus source-intelligence backend ` + import_picocolors32.default.dim(`(${backendVersion})`)
113344
+ ` ${import_picocolors33.default.green("\u25CF")} Horus source-intelligence backend ` + import_picocolors33.default.dim(`(${backendVersion})`)
112986
113345
  );
112987
113346
  }
112988
113347
  let dbUrl = process.env["DATABASE_URL"] ?? DEFAULT_DB_URL3;
@@ -112994,11 +113353,11 @@ async function runSetup(opts) {
112994
113353
  }
112995
113354
  const db = await checkDatabase(dbUrl);
112996
113355
  if (db.reachable) {
112997
- write(` ${import_picocolors32.default.green("\u25CF")} Postgres reachable ${import_picocolors32.default.dim(`(${db.schemaDetail})`)}`);
113356
+ write(` ${import_picocolors33.default.green("\u25CF")} Postgres reachable ${import_picocolors33.default.dim(`(${db.schemaDetail})`)}`);
112998
113357
  if (!db.schemaReady) {
112999
113358
  ok = false;
113000
113359
  write(
113001
- import_picocolors32.default.dim(
113360
+ import_picocolors33.default.dim(
113002
113361
  ` schema not applied \u2014 run migrations:
113003
113362
  from the Horus repo: pnpm db migrate
113004
113363
  or apply the schema directly: https://github.com/meritt-dev/horus/tree/master/packages/db/drizzle`
@@ -113007,9 +113366,9 @@ async function runSetup(opts) {
113007
113366
  }
113008
113367
  } else {
113009
113368
  ok = false;
113010
- write(` ${import_picocolors32.default.red("\u25CF")} Postgres unreachable`);
113369
+ write(` ${import_picocolors33.default.red("\u25CF")} Postgres unreachable`);
113011
113370
  write(
113012
- import_picocolors32.default.dim(
113371
+ import_picocolors33.default.dim(
113013
113372
  ` start a local instance:
113014
113373
  docker run -d --name horus-db \\
113015
113374
  -e POSTGRES_USER=horus -e POSTGRES_PASSWORD=horus -e POSTGRES_DB=horus \\
@@ -113034,10 +113393,10 @@ async function runSetup(opts) {
113034
113393
  if (!health.ok) {
113035
113394
  ok = false;
113036
113395
  write(
113037
- ` ${import_picocolors32.default.red("\u25CF")} Source intelligence host unreachable for ${import_picocolors32.default.bold(repo.name)} ` + import_picocolors32.default.dim(`(${repoHostUrl})`)
113396
+ ` ${import_picocolors33.default.red("\u25CF")} Source intelligence host unreachable for ${import_picocolors33.default.bold(repo.name)} ` + import_picocolors33.default.dim(`(${repoHostUrl})`)
113038
113397
  );
113039
113398
  write(
113040
- import_picocolors32.default.dim(
113399
+ import_picocolors33.default.dim(
113041
113400
  ` start the source intelligence host:
113042
113401
  cd ${repo.path}
113043
113402
  horus index`
@@ -113048,10 +113407,10 @@ async function runSetup(opts) {
113048
113407
  if (count === 0) {
113049
113408
  ok = false;
113050
113409
  write(
113051
- ` ${import_picocolors32.default.yellow("\u25CF")} Source intelligence host running but ${import_picocolors32.default.bold(repo.name)} is not indexed`
113410
+ ` ${import_picocolors33.default.yellow("\u25CF")} Source intelligence host running but ${import_picocolors33.default.bold(repo.name)} is not indexed`
113052
113411
  );
113053
113412
  write(
113054
- import_picocolors32.default.dim(
113413
+ import_picocolors33.default.dim(
113055
113414
  ` index the repo:
113056
113415
  cd ${repo.path}
113057
113416
  horus index`
@@ -113059,7 +113418,7 @@ async function runSetup(opts) {
113059
113418
  );
113060
113419
  } else {
113061
113420
  write(
113062
- ` ${import_picocolors32.default.green("\u25CF")} ${import_picocolors32.default.bold(repo.name)} \u2014 ${count} nodes indexed ` + import_picocolors32.default.dim(`(${repoHostUrl})`)
113421
+ ` ${import_picocolors33.default.green("\u25CF")} ${import_picocolors33.default.bold(repo.name)} \u2014 ${count} nodes indexed ` + import_picocolors33.default.dim(`(${repoHostUrl})`)
113063
113422
  );
113064
113423
  }
113065
113424
  }
@@ -113069,10 +113428,10 @@ async function runSetup(opts) {
113069
113428
  write("");
113070
113429
  if (ok) {
113071
113430
  write(
113072
- import_picocolors32.default.green("Ready.") + ' Next: `cd` into a repo and run `horus index`, then `horus investigate "<hint>"`.'
113431
+ import_picocolors33.default.green("Ready.") + ' Next: `cd` into a repo and run `horus index`, then `horus investigate "<hint>"`.'
113073
113432
  );
113074
113433
  } else {
113075
- write(import_picocolors32.default.yellow("Resolve the items above, then re-run `horus setup`."));
113434
+ write(import_picocolors33.default.yellow("Resolve the items above, then re-run `horus setup`."));
113076
113435
  }
113077
113436
  return ok ? 0 : 1;
113078
113437
  }
@@ -113080,13 +113439,13 @@ async function runSetup(opts) {
113080
113439
  // ../../packages/cli/src/commands/connect.ts
113081
113440
  init_cjs_shims();
113082
113441
  var import_node_readline = require("readline");
113083
- var import_node_child_process6 = require("child_process");
113084
- var import_picocolors35 = __toESM(require_picocolors(), 1);
113442
+ var import_node_child_process7 = require("child_process");
113443
+ var import_picocolors36 = __toESM(require_picocolors(), 1);
113085
113444
 
113086
113445
  // ../../packages/cli/src/lib/tty-selector.ts
113087
113446
  init_cjs_shims();
113088
113447
  var import_node_tty = require("tty");
113089
- var import_picocolors33 = __toESM(require_picocolors(), 1);
113448
+ var import_picocolors34 = __toESM(require_picocolors(), 1);
113090
113449
  var ExitPromptError = class extends Error {
113091
113450
  constructor(message = "Prompt was cancelled") {
113092
113451
  super(message);
@@ -113142,7 +113501,7 @@ async function checkboxSearch(opts) {
113142
113501
  clear();
113143
113502
  const lines = [];
113144
113503
  lines.push(
113145
- `? ${import_picocolors33.default.bold(message)} ${import_picocolors33.default.dim("(\u2191\u2193 navigate \u2022 space toggle \u2022 enter confirm \u2022 type filter)")}`
113504
+ `? ${import_picocolors34.default.bold(message)} ${import_picocolors34.default.dim("(\u2191\u2193 navigate \u2022 space toggle \u2022 enter confirm \u2022 type filter)")}`
113146
113505
  );
113147
113506
  const visible = filtered.slice(visibleOffset, visibleOffset + pageSize);
113148
113507
  for (let i3 = 0; i3 < visible.length; i3++) {
@@ -113150,29 +113509,29 @@ async function checkboxSearch(opts) {
113150
113509
  const choice = visible[i3];
113151
113510
  const isCursor = idx === cursor;
113152
113511
  const isSelected = selected.has(choice);
113153
- const marker = isSelected ? import_picocolors33.default.green("\u25CF") : " ";
113512
+ const marker = isSelected ? import_picocolors34.default.green("\u25CF") : " ";
113154
113513
  const prefix = `[${marker}]`;
113155
- const label = isCursor ? import_picocolors33.default.cyan(choice) : choice;
113156
- const pointer = isCursor ? import_picocolors33.default.cyan("\u276F") : " ";
113514
+ const label = isCursor ? import_picocolors34.default.cyan(choice) : choice;
113515
+ const pointer = isCursor ? import_picocolors34.default.cyan("\u276F") : " ";
113157
113516
  lines.push(` ${pointer} ${prefix} ${label}`);
113158
113517
  }
113159
113518
  if (filtered.length === 0) {
113160
- lines.push(import_picocolors33.default.dim(" No matches"));
113519
+ lines.push(import_picocolors34.default.dim(" No matches"));
113161
113520
  }
113162
113521
  const statusParts = [
113163
113522
  `${selected.size} selected`,
113164
113523
  `${filtered.length}/${choices.length} matches`
113165
113524
  ];
113166
113525
  if (filter) statusParts.push(`filter: ${filter}`);
113167
- lines.push(import_picocolors33.default.dim(` ${statusParts.join(" \xB7 ")}`));
113526
+ lines.push(import_picocolors34.default.dim(` ${statusParts.join(" \xB7 ")}`));
113168
113527
  output.write(lines.join("\n"));
113169
113528
  lastRenderLines = lines.length;
113170
113529
  }
113171
113530
  function finish(values2) {
113172
113531
  cleanup();
113173
- const summary = values2.length > 0 ? values2.join(", ") : import_picocolors33.default.dim("none");
113532
+ const summary = values2.length > 0 ? values2.join(", ") : import_picocolors34.default.dim("none");
113174
113533
  output.write(`
113175
- ? ${import_picocolors33.default.bold(message)} ${summary}
113534
+ ? ${import_picocolors34.default.bold(message)} ${summary}
113176
113535
  `);
113177
113536
  resolve9(values2);
113178
113537
  }
@@ -113263,10 +113622,10 @@ async function checkboxSearch(opts) {
113263
113622
 
113264
113623
  // ../../packages/cli/src/commands/connect-ai.ts
113265
113624
  init_cjs_shims();
113266
- var import_node_child_process5 = require("child_process");
113267
- var import_picocolors34 = __toESM(require_picocolors(), 1);
113625
+ var import_node_child_process6 = require("child_process");
113626
+ var import_picocolors35 = __toESM(require_picocolors(), 1);
113268
113627
  function cliInstalled(id) {
113269
- const r = (0, import_node_child_process5.spawnSync)(id, ["--version"], { stdio: "ignore", timeout: 2e3 });
113628
+ const r = (0, import_node_child_process6.spawnSync)(id, ["--version"], { stdio: "ignore", timeout: 2e3 });
113270
113629
  return !r.error;
113271
113630
  }
113272
113631
  async function probeAnthropic(apiKey) {
@@ -113292,13 +113651,13 @@ async function runConnectAi(opts) {
113292
113651
  const root = findRepoRoot(cwd) ?? cwd;
113293
113652
  const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
113294
113653
  const installed = LOCAL_PROVIDER_IDS.filter((id) => cliInstalled(id));
113295
- console.log(import_picocolors34.default.bold("\nAI providers"));
113654
+ console.log(import_picocolors35.default.bold("\nAI providers"));
113296
113655
  console.log(
113297
- import_picocolors34.default.dim(
113656
+ import_picocolors35.default.dim(
113298
113657
  ` Local CLIs on PATH: ${installed.length > 0 ? installed.join(", ") : "none detected"}`
113299
113658
  )
113300
113659
  );
113301
- console.log(import_picocolors34.default.dim(" Cloud: anthropic (Anthropic Claude API \u2014 used by `investigate --ai`)\n"));
113660
+ console.log(import_picocolors35.default.dim(" Cloud: anthropic (Anthropic Claude API \u2014 used by `investigate --ai`)\n"));
113302
113661
  let provider = opts.provider;
113303
113662
  if (provider === void 0) {
113304
113663
  if (isInteractive()) {
@@ -113309,7 +113668,7 @@ async function runConnectAi(opts) {
113309
113668
  }
113310
113669
  }
113311
113670
  if (!AI_PROVIDERS.includes(provider)) {
113312
- console.error(import_picocolors34.default.red(`Unknown AI provider: ${provider}`) + import_picocolors34.default.dim(`
113671
+ console.error(import_picocolors35.default.red(`Unknown AI provider: ${provider}`) + import_picocolors35.default.dim(`
113313
113672
  supported: ${AI_PROVIDERS.join(", ")}`));
113314
113673
  return 1;
113315
113674
  }
@@ -113322,7 +113681,7 @@ async function runConnectAi(opts) {
113322
113681
  }
113323
113682
  if (!apiKey) {
113324
113683
  console.error(
113325
- import_picocolors34.default.red("No API key provided.") + import_picocolors34.default.dim("\n Pass --api-key sk-ant-\u2026 or set ANTHROPIC_API_KEY and re-run.")
113684
+ import_picocolors35.default.red("No API key provided.") + import_picocolors35.default.dim("\n Pass --api-key sk-ant-\u2026 or set ANTHROPIC_API_KEY and re-run.")
113326
113685
  );
113327
113686
  return 1;
113328
113687
  }
@@ -113330,28 +113689,28 @@ async function runConnectAi(opts) {
113330
113689
  const probe2 = await probeAnthropic(apiKey);
113331
113690
  if (!probe2.ok) {
113332
113691
  console.error(`
113333
- ${import_picocolors34.default.red("\u2717 Anthropic key check failed:")} ${probe2.detail}`);
113334
- console.error(import_picocolors34.default.dim(" Fix the key and retry, or pass --no-test to skip."));
113692
+ ${import_picocolors35.default.red("\u2717 Anthropic key check failed:")} ${probe2.detail}`);
113693
+ console.error(import_picocolors35.default.dim(" Fix the key and retry, or pass --no-test to skip."));
113335
113694
  return 1;
113336
113695
  }
113337
113696
  console.log(`
113338
- ${import_picocolors34.default.green("\u2713")} anthropic ${import_picocolors34.default.dim(`(${probe2.detail})`)}`);
113697
+ ${import_picocolors35.default.green("\u2713")} anthropic ${import_picocolors35.default.dim(`(${probe2.detail})`)}`);
113339
113698
  }
113340
113699
  if (opts.model) aiBlock["anthropic"] = { model: opts.model };
113341
113700
  storedKey = apiKey;
113342
113701
  } else {
113343
113702
  if (!installed.includes(provider)) {
113344
113703
  console.error(
113345
- import_picocolors34.default.red(`${provider} CLI not found on PATH.`) + import_picocolors34.default.dim(`
113704
+ import_picocolors35.default.red(`${provider} CLI not found on PATH.`) + import_picocolors35.default.dim(`
113346
113705
  Install it first, or choose anthropic.`)
113347
113706
  );
113348
113707
  return 1;
113349
113708
  }
113350
113709
  const desc2 = DEFAULT_LOCAL_PROVIDER_REGISTRY.get(provider);
113351
113710
  console.log(`
113352
- ${import_picocolors34.default.green("\u2713")} ${desc2?.displayName ?? provider} ${import_picocolors34.default.dim("detected on PATH")}`);
113711
+ ${import_picocolors35.default.green("\u2713")} ${desc2?.displayName ?? provider} ${import_picocolors35.default.dim("detected on PATH")}`);
113353
113712
  console.log(
113354
- import_picocolors34.default.dim(
113713
+ import_picocolors35.default.dim(
113355
113714
  " Note: `investigate --ai` currently uses the Anthropic API for narrative.\n Local-CLI narrative generation is recorded as your preference for future use."
113356
113715
  )
113357
113716
  );
@@ -113369,15 +113728,15 @@ ${import_picocolors34.default.green("\u2713")} ${desc2?.displayName ?? provider}
113369
113728
  });
113370
113729
  }
113371
113730
  console.log(`
113372
- ${import_picocolors34.default.green("\u2713")} ${import_picocolors34.default.bold("ai")} provider saved \u2192 ${import_picocolors34.default.dim(configPath)}`);
113373
- console.log(import_picocolors34.default.dim(` provider: ${provider}`));
113731
+ ${import_picocolors35.default.green("\u2713")} ${import_picocolors35.default.bold("ai")} provider saved \u2192 ${import_picocolors35.default.dim(configPath)}`);
113732
+ console.log(import_picocolors35.default.dim(` provider: ${provider}`));
113374
113733
  if (storedKey && secretsPathStr) {
113375
- console.log(import_picocolors34.default.dim(` anthropic key: ${redactKey(storedKey)} \u2192 ${secretsPathStr} (gitignored)`));
113734
+ console.log(import_picocolors35.default.dim(` anthropic key: ${redactKey(storedKey)} \u2192 ${secretsPathStr} (gitignored)`));
113376
113735
  }
113377
- console.log(import_picocolors34.default.dim(' run: horus investigate "<hint>" --ai'));
113736
+ console.log(import_picocolors35.default.dim(' run: horus investigate "<hint>" --ai'));
113378
113737
  return 0;
113379
113738
  } catch (err2) {
113380
- console.error(import_picocolors34.default.red(err2 instanceof Error ? err2.message : String(err2)));
113739
+ console.error(import_picocolors35.default.red(err2 instanceof Error ? err2.message : String(err2)));
113381
113740
  return 1;
113382
113741
  }
113383
113742
  }
@@ -113409,7 +113768,7 @@ async function runConnect(type, opts) {
113409
113768
  }
113410
113769
  if (!SUPPORTED.includes(type)) {
113411
113770
  console.error(
113412
- import_picocolors35.default.red(`Unknown connector type: ${type}`) + import_picocolors35.default.dim(`
113771
+ import_picocolors36.default.red(`Unknown connector type: ${type}`) + import_picocolors36.default.dim(`
113413
113772
  supported: ${SUPPORTED.join(", ")}, ai`)
113414
113773
  );
113415
113774
  return 1;
@@ -113446,20 +113805,20 @@ async function runConnect(type, opts) {
113446
113805
  if (!probeResult.ok) {
113447
113806
  console.error(
113448
113807
  `
113449
- ${import_picocolors35.default.red(`\u2717 Could not reach ${connectorType}:`)} ${probeResult.detail}` + import_picocolors35.default.dim("\n Fix the connection and retry, or pass --no-test to skip.")
113808
+ ${import_picocolors36.default.red(`\u2717 Could not reach ${connectorType}:`)} ${probeResult.detail}` + import_picocolors36.default.dim("\n Fix the connection and retry, or pass --no-test to skip.")
113450
113809
  );
113451
113810
  return 1;
113452
113811
  }
113453
113812
  console.log(
113454
113813
  `
113455
- ${import_picocolors35.default.green("\u2713")} ${connectorType} reachable ${import_picocolors35.default.dim(`(${probeResult.detail})`)}`
113814
+ ${import_picocolors36.default.green("\u2713")} ${connectorType} reachable ${import_picocolors36.default.dim(`(${probeResult.detail})`)}`
113456
113815
  );
113457
113816
  }
113458
113817
  const hasLiteralCredentials = filled.url !== void 0 || filled.password !== void 0 || filled.username !== void 0 || filled.authToken !== void 0;
113459
113818
  if (hasLiteralCredentials) {
113460
113819
  if (isGitTracked(configPath, root)) {
113461
113820
  console.error(
113462
- import_picocolors35.default.red(".horus/config.json is already tracked by Git.") + "\nStoring credentials here would expose them in the repository.\n" + import_picocolors35.default.dim(
113821
+ import_picocolors36.default.red(".horus/config.json is already tracked by Git.") + "\nStoring credentials here would expose them in the repository.\n" + import_picocolors36.default.dim(
113463
113822
  " 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."
113464
113823
  )
113465
113824
  );
@@ -113469,18 +113828,18 @@ ${import_picocolors35.default.green("\u2713")} ${connectorType} reachable ${impo
113469
113828
  }
113470
113829
  patchLocalConnector(configPath, connectorType, patch, filled.env);
113471
113830
  console.log(
113472
- `${import_picocolors35.default.green("\u2713")} ${import_picocolors35.default.bold(connectorType)} connector saved \u2192 ${import_picocolors35.default.dim(configPath)}`
113831
+ `${import_picocolors36.default.green("\u2713")} ${import_picocolors36.default.bold(connectorType)} connector saved \u2192 ${import_picocolors36.default.dim(configPath)}`
113473
113832
  );
113474
113833
  printSummary(connectorType, filled);
113475
- console.log(import_picocolors35.default.dim(`
113834
+ console.log(import_picocolors36.default.dim(`
113476
113835
  run: horus investigate "<hint>"`));
113477
113836
  return 0;
113478
113837
  } catch (err2) {
113479
113838
  if (err2 instanceof ExitPromptError) {
113480
- console.error(import_picocolors35.default.red("Cancelled."));
113839
+ console.error(import_picocolors36.default.red("Cancelled."));
113481
113840
  return 1;
113482
113841
  }
113483
- console.error(import_picocolors35.default.red(err2.message));
113842
+ console.error(import_picocolors36.default.red(err2.message));
113484
113843
  return 1;
113485
113844
  }
113486
113845
  }
@@ -113489,7 +113848,7 @@ async function fillInteractive(type, opts) {
113489
113848
  if (!needsInteraction) return opts;
113490
113849
  console.log(
113491
113850
  `
113492
- ${import_picocolors35.default.bold(`Connect ${type}`)} ${import_picocolors35.default.dim("(press Enter to skip optional fields)")}
113851
+ ${import_picocolors36.default.bold(`Connect ${type}`)} ${import_picocolors36.default.dim("(press Enter to skip optional fields)")}
113493
113852
  `
113494
113853
  );
113495
113854
  const filled = { ...opts };
@@ -113555,7 +113914,7 @@ ${import_picocolors35.default.bold(`Connect ${type}`)} ${import_picocolors35.def
113555
113914
  break;
113556
113915
  case "redis": {
113557
113916
  console.log(
113558
- import_picocolors35.default.dim(
113917
+ import_picocolors36.default.dim(
113559
113918
  " Tip: embed credentials directly in the URL \u2014 redis://:password@host:6379\n or enter the URL and password separately below."
113560
113919
  )
113561
113920
  );
@@ -113597,8 +113956,8 @@ function missingRequired(type, opts) {
113597
113956
  }
113598
113957
  function ask(label, placeholder = "", required2 = true) {
113599
113958
  return new Promise((resolve9) => {
113600
- const hint = placeholder ? import_picocolors35.default.dim(` (${placeholder})`) : "";
113601
- const suffix = required2 ? "" : import_picocolors35.default.dim(" [optional]");
113959
+ const hint = placeholder ? import_picocolors36.default.dim(` (${placeholder})`) : "";
113960
+ const suffix = required2 ? "" : import_picocolors36.default.dim(" [optional]");
113602
113961
  process.stdout.write(` ${label}${suffix}${hint}: `);
113603
113962
  const rl = (0, import_node_readline.createInterface)({
113604
113963
  input: process.stdin,
@@ -113615,7 +113974,7 @@ function askPassword(label) {
113615
113974
  return new Promise((resolve9) => {
113616
113975
  const stdin = process.stdin;
113617
113976
  if (typeof stdin.setRawMode === "function") {
113618
- process.stdout.write(` ${label}${import_picocolors35.default.dim(" [optional]")}: `);
113977
+ process.stdout.write(` ${label}${import_picocolors36.default.dim(" [optional]")}: `);
113619
113978
  stdin.setRawMode(true);
113620
113979
  stdin.resume();
113621
113980
  let value = "";
@@ -113732,15 +114091,15 @@ function describeProbe(p5) {
113732
114091
  return `${p5.keyCount} keys \xB7 ${p5.suggestedRoles.join("/")}${examples ? ` \xB7 ${examples}` : ""}`;
113733
114092
  }
113734
114093
  async function discoverAndSelectDbs(url, bullmqPrefix) {
113735
- console.log(import_picocolors35.default.dim("\n Scanning DBs 0-15 (read-only, sampled)\u2026"));
114094
+ console.log(import_picocolors36.default.dim("\n Scanning DBs 0-15 (read-only, sampled)\u2026"));
113736
114095
  const probes = await probeRedisDatabases(url, { bullmqPrefix });
113737
114096
  const nonEmpty = probes.filter((p5) => p5.reachable && p5.keyCount > 0);
113738
114097
  if (nonEmpty.length === 0) {
113739
- console.log(import_picocolors35.default.dim(" No populated DBs found."));
114098
+ console.log(import_picocolors36.default.dim(" No populated DBs found."));
113740
114099
  return [];
113741
114100
  }
113742
114101
  for (const p5 of nonEmpty) {
113743
- console.log(` ${import_picocolors35.default.bold(`DB ${p5.db}`)} ${import_picocolors35.default.dim("\xB7 " + describeProbe(p5))}`);
114102
+ console.log(` ${import_picocolors36.default.bold(`DB ${p5.db}`)} ${import_picocolors36.default.dim("\xB7 " + describeProbe(p5))}`);
113744
114103
  }
113745
114104
  const byLabel = /* @__PURE__ */ new Map();
113746
114105
  const choices = nonEmpty.map((p5) => {
@@ -113880,11 +114239,11 @@ function printSummary(type, opts) {
113880
114239
  } else if (opts.dashboard) {
113881
114240
  lines.push(` dashboard: ${opts.dashboard}`);
113882
114241
  }
113883
- if (lines.length > 0) console.log(import_picocolors35.default.dim(lines.join("\n")));
114242
+ if (lines.length > 0) console.log(import_picocolors36.default.dim(lines.join("\n")));
113884
114243
  }
113885
114244
  function isGitTracked(filePath, cwd) {
113886
114245
  try {
113887
- (0, import_node_child_process6.execFileSync)("git", ["ls-files", "--error-unmatch", filePath], {
114246
+ (0, import_node_child_process7.execFileSync)("git", ["ls-files", "--error-unmatch", filePath], {
113888
114247
  cwd,
113889
114248
  stdio: "pipe"
113890
114249
  });
@@ -113919,11 +114278,11 @@ async function askIndexSelection(indices) {
113919
114278
  const shown = indices.slice(0, MAX_DISPLAY);
113920
114279
  console.log("\n Available Elasticsearch indexes/data streams:");
113921
114280
  shown.forEach((name2, i3) => {
113922
- console.log(` ${import_picocolors35.default.dim(`[${i3 + 1}]`)} ${name2}`);
114281
+ console.log(` ${import_picocolors36.default.dim(`[${i3 + 1}]`)} ${name2}`);
113923
114282
  });
113924
114283
  if (indices.length > MAX_DISPLAY) {
113925
114284
  console.log(
113926
- import_picocolors35.default.dim(
114285
+ import_picocolors36.default.dim(
113927
114286
  ` \u2026 and ${indices.length - MAX_DISPLAY} more (type a pattern manually to match all)`
113928
114287
  )
113929
114288
  );
@@ -113967,11 +114326,11 @@ async function askDashboardSelection(dashboards) {
113967
114326
  const shown = dashboards.slice(0, MAX_DISPLAY);
113968
114327
  console.log("\n Available Grafana dashboards:");
113969
114328
  shown.forEach((d3, i3) => {
113970
- const folder = d3.folderTitle ? import_picocolors35.default.dim(` (${d3.folderTitle})`) : "";
113971
- console.log(` ${import_picocolors35.default.dim(`[${i3 + 1}]`)} ${d3.title}${folder}`);
114329
+ const folder = d3.folderTitle ? import_picocolors36.default.dim(` (${d3.folderTitle})`) : "";
114330
+ console.log(` ${import_picocolors36.default.dim(`[${i3 + 1}]`)} ${d3.title}${folder}`);
113972
114331
  });
113973
114332
  if (dashboards.length > MAX_DISPLAY) {
113974
- console.log(import_picocolors35.default.dim(` \u2026 and ${dashboards.length - MAX_DISPLAY} more`));
114333
+ console.log(import_picocolors36.default.dim(` \u2026 and ${dashboards.length - MAX_DISPLAY} more`));
113975
114334
  }
113976
114335
  const input = (await ask(
113977
114336
  ` Select dashboards to use (e.g. 1,2 or Enter to type uid manually)`,
@@ -114021,16 +114380,17 @@ function redactUrl(raw) {
114021
114380
 
114022
114381
  // ../../packages/cli/src/commands/stop.ts
114023
114382
  init_cjs_shims();
114024
- var import_node_child_process7 = require("child_process");
114025
- var import_node_fs16 = require("fs");
114026
- var import_node_util4 = require("util");
114027
- var import_node_path18 = require("path");
114028
- var import_picocolors36 = __toESM(require_picocolors(), 1);
114029
- var execFileAsync = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
114030
- var unlinkAsync = (0, import_node_util4.promisify)(import_node_fs16.unlink);
114383
+ var import_node_child_process8 = require("child_process");
114384
+ var import_node_fs17 = require("fs");
114385
+ var import_node_util5 = require("util");
114386
+ var import_node_path19 = require("path");
114387
+ var import_picocolors37 = __toESM(require_picocolors(), 1);
114388
+ var execFileAsync2 = (0, import_node_util5.promisify)(import_node_child_process8.execFile);
114389
+ var unlinkAsync = (0, import_node_util5.promisify)(import_node_fs17.unlink);
114031
114390
  var SPAWNED_HOST_FILE2 = "spawned-host.json";
114032
114391
  var START_TIME_TOLERANCE_S = 60;
114033
114392
  var STOP_WAIT_MS = 5e3;
114393
+ var STOP_KILL_WAIT_MS = 3e3;
114034
114394
  var STOP_POLL_MS = 200;
114035
114395
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
114036
114396
  async function runStop(opts) {
@@ -114042,19 +114402,19 @@ async function runStop(opts) {
114042
114402
  const root = findRepoRoot(cwd) ?? cwd;
114043
114403
  const hostUrl = readSourceHostUrl(root);
114044
114404
  if (!hostUrl) {
114045
- console.log(import_picocolors36.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
114405
+ console.log(import_picocolors37.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
114046
114406
  return 0;
114047
114407
  }
114048
114408
  return await stopHost(root, hostUrl);
114049
114409
  } catch (err2) {
114050
- console.error(import_picocolors36.default.red(err2.message));
114410
+ console.error(import_picocolors37.default.red(err2.message));
114051
114411
  return 1;
114052
114412
  }
114053
114413
  }
114054
114414
  async function stopHost(root, hostUrl) {
114055
114415
  const port = extractPort(hostUrl);
114056
114416
  if (port === null) {
114057
- console.error(import_picocolors36.default.red(`Cannot determine port from host URL: ${hostUrl}`));
114417
+ console.error(import_picocolors37.default.red(`Cannot determine port from host URL: ${hostUrl}`));
114058
114418
  return 1;
114059
114419
  }
114060
114420
  const healthy = await isHostHealthy(hostUrl);
@@ -114064,12 +114424,12 @@ async function stopHost(root, hostUrl) {
114064
114424
  if (!wrapperAlive) {
114065
114425
  const res = await stopBackendServerPid(root, port);
114066
114426
  if (res === "failed") return 1;
114067
- if (res !== "stopped") console.log(import_picocolors36.default.dim(`Host ${hostUrl} is already stopped.`));
114427
+ if (res !== "stopped") console.log(import_picocolors37.default.dim(`Host ${hostUrl} is already stopped.`));
114068
114428
  await cleanupSpawnedRecord(root);
114069
114429
  return 0;
114070
114430
  }
114071
114431
  console.log(
114072
- import_picocolors36.default.dim(
114432
+ import_picocolors37.default.dim(
114073
114433
  `Host ${hostUrl} is unreachable but pid ${owned.pid} is still running \u2014 terminating a stuck host.`
114074
114434
  )
114075
114435
  );
@@ -114077,7 +114437,7 @@ async function stopHost(root, hostUrl) {
114077
114437
  const spawned = readSpawnedHost(root);
114078
114438
  if (spawned === null) {
114079
114439
  console.error(
114080
- import_picocolors36.default.red(
114440
+ import_picocolors37.default.red(
114081
114441
  `No ownership record found (.horus/${SPAWNED_HOST_FILE2} absent). Horus will not stop a host it did not spawn.`
114082
114442
  )
114083
114443
  );
@@ -114085,12 +114445,12 @@ async function stopHost(root, hostUrl) {
114085
114445
  }
114086
114446
  const recordError = validateSpawnedRecord(spawned);
114087
114447
  if (recordError !== null) {
114088
- console.error(import_picocolors36.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
114448
+ console.error(import_picocolors37.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
114089
114449
  return 1;
114090
114450
  }
114091
114451
  if (spawned.port !== port) {
114092
114452
  console.error(
114093
- import_picocolors36.default.red(
114453
+ import_picocolors37.default.red(
114094
114454
  `Ownership record port (${spawned.port}) does not match host URL port (${port}). Record may be stale.`
114095
114455
  )
114096
114456
  );
@@ -114098,7 +114458,7 @@ async function stopHost(root, hostUrl) {
114098
114458
  }
114099
114459
  if (spawned.root !== root) {
114100
114460
  console.error(
114101
- import_picocolors36.default.red(
114461
+ import_picocolors37.default.red(
114102
114462
  `Ownership record root (${spawned.root}) does not match resolved root (${root}). Record may be stale.`
114103
114463
  )
114104
114464
  );
@@ -114109,14 +114469,14 @@ async function stopHost(root, hostUrl) {
114109
114469
  const res = await stopBackendServerPid(root, port);
114110
114470
  if (res === "failed") return 1;
114111
114471
  if (res !== "stopped") {
114112
- console.log(import_picocolors36.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
114472
+ console.log(import_picocolors37.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
114113
114473
  }
114114
114474
  await cleanupSpawnedRecord(root);
114115
114475
  return 0;
114116
114476
  }
114117
114477
  if (!hostArgvRegex(port).test(info2.args)) {
114118
114478
  console.error(
114119
- import_picocolors36.default.red(
114479
+ import_picocolors37.default.red(
114120
114480
  `Pid ${spawned.pid} args do not match "horus-source host --port ${port}". Got: "${info2.args.slice(0, 120)}". Aborting for safety.`
114121
114481
  )
114122
114482
  );
@@ -114125,51 +114485,33 @@ async function stopHost(root, hostUrl) {
114125
114485
  const startTs = new Date(spawned.startedAt).getTime();
114126
114486
  const recordedAgeS = Math.round((Date.now() - startTs) / 1e3);
114127
114487
  if (!Number.isFinite(info2.etimeSeconds)) {
114128
- console.error(import_picocolors36.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
114488
+ console.error(import_picocolors37.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
114129
114489
  return 1;
114130
114490
  }
114131
114491
  if (Math.abs(info2.etimeSeconds - recordedAgeS) > START_TIME_TOLERANCE_S) {
114132
114492
  console.error(
114133
- import_picocolors36.default.red(
114493
+ import_picocolors37.default.red(
114134
114494
  `Pid ${spawned.pid} age mismatch: record says ~${recordedAgeS}s, process reports ${info2.etimeSeconds}s elapsed. Possible PID reuse \u2014 aborting for safety.`
114135
114495
  )
114136
114496
  );
114137
114497
  return 1;
114138
114498
  }
114139
- let signaled = false;
114499
+ let terminated;
114140
114500
  try {
114141
- process.kill(spawned.pid, "SIGTERM");
114142
- signaled = true;
114501
+ terminated = await terminatePid(spawned.pid);
114143
114502
  } catch (err2) {
114144
- if (err2.code === "ESRCH") {
114145
- console.log(import_picocolors36.default.dim(`Process pid ${spawned.pid} exited before signal \u2014 already stopped.`));
114146
- } else {
114147
- console.error(import_picocolors36.default.red(`Failed to signal pid ${spawned.pid}: ${err2.message}`));
114148
- return 1;
114149
- }
114503
+ console.error(import_picocolors37.default.red(`Failed to signal pid ${spawned.pid}: ${err2.message}`));
114504
+ return 1;
114150
114505
  }
114151
- if (signaled) {
114152
- const deadline = Date.now() + STOP_WAIT_MS;
114153
- let exited = false;
114154
- while (Date.now() < deadline) {
114155
- await sleep(STOP_POLL_MS);
114156
- if (await getProcessInfo(spawned.pid) === null) {
114157
- exited = true;
114158
- break;
114159
- }
114160
- }
114161
- if (!exited) {
114162
- console.error(
114163
- import_picocolors36.default.red(
114164
- `Host pid ${spawned.pid} did not exit within ${STOP_WAIT_MS / 1e3}s after SIGTERM.`
114165
- )
114166
- );
114167
- return 1;
114168
- }
114169
- console.log(
114170
- `${import_picocolors36.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors36.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
114506
+ if (!terminated) {
114507
+ console.error(
114508
+ import_picocolors37.default.red(`Host pid ${spawned.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
114171
114509
  );
114510
+ return 1;
114172
114511
  }
114512
+ console.log(
114513
+ `${import_picocolors37.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors37.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
114514
+ );
114173
114515
  if (await stopBackendServerPid(root, port) === "failed") return 1;
114174
114516
  await cleanupSpawnedRecord(root);
114175
114517
  return 0;
@@ -114181,7 +114523,7 @@ function hostArgvRegex(port) {
114181
114523
  }
114182
114524
  async function cleanupSpawnedRecord(root) {
114183
114525
  try {
114184
- await unlinkAsync((0, import_node_path18.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
114526
+ await unlinkAsync((0, import_node_path19.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
114185
114527
  } catch {
114186
114528
  }
114187
114529
  }
@@ -114193,40 +114535,36 @@ async function stopBackendServerPid(root, port) {
114193
114535
  const info2 = await getProcessInfo(rec.pid);
114194
114536
  if (info2 === null) return "none";
114195
114537
  if (!hostArgvRegex(port).test(info2.args)) {
114196
- console.error(
114197
- import_picocolors36.default.red(
114198
- `Backend host pid ${rec.pid} args do not match "horus-source host --port ${port}". Not signalling \u2014 possible stale source/host.json or PID reuse.`
114538
+ console.log(
114539
+ import_picocolors37.default.dim(
114540
+ `Host pid ${rec.pid} is now an unrelated process (stale source/host.json / PID reuse) \u2014 host already gone.`
114199
114541
  )
114200
114542
  );
114201
- return "failed";
114543
+ return "none";
114202
114544
  }
114545
+ let terminated;
114203
114546
  try {
114204
- process.kill(rec.pid, "SIGTERM");
114547
+ terminated = await terminatePid(rec.pid);
114205
114548
  } catch (err2) {
114206
- if (err2.code === "ESRCH") return "stopped";
114207
- console.error(import_picocolors36.default.red(`Failed to signal pid ${rec.pid}: ${err2.message}`));
114549
+ console.error(import_picocolors37.default.red(`Failed to signal pid ${rec.pid}: ${err2.message}`));
114208
114550
  return "failed";
114209
114551
  }
114210
- const deadline = Date.now() + STOP_WAIT_MS;
114211
- while (Date.now() < deadline) {
114212
- await sleep(STOP_POLL_MS);
114213
- if (await getProcessInfo(rec.pid) === null) {
114214
- console.log(
114215
- `${import_picocolors36.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors36.default.dim(`(pid ${rec.pid}, port ${port})`) + ` for ${root}`
114216
- );
114217
- return "stopped";
114218
- }
114552
+ if (!terminated) {
114553
+ console.error(
114554
+ import_picocolors37.default.red(`Host pid ${rec.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
114555
+ );
114556
+ return "failed";
114219
114557
  }
114220
- console.error(
114221
- import_picocolors36.default.red(`Host pid ${rec.pid} did not exit within ${STOP_WAIT_MS / 1e3}s after SIGTERM.`)
114558
+ console.log(
114559
+ `${import_picocolors37.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors37.default.dim(`(pid ${rec.pid}, port ${port})`) + ` for ${root}`
114222
114560
  );
114223
- return "failed";
114561
+ return "stopped";
114224
114562
  }
114225
114563
  async function stopAll() {
114226
114564
  const registry2 = readRegistry();
114227
114565
  const projects2 = Object.entries(registry2.projects);
114228
114566
  if (projects2.length === 0) {
114229
- console.log(import_picocolors36.default.dim("No registered projects."));
114567
+ console.log(import_picocolors37.default.dim("No registered projects."));
114230
114568
  return 0;
114231
114569
  }
114232
114570
  let stopped = 0;
@@ -114238,17 +114576,17 @@ async function stopAll() {
114238
114576
  if (!healthy && readSpawnedHost(entry2.root) === null && readSourceHostPid(entry2.root) === null) {
114239
114577
  continue;
114240
114578
  }
114241
- console.log(` Stopping ${import_picocolors36.default.bold(name2)} ${import_picocolors36.default.dim(`(${hostUrl})`)}`);
114579
+ console.log(` Stopping ${import_picocolors37.default.bold(name2)} ${import_picocolors37.default.dim(`(${hostUrl})`)}`);
114242
114580
  const code = await stopHost(entry2.root, hostUrl);
114243
114581
  if (code === 0) stopped++;
114244
114582
  else failed++;
114245
114583
  }
114246
114584
  if (stopped === 0 && failed === 0) {
114247
- console.log(import_picocolors36.default.dim("No running source-intelligence hosts found."));
114585
+ console.log(import_picocolors37.default.dim("No running source-intelligence hosts found."));
114248
114586
  } else {
114249
114587
  console.log(
114250
114588
  `
114251
- Stopped ${stopped} host(s)${failed > 0 ? import_picocolors36.default.red(`, ${failed} failed`) : ""}.`
114589
+ Stopped ${stopped} host(s)${failed > 0 ? import_picocolors37.default.red(`, ${failed} failed`) : ""}.`
114252
114590
  );
114253
114591
  }
114254
114592
  return failed > 0 ? 1 : 0;
@@ -114275,10 +114613,30 @@ function validateSpawnedRecord(r) {
114275
114613
  }
114276
114614
  return null;
114277
114615
  }
114616
+ async function terminatePid(pid) {
114617
+ const escalation = [
114618
+ { signal: "SIGTERM", waitMs: STOP_WAIT_MS },
114619
+ { signal: "SIGKILL", waitMs: STOP_KILL_WAIT_MS }
114620
+ ];
114621
+ for (const { signal, waitMs } of escalation) {
114622
+ try {
114623
+ process.kill(pid, signal);
114624
+ } catch (err2) {
114625
+ if (err2.code === "ESRCH") return true;
114626
+ throw err2;
114627
+ }
114628
+ const deadline = Date.now() + waitMs;
114629
+ while (Date.now() < deadline) {
114630
+ await sleep(STOP_POLL_MS);
114631
+ if (await getProcessInfo(pid) === null) return true;
114632
+ }
114633
+ }
114634
+ return await getProcessInfo(pid) === null;
114635
+ }
114278
114636
  async function getProcessInfo(pid) {
114279
114637
  let args2;
114280
114638
  try {
114281
- const argsResult = await execFileAsync("ps", ["-p", String(pid), "-o", "args="], {
114639
+ const argsResult = await execFileAsync2("ps", ["-p", String(pid), "-o", "args="], {
114282
114640
  timeout: 3e3
114283
114641
  });
114284
114642
  args2 = argsResult.stdout.trim();
@@ -114288,7 +114646,7 @@ async function getProcessInfo(pid) {
114288
114646
  if (!args2) return null;
114289
114647
  let etimeSeconds = Number.NaN;
114290
114648
  try {
114291
- const etimeResult = await execFileAsync("ps", ["-p", String(pid), "-o", "etime="], {
114649
+ const etimeResult = await execFileAsync2("ps", ["-p", String(pid), "-o", "etime="], {
114292
114650
  timeout: 3e3
114293
114651
  });
114294
114652
  etimeSeconds = parseEtimeSeconds(etimeResult.stdout.trim());
@@ -114316,14 +114674,77 @@ function extractPort(hostUrl) {
114316
114674
 
114317
114675
  // ../../packages/cli/src/commands/hosts.ts
114318
114676
  init_cjs_shims();
114319
- var import_picocolors37 = __toESM(require_picocolors(), 1);
114320
- async function runHosts() {
114677
+ var import_picocolors38 = __toESM(require_picocolors(), 1);
114678
+
114679
+ // ../../packages/cli/src/lib/host-reaper.ts
114680
+ init_cjs_shims();
114681
+ var import_node_child_process9 = require("child_process");
114682
+ var import_node_util6 = require("util");
114683
+ var execFileAsync3 = (0, import_node_util6.promisify)(import_node_child_process9.execFile);
114684
+ var HOST_ARGV = /(?:^|\s)(?:\S*\/)?horus-source\s+host\s+--port(?:=|\s+)(\d+)(?=\s|$)/;
114685
+ function parseSourceHosts(psStdout) {
114686
+ const hosts = [];
114687
+ for (const line2 of psStdout.split("\n")) {
114688
+ const trimmed = line2.trim();
114689
+ if (!trimmed) continue;
114690
+ const sp = trimmed.indexOf(" ");
114691
+ if (sp < 0) continue;
114692
+ const pid = Number(trimmed.slice(0, sp));
114693
+ if (!Number.isInteger(pid) || pid <= 0) continue;
114694
+ const m5 = HOST_ARGV.exec(trimmed.slice(sp + 1));
114695
+ if (!m5) continue;
114696
+ hosts.push({ pid, port: Number(m5[1]) });
114697
+ }
114698
+ return hosts;
114699
+ }
114700
+ function selectOrphans(running, claimedPids) {
114701
+ return running.filter((h3) => !claimedPids.has(h3.pid));
114702
+ }
114703
+ async function listRunningSourceHosts() {
114704
+ try {
114705
+ const { stdout } = await execFileAsync3("ps", ["-axww", "-o", "pid=,args="], {
114706
+ maxBuffer: 8 * 1024 * 1024,
114707
+ timeout: 5e3
114708
+ });
114709
+ return parseSourceHosts(stdout);
114710
+ } catch {
114711
+ return [];
114712
+ }
114713
+ }
114714
+ function isAlive(pid) {
114715
+ try {
114716
+ process.kill(pid, 0);
114717
+ return true;
114718
+ } catch (err2) {
114719
+ return err2.code === "EPERM";
114720
+ }
114721
+ }
114722
+ async function reapPid(pid, opts = {}) {
114723
+ const termMs = opts.termMs ?? 4e3;
114724
+ const killMs = opts.killMs ?? 3e3;
114725
+ const pollMs = opts.pollMs ?? 200;
114726
+ for (const [signal, wait] of [
114727
+ ["SIGTERM", termMs],
114728
+ ["SIGKILL", killMs]
114729
+ ]) {
114730
+ try {
114731
+ process.kill(pid, signal);
114732
+ } catch (err2) {
114733
+ if (err2.code === "ESRCH") return true;
114734
+ }
114735
+ const deadline = Date.now() + wait;
114736
+ while (Date.now() < deadline) {
114737
+ await new Promise((r) => setTimeout(r, pollMs));
114738
+ if (!isAlive(pid)) return true;
114739
+ }
114740
+ }
114741
+ return !isAlive(pid);
114742
+ }
114743
+
114744
+ // ../../packages/cli/src/commands/hosts.ts
114745
+ async function runHosts(opts = {}) {
114321
114746
  const registry2 = readRegistry();
114322
114747
  const projects2 = Object.entries(registry2.projects);
114323
- if (projects2.length === 0) {
114324
- console.log(import_picocolors37.default.dim("No registered projects. Run `horus index` in a repo first."));
114325
- return 0;
114326
- }
114327
114748
  const rows = [];
114328
114749
  await Promise.all(
114329
114750
  projects2.map(async ([name2, entry2]) => {
@@ -114332,39 +114753,69 @@ async function runHosts() {
114332
114753
  rows.push({ name: name2, hostUrl: hostUrl ?? null, healthy, root: entry2.root });
114333
114754
  })
114334
114755
  );
114335
- rows.sort((a2, b5) => {
114336
- if (a2.healthy !== b5.healthy) return a2.healthy ? -1 : 1;
114337
- return a2.name.localeCompare(b5.name);
114338
- });
114339
- const anyHost = rows.some((r) => r.hostUrl !== null);
114340
- if (!anyHost) {
114341
- console.log(import_picocolors37.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
114342
- return 0;
114343
- }
114756
+ rows.sort(
114757
+ (a2, b5) => a2.healthy !== b5.healthy ? a2.healthy ? -1 : 1 : a2.name.localeCompare(b5.name)
114758
+ );
114344
114759
  console.log("");
114760
+ let printedAny = false;
114345
114761
  for (const row of rows) {
114346
114762
  if (row.hostUrl === null) continue;
114347
- const status = row.healthy ? import_picocolors37.default.green("\u25CF running") : import_picocolors37.default.red("\u25CF stopped");
114763
+ printedAny = true;
114764
+ const status = row.healthy ? import_picocolors38.default.green("\u25CF running") : import_picocolors38.default.red("\u25CF stopped");
114348
114765
  const port = extractPort2(row.hostUrl) ?? "?";
114349
114766
  console.log(
114350
- ` ${status} ${import_picocolors37.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors37.default.dim(row.root)}`
114767
+ ` ${status} ${import_picocolors38.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors38.default.dim(row.root)}`
114351
114768
  );
114352
114769
  }
114353
- console.log("");
114354
114770
  const noHost = rows.filter((r) => r.hostUrl === null);
114355
- if (noHost.length > 0) {
114356
- for (const row of noHost) {
114357
- console.log(` ${import_picocolors37.default.dim("\u25CB no host")} ${import_picocolors37.default.dim(row.name)}`);
114771
+ for (const row of noHost) console.log(` ${import_picocolors38.default.dim("\u25CB no host")} ${import_picocolors38.default.dim(row.name)}`);
114772
+ if (printedAny || noHost.length > 0) console.log("");
114773
+ const claimedPids = /* @__PURE__ */ new Set();
114774
+ for (const [, entry2] of projects2) {
114775
+ const hp = readSourceHostPid(entry2.root);
114776
+ if (hp?.pid) claimedPids.add(hp.pid);
114777
+ const sp = readSpawnedHost(entry2.root);
114778
+ if (sp?.pid) claimedPids.add(sp.pid);
114779
+ }
114780
+ const orphans = selectOrphans(await listRunningSourceHosts(), claimedPids);
114781
+ let reapFailed = 0;
114782
+ if (orphans.length > 0) {
114783
+ console.log(
114784
+ import_picocolors38.default.yellow(` \u26A0 ${orphans.length} orphaned source host(s) \u2014 no registered repo owns them:`)
114785
+ );
114786
+ for (const o5 of orphans) console.log(import_picocolors38.default.dim(` pid ${o5.pid} port ${o5.port}`));
114787
+ if (opts.reap) {
114788
+ let reaped = 0;
114789
+ for (const o5 of orphans) {
114790
+ if (await reapPid(o5.pid)) {
114791
+ reaped++;
114792
+ console.log(` ${import_picocolors38.default.green("\u2713")} reaped pid ${o5.pid} ${import_picocolors38.default.dim(`(port ${o5.port})`)}`);
114793
+ } else {
114794
+ reapFailed++;
114795
+ console.log(import_picocolors38.default.red(` \u2717 could not stop pid ${o5.pid} (port ${o5.port})`));
114796
+ }
114797
+ }
114798
+ console.log(import_picocolors38.default.dim(` Reaped ${reaped}/${orphans.length} orphan(s).`));
114799
+ } else {
114800
+ console.log(import_picocolors38.default.dim(" Run `horus hosts --reap` to stop them."));
114358
114801
  }
114359
114802
  console.log("");
114360
114803
  }
114804
+ if (projects2.length === 0 && orphans.length === 0) {
114805
+ console.log(import_picocolors38.default.dim("No registered projects. Run `horus index` in a repo first."));
114806
+ return 0;
114807
+ }
114808
+ if (!printedAny && orphans.length === 0) {
114809
+ console.log(import_picocolors38.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
114810
+ return 0;
114811
+ }
114361
114812
  const running = rows.filter((r) => r.healthy).length;
114362
114813
  console.log(
114363
- import_picocolors37.default.dim(
114364
- `${running} running \xB7 horus stop to reap \xB7 horus stop --all to stop everything`
114814
+ import_picocolors38.default.dim(
114815
+ `${running} running${orphans.length ? ` \xB7 ${orphans.length} orphan(s)` : ""} \xB7 horus hosts --reap to clear orphans \xB7 horus stop --all to stop everything`
114365
114816
  )
114366
114817
  );
114367
- return 0;
114818
+ return reapFailed > 0 ? 1 : 0;
114368
114819
  }
114369
114820
  function extractPort2(hostUrl) {
114370
114821
  try {
@@ -114377,12 +114828,12 @@ function extractPort2(hostUrl) {
114377
114828
 
114378
114829
  // ../../packages/cli/src/commands/doctor.ts
114379
114830
  init_cjs_shims();
114380
- var import_picocolors38 = __toESM(require_picocolors(), 1);
114831
+ var import_picocolors39 = __toESM(require_picocolors(), 1);
114381
114832
  var DEFAULT_DB_URL4 = "postgresql://horus:horus@localhost:5433/horus";
114382
114833
  function mark2(status) {
114383
- if (status === "pass") return import_picocolors38.default.green("\u2713");
114384
- if (status === "warn") return import_picocolors38.default.yellow("~");
114385
- return import_picocolors38.default.red("\u2717");
114834
+ if (status === "pass") return import_picocolors39.default.green("\u2713");
114835
+ if (status === "warn") return import_picocolors39.default.yellow("~");
114836
+ return import_picocolors39.default.red("\u2717");
114386
114837
  }
114387
114838
  async function runDoctor(opts) {
114388
114839
  const cwd = opts?.cwd ?? process.cwd();
@@ -114662,11 +115113,11 @@ async function runDoctor(opts) {
114662
115113
  write(JSON.stringify(output, null, 2));
114663
115114
  return hasFailure ? 1 : 0;
114664
115115
  }
114665
- write(import_picocolors38.default.bold("\nHorus readiness check\n"));
115116
+ write(import_picocolors39.default.bold("\nHorus readiness check\n"));
114666
115117
  for (const check2 of checks) {
114667
- write(` ${mark2(check2.status)} ${import_picocolors38.default.bold(check2.label.padEnd(26))} ${import_picocolors38.default.dim(check2.detail)}`);
115118
+ write(` ${mark2(check2.status)} ${import_picocolors39.default.bold(check2.label.padEnd(26))} ${import_picocolors39.default.dim(check2.detail)}`);
114668
115119
  if (check2.next) {
114669
- write(` ${import_picocolors38.default.dim("\u2192 " + check2.next)}`);
115120
+ write(` ${import_picocolors39.default.dim("\u2192 " + check2.next)}`);
114670
115121
  }
114671
115122
  }
114672
115123
  write("");
@@ -114675,20 +115126,20 @@ async function runDoctor(opts) {
114675
115126
 
114676
115127
  // ../../packages/cli/src/commands/providers-doctor.ts
114677
115128
  init_cjs_shims();
114678
- var import_node_child_process8 = require("child_process");
114679
- var import_picocolors39 = __toESM(require_picocolors(), 1);
115129
+ var import_node_child_process10 = require("child_process");
115130
+ var import_picocolors40 = __toESM(require_picocolors(), 1);
114680
115131
  function statusMark(status) {
114681
- if (status === "ready") return import_picocolors39.default.green("\u2713");
114682
- if (status === "installed") return import_picocolors39.default.yellow("~");
114683
- return import_picocolors39.default.red("\u2717");
115132
+ if (status === "ready") return import_picocolors40.default.green("\u2713");
115133
+ if (status === "installed") return import_picocolors40.default.yellow("~");
115134
+ return import_picocolors40.default.red("\u2717");
114684
115135
  }
114685
115136
  function statusLabel(status) {
114686
- if (status === "ready") return import_picocolors39.default.green("ready");
114687
- if (status === "installed") return import_picocolors39.default.yellow("installed (not configured)");
114688
- return import_picocolors39.default.dim("not found on PATH");
115137
+ if (status === "ready") return import_picocolors40.default.green("ready");
115138
+ if (status === "installed") return import_picocolors40.default.yellow("installed (not configured)");
115139
+ return import_picocolors40.default.dim("not found on PATH");
114689
115140
  }
114690
115141
  function detectBinary(id) {
114691
- const result = (0, import_node_child_process8.spawnSync)(id, ["--version"], { stdio: "pipe", timeout: 2e3 });
115142
+ const result = (0, import_node_child_process10.spawnSync)(id, ["--version"], { stdio: "pipe", timeout: 2e3 });
114692
115143
  if (result.error) {
114693
115144
  return { id, status: "unavailable", detail: `${id}: command not found` };
114694
115145
  }
@@ -114702,7 +115153,7 @@ async function runProvidersDoctorCommand(opts) {
114702
115153
  const registry2 = opts?.registry ?? DEFAULT_LOCAL_PROVIDER_REGISTRY;
114703
115154
  const write = opts?.write ?? ((line2) => console.log(line2));
114704
115155
  const results = buildProviderResults(registry2, opts?._detect);
114705
- write(import_picocolors39.default.bold("\nLocal AI providers\n"));
115156
+ write(import_picocolors40.default.bold("\nLocal AI providers\n"));
114706
115157
  for (const result of results) {
114707
115158
  const descriptor = registry2.get(result.id);
114708
115159
  const name2 = descriptor?.displayName ?? result.id;
@@ -114710,11 +115161,11 @@ async function runProvidersDoctorCommand(opts) {
114710
115161
  ` ${statusMark(result.status)} ${result.id.padEnd(8)} ${name2.padEnd(22)} ${statusLabel(result.status)}`
114711
115162
  );
114712
115163
  if (result.status !== "ready" && result.detail) {
114713
- write(` ${import_picocolors39.default.dim("\u2192 " + result.detail)}`);
115164
+ write(` ${import_picocolors40.default.dim("\u2192 " + result.detail)}`);
114714
115165
  }
114715
115166
  }
114716
115167
  write("");
114717
- write(import_picocolors39.default.bold("Cloud AI providers\n"));
115168
+ write(import_picocolors40.default.bold("Cloud AI providers\n"));
114718
115169
  let source = null;
114719
115170
  if (opts?._anthropicKey !== void 0) {
114720
115171
  source = opts._anthropicKey ? "env" : null;
@@ -114729,18 +115180,18 @@ async function runProvidersDoctorCommand(opts) {
114729
115180
  }
114730
115181
  if (source === "config") {
114731
115182
  write(
114732
- ` ${import_picocolors39.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors39.default.green("configured (local .horus config)")}`
115183
+ ` ${import_picocolors40.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors40.default.green("configured (local .horus config)")}`
114733
115184
  );
114734
115185
  } else if (source === "env") {
114735
115186
  write(
114736
- ` ${import_picocolors39.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors39.default.green("configured (ANTHROPIC_API_KEY env)")}`
115187
+ ` ${import_picocolors40.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors40.default.green("configured (ANTHROPIC_API_KEY env)")}`
114737
115188
  );
114738
115189
  } else {
114739
115190
  write(
114740
- ` ${import_picocolors39.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors39.default.dim("not configured")}`
115191
+ ` ${import_picocolors40.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors40.default.dim("not configured")}`
114741
115192
  );
114742
115193
  write(
114743
- ` ${import_picocolors39.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
115194
+ ` ${import_picocolors40.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
114744
115195
  );
114745
115196
  }
114746
115197
  write("");
@@ -114749,9 +115200,9 @@ async function runProvidersDoctorCommand(opts) {
114749
115200
 
114750
115201
  // ../../packages/cli/src/commands/generate-config.ts
114751
115202
  init_cjs_shims();
114752
- var import_node_fs17 = require("fs");
114753
- var import_node_path19 = require("path");
114754
- var import_picocolors40 = __toESM(require_picocolors(), 1);
115203
+ var import_node_fs18 = require("fs");
115204
+ var import_node_path20 = require("path");
115205
+ var import_picocolors41 = __toESM(require_picocolors(), 1);
114755
115206
  function configTemplate(name2, repoPath) {
114756
115207
  return `export default {
114757
115208
  database: {
@@ -114799,39 +115250,39 @@ async function runGenerateConfig(opts) {
114799
115250
  const defaults2 = localConfigPath2 != null ? projectDefaults(localConfigPath2) : null;
114800
115251
  const hasLocalConfig = defaults2 != null;
114801
115252
  const defaultOut = hasLocalConfig ? "horus.config.example.js" : "horus.config.js";
114802
- const outPath = (0, import_node_path19.resolve)(cwd, opts.out ?? defaultOut);
115253
+ const outPath = (0, import_node_path20.resolve)(cwd, opts.out ?? defaultOut);
114803
115254
  const name2 = opts.name ?? defaults2?.name ?? "my-project";
114804
115255
  const repoPath = opts.repo ?? defaults2?.repoPath ?? `/path/to/${name2}`;
114805
- if ((0, import_node_fs17.existsSync)(outPath) && !opts.force) {
114806
- log(`${import_picocolors40.default.red("\u2717")} ${outPath} already exists`);
114807
- log(import_picocolors40.default.dim(" pass --force to overwrite"));
115256
+ if ((0, import_node_fs18.existsSync)(outPath) && !opts.force) {
115257
+ log(`${import_picocolors41.default.red("\u2717")} ${outPath} already exists`);
115258
+ log(import_picocolors41.default.dim(" pass --force to overwrite"));
114808
115259
  return 1;
114809
115260
  }
114810
115261
  try {
114811
- (0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(outPath), { recursive: true });
114812
- (0, import_node_fs17.writeFileSync)(outPath, configTemplate(name2, repoPath), "utf8");
115262
+ (0, import_node_fs18.mkdirSync)((0, import_node_path20.dirname)(outPath), { recursive: true });
115263
+ (0, import_node_fs18.writeFileSync)(outPath, configTemplate(name2, repoPath), "utf8");
114813
115264
  } catch (err2) {
114814
- log(`${import_picocolors40.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
115265
+ log(`${import_picocolors41.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
114815
115266
  return 1;
114816
115267
  }
114817
- log(`${import_picocolors40.default.green("\u2713")} Created ${outPath}`);
114818
- log(import_picocolors40.default.dim(` project: ${name2}`));
114819
- log(import_picocolors40.default.dim(` repo: ${repoPath}`));
115268
+ log(`${import_picocolors41.default.green("\u2713")} Created ${outPath}`);
115269
+ log(import_picocolors41.default.dim(` project: ${name2}`));
115270
+ log(import_picocolors41.default.dim(` repo: ${repoPath}`));
114820
115271
  if (hasLocalConfig && localConfigPath2 != null) {
114821
115272
  log("");
114822
- log(import_picocolors40.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
115273
+ log(import_picocolors41.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
114823
115274
  log(" \u2022 .horus/config.json \u2014 project config used by `horus investigate` from this repo");
114824
115275
  log(" \u2022 horus.config.js \u2014 standalone/global config used with `horus doctor --config <path>`");
114825
- log(import_picocolors40.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
115276
+ log(import_picocolors41.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
114826
115277
  } else {
114827
- log(import_picocolors40.default.dim(` next: horus doctor --config ${outPath}`));
115278
+ log(import_picocolors41.default.dim(` next: horus doctor --config ${outPath}`));
114828
115279
  }
114829
115280
  return 0;
114830
115281
  }
114831
115282
 
114832
115283
  // ../../packages/cli/src/commands/readiness.ts
114833
115284
  init_cjs_shims();
114834
- var import_picocolors41 = __toESM(require_picocolors(), 1);
115285
+ var import_picocolors42 = __toESM(require_picocolors(), 1);
114835
115286
  var READINESS_AI_CONTRACT = `Provide a clearly separated AI readiness summary with:
114836
115287
 
114837
115288
  Overall assessment
@@ -114854,9 +115305,9 @@ Confidence / gaps
114854
115305
  - Which checks Horus could verify vs. which require manual confirmation`;
114855
115306
  var DEFAULT_DB_URL5 = "postgresql://horus:horus@localhost:5433/horus";
114856
115307
  function mark3(status) {
114857
- if (status === "pass") return import_picocolors41.default.green("\u2713");
114858
- if (status === "warn") return import_picocolors41.default.yellow("~");
114859
- return import_picocolors41.default.red("\u2717");
115308
+ if (status === "pass") return import_picocolors42.default.green("\u2713");
115309
+ if (status === "warn") return import_picocolors42.default.yellow("~");
115310
+ return import_picocolors42.default.red("\u2717");
114860
115311
  }
114861
115312
  async function runReadiness(opts) {
114862
115313
  const cwd = opts?.cwd ?? process.cwd();
@@ -115033,20 +115484,20 @@ async function runReadiness(opts) {
115033
115484
  }
115034
115485
  const blockingChecks = checks.filter((c4) => c4.blocking);
115035
115486
  const optionalChecks = checks.filter((c4) => !c4.blocking);
115036
- write(import_picocolors41.default.bold("\nHorus release readiness\n"));
115037
- write(import_picocolors41.default.bold(" Blocking"));
115487
+ write(import_picocolors42.default.bold("\nHorus release readiness\n"));
115488
+ write(import_picocolors42.default.bold(" Blocking"));
115038
115489
  for (const check2 of blockingChecks) {
115039
- write(` ${mark3(check2.status)} ${import_picocolors41.default.bold(check2.label.padEnd(22))} ${import_picocolors41.default.dim(check2.detail)}`);
115490
+ write(` ${mark3(check2.status)} ${import_picocolors42.default.bold(check2.label.padEnd(22))} ${import_picocolors42.default.dim(check2.detail)}`);
115040
115491
  if (check2.next) {
115041
- write(` ${import_picocolors41.default.dim("\u2192 " + check2.next)}`);
115492
+ write(` ${import_picocolors42.default.dim("\u2192 " + check2.next)}`);
115042
115493
  }
115043
115494
  }
115044
115495
  write("");
115045
- write(import_picocolors41.default.bold(" Optional"));
115496
+ write(import_picocolors42.default.bold(" Optional"));
115046
115497
  for (const check2 of optionalChecks) {
115047
- write(` ${mark3(check2.status)} ${import_picocolors41.default.bold(check2.label.padEnd(22))} ${import_picocolors41.default.dim(check2.detail)}`);
115498
+ write(` ${mark3(check2.status)} ${import_picocolors42.default.bold(check2.label.padEnd(22))} ${import_picocolors42.default.dim(check2.detail)}`);
115048
115499
  if (check2.next) {
115049
- write(` ${import_picocolors41.default.dim("\u2192 " + check2.next)}`);
115500
+ write(` ${import_picocolors42.default.dim("\u2192 " + check2.next)}`);
115050
115501
  }
115051
115502
  }
115052
115503
  write("");
@@ -115054,21 +115505,21 @@ async function runReadiness(opts) {
115054
115505
  const optionalWarns = optionalChecks.filter((c4) => c4.status === "warn").length;
115055
115506
  if (blockingFails.length === 0) {
115056
115507
  if (optionalWarns === 0) {
115057
- write(import_picocolors41.default.green(" Ready for demo/release."));
115508
+ write(import_picocolors42.default.green(" Ready for demo/release."));
115058
115509
  } else {
115059
115510
  write(
115060
- import_picocolors41.default.yellow(
115511
+ import_picocolors42.default.yellow(
115061
115512
  ` Ready for a basic demo. ${optionalWarns} optional item(s) not configured \u2014 investigation evidence will be limited.`
115062
115513
  )
115063
115514
  );
115064
115515
  }
115065
115516
  } else {
115066
115517
  write(
115067
- import_picocolors41.default.red(
115518
+ import_picocolors42.default.red(
115068
115519
  ` Not ready. ${blockingFails.length} blocking item(s) must be resolved before demo/release.`
115069
115520
  )
115070
115521
  );
115071
- write(import_picocolors41.default.dim(" Re-run `horus readiness` after resolving the items above."));
115522
+ write(import_picocolors42.default.dim(" Re-run `horus readiness` after resolving the items above."));
115072
115523
  }
115073
115524
  write("");
115074
115525
  if (opts?.ai) {
@@ -115083,7 +115534,7 @@ async function runReadiness(opts) {
115083
115534
  });
115084
115535
  console.log("\n" + renderInterpretation(result));
115085
115536
  if (!result.ok) {
115086
- console.error(import_picocolors41.default.yellow(`[ai] ${result.warning}`));
115537
+ console.error(import_picocolors42.default.yellow(`[ai] ${result.warning}`));
115087
115538
  }
115088
115539
  }
115089
115540
  return blockingFails.length > 0 ? 1 : 0;
@@ -115091,33 +115542,33 @@ async function runReadiness(opts) {
115091
115542
 
115092
115543
  // ../../packages/cli/src/commands/skill.ts
115093
115544
  init_cjs_shims();
115094
- var import_node_fs18 = require("fs");
115095
- var import_node_path20 = require("path");
115545
+ var import_node_fs19 = require("fs");
115546
+ var import_node_path21 = require("path");
115096
115547
  var import_node_os5 = require("os");
115097
115548
  var import_promises2 = require("readline/promises");
115098
- var import_picocolors42 = __toESM(require_picocolors(), 1);
115549
+ var import_picocolors43 = __toESM(require_picocolors(), 1);
115099
115550
  var SUPPORTED_TARGETS = ["claude", "codex", "gemini", "cursor", "generic"];
115100
115551
  function isValidTarget(target) {
115101
115552
  return SUPPORTED_TARGETS.includes(target);
115102
115553
  }
115103
115554
  function getLegacyClaudeSkillPath(opts) {
115104
115555
  const base2 = opts.global ? (0, import_node_os5.homedir)() : opts.cwd ?? process.cwd();
115105
- return (0, import_node_path20.join)(base2, ".claude", "skills", "horus.md");
115556
+ return (0, import_node_path21.join)(base2, ".claude", "skills", "horus.md");
115106
115557
  }
115107
115558
  function getSkillInstallPath(target, opts) {
115108
115559
  const base2 = opts.global ? (0, import_node_os5.homedir)() : opts.cwd ?? process.cwd();
115109
115560
  switch (target) {
115110
115561
  case "claude":
115111
- return (0, import_node_path20.join)(base2, ".claude", "skills", "horus", "SKILL.md");
115562
+ return (0, import_node_path21.join)(base2, ".claude", "skills", "horus", "SKILL.md");
115112
115563
  case "gemini":
115113
- return opts.global ? (0, import_node_path20.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path20.join)(base2, "GEMINI.md");
115564
+ return opts.global ? (0, import_node_path21.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path21.join)(base2, "GEMINI.md");
115114
115565
  case "cursor":
115115
- return opts.global ? (0, import_node_path20.join)(base2, ".cursorrules") : (0, import_node_path20.join)(base2, ".cursor", "rules", "horus.mdc");
115566
+ return opts.global ? (0, import_node_path21.join)(base2, ".cursorrules") : (0, import_node_path21.join)(base2, ".cursor", "rules", "horus.mdc");
115116
115567
  case "codex":
115117
- return opts.global ? (0, import_node_path20.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path20.join)(base2, "AGENTS.md");
115568
+ return opts.global ? (0, import_node_path21.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path21.join)(base2, "AGENTS.md");
115118
115569
  case "generic":
115119
115570
  default:
115120
- return (0, import_node_path20.join)(base2, ".horus", "skills", `horus-${target}.md`);
115571
+ return (0, import_node_path21.join)(base2, ".horus", "skills", `horus-${target}.md`);
115121
115572
  }
115122
115573
  }
115123
115574
  var BASE_SKILL = `# Horus Grounded Investigation Skill
@@ -115434,66 +115885,66 @@ async function confirm(message) {
115434
115885
  async function runSkillInstall(target, opts) {
115435
115886
  const log = opts.write ?? ((line2) => console.log(line2));
115436
115887
  if (!isValidTarget(target)) {
115437
- log(`${import_picocolors42.default.red("\u2717")} Unknown target: ${import_picocolors42.default.bold(target)}`);
115438
- log(import_picocolors42.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
115888
+ log(`${import_picocolors43.default.red("\u2717")} Unknown target: ${import_picocolors43.default.bold(target)}`);
115889
+ log(import_picocolors43.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
115439
115890
  return 1;
115440
115891
  }
115441
115892
  const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
115442
115893
  const content = generateSkillContent(target);
115443
115894
  if (target === "claude") {
115444
115895
  const legacyPath = getLegacyClaudeSkillPath({ global: opts.global, cwd: opts.cwd });
115445
- if ((0, import_node_fs18.existsSync)(legacyPath)) {
115896
+ if ((0, import_node_fs19.existsSync)(legacyPath)) {
115446
115897
  if (!opts.force) {
115447
115898
  const confirmed = await (opts.confirm ?? confirm)(
115448
115899
  `Found old flat skill file at ${legacyPath}. Replace it with the new directory layout?`
115449
115900
  );
115450
115901
  if (!confirmed) {
115451
- log(`${import_picocolors42.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
115452
- log(import_picocolors42.default.dim(" Pass --force to replace without prompting."));
115902
+ log(`${import_picocolors43.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
115903
+ log(import_picocolors43.default.dim(" Pass --force to replace without prompting."));
115453
115904
  return 1;
115454
115905
  }
115455
115906
  }
115456
115907
  try {
115457
- (0, import_node_fs18.rmSync)(legacyPath);
115458
- log(`${import_picocolors42.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
115908
+ (0, import_node_fs19.rmSync)(legacyPath);
115909
+ log(`${import_picocolors43.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
115459
115910
  } catch (err2) {
115460
- log(`${import_picocolors42.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err2.message}`);
115911
+ log(`${import_picocolors43.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err2.message}`);
115461
115912
  return 1;
115462
115913
  }
115463
115914
  }
115464
115915
  }
115465
- if ((0, import_node_fs18.existsSync)(outPath) && !opts.force) {
115466
- log(`${import_picocolors42.default.red("\u2717")} ${outPath} already exists`);
115467
- log(import_picocolors42.default.dim(" pass --force to overwrite"));
115916
+ if ((0, import_node_fs19.existsSync)(outPath) && !opts.force) {
115917
+ log(`${import_picocolors43.default.red("\u2717")} ${outPath} already exists`);
115918
+ log(import_picocolors43.default.dim(" pass --force to overwrite"));
115468
115919
  return 1;
115469
115920
  }
115470
115921
  try {
115471
- (0, import_node_fs18.mkdirSync)((0, import_node_path20.dirname)(outPath), { recursive: true });
115472
- (0, import_node_fs18.writeFileSync)(outPath, content, "utf8");
115922
+ (0, import_node_fs19.mkdirSync)((0, import_node_path21.dirname)(outPath), { recursive: true });
115923
+ (0, import_node_fs19.writeFileSync)(outPath, content, "utf8");
115473
115924
  } catch (err2) {
115474
- log(`${import_picocolors42.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
115925
+ log(`${import_picocolors43.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
115475
115926
  return 1;
115476
115927
  }
115477
- log(`${import_picocolors42.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
115928
+ log(`${import_picocolors43.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
115478
115929
  if (target === "claude") {
115479
- log(import_picocolors42.default.dim(" Claude Code will load this skill automatically."));
115480
- log(import_picocolors42.default.dim(" Invoke it with: /horus"));
115930
+ log(import_picocolors43.default.dim(" Claude Code will load this skill automatically."));
115931
+ log(import_picocolors43.default.dim(" Invoke it with: /horus"));
115481
115932
  } else if (target === "gemini") {
115482
- log(import_picocolors42.default.dim(" Gemini CLI will load this context file automatically."));
115933
+ log(import_picocolors43.default.dim(" Gemini CLI will load this context file automatically."));
115483
115934
  } else if (target === "cursor") {
115484
- log(import_picocolors42.default.dim(" Cursor will load this rule automatically."));
115935
+ log(import_picocolors43.default.dim(" Cursor will load this rule automatically."));
115485
115936
  } else if (target === "codex") {
115486
- log(import_picocolors42.default.dim(" Codex CLI will load this file automatically."));
115937
+ log(import_picocolors43.default.dim(" Codex CLI will load this file automatically."));
115487
115938
  } else {
115488
- log(import_picocolors42.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
115939
+ log(import_picocolors43.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
115489
115940
  }
115490
115941
  return 0;
115491
115942
  }
115492
115943
  async function runSkillPrint(target, opts) {
115493
115944
  const log = opts.write ?? ((line2) => console.log(line2));
115494
115945
  if (!isValidTarget(target)) {
115495
- log(`${import_picocolors42.default.red("\u2717")} Unknown target: ${import_picocolors42.default.bold(target)}`);
115496
- log(import_picocolors42.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
115946
+ log(`${import_picocolors43.default.red("\u2717")} Unknown target: ${import_picocolors43.default.bold(target)}`);
115947
+ log(import_picocolors43.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
115497
115948
  return 1;
115498
115949
  }
115499
115950
  process.stdout.write(generateSkillContent(target));
@@ -115502,8 +115953,8 @@ async function runSkillPrint(target, opts) {
115502
115953
  async function runSkillPath(target, opts) {
115503
115954
  const log = opts.write ?? ((line2) => console.log(line2));
115504
115955
  if (!isValidTarget(target)) {
115505
- log(`${import_picocolors42.default.red("\u2717")} Unknown target: ${import_picocolors42.default.bold(target)}`);
115506
- log(import_picocolors42.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
115956
+ log(`${import_picocolors43.default.red("\u2717")} Unknown target: ${import_picocolors43.default.bold(target)}`);
115957
+ log(import_picocolors43.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
115507
115958
  return 1;
115508
115959
  }
115509
115960
  const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
@@ -115513,14 +115964,14 @@ async function runSkillPath(target, opts) {
115513
115964
 
115514
115965
  // ../../packages/cli/src/commands/update.ts
115515
115966
  init_cjs_shims();
115516
- var import_node_fs19 = require("fs");
115517
- var import_node_path21 = require("path");
115967
+ var import_node_fs20 = require("fs");
115968
+ var import_node_path22 = require("path");
115518
115969
  var import_node_os6 = require("os");
115519
115970
  var import_node_crypto7 = require("crypto");
115520
- var import_node_child_process9 = require("child_process");
115521
- var import_node_util5 = require("util");
115522
- var import_picocolors43 = __toESM(require_picocolors(), 1);
115523
- var execFileAsync2 = (0, import_node_util5.promisify)(import_node_child_process9.execFile);
115971
+ var import_node_child_process11 = require("child_process");
115972
+ var import_node_util7 = require("util");
115973
+ var import_picocolors44 = __toESM(require_picocolors(), 1);
115974
+ var execFileAsync4 = (0, import_node_util7.promisify)(import_node_child_process11.execFile);
115524
115975
  async function ensureBackendPinned(write) {
115525
115976
  let installed = null;
115526
115977
  try {
@@ -115529,18 +115980,18 @@ async function ensureBackendPinned(write) {
115529
115980
  installed = null;
115530
115981
  }
115531
115982
  if (installed === PINNED_SOURCE_VERSION) {
115532
- write(` ${import_picocolors43.default.green("\u2713")} Source backend already on pinned ${PINNED_SOURCE_VERSION}.`);
115983
+ write(` ${import_picocolors44.default.green("\u2713")} Source backend already on pinned ${PINNED_SOURCE_VERSION}.`);
115533
115984
  return;
115534
115985
  }
115535
115986
  if (installed === null) {
115536
115987
  write(
115537
- ` ${import_picocolors43.default.dim("Source backend not installed \u2014 install it: curl -fsSL https://horus.sh/install.sh | bash")}`
115988
+ ` ${import_picocolors44.default.dim("Source backend not installed \u2014 install it: curl -fsSL https://horus.sh/install.sh | bash")}`
115538
115989
  );
115539
115990
  return;
115540
115991
  }
115541
115992
  write(` Upgrading source backend ${installed} \u2192 ${PINNED_SOURCE_VERSION}\u2026`);
115542
115993
  try {
115543
- await execFileAsync2(
115994
+ await execFileAsync4(
115544
115995
  "uv",
115545
115996
  // --refresh: a CLI update commonly lands seconds after a backend release, so uv's
115546
115997
  // cached PyPI index may not list the just-published version yet and the install
@@ -115549,10 +116000,10 @@ async function ensureBackendPinned(write) {
115549
116000
  ["tool", "install", "--force", "--refresh", `horus-source==${PINNED_SOURCE_VERSION}`],
115550
116001
  { timeout: 3e5 }
115551
116002
  );
115552
- write(` ${import_picocolors43.default.green("\u2713")} Source backend upgraded to ${PINNED_SOURCE_VERSION}.`);
116003
+ write(` ${import_picocolors44.default.green("\u2713")} Source backend upgraded to ${PINNED_SOURCE_VERSION}.`);
115553
116004
  } catch {
115554
- write(` ${import_picocolors43.default.yellow("!")} Couldn't auto-upgrade the source backend. Re-run the installer:`);
115555
- write(` ${import_picocolors43.default.dim("curl -fsSL https://horus.sh/install.sh | bash")}`);
116005
+ write(` ${import_picocolors44.default.yellow("!")} Couldn't auto-upgrade the source backend. Re-run the installer:`);
116006
+ write(` ${import_picocolors44.default.dim("curl -fsSL https://horus.sh/install.sh | bash")}`);
115556
116007
  }
115557
116008
  }
115558
116009
  var RELEASES_API = "https://api.github.com/repos/meritt-dev/horus/releases/latest";
@@ -115585,7 +116036,7 @@ function resolveBinaryPath() {
115585
116036
  const raw = process.argv[1];
115586
116037
  if (!raw) throw new Error("Cannot determine binary path from process.argv[1]");
115587
116038
  try {
115588
- return (0, import_node_fs19.realpathSync)(raw);
116039
+ return (0, import_node_fs20.realpathSync)(raw);
115589
116040
  } catch {
115590
116041
  return raw;
115591
116042
  }
@@ -115595,33 +116046,33 @@ async function runUpdate(opts) {
115595
116046
  const _fetch = opts._fetch ?? fetch;
115596
116047
  const currentVersion = opts._currentVersion ?? HORUS_VERSION;
115597
116048
  write(`
115598
- ${import_picocolors43.default.bold("Horus update")}
116049
+ ${import_picocolors44.default.bold("Horus update")}
115599
116050
  `);
115600
- write(` Current version: ${import_picocolors43.default.cyan(currentVersion)}`);
116051
+ write(` Current version: ${import_picocolors44.default.cyan(currentVersion)}`);
115601
116052
  let release;
115602
116053
  try {
115603
116054
  release = await fetchLatestRelease(_fetch);
115604
116055
  } catch (e) {
115605
- write(` ${import_picocolors43.default.red("\u2717")} Could not reach GitHub: ${e.message}`);
116056
+ write(` ${import_picocolors44.default.red("\u2717")} Could not reach GitHub: ${e.message}`);
115606
116057
  return 1;
115607
116058
  }
115608
116059
  const latest = release.tag_name.replace(/^v/, "");
115609
- write(` Latest version: ${import_picocolors43.default.cyan(latest)}`);
116060
+ write(` Latest version: ${import_picocolors44.default.cyan(latest)}`);
115610
116061
  const newer = isNewer(latest, currentVersion);
115611
116062
  if (opts.check) {
115612
116063
  if (newer) {
115613
116064
  write(`
115614
- ${import_picocolors43.default.yellow("\u2192")} ${import_picocolors43.default.bold(latest)} is available.`);
115615
- write(` Run ${import_picocolors43.default.bold("horus update")} to upgrade.`);
116065
+ ${import_picocolors44.default.yellow("\u2192")} ${import_picocolors44.default.bold(latest)} is available.`);
116066
+ write(` Run ${import_picocolors44.default.bold("horus update")} to upgrade.`);
115616
116067
  } else {
115617
116068
  write(`
115618
- ${import_picocolors43.default.green("\u2713")} Already on the latest version.`);
116069
+ ${import_picocolors44.default.green("\u2713")} Already on the latest version.`);
115619
116070
  }
115620
116071
  return 0;
115621
116072
  }
115622
116073
  if (!newer && !opts.force) {
115623
116074
  write(`
115624
- ${import_picocolors43.default.green("\u2713")} Already on the latest version.`);
116075
+ ${import_picocolors44.default.green("\u2713")} Already on the latest version.`);
115625
116076
  await ensureBackendPinned(write);
115626
116077
  return 0;
115627
116078
  }
@@ -115631,8 +116082,8 @@ ${import_picocolors43.default.bold("Horus update")}
115631
116082
  const binaryAsset = release.assets.find((a2) => a2.name === assetName);
115632
116083
  const checksumAsset = release.assets.find((a2) => a2.name === checksumName);
115633
116084
  if (!binaryAsset) {
115634
- write(` ${import_picocolors43.default.red("\u2717")} Release ${tag} has no binary asset named '${assetName}'.`);
115635
- write(` Fallback: ${import_picocolors43.default.dim("curl -fsSL https://horus.sh/install.sh | bash")}`);
116085
+ write(` ${import_picocolors44.default.red("\u2717")} Release ${tag} has no binary asset named '${assetName}'.`);
116086
+ write(` Fallback: ${import_picocolors44.default.dim("curl -fsSL https://horus.sh/install.sh | bash")}`);
115636
116087
  return 1;
115637
116088
  }
115638
116089
  write(`
@@ -115642,7 +116093,7 @@ ${import_picocolors43.default.bold("Horus update")}
115642
116093
  redirect: "follow"
115643
116094
  });
115644
116095
  if (!binRes.ok || !binRes.body) {
115645
- write(` ${import_picocolors43.default.red("\u2717")} Download failed: ${binRes.status}`);
116096
+ write(` ${import_picocolors44.default.red("\u2717")} Download failed: ${binRes.status}`);
115646
116097
  return 1;
115647
116098
  }
115648
116099
  const binBuf = Buffer.from(await binRes.arrayBuffer());
@@ -115656,82 +116107,82 @@ ${import_picocolors43.default.bold("Horus update")}
115656
116107
  const expectedHash = csText.trim().split(/\s+/)[0];
115657
116108
  const actualHash = sha256hex(binBuf);
115658
116109
  if (expectedHash !== actualHash) {
115659
- write(` ${import_picocolors43.default.red("\u2717")} Checksum mismatch \u2014 download may be corrupt.`);
116110
+ write(` ${import_picocolors44.default.red("\u2717")} Checksum mismatch \u2014 download may be corrupt.`);
115660
116111
  write(` Expected: ${expectedHash}`);
115661
116112
  write(` Got: ${actualHash}`);
115662
116113
  return 1;
115663
116114
  }
115664
- write(` ${import_picocolors43.default.green("\u2713")} Checksum verified.`);
116115
+ write(` ${import_picocolors44.default.green("\u2713")} Checksum verified.`);
115665
116116
  }
115666
116117
  }
115667
116118
  let binaryPath;
115668
116119
  try {
115669
116120
  binaryPath = resolveBinaryPath();
115670
116121
  } catch (e) {
115671
- write(` ${import_picocolors43.default.red("\u2717")} ${e.message}`);
116122
+ write(` ${import_picocolors44.default.red("\u2717")} ${e.message}`);
115672
116123
  return 1;
115673
116124
  }
115674
- if (!(0, import_node_fs19.existsSync)(binaryPath)) {
115675
- write(` ${import_picocolors43.default.red("\u2717")} Binary not found at ${binaryPath}`);
116125
+ if (!(0, import_node_fs20.existsSync)(binaryPath)) {
116126
+ write(` ${import_picocolors44.default.red("\u2717")} Binary not found at ${binaryPath}`);
115676
116127
  return 1;
115677
116128
  }
115678
- const tmpPath = (0, import_node_path21.join)((0, import_node_os6.tmpdir)(), `horus-update-${tag}-${process.pid}`);
116129
+ const tmpPath = (0, import_node_path22.join)((0, import_node_os6.tmpdir)(), `horus-update-${tag}-${process.pid}`);
115679
116130
  const backupPath = `${binaryPath}.bak`;
115680
116131
  try {
115681
- (0, import_node_fs19.writeFileSync)(tmpPath, binBuf, { mode: 493 });
116132
+ (0, import_node_fs20.writeFileSync)(tmpPath, binBuf, { mode: 493 });
115682
116133
  } catch (e) {
115683
- write(` ${import_picocolors43.default.red("\u2717")} Could not write to temp dir: ${e.message}`);
116134
+ write(` ${import_picocolors44.default.red("\u2717")} Could not write to temp dir: ${e.message}`);
115684
116135
  return 1;
115685
116136
  }
115686
116137
  try {
115687
- (0, import_node_fs19.renameSync)(binaryPath, backupPath);
116138
+ (0, import_node_fs20.renameSync)(binaryPath, backupPath);
115688
116139
  try {
115689
- (0, import_node_fs19.renameSync)(tmpPath, binaryPath);
115690
- (0, import_node_fs19.chmodSync)(binaryPath, 493);
116140
+ (0, import_node_fs20.renameSync)(tmpPath, binaryPath);
116141
+ (0, import_node_fs20.chmodSync)(binaryPath, 493);
115691
116142
  } catch (e) {
115692
116143
  try {
115693
- (0, import_node_fs19.renameSync)(backupPath, binaryPath);
116144
+ (0, import_node_fs20.renameSync)(backupPath, binaryPath);
115694
116145
  } catch {
115695
116146
  }
115696
116147
  throw e;
115697
116148
  }
115698
116149
  try {
115699
- (0, import_node_fs19.unlinkSync)(backupPath);
116150
+ (0, import_node_fs20.unlinkSync)(backupPath);
115700
116151
  } catch {
115701
116152
  }
115702
116153
  } catch (e) {
115703
116154
  try {
115704
- (0, import_node_fs19.unlinkSync)(tmpPath);
116155
+ (0, import_node_fs20.unlinkSync)(tmpPath);
115705
116156
  } catch {
115706
116157
  }
115707
116158
  const msg = e.message ?? String(e);
115708
116159
  const needsSudo = e.code === "EACCES" || e.code === "EPERM";
115709
- write(` ${import_picocolors43.default.red("\u2717")} Could not replace binary at ${binaryPath}: ${msg}`);
116160
+ write(` ${import_picocolors44.default.red("\u2717")} Could not replace binary at ${binaryPath}: ${msg}`);
115710
116161
  if (needsSudo) {
115711
116162
  write(`
115712
116163
  Try with sudo:`);
115713
116164
  write(
115714
- ` ${import_picocolors43.default.dim(`sudo curl -fsSL https://github.com/meritt-dev/horus/releases/download/${tag}/${assetName} -o ${binaryPath} && sudo chmod +x ${binaryPath}`)}`
116165
+ ` ${import_picocolors44.default.dim(`sudo curl -fsSL https://github.com/meritt-dev/horus/releases/download/${tag}/${assetName} -o ${binaryPath} && sudo chmod +x ${binaryPath}`)}`
115715
116166
  );
115716
116167
  }
115717
116168
  return 1;
115718
116169
  }
115719
- write(` ${import_picocolors43.default.green("\u2713")} Updated: ${import_picocolors43.default.bold(currentVersion)} \u2192 ${import_picocolors43.default.bold(latest)}`);
115720
- write(` ${import_picocolors43.default.dim(binaryPath)}`);
116170
+ write(` ${import_picocolors44.default.green("\u2713")} Updated: ${import_picocolors44.default.bold(currentVersion)} \u2192 ${import_picocolors44.default.bold(latest)}`);
116171
+ write(` ${import_picocolors44.default.dim(binaryPath)}`);
115721
116172
  await ensureBackendPinned(write);
115722
116173
  return 0;
115723
116174
  }
115724
116175
 
115725
116176
  // ../../packages/cli/src/commands/login.ts
115726
116177
  init_cjs_shims();
115727
- var import_node_child_process10 = require("child_process");
115728
- var import_picocolors44 = __toESM(require_picocolors(), 1);
116178
+ var import_node_child_process12 = require("child_process");
116179
+ var import_picocolors45 = __toESM(require_picocolors(), 1);
115729
116180
  var sleep2 = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
115730
116181
  function openBrowser(url) {
115731
116182
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
115732
116183
  const args2 = process.platform === "win32" ? ["/c", "start", "", url] : [url];
115733
116184
  try {
115734
- (0, import_node_child_process10.execFile)(cmd, args2, () => {
116185
+ (0, import_node_child_process12.execFile)(cmd, args2, () => {
115735
116186
  });
115736
116187
  } catch {
115737
116188
  }
@@ -115750,19 +116201,19 @@ async function loginWithToken(apiBaseUrl, token) {
115750
116201
  }
115751
116202
  });
115752
116203
  console.log(
115753
- `${import_picocolors44.default.green("\u2713")} Logged in as ${import_picocolors44.default.bold(me3.user.primaryEmail)}. Run ${import_picocolors44.default.bold("horus cloud link")} to connect this repo.`
116204
+ `${import_picocolors45.default.green("\u2713")} Logged in as ${import_picocolors45.default.bold(me3.user.primaryEmail)}. Run ${import_picocolors45.default.bold("horus cloud link")} to connect this repo.`
115754
116205
  );
115755
116206
  return 0;
115756
116207
  } catch (err2) {
115757
116208
  if (err2 instanceof CloudOfflineError) {
115758
- console.error(import_picocolors44.default.red(err2.message));
116209
+ console.error(import_picocolors45.default.red(err2.message));
115759
116210
  return 1;
115760
116211
  }
115761
116212
  if (err2 instanceof CloudError && err2.status === 401) {
115762
- console.error(import_picocolors44.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
116213
+ console.error(import_picocolors45.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
115763
116214
  return 1;
115764
116215
  }
115765
- console.error(import_picocolors44.default.red(`Login failed: ${err2.message}`));
116216
+ console.error(import_picocolors45.default.red(`Login failed: ${err2.message}`));
115766
116217
  return 1;
115767
116218
  }
115768
116219
  }
@@ -115773,19 +116224,19 @@ async function loginWithBrowser(apiBaseUrl) {
115773
116224
  session = await client.startCliSession();
115774
116225
  } catch (err2) {
115775
116226
  if (err2 instanceof CloudOfflineError) {
115776
- console.error(import_picocolors44.default.red(err2.message));
116227
+ console.error(import_picocolors45.default.red(err2.message));
115777
116228
  return 1;
115778
116229
  }
115779
- console.error(import_picocolors44.default.red(`Could not start login: ${err2.message}`));
116230
+ console.error(import_picocolors45.default.red(`Could not start login: ${err2.message}`));
115780
116231
  return 1;
115781
116232
  }
115782
116233
  console.log("");
115783
116234
  console.log(` To sign in, open this URL in your browser:`);
115784
- console.log(` ${import_picocolors44.default.cyan(import_picocolors44.default.bold(session.verificationUri))}`);
116235
+ console.log(` ${import_picocolors45.default.cyan(import_picocolors45.default.bold(session.verificationUri))}`);
115785
116236
  console.log("");
115786
- console.log(` and enter the code: ${import_picocolors44.default.bold(session.userCode)}`);
116237
+ console.log(` and enter the code: ${import_picocolors45.default.bold(session.userCode)}`);
115787
116238
  console.log("");
115788
- console.log(import_picocolors44.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
116239
+ console.log(import_picocolors45.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
115789
116240
  openBrowser(session.verificationUriComplete);
115790
116241
  const deadline = Date.now() + session.expiresIn * 1e3;
115791
116242
  let intervalMs = Math.max(session.interval, 1) * 1e3;
@@ -115796,7 +116247,7 @@ async function loginWithBrowser(apiBaseUrl) {
115796
116247
  poll = await client.pollCliSession(session.deviceCode);
115797
116248
  } catch (err2) {
115798
116249
  if (err2 instanceof CloudOfflineError) {
115799
- console.error(import_picocolors44.default.red(`
116250
+ console.error(import_picocolors45.default.red(`
115800
116251
  ${err2.message}`));
115801
116252
  return 1;
115802
116253
  }
@@ -115809,14 +116260,14 @@ ${err2.message}`));
115809
116260
  intervalMs += 2e3;
115810
116261
  break;
115811
116262
  case "denied":
115812
- console.error(import_picocolors44.default.red("\nLogin was denied in the browser."));
116263
+ console.error(import_picocolors45.default.red("\nLogin was denied in the browser."));
115813
116264
  return 1;
115814
116265
  case "expired":
115815
- console.error(import_picocolors44.default.red("\nThis login request expired. Run `horus login` again."));
116266
+ console.error(import_picocolors45.default.red("\nThis login request expired. Run `horus login` again."));
115816
116267
  return 1;
115817
116268
  case "approved":
115818
116269
  if (!poll.token || !poll.account) {
115819
- console.error(import_picocolors44.default.red("\nLogin approved but no token was returned. Try again."));
116270
+ console.error(import_picocolors45.default.red("\nLogin approved but no token was returned. Try again."));
115820
116271
  return 1;
115821
116272
  }
115822
116273
  writeAuth({
@@ -115826,12 +116277,12 @@ ${err2.message}`));
115826
116277
  });
115827
116278
  console.log(
115828
116279
  `
115829
- ${import_picocolors44.default.green("\u2713")} Logged in as ${import_picocolors44.default.bold(poll.account.email)}. Run ${import_picocolors44.default.bold("horus cloud link")} to connect this repo.`
116280
+ ${import_picocolors45.default.green("\u2713")} Logged in as ${import_picocolors45.default.bold(poll.account.email)}. Run ${import_picocolors45.default.bold("horus cloud link")} to connect this repo.`
115830
116281
  );
115831
116282
  return 0;
115832
116283
  }
115833
116284
  }
115834
- console.error(import_picocolors44.default.red("\nTimed out waiting for approval. Run `horus login` again."));
116285
+ console.error(import_picocolors45.default.red("\nTimed out waiting for approval. Run `horus login` again."));
115835
116286
  return 1;
115836
116287
  }
115837
116288
  async function runLogin(opts = {}) {
@@ -115845,7 +116296,7 @@ async function runLogin(opts = {}) {
115845
116296
  async function runLogout() {
115846
116297
  const auth = readAuth();
115847
116298
  if (!auth) {
115848
- console.log(import_picocolors44.default.dim("Not logged in."));
116299
+ console.log(import_picocolors45.default.dim("Not logged in."));
115849
116300
  return 0;
115850
116301
  }
115851
116302
  const session = authedClient();
@@ -115859,18 +116310,18 @@ async function runLogout() {
115859
116310
  }
115860
116311
  }
115861
116312
  clearAuth();
115862
- console.log(`${import_picocolors44.default.green("\u2713")} Logged out. Local mode still works.`);
116313
+ console.log(`${import_picocolors45.default.green("\u2713")} Logged out. Local mode still works.`);
115863
116314
  return 0;
115864
116315
  }
115865
116316
 
115866
116317
  // ../../packages/cli/src/commands/cloud.ts
115867
116318
  init_cjs_shims();
115868
- var import_picocolors45 = __toESM(require_picocolors(), 1);
116319
+ var import_picocolors46 = __toESM(require_picocolors(), 1);
115869
116320
  var import_promises3 = require("readline/promises");
115870
116321
 
115871
116322
  // ../../packages/cli/src/lib/cloud/git.ts
115872
116323
  init_cjs_shims();
115873
- var import_node_child_process11 = require("child_process");
116324
+ var import_node_child_process13 = require("child_process");
115874
116325
  function parseRepoName(remoteUrl) {
115875
116326
  const cleaned = remoteUrl.trim().replace(/\.git$/, "");
115876
116327
  const lastSegment = cleaned.split(/[/:]/).filter(Boolean).pop() ?? "";
@@ -115894,7 +116345,7 @@ function inferProvider(remoteUrl) {
115894
116345
  }
115895
116346
  function detectGitRemote(root) {
115896
116347
  try {
115897
- const remoteUrl = (0, import_node_child_process11.execFileSync)("git", ["-C", root, "remote", "get-url", "origin"], {
116348
+ const remoteUrl = (0, import_node_child_process13.execFileSync)("git", ["-C", root, "remote", "get-url", "origin"], {
115898
116349
  encoding: "utf8",
115899
116350
  stdio: ["ignore", "pipe", "ignore"]
115900
116351
  }).trim();
@@ -115910,7 +116361,7 @@ async function runCloudLink(opts = {}) {
115910
116361
  const root = repoRootOrCwd(opts.cwd);
115911
116362
  const session = authedClient();
115912
116363
  if (!session) {
115913
- console.error(import_picocolors45.default.red(`Not logged in. Run ${import_picocolors45.default.bold("horus login")} first.`));
116364
+ console.error(import_picocolors46.default.red(`Not logged in. Run ${import_picocolors46.default.bold("horus login")} first.`));
115914
116365
  return 1;
115915
116366
  }
115916
116367
  let ctx;
@@ -115920,7 +116371,7 @@ async function runCloudLink(opts = {}) {
115920
116371
  return reportCloudError(err2);
115921
116372
  }
115922
116373
  const remote = detectGitRemote(root);
115923
- if (remote) console.log(import_picocolors45.default.dim(`Detected git remote: ${remote.remoteUrl}`));
116374
+ if (remote) console.log(import_picocolors46.default.dim(`Detected git remote: ${remote.remoteUrl}`));
115924
116375
  let resolved = null;
115925
116376
  let target = opts.project;
115926
116377
  if (!target) {
@@ -115936,7 +116387,7 @@ async function runCloudLink(opts = {}) {
115936
116387
  const org = ctx.organizations.find((o5) => o5.id === match.organizationId);
115937
116388
  if (ws && org) {
115938
116389
  target = `${org.slug}/${ws.slug}/${match.slug}`;
115939
- console.log(import_picocolors45.default.dim(`Matched existing project by remote: ${import_picocolors45.default.bold(target)}`));
116390
+ console.log(import_picocolors46.default.dim(`Matched existing project by remote: ${import_picocolors46.default.bold(target)}`));
115940
116391
  }
115941
116392
  }
115942
116393
  }
@@ -115945,8 +116396,8 @@ async function runCloudLink(opts = {}) {
115945
116396
  if (created === "aborted") return 1;
115946
116397
  if (!created) {
115947
116398
  console.error(
115948
- import_picocolors45.default.red("No project to link.") + `
115949
- Run ${import_picocolors45.default.bold("horus cloud link")} in a TTY to create one, pass ${import_picocolors45.default.bold("--project <org/workspace/project>")}, or create a project at ${import_picocolors45.default.bold("https://cloud.horus.sh")}.`
116399
+ import_picocolors46.default.red("No project to link.") + `
116400
+ Run ${import_picocolors46.default.bold("horus cloud link")} in a TTY to create one, pass ${import_picocolors46.default.bold("--project <org/workspace/project>")}, or create a project at ${import_picocolors46.default.bold("https://cloud.horus.sh")}.`
115950
116401
  );
115951
116402
  return 1;
115952
116403
  }
@@ -115956,8 +116407,8 @@ async function runCloudLink(opts = {}) {
115956
116407
  resolved = resolveTriple(ctx, target);
115957
116408
  if (!resolved) {
115958
116409
  console.error(
115959
- import_picocolors45.default.red(`You don't have access to ${import_picocolors45.default.bold(target)}.`) + `
115960
- Run ${import_picocolors45.default.bold("horus context list")} to see available projects.`
116410
+ import_picocolors46.default.red(`You don't have access to ${import_picocolors46.default.bold(target)}.`) + `
116411
+ Run ${import_picocolors46.default.bold("horus context list")} to see available projects.`
115961
116412
  );
115962
116413
  return 1;
115963
116414
  }
@@ -115970,10 +116421,10 @@ async function runCloudLink(opts = {}) {
115970
116421
  project: resolved.project
115971
116422
  });
115972
116423
  console.log(
115973
- `${import_picocolors45.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors45.default.bold(label)} ${import_picocolors45.default.dim("(cloud)")}.`
116424
+ `${import_picocolors46.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors46.default.bold(label)} ${import_picocolors46.default.dim("(cloud)")}.`
115974
116425
  );
115975
116426
  console.log(
115976
- import_picocolors45.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors45.default.bold("horus context use local")} to switch back.`)
116427
+ import_picocolors46.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors46.default.bold("horus context use local")} to switch back.`)
115977
116428
  );
115978
116429
  return 0;
115979
116430
  }
@@ -115981,11 +116432,11 @@ async function runCloudUnlink(opts = {}) {
115981
116432
  const root = repoRootOrCwd(opts.cwd);
115982
116433
  const cfg = readCloudConfig(root);
115983
116434
  if (!cfg || cfg.context !== "cloud") {
115984
- console.log(import_picocolors45.default.dim("This repo isn't linked to a cloud project."));
116435
+ console.log(import_picocolors46.default.dim("This repo isn't linked to a cloud project."));
115985
116436
  return 0;
115986
116437
  }
115987
116438
  clearCloudConfig(root);
115988
- console.log(`${import_picocolors45.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors45.default.bold("local")} mode.`);
116439
+ console.log(`${import_picocolors46.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors46.default.bold("local")} mode.`);
115989
116440
  return 0;
115990
116441
  }
115991
116442
  async function runCloudStatus(opts = {}) {
@@ -115993,18 +116444,18 @@ async function runCloudStatus(opts = {}) {
115993
116444
  const cfg = readCloudConfig(root);
115994
116445
  const session = authedClient();
115995
116446
  if (!isCloudActive(cfg) || !cfg?.project) {
115996
- console.log(`${import_picocolors45.default.bold("Context:")} local`);
115997
- console.log(`${import_picocolors45.default.bold("Storage:")} local Postgres (~/.horus)`);
116447
+ console.log(`${import_picocolors46.default.bold("Context:")} local`);
116448
+ console.log(`${import_picocolors46.default.bold("Storage:")} local Postgres (~/.horus)`);
115998
116449
  console.log(
115999
- import_picocolors45.default.dim(`Tip: ${import_picocolors45.default.bold("horus login")} then ${import_picocolors45.default.bold("horus cloud link")} to share investigations with your team.`)
116450
+ import_picocolors46.default.dim(`Tip: ${import_picocolors46.default.bold("horus login")} then ${import_picocolors46.default.bold("horus cloud link")} to share investigations with your team.`)
116000
116451
  );
116001
116452
  return 0;
116002
116453
  }
116003
116454
  const triple = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
116004
- console.log(`${import_picocolors45.default.bold("Context:")} ${triple} ${import_picocolors45.default.dim("(cloud)")}`);
116455
+ console.log(`${import_picocolors46.default.bold("Context:")} ${triple} ${import_picocolors46.default.dim("(cloud)")}`);
116005
116456
  let projectLine = `${cfg.project.slug}`;
116006
116457
  let metaLines = [];
116007
- let account = import_picocolors45.default.dim("not logged in");
116458
+ let account = import_picocolors46.default.dim("not logged in");
116008
116459
  if (session) {
116009
116460
  account = session.auth.account.email;
116010
116461
  try {
@@ -116019,9 +116470,9 @@ async function runCloudStatus(opts = {}) {
116019
116470
  } catch {
116020
116471
  }
116021
116472
  }
116022
- console.log(`${import_picocolors45.default.bold("Project:")} ${projectLine}`);
116473
+ console.log(`${import_picocolors46.default.bold("Project:")} ${projectLine}`);
116023
116474
  for (const line2 of metaLines) console.log(line2);
116024
- console.log(`${import_picocolors45.default.bold("Account:")} ${account}`);
116475
+ console.log(`${import_picocolors46.default.bold("Account:")} ${account}`);
116025
116476
  return 0;
116026
116477
  }
116027
116478
  async function runCloudSync(opts = {}) {
@@ -116029,13 +116480,13 @@ async function runCloudSync(opts = {}) {
116029
116480
  const cfg = readCloudConfig(root);
116030
116481
  if (!isCloudActive(cfg) || !cfg.project) {
116031
116482
  console.error(
116032
- import_picocolors45.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors45.default.bold("horus cloud link")} first.`
116483
+ import_picocolors46.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors46.default.bold("horus cloud link")} first.`
116033
116484
  );
116034
116485
  return 1;
116035
116486
  }
116036
116487
  const session = authedClient();
116037
116488
  if (!session) {
116038
- console.error(import_picocolors45.default.red(`Not logged in. Run ${import_picocolors45.default.bold("horus login")} first.`));
116489
+ console.error(import_picocolors46.default.red(`Not logged in. Run ${import_picocolors46.default.bold("horus login")} first.`));
116039
116490
  return 1;
116040
116491
  }
116041
116492
  const { db, sql: sql2 } = await openDb(await resolveDbUrl(opts.config));
@@ -116056,26 +116507,26 @@ async function runCloudSync(opts = {}) {
116056
116507
  const target = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
116057
116508
  if (uploadable.length === 0) {
116058
116509
  console.log(
116059
- import_picocolors45.default.dim(
116510
+ import_picocolors46.default.dim(
116060
116511
  `No local investigations with reports to upload.` + (skippedNoReport ? ` (${skippedNoReport} without a report skipped)` : "")
116061
116512
  )
116062
116513
  );
116063
116514
  return 0;
116064
116515
  }
116065
- console.log(import_picocolors45.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors45.default.dim("(cloud)")}:`));
116516
+ console.log(import_picocolors46.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors46.default.dim("(cloud)")}:`));
116066
116517
  for (const c4 of uploadable.slice(0, 20)) {
116067
- console.log(` ${import_picocolors45.default.dim(c4.id.slice(0, 8))} ${(c4.title ?? "untitled").slice(0, 70)}`);
116518
+ console.log(` ${import_picocolors46.default.dim(c4.id.slice(0, 8))} ${(c4.title ?? "untitled").slice(0, 70)}`);
116068
116519
  }
116069
- if (uploadable.length > 20) console.log(import_picocolors45.default.dim(` \u2026and ${uploadable.length - 20} more`));
116070
- if (skippedNoReport) console.log(import_picocolors45.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
116520
+ if (uploadable.length > 20) console.log(import_picocolors46.default.dim(` \u2026and ${uploadable.length - 20} more`));
116521
+ if (skippedNoReport) console.log(import_picocolors46.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
116071
116522
  if (opts.dryRun) {
116072
- console.log(import_picocolors45.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
116523
+ console.log(import_picocolors46.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
116073
116524
  return 0;
116074
116525
  }
116075
116526
  if (!opts.yes) {
116076
116527
  if (!process.stdin.isTTY) {
116077
116528
  console.error(
116078
- import_picocolors45.default.yellow(`Re-run with ${import_picocolors45.default.bold("--yes")} to upload, or ${import_picocolors45.default.bold("--dry-run")} to preview only.`)
116529
+ import_picocolors46.default.yellow(`Re-run with ${import_picocolors46.default.bold("--yes")} to upload, or ${import_picocolors46.default.bold("--dry-run")} to preview only.`)
116079
116530
  );
116080
116531
  return 1;
116081
116532
  }
@@ -116083,7 +116534,7 @@ async function runCloudSync(opts = {}) {
116083
116534
  try {
116084
116535
  const answer = (await rl.question(`Upload ${uploadable.length} investigation(s) to ${target}? (y/N) `)).trim().toLowerCase();
116085
116536
  if (answer !== "y" && answer !== "yes") {
116086
- console.log(import_picocolors45.default.dim("Aborted. Nothing uploaded."));
116537
+ console.log(import_picocolors46.default.dim("Aborted. Nothing uploaded."));
116087
116538
  return 0;
116088
116539
  }
116089
116540
  } finally {
@@ -116096,18 +116547,18 @@ async function runCloudSync(opts = {}) {
116096
116547
  try {
116097
116548
  const refs = await uploadInvestigationToCloud(session.client, cfg, c4.report);
116098
116549
  created++;
116099
- console.log(`${import_picocolors45.default.green("\u2713")} ${import_picocolors45.default.dim(c4.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
116550
+ console.log(`${import_picocolors46.default.green("\u2713")} ${import_picocolors46.default.dim(c4.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
116100
116551
  } catch (err2) {
116101
116552
  failed++;
116102
- console.error(`${import_picocolors45.default.red("\u2717")} ${import_picocolors45.default.dim(c4.id.slice(0, 8))} ${err2.message}`);
116553
+ console.error(`${import_picocolors46.default.red("\u2717")} ${import_picocolors46.default.dim(c4.id.slice(0, 8))} ${err2.message}`);
116103
116554
  }
116104
116555
  }
116105
116556
  console.log("");
116106
116557
  console.log(
116107
- `${import_picocolors45.default.bold("Sync complete:")} ${import_picocolors45.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors45.default.red(`${failed} failed`) : "0 failed") + "."
116558
+ `${import_picocolors46.default.bold("Sync complete:")} ${import_picocolors46.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors46.default.red(`${failed} failed`) : "0 failed") + "."
116108
116559
  );
116109
116560
  console.log(
116110
- import_picocolors45.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
116561
+ import_picocolors46.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
116111
116562
  );
116112
116563
  return failed > 0 ? 1 : 0;
116113
116564
  }
@@ -116115,8 +116566,8 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
116115
116566
  if (!process.stdin.isTTY && !yes) return null;
116116
116567
  if (ctx.organizations.length === 0) {
116117
116568
  console.error(
116118
- import_picocolors45.default.red("You're not a member of any organization yet.") + `
116119
- Create one at ${import_picocolors45.default.bold("https://cloud.horus.sh")} first.`
116569
+ import_picocolors46.default.red("You're not a member of any organization yet.") + `
116570
+ Create one at ${import_picocolors46.default.bold("https://cloud.horus.sh")} first.`
116120
116571
  );
116121
116572
  return null;
116122
116573
  }
@@ -116141,9 +116592,9 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
116141
116592
  const wsName = await ask2("New workspace name", repoName || "default");
116142
116593
  const ws = await client.createWorkspace(org.id, { name: wsName });
116143
116594
  workspace = { id: ws.id, slug: ws.slug };
116144
- console.log(import_picocolors45.default.dim(`Created workspace ${import_picocolors45.default.bold(ws.slug)}.`));
116595
+ console.log(import_picocolors46.default.dim(`Created workspace ${import_picocolors46.default.bold(ws.slug)}.`));
116145
116596
  } else {
116146
- console.log(`Workspaces in ${import_picocolors45.default.bold(org.slug)}:`);
116597
+ console.log(`Workspaces in ${import_picocolors46.default.bold(org.slug)}:`);
116147
116598
  orgWorkspaces.forEach((w4, i3) => console.log(` ${i3 + 1}) ${w4.slug}`));
116148
116599
  console.log(` ${orgWorkspaces.length + 1}) + create a new workspace`);
116149
116600
  const pick2 = Number(await ask2("Workspace number", "1"));
@@ -116151,7 +116602,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
116151
116602
  const wsName = await ask2("New workspace name", repoName || "default");
116152
116603
  const ws = await client.createWorkspace(org.id, { name: wsName });
116153
116604
  workspace = { id: ws.id, slug: ws.slug };
116154
- console.log(import_picocolors45.default.dim(`Created workspace ${import_picocolors45.default.bold(ws.slug)}.`));
116605
+ console.log(import_picocolors46.default.dim(`Created workspace ${import_picocolors46.default.bold(ws.slug)}.`));
116155
116606
  } else {
116156
116607
  const chosen = orgWorkspaces[pick2 - 1] ?? orgWorkspaces[0];
116157
116608
  workspace = { id: chosen.id, slug: chosen.slug };
@@ -116163,7 +116614,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
116163
116614
  remoteUrl: remote?.remoteUrl,
116164
116615
  provider: remote ? inferProvider(remote.remoteUrl) : void 0
116165
116616
  });
116166
- console.log(import_picocolors45.default.dim(`Created project ${import_picocolors45.default.bold(project.slug)}.`));
116617
+ console.log(import_picocolors46.default.dim(`Created project ${import_picocolors46.default.bold(project.slug)}.`));
116167
116618
  return {
116168
116619
  organization: { id: org.id, slug: org.slug },
116169
116620
  workspace,
@@ -116179,7 +116630,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
116179
116630
 
116180
116631
  // ../../packages/cli/src/commands/telemetry.ts
116181
116632
  init_cjs_shims();
116182
- var import_picocolors47 = __toESM(require_picocolors(), 1);
116633
+ var import_picocolors48 = __toESM(require_picocolors(), 1);
116183
116634
  var import_node_crypto8 = require("crypto");
116184
116635
 
116185
116636
  // ../../packages/cli/src/lib/telemetry/transport.ts
@@ -116240,7 +116691,7 @@ async function deleteRemoteTelemetry(installId, opts = {}) {
116240
116691
 
116241
116692
  // ../../packages/cli/src/lib/telemetry/notice.ts
116242
116693
  init_cjs_shims();
116243
- var import_picocolors46 = __toESM(require_picocolors(), 1);
116694
+ var import_picocolors47 = __toESM(require_picocolors(), 1);
116244
116695
  var PRIVACY_URL = "https://horus.sh/privacy";
116245
116696
  var SUPPRESS_FIRST_TOKEN = /* @__PURE__ */ new Set(["telemetry", "help"]);
116246
116697
  var SUPPRESS_FLAGS = /* @__PURE__ */ new Set(["-V", "--version", "-h", "--help"]);
@@ -116252,11 +116703,11 @@ function shouldSuppressFor(argv) {
116252
116703
  return firstToken != null && SUPPRESS_FIRST_TOKEN.has(firstToken);
116253
116704
  }
116254
116705
  function banner() {
116255
- const b5 = import_picocolors46.default.bold;
116256
- const dim = import_picocolors46.default.dim;
116706
+ const b5 = import_picocolors47.default.bold;
116707
+ const dim = import_picocolors47.default.dim;
116257
116708
  return [
116258
116709
  "",
116259
- import_picocolors46.default.cyan(b5("Horus collects anonymous usage data to improve the tool.")),
116710
+ import_picocolors47.default.cyan(b5("Horus collects anonymous usage data to improve the tool.")),
116260
116711
  dim(" \u2022 On by default: command names, timings, success/failure, and where the"),
116261
116712
  dim(" engine ran out of evidence. No file contents, queries, or secrets."),
116262
116713
  dim(" \u2022 Off by default: your investigation inputs/outputs (opt in to help train"),
@@ -116264,7 +116715,7 @@ function banner() {
116264
116715
  dim(" \u2022 If you use Horus Cloud, linked investigations sync to your workspace."),
116265
116716
  "",
116266
116717
  ` ${dim("Opt out anytime:")} ${b5("horus telemetry disable")} ${dim("\xB7")} ${b5("HORUS_TELEMETRY=0")} ${dim("\xB7")} ${b5("DO_NOT_TRACK=1")}`,
116267
- ` ${dim("Details:")} ${import_picocolors46.default.underline(PRIVACY_URL)}`,
116718
+ ` ${dim("Details:")} ${import_picocolors47.default.underline(PRIVACY_URL)}`,
116268
116719
  ""
116269
116720
  ].join("\n");
116270
116721
  }
@@ -116287,45 +116738,45 @@ function maybeShowFirstRunNotice(argv = process.argv) {
116287
116738
 
116288
116739
  // ../../packages/cli/src/commands/telemetry.ts
116289
116740
  function onOff(enabled) {
116290
- return enabled ? import_picocolors47.default.green("on") : import_picocolors47.default.dim("off");
116741
+ return enabled ? import_picocolors48.default.green("on") : import_picocolors48.default.dim("off");
116291
116742
  }
116292
116743
  function warnIfEnvOverrides() {
116293
116744
  const decision = resolveConsent();
116294
116745
  if (decision.forcedOff) {
116295
116746
  console.log(
116296
- import_picocolors47.default.yellow(
116747
+ import_picocolors48.default.yellow(
116297
116748
  `
116298
116749
  Note: telemetry is currently forced off by your environment (${decision.reason}).`
116299
116750
  )
116300
116751
  );
116301
- console.log(import_picocolors47.default.dim("Your saved preference will apply once that override is removed."));
116752
+ console.log(import_picocolors48.default.dim("Your saved preference will apply once that override is removed."));
116302
116753
  } else if (decision.source === "ci") {
116303
116754
  console.log(
116304
- import_picocolors47.default.yellow("\nNote: CI environment detected \u2014 telemetry stays off here regardless.")
116755
+ import_picocolors48.default.yellow("\nNote: CI environment detected \u2014 telemetry stays off here regardless.")
116305
116756
  );
116306
116757
  }
116307
116758
  }
116308
116759
  async function runTelemetryStatus() {
116309
116760
  const state = readTelemetryState();
116310
116761
  const decision = resolveConsent({ state });
116311
- console.log(import_picocolors47.default.bold("Horus telemetry"));
116762
+ console.log(import_picocolors48.default.bold("Horus telemetry"));
116312
116763
  console.log(
116313
- ` Usage metadata (Tier A): ${onOff(decision.tierA)} ${import_picocolors47.default.dim(`[${decision.source}]`)}`
116764
+ ` Usage metadata (Tier A): ${onOff(decision.tierA)} ${import_picocolors48.default.dim(`[${decision.source}]`)}`
116314
116765
  );
116315
116766
  console.log(` Content sharing (Tier B): ${onOff(decision.tierB)}`);
116316
- console.log(import_picocolors47.default.dim(` Reason: ${decision.reason}`));
116767
+ console.log(import_picocolors48.default.dim(` Reason: ${decision.reason}`));
116317
116768
  if (state) {
116318
- console.log(import_picocolors47.default.dim(` Install ID: ${state.installId}`));
116769
+ console.log(import_picocolors48.default.dim(` Install ID: ${state.installId}`));
116319
116770
  console.log(
116320
- import_picocolors47.default.dim(
116771
+ import_picocolors48.default.dim(
116321
116772
  ` Saved: Tier A ${state.tierA.enabled ? "on" : "off"}, Tier B ${state.tierB.enabled ? "on" : "off"}`
116322
116773
  )
116323
116774
  );
116324
116775
  } else {
116325
- console.log(import_picocolors47.default.dim(" No saved preference yet (defaults apply)."));
116776
+ console.log(import_picocolors48.default.dim(" No saved preference yet (defaults apply)."));
116326
116777
  }
116327
- console.log(import_picocolors47.default.dim(` Config: ${telemetryPath()}`));
116328
- console.log(import_picocolors47.default.dim(` Privacy: ${PRIVACY_URL}`));
116778
+ console.log(import_picocolors48.default.dim(` Config: ${telemetryPath()}`));
116779
+ console.log(import_picocolors48.default.dim(` Privacy: ${PRIVACY_URL}`));
116329
116780
  if (!state || decision.source === "env" || decision.source === "ci") {
116330
116781
  warnIfEnvOverrides();
116331
116782
  }
@@ -116336,7 +116787,7 @@ async function runTelemetryEnable() {
116336
116787
  s5.tierA.enabled = true;
116337
116788
  if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
116338
116789
  });
116339
- console.log(import_picocolors47.default.green("Anonymous usage metadata (Tier A) is now ON. Thank you!"));
116790
+ console.log(import_picocolors48.default.green("Anonymous usage metadata (Tier A) is now ON. Thank you!"));
116340
116791
  warnIfEnvOverrides();
116341
116792
  return 0;
116342
116793
  }
@@ -116346,7 +116797,7 @@ async function runTelemetryDisable() {
116346
116797
  s5.tierB.enabled = false;
116347
116798
  if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
116348
116799
  });
116349
- console.log(import_picocolors47.default.yellow("All telemetry is now OFF (Tier A and Tier B)."));
116800
+ console.log(import_picocolors48.default.yellow("All telemetry is now OFF (Tier A and Tier B)."));
116350
116801
  return 0;
116351
116802
  }
116352
116803
  async function runTelemetryEnableContent() {
@@ -116357,10 +116808,10 @@ async function runTelemetryEnableContent() {
116357
116808
  if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
116358
116809
  });
116359
116810
  console.log(
116360
- import_picocolors47.default.green("Content sharing (Tier B) is now ON \u2014 redacted inputs/outputs help improve Horus.")
116811
+ import_picocolors48.default.green("Content sharing (Tier B) is now ON \u2014 redacted inputs/outputs help improve Horus.")
116361
116812
  );
116362
- console.log(import_picocolors47.default.dim("Content is scrubbed of secrets/PII before it ever leaves your machine."));
116363
- console.log(import_picocolors47.default.dim(`What this means: ${PRIVACY_URL}`));
116813
+ console.log(import_picocolors48.default.dim("Content is scrubbed of secrets/PII before it ever leaves your machine."));
116814
+ console.log(import_picocolors48.default.dim(`What this means: ${PRIVACY_URL}`));
116364
116815
  warnIfEnvOverrides();
116365
116816
  return 0;
116366
116817
  }
@@ -116368,7 +116819,7 @@ async function runTelemetryDisableContent() {
116368
116819
  updateTelemetryState((s5) => {
116369
116820
  s5.tierB.enabled = false;
116370
116821
  });
116371
- console.log(import_picocolors47.default.yellow("Content sharing (Tier B) is now OFF. Usage metadata is unchanged."));
116822
+ console.log(import_picocolors48.default.yellow("Content sharing (Tier B) is now OFF. Usage metadata is unchanged."));
116372
116823
  return 0;
116373
116824
  }
116374
116825
  async function runTelemetryResetId() {
@@ -116376,8 +116827,8 @@ async function runTelemetryResetId() {
116376
116827
  updateTelemetryState((s5) => {
116377
116828
  s5.installId = next;
116378
116829
  });
116379
- console.log(import_picocolors47.default.green("Install ID reset."));
116380
- console.log(import_picocolors47.default.dim(` New install ID: ${next}`));
116830
+ console.log(import_picocolors48.default.green("Install ID reset."));
116831
+ console.log(import_picocolors48.default.dim(` New install ID: ${next}`));
116381
116832
  return 0;
116382
116833
  }
116383
116834
  async function runTelemetryDelete() {
@@ -116385,9 +116836,9 @@ async function runTelemetryDelete() {
116385
116836
  if (installId) await deleteRemoteTelemetry(installId);
116386
116837
  deleteTelemetryState();
116387
116838
  clearSpool();
116388
- console.log(import_picocolors47.default.green("Telemetry deleted \u2014 local state cleared and a server purge requested."));
116839
+ console.log(import_picocolors48.default.green("Telemetry deleted \u2014 local state cleared and a server purge requested."));
116389
116840
  console.log(
116390
- import_picocolors47.default.dim(
116841
+ import_picocolors48.default.dim(
116391
116842
  "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."
116392
116843
  )
116393
116844
  );
@@ -116430,35 +116881,35 @@ function installCommandTelemetry(program2) {
116430
116881
 
116431
116882
  // ../../packages/cli/src/commands/feedback.ts
116432
116883
  init_cjs_shims();
116433
- var import_picocolors48 = __toESM(require_picocolors(), 1);
116884
+ var import_picocolors49 = __toESM(require_picocolors(), 1);
116434
116885
  async function runFeedback(investigationId, opts = {}) {
116435
116886
  const id = investigationId?.trim();
116436
116887
  if (!id) {
116437
- console.error(import_picocolors48.default.red("Usage: horus feedback <investigationId> [--resolved yes|partly|no]"));
116888
+ console.error(import_picocolors49.default.red("Usage: horus feedback <investigationId> [--resolved yes|partly|no]"));
116438
116889
  return 1;
116439
116890
  }
116440
116891
  if (opts.resolved !== void 0) {
116441
116892
  const resolved = parseResolved(opts.resolved);
116442
116893
  if (resolved === null) {
116443
- console.error(import_picocolors48.default.red(`Invalid --resolved "${opts.resolved}". Use: yes | partly | no.`));
116894
+ console.error(import_picocolors49.default.red(`Invalid --resolved "${opts.resolved}". Use: yes | partly | no.`));
116444
116895
  return 1;
116445
116896
  }
116446
116897
  let manualEstimateMinutes = null;
116447
116898
  if (opts.manualEstimateMin !== void 0) {
116448
116899
  const n4 = Number.parseInt(opts.manualEstimateMin, 10);
116449
116900
  if (!Number.isFinite(n4) || n4 < 0) {
116450
- console.error(import_picocolors48.default.red(`Invalid --manual-estimate-min "${opts.manualEstimateMin}" (expect a non-negative integer).`));
116901
+ console.error(import_picocolors49.default.red(`Invalid --manual-estimate-min "${opts.manualEstimateMin}" (expect a non-negative integer).`));
116451
116902
  return 1;
116452
116903
  }
116453
116904
  manualEstimateMinutes = n4;
116454
116905
  }
116455
116906
  submitFeedback({ investigationId: id, resolved, manualEstimateMinutes, horusSeconds: null, source: "flag" });
116456
- console.log(import_picocolors48.default.dim(`Feedback recorded (${resolved}) \u2014 thanks, this helps improve Horus.`));
116907
+ console.log(import_picocolors49.default.dim(`Feedback recorded (${resolved}) \u2014 thanks, this helps improve Horus.`));
116457
116908
  return 0;
116458
116909
  }
116459
116910
  if (!process.stdin.isTTY) {
116460
116911
  console.error(
116461
- import_picocolors48.default.yellow(
116912
+ import_picocolors49.default.yellow(
116462
116913
  "horus feedback needs an interactive terminal \u2014 or pass --resolved yes|partly|no for non-interactive (agent) use."
116463
116914
  )
116464
116915
  );
@@ -116551,8 +117002,8 @@ Examples:
116551
117002
  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) => {
116552
117003
  process.exitCode = await runStop(opts);
116553
117004
  });
116554
- program2.command("hosts").description("List registered source-intelligence hosts and their live status (port, repo, running/stopped)").action(async () => {
116555
- process.exitCode = await runHosts();
117005
+ program2.command("hosts").description("List registered source-intelligence hosts and their live status (port, repo, running/stopped)").option("--reap", "stop orphaned source hosts that no registered repo owns").action(async (opts) => {
117006
+ process.exitCode = await runHosts({ reap: opts.reap });
116556
117007
  });
116557
117008
  program2.command("status").description("Show config, provider health, and project/environment matrix").option("-c, --config <path>", "path to horus.config.ts").option("--name <name>", "registered project name (resolves via the registry)").option("--project <name>", "project name (show only this project)").option("--env <name>", "environment name (e.g. production)").action(
116558
117009
  async (opts) => {