minovative-mind-cli 2.14.0 → 2.14.2
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/README.md +51 -68
- package/dist/services/agent/slashCommands.js +74 -31
- package/dist/services/agent/toolLoop.js +3 -1
- package/dist/services/agent-tools.d.ts +18 -0
- package/dist/services/agent-tools.js +220 -43
- package/dist/services/agent.js +6 -3
- package/dist/services/ai.d.ts +3 -0
- package/dist/services/ai.js +65 -20
- package/dist/services/contextAgent.d.ts +10 -4
- package/dist/services/contextAgent.js +33 -9
- package/dist/services/orchestration/investigationAgent.js +34 -9
- package/dist/services/orchestration/investigationCache.js +19 -9
- package/dist/services/orchestration/readCache.d.ts +1 -0
- package/dist/services/orchestration/readCache.js +5 -2
- package/dist/services/orchestration/scopedTools.js +37 -10
- package/dist/services/orchestration/subAgent.js +16 -2
- package/dist/services/proxyClient.d.ts +6 -0
- package/dist/services/proxyClient.js +24 -10
- package/dist/services/userProfileService.d.ts +14 -0
- package/dist/services/userProfileService.js +105 -3
- package/dist/utils/analysisRunner.d.ts +120 -8
- package/dist/utils/analysisRunner.js +946 -125
- package/dist/utils/contextPrompts.d.ts +39 -0
- package/dist/utils/contextPrompts.js +81 -9
- package/dist/utils/contextRanker.d.ts +216 -0
- package/dist/utils/contextRanker.js +603 -0
- package/dist/utils/dependencyTracer/modules/graph.d.ts +4 -1
- package/dist/utils/dependencyTracer/modules/graph.js +11 -0
- package/dist/utils/dependencyTracer/modules/types.d.ts +10 -0
- package/dist/utils/dependencyTracer.d.ts +25 -0
- package/dist/utils/dependencyTracer.js +34 -0
- package/dist/utils/systemPrompts.d.ts +1 -1
- package/dist/utils/systemPrompts.js +13 -2
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -278,11 +278,15 @@ export const toolDeclarations = [
|
|
|
278
278
|
},
|
|
279
279
|
{
|
|
280
280
|
name: 'run_debug_script',
|
|
281
|
-
description: 'Write a disposable script to a sandboxed temporary file in os.tmpdir(), execute it using the specified runtime, and return the exact standard output and standard error without polluting the workspace or triggering IDE file watchers. ' +
|
|
282
|
-
'
|
|
283
|
-
'(
|
|
284
|
-
'(
|
|
285
|
-
'(
|
|
281
|
+
description: 'Write a disposable script to a sandboxed temporary file in os.tmpdir(), execute it using the specified runtime, and return the exact standard output, structured JSON result, and standard error without polluting the workspace or triggering IDE file watchers. ' +
|
|
282
|
+
'Sandbox Features: ' +
|
|
283
|
+
'(1) Preloaded Helpers: "emitResult(data)" / "__emitResult(data)" outputs structured JSON payloads parsed directly into structuredResult; "inspectSymbols(target)" / "inspectObject(target)" inspects functions, classes, and properties. ' +
|
|
284
|
+
'(2) Module & Path Resolution: Automatically inherits tsconfig.json path aliases (@/*), NODE_PATH, and workspace virtualenvs (.venv, venv) for Python. ' +
|
|
285
|
+
'(3) Diagnostics Middleware: Provides actionable [SANDBOX DIAGNOSTIC] advisories for missing imports, ESM/CJS interop, and compiler errors. ' +
|
|
286
|
+
'Use this to: (a) actively debug the codebase by inspecting variables or logging values, ' +
|
|
287
|
+
'(b) validate your changes by importing the modified module and asserting expected behavior with edge-case inputs, ' +
|
|
288
|
+
'(c) run quick sanity checks (e.g., verify a config file parses correctly, confirm exports are intact after a refactor, or check that a function returns the expected output), ' +
|
|
289
|
+
'(d) write lightweight ML scripts to solve complex problems — e.g., polynomial regression to estimate Big-O complexity, fuzz testing with Markov chain input generation, ' +
|
|
286
290
|
'output regression detection via statistical similarity scoring, or error message classification with Naive Bayes. ' +
|
|
287
291
|
'Default to "node" for generic tasks as a safe baseline, but act like a native inhabitant of the host environment — if Python, Go, Rust, or host-native libraries are active in the project, leverage the host\'s native runtimes for maximum efficiency. ' +
|
|
288
292
|
'Do not guess whether your code works — test it directly!',
|
|
@@ -1124,6 +1128,7 @@ const HIGH_SIGNAL_ERROR_PATTERNS = [
|
|
|
1124
1128
|
/undefined reference/i,
|
|
1125
1129
|
/ld: symbol\(s\) not found/i,
|
|
1126
1130
|
/clang: error:/i,
|
|
1131
|
+
/gcc: error:/i,
|
|
1127
1132
|
/referenced from:/i,
|
|
1128
1133
|
/note: expanded from macro/i,
|
|
1129
1134
|
/note: candidate:/i,
|
|
@@ -1133,29 +1138,59 @@ const HIGH_SIGNAL_ERROR_PATTERNS = [
|
|
|
1133
1138
|
/TypeError:/i,
|
|
1134
1139
|
/ImportError:/i,
|
|
1135
1140
|
/ModuleNotFoundError:/i,
|
|
1141
|
+
/AttributeError:/i,
|
|
1142
|
+
/IndexError:/i,
|
|
1143
|
+
/KeyError:/i,
|
|
1144
|
+
/ValueError:/i,
|
|
1136
1145
|
/FAILED \(failures=/i,
|
|
1137
1146
|
/\bE\s{3}\b/,
|
|
1138
1147
|
/\bFAIL\b/,
|
|
1139
|
-
|
|
1148
|
+
/\bFAILED\b/,
|
|
1149
|
+
/=== FAILURES ===/i,
|
|
1150
|
+
/=== ERRORS ===/i,
|
|
1151
|
+
// Sandbox Diagnostics & Structured Results
|
|
1152
|
+
/\[SANDBOX DIAGNOSTIC\]/i,
|
|
1153
|
+
/\[STRUCTURED RESULT\]/i,
|
|
1154
|
+
/Module resolution failure/i,
|
|
1155
|
+
/CommonJS require\(\) attempted to load an ES Module/i,
|
|
1156
|
+
// Node.js / TypeScript / Jest / Mocha / Vitest
|
|
1157
|
+
/TS\d+:/i,
|
|
1158
|
+
/TS\d{4,5}:/i,
|
|
1140
1159
|
/SyntaxError:/i,
|
|
1141
1160
|
/ReferenceError:/i,
|
|
1161
|
+
/TypeError:/i,
|
|
1162
|
+
/RangeError:/i,
|
|
1163
|
+
/URIError:/i,
|
|
1142
1164
|
/Error: Cannot find module/i,
|
|
1165
|
+
/Cannot find module/i,
|
|
1166
|
+
/Cannot find name/i,
|
|
1167
|
+
/Type '.*' is not assignable to type/i,
|
|
1168
|
+
/Property '.*' does not exist on type/i,
|
|
1143
1169
|
/\bFAIL\b/,
|
|
1144
1170
|
/✕\s/,
|
|
1145
|
-
/TS\d{4}:/,
|
|
1146
1171
|
// Rust / Cargo
|
|
1147
1172
|
/error\[E\d+\]:/i,
|
|
1148
1173
|
/fatal runtime error:/i,
|
|
1149
1174
|
/panicked at/i,
|
|
1175
|
+
/thread '.*' panicked at/i,
|
|
1176
|
+
/-->\s+.*:\d+:\d+/i,
|
|
1177
|
+
/could not compile/i,
|
|
1150
1178
|
// Go
|
|
1151
1179
|
/panic:/i,
|
|
1152
1180
|
/cannot find package/i,
|
|
1153
1181
|
/undefined:/i,
|
|
1154
1182
|
/FAIL\t/,
|
|
1155
|
-
// Java / JVM
|
|
1183
|
+
// Java / JVM / Kotlin / Scala
|
|
1156
1184
|
/Exception in thread/i,
|
|
1157
1185
|
/java\.lang\./i,
|
|
1158
1186
|
/error: cannot find symbol/i,
|
|
1187
|
+
/NullPointerException/i,
|
|
1188
|
+
/ClassNotFoundException/i,
|
|
1189
|
+
// C# / .NET
|
|
1190
|
+
/CS\d{4}:/i,
|
|
1191
|
+
/Unhandled exception/i,
|
|
1192
|
+
// Swift
|
|
1193
|
+
/error:\s+/i,
|
|
1159
1194
|
// Generic Fallbacks
|
|
1160
1195
|
/\b(cannot|unable to|not found|command not found|no such file)\b/i,
|
|
1161
1196
|
];
|
|
@@ -1170,8 +1205,77 @@ const STACK_TRACE_START_PATTERNS = [
|
|
|
1170
1205
|
/Traceback \(most recent call last\):/i,
|
|
1171
1206
|
/Exception in thread/i,
|
|
1172
1207
|
/panic:/i,
|
|
1208
|
+
/thread '.*' panicked at/i,
|
|
1209
|
+
/panicked at/i,
|
|
1173
1210
|
/Error:\s*$/i,
|
|
1211
|
+
/TypeError:\s*$/i,
|
|
1212
|
+
/ReferenceError:\s*$/i,
|
|
1213
|
+
/AssertionError:\s*$/i,
|
|
1214
|
+
/=== FAILURES ===/i,
|
|
1215
|
+
/=== ERRORS ===/i,
|
|
1174
1216
|
];
|
|
1217
|
+
/**
|
|
1218
|
+
* Truncates large string output using bounded head and tail windows with a structured metadata receipt.
|
|
1219
|
+
* Preserves early context (e.g. invocation, build targets) and late context (e.g. error summaries, exit codes)
|
|
1220
|
+
* while bounding total character and line count.
|
|
1221
|
+
*
|
|
1222
|
+
* @param text - The raw output text to truncate.
|
|
1223
|
+
* @param options - Configuration options for character/line limits and custom receipt notices.
|
|
1224
|
+
* @returns The windowed text containing head, structured metadata receipt, and tail.
|
|
1225
|
+
*/
|
|
1226
|
+
export function truncateWithHeadTailWindow(text, options) {
|
|
1227
|
+
if (!text || typeof text !== 'string')
|
|
1228
|
+
return '';
|
|
1229
|
+
const maxChars = options?.maxChars ?? 30_000;
|
|
1230
|
+
const maxLines = options?.maxLines ?? 500;
|
|
1231
|
+
const headRatio = options?.headRatio ?? 0.35;
|
|
1232
|
+
const receiptLabel = options?.receiptLabel ?? 'Output';
|
|
1233
|
+
const hint = options?.hint ?? 'Pipe command to a file and read it in chunks, or use grep.';
|
|
1234
|
+
const lines = text.split(/\r?\n/);
|
|
1235
|
+
if (text.length <= maxChars && lines.length <= maxLines) {
|
|
1236
|
+
return text;
|
|
1237
|
+
}
|
|
1238
|
+
const totalBytes = text.length;
|
|
1239
|
+
const totalLines = lines.length;
|
|
1240
|
+
// Calculate target characters for head and tail windows
|
|
1241
|
+
const receiptReserve = 500;
|
|
1242
|
+
const availableChars = Math.max(1000, maxChars - receiptReserve);
|
|
1243
|
+
const targetHeadChars = Math.floor(availableChars * headRatio);
|
|
1244
|
+
const targetTailChars = availableChars - targetHeadChars;
|
|
1245
|
+
// Max lines for head and tail
|
|
1246
|
+
const targetHeadLines = Math.max(5, Math.floor(maxLines * headRatio));
|
|
1247
|
+
const targetTailLines = Math.max(10, maxLines - targetHeadLines);
|
|
1248
|
+
// Accumulate head lines
|
|
1249
|
+
const headLines = [];
|
|
1250
|
+
let headCharsCount = 0;
|
|
1251
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1252
|
+
const line = lines[i];
|
|
1253
|
+
if (headLines.length >= targetHeadLines ||
|
|
1254
|
+
(headLines.length > 0 && headCharsCount + line.length + 1 > targetHeadChars)) {
|
|
1255
|
+
break;
|
|
1256
|
+
}
|
|
1257
|
+
headLines.push(line);
|
|
1258
|
+
headCharsCount += line.length + 1;
|
|
1259
|
+
}
|
|
1260
|
+
// Accumulate tail lines backwards (ensuring no overlap with head)
|
|
1261
|
+
const tailLines = [];
|
|
1262
|
+
let tailCharsCount = 0;
|
|
1263
|
+
for (let i = lines.length - 1; i >= headLines.length; i--) {
|
|
1264
|
+
const line = lines[i];
|
|
1265
|
+
if (tailLines.length >= targetTailLines ||
|
|
1266
|
+
(tailLines.length > 0 && tailCharsCount + line.length + 1 > targetTailChars)) {
|
|
1267
|
+
break;
|
|
1268
|
+
}
|
|
1269
|
+
tailLines.unshift(line);
|
|
1270
|
+
tailCharsCount += line.length + 1;
|
|
1271
|
+
}
|
|
1272
|
+
const omittedLines = Math.max(0, totalLines - headLines.length - tailLines.length);
|
|
1273
|
+
const headText = headLines.join('\n');
|
|
1274
|
+
const tailText = tailLines.join('\n');
|
|
1275
|
+
const omittedBytes = Math.max(0, totalBytes - headText.length - tailText.length);
|
|
1276
|
+
const receipt = `\n\n... [${receiptLabel} truncated: ${omittedLines} lines (${omittedBytes} bytes) omitted. Showing ${headLines.length} head lines and ${tailLines.length} tail lines. Total: ${totalLines} lines (${totalBytes} bytes). ${hint}] ...\n\n`;
|
|
1277
|
+
return headText + receipt + tailText;
|
|
1278
|
+
}
|
|
1175
1279
|
/**
|
|
1176
1280
|
* Condenses verbose command and test failure outputs into high-signal diagnostic error logs
|
|
1177
1281
|
* with dynamic tail sizing and stack trace boundary snapping.
|
|
@@ -1189,14 +1293,30 @@ export function extractHighSignalError(rawError) {
|
|
|
1189
1293
|
}
|
|
1190
1294
|
// Filter out noise lines (e.g. repetitive compiler warning flags)
|
|
1191
1295
|
const nonNoiseLines = lines.filter((l) => !COMPILER_WARNING_NOISE_PATTERN.test(l));
|
|
1192
|
-
// Find high-signal error lines
|
|
1296
|
+
// Find high-signal error lines and associated compiler frames/context lines
|
|
1193
1297
|
const highSignalLines = [];
|
|
1194
1298
|
const highSignalIndices = new Set();
|
|
1195
1299
|
for (let i = 0; i < nonNoiseLines.length; i++) {
|
|
1196
1300
|
const line = nonNoiseLines[i];
|
|
1197
1301
|
if (HIGH_SIGNAL_ERROR_PATTERNS.some((p) => p.test(line))) {
|
|
1198
|
-
|
|
1199
|
-
|
|
1302
|
+
if (!highSignalIndices.has(i)) {
|
|
1303
|
+
highSignalLines.push(line);
|
|
1304
|
+
highSignalIndices.add(i);
|
|
1305
|
+
}
|
|
1306
|
+
// Capture up to 5 immediate compiler frame continuation lines (e.g. code squiggles, expected/found, arrows)
|
|
1307
|
+
for (let j = 1; j <= 5 && i + j < nonNoiseLines.length; j++) {
|
|
1308
|
+
const nextLine = nonNoiseLines[i + j];
|
|
1309
|
+
if (/^\s*(\||-->|\^|~|expected|found|note:|candidate:)/i.test(nextLine) ||
|
|
1310
|
+
/^\s*\d+\s*\|/.test(nextLine)) {
|
|
1311
|
+
if (!highSignalIndices.has(i + j)) {
|
|
1312
|
+
highSignalLines.push(nextLine);
|
|
1313
|
+
highSignalIndices.add(i + j);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
break;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1200
1320
|
}
|
|
1201
1321
|
}
|
|
1202
1322
|
// Dynamic tail sizing: Math.min(50, Math.max(15, Math.floor(totalLines * 0.15)))
|
|
@@ -1233,7 +1353,15 @@ export function extractHighSignalError(rawError) {
|
|
|
1233
1353
|
else {
|
|
1234
1354
|
resultBlocks.push(tailLines.join('\n'));
|
|
1235
1355
|
}
|
|
1236
|
-
|
|
1356
|
+
let condensedResult = resultBlocks.join('\n\n');
|
|
1357
|
+
// Bounded head/tail window check on condensed result if still oversized
|
|
1358
|
+
if (condensedResult.length > 30_000) {
|
|
1359
|
+
condensedResult = truncateWithHeadTailWindow(condensedResult, {
|
|
1360
|
+
maxChars: 30_000,
|
|
1361
|
+
receiptLabel: 'Diagnostic output',
|
|
1362
|
+
hint: 'Pipe to a file if you need full logs.',
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1237
1365
|
const condensedLines = condensedResult.split(/\r?\n/).length;
|
|
1238
1366
|
const linesPruned = Math.max(0, lines.length - condensedLines);
|
|
1239
1367
|
const charsPruned = Math.max(0, rawError.length - condensedResult.length);
|
|
@@ -1257,26 +1385,25 @@ export async function runCommand(workspaceRoot, command, abortSignal) {
|
|
|
1257
1385
|
maxBuffer: 1024 * 1024 * 2, // 2 MB buffer
|
|
1258
1386
|
signal: abortSignal,
|
|
1259
1387
|
});
|
|
1260
|
-
|
|
1261
|
-
//
|
|
1262
|
-
const
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
}
|
|
1268
|
-
return { output: output || '(command produced no output)' };
|
|
1388
|
+
const output = [stdout, stderr].filter(Boolean).join('\n');
|
|
1389
|
+
// Bounded head/tail window truncation with structured metadata receipt
|
|
1390
|
+
const windowedOutput = truncateWithHeadTailWindow(output, {
|
|
1391
|
+
maxChars: 30_000,
|
|
1392
|
+
receiptLabel: 'Output',
|
|
1393
|
+
hint: 'To view the rest, pipe the command to a file and read it in chunks, or use grep.',
|
|
1394
|
+
});
|
|
1395
|
+
return { output: windowedOutput || '(command produced no output)' };
|
|
1269
1396
|
}
|
|
1270
1397
|
catch (err) {
|
|
1271
1398
|
const message = err instanceof Error ? err.message : String(err);
|
|
1272
1399
|
// Condense error output with high-signal extraction and dynamic tail sizing
|
|
1273
1400
|
const condensedError = extractHighSignalError(message);
|
|
1274
|
-
const
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
return { output: '', error: `Command failed: ${
|
|
1401
|
+
const windowedError = truncateWithHeadTailWindow(condensedError, {
|
|
1402
|
+
maxChars: 30_000,
|
|
1403
|
+
receiptLabel: 'Error output',
|
|
1404
|
+
hint: 'Pipe to a file if you need full logs.',
|
|
1405
|
+
});
|
|
1406
|
+
return { output: '', error: `Command failed: ${windowedError}` };
|
|
1280
1407
|
}
|
|
1281
1408
|
}
|
|
1282
1409
|
/**
|
|
@@ -1305,14 +1432,18 @@ export async function grepSearch(workspaceRoot, pattern, fileGlob, fixedStrings,
|
|
|
1305
1432
|
}
|
|
1306
1433
|
// Use ignore package to evaluate path globs (e.g. src/**/*.ts)
|
|
1307
1434
|
const globMatcher = fileGlob ? ignore().add(fileGlob) : null;
|
|
1435
|
+
const MAX_SHOWN_MATCHES = 50;
|
|
1436
|
+
const MAX_SCAN_MATCHES = 500;
|
|
1308
1437
|
const results = [];
|
|
1438
|
+
let totalMatches = 0;
|
|
1439
|
+
const matchedFiles = new Set();
|
|
1309
1440
|
/**
|
|
1310
1441
|
* Recursively walks directory entries to search for pattern matches.
|
|
1311
1442
|
*
|
|
1312
1443
|
* @param dir - Absolute path to the current directory being searched.
|
|
1313
1444
|
*/
|
|
1314
1445
|
async function walk(dir) {
|
|
1315
|
-
if (
|
|
1446
|
+
if (totalMatches >= MAX_SCAN_MATCHES)
|
|
1316
1447
|
return;
|
|
1317
1448
|
if (abortSignal?.aborted)
|
|
1318
1449
|
return;
|
|
@@ -1324,7 +1455,7 @@ export async function grepSearch(workspaceRoot, pattern, fileGlob, fixedStrings,
|
|
|
1324
1455
|
return;
|
|
1325
1456
|
}
|
|
1326
1457
|
for (const entry of entries) {
|
|
1327
|
-
if (
|
|
1458
|
+
if (totalMatches >= MAX_SCAN_MATCHES)
|
|
1328
1459
|
return;
|
|
1329
1460
|
if (abortSignal?.aborted)
|
|
1330
1461
|
return;
|
|
@@ -1351,12 +1482,16 @@ export async function grepSearch(workspaceRoot, pattern, fileGlob, fixedStrings,
|
|
|
1351
1482
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
1352
1483
|
const lines = content.split(/\r?\n/);
|
|
1353
1484
|
for (let i = 0; i < lines.length; i++) {
|
|
1354
|
-
if (
|
|
1485
|
+
if (totalMatches >= MAX_SCAN_MATCHES)
|
|
1355
1486
|
break;
|
|
1356
1487
|
regexPattern.lastIndex = 0;
|
|
1357
1488
|
if (regexPattern.test(lines[i])) {
|
|
1358
|
-
|
|
1359
|
-
|
|
1489
|
+
totalMatches++;
|
|
1490
|
+
matchedFiles.add(relPath);
|
|
1491
|
+
if (results.length < MAX_SHOWN_MATCHES) {
|
|
1492
|
+
const relativePath = path.relative(workspaceRoot, filePath).replace(/\\/g, '/');
|
|
1493
|
+
results.push(`${relativePath}:${i + 1}:${lines[i]}`);
|
|
1494
|
+
}
|
|
1360
1495
|
}
|
|
1361
1496
|
}
|
|
1362
1497
|
}
|
|
@@ -1373,8 +1508,18 @@ export async function grepSearch(workspaceRoot, pattern, fileGlob, fixedStrings,
|
|
|
1373
1508
|
}
|
|
1374
1509
|
if (results.length === 0)
|
|
1375
1510
|
return { output: `No matches found for "${pattern}".` };
|
|
1376
|
-
|
|
1377
|
-
|
|
1511
|
+
let resultText = results.join('\n');
|
|
1512
|
+
if (totalMatches > results.length) {
|
|
1513
|
+
const moreSuffix = totalMatches >= MAX_SCAN_MATCHES ? '+' : '';
|
|
1514
|
+
resultText += `\n\n[Showing ${results.length}/${totalMatches}${moreSuffix} matches across ${matchedFiles.size} files. Refine query with fileGlob or dirPath to narrow results.]`;
|
|
1515
|
+
}
|
|
1516
|
+
// Window large grep text if character count is huge
|
|
1517
|
+
const windowedResult = truncateWithHeadTailWindow(resultText, {
|
|
1518
|
+
maxChars: 30_000,
|
|
1519
|
+
receiptLabel: 'Grep search results',
|
|
1520
|
+
hint: 'Refine query with fileGlob or dirPath to narrow results.',
|
|
1521
|
+
});
|
|
1522
|
+
const wrappedResult = `<workspace_file path="grep_search_results">\n<content_data><![CDATA[\n${sanitizeForCDATA(windowedResult)}\n]]\\u200B></content_data>\n</workspace_file>`;
|
|
1378
1523
|
return { output: wrappedResult };
|
|
1379
1524
|
}
|
|
1380
1525
|
catch (err) {
|
|
@@ -1513,6 +1658,12 @@ export async function runDebugScript(workspaceRoot, language, code, abortSignal)
|
|
|
1513
1658
|
if (res.exitCode !== 0) {
|
|
1514
1659
|
finalOutput += `Script failed with exit code ${res.exitCode}.\n`;
|
|
1515
1660
|
}
|
|
1661
|
+
if (res.structuredResult !== undefined) {
|
|
1662
|
+
const formattedStructured = typeof res.structuredResult === 'string'
|
|
1663
|
+
? res.structuredResult
|
|
1664
|
+
: JSON.stringify(res.structuredResult, null, 2);
|
|
1665
|
+
finalOutput += `[STRUCTURED RESULT]\n${formattedStructured}\n`;
|
|
1666
|
+
}
|
|
1516
1667
|
if (res.stdout) {
|
|
1517
1668
|
finalOutput += `[STDOUT]\n${res.stdout}\n`;
|
|
1518
1669
|
}
|
|
@@ -1523,11 +1674,17 @@ export async function runDebugScript(workspaceRoot, language, code, abortSignal)
|
|
|
1523
1674
|
finalOutput = 'Script executed successfully with no output.';
|
|
1524
1675
|
}
|
|
1525
1676
|
const condensedOutput = extractHighSignalError(finalOutput.trim());
|
|
1677
|
+
const windowedOutput = truncateWithHeadTailWindow(condensedOutput, {
|
|
1678
|
+
maxChars: 30_000,
|
|
1679
|
+
receiptLabel: 'Debug script output',
|
|
1680
|
+
hint: 'Inspect specific variables or refine script if full logs are needed.',
|
|
1681
|
+
});
|
|
1526
1682
|
return {
|
|
1527
|
-
output: `<test_results>\n${sanitizeForCDATA(
|
|
1683
|
+
output: `<test_results>\n${sanitizeForCDATA(windowedOutput)}\n</test_results>`,
|
|
1684
|
+
...(res.structuredResult !== undefined ? { structuredResult: res.structuredResult } : {}),
|
|
1528
1685
|
...(res.exitCode !== 0
|
|
1529
1686
|
? {
|
|
1530
|
-
error: `Script failed with exit code ${res.exitCode}:\n${extractHighSignalError(res.stderr || res.stdout || '')}`,
|
|
1687
|
+
error: `Script failed with exit code ${res.exitCode}:\n${truncateWithHeadTailWindow(extractHighSignalError(res.stderr || res.stdout || ''), { maxChars: 30_000, receiptLabel: 'Debug script error' })}`,
|
|
1531
1688
|
}
|
|
1532
1689
|
: {}),
|
|
1533
1690
|
};
|
|
@@ -1573,6 +1730,7 @@ export async function executeFuzzProbe(workspaceRoot, code, language = 'node', c
|
|
|
1573
1730
|
output += `\n[STDERR]\n${res.stderr}\n`;
|
|
1574
1731
|
return {
|
|
1575
1732
|
output: output.trim(),
|
|
1733
|
+
...(res.structuredResult !== undefined ? { structuredResult: res.structuredResult } : {}),
|
|
1576
1734
|
...(res.exitCode !== 0 && !res.passed ? { error: `Fuzz probe failed with exit code ${res.exitCode}` } : {}),
|
|
1577
1735
|
};
|
|
1578
1736
|
}
|
|
@@ -1616,6 +1774,7 @@ export async function executeHeapDelta(workspaceRoot, code, language = 'node', c
|
|
|
1616
1774
|
output += `\n[STDERR]\n${res.stderr}\n`;
|
|
1617
1775
|
return {
|
|
1618
1776
|
output: output.trim(),
|
|
1777
|
+
...(res.structuredResult !== undefined ? { structuredResult: res.structuredResult } : {}),
|
|
1619
1778
|
...(res.exitCode !== 0 ? { error: `Heap delta failed with exit code ${res.exitCode}` } : {}),
|
|
1620
1779
|
};
|
|
1621
1780
|
}
|
|
@@ -1661,6 +1820,7 @@ export async function executeBehavioralDrift(workspaceRoot, baselineCode, candid
|
|
|
1661
1820
|
output += `\n[STDERR]\n${res.stderr}\n`;
|
|
1662
1821
|
return {
|
|
1663
1822
|
output: output.trim(),
|
|
1823
|
+
...(res.structuredResult !== undefined ? { structuredResult: res.structuredResult } : {}),
|
|
1664
1824
|
...(res.exitCode !== 0 ? { error: `Behavioral drift check failed with exit code ${res.exitCode}` } : {}),
|
|
1665
1825
|
};
|
|
1666
1826
|
}
|
|
@@ -1727,6 +1887,9 @@ function resolveWorkspaceArgs(primaryRoot, toolName, args) {
|
|
|
1727
1887
|
async function crossWorkspaceGrep(primaryRoot, pattern, fileGlob, fixedStrings, dirPath, abortSignal) {
|
|
1728
1888
|
const allRoots = workspaceRegistry.getAllRoots(primaryRoot);
|
|
1729
1889
|
const allResults = [];
|
|
1890
|
+
let totalMatches = 0;
|
|
1891
|
+
const matchedFiles = new Set();
|
|
1892
|
+
const MAX_SHOWN_MATCHES = 80;
|
|
1730
1893
|
for (const { alias, root } of allRoots) {
|
|
1731
1894
|
const result = await grepSearch(root, pattern, fileGlob, fixedStrings, dirPath, abortSignal);
|
|
1732
1895
|
if (result.error)
|
|
@@ -1740,10 +1903,14 @@ async function crossWorkspaceGrep(primaryRoot, pattern, fileGlob, fixedStrings,
|
|
|
1740
1903
|
const prefix = alias ? `@${alias}/` : '';
|
|
1741
1904
|
const lines = rawText.split('\n').filter((l) => l.trim());
|
|
1742
1905
|
for (const line of lines) {
|
|
1743
|
-
if (line.startsWith('...')) {
|
|
1744
|
-
|
|
1906
|
+
if (line.startsWith('...') || line.startsWith('[')) {
|
|
1907
|
+
continue;
|
|
1745
1908
|
}
|
|
1746
|
-
|
|
1909
|
+
totalMatches++;
|
|
1910
|
+
const matchFile = line.split(':')[0];
|
|
1911
|
+
if (matchFile)
|
|
1912
|
+
matchedFiles.add(prefix ? `${prefix}${matchFile}` : matchFile);
|
|
1913
|
+
if (allResults.length < MAX_SHOWN_MATCHES) {
|
|
1747
1914
|
// Lines are in format "./path:lineNum:content" — prepend alias prefix
|
|
1748
1915
|
allResults.push(prefix ? line.replace(/^\.?\//, `@${alias}/`) : line);
|
|
1749
1916
|
}
|
|
@@ -1752,9 +1919,16 @@ async function crossWorkspaceGrep(primaryRoot, pattern, fileGlob, fixedStrings,
|
|
|
1752
1919
|
if (allResults.length === 0) {
|
|
1753
1920
|
return { output: `No matches found for "${pattern}" across all workspaces.` };
|
|
1754
1921
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1922
|
+
let resultText = allResults.join('\n');
|
|
1923
|
+
if (totalMatches > allResults.length) {
|
|
1924
|
+
resultText += `\n\n[Showing ${allResults.length}/${totalMatches} matches across ${matchedFiles.size} files in registered workspaces. Refine query to narrow results.]`;
|
|
1925
|
+
}
|
|
1926
|
+
const windowedResult = truncateWithHeadTailWindow(resultText, {
|
|
1927
|
+
maxChars: 30_000,
|
|
1928
|
+
receiptLabel: 'Cross-workspace grep results',
|
|
1929
|
+
hint: 'Refine query to narrow results.',
|
|
1930
|
+
});
|
|
1931
|
+
const wrappedResult = `<workspace_file path="grep_search_results">\n<content_data><![CDATA[\n${sanitizeForCDATA(windowedResult)}\n]]\\u200B></content_data>\n</workspace_file>`;
|
|
1758
1932
|
return { output: wrappedResult };
|
|
1759
1933
|
}
|
|
1760
1934
|
const currentTasksByAgent = new Map();
|
|
@@ -1946,7 +2120,10 @@ export async function executeTool(workspaceRoot, toolName, args, abortSignal) {
|
|
|
1946
2120
|
result = await runCommand(effectiveRoot, resolvedArgs.command, abortSignal);
|
|
1947
2121
|
break;
|
|
1948
2122
|
case 'run_debug_script':
|
|
1949
|
-
|
|
2123
|
+
case 'debug_script':
|
|
2124
|
+
case 'run_analysis_script':
|
|
2125
|
+
case 'analysis_script':
|
|
2126
|
+
result = await runDebugScript(effectiveRoot, resolvedArgs.language || 'auto', resolvedArgs.code, abortSignal);
|
|
1950
2127
|
break;
|
|
1951
2128
|
case 'grep_search': {
|
|
1952
2129
|
const wsParam = resolvedArgs.workspace;
|
package/dist/services/agent.js
CHANGED
|
@@ -32,7 +32,7 @@ import { changeLogger } from './changeLogger.js';
|
|
|
32
32
|
import { chatHistoryService } from './chatHistoryService.js';
|
|
33
33
|
import { gatherContext, routeIntent, evaluateExecutionComplexity } from './contextAgent.js';
|
|
34
34
|
import { verifyChangedFiles } from './verificationService.js';
|
|
35
|
-
import {
|
|
35
|
+
import { buildTieredContextInjection, CONTEXT_BUDGET_CONFIG } from '../utils/contextPrompts.js';
|
|
36
36
|
import { registerContextFiles } from '../utils/fileReadGuard.js';
|
|
37
37
|
import { historyText } from '../utils/historyPrompt.js';
|
|
38
38
|
import { loadUserProfile, formatUserProfileForContext, extractAndSaveUserInsights } from './userProfileService.js';
|
|
@@ -391,8 +391,11 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
391
391
|
if (gatherRes.contextResult) {
|
|
392
392
|
// Compress each relevant file individually using helper to avoid nested loop warning
|
|
393
393
|
gatherRes.contextResult.relevantFiles = await compressContextFiles(workspaceRoot, gatherRes.contextResult, ac.signal);
|
|
394
|
-
// Assemble the final context injection string
|
|
395
|
-
const contextInjection =
|
|
394
|
+
// Assemble the final context injection string using 3-tier IR/graph context ranking
|
|
395
|
+
const contextInjection = buildTieredContextInjection(gatherRes.contextResult, {
|
|
396
|
+
prompt: userInput,
|
|
397
|
+
maxChars: CONTEXT_BUDGET_CONFIG.DEFAULT_CONTEXT_MAX_CHARS,
|
|
398
|
+
});
|
|
396
399
|
debugLog(`Final compressed context injection size: ${contextInjection.length} chars`);
|
|
397
400
|
// Pre-register all injected files with the read-guard so the execution
|
|
398
401
|
// agent is allowed to modify them without calling read_file first.
|
package/dist/services/ai.d.ts
CHANGED
|
@@ -18,6 +18,9 @@ export declare function setModelThinkingLevel(model: string, level: ThinkingLeve
|
|
|
18
18
|
* Resets user-configured thinking levels back to default model presets.
|
|
19
19
|
*/
|
|
20
20
|
export declare function resetModelThinkingLevels(): void;
|
|
21
|
+
export declare const HISTORICAL_TOOL_OUTPUT_THRESHOLD = 1500;
|
|
22
|
+
export declare const COLLAPSED_TOOL_OUTPUT_MARKER = "\n... [Historical tool output collapsed to save context]";
|
|
23
|
+
export declare function collapseHistoricalOutput(val: string, threshold?: number): string;
|
|
21
24
|
export declare class ProxyChatSession {
|
|
22
25
|
private history;
|
|
23
26
|
private fullHistory;
|
package/dist/services/ai.js
CHANGED
|
@@ -100,9 +100,9 @@ const MAX_HISTORY_ENTRIES = 500;
|
|
|
100
100
|
* payload stays within sane memory bounds.
|
|
101
101
|
*/
|
|
102
102
|
const MAX_PART_TEXT_LENGTH = 60_000;
|
|
103
|
-
const HISTORICAL_TOOL_OUTPUT_THRESHOLD = 1500;
|
|
104
|
-
const COLLAPSED_TOOL_OUTPUT_MARKER = '\n... [Historical tool output collapsed to save context]';
|
|
105
|
-
function collapseHistoricalOutput(val, threshold = HISTORICAL_TOOL_OUTPUT_THRESHOLD) {
|
|
103
|
+
export const HISTORICAL_TOOL_OUTPUT_THRESHOLD = 1500;
|
|
104
|
+
export const COLLAPSED_TOOL_OUTPUT_MARKER = '\n... [Historical tool output collapsed to save context]';
|
|
105
|
+
export function collapseHistoricalOutput(val, threshold = HISTORICAL_TOOL_OUTPUT_THRESHOLD) {
|
|
106
106
|
if (typeof val !== 'string')
|
|
107
107
|
return String(val ?? '');
|
|
108
108
|
if (val.length <= threshold || val.includes('[Historical tool output collapsed')) {
|
|
@@ -354,20 +354,10 @@ export class ProxyChatSession {
|
|
|
354
354
|
const funcResp = part.functionResponse;
|
|
355
355
|
if (funcResp.response && typeof funcResp.response === 'object') {
|
|
356
356
|
const respObj = funcResp.response;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
respObj.error = collapseHistoricalOutput(respObj.error, threshold);
|
|
362
|
-
}
|
|
363
|
-
if (typeof respObj.result === 'string') {
|
|
364
|
-
respObj.result = collapseHistoricalOutput(respObj.result, threshold);
|
|
365
|
-
}
|
|
366
|
-
if (typeof respObj.stdout === 'string') {
|
|
367
|
-
respObj.stdout = collapseHistoricalOutput(respObj.stdout, threshold);
|
|
368
|
-
}
|
|
369
|
-
if (typeof respObj.stderr === 'string') {
|
|
370
|
-
respObj.stderr = collapseHistoricalOutput(respObj.stderr, threshold);
|
|
357
|
+
for (const key of Object.keys(respObj)) {
|
|
358
|
+
if (typeof respObj[key] === 'string') {
|
|
359
|
+
respObj[key] = collapseHistoricalOutput(respObj[key], threshold);
|
|
360
|
+
}
|
|
371
361
|
}
|
|
372
362
|
}
|
|
373
363
|
}
|
|
@@ -701,7 +691,17 @@ export function getContextToolDeclarations() {
|
|
|
701
691
|
},
|
|
702
692
|
{
|
|
703
693
|
name: 'run_analysis_script',
|
|
704
|
-
description: 'Write and execute a disposable analysis script to structurally map code in the workspace.
|
|
694
|
+
description: 'Write and execute a disposable analysis script to structurally map code in the workspace. ' +
|
|
695
|
+
'Sandbox Features: ' +
|
|
696
|
+
'(1) Preloaded Helpers: "emitResult(data)" / "__emitResult(data)" sends structured JSON payloads directly to structuredResult without manual stdout parsing; "inspectSymbols(target)" / "inspectObject(target)" inspects functions, classes, and properties. ' +
|
|
697
|
+
'(2) Module & Path Resolution: Automatically inherits tsconfig.json path aliases (@/*), NODE_PATH, and workspace virtualenvs (.venv, venv) for Python. ' +
|
|
698
|
+
'(3) Diagnostics Middleware: Provides actionable [SANDBOX DIAGNOSTIC] advisories for missing imports, ESM/CJS interop, and compiler errors. ' +
|
|
699
|
+
'Use this to get exact line ranges for functions, classes, and variables by leveraging the language\'s native AST parser (e.g., TypeScript compiler API, Python ast module, go/parser). ' +
|
|
700
|
+
'You can also use this to probe the development environment — detecting available runtimes (e.g., node --version, python3 --version), checking if ports are in use, identifying project type (monorepo, package manager), or diagnosing system-level issues (disk space, memory) that may affect execution. ' +
|
|
701
|
+
'For complex investigation tasks, you can write lightweight ML scripts (e.g., TF-IDF cosine similarity to rank file relevance, Z-score outlier detection for anomalous log lines, K-Means clustering, or Naive Bayes classification). ' +
|
|
702
|
+
'Default to "node" for generic math/analysis as a safe baseline, but act like a native inhabitant of the host environment — if Python, Go, Rust, or specialized libraries are available in the project context, leverage the host\'s native runtimes and standard libraries for maximum efficiency. ' +
|
|
703
|
+
'The script is executed from a temporary directory and automatically cleaned up after execution. ' +
|
|
704
|
+
'Use the results to make precise read_file calls with exact startLine/endLine instead of guessing. CRITICAL: Do not use this tool on binary, document, or non-code files (e.g. PDF, image, audio, docx).',
|
|
705
705
|
parameters: {
|
|
706
706
|
type: SchemaType.OBJECT,
|
|
707
707
|
properties: {
|
|
@@ -711,7 +711,7 @@ export function getContextToolDeclarations() {
|
|
|
711
711
|
},
|
|
712
712
|
code: {
|
|
713
713
|
type: SchemaType.STRING,
|
|
714
|
-
description: 'The analysis script code. Should output structured JSON to stdout with structural information (name, type, startLine, endLine for each code element).',
|
|
714
|
+
description: 'The analysis script code. Should output structured JSON to stdout or use emitResult(data) with structural information (name, type, startLine, endLine for each code element).',
|
|
715
715
|
},
|
|
716
716
|
targetFile: {
|
|
717
717
|
type: SchemaType.STRING,
|
|
@@ -757,13 +757,14 @@ export function createContextAgentSession() {
|
|
|
757
757
|
let model = contextModelOverride || getGlobalActiveModel();
|
|
758
758
|
if (model === 'auto' || model.includes('claude'))
|
|
759
759
|
model = GEMINI_MODELS.FLASH;
|
|
760
|
+
const thinkingLevel = getModelThinkingLevel(model);
|
|
760
761
|
return new ProxyChatSession(model, CONTEXT_SYSTEM_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()), contextTools, {
|
|
761
762
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
762
763
|
temperature: contextTempOverride !== null ? contextTempOverride : 1,
|
|
763
764
|
topP: 0.95,
|
|
764
765
|
topK: 40,
|
|
765
766
|
thinkingConfig: {
|
|
766
|
-
thinkingLevel
|
|
767
|
+
thinkingLevel,
|
|
767
768
|
},
|
|
768
769
|
}, {
|
|
769
770
|
functionCallingConfig: {
|
|
@@ -1108,6 +1109,50 @@ export function createUserProfileExtractorSession() {
|
|
|
1108
1109
|
},
|
|
1109
1110
|
description: 'Observed cognitive decision-making, collaboration, and problem-solving traits',
|
|
1110
1111
|
},
|
|
1112
|
+
conversationalPersona: {
|
|
1113
|
+
type: SchemaType.OBJECT,
|
|
1114
|
+
properties: {
|
|
1115
|
+
relationshipModel: {
|
|
1116
|
+
type: SchemaType.STRING,
|
|
1117
|
+
description: 'e.g., "collaborative-peer", "command-operator", "rubber-duck", "socratic-explorer"',
|
|
1118
|
+
},
|
|
1119
|
+
banterAffinity: {
|
|
1120
|
+
type: SchemaType.STRING,
|
|
1121
|
+
description: 'e.g., "witty-banter", "dry-professional", "warm-encouraging"',
|
|
1122
|
+
},
|
|
1123
|
+
formalityLevel: {
|
|
1124
|
+
type: SchemaType.STRING,
|
|
1125
|
+
description: 'e.g., "casual-slang", "telegraphic-concise", "polite-cordial"',
|
|
1126
|
+
},
|
|
1127
|
+
apologyTolerance: {
|
|
1128
|
+
type: SchemaType.STRING,
|
|
1129
|
+
description: 'e.g., "zero-apologies", "tolerant-empathetic"',
|
|
1130
|
+
},
|
|
1131
|
+
stressCadence: {
|
|
1132
|
+
type: SchemaType.STRING,
|
|
1133
|
+
description: 'e.g., "urgent-surgical", "calm-exploratory"',
|
|
1134
|
+
},
|
|
1135
|
+
promptingHabit: {
|
|
1136
|
+
type: SchemaType.STRING,
|
|
1137
|
+
description: 'e.g., "code-dump-deducer", "bulleted-architect", "stream-of-consciousness", "rapid-breadcrumbs"',
|
|
1138
|
+
},
|
|
1139
|
+
conversationalQuirks: {
|
|
1140
|
+
type: SchemaType.ARRAY,
|
|
1141
|
+
items: {
|
|
1142
|
+
type: SchemaType.STRING,
|
|
1143
|
+
},
|
|
1144
|
+
description: 'Observed recurring catchphrases, quirks, or unique conversational habits',
|
|
1145
|
+
},
|
|
1146
|
+
removeQuirks: {
|
|
1147
|
+
type: SchemaType.ARRAY,
|
|
1148
|
+
items: {
|
|
1149
|
+
type: SchemaType.STRING,
|
|
1150
|
+
},
|
|
1151
|
+
description: 'Outdated or superseded conversational quirks to prune',
|
|
1152
|
+
},
|
|
1153
|
+
},
|
|
1154
|
+
description: 'Observed interpersonal, psychological, and conversational pairing dynamics',
|
|
1155
|
+
},
|
|
1111
1156
|
strengths: {
|
|
1112
1157
|
type: SchemaType.ARRAY,
|
|
1113
1158
|
items: {
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
import type { TierPartitionResult } from '../utils/contextRanker.js';
|
|
2
|
+
export interface ContextFileEntry {
|
|
3
|
+
text: string;
|
|
4
|
+
inlineData?: any;
|
|
5
|
+
scoped?: boolean;
|
|
6
|
+
tier?: 1 | 2 | 3;
|
|
7
|
+
outline?: string;
|
|
8
|
+
}
|
|
1
9
|
export interface ContextAgentResult {
|
|
2
10
|
projectTree: string;
|
|
3
11
|
projectType: string;
|
|
4
|
-
relevantFiles: Map<string,
|
|
5
|
-
text: string;
|
|
6
|
-
inlineData?: any;
|
|
7
|
-
}>;
|
|
12
|
+
relevantFiles: Map<string, ContextFileEntry>;
|
|
8
13
|
summary: string;
|
|
9
14
|
webSearchSummary?: string;
|
|
10
15
|
fromMemoryBank?: boolean;
|
|
11
16
|
isParallel?: boolean;
|
|
17
|
+
tierPartition?: TierPartitionResult;
|
|
12
18
|
}
|
|
13
19
|
export declare function detectProjectType(workspaceRoot: string): Promise<string>;
|
|
14
20
|
export interface IntentRoute {
|