minovative-mind-cli 1.5.1 → 2.1.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.
Files changed (79) hide show
  1. package/README.md +59 -45
  2. package/dist/commands/chat.js +10 -2
  3. package/dist/services/agent/slashCommands.js +369 -42
  4. package/dist/services/agent/toolLoop.d.ts +1 -1
  5. package/dist/services/agent/toolLoop.js +7 -2
  6. package/dist/services/agent/types.d.ts +2 -0
  7. package/dist/services/agent-tools.d.ts +9 -4
  8. package/dist/services/agent-tools.js +272 -34
  9. package/dist/services/agent.d.ts +8 -0
  10. package/dist/services/agent.js +288 -40
  11. package/dist/services/ai.d.ts +19 -5
  12. package/dist/services/ai.js +182 -36
  13. package/dist/services/changeLogger.d.ts +142 -0
  14. package/dist/services/changeLogger.js +132 -3
  15. package/dist/services/contextAgent.d.ts +6 -1
  16. package/dist/services/contextAgent.js +112 -19
  17. package/dist/services/embeddingIndex.d.ts +82 -0
  18. package/dist/services/embeddingIndex.js +613 -0
  19. package/dist/services/investigationComplexity.d.ts +45 -0
  20. package/dist/services/investigationComplexity.js +91 -0
  21. package/dist/services/metrics.d.ts +18 -0
  22. package/dist/services/metrics.js +7 -0
  23. package/dist/services/orchestration/fileLockRegistry.d.ts +125 -0
  24. package/dist/services/orchestration/fileLockRegistry.js +276 -0
  25. package/dist/services/orchestration/investigationAgent.d.ts +85 -0
  26. package/dist/services/orchestration/investigationAgent.js +362 -0
  27. package/dist/services/orchestration/investigationOrchestrator.d.ts +53 -0
  28. package/dist/services/orchestration/investigationOrchestrator.js +180 -0
  29. package/dist/services/orchestration/messageBus.d.ts +162 -0
  30. package/dist/services/orchestration/messageBus.js +225 -0
  31. package/dist/services/orchestration/orchestrator.d.ts +45 -0
  32. package/dist/services/orchestration/orchestrator.js +217 -0
  33. package/dist/services/orchestration/readCache.d.ts +79 -0
  34. package/dist/services/orchestration/readCache.js +108 -0
  35. package/dist/services/orchestration/scopedTools.d.ts +57 -0
  36. package/dist/services/orchestration/scopedTools.js +172 -0
  37. package/dist/services/orchestration/subAgent.d.ts +58 -0
  38. package/dist/services/orchestration/subAgent.js +190 -0
  39. package/dist/services/orchestration/taskGraph.d.ts +129 -0
  40. package/dist/services/orchestration/taskGraph.js +254 -0
  41. package/dist/services/proxyClient.d.ts +25 -0
  42. package/dist/services/proxyClient.js +60 -0
  43. package/dist/services/workspaceRegistry.d.ts +137 -0
  44. package/dist/services/workspaceRegistry.js +270 -0
  45. package/dist/utils/asyncContext.d.ts +16 -0
  46. package/dist/utils/asyncContext.js +25 -0
  47. package/dist/utils/config.d.ts +3 -1
  48. package/dist/utils/config.js +3 -1
  49. package/dist/utils/contextPrompts.js +10 -3
  50. package/dist/utils/dependencyTracer/modules/api.d.ts +9 -0
  51. package/dist/utils/dependencyTracer/modules/api.js +62 -0
  52. package/dist/utils/dependencyTracer/modules/graph.d.ts +9 -0
  53. package/dist/utils/dependencyTracer/modules/graph.js +23 -0
  54. package/dist/utils/dependencyTracer/modules/profiles.d.ts +7 -0
  55. package/dist/utils/dependencyTracer/modules/profiles.js +120 -0
  56. package/dist/utils/dependencyTracer/modules/resolver.d.ts +7 -0
  57. package/dist/utils/dependencyTracer/modules/resolver.js +51 -0
  58. package/dist/utils/dependencyTracer/modules/types.d.ts +4 -0
  59. package/dist/utils/dependencyTracer/modules/types.js +1 -0
  60. package/dist/utils/dependencyTracer/modules/walker.d.ts +1 -0
  61. package/dist/utils/dependencyTracer/modules/walker.js +48 -0
  62. package/dist/utils/dependencyTracer.js +31 -17
  63. package/dist/utils/excludedExtensions.js +0 -1
  64. package/dist/utils/historyPrompt.d.ts +9 -0
  65. package/dist/utils/historyPrompt.js +87 -0
  66. package/dist/utils/logo.js +7 -7
  67. package/dist/utils/paste.d.ts +21 -0
  68. package/dist/utils/paste.js +22 -1
  69. package/dist/utils/pathSecurity.d.ts +31 -0
  70. package/dist/utils/pathSecurity.js +48 -0
  71. package/dist/utils/profiles.d.ts +2 -0
  72. package/dist/utils/profiles.js +44 -0
  73. package/dist/utils/projectStorage.js +10 -7
  74. package/dist/utils/systemPrompts.d.ts +6 -3
  75. package/dist/utils/systemPrompts.js +111 -6
  76. package/dist/utils/types.d.ts +33 -0
  77. package/dist/utils/types.js +1 -0
  78. package/oclif.manifest.json +2 -2
  79. package/package.json +4 -3
@@ -1,10 +1,60 @@
1
- import { DEFAULT_MODEL, GEMINI_MODELS, MAX_OUTPUT_TOKENS } from '../utils/config.js';
2
- import { toolDeclarations } from './agent-tools.js';
1
+ import { GEMINI_MODELS, DEFAULT_MODEL, MAX_OUTPUT_TOKENS } from '../utils/config.js';
2
+ import { getToolDeclarations } from './agent-tools.js';
3
3
  import { ProxyClient } from './proxyClient.js';
4
4
  import { getAuthorizedIdToken } from './auth.js';
5
5
  import { debugLog } from '../utils/logger.js';
6
- import { GENERAL_CHAT_INSTRUCTION, PLAN_EXECUTION_INSTRUCTION, CONTEXT_SYSTEM_INSTRUCTION, INTENT_ROUTER_SYSTEM_INSTRUCTION, WEB_SEARCH_SYSTEM_INSTRUCTION, } from '../utils/systemPrompts.js';
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
+ 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
+ }
22
+ // ─── Model Overrides (for Regression Testing) ────────────────────────
23
+ let contextModelOverride = null;
24
+ let contextTempOverride = null;
25
+ let executionModelOverride = null;
26
+ let executionTempOverride = null;
27
+ export function setModelOverride(agent, overrideStr) {
28
+ const [model, temp] = overrideStr.split(':');
29
+ if (agent === 'context') {
30
+ contextModelOverride = model || null;
31
+ if (temp)
32
+ contextTempOverride = parseFloat(temp);
33
+ }
34
+ else {
35
+ executionModelOverride = model || null;
36
+ if (temp)
37
+ executionTempOverride = parseFloat(temp);
38
+ }
39
+ }
40
+ export function clearModelOverrides() {
41
+ contextModelOverride = null;
42
+ contextTempOverride = null;
43
+ executionModelOverride = null;
44
+ executionTempOverride = null;
45
+ }
7
46
  // ─── AI Service ──────────────────────────────────────────────────────
47
+ let globalActiveModel = DEFAULT_MODEL;
48
+ export function setGlobalActiveModel(model) {
49
+ globalActiveModel = model;
50
+ }
51
+ export function getGlobalActiveModel() {
52
+ return globalActiveModel;
53
+ }
54
+ let globalLatestUsageMetadata = undefined;
55
+ export function getGlobalLatestUsageMetadata() {
56
+ return globalLatestUsageMetadata;
57
+ }
8
58
  const proxyClient = new ProxyClient();
9
59
  // ─── History Limits ──────────────────────────────────────────────────
10
60
  /** Maximum number of Content entries to keep in the sliding history window. */
@@ -91,7 +141,7 @@ export class ProxyChatSession {
91
141
  this.history = this.history.slice(trimCount);
92
142
  }
93
143
  }
94
- async sendMessage(message, additionalText, abortSignal) {
144
+ async sendMessage(message, additionalText, abortSignal, onChunk) {
95
145
  const idToken = await getAuthorizedIdToken();
96
146
  if (!idToken) {
97
147
  throw new Error('You are not signed in. Please run `minovative-mind-cli login` first.');
@@ -102,18 +152,29 @@ export class ProxyChatSession {
102
152
  newParts = [{ text: truncatePartText(message) }];
103
153
  }
104
154
  else {
105
- // It's an array of function responses — truncate output strings
106
- newParts = message.map((m) => ({
107
- functionResponse: {
108
- name: m.functionResponse.name,
109
- response: {
110
- ...m.functionResponse.response,
111
- output: typeof m.functionResponse.response.output === 'string'
112
- ? truncatePartText(m.functionResponse.response.output)
113
- : m.functionResponse.response.output,
155
+ // It's an array of function responses
156
+ newParts = [];
157
+ for (const m of message) {
158
+ newParts.push({
159
+ functionResponse: {
160
+ name: m.functionResponse.name,
161
+ response: {
162
+ ...m.functionResponse.response,
163
+ output: typeof m.functionResponse.response.output === 'string'
164
+ ? truncatePartText(m.functionResponse.response.output)
165
+ : m.functionResponse.response.output,
166
+ },
114
167
  },
115
- },
116
- }));
168
+ });
169
+ // If the tool execution returned inlineData (e.g. reading a PDF), append it as a sibling Part
170
+ if (m.functionResponse.response.inlineData) {
171
+ newParts.push({
172
+ inlineData: m.functionResponse.response.inlineData
173
+ });
174
+ // Remove it from the textual output payload to avoid schema violations in functionResponse
175
+ delete newParts[newParts.length - 2].functionResponse.response.inlineData;
176
+ }
177
+ }
117
178
  }
118
179
  if (additionalText) {
119
180
  newParts.push({ text: truncatePartText(additionalText) });
@@ -125,8 +186,20 @@ export class ProxyChatSession {
125
186
  // Prune old history before sending to keep payload bounded
126
187
  this.pruneHistory();
127
188
  const effectiveGenerationConfig = { ...this.generationConfig };
128
- const result = await proxyClient.generateFunctionCallViaProxy(idToken, this.modelName, this.history, this.tools, undefined, this.systemInstruction, effectiveGenerationConfig, undefined, abortSignal);
189
+ const result = await proxyClient.generateFunctionCallViaProxy(idToken, this.modelName, this.history, this.tools, undefined, // toolConfig
190
+ this.systemInstruction, effectiveGenerationConfig, onChunk ? { onChunk } : undefined, // streamCallbacks
191
+ abortSignal);
129
192
  this.latestUsageMetadata = result.usageMetadata;
193
+ if (result.usageMetadata) {
194
+ globalLatestUsageMetadata = result.usageMetadata;
195
+ }
196
+ // Track token usage metrics
197
+ if (result.usageMetadata) {
198
+ const collector = getMetricCollector();
199
+ if (collector) {
200
+ collector.recordTokenUsage(result.usageMetadata.promptTokens || 0, result.usageMetadata.candidatesTokens || 0, result.usageMetadata.cachedTokens || 0);
201
+ }
202
+ }
130
203
  // Append model response to history
131
204
  let modelParts = [];
132
205
  const allFunctionCalls = [...(result.functionCalls || [])];
@@ -184,9 +257,12 @@ export class ProxyChatSession {
184
257
  * Creates a new shared multi-turn chat session via the proxy.
185
258
  */
186
259
  export function createSharedChatSession() {
187
- return new ProxyChatSession(DEFAULT_MODEL, GENERAL_CHAT_INSTRUCTION, [], {
260
+ let model = executionModelOverride || getGlobalActiveModel();
261
+ if (model === 'auto')
262
+ model = GEMINI_MODELS.FLASH_3_5; // Will be overridden per-turn in executeSingleTurn
263
+ return new ProxyChatSession(model, GENERAL_CHAT_INSTRUCTION, [], {
188
264
  maxOutputTokens: MAX_OUTPUT_TOKENS,
189
- temperature: 1,
265
+ temperature: executionTempOverride !== null ? executionTempOverride : 1,
190
266
  topP: 0.95,
191
267
  topK: 40,
192
268
  });
@@ -199,23 +275,36 @@ export function getGeneralChatConfig() {
199
275
  }
200
276
  export function getPlanExecutionConfig() {
201
277
  return {
202
- systemInstruction: PLAN_EXECUTION_INSTRUCTION,
203
- tools: [{ functionDeclarations: toolDeclarations }],
278
+ systemInstruction: PLAN_EXECUTION_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()),
279
+ tools: [{ functionDeclarations: getToolDeclarations() }],
280
+ };
281
+ }
282
+ export function getPlanModeConfig() {
283
+ return {
284
+ systemInstruction: PLAN_MODE_INSTRUCTION,
285
+ tools: [], // No tools allowed in plan mode
204
286
  };
205
287
  }
206
288
  /**
207
289
  * Compresses a large string of text using gemini-3.1-flash-lite.
208
290
  * Used for shrinking context payloads to prevent OOM/choking.
209
291
  */
210
- export async function compressTextUsingFlashLite(text, instruction = 'Summarize the following text concisely. Preserve the most critical technical details, function names, and architecture logic. Keep it under 1500 characters.') {
211
- if (!text || text.length < 1000)
292
+ export async function compressTextUsingFlashLite(text, instruction = 'Summarize the following text concisely. Preserve the most critical technical details, function names, and architecture logic. Keep it under 1500 characters.', inlineData) {
293
+ if (!text || (text.length < 1000 && !inlineData))
212
294
  return text; // Don't compress tiny texts
213
295
  try {
214
296
  const idToken = await getAuthorizedIdToken();
215
297
  if (!idToken)
216
298
  return text;
217
- const contents = [{ role: 'user', parts: [{ text }] }];
218
- const result = await proxyClient.generateFunctionCallViaProxy(idToken, 'gemini-3.1-flash-lite', contents, [], // no tools
299
+ let model = getGlobalActiveModel();
300
+ if (model === 'auto')
301
+ model = GEMINI_MODELS.FLASH_LITE_3_1;
302
+ const parts = [{ text }];
303
+ if (inlineData) {
304
+ parts.push({ inlineData });
305
+ }
306
+ const contents = [{ role: 'user', parts }];
307
+ const result = await proxyClient.generateFunctionCallViaProxy(idToken, model, contents, [], // no tools
219
308
  undefined, instruction, { temperature: 0.2 });
220
309
  let textPart = '';
221
310
  if (result.parts) {
@@ -236,9 +325,13 @@ export async function compressTextUsingFlashLite(text, instruction = 'Summarize
236
325
  }
237
326
  }
238
327
  // ─── Context Agent Service ───────────────────────────────────────────
239
- export const CONTEXT_AGENT_MODEL = DEFAULT_MODEL;
240
- export function createContextAgentSession() {
241
- const contextTools = [
328
+ /**
329
+ * Returns the tool declarations for the read-only Context Agent.
330
+ * Extracted as a reusable function so investigation sub-agents can import
331
+ * the same schema without duplicating the declarations.
332
+ */
333
+ export function getContextToolDeclarations() {
334
+ return [
242
335
  {
243
336
  functionDeclarations: [
244
337
  {
@@ -271,7 +364,7 @@ export function createContextAgentSession() {
271
364
  },
272
365
  {
273
366
  name: 'read_file',
274
- description: 'Read a single file. Use startLine and endLine to read specific chunks of massive files.',
367
+ description: 'Read a single file. Supports text files and native parsing of .pdf files (including math and diagrams). Use startLine and endLine to read specific chunks of massive text files.',
275
368
  parameters: {
276
369
  type: 'OBJECT',
277
370
  properties: {
@@ -346,7 +439,8 @@ export function createContextAgentSession() {
346
439
  "language's native AST parser (e.g., TypeScript compiler API, Python ast module, go/parser). " +
347
440
  'The script is executed from a temporary directory and automatically cleaned up after execution. ' +
348
441
  'Output should be structured JSON to stdout with name, type, startLine, endLine for each code element. ' +
349
- 'Use the results to make precise read_file calls with exact startLine/endLine instead of guessing.',
442
+ 'Use the results to make precise read_file calls with exact startLine/endLine instead of guessing. ' +
443
+ 'CRITICAL: Do not use this tool on binary, document, or non-code files (e.g. PDF, image, audio, docx).',
350
444
  parameters: {
351
445
  type: 'OBJECT',
352
446
  properties: {
@@ -393,26 +487,75 @@ export function createContextAgentSession() {
393
487
  required: ['query'],
394
488
  },
395
489
  },
490
+ {
491
+ name: 'semantic_search',
492
+ description: 'Search the codebase by meaning and concept rather than exact text match. ' +
493
+ 'Use this when you need to find code related to a concept, pattern, or behavior ' +
494
+ "but don't know the exact variable or function names to grep for. " +
495
+ 'Examples: "error handling for API requests", "user authentication flow", ' +
496
+ '"database connection pooling logic". Returns ranked results with file paths, ' +
497
+ 'line ranges, and similarity scores.',
498
+ parameters: {
499
+ type: 'OBJECT',
500
+ properties: {
501
+ query: {
502
+ type: 'STRING',
503
+ description: "Natural language description of what you're looking for in the codebase.",
504
+ },
505
+ topK: {
506
+ type: 'NUMBER',
507
+ description: 'Number of results to return. Defaults to 5, maximum 15.',
508
+ },
509
+ },
510
+ required: ['query'],
511
+ },
512
+ },
396
513
  ],
397
514
  },
398
515
  ];
399
- return new ProxyChatSession(CONTEXT_AGENT_MODEL, CONTEXT_SYSTEM_INSTRUCTION, contextTools, {
516
+ }
517
+ export function createContextAgentSession() {
518
+ const contextTools = getContextToolDeclarations();
519
+ let model = contextModelOverride || getGlobalActiveModel();
520
+ if (model === 'auto')
521
+ model = GEMINI_MODELS.FLASH_3_5;
522
+ return new ProxyChatSession(model, CONTEXT_SYSTEM_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()), contextTools, {
400
523
  maxOutputTokens: MAX_OUTPUT_TOKENS,
401
- temperature: 1,
524
+ temperature: contextTempOverride !== null ? contextTempOverride : 1,
402
525
  topP: 0.95,
403
526
  topK: 40,
404
527
  });
405
528
  }
406
529
  // ─── Intent Router Service ───────────────────────────────────────────
407
- export const INTENT_ROUTER_MODEL = GEMINI_MODELS.FLASH_LITE_3_1;
408
530
  export function createIntentRouterSession() {
409
- return new ProxyChatSession(INTENT_ROUTER_MODEL, INTENT_ROUTER_SYSTEM_INSTRUCTION, [], // no tools
531
+ let model = getGlobalActiveModel();
532
+ if (model === 'auto')
533
+ model = GEMINI_MODELS.FLASH_LITE_3_1;
534
+ return new ProxyChatSession(model, INTENT_ROUTER_SYSTEM_INSTRUCTION, [], // no tools
535
+ { temperature: 0, responseMimeType: 'application/json' });
536
+ }
537
+ // ─── Execution Complexity Router Service ──────────────────────────────
538
+ export function createExecutionComplexitySession() {
539
+ let model = getGlobalActiveModel();
540
+ if (model === 'auto')
541
+ model = GEMINI_MODELS.FLASH_LITE_3_1;
542
+ return new ProxyChatSession(model, EXECUTION_COMPLEXITY_SYSTEM_INSTRUCTION, [], // no tools
543
+ { temperature: 0, responseMimeType: 'application/json' });
544
+ }
545
+ // ─── Investigation Complexity Router Service ─────────────────────────
546
+ export function createInvestigationComplexitySession() {
547
+ let model = getGlobalActiveModel();
548
+ if (model === 'auto')
549
+ model = GEMINI_MODELS.FLASH_LITE_3_1;
550
+ return new ProxyChatSession(model, INVESTIGATION_COMPLEXITY_SYSTEM_INSTRUCTION, [], // no tools
410
551
  { temperature: 0, responseMimeType: 'application/json' });
411
552
  }
412
553
  // ─── Web Search Agent Service ───────────────────────────────────────────
413
- export const WEB_SEARCH_AGENT_MODEL = GEMINI_MODELS.FLASH_LITE_3_1;
414
554
  export function createWebSearchAgentSession() {
415
- return new ProxyChatSession(WEB_SEARCH_AGENT_MODEL, WEB_SEARCH_SYSTEM_INSTRUCTION, [{ googleSearch: {} }], {
555
+ let model = getGlobalActiveModel();
556
+ if (model === 'auto')
557
+ model = GEMINI_MODELS.FLASH_3_5;
558
+ return new ProxyChatSession(model, WEB_SEARCH_SYSTEM_INSTRUCTION, [{ googleSearch: {} }], {
416
559
  maxOutputTokens: MAX_OUTPUT_TOKENS,
417
560
  temperature: 1,
418
561
  topP: 0.95,
@@ -432,7 +575,10 @@ export async function generateChatTitle(firstMessage) {
432
575
  return firstMessage.substring(0, maxLength);
433
576
  const instruction = "You are a helpful assistant that generates extremely concise chat titles (max 4-5 words) based on a user's first message. Output ONLY the title, no quotes, no markdown, no punctuation.";
434
577
  const contents = [{ role: 'user', parts: [{ text: firstMessage.substring(0, 500) }] }];
435
- const result = await proxyClient.generateFunctionCallViaProxy(idToken, 'gemini-3.1-flash-lite', contents, [], // no tools
578
+ let model = getGlobalActiveModel();
579
+ if (model === 'auto')
580
+ model = GEMINI_MODELS.FLASH_LITE_3_1;
581
+ const result = await proxyClient.generateFunctionCallViaProxy(idToken, model, contents, [], // no tools
436
582
  undefined, instruction, { temperature: 0.2 });
437
583
  let title = '';
438
584
  if (result.parts) {
@@ -1,31 +1,173 @@
1
+ /**
2
+ * Represents a single file modification tracked within a workspace changeset.
3
+ * Captures the state of a file before a change was applied, facilitating reversion.
4
+ */
1
5
  export interface FileChange {
6
+ /**
7
+ * Relative or absolute file path of the affected file.
8
+ */
2
9
  filePath: string;
10
+ /**
11
+ * The original content of the file before any modification in the changeset.
12
+ * A value of `null` indicates the file was newly created and did not exist previously.
13
+ */
3
14
  originalContent: string | null;
15
+ /**
16
+ * The nature of the file operation that occurred.
17
+ * - 'create': The file was newly written to disk.
18
+ * - 'modify': An existing file was updated.
19
+ * - 'delete': An existing file was removed.
20
+ */
4
21
  action: 'create' | 'modify' | 'delete';
5
22
  }
23
+ /**
24
+ * Represents a transactional unit of workspace modifications.
25
+ * Groups related file changes under a shared timestamp and intent description.
26
+ */
6
27
  export interface ChangeSet {
28
+ /**
29
+ * Unix epoch timestamp (in milliseconds) when this changeset was initiated.
30
+ */
7
31
  timestamp: number;
32
+ /**
33
+ * Developer or system-provided description explaining the intent of the changes (e.g. "Edit index.ts").
34
+ */
8
35
  description: string;
36
+ /**
37
+ * Array of individual file modifications tracking the original states prior to this changeset.
38
+ */
9
39
  changes: FileChange[];
40
+ /**
41
+ * The execution outcome status of this changeset.
42
+ * - 'partial': The change operation is still in progress or was interrupted.
43
+ * - 'complete': All planned modifications in the transaction finished successfully.
44
+ */
10
45
  status?: 'complete' | 'partial';
11
46
  }
47
+ /**
48
+ * Service class responsible for tracking, persisting, and reverting file modifications in the workspace.
49
+ * Uses a local project state file (`revert_state.json`) to persist state across CLI invocations.
50
+ */
12
51
  declare class ChangeLogger {
52
+ /**
53
+ * Ordered history stack of committed changesets, oldest first, newest last.
54
+ */
13
55
  private changeStack;
56
+ /**
57
+ * The active changeset currently receiving recorded modifications.
58
+ * Null if no change transaction is actively in progress.
59
+ */
14
60
  private currentChangeSet;
61
+ /**
62
+ * Absolute path to the active workspace root directory.
63
+ */
15
64
  private workspaceRoot;
65
+ /**
66
+ * Maximum number of historical changesets retained in memory and on disk.
67
+ * Older changesets are discarded on save once this limit is exceeded.
68
+ */
16
69
  private readonly MAX_HISTORY;
70
+ /**
71
+ * Whether the change logger is currently enabled.
72
+ */
73
+ private isEnabled;
74
+ getIsEnabled(): boolean;
75
+ setIsEnabled(enabled: boolean): void;
76
+ /**
77
+ * Initializes the ChangeLogger by setting the workspace root and loading existing
78
+ * history from the local `.minovativemind/revert_state.json` cache file.
79
+ *
80
+ * @param workspaceRoot - The absolute path to the project workspace root.
81
+ */
17
82
  init(workspaceRoot: string): void;
83
+ /**
84
+ * Persists the current committed change stack to the local cache directory.
85
+ * Enforces the `MAX_HISTORY` retention policy by slicing out older entries.
86
+ * Does nothing if the workspace root has not yet been initialized.
87
+ */
18
88
  private saveState;
89
+ /**
90
+ * Retrieves a copy of the active history stack.
91
+ *
92
+ * @returns A shallow copy of the array containing all tracked changesets.
93
+ */
19
94
  getHistory(): ChangeSet[];
95
+ /**
96
+ * Traverses backward through the history stack, popping and collecting changesets
97
+ * until a changeset matching the specified timestamp is encountered (inclusive).
98
+ * Persists the resulting truncated stack after execution.
99
+ *
100
+ * @param timestamp - The unique timestamp identifier of the target changeset to revert back to.
101
+ * @returns An array of popped changesets ordered from newest to oldest.
102
+ */
20
103
  popUntil(timestamp: number): ChangeSet[];
104
+ /**
105
+ * Initiates a new transactional changeset. If a previous changeset was in progress and
106
+ * uncommitted, it is automatically finalized and committed to the history stack first.
107
+ *
108
+ * @param description - Descriptive label summarizing the purpose of the new changeset.
109
+ */
21
110
  startChangeSet(description: string): void;
111
+ /**
112
+ * Records a file change within the active changeset.
113
+ * If no changeset is active, an anonymous default changeset is automatically initialized.
114
+ *
115
+ * @remarks
116
+ * Idempotency Guard: If the specified file already has an entry in the current changeset,
117
+ * the original state is preserved. This ensures that multiple successive modifications to
118
+ * the same file within a single transaction map back to the true original state prior to
119
+ * the onset of the transaction.
120
+ *
121
+ * @param filePath - The relative or absolute path of the file being altered.
122
+ * @param originalContent - The text content of the file prior to the change, or null if created.
123
+ * @param action - The classification of the operation ('create', 'modify', or 'delete').
124
+ */
22
125
  logChange(filePath: string, originalContent: string | null, action: 'create' | 'modify' | 'delete'): void;
126
+ /**
127
+ * Marks the status of the active changeset as 'complete', indicating that all scheduled
128
+ * operations within the scope of this transaction finished without interruption.
129
+ */
23
130
  markComplete(): void;
131
+ /**
132
+ * Retrieves a list of file paths that have been modified in the currently active changeset.
133
+ *
134
+ * @returns An array of string file paths, or an empty array if no changeset is active.
135
+ */
136
+ getChangedFiles(): string[];
137
+ /**
138
+ * Commits the active changeset to the history stack and persists the state to disk,
139
+ * provided that the changeset actually contains one or more recorded file modifications.
140
+ * Resets the active changeset state to null.
141
+ */
24
142
  commitChangeSet(): void;
143
+ /**
144
+ * Retrieves the most recently committed changeset from the history stack without removing it.
145
+ *
146
+ * @returns The latest committed ChangeSet, or null if the stack is currently empty.
147
+ */
25
148
  getLastChangeSet(): ChangeSet | null;
149
+ /**
150
+ * Returns the active, uncommitted changeset currently receiving modifications.
151
+ *
152
+ * @returns The in-progress ChangeSet, or null if no changeset is active.
153
+ */
26
154
  getCurrentChangeSet(): ChangeSet | null;
155
+ /**
156
+ * Removes and returns the most recently committed changeset from the history stack.
157
+ * Persists the newly truncated stack state back to the cache.
158
+ *
159
+ * @returns The removed ChangeSet, or null if no historical changes exist.
160
+ */
27
161
  popLastChangeSet(): ChangeSet | null;
162
+ /**
163
+ * Checks whether the history stack contains any tracked changesets.
164
+ *
165
+ * @returns True if at least one changeset is recorded; false otherwise.
166
+ */
28
167
  hasChanges(): boolean;
29
168
  }
169
+ /**
170
+ * Singleton instance of the ChangeLogger service exported for application-wide tracking.
171
+ */
30
172
  export declare const changeLogger: ChangeLogger;
31
173
  export {};