@massa-ai/mcp-client 1.17.0 → 1.18.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.
package/dist/index.js CHANGED
@@ -38111,6 +38111,16 @@ var init_index_manager = __esm(() => {
38111
38111
  globAsync = glob;
38112
38112
  });
38113
38113
 
38114
+ // ../../packages/core/dist/services/cache/lru-evict.js
38115
+ function evictOldest(cache, maxRetained) {
38116
+ while (cache.size > maxRetained) {
38117
+ const oldest = cache.keys().next().value;
38118
+ if (oldest === undefined)
38119
+ break;
38120
+ cache.delete(oldest);
38121
+ }
38122
+ }
38123
+
38114
38124
  // ../../packages/core/dist/services/search/file-filter-cache.js
38115
38125
  class FileFilterCache {
38116
38126
  cache = new Map;
@@ -38179,18 +38189,7 @@ class FileFilterCache {
38179
38189
  return parts.join("|");
38180
38190
  }
38181
38191
  evictOldest() {
38182
- let oldestKey = null;
38183
- let oldestTime = Infinity;
38184
- for (const [key, entry] of this.cache.entries()) {
38185
- if (entry.createdAt < oldestTime) {
38186
- oldestTime = entry.createdAt;
38187
- oldestKey = key;
38188
- }
38189
- }
38190
- if (oldestKey) {
38191
- this.cache.delete(oldestKey);
38192
- logger.debug("Evicted oldest filter cache entry", { key: oldestKey });
38193
- }
38192
+ evictOldest(this.cache, this.MAX_CACHE_SIZE);
38194
38193
  }
38195
38194
  invalidateProject(projectId) {
38196
38195
  let removed = 0;
@@ -118540,7 +118539,7 @@ var init_memory_repository_factory = __esm(() => {
118540
118539
  init_memory_repository_pg();
118541
118540
  });
118542
118541
 
118543
- // ../../packages/core/dist/services/graph/graph-store-pg.js
118542
+ // ../../packages/core/dist/services/memory-graph/graph-store-pg.js
118544
118543
  function metadataForEdge(edge) {
118545
118544
  return {
118546
118545
  autoExtracted: edge.autoExtracted ?? false,
@@ -118856,7 +118855,7 @@ var init_graph_store_pg = __esm(() => {
118856
118855
  graphStorePg = GraphStorePg.getInstance();
118857
118856
  });
118858
118857
 
118859
- // ../../packages/core/dist/services/graph/graph-store-factory.js
118858
+ // ../../packages/core/dist/services/memory-graph/graph-store-factory.js
118860
118859
  function getGraphStore() {
118861
118860
  if (cachedStore2)
118862
118861
  return cachedStore2;
@@ -129055,6 +129054,133 @@ var init_pipeline = __esm(() => {
129055
129054
  };
129056
129055
  });
129057
129056
 
129057
+ // ../../packages/core/dist/services/indexing/execute-indexing.js
129058
+ async function executeIndexing(request) {
129059
+ const { jobId, projectId, projectPath, forceReindex, warmCache, warmupQueries, include_tests = false, managedRunLease, warmupCache: warmupCache2 } = request;
129060
+ const startTime = Date.now();
129061
+ try {
129062
+ indexJobTracker.updateStatus(jobId, "running");
129063
+ logger.info("Starting project indexing via ETL Pipeline", {
129064
+ jobId,
129065
+ projectPath,
129066
+ projectId,
129067
+ forceReindex,
129068
+ warmCache,
129069
+ include_tests
129070
+ });
129071
+ const etlResult = await EtlPipeline.getInstance().run({
129072
+ projectId,
129073
+ projectPath,
129074
+ jobId,
129075
+ forceReindex,
129076
+ include_tests,
129077
+ managedRunLease
129078
+ });
129079
+ const duration3 = Date.now() - startTime;
129080
+ logger.info("ETL Pipeline completed", {
129081
+ jobId,
129082
+ projectId,
129083
+ duration: duration3,
129084
+ filesIndexed: etlResult.filesIndexed,
129085
+ filesSkipped: etlResult.filesSkipped,
129086
+ chunksIndexed: etlResult.chunksIndexed,
129087
+ symbolsIndexed: etlResult.symbolsIndexed,
129088
+ errors: etlResult.errors,
129089
+ stageTimings: etlResult.stageTimings
129090
+ });
129091
+ if (warmCache) {
129092
+ logger.info("Starting cache warmup", { jobId, projectId });
129093
+ const warmupStats = await warmupCache2(projectId, projectPath, warmupQueries);
129094
+ logger.info("Cache warmup completed", { jobId, projectId, ...warmupStats });
129095
+ }
129096
+ indexJobTracker.updateProgress(jobId, etlResult.filesIndexed, etlResult.filesIndexed);
129097
+ await indexJobTracker.setResultAndFlush(jobId, {
129098
+ filesIndexed: etlResult.filesIndexed,
129099
+ chunksIndexed: etlResult.chunksIndexed,
129100
+ errors: etlResult.errors,
129101
+ duration: duration3,
129102
+ activatedGraphGenerationId: etlResult.activatedGraphGenerationId,
129103
+ parserDiagnostics: etlResult.parserDiagnostics
129104
+ });
129105
+ } catch (error51) {
129106
+ const duration3 = Date.now() - startTime;
129107
+ logger.error("Project indexing failed", error51, {
129108
+ jobId,
129109
+ projectPath,
129110
+ projectId,
129111
+ duration: duration3
129112
+ });
129113
+ indexJobTracker.setResult(jobId, {
129114
+ filesIndexed: 0,
129115
+ chunksIndexed: 0,
129116
+ errors: 1,
129117
+ duration: duration3
129118
+ }, error51.message);
129119
+ }
129120
+ }
129121
+ var init_execute_indexing = __esm(() => {
129122
+ init_dist();
129123
+ init_index_job_tracker();
129124
+ init_pipeline();
129125
+ });
129126
+
129127
+ // ../../packages/core/dist/services/indexing/acquire-indexing-lease.js
129128
+ async function acquireIndexingLease(request) {
129129
+ const { jobId, projectId } = request;
129130
+ const eventId = `index:${jobId}`;
129131
+ const managedRunRepo = ManagedRunRepositoryPg.getInstance();
129132
+ try {
129133
+ const beginOutcome = await managedRunRepo.begin({
129134
+ projectId,
129135
+ runKind: "indexing",
129136
+ eventId
129137
+ });
129138
+ if (beginOutcome.status === "busy") {
129139
+ indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 0, duration: 0 }, `indexing_busy:${beginOutcome.activeRunId}`);
129140
+ return {
129141
+ status: "busy",
129142
+ activeRunId: beginOutcome.activeRunId,
129143
+ leaseExpiresAt: beginOutcome.leaseExpiresAt
129144
+ };
129145
+ }
129146
+ return { status: "acquired", lease: beginOutcome.lease };
129147
+ } catch (beginError) {
129148
+ logger.error("managed_runs begin failed", beginError, {
129149
+ jobId,
129150
+ projectId
129151
+ });
129152
+ indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: 0 }, `managed_runs_begin_failed:${beginError.message}`);
129153
+ return { status: "failed", message: beginError.message };
129154
+ }
129155
+ }
129156
+ var init_acquire_indexing_lease = __esm(() => {
129157
+ init_dist();
129158
+ init_index_job_tracker();
129159
+ init_managed_run_repository_pg();
129160
+ });
129161
+
129162
+ // ../../packages/core/dist/services/project-identity/project-root-identity.js
129163
+ import { realpath as realpath2 } from "fs/promises";
129164
+ import path17 from "path";
129165
+ async function canonicalizeProjectRoot(projectPath, canonicalize = realpath2) {
129166
+ return canonicalize(path17.resolve(projectPath));
129167
+ }
129168
+ async function assertProjectRootReuse(options) {
129169
+ if (!options.storedProjectPath || options.forceReindex)
129170
+ return;
129171
+ const canonicalize = options.canonicalize ?? realpath2;
129172
+ let storedCanonical;
129173
+ try {
129174
+ storedCanonical = await canonicalize(path17.resolve(options.storedProjectPath));
129175
+ } catch {
129176
+ storedCanonical = path17.resolve(options.storedProjectPath);
129177
+ }
129178
+ if (storedCanonical !== options.canonicalProjectPath) {
129179
+ 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");
129180
+ }
129181
+ }
129182
+ var init_project_root_identity = () => {};
129183
+
129058
129184
  // ../../packages/core/dist/services/symbol/definition-lookup.js
129059
129185
  function toSymbolIdentityResolution(result) {
129060
129186
  switch (result.status) {
@@ -129790,16 +129916,16 @@ function detectRoutes(httpEdges, defs, opts = {}) {
129790
129916
  const seen = new Set;
129791
129917
  const out = [];
129792
129918
  for (const e of httpEdges) {
129793
- const path17 = e.route;
129794
- if (!path17)
129919
+ const path18 = e.route;
129920
+ if (!path18)
129795
129921
  continue;
129796
129922
  const method = (e.method ?? "ANY").toUpperCase();
129797
- const key = method + " " + path17;
129923
+ const key = method + " " + path18;
129798
129924
  if (seen.has(key))
129799
129925
  continue;
129800
129926
  seen.add(key);
129801
129927
  out.push({
129802
- path: path17,
129928
+ path: path18,
129803
129929
  method: e.method,
129804
129930
  file: e.fromFile,
129805
129931
  handler: e.targetFqn ?? e.symbolName
@@ -129810,12 +129936,12 @@ function detectRoutes(httpEdges, defs, opts = {}) {
129810
129936
  continue;
129811
129937
  const parsed = parseRouteName(d.name);
129812
129938
  const method = parsed?.method ?? "ANY";
129813
- const path17 = parsed?.path ?? d.name;
129814
- const key = method + " " + path17;
129939
+ const path18 = parsed?.path ?? d.name;
129940
+ const key = method + " " + path18;
129815
129941
  if (seen.has(key))
129816
129942
  continue;
129817
129943
  seen.add(key);
129818
- out.push({ path: path17, method: parsed?.method, file: d.filePath, handler: d.name });
129944
+ out.push({ path: path18, method: parsed?.method, file: d.filePath, handler: d.name });
129819
129945
  }
129820
129946
  for (const d of defs) {
129821
129947
  const parsed = parseRouteName(d.name);
@@ -130036,7 +130162,7 @@ __export(exports_symbol_graph_service, {
130036
130162
  symbolGraphService: () => symbolGraphService,
130037
130163
  SymbolGraphService: () => SymbolGraphService
130038
130164
  });
130039
- import path17 from "path";
130165
+ import path18 from "path";
130040
130166
  import fs8 from "fs/promises";
130041
130167
 
130042
130168
  class SymbolGraphService {
@@ -130390,7 +130516,7 @@ class SymbolGraphService {
130390
130516
  }
130391
130517
  async resolveToAbsolute(relativePath, projectId) {
130392
130518
  const root = await this.getProjectRoot(projectId);
130393
- return root ? path17.resolve(root, relativePath) : relativePath;
130519
+ return root ? path18.resolve(root, relativePath) : relativePath;
130394
130520
  }
130395
130521
  async getProjectRoot(projectId) {
130396
130522
  const cached2 = this.projectRootCache.get(projectId);
@@ -130410,12 +130536,7 @@ class SymbolGraphService {
130410
130536
  return null;
130411
130537
  }
130412
130538
  evictOldestProjectRoot() {
130413
- while (this.projectRootCache.size >= this.PROJECT_ROOT_CACHE_MAX_ENTRIES) {
130414
- const oldest = this.projectRootCache.keys().next().value;
130415
- if (oldest === undefined)
130416
- break;
130417
- this.projectRootCache.delete(oldest);
130418
- }
130539
+ evictOldest(this.projectRootCache, this.PROJECT_ROOT_CACHE_MAX_ENTRIES - 1);
130419
130540
  }
130420
130541
  clearProjectRoot(projectId) {
130421
130542
  this.projectRootCache.delete(projectId);
@@ -130538,25 +130659,7 @@ var init_workspace_manager = __esm(() => {
130538
130659
  });
130539
130660
 
130540
130661
  // ../../packages/core/dist/tools/index_project.js
130541
- import { realpath as realpath2 } from "fs/promises";
130542
- import path18 from "path";
130543
- async function canonicalizeProjectRoot(projectPath, canonicalize = realpath2) {
130544
- return canonicalize(path18.resolve(projectPath));
130545
- }
130546
- async function assertProjectRootReuse(options) {
130547
- if (!options.storedProjectPath || options.forceReindex)
130548
- return;
130549
- const canonicalize = options.canonicalize ?? realpath2;
130550
- let storedCanonical;
130551
- try {
130552
- storedCanonical = await canonicalize(path18.resolve(options.storedProjectPath));
130553
- } catch {
130554
- storedCanonical = path18.resolve(options.storedProjectPath);
130555
- }
130556
- if (storedCanonical !== options.canonicalProjectPath) {
130557
- 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");
130558
- }
130559
- }
130662
+ import path19 from "path";
130560
130663
 
130561
130664
  class IndexProjectTool {
130562
130665
  name = "index_project";
@@ -130604,7 +130707,7 @@ class IndexProjectTool {
130604
130707
  try {
130605
130708
  await assertParserReadyForIndexing();
130606
130709
  const canonicalProjectPath = await canonicalizeProjectRoot(projectPath);
130607
- const finalProjectId = projectId || path18.basename(canonicalProjectPath) || "default";
130710
+ const finalProjectId = projectId || path19.basename(canonicalProjectPath) || "default";
130608
130711
  const existing = await workspaceManager.getWorkspace(finalProjectId);
130609
130712
  await assertProjectRootReuse({
130610
130713
  projectId: finalProjectId,
@@ -130618,40 +130721,42 @@ class IndexProjectTool {
130618
130721
  projectPath: canonicalProjectPath,
130619
130722
  projectId: finalProjectId
130620
130723
  });
130621
- const eventId = `index:${job.jobId}`;
130622
- const managedRunRepo = ManagedRunRepositoryPg.getInstance();
130623
- let lease;
130624
- try {
130625
- const beginOutcome = await managedRunRepo.begin({
130626
- projectId: finalProjectId,
130627
- runKind: "indexing",
130628
- eventId
130629
- });
130630
- if (beginOutcome.status === "busy") {
130631
- indexJobTracker.setResult(job.jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 0, duration: 0 }, `indexing_busy:${beginOutcome.activeRunId}`);
130632
- return {
130633
- success: false,
130634
- error: `indexing_busy:${beginOutcome.activeRunId}`,
130635
- data: {
130636
- jobId: job.jobId,
130637
- projectId: finalProjectId,
130638
- status: "busy",
130639
- activeRunId: beginOutcome.activeRunId,
130640
- leaseExpiresAt: beginOutcome.leaseExpiresAt,
130641
- message: "Another indexing run is active for this project. Poll get_index_status(activeRunId)."
130642
- }
130643
- };
130644
- }
130645
- lease = beginOutcome.lease;
130646
- } catch (beginError) {
130647
- logger.error("managed_runs begin failed", beginError, { jobId: job.jobId, projectId: finalProjectId });
130648
- indexJobTracker.setResult(job.jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: 0 }, `managed_runs_begin_failed:${beginError.message}`);
130724
+ const leaseOutcome = await acquireIndexingLease({
130725
+ jobId: job.jobId,
130726
+ projectId: finalProjectId
130727
+ });
130728
+ if (leaseOutcome.status === "busy") {
130729
+ return {
130730
+ success: false,
130731
+ error: `indexing_busy:${leaseOutcome.activeRunId}`,
130732
+ data: {
130733
+ jobId: job.jobId,
130734
+ projectId: finalProjectId,
130735
+ status: "busy",
130736
+ activeRunId: leaseOutcome.activeRunId,
130737
+ leaseExpiresAt: leaseOutcome.leaseExpiresAt,
130738
+ message: "Another indexing run is active for this project. Poll get_index_status(activeRunId)."
130739
+ }
130740
+ };
130741
+ }
130742
+ if (leaseOutcome.status === "failed") {
130649
130743
  return {
130650
130744
  success: false,
130651
- error: `Failed to acquire indexing lease: ${beginError.message}`
130745
+ error: `Failed to acquire indexing lease: ${leaseOutcome.message}`
130652
130746
  };
130653
130747
  }
130654
- this.executeIndexing(job.jobId, finalProjectId, canonicalProjectPath, forceReindex, warmCache, warmupQueries, include_tests, lease).catch((error51) => {
130748
+ const lease = leaseOutcome.lease;
130749
+ executeIndexing({
130750
+ jobId: job.jobId,
130751
+ projectId: finalProjectId,
130752
+ projectPath: canonicalProjectPath,
130753
+ forceReindex,
130754
+ warmCache,
130755
+ warmupQueries,
130756
+ include_tests,
130757
+ managedRunLease: lease,
130758
+ warmupCache: this.contextualSearch.warmupCache.bind(this.contextualSearch)
130759
+ }).catch((error51) => {
130655
130760
  logger.error("Background indexing failed", error51, {
130656
130761
  jobId: job.jobId
130657
130762
  });
@@ -130678,77 +130783,16 @@ class IndexProjectTool {
130678
130783
  };
130679
130784
  }
130680
130785
  }
130681
- async executeIndexing(jobId, projectId, projectPath, forceReindex, warmCache, warmupQueries, include_tests = false, managedRunLease) {
130682
- const startTime = Date.now();
130683
- try {
130684
- indexJobTracker.updateStatus(jobId, "running");
130685
- logger.info("Starting project indexing via ETL Pipeline", {
130686
- jobId,
130687
- projectPath,
130688
- projectId,
130689
- forceReindex,
130690
- warmCache,
130691
- include_tests
130692
- });
130693
- const etlResult = await EtlPipeline.getInstance().run({
130694
- projectId,
130695
- projectPath,
130696
- jobId,
130697
- forceReindex,
130698
- include_tests,
130699
- managedRunLease
130700
- });
130701
- const duration3 = Date.now() - startTime;
130702
- logger.info("ETL Pipeline completed", {
130703
- jobId,
130704
- projectId,
130705
- duration: duration3,
130706
- filesIndexed: etlResult.filesIndexed,
130707
- filesSkipped: etlResult.filesSkipped,
130708
- chunksIndexed: etlResult.chunksIndexed,
130709
- symbolsIndexed: etlResult.symbolsIndexed,
130710
- errors: etlResult.errors,
130711
- stageTimings: etlResult.stageTimings
130712
- });
130713
- if (warmCache) {
130714
- logger.info("Starting cache warmup", { jobId, projectId });
130715
- const warmupStats = await this.contextualSearch.warmupCache(projectId, projectPath, warmupQueries);
130716
- logger.info("Cache warmup completed", { jobId, projectId, ...warmupStats });
130717
- }
130718
- indexJobTracker.updateProgress(jobId, etlResult.filesIndexed, etlResult.filesIndexed);
130719
- await indexJobTracker.setResultAndFlush(jobId, {
130720
- filesIndexed: etlResult.filesIndexed,
130721
- chunksIndexed: etlResult.chunksIndexed,
130722
- errors: etlResult.errors,
130723
- duration: duration3,
130724
- activatedGraphGenerationId: etlResult.activatedGraphGenerationId,
130725
- parserDiagnostics: etlResult.parserDiagnostics
130726
- });
130727
- } catch (error51) {
130728
- const duration3 = Date.now() - startTime;
130729
- logger.error("Project indexing failed", error51, {
130730
- jobId,
130731
- projectPath,
130732
- projectId,
130733
- duration: duration3
130734
- });
130735
- indexJobTracker.setResult(jobId, {
130736
- filesIndexed: 0,
130737
- chunksIndexed: 0,
130738
- errors: 1,
130739
- duration: duration3
130740
- }, error51.message);
130741
- }
130742
- }
130743
130786
  }
130744
130787
  var init_index_project = __esm(() => {
130745
130788
  init_contextual_search_rlm();
130746
130789
  init_dist();
130747
130790
  init_index_job_tracker();
130748
- init_pipeline();
130791
+ init_execute_indexing();
130792
+ init_acquire_indexing_lease();
130793
+ init_project_root_identity();
130749
130794
  init_workspace_manager();
130750
130795
  init_parser_readiness();
130751
- init_managed_run_repository_pg();
130752
130796
  });
130753
130797
 
130754
130798
  // ../../packages/core/dist/tools/get_index_status.js
@@ -131216,17 +131260,17 @@ function applyReplacer(root, replacer) {
131216
131260
  return transformChildren(root, replacer, []);
131217
131261
  return transformChildren(normalizeValue(replacedRoot), replacer, []);
131218
131262
  }
131219
- function transformChildren(value, replacer, path19) {
131263
+ function transformChildren(value, replacer, path20) {
131220
131264
  if (isJsonObject(value))
131221
- return transformObject(value, replacer, path19);
131265
+ return transformObject(value, replacer, path20);
131222
131266
  if (isJsonArray(value))
131223
- return transformArray(value, replacer, path19);
131267
+ return transformArray(value, replacer, path20);
131224
131268
  return value;
131225
131269
  }
131226
- function transformObject(obj, replacer, path19) {
131270
+ function transformObject(obj, replacer, path20) {
131227
131271
  const result = {};
131228
131272
  for (const [key, value] of Object.entries(obj)) {
131229
- const childPath = [...path19, key];
131273
+ const childPath = [...path20, key];
131230
131274
  const replacedValue = replacer(key, value, childPath);
131231
131275
  if (replacedValue === undefined)
131232
131276
  continue;
@@ -131234,11 +131278,11 @@ function transformObject(obj, replacer, path19) {
131234
131278
  }
131235
131279
  return result;
131236
131280
  }
131237
- function transformArray(arr, replacer, path19) {
131281
+ function transformArray(arr, replacer, path20) {
131238
131282
  const result = [];
131239
131283
  for (let i = 0;i < arr.length; i++) {
131240
131284
  const value = arr[i];
131241
- const childPath = [...path19, i];
131285
+ const childPath = [...path20, i];
131242
131286
  const replacedValue = replacer(String(i), value, childPath);
131243
131287
  if (replacedValue === undefined)
131244
131288
  continue;
@@ -131961,7 +132005,7 @@ var init_memory_service = __esm(() => {
131961
132005
  init_decay();
131962
132006
  });
131963
132007
 
131964
- // ../../packages/core/dist/services/graph/relation-extractor.js
132008
+ // ../../packages/core/dist/services/memory-graph/relation-extractor.js
131965
132009
  class RelationExtractor {
131966
132010
  graphStore;
131967
132011
  constructor(graphStore) {
@@ -132199,7 +132243,7 @@ var init_relation_extractor = __esm(() => {
132199
132243
  ];
132200
132244
  });
132201
132245
 
132202
- // ../../packages/core/dist/services/graph/graph-queries.js
132246
+ // ../../packages/core/dist/services/memory-graph/graph-queries.js
132203
132247
  class GraphQueries {
132204
132248
  graphStore;
132205
132249
  constructor(graphStore) {
@@ -132419,7 +132463,7 @@ var init_graph_queries = __esm(() => {
132419
132463
  };
132420
132464
  });
132421
132465
 
132422
- // ../../packages/core/dist/services/graph/memory-graph.service.js
132466
+ // ../../packages/core/dist/services/memory-graph/memory-graph.service.js
132423
132467
  class MemoryGraphService {
132424
132468
  static instance = null;
132425
132469
  store;
@@ -136306,7 +136350,7 @@ var init_session_pin_store = __esm(() => {
136306
136350
  // ../../packages/core/dist/services/hooks/attribution-resolver.js
136307
136351
  import fs9 from "fs";
136308
136352
  import os3 from "os";
136309
- import path19 from "path";
136353
+ import path20 from "path";
136310
136354
 
136311
136355
  class PgWorkspaceRootProvider {
136312
136356
  cache = null;
@@ -136358,7 +136402,7 @@ class AttributionResolver {
136358
136402
  this.pins = options.pins ?? new SessionPinStore;
136359
136403
  this.canonicalize = options.canonicalize ?? defaultCanonicalize;
136360
136404
  this.homedir = options.homedir ?? os3.homedir;
136361
- this.fsRoot = options.fsRoot ?? (() => path19.parse(path19.sep).root);
136405
+ this.fsRoot = options.fsRoot ?? (() => path20.parse(path20.sep).root);
136362
136406
  }
136363
136407
  async resolve(input) {
136364
136408
  const caller = input.callerProjectId;
@@ -136411,7 +136455,7 @@ class AttributionResolver {
136411
136455
  }
136412
136456
  let bestPath = null;
136413
136457
  for (const candidate2 of byPath.keys()) {
136414
- if (canonicalCwd === candidate2 || canonicalCwd.startsWith(candidate2.endsWith(path19.sep) ? candidate2 : candidate2 + path19.sep)) {
136458
+ if (canonicalCwd === candidate2 || canonicalCwd.startsWith(candidate2.endsWith(path20.sep) ? candidate2 : candidate2 + path20.sep)) {
136415
136459
  if (bestPath === null || candidate2.length > bestPath.length) {
136416
136460
  bestPath = candidate2;
136417
136461
  }
@@ -136434,7 +136478,7 @@ class AttributionResolver {
136434
136478
  return projectPath2;
136435
136479
  const fsRoot = this.fsRoot();
136436
136480
  let normalized = projectPath2;
136437
- while (normalized.length > fsRoot.length && normalized.endsWith(path19.sep)) {
136481
+ while (normalized.length > fsRoot.length && normalized.endsWith(path20.sep)) {
136438
136482
  normalized = normalized.slice(0, -1);
136439
136483
  }
136440
136484
  return normalized;
@@ -136445,7 +136489,7 @@ function defaultCanonicalize(cwd) {
136445
136489
  return fs9.realpathSync(cwd);
136446
136490
  } catch {
136447
136491
  try {
136448
- return path19.resolve(cwd);
136492
+ return path20.resolve(cwd);
136449
136493
  } catch {
136450
136494
  return;
136451
136495
  }
@@ -137184,31 +137228,31 @@ class TracePathService {
137184
137228
  const chains = [];
137185
137229
  const seen = new Set;
137186
137230
  let walks = 0;
137187
- const walk = (fqn, path20) => {
137231
+ const walk = (fqn, path21) => {
137188
137232
  if (chains.length >= CHAIN_CAP)
137189
137233
  return;
137190
137234
  if (walks >= MAX_WALKS)
137191
137235
  return;
137192
137236
  walks++;
137193
- const key = path20.join("\u2192");
137237
+ const key = path21.join("\u2192");
137194
137238
  if (seen.has(key))
137195
137239
  return;
137196
137240
  seen.add(key);
137197
137241
  const next = adj.get(fqn);
137198
137242
  if (!next || next.length === 0 || !whoHasChild.has(fqn)) {
137199
- if (path20.length > 1)
137200
- chains.push(path20.map((n) => this.fqnToName(n)).join(" \u2192 "));
137243
+ if (path21.length > 1)
137244
+ chains.push(path21.map((n) => this.fqnToName(n)).join(" \u2192 "));
137201
137245
  return;
137202
137246
  }
137203
137247
  for (const child of next) {
137204
137248
  if (chains.length >= CHAIN_CAP || walks >= MAX_WALKS)
137205
137249
  return;
137206
- if (path20.includes(child)) {
137207
- const cycled = [...path20, `${this.fqnToName(child)}\u21BA`];
137250
+ if (path21.includes(child)) {
137251
+ const cycled = [...path21, `${this.fqnToName(child)}\u21BA`];
137208
137252
  chains.push(cycled.map((n) => n).join(" \u2192 "));
137209
137253
  continue;
137210
137254
  }
137211
- walk(child, [...path20, child]);
137255
+ walk(child, [...path21, child]);
137212
137256
  }
137213
137257
  };
137214
137258
  for (const seed of seeds) {
@@ -138040,216 +138084,231 @@ var init_get_architecture = __esm(() => {
138040
138084
  init_architecture();
138041
138085
  });
138042
138086
 
138043
- // ../../packages/core/dist/tools/read_file.js
138087
+ // ../../packages/core/dist/services/file-read/file-content-cache.js
138044
138088
  import fs10 from "fs/promises";
138045
- import path20 from "path";
138046
138089
 
138047
- class ReadFileTool {
138048
- name = "read_file";
138049
- description = "Read file with automatic compression, caching, and symbol metadata. " + "Use with search results for 60% token savings.";
138050
- inputSchema = {
138051
- type: "object",
138052
- properties: {
138053
- filePath: {
138054
- type: "string",
138055
- description: "File path (absolute or relative to project root)"
138056
- },
138057
- projectId: {
138058
- type: "string",
138059
- description: "Project ID for symbol metadata (optional)"
138060
- },
138061
- offset: {
138062
- type: "number",
138063
- description: "Start line number (1-indexed)"
138064
- },
138065
- limit: {
138066
- type: "number",
138067
- description: "Number of lines to read"
138068
- },
138069
- lineStart: {
138070
- type: "number",
138071
- description: "Start line (alternative to offset)"
138072
- },
138073
- lineEnd: {
138074
- type: "number",
138075
- description: "End line (alternative to limit)"
138076
- },
138077
- compress: {
138078
- type: "boolean",
138079
- description: "Auto-compress content > 100 lines (default: true)",
138080
- default: true
138081
- },
138082
- targetRatio: {
138083
- type: "number",
138084
- description: "Compression target ratio (0.3 = 70% reduction)",
138085
- default: 0.3
138086
- },
138087
- format: {
138088
- type: "string",
138089
- enum: ["json", "toon"],
138090
- description: "Output format",
138091
- default: "json"
138092
- },
138093
- fields: {
138094
- type: "array",
138095
- items: { type: "string" },
138096
- description: "Projection \u2014 keep only these keys (dotted paths supported, e.g. ['nodes.symbol']). Absent/empty \u2192 full data."
138097
- },
138098
- includeSymbols: {
138099
- type: "boolean",
138100
- description: "Include symbol metadata from graph (default: true)",
138101
- default: true
138102
- },
138103
- includeImports: {
138104
- type: "boolean",
138105
- description: "Extract and show import statements (default: true)",
138106
- default: true
138107
- }
138108
- },
138109
- required: ["filePath"]
138110
- };
138111
- compressor;
138112
- symbolGraph;
138090
+ class FileContentCache {
138091
+ extractMetadata;
138113
138092
  fileCache = new Map;
138114
- projectRootCache = new Map;
138115
138093
  CACHE_TTL = 60000;
138116
- ROOT_CACHE_TTL = 300000;
138117
138094
  FILE_CACHE_MAX_ENTRIES = 512;
138095
+ constructor(extractMetadata) {
138096
+ this.extractMetadata = extractMetadata;
138097
+ }
138098
+ async readFileWithCache(filePath, options) {
138099
+ const cacheKey = JSON.stringify({
138100
+ filePath,
138101
+ includeSymbols: options.includeSymbols ?? false,
138102
+ includeImports: options.includeImports ?? false,
138103
+ projectId: options.projectId ?? null,
138104
+ relativePath: options.relativePath ?? null
138105
+ });
138106
+ const cached2 = this.fileCache.get(cacheKey);
138107
+ if (cached2 && Date.now() - cached2.timestamp < this.CACHE_TTL) {
138108
+ logger.debug("File cache hit", { filePath });
138109
+ this.fileCache.delete(cacheKey);
138110
+ this.fileCache.set(cacheKey, cached2);
138111
+ if (!cached2.metadata) {
138112
+ const metadata2 = await this.extractMetadata(cached2.content, filePath, options);
138113
+ this.fileCache.set(cacheKey, { ...cached2, metadata: metadata2 });
138114
+ return { content: cached2.content, metadata: metadata2 };
138115
+ }
138116
+ return {
138117
+ content: cached2.content,
138118
+ metadata: cached2.metadata
138119
+ };
138120
+ }
138121
+ const content = await fs10.readFile(filePath, "utf-8");
138122
+ const metadata = await this.extractMetadata(content, filePath, options);
138123
+ evictOldest(this.fileCache, this.FILE_CACHE_MAX_ENTRIES - 1);
138124
+ this.fileCache.set(cacheKey, {
138125
+ content,
138126
+ timestamp: Date.now(),
138127
+ metadata
138128
+ });
138129
+ logger.debug("File read and cached", { filePath });
138130
+ return { content, metadata };
138131
+ }
138132
+ }
138133
+ var init_file_content_cache = __esm(() => {
138134
+ init_dist();
138135
+ });
138136
+
138137
+ // ../../packages/core/dist/services/file-read/file-metadata.js
138138
+ import path21 from "path";
138139
+
138140
+ class FileMetadataExtractor {
138141
+ symbolGraph;
138118
138142
  constructor(symbolGraph) {
138119
- this.compressor = new CodeCompressor;
138120
138143
  this.symbolGraph = symbolGraph;
138121
- eventBus.subscribe("indexing:started", ({ projectId, projectPath: projectPath2 }) => {
138122
- this.projectRootCache.delete(projectId);
138123
- this.evictOldest(this.projectRootCache);
138124
- this.projectRootCache.set(projectId, projectPath2);
138125
- });
138126
138144
  }
138127
- async handle(params) {
138128
- const p = params;
138129
- const shouldCompress = p.compress !== false;
138130
- const targetRatio = p.targetRatio || 0.3;
138131
- const format = p.format || "json";
138132
- const { fields } = p;
138133
- const includeSymbols = p.includeSymbols !== false;
138134
- const includeImports = p.includeImports !== false;
138135
- try {
138136
- const resolved = await this.resolveFilePath(p.filePath, p.projectId);
138137
- if (resolved === null) {
138138
- return {
138139
- success: false,
138140
- error: "Relative filePath requires a projectId (to resolve against the workspace) or an absolute path."
138145
+ async extractMetadata(content, filePath, options) {
138146
+ const lines = content.split(`
138147
+ `);
138148
+ const language = this.detectLanguage(filePath);
138149
+ const metadata = {
138150
+ totalLines: lines.length,
138151
+ language
138152
+ };
138153
+ if (options.includeImports && language) {
138154
+ metadata.imports = this.extractImports(lines, language);
138155
+ }
138156
+ if (options.includeSymbols && this.symbolGraph && options.projectId) {
138157
+ try {
138158
+ const queryPath = options.relativePath || filePath;
138159
+ const { definitions } = await this.symbolGraph.listDefinitions(options.projectId, {
138160
+ file: queryPath,
138161
+ limit: 100
138162
+ });
138163
+ metadata.symbols = {
138164
+ definitions: definitions.length,
138165
+ references: 0
138141
138166
  };
138167
+ } catch (error51) {
138168
+ logger.debug("Failed to get symbol metadata", { filePath, error: error51 });
138142
138169
  }
138143
- const filePath = resolved;
138144
- const containment = await this.checkPathContainment(filePath, p.projectId);
138145
- if (!containment.allowed) {
138146
- return {
138147
- success: false,
138148
- error: containment.error
138149
- };
138170
+ }
138171
+ return metadata;
138172
+ }
138173
+ detectLanguage(filePath) {
138174
+ const ext2 = path21.extname(filePath).toLowerCase();
138175
+ const languageMap2 = {
138176
+ ".ts": "TypeScript",
138177
+ ".tsx": "TypeScript",
138178
+ ".js": "JavaScript",
138179
+ ".jsx": "JavaScript",
138180
+ ".vue": "Vue",
138181
+ ".py": "Python",
138182
+ ".go": "Go",
138183
+ ".rs": "Rust",
138184
+ ".java": "Java",
138185
+ ".cpp": "C++",
138186
+ ".c": "C",
138187
+ ".h": "C",
138188
+ ".hpp": "C++",
138189
+ ".cs": "C#",
138190
+ ".rb": "Ruby",
138191
+ ".php": "PHP",
138192
+ ".swift": "Swift",
138193
+ ".kt": "Kotlin",
138194
+ ".kts": "Kotlin",
138195
+ ".scala": "Scala",
138196
+ ".md": "Markdown",
138197
+ ".json": "JSON",
138198
+ ".yaml": "YAML",
138199
+ ".yml": "YAML",
138200
+ ".xml": "XML",
138201
+ ".html": "HTML",
138202
+ ".css": "CSS",
138203
+ ".scss": "SCSS",
138204
+ ".sql": "SQL",
138205
+ ".sh": "Shell",
138206
+ ".bash": "Shell"
138207
+ };
138208
+ return languageMap2[ext2];
138209
+ }
138210
+ extractImports(lines, language) {
138211
+ const imports = [];
138212
+ const importPatterns = {
138213
+ TypeScript: /^(import\s+.*?from\s+['"]|import\s+['"])/,
138214
+ JavaScript: /^(import\s+.*?from\s+['"]|import\s+['"]|require\s*\(\s*['"])/,
138215
+ Python: /^(import\s+|from\s+\S+\s+import)/,
138216
+ Go: /^import\s+/,
138217
+ Java: /^import\s+/,
138218
+ Rust: /^use\s+/
138219
+ };
138220
+ const pattern = importPatterns[language];
138221
+ if (!pattern)
138222
+ return imports;
138223
+ for (const line of lines) {
138224
+ const trimmed = line.trim();
138225
+ if (pattern.test(trimmed)) {
138226
+ imports.push(trimmed);
138150
138227
  }
138151
- const relativePath = p.filePath;
138152
- const range = this.calculateRange(p);
138153
- const { content, metadata } = await this.readFileWithCache(filePath, {
138154
- includeSymbols,
138155
- includeImports,
138156
- projectId: p.projectId,
138157
- relativePath
138158
- });
138159
- const lines = content.split(`
138228
+ }
138229
+ return imports;
138230
+ }
138231
+ }
138232
+ var init_file_metadata = __esm(() => {
138233
+ init_dist();
138234
+ });
138235
+
138236
+ // ../../packages/core/dist/services/file-read/line-range.js
138237
+ function calculateRange(params) {
138238
+ if (params.lineStart !== undefined && params.lineEnd !== undefined) {
138239
+ return {
138240
+ start: Math.max(1, params.lineStart),
138241
+ end: params.lineEnd
138242
+ };
138243
+ }
138244
+ if (params.offset !== undefined) {
138245
+ const offset = Math.max(1, params.offset);
138246
+ const limit = params.limit || 1000;
138247
+ return {
138248
+ start: offset,
138249
+ end: offset + limit - 1
138250
+ };
138251
+ }
138252
+ return {
138253
+ start: 1,
138254
+ end: Infinity
138255
+ };
138256
+ }
138257
+ function adjustRange(range, totalLines) {
138258
+ const start = Math.max(1, Math.min(range.start, totalLines));
138259
+ const end = range.end === Infinity ? totalLines : Math.min(range.end, totalLines);
138260
+ return { start, end };
138261
+ }
138262
+ function extractLines(lines, range) {
138263
+ const start = range.start - 1;
138264
+ const end = range.end;
138265
+ const selectedLines = lines.slice(start, end);
138266
+ return selectedLines.map((line, index) => {
138267
+ const lineNum = start + index + 1;
138268
+ return `${lineNum.toString().padStart(6, " ")}: ${line}`;
138269
+ }).join(`
138160
138270
  `);
138161
- const totalLines = lines.length;
138162
- const adjustedRange = this.adjustRange(range, totalLines);
138163
- let selectedContent = this.extractLines(lines, adjustedRange);
138164
- let selectedLineCount = selectedContent.split(`
138271
+ }
138272
+ function selectLines(lines, range) {
138273
+ let content = extractLines(lines, range);
138274
+ let lineCount = content.split(`
138165
138275
  `).length;
138166
- let source_clipped = false;
138167
- if (selectedLineCount > MASSA_AI_READ_FILE_MAX_LINES) {
138168
- const cappedLines = lines.slice(adjustedRange.start - 1, adjustedRange.start - 1 + MASSA_AI_READ_FILE_MAX_LINES);
138169
- selectedContent = cappedLines.join(`
138276
+ let clipped = false;
138277
+ if (lineCount > MASSA_AI_READ_FILE_MAX_LINES) {
138278
+ const cappedLines = lines.slice(range.start - 1, range.start - 1 + MASSA_AI_READ_FILE_MAX_LINES);
138279
+ content = cappedLines.join(`
138170
138280
  `);
138171
- selectedLineCount = selectedContent.split(`
138281
+ lineCount = content.split(`
138172
138282
  `).length;
138173
- source_clipped = true;
138174
- }
138175
- const shouldAutoCompress = shouldCompress && selectedLineCount > 100 && targetRatio < 1;
138176
- const result = {
138177
- filePath: p.filePath,
138178
- absolutePath: filePath,
138179
- lineRange: {
138180
- requested: {
138181
- start: range.start,
138182
- end: range.end === Infinity ? null : range.end
138183
- },
138184
- actual: {
138185
- start: adjustedRange.start,
138186
- end: source_clipped ? adjustedRange.start + selectedLineCount - 1 : adjustedRange.end,
138187
- total: totalLines
138188
- },
138189
- selected: selectedLineCount
138190
- },
138191
- source_clipped,
138192
- metadata: {
138193
- totalLines,
138194
- language: metadata.language,
138195
- ...metadata.symbols && { symbols: metadata.symbols },
138196
- ...metadata.imports && { imports: metadata.imports }
138197
- },
138198
- compressed: shouldAutoCompress,
138199
- recommendations: []
138200
- };
138201
- if (shouldAutoCompress) {
138202
- const compressed = await this.compressor.compress(selectedContent, "code_structure");
138203
- const originalTokens = estimateTokens(selectedContent, "code");
138204
- const compressedTokens = estimateTokens(compressed.compressed, "code");
138205
- const actualRatio = compressedTokens / originalTokens;
138206
- result.content = compressed.compressed;
138207
- result.tokens = {
138208
- original: originalTokens,
138209
- compressed: compressedTokens,
138210
- saved: originalTokens - compressedTokens,
138211
- savingsPercent: Math.round((1 - actualRatio) * 100)
138212
- };
138213
- result.compressionRatio = actualRatio;
138214
- result.recommendations.push(`\u2713 Auto-compressed ${selectedLineCount} lines (${result.tokens.savingsPercent}% reduction)`);
138215
- } else {
138216
- result.content = selectedContent;
138217
- result.tokens = {
138218
- original: estimateTokens(selectedContent, "code"),
138219
- compressed: estimateTokens(selectedContent, "code"),
138220
- saved: 0,
138221
- savingsPercent: 0
138222
- };
138223
- if (selectedLineCount > 100) {
138224
- result.recommendations.push("\uD83D\uDCA1 Content > 100 lines. Consider compress=true for token savings");
138225
- }
138226
- }
138227
- if (range.start === 1 && range.end === Infinity) {
138228
- result.recommendations.push("\uD83D\uDCA1 Use lineStart/lineEnd or offset/limit to read specific sections (60% token savings)");
138229
- }
138230
- if (metadata.symbols && metadata.symbols.definitions > 0) {
138231
- result.recommendations.push(`\uD83D\uDCA1 Use get_references() to find usages of ${metadata.symbols.definitions} symbols in this file`);
138232
- }
138233
- return serializeToolResponse(result, { format, fields });
138234
- } catch (error51) {
138235
- logger.error("Failed to read file", error51, {
138236
- filePath: p.filePath
138237
- });
138238
- return {
138239
- success: false,
138240
- error: `Failed to read file: ${error51.message}`
138241
- };
138242
- }
138283
+ clipped = true;
138284
+ }
138285
+ return { content, lineCount, clipped };
138286
+ }
138287
+ var MASSA_AI_READ_FILE_MAX_LINES;
138288
+ var init_line_range = __esm(() => {
138289
+ MASSA_AI_READ_FILE_MAX_LINES = (() => {
138290
+ const v = Number(process.env.MASSA_AI_READ_FILE_MAX_LINES);
138291
+ return Number.isFinite(v) && v > 0 ? Math.floor(v) : 500;
138292
+ })();
138293
+ });
138294
+
138295
+ // ../../packages/core/dist/services/file-read/path-containment.js
138296
+ import path22 from "path";
138297
+
138298
+ class PathContainment {
138299
+ projectRoots;
138300
+ constructor(projectRoots) {
138301
+ this.projectRoots = projectRoots;
138243
138302
  }
138244
138303
  async resolveFilePath(filePath, projectId) {
138245
- if (path20.isAbsolute(filePath)) {
138246
- return path20.resolve(filePath);
138304
+ if (path22.isAbsolute(filePath)) {
138305
+ return path22.resolve(filePath);
138247
138306
  }
138248
138307
  if (projectId) {
138249
- const root = await this.getProjectRoot(projectId);
138308
+ const root = await this.projectRoots.getProjectRoot(projectId);
138250
138309
  if (root) {
138251
138310
  const cleaned = sanitizeFilePath(filePath);
138252
- return path20.resolve(root, cleaned);
138311
+ return path22.resolve(root, cleaned);
138253
138312
  }
138254
138313
  return null;
138255
138314
  }
@@ -138258,19 +138317,19 @@ class ReadFileTool {
138258
138317
  async checkPathContainment(absoluteFilePath, projectId) {
138259
138318
  const roots = [];
138260
138319
  if (projectId) {
138261
- const root = await this.getProjectRoot(projectId);
138320
+ const root = await this.projectRoots.getProjectRoot(projectId);
138262
138321
  if (root)
138263
- roots.push(path20.resolve(root));
138322
+ roots.push(path22.resolve(root));
138264
138323
  }
138265
- roots.push(path20.resolve(process.cwd()));
138324
+ roots.push(path22.resolve(process.cwd()));
138266
138325
  const envRoots = (process.env.MASSA_AI_READ_FILE_ROOTS ?? "").split(":").map((s) => s.trim()).filter((s) => s.length > 0);
138267
138326
  for (const extra of envRoots) {
138268
- roots.push(path20.resolve(extra));
138327
+ roots.push(path22.resolve(extra));
138269
138328
  }
138270
- const target = path20.resolve(absoluteFilePath);
138329
+ const target = path22.resolve(absoluteFilePath);
138271
138330
  for (const root of roots) {
138272
- const rel = path20.relative(root, target);
138273
- if (rel !== "" && !rel.startsWith("..") && !path20.isAbsolute(rel)) {
138331
+ const rel = path22.relative(root, target);
138332
+ if (rel !== "" && !rel.startsWith("..") && !path22.isAbsolute(rel)) {
138274
138333
  return { allowed: true };
138275
138334
  }
138276
138335
  if (rel === "")
@@ -138286,6 +138345,23 @@ ${validRootsList}
138286
138345
  ` + `Provide a filePath that resolves under one of these roots.`
138287
138346
  };
138288
138347
  }
138348
+ }
138349
+ var init_path_containment = __esm(() => {
138350
+ init_dist();
138351
+ });
138352
+
138353
+ // ../../packages/core/dist/services/file-read/project-root-cache.js
138354
+ class ProjectRootCache {
138355
+ projectRootCache = new Map;
138356
+ ROOT_CACHE_TTL = 300000;
138357
+ PROJECT_ROOT_CACHE_MAX_ENTRIES = 512;
138358
+ constructor() {
138359
+ eventBus.subscribe("indexing:started", ({ projectId, projectPath: projectPath2 }) => {
138360
+ this.projectRootCache.delete(projectId);
138361
+ evictOldest(this.projectRootCache, this.PROJECT_ROOT_CACHE_MAX_ENTRIES - 1);
138362
+ this.projectRootCache.set(projectId, projectPath2);
138363
+ });
138364
+ }
138289
138365
  async getProjectRoot(projectId) {
138290
138366
  const cached2 = this.projectRootCache.get(projectId);
138291
138367
  if (cached2 !== undefined) {
@@ -138296,7 +138372,7 @@ ${validRootsList}
138296
138372
  try {
138297
138373
  const workspace = await workspaceManager.getWorkspace(projectId);
138298
138374
  if (workspace?.project_path) {
138299
- this.evictOldest(this.projectRootCache);
138375
+ evictOldest(this.projectRootCache, this.PROJECT_ROOT_CACHE_MAX_ENTRIES - 1);
138300
138376
  this.projectRootCache.set(projectId, workspace.project_path);
138301
138377
  return workspace.project_path;
138302
138378
  }
@@ -138305,182 +138381,236 @@ ${validRootsList}
138305
138381
  }
138306
138382
  return null;
138307
138383
  }
138308
- evictOldest(cache) {
138309
- while (cache.size >= this.FILE_CACHE_MAX_ENTRIES) {
138310
- const oldest = cache.keys().next().value;
138311
- if (oldest === undefined)
138312
- break;
138313
- cache.delete(oldest);
138314
- }
138315
- }
138316
- calculateRange(params) {
138317
- if (params.lineStart !== undefined && params.lineEnd !== undefined) {
138384
+ }
138385
+ var init_project_root_cache = __esm(() => {
138386
+ init_dist();
138387
+ init_event_bus();
138388
+ init_workspace_manager();
138389
+ });
138390
+
138391
+ // ../../packages/core/dist/services/file-read/read-file.service.js
138392
+ function readFileOptions(p) {
138393
+ const shouldCompress = p.compress !== false;
138394
+ const targetRatio = p.targetRatio || 0.3;
138395
+ const format = p.format || "json";
138396
+ const { fields } = p;
138397
+ const includeSymbols = p.includeSymbols !== false;
138398
+ const includeImports = p.includeImports !== false;
138399
+ return { shouldCompress, targetRatio, format, fields, includeSymbols, includeImports };
138400
+ }
138401
+
138402
+ class ReadFileService {
138403
+ compressor;
138404
+ symbolGraph;
138405
+ projectRoots;
138406
+ pathContainment;
138407
+ fileMetadata;
138408
+ fileContent;
138409
+ constructor(symbolGraph) {
138410
+ this.compressor = new CodeCompressor;
138411
+ this.symbolGraph = symbolGraph;
138412
+ this.projectRoots = new ProjectRootCache;
138413
+ this.pathContainment = new PathContainment(this.projectRoots);
138414
+ this.fileMetadata = new FileMetadataExtractor(symbolGraph);
138415
+ this.fileContent = new FileContentCache((content, filePath, options) => this.fileMetadata.extractMetadata(content, filePath, options));
138416
+ }
138417
+ async read(p, options) {
138418
+ const { shouldCompress, targetRatio, includeSymbols, includeImports } = options;
138419
+ const resolved = await this.pathContainment.resolveFilePath(p.filePath, p.projectId);
138420
+ if (resolved === null) {
138318
138421
  return {
138319
- start: Math.max(1, params.lineStart),
138320
- end: params.lineEnd
138422
+ ok: false,
138423
+ error: "Relative filePath requires a projectId (to resolve against the workspace) or an absolute path."
138321
138424
  };
138322
138425
  }
138323
- if (params.offset !== undefined) {
138324
- const offset = Math.max(1, params.offset);
138325
- const limit = params.limit || 1000;
138426
+ const filePath = resolved;
138427
+ const containment = await this.pathContainment.checkPathContainment(filePath, p.projectId);
138428
+ if (!containment.allowed) {
138326
138429
  return {
138327
- start: offset,
138328
- end: offset + limit - 1
138430
+ ok: false,
138431
+ error: containment.error
138329
138432
  };
138330
138433
  }
138331
- return {
138332
- start: 1,
138333
- end: Infinity
138334
- };
138335
- }
138336
- adjustRange(range, totalLines) {
138337
- const start = Math.max(1, Math.min(range.start, totalLines));
138338
- const end = range.end === Infinity ? totalLines : Math.min(range.end, totalLines);
138339
- return { start, end };
138340
- }
138341
- async readFileWithCache(filePath, options) {
138342
- const cacheKey = JSON.stringify({
138343
- filePath,
138344
- includeSymbols: options.includeSymbols ?? false,
138345
- includeImports: options.includeImports ?? false,
138346
- projectId: options.projectId ?? null,
138347
- relativePath: options.relativePath ?? null
138348
- });
138349
- const cached2 = this.fileCache.get(cacheKey);
138350
- if (cached2 && Date.now() - cached2.timestamp < this.CACHE_TTL) {
138351
- logger.debug("File cache hit", { filePath });
138352
- this.fileCache.delete(cacheKey);
138353
- this.fileCache.set(cacheKey, cached2);
138354
- if (!cached2.metadata) {
138355
- const metadata2 = await this.extractMetadata(cached2.content, filePath, options);
138356
- this.fileCache.set(cacheKey, { ...cached2, metadata: metadata2 });
138357
- return { content: cached2.content, metadata: metadata2 };
138358
- }
138359
- return {
138360
- content: cached2.content,
138361
- metadata: cached2.metadata
138362
- };
138363
- }
138364
- const content = await fs10.readFile(filePath, "utf-8");
138365
- const metadata = await this.extractMetadata(content, filePath, options);
138366
- this.evictOldest(this.fileCache);
138367
- this.fileCache.set(cacheKey, {
138368
- content,
138369
- timestamp: Date.now(),
138370
- metadata
138434
+ const relativePath = p.filePath;
138435
+ const range = calculateRange(p);
138436
+ const { content, metadata } = await this.fileContent.readFileWithCache(filePath, {
138437
+ includeSymbols,
138438
+ includeImports,
138439
+ projectId: p.projectId,
138440
+ relativePath
138371
138441
  });
138372
- logger.debug("File read and cached", { filePath });
138373
- return { content, metadata };
138374
- }
138375
- async extractMetadata(content, filePath, options) {
138376
138442
  const lines = content.split(`
138377
138443
  `);
138378
- const language = this.detectLanguage(filePath);
138379
- const metadata = {
138380
- totalLines: lines.length,
138381
- language
138444
+ const totalLines = lines.length;
138445
+ const adjustedRange = adjustRange(range, totalLines);
138446
+ const { content: selectedContent, lineCount: selectedLineCount, clipped: source_clipped } = selectLines(lines, adjustedRange);
138447
+ const shouldAutoCompress = shouldCompress && selectedLineCount > 100 && targetRatio < 1;
138448
+ const result = {
138449
+ filePath: p.filePath,
138450
+ absolutePath: filePath,
138451
+ lineRange: {
138452
+ requested: {
138453
+ start: range.start,
138454
+ end: range.end === Infinity ? null : range.end
138455
+ },
138456
+ actual: {
138457
+ start: adjustedRange.start,
138458
+ end: source_clipped ? adjustedRange.start + selectedLineCount - 1 : adjustedRange.end,
138459
+ total: totalLines
138460
+ },
138461
+ selected: selectedLineCount
138462
+ },
138463
+ source_clipped,
138464
+ metadata: {
138465
+ totalLines,
138466
+ language: metadata.language,
138467
+ ...metadata.symbols && { symbols: metadata.symbols },
138468
+ ...metadata.imports && { imports: metadata.imports }
138469
+ },
138470
+ compressed: shouldAutoCompress,
138471
+ recommendations: []
138382
138472
  };
138383
- if (options.includeImports && language) {
138384
- metadata.imports = this.extractImports(lines, language);
138385
- }
138386
- if (options.includeSymbols && this.symbolGraph && options.projectId) {
138387
- try {
138388
- const queryPath = options.relativePath || filePath;
138389
- const { definitions } = await this.symbolGraph.listDefinitions(options.projectId, {
138390
- file: queryPath,
138391
- limit: 100
138392
- });
138393
- metadata.symbols = {
138394
- definitions: definitions.length,
138395
- references: 0
138396
- };
138397
- } catch (error51) {
138398
- logger.debug("Failed to get symbol metadata", { filePath, error: error51 });
138473
+ if (shouldAutoCompress) {
138474
+ const compressed = await this.compressor.compress(selectedContent, "code_structure");
138475
+ const originalTokens = estimateTokens(selectedContent, "code");
138476
+ const compressedTokens = estimateTokens(compressed.compressed, "code");
138477
+ const actualRatio = compressedTokens / originalTokens;
138478
+ result.content = compressed.compressed;
138479
+ result.tokens = {
138480
+ original: originalTokens,
138481
+ compressed: compressedTokens,
138482
+ saved: originalTokens - compressedTokens,
138483
+ savingsPercent: Math.round((1 - actualRatio) * 100)
138484
+ };
138485
+ result.compressionRatio = actualRatio;
138486
+ result.recommendations.push(`\u2713 Auto-compressed ${selectedLineCount} lines (${result.tokens.savingsPercent}% reduction)`);
138487
+ } else {
138488
+ result.content = selectedContent;
138489
+ result.tokens = {
138490
+ original: estimateTokens(selectedContent, "code"),
138491
+ compressed: estimateTokens(selectedContent, "code"),
138492
+ saved: 0,
138493
+ savingsPercent: 0
138494
+ };
138495
+ if (selectedLineCount > 100) {
138496
+ result.recommendations.push("\uD83D\uDCA1 Content > 100 lines. Consider compress=true for token savings");
138399
138497
  }
138400
138498
  }
138401
- return metadata;
138402
- }
138403
- extractLines(lines, range) {
138404
- const start = range.start - 1;
138405
- const end = range.end;
138406
- const selectedLines = lines.slice(start, end);
138407
- return selectedLines.map((line, index) => {
138408
- const lineNum = start + index + 1;
138409
- return `${lineNum.toString().padStart(6, " ")}: ${line}`;
138410
- }).join(`
138411
- `);
138499
+ if (range.start === 1 && range.end === Infinity) {
138500
+ result.recommendations.push("\uD83D\uDCA1 Use lineStart/lineEnd or offset/limit to read specific sections (60% token savings)");
138501
+ }
138502
+ if (metadata.symbols && metadata.symbols.definitions > 0) {
138503
+ result.recommendations.push(`\uD83D\uDCA1 Use get_references() to find usages of ${metadata.symbols.definitions} symbols in this file`);
138504
+ }
138505
+ return { ok: true, data: result };
138412
138506
  }
138413
- detectLanguage(filePath) {
138414
- const ext2 = path20.extname(filePath).toLowerCase();
138415
- const languageMap2 = {
138416
- ".ts": "TypeScript",
138417
- ".tsx": "TypeScript",
138418
- ".js": "JavaScript",
138419
- ".jsx": "JavaScript",
138420
- ".vue": "Vue",
138421
- ".py": "Python",
138422
- ".go": "Go",
138423
- ".rs": "Rust",
138424
- ".java": "Java",
138425
- ".cpp": "C++",
138426
- ".c": "C",
138427
- ".h": "C",
138428
- ".hpp": "C++",
138429
- ".cs": "C#",
138430
- ".rb": "Ruby",
138431
- ".php": "PHP",
138432
- ".swift": "Swift",
138433
- ".kt": "Kotlin",
138434
- ".kts": "Kotlin",
138435
- ".scala": "Scala",
138436
- ".md": "Markdown",
138437
- ".json": "JSON",
138438
- ".yaml": "YAML",
138439
- ".yml": "YAML",
138440
- ".xml": "XML",
138441
- ".html": "HTML",
138442
- ".css": "CSS",
138443
- ".scss": "SCSS",
138444
- ".sql": "SQL",
138445
- ".sh": "Shell",
138446
- ".bash": "Shell"
138447
- };
138448
- return languageMap2[ext2];
138507
+ }
138508
+ var init_read_file_service = __esm(() => {
138509
+ init_dist();
138510
+ init_code_compressor();
138511
+ init_file_content_cache();
138512
+ init_file_metadata();
138513
+ init_line_range();
138514
+ init_path_containment();
138515
+ init_project_root_cache();
138516
+ });
138517
+
138518
+ // ../../packages/core/dist/tools/read_file.js
138519
+ class ReadFileTool {
138520
+ name = "read_file";
138521
+ description = "Read file with automatic compression, caching, and symbol metadata. " + "Use with search results for 60% token savings.";
138522
+ inputSchema = {
138523
+ type: "object",
138524
+ properties: {
138525
+ filePath: {
138526
+ type: "string",
138527
+ description: "File path (absolute or relative to project root)"
138528
+ },
138529
+ projectId: {
138530
+ type: "string",
138531
+ description: "Project ID for symbol metadata (optional)"
138532
+ },
138533
+ offset: {
138534
+ type: "number",
138535
+ description: "Start line number (1-indexed)"
138536
+ },
138537
+ limit: {
138538
+ type: "number",
138539
+ description: "Number of lines to read"
138540
+ },
138541
+ lineStart: {
138542
+ type: "number",
138543
+ description: "Start line (alternative to offset)"
138544
+ },
138545
+ lineEnd: {
138546
+ type: "number",
138547
+ description: "End line (alternative to limit)"
138548
+ },
138549
+ compress: {
138550
+ type: "boolean",
138551
+ description: "Auto-compress content > 100 lines (default: true)",
138552
+ default: true
138553
+ },
138554
+ targetRatio: {
138555
+ type: "number",
138556
+ description: "Compression target ratio (0.3 = 70% reduction)",
138557
+ default: 0.3
138558
+ },
138559
+ format: {
138560
+ type: "string",
138561
+ enum: ["json", "toon"],
138562
+ description: "Output format",
138563
+ default: "json"
138564
+ },
138565
+ fields: {
138566
+ type: "array",
138567
+ items: { type: "string" },
138568
+ description: "Projection \u2014 keep only these keys (dotted paths supported, e.g. ['nodes.symbol']). Absent/empty \u2192 full data."
138569
+ },
138570
+ includeSymbols: {
138571
+ type: "boolean",
138572
+ description: "Include symbol metadata from graph (default: true)",
138573
+ default: true
138574
+ },
138575
+ includeImports: {
138576
+ type: "boolean",
138577
+ description: "Extract and show import statements (default: true)",
138578
+ default: true
138579
+ }
138580
+ },
138581
+ required: ["filePath"]
138582
+ };
138583
+ service;
138584
+ constructor(symbolGraph) {
138585
+ this.service = new ReadFileService(symbolGraph);
138449
138586
  }
138450
- extractImports(lines, language) {
138451
- const imports = [];
138452
- const importPatterns = {
138453
- TypeScript: /^(import\s+.*?from\s+['"]|import\s+['"])/,
138454
- JavaScript: /^(import\s+.*?from\s+['"]|import\s+['"]|require\s*\(\s*['"])/,
138455
- Python: /^(import\s+|from\s+\S+\s+import)/,
138456
- Go: /^import\s+/,
138457
- Java: /^import\s+/,
138458
- Rust: /^use\s+/
138459
- };
138460
- const pattern = importPatterns[language];
138461
- if (!pattern)
138462
- return imports;
138463
- for (const line of lines) {
138464
- const trimmed = line.trim();
138465
- if (pattern.test(trimmed)) {
138466
- imports.push(trimmed);
138587
+ async handle(params) {
138588
+ const p = params;
138589
+ const options = readFileOptions(p);
138590
+ try {
138591
+ const outcome2 = await this.service.read(p, options);
138592
+ if (!outcome2.ok) {
138593
+ return { success: false, error: outcome2.error };
138467
138594
  }
138595
+ return serializeToolResponse(outcome2.data, {
138596
+ format: options.format,
138597
+ fields: options.fields
138598
+ });
138599
+ } catch (error51) {
138600
+ logger.error("Failed to read file", error51, {
138601
+ filePath: p.filePath
138602
+ });
138603
+ return {
138604
+ success: false,
138605
+ error: `Failed to read file: ${error51.message}`
138606
+ };
138468
138607
  }
138469
- return imports;
138470
138608
  }
138471
138609
  }
138472
- var MASSA_AI_READ_FILE_MAX_LINES;
138473
138610
  var init_read_file = __esm(() => {
138474
138611
  init_dist();
138475
- init_dist();
138476
- init_code_compressor();
138477
138612
  init_serialize();
138478
- init_event_bus();
138479
- init_workspace_manager();
138480
- MASSA_AI_READ_FILE_MAX_LINES = (() => {
138481
- const v = Number(process.env.MASSA_AI_READ_FILE_MAX_LINES);
138482
- return Number.isFinite(v) && v > 0 ? Math.floor(v) : 500;
138483
- })();
138613
+ init_read_file_service();
138484
138614
  });
138485
138615
 
138486
138616
  // ../../packages/core/dist/tools/execute.js
@@ -141415,7 +141545,7 @@ var init_l1_memory_cache = __esm(() => {
141415
141545
  // ../../packages/core/dist/services/health/local-health-checker.js
141416
141546
  import fs11 from "fs/promises";
141417
141547
  import { existsSync as existsSync3 } from "fs";
141418
- import path21 from "path";
141548
+ import path23 from "path";
141419
141549
 
141420
141550
  class LocalHealthChecker {
141421
141551
  ollamaBaseUrl = process.env.OLLAMA_BASE_URL || "http://localhost:11434";
@@ -141450,7 +141580,7 @@ class LocalHealthChecker {
141450
141580
  try {
141451
141581
  if (!existsSync3(this.dataDir))
141452
141582
  await fs11.mkdir(this.dataDir, { recursive: true });
141453
- const probe2 = path21.join(this.dataDir, ".health-check-test");
141583
+ const probe2 = path23.join(this.dataDir, ".health-check-test");
141454
141584
  await fs11.writeFile(probe2, "ok");
141455
141585
  await fs11.unlink(probe2);
141456
141586
  return { available: true, latency: Date.now() - start, details: { path: this.dataDir, writable: true } };
@@ -143393,7 +143523,7 @@ var init_scheduler2 = __esm(() => {
143393
143523
  // ../../packages/core/dist/services/pricing/models-dev-client.js
143394
143524
  import fs12 from "fs/promises";
143395
143525
  import { existsSync as existsSync4 } from "fs";
143396
- import path22 from "path";
143526
+ import path24 from "path";
143397
143527
  function getModelsDevClient() {
143398
143528
  if (!clientInstance) {
143399
143529
  clientInstance = new ModelsDevClient;
@@ -143413,7 +143543,7 @@ var init_models_dev_client = __esm(() => {
143413
143543
  memoryCacheTimestamp = 0;
143414
143544
  getLocalCachePath() {
143415
143545
  const dataDir = config2.get("dataDir");
143416
- return path22.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
143546
+ return path24.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
143417
143547
  }
143418
143548
  async loadLocalCache() {
143419
143549
  const cachePath = this.getLocalCachePath();
@@ -143448,7 +143578,7 @@ var init_models_dev_client = __esm(() => {
143448
143578
  async saveLocalCache(models) {
143449
143579
  const cachePath = this.getLocalCachePath();
143450
143580
  try {
143451
- const dir = path22.dirname(cachePath);
143581
+ const dir = path24.dirname(cachePath);
143452
143582
  await fs12.mkdir(dir, { recursive: true });
143453
143583
  const data = {
143454
143584
  timestamp: Date.now(),
@@ -149339,33 +149469,33 @@ var require_URL = __commonJS((exports, module) => {
149339
149469
  else
149340
149470
  return basepath.substring(0, lastslash + 1) + refpath;
149341
149471
  }
149342
- function remove_dot_segments(path23) {
149343
- if (!path23)
149344
- return path23;
149472
+ function remove_dot_segments(path25) {
149473
+ if (!path25)
149474
+ return path25;
149345
149475
  var output = "";
149346
- while (path23.length > 0) {
149347
- if (path23 === "." || path23 === "..") {
149348
- path23 = "";
149476
+ while (path25.length > 0) {
149477
+ if (path25 === "." || path25 === "..") {
149478
+ path25 = "";
149349
149479
  break;
149350
149480
  }
149351
- var twochars = path23.substring(0, 2);
149352
- var threechars = path23.substring(0, 3);
149353
- var fourchars = path23.substring(0, 4);
149481
+ var twochars = path25.substring(0, 2);
149482
+ var threechars = path25.substring(0, 3);
149483
+ var fourchars = path25.substring(0, 4);
149354
149484
  if (threechars === "../") {
149355
- path23 = path23.substring(3);
149485
+ path25 = path25.substring(3);
149356
149486
  } else if (twochars === "./") {
149357
- path23 = path23.substring(2);
149487
+ path25 = path25.substring(2);
149358
149488
  } else if (threechars === "/./") {
149359
- path23 = "/" + path23.substring(3);
149360
- } else if (twochars === "/." && path23.length === 2) {
149361
- path23 = "/";
149362
- } else if (fourchars === "/../" || threechars === "/.." && path23.length === 3) {
149363
- path23 = "/" + path23.substring(4);
149489
+ path25 = "/" + path25.substring(3);
149490
+ } else if (twochars === "/." && path25.length === 2) {
149491
+ path25 = "/";
149492
+ } else if (fourchars === "/../" || threechars === "/.." && path25.length === 3) {
149493
+ path25 = "/" + path25.substring(4);
149364
149494
  output = output.replace(/\/?[^\/]*$/, "");
149365
149495
  } else {
149366
- var segment = path23.match(/(\/?([^\/]*))/)[0];
149496
+ var segment = path25.match(/(\/?([^\/]*))/)[0];
149367
149497
  output += segment;
149368
- path23 = path23.substring(segment.length);
149498
+ path25 = path25.substring(segment.length);
149369
149499
  }
149370
149500
  }
149371
149501
  return output;
@@ -161435,21 +161565,21 @@ function jsonToKeyPathChunks(value, label = "$") {
161435
161565
  walk(value, label, out);
161436
161566
  return out;
161437
161567
  }
161438
- function walk(val, path23, out) {
161568
+ function walk(val, path25, out) {
161439
161569
  if (val === null || val === undefined)
161440
161570
  return;
161441
161571
  if (Array.isArray(val)) {
161442
161572
  if (val.length === 0) {
161443
- out.push({ path: path23, content: `**${path23}** = _[]_` });
161573
+ out.push({ path: path25, content: `**${path25}** = _[]_` });
161444
161574
  return;
161445
161575
  }
161446
161576
  if (val.every((v) => v !== null && typeof v === "object")) {
161447
- val.forEach((v, i) => walk(v, `${path23}[${i}]`, out));
161577
+ val.forEach((v, i) => walk(v, `${path25}[${i}]`, out));
161448
161578
  return;
161449
161579
  }
161450
161580
  const items = val.map((v) => `- \`${String(v)}\``).join(`
161451
161581
  `);
161452
- out.push({ path: path23, content: `**${path23}**
161582
+ out.push({ path: path25, content: `**${path25}**
161453
161583
 
161454
161584
  ${items}` });
161455
161585
  return;
@@ -161457,16 +161587,16 @@ ${items}` });
161457
161587
  if (typeof val === "object") {
161458
161588
  const entries = Object.entries(val);
161459
161589
  if (entries.length === 0) {
161460
- out.push({ path: path23, content: `**${path23}** = _{}_` });
161590
+ out.push({ path: path25, content: `**${path25}** = _{}_` });
161461
161591
  return;
161462
161592
  }
161463
161593
  for (const [k, v] of entries) {
161464
161594
  const safeKey = /^[A-Za-z_$][\w$]*$/.test(k) ? k : JSON.stringify(k);
161465
- walk(v, `${path23}.${safeKey}`, out);
161595
+ walk(v, `${path25}.${safeKey}`, out);
161466
161596
  }
161467
161597
  return;
161468
161598
  }
161469
- out.push({ path: path23, content: `**${path23}** = \`${String(val)}\`` });
161599
+ out.push({ path: path25, content: `**${path25}** = \`${String(val)}\`` });
161470
161600
  }
161471
161601
  var gfm, STRIP_SELECTORS, tdCache = null;
161472
161602
  var init_html_to_md = __esm(() => {
@@ -161732,12 +161862,7 @@ class WebController {
161732
161862
  markIndexed: (key, ts) => {
161733
161863
  this.cache.delete(key);
161734
161864
  this.cache.set(key, ts);
161735
- while (this.cache.size > WEB_CACHE_MAX_ENTRIES) {
161736
- const oldest = this.cache.keys().next().value;
161737
- if (oldest === undefined)
161738
- break;
161739
- this.cache.delete(oldest);
161740
- }
161865
+ evictOldest(this.cache, WEB_CACHE_MAX_ENTRIES);
161741
161866
  }
161742
161867
  };
161743
161868
  }
@@ -162225,7 +162350,7 @@ var init_hook_service = __esm(() => {
162225
162350
  // ../../packages/core/dist/services/bootstrap/bootstrap-service.js
162226
162351
  import { randomUUID as randomUUID9 } from "crypto";
162227
162352
  import fs13 from "fs";
162228
- import path23 from "path";
162353
+ import path25 from "path";
162229
162354
  import { spawn as spawn2 } from "child_process";
162230
162355
  function readBootstrapConfig() {
162231
162356
  try {
@@ -162385,7 +162510,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
162385
162510
  }
162386
162511
  try {
162387
162512
  for (const name26 of README_CANDIDATES) {
162388
- const p = path23.join(projectRoot, name26);
162513
+ const p = path25.join(projectRoot, name26);
162389
162514
  if (fs13.existsSync(p) && fs13.statSync(p).isFile()) {
162390
162515
  const buf = fs13.readFileSync(p);
162391
162516
  signals.readme = buf.slice(0, MAX_README_BYTES).toString("utf8");
@@ -162396,14 +162521,14 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
162396
162521
  logger.debug("bootstrap scan: README read failed", { error: e.message });
162397
162522
  }
162398
162523
  try {
162399
- const docsDir = path23.join(projectRoot, "docs");
162524
+ const docsDir = path25.join(projectRoot, "docs");
162400
162525
  if (fs13.existsSync(docsDir) && fs13.statSync(docsDir).isDirectory()) {
162401
162526
  const entries = walkMarkdown(docsDir).slice(0, MAX_DOCS);
162402
162527
  for (const rel of entries) {
162403
162528
  try {
162404
162529
  const buf = fs13.readFileSync(rel);
162405
162530
  signals.docs.push({
162406
- path: path23.relative(projectRoot, rel),
162531
+ path: path25.relative(projectRoot, rel),
162407
162532
  snippet: buf.slice(0, MAX_DOC_BYTES).toString("utf8")
162408
162533
  });
162409
162534
  } catch {}
@@ -162414,7 +162539,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
162414
162539
  }
162415
162540
  try {
162416
162541
  for (const name26 of MANIFEST_FILES) {
162417
- const p = path23.join(projectRoot, name26);
162542
+ const p = path25.join(projectRoot, name26);
162418
162543
  if (!fs13.existsSync(p) || !fs13.statSync(p).isFile())
162419
162544
  continue;
162420
162545
  const raw2 = fs13.readFileSync(p).slice(0, MAX_MANIFEST_BYTES).toString("utf8");
@@ -162462,7 +162587,7 @@ function walkMarkdown(dir) {
162462
162587
  continue;
162463
162588
  }
162464
162589
  for (const e of entries) {
162465
- const full = path23.join(cur, e.name);
162590
+ const full = path25.join(cur, e.name);
162466
162591
  if (e.isDirectory()) {
162467
162592
  if (e.name === "node_modules" || e.name.startsWith("."))
162468
162593
  continue;
@@ -165980,7 +166105,7 @@ init_dist();
165980
166105
  init_dist15();
165981
166106
  init_dist();
165982
166107
  import fs14 from "fs/promises";
165983
- import path24 from "path";
166108
+ import path26 from "path";
165984
166109
  var _indexProjectTool = null;
165985
166110
  function indexProjectTool() {
165986
166111
  if (!_indexProjectTool)
@@ -166250,7 +166375,7 @@ class EmbeddedApiClient {
166250
166375
  } else {
166251
166376
  end = start + 20;
166252
166377
  }
166253
- const absolutePath = path24.join(workspace.project_path, file2);
166378
+ const absolutePath = path26.join(workspace.project_path, file2);
166254
166379
  const content = await fs14.readFile(absolutePath, "utf-8");
166255
166380
  const lines = content.split(/\r?\n/);
166256
166381
  const slice = lines.slice(start - 1, Math.min(lines.length, end));
@@ -166474,21 +166599,21 @@ class EmbeddedApiClient {
166474
166599
  async uploadAndIndex(params) {
166475
166600
  const rawBase = params.projectId || params.projectPath.replace(/\\/g, "/").split("/").filter(Boolean).pop() || "default";
166476
166601
  const finalProjectId = rawBase.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 128);
166477
- const uploadRoot = process.env.MASSA_AI_UPLOAD_DIR || path24.join(getGlobalDataDir(), "uploads");
166478
- const stagingDir = path24.resolve(uploadRoot, finalProjectId);
166602
+ const uploadRoot = process.env.MASSA_AI_UPLOAD_DIR || path26.join(getGlobalDataDir(), "uploads");
166603
+ const stagingDir = path26.resolve(uploadRoot, finalProjectId);
166479
166604
  await fs14.rm(stagingDir, { recursive: true, force: true });
166480
166605
  await fs14.mkdir(stagingDir, { recursive: true });
166481
166606
  const WRITE_BATCH = 20;
166482
166607
  for (let i = 0;i < params.files.length; i += WRITE_BATCH) {
166483
166608
  await Promise.all(params.files.slice(i, i + WRITE_BATCH).map(async (file2) => {
166484
- if (path24.isAbsolute(file2.relativePath) || file2.relativePath.includes("..")) {
166609
+ if (path26.isAbsolute(file2.relativePath) || file2.relativePath.includes("..")) {
166485
166610
  throw new Error(`Invalid file path: ${file2.relativePath}`);
166486
166611
  }
166487
- const dest = path24.resolve(stagingDir, file2.relativePath.replace(/\//g, path24.sep));
166488
- if (!dest.startsWith(stagingDir + path24.sep)) {
166612
+ const dest = path26.resolve(stagingDir, file2.relativePath.replace(/\//g, path26.sep));
166613
+ if (!dest.startsWith(stagingDir + path26.sep)) {
166489
166614
  throw new Error(`Path escapes staging directory: ${file2.relativePath}`);
166490
166615
  }
166491
- await fs14.mkdir(path24.dirname(dest), { recursive: true });
166616
+ await fs14.mkdir(path26.dirname(dest), { recursive: true });
166492
166617
  await fs14.writeFile(dest, file2.content, "utf-8");
166493
166618
  }));
166494
166619
  }
@@ -166822,7 +166947,7 @@ class EmbeddedApiClient {
166822
166947
  // src/file-collector.ts
166823
166948
  init_config();
166824
166949
  import fs15 from "fs/promises";
166825
- import path25 from "path";
166950
+ import path27 from "path";
166826
166951
  var SKIP_DIRS = new Set([
166827
166952
  "node_modules",
166828
166953
  ".git",
@@ -166872,13 +166997,13 @@ async function walk2(root2, dir, files, state, allowed) {
166872
166997
  break;
166873
166998
  if (entry2.isDirectory()) {
166874
166999
  if (!SKIP_DIRS.has(entry2.name) && !entry2.name.startsWith(".")) {
166875
- await walk2(root2, path25.join(dir, entry2.name), files, state, allowed);
167000
+ await walk2(root2, path27.join(dir, entry2.name), files, state, allowed);
166876
167001
  }
166877
167002
  } else if (entry2.isFile()) {
166878
- const ext2 = path25.extname(entry2.name).toLowerCase();
167003
+ const ext2 = path27.extname(entry2.name).toLowerCase();
166879
167004
  if (!allowed.has(ext2))
166880
167005
  continue;
166881
- const fullPath = path25.join(dir, entry2.name);
167006
+ const fullPath = path27.join(dir, entry2.name);
166882
167007
  try {
166883
167008
  const stat = await fs15.stat(fullPath);
166884
167009
  if (stat.size > MAX_FILE_BYTES)
@@ -166887,7 +167012,7 @@ async function walk2(root2, dir, files, state, allowed) {
166887
167012
  continue;
166888
167013
  const content = await fs15.readFile(fullPath, "utf-8");
166889
167014
  state.totalBytes += stat.size;
166890
- const relativePath = path25.relative(root2, fullPath).split(path25.sep).join("/");
167015
+ const relativePath = path27.relative(root2, fullPath).split(path27.sep).join("/");
166891
167016
  files.push({ relativePath, content });
166892
167017
  } catch {}
166893
167018
  }