@massa-ai/tools-api 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 (2) hide show
  1. package/dist/index.js +1435 -1295
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -13109,7 +13109,7 @@ var init_ignore_patterns = __esm(() => {
13109
13109
  ];
13110
13110
  });
13111
13111
 
13112
- // ../../packages/core/dist/data/db-connection.js
13112
+ // ../../packages/core/dist/kernel/db-connection.js
13113
13113
  import { Pool } from "pg";
13114
13114
  function getDbConfig() {
13115
13115
  return {
@@ -13137,7 +13137,7 @@ var init_db_connection = __esm(() => {
13137
13137
  init_config();
13138
13138
  });
13139
13139
 
13140
- // ../../packages/core/dist/services/project-identity/alias-resolver.js
13140
+ // ../../packages/core/dist/kernel/alias-resolver.js
13141
13141
  class ProjectIdentityAliasResolver {
13142
13142
  ttlMs;
13143
13143
  resolveTimeoutMs;
@@ -13461,6 +13461,16 @@ var init_index_manager = __esm(() => {
13461
13461
  globAsync = glob;
13462
13462
  });
13463
13463
 
13464
+ // ../../packages/core/dist/services/cache/lru-evict.js
13465
+ function evictOldest(cache, maxRetained) {
13466
+ while (cache.size > maxRetained) {
13467
+ const oldest = cache.keys().next().value;
13468
+ if (oldest === undefined)
13469
+ break;
13470
+ cache.delete(oldest);
13471
+ }
13472
+ }
13473
+
13464
13474
  // ../../packages/core/dist/services/search/file-filter-cache.js
13465
13475
  class FileFilterCache {
13466
13476
  cache = new Map;
@@ -13529,18 +13539,7 @@ class FileFilterCache {
13529
13539
  return parts.join("|");
13530
13540
  }
13531
13541
  evictOldest() {
13532
- let oldestKey = null;
13533
- let oldestTime = Infinity;
13534
- for (const [key, entry] of this.cache.entries()) {
13535
- if (entry.createdAt < oldestTime) {
13536
- oldestTime = entry.createdAt;
13537
- oldestKey = key;
13538
- }
13539
- }
13540
- if (oldestKey) {
13541
- this.cache.delete(oldestKey);
13542
- logger.debug("Evicted oldest filter cache entry", { key: oldestKey });
13543
- }
13542
+ evictOldest(this.cache, this.MAX_CACHE_SIZE);
13544
13543
  }
13545
13544
  invalidateProject(projectId) {
13546
13545
  let removed = 0;
@@ -104662,7 +104661,7 @@ model ManagedRun {
104662
104661
  Object.assign(exports, Prisma);
104663
104662
  });
104664
104663
 
104665
- // ../../packages/core/dist/services/query/prisma-client.js
104664
+ // ../../packages/core/dist/kernel/prisma-client.js
104666
104665
  var exports_prisma_client = {};
104667
104666
  __export(exports_prisma_client, {
104668
104667
  getPrismaClient: () => getPrismaClient2,
@@ -105473,7 +105472,7 @@ var init_query_understanding = __esm(() => {
105473
105472
  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.";
105474
105473
  });
105475
105474
 
105476
- // ../../packages/core/dist/services/structural/types.js
105475
+ // ../../packages/core/dist/kernel/types.js
105477
105476
  var STRUCTURAL_TAXONOMY_VERSION = "1.0.0", SOURCE_SPAN_SCHEMA_VERSION = "1.0.0", STRUCTURAL_FQN_SCHEMA_VERSION = "1.0.0";
105478
105477
  var init_types3 = __esm(() => {
105479
105478
  init_dist();
@@ -106565,7 +106564,7 @@ answer = 42
106565
106564
  });
106566
106565
  });
106567
106566
 
106568
- // ../../packages/core/dist/services/project-identity/registry.js
106567
+ // ../../packages/core/dist/kernel/registry.js
106569
106568
  function directStorePolicy(tableName, columnName) {
106570
106569
  if (/^vector_documents(?:_\d+d)?$/.test(tableName) && columnName === "project_id") {
106571
106570
  return { storeId: tableName, identityColumn: columnName, mutable: true };
@@ -106626,7 +106625,7 @@ var init_registry = __esm(() => {
106626
106625
  ];
106627
106626
  });
106628
106627
 
106629
- // ../../packages/core/dist/services/project-identity/identity-guard-installer.js
106628
+ // ../../packages/core/dist/kernel/identity-guard-installer.js
106630
106629
  async function installGuardOnTable(client, schema, table, column) {
106631
106630
  try {
106632
106631
  await client.query(`SELECT project_identity_install_guard($1::regclass, $2)`, [`${schema}.${table}`, column]);
@@ -106691,7 +106690,7 @@ var init_identity_guard_installer = __esm(() => {
106691
106690
  init_registry();
106692
106691
  });
106693
106692
 
106694
- // ../../packages/core/dist/services/search/lexical-search.js
106693
+ // ../../packages/core/dist/kernel/lexical-search.js
106695
106694
  function dedupeTokens(tokens) {
106696
106695
  const seen = new Set;
106697
106696
  const out = [];
@@ -107355,9 +107354,16 @@ var init_keyword_search_factory = __esm(() => {
107355
107354
  // ../../packages/core/dist/data/vector/base-vector-store.js
107356
107355
  class BaseVectorStore {
107357
107356
  embeddingProviderPromise = null;
107357
+ embeddingProviderFactory;
107358
+ constructor(options) {
107359
+ this.embeddingProviderFactory = options?.embeddingProviderFactory;
107360
+ }
107358
107361
  getEmbeddingProvider() {
107359
107362
  if (!this.embeddingProviderPromise) {
107360
- this.embeddingProviderPromise = createEmbeddingProvider({ cache: true });
107363
+ if (!this.embeddingProviderFactory) {
107364
+ 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.");
107365
+ }
107366
+ this.embeddingProviderPromise = this.embeddingProviderFactory();
107361
107367
  }
107362
107368
  return this.embeddingProviderPromise;
107363
107369
  }
@@ -107403,7 +107409,6 @@ class BaseVectorStore {
107403
107409
  }
107404
107410
  }
107405
107411
  var init_base_vector_store = __esm(() => {
107406
- init_embeddings();
107407
107412
  init_dist();
107408
107413
  });
107409
107414
 
@@ -107529,7 +107534,7 @@ var init_postgres_vector_store = __esm(() => {
107529
107534
  tableName = "vector_documents";
107530
107535
  bqEnabled = false;
107531
107536
  constructor(config3) {
107532
- super();
107537
+ super(config3.embeddingProviderFactory ? { embeddingProviderFactory: config3.embeddingProviderFactory } : undefined);
107533
107538
  this.config = {
107534
107539
  poolSize: 10,
107535
107540
  indexType: "hnsw",
@@ -107985,7 +107990,7 @@ var init_postgres_vector_store = __esm(() => {
107985
107990
  };
107986
107991
  });
107987
107992
 
107988
- // ../../packages/core/dist/data/vector/vector-store-factory.js
107993
+ // ../../packages/core/dist/services/vector/vector-store-factory.js
107989
107994
  async function getVectorStore(config3) {
107990
107995
  if (cachedStore)
107991
107996
  return cachedStore;
@@ -108002,6 +108007,7 @@ async function getVectorStore(config3) {
108002
108007
  ...ivfflatLists ? { lists: ivfflatLists } : {}
108003
108008
  };
108004
108009
  const store = new PostgresVectorStore({
108010
+ embeddingProviderFactory: () => createEmbeddingProvider({ cache: true }),
108005
108011
  connectionString,
108006
108012
  poolSize: Number.parseInt(process.env.POSTGRES_VECTOR_POOL_SIZE || "10", 10),
108007
108013
  indexType: process.env.POSTGRES_VECTOR_INDEX || "hnsw",
@@ -108028,6 +108034,7 @@ var init_vector_store_factory = __esm(() => {
108028
108034
  init_dist();
108029
108035
  init_config();
108030
108036
  init_postgres_vector_store();
108037
+ init_embeddings();
108031
108038
  });
108032
108039
 
108033
108040
  // ../../packages/core/dist/services/search/search-cache-pg.js
@@ -108599,7 +108606,7 @@ var init_analytics_factory = __esm(() => {
108599
108606
  init_dist();
108600
108607
  });
108601
108608
 
108602
- // ../../packages/core/dist/services/structural/schema-version.js
108609
+ // ../../packages/core/dist/kernel/schema-version.js
108603
108610
  function parseSemver(version3) {
108604
108611
  const match2 = SEMVER_PATTERN.exec(version3.trim());
108605
108612
  if (!match2)
@@ -108638,7 +108645,7 @@ var init_schema_version = __esm(() => {
108638
108645
  SEMVER_PATTERN = /^(\d+)\.(\d+)\.(\d+)$/u;
108639
108646
  });
108640
108647
 
108641
- // ../../packages/core/dist/services/structural/fqn-codec.js
108648
+ // ../../packages/core/dist/kernel/fqn-codec.js
108642
108649
  import { createHash as createHash3 } from "crypto";
108643
108650
  function normalizedNfcText(value, label) {
108644
108651
  const normalized = value.normalize("NFC").trim();
@@ -110955,7 +110962,7 @@ var init_memory_repository_factory = __esm(() => {
110955
110962
  init_memory_repository_pg();
110956
110963
  });
110957
110964
 
110958
- // ../../packages/core/dist/services/graph/graph-store-pg.js
110965
+ // ../../packages/core/dist/services/memory-graph/graph-store-pg.js
110959
110966
  function metadataForEdge(edge) {
110960
110967
  return {
110961
110968
  autoExtracted: edge.autoExtracted ?? false,
@@ -111271,7 +111278,7 @@ var init_graph_store_pg = __esm(() => {
111271
111278
  graphStorePg = GraphStorePg.getInstance();
111272
111279
  });
111273
111280
 
111274
- // ../../packages/core/dist/services/graph/graph-store-factory.js
111281
+ // ../../packages/core/dist/services/memory-graph/graph-store-factory.js
111275
111282
  function getGraphStore() {
111276
111283
  if (cachedStore2)
111277
111284
  return cachedStore2;
@@ -112877,7 +112884,7 @@ var init_reranker = __esm(() => {
112877
112884
  });
112878
112885
  });
112879
112886
 
112880
- // ../../packages/core/dist/tools/enum-validation.js
112887
+ // ../../packages/core/dist/kernel/enum-validation.js
112881
112888
  function validateEnum(paramName, value, validValues) {
112882
112889
  if (typeof value !== "string" || !validValues.includes(value)) {
112883
112890
  throw new ToolError(`Invalid ${paramName} value: ${String(value)}. Valid values: ${validValues.join(", ")}.`);
@@ -112949,7 +112956,7 @@ var init_filter_validation = __esm(() => {
112949
112956
  init_enum_validation();
112950
112957
  });
112951
112958
 
112952
- // ../../packages/core/dist/controllers/search-controller.js
112959
+ // ../../packages/core/dist/services/search/search-controller.js
112953
112960
  var exports_search_controller = {};
112954
112961
  __export(exports_search_controller, {
112955
112962
  SearchController: () => SearchController
@@ -113694,7 +113701,7 @@ var init_session_bias = __esm(() => {
113694
113701
  init_synapse();
113695
113702
  });
113696
113703
 
113697
- // ../../packages/core/dist/services/search/search-diagnostics.js
113704
+ // ../../packages/core/dist/kernel/search-diagnostics.js
113698
113705
  function searchBackendUnavailable(component, cause) {
113699
113706
  return cause instanceof SearchServiceError ? cause : new SearchServiceError("SEARCH_BACKEND_UNAVAILABLE", component, { cause });
113700
113707
  }
@@ -122205,16 +122212,16 @@ function detectRoutes(httpEdges, defs, opts = {}) {
122205
122212
  const seen = new Set;
122206
122213
  const out = [];
122207
122214
  for (const e of httpEdges) {
122208
- const path18 = e.route;
122209
- if (!path18)
122215
+ const path19 = e.route;
122216
+ if (!path19)
122210
122217
  continue;
122211
122218
  const method = (e.method ?? "ANY").toUpperCase();
122212
- const key = method + " " + path18;
122219
+ const key = method + " " + path19;
122213
122220
  if (seen.has(key))
122214
122221
  continue;
122215
122222
  seen.add(key);
122216
122223
  out.push({
122217
- path: path18,
122224
+ path: path19,
122218
122225
  method: e.method,
122219
122226
  file: e.fromFile,
122220
122227
  handler: e.targetFqn ?? e.symbolName
@@ -122225,12 +122232,12 @@ function detectRoutes(httpEdges, defs, opts = {}) {
122225
122232
  continue;
122226
122233
  const parsed = parseRouteName(d.name);
122227
122234
  const method = parsed?.method ?? "ANY";
122228
- const path18 = parsed?.path ?? d.name;
122229
- const key = method + " " + path18;
122235
+ const path19 = parsed?.path ?? d.name;
122236
+ const key = method + " " + path19;
122230
122237
  if (seen.has(key))
122231
122238
  continue;
122232
122239
  seen.add(key);
122233
- out.push({ path: path18, method: parsed?.method, file: d.filePath, handler: d.name });
122240
+ out.push({ path: path19, method: parsed?.method, file: d.filePath, handler: d.name });
122234
122241
  }
122235
122242
  for (const d of defs) {
122236
122243
  const parsed = parseRouteName(d.name);
@@ -122451,7 +122458,7 @@ __export(exports_symbol_graph_service, {
122451
122458
  symbolGraphService: () => symbolGraphService,
122452
122459
  SymbolGraphService: () => SymbolGraphService
122453
122460
  });
122454
- import path18 from "path";
122461
+ import path19 from "path";
122455
122462
  import fs9 from "fs/promises";
122456
122463
 
122457
122464
  class SymbolGraphService {
@@ -122805,7 +122812,7 @@ class SymbolGraphService {
122805
122812
  }
122806
122813
  async resolveToAbsolute(relativePath, projectId) {
122807
122814
  const root = await this.getProjectRoot(projectId);
122808
- return root ? path18.resolve(root, relativePath) : relativePath;
122815
+ return root ? path19.resolve(root, relativePath) : relativePath;
122809
122816
  }
122810
122817
  async getProjectRoot(projectId) {
122811
122818
  const cached2 = this.projectRootCache.get(projectId);
@@ -122825,12 +122832,7 @@ class SymbolGraphService {
122825
122832
  return null;
122826
122833
  }
122827
122834
  evictOldestProjectRoot() {
122828
- while (this.projectRootCache.size >= this.PROJECT_ROOT_CACHE_MAX_ENTRIES) {
122829
- const oldest = this.projectRootCache.keys().next().value;
122830
- if (oldest === undefined)
122831
- break;
122832
- this.projectRootCache.delete(oldest);
122833
- }
122835
+ evictOldest(this.projectRootCache, this.PROJECT_ROOT_CACHE_MAX_ENTRIES - 1);
122834
122836
  }
122835
122837
  clearProjectRoot(projectId) {
122836
122838
  this.projectRootCache.delete(projectId);
@@ -123122,7 +123124,7 @@ var init_memory_service = __esm(() => {
123122
123124
  init_decay();
123123
123125
  });
123124
123126
 
123125
- // ../../packages/core/dist/services/graph/relation-extractor.js
123127
+ // ../../packages/core/dist/services/memory-graph/relation-extractor.js
123126
123128
  class RelationExtractor {
123127
123129
  graphStore;
123128
123130
  constructor(graphStore) {
@@ -123360,7 +123362,7 @@ var init_relation_extractor = __esm(() => {
123360
123362
  ];
123361
123363
  });
123362
123364
 
123363
- // ../../packages/core/dist/services/graph/graph-queries.js
123365
+ // ../../packages/core/dist/services/memory-graph/graph-queries.js
123364
123366
  class GraphQueries {
123365
123367
  graphStore;
123366
123368
  constructor(graphStore) {
@@ -123580,7 +123582,7 @@ var init_graph_queries = __esm(() => {
123580
123582
  };
123581
123583
  });
123582
123584
 
123583
- // ../../packages/core/dist/services/graph/memory-graph.service.js
123585
+ // ../../packages/core/dist/services/memory-graph/memory-graph.service.js
123584
123586
  class MemoryGraphService {
123585
123587
  static instance = null;
123586
123588
  store;
@@ -124146,7 +124148,7 @@ var init_salience_judge = __esm(() => {
124146
124148
  });
124147
124149
  });
124148
124150
 
124149
- // ../../packages/core/dist/controllers/memory-controller.js
124151
+ // ../../packages/core/dist/services/memory/memory-controller.js
124150
124152
  class MemoryController {
124151
124153
  static instance = null;
124152
124154
  repo;
@@ -124783,6 +124785,45 @@ var init_code_compressor = __esm(() => {
124783
124785
  init_llm_client();
124784
124786
  });
124785
124787
 
124788
+ // ../../packages/core/dist/services/compression/compress-with-metrics.js
124789
+ async function compressWithMetrics(compressor, content, strategy, options = {}) {
124790
+ const { language, targetRatio } = options;
124791
+ const unit = language || "code";
124792
+ const originalTokens = estimateTokens(content, unit);
124793
+ logger.info("Compressing context", {
124794
+ originalTokens,
124795
+ strategy,
124796
+ targetRatio
124797
+ });
124798
+ const result = await compressor.compress(content, strategy);
124799
+ const compressedTokens = estimateTokens(result.compressed, unit);
124800
+ const compressionRatio = 1 - compressedTokens / originalTokens;
124801
+ const tokensSaved = originalTokens - compressedTokens;
124802
+ logger.info("Context compressed", {
124803
+ originalTokens,
124804
+ compressedTokens,
124805
+ tokensSaved,
124806
+ actualRatio: compressionRatio.toFixed(2),
124807
+ targetRatio
124808
+ });
124809
+ return {
124810
+ compressed: result.compressed,
124811
+ originalTokens,
124812
+ compressedTokens,
124813
+ tokensSaved,
124814
+ compressionRatio
124815
+ };
124816
+ }
124817
+ var init_compress_with_metrics = __esm(() => {
124818
+ init_dist();
124819
+ });
124820
+
124821
+ // ../../packages/core/dist/services/compression/index.js
124822
+ var init_compression = __esm(() => {
124823
+ init_code_compressor();
124824
+ init_compress_with_metrics();
124825
+ });
124826
+
124786
124827
  // ../../packages/core/dist/services/metrics/token-metrics.js
124787
124828
  class TokenMetrics {
124788
124829
  static instance = null;
@@ -125116,6 +125157,340 @@ var init_session_file_cache = __esm(() => {
125116
125157
  SESSION_TTL_MS = 4 * 60 * 60 * 1000;
125117
125158
  });
125118
125159
 
125160
+ // ../../packages/core/dist/services/context/context-controller.js
125161
+ class ContextController {
125162
+ static instance = null;
125163
+ searchCtrl;
125164
+ memoryCtrl;
125165
+ compressor;
125166
+ sessionCache;
125167
+ constructor() {
125168
+ this.searchCtrl = SearchController.getInstance();
125169
+ this.memoryCtrl = MemoryController.getInstance();
125170
+ this.compressor = new CodeCompressor;
125171
+ this.sessionCache = SessionFileCache.getInstance();
125172
+ }
125173
+ static getInstance() {
125174
+ if (!ContextController.instance) {
125175
+ ContextController.instance = new ContextController;
125176
+ }
125177
+ return ContextController.instance;
125178
+ }
125179
+ async getOptimizedContext(input) {
125180
+ const { query, projectId, projectPath: projectPath2, maxTokens = 4000, maxResults = 5, workingMemoryBudget, userId, sessionId, includeMemories = true, memoryBudgetRatio = 0.2 } = input;
125181
+ const clampedRatio = Math.max(0, Math.min(0.5, memoryBudgetRatio));
125182
+ const memoryTokenBudget = includeMemories ? Math.floor(maxTokens * clampedRatio) : 0;
125183
+ const codeTokenBudget = maxTokens - memoryTokenBudget;
125184
+ const wmBudget = workingMemoryBudget || Math.floor(codeTokenBudget * 0.8);
125185
+ logger.info("Getting optimized context", {
125186
+ query: query.slice(0, 50),
125187
+ projectId,
125188
+ maxTokens,
125189
+ includeMemories,
125190
+ memoryTokenBudget,
125191
+ codeTokenBudget,
125192
+ workingMemoryBudget: wmBudget
125193
+ });
125194
+ let graphContextSection = "";
125195
+ let graphBoostFiles = [];
125196
+ if (projectId && await symbolGraphService.hasData(projectId) && looksLikeSymbol(query)) {
125197
+ try {
125198
+ const [defs, refs] = await Promise.all([
125199
+ symbolGraphService.goToDefinition(projectId, query),
125200
+ symbolGraphService.getReferences(projectId, query)
125201
+ ]);
125202
+ if (defs.length > 0) {
125203
+ const graphTokenBudget = Math.floor(codeTokenBudget * 0.2);
125204
+ graphContextSection = formatGraphContext(defs, refs, graphTokenBudget);
125205
+ graphBoostFiles = [
125206
+ ...new Set([
125207
+ ...defs.map((d) => d.file),
125208
+ ...refs.slice(0, 10).map((r2) => r2.fromFile)
125209
+ ])
125210
+ ];
125211
+ logger.debug("Graph prefilter hit", {
125212
+ query,
125213
+ defs: defs.length,
125214
+ refs: refs.length,
125215
+ boostFiles: graphBoostFiles.length
125216
+ });
125217
+ }
125218
+ } catch (err) {
125219
+ logger.warn("Graph prefilter failed", { query, error: err.message });
125220
+ }
125221
+ }
125222
+ const [searchResult, memories] = await Promise.all([
125223
+ this.searchCtrl.searchProject({
125224
+ query,
125225
+ projectId,
125226
+ projectPath: projectPath2,
125227
+ maxResults,
125228
+ responseMode: "full",
125229
+ autoReindex: false,
125230
+ minScore: 0.4,
125231
+ boostFiles: graphBoostFiles.length > 0 ? graphBoostFiles : undefined
125232
+ }),
125233
+ includeMemories ? this.searchMemoriesSafe(query, {
125234
+ projectId,
125235
+ userId,
125236
+ sessionId,
125237
+ limit: 5
125238
+ }) : Promise.resolve([])
125239
+ ]);
125240
+ const codeResults = searchResult.results;
125241
+ const workingSet = this.selectWorkingSet(codeResults, wmBudget);
125242
+ const memorySection = this.formatMemorySection(memories, memoryTokenBudget);
125243
+ if (workingSet.length === 0 && memories.length === 0) {
125244
+ return {
125245
+ context: `No relevant code or memories found for query: "${query}"`,
125246
+ sources: [],
125247
+ resultsCount: 0,
125248
+ memoriesCount: 0,
125249
+ tokensSaved: 0,
125250
+ compressionRatio: 0,
125251
+ sessionCacheHits: 0,
125252
+ tokensSavedBySessionCache: 0
125253
+ };
125254
+ }
125255
+ let sessionCacheHits = 0;
125256
+ let tokensSavedBySessionCache = 0;
125257
+ const deliveryPlan = workingSet.map((r2) => {
125258
+ if (!sessionId) {
125259
+ return { result: r2, kind: "full", tokensSaved: 0 };
125260
+ }
125261
+ const content = r2.content || r2.preview || "";
125262
+ const key = this.sessionCache.chunkKey(r2.filePath || "unknown", r2.lineStart ?? 0, r2.lineEnd ?? 0);
125263
+ const check3 = this.sessionCache.check(sessionId, key, content);
125264
+ if (check3.status === "unchanged") {
125265
+ sessionCacheHits++;
125266
+ tokensSavedBySessionCache += check3.tokensSaved;
125267
+ return { result: r2, kind: "ref", tokensSaved: check3.tokensSaved };
125268
+ }
125269
+ if (check3.status === "changed" && check3.diff !== undefined) {
125270
+ sessionCacheHits++;
125271
+ tokensSavedBySessionCache += check3.tokensSaved;
125272
+ return { result: r2, kind: "diff", diff: check3.diff, tokensSaved: check3.tokensSaved };
125273
+ }
125274
+ return { result: r2, kind: "full", tokensSaved: 0 };
125275
+ });
125276
+ const parts = [`# Context for: ${query}
125277
+ `];
125278
+ if (graphContextSection) {
125279
+ parts.push(graphContextSection, "");
125280
+ }
125281
+ if (memorySection) {
125282
+ parts.push(memorySection, "");
125283
+ }
125284
+ if (deliveryPlan.length > 0) {
125285
+ const fullCount = deliveryPlan.filter((d) => d.kind === "full").length;
125286
+ const refCount = deliveryPlan.filter((d) => d.kind === "ref").length;
125287
+ const diffCount = deliveryPlan.filter((d) => d.kind === "diff").length;
125288
+ parts.push(`## Code (${deliveryPlan.length} sections \u2014 ${fullCount} full, ${refCount} cached, ${diffCount} diff | WM budget: ${wmBudget} tokens)
125289
+ `);
125290
+ deliveryPlan.forEach(({ result: r2, kind, diff }, idx) => {
125291
+ const filePath = r2.filePath || "Unknown";
125292
+ const scoreLabel = (r2.score * 100).toFixed(1);
125293
+ const lineRange = `${r2.lineStart ?? "?"}-${r2.lineEnd ?? "?"}`;
125294
+ parts.push(`### ${idx + 1}. ${filePath} (score: ${scoreLabel}%)`);
125295
+ parts.push(`Lines ${lineRange}
125296
+ `);
125297
+ if (kind === "ref") {
125298
+ parts.push(`[CACHED: ${filePath}:${lineRange}]
125299
+ `);
125300
+ } else if (kind === "diff" && diff) {
125301
+ parts.push("```diff");
125302
+ parts.push(diff);
125303
+ parts.push("```\n");
125304
+ } else {
125305
+ parts.push("```" + (r2.language || ""));
125306
+ parts.push(r2.content || r2.preview || "(no content)");
125307
+ parts.push("```\n");
125308
+ }
125309
+ });
125310
+ }
125311
+ const rawContext = parts.join(`
125312
+ `);
125313
+ const rawTokens = estimateTokens(rawContext, "code");
125314
+ let finalContext = rawContext;
125315
+ let compressionRatio = 0;
125316
+ let tokensSaved = 0;
125317
+ if (rawTokens > maxTokens) {
125318
+ logger.info("Context exceeds maxTokens, compressing", {
125319
+ rawTokens,
125320
+ maxTokens
125321
+ });
125322
+ try {
125323
+ const metrics2 = await compressWithMetrics(this.compressor, rawContext, "code_structure", { targetRatio: 0.6 });
125324
+ finalContext = metrics2.compressed;
125325
+ compressionRatio = metrics2.compressionRatio || 0;
125326
+ tokensSaved = metrics2.tokensSaved || 0;
125327
+ } catch (error51) {
125328
+ logger.error("Failed to compress context", error51, {
125329
+ strategy: "code_structure",
125330
+ contentLength: rawContext.length
125331
+ });
125332
+ }
125333
+ }
125334
+ const finalTokens = estimateTokens(finalContext, "code");
125335
+ const totalTokensSaved = rawTokens - finalTokens;
125336
+ const compressionSavings = tokensSaved;
125337
+ TokenMetrics.getInstance().recordContextRequest(rawTokens, finalTokens, tokensSavedBySessionCache, compressionSavings);
125338
+ logger.info("Optimized context retrieved", {
125339
+ rawTokens,
125340
+ finalTokens,
125341
+ tokensSaved: totalTokensSaved,
125342
+ compressionRatio,
125343
+ codeSources: workingSet.length,
125344
+ memoriesIncluded: memories.length,
125345
+ wmBudget,
125346
+ sessionCacheHits,
125347
+ tokensSavedBySessionCache
125348
+ });
125349
+ return {
125350
+ context: finalContext,
125351
+ sources: workingSet.map((r2) => r2.filePath || "unknown"),
125352
+ resultsCount: workingSet.length,
125353
+ memoriesCount: memories.length,
125354
+ tokensSaved: totalTokensSaved,
125355
+ compressionRatio,
125356
+ sessionCacheHits,
125357
+ tokensSavedBySessionCache
125358
+ };
125359
+ }
125360
+ async searchMemoriesSafe(query, opts) {
125361
+ try {
125362
+ const result = await this.memoryCtrl.search({
125363
+ query,
125364
+ projectId: opts.projectId,
125365
+ userId: opts.userId,
125366
+ sessionId: opts.sessionId,
125367
+ includePersistent: true,
125368
+ minImportance: 0.3,
125369
+ limit: opts.limit
125370
+ });
125371
+ return result.memories;
125372
+ } catch (error51) {
125373
+ logger.warn("Memory search failed, continuing without memories", {
125374
+ error: error51.message,
125375
+ query: query.slice(0, 30)
125376
+ });
125377
+ return [];
125378
+ }
125379
+ }
125380
+ formatMemorySection(memories, tokenBudget) {
125381
+ if (memories.length === 0 || tokenBudget <= 0)
125382
+ return null;
125383
+ const parts = [
125384
+ `## Relevant Memories (from previous sessions)
125385
+ `
125386
+ ];
125387
+ let usedTokens = estimateTokens(parts[0], "text");
125388
+ for (const memory of memories) {
125389
+ const typeLabel = (memory.type || "unknown").toUpperCase();
125390
+ const score = memory.score ? ` (relevance: ${(memory.score * 100).toFixed(0)}%)` : "";
125391
+ const importance = memory.importance ? ` [importance: ${(memory.importance * 100).toFixed(0)}%]` : "";
125392
+ const agent = memory.agentId ? ` (by: ${memory.agentId})` : "";
125393
+ const entry2 = `- **[${typeLabel}]**${score}${importance}${agent}: ${memory.content}`;
125394
+ const entryTokens = estimateTokens(entry2, "text");
125395
+ if (usedTokens + entryTokens > tokenBudget)
125396
+ break;
125397
+ parts.push(entry2);
125398
+ usedTokens += entryTokens;
125399
+ }
125400
+ return parts.length <= 1 ? null : parts.join(`
125401
+ `);
125402
+ }
125403
+ selectWorkingSet(results, tokenBudget) {
125404
+ if (!results.length || tokenBudget <= 0)
125405
+ return [];
125406
+ const selected = [];
125407
+ const selectedFiles = new Set;
125408
+ let usedTokens = 0;
125409
+ const sorted = [...results].sort((a12, b) => (b.score || 0) - (a12.score || 0));
125410
+ for (const result of sorted) {
125411
+ const filePath = result.filePath || "unknown";
125412
+ if (selectedFiles.has(filePath))
125413
+ continue;
125414
+ const content = result.content || result.preview || "";
125415
+ const tokens = estimateTokens(content, "code");
125416
+ if (usedTokens + tokens > tokenBudget)
125417
+ continue;
125418
+ selected.push(result);
125419
+ selectedFiles.add(filePath);
125420
+ usedTokens += tokens;
125421
+ }
125422
+ for (const result of sorted) {
125423
+ if (selected.includes(result))
125424
+ continue;
125425
+ const content = result.content || result.preview || "";
125426
+ const tokens = estimateTokens(content, "code");
125427
+ if (usedTokens + tokens > tokenBudget)
125428
+ continue;
125429
+ selected.push(result);
125430
+ usedTokens += tokens;
125431
+ }
125432
+ return selected;
125433
+ }
125434
+ }
125435
+ function looksLikeSymbol(query) {
125436
+ if (query.length > 80)
125437
+ return false;
125438
+ const words = query.trim().split(/\s+/);
125439
+ if (words.length > 3)
125440
+ return false;
125441
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(words[0]);
125442
+ }
125443
+ function formatGraphContext(defs, refs, tokenBudget) {
125444
+ const parts = [`## Symbol Graph
125445
+ `];
125446
+ if (defs.length > 0) {
125447
+ parts.push(`### Definition(s)
125448
+ `);
125449
+ for (const def of defs.slice(0, 3)) {
125450
+ parts.push(`- **${def.kind}** \`${def.name}\` \u2192 \`${def.file}\` L${def.lineStart}\u2013${def.lineEnd}`);
125451
+ if (def.docComment)
125452
+ parts.push(` > ${def.docComment.slice(0, 120)}`);
125453
+ if (def.snippet) {
125454
+ parts.push(" ```");
125455
+ parts.push(def.snippet.split(`
125456
+ `).slice(0, 8).join(`
125457
+ `));
125458
+ parts.push(" ```");
125459
+ }
125460
+ }
125461
+ parts.push("");
125462
+ }
125463
+ if (refs.length > 0) {
125464
+ parts.push(`### References (${refs.length} total)
125465
+ `);
125466
+ const byFile = new Map;
125467
+ for (const r2 of refs.slice(0, 30)) {
125468
+ const arr = byFile.get(r2.fromFile) ?? [];
125469
+ arr.push(r2.fromLine);
125470
+ byFile.set(r2.fromFile, arr);
125471
+ }
125472
+ for (const [file3, lines] of byFile) {
125473
+ parts.push(`- \`${file3}\` L${lines.join(", ")}`);
125474
+ }
125475
+ parts.push("");
125476
+ }
125477
+ const section = parts.join(`
125478
+ `);
125479
+ const charBudget = tokenBudget * 4;
125480
+ return section.length > charBudget ? section.slice(0, charBudget) + `
125481
+ ...
125482
+ ` : section;
125483
+ }
125484
+ var init_context_controller = __esm(() => {
125485
+ init_dist();
125486
+ init_search_controller();
125487
+ init_memory_controller();
125488
+ init_compression();
125489
+ init_session_file_cache();
125490
+ init_symbol_graph_service();
125491
+ init_token_metrics();
125492
+ });
125493
+
125119
125494
  // ../../packages/core/dist/services/checkpoint/checkpoint-store-pg.js
125120
125495
  function toNum2(v) {
125121
125496
  if (v == null)
@@ -126427,31 +126802,31 @@ class TracePathService {
126427
126802
  const chains = [];
126428
126803
  const seen = new Set;
126429
126804
  let walks = 0;
126430
- const walk = (fqn, path21) => {
126805
+ const walk = (fqn, path22) => {
126431
126806
  if (chains.length >= CHAIN_CAP)
126432
126807
  return;
126433
126808
  if (walks >= MAX_WALKS)
126434
126809
  return;
126435
126810
  walks++;
126436
- const key = path21.join("\u2192");
126811
+ const key = path22.join("\u2192");
126437
126812
  if (seen.has(key))
126438
126813
  return;
126439
126814
  seen.add(key);
126440
126815
  const next = adj.get(fqn);
126441
126816
  if (!next || next.length === 0 || !whoHasChild.has(fqn)) {
126442
- if (path21.length > 1)
126443
- chains.push(path21.map((n2) => this.fqnToName(n2)).join(" \u2192 "));
126817
+ if (path22.length > 1)
126818
+ chains.push(path22.map((n2) => this.fqnToName(n2)).join(" \u2192 "));
126444
126819
  return;
126445
126820
  }
126446
126821
  for (const child of next) {
126447
126822
  if (chains.length >= CHAIN_CAP || walks >= MAX_WALKS)
126448
126823
  return;
126449
- if (path21.includes(child)) {
126450
- const cycled = [...path21, `${this.fqnToName(child)}\u21BA`];
126824
+ if (path22.includes(child)) {
126825
+ const cycled = [...path22, `${this.fqnToName(child)}\u21BA`];
126451
126826
  chains.push(cycled.map((n2) => n2).join(" \u2192 "));
126452
126827
  continue;
126453
126828
  }
126454
- walk(child, [...path21, child]);
126829
+ walk(child, [...path22, child]);
126455
126830
  }
126456
126831
  };
126457
126832
  for (const seed of seeds) {
@@ -127847,6 +128222,319 @@ var init_executor2 = __esm(() => {
127847
128222
  init_intent_search();
127848
128223
  });
127849
128224
 
128225
+ // ../../packages/core/dist/services/executor/executor-controller.js
128226
+ import { cpus as cpus2 } from "os";
128227
+ function applyIntent(result, intent) {
128228
+ if (!intent || !result.stdout)
128229
+ return result;
128230
+ const ir = intentSearch(result.stdout, intent);
128231
+ if (!ir.searched)
128232
+ return result;
128233
+ const rendered = renderIntentResult(ir, intent);
128234
+ return {
128235
+ ...result,
128236
+ stdout: `${rendered}
128237
+
128238
+ --- tail (last 512 chars) ---
128239
+ ${result.stdout.slice(-512)}`
128240
+ };
128241
+ }
128242
+
128243
+ class ExecutorController {
128244
+ static instance = null;
128245
+ executor;
128246
+ constructor(executor) {
128247
+ this.executor = executor ?? new PolyglotExecutor;
128248
+ }
128249
+ static getInstance() {
128250
+ if (!ExecutorController.instance) {
128251
+ ExecutorController.instance = new ExecutorController;
128252
+ }
128253
+ return ExecutorController.instance;
128254
+ }
128255
+ static resetInstance() {
128256
+ ExecutorController.instance?.executor.cleanupBackgrounded();
128257
+ ExecutorController.instance = null;
128258
+ }
128259
+ get runtimes() {
128260
+ return this.executor.runtimes;
128261
+ }
128262
+ async execute(params) {
128263
+ try {
128264
+ const language = validateEnum("language", params.language, EXECUTOR_LANGUAGES);
128265
+ const result = await this.executor.execute({
128266
+ language,
128267
+ code: params.code,
128268
+ timeout: params.timeout,
128269
+ background: params.background,
128270
+ cwd: params.cwd
128271
+ });
128272
+ const finalResult = applyIntent(result, params.intent);
128273
+ const ok = !finalResult.timedOut && finalResult.exitCode === 0;
128274
+ return {
128275
+ success: ok,
128276
+ data: {
128277
+ stdout: finalResult.stdout,
128278
+ stderr: finalResult.stderr,
128279
+ exitCode: finalResult.exitCode,
128280
+ timedOut: finalResult.timedOut,
128281
+ backgrounded: finalResult.backgrounded ?? false,
128282
+ command: finalResult.command,
128283
+ cwd: finalResult.cwd,
128284
+ sandboxMode: finalResult.sandboxMode
128285
+ }
128286
+ };
128287
+ } catch (error51) {
128288
+ logger.error("execute failed", error51, {
128289
+ language: params.language
128290
+ });
128291
+ return {
128292
+ success: false,
128293
+ error: `execute failed: ${error51.message}`
128294
+ };
128295
+ }
128296
+ }
128297
+ async executeFile(params) {
128298
+ try {
128299
+ const language = validateEnum("language", params.language, EXECUTOR_LANGUAGES);
128300
+ const result = await this.executor.executeFile({
128301
+ path: params.path,
128302
+ language,
128303
+ code: params.code,
128304
+ timeout: params.timeout
128305
+ });
128306
+ const blocked = result.stderr?.startsWith("Blocked:");
128307
+ if (blocked) {
128308
+ return { success: false, error: result.stderr };
128309
+ }
128310
+ const finalResult = applyIntent(result, params.intent);
128311
+ const ok = !finalResult.timedOut && finalResult.exitCode === 0;
128312
+ return {
128313
+ success: ok,
128314
+ data: {
128315
+ stdout: finalResult.stdout,
128316
+ stderr: finalResult.stderr,
128317
+ exitCode: finalResult.exitCode,
128318
+ timedOut: finalResult.timedOut,
128319
+ command: finalResult.command,
128320
+ cwd: finalResult.cwd,
128321
+ sandboxMode: finalResult.sandboxMode
128322
+ }
128323
+ };
128324
+ } catch (error51) {
128325
+ logger.error("execute_file failed", error51, {
128326
+ path: params.path,
128327
+ language: params.language
128328
+ });
128329
+ return {
128330
+ success: false,
128331
+ error: `execute_file failed: ${error51.message}`
128332
+ };
128333
+ }
128334
+ }
128335
+ async batchExecute(params) {
128336
+ const { commands, concurrency, cwd, timeout } = params;
128337
+ if (!Array.isArray(commands) || commands.length === 0) {
128338
+ return { success: false, error: "commands must be a non-empty array." };
128339
+ }
128340
+ if (commands.length > MAX_BATCH_COMMANDS) {
128341
+ return {
128342
+ success: false,
128343
+ error: `batch_execute accepts at most ${MAX_BATCH_COMMANDS} commands; received ${commands.length}. Split the batch or reduce the payload.`
128344
+ };
128345
+ }
128346
+ const effectiveConcurrency = concurrency && concurrency > 0 ? concurrency : Math.max(1, cpus2().length);
128347
+ const perTimeout = timeout ?? DEFAULT_TIMEOUT_MS2;
128348
+ try {
128349
+ const poolResult = await runPool(commands.map((cmd) => ({
128350
+ run: () => this.executor.execute({
128351
+ language: "shell",
128352
+ code: cmd,
128353
+ timeout: perTimeout,
128354
+ cwd
128355
+ })
128356
+ })), { concurrency: effectiveConcurrency });
128357
+ const results = poolResult.settled.map((s, i) => {
128358
+ if (s.status === "fulfilled") {
128359
+ const r2 = s.value;
128360
+ return {
128361
+ command: commands[i],
128362
+ stdout: r2.stdout,
128363
+ stderr: r2.stderr,
128364
+ exitCode: r2.exitCode,
128365
+ timedOut: r2.timedOut,
128366
+ sandboxMode: r2.sandboxMode
128367
+ };
128368
+ }
128369
+ return {
128370
+ command: commands[i],
128371
+ stdout: "",
128372
+ stderr: String(s.reason ?? "unknown error"),
128373
+ exitCode: null,
128374
+ timedOut: false,
128375
+ sandboxMode: getSandboxMode()
128376
+ };
128377
+ });
128378
+ const anyFailed = results.some((r2) => r2.exitCode !== 0 || r2.timedOut);
128379
+ return {
128380
+ success: !anyFailed,
128381
+ data: {
128382
+ results,
128383
+ concurrency: poolResult.effectiveConcurrency,
128384
+ capped: poolResult.capped
128385
+ }
128386
+ };
128387
+ } catch (error51) {
128388
+ logger.error("batch_execute failed", error51);
128389
+ return {
128390
+ success: false,
128391
+ error: `batch_execute failed: ${error51.message}`
128392
+ };
128393
+ }
128394
+ }
128395
+ static get MAX_TIMEOUT_MS() {
128396
+ return MAX_TIMEOUT_MS;
128397
+ }
128398
+ }
128399
+ var EXECUTOR_LANGUAGES, MAX_BATCH_COMMANDS = 256;
128400
+ var init_executor_controller = __esm(() => {
128401
+ init_dist();
128402
+ init_executor2();
128403
+ init_enum_validation();
128404
+ EXECUTOR_LANGUAGES = [
128405
+ "javascript",
128406
+ "typescript",
128407
+ "python",
128408
+ "shell",
128409
+ "ruby",
128410
+ "go",
128411
+ "rust",
128412
+ "php",
128413
+ "perl",
128414
+ "r"
128415
+ ];
128416
+ });
128417
+
128418
+ // ../../packages/core/dist/services/symbol/graph-controller.js
128419
+ class GraphController {
128420
+ static instance = null;
128421
+ constructor() {}
128422
+ static getInstance() {
128423
+ if (!GraphController.instance) {
128424
+ GraphController.instance = new GraphController;
128425
+ }
128426
+ return GraphController.instance;
128427
+ }
128428
+ async tracePath(input) {
128429
+ const projectId = input.projectId;
128430
+ const seed = input.function_name ?? input.symbol ?? input.qualifiedName;
128431
+ if (!projectId)
128432
+ throw new Error("projectId is required");
128433
+ if (!seed)
128434
+ throw new Error("function_name (or symbol/qualifiedName) is required");
128435
+ const t0 = performance.now();
128436
+ const result = await tracePathService.tracePath({
128437
+ symbol: input.function_name ?? input.symbol ?? "",
128438
+ function_name: input.function_name,
128439
+ qualifiedName: input.qualifiedName,
128440
+ projectId,
128441
+ direction: input.direction,
128442
+ mode: input.mode,
128443
+ depth: input.depth,
128444
+ include_tests: input.include_tests,
128445
+ edge_types: input.edge_types
128446
+ });
128447
+ logger.info("GraphController: trace_path", {
128448
+ projectId,
128449
+ symbol: seed,
128450
+ mode: result.mode,
128451
+ direction: result.direction,
128452
+ seeds: result.seeds.length,
128453
+ nodes: result.nodes.length,
128454
+ edges: result.edges.length,
128455
+ durationMs: Math.round(performance.now() - t0)
128456
+ });
128457
+ if (result.seeds.length === 0) {
128458
+ return {
128459
+ found: false,
128460
+ symbol: seed,
128461
+ projectId,
128462
+ ...result.identityResolution ? { identityResolution: result.identityResolution } : {},
128463
+ hint: "Use search_definitions(search=...) to find the exact name, or pass a fully-qualified name (qualifiedName='rel/path.ts#Name')."
128464
+ };
128465
+ }
128466
+ return {
128467
+ found: true,
128468
+ result: {
128469
+ projectId: result.projectId,
128470
+ symbol: result.symbol,
128471
+ mode: result.mode,
128472
+ direction: result.direction,
128473
+ edgeTypes: result.edgeTypes,
128474
+ seeds: result.seeds,
128475
+ truncated: result.truncated,
128476
+ nodes_total: result.nodes_total,
128477
+ nodes_shown: result.nodes_shown,
128478
+ nodes_omitted: result.nodes_omitted,
128479
+ nodeCount: result.nodes.length,
128480
+ edgeCount: result.edges.length,
128481
+ chains: result.chains,
128482
+ nodes: result.nodes,
128483
+ edges: result.edges,
128484
+ ...result.identityResolution ? { identity: toSymbolIdentityResolution(result.identityResolution) } : {}
128485
+ }
128486
+ };
128487
+ }
128488
+ async analyzeImpact(input) {
128489
+ if (!input.projectId)
128490
+ throw new Error("projectId is required");
128491
+ if (!input.projectPath)
128492
+ throw new Error("projectPath is required");
128493
+ const t0 = performance.now();
128494
+ const result = await impactAnalysisService.analyze({
128495
+ projectId: input.projectId,
128496
+ projectPath: input.projectPath,
128497
+ scope: input.scope ?? "unstaged",
128498
+ baseBranch: input.base_branch,
128499
+ since: input.since,
128500
+ depth: input.depth,
128501
+ paths: input.paths,
128502
+ diffRunner: input.diffRunner
128503
+ });
128504
+ logger.info("GraphController: impact_analysis", {
128505
+ projectId: input.projectId,
128506
+ scope: result.scope,
128507
+ changedFiles: result.changedFiles.length,
128508
+ impacted: result.impacted.length,
128509
+ truncated: result.truncated,
128510
+ durationMs: Math.round(performance.now() - t0)
128511
+ });
128512
+ return {
128513
+ projectId: result.projectId,
128514
+ scope: result.scope,
128515
+ baseBranch: result.baseBranch,
128516
+ since: result.since,
128517
+ depth: result.depth,
128518
+ changedFileCount: result.changedFiles.length,
128519
+ changedFiles: result.changedFiles,
128520
+ impactedCount: result.impacted.length,
128521
+ truncated: result.truncated,
128522
+ impacted: result.impacted,
128523
+ untrackedFiltered: result.untrackedFiltered,
128524
+ impacted_total: result.impacted_total,
128525
+ impacted_shown: result.impacted_shown,
128526
+ impacted_omitted: result.impacted_omitted,
128527
+ note: result.note
128528
+ };
128529
+ }
128530
+ }
128531
+ var init_graph_controller = __esm(() => {
128532
+ init_dist();
128533
+ init_trace_path();
128534
+ init_impact_analysis();
128535
+ init_definition_lookup();
128536
+ });
128537
+
127850
128538
  // ../../packages/core/dist/services/project-identity/errors.js
127851
128539
  var ERROR_MESSAGES, ERROR_STATUS, ProjectIdentityError;
127852
128540
  var init_errors4 = __esm(() => {
@@ -129282,7 +129970,7 @@ var init_l1_memory_cache = __esm(() => {
129282
129970
  // ../../packages/core/dist/services/health/local-health-checker.js
129283
129971
  import fs12 from "fs/promises";
129284
129972
  import { existsSync as existsSync3 } from "fs";
129285
- import path22 from "path";
129973
+ import path24 from "path";
129286
129974
 
129287
129975
  class LocalHealthChecker {
129288
129976
  ollamaBaseUrl = process.env.OLLAMA_BASE_URL || "http://localhost:11434";
@@ -129317,7 +130005,7 @@ class LocalHealthChecker {
129317
130005
  try {
129318
130006
  if (!existsSync3(this.dataDir))
129319
130007
  await fs12.mkdir(this.dataDir, { recursive: true });
129320
- const probe2 = path22.join(this.dataDir, ".health-check-test");
130008
+ const probe2 = path24.join(this.dataDir, ".health-check-test");
129321
130009
  await fs12.writeFile(probe2, "ok");
129322
130010
  await fs12.unlink(probe2);
129323
130011
  return { available: true, latency: Date.now() - start, details: { path: this.dataDir, writable: true } };
@@ -131231,7 +131919,7 @@ var init_scheduler2 = __esm(() => {
131231
131919
  // ../../packages/core/dist/services/pricing/models-dev-client.js
131232
131920
  import fs13 from "fs/promises";
131233
131921
  import { existsSync as existsSync4 } from "fs";
131234
- import path23 from "path";
131922
+ import path25 from "path";
131235
131923
  function getModelsDevClient() {
131236
131924
  if (!clientInstance) {
131237
131925
  clientInstance = new ModelsDevClient;
@@ -131251,7 +131939,7 @@ var init_models_dev_client = __esm(() => {
131251
131939
  memoryCacheTimestamp = 0;
131252
131940
  getLocalCachePath() {
131253
131941
  const dataDir = config.get("dataDir");
131254
- return path23.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
131942
+ return path25.join(dataDir, ModelsDevClient.LOCAL_CACHE_FILE);
131255
131943
  }
131256
131944
  async loadLocalCache() {
131257
131945
  const cachePath = this.getLocalCachePath();
@@ -131286,7 +131974,7 @@ var init_models_dev_client = __esm(() => {
131286
131974
  async saveLocalCache(models) {
131287
131975
  const cachePath = this.getLocalCachePath();
131288
131976
  try {
131289
- const dir = path23.dirname(cachePath);
131977
+ const dir = path25.dirname(cachePath);
131290
131978
  await fs13.mkdir(dir, { recursive: true });
131291
131979
  const data = {
131292
131980
  timestamp: Date.now(),
@@ -137177,33 +137865,33 @@ var require_URL = __commonJS((exports, module) => {
137177
137865
  else
137178
137866
  return basepath.substring(0, lastslash + 1) + refpath;
137179
137867
  }
137180
- function remove_dot_segments(path24) {
137181
- if (!path24)
137182
- return path24;
137868
+ function remove_dot_segments(path26) {
137869
+ if (!path26)
137870
+ return path26;
137183
137871
  var output = "";
137184
- while (path24.length > 0) {
137185
- if (path24 === "." || path24 === "..") {
137186
- path24 = "";
137872
+ while (path26.length > 0) {
137873
+ if (path26 === "." || path26 === "..") {
137874
+ path26 = "";
137187
137875
  break;
137188
137876
  }
137189
- var twochars = path24.substring(0, 2);
137190
- var threechars = path24.substring(0, 3);
137191
- var fourchars = path24.substring(0, 4);
137877
+ var twochars = path26.substring(0, 2);
137878
+ var threechars = path26.substring(0, 3);
137879
+ var fourchars = path26.substring(0, 4);
137192
137880
  if (threechars === "../") {
137193
- path24 = path24.substring(3);
137881
+ path26 = path26.substring(3);
137194
137882
  } else if (twochars === "./") {
137195
- path24 = path24.substring(2);
137883
+ path26 = path26.substring(2);
137196
137884
  } else if (threechars === "/./") {
137197
- path24 = "/" + path24.substring(3);
137198
- } else if (twochars === "/." && path24.length === 2) {
137199
- path24 = "/";
137200
- } else if (fourchars === "/../" || threechars === "/.." && path24.length === 3) {
137201
- path24 = "/" + path24.substring(4);
137885
+ path26 = "/" + path26.substring(3);
137886
+ } else if (twochars === "/." && path26.length === 2) {
137887
+ path26 = "/";
137888
+ } else if (fourchars === "/../" || threechars === "/.." && path26.length === 3) {
137889
+ path26 = "/" + path26.substring(4);
137202
137890
  output = output.replace(/\/?[^\/]*$/, "");
137203
137891
  } else {
137204
- var segment = path24.match(/(\/?([^\/]*))/)[0];
137892
+ var segment = path26.match(/(\/?([^\/]*))/)[0];
137205
137893
  output += segment;
137206
- path24 = path24.substring(segment.length);
137894
+ path26 = path26.substring(segment.length);
137207
137895
  }
137208
137896
  }
137209
137897
  return output;
@@ -149273,21 +149961,21 @@ function jsonToKeyPathChunks(value, label = "$") {
149273
149961
  walk(value, label, out);
149274
149962
  return out;
149275
149963
  }
149276
- function walk(val, path24, out) {
149964
+ function walk(val, path26, out) {
149277
149965
  if (val === null || val === undefined)
149278
149966
  return;
149279
149967
  if (Array.isArray(val)) {
149280
149968
  if (val.length === 0) {
149281
- out.push({ path: path24, content: `**${path24}** = _[]_` });
149969
+ out.push({ path: path26, content: `**${path26}** = _[]_` });
149282
149970
  return;
149283
149971
  }
149284
149972
  if (val.every((v) => v !== null && typeof v === "object")) {
149285
- val.forEach((v, i) => walk(v, `${path24}[${i}]`, out));
149973
+ val.forEach((v, i) => walk(v, `${path26}[${i}]`, out));
149286
149974
  return;
149287
149975
  }
149288
149976
  const items = val.map((v) => `- \`${String(v)}\``).join(`
149289
149977
  `);
149290
- out.push({ path: path24, content: `**${path24}**
149978
+ out.push({ path: path26, content: `**${path26}**
149291
149979
 
149292
149980
  ${items}` });
149293
149981
  return;
@@ -149295,16 +149983,16 @@ ${items}` });
149295
149983
  if (typeof val === "object") {
149296
149984
  const entries = Object.entries(val);
149297
149985
  if (entries.length === 0) {
149298
- out.push({ path: path24, content: `**${path24}** = _{}_` });
149986
+ out.push({ path: path26, content: `**${path26}** = _{}_` });
149299
149987
  return;
149300
149988
  }
149301
149989
  for (const [k2, v] of entries) {
149302
149990
  const safeKey = /^[A-Za-z_$][\w$]*$/.test(k2) ? k2 : JSON.stringify(k2);
149303
- walk(v, `${path24}.${safeKey}`, out);
149991
+ walk(v, `${path26}.${safeKey}`, out);
149304
149992
  }
149305
149993
  return;
149306
149994
  }
149307
- out.push({ path: path24, content: `**${path24}** = \`${String(val)}\`` });
149995
+ out.push({ path: path26, content: `**${path26}** = \`${String(val)}\`` });
149308
149996
  }
149309
149997
  var gfm, STRIP_SELECTORS, tdCache = null;
149310
149998
  var init_html_to_md = __esm(() => {
@@ -149570,12 +150258,7 @@ class WebController {
149570
150258
  markIndexed: (key, ts) => {
149571
150259
  this.cache.delete(key);
149572
150260
  this.cache.set(key, ts);
149573
- while (this.cache.size > WEB_CACHE_MAX_ENTRIES) {
149574
- const oldest = this.cache.keys().next().value;
149575
- if (oldest === undefined)
149576
- break;
149577
- this.cache.delete(oldest);
149578
- }
150261
+ evictOldest(this.cache, WEB_CACHE_MAX_ENTRIES);
149579
150262
  }
149580
150263
  };
149581
150264
  }
@@ -149777,6 +150460,7 @@ __export(exports_services, {
149777
150460
  SessionFileCache: () => SessionFileCache,
149778
150461
  SearchSessionHook: () => SearchSessionHook,
149779
150462
  SearchServiceError: () => SearchServiceError,
150463
+ SearchController: () => SearchController,
149780
150464
  SearchCachePg: () => SearchCachePg,
149781
150465
  SearchAnalyticsPg: () => SearchAnalyticsPg,
149782
150466
  Scheduler: () => Scheduler,
@@ -149810,6 +150494,7 @@ __export(exports_services, {
149810
150494
  ModelsDevClient: () => ModelsDevClient,
149811
150495
  MemoryService: () => MemoryService,
149812
150496
  MemoryGraphService: () => MemoryGraphService,
150497
+ MemoryController: () => MemoryController,
149813
150498
  MemoryClustering: () => MemoryClustering,
149814
150499
  MAX_TIMEOUT_MS: () => MAX_TIMEOUT_MS,
149815
150500
  MAX_STRUCTURAL_PARSER_CAPACITY: () => MAX_STRUCTURAL_PARSER_CAPACITY,
@@ -149828,10 +150513,12 @@ __export(exports_services, {
149828
150513
  ImpactAnalysisService: () => ImpactAnalysisService,
149829
150514
  GraphStorePg: () => GraphStorePg,
149830
150515
  GraphQueries: () => GraphQueries,
150516
+ GraphController: () => GraphController,
149831
150517
  GO_QUERY_PACK: () => GO_QUERY_PACK,
149832
150518
  FqnHashCollisionError: () => FqnHashCollisionError,
149833
150519
  FUNCTIONAL_QUERY_PACKS: () => FUNCTIONAL_QUERY_PACKS,
149834
150520
  FUNCTIONAL_LANGUAGE_RESOLVER: () => FUNCTIONAL_LANGUAGE_RESOLVER,
150521
+ ExecutorController: () => ExecutorController,
149835
150522
  EventBus: () => TypedEventBus,
149836
150523
  EtlPipeline: () => EtlPipeline,
149837
150524
  EmbeddingCachePg: () => EmbeddingCachePg,
@@ -149853,6 +150540,7 @@ __export(exports_services, {
149853
150540
  DATA_DOCUMENT_QUERY_PACKS: () => DATA_DOCUMENT_QUERY_PACKS,
149854
150541
  DATA_DOCUMENT_LANGUAGE_RESOLVER: () => DATA_DOCUMENT_LANGUAGE_RESOLVER,
149855
150542
  ContextualSearchRLM: () => ContextualSearchRLM,
150543
+ ContextController: () => ContextController,
149856
150544
  CompactionSnapshotService: () => CompactionSnapshotService,
149857
150545
  CodeCompressor: () => CodeCompressor,
149858
150546
  CoRetrievalHook: () => CoRetrievalHook,
@@ -149869,6 +150557,11 @@ var init_services = __esm(() => {
149869
150557
  init_search_analytics_pg();
149870
150558
  init_index_manager();
149871
150559
  init_search_diagnostics();
150560
+ init_memory_controller();
150561
+ init_search_controller();
150562
+ init_context_controller();
150563
+ init_executor_controller();
150564
+ init_graph_controller();
149872
150565
  init_l1_memory_cache();
149873
150566
  init_embedding_cache_pg();
149874
150567
  init_code_compressor();
@@ -172180,14 +172873,113 @@ var cors = (config2) => {
172180
172873
  init_contextual_search_rlm();
172181
172874
  init_dist();
172182
172875
  init_index_job_tracker();
172876
+
172877
+ // ../../packages/core/dist/services/indexing/execute-indexing.js
172878
+ init_dist();
172879
+ init_index_job_tracker();
172183
172880
  init_pipeline();
172184
- init_workspace_manager();
172185
- init_parser_readiness();
172881
+ async function executeIndexing(request) {
172882
+ const { jobId, projectId, projectPath, forceReindex, warmCache, warmupQueries, include_tests = false, managedRunLease, warmupCache: warmupCache2 } = request;
172883
+ const startTime = Date.now();
172884
+ try {
172885
+ indexJobTracker.updateStatus(jobId, "running");
172886
+ logger.info("Starting project indexing via ETL Pipeline", {
172887
+ jobId,
172888
+ projectPath,
172889
+ projectId,
172890
+ forceReindex,
172891
+ warmCache,
172892
+ include_tests
172893
+ });
172894
+ const etlResult = await EtlPipeline.getInstance().run({
172895
+ projectId,
172896
+ projectPath,
172897
+ jobId,
172898
+ forceReindex,
172899
+ include_tests,
172900
+ managedRunLease
172901
+ });
172902
+ const duration3 = Date.now() - startTime;
172903
+ logger.info("ETL Pipeline completed", {
172904
+ jobId,
172905
+ projectId,
172906
+ duration: duration3,
172907
+ filesIndexed: etlResult.filesIndexed,
172908
+ filesSkipped: etlResult.filesSkipped,
172909
+ chunksIndexed: etlResult.chunksIndexed,
172910
+ symbolsIndexed: etlResult.symbolsIndexed,
172911
+ errors: etlResult.errors,
172912
+ stageTimings: etlResult.stageTimings
172913
+ });
172914
+ if (warmCache) {
172915
+ logger.info("Starting cache warmup", { jobId, projectId });
172916
+ const warmupStats = await warmupCache2(projectId, projectPath, warmupQueries);
172917
+ logger.info("Cache warmup completed", { jobId, projectId, ...warmupStats });
172918
+ }
172919
+ indexJobTracker.updateProgress(jobId, etlResult.filesIndexed, etlResult.filesIndexed);
172920
+ await indexJobTracker.setResultAndFlush(jobId, {
172921
+ filesIndexed: etlResult.filesIndexed,
172922
+ chunksIndexed: etlResult.chunksIndexed,
172923
+ errors: etlResult.errors,
172924
+ duration: duration3,
172925
+ activatedGraphGenerationId: etlResult.activatedGraphGenerationId,
172926
+ parserDiagnostics: etlResult.parserDiagnostics
172927
+ });
172928
+ } catch (error51) {
172929
+ const duration3 = Date.now() - startTime;
172930
+ logger.error("Project indexing failed", error51, {
172931
+ jobId,
172932
+ projectPath,
172933
+ projectId,
172934
+ duration: duration3
172935
+ });
172936
+ indexJobTracker.setResult(jobId, {
172937
+ filesIndexed: 0,
172938
+ chunksIndexed: 0,
172939
+ errors: 1,
172940
+ duration: duration3
172941
+ }, error51.message);
172942
+ }
172943
+ }
172944
+
172945
+ // ../../packages/core/dist/services/indexing/acquire-indexing-lease.js
172946
+ init_dist();
172947
+ init_index_job_tracker();
172186
172948
  init_managed_run_repository_pg();
172949
+ async function acquireIndexingLease(request) {
172950
+ const { jobId, projectId } = request;
172951
+ const eventId = `index:${jobId}`;
172952
+ const managedRunRepo = ManagedRunRepositoryPg.getInstance();
172953
+ try {
172954
+ const beginOutcome = await managedRunRepo.begin({
172955
+ projectId,
172956
+ runKind: "indexing",
172957
+ eventId
172958
+ });
172959
+ if (beginOutcome.status === "busy") {
172960
+ indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 0, duration: 0 }, `indexing_busy:${beginOutcome.activeRunId}`);
172961
+ return {
172962
+ status: "busy",
172963
+ activeRunId: beginOutcome.activeRunId,
172964
+ leaseExpiresAt: beginOutcome.leaseExpiresAt
172965
+ };
172966
+ }
172967
+ return { status: "acquired", lease: beginOutcome.lease };
172968
+ } catch (beginError) {
172969
+ logger.error("managed_runs begin failed", beginError, {
172970
+ jobId,
172971
+ projectId
172972
+ });
172973
+ indexJobTracker.setResult(jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: 0 }, `managed_runs_begin_failed:${beginError.message}`);
172974
+ return { status: "failed", message: beginError.message };
172975
+ }
172976
+ }
172977
+
172978
+ // ../../packages/core/dist/services/project-identity/project-root-identity.js
172187
172979
  import { realpath as realpath2 } from "fs/promises";
172188
- import path19 from "path";
172980
+ import path18 from "path";
172189
172981
  async function canonicalizeProjectRoot(projectPath, canonicalize = realpath2) {
172190
- return canonicalize(path19.resolve(projectPath));
172982
+ return canonicalize(path18.resolve(projectPath));
172191
172983
  }
172192
172984
  async function assertProjectRootReuse(options) {
172193
172985
  if (!options.storedProjectPath || options.forceReindex)
@@ -172195,15 +172987,20 @@ async function assertProjectRootReuse(options) {
172195
172987
  const canonicalize = options.canonicalize ?? realpath2;
172196
172988
  let storedCanonical;
172197
172989
  try {
172198
- storedCanonical = await canonicalize(path19.resolve(options.storedProjectPath));
172990
+ storedCanonical = await canonicalize(path18.resolve(options.storedProjectPath));
172199
172991
  } catch {
172200
- storedCanonical = path19.resolve(options.storedProjectPath);
172992
+ storedCanonical = path18.resolve(options.storedProjectPath);
172201
172993
  }
172202
172994
  if (storedCanonical !== options.canonicalProjectPath) {
172203
172995
  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");
172204
172996
  }
172205
172997
  }
172206
172998
 
172999
+ // ../../packages/core/dist/tools/index_project.js
173000
+ init_workspace_manager();
173001
+ init_parser_readiness();
173002
+ import path20 from "path";
173003
+
172207
173004
  class IndexProjectTool {
172208
173005
  name = "index_project";
172209
173006
  description = "Index a project directory for contextual code search with semantic embeddings";
@@ -172250,7 +173047,7 @@ class IndexProjectTool {
172250
173047
  try {
172251
173048
  await assertParserReadyForIndexing();
172252
173049
  const canonicalProjectPath = await canonicalizeProjectRoot(projectPath);
172253
- const finalProjectId = projectId || path19.basename(canonicalProjectPath) || "default";
173050
+ const finalProjectId = projectId || path20.basename(canonicalProjectPath) || "default";
172254
173051
  const existing = await workspaceManager.getWorkspace(finalProjectId);
172255
173052
  await assertProjectRootReuse({
172256
173053
  projectId: finalProjectId,
@@ -172264,40 +173061,42 @@ class IndexProjectTool {
172264
173061
  projectPath: canonicalProjectPath,
172265
173062
  projectId: finalProjectId
172266
173063
  });
172267
- const eventId = `index:${job.jobId}`;
172268
- const managedRunRepo = ManagedRunRepositoryPg.getInstance();
172269
- let lease;
172270
- try {
172271
- const beginOutcome = await managedRunRepo.begin({
172272
- projectId: finalProjectId,
172273
- runKind: "indexing",
172274
- eventId
172275
- });
172276
- if (beginOutcome.status === "busy") {
172277
- indexJobTracker.setResult(job.jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 0, duration: 0 }, `indexing_busy:${beginOutcome.activeRunId}`);
172278
- return {
172279
- success: false,
172280
- error: `indexing_busy:${beginOutcome.activeRunId}`,
172281
- data: {
172282
- jobId: job.jobId,
172283
- projectId: finalProjectId,
172284
- status: "busy",
172285
- activeRunId: beginOutcome.activeRunId,
172286
- leaseExpiresAt: beginOutcome.leaseExpiresAt,
172287
- message: "Another indexing run is active for this project. Poll get_index_status(activeRunId)."
172288
- }
172289
- };
172290
- }
172291
- lease = beginOutcome.lease;
172292
- } catch (beginError) {
172293
- logger.error("managed_runs begin failed", beginError, { jobId: job.jobId, projectId: finalProjectId });
172294
- indexJobTracker.setResult(job.jobId, { filesIndexed: 0, chunksIndexed: 0, errors: 1, duration: 0 }, `managed_runs_begin_failed:${beginError.message}`);
173064
+ const leaseOutcome = await acquireIndexingLease({
173065
+ jobId: job.jobId,
173066
+ projectId: finalProjectId
173067
+ });
173068
+ if (leaseOutcome.status === "busy") {
173069
+ return {
173070
+ success: false,
173071
+ error: `indexing_busy:${leaseOutcome.activeRunId}`,
173072
+ data: {
173073
+ jobId: job.jobId,
173074
+ projectId: finalProjectId,
173075
+ status: "busy",
173076
+ activeRunId: leaseOutcome.activeRunId,
173077
+ leaseExpiresAt: leaseOutcome.leaseExpiresAt,
173078
+ message: "Another indexing run is active for this project. Poll get_index_status(activeRunId)."
173079
+ }
173080
+ };
173081
+ }
173082
+ if (leaseOutcome.status === "failed") {
172295
173083
  return {
172296
173084
  success: false,
172297
- error: `Failed to acquire indexing lease: ${beginError.message}`
173085
+ error: `Failed to acquire indexing lease: ${leaseOutcome.message}`
172298
173086
  };
172299
173087
  }
172300
- this.executeIndexing(job.jobId, finalProjectId, canonicalProjectPath, forceReindex, warmCache, warmupQueries, include_tests, lease).catch((error51) => {
173088
+ const lease = leaseOutcome.lease;
173089
+ executeIndexing({
173090
+ jobId: job.jobId,
173091
+ projectId: finalProjectId,
173092
+ projectPath: canonicalProjectPath,
173093
+ forceReindex,
173094
+ warmCache,
173095
+ warmupQueries,
173096
+ include_tests,
173097
+ managedRunLease: lease,
173098
+ warmupCache: this.contextualSearch.warmupCache.bind(this.contextualSearch)
173099
+ }).catch((error51) => {
172301
173100
  logger.error("Background indexing failed", error51, {
172302
173101
  jobId: job.jobId
172303
173102
  });
@@ -172324,68 +173123,6 @@ class IndexProjectTool {
172324
173123
  };
172325
173124
  }
172326
173125
  }
172327
- async executeIndexing(jobId, projectId, projectPath, forceReindex, warmCache, warmupQueries, include_tests = false, managedRunLease) {
172328
- const startTime = Date.now();
172329
- try {
172330
- indexJobTracker.updateStatus(jobId, "running");
172331
- logger.info("Starting project indexing via ETL Pipeline", {
172332
- jobId,
172333
- projectPath,
172334
- projectId,
172335
- forceReindex,
172336
- warmCache,
172337
- include_tests
172338
- });
172339
- const etlResult = await EtlPipeline.getInstance().run({
172340
- projectId,
172341
- projectPath,
172342
- jobId,
172343
- forceReindex,
172344
- include_tests,
172345
- managedRunLease
172346
- });
172347
- const duration3 = Date.now() - startTime;
172348
- logger.info("ETL Pipeline completed", {
172349
- jobId,
172350
- projectId,
172351
- duration: duration3,
172352
- filesIndexed: etlResult.filesIndexed,
172353
- filesSkipped: etlResult.filesSkipped,
172354
- chunksIndexed: etlResult.chunksIndexed,
172355
- symbolsIndexed: etlResult.symbolsIndexed,
172356
- errors: etlResult.errors,
172357
- stageTimings: etlResult.stageTimings
172358
- });
172359
- if (warmCache) {
172360
- logger.info("Starting cache warmup", { jobId, projectId });
172361
- const warmupStats = await this.contextualSearch.warmupCache(projectId, projectPath, warmupQueries);
172362
- logger.info("Cache warmup completed", { jobId, projectId, ...warmupStats });
172363
- }
172364
- indexJobTracker.updateProgress(jobId, etlResult.filesIndexed, etlResult.filesIndexed);
172365
- await indexJobTracker.setResultAndFlush(jobId, {
172366
- filesIndexed: etlResult.filesIndexed,
172367
- chunksIndexed: etlResult.chunksIndexed,
172368
- errors: etlResult.errors,
172369
- duration: duration3,
172370
- activatedGraphGenerationId: etlResult.activatedGraphGenerationId,
172371
- parserDiagnostics: etlResult.parserDiagnostics
172372
- });
172373
- } catch (error51) {
172374
- const duration3 = Date.now() - startTime;
172375
- logger.error("Project indexing failed", error51, {
172376
- jobId,
172377
- projectPath,
172378
- projectId,
172379
- duration: duration3
172380
- });
172381
- indexJobTracker.setResult(jobId, {
172382
- filesIndexed: 0,
172383
- chunksIndexed: 0,
172384
- errors: 1,
172385
- duration: duration3
172386
- }, error51.message);
172387
- }
172388
- }
172389
173126
  }
172390
173127
  // ../../packages/core/dist/tools/get_index_status.js
172391
173128
  init_index_job_tracker();
@@ -172864,17 +173601,17 @@ function applyReplacer(root, replacer) {
172864
173601
  return transformChildren(root, replacer, []);
172865
173602
  return transformChildren(normalizeValue(replacedRoot), replacer, []);
172866
173603
  }
172867
- function transformChildren(value, replacer, path20) {
173604
+ function transformChildren(value, replacer, path21) {
172868
173605
  if (isJsonObject(value))
172869
- return transformObject(value, replacer, path20);
173606
+ return transformObject(value, replacer, path21);
172870
173607
  if (isJsonArray(value))
172871
- return transformArray(value, replacer, path20);
173608
+ return transformArray(value, replacer, path21);
172872
173609
  return value;
172873
173610
  }
172874
- function transformObject(obj, replacer, path20) {
173611
+ function transformObject(obj, replacer, path21) {
172875
173612
  const result = {};
172876
173613
  for (const [key, value] of Object.entries(obj)) {
172877
- const childPath = [...path20, key];
173614
+ const childPath = [...path21, key];
172878
173615
  const replacedValue = replacer(key, value, childPath);
172879
173616
  if (replacedValue === undefined)
172880
173617
  continue;
@@ -172882,11 +173619,11 @@ function transformObject(obj, replacer, path20) {
172882
173619
  }
172883
173620
  return result;
172884
173621
  }
172885
- function transformArray(arr, replacer, path20) {
173622
+ function transformArray(arr, replacer, path21) {
172886
173623
  const result = [];
172887
173624
  for (let i = 0;i < arr.length; i++) {
172888
173625
  const value = arr[i];
172889
- const childPath = [...path20, i];
173626
+ const childPath = [...path21, i];
172890
173627
  const replacedValue = replacer(String(i), value, childPath);
172891
173628
  if (replacedValue === undefined)
172892
173629
  continue;
@@ -173418,438 +174155,7 @@ class GetAnalyticsTool {
173418
174155
  }
173419
174156
  // ../../packages/core/dist/tools/get_optimized_context.js
173420
174157
  init_dist();
173421
-
173422
- // ../../packages/core/dist/controllers/context-controller.js
173423
- init_dist();
173424
- init_search_controller();
173425
- init_memory_controller();
173426
-
173427
- // ../../packages/core/dist/tools/compress_context.js
173428
- init_code_compressor();
173429
- init_dist();
173430
- init_dist();
173431
- init_enum_validation();
173432
-
173433
- class CompressContextTool {
173434
- name = "compress_context";
173435
- description = "Compress context using semantic compression (keeps structure, removes details)";
173436
- inputSchema = {
173437
- type: "object",
173438
- properties: {
173439
- content: {
173440
- type: "string",
173441
- description: "Content to compress"
173442
- },
173443
- strategy: {
173444
- type: "string",
173445
- enum: [
173446
- "code_structure",
173447
- "conversation_summary",
173448
- "semantic_dedup",
173449
- "hierarchical"
173450
- ],
173451
- description: "Compression strategy",
173452
- default: "code_structure"
173453
- },
173454
- language: {
173455
- type: "string",
173456
- description: "Programming language (for code compression)"
173457
- },
173458
- targetRatio: {
173459
- type: "number",
173460
- description: "Target compression ratio (0-1, e.g., 0.7 = 70% reduction)",
173461
- default: 0.7
173462
- }
173463
- },
173464
- required: ["content"]
173465
- };
173466
- compressor;
173467
- constructor() {
173468
- this.compressor = new CodeCompressor;
173469
- }
173470
- async handle(params) {
173471
- const { content, language, targetRatio = 0.7 } = params;
173472
- const strategy = validateEnum("strategy", params.strategy ?? "code_structure", [
173473
- "code_structure",
173474
- "conversation_summary",
173475
- "semantic_dedup",
173476
- "hierarchical"
173477
- ]);
173478
- try {
173479
- const originalTokens = estimateTokens(content, language || "code");
173480
- logger.info("Compressing context", {
173481
- originalTokens,
173482
- strategy,
173483
- targetRatio
173484
- });
173485
- const result = await this.compressor.compress(content, strategy);
173486
- const compressedTokens = estimateTokens(result.compressed, language || "code");
173487
- const actualRatio = 1 - compressedTokens / originalTokens;
173488
- const tokensSaved = originalTokens - compressedTokens;
173489
- logger.info("Context compressed", {
173490
- originalTokens,
173491
- compressedTokens,
173492
- tokensSaved,
173493
- actualRatio: actualRatio.toFixed(2),
173494
- targetRatio
173495
- });
173496
- return {
173497
- success: true,
173498
- data: {
173499
- compressed: result.compressed,
173500
- originalLength: content.length,
173501
- compressedLength: result.compressed.length,
173502
- originalTokens,
173503
- compressedTokens,
173504
- strategy
173505
- },
173506
- metadata: {
173507
- tokensSaved,
173508
- compressionRatio: actualRatio
173509
- }
173510
- };
173511
- } catch (error51) {
173512
- logger.error("Failed to compress context", error51, {
173513
- strategy,
173514
- contentLength: typeof content === "string" ? content.length : 0
173515
- });
173516
- return {
173517
- success: false,
173518
- error: `Failed to compress context: ${error51.message}`
173519
- };
173520
- }
173521
- }
173522
- }
173523
-
173524
- // ../../packages/core/dist/controllers/context-controller.js
173525
- init_session_file_cache();
173526
- init_symbol_graph_service();
173527
- init_token_metrics();
173528
-
173529
- class ContextController {
173530
- static instance = null;
173531
- searchCtrl;
173532
- memoryCtrl;
173533
- compressor;
173534
- sessionCache;
173535
- constructor() {
173536
- this.searchCtrl = SearchController.getInstance();
173537
- this.memoryCtrl = MemoryController.getInstance();
173538
- this.compressor = new CompressContextTool;
173539
- this.sessionCache = SessionFileCache.getInstance();
173540
- }
173541
- static getInstance() {
173542
- if (!ContextController.instance) {
173543
- ContextController.instance = new ContextController;
173544
- }
173545
- return ContextController.instance;
173546
- }
173547
- async getOptimizedContext(input) {
173548
- const { query, projectId, projectPath: projectPath2, maxTokens = 4000, maxResults = 5, workingMemoryBudget, userId, sessionId, includeMemories = true, memoryBudgetRatio = 0.2 } = input;
173549
- const clampedRatio = Math.max(0, Math.min(0.5, memoryBudgetRatio));
173550
- const memoryTokenBudget = includeMemories ? Math.floor(maxTokens * clampedRatio) : 0;
173551
- const codeTokenBudget = maxTokens - memoryTokenBudget;
173552
- const wmBudget = workingMemoryBudget || Math.floor(codeTokenBudget * 0.8);
173553
- logger.info("Getting optimized context", {
173554
- query: query.slice(0, 50),
173555
- projectId,
173556
- maxTokens,
173557
- includeMemories,
173558
- memoryTokenBudget,
173559
- codeTokenBudget,
173560
- workingMemoryBudget: wmBudget
173561
- });
173562
- let graphContextSection = "";
173563
- let graphBoostFiles = [];
173564
- if (projectId && await symbolGraphService.hasData(projectId) && looksLikeSymbol(query)) {
173565
- try {
173566
- const [defs, refs] = await Promise.all([
173567
- symbolGraphService.goToDefinition(projectId, query),
173568
- symbolGraphService.getReferences(projectId, query)
173569
- ]);
173570
- if (defs.length > 0) {
173571
- const graphTokenBudget = Math.floor(codeTokenBudget * 0.2);
173572
- graphContextSection = formatGraphContext(defs, refs, graphTokenBudget);
173573
- graphBoostFiles = [
173574
- ...new Set([
173575
- ...defs.map((d) => d.file),
173576
- ...refs.slice(0, 10).map((r2) => r2.fromFile)
173577
- ])
173578
- ];
173579
- logger.debug("Graph prefilter hit", {
173580
- query,
173581
- defs: defs.length,
173582
- refs: refs.length,
173583
- boostFiles: graphBoostFiles.length
173584
- });
173585
- }
173586
- } catch (err) {
173587
- logger.warn("Graph prefilter failed", { query, error: err.message });
173588
- }
173589
- }
173590
- const [searchResult, memories] = await Promise.all([
173591
- this.searchCtrl.searchProject({
173592
- query,
173593
- projectId,
173594
- projectPath: projectPath2,
173595
- maxResults,
173596
- responseMode: "full",
173597
- autoReindex: false,
173598
- minScore: 0.4,
173599
- boostFiles: graphBoostFiles.length > 0 ? graphBoostFiles : undefined
173600
- }),
173601
- includeMemories ? this.searchMemoriesSafe(query, {
173602
- projectId,
173603
- userId,
173604
- sessionId,
173605
- limit: 5
173606
- }) : Promise.resolve([])
173607
- ]);
173608
- const codeResults = searchResult.results;
173609
- const workingSet = this.selectWorkingSet(codeResults, wmBudget);
173610
- const memorySection = this.formatMemorySection(memories, memoryTokenBudget);
173611
- if (workingSet.length === 0 && memories.length === 0) {
173612
- return {
173613
- context: `No relevant code or memories found for query: "${query}"`,
173614
- sources: [],
173615
- resultsCount: 0,
173616
- memoriesCount: 0,
173617
- tokensSaved: 0,
173618
- compressionRatio: 0,
173619
- sessionCacheHits: 0,
173620
- tokensSavedBySessionCache: 0
173621
- };
173622
- }
173623
- let sessionCacheHits = 0;
173624
- let tokensSavedBySessionCache = 0;
173625
- const deliveryPlan = workingSet.map((r2) => {
173626
- if (!sessionId) {
173627
- return { result: r2, kind: "full", tokensSaved: 0 };
173628
- }
173629
- const content = r2.content || r2.preview || "";
173630
- const key = this.sessionCache.chunkKey(r2.filePath || "unknown", r2.lineStart ?? 0, r2.lineEnd ?? 0);
173631
- const check3 = this.sessionCache.check(sessionId, key, content);
173632
- if (check3.status === "unchanged") {
173633
- sessionCacheHits++;
173634
- tokensSavedBySessionCache += check3.tokensSaved;
173635
- return { result: r2, kind: "ref", tokensSaved: check3.tokensSaved };
173636
- }
173637
- if (check3.status === "changed" && check3.diff !== undefined) {
173638
- sessionCacheHits++;
173639
- tokensSavedBySessionCache += check3.tokensSaved;
173640
- return { result: r2, kind: "diff", diff: check3.diff, tokensSaved: check3.tokensSaved };
173641
- }
173642
- return { result: r2, kind: "full", tokensSaved: 0 };
173643
- });
173644
- const parts = [`# Context for: ${query}
173645
- `];
173646
- if (graphContextSection) {
173647
- parts.push(graphContextSection, "");
173648
- }
173649
- if (memorySection) {
173650
- parts.push(memorySection, "");
173651
- }
173652
- if (deliveryPlan.length > 0) {
173653
- const fullCount = deliveryPlan.filter((d) => d.kind === "full").length;
173654
- const refCount = deliveryPlan.filter((d) => d.kind === "ref").length;
173655
- const diffCount = deliveryPlan.filter((d) => d.kind === "diff").length;
173656
- parts.push(`## Code (${deliveryPlan.length} sections \u2014 ${fullCount} full, ${refCount} cached, ${diffCount} diff | WM budget: ${wmBudget} tokens)
173657
- `);
173658
- deliveryPlan.forEach(({ result: r2, kind, diff }, idx) => {
173659
- const filePath = r2.filePath || "Unknown";
173660
- const scoreLabel = (r2.score * 100).toFixed(1);
173661
- const lineRange = `${r2.lineStart ?? "?"}-${r2.lineEnd ?? "?"}`;
173662
- parts.push(`### ${idx + 1}. ${filePath} (score: ${scoreLabel}%)`);
173663
- parts.push(`Lines ${lineRange}
173664
- `);
173665
- if (kind === "ref") {
173666
- parts.push(`[CACHED: ${filePath}:${lineRange}]
173667
- `);
173668
- } else if (kind === "diff" && diff) {
173669
- parts.push("```diff");
173670
- parts.push(diff);
173671
- parts.push("```\n");
173672
- } else {
173673
- parts.push("```" + (r2.language || ""));
173674
- parts.push(r2.content || r2.preview || "(no content)");
173675
- parts.push("```\n");
173676
- }
173677
- });
173678
- }
173679
- const rawContext = parts.join(`
173680
- `);
173681
- const rawTokens = estimateTokens(rawContext, "code");
173682
- let finalContext = rawContext;
173683
- let compressionRatio = 0;
173684
- let tokensSaved = 0;
173685
- if (rawTokens > maxTokens) {
173686
- logger.info("Context exceeds maxTokens, compressing", {
173687
- rawTokens,
173688
- maxTokens
173689
- });
173690
- const resp = await this.compressor.handle({
173691
- content: rawContext,
173692
- strategy: "code_structure",
173693
- targetRatio: 0.6
173694
- });
173695
- if (resp.success && resp.data) {
173696
- finalContext = resp.data.compressed;
173697
- compressionRatio = resp.metadata?.compressionRatio || 0;
173698
- tokensSaved = resp.metadata?.tokensSaved || 0;
173699
- }
173700
- }
173701
- const finalTokens = estimateTokens(finalContext, "code");
173702
- const totalTokensSaved = rawTokens - finalTokens;
173703
- const compressionSavings = tokensSaved;
173704
- TokenMetrics.getInstance().recordContextRequest(rawTokens, finalTokens, tokensSavedBySessionCache, compressionSavings);
173705
- logger.info("Optimized context retrieved", {
173706
- rawTokens,
173707
- finalTokens,
173708
- tokensSaved: totalTokensSaved,
173709
- compressionRatio,
173710
- codeSources: workingSet.length,
173711
- memoriesIncluded: memories.length,
173712
- wmBudget,
173713
- sessionCacheHits,
173714
- tokensSavedBySessionCache
173715
- });
173716
- return {
173717
- context: finalContext,
173718
- sources: workingSet.map((r2) => r2.filePath || "unknown"),
173719
- resultsCount: workingSet.length,
173720
- memoriesCount: memories.length,
173721
- tokensSaved: totalTokensSaved,
173722
- compressionRatio,
173723
- sessionCacheHits,
173724
- tokensSavedBySessionCache
173725
- };
173726
- }
173727
- async searchMemoriesSafe(query, opts) {
173728
- try {
173729
- const result = await this.memoryCtrl.search({
173730
- query,
173731
- projectId: opts.projectId,
173732
- userId: opts.userId,
173733
- sessionId: opts.sessionId,
173734
- includePersistent: true,
173735
- minImportance: 0.3,
173736
- limit: opts.limit
173737
- });
173738
- return result.memories;
173739
- } catch (error51) {
173740
- logger.warn("Memory search failed, continuing without memories", {
173741
- error: error51.message,
173742
- query: query.slice(0, 30)
173743
- });
173744
- return [];
173745
- }
173746
- }
173747
- formatMemorySection(memories, tokenBudget) {
173748
- if (memories.length === 0 || tokenBudget <= 0)
173749
- return null;
173750
- const parts = [
173751
- `## Relevant Memories (from previous sessions)
173752
- `
173753
- ];
173754
- let usedTokens = estimateTokens(parts[0], "text");
173755
- for (const memory of memories) {
173756
- const typeLabel = (memory.type || "unknown").toUpperCase();
173757
- const score = memory.score ? ` (relevance: ${(memory.score * 100).toFixed(0)}%)` : "";
173758
- const importance = memory.importance ? ` [importance: ${(memory.importance * 100).toFixed(0)}%]` : "";
173759
- const agent = memory.agentId ? ` (by: ${memory.agentId})` : "";
173760
- const entry2 = `- **[${typeLabel}]**${score}${importance}${agent}: ${memory.content}`;
173761
- const entryTokens = estimateTokens(entry2, "text");
173762
- if (usedTokens + entryTokens > tokenBudget)
173763
- break;
173764
- parts.push(entry2);
173765
- usedTokens += entryTokens;
173766
- }
173767
- return parts.length <= 1 ? null : parts.join(`
173768
- `);
173769
- }
173770
- selectWorkingSet(results, tokenBudget) {
173771
- if (!results.length || tokenBudget <= 0)
173772
- return [];
173773
- const selected = [];
173774
- const selectedFiles = new Set;
173775
- let usedTokens = 0;
173776
- const sorted = [...results].sort((a12, b) => (b.score || 0) - (a12.score || 0));
173777
- for (const result of sorted) {
173778
- const filePath = result.filePath || "unknown";
173779
- if (selectedFiles.has(filePath))
173780
- continue;
173781
- const content = result.content || result.preview || "";
173782
- const tokens = estimateTokens(content, "code");
173783
- if (usedTokens + tokens > tokenBudget)
173784
- continue;
173785
- selected.push(result);
173786
- selectedFiles.add(filePath);
173787
- usedTokens += tokens;
173788
- }
173789
- for (const result of sorted) {
173790
- if (selected.includes(result))
173791
- continue;
173792
- const content = result.content || result.preview || "";
173793
- const tokens = estimateTokens(content, "code");
173794
- if (usedTokens + tokens > tokenBudget)
173795
- continue;
173796
- selected.push(result);
173797
- usedTokens += tokens;
173798
- }
173799
- return selected;
173800
- }
173801
- }
173802
- function looksLikeSymbol(query) {
173803
- if (query.length > 80)
173804
- return false;
173805
- const words = query.trim().split(/\s+/);
173806
- if (words.length > 3)
173807
- return false;
173808
- return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(words[0]);
173809
- }
173810
- function formatGraphContext(defs, refs, tokenBudget) {
173811
- const parts = [`## Symbol Graph
173812
- `];
173813
- if (defs.length > 0) {
173814
- parts.push(`### Definition(s)
173815
- `);
173816
- for (const def of defs.slice(0, 3)) {
173817
- parts.push(`- **${def.kind}** \`${def.name}\` \u2192 \`${def.file}\` L${def.lineStart}\u2013${def.lineEnd}`);
173818
- if (def.docComment)
173819
- parts.push(` > ${def.docComment.slice(0, 120)}`);
173820
- if (def.snippet) {
173821
- parts.push(" ```");
173822
- parts.push(def.snippet.split(`
173823
- `).slice(0, 8).join(`
173824
- `));
173825
- parts.push(" ```");
173826
- }
173827
- }
173828
- parts.push("");
173829
- }
173830
- if (refs.length > 0) {
173831
- parts.push(`### References (${refs.length} total)
173832
- `);
173833
- const byFile = new Map;
173834
- for (const r2 of refs.slice(0, 30)) {
173835
- const arr = byFile.get(r2.fromFile) ?? [];
173836
- arr.push(r2.fromLine);
173837
- byFile.set(r2.fromFile, arr);
173838
- }
173839
- for (const [file3, lines] of byFile) {
173840
- parts.push(`- \`${file3}\` L${lines.join(", ")}`);
173841
- }
173842
- parts.push("");
173843
- }
173844
- const section = parts.join(`
173845
- `);
173846
- const charBudget = tokenBudget * 4;
173847
- return section.length > charBudget ? section.slice(0, charBudget) + `
173848
- ...
173849
- ` : section;
173850
- }
173851
-
173852
- // ../../packages/core/dist/tools/get_optimized_context.js
174158
+ init_context_controller();
173853
174159
  class GetOptimizedContextTool {
173854
174160
  name = "get_optimized_context";
173855
174161
  description = "Retrieve code context + persistent memories with maximum token efficiency (search + memories + compress)";
@@ -173949,6 +174255,86 @@ class GetOptimizedContextTool {
173949
174255
  }
173950
174256
  }
173951
174257
  }
174258
+ // ../../packages/core/dist/tools/compress_context.js
174259
+ init_code_compressor();
174260
+ init_compress_with_metrics();
174261
+ init_dist();
174262
+ init_enum_validation();
174263
+
174264
+ class CompressContextTool {
174265
+ name = "compress_context";
174266
+ description = "Compress context using semantic compression (keeps structure, removes details)";
174267
+ inputSchema = {
174268
+ type: "object",
174269
+ properties: {
174270
+ content: {
174271
+ type: "string",
174272
+ description: "Content to compress"
174273
+ },
174274
+ strategy: {
174275
+ type: "string",
174276
+ enum: [
174277
+ "code_structure",
174278
+ "conversation_summary",
174279
+ "semantic_dedup",
174280
+ "hierarchical"
174281
+ ],
174282
+ description: "Compression strategy",
174283
+ default: "code_structure"
174284
+ },
174285
+ language: {
174286
+ type: "string",
174287
+ description: "Programming language (for code compression)"
174288
+ },
174289
+ targetRatio: {
174290
+ type: "number",
174291
+ description: "Target compression ratio (0-1, e.g., 0.7 = 70% reduction)",
174292
+ default: 0.7
174293
+ }
174294
+ },
174295
+ required: ["content"]
174296
+ };
174297
+ compressor;
174298
+ constructor() {
174299
+ this.compressor = new CodeCompressor;
174300
+ }
174301
+ async handle(params) {
174302
+ const { content, language, targetRatio = 0.7 } = params;
174303
+ const strategy = validateEnum("strategy", params.strategy ?? "code_structure", [
174304
+ "code_structure",
174305
+ "conversation_summary",
174306
+ "semantic_dedup",
174307
+ "hierarchical"
174308
+ ]);
174309
+ try {
174310
+ const metrics2 = await compressWithMetrics(this.compressor, content, strategy, { language, targetRatio });
174311
+ return {
174312
+ success: true,
174313
+ data: {
174314
+ compressed: metrics2.compressed,
174315
+ originalLength: content.length,
174316
+ compressedLength: metrics2.compressed.length,
174317
+ originalTokens: metrics2.originalTokens,
174318
+ compressedTokens: metrics2.compressedTokens,
174319
+ strategy
174320
+ },
174321
+ metadata: {
174322
+ tokensSaved: metrics2.tokensSaved,
174323
+ compressionRatio: metrics2.compressionRatio
174324
+ }
174325
+ };
174326
+ } catch (error51) {
174327
+ logger.error("Failed to compress context", error51, {
174328
+ strategy,
174329
+ contentLength: typeof content === "string" ? content.length : 0
174330
+ });
174331
+ return {
174332
+ success: false,
174333
+ error: `Failed to compress context: ${error51.message}`
174334
+ };
174335
+ }
174336
+ }
174337
+ }
173952
174338
  // ../../packages/core/dist/tools/store_memory.js
173953
174339
  init_dist();
173954
174340
  init_memory_controller();
@@ -174619,7 +175005,7 @@ init_db_connection();
174619
175005
  init_alias_resolver();
174620
175006
  import fs10 from "fs";
174621
175007
  import os3 from "os";
174622
- import path20 from "path";
175008
+ import path21 from "path";
174623
175009
 
174624
175010
  // ../../packages/core/dist/services/hooks/session-pin-store.js
174625
175011
  var DEFAULT_MAX_SIZE = 1000;
@@ -174721,7 +175107,7 @@ class AttributionResolver {
174721
175107
  this.pins = options.pins ?? new SessionPinStore;
174722
175108
  this.canonicalize = options.canonicalize ?? defaultCanonicalize;
174723
175109
  this.homedir = options.homedir ?? os3.homedir;
174724
- this.fsRoot = options.fsRoot ?? (() => path20.parse(path20.sep).root);
175110
+ this.fsRoot = options.fsRoot ?? (() => path21.parse(path21.sep).root);
174725
175111
  }
174726
175112
  async resolve(input) {
174727
175113
  const caller = input.callerProjectId;
@@ -174774,7 +175160,7 @@ class AttributionResolver {
174774
175160
  }
174775
175161
  let bestPath = null;
174776
175162
  for (const candidate2 of byPath.keys()) {
174777
- if (canonicalCwd === candidate2 || canonicalCwd.startsWith(candidate2.endsWith(path20.sep) ? candidate2 : candidate2 + path20.sep)) {
175163
+ if (canonicalCwd === candidate2 || canonicalCwd.startsWith(candidate2.endsWith(path21.sep) ? candidate2 : candidate2 + path21.sep)) {
174778
175164
  if (bestPath === null || candidate2.length > bestPath.length) {
174779
175165
  bestPath = candidate2;
174780
175166
  }
@@ -174797,7 +175183,7 @@ class AttributionResolver {
174797
175183
  return projectPath2;
174798
175184
  const fsRoot = this.fsRoot();
174799
175185
  let normalized = projectPath2;
174800
- while (normalized.length > fsRoot.length && normalized.endsWith(path20.sep)) {
175186
+ while (normalized.length > fsRoot.length && normalized.endsWith(path21.sep)) {
174801
175187
  normalized = normalized.slice(0, -1);
174802
175188
  }
174803
175189
  return normalized;
@@ -174808,7 +175194,7 @@ function defaultCanonicalize(cwd) {
174808
175194
  return fs10.realpathSync(cwd);
174809
175195
  } catch {
174810
175196
  try {
174811
- return path20.resolve(cwd);
175197
+ return path21.resolve(cwd);
174812
175198
  } catch {
174813
175199
  return;
174814
175200
  }
@@ -175329,310 +175715,22 @@ class GetArchitectureTool {
175329
175715
  }
175330
175716
  // ../../packages/core/dist/tools/read_file.js
175331
175717
  init_dist();
175718
+
175719
+ // ../../packages/core/dist/services/file-read/read-file.service.js
175332
175720
  init_dist();
175333
175721
  init_code_compressor();
175334
- init_event_bus();
175335
- init_workspace_manager();
175722
+
175723
+ // ../../packages/core/dist/services/file-read/file-content-cache.js
175724
+ init_dist();
175336
175725
  import fs11 from "fs/promises";
175337
- import path21 from "path";
175338
- var MASSA_AI_READ_FILE_MAX_LINES = (() => {
175339
- const v = Number(process.env.MASSA_AI_READ_FILE_MAX_LINES);
175340
- return Number.isFinite(v) && v > 0 ? Math.floor(v) : 500;
175341
- })();
175342
175726
 
175343
- class ReadFileTool {
175344
- name = "read_file";
175345
- description = "Read file with automatic compression, caching, and symbol metadata. " + "Use with search results for 60% token savings.";
175346
- inputSchema = {
175347
- type: "object",
175348
- properties: {
175349
- filePath: {
175350
- type: "string",
175351
- description: "File path (absolute or relative to project root)"
175352
- },
175353
- projectId: {
175354
- type: "string",
175355
- description: "Project ID for symbol metadata (optional)"
175356
- },
175357
- offset: {
175358
- type: "number",
175359
- description: "Start line number (1-indexed)"
175360
- },
175361
- limit: {
175362
- type: "number",
175363
- description: "Number of lines to read"
175364
- },
175365
- lineStart: {
175366
- type: "number",
175367
- description: "Start line (alternative to offset)"
175368
- },
175369
- lineEnd: {
175370
- type: "number",
175371
- description: "End line (alternative to limit)"
175372
- },
175373
- compress: {
175374
- type: "boolean",
175375
- description: "Auto-compress content > 100 lines (default: true)",
175376
- default: true
175377
- },
175378
- targetRatio: {
175379
- type: "number",
175380
- description: "Compression target ratio (0.3 = 70% reduction)",
175381
- default: 0.3
175382
- },
175383
- format: {
175384
- type: "string",
175385
- enum: ["json", "toon"],
175386
- description: "Output format",
175387
- default: "json"
175388
- },
175389
- fields: {
175390
- type: "array",
175391
- items: { type: "string" },
175392
- description: "Projection \u2014 keep only these keys (dotted paths supported, e.g. ['nodes.symbol']). Absent/empty \u2192 full data."
175393
- },
175394
- includeSymbols: {
175395
- type: "boolean",
175396
- description: "Include symbol metadata from graph (default: true)",
175397
- default: true
175398
- },
175399
- includeImports: {
175400
- type: "boolean",
175401
- description: "Extract and show import statements (default: true)",
175402
- default: true
175403
- }
175404
- },
175405
- required: ["filePath"]
175406
- };
175407
- compressor;
175408
- symbolGraph;
175727
+ class FileContentCache {
175728
+ extractMetadata;
175409
175729
  fileCache = new Map;
175410
- projectRootCache = new Map;
175411
175730
  CACHE_TTL = 60000;
175412
- ROOT_CACHE_TTL = 300000;
175413
175731
  FILE_CACHE_MAX_ENTRIES = 512;
175414
- constructor(symbolGraph) {
175415
- this.compressor = new CodeCompressor;
175416
- this.symbolGraph = symbolGraph;
175417
- eventBus.subscribe("indexing:started", ({ projectId, projectPath: projectPath2 }) => {
175418
- this.projectRootCache.delete(projectId);
175419
- this.evictOldest(this.projectRootCache);
175420
- this.projectRootCache.set(projectId, projectPath2);
175421
- });
175422
- }
175423
- async handle(params) {
175424
- const p = params;
175425
- const shouldCompress = p.compress !== false;
175426
- const targetRatio = p.targetRatio || 0.3;
175427
- const format = p.format || "json";
175428
- const { fields } = p;
175429
- const includeSymbols = p.includeSymbols !== false;
175430
- const includeImports = p.includeImports !== false;
175431
- try {
175432
- const resolved = await this.resolveFilePath(p.filePath, p.projectId);
175433
- if (resolved === null) {
175434
- return {
175435
- success: false,
175436
- error: "Relative filePath requires a projectId (to resolve against the workspace) or an absolute path."
175437
- };
175438
- }
175439
- const filePath = resolved;
175440
- const containment = await this.checkPathContainment(filePath, p.projectId);
175441
- if (!containment.allowed) {
175442
- return {
175443
- success: false,
175444
- error: containment.error
175445
- };
175446
- }
175447
- const relativePath = p.filePath;
175448
- const range = this.calculateRange(p);
175449
- const { content, metadata } = await this.readFileWithCache(filePath, {
175450
- includeSymbols,
175451
- includeImports,
175452
- projectId: p.projectId,
175453
- relativePath
175454
- });
175455
- const lines = content.split(`
175456
- `);
175457
- const totalLines = lines.length;
175458
- const adjustedRange = this.adjustRange(range, totalLines);
175459
- let selectedContent = this.extractLines(lines, adjustedRange);
175460
- let selectedLineCount = selectedContent.split(`
175461
- `).length;
175462
- let source_clipped = false;
175463
- if (selectedLineCount > MASSA_AI_READ_FILE_MAX_LINES) {
175464
- const cappedLines = lines.slice(adjustedRange.start - 1, adjustedRange.start - 1 + MASSA_AI_READ_FILE_MAX_LINES);
175465
- selectedContent = cappedLines.join(`
175466
- `);
175467
- selectedLineCount = selectedContent.split(`
175468
- `).length;
175469
- source_clipped = true;
175470
- }
175471
- const shouldAutoCompress = shouldCompress && selectedLineCount > 100 && targetRatio < 1;
175472
- const result = {
175473
- filePath: p.filePath,
175474
- absolutePath: filePath,
175475
- lineRange: {
175476
- requested: {
175477
- start: range.start,
175478
- end: range.end === Infinity ? null : range.end
175479
- },
175480
- actual: {
175481
- start: adjustedRange.start,
175482
- end: source_clipped ? adjustedRange.start + selectedLineCount - 1 : adjustedRange.end,
175483
- total: totalLines
175484
- },
175485
- selected: selectedLineCount
175486
- },
175487
- source_clipped,
175488
- metadata: {
175489
- totalLines,
175490
- language: metadata.language,
175491
- ...metadata.symbols && { symbols: metadata.symbols },
175492
- ...metadata.imports && { imports: metadata.imports }
175493
- },
175494
- compressed: shouldAutoCompress,
175495
- recommendations: []
175496
- };
175497
- if (shouldAutoCompress) {
175498
- const compressed = await this.compressor.compress(selectedContent, "code_structure");
175499
- const originalTokens = estimateTokens(selectedContent, "code");
175500
- const compressedTokens = estimateTokens(compressed.compressed, "code");
175501
- const actualRatio = compressedTokens / originalTokens;
175502
- result.content = compressed.compressed;
175503
- result.tokens = {
175504
- original: originalTokens,
175505
- compressed: compressedTokens,
175506
- saved: originalTokens - compressedTokens,
175507
- savingsPercent: Math.round((1 - actualRatio) * 100)
175508
- };
175509
- result.compressionRatio = actualRatio;
175510
- result.recommendations.push(`\u2713 Auto-compressed ${selectedLineCount} lines (${result.tokens.savingsPercent}% reduction)`);
175511
- } else {
175512
- result.content = selectedContent;
175513
- result.tokens = {
175514
- original: estimateTokens(selectedContent, "code"),
175515
- compressed: estimateTokens(selectedContent, "code"),
175516
- saved: 0,
175517
- savingsPercent: 0
175518
- };
175519
- if (selectedLineCount > 100) {
175520
- result.recommendations.push("\uD83D\uDCA1 Content > 100 lines. Consider compress=true for token savings");
175521
- }
175522
- }
175523
- if (range.start === 1 && range.end === Infinity) {
175524
- result.recommendations.push("\uD83D\uDCA1 Use lineStart/lineEnd or offset/limit to read specific sections (60% token savings)");
175525
- }
175526
- if (metadata.symbols && metadata.symbols.definitions > 0) {
175527
- result.recommendations.push(`\uD83D\uDCA1 Use get_references() to find usages of ${metadata.symbols.definitions} symbols in this file`);
175528
- }
175529
- return serializeToolResponse(result, { format, fields });
175530
- } catch (error51) {
175531
- logger.error("Failed to read file", error51, {
175532
- filePath: p.filePath
175533
- });
175534
- return {
175535
- success: false,
175536
- error: `Failed to read file: ${error51.message}`
175537
- };
175538
- }
175539
- }
175540
- async resolveFilePath(filePath, projectId) {
175541
- if (path21.isAbsolute(filePath)) {
175542
- return path21.resolve(filePath);
175543
- }
175544
- if (projectId) {
175545
- const root = await this.getProjectRoot(projectId);
175546
- if (root) {
175547
- const cleaned = sanitizeFilePath(filePath);
175548
- return path21.resolve(root, cleaned);
175549
- }
175550
- return null;
175551
- }
175552
- return null;
175553
- }
175554
- async checkPathContainment(absoluteFilePath, projectId) {
175555
- const roots = [];
175556
- if (projectId) {
175557
- const root = await this.getProjectRoot(projectId);
175558
- if (root)
175559
- roots.push(path21.resolve(root));
175560
- }
175561
- roots.push(path21.resolve(process.cwd()));
175562
- const envRoots = (process.env.MASSA_AI_READ_FILE_ROOTS ?? "").split(":").map((s) => s.trim()).filter((s) => s.length > 0);
175563
- for (const extra of envRoots) {
175564
- roots.push(path21.resolve(extra));
175565
- }
175566
- const target = path21.resolve(absoluteFilePath);
175567
- for (const root of roots) {
175568
- const rel = path21.relative(root, target);
175569
- if (rel !== "" && !rel.startsWith("..") && !path21.isAbsolute(rel)) {
175570
- return { allowed: true };
175571
- }
175572
- if (rel === "")
175573
- return { allowed: true };
175574
- }
175575
- const validRootsList = roots.map((r2) => ` - ${r2}`).join(`
175576
- `);
175577
- return {
175578
- allowed: false,
175579
- error: `read_file path containment: "${target}" is outside the allowed roots.
175580
- ` + `Valid roots (project root + cwd + MASSA_AI_READ_FILE_ROOTS):
175581
- ${validRootsList}
175582
- ` + `Provide a filePath that resolves under one of these roots.`
175583
- };
175584
- }
175585
- async getProjectRoot(projectId) {
175586
- const cached2 = this.projectRootCache.get(projectId);
175587
- if (cached2 !== undefined) {
175588
- this.projectRootCache.delete(projectId);
175589
- this.projectRootCache.set(projectId, cached2);
175590
- return cached2;
175591
- }
175592
- try {
175593
- const workspace = await workspaceManager.getWorkspace(projectId);
175594
- if (workspace?.project_path) {
175595
- this.evictOldest(this.projectRootCache);
175596
- this.projectRootCache.set(projectId, workspace.project_path);
175597
- return workspace.project_path;
175598
- }
175599
- } catch (error51) {
175600
- logger.warn("Failed to look up project root", { projectId, error: error51.message });
175601
- }
175602
- return null;
175603
- }
175604
- evictOldest(cache) {
175605
- while (cache.size >= this.FILE_CACHE_MAX_ENTRIES) {
175606
- const oldest = cache.keys().next().value;
175607
- if (oldest === undefined)
175608
- break;
175609
- cache.delete(oldest);
175610
- }
175611
- }
175612
- calculateRange(params) {
175613
- if (params.lineStart !== undefined && params.lineEnd !== undefined) {
175614
- return {
175615
- start: Math.max(1, params.lineStart),
175616
- end: params.lineEnd
175617
- };
175618
- }
175619
- if (params.offset !== undefined) {
175620
- const offset = Math.max(1, params.offset);
175621
- const limit = params.limit || 1000;
175622
- return {
175623
- start: offset,
175624
- end: offset + limit - 1
175625
- };
175626
- }
175627
- return {
175628
- start: 1,
175629
- end: Infinity
175630
- };
175631
- }
175632
- adjustRange(range, totalLines) {
175633
- const start = Math.max(1, Math.min(range.start, totalLines));
175634
- const end = range.end === Infinity ? totalLines : Math.min(range.end, totalLines);
175635
- return { start, end };
175732
+ constructor(extractMetadata) {
175733
+ this.extractMetadata = extractMetadata;
175636
175734
  }
175637
175735
  async readFileWithCache(filePath, options) {
175638
175736
  const cacheKey = JSON.stringify({
@@ -175659,7 +175757,7 @@ ${validRootsList}
175659
175757
  }
175660
175758
  const content = await fs11.readFile(filePath, "utf-8");
175661
175759
  const metadata = await this.extractMetadata(content, filePath, options);
175662
- this.evictOldest(this.fileCache);
175760
+ evictOldest(this.fileCache, this.FILE_CACHE_MAX_ENTRIES - 1);
175663
175761
  this.fileCache.set(cacheKey, {
175664
175762
  content,
175665
175763
  timestamp: Date.now(),
@@ -175668,6 +175766,17 @@ ${validRootsList}
175668
175766
  logger.debug("File read and cached", { filePath });
175669
175767
  return { content, metadata };
175670
175768
  }
175769
+ }
175770
+
175771
+ // ../../packages/core/dist/services/file-read/file-metadata.js
175772
+ init_dist();
175773
+ import path22 from "path";
175774
+
175775
+ class FileMetadataExtractor {
175776
+ symbolGraph;
175777
+ constructor(symbolGraph) {
175778
+ this.symbolGraph = symbolGraph;
175779
+ }
175671
175780
  async extractMetadata(content, filePath, options) {
175672
175781
  const lines = content.split(`
175673
175782
  `);
@@ -175696,18 +175805,8 @@ ${validRootsList}
175696
175805
  }
175697
175806
  return metadata;
175698
175807
  }
175699
- extractLines(lines, range) {
175700
- const start = range.start - 1;
175701
- const end = range.end;
175702
- const selectedLines = lines.slice(start, end);
175703
- return selectedLines.map((line, index) => {
175704
- const lineNum = start + index + 1;
175705
- return `${lineNum.toString().padStart(6, " ")}: ${line}`;
175706
- }).join(`
175707
- `);
175708
- }
175709
175808
  detectLanguage(filePath) {
175710
- const ext2 = path21.extname(filePath).toLowerCase();
175809
+ const ext2 = path22.extname(filePath).toLowerCase();
175711
175810
  const languageMap2 = {
175712
175811
  ".ts": "TypeScript",
175713
175812
  ".tsx": "TypeScript",
@@ -175765,6 +175864,366 @@ ${validRootsList}
175765
175864
  return imports;
175766
175865
  }
175767
175866
  }
175867
+
175868
+ // ../../packages/core/dist/services/file-read/line-range.js
175869
+ var MASSA_AI_READ_FILE_MAX_LINES = (() => {
175870
+ const v = Number(process.env.MASSA_AI_READ_FILE_MAX_LINES);
175871
+ return Number.isFinite(v) && v > 0 ? Math.floor(v) : 500;
175872
+ })();
175873
+ function calculateRange(params) {
175874
+ if (params.lineStart !== undefined && params.lineEnd !== undefined) {
175875
+ return {
175876
+ start: Math.max(1, params.lineStart),
175877
+ end: params.lineEnd
175878
+ };
175879
+ }
175880
+ if (params.offset !== undefined) {
175881
+ const offset = Math.max(1, params.offset);
175882
+ const limit = params.limit || 1000;
175883
+ return {
175884
+ start: offset,
175885
+ end: offset + limit - 1
175886
+ };
175887
+ }
175888
+ return {
175889
+ start: 1,
175890
+ end: Infinity
175891
+ };
175892
+ }
175893
+ function adjustRange(range, totalLines) {
175894
+ const start = Math.max(1, Math.min(range.start, totalLines));
175895
+ const end = range.end === Infinity ? totalLines : Math.min(range.end, totalLines);
175896
+ return { start, end };
175897
+ }
175898
+ function extractLines(lines, range) {
175899
+ const start = range.start - 1;
175900
+ const end = range.end;
175901
+ const selectedLines = lines.slice(start, end);
175902
+ return selectedLines.map((line, index) => {
175903
+ const lineNum = start + index + 1;
175904
+ return `${lineNum.toString().padStart(6, " ")}: ${line}`;
175905
+ }).join(`
175906
+ `);
175907
+ }
175908
+ function selectLines(lines, range) {
175909
+ let content = extractLines(lines, range);
175910
+ let lineCount = content.split(`
175911
+ `).length;
175912
+ let clipped = false;
175913
+ if (lineCount > MASSA_AI_READ_FILE_MAX_LINES) {
175914
+ const cappedLines = lines.slice(range.start - 1, range.start - 1 + MASSA_AI_READ_FILE_MAX_LINES);
175915
+ content = cappedLines.join(`
175916
+ `);
175917
+ lineCount = content.split(`
175918
+ `).length;
175919
+ clipped = true;
175920
+ }
175921
+ return { content, lineCount, clipped };
175922
+ }
175923
+
175924
+ // ../../packages/core/dist/services/file-read/path-containment.js
175925
+ init_dist();
175926
+ import path23 from "path";
175927
+
175928
+ class PathContainment {
175929
+ projectRoots;
175930
+ constructor(projectRoots) {
175931
+ this.projectRoots = projectRoots;
175932
+ }
175933
+ async resolveFilePath(filePath, projectId) {
175934
+ if (path23.isAbsolute(filePath)) {
175935
+ return path23.resolve(filePath);
175936
+ }
175937
+ if (projectId) {
175938
+ const root = await this.projectRoots.getProjectRoot(projectId);
175939
+ if (root) {
175940
+ const cleaned = sanitizeFilePath(filePath);
175941
+ return path23.resolve(root, cleaned);
175942
+ }
175943
+ return null;
175944
+ }
175945
+ return null;
175946
+ }
175947
+ async checkPathContainment(absoluteFilePath, projectId) {
175948
+ const roots = [];
175949
+ if (projectId) {
175950
+ const root = await this.projectRoots.getProjectRoot(projectId);
175951
+ if (root)
175952
+ roots.push(path23.resolve(root));
175953
+ }
175954
+ roots.push(path23.resolve(process.cwd()));
175955
+ const envRoots = (process.env.MASSA_AI_READ_FILE_ROOTS ?? "").split(":").map((s) => s.trim()).filter((s) => s.length > 0);
175956
+ for (const extra of envRoots) {
175957
+ roots.push(path23.resolve(extra));
175958
+ }
175959
+ const target = path23.resolve(absoluteFilePath);
175960
+ for (const root of roots) {
175961
+ const rel = path23.relative(root, target);
175962
+ if (rel !== "" && !rel.startsWith("..") && !path23.isAbsolute(rel)) {
175963
+ return { allowed: true };
175964
+ }
175965
+ if (rel === "")
175966
+ return { allowed: true };
175967
+ }
175968
+ const validRootsList = roots.map((r2) => ` - ${r2}`).join(`
175969
+ `);
175970
+ return {
175971
+ allowed: false,
175972
+ error: `read_file path containment: "${target}" is outside the allowed roots.
175973
+ ` + `Valid roots (project root + cwd + MASSA_AI_READ_FILE_ROOTS):
175974
+ ${validRootsList}
175975
+ ` + `Provide a filePath that resolves under one of these roots.`
175976
+ };
175977
+ }
175978
+ }
175979
+
175980
+ // ../../packages/core/dist/services/file-read/project-root-cache.js
175981
+ init_dist();
175982
+ init_event_bus();
175983
+ init_workspace_manager();
175984
+
175985
+ class ProjectRootCache {
175986
+ projectRootCache = new Map;
175987
+ ROOT_CACHE_TTL = 300000;
175988
+ PROJECT_ROOT_CACHE_MAX_ENTRIES = 512;
175989
+ constructor() {
175990
+ eventBus.subscribe("indexing:started", ({ projectId, projectPath: projectPath2 }) => {
175991
+ this.projectRootCache.delete(projectId);
175992
+ evictOldest(this.projectRootCache, this.PROJECT_ROOT_CACHE_MAX_ENTRIES - 1);
175993
+ this.projectRootCache.set(projectId, projectPath2);
175994
+ });
175995
+ }
175996
+ async getProjectRoot(projectId) {
175997
+ const cached2 = this.projectRootCache.get(projectId);
175998
+ if (cached2 !== undefined) {
175999
+ this.projectRootCache.delete(projectId);
176000
+ this.projectRootCache.set(projectId, cached2);
176001
+ return cached2;
176002
+ }
176003
+ try {
176004
+ const workspace = await workspaceManager.getWorkspace(projectId);
176005
+ if (workspace?.project_path) {
176006
+ evictOldest(this.projectRootCache, this.PROJECT_ROOT_CACHE_MAX_ENTRIES - 1);
176007
+ this.projectRootCache.set(projectId, workspace.project_path);
176008
+ return workspace.project_path;
176009
+ }
176010
+ } catch (error51) {
176011
+ logger.warn("Failed to look up project root", { projectId, error: error51.message });
176012
+ }
176013
+ return null;
176014
+ }
176015
+ }
176016
+
176017
+ // ../../packages/core/dist/services/file-read/read-file.service.js
176018
+ function readFileOptions(p) {
176019
+ const shouldCompress = p.compress !== false;
176020
+ const targetRatio = p.targetRatio || 0.3;
176021
+ const format = p.format || "json";
176022
+ const { fields } = p;
176023
+ const includeSymbols = p.includeSymbols !== false;
176024
+ const includeImports = p.includeImports !== false;
176025
+ return { shouldCompress, targetRatio, format, fields, includeSymbols, includeImports };
176026
+ }
176027
+
176028
+ class ReadFileService {
176029
+ compressor;
176030
+ symbolGraph;
176031
+ projectRoots;
176032
+ pathContainment;
176033
+ fileMetadata;
176034
+ fileContent;
176035
+ constructor(symbolGraph) {
176036
+ this.compressor = new CodeCompressor;
176037
+ this.symbolGraph = symbolGraph;
176038
+ this.projectRoots = new ProjectRootCache;
176039
+ this.pathContainment = new PathContainment(this.projectRoots);
176040
+ this.fileMetadata = new FileMetadataExtractor(symbolGraph);
176041
+ this.fileContent = new FileContentCache((content, filePath, options) => this.fileMetadata.extractMetadata(content, filePath, options));
176042
+ }
176043
+ async read(p, options) {
176044
+ const { shouldCompress, targetRatio, includeSymbols, includeImports } = options;
176045
+ const resolved = await this.pathContainment.resolveFilePath(p.filePath, p.projectId);
176046
+ if (resolved === null) {
176047
+ return {
176048
+ ok: false,
176049
+ error: "Relative filePath requires a projectId (to resolve against the workspace) or an absolute path."
176050
+ };
176051
+ }
176052
+ const filePath = resolved;
176053
+ const containment = await this.pathContainment.checkPathContainment(filePath, p.projectId);
176054
+ if (!containment.allowed) {
176055
+ return {
176056
+ ok: false,
176057
+ error: containment.error
176058
+ };
176059
+ }
176060
+ const relativePath = p.filePath;
176061
+ const range = calculateRange(p);
176062
+ const { content, metadata } = await this.fileContent.readFileWithCache(filePath, {
176063
+ includeSymbols,
176064
+ includeImports,
176065
+ projectId: p.projectId,
176066
+ relativePath
176067
+ });
176068
+ const lines = content.split(`
176069
+ `);
176070
+ const totalLines = lines.length;
176071
+ const adjustedRange = adjustRange(range, totalLines);
176072
+ const { content: selectedContent, lineCount: selectedLineCount, clipped: source_clipped } = selectLines(lines, adjustedRange);
176073
+ const shouldAutoCompress = shouldCompress && selectedLineCount > 100 && targetRatio < 1;
176074
+ const result = {
176075
+ filePath: p.filePath,
176076
+ absolutePath: filePath,
176077
+ lineRange: {
176078
+ requested: {
176079
+ start: range.start,
176080
+ end: range.end === Infinity ? null : range.end
176081
+ },
176082
+ actual: {
176083
+ start: adjustedRange.start,
176084
+ end: source_clipped ? adjustedRange.start + selectedLineCount - 1 : adjustedRange.end,
176085
+ total: totalLines
176086
+ },
176087
+ selected: selectedLineCount
176088
+ },
176089
+ source_clipped,
176090
+ metadata: {
176091
+ totalLines,
176092
+ language: metadata.language,
176093
+ ...metadata.symbols && { symbols: metadata.symbols },
176094
+ ...metadata.imports && { imports: metadata.imports }
176095
+ },
176096
+ compressed: shouldAutoCompress,
176097
+ recommendations: []
176098
+ };
176099
+ if (shouldAutoCompress) {
176100
+ const compressed = await this.compressor.compress(selectedContent, "code_structure");
176101
+ const originalTokens = estimateTokens(selectedContent, "code");
176102
+ const compressedTokens = estimateTokens(compressed.compressed, "code");
176103
+ const actualRatio = compressedTokens / originalTokens;
176104
+ result.content = compressed.compressed;
176105
+ result.tokens = {
176106
+ original: originalTokens,
176107
+ compressed: compressedTokens,
176108
+ saved: originalTokens - compressedTokens,
176109
+ savingsPercent: Math.round((1 - actualRatio) * 100)
176110
+ };
176111
+ result.compressionRatio = actualRatio;
176112
+ result.recommendations.push(`\u2713 Auto-compressed ${selectedLineCount} lines (${result.tokens.savingsPercent}% reduction)`);
176113
+ } else {
176114
+ result.content = selectedContent;
176115
+ result.tokens = {
176116
+ original: estimateTokens(selectedContent, "code"),
176117
+ compressed: estimateTokens(selectedContent, "code"),
176118
+ saved: 0,
176119
+ savingsPercent: 0
176120
+ };
176121
+ if (selectedLineCount > 100) {
176122
+ result.recommendations.push("\uD83D\uDCA1 Content > 100 lines. Consider compress=true for token savings");
176123
+ }
176124
+ }
176125
+ if (range.start === 1 && range.end === Infinity) {
176126
+ result.recommendations.push("\uD83D\uDCA1 Use lineStart/lineEnd or offset/limit to read specific sections (60% token savings)");
176127
+ }
176128
+ if (metadata.symbols && metadata.symbols.definitions > 0) {
176129
+ result.recommendations.push(`\uD83D\uDCA1 Use get_references() to find usages of ${metadata.symbols.definitions} symbols in this file`);
176130
+ }
176131
+ return { ok: true, data: result };
176132
+ }
176133
+ }
176134
+
176135
+ // ../../packages/core/dist/tools/read_file.js
176136
+ class ReadFileTool {
176137
+ name = "read_file";
176138
+ description = "Read file with automatic compression, caching, and symbol metadata. " + "Use with search results for 60% token savings.";
176139
+ inputSchema = {
176140
+ type: "object",
176141
+ properties: {
176142
+ filePath: {
176143
+ type: "string",
176144
+ description: "File path (absolute or relative to project root)"
176145
+ },
176146
+ projectId: {
176147
+ type: "string",
176148
+ description: "Project ID for symbol metadata (optional)"
176149
+ },
176150
+ offset: {
176151
+ type: "number",
176152
+ description: "Start line number (1-indexed)"
176153
+ },
176154
+ limit: {
176155
+ type: "number",
176156
+ description: "Number of lines to read"
176157
+ },
176158
+ lineStart: {
176159
+ type: "number",
176160
+ description: "Start line (alternative to offset)"
176161
+ },
176162
+ lineEnd: {
176163
+ type: "number",
176164
+ description: "End line (alternative to limit)"
176165
+ },
176166
+ compress: {
176167
+ type: "boolean",
176168
+ description: "Auto-compress content > 100 lines (default: true)",
176169
+ default: true
176170
+ },
176171
+ targetRatio: {
176172
+ type: "number",
176173
+ description: "Compression target ratio (0.3 = 70% reduction)",
176174
+ default: 0.3
176175
+ },
176176
+ format: {
176177
+ type: "string",
176178
+ enum: ["json", "toon"],
176179
+ description: "Output format",
176180
+ default: "json"
176181
+ },
176182
+ fields: {
176183
+ type: "array",
176184
+ items: { type: "string" },
176185
+ description: "Projection \u2014 keep only these keys (dotted paths supported, e.g. ['nodes.symbol']). Absent/empty \u2192 full data."
176186
+ },
176187
+ includeSymbols: {
176188
+ type: "boolean",
176189
+ description: "Include symbol metadata from graph (default: true)",
176190
+ default: true
176191
+ },
176192
+ includeImports: {
176193
+ type: "boolean",
176194
+ description: "Extract and show import statements (default: true)",
176195
+ default: true
176196
+ }
176197
+ },
176198
+ required: ["filePath"]
176199
+ };
176200
+ service;
176201
+ constructor(symbolGraph) {
176202
+ this.service = new ReadFileService(symbolGraph);
176203
+ }
176204
+ async handle(params) {
176205
+ const p = params;
176206
+ const options = readFileOptions(p);
176207
+ try {
176208
+ const outcome2 = await this.service.read(p, options);
176209
+ if (!outcome2.ok) {
176210
+ return { success: false, error: outcome2.error };
176211
+ }
176212
+ return serializeToolResponse(outcome2.data, {
176213
+ format: options.format,
176214
+ fields: options.fields
176215
+ });
176216
+ } catch (error51) {
176217
+ logger.error("Failed to read file", error51, {
176218
+ filePath: p.filePath
176219
+ });
176220
+ return {
176221
+ success: false,
176222
+ error: `Failed to read file: ${error51.message}`
176223
+ };
176224
+ }
176225
+ }
176226
+ }
175768
176227
  // ../../packages/core/dist/tools/execute.js
175769
176228
  class ExecuteTool {
175770
176229
  name = "execute";
@@ -175963,331 +176422,12 @@ class FetchAndIndexTool {
175963
176422
  return this.run(params);
175964
176423
  }
175965
176424
  }
175966
- // ../../packages/core/dist/controllers/index.js
175967
- init_memory_controller();
175968
- init_search_controller();
175969
-
175970
- // ../../packages/core/dist/controllers/executor-controller.js
175971
- init_dist();
175972
- init_executor2();
175973
- init_enum_validation();
175974
- import { cpus as cpus2 } from "os";
175975
- var EXECUTOR_LANGUAGES = [
175976
- "javascript",
175977
- "typescript",
175978
- "python",
175979
- "shell",
175980
- "ruby",
175981
- "go",
175982
- "rust",
175983
- "php",
175984
- "perl",
175985
- "r"
175986
- ];
175987
- var MAX_BATCH_COMMANDS = 256;
175988
- function applyIntent(result, intent) {
175989
- if (!intent || !result.stdout)
175990
- return result;
175991
- const ir = intentSearch(result.stdout, intent);
175992
- if (!ir.searched)
175993
- return result;
175994
- const rendered = renderIntentResult(ir, intent);
175995
- return {
175996
- ...result,
175997
- stdout: `${rendered}
175998
-
175999
- --- tail (last 512 chars) ---
176000
- ${result.stdout.slice(-512)}`
176001
- };
176002
- }
176003
-
176004
- class ExecutorController {
176005
- static instance = null;
176006
- executor;
176007
- constructor(executor) {
176008
- this.executor = executor ?? new PolyglotExecutor;
176009
- }
176010
- static getInstance() {
176011
- if (!ExecutorController.instance) {
176012
- ExecutorController.instance = new ExecutorController;
176013
- }
176014
- return ExecutorController.instance;
176015
- }
176016
- static resetInstance() {
176017
- ExecutorController.instance?.executor.cleanupBackgrounded();
176018
- ExecutorController.instance = null;
176019
- }
176020
- get runtimes() {
176021
- return this.executor.runtimes;
176022
- }
176023
- async execute(params) {
176024
- try {
176025
- const language = validateEnum("language", params.language, EXECUTOR_LANGUAGES);
176026
- const result = await this.executor.execute({
176027
- language,
176028
- code: params.code,
176029
- timeout: params.timeout,
176030
- background: params.background,
176031
- cwd: params.cwd
176032
- });
176033
- const finalResult = applyIntent(result, params.intent);
176034
- const ok = !finalResult.timedOut && finalResult.exitCode === 0;
176035
- return {
176036
- success: ok,
176037
- data: {
176038
- stdout: finalResult.stdout,
176039
- stderr: finalResult.stderr,
176040
- exitCode: finalResult.exitCode,
176041
- timedOut: finalResult.timedOut,
176042
- backgrounded: finalResult.backgrounded ?? false,
176043
- command: finalResult.command,
176044
- cwd: finalResult.cwd,
176045
- sandboxMode: finalResult.sandboxMode
176046
- }
176047
- };
176048
- } catch (error51) {
176049
- logger.error("execute failed", error51, {
176050
- language: params.language
176051
- });
176052
- return {
176053
- success: false,
176054
- error: `execute failed: ${error51.message}`
176055
- };
176056
- }
176057
- }
176058
- async executeFile(params) {
176059
- try {
176060
- const language = validateEnum("language", params.language, EXECUTOR_LANGUAGES);
176061
- const result = await this.executor.executeFile({
176062
- path: params.path,
176063
- language,
176064
- code: params.code,
176065
- timeout: params.timeout
176066
- });
176067
- const blocked = result.stderr?.startsWith("Blocked:");
176068
- if (blocked) {
176069
- return { success: false, error: result.stderr };
176070
- }
176071
- const finalResult = applyIntent(result, params.intent);
176072
- const ok = !finalResult.timedOut && finalResult.exitCode === 0;
176073
- return {
176074
- success: ok,
176075
- data: {
176076
- stdout: finalResult.stdout,
176077
- stderr: finalResult.stderr,
176078
- exitCode: finalResult.exitCode,
176079
- timedOut: finalResult.timedOut,
176080
- command: finalResult.command,
176081
- cwd: finalResult.cwd,
176082
- sandboxMode: finalResult.sandboxMode
176083
- }
176084
- };
176085
- } catch (error51) {
176086
- logger.error("execute_file failed", error51, {
176087
- path: params.path,
176088
- language: params.language
176089
- });
176090
- return {
176091
- success: false,
176092
- error: `execute_file failed: ${error51.message}`
176093
- };
176094
- }
176095
- }
176096
- async batchExecute(params) {
176097
- const { commands, concurrency, cwd, timeout } = params;
176098
- if (!Array.isArray(commands) || commands.length === 0) {
176099
- return { success: false, error: "commands must be a non-empty array." };
176100
- }
176101
- if (commands.length > MAX_BATCH_COMMANDS) {
176102
- return {
176103
- success: false,
176104
- error: `batch_execute accepts at most ${MAX_BATCH_COMMANDS} commands; received ${commands.length}. Split the batch or reduce the payload.`
176105
- };
176106
- }
176107
- const effectiveConcurrency = concurrency && concurrency > 0 ? concurrency : Math.max(1, cpus2().length);
176108
- const perTimeout = timeout ?? DEFAULT_TIMEOUT_MS2;
176109
- try {
176110
- const poolResult = await runPool(commands.map((cmd) => ({
176111
- run: () => this.executor.execute({
176112
- language: "shell",
176113
- code: cmd,
176114
- timeout: perTimeout,
176115
- cwd
176116
- })
176117
- })), { concurrency: effectiveConcurrency });
176118
- const results = poolResult.settled.map((s, i) => {
176119
- if (s.status === "fulfilled") {
176120
- const r2 = s.value;
176121
- return {
176122
- command: commands[i],
176123
- stdout: r2.stdout,
176124
- stderr: r2.stderr,
176125
- exitCode: r2.exitCode,
176126
- timedOut: r2.timedOut,
176127
- sandboxMode: r2.sandboxMode
176128
- };
176129
- }
176130
- return {
176131
- command: commands[i],
176132
- stdout: "",
176133
- stderr: String(s.reason ?? "unknown error"),
176134
- exitCode: null,
176135
- timedOut: false,
176136
- sandboxMode: getSandboxMode()
176137
- };
176138
- });
176139
- const anyFailed = results.some((r2) => r2.exitCode !== 0 || r2.timedOut);
176140
- return {
176141
- success: !anyFailed,
176142
- data: {
176143
- results,
176144
- concurrency: poolResult.effectiveConcurrency,
176145
- capped: poolResult.capped
176146
- }
176147
- };
176148
- } catch (error51) {
176149
- logger.error("batch_execute failed", error51);
176150
- return {
176151
- success: false,
176152
- error: `batch_execute failed: ${error51.message}`
176153
- };
176154
- }
176155
- }
176156
- static get MAX_TIMEOUT_MS() {
176157
- return MAX_TIMEOUT_MS;
176158
- }
176159
- }
176160
- // ../../packages/core/dist/controllers/graph-controller.js
176161
- init_dist();
176162
- init_trace_path();
176163
- init_impact_analysis();
176164
- init_definition_lookup();
176165
-
176166
- class GraphController {
176167
- static instance = null;
176168
- constructor() {}
176169
- static getInstance() {
176170
- if (!GraphController.instance) {
176171
- GraphController.instance = new GraphController;
176172
- }
176173
- return GraphController.instance;
176174
- }
176175
- async tracePath(input) {
176176
- const projectId = input.projectId;
176177
- const seed = input.function_name ?? input.symbol ?? input.qualifiedName;
176178
- if (!projectId)
176179
- throw new Error("projectId is required");
176180
- if (!seed)
176181
- throw new Error("function_name (or symbol/qualifiedName) is required");
176182
- const t0 = performance.now();
176183
- const result = await tracePathService.tracePath({
176184
- symbol: input.function_name ?? input.symbol ?? "",
176185
- function_name: input.function_name,
176186
- qualifiedName: input.qualifiedName,
176187
- projectId,
176188
- direction: input.direction,
176189
- mode: input.mode,
176190
- depth: input.depth,
176191
- include_tests: input.include_tests,
176192
- edge_types: input.edge_types
176193
- });
176194
- logger.info("GraphController: trace_path", {
176195
- projectId,
176196
- symbol: seed,
176197
- mode: result.mode,
176198
- direction: result.direction,
176199
- seeds: result.seeds.length,
176200
- nodes: result.nodes.length,
176201
- edges: result.edges.length,
176202
- durationMs: Math.round(performance.now() - t0)
176203
- });
176204
- if (result.seeds.length === 0) {
176205
- return {
176206
- found: false,
176207
- symbol: seed,
176208
- projectId,
176209
- ...result.identityResolution ? { identityResolution: result.identityResolution } : {},
176210
- hint: "Use search_definitions(search=...) to find the exact name, or pass a fully-qualified name (qualifiedName='rel/path.ts#Name')."
176211
- };
176212
- }
176213
- return {
176214
- found: true,
176215
- result: {
176216
- projectId: result.projectId,
176217
- symbol: result.symbol,
176218
- mode: result.mode,
176219
- direction: result.direction,
176220
- edgeTypes: result.edgeTypes,
176221
- seeds: result.seeds,
176222
- truncated: result.truncated,
176223
- nodes_total: result.nodes_total,
176224
- nodes_shown: result.nodes_shown,
176225
- nodes_omitted: result.nodes_omitted,
176226
- nodeCount: result.nodes.length,
176227
- edgeCount: result.edges.length,
176228
- chains: result.chains,
176229
- nodes: result.nodes,
176230
- edges: result.edges,
176231
- ...result.identityResolution ? { identity: toSymbolIdentityResolution(result.identityResolution) } : {}
176232
- }
176233
- };
176234
- }
176235
- async analyzeImpact(input) {
176236
- if (!input.projectId)
176237
- throw new Error("projectId is required");
176238
- if (!input.projectPath)
176239
- throw new Error("projectPath is required");
176240
- const t0 = performance.now();
176241
- const result = await impactAnalysisService.analyze({
176242
- projectId: input.projectId,
176243
- projectPath: input.projectPath,
176244
- scope: input.scope ?? "unstaged",
176245
- baseBranch: input.base_branch,
176246
- since: input.since,
176247
- depth: input.depth,
176248
- paths: input.paths,
176249
- diffRunner: input.diffRunner
176250
- });
176251
- logger.info("GraphController: impact_analysis", {
176252
- projectId: input.projectId,
176253
- scope: result.scope,
176254
- changedFiles: result.changedFiles.length,
176255
- impacted: result.impacted.length,
176256
- truncated: result.truncated,
176257
- durationMs: Math.round(performance.now() - t0)
176258
- });
176259
- return {
176260
- projectId: result.projectId,
176261
- scope: result.scope,
176262
- baseBranch: result.baseBranch,
176263
- since: result.since,
176264
- depth: result.depth,
176265
- changedFileCount: result.changedFiles.length,
176266
- changedFiles: result.changedFiles,
176267
- impactedCount: result.impacted.length,
176268
- truncated: result.truncated,
176269
- impacted: result.impacted,
176270
- untrackedFiltered: result.untrackedFiltered,
176271
- impacted_total: result.impacted_total,
176272
- impacted_shown: result.impacted_shown,
176273
- impacted_omitted: result.impacted_omitted,
176274
- note: result.note
176275
- };
176276
- }
176277
- }
176278
176425
  // ../../packages/core/dist/index.js
176279
176426
  init_memory_repository_pg();
176280
176427
  init_memory_repository_factory();
176281
- init_services();
176282
-
176283
- // ../../packages/core/dist/data/vector/hybrid-search.js
176284
176428
  init_vector_store_factory();
176285
- init_keyword_search_pg();
176286
- init_dist();
176429
+ init_services();
176287
176430
 
176288
- // ../../packages/core/dist/data/vector/index.js
176289
- init_vector_store_factory();
176290
- init_base_vector_store();
176291
176431
  // ../../packages/core/dist/data/graph-generation/index.js
176292
176432
  init_graph_generation_repository_pg();
176293
176433
  init_graph_generation_repository_factory();
@@ -176648,7 +176788,7 @@ init_llm_client();
176648
176788
  init_symbol_graph_service();
176649
176789
  import { randomUUID as randomUUID9 } from "crypto";
176650
176790
  import fs14 from "fs";
176651
- import path24 from "path";
176791
+ import path26 from "path";
176652
176792
  import { spawn as spawn2 } from "child_process";
176653
176793
  var FALLBACK_BOOTSTRAP = {
176654
176794
  enabled: true,
@@ -176832,7 +176972,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
176832
176972
  }
176833
176973
  try {
176834
176974
  for (const name26 of README_CANDIDATES) {
176835
- const p = path24.join(projectRoot, name26);
176975
+ const p = path26.join(projectRoot, name26);
176836
176976
  if (fs14.existsSync(p) && fs14.statSync(p).isFile()) {
176837
176977
  const buf = fs14.readFileSync(p);
176838
176978
  signals.readme = buf.slice(0, MAX_README_BYTES).toString("utf8");
@@ -176843,14 +176983,14 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
176843
176983
  logger.debug("bootstrap scan: README read failed", { error: e.message });
176844
176984
  }
176845
176985
  try {
176846
- const docsDir = path24.join(projectRoot, "docs");
176986
+ const docsDir = path26.join(projectRoot, "docs");
176847
176987
  if (fs14.existsSync(docsDir) && fs14.statSync(docsDir).isDirectory()) {
176848
176988
  const entries = walkMarkdown(docsDir).slice(0, MAX_DOCS);
176849
176989
  for (const rel of entries) {
176850
176990
  try {
176851
176991
  const buf = fs14.readFileSync(rel);
176852
176992
  signals.docs.push({
176853
- path: path24.relative(projectRoot, rel),
176993
+ path: path26.relative(projectRoot, rel),
176854
176994
  snippet: buf.slice(0, MAX_DOC_BYTES).toString("utf8")
176855
176995
  });
176856
176996
  } catch {}
@@ -176861,7 +177001,7 @@ async function scanSignals(_projectId, projectRoot, caps, symbolGraph, gitRunner
176861
177001
  }
176862
177002
  try {
176863
177003
  for (const name26 of MANIFEST_FILES) {
176864
- const p = path24.join(projectRoot, name26);
177004
+ const p = path26.join(projectRoot, name26);
176865
177005
  if (!fs14.existsSync(p) || !fs14.statSync(p).isFile())
176866
177006
  continue;
176867
177007
  const raw2 = fs14.readFileSync(p).slice(0, MAX_MANIFEST_BYTES).toString("utf8");
@@ -176909,7 +177049,7 @@ function walkMarkdown(dir) {
176909
177049
  continue;
176910
177050
  }
176911
177051
  for (const e of entries) {
176912
- const full = path24.join(cur, e.name);
177052
+ const full = path26.join(cur, e.name);
176913
177053
  if (e.isDirectory()) {
176914
177054
  if (e.name === "node_modules" || e.name.startsWith("."))
176915
177055
  continue;
@@ -177943,7 +178083,7 @@ var checkpointRoutes = new Elysia({ prefix: "/api/v1/checkpoints" }).post("/list
177943
178083
  // src/routes/project.ts
177944
178084
  init_dist();
177945
178085
  import fs15 from "fs/promises";
177946
- import path25 from "path";
178086
+ import path27 from "path";
177947
178087
  var indexProjectTool = null;
177948
178088
  var indexStatusTool = null;
177949
178089
  var projectIdentityService = null;
@@ -178152,21 +178292,21 @@ var projectRoutes = new Elysia({ prefix: "/api/v1/project" }).get("/list", async
178152
178292
  }).post("/upload-and-index", async ({ body }) => {
178153
178293
  const rawBase = body.projectId || body.projectPath.replace(/\\/g, "/").split("/").filter(Boolean).pop() || "default";
178154
178294
  const finalProjectId = rawBase.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 128);
178155
- const uploadRoot = process.env.MASSA_AI_UPLOAD_DIR || path25.join(getGlobalDataDir(), "uploads");
178156
- const stagingDir = path25.resolve(uploadRoot, finalProjectId);
178295
+ const uploadRoot = process.env.MASSA_AI_UPLOAD_DIR || path27.join(getGlobalDataDir(), "uploads");
178296
+ const stagingDir = path27.resolve(uploadRoot, finalProjectId);
178157
178297
  await fs15.rm(stagingDir, { recursive: true, force: true });
178158
178298
  await fs15.mkdir(stagingDir, { recursive: true });
178159
178299
  const WRITE_BATCH = 20;
178160
178300
  for (let i = 0;i < body.files.length; i += WRITE_BATCH) {
178161
178301
  await Promise.all(body.files.slice(i, i + WRITE_BATCH).map(async (file3) => {
178162
- if (path25.isAbsolute(file3.relativePath) || file3.relativePath.includes("..")) {
178302
+ if (path27.isAbsolute(file3.relativePath) || file3.relativePath.includes("..")) {
178163
178303
  throw new Error(`Invalid file path: ${file3.relativePath}`);
178164
178304
  }
178165
- const dest = path25.resolve(stagingDir, file3.relativePath.replace(/\//g, path25.sep));
178166
- if (!dest.startsWith(stagingDir + path25.sep)) {
178305
+ const dest = path27.resolve(stagingDir, file3.relativePath.replace(/\//g, path27.sep));
178306
+ if (!dest.startsWith(stagingDir + path27.sep)) {
178167
178307
  throw new Error(`Path escapes staging directory: ${file3.relativePath}`);
178168
178308
  }
178169
- await fs15.mkdir(path25.dirname(dest), { recursive: true });
178309
+ await fs15.mkdir(path27.dirname(dest), { recursive: true });
178170
178310
  await fs15.writeFile(dest, file3.content, "utf-8");
178171
178311
  }));
178172
178312
  }
@@ -178321,7 +178461,7 @@ var analyticsRoutes = new Elysia({ prefix: "/api/v1/analytics" }).post("/", asyn
178321
178461
 
178322
178462
  // src/routes/system.ts
178323
178463
  init_dist();
178324
- import path26 from "path";
178464
+ import path28 from "path";
178325
178465
  import fs16 from "fs";
178326
178466
  import os4 from "os";
178327
178467
  function databaseUrlParts() {
@@ -178396,7 +178536,7 @@ var systemRoutes = new Elysia({ prefix: "/api/v1/system" }).get("/info", async (
178396
178536
  description: "Check PostgreSQL, pgvector, Ollama, and local artifact directory health"
178397
178537
  }
178398
178538
  }).get("/metrics", async () => {
178399
- const metricsPath = path26.join(process.cwd(), "data", "metrics.json");
178539
+ const metricsPath = path28.join(process.cwd(), "data", "metrics.json");
178400
178540
  let metrics2 = {};
178401
178541
  if (fs16.existsSync(metricsPath)) {
178402
178542
  try {
@@ -178551,7 +178691,7 @@ var eventsRoutes = new Elysia({ prefix: "/api/v1" }).get("/events", async ({ que
178551
178691
 
178552
178692
  // src/routes/workspace.ts
178553
178693
  import fs17 from "fs/promises";
178554
- import path27 from "path";
178694
+ import path29 from "path";
178555
178695
  import { realpathSync as realpathSync4 } from "fs";
178556
178696
  var indexProjectTool2 = null;
178557
178697
  function getIndexProjectTool2() {
@@ -178593,7 +178733,7 @@ function realpathSafe(p) {
178593
178733
  try {
178594
178734
  return realpathSync4(p);
178595
178735
  } catch {
178596
- return path27.resolve(p);
178736
+ return path29.resolve(p);
178597
178737
  }
178598
178738
  }
178599
178739
  var graphController = null;
@@ -178944,8 +179084,8 @@ var workspaceRoutes = new Elysia({ prefix: "/api/v1" }).get("/workspace/list", a
178944
179084
  }
178945
179085
  const registeredRoot = realpathSafe(workspace.project_path);
178946
179086
  const callerRoot = realpathSafe(projectPath2);
178947
- const rel = path27.relative(registeredRoot, callerRoot);
178948
- const escapes = rel.startsWith("..") || path27.isAbsolute(rel);
179087
+ const rel = path29.relative(registeredRoot, callerRoot);
179088
+ const escapes = rel.startsWith("..") || path29.isAbsolute(rel);
178949
179089
  if (registeredRoot !== callerRoot && escapes) {
178950
179090
  return {
178951
179091
  success: false,
@@ -179075,7 +179215,7 @@ var workspaceRoutes = new Elysia({ prefix: "/api/v1" }).get("/workspace/list", a
179075
179215
  } else {
179076
179216
  end = start + 20;
179077
179217
  }
179078
- const absolutePath = path27.join(workspace.project_path, file3);
179218
+ const absolutePath = path29.join(workspace.project_path, file3);
179079
179219
  const content = await fs17.readFile(absolutePath, "utf-8");
179080
179220
  const lines = content.split(/\r?\n/);
179081
179221
  const slice = lines.slice(start - 1, Math.min(lines.length, end));
@@ -179992,7 +180132,7 @@ var webRoutes = new Elysia({ prefix: "/api/v1/web" }).post("/fetch_and_index", a
179992
180132
 
179993
180133
  // src/routes/web-ui.ts
179994
180134
  import fs18 from "fs/promises";
179995
- import path28 from "path";
180135
+ import path30 from "path";
179996
180136
  import { fileURLToPath as fileURLToPath3 } from "url";
179997
180137
 
179998
180138
  // src/web-ui-trust.ts
@@ -180036,9 +180176,9 @@ function buildStaticDirCandidates(moduleDir, cwd) {
180036
180176
  for (const root2 of [moduleDir, cwd]) {
180037
180177
  let dir = root2;
180038
180178
  for (let i = 0;i < 10; i++) {
180039
- candidates2.push(path28.resolve(dir, "apps/web-ui/src/static"));
180040
- candidates2.push(path28.resolve(dir, "web-ui/src/static"));
180041
- const parent = path28.dirname(dir);
180179
+ candidates2.push(path30.resolve(dir, "apps/web-ui/src/static"));
180180
+ candidates2.push(path30.resolve(dir, "web-ui/src/static"));
180181
+ const parent = path30.dirname(dir);
180042
180182
  if (parent === dir)
180043
180183
  break;
180044
180184
  dir = parent;
@@ -180046,7 +180186,7 @@ function buildStaticDirCandidates(moduleDir, cwd) {
180046
180186
  }
180047
180187
  return [...new Set(candidates2)];
180048
180188
  }
180049
- var STATIC_DIR_CANDIDATES = buildStaticDirCandidates(path28.dirname(fileURLToPath3(import.meta.url)), process.cwd());
180189
+ var STATIC_DIR_CANDIDATES = buildStaticDirCandidates(path30.dirname(fileURLToPath3(import.meta.url)), process.cwd());
180050
180190
  async function resolveStaticDir() {
180051
180191
  for (const dir of STATIC_DIR_CANDIDATES) {
180052
180192
  try {
@@ -180071,7 +180211,7 @@ var CONTENT_TYPES = {
180071
180211
  ".woff2": "font/woff2"
180072
180212
  };
180073
180213
  function contentTypeFor(filePath) {
180074
- const ext2 = path28.extname(filePath).toLowerCase();
180214
+ const ext2 = path30.extname(filePath).toLowerCase();
180075
180215
  return CONTENT_TYPES[ext2] ?? "application/octet-stream";
180076
180216
  }
180077
180217
  function webUiDisabled() {
@@ -180082,9 +180222,9 @@ function webUiDisabled() {
180082
180222
  }
180083
180223
  async function resolveSafePath(staticDir, sub) {
180084
180224
  const cleaned = sub.replace(/^\/+/, "");
180085
- const abs = path28.resolve(staticDir, cleaned);
180086
- const rel = path28.relative(staticDir, abs);
180087
- if (rel.startsWith("..") || path28.isAbsolute(rel)) {
180225
+ const abs = path30.resolve(staticDir, cleaned);
180226
+ const rel = path30.relative(staticDir, abs);
180227
+ if (rel.startsWith("..") || path30.isAbsolute(rel)) {
180088
180228
  return null;
180089
180229
  }
180090
180230
  try {
@@ -180128,7 +180268,7 @@ var webUiRoutes = new Elysia().get("/ui", async ({ set: set3, request }) => {
180128
180268
  set3.status = 500;
180129
180269
  return { status: 500, error: "web ui static dir not found" };
180130
180270
  }
180131
- const indexPath = path28.join(dir, "index.html");
180271
+ const indexPath = path30.join(dir, "index.html");
180132
180272
  try {
180133
180273
  const body = await readShell(indexPath, remoteAddressOf(request));
180134
180274
  set3.headers["content-type"] = contentTypeFor(indexPath);
@@ -180170,7 +180310,7 @@ var webUiRoutes = new Elysia().get("/ui", async ({ set: set3, request }) => {
180170
180310
  }
180171
180311
  }
180172
180312
  try {
180173
- const body = await readShell(path28.join(dir, "index.html"), remoteAddressOf(request));
180313
+ const body = await readShell(path30.join(dir, "index.html"), remoteAddressOf(request));
180174
180314
  set3.headers["content-type"] = "text/html; charset=utf-8";
180175
180315
  return body;
180176
180316
  } catch {