minovative-mind-cli 2.11.4 → 2.12.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/README.md +21 -7
- package/dist/commands/eval.d.ts +22 -0
- package/dist/commands/eval.js +141 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/services/agent/toolLoop.d.ts +4 -0
- package/dist/services/agent/toolLoop.js +61 -10
- package/dist/services/agent-tools.d.ts +5 -5
- package/dist/services/agent-tools.js +147 -9
- package/dist/services/ai.d.ts +1 -1
- package/dist/services/ai.js +40 -7
- package/dist/services/contextAgent.d.ts +1 -0
- package/dist/services/contextAgent.js +29 -6
- package/dist/services/investigationComplexity.d.ts +39 -13
- package/dist/services/investigationComplexity.js +325 -46
- package/dist/services/metrics.d.ts +10 -0
- package/dist/services/metrics.js +24 -0
- package/dist/services/orchestration/scopedTools.d.ts +27 -50
- package/dist/services/orchestration/scopedTools.js +60 -18
- package/dist/services/swebench/gitDiffExtractor.d.ts +57 -0
- package/dist/services/swebench/gitDiffExtractor.js +209 -0
- package/dist/services/swebench/index.d.ts +4 -0
- package/dist/services/swebench/index.js +4 -0
- package/dist/services/swebench/instanceLoader.d.ts +21 -0
- package/dist/services/swebench/instanceLoader.js +171 -0
- package/dist/services/swebench/sweBenchRunnerService.d.ts +38 -0
- package/dist/services/swebench/sweBenchRunnerService.js +618 -0
- package/dist/services/swebench/types.d.ts +167 -0
- package/dist/services/swebench/types.js +7 -0
- package/dist/services/verificationService.js +3 -0
- package/dist/services/workspaceRegistry.d.ts +81 -8
- package/dist/services/workspaceRegistry.js +222 -34
- package/dist/utils/analysisRunner.js +2 -1
- package/dist/utils/pathSecurity.d.ts +56 -14
- package/dist/utils/pathSecurity.js +120 -39
- package/dist/utils/systemPrompts.d.ts +6 -6
- package/dist/utils/systemPrompts.js +46 -25
- package/oclif.manifest.json +137 -1
- package/package.json +1 -1
|
@@ -11,91 +11,370 @@
|
|
|
11
11
|
* has already determined that context gathering is needed (SEARCH).
|
|
12
12
|
*/
|
|
13
13
|
import { createInvestigationComplexitySession } from './ai.js';
|
|
14
|
+
import { workspaceRegistry } from './workspaceRegistry.js';
|
|
14
15
|
import { debugLog } from '../utils/logger.js';
|
|
15
|
-
// ───
|
|
16
|
+
// ─── Helper Functions ────────────────────────────────────────────────
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
+
* Checks whether the user's prompt contains an explicit path or workspace override
|
|
19
|
+
* that supersedes default primary sub-path auto-focusing.
|
|
18
20
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
|
|
21
|
+
* @param userRequest - The prompt text from the user
|
|
22
|
+
* @param activeSubPath - The currently active primary sub-path (if any)
|
|
23
|
+
* @returns The detected override identifier or null if no override exists
|
|
24
|
+
*/
|
|
25
|
+
export function detectSubPathOverride(userRequest, activeSubPath) {
|
|
26
|
+
if (!userRequest)
|
|
27
|
+
return null;
|
|
28
|
+
// Check for external workspace alias syntax (e.g. "@backend/...", "@calc", etc.)
|
|
29
|
+
const aliasMatch = userRequest.match(/@([a-zA-Z0-9_\-]+)(\/|\s|$)/);
|
|
30
|
+
if (aliasMatch) {
|
|
31
|
+
return `@${aliasMatch[1]}`;
|
|
32
|
+
}
|
|
33
|
+
// Check for explicit root-level or full-codebase directives
|
|
34
|
+
const lower = userRequest.toLowerCase();
|
|
35
|
+
if (lower.includes('whole project') ||
|
|
36
|
+
lower.includes('entire codebase') ||
|
|
37
|
+
lower.includes('full codebase') ||
|
|
38
|
+
lower.includes('across workspaces') ||
|
|
39
|
+
lower.includes('all workspaces') ||
|
|
40
|
+
lower.includes('root directory') ||
|
|
41
|
+
lower.includes('from root') ||
|
|
42
|
+
lower.includes('@root') ||
|
|
43
|
+
lower.includes('entire project') ||
|
|
44
|
+
lower.includes('entire repo') ||
|
|
45
|
+
lower.includes('all packages') ||
|
|
46
|
+
lower.includes('all modules') ||
|
|
47
|
+
lower.includes('across the project') ||
|
|
48
|
+
lower.includes('across the codebase') ||
|
|
49
|
+
lower.includes('every workspace')) {
|
|
50
|
+
return 'root';
|
|
51
|
+
}
|
|
52
|
+
// If an active sub-path is present (e.g. "src" or "packages/core"), check if root files outside it are targeted
|
|
53
|
+
if (activeSubPath) {
|
|
54
|
+
const rootFiles = [
|
|
55
|
+
// Package Managers & Dependencies
|
|
56
|
+
'package.json',
|
|
57
|
+
'package-lock.json',
|
|
58
|
+
'yarn.lock',
|
|
59
|
+
'pnpm-lock.yaml',
|
|
60
|
+
'pnpm-workspace.yaml',
|
|
61
|
+
'bun.lockb',
|
|
62
|
+
'bunfig.toml',
|
|
63
|
+
'cargo.toml',
|
|
64
|
+
'cargo.lock',
|
|
65
|
+
'go.mod',
|
|
66
|
+
'go.sum',
|
|
67
|
+
'go.work',
|
|
68
|
+
'pyproject.toml',
|
|
69
|
+
'requirements.txt',
|
|
70
|
+
'requirements-dev.txt',
|
|
71
|
+
'pipfile',
|
|
72
|
+
'pipfile.lock',
|
|
73
|
+
'setup.py',
|
|
74
|
+
'setup.cfg',
|
|
75
|
+
'poetry.lock',
|
|
76
|
+
'gemfile',
|
|
77
|
+
'gemfile.lock',
|
|
78
|
+
'composer.json',
|
|
79
|
+
'composer.lock',
|
|
80
|
+
'pom.xml',
|
|
81
|
+
'build.gradle',
|
|
82
|
+
'build.gradle.kts',
|
|
83
|
+
'settings.gradle',
|
|
84
|
+
'settings.gradle.kts',
|
|
85
|
+
'package.swift',
|
|
86
|
+
// Compilers, Bundlers & Frameworks
|
|
87
|
+
'tsconfig.json',
|
|
88
|
+
'jsconfig.json',
|
|
89
|
+
'next.config.ts',
|
|
90
|
+
'next.config.js',
|
|
91
|
+
'next.config.mjs',
|
|
92
|
+
'vite.config.ts',
|
|
93
|
+
'vite.config.js',
|
|
94
|
+
'vite.config.mjs',
|
|
95
|
+
'webpack.config.js',
|
|
96
|
+
'webpack.config.ts',
|
|
97
|
+
'rollup.config.js',
|
|
98
|
+
'rollup.config.ts',
|
|
99
|
+
'turbo.json',
|
|
100
|
+
'lerna.json',
|
|
101
|
+
'nx.json',
|
|
102
|
+
'babel.config.js',
|
|
103
|
+
'babel.config.json',
|
|
104
|
+
'.babelrc',
|
|
105
|
+
'postcss.config.js',
|
|
106
|
+
'tailwind.config.js',
|
|
107
|
+
'tailwind.config.ts',
|
|
108
|
+
'tailwind.config.mjs',
|
|
109
|
+
// Testing & Quality / Linters
|
|
110
|
+
'vitest.config.ts',
|
|
111
|
+
'vitest.config.mts',
|
|
112
|
+
'vitest.config.js',
|
|
113
|
+
'jest.config.js',
|
|
114
|
+
'jest.config.ts',
|
|
115
|
+
'jest.config.mjs',
|
|
116
|
+
'pytest.ini',
|
|
117
|
+
'tox.ini',
|
|
118
|
+
'.eslintrc',
|
|
119
|
+
'.eslintrc.json',
|
|
120
|
+
'.eslintrc.js',
|
|
121
|
+
'.eslintrc.cjs',
|
|
122
|
+
'eslint.config.js',
|
|
123
|
+
'eslint.config.mjs',
|
|
124
|
+
'eslint.config.cjs',
|
|
125
|
+
'eslint.config.ts',
|
|
126
|
+
'.prettierrc',
|
|
127
|
+
'.prettierrc.json',
|
|
128
|
+
'.prettierrc.js',
|
|
129
|
+
'prettier.config.js',
|
|
130
|
+
'prettier.config.mjs',
|
|
131
|
+
'biome.json',
|
|
132
|
+
'ruff.toml',
|
|
133
|
+
'.flake8',
|
|
134
|
+
'mypy.ini',
|
|
135
|
+
'playwright.config.ts',
|
|
136
|
+
'playwright.config.js',
|
|
137
|
+
'cypress.config.ts',
|
|
138
|
+
'cypress.config.js',
|
|
139
|
+
// C / C++ / Build Systems
|
|
140
|
+
'cmakelists.txt',
|
|
141
|
+
'makefile',
|
|
142
|
+
'gnumakefile',
|
|
143
|
+
'meson.build',
|
|
144
|
+
'rakefile',
|
|
145
|
+
// Cloud, Containers, Deployments & CI/CD
|
|
146
|
+
'dockerfile',
|
|
147
|
+
'containerfile',
|
|
148
|
+
'docker-compose.yml',
|
|
149
|
+
'docker-compose.yaml',
|
|
150
|
+
'compose.yaml',
|
|
151
|
+
'compose.yml',
|
|
152
|
+
'.dockerignore',
|
|
153
|
+
'fly.toml',
|
|
154
|
+
'vercel.json',
|
|
155
|
+
'netlify.toml',
|
|
156
|
+
'wrangler.toml',
|
|
157
|
+
'wrangler.json',
|
|
158
|
+
'firebase.json',
|
|
159
|
+
'firestore.rules',
|
|
160
|
+
'firestore.indexes.json',
|
|
161
|
+
'storage.rules',
|
|
162
|
+
'serverless.yml',
|
|
163
|
+
'procfile',
|
|
164
|
+
'app.yaml',
|
|
165
|
+
'cloudbuild.yaml',
|
|
166
|
+
'jenkinsfile',
|
|
167
|
+
'.gitlab-ci.yml',
|
|
168
|
+
// Environments & System Config
|
|
169
|
+
'.env',
|
|
170
|
+
'.env.local',
|
|
171
|
+
'.env.development',
|
|
172
|
+
'.env.production',
|
|
173
|
+
'.env.staging',
|
|
174
|
+
'.env.example',
|
|
175
|
+
'.env.test',
|
|
176
|
+
'.gitignore',
|
|
177
|
+
'.gitattributes',
|
|
178
|
+
'.editorconfig',
|
|
179
|
+
// Documentation & Project Metadata
|
|
180
|
+
'readme.md',
|
|
181
|
+
'contributing.md',
|
|
182
|
+
'changelog.md',
|
|
183
|
+
'license',
|
|
184
|
+
'license.md',
|
|
185
|
+
'architecture.md',
|
|
186
|
+
'features.md',
|
|
187
|
+
'roadmap.md',
|
|
188
|
+
];
|
|
189
|
+
for (const rf of rootFiles) {
|
|
190
|
+
if (lower.includes(rf)) {
|
|
191
|
+
return rf;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
// ─── Main Evaluator ──────────────────────────────────────────────────
|
|
198
|
+
/**
|
|
199
|
+
* Evaluates whether a user request warrants parallel investigation or a single agent.
|
|
200
|
+
* Respects default primary sub-path auto-focusing while allowing explicit overrides.
|
|
23
201
|
*
|
|
24
|
-
* @param userRequest - The user's prompt
|
|
25
|
-
* @param projectType - Detected project type (e.g., "Node.js / TypeScript
|
|
26
|
-
* @param approximateFileCount -
|
|
27
|
-
* @param chatHistory -
|
|
28
|
-
* @
|
|
202
|
+
* @param userRequest - The user's prompt/request
|
|
203
|
+
* @param projectType - Detected project type string (e.g., "Node.js / TypeScript")
|
|
204
|
+
* @param approximateFileCount - Approximate total file count in the project
|
|
205
|
+
* @param chatHistory - Formatted recent conversation history (optional)
|
|
206
|
+
* @param abortSignal - Optional signal to abort the LLM request
|
|
207
|
+
* @param options - Optional sub-path auto-focus and override configuration
|
|
208
|
+
* @returns Structured complexity result with strategy and domain assignments
|
|
29
209
|
*/
|
|
30
|
-
export async function evaluateInvestigationComplexity(userRequest, projectType, approximateFileCount, chatHistory = '', abortSignal) {
|
|
210
|
+
export async function evaluateInvestigationComplexity(userRequest, projectType, approximateFileCount, chatHistory = '', abortSignal, options) {
|
|
31
211
|
if (abortSignal?.aborted) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
throw
|
|
212
|
+
const error = new Error('The operation was aborted');
|
|
213
|
+
error.name = 'AbortError';
|
|
214
|
+
throw error;
|
|
35
215
|
}
|
|
216
|
+
const configuredSubPath = options?.autoFocusSubPath !== undefined
|
|
217
|
+
? options.autoFocusSubPath
|
|
218
|
+
: workspaceRegistry.getPrimarySubPath();
|
|
219
|
+
const activeSubPath = options?.disableAutoFocus ? null : configuredSubPath;
|
|
220
|
+
const explicitOverride = options?.subPathOverride ?? detectSubPathOverride(userRequest, activeSubPath);
|
|
221
|
+
const isAutoFocused = Boolean(activeSubPath && !explicitOverride);
|
|
36
222
|
try {
|
|
37
|
-
const session = createInvestigationComplexitySession();
|
|
223
|
+
const session = await createInvestigationComplexitySession();
|
|
38
224
|
let prompt = `User Request: "${userRequest}"
|
|
39
225
|
Project Type: ${projectType}
|
|
40
226
|
Approximate File Count: ${approximateFileCount}`;
|
|
41
|
-
if (
|
|
42
|
-
|
|
227
|
+
if (activeSubPath) {
|
|
228
|
+
if (explicitOverride) {
|
|
229
|
+
prompt += `\nConfigured Primary Sub-Path: ${activeSubPath}\nSub-Path Override: Active (${explicitOverride}) - scope investigation to requested override.`;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
prompt += `\nConfigured Primary Sub-Path: ${activeSubPath}\nSub-Path Auto-Focus: Active - prioritize and decompose investigation within "${activeSubPath}" unless user request requires broader exploration.`;
|
|
233
|
+
}
|
|
43
234
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
debugLog(`
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
235
|
+
if (chatHistory.trim()) {
|
|
236
|
+
prompt += `\n\nRecent Conversation:\n${chatHistory.trim()}`;
|
|
237
|
+
}
|
|
238
|
+
debugLog(`[InvestigationComplexity] Evaluating prompt complexity (autoFocus: ${activeSubPath || 'none'}, override: ${explicitOverride || 'none'})`);
|
|
239
|
+
const response = await session.sendMessage(prompt, undefined, abortSignal);
|
|
240
|
+
const rawText = typeof response?.response?.text === 'function'
|
|
241
|
+
? response.response.text()
|
|
242
|
+
: typeof response?.text === 'function'
|
|
243
|
+
? response.text()
|
|
244
|
+
: response?.text || '';
|
|
245
|
+
// Clean JSON response (strip markdown fences if present)
|
|
246
|
+
const cleaned = rawText.replace(/```(?:json)?\s*([\s\S]*?)```/g, '$1').trim();
|
|
247
|
+
const parsed = JSON.parse(cleaned);
|
|
248
|
+
// Determine semantic scope and override from AI response with fast token precedence
|
|
249
|
+
let finalScope = 'SUB_PATH';
|
|
250
|
+
let finalOverride = explicitOverride;
|
|
251
|
+
if (parsed.scope === 'FULL_WORKSPACE') {
|
|
252
|
+
finalScope = 'FULL_WORKSPACE';
|
|
253
|
+
if (!finalOverride)
|
|
254
|
+
finalOverride = parsed.subPathOverride || 'root';
|
|
255
|
+
}
|
|
256
|
+
else if (parsed.scope === 'EXTERNAL_WORKSPACE') {
|
|
257
|
+
finalScope = 'EXTERNAL_WORKSPACE';
|
|
258
|
+
if (!finalOverride)
|
|
259
|
+
finalOverride = parsed.subPathOverride || '@alias';
|
|
260
|
+
}
|
|
261
|
+
else if (parsed.scope === 'SUB_PATH') {
|
|
262
|
+
finalScope = 'SUB_PATH';
|
|
263
|
+
if (!options?.subPathOverride)
|
|
264
|
+
finalOverride = null;
|
|
265
|
+
}
|
|
266
|
+
else if (parsed.subPathOverride && !finalOverride) {
|
|
267
|
+
finalOverride = parsed.subPathOverride;
|
|
268
|
+
finalScope = (finalOverride && finalOverride.startsWith('@')) ? 'EXTERNAL_WORKSPACE' : 'FULL_WORKSPACE';
|
|
269
|
+
}
|
|
270
|
+
const finalIsAutoFocused = Boolean(activeSubPath && !finalOverride);
|
|
271
|
+
const rawStrategy = typeof parsed.strategy === 'string' ? parsed.strategy.toUpperCase() : '';
|
|
272
|
+
const rawDomains = Array.isArray(parsed.domains)
|
|
273
|
+
? parsed.domains.map(String).filter(Boolean)
|
|
274
|
+
: [];
|
|
275
|
+
const rawAssignments = Array.isArray(parsed.agentAssignments) ? parsed.agentAssignments : [];
|
|
276
|
+
// Permissive strategy determination: trigger PARALLEL if explicitly requested OR if multiple domains/assignments exist
|
|
277
|
+
const isParallel = rawStrategy === 'PARALLEL' || rawAssignments.length >= 2 || rawDomains.length >= 2;
|
|
278
|
+
// If SINGLE without multi-domain signals, return SINGLE
|
|
279
|
+
if (!isParallel) {
|
|
280
|
+
debugLog(`[InvestigationComplexity] Strategy: SINGLE (Scope: ${finalScope}, Reason: ${parsed.reasoning || 'N/A'})`);
|
|
51
281
|
return {
|
|
52
282
|
strategy: 'SINGLE',
|
|
283
|
+
scope: finalScope,
|
|
53
284
|
domains: [],
|
|
54
285
|
agentAssignments: [],
|
|
55
|
-
reasoning: parsed.reasoning || '
|
|
286
|
+
reasoning: parsed.reasoning || 'Localized prompt — single agent sufficient.',
|
|
287
|
+
focusedSubPath: activeSubPath,
|
|
288
|
+
subPathOverride: finalOverride,
|
|
289
|
+
isAutoFocused: finalIsAutoFocused,
|
|
56
290
|
};
|
|
57
291
|
}
|
|
58
|
-
// Validate
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
67
|
-
}
|
|
292
|
+
// Validate agent assignments for PARALLEL
|
|
293
|
+
let agentAssignments = [];
|
|
294
|
+
for (const a of rawAssignments) {
|
|
295
|
+
if (typeof a?.agentLabel === 'string' && Array.isArray(a?.domains) && a.domains.length > 0) {
|
|
296
|
+
agentAssignments.push({
|
|
297
|
+
agentLabel: a.agentLabel.trim(),
|
|
298
|
+
domains: a.domains.map(String).filter(Boolean),
|
|
299
|
+
});
|
|
68
300
|
}
|
|
69
301
|
}
|
|
70
|
-
//
|
|
302
|
+
// Permissive Auto-Recovery: if agentAssignments was missing/incomplete but multiple domains were identified
|
|
303
|
+
if (agentAssignments.length < 2 && rawDomains.length >= 2) {
|
|
304
|
+
debugLog('[InvestigationComplexity] Auto-constructing agent assignments from identified domains');
|
|
305
|
+
if (rawDomains.length === 2) {
|
|
306
|
+
agentAssignments = rawDomains.map((d) => ({
|
|
307
|
+
agentLabel: `${d} Specialist`,
|
|
308
|
+
domains: [d],
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
const mid = Math.ceil(rawDomains.length / 2);
|
|
313
|
+
agentAssignments = [
|
|
314
|
+
{
|
|
315
|
+
agentLabel: `${rawDomains[0]} & Subsystems`,
|
|
316
|
+
domains: rawDomains.slice(0, mid),
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
agentLabel: `${rawDomains[mid]} & Related`,
|
|
320
|
+
domains: rawDomains.slice(mid),
|
|
321
|
+
},
|
|
322
|
+
];
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// If still fewer than 2 valid assignments after auto-recovery, fall back to SINGLE
|
|
71
326
|
if (agentAssignments.length < 2) {
|
|
72
|
-
debugLog('
|
|
327
|
+
debugLog('[InvestigationComplexity] PARALLEL requested but <2 valid assignments — falling back to SINGLE');
|
|
73
328
|
return {
|
|
74
329
|
strategy: 'SINGLE',
|
|
330
|
+
scope: finalScope,
|
|
75
331
|
domains: [],
|
|
76
332
|
agentAssignments: [],
|
|
77
|
-
reasoning:
|
|
333
|
+
reasoning: parsed.reasoning || 'Insufficient domain separation for parallel investigation.',
|
|
334
|
+
focusedSubPath: activeSubPath,
|
|
335
|
+
subPathOverride: finalOverride,
|
|
336
|
+
isAutoFocused: finalIsAutoFocused,
|
|
78
337
|
};
|
|
79
338
|
}
|
|
339
|
+
let allDomains = rawDomains;
|
|
340
|
+
if (allDomains.length === 0 && agentAssignments.length > 0) {
|
|
341
|
+
allDomains = Array.from(new Set(agentAssignments.flatMap((a) => a.domains)));
|
|
342
|
+
}
|
|
343
|
+
debugLog(`[InvestigationComplexity] Strategy: PARALLEL with ${agentAssignments.length} agents: ${agentAssignments.map(a => a.agentLabel).join(', ')} (Scope: ${finalScope})`);
|
|
80
344
|
return {
|
|
81
345
|
strategy: 'PARALLEL',
|
|
82
|
-
|
|
346
|
+
scope: finalScope,
|
|
347
|
+
domains: allDomains,
|
|
83
348
|
agentAssignments,
|
|
84
|
-
reasoning: parsed.reasoning || '',
|
|
349
|
+
reasoning: parsed.reasoning || 'Multi-domain parallel investigation dispatched.',
|
|
350
|
+
focusedSubPath: activeSubPath,
|
|
351
|
+
subPathOverride: finalOverride,
|
|
352
|
+
isAutoFocused: finalIsAutoFocused,
|
|
85
353
|
};
|
|
86
354
|
}
|
|
87
|
-
catch (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
err
|
|
355
|
+
catch (err) {
|
|
356
|
+
// If aborted, rethrow
|
|
357
|
+
if (abortSignal?.aborted ||
|
|
358
|
+
err?.name === 'AbortError' ||
|
|
359
|
+
err?.name === 'CanceledError' ||
|
|
360
|
+
err?.code === 'ABORT_ERR' ||
|
|
361
|
+
err?.message?.includes('aborted') ||
|
|
362
|
+
err?.message?.includes('abort') ||
|
|
363
|
+
err?.message?.includes('canceled')) {
|
|
364
|
+
if (err && !err.name)
|
|
365
|
+
err.name = 'AbortError';
|
|
91
366
|
throw err;
|
|
92
367
|
}
|
|
93
|
-
debugLog(`
|
|
368
|
+
debugLog(`[InvestigationComplexity] Evaluation failed (${err?.message}) — falling back to SINGLE`);
|
|
94
369
|
return {
|
|
95
370
|
strategy: 'SINGLE',
|
|
371
|
+
scope: 'SUB_PATH',
|
|
96
372
|
domains: [],
|
|
97
373
|
agentAssignments: [],
|
|
98
374
|
reasoning: 'Evaluator failed — falling back to single agent.',
|
|
375
|
+
focusedSubPath: activeSubPath,
|
|
376
|
+
subPathOverride: explicitOverride,
|
|
377
|
+
isAutoFocused,
|
|
99
378
|
};
|
|
100
379
|
}
|
|
101
380
|
}
|
|
@@ -19,6 +19,8 @@ export interface MetricCollector {
|
|
|
19
19
|
recordCacheHit(cacheType?: 'investigation' | 'read'): void;
|
|
20
20
|
recordCacheMiss(cacheType?: 'investigation' | 'read'): void;
|
|
21
21
|
recordCachePerformance(cacheType: 'investigation' | 'read', durationMs: number): void;
|
|
22
|
+
recordCircuitBreakerTrip?(): void;
|
|
23
|
+
recordPrunedLogVolume?(lines: number, chars: number): void;
|
|
22
24
|
recordWriteFailure?(): void;
|
|
23
25
|
recordModifyFailure?(): void;
|
|
24
26
|
recordToolFailure?(toolName?: string): void;
|
|
@@ -33,3 +35,11 @@ export declare function getTurnTotals(): {
|
|
|
33
35
|
outputTokens: number;
|
|
34
36
|
cachedTokens: number;
|
|
35
37
|
};
|
|
38
|
+
export declare function recordRecoveryCircuitBreakerTrip(): void;
|
|
39
|
+
export declare function recordRecoveryPrunedLogVolume(lines: number, chars: number): void;
|
|
40
|
+
export declare function getRecoveryMetrics(): {
|
|
41
|
+
circuitBreakerTrips: number;
|
|
42
|
+
prunedLines: number;
|
|
43
|
+
prunedChars: number;
|
|
44
|
+
};
|
|
45
|
+
export declare function resetRecoveryMetrics(): void;
|
package/dist/services/metrics.js
CHANGED
|
@@ -8,6 +8,9 @@ export function getMetricCollector() {
|
|
|
8
8
|
let turnPromptTokens = 0;
|
|
9
9
|
let turnOutputTokens = 0;
|
|
10
10
|
let turnCachedTokens = 0;
|
|
11
|
+
let sessionCircuitBreakerTrips = 0;
|
|
12
|
+
let sessionPrunedLines = 0;
|
|
13
|
+
let sessionPrunedChars = 0;
|
|
11
14
|
export function resetTurnAccumulator() {
|
|
12
15
|
turnPromptTokens = 0;
|
|
13
16
|
turnOutputTokens = 0;
|
|
@@ -23,3 +26,24 @@ export function accumulateUsage(usage) {
|
|
|
23
26
|
export function getTurnTotals() {
|
|
24
27
|
return { promptTokens: turnPromptTokens, outputTokens: turnOutputTokens, cachedTokens: turnCachedTokens };
|
|
25
28
|
}
|
|
29
|
+
export function recordRecoveryCircuitBreakerTrip() {
|
|
30
|
+
sessionCircuitBreakerTrips++;
|
|
31
|
+
globalCollector?.recordCircuitBreakerTrip?.();
|
|
32
|
+
}
|
|
33
|
+
export function recordRecoveryPrunedLogVolume(lines, chars) {
|
|
34
|
+
sessionPrunedLines += lines;
|
|
35
|
+
sessionPrunedChars += chars;
|
|
36
|
+
globalCollector?.recordPrunedLogVolume?.(lines, chars);
|
|
37
|
+
}
|
|
38
|
+
export function getRecoveryMetrics() {
|
|
39
|
+
return {
|
|
40
|
+
circuitBreakerTrips: sessionCircuitBreakerTrips,
|
|
41
|
+
prunedLines: sessionPrunedLines,
|
|
42
|
+
prunedChars: sessionPrunedChars,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function resetRecoveryMetrics() {
|
|
46
|
+
sessionCircuitBreakerTrips = 0;
|
|
47
|
+
sessionPrunedLines = 0;
|
|
48
|
+
sessionPrunedChars = 0;
|
|
49
|
+
}
|
|
@@ -1,57 +1,34 @@
|
|
|
1
1
|
import { MessageBus } from './messageBus.js';
|
|
2
2
|
import { FileLockRegistry } from './fileLockRegistry.js';
|
|
3
|
+
import { type PathResolutionOptions } from '../../utils/pathSecurity.js';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* Resolves a file path to its canonical absolute path for lock registry keying,
|
|
6
|
+
* accounting for multi-workspace alias resolution and default primary sub-path auto-focusing.
|
|
7
|
+
*
|
|
8
|
+
* @param workspaceRoot - The base primary workspace root directory
|
|
9
|
+
* @param filePath - The relative or aliased file path
|
|
10
|
+
* @param options - Optional sub-path override configuration
|
|
11
|
+
* @returns Absolute canonical file path
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveCanonicalLockPath(workspaceRoot: string, filePath: string, options?: PathResolutionOptions): string;
|
|
14
|
+
/**
|
|
15
|
+
* Returns Gemini tool declarations available to sub-agents during orchestration.
|
|
16
|
+
* In addition to standard agent tools (read/write/search/command/etc.), includes
|
|
17
|
+
* inter-agent communication tools (post_message, read_messages).
|
|
6
18
|
*/
|
|
7
|
-
export declare function getScopedToolDeclarations():
|
|
8
|
-
name: string;
|
|
9
|
-
description: string;
|
|
10
|
-
parameters: {
|
|
11
|
-
type: string;
|
|
12
|
-
properties: {
|
|
13
|
-
type: {
|
|
14
|
-
type: string;
|
|
15
|
-
description: string;
|
|
16
|
-
};
|
|
17
|
-
content: {
|
|
18
|
-
type: string;
|
|
19
|
-
description: string;
|
|
20
|
-
};
|
|
21
|
-
toAgent: {
|
|
22
|
-
type: string;
|
|
23
|
-
description: string;
|
|
24
|
-
};
|
|
25
|
-
affectedFiles: {
|
|
26
|
-
type: string;
|
|
27
|
-
items: {
|
|
28
|
-
type: string;
|
|
29
|
-
};
|
|
30
|
-
description: string;
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
required: string[];
|
|
34
|
-
};
|
|
35
|
-
} | {
|
|
36
|
-
name: string;
|
|
37
|
-
description: string;
|
|
38
|
-
parameters: {
|
|
39
|
-
type: string;
|
|
40
|
-
properties: {
|
|
41
|
-
type?: undefined;
|
|
42
|
-
content?: undefined;
|
|
43
|
-
toAgent?: undefined;
|
|
44
|
-
affectedFiles?: undefined;
|
|
45
|
-
};
|
|
46
|
-
required?: undefined;
|
|
47
|
-
};
|
|
48
|
-
})[];
|
|
19
|
+
export declare function getScopedToolDeclarations(): any[];
|
|
49
20
|
/**
|
|
50
|
-
*
|
|
21
|
+
* Executes a tool within the sub-agent execution boundary.
|
|
22
|
+
* Handles concurrency locking for file-mutating operations, sends progress
|
|
23
|
+
* notifications to the orchestrator, and logs activity to the message bus.
|
|
51
24
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
25
|
+
* @param name - Tool function name
|
|
26
|
+
* @param args - Tool arguments object
|
|
27
|
+
* @param workspaceRoot - Primary workspace root directory
|
|
28
|
+
* @param agentId - Unique ID of the executing agent
|
|
29
|
+
* @param bus - Shared message bus instance
|
|
30
|
+
* @param locks - Shared file lock registry instance
|
|
31
|
+
* @param onProgress - Callback to notify parent of sub-agent progress
|
|
32
|
+
* @param options - Optional sub-path auto-focus and override configuration
|
|
56
33
|
*/
|
|
57
|
-
export declare function executeScopedTool(name: string, args: Record<string, any>, workspaceRoot: string, agentId: string, bus: MessageBus, locks: FileLockRegistry, onProgress: (msg?: string) => void): Promise<any>;
|
|
34
|
+
export declare function executeScopedTool(name: string, args: Record<string, any>, workspaceRoot: string, agentId: string, bus: MessageBus, locks: FileLockRegistry, onProgress: (msg?: string) => void, options?: PathResolutionOptions): Promise<any>;
|