@nestbox-ai/cli 1.0.6 → 1.0.8
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/.nestboxrc +0 -0
- package/dist/commands/agent.d.ts +2 -0
- package/dist/commands/agent.js +308 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/auth.js +23 -2
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/compute.js +350 -94
- package/dist/commands/compute.js.map +1 -1
- package/dist/commands/document.d.ts +2 -0
- package/dist/commands/document.js +340 -0
- package/dist/commands/document.js.map +1 -0
- package/dist/commands/image.d.ts +2 -0
- package/dist/commands/image.js +147 -0
- package/dist/commands/image.js.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/agent.d.ts +5 -0
- package/dist/utils/agent.js +192 -0
- package/dist/utils/agent.js.map +1 -0
- package/dist/utils/project.d.ts +15 -0
- package/dist/utils/project.js +76 -0
- package/dist/utils/project.js.map +1 -0
- package/dist/utils/user.d.ts +1 -0
- package/dist/utils/user.js +40 -0
- package/dist/utils/user.js.map +1 -0
- package/nestbox.config.json +9 -0
- package/package.json +12 -3
- package/src/commands/agent.ts +355 -0
- package/src/commands/auth.ts +261 -238
- package/src/commands/compute.ts +407 -115
- package/src/commands/document.ts +472 -0
- package/src/commands/image.ts +155 -0
- package/src/index.ts +6 -0
- package/src/utils/agent.ts +170 -0
- package/src/utils/project.ts +81 -0
- package/src/utils/user.ts +28 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { getAuthToken } from '../utils/auth';
|
|
5
|
+
import { Configuration, DocumentsApi, ProjectsApi } from '@nestbox-ai/admin';
|
|
6
|
+
import { readNestboxConfig } from './projects';
|
|
7
|
+
import { resolveProject } from '../utils/project';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Executes an async command with proper error handling and spinner feedback
|
|
12
|
+
*/
|
|
13
|
+
async function executeCommand<T>(
|
|
14
|
+
description: string,
|
|
15
|
+
command: () => Promise<T>,
|
|
16
|
+
successMessage: string
|
|
17
|
+
): Promise<T> {
|
|
18
|
+
const spinner = ora(description).start();
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const result = await command();
|
|
22
|
+
spinner.succeed(successMessage);
|
|
23
|
+
return result;
|
|
24
|
+
} catch (error: any) {
|
|
25
|
+
spinner.fail('Operation failed');
|
|
26
|
+
|
|
27
|
+
if (error.response?.data?.message) {
|
|
28
|
+
console.error(chalk.red('API Error:'), error.response.data.message);
|
|
29
|
+
} else {
|
|
30
|
+
console.error(chalk.red('Error:'), error.message || 'Unknown error');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function registerDocumentCommands(program: Command): void {
|
|
38
|
+
const authToken = getAuthToken();
|
|
39
|
+
|
|
40
|
+
if (!authToken) {
|
|
41
|
+
console.error(chalk.red('No authentication token found. Please login first.'));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const configuration = new Configuration({
|
|
46
|
+
basePath: authToken.serverUrl,
|
|
47
|
+
baseOptions: {
|
|
48
|
+
headers: {
|
|
49
|
+
Authorization: authToken.token,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const documentsApi = new DocumentsApi(configuration);
|
|
55
|
+
const projectsApi = new ProjectsApi(configuration);
|
|
56
|
+
|
|
57
|
+
const documentCommand = program.command('document').description('Manage Nestbox documents');
|
|
58
|
+
const docCommand = documentCommand.command('doc').description('Manage individual documents');
|
|
59
|
+
const collectionCommand = documentCommand.command('collection').description('Manage document collections');
|
|
60
|
+
|
|
61
|
+
// Add shared options to parent command that will be inherited by all subcommands
|
|
62
|
+
const addSharedOptions = (cmd: Command) =>
|
|
63
|
+
cmd
|
|
64
|
+
.requiredOption('--instance <instanceId>', 'Instance ID')
|
|
65
|
+
.option('--project <projectId>', 'Project ID or name (defaults to the current project)');
|
|
66
|
+
|
|
67
|
+
// LIST command
|
|
68
|
+
const listCmd = collectionCommand
|
|
69
|
+
.command('list')
|
|
70
|
+
.description('List document collections for a specific instance');
|
|
71
|
+
|
|
72
|
+
addSharedOptions(listCmd);
|
|
73
|
+
|
|
74
|
+
listCmd.action(async (options) => {
|
|
75
|
+
try {
|
|
76
|
+
const project = await resolveProject(projectsApi, options);
|
|
77
|
+
|
|
78
|
+
const collections = await executeCommand(
|
|
79
|
+
`Listing document collections for instance ${options.instance} in project ${project.name}...`,
|
|
80
|
+
async () => {
|
|
81
|
+
const response: any = await documentsApi.documentControllerGetAllCollections(project.id, options.instance);
|
|
82
|
+
return Array.isArray(response.data?.collections) ? response.data.collections : [];
|
|
83
|
+
},
|
|
84
|
+
'Successfully retrieved document collections'
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (collections.length === 0) {
|
|
88
|
+
console.log(chalk.yellow(`No document collections found for instance ${options.instance} in project ${project.name}`));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(chalk.blue(`\nDocument collections for instance ${options.instance} in project ${project.name}:\n`));
|
|
93
|
+
|
|
94
|
+
collections.forEach((collection: any) => {
|
|
95
|
+
const name = typeof collection === 'string' ? collection : collection?.name || 'Unnamed Collection';
|
|
96
|
+
console.log(chalk.white.bold(name));
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
// Error already handled by executeCommand
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// CREATE command
|
|
104
|
+
const createCmd = collectionCommand
|
|
105
|
+
.command('create')
|
|
106
|
+
.description('Create a new document collection for a specific instance')
|
|
107
|
+
.requiredOption('--name <name>', 'Name of the document collection')
|
|
108
|
+
.option('--metadata <json>', 'Metadata for the document collection in JSON format');
|
|
109
|
+
|
|
110
|
+
addSharedOptions(createCmd);
|
|
111
|
+
|
|
112
|
+
createCmd.action(async (options) => {
|
|
113
|
+
try {
|
|
114
|
+
const project = await resolveProject(projectsApi, options);
|
|
115
|
+
|
|
116
|
+
await executeCommand(
|
|
117
|
+
`Creating document collection "${options.name}" for instance ${options.instance} in project ${project.name}...`,
|
|
118
|
+
async () => {
|
|
119
|
+
const metadataObj = options.metadata ? JSON.parse(options.metadata) : {};
|
|
120
|
+
await documentsApi.documentControllerCreateCollection(project.id, options.instance, {
|
|
121
|
+
name: options.name,
|
|
122
|
+
metadata: metadataObj,
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
'Successfully created document collection'
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
console.log(chalk.green(`Document collection "${options.name}" created successfully.`));
|
|
129
|
+
} catch (error) {
|
|
130
|
+
// Error already handled by executeCommand
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// GET command
|
|
135
|
+
const getCmd = collectionCommand
|
|
136
|
+
.command('get')
|
|
137
|
+
.description('Get details of a specific document collection for a specific instance')
|
|
138
|
+
.requiredOption('--collection <collectionId>', 'ID of the document collection to get');
|
|
139
|
+
|
|
140
|
+
addSharedOptions(getCmd);
|
|
141
|
+
|
|
142
|
+
getCmd.action(async (options) => {
|
|
143
|
+
try {
|
|
144
|
+
const project = await resolveProject(projectsApi, options);
|
|
145
|
+
|
|
146
|
+
const collectionDetails = await executeCommand(
|
|
147
|
+
`Getting document collection "${options.collection}" for instance ${options.instance} in project ${project.name}...`,
|
|
148
|
+
async () => {
|
|
149
|
+
const response = await documentsApi.documentControllerGetCollectionInfo(
|
|
150
|
+
project.id,
|
|
151
|
+
options.instance,
|
|
152
|
+
options.collection
|
|
153
|
+
);
|
|
154
|
+
return response.data;
|
|
155
|
+
},
|
|
156
|
+
'Successfully retrieved document collection'
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
console.log(chalk.blue(`\nDocument collection details for instance ${options.instance} in project ${project.name}:\n`));
|
|
160
|
+
console.log(JSON.stringify(collectionDetails, null, 2));
|
|
161
|
+
} catch (error) {
|
|
162
|
+
// Error already handled by executeCommand
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// DELETE command
|
|
167
|
+
const deleteCmd = collectionCommand
|
|
168
|
+
.command('delete')
|
|
169
|
+
.description('Delete a document collection for a specific instance')
|
|
170
|
+
.requiredOption('--collection <collectionId>', 'ID of the document collection to delete');
|
|
171
|
+
|
|
172
|
+
addSharedOptions(deleteCmd);
|
|
173
|
+
|
|
174
|
+
deleteCmd.action(async (options) => {
|
|
175
|
+
try {
|
|
176
|
+
const project = await resolveProject(projectsApi, options);
|
|
177
|
+
|
|
178
|
+
await executeCommand(
|
|
179
|
+
`Deleting document collection "${options.collection}" for instance ${options.instance} in project ${project.name}...`,
|
|
180
|
+
async () => {
|
|
181
|
+
await documentsApi.documentControllerDeleteCollection(
|
|
182
|
+
project.id,
|
|
183
|
+
options.instance,
|
|
184
|
+
options.collection
|
|
185
|
+
);
|
|
186
|
+
},
|
|
187
|
+
'Successfully deleted document collection'
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
console.log(chalk.green(`Document collection "${options.collection}" deleted successfully.`));
|
|
191
|
+
} catch (error) {
|
|
192
|
+
// Error already handled by executeCommand
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// UPDATE command
|
|
197
|
+
const updateCmd = collectionCommand
|
|
198
|
+
.command('update')
|
|
199
|
+
.description('Update a document collection for a specific instance')
|
|
200
|
+
.requiredOption('--collection <collectionId>', 'ID of the document collection to update')
|
|
201
|
+
.option('--name <name>', 'New name of the document collection')
|
|
202
|
+
.option('--metadata <json>', 'New metadata for the document collection in JSON format');
|
|
203
|
+
|
|
204
|
+
addSharedOptions(updateCmd);
|
|
205
|
+
|
|
206
|
+
updateCmd.action(async (options) => {
|
|
207
|
+
try {
|
|
208
|
+
const project = await resolveProject(projectsApi, options);
|
|
209
|
+
|
|
210
|
+
await executeCommand(
|
|
211
|
+
`Updating document collection "${options.collection}" for instance ${options.instance} in project ${project.name}...`,
|
|
212
|
+
async () => {
|
|
213
|
+
const metadataObj = options.metadata ? JSON.parse(options.metadata) : {};
|
|
214
|
+
|
|
215
|
+
await documentsApi.documentControllerUpdateCollection(
|
|
216
|
+
project.id,
|
|
217
|
+
options.instance,
|
|
218
|
+
options.collection,
|
|
219
|
+
{
|
|
220
|
+
name: options.name,
|
|
221
|
+
metadata: metadataObj,
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
},
|
|
225
|
+
'Successfully updated document collection'
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
console.log(chalk.green(`Document collection "${options.collection}" updated successfully.`));
|
|
229
|
+
} catch (error) {
|
|
230
|
+
// Error already handled by executeCommand
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
const addDocCmd = docCommand
|
|
236
|
+
.command('add')
|
|
237
|
+
.description('Add a new document to a collection')
|
|
238
|
+
.requiredOption('--instance <instanceId>', 'Instance ID')
|
|
239
|
+
.requiredOption('--collection <collectionId>', 'Collection ID')
|
|
240
|
+
.requiredOption('--id <id>', 'Document ID')
|
|
241
|
+
.requiredOption('--document <json>', 'Document content in JSON format')
|
|
242
|
+
.option('--metadata <json>', 'Document metadata in JSON format (optional)')
|
|
243
|
+
.option('--project <projectId>', 'Project ID or name (defaults to the current project)');
|
|
244
|
+
|
|
245
|
+
addDocCmd.action(async (options) => {
|
|
246
|
+
try {
|
|
247
|
+
const project = await resolveProject(projectsApi, options);
|
|
248
|
+
|
|
249
|
+
await executeCommand(
|
|
250
|
+
`Adding document to collection "${options.collection}" in instance ${options.instance}...`,
|
|
251
|
+
async () => {
|
|
252
|
+
const documentContent = JSON.parse(options.document);
|
|
253
|
+
const metadata = options.metadata ? JSON.parse(options.metadata) : {};
|
|
254
|
+
|
|
255
|
+
await documentsApi.documentControllerAddDocToCollection(
|
|
256
|
+
project.id,
|
|
257
|
+
options.instance,
|
|
258
|
+
options.collection,
|
|
259
|
+
{
|
|
260
|
+
id: options.id,
|
|
261
|
+
document: JSON.stringify(documentContent),
|
|
262
|
+
metadata: metadata
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
},
|
|
266
|
+
'Successfully added document to collection'
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
console.log(chalk.green(`Document with ID "${options.id}" added successfully to collection "${options.collection}".`));
|
|
270
|
+
} catch (error) {
|
|
271
|
+
// Error already handled by executeCommand
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const getDocCmd = docCommand
|
|
276
|
+
.command('get')
|
|
277
|
+
.description('Get a document from a collection')
|
|
278
|
+
.requiredOption('--instance <instanceId>', 'Instance ID')
|
|
279
|
+
.requiredOption('--collection <collectionId>', 'Collection ID')
|
|
280
|
+
.requiredOption('--doc <docId>', 'Document ID')
|
|
281
|
+
.option('--project <projectId>', 'Project ID or name (defaults to the current project)');
|
|
282
|
+
getDocCmd.action(async (options) => {
|
|
283
|
+
try {
|
|
284
|
+
const project = await resolveProject(projectsApi, options);
|
|
285
|
+
|
|
286
|
+
const document = await executeCommand(
|
|
287
|
+
`Getting document "${options.doc}" from collection "${options.collection}" in instance ${options.instance}...`,
|
|
288
|
+
async () => {
|
|
289
|
+
const response = await documentsApi.documentControllerGetDocById(
|
|
290
|
+
project.id,
|
|
291
|
+
options.instance,
|
|
292
|
+
options.collection,
|
|
293
|
+
options.doc
|
|
294
|
+
);
|
|
295
|
+
return response.data;
|
|
296
|
+
},
|
|
297
|
+
'Successfully retrieved document'
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
console.log(chalk.blue(`\nDocument details for ID "${options.doc}" in collection "${options.collection}":\n`));
|
|
301
|
+
console.log(JSON.stringify(document, null, 2));
|
|
302
|
+
} catch (error) {
|
|
303
|
+
// Error already handled by executeCommand
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const deleteDocCmd = docCommand
|
|
308
|
+
.command('delete')
|
|
309
|
+
.description('Delete a document from a collection')
|
|
310
|
+
.requiredOption('--instance <instanceId>', 'Instance ID')
|
|
311
|
+
.requiredOption('--collection <collectionId>', 'Collection ID')
|
|
312
|
+
.requiredOption('--doc <docId>', 'Document ID')
|
|
313
|
+
.option('--project <projectId>', 'Project ID or name (defaults to the current project)');
|
|
314
|
+
deleteDocCmd.action(async (options) => {
|
|
315
|
+
try {
|
|
316
|
+
const project = await resolveProject(projectsApi, options);
|
|
317
|
+
|
|
318
|
+
await executeCommand(
|
|
319
|
+
`Deleting document "${options.doc}" from collection "${options.collection}" in instance ${options.instance}...`,
|
|
320
|
+
async () => {
|
|
321
|
+
await documentsApi.documentControllerDeleteDocById(
|
|
322
|
+
project.id,
|
|
323
|
+
options.instance,
|
|
324
|
+
options.collection,
|
|
325
|
+
options.doc
|
|
326
|
+
);
|
|
327
|
+
},
|
|
328
|
+
'Successfully deleted document'
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
console.log(chalk.green(`Document with ID "${options.doc}" deleted successfully from collection "${options.collection}".`));
|
|
332
|
+
} catch (error) {
|
|
333
|
+
// Error already handled by executeCommand
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
const updateDocCmd = docCommand
|
|
338
|
+
.command('update')
|
|
339
|
+
.description('Update a document in a collection')
|
|
340
|
+
.requiredOption('--instance <instanceId>', 'Instance ID')
|
|
341
|
+
.requiredOption('--collection <collectionId>', 'Collection ID')
|
|
342
|
+
.requiredOption('--doc <docId>', 'Document ID')
|
|
343
|
+
.requiredOption('--document <string>', 'Updated document content as a string')
|
|
344
|
+
.option('--metadata <json>', 'Updated document metadata in JSON format (optional)')
|
|
345
|
+
.option('--project <projectId>', 'Project ID or name (defaults to the current project)');
|
|
346
|
+
|
|
347
|
+
updateDocCmd.action(async (options) => {
|
|
348
|
+
try {
|
|
349
|
+
const project = await resolveProject(projectsApi, options);
|
|
350
|
+
|
|
351
|
+
await executeCommand(
|
|
352
|
+
`Updating document "${options.doc}" in collection "${options.collection}" in instance ${options.instance}...`,
|
|
353
|
+
async () => {
|
|
354
|
+
const documentContent = options.document;
|
|
355
|
+
const metadata = options.metadata ? JSON.parse(options.metadata) : {};
|
|
356
|
+
|
|
357
|
+
await documentsApi.documentControllerUpdateDoc(
|
|
358
|
+
project.id,
|
|
359
|
+
options.instance,
|
|
360
|
+
options.collection,
|
|
361
|
+
options.doc,
|
|
362
|
+
{
|
|
363
|
+
document: documentContent,
|
|
364
|
+
metadata: metadata
|
|
365
|
+
}
|
|
366
|
+
);
|
|
367
|
+
},
|
|
368
|
+
'Successfully updated document'
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
console.log(chalk.green(`Document with ID "${options.doc}" updated successfully in collection "${options.collection}".`));
|
|
372
|
+
} catch (error) {
|
|
373
|
+
// Error already handled by executeCommand
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
const uploadFileCmd = docCommand
|
|
378
|
+
.command('upload-file')
|
|
379
|
+
.description('Add documents by file chunking')
|
|
380
|
+
.requiredOption('--instance <instanceId>', 'Instance ID')
|
|
381
|
+
.requiredOption('--collection <collectionId>', 'Collection ID')
|
|
382
|
+
.requiredOption('--file <path>', 'Path to the file to upload')
|
|
383
|
+
.option('--type <fileType>', 'Type of the file (e.g., pdf, txt, doc)')
|
|
384
|
+
.option('--options <json>', 'Additional options for file processing in JSON format')
|
|
385
|
+
.option('--project <projectId>', 'Project ID or name (defaults to the current project)');
|
|
386
|
+
|
|
387
|
+
uploadFileCmd.action(async (options) => {
|
|
388
|
+
try {
|
|
389
|
+
const project = await resolveProject(projectsApi, options);
|
|
390
|
+
|
|
391
|
+
await executeCommand(
|
|
392
|
+
`Processing file "${options.file}" for collection "${options.collection}" in instance ${options.instance}...`,
|
|
393
|
+
async () => {
|
|
394
|
+
|
|
395
|
+
const requestData = {
|
|
396
|
+
type: options.type,
|
|
397
|
+
url: options.file,
|
|
398
|
+
options: options.options ? JSON.parse(options.options) : {},
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
await documentsApi.documentControllerAddDocToCollectionFromFile(
|
|
402
|
+
project.id,
|
|
403
|
+
options.instance,
|
|
404
|
+
options.collection,
|
|
405
|
+
requestData
|
|
406
|
+
);
|
|
407
|
+
},
|
|
408
|
+
'Successfully processed file for document chunking'
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
console.log(chalk.green(`File "${options.file}" processed successfully for collection "${options.collection}".`));
|
|
412
|
+
} catch (error) {
|
|
413
|
+
// Error already handled by executeCommand
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
const searchCmd = docCommand
|
|
418
|
+
.command('search')
|
|
419
|
+
.description('Search for documents in a collection')
|
|
420
|
+
.requiredOption('--instance <instanceId>', 'Instance ID')
|
|
421
|
+
.requiredOption('--collection <collectionId>', 'Collection ID')
|
|
422
|
+
.requiredOption('--query <query>', 'Search query')
|
|
423
|
+
.option('--project <projectId>', 'Project ID or name (defaults to the current project)')
|
|
424
|
+
.option('--filter <json>', 'Filter criteria as JSON string');
|
|
425
|
+
|
|
426
|
+
searchCmd.action(async (options) => {
|
|
427
|
+
try {
|
|
428
|
+
const project = await resolveProject(projectsApi, options);
|
|
429
|
+
|
|
430
|
+
// Build the request body
|
|
431
|
+
const requestBody = {
|
|
432
|
+
query: options.query,
|
|
433
|
+
params: {},
|
|
434
|
+
filter: {},
|
|
435
|
+
include: ["embedding"]
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
// Parse filter JSON if provided
|
|
440
|
+
if (options.filter) {
|
|
441
|
+
try {
|
|
442
|
+
requestBody.filter = JSON.parse(options.filter);
|
|
443
|
+
} catch (e: any) {
|
|
444
|
+
console.error(chalk.red('Error parsing filter JSON:'), e.message);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
console.log("REQUEST BODY", requestBody);
|
|
450
|
+
|
|
451
|
+
const results = await executeCommand(
|
|
452
|
+
`Searching for documents in collection "${options.collection}" in instance ${options.instance}...`,
|
|
453
|
+
async () => {
|
|
454
|
+
const response = await documentsApi.documentControllerSimilaritySearch(
|
|
455
|
+
project.id,
|
|
456
|
+
options.instance,
|
|
457
|
+
options.collection,
|
|
458
|
+
requestBody
|
|
459
|
+
);
|
|
460
|
+
return response.data;
|
|
461
|
+
},
|
|
462
|
+
'Successfully retrieved search results'
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
console.log(chalk.blue(`\nSearch results for query "${options.query}" in collection "${options.collection}":\n`));
|
|
466
|
+
console.log(JSON.stringify(results, null, 2));
|
|
467
|
+
} catch (error) {
|
|
468
|
+
// Error already handled by executeCommand
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import Table from 'cli-table3';
|
|
5
|
+
import { getAuthToken } from '../utils/auth';
|
|
6
|
+
import { Configuration, MiscellaneousApi, ProjectsApi } from '@nestbox-ai/admin';
|
|
7
|
+
import { resolveProject } from '../utils/project';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Executes an async command with proper error handling and spinner feedback
|
|
11
|
+
*/
|
|
12
|
+
async function executeCommand<T>(
|
|
13
|
+
description: string,
|
|
14
|
+
command: () => Promise<T>,
|
|
15
|
+
successMessage: string
|
|
16
|
+
): Promise<T> {
|
|
17
|
+
const spinner = ora(description).start();
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const result = await command();
|
|
21
|
+
spinner.succeed(successMessage);
|
|
22
|
+
return result;
|
|
23
|
+
} catch (error: any) {
|
|
24
|
+
spinner.fail('Operation failed');
|
|
25
|
+
|
|
26
|
+
if (error.response?.data?.message) {
|
|
27
|
+
console.error(chalk.red('API Error:'), error.response.data.message);
|
|
28
|
+
} else {
|
|
29
|
+
console.error(chalk.red('Error:'), error.message || 'Unknown error');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function registerImageCommands(program: Command): void {
|
|
37
|
+
const authToken = getAuthToken();
|
|
38
|
+
|
|
39
|
+
if (!authToken) {
|
|
40
|
+
console.error(chalk.red('No authentication token found. Please login first.'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const configuration = new Configuration({
|
|
45
|
+
basePath: authToken.serverUrl,
|
|
46
|
+
baseOptions: {
|
|
47
|
+
headers: {
|
|
48
|
+
Authorization: authToken.token,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const miscellaneousApi = new MiscellaneousApi(configuration);
|
|
54
|
+
const projectsApi = new ProjectsApi(configuration);
|
|
55
|
+
|
|
56
|
+
const imageCommand = program.command('image').description('Manage Nestbox images');
|
|
57
|
+
|
|
58
|
+
// LIST command
|
|
59
|
+
const listCmd = imageCommand
|
|
60
|
+
.command('list')
|
|
61
|
+
.description('List images for a project')
|
|
62
|
+
.option('--project <projectId>', 'Project ID or name (defaults to the current project)');
|
|
63
|
+
|
|
64
|
+
listCmd.action(async (options) => {
|
|
65
|
+
try {
|
|
66
|
+
const project = await resolveProject(projectsApi, options);
|
|
67
|
+
|
|
68
|
+
const images: any = await executeCommand(
|
|
69
|
+
`Listing images for project ${project.name}...`,
|
|
70
|
+
async () => {
|
|
71
|
+
const response = await miscellaneousApi.miscellaneousControllerGetMachineInstanceByImageId(project.id);
|
|
72
|
+
return response.data;
|
|
73
|
+
},
|
|
74
|
+
'Successfully retrieved images'
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (!images || images.length === 0) {
|
|
78
|
+
console.log(chalk.yellow('No images found for this project.'));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Create a table for displaying the image data
|
|
83
|
+
const table = new Table({
|
|
84
|
+
head: [
|
|
85
|
+
chalk.white.bold('ID'),
|
|
86
|
+
chalk.white.bold('Name'),
|
|
87
|
+
chalk.white.bold('Machine Type'),
|
|
88
|
+
chalk.white.bold('Status'),
|
|
89
|
+
chalk.white.bold('Region'),
|
|
90
|
+
chalk.white.bold('API Key'),
|
|
91
|
+
chalk.white.bold('Internal IP')
|
|
92
|
+
],
|
|
93
|
+
style: {
|
|
94
|
+
head: [], // Disable the default styling
|
|
95
|
+
border: []
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Status mappings
|
|
100
|
+
const statusMappings: Record<string, string> = {
|
|
101
|
+
'Job Scheduled': 'Scheduled',
|
|
102
|
+
'Job Executed': 'Ready',
|
|
103
|
+
'Job in Progress': 'Initializing',
|
|
104
|
+
'Job Failed': 'Failed',
|
|
105
|
+
'Deleting': 'Deleting',
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Add rows to the table
|
|
109
|
+
images.forEach((image: any) => {
|
|
110
|
+
// Map the status if a mapping exists
|
|
111
|
+
const originalStatus = image.runningStatus || 'unknown';
|
|
112
|
+
const displayStatus = statusMappings[originalStatus] || originalStatus;
|
|
113
|
+
|
|
114
|
+
// Color the status based on its mapped value
|
|
115
|
+
let statusColor;
|
|
116
|
+
|
|
117
|
+
switch(displayStatus.toLowerCase()) {
|
|
118
|
+
case 'ready':
|
|
119
|
+
statusColor = chalk.green(displayStatus);
|
|
120
|
+
break;
|
|
121
|
+
case 'failed':
|
|
122
|
+
statusColor = chalk.red(displayStatus);
|
|
123
|
+
break;
|
|
124
|
+
case 'initializing':
|
|
125
|
+
statusColor = chalk.yellow(displayStatus);
|
|
126
|
+
break;
|
|
127
|
+
case 'scheduled':
|
|
128
|
+
statusColor = chalk.blue(displayStatus);
|
|
129
|
+
break;
|
|
130
|
+
case 'deleting':
|
|
131
|
+
statusColor = chalk.red(displayStatus);
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
statusColor = chalk.gray(displayStatus);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
table.push([
|
|
138
|
+
image.id || 'N/A',
|
|
139
|
+
image.instanceName || 'N/A',
|
|
140
|
+
image.machineTitle || 'N/A',
|
|
141
|
+
statusColor,
|
|
142
|
+
image.region || 'N/A',
|
|
143
|
+
image.instanceApiKey || 'N/A',
|
|
144
|
+
image.internalIP || 'N/A'
|
|
145
|
+
]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Display the table
|
|
149
|
+
console.log(table.toString());
|
|
150
|
+
|
|
151
|
+
} catch (error) {
|
|
152
|
+
// Error already handled by executeCommand
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,9 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { registerAuthCommands } from './commands/auth';
|
|
4
4
|
import { registerProjectCommands } from './commands/projects';
|
|
5
5
|
import { registerComputeProgram } from './commands/compute';
|
|
6
|
+
import { registerAgentCommands } from './commands/agent';
|
|
7
|
+
import { registerDocumentCommands } from './commands/document';
|
|
8
|
+
import { registerImageCommands } from './commands/image';
|
|
6
9
|
|
|
7
10
|
// Setup the CLI program
|
|
8
11
|
const program = new Command();
|
|
@@ -15,6 +18,9 @@ program
|
|
|
15
18
|
registerAuthCommands(program);
|
|
16
19
|
registerProjectCommands(program);
|
|
17
20
|
registerComputeProgram(program);
|
|
21
|
+
registerAgentCommands(program);
|
|
22
|
+
registerDocumentCommands(program);
|
|
23
|
+
registerImageCommands(program);
|
|
18
24
|
|
|
19
25
|
// Parse command line arguments
|
|
20
26
|
program.parse(process.argv);
|