intentiai 0.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/README.md +156 -0
- package/bin/intentiai.js +39 -0
- package/commands/auth.js +242 -0
- package/commands/deploy.js +153 -0
- package/commands/docs.js +164 -0
- package/commands/intent.js +251 -0
- package/commands/project.js +193 -0
- package/commands/prompt.js +164 -0
- package/commands/route.js +187 -0
- package/commands/test.js +88 -0
- package/commands/train.js +135 -0
- package/lib/api.js +233 -0
- package/lib/config.js +94 -0
- package/package.json +47 -0
package/commands/docs.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const ora = require('ora');
|
|
4
|
+
const Table = require('cli-table3');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const FormData = require('form-data');
|
|
8
|
+
const api = require('../lib/api');
|
|
9
|
+
const config = require('../lib/config');
|
|
10
|
+
|
|
11
|
+
function requireProject() {
|
|
12
|
+
const projectKey = config.getCurrentProject();
|
|
13
|
+
if (!projectKey) {
|
|
14
|
+
console.error(chalk.red('No project selected'));
|
|
15
|
+
console.log(chalk.gray('Select a project with:'), chalk.cyan('gatellm project select'));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
return projectKey;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = (program) => {
|
|
22
|
+
const docs = program.command('docs').description('Document management for RAG');
|
|
23
|
+
|
|
24
|
+
// Upload documents
|
|
25
|
+
docs
|
|
26
|
+
.command('upload <files...>')
|
|
27
|
+
.description('Upload documents to knowledge base')
|
|
28
|
+
.option('-i, --intent <intent>', 'Associate with specific intent')
|
|
29
|
+
.action(async (files, options) => {
|
|
30
|
+
requireProject();
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const uploadResults = [];
|
|
34
|
+
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
const filePath = path.resolve(file);
|
|
37
|
+
|
|
38
|
+
if (!fs.existsSync(filePath)) {
|
|
39
|
+
console.error(chalk.red('File not found:'), filePath);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const stats = fs.statSync(filePath);
|
|
44
|
+
if (!stats.isFile()) {
|
|
45
|
+
console.error(chalk.red('Not a file:'), filePath);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const spinner = ora(`Uploading ${path.basename(filePath)}...`).start();
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const formData = new FormData();
|
|
53
|
+
formData.append('file', fs.createReadStream(filePath));
|
|
54
|
+
|
|
55
|
+
if (options.intent) {
|
|
56
|
+
formData.append('intent_name', options.intent);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await api.uploadDocument(formData);
|
|
60
|
+
|
|
61
|
+
spinner.succeed(chalk.green(`Uploaded ${path.basename(filePath)}`));
|
|
62
|
+
uploadResults.push({ file: filePath, status: 'success' });
|
|
63
|
+
} catch (error) {
|
|
64
|
+
spinner.fail(chalk.red(`Failed to upload ${path.basename(filePath)}`));
|
|
65
|
+
console.error(chalk.red(' Error:'), error.message);
|
|
66
|
+
uploadResults.push({ file: filePath, status: 'failed', error: error.message });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Summary
|
|
71
|
+
const succeeded = uploadResults.filter(r => r.status === 'success').length;
|
|
72
|
+
const failed = uploadResults.filter(r => r.status === 'failed').length;
|
|
73
|
+
|
|
74
|
+
console.log(chalk.gray('\nUpload Summary:'));
|
|
75
|
+
console.log(chalk.green(` Succeeded: ${succeeded}`));
|
|
76
|
+
if (failed > 0) {
|
|
77
|
+
console.log(chalk.red(` Failed: ${failed}`));
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error(chalk.red('Upload failed:'), error.message);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// List documents
|
|
86
|
+
docs
|
|
87
|
+
.command('list')
|
|
88
|
+
.alias('ls')
|
|
89
|
+
.description('List all documents')
|
|
90
|
+
.option('-i, --intent <intent>', 'Filter by intent')
|
|
91
|
+
.action(async (options) => {
|
|
92
|
+
requireProject();
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const spinner = ora('Fetching documents...').start();
|
|
96
|
+
|
|
97
|
+
const documents = await api.listDocuments(options.intent);
|
|
98
|
+
|
|
99
|
+
spinner.stop();
|
|
100
|
+
|
|
101
|
+
if (documents.length === 0) {
|
|
102
|
+
console.log(chalk.yellow('No documents found'));
|
|
103
|
+
console.log(chalk.gray('Upload one with:'), chalk.cyan('gatellm docs upload <file>'));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const table = new Table({
|
|
108
|
+
head: [chalk.cyan('ID'), chalk.cyan('Filename'), chalk.cyan('Intent'), chalk.cyan('Chunks'), chalk.cyan('Uploaded')],
|
|
109
|
+
colWidths: [8, 30, 20, 10, 20]
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
documents.forEach(doc => {
|
|
113
|
+
table.push([
|
|
114
|
+
doc.id,
|
|
115
|
+
doc.filename,
|
|
116
|
+
doc.intent_name || chalk.gray('(global)'),
|
|
117
|
+
doc.chunk_count || 0,
|
|
118
|
+
new Date(doc.uploaded_at).toLocaleDateString()
|
|
119
|
+
]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
console.log(table.toString());
|
|
123
|
+
console.log(chalk.gray(`\nTotal: ${documents.length} document(s)`));
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error(chalk.red('Failed to list documents:'), error.message);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Delete document
|
|
131
|
+
docs
|
|
132
|
+
.command('delete <id>')
|
|
133
|
+
.alias('rm')
|
|
134
|
+
.description('Delete a document')
|
|
135
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
136
|
+
.action(async (id, options) => {
|
|
137
|
+
requireProject();
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
if (!options.yes) {
|
|
141
|
+
const answers = await inquirer.prompt([
|
|
142
|
+
{
|
|
143
|
+
type: 'confirm',
|
|
144
|
+
name: 'confirm',
|
|
145
|
+
message: `Are you sure you want to delete document ${id}?`,
|
|
146
|
+
default: false
|
|
147
|
+
}
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
if (!answers.confirm) {
|
|
151
|
+
console.log(chalk.yellow('Cancelled'));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const spinner = ora('Deleting document...').start();
|
|
157
|
+
await api.deleteDocument(id);
|
|
158
|
+
spinner.succeed(chalk.green('Document deleted successfully'));
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error(chalk.red('Failed to delete document:'), error.message);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const ora = require('ora');
|
|
4
|
+
const Table = require('cli-table3');
|
|
5
|
+
const api = require('../lib/api');
|
|
6
|
+
const config = require('../lib/config');
|
|
7
|
+
|
|
8
|
+
function requireProject() {
|
|
9
|
+
const projectKey = config.getCurrentProject();
|
|
10
|
+
if (!projectKey) {
|
|
11
|
+
console.error(chalk.red('No project selected'));
|
|
12
|
+
console.log(chalk.gray('Select a project with:'), chalk.cyan('gatellm project select'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
return projectKey;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = (program) => {
|
|
19
|
+
const intent = program.command('intent').description('Intent management commands');
|
|
20
|
+
|
|
21
|
+
// Add intent
|
|
22
|
+
intent
|
|
23
|
+
.command('add <name>')
|
|
24
|
+
.description('Add a new intent')
|
|
25
|
+
.option('-d, --description <description>', 'Intent description')
|
|
26
|
+
.option('-e, --examples <examples...>', 'Example queries (comma-separated or multiple -e flags)')
|
|
27
|
+
.action(async (name, options) => {
|
|
28
|
+
requireProject();
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
let { description, examples } = options;
|
|
32
|
+
|
|
33
|
+
// Prompt for description if not provided
|
|
34
|
+
if (!description) {
|
|
35
|
+
const answers = await inquirer.prompt([
|
|
36
|
+
{
|
|
37
|
+
type: 'input',
|
|
38
|
+
name: 'description',
|
|
39
|
+
message: 'Intent description:',
|
|
40
|
+
validate: (input) => input.length > 0 || 'Description is required'
|
|
41
|
+
}
|
|
42
|
+
]);
|
|
43
|
+
description = answers.description;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Parse examples
|
|
47
|
+
const examplesList = examples || [];
|
|
48
|
+
|
|
49
|
+
const spinner = ora('Creating intent...').start();
|
|
50
|
+
|
|
51
|
+
await api.createIntent(name, description, examplesList);
|
|
52
|
+
|
|
53
|
+
spinner.succeed(chalk.green('Intent created successfully!'));
|
|
54
|
+
console.log(chalk.gray('Name:'), name);
|
|
55
|
+
console.log(chalk.gray('Description:'), description);
|
|
56
|
+
if (examplesList.length > 0) {
|
|
57
|
+
console.log(chalk.gray('Examples:'), examplesList.length);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log('\n' + chalk.yellow('Next steps:'));
|
|
61
|
+
console.log(chalk.gray(' 1. Add routing rule:'), chalk.cyan(`gatellm route add --intent "${name}"`));
|
|
62
|
+
console.log(chalk.gray(' 2. Set system prompt:'), chalk.cyan(`gatellm prompt set --intent "${name}"`));
|
|
63
|
+
} catch (error) {
|
|
64
|
+
spinner.fail(chalk.red('Failed to create intent'));
|
|
65
|
+
console.error(chalk.red('Error:'), error.message);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// List intents
|
|
71
|
+
intent
|
|
72
|
+
.command('list')
|
|
73
|
+
.alias('ls')
|
|
74
|
+
.description('List all intents')
|
|
75
|
+
.action(async () => {
|
|
76
|
+
requireProject();
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const spinner = ora('Fetching intents...').start();
|
|
80
|
+
|
|
81
|
+
const intents = await api.listIntents();
|
|
82
|
+
|
|
83
|
+
spinner.stop();
|
|
84
|
+
|
|
85
|
+
if (intents.length === 0) {
|
|
86
|
+
console.log(chalk.yellow('No intents found'));
|
|
87
|
+
console.log(chalk.gray('Create one with:'), chalk.cyan('gatellm intent add <name>'));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const table = new Table({
|
|
92
|
+
head: [chalk.cyan('Name'), chalk.cyan('Description'), chalk.cyan('Examples'), chalk.cyan('Created')],
|
|
93
|
+
colWidths: [25, 40, 12, 20]
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
intents.forEach(intent => {
|
|
97
|
+
table.push([
|
|
98
|
+
chalk.green(intent.name),
|
|
99
|
+
intent.description || chalk.gray('(no description)'),
|
|
100
|
+
intent.example_count || 0,
|
|
101
|
+
new Date(intent.created_at).toLocaleDateString()
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
console.log(table.toString());
|
|
106
|
+
console.log(chalk.gray(`\nTotal: ${intents.length} intent(s)`));
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error(chalk.red('Failed to list intents:'), error.message);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Get intent details
|
|
114
|
+
intent
|
|
115
|
+
.command('get <name>')
|
|
116
|
+
.description('Get intent details')
|
|
117
|
+
.action(async (name) => {
|
|
118
|
+
requireProject();
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const spinner = ora('Fetching intent...').start();
|
|
122
|
+
const intent = await api.getIntent(name);
|
|
123
|
+
spinner.stop();
|
|
124
|
+
|
|
125
|
+
console.log(chalk.green('Intent Details:'));
|
|
126
|
+
console.log(chalk.gray(' Name:'), intent.name);
|
|
127
|
+
console.log(chalk.gray(' Description:'), intent.description);
|
|
128
|
+
console.log(chalk.gray(' Created:'), new Date(intent.created_at).toLocaleString());
|
|
129
|
+
|
|
130
|
+
if (intent.examples && intent.examples.length > 0) {
|
|
131
|
+
console.log(chalk.gray(' Examples:'));
|
|
132
|
+
intent.examples.forEach((ex, i) => {
|
|
133
|
+
console.log(chalk.gray(` ${i + 1}. ${ex}`));
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error(chalk.red('Failed to get intent:'), error.message);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Delete intent
|
|
143
|
+
intent
|
|
144
|
+
.command('delete <name>')
|
|
145
|
+
.alias('rm')
|
|
146
|
+
.description('Delete an intent')
|
|
147
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
148
|
+
.action(async (name, options) => {
|
|
149
|
+
requireProject();
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
if (!options.yes) {
|
|
153
|
+
const answers = await inquirer.prompt([
|
|
154
|
+
{
|
|
155
|
+
type: 'confirm',
|
|
156
|
+
name: 'confirm',
|
|
157
|
+
message: `Are you sure you want to delete intent "${name}"?`,
|
|
158
|
+
default: false
|
|
159
|
+
}
|
|
160
|
+
]);
|
|
161
|
+
|
|
162
|
+
if (!answers.confirm) {
|
|
163
|
+
console.log(chalk.yellow('Cancelled'));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const spinner = ora('Deleting intent...').start();
|
|
169
|
+
await api.deleteIntent(name);
|
|
170
|
+
spinner.succeed(chalk.green('Intent deleted successfully'));
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error(chalk.red('Failed to delete intent:'), error.message);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Batch add intents from JSON or TOON file
|
|
178
|
+
intent
|
|
179
|
+
.command('batch <file>')
|
|
180
|
+
.description('Batch create intents from JSON or TOON file')
|
|
181
|
+
.action(async (file) => {
|
|
182
|
+
requireProject();
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
const fs = require('fs');
|
|
186
|
+
const path = require('path');
|
|
187
|
+
|
|
188
|
+
const filePath = path.resolve(file);
|
|
189
|
+
|
|
190
|
+
if (!fs.existsSync(filePath)) {
|
|
191
|
+
console.error(chalk.red('File not found:'), filePath);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
196
|
+
let intents;
|
|
197
|
+
|
|
198
|
+
if (ext === '.toon') {
|
|
199
|
+
// Parse TOON format (39.6% more token-efficient!)
|
|
200
|
+
console.log(chalk.gray('Parsing TOON format file...'));
|
|
201
|
+
|
|
202
|
+
// Load TOON parser from agent-skill
|
|
203
|
+
const toonParserPath = path.join(__dirname, '../../agent-skill/lib/toon-parser.js');
|
|
204
|
+
|
|
205
|
+
if (fs.existsSync(toonParserPath)) {
|
|
206
|
+
const toonParser = require(toonParserPath);
|
|
207
|
+
const parsed = toonParser.parseFile(filePath);
|
|
208
|
+
intents = parsed.intents;
|
|
209
|
+
|
|
210
|
+
if (!intents || !Array.isArray(intents)) {
|
|
211
|
+
console.error(chalk.red('Invalid TOON format: No intents array found'));
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log(chalk.green(`✓ Parsed ${intents.length} intents from TOON file`));
|
|
216
|
+
} else {
|
|
217
|
+
console.error(chalk.red('TOON parser not found. Install agent-skill package.'));
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
// Parse JSON format
|
|
222
|
+
console.log(chalk.gray('Parsing JSON format file...'));
|
|
223
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
224
|
+
intents = JSON.parse(content);
|
|
225
|
+
|
|
226
|
+
if (!Array.isArray(intents)) {
|
|
227
|
+
console.error(chalk.red('Invalid format: Expected an array of intents'));
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const spinner = ora(`Creating ${intents.length} intents...`).start();
|
|
233
|
+
|
|
234
|
+
const response = await api.batchCreateIntents(intents);
|
|
235
|
+
|
|
236
|
+
spinner.succeed(chalk.green(`Created ${response.created} intents successfully!`));
|
|
237
|
+
|
|
238
|
+
if (response.failed > 0) {
|
|
239
|
+
console.log(chalk.yellow(`Failed: ${response.failed}`));
|
|
240
|
+
if (response.errors) {
|
|
241
|
+
response.errors.forEach(err => {
|
|
242
|
+
console.log(chalk.red(` - ${err}`));
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
console.error(chalk.red('Failed to batch create intents:'), error.message);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const ora = require('ora');
|
|
4
|
+
const Table = require('cli-table3');
|
|
5
|
+
const api = require('../lib/api');
|
|
6
|
+
const config = require('../lib/config');
|
|
7
|
+
|
|
8
|
+
module.exports = (program) => {
|
|
9
|
+
const project = program.command('project').description('Project management commands');
|
|
10
|
+
|
|
11
|
+
// Create project
|
|
12
|
+
project
|
|
13
|
+
.command('create <name>')
|
|
14
|
+
.description('Create a new project')
|
|
15
|
+
.option('-d, --description <description>', 'Project description')
|
|
16
|
+
.action(async (name, options) => {
|
|
17
|
+
try {
|
|
18
|
+
const spinner = ora('Creating project...').start();
|
|
19
|
+
|
|
20
|
+
const response = await api.createProject(name, options.description || '');
|
|
21
|
+
|
|
22
|
+
// Auto-select the new project
|
|
23
|
+
config.setCurrentProject(response.project_key);
|
|
24
|
+
|
|
25
|
+
spinner.succeed(chalk.green('Project created successfully!'));
|
|
26
|
+
console.log(chalk.gray('Name:'), name);
|
|
27
|
+
console.log(chalk.gray('Project Key:'), chalk.cyan(response.project_key));
|
|
28
|
+
console.log(chalk.gray('Status:'), chalk.green('Active (selected)'));
|
|
29
|
+
|
|
30
|
+
console.log('\n' + chalk.yellow('Next steps:'));
|
|
31
|
+
console.log(chalk.gray(' 1. Add intents:'), chalk.cyan('gatellm intent add "intent_name"'));
|
|
32
|
+
console.log(chalk.gray(' 2. Configure routes:'), chalk.cyan('gatellm route add'));
|
|
33
|
+
console.log(chalk.gray(' 3. Train model:'), chalk.cyan('gatellm train'));
|
|
34
|
+
} catch (error) {
|
|
35
|
+
spinner.fail(chalk.red('Failed to create project'));
|
|
36
|
+
console.error(chalk.red('Error:'), error.message);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// List projects
|
|
42
|
+
project
|
|
43
|
+
.command('list')
|
|
44
|
+
.alias('ls')
|
|
45
|
+
.description('List all projects')
|
|
46
|
+
.action(async () => {
|
|
47
|
+
try {
|
|
48
|
+
const spinner = ora('Fetching projects...').start();
|
|
49
|
+
|
|
50
|
+
const projects = await api.listProjects();
|
|
51
|
+
const currentProject = config.getCurrentProject();
|
|
52
|
+
|
|
53
|
+
spinner.stop();
|
|
54
|
+
|
|
55
|
+
if (projects.length === 0) {
|
|
56
|
+
console.log(chalk.yellow('No projects found'));
|
|
57
|
+
console.log(chalk.gray('Create one with:'), chalk.cyan('gatellm project create <name>'));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const table = new Table({
|
|
62
|
+
head: [chalk.cyan('Name'), chalk.cyan('Project Key'), chalk.cyan('Description'), chalk.cyan('Status')],
|
|
63
|
+
colWidths: [25, 40, 35, 10]
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
projects.forEach(proj => {
|
|
67
|
+
const isActive = proj.project_key === currentProject;
|
|
68
|
+
table.push([
|
|
69
|
+
isActive ? chalk.green(`${proj.name} *`) : proj.name,
|
|
70
|
+
proj.project_key,
|
|
71
|
+
proj.description || chalk.gray('(no description)'),
|
|
72
|
+
isActive ? chalk.green('Active') : chalk.gray('---')
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
console.log(table.toString());
|
|
77
|
+
console.log(chalk.gray('\n* = Currently selected project'));
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error(chalk.red('Failed to list projects:'), error.message);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Select project
|
|
85
|
+
project
|
|
86
|
+
.command('select [projectKey]')
|
|
87
|
+
.description('Select a project to work with')
|
|
88
|
+
.action(async (projectKey) => {
|
|
89
|
+
try {
|
|
90
|
+
if (!projectKey) {
|
|
91
|
+
// Show interactive selection
|
|
92
|
+
const projects = await api.listProjects();
|
|
93
|
+
|
|
94
|
+
if (projects.length === 0) {
|
|
95
|
+
console.log(chalk.yellow('No projects found'));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const answers = await inquirer.prompt([
|
|
100
|
+
{
|
|
101
|
+
type: 'list',
|
|
102
|
+
name: 'projectKey',
|
|
103
|
+
message: 'Select a project:',
|
|
104
|
+
choices: projects.map(p => ({
|
|
105
|
+
name: `${p.name} (${p.project_key})`,
|
|
106
|
+
value: p.project_key
|
|
107
|
+
}))
|
|
108
|
+
}
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
projectKey = answers.projectKey;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Verify project exists
|
|
115
|
+
const project = await api.getProject(projectKey);
|
|
116
|
+
|
|
117
|
+
config.setCurrentProject(projectKey);
|
|
118
|
+
|
|
119
|
+
console.log(chalk.green('Project selected:'), project.name);
|
|
120
|
+
console.log(chalk.gray('Project Key:'), chalk.cyan(projectKey));
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error(chalk.red('Failed to select project:'), error.message);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Show current project
|
|
128
|
+
project
|
|
129
|
+
.command('current')
|
|
130
|
+
.description('Show currently selected project')
|
|
131
|
+
.action(async () => {
|
|
132
|
+
const projectKey = config.getCurrentProject();
|
|
133
|
+
|
|
134
|
+
if (!projectKey) {
|
|
135
|
+
console.log(chalk.yellow('No project selected'));
|
|
136
|
+
console.log(chalk.gray('Select one with:'), chalk.cyan('gatellm project select'));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const spinner = ora('Fetching project details...').start();
|
|
142
|
+
const project = await api.getProject(projectKey);
|
|
143
|
+
spinner.stop();
|
|
144
|
+
|
|
145
|
+
console.log(chalk.green('Current Project:'));
|
|
146
|
+
console.log(chalk.gray(' Name:'), project.name);
|
|
147
|
+
console.log(chalk.gray(' Project Key:'), chalk.cyan(project.project_key));
|
|
148
|
+
console.log(chalk.gray(' Description:'), project.description || chalk.gray('(no description)'));
|
|
149
|
+
console.log(chalk.gray(' Created:'), new Date(project.created_at).toLocaleString());
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error(chalk.red('Failed to get project:'), error.message);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Delete project
|
|
157
|
+
project
|
|
158
|
+
.command('delete <projectKey>')
|
|
159
|
+
.description('Delete a project')
|
|
160
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
161
|
+
.action(async (projectKey, options) => {
|
|
162
|
+
try {
|
|
163
|
+
if (!options.yes) {
|
|
164
|
+
const answers = await inquirer.prompt([
|
|
165
|
+
{
|
|
166
|
+
type: 'confirm',
|
|
167
|
+
name: 'confirm',
|
|
168
|
+
message: `Are you sure you want to delete project ${projectKey}?`,
|
|
169
|
+
default: false
|
|
170
|
+
}
|
|
171
|
+
]);
|
|
172
|
+
|
|
173
|
+
if (!answers.confirm) {
|
|
174
|
+
console.log(chalk.yellow('Cancelled'));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const spinner = ora('Deleting project...').start();
|
|
180
|
+
await api.deleteProject(projectKey);
|
|
181
|
+
|
|
182
|
+
// Clear current project if it's the one being deleted
|
|
183
|
+
if (config.getCurrentProject() === projectKey) {
|
|
184
|
+
config.setCurrentProject(null);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
spinner.succeed(chalk.green('Project deleted successfully'));
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(chalk.red('Failed to delete project:'), error.message);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
};
|