@indiccoder/mentis-cli 1.0.8 ā 1.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.
- package/.mentis/commands/ls.md +12 -0
- package/dist/commands/Command.js +6 -0
- package/dist/commands/CommandCreator.js +286 -0
- package/dist/commands/CommandManager.js +268 -0
- package/dist/commands/SlashCommandTool.js +160 -0
- package/dist/repl/ReplManager.js +245 -3
- package/dist/skills/LoadSkillTool.js +133 -0
- package/dist/skills/Skill.js +6 -0
- package/dist/skills/SkillCreator.js +247 -0
- package/dist/skills/SkillsManager.js +337 -0
- package/dist/ui/UIManager.js +2 -2
- package/dist/utils/ContextVisualizer.js +92 -0
- package/dist/utils/ConversationCompacter.js +98 -0
- package/dist/utils/ProjectInitializer.js +181 -0
- package/docs/SKILLS.md +319 -0
- package/examples/skills/code-reviewer/SKILL.md +88 -0
- package/examples/skills/commit-helper/SKILL.md +66 -0
- package/examples/skills/pdf-processing/SKILL.md +108 -0
- package/package.json +4 -3
- package/src/commands/Command.ts +40 -0
- package/src/commands/CommandCreator.ts +281 -0
- package/src/commands/CommandManager.ts +280 -0
- package/src/commands/SlashCommandTool.ts +152 -0
- package/src/repl/ReplManager.ts +302 -3
- package/src/skills/LoadSkillTool.ts +168 -0
- package/src/skills/Skill.ts +51 -0
- package/src/skills/SkillCreator.ts +237 -0
- package/src/skills/SkillsManager.ts +354 -0
- package/src/ui/UIManager.ts +2 -2
- package/src/utils/ContextVisualizer.ts +105 -0
- package/src/utils/ConversationCompacter.ts +124 -0
- package/src/utils/ProjectInitializer.ts +170 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit-helper
|
|
3
|
+
description: Generates clear, conventional commit messages from git diffs. Use when writing commit messages, reviewing staged changes, or when the user asks for help with git commits.
|
|
4
|
+
allowed-tools: ["GitStatus", "GitDiff", "GitCommit"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Commit Message Helper
|
|
8
|
+
|
|
9
|
+
This skill helps you write clear, informative git commit messages following conventional commit format.
|
|
10
|
+
|
|
11
|
+
## Instructions
|
|
12
|
+
|
|
13
|
+
When the user wants to commit changes:
|
|
14
|
+
|
|
15
|
+
1. **Check git status** to see what files are staged
|
|
16
|
+
2. **Review the diff** to understand what changed
|
|
17
|
+
3. **Generate a commit message** with:
|
|
18
|
+
- **Type**: One of `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
|
|
19
|
+
- **Scope**: (optional) The component or module affected
|
|
20
|
+
- **Summary**: Brief description under 50 characters
|
|
21
|
+
- **Body**: Detailed explanation of what and why (not how)
|
|
22
|
+
- **Footer**: (optional) Breaking changes or references
|
|
23
|
+
|
|
24
|
+
## Commit Types
|
|
25
|
+
|
|
26
|
+
| Type | Description |
|
|
27
|
+
|------|-------------|
|
|
28
|
+
| `feat` | New feature |
|
|
29
|
+
| `fix` | Bug fix |
|
|
30
|
+
| `docs` | Documentation changes |
|
|
31
|
+
| `style` | Code style changes (formatting, etc.) |
|
|
32
|
+
| `refactor` | Code refactoring |
|
|
33
|
+
| `test` | Adding or updating tests |
|
|
34
|
+
| `chore` | Maintenance tasks |
|
|
35
|
+
|
|
36
|
+
## Examples
|
|
37
|
+
|
|
38
|
+
### Feature Addition
|
|
39
|
+
```
|
|
40
|
+
feat(api): add user authentication endpoint
|
|
41
|
+
|
|
42
|
+
Add OAuth2 authentication for the REST API.
|
|
43
|
+
Implements login, logout, and token refresh.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Bug Fix
|
|
47
|
+
```
|
|
48
|
+
fix(cli): prevent crash when config file is missing
|
|
49
|
+
|
|
50
|
+
Check for config file existence before reading.
|
|
51
|
+
Show helpful error message if file not found.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Documentation
|
|
55
|
+
```
|
|
56
|
+
docs: update README with new installation instructions
|
|
57
|
+
|
|
58
|
+
Clarify NPM installation steps and add troubleshooting section.
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Best Practices
|
|
62
|
+
|
|
63
|
+
- Use present tense ("add" not "added")
|
|
64
|
+
- Explain what and why, not how
|
|
65
|
+
- Keep summary under 50 characters
|
|
66
|
+
- Reference issues in footer: `Closes #123`
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pdf-processing
|
|
3
|
+
description: Extract text, fill forms, merge PDFs, and manipulate PDF documents. Use when working with PDF files, forms, or document extraction. Requires pdf-parse package.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PDF Processing
|
|
7
|
+
|
|
8
|
+
This skill provides PDF manipulation capabilities for text extraction, form filling, and document operations.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
Install required packages:
|
|
13
|
+
```bash
|
|
14
|
+
npm install pdf-parse
|
|
15
|
+
# or
|
|
16
|
+
pnpm add pdf-parse
|
|
17
|
+
# or
|
|
18
|
+
yarn add pdf-parse
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Capabilities
|
|
22
|
+
|
|
23
|
+
### 1. Text Extraction
|
|
24
|
+
Extract plain text from PDF files with page-by-page information.
|
|
25
|
+
|
|
26
|
+
### 2. Form Field Detection
|
|
27
|
+
Identify and extract form fields from PDF documents.
|
|
28
|
+
|
|
29
|
+
### 3. Metadata Reading
|
|
30
|
+
Access PDF metadata like author, creation date, title.
|
|
31
|
+
|
|
32
|
+
### 4. Page Count & Info
|
|
33
|
+
Get total pages and document dimensions.
|
|
34
|
+
|
|
35
|
+
## Common Operations
|
|
36
|
+
|
|
37
|
+
### Extract All Text
|
|
38
|
+
```typescript
|
|
39
|
+
import fs from 'fs';
|
|
40
|
+
import pdf from 'pdf-parse';
|
|
41
|
+
|
|
42
|
+
const dataBuffer = fs.readFileSync('document.pdf');
|
|
43
|
+
const data = await pdf(dataBuffer);
|
|
44
|
+
|
|
45
|
+
console.log(data.text); // Full text content
|
|
46
|
+
console.log(data.numpages); // Number of pages
|
|
47
|
+
console.log(data.info); // PDF metadata
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Extract Text by Page
|
|
51
|
+
```typescript
|
|
52
|
+
const data = await pdf(dataBuffer);
|
|
53
|
+
// Text includes page breaks
|
|
54
|
+
// Split by page markers if needed
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Get PDF Info
|
|
58
|
+
```typescript
|
|
59
|
+
const data = await pdf(dataBuffer);
|
|
60
|
+
console.log({
|
|
61
|
+
pages: data.numpages,
|
|
62
|
+
info: data.info,
|
|
63
|
+
metadata: data.metadata
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Troubleshooting
|
|
68
|
+
|
|
69
|
+
### "pdf-parse not found"
|
|
70
|
+
Install the package: `npm install pdf-parse`
|
|
71
|
+
|
|
72
|
+
### Scanned PDFs return no text
|
|
73
|
+
Scanned PDFs are images. Use OCR (tesseract.js) instead.
|
|
74
|
+
|
|
75
|
+
### Encrypted PDFs
|
|
76
|
+
Password-protected PDFs cannot be read. Remove password first.
|
|
77
|
+
|
|
78
|
+
### Memory Issues with Large Files
|
|
79
|
+
For very large PDFs (>100MB), process in chunks or use streaming.
|
|
80
|
+
|
|
81
|
+
## Advanced Topics
|
|
82
|
+
|
|
83
|
+
For advanced PDF operations like filling forms, merging, or creating PDFs, see [ADVANCED.md](ADVANCED.md).
|
|
84
|
+
|
|
85
|
+
## Examples
|
|
86
|
+
|
|
87
|
+
### Quick Text Extraction
|
|
88
|
+
```bash
|
|
89
|
+
# User asks: "Extract text from this PDF"
|
|
90
|
+
# 1. Read the PDF file
|
|
91
|
+
# 2. Use pdf-parse to extract text
|
|
92
|
+
# 3. Return the text content
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Get Page Count
|
|
96
|
+
```bash
|
|
97
|
+
# User asks: "How many pages in this PDF?"
|
|
98
|
+
# 1. Parse the PDF
|
|
99
|
+
# 2. Return numpages value
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Form Analysis
|
|
103
|
+
```bash
|
|
104
|
+
# User asks: "What fields are in this PDF form?"
|
|
105
|
+
# 1. Parse the PDF
|
|
106
|
+
# 2. Look for form field patterns
|
|
107
|
+
# 3. List detected fields
|
|
108
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indiccoder/mentis-cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"screenshot-desktop": "^1.15.3",
|
|
51
51
|
"uuid": "^13.0.0",
|
|
52
52
|
"vscode-ripgrep": "^1.13.2",
|
|
53
|
-
"xlsx": "^0.18.5"
|
|
53
|
+
"xlsx": "^0.18.5",
|
|
54
|
+
"yaml": "^2.7.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/figlet": "^1.7.0",
|
|
@@ -60,4 +61,4 @@
|
|
|
60
61
|
"@types/node": "^25.0.2",
|
|
61
62
|
"typescript": "^5.9.3"
|
|
62
63
|
}
|
|
63
|
-
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Slash Commands System
|
|
3
|
+
* Users can define their own slash commands as markdown files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface CommandFrontmatter {
|
|
7
|
+
description?: string;
|
|
8
|
+
'allowed-tools'?: string[];
|
|
9
|
+
'argument-hint'?: string;
|
|
10
|
+
model?: string;
|
|
11
|
+
'disable-model-invocation'?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Command {
|
|
15
|
+
name: string; // Command name (from filename)
|
|
16
|
+
type: 'personal' | 'project'; // Personal or project command
|
|
17
|
+
path: string; // Path to command file
|
|
18
|
+
directory: string; // Directory containing the command
|
|
19
|
+
frontmatter: CommandFrontmatter;
|
|
20
|
+
content: string; // Command content (markdown)
|
|
21
|
+
description: string; // Command description
|
|
22
|
+
hasParameters: boolean; // Whether command uses parameters
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface CommandExecutionContext {
|
|
26
|
+
command: Command;
|
|
27
|
+
args: string[]; // Command arguments
|
|
28
|
+
substitutePlaceholders: (content: string, args: string[]) => string;
|
|
29
|
+
executeBash: (bashCommand: string) => Promise<string>;
|
|
30
|
+
readFile: (filePath: string) => Promise<string>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parsed command with substitutions applied
|
|
35
|
+
*/
|
|
36
|
+
export interface ParsedCommand {
|
|
37
|
+
content: string; // Content with substitutions applied
|
|
38
|
+
bashCommands: string[]; // Bash commands to execute
|
|
39
|
+
fileReferences: string[]; // Files to read
|
|
40
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CommandCreator - Interactive wizard for creating new custom slash commands
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import * as os from 'os';
|
|
9
|
+
import { CommandManager } from './CommandManager';
|
|
10
|
+
|
|
11
|
+
export class CommandCreator {
|
|
12
|
+
private commandManager: CommandManager;
|
|
13
|
+
|
|
14
|
+
constructor(commandManager?: CommandManager) {
|
|
15
|
+
this.commandManager = commandManager || new CommandManager();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Run the interactive command creation wizard
|
|
20
|
+
*/
|
|
21
|
+
async run(name?: string): Promise<boolean> {
|
|
22
|
+
console.log('\nš Create a new Custom Slash Command\n');
|
|
23
|
+
|
|
24
|
+
let commandName: string;
|
|
25
|
+
let commandType: 'personal' | 'project';
|
|
26
|
+
let description: string;
|
|
27
|
+
let allowedTools: string[] | undefined;
|
|
28
|
+
let argumentHint: string | undefined;
|
|
29
|
+
let namespace: string | undefined;
|
|
30
|
+
|
|
31
|
+
// Step 1: Command Name
|
|
32
|
+
if (name) {
|
|
33
|
+
commandName = name;
|
|
34
|
+
} else {
|
|
35
|
+
const { name: inputName } = await inquirer.prompt([
|
|
36
|
+
{
|
|
37
|
+
type: 'input',
|
|
38
|
+
name: 'name',
|
|
39
|
+
message: 'Command name (lowercase, numbers, hyphens only):',
|
|
40
|
+
validate: (input: string) => {
|
|
41
|
+
if (!input) return 'Name is required';
|
|
42
|
+
if (!/^[a-z0-9-]+$/.test(input)) {
|
|
43
|
+
return 'Name must contain only lowercase letters, numbers, and hyphens';
|
|
44
|
+
}
|
|
45
|
+
if (input.length > 64) return 'Name must be 64 characters or less';
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
]);
|
|
50
|
+
commandName = inputName;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Step 2: Command Type
|
|
54
|
+
const { type } = await inquirer.prompt([
|
|
55
|
+
{
|
|
56
|
+
type: 'list',
|
|
57
|
+
name: 'type',
|
|
58
|
+
message: 'Command type:',
|
|
59
|
+
choices: [
|
|
60
|
+
{ name: 'Personal (available in all projects)', value: 'personal' },
|
|
61
|
+
{ name: 'Project (shared with team via git)', value: 'project' }
|
|
62
|
+
],
|
|
63
|
+
default: 'personal'
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
commandType = type;
|
|
67
|
+
|
|
68
|
+
// Step 3: Namespace (optional, for grouping)
|
|
69
|
+
const { useNamespace } = await inquirer.prompt([
|
|
70
|
+
{
|
|
71
|
+
type: 'confirm',
|
|
72
|
+
name: 'useNamespace',
|
|
73
|
+
message: 'Add a namespace for grouping?',
|
|
74
|
+
default: false
|
|
75
|
+
}
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
if (useNamespace) {
|
|
79
|
+
const { ns } = await inquirer.prompt([
|
|
80
|
+
{
|
|
81
|
+
type: 'input',
|
|
82
|
+
name: 'ns',
|
|
83
|
+
message: 'Namespace (e.g., "git", "review", "test"):',
|
|
84
|
+
validate: (input: string) => {
|
|
85
|
+
if (!input) return 'Namespace is required';
|
|
86
|
+
if (!/^[a-z0-9-]+$/.test(input)) {
|
|
87
|
+
return 'Namespace must contain only lowercase letters, numbers, and hyphens';
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
]);
|
|
93
|
+
namespace = ns;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Step 4: Description
|
|
97
|
+
const { desc } = await inquirer.prompt([
|
|
98
|
+
{
|
|
99
|
+
type: 'input',
|
|
100
|
+
name: 'desc',
|
|
101
|
+
message: 'Description:',
|
|
102
|
+
validate: (input: string) => {
|
|
103
|
+
if (!input) return 'Description is required';
|
|
104
|
+
if (input.length > 1024) return 'Description must be 1024 characters or less';
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
]);
|
|
109
|
+
description = desc;
|
|
110
|
+
|
|
111
|
+
// Step 5: Arguments (optional)
|
|
112
|
+
const { useArgs } = await inquirer.prompt([
|
|
113
|
+
{
|
|
114
|
+
type: 'confirm',
|
|
115
|
+
name: 'useArgs',
|
|
116
|
+
message: 'Does this command accept arguments?',
|
|
117
|
+
default: false
|
|
118
|
+
}
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
if (useArgs) {
|
|
122
|
+
const { hint } = await inquirer.prompt([
|
|
123
|
+
{
|
|
124
|
+
type: 'input',
|
|
125
|
+
name: 'hint',
|
|
126
|
+
message: 'Argument hint (e.g., "<file>", "[options]"):',
|
|
127
|
+
validate: (input: string) => {
|
|
128
|
+
if (!input) return 'Argument hint is required';
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]);
|
|
133
|
+
argumentHint = hint;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Step 6: Allowed Tools (optional)
|
|
137
|
+
const { useAllowedTools } = await inquirer.prompt([
|
|
138
|
+
{
|
|
139
|
+
type: 'confirm',
|
|
140
|
+
name: 'useAllowedTools',
|
|
141
|
+
message: 'Restrict which tools this command can use?',
|
|
142
|
+
default: false
|
|
143
|
+
}
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
if (useAllowedTools) {
|
|
147
|
+
const { tools } = await inquirer.prompt([
|
|
148
|
+
{
|
|
149
|
+
type: 'checkbox',
|
|
150
|
+
name: 'tools',
|
|
151
|
+
message: 'Select allowed tools:',
|
|
152
|
+
choices: [
|
|
153
|
+
{ name: 'Read (read_file)', value: 'Read' },
|
|
154
|
+
{ name: 'Write (write_file)', value: 'Write' },
|
|
155
|
+
{ name: 'Edit (edit_file)', value: 'Edit' },
|
|
156
|
+
{ name: 'Grep (search files)', value: 'Grep' },
|
|
157
|
+
{ name: 'Glob (find files)', value: 'Glob' },
|
|
158
|
+
{ name: 'ListDir (list directory)', value: 'ListDir' },
|
|
159
|
+
{ name: 'SearchFile (search in files)', value: 'SearchFile' },
|
|
160
|
+
{ name: 'RunShell (run shell command)', value: 'RunShell' },
|
|
161
|
+
{ name: 'WebSearch (web search)', value: 'WebSearch' },
|
|
162
|
+
{ name: 'GitStatus', value: 'GitStatus' },
|
|
163
|
+
{ name: 'GitDiff', value: 'GitDiff' },
|
|
164
|
+
{ name: 'GitCommit', value: 'GitCommit' },
|
|
165
|
+
{ name: 'GitPush', value: 'GitPush' },
|
|
166
|
+
{ name: 'GitPull', value: 'GitPull' }
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
]);
|
|
170
|
+
allowedTools = tools.length > 0 ? tools : undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Step 7: Create the command
|
|
174
|
+
return this.createCommand(commandName, commandType, description, allowedTools, argumentHint, namespace);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Create the command file
|
|
179
|
+
*/
|
|
180
|
+
async createCommand(
|
|
181
|
+
name: string,
|
|
182
|
+
type: 'personal' | 'project',
|
|
183
|
+
description: string,
|
|
184
|
+
allowedTools?: string[],
|
|
185
|
+
argumentHint?: string,
|
|
186
|
+
namespace?: string
|
|
187
|
+
): Promise<boolean> {
|
|
188
|
+
const baseDir = type === 'personal'
|
|
189
|
+
? path.join(os.homedir(), '.mentis', 'commands')
|
|
190
|
+
: path.join(process.cwd(), '.mentis', 'commands');
|
|
191
|
+
|
|
192
|
+
const commandDir = namespace ? path.join(baseDir, namespace) : baseDir;
|
|
193
|
+
const commandFile = path.join(commandDir, `${name}.md`);
|
|
194
|
+
|
|
195
|
+
// Check if command already exists
|
|
196
|
+
if (fs.existsSync(commandFile)) {
|
|
197
|
+
const { overwrite } = await inquirer.prompt([
|
|
198
|
+
{
|
|
199
|
+
type: 'confirm',
|
|
200
|
+
name: 'overwrite',
|
|
201
|
+
message: `Command "${name}" already exists. Overwrite?`,
|
|
202
|
+
default: false
|
|
203
|
+
}
|
|
204
|
+
]);
|
|
205
|
+
|
|
206
|
+
if (!overwrite) {
|
|
207
|
+
console.log('Cancelled.');
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Create directory
|
|
213
|
+
if (!fs.existsSync(commandDir)) {
|
|
214
|
+
fs.mkdirSync(commandDir, { recursive: true });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Generate command content
|
|
218
|
+
let content = `---\ndescription: ${description}\n`;
|
|
219
|
+
|
|
220
|
+
if (allowedTools && allowedTools.length > 0) {
|
|
221
|
+
content += `allowed-tools: [${allowedTools.map(t => `"${t}"`).join(', ')}]\n`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (argumentHint) {
|
|
225
|
+
content += `argument-hint: "${argumentHint}"\n`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
content += `---\n\n`;
|
|
229
|
+
|
|
230
|
+
// Add usage instructions in markdown
|
|
231
|
+
content += `## Usage\n\n`;
|
|
232
|
+
content += `Use this command by typing: /${name}${argumentHint ? ` ${argumentHint}` : ''}\n\n`;
|
|
233
|
+
content += `## Instructions\n\n`;
|
|
234
|
+
content += `Add your instructions here. You can use:\n`;
|
|
235
|
+
content += `- \`$1\`, \`$2\`, etc. for positional arguments\n`;
|
|
236
|
+
content += `- \`$ARGUMENTS\` for all arguments\n`;
|
|
237
|
+
content += `- \`\!\\\`command\`\` for bash commands\n`;
|
|
238
|
+
content += `- \`@file\` for file references\n\n`;
|
|
239
|
+
|
|
240
|
+
// Write command file
|
|
241
|
+
fs.writeFileSync(commandFile, content, 'utf-8');
|
|
242
|
+
|
|
243
|
+
console.log(`\nā Command created at: ${commandFile}`);
|
|
244
|
+
console.log(`\nNext steps:`);
|
|
245
|
+
console.log(` 1. Edit ${commandFile} to add instructions`);
|
|
246
|
+
console.log(` 2. Restart Mentis or use /commands validate to load the new command`);
|
|
247
|
+
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Validate commands and show results
|
|
254
|
+
*/
|
|
255
|
+
export async function validateCommands(commandManager: CommandManager): Promise<void> {
|
|
256
|
+
const commands = commandManager.getAllCommands();
|
|
257
|
+
|
|
258
|
+
console.log('\nš Command Validation Results\n');
|
|
259
|
+
|
|
260
|
+
if (commands.length === 0) {
|
|
261
|
+
console.log('No custom commands to validate.');
|
|
262
|
+
console.log('Create commands with: /commands create');
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for (const cmd of commands) {
|
|
267
|
+
const isValid = cmd.name && cmd.name.length > 0 && cmd.content.length > 0;
|
|
268
|
+
const icon = isValid ? 'ā' : 'ā';
|
|
269
|
+
console.log(`${icon} /${cmd.name} (${cmd.type})`);
|
|
270
|
+
|
|
271
|
+
if (!isValid) {
|
|
272
|
+
console.log(` ERROR: Invalid command structure`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (cmd.frontmatter['allowed-tools'] && cmd.frontmatter['allowed-tools'].length > 0) {
|
|
276
|
+
console.log(` Allowed tools: ${cmd.frontmatter['allowed-tools'].join(', ')}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
console.log(`\nā Validated ${commands.length} commands`);
|
|
281
|
+
}
|