minovative-mind-cli 2.0.0 → 2.1.1
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 +9 -0
- package/dist/commands/chat.js +3 -0
- package/dist/services/agent/slashCommands.js +213 -12
- package/dist/services/agent-tools.js +142 -28
- package/dist/services/agent.js +3 -0
- package/dist/services/ai.js +16 -2
- package/dist/services/contextAgent.js +41 -49
- package/dist/services/orchestration/investigationAgent.js +5 -2
- package/dist/services/orchestration/orchestrator.js +5 -2
- package/dist/services/orchestration/subAgent.js +5 -2
- package/dist/services/workspaceRegistry.d.ts +137 -0
- package/dist/services/workspaceRegistry.js +270 -0
- package/dist/utils/contextPrompts.js +7 -1
- package/dist/utils/pathSecurity.d.ts +31 -0
- package/dist/utils/pathSecurity.js +48 -0
- package/dist/utils/systemPrompts.d.ts +2 -2
- package/dist/utils/systemPrompts.js +5 -1
- package/oclif.manifest.json +2 -2
- package/package.json +1 -1
package/dist/services/ai.js
CHANGED
|
@@ -5,6 +5,20 @@ import { getAuthorizedIdToken } from './auth.js';
|
|
|
5
5
|
import { debugLog } from '../utils/logger.js';
|
|
6
6
|
import { GENERAL_CHAT_INSTRUCTION, PLAN_EXECUTION_INSTRUCTION, PLAN_MODE_INSTRUCTION, CONTEXT_SYSTEM_INSTRUCTION, INTENT_ROUTER_SYSTEM_INSTRUCTION, WEB_SEARCH_SYSTEM_INSTRUCTION, EXECUTION_COMPLEXITY_SYSTEM_INSTRUCTION, INVESTIGATION_COMPLEXITY_SYSTEM_INSTRUCTION, } from '../utils/systemPrompts.js';
|
|
7
7
|
import { getMetricCollector } from './metrics.js';
|
|
8
|
+
import { workspaceRegistry } from './workspaceRegistry.js';
|
|
9
|
+
function getMultiWorkspaceBlock() {
|
|
10
|
+
const summary = workspaceRegistry.buildPromptSummary();
|
|
11
|
+
if (!summary)
|
|
12
|
+
return '';
|
|
13
|
+
return `<multi_workspace>
|
|
14
|
+
The user has registered external workspaces that you can access using the @alias/ prefix:
|
|
15
|
+
${summary}
|
|
16
|
+
|
|
17
|
+
To 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".
|
|
18
|
+
|
|
19
|
+
When 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.
|
|
20
|
+
</multi_workspace>`;
|
|
21
|
+
}
|
|
8
22
|
// ─── Model Overrides (for Regression Testing) ────────────────────────
|
|
9
23
|
let contextModelOverride = null;
|
|
10
24
|
let contextTempOverride = null;
|
|
@@ -261,7 +275,7 @@ export function getGeneralChatConfig() {
|
|
|
261
275
|
}
|
|
262
276
|
export function getPlanExecutionConfig() {
|
|
263
277
|
return {
|
|
264
|
-
systemInstruction: PLAN_EXECUTION_INSTRUCTION,
|
|
278
|
+
systemInstruction: PLAN_EXECUTION_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()),
|
|
265
279
|
tools: [{ functionDeclarations: getToolDeclarations() }],
|
|
266
280
|
};
|
|
267
281
|
}
|
|
@@ -505,7 +519,7 @@ export function createContextAgentSession() {
|
|
|
505
519
|
let model = contextModelOverride || getGlobalActiveModel();
|
|
506
520
|
if (model === 'auto')
|
|
507
521
|
model = GEMINI_MODELS.FLASH_3_5;
|
|
508
|
-
return new ProxyChatSession(model, CONTEXT_SYSTEM_INSTRUCTION, contextTools, {
|
|
522
|
+
return new ProxyChatSession(model, CONTEXT_SYSTEM_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()), contextTools, {
|
|
509
523
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
510
524
|
temperature: contextTempOverride !== null ? contextTempOverride : 1,
|
|
511
525
|
topP: 0.95,
|
|
@@ -4,7 +4,7 @@ import pc from 'picocolors';
|
|
|
4
4
|
import { createContextAgentSession, createIntentRouterSession, createWebSearchAgentSession, createExecutionComplexitySession, } from './ai.js';
|
|
5
5
|
import { evaluateInvestigationComplexity } from './investigationComplexity.js';
|
|
6
6
|
import { InvestigationOrchestrator } from './orchestration/investigationOrchestrator.js';
|
|
7
|
-
import { isSubAgentsEnabled,
|
|
7
|
+
import { isSubAgentsEnabled, executeTool } from './agent-tools.js';
|
|
8
8
|
import { debugLog } from '../utils/logger.js';
|
|
9
9
|
import { buildDependencyGraph } from '../utils/dependencyTracer.js';
|
|
10
10
|
import { runEphemeralScript } from '../utils/analysisRunner.js';
|
|
@@ -192,12 +192,24 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
192
192
|
if (!needsContext) {
|
|
193
193
|
return { contextResult: null, targetAgent, chainedMessages: [] };
|
|
194
194
|
}
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
const { workspaceRegistry } = await import('./workspaceRegistry.js');
|
|
196
|
+
const allRoots = workspaceRegistry.getAllRoots(workspaceRoot);
|
|
197
|
+
let projectTree = '';
|
|
198
|
+
let primaryProjectType = 'Unknown';
|
|
199
|
+
for (const { alias, root } of allRoots) {
|
|
200
|
+
const label = alias ? `@${alias} (${root})` : `Primary Workspace (${root})`;
|
|
201
|
+
const treeResult = await executeTool(root, 'list_directory', { dirPath: '.', maxDepth: 10 });
|
|
202
|
+
let tree = treeResult.output;
|
|
203
|
+
if (tree.length > 30000) {
|
|
204
|
+
tree = tree.substring(0, 30000) + '\\n... (Project tree truncated due to size)';
|
|
205
|
+
}
|
|
206
|
+
const type = await detectProjectType(root);
|
|
207
|
+
if (!alias) {
|
|
208
|
+
primaryProjectType = type;
|
|
209
|
+
}
|
|
210
|
+
projectTree += `=== ${label} ===\\nProject Type: ${type}\\n${tree}\\n\\n`;
|
|
199
211
|
}
|
|
200
|
-
const projectType =
|
|
212
|
+
const projectType = primaryProjectType;
|
|
201
213
|
// ─── Parallel Investigation Gate ─────────────────────────────
|
|
202
214
|
if (isSubAgentsEnabled()) {
|
|
203
215
|
// Determine complexity and domain breakdown
|
|
@@ -316,7 +328,7 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
316
328
|
debugLog(`Context Agent finished. Selected files: ${JSON.stringify(filesToRead)}`);
|
|
317
329
|
for (const filePath of filesToRead) {
|
|
318
330
|
if (!relevantFiles.has(filePath)) {
|
|
319
|
-
const readResult = await
|
|
331
|
+
const readResult = await executeTool(workspaceRoot, 'read_file', { filePath });
|
|
320
332
|
if (!readResult.error) {
|
|
321
333
|
relevantFiles.set(filePath, { text: readResult.output, inlineData: readResult.inlineData });
|
|
322
334
|
}
|
|
@@ -330,15 +342,23 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
330
342
|
// Execution Agent won't break imports when modifying/deleting/renaming.
|
|
331
343
|
const MAX_TOTAL_FILES = 15;
|
|
332
344
|
try {
|
|
333
|
-
const
|
|
345
|
+
const { resolveAndValidateMultiWorkspacePath } = await import('../utils/pathSecurity.js');
|
|
334
346
|
const autoDiscovered = new Set();
|
|
335
347
|
for (const filePath of filesToRead) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
348
|
+
try {
|
|
349
|
+
const resolved = resolveAndValidateMultiWorkspacePath(workspaceRoot, filePath);
|
|
350
|
+
const graph = await buildDependencyGraph(resolved.workspaceRoot);
|
|
351
|
+
const reverseDeps = graph.getImportedBy(resolved.relativePath);
|
|
352
|
+
for (const dep of reverseDeps) {
|
|
353
|
+
const aliasedDep = resolved.alias ? `@${resolved.alias}/${dep}` : dep;
|
|
354
|
+
if (!filesToRead.includes(aliasedDep) && !autoDiscovered.has(aliasedDep)) {
|
|
355
|
+
autoDiscovered.add(aliasedDep);
|
|
356
|
+
}
|
|
340
357
|
}
|
|
341
358
|
}
|
|
359
|
+
catch (e) {
|
|
360
|
+
// Ignore path resolution errors for trace dependencies
|
|
361
|
+
}
|
|
342
362
|
}
|
|
343
363
|
// Merge auto-discovered dependents, respecting the file cap
|
|
344
364
|
const remaining = MAX_TOTAL_FILES - relevantFiles.size;
|
|
@@ -347,7 +367,7 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
347
367
|
if (added >= remaining)
|
|
348
368
|
break;
|
|
349
369
|
if (!relevantFiles.has(dep)) {
|
|
350
|
-
const readResult = await
|
|
370
|
+
const readResult = await executeTool(workspaceRoot, 'read_file', { filePath: dep });
|
|
351
371
|
if (!readResult.error) {
|
|
352
372
|
relevantFiles.set(dep, { text: readResult.output, inlineData: readResult.inlineData });
|
|
353
373
|
added++;
|
|
@@ -377,7 +397,7 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
377
397
|
const filesToRead = args.files || [];
|
|
378
398
|
let output = '';
|
|
379
399
|
for (const filePath of filesToRead) {
|
|
380
|
-
const readResult = await
|
|
400
|
+
const readResult = await executeTool(workspaceRoot, 'read_file', { filePath });
|
|
381
401
|
if (!readResult.error) {
|
|
382
402
|
relevantFiles.set(filePath, { text: readResult.output, inlineData: readResult.inlineData });
|
|
383
403
|
output += `\n--- File: ${filePath} ---\n${readResult.output}\n`;
|
|
@@ -394,7 +414,7 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
394
414
|
});
|
|
395
415
|
}
|
|
396
416
|
else if (call.name === 'list_directory') {
|
|
397
|
-
const listRes = await
|
|
417
|
+
const listRes = await executeTool(workspaceRoot, 'list_directory', args);
|
|
398
418
|
functionResponses.push({
|
|
399
419
|
functionResponse: {
|
|
400
420
|
name: call.name,
|
|
@@ -406,7 +426,7 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
406
426
|
});
|
|
407
427
|
}
|
|
408
428
|
else if (call.name === 'search_codebase') {
|
|
409
|
-
const grepRes = await
|
|
429
|
+
const grepRes = await executeTool(workspaceRoot, 'grep_search', { ...args, workspace: 'all' });
|
|
410
430
|
functionResponses.push({
|
|
411
431
|
functionResponse: {
|
|
412
432
|
name: call.name,
|
|
@@ -415,44 +435,16 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
415
435
|
});
|
|
416
436
|
}
|
|
417
437
|
else if (call.name === 'semantic_search') {
|
|
418
|
-
const
|
|
419
|
-
const topK = args.topK || 5;
|
|
420
|
-
let output = '';
|
|
421
|
-
try {
|
|
422
|
-
const { getEmbeddingIndex } = await import('./embeddingIndex.js');
|
|
423
|
-
const index = getEmbeddingIndex();
|
|
424
|
-
if (!index.isReady()) {
|
|
425
|
-
// Lazy load from disk or build if missing
|
|
426
|
-
const loaded = await index.load(workspaceRoot);
|
|
427
|
-
if (!loaded) {
|
|
428
|
-
if (onProgress)
|
|
429
|
-
onProgress('Building semantic search index (first run)...');
|
|
430
|
-
await index.buildIndex(workspaceRoot, onProgress);
|
|
431
|
-
await index.save(workspaceRoot);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
const results = await index.search(query, topK);
|
|
435
|
-
if (results.length === 0) {
|
|
436
|
-
output = 'No semantically similar code found. (Index might be empty or embedding failed)';
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
output = results
|
|
440
|
-
.map((r) => `[Score: ${r.score.toFixed(3)}] ${r.filePath}:${r.startLine}-${r.endLine}\n${r.preview}`)
|
|
441
|
-
.join('\n---\n');
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
catch (e) {
|
|
445
|
-
output = `Semantic search failed: ${e.message}`;
|
|
446
|
-
}
|
|
438
|
+
const semRes = await executeTool(workspaceRoot, 'semantic_search', args);
|
|
447
439
|
functionResponses.push({
|
|
448
440
|
functionResponse: {
|
|
449
441
|
name: call.name,
|
|
450
|
-
response: { output },
|
|
442
|
+
response: { output: semRes.output },
|
|
451
443
|
},
|
|
452
444
|
});
|
|
453
445
|
}
|
|
454
446
|
else if (call.name === 'read_file') {
|
|
455
|
-
const readRes = await
|
|
447
|
+
const readRes = await executeTool(workspaceRoot, 'read_file', args);
|
|
456
448
|
if (!readRes.error) {
|
|
457
449
|
relevantFiles.set(args.filePath, { text: readRes.output, inlineData: readRes.inlineData });
|
|
458
450
|
}
|
|
@@ -494,7 +486,7 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
494
486
|
}
|
|
495
487
|
}
|
|
496
488
|
else if (call.name === 'find_dependencies') {
|
|
497
|
-
const depResult = await
|
|
489
|
+
const depResult = await executeTool(workspaceRoot, 'find_dependencies', args);
|
|
498
490
|
functionResponses.push({
|
|
499
491
|
functionResponse: {
|
|
500
492
|
name: call.name,
|
|
@@ -503,7 +495,7 @@ export async function gatherContext(workspaceRoot, userRequest, chatHistory = ''
|
|
|
503
495
|
});
|
|
504
496
|
}
|
|
505
497
|
else if (call.name === 'find_recent_changes') {
|
|
506
|
-
const recentRes = await
|
|
498
|
+
const recentRes = await executeTool(workspaceRoot, 'find_recent_changes', args);
|
|
507
499
|
functionResponses.push({
|
|
508
500
|
functionResponse: {
|
|
509
501
|
name: call.name,
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* components" + "Auth UI styling") and produces an `InvestigationResult` containing
|
|
12
12
|
* the files it found and a summary of its findings.
|
|
13
13
|
*/
|
|
14
|
-
import { ProxyChatSession, getContextToolDeclarations } from '../ai.js';
|
|
14
|
+
import { ProxyChatSession, getContextToolDeclarations, getGlobalActiveModel } from '../ai.js';
|
|
15
15
|
import { GEMINI_MODELS, MAX_OUTPUT_TOKENS } from '../../utils/config.js';
|
|
16
16
|
import { CONTEXT_SYSTEM_INSTRUCTION } from '../../utils/systemPrompts.js';
|
|
17
17
|
import { debugLog } from '../../utils/logger.js';
|
|
@@ -47,7 +47,10 @@ export class InvestigationAgentRunner {
|
|
|
47
47
|
this.readCache = readCache;
|
|
48
48
|
this.projectTree = projectTree;
|
|
49
49
|
this.projectType = projectType;
|
|
50
|
-
|
|
50
|
+
let model = getGlobalActiveModel();
|
|
51
|
+
if (model === GEMINI_MODELS.AUTO)
|
|
52
|
+
model = GEMINI_MODELS.FLASH_3_5;
|
|
53
|
+
this.chat = new ProxyChatSession(model, this.buildSystemInstruction(), getContextToolDeclarations(), {
|
|
51
54
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
52
55
|
temperature: 1,
|
|
53
56
|
topP: 0.95,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import * as p from '@clack/prompts';
|
|
12
12
|
import pc from 'picocolors';
|
|
13
|
-
import { ProxyChatSession } from '../ai.js';
|
|
13
|
+
import { ProxyChatSession, getGlobalActiveModel } from '../ai.js';
|
|
14
14
|
import { GEMINI_MODELS, MAX_OUTPUT_TOKENS } from '../../utils/config.js';
|
|
15
15
|
import { debugLog } from '../../utils/logger.js';
|
|
16
16
|
import { MessageBus } from './messageBus.js';
|
|
@@ -61,7 +61,10 @@ export class Orchestrator {
|
|
|
61
61
|
this.inputHandler = inputHandler;
|
|
62
62
|
this.bus = new MessageBus(workspaceRoot, conversationId);
|
|
63
63
|
this.locks = new FileLockRegistry();
|
|
64
|
-
|
|
64
|
+
let model = getGlobalActiveModel();
|
|
65
|
+
if (model === GEMINI_MODELS.AUTO)
|
|
66
|
+
model = GEMINI_MODELS.FLASH_3_5;
|
|
67
|
+
this.pmChat = new ProxyChatSession(model, PM_SYSTEM_INSTRUCTION, [], {
|
|
65
68
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
66
69
|
temperature: 0.1,
|
|
67
70
|
responseMimeType: 'application/json',
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the lifecycle, health monitoring, and tool-loop execution for a single
|
|
5
5
|
* parallelized sub-agent.
|
|
6
6
|
*/
|
|
7
|
-
import { ProxyChatSession } from '../ai.js';
|
|
7
|
+
import { ProxyChatSession, getGlobalActiveModel } from '../ai.js';
|
|
8
8
|
import { GEMINI_MODELS, MAX_OUTPUT_TOKENS } from '../../utils/config.js';
|
|
9
9
|
import { executeScopedTool, getScopedToolDeclarations } from './scopedTools.js';
|
|
10
10
|
import { debugLog } from '../../utils/logger.js';
|
|
@@ -32,8 +32,11 @@ export class SubAgentRunner {
|
|
|
32
32
|
this.bus = bus;
|
|
33
33
|
this.locks = locks;
|
|
34
34
|
this.globalContext = globalContext;
|
|
35
|
+
let model = getGlobalActiveModel();
|
|
36
|
+
if (model === GEMINI_MODELS.AUTO)
|
|
37
|
+
model = GEMINI_MODELS.FLASH_3_5;
|
|
35
38
|
// Sub-agents default to flash-3.5 for better reasoning capabilities
|
|
36
|
-
this.chat = new ProxyChatSession(
|
|
39
|
+
this.chat = new ProxyChatSession(model, this.buildSystemInstruction(), [{ functionDeclarations: getScopedToolDeclarations() }], {
|
|
37
40
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
38
41
|
temperature: 0.3, // Lower temperature for more focused execution
|
|
39
42
|
topP: 0.95,
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a single registered external workspace entry in the global registry.
|
|
3
|
+
*/
|
|
4
|
+
export interface RegisteredWorkspace {
|
|
5
|
+
/** User-chosen short alias (e.g., "backend", "shared-lib"). Used as the `@alias/` prefix. */
|
|
6
|
+
alias: string;
|
|
7
|
+
/** Validated, normalized absolute path on disk. */
|
|
8
|
+
absolutePath: string;
|
|
9
|
+
/** Unix epoch timestamp (ms) when this workspace was registered. */
|
|
10
|
+
registeredAt: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Result of resolving an `@alias/relative/path` string against the workspace registry.
|
|
14
|
+
*/
|
|
15
|
+
export interface ResolvedWorkspacePath {
|
|
16
|
+
/** The alias that was matched (e.g., "backend"). */
|
|
17
|
+
alias: string;
|
|
18
|
+
/** The absolute root directory of the matched registered workspace. */
|
|
19
|
+
workspaceRoot: string;
|
|
20
|
+
/** The relative path within that workspace (e.g., "src/routes.ts"). */
|
|
21
|
+
relativePath: string;
|
|
22
|
+
/** The fully resolved absolute path to the target file or directory. */
|
|
23
|
+
absolutePath: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Service that manages a global registry of external workspace roots.
|
|
27
|
+
*
|
|
28
|
+
* Workspaces are registered with short aliases (e.g., "backend") and referenced
|
|
29
|
+
* in file paths using the `@alias/path` prefix syntax. The registry is persisted
|
|
30
|
+
* globally at `~/.minovative-mind-cli/workspaces.json` so registrations carry
|
|
31
|
+
* across different primary workspaces.
|
|
32
|
+
*
|
|
33
|
+
* @remarks
|
|
34
|
+
* This is a singleton — use the exported `workspaceRegistry` instance.
|
|
35
|
+
* All filesystem access goes through this service to maintain the security
|
|
36
|
+
* boundary: the agent can only touch the primary workspace and explicitly
|
|
37
|
+
* registered secondary workspaces.
|
|
38
|
+
*/
|
|
39
|
+
declare class WorkspaceRegistry {
|
|
40
|
+
/** In-memory map of alias → registered workspace. */
|
|
41
|
+
private workspaces;
|
|
42
|
+
/** Whether the registry has been loaded from disk. */
|
|
43
|
+
private initialized;
|
|
44
|
+
/**
|
|
45
|
+
* Initializes the registry by loading persisted workspace entries from disk.
|
|
46
|
+
* Safe to call multiple times — subsequent calls are no-ops.
|
|
47
|
+
*/
|
|
48
|
+
init(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Registers a new external workspace root with the given alias.
|
|
51
|
+
*
|
|
52
|
+
* @param alias - Short identifier for the workspace (e.g., "backend").
|
|
53
|
+
* Must be lowercase alphanumeric with hyphens/underscores, 1–30 chars.
|
|
54
|
+
* @param absolutePath - Absolute path to the workspace root directory.
|
|
55
|
+
* Must exist on disk and be a directory.
|
|
56
|
+
* @returns The created `RegisteredWorkspace`, or throws on validation failure.
|
|
57
|
+
* @throws Error if the alias is invalid, the path doesn't exist, or the alias is already taken.
|
|
58
|
+
*/
|
|
59
|
+
register(alias: string, absolutePath: string): RegisteredWorkspace;
|
|
60
|
+
/**
|
|
61
|
+
* Removes a registered workspace by alias.
|
|
62
|
+
*
|
|
63
|
+
* @param alias - The alias to unregister.
|
|
64
|
+
* @returns `true` if the workspace was found and removed, `false` otherwise.
|
|
65
|
+
*/
|
|
66
|
+
unregister(alias: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Returns all registered workspaces as an array, sorted by alias.
|
|
69
|
+
*/
|
|
70
|
+
list(): RegisteredWorkspace[];
|
|
71
|
+
/**
|
|
72
|
+
* Returns the number of registered workspaces.
|
|
73
|
+
*/
|
|
74
|
+
get size(): number;
|
|
75
|
+
/**
|
|
76
|
+
* Checks whether any external workspaces are registered.
|
|
77
|
+
*/
|
|
78
|
+
hasWorkspaces(): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Looks up a workspace by alias.
|
|
81
|
+
*
|
|
82
|
+
* @param alias - The alias to find (without the `@` prefix).
|
|
83
|
+
* @returns The registered workspace, or `undefined` if not found.
|
|
84
|
+
*/
|
|
85
|
+
get(alias: string): RegisteredWorkspace | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Returns all workspace roots (primary + registered secondaries).
|
|
88
|
+
*
|
|
89
|
+
* @param primaryRoot - The primary workspace root (from `process.cwd()`).
|
|
90
|
+
* @returns An array of `{ alias: string | null, root: string }` entries.
|
|
91
|
+
* The primary workspace has `alias: null`.
|
|
92
|
+
*/
|
|
93
|
+
getAllRoots(primaryRoot: string): Array<{
|
|
94
|
+
alias: string | null;
|
|
95
|
+
root: string;
|
|
96
|
+
}>;
|
|
97
|
+
/**
|
|
98
|
+
* Resolves an `@alias/relative/path` string into its constituent parts.
|
|
99
|
+
*
|
|
100
|
+
* @param filePath - A file path that may or may not start with `@alias/`.
|
|
101
|
+
* @returns A `ResolvedWorkspacePath` if the path has a valid `@alias/` prefix
|
|
102
|
+
* and the alias is registered, or `null` if the path is a standard
|
|
103
|
+
* workspace-relative path (no `@` prefix or unrecognized alias).
|
|
104
|
+
* @throws Error if the path has an `@` prefix but the alias is not registered.
|
|
105
|
+
*/
|
|
106
|
+
resolve(filePath: string): ResolvedWorkspacePath | null;
|
|
107
|
+
/**
|
|
108
|
+
* Checks if a given file path uses the `@alias/` prefix syntax.
|
|
109
|
+
*
|
|
110
|
+
* @param filePath - The path to check.
|
|
111
|
+
* @returns `true` if the path starts with `@`.
|
|
112
|
+
*/
|
|
113
|
+
isAliasedPath(filePath: string): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Builds a formatted summary of all registered workspaces for system prompt injection.
|
|
116
|
+
*
|
|
117
|
+
* @returns A human-readable string listing all aliases and their paths,
|
|
118
|
+
* or an empty string if no workspaces are registered.
|
|
119
|
+
*/
|
|
120
|
+
buildPromptSummary(): string;
|
|
121
|
+
/**
|
|
122
|
+
* Loads the workspace registry from the global config file.
|
|
123
|
+
* Silently handles missing or corrupted files.
|
|
124
|
+
*/
|
|
125
|
+
private loadFromDisk;
|
|
126
|
+
/**
|
|
127
|
+
* Persists the current workspace registry to the global config file.
|
|
128
|
+
* Creates the config directory if it doesn't exist.
|
|
129
|
+
*/
|
|
130
|
+
private saveToDisk;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Singleton instance of the WorkspaceRegistry service.
|
|
134
|
+
* Initialize with `workspaceRegistry.init()` during CLI startup.
|
|
135
|
+
*/
|
|
136
|
+
export declare const workspaceRegistry: WorkspaceRegistry;
|
|
137
|
+
export {};
|