@massa-ai/mcp-client 1.16.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.
Files changed (3) hide show
  1. package/dist/config-cli.js +9645 -8957
  2. package/dist/index.js +818 -680
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -37759,7 +37759,7 @@ var init_esm6 = __esm(() => {
37759
37759
  esm_default = import_lib.default;
37760
37760
  });
37761
37761
 
37762
- // ../../packages/core/dist/data/db-connection.js
37762
+ // ../../packages/core/dist/kernel/db-connection.js
37763
37763
  function getDbConfig() {
37764
37764
  return {
37765
37765
  connectionString: requirePostgresDatabaseUrl(),
@@ -37787,7 +37787,7 @@ var init_db_connection = __esm(() => {
37787
37787
  init_config();
37788
37788
  });
37789
37789
 
37790
- // ../../packages/core/dist/services/project-identity/alias-resolver.js
37790
+ // ../../packages/core/dist/kernel/alias-resolver.js
37791
37791
  class ProjectIdentityAliasResolver {
37792
37792
  ttlMs;
37793
37793
  resolveTimeoutMs;
@@ -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;
@@ -112233,7 +112232,7 @@ var require_dist9 = __commonJS((exports, module) => {
112233
112232
  };
112234
112233
  });
112235
112234
 
112236
- // ../../packages/core/dist/services/query/prisma-client.js
112235
+ // ../../packages/core/dist/kernel/prisma-client.js
112237
112236
  var exports_prisma_client = {};
112238
112237
  __export(exports_prisma_client, {
112239
112238
  getPrismaClient: () => getPrismaClient2,
@@ -113044,7 +113043,7 @@ var init_query_understanding = __esm(() => {
113044
113043
  HYDE_SYSTEM = "You write a hypothetical implementation paragraph that a code-knowledge " + "search system will embed and match against real documents. Write ONE " + "concise paragraph (3-6 sentences) of plausible implementation detail " + "(types, function signatures, control flow) that a relevant document would " + "contain. No preamble, no markdown.";
113045
113044
  });
113046
113045
 
113047
- // ../../packages/core/dist/services/structural/types.js
113046
+ // ../../packages/core/dist/kernel/types.js
113048
113047
  var STRUCTURAL_TAXONOMY_VERSION = "1.0.0", SOURCE_SPAN_SCHEMA_VERSION = "1.0.0", STRUCTURAL_FQN_SCHEMA_VERSION = "1.0.0";
113049
113048
  var init_types3 = __esm(() => {
113050
113049
  init_dist();
@@ -114136,7 +114135,7 @@ answer = 42
114136
114135
  });
114137
114136
  });
114138
114137
 
114139
- // ../../packages/core/dist/services/project-identity/registry.js
114138
+ // ../../packages/core/dist/kernel/registry.js
114140
114139
  function directStorePolicy(tableName, columnName) {
114141
114140
  if (/^vector_documents(?:_\d+d)?$/.test(tableName) && columnName === "project_id") {
114142
114141
  return { storeId: tableName, identityColumn: columnName, mutable: true };
@@ -114197,7 +114196,7 @@ var init_registry = __esm(() => {
114197
114196
  ];
114198
114197
  });
114199
114198
 
114200
- // ../../packages/core/dist/services/project-identity/identity-guard-installer.js
114199
+ // ../../packages/core/dist/kernel/identity-guard-installer.js
114201
114200
  async function installGuardOnTable(client, schema, table, column) {
114202
114201
  try {
114203
114202
  await client.query(`SELECT project_identity_install_guard($1::regclass, $2)`, [`${schema}.${table}`, column]);
@@ -114262,7 +114261,7 @@ var init_identity_guard_installer = __esm(() => {
114262
114261
  init_registry();
114263
114262
  });
114264
114263
 
114265
- // ../../packages/core/dist/services/search/lexical-search.js
114264
+ // ../../packages/core/dist/kernel/lexical-search.js
114266
114265
  function dedupeTokens(tokens) {
114267
114266
  const seen = new Set;
114268
114267
  const out = [];
@@ -114926,9 +114925,16 @@ var init_keyword_search_factory = __esm(() => {
114926
114925
  // ../../packages/core/dist/data/vector/base-vector-store.js
114927
114926
  class BaseVectorStore {
114928
114927
  embeddingProviderPromise = null;
114928
+ embeddingProviderFactory;
114929
+ constructor(options) {
114930
+ this.embeddingProviderFactory = options?.embeddingProviderFactory;
114931
+ }
114929
114932
  getEmbeddingProvider() {
114930
114933
  if (!this.embeddingProviderPromise) {
114931
- this.embeddingProviderPromise = createEmbeddingProvider({ cache: true });
114934
+ if (!this.embeddingProviderFactory) {
114935
+ throw new Error("BaseVectorStore: no embeddingProviderFactory was supplied. Construct this store " + "via services/vector/vector-store-factory.ts (getVectorStore), or pass an explicit " + "embeddingProviderFactory to the constructor.");
114936
+ }
114937
+ this.embeddingProviderPromise = this.embeddingProviderFactory();
114932
114938
  }
114933
114939
  return this.embeddingProviderPromise;
114934
114940
  }
@@ -114974,7 +114980,6 @@ class BaseVectorStore {
114974
114980
  }
114975
114981
  }
114976
114982
  var init_base_vector_store = __esm(() => {
114977
- init_embeddings();
114978
114983
  init_dist();
114979
114984
  });
114980
114985
 
@@ -115100,7 +115105,7 @@ var init_postgres_vector_store = __esm(() => {
115100
115105
  tableName = "vector_documents";
115101
115106
  bqEnabled = false;
115102
115107
  constructor(config3) {
115103
- super();
115108
+ super(config3.embeddingProviderFactory ? { embeddingProviderFactory: config3.embeddingProviderFactory } : undefined);
115104
115109
  this.config = {
115105
115110
  poolSize: 10,
115106
115111
  indexType: "hnsw",
@@ -115556,7 +115561,7 @@ var init_postgres_vector_store = __esm(() => {
115556
115561
  };
115557
115562
  });
115558
115563
 
115559
- // ../../packages/core/dist/data/vector/vector-store-factory.js
115564
+ // ../../packages/core/dist/services/vector/vector-store-factory.js
115560
115565
  async function getVectorStore(config3) {
115561
115566
  if (cachedStore)
115562
115567
  return cachedStore;
@@ -115573,6 +115578,7 @@ async function getVectorStore(config3) {
115573
115578
  ...ivfflatLists ? { lists: ivfflatLists } : {}
115574
115579
  };
115575
115580
  const store = new PostgresVectorStore({
115581
+ embeddingProviderFactory: () => createEmbeddingProvider({ cache: true }),
115576
115582
  connectionString,
115577
115583
  poolSize: Number.parseInt(process.env.POSTGRES_VECTOR_POOL_SIZE || "10", 10),
115578
115584
  indexType: process.env.POSTGRES_VECTOR_INDEX || "hnsw",
@@ -115605,6 +115611,7 @@ var init_vector_store_factory = __esm(() => {
115605
115611
  init_dist();
115606
115612
  init_config();
115607
115613
  init_postgres_vector_store();
115614
+ init_embeddings();
115608
115615
  });
115609
115616
 
115610
115617
  // ../../packages/core/dist/services/search/search-cache-pg.js
@@ -116176,7 +116183,7 @@ var init_analytics_factory = __esm(() => {
116176
116183
  init_dist();
116177
116184
  });
116178
116185
 
116179
- // ../../packages/core/dist/services/structural/schema-version.js
116186
+ // ../../packages/core/dist/kernel/schema-version.js
116180
116187
  function parseSemver(version3) {
116181
116188
  const match2 = SEMVER_PATTERN.exec(version3.trim());
116182
116189
  if (!match2)
@@ -116215,7 +116222,7 @@ var init_schema_version = __esm(() => {
116215
116222
  SEMVER_PATTERN = /^(\d+)\.(\d+)\.(\d+)$/u;
116216
116223
  });
116217
116224
 
116218
- // ../../packages/core/dist/services/structural/fqn-codec.js
116225
+ // ../../packages/core/dist/kernel/fqn-codec.js
116219
116226
  import { createHash as createHash3 } from "crypto";
116220
116227
  function normalizedNfcText(value, label) {
116221
116228
  const normalized = value.normalize("NFC").trim();
@@ -118532,7 +118539,7 @@ var init_memory_repository_factory = __esm(() => {
118532
118539
  init_memory_repository_pg();
118533
118540
  });
118534
118541
 
118535
- // ../../packages/core/dist/services/graph/graph-store-pg.js
118542
+ // ../../packages/core/dist/services/memory-graph/graph-store-pg.js
118536
118543
  function metadataForEdge(edge) {
118537
118544
  return {
118538
118545
  autoExtracted: edge.autoExtracted ?? false,
@@ -118848,7 +118855,7 @@ var init_graph_store_pg = __esm(() => {
118848
118855
  graphStorePg = GraphStorePg.getInstance();
118849
118856
  });
118850
118857
 
118851
- // ../../packages/core/dist/services/graph/graph-store-factory.js
118858
+ // ../../packages/core/dist/services/memory-graph/graph-store-factory.js
118852
118859
  function getGraphStore() {
118853
118860
  if (cachedStore2)
118854
118861
  return cachedStore2;
@@ -120454,7 +120461,7 @@ var init_reranker = __esm(() => {
120454
120461
  });
120455
120462
  });
120456
120463
 
120457
- // ../../packages/core/dist/tools/enum-validation.js
120464
+ // ../../packages/core/dist/kernel/enum-validation.js
120458
120465
  function validateEnum(paramName, value, validValues) {
120459
120466
  if (typeof value !== "string" || !validValues.includes(value)) {
120460
120467
  throw new ToolError(`Invalid ${paramName} value: ${String(value)}. Valid values: ${validValues.join(", ")}.`);
@@ -120526,7 +120533,7 @@ var init_filter_validation = __esm(() => {
120526
120533
  init_enum_validation();
120527
120534
  });
120528
120535
 
120529
- // ../../packages/core/dist/controllers/search-controller.js
120536
+ // ../../packages/core/dist/services/search/search-controller.js
120530
120537
  var exports_search_controller = {};
120531
120538
  __export(exports_search_controller, {
120532
120539
  SearchController: () => SearchController
@@ -121271,7 +121278,7 @@ var init_session_bias = __esm(() => {
121271
121278
  init_synapse();
121272
121279
  });
121273
121280
 
121274
- // ../../packages/core/dist/services/search/search-diagnostics.js
121281
+ // ../../packages/core/dist/kernel/search-diagnostics.js
121275
121282
  function searchBackendUnavailable(component, cause) {
121276
121283
  return cause instanceof SearchServiceError ? cause : new SearchServiceError("SEARCH_BACKEND_UNAVAILABLE", component, { cause });
121277
121284
  }
@@ -129047,6 +129054,133 @@ var init_pipeline = __esm(() => {
129047
129054
  };
129048
129055
  });
129049
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
+
129050
129184
  // ../../packages/core/dist/services/symbol/definition-lookup.js
129051
129185
  function toSymbolIdentityResolution(result) {
129052
129186
  switch (result.status) {
@@ -129782,16 +129916,16 @@ function detectRoutes(httpEdges, defs, opts = {}) {
129782
129916
  const seen = new Set;
129783
129917
  const out = [];
129784
129918
  for (const e of httpEdges) {
129785
- const path17 = e.route;
129786
- if (!path17)
129919
+ const path18 = e.route;
129920
+ if (!path18)
129787
129921
  continue;
129788
129922
  const method = (e.method ?? "ANY").toUpperCase();
129789
- const key = method + " " + path17;
129923
+ const key = method + " " + path18;
129790
129924
  if (seen.has(key))
129791
129925
  continue;
129792
129926
  seen.add(key);
129793
129927
  out.push({
129794
- path: path17,
129928
+ path: path18,
129795
129929
  method: e.method,
129796
129930
  file: e.fromFile,
129797
129931
  handler: e.targetFqn ?? e.symbolName
@@ -129802,12 +129936,12 @@ function detectRoutes(httpEdges, defs, opts = {}) {
129802
129936
  continue;
129803
129937
  const parsed = parseRouteName(d.name);
129804
129938
  const method = parsed?.method ?? "ANY";
129805
- const path17 = parsed?.path ?? d.name;
129806
- const key = method + " " + path17;
129939
+ const path18 = parsed?.path ?? d.name;
129940
+ const key = method + " " + path18;
129807
129941
  if (seen.has(key))
129808
129942
  continue;
129809
129943
  seen.add(key);
129810
- 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 });
129811
129945
  }
129812
129946
  for (const d of defs) {
129813
129947
  const parsed = parseRouteName(d.name);
@@ -130028,7 +130162,7 @@ __export(exports_symbol_graph_service, {
130028
130162
  symbolGraphService: () => symbolGraphService,
130029
130163
  SymbolGraphService: () => SymbolGraphService
130030
130164
  });
130031
- import path17 from "path";
130165
+ import path18 from "path";
130032
130166
  import fs8 from "fs/promises";
130033
130167
 
130034
130168
  class SymbolGraphService {
@@ -130382,7 +130516,7 @@ class SymbolGraphService {
130382
130516
  }
130383
130517
  async resolveToAbsolute(relativePath, projectId) {
130384
130518
  const root = await this.getProjectRoot(projectId);
130385
- return root ? path17.resolve(root, relativePath) : relativePath;
130519
+ return root ? path18.resolve(root, relativePath) : relativePath;
130386
130520
  }
130387
130521
  async getProjectRoot(projectId) {
130388
130522
  const cached2 = this.projectRootCache.get(projectId);
@@ -130402,12 +130536,7 @@ class SymbolGraphService {
130402
130536
  return null;
130403
130537
  }
130404
130538
  evictOldestProjectRoot() {
130405
- while (this.projectRootCache.size >= this.PROJECT_ROOT_CACHE_MAX_ENTRIES) {
130406
- const oldest = this.projectRootCache.keys().next().value;
130407
- if (oldest === undefined)
130408
- break;
130409
- this.projectRootCache.delete(oldest);
130410
- }
130539
+ evictOldest(this.projectRootCache, this.PROJECT_ROOT_CACHE_MAX_ENTRIES - 1);
130411
130540
  }
130412
130541
  clearProjectRoot(projectId) {
130413
130542
  this.projectRootCache.delete(projectId);
@@ -130530,25 +130659,7 @@ var init_workspace_manager = __esm(() => {
130530
130659
  });
130531
130660
 
130532
130661
  // ../../packages/core/dist/tools/index_project.js
130533
- import { realpath as realpath2 } from "fs/promises";
130534
- import path18 from "path";
130535
- async function canonicalizeProjectRoot(projectPath, canonicalize = realpath2) {
130536
- return canonicalize(path18.resolve(projectPath));
130537
- }
130538
- async function assertProjectRootReuse(options) {
130539
- if (!options.storedProjectPath || options.forceReindex)
130540
- return;
130541
- const canonicalize = options.canonicalize ?? realpath2;
130542
- let storedCanonical;
130543
- try {
130544
- storedCanonical = await canonicalize(path18.resolve(options.storedProjectPath));
130545
- } catch {
130546
- storedCanonical = path18.resolve(options.storedProjectPath);
130547
- }
130548
- if (storedCanonical !== options.canonicalProjectPath) {
130549
- 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");
130550
- }
130551
- }
130662
+ import path19 from "path";
130552
130663
 
130553
130664
  class IndexProjectTool {
130554
130665
  name = "index_project";
@@ -130596,7 +130707,7 @@ class IndexProjectTool {
130596
130707
  try {
130597
130708
  await assertParserReadyForIndexing();
130598
130709
  const canonicalProjectPath = await canonicalizeProjectRoot(projectPath);
130599
- const finalProjectId = projectId || path18.basename(canonicalProjectPath) || "default";
130710
+ const finalProjectId = projectId || path19.basename(canonicalProjectPath) || "default";
130600
130711
  const existing = await workspaceManager.getWorkspace(finalProjectId);
130601
130712
  await assertProjectRootReuse({
130602
130713
  projectId: finalProjectId,
@@ -130610,40 +130721,42 @@ class IndexProjectTool {
130610
130721
  projectPath: canonicalProjectPath,
130611
130722
  projectId: finalProjectId
130612
130723
  });
130613
- const eventId = `index:${job.jobId}`;
130614
- const managedRunRepo = ManagedRunRepositoryPg.getInstance();
130615
- let lease;
130616
- try {
130617
- const beginOutcome = await managedRunRepo.begin({
130618
- projectId: finalProjectId,
130619
- runKind: "indexing",
130620
- eventId
130621
- });
130622
- if (beginOutcome.status === "busy") {
130623
- indexJobTracker.setResult(job.jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 0, duration: 0 }, `indexing_busy:${beginOutcome.activeRunId}`);
130624
- return {
130625
- success: false,
130626
- error: `indexing_busy:${beginOutcome.activeRunId}`,
130627
- data: {
130628
- jobId: job.jobId,
130629
- projectId: finalProjectId,
130630
- status: "busy",
130631
- activeRunId: beginOutcome.activeRunId,
130632
- leaseExpiresAt: beginOutcome.leaseExpiresAt,
130633
- message: "Another indexing run is active for this project. Poll get_index_status(activeRunId)."
130634
- }
130635
- };
130636
- }
130637
- lease = beginOutcome.lease;
130638
- } catch (beginError) {
130639
- logger.error("managed_runs begin failed", beginError, { jobId: job.jobId, projectId: finalProjectId });
130640
- 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") {
130641
130743
  return {
130642
130744
  success: false,
130643
- error: `Failed to acquire indexing lease: ${beginError.message}`
130745
+ error: `Failed to acquire indexing lease: ${leaseOutcome.message}`
130644
130746
  };
130645
130747
  }
130646
- 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) => {
130647
130760
  logger.error("Background indexing failed", error51, {
130648
130761
  jobId: job.jobId
130649
130762
  });
@@ -130670,77 +130783,16 @@ class IndexProjectTool {
130670
130783
  };
130671
130784
  }
130672
130785
  }
130673
- async executeIndexing(jobId, projectId, projectPath, forceReindex, warmCache, warmupQueries, include_tests = false, managedRunLease) {
130674
- const startTime = Date.now();
130675
- try {
130676
- indexJobTracker.updateStatus(jobId, "running");
130677
- logger.info("Starting project indexing via ETL Pipeline", {
130678
- jobId,
130679
- projectPath,
130680
- projectId,
130681
- forceReindex,
130682
- warmCache,
130683
- include_tests
130684
- });
130685
- const etlResult = await EtlPipeline.getInstance().run({
130686
- projectId,
130687
- projectPath,
130688
- jobId,
130689
- forceReindex,
130690
- include_tests,
130691
- managedRunLease
130692
- });
130693
- const duration3 = Date.now() - startTime;
130694
- logger.info("ETL Pipeline completed", {
130695
- jobId,
130696
- projectId,
130697
- duration: duration3,
130698
- filesIndexed: etlResult.filesIndexed,
130699
- filesSkipped: etlResult.filesSkipped,
130700
- chunksIndexed: etlResult.chunksIndexed,
130701
- symbolsIndexed: etlResult.symbolsIndexed,
130702
- errors: etlResult.errors,
130703
- stageTimings: etlResult.stageTimings
130704
- });
130705
- if (warmCache) {
130706
- logger.info("Starting cache warmup", { jobId, projectId });
130707
- const warmupStats = await this.contextualSearch.warmupCache(projectId, projectPath, warmupQueries);
130708
- logger.info("Cache warmup completed", { jobId, projectId, ...warmupStats });
130709
- }
130710
- indexJobTracker.updateProgress(jobId, etlResult.filesIndexed, etlResult.filesIndexed);
130711
- await indexJobTracker.setResultAndFlush(jobId, {
130712
- filesIndexed: etlResult.filesIndexed,
130713
- chunksIndexed: etlResult.chunksIndexed,
130714
- errors: etlResult.errors,
130715
- duration: duration3,
130716
- activatedGraphGenerationId: etlResult.activatedGraphGenerationId,
130717
- parserDiagnostics: etlResult.parserDiagnostics
130718
- });
130719
- } catch (error51) {
130720
- const duration3 = Date.now() - startTime;
130721
- logger.error("Project indexing failed", error51, {
130722
- jobId,
130723
- projectPath,
130724
- projectId,
130725
- duration: duration3
130726
- });
130727
- indexJobTracker.setResult(jobId, {
130728
- filesIndexed: 0,
130729
- chunksIndexed: 0,
130730
- errors: 1,
130731
- duration: duration3
130732
- }, error51.message);
130733
- }
130734
- }
130735
130786
  }
130736
130787
  var init_index_project = __esm(() => {
130737
130788
  init_contextual_search_rlm();
130738
130789
  init_dist();
130739
130790
  init_index_job_tracker();
130740
- init_pipeline();
130791
+ init_execute_indexing();
130792
+ init_acquire_indexing_lease();
130793
+ init_project_root_identity();
130741
130794
  init_workspace_manager();
130742
130795
  init_parser_readiness();
130743
- init_managed_run_repository_pg();
130744
130796
  });
130745
130797
 
130746
130798
  // ../../packages/core/dist/tools/get_index_status.js
@@ -131208,17 +131260,17 @@ function applyReplacer(root, replacer) {
131208
131260
  return transformChildren(root, replacer, []);
131209
131261
  return transformChildren(normalizeValue(replacedRoot), replacer, []);
131210
131262
  }
131211
- function transformChildren(value, replacer, path19) {
131263
+ function transformChildren(value, replacer, path20) {
131212
131264
  if (isJsonObject(value))
131213
- return transformObject(value, replacer, path19);
131265
+ return transformObject(value, replacer, path20);
131214
131266
  if (isJsonArray(value))
131215
- return transformArray(value, replacer, path19);
131267
+ return transformArray(value, replacer, path20);
131216
131268
  return value;
131217
131269
  }
131218
- function transformObject(obj, replacer, path19) {
131270
+ function transformObject(obj, replacer, path20) {
131219
131271
  const result = {};
131220
131272
  for (const [key, value] of Object.entries(obj)) {
131221
- const childPath = [...path19, key];
131273
+ const childPath = [...path20, key];
131222
131274
  const replacedValue = replacer(key, value, childPath);
131223
131275
  if (replacedValue === undefined)
131224
131276
  continue;
@@ -131226,11 +131278,11 @@ function transformObject(obj, replacer, path19) {
131226
131278
  }
131227
131279
  return result;
131228
131280
  }
131229
- function transformArray(arr, replacer, path19) {
131281
+ function transformArray(arr, replacer, path20) {
131230
131282
  const result = [];
131231
131283
  for (let i = 0;i < arr.length; i++) {
131232
131284
  const value = arr[i];
131233
- const childPath = [...path19, i];
131285
+ const childPath = [...path20, i];
131234
131286
  const replacedValue = replacer(String(i), value, childPath);
131235
131287
  if (replacedValue === undefined)
131236
131288
  continue;
@@ -131953,7 +132005,7 @@ var init_memory_service = __esm(() => {
131953
132005
  init_decay();
131954
132006
  });
131955
132007
 
131956
- // ../../packages/core/dist/services/graph/relation-extractor.js
132008
+ // ../../packages/core/dist/services/memory-graph/relation-extractor.js
131957
132009
  class RelationExtractor {
131958
132010
  graphStore;
131959
132011
  constructor(graphStore) {
@@ -132191,7 +132243,7 @@ var init_relation_extractor = __esm(() => {
132191
132243
  ];
132192
132244
  });
132193
132245
 
132194
- // ../../packages/core/dist/services/graph/graph-queries.js
132246
+ // ../../packages/core/dist/services/memory-graph/graph-queries.js
132195
132247
  class GraphQueries {
132196
132248
  graphStore;
132197
132249
  constructor(graphStore) {
@@ -132411,7 +132463,7 @@ var init_graph_queries = __esm(() => {
132411
132463
  };
132412
132464
  });
132413
132465
 
132414
- // ../../packages/core/dist/services/graph/memory-graph.service.js
132466
+ // ../../packages/core/dist/services/memory-graph/memory-graph.service.js
132415
132467
  class MemoryGraphService {
132416
132468
  static instance = null;
132417
132469
  store;
@@ -132977,7 +133029,7 @@ var init_salience_judge = __esm(() => {
132977
133029
  });
132978
133030
  });
132979
133031
 
132980
- // ../../packages/core/dist/controllers/memory-controller.js
133032
+ // ../../packages/core/dist/services/memory/memory-controller.js
132981
133033
  class MemoryController {
132982
133034
  static instance = null;
132983
133035
  repo;
@@ -133614,102 +133666,43 @@ var init_code_compressor = __esm(() => {
133614
133666
  init_llm_client();
133615
133667
  });
133616
133668
 
133617
- // ../../packages/core/dist/tools/compress_context.js
133618
- class CompressContextTool {
133619
- name = "compress_context";
133620
- description = "Compress context using semantic compression (keeps structure, removes details)";
133621
- inputSchema = {
133622
- type: "object",
133623
- properties: {
133624
- content: {
133625
- type: "string",
133626
- description: "Content to compress"
133627
- },
133628
- strategy: {
133629
- type: "string",
133630
- enum: [
133631
- "code_structure",
133632
- "conversation_summary",
133633
- "semantic_dedup",
133634
- "hierarchical"
133635
- ],
133636
- description: "Compression strategy",
133637
- default: "code_structure"
133638
- },
133639
- language: {
133640
- type: "string",
133641
- description: "Programming language (for code compression)"
133642
- },
133643
- targetRatio: {
133644
- type: "number",
133645
- description: "Target compression ratio (0-1, e.g., 0.7 = 70% reduction)",
133646
- default: 0.7
133647
- }
133648
- },
133649
- required: ["content"]
133669
+ // ../../packages/core/dist/services/compression/compress-with-metrics.js
133670
+ async function compressWithMetrics(compressor, content, strategy, options = {}) {
133671
+ const { language, targetRatio } = options;
133672
+ const unit = language || "code";
133673
+ const originalTokens = estimateTokens(content, unit);
133674
+ logger.info("Compressing context", {
133675
+ originalTokens,
133676
+ strategy,
133677
+ targetRatio
133678
+ });
133679
+ const result = await compressor.compress(content, strategy);
133680
+ const compressedTokens = estimateTokens(result.compressed, unit);
133681
+ const compressionRatio = 1 - compressedTokens / originalTokens;
133682
+ const tokensSaved = originalTokens - compressedTokens;
133683
+ logger.info("Context compressed", {
133684
+ originalTokens,
133685
+ compressedTokens,
133686
+ tokensSaved,
133687
+ actualRatio: compressionRatio.toFixed(2),
133688
+ targetRatio
133689
+ });
133690
+ return {
133691
+ compressed: result.compressed,
133692
+ originalTokens,
133693
+ compressedTokens,
133694
+ tokensSaved,
133695
+ compressionRatio
133650
133696
  };
133651
- compressor;
133652
- constructor() {
133653
- this.compressor = new CodeCompressor;
133654
- }
133655
- async handle(params) {
133656
- const { content, language, targetRatio = 0.7 } = params;
133657
- const strategy = validateEnum("strategy", params.strategy ?? "code_structure", [
133658
- "code_structure",
133659
- "conversation_summary",
133660
- "semantic_dedup",
133661
- "hierarchical"
133662
- ]);
133663
- try {
133664
- const originalTokens = estimateTokens(content, language || "code");
133665
- logger.info("Compressing context", {
133666
- originalTokens,
133667
- strategy,
133668
- targetRatio
133669
- });
133670
- const result = await this.compressor.compress(content, strategy);
133671
- const compressedTokens = estimateTokens(result.compressed, language || "code");
133672
- const actualRatio = 1 - compressedTokens / originalTokens;
133673
- const tokensSaved = originalTokens - compressedTokens;
133674
- logger.info("Context compressed", {
133675
- originalTokens,
133676
- compressedTokens,
133677
- tokensSaved,
133678
- actualRatio: actualRatio.toFixed(2),
133679
- targetRatio
133680
- });
133681
- return {
133682
- success: true,
133683
- data: {
133684
- compressed: result.compressed,
133685
- originalLength: content.length,
133686
- compressedLength: result.compressed.length,
133687
- originalTokens,
133688
- compressedTokens,
133689
- strategy
133690
- },
133691
- metadata: {
133692
- tokensSaved,
133693
- compressionRatio: actualRatio
133694
- }
133695
- };
133696
- } catch (error51) {
133697
- logger.error("Failed to compress context", error51, {
133698
- strategy,
133699
- contentLength: typeof content === "string" ? content.length : 0
133700
- });
133701
- return {
133702
- success: false,
133703
- error: `Failed to compress context: ${error51.message}`
133704
- };
133705
- }
133706
- }
133707
133697
  }
133708
- var init_compress_context = __esm(() => {
133709
- init_code_compressor();
133710
- init_dist();
133698
+ var init_compress_with_metrics = __esm(() => {
133711
133699
  init_dist();
133712
- init_enum_validation();
133700
+ });
133701
+
133702
+ // ../../packages/core/dist/services/compression/index.js
133703
+ var init_compression = __esm(() => {
133704
+ init_code_compressor();
133705
+ init_compress_with_metrics();
133713
133706
  });
133714
133707
 
133715
133708
  // ../../packages/core/dist/services/metrics/token-metrics.js
@@ -134045,7 +134038,7 @@ var init_session_file_cache = __esm(() => {
134045
134038
  SESSION_TTL_MS = 4 * 60 * 60 * 1000;
134046
134039
  });
134047
134040
 
134048
- // ../../packages/core/dist/controllers/context-controller.js
134041
+ // ../../packages/core/dist/services/context/context-controller.js
134049
134042
  class ContextController {
134050
134043
  static instance = null;
134051
134044
  searchCtrl;
@@ -134055,7 +134048,7 @@ class ContextController {
134055
134048
  constructor() {
134056
134049
  this.searchCtrl = SearchController.getInstance();
134057
134050
  this.memoryCtrl = MemoryController.getInstance();
134058
- this.compressor = new CompressContextTool;
134051
+ this.compressor = new CodeCompressor;
134059
134052
  this.sessionCache = SessionFileCache.getInstance();
134060
134053
  }
134061
134054
  static getInstance() {
@@ -134207,15 +134200,16 @@ class ContextController {
134207
134200
  rawTokens,
134208
134201
  maxTokens
134209
134202
  });
134210
- const resp = await this.compressor.handle({
134211
- content: rawContext,
134212
- strategy: "code_structure",
134213
- targetRatio: 0.6
134214
- });
134215
- if (resp.success && resp.data) {
134216
- finalContext = resp.data.compressed;
134217
- compressionRatio = resp.metadata?.compressionRatio || 0;
134218
- tokensSaved = resp.metadata?.tokensSaved || 0;
134203
+ try {
134204
+ const metrics2 = await compressWithMetrics(this.compressor, rawContext, "code_structure", { targetRatio: 0.6 });
134205
+ finalContext = metrics2.compressed;
134206
+ compressionRatio = metrics2.compressionRatio || 0;
134207
+ tokensSaved = metrics2.tokensSaved || 0;
134208
+ } catch (error51) {
134209
+ logger.error("Failed to compress context", error51, {
134210
+ strategy: "code_structure",
134211
+ contentLength: rawContext.length
134212
+ });
134219
134213
  }
134220
134214
  }
134221
134215
  const finalTokens = estimateTokens(finalContext, "code");
@@ -134372,7 +134366,7 @@ var init_context_controller = __esm(() => {
134372
134366
  init_dist();
134373
134367
  init_search_controller();
134374
134368
  init_memory_controller();
134375
- init_compress_context();
134369
+ init_compression();
134376
134370
  init_session_file_cache();
134377
134371
  init_symbol_graph_service();
134378
134372
  init_token_metrics();
@@ -134484,6 +134478,88 @@ var init_get_optimized_context = __esm(() => {
134484
134478
  init_serialize();
134485
134479
  });
134486
134480
 
134481
+ // ../../packages/core/dist/tools/compress_context.js
134482
+ class CompressContextTool {
134483
+ name = "compress_context";
134484
+ description = "Compress context using semantic compression (keeps structure, removes details)";
134485
+ inputSchema = {
134486
+ type: "object",
134487
+ properties: {
134488
+ content: {
134489
+ type: "string",
134490
+ description: "Content to compress"
134491
+ },
134492
+ strategy: {
134493
+ type: "string",
134494
+ enum: [
134495
+ "code_structure",
134496
+ "conversation_summary",
134497
+ "semantic_dedup",
134498
+ "hierarchical"
134499
+ ],
134500
+ description: "Compression strategy",
134501
+ default: "code_structure"
134502
+ },
134503
+ language: {
134504
+ type: "string",
134505
+ description: "Programming language (for code compression)"
134506
+ },
134507
+ targetRatio: {
134508
+ type: "number",
134509
+ description: "Target compression ratio (0-1, e.g., 0.7 = 70% reduction)",
134510
+ default: 0.7
134511
+ }
134512
+ },
134513
+ required: ["content"]
134514
+ };
134515
+ compressor;
134516
+ constructor() {
134517
+ this.compressor = new CodeCompressor;
134518
+ }
134519
+ async handle(params) {
134520
+ const { content, language, targetRatio = 0.7 } = params;
134521
+ const strategy = validateEnum("strategy", params.strategy ?? "code_structure", [
134522
+ "code_structure",
134523
+ "conversation_summary",
134524
+ "semantic_dedup",
134525
+ "hierarchical"
134526
+ ]);
134527
+ try {
134528
+ const metrics2 = await compressWithMetrics(this.compressor, content, strategy, { language, targetRatio });
134529
+ return {
134530
+ success: true,
134531
+ data: {
134532
+ compressed: metrics2.compressed,
134533
+ originalLength: content.length,
134534
+ compressedLength: metrics2.compressed.length,
134535
+ originalTokens: metrics2.originalTokens,
134536
+ compressedTokens: metrics2.compressedTokens,
134537
+ strategy
134538
+ },
134539
+ metadata: {
134540
+ tokensSaved: metrics2.tokensSaved,
134541
+ compressionRatio: metrics2.compressionRatio
134542
+ }
134543
+ };
134544
+ } catch (error51) {
134545
+ logger.error("Failed to compress context", error51, {
134546
+ strategy,
134547
+ contentLength: typeof content === "string" ? content.length : 0
134548
+ });
134549
+ return {
134550
+ success: false,
134551
+ error: `Failed to compress context: ${error51.message}`
134552
+ };
134553
+ }
134554
+ }
134555
+ }
134556
+ var init_compress_context = __esm(() => {
134557
+ init_code_compressor();
134558
+ init_compress_with_metrics();
134559
+ init_dist();
134560
+ init_enum_validation();
134561
+ });
134562
+
134487
134563
  // ../../packages/core/dist/tools/store_memory.js
134488
134564
  class StoreMemoryTool {
134489
134565
  name = "store_memory";
@@ -136274,7 +136350,7 @@ var init_session_pin_store = __esm(() => {
136274
136350
  // ../../packages/core/dist/services/hooks/attribution-resolver.js
136275
136351
  import fs9 from "fs";
136276
136352
  import os3 from "os";
136277
- import path19 from "path";
136353
+ import path20 from "path";
136278
136354
 
136279
136355
  class PgWorkspaceRootProvider {
136280
136356
  cache = null;
@@ -136326,7 +136402,7 @@ class AttributionResolver {
136326
136402
  this.pins = options.pins ?? new SessionPinStore;
136327
136403
  this.canonicalize = options.canonicalize ?? defaultCanonicalize;
136328
136404
  this.homedir = options.homedir ?? os3.homedir;
136329
- this.fsRoot = options.fsRoot ?? (() => path19.parse(path19.sep).root);
136405
+ this.fsRoot = options.fsRoot ?? (() => path20.parse(path20.sep).root);
136330
136406
  }
136331
136407
  async resolve(input) {
136332
136408
  const caller = input.callerProjectId;
@@ -136379,7 +136455,7 @@ class AttributionResolver {
136379
136455
  }
136380
136456
  let bestPath = null;
136381
136457
  for (const candidate2 of byPath.keys()) {
136382
- 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)) {
136383
136459
  if (bestPath === null || candidate2.length > bestPath.length) {
136384
136460
  bestPath = candidate2;
136385
136461
  }
@@ -136402,7 +136478,7 @@ class AttributionResolver {
136402
136478
  return projectPath2;
136403
136479
  const fsRoot = this.fsRoot();
136404
136480
  let normalized = projectPath2;
136405
- while (normalized.length > fsRoot.length && normalized.endsWith(path19.sep)) {
136481
+ while (normalized.length > fsRoot.length && normalized.endsWith(path20.sep)) {
136406
136482
  normalized = normalized.slice(0, -1);
136407
136483
  }
136408
136484
  return normalized;
@@ -136413,7 +136489,7 @@ function defaultCanonicalize(cwd) {
136413
136489
  return fs9.realpathSync(cwd);
136414
136490
  } catch {
136415
136491
  try {
136416
- return path19.resolve(cwd);
136492
+ return path20.resolve(cwd);
136417
136493
  } catch {
136418
136494
  return;
136419
136495
  }
@@ -137152,31 +137228,31 @@ class TracePathService {
137152
137228
  const chains = [];
137153
137229
  const seen = new Set;
137154
137230
  let walks = 0;
137155
- const walk = (fqn, path20) => {
137231
+ const walk = (fqn, path21) => {
137156
137232
  if (chains.length >= CHAIN_CAP)
137157
137233
  return;
137158
137234
  if (walks >= MAX_WALKS)
137159
137235
  return;
137160
137236
  walks++;
137161
- const key = path20.join("\u2192");
137237
+ const key = path21.join("\u2192");
137162
137238
  if (seen.has(key))
137163
137239
  return;
137164
137240
  seen.add(key);
137165
137241
  const next = adj.get(fqn);
137166
137242
  if (!next || next.length === 0 || !whoHasChild.has(fqn)) {
137167
- if (path20.length > 1)
137168
- 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 "));
137169
137245
  return;
137170
137246
  }
137171
137247
  for (const child of next) {
137172
137248
  if (chains.length >= CHAIN_CAP || walks >= MAX_WALKS)
137173
137249
  return;
137174
- if (path20.includes(child)) {
137175
- const cycled = [...path20, `${this.fqnToName(child)}\u21BA`];
137250
+ if (path21.includes(child)) {
137251
+ const cycled = [...path21, `${this.fqnToName(child)}\u21BA`];
137176
137252
  chains.push(cycled.map((n) => n).join(" \u2192 "));
137177
137253
  continue;
137178
137254
  }
137179
- walk(child, [...path20, child]);
137255
+ walk(child, [...path21, child]);
137180
137256
  }
137181
137257
  };
137182
137258
  for (const seed of seeds) {
@@ -138008,303 +138084,16 @@ var init_get_architecture = __esm(() => {
138008
138084
  init_architecture();
138009
138085
  });
138010
138086
 
138011
- // ../../packages/core/dist/tools/read_file.js
138087
+ // ../../packages/core/dist/services/file-read/file-content-cache.js
138012
138088
  import fs10 from "fs/promises";
138013
- import path20 from "path";
138014
138089
 
138015
- class ReadFileTool {
138016
- name = "read_file";
138017
- description = "Read file with automatic compression, caching, and symbol metadata. " + "Use with search results for 60% token savings.";
138018
- inputSchema = {
138019
- type: "object",
138020
- properties: {
138021
- filePath: {
138022
- type: "string",
138023
- description: "File path (absolute or relative to project root)"
138024
- },
138025
- projectId: {
138026
- type: "string",
138027
- description: "Project ID for symbol metadata (optional)"
138028
- },
138029
- offset: {
138030
- type: "number",
138031
- description: "Start line number (1-indexed)"
138032
- },
138033
- limit: {
138034
- type: "number",
138035
- description: "Number of lines to read"
138036
- },
138037
- lineStart: {
138038
- type: "number",
138039
- description: "Start line (alternative to offset)"
138040
- },
138041
- lineEnd: {
138042
- type: "number",
138043
- description: "End line (alternative to limit)"
138044
- },
138045
- compress: {
138046
- type: "boolean",
138047
- description: "Auto-compress content > 100 lines (default: true)",
138048
- default: true
138049
- },
138050
- targetRatio: {
138051
- type: "number",
138052
- description: "Compression target ratio (0.3 = 70% reduction)",
138053
- default: 0.3
138054
- },
138055
- format: {
138056
- type: "string",
138057
- enum: ["json", "toon"],
138058
- description: "Output format",
138059
- default: "json"
138060
- },
138061
- fields: {
138062
- type: "array",
138063
- items: { type: "string" },
138064
- description: "Projection \u2014 keep only these keys (dotted paths supported, e.g. ['nodes.symbol']). Absent/empty \u2192 full data."
138065
- },
138066
- includeSymbols: {
138067
- type: "boolean",
138068
- description: "Include symbol metadata from graph (default: true)",
138069
- default: true
138070
- },
138071
- includeImports: {
138072
- type: "boolean",
138073
- description: "Extract and show import statements (default: true)",
138074
- default: true
138075
- }
138076
- },
138077
- required: ["filePath"]
138078
- };
138079
- compressor;
138080
- symbolGraph;
138090
+ class FileContentCache {
138091
+ extractMetadata;
138081
138092
  fileCache = new Map;
138082
- projectRootCache = new Map;
138083
138093
  CACHE_TTL = 60000;
138084
- ROOT_CACHE_TTL = 300000;
138085
138094
  FILE_CACHE_MAX_ENTRIES = 512;
138086
- constructor(symbolGraph) {
138087
- this.compressor = new CodeCompressor;
138088
- this.symbolGraph = symbolGraph;
138089
- eventBus.subscribe("indexing:started", ({ projectId, projectPath: projectPath2 }) => {
138090
- this.projectRootCache.delete(projectId);
138091
- this.evictOldest(this.projectRootCache);
138092
- this.projectRootCache.set(projectId, projectPath2);
138093
- });
138094
- }
138095
- async handle(params) {
138096
- const p = params;
138097
- const shouldCompress = p.compress !== false;
138098
- const targetRatio = p.targetRatio || 0.3;
138099
- const format = p.format || "json";
138100
- const { fields } = p;
138101
- const includeSymbols = p.includeSymbols !== false;
138102
- const includeImports = p.includeImports !== false;
138103
- try {
138104
- const resolved = await this.resolveFilePath(p.filePath, p.projectId);
138105
- if (resolved === null) {
138106
- return {
138107
- success: false,
138108
- error: "Relative filePath requires a projectId (to resolve against the workspace) or an absolute path."
138109
- };
138110
- }
138111
- const filePath = resolved;
138112
- const containment = await this.checkPathContainment(filePath, p.projectId);
138113
- if (!containment.allowed) {
138114
- return {
138115
- success: false,
138116
- error: containment.error
138117
- };
138118
- }
138119
- const relativePath = p.filePath;
138120
- const range = this.calculateRange(p);
138121
- const { content, metadata } = await this.readFileWithCache(filePath, {
138122
- includeSymbols,
138123
- includeImports,
138124
- projectId: p.projectId,
138125
- relativePath
138126
- });
138127
- const lines = content.split(`
138128
- `);
138129
- const totalLines = lines.length;
138130
- const adjustedRange = this.adjustRange(range, totalLines);
138131
- let selectedContent = this.extractLines(lines, adjustedRange);
138132
- let selectedLineCount = selectedContent.split(`
138133
- `).length;
138134
- let source_clipped = false;
138135
- if (selectedLineCount > MASSA_AI_READ_FILE_MAX_LINES) {
138136
- const cappedLines = lines.slice(adjustedRange.start - 1, adjustedRange.start - 1 + MASSA_AI_READ_FILE_MAX_LINES);
138137
- selectedContent = cappedLines.join(`
138138
- `);
138139
- selectedLineCount = selectedContent.split(`
138140
- `).length;
138141
- source_clipped = true;
138142
- }
138143
- const shouldAutoCompress = shouldCompress && selectedLineCount > 100 && targetRatio < 1;
138144
- const result = {
138145
- filePath: p.filePath,
138146
- absolutePath: filePath,
138147
- lineRange: {
138148
- requested: {
138149
- start: range.start,
138150
- end: range.end === Infinity ? null : range.end
138151
- },
138152
- actual: {
138153
- start: adjustedRange.start,
138154
- end: source_clipped ? adjustedRange.start + selectedLineCount - 1 : adjustedRange.end,
138155
- total: totalLines
138156
- },
138157
- selected: selectedLineCount
138158
- },
138159
- source_clipped,
138160
- metadata: {
138161
- totalLines,
138162
- language: metadata.language,
138163
- ...metadata.symbols && { symbols: metadata.symbols },
138164
- ...metadata.imports && { imports: metadata.imports }
138165
- },
138166
- compressed: shouldAutoCompress,
138167
- recommendations: []
138168
- };
138169
- if (shouldAutoCompress) {
138170
- const compressed = await this.compressor.compress(selectedContent, "code_structure");
138171
- const originalTokens = estimateTokens(selectedContent, "code");
138172
- const compressedTokens = estimateTokens(compressed.compressed, "code");
138173
- const actualRatio = compressedTokens / originalTokens;
138174
- result.content = compressed.compressed;
138175
- result.tokens = {
138176
- original: originalTokens,
138177
- compressed: compressedTokens,
138178
- saved: originalTokens - compressedTokens,
138179
- savingsPercent: Math.round((1 - actualRatio) * 100)
138180
- };
138181
- result.compressionRatio = actualRatio;
138182
- result.recommendations.push(`\u2713 Auto-compressed ${selectedLineCount} lines (${result.tokens.savingsPercent}% reduction)`);
138183
- } else {
138184
- result.content = selectedContent;
138185
- result.tokens = {
138186
- original: estimateTokens(selectedContent, "code"),
138187
- compressed: estimateTokens(selectedContent, "code"),
138188
- saved: 0,
138189
- savingsPercent: 0
138190
- };
138191
- if (selectedLineCount > 100) {
138192
- result.recommendations.push("\uD83D\uDCA1 Content > 100 lines. Consider compress=true for token savings");
138193
- }
138194
- }
138195
- if (range.start === 1 && range.end === Infinity) {
138196
- result.recommendations.push("\uD83D\uDCA1 Use lineStart/lineEnd or offset/limit to read specific sections (60% token savings)");
138197
- }
138198
- if (metadata.symbols && metadata.symbols.definitions > 0) {
138199
- result.recommendations.push(`\uD83D\uDCA1 Use get_references() to find usages of ${metadata.symbols.definitions} symbols in this file`);
138200
- }
138201
- return serializeToolResponse(result, { format, fields });
138202
- } catch (error51) {
138203
- logger.error("Failed to read file", error51, {
138204
- filePath: p.filePath
138205
- });
138206
- return {
138207
- success: false,
138208
- error: `Failed to read file: ${error51.message}`
138209
- };
138210
- }
138211
- }
138212
- async resolveFilePath(filePath, projectId) {
138213
- if (path20.isAbsolute(filePath)) {
138214
- return path20.resolve(filePath);
138215
- }
138216
- if (projectId) {
138217
- const root = await this.getProjectRoot(projectId);
138218
- if (root) {
138219
- const cleaned = sanitizeFilePath(filePath);
138220
- return path20.resolve(root, cleaned);
138221
- }
138222
- return null;
138223
- }
138224
- return null;
138225
- }
138226
- async checkPathContainment(absoluteFilePath, projectId) {
138227
- const roots = [];
138228
- if (projectId) {
138229
- const root = await this.getProjectRoot(projectId);
138230
- if (root)
138231
- roots.push(path20.resolve(root));
138232
- }
138233
- roots.push(path20.resolve(process.cwd()));
138234
- const envRoots = (process.env.MASSA_AI_READ_FILE_ROOTS ?? "").split(":").map((s) => s.trim()).filter((s) => s.length > 0);
138235
- for (const extra of envRoots) {
138236
- roots.push(path20.resolve(extra));
138237
- }
138238
- const target = path20.resolve(absoluteFilePath);
138239
- for (const root of roots) {
138240
- const rel = path20.relative(root, target);
138241
- if (rel !== "" && !rel.startsWith("..") && !path20.isAbsolute(rel)) {
138242
- return { allowed: true };
138243
- }
138244
- if (rel === "")
138245
- return { allowed: true };
138246
- }
138247
- const validRootsList = roots.map((r) => ` - ${r}`).join(`
138248
- `);
138249
- return {
138250
- allowed: false,
138251
- error: `read_file path containment: "${target}" is outside the allowed roots.
138252
- ` + `Valid roots (project root + cwd + MASSA_AI_READ_FILE_ROOTS):
138253
- ${validRootsList}
138254
- ` + `Provide a filePath that resolves under one of these roots.`
138255
- };
138256
- }
138257
- async getProjectRoot(projectId) {
138258
- const cached2 = this.projectRootCache.get(projectId);
138259
- if (cached2 !== undefined) {
138260
- this.projectRootCache.delete(projectId);
138261
- this.projectRootCache.set(projectId, cached2);
138262
- return cached2;
138263
- }
138264
- try {
138265
- const workspace = await workspaceManager.getWorkspace(projectId);
138266
- if (workspace?.project_path) {
138267
- this.evictOldest(this.projectRootCache);
138268
- this.projectRootCache.set(projectId, workspace.project_path);
138269
- return workspace.project_path;
138270
- }
138271
- } catch (error51) {
138272
- logger.warn("Failed to look up project root", { projectId, error: error51.message });
138273
- }
138274
- return null;
138275
- }
138276
- evictOldest(cache) {
138277
- while (cache.size >= this.FILE_CACHE_MAX_ENTRIES) {
138278
- const oldest = cache.keys().next().value;
138279
- if (oldest === undefined)
138280
- break;
138281
- cache.delete(oldest);
138282
- }
138283
- }
138284
- calculateRange(params) {
138285
- if (params.lineStart !== undefined && params.lineEnd !== undefined) {
138286
- return {
138287
- start: Math.max(1, params.lineStart),
138288
- end: params.lineEnd
138289
- };
138290
- }
138291
- if (params.offset !== undefined) {
138292
- const offset = Math.max(1, params.offset);
138293
- const limit = params.limit || 1000;
138294
- return {
138295
- start: offset,
138296
- end: offset + limit - 1
138297
- };
138298
- }
138299
- return {
138300
- start: 1,
138301
- end: Infinity
138302
- };
138303
- }
138304
- adjustRange(range, totalLines) {
138305
- const start = Math.max(1, Math.min(range.start, totalLines));
138306
- const end = range.end === Infinity ? totalLines : Math.min(range.end, totalLines);
138307
- return { start, end };
138095
+ constructor(extractMetadata) {
138096
+ this.extractMetadata = extractMetadata;
138308
138097
  }
138309
138098
  async readFileWithCache(filePath, options) {
138310
138099
  const cacheKey = JSON.stringify({
@@ -138331,7 +138120,7 @@ ${validRootsList}
138331
138120
  }
138332
138121
  const content = await fs10.readFile(filePath, "utf-8");
138333
138122
  const metadata = await this.extractMetadata(content, filePath, options);
138334
- this.evictOldest(this.fileCache);
138123
+ evictOldest(this.fileCache, this.FILE_CACHE_MAX_ENTRIES - 1);
138335
138124
  this.fileCache.set(cacheKey, {
138336
138125
  content,
138337
138126
  timestamp: Date.now(),
@@ -138340,6 +138129,19 @@ ${validRootsList}
138340
138129
  logger.debug("File read and cached", { filePath });
138341
138130
  return { content, metadata };
138342
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;
138142
+ constructor(symbolGraph) {
138143
+ this.symbolGraph = symbolGraph;
138144
+ }
138343
138145
  async extractMetadata(content, filePath, options) {
138344
138146
  const lines = content.split(`
138345
138147
  `);
@@ -138368,18 +138170,8 @@ ${validRootsList}
138368
138170
  }
138369
138171
  return metadata;
138370
138172
  }
138371
- extractLines(lines, range) {
138372
- const start = range.start - 1;
138373
- const end = range.end;
138374
- const selectedLines = lines.slice(start, end);
138375
- return selectedLines.map((line, index) => {
138376
- const lineNum = start + index + 1;
138377
- return `${lineNum.toString().padStart(6, " ")}: ${line}`;
138378
- }).join(`
138379
- `);
138380
- }
138381
138173
  detectLanguage(filePath) {
138382
- const ext2 = path20.extname(filePath).toLowerCase();
138174
+ const ext2 = path21.extname(filePath).toLowerCase();
138383
138175
  const languageMap2 = {
138384
138176
  ".ts": "TypeScript",
138385
138177
  ".tsx": "TypeScript",
@@ -138437,20 +138229,390 @@ ${validRootsList}
138437
138229
  return imports;
138438
138230
  }
138439
138231
  }
138440
- var MASSA_AI_READ_FILE_MAX_LINES;
138441
- var init_read_file = __esm(() => {
138232
+ var init_file_metadata = __esm(() => {
138442
138233
  init_dist();
138443
- init_dist();
138444
- init_code_compressor();
138445
- init_serialize();
138446
- init_event_bus();
138447
- init_workspace_manager();
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(`
138270
+ `);
138271
+ }
138272
+ function selectLines(lines, range) {
138273
+ let content = extractLines(lines, range);
138274
+ let lineCount = content.split(`
138275
+ `).length;
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(`
138280
+ `);
138281
+ lineCount = content.split(`
138282
+ `).length;
138283
+ clipped = true;
138284
+ }
138285
+ return { content, lineCount, clipped };
138286
+ }
138287
+ var MASSA_AI_READ_FILE_MAX_LINES;
138288
+ var init_line_range = __esm(() => {
138448
138289
  MASSA_AI_READ_FILE_MAX_LINES = (() => {
138449
138290
  const v = Number(process.env.MASSA_AI_READ_FILE_MAX_LINES);
138450
138291
  return Number.isFinite(v) && v > 0 ? Math.floor(v) : 500;
138451
138292
  })();
138452
138293
  });
138453
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;
138302
+ }
138303
+ async resolveFilePath(filePath, projectId) {
138304
+ if (path22.isAbsolute(filePath)) {
138305
+ return path22.resolve(filePath);
138306
+ }
138307
+ if (projectId) {
138308
+ const root = await this.projectRoots.getProjectRoot(projectId);
138309
+ if (root) {
138310
+ const cleaned = sanitizeFilePath(filePath);
138311
+ return path22.resolve(root, cleaned);
138312
+ }
138313
+ return null;
138314
+ }
138315
+ return null;
138316
+ }
138317
+ async checkPathContainment(absoluteFilePath, projectId) {
138318
+ const roots = [];
138319
+ if (projectId) {
138320
+ const root = await this.projectRoots.getProjectRoot(projectId);
138321
+ if (root)
138322
+ roots.push(path22.resolve(root));
138323
+ }
138324
+ roots.push(path22.resolve(process.cwd()));
138325
+ const envRoots = (process.env.MASSA_AI_READ_FILE_ROOTS ?? "").split(":").map((s) => s.trim()).filter((s) => s.length > 0);
138326
+ for (const extra of envRoots) {
138327
+ roots.push(path22.resolve(extra));
138328
+ }
138329
+ const target = path22.resolve(absoluteFilePath);
138330
+ for (const root of roots) {
138331
+ const rel = path22.relative(root, target);
138332
+ if (rel !== "" && !rel.startsWith("..") && !path22.isAbsolute(rel)) {
138333
+ return { allowed: true };
138334
+ }
138335
+ if (rel === "")
138336
+ return { allowed: true };
138337
+ }
138338
+ const validRootsList = roots.map((r) => ` - ${r}`).join(`
138339
+ `);
138340
+ return {
138341
+ allowed: false,
138342
+ error: `read_file path containment: "${target}" is outside the allowed roots.
138343
+ ` + `Valid roots (project root + cwd + MASSA_AI_READ_FILE_ROOTS):
138344
+ ${validRootsList}
138345
+ ` + `Provide a filePath that resolves under one of these roots.`
138346
+ };
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
+ }
138365
+ async getProjectRoot(projectId) {
138366
+ const cached2 = this.projectRootCache.get(projectId);
138367
+ if (cached2 !== undefined) {
138368
+ this.projectRootCache.delete(projectId);
138369
+ this.projectRootCache.set(projectId, cached2);
138370
+ return cached2;
138371
+ }
138372
+ try {
138373
+ const workspace = await workspaceManager.getWorkspace(projectId);
138374
+ if (workspace?.project_path) {
138375
+ evictOldest(this.projectRootCache, this.PROJECT_ROOT_CACHE_MAX_ENTRIES - 1);
138376
+ this.projectRootCache.set(projectId, workspace.project_path);
138377
+ return workspace.project_path;
138378
+ }
138379
+ } catch (error51) {
138380
+ logger.warn("Failed to look up project root", { projectId, error: error51.message });
138381
+ }
138382
+ return null;
138383
+ }
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) {
138421
+ return {
138422
+ ok: false,
138423
+ error: "Relative filePath requires a projectId (to resolve against the workspace) or an absolute path."
138424
+ };
138425
+ }
138426
+ const filePath = resolved;
138427
+ const containment = await this.pathContainment.checkPathContainment(filePath, p.projectId);
138428
+ if (!containment.allowed) {
138429
+ return {
138430
+ ok: false,
138431
+ error: containment.error
138432
+ };
138433
+ }
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
138441
+ });
138442
+ const lines = content.split(`
138443
+ `);
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: []
138472
+ };
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");
138497
+ }
138498
+ }
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 };
138506
+ }
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);
138586
+ }
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 };
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
+ };
138607
+ }
138608
+ }
138609
+ }
138610
+ var init_read_file = __esm(() => {
138611
+ init_dist();
138612
+ init_serialize();
138613
+ init_read_file_service();
138614
+ });
138615
+
138454
138616
  // ../../packages/core/dist/tools/execute.js
138455
138617
  class ExecuteTool {
138456
138618
  name = "execute";
@@ -139635,7 +139797,7 @@ var init_executor2 = __esm(() => {
139635
139797
  init_intent_search();
139636
139798
  });
139637
139799
 
139638
- // ../../packages/core/dist/controllers/executor-controller.js
139800
+ // ../../packages/core/dist/services/executor/executor-controller.js
139639
139801
  import { cpus as cpus2 } from "os";
139640
139802
  function applyIntent(result, intent) {
139641
139803
  if (!intent || !result.stdout)
@@ -139828,7 +139990,7 @@ var init_executor_controller = __esm(() => {
139828
139990
  ];
139829
139991
  });
139830
139992
 
139831
- // ../../packages/core/dist/controllers/graph-controller.js
139993
+ // ../../packages/core/dist/services/symbol/graph-controller.js
139832
139994
  class GraphController {
139833
139995
  static instance = null;
139834
139996
  constructor() {}
@@ -139948,15 +140110,6 @@ var init_graph_controller = __esm(() => {
139948
140110
  init_definition_lookup();
139949
140111
  });
139950
140112
 
139951
- // ../../packages/core/dist/controllers/index.js
139952
- var init_controllers = __esm(() => {
139953
- init_memory_controller();
139954
- init_search_controller();
139955
- init_context_controller();
139956
- init_executor_controller();
139957
- init_graph_controller();
139958
- });
139959
-
139960
140113
  // ../../packages/core/dist/services/project-identity/errors.js
139961
140114
  var ERROR_MESSAGES, ERROR_STATUS, ProjectIdentityError;
139962
140115
  var init_errors4 = __esm(() => {
@@ -141392,7 +141545,7 @@ var init_l1_memory_cache = __esm(() => {
141392
141545
  // ../../packages/core/dist/services/health/local-health-checker.js
141393
141546
  import fs11 from "fs/promises";
141394
141547
  import { existsSync as existsSync3 } from "fs";
141395
- import path21 from "path";
141548
+ import path23 from "path";
141396
141549
 
141397
141550
  class LocalHealthChecker {
141398
141551
  ollamaBaseUrl = process.env.OLLAMA_BASE_URL || "http://localhost:11434";
@@ -141427,7 +141580,7 @@ class LocalHealthChecker {
141427
141580
  try {
141428
141581
  if (!existsSync3(this.dataDir))
141429
141582
  await fs11.mkdir(this.dataDir, { recursive: true });
141430
- const probe2 = path21.join(this.dataDir, ".health-check-test");
141583
+ const probe2 = path23.join(this.dataDir, ".health-check-test");
141431
141584
  await fs11.writeFile(probe2, "ok");
141432
141585
  await fs11.unlink(probe2);
141433
141586
  return { available: true, latency: Date.now() - start, details: { path: this.dataDir, writable: true } };
@@ -143370,7 +143523,7 @@ var init_scheduler2 = __esm(() => {
143370
143523
  // ../../packages/core/dist/services/pricing/models-dev-client.js
143371
143524
  import fs12 from "fs/promises";
143372
143525
  import { existsSync as existsSync4 } from "fs";
143373
- import path22 from "path";
143526
+ import path24 from "path";
143374
143527
  function getModelsDevClient() {
143375
143528
  if (!clientInstance) {
143376
143529
  clientInstance = new ModelsDevClient;
@@ -143390,7 +143543,7 @@ var init_models_dev_client = __esm(() => {
143390
143543
  memoryCacheTimestamp = 0;
143391
143544
  getLocalCachePath() {
143392
143545
  const dataDir = config2.get("dataDir");
143393
- return path22.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
143546
+ return path24.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
143394
143547
  }
143395
143548
  async loadLocalCache() {
143396
143549
  const cachePath = this.getLocalCachePath();
@@ -143425,7 +143578,7 @@ var init_models_dev_client = __esm(() => {
143425
143578
  async saveLocalCache(models) {
143426
143579
  const cachePath = this.getLocalCachePath();
143427
143580
  try {
143428
- const dir = path22.dirname(cachePath);
143581
+ const dir = path24.dirname(cachePath);
143429
143582
  await fs12.mkdir(dir, { recursive: true });
143430
143583
  const data = {
143431
143584
  timestamp: Date.now(),
@@ -149316,33 +149469,33 @@ var require_URL = __commonJS((exports, module) => {
149316
149469
  else
149317
149470
  return basepath.substring(0, lastslash + 1) + refpath;
149318
149471
  }
149319
- function remove_dot_segments(path23) {
149320
- if (!path23)
149321
- return path23;
149472
+ function remove_dot_segments(path25) {
149473
+ if (!path25)
149474
+ return path25;
149322
149475
  var output = "";
149323
- while (path23.length > 0) {
149324
- if (path23 === "." || path23 === "..") {
149325
- path23 = "";
149476
+ while (path25.length > 0) {
149477
+ if (path25 === "." || path25 === "..") {
149478
+ path25 = "";
149326
149479
  break;
149327
149480
  }
149328
- var twochars = path23.substring(0, 2);
149329
- var threechars = path23.substring(0, 3);
149330
- 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);
149331
149484
  if (threechars === "../") {
149332
- path23 = path23.substring(3);
149485
+ path25 = path25.substring(3);
149333
149486
  } else if (twochars === "./") {
149334
- path23 = path23.substring(2);
149487
+ path25 = path25.substring(2);
149335
149488
  } else if (threechars === "/./") {
149336
- path23 = "/" + path23.substring(3);
149337
- } else if (twochars === "/." && path23.length === 2) {
149338
- path23 = "/";
149339
- } else if (fourchars === "/../" || threechars === "/.." && path23.length === 3) {
149340
- 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);
149341
149494
  output = output.replace(/\/?[^\/]*$/, "");
149342
149495
  } else {
149343
- var segment = path23.match(/(\/?([^\/]*))/)[0];
149496
+ var segment = path25.match(/(\/?([^\/]*))/)[0];
149344
149497
  output += segment;
149345
- path23 = path23.substring(segment.length);
149498
+ path25 = path25.substring(segment.length);
149346
149499
  }
149347
149500
  }
149348
149501
  return output;
@@ -161412,21 +161565,21 @@ function jsonToKeyPathChunks(value, label = "$") {
161412
161565
  walk(value, label, out);
161413
161566
  return out;
161414
161567
  }
161415
- function walk(val, path23, out) {
161568
+ function walk(val, path25, out) {
161416
161569
  if (val === null || val === undefined)
161417
161570
  return;
161418
161571
  if (Array.isArray(val)) {
161419
161572
  if (val.length === 0) {
161420
- out.push({ path: path23, content: `**${path23}** = _[]_` });
161573
+ out.push({ path: path25, content: `**${path25}** = _[]_` });
161421
161574
  return;
161422
161575
  }
161423
161576
  if (val.every((v) => v !== null && typeof v === "object")) {
161424
- val.forEach((v, i) => walk(v, `${path23}[${i}]`, out));
161577
+ val.forEach((v, i) => walk(v, `${path25}[${i}]`, out));
161425
161578
  return;
161426
161579
  }
161427
161580
  const items = val.map((v) => `- \`${String(v)}\``).join(`
161428
161581
  `);
161429
- out.push({ path: path23, content: `**${path23}**
161582
+ out.push({ path: path25, content: `**${path25}**
161430
161583
 
161431
161584
  ${items}` });
161432
161585
  return;
@@ -161434,16 +161587,16 @@ ${items}` });
161434
161587
  if (typeof val === "object") {
161435
161588
  const entries = Object.entries(val);
161436
161589
  if (entries.length === 0) {
161437
- out.push({ path: path23, content: `**${path23}** = _{}_` });
161590
+ out.push({ path: path25, content: `**${path25}** = _{}_` });
161438
161591
  return;
161439
161592
  }
161440
161593
  for (const [k, v] of entries) {
161441
161594
  const safeKey = /^[A-Za-z_$][\w$]*$/.test(k) ? k : JSON.stringify(k);
161442
- walk(v, `${path23}.${safeKey}`, out);
161595
+ walk(v, `${path25}.${safeKey}`, out);
161443
161596
  }
161444
161597
  return;
161445
161598
  }
161446
- out.push({ path: path23, content: `**${path23}** = \`${String(val)}\`` });
161599
+ out.push({ path: path25, content: `**${path25}** = \`${String(val)}\`` });
161447
161600
  }
161448
161601
  var gfm, STRIP_SELECTORS, tdCache = null;
161449
161602
  var init_html_to_md = __esm(() => {
@@ -161709,12 +161862,7 @@ class WebController {
161709
161862
  markIndexed: (key, ts) => {
161710
161863
  this.cache.delete(key);
161711
161864
  this.cache.set(key, ts);
161712
- while (this.cache.size > WEB_CACHE_MAX_ENTRIES) {
161713
- const oldest = this.cache.keys().next().value;
161714
- if (oldest === undefined)
161715
- break;
161716
- this.cache.delete(oldest);
161717
- }
161865
+ evictOldest(this.cache, WEB_CACHE_MAX_ENTRIES);
161718
161866
  }
161719
161867
  };
161720
161868
  }
@@ -161773,6 +161921,11 @@ var init_services = __esm(() => {
161773
161921
  init_search_analytics_pg();
161774
161922
  init_index_manager();
161775
161923
  init_search_diagnostics();
161924
+ init_memory_controller();
161925
+ init_search_controller();
161926
+ init_context_controller();
161927
+ init_executor_controller();
161928
+ init_graph_controller();
161776
161929
  init_l1_memory_cache();
161777
161930
  init_embedding_cache_pg();
161778
161931
  init_code_compressor();
@@ -161834,20 +161987,6 @@ var init_services = __esm(() => {
161834
161987
  init_project_identity();
161835
161988
  });
161836
161989
 
161837
- // ../../packages/core/dist/data/vector/hybrid-search.js
161838
- var init_hybrid_search2 = __esm(() => {
161839
- init_vector_store_factory();
161840
- init_keyword_search_pg();
161841
- init_dist();
161842
- });
161843
-
161844
- // ../../packages/core/dist/data/vector/index.js
161845
- var init_vector = __esm(() => {
161846
- init_hybrid_search2();
161847
- init_vector_store_factory();
161848
- init_base_vector_store();
161849
- });
161850
-
161851
161990
  // ../../packages/core/dist/data/graph-generation/index.js
161852
161991
  var init_graph_generation = __esm(() => {
161853
161992
  init_graph_generation_repository_pg();
@@ -162211,7 +162350,7 @@ var init_hook_service = __esm(() => {
162211
162350
  // ../../packages/core/dist/services/bootstrap/bootstrap-service.js
162212
162351
  import { randomUUID as randomUUID9 } from "crypto";
162213
162352
  import fs13 from "fs";
162214
- import path23 from "path";
162353
+ import path25 from "path";
162215
162354
  import { spawn as spawn2 } from "child_process";
162216
162355
  function readBootstrapConfig() {
162217
162356
  try {
@@ -162371,7 +162510,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
162371
162510
  }
162372
162511
  try {
162373
162512
  for (const name26 of README_CANDIDATES) {
162374
- const p = path23.join(projectRoot, name26);
162513
+ const p = path25.join(projectRoot, name26);
162375
162514
  if (fs13.existsSync(p) && fs13.statSync(p).isFile()) {
162376
162515
  const buf = fs13.readFileSync(p);
162377
162516
  signals.readme = buf.slice(0, MAX_README_BYTES).toString("utf8");
@@ -162382,14 +162521,14 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
162382
162521
  logger.debug("bootstrap scan: README read failed", { error: e.message });
162383
162522
  }
162384
162523
  try {
162385
- const docsDir = path23.join(projectRoot, "docs");
162524
+ const docsDir = path25.join(projectRoot, "docs");
162386
162525
  if (fs13.existsSync(docsDir) && fs13.statSync(docsDir).isDirectory()) {
162387
162526
  const entries = walkMarkdown(docsDir).slice(0, MAX_DOCS);
162388
162527
  for (const rel of entries) {
162389
162528
  try {
162390
162529
  const buf = fs13.readFileSync(rel);
162391
162530
  signals.docs.push({
162392
- path: path23.relative(projectRoot, rel),
162531
+ path: path25.relative(projectRoot, rel),
162393
162532
  snippet: buf.slice(0, MAX_DOC_BYTES).toString("utf8")
162394
162533
  });
162395
162534
  } catch {}
@@ -162400,7 +162539,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
162400
162539
  }
162401
162540
  try {
162402
162541
  for (const name26 of MANIFEST_FILES) {
162403
- const p = path23.join(projectRoot, name26);
162542
+ const p = path25.join(projectRoot, name26);
162404
162543
  if (!fs13.existsSync(p) || !fs13.statSync(p).isFile())
162405
162544
  continue;
162406
162545
  const raw2 = fs13.readFileSync(p).slice(0, MAX_MANIFEST_BYTES).toString("utf8");
@@ -162448,7 +162587,7 @@ function walkMarkdown(dir) {
162448
162587
  continue;
162449
162588
  }
162450
162589
  for (const e of entries) {
162451
- const full = path23.join(cur, e.name);
162590
+ const full = path25.join(cur, e.name);
162452
162591
  if (e.isDirectory()) {
162453
162592
  if (e.name === "node_modules" || e.name.startsWith("."))
162454
162593
  continue;
@@ -163484,7 +163623,7 @@ __export(exports_dist, {
163484
163623
  var init_dist15 = __esm(() => {
163485
163624
  init_memory_repository_pg();
163486
163625
  init_memory_repository_factory();
163487
- init_vector();
163626
+ init_vector_store_factory();
163488
163627
  init_operation_log_pg();
163489
163628
  init_operation_log_factory();
163490
163629
  init_operation_log_contract();
@@ -163501,7 +163640,6 @@ var init_dist15 = __esm(() => {
163501
163640
  init_proposal_repository();
163502
163641
  init_auto_improve_job();
163503
163642
  init_tools();
163504
- init_controllers();
163505
163643
  init_services();
163506
163644
  init_graph_generation();
163507
163645
  });
@@ -165967,7 +166105,7 @@ init_dist();
165967
166105
  init_dist15();
165968
166106
  init_dist();
165969
166107
  import fs14 from "fs/promises";
165970
- import path24 from "path";
166108
+ import path26 from "path";
165971
166109
  var _indexProjectTool = null;
165972
166110
  function indexProjectTool() {
165973
166111
  if (!_indexProjectTool)
@@ -166237,7 +166375,7 @@ class EmbeddedApiClient {
166237
166375
  } else {
166238
166376
  end = start + 20;
166239
166377
  }
166240
- const absolutePath = path24.join(workspace.project_path, file2);
166378
+ const absolutePath = path26.join(workspace.project_path, file2);
166241
166379
  const content = await fs14.readFile(absolutePath, "utf-8");
166242
166380
  const lines = content.split(/\r?\n/);
166243
166381
  const slice = lines.slice(start - 1, Math.min(lines.length, end));
@@ -166461,21 +166599,21 @@ class EmbeddedApiClient {
166461
166599
  async uploadAndIndex(params) {
166462
166600
  const rawBase = params.projectId || params.projectPath.replace(/\\/g, "/").split("/").filter(Boolean).pop() || "default";
166463
166601
  const finalProjectId = rawBase.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 128);
166464
- const uploadRoot = process.env.MASSA_AI_UPLOAD_DIR || path24.join(getGlobalDataDir(), "uploads");
166465
- 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);
166466
166604
  await fs14.rm(stagingDir, { recursive: true, force: true });
166467
166605
  await fs14.mkdir(stagingDir, { recursive: true });
166468
166606
  const WRITE_BATCH = 20;
166469
166607
  for (let i = 0;i < params.files.length; i += WRITE_BATCH) {
166470
166608
  await Promise.all(params.files.slice(i, i + WRITE_BATCH).map(async (file2) => {
166471
- if (path24.isAbsolute(file2.relativePath) || file2.relativePath.includes("..")) {
166609
+ if (path26.isAbsolute(file2.relativePath) || file2.relativePath.includes("..")) {
166472
166610
  throw new Error(`Invalid file path: ${file2.relativePath}`);
166473
166611
  }
166474
- const dest = path24.resolve(stagingDir, file2.relativePath.replace(/\//g, path24.sep));
166475
- 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)) {
166476
166614
  throw new Error(`Path escapes staging directory: ${file2.relativePath}`);
166477
166615
  }
166478
- await fs14.mkdir(path24.dirname(dest), { recursive: true });
166616
+ await fs14.mkdir(path26.dirname(dest), { recursive: true });
166479
166617
  await fs14.writeFile(dest, file2.content, "utf-8");
166480
166618
  }));
166481
166619
  }
@@ -166809,7 +166947,7 @@ class EmbeddedApiClient {
166809
166947
  // src/file-collector.ts
166810
166948
  init_config();
166811
166949
  import fs15 from "fs/promises";
166812
- import path25 from "path";
166950
+ import path27 from "path";
166813
166951
  var SKIP_DIRS = new Set([
166814
166952
  "node_modules",
166815
166953
  ".git",
@@ -166859,13 +166997,13 @@ async function walk2(root2, dir, files, state, allowed) {
166859
166997
  break;
166860
166998
  if (entry2.isDirectory()) {
166861
166999
  if (!SKIP_DIRS.has(entry2.name) && !entry2.name.startsWith(".")) {
166862
- await walk2(root2, path25.join(dir, entry2.name), files, state, allowed);
167000
+ await walk2(root2, path27.join(dir, entry2.name), files, state, allowed);
166863
167001
  }
166864
167002
  } else if (entry2.isFile()) {
166865
- const ext2 = path25.extname(entry2.name).toLowerCase();
167003
+ const ext2 = path27.extname(entry2.name).toLowerCase();
166866
167004
  if (!allowed.has(ext2))
166867
167005
  continue;
166868
- const fullPath = path25.join(dir, entry2.name);
167006
+ const fullPath = path27.join(dir, entry2.name);
166869
167007
  try {
166870
167008
  const stat = await fs15.stat(fullPath);
166871
167009
  if (stat.size > MAX_FILE_BYTES)
@@ -166874,7 +167012,7 @@ async function walk2(root2, dir, files, state, allowed) {
166874
167012
  continue;
166875
167013
  const content = await fs15.readFile(fullPath, "utf-8");
166876
167014
  state.totalBytes += stat.size;
166877
- const relativePath = path25.relative(root2, fullPath).split(path25.sep).join("/");
167015
+ const relativePath = path27.relative(root2, fullPath).split(path27.sep).join("/");
166878
167016
  files.push({ relativePath, content });
166879
167017
  } catch {}
166880
167018
  }