minovative-mind-cli 2.11.3 → 2.11.5

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.
@@ -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
- // ─── Evaluator ───────────────────────────────────────────────────────
16
+ // ─── Helper Functions ────────────────────────────────────────────────
16
17
  /**
17
- * Evaluates whether the investigation phase should be parallelized.
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
- * Uses `gemini-3.7-flash` (under auto mode) at temperature 0 to classify the prompt's
20
- * investigation complexity. The PM dynamically identifies domains and groups
21
- * them into agent assignments. Agent count = `agentAssignments.length`, which
22
- * may be fewer than `domains.length` when related domains are batched together.
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 / React").
26
- * @param approximateFileCount - Rough file count from the project tree.
27
- * @param chatHistory - Recent conversation history for context.
28
- * @returns The complexity classification with domain decomposition.
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 err = new Error('Operation aborted');
33
- err.name = 'AbortError';
34
- throw err;
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 (chatHistory) {
42
- prompt = `Previous Conversation Context:\n${chatHistory}\n\n${prompt}`;
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
- const result = await session.sendMessage(prompt, undefined, abortSignal);
45
- const text = result.response.text()?.trim() || '{}';
46
- const parsed = JSON.parse(text);
47
- debugLog(`Investigation Complexity Parsed: ${JSON.stringify(parsed)}`);
48
- // Validate the response shape
49
- const strategy = parsed.strategy === 'PARALLEL' ? 'PARALLEL' : 'SINGLE';
50
- if (strategy === 'SINGLE') {
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 || 'Simple prompt — single agent sufficient.',
286
+ reasoning: parsed.reasoning || 'Localized prompt — single agent sufficient.',
287
+ focusedSubPath: activeSubPath,
288
+ subPathOverride: finalOverride,
289
+ isAutoFocused: finalIsAutoFocused,
56
290
  };
57
291
  }
58
- // Validate agentAssignments array
59
- const agentAssignments = [];
60
- if (Array.isArray(parsed.agentAssignments)) {
61
- for (const assignment of parsed.agentAssignments) {
62
- if (assignment.agentLabel && Array.isArray(assignment.domains) && assignment.domains.length > 0) {
63
- agentAssignments.push({
64
- agentLabel: String(assignment.agentLabel),
65
- domains: assignment.domains.map(String),
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
- // If the PM said PARALLEL but produced no valid assignments, fall back to SINGLE
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('Investigation Complexity: PM said PARALLEL but produced <2 valid assignments. Falling back to SINGLE.');
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: 'PM produced insufficient agent assignments falling back to single agent.',
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
- domains: Array.isArray(parsed.domains) ? parsed.domains.map(String) : [],
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 (e) {
88
- if (abortSignal?.aborted || e?.name === 'AbortError' || e?.message?.includes('abort')) {
89
- const err = new Error('Operation aborted');
90
- err.name = 'AbortError';
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(`Investigation Complexity Router failed, falling back to SINGLE. Error: ${String(e)}`);
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
  }
@@ -52,7 +52,7 @@ export class InvestigationAgentRunner {
52
52
  this.projectType = projectType;
53
53
  let model = getGlobalActiveModel();
54
54
  if (model === GEMINI_MODELS.AUTO || model.includes('claude'))
55
- model = GEMINI_MODELS.FLASH;
55
+ model = GEMINI_MODELS.FLASH_LITE;
56
56
  this.chat = new ProxyChatSession(model, this.buildSystemInstruction(), getContextToolDeclarations(), {
57
57
  maxOutputTokens: MAX_OUTPUT_TOKENS,
58
58
  temperature: 1,
@@ -66,6 +66,11 @@ export class InvestigationOrchestrator {
66
66
  for (let i = 0; i < agents.length; i += MAX_CONCURRENT) {
67
67
  if (abortSignal.aborted)
68
68
  break;
69
+ if (i > 0) {
70
+ await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.PARALLEL_CHUNK_MS));
71
+ if (abortSignal.aborted)
72
+ break;
73
+ }
69
74
  const chunk = agents.slice(i, i + MAX_CONCURRENT);
70
75
  const chunkAssignments = agentAssignments.slice(i, i + MAX_CONCURRENT);
71
76
  const chunkPromises = chunk.map((agent, chunkIndex) => {
@@ -12,7 +12,7 @@ import * as p from '@clack/prompts';
12
12
  import pc from 'picocolors';
13
13
  import { ProxyChatSession, getGlobalActiveModel, compressTextUsingFlashLite } from '../ai.js';
14
14
  import { peekTurnUsage } from '../proxyClient.js';
15
- import { GEMINI_MODELS, MAX_OUTPUT_TOKENS } from '../../utils/config.js';
15
+ import { GEMINI_MODELS, MAX_OUTPUT_TOKENS, TPM_COOLING_DELAYS } from '../../utils/config.js';
16
16
  import { debugLog } from '../../utils/logger.js';
17
17
  import { MessageBus } from './messageBus.js';
18
18
  import { FileLockRegistry } from './fileLockRegistry.js';
@@ -100,6 +100,10 @@ export class Orchestrator {
100
100
  p.log.info(pc.blue(`Orchestrator: Generated ${waves.length} execution wave(s) with ${graph.tasks.length} total tasks.`));
101
101
  // 3. Dispatch Waves
102
102
  for (const wave of waves) {
103
+ if (signal.aborted)
104
+ break;
105
+ // Cooling-off pause before dispatching each execution wave
106
+ await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.ORCHESTRATION_WAVE_MS));
103
107
  if (signal.aborted)
104
108
  break;
105
109
  const taskDescriptions = wave.taskIds
@@ -126,6 +130,11 @@ export class Orchestrator {
126
130
  for (let i = 0; i < wave.taskIds.length; i += MAX_CONCURRENT) {
127
131
  if (signal.aborted)
128
132
  break;
133
+ if (i > 0) {
134
+ await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.PARALLEL_CHUNK_MS));
135
+ if (signal.aborted)
136
+ break;
137
+ }
129
138
  const chunk = wave.taskIds.slice(i, i + MAX_CONCURRENT);
130
139
  const wavePromises = chunk.map((taskId) => {
131
140
  const taskDef = graph.tasks.find((t) => t.id === taskId);
@@ -169,7 +178,10 @@ export class Orchestrator {
169
178
  }
170
179
  }
171
180
  // 4. Reconciliation
172
- const finalSummary = await this.reconcile(graph);
181
+ if (!signal.aborted) {
182
+ await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.ORCHESTRATION_RECONCILE_MS));
183
+ }
184
+ const finalSummary = await this.reconcile(graph, signal);
173
185
  return finalSummary;
174
186
  }
175
187
  /**
@@ -248,7 +260,7 @@ export class Orchestrator {
248
260
  /**
249
261
  * Final reconciliation phase after all waves complete.
250
262
  */
251
- async reconcile(graph) {
263
+ async reconcile(graph, signal) {
252
264
  p.log.step(pc.cyan('Orchestrator: Reconciling results'));
253
265
  const stats = this.bus.getStats();
254
266
  let totalTokens = 0;
@@ -280,7 +292,7 @@ export class Orchestrator {
280
292
  'DO NOT list changes by task name or separate them by agent. ' +
281
293
  'Be concise, helpful, and conclude by asking if they need any further adjustments.\n' +
282
294
  '</directives>';
283
- const synthesized = await compressTextUsingFlashLite(payloadWithContext, instruction, undefined, true);
295
+ const synthesized = await compressTextUsingFlashLite(payloadWithContext, instruction, undefined, true, signal);
284
296
  finalSummary += synthesized + '\n\n';
285
297
  }
286
298
  catch (e) {
@@ -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
- * Extended tool declarations for sub-agents, merging the standard tools
5
- * with orchestration-specific ones (e.g., post_message, read_messages).
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(): (import("@google/generative-ai").FunctionDeclaration | {
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
- * Wraps the global executeTool to provide sub-agent context.
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
- * 1. Captures tool execution into the MessageBus (Layer 1: zero-cost logs).
53
- * 2. Implements FileLocks for write/modify operations to prevent race conditions.
54
- * 3. Handles `post_message` and `read_messages` directly.
55
- * 4. Calls a heartbeat callback to notify the orchestrator this agent is alive.
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>;