@indiccoder/mentis-cli 1.1.0 → 1.1.2

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/dist/index.js CHANGED
@@ -2,14 +2,74 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const ReplManager_1 = require("./repl/ReplManager");
5
+ function parseArgs() {
6
+ const args = process.argv.slice(2);
7
+ const options = {
8
+ resume: false,
9
+ yolo: false,
10
+ headless: false
11
+ };
12
+ let command = null;
13
+ for (let i = 0; i < args.length; i++) {
14
+ const arg = args[i];
15
+ switch (arg) {
16
+ case 'update':
17
+ command = 'update';
18
+ break;
19
+ case '--resume':
20
+ options.resume = true;
21
+ break;
22
+ case '--yolo':
23
+ options.yolo = true;
24
+ break;
25
+ case '-p':
26
+ case '--prompt':
27
+ options.headless = true;
28
+ options.headlessPrompt = args[++i] || '';
29
+ break;
30
+ case '-h':
31
+ case '--help':
32
+ console.log(`
33
+ Mentis CLI - AI Coding Assistant
34
+
35
+ Usage:
36
+ mentis Start interactive REPL
37
+ mentis update Update to latest version
38
+ mentis --resume Resume last session
39
+ mentis --yolo Auto-confirm mode (skip confirmations)
40
+ mentis -p "<prompt>" Headless mode (non-interactive)
41
+
42
+ Options:
43
+ --resume Load latest checkpoint on start
44
+ --yolo Skip all confirmation prompts
45
+ -p, --prompt <text> Headless mode with prompt
46
+ -h, --help Show this help message
47
+
48
+ Commands (in REPL):
49
+ /help Show all available commands
50
+ /clear Clear conversation context
51
+ /resume Resume last session
52
+ /init Initialize project with .mentis.md
53
+ /skills <list|show|create|validate> Manage Agent Skills
54
+ /commands <list|create|validate> Manage Custom Commands
55
+ `);
56
+ process.exit(0);
57
+ break;
58
+ }
59
+ }
60
+ return { command, options };
61
+ }
5
62
  async function main() {
6
- if (process.argv.includes('update')) {
63
+ const { command, options } = parseArgs();
64
+ // Handle update command
65
+ if (command === 'update') {
7
66
  const { UpdateManager } = require('./utils/UpdateManager');
8
67
  const updater = new UpdateManager();
9
68
  await updater.checkAndPerformUpdate(true);
10
69
  return;
11
70
  }
12
- const repl = new ReplManager_1.ReplManager();
71
+ // Start REPL with options
72
+ const repl = new ReplManager_1.ReplManager(options);
13
73
  await repl.start();
14
74
  }
15
75
  main().catch((error) => {
@@ -67,13 +67,14 @@ const marked_1 = require("marked");
67
67
  const marked_terminal_1 = __importDefault(require("marked-terminal"));
68
68
  const HISTORY_FILE = path.join(os.homedir(), '.mentis_history');
69
69
  class ReplManager {
70
- constructor() {
70
+ constructor(options = { resume: false, yolo: false, headless: false }) {
71
71
  this.history = [];
72
72
  this.mode = 'BUILD';
73
73
  this.tools = [];
74
74
  this.mcpClients = [];
75
75
  this.currentModelName = 'Unknown';
76
76
  this.activeSkill = null; // Track currently active skill for allowed-tools
77
+ this.options = options;
77
78
  this.configManager = new ConfigManager_1.ConfigManager();
78
79
  this.contextManager = new ContextManager_1.ContextManager();
79
80
  this.checkpointManager = new CheckpointManager_1.CheckpointManager();
@@ -192,11 +193,29 @@ class ReplManager {
192
193
  // console.log(chalk.dim(`Initialized ${provider} client with model ${model}`));
193
194
  }
194
195
  async start() {
196
+ // Headless mode: non-interactive, process prompt and exit
197
+ if (this.options.headless && this.options.headlessPrompt) {
198
+ await this.handleChat(this.options.headlessPrompt);
199
+ process.exit(0);
200
+ return;
201
+ }
195
202
  UIManager_1.UIManager.renderDashboard({
196
203
  model: this.currentModelName,
197
204
  mode: this.mode,
198
205
  cwd: process.cwd()
199
206
  });
207
+ // Auto-resume if --resume flag is set
208
+ if (this.options.resume) {
209
+ const cp = this.checkpointManager.load('latest');
210
+ if (cp) {
211
+ this.history = cp.history;
212
+ console.log(chalk_1.default.green(`\n✓ Resumed session from ${new Date(cp.timestamp).toLocaleString()}`));
213
+ console.log(chalk_1.default.dim(` Messages: ${this.history.length}\n`));
214
+ }
215
+ else {
216
+ console.log(chalk_1.default.yellow('\n⚠ No previous session found to resume.\n'));
217
+ }
218
+ }
200
219
  // Load History
201
220
  let commandHistory = [];
202
221
  if (fs.existsSync(HISTORY_FILE)) {
@@ -348,6 +367,10 @@ class ReplManager {
348
367
  const updater = new UpdateManager();
349
368
  await updater.checkAndPerformUpdate(true);
350
369
  break;
370
+ case '/clear':
371
+ this.history = [];
372
+ console.log(chalk_1.default.green('\n✓ Context cleared\n'));
373
+ break;
351
374
  case '/init':
352
375
  await this.handleInitCommand();
353
376
  break;
@@ -529,7 +552,7 @@ class ReplManager {
529
552
  // Auto-compact prompt when context is at 80%
530
553
  const usage = this.contextVisualizer.calculateUsage(this.history);
531
554
  if (usage.percentage >= 80) {
532
- this.history = await this.conversationCompacter.promptIfCompactNeeded(usage.percentage, this.history, this.modelClient);
555
+ this.history = await this.conversationCompacter.promptIfCompactNeeded(usage.percentage, this.history, this.modelClient, this.options.yolo);
533
556
  }
534
557
  }
535
558
  }
@@ -19,12 +19,12 @@ class UIManager {
19
19
  whitespaceBreak: true,
20
20
  });
21
21
  console.log(gradient_string_1.default.pastel.multiline(logoText));
22
- console.log(chalk_1.default.gray(' v1.1.0 - AI Coding Agent'));
22
+ console.log(chalk_1.default.gray(' v1.1.2 - AI Coding Agent'));
23
23
  console.log('');
24
24
  }
25
25
  static renderDashboard(config) {
26
26
  const { model, cwd } = config;
27
- const version = 'v1.1.0';
27
+ const version = 'v1.1.2';
28
28
  // Layout: Left (Status/Welcome) | Right (Tips/Activity)
29
29
  // Total width ~80 chars.
30
30
  // Left ~45, Right ~30.
@@ -65,30 +65,33 @@ class ConversationCompacter {
65
65
  /**
66
66
  * Prompt user to compact when threshold is reached
67
67
  */
68
- async promptIfCompactNeeded(percentage, history, modelClient) {
68
+ async promptIfCompactNeeded(percentage, history, modelClient, yolo = false) {
69
69
  if (percentage < 80) {
70
70
  return history;
71
71
  }
72
72
  console.log(chalk_1.default.yellow(`\n⚠️ Context is ${percentage}% full. Consider compacting to save tokens.`));
73
- const { shouldCompact } = await inquirer_1.default.prompt([
74
- {
75
- type: 'confirm',
76
- name: 'shouldCompact',
77
- message: 'Compact conversation now?',
78
- default: true
73
+ // Skip confirmation if yolo mode is enabled
74
+ if (!yolo) {
75
+ const { shouldCompact } = await inquirer_1.default.prompt([
76
+ {
77
+ type: 'confirm',
78
+ name: 'shouldCompact',
79
+ message: 'Compact conversation now?',
80
+ default: true
81
+ }
82
+ ]);
83
+ if (!shouldCompact) {
84
+ return history;
79
85
  }
80
- ]);
81
- if (!shouldCompact) {
82
- return history;
83
86
  }
84
- const { focusTopic } = await inquirer_1.default.prompt([
87
+ const focusTopic = yolo ? '' : await inquirer_1.default.prompt([
85
88
  {
86
89
  type: 'input',
87
90
  name: 'focusTopic',
88
91
  message: 'Focus on specific topic? (leave empty for general)',
89
92
  default: ''
90
93
  }
91
- ]);
94
+ ]).then(a => a.focusTopic);
92
95
  return await this.compact(history, modelClient, {
93
96
  keepSystemMessages: true,
94
97
  focusTopic: focusTopic || undefined
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indiccoder/mentis-cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/index.ts CHANGED
@@ -1,15 +1,87 @@
1
1
  #!/usr/bin/env node
2
2
  import { ReplManager } from './repl/ReplManager';
3
3
 
4
+ interface CliOptions {
5
+ resume: boolean;
6
+ yolo: boolean;
7
+ headless: boolean;
8
+ headlessPrompt?: string;
9
+ }
10
+
11
+ function parseArgs(): { command: string | null, options: CliOptions } {
12
+ const args = process.argv.slice(2);
13
+ const options: CliOptions = {
14
+ resume: false,
15
+ yolo: false,
16
+ headless: false
17
+ };
18
+
19
+ let command: string | null = null;
20
+
21
+ for (let i = 0; i < args.length; i++) {
22
+ const arg = args[i];
23
+ switch (arg) {
24
+ case 'update':
25
+ command = 'update';
26
+ break;
27
+ case '--resume':
28
+ options.resume = true;
29
+ break;
30
+ case '--yolo':
31
+ options.yolo = true;
32
+ break;
33
+ case '-p':
34
+ case '--prompt':
35
+ options.headless = true;
36
+ options.headlessPrompt = args[++i] || '';
37
+ break;
38
+ case '-h':
39
+ case '--help':
40
+ console.log(`
41
+ Mentis CLI - AI Coding Assistant
42
+
43
+ Usage:
44
+ mentis Start interactive REPL
45
+ mentis update Update to latest version
46
+ mentis --resume Resume last session
47
+ mentis --yolo Auto-confirm mode (skip confirmations)
48
+ mentis -p "<prompt>" Headless mode (non-interactive)
49
+
50
+ Options:
51
+ --resume Load latest checkpoint on start
52
+ --yolo Skip all confirmation prompts
53
+ -p, --prompt <text> Headless mode with prompt
54
+ -h, --help Show this help message
55
+
56
+ Commands (in REPL):
57
+ /help Show all available commands
58
+ /clear Clear conversation context
59
+ /resume Resume last session
60
+ /init Initialize project with .mentis.md
61
+ /skills <list|show|create|validate> Manage Agent Skills
62
+ /commands <list|create|validate> Manage Custom Commands
63
+ `);
64
+ process.exit(0);
65
+ break;
66
+ }
67
+ }
68
+
69
+ return { command, options };
70
+ }
71
+
4
72
  async function main() {
5
- if (process.argv.includes('update')) {
73
+ const { command, options } = parseArgs();
74
+
75
+ // Handle update command
76
+ if (command === 'update') {
6
77
  const { UpdateManager } = require('./utils/UpdateManager');
7
78
  const updater = new UpdateManager();
8
79
  await updater.checkAndPerformUpdate(true);
9
80
  return;
10
81
  }
11
82
 
12
- const repl = new ReplManager();
83
+ // Start REPL with options
84
+ const repl = new ReplManager(options);
13
85
  await repl.start();
14
86
  }
15
87
 
@@ -33,6 +33,13 @@ import TerminalRenderer from 'marked-terminal';
33
33
 
34
34
  const HISTORY_FILE = path.join(os.homedir(), '.mentis_history');
35
35
 
36
+ export interface CliOptions {
37
+ resume: boolean;
38
+ yolo: boolean;
39
+ headless: boolean;
40
+ headlessPrompt?: string;
41
+ }
42
+
36
43
  export class ReplManager {
37
44
  private configManager: ConfigManager;
38
45
  private modelClient!: ModelClient;
@@ -49,8 +56,10 @@ export class ReplManager {
49
56
  private shell: PersistentShell;
50
57
  private currentModelName: string = 'Unknown';
51
58
  private activeSkill: string | null = null; // Track currently active skill for allowed-tools
59
+ private options: CliOptions;
52
60
 
53
- constructor() {
61
+ constructor(options: CliOptions = { resume: false, yolo: false, headless: false }) {
62
+ this.options = options;
54
63
  this.configManager = new ConfigManager();
55
64
  this.contextManager = new ContextManager();
56
65
  this.checkpointManager = new CheckpointManager();
@@ -187,12 +196,31 @@ export class ReplManager {
187
196
  }
188
197
 
189
198
  public async start() {
199
+ // Headless mode: non-interactive, process prompt and exit
200
+ if (this.options.headless && this.options.headlessPrompt) {
201
+ await this.handleChat(this.options.headlessPrompt);
202
+ process.exit(0);
203
+ return;
204
+ }
205
+
190
206
  UIManager.renderDashboard({
191
207
  model: this.currentModelName,
192
208
  mode: this.mode,
193
209
  cwd: process.cwd()
194
210
  });
195
211
 
212
+ // Auto-resume if --resume flag is set
213
+ if (this.options.resume) {
214
+ const cp = this.checkpointManager.load('latest');
215
+ if (cp) {
216
+ this.history = cp.history;
217
+ console.log(chalk.green(`\n✓ Resumed session from ${new Date(cp.timestamp).toLocaleString()}`));
218
+ console.log(chalk.dim(` Messages: ${this.history.length}\n`));
219
+ } else {
220
+ console.log(chalk.yellow('\n⚠ No previous session found to resume.\n'));
221
+ }
222
+ }
223
+
196
224
  // Load History
197
225
  let commandHistory: string[] = [];
198
226
  if (fs.existsSync(HISTORY_FILE)) {
@@ -352,6 +380,10 @@ export class ReplManager {
352
380
  const updater = new UpdateManager();
353
381
  await updater.checkAndPerformUpdate(true);
354
382
  break;
383
+ case '/clear':
384
+ this.history = [];
385
+ console.log(chalk.green('\n✓ Context cleared\n'));
386
+ break;
355
387
  case '/init':
356
388
  await this.handleInitCommand();
357
389
  break;
@@ -565,7 +597,8 @@ export class ReplManager {
565
597
  this.history = await this.conversationCompacter.promptIfCompactNeeded(
566
598
  usage.percentage,
567
599
  this.history,
568
- this.modelClient
600
+ this.modelClient,
601
+ this.options.yolo
569
602
  );
570
603
  }
571
604
  }
@@ -14,13 +14,13 @@ export class UIManager {
14
14
  whitespaceBreak: true,
15
15
  });
16
16
  console.log(gradient.pastel.multiline(logoText));
17
- console.log(chalk.gray(' v1.1.0 - AI Coding Agent'));
17
+ console.log(chalk.gray(' v1.1.2 - AI Coding Agent'));
18
18
  console.log('');
19
19
  }
20
20
 
21
21
  public static renderDashboard(config: { model: string, mode: string, cwd: string }) {
22
22
  const { model, cwd } = config;
23
- const version = 'v1.1.0';
23
+ const version = 'v1.1.2';
24
24
 
25
25
  // Layout: Left (Status/Welcome) | Right (Tips/Activity)
26
26
  // Total width ~80 chars.
@@ -86,7 +86,8 @@ export class ConversationCompacter {
86
86
  async promptIfCompactNeeded(
87
87
  percentage: number,
88
88
  history: ChatMessage[],
89
- modelClient: ModelClient
89
+ modelClient: ModelClient,
90
+ yolo: boolean = false
90
91
  ): Promise<ChatMessage[]> {
91
92
  if (percentage < 80) {
92
93
  return history;
@@ -94,27 +95,30 @@ export class ConversationCompacter {
94
95
 
95
96
  console.log(chalk.yellow(`\n⚠️ Context is ${percentage}% full. Consider compacting to save tokens.`));
96
97
 
97
- const { shouldCompact } = await inquirer.prompt([
98
- {
99
- type: 'confirm',
100
- name: 'shouldCompact',
101
- message: 'Compact conversation now?',
102
- default: true
98
+ // Skip confirmation if yolo mode is enabled
99
+ if (!yolo) {
100
+ const { shouldCompact } = await inquirer.prompt([
101
+ {
102
+ type: 'confirm',
103
+ name: 'shouldCompact',
104
+ message: 'Compact conversation now?',
105
+ default: true
106
+ }
107
+ ]);
108
+
109
+ if (!shouldCompact) {
110
+ return history;
103
111
  }
104
- ]);
105
-
106
- if (!shouldCompact) {
107
- return history;
108
112
  }
109
113
 
110
- const { focusTopic } = await inquirer.prompt([
114
+ const focusTopic = yolo ? '' : await inquirer.prompt([
111
115
  {
112
116
  type: 'input',
113
117
  name: 'focusTopic',
114
118
  message: 'Focus on specific topic? (leave empty for general)',
115
119
  default: ''
116
120
  }
117
- ]);
121
+ ]).then(a => a.focusTopic);
118
122
 
119
123
  return await this.compact(history, modelClient, {
120
124
  keepSystemMessages: true,