@merittdev/horus 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.cjs +1313 -569
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -23435,9 +23435,9 @@ var require_client_metadata = __commonJS({
23435
23435
  throw new error_1.MongoInvalidArgumentError("Unable to include driverInfo name and version, metadata cannot exceed 512 bytes");
23436
23436
  }
23437
23437
  let runtimeInfo = getRuntimeInfo();
23438
- for (const { platform = "" } of driverInfoList) {
23439
- if (platform.length > 0) {
23440
- runtimeInfo = `${runtimeInfo}|${platform}`;
23438
+ for (const { platform: platform2 = "" } of driverInfoList) {
23439
+ if (platform2.length > 0) {
23440
+ runtimeInfo = `${runtimeInfo}|${platform2}`;
23441
23441
  }
23442
23442
  }
23443
23443
  if (!metadataDocument.ifItFitsItSits("platform", runtimeInfo)) {
@@ -43447,7 +43447,7 @@ var require_common3 = __commonJS({
43447
43447
  function setup(env) {
43448
43448
  createDebug.debug = createDebug;
43449
43449
  createDebug.default = createDebug;
43450
- createDebug.coerce = coerce2;
43450
+ createDebug.coerce = coerce3;
43451
43451
  createDebug.disable = disable;
43452
43452
  createDebug.enable = enable;
43453
43453
  createDebug.enabled = enabled;
@@ -43602,7 +43602,7 @@ var require_common3 = __commonJS({
43602
43602
  }
43603
43603
  return false;
43604
43604
  }
43605
- function coerce2(val) {
43605
+ function coerce3(val) {
43606
43606
  if (val instanceof Error) {
43607
43607
  return val.stack || val.message;
43608
43608
  }
@@ -57239,9 +57239,8 @@ init_cjs_shims();
57239
57239
 
57240
57240
  // ../../packages/core/src/version.ts
57241
57241
  init_cjs_shims();
57242
- var HORUS_VERSION = true ? "0.2.3" : "dev";
57243
- var PINNED_AXON_VERSION = "1.0.7";
57244
- var PINNED_SOURCE_VERSION = PINNED_AXON_VERSION;
57242
+ var HORUS_VERSION = true ? "0.3.0" : "dev";
57243
+ var PINNED_SOURCE_VERSION = "1.1.1";
57245
57244
 
57246
57245
  // ../../packages/core/src/evidence.ts
57247
57246
  init_cjs_shims();
@@ -61672,7 +61671,7 @@ var horusConfigSchema = external_exports.object({
61672
61671
  projects: external_exports.array(projectSchema).default([]),
61673
61672
  axon: external_exports.object({
61674
61673
  /** Fail fast if the running Axon is not this version. */
61675
- pinnedVersion: external_exports.string().default("1.0.7")
61674
+ pinnedVersion: external_exports.string().default("1.1.1")
61676
61675
  }).default({}),
61677
61676
  database: databaseSchema,
61678
61677
  models: modelsSchema.default({}),
@@ -62052,6 +62051,73 @@ packages/core/src/git.ts @horus/core-team @horus/devex-team
62052
62051
  `.trim();
62053
62052
  var FIXTURE_CODEOWNERS_RULES = parseCodeowners(FIXTURE_CODEOWNERS);
62054
62053
 
62054
+ // ../../packages/core/src/redact.ts
62055
+ init_cjs_shims();
62056
+ var BASE_PATTERNS = [
62057
+ [/(authorization\s*[=:]\s*)(bearer\s+)[^\s,"')]+/gi, "$1$2[REDACTED]"],
62058
+ [/(authorization\s*[=:]\s*)(basic\s+)[^\s,"')]+/gi, "$1$2[REDACTED]"],
62059
+ [
62060
+ /("?(?:password|passwd|secret|token|api[_-]key|apikey|x-api-key)"?\s*[=:]\s*)"?[^"',\s)>]+/gi,
62061
+ "$1[REDACTED]"
62062
+ ],
62063
+ [/((?:cookie|set-cookie)\s*[=:]\s*)[^\s"',;>]{4,}/gi, "$1[REDACTED]"],
62064
+ [
62065
+ /((?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis(?:s)?):\/\/)[^:@/\s]+:[^@\s]+@/gi,
62066
+ "$1[REDACTED]@"
62067
+ ],
62068
+ [/\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g, "[REDACTED-CARD]"]
62069
+ ];
62070
+ var EXTENDED_PATTERNS = [
62071
+ // PEM private key blocks (run first — multi-line, highest risk).
62072
+ [
62073
+ /-----BEGIN (?:[A-Z ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z ]+ )?PRIVATE KEY-----/g,
62074
+ "[REDACTED-PRIVATE-KEY]"
62075
+ ],
62076
+ // JSON Web Tokens (three base64url segments starting with the `{"` header).
62077
+ [/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[REDACTED-JWT]"],
62078
+ // AWS access key ids.
62079
+ [/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g, "[REDACTED-AWS-KEY]"],
62080
+ // Google API keys.
62081
+ [/\bAIza[0-9A-Za-z_-]{35}\b/g, "[REDACTED-GCP-KEY]"],
62082
+ // Slack tokens.
62083
+ [/\bxox[baprs]-[0-9A-Za-z-]{10,}\b/g, "[REDACTED-SLACK-TOKEN]"],
62084
+ // GitHub tokens.
62085
+ [/\bgh[pousr]_[0-9A-Za-z]{36,}\b/g, "[REDACTED-GH-TOKEN]"],
62086
+ // Emails.
62087
+ [/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g, "[REDACTED-EMAIL]"],
62088
+ // IPv4 addresses.
62089
+ [/\b(?:\d{1,3}\.){3}\d{1,3}\b/g, "[REDACTED-IP]"]
62090
+ ];
62091
+ var RESIDUAL_HIGH_RISK = [
62092
+ /-----BEGIN (?:[A-Z ]+ )?PRIVATE KEY-----/,
62093
+ /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/,
62094
+ /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/
62095
+ ];
62096
+ function apply(patterns, input) {
62097
+ let out = input;
62098
+ for (const [pattern, replacement] of patterns) {
62099
+ out = out.replace(pattern, replacement);
62100
+ }
62101
+ return out;
62102
+ }
62103
+ function redactSecrets(input) {
62104
+ return apply(BASE_PATTERNS, input);
62105
+ }
62106
+ function redactContent(input) {
62107
+ return apply(EXTENDED_PATTERNS, apply(BASE_PATTERNS, input));
62108
+ }
62109
+ function redactOrDrop(input) {
62110
+ try {
62111
+ const value = redactContent(input);
62112
+ if (RESIDUAL_HIGH_RISK.some((p) => p.test(value))) {
62113
+ return { value: null, dropped: true };
62114
+ }
62115
+ return { value, dropped: false };
62116
+ } catch {
62117
+ return { value: null, dropped: true };
62118
+ }
62119
+ }
62120
+
62055
62121
  // ../../packages/cli/src/commands/status.ts
62056
62122
  init_cjs_shims();
62057
62123
  var import_picocolors = __toESM(require_picocolors(), 1);
@@ -63135,25 +63201,8 @@ function annotateAgainstBaseline(current, baseline) {
63135
63201
  current.newSignatures = newSignatures;
63136
63202
  return current;
63137
63203
  }
63138
- var REDACTION_PATTERNS = [
63139
- // Authorization headers (Bearer / Basic / API-key tokens)
63140
- [/(authorization\s*[=:]\s*)(bearer\s+)[^\s,"')]+/gi, "$1$2[REDACTED]"],
63141
- [/(authorization\s*[=:]\s*)(basic\s+)[^\s,"')]+/gi, "$1$2[REDACTED]"],
63142
- // Standalone password/token/secret keys in KV strings, query params, JSON
63143
- [/("?(?:password|passwd|secret|token|api[_-]key|apikey|x-api-key)"?\s*[=:]\s*)"?[^"',\s)>]+/gi, "$1[REDACTED]"],
63144
- // Cookie / set-cookie header values
63145
- [/((?:cookie|set-cookie)\s*[=:]\s*)[^\s"',;>]{4,}/gi, "$1[REDACTED]"],
63146
- // Database / service connection strings with embedded credentials
63147
- [/((?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis(?:s)?):\/\/)[^:@/\s]+:[^@\s]+@/gi, "$1[REDACTED]@"],
63148
- // 16-digit card-number-like sequences (PCIDSS)
63149
- [/\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g, "[REDACTED-CARD]"]
63150
- ];
63151
63204
  function redactSensitiveString(s) {
63152
- let out = s;
63153
- for (const [pattern, replacement] of REDACTION_PATTERNS) {
63154
- out = out.replace(pattern, replacement);
63155
- }
63156
- return out;
63205
+ return redactSecrets(s);
63157
63206
  }
63158
63207
  function redactErrorSignature(sig) {
63159
63208
  if (sig.sampleMessage === void 0) return sig;
@@ -66196,7 +66245,7 @@ function sql(strings, ...params) {
66196
66245
  return new SQL([new StringChunk(str3)]);
66197
66246
  }
66198
66247
  sql2.raw = raw;
66199
- function join11(chunks, separator) {
66248
+ function join13(chunks, separator) {
66200
66249
  const result = [];
66201
66250
  for (const [i, chunk] of chunks.entries()) {
66202
66251
  if (i > 0 && separator !== void 0) {
@@ -66206,7 +66255,7 @@ function sql(strings, ...params) {
66206
66255
  }
66207
66256
  return new SQL(result);
66208
66257
  }
66209
- sql2.join = join11;
66258
+ sql2.join = join13;
66210
66259
  function identifier(value) {
66211
66260
  return new Name(value);
66212
66261
  }
@@ -69797,7 +69846,7 @@ var PgSelectQueryBuilderBase = class extends TypedQueryBuilder {
69797
69846
  return (table, on) => {
69798
69847
  const baseTableName = this.tableName;
69799
69848
  const tableName = getTableLikeName(table);
69800
- if (typeof tableName === "string" && this.config.joins?.some((join11) => join11.alias === tableName)) {
69849
+ if (typeof tableName === "string" && this.config.joins?.some((join13) => join13.alias === tableName)) {
69801
69850
  throw new Error(`Alias "${tableName}" is already used in this query`);
69802
69851
  }
69803
69852
  if (!this.isPartialSelect) {
@@ -70809,7 +70858,7 @@ var PgUpdateBase = class extends QueryPromise {
70809
70858
  createJoin(joinType) {
70810
70859
  return (table, on) => {
70811
70860
  const tableName = getTableLikeName(table);
70812
- if (typeof tableName === "string" && this.config.joins.some((join11) => join11.alias === tableName)) {
70861
+ if (typeof tableName === "string" && this.config.joins.some((join13) => join13.alias === tableName)) {
70813
70862
  throw new Error(`Alias "${tableName}" is already used in this query`);
70814
70863
  }
70815
70864
  if (typeof on === "function") {
@@ -70905,10 +70954,10 @@ var PgUpdateBase = class extends QueryPromise {
70905
70954
  const fromFields = this.getTableLikeFields(this.config.from);
70906
70955
  fields[tableName] = fromFields;
70907
70956
  }
70908
- for (const join11 of this.config.joins) {
70909
- const tableName2 = getTableLikeName(join11.table);
70910
- if (typeof tableName2 === "string" && !is(join11.table, SQL)) {
70911
- const fromFields = this.getTableLikeFields(join11.table);
70957
+ for (const join13 of this.config.joins) {
70958
+ const tableName2 = getTableLikeName(join13.table);
70959
+ if (typeof tableName2 === "string" && !is(join13.table, SQL)) {
70960
+ const fromFields = this.getTableLikeFields(join13.table);
70912
70961
  fields[tableName2] = fromFields;
70913
70962
  }
70914
70963
  }
@@ -77143,7 +77192,12 @@ async function investigate(input, deps) {
77143
77192
  code.impact(top.id, 2),
77144
77193
  code.flowsFor(top.id)
77145
77194
  ]);
77146
- const edges = await listQueueEdges(db, { project: input.repo });
77195
+ let edges = [];
77196
+ try {
77197
+ edges = await listQueueEdges(db, { project: input.repo });
77198
+ } catch {
77199
+ edges = [];
77200
+ }
77147
77201
  const symbolNames = /* @__PURE__ */ new Set([
77148
77202
  top.name,
77149
77203
  ...ctx.callers.map((s) => s.name),
@@ -77826,9 +77880,9 @@ async function investigate(input, deps) {
77826
77880
  const confidence = clamp015(0.5 * evidenceConfidence + 0.5 * seedResolved);
77827
77881
  const area = ctx?.community?.name ?? top?.filePath ?? (input.service ?? "runtime evidence");
77828
77882
  const topCause = rankedCauses[0];
77829
- const banner = degradedNoSource ? "Runtime-only (source intelligence unavailable). " : "";
77883
+ const banner2 = degradedNoSource ? "Runtime-only (source intelligence unavailable). " : "";
77830
77884
  const scope = top ? `resolved to ${label} (${area})` : `over runtime evidence (${area})`;
77831
- const summary = topCause ? `${banner}Investigation of "${hint}" ${scope}. Top suspected cause: ${topCause.title}.` : `${banner}Investigation of "${hint}" ${scope}. No dominant suspected cause emerged from the available ${degradedNoSource ? "runtime" : "structural"} evidence.`;
77885
+ const summary = topCause ? `${banner2}Investigation of "${hint}" ${scope}. Top suspected cause: ${topCause.title}.` : `${banner2}Investigation of "${hint}" ${scope}. No dominant suspected cause emerged from the available ${degradedNoSource ? "runtime" : "structural"} evidence.`;
77832
77886
  const nextActions = buildNextActions(top, ctx, impact, queueHits, changes, input);
77833
77887
  if (degradedNoSource) {
77834
77888
  nextActions.unshift(
@@ -77889,6 +77943,7 @@ async function investigate(input, deps) {
77889
77943
  report.sourceStatus = buildRuntimeSourceStatus(evidence2, connectorFlags);
77890
77944
  const persistedId = await persist(db, input, report);
77891
77945
  if (persistedId) report.id = persistedId;
77946
+ report.persisted = persistedId !== null;
77892
77947
  if (persistedId !== null) {
77893
77948
  const tags = deriveTags(report);
77894
77949
  report.similarIncidents = await recallSimilar(db, tags, persistedId, input.repo ?? null);
@@ -80983,22 +81038,22 @@ function extractQueueGraph(input) {
80983
81038
  }
80984
81039
  }
80985
81040
  const producers = [];
80986
- for (const pc43 of input.producerClasses) {
80987
- for (const m of pc43.content.matchAll(INJECT_QUEUE_RE)) {
81041
+ for (const pc47 of input.producerClasses) {
81042
+ for (const m of pc47.content.matchAll(INJECT_QUEUE_RE)) {
80988
81043
  const queue = m[1] ?? "";
80989
- if (queue) producers.push({ queue, symbol: pc43.name, file: pc43.filePath });
81044
+ if (queue) producers.push({ queue, symbol: pc47.name, file: pc47.filePath });
80990
81045
  }
80991
- for (const m of pc43.content.matchAll(NEW_BULL_RE)) {
81046
+ for (const m of pc47.content.matchAll(NEW_BULL_RE)) {
80992
81047
  if (m[2] !== "Queue") continue;
80993
81048
  const queue = resolveArg(m[3] ?? "", constMap);
80994
81049
  if (queue) {
80995
- producers.push({ queue, symbol: (m[1] ?? pc43.name) || baseName(pc43.filePath), file: pc43.filePath });
81050
+ producers.push({ queue, symbol: (m[1] ?? pc47.name) || baseName(pc47.filePath), file: pc47.filePath });
80996
81051
  }
80997
81052
  }
80998
- for (const m of pc43.content.matchAll(QUEUE_NAME_CONST_RE)) {
81053
+ for (const m of pc47.content.matchAll(QUEUE_NAME_CONST_RE)) {
80999
81054
  const ident = m[1] ?? "";
81000
81055
  const queue = m[2] ?? "";
81001
- if (queue) producers.push({ queue, symbol: ident || baseName(pc43.filePath), file: pc43.filePath });
81056
+ if (queue) producers.push({ queue, symbol: ident || baseName(pc47.filePath), file: pc47.filePath });
81002
81057
  }
81003
81058
  }
81004
81059
  const workers = [];
@@ -90068,21 +90123,21 @@ var Protocol = class {
90068
90123
  * the error appropriately (e.g., by failing the task, logging, etc.). The Protocol layer
90069
90124
  * simply propagates the error.
90070
90125
  */
90071
- async _enqueueTaskMessage(taskId, message, sessionId) {
90126
+ async _enqueueTaskMessage(taskId, message, sessionId2) {
90072
90127
  if (!this._taskStore || !this._taskMessageQueue) {
90073
90128
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
90074
90129
  }
90075
90130
  const maxQueueSize = this._options?.maxTaskQueueSize;
90076
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
90131
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId2, maxQueueSize);
90077
90132
  }
90078
90133
  /**
90079
90134
  * Clears the message queue for a task and rejects any pending request resolvers.
90080
90135
  * @param taskId The task ID whose queue should be cleared
90081
90136
  * @param sessionId Optional session ID for binding the operation to a specific session
90082
90137
  */
90083
- async _clearTaskQueue(taskId, sessionId) {
90138
+ async _clearTaskQueue(taskId, sessionId2) {
90084
90139
  if (this._taskMessageQueue) {
90085
- const messages2 = await this._taskMessageQueue.dequeueAll(taskId, sessionId);
90140
+ const messages2 = await this._taskMessageQueue.dequeueAll(taskId, sessionId2);
90086
90141
  for (const message of messages2) {
90087
90142
  if (message.type === "request" && isJSONRPCRequest(message.message)) {
90088
90143
  const requestId = message.message.id;
@@ -90125,7 +90180,7 @@ var Protocol = class {
90125
90180
  }, { once: true });
90126
90181
  });
90127
90182
  }
90128
- requestTaskStore(request, sessionId) {
90183
+ requestTaskStore(request, sessionId2) {
90129
90184
  const taskStore = this._taskStore;
90130
90185
  if (!taskStore) {
90131
90186
  throw new Error("No task store configured");
@@ -90138,18 +90193,18 @@ var Protocol = class {
90138
90193
  return await taskStore.createTask(taskParams, request.id, {
90139
90194
  method: request.method,
90140
90195
  params: request.params
90141
- }, sessionId);
90196
+ }, sessionId2);
90142
90197
  },
90143
90198
  getTask: async (taskId) => {
90144
- const task = await taskStore.getTask(taskId, sessionId);
90199
+ const task = await taskStore.getTask(taskId, sessionId2);
90145
90200
  if (!task) {
90146
90201
  throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
90147
90202
  }
90148
90203
  return task;
90149
90204
  },
90150
90205
  storeTaskResult: async (taskId, status, result) => {
90151
- await taskStore.storeTaskResult(taskId, status, result, sessionId);
90152
- const task = await taskStore.getTask(taskId, sessionId);
90206
+ await taskStore.storeTaskResult(taskId, status, result, sessionId2);
90207
+ const task = await taskStore.getTask(taskId, sessionId2);
90153
90208
  if (task) {
90154
90209
  const notification = TaskStatusNotificationSchema.parse({
90155
90210
  method: "notifications/tasks/status",
@@ -90162,18 +90217,18 @@ var Protocol = class {
90162
90217
  }
90163
90218
  },
90164
90219
  getTaskResult: (taskId) => {
90165
- return taskStore.getTaskResult(taskId, sessionId);
90220
+ return taskStore.getTaskResult(taskId, sessionId2);
90166
90221
  },
90167
90222
  updateTaskStatus: async (taskId, status, statusMessage) => {
90168
- const task = await taskStore.getTask(taskId, sessionId);
90223
+ const task = await taskStore.getTask(taskId, sessionId2);
90169
90224
  if (!task) {
90170
90225
  throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
90171
90226
  }
90172
90227
  if (isTerminal(task.status)) {
90173
90228
  throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
90174
90229
  }
90175
- await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
90176
- const updatedTask = await taskStore.getTask(taskId, sessionId);
90230
+ await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId2);
90231
+ const updatedTask = await taskStore.getTask(taskId, sessionId2);
90177
90232
  if (updatedTask) {
90178
90233
  const notification = TaskStatusNotificationSchema.parse({
90179
90234
  method: "notifications/tasks/status",
@@ -90186,7 +90241,7 @@ var Protocol = class {
90186
90241
  }
90187
90242
  },
90188
90243
  listTasks: (cursor) => {
90189
- return taskStore.listTasks(cursor, sessionId);
90244
+ return taskStore.listTasks(cursor, sessionId2);
90190
90245
  }
90191
90246
  };
90192
90247
  }
@@ -90540,8 +90595,8 @@ var Server = class extends Protocol {
90540
90595
  this._serverInfo = _serverInfo;
90541
90596
  this._loggingLevels = /* @__PURE__ */ new Map();
90542
90597
  this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index2) => [level, index2]));
90543
- this.isMessageIgnored = (level, sessionId) => {
90544
- const currentLevel = this._loggingLevels.get(sessionId);
90598
+ this.isMessageIgnored = (level, sessionId2) => {
90599
+ const currentLevel = this._loggingLevels.get(sessionId2);
90545
90600
  return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
90546
90601
  };
90547
90602
  this._capabilities = options?.capabilities ?? {};
@@ -90884,9 +90939,9 @@ var Server = class extends Protocol {
90884
90939
  * @param params
90885
90940
  * @param sessionId optional for stateless and backward compatibility
90886
90941
  */
90887
- async sendLoggingMessage(params, sessionId) {
90942
+ async sendLoggingMessage(params, sessionId2) {
90888
90943
  if (this._capabilities.logging) {
90889
- if (!this.isMessageIgnored(params.level, sessionId)) {
90944
+ if (!this.isMessageIgnored(params.level, sessionId2)) {
90890
90945
  return this.notification({ method: "notifications/message", params });
90891
90946
  }
90892
90947
  }
@@ -91691,8 +91746,8 @@ var McpServer = class {
91691
91746
  * @param params
91692
91747
  * @param sessionId optional for stateless and backward compatibility
91693
91748
  */
91694
- async sendLoggingMessage(params, sessionId) {
91695
- return this.server.sendLoggingMessage(params, sessionId);
91749
+ async sendLoggingMessage(params, sessionId2) {
91750
+ return this.server.sendLoggingMessage(params, sessionId2);
91696
91751
  }
91697
91752
  /**
91698
91753
  * Sends a resource list changed event to the client, if connected.
@@ -93743,7 +93798,7 @@ function formatAge(ms) {
93743
93798
 
93744
93799
  // ../../packages/cli/src/commands/investigate.ts
93745
93800
  init_cjs_shims();
93746
- var import_picocolors8 = __toESM(require_picocolors(), 1);
93801
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
93747
93802
 
93748
93803
  // ../../packages/cli/src/lib/cloud/investigation-sync.ts
93749
93804
  init_cjs_shims();
@@ -93820,6 +93875,345 @@ async function listCloudInvestigations(client, cfg) {
93820
93875
  return result.investigations;
93821
93876
  }
93822
93877
 
93878
+ // ../../packages/cli/src/lib/telemetry/client.ts
93879
+ init_cjs_shims();
93880
+ var import_node_crypto6 = require("crypto");
93881
+ var import_node_os3 = require("os");
93882
+
93883
+ // ../../packages/cli/src/lib/telemetry/consent.ts
93884
+ init_cjs_shims();
93885
+
93886
+ // ../../packages/cli/src/lib/telemetry/store.ts
93887
+ init_cjs_shims();
93888
+ var import_node_fs13 = require("fs");
93889
+ var import_node_crypto5 = require("crypto");
93890
+
93891
+ // ../../packages/cli/src/lib/telemetry/paths.ts
93892
+ init_cjs_shims();
93893
+ var import_node_path14 = require("path");
93894
+ var TELEMETRY_FILE = "telemetry.json";
93895
+ var TELEMETRY_QUEUE_DIR = "telemetry-queue";
93896
+ function telemetryPath() {
93897
+ return (0, import_node_path14.join)(horusHome(), TELEMETRY_FILE);
93898
+ }
93899
+ function telemetryQueueDir() {
93900
+ return (0, import_node_path14.join)(horusHome(), TELEMETRY_QUEUE_DIR);
93901
+ }
93902
+
93903
+ // ../../packages/cli/src/lib/telemetry/store.ts
93904
+ var TELEMETRY_SCHEMA_VERSION = 1;
93905
+ function nowIso() {
93906
+ return (/* @__PURE__ */ new Date()).toISOString();
93907
+ }
93908
+ function defaultTelemetryState(installId = (0, import_node_crypto5.randomUUID)()) {
93909
+ const now = nowIso();
93910
+ return {
93911
+ schemaVersion: TELEMETRY_SCHEMA_VERSION,
93912
+ installId,
93913
+ tierA: { enabled: true, noticeShownAt: null },
93914
+ tierB: { enabled: false, enabledAt: null },
93915
+ createdAt: now,
93916
+ updatedAt: now
93917
+ };
93918
+ }
93919
+ function coerce2(raw) {
93920
+ if (!raw || typeof raw !== "object") return null;
93921
+ const r = raw;
93922
+ if (typeof r.installId !== "string" || r.installId.length === 0) return null;
93923
+ const tierA = r.tierA ?? {};
93924
+ const tierB = r.tierB ?? {};
93925
+ return {
93926
+ schemaVersion: typeof r.schemaVersion === "number" ? r.schemaVersion : TELEMETRY_SCHEMA_VERSION,
93927
+ installId: r.installId,
93928
+ tierA: {
93929
+ enabled: typeof tierA.enabled === "boolean" ? tierA.enabled : true,
93930
+ noticeShownAt: typeof tierA.noticeShownAt === "string" ? tierA.noticeShownAt : null
93931
+ },
93932
+ tierB: {
93933
+ enabled: typeof tierB.enabled === "boolean" ? tierB.enabled : false,
93934
+ enabledAt: typeof tierB.enabledAt === "string" ? tierB.enabledAt : null
93935
+ },
93936
+ createdAt: typeof r.createdAt === "string" ? r.createdAt : nowIso(),
93937
+ updatedAt: typeof r.updatedAt === "string" ? r.updatedAt : nowIso()
93938
+ };
93939
+ }
93940
+ function readTelemetryState() {
93941
+ const p = telemetryPath();
93942
+ if (!(0, import_node_fs13.existsSync)(p)) return null;
93943
+ try {
93944
+ return coerce2(JSON.parse((0, import_node_fs13.readFileSync)(p, "utf8")));
93945
+ } catch {
93946
+ return null;
93947
+ }
93948
+ }
93949
+ function writeTelemetryState(state) {
93950
+ (0, import_node_fs13.mkdirSync)(horusHome(), { recursive: true });
93951
+ const p = telemetryPath();
93952
+ const tmp = `${p}.${process.pid}.tmp`;
93953
+ (0, import_node_fs13.writeFileSync)(tmp, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
93954
+ try {
93955
+ (0, import_node_fs13.renameSync)(tmp, p);
93956
+ } catch (err) {
93957
+ try {
93958
+ (0, import_node_fs13.rmSync)(tmp);
93959
+ } catch {
93960
+ }
93961
+ throw err;
93962
+ }
93963
+ try {
93964
+ (0, import_node_fs13.chmodSync)(p, 384);
93965
+ } catch {
93966
+ }
93967
+ }
93968
+ function loadOrInitTelemetryState() {
93969
+ const existing = readTelemetryState();
93970
+ if (existing) return existing;
93971
+ const created = defaultTelemetryState();
93972
+ writeTelemetryState(created);
93973
+ return created;
93974
+ }
93975
+ function updateTelemetryState(mutate) {
93976
+ const state = loadOrInitTelemetryState();
93977
+ mutate(state);
93978
+ state.updatedAt = nowIso();
93979
+ writeTelemetryState(state);
93980
+ return state;
93981
+ }
93982
+ function deleteTelemetryState() {
93983
+ const p = telemetryPath();
93984
+ if ((0, import_node_fs13.existsSync)(p)) (0, import_node_fs13.rmSync)(p);
93985
+ }
93986
+
93987
+ // ../../packages/cli/src/lib/telemetry/consent.ts
93988
+ var OFF_VALUES = /* @__PURE__ */ new Set(["0", "false", "off", "no", "disable", "disabled"]);
93989
+ var ON_VALUES = /* @__PURE__ */ new Set(["1", "true", "on", "yes", "enable", "enabled", "all"]);
93990
+ var CI_ENV_VARS = [
93991
+ "CI",
93992
+ "CONTINUOUS_INTEGRATION",
93993
+ "GITHUB_ACTIONS",
93994
+ "GITLAB_CI",
93995
+ "BUILDKITE",
93996
+ "CIRCLECI",
93997
+ "TRAVIS",
93998
+ "JENKINS_URL",
93999
+ "TEAMCITY_VERSION"
94000
+ ];
94001
+ function doNotTrack(env) {
94002
+ const v = env.DO_NOT_TRACK;
94003
+ if (v == null || v === "") return false;
94004
+ return !OFF_VALUES.has(v.trim().toLowerCase());
94005
+ }
94006
+ function parseEnvFlag(value) {
94007
+ if (value == null || value === "") return void 0;
94008
+ const v = value.trim().toLowerCase();
94009
+ if (OFF_VALUES.has(v)) return "off";
94010
+ if (ON_VALUES.has(v)) return "on";
94011
+ return void 0;
94012
+ }
94013
+ function isCI(env = process.env) {
94014
+ return CI_ENV_VARS.some((key) => {
94015
+ const v = env[key];
94016
+ return v != null && v !== "" && !OFF_VALUES.has(v.trim().toLowerCase());
94017
+ });
94018
+ }
94019
+ function off(source, reason) {
94020
+ return { tierA: false, tierB: false, forcedOff: source === "env", source, reason };
94021
+ }
94022
+ function resolveConsent(opts = {}) {
94023
+ const env = opts.env ?? process.env;
94024
+ if (doNotTrack(env)) return off("env", "DO_NOT_TRACK is set");
94025
+ const envFlag = parseEnvFlag(env.HORUS_TELEMETRY);
94026
+ if (envFlag === "off") return off("env", "HORUS_TELEMETRY disables telemetry");
94027
+ const state = opts.state !== void 0 ? opts.state : readTelemetryState();
94028
+ const storedTierA = state?.tierA.enabled ?? true;
94029
+ const storedTierB = state?.tierB.enabled ?? false;
94030
+ if (isCI(env) && envFlag !== "on") {
94031
+ return {
94032
+ tierA: false,
94033
+ tierB: false,
94034
+ forcedOff: false,
94035
+ source: "ci",
94036
+ reason: "CI environment detected \u2014 telemetry off by default"
94037
+ };
94038
+ }
94039
+ if (envFlag === "on") {
94040
+ return {
94041
+ tierA: true,
94042
+ tierB: storedTierB,
94043
+ forcedOff: false,
94044
+ source: "env",
94045
+ reason: "HORUS_TELEMETRY enables usage metadata"
94046
+ };
94047
+ }
94048
+ return {
94049
+ tierA: storedTierA,
94050
+ tierB: storedTierB,
94051
+ forcedOff: false,
94052
+ source: state ? "state" : "default",
94053
+ reason: state ? "from ~/.horus/telemetry.json" : "default settings (no saved preference)"
94054
+ };
94055
+ }
94056
+ function isContentSharingEnabled(env = process.env) {
94057
+ return resolveConsent({ env }).tierB;
94058
+ }
94059
+
94060
+ // ../../packages/cli/src/lib/telemetry/spool.ts
94061
+ init_cjs_shims();
94062
+ var import_node_fs14 = require("fs");
94063
+ var import_node_path15 = require("path");
94064
+ var SPOOL_FILE = "events.jsonl";
94065
+ var MAX_SPOOL_BYTES = 256 * 1024;
94066
+ function spoolFilePath() {
94067
+ return (0, import_node_path15.join)(telemetryQueueDir(), SPOOL_FILE);
94068
+ }
94069
+ function spoolEvent(event) {
94070
+ try {
94071
+ (0, import_node_fs14.mkdirSync)(telemetryQueueDir(), { recursive: true });
94072
+ const file = spoolFilePath();
94073
+ let size2 = 0;
94074
+ try {
94075
+ size2 = (0, import_node_fs14.statSync)(file).size;
94076
+ } catch {
94077
+ }
94078
+ if (size2 >= MAX_SPOOL_BYTES) return;
94079
+ (0, import_node_fs14.appendFileSync)(file, JSON.stringify(event) + "\n", { mode: 384 });
94080
+ } catch {
94081
+ }
94082
+ }
94083
+ function readSpooledEvents() {
94084
+ try {
94085
+ const file = spoolFilePath();
94086
+ if (!(0, import_node_fs14.existsSync)(file)) return [];
94087
+ return (0, import_node_fs14.readFileSync)(file, "utf8").split("\n").filter((line2) => line2.trim().length > 0).map((line2) => {
94088
+ try {
94089
+ return JSON.parse(line2);
94090
+ } catch {
94091
+ return null;
94092
+ }
94093
+ }).filter((e) => e !== null);
94094
+ } catch {
94095
+ return [];
94096
+ }
94097
+ }
94098
+ function clearSpool() {
94099
+ try {
94100
+ const file = spoolFilePath();
94101
+ if ((0, import_node_fs14.existsSync)(file)) (0, import_node_fs14.rmSync)(file);
94102
+ } catch {
94103
+ }
94104
+ }
94105
+
94106
+ // ../../packages/cli/src/lib/telemetry/events.ts
94107
+ init_cjs_shims();
94108
+ var TELEMETRY_EVENT_SCHEMA_VERSION = 1;
94109
+ var TIER_B_EVENT_TYPES = /* @__PURE__ */ new Set(["investigation.content"]);
94110
+ function tierForEventType(type) {
94111
+ return TIER_B_EVENT_TYPES.has(type) ? "B" : "A";
94112
+ }
94113
+ function extractFlagNames(argv) {
94114
+ const names = /* @__PURE__ */ new Set();
94115
+ for (const token of argv.slice(2)) {
94116
+ if (token.startsWith("--") && token.length > 2) {
94117
+ const name = token.slice(2).split("=")[0];
94118
+ if (name) names.add(name);
94119
+ }
94120
+ }
94121
+ return [...names];
94122
+ }
94123
+
94124
+ // ../../packages/cli/src/lib/telemetry/client.ts
94125
+ var sessionId = null;
94126
+ function getSessionId() {
94127
+ if (!sessionId) sessionId = (0, import_node_crypto6.randomUUID)();
94128
+ return sessionId;
94129
+ }
94130
+ function track(input) {
94131
+ try {
94132
+ const state = readTelemetryState();
94133
+ if (!state) return;
94134
+ const tier = tierForEventType(input.type);
94135
+ const decision = resolveConsent({ state });
94136
+ if (tier === "A" ? !decision.tierA : !decision.tierB) return;
94137
+ const event = {
94138
+ schemaVersion: TELEMETRY_EVENT_SCHEMA_VERSION,
94139
+ tier,
94140
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
94141
+ installId: state.installId,
94142
+ sessionId: getSessionId(),
94143
+ cliVersion: HORUS_VERSION,
94144
+ os: (0, import_node_os3.platform)(),
94145
+ arch: (0, import_node_os3.arch)(),
94146
+ ...input
94147
+ };
94148
+ spoolEvent(event);
94149
+ } catch {
94150
+ }
94151
+ }
94152
+
94153
+ // ../../packages/cli/src/lib/telemetry/feedback.ts
94154
+ init_cjs_shims();
94155
+ var import_promises = require("readline/promises");
94156
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
94157
+ var MANUAL_MINUTES = {
94158
+ "1": 5,
94159
+ // < 5 min
94160
+ "2": 30,
94161
+ // ~30 min
94162
+ "3": 120,
94163
+ // ~2 h
94164
+ "4": 480,
94165
+ // half-day+
94166
+ "5": null
94167
+ // unsure
94168
+ };
94169
+ function parseResolved(raw) {
94170
+ const v = raw.trim().toLowerCase();
94171
+ if (v.startsWith("y")) return "yes";
94172
+ if (v.startsWith("p")) return "partly";
94173
+ if (v.startsWith("n")) return "no";
94174
+ return null;
94175
+ }
94176
+ function parseManualEstimate(raw) {
94177
+ return MANUAL_MINUTES[raw.trim()] ?? null;
94178
+ }
94179
+ function submitFeedback(input) {
94180
+ track({ type: "feedback.submitted", ...input });
94181
+ }
94182
+ async function runFeedbackPrompt(investigationId, horusSeconds) {
94183
+ const rl = (0, import_promises.createInterface)({ input: process.stdin, output: process.stdout });
94184
+ try {
94185
+ console.log(import_picocolors8.default.dim("\nQuick feedback to improve Horus (press Enter to skip):"));
94186
+ const a1 = await rl.question(
94187
+ import_picocolors8.default.bold(" Did this point you at the cause? ") + import_picocolors8.default.dim("[y / partly / n] ")
94188
+ );
94189
+ if (a1.trim() === "") return false;
94190
+ const a2 = await rl.question(
94191
+ import_picocolors8.default.bold(" Manually, finding this would have taken? ") + import_picocolors8.default.dim("[1:<5m 2:~30m 3:~2h 4:half-day+ 5:unsure] ")
94192
+ );
94193
+ submitFeedback({
94194
+ investigationId,
94195
+ resolved: parseResolved(a1),
94196
+ manualEstimateMinutes: parseManualEstimate(a2),
94197
+ horusSeconds
94198
+ });
94199
+ console.log(import_picocolors8.default.dim(" Thanks \u2014 recorded."));
94200
+ return true;
94201
+ } finally {
94202
+ rl.close();
94203
+ }
94204
+ }
94205
+ async function maybePromptFeedback(opts) {
94206
+ try {
94207
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return;
94208
+ if (!resolveConsent().tierA) return;
94209
+ const rate = opts.sampleRate ?? 0.25;
94210
+ const rand = (opts.random ?? Math.random)();
94211
+ if (rand > rate) return;
94212
+ await runFeedbackPrompt(opts.investigationId, opts.horusSeconds ?? null);
94213
+ } catch {
94214
+ }
94215
+ }
94216
+
93823
94217
  // ../../packages/cli/src/lib/ensure-host.ts
93824
94218
  init_cjs_shims();
93825
94219
  function parseHostPort(hostUrl) {
@@ -93912,37 +94306,37 @@ function renderStoredAIJudgment(judgment, write = (l) => console.log(l)) {
93912
94306
  const sep = "\u2500".repeat(60);
93913
94307
  write(`
93914
94308
  ${sep}`);
93915
- write(import_picocolors8.default.bold("AI Judgment") + import_picocolors8.default.dim(` (confidence: ${(judgment.confidence * 100).toFixed(0)}%, provider: ${judgment.provider})`));
94309
+ write(import_picocolors9.default.bold("AI Judgment") + import_picocolors9.default.dim(` (confidence: ${(judgment.confidence * 100).toFixed(0)}%, provider: ${judgment.provider})`));
93916
94310
  write(sep);
93917
94311
  if (judgment.hypothesisJudgments && judgment.hypothesisJudgments.length > 0) {
93918
- write(import_picocolors8.default.bold("Hypothesis verdicts:"));
94312
+ write(import_picocolors9.default.bold("Hypothesis verdicts:"));
93919
94313
  for (const j of judgment.hypothesisJudgments) {
93920
- const verdictColor = j.verdict === "supported" ? import_picocolors8.default.green : j.verdict === "weakened" ? import_picocolors8.default.yellow : j.verdict === "eliminated" ? import_picocolors8.default.red : import_picocolors8.default.dim;
93921
- write(` ${verdictColor(`[${j.verdict}]`)} ${j.category}` + import_picocolors8.default.dim(` (${(j.confidence * 100).toFixed(0)}%)`));
93922
- write(import_picocolors8.default.dim(` ${j.rationale}`));
94314
+ const verdictColor = j.verdict === "supported" ? import_picocolors9.default.green : j.verdict === "weakened" ? import_picocolors9.default.yellow : j.verdict === "eliminated" ? import_picocolors9.default.red : import_picocolors9.default.dim;
94315
+ write(` ${verdictColor(`[${j.verdict}]`)} ${j.category}` + import_picocolors9.default.dim(` (${(j.confidence * 100).toFixed(0)}%)`));
94316
+ write(import_picocolors9.default.dim(` ${j.rationale}`));
93923
94317
  }
93924
94318
  write("");
93925
94319
  }
93926
94320
  if (judgment.rootCauseAssessment) {
93927
94321
  const rca = judgment.rootCauseAssessment;
93928
- const uncertaintyColor = rca.uncertainty === "low" ? import_picocolors8.default.green : rca.uncertainty === "medium" ? import_picocolors8.default.yellow : import_picocolors8.default.red;
93929
- write(import_picocolors8.default.bold("Root cause assessment:") + import_picocolors8.default.dim(` uncertainty: ${uncertaintyColor(rca.uncertainty)}`));
94322
+ const uncertaintyColor = rca.uncertainty === "low" ? import_picocolors9.default.green : rca.uncertainty === "medium" ? import_picocolors9.default.yellow : import_picocolors9.default.red;
94323
+ write(import_picocolors9.default.bold("Root cause assessment:") + import_picocolors9.default.dim(` uncertainty: ${uncertaintyColor(rca.uncertainty)}`));
93930
94324
  write(rca.summary);
93931
94325
  if (rca.citedEvidenceIds.length > 0) {
93932
- write(import_picocolors8.default.dim(` Cited: ${rca.citedEvidenceIds.join(", ")}`));
94326
+ write(import_picocolors9.default.dim(` Cited: ${rca.citedEvidenceIds.join(", ")}`));
93933
94327
  }
93934
94328
  write("");
93935
94329
  }
93936
- write(import_picocolors8.default.bold("What:") + " " + judgment.what);
93937
- write(import_picocolors8.default.bold("Why:") + " " + judgment.why);
94330
+ write(import_picocolors9.default.bold("What:") + " " + judgment.what);
94331
+ write(import_picocolors9.default.bold("Why:") + " " + judgment.why);
93938
94332
  if (judgment.whereNext.length > 0) {
93939
- write(import_picocolors8.default.bold("Next steps:"));
94333
+ write(import_picocolors9.default.bold("Next steps:"));
93940
94334
  for (const step of judgment.whereNext) {
93941
94335
  write(` \u2022 ${step}`);
93942
94336
  }
93943
94337
  }
93944
94338
  if (judgment.citations.length > 0) {
93945
- write(import_picocolors8.default.dim(`
94339
+ write(import_picocolors9.default.dim(`
93946
94340
  Cited evidence: ${judgment.citations.map((c) => c.evidenceId).join(", ")}`));
93947
94341
  }
93948
94342
  }
@@ -93960,6 +94354,7 @@ function classifyAIFailure(firstError) {
93960
94354
  return firstError;
93961
94355
  }
93962
94356
  async function runInvestigate(hint, opts) {
94357
+ const startedAtMs = Date.now();
93963
94358
  try {
93964
94359
  const config2 = await loadConfig(opts.config, { name: opts.name });
93965
94360
  const projectName = opts.project ?? opts.repo;
@@ -93967,7 +94362,7 @@ async function runInvestigate(hint, opts) {
93967
94362
  try {
93968
94363
  renv = resolveEnvironment(config2, { project: projectName, env: opts.env });
93969
94364
  } catch (err) {
93970
- console.error(import_picocolors8.default.red(err.message));
94365
+ console.error(import_picocolors9.default.red(err.message));
93971
94366
  return 1;
93972
94367
  }
93973
94368
  const repoRoot = repoRootOrCwd(renv.path);
@@ -93976,16 +94371,15 @@ async function runInvestigate(hint, opts) {
93976
94371
  const cloudSession = cloudActive ? authedClient() : null;
93977
94372
  if (cloudActive && !cloudSession) {
93978
94373
  console.error(
93979
- import_picocolors8.default.red(
93980
- `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors8.default.bold("horus login")} first.`
94374
+ import_picocolors9.default.yellow(
94375
+ `This repo is linked to Horus Cloud but you are not logged in \u2014 running locally only. Run ${import_picocolors9.default.bold("horus login")} to also sync results to the cloud.`
93981
94376
  )
93982
94377
  );
93983
- return 1;
93984
94378
  }
93985
94379
  const code = codeForEnv(renv);
93986
94380
  if (!code) {
93987
94381
  console.error(
93988
- import_picocolors8.default.red(
94382
+ import_picocolors9.default.red(
93989
94383
  `No source-intelligence connector configured for project "${renv.project}" / env "${renv.env}".`
93990
94384
  )
93991
94385
  );
@@ -93995,21 +94389,21 @@ async function runInvestigate(hint, opts) {
93995
94389
  let health = await code.health();
93996
94390
  if (!health.ok && sourceUrl) {
93997
94391
  console.error(
93998
- import_picocolors8.default.yellow(`Source-intelligence host unreachable (${sourceUrl}) \u2014 attempting to start it\u2026`)
94392
+ import_picocolors9.default.yellow(`Source-intelligence host unreachable (${sourceUrl}) \u2014 attempting to start it\u2026`)
93999
94393
  );
94000
94394
  const healed = await ensureSourceHost(renv.path, sourceUrl);
94001
94395
  if (healed.ok) {
94002
- console.error(import_picocolors8.default.green(`Source-intelligence host is up at ${healed.hostUrl}.`));
94396
+ console.error(import_picocolors9.default.green(`Source-intelligence host is up at ${healed.hostUrl}.`));
94003
94397
  health = await code.health();
94004
94398
  } else {
94005
- console.error(import_picocolors8.default.dim(` ${ensureHostReasonHint(healed.reason)}`));
94399
+ console.error(import_picocolors9.default.dim(` ${ensureHostReasonHint(healed.reason)}`));
94006
94400
  }
94007
94401
  }
94008
94402
  const runtimeOnly = !health.ok;
94009
94403
  if (runtimeOnly) {
94010
94404
  console.error(
94011
- import_picocolors8.default.yellow(
94012
- `Proceeding in runtime-only mode \u2014 no source intelligence. Run ${import_picocolors8.default.bold("horus index")} for a full (code-aware) investigation.`
94405
+ import_picocolors9.default.yellow(
94406
+ `Proceeding in runtime-only mode \u2014 no source intelligence. Run ${import_picocolors9.default.bold("horus index")} for a full (code-aware) investigation.`
94013
94407
  )
94014
94408
  );
94015
94409
  }
@@ -94054,7 +94448,7 @@ async function runInvestigate(hint, opts) {
94054
94448
  model,
94055
94449
  ...ai.anthropicApiKey !== void 0 ? { apiKey: ai.anthropicApiKey } : {}
94056
94450
  });
94057
- console.log(import_picocolors8.default.dim(`[ai] model: ${model}`));
94451
+ console.log(import_picocolors9.default.dim(`[ai] model: ${model}`));
94058
94452
  const narrativeInput = buildNarrativeInput(report);
94059
94453
  const { output, fromProvider, degraded, validationErrors } = await renderNarrative(
94060
94454
  narrativeInput,
@@ -94070,37 +94464,78 @@ async function runInvestigate(hint, opts) {
94070
94464
  renderStoredAIJudgment(stored);
94071
94465
  } else if (degraded) {
94072
94466
  if (validationErrors && validationErrors.length > 0) {
94073
- console.error(import_picocolors8.default.yellow(`[ai] structured validation incomplete \u2014 showing raw AI narrative`));
94467
+ console.error(import_picocolors9.default.yellow(`[ai] structured validation incomplete \u2014 showing raw AI narrative`));
94074
94468
  }
94075
94469
  console.log("");
94076
- console.log(import_picocolors8.default.dim("\u2500".repeat(60)));
94077
- console.log(import_picocolors8.default.bold("AI narrative ") + import_picocolors8.default.yellow("(unstructured \u2014 not validated)"));
94470
+ console.log(import_picocolors9.default.dim("\u2500".repeat(60)));
94471
+ console.log(import_picocolors9.default.bold("AI narrative ") + import_picocolors9.default.yellow("(unstructured \u2014 not validated)"));
94078
94472
  if (output.what?.trim()) {
94079
- console.log(import_picocolors8.default.bold("\nWhat:"), output.what.trim());
94473
+ console.log(import_picocolors9.default.bold("\nWhat:"), output.what.trim());
94080
94474
  }
94081
94475
  if (output.why?.trim()) {
94082
- console.log(import_picocolors8.default.bold("\nWhy:"), output.why.trim());
94476
+ console.log(import_picocolors9.default.bold("\nWhy:"), output.why.trim());
94083
94477
  }
94084
94478
  if (output.whereNext.length > 0) {
94085
- console.log(import_picocolors8.default.bold("\nNext:"));
94479
+ console.log(import_picocolors9.default.bold("\nNext:"));
94086
94480
  for (const a of output.whereNext) console.log(` - ${a}`);
94087
94481
  }
94088
94482
  } else {
94089
94483
  const reason = classifyAIFailure(validationErrors?.[0]);
94090
- console.error(import_picocolors8.default.yellow(`[ai] fallback to deterministic \u2014 ${reason}`));
94484
+ console.error(import_picocolors9.default.yellow(`[ai] fallback to deterministic \u2014 ${reason}`));
94485
+ }
94486
+ }
94487
+ track({
94488
+ type: "investigation.completed",
94489
+ investigationId: report.id,
94490
+ confidence: typeof report.confidence === "number" ? report.confidence : null,
94491
+ evidenceCount: report.evidence?.length ?? 0,
94492
+ findingCount: report.findings?.length ?? 0,
94493
+ suspectedCauseCount: report.suspectedCauses?.length ?? 0,
94494
+ degraded: Boolean(report.degraded),
94495
+ gapCount: report.gapAnalysis?.gaps?.length ?? 0,
94496
+ hasAi: Boolean(report.aiJudgment)
94497
+ });
94498
+ if (isContentSharingEnabled()) {
94499
+ const hint2 = redactOrDrop(report.input.hint ?? "");
94500
+ if (!hint2.dropped) {
94501
+ track({
94502
+ type: "investigation.content",
94503
+ investigationId: report.id,
94504
+ hint: hint2.value ?? "",
94505
+ summary: redactContent(report.summary ?? ""),
94506
+ findingTitles: (report.findings ?? []).slice(0, 20).map((f) => redactContent(f.title ?? "")),
94507
+ suspectedCauseTitles: (report.suspectedCauses ?? []).slice(0, 20).map((c) => redactContent(c.title ?? "")),
94508
+ confidence: typeof report.confidence === "number" ? report.confidence : null
94509
+ });
94091
94510
  }
94092
94511
  }
94093
94512
  if (cloudActive && cloudSession && cloudCfg) {
94094
94513
  try {
94095
94514
  const refs = await uploadInvestigationToCloud(cloudSession.client, cloudCfg, report);
94096
- console.log(import_picocolors8.default.dim(`[cloud] investigation saved: ${refs.investigationId}`));
94515
+ console.log(import_picocolors9.default.dim(`[cloud] investigation saved: ${refs.investigationId}`));
94097
94516
  } catch (err) {
94098
94517
  return reportCloudError(err);
94099
94518
  }
94100
94519
  }
94101
94520
  if (format !== "json") {
94102
- console.log(import_picocolors8.default.dim(`
94521
+ if (report.persisted === false) {
94522
+ console.error(
94523
+ import_picocolors9.default.yellow(`
94524
+ \u26A0 Results were not saved \u2014 the investigation database was unreachable.`)
94525
+ );
94526
+ console.error(
94527
+ import_picocolors9.default.dim(
94528
+ ` This report is display-only; \`horus ask\` won't find it. Start the database and re-run to persist.`
94529
+ )
94530
+ );
94531
+ } else {
94532
+ console.log(import_picocolors9.default.dim(`
94103
94533
  Ask a follow-up: horus ask ${report.id} "<question>"`));
94534
+ }
94535
+ await maybePromptFeedback({
94536
+ investigationId: report.id,
94537
+ horusSeconds: (Date.now() - startedAtMs) / 1e3
94538
+ });
94104
94539
  }
94105
94540
  } finally {
94106
94541
  await sql2.end();
@@ -94109,14 +94544,16 @@ Ask a follow-up: horus ask ${report.id} "<question>"`));
94109
94544
  }
94110
94545
  return 0;
94111
94546
  } catch (err) {
94112
- console.error(import_picocolors8.default.red(err.message));
94547
+ const msg = err?.message || String(err);
94548
+ console.error(import_picocolors9.default.red(msg.trim() ? msg : "Investigation failed (unknown error)."));
94549
+ if (process.env.HORUS_DEBUG) console.error(import_picocolors9.default.dim(err?.stack ?? String(err)));
94113
94550
  return 1;
94114
94551
  }
94115
94552
  }
94116
94553
 
94117
94554
  // ../../packages/cli/src/commands/changes.ts
94118
94555
  init_cjs_shims();
94119
- var import_picocolors9 = __toESM(require_picocolors(), 1);
94556
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
94120
94557
  var CHANGES_AI_CONTRACT = `Provide a clearly separated AI change-impact review with:
94121
94558
 
94122
94559
  Highest-risk changes
@@ -94141,7 +94578,7 @@ async function runChanges(base2, compare, opts) {
94141
94578
  const health = await code.health();
94142
94579
  if (!health.ok) {
94143
94580
  console.error(
94144
- import_picocolors9.default.red("Source-intelligence host unreachable \u2014 run: horus index")
94581
+ import_picocolors10.default.red("Source-intelligence host unreachable \u2014 run: horus index")
94145
94582
  );
94146
94583
  return 1;
94147
94584
  }
@@ -94163,20 +94600,20 @@ async function runChanges(base2, compare, opts) {
94163
94600
  });
94164
94601
  console.log("\n" + renderInterpretation(result));
94165
94602
  if (!result.ok) {
94166
- console.error(import_picocolors9.default.yellow(`[ai] ${result.warning}`));
94603
+ console.error(import_picocolors10.default.yellow(`[ai] ${result.warning}`));
94167
94604
  }
94168
94605
  }
94169
94606
  }
94170
94607
  return 0;
94171
94608
  } catch (err) {
94172
- console.error(import_picocolors9.default.red(err.message));
94609
+ console.error(import_picocolors10.default.red(err.message));
94173
94610
  return 1;
94174
94611
  }
94175
94612
  }
94176
94613
 
94177
94614
  // ../../packages/cli/src/commands/timeline.ts
94178
94615
  init_cjs_shims();
94179
- var import_picocolors10 = __toESM(require_picocolors(), 1);
94616
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
94180
94617
  var DEFAULT_SINCE = "7 days ago";
94181
94618
  function resolveTimelineWindow(opts) {
94182
94619
  const usingDefault = !opts.all && opts.since === void 0;
@@ -94206,7 +94643,7 @@ async function runTimeline(service, opts) {
94206
94643
  try {
94207
94644
  renv = resolveEnvironment(config2, { project: opts.repo });
94208
94645
  } catch (err) {
94209
- console.error(import_picocolors10.default.red(err.message));
94646
+ console.error(import_picocolors11.default.red(err.message));
94210
94647
  return 1;
94211
94648
  }
94212
94649
  const { code } = createConnectors(config2);
@@ -94221,9 +94658,9 @@ async function runTimeline(service, opts) {
94221
94658
  console.log(renderChangeTimeline(t));
94222
94659
  if (usingDefaultWindow) {
94223
94660
  console.log(
94224
- import_picocolors10.default.dim(
94661
+ import_picocolors11.default.dim(
94225
94662
  `
94226
- Showing the last 7 days (default). Widen with ${import_picocolors10.default.bold('--since "30 days ago"')}, pin a range with ${import_picocolors10.default.bold("--since <when> --until <when>")}, or see everything with ${import_picocolors10.default.bold("--all")}.`
94663
+ Showing the last 7 days (default). Widen with ${import_picocolors11.default.bold('--since "30 days ago"')}, pin a range with ${import_picocolors11.default.bold("--since <when> --until <when>")}, or see everything with ${import_picocolors11.default.bold("--all")}.`
94227
94664
  )
94228
94665
  );
94229
94666
  }
@@ -94240,20 +94677,20 @@ async function runTimeline(service, opts) {
94240
94677
  });
94241
94678
  console.log("\n" + renderInterpretation(result));
94242
94679
  if (!result.ok) {
94243
- console.error(import_picocolors10.default.yellow(`[ai] ${result.warning}`));
94680
+ console.error(import_picocolors11.default.yellow(`[ai] ${result.warning}`));
94244
94681
  }
94245
94682
  }
94246
94683
  }
94247
94684
  return 0;
94248
94685
  } catch (err) {
94249
- console.error(import_picocolors10.default.red(err.message));
94686
+ console.error(import_picocolors11.default.red(err.message));
94250
94687
  return 1;
94251
94688
  }
94252
94689
  }
94253
94690
 
94254
94691
  // ../../packages/cli/src/commands/what-changed.ts
94255
94692
  init_cjs_shims();
94256
- var import_picocolors11 = __toESM(require_picocolors(), 1);
94693
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
94257
94694
  var DEFAULT_SINCE2 = "7 days ago";
94258
94695
  var WHAT_CHANGED_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
94259
94696
 
@@ -94277,7 +94714,7 @@ async function runWhatChanged(service, opts) {
94277
94714
  try {
94278
94715
  renv = resolveEnvironment(config2, { project: opts.repo });
94279
94716
  } catch (err) {
94280
- console.error(import_picocolors11.default.red(err.message));
94717
+ console.error(import_picocolors12.default.red(err.message));
94281
94718
  return 1;
94282
94719
  }
94283
94720
  const { code } = createConnectors(config2);
@@ -94300,19 +94737,19 @@ async function runWhatChanged(service, opts) {
94300
94737
  });
94301
94738
  console.log("\n" + renderInterpretation(result));
94302
94739
  if (!result.ok) {
94303
- console.error(import_picocolors11.default.yellow(`[ai] ${result.warning}`));
94740
+ console.error(import_picocolors12.default.yellow(`[ai] ${result.warning}`));
94304
94741
  }
94305
94742
  }
94306
94743
  return 0;
94307
94744
  } catch (err) {
94308
- console.error(import_picocolors11.default.red(err.message));
94745
+ console.error(import_picocolors12.default.red(err.message));
94309
94746
  return 1;
94310
94747
  }
94311
94748
  }
94312
94749
 
94313
94750
  // ../../packages/cli/src/commands/architecture.ts
94314
94751
  init_cjs_shims();
94315
- var import_picocolors12 = __toESM(require_picocolors(), 1);
94752
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
94316
94753
  var ARCHITECTURE_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
94317
94754
 
94318
94755
  System summary
@@ -94341,7 +94778,7 @@ async function runArchitecture(opts) {
94341
94778
  const health = await code.health();
94342
94779
  if (!health.ok) {
94343
94780
  console.error(
94344
- import_picocolors12.default.red("Source-intelligence host unreachable \u2014 run: horus index")
94781
+ import_picocolors13.default.red("Source-intelligence host unreachable \u2014 run: horus index")
94345
94782
  );
94346
94783
  return 1;
94347
94784
  }
@@ -94369,7 +94806,7 @@ async function runArchitecture(opts) {
94369
94806
  });
94370
94807
  console.log("\n" + renderInterpretation(result));
94371
94808
  if (!result.ok) {
94372
- console.error(import_picocolors12.default.yellow(`[ai] ${result.warning}`));
94809
+ console.error(import_picocolors13.default.yellow(`[ai] ${result.warning}`));
94373
94810
  }
94374
94811
  }
94375
94812
  }
@@ -94378,14 +94815,14 @@ async function runArchitecture(opts) {
94378
94815
  }
94379
94816
  return 0;
94380
94817
  } catch (err) {
94381
- console.error(import_picocolors12.default.red(err.message));
94818
+ console.error(import_picocolors13.default.red(err.message));
94382
94819
  return 1;
94383
94820
  }
94384
94821
  }
94385
94822
 
94386
94823
  // ../../packages/cli/src/commands/blast-radius.ts
94387
94824
  init_cjs_shims();
94388
- var import_picocolors13 = __toESM(require_picocolors(), 1);
94825
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
94389
94826
  var BLAST_RADIUS_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
94390
94827
 
94391
94828
  Evidence used
@@ -94412,7 +94849,7 @@ async function runBlastRadius(query, opts) {
94412
94849
  const { code } = createConnectors(config2);
94413
94850
  const health = await code.health();
94414
94851
  if (!health.ok) {
94415
- console.error(import_picocolors13.default.red("Source-intelligence host unreachable \u2014 run: horus index"));
94852
+ console.error(import_picocolors14.default.red("Source-intelligence host unreachable \u2014 run: horus index"));
94416
94853
  return 1;
94417
94854
  }
94418
94855
  let project;
@@ -94425,12 +94862,12 @@ async function runBlastRadius(query, opts) {
94425
94862
  const r = await analyzeBlastRadius(query, { code, db, project }, opts.depth ?? 3);
94426
94863
  if (!r) {
94427
94864
  console.log(`No symbol found for: ${query}`);
94428
- console.log(import_picocolors13.default.dim(` Tip: use an exact class or function name, e.g. "MyService"`));
94865
+ console.log(import_picocolors14.default.dim(` Tip: use an exact class or function name, e.g. "MyService"`));
94429
94866
  return 1;
94430
94867
  }
94431
94868
  if (r.seed.name.toLowerCase() !== query.toLowerCase()) {
94432
94869
  console.log(
94433
- import_picocolors13.default.yellow(` No exact match for "${query}"`) + import_picocolors13.default.dim(` \u2014 showing closest: "${r.seed.name}" (fuzzy match)`)
94870
+ import_picocolors14.default.yellow(` No exact match for "${query}"`) + import_picocolors14.default.dim(` \u2014 showing closest: "${r.seed.name}" (fuzzy match)`)
94434
94871
  );
94435
94872
  }
94436
94873
  if (opts.json) {
@@ -94450,7 +94887,7 @@ async function runBlastRadius(query, opts) {
94450
94887
  });
94451
94888
  console.log("\n" + renderInterpretation(result));
94452
94889
  if (!result.ok) {
94453
- console.error(import_picocolors13.default.yellow(`[ai] ${result.warning}`));
94890
+ console.error(import_picocolors14.default.yellow(`[ai] ${result.warning}`));
94454
94891
  }
94455
94892
  }
94456
94893
  }
@@ -94459,28 +94896,28 @@ async function runBlastRadius(query, opts) {
94459
94896
  }
94460
94897
  return 0;
94461
94898
  } catch (err) {
94462
- console.error(import_picocolors13.default.red(err.message));
94899
+ console.error(import_picocolors14.default.red(err.message));
94463
94900
  return 1;
94464
94901
  }
94465
94902
  }
94466
94903
 
94467
94904
  // ../../packages/cli/src/commands/repos.ts
94468
94905
  init_cjs_shims();
94469
- var import_picocolors14 = __toESM(require_picocolors(), 1);
94906
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
94470
94907
  async function runRepos(opts) {
94471
94908
  const config2 = await loadConfig(opts.config);
94472
94909
  const providers = repoProviders(config2);
94473
94910
  if (providers.length === 0) {
94474
- console.log(import_picocolors14.default.dim("No repositories configured."));
94911
+ console.log(import_picocolors15.default.dim("No repositories configured."));
94475
94912
  return 0;
94476
94913
  }
94477
94914
  const health = await reposHealth(providers);
94478
94915
  for (const h of health) {
94479
- const dot = h.reachable ? import_picocolors14.default.green("\u25CF") : import_picocolors14.default.red("\u25CF");
94480
- const name = import_picocolors14.default.bold(h.repo.padEnd(20));
94481
- const hostUrl = import_picocolors14.default.cyan(h.hostUrl.padEnd(30));
94482
- const path = import_picocolors14.default.dim(h.path);
94483
- const detail = h.detail ? import_picocolors14.default.dim(`(${h.detail})`) : "";
94916
+ const dot = h.reachable ? import_picocolors15.default.green("\u25CF") : import_picocolors15.default.red("\u25CF");
94917
+ const name = import_picocolors15.default.bold(h.repo.padEnd(20));
94918
+ const hostUrl = import_picocolors15.default.cyan(h.hostUrl.padEnd(30));
94919
+ const path = import_picocolors15.default.dim(h.path);
94920
+ const detail = h.detail ? import_picocolors15.default.dim(`(${h.detail})`) : "";
94484
94921
  console.log(` ${dot} ${name} ${hostUrl} ${path} ${detail}`);
94485
94922
  }
94486
94923
  return 0;
@@ -94488,7 +94925,7 @@ async function runRepos(opts) {
94488
94925
 
94489
94926
  // ../../packages/cli/src/commands/search.ts
94490
94927
  init_cjs_shims();
94491
- var import_picocolors15 = __toESM(require_picocolors(), 1);
94928
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
94492
94929
  async function runSearch(query, opts) {
94493
94930
  const config2 = await loadConfig(opts.config);
94494
94931
  const providers = repoProviders(config2);
@@ -94499,16 +94936,16 @@ async function runSearch(query, opts) {
94499
94936
  }
94500
94937
  let totalMatches = 0;
94501
94938
  for (const result of results) {
94502
- const statusDot = result.reachable ? import_picocolors15.default.green("\u25CF") : import_picocolors15.default.red("\u25CF");
94939
+ const statusDot = result.reachable ? import_picocolors16.default.green("\u25CF") : import_picocolors16.default.red("\u25CF");
94503
94940
  console.log("");
94504
- console.log(`${statusDot} ${import_picocolors15.default.bold("## " + result.repo)} ${import_picocolors15.default.dim(result.hostUrl)}`);
94941
+ console.log(`${statusDot} ${import_picocolors16.default.bold("## " + result.repo)} ${import_picocolors16.default.dim(result.hostUrl)}`);
94505
94942
  if (!result.reachable) {
94506
- console.log(import_picocolors15.default.dim(" (unreachable)"));
94943
+ console.log(import_picocolors16.default.dim(" (unreachable)"));
94507
94944
  } else if (result.symbols.length === 0) {
94508
- console.log(import_picocolors15.default.dim(" (no matches)"));
94945
+ console.log(import_picocolors16.default.dim(" (no matches)"));
94509
94946
  } else {
94510
94947
  for (const sym of result.symbols) {
94511
- console.log(` - ${import_picocolors15.default.bold(sym.name)} ${import_picocolors15.default.dim(sym.filePath)}`);
94948
+ console.log(` - ${import_picocolors16.default.bold(sym.name)} ${import_picocolors16.default.dim(sym.filePath)}`);
94512
94949
  }
94513
94950
  totalMatches += result.symbols.length;
94514
94951
  }
@@ -94516,7 +94953,7 @@ async function runSearch(query, opts) {
94516
94953
  console.log("");
94517
94954
  const reachableCount = results.filter((r) => r.reachable).length;
94518
94955
  console.log(
94519
- import_picocolors15.default.dim(
94956
+ import_picocolors16.default.dim(
94520
94957
  `${totalMatches} match(es) across ${reachableCount}/${results.length} reachable repo(s) for query: "${query}"`
94521
94958
  )
94522
94959
  );
@@ -94525,7 +94962,7 @@ async function runSearch(query, opts) {
94525
94962
 
94526
94963
  // ../../packages/cli/src/commands/investigations.ts
94527
94964
  init_cjs_shims();
94528
- var import_picocolors16 = __toESM(require_picocolors(), 1);
94965
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
94529
94966
 
94530
94967
  // ../../packages/cli/src/lib/format.ts
94531
94968
  init_cjs_shims();
@@ -94568,8 +95005,8 @@ async function runInvestigations(opts) {
94568
95005
  const session = authedClient();
94569
95006
  if (!session) {
94570
95007
  console.error(
94571
- import_picocolors16.default.red(
94572
- `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors16.default.bold("horus login")} first.`
95008
+ import_picocolors17.default.red(
95009
+ `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors17.default.bold("horus login")} first.`
94573
95010
  )
94574
95011
  );
94575
95012
  return 1;
@@ -94610,18 +95047,18 @@ async function runInvestigations(opts) {
94610
95047
 
94611
95048
  // ../../packages/cli/src/commands/replay.ts
94612
95049
  init_cjs_shims();
94613
- var import_picocolors17 = __toESM(require_picocolors(), 1);
95050
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
94614
95051
  async function runReplay(id, opts) {
94615
95052
  const { db, sql: sql2 } = createDb(await resolveDbUrl(opts.config));
94616
95053
  try {
94617
95054
  const row = await getInvestigation(db, id);
94618
95055
  if (!row) {
94619
- console.error(import_picocolors17.default.red("No investigation found: " + id));
95056
+ console.error(import_picocolors18.default.red("No investigation found: " + id));
94620
95057
  return 1;
94621
95058
  }
94622
95059
  if (!row.report) {
94623
95060
  console.error(
94624
- import_picocolors17.default.red(
95061
+ import_picocolors18.default.red(
94625
95062
  "Investigation " + id + " has no stored report (run a newer investigation)."
94626
95063
  )
94627
95064
  );
@@ -94634,7 +95071,7 @@ async function runReplay(id, opts) {
94634
95071
  if (opts.ai && fmt !== "json") {
94635
95072
  if (report.aiJudgment && !opts.refreshAi) {
94636
95073
  renderStoredAIJudgment(report.aiJudgment);
94637
- console.log(import_picocolors17.default.dim("[ai] Stored judgment replayed. Use --refresh-ai to regenerate."));
95074
+ console.log(import_picocolors18.default.dim("[ai] Stored judgment replayed. Use --refresh-ai to regenerate."));
94638
95075
  } else {
94639
95076
  const narrativeInput = buildNarrativeInput(report);
94640
95077
  const { provider } = await buildNarrativeProvider({
@@ -94647,17 +95084,17 @@ async function runReplay(id, opts) {
94647
95084
  );
94648
95085
  if (!fromProvider && degraded) {
94649
95086
  if (validationErrors?.length) {
94650
- console.error(import_picocolors17.default.yellow("[ai] structured validation incomplete \u2014 showing raw AI narrative"));
95087
+ console.error(import_picocolors18.default.yellow("[ai] structured validation incomplete \u2014 showing raw AI narrative"));
94651
95088
  }
94652
95089
  console.log("");
94653
- console.log(import_picocolors17.default.dim("\u2500".repeat(60)));
94654
- console.log(import_picocolors17.default.bold("AI narrative ") + import_picocolors17.default.yellow("(unstructured \u2014 not validated)"));
94655
- if (output.what?.trim()) console.log(import_picocolors17.default.bold("\nWhat:"), output.what.trim());
94656
- if (output.why?.trim()) console.log(import_picocolors17.default.bold("\nWhy:"), output.why.trim());
95090
+ console.log(import_picocolors18.default.dim("\u2500".repeat(60)));
95091
+ console.log(import_picocolors18.default.bold("AI narrative ") + import_picocolors18.default.yellow("(unstructured \u2014 not validated)"));
95092
+ if (output.what?.trim()) console.log(import_picocolors18.default.bold("\nWhat:"), output.what.trim());
95093
+ if (output.why?.trim()) console.log(import_picocolors18.default.bold("\nWhy:"), output.why.trim());
94657
95094
  } else if (!fromProvider) {
94658
- console.error(import_picocolors17.default.yellow("[ai] Provider unavailable \u2014 deterministic output shown above."));
95095
+ console.error(import_picocolors18.default.yellow("[ai] Provider unavailable \u2014 deterministic output shown above."));
94659
95096
  if (validationErrors?.length) {
94660
- console.error(import_picocolors17.default.dim(` ${validationErrors[0]}`));
95097
+ console.error(import_picocolors18.default.dim(` ${validationErrors[0]}`));
94661
95098
  }
94662
95099
  } else {
94663
95100
  const stored = narrativeOutputToStoredJudgment(output, "anthropic");
@@ -94678,7 +95115,7 @@ async function runReplay(id, opts) {
94678
95115
 
94679
95116
  // ../../packages/cli/src/commands/owner.ts
94680
95117
  init_cjs_shims();
94681
- var import_picocolors18 = __toESM(require_picocolors(), 1);
95118
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
94682
95119
  async function runOwner(query, opts) {
94683
95120
  try {
94684
95121
  const config2 = await loadConfig(opts.config);
@@ -94686,7 +95123,7 @@ async function runOwner(query, opts) {
94686
95123
  try {
94687
95124
  renv = resolveEnvironment(config2, { project: opts.repo });
94688
95125
  } catch (err) {
94689
- console.error(import_picocolors18.default.red(err.message));
95126
+ console.error(import_picocolors19.default.red(err.message));
94690
95127
  return 1;
94691
95128
  }
94692
95129
  const code = codeForRepo(config2, renv.project);
@@ -94694,16 +95131,16 @@ async function runOwner(query, opts) {
94694
95131
  console.log(opts.json ? ownershipToJSON(o) : renderOwnership(o));
94695
95132
  return 0;
94696
95133
  } catch (err) {
94697
- console.error(import_picocolors18.default.red(err.message));
95134
+ console.error(import_picocolors19.default.red(err.message));
94698
95135
  return 1;
94699
95136
  }
94700
95137
  }
94701
95138
 
94702
95139
  // ../../packages/cli/src/commands/postmortem.ts
94703
95140
  init_cjs_shims();
94704
- var import_node_fs13 = require("fs");
94705
- var import_node_path14 = require("path");
94706
- var import_picocolors19 = __toESM(require_picocolors(), 1);
95141
+ var import_node_fs15 = require("fs");
95142
+ var import_node_path16 = require("path");
95143
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
94707
95144
  async function runPostmortem(id, opts) {
94708
95145
  const log = opts.write ?? ((line2) => console.log(line2));
94709
95146
  let sql2;
@@ -94717,11 +95154,11 @@ async function runPostmortem(id, opts) {
94717
95154
  const { db } = conn;
94718
95155
  const row = await getInvestigation(db, id);
94719
95156
  if (!row) {
94720
- log(import_picocolors19.default.red("No investigation found: " + id));
95157
+ log(import_picocolors20.default.red("No investigation found: " + id));
94721
95158
  return 1;
94722
95159
  }
94723
95160
  if (!row.report) {
94724
- log(import_picocolors19.default.red("Investigation " + id + " has no stored report."));
95161
+ log(import_picocolors20.default.red("Investigation " + id + " has no stored report."));
94725
95162
  return 1;
94726
95163
  }
94727
95164
  report = migrateReport(row.report);
@@ -94813,25 +95250,25 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
94813
95250
  }
94814
95251
  }
94815
95252
  if (opts.output) {
94816
- const outputPath = (0, import_node_path14.resolve)(opts.output);
94817
- if ((0, import_node_fs13.existsSync)(outputPath) && !opts.force) {
94818
- log(import_picocolors19.default.red("\u2717") + " " + outputPath + " already exists");
94819
- log(import_picocolors19.default.dim(" pass --force to overwrite"));
95253
+ const outputPath = (0, import_node_path16.resolve)(opts.output);
95254
+ if ((0, import_node_fs15.existsSync)(outputPath) && !opts.force) {
95255
+ log(import_picocolors20.default.red("\u2717") + " " + outputPath + " already exists");
95256
+ log(import_picocolors20.default.dim(" pass --force to overwrite"));
94820
95257
  return 1;
94821
95258
  }
94822
95259
  try {
94823
- (0, import_node_fs13.writeFileSync)(outputPath, content, "utf8");
95260
+ (0, import_node_fs15.writeFileSync)(outputPath, content, "utf8");
94824
95261
  } catch (err) {
94825
- log(import_picocolors19.default.red("\u2717 Could not write " + outputPath + ": ") + err.message);
95262
+ log(import_picocolors20.default.red("\u2717 Could not write " + outputPath + ": ") + err.message);
94826
95263
  return 1;
94827
95264
  }
94828
- log(import_picocolors19.default.green("\u2713") + " Saved postmortem to " + outputPath);
95265
+ log(import_picocolors20.default.green("\u2713") + " Saved postmortem to " + outputPath);
94829
95266
  } else {
94830
95267
  log(content);
94831
95268
  }
94832
95269
  } catch (err) {
94833
95270
  const message = err instanceof Error ? err.message : String(err);
94834
- log(import_picocolors19.default.red("postmortem failed: " + message));
95271
+ log(import_picocolors20.default.red("postmortem failed: " + message));
94835
95272
  return 1;
94836
95273
  } finally {
94837
95274
  if (sql2) {
@@ -94843,7 +95280,7 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
94843
95280
 
94844
95281
  // ../../packages/cli/src/commands/score.ts
94845
95282
  init_cjs_shims();
94846
- var import_picocolors20 = __toESM(require_picocolors(), 1);
95283
+ var import_picocolors21 = __toESM(require_picocolors(), 1);
94847
95284
  var SCORE_AI_CONTRACT = `Provide a clearly separated AI score explanation with:
94848
95285
 
94849
95286
  Why this scored this way
@@ -94862,11 +95299,11 @@ async function runScore(id, opts) {
94862
95299
  try {
94863
95300
  const row = await getInvestigation(db, id);
94864
95301
  if (!row) {
94865
- console.error(import_picocolors20.default.red("No investigation found: " + id));
95302
+ console.error(import_picocolors21.default.red("No investigation found: " + id));
94866
95303
  return 1;
94867
95304
  }
94868
95305
  if (!row.report) {
94869
- console.error(import_picocolors20.default.red("Investigation " + id + " has no stored report."));
95306
+ console.error(import_picocolors21.default.red("Investigation " + id + " has no stored report."));
94870
95307
  return 1;
94871
95308
  }
94872
95309
  const s = scoreInvestigation(migrateReport(row.report));
@@ -94887,7 +95324,7 @@ async function runScore(id, opts) {
94887
95324
  });
94888
95325
  console.log("\n" + renderInterpretation(result));
94889
95326
  if (!result.ok) {
94890
- console.error(import_picocolors20.default.yellow(`[ai] ${result.warning}`));
95327
+ console.error(import_picocolors21.default.yellow(`[ai] ${result.warning}`));
94891
95328
  }
94892
95329
  }
94893
95330
  }
@@ -94927,7 +95364,7 @@ async function runScores(opts) {
94927
95364
 
94928
95365
  // ../../packages/cli/src/commands/ask.ts
94929
95366
  init_cjs_shims();
94930
- var import_picocolors21 = __toESM(require_picocolors(), 1);
95367
+ var import_picocolors22 = __toESM(require_picocolors(), 1);
94931
95368
  function renderAnswer(report, directive, opts) {
94932
95369
  const answer = answerQuestion(report, directive);
94933
95370
  if (answer) {
@@ -94939,13 +95376,13 @@ function renderAnswer(report, directive, opts) {
94939
95376
  if (!opts.json && report.aiJudgment) {
94940
95377
  const j = report.aiJudgment;
94941
95378
  console.log("");
94942
- console.log(import_picocolors21.default.dim("\u2500".repeat(60)));
94943
- console.log(import_picocolors21.default.dim(`Stored AI judgment (${j.provider}, ${j.generatedAt}):`));
95379
+ console.log(import_picocolors22.default.dim("\u2500".repeat(60)));
95380
+ console.log(import_picocolors22.default.dim(`Stored AI judgment (${j.provider}, ${j.generatedAt}):`));
94944
95381
  if (j.rootCauseAssessment) {
94945
- console.log(import_picocolors21.default.bold("Root cause (AI):"), j.rootCauseAssessment.summary);
94946
- console.log(import_picocolors21.default.dim(`Uncertainty: ${j.rootCauseAssessment.uncertainty}`));
95382
+ console.log(import_picocolors22.default.bold("Root cause (AI):"), j.rootCauseAssessment.summary);
95383
+ console.log(import_picocolors22.default.dim(`Uncertainty: ${j.rootCauseAssessment.uncertainty}`));
94947
95384
  } else {
94948
- console.log(import_picocolors21.default.bold("AI Why:"), j.why);
95385
+ console.log(import_picocolors22.default.bold("AI Why:"), j.why);
94949
95386
  }
94950
95387
  }
94951
95388
  return 0;
@@ -94974,8 +95411,8 @@ async function runAsk(id, directive, opts) {
94974
95411
  const session = authedClient();
94975
95412
  if (!session) {
94976
95413
  console.error(
94977
- import_picocolors21.default.red(
94978
- `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors21.default.bold("horus login")} first.`
95414
+ import_picocolors22.default.red(
95415
+ `This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors22.default.bold("horus login")} first.`
94979
95416
  )
94980
95417
  );
94981
95418
  return 1;
@@ -94984,15 +95421,15 @@ async function runAsk(id, directive, opts) {
94984
95421
  const report = await fetchInvestigationReportFromCloud(session.client, cloudCfg, id);
94985
95422
  if (report) return renderAnswer(report, directive, opts);
94986
95423
  console.error(
94987
- import_picocolors21.default.red(
94988
- `Investigation ${id} has no saved report locally or in Horus Cloud. Run ${import_picocolors21.default.bold("horus investigate")} first.`
95424
+ import_picocolors22.default.red(
95425
+ `Investigation ${id} has no saved report locally or in Horus Cloud. Run ${import_picocolors22.default.bold("horus investigate")} first.`
94989
95426
  )
94990
95427
  );
94991
95428
  return 1;
94992
95429
  } catch (err) {
94993
95430
  if (err instanceof CloudError && err.status === 404) {
94994
95431
  console.error(
94995
- import_picocolors21.default.red(
95432
+ import_picocolors22.default.red(
94996
95433
  `No investigation found for "${id}" locally or in Horus Cloud. Use the id printed at the top of \`horus investigate\` output.`
94997
95434
  )
94998
95435
  );
@@ -95006,21 +95443,21 @@ async function runAsk(id, directive, opts) {
95006
95443
  case "found":
95007
95444
  return renderAnswer(local.report, directive, opts);
95008
95445
  case "no-report":
95009
- console.error(import_picocolors21.default.red("Investigation " + id + " has no stored report."));
95446
+ console.error(import_picocolors22.default.red("Investigation " + id + " has no stored report."));
95010
95447
  return 1;
95011
95448
  case "error":
95012
- console.error(import_picocolors21.default.red(local.message));
95449
+ console.error(import_picocolors22.default.red(local.message));
95013
95450
  return 1;
95014
95451
  case "not-found":
95015
95452
  default:
95016
- console.error(import_picocolors21.default.red("No investigation found: " + id));
95453
+ console.error(import_picocolors22.default.red("No investigation found: " + id));
95017
95454
  return 1;
95018
95455
  }
95019
95456
  }
95020
95457
 
95021
95458
  // ../../packages/cli/src/commands/onboard.ts
95022
95459
  init_cjs_shims();
95023
- var import_picocolors22 = __toESM(require_picocolors(), 1);
95460
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
95024
95461
  var ONBOARD_AI_CONTRACT = `Provide a clearly separated AI onboarding guide with:
95025
95462
 
95026
95463
  Start here
@@ -95048,7 +95485,7 @@ async function runOnboard(area, opts) {
95048
95485
  try {
95049
95486
  renv = resolveEnvironment(config2, { project: opts.repo });
95050
95487
  } catch (err) {
95051
- console.error(import_picocolors22.default.red(err.message));
95488
+ console.error(import_picocolors23.default.red(err.message));
95052
95489
  return 1;
95053
95490
  }
95054
95491
  const repo = { name: renv.project, path: renv.path };
@@ -95056,7 +95493,7 @@ async function runOnboard(area, opts) {
95056
95493
  const health = await code.health();
95057
95494
  if (!health.ok) {
95058
95495
  console.error(
95059
- import_picocolors22.default.red("Source-intelligence host unreachable \u2014 run: horus index")
95496
+ import_picocolors23.default.red("Source-intelligence host unreachable \u2014 run: horus index")
95060
95497
  );
95061
95498
  return 1;
95062
95499
  }
@@ -95083,7 +95520,7 @@ async function runOnboard(area, opts) {
95083
95520
  });
95084
95521
  console.log("\n" + renderInterpretation(result));
95085
95522
  if (!result.ok) {
95086
- console.error(import_picocolors22.default.yellow(`[ai] ${result.warning}`));
95523
+ console.error(import_picocolors23.default.yellow(`[ai] ${result.warning}`));
95087
95524
  }
95088
95525
  }
95089
95526
  }
@@ -95092,14 +95529,14 @@ async function runOnboard(area, opts) {
95092
95529
  }
95093
95530
  return 0;
95094
95531
  } catch (err) {
95095
- console.error(import_picocolors22.default.red(err.message));
95532
+ console.error(import_picocolors23.default.red(err.message));
95096
95533
  return 1;
95097
95534
  }
95098
95535
  }
95099
95536
 
95100
95537
  // ../../packages/cli/src/commands/simulate.ts
95101
95538
  init_cjs_shims();
95102
- var import_picocolors23 = __toESM(require_picocolors(), 1);
95539
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
95103
95540
  async function runSimulate(scenarioId, opts) {
95104
95541
  try {
95105
95542
  if (scenarioId === void 0) {
@@ -95109,7 +95546,7 @@ async function runSimulate(scenarioId, opts) {
95109
95546
  const scenario = getScenario(scenarioId);
95110
95547
  if (scenario === null) {
95111
95548
  console.error(
95112
- import_picocolors23.default.red(
95549
+ import_picocolors24.default.red(
95113
95550
  `Unknown scenario: "${scenarioId}". Run horus simulate to list available scenarios.`
95114
95551
  )
95115
95552
  );
@@ -95120,14 +95557,14 @@ async function runSimulate(scenarioId, opts) {
95120
95557
  try {
95121
95558
  renv = resolveEnvironment(config2, { project: opts.repo });
95122
95559
  } catch (err) {
95123
- console.error(import_picocolors23.default.red(err.message));
95560
+ console.error(import_picocolors24.default.red(err.message));
95124
95561
  return 1;
95125
95562
  }
95126
95563
  const code = codeForRepo(config2, renv.project);
95127
95564
  const health = await code.health();
95128
95565
  if (!health.ok) {
95129
95566
  console.error(
95130
- import_picocolors23.default.red("Source-intelligence host unreachable \u2014 run: horus index")
95567
+ import_picocolors24.default.red("Source-intelligence host unreachable \u2014 run: horus index")
95131
95568
  );
95132
95569
  return 1;
95133
95570
  }
@@ -95144,14 +95581,14 @@ async function runSimulate(scenarioId, opts) {
95144
95581
  }
95145
95582
  return 0;
95146
95583
  } catch (err) {
95147
- console.error(import_picocolors23.default.red(err.message));
95584
+ console.error(import_picocolors24.default.red(err.message));
95148
95585
  return 1;
95149
95586
  }
95150
95587
  }
95151
95588
 
95152
95589
  // ../../packages/cli/src/commands/logs.ts
95153
95590
  init_cjs_shims();
95154
- var import_picocolors24 = __toESM(require_picocolors(), 1);
95591
+ var import_picocolors25 = __toESM(require_picocolors(), 1);
95155
95592
  var LOGS_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
95156
95593
 
95157
95594
  Evidence used
@@ -95184,9 +95621,9 @@ function resolveRawLevel(opts) {
95184
95621
  return opts.level ?? "error";
95185
95622
  }
95186
95623
  function levelColor(level, text2) {
95187
- if (level === "error" || level === "fatal") return import_picocolors24.default.red(text2);
95188
- if (level === "warn") return import_picocolors24.default.yellow(text2);
95189
- return import_picocolors24.default.dim(text2);
95624
+ if (level === "error" || level === "fatal") return import_picocolors25.default.red(text2);
95625
+ if (level === "warn") return import_picocolors25.default.yellow(text2);
95626
+ return import_picocolors25.default.dim(text2);
95190
95627
  }
95191
95628
  function matchServiceLabel(requested, candidates) {
95192
95629
  if (candidates.includes(requested)) return { kind: "unique", matched: requested };
@@ -95203,13 +95640,13 @@ async function runLogs(service, opts) {
95203
95640
  try {
95204
95641
  renv = resolveEnvironment(config2, { project: opts.project, env: opts.env });
95205
95642
  } catch (err) {
95206
- console.error(import_picocolors24.default.red(err.message));
95643
+ console.error(import_picocolors25.default.red(err.message));
95207
95644
  return 1;
95208
95645
  }
95209
95646
  const logs = logsForEnv(renv);
95210
95647
  if (logs === null) {
95211
95648
  console.error(
95212
- import_picocolors24.default.red(
95649
+ import_picocolors25.default.red(
95213
95650
  `No Elasticsearch connector configured for ${renv.project}/${renv.env} (set ES_URL / ES_USERNAME / ES_PASSWORD)`
95214
95651
  )
95215
95652
  );
@@ -95217,7 +95654,7 @@ async function runLogs(service, opts) {
95217
95654
  }
95218
95655
  const health = await logs.health();
95219
95656
  if (!health.ok) {
95220
- console.error(import_picocolors24.default.red(`Elasticsearch unreachable: ${health.detail}`));
95657
+ console.error(import_picocolors25.default.red(`Elasticsearch unreachable: ${health.detail}`));
95221
95658
  return 1;
95222
95659
  }
95223
95660
  const resolvedService = service ?? renv.connectors.elasticsearch?.serviceName;
@@ -95230,21 +95667,21 @@ async function runLogs(service, opts) {
95230
95667
  requiresEventCode: aggregatesEventCode
95231
95668
  });
95232
95669
  for (const w of compat.issues.filter((i) => i.severity === "warning")) {
95233
- console.warn(import_picocolors24.default.yellow(`[warn] ${w.field}: ${w.message}`));
95670
+ console.warn(import_picocolors25.default.yellow(`[warn] ${w.field}: ${w.message}`));
95234
95671
  }
95235
95672
  const errors2 = compat.issues.filter((i) => i.severity === "error");
95236
95673
  if (errors2.length > 0) {
95237
- console.error(import_picocolors24.default.red("Elasticsearch field mapping is incompatible with the index:"));
95674
+ console.error(import_picocolors25.default.red("Elasticsearch field mapping is incompatible with the index:"));
95238
95675
  for (const e of errors2) {
95239
- console.error(import_picocolors24.default.red(` ${e.field}: ${e.message}`));
95676
+ console.error(import_picocolors25.default.red(` ${e.field}: ${e.message}`));
95240
95677
  }
95241
95678
  console.error(
95242
- import_picocolors24.default.dim("Fix fields.* overrides in your connector config or choose the correct preset.")
95679
+ import_picocolors25.default.dim("Fix fields.* overrides in your connector config or choose the correct preset.")
95243
95680
  );
95244
95681
  return 1;
95245
95682
  }
95246
95683
  } catch {
95247
- console.warn(import_picocolors24.default.dim("[warn] Elasticsearch compatibility check unavailable \u2014 proceeding."));
95684
+ console.warn(import_picocolors25.default.dim("[warn] Elasticsearch compatibility check unavailable \u2014 proceeding."));
95248
95685
  }
95249
95686
  const from = sinceToIso(opts.since) ?? new Date(Date.now() - 7 * 864e5).toISOString();
95250
95687
  const fromDisplay = from.slice(0, 16).replace("T", " ");
@@ -95295,7 +95732,7 @@ async function runLogs(service, opts) {
95295
95732
  return 0;
95296
95733
  }
95297
95734
  if (records.length === 0) {
95298
- console.log(import_picocolors24.default.dim("No logs matched."));
95735
+ console.log(import_picocolors25.default.dim("No logs matched."));
95299
95736
  return 0;
95300
95737
  }
95301
95738
  for (const r of records) {
@@ -95305,7 +95742,7 @@ async function runLogs(service, opts) {
95305
95742
  const line2 = `${ts} ${lvl} ${comp} ${r.message.slice(0, 120)}`;
95306
95743
  console.log(levelColor(r.level, line2));
95307
95744
  for (const { key, value } of extractContextFields(r)) {
95308
- console.log(import_picocolors24.default.dim(` ${key}: ${value.slice(0, 200)}`));
95745
+ console.log(import_picocolors25.default.dim(` ${key}: ${value.slice(0, 200)}`));
95309
95746
  }
95310
95747
  }
95311
95748
  return 0;
@@ -95344,22 +95781,22 @@ async function runLogs(service, opts) {
95344
95781
  return 0;
95345
95782
  }
95346
95783
  console.log(
95347
- import_picocolors24.default.bold(`Top ${field}`) + import_picocolors24.default.dim(
95784
+ import_picocolors25.default.bold(`Top ${field}`) + import_picocolors25.default.dim(
95348
95785
  ` \u2014 ${renv.project}/${renv.env}` + (resolvedService ? ` \xB7 service ${resolvedService}` : "") + (opts.grep ? ` \xB7 grep "${opts.grep}"` : "")
95349
95786
  )
95350
95787
  );
95351
- console.log(import_picocolors24.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
95788
+ console.log(import_picocolors25.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
95352
95789
  console.log("");
95353
95790
  if (buckets.length === 0) {
95354
- console.log(import_picocolors24.default.dim(` No error logs with field "${field}" in the window.`));
95355
- console.log(import_picocolors24.default.dim(` Tip: ensure "${field}" is an aggregatable (keyword) field.`));
95791
+ console.log(import_picocolors25.default.dim(` No error logs with field "${field}" in the window.`));
95792
+ console.log(import_picocolors25.default.dim(` Tip: ensure "${field}" is an aggregatable (keyword) field.`));
95356
95793
  return 0;
95357
95794
  }
95358
95795
  for (const b2 of buckets) {
95359
- console.log(` ${import_picocolors24.default.red(String(b2.count).padStart(6))} ${b2.key}`);
95796
+ console.log(` ${import_picocolors25.default.red(String(b2.count).padStart(6))} ${b2.key}`);
95360
95797
  }
95361
95798
  console.log("");
95362
- console.log(import_picocolors24.default.dim(` ${buckets.length} distinct ${field} value(s) shown (top by error count).`));
95799
+ console.log(import_picocolors25.default.dim(` ${buckets.length} distinct ${field} value(s) shown (top by error count).`));
95363
95800
  return 0;
95364
95801
  }
95365
95802
  let analysis = await logs.analyzeErrors({
@@ -95426,46 +95863,46 @@ async function runLogs(service, opts) {
95426
95863
  return 0;
95427
95864
  }
95428
95865
  console.log(
95429
- import_picocolors24.default.bold(`Error analysis`) + import_picocolors24.default.dim(
95866
+ import_picocolors25.default.bold(`Error analysis`) + import_picocolors25.default.dim(
95430
95867
  ` \u2014 ${renv.project}/${renv.env}` + (scopeService ? ` \xB7 service ${scopeService}` : "") + (opts.grep ? ` \xB7 grep "${opts.grep}"` : "")
95431
95868
  )
95432
95869
  );
95433
- console.log(import_picocolors24.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
95870
+ console.log(import_picocolors25.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
95434
95871
  if (broadeningNote) {
95435
- console.log(import_picocolors24.default.yellow(` ${broadeningNote}`));
95872
+ console.log(import_picocolors25.default.yellow(` ${broadeningNote}`));
95436
95873
  }
95437
95874
  console.log(
95438
- ` ${analysis.totalErrors} error(s) \xB7 ${analysis.signatures.length} signature(s) \xB7 ${import_picocolors24.default.yellow(String(analysis.newSignatures.length))} new`
95875
+ ` ${analysis.totalErrors} error(s) \xB7 ${analysis.signatures.length} signature(s) \xB7 ${import_picocolors25.default.yellow(String(analysis.newSignatures.length))} new`
95439
95876
  );
95440
95877
  console.log("");
95441
95878
  if (analysis.signatures.length === 0) {
95442
- console.log(import_picocolors24.default.dim(" No error-level logs in the window."));
95879
+ console.log(import_picocolors25.default.dim(" No error-level logs in the window."));
95443
95880
  console.log(
95444
- import_picocolors24.default.dim(
95881
+ import_picocolors25.default.dim(
95445
95882
  ` Searched: ${scopeService ? `service "${scopeService}"` : "all services"} \xB7 index: ${indexPattern} \xB7 from: ${fromDisplay} UTC`
95446
95883
  )
95447
95884
  );
95448
- console.log(import_picocolors24.default.dim(` Tip: use --since to widen the window (e.g. --since 30d).`));
95885
+ console.log(import_picocolors25.default.dim(` Tip: use --since to widen the window (e.g. --since 30d).`));
95449
95886
  return 0;
95450
95887
  }
95451
95888
  for (const s of analysis.signatures) {
95452
95889
  const tags = [];
95453
- if (s.isNew) tags.push(import_picocolors24.default.red("NEW"));
95890
+ if (s.isNew) tags.push(import_picocolors25.default.red("NEW"));
95454
95891
  else if (s.ratio !== void 0 && Number.isFinite(s.ratio) && s.ratio >= 1.5) {
95455
- tags.push(import_picocolors24.default.yellow(`spike x${s.ratio.toFixed(1)}`));
95892
+ tags.push(import_picocolors25.default.yellow(`spike x${s.ratio.toFixed(1)}`));
95456
95893
  }
95457
- const svc = s.services.length > 0 ? import_picocolors24.default.dim(` \xB7 ${s.services.slice(0, 3).join(", ")}`) : "";
95894
+ const svc = s.services.length > 0 ? import_picocolors25.default.dim(` \xB7 ${s.services.slice(0, 3).join(", ")}`) : "";
95458
95895
  const tagStr = tags.length > 0 ? ` [${tags.join(", ")}]` : "";
95459
95896
  console.log(
95460
- ` ${import_picocolors24.default.red(String(s.count).padStart(6))} ${import_picocolors24.default.bold(s.key.padEnd(14).slice(0, 14))} ` + import_picocolors24.default.dim(`first ${shortTs(s.firstSeen)} \xB7 last ${shortTs(s.lastSeen)}`) + svc + tagStr
95897
+ ` ${import_picocolors25.default.red(String(s.count).padStart(6))} ${import_picocolors25.default.bold(s.key.padEnd(14).slice(0, 14))} ` + import_picocolors25.default.dim(`first ${shortTs(s.firstSeen)} \xB7 last ${shortTs(s.lastSeen)}`) + svc + tagStr
95461
95898
  );
95462
95899
  }
95463
95900
  if (analysis.affectedServices.length > 0) {
95464
95901
  console.log("");
95465
- console.log(` ${import_picocolors24.default.bold("Affected services:")} ${analysis.affectedServices.join(", ")}`);
95902
+ console.log(` ${import_picocolors25.default.bold("Affected services:")} ${analysis.affectedServices.join(", ")}`);
95466
95903
  }
95467
95904
  console.log("");
95468
- console.log(import_picocolors24.default.dim(" (use --raw to see individual log lines)"));
95905
+ console.log(import_picocolors25.default.dim(" (use --raw to see individual log lines)"));
95469
95906
  if (opts.ai) {
95470
95907
  const result = await renderAiInterpretation({
95471
95908
  command: "logs",
@@ -95484,19 +95921,19 @@ async function runLogs(service, opts) {
95484
95921
  });
95485
95922
  console.log("\n" + renderInterpretation(result));
95486
95923
  if (!result.ok) {
95487
- console.error(import_picocolors24.default.yellow(`[ai] ${result.warning}`));
95924
+ console.error(import_picocolors25.default.yellow(`[ai] ${result.warning}`));
95488
95925
  }
95489
95926
  }
95490
95927
  return 0;
95491
95928
  } catch (err) {
95492
- console.error(import_picocolors24.default.red(err.message));
95929
+ console.error(import_picocolors25.default.red(err.message));
95493
95930
  return 1;
95494
95931
  }
95495
95932
  }
95496
95933
 
95497
95934
  // ../../packages/cli/src/commands/metrics.ts
95498
95935
  init_cjs_shims();
95499
- var import_picocolors25 = __toESM(require_picocolors(), 1);
95936
+ var import_picocolors26 = __toESM(require_picocolors(), 1);
95500
95937
  var METRICS_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
95501
95938
 
95502
95939
  Evidence used
@@ -95541,10 +95978,10 @@ function anomalyColor(anomaly) {
95541
95978
  case "latency-spike":
95542
95979
  case "error-rate-change":
95543
95980
  case "throughput-drop":
95544
- return import_picocolors25.default.red;
95981
+ return import_picocolors26.default.red;
95545
95982
  case "queue-growth":
95546
95983
  case "change":
95547
- return import_picocolors25.default.yellow;
95984
+ return import_picocolors26.default.yellow;
95548
95985
  default:
95549
95986
  return (s) => s;
95550
95987
  }
@@ -95571,7 +96008,7 @@ async function runMetrics(hint, opts) {
95571
96008
  const metrics = metricsProviderFromConfig(config2);
95572
96009
  if (metrics === null) {
95573
96010
  console.error(
95574
- import_picocolors25.default.red(
96011
+ import_picocolors26.default.red(
95575
96012
  "Grafana not configured \u2014 set GRAFANA_URL + GRAFANA_USER + GRAFANA_PASSWORD"
95576
96013
  )
95577
96014
  );
@@ -95579,7 +96016,7 @@ async function runMetrics(hint, opts) {
95579
96016
  }
95580
96017
  const health = await metrics.health();
95581
96018
  if (!health.ok) {
95582
- console.error(import_picocolors25.default.red(`Grafana unreachable: ${health.detail}`));
96019
+ console.error(import_picocolors26.default.red(`Grafana unreachable: ${health.detail}`));
95583
96020
  return 1;
95584
96021
  }
95585
96022
  const stepNum = opts.step !== void 0 ? Number(opts.step) : void 0;
@@ -95608,14 +96045,14 @@ async function runMetrics(hint, opts) {
95608
96045
  return 0;
95609
96046
  }
95610
96047
  if (series.length === 0) {
95611
- console.log(import_picocolors25.default.dim("No series returned."));
96048
+ console.log(import_picocolors26.default.dim("No series returned."));
95612
96049
  return 0;
95613
96050
  }
95614
96051
  for (const s of series) {
95615
96052
  const summary = summarize(s);
95616
96053
  const label = labelStr(s.labels);
95617
96054
  console.log(
95618
- ` ${import_picocolors25.default.cyan(label || "(no labels)")} last=${import_picocolors25.default.bold(fmtNum(summary.last))} avg=${fmtNum(summary.avg)}`
96055
+ ` ${import_picocolors26.default.cyan(label || "(no labels)")} last=${import_picocolors26.default.bold(fmtNum(summary.last))} avg=${fmtNum(summary.avg)}`
95619
96056
  );
95620
96057
  }
95621
96058
  return 0;
@@ -95630,36 +96067,36 @@ async function runMetrics(hint, opts) {
95630
96067
  if (findings2.length === 0) {
95631
96068
  if (hint !== void 0) {
95632
96069
  const tokens = extractHintTokens(hint);
95633
- console.log(import_picocolors25.default.dim(`No panels matched hint "${hint}".`));
96070
+ console.log(import_picocolors26.default.dim(`No panels matched hint "${hint}".`));
95634
96071
  if (tokens.length > 0) {
95635
- console.log(import_picocolors25.default.dim(` Searched for panels containing: ${tokens.join(", ")}`));
96072
+ console.log(import_picocolors26.default.dim(` Searched for panels containing: ${tokens.join(", ")}`));
95636
96073
  }
95637
96074
  console.log(
95638
- import_picocolors25.default.dim(
95639
- ` Tip: run ${import_picocolors25.default.bold("horus metrics")} (no hint) to see all available panels, then use a panel title or keyword directly.`
96075
+ import_picocolors26.default.dim(
96076
+ ` Tip: run ${import_picocolors26.default.bold("horus metrics")} (no hint) to see all available panels, then use a panel title or keyword directly.`
95640
96077
  )
95641
96078
  );
95642
96079
  } else {
95643
- console.log(import_picocolors25.default.dim("No panels found in configured Grafana dashboards."));
96080
+ console.log(import_picocolors26.default.dim("No panels found in configured Grafana dashboards."));
95644
96081
  }
95645
96082
  return 0;
95646
96083
  }
95647
96084
  const hintSuffix = hint !== void 0 ? ` (hint: "${hint}")` : "";
95648
96085
  const matchSources = hint !== void 0 ? [...new Set(findings2.map((f) => f.matchSource).filter(Boolean))] : [];
95649
- const matchSuffix = matchSources.length > 0 ? import_picocolors25.default.dim(` [matched via ${matchSources.join(", ")}]`) : "";
96086
+ const matchSuffix = matchSources.length > 0 ? import_picocolors26.default.dim(` [matched via ${matchSources.join(", ")}]`) : "";
95650
96087
  console.log(
95651
- import_picocolors25.default.bold(
96088
+ import_picocolors26.default.bold(
95652
96089
  `Grafana metrics${hintSuffix} \u2014 ${findings2.length} series across panels`
95653
96090
  ) + matchSuffix
95654
96091
  );
95655
96092
  console.log(
95656
- import_picocolors25.default.dim(
96093
+ import_picocolors26.default.dim(
95657
96094
  ` window: ${new Date(from * 1e3).toISOString()} \u2013 ${new Date(to * 1e3).toISOString()}`
95658
96095
  )
95659
96096
  );
95660
96097
  console.log("");
95661
96098
  if (flagged.length === 0) {
95662
- console.log(import_picocolors25.default.green(" No anomalies detected."));
96099
+ console.log(import_picocolors26.default.green(" No anomalies detected."));
95663
96100
  } else {
95664
96101
  for (const f of flagged) {
95665
96102
  const color = anomalyColor(f.anomaly);
@@ -95668,14 +96105,14 @@ async function runMetrics(hint, opts) {
95668
96105
  const lblStr = labelStr(f.labels);
95669
96106
  console.log(
95670
96107
  color(
95671
- ` ${label.padEnd(22)} ${f.panelTitle.padEnd(40).slice(0, 40)} ${fmtNum(f.baselineAvg)} -> ${fmtNum(f.currentAvg)} (${ratioStr})` + (lblStr !== "" ? ` ${import_picocolors25.default.dim(lblStr)}` : "")
96108
+ ` ${label.padEnd(22)} ${f.panelTitle.padEnd(40).slice(0, 40)} ${fmtNum(f.baselineAvg)} -> ${fmtNum(f.currentAvg)} (${ratioStr})` + (lblStr !== "" ? ` ${import_picocolors26.default.dim(lblStr)}` : "")
95672
96109
  )
95673
96110
  );
95674
96111
  }
95675
96112
  }
95676
96113
  if (ok.length > 0) {
95677
96114
  console.log("");
95678
- console.log(import_picocolors25.default.dim(` ${ok.length} panel series with no anomaly.`));
96115
+ console.log(import_picocolors26.default.dim(` ${ok.length} panel series with no anomaly.`));
95679
96116
  }
95680
96117
  if (opts.ai) {
95681
96118
  const result = await renderAiInterpretation({
@@ -95690,19 +96127,19 @@ async function runMetrics(hint, opts) {
95690
96127
  });
95691
96128
  console.log("\n" + renderInterpretation(result));
95692
96129
  if (!result.ok) {
95693
- console.error(import_picocolors25.default.yellow(`[ai] ${result.warning}`));
96130
+ console.error(import_picocolors26.default.yellow(`[ai] ${result.warning}`));
95694
96131
  }
95695
96132
  }
95696
96133
  return 0;
95697
96134
  } catch (err) {
95698
- console.error(import_picocolors25.default.red(err.message));
96135
+ console.error(import_picocolors26.default.red(err.message));
95699
96136
  return 1;
95700
96137
  }
95701
96138
  }
95702
96139
 
95703
96140
  // ../../packages/cli/src/commands/state.ts
95704
96141
  init_cjs_shims();
95705
- var import_picocolors26 = __toESM(require_picocolors(), 1);
96142
+ var import_picocolors27 = __toESM(require_picocolors(), 1);
95706
96143
  var STATE_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
95707
96144
 
95708
96145
  Evidence used
@@ -95728,13 +96165,13 @@ async function runState(opts) {
95728
96165
  try {
95729
96166
  renv = resolveEnvironment(config2, { project: opts.project, env: opts.env });
95730
96167
  } catch (err) {
95731
- console.error(import_picocolors26.default.red(err.message));
96168
+ console.error(import_picocolors27.default.red(err.message));
95732
96169
  return 1;
95733
96170
  }
95734
96171
  const mongo = mongoForEnv(renv);
95735
96172
  if (mongo === null) {
95736
96173
  console.error(
95737
- import_picocolors26.default.red(
96174
+ import_picocolors27.default.red(
95738
96175
  `No MongoDB connector configured for ${renv.project}/${renv.env} (set the project's Mongo URL env var).`
95739
96176
  )
95740
96177
  );
@@ -95742,7 +96179,7 @@ async function runState(opts) {
95742
96179
  }
95743
96180
  const health = await mongo.health();
95744
96181
  if (!health.ok) {
95745
- console.error(import_picocolors26.default.red(`MongoDB unreachable: ${health.detail}`));
96182
+ console.error(import_picocolors27.default.red(`MongoDB unreachable: ${health.detail}`));
95746
96183
  await mongo.close();
95747
96184
  return 1;
95748
96185
  }
@@ -95768,38 +96205,38 @@ async function runState(opts) {
95768
96205
  );
95769
96206
  return 0;
95770
96207
  }
95771
- const discoveryNote = analysis.autoDiscovered ? import_picocolors26.default.dim(` (${analysis.collections.length} collections, auto-discovered)`) : "";
96208
+ const discoveryNote = analysis.autoDiscovered ? import_picocolors27.default.dim(` (${analysis.collections.length} collections, auto-discovered)`) : "";
95772
96209
  console.log(
95773
- import_picocolors26.default.bold("State analysis") + import_picocolors26.default.dim(` \u2014 ${renv.project}/${renv.env} \xB7 db ${analysis.database}`) + discoveryNote
96210
+ import_picocolors27.default.bold("State analysis") + import_picocolors27.default.dim(` \u2014 ${renv.project}/${renv.env} \xB7 db ${analysis.database}`) + discoveryNote
95774
96211
  );
95775
96212
  console.log("");
95776
96213
  let signals = 0;
95777
96214
  for (const c of analysis.collections) {
95778
96215
  const flags = [];
95779
96216
  if (c.isStale === true) {
95780
- flags.push(import_picocolors26.default.yellow(`stale (last ${c.dateField}, ~${Math.round(c.ageHours ?? 0)}h)`));
96217
+ flags.push(import_picocolors27.default.yellow(`stale (last ${c.dateField}, ~${Math.round(c.ageHours ?? 0)}h)`));
95781
96218
  }
95782
96219
  for (const a of c.anomalies) {
95783
- flags.push(import_picocolors26.default.red(`${a.count}\xD7 "${a.value}"`));
96220
+ flags.push(import_picocolors27.default.red(`${a.count}\xD7 "${a.value}"`));
95784
96221
  signals += 1;
95785
96222
  }
95786
96223
  if (c.isStale === true) signals += 1;
95787
- const head = ` ${import_picocolors26.default.bold(c.collection.padEnd(18).slice(0, 18))} ${import_picocolors26.default.dim(String(c.count).padStart(8) + " docs")}`;
95788
- console.log(flags.length > 0 ? `${head} ${flags.join(" ")}` : import_picocolors26.default.dim(head));
96224
+ const head = ` ${import_picocolors27.default.bold(c.collection.padEnd(18).slice(0, 18))} ${import_picocolors27.default.dim(String(c.count).padStart(8) + " docs")}`;
96225
+ console.log(flags.length > 0 ? `${head} ${flags.join(" ")}` : import_picocolors27.default.dim(head));
95789
96226
  }
95790
96227
  console.log("");
95791
96228
  if (analysis.collections.length === 0) {
95792
96229
  console.log(
95793
- import_picocolors26.default.yellow(" No collections discovered in this database.") + import_picocolors26.default.dim(" Verify the database name in your MongoDB connector config.")
96230
+ import_picocolors27.default.yellow(" No collections discovered in this database.") + import_picocolors27.default.dim(" Verify the database name in your MongoDB connector config.")
95794
96231
  );
95795
96232
  } else {
95796
96233
  const scope = analysis.autoDiscovered ? "collection(s)" : "allowlisted collection(s)";
95797
96234
  console.log(
95798
- signals > 0 ? ` ${import_picocolors26.default.bold(String(signals))} state signal(s) across ${analysis.collections.length} ${scope}` : import_picocolors26.default.dim(` No state anomalies across ${analysis.collections.length} ${scope}.`)
96235
+ signals > 0 ? ` ${import_picocolors27.default.bold(String(signals))} state signal(s) across ${analysis.collections.length} ${scope}` : import_picocolors27.default.dim(` No state anomalies across ${analysis.collections.length} ${scope}.`)
95799
96236
  );
95800
96237
  if (analysis.autoDiscovered) {
95801
96238
  console.log(
95802
- import_picocolors26.default.dim(
96239
+ import_picocolors27.default.dim(
95803
96240
  ` Tip: add a "collections" list to your MongoDB connector config to restrict analysis.`
95804
96241
  )
95805
96242
  );
@@ -95817,7 +96254,7 @@ async function runState(opts) {
95817
96254
  });
95818
96255
  console.log("\n" + renderInterpretation(result));
95819
96256
  if (!result.ok) {
95820
- console.error(import_picocolors26.default.yellow(`[ai] ${result.warning}`));
96257
+ console.error(import_picocolors27.default.yellow(`[ai] ${result.warning}`));
95821
96258
  }
95822
96259
  }
95823
96260
  return 0;
@@ -95825,20 +96262,20 @@ async function runState(opts) {
95825
96262
  await mongo.close();
95826
96263
  }
95827
96264
  } catch (err) {
95828
- console.error(import_picocolors26.default.red(err.message));
96265
+ console.error(import_picocolors27.default.red(err.message));
95829
96266
  return 1;
95830
96267
  }
95831
96268
  }
95832
96269
 
95833
96270
  // ../../packages/cli/src/commands/init.ts
95834
96271
  init_cjs_shims();
95835
- var import_picocolors27 = __toESM(require_picocolors(), 1);
95836
- var import_node_path15 = require("path");
96272
+ var import_picocolors28 = __toESM(require_picocolors(), 1);
96273
+ var import_node_path17 = require("path");
95837
96274
  async function runInit(opts) {
95838
96275
  try {
95839
96276
  const cwd = process.cwd();
95840
- const root = opts.path ? (0, import_node_path15.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
95841
- const name = opts.name ?? (0, import_node_path15.basename)(root);
96277
+ const root = opts.path ? (0, import_node_path17.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
96278
+ const name = opts.name ?? (0, import_node_path17.basename)(root);
95842
96279
  const envName = opts.env ?? "production";
95843
96280
  const repo = { name, path: root };
95844
96281
  if (opts.source) repo["source"] = { hostUrl: opts.source };
@@ -95853,65 +96290,65 @@ async function runInit(opts) {
95853
96290
  const configPath = writeLocalConfig(root, file);
95854
96291
  registerProject(name, root, configPath);
95855
96292
  ensureProjectGitignore(root);
95856
- console.log(`${import_picocolors27.default.green("\u2713")} Initialized Horus project ${import_picocolors27.default.bold(name)}`);
95857
- console.log(import_picocolors27.default.dim(` config: ${configPath}`));
95858
- console.log(import_picocolors27.default.dim(` registered: horus investigate --name ${name} "<hint>"`));
96293
+ console.log(`${import_picocolors28.default.green("\u2713")} Initialized Horus project ${import_picocolors28.default.bold(name)}`);
96294
+ console.log(import_picocolors28.default.dim(` config: ${configPath}`));
96295
+ console.log(import_picocolors28.default.dim(` registered: horus investigate --name ${name} "<hint>"`));
95859
96296
  if (!opts.source) {
95860
96297
  console.log(
95861
- import_picocolors27.default.dim(" no source-intelligence host set \u2014 run `horus index` to analyze + host, or pass --source <url>")
96298
+ import_picocolors28.default.dim(" no source-intelligence host set \u2014 run `horus index` to analyze + host, or pass --source <url>")
95862
96299
  );
95863
96300
  }
95864
96301
  console.log(
95865
- import_picocolors27.default.dim(" add runtime connectors (elasticsearch/mongodb/grafana) to .horus/config.json")
96302
+ import_picocolors28.default.dim(" add runtime connectors (elasticsearch/mongodb/grafana) to .horus/config.json")
95866
96303
  );
95867
96304
  console.log(
95868
- import_picocolors27.default.dim(" .horus/ is gitignored \u2014 local config and runtime state stay out of version control")
96305
+ import_picocolors28.default.dim(" .horus/ is gitignored \u2014 local config and runtime state stay out of version control")
95869
96306
  );
95870
96307
  return 0;
95871
96308
  } catch (err) {
95872
- console.error(import_picocolors27.default.red(err.message));
96309
+ console.error(import_picocolors28.default.red(err.message));
95873
96310
  return 1;
95874
96311
  }
95875
96312
  }
95876
96313
 
95877
96314
  // ../../packages/cli/src/commands/projects.ts
95878
96315
  init_cjs_shims();
95879
- var import_picocolors28 = __toESM(require_picocolors(), 1);
96316
+ var import_picocolors29 = __toESM(require_picocolors(), 1);
95880
96317
  async function runProjects() {
95881
96318
  const reg = readRegistry();
95882
96319
  const names = Object.keys(reg.projects).sort();
95883
96320
  if (names.length === 0) {
95884
96321
  console.log(
95885
- import_picocolors28.default.dim("No registered projects. Run `horus index` (or `horus init`) inside a repo.")
96322
+ import_picocolors29.default.dim("No registered projects. Run `horus index` (or `horus init`) inside a repo.")
95886
96323
  );
95887
96324
  return 0;
95888
96325
  }
95889
- console.log(import_picocolors28.default.bold("Registered Horus projects"));
96326
+ console.log(import_picocolors29.default.bold("Registered Horus projects"));
95890
96327
  console.log("");
95891
96328
  for (const name of names) {
95892
96329
  const entry2 = reg.projects[name];
95893
96330
  if (entry2 === void 0) continue;
95894
- console.log(` ${import_picocolors28.default.bold(name.padEnd(22))} ${import_picocolors28.default.dim(entry2.root)}`);
96331
+ console.log(` ${import_picocolors29.default.bold(name.padEnd(22))} ${import_picocolors29.default.dim(entry2.root)}`);
95895
96332
  }
95896
96333
  console.log("");
95897
- console.log(import_picocolors28.default.dim(' horus investigate --name <name> "<hint>"'));
96334
+ console.log(import_picocolors29.default.dim(' horus investigate --name <name> "<hint>"'));
95898
96335
  return 0;
95899
96336
  }
95900
96337
 
95901
96338
  // ../../packages/cli/src/commands/setup.ts
95902
96339
  init_cjs_shims();
95903
- var import_picocolors29 = __toESM(require_picocolors(), 1);
96340
+ var import_picocolors30 = __toESM(require_picocolors(), 1);
95904
96341
  var DEFAULT_DB_URL3 = "postgresql://horus:horus@localhost:5433/horus";
95905
96342
  async function runSetup(opts) {
95906
96343
  const write = opts.write ?? ((line2) => console.log(line2));
95907
96344
  let ok = true;
95908
- write(import_picocolors29.default.bold("\nHorus setup\n"));
96345
+ write(import_picocolors30.default.bold("\nHorus setup\n"));
95909
96346
  const backendVersion = await getSourceVersion();
95910
96347
  if (backendVersion === null) {
95911
96348
  ok = false;
95912
- write(` ${import_picocolors29.default.red("\u25CF")} Horus source-intelligence backend not found`);
96349
+ write(` ${import_picocolors30.default.red("\u25CF")} Horus source-intelligence backend not found`);
95913
96350
  write(
95914
- import_picocolors29.default.dim(
96351
+ import_picocolors30.default.dim(
95915
96352
  ` install it (Python 3.11+ required):
95916
96353
  pip install horus-source
95917
96354
  ensure ~/.local/bin is on your PATH`
@@ -95920,17 +96357,17 @@ async function runSetup(opts) {
95920
96357
  } else if (backendVersion !== PINNED_SOURCE_VERSION) {
95921
96358
  ok = false;
95922
96359
  write(
95923
- ` ${import_picocolors29.default.yellow("\u25CF")} Horus source-intelligence backend version mismatch` + import_picocolors29.default.dim(` (installed: ${backendVersion}, required: ${PINNED_SOURCE_VERSION})`)
96360
+ ` ${import_picocolors30.default.yellow("\u25CF")} Horus source-intelligence backend version mismatch` + import_picocolors30.default.dim(` (installed: ${backendVersion}, required: ${PINNED_SOURCE_VERSION})`)
95924
96361
  );
95925
96362
  write(
95926
- import_picocolors29.default.dim(
96363
+ import_picocolors30.default.dim(
95927
96364
  ` update it:
95928
96365
  pip install --upgrade horus-source`
95929
96366
  )
95930
96367
  );
95931
96368
  } else {
95932
96369
  write(
95933
- ` ${import_picocolors29.default.green("\u25CF")} Horus source-intelligence backend ` + import_picocolors29.default.dim(`(${backendVersion})`)
96370
+ ` ${import_picocolors30.default.green("\u25CF")} Horus source-intelligence backend ` + import_picocolors30.default.dim(`(${backendVersion})`)
95934
96371
  );
95935
96372
  }
95936
96373
  let dbUrl = process.env["DATABASE_URL"] ?? DEFAULT_DB_URL3;
@@ -95942,11 +96379,11 @@ async function runSetup(opts) {
95942
96379
  }
95943
96380
  const db = await checkDatabase(dbUrl);
95944
96381
  if (db.reachable) {
95945
- write(` ${import_picocolors29.default.green("\u25CF")} Postgres reachable ${import_picocolors29.default.dim(`(${db.schemaDetail})`)}`);
96382
+ write(` ${import_picocolors30.default.green("\u25CF")} Postgres reachable ${import_picocolors30.default.dim(`(${db.schemaDetail})`)}`);
95946
96383
  if (!db.schemaReady) {
95947
96384
  ok = false;
95948
96385
  write(
95949
- import_picocolors29.default.dim(
96386
+ import_picocolors30.default.dim(
95950
96387
  ` schema not applied \u2014 run migrations:
95951
96388
  from the Horus repo: pnpm db migrate
95952
96389
  or apply the schema directly: https://github.com/meritt-dev/horus/tree/master/packages/db/drizzle`
@@ -95955,9 +96392,9 @@ async function runSetup(opts) {
95955
96392
  }
95956
96393
  } else {
95957
96394
  ok = false;
95958
- write(` ${import_picocolors29.default.red("\u25CF")} Postgres unreachable`);
96395
+ write(` ${import_picocolors30.default.red("\u25CF")} Postgres unreachable`);
95959
96396
  write(
95960
- import_picocolors29.default.dim(
96397
+ import_picocolors30.default.dim(
95961
96398
  ` start a local instance:
95962
96399
  docker run -d --name horus-db \\
95963
96400
  -e POSTGRES_USER=horus -e POSTGRES_PASSWORD=horus -e POSTGRES_DB=horus \\
@@ -95982,10 +96419,10 @@ async function runSetup(opts) {
95982
96419
  if (!health.ok) {
95983
96420
  ok = false;
95984
96421
  write(
95985
- ` ${import_picocolors29.default.red("\u25CF")} Source intelligence host unreachable for ${import_picocolors29.default.bold(repo.name)} ` + import_picocolors29.default.dim(`(${repoHostUrl})`)
96422
+ ` ${import_picocolors30.default.red("\u25CF")} Source intelligence host unreachable for ${import_picocolors30.default.bold(repo.name)} ` + import_picocolors30.default.dim(`(${repoHostUrl})`)
95986
96423
  );
95987
96424
  write(
95988
- import_picocolors29.default.dim(
96425
+ import_picocolors30.default.dim(
95989
96426
  ` start the source intelligence host:
95990
96427
  cd ${repo.path}
95991
96428
  horus index`
@@ -95996,10 +96433,10 @@ async function runSetup(opts) {
95996
96433
  if (count === 0) {
95997
96434
  ok = false;
95998
96435
  write(
95999
- ` ${import_picocolors29.default.yellow("\u25CF")} Source intelligence host running but ${import_picocolors29.default.bold(repo.name)} is not indexed`
96436
+ ` ${import_picocolors30.default.yellow("\u25CF")} Source intelligence host running but ${import_picocolors30.default.bold(repo.name)} is not indexed`
96000
96437
  );
96001
96438
  write(
96002
- import_picocolors29.default.dim(
96439
+ import_picocolors30.default.dim(
96003
96440
  ` index the repo:
96004
96441
  cd ${repo.path}
96005
96442
  horus index`
@@ -96007,7 +96444,7 @@ async function runSetup(opts) {
96007
96444
  );
96008
96445
  } else {
96009
96446
  write(
96010
- ` ${import_picocolors29.default.green("\u25CF")} ${import_picocolors29.default.bold(repo.name)} \u2014 ${count} nodes indexed ` + import_picocolors29.default.dim(`(${repoHostUrl})`)
96447
+ ` ${import_picocolors30.default.green("\u25CF")} ${import_picocolors30.default.bold(repo.name)} \u2014 ${count} nodes indexed ` + import_picocolors30.default.dim(`(${repoHostUrl})`)
96011
96448
  );
96012
96449
  }
96013
96450
  }
@@ -96017,10 +96454,10 @@ async function runSetup(opts) {
96017
96454
  write("");
96018
96455
  if (ok) {
96019
96456
  write(
96020
- import_picocolors29.default.green("Ready.") + ' Next: `cd` into a repo and run `horus index`, then `horus investigate "<hint>"`.'
96457
+ import_picocolors30.default.green("Ready.") + ' Next: `cd` into a repo and run `horus index`, then `horus investigate "<hint>"`.'
96021
96458
  );
96022
96459
  } else {
96023
- write(import_picocolors29.default.yellow("Resolve the items above, then re-run `horus setup`."));
96460
+ write(import_picocolors30.default.yellow("Resolve the items above, then re-run `horus setup`."));
96024
96461
  }
96025
96462
  return ok ? 0 : 1;
96026
96463
  }
@@ -96029,12 +96466,12 @@ async function runSetup(opts) {
96029
96466
  init_cjs_shims();
96030
96467
  var import_node_readline = require("readline");
96031
96468
  var import_node_child_process6 = require("child_process");
96032
- var import_picocolors32 = __toESM(require_picocolors(), 1);
96469
+ var import_picocolors33 = __toESM(require_picocolors(), 1);
96033
96470
 
96034
96471
  // ../../packages/cli/src/lib/tty-selector.ts
96035
96472
  init_cjs_shims();
96036
96473
  var import_node_tty = require("tty");
96037
- var import_picocolors30 = __toESM(require_picocolors(), 1);
96474
+ var import_picocolors31 = __toESM(require_picocolors(), 1);
96038
96475
  var ExitPromptError = class extends Error {
96039
96476
  constructor(message = "Prompt was cancelled") {
96040
96477
  super(message);
@@ -96090,7 +96527,7 @@ async function checkboxSearch(opts) {
96090
96527
  clear();
96091
96528
  const lines = [];
96092
96529
  lines.push(
96093
- `? ${import_picocolors30.default.bold(message)} ${import_picocolors30.default.dim("(\u2191\u2193 navigate \u2022 space toggle \u2022 enter confirm \u2022 type filter)")}`
96530
+ `? ${import_picocolors31.default.bold(message)} ${import_picocolors31.default.dim("(\u2191\u2193 navigate \u2022 space toggle \u2022 enter confirm \u2022 type filter)")}`
96094
96531
  );
96095
96532
  const visible = filtered.slice(visibleOffset, visibleOffset + pageSize);
96096
96533
  for (let i = 0; i < visible.length; i++) {
@@ -96098,29 +96535,29 @@ async function checkboxSearch(opts) {
96098
96535
  const choice = visible[i];
96099
96536
  const isCursor = idx === cursor;
96100
96537
  const isSelected = selected.has(choice);
96101
- const marker = isSelected ? import_picocolors30.default.green("\u25CF") : " ";
96538
+ const marker = isSelected ? import_picocolors31.default.green("\u25CF") : " ";
96102
96539
  const prefix = `[${marker}]`;
96103
- const label = isCursor ? import_picocolors30.default.cyan(choice) : choice;
96104
- const pointer = isCursor ? import_picocolors30.default.cyan("\u276F") : " ";
96540
+ const label = isCursor ? import_picocolors31.default.cyan(choice) : choice;
96541
+ const pointer = isCursor ? import_picocolors31.default.cyan("\u276F") : " ";
96105
96542
  lines.push(` ${pointer} ${prefix} ${label}`);
96106
96543
  }
96107
96544
  if (filtered.length === 0) {
96108
- lines.push(import_picocolors30.default.dim(" No matches"));
96545
+ lines.push(import_picocolors31.default.dim(" No matches"));
96109
96546
  }
96110
96547
  const statusParts = [
96111
96548
  `${selected.size} selected`,
96112
96549
  `${filtered.length}/${choices.length} matches`
96113
96550
  ];
96114
96551
  if (filter) statusParts.push(`filter: ${filter}`);
96115
- lines.push(import_picocolors30.default.dim(` ${statusParts.join(" \xB7 ")}`));
96552
+ lines.push(import_picocolors31.default.dim(` ${statusParts.join(" \xB7 ")}`));
96116
96553
  output.write(lines.join("\n"));
96117
96554
  lastRenderLines = lines.length;
96118
96555
  }
96119
96556
  function finish(values2) {
96120
96557
  cleanup();
96121
- const summary = values2.length > 0 ? values2.join(", ") : import_picocolors30.default.dim("none");
96558
+ const summary = values2.length > 0 ? values2.join(", ") : import_picocolors31.default.dim("none");
96122
96559
  output.write(`
96123
- ? ${import_picocolors30.default.bold(message)} ${summary}
96560
+ ? ${import_picocolors31.default.bold(message)} ${summary}
96124
96561
  `);
96125
96562
  resolve8(values2);
96126
96563
  }
@@ -96212,7 +96649,7 @@ async function checkboxSearch(opts) {
96212
96649
  // ../../packages/cli/src/commands/connect-ai.ts
96213
96650
  init_cjs_shims();
96214
96651
  var import_node_child_process5 = require("child_process");
96215
- var import_picocolors31 = __toESM(require_picocolors(), 1);
96652
+ var import_picocolors32 = __toESM(require_picocolors(), 1);
96216
96653
  function cliInstalled(id) {
96217
96654
  const r = (0, import_node_child_process5.spawnSync)(id, ["--version"], { stdio: "ignore", timeout: 2e3 });
96218
96655
  return !r.error;
@@ -96240,13 +96677,13 @@ async function runConnectAi(opts) {
96240
96677
  const root = findRepoRoot(cwd) ?? cwd;
96241
96678
  const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
96242
96679
  const installed = LOCAL_PROVIDER_IDS.filter((id) => cliInstalled(id));
96243
- console.log(import_picocolors31.default.bold("\nAI providers"));
96680
+ console.log(import_picocolors32.default.bold("\nAI providers"));
96244
96681
  console.log(
96245
- import_picocolors31.default.dim(
96682
+ import_picocolors32.default.dim(
96246
96683
  ` Local CLIs on PATH: ${installed.length > 0 ? installed.join(", ") : "none detected"}`
96247
96684
  )
96248
96685
  );
96249
- console.log(import_picocolors31.default.dim(" Cloud: anthropic (Anthropic Claude API \u2014 used by `investigate --ai`)\n"));
96686
+ console.log(import_picocolors32.default.dim(" Cloud: anthropic (Anthropic Claude API \u2014 used by `investigate --ai`)\n"));
96250
96687
  let provider = opts.provider;
96251
96688
  if (provider === void 0) {
96252
96689
  if (isInteractive()) {
@@ -96257,7 +96694,7 @@ async function runConnectAi(opts) {
96257
96694
  }
96258
96695
  }
96259
96696
  if (!AI_PROVIDERS.includes(provider)) {
96260
- console.error(import_picocolors31.default.red(`Unknown AI provider: ${provider}`) + import_picocolors31.default.dim(`
96697
+ console.error(import_picocolors32.default.red(`Unknown AI provider: ${provider}`) + import_picocolors32.default.dim(`
96261
96698
  supported: ${AI_PROVIDERS.join(", ")}`));
96262
96699
  return 1;
96263
96700
  }
@@ -96270,7 +96707,7 @@ async function runConnectAi(opts) {
96270
96707
  }
96271
96708
  if (!apiKey) {
96272
96709
  console.error(
96273
- import_picocolors31.default.red("No API key provided.") + import_picocolors31.default.dim("\n Pass --api-key sk-ant-\u2026 or set ANTHROPIC_API_KEY and re-run.")
96710
+ import_picocolors32.default.red("No API key provided.") + import_picocolors32.default.dim("\n Pass --api-key sk-ant-\u2026 or set ANTHROPIC_API_KEY and re-run.")
96274
96711
  );
96275
96712
  return 1;
96276
96713
  }
@@ -96278,28 +96715,28 @@ async function runConnectAi(opts) {
96278
96715
  const probe2 = await probeAnthropic(apiKey);
96279
96716
  if (!probe2.ok) {
96280
96717
  console.error(`
96281
- ${import_picocolors31.default.red("\u2717 Anthropic key check failed:")} ${probe2.detail}`);
96282
- console.error(import_picocolors31.default.dim(" Fix the key and retry, or pass --no-test to skip."));
96718
+ ${import_picocolors32.default.red("\u2717 Anthropic key check failed:")} ${probe2.detail}`);
96719
+ console.error(import_picocolors32.default.dim(" Fix the key and retry, or pass --no-test to skip."));
96283
96720
  return 1;
96284
96721
  }
96285
96722
  console.log(`
96286
- ${import_picocolors31.default.green("\u2713")} anthropic ${import_picocolors31.default.dim(`(${probe2.detail})`)}`);
96723
+ ${import_picocolors32.default.green("\u2713")} anthropic ${import_picocolors32.default.dim(`(${probe2.detail})`)}`);
96287
96724
  }
96288
96725
  if (opts.model) aiBlock["anthropic"] = { model: opts.model };
96289
96726
  storedKey = apiKey;
96290
96727
  } else {
96291
96728
  if (!installed.includes(provider)) {
96292
96729
  console.error(
96293
- import_picocolors31.default.red(`${provider} CLI not found on PATH.`) + import_picocolors31.default.dim(`
96730
+ import_picocolors32.default.red(`${provider} CLI not found on PATH.`) + import_picocolors32.default.dim(`
96294
96731
  Install it first, or choose anthropic.`)
96295
96732
  );
96296
96733
  return 1;
96297
96734
  }
96298
96735
  const desc2 = DEFAULT_LOCAL_PROVIDER_REGISTRY.get(provider);
96299
96736
  console.log(`
96300
- ${import_picocolors31.default.green("\u2713")} ${desc2?.displayName ?? provider} ${import_picocolors31.default.dim("detected on PATH")}`);
96737
+ ${import_picocolors32.default.green("\u2713")} ${desc2?.displayName ?? provider} ${import_picocolors32.default.dim("detected on PATH")}`);
96301
96738
  console.log(
96302
- import_picocolors31.default.dim(
96739
+ import_picocolors32.default.dim(
96303
96740
  " Note: `investigate --ai` currently uses the Anthropic API for narrative.\n Local-CLI narrative generation is recorded as your preference for future use."
96304
96741
  )
96305
96742
  );
@@ -96317,15 +96754,15 @@ ${import_picocolors31.default.green("\u2713")} ${desc2?.displayName ?? provider}
96317
96754
  });
96318
96755
  }
96319
96756
  console.log(`
96320
- ${import_picocolors31.default.green("\u2713")} ${import_picocolors31.default.bold("ai")} provider saved \u2192 ${import_picocolors31.default.dim(configPath)}`);
96321
- console.log(import_picocolors31.default.dim(` provider: ${provider}`));
96757
+ ${import_picocolors32.default.green("\u2713")} ${import_picocolors32.default.bold("ai")} provider saved \u2192 ${import_picocolors32.default.dim(configPath)}`);
96758
+ console.log(import_picocolors32.default.dim(` provider: ${provider}`));
96322
96759
  if (storedKey && secretsPathStr) {
96323
- console.log(import_picocolors31.default.dim(` anthropic key: ${redactKey(storedKey)} \u2192 ${secretsPathStr} (gitignored)`));
96760
+ console.log(import_picocolors32.default.dim(` anthropic key: ${redactKey(storedKey)} \u2192 ${secretsPathStr} (gitignored)`));
96324
96761
  }
96325
- console.log(import_picocolors31.default.dim(' run: horus investigate "<hint>" --ai'));
96762
+ console.log(import_picocolors32.default.dim(' run: horus investigate "<hint>" --ai'));
96326
96763
  return 0;
96327
96764
  } catch (err) {
96328
- console.error(import_picocolors31.default.red(err instanceof Error ? err.message : String(err)));
96765
+ console.error(import_picocolors32.default.red(err instanceof Error ? err.message : String(err)));
96329
96766
  return 1;
96330
96767
  }
96331
96768
  }
@@ -96357,7 +96794,7 @@ async function runConnect(type, opts) {
96357
96794
  }
96358
96795
  if (!SUPPORTED.includes(type)) {
96359
96796
  console.error(
96360
- import_picocolors32.default.red(`Unknown connector type: ${type}`) + import_picocolors32.default.dim(`
96797
+ import_picocolors33.default.red(`Unknown connector type: ${type}`) + import_picocolors33.default.dim(`
96361
96798
  supported: ${SUPPORTED.join(", ")}, ai`)
96362
96799
  );
96363
96800
  return 1;
@@ -96388,20 +96825,20 @@ async function runConnect(type, opts) {
96388
96825
  if (!probeResult.ok) {
96389
96826
  console.error(
96390
96827
  `
96391
- ${import_picocolors32.default.red(`\u2717 Could not reach ${connectorType}:`)} ${probeResult.detail}` + import_picocolors32.default.dim("\n Fix the connection and retry, or pass --no-test to skip.")
96828
+ ${import_picocolors33.default.red(`\u2717 Could not reach ${connectorType}:`)} ${probeResult.detail}` + import_picocolors33.default.dim("\n Fix the connection and retry, or pass --no-test to skip.")
96392
96829
  );
96393
96830
  return 1;
96394
96831
  }
96395
96832
  console.log(
96396
96833
  `
96397
- ${import_picocolors32.default.green("\u2713")} ${connectorType} reachable ${import_picocolors32.default.dim(`(${probeResult.detail})`)}`
96834
+ ${import_picocolors33.default.green("\u2713")} ${connectorType} reachable ${import_picocolors33.default.dim(`(${probeResult.detail})`)}`
96398
96835
  );
96399
96836
  }
96400
96837
  const hasLiteralCredentials = filled.url !== void 0 || filled.password !== void 0 || filled.username !== void 0;
96401
96838
  if (hasLiteralCredentials) {
96402
96839
  if (isGitTracked(configPath, root)) {
96403
96840
  console.error(
96404
- import_picocolors32.default.red(".horus/config.json is already tracked by Git.") + "\nStoring credentials here would expose them in the repository.\n" + import_picocolors32.default.dim(
96841
+ import_picocolors33.default.red(".horus/config.json is already tracked by Git.") + "\nStoring credentials here would expose them in the repository.\n" + import_picocolors33.default.dim(
96405
96842
  " 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."
96406
96843
  )
96407
96844
  );
@@ -96411,18 +96848,18 @@ ${import_picocolors32.default.green("\u2713")} ${connectorType} reachable ${impo
96411
96848
  }
96412
96849
  patchLocalConnector(configPath, connectorType, patch, filled.env);
96413
96850
  console.log(
96414
- `${import_picocolors32.default.green("\u2713")} ${import_picocolors32.default.bold(connectorType)} connector saved \u2192 ${import_picocolors32.default.dim(configPath)}`
96851
+ `${import_picocolors33.default.green("\u2713")} ${import_picocolors33.default.bold(connectorType)} connector saved \u2192 ${import_picocolors33.default.dim(configPath)}`
96415
96852
  );
96416
96853
  printSummary(connectorType, filled);
96417
- console.log(import_picocolors32.default.dim(`
96854
+ console.log(import_picocolors33.default.dim(`
96418
96855
  run: horus investigate "<hint>"`));
96419
96856
  return 0;
96420
96857
  } catch (err) {
96421
96858
  if (err instanceof ExitPromptError) {
96422
- console.error(import_picocolors32.default.red("Cancelled."));
96859
+ console.error(import_picocolors33.default.red("Cancelled."));
96423
96860
  return 1;
96424
96861
  }
96425
- console.error(import_picocolors32.default.red(err.message));
96862
+ console.error(import_picocolors33.default.red(err.message));
96426
96863
  return 1;
96427
96864
  }
96428
96865
  }
@@ -96431,7 +96868,7 @@ async function fillInteractive(type, opts) {
96431
96868
  if (!needsInteraction) return opts;
96432
96869
  console.log(
96433
96870
  `
96434
- ${import_picocolors32.default.bold(`Connect ${type}`)} ${import_picocolors32.default.dim("(press Enter to skip optional fields)")}
96871
+ ${import_picocolors33.default.bold(`Connect ${type}`)} ${import_picocolors33.default.dim("(press Enter to skip optional fields)")}
96435
96872
  `
96436
96873
  );
96437
96874
  const filled = { ...opts };
@@ -96486,7 +96923,7 @@ ${import_picocolors32.default.bold(`Connect ${type}`)} ${import_picocolors32.def
96486
96923
  break;
96487
96924
  case "redis": {
96488
96925
  console.log(
96489
- import_picocolors32.default.dim(
96926
+ import_picocolors33.default.dim(
96490
96927
  " Tip: embed credentials directly in the URL \u2014 redis://:password@host:6379\n or enter the URL and password separately below."
96491
96928
  )
96492
96929
  );
@@ -96524,8 +96961,8 @@ function missingRequired(type, opts) {
96524
96961
  }
96525
96962
  function ask(label, placeholder = "", required2 = true) {
96526
96963
  return new Promise((resolve8) => {
96527
- const hint = placeholder ? import_picocolors32.default.dim(` (${placeholder})`) : "";
96528
- const suffix = required2 ? "" : import_picocolors32.default.dim(" [optional]");
96964
+ const hint = placeholder ? import_picocolors33.default.dim(` (${placeholder})`) : "";
96965
+ const suffix = required2 ? "" : import_picocolors33.default.dim(" [optional]");
96529
96966
  process.stdout.write(` ${label}${suffix}${hint}: `);
96530
96967
  const rl = (0, import_node_readline.createInterface)({
96531
96968
  input: process.stdin,
@@ -96542,7 +96979,7 @@ function askPassword(label) {
96542
96979
  return new Promise((resolve8) => {
96543
96980
  const stdin = process.stdin;
96544
96981
  if (typeof stdin.setRawMode === "function") {
96545
- process.stdout.write(` ${label}${import_picocolors32.default.dim(" [optional]")}: `);
96982
+ process.stdout.write(` ${label}${import_picocolors33.default.dim(" [optional]")}: `);
96546
96983
  stdin.setRawMode(true);
96547
96984
  stdin.resume();
96548
96985
  let value = "";
@@ -96642,15 +97079,15 @@ function describeProbe(p) {
96642
97079
  return `${p.keyCount} keys \xB7 ${p.suggestedRoles.join("/")}${examples ? ` \xB7 ${examples}` : ""}`;
96643
97080
  }
96644
97081
  async function discoverAndSelectDbs(url, bullmqPrefix) {
96645
- console.log(import_picocolors32.default.dim("\n Scanning DBs 0-15 (read-only, sampled)\u2026"));
97082
+ console.log(import_picocolors33.default.dim("\n Scanning DBs 0-15 (read-only, sampled)\u2026"));
96646
97083
  const probes = await probeRedisDatabases(url, { bullmqPrefix });
96647
97084
  const nonEmpty = probes.filter((p) => p.reachable && p.keyCount > 0);
96648
97085
  if (nonEmpty.length === 0) {
96649
- console.log(import_picocolors32.default.dim(" No populated DBs found."));
97086
+ console.log(import_picocolors33.default.dim(" No populated DBs found."));
96650
97087
  return [];
96651
97088
  }
96652
97089
  for (const p of nonEmpty) {
96653
- console.log(` ${import_picocolors32.default.bold(`DB ${p.db}`)} ${import_picocolors32.default.dim("\xB7 " + describeProbe(p))}`);
97090
+ console.log(` ${import_picocolors33.default.bold(`DB ${p.db}`)} ${import_picocolors33.default.dim("\xB7 " + describeProbe(p))}`);
96654
97091
  }
96655
97092
  const byLabel = /* @__PURE__ */ new Map();
96656
97093
  const choices = nonEmpty.map((p) => {
@@ -96761,7 +97198,7 @@ function printSummary(type, opts) {
96761
97198
  } else if (opts.dashboard) {
96762
97199
  lines.push(` dashboard: ${opts.dashboard}`);
96763
97200
  }
96764
- if (lines.length > 0) console.log(import_picocolors32.default.dim(lines.join("\n")));
97201
+ if (lines.length > 0) console.log(import_picocolors33.default.dim(lines.join("\n")));
96765
97202
  }
96766
97203
  function isGitTracked(filePath, cwd) {
96767
97204
  try {
@@ -96800,11 +97237,11 @@ async function askIndexSelection(indices) {
96800
97237
  const shown = indices.slice(0, MAX_DISPLAY);
96801
97238
  console.log("\n Available Elasticsearch indexes/data streams:");
96802
97239
  shown.forEach((name, i) => {
96803
- console.log(` ${import_picocolors32.default.dim(`[${i + 1}]`)} ${name}`);
97240
+ console.log(` ${import_picocolors33.default.dim(`[${i + 1}]`)} ${name}`);
96804
97241
  });
96805
97242
  if (indices.length > MAX_DISPLAY) {
96806
97243
  console.log(
96807
- import_picocolors32.default.dim(
97244
+ import_picocolors33.default.dim(
96808
97245
  ` \u2026 and ${indices.length - MAX_DISPLAY} more (type a pattern manually to match all)`
96809
97246
  )
96810
97247
  );
@@ -96848,11 +97285,11 @@ async function askDashboardSelection(dashboards) {
96848
97285
  const shown = dashboards.slice(0, MAX_DISPLAY);
96849
97286
  console.log("\n Available Grafana dashboards:");
96850
97287
  shown.forEach((d, i) => {
96851
- const folder = d.folderTitle ? import_picocolors32.default.dim(` (${d.folderTitle})`) : "";
96852
- console.log(` ${import_picocolors32.default.dim(`[${i + 1}]`)} ${d.title}${folder}`);
97288
+ const folder = d.folderTitle ? import_picocolors33.default.dim(` (${d.folderTitle})`) : "";
97289
+ console.log(` ${import_picocolors33.default.dim(`[${i + 1}]`)} ${d.title}${folder}`);
96853
97290
  });
96854
97291
  if (dashboards.length > MAX_DISPLAY) {
96855
- console.log(import_picocolors32.default.dim(` \u2026 and ${dashboards.length - MAX_DISPLAY} more`));
97292
+ console.log(import_picocolors33.default.dim(` \u2026 and ${dashboards.length - MAX_DISPLAY} more`));
96856
97293
  }
96857
97294
  const input = (await ask(
96858
97295
  ` Select dashboards to use (e.g. 1,2 or Enter to type uid manually)`,
@@ -96903,12 +97340,12 @@ function redactUrl(raw) {
96903
97340
  // ../../packages/cli/src/commands/stop.ts
96904
97341
  init_cjs_shims();
96905
97342
  var import_node_child_process7 = require("child_process");
96906
- var import_node_fs14 = require("fs");
97343
+ var import_node_fs16 = require("fs");
96907
97344
  var import_node_util4 = require("util");
96908
- var import_node_path16 = require("path");
96909
- var import_picocolors33 = __toESM(require_picocolors(), 1);
97345
+ var import_node_path18 = require("path");
97346
+ var import_picocolors34 = __toESM(require_picocolors(), 1);
96910
97347
  var execFileAsync = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
96911
- var unlinkAsync = (0, import_node_util4.promisify)(import_node_fs14.unlink);
97348
+ var unlinkAsync = (0, import_node_util4.promisify)(import_node_fs16.unlink);
96912
97349
  var SPAWNED_HOST_FILE2 = "spawned-host.json";
96913
97350
  var START_TIME_TOLERANCE_S = 60;
96914
97351
  var STOP_WAIT_MS = 5e3;
@@ -96923,30 +97360,30 @@ async function runStop(opts) {
96923
97360
  const root = findRepoRoot(cwd) ?? cwd;
96924
97361
  const hostUrl = readSourceHostUrl(root);
96925
97362
  if (!hostUrl) {
96926
- console.log(import_picocolors33.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
97363
+ console.log(import_picocolors34.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
96927
97364
  return 0;
96928
97365
  }
96929
97366
  return await stopHost(root, hostUrl);
96930
97367
  } catch (err) {
96931
- console.error(import_picocolors33.default.red(err.message));
97368
+ console.error(import_picocolors34.default.red(err.message));
96932
97369
  return 1;
96933
97370
  }
96934
97371
  }
96935
97372
  async function stopHost(root, hostUrl) {
96936
97373
  const alive = await isHostHealthy(hostUrl);
96937
97374
  if (!alive) {
96938
- console.log(import_picocolors33.default.dim(`Host ${hostUrl} is already stopped.`));
97375
+ console.log(import_picocolors34.default.dim(`Host ${hostUrl} is already stopped.`));
96939
97376
  return 0;
96940
97377
  }
96941
97378
  const port = extractPort(hostUrl);
96942
97379
  if (port === null) {
96943
- console.error(import_picocolors33.default.red(`Cannot determine port from host URL: ${hostUrl}`));
97380
+ console.error(import_picocolors34.default.red(`Cannot determine port from host URL: ${hostUrl}`));
96944
97381
  return 1;
96945
97382
  }
96946
97383
  const spawned = readSpawnedHost(root);
96947
97384
  if (spawned === null) {
96948
97385
  console.error(
96949
- import_picocolors33.default.red(
97386
+ import_picocolors34.default.red(
96950
97387
  `No ownership record found (.horus/${SPAWNED_HOST_FILE2} absent). Horus will not stop a host it did not spawn.`
96951
97388
  )
96952
97389
  );
@@ -96954,12 +97391,12 @@ async function stopHost(root, hostUrl) {
96954
97391
  }
96955
97392
  const recordError = validateSpawnedRecord(spawned);
96956
97393
  if (recordError !== null) {
96957
- console.error(import_picocolors33.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
97394
+ console.error(import_picocolors34.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
96958
97395
  return 1;
96959
97396
  }
96960
97397
  if (spawned.port !== port) {
96961
97398
  console.error(
96962
- import_picocolors33.default.red(
97399
+ import_picocolors34.default.red(
96963
97400
  `Ownership record port (${spawned.port}) does not match host URL port (${port}). Record may be stale.`
96964
97401
  )
96965
97402
  );
@@ -96967,7 +97404,7 @@ async function stopHost(root, hostUrl) {
96967
97404
  }
96968
97405
  if (spawned.root !== root) {
96969
97406
  console.error(
96970
- import_picocolors33.default.red(
97407
+ import_picocolors34.default.red(
96971
97408
  `Ownership record root (${spawned.root}) does not match resolved root (${root}). Record may be stale.`
96972
97409
  )
96973
97410
  );
@@ -96975,9 +97412,9 @@ async function stopHost(root, hostUrl) {
96975
97412
  }
96976
97413
  const info = await getProcessInfo(spawned.pid);
96977
97414
  if (info === null) {
96978
- console.log(import_picocolors33.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
97415
+ console.log(import_picocolors34.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
96979
97416
  try {
96980
- await unlinkAsync((0, import_node_path16.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
97417
+ await unlinkAsync((0, import_node_path18.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
96981
97418
  } catch {
96982
97419
  }
96983
97420
  return 0;
@@ -96988,7 +97425,7 @@ async function stopHost(root, hostUrl) {
96988
97425
  );
96989
97426
  if (!hostPortRe.test(info.args)) {
96990
97427
  console.error(
96991
- import_picocolors33.default.red(
97428
+ import_picocolors34.default.red(
96992
97429
  `Pid ${spawned.pid} args do not match "horus-source host --port ${portStr}". Got: "${info.args.slice(0, 120)}". Aborting for safety.`
96993
97430
  )
96994
97431
  );
@@ -96997,12 +97434,12 @@ async function stopHost(root, hostUrl) {
96997
97434
  const startTs = new Date(spawned.startedAt).getTime();
96998
97435
  const recordedAgeS = Math.round((Date.now() - startTs) / 1e3);
96999
97436
  if (!Number.isFinite(info.etimeSeconds)) {
97000
- console.error(import_picocolors33.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
97437
+ console.error(import_picocolors34.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
97001
97438
  return 1;
97002
97439
  }
97003
97440
  if (Math.abs(info.etimeSeconds - recordedAgeS) > START_TIME_TOLERANCE_S) {
97004
97441
  console.error(
97005
- import_picocolors33.default.red(
97442
+ import_picocolors34.default.red(
97006
97443
  `Pid ${spawned.pid} age mismatch: record says ~${recordedAgeS}s, process reports ${info.etimeSeconds}s elapsed. Possible PID reuse \u2014 aborting for safety.`
97007
97444
  )
97008
97445
  );
@@ -97014,9 +97451,9 @@ async function stopHost(root, hostUrl) {
97014
97451
  signaled = true;
97015
97452
  } catch (err) {
97016
97453
  if (err.code === "ESRCH") {
97017
- console.log(import_picocolors33.default.dim(`Process pid ${spawned.pid} exited before signal \u2014 already stopped.`));
97454
+ console.log(import_picocolors34.default.dim(`Process pid ${spawned.pid} exited before signal \u2014 already stopped.`));
97018
97455
  } else {
97019
- console.error(import_picocolors33.default.red(`Failed to signal pid ${spawned.pid}: ${err.message}`));
97456
+ console.error(import_picocolors34.default.red(`Failed to signal pid ${spawned.pid}: ${err.message}`));
97020
97457
  return 1;
97021
97458
  }
97022
97459
  }
@@ -97032,18 +97469,18 @@ async function stopHost(root, hostUrl) {
97032
97469
  }
97033
97470
  if (!exited) {
97034
97471
  console.error(
97035
- import_picocolors33.default.red(
97472
+ import_picocolors34.default.red(
97036
97473
  `Host pid ${spawned.pid} did not exit within ${STOP_WAIT_MS / 1e3}s after SIGTERM.`
97037
97474
  )
97038
97475
  );
97039
97476
  return 1;
97040
97477
  }
97041
97478
  console.log(
97042
- `${import_picocolors33.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors33.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
97479
+ `${import_picocolors34.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors34.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
97043
97480
  );
97044
97481
  }
97045
97482
  try {
97046
- await unlinkAsync((0, import_node_path16.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
97483
+ await unlinkAsync((0, import_node_path18.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
97047
97484
  } catch {
97048
97485
  }
97049
97486
  return 0;
@@ -97052,7 +97489,7 @@ async function stopAll() {
97052
97489
  const registry2 = readRegistry();
97053
97490
  const projects2 = Object.entries(registry2.projects);
97054
97491
  if (projects2.length === 0) {
97055
- console.log(import_picocolors33.default.dim("No registered projects."));
97492
+ console.log(import_picocolors34.default.dim("No registered projects."));
97056
97493
  return 0;
97057
97494
  }
97058
97495
  let stopped = 0;
@@ -97062,17 +97499,17 @@ async function stopAll() {
97062
97499
  if (!hostUrl) continue;
97063
97500
  const alive = await isHostHealthy(hostUrl);
97064
97501
  if (!alive) continue;
97065
- console.log(` Stopping ${import_picocolors33.default.bold(name)} ${import_picocolors33.default.dim(`(${hostUrl})`)}`);
97502
+ console.log(` Stopping ${import_picocolors34.default.bold(name)} ${import_picocolors34.default.dim(`(${hostUrl})`)}`);
97066
97503
  const code = await stopHost(entry2.root, hostUrl);
97067
97504
  if (code === 0) stopped++;
97068
97505
  else failed++;
97069
97506
  }
97070
97507
  if (stopped === 0 && failed === 0) {
97071
- console.log(import_picocolors33.default.dim("No running source-intelligence hosts found."));
97508
+ console.log(import_picocolors34.default.dim("No running source-intelligence hosts found."));
97072
97509
  } else {
97073
97510
  console.log(
97074
97511
  `
97075
- Stopped ${stopped} host(s)${failed > 0 ? import_picocolors33.default.red(`, ${failed} failed`) : ""}.`
97512
+ Stopped ${stopped} host(s)${failed > 0 ? import_picocolors34.default.red(`, ${failed} failed`) : ""}.`
97076
97513
  );
97077
97514
  }
97078
97515
  return failed > 0 ? 1 : 0;
@@ -97124,12 +97561,12 @@ function extractPort(hostUrl) {
97124
97561
 
97125
97562
  // ../../packages/cli/src/commands/hosts.ts
97126
97563
  init_cjs_shims();
97127
- var import_picocolors34 = __toESM(require_picocolors(), 1);
97564
+ var import_picocolors35 = __toESM(require_picocolors(), 1);
97128
97565
  async function runHosts() {
97129
97566
  const registry2 = readRegistry();
97130
97567
  const projects2 = Object.entries(registry2.projects);
97131
97568
  if (projects2.length === 0) {
97132
- console.log(import_picocolors34.default.dim("No registered projects. Run `horus index` in a repo first."));
97569
+ console.log(import_picocolors35.default.dim("No registered projects. Run `horus index` in a repo first."));
97133
97570
  return 0;
97134
97571
  }
97135
97572
  const rows = [];
@@ -97146,29 +97583,29 @@ async function runHosts() {
97146
97583
  });
97147
97584
  const anyHost = rows.some((r) => r.hostUrl !== null);
97148
97585
  if (!anyHost) {
97149
- console.log(import_picocolors34.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
97586
+ console.log(import_picocolors35.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
97150
97587
  return 0;
97151
97588
  }
97152
97589
  console.log("");
97153
97590
  for (const row of rows) {
97154
97591
  if (row.hostUrl === null) continue;
97155
- const status = row.healthy ? import_picocolors34.default.green("\u25CF running") : import_picocolors34.default.red("\u25CF stopped");
97592
+ const status = row.healthy ? import_picocolors35.default.green("\u25CF running") : import_picocolors35.default.red("\u25CF stopped");
97156
97593
  const port = extractPort2(row.hostUrl) ?? "?";
97157
97594
  console.log(
97158
- ` ${status} ${import_picocolors34.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors34.default.dim(row.root)}`
97595
+ ` ${status} ${import_picocolors35.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors35.default.dim(row.root)}`
97159
97596
  );
97160
97597
  }
97161
97598
  console.log("");
97162
97599
  const noHost = rows.filter((r) => r.hostUrl === null);
97163
97600
  if (noHost.length > 0) {
97164
97601
  for (const row of noHost) {
97165
- console.log(` ${import_picocolors34.default.dim("\u25CB no host")} ${import_picocolors34.default.dim(row.name)}`);
97602
+ console.log(` ${import_picocolors35.default.dim("\u25CB no host")} ${import_picocolors35.default.dim(row.name)}`);
97166
97603
  }
97167
97604
  console.log("");
97168
97605
  }
97169
97606
  const running = rows.filter((r) => r.healthy).length;
97170
97607
  console.log(
97171
- import_picocolors34.default.dim(
97608
+ import_picocolors35.default.dim(
97172
97609
  `${running} running \xB7 horus stop to reap \xB7 horus stop --all to stop everything`
97173
97610
  )
97174
97611
  );
@@ -97185,12 +97622,12 @@ function extractPort2(hostUrl) {
97185
97622
 
97186
97623
  // ../../packages/cli/src/commands/doctor.ts
97187
97624
  init_cjs_shims();
97188
- var import_picocolors35 = __toESM(require_picocolors(), 1);
97625
+ var import_picocolors36 = __toESM(require_picocolors(), 1);
97189
97626
  var DEFAULT_DB_URL4 = "postgresql://horus:horus@localhost:5433/horus";
97190
97627
  function mark2(status) {
97191
- if (status === "pass") return import_picocolors35.default.green("\u2713");
97192
- if (status === "warn") return import_picocolors35.default.yellow("~");
97193
- return import_picocolors35.default.red("\u2717");
97628
+ if (status === "pass") return import_picocolors36.default.green("\u2713");
97629
+ if (status === "warn") return import_picocolors36.default.yellow("~");
97630
+ return import_picocolors36.default.red("\u2717");
97194
97631
  }
97195
97632
  async function runDoctor(opts) {
97196
97633
  const cwd = opts?.cwd ?? process.cwd();
@@ -97417,11 +97854,11 @@ async function runDoctor(opts) {
97417
97854
  write(JSON.stringify(output, null, 2));
97418
97855
  return hasFailure ? 1 : 0;
97419
97856
  }
97420
- write(import_picocolors35.default.bold("\nHorus readiness check\n"));
97857
+ write(import_picocolors36.default.bold("\nHorus readiness check\n"));
97421
97858
  for (const check2 of checks) {
97422
- write(` ${mark2(check2.status)} ${import_picocolors35.default.bold(check2.label.padEnd(26))} ${import_picocolors35.default.dim(check2.detail)}`);
97859
+ write(` ${mark2(check2.status)} ${import_picocolors36.default.bold(check2.label.padEnd(26))} ${import_picocolors36.default.dim(check2.detail)}`);
97423
97860
  if (check2.next) {
97424
- write(` ${import_picocolors35.default.dim("\u2192 " + check2.next)}`);
97861
+ write(` ${import_picocolors36.default.dim("\u2192 " + check2.next)}`);
97425
97862
  }
97426
97863
  }
97427
97864
  write("");
@@ -97431,16 +97868,16 @@ async function runDoctor(opts) {
97431
97868
  // ../../packages/cli/src/commands/providers-doctor.ts
97432
97869
  init_cjs_shims();
97433
97870
  var import_node_child_process8 = require("child_process");
97434
- var import_picocolors36 = __toESM(require_picocolors(), 1);
97871
+ var import_picocolors37 = __toESM(require_picocolors(), 1);
97435
97872
  function statusMark(status) {
97436
- if (status === "ready") return import_picocolors36.default.green("\u2713");
97437
- if (status === "installed") return import_picocolors36.default.yellow("~");
97438
- return import_picocolors36.default.red("\u2717");
97873
+ if (status === "ready") return import_picocolors37.default.green("\u2713");
97874
+ if (status === "installed") return import_picocolors37.default.yellow("~");
97875
+ return import_picocolors37.default.red("\u2717");
97439
97876
  }
97440
97877
  function statusLabel(status) {
97441
- if (status === "ready") return import_picocolors36.default.green("ready");
97442
- if (status === "installed") return import_picocolors36.default.yellow("installed (not configured)");
97443
- return import_picocolors36.default.dim("not found on PATH");
97878
+ if (status === "ready") return import_picocolors37.default.green("ready");
97879
+ if (status === "installed") return import_picocolors37.default.yellow("installed (not configured)");
97880
+ return import_picocolors37.default.dim("not found on PATH");
97444
97881
  }
97445
97882
  function detectBinary(id) {
97446
97883
  const result = (0, import_node_child_process8.spawnSync)(id, ["--version"], { stdio: "pipe", timeout: 2e3 });
@@ -97457,7 +97894,7 @@ async function runProvidersDoctorCommand(opts) {
97457
97894
  const registry2 = opts?.registry ?? DEFAULT_LOCAL_PROVIDER_REGISTRY;
97458
97895
  const write = opts?.write ?? ((line2) => console.log(line2));
97459
97896
  const results = buildProviderResults(registry2, opts?._detect);
97460
- write(import_picocolors36.default.bold("\nLocal AI providers\n"));
97897
+ write(import_picocolors37.default.bold("\nLocal AI providers\n"));
97461
97898
  for (const result of results) {
97462
97899
  const descriptor = registry2.get(result.id);
97463
97900
  const name = descriptor?.displayName ?? result.id;
@@ -97465,11 +97902,11 @@ async function runProvidersDoctorCommand(opts) {
97465
97902
  ` ${statusMark(result.status)} ${result.id.padEnd(8)} ${name.padEnd(22)} ${statusLabel(result.status)}`
97466
97903
  );
97467
97904
  if (result.status !== "ready" && result.detail) {
97468
- write(` ${import_picocolors36.default.dim("\u2192 " + result.detail)}`);
97905
+ write(` ${import_picocolors37.default.dim("\u2192 " + result.detail)}`);
97469
97906
  }
97470
97907
  }
97471
97908
  write("");
97472
- write(import_picocolors36.default.bold("Cloud AI providers\n"));
97909
+ write(import_picocolors37.default.bold("Cloud AI providers\n"));
97473
97910
  let source = null;
97474
97911
  if (opts?._anthropicKey !== void 0) {
97475
97912
  source = opts._anthropicKey ? "env" : null;
@@ -97484,18 +97921,18 @@ async function runProvidersDoctorCommand(opts) {
97484
97921
  }
97485
97922
  if (source === "config") {
97486
97923
  write(
97487
- ` ${import_picocolors36.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors36.default.green("configured (local .horus config)")}`
97924
+ ` ${import_picocolors37.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors37.default.green("configured (local .horus config)")}`
97488
97925
  );
97489
97926
  } else if (source === "env") {
97490
97927
  write(
97491
- ` ${import_picocolors36.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors36.default.green("configured (ANTHROPIC_API_KEY env)")}`
97928
+ ` ${import_picocolors37.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors37.default.green("configured (ANTHROPIC_API_KEY env)")}`
97492
97929
  );
97493
97930
  } else {
97494
97931
  write(
97495
- ` ${import_picocolors36.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors36.default.dim("not configured")}`
97932
+ ` ${import_picocolors37.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors37.default.dim("not configured")}`
97496
97933
  );
97497
97934
  write(
97498
- ` ${import_picocolors36.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
97935
+ ` ${import_picocolors37.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
97499
97936
  );
97500
97937
  }
97501
97938
  write("");
@@ -97504,9 +97941,9 @@ async function runProvidersDoctorCommand(opts) {
97504
97941
 
97505
97942
  // ../../packages/cli/src/commands/generate-config.ts
97506
97943
  init_cjs_shims();
97507
- var import_node_fs15 = require("fs");
97508
- var import_node_path17 = require("path");
97509
- var import_picocolors37 = __toESM(require_picocolors(), 1);
97944
+ var import_node_fs17 = require("fs");
97945
+ var import_node_path19 = require("path");
97946
+ var import_picocolors38 = __toESM(require_picocolors(), 1);
97510
97947
  function configTemplate(name, repoPath) {
97511
97948
  return `export default {
97512
97949
  database: {
@@ -97554,39 +97991,39 @@ async function runGenerateConfig(opts) {
97554
97991
  const defaults = localConfigPath2 != null ? projectDefaults(localConfigPath2) : null;
97555
97992
  const hasLocalConfig = defaults != null;
97556
97993
  const defaultOut = hasLocalConfig ? "horus.config.example.js" : "horus.config.js";
97557
- const outPath = (0, import_node_path17.resolve)(cwd, opts.out ?? defaultOut);
97994
+ const outPath = (0, import_node_path19.resolve)(cwd, opts.out ?? defaultOut);
97558
97995
  const name = opts.name ?? defaults?.name ?? "my-project";
97559
97996
  const repoPath = opts.repo ?? defaults?.repoPath ?? `/path/to/${name}`;
97560
- if ((0, import_node_fs15.existsSync)(outPath) && !opts.force) {
97561
- log(`${import_picocolors37.default.red("\u2717")} ${outPath} already exists`);
97562
- log(import_picocolors37.default.dim(" pass --force to overwrite"));
97997
+ if ((0, import_node_fs17.existsSync)(outPath) && !opts.force) {
97998
+ log(`${import_picocolors38.default.red("\u2717")} ${outPath} already exists`);
97999
+ log(import_picocolors38.default.dim(" pass --force to overwrite"));
97563
98000
  return 1;
97564
98001
  }
97565
98002
  try {
97566
- (0, import_node_fs15.mkdirSync)((0, import_node_path17.dirname)(outPath), { recursive: true });
97567
- (0, import_node_fs15.writeFileSync)(outPath, configTemplate(name, repoPath), "utf8");
98003
+ (0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(outPath), { recursive: true });
98004
+ (0, import_node_fs17.writeFileSync)(outPath, configTemplate(name, repoPath), "utf8");
97568
98005
  } catch (err) {
97569
- log(`${import_picocolors37.default.red("\u2717")} Could not write ${outPath}: ${err.message}`);
98006
+ log(`${import_picocolors38.default.red("\u2717")} Could not write ${outPath}: ${err.message}`);
97570
98007
  return 1;
97571
98008
  }
97572
- log(`${import_picocolors37.default.green("\u2713")} Created ${outPath}`);
97573
- log(import_picocolors37.default.dim(` project: ${name}`));
97574
- log(import_picocolors37.default.dim(` repo: ${repoPath}`));
98009
+ log(`${import_picocolors38.default.green("\u2713")} Created ${outPath}`);
98010
+ log(import_picocolors38.default.dim(` project: ${name}`));
98011
+ log(import_picocolors38.default.dim(` repo: ${repoPath}`));
97575
98012
  if (hasLocalConfig && localConfigPath2 != null) {
97576
98013
  log("");
97577
- log(import_picocolors37.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
98014
+ log(import_picocolors38.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
97578
98015
  log(" \u2022 .horus/config.json \u2014 project config used by `horus investigate` from this repo");
97579
98016
  log(" \u2022 horus.config.js \u2014 standalone/global config used with `horus doctor --config <path>`");
97580
- log(import_picocolors37.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
98017
+ log(import_picocolors38.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
97581
98018
  } else {
97582
- log(import_picocolors37.default.dim(` next: horus doctor --config ${outPath}`));
98019
+ log(import_picocolors38.default.dim(` next: horus doctor --config ${outPath}`));
97583
98020
  }
97584
98021
  return 0;
97585
98022
  }
97586
98023
 
97587
98024
  // ../../packages/cli/src/commands/readiness.ts
97588
98025
  init_cjs_shims();
97589
- var import_picocolors38 = __toESM(require_picocolors(), 1);
98026
+ var import_picocolors39 = __toESM(require_picocolors(), 1);
97590
98027
  var READINESS_AI_CONTRACT = `Provide a clearly separated AI readiness summary with:
97591
98028
 
97592
98029
  Overall assessment
@@ -97609,9 +98046,9 @@ Confidence / gaps
97609
98046
  - Which checks Horus could verify vs. which require manual confirmation`;
97610
98047
  var DEFAULT_DB_URL5 = "postgresql://horus:horus@localhost:5433/horus";
97611
98048
  function mark3(status) {
97612
- if (status === "pass") return import_picocolors38.default.green("\u2713");
97613
- if (status === "warn") return import_picocolors38.default.yellow("~");
97614
- return import_picocolors38.default.red("\u2717");
98049
+ if (status === "pass") return import_picocolors39.default.green("\u2713");
98050
+ if (status === "warn") return import_picocolors39.default.yellow("~");
98051
+ return import_picocolors39.default.red("\u2717");
97615
98052
  }
97616
98053
  async function runReadiness(opts) {
97617
98054
  const cwd = opts?.cwd ?? process.cwd();
@@ -97766,20 +98203,20 @@ async function runReadiness(opts) {
97766
98203
  }
97767
98204
  const blockingChecks = checks.filter((c) => c.blocking);
97768
98205
  const optionalChecks = checks.filter((c) => !c.blocking);
97769
- write(import_picocolors38.default.bold("\nHorus release readiness\n"));
97770
- write(import_picocolors38.default.bold(" Blocking"));
98206
+ write(import_picocolors39.default.bold("\nHorus release readiness\n"));
98207
+ write(import_picocolors39.default.bold(" Blocking"));
97771
98208
  for (const check2 of blockingChecks) {
97772
- write(` ${mark3(check2.status)} ${import_picocolors38.default.bold(check2.label.padEnd(22))} ${import_picocolors38.default.dim(check2.detail)}`);
98209
+ write(` ${mark3(check2.status)} ${import_picocolors39.default.bold(check2.label.padEnd(22))} ${import_picocolors39.default.dim(check2.detail)}`);
97773
98210
  if (check2.next) {
97774
- write(` ${import_picocolors38.default.dim("\u2192 " + check2.next)}`);
98211
+ write(` ${import_picocolors39.default.dim("\u2192 " + check2.next)}`);
97775
98212
  }
97776
98213
  }
97777
98214
  write("");
97778
- write(import_picocolors38.default.bold(" Optional"));
98215
+ write(import_picocolors39.default.bold(" Optional"));
97779
98216
  for (const check2 of optionalChecks) {
97780
- write(` ${mark3(check2.status)} ${import_picocolors38.default.bold(check2.label.padEnd(22))} ${import_picocolors38.default.dim(check2.detail)}`);
98217
+ write(` ${mark3(check2.status)} ${import_picocolors39.default.bold(check2.label.padEnd(22))} ${import_picocolors39.default.dim(check2.detail)}`);
97781
98218
  if (check2.next) {
97782
- write(` ${import_picocolors38.default.dim("\u2192 " + check2.next)}`);
98219
+ write(` ${import_picocolors39.default.dim("\u2192 " + check2.next)}`);
97783
98220
  }
97784
98221
  }
97785
98222
  write("");
@@ -97787,21 +98224,21 @@ async function runReadiness(opts) {
97787
98224
  const optionalWarns = optionalChecks.filter((c) => c.status === "warn").length;
97788
98225
  if (blockingFails.length === 0) {
97789
98226
  if (optionalWarns === 0) {
97790
- write(import_picocolors38.default.green(" Ready for demo/release."));
98227
+ write(import_picocolors39.default.green(" Ready for demo/release."));
97791
98228
  } else {
97792
98229
  write(
97793
- import_picocolors38.default.yellow(
98230
+ import_picocolors39.default.yellow(
97794
98231
  ` Ready for a basic demo. ${optionalWarns} optional item(s) not configured \u2014 investigation evidence will be limited.`
97795
98232
  )
97796
98233
  );
97797
98234
  }
97798
98235
  } else {
97799
98236
  write(
97800
- import_picocolors38.default.red(
98237
+ import_picocolors39.default.red(
97801
98238
  ` Not ready. ${blockingFails.length} blocking item(s) must be resolved before demo/release.`
97802
98239
  )
97803
98240
  );
97804
- write(import_picocolors38.default.dim(" Re-run `horus readiness` after resolving the items above."));
98241
+ write(import_picocolors39.default.dim(" Re-run `horus readiness` after resolving the items above."));
97805
98242
  }
97806
98243
  write("");
97807
98244
  if (opts?.ai) {
@@ -97816,7 +98253,7 @@ async function runReadiness(opts) {
97816
98253
  });
97817
98254
  console.log("\n" + renderInterpretation(result));
97818
98255
  if (!result.ok) {
97819
- console.error(import_picocolors38.default.yellow(`[ai] ${result.warning}`));
98256
+ console.error(import_picocolors39.default.yellow(`[ai] ${result.warning}`));
97820
98257
  }
97821
98258
  }
97822
98259
  return blockingFails.length > 0 ? 1 : 0;
@@ -97824,33 +98261,33 @@ async function runReadiness(opts) {
97824
98261
 
97825
98262
  // ../../packages/cli/src/commands/skill.ts
97826
98263
  init_cjs_shims();
97827
- var import_node_fs16 = require("fs");
97828
- var import_node_path18 = require("path");
97829
- var import_node_os3 = require("os");
97830
- var import_promises = require("readline/promises");
97831
- var import_picocolors39 = __toESM(require_picocolors(), 1);
98264
+ var import_node_fs18 = require("fs");
98265
+ var import_node_path20 = require("path");
98266
+ var import_node_os4 = require("os");
98267
+ var import_promises2 = require("readline/promises");
98268
+ var import_picocolors40 = __toESM(require_picocolors(), 1);
97832
98269
  var SUPPORTED_TARGETS = ["claude", "codex", "gemini", "cursor", "generic"];
97833
98270
  function isValidTarget(target) {
97834
98271
  return SUPPORTED_TARGETS.includes(target);
97835
98272
  }
97836
98273
  function getLegacyClaudeSkillPath(opts) {
97837
- const base2 = opts.global ? (0, import_node_os3.homedir)() : opts.cwd ?? process.cwd();
97838
- return (0, import_node_path18.join)(base2, ".claude", "skills", "horus.md");
98274
+ const base2 = opts.global ? (0, import_node_os4.homedir)() : opts.cwd ?? process.cwd();
98275
+ return (0, import_node_path20.join)(base2, ".claude", "skills", "horus.md");
97839
98276
  }
97840
98277
  function getSkillInstallPath(target, opts) {
97841
- const base2 = opts.global ? (0, import_node_os3.homedir)() : opts.cwd ?? process.cwd();
98278
+ const base2 = opts.global ? (0, import_node_os4.homedir)() : opts.cwd ?? process.cwd();
97842
98279
  switch (target) {
97843
98280
  case "claude":
97844
- return (0, import_node_path18.join)(base2, ".claude", "skills", "horus", "SKILL.md");
98281
+ return (0, import_node_path20.join)(base2, ".claude", "skills", "horus", "SKILL.md");
97845
98282
  case "gemini":
97846
- return opts.global ? (0, import_node_path18.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path18.join)(base2, "GEMINI.md");
98283
+ return opts.global ? (0, import_node_path20.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path20.join)(base2, "GEMINI.md");
97847
98284
  case "cursor":
97848
- return opts.global ? (0, import_node_path18.join)(base2, ".cursorrules") : (0, import_node_path18.join)(base2, ".cursor", "rules", "horus.mdc");
98285
+ return opts.global ? (0, import_node_path20.join)(base2, ".cursorrules") : (0, import_node_path20.join)(base2, ".cursor", "rules", "horus.mdc");
97849
98286
  case "codex":
97850
- return opts.global ? (0, import_node_path18.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path18.join)(base2, "AGENTS.md");
98287
+ return opts.global ? (0, import_node_path20.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path20.join)(base2, "AGENTS.md");
97851
98288
  case "generic":
97852
98289
  default:
97853
- return (0, import_node_path18.join)(base2, ".horus", "skills", `horus-${target}.md`);
98290
+ return (0, import_node_path20.join)(base2, ".horus", "skills", `horus-${target}.md`);
97854
98291
  }
97855
98292
  }
97856
98293
  var BASE_SKILL = `# Horus Grounded Investigation Skill
@@ -98135,7 +98572,7 @@ async function confirm(message) {
98135
98572
  if (!process.stdin.isTTY) {
98136
98573
  return false;
98137
98574
  }
98138
- const rl = (0, import_promises.createInterface)({ input: process.stdin, output: process.stdout });
98575
+ const rl = (0, import_promises2.createInterface)({ input: process.stdin, output: process.stdout });
98139
98576
  try {
98140
98577
  const answer = await rl.question(`${message} [y/N] `);
98141
98578
  return /^y(es)?$/i.test(answer.trim());
@@ -98146,66 +98583,66 @@ async function confirm(message) {
98146
98583
  async function runSkillInstall(target, opts) {
98147
98584
  const log = opts.write ?? ((line2) => console.log(line2));
98148
98585
  if (!isValidTarget(target)) {
98149
- log(`${import_picocolors39.default.red("\u2717")} Unknown target: ${import_picocolors39.default.bold(target)}`);
98150
- log(import_picocolors39.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
98586
+ log(`${import_picocolors40.default.red("\u2717")} Unknown target: ${import_picocolors40.default.bold(target)}`);
98587
+ log(import_picocolors40.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
98151
98588
  return 1;
98152
98589
  }
98153
98590
  const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
98154
98591
  const content = generateSkillContent(target);
98155
98592
  if (target === "claude") {
98156
98593
  const legacyPath = getLegacyClaudeSkillPath({ global: opts.global, cwd: opts.cwd });
98157
- if ((0, import_node_fs16.existsSync)(legacyPath)) {
98594
+ if ((0, import_node_fs18.existsSync)(legacyPath)) {
98158
98595
  if (!opts.force) {
98159
98596
  const confirmed = await (opts.confirm ?? confirm)(
98160
98597
  `Found old flat skill file at ${legacyPath}. Replace it with the new directory layout?`
98161
98598
  );
98162
98599
  if (!confirmed) {
98163
- log(`${import_picocolors39.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
98164
- log(import_picocolors39.default.dim(" Pass --force to replace without prompting."));
98600
+ log(`${import_picocolors40.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
98601
+ log(import_picocolors40.default.dim(" Pass --force to replace without prompting."));
98165
98602
  return 1;
98166
98603
  }
98167
98604
  }
98168
98605
  try {
98169
- (0, import_node_fs16.rmSync)(legacyPath);
98170
- log(`${import_picocolors39.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
98606
+ (0, import_node_fs18.rmSync)(legacyPath);
98607
+ log(`${import_picocolors40.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
98171
98608
  } catch (err) {
98172
- log(`${import_picocolors39.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err.message}`);
98609
+ log(`${import_picocolors40.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err.message}`);
98173
98610
  return 1;
98174
98611
  }
98175
98612
  }
98176
98613
  }
98177
- if ((0, import_node_fs16.existsSync)(outPath) && !opts.force) {
98178
- log(`${import_picocolors39.default.red("\u2717")} ${outPath} already exists`);
98179
- log(import_picocolors39.default.dim(" pass --force to overwrite"));
98614
+ if ((0, import_node_fs18.existsSync)(outPath) && !opts.force) {
98615
+ log(`${import_picocolors40.default.red("\u2717")} ${outPath} already exists`);
98616
+ log(import_picocolors40.default.dim(" pass --force to overwrite"));
98180
98617
  return 1;
98181
98618
  }
98182
98619
  try {
98183
- (0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(outPath), { recursive: true });
98184
- (0, import_node_fs16.writeFileSync)(outPath, content, "utf8");
98620
+ (0, import_node_fs18.mkdirSync)((0, import_node_path20.dirname)(outPath), { recursive: true });
98621
+ (0, import_node_fs18.writeFileSync)(outPath, content, "utf8");
98185
98622
  } catch (err) {
98186
- log(`${import_picocolors39.default.red("\u2717")} Could not write ${outPath}: ${err.message}`);
98623
+ log(`${import_picocolors40.default.red("\u2717")} Could not write ${outPath}: ${err.message}`);
98187
98624
  return 1;
98188
98625
  }
98189
- log(`${import_picocolors39.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
98626
+ log(`${import_picocolors40.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
98190
98627
  if (target === "claude") {
98191
- log(import_picocolors39.default.dim(" Claude Code will load this skill automatically."));
98192
- log(import_picocolors39.default.dim(" Invoke it with: /horus"));
98628
+ log(import_picocolors40.default.dim(" Claude Code will load this skill automatically."));
98629
+ log(import_picocolors40.default.dim(" Invoke it with: /horus"));
98193
98630
  } else if (target === "gemini") {
98194
- log(import_picocolors39.default.dim(" Gemini CLI will load this context file automatically."));
98631
+ log(import_picocolors40.default.dim(" Gemini CLI will load this context file automatically."));
98195
98632
  } else if (target === "cursor") {
98196
- log(import_picocolors39.default.dim(" Cursor will load this rule automatically."));
98633
+ log(import_picocolors40.default.dim(" Cursor will load this rule automatically."));
98197
98634
  } else if (target === "codex") {
98198
- log(import_picocolors39.default.dim(" Codex CLI will load this file automatically."));
98635
+ log(import_picocolors40.default.dim(" Codex CLI will load this file automatically."));
98199
98636
  } else {
98200
- log(import_picocolors39.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
98637
+ log(import_picocolors40.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
98201
98638
  }
98202
98639
  return 0;
98203
98640
  }
98204
98641
  async function runSkillPrint(target, opts) {
98205
98642
  const log = opts.write ?? ((line2) => console.log(line2));
98206
98643
  if (!isValidTarget(target)) {
98207
- log(`${import_picocolors39.default.red("\u2717")} Unknown target: ${import_picocolors39.default.bold(target)}`);
98208
- log(import_picocolors39.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
98644
+ log(`${import_picocolors40.default.red("\u2717")} Unknown target: ${import_picocolors40.default.bold(target)}`);
98645
+ log(import_picocolors40.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
98209
98646
  return 1;
98210
98647
  }
98211
98648
  process.stdout.write(generateSkillContent(target));
@@ -98214,8 +98651,8 @@ async function runSkillPrint(target, opts) {
98214
98651
  async function runSkillPath(target, opts) {
98215
98652
  const log = opts.write ?? ((line2) => console.log(line2));
98216
98653
  if (!isValidTarget(target)) {
98217
- log(`${import_picocolors39.default.red("\u2717")} Unknown target: ${import_picocolors39.default.bold(target)}`);
98218
- log(import_picocolors39.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
98654
+ log(`${import_picocolors40.default.red("\u2717")} Unknown target: ${import_picocolors40.default.bold(target)}`);
98655
+ log(import_picocolors40.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
98219
98656
  return 1;
98220
98657
  }
98221
98658
  const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
@@ -98225,11 +98662,11 @@ async function runSkillPath(target, opts) {
98225
98662
 
98226
98663
  // ../../packages/cli/src/commands/update.ts
98227
98664
  init_cjs_shims();
98228
- var import_node_fs17 = require("fs");
98229
- var import_node_path19 = require("path");
98230
- var import_node_os4 = require("os");
98231
- var import_node_crypto5 = require("crypto");
98232
- var import_picocolors40 = __toESM(require_picocolors(), 1);
98665
+ var import_node_fs19 = require("fs");
98666
+ var import_node_path21 = require("path");
98667
+ var import_node_os5 = require("os");
98668
+ var import_node_crypto7 = require("crypto");
98669
+ var import_picocolors41 = __toESM(require_picocolors(), 1);
98233
98670
  var RELEASES_API = "https://api.github.com/repos/meritt-dev/horus/releases/latest";
98234
98671
  function parseVersion(v) {
98235
98672
  const m = v.replace(/^v/, "").match(/^(\d+)\.(\d+)\.(\d+)/);
@@ -98254,13 +98691,13 @@ async function fetchLatestRelease(_fetch = fetch) {
98254
98691
  return res.json();
98255
98692
  }
98256
98693
  function sha256hex(buf) {
98257
- return (0, import_node_crypto5.createHash)("sha256").update(buf).digest("hex");
98694
+ return (0, import_node_crypto7.createHash)("sha256").update(buf).digest("hex");
98258
98695
  }
98259
98696
  function resolveBinaryPath() {
98260
98697
  const raw = process.argv[1];
98261
98698
  if (!raw) throw new Error("Cannot determine binary path from process.argv[1]");
98262
98699
  try {
98263
- return (0, import_node_fs17.realpathSync)(raw);
98700
+ return (0, import_node_fs19.realpathSync)(raw);
98264
98701
  } catch {
98265
98702
  return raw;
98266
98703
  }
@@ -98270,33 +98707,33 @@ async function runUpdate(opts) {
98270
98707
  const _fetch = opts._fetch ?? fetch;
98271
98708
  const currentVersion = opts._currentVersion ?? HORUS_VERSION;
98272
98709
  write(`
98273
- ${import_picocolors40.default.bold("Horus update")}
98710
+ ${import_picocolors41.default.bold("Horus update")}
98274
98711
  `);
98275
- write(` Current version: ${import_picocolors40.default.cyan(currentVersion)}`);
98712
+ write(` Current version: ${import_picocolors41.default.cyan(currentVersion)}`);
98276
98713
  let release;
98277
98714
  try {
98278
98715
  release = await fetchLatestRelease(_fetch);
98279
98716
  } catch (e) {
98280
- write(` ${import_picocolors40.default.red("\u2717")} Could not reach GitHub: ${e.message}`);
98717
+ write(` ${import_picocolors41.default.red("\u2717")} Could not reach GitHub: ${e.message}`);
98281
98718
  return 1;
98282
98719
  }
98283
98720
  const latest = release.tag_name.replace(/^v/, "");
98284
- write(` Latest version: ${import_picocolors40.default.cyan(latest)}`);
98721
+ write(` Latest version: ${import_picocolors41.default.cyan(latest)}`);
98285
98722
  const newer = isNewer(latest, currentVersion);
98286
98723
  if (opts.check) {
98287
98724
  if (newer) {
98288
98725
  write(`
98289
- ${import_picocolors40.default.yellow("\u2192")} ${import_picocolors40.default.bold(latest)} is available.`);
98290
- write(` Run ${import_picocolors40.default.bold("horus update")} to upgrade.`);
98726
+ ${import_picocolors41.default.yellow("\u2192")} ${import_picocolors41.default.bold(latest)} is available.`);
98727
+ write(` Run ${import_picocolors41.default.bold("horus update")} to upgrade.`);
98291
98728
  } else {
98292
98729
  write(`
98293
- ${import_picocolors40.default.green("\u2713")} Already on the latest version.`);
98730
+ ${import_picocolors41.default.green("\u2713")} Already on the latest version.`);
98294
98731
  }
98295
98732
  return 0;
98296
98733
  }
98297
98734
  if (!newer && !opts.force) {
98298
98735
  write(`
98299
- ${import_picocolors40.default.green("\u2713")} Already on the latest version.`);
98736
+ ${import_picocolors41.default.green("\u2713")} Already on the latest version.`);
98300
98737
  return 0;
98301
98738
  }
98302
98739
  const tag = release.tag_name;
@@ -98305,8 +98742,8 @@ ${import_picocolors40.default.bold("Horus update")}
98305
98742
  const binaryAsset = release.assets.find((a) => a.name === assetName);
98306
98743
  const checksumAsset = release.assets.find((a) => a.name === checksumName);
98307
98744
  if (!binaryAsset) {
98308
- write(` ${import_picocolors40.default.red("\u2717")} Release ${tag} has no binary asset named '${assetName}'.`);
98309
- write(` Fallback: ${import_picocolors40.default.dim("curl -fsSL https://horus.sh/install.sh | bash")}`);
98745
+ write(` ${import_picocolors41.default.red("\u2717")} Release ${tag} has no binary asset named '${assetName}'.`);
98746
+ write(` Fallback: ${import_picocolors41.default.dim("curl -fsSL https://horus.sh/install.sh | bash")}`);
98310
98747
  return 1;
98311
98748
  }
98312
98749
  write(`
@@ -98316,7 +98753,7 @@ ${import_picocolors40.default.bold("Horus update")}
98316
98753
  redirect: "follow"
98317
98754
  });
98318
98755
  if (!binRes.ok || !binRes.body) {
98319
- write(` ${import_picocolors40.default.red("\u2717")} Download failed: ${binRes.status}`);
98756
+ write(` ${import_picocolors41.default.red("\u2717")} Download failed: ${binRes.status}`);
98320
98757
  return 1;
98321
98758
  }
98322
98759
  const binBuf = Buffer.from(await binRes.arrayBuffer());
@@ -98330,75 +98767,75 @@ ${import_picocolors40.default.bold("Horus update")}
98330
98767
  const expectedHash = csText.trim().split(/\s+/)[0];
98331
98768
  const actualHash = sha256hex(binBuf);
98332
98769
  if (expectedHash !== actualHash) {
98333
- write(` ${import_picocolors40.default.red("\u2717")} Checksum mismatch \u2014 download may be corrupt.`);
98770
+ write(` ${import_picocolors41.default.red("\u2717")} Checksum mismatch \u2014 download may be corrupt.`);
98334
98771
  write(` Expected: ${expectedHash}`);
98335
98772
  write(` Got: ${actualHash}`);
98336
98773
  return 1;
98337
98774
  }
98338
- write(` ${import_picocolors40.default.green("\u2713")} Checksum verified.`);
98775
+ write(` ${import_picocolors41.default.green("\u2713")} Checksum verified.`);
98339
98776
  }
98340
98777
  }
98341
98778
  let binaryPath;
98342
98779
  try {
98343
98780
  binaryPath = resolveBinaryPath();
98344
98781
  } catch (e) {
98345
- write(` ${import_picocolors40.default.red("\u2717")} ${e.message}`);
98782
+ write(` ${import_picocolors41.default.red("\u2717")} ${e.message}`);
98346
98783
  return 1;
98347
98784
  }
98348
- if (!(0, import_node_fs17.existsSync)(binaryPath)) {
98349
- write(` ${import_picocolors40.default.red("\u2717")} Binary not found at ${binaryPath}`);
98785
+ if (!(0, import_node_fs19.existsSync)(binaryPath)) {
98786
+ write(` ${import_picocolors41.default.red("\u2717")} Binary not found at ${binaryPath}`);
98350
98787
  return 1;
98351
98788
  }
98352
- const tmpPath = (0, import_node_path19.join)((0, import_node_os4.tmpdir)(), `horus-update-${tag}-${process.pid}`);
98789
+ const tmpPath = (0, import_node_path21.join)((0, import_node_os5.tmpdir)(), `horus-update-${tag}-${process.pid}`);
98353
98790
  const backupPath = `${binaryPath}.bak`;
98354
98791
  try {
98355
- (0, import_node_fs17.writeFileSync)(tmpPath, binBuf, { mode: 493 });
98792
+ (0, import_node_fs19.writeFileSync)(tmpPath, binBuf, { mode: 493 });
98356
98793
  } catch (e) {
98357
- write(` ${import_picocolors40.default.red("\u2717")} Could not write to temp dir: ${e.message}`);
98794
+ write(` ${import_picocolors41.default.red("\u2717")} Could not write to temp dir: ${e.message}`);
98358
98795
  return 1;
98359
98796
  }
98360
98797
  try {
98361
- (0, import_node_fs17.renameSync)(binaryPath, backupPath);
98798
+ (0, import_node_fs19.renameSync)(binaryPath, backupPath);
98362
98799
  try {
98363
- (0, import_node_fs17.renameSync)(tmpPath, binaryPath);
98364
- (0, import_node_fs17.chmodSync)(binaryPath, 493);
98800
+ (0, import_node_fs19.renameSync)(tmpPath, binaryPath);
98801
+ (0, import_node_fs19.chmodSync)(binaryPath, 493);
98365
98802
  } catch (e) {
98366
98803
  try {
98367
- (0, import_node_fs17.renameSync)(backupPath, binaryPath);
98804
+ (0, import_node_fs19.renameSync)(backupPath, binaryPath);
98368
98805
  } catch {
98369
98806
  }
98370
98807
  throw e;
98371
98808
  }
98372
98809
  try {
98373
- (0, import_node_fs17.unlinkSync)(backupPath);
98810
+ (0, import_node_fs19.unlinkSync)(backupPath);
98374
98811
  } catch {
98375
98812
  }
98376
98813
  } catch (e) {
98377
98814
  try {
98378
- (0, import_node_fs17.unlinkSync)(tmpPath);
98815
+ (0, import_node_fs19.unlinkSync)(tmpPath);
98379
98816
  } catch {
98380
98817
  }
98381
98818
  const msg = e.message ?? String(e);
98382
98819
  const needsSudo = e.code === "EACCES" || e.code === "EPERM";
98383
- write(` ${import_picocolors40.default.red("\u2717")} Could not replace binary at ${binaryPath}: ${msg}`);
98820
+ write(` ${import_picocolors41.default.red("\u2717")} Could not replace binary at ${binaryPath}: ${msg}`);
98384
98821
  if (needsSudo) {
98385
98822
  write(`
98386
98823
  Try with sudo:`);
98387
98824
  write(
98388
- ` ${import_picocolors40.default.dim(`sudo curl -fsSL https://github.com/meritt-dev/horus/releases/download/${tag}/${assetName} -o ${binaryPath} && sudo chmod +x ${binaryPath}`)}`
98825
+ ` ${import_picocolors41.default.dim(`sudo curl -fsSL https://github.com/meritt-dev/horus/releases/download/${tag}/${assetName} -o ${binaryPath} && sudo chmod +x ${binaryPath}`)}`
98389
98826
  );
98390
98827
  }
98391
98828
  return 1;
98392
98829
  }
98393
- write(` ${import_picocolors40.default.green("\u2713")} Updated: ${import_picocolors40.default.bold(currentVersion)} \u2192 ${import_picocolors40.default.bold(latest)}`);
98394
- write(` ${import_picocolors40.default.dim(binaryPath)}`);
98830
+ write(` ${import_picocolors41.default.green("\u2713")} Updated: ${import_picocolors41.default.bold(currentVersion)} \u2192 ${import_picocolors41.default.bold(latest)}`);
98831
+ write(` ${import_picocolors41.default.dim(binaryPath)}`);
98395
98832
  return 0;
98396
98833
  }
98397
98834
 
98398
98835
  // ../../packages/cli/src/commands/login.ts
98399
98836
  init_cjs_shims();
98400
98837
  var import_node_child_process9 = require("child_process");
98401
- var import_picocolors41 = __toESM(require_picocolors(), 1);
98838
+ var import_picocolors42 = __toESM(require_picocolors(), 1);
98402
98839
  var sleep2 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
98403
98840
  function openBrowser(url) {
98404
98841
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
@@ -98423,19 +98860,19 @@ async function loginWithToken(apiBaseUrl, token) {
98423
98860
  }
98424
98861
  });
98425
98862
  console.log(
98426
- `${import_picocolors41.default.green("\u2713")} Logged in as ${import_picocolors41.default.bold(me.user.primaryEmail)}. Run ${import_picocolors41.default.bold("horus cloud link")} to connect this repo.`
98863
+ `${import_picocolors42.default.green("\u2713")} Logged in as ${import_picocolors42.default.bold(me.user.primaryEmail)}. Run ${import_picocolors42.default.bold("horus cloud link")} to connect this repo.`
98427
98864
  );
98428
98865
  return 0;
98429
98866
  } catch (err) {
98430
98867
  if (err instanceof CloudOfflineError) {
98431
- console.error(import_picocolors41.default.red(err.message));
98868
+ console.error(import_picocolors42.default.red(err.message));
98432
98869
  return 1;
98433
98870
  }
98434
98871
  if (err instanceof CloudError && err.status === 401) {
98435
- console.error(import_picocolors41.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
98872
+ console.error(import_picocolors42.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
98436
98873
  return 1;
98437
98874
  }
98438
- console.error(import_picocolors41.default.red(`Login failed: ${err.message}`));
98875
+ console.error(import_picocolors42.default.red(`Login failed: ${err.message}`));
98439
98876
  return 1;
98440
98877
  }
98441
98878
  }
@@ -98446,19 +98883,19 @@ async function loginWithBrowser(apiBaseUrl) {
98446
98883
  session = await client.startCliSession();
98447
98884
  } catch (err) {
98448
98885
  if (err instanceof CloudOfflineError) {
98449
- console.error(import_picocolors41.default.red(err.message));
98886
+ console.error(import_picocolors42.default.red(err.message));
98450
98887
  return 1;
98451
98888
  }
98452
- console.error(import_picocolors41.default.red(`Could not start login: ${err.message}`));
98889
+ console.error(import_picocolors42.default.red(`Could not start login: ${err.message}`));
98453
98890
  return 1;
98454
98891
  }
98455
98892
  console.log("");
98456
98893
  console.log(` To sign in, open this URL in your browser:`);
98457
- console.log(` ${import_picocolors41.default.cyan(import_picocolors41.default.bold(session.verificationUri))}`);
98894
+ console.log(` ${import_picocolors42.default.cyan(import_picocolors42.default.bold(session.verificationUri))}`);
98458
98895
  console.log("");
98459
- console.log(` and enter the code: ${import_picocolors41.default.bold(session.userCode)}`);
98896
+ console.log(` and enter the code: ${import_picocolors42.default.bold(session.userCode)}`);
98460
98897
  console.log("");
98461
- console.log(import_picocolors41.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
98898
+ console.log(import_picocolors42.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
98462
98899
  openBrowser(session.verificationUriComplete);
98463
98900
  const deadline = Date.now() + session.expiresIn * 1e3;
98464
98901
  let intervalMs = Math.max(session.interval, 1) * 1e3;
@@ -98469,7 +98906,7 @@ async function loginWithBrowser(apiBaseUrl) {
98469
98906
  poll = await client.pollCliSession(session.deviceCode);
98470
98907
  } catch (err) {
98471
98908
  if (err instanceof CloudOfflineError) {
98472
- console.error(import_picocolors41.default.red(`
98909
+ console.error(import_picocolors42.default.red(`
98473
98910
  ${err.message}`));
98474
98911
  return 1;
98475
98912
  }
@@ -98482,14 +98919,14 @@ ${err.message}`));
98482
98919
  intervalMs += 2e3;
98483
98920
  break;
98484
98921
  case "denied":
98485
- console.error(import_picocolors41.default.red("\nLogin was denied in the browser."));
98922
+ console.error(import_picocolors42.default.red("\nLogin was denied in the browser."));
98486
98923
  return 1;
98487
98924
  case "expired":
98488
- console.error(import_picocolors41.default.red("\nThis login request expired. Run `horus login` again."));
98925
+ console.error(import_picocolors42.default.red("\nThis login request expired. Run `horus login` again."));
98489
98926
  return 1;
98490
98927
  case "approved":
98491
98928
  if (!poll.token || !poll.account) {
98492
- console.error(import_picocolors41.default.red("\nLogin approved but no token was returned. Try again."));
98929
+ console.error(import_picocolors42.default.red("\nLogin approved but no token was returned. Try again."));
98493
98930
  return 1;
98494
98931
  }
98495
98932
  writeAuth({
@@ -98499,12 +98936,12 @@ ${err.message}`));
98499
98936
  });
98500
98937
  console.log(
98501
98938
  `
98502
- ${import_picocolors41.default.green("\u2713")} Logged in as ${import_picocolors41.default.bold(poll.account.email)}. Run ${import_picocolors41.default.bold("horus cloud link")} to connect this repo.`
98939
+ ${import_picocolors42.default.green("\u2713")} Logged in as ${import_picocolors42.default.bold(poll.account.email)}. Run ${import_picocolors42.default.bold("horus cloud link")} to connect this repo.`
98503
98940
  );
98504
98941
  return 0;
98505
98942
  }
98506
98943
  }
98507
- console.error(import_picocolors41.default.red("\nTimed out waiting for approval. Run `horus login` again."));
98944
+ console.error(import_picocolors42.default.red("\nTimed out waiting for approval. Run `horus login` again."));
98508
98945
  return 1;
98509
98946
  }
98510
98947
  async function runLogin(opts = {}) {
@@ -98518,7 +98955,7 @@ async function runLogin(opts = {}) {
98518
98955
  async function runLogout() {
98519
98956
  const auth = readAuth();
98520
98957
  if (!auth) {
98521
- console.log(import_picocolors41.default.dim("Not logged in."));
98958
+ console.log(import_picocolors42.default.dim("Not logged in."));
98522
98959
  return 0;
98523
98960
  }
98524
98961
  const session = authedClient();
@@ -98532,14 +98969,14 @@ async function runLogout() {
98532
98969
  }
98533
98970
  }
98534
98971
  clearAuth();
98535
- console.log(`${import_picocolors41.default.green("\u2713")} Logged out. Local mode still works.`);
98972
+ console.log(`${import_picocolors42.default.green("\u2713")} Logged out. Local mode still works.`);
98536
98973
  return 0;
98537
98974
  }
98538
98975
 
98539
98976
  // ../../packages/cli/src/commands/cloud.ts
98540
98977
  init_cjs_shims();
98541
- var import_picocolors42 = __toESM(require_picocolors(), 1);
98542
- var import_promises2 = require("readline/promises");
98978
+ var import_picocolors43 = __toESM(require_picocolors(), 1);
98979
+ var import_promises3 = require("readline/promises");
98543
98980
 
98544
98981
  // ../../packages/cli/src/lib/cloud/git.ts
98545
98982
  init_cjs_shims();
@@ -98583,7 +99020,7 @@ async function runCloudLink(opts = {}) {
98583
99020
  const root = repoRootOrCwd(opts.cwd);
98584
99021
  const session = authedClient();
98585
99022
  if (!session) {
98586
- console.error(import_picocolors42.default.red(`Not logged in. Run ${import_picocolors42.default.bold("horus login")} first.`));
99023
+ console.error(import_picocolors43.default.red(`Not logged in. Run ${import_picocolors43.default.bold("horus login")} first.`));
98587
99024
  return 1;
98588
99025
  }
98589
99026
  let ctx;
@@ -98593,7 +99030,7 @@ async function runCloudLink(opts = {}) {
98593
99030
  return reportCloudError(err);
98594
99031
  }
98595
99032
  const remote = detectGitRemote(root);
98596
- if (remote) console.log(import_picocolors42.default.dim(`Detected git remote: ${remote.remoteUrl}`));
99033
+ if (remote) console.log(import_picocolors43.default.dim(`Detected git remote: ${remote.remoteUrl}`));
98597
99034
  let resolved = null;
98598
99035
  let target = opts.project;
98599
99036
  if (!target) {
@@ -98609,7 +99046,7 @@ async function runCloudLink(opts = {}) {
98609
99046
  const org = ctx.organizations.find((o) => o.id === match.organizationId);
98610
99047
  if (ws && org) {
98611
99048
  target = `${org.slug}/${ws.slug}/${match.slug}`;
98612
- console.log(import_picocolors42.default.dim(`Matched existing project by remote: ${import_picocolors42.default.bold(target)}`));
99049
+ console.log(import_picocolors43.default.dim(`Matched existing project by remote: ${import_picocolors43.default.bold(target)}`));
98613
99050
  }
98614
99051
  }
98615
99052
  }
@@ -98618,8 +99055,8 @@ async function runCloudLink(opts = {}) {
98618
99055
  if (created === "aborted") return 1;
98619
99056
  if (!created) {
98620
99057
  console.error(
98621
- import_picocolors42.default.red("No project to link.") + `
98622
- Run ${import_picocolors42.default.bold("horus cloud link")} in a TTY to create one, pass ${import_picocolors42.default.bold("--project <org/workspace/project>")}, or create a project at ${import_picocolors42.default.bold("https://cloud.horus.sh")}.`
99058
+ import_picocolors43.default.red("No project to link.") + `
99059
+ Run ${import_picocolors43.default.bold("horus cloud link")} in a TTY to create one, pass ${import_picocolors43.default.bold("--project <org/workspace/project>")}, or create a project at ${import_picocolors43.default.bold("https://cloud.horus.sh")}.`
98623
99060
  );
98624
99061
  return 1;
98625
99062
  }
@@ -98629,8 +99066,8 @@ async function runCloudLink(opts = {}) {
98629
99066
  resolved = resolveTriple(ctx, target);
98630
99067
  if (!resolved) {
98631
99068
  console.error(
98632
- import_picocolors42.default.red(`You don't have access to ${import_picocolors42.default.bold(target)}.`) + `
98633
- Run ${import_picocolors42.default.bold("horus context list")} to see available projects.`
99069
+ import_picocolors43.default.red(`You don't have access to ${import_picocolors43.default.bold(target)}.`) + `
99070
+ Run ${import_picocolors43.default.bold("horus context list")} to see available projects.`
98634
99071
  );
98635
99072
  return 1;
98636
99073
  }
@@ -98643,10 +99080,10 @@ async function runCloudLink(opts = {}) {
98643
99080
  project: resolved.project
98644
99081
  });
98645
99082
  console.log(
98646
- `${import_picocolors42.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors42.default.bold(label)} ${import_picocolors42.default.dim("(cloud)")}.`
99083
+ `${import_picocolors43.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors43.default.bold(label)} ${import_picocolors43.default.dim("(cloud)")}.`
98647
99084
  );
98648
99085
  console.log(
98649
- import_picocolors42.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors42.default.bold("horus context use local")} to switch back.`)
99086
+ import_picocolors43.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors43.default.bold("horus context use local")} to switch back.`)
98650
99087
  );
98651
99088
  return 0;
98652
99089
  }
@@ -98654,11 +99091,11 @@ async function runCloudUnlink(opts = {}) {
98654
99091
  const root = repoRootOrCwd(opts.cwd);
98655
99092
  const cfg = readCloudConfig(root);
98656
99093
  if (!cfg || cfg.context !== "cloud") {
98657
- console.log(import_picocolors42.default.dim("This repo isn't linked to a cloud project."));
99094
+ console.log(import_picocolors43.default.dim("This repo isn't linked to a cloud project."));
98658
99095
  return 0;
98659
99096
  }
98660
99097
  clearCloudConfig(root);
98661
- console.log(`${import_picocolors42.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors42.default.bold("local")} mode.`);
99098
+ console.log(`${import_picocolors43.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors43.default.bold("local")} mode.`);
98662
99099
  return 0;
98663
99100
  }
98664
99101
  async function runCloudStatus(opts = {}) {
@@ -98666,18 +99103,18 @@ async function runCloudStatus(opts = {}) {
98666
99103
  const cfg = readCloudConfig(root);
98667
99104
  const session = authedClient();
98668
99105
  if (!isCloudActive(cfg) || !cfg?.project) {
98669
- console.log(`${import_picocolors42.default.bold("Context:")} local`);
98670
- console.log(`${import_picocolors42.default.bold("Storage:")} local Postgres (~/.horus)`);
99106
+ console.log(`${import_picocolors43.default.bold("Context:")} local`);
99107
+ console.log(`${import_picocolors43.default.bold("Storage:")} local Postgres (~/.horus)`);
98671
99108
  console.log(
98672
- import_picocolors42.default.dim(`Tip: ${import_picocolors42.default.bold("horus login")} then ${import_picocolors42.default.bold("horus cloud link")} to share investigations with your team.`)
99109
+ import_picocolors43.default.dim(`Tip: ${import_picocolors43.default.bold("horus login")} then ${import_picocolors43.default.bold("horus cloud link")} to share investigations with your team.`)
98673
99110
  );
98674
99111
  return 0;
98675
99112
  }
98676
99113
  const triple = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
98677
- console.log(`${import_picocolors42.default.bold("Context:")} ${triple} ${import_picocolors42.default.dim("(cloud)")}`);
99114
+ console.log(`${import_picocolors43.default.bold("Context:")} ${triple} ${import_picocolors43.default.dim("(cloud)")}`);
98678
99115
  let projectLine = `${cfg.project.slug}`;
98679
99116
  let metaLines = [];
98680
- let account = import_picocolors42.default.dim("not logged in");
99117
+ let account = import_picocolors43.default.dim("not logged in");
98681
99118
  if (session) {
98682
99119
  account = session.auth.account.email;
98683
99120
  try {
@@ -98692,9 +99129,9 @@ async function runCloudStatus(opts = {}) {
98692
99129
  } catch {
98693
99130
  }
98694
99131
  }
98695
- console.log(`${import_picocolors42.default.bold("Project:")} ${projectLine}`);
99132
+ console.log(`${import_picocolors43.default.bold("Project:")} ${projectLine}`);
98696
99133
  for (const line2 of metaLines) console.log(line2);
98697
- console.log(`${import_picocolors42.default.bold("Account:")} ${account}`);
99134
+ console.log(`${import_picocolors43.default.bold("Account:")} ${account}`);
98698
99135
  return 0;
98699
99136
  }
98700
99137
  async function runCloudSync(opts = {}) {
@@ -98702,13 +99139,13 @@ async function runCloudSync(opts = {}) {
98702
99139
  const cfg = readCloudConfig(root);
98703
99140
  if (!isCloudActive(cfg) || !cfg.project) {
98704
99141
  console.error(
98705
- import_picocolors42.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors42.default.bold("horus cloud link")} first.`
99142
+ import_picocolors43.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors43.default.bold("horus cloud link")} first.`
98706
99143
  );
98707
99144
  return 1;
98708
99145
  }
98709
99146
  const session = authedClient();
98710
99147
  if (!session) {
98711
- console.error(import_picocolors42.default.red(`Not logged in. Run ${import_picocolors42.default.bold("horus login")} first.`));
99148
+ console.error(import_picocolors43.default.red(`Not logged in. Run ${import_picocolors43.default.bold("horus login")} first.`));
98712
99149
  return 1;
98713
99150
  }
98714
99151
  const { db, sql: sql2 } = createDb(await resolveDbUrl(opts.config));
@@ -98729,34 +99166,34 @@ async function runCloudSync(opts = {}) {
98729
99166
  const target = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
98730
99167
  if (uploadable.length === 0) {
98731
99168
  console.log(
98732
- import_picocolors42.default.dim(
99169
+ import_picocolors43.default.dim(
98733
99170
  `No local investigations with reports to upload.` + (skippedNoReport ? ` (${skippedNoReport} without a report skipped)` : "")
98734
99171
  )
98735
99172
  );
98736
99173
  return 0;
98737
99174
  }
98738
- console.log(import_picocolors42.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors42.default.dim("(cloud)")}:`));
99175
+ console.log(import_picocolors43.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors43.default.dim("(cloud)")}:`));
98739
99176
  for (const c of uploadable.slice(0, 20)) {
98740
- console.log(` ${import_picocolors42.default.dim(c.id.slice(0, 8))} ${(c.title ?? "untitled").slice(0, 70)}`);
99177
+ console.log(` ${import_picocolors43.default.dim(c.id.slice(0, 8))} ${(c.title ?? "untitled").slice(0, 70)}`);
98741
99178
  }
98742
- if (uploadable.length > 20) console.log(import_picocolors42.default.dim(` \u2026and ${uploadable.length - 20} more`));
98743
- if (skippedNoReport) console.log(import_picocolors42.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
99179
+ if (uploadable.length > 20) console.log(import_picocolors43.default.dim(` \u2026and ${uploadable.length - 20} more`));
99180
+ if (skippedNoReport) console.log(import_picocolors43.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
98744
99181
  if (opts.dryRun) {
98745
- console.log(import_picocolors42.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
99182
+ console.log(import_picocolors43.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
98746
99183
  return 0;
98747
99184
  }
98748
99185
  if (!opts.yes) {
98749
99186
  if (!process.stdin.isTTY) {
98750
99187
  console.error(
98751
- import_picocolors42.default.yellow(`Re-run with ${import_picocolors42.default.bold("--yes")} to upload, or ${import_picocolors42.default.bold("--dry-run")} to preview only.`)
99188
+ import_picocolors43.default.yellow(`Re-run with ${import_picocolors43.default.bold("--yes")} to upload, or ${import_picocolors43.default.bold("--dry-run")} to preview only.`)
98752
99189
  );
98753
99190
  return 1;
98754
99191
  }
98755
- const rl = (0, import_promises2.createInterface)({ input: process.stdin, output: process.stdout });
99192
+ const rl = (0, import_promises3.createInterface)({ input: process.stdin, output: process.stdout });
98756
99193
  try {
98757
99194
  const answer = (await rl.question(`Upload ${uploadable.length} investigation(s) to ${target}? (y/N) `)).trim().toLowerCase();
98758
99195
  if (answer !== "y" && answer !== "yes") {
98759
- console.log(import_picocolors42.default.dim("Aborted. Nothing uploaded."));
99196
+ console.log(import_picocolors43.default.dim("Aborted. Nothing uploaded."));
98760
99197
  return 0;
98761
99198
  }
98762
99199
  } finally {
@@ -98769,18 +99206,18 @@ async function runCloudSync(opts = {}) {
98769
99206
  try {
98770
99207
  const refs = await uploadInvestigationToCloud(session.client, cfg, c.report);
98771
99208
  created++;
98772
- console.log(`${import_picocolors42.default.green("\u2713")} ${import_picocolors42.default.dim(c.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
99209
+ console.log(`${import_picocolors43.default.green("\u2713")} ${import_picocolors43.default.dim(c.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
98773
99210
  } catch (err) {
98774
99211
  failed++;
98775
- console.error(`${import_picocolors42.default.red("\u2717")} ${import_picocolors42.default.dim(c.id.slice(0, 8))} ${err.message}`);
99212
+ console.error(`${import_picocolors43.default.red("\u2717")} ${import_picocolors43.default.dim(c.id.slice(0, 8))} ${err.message}`);
98776
99213
  }
98777
99214
  }
98778
99215
  console.log("");
98779
99216
  console.log(
98780
- `${import_picocolors42.default.bold("Sync complete:")} ${import_picocolors42.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors42.default.red(`${failed} failed`) : "0 failed") + "."
99217
+ `${import_picocolors43.default.bold("Sync complete:")} ${import_picocolors43.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors43.default.red(`${failed} failed`) : "0 failed") + "."
98781
99218
  );
98782
99219
  console.log(
98783
- import_picocolors42.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
99220
+ import_picocolors43.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
98784
99221
  );
98785
99222
  return failed > 0 ? 1 : 0;
98786
99223
  }
@@ -98788,12 +99225,12 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
98788
99225
  if (!process.stdin.isTTY && !yes) return null;
98789
99226
  if (ctx.organizations.length === 0) {
98790
99227
  console.error(
98791
- import_picocolors42.default.red("You're not a member of any organization yet.") + `
98792
- Create one at ${import_picocolors42.default.bold("https://cloud.horus.sh")} first.`
99228
+ import_picocolors43.default.red("You're not a member of any organization yet.") + `
99229
+ Create one at ${import_picocolors43.default.bold("https://cloud.horus.sh")} first.`
98793
99230
  );
98794
99231
  return null;
98795
99232
  }
98796
- const rl = (0, import_promises2.createInterface)({ input: process.stdin, output: process.stdout });
99233
+ const rl = (0, import_promises3.createInterface)({ input: process.stdin, output: process.stdout });
98797
99234
  const ask2 = async (q, def) => {
98798
99235
  if (yes && def !== void 0) return def;
98799
99236
  const a = (await rl.question(def ? `${q} (${def}): ` : `${q}: `)).trim();
@@ -98814,9 +99251,9 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
98814
99251
  const wsName = await ask2("New workspace name", repoName || "default");
98815
99252
  const ws = await client.createWorkspace(org.id, { name: wsName });
98816
99253
  workspace = { id: ws.id, slug: ws.slug };
98817
- console.log(import_picocolors42.default.dim(`Created workspace ${import_picocolors42.default.bold(ws.slug)}.`));
99254
+ console.log(import_picocolors43.default.dim(`Created workspace ${import_picocolors43.default.bold(ws.slug)}.`));
98818
99255
  } else {
98819
- console.log(`Workspaces in ${import_picocolors42.default.bold(org.slug)}:`);
99256
+ console.log(`Workspaces in ${import_picocolors43.default.bold(org.slug)}:`);
98820
99257
  orgWorkspaces.forEach((w, i) => console.log(` ${i + 1}) ${w.slug}`));
98821
99258
  console.log(` ${orgWorkspaces.length + 1}) + create a new workspace`);
98822
99259
  const pick2 = Number(await ask2("Workspace number", "1"));
@@ -98824,7 +99261,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
98824
99261
  const wsName = await ask2("New workspace name", repoName || "default");
98825
99262
  const ws = await client.createWorkspace(org.id, { name: wsName });
98826
99263
  workspace = { id: ws.id, slug: ws.slug };
98827
- console.log(import_picocolors42.default.dim(`Created workspace ${import_picocolors42.default.bold(ws.slug)}.`));
99264
+ console.log(import_picocolors43.default.dim(`Created workspace ${import_picocolors43.default.bold(ws.slug)}.`));
98828
99265
  } else {
98829
99266
  const chosen = orgWorkspaces[pick2 - 1] ?? orgWorkspaces[0];
98830
99267
  workspace = { id: chosen.id, slug: chosen.slug };
@@ -98836,7 +99273,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
98836
99273
  remoteUrl: remote?.remoteUrl,
98837
99274
  provider: remote ? inferProvider(remote.remoteUrl) : void 0
98838
99275
  });
98839
- console.log(import_picocolors42.default.dim(`Created project ${import_picocolors42.default.bold(project.slug)}.`));
99276
+ console.log(import_picocolors43.default.dim(`Created project ${import_picocolors43.default.bold(project.slug)}.`));
98840
99277
  return {
98841
99278
  organization: { id: org.id, slug: org.slug },
98842
99279
  workspace,
@@ -98850,6 +99287,274 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
98850
99287
  }
98851
99288
  }
98852
99289
 
99290
+ // ../../packages/cli/src/commands/telemetry.ts
99291
+ init_cjs_shims();
99292
+ var import_picocolors45 = __toESM(require_picocolors(), 1);
99293
+ var import_node_crypto8 = require("crypto");
99294
+
99295
+ // ../../packages/cli/src/lib/telemetry/transport.ts
99296
+ init_cjs_shims();
99297
+ var CHUNK = 100;
99298
+ var DEFAULT_TIMEOUT_MS = 1500;
99299
+ function telemetryBaseUrl() {
99300
+ return process.env.HORUS_TELEMETRY_URL ?? process.env.HORUS_API_BASE_URL ?? readAuth()?.apiBaseUrl ?? DEFAULT_API_BASE_URL;
99301
+ }
99302
+ async function postBatch(url, events, signal) {
99303
+ const res = await fetch(url, {
99304
+ method: "POST",
99305
+ headers: { "content-type": "application/json" },
99306
+ body: JSON.stringify({ events }),
99307
+ signal
99308
+ });
99309
+ return res.ok;
99310
+ }
99311
+ async function flushTelemetry(opts = {}) {
99312
+ try {
99313
+ if (!resolveConsent().tierA) return;
99314
+ const events = readSpooledEvents();
99315
+ if (events.length === 0) return;
99316
+ const url = `${telemetryBaseUrl().replace(/\/$/, "")}/v1/telemetry`;
99317
+ const controller = new AbortController();
99318
+ const timer2 = setTimeout(() => controller.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
99319
+ try {
99320
+ for (let i = 0; i < events.length; i += CHUNK) {
99321
+ const ok = await postBatch(url, events.slice(i, i + CHUNK), controller.signal);
99322
+ if (!ok) return;
99323
+ }
99324
+ clearSpool();
99325
+ } finally {
99326
+ clearTimeout(timer2);
99327
+ }
99328
+ } catch {
99329
+ }
99330
+ }
99331
+ async function deleteRemoteTelemetry(installId, opts = {}) {
99332
+ try {
99333
+ if (!installId) return;
99334
+ const url = `${telemetryBaseUrl().replace(/\/$/, "")}/v1/telemetry/delete`;
99335
+ const controller = new AbortController();
99336
+ const timer2 = setTimeout(() => controller.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
99337
+ try {
99338
+ await fetch(url, {
99339
+ method: "POST",
99340
+ headers: { "content-type": "application/json" },
99341
+ body: JSON.stringify({ installId }),
99342
+ signal: controller.signal
99343
+ });
99344
+ } finally {
99345
+ clearTimeout(timer2);
99346
+ }
99347
+ } catch {
99348
+ }
99349
+ }
99350
+
99351
+ // ../../packages/cli/src/lib/telemetry/notice.ts
99352
+ init_cjs_shims();
99353
+ var import_picocolors44 = __toESM(require_picocolors(), 1);
99354
+ var PRIVACY_URL = "https://horus.sh/privacy";
99355
+ var SUPPRESS_FIRST_TOKEN = /* @__PURE__ */ new Set(["telemetry", "help"]);
99356
+ var SUPPRESS_FLAGS = /* @__PURE__ */ new Set(["-V", "--version", "-h", "--help"]);
99357
+ function shouldSuppressFor(argv) {
99358
+ const args = argv.slice(2);
99359
+ if (args.length === 0) return true;
99360
+ if (args.some((a) => SUPPRESS_FLAGS.has(a))) return true;
99361
+ const firstToken = args.find((a) => !a.startsWith("-"));
99362
+ return firstToken != null && SUPPRESS_FIRST_TOKEN.has(firstToken);
99363
+ }
99364
+ function banner() {
99365
+ const b2 = import_picocolors44.default.bold;
99366
+ const dim = import_picocolors44.default.dim;
99367
+ return [
99368
+ "",
99369
+ import_picocolors44.default.cyan(b2("Horus collects anonymous usage data to improve the tool.")),
99370
+ dim(" \u2022 On by default: command names, timings, success/failure, and where the"),
99371
+ dim(" engine ran out of evidence. No file contents, queries, or secrets."),
99372
+ dim(" \u2022 Off by default: your investigation inputs/outputs (opt in to help train"),
99373
+ ` ${dim("Horus)")} ${dim("\u2014 run")} ${b2("horus telemetry enable-content")}`,
99374
+ dim(" \u2022 If you use Horus Cloud, linked investigations sync to your workspace."),
99375
+ "",
99376
+ ` ${dim("Opt out anytime:")} ${b2("horus telemetry disable")} ${dim("\xB7")} ${b2("HORUS_TELEMETRY=0")} ${dim("\xB7")} ${b2("DO_NOT_TRACK=1")}`,
99377
+ ` ${dim("Details:")} ${import_picocolors44.default.underline(PRIVACY_URL)}`,
99378
+ ""
99379
+ ].join("\n");
99380
+ }
99381
+ function maybeShowFirstRunNotice(argv = process.argv) {
99382
+ try {
99383
+ const env = process.env;
99384
+ if (resolveConsent({ env }).forcedOff) return;
99385
+ if (isCI(env)) return;
99386
+ const state = loadOrInitTelemetryState();
99387
+ if (state.tierA.noticeShownAt) return;
99388
+ if (shouldSuppressFor(argv)) return;
99389
+ if (!process.stderr.isTTY) return;
99390
+ process.stderr.write(banner() + "\n");
99391
+ updateTelemetryState((s) => {
99392
+ s.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
99393
+ });
99394
+ } catch {
99395
+ }
99396
+ }
99397
+
99398
+ // ../../packages/cli/src/commands/telemetry.ts
99399
+ function onOff(enabled) {
99400
+ return enabled ? import_picocolors45.default.green("on") : import_picocolors45.default.dim("off");
99401
+ }
99402
+ function warnIfEnvOverrides() {
99403
+ const decision = resolveConsent();
99404
+ if (decision.forcedOff) {
99405
+ console.log(
99406
+ import_picocolors45.default.yellow(
99407
+ `
99408
+ Note: telemetry is currently forced off by your environment (${decision.reason}).`
99409
+ )
99410
+ );
99411
+ console.log(import_picocolors45.default.dim("Your saved preference will apply once that override is removed."));
99412
+ } else if (decision.source === "ci") {
99413
+ console.log(
99414
+ import_picocolors45.default.yellow("\nNote: CI environment detected \u2014 telemetry stays off here regardless.")
99415
+ );
99416
+ }
99417
+ }
99418
+ async function runTelemetryStatus() {
99419
+ const state = readTelemetryState();
99420
+ const decision = resolveConsent({ state });
99421
+ console.log(import_picocolors45.default.bold("Horus telemetry"));
99422
+ console.log(
99423
+ ` Usage metadata (Tier A): ${onOff(decision.tierA)} ${import_picocolors45.default.dim(`[${decision.source}]`)}`
99424
+ );
99425
+ console.log(` Content sharing (Tier B): ${onOff(decision.tierB)}`);
99426
+ console.log(import_picocolors45.default.dim(` Reason: ${decision.reason}`));
99427
+ if (state) {
99428
+ console.log(import_picocolors45.default.dim(` Install ID: ${state.installId}`));
99429
+ console.log(
99430
+ import_picocolors45.default.dim(
99431
+ ` Saved: Tier A ${state.tierA.enabled ? "on" : "off"}, Tier B ${state.tierB.enabled ? "on" : "off"}`
99432
+ )
99433
+ );
99434
+ } else {
99435
+ console.log(import_picocolors45.default.dim(" No saved preference yet (defaults apply)."));
99436
+ }
99437
+ console.log(import_picocolors45.default.dim(` Config: ${telemetryPath()}`));
99438
+ console.log(import_picocolors45.default.dim(` Privacy: ${PRIVACY_URL}`));
99439
+ if (!state || decision.source === "env" || decision.source === "ci") {
99440
+ warnIfEnvOverrides();
99441
+ }
99442
+ return 0;
99443
+ }
99444
+ async function runTelemetryEnable() {
99445
+ updateTelemetryState((s) => {
99446
+ s.tierA.enabled = true;
99447
+ if (!s.tierA.noticeShownAt) s.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
99448
+ });
99449
+ console.log(import_picocolors45.default.green("Anonymous usage metadata (Tier A) is now ON. Thank you!"));
99450
+ warnIfEnvOverrides();
99451
+ return 0;
99452
+ }
99453
+ async function runTelemetryDisable() {
99454
+ updateTelemetryState((s) => {
99455
+ s.tierA.enabled = false;
99456
+ s.tierB.enabled = false;
99457
+ if (!s.tierA.noticeShownAt) s.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
99458
+ });
99459
+ console.log(import_picocolors45.default.yellow("All telemetry is now OFF (Tier A and Tier B)."));
99460
+ return 0;
99461
+ }
99462
+ async function runTelemetryEnableContent() {
99463
+ updateTelemetryState((s) => {
99464
+ s.tierA.enabled = true;
99465
+ s.tierB.enabled = true;
99466
+ s.tierB.enabledAt = (/* @__PURE__ */ new Date()).toISOString();
99467
+ if (!s.tierA.noticeShownAt) s.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
99468
+ });
99469
+ console.log(
99470
+ import_picocolors45.default.green("Content sharing (Tier B) is now ON \u2014 redacted inputs/outputs help improve Horus.")
99471
+ );
99472
+ console.log(import_picocolors45.default.dim("Content is scrubbed of secrets/PII before it ever leaves your machine."));
99473
+ console.log(import_picocolors45.default.dim(`What this means: ${PRIVACY_URL}`));
99474
+ warnIfEnvOverrides();
99475
+ return 0;
99476
+ }
99477
+ async function runTelemetryDisableContent() {
99478
+ updateTelemetryState((s) => {
99479
+ s.tierB.enabled = false;
99480
+ });
99481
+ console.log(import_picocolors45.default.yellow("Content sharing (Tier B) is now OFF. Usage metadata is unchanged."));
99482
+ return 0;
99483
+ }
99484
+ async function runTelemetryResetId() {
99485
+ const next = (0, import_node_crypto8.randomUUID)();
99486
+ updateTelemetryState((s) => {
99487
+ s.installId = next;
99488
+ });
99489
+ console.log(import_picocolors45.default.green("Install ID reset."));
99490
+ console.log(import_picocolors45.default.dim(` New install ID: ${next}`));
99491
+ return 0;
99492
+ }
99493
+ async function runTelemetryDelete() {
99494
+ const installId = readTelemetryState()?.installId;
99495
+ if (installId) await deleteRemoteTelemetry(installId);
99496
+ deleteTelemetryState();
99497
+ clearSpool();
99498
+ console.log(import_picocolors45.default.green("Telemetry deleted \u2014 local state cleared and a server purge requested."));
99499
+ console.log(
99500
+ import_picocolors45.default.dim(
99501
+ "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."
99502
+ )
99503
+ );
99504
+ return 0;
99505
+ }
99506
+
99507
+ // ../../packages/cli/src/lib/telemetry/command-hooks.ts
99508
+ init_cjs_shims();
99509
+ function commandPath(cmd) {
99510
+ const parts = [];
99511
+ let current = cmd;
99512
+ while (current && current.parent) {
99513
+ parts.unshift(current.name());
99514
+ current = current.parent;
99515
+ }
99516
+ return parts.join(" ") || cmd.name();
99517
+ }
99518
+ function installCommandTelemetry(program2) {
99519
+ let startedAt = 0;
99520
+ program2.hook("preAction", (_thisCommand, actionCommand) => {
99521
+ startedAt = Date.now();
99522
+ track({
99523
+ type: "command.invoked",
99524
+ command: commandPath(actionCommand),
99525
+ flags: extractFlagNames(process.argv)
99526
+ });
99527
+ });
99528
+ program2.hook("postAction", (_thisCommand, actionCommand) => {
99529
+ const exitCode = typeof process.exitCode === "number" ? process.exitCode : 0;
99530
+ track({
99531
+ type: "command.completed",
99532
+ command: commandPath(actionCommand),
99533
+ flags: extractFlagNames(process.argv),
99534
+ durationMs: startedAt ? Date.now() - startedAt : 0,
99535
+ exitCode,
99536
+ ok: exitCode === 0
99537
+ });
99538
+ });
99539
+ }
99540
+
99541
+ // ../../packages/cli/src/commands/feedback.ts
99542
+ init_cjs_shims();
99543
+ var import_picocolors46 = __toESM(require_picocolors(), 1);
99544
+ async function runFeedback(investigationId) {
99545
+ if (!process.stdin.isTTY) {
99546
+ console.error(import_picocolors46.default.yellow("horus feedback needs an interactive terminal."));
99547
+ return 1;
99548
+ }
99549
+ const id = investigationId?.trim();
99550
+ if (!id) {
99551
+ console.error(import_picocolors46.default.red("Usage: horus feedback <investigationId>"));
99552
+ return 1;
99553
+ }
99554
+ await runFeedbackPrompt(id, null);
99555
+ return 0;
99556
+ }
99557
+
98853
99558
  // ../../packages/cli/src/index.ts
98854
99559
  function buildProgram() {
98855
99560
  const program2 = new Command();
@@ -99271,11 +99976,50 @@ Examples:
99271
99976
  horus cloud sync --dry-run # preview what would upload
99272
99977
  horus cloud sync # confirm, then upload
99273
99978
  horus cloud sync --yes # upload without prompting`);
99979
+ program2.command("feedback [investigationId]").description("Leave quick impact feedback on an investigation (helps improve Horus)").action(async (investigationId) => {
99980
+ process.exitCode = await runFeedback(investigationId);
99981
+ });
99982
+ const telemetry = program2.command("telemetry").description("Manage anonymous usage telemetry that helps improve Horus");
99983
+ telemetry.command("status").description("Show the effective telemetry decision, saved preferences, and install ID").action(async () => {
99984
+ process.exitCode = await runTelemetryStatus();
99985
+ });
99986
+ telemetry.command("enable").description("Turn on anonymous usage metadata (Tier A)").action(async () => {
99987
+ process.exitCode = await runTelemetryEnable();
99988
+ });
99989
+ telemetry.command("disable").description("Turn off all telemetry (Tier A and Tier B)").action(async () => {
99990
+ process.exitCode = await runTelemetryDisable();
99991
+ });
99992
+ telemetry.command("enable-content").description("Opt in to sharing redacted investigation inputs/outputs (Tier B)").action(async () => {
99993
+ process.exitCode = await runTelemetryEnableContent();
99994
+ });
99995
+ telemetry.command("disable-content").description("Stop sharing inputs/outputs; keep usage metadata (Tier B off)").action(async () => {
99996
+ process.exitCode = await runTelemetryDisableContent();
99997
+ });
99998
+ telemetry.command("reset-id").description("Generate a new random install ID").action(async () => {
99999
+ process.exitCode = await runTelemetryResetId();
100000
+ });
100001
+ telemetry.command("delete").description("Delete local telemetry state (install ID + saved preferences)").action(async () => {
100002
+ process.exitCode = await runTelemetryDelete();
100003
+ });
100004
+ telemetry.addHelpText(
100005
+ "after",
100006
+ `
100007
+ Defaults: usage metadata ON (with this notice), content sharing OFF.
100008
+ Hard opt-out via env: HORUS_TELEMETRY=0 or DO_NOT_TRACK=1.
100009
+
100010
+ Examples:
100011
+ horus telemetry status
100012
+ horus telemetry disable
100013
+ horus telemetry enable-content`
100014
+ );
99274
100015
  return program2;
99275
100016
  }
99276
100017
  async function run(argv = process.argv) {
100018
+ maybeShowFirstRunNotice(argv);
99277
100019
  const program2 = buildProgram();
100020
+ installCommandTelemetry(program2);
99278
100021
  await program2.parseAsync(argv);
100022
+ await flushTelemetry();
99279
100023
  }
99280
100024
 
99281
100025
  // src/index.ts