@startanaicompany/cli 1.4.10 → 1.4.12

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/CLAUDE.md CHANGED
@@ -103,6 +103,11 @@ All commands follow this pattern:
103
103
 
104
104
  **Important:** Commands require flags and do NOT use interactive prompts. This makes them LLM and automation-friendly.
105
105
 
106
+ **Exceptions to Non-Interactive Rule:**
107
+ - `saac init` - Uses inquirer to select from existing applications (intentionally interactive)
108
+ - `saac logout-all` - Confirmation prompt (can be skipped with `-y` flag)
109
+ - `saac git connect` - Interactive provider selection when no host specified
110
+
106
111
  **Examples:**
107
112
  ```bash
108
113
  # ✅ Correct - with flags
@@ -115,10 +120,11 @@ saac login
115
120
  ```
116
121
 
117
122
  **Command Files**:
118
- - Authentication: `register.js`, `login.js`, `verify.js`, `logout.js`, `whoami.js`
119
- - App Management: `create.js`, `init.js`, `deploy.js`, `delete.js`, `list.js`, `status.js`
120
- - Configuration: `env.js`, `domain.js`
121
- - Logs: `logs.js`
123
+ - Authentication: `register.js`, `login.js`, `verify.js`, `logout.js`, `logoutAll.js`, `sessions.js`, `whoami.js` (stub)
124
+ - Git OAuth: `git.js` (exports object with `connect`, `list`, `disconnect` methods)
125
+ - App Management: `create.js`, `init.js`, `deploy.js`, `update.js`, `delete.js` (stub), `list.js`, `status.js`
126
+ - Configuration: `env.js` (stub), `domain.js` (stub)
127
+ - Logs: `logs.js` (stub)
122
128
 
123
129
  ### Entry Point (`bin/saac.js`)
124
130
 
@@ -361,9 +367,33 @@ saac git disconnect git.startanaicompany.com
361
367
  - ✅ Supports multiple Git providers
362
368
 
363
369
  **Implementation Files:**
364
- - `src/lib/oauth.js` - OAuth helper functions
365
- - `src/commands/git.js` - Git command implementation
366
- - Updated `src/commands/create.js` - OAuth integration
370
+ - `src/lib/oauth.js` - OAuth helper functions (exports: `extractGitHost`, `connectGitAccount`, `getConnection`, `listConnections`, `revokeConnection`)
371
+ - `src/commands/git.js` - Git command implementation (exports object with `connect`, `list`, `disconnect` methods)
372
+ - Updated `src/commands/create.js` - OAuth integration (checks for existing OAuth connection before requiring `--git-token`)
373
+
374
+ ### Deploy Command Implementation
375
+
376
+ The `deploy` command triggers deployment for the current application.
377
+
378
+ **Usage:**
379
+ ```bash
380
+ saac deploy
381
+ saac deploy --force
382
+ ```
383
+
384
+ **How It Works:**
385
+ 1. Validates authentication (session token not expired)
386
+ 2. Checks for project config (`.saac/config.json`)
387
+ 3. Makes POST request to `/api/v1/applications/:uuid/deploy`
388
+ 4. Displays deployment status and deployment ID
389
+ 5. Shows command to follow logs: `saac logs --follow`
390
+
391
+ **Response Fields:**
392
+ - `status` - Application status after deployment triggered
393
+ - `domain` - Application domain (if available)
394
+ - `deployment_id` - Unique ID for this deployment
395
+
396
+ **Note:** The `--force` flag is defined in the CLI but not currently used by the API.
367
397
 
368
398
  ### Init Command Implementation
369
399
 
@@ -392,25 +422,58 @@ saac init
392
422
 
393
423
  **Note:** The `init` command options (`-n, --name`, etc.) are currently not implemented. To create a new application, use `saac create` instead.
394
424
 
425
+ ### List Command Implementation
426
+
427
+ The `list` command displays all user applications in a formatted table.
428
+
429
+ **Usage:**
430
+ ```bash
431
+ saac list
432
+ saac ls # Alias
433
+ ```
434
+
435
+ **How It Works:**
436
+ 1. Validates authentication
437
+ 2. Fetches all applications from `/api/v1/applications`
438
+ 3. Displays table with columns: Name, Domain, Status, Branch, Created
439
+ 4. Shows total count and helpful next-step commands
440
+
441
+ **Status Display:**
442
+ Uses the same status display logic as the status command (see "Application Status Values" section).
443
+
444
+ **Table Formatting:**
445
+ - Uses the `table` npm package
446
+ - Header shows total application count
447
+ - Domains fallback to `{subdomain}.startanaicompany.com` if not set
448
+ - Branch defaults to 'master' if not specified
449
+
395
450
  ### Incomplete Commands
396
451
 
397
452
  Several commands still need implementation:
398
- - `src/commands/env.js` - Not implemented (partial stub)
399
- - `src/commands/domain.js` - Not implemented (partial stub)
400
- - `src/commands/logs.js` - Not implemented (partial stub)
401
- - `src/commands/delete.js` - Not implemented (partial stub)
402
- - `src/commands/list.js` - Not implemented (partial stub)
403
- - `src/commands/whoami.js` - Not implemented (partial stub)
453
+ - `src/commands/env.js` - Not implemented (stub only)
454
+ - `src/commands/domain.js` - Not implemented (stub only)
455
+ - `src/commands/logs.js` - Not implemented (stub only)
456
+ - `src/commands/delete.js` - Not implemented (stub only)
457
+ - `src/commands/whoami.js` - Not implemented (stub only)
404
458
 
405
- These need full implementation following the pattern from completed commands like `create.js` or `login.js`.
459
+ **Important:** The `env` and `domain` commands need to export OBJECTS with subcommand methods (e.g., `module.exports = { set, get, list }`), not simple functions. See `bin/saac.js:189-219` for how these are called.
406
460
 
407
461
  **Implementation Pattern for New Commands:**
408
- 1. Require flags, no interactive prompts
462
+ 1. Require flags, no interactive prompts (exception: `init` uses inquirer for app selection)
409
463
  2. Show usage info if required flags missing
410
464
  3. Validate inputs before API calls
411
465
  4. Use spinners for async operations
412
466
  5. Handle errors with descriptive messages
413
467
 
468
+ **Example Module Structure for env.js:**
469
+ ```javascript
470
+ async function set(vars) { /* implementation */ }
471
+ async function get(key) { /* implementation */ }
472
+ async function list() { /* implementation */ }
473
+
474
+ module.exports = { set, get, list };
475
+ ```
476
+
414
477
  ### MailHog Integration
415
478
 
416
479
  The system uses MailHog for email verification in development:
@@ -430,7 +493,183 @@ The wrapper API expects Git repositories to be hosted on the StartAnAiCompany Gi
430
493
  - During registration, Gitea username can be auto-detected or manually provided
431
494
  - Applications reference repositories in the format: `git@git.startanaicompany.com:user/repo.git`
432
495
 
433
- ## Testing Considerations
496
+ ## Current Status - Version 1.4.12
497
+
498
+ ### Completed Features
499
+
500
+ **Authentication & Sessions:**
501
+ - ✅ `saac register` - Register with email only (git_username auto-detected from email)
502
+ - ✅ `saac login` - Login with email + API key, receives 1-year session token
503
+ - ✅ `saac verify` - Email verification, shows FULL API key for user to save
504
+ - ✅ `saac logout` - Logout from current device
505
+ - ✅ `saac logout-all` - Revoke all sessions
506
+ - ✅ `saac sessions` - List all active sessions
507
+ - ✅ `saac whoami` - Show current user info
508
+
509
+ **Git OAuth (NEW in 1.4.0):**
510
+ - ✅ `saac git connect [host]` - OAuth flow for Git authentication
511
+ - ✅ `saac git list` - List connected Git accounts
512
+ - ✅ `saac git disconnect <host>` - Revoke Git connection
513
+ - ✅ OAuth integration in create command (prompts if not connected)
514
+
515
+ **Application Management:**
516
+ - ✅ `saac create` - Create application with ALL advanced features
517
+ - ✅ `saac update` - Update application configuration (PATCH endpoint)
518
+ - ✅ `saac init` - Link existing application to current directory (interactive)
519
+ - ✅ `saac deploy` - Trigger deployment for current application
520
+ - ✅ `saac list` - List all applications with table display
521
+ - ✅ `saac status` - Show login status, user info, and applications
522
+
523
+ **Incomplete Commands:**
524
+ - ⏳ `saac logs` - Not implemented (stub only)
525
+ - ⏳ `saac env` - Not implemented (stub only, needs to export object with set/get/list methods)
526
+ - ⏳ `saac domain` - Not implemented (stub only, needs to export object with set/show methods)
527
+ - ⏳ `saac delete` - Not implemented (stub only)
528
+ - ⏳ `saac whoami` - Not implemented (stub only)
529
+ - ✅ `saac deploy` - Fully implemented
530
+ - ✅ `saac list` - Fully implemented
531
+
532
+ ### Critical Learnings & Bug Fixes
533
+
534
+ **Issue 1: Config Location**
535
+ - **Problem:** Conf package auto-appended `-nodejs` suffix to folder name
536
+ - **Solution:** Use explicit `cwd: path.join(os.homedir(), '.config', 'startanaicompany')` instead of `projectName`
537
+ - **Location:** `src/lib/config.js`
538
+
539
+ **Issue 2: Status Command Showing "Logged in" Then "Expired"**
540
+ - **Problem:** Command checked local session first, displayed status, THEN verified with server
541
+ - **Solution:** Verify with server FIRST before displaying any status
542
+ - **Location:** `src/commands/status.js`
543
+
544
+ **Issue 3: Application List Inconsistency**
545
+ - **Problem:** `/users/me` returned `application_count: 1` but `/applications` returned empty array
546
+ - **Root Cause:** Backend filtered by `status='active'` but new apps start with `status='creating'`
547
+ - **Solution:** Backend team fixed to filter by `status != 'deleted'`
548
+ - **Location:** Backend - `src/services/application.js:447`
549
+
550
+ **Issue 4: Register Endpoint 404 Error**
551
+ - **Problem:** CLI was calling `POST /api/v1/register` but actual endpoint is `POST /api/v1/users/register`
552
+ - **Solution:** Changed endpoint path in api.js
553
+ - **Location:** `src/lib/api.js:64`
554
+
555
+ **Issue 5: Deprecated Field Names**
556
+ - **Problem:** CLI still used `gitea_username` and `gitea_api_token`
557
+ - **Solution:** Renamed to `git_username` and `git_api_token` throughout codebase
558
+ - **Affected:** `register.js`, `api.js`, `bin/saac.js`
559
+
560
+ **Issue 6: Truncated API Key Display**
561
+ - **Problem:** Showing truncated API key with "Save this key" message was confusing
562
+ - **Solution:** Show FULL API key in verify command (it's only shown once)
563
+ - **Location:** `src/commands/verify.js:72`
564
+
565
+ **Issue 7: Git Username Auto-Detection**
566
+ - **Finding:** Server auto-populates `git_username` from email address (e.g., `kalle.johansson@goryan.io` → `kalle.johansson`)
567
+ - **Behavior:** This is backend behavior, CLI just displays what server returns
568
+ - **No action needed:** Working as designed
569
+
570
+ ### API Endpoint Reference
571
+
572
+ **Correct Endpoint Paths (v1.4.12):**
573
+ - `POST /api/v1/users/register` - Register (email only, git_username optional)
574
+ - `POST /api/v1/users/verify` - Verify email with code
575
+ - `POST /api/v1/auth/login` - Login with API key, get session token
576
+ - `POST /api/v1/auth/logout` - Logout current session
577
+ - `POST /api/v1/auth/logout-all` - Revoke all sessions
578
+ - `GET /api/v1/auth/sessions` - List all sessions
579
+ - `GET /api/v1/users/me` - Get user info
580
+ - `GET /api/v1/users/me/oauth` - List OAuth connections
581
+ - `DELETE /api/v1/users/me/oauth/:git_host` - Revoke OAuth connection
582
+ - `GET /oauth/authorize` - Initiate OAuth flow (no /api/v1 prefix!)
583
+ - `GET /oauth/poll/:session_id` - Poll OAuth status (no /api/v1 prefix!)
584
+ - `POST /api/v1/applications` - Create application
585
+ - `GET /api/v1/applications` - List applications
586
+ - `PATCH /api/v1/applications/:uuid` - Update application
587
+ - `POST /api/v1/applications/:uuid/deploy` - Deploy application
588
+ - `GET /api/v1/applications/:uuid/logs` - Get logs
589
+ - `DELETE /api/v1/applications/:uuid` - Delete application
590
+
591
+ **Important:** OAuth endpoints (`/oauth/*`) do NOT have the `/api/v1` prefix!
592
+
593
+ ### OAuth Implementation Details
594
+
595
+ **Token Handling:**
596
+ - Session tokens start with `st_`
597
+ - API keys start with `cw_`
598
+ - OAuth helper functions detect token type and use correct header:
599
+ - `st_*` → `X-Session-Token`
600
+ - `cw_*` → `X-API-Key`
601
+
602
+ **Polling Strategy:**
603
+ - Initial 60-second wait before polling starts (gives user time to complete OAuth)
604
+ - Poll every 2 seconds for up to 5 minutes
605
+ - Handles 401/404 errors during polling (expected while user authorizes)
606
+ - Only fails on non-auth errors (500, network errors)
607
+
608
+ **OAuth URL Construction:**
609
+ - Remove `/api/v1` suffix from base URL: `baseUrl.replace('/api/v1', '')`
610
+ - OAuth endpoints: `${baseUrl}/oauth/authorize` and `${baseUrl}/oauth/poll/:id`
611
+
612
+ ### Application Status Values
613
+
614
+ Backend returns these status values (from Coolify):
615
+ - `creating` - Application being created (initial state)
616
+ - `active` - Fully created and operational
617
+ - `running:healthy` - Container running and healthy
618
+ - `running:unknown` - Container running, health status unknown
619
+ - `stopped` - Container stopped
620
+ - `error` - Creation or deployment failed
621
+ - `suspended` - Suspended by admin
622
+
623
+ **CLI Display Logic:**
624
+ ```javascript
625
+ if (status.startsWith('running')) {
626
+ display = 'Running ✓' (green);
627
+ } else if (status.startsWith('stopped')) {
628
+ display = 'Stopped' (yellow);
629
+ } else {
630
+ switch (status) {
631
+ case 'active': display = 'Active ✓' (green);
632
+ case 'creating': display = 'Creating...' (yellow);
633
+ case 'error': display = 'Error ✗' (red);
634
+ case 'suspended': display = 'Suspended ⚠' (yellow);
635
+ }
636
+ }
637
+ ```
638
+
639
+ ### User Registration & Authentication Flow
640
+
641
+ **Complete Flow:**
642
+ 1. `saac register -e user@example.com` → Creates account, sends verification email
643
+ 2. Check MailHog at https://mailhog.goryan.io for verification code
644
+ 3. `saac verify 123456` → Verifies email, returns API key (shown in full, only once)
645
+ 4. `saac login -e user@example.com -k cw_...` → Exchanges API key for 1-year session token
646
+ 5. Session token saved to `~/.config/startanaicompany/config.json`
647
+ 6. All future commands use session token automatically
648
+
649
+ **Note:** User MUST login after verification to get session token. Verification only provides API key.
650
+
651
+ ### Sessions Management Commands
652
+
653
+ **Sessions Command (`saac sessions`):**
654
+ - Lists all active sessions with creation date, last used time, IP address, and expiration
655
+ - Uses table format for clear display
656
+ - Shows total session count
657
+ - Located in `src/commands/sessions.js`
658
+
659
+ **Logout All Command (`saac logout-all`):**
660
+ - Revokes ALL session tokens across all devices
661
+ - Requires confirmation prompt unless `--yes` flag provided
662
+ - Clears local config after successful revocation
663
+ - Shows count of sessions revoked
664
+ - Located in `src/commands/logoutAll.js`
665
+ - **Exception to non-interactive rule:** Uses inquirer for confirmation prompt (but can be skipped with `-y`)
666
+
667
+ **Implementation Notes:**
668
+ - Both commands check authentication before proceeding
669
+ - Handle gracefully if session already expired (401 errors)
670
+ - Clear local config even if server call fails
671
+
672
+ ### Testing Considerations
434
673
 
435
674
  When implementing new commands:
436
675
  1. Test both with flags and interactive prompts
@@ -439,3 +678,32 @@ When implementing new commands:
439
678
  4. Test API error responses
440
679
  5. Ensure proper exit codes (0 for success, 1 for errors)
441
680
  6. Check that spinners succeed/fail appropriately
681
+ 7. **NEVER truncate sensitive data if user needs to save it** (API keys, session tokens)
682
+ 8. Show full values for one-time credentials
683
+
684
+ ### Publishing Checklist
685
+
686
+ Before publishing to npm:
687
+ 1. Verify all new commands work with live backend
688
+ 2. Test OAuth flow end-to-end
689
+ 3. Check syntax: `node -c src/**/*.js bin/*.js`
690
+ 4. Update version in package.json
691
+ 5. Update CLAUDE.md with changes
692
+ 6. Run: `npm publish --access public --otp=<code>`
693
+
694
+ ### Dependencies
695
+
696
+ **Required packages:**
697
+ - `axios` - HTTP client for API calls
698
+ - `chalk` - Terminal colors
699
+ - `commander` - CLI framework
700
+ - `conf` - Configuration management
701
+ - `inquirer` - Interactive prompts
702
+ - `ora` - Spinners
703
+ - `boxen` - Boxed messages
704
+ - `table` - Table display
705
+ - `validator` - Email validation
706
+ - `dotenv` - Environment variables
707
+ - `open` - Open browser for OAuth (v8.4.2 for compatibility with chalk v4)
708
+
709
+ **Version:** 1.4.12 (current)
package/bin/saac.js CHANGED
@@ -28,13 +28,21 @@ const deleteCmd = require('../src/commands/delete');
28
28
  const list = require('../src/commands/list');
29
29
  const status = require('../src/commands/status');
30
30
  const whoami = require('../src/commands/whoami');
31
+ const manual = require('../src/commands/manual');
31
32
 
32
33
  // Configure CLI
33
34
  program
34
35
  .name('saac')
35
36
  .description(chalk.cyan('Official CLI for StartAnAiCompany.com'))
36
37
  .version(pkg.version, '-v, --version', 'Output the current version')
37
- .helpOption('-h, --help', 'Display help for command');
38
+ .helpOption('-h, --help', 'Display help for command')
39
+ .addHelpText('after', `
40
+ ${chalk.dim('For detailed documentation, visit:')}
41
+ ${chalk.cyan('https://github.com/startanaicompany/cli')}
42
+
43
+ ${chalk.dim('Or run:')}
44
+ ${chalk.yellow('saac manual')} ${chalk.dim('- Display full manual from GitHub')}
45
+ `);
38
46
 
39
47
  // Authentication commands
40
48
  program
@@ -235,6 +243,12 @@ program
235
243
  .description('Show current user information')
236
244
  .action(whoami);
237
245
 
246
+ // Documentation
247
+ program
248
+ .command('manual')
249
+ .description('Display full documentation from GitHub')
250
+ .action(manual);
251
+
238
252
  // Deletion
239
253
  program
240
254
  .command('delete')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startanaicompany/cli",
3
- "version": "1.4.10",
3
+ "version": "1.4.12",
4
4
  "description": "Official CLI for StartAnAiCompany.com - Deploy AI recruitment sites with ease",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -36,7 +36,7 @@ async function connect(host) {
36
36
  name: 'choice',
37
37
  message: 'Select Git provider:',
38
38
  choices: [
39
- { name: 'git.startanaicompany.com (Gitea)', value: 'git.startanaicompany.com' },
39
+ { name: 'git.startanaicompany.com (Git StartanAICompany)', value: 'git.startanaicompany.com' },
40
40
  { name: 'github.com', value: 'github.com' },
41
41
  { name: 'gitlab.com', value: 'gitlab.com' },
42
42
  { name: 'Custom host', value: 'custom' },
@@ -95,13 +95,13 @@ async function connect(host) {
95
95
  }
96
96
 
97
97
  // Initiate OAuth flow
98
- await oauth.connectGitAccount(gitHost, user.sessionToken || user.apiKey);
98
+ const result = await oauth.connectGitAccount(gitHost, user.sessionToken || user.apiKey);
99
99
 
100
100
  logger.newline();
101
101
  logger.success('Git account connected successfully!');
102
102
  logger.newline();
103
103
  logger.info('You can now create applications without providing --git-token:');
104
- logger.log(` saac create my-app -s myapp -r git@${gitHost}:user/repo.git`);
104
+ logger.log(` saac create my-app -s myapp -r git@${gitHost}:${result.gitUsername}/repo.git`);
105
105
 
106
106
  } catch (error) {
107
107
  logger.error(error.message);
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Manual command - Display full documentation from GitHub
3
+ */
4
+
5
+ const axios = require('axios');
6
+ const logger = require('../lib/logger');
7
+
8
+ async function manual() {
9
+ try {
10
+ logger.section('SAAC CLI Manual');
11
+ logger.newline();
12
+
13
+ const spin = logger.spinner('Fetching documentation from GitHub...').start();
14
+
15
+ try {
16
+ // Fetch README from GitHub
17
+ const response = await axios.get(
18
+ 'https://raw.githubusercontent.com/startanaicompany/cli/master/README.md',
19
+ { timeout: 10000 }
20
+ );
21
+
22
+ spin.succeed('Documentation loaded');
23
+ logger.newline();
24
+
25
+ // Display the README content
26
+ console.log(response.data);
27
+
28
+ logger.newline();
29
+ logger.info('Online documentation: https://github.com/startanaicompany/cli');
30
+
31
+ } catch (error) {
32
+ spin.fail('Failed to fetch documentation');
33
+
34
+ logger.newline();
35
+ logger.error('Could not fetch README from GitHub');
36
+ logger.newline();
37
+ logger.info('Visit the documentation online:');
38
+ logger.log(' https://github.com/startanaicompany/cli');
39
+ logger.newline();
40
+ logger.info('Or run:');
41
+ logger.log(' saac --help');
42
+
43
+ process.exit(1);
44
+ }
45
+ } catch (error) {
46
+ logger.error(error.message);
47
+ process.exit(1);
48
+ }
49
+ }
50
+
51
+ module.exports = manual;
@@ -66,11 +66,18 @@ async function status() {
66
66
 
67
67
  // Show account info
68
68
  logger.field('User ID', userData.id);
69
- if (userData.git_username) {
70
- logger.field('Git Username', userData.git_username);
69
+
70
+ // Show OAuth connections
71
+ if (userData.git_connections && userData.git_connections.length > 0) {
72
+ // Show all OAuth connections
73
+ userData.git_connections.forEach((conn, index) => {
74
+ const label = index === 0 ? 'Git Connection' : ' '; // Align subsequent connections
75
+ logger.field(label, `${conn.gitUsername} @ ${conn.gitHost}`);
76
+ });
71
77
  } else {
72
- logger.field('Git Connection', 'Not connected (use OAuth to connect)');
78
+ logger.field('Git Connection', 'Not connected (use: saac git connect)');
73
79
  }
80
+
74
81
  logger.field('Applications', `${userData.application_count} / ${userData.max_applications}`);
75
82
 
76
83
  logger.newline();