@merittdev/horus 0.21.2 → 0.21.3

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.
Binary file
package/dist/index.cjs CHANGED
@@ -3057,7 +3057,7 @@ var init_version = __esm({
3057
3057
  "../../packages/core/src/version.ts"() {
3058
3058
  "use strict";
3059
3059
  init_cjs_shims();
3060
- HORUS_VERSION = true ? "0.21.2" : "dev";
3060
+ HORUS_VERSION = true ? "0.21.3" : "dev";
3061
3061
  PINNED_SOURCE_VERSION = HORUS_VERSION;
3062
3062
  SOURCE_PIN_ENFORCED = HORUS_VERSION !== "dev";
3063
3063
  }
@@ -72160,12 +72160,17 @@ function readSourceMeta(root) {
72160
72160
  return {
72161
72161
  storeBackend: typeof j3["store_backend"] === "string" ? j3["store_backend"].toLowerCase() : void 0,
72162
72162
  embeddingsComplete: typeof j3["embeddings_complete"] === "boolean" ? j3["embeddings_complete"] : void 0,
72163
+ structuralComplete: typeof j3["structural_complete"] === "boolean" ? j3["structural_complete"] : void 0,
72163
72164
  stats: stats ? { symbols: stats["symbols"], embeddings: stats["embeddings"] } : void 0
72164
72165
  };
72165
72166
  } catch {
72166
72167
  return null;
72167
72168
  }
72168
72169
  }
72170
+ function indexEmbeddingsPending(root) {
72171
+ const meta = readSourceMeta(root);
72172
+ return meta?.structuralComplete === true && meta?.embeddingsComplete === false;
72173
+ }
72169
72174
  function metaHasEmbeddings(meta) {
72170
72175
  if (meta.embeddingsComplete === false) return false;
72171
72176
  const embeddings = meta.stats?.embeddings ?? 0;
@@ -72183,25 +72188,88 @@ function indexNeedsReanalyze(root) {
72183
72188
  return `store backend changed (${meta.storeBackend} -> ${CURRENT_STORE_BACKEND})`;
72184
72189
  }
72185
72190
  if (!metaHasEmbeddings(meta)) {
72191
+ if (meta.structuralComplete === true) return null;
72186
72192
  return "index has no semantic embeddings (symbols present but 0 vectors)";
72187
72193
  }
72188
72194
  return null;
72189
72195
  }
72196
+ var BASE_ANALYZE_TIMEOUT_MS = 9e5;
72197
+ var MAX_ANALYZE_TIMEOUT_MS = 36e5;
72198
+ var ANALYZE_BASELINE_FILES = 5e3;
72199
+ var ANALYZE_TIMEOUT_PER_FILE_MS = 15;
72200
+ var ANALYZE_COUNT_SKIP_DIRS = /* @__PURE__ */ new Set([
72201
+ "node_modules",
72202
+ ".git",
72203
+ ".horus",
72204
+ "dist",
72205
+ "build",
72206
+ "out",
72207
+ "target",
72208
+ "vendor",
72209
+ ".venv",
72210
+ "venv",
72211
+ "__pycache__",
72212
+ ".next",
72213
+ ".turbo",
72214
+ "coverage",
72215
+ ".cache"
72216
+ ]);
72217
+ function countRepoFiles(root, limit = 2e5) {
72218
+ let count = 0;
72219
+ const stack = [root];
72220
+ while (stack.length > 0) {
72221
+ const dir = stack.pop();
72222
+ let entries;
72223
+ try {
72224
+ entries = (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true });
72225
+ } catch {
72226
+ continue;
72227
+ }
72228
+ for (const e of entries) {
72229
+ if (e.isDirectory()) {
72230
+ if (ANALYZE_COUNT_SKIP_DIRS.has(e.name) || e.name.startsWith(".")) continue;
72231
+ stack.push((0, import_node_path4.join)(dir, e.name));
72232
+ } else if (e.isFile()) {
72233
+ count++;
72234
+ if (count >= limit) return count;
72235
+ }
72236
+ }
72237
+ }
72238
+ return count;
72239
+ }
72240
+ function resolveAnalyzeTimeoutMs(root) {
72241
+ const override = process.env["HORUS_ANALYZE_TIMEOUT_MS"];
72242
+ if (override !== void 0 && override.trim() !== "") {
72243
+ const n4 = Number(override);
72244
+ if (Number.isFinite(n4) && n4 > 0) return Math.floor(n4);
72245
+ }
72246
+ let files = 0;
72247
+ try {
72248
+ files = countRepoFiles(root);
72249
+ } catch {
72250
+ return BASE_ANALYZE_TIMEOUT_MS;
72251
+ }
72252
+ if (files <= ANALYZE_BASELINE_FILES) return BASE_ANALYZE_TIMEOUT_MS;
72253
+ const scaled = BASE_ANALYZE_TIMEOUT_MS + (files - ANALYZE_BASELINE_FILES) * ANALYZE_TIMEOUT_PER_FILE_MS;
72254
+ return Math.min(scaled, MAX_ANALYZE_TIMEOUT_MS);
72255
+ }
72190
72256
  async function analyzeRepo(root) {
72191
72257
  const bin = await resolveSourceBin();
72192
72258
  if (!bin) throw new Error("horus-source not found on PATH. Install it: curl -fsSL https://horus.sh/install.sh | bash");
72259
+ const timeoutMs = resolveAnalyzeTimeoutMs(root);
72193
72260
  try {
72194
- await exec(bin, ["analyze", "."], {
72261
+ await exec(bin, ["analyze", ".", "--defer-embeddings"], {
72195
72262
  cwd: root,
72196
- timeout: 9e5,
72263
+ timeout: timeoutMs,
72197
72264
  maxBuffer: 64 * 1024 * 1024
72198
72265
  });
72199
72266
  } catch (err2) {
72200
72267
  const e = err2;
72201
72268
  const tail = redactSecrets((e.stderr ?? "").trim()).slice(-800);
72202
72269
  if (e.killed || e.signal === "SIGTERM" || e.code === "ETIMEDOUT") {
72270
+ const secs = Math.round(timeoutMs / 1e3);
72203
72271
  throw new Error(
72204
- `horus-source analyze timed out after 900s (large repo / slow embeddings phase)` + (tail ? ` \u2014 last output: ${tail}` : "")
72272
+ `horus-source analyze timed out after ${secs}s while building the structural index (large repo). Raise the cap with HORUS_ANALYZE_TIMEOUT_MS.` + (tail ? ` \u2014 last output: ${tail}` : "")
72205
72273
  );
72206
72274
  }
72207
72275
  throw new Error(tail ? `horus-source analyze failed: ${tail}` : redactSecrets(e.message ?? "horus-source analyze failed"));
@@ -124755,7 +124823,7 @@ async function runIndex(opts) {
124755
124823
  if (incomplete) {
124756
124824
  console.error(
124757
124825
  import_picocolors41.default.red(
124758
- ` source analysis did not finish (${incomplete}) \u2014 the index has symbols but no embeddings. Re-run \`horus init\` to resume (the embedding cache is warm).`
124826
+ ` source analysis did not finish (${incomplete}) \u2014 the structural index is missing or broken. Re-run \`horus init\` to rebuild it.`
124759
124827
  )
124760
124828
  );
124761
124829
  return 1;
@@ -124810,6 +124878,9 @@ async function runIndex(opts) {
124810
124878
  );
124811
124879
  return 1;
124812
124880
  }
124881
+ if (indexEmbeddingsPending(root)) {
124882
+ console.log(import_picocolors41.default.dim(" index ready (semantic search warming up)"));
124883
+ }
124813
124884
  try {
124814
124885
  await stitchQueueMap(hostUrl, label);
124815
124886
  } catch (err2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@merittdev/horus",
3
- "version": "0.21.2",
3
+ "version": "0.21.3",
4
4
  "description": "Local-first, source-aware production-incident investigation engine",
5
5
  "type": "module",
6
6
  "bin": {