@massa-ai/mcp-client 1.64.0 → 1.66.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 +408 -165
  2. package/dist/index.js +1104 -835
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -35187,7 +35187,8 @@ var init_ignore_patterns = __esm(() => {
35187
35187
  "**/pnpm-lock.yaml",
35188
35188
  "**/package-lock.json",
35189
35189
  "**/bun.lockb",
35190
- "**/yarn.lock"
35190
+ "**/yarn.lock",
35191
+ "**/Pods/**"
35191
35192
  ];
35192
35193
  });
35193
35194
 
@@ -124305,6 +124306,33 @@ class ManagedRunRepositoryPg {
124305
124306
  `;
124306
124307
  return rows[0] ? toActive(rows[0]) : null;
124307
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
+ }
124308
124336
  }
124309
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;
124310
124338
  var init_managed_run_repository_pg = __esm(() => {
@@ -124342,10 +124370,111 @@ var init_embedding_freshness = __esm(() => {
124342
124370
  };
124343
124371
  });
124344
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
+
124345
124474
  // ../../packages/core/dist/services/search/project-indexer.js
124346
124475
  import fs15 from "fs/promises";
124347
- import path21 from "path";
124348
- import { randomUUID as randomUUID3 } from "crypto";
124476
+ import path22 from "path";
124477
+ import { randomUUID as randomUUID4 } from "crypto";
124349
124478
  async function runWithIndexLock(lockMap, projectId, work) {
124350
124479
  const prevLock = lockMap.get(projectId);
124351
124480
  const isQueued = prevLock !== undefined;
@@ -124387,7 +124516,7 @@ async function indexProjectInternal(deps, projectPath, projectId, options = {})
124387
124516
  dot: false
124388
124517
  });
124389
124518
  const filteredFiles = files.filter((file2) => {
124390
- const relativePath = path21.relative(projectPath, file2);
124519
+ const relativePath = path22.relative(projectPath, file2);
124391
124520
  const shouldIgnore = ig.ignores(relativePath);
124392
124521
  if (shouldIgnore) {
124393
124522
  logger.debug("Ignoring file per .gitignore during indexing", {
@@ -124427,7 +124556,7 @@ async function indexProjectInternal(deps, projectPath, projectId, options = {})
124427
124556
  });
124428
124557
  }
124429
124558
  }
124430
- const indexedFilesList = filteredFiles.map((f) => path21.relative(projectPath, f));
124559
+ const indexedFilesList = filteredFiles.map((f) => path22.relative(projectPath, f));
124431
124560
  await deps.indexManager.updateIndexMetadata(projectId, projectPath, indexedFilesList);
124432
124561
  logger.info("Project indexing completed", {
124433
124562
  projectId,
@@ -124498,7 +124627,7 @@ async function ensureFreshIndex(deps, projectId, projectPath, options = {}) {
124498
124627
  if (needsFullReindex) {
124499
124628
  logger.info("Performing full reindex", { projectId });
124500
124629
  const managedRunRepo = ManagedRunRepositoryPg.getInstance();
124501
- const eventId = `reindex:${projectId}:${randomUUID3()}`;
124630
+ const eventId = `reindex:${projectId}:${randomUUID4()}`;
124502
124631
  const beginOutcome = await managedRunRepo.begin({
124503
124632
  projectId,
124504
124633
  runKind: "indexing",
@@ -124551,25 +124680,7 @@ async function ensureFreshIndex(deps, projectId, projectPath, options = {}) {
124551
124680
  projectId,
124552
124681
  fileCount: filesToReindex.length
124553
124682
  });
124554
- const centralityMap = await deps.symbolRepo.getCentrality(await getProjectIdentityAliasResolver().resolve(projectId));
124555
- let filesIndexed = 0;
124556
- let chunksIndexed = 0;
124557
- let errors4 = 0;
124558
- for (const relativeFilePath of filesToReindex) {
124559
- try {
124560
- const fullPath = path21.join(projectPath, relativeFilePath);
124561
- const result = await deps.indexFile(fullPath, projectId, projectPath, centralityMap);
124562
- filesIndexed++;
124563
- chunksIndexed += result.chunks;
124564
- } catch (error51) {
124565
- logger.error("Failed to reindex file", error51, {
124566
- file: relativeFilePath
124567
- });
124568
- errors4++;
124569
- }
124570
- }
124571
- await deps.indexManager.updateIndexMetadata(projectId, projectPath, filesToReindex);
124572
- await deps.searchCache.invalidateProject(projectId);
124683
+ const { filesIndexed, chunksIndexed, errors: errors4 } = await runIncrementalReindex(deps, projectId, projectPath, filesToReindex);
124573
124684
  logger.info("Incremental reindex completed", {
124574
124685
  projectId,
124575
124686
  filesIndexed,
@@ -124618,7 +124729,7 @@ async function checkSearchAdmission(deps, projectId, projectPath) {
124618
124729
  async function indexFile(deps, filePath, projectId, projectRoot, centralityMap) {
124619
124730
  projectId = await getProjectIdentityAliasResolver().resolve(projectId);
124620
124731
  const content = await fs15.readFile(filePath, "utf-8");
124621
- const relativePath = path21.relative(projectRoot, filePath);
124732
+ const relativePath = path22.relative(projectRoot, filePath);
124622
124733
  const maxFileSize = config2.get("security").maxFileSize || 1024 * 1024;
124623
124734
  if (content.length > maxFileSize) {
124624
124735
  logger.warn("File too large, skipping", {
@@ -124638,7 +124749,7 @@ async function indexFile(deps, filePath, projectId, projectRoot, centralityMap)
124638
124749
  chunkIndex: i,
124639
124750
  totalChunks: chunks.length,
124640
124751
  type: chunk.type,
124641
- language: path21.extname(filePath).slice(1),
124752
+ language: path22.extname(filePath).slice(1),
124642
124753
  lineStart: chunk.lineStart,
124643
124754
  lineEnd: chunk.lineEnd,
124644
124755
  label: chunk.label,
@@ -124663,6 +124774,7 @@ var init_project_indexer = __esm(() => {
124663
124774
  init_managed_run_repository_pg();
124664
124775
  init_symbol_repo_workspace();
124665
124776
  init_embedding_freshness();
124777
+ init_incremental_reindex();
124666
124778
  globAsync2 = glob;
124667
124779
  });
124668
124780
 
@@ -126482,7 +126594,7 @@ var init_index_job_store = __esm(() => {
126482
126594
  });
126483
126595
 
126484
126596
  // ../../packages/core/dist/services/jobs/index-job-tracker.js
126485
- import { randomUUID as randomUUID4 } from "crypto";
126597
+ import { randomUUID as randomUUID5 } from "crypto";
126486
126598
 
126487
126599
  class IndexJobTracker {
126488
126600
  static instance;
@@ -126506,7 +126618,7 @@ class IndexJobTracker {
126506
126618
  return IndexJobTracker.instance;
126507
126619
  }
126508
126620
  createJob(projectId, projectPath) {
126509
- const jobId = randomUUID4();
126621
+ const jobId = randomUUID5();
126510
126622
  const job = {
126511
126623
  jobId,
126512
126624
  projectId,
@@ -126596,7 +126708,9 @@ class IndexJobTracker {
126596
126708
  const cutoff = now2 - staleMs;
126597
126709
  let reaped = 0;
126598
126710
  for (const job of running) {
126599
- 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();
126600
126714
  const startedMs = job.startedAt?.getTime();
126601
126715
  const stale = hbMs != null && hbMs < cutoff || hbMs == null && startedMs != null && startedMs < cutoff;
126602
126716
  if (!stale)
@@ -126710,7 +126824,7 @@ function stripNul(content) {
126710
126824
 
126711
126825
  // ../../packages/core/dist/services/etl/stages/discover.js
126712
126826
  import fs16 from "fs/promises";
126713
- import path22 from "path";
126827
+ import path23 from "path";
126714
126828
  import { createHash as createHash5 } from "crypto";
126715
126829
 
126716
126830
  class DiscoverStage {
@@ -126736,7 +126850,7 @@ class DiscoverStage {
126736
126850
  dot: false,
126737
126851
  absolute: false
126738
126852
  });
126739
- 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");
126740
126854
  }
126741
126855
  if (ctx.resumeCursor?.path) {
126742
126856
  const cursorPath = ctx.resumeCursor.path;
@@ -126795,7 +126909,7 @@ class DiscoverStage {
126795
126909
  return discovered;
126796
126910
  }
126797
126911
  async processFile(ctx, relativePath, forceReindex) {
126798
- const absolutePath = path22.join(ctx.projectPath, relativePath);
126912
+ const absolutePath = path23.join(ctx.projectPath, relativePath);
126799
126913
  try {
126800
126914
  const stat = await fs16.stat(absolutePath);
126801
126915
  const content = stripNul(await fs16.readFile(absolutePath, "utf-8"));
@@ -126842,7 +126956,7 @@ class DiscoverStage {
126842
126956
  ig.add(pattern);
126843
126957
  }
126844
126958
  try {
126845
- const gitignorePath = path22.join(projectPath, ".gitignore");
126959
+ const gitignorePath = path23.join(projectPath, ".gitignore");
126846
126960
  const gitignoreContent = await fs16.readFile(gitignorePath, "utf8");
126847
126961
  const rules = gitignoreContent.split(`
126848
126962
  `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
@@ -128198,8 +128312,8 @@ function rustUseLeaves(node, source, prefix = []) {
128198
128312
  }
128199
128313
  if (node.type === "use_wildcard")
128200
128314
  return [{ path: [...prefix, "*"], glob: true }];
128201
- const path23 = rustPathSegments(node, source);
128202
- return path23.length ? [{ path: [...prefix, ...path23] }] : [];
128315
+ const path24 = rustPathSegments(node, source);
128316
+ return path24.length ? [{ path: [...prefix, ...path24] }] : [];
128203
128317
  }
128204
128318
  function functionalCaptures(captures, source, family) {
128205
128319
  if (family !== "clojure")
@@ -129171,7 +129285,7 @@ var init_structural_runtime = __esm(() => {
129171
129285
  });
129172
129286
 
129173
129287
  // ../../packages/core/dist/services/etl/stages/parse.js
129174
- import path23 from "path";
129288
+ import path24 from "path";
129175
129289
  import fs17 from "fs/promises";
129176
129290
  function resolveChunkerMaxChars() {
129177
129291
  const global2 = Number(process.env.EMBEDDING_MAX_CHARS);
@@ -129200,8 +129314,8 @@ class ParseStage {
129200
129314
  const results = new Map;
129201
129315
  let processed = 0;
129202
129316
  const phases = [
129203
- files.filter((file2) => path23.extname(file2.relativePath).toLowerCase() !== ".h"),
129204
- 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")
129205
129319
  ];
129206
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)));
129207
129321
  for (const batch of batches) {
@@ -129239,19 +129353,19 @@ class ParseStage {
129239
129353
  return files.map((file2) => results.get(file2.relativePath));
129240
129354
  }
129241
129355
  recordHeaderImporterEvidence(ctx, files, parsedFiles) {
129242
- 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)));
129243
129357
  const mutable = {
129244
129358
  ...ctx.structuralHeaderEvidenceByFile
129245
129359
  };
129246
129360
  for (const parsed of parsedFiles) {
129247
- const extension = path23.extname(parsed.file.relativePath).toLowerCase();
129361
+ const extension = path24.extname(parsed.file.relativePath).toLowerCase();
129248
129362
  const key = extension === ".c" ? "cImporters" : [".cpp", ".hpp"].includes(extension) ? "cppImporters" : undefined;
129249
129363
  if (!key)
129250
129364
  continue;
129251
129365
  for (const imported of parsed.rawImports) {
129252
129366
  if (!["c_include", "cpp_include"].includes(imported.form) || imported.specifier.startsWith("<"))
129253
129367
  continue;
129254
- 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));
129255
129369
  if (!knownHeaders.has(header))
129256
129370
  continue;
129257
129371
  const existing = mutable[header] ?? {};
@@ -129262,7 +129376,7 @@ class ParseStage {
129262
129376
  }
129263
129377
  async parseFile(ctx, file2) {
129264
129378
  if (!file2.needsReparse) {
129265
- const extension = path23.extname(file2.relativePath).toLowerCase();
129379
+ const extension = path24.extname(file2.relativePath).toLowerCase();
129266
129380
  if ([".c", ".cpp", ".hpp"].includes(extension)) {
129267
129381
  const content = file2.snapshotContent ?? await fs17.readFile(file2.absolutePath, "utf8");
129268
129382
  const outcome = await this.runtime.parse({ extension, source: Buffer.from(content) });
@@ -129277,7 +129391,7 @@ class ParseStage {
129277
129391
  }
129278
129392
  try {
129279
129393
  const content = file2.snapshotContent ?? await fs17.readFile(file2.absolutePath, "utf-8");
129280
- const ext2 = path23.extname(file2.relativePath).toLowerCase();
129394
+ const ext2 = path24.extname(file2.relativePath).toLowerCase();
129281
129395
  const chunkerMaxChars = resolveChunkerMaxChars();
129282
129396
  const chunks = smartChunk(content, file2.relativePath, chunkerMaxChars ? { maxChunkChars: chunkerMaxChars } : {});
129283
129397
  let symbols;
@@ -129832,7 +129946,7 @@ var init_resolver = __esm(() => {
129832
129946
  });
129833
129947
 
129834
129948
  // ../../packages/core/dist/services/structural/resolvers/typescript.js
129835
- import path24 from "path";
129949
+ import path25 from "path";
129836
129950
  function candidates(identities) {
129837
129951
  return Object.freeze(identities.map((identity) => Object.freeze({
129838
129952
  fqn: identity.fqn,
@@ -129927,7 +130041,7 @@ function probe(base, known, dialect = "typescript") {
129927
130041
  const bases = /\.[cm]?jsx?$/u.test(base) ? [base.replace(/\.[cm]?jsx?$/u, ".ts"), base.replace(/\.[cm]?jsx?$/u, ".tsx"), base] : [base];
129928
130042
  for (const candidateBase of bases)
129929
130043
  for (const suffix of DIALECT_PROBES[dialect] ?? [""]) {
129930
- const value = path24.posix.normalize(`${candidateBase}${suffix}`);
130044
+ const value = path25.posix.normalize(`${candidateBase}${suffix}`);
129931
130045
  if (!value.startsWith("../") && value !== ".." && known.has(value))
129932
130046
  return value;
129933
130047
  }
@@ -129936,7 +130050,7 @@ function probe(base, known, dialect = "typescript") {
129936
130050
  function resolveStructuralSpecifier(specifier, fromFile, build, dialect = "typescript") {
129937
130051
  const known = new Set(build.knownFiles.map(normalizeStructuralFile));
129938
130052
  if (specifier.startsWith("./") || specifier.startsWith("../")) {
129939
- 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);
129940
130054
  }
129941
130055
  const aliases = build.pathAliasesByFile?.[normalizeStructuralFile(fromFile)] ?? build.pathAliases ?? [];
129942
130056
  for (const alias of aliases) {
@@ -130200,7 +130314,7 @@ var init_scripting2 = __esm(() => {
130200
130314
  });
130201
130315
 
130202
130316
  // ../../packages/core/dist/services/structural/resolvers/systems.js
130203
- import path25 from "path";
130317
+ import path26 from "path";
130204
130318
  var DIALECTS, SYSTEMS_LANGUAGE_RESOLVER;
130205
130319
  var init_systems2 = __esm(() => {
130206
130320
  init_typescript2();
@@ -130219,7 +130333,7 @@ var init_systems2 = __esm(() => {
130219
130333
  const bindings = item.bindings.map((binding) => binding.imported === "*" && binding.local === "*" && unresolvedTarget && !unresolvedTarget.qualifier ? { ...binding, imported: unresolvedTarget.name, local: unresolvedTarget.name } : binding);
130220
130334
  if (item.specifier === "crate" || item.specifier.startsWith("crate/")) {
130221
130335
  const crateRoot = file2.file.startsWith("src/") ? "src" : "";
130222
- 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, "")))}` };
130223
130337
  }
130224
130338
  if (item.specifier === "self" || item.specifier.startsWith("self/"))
130225
130339
  return { ...item, bindings, specifier: `./${item.specifier.replace(/^self\/?/u, "")}` };
@@ -130317,7 +130431,7 @@ var init_data_document2 = __esm(() => {
130317
130431
  });
130318
130432
 
130319
130433
  // ../../packages/core/dist/services/etl/stages/resolve.js
130320
- import path26 from "path";
130434
+ import path27 from "path";
130321
130435
  import fs18 from "fs";
130322
130436
 
130323
130437
  class ResolveStage {
@@ -130342,7 +130456,7 @@ class ResolveStage {
130342
130456
  const structuralDocuments = files.flatMap((file2) => {
130343
130457
  if (!file2.structure)
130344
130458
  return [];
130345
- const language = resolveStructuralLanguage(path26.extname(file2.file.relativePath));
130459
+ const language = resolveStructuralLanguage(path27.extname(file2.file.relativePath));
130346
130460
  if (language.status !== "supported")
130347
130461
  throw new Error(`structural_manifest_missing:${file2.file.relativePath}`);
130348
130462
  return [{
@@ -130354,13 +130468,13 @@ class ResolveStage {
130354
130468
  }];
130355
130469
  });
130356
130470
  const currentStructuralFiles = new Set(structuralDocuments.map((document2) => document2.file));
130357
- 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));
130358
130472
  const pathAliasesByFile = Object.fromEntries([...knownRelPaths].map((file2) => [
130359
130473
  file2,
130360
130474
  this.structuralAliasesFor(file2, rootAliases, monorepoPackages)
130361
130475
  ]));
130362
130476
  const buildMetadata = { knownFiles: [...knownRelPaths], pathAliasesByFile };
130363
- 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));
130364
130478
  const seedIds = new Set;
130365
130479
  for (const definition of seedRows) {
130366
130480
  if (seedIds.has(definition.id))
@@ -130457,7 +130571,7 @@ class ResolveStage {
130457
130571
  if (parsed.file !== definition.file_path) {
130458
130572
  throw new Error(`structural_repository_seed_file_mismatch:${definition.id}`);
130459
130573
  }
130460
- const language = resolveStructuralLanguage(path26.extname(definition.file_path));
130574
+ const language = resolveStructuralLanguage(path27.extname(definition.file_path));
130461
130575
  if (language.status !== "supported")
130462
130576
  throw new Error(`structural_repository_seed_language:${definition.id}`);
130463
130577
  let identity;
@@ -130509,7 +130623,7 @@ class ResolveStage {
130509
130623
  });
130510
130624
  }
130511
130625
  resolveFile(parsed, projectPath, knownRelPaths, rootAliases, monorepoPackages, symbolIndex, knownFqns) {
130512
- const fromDir = path26.dirname(path26.join(projectPath, parsed.file.relativePath));
130626
+ const fromDir = path27.dirname(path27.join(projectPath, parsed.file.relativePath));
130513
130627
  const packageAliases = this.getPackageAliases(parsed.file.relativePath, monorepoPackages);
130514
130628
  const allAliases = [...packageAliases, ...rootAliases];
130515
130629
  const resolvedImports = parsed.rawImports.map((raw2) => {
@@ -130580,7 +130694,7 @@ class ResolveStage {
130580
130694
  index.set(def.name, `${def.file_path}#${def.name}`);
130581
130695
  }
130582
130696
  } catch (err) {
130583
- 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()));
130584
130698
  if (skippedStructural)
130585
130699
  throw new Error("structural_repository_seed_failed", { cause: err });
130586
130700
  logger.warn("buildSymbolIndex: repo seed failed, in-batch only", {
@@ -130604,7 +130718,7 @@ class ResolveStage {
130604
130718
  }
130605
130719
  resolveSpecifier(specifier, fromDir, projectPath, knownRelPaths, aliases) {
130606
130720
  if (specifier.startsWith("./") || specifier.startsWith("../")) {
130607
- const resolved = this.probeExtensions(path26.resolve(fromDir, specifier), projectPath, knownRelPaths);
130721
+ const resolved = this.probeExtensions(path27.resolve(fromDir, specifier), projectPath, knownRelPaths);
130608
130722
  return { resolvedPath: resolved, external: false };
130609
130723
  }
130610
130724
  for (const alias of aliases) {
@@ -130612,8 +130726,8 @@ class ResolveStage {
130612
130726
  const suffix = specifier.slice(alias.prefix.length);
130613
130727
  for (const target of alias.targets) {
130614
130728
  const cleanTarget = target.replace(/\/\*$/, "");
130615
- const basePath = alias.packagePath ? path26.join(projectPath, alias.packagePath) : projectPath;
130616
- 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);
130617
130731
  const resolved = this.probeExtensions(absPath, projectPath, knownRelPaths);
130618
130732
  if (resolved)
130619
130733
  return { resolvedPath: resolved, external: false };
@@ -130629,7 +130743,7 @@ class ResolveStage {
130629
130743
  ...TS_EXTENSIONS.map((ext2) => absPath.replace(/\.[^.]+$/, ext2))
130630
130744
  ];
130631
130745
  for (const candidate2 of candidates2) {
130632
- const rel = path26.relative(projectPath, candidate2).replace(/\\/g, "/");
130746
+ const rel = path27.relative(projectPath, candidate2).replace(/\\/g, "/");
130633
130747
  if (knownRelPaths.has(rel))
130634
130748
  return rel;
130635
130749
  }
@@ -130637,7 +130751,7 @@ class ResolveStage {
130637
130751
  }
130638
130752
  loadTsConfigPaths(projectPath, packageBase) {
130639
130753
  const aliases = [];
130640
- const tsconfigPath = path26.join(projectPath, "tsconfig.json");
130754
+ const tsconfigPath = path27.join(projectPath, "tsconfig.json");
130641
130755
  try {
130642
130756
  const raw2 = fs18.readFileSync(tsconfigPath, "utf-8");
130643
130757
  const stripped = raw2.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
@@ -130668,7 +130782,7 @@ class ResolveStage {
130668
130782
  }
130669
130783
  }
130670
130784
  for (const packageRelPath of packagePaths) {
130671
- const absPackagePath = path26.join(projectPath, packageRelPath);
130785
+ const absPackagePath = path27.join(projectPath, packageRelPath);
130672
130786
  const aliases = this.loadTsConfigPaths(absPackagePath, packageRelPath);
130673
130787
  if (aliases.length > 0) {
130674
130788
  packages.push({
@@ -130698,7 +130812,7 @@ class ResolveStage {
130698
130812
  structuralAliasesFor(filePath, rootAliases, packages) {
130699
130813
  return [...this.getPackageAliases(filePath, packages), ...rootAliases].map((alias) => ({
130700
130814
  pattern: alias.prefix + (alias.targets.some((target) => target.includes("*")) ? "/*" : ""),
130701
- 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)
130702
130816
  }));
130703
130817
  }
130704
130818
  }
@@ -130762,7 +130876,7 @@ var init_with_deadlock_retry = __esm(() => {
130762
130876
  });
130763
130877
 
130764
130878
  // ../../packages/core/dist/services/etl/stages/load.js
130765
- import path27 from "path";
130879
+ import path28 from "path";
130766
130880
  function formatDuration(ms) {
130767
130881
  const totalSec = Math.max(0, Math.round(ms / 1000));
130768
130882
  if (totalSec < 60)
@@ -131039,7 +131153,7 @@ class LoadStage {
131039
131153
  const filePath = file2.file.relativePath;
131040
131154
  const batch = buildSymbolPersistenceBatch(ctx.projectId, file2);
131041
131155
  if (ctx.graphGenerationLease) {
131042
- const manifest = getLanguageManifestEntry(path27.extname(filePath));
131156
+ const manifest = getLanguageManifestEntry(path28.extname(filePath));
131043
131157
  const diagnostics2 = (file2.structuralDiagnostics ?? []).slice(0, 10).map((diagnostic2) => ({
131044
131158
  code: diagnostic2.code,
131045
131159
  severity: diagnostic2.severity,
@@ -131091,7 +131205,7 @@ var init_load = __esm(() => {
131091
131205
  });
131092
131206
 
131093
131207
  // ../../packages/core/dist/data/graph-generation/graph-generation-repository-pg.js
131094
- import { randomUUID as randomUUID5 } from "crypto";
131208
+ import { randomUUID as randomUUID6 } from "crypto";
131095
131209
  function boundedText2(value, label, max = 512) {
131096
131210
  const normalized = value.normalize("NFC").trim();
131097
131211
  if (!normalized || normalized.length > max || normalized.includes("\x00")) {
@@ -131195,8 +131309,8 @@ class GraphGenerationRepositoryPg {
131195
131309
  }
131196
131310
  async begin(rawInput) {
131197
131311
  const input = validateBegin2(rawInput);
131198
- const generationId = randomUUID5();
131199
- const leaseToken = randomUUID5();
131312
+ const generationId = randomUUID6();
131313
+ const leaseToken = randomUUID6();
131200
131314
  return getPrismaClient2().$transaction(async (tx) => {
131201
131315
  const workspace = await lockWorkspace(tx, input.projectId);
131202
131316
  if (workspace.active_graph_generation_id !== input.expectedActiveGenerationId) {
@@ -131436,8 +131550,8 @@ function buildGraphInputSnapshotHash(files) {
131436
131550
 
131437
131551
  class GraphGenerationCoordinator {
131438
131552
  repository;
131439
- constructor(repository = getGraphGenerationRepository()) {
131440
- this.repository = repository;
131553
+ constructor(repository2 = getGraphGenerationRepository()) {
131554
+ this.repository = repository2;
131441
131555
  }
131442
131556
  async begin(input) {
131443
131557
  const deadline = Date.now() + GRAPH_GENERATION_LEASE_TTL_MS;
@@ -131493,609 +131607,6 @@ var init_graph_generation_coordinator = __esm(() => {
131493
131607
  init_with_deadlock_retry();
131494
131608
  });
131495
131609
 
131496
- // ../../packages/core/dist/services/etl/pipeline.js
131497
- import { createHash as createHash7 } from "crypto";
131498
- import { setTimeout as delay2 } from "timers/promises";
131499
- import path28 from "path";
131500
- function buildHeaderLanguageEvidence(files) {
131501
- const headers = new Set(files.filter((file2) => path28.posix.extname(file2.relativePath).toLowerCase() === ".h").map((file2) => path28.posix.normalize(file2.relativePath)));
131502
- const mutable = new Map;
131503
- const entry2 = (header) => {
131504
- let value = mutable.get(header);
131505
- if (!value) {
131506
- value = { cImporters: new Set, cppImporters: new Set, build: new Set };
131507
- mutable.set(header, value);
131508
- }
131509
- return value;
131510
- };
131511
- for (const file2 of files) {
131512
- if (path28.posix.basename(file2.relativePath) !== "compile_commands.json" || file2.snapshotContent === undefined)
131513
- continue;
131514
- let commands;
131515
- try {
131516
- commands = JSON.parse(file2.snapshotContent);
131517
- } catch {
131518
- continue;
131519
- }
131520
- if (!Array.isArray(commands))
131521
- continue;
131522
- for (const command of commands) {
131523
- if (!command || typeof command !== "object")
131524
- continue;
131525
- const record3 = command;
131526
- if (typeof record3.file !== "string")
131527
- continue;
131528
- const projectRoot = path28.resolve(file2.absolutePath, ...file2.relativePath.split("/").map(() => ".."));
131529
- const commandDirectory = typeof record3.directory === "string" ? path28.resolve(projectRoot, record3.directory) : projectRoot;
131530
- const absoluteInput = path28.resolve(commandDirectory, record3.file);
131531
- const relative2 = path28.relative(projectRoot, absoluteInput);
131532
- const header = path28.posix.normalize(relative2.replaceAll(path28.sep, "/"));
131533
- if (!headers.has(header))
131534
- continue;
131535
- const invocation = typeof record3.command === "string" ? record3.command : Array.isArray(record3.arguments) ? record3.arguments.join(" ") : "";
131536
- if (/(?:^|\s)(?:clang\+\+|g\+\+|c\+\+)(?:\s|$)|(?:^|\s)-x\s*c\+\+(?:\s|$)/u.test(invocation))
131537
- entry2(header).build.add("cpp");
131538
- else if (/(?:^|\s)(?:clang|gcc|cc)(?:\s|$)|(?:^|\s)-x\s*c(?:\s|$)/u.test(invocation))
131539
- entry2(header).build.add("c");
131540
- }
131541
- }
131542
- return Object.freeze(Object.fromEntries([...mutable.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([header, value]) => [header, Object.freeze({
131543
- ...value.cImporters.size ? { cImporters: Object.freeze([...value.cImporters].sort()) } : {},
131544
- ...value.cppImporters.size ? { cppImporters: Object.freeze([...value.cppImporters].sort()) } : {},
131545
- ...value.build.size ? { buildLanguage: value.build.size > 1 ? "conflict" : [...value.build][0] } : {}
131546
- })])));
131547
- }
131548
- function abortable(operation, signal) {
131549
- if (signal.aborted)
131550
- return Promise.reject(signal.reason);
131551
- return new Promise((resolve5, reject) => {
131552
- let abortReason;
131553
- const onAbort = () => {
131554
- abortReason = signal.reason;
131555
- };
131556
- signal.addEventListener("abort", onAbort, { once: true });
131557
- operation.then((value) => abortReason === undefined ? resolve5(value) : reject(abortReason), (error51) => reject(abortReason ?? error51)).finally(() => signal.removeEventListener("abort", onAbort));
131558
- });
131559
- }
131560
- var EtlPipeline;
131561
- var init_pipeline = __esm(() => {
131562
- init_dist();
131563
- init_discover();
131564
- init_parse3();
131565
- init_resolve();
131566
- init_load();
131567
- init_event_bus();
131568
- init_symbol_repository_factory();
131569
- init_index_job_tracker();
131570
- init_cache_factory();
131571
- init_index_manager();
131572
- init_vector_store_factory();
131573
- init_keyword_search_factory();
131574
- init_alias_resolver();
131575
- init_symbol_repo_workspace();
131576
- init_project_indexer();
131577
- init_parser_readiness();
131578
- init_parse3();
131579
- init_language_manifest();
131580
- init_graph_generation_coordinator();
131581
- init_managed_run_repository_pg();
131582
- EtlPipeline = class EtlPipeline {
131583
- static instance = null;
131584
- static runTails = new Map;
131585
- discover = new DiscoverStage;
131586
- parse = new ParseStage;
131587
- resolve = new ResolveStage;
131588
- load = new LoadStage;
131589
- graphGenerations = new GraphGenerationCoordinator;
131590
- constructor() {}
131591
- static getInstance() {
131592
- if (!EtlPipeline.instance) {
131593
- EtlPipeline.instance = new EtlPipeline;
131594
- }
131595
- return EtlPipeline.instance;
131596
- }
131597
- async run(input) {
131598
- await assertParserReadyForIndexing();
131599
- const projectId = await getProjectIdentityAliasResolver().resolve(input.projectId);
131600
- const canonicalInput = projectId === input.projectId ? input : { ...input, projectId };
131601
- const previous = EtlPipeline.runTails.get(projectId);
131602
- let release;
131603
- const tail = new Promise((resolve5) => {
131604
- release = resolve5;
131605
- });
131606
- EtlPipeline.runTails.set(projectId, tail);
131607
- if (previous) {
131608
- logger.info("EtlPipeline: waiting for prior project run", {
131609
- projectId,
131610
- jobId: input.jobId
131611
- });
131612
- await previous;
131613
- }
131614
- try {
131615
- return await this.runInternal(canonicalInput);
131616
- } finally {
131617
- if (EtlPipeline.runTails.get(projectId) === tail) {
131618
- EtlPipeline.runTails.delete(projectId);
131619
- }
131620
- release();
131621
- }
131622
- }
131623
- async runInternal(input, generationRetry = 0) {
131624
- const projectId = await getProjectIdentityAliasResolver().resolve(input.projectId);
131625
- const { projectPath, jobId, forceReindex = false, filesToProcess, include_tests = false, managedRunLease } = input;
131626
- const t0 = performance.now();
131627
- const stageTimings = {
131628
- discover: 0,
131629
- parse: 0,
131630
- resolve: 0,
131631
- load: 0
131632
- };
131633
- if (forceReindex) {
131634
- const vectorStore = await getVectorStore();
131635
- const keywordSearch = getKeywordSearch();
131636
- await Promise.all([
131637
- vectorStore.deleteByProject(projectId),
131638
- keywordSearch.deleteByProject(projectId)
131639
- ]);
131640
- }
131641
- const managedRunRepository = managedRunLease ? ManagedRunRepositoryPg.getInstance() : undefined;
131642
- const ctx = {
131643
- projectId,
131644
- projectPath,
131645
- jobId,
131646
- resumeCursor: managedRunLease ? (await managedRunRepository?.getActive(projectId, "indexing"))?.fileCursor ?? undefined : undefined,
131647
- managedRunLease,
131648
- emit: (event) => {
131649
- if (event.type === "progress") {
131650
- const p = event.payload;
131651
- indexJobTracker.updateProgress(jobId, p.current, p.total);
131652
- eventBus.publish("indexing:progress", {
131653
- jobId,
131654
- projectId,
131655
- stage: event.stage,
131656
- current: p.current,
131657
- total: p.total,
131658
- percentage: p.percentage
131659
- });
131660
- } else if (event.type === "file_error") {
131661
- const p = event.payload;
131662
- eventBus.publish("indexing:file", {
131663
- jobId,
131664
- projectId,
131665
- filePath: p.filePath,
131666
- stage: event.stage,
131667
- status: "error",
131668
- error: p.error
131669
- });
131670
- } else if (event.type === "file_processed") {
131671
- const p = event.payload;
131672
- eventBus.publish("indexing:file", {
131673
- jobId,
131674
- projectId,
131675
- filePath: p.filePath,
131676
- stage: event.stage,
131677
- status: "ok"
131678
- });
131679
- }
131680
- }
131681
- };
131682
- eventBus.publish("indexing:started", { jobId, projectId, projectPath });
131683
- let graphGenerationLease;
131684
- let graphHeartbeat;
131685
- let graphHeartbeatFailure;
131686
- const graphAbortController = new AbortController;
131687
- const heartbeatTimerController = new AbortController;
131688
- let stopGraphHeartbeat = false;
131689
- let managedRunHeartbeat;
131690
- let managedRunLeaseLost;
131691
- let stopManagedRunHeartbeat = false;
131692
- const managedRunTimerController = new AbortController;
131693
- if (managedRunLease && managedRunRepository) {
131694
- managedRunHeartbeat = (async () => {
131695
- while (!stopManagedRunHeartbeat) {
131696
- try {
131697
- await delay2(30000, undefined, { signal: managedRunTimerController.signal });
131698
- } catch {
131699
- return;
131700
- }
131701
- if (stopManagedRunHeartbeat || !managedRunLease)
131702
- return;
131703
- try {
131704
- const outcome2 = await managedRunRepository.heartbeat(managedRunLease);
131705
- if (outcome2.status === "lease_lost") {
131706
- managedRunLeaseLost = new Error("managed_run_lease_lost");
131707
- graphAbortController.abort(managedRunLeaseLost);
131708
- return;
131709
- }
131710
- } catch (heartbeatError) {
131711
- managedRunLeaseLost = heartbeatError;
131712
- graphAbortController.abort(managedRunLeaseLost);
131713
- return;
131714
- }
131715
- }
131716
- })();
131717
- }
131718
- try {
131719
- const st1 = performance.now();
131720
- const discoveredSnapshot = await this.discover.run(ctx, { forceReindex, includeTests: include_tests });
131721
- ctx.structuralHeaderEvidenceByFile = buildHeaderLanguageEvidence(discoveredSnapshot);
131722
- stageTimings.discover = Math.round(performance.now() - st1);
131723
- const activeGraph = await getSymbolRepository().getActiveGraphSnapshot(projectId);
131724
- try {
131725
- graphGenerationLease = await this.graphGenerations.begin({
131726
- projectId,
131727
- expectedActiveGenerationId: activeGraph?.generationId ?? null,
131728
- fingerprint: `sha256:${createHash7("sha256").update(JSON.stringify(STRUCTURAL_FINGERPRINT_INPUTS)).digest("hex")}`,
131729
- inputSnapshotHash: buildGraphInputSnapshotHash(discoveredSnapshot),
131730
- expectedFilesCount: discoveredSnapshot.length
131731
- });
131732
- } catch (beginError) {
131733
- if (beginError.message.startsWith("graph_generation_stale_active:") && generationRetry < 3) {
131734
- stopManagedRunHeartbeat = true;
131735
- managedRunTimerController.abort();
131736
- if (managedRunHeartbeat)
131737
- await managedRunHeartbeat;
131738
- return this.runInternal(input, generationRetry + 1);
131739
- }
131740
- throw beginError;
131741
- }
131742
- ctx.graphGenerationLease = graphGenerationLease;
131743
- ctx.abortSignal = graphAbortController.signal;
131744
- graphHeartbeat = (async () => {
131745
- while (!stopGraphHeartbeat) {
131746
- try {
131747
- await delay2(30000, undefined, { signal: heartbeatTimerController.signal });
131748
- } catch {
131749
- return;
131750
- }
131751
- if (stopGraphHeartbeat || !graphGenerationLease)
131752
- return;
131753
- try {
131754
- await this.graphGenerations.heartbeat(graphGenerationLease);
131755
- } catch (heartbeatError) {
131756
- graphHeartbeatFailure = heartbeatError;
131757
- graphAbortController.abort(graphHeartbeatFailure);
131758
- return;
131759
- }
131760
- }
131761
- })();
131762
- const requestedPaths = new Set(filesToProcess ?? []);
131763
- const preparedFiles = discoveredSnapshot.map((file2) => ({
131764
- ...file2,
131765
- needsReparse: forceReindex || !activeGraph || file2.needsReparse || requestedPaths.has(file2.relativePath)
131766
- }));
131767
- if (activeGraph) {
131768
- for (const file2 of preparedFiles) {
131769
- if (file2.needsReparse)
131770
- continue;
131771
- const copied = await getSymbolRepository().copyFileGeneration(graphGenerationLease, activeGraph.generationId, file2.relativePath);
131772
- if (copied.status === "lease_lost")
131773
- throw new Error("graph_generation_lease_lost");
131774
- if (copied.status === "missing")
131775
- file2.needsReparse = true;
131776
- }
131777
- }
131778
- const discovered = preparedFiles.map((file2) => Object.freeze(file2));
131779
- eventBus.publish("indexing:started", {
131780
- jobId,
131781
- projectId,
131782
- projectPath,
131783
- totalFiles: discovered.filter((f) => f.needsReparse).length
131784
- });
131785
- const st2 = performance.now();
131786
- let remainingFiles = [...discovered];
131787
- let parsed = [];
131788
- const staleFailures = new Set;
131789
- while (remainingFiles.length > 0) {
131790
- try {
131791
- parsed.push(...await abortable(this.parse.run(ctx, remainingFiles), graphAbortController.signal));
131792
- break;
131793
- } catch (parseError) {
131794
- if (!activeGraph || forceReindex || !filesToProcess?.length || !(parseError instanceof StructuralEtlParseError) || staleFailures.has(parseError.filePath))
131795
- throw parseError;
131796
- staleFailures.add(parseError.filePath);
131797
- const stale = await getSymbolRepository().markFileStaleGeneration(graphGenerationLease, parseError.filePath, {
131798
- lastKnownGoodGenerationId: activeGraph.generationId,
131799
- diagnostics: parseError.diagnostics.length > 0 ? parseError.diagnostics.slice(0, 10).map((diagnostic2) => ({ ...diagnostic2 })) : [{ code: "incremental_structural_failure", message: parseError.message }],
131800
- parserErrorCount: parseError.diagnosticCount
131801
- });
131802
- if (stale.status !== "stale")
131803
- throw parseError;
131804
- remainingFiles = remainingFiles.filter((file2) => file2.relativePath !== parseError.filePath);
131805
- }
131806
- }
131807
- if (graphHeartbeatFailure)
131808
- throw graphHeartbeatFailure;
131809
- if (managedRunLeaseLost)
131810
- throw managedRunLeaseLost;
131811
- stageTimings.parse = Math.round(performance.now() - st2);
131812
- const st3 = performance.now();
131813
- const resolved = await abortable(this.resolve.run(ctx, parsed), graphAbortController.signal);
131814
- if (graphHeartbeatFailure)
131815
- throw graphHeartbeatFailure;
131816
- if (managedRunLeaseLost)
131817
- throw managedRunLeaseLost;
131818
- stageTimings.resolve = Math.round(performance.now() - st3);
131819
- const st4 = performance.now();
131820
- const loadResult = await abortable(this.load.run(ctx, resolved), graphAbortController.signal);
131821
- if (graphHeartbeatFailure)
131822
- throw graphHeartbeatFailure;
131823
- if (managedRunLeaseLost)
131824
- throw managedRunLeaseLost;
131825
- stageTimings.load = Math.round(performance.now() - st4);
131826
- if (loadResult.errors > 0) {
131827
- logger.warn("EtlPipeline: completed with file errors", {
131828
- projectId,
131829
- jobId,
131830
- errors: loadResult.errors,
131831
- fileErrors: (loadResult.fileErrors ?? []).slice(0, 10)
131832
- });
131833
- }
131834
- const activationSnapshot = await abortable(this.discover.run(ctx, { forceReindex, includeTests: include_tests }), graphAbortController.signal);
131835
- if (buildGraphInputSnapshotHash(activationSnapshot) !== graphGenerationLease.inputSnapshotHash) {
131836
- throw new Error("graph_generation_stale_snapshot");
131837
- }
131838
- if (graphHeartbeatFailure)
131839
- throw graphHeartbeatFailure;
131840
- if (managedRunLeaseLost)
131841
- throw managedRunLeaseLost;
131842
- stopGraphHeartbeat = true;
131843
- heartbeatTimerController.abort();
131844
- await graphHeartbeat;
131845
- stopManagedRunHeartbeat = true;
131846
- managedRunTimerController.abort();
131847
- if (managedRunHeartbeat)
131848
- await managedRunHeartbeat;
131849
- const activatedGraph = await this.graphGenerations.activate(graphGenerationLease);
131850
- const activeGraphSummary = await getSymbolRepository().getActiveGraphSnapshot(projectId);
131851
- if (!activeGraphSummary || activeGraphSummary.generationId !== activatedGraph.generationId) {
131852
- throw new Error("activated_graph_summary_mismatch");
131853
- }
131854
- const durationMs = Math.round(performance.now() - t0);
131855
- const result = {
131856
- filesDiscovered: discovered.length,
131857
- filesIndexed: loadResult.filesLoaded,
131858
- filesSkipped: discovered.filter((f) => !f.needsReparse).length,
131859
- chunksIndexed: loadResult.chunksLoaded,
131860
- symbolsIndexed: loadResult.symbolsLoaded,
131861
- errors: loadResult.errors,
131862
- durationMs,
131863
- stageTimings,
131864
- activatedGraphGenerationId: activatedGraph.generationId,
131865
- parserDiagnostics: {
131866
- diagnosticsCount: activeGraphSummary.diagnostics.errors,
131867
- recoveredFiles: activeGraphSummary.diagnostics.recovered,
131868
- hardFailureFiles: activeGraphSummary.diagnostics.hardFailures,
131869
- staleFiles: activeGraphSummary.diagnostics.staleFiles,
131870
- languages: activeGraphSummary.languages
131871
- }
131872
- };
131873
- await getSearchCache().invalidateProject(projectId);
131874
- try {
131875
- const admissionMarker = new IndexManager(await getVectorStore());
131876
- await admissionMarker.updateIndexMetadata(projectId, projectPath, discovered.map((file2) => file2.relativePath));
131877
- } catch (markerError) {
131878
- logger.warn("EtlPipeline: search-admission marker write failed", {
131879
- projectId,
131880
- jobId,
131881
- error: markerError
131882
- });
131883
- }
131884
- if (forceReindex) {
131885
- const liveFingerprint = currentEmbeddingFingerprint();
131886
- if (liveFingerprint !== null) {
131887
- try {
131888
- await stampEmbeddingFingerprint(projectId, liveFingerprint);
131889
- } catch (stampError) {
131890
- logger.warn("EtlPipeline: embedding fingerprint stamp failed", {
131891
- projectId,
131892
- jobId,
131893
- error: stampError
131894
- });
131895
- }
131896
- }
131897
- }
131898
- indexJobTracker.updateProgress(jobId, result.filesIndexed, result.filesIndexed);
131899
- await indexJobTracker.setResultAndFlush(jobId, {
131900
- filesIndexed: result.filesIndexed,
131901
- chunksIndexed: result.chunksIndexed,
131902
- errors: result.errors,
131903
- fileErrors: loadResult.fileErrors ?? [],
131904
- duration: durationMs,
131905
- activatedGraphGenerationId: result.activatedGraphGenerationId,
131906
- parserDiagnostics: result.parserDiagnostics
131907
- });
131908
- eventBus.publish("indexing:completed", {
131909
- jobId,
131910
- projectId,
131911
- filesIndexed: result.filesIndexed,
131912
- chunksIndexed: result.chunksIndexed,
131913
- symbolsIndexed: result.symbolsIndexed,
131914
- errors: result.errors,
131915
- durationMs,
131916
- activatedGraphGenerationId: result.activatedGraphGenerationId
131917
- });
131918
- await this.graphGenerations.cleanup(graphGenerationLease);
131919
- stopGraphHeartbeat = true;
131920
- heartbeatTimerController.abort();
131921
- await graphHeartbeat;
131922
- stopManagedRunHeartbeat = true;
131923
- managedRunTimerController.abort();
131924
- if (managedRunHeartbeat)
131925
- await managedRunHeartbeat;
131926
- if (managedRunLease && managedRunRepository) {
131927
- try {
131928
- await managedRunRepository.complete(managedRunLease);
131929
- } catch (completeError) {
131930
- logger.error("EtlPipeline: managed_runs complete failed", completeError, { projectId, jobId });
131931
- }
131932
- }
131933
- logger.info("EtlPipeline: run completed", { projectId, jobId, ...result });
131934
- return result;
131935
- } catch (err) {
131936
- const durationMs = Math.round(performance.now() - t0);
131937
- const error51 = err.message;
131938
- if (graphGenerationLease) {
131939
- try {
131940
- await this.graphGenerations.abort(graphGenerationLease, error51);
131941
- } catch (abortError) {
131942
- logger.error("EtlPipeline: pending generation abort failed", abortError, { projectId, jobId });
131943
- }
131944
- }
131945
- stopGraphHeartbeat = true;
131946
- heartbeatTimerController.abort();
131947
- graphAbortController.abort();
131948
- await graphHeartbeat;
131949
- stopManagedRunHeartbeat = true;
131950
- managedRunTimerController.abort();
131951
- if (managedRunHeartbeat)
131952
- await managedRunHeartbeat;
131953
- if (managedRunLease && managedRunRepository) {
131954
- try {
131955
- const outcome2 = await managedRunRepository.abort(managedRunLease);
131956
- if (outcome2.status === "lease_lost") {
131957
- logger.warn("EtlPipeline: managed_runs abort saw lease_lost", { projectId, jobId });
131958
- }
131959
- } catch (abortError) {
131960
- logger.error("EtlPipeline: managed_runs abort failed", abortError, { projectId, jobId });
131961
- }
131962
- }
131963
- eventBus.publish("indexing:failed", { jobId, projectId, error: error51, durationMs });
131964
- indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: durationMs }, error51);
131965
- logger.error("EtlPipeline: run failed", err, { projectId, jobId, durationMs });
131966
- throw err;
131967
- }
131968
- }
131969
- };
131970
- });
131971
-
131972
- // ../../packages/core/dist/services/indexing/execute-indexing.js
131973
- async function executeIndexing(request) {
131974
- const { jobId, projectId, projectPath, forceReindex, warmCache, warmupQueries, include_tests = false, managedRunLease, warmupCache: warmupCache2 } = request;
131975
- const startTime = Date.now();
131976
- try {
131977
- indexJobTracker.updateStatus(jobId, "running");
131978
- logger.info("Starting project indexing via ETL Pipeline", {
131979
- jobId,
131980
- projectPath,
131981
- projectId,
131982
- forceReindex,
131983
- warmCache,
131984
- include_tests
131985
- });
131986
- const etlResult = await EtlPipeline.getInstance().run({
131987
- projectId,
131988
- projectPath,
131989
- jobId,
131990
- forceReindex,
131991
- include_tests,
131992
- managedRunLease
131993
- });
131994
- const duration3 = Date.now() - startTime;
131995
- logger.info("ETL Pipeline completed", {
131996
- jobId,
131997
- projectId,
131998
- duration: duration3,
131999
- filesIndexed: etlResult.filesIndexed,
132000
- filesSkipped: etlResult.filesSkipped,
132001
- chunksIndexed: etlResult.chunksIndexed,
132002
- symbolsIndexed: etlResult.symbolsIndexed,
132003
- errors: etlResult.errors,
132004
- stageTimings: etlResult.stageTimings
132005
- });
132006
- if (warmCache) {
132007
- logger.info("Starting cache warmup", { jobId, projectId });
132008
- const warmupStats = await warmupCache2(projectId, projectPath, warmupQueries);
132009
- logger.info("Cache warmup completed", { jobId, projectId, ...warmupStats });
132010
- }
132011
- indexJobTracker.updateProgress(jobId, etlResult.filesIndexed, etlResult.filesIndexed);
132012
- await indexJobTracker.setResultAndFlush(jobId, {
132013
- filesIndexed: etlResult.filesIndexed,
132014
- chunksIndexed: etlResult.chunksIndexed,
132015
- errors: etlResult.errors,
132016
- duration: duration3,
132017
- activatedGraphGenerationId: etlResult.activatedGraphGenerationId,
132018
- parserDiagnostics: etlResult.parserDiagnostics
132019
- });
132020
- } catch (error51) {
132021
- const duration3 = Date.now() - startTime;
132022
- logger.error("Project indexing failed", error51, {
132023
- jobId,
132024
- projectPath,
132025
- projectId,
132026
- duration: duration3
132027
- });
132028
- indexJobTracker.setResult(jobId, {
132029
- filesIndexed: 0,
132030
- chunksIndexed: 0,
132031
- errors: 1,
132032
- duration: duration3
132033
- }, error51.message);
132034
- }
132035
- }
132036
- var init_execute_indexing = __esm(() => {
132037
- init_dist();
132038
- init_index_job_tracker();
132039
- init_pipeline();
132040
- });
132041
-
132042
- // ../../packages/core/dist/services/indexing/acquire-indexing-lease.js
132043
- async function acquireIndexingLease(request) {
132044
- const { jobId, projectId } = request;
132045
- const eventId = `index:${jobId}`;
132046
- const managedRunRepo = ManagedRunRepositoryPg.getInstance();
132047
- try {
132048
- const beginOutcome = await managedRunRepo.begin({
132049
- projectId,
132050
- runKind: "indexing",
132051
- eventId
132052
- });
132053
- if (beginOutcome.status === "busy") {
132054
- indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 0, duration: 0 }, `indexing_busy:${beginOutcome.activeRunId}`);
132055
- return {
132056
- status: "busy",
132057
- activeRunId: beginOutcome.activeRunId,
132058
- leaseExpiresAt: beginOutcome.leaseExpiresAt
132059
- };
132060
- }
132061
- return { status: "acquired", lease: beginOutcome.lease };
132062
- } catch (beginError) {
132063
- logger.error("managed_runs begin failed", beginError, {
132064
- jobId,
132065
- projectId
132066
- });
132067
- indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: 0 }, `managed_runs_begin_failed:${beginError.message}`);
132068
- return { status: "failed", message: beginError.message };
132069
- }
132070
- }
132071
- var init_acquire_indexing_lease = __esm(() => {
132072
- init_dist();
132073
- init_index_job_tracker();
132074
- init_managed_run_repository_pg();
132075
- });
132076
-
132077
- // ../../packages/core/dist/services/project-identity/project-root-identity.js
132078
- import { realpath as realpath2 } from "fs/promises";
132079
- import path29 from "path";
132080
- async function canonicalizeProjectRoot(projectPath, canonicalize = realpath2) {
132081
- return canonicalize(path29.resolve(projectPath));
132082
- }
132083
- async function assertProjectRootReuse(options) {
132084
- if (!options.storedProjectPath || options.forceReindex)
132085
- return;
132086
- const canonicalize = options.canonicalize ?? realpath2;
132087
- let storedCanonical;
132088
- try {
132089
- storedCanonical = await canonicalize(path29.resolve(options.storedProjectPath));
132090
- } catch {
132091
- storedCanonical = path29.resolve(options.storedProjectPath);
132092
- }
132093
- if (storedCanonical !== options.canonicalProjectPath) {
132094
- 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");
132095
- }
132096
- }
132097
- var init_project_root_identity = () => {};
132098
-
132099
131610
  // ../../packages/core/dist/services/symbol/definition-lookup.js
132100
131611
  function toSymbolIdentityResolution(result) {
132101
131612
  switch (result.status) {
@@ -132116,8 +131627,8 @@ function toSymbolIdentityResolution(result) {
132116
131627
 
132117
131628
  class DefinitionLookupService {
132118
131629
  repository;
132119
- constructor(repository = getSymbolRepository) {
132120
- this.repository = repository;
131630
+ constructor(repository2 = getSymbolRepository) {
131631
+ this.repository = repository2;
132121
131632
  }
132122
131633
  async lookup(projectId, query) {
132123
131634
  const repo = this.repository();
@@ -132831,16 +132342,16 @@ function detectRoutes(httpEdges, defs, opts = {}) {
132831
132342
  const seen = new Set;
132832
132343
  const out = [];
132833
132344
  for (const e of httpEdges) {
132834
- const path30 = e.route;
132835
- if (!path30)
132345
+ const path29 = e.route;
132346
+ if (!path29)
132836
132347
  continue;
132837
132348
  const method = (e.method ?? "ANY").toUpperCase();
132838
- const key = method + " " + path30;
132349
+ const key = method + " " + path29;
132839
132350
  if (seen.has(key))
132840
132351
  continue;
132841
132352
  seen.add(key);
132842
132353
  out.push({
132843
- path: path30,
132354
+ path: path29,
132844
132355
  method: e.method,
132845
132356
  file: e.fromFile,
132846
132357
  handler: e.targetFqn ?? e.symbolName
@@ -132851,12 +132362,12 @@ function detectRoutes(httpEdges, defs, opts = {}) {
132851
132362
  continue;
132852
132363
  const parsed = parseRouteName(d.name);
132853
132364
  const method = parsed?.method ?? "ANY";
132854
- const path30 = parsed?.path ?? d.name;
132855
- const key = method + " " + path30;
132365
+ const path29 = parsed?.path ?? d.name;
132366
+ const key = method + " " + path29;
132856
132367
  if (seen.has(key))
132857
132368
  continue;
132858
132369
  seen.add(key);
132859
- 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 });
132860
132371
  }
132861
132372
  for (const d of defs) {
132862
132373
  const parsed = parseRouteName(d.name);
@@ -133077,7 +132588,7 @@ __export(exports_symbol_graph_service, {
133077
132588
  symbolGraphService: () => symbolGraphService,
133078
132589
  SymbolGraphService: () => SymbolGraphService
133079
132590
  });
133080
- import path30 from "path";
132591
+ import path29 from "path";
133081
132592
  import fs19 from "fs/promises";
133082
132593
 
133083
132594
  class SymbolGraphService {
@@ -133431,7 +132942,7 @@ class SymbolGraphService {
133431
132942
  }
133432
132943
  async resolveToAbsolute(relativePath, projectId) {
133433
132944
  const root = await this.getProjectRoot(projectId);
133434
- return root ? path30.resolve(root, relativePath) : relativePath;
132945
+ return root ? path29.resolve(root, relativePath) : relativePath;
133435
132946
  }
133436
132947
  async getProjectRoot(projectId) {
133437
132948
  const cached2 = this.projectRootCache.get(projectId);
@@ -133545,7 +133056,7 @@ class WorkspaceManager {
133545
133056
  return matches[0];
133546
133057
  }
133547
133058
  async removeWorkspace(projectId) {
133548
- await getSymbolRepository().clearProject(projectId);
133059
+ await withHeavyWorkLease("maintenance", `workspace-remove:${projectId}`, () => getSymbolRepository().clearProject(projectId));
133549
133060
  logger.info("WorkspaceManager: workspace removed", { projectId });
133550
133061
  }
133551
133062
  subscribeToEvents() {
@@ -133570,11 +133081,633 @@ var init_workspace_manager = __esm(() => {
133570
133081
  init_symbol_repository_factory();
133571
133082
  init_event_bus();
133572
133083
  init_symbol_graph_service();
133084
+ init_heavy_work_lease();
133573
133085
  workspaceManager = WorkspaceManager.getInstance();
133574
133086
  });
133575
133087
 
133576
- // ../../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";
133577
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";
133578
133711
 
133579
133712
  class IndexProjectTool {
133580
133713
  name = "index_project";
@@ -133622,7 +133755,7 @@ class IndexProjectTool {
133622
133755
  try {
133623
133756
  await assertParserReadyForIndexing();
133624
133757
  const canonicalProjectPath = await canonicalizeProjectRoot(projectPath);
133625
- const finalProjectId = projectId || path31.basename(canonicalProjectPath) || "default";
133758
+ const finalProjectId = projectId || path32.basename(canonicalProjectPath) || "default";
133626
133759
  const existing = await workspaceManager.getWorkspace(finalProjectId);
133627
133760
  await assertProjectRootReuse({
133628
133761
  projectId: finalProjectId,
@@ -134175,17 +134308,17 @@ function applyReplacer(root, replacer) {
134175
134308
  return transformChildren(root, replacer, []);
134176
134309
  return transformChildren(normalizeValue(replacedRoot), replacer, []);
134177
134310
  }
134178
- function transformChildren(value, replacer, path32) {
134311
+ function transformChildren(value, replacer, path33) {
134179
134312
  if (isJsonObject(value))
134180
- return transformObject(value, replacer, path32);
134313
+ return transformObject(value, replacer, path33);
134181
134314
  if (isJsonArray(value))
134182
- return transformArray(value, replacer, path32);
134315
+ return transformArray(value, replacer, path33);
134183
134316
  return value;
134184
134317
  }
134185
- function transformObject(obj, replacer, path32) {
134318
+ function transformObject(obj, replacer, path33) {
134186
134319
  const result = {};
134187
134320
  for (const [key, value] of Object.entries(obj)) {
134188
- const childPath = [...path32, key];
134321
+ const childPath = [...path33, key];
134189
134322
  const replacedValue = replacer(key, value, childPath);
134190
134323
  if (replacedValue === undefined)
134191
134324
  continue;
@@ -134193,11 +134326,11 @@ function transformObject(obj, replacer, path32) {
134193
134326
  }
134194
134327
  return result;
134195
134328
  }
134196
- function transformArray(arr, replacer, path32) {
134329
+ function transformArray(arr, replacer, path33) {
134197
134330
  const result = [];
134198
134331
  for (let i = 0;i < arr.length; i++) {
134199
134332
  const value = arr[i];
134200
- const childPath = [...path32, i];
134333
+ const childPath = [...path33, i];
134201
134334
  const replacedValue = replacer(String(i), value, childPath);
134202
134335
  if (replacedValue === undefined)
134203
134336
  continue;
@@ -135635,7 +135768,7 @@ __export(exports_memory_consolidation_job, {
135635
135768
  memoryConsolidationJob: () => memoryConsolidationJob,
135636
135769
  MemoryConsolidationJob: () => MemoryConsolidationJob
135637
135770
  });
135638
- import { randomUUID as randomUUID6 } from "crypto";
135771
+ import { randomUUID as randomUUID7 } from "crypto";
135639
135772
  async function addSupercedesEdge(store3, newId, sourceId, batchId) {
135640
135773
  const evidence = JSON.stringify({ batchId, consolidated: true });
135641
135774
  await store3.createEdge({
@@ -135779,11 +135912,11 @@ class MemoryConsolidationJob {
135779
135912
  });
135780
135913
  return { merged: 0, batchesCreated: 0 };
135781
135914
  }
135782
- 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);
135783
135916
  if (!batch)
135784
135917
  return { merged: 0, batchesCreated: 0 };
135785
135918
  const sourceRows = candidates2.filter((c) => batch.sourceIds.includes(c.id));
135786
- const newId = `mem-${now2}-${randomUUID6().slice(0, 8)}`;
135919
+ const newId = `mem-${now2}-${randomUUID7().slice(0, 8)}`;
135787
135920
  const importance = sourceRows.length ? Math.min(1, Math.max(...sourceRows.map((r) => r.importance))) : 0.7;
135788
135921
  const projectId = sourceRows.find((r) => r.project_id)?.project_id ?? null;
135789
135922
  try {
@@ -139290,7 +139423,7 @@ var init_session_pin_store = __esm(() => {
139290
139423
  // ../../packages/core/dist/services/hooks/attribution-resolver.js
139291
139424
  import fs20 from "fs";
139292
139425
  import os9 from "os";
139293
- import path32 from "path";
139426
+ import path33 from "path";
139294
139427
 
139295
139428
  class PgWorkspaceRootProvider {
139296
139429
  cache = null;
@@ -139340,7 +139473,7 @@ class AttributionResolver {
139340
139473
  this.pins = options.pins ?? new SessionPinStore;
139341
139474
  this.canonicalize = options.canonicalize ?? defaultCanonicalize;
139342
139475
  this.homedir = options.homedir ?? os9.homedir;
139343
- this.fsRoot = options.fsRoot ?? (() => path32.parse(path32.sep).root);
139476
+ this.fsRoot = options.fsRoot ?? (() => path33.parse(path33.sep).root);
139344
139477
  }
139345
139478
  async resolve(input) {
139346
139479
  const caller = input.callerProjectId;
@@ -139391,7 +139524,7 @@ class AttributionResolver {
139391
139524
  }
139392
139525
  let bestPath = null;
139393
139526
  for (const candidate2 of byPath.keys()) {
139394
- 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)) {
139395
139528
  if (bestPath === null || candidate2.length > bestPath.length) {
139396
139529
  bestPath = candidate2;
139397
139530
  }
@@ -139414,7 +139547,7 @@ class AttributionResolver {
139414
139547
  return projectPath2;
139415
139548
  const fsRoot = this.fsRoot();
139416
139549
  let normalized = projectPath2;
139417
- while (normalized.length > fsRoot.length && normalized.endsWith(path32.sep)) {
139550
+ while (normalized.length > fsRoot.length && normalized.endsWith(path33.sep)) {
139418
139551
  normalized = normalized.slice(0, -1);
139419
139552
  }
139420
139553
  return normalized;
@@ -139425,7 +139558,7 @@ function defaultCanonicalize(cwd) {
139425
139558
  return fs20.realpathSync(cwd);
139426
139559
  } catch {
139427
139560
  try {
139428
- return path32.resolve(cwd);
139561
+ return path33.resolve(cwd);
139429
139562
  } catch {
139430
139563
  return;
139431
139564
  }
@@ -140174,31 +140307,31 @@ class TracePathService {
140174
140307
  const chains = [];
140175
140308
  const seen = new Set;
140176
140309
  let walks = 0;
140177
- const walk = (fqn, path33) => {
140310
+ const walk = (fqn, path34) => {
140178
140311
  if (chains.length >= CHAIN_CAP)
140179
140312
  return;
140180
140313
  if (walks >= MAX_WALKS)
140181
140314
  return;
140182
140315
  walks++;
140183
- const key = path33.join("\u2192");
140316
+ const key = path34.join("\u2192");
140184
140317
  if (seen.has(key))
140185
140318
  return;
140186
140319
  seen.add(key);
140187
140320
  const next = adj.get(fqn);
140188
140321
  if (!next || next.length === 0 || !whoHasChild.has(fqn)) {
140189
- if (path33.length > 1)
140190
- 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 "));
140191
140324
  return;
140192
140325
  }
140193
140326
  for (const child of next) {
140194
140327
  if (chains.length >= CHAIN_CAP || walks >= MAX_WALKS)
140195
140328
  return;
140196
- if (path33.includes(child)) {
140197
- const cycled = [...path33, `${this.fqnToName(child)}\u21BA`];
140329
+ if (path34.includes(child)) {
140330
+ const cycled = [...path34, `${this.fqnToName(child)}\u21BA`];
140198
140331
  chains.push(cycled.map((n) => n).join(" \u2192 "));
140199
140332
  continue;
140200
140333
  }
140201
- walk(child, [...path33, child]);
140334
+ walk(child, [...path34, child]);
140202
140335
  }
140203
140336
  };
140204
140337
  for (const seed of seeds) {
@@ -141081,7 +141214,7 @@ var init_file_content_cache = __esm(() => {
141081
141214
  });
141082
141215
 
141083
141216
  // ../../packages/core/dist/services/file-read/file-metadata.js
141084
- import path33 from "path";
141217
+ import path34 from "path";
141085
141218
 
141086
141219
  class FileMetadataExtractor {
141087
141220
  symbolGraph;
@@ -141117,7 +141250,7 @@ class FileMetadataExtractor {
141117
141250
  return metadata;
141118
141251
  }
141119
141252
  detectLanguage(filePath) {
141120
- const ext2 = path33.extname(filePath).toLowerCase();
141253
+ const ext2 = path34.extname(filePath).toLowerCase();
141121
141254
  const languageMap2 = {
141122
141255
  ".ts": "TypeScript",
141123
141256
  ".tsx": "TypeScript",
@@ -141239,7 +141372,7 @@ var init_line_range = __esm(() => {
141239
141372
  });
141240
141373
 
141241
141374
  // ../../packages/core/dist/services/file-read/path-containment.js
141242
- import path34 from "path";
141375
+ import path35 from "path";
141243
141376
 
141244
141377
  class PathContainment {
141245
141378
  projectRoots;
@@ -141247,14 +141380,14 @@ class PathContainment {
141247
141380
  this.projectRoots = projectRoots;
141248
141381
  }
141249
141382
  async resolveFilePath(filePath, projectId) {
141250
- if (path34.isAbsolute(filePath)) {
141251
- return path34.resolve(filePath);
141383
+ if (path35.isAbsolute(filePath)) {
141384
+ return path35.resolve(filePath);
141252
141385
  }
141253
141386
  if (projectId) {
141254
141387
  const root = await this.projectRoots.getProjectRoot(projectId);
141255
141388
  if (root) {
141256
141389
  const cleaned = sanitizeFilePath(filePath);
141257
- return path34.resolve(root, cleaned);
141390
+ return path35.resolve(root, cleaned);
141258
141391
  }
141259
141392
  return null;
141260
141393
  }
@@ -141265,17 +141398,17 @@ class PathContainment {
141265
141398
  if (projectId) {
141266
141399
  const root = await this.projectRoots.getProjectRoot(projectId);
141267
141400
  if (root)
141268
- roots.push(path34.resolve(root));
141401
+ roots.push(path35.resolve(root));
141269
141402
  }
141270
- roots.push(path34.resolve(process.cwd()));
141403
+ roots.push(path35.resolve(process.cwd()));
141271
141404
  const envRoots = (process.env.MASSA_AI_READ_FILE_ROOTS ?? "").split(":").map((s) => s.trim()).filter((s) => s.length > 0);
141272
141405
  for (const extra of envRoots) {
141273
- roots.push(path34.resolve(extra));
141406
+ roots.push(path35.resolve(extra));
141274
141407
  }
141275
- const target = path34.resolve(absoluteFilePath);
141408
+ const target = path35.resolve(absoluteFilePath);
141276
141409
  for (const root of roots) {
141277
- const rel = path34.relative(root, target);
141278
- if (rel !== "" && !rel.startsWith("..") && !path34.isAbsolute(rel)) {
141410
+ const rel = path35.relative(root, target);
141411
+ if (rel !== "" && !rel.startsWith("..") && !path35.isAbsolute(rel)) {
141279
141412
  return { allowed: true };
141280
141413
  }
141281
141414
  if (rel === "")
@@ -144220,12 +144353,13 @@ function createProjectIdentityService(options = {}) {
144220
144353
  }
144221
144354
  },
144222
144355
  apply(input) {
144223
- return applyService.apply(input);
144356
+ return withHeavyWorkLease("maintenance", "project-identity", () => applyService.apply(input));
144224
144357
  }
144225
144358
  };
144226
144359
  }
144227
144360
  var init_service = __esm(() => {
144228
144361
  init_db_connection();
144362
+ init_heavy_work_lease();
144229
144363
  init_apply();
144230
144364
  init_errors4();
144231
144365
  init_planner();
@@ -144523,7 +144657,7 @@ var init_inference_probe = __esm(() => {
144523
144657
  // ../../packages/core/dist/services/health/local-health-checker.js
144524
144658
  import fs22 from "fs/promises";
144525
144659
  import { existsSync as existsSync3 } from "fs";
144526
- import path35 from "path";
144660
+ import path36 from "path";
144527
144661
 
144528
144662
  class LocalHealthChecker {
144529
144663
  dataDir = config2.get("dataDir");
@@ -144602,7 +144736,7 @@ class LocalHealthChecker {
144602
144736
  try {
144603
144737
  if (!existsSync3(this.dataDir))
144604
144738
  await fs22.mkdir(this.dataDir, { recursive: true });
144605
- const probe2 = path35.join(this.dataDir, ".health-check-test");
144739
+ const probe2 = path36.join(this.dataDir, ".health-check-test");
144606
144740
  await fs22.writeFile(probe2, "ok");
144607
144741
  await fs22.unlink(probe2);
144608
144742
  return { available: true, latency: Date.now() - start, details: { path: this.dataDir, writable: true } };
@@ -144948,6 +145082,9 @@ class PgScheduledJobStore {
144948
145082
  }, "save");
144949
145083
  this.ensureHydrated();
144950
145084
  }
145085
+ async ready() {
145086
+ await this.ensureHydrated();
145087
+ }
144951
145088
  get(id) {
144952
145089
  this.ensureHydrated();
144953
145090
  return this.mirror.get(id) ?? null;
@@ -145024,10 +145161,18 @@ class Scheduler {
145024
145161
  handlers = new Map;
145025
145162
  cronCache = new Map;
145026
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;
145027
145171
  timer = null;
145028
145172
  started = false;
145029
145173
  constructor(opts = {}) {
145030
145174
  this.store = opts.store ?? getScheduledJobStore();
145175
+ this.heavyWorkProbe = opts.heavyWorkProbe ?? probeHeavyWork;
145031
145176
  const schedulerConfig = config2.get("scheduler");
145032
145177
  this.tickIntervalMs = opts.tickIntervalMs ?? envPositiveInt(process.env.MASSA_AI_SCHEDULER_TICK_MS) ?? schedulerConfig?.tickMs ?? DEFAULTS.tickMs;
145033
145178
  this.maxConcurrent = opts.maxConcurrent ?? envPositiveInt(process.env.MASSA_AI_SCHEDULER_MAX_CONCURRENT) ?? schedulerConfig?.maxConcurrent ?? DEFAULTS.maxConcurrent;
@@ -145128,31 +145273,43 @@ class Scheduler {
145128
145273
  this.timer.unref?.();
145129
145274
  this.tick().catch(() => {});
145130
145275
  }
145131
- catchUpMissedJobs(now2 = Date.now()) {
145132
- if (!this.enabled)
145133
- 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) {
145134
145287
  const jobs = this.store.listEnabled();
145135
- let caughtUp = 0;
145136
145288
  let skipped = 0;
145289
+ const missed = [];
145137
145290
  for (const job of jobs) {
145138
145291
  if (this.running.has(job.jobKind)) {
145139
145292
  skipped++;
145140
145293
  continue;
145141
145294
  }
145142
- const overdueMs = now2 - job.nextRunAt;
145143
- if (overdueMs <= this.tickIntervalMs) {
145144
- continue;
145145
- }
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) {
145146
145304
  logger.info("Scheduler: catch-up tick for missed job", {
145147
145305
  id: job.id,
145148
145306
  name: job.name,
145149
145307
  jobKind: job.jobKind,
145150
- overdueMs
145308
+ overdueMs: now2 - job.nextRunAt
145151
145309
  });
145152
145310
  this.fireJob(job, now2);
145153
- caughtUp++;
145154
145311
  }
145155
- return { caughtUp, skipped };
145312
+ return { caughtUp: missed.length, skipped, deferred: 0 };
145156
145313
  }
145157
145314
  stop() {
145158
145315
  if (this.timer) {
@@ -145160,17 +145317,47 @@ class Scheduler {
145160
145317
  this.timer = null;
145161
145318
  }
145162
145319
  this.started = false;
145320
+ this.pendingTickAt = null;
145163
145321
  logger.info("Scheduler stopped");
145164
145322
  }
145165
145323
  isRunning() {
145166
145324
  return this.started && this.timer !== null;
145167
145325
  }
145168
145326
  async tick(now2 = Date.now()) {
145169
- const result = { evaluated: 0, fired: 0, skipped: 0, errors: 0 };
145327
+ const result = { evaluated: 0, fired: 0, skipped: 0, errors: 0, deferred: 0 };
145170
145328
  if (!this.enabled)
145171
145329
  return result;
145172
- 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();
145173
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
+ }
145174
145361
  for (const job of jobs) {
145175
145362
  if (this.running.has(job.jobKind)) {
145176
145363
  result.skipped++;
@@ -145180,7 +145367,7 @@ class Scheduler {
145180
145367
  continue;
145181
145368
  }
145182
145369
  const overdueMs = now2 - job.nextRunAt;
145183
- const isMissed = overdueMs > this.tickIntervalMs;
145370
+ const isMissed = overdueMs > this.tickIntervalMs && !this.deferred.has(job.id);
145184
145371
  if (isMissed) {
145185
145372
  logger.warn("Scheduler: missed run (skipping, rescheduling)", {
145186
145373
  id: job.id,
@@ -145202,7 +145389,42 @@ class Scheduler {
145202
145389
  }
145203
145390
  return result;
145204
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
+ }
145205
145426
  fireJob(job, firedAt) {
145427
+ this.deferred.delete(job.id);
145206
145428
  const handler = this.handlers.get(job.jobKind);
145207
145429
  if (!handler) {
145208
145430
  logger.warn("Scheduler: no handler registered for jobKind", {
@@ -145262,6 +145484,9 @@ class Scheduler {
145262
145484
  }
145263
145485
  })();
145264
145486
  }
145487
+ async ready() {
145488
+ await this.store.ready?.();
145489
+ }
145265
145490
  status(now2 = Date.now()) {
145266
145491
  const jobs = this.store.listAll();
145267
145492
  return {
@@ -145276,10 +145501,17 @@ class Scheduler {
145276
145501
  nextRunAt: j.nextRunAt,
145277
145502
  lastRunAt: j.lastRunAt,
145278
145503
  lastSuccessAt: j.lastSuccessAt ?? null,
145504
+ lastFailureAt: j.lastFailureAt ?? null,
145279
145505
  consecutiveFailures: j.consecutiveFailures ?? 0,
145506
+ lastError: j.lastError ?? null,
145280
145507
  due: j.enabled && j.nextRunAt <= now2,
145281
- currentlyRunning: this.running.has(j.jobKind)
145282
- }))
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
+ }
145283
145515
  };
145284
145516
  }
145285
145517
  isJobRunning(jobKind) {
@@ -145298,12 +145530,13 @@ function resetScheduler() {
145298
145530
  }
145299
145531
  resetScheduledJobStore();
145300
145532
  }
145301
- var DEFAULTS, cachedScheduler = null;
145533
+ var DEFAULTS, PROBE_FAILURE_WARN_EVERY = 5, cachedScheduler = null;
145302
145534
  var init_scheduler = __esm(() => {
145303
145535
  init_dist();
145304
145536
  init_config();
145305
145537
  init_scheduler_cron();
145306
145538
  init_scheduler_store_factory();
145539
+ init_heavy_work_lease();
145307
145540
  DEFAULTS = {
145308
145541
  tickMs: 60000,
145309
145542
  maxConcurrent: 2
@@ -145992,7 +146225,7 @@ var init_auto_improve_llm = __esm(() => {
145992
146225
  });
145993
146226
 
145994
146227
  // ../../packages/core/dist/services/jobs/auto-improve-apply.js
145995
- import { randomUUID as randomUUID7 } from "crypto";
146228
+ import { randomUUID as randomUUID8 } from "crypto";
145996
146229
  function validateCreatePayload(p) {
145997
146230
  if ("type" in p && p.type !== undefined && p.type !== null) {
145998
146231
  if (typeof p.type !== "string" || !VALID_MEMORY_TYPES.has(p.type)) {
@@ -146033,7 +146266,7 @@ function buildUpdatePatch(p) {
146033
146266
  return patch;
146034
146267
  }
146035
146268
  async function applyProposal(job, record3) {
146036
- 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)}`;
146037
146270
  const p = record3.payload;
146038
146271
  if (record3.kind === "memory.create") {
146039
146272
  validateCreatePayload(p);
@@ -146300,8 +146533,8 @@ __export(exports_auto_improve_job, {
146300
146533
 
146301
146534
  class AutoImproveJob {
146302
146535
  llm;
146303
- observationStore;
146304
- proposalStore;
146536
+ injectedObservationStore;
146537
+ injectedProposalStore;
146305
146538
  memoryRepo;
146306
146539
  thresholds;
146307
146540
  minObservations;
@@ -146312,10 +146545,16 @@ class AutoImproveJob {
146312
146545
  lastRunAt = 0;
146313
146546
  newSinceRun = 0;
146314
146547
  runCalls = 0;
146548
+ get observationStore() {
146549
+ return this.injectedObservationStore ?? getObservationStore();
146550
+ }
146551
+ get proposalStore() {
146552
+ return this.injectedProposalStore ?? getProposalStore();
146553
+ }
146315
146554
  constructor(opts = {}) {
146316
146555
  this.llm = opts.llm ?? llm;
146317
- this.observationStore = opts.observationStore ?? getObservationStore();
146318
- this.proposalStore = opts.proposalStore ?? getProposalStore();
146556
+ this.injectedObservationStore = opts.observationStore;
146557
+ this.injectedProposalStore = opts.proposalStore;
146319
146558
  this.thresholds = { ...DEFAULT_THRESHOLDS, ...opts.thresholds };
146320
146559
  this.reviewGateOverride = opts.reviewGate;
146321
146560
  this.idFactory = opts.idFactory ?? (() => newProposalId());
@@ -146395,7 +146634,7 @@ __export(exports_observation_consolidation_job, {
146395
146634
  observationConsolidationJob: () => observationConsolidationJob,
146396
146635
  ObservationConsolidationJob: () => ObservationConsolidationJob
146397
146636
  });
146398
- import { randomUUID as randomUUID8 } from "crypto";
146637
+ import { randomUUID as randomUUID9 } from "crypto";
146399
146638
  function readBridgeConfig() {
146400
146639
  try {
146401
146640
  const c = config2.get("hooks")?.bridge;
@@ -146413,7 +146652,7 @@ function readBridgeConfig() {
146413
146652
 
146414
146653
  class ObservationConsolidationJob {
146415
146654
  llm;
146416
- store;
146655
+ injectedStore;
146417
146656
  memoryRepo;
146418
146657
  minObservations;
146419
146658
  minIntervalMs;
@@ -146421,9 +146660,12 @@ class ObservationConsolidationJob {
146421
146660
  lastRunAt = 0;
146422
146661
  newSinceRun = 0;
146423
146662
  runCalls = 0;
146663
+ get store() {
146664
+ return this.injectedStore ?? getObservationStore();
146665
+ }
146424
146666
  constructor(opts = {}) {
146425
146667
  this.llm = opts.llm ?? llm;
146426
- this.store = opts.store ?? getObservationStore();
146668
+ this.injectedStore = opts.store;
146427
146669
  const injected = opts.memoryRepo;
146428
146670
  this.memoryRepo = injected ?? { insert: (i) => getMemoryRepository().insert(i) };
146429
146671
  const cfg = readBridgeConfig();
@@ -146485,7 +146727,7 @@ class ObservationConsolidationJob {
146485
146727
  if (observations.length < 2)
146486
146728
  return noop2;
146487
146729
  const window2 = observations.slice(0, this.maxWindow);
146488
- const batchId = `obs-batch-${Date.now()}-${randomUUID8().slice(0, 8)}`;
146730
+ const batchId = `obs-batch-${Date.now()}-${randomUUID9().slice(0, 8)}`;
146489
146731
  const prompt = buildObservationPrompt(window2);
146490
146732
  let batch;
146491
146733
  try {
@@ -146511,7 +146753,7 @@ class ObservationConsolidationJob {
146511
146753
  }
146512
146754
  if (!batch)
146513
146755
  return noop2;
146514
- const newId = `mem-${Date.now()}-${randomUUID8().slice(0, 8)}`;
146756
+ const newId = `mem-${Date.now()}-${randomUUID9().slice(0, 8)}`;
146515
146757
  const importance = 0.7;
146516
146758
  try {
146517
146759
  await Promise.resolve(this.memoryRepo.insert({
@@ -146743,7 +146985,7 @@ var init_scheduler2 = __esm(() => {
146743
146985
  // ../../packages/core/dist/services/pricing/models-dev-client.js
146744
146986
  import fs23 from "fs/promises";
146745
146987
  import { existsSync as existsSync4 } from "fs";
146746
- import path36 from "path";
146988
+ import path37 from "path";
146747
146989
  function getModelsDevClient() {
146748
146990
  if (!clientInstance) {
146749
146991
  clientInstance = new ModelsDevClient;
@@ -146763,7 +147005,7 @@ var init_models_dev_client = __esm(() => {
146763
147005
  memoryCacheTimestamp = 0;
146764
147006
  getLocalCachePath() {
146765
147007
  const dataDir = config2.get("dataDir");
146766
- return path36.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
147008
+ return path37.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
146767
147009
  }
146768
147010
  async loadLocalCache() {
146769
147011
  const cachePath = this.getLocalCachePath();
@@ -146798,7 +147040,7 @@ var init_models_dev_client = __esm(() => {
146798
147040
  async saveLocalCache(models) {
146799
147041
  const cachePath = this.getLocalCachePath();
146800
147042
  try {
146801
- const dir = path36.dirname(cachePath);
147043
+ const dir = path37.dirname(cachePath);
146802
147044
  await fs23.mkdir(dir, { recursive: true });
146803
147045
  const data = {
146804
147046
  timestamp: Date.now(),
@@ -152694,33 +152936,33 @@ var require_URL = __commonJS((exports, module) => {
152694
152936
  else
152695
152937
  return basepath.substring(0, lastslash + 1) + refpath;
152696
152938
  }
152697
- function remove_dot_segments(path37) {
152698
- if (!path37)
152699
- return path37;
152939
+ function remove_dot_segments(path38) {
152940
+ if (!path38)
152941
+ return path38;
152700
152942
  var output = "";
152701
- while (path37.length > 0) {
152702
- if (path37 === "." || path37 === "..") {
152703
- path37 = "";
152943
+ while (path38.length > 0) {
152944
+ if (path38 === "." || path38 === "..") {
152945
+ path38 = "";
152704
152946
  break;
152705
152947
  }
152706
- var twochars = path37.substring(0, 2);
152707
- var threechars = path37.substring(0, 3);
152708
- 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);
152709
152951
  if (threechars === "../") {
152710
- path37 = path37.substring(3);
152952
+ path38 = path38.substring(3);
152711
152953
  } else if (twochars === "./") {
152712
- path37 = path37.substring(2);
152954
+ path38 = path38.substring(2);
152713
152955
  } else if (threechars === "/./") {
152714
- path37 = "/" + path37.substring(3);
152715
- } else if (twochars === "/." && path37.length === 2) {
152716
- path37 = "/";
152717
- } else if (fourchars === "/../" || threechars === "/.." && path37.length === 3) {
152718
- 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);
152719
152961
  output = output.replace(/\/?[^\/]*$/, "");
152720
152962
  } else {
152721
- var segment = path37.match(/(\/?([^\/]*))/)[0];
152963
+ var segment = path38.match(/(\/?([^\/]*))/)[0];
152722
152964
  output += segment;
152723
- path37 = path37.substring(segment.length);
152965
+ path38 = path38.substring(segment.length);
152724
152966
  }
152725
152967
  }
152726
152968
  return output;
@@ -164790,21 +165032,21 @@ function jsonToKeyPathChunks(value, label = "$") {
164790
165032
  walk(value, label, out);
164791
165033
  return out;
164792
165034
  }
164793
- function walk(val, path37, out) {
165035
+ function walk(val, path38, out) {
164794
165036
  if (val === null || val === undefined)
164795
165037
  return;
164796
165038
  if (Array.isArray(val)) {
164797
165039
  if (val.length === 0) {
164798
- out.push({ path: path37, content: `**${path37}** = _[]_` });
165040
+ out.push({ path: path38, content: `**${path38}** = _[]_` });
164799
165041
  return;
164800
165042
  }
164801
165043
  if (val.every((v) => v !== null && typeof v === "object")) {
164802
- val.forEach((v, i) => walk(v, `${path37}[${i}]`, out));
165044
+ val.forEach((v, i) => walk(v, `${path38}[${i}]`, out));
164803
165045
  return;
164804
165046
  }
164805
165047
  const items = val.map((v) => `- \`${String(v)}\``).join(`
164806
165048
  `);
164807
- out.push({ path: path37, content: `**${path37}**
165049
+ out.push({ path: path38, content: `**${path38}**
164808
165050
 
164809
165051
  ${items}` });
164810
165052
  return;
@@ -164812,16 +165054,16 @@ ${items}` });
164812
165054
  if (typeof val === "object") {
164813
165055
  const entries = Object.entries(val);
164814
165056
  if (entries.length === 0) {
164815
- out.push({ path: path37, content: `**${path37}** = _{}_` });
165057
+ out.push({ path: path38, content: `**${path38}** = _{}_` });
164816
165058
  return;
164817
165059
  }
164818
165060
  for (const [k, v] of entries) {
164819
165061
  const safeKey = /^[A-Za-z_$][\w$]*$/.test(k) ? k : JSON.stringify(k);
164820
- walk(v, `${path37}.${safeKey}`, out);
165062
+ walk(v, `${path38}.${safeKey}`, out);
164821
165063
  }
164822
165064
  return;
164823
165065
  }
164824
- out.push({ path: path37, content: `**${path37}** = \`${String(val)}\`` });
165066
+ out.push({ path: path38, content: `**${path38}** = \`${String(val)}\`` });
164825
165067
  }
164826
165068
  var gfm, STRIP_SELECTORS, tdCache = null;
164827
165069
  var init_html_to_md = __esm(() => {
@@ -165161,6 +165403,7 @@ var init_services = __esm(() => {
165161
165403
  init_embeddings();
165162
165404
  init_local_health_checker();
165163
165405
  init_index_job_tracker();
165406
+ init_heavy_work_lease();
165164
165407
  init_scheduler2();
165165
165408
  init_models_dev_client();
165166
165409
  init_memory_graph_service();
@@ -165587,9 +165830,9 @@ var init_hook_service = __esm(() => {
165587
165830
  });
165588
165831
 
165589
165832
  // ../../packages/core/dist/services/bootstrap/bootstrap-service.js
165590
- import { randomUUID as randomUUID9 } from "crypto";
165833
+ import { randomUUID as randomUUID10 } from "crypto";
165591
165834
  import fs24 from "fs";
165592
- import path37 from "path";
165835
+ import path38 from "path";
165593
165836
  import { spawn as spawn2 } from "child_process";
165594
165837
  function readBootstrapConfig() {
165595
165838
  try {
@@ -165689,7 +165932,7 @@ class BootstrapService {
165689
165932
  return { ...noopResult("no-signals"), signalCount };
165690
165933
  }
165691
165934
  const capped = seeds.slice(0, cfg.maxSeedMemories);
165692
- const bootstrapId = `boot-${Date.now()}-${randomUUID9().slice(0, 8)}`;
165935
+ const bootstrapId = `boot-${Date.now()}-${randomUUID10().slice(0, 8)}`;
165693
165936
  let ids;
165694
165937
  try {
165695
165938
  ids = await storeSeeds(this.memoryRepo, projectId, bootstrapId, capped, signals);
@@ -165749,7 +165992,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
165749
165992
  }
165750
165993
  try {
165751
165994
  for (const name26 of README_CANDIDATES) {
165752
- const p = path37.join(projectRoot, name26);
165995
+ const p = path38.join(projectRoot, name26);
165753
165996
  if (fs24.existsSync(p) && fs24.statSync(p).isFile()) {
165754
165997
  const buf = fs24.readFileSync(p);
165755
165998
  signals.readme = buf.slice(0, MAX_README_BYTES).toString("utf8");
@@ -165760,14 +166003,14 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
165760
166003
  logger.debug("bootstrap scan: README read failed", { error: e.message });
165761
166004
  }
165762
166005
  try {
165763
- const docsDir = path37.join(projectRoot, "docs");
166006
+ const docsDir = path38.join(projectRoot, "docs");
165764
166007
  if (fs24.existsSync(docsDir) && fs24.statSync(docsDir).isDirectory()) {
165765
166008
  const entries = walkMarkdown(docsDir).slice(0, MAX_DOCS);
165766
166009
  for (const rel of entries) {
165767
166010
  try {
165768
166011
  const buf = fs24.readFileSync(rel);
165769
166012
  signals.docs.push({
165770
- path: path37.relative(projectRoot, rel),
166013
+ path: path38.relative(projectRoot, rel),
165771
166014
  snippet: buf.slice(0, MAX_DOC_BYTES).toString("utf8")
165772
166015
  });
165773
166016
  } catch {}
@@ -165778,7 +166021,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
165778
166021
  }
165779
166022
  try {
165780
166023
  for (const name26 of MANIFEST_FILES) {
165781
- const p = path37.join(projectRoot, name26);
166024
+ const p = path38.join(projectRoot, name26);
165782
166025
  if (!fs24.existsSync(p) || !fs24.statSync(p).isFile())
165783
166026
  continue;
165784
166027
  const raw2 = fs24.readFileSync(p).slice(0, MAX_MANIFEST_BYTES).toString("utf8");
@@ -165826,7 +166069,7 @@ function walkMarkdown(dir) {
165826
166069
  continue;
165827
166070
  }
165828
166071
  for (const e of entries) {
165829
- const full = path37.join(cur, e.name);
166072
+ const full = path38.join(cur, e.name);
165830
166073
  if (e.isDirectory()) {
165831
166074
  if (e.name === "node_modules" || e.name.startsWith("."))
165832
166075
  continue;
@@ -165943,7 +166186,7 @@ async function storeSeeds(memoryRepo, projectId, bootstrapId, seeds, signals) {
165943
166186
  const ids = [];
165944
166187
  const signalCount = countSignals(signals);
165945
166188
  for (const seed of seeds) {
165946
- const id = `seed-${Date.now()}-${randomUUID9().slice(0, 8)}`;
166189
+ const id = `seed-${Date.now()}-${randomUUID10().slice(0, 8)}`;
165947
166190
  const input = {
165948
166191
  id,
165949
166192
  content: truncate3(seed.summary, MAX_SUMMARY_CHARS),
@@ -166057,7 +166300,7 @@ var init_bootstrap_service = __esm(() => {
166057
166300
  MAX_DOC_BYTES = 2 * 1024;
166058
166301
  MAX_MANIFEST_BYTES = 2 * 1024;
166059
166302
  SeedMemorySchema = exports_external.object({
166060
- summary: exports_external.string().min(1).max(MAX_SUMMARY_CHARS),
166303
+ summary: exports_external.string().min(1),
166061
166304
  type: exports_external.enum(["pattern", "code", "decision"]),
166062
166305
  level: exports_external.union([exports_external.literal(0), exports_external.literal(1), exports_external.literal(2)]),
166063
166306
  importance: exports_external.number().min(0).max(1),
@@ -166650,7 +166893,9 @@ var init_handoff_auto_injector = __esm(() => {
166650
166893
  var exports_dist = {};
166651
166894
  __export(exports_dist, {
166652
166895
  workspaceManager: () => workspaceManager,
166896
+ withHeavyWorkLease: () => withHeavyWorkLease,
166653
166897
  validateEvent: () => validateEvent,
166898
+ validateEnum: () => validateEnum,
166654
166899
  validateAllGrammars: () => validateAllGrammars,
166655
166900
  tracePathService: () => tracePathService,
166656
166901
  toSymbolIdentityResolution: () => toSymbolIdentityResolution,
@@ -166694,6 +166939,7 @@ __export(exports_dist, {
166694
166939
  recordSearchDegradation: () => recordSearchDegradation,
166695
166940
  quoteDiscoveredIdentifier: () => quoteDiscoveredIdentifier,
166696
166941
  projectNotIndexed: () => projectNotIndexed,
166942
+ probeHeavyWork: () => probeHeavyWork,
166697
166943
  payloadStorePolicies: () => payloadStorePolicies,
166698
166944
  parseStructuralFqn: () => parseStructuralFqn,
166699
166945
  parseProjectIdentityPreviewRequest: () => parseProjectIdentityPreviewRequest,
@@ -166824,6 +167070,7 @@ __export(exports_dist, {
166824
167070
  UNKNOWN_ACTOR: () => UNKNOWN_ACTOR,
166825
167071
  TracePathTool: () => TracePathTool,
166826
167072
  TracePathService: () => TracePathService,
167073
+ ToolError: () => ToolError,
166827
167074
  TokenMetrics: () => TokenMetrics,
166828
167075
  TaskEnvelopeService: () => TaskEnvelopeService,
166829
167076
  TYPESCRIPT_RESOLVER_VERSION: () => TYPESCRIPT_RESOLVER_VERSION,
@@ -167000,6 +167247,7 @@ var init_dist15 = __esm(() => {
167000
167247
  init_proposal_repository();
167001
167248
  init_proposal_payload_validation();
167002
167249
  init_auto_improve_job();
167250
+ init_enum_validation();
167003
167251
  init_tools();
167004
167252
  init_services();
167005
167253
  init_graph_generation();
@@ -169467,7 +169715,7 @@ init_dist();
169467
169715
  init_dist15();
169468
169716
  init_dist();
169469
169717
  import fs25 from "fs/promises";
169470
- import path38 from "path";
169718
+ import path39 from "path";
169471
169719
  var _indexProjectTool = null;
169472
169720
  function indexProjectTool() {
169473
169721
  if (!_indexProjectTool)
@@ -169770,7 +170018,7 @@ class EmbeddedApiClient {
169770
170018
  } else {
169771
170019
  end = start + 20;
169772
170020
  }
169773
- const absolutePath = path38.join(workspace.project_path, file2);
170021
+ const absolutePath = path39.join(workspace.project_path, file2);
169774
170022
  const content = await fs25.readFile(absolutePath, "utf-8");
169775
170023
  const lines = content.split(/\r?\n/);
169776
170024
  const slice = lines.slice(start - 1, Math.min(lines.length, end));
@@ -170026,21 +170274,21 @@ class EmbeddedApiClient {
170026
170274
  async uploadAndIndex(params) {
170027
170275
  const rawBase = params.projectId || params.projectPath.replace(/\\/g, "/").split("/").filter(Boolean).pop() || "default";
170028
170276
  const finalProjectId = rawBase.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 128);
170029
- const uploadRoot = process.env.MASSA_AI_UPLOAD_DIR || path38.join(getGlobalDataDir(), "uploads");
170030
- 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);
170031
170279
  await fs25.rm(stagingDir, { recursive: true, force: true });
170032
170280
  await fs25.mkdir(stagingDir, { recursive: true });
170033
170281
  const WRITE_BATCH = 20;
170034
170282
  for (let i = 0;i < params.files.length; i += WRITE_BATCH) {
170035
170283
  await Promise.all(params.files.slice(i, i + WRITE_BATCH).map(async (file2) => {
170036
- if (path38.isAbsolute(file2.relativePath) || file2.relativePath.includes("..")) {
170284
+ if (path39.isAbsolute(file2.relativePath) || file2.relativePath.includes("..")) {
170037
170285
  throw new Error(`Invalid file path: ${file2.relativePath}`);
170038
170286
  }
170039
- const dest = path38.resolve(stagingDir, file2.relativePath.replace(/\//g, path38.sep));
170040
- 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)) {
170041
170289
  throw new Error(`Path escapes staging directory: ${file2.relativePath}`);
170042
170290
  }
170043
- await fs25.mkdir(path38.dirname(dest), { recursive: true });
170291
+ await fs25.mkdir(path39.dirname(dest), { recursive: true });
170044
170292
  await fs25.writeFile(dest, file2.content, "utf-8");
170045
170293
  }));
170046
170294
  }
@@ -170100,37 +170348,39 @@ class EmbeddedApiClient {
170100
170348
  return { success: false, error: "projectId is required" };
170101
170349
  const result = {};
170102
170350
  const errors4 = [];
170103
- if (clearVectors) {
170104
- try {
170105
- const vectorStore = await getVectorStore();
170106
- const keywordSearch = getKeywordSearch();
170107
- const [vectorsDeleted, keywordsDeleted] = await Promise.all([
170108
- vectorStore.deleteByProject(projectId),
170109
- keywordSearch.deleteByProject(projectId)
170110
- ]);
170111
- result.vectorsDeleted = vectorsDeleted;
170112
- result.keywordsDeleted = keywordsDeleted;
170113
- } catch (e) {
170114
- 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
+ }
170115
170365
  }
170116
- }
170117
- if (clearSymbols) {
170118
- try {
170119
- await workspaceManager.removeWorkspace(projectId);
170120
- result.symbolsDeleted = "ok";
170121
- } catch (e) {
170122
- 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
+ }
170123
170373
  }
170124
- }
170125
- if (clearMemories) {
170126
- try {
170127
- const repo = getMemoryRepository();
170128
- const deleted = await repo.deleteByProject(projectId);
170129
- result.memoriesDeleted = deleted;
170130
- } catch (e) {
170131
- 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
+ }
170132
170382
  }
170133
- }
170383
+ });
170134
170384
  return {
170135
170385
  success: errors4.length === 0,
170136
170386
  data: { projectId, ...result, errors: errors4, message: `Project '${projectId}' reset complete.` }
@@ -170542,7 +170792,7 @@ class EmbeddedApiClient {
170542
170792
  // src/file-collector.ts
170543
170793
  init_config();
170544
170794
  import fs26 from "fs/promises";
170545
- import path39 from "path";
170795
+ import path40 from "path";
170546
170796
  var SKIP_DIRS = new Set([
170547
170797
  "node_modules",
170548
170798
  ".git",
@@ -170558,11 +170808,21 @@ var SKIP_DIRS = new Set([
170558
170808
  ".cache",
170559
170809
  "vendor",
170560
170810
  ".svn",
170561
- ".hg"
170811
+ ".hg",
170812
+ "Pods"
170562
170813
  ]);
170563
170814
  var MAX_FILE_BYTES = 512 * 1024;
170564
- var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
170565
- 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
+ }
170566
170826
  function getAllowedExtensions() {
170567
170827
  try {
170568
170828
  const list = config2.get("security").allowedExtensions;
@@ -170575,7 +170835,16 @@ async function collectFiles(projectPath2) {
170575
170835
  const files = [];
170576
170836
  const state = { totalBytes: 0 };
170577
170837
  const allowed = getAllowedExtensions();
170578
- 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
+ }
170579
170848
  return files;
170580
170849
  }
170581
170850
  async function walk2(root2, dir, files, state, allowed) {
@@ -170592,13 +170861,13 @@ async function walk2(root2, dir, files, state, allowed) {
170592
170861
  break;
170593
170862
  if (entry2.isDirectory()) {
170594
170863
  if (!SKIP_DIRS.has(entry2.name) && !entry2.name.startsWith(".")) {
170595
- await walk2(root2, path39.join(dir, entry2.name), files, state, allowed);
170864
+ await walk2(root2, path40.join(dir, entry2.name), files, state, allowed);
170596
170865
  }
170597
170866
  } else if (entry2.isFile()) {
170598
- const ext2 = path39.extname(entry2.name).toLowerCase();
170867
+ const ext2 = path40.extname(entry2.name).toLowerCase();
170599
170868
  if (!allowed.has(ext2))
170600
170869
  continue;
170601
- const fullPath = path39.join(dir, entry2.name);
170870
+ const fullPath = path40.join(dir, entry2.name);
170602
170871
  try {
170603
170872
  const stat = await fs26.stat(fullPath);
170604
170873
  if (stat.size > MAX_FILE_BYTES)
@@ -170607,7 +170876,7 @@ async function walk2(root2, dir, files, state, allowed) {
170607
170876
  continue;
170608
170877
  const content = await fs26.readFile(fullPath, "utf-8");
170609
170878
  state.totalBytes += stat.size;
170610
- const relativePath = path39.relative(root2, fullPath).split(path39.sep).join("/");
170879
+ const relativePath = path40.relative(root2, fullPath).split(path40.sep).join("/");
170611
170880
  files.push({ relativePath, content });
170612
170881
  } catch {}
170613
170882
  }