@nestbox-ai/cli 1.0.2 → 1.0.3
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/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +254 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/compute.d.ts +2 -0
- package/dist/commands/compute.js +132 -0
- package/dist/commands/compute.js.map +1 -0
- package/dist/commands/projects.d.ts +13 -0
- package/dist/commands/projects.js +126 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -0
- package/dist/types/auth.d.ts +12 -0
- package/dist/types/auth.js +3 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/utils/auth.d.ts +27 -0
- package/dist/utils/auth.js +159 -0
- package/dist/utils/auth.js.map +1 -0
- package/package.json +30 -5
- package/src/commands/auth.ts +267 -0
- package/src/commands/compute.ts +147 -0
- package/src/commands/projects.ts +139 -0
- package/src/index.ts +24 -1
- package/src/types/auth.ts +12 -0
- package/src/utils/auth.ts +177 -0
- package/tsconfig.json +4 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { getAuthToken } from '../utils/auth';
|
|
6
|
+
import { Configuration, ProjectsApi } from '@nestbox-ai/admin';
|
|
7
|
+
|
|
8
|
+
// Define a type for the projects configuration
|
|
9
|
+
interface ProjectsConfig {
|
|
10
|
+
default?: string;
|
|
11
|
+
[key: string]: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface NestboxConfig {
|
|
15
|
+
projects: ProjectsConfig;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Utility functions for project configuration
|
|
19
|
+
export function getNestboxConfigPath(): string {
|
|
20
|
+
return path.join(process.cwd(), '.nestboxrc');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function readNestboxConfig(): NestboxConfig {
|
|
24
|
+
const configPath = getNestboxConfigPath();
|
|
25
|
+
if (fs.existsSync(configPath)) {
|
|
26
|
+
try {
|
|
27
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
28
|
+
return JSON.parse(content);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return { projects: {} };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { projects: {} };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function writeNestboxConfig(config: NestboxConfig): void {
|
|
37
|
+
const configPath = getNestboxConfigPath();
|
|
38
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function registerProjectCommands(program: Command): void {
|
|
42
|
+
|
|
43
|
+
const authToken = getAuthToken();
|
|
44
|
+
const configuration = new Configuration({
|
|
45
|
+
basePath: authToken?.serverUrl,
|
|
46
|
+
baseOptions:{
|
|
47
|
+
headers: {
|
|
48
|
+
"Authorization": authToken?.token,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const projectsApi = new ProjectsApi(configuration);
|
|
54
|
+
|
|
55
|
+
// Create the main project command
|
|
56
|
+
const projectCommand = program
|
|
57
|
+
.command('project')
|
|
58
|
+
.description('Manage Nestbox projects');
|
|
59
|
+
|
|
60
|
+
// Add the basic 'use' subcommand
|
|
61
|
+
projectCommand
|
|
62
|
+
.command('use <project-name>')
|
|
63
|
+
.description('Set default project for all commands')
|
|
64
|
+
.action((projectName: string) => {
|
|
65
|
+
try {
|
|
66
|
+
if (!authToken) {
|
|
67
|
+
console.error(chalk.red('No authentication token found. Please log in first.'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const config = readNestboxConfig();
|
|
71
|
+
|
|
72
|
+
// Set the default project
|
|
73
|
+
config.projects = config.projects || {};
|
|
74
|
+
config.projects.default = projectName;
|
|
75
|
+
|
|
76
|
+
projectsApi.projectControllerGetAllProjects()
|
|
77
|
+
.then((response) => {
|
|
78
|
+
// Check if the project exists
|
|
79
|
+
const projectExists = response.data.data.projects.some((project: any) => project.name === projectName);
|
|
80
|
+
if (!projectExists) {
|
|
81
|
+
throw new Error(`Project '${projectName}' does not exist.`);
|
|
82
|
+
}
|
|
83
|
+
// Write the configuration
|
|
84
|
+
writeNestboxConfig(config);
|
|
85
|
+
console.log(chalk.green(`Default project set to '${projectName}'`));
|
|
86
|
+
})
|
|
87
|
+
.catch((error) => {
|
|
88
|
+
console.error(error.message);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error(chalk.red('Error setting default project:'), error instanceof Error ? error.message : 'Unknown error');
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Add basic 'add' subcommand
|
|
97
|
+
projectCommand
|
|
98
|
+
.command('add <project-name> [alias]')
|
|
99
|
+
.description('Add a project with optional alias')
|
|
100
|
+
.action((projectName: string, alias?: string) => {
|
|
101
|
+
try {
|
|
102
|
+
if (!authToken) {
|
|
103
|
+
console.error(chalk.red('No authentication token found. Please log in first.'));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const config = readNestboxConfig();
|
|
107
|
+
config.projects = config.projects || {};
|
|
108
|
+
|
|
109
|
+
// Check if the project already exists
|
|
110
|
+
if (config.projects[projectName]) {
|
|
111
|
+
console.error(chalk.red(`Project '${projectName}' already exists.`));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Check if the alias already exists
|
|
115
|
+
if (alias && config.projects[alias]) {
|
|
116
|
+
console.error(chalk.red(`Alias '${alias}' already exists.`));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (alias) {
|
|
121
|
+
config.projects[alias] = projectName;
|
|
122
|
+
console.log(chalk.green(`Added project '${projectName}' with alias '${alias}'`));
|
|
123
|
+
} else {
|
|
124
|
+
config.projects[projectName] = projectName;
|
|
125
|
+
console.log(chalk.green(`Added project '${projectName}'`));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// If this is the first project, set it as default
|
|
129
|
+
if (!config.projects.default) {
|
|
130
|
+
config.projects.default = projectName;
|
|
131
|
+
console.log(chalk.green(`Set '${projectName}' as the default project`));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
writeNestboxConfig(config);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error(chalk.red('Error adding project:'), error instanceof Error ? error.message : 'Unknown error');
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { registerAuthCommands } from './commands/auth';
|
|
4
|
+
import { registerProjectCommands } from './commands/projects';
|
|
5
|
+
import { registerComputeProgram } from './commands/compute';
|
|
6
|
+
|
|
7
|
+
// Setup the CLI program
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program
|
|
10
|
+
.name('nestbox')
|
|
11
|
+
.description('CLI tool for the Nestbox AI platform')
|
|
12
|
+
.version('1.0.0');
|
|
13
|
+
|
|
14
|
+
// Register command groups
|
|
15
|
+
registerAuthCommands(program);
|
|
16
|
+
registerProjectCommands(program);
|
|
17
|
+
registerComputeProgram(program);
|
|
18
|
+
|
|
19
|
+
// Parse command line arguments
|
|
20
|
+
program.parse(process.argv);
|
|
21
|
+
// Only show help if no arguments were provided
|
|
22
|
+
if (process.argv.length === 2) {
|
|
23
|
+
program.help();
|
|
24
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { UserCredentials } from '../types/auth';
|
|
6
|
+
|
|
7
|
+
// Config path
|
|
8
|
+
const CONFIG_DIR = path.join(os.homedir(), '.config', '.nestbox');
|
|
9
|
+
|
|
10
|
+
// Ensure config directory exists
|
|
11
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
12
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get authentication token for a specific domain
|
|
17
|
+
*/
|
|
18
|
+
export function getAuthToken(domain?: string): {token: string, serverUrl: string, accessToken?: string} | null {
|
|
19
|
+
try {
|
|
20
|
+
const files = fs.readdirSync(CONFIG_DIR);
|
|
21
|
+
|
|
22
|
+
if (!domain) {
|
|
23
|
+
// If no domain is provided, return the first token found
|
|
24
|
+
const tokenFiles = files.filter(file => file.endsWith('.json'));
|
|
25
|
+
if (tokenFiles.length === 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const configData = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, tokenFiles[0])).toString());
|
|
30
|
+
return {
|
|
31
|
+
token: configData.token,
|
|
32
|
+
serverUrl: configData.apiServerUrl,
|
|
33
|
+
accessToken: configData.accessToken,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const domainFiles = files.filter(file => file.endsWith(`_${domain}.json`));
|
|
37
|
+
|
|
38
|
+
if (domainFiles.length === 0) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If multiple accounts, sort by last used and take the most recent
|
|
43
|
+
let configData: UserCredentials;
|
|
44
|
+
|
|
45
|
+
if (domainFiles.length > 1) {
|
|
46
|
+
const allConfigs = domainFiles.map(file => {
|
|
47
|
+
const data = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, file)).toString()) as UserCredentials;
|
|
48
|
+
return {
|
|
49
|
+
file,
|
|
50
|
+
data,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Sort by last used, most recent first
|
|
55
|
+
configData = allConfigs[0].data;
|
|
56
|
+
} else {
|
|
57
|
+
// Just one file
|
|
58
|
+
const configFile = domainFiles[0];
|
|
59
|
+
configData = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, configFile)).toString());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
token: configData.token,
|
|
64
|
+
serverUrl: configData.apiServerUrl,
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('Error getting auth token:', error);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get user credentials for a specific domain and email
|
|
74
|
+
*/
|
|
75
|
+
export function getUserCredentials(domain: string, email?: string): UserCredentials | null {
|
|
76
|
+
try {
|
|
77
|
+
const files = fs.readdirSync(CONFIG_DIR);
|
|
78
|
+
let targetFiles: string[];
|
|
79
|
+
|
|
80
|
+
if (email) {
|
|
81
|
+
// Get specific email for domain
|
|
82
|
+
targetFiles = files.filter(file => file === `${email}_${domain}.json`);
|
|
83
|
+
} else {
|
|
84
|
+
// Get all for domain, sort by last used
|
|
85
|
+
targetFiles = files.filter(file => file.endsWith(`_${domain}.json`));
|
|
86
|
+
|
|
87
|
+
if (targetFiles.length > 1) {
|
|
88
|
+
const allConfigs = targetFiles.map(file => {
|
|
89
|
+
const data = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, file)).toString()) as UserCredentials;
|
|
90
|
+
return {
|
|
91
|
+
file,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Sort by last used, most recent first
|
|
96
|
+
targetFiles = [allConfigs[0].file];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (targetFiles.length === 0) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, targetFiles[0])).toString());
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('Error getting user credentials:', error);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* List all saved credentials
|
|
113
|
+
*/
|
|
114
|
+
export function listCredentials(): Array<{
|
|
115
|
+
domain: string;
|
|
116
|
+
email: string;
|
|
117
|
+
name?: string;
|
|
118
|
+
authMethod?: string;
|
|
119
|
+
lastUsed?: number;
|
|
120
|
+
}> {
|
|
121
|
+
try {
|
|
122
|
+
const files = fs.readdirSync(CONFIG_DIR);
|
|
123
|
+
return files.map(file => {
|
|
124
|
+
try {
|
|
125
|
+
const data = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, file)).toString()) as UserCredentials;
|
|
126
|
+
return {
|
|
127
|
+
domain: data.domain,
|
|
128
|
+
email: data.email,
|
|
129
|
+
name: data.name,
|
|
130
|
+
};
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// Skip invalid files
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}).filter(Boolean) as Array<{
|
|
136
|
+
domain: string;
|
|
137
|
+
email: string;
|
|
138
|
+
name?: string;
|
|
139
|
+
authMethod?: string;
|
|
140
|
+
lastUsed?: number;
|
|
141
|
+
}>;
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('Error listing credentials:', error);
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Remove credentials for a domain/email combination
|
|
150
|
+
*/
|
|
151
|
+
export function removeCredentials(domain: string, email?: string): boolean {
|
|
152
|
+
try {
|
|
153
|
+
const files = fs.readdirSync(CONFIG_DIR);
|
|
154
|
+
let domainFiles: string[];
|
|
155
|
+
|
|
156
|
+
if (email) {
|
|
157
|
+
// Remove specific email for domain
|
|
158
|
+
domainFiles = files.filter(file => file === `${email}_${domain}.json`);
|
|
159
|
+
} else {
|
|
160
|
+
// Remove all for domain
|
|
161
|
+
domainFiles = files.filter(file => file.endsWith(`_${domain}.json`));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (domainFiles.length === 0) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
domainFiles.forEach(file => {
|
|
169
|
+
fs.unlinkSync(path.join(CONFIG_DIR, file));
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return true;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error('Error removing credentials:', error);
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -108,6 +108,9 @@
|
|
|
108
108
|
|
|
109
109
|
/* Completeness */
|
|
110
110
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
|
111
|
-
"skipLibCheck": true
|
|
111
|
+
"skipLibCheck": true , /* Skip type checking all .d.ts files. */
|
|
112
|
+
"declaration": true,
|
|
113
|
+
"sourceMap": true,
|
|
114
|
+
"resolveJsonModule": true
|
|
112
115
|
}
|
|
113
116
|
}
|