minovative-mind-cli 2.11.4 → 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.
package/README.md CHANGED
@@ -105,8 +105,8 @@ If you prefer to use your own API key instead of credits, you can configure it v
105
105
 
106
106
  Background tasks automatically route to dedicated auxiliary models with native `responseSchema` constraints for optimal latency, cost efficiency, and structured output reliability:
107
107
 
108
- - **Intent Router (`routeIntent`)**: `Gemini 3.7 Flash` (Temp 0, native `responseSchema`) — zero-temperature classification of `SEARCH` vs `SKIP` and `CHAT` vs `EXECUTE`.
109
- - **Complexity Evaluators**: `Gemini 3.7 Flash` (Temp 0, native `responseSchema`) — domain partitioning and parallel execution wave feasibility.
108
+ - **Intent Routing (`routeIntent`)**: `Gemini 3.7 Flash` (Temp 0, native `responseSchema`) — permissive zero-temperature classification into `SEARCH` vs `SKIP` and `CHAT` vs `EXECUTE` with resilient fallback to repository exploration.
109
+ - **Complexity Evaluators (`evaluateInvestigationComplexity`)**: `Gemini 3.7 Flash` (Temp 0, native `responseSchema`) — permissive parallel domain partitioning, global override detection, primary sub-path auto-focusing, and dynamic agent assignment recovery.
110
110
  - **Context Compressor**: `Gemini 3.7 Flash` (Temp 0.2) — surgical code distillation for files exceeding 2,000 characters.
111
111
  - **Session Titling**: `Gemini 3.7 Flash` (Temp 0.7, native `responseSchema`) — automated concise chat session titling.
112
112
  - **Semantic Cache Classifier**: `Gemini 3.5 Flash Lite` (Temp 0, native `responseSchema`) — intent and topic classification for cache hits.
@@ -139,13 +139,14 @@ Background tasks automatically route to dedicated auxiliary models with native `
139
139
 
140
140
  ---
141
141
 
142
- ## 🌐 Multi-Workspace & Cross-Repo Support (Master & Sub-Workspaces)
142
+ ## 🌐 Multi-Workspace, Sub-Path Focusing & Security Guardrails
143
143
 
144
144
  Minovative Mind CLI doesn't restrict you to a single repository. You can logically group multiple external repositories into **Master Workspaces** (Profiles) containing dedicated **Sub-Workspaces** (mapped to short aliases like `@backend` or `@frontend`).
145
145
 
146
- The Context Agent and Thread Agents operate strictly within the boundaries of the active Master Workspace, ignoring other profiles to keep the context window highly targeted and memory-efficient.
147
-
148
- By prefixing file paths with `@alias/` (e.g., `@backend/src/api.ts` and `@frontend/src/App.tsx`), the agents can investigate, refactor, and coordinate changes across your entire nested stack in a single prompt. The terminal highlights cross-workspace actions with a blue `[alias]` visual tag. Use the `/workspaces` command to create profiles, link sub-workspaces, or switch active environments.
146
+ - **Primary Sub-Path Auto-Focusing & Global Override Detection**: Workspaces can designate a default primary sub-path (e.g. `src/` or `packages/core`), automatically scoping file operations and context turns without repetitive prefixing. If global override search phrases (e.g., "across the codebase", "entire project", "global", "end to end") or root monorepo configurations are detected, sub-path auto-focusing is dynamically bypassed to evaluate the entire repository.
147
+ - **Multi-Workspace Path Security Boundaries**: Strictly enforces workspace and profile containment via `resolveAndValidateMultiWorkspacePath`, preventing directory traversal (`../`), null-byte injections (`\0`), and absolute path escapes.
148
+ - **Canonical Lock Path Resolution in Scoped Tool Execution**: In parallel multi-agent workflows (MMAAK), file mutation tools automatically resolve relative paths, auto-focused sub-paths, and `@alias/` cross-repo prefixes to canonical absolute filesystem paths before acquiring mutexes in `FileLockRegistry`, preventing race conditions and lock collisions across concurrent agents.
149
+ - **Cross-Repo Coordination**: Prefix file paths with `@alias/` (e.g., `@backend/src/api.ts` and `@frontend/src/App.tsx`) to investigate, refactor, and coordinate changes across your entire stack in a single prompt. The terminal highlights cross-workspace actions with a blue `[alias]` visual tag. Use `/workspaces` to create profiles, link sub-workspaces, or switch active environments.
149
150
 
150
151
  ---
151
152
 
@@ -66,7 +66,7 @@ export declare class ProxyChatSession {
66
66
  name: string;
67
67
  response: any;
68
68
  };
69
- }>, additionalText?: string, abortSignal?: AbortSignal, onChunk?: (chunk: string) => void): Promise<{
69
+ }>, additionalText?: string | AbortSignal, abortSignal?: AbortSignal, onChunk?: (chunk: string) => void): Promise<{
70
70
  response: {
71
71
  text: () => string;
72
72
  functionCalls: () => FunctionCall[] | undefined;
@@ -13,7 +13,17 @@ function getMultiWorkspaceBlock() {
13
13
  const summary = workspaceRegistry.buildPromptSummary();
14
14
  const primaryRoot = process.cwd();
15
15
  const primaryName = primaryRoot.split(/[/\\]/).pop() || 'Primary';
16
+ const primarySubPath = workspaceRegistry.getPrimarySubPath();
16
17
  let block = `<workspace_context>\nYour current primary workspace (the default "./" root) is:\n- ./ (Workspace: ${primaryName}) → ${primaryRoot}\n`;
18
+ if (primarySubPath) {
19
+ block += `- Active Primary Sub-Path: "${primarySubPath}" (All relative search, inspection, and file operations focus into this sub-directory by default unless another sub-path or external workspace is explicitly specified).\n`;
20
+ }
21
+ block += `\n<workspace_focus_rules>
22
+ - **Primary Focus Default (CRITICAL)**: Always default your investigation, search, file reading, and modifications to the current primary workspace and active primary sub-path. Unless the user explicitly names another sub-path or external workspace, assume all user instructions ("find this", "update that", "refactor X") refer to the primary workspace and active sub-path you are currently in.
23
+ - **Explicit Sub-Paths**: Only target a different sub-directory if the user explicitly specifies it.
24
+ - **External Workspaces (@alias/)**: Only access external workspaces if the user explicitly references them or uses the registered @alias prefix.
25
+ - **Strict Boundary Defense & Missing Workspace Handling**: Never attempt relative path traversal (like "../other-repo") or use "run_command" (such as node -e or bash scripts with fs/cat/cp) to read or write files outside registered workspace boundaries. If the user asks for a project or workspace that is NOT registered or available, you MUST NOT use commands or scripts to work around it; instead, immediately and clearly inform the user that the project or workspace is not registered and instruct them to add it via "/workspaces".
26
+ </workspace_focus_rules>\n`;
17
27
  if (summary) {
18
28
  block += `\nThe user has also registered external workspaces that you can access using the @alias/ prefix:\n${summary}\n\nTo read, modify, or search files in an external workspace, prefix the file path with the alias (e.g., "@backend/src/routes.ts"). To search across ALL workspaces, use grep_search with workspace="all".\n\nWhen the user asks to "transfer", "sync", or "port" features between projects, read the source files from one workspace and apply the changes to the target.\n`;
19
29
  }
@@ -65,12 +75,16 @@ const MAX_PART_TEXT_LENGTH = 60_000;
65
75
  const HISTORICAL_TOOL_OUTPUT_THRESHOLD = 1500;
66
76
  const COLLAPSED_TOOL_OUTPUT_MARKER = '\n... [Historical tool output collapsed to save context]';
67
77
  function collapseHistoricalOutput(val, threshold = HISTORICAL_TOOL_OUTPUT_THRESHOLD) {
78
+ if (typeof val !== 'string')
79
+ return String(val ?? '');
68
80
  if (val.length <= threshold || val.includes('[Historical tool output collapsed')) {
69
81
  return val;
70
82
  }
71
83
  return `${val.substring(0, threshold)}${COLLAPSED_TOOL_OUTPUT_MARKER}`;
72
84
  }
73
85
  function truncatePartText(text) {
86
+ if (typeof text !== 'string')
87
+ return String(text ?? '');
74
88
  if (text.length <= MAX_PART_TEXT_LENGTH)
75
89
  return text;
76
90
  return text.substring(0, MAX_PART_TEXT_LENGTH) + '\n... (output truncated to prevent memory overflow)';
@@ -289,6 +303,16 @@ export class ProxyChatSession {
289
303
  }
290
304
  }
291
305
  async sendMessage(message, additionalText, abortSignal, onChunk) {
306
+ // Graceful argument normalization if AbortSignal is passed as 2nd argument
307
+ let actualAdditionalText;
308
+ let actualAbortSignal = abortSignal;
309
+ if (additionalText && typeof additionalText !== 'string' && additionalText.aborted !== undefined) {
310
+ actualAbortSignal = additionalText;
311
+ actualAdditionalText = undefined;
312
+ }
313
+ else if (typeof additionalText === 'string') {
314
+ actualAdditionalText = additionalText;
315
+ }
292
316
  const idToken = await getAuthorizedIdToken();
293
317
  if (!idToken) {
294
318
  throw new Error('You are not signed in. Please run `minovative-mind-cli login` first.');
@@ -331,8 +355,8 @@ export class ProxyChatSession {
331
355
  }
332
356
  }
333
357
  }
334
- if (additionalText) {
335
- newParts.push({ text: truncatePartText(additionalText) });
358
+ if (actualAdditionalText) {
359
+ newParts.push({ text: truncatePartText(actualAdditionalText) });
336
360
  }
337
361
  const userEntry = {
338
362
  role: 'user',
@@ -348,12 +372,12 @@ export class ProxyChatSession {
348
372
  const creds = await loadCredentials();
349
373
  result = await proxyClient.generateViaBYOK(creds.geminiApiKey, this.modelName, this.history, this.tools, undefined, // toolConfig
350
374
  this.systemInstruction, effectiveGenerationConfig, onChunk ? { onChunk } : undefined, // streamCallbacks
351
- abortSignal);
375
+ actualAbortSignal);
352
376
  }
353
377
  else {
354
378
  result = await proxyClient.generateFunctionCallViaProxy(idToken, this.modelName, this.history, this.tools, undefined, // toolConfig
355
379
  this.systemInstruction, effectiveGenerationConfig, onChunk ? { onChunk } : undefined, // streamCallbacks
356
- abortSignal);
380
+ actualAbortSignal);
357
381
  }
358
382
  this.latestUsageMetadata = result.usageMetadata;
359
383
  // Track token usage metrics
@@ -426,7 +450,7 @@ export function createSharedChatSession() {
426
450
  let model = executionModelOverride || getGlobalActiveModel();
427
451
  if (model === 'auto')
428
452
  model = GEMINI_MODELS.FLASH; // Will be overridden per-turn in executeSingleTurn
429
- return new ProxyChatSession(model, GENERAL_CHAT_INSTRUCTION, [], {
453
+ return new ProxyChatSession(model, GENERAL_CHAT_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()), [], {
430
454
  maxOutputTokens: MAX_OUTPUT_TOKENS,
431
455
  temperature: executionTempOverride !== null ? executionTempOverride : 1,
432
456
  topP: 0.95,
@@ -435,7 +459,7 @@ export function createSharedChatSession() {
435
459
  }
436
460
  export function getGeneralChatConfig() {
437
461
  return {
438
- systemInstruction: GENERAL_CHAT_INSTRUCTION,
462
+ systemInstruction: GENERAL_CHAT_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()),
439
463
  tools: [{ googleSearch: {} }],
440
464
  };
441
465
  }
@@ -447,7 +471,7 @@ export function getPlanExecutionConfig() {
447
471
  }
448
472
  export function getPlanModeConfig() {
449
473
  return {
450
- systemInstruction: PLAN_MODE_INSTRUCTION,
474
+ systemInstruction: PLAN_MODE_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()),
451
475
  tools: [], // No tools allowed in plan mode
452
476
  };
453
477
  }
@@ -737,6 +761,15 @@ export function createInvestigationComplexitySession() {
737
761
  enum: ['SINGLE', 'PARALLEL'],
738
762
  description: 'Investigation strategy (SINGLE or PARALLEL)',
739
763
  },
764
+ scope: {
765
+ type: SchemaType.STRING,
766
+ enum: ['SUB_PATH', 'FULL_WORKSPACE', 'EXTERNAL_WORKSPACE'],
767
+ description: 'Investigation scope: SUB_PATH (confined to active primary sub-path), FULL_WORKSPACE (spans whole repository or root files), or EXTERNAL_WORKSPACE (targets @alias/)',
768
+ },
769
+ subPathOverride: {
770
+ type: SchemaType.STRING,
771
+ description: 'The target scope identifier if overridden (e.g. "root", target root file, or @alias), or null if strictly confined to active primary sub-path',
772
+ },
740
773
  domains: {
741
774
  type: SchemaType.ARRAY,
742
775
  items: {
@@ -10,6 +10,17 @@
10
10
  * Only invoked when the `/sub-agents` toggle is ON and the Intent Router
11
11
  * has already determined that context gathering is needed (SEARCH).
12
12
  */
13
+ /** Options for customizing investigation complexity evaluation. */
14
+ export interface InvestigationComplexityOptions {
15
+ /** Explicit primary sub-path focus override for the evaluation */
16
+ autoFocusSubPath?: string | null;
17
+ /** Explicit sub-path override if user explicitly targeted another scope */
18
+ subPathOverride?: string | null;
19
+ /** Flag to disable sub-path auto-focusing completely */
20
+ disableAutoFocus?: boolean;
21
+ /** Primary workspace root directory path */
22
+ primaryRoot?: string;
23
+ }
13
24
  /** A single agent assignment grouping related investigation domains. */
14
25
  export interface AgentAssignment {
15
26
  /** Human-readable label for this agent (e.g., "Frontend", "Backend") */
@@ -21,25 +32,40 @@ export interface AgentAssignment {
21
32
  export interface InvestigationComplexityResult {
22
33
  /** Whether investigation should use a single agent or parallel agents */
23
34
  strategy: 'SINGLE' | 'PARALLEL';
35
+ /** The evaluated investigation scope */
36
+ scope?: 'SUB_PATH' | 'FULL_WORKSPACE' | 'EXTERNAL_WORKSPACE';
24
37
  /** All identified investigation domains (flat list) */
25
38
  domains: string[];
26
- /** Grouped domain assignments — one per agent to spawn */
39
+ /** Grouped domain assignments — one per agent to spawn (2–3 max) */
27
40
  agentAssignments: AgentAssignment[];
28
- /** Brief justification from the PM for its decision */
41
+ /** Brief explanation of the routing decision */
29
42
  reasoning: string;
43
+ /** The active primary sub-path auto-focus, if any */
44
+ focusedSubPath?: string | null;
45
+ /** The active sub-path or workspace override, if detected or provided */
46
+ subPathOverride?: string | null;
47
+ /** Whether the evaluation was constrained by active sub-path auto-focusing */
48
+ isAutoFocused?: boolean;
30
49
  }
31
50
  /**
32
- * Evaluates whether the investigation phase should be parallelized.
51
+ * Checks whether the user's prompt contains an explicit path or workspace override
52
+ * that supersedes default primary sub-path auto-focusing.
33
53
  *
34
- * Uses `gemini-3.7-flash` (under auto mode) at temperature 0 to classify the prompt's
35
- * investigation complexity. The PM dynamically identifies domains and groups
36
- * them into agent assignments. Agent count = `agentAssignments.length`, which
37
- * may be fewer than `domains.length` when related domains are batched together.
54
+ * @param userRequest - The prompt text from the user
55
+ * @param activeSubPath - The currently active primary sub-path (if any)
56
+ * @returns The detected override identifier or null if no override exists
57
+ */
58
+ export declare function detectSubPathOverride(userRequest: string, activeSubPath?: string | null): string | null;
59
+ /**
60
+ * Evaluates whether a user request warrants parallel investigation or a single agent.
61
+ * Respects default primary sub-path auto-focusing while allowing explicit overrides.
38
62
  *
39
- * @param userRequest - The user's prompt.
40
- * @param projectType - Detected project type (e.g., "Node.js / TypeScript / React").
41
- * @param approximateFileCount - Rough file count from the project tree.
42
- * @param chatHistory - Recent conversation history for context.
43
- * @returns The complexity classification with domain decomposition.
63
+ * @param userRequest - The user's prompt/request
64
+ * @param projectType - Detected project type string (e.g., "Node.js / TypeScript")
65
+ * @param approximateFileCount - Approximate total file count in the project
66
+ * @param chatHistory - Formatted recent conversation history (optional)
67
+ * @param abortSignal - Optional signal to abort the LLM request
68
+ * @param options - Optional sub-path auto-focus and override configuration
69
+ * @returns Structured complexity result with strategy and domain assignments
44
70
  */
45
- export declare function evaluateInvestigationComplexity(userRequest: string, projectType: string, approximateFileCount: number, chatHistory?: string, abortSignal?: AbortSignal): Promise<InvestigationComplexityResult>;
71
+ export declare function evaluateInvestigationComplexity(userRequest: string, projectType: string, approximateFileCount: number, chatHistory?: string, abortSignal?: AbortSignal, options?: InvestigationComplexityOptions): Promise<InvestigationComplexityResult>;