@startanaicompany/cli 1.0.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/PUBLISHING.md +108 -0
- package/README.md +325 -0
- package/bin/saac.js +167 -0
- package/package.json +51 -0
- package/src/commands/create.js +4 -0
- package/src/commands/delete.js +4 -0
- package/src/commands/deploy.js +60 -0
- package/src/commands/domain.js +4 -0
- package/src/commands/env.js +4 -0
- package/src/commands/init.js +4 -0
- package/src/commands/list.js +4 -0
- package/src/commands/login.js +85 -0
- package/src/commands/logout.js +9 -0
- package/src/commands/logs.js +4 -0
- package/src/commands/register.js +96 -0
- package/src/commands/status.js +4 -0
- package/src/commands/verify.js +54 -0
- package/src/commands/whoami.js +4 -0
- package/src/lib/api.js +156 -0
- package/src/lib/config.js +107 -0
- package/src/lib/logger.js +103 -0
package/PUBLISHING.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Publishing Guide for @startanaicompany/cli
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
1. **npm account** created
|
|
6
|
+
2. **Organization @startanaicompany** created on npm
|
|
7
|
+
3. Logged in to npm: `npm login`
|
|
8
|
+
|
|
9
|
+
## Publishing Steps
|
|
10
|
+
|
|
11
|
+
### 1. First Time Setup
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cd ~/projects/saac-cli
|
|
15
|
+
|
|
16
|
+
# Login to npm
|
|
17
|
+
npm login
|
|
18
|
+
|
|
19
|
+
# Test the package locally first
|
|
20
|
+
npm link
|
|
21
|
+
|
|
22
|
+
# Test the CLI
|
|
23
|
+
saac --help
|
|
24
|
+
saac register --help
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Publish to npm
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Make sure everything is committed
|
|
31
|
+
git status
|
|
32
|
+
|
|
33
|
+
# Publish as public package
|
|
34
|
+
npm publish --access public
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 3. Verify Publication
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Check on npm
|
|
41
|
+
open https://www.npmjs.com/package/@startanaicompany/cli
|
|
42
|
+
|
|
43
|
+
# Test global installation
|
|
44
|
+
npm install -g @startanaicompany/cli
|
|
45
|
+
|
|
46
|
+
# Test it works
|
|
47
|
+
saac --help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Updating the Package
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Update version in package.json
|
|
54
|
+
npm version patch # or minor, or major
|
|
55
|
+
|
|
56
|
+
# Publish update
|
|
57
|
+
npm publish
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Version Numbers
|
|
61
|
+
|
|
62
|
+
- **patch** (1.0.0 → 1.0.1): Bug fixes
|
|
63
|
+
- **minor** (1.0.0 → 1.1.0): New features (backwards compatible)
|
|
64
|
+
- **major** (1.0.0 → 2.0.0): Breaking changes
|
|
65
|
+
|
|
66
|
+
## Current Status
|
|
67
|
+
|
|
68
|
+
- ✅ Package structure created
|
|
69
|
+
- ✅ Core commands implemented (register, login, verify, deploy)
|
|
70
|
+
- ✅ Beautiful CLI with colors and spinners
|
|
71
|
+
- ✅ Configuration management
|
|
72
|
+
- ✅ API client
|
|
73
|
+
- ✅ Comprehensive README
|
|
74
|
+
- ⏳ Ready to publish!
|
|
75
|
+
|
|
76
|
+
## Testing Before Publishing
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Link locally
|
|
80
|
+
npm link
|
|
81
|
+
|
|
82
|
+
# Test all commands
|
|
83
|
+
saac --help
|
|
84
|
+
saac register
|
|
85
|
+
saac login
|
|
86
|
+
saac deploy
|
|
87
|
+
|
|
88
|
+
# Unlink when done
|
|
89
|
+
npm unlink -g @startanaicompany/cli
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Post-Publishing
|
|
93
|
+
|
|
94
|
+
After publishing, users can install with:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm install -g @startanaicompany/cli
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then use:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
saac register
|
|
104
|
+
saac create my-site
|
|
105
|
+
saac deploy
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Perfect! 🚀
|
package/README.md
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# @startanaicompany/cli
|
|
2
|
+
|
|
3
|
+
> Official CLI for StartAnAiCompany.com - Deploy AI recruitment sites with ease
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@startanaicompany/cli)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- ✨ **Simple & Intuitive** - Deploy with a single command
|
|
11
|
+
- 🔐 **Secure** - API key-based authentication
|
|
12
|
+
- 🚀 **Fast** - Optimized for quick deployments
|
|
13
|
+
- 📦 **Zero Configuration** - Works out of the box
|
|
14
|
+
- 🎨 **Beautiful CLI** - Color-coded output and progress indicators
|
|
15
|
+
- 🔄 **Auto-healing** - Automatically fixes common deployment issues
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @startanaicompany/cli
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 1. Register for an account
|
|
27
|
+
saac register
|
|
28
|
+
|
|
29
|
+
# 2. Verify your email (check MailHog)
|
|
30
|
+
saac verify <code>
|
|
31
|
+
|
|
32
|
+
# 3. Create a new application
|
|
33
|
+
saac create my-recruitment-site
|
|
34
|
+
|
|
35
|
+
# 4. Deploy!
|
|
36
|
+
saac deploy
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Commands
|
|
40
|
+
|
|
41
|
+
### Authentication
|
|
42
|
+
|
|
43
|
+
#### `saac register`
|
|
44
|
+
Register for a new account
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
saac register
|
|
48
|
+
saac register --email user@example.com
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### `saac login`
|
|
52
|
+
Login with existing credentials
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
saac login
|
|
56
|
+
saac login --email user@example.com --api-key cw_...
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### `saac verify <code>`
|
|
60
|
+
Verify your email address
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
saac verify 123456
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Note:** Check MailHog at https://mailhog.goryan.io for verification codes
|
|
67
|
+
|
|
68
|
+
#### `saac logout`
|
|
69
|
+
Clear saved credentials
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
saac logout
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Application Management
|
|
76
|
+
|
|
77
|
+
#### `saac init`
|
|
78
|
+
Initialize SAAC in an existing project
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
saac init
|
|
82
|
+
saac init --name myapp --subdomain myapp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### `saac create [name]`
|
|
86
|
+
Create a new application
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
saac create
|
|
90
|
+
saac create my-site --subdomain mysite
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Options:
|
|
94
|
+
- `-s, --subdomain <subdomain>` - Subdomain for your site
|
|
95
|
+
- `-d, --domain-suffix <suffix>` - Domain suffix (default: startanaicompany.com)
|
|
96
|
+
- `-r, --repository <url>` - Git repository URL
|
|
97
|
+
- `-b, --branch <branch>` - Git branch (default: master)
|
|
98
|
+
|
|
99
|
+
#### `saac deploy`
|
|
100
|
+
Deploy your application
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
saac deploy
|
|
104
|
+
saac deploy --force
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### `saac logs`
|
|
108
|
+
View application logs
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
saac logs
|
|
112
|
+
saac logs --tail 50
|
|
113
|
+
saac logs --follow
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Environment Variables
|
|
117
|
+
|
|
118
|
+
#### `saac env set <vars...>`
|
|
119
|
+
Set environment variables
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
saac env set KEY=value
|
|
123
|
+
saac env set KEY1=value1 KEY2=value2
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### `saac env get [key]`
|
|
127
|
+
Get environment variable(s)
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
saac env get
|
|
131
|
+
saac env get KEY
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### `saac env list`
|
|
135
|
+
List all environment variables
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
saac env list
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Domain Management
|
|
142
|
+
|
|
143
|
+
#### `saac domain set <subdomain>`
|
|
144
|
+
Change your application subdomain
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
saac domain set newsubdomain
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### `saac domain show`
|
|
151
|
+
Show current domain
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
saac domain show
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Information
|
|
158
|
+
|
|
159
|
+
#### `saac list`
|
|
160
|
+
List all your applications
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
saac list
|
|
164
|
+
saac ls
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### `saac status`
|
|
168
|
+
Show current application status
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
saac status
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### `saac whoami`
|
|
175
|
+
Show current user information
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
saac whoami
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Deletion
|
|
182
|
+
|
|
183
|
+
#### `saac delete`
|
|
184
|
+
Delete current application
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
saac delete
|
|
188
|
+
saac delete --yes # Skip confirmation
|
|
189
|
+
saac rm # Alias
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Configuration
|
|
193
|
+
|
|
194
|
+
### Global Configuration
|
|
195
|
+
|
|
196
|
+
Stored in `~/.saac/config.json`:
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"apiUrl": "https://apps.startanaicompany.com/api/v1",
|
|
201
|
+
"user": {
|
|
202
|
+
"email": "user@example.com",
|
|
203
|
+
"userId": "...",
|
|
204
|
+
"apiKey": "cw_...",
|
|
205
|
+
"verified": true
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Project Configuration
|
|
211
|
+
|
|
212
|
+
Stored in `.saac/config.json` in your project:
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"applicationUuid": "...",
|
|
217
|
+
"applicationName": "my-site",
|
|
218
|
+
"subdomain": "mysite",
|
|
219
|
+
"domainSuffix": "startanaicompany.com",
|
|
220
|
+
"gitRepository": "git@git.startanaicompany.com:user/repo.git"
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Workflow Example
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# Step 1: Register and verify
|
|
228
|
+
saac register --email dev@company.com
|
|
229
|
+
# Check MailHog for code
|
|
230
|
+
saac verify 123456
|
|
231
|
+
|
|
232
|
+
# Step 2: Clone or create your project
|
|
233
|
+
git clone git@git.startanaicompany.com:user/mysite.git
|
|
234
|
+
cd mysite
|
|
235
|
+
|
|
236
|
+
# Step 3: Initialize SAAC
|
|
237
|
+
saac init --subdomain mycompany
|
|
238
|
+
|
|
239
|
+
# Step 4: Deploy
|
|
240
|
+
saac deploy
|
|
241
|
+
|
|
242
|
+
# Step 5: View logs
|
|
243
|
+
saac logs --follow
|
|
244
|
+
|
|
245
|
+
# Step 6: Update environment variables
|
|
246
|
+
saac env set COMPANY_NAME="My Company"
|
|
247
|
+
saac deploy # Redeploy to apply changes
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Environment Variables
|
|
251
|
+
|
|
252
|
+
The CLI sets these automatically:
|
|
253
|
+
- `DOMAIN` - Your application domain
|
|
254
|
+
- `COOLIFY_*` - Coolify API configuration (managed by wrapper)
|
|
255
|
+
|
|
256
|
+
You can set custom variables:
|
|
257
|
+
```bash
|
|
258
|
+
saac env set COMPANY_NAME="Acme Corp"
|
|
259
|
+
saac env set PRIMARY_COLOR="#2563EB"
|
|
260
|
+
saac env set CONTACT_EMAIL="contact@acme.com"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Troubleshooting
|
|
264
|
+
|
|
265
|
+
### "Not logged in"
|
|
266
|
+
```bash
|
|
267
|
+
saac login
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### "No application found"
|
|
271
|
+
```bash
|
|
272
|
+
saac init
|
|
273
|
+
# or
|
|
274
|
+
saac create
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### "Email not verified"
|
|
278
|
+
Check MailHog at https://mailhog.goryan.io and run:
|
|
279
|
+
```bash
|
|
280
|
+
saac verify <code>
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Deployment fails
|
|
284
|
+
```bash
|
|
285
|
+
# View logs to see what went wrong
|
|
286
|
+
saac logs
|
|
287
|
+
|
|
288
|
+
# Try force deploy
|
|
289
|
+
saac deploy --force
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Development
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# Clone repository
|
|
296
|
+
git clone https://github.com/startanaicompany/cli.git
|
|
297
|
+
cd cli
|
|
298
|
+
|
|
299
|
+
# Install dependencies
|
|
300
|
+
npm install
|
|
301
|
+
|
|
302
|
+
# Link for local development
|
|
303
|
+
npm link
|
|
304
|
+
|
|
305
|
+
# Now you can use `saac` command
|
|
306
|
+
saac --help
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Support
|
|
310
|
+
|
|
311
|
+
- 📧 Email: support@startanaicompany.com
|
|
312
|
+
- 🐛 Issues: https://github.com/startanaicompany/cli/issues
|
|
313
|
+
- 📚 Docs: https://startanaicompany.com/docs
|
|
314
|
+
|
|
315
|
+
## License
|
|
316
|
+
|
|
317
|
+
MIT © StartAnAiCompany
|
|
318
|
+
|
|
319
|
+
## Contributing
|
|
320
|
+
|
|
321
|
+
Pull requests are welcome! Please read our contributing guidelines first.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
Made with ❤️ by StartAnAiCompany
|
package/bin/saac.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SAAC CLI - StartAnAiCompany Official CLI
|
|
5
|
+
* Deploy AI recruitment sites with ease
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { program } = require('commander');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const pkg = require('../package.json');
|
|
11
|
+
|
|
12
|
+
// Import commands
|
|
13
|
+
const register = require('../src/commands/register');
|
|
14
|
+
const login = require('../src/commands/login');
|
|
15
|
+
const verify = require('../src/commands/verify');
|
|
16
|
+
const logout = require('../src/commands/logout');
|
|
17
|
+
const init = require('../src/commands/init');
|
|
18
|
+
const create = require('../src/commands/create');
|
|
19
|
+
const deploy = require('../src/commands/deploy');
|
|
20
|
+
const logs = require('../src/commands/logs');
|
|
21
|
+
const env = require('../src/commands/env');
|
|
22
|
+
const domain = require('../src/commands/domain');
|
|
23
|
+
const deleteCmd = require('../src/commands/delete');
|
|
24
|
+
const list = require('../src/commands/list');
|
|
25
|
+
const status = require('../src/commands/status');
|
|
26
|
+
const whoami = require('../src/commands/whoami');
|
|
27
|
+
|
|
28
|
+
// Configure CLI
|
|
29
|
+
program
|
|
30
|
+
.name('saac')
|
|
31
|
+
.description(chalk.cyan('Official CLI for StartAnAiCompany.com'))
|
|
32
|
+
.version(pkg.version, '-v, --version', 'Output the current version')
|
|
33
|
+
.helpOption('-h, --help', 'Display help for command');
|
|
34
|
+
|
|
35
|
+
// Authentication commands
|
|
36
|
+
program
|
|
37
|
+
.command('register')
|
|
38
|
+
.description('Register for a new account')
|
|
39
|
+
.option('-e, --email <email>', 'Email address')
|
|
40
|
+
.option('--gitea-username <username>', 'Gitea username (auto-detected if not provided)')
|
|
41
|
+
.action(register);
|
|
42
|
+
|
|
43
|
+
program
|
|
44
|
+
.command('login')
|
|
45
|
+
.description('Login with existing account')
|
|
46
|
+
.option('-e, --email <email>', 'Email address')
|
|
47
|
+
.option('-k, --api-key <key>', 'API key')
|
|
48
|
+
.action(login);
|
|
49
|
+
|
|
50
|
+
program
|
|
51
|
+
.command('verify <code>')
|
|
52
|
+
.description('Verify email with verification code')
|
|
53
|
+
.action(verify);
|
|
54
|
+
|
|
55
|
+
program
|
|
56
|
+
.command('logout')
|
|
57
|
+
.description('Clear saved credentials')
|
|
58
|
+
.action(logout);
|
|
59
|
+
|
|
60
|
+
// Application management
|
|
61
|
+
program
|
|
62
|
+
.command('init')
|
|
63
|
+
.description('Initialize a new SAAC project in current directory')
|
|
64
|
+
.option('-n, --name <name>', 'Application name')
|
|
65
|
+
.option('-s, --subdomain <subdomain>', 'Subdomain')
|
|
66
|
+
.option('-d, --domain-suffix <suffix>', 'Domain suffix', 'startanaicompany.com')
|
|
67
|
+
.option('-r, --repository <url>', 'Git repository URL')
|
|
68
|
+
.action(init);
|
|
69
|
+
|
|
70
|
+
program
|
|
71
|
+
.command('create [name]')
|
|
72
|
+
.description('Create a new application')
|
|
73
|
+
.option('-s, --subdomain <subdomain>', 'Subdomain')
|
|
74
|
+
.option('-d, --domain-suffix <suffix>', 'Domain suffix', 'startanaicompany.com')
|
|
75
|
+
.option('-r, --repository <url>', 'Git repository URL')
|
|
76
|
+
.option('-b, --branch <branch>', 'Git branch', 'master')
|
|
77
|
+
.action(create);
|
|
78
|
+
|
|
79
|
+
program
|
|
80
|
+
.command('deploy')
|
|
81
|
+
.description('Deploy current application')
|
|
82
|
+
.option('-f, --force', 'Force deployment')
|
|
83
|
+
.action(deploy);
|
|
84
|
+
|
|
85
|
+
program
|
|
86
|
+
.command('logs')
|
|
87
|
+
.description('View application logs')
|
|
88
|
+
.option('-t, --tail <lines>', 'Number of lines to show', '100')
|
|
89
|
+
.option('-f, --follow', 'Follow log output')
|
|
90
|
+
.action(logs);
|
|
91
|
+
|
|
92
|
+
// Environment variable commands
|
|
93
|
+
const envCommand = program
|
|
94
|
+
.command('env')
|
|
95
|
+
.description('Manage environment variables');
|
|
96
|
+
|
|
97
|
+
envCommand
|
|
98
|
+
.command('set <vars...>')
|
|
99
|
+
.description('Set environment variables (KEY=VALUE format)')
|
|
100
|
+
.action(env.set);
|
|
101
|
+
|
|
102
|
+
envCommand
|
|
103
|
+
.command('get [key]')
|
|
104
|
+
.description('Get environment variable(s)')
|
|
105
|
+
.action(env.get);
|
|
106
|
+
|
|
107
|
+
envCommand
|
|
108
|
+
.command('list')
|
|
109
|
+
.alias('ls')
|
|
110
|
+
.description('List all environment variables')
|
|
111
|
+
.action(env.list);
|
|
112
|
+
|
|
113
|
+
// Domain management
|
|
114
|
+
const domainCommand = program
|
|
115
|
+
.command('domain')
|
|
116
|
+
.description('Manage application domain');
|
|
117
|
+
|
|
118
|
+
domainCommand
|
|
119
|
+
.command('set <subdomain>')
|
|
120
|
+
.description('Change subdomain')
|
|
121
|
+
.option('-d, --domain-suffix <suffix>', 'Domain suffix', 'startanaicompany.com')
|
|
122
|
+
.action(domain.set);
|
|
123
|
+
|
|
124
|
+
domainCommand
|
|
125
|
+
.command('show')
|
|
126
|
+
.description('Show current domain')
|
|
127
|
+
.action(domain.show);
|
|
128
|
+
|
|
129
|
+
// Application info
|
|
130
|
+
program
|
|
131
|
+
.command('list')
|
|
132
|
+
.alias('ls')
|
|
133
|
+
.description('List all your applications')
|
|
134
|
+
.action(list);
|
|
135
|
+
|
|
136
|
+
program
|
|
137
|
+
.command('status')
|
|
138
|
+
.description('Show current application status')
|
|
139
|
+
.action(status);
|
|
140
|
+
|
|
141
|
+
program
|
|
142
|
+
.command('whoami')
|
|
143
|
+
.description('Show current user information')
|
|
144
|
+
.action(whoami);
|
|
145
|
+
|
|
146
|
+
// Deletion
|
|
147
|
+
program
|
|
148
|
+
.command('delete')
|
|
149
|
+
.alias('rm')
|
|
150
|
+
.description('Delete current application')
|
|
151
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
152
|
+
.action(deleteCmd);
|
|
153
|
+
|
|
154
|
+
// Error handling
|
|
155
|
+
program.on('command:*', function () {
|
|
156
|
+
console.error(chalk.red('\n Invalid command: %s\n'), program.args.join(' '));
|
|
157
|
+
console.log(chalk.yellow(' Run'), chalk.cyan('saac --help'), chalk.yellow('to see available commands'));
|
|
158
|
+
process.exit(1);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Parse arguments
|
|
162
|
+
program.parse(process.argv);
|
|
163
|
+
|
|
164
|
+
// Show help if no command provided
|
|
165
|
+
if (!process.argv.slice(2).length) {
|
|
166
|
+
program.outputHelp();
|
|
167
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@startanaicompany/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official CLI for StartAnAiCompany.com - Deploy AI recruitment sites with ease",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"saac": "./bin/saac.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"dev": "node bin/saac.js",
|
|
12
|
+
"lint": "eslint src/"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"saac",
|
|
16
|
+
"startanaicompany",
|
|
17
|
+
"deployment",
|
|
18
|
+
"cli",
|
|
19
|
+
"ai",
|
|
20
|
+
"recruitment",
|
|
21
|
+
"coolify"
|
|
22
|
+
],
|
|
23
|
+
"author": "StartAnAiCompany <support@startanaicompany.com>",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/startanaicompany/cli.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/startanaicompany/cli/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/startanaicompany/cli#readme",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=16.0.0"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"axios": "^1.6.0",
|
|
38
|
+
"chalk": "^4.1.2",
|
|
39
|
+
"commander": "^11.1.0",
|
|
40
|
+
"conf": "^10.2.0",
|
|
41
|
+
"inquirer": "^8.2.5",
|
|
42
|
+
"ora": "^5.4.1",
|
|
43
|
+
"boxen": "^5.1.2",
|
|
44
|
+
"table": "^6.8.1",
|
|
45
|
+
"dotenv": "^16.3.1",
|
|
46
|
+
"validator": "^13.11.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"eslint": "^8.54.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy command
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const api = require('../lib/api');
|
|
6
|
+
const { getProjectConfig, isAuthenticated } = require('../lib/config');
|
|
7
|
+
const logger = require('../lib/logger');
|
|
8
|
+
|
|
9
|
+
async function deploy(options) {
|
|
10
|
+
try {
|
|
11
|
+
// Check authentication
|
|
12
|
+
if (!isAuthenticated()) {
|
|
13
|
+
logger.error('Not logged in. Run: saac login');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Check for project config
|
|
18
|
+
const projectConfig = getProjectConfig();
|
|
19
|
+
if (!projectConfig || !projectConfig.applicationUuid) {
|
|
20
|
+
logger.error('No application found in current directory');
|
|
21
|
+
logger.info('Run: saac init or saac create');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { applicationUuid, applicationName } = projectConfig;
|
|
26
|
+
|
|
27
|
+
logger.section(`Deploying ${applicationName}`);
|
|
28
|
+
|
|
29
|
+
const spin = logger.spinner('Triggering deployment...').start();
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const result = await api.deployApplication(applicationUuid);
|
|
33
|
+
|
|
34
|
+
spin.succeed('Deployment triggered!');
|
|
35
|
+
|
|
36
|
+
logger.newline();
|
|
37
|
+
logger.success('Deployment started successfully');
|
|
38
|
+
logger.newline();
|
|
39
|
+
logger.field('Application', applicationName);
|
|
40
|
+
logger.field('Status', result.status);
|
|
41
|
+
if (result.domain) {
|
|
42
|
+
logger.field('Domain', result.domain);
|
|
43
|
+
}
|
|
44
|
+
logger.field('Deployment ID', result.deployment_id);
|
|
45
|
+
logger.newline();
|
|
46
|
+
logger.info(
|
|
47
|
+
`View logs with: ${logger.chalk.yellow('saac logs --follow')}`
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
} catch (error) {
|
|
51
|
+
spin.fail('Deployment failed');
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
logger.error(error.response?.data?.message || error.message);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = deploy;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Login command
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const inquirer = require('inquirer');
|
|
6
|
+
const validator = require('validator');
|
|
7
|
+
const api = require('../lib/api');
|
|
8
|
+
const { saveUser } = require('../lib/config');
|
|
9
|
+
const logger = require('../lib/logger');
|
|
10
|
+
|
|
11
|
+
async function login(options) {
|
|
12
|
+
try {
|
|
13
|
+
logger.section('Login to StartAnAiCompany');
|
|
14
|
+
|
|
15
|
+
// Get email
|
|
16
|
+
let email = options.email;
|
|
17
|
+
if (!email) {
|
|
18
|
+
const answers = await inquirer.prompt([
|
|
19
|
+
{
|
|
20
|
+
type: 'input',
|
|
21
|
+
name: 'email',
|
|
22
|
+
message: 'Email address:',
|
|
23
|
+
validate: (input) => {
|
|
24
|
+
if (!validator.isEmail(input)) {
|
|
25
|
+
return 'Please enter a valid email address';
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
]);
|
|
31
|
+
email = answers.email;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Get API key
|
|
35
|
+
let apiKey = options.apiKey;
|
|
36
|
+
if (!apiKey) {
|
|
37
|
+
const answers = await inquirer.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: 'password',
|
|
40
|
+
name: 'apiKey',
|
|
41
|
+
message: 'API Key:',
|
|
42
|
+
mask: '*',
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
apiKey = answers.apiKey;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Verify credentials by getting user info
|
|
49
|
+
const spin = logger.spinner('Verifying credentials...').start();
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// Save temporarily to make API call
|
|
53
|
+
saveUser({ email, apiKey });
|
|
54
|
+
|
|
55
|
+
const userInfo = await api.getUserInfo();
|
|
56
|
+
|
|
57
|
+
spin.succeed('Login successful!');
|
|
58
|
+
|
|
59
|
+
// Update with full user info
|
|
60
|
+
saveUser({
|
|
61
|
+
email: userInfo.email,
|
|
62
|
+
userId: userInfo.id,
|
|
63
|
+
apiKey,
|
|
64
|
+
verified: userInfo.email_verified,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
logger.newline();
|
|
68
|
+
logger.success('You are now logged in!');
|
|
69
|
+
logger.newline();
|
|
70
|
+
logger.field('Email', userInfo.email);
|
|
71
|
+
logger.field('Verified', userInfo.email_verified ? 'Yes' : 'No');
|
|
72
|
+
|
|
73
|
+
} catch (error) {
|
|
74
|
+
spin.fail('Login failed');
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logger.error(
|
|
79
|
+
error.response?.data?.message || 'Invalid credentials'
|
|
80
|
+
);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = login;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register command - Create a new account
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const inquirer = require('inquirer');
|
|
6
|
+
const validator = require('validator');
|
|
7
|
+
const api = require('../lib/api');
|
|
8
|
+
const { saveUser } = require('../lib/config');
|
|
9
|
+
const logger = require('../lib/logger');
|
|
10
|
+
|
|
11
|
+
async function register(options) {
|
|
12
|
+
try {
|
|
13
|
+
logger.section('Register for StartAnAiCompany');
|
|
14
|
+
|
|
15
|
+
// Get email (from flag or prompt)
|
|
16
|
+
let email = options.email;
|
|
17
|
+
if (!email) {
|
|
18
|
+
const answers = await inquirer.prompt([
|
|
19
|
+
{
|
|
20
|
+
type: 'input',
|
|
21
|
+
name: 'email',
|
|
22
|
+
message: 'Email address:',
|
|
23
|
+
validate: (input) => {
|
|
24
|
+
if (!validator.isEmail(input)) {
|
|
25
|
+
return 'Please enter a valid email address';
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
]);
|
|
31
|
+
email = answers.email;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Get Gitea username (optional, auto-detected from git)
|
|
35
|
+
let giteaUsername = options.giteaUsername;
|
|
36
|
+
if (!giteaUsername) {
|
|
37
|
+
const answers = await inquirer.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: 'input',
|
|
40
|
+
name: 'giteaUsername',
|
|
41
|
+
message: 'Gitea username (optional, press Enter to skip):',
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
giteaUsername = answers.giteaUsername || undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Register via API
|
|
48
|
+
const spin = logger.spinner('Creating account...').start();
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const result = await api.register(email, giteaUsername);
|
|
52
|
+
|
|
53
|
+
spin.succeed('Account created successfully!');
|
|
54
|
+
|
|
55
|
+
// Save user info
|
|
56
|
+
saveUser({
|
|
57
|
+
email: result.email || email,
|
|
58
|
+
userId: result.user_id,
|
|
59
|
+
apiKey: result.api_key,
|
|
60
|
+
verified: result.verified || false,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
logger.newline();
|
|
64
|
+
logger.success('Registration complete!');
|
|
65
|
+
logger.newline();
|
|
66
|
+
|
|
67
|
+
if (!result.verified) {
|
|
68
|
+
logger.info(
|
|
69
|
+
`A verification code has been sent to ${logger.chalk.cyan(email)}`
|
|
70
|
+
);
|
|
71
|
+
logger.info(
|
|
72
|
+
`Check your email and run: ${logger.chalk.yellow(
|
|
73
|
+
'saac verify <code>'
|
|
74
|
+
)}`
|
|
75
|
+
);
|
|
76
|
+
logger.newline();
|
|
77
|
+
logger.warn(
|
|
78
|
+
'Note: Check MailHog at https://mailhog.goryan.io for the verification code'
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
logger.newline();
|
|
83
|
+
logger.field('Email', email);
|
|
84
|
+
logger.field('API Key', result.api_key.substring(0, 20) + '...');
|
|
85
|
+
|
|
86
|
+
} catch (error) {
|
|
87
|
+
spin.fail('Registration failed');
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logger.error(error.response?.data?.message || error.message);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = register;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify email command
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const api = require('../lib/api');
|
|
6
|
+
const { getUser, saveUser } = require('../lib/config');
|
|
7
|
+
const logger = require('../lib/logger');
|
|
8
|
+
|
|
9
|
+
async function verify(code) {
|
|
10
|
+
try {
|
|
11
|
+
const user = getUser();
|
|
12
|
+
|
|
13
|
+
if (!user || !user.email) {
|
|
14
|
+
logger.error('No user found. Please register first with: saac register');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (user.verified) {
|
|
19
|
+
logger.warn('Email already verified!');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
logger.section('Verify Email');
|
|
24
|
+
|
|
25
|
+
const spin = logger.spinner('Verifying email...').start();
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const result = await api.verifyEmail(user.email, code);
|
|
29
|
+
|
|
30
|
+
spin.succeed('Email verified successfully!');
|
|
31
|
+
|
|
32
|
+
// Update user verification status
|
|
33
|
+
saveUser({
|
|
34
|
+
...user,
|
|
35
|
+
verified: true,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
logger.newline();
|
|
39
|
+
logger.success('Your account is now verified!');
|
|
40
|
+
logger.info('You can now create and deploy applications.');
|
|
41
|
+
|
|
42
|
+
} catch (error) {
|
|
43
|
+
spin.fail('Verification failed');
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
} catch (error) {
|
|
47
|
+
logger.error(
|
|
48
|
+
error.response?.data?.message || 'Invalid verification code'
|
|
49
|
+
);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = verify;
|
package/src/lib/api.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client for SAAC Wrapper API
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const axios = require('axios');
|
|
6
|
+
const { getApiUrl, getUser } = require('./config');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create axios instance with base configuration
|
|
10
|
+
*/
|
|
11
|
+
function createClient() {
|
|
12
|
+
const user = getUser();
|
|
13
|
+
|
|
14
|
+
return axios.create({
|
|
15
|
+
baseURL: getApiUrl(),
|
|
16
|
+
timeout: 30000,
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
...(user?.apiKey && { 'X-API-Key': user.apiKey }),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Register a new user
|
|
26
|
+
*/
|
|
27
|
+
async function register(email, giteaUsername) {
|
|
28
|
+
const client = createClient();
|
|
29
|
+
const response = await client.post('/register', {
|
|
30
|
+
email,
|
|
31
|
+
gitea_username: giteaUsername,
|
|
32
|
+
});
|
|
33
|
+
return response.data;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Verify email with code
|
|
38
|
+
*/
|
|
39
|
+
async function verifyEmail(email, code) {
|
|
40
|
+
const client = createClient();
|
|
41
|
+
const response = await client.post('/users/verify', {
|
|
42
|
+
email,
|
|
43
|
+
verification_code: code,
|
|
44
|
+
});
|
|
45
|
+
return response.data;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get current user info
|
|
50
|
+
*/
|
|
51
|
+
async function getUserInfo() {
|
|
52
|
+
const client = createClient();
|
|
53
|
+
const response = await client.get('/users/me');
|
|
54
|
+
return response.data;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create a new application
|
|
59
|
+
*/
|
|
60
|
+
async function createApplication(appData) {
|
|
61
|
+
const client = createClient();
|
|
62
|
+
const response = await client.post('/applications', appData);
|
|
63
|
+
return response.data;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* List all applications
|
|
68
|
+
*/
|
|
69
|
+
async function listApplications() {
|
|
70
|
+
const client = createClient();
|
|
71
|
+
const response = await client.get('/applications');
|
|
72
|
+
return response.data;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get application details
|
|
77
|
+
*/
|
|
78
|
+
async function getApplication(uuid) {
|
|
79
|
+
const client = createClient();
|
|
80
|
+
const response = await client.get(`/applications/${uuid}`);
|
|
81
|
+
return response.data;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Deploy application
|
|
86
|
+
*/
|
|
87
|
+
async function deployApplication(uuid) {
|
|
88
|
+
const client = createClient();
|
|
89
|
+
const response = await client.post(`/applications/${uuid}/deploy`);
|
|
90
|
+
return response.data;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get application logs
|
|
95
|
+
*/
|
|
96
|
+
async function getApplicationLogs(uuid, params = {}) {
|
|
97
|
+
const client = createClient();
|
|
98
|
+
const response = await client.get(`/applications/${uuid}/logs`, { params });
|
|
99
|
+
return response.data;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Update environment variables
|
|
104
|
+
*/
|
|
105
|
+
async function updateEnvironmentVariables(uuid, variables) {
|
|
106
|
+
const client = createClient();
|
|
107
|
+
const response = await client.patch(`/applications/${uuid}/env`, {
|
|
108
|
+
variables,
|
|
109
|
+
});
|
|
110
|
+
return response.data;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Update application domain
|
|
115
|
+
*/
|
|
116
|
+
async function updateDomain(uuid, subdomain, domainSuffix) {
|
|
117
|
+
const client = createClient();
|
|
118
|
+
const response = await client.patch(`/applications/${uuid}/domain`, {
|
|
119
|
+
subdomain,
|
|
120
|
+
domain_suffix: domainSuffix,
|
|
121
|
+
});
|
|
122
|
+
return response.data;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Delete application
|
|
127
|
+
*/
|
|
128
|
+
async function deleteApplication(uuid) {
|
|
129
|
+
const client = createClient();
|
|
130
|
+
const response = await client.delete(`/applications/${uuid}`);
|
|
131
|
+
return response.data;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Health check
|
|
136
|
+
*/
|
|
137
|
+
async function healthCheck() {
|
|
138
|
+
const client = createClient();
|
|
139
|
+
const response = await client.get('/health');
|
|
140
|
+
return response.data;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = {
|
|
144
|
+
register,
|
|
145
|
+
verifyEmail,
|
|
146
|
+
getUserInfo,
|
|
147
|
+
createApplication,
|
|
148
|
+
listApplications,
|
|
149
|
+
getApplication,
|
|
150
|
+
deployApplication,
|
|
151
|
+
getApplicationLogs,
|
|
152
|
+
updateEnvironmentVariables,
|
|
153
|
+
updateDomain,
|
|
154
|
+
deleteApplication,
|
|
155
|
+
healthCheck,
|
|
156
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration management
|
|
3
|
+
* Handles both global (~/.saac/config.json) and project (.saac/config.json) configs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const Conf = require('conf');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
|
|
10
|
+
// Global configuration (user credentials, API settings)
|
|
11
|
+
const globalConfig = new Conf({
|
|
12
|
+
projectName: 'saac',
|
|
13
|
+
configName: 'config',
|
|
14
|
+
defaults: {
|
|
15
|
+
apiUrl: 'https://apps.startanaicompany.com/api/v1',
|
|
16
|
+
giteaUrl: 'https://git.startanaicompany.com/api/v1',
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get project configuration (from .saac/config.json in current directory)
|
|
22
|
+
*/
|
|
23
|
+
function getProjectConfig() {
|
|
24
|
+
const configPath = path.join(process.cwd(), '.saac', 'config.json');
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(configPath)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const data = fs.readFileSync(configPath, 'utf8');
|
|
32
|
+
return JSON.parse(data);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Save project configuration
|
|
40
|
+
*/
|
|
41
|
+
function saveProjectConfig(config) {
|
|
42
|
+
const configDir = path.join(process.cwd(), '.saac');
|
|
43
|
+
const configPath = path.join(configDir, 'config.json');
|
|
44
|
+
|
|
45
|
+
// Create .saac directory if it doesn't exist
|
|
46
|
+
if (!fs.existsSync(configDir)) {
|
|
47
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check if user is authenticated
|
|
55
|
+
*/
|
|
56
|
+
function isAuthenticated() {
|
|
57
|
+
const apiKey = globalConfig.get('user.apiKey');
|
|
58
|
+
const email = globalConfig.get('user.email');
|
|
59
|
+
return !!(apiKey && email);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get user info
|
|
64
|
+
*/
|
|
65
|
+
function getUser() {
|
|
66
|
+
return globalConfig.get('user') || null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Save user info
|
|
71
|
+
*/
|
|
72
|
+
function saveUser(user) {
|
|
73
|
+
globalConfig.set('user', user);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Clear user info (logout)
|
|
78
|
+
*/
|
|
79
|
+
function clearUser() {
|
|
80
|
+
globalConfig.delete('user');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get API URL
|
|
85
|
+
*/
|
|
86
|
+
function getApiUrl() {
|
|
87
|
+
return globalConfig.get('apiUrl');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get Gitea URL
|
|
92
|
+
*/
|
|
93
|
+
function getGiteaUrl() {
|
|
94
|
+
return globalConfig.get('giteaUrl');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
globalConfig,
|
|
99
|
+
getProjectConfig,
|
|
100
|
+
saveProjectConfig,
|
|
101
|
+
isAuthenticated,
|
|
102
|
+
getUser,
|
|
103
|
+
saveUser,
|
|
104
|
+
clearUser,
|
|
105
|
+
getApiUrl,
|
|
106
|
+
getGiteaUrl,
|
|
107
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pretty logging with colors and symbols
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const ora = require('ora');
|
|
7
|
+
const boxen = require('boxen');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Log success message
|
|
11
|
+
*/
|
|
12
|
+
function success(message) {
|
|
13
|
+
console.log(chalk.green('✓'), message);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Log error message
|
|
18
|
+
*/
|
|
19
|
+
function error(message) {
|
|
20
|
+
console.log(chalk.red('✗'), message);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Log warning message
|
|
25
|
+
*/
|
|
26
|
+
function warn(message) {
|
|
27
|
+
console.log(chalk.yellow('⚠'), message);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Log info message
|
|
32
|
+
*/
|
|
33
|
+
function info(message) {
|
|
34
|
+
console.log(chalk.blue('ℹ'), message);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Log plain message
|
|
39
|
+
*/
|
|
40
|
+
function log(message) {
|
|
41
|
+
console.log(message);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Create a spinner
|
|
46
|
+
*/
|
|
47
|
+
function spinner(text) {
|
|
48
|
+
return ora({
|
|
49
|
+
text,
|
|
50
|
+
color: 'cyan',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Log a boxed message
|
|
56
|
+
*/
|
|
57
|
+
function box(message, options = {}) {
|
|
58
|
+
console.log(
|
|
59
|
+
boxen(message, {
|
|
60
|
+
padding: 1,
|
|
61
|
+
margin: 1,
|
|
62
|
+
borderStyle: 'round',
|
|
63
|
+
borderColor: 'cyan',
|
|
64
|
+
...options,
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Log section header
|
|
71
|
+
*/
|
|
72
|
+
function section(title) {
|
|
73
|
+
console.log('\n' + chalk.bold.cyan(title));
|
|
74
|
+
console.log(chalk.gray('─'.repeat(title.length)));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Log key-value pair
|
|
79
|
+
*/
|
|
80
|
+
function field(key, value) {
|
|
81
|
+
console.log(chalk.gray(` ${key}:`), chalk.white(value));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Log newline
|
|
86
|
+
*/
|
|
87
|
+
function newline() {
|
|
88
|
+
console.log('');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
success,
|
|
93
|
+
error,
|
|
94
|
+
warn,
|
|
95
|
+
info,
|
|
96
|
+
log,
|
|
97
|
+
spinner,
|
|
98
|
+
box,
|
|
99
|
+
section,
|
|
100
|
+
field,
|
|
101
|
+
newline,
|
|
102
|
+
chalk,
|
|
103
|
+
};
|