@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.
- package/dist/index.js +1435 -1295
- 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/
|
|
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/
|
|
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
|
-
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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.
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
122209
|
-
if (!
|
|
122215
|
+
const path19 = e.route;
|
|
122216
|
+
if (!path19)
|
|
122210
122217
|
continue;
|
|
122211
122218
|
const method = (e.method ?? "ANY").toUpperCase();
|
|
122212
|
-
const key = method + " " +
|
|
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:
|
|
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
|
|
122229
|
-
const key = method + " " +
|
|
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:
|
|
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
|
|
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 ?
|
|
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
|
-
|
|
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/
|
|
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,
|
|
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 =
|
|
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 (
|
|
126443
|
-
chains.push(
|
|
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 (
|
|
126450
|
-
const cycled = [...
|
|
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, [...
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
137181
|
-
if (!
|
|
137182
|
-
return
|
|
137868
|
+
function remove_dot_segments(path26) {
|
|
137869
|
+
if (!path26)
|
|
137870
|
+
return path26;
|
|
137183
137871
|
var output = "";
|
|
137184
|
-
while (
|
|
137185
|
-
if (
|
|
137186
|
-
|
|
137872
|
+
while (path26.length > 0) {
|
|
137873
|
+
if (path26 === "." || path26 === "..") {
|
|
137874
|
+
path26 = "";
|
|
137187
137875
|
break;
|
|
137188
137876
|
}
|
|
137189
|
-
var twochars =
|
|
137190
|
-
var threechars =
|
|
137191
|
-
var fourchars =
|
|
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
|
-
|
|
137881
|
+
path26 = path26.substring(3);
|
|
137194
137882
|
} else if (twochars === "./") {
|
|
137195
|
-
|
|
137883
|
+
path26 = path26.substring(2);
|
|
137196
137884
|
} else if (threechars === "/./") {
|
|
137197
|
-
|
|
137198
|
-
} else if (twochars === "/." &&
|
|
137199
|
-
|
|
137200
|
-
} else if (fourchars === "/../" || threechars === "/.." &&
|
|
137201
|
-
|
|
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 =
|
|
137892
|
+
var segment = path26.match(/(\/?([^\/]*))/)[0];
|
|
137205
137893
|
output += segment;
|
|
137206
|
-
|
|
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,
|
|
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:
|
|
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, `${
|
|
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:
|
|
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:
|
|
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, `${
|
|
149991
|
+
walk(v, `${path26}.${safeKey}`, out);
|
|
149304
149992
|
}
|
|
149305
149993
|
return;
|
|
149306
149994
|
}
|
|
149307
|
-
out.push({ path:
|
|
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
|
-
|
|
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
|
-
|
|
172185
|
-
|
|
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
|
|
172980
|
+
import path18 from "path";
|
|
172189
172981
|
async function canonicalizeProjectRoot(projectPath, canonicalize = realpath2) {
|
|
172190
|
-
return canonicalize(
|
|
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(
|
|
172990
|
+
storedCanonical = await canonicalize(path18.resolve(options.storedProjectPath));
|
|
172199
172991
|
} catch {
|
|
172200
|
-
storedCanonical =
|
|
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 ||
|
|
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
|
|
172268
|
-
|
|
172269
|
-
|
|
172270
|
-
|
|
172271
|
-
|
|
172272
|
-
|
|
172273
|
-
|
|
172274
|
-
|
|
172275
|
-
|
|
172276
|
-
|
|
172277
|
-
|
|
172278
|
-
|
|
172279
|
-
|
|
172280
|
-
|
|
172281
|
-
|
|
172282
|
-
|
|
172283
|
-
|
|
172284
|
-
|
|
172285
|
-
|
|
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: ${
|
|
173085
|
+
error: `Failed to acquire indexing lease: ${leaseOutcome.message}`
|
|
172298
173086
|
};
|
|
172299
173087
|
}
|
|
172300
|
-
|
|
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,
|
|
173604
|
+
function transformChildren(value, replacer, path21) {
|
|
172868
173605
|
if (isJsonObject(value))
|
|
172869
|
-
return transformObject(value, replacer,
|
|
173606
|
+
return transformObject(value, replacer, path21);
|
|
172870
173607
|
if (isJsonArray(value))
|
|
172871
|
-
return transformArray(value, replacer,
|
|
173608
|
+
return transformArray(value, replacer, path21);
|
|
172872
173609
|
return value;
|
|
172873
173610
|
}
|
|
172874
|
-
function transformObject(obj, replacer,
|
|
173611
|
+
function transformObject(obj, replacer, path21) {
|
|
172875
173612
|
const result = {};
|
|
172876
173613
|
for (const [key, value] of Object.entries(obj)) {
|
|
172877
|
-
const childPath = [...
|
|
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,
|
|
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 = [...
|
|
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
|
|
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 ?? (() =>
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
175335
|
-
|
|
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
|
|
175344
|
-
|
|
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(
|
|
175415
|
-
this.
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
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 ||
|
|
178156
|
-
const stagingDir =
|
|
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 (
|
|
178302
|
+
if (path27.isAbsolute(file3.relativePath) || file3.relativePath.includes("..")) {
|
|
178163
178303
|
throw new Error(`Invalid file path: ${file3.relativePath}`);
|
|
178164
178304
|
}
|
|
178165
|
-
const dest =
|
|
178166
|
-
if (!dest.startsWith(stagingDir +
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
178948
|
-
const escapes = rel.startsWith("..") ||
|
|
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 =
|
|
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
|
|
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(
|
|
180040
|
-
candidates2.push(
|
|
180041
|
-
const parent =
|
|
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(
|
|
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 =
|
|
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 =
|
|
180086
|
-
const rel =
|
|
180087
|
-
if (rel.startsWith("..") ||
|
|
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 =
|
|
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(
|
|
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 {
|