@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 +62 -2
- package/dist/repl/ReplManager.js +25 -2
- package/dist/ui/UIManager.js +2 -2
- package/dist/utils/ConversationCompacter.js +15 -12
- package/package.json +1 -1
- package/src/index.ts +74 -2
- package/src/repl/ReplManager.ts +35 -2
- package/src/ui/UIManager.ts +2 -2
- package/src/utils/ConversationCompacter.ts +17 -13
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
|
-
|
|
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
|
-
|
|
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) => {
|
package/dist/repl/ReplManager.js
CHANGED
|
@@ -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
|
}
|
package/dist/ui/UIManager.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
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
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
|
-
|
|
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
|
-
|
|
83
|
+
// Start REPL with options
|
|
84
|
+
const repl = new ReplManager(options);
|
|
13
85
|
await repl.start();
|
|
14
86
|
}
|
|
15
87
|
|
package/src/repl/ReplManager.ts
CHANGED
|
@@ -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
|
}
|
package/src/ui/UIManager.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
|
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,
|