@massa-ai/mcp-client 1.63.1 → 1.65.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 (3) hide show
  1. package/dist/config-cli.js +410 -179
  2. package/dist/index.js +1105 -848
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -28537,22 +28537,15 @@ var BOOTSTRAP_RULE_IDS, RETIRED_RULE_IDS, BOOTSTRAP_RULES, RULES_BY_ID, Bootstra
28537
28537
  };
28538
28538
  var init_rules = __esm(() => {
28539
28539
  BOOTSTRAP_RULE_IDS = [
28540
- "caveman",
28541
28540
  "massa-ai-router",
28542
28541
  "dedupe-guardrails",
28543
- "plan-challenge",
28544
28542
  "conversation-feedback",
28545
28543
  "indexing-hygiene",
28546
28544
  "english-code",
28547
28545
  "code-comments"
28548
28546
  ];
28549
- RETIRED_RULE_IDS = ["persona-router"];
28547
+ RETIRED_RULE_IDS = ["persona-router", "caveman", "plan-challenge"];
28550
28548
  BOOTSTRAP_RULES = [
28551
- {
28552
- id: "caveman",
28553
- defaultEnabled: true,
28554
- description: "Keep communication compressed while preserving technical accuracy."
28555
- },
28556
28549
  {
28557
28550
  id: "massa-ai-router",
28558
28551
  defaultEnabled: true,
@@ -28563,11 +28556,6 @@ var init_rules = __esm(() => {
28563
28556
  defaultEnabled: true,
28564
28557
  description: "Reuse already-loaded massa-ai context instead of bulk-loading workflows or references."
28565
28558
  },
28566
- {
28567
- id: "plan-challenge",
28568
- defaultEnabled: true,
28569
- description: "Run The Fool as a post-plan challenge gate per the configured policy."
28570
- },
28571
28559
  {
28572
28560
  id: "conversation-feedback",
28573
28561
  defaultEnabled: true,
@@ -35199,7 +35187,8 @@ var init_ignore_patterns = __esm(() => {
35199
35187
  "**/pnpm-lock.yaml",
35200
35188
  "**/package-lock.json",
35201
35189
  "**/bun.lockb",
35202
- "**/yarn.lock"
35190
+ "**/yarn.lock",
35191
+ "**/Pods/**"
35203
35192
  ];
35204
35193
  });
35205
35194
 
@@ -124317,6 +124306,33 @@ class ManagedRunRepositoryPg {
124317
124306
  `;
124318
124307
  return rows[0] ? toActive(rows[0]) : null;
124319
124308
  }
124309
+ async getAnyActive() {
124310
+ const rows = await getPrismaClient2().$queryRaw`
124311
+ SELECT id, project_id, run_kind, event_id, content_hash, file_cursor,
124312
+ status, lease_token, lease_expires_at, heartbeat_at,
124313
+ created_at, completed_at
124314
+ FROM managed_runs
124315
+ WHERE status = 'active'
124316
+ AND lease_expires_at > clock_timestamp()
124317
+ ORDER BY lease_expires_at DESC
124318
+ LIMIT 1
124319
+ `;
124320
+ return rows[0] ? toActive(rows[0]) : null;
124321
+ }
124322
+ async release(lease) {
124323
+ const leaseToken = boundedText(lease.leaseToken, "leaseToken", MAX_LEASE_TOKEN);
124324
+ const deleted = await getPrismaClient2().$queryRaw`
124325
+ DELETE FROM managed_runs
124326
+ WHERE id = ${BigInt(lease.runId)}
124327
+ AND project_id = ${lease.projectId}
124328
+ AND run_kind = ${lease.runKind}
124329
+ AND lease_token = ${leaseToken}
124330
+ RETURNING id
124331
+ `;
124332
+ if (!deleted[0])
124333
+ return { status: "lease_lost" };
124334
+ return { status: "aborted", runId: deleted[0].id.toString() };
124335
+ }
124320
124336
  }
124321
124337
  var DEFAULT_LEASE_TTL_MS = 90000, MIN_LEASE_TTL_MS = 1000, MAX_LEASE_TTL_MS = 300000, HEARTBEAT_TTL_MS = 90000, MAX_PROJECT_ID = 512, MAX_EVENT_ID = 2000, MAX_CONTENT_HASH = 2000, MAX_LEASE_TOKEN = 512;
124322
124338
  var init_managed_run_repository_pg = __esm(() => {
@@ -124354,10 +124370,111 @@ var init_embedding_freshness = __esm(() => {
124354
124370
  };
124355
124371
  });
124356
124372
 
124373
+ // ../../packages/core/dist/services/jobs/heavy-work-lease.js
124374
+ import { randomUUID as randomUUID3 } from "crypto";
124375
+ import { setTimeout as delay2 } from "timers/promises";
124376
+ function repository() {
124377
+ return repositoryOverride ?? ManagedRunRepositoryPg.getInstance();
124378
+ }
124379
+ async function withHeavyWorkLease(kind, label, fn) {
124380
+ let repo;
124381
+ let lease;
124382
+ try {
124383
+ repo = repository();
124384
+ const outcome = await repo.begin({
124385
+ projectId: `heavy-work:${label}:${randomUUID3()}`,
124386
+ runKind: kind,
124387
+ eventId: `heavy-work:${label}`
124388
+ });
124389
+ if (outcome.status === "acquired")
124390
+ lease = outcome.lease;
124391
+ } catch (error51) {
124392
+ logger.warn("heavy-work lease unavailable; running without it", { label, error: error51 });
124393
+ }
124394
+ if (!repo || !lease)
124395
+ return fn();
124396
+ const heldRepo = repo;
124397
+ const heldLease = lease;
124398
+ const heartbeatController = new AbortController;
124399
+ (async () => {
124400
+ while (true) {
124401
+ try {
124402
+ await delay2(HEARTBEAT_MS, undefined, { signal: heartbeatController.signal });
124403
+ } catch {
124404
+ return;
124405
+ }
124406
+ try {
124407
+ await heldRepo.heartbeat(heldLease);
124408
+ } catch {}
124409
+ }
124410
+ })();
124411
+ try {
124412
+ return await fn();
124413
+ } finally {
124414
+ heartbeatController.abort();
124415
+ try {
124416
+ await heldRepo.release(heldLease);
124417
+ } catch (error51) {
124418
+ logger.warn("heavy-work lease release failed; it expires on its own", { label, error: error51 });
124419
+ }
124420
+ }
124421
+ }
124422
+ async function probeHeavyWork() {
124423
+ let timer;
124424
+ const timeout = new Promise((_, reject) => {
124425
+ timer = setTimeout(() => reject(new Error(`heavy-work probe timed out after ${PROBE_TIMEOUT_MS}ms`)), PROBE_TIMEOUT_MS);
124426
+ });
124427
+ try {
124428
+ const active = await Promise.race([repository().getAnyActive(), timeout]);
124429
+ if (!active)
124430
+ return { busy: false };
124431
+ return { busy: true, reason: `${active.runKind} run ${active.runId} (${active.projectId})` };
124432
+ } finally {
124433
+ clearTimeout(timer);
124434
+ }
124435
+ }
124436
+ var HEARTBEAT_MS = 30000, PROBE_TIMEOUT_MS = 5000, repositoryOverride = null;
124437
+ var init_heavy_work_lease = __esm(() => {
124438
+ init_dist();
124439
+ init_managed_run_repository_pg();
124440
+ });
124441
+
124442
+ // ../../packages/core/dist/services/search/incremental-reindex.js
124443
+ import path21 from "path";
124444
+ function runIncrementalReindex(deps, projectId, projectPath, filesToReindex) {
124445
+ return withHeavyWorkLease("reindex", `incremental-reindex:${projectId}`, async () => {
124446
+ const centralityMap = await deps.symbolRepo.getCentrality(await getProjectIdentityAliasResolver().resolve(projectId));
124447
+ let filesIndexed = 0;
124448
+ let chunksIndexed = 0;
124449
+ let errors4 = 0;
124450
+ for (const relativeFilePath of filesToReindex) {
124451
+ try {
124452
+ const fullPath = path21.join(projectPath, relativeFilePath);
124453
+ const result = await deps.indexFile(fullPath, projectId, projectPath, centralityMap);
124454
+ filesIndexed++;
124455
+ chunksIndexed += result.chunks;
124456
+ } catch (error51) {
124457
+ logger.error("Failed to reindex file", error51, {
124458
+ file: relativeFilePath
124459
+ });
124460
+ errors4++;
124461
+ }
124462
+ }
124463
+ await deps.indexManager.updateIndexMetadata(projectId, projectPath, filesToReindex);
124464
+ await deps.searchCache.invalidateProject(projectId);
124465
+ return { filesIndexed, chunksIndexed, errors: errors4 };
124466
+ });
124467
+ }
124468
+ var init_incremental_reindex = __esm(() => {
124469
+ init_dist();
124470
+ init_alias_resolver();
124471
+ init_heavy_work_lease();
124472
+ });
124473
+
124357
124474
  // ../../packages/core/dist/services/search/project-indexer.js
124358
124475
  import fs15 from "fs/promises";
124359
- import path21 from "path";
124360
- import { randomUUID as randomUUID3 } from "crypto";
124476
+ import path22 from "path";
124477
+ import { randomUUID as randomUUID4 } from "crypto";
124361
124478
  async function runWithIndexLock(lockMap, projectId, work) {
124362
124479
  const prevLock = lockMap.get(projectId);
124363
124480
  const isQueued = prevLock !== undefined;
@@ -124399,7 +124516,7 @@ async function indexProjectInternal(deps, projectPath, projectId, options = {})
124399
124516
  dot: false
124400
124517
  });
124401
124518
  const filteredFiles = files.filter((file2) => {
124402
- const relativePath = path21.relative(projectPath, file2);
124519
+ const relativePath = path22.relative(projectPath, file2);
124403
124520
  const shouldIgnore = ig.ignores(relativePath);
124404
124521
  if (shouldIgnore) {
124405
124522
  logger.debug("Ignoring file per .gitignore during indexing", {
@@ -124439,7 +124556,7 @@ async function indexProjectInternal(deps, projectPath, projectId, options = {})
124439
124556
  });
124440
124557
  }
124441
124558
  }
124442
- const indexedFilesList = filteredFiles.map((f) => path21.relative(projectPath, f));
124559
+ const indexedFilesList = filteredFiles.map((f) => path22.relative(projectPath, f));
124443
124560
  await deps.indexManager.updateIndexMetadata(projectId, projectPath, indexedFilesList);
124444
124561
  logger.info("Project indexing completed", {
124445
124562
  projectId,
@@ -124510,7 +124627,7 @@ async function ensureFreshIndex(deps, projectId, projectPath, options = {}) {
124510
124627
  if (needsFullReindex) {
124511
124628
  logger.info("Performing full reindex", { projectId });
124512
124629
  const managedRunRepo = ManagedRunRepositoryPg.getInstance();
124513
- const eventId = `reindex:${projectId}:${randomUUID3()}`;
124630
+ const eventId = `reindex:${projectId}:${randomUUID4()}`;
124514
124631
  const beginOutcome = await managedRunRepo.begin({
124515
124632
  projectId,
124516
124633
  runKind: "indexing",
@@ -124563,25 +124680,7 @@ async function ensureFreshIndex(deps, projectId, projectPath, options = {}) {
124563
124680
  projectId,
124564
124681
  fileCount: filesToReindex.length
124565
124682
  });
124566
- const centralityMap = await deps.symbolRepo.getCentrality(await getProjectIdentityAliasResolver().resolve(projectId));
124567
- let filesIndexed = 0;
124568
- let chunksIndexed = 0;
124569
- let errors4 = 0;
124570
- for (const relativeFilePath of filesToReindex) {
124571
- try {
124572
- const fullPath = path21.join(projectPath, relativeFilePath);
124573
- const result = await deps.indexFile(fullPath, projectId, projectPath, centralityMap);
124574
- filesIndexed++;
124575
- chunksIndexed += result.chunks;
124576
- } catch (error51) {
124577
- logger.error("Failed to reindex file", error51, {
124578
- file: relativeFilePath
124579
- });
124580
- errors4++;
124581
- }
124582
- }
124583
- await deps.indexManager.updateIndexMetadata(projectId, projectPath, filesToReindex);
124584
- await deps.searchCache.invalidateProject(projectId);
124683
+ const { filesIndexed, chunksIndexed, errors: errors4 } = await runIncrementalReindex(deps, projectId, projectPath, filesToReindex);
124585
124684
  logger.info("Incremental reindex completed", {
124586
124685
  projectId,
124587
124686
  filesIndexed,
@@ -124630,7 +124729,7 @@ async function checkSearchAdmission(deps, projectId, projectPath) {
124630
124729
  async function indexFile(deps, filePath, projectId, projectRoot, centralityMap) {
124631
124730
  projectId = await getProjectIdentityAliasResolver().resolve(projectId);
124632
124731
  const content = await fs15.readFile(filePath, "utf-8");
124633
- const relativePath = path21.relative(projectRoot, filePath);
124732
+ const relativePath = path22.relative(projectRoot, filePath);
124634
124733
  const maxFileSize = config2.get("security").maxFileSize || 1024 * 1024;
124635
124734
  if (content.length > maxFileSize) {
124636
124735
  logger.warn("File too large, skipping", {
@@ -124650,7 +124749,7 @@ async function indexFile(deps, filePath, projectId, projectRoot, centralityMap)
124650
124749
  chunkIndex: i,
124651
124750
  totalChunks: chunks.length,
124652
124751
  type: chunk.type,
124653
- language: path21.extname(filePath).slice(1),
124752
+ language: path22.extname(filePath).slice(1),
124654
124753
  lineStart: chunk.lineStart,
124655
124754
  lineEnd: chunk.lineEnd,
124656
124755
  label: chunk.label,
@@ -124675,6 +124774,7 @@ var init_project_indexer = __esm(() => {
124675
124774
  init_managed_run_repository_pg();
124676
124775
  init_symbol_repo_workspace();
124677
124776
  init_embedding_freshness();
124777
+ init_incremental_reindex();
124678
124778
  globAsync2 = glob;
124679
124779
  });
124680
124780
 
@@ -126494,7 +126594,7 @@ var init_index_job_store = __esm(() => {
126494
126594
  });
126495
126595
 
126496
126596
  // ../../packages/core/dist/services/jobs/index-job-tracker.js
126497
- import { randomUUID as randomUUID4 } from "crypto";
126597
+ import { randomUUID as randomUUID5 } from "crypto";
126498
126598
 
126499
126599
  class IndexJobTracker {
126500
126600
  static instance;
@@ -126518,7 +126618,7 @@ class IndexJobTracker {
126518
126618
  return IndexJobTracker.instance;
126519
126619
  }
126520
126620
  createJob(projectId, projectPath) {
126521
- const jobId = randomUUID4();
126621
+ const jobId = randomUUID5();
126522
126622
  const job = {
126523
126623
  jobId,
126524
126624
  projectId,
@@ -126608,7 +126708,9 @@ class IndexJobTracker {
126608
126708
  const cutoff = now2 - staleMs;
126609
126709
  let reaped = 0;
126610
126710
  for (const job of running) {
126611
- const hbMs = job.heartbeatAt?.getTime();
126711
+ const live = this.jobs.get(job.jobId);
126712
+ const liveHb = live?.heartbeatAt?.getTime();
126713
+ const hbMs = liveHb ?? job.heartbeatAt?.getTime();
126612
126714
  const startedMs = job.startedAt?.getTime();
126613
126715
  const stale = hbMs != null && hbMs < cutoff || hbMs == null && startedMs != null && startedMs < cutoff;
126614
126716
  if (!stale)
@@ -126722,7 +126824,7 @@ function stripNul(content) {
126722
126824
 
126723
126825
  // ../../packages/core/dist/services/etl/stages/discover.js
126724
126826
  import fs16 from "fs/promises";
126725
- import path22 from "path";
126827
+ import path23 from "path";
126726
126828
  import { createHash as createHash5 } from "crypto";
126727
126829
 
126728
126830
  class DiscoverStage {
@@ -126748,7 +126850,7 @@ class DiscoverStage {
126748
126850
  dot: false,
126749
126851
  absolute: false
126750
126852
  });
126751
- relPaths = found.map((p) => path22.isAbsolute(p) ? path22.relative(ctx.projectPath, p) : p).filter((p) => !ig.ignores(p) && applyPolicy(p, policy) !== "Drop");
126853
+ relPaths = found.map((p) => path23.isAbsolute(p) ? path23.relative(ctx.projectPath, p) : p).filter((p) => !ig.ignores(p) && applyPolicy(p, policy) !== "Drop");
126752
126854
  }
126753
126855
  if (ctx.resumeCursor?.path) {
126754
126856
  const cursorPath = ctx.resumeCursor.path;
@@ -126807,7 +126909,7 @@ class DiscoverStage {
126807
126909
  return discovered;
126808
126910
  }
126809
126911
  async processFile(ctx, relativePath, forceReindex) {
126810
- const absolutePath = path22.join(ctx.projectPath, relativePath);
126912
+ const absolutePath = path23.join(ctx.projectPath, relativePath);
126811
126913
  try {
126812
126914
  const stat = await fs16.stat(absolutePath);
126813
126915
  const content = stripNul(await fs16.readFile(absolutePath, "utf-8"));
@@ -126854,7 +126956,7 @@ class DiscoverStage {
126854
126956
  ig.add(pattern);
126855
126957
  }
126856
126958
  try {
126857
- const gitignorePath = path22.join(projectPath, ".gitignore");
126959
+ const gitignorePath = path23.join(projectPath, ".gitignore");
126858
126960
  const gitignoreContent = await fs16.readFile(gitignorePath, "utf8");
126859
126961
  const rules = gitignoreContent.split(`
126860
126962
  `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
@@ -128210,8 +128312,8 @@ function rustUseLeaves(node, source, prefix = []) {
128210
128312
  }
128211
128313
  if (node.type === "use_wildcard")
128212
128314
  return [{ path: [...prefix, "*"], glob: true }];
128213
- const path23 = rustPathSegments(node, source);
128214
- return path23.length ? [{ path: [...prefix, ...path23] }] : [];
128315
+ const path24 = rustPathSegments(node, source);
128316
+ return path24.length ? [{ path: [...prefix, ...path24] }] : [];
128215
128317
  }
128216
128318
  function functionalCaptures(captures, source, family) {
128217
128319
  if (family !== "clojure")
@@ -129183,7 +129285,7 @@ var init_structural_runtime = __esm(() => {
129183
129285
  });
129184
129286
 
129185
129287
  // ../../packages/core/dist/services/etl/stages/parse.js
129186
- import path23 from "path";
129288
+ import path24 from "path";
129187
129289
  import fs17 from "fs/promises";
129188
129290
  function resolveChunkerMaxChars() {
129189
129291
  const global2 = Number(process.env.EMBEDDING_MAX_CHARS);
@@ -129212,8 +129314,8 @@ class ParseStage {
129212
129314
  const results = new Map;
129213
129315
  let processed = 0;
129214
129316
  const phases = [
129215
- files.filter((file2) => path23.extname(file2.relativePath).toLowerCase() !== ".h"),
129216
- files.filter((file2) => path23.extname(file2.relativePath).toLowerCase() === ".h")
129317
+ files.filter((file2) => path24.extname(file2.relativePath).toLowerCase() !== ".h"),
129318
+ files.filter((file2) => path24.extname(file2.relativePath).toLowerCase() === ".h")
129217
129319
  ];
129218
129320
  const batches = phases.flatMap((phase) => Array.from({ length: Math.ceil(phase.length / BATCH_SIZE) }, (_, index) => phase.slice(index * BATCH_SIZE, (index + 1) * BATCH_SIZE)));
129219
129321
  for (const batch of batches) {
@@ -129251,19 +129353,19 @@ class ParseStage {
129251
129353
  return files.map((file2) => results.get(file2.relativePath));
129252
129354
  }
129253
129355
  recordHeaderImporterEvidence(ctx, files, parsedFiles) {
129254
- const knownHeaders = new Set(files.filter((file2) => path23.extname(file2.relativePath).toLowerCase() === ".h").map((file2) => path23.posix.normalize(file2.relativePath)));
129356
+ const knownHeaders = new Set(files.filter((file2) => path24.extname(file2.relativePath).toLowerCase() === ".h").map((file2) => path24.posix.normalize(file2.relativePath)));
129255
129357
  const mutable = {
129256
129358
  ...ctx.structuralHeaderEvidenceByFile
129257
129359
  };
129258
129360
  for (const parsed of parsedFiles) {
129259
- const extension = path23.extname(parsed.file.relativePath).toLowerCase();
129361
+ const extension = path24.extname(parsed.file.relativePath).toLowerCase();
129260
129362
  const key = extension === ".c" ? "cImporters" : [".cpp", ".hpp"].includes(extension) ? "cppImporters" : undefined;
129261
129363
  if (!key)
129262
129364
  continue;
129263
129365
  for (const imported of parsed.rawImports) {
129264
129366
  if (!["c_include", "cpp_include"].includes(imported.form) || imported.specifier.startsWith("<"))
129265
129367
  continue;
129266
- const header = path23.posix.normalize(path23.posix.join(path23.posix.dirname(parsed.file.relativePath), imported.specifier));
129368
+ const header = path24.posix.normalize(path24.posix.join(path24.posix.dirname(parsed.file.relativePath), imported.specifier));
129267
129369
  if (!knownHeaders.has(header))
129268
129370
  continue;
129269
129371
  const existing = mutable[header] ?? {};
@@ -129274,7 +129376,7 @@ class ParseStage {
129274
129376
  }
129275
129377
  async parseFile(ctx, file2) {
129276
129378
  if (!file2.needsReparse) {
129277
- const extension = path23.extname(file2.relativePath).toLowerCase();
129379
+ const extension = path24.extname(file2.relativePath).toLowerCase();
129278
129380
  if ([".c", ".cpp", ".hpp"].includes(extension)) {
129279
129381
  const content = file2.snapshotContent ?? await fs17.readFile(file2.absolutePath, "utf8");
129280
129382
  const outcome = await this.runtime.parse({ extension, source: Buffer.from(content) });
@@ -129289,7 +129391,7 @@ class ParseStage {
129289
129391
  }
129290
129392
  try {
129291
129393
  const content = file2.snapshotContent ?? await fs17.readFile(file2.absolutePath, "utf-8");
129292
- const ext2 = path23.extname(file2.relativePath).toLowerCase();
129394
+ const ext2 = path24.extname(file2.relativePath).toLowerCase();
129293
129395
  const chunkerMaxChars = resolveChunkerMaxChars();
129294
129396
  const chunks = smartChunk(content, file2.relativePath, chunkerMaxChars ? { maxChunkChars: chunkerMaxChars } : {});
129295
129397
  let symbols;
@@ -129844,7 +129946,7 @@ var init_resolver = __esm(() => {
129844
129946
  });
129845
129947
 
129846
129948
  // ../../packages/core/dist/services/structural/resolvers/typescript.js
129847
- import path24 from "path";
129949
+ import path25 from "path";
129848
129950
  function candidates(identities) {
129849
129951
  return Object.freeze(identities.map((identity) => Object.freeze({
129850
129952
  fqn: identity.fqn,
@@ -129939,7 +130041,7 @@ function probe(base, known, dialect = "typescript") {
129939
130041
  const bases = /\.[cm]?jsx?$/u.test(base) ? [base.replace(/\.[cm]?jsx?$/u, ".ts"), base.replace(/\.[cm]?jsx?$/u, ".tsx"), base] : [base];
129940
130042
  for (const candidateBase of bases)
129941
130043
  for (const suffix of DIALECT_PROBES[dialect] ?? [""]) {
129942
- const value = path24.posix.normalize(`${candidateBase}${suffix}`);
130044
+ const value = path25.posix.normalize(`${candidateBase}${suffix}`);
129943
130045
  if (!value.startsWith("../") && value !== ".." && known.has(value))
129944
130046
  return value;
129945
130047
  }
@@ -129948,7 +130050,7 @@ function probe(base, known, dialect = "typescript") {
129948
130050
  function resolveStructuralSpecifier(specifier, fromFile, build, dialect = "typescript") {
129949
130051
  const known = new Set(build.knownFiles.map(normalizeStructuralFile));
129950
130052
  if (specifier.startsWith("./") || specifier.startsWith("../")) {
129951
- return probe(path24.posix.join(path24.posix.dirname(fromFile), specifier), known, dialect);
130053
+ return probe(path25.posix.join(path25.posix.dirname(fromFile), specifier), known, dialect);
129952
130054
  }
129953
130055
  const aliases = build.pathAliasesByFile?.[normalizeStructuralFile(fromFile)] ?? build.pathAliases ?? [];
129954
130056
  for (const alias of aliases) {
@@ -130212,7 +130314,7 @@ var init_scripting2 = __esm(() => {
130212
130314
  });
130213
130315
 
130214
130316
  // ../../packages/core/dist/services/structural/resolvers/systems.js
130215
- import path25 from "path";
130317
+ import path26 from "path";
130216
130318
  var DIALECTS, SYSTEMS_LANGUAGE_RESOLVER;
130217
130319
  var init_systems2 = __esm(() => {
130218
130320
  init_typescript2();
@@ -130231,7 +130333,7 @@ var init_systems2 = __esm(() => {
130231
130333
  const bindings = item.bindings.map((binding) => binding.imported === "*" && binding.local === "*" && unresolvedTarget && !unresolvedTarget.qualifier ? { ...binding, imported: unresolvedTarget.name, local: unresolvedTarget.name } : binding);
130232
130334
  if (item.specifier === "crate" || item.specifier.startsWith("crate/")) {
130233
130335
  const crateRoot = file2.file.startsWith("src/") ? "src" : "";
130234
- return { ...item, bindings, specifier: `./${path25.posix.relative(path25.posix.dirname(file2.file), path25.posix.join(crateRoot, item.specifier.replace(/^crate\/?/u, "")))}` };
130336
+ return { ...item, bindings, specifier: `./${path26.posix.relative(path26.posix.dirname(file2.file), path26.posix.join(crateRoot, item.specifier.replace(/^crate\/?/u, "")))}` };
130235
130337
  }
130236
130338
  if (item.specifier === "self" || item.specifier.startsWith("self/"))
130237
130339
  return { ...item, bindings, specifier: `./${item.specifier.replace(/^self\/?/u, "")}` };
@@ -130329,7 +130431,7 @@ var init_data_document2 = __esm(() => {
130329
130431
  });
130330
130432
 
130331
130433
  // ../../packages/core/dist/services/etl/stages/resolve.js
130332
- import path26 from "path";
130434
+ import path27 from "path";
130333
130435
  import fs18 from "fs";
130334
130436
 
130335
130437
  class ResolveStage {
@@ -130354,7 +130456,7 @@ class ResolveStage {
130354
130456
  const structuralDocuments = files.flatMap((file2) => {
130355
130457
  if (!file2.structure)
130356
130458
  return [];
130357
- const language = resolveStructuralLanguage(path26.extname(file2.file.relativePath));
130459
+ const language = resolveStructuralLanguage(path27.extname(file2.file.relativePath));
130358
130460
  if (language.status !== "supported")
130359
130461
  throw new Error(`structural_manifest_missing:${file2.file.relativePath}`);
130360
130462
  return [{
@@ -130366,13 +130468,13 @@ class ResolveStage {
130366
130468
  }];
130367
130469
  });
130368
130470
  const currentStructuralFiles = new Set(structuralDocuments.map((document2) => document2.file));
130369
- const skippedStructuralFiles = new Set(files.filter((item) => !item.file.needsReparse && STRUCTURAL_SEED_EXTENSIONS.has(path26.extname(item.file.relativePath).toLowerCase())).map((item) => item.file.relativePath));
130471
+ const skippedStructuralFiles = new Set(files.filter((item) => !item.file.needsReparse && STRUCTURAL_SEED_EXTENSIONS.has(path27.extname(item.file.relativePath).toLowerCase())).map((item) => item.file.relativePath));
130370
130472
  const pathAliasesByFile = Object.fromEntries([...knownRelPaths].map((file2) => [
130371
130473
  file2,
130372
130474
  this.structuralAliasesFor(file2, rootAliases, monorepoPackages)
130373
130475
  ]));
130374
130476
  const buildMetadata = { knownFiles: [...knownRelPaths], pathAliasesByFile };
130375
- const seedRows = repositoryDefinitions.filter((definition) => STRUCTURAL_SEED_EXTENSIONS.has(path26.extname(definition.file_path).toLowerCase())).filter((definition) => knownRelPaths.has(definition.file_path) && skippedStructuralFiles.has(definition.file_path)).filter((definition) => !currentStructuralFiles.has(definition.file_path));
130477
+ const seedRows = repositoryDefinitions.filter((definition) => STRUCTURAL_SEED_EXTENSIONS.has(path27.extname(definition.file_path).toLowerCase())).filter((definition) => knownRelPaths.has(definition.file_path) && skippedStructuralFiles.has(definition.file_path)).filter((definition) => !currentStructuralFiles.has(definition.file_path));
130376
130478
  const seedIds = new Set;
130377
130479
  for (const definition of seedRows) {
130378
130480
  if (seedIds.has(definition.id))
@@ -130469,7 +130571,7 @@ class ResolveStage {
130469
130571
  if (parsed.file !== definition.file_path) {
130470
130572
  throw new Error(`structural_repository_seed_file_mismatch:${definition.id}`);
130471
130573
  }
130472
- const language = resolveStructuralLanguage(path26.extname(definition.file_path));
130574
+ const language = resolveStructuralLanguage(path27.extname(definition.file_path));
130473
130575
  if (language.status !== "supported")
130474
130576
  throw new Error(`structural_repository_seed_language:${definition.id}`);
130475
130577
  let identity;
@@ -130521,7 +130623,7 @@ class ResolveStage {
130521
130623
  });
130522
130624
  }
130523
130625
  resolveFile(parsed, projectPath, knownRelPaths, rootAliases, monorepoPackages, symbolIndex, knownFqns) {
130524
- const fromDir = path26.dirname(path26.join(projectPath, parsed.file.relativePath));
130626
+ const fromDir = path27.dirname(path27.join(projectPath, parsed.file.relativePath));
130525
130627
  const packageAliases = this.getPackageAliases(parsed.file.relativePath, monorepoPackages);
130526
130628
  const allAliases = [...packageAliases, ...rootAliases];
130527
130629
  const resolvedImports = parsed.rawImports.map((raw2) => {
@@ -130592,7 +130694,7 @@ class ResolveStage {
130592
130694
  index.set(def.name, `${def.file_path}#${def.name}`);
130593
130695
  }
130594
130696
  } catch (err) {
130595
- const skippedStructural = files.some((file2) => !file2.file.needsReparse && STRUCTURAL_SEED_EXTENSIONS.has(path26.extname(file2.file.relativePath).toLowerCase()));
130697
+ const skippedStructural = files.some((file2) => !file2.file.needsReparse && STRUCTURAL_SEED_EXTENSIONS.has(path27.extname(file2.file.relativePath).toLowerCase()));
130596
130698
  if (skippedStructural)
130597
130699
  throw new Error("structural_repository_seed_failed", { cause: err });
130598
130700
  logger.warn("buildSymbolIndex: repo seed failed, in-batch only", {
@@ -130616,7 +130718,7 @@ class ResolveStage {
130616
130718
  }
130617
130719
  resolveSpecifier(specifier, fromDir, projectPath, knownRelPaths, aliases) {
130618
130720
  if (specifier.startsWith("./") || specifier.startsWith("../")) {
130619
- const resolved = this.probeExtensions(path26.resolve(fromDir, specifier), projectPath, knownRelPaths);
130721
+ const resolved = this.probeExtensions(path27.resolve(fromDir, specifier), projectPath, knownRelPaths);
130620
130722
  return { resolvedPath: resolved, external: false };
130621
130723
  }
130622
130724
  for (const alias of aliases) {
@@ -130624,8 +130726,8 @@ class ResolveStage {
130624
130726
  const suffix = specifier.slice(alias.prefix.length);
130625
130727
  for (const target of alias.targets) {
130626
130728
  const cleanTarget = target.replace(/\/\*$/, "");
130627
- const basePath = alias.packagePath ? path26.join(projectPath, alias.packagePath) : projectPath;
130628
- const absPath = path26.join(basePath, cleanTarget + suffix);
130729
+ const basePath = alias.packagePath ? path27.join(projectPath, alias.packagePath) : projectPath;
130730
+ const absPath = path27.join(basePath, cleanTarget + suffix);
130629
130731
  const resolved = this.probeExtensions(absPath, projectPath, knownRelPaths);
130630
130732
  if (resolved)
130631
130733
  return { resolvedPath: resolved, external: false };
@@ -130641,7 +130743,7 @@ class ResolveStage {
130641
130743
  ...TS_EXTENSIONS.map((ext2) => absPath.replace(/\.[^.]+$/, ext2))
130642
130744
  ];
130643
130745
  for (const candidate2 of candidates2) {
130644
- const rel = path26.relative(projectPath, candidate2).replace(/\\/g, "/");
130746
+ const rel = path27.relative(projectPath, candidate2).replace(/\\/g, "/");
130645
130747
  if (knownRelPaths.has(rel))
130646
130748
  return rel;
130647
130749
  }
@@ -130649,7 +130751,7 @@ class ResolveStage {
130649
130751
  }
130650
130752
  loadTsConfigPaths(projectPath, packageBase) {
130651
130753
  const aliases = [];
130652
- const tsconfigPath = path26.join(projectPath, "tsconfig.json");
130754
+ const tsconfigPath = path27.join(projectPath, "tsconfig.json");
130653
130755
  try {
130654
130756
  const raw2 = fs18.readFileSync(tsconfigPath, "utf-8");
130655
130757
  const stripped = raw2.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
@@ -130680,7 +130782,7 @@ class ResolveStage {
130680
130782
  }
130681
130783
  }
130682
130784
  for (const packageRelPath of packagePaths) {
130683
- const absPackagePath = path26.join(projectPath, packageRelPath);
130785
+ const absPackagePath = path27.join(projectPath, packageRelPath);
130684
130786
  const aliases = this.loadTsConfigPaths(absPackagePath, packageRelPath);
130685
130787
  if (aliases.length > 0) {
130686
130788
  packages.push({
@@ -130710,7 +130812,7 @@ class ResolveStage {
130710
130812
  structuralAliasesFor(filePath, rootAliases, packages) {
130711
130813
  return [...this.getPackageAliases(filePath, packages), ...rootAliases].map((alias) => ({
130712
130814
  pattern: alias.prefix + (alias.targets.some((target) => target.includes("*")) ? "/*" : ""),
130713
- targets: alias.targets.map((target) => alias.packagePath ? path26.posix.join(alias.packagePath, target) : target)
130815
+ targets: alias.targets.map((target) => alias.packagePath ? path27.posix.join(alias.packagePath, target) : target)
130714
130816
  }));
130715
130817
  }
130716
130818
  }
@@ -130774,7 +130876,7 @@ var init_with_deadlock_retry = __esm(() => {
130774
130876
  });
130775
130877
 
130776
130878
  // ../../packages/core/dist/services/etl/stages/load.js
130777
- import path27 from "path";
130879
+ import path28 from "path";
130778
130880
  function formatDuration(ms) {
130779
130881
  const totalSec = Math.max(0, Math.round(ms / 1000));
130780
130882
  if (totalSec < 60)
@@ -131051,7 +131153,7 @@ class LoadStage {
131051
131153
  const filePath = file2.file.relativePath;
131052
131154
  const batch = buildSymbolPersistenceBatch(ctx.projectId, file2);
131053
131155
  if (ctx.graphGenerationLease) {
131054
- const manifest = getLanguageManifestEntry(path27.extname(filePath));
131156
+ const manifest = getLanguageManifestEntry(path28.extname(filePath));
131055
131157
  const diagnostics2 = (file2.structuralDiagnostics ?? []).slice(0, 10).map((diagnostic2) => ({
131056
131158
  code: diagnostic2.code,
131057
131159
  severity: diagnostic2.severity,
@@ -131103,7 +131205,7 @@ var init_load = __esm(() => {
131103
131205
  });
131104
131206
 
131105
131207
  // ../../packages/core/dist/data/graph-generation/graph-generation-repository-pg.js
131106
- import { randomUUID as randomUUID5 } from "crypto";
131208
+ import { randomUUID as randomUUID6 } from "crypto";
131107
131209
  function boundedText2(value, label, max = 512) {
131108
131210
  const normalized = value.normalize("NFC").trim();
131109
131211
  if (!normalized || normalized.length > max || normalized.includes("\x00")) {
@@ -131207,8 +131309,8 @@ class GraphGenerationRepositoryPg {
131207
131309
  }
131208
131310
  async begin(rawInput) {
131209
131311
  const input = validateBegin2(rawInput);
131210
- const generationId = randomUUID5();
131211
- const leaseToken = randomUUID5();
131312
+ const generationId = randomUUID6();
131313
+ const leaseToken = randomUUID6();
131212
131314
  return getPrismaClient2().$transaction(async (tx) => {
131213
131315
  const workspace = await lockWorkspace(tx, input.projectId);
131214
131316
  if (workspace.active_graph_generation_id !== input.expectedActiveGenerationId) {
@@ -131448,8 +131550,8 @@ function buildGraphInputSnapshotHash(files) {
131448
131550
 
131449
131551
  class GraphGenerationCoordinator {
131450
131552
  repository;
131451
- constructor(repository = getGraphGenerationRepository()) {
131452
- this.repository = repository;
131553
+ constructor(repository2 = getGraphGenerationRepository()) {
131554
+ this.repository = repository2;
131453
131555
  }
131454
131556
  async begin(input) {
131455
131557
  const deadline = Date.now() + GRAPH_GENERATION_LEASE_TTL_MS;
@@ -131505,609 +131607,6 @@ var init_graph_generation_coordinator = __esm(() => {
131505
131607
  init_with_deadlock_retry();
131506
131608
  });
131507
131609
 
131508
- // ../../packages/core/dist/services/etl/pipeline.js
131509
- import { createHash as createHash7 } from "crypto";
131510
- import { setTimeout as delay2 } from "timers/promises";
131511
- import path28 from "path";
131512
- function buildHeaderLanguageEvidence(files) {
131513
- const headers = new Set(files.filter((file2) => path28.posix.extname(file2.relativePath).toLowerCase() === ".h").map((file2) => path28.posix.normalize(file2.relativePath)));
131514
- const mutable = new Map;
131515
- const entry2 = (header) => {
131516
- let value = mutable.get(header);
131517
- if (!value) {
131518
- value = { cImporters: new Set, cppImporters: new Set, build: new Set };
131519
- mutable.set(header, value);
131520
- }
131521
- return value;
131522
- };
131523
- for (const file2 of files) {
131524
- if (path28.posix.basename(file2.relativePath) !== "compile_commands.json" || file2.snapshotContent === undefined)
131525
- continue;
131526
- let commands;
131527
- try {
131528
- commands = JSON.parse(file2.snapshotContent);
131529
- } catch {
131530
- continue;
131531
- }
131532
- if (!Array.isArray(commands))
131533
- continue;
131534
- for (const command of commands) {
131535
- if (!command || typeof command !== "object")
131536
- continue;
131537
- const record3 = command;
131538
- if (typeof record3.file !== "string")
131539
- continue;
131540
- const projectRoot = path28.resolve(file2.absolutePath, ...file2.relativePath.split("/").map(() => ".."));
131541
- const commandDirectory = typeof record3.directory === "string" ? path28.resolve(projectRoot, record3.directory) : projectRoot;
131542
- const absoluteInput = path28.resolve(commandDirectory, record3.file);
131543
- const relative2 = path28.relative(projectRoot, absoluteInput);
131544
- const header = path28.posix.normalize(relative2.replaceAll(path28.sep, "/"));
131545
- if (!headers.has(header))
131546
- continue;
131547
- const invocation = typeof record3.command === "string" ? record3.command : Array.isArray(record3.arguments) ? record3.arguments.join(" ") : "";
131548
- if (/(?:^|\s)(?:clang\+\+|g\+\+|c\+\+)(?:\s|$)|(?:^|\s)-x\s*c\+\+(?:\s|$)/u.test(invocation))
131549
- entry2(header).build.add("cpp");
131550
- else if (/(?:^|\s)(?:clang|gcc|cc)(?:\s|$)|(?:^|\s)-x\s*c(?:\s|$)/u.test(invocation))
131551
- entry2(header).build.add("c");
131552
- }
131553
- }
131554
- return Object.freeze(Object.fromEntries([...mutable.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([header, value]) => [header, Object.freeze({
131555
- ...value.cImporters.size ? { cImporters: Object.freeze([...value.cImporters].sort()) } : {},
131556
- ...value.cppImporters.size ? { cppImporters: Object.freeze([...value.cppImporters].sort()) } : {},
131557
- ...value.build.size ? { buildLanguage: value.build.size > 1 ? "conflict" : [...value.build][0] } : {}
131558
- })])));
131559
- }
131560
- function abortable(operation, signal) {
131561
- if (signal.aborted)
131562
- return Promise.reject(signal.reason);
131563
- return new Promise((resolve5, reject) => {
131564
- let abortReason;
131565
- const onAbort = () => {
131566
- abortReason = signal.reason;
131567
- };
131568
- signal.addEventListener("abort", onAbort, { once: true });
131569
- operation.then((value) => abortReason === undefined ? resolve5(value) : reject(abortReason), (error51) => reject(abortReason ?? error51)).finally(() => signal.removeEventListener("abort", onAbort));
131570
- });
131571
- }
131572
- var EtlPipeline;
131573
- var init_pipeline = __esm(() => {
131574
- init_dist();
131575
- init_discover();
131576
- init_parse3();
131577
- init_resolve();
131578
- init_load();
131579
- init_event_bus();
131580
- init_symbol_repository_factory();
131581
- init_index_job_tracker();
131582
- init_cache_factory();
131583
- init_index_manager();
131584
- init_vector_store_factory();
131585
- init_keyword_search_factory();
131586
- init_alias_resolver();
131587
- init_symbol_repo_workspace();
131588
- init_project_indexer();
131589
- init_parser_readiness();
131590
- init_parse3();
131591
- init_language_manifest();
131592
- init_graph_generation_coordinator();
131593
- init_managed_run_repository_pg();
131594
- EtlPipeline = class EtlPipeline {
131595
- static instance = null;
131596
- static runTails = new Map;
131597
- discover = new DiscoverStage;
131598
- parse = new ParseStage;
131599
- resolve = new ResolveStage;
131600
- load = new LoadStage;
131601
- graphGenerations = new GraphGenerationCoordinator;
131602
- constructor() {}
131603
- static getInstance() {
131604
- if (!EtlPipeline.instance) {
131605
- EtlPipeline.instance = new EtlPipeline;
131606
- }
131607
- return EtlPipeline.instance;
131608
- }
131609
- async run(input) {
131610
- await assertParserReadyForIndexing();
131611
- const projectId = await getProjectIdentityAliasResolver().resolve(input.projectId);
131612
- const canonicalInput = projectId === input.projectId ? input : { ...input, projectId };
131613
- const previous = EtlPipeline.runTails.get(projectId);
131614
- let release;
131615
- const tail = new Promise((resolve5) => {
131616
- release = resolve5;
131617
- });
131618
- EtlPipeline.runTails.set(projectId, tail);
131619
- if (previous) {
131620
- logger.info("EtlPipeline: waiting for prior project run", {
131621
- projectId,
131622
- jobId: input.jobId
131623
- });
131624
- await previous;
131625
- }
131626
- try {
131627
- return await this.runInternal(canonicalInput);
131628
- } finally {
131629
- if (EtlPipeline.runTails.get(projectId) === tail) {
131630
- EtlPipeline.runTails.delete(projectId);
131631
- }
131632
- release();
131633
- }
131634
- }
131635
- async runInternal(input, generationRetry = 0) {
131636
- const projectId = await getProjectIdentityAliasResolver().resolve(input.projectId);
131637
- const { projectPath, jobId, forceReindex = false, filesToProcess, include_tests = false, managedRunLease } = input;
131638
- const t0 = performance.now();
131639
- const stageTimings = {
131640
- discover: 0,
131641
- parse: 0,
131642
- resolve: 0,
131643
- load: 0
131644
- };
131645
- if (forceReindex) {
131646
- const vectorStore = await getVectorStore();
131647
- const keywordSearch = getKeywordSearch();
131648
- await Promise.all([
131649
- vectorStore.deleteByProject(projectId),
131650
- keywordSearch.deleteByProject(projectId)
131651
- ]);
131652
- }
131653
- const managedRunRepository = managedRunLease ? ManagedRunRepositoryPg.getInstance() : undefined;
131654
- const ctx = {
131655
- projectId,
131656
- projectPath,
131657
- jobId,
131658
- resumeCursor: managedRunLease ? (await managedRunRepository?.getActive(projectId, "indexing"))?.fileCursor ?? undefined : undefined,
131659
- managedRunLease,
131660
- emit: (event) => {
131661
- if (event.type === "progress") {
131662
- const p = event.payload;
131663
- indexJobTracker.updateProgress(jobId, p.current, p.total);
131664
- eventBus.publish("indexing:progress", {
131665
- jobId,
131666
- projectId,
131667
- stage: event.stage,
131668
- current: p.current,
131669
- total: p.total,
131670
- percentage: p.percentage
131671
- });
131672
- } else if (event.type === "file_error") {
131673
- const p = event.payload;
131674
- eventBus.publish("indexing:file", {
131675
- jobId,
131676
- projectId,
131677
- filePath: p.filePath,
131678
- stage: event.stage,
131679
- status: "error",
131680
- error: p.error
131681
- });
131682
- } else if (event.type === "file_processed") {
131683
- const p = event.payload;
131684
- eventBus.publish("indexing:file", {
131685
- jobId,
131686
- projectId,
131687
- filePath: p.filePath,
131688
- stage: event.stage,
131689
- status: "ok"
131690
- });
131691
- }
131692
- }
131693
- };
131694
- eventBus.publish("indexing:started", { jobId, projectId, projectPath });
131695
- let graphGenerationLease;
131696
- let graphHeartbeat;
131697
- let graphHeartbeatFailure;
131698
- const graphAbortController = new AbortController;
131699
- const heartbeatTimerController = new AbortController;
131700
- let stopGraphHeartbeat = false;
131701
- let managedRunHeartbeat;
131702
- let managedRunLeaseLost;
131703
- let stopManagedRunHeartbeat = false;
131704
- const managedRunTimerController = new AbortController;
131705
- if (managedRunLease && managedRunRepository) {
131706
- managedRunHeartbeat = (async () => {
131707
- while (!stopManagedRunHeartbeat) {
131708
- try {
131709
- await delay2(30000, undefined, { signal: managedRunTimerController.signal });
131710
- } catch {
131711
- return;
131712
- }
131713
- if (stopManagedRunHeartbeat || !managedRunLease)
131714
- return;
131715
- try {
131716
- const outcome2 = await managedRunRepository.heartbeat(managedRunLease);
131717
- if (outcome2.status === "lease_lost") {
131718
- managedRunLeaseLost = new Error("managed_run_lease_lost");
131719
- graphAbortController.abort(managedRunLeaseLost);
131720
- return;
131721
- }
131722
- } catch (heartbeatError) {
131723
- managedRunLeaseLost = heartbeatError;
131724
- graphAbortController.abort(managedRunLeaseLost);
131725
- return;
131726
- }
131727
- }
131728
- })();
131729
- }
131730
- try {
131731
- const st1 = performance.now();
131732
- const discoveredSnapshot = await this.discover.run(ctx, { forceReindex, includeTests: include_tests });
131733
- ctx.structuralHeaderEvidenceByFile = buildHeaderLanguageEvidence(discoveredSnapshot);
131734
- stageTimings.discover = Math.round(performance.now() - st1);
131735
- const activeGraph = await getSymbolRepository().getActiveGraphSnapshot(projectId);
131736
- try {
131737
- graphGenerationLease = await this.graphGenerations.begin({
131738
- projectId,
131739
- expectedActiveGenerationId: activeGraph?.generationId ?? null,
131740
- fingerprint: `sha256:${createHash7("sha256").update(JSON.stringify(STRUCTURAL_FINGERPRINT_INPUTS)).digest("hex")}`,
131741
- inputSnapshotHash: buildGraphInputSnapshotHash(discoveredSnapshot),
131742
- expectedFilesCount: discoveredSnapshot.length
131743
- });
131744
- } catch (beginError) {
131745
- if (beginError.message.startsWith("graph_generation_stale_active:") && generationRetry < 3) {
131746
- stopManagedRunHeartbeat = true;
131747
- managedRunTimerController.abort();
131748
- if (managedRunHeartbeat)
131749
- await managedRunHeartbeat;
131750
- return this.runInternal(input, generationRetry + 1);
131751
- }
131752
- throw beginError;
131753
- }
131754
- ctx.graphGenerationLease = graphGenerationLease;
131755
- ctx.abortSignal = graphAbortController.signal;
131756
- graphHeartbeat = (async () => {
131757
- while (!stopGraphHeartbeat) {
131758
- try {
131759
- await delay2(30000, undefined, { signal: heartbeatTimerController.signal });
131760
- } catch {
131761
- return;
131762
- }
131763
- if (stopGraphHeartbeat || !graphGenerationLease)
131764
- return;
131765
- try {
131766
- await this.graphGenerations.heartbeat(graphGenerationLease);
131767
- } catch (heartbeatError) {
131768
- graphHeartbeatFailure = heartbeatError;
131769
- graphAbortController.abort(graphHeartbeatFailure);
131770
- return;
131771
- }
131772
- }
131773
- })();
131774
- const requestedPaths = new Set(filesToProcess ?? []);
131775
- const preparedFiles = discoveredSnapshot.map((file2) => ({
131776
- ...file2,
131777
- needsReparse: forceReindex || !activeGraph || file2.needsReparse || requestedPaths.has(file2.relativePath)
131778
- }));
131779
- if (activeGraph) {
131780
- for (const file2 of preparedFiles) {
131781
- if (file2.needsReparse)
131782
- continue;
131783
- const copied = await getSymbolRepository().copyFileGeneration(graphGenerationLease, activeGraph.generationId, file2.relativePath);
131784
- if (copied.status === "lease_lost")
131785
- throw new Error("graph_generation_lease_lost");
131786
- if (copied.status === "missing")
131787
- file2.needsReparse = true;
131788
- }
131789
- }
131790
- const discovered = preparedFiles.map((file2) => Object.freeze(file2));
131791
- eventBus.publish("indexing:started", {
131792
- jobId,
131793
- projectId,
131794
- projectPath,
131795
- totalFiles: discovered.filter((f) => f.needsReparse).length
131796
- });
131797
- const st2 = performance.now();
131798
- let remainingFiles = [...discovered];
131799
- let parsed = [];
131800
- const staleFailures = new Set;
131801
- while (remainingFiles.length > 0) {
131802
- try {
131803
- parsed.push(...await abortable(this.parse.run(ctx, remainingFiles), graphAbortController.signal));
131804
- break;
131805
- } catch (parseError) {
131806
- if (!activeGraph || forceReindex || !filesToProcess?.length || !(parseError instanceof StructuralEtlParseError) || staleFailures.has(parseError.filePath))
131807
- throw parseError;
131808
- staleFailures.add(parseError.filePath);
131809
- const stale = await getSymbolRepository().markFileStaleGeneration(graphGenerationLease, parseError.filePath, {
131810
- lastKnownGoodGenerationId: activeGraph.generationId,
131811
- diagnostics: parseError.diagnostics.length > 0 ? parseError.diagnostics.slice(0, 10).map((diagnostic2) => ({ ...diagnostic2 })) : [{ code: "incremental_structural_failure", message: parseError.message }],
131812
- parserErrorCount: parseError.diagnosticCount
131813
- });
131814
- if (stale.status !== "stale")
131815
- throw parseError;
131816
- remainingFiles = remainingFiles.filter((file2) => file2.relativePath !== parseError.filePath);
131817
- }
131818
- }
131819
- if (graphHeartbeatFailure)
131820
- throw graphHeartbeatFailure;
131821
- if (managedRunLeaseLost)
131822
- throw managedRunLeaseLost;
131823
- stageTimings.parse = Math.round(performance.now() - st2);
131824
- const st3 = performance.now();
131825
- const resolved = await abortable(this.resolve.run(ctx, parsed), graphAbortController.signal);
131826
- if (graphHeartbeatFailure)
131827
- throw graphHeartbeatFailure;
131828
- if (managedRunLeaseLost)
131829
- throw managedRunLeaseLost;
131830
- stageTimings.resolve = Math.round(performance.now() - st3);
131831
- const st4 = performance.now();
131832
- const loadResult = await abortable(this.load.run(ctx, resolved), graphAbortController.signal);
131833
- if (graphHeartbeatFailure)
131834
- throw graphHeartbeatFailure;
131835
- if (managedRunLeaseLost)
131836
- throw managedRunLeaseLost;
131837
- stageTimings.load = Math.round(performance.now() - st4);
131838
- if (loadResult.errors > 0) {
131839
- logger.warn("EtlPipeline: completed with file errors", {
131840
- projectId,
131841
- jobId,
131842
- errors: loadResult.errors,
131843
- fileErrors: (loadResult.fileErrors ?? []).slice(0, 10)
131844
- });
131845
- }
131846
- const activationSnapshot = await abortable(this.discover.run(ctx, { forceReindex, includeTests: include_tests }), graphAbortController.signal);
131847
- if (buildGraphInputSnapshotHash(activationSnapshot) !== graphGenerationLease.inputSnapshotHash) {
131848
- throw new Error("graph_generation_stale_snapshot");
131849
- }
131850
- if (graphHeartbeatFailure)
131851
- throw graphHeartbeatFailure;
131852
- if (managedRunLeaseLost)
131853
- throw managedRunLeaseLost;
131854
- stopGraphHeartbeat = true;
131855
- heartbeatTimerController.abort();
131856
- await graphHeartbeat;
131857
- stopManagedRunHeartbeat = true;
131858
- managedRunTimerController.abort();
131859
- if (managedRunHeartbeat)
131860
- await managedRunHeartbeat;
131861
- const activatedGraph = await this.graphGenerations.activate(graphGenerationLease);
131862
- const activeGraphSummary = await getSymbolRepository().getActiveGraphSnapshot(projectId);
131863
- if (!activeGraphSummary || activeGraphSummary.generationId !== activatedGraph.generationId) {
131864
- throw new Error("activated_graph_summary_mismatch");
131865
- }
131866
- const durationMs = Math.round(performance.now() - t0);
131867
- const result = {
131868
- filesDiscovered: discovered.length,
131869
- filesIndexed: loadResult.filesLoaded,
131870
- filesSkipped: discovered.filter((f) => !f.needsReparse).length,
131871
- chunksIndexed: loadResult.chunksLoaded,
131872
- symbolsIndexed: loadResult.symbolsLoaded,
131873
- errors: loadResult.errors,
131874
- durationMs,
131875
- stageTimings,
131876
- activatedGraphGenerationId: activatedGraph.generationId,
131877
- parserDiagnostics: {
131878
- diagnosticsCount: activeGraphSummary.diagnostics.errors,
131879
- recoveredFiles: activeGraphSummary.diagnostics.recovered,
131880
- hardFailureFiles: activeGraphSummary.diagnostics.hardFailures,
131881
- staleFiles: activeGraphSummary.diagnostics.staleFiles,
131882
- languages: activeGraphSummary.languages
131883
- }
131884
- };
131885
- await getSearchCache().invalidateProject(projectId);
131886
- try {
131887
- const admissionMarker = new IndexManager(await getVectorStore());
131888
- await admissionMarker.updateIndexMetadata(projectId, projectPath, discovered.map((file2) => file2.relativePath));
131889
- } catch (markerError) {
131890
- logger.warn("EtlPipeline: search-admission marker write failed", {
131891
- projectId,
131892
- jobId,
131893
- error: markerError
131894
- });
131895
- }
131896
- if (forceReindex) {
131897
- const liveFingerprint = currentEmbeddingFingerprint();
131898
- if (liveFingerprint !== null) {
131899
- try {
131900
- await stampEmbeddingFingerprint(projectId, liveFingerprint);
131901
- } catch (stampError) {
131902
- logger.warn("EtlPipeline: embedding fingerprint stamp failed", {
131903
- projectId,
131904
- jobId,
131905
- error: stampError
131906
- });
131907
- }
131908
- }
131909
- }
131910
- indexJobTracker.updateProgress(jobId, result.filesIndexed, result.filesIndexed);
131911
- await indexJobTracker.setResultAndFlush(jobId, {
131912
- filesIndexed: result.filesIndexed,
131913
- chunksIndexed: result.chunksIndexed,
131914
- errors: result.errors,
131915
- fileErrors: loadResult.fileErrors ?? [],
131916
- duration: durationMs,
131917
- activatedGraphGenerationId: result.activatedGraphGenerationId,
131918
- parserDiagnostics: result.parserDiagnostics
131919
- });
131920
- eventBus.publish("indexing:completed", {
131921
- jobId,
131922
- projectId,
131923
- filesIndexed: result.filesIndexed,
131924
- chunksIndexed: result.chunksIndexed,
131925
- symbolsIndexed: result.symbolsIndexed,
131926
- errors: result.errors,
131927
- durationMs,
131928
- activatedGraphGenerationId: result.activatedGraphGenerationId
131929
- });
131930
- await this.graphGenerations.cleanup(graphGenerationLease);
131931
- stopGraphHeartbeat = true;
131932
- heartbeatTimerController.abort();
131933
- await graphHeartbeat;
131934
- stopManagedRunHeartbeat = true;
131935
- managedRunTimerController.abort();
131936
- if (managedRunHeartbeat)
131937
- await managedRunHeartbeat;
131938
- if (managedRunLease && managedRunRepository) {
131939
- try {
131940
- await managedRunRepository.complete(managedRunLease);
131941
- } catch (completeError) {
131942
- logger.error("EtlPipeline: managed_runs complete failed", completeError, { projectId, jobId });
131943
- }
131944
- }
131945
- logger.info("EtlPipeline: run completed", { projectId, jobId, ...result });
131946
- return result;
131947
- } catch (err) {
131948
- const durationMs = Math.round(performance.now() - t0);
131949
- const error51 = err.message;
131950
- if (graphGenerationLease) {
131951
- try {
131952
- await this.graphGenerations.abort(graphGenerationLease, error51);
131953
- } catch (abortError) {
131954
- logger.error("EtlPipeline: pending generation abort failed", abortError, { projectId, jobId });
131955
- }
131956
- }
131957
- stopGraphHeartbeat = true;
131958
- heartbeatTimerController.abort();
131959
- graphAbortController.abort();
131960
- await graphHeartbeat;
131961
- stopManagedRunHeartbeat = true;
131962
- managedRunTimerController.abort();
131963
- if (managedRunHeartbeat)
131964
- await managedRunHeartbeat;
131965
- if (managedRunLease && managedRunRepository) {
131966
- try {
131967
- const outcome2 = await managedRunRepository.abort(managedRunLease);
131968
- if (outcome2.status === "lease_lost") {
131969
- logger.warn("EtlPipeline: managed_runs abort saw lease_lost", { projectId, jobId });
131970
- }
131971
- } catch (abortError) {
131972
- logger.error("EtlPipeline: managed_runs abort failed", abortError, { projectId, jobId });
131973
- }
131974
- }
131975
- eventBus.publish("indexing:failed", { jobId, projectId, error: error51, durationMs });
131976
- indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: durationMs }, error51);
131977
- logger.error("EtlPipeline: run failed", err, { projectId, jobId, durationMs });
131978
- throw err;
131979
- }
131980
- }
131981
- };
131982
- });
131983
-
131984
- // ../../packages/core/dist/services/indexing/execute-indexing.js
131985
- async function executeIndexing(request) {
131986
- const { jobId, projectId, projectPath, forceReindex, warmCache, warmupQueries, include_tests = false, managedRunLease, warmupCache: warmupCache2 } = request;
131987
- const startTime = Date.now();
131988
- try {
131989
- indexJobTracker.updateStatus(jobId, "running");
131990
- logger.info("Starting project indexing via ETL Pipeline", {
131991
- jobId,
131992
- projectPath,
131993
- projectId,
131994
- forceReindex,
131995
- warmCache,
131996
- include_tests
131997
- });
131998
- const etlResult = await EtlPipeline.getInstance().run({
131999
- projectId,
132000
- projectPath,
132001
- jobId,
132002
- forceReindex,
132003
- include_tests,
132004
- managedRunLease
132005
- });
132006
- const duration3 = Date.now() - startTime;
132007
- logger.info("ETL Pipeline completed", {
132008
- jobId,
132009
- projectId,
132010
- duration: duration3,
132011
- filesIndexed: etlResult.filesIndexed,
132012
- filesSkipped: etlResult.filesSkipped,
132013
- chunksIndexed: etlResult.chunksIndexed,
132014
- symbolsIndexed: etlResult.symbolsIndexed,
132015
- errors: etlResult.errors,
132016
- stageTimings: etlResult.stageTimings
132017
- });
132018
- if (warmCache) {
132019
- logger.info("Starting cache warmup", { jobId, projectId });
132020
- const warmupStats = await warmupCache2(projectId, projectPath, warmupQueries);
132021
- logger.info("Cache warmup completed", { jobId, projectId, ...warmupStats });
132022
- }
132023
- indexJobTracker.updateProgress(jobId, etlResult.filesIndexed, etlResult.filesIndexed);
132024
- await indexJobTracker.setResultAndFlush(jobId, {
132025
- filesIndexed: etlResult.filesIndexed,
132026
- chunksIndexed: etlResult.chunksIndexed,
132027
- errors: etlResult.errors,
132028
- duration: duration3,
132029
- activatedGraphGenerationId: etlResult.activatedGraphGenerationId,
132030
- parserDiagnostics: etlResult.parserDiagnostics
132031
- });
132032
- } catch (error51) {
132033
- const duration3 = Date.now() - startTime;
132034
- logger.error("Project indexing failed", error51, {
132035
- jobId,
132036
- projectPath,
132037
- projectId,
132038
- duration: duration3
132039
- });
132040
- indexJobTracker.setResult(jobId, {
132041
- filesIndexed: 0,
132042
- chunksIndexed: 0,
132043
- errors: 1,
132044
- duration: duration3
132045
- }, error51.message);
132046
- }
132047
- }
132048
- var init_execute_indexing = __esm(() => {
132049
- init_dist();
132050
- init_index_job_tracker();
132051
- init_pipeline();
132052
- });
132053
-
132054
- // ../../packages/core/dist/services/indexing/acquire-indexing-lease.js
132055
- async function acquireIndexingLease(request) {
132056
- const { jobId, projectId } = request;
132057
- const eventId = `index:${jobId}`;
132058
- const managedRunRepo = ManagedRunRepositoryPg.getInstance();
132059
- try {
132060
- const beginOutcome = await managedRunRepo.begin({
132061
- projectId,
132062
- runKind: "indexing",
132063
- eventId
132064
- });
132065
- if (beginOutcome.status === "busy") {
132066
- indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 0, duration: 0 }, `indexing_busy:${beginOutcome.activeRunId}`);
132067
- return {
132068
- status: "busy",
132069
- activeRunId: beginOutcome.activeRunId,
132070
- leaseExpiresAt: beginOutcome.leaseExpiresAt
132071
- };
132072
- }
132073
- return { status: "acquired", lease: beginOutcome.lease };
132074
- } catch (beginError) {
132075
- logger.error("managed_runs begin failed", beginError, {
132076
- jobId,
132077
- projectId
132078
- });
132079
- indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: 0 }, `managed_runs_begin_failed:${beginError.message}`);
132080
- return { status: "failed", message: beginError.message };
132081
- }
132082
- }
132083
- var init_acquire_indexing_lease = __esm(() => {
132084
- init_dist();
132085
- init_index_job_tracker();
132086
- init_managed_run_repository_pg();
132087
- });
132088
-
132089
- // ../../packages/core/dist/services/project-identity/project-root-identity.js
132090
- import { realpath as realpath2 } from "fs/promises";
132091
- import path29 from "path";
132092
- async function canonicalizeProjectRoot(projectPath, canonicalize = realpath2) {
132093
- return canonicalize(path29.resolve(projectPath));
132094
- }
132095
- async function assertProjectRootReuse(options) {
132096
- if (!options.storedProjectPath || options.forceReindex)
132097
- return;
132098
- const canonicalize = options.canonicalize ?? realpath2;
132099
- let storedCanonical;
132100
- try {
132101
- storedCanonical = await canonicalize(path29.resolve(options.storedProjectPath));
132102
- } catch {
132103
- storedCanonical = path29.resolve(options.storedProjectPath);
132104
- }
132105
- if (storedCanonical !== options.canonicalProjectPath) {
132106
- throw new Error(`Project ID "${options.projectId}" already indexes canonical root ` + `"${storedCanonical}", not "${options.canonicalProjectPath}"; ` + "use forceReindex only after verifying ownership of the existing project");
132107
- }
132108
- }
132109
- var init_project_root_identity = () => {};
132110
-
132111
131610
  // ../../packages/core/dist/services/symbol/definition-lookup.js
132112
131611
  function toSymbolIdentityResolution(result) {
132113
131612
  switch (result.status) {
@@ -132128,8 +131627,8 @@ function toSymbolIdentityResolution(result) {
132128
131627
 
132129
131628
  class DefinitionLookupService {
132130
131629
  repository;
132131
- constructor(repository = getSymbolRepository) {
132132
- this.repository = repository;
131630
+ constructor(repository2 = getSymbolRepository) {
131631
+ this.repository = repository2;
132133
131632
  }
132134
131633
  async lookup(projectId, query) {
132135
131634
  const repo = this.repository();
@@ -132843,16 +132342,16 @@ function detectRoutes(httpEdges, defs, opts = {}) {
132843
132342
  const seen = new Set;
132844
132343
  const out = [];
132845
132344
  for (const e of httpEdges) {
132846
- const path30 = e.route;
132847
- if (!path30)
132345
+ const path29 = e.route;
132346
+ if (!path29)
132848
132347
  continue;
132849
132348
  const method = (e.method ?? "ANY").toUpperCase();
132850
- const key = method + " " + path30;
132349
+ const key = method + " " + path29;
132851
132350
  if (seen.has(key))
132852
132351
  continue;
132853
132352
  seen.add(key);
132854
132353
  out.push({
132855
- path: path30,
132354
+ path: path29,
132856
132355
  method: e.method,
132857
132356
  file: e.fromFile,
132858
132357
  handler: e.targetFqn ?? e.symbolName
@@ -132863,12 +132362,12 @@ function detectRoutes(httpEdges, defs, opts = {}) {
132863
132362
  continue;
132864
132363
  const parsed = parseRouteName(d.name);
132865
132364
  const method = parsed?.method ?? "ANY";
132866
- const path30 = parsed?.path ?? d.name;
132867
- const key = method + " " + path30;
132365
+ const path29 = parsed?.path ?? d.name;
132366
+ const key = method + " " + path29;
132868
132367
  if (seen.has(key))
132869
132368
  continue;
132870
132369
  seen.add(key);
132871
- out.push({ path: path30, method: parsed?.method, file: d.filePath, handler: d.name });
132370
+ out.push({ path: path29, method: parsed?.method, file: d.filePath, handler: d.name });
132872
132371
  }
132873
132372
  for (const d of defs) {
132874
132373
  const parsed = parseRouteName(d.name);
@@ -133089,7 +132588,7 @@ __export(exports_symbol_graph_service, {
133089
132588
  symbolGraphService: () => symbolGraphService,
133090
132589
  SymbolGraphService: () => SymbolGraphService
133091
132590
  });
133092
- import path30 from "path";
132591
+ import path29 from "path";
133093
132592
  import fs19 from "fs/promises";
133094
132593
 
133095
132594
  class SymbolGraphService {
@@ -133443,7 +132942,7 @@ class SymbolGraphService {
133443
132942
  }
133444
132943
  async resolveToAbsolute(relativePath, projectId) {
133445
132944
  const root = await this.getProjectRoot(projectId);
133446
- return root ? path30.resolve(root, relativePath) : relativePath;
132945
+ return root ? path29.resolve(root, relativePath) : relativePath;
133447
132946
  }
133448
132947
  async getProjectRoot(projectId) {
133449
132948
  const cached2 = this.projectRootCache.get(projectId);
@@ -133557,7 +133056,7 @@ class WorkspaceManager {
133557
133056
  return matches[0];
133558
133057
  }
133559
133058
  async removeWorkspace(projectId) {
133560
- await getSymbolRepository().clearProject(projectId);
133059
+ await withHeavyWorkLease("maintenance", `workspace-remove:${projectId}`, () => getSymbolRepository().clearProject(projectId));
133561
133060
  logger.info("WorkspaceManager: workspace removed", { projectId });
133562
133061
  }
133563
133062
  subscribeToEvents() {
@@ -133582,11 +133081,633 @@ var init_workspace_manager = __esm(() => {
133582
133081
  init_symbol_repository_factory();
133583
133082
  init_event_bus();
133584
133083
  init_symbol_graph_service();
133084
+ init_heavy_work_lease();
133585
133085
  workspaceManager = WorkspaceManager.getInstance();
133586
133086
  });
133587
133087
 
133588
- // ../../packages/core/dist/tools/index_project.js
133088
+ // ../../packages/core/dist/services/etl/pipeline.js
133089
+ import { createHash as createHash7 } from "crypto";
133090
+ import { setTimeout as delay3 } from "timers/promises";
133091
+ import path30 from "path";
133092
+ function buildHeaderLanguageEvidence(files) {
133093
+ const headers = new Set(files.filter((file2) => path30.posix.extname(file2.relativePath).toLowerCase() === ".h").map((file2) => path30.posix.normalize(file2.relativePath)));
133094
+ const mutable = new Map;
133095
+ const entry2 = (header) => {
133096
+ let value = mutable.get(header);
133097
+ if (!value) {
133098
+ value = { cImporters: new Set, cppImporters: new Set, build: new Set };
133099
+ mutable.set(header, value);
133100
+ }
133101
+ return value;
133102
+ };
133103
+ for (const file2 of files) {
133104
+ if (path30.posix.basename(file2.relativePath) !== "compile_commands.json" || file2.snapshotContent === undefined)
133105
+ continue;
133106
+ let commands;
133107
+ try {
133108
+ commands = JSON.parse(file2.snapshotContent);
133109
+ } catch {
133110
+ continue;
133111
+ }
133112
+ if (!Array.isArray(commands))
133113
+ continue;
133114
+ for (const command of commands) {
133115
+ if (!command || typeof command !== "object")
133116
+ continue;
133117
+ const record3 = command;
133118
+ if (typeof record3.file !== "string")
133119
+ continue;
133120
+ const projectRoot = path30.resolve(file2.absolutePath, ...file2.relativePath.split("/").map(() => ".."));
133121
+ const commandDirectory = typeof record3.directory === "string" ? path30.resolve(projectRoot, record3.directory) : projectRoot;
133122
+ const absoluteInput = path30.resolve(commandDirectory, record3.file);
133123
+ const relative2 = path30.relative(projectRoot, absoluteInput);
133124
+ const header = path30.posix.normalize(relative2.replaceAll(path30.sep, "/"));
133125
+ if (!headers.has(header))
133126
+ continue;
133127
+ const invocation = typeof record3.command === "string" ? record3.command : Array.isArray(record3.arguments) ? record3.arguments.join(" ") : "";
133128
+ if (/(?:^|\s)(?:clang\+\+|g\+\+|c\+\+)(?:\s|$)|(?:^|\s)-x\s*c\+\+(?:\s|$)/u.test(invocation))
133129
+ entry2(header).build.add("cpp");
133130
+ else if (/(?:^|\s)(?:clang|gcc|cc)(?:\s|$)|(?:^|\s)-x\s*c(?:\s|$)/u.test(invocation))
133131
+ entry2(header).build.add("c");
133132
+ }
133133
+ }
133134
+ return Object.freeze(Object.fromEntries([...mutable.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([header, value]) => [header, Object.freeze({
133135
+ ...value.cImporters.size ? { cImporters: Object.freeze([...value.cImporters].sort()) } : {},
133136
+ ...value.cppImporters.size ? { cppImporters: Object.freeze([...value.cppImporters].sort()) } : {},
133137
+ ...value.build.size ? { buildLanguage: value.build.size > 1 ? "conflict" : [...value.build][0] } : {}
133138
+ })])));
133139
+ }
133140
+ function abortable(operation, signal) {
133141
+ if (signal.aborted)
133142
+ return Promise.reject(signal.reason);
133143
+ return new Promise((resolve5, reject) => {
133144
+ let abortReason;
133145
+ const onAbort = () => {
133146
+ abortReason = signal.reason;
133147
+ };
133148
+ signal.addEventListener("abort", onAbort, { once: true });
133149
+ operation.then((value) => abortReason === undefined ? resolve5(value) : reject(abortReason), (error51) => reject(abortReason ?? error51)).finally(() => signal.removeEventListener("abort", onAbort));
133150
+ });
133151
+ }
133152
+ var EtlPipeline;
133153
+ var init_pipeline = __esm(() => {
133154
+ init_dist();
133155
+ init_discover();
133156
+ init_parse3();
133157
+ init_resolve();
133158
+ init_load();
133159
+ init_event_bus();
133160
+ init_symbol_repository_factory();
133161
+ init_index_job_tracker();
133162
+ init_cache_factory();
133163
+ init_index_manager();
133164
+ init_vector_store_factory();
133165
+ init_keyword_search_factory();
133166
+ init_alias_resolver();
133167
+ init_symbol_repo_workspace();
133168
+ init_project_indexer();
133169
+ init_parser_readiness();
133170
+ init_parse3();
133171
+ init_language_manifest();
133172
+ init_graph_generation_coordinator();
133173
+ init_managed_run_repository_pg();
133174
+ init_workspace_manager();
133175
+ EtlPipeline = class EtlPipeline {
133176
+ static instance = null;
133177
+ static runTails = new Map;
133178
+ discover = new DiscoverStage;
133179
+ parse = new ParseStage;
133180
+ resolve = new ResolveStage;
133181
+ load = new LoadStage;
133182
+ graphGenerations = new GraphGenerationCoordinator;
133183
+ constructor() {}
133184
+ static getInstance() {
133185
+ if (!EtlPipeline.instance) {
133186
+ EtlPipeline.instance = new EtlPipeline;
133187
+ }
133188
+ return EtlPipeline.instance;
133189
+ }
133190
+ async run(input) {
133191
+ await assertParserReadyForIndexing();
133192
+ const projectId = await getProjectIdentityAliasResolver().resolve(input.projectId);
133193
+ const canonicalInput = projectId === input.projectId ? input : { ...input, projectId };
133194
+ const previous = EtlPipeline.runTails.get(projectId);
133195
+ let release;
133196
+ const tail = new Promise((resolve5) => {
133197
+ release = resolve5;
133198
+ });
133199
+ EtlPipeline.runTails.set(projectId, tail);
133200
+ if (previous) {
133201
+ logger.info("EtlPipeline: waiting for prior project run", {
133202
+ projectId,
133203
+ jobId: input.jobId
133204
+ });
133205
+ await previous;
133206
+ }
133207
+ try {
133208
+ return await this.runInternal(canonicalInput);
133209
+ } finally {
133210
+ if (EtlPipeline.runTails.get(projectId) === tail) {
133211
+ EtlPipeline.runTails.delete(projectId);
133212
+ }
133213
+ release();
133214
+ }
133215
+ }
133216
+ async runInternal(input, generationRetry = 0) {
133217
+ const projectId = await getProjectIdentityAliasResolver().resolve(input.projectId);
133218
+ const { projectPath, jobId, forceReindex = false, filesToProcess, include_tests = false, managedRunLease } = input;
133219
+ const t0 = performance.now();
133220
+ const stageTimings = {
133221
+ discover: 0,
133222
+ parse: 0,
133223
+ resolve: 0,
133224
+ load: 0
133225
+ };
133226
+ if (forceReindex) {
133227
+ const vectorStore = await getVectorStore();
133228
+ const keywordSearch = getKeywordSearch();
133229
+ await Promise.all([
133230
+ vectorStore.deleteByProject(projectId),
133231
+ keywordSearch.deleteByProject(projectId)
133232
+ ]);
133233
+ }
133234
+ const managedRunRepository = managedRunLease ? ManagedRunRepositoryPg.getInstance() : undefined;
133235
+ const ctx = {
133236
+ projectId,
133237
+ projectPath,
133238
+ jobId,
133239
+ resumeCursor: managedRunLease ? (await managedRunRepository?.getActive(projectId, "indexing"))?.fileCursor ?? undefined : undefined,
133240
+ managedRunLease,
133241
+ emit: (event) => {
133242
+ if (event.type === "progress") {
133243
+ const p = event.payload;
133244
+ indexJobTracker.updateProgress(jobId, p.current, p.total);
133245
+ eventBus.publish("indexing:progress", {
133246
+ jobId,
133247
+ projectId,
133248
+ stage: event.stage,
133249
+ current: p.current,
133250
+ total: p.total,
133251
+ percentage: p.percentage
133252
+ });
133253
+ } else if (event.type === "file_error") {
133254
+ const p = event.payload;
133255
+ eventBus.publish("indexing:file", {
133256
+ jobId,
133257
+ projectId,
133258
+ filePath: p.filePath,
133259
+ stage: event.stage,
133260
+ status: "error",
133261
+ error: p.error
133262
+ });
133263
+ } else if (event.type === "file_processed") {
133264
+ const p = event.payload;
133265
+ eventBus.publish("indexing:file", {
133266
+ jobId,
133267
+ projectId,
133268
+ filePath: p.filePath,
133269
+ stage: event.stage,
133270
+ status: "ok"
133271
+ });
133272
+ }
133273
+ }
133274
+ };
133275
+ eventBus.publish("indexing:started", { jobId, projectId, projectPath });
133276
+ let graphGenerationLease;
133277
+ let graphHeartbeat;
133278
+ let graphHeartbeatFailure;
133279
+ const graphAbortController = new AbortController;
133280
+ const heartbeatTimerController = new AbortController;
133281
+ let stopGraphHeartbeat = false;
133282
+ let managedRunHeartbeat;
133283
+ let managedRunLeaseLost;
133284
+ let stopManagedRunHeartbeat = false;
133285
+ const managedRunTimerController = new AbortController;
133286
+ if (managedRunLease && managedRunRepository) {
133287
+ managedRunHeartbeat = (async () => {
133288
+ while (!stopManagedRunHeartbeat) {
133289
+ try {
133290
+ await delay3(30000, undefined, { signal: managedRunTimerController.signal });
133291
+ } catch {
133292
+ return;
133293
+ }
133294
+ if (stopManagedRunHeartbeat || !managedRunLease)
133295
+ return;
133296
+ try {
133297
+ const outcome2 = await managedRunRepository.heartbeat(managedRunLease);
133298
+ if (outcome2.status === "lease_lost") {
133299
+ managedRunLeaseLost = new Error("managed_run_lease_lost");
133300
+ graphAbortController.abort(managedRunLeaseLost);
133301
+ return;
133302
+ }
133303
+ } catch (heartbeatError) {
133304
+ managedRunLeaseLost = heartbeatError;
133305
+ graphAbortController.abort(managedRunLeaseLost);
133306
+ return;
133307
+ }
133308
+ }
133309
+ })();
133310
+ }
133311
+ const jobHeartbeatController = new AbortController;
133312
+ (async () => {
133313
+ while (true) {
133314
+ try {
133315
+ await delay3(30000, undefined, { signal: jobHeartbeatController.signal });
133316
+ } catch {
133317
+ return;
133318
+ }
133319
+ try {
133320
+ indexJobTracker.heartbeat(jobId);
133321
+ } catch {}
133322
+ }
133323
+ })();
133324
+ try {
133325
+ const st1 = performance.now();
133326
+ const discoveredSnapshot = await this.discover.run(ctx, { forceReindex, includeTests: include_tests });
133327
+ ctx.structuralHeaderEvidenceByFile = buildHeaderLanguageEvidence(discoveredSnapshot);
133328
+ stageTimings.discover = Math.round(performance.now() - st1);
133329
+ await workspaceManager.markIndexing(projectId, projectPath);
133330
+ const activeGraph = await getSymbolRepository().getActiveGraphSnapshot(projectId);
133331
+ try {
133332
+ graphGenerationLease = await this.graphGenerations.begin({
133333
+ projectId,
133334
+ expectedActiveGenerationId: activeGraph?.generationId ?? null,
133335
+ fingerprint: `sha256:${createHash7("sha256").update(JSON.stringify(STRUCTURAL_FINGERPRINT_INPUTS)).digest("hex")}`,
133336
+ inputSnapshotHash: buildGraphInputSnapshotHash(discoveredSnapshot),
133337
+ expectedFilesCount: discoveredSnapshot.length
133338
+ });
133339
+ } catch (beginError) {
133340
+ if (beginError.message.startsWith("graph_generation_stale_active:") && generationRetry < 3) {
133341
+ stopManagedRunHeartbeat = true;
133342
+ managedRunTimerController.abort();
133343
+ jobHeartbeatController.abort();
133344
+ if (managedRunHeartbeat)
133345
+ await managedRunHeartbeat;
133346
+ return this.runInternal(input, generationRetry + 1);
133347
+ }
133348
+ throw beginError;
133349
+ }
133350
+ ctx.graphGenerationLease = graphGenerationLease;
133351
+ ctx.abortSignal = graphAbortController.signal;
133352
+ graphHeartbeat = (async () => {
133353
+ while (!stopGraphHeartbeat) {
133354
+ try {
133355
+ await delay3(30000, undefined, { signal: heartbeatTimerController.signal });
133356
+ } catch {
133357
+ return;
133358
+ }
133359
+ if (stopGraphHeartbeat || !graphGenerationLease)
133360
+ return;
133361
+ try {
133362
+ await this.graphGenerations.heartbeat(graphGenerationLease);
133363
+ } catch (heartbeatError) {
133364
+ graphHeartbeatFailure = heartbeatError;
133365
+ graphAbortController.abort(graphHeartbeatFailure);
133366
+ return;
133367
+ }
133368
+ }
133369
+ })();
133370
+ const requestedPaths = new Set(filesToProcess ?? []);
133371
+ const preparedFiles = discoveredSnapshot.map((file2) => ({
133372
+ ...file2,
133373
+ needsReparse: forceReindex || !activeGraph || file2.needsReparse || requestedPaths.has(file2.relativePath)
133374
+ }));
133375
+ if (activeGraph) {
133376
+ for (const file2 of preparedFiles) {
133377
+ if (file2.needsReparse)
133378
+ continue;
133379
+ const copied = await getSymbolRepository().copyFileGeneration(graphGenerationLease, activeGraph.generationId, file2.relativePath);
133380
+ if (copied.status === "lease_lost")
133381
+ throw new Error("graph_generation_lease_lost");
133382
+ if (copied.status === "missing")
133383
+ file2.needsReparse = true;
133384
+ }
133385
+ }
133386
+ const discovered = preparedFiles.map((file2) => Object.freeze(file2));
133387
+ eventBus.publish("indexing:started", {
133388
+ jobId,
133389
+ projectId,
133390
+ projectPath,
133391
+ totalFiles: discovered.filter((f) => f.needsReparse).length
133392
+ });
133393
+ const st2 = performance.now();
133394
+ let remainingFiles = [...discovered];
133395
+ let parsed = [];
133396
+ const staleFailures = new Set;
133397
+ while (remainingFiles.length > 0) {
133398
+ try {
133399
+ parsed.push(...await abortable(this.parse.run(ctx, remainingFiles), graphAbortController.signal));
133400
+ break;
133401
+ } catch (parseError) {
133402
+ if (!activeGraph || forceReindex || !filesToProcess?.length || !(parseError instanceof StructuralEtlParseError) || staleFailures.has(parseError.filePath))
133403
+ throw parseError;
133404
+ staleFailures.add(parseError.filePath);
133405
+ const stale = await getSymbolRepository().markFileStaleGeneration(graphGenerationLease, parseError.filePath, {
133406
+ lastKnownGoodGenerationId: activeGraph.generationId,
133407
+ diagnostics: parseError.diagnostics.length > 0 ? parseError.diagnostics.slice(0, 10).map((diagnostic2) => ({ ...diagnostic2 })) : [{ code: "incremental_structural_failure", message: parseError.message }],
133408
+ parserErrorCount: parseError.diagnosticCount
133409
+ });
133410
+ if (stale.status !== "stale")
133411
+ throw parseError;
133412
+ remainingFiles = remainingFiles.filter((file2) => file2.relativePath !== parseError.filePath);
133413
+ }
133414
+ }
133415
+ if (graphHeartbeatFailure)
133416
+ throw graphHeartbeatFailure;
133417
+ if (managedRunLeaseLost)
133418
+ throw managedRunLeaseLost;
133419
+ stageTimings.parse = Math.round(performance.now() - st2);
133420
+ const st3 = performance.now();
133421
+ const resolved = await abortable(this.resolve.run(ctx, parsed), graphAbortController.signal);
133422
+ if (graphHeartbeatFailure)
133423
+ throw graphHeartbeatFailure;
133424
+ if (managedRunLeaseLost)
133425
+ throw managedRunLeaseLost;
133426
+ stageTimings.resolve = Math.round(performance.now() - st3);
133427
+ const st4 = performance.now();
133428
+ const loadResult = await abortable(this.load.run(ctx, resolved), graphAbortController.signal);
133429
+ if (graphHeartbeatFailure)
133430
+ throw graphHeartbeatFailure;
133431
+ if (managedRunLeaseLost)
133432
+ throw managedRunLeaseLost;
133433
+ stageTimings.load = Math.round(performance.now() - st4);
133434
+ if (loadResult.errors > 0) {
133435
+ logger.warn("EtlPipeline: completed with file errors", {
133436
+ projectId,
133437
+ jobId,
133438
+ errors: loadResult.errors,
133439
+ fileErrors: (loadResult.fileErrors ?? []).slice(0, 10)
133440
+ });
133441
+ }
133442
+ const activationSnapshot = await abortable(this.discover.run(ctx, { forceReindex, includeTests: include_tests }), graphAbortController.signal);
133443
+ if (buildGraphInputSnapshotHash(activationSnapshot) !== graphGenerationLease.inputSnapshotHash) {
133444
+ throw new Error("graph_generation_stale_snapshot");
133445
+ }
133446
+ if (graphHeartbeatFailure)
133447
+ throw graphHeartbeatFailure;
133448
+ if (managedRunLeaseLost)
133449
+ throw managedRunLeaseLost;
133450
+ stopGraphHeartbeat = true;
133451
+ heartbeatTimerController.abort();
133452
+ await graphHeartbeat;
133453
+ stopManagedRunHeartbeat = true;
133454
+ managedRunTimerController.abort();
133455
+ if (managedRunHeartbeat)
133456
+ await managedRunHeartbeat;
133457
+ const activatedGraph = await this.graphGenerations.activate(graphGenerationLease);
133458
+ const activeGraphSummary = await getSymbolRepository().getActiveGraphSnapshot(projectId);
133459
+ if (!activeGraphSummary || activeGraphSummary.generationId !== activatedGraph.generationId) {
133460
+ throw new Error("activated_graph_summary_mismatch");
133461
+ }
133462
+ const durationMs = Math.round(performance.now() - t0);
133463
+ const result = {
133464
+ filesDiscovered: discovered.length,
133465
+ filesIndexed: loadResult.filesLoaded,
133466
+ filesSkipped: discovered.filter((f) => !f.needsReparse).length,
133467
+ chunksIndexed: loadResult.chunksLoaded,
133468
+ symbolsIndexed: loadResult.symbolsLoaded,
133469
+ errors: loadResult.errors,
133470
+ durationMs,
133471
+ stageTimings,
133472
+ activatedGraphGenerationId: activatedGraph.generationId,
133473
+ parserDiagnostics: {
133474
+ diagnosticsCount: activeGraphSummary.diagnostics.errors,
133475
+ recoveredFiles: activeGraphSummary.diagnostics.recovered,
133476
+ hardFailureFiles: activeGraphSummary.diagnostics.hardFailures,
133477
+ staleFiles: activeGraphSummary.diagnostics.staleFiles,
133478
+ languages: activeGraphSummary.languages
133479
+ }
133480
+ };
133481
+ await getSearchCache().invalidateProject(projectId);
133482
+ try {
133483
+ const admissionMarker = new IndexManager(await getVectorStore());
133484
+ await admissionMarker.updateIndexMetadata(projectId, projectPath, discovered.map((file2) => file2.relativePath));
133485
+ } catch (markerError) {
133486
+ logger.warn("EtlPipeline: search-admission marker write failed", {
133487
+ projectId,
133488
+ jobId,
133489
+ error: markerError
133490
+ });
133491
+ }
133492
+ if (forceReindex) {
133493
+ const liveFingerprint = currentEmbeddingFingerprint();
133494
+ if (liveFingerprint !== null) {
133495
+ try {
133496
+ await stampEmbeddingFingerprint(projectId, liveFingerprint);
133497
+ } catch (stampError) {
133498
+ logger.warn("EtlPipeline: embedding fingerprint stamp failed", {
133499
+ projectId,
133500
+ jobId,
133501
+ error: stampError
133502
+ });
133503
+ }
133504
+ }
133505
+ }
133506
+ indexJobTracker.updateProgress(jobId, result.filesIndexed, result.filesIndexed);
133507
+ await indexJobTracker.setResultAndFlush(jobId, {
133508
+ filesIndexed: result.filesIndexed,
133509
+ chunksIndexed: result.chunksIndexed,
133510
+ errors: result.errors,
133511
+ fileErrors: loadResult.fileErrors ?? [],
133512
+ duration: durationMs,
133513
+ activatedGraphGenerationId: result.activatedGraphGenerationId,
133514
+ parserDiagnostics: result.parserDiagnostics
133515
+ });
133516
+ eventBus.publish("indexing:completed", {
133517
+ jobId,
133518
+ projectId,
133519
+ filesIndexed: result.filesIndexed,
133520
+ chunksIndexed: result.chunksIndexed,
133521
+ symbolsIndexed: result.symbolsIndexed,
133522
+ errors: result.errors,
133523
+ durationMs,
133524
+ activatedGraphGenerationId: result.activatedGraphGenerationId
133525
+ });
133526
+ await this.graphGenerations.cleanup(graphGenerationLease);
133527
+ jobHeartbeatController.abort();
133528
+ stopGraphHeartbeat = true;
133529
+ heartbeatTimerController.abort();
133530
+ await graphHeartbeat;
133531
+ stopManagedRunHeartbeat = true;
133532
+ managedRunTimerController.abort();
133533
+ if (managedRunHeartbeat)
133534
+ await managedRunHeartbeat;
133535
+ if (managedRunLease && managedRunRepository) {
133536
+ try {
133537
+ await managedRunRepository.complete(managedRunLease);
133538
+ } catch (completeError) {
133539
+ logger.error("EtlPipeline: managed_runs complete failed", completeError, { projectId, jobId });
133540
+ }
133541
+ }
133542
+ logger.info("EtlPipeline: run completed", { projectId, jobId, ...result });
133543
+ return result;
133544
+ } catch (err) {
133545
+ const durationMs = Math.round(performance.now() - t0);
133546
+ const error51 = err.message;
133547
+ if (graphGenerationLease) {
133548
+ try {
133549
+ await this.graphGenerations.abort(graphGenerationLease, error51);
133550
+ } catch (abortError) {
133551
+ logger.error("EtlPipeline: pending generation abort failed", abortError, { projectId, jobId });
133552
+ }
133553
+ }
133554
+ jobHeartbeatController.abort();
133555
+ stopGraphHeartbeat = true;
133556
+ heartbeatTimerController.abort();
133557
+ graphAbortController.abort();
133558
+ await graphHeartbeat;
133559
+ stopManagedRunHeartbeat = true;
133560
+ managedRunTimerController.abort();
133561
+ if (managedRunHeartbeat)
133562
+ await managedRunHeartbeat;
133563
+ if (managedRunLease && managedRunRepository) {
133564
+ try {
133565
+ const outcome2 = await managedRunRepository.abort(managedRunLease);
133566
+ if (outcome2.status === "lease_lost") {
133567
+ logger.warn("EtlPipeline: managed_runs abort saw lease_lost", { projectId, jobId });
133568
+ }
133569
+ } catch (abortError) {
133570
+ logger.error("EtlPipeline: managed_runs abort failed", abortError, { projectId, jobId });
133571
+ }
133572
+ }
133573
+ eventBus.publish("indexing:failed", { jobId, projectId, error: error51, durationMs });
133574
+ indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: durationMs }, error51);
133575
+ logger.error("EtlPipeline: run failed", err, { projectId, jobId, durationMs });
133576
+ throw err;
133577
+ }
133578
+ }
133579
+ };
133580
+ });
133581
+
133582
+ // ../../packages/core/dist/services/indexing/execute-indexing.js
133583
+ async function executeIndexing(request) {
133584
+ const { jobId, projectId, projectPath, forceReindex, warmCache, warmupQueries, include_tests = false, managedRunLease, warmupCache: warmupCache2 } = request;
133585
+ const startTime = Date.now();
133586
+ try {
133587
+ indexJobTracker.updateStatus(jobId, "running");
133588
+ logger.info("Starting project indexing via ETL Pipeline", {
133589
+ jobId,
133590
+ projectPath,
133591
+ projectId,
133592
+ forceReindex,
133593
+ warmCache,
133594
+ include_tests
133595
+ });
133596
+ const etlResult = await EtlPipeline.getInstance().run({
133597
+ projectId,
133598
+ projectPath,
133599
+ jobId,
133600
+ forceReindex,
133601
+ include_tests,
133602
+ managedRunLease
133603
+ });
133604
+ const duration3 = Date.now() - startTime;
133605
+ logger.info("ETL Pipeline completed", {
133606
+ jobId,
133607
+ projectId,
133608
+ duration: duration3,
133609
+ filesIndexed: etlResult.filesIndexed,
133610
+ filesSkipped: etlResult.filesSkipped,
133611
+ chunksIndexed: etlResult.chunksIndexed,
133612
+ symbolsIndexed: etlResult.symbolsIndexed,
133613
+ errors: etlResult.errors,
133614
+ stageTimings: etlResult.stageTimings
133615
+ });
133616
+ if (warmCache) {
133617
+ logger.info("Starting cache warmup", { jobId, projectId });
133618
+ const warmupStats = await warmupCache2(projectId, projectPath, warmupQueries);
133619
+ logger.info("Cache warmup completed", { jobId, projectId, ...warmupStats });
133620
+ }
133621
+ indexJobTracker.updateProgress(jobId, etlResult.filesIndexed, etlResult.filesIndexed);
133622
+ await indexJobTracker.setResultAndFlush(jobId, {
133623
+ filesIndexed: etlResult.filesIndexed,
133624
+ chunksIndexed: etlResult.chunksIndexed,
133625
+ errors: etlResult.errors,
133626
+ duration: duration3,
133627
+ activatedGraphGenerationId: etlResult.activatedGraphGenerationId,
133628
+ parserDiagnostics: etlResult.parserDiagnostics
133629
+ });
133630
+ } catch (error51) {
133631
+ const duration3 = Date.now() - startTime;
133632
+ logger.error("Project indexing failed", error51, {
133633
+ jobId,
133634
+ projectPath,
133635
+ projectId,
133636
+ duration: duration3
133637
+ });
133638
+ indexJobTracker.setResult(jobId, {
133639
+ filesIndexed: 0,
133640
+ chunksIndexed: 0,
133641
+ errors: 1,
133642
+ duration: duration3
133643
+ }, error51.message);
133644
+ }
133645
+ }
133646
+ var init_execute_indexing = __esm(() => {
133647
+ init_dist();
133648
+ init_index_job_tracker();
133649
+ init_pipeline();
133650
+ });
133651
+
133652
+ // ../../packages/core/dist/services/indexing/acquire-indexing-lease.js
133653
+ async function acquireIndexingLease(request) {
133654
+ const { jobId, projectId } = request;
133655
+ const eventId = `index:${jobId}`;
133656
+ const managedRunRepo = ManagedRunRepositoryPg.getInstance();
133657
+ try {
133658
+ const beginOutcome = await managedRunRepo.begin({
133659
+ projectId,
133660
+ runKind: "indexing",
133661
+ eventId
133662
+ });
133663
+ if (beginOutcome.status === "busy") {
133664
+ indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 0, duration: 0 }, `indexing_busy:${beginOutcome.activeRunId}`);
133665
+ return {
133666
+ status: "busy",
133667
+ activeRunId: beginOutcome.activeRunId,
133668
+ leaseExpiresAt: beginOutcome.leaseExpiresAt
133669
+ };
133670
+ }
133671
+ return { status: "acquired", lease: beginOutcome.lease };
133672
+ } catch (beginError) {
133673
+ logger.error("managed_runs begin failed", beginError, {
133674
+ jobId,
133675
+ projectId
133676
+ });
133677
+ indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: 0 }, `managed_runs_begin_failed:${beginError.message}`);
133678
+ return { status: "failed", message: beginError.message };
133679
+ }
133680
+ }
133681
+ var init_acquire_indexing_lease = __esm(() => {
133682
+ init_dist();
133683
+ init_index_job_tracker();
133684
+ init_managed_run_repository_pg();
133685
+ });
133686
+
133687
+ // ../../packages/core/dist/services/project-identity/project-root-identity.js
133688
+ import { realpath as realpath2 } from "fs/promises";
133589
133689
  import path31 from "path";
133690
+ async function canonicalizeProjectRoot(projectPath, canonicalize = realpath2) {
133691
+ return canonicalize(path31.resolve(projectPath));
133692
+ }
133693
+ async function assertProjectRootReuse(options) {
133694
+ if (!options.storedProjectPath || options.forceReindex)
133695
+ return;
133696
+ const canonicalize = options.canonicalize ?? realpath2;
133697
+ let storedCanonical;
133698
+ try {
133699
+ storedCanonical = await canonicalize(path31.resolve(options.storedProjectPath));
133700
+ } catch {
133701
+ storedCanonical = path31.resolve(options.storedProjectPath);
133702
+ }
133703
+ if (storedCanonical !== options.canonicalProjectPath) {
133704
+ throw new Error(`Project ID "${options.projectId}" already indexes canonical root ` + `"${storedCanonical}", not "${options.canonicalProjectPath}"; ` + "use forceReindex only after verifying ownership of the existing project");
133705
+ }
133706
+ }
133707
+ var init_project_root_identity = () => {};
133708
+
133709
+ // ../../packages/core/dist/tools/index_project.js
133710
+ import path32 from "path";
133590
133711
 
133591
133712
  class IndexProjectTool {
133592
133713
  name = "index_project";
@@ -133634,7 +133755,7 @@ class IndexProjectTool {
133634
133755
  try {
133635
133756
  await assertParserReadyForIndexing();
133636
133757
  const canonicalProjectPath = await canonicalizeProjectRoot(projectPath);
133637
- const finalProjectId = projectId || path31.basename(canonicalProjectPath) || "default";
133758
+ const finalProjectId = projectId || path32.basename(canonicalProjectPath) || "default";
133638
133759
  const existing = await workspaceManager.getWorkspace(finalProjectId);
133639
133760
  await assertProjectRootReuse({
133640
133761
  projectId: finalProjectId,
@@ -134187,17 +134308,17 @@ function applyReplacer(root, replacer) {
134187
134308
  return transformChildren(root, replacer, []);
134188
134309
  return transformChildren(normalizeValue(replacedRoot), replacer, []);
134189
134310
  }
134190
- function transformChildren(value, replacer, path32) {
134311
+ function transformChildren(value, replacer, path33) {
134191
134312
  if (isJsonObject(value))
134192
- return transformObject(value, replacer, path32);
134313
+ return transformObject(value, replacer, path33);
134193
134314
  if (isJsonArray(value))
134194
- return transformArray(value, replacer, path32);
134315
+ return transformArray(value, replacer, path33);
134195
134316
  return value;
134196
134317
  }
134197
- function transformObject(obj, replacer, path32) {
134318
+ function transformObject(obj, replacer, path33) {
134198
134319
  const result = {};
134199
134320
  for (const [key, value] of Object.entries(obj)) {
134200
- const childPath = [...path32, key];
134321
+ const childPath = [...path33, key];
134201
134322
  const replacedValue = replacer(key, value, childPath);
134202
134323
  if (replacedValue === undefined)
134203
134324
  continue;
@@ -134205,11 +134326,11 @@ function transformObject(obj, replacer, path32) {
134205
134326
  }
134206
134327
  return result;
134207
134328
  }
134208
- function transformArray(arr, replacer, path32) {
134329
+ function transformArray(arr, replacer, path33) {
134209
134330
  const result = [];
134210
134331
  for (let i = 0;i < arr.length; i++) {
134211
134332
  const value = arr[i];
134212
- const childPath = [...path32, i];
134333
+ const childPath = [...path33, i];
134213
134334
  const replacedValue = replacer(String(i), value, childPath);
134214
134335
  if (replacedValue === undefined)
134215
134336
  continue;
@@ -135647,7 +135768,7 @@ __export(exports_memory_consolidation_job, {
135647
135768
  memoryConsolidationJob: () => memoryConsolidationJob,
135648
135769
  MemoryConsolidationJob: () => MemoryConsolidationJob
135649
135770
  });
135650
- import { randomUUID as randomUUID6 } from "crypto";
135771
+ import { randomUUID as randomUUID7 } from "crypto";
135651
135772
  async function addSupercedesEdge(store3, newId, sourceId, batchId) {
135652
135773
  const evidence = JSON.stringify({ batchId, consolidated: true });
135653
135774
  await store3.createEdge({
@@ -135791,11 +135912,11 @@ class MemoryConsolidationJob {
135791
135912
  });
135792
135913
  return { merged: 0, batchesCreated: 0 };
135793
135914
  }
135794
- const batch = await consolidateWindow(rowsToCandidates(candidates2), this.llm, { idFactory: () => `batch-${now2}-${randomUUID6().slice(0, 8)}` }).catch(() => null);
135915
+ const batch = await consolidateWindow(rowsToCandidates(candidates2), this.llm, { idFactory: () => `batch-${now2}-${randomUUID7().slice(0, 8)}` }).catch(() => null);
135795
135916
  if (!batch)
135796
135917
  return { merged: 0, batchesCreated: 0 };
135797
135918
  const sourceRows = candidates2.filter((c) => batch.sourceIds.includes(c.id));
135798
- const newId = `mem-${now2}-${randomUUID6().slice(0, 8)}`;
135919
+ const newId = `mem-${now2}-${randomUUID7().slice(0, 8)}`;
135799
135920
  const importance = sourceRows.length ? Math.min(1, Math.max(...sourceRows.map((r) => r.importance))) : 0.7;
135800
135921
  const projectId = sourceRows.find((r) => r.project_id)?.project_id ?? null;
135801
135922
  try {
@@ -139302,7 +139423,7 @@ var init_session_pin_store = __esm(() => {
139302
139423
  // ../../packages/core/dist/services/hooks/attribution-resolver.js
139303
139424
  import fs20 from "fs";
139304
139425
  import os9 from "os";
139305
- import path32 from "path";
139426
+ import path33 from "path";
139306
139427
 
139307
139428
  class PgWorkspaceRootProvider {
139308
139429
  cache = null;
@@ -139352,7 +139473,7 @@ class AttributionResolver {
139352
139473
  this.pins = options.pins ?? new SessionPinStore;
139353
139474
  this.canonicalize = options.canonicalize ?? defaultCanonicalize;
139354
139475
  this.homedir = options.homedir ?? os9.homedir;
139355
- this.fsRoot = options.fsRoot ?? (() => path32.parse(path32.sep).root);
139476
+ this.fsRoot = options.fsRoot ?? (() => path33.parse(path33.sep).root);
139356
139477
  }
139357
139478
  async resolve(input) {
139358
139479
  const caller = input.callerProjectId;
@@ -139403,7 +139524,7 @@ class AttributionResolver {
139403
139524
  }
139404
139525
  let bestPath = null;
139405
139526
  for (const candidate2 of byPath.keys()) {
139406
- if (canonicalCwd === candidate2 || canonicalCwd.startsWith(candidate2.endsWith(path32.sep) ? candidate2 : candidate2 + path32.sep)) {
139527
+ if (canonicalCwd === candidate2 || canonicalCwd.startsWith(candidate2.endsWith(path33.sep) ? candidate2 : candidate2 + path33.sep)) {
139407
139528
  if (bestPath === null || candidate2.length > bestPath.length) {
139408
139529
  bestPath = candidate2;
139409
139530
  }
@@ -139426,7 +139547,7 @@ class AttributionResolver {
139426
139547
  return projectPath2;
139427
139548
  const fsRoot = this.fsRoot();
139428
139549
  let normalized = projectPath2;
139429
- while (normalized.length > fsRoot.length && normalized.endsWith(path32.sep)) {
139550
+ while (normalized.length > fsRoot.length && normalized.endsWith(path33.sep)) {
139430
139551
  normalized = normalized.slice(0, -1);
139431
139552
  }
139432
139553
  return normalized;
@@ -139437,7 +139558,7 @@ function defaultCanonicalize(cwd) {
139437
139558
  return fs20.realpathSync(cwd);
139438
139559
  } catch {
139439
139560
  try {
139440
- return path32.resolve(cwd);
139561
+ return path33.resolve(cwd);
139441
139562
  } catch {
139442
139563
  return;
139443
139564
  }
@@ -140186,31 +140307,31 @@ class TracePathService {
140186
140307
  const chains = [];
140187
140308
  const seen = new Set;
140188
140309
  let walks = 0;
140189
- const walk = (fqn, path33) => {
140310
+ const walk = (fqn, path34) => {
140190
140311
  if (chains.length >= CHAIN_CAP)
140191
140312
  return;
140192
140313
  if (walks >= MAX_WALKS)
140193
140314
  return;
140194
140315
  walks++;
140195
- const key = path33.join("\u2192");
140316
+ const key = path34.join("\u2192");
140196
140317
  if (seen.has(key))
140197
140318
  return;
140198
140319
  seen.add(key);
140199
140320
  const next = adj.get(fqn);
140200
140321
  if (!next || next.length === 0 || !whoHasChild.has(fqn)) {
140201
- if (path33.length > 1)
140202
- chains.push(path33.map((n) => this.fqnToName(n)).join(" \u2192 "));
140322
+ if (path34.length > 1)
140323
+ chains.push(path34.map((n) => this.fqnToName(n)).join(" \u2192 "));
140203
140324
  return;
140204
140325
  }
140205
140326
  for (const child of next) {
140206
140327
  if (chains.length >= CHAIN_CAP || walks >= MAX_WALKS)
140207
140328
  return;
140208
- if (path33.includes(child)) {
140209
- const cycled = [...path33, `${this.fqnToName(child)}\u21BA`];
140329
+ if (path34.includes(child)) {
140330
+ const cycled = [...path34, `${this.fqnToName(child)}\u21BA`];
140210
140331
  chains.push(cycled.map((n) => n).join(" \u2192 "));
140211
140332
  continue;
140212
140333
  }
140213
- walk(child, [...path33, child]);
140334
+ walk(child, [...path34, child]);
140214
140335
  }
140215
140336
  };
140216
140337
  for (const seed of seeds) {
@@ -141093,7 +141214,7 @@ var init_file_content_cache = __esm(() => {
141093
141214
  });
141094
141215
 
141095
141216
  // ../../packages/core/dist/services/file-read/file-metadata.js
141096
- import path33 from "path";
141217
+ import path34 from "path";
141097
141218
 
141098
141219
  class FileMetadataExtractor {
141099
141220
  symbolGraph;
@@ -141129,7 +141250,7 @@ class FileMetadataExtractor {
141129
141250
  return metadata;
141130
141251
  }
141131
141252
  detectLanguage(filePath) {
141132
- const ext2 = path33.extname(filePath).toLowerCase();
141253
+ const ext2 = path34.extname(filePath).toLowerCase();
141133
141254
  const languageMap2 = {
141134
141255
  ".ts": "TypeScript",
141135
141256
  ".tsx": "TypeScript",
@@ -141251,7 +141372,7 @@ var init_line_range = __esm(() => {
141251
141372
  });
141252
141373
 
141253
141374
  // ../../packages/core/dist/services/file-read/path-containment.js
141254
- import path34 from "path";
141375
+ import path35 from "path";
141255
141376
 
141256
141377
  class PathContainment {
141257
141378
  projectRoots;
@@ -141259,14 +141380,14 @@ class PathContainment {
141259
141380
  this.projectRoots = projectRoots;
141260
141381
  }
141261
141382
  async resolveFilePath(filePath, projectId) {
141262
- if (path34.isAbsolute(filePath)) {
141263
- return path34.resolve(filePath);
141383
+ if (path35.isAbsolute(filePath)) {
141384
+ return path35.resolve(filePath);
141264
141385
  }
141265
141386
  if (projectId) {
141266
141387
  const root = await this.projectRoots.getProjectRoot(projectId);
141267
141388
  if (root) {
141268
141389
  const cleaned = sanitizeFilePath(filePath);
141269
- return path34.resolve(root, cleaned);
141390
+ return path35.resolve(root, cleaned);
141270
141391
  }
141271
141392
  return null;
141272
141393
  }
@@ -141277,17 +141398,17 @@ class PathContainment {
141277
141398
  if (projectId) {
141278
141399
  const root = await this.projectRoots.getProjectRoot(projectId);
141279
141400
  if (root)
141280
- roots.push(path34.resolve(root));
141401
+ roots.push(path35.resolve(root));
141281
141402
  }
141282
- roots.push(path34.resolve(process.cwd()));
141403
+ roots.push(path35.resolve(process.cwd()));
141283
141404
  const envRoots = (process.env.MASSA_AI_READ_FILE_ROOTS ?? "").split(":").map((s) => s.trim()).filter((s) => s.length > 0);
141284
141405
  for (const extra of envRoots) {
141285
- roots.push(path34.resolve(extra));
141406
+ roots.push(path35.resolve(extra));
141286
141407
  }
141287
- const target = path34.resolve(absoluteFilePath);
141408
+ const target = path35.resolve(absoluteFilePath);
141288
141409
  for (const root of roots) {
141289
- const rel = path34.relative(root, target);
141290
- if (rel !== "" && !rel.startsWith("..") && !path34.isAbsolute(rel)) {
141410
+ const rel = path35.relative(root, target);
141411
+ if (rel !== "" && !rel.startsWith("..") && !path35.isAbsolute(rel)) {
141291
141412
  return { allowed: true };
141292
141413
  }
141293
141414
  if (rel === "")
@@ -144232,12 +144353,13 @@ function createProjectIdentityService(options = {}) {
144232
144353
  }
144233
144354
  },
144234
144355
  apply(input) {
144235
- return applyService.apply(input);
144356
+ return withHeavyWorkLease("maintenance", "project-identity", () => applyService.apply(input));
144236
144357
  }
144237
144358
  };
144238
144359
  }
144239
144360
  var init_service = __esm(() => {
144240
144361
  init_db_connection();
144362
+ init_heavy_work_lease();
144241
144363
  init_apply();
144242
144364
  init_errors4();
144243
144365
  init_planner();
@@ -144535,7 +144657,7 @@ var init_inference_probe = __esm(() => {
144535
144657
  // ../../packages/core/dist/services/health/local-health-checker.js
144536
144658
  import fs22 from "fs/promises";
144537
144659
  import { existsSync as existsSync3 } from "fs";
144538
- import path35 from "path";
144660
+ import path36 from "path";
144539
144661
 
144540
144662
  class LocalHealthChecker {
144541
144663
  dataDir = config2.get("dataDir");
@@ -144614,7 +144736,7 @@ class LocalHealthChecker {
144614
144736
  try {
144615
144737
  if (!existsSync3(this.dataDir))
144616
144738
  await fs22.mkdir(this.dataDir, { recursive: true });
144617
- const probe2 = path35.join(this.dataDir, ".health-check-test");
144739
+ const probe2 = path36.join(this.dataDir, ".health-check-test");
144618
144740
  await fs22.writeFile(probe2, "ok");
144619
144741
  await fs22.unlink(probe2);
144620
144742
  return { available: true, latency: Date.now() - start, details: { path: this.dataDir, writable: true } };
@@ -144960,6 +145082,9 @@ class PgScheduledJobStore {
144960
145082
  }, "save");
144961
145083
  this.ensureHydrated();
144962
145084
  }
145085
+ async ready() {
145086
+ await this.ensureHydrated();
145087
+ }
144963
145088
  get(id) {
144964
145089
  this.ensureHydrated();
144965
145090
  return this.mirror.get(id) ?? null;
@@ -145036,10 +145161,18 @@ class Scheduler {
145036
145161
  handlers = new Map;
145037
145162
  cronCache = new Map;
145038
145163
  running = new Set;
145164
+ heavyWorkProbe;
145165
+ deferred = new Set;
145166
+ heavyWorkReason = null;
145167
+ lastProbeError = null;
145168
+ consecutiveProbeFailures = 0;
145169
+ evaluating = false;
145170
+ pendingTickAt = null;
145039
145171
  timer = null;
145040
145172
  started = false;
145041
145173
  constructor(opts = {}) {
145042
145174
  this.store = opts.store ?? getScheduledJobStore();
145175
+ this.heavyWorkProbe = opts.heavyWorkProbe ?? probeHeavyWork;
145043
145176
  const schedulerConfig = config2.get("scheduler");
145044
145177
  this.tickIntervalMs = opts.tickIntervalMs ?? envPositiveInt(process.env.MASSA_AI_SCHEDULER_TICK_MS) ?? schedulerConfig?.tickMs ?? DEFAULTS.tickMs;
145045
145178
  this.maxConcurrent = opts.maxConcurrent ?? envPositiveInt(process.env.MASSA_AI_SCHEDULER_MAX_CONCURRENT) ?? schedulerConfig?.maxConcurrent ?? DEFAULTS.maxConcurrent;
@@ -145140,31 +145273,43 @@ class Scheduler {
145140
145273
  this.timer.unref?.();
145141
145274
  this.tick().catch(() => {});
145142
145275
  }
145143
- catchUpMissedJobs(now2 = Date.now()) {
145144
- if (!this.enabled)
145145
- return { caughtUp: 0, skipped: 0 };
145276
+ async catchUpMissedJobs(now2 = Date.now()) {
145277
+ if (!this.enabled || this.evaluating)
145278
+ return { caughtUp: 0, skipped: 0, deferred: 0 };
145279
+ this.evaluating = true;
145280
+ try {
145281
+ return await this.catchUpOnce(now2);
145282
+ } finally {
145283
+ this.evaluating = false;
145284
+ }
145285
+ }
145286
+ async catchUpOnce(now2) {
145146
145287
  const jobs = this.store.listEnabled();
145147
- let caughtUp = 0;
145148
145288
  let skipped = 0;
145289
+ const missed = [];
145149
145290
  for (const job of jobs) {
145150
145291
  if (this.running.has(job.jobKind)) {
145151
145292
  skipped++;
145152
145293
  continue;
145153
145294
  }
145154
- const overdueMs = now2 - job.nextRunAt;
145155
- if (overdueMs <= this.tickIntervalMs) {
145156
- continue;
145157
- }
145295
+ if (now2 - job.nextRunAt > this.tickIntervalMs)
145296
+ missed.push(job);
145297
+ }
145298
+ if (missed.length > 0 && await this.heavyWorkBusy()) {
145299
+ for (const job of missed)
145300
+ this.deferred.add(job.id);
145301
+ return { caughtUp: 0, skipped, deferred: missed.length };
145302
+ }
145303
+ for (const job of missed) {
145158
145304
  logger.info("Scheduler: catch-up tick for missed job", {
145159
145305
  id: job.id,
145160
145306
  name: job.name,
145161
145307
  jobKind: job.jobKind,
145162
- overdueMs
145308
+ overdueMs: now2 - job.nextRunAt
145163
145309
  });
145164
145310
  this.fireJob(job, now2);
145165
- caughtUp++;
145166
145311
  }
145167
- return { caughtUp, skipped };
145312
+ return { caughtUp: missed.length, skipped, deferred: 0 };
145168
145313
  }
145169
145314
  stop() {
145170
145315
  if (this.timer) {
@@ -145172,17 +145317,47 @@ class Scheduler {
145172
145317
  this.timer = null;
145173
145318
  }
145174
145319
  this.started = false;
145320
+ this.pendingTickAt = null;
145175
145321
  logger.info("Scheduler stopped");
145176
145322
  }
145177
145323
  isRunning() {
145178
145324
  return this.started && this.timer !== null;
145179
145325
  }
145180
145326
  async tick(now2 = Date.now()) {
145181
- const result = { evaluated: 0, fired: 0, skipped: 0, errors: 0 };
145327
+ const result = { evaluated: 0, fired: 0, skipped: 0, errors: 0, deferred: 0 };
145182
145328
  if (!this.enabled)
145183
145329
  return result;
145184
- const jobs = this.store.listEnabled();
145330
+ if (this.evaluating) {
145331
+ this.pendingTickAt = now2;
145332
+ return result;
145333
+ }
145334
+ this.evaluating = true;
145335
+ try {
145336
+ return await this.tickOnce(now2, result);
145337
+ } finally {
145338
+ this.evaluating = false;
145339
+ const pending = this.pendingTickAt;
145340
+ this.pendingTickAt = null;
145341
+ if (pending !== null) {
145342
+ this.tick(pending).catch((e) => {
145343
+ logger.warn("Scheduler tick failed (swallowed)", { error: e });
145344
+ });
145345
+ }
145346
+ }
145347
+ }
145348
+ async tickOnce(now2, result) {
145349
+ let jobs = this.store.listEnabled();
145185
145350
  result.evaluated = jobs.length;
145351
+ const due = jobs.filter((job) => !this.running.has(job.jobKind) && job.nextRunAt <= now2);
145352
+ if (due.length > 0) {
145353
+ if (await this.heavyWorkBusy()) {
145354
+ for (const job of due)
145355
+ this.deferred.add(job.id);
145356
+ result.deferred = due.length;
145357
+ return result;
145358
+ }
145359
+ jobs = this.store.listEnabled();
145360
+ }
145186
145361
  for (const job of jobs) {
145187
145362
  if (this.running.has(job.jobKind)) {
145188
145363
  result.skipped++;
@@ -145192,7 +145367,7 @@ class Scheduler {
145192
145367
  continue;
145193
145368
  }
145194
145369
  const overdueMs = now2 - job.nextRunAt;
145195
- const isMissed = overdueMs > this.tickIntervalMs;
145370
+ const isMissed = overdueMs > this.tickIntervalMs && !this.deferred.has(job.id);
145196
145371
  if (isMissed) {
145197
145372
  logger.warn("Scheduler: missed run (skipping, rescheduling)", {
145198
145373
  id: job.id,
@@ -145214,7 +145389,42 @@ class Scheduler {
145214
145389
  }
145215
145390
  return result;
145216
145391
  }
145392
+ async heavyWorkBusy() {
145393
+ let state;
145394
+ try {
145395
+ state = await this.heavyWorkProbe();
145396
+ } catch (e) {
145397
+ this.consecutiveProbeFailures++;
145398
+ this.lastProbeError = e.message;
145399
+ if (this.consecutiveProbeFailures === 1 || this.consecutiveProbeFailures % PROBE_FAILURE_WARN_EVERY === 0) {
145400
+ logger.warn("Scheduler: heavy-work probe failed; deferring due jobs", {
145401
+ consecutiveFailures: this.consecutiveProbeFailures,
145402
+ error: e
145403
+ });
145404
+ }
145405
+ return true;
145406
+ }
145407
+ this.consecutiveProbeFailures = 0;
145408
+ this.lastProbeError = null;
145409
+ if (state.busy) {
145410
+ if (this.heavyWorkReason === null) {
145411
+ logger.info("Scheduler: heavy database work in progress; deferring due jobs", {
145412
+ reason: state.reason ?? "unknown"
145413
+ });
145414
+ }
145415
+ this.heavyWorkReason = state.reason ?? "unknown";
145416
+ return true;
145417
+ }
145418
+ if (this.heavyWorkReason !== null) {
145419
+ logger.info("Scheduler: heavy database work finished; running deferred jobs", {
145420
+ deferred: this.deferred.size
145421
+ });
145422
+ this.heavyWorkReason = null;
145423
+ }
145424
+ return false;
145425
+ }
145217
145426
  fireJob(job, firedAt) {
145427
+ this.deferred.delete(job.id);
145218
145428
  const handler = this.handlers.get(job.jobKind);
145219
145429
  if (!handler) {
145220
145430
  logger.warn("Scheduler: no handler registered for jobKind", {
@@ -145274,6 +145484,9 @@ class Scheduler {
145274
145484
  }
145275
145485
  })();
145276
145486
  }
145487
+ async ready() {
145488
+ await this.store.ready?.();
145489
+ }
145277
145490
  status(now2 = Date.now()) {
145278
145491
  const jobs = this.store.listAll();
145279
145492
  return {
@@ -145288,10 +145501,17 @@ class Scheduler {
145288
145501
  nextRunAt: j.nextRunAt,
145289
145502
  lastRunAt: j.lastRunAt,
145290
145503
  lastSuccessAt: j.lastSuccessAt ?? null,
145504
+ lastFailureAt: j.lastFailureAt ?? null,
145291
145505
  consecutiveFailures: j.consecutiveFailures ?? 0,
145506
+ lastError: j.lastError ?? null,
145292
145507
  due: j.enabled && j.nextRunAt <= now2,
145293
- currentlyRunning: this.running.has(j.jobKind)
145294
- }))
145508
+ currentlyRunning: this.running.has(j.jobKind),
145509
+ deferred: this.deferred.has(j.id)
145510
+ })),
145511
+ heavyWork: {
145512
+ lastProbeError: this.lastProbeError,
145513
+ consecutiveProbeFailures: this.consecutiveProbeFailures
145514
+ }
145295
145515
  };
145296
145516
  }
145297
145517
  isJobRunning(jobKind) {
@@ -145310,12 +145530,13 @@ function resetScheduler() {
145310
145530
  }
145311
145531
  resetScheduledJobStore();
145312
145532
  }
145313
- var DEFAULTS, cachedScheduler = null;
145533
+ var DEFAULTS, PROBE_FAILURE_WARN_EVERY = 5, cachedScheduler = null;
145314
145534
  var init_scheduler = __esm(() => {
145315
145535
  init_dist();
145316
145536
  init_config();
145317
145537
  init_scheduler_cron();
145318
145538
  init_scheduler_store_factory();
145539
+ init_heavy_work_lease();
145319
145540
  DEFAULTS = {
145320
145541
  tickMs: 60000,
145321
145542
  maxConcurrent: 2
@@ -146004,7 +146225,7 @@ var init_auto_improve_llm = __esm(() => {
146004
146225
  });
146005
146226
 
146006
146227
  // ../../packages/core/dist/services/jobs/auto-improve-apply.js
146007
- import { randomUUID as randomUUID7 } from "crypto";
146228
+ import { randomUUID as randomUUID8 } from "crypto";
146008
146229
  function validateCreatePayload(p) {
146009
146230
  if ("type" in p && p.type !== undefined && p.type !== null) {
146010
146231
  if (typeof p.type !== "string" || !VALID_MEMORY_TYPES.has(p.type)) {
@@ -146045,7 +146266,7 @@ function buildUpdatePatch(p) {
146045
146266
  return patch;
146046
146267
  }
146047
146268
  async function applyProposal(job, record3) {
146048
- const memId = record3.targetMemoryId ?? `proposal-mem-${record3.id}-${randomUUID7().slice(0, 8)}`;
146269
+ const memId = record3.targetMemoryId ?? `proposal-mem-${record3.id}-${randomUUID8().slice(0, 8)}`;
146049
146270
  const p = record3.payload;
146050
146271
  if (record3.kind === "memory.create") {
146051
146272
  validateCreatePayload(p);
@@ -146312,8 +146533,8 @@ __export(exports_auto_improve_job, {
146312
146533
 
146313
146534
  class AutoImproveJob {
146314
146535
  llm;
146315
- observationStore;
146316
- proposalStore;
146536
+ injectedObservationStore;
146537
+ injectedProposalStore;
146317
146538
  memoryRepo;
146318
146539
  thresholds;
146319
146540
  minObservations;
@@ -146324,10 +146545,16 @@ class AutoImproveJob {
146324
146545
  lastRunAt = 0;
146325
146546
  newSinceRun = 0;
146326
146547
  runCalls = 0;
146548
+ get observationStore() {
146549
+ return this.injectedObservationStore ?? getObservationStore();
146550
+ }
146551
+ get proposalStore() {
146552
+ return this.injectedProposalStore ?? getProposalStore();
146553
+ }
146327
146554
  constructor(opts = {}) {
146328
146555
  this.llm = opts.llm ?? llm;
146329
- this.observationStore = opts.observationStore ?? getObservationStore();
146330
- this.proposalStore = opts.proposalStore ?? getProposalStore();
146556
+ this.injectedObservationStore = opts.observationStore;
146557
+ this.injectedProposalStore = opts.proposalStore;
146331
146558
  this.thresholds = { ...DEFAULT_THRESHOLDS, ...opts.thresholds };
146332
146559
  this.reviewGateOverride = opts.reviewGate;
146333
146560
  this.idFactory = opts.idFactory ?? (() => newProposalId());
@@ -146407,7 +146634,7 @@ __export(exports_observation_consolidation_job, {
146407
146634
  observationConsolidationJob: () => observationConsolidationJob,
146408
146635
  ObservationConsolidationJob: () => ObservationConsolidationJob
146409
146636
  });
146410
- import { randomUUID as randomUUID8 } from "crypto";
146637
+ import { randomUUID as randomUUID9 } from "crypto";
146411
146638
  function readBridgeConfig() {
146412
146639
  try {
146413
146640
  const c = config2.get("hooks")?.bridge;
@@ -146425,7 +146652,7 @@ function readBridgeConfig() {
146425
146652
 
146426
146653
  class ObservationConsolidationJob {
146427
146654
  llm;
146428
- store;
146655
+ injectedStore;
146429
146656
  memoryRepo;
146430
146657
  minObservations;
146431
146658
  minIntervalMs;
@@ -146433,9 +146660,12 @@ class ObservationConsolidationJob {
146433
146660
  lastRunAt = 0;
146434
146661
  newSinceRun = 0;
146435
146662
  runCalls = 0;
146663
+ get store() {
146664
+ return this.injectedStore ?? getObservationStore();
146665
+ }
146436
146666
  constructor(opts = {}) {
146437
146667
  this.llm = opts.llm ?? llm;
146438
- this.store = opts.store ?? getObservationStore();
146668
+ this.injectedStore = opts.store;
146439
146669
  const injected = opts.memoryRepo;
146440
146670
  this.memoryRepo = injected ?? { insert: (i) => getMemoryRepository().insert(i) };
146441
146671
  const cfg = readBridgeConfig();
@@ -146497,7 +146727,7 @@ class ObservationConsolidationJob {
146497
146727
  if (observations.length < 2)
146498
146728
  return noop2;
146499
146729
  const window2 = observations.slice(0, this.maxWindow);
146500
- const batchId = `obs-batch-${Date.now()}-${randomUUID8().slice(0, 8)}`;
146730
+ const batchId = `obs-batch-${Date.now()}-${randomUUID9().slice(0, 8)}`;
146501
146731
  const prompt = buildObservationPrompt(window2);
146502
146732
  let batch;
146503
146733
  try {
@@ -146523,7 +146753,7 @@ class ObservationConsolidationJob {
146523
146753
  }
146524
146754
  if (!batch)
146525
146755
  return noop2;
146526
- const newId = `mem-${Date.now()}-${randomUUID8().slice(0, 8)}`;
146756
+ const newId = `mem-${Date.now()}-${randomUUID9().slice(0, 8)}`;
146527
146757
  const importance = 0.7;
146528
146758
  try {
146529
146759
  await Promise.resolve(this.memoryRepo.insert({
@@ -146755,7 +146985,7 @@ var init_scheduler2 = __esm(() => {
146755
146985
  // ../../packages/core/dist/services/pricing/models-dev-client.js
146756
146986
  import fs23 from "fs/promises";
146757
146987
  import { existsSync as existsSync4 } from "fs";
146758
- import path36 from "path";
146988
+ import path37 from "path";
146759
146989
  function getModelsDevClient() {
146760
146990
  if (!clientInstance) {
146761
146991
  clientInstance = new ModelsDevClient;
@@ -146775,7 +147005,7 @@ var init_models_dev_client = __esm(() => {
146775
147005
  memoryCacheTimestamp = 0;
146776
147006
  getLocalCachePath() {
146777
147007
  const dataDir = config2.get("dataDir");
146778
- return path36.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
147008
+ return path37.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
146779
147009
  }
146780
147010
  async loadLocalCache() {
146781
147011
  const cachePath = this.getLocalCachePath();
@@ -146810,7 +147040,7 @@ var init_models_dev_client = __esm(() => {
146810
147040
  async saveLocalCache(models) {
146811
147041
  const cachePath = this.getLocalCachePath();
146812
147042
  try {
146813
- const dir = path36.dirname(cachePath);
147043
+ const dir = path37.dirname(cachePath);
146814
147044
  await fs23.mkdir(dir, { recursive: true });
146815
147045
  const data = {
146816
147046
  timestamp: Date.now(),
@@ -152706,33 +152936,33 @@ var require_URL = __commonJS((exports, module) => {
152706
152936
  else
152707
152937
  return basepath.substring(0, lastslash + 1) + refpath;
152708
152938
  }
152709
- function remove_dot_segments(path37) {
152710
- if (!path37)
152711
- return path37;
152939
+ function remove_dot_segments(path38) {
152940
+ if (!path38)
152941
+ return path38;
152712
152942
  var output = "";
152713
- while (path37.length > 0) {
152714
- if (path37 === "." || path37 === "..") {
152715
- path37 = "";
152943
+ while (path38.length > 0) {
152944
+ if (path38 === "." || path38 === "..") {
152945
+ path38 = "";
152716
152946
  break;
152717
152947
  }
152718
- var twochars = path37.substring(0, 2);
152719
- var threechars = path37.substring(0, 3);
152720
- var fourchars = path37.substring(0, 4);
152948
+ var twochars = path38.substring(0, 2);
152949
+ var threechars = path38.substring(0, 3);
152950
+ var fourchars = path38.substring(0, 4);
152721
152951
  if (threechars === "../") {
152722
- path37 = path37.substring(3);
152952
+ path38 = path38.substring(3);
152723
152953
  } else if (twochars === "./") {
152724
- path37 = path37.substring(2);
152954
+ path38 = path38.substring(2);
152725
152955
  } else if (threechars === "/./") {
152726
- path37 = "/" + path37.substring(3);
152727
- } else if (twochars === "/." && path37.length === 2) {
152728
- path37 = "/";
152729
- } else if (fourchars === "/../" || threechars === "/.." && path37.length === 3) {
152730
- path37 = "/" + path37.substring(4);
152956
+ path38 = "/" + path38.substring(3);
152957
+ } else if (twochars === "/." && path38.length === 2) {
152958
+ path38 = "/";
152959
+ } else if (fourchars === "/../" || threechars === "/.." && path38.length === 3) {
152960
+ path38 = "/" + path38.substring(4);
152731
152961
  output = output.replace(/\/?[^\/]*$/, "");
152732
152962
  } else {
152733
- var segment = path37.match(/(\/?([^\/]*))/)[0];
152963
+ var segment = path38.match(/(\/?([^\/]*))/)[0];
152734
152964
  output += segment;
152735
- path37 = path37.substring(segment.length);
152965
+ path38 = path38.substring(segment.length);
152736
152966
  }
152737
152967
  }
152738
152968
  return output;
@@ -164802,21 +165032,21 @@ function jsonToKeyPathChunks(value, label = "$") {
164802
165032
  walk(value, label, out);
164803
165033
  return out;
164804
165034
  }
164805
- function walk(val, path37, out) {
165035
+ function walk(val, path38, out) {
164806
165036
  if (val === null || val === undefined)
164807
165037
  return;
164808
165038
  if (Array.isArray(val)) {
164809
165039
  if (val.length === 0) {
164810
- out.push({ path: path37, content: `**${path37}** = _[]_` });
165040
+ out.push({ path: path38, content: `**${path38}** = _[]_` });
164811
165041
  return;
164812
165042
  }
164813
165043
  if (val.every((v) => v !== null && typeof v === "object")) {
164814
- val.forEach((v, i) => walk(v, `${path37}[${i}]`, out));
165044
+ val.forEach((v, i) => walk(v, `${path38}[${i}]`, out));
164815
165045
  return;
164816
165046
  }
164817
165047
  const items = val.map((v) => `- \`${String(v)}\``).join(`
164818
165048
  `);
164819
- out.push({ path: path37, content: `**${path37}**
165049
+ out.push({ path: path38, content: `**${path38}**
164820
165050
 
164821
165051
  ${items}` });
164822
165052
  return;
@@ -164824,16 +165054,16 @@ ${items}` });
164824
165054
  if (typeof val === "object") {
164825
165055
  const entries = Object.entries(val);
164826
165056
  if (entries.length === 0) {
164827
- out.push({ path: path37, content: `**${path37}** = _{}_` });
165057
+ out.push({ path: path38, content: `**${path38}** = _{}_` });
164828
165058
  return;
164829
165059
  }
164830
165060
  for (const [k, v] of entries) {
164831
165061
  const safeKey = /^[A-Za-z_$][\w$]*$/.test(k) ? k : JSON.stringify(k);
164832
- walk(v, `${path37}.${safeKey}`, out);
165062
+ walk(v, `${path38}.${safeKey}`, out);
164833
165063
  }
164834
165064
  return;
164835
165065
  }
164836
- out.push({ path: path37, content: `**${path37}** = \`${String(val)}\`` });
165066
+ out.push({ path: path38, content: `**${path38}** = \`${String(val)}\`` });
164837
165067
  }
164838
165068
  var gfm, STRIP_SELECTORS, tdCache = null;
164839
165069
  var init_html_to_md = __esm(() => {
@@ -165173,6 +165403,7 @@ var init_services = __esm(() => {
165173
165403
  init_embeddings();
165174
165404
  init_local_health_checker();
165175
165405
  init_index_job_tracker();
165406
+ init_heavy_work_lease();
165176
165407
  init_scheduler2();
165177
165408
  init_models_dev_client();
165178
165409
  init_memory_graph_service();
@@ -165599,9 +165830,9 @@ var init_hook_service = __esm(() => {
165599
165830
  });
165600
165831
 
165601
165832
  // ../../packages/core/dist/services/bootstrap/bootstrap-service.js
165602
- import { randomUUID as randomUUID9 } from "crypto";
165833
+ import { randomUUID as randomUUID10 } from "crypto";
165603
165834
  import fs24 from "fs";
165604
- import path37 from "path";
165835
+ import path38 from "path";
165605
165836
  import { spawn as spawn2 } from "child_process";
165606
165837
  function readBootstrapConfig() {
165607
165838
  try {
@@ -165701,7 +165932,7 @@ class BootstrapService {
165701
165932
  return { ...noopResult("no-signals"), signalCount };
165702
165933
  }
165703
165934
  const capped = seeds.slice(0, cfg.maxSeedMemories);
165704
- const bootstrapId = `boot-${Date.now()}-${randomUUID9().slice(0, 8)}`;
165935
+ const bootstrapId = `boot-${Date.now()}-${randomUUID10().slice(0, 8)}`;
165705
165936
  let ids;
165706
165937
  try {
165707
165938
  ids = await storeSeeds(this.memoryRepo, projectId, bootstrapId, capped, signals);
@@ -165761,7 +165992,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
165761
165992
  }
165762
165993
  try {
165763
165994
  for (const name26 of README_CANDIDATES) {
165764
- const p = path37.join(projectRoot, name26);
165995
+ const p = path38.join(projectRoot, name26);
165765
165996
  if (fs24.existsSync(p) && fs24.statSync(p).isFile()) {
165766
165997
  const buf = fs24.readFileSync(p);
165767
165998
  signals.readme = buf.slice(0, MAX_README_BYTES).toString("utf8");
@@ -165772,14 +166003,14 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
165772
166003
  logger.debug("bootstrap scan: README read failed", { error: e.message });
165773
166004
  }
165774
166005
  try {
165775
- const docsDir = path37.join(projectRoot, "docs");
166006
+ const docsDir = path38.join(projectRoot, "docs");
165776
166007
  if (fs24.existsSync(docsDir) && fs24.statSync(docsDir).isDirectory()) {
165777
166008
  const entries = walkMarkdown(docsDir).slice(0, MAX_DOCS);
165778
166009
  for (const rel of entries) {
165779
166010
  try {
165780
166011
  const buf = fs24.readFileSync(rel);
165781
166012
  signals.docs.push({
165782
- path: path37.relative(projectRoot, rel),
166013
+ path: path38.relative(projectRoot, rel),
165783
166014
  snippet: buf.slice(0, MAX_DOC_BYTES).toString("utf8")
165784
166015
  });
165785
166016
  } catch {}
@@ -165790,7 +166021,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
165790
166021
  }
165791
166022
  try {
165792
166023
  for (const name26 of MANIFEST_FILES) {
165793
- const p = path37.join(projectRoot, name26);
166024
+ const p = path38.join(projectRoot, name26);
165794
166025
  if (!fs24.existsSync(p) || !fs24.statSync(p).isFile())
165795
166026
  continue;
165796
166027
  const raw2 = fs24.readFileSync(p).slice(0, MAX_MANIFEST_BYTES).toString("utf8");
@@ -165838,7 +166069,7 @@ function walkMarkdown(dir) {
165838
166069
  continue;
165839
166070
  }
165840
166071
  for (const e of entries) {
165841
- const full = path37.join(cur, e.name);
166072
+ const full = path38.join(cur, e.name);
165842
166073
  if (e.isDirectory()) {
165843
166074
  if (e.name === "node_modules" || e.name.startsWith("."))
165844
166075
  continue;
@@ -165955,7 +166186,7 @@ async function storeSeeds(memoryRepo, projectId, bootstrapId, seeds, signals) {
165955
166186
  const ids = [];
165956
166187
  const signalCount = countSignals(signals);
165957
166188
  for (const seed of seeds) {
165958
- const id = `seed-${Date.now()}-${randomUUID9().slice(0, 8)}`;
166189
+ const id = `seed-${Date.now()}-${randomUUID10().slice(0, 8)}`;
165959
166190
  const input = {
165960
166191
  id,
165961
166192
  content: truncate3(seed.summary, MAX_SUMMARY_CHARS),
@@ -166069,7 +166300,7 @@ var init_bootstrap_service = __esm(() => {
166069
166300
  MAX_DOC_BYTES = 2 * 1024;
166070
166301
  MAX_MANIFEST_BYTES = 2 * 1024;
166071
166302
  SeedMemorySchema = exports_external.object({
166072
- summary: exports_external.string().min(1).max(MAX_SUMMARY_CHARS),
166303
+ summary: exports_external.string().min(1),
166073
166304
  type: exports_external.enum(["pattern", "code", "decision"]),
166074
166305
  level: exports_external.union([exports_external.literal(0), exports_external.literal(1), exports_external.literal(2)]),
166075
166306
  importance: exports_external.number().min(0).max(1),
@@ -166662,7 +166893,9 @@ var init_handoff_auto_injector = __esm(() => {
166662
166893
  var exports_dist = {};
166663
166894
  __export(exports_dist, {
166664
166895
  workspaceManager: () => workspaceManager,
166896
+ withHeavyWorkLease: () => withHeavyWorkLease,
166665
166897
  validateEvent: () => validateEvent,
166898
+ validateEnum: () => validateEnum,
166666
166899
  validateAllGrammars: () => validateAllGrammars,
166667
166900
  tracePathService: () => tracePathService,
166668
166901
  toSymbolIdentityResolution: () => toSymbolIdentityResolution,
@@ -166706,6 +166939,7 @@ __export(exports_dist, {
166706
166939
  recordSearchDegradation: () => recordSearchDegradation,
166707
166940
  quoteDiscoveredIdentifier: () => quoteDiscoveredIdentifier,
166708
166941
  projectNotIndexed: () => projectNotIndexed,
166942
+ probeHeavyWork: () => probeHeavyWork,
166709
166943
  payloadStorePolicies: () => payloadStorePolicies,
166710
166944
  parseStructuralFqn: () => parseStructuralFqn,
166711
166945
  parseProjectIdentityPreviewRequest: () => parseProjectIdentityPreviewRequest,
@@ -166836,6 +167070,7 @@ __export(exports_dist, {
166836
167070
  UNKNOWN_ACTOR: () => UNKNOWN_ACTOR,
166837
167071
  TracePathTool: () => TracePathTool,
166838
167072
  TracePathService: () => TracePathService,
167073
+ ToolError: () => ToolError,
166839
167074
  TokenMetrics: () => TokenMetrics,
166840
167075
  TaskEnvelopeService: () => TaskEnvelopeService,
166841
167076
  TYPESCRIPT_RESOLVER_VERSION: () => TYPESCRIPT_RESOLVER_VERSION,
@@ -167012,6 +167247,7 @@ var init_dist15 = __esm(() => {
167012
167247
  init_proposal_repository();
167013
167248
  init_proposal_payload_validation();
167014
167249
  init_auto_improve_job();
167250
+ init_enum_validation();
167015
167251
  init_tools();
167016
167252
  init_services();
167017
167253
  init_graph_generation();
@@ -169479,7 +169715,7 @@ init_dist();
169479
169715
  init_dist15();
169480
169716
  init_dist();
169481
169717
  import fs25 from "fs/promises";
169482
- import path38 from "path";
169718
+ import path39 from "path";
169483
169719
  var _indexProjectTool = null;
169484
169720
  function indexProjectTool() {
169485
169721
  if (!_indexProjectTool)
@@ -169782,7 +170018,7 @@ class EmbeddedApiClient {
169782
170018
  } else {
169783
170019
  end = start + 20;
169784
170020
  }
169785
- const absolutePath = path38.join(workspace.project_path, file2);
170021
+ const absolutePath = path39.join(workspace.project_path, file2);
169786
170022
  const content = await fs25.readFile(absolutePath, "utf-8");
169787
170023
  const lines = content.split(/\r?\n/);
169788
170024
  const slice = lines.slice(start - 1, Math.min(lines.length, end));
@@ -170038,21 +170274,21 @@ class EmbeddedApiClient {
170038
170274
  async uploadAndIndex(params) {
170039
170275
  const rawBase = params.projectId || params.projectPath.replace(/\\/g, "/").split("/").filter(Boolean).pop() || "default";
170040
170276
  const finalProjectId = rawBase.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 128);
170041
- const uploadRoot = process.env.MASSA_AI_UPLOAD_DIR || path38.join(getGlobalDataDir(), "uploads");
170042
- const stagingDir = path38.resolve(uploadRoot, finalProjectId);
170277
+ const uploadRoot = process.env.MASSA_AI_UPLOAD_DIR || path39.join(getGlobalDataDir(), "uploads");
170278
+ const stagingDir = path39.resolve(uploadRoot, finalProjectId);
170043
170279
  await fs25.rm(stagingDir, { recursive: true, force: true });
170044
170280
  await fs25.mkdir(stagingDir, { recursive: true });
170045
170281
  const WRITE_BATCH = 20;
170046
170282
  for (let i = 0;i < params.files.length; i += WRITE_BATCH) {
170047
170283
  await Promise.all(params.files.slice(i, i + WRITE_BATCH).map(async (file2) => {
170048
- if (path38.isAbsolute(file2.relativePath) || file2.relativePath.includes("..")) {
170284
+ if (path39.isAbsolute(file2.relativePath) || file2.relativePath.includes("..")) {
170049
170285
  throw new Error(`Invalid file path: ${file2.relativePath}`);
170050
170286
  }
170051
- const dest = path38.resolve(stagingDir, file2.relativePath.replace(/\//g, path38.sep));
170052
- if (!dest.startsWith(stagingDir + path38.sep)) {
170287
+ const dest = path39.resolve(stagingDir, file2.relativePath.replace(/\//g, path39.sep));
170288
+ if (!dest.startsWith(stagingDir + path39.sep)) {
170053
170289
  throw new Error(`Path escapes staging directory: ${file2.relativePath}`);
170054
170290
  }
170055
- await fs25.mkdir(path38.dirname(dest), { recursive: true });
170291
+ await fs25.mkdir(path39.dirname(dest), { recursive: true });
170056
170292
  await fs25.writeFile(dest, file2.content, "utf-8");
170057
170293
  }));
170058
170294
  }
@@ -170112,37 +170348,39 @@ class EmbeddedApiClient {
170112
170348
  return { success: false, error: "projectId is required" };
170113
170349
  const result = {};
170114
170350
  const errors4 = [];
170115
- if (clearVectors) {
170116
- try {
170117
- const vectorStore = await getVectorStore();
170118
- const keywordSearch = getKeywordSearch();
170119
- const [vectorsDeleted, keywordsDeleted] = await Promise.all([
170120
- vectorStore.deleteByProject(projectId),
170121
- keywordSearch.deleteByProject(projectId)
170122
- ]);
170123
- result.vectorsDeleted = vectorsDeleted;
170124
- result.keywordsDeleted = keywordsDeleted;
170125
- } catch (e) {
170126
- errors4.push(`vectors: ${e.message}`);
170351
+ await withHeavyWorkLease("maintenance", `project-reset:${projectId}`, async () => {
170352
+ if (clearVectors) {
170353
+ try {
170354
+ const vectorStore = await getVectorStore();
170355
+ const keywordSearch = getKeywordSearch();
170356
+ const [vectorsDeleted, keywordsDeleted] = await Promise.all([
170357
+ vectorStore.deleteByProject(projectId),
170358
+ keywordSearch.deleteByProject(projectId)
170359
+ ]);
170360
+ result.vectorsDeleted = vectorsDeleted;
170361
+ result.keywordsDeleted = keywordsDeleted;
170362
+ } catch (e) {
170363
+ errors4.push(`vectors: ${e.message}`);
170364
+ }
170127
170365
  }
170128
- }
170129
- if (clearSymbols) {
170130
- try {
170131
- await workspaceManager.removeWorkspace(projectId);
170132
- result.symbolsDeleted = "ok";
170133
- } catch (e) {
170134
- errors4.push(`symbols: ${e.message}`);
170366
+ if (clearSymbols) {
170367
+ try {
170368
+ await workspaceManager.removeWorkspace(projectId);
170369
+ result.symbolsDeleted = "ok";
170370
+ } catch (e) {
170371
+ errors4.push(`symbols: ${e.message}`);
170372
+ }
170135
170373
  }
170136
- }
170137
- if (clearMemories) {
170138
- try {
170139
- const repo = getMemoryRepository();
170140
- const deleted = await repo.deleteByProject(projectId);
170141
- result.memoriesDeleted = deleted;
170142
- } catch (e) {
170143
- errors4.push(`memories: ${e.message}`);
170374
+ if (clearMemories) {
170375
+ try {
170376
+ const repo = getMemoryRepository();
170377
+ const deleted = await repo.deleteByProject(projectId);
170378
+ result.memoriesDeleted = deleted;
170379
+ } catch (e) {
170380
+ errors4.push(`memories: ${e.message}`);
170381
+ }
170144
170382
  }
170145
- }
170383
+ });
170146
170384
  return {
170147
170385
  success: errors4.length === 0,
170148
170386
  data: { projectId, ...result, errors: errors4, message: `Project '${projectId}' reset complete.` }
@@ -170554,7 +170792,7 @@ class EmbeddedApiClient {
170554
170792
  // src/file-collector.ts
170555
170793
  init_config();
170556
170794
  import fs26 from "fs/promises";
170557
- import path39 from "path";
170795
+ import path40 from "path";
170558
170796
  var SKIP_DIRS = new Set([
170559
170797
  "node_modules",
170560
170798
  ".git",
@@ -170570,11 +170808,21 @@ var SKIP_DIRS = new Set([
170570
170808
  ".cache",
170571
170809
  "vendor",
170572
170810
  ".svn",
170573
- ".hg"
170811
+ ".hg",
170812
+ "Pods"
170574
170813
  ]);
170575
170814
  var MAX_FILE_BYTES = 512 * 1024;
170576
- var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
170577
- var MAX_FILES = 3000;
170815
+ var MAX_TOTAL_BYTES = 150 * 1024 * 1024;
170816
+ var MAX_FILES = 15000;
170817
+ async function getIncludeDirs(projectPath2) {
170818
+ try {
170819
+ const raw2 = await fs26.readFile(path40.join(projectPath2, ".massa-ai-collect"), "utf-8");
170820
+ return raw2.split(`
170821
+ `).map((s) => s.trim().replace(/^\/+|\/+$/g, "")).filter((s) => s && !s.startsWith("#"));
170822
+ } catch {
170823
+ return [];
170824
+ }
170825
+ }
170578
170826
  function getAllowedExtensions() {
170579
170827
  try {
170580
170828
  const list = config2.get("security").allowedExtensions;
@@ -170587,7 +170835,16 @@ async function collectFiles(projectPath2) {
170587
170835
  const files = [];
170588
170836
  const state = { totalBytes: 0 };
170589
170837
  const allowed = getAllowedExtensions();
170590
- await walk2(projectPath2, projectPath2, files, state, allowed);
170838
+ const includeDirs = await getIncludeDirs(projectPath2);
170839
+ if (includeDirs.length === 0) {
170840
+ await walk2(projectPath2, projectPath2, files, state, allowed);
170841
+ } else {
170842
+ for (const top of includeDirs) {
170843
+ if (files.length >= MAX_FILES || state.totalBytes >= MAX_TOTAL_BYTES)
170844
+ break;
170845
+ await walk2(projectPath2, path40.join(projectPath2, top), files, state, allowed);
170846
+ }
170847
+ }
170591
170848
  return files;
170592
170849
  }
170593
170850
  async function walk2(root2, dir, files, state, allowed) {
@@ -170604,13 +170861,13 @@ async function walk2(root2, dir, files, state, allowed) {
170604
170861
  break;
170605
170862
  if (entry2.isDirectory()) {
170606
170863
  if (!SKIP_DIRS.has(entry2.name) && !entry2.name.startsWith(".")) {
170607
- await walk2(root2, path39.join(dir, entry2.name), files, state, allowed);
170864
+ await walk2(root2, path40.join(dir, entry2.name), files, state, allowed);
170608
170865
  }
170609
170866
  } else if (entry2.isFile()) {
170610
- const ext2 = path39.extname(entry2.name).toLowerCase();
170867
+ const ext2 = path40.extname(entry2.name).toLowerCase();
170611
170868
  if (!allowed.has(ext2))
170612
170869
  continue;
170613
- const fullPath = path39.join(dir, entry2.name);
170870
+ const fullPath = path40.join(dir, entry2.name);
170614
170871
  try {
170615
170872
  const stat = await fs26.stat(fullPath);
170616
170873
  if (stat.size > MAX_FILE_BYTES)
@@ -170619,7 +170876,7 @@ async function walk2(root2, dir, files, state, allowed) {
170619
170876
  continue;
170620
170877
  const content = await fs26.readFile(fullPath, "utf-8");
170621
170878
  state.totalBytes += stat.size;
170622
- const relativePath = path39.relative(root2, fullPath).split(path39.sep).join("/");
170879
+ const relativePath = path40.relative(root2, fullPath).split(path40.sep).join("/");
170623
170880
  files.push({ relativePath, content });
170624
170881
  } catch {}
170625
170882
  }