@startanaicompany/crm 1.0.0 → 1.0.1

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.
Files changed (3) hide show
  1. package/README.md +54 -11
  2. package/index.js +89 -29
  3. package/package.json +15 -2
package/README.md CHANGED
@@ -8,34 +8,53 @@ AI-first CRM CLI (`saac_crm`) — manage leads, API keys, and user accounts from
8
8
  npm install -g @startanaicompany/crm
9
9
  ```
10
10
 
11
- ## Configuration
11
+ ## First-Time Setup
12
12
 
13
13
  ```bash
14
- # Set API URL and default key
15
- saac_crm config set --url https://yourapp.example.com --api-key crm_xxxx
14
+ # 1. Point at your CRM deployment
15
+ saac_crm config set --url https://your-crm.example.com
16
16
 
17
- # Auth priority: --api-key flag > SAAC_CRM_API_KEY env > config file
18
- export SAAC_CRM_API_KEY=crm_xxxx
17
+ # 2. Register your workspace and create the first admin key
18
+ # (prompts for deployment admin password)
19
+ saac_crm register --workspace mycompany --name "main-admin-key"
20
+
21
+ # 3. Save the returned key as default (or use SAAC_CRM_API_KEY env)
22
+ saac_crm config set --api-key crm_xxxxxxxxxxxx
23
+ # OR
24
+ export SAAC_CRM_API_KEY=crm_xxxxxxxxxxxx
19
25
  ```
20
26
 
27
+ > **Auth priority**: `--api-key` flag > `SAAC_CRM_API_KEY` env var > config file (`~/.saac_crm/config.json`)
28
+
21
29
  ## Commands
22
30
 
31
+ ### Workspace Registration
32
+
33
+ ```bash
34
+ # Register workspace + create first admin key (all-in-one)
35
+ saac_crm register --workspace mycompany --name "admin-key"
36
+
37
+ # Check current workspace slug (public — no auth needed)
38
+ curl https://your-crm.example.com/api/v1/workspace
39
+ ```
40
+
23
41
  ### API Keys
24
42
 
25
43
  ```bash
26
44
  # Create an agent key (no auth required)
27
45
  saac_crm keys create --name "my-agent"
28
46
 
29
- # Create an admin scope key (requires deployment password)
30
- saac_crm keys create --name "admin-agent" --scope admin --admin-password <password>
47
+ # Create an admin scope key (requires deployment password + workspace slug)
48
+ saac_crm keys create --name "admin-agent" --scope admin \
49
+ --workspace mycompany --admin-password <deployment-password>
31
50
 
32
- # List all keys
51
+ # List all keys (metadata only — full key never shown again)
33
52
  saac_crm keys list
34
53
 
35
54
  # Show current key info
36
55
  saac_crm keys self
37
56
 
38
- # Revoke a key
57
+ # Revoke a key by ID
39
58
  saac_crm keys revoke <id>
40
59
  ```
41
60
 
@@ -54,10 +73,10 @@ saac_crm leads get <id>
54
73
  # Update lead
55
74
  saac_crm leads update <id> --status contacted --notes "Called, interested"
56
75
 
57
- # Delete lead (soft)
76
+ # Soft-delete lead
58
77
  saac_crm leads delete <id>
59
78
 
60
- # Status history
79
+ # Status change history
61
80
  saac_crm leads history <id>
62
81
  ```
63
82
 
@@ -76,3 +95,27 @@ saac_crm users update <id> --role viewer
76
95
  # Deactivate user
77
96
  saac_crm users deactivate <id>
78
97
  ```
98
+
99
+ ### Configuration
100
+
101
+ ```bash
102
+ saac_crm config set --url https://your-crm.example.com
103
+ saac_crm config set --api-key crm_xxxxxxxxxxxx
104
+ saac_crm config get
105
+ ```
106
+
107
+ ## Global Options
108
+
109
+ ```
110
+ --api-key <key> Override API key for this command
111
+ --url <url> Override API base URL for this command
112
+ ```
113
+
114
+ ## Human Login
115
+
116
+ Humans log in via the web UI at the deployment URL. Login requires:
117
+ 1. **Workspace slug** (e.g. `mycompany`)
118
+ 2. **Email**
119
+ 3. **Password**
120
+
121
+ User accounts are created by an AI agent using an admin scope key via `saac_crm users register`.
package/index.js CHANGED
@@ -99,7 +99,7 @@ const program = new Command();
99
99
  program
100
100
  .name('saac_crm')
101
101
  .description('AI-first CRM CLI — manage leads and API keys')
102
- .version('1.0.0')
102
+ .version('1.0.1')
103
103
  .option('--api-key <key>', 'API key (overrides SAAC_CRM_API_KEY env and config)')
104
104
  .option('--url <url>', 'API base URL (overrides config)');
105
105
 
@@ -185,15 +185,15 @@ keysCmd
185
185
  });
186
186
 
187
187
  // ============================================================
188
- // REGISTER — shortcut for first admin setup
188
+ // REGISTER — first-time workspace + admin key setup
189
+ // NOTE: For agent self-service (zero-auth), use: saac_crm keys create --name <name>
189
190
  // ============================================================
190
191
 
191
192
  program
192
193
  .command('register')
193
- .description('Register this workspace and create an admin scope API key')
194
- .requiredOption('--workspace <slug>', 'Workspace slug (3-30 chars, a-z0-9 only, e.g. goldenrecruit101)')
194
+ .description('First-time setup: register workspace slug and create admin scope API key (prompts for missing values)')
195
195
  .requiredOption('--name <name>', 'Name/label for this admin key')
196
- .option('--scope <scope>', 'Key scope (must be admin)', 'admin')
196
+ .option('--workspace <slug>', 'Workspace slug (3-30 chars, a-z0-9 only, e.g. mycompany)')
197
197
  .option('--admin-password <password>', 'Deployment admin password (will prompt if not provided)')
198
198
  .action(async (opts) => {
199
199
  const globalOpts = program.opts();
@@ -203,6 +203,13 @@ program
203
203
  process.exit(1);
204
204
  }
205
205
 
206
+ // Prompt for workspace slug if not provided
207
+ let workspace = opts.workspace;
208
+ if (!workspace) {
209
+ workspace = await promptSecret('Workspace slug (e.g. mycompany): ');
210
+ }
211
+
212
+ // Prompt for admin password if not provided
206
213
  let adminPw = opts.adminPassword;
207
214
  if (!adminPw) {
208
215
  adminPw = await promptSecret('Deployment admin password: ');
@@ -211,7 +218,7 @@ program
211
218
  const body = {
212
219
  name: opts.name,
213
220
  scope: 'admin',
214
- workspace: opts.workspace,
221
+ workspace: workspace.trim().toLowerCase(),
215
222
  admin_password: adminPw
216
223
  };
217
224
 
@@ -221,7 +228,7 @@ program
221
228
  body,
222
229
  { headers: { 'Content-Type': 'application/json' } }
223
230
  );
224
- console.log(`Workspace '${opts.workspace}' registered. Admin key created — store it securely.`);
231
+ console.log(`Workspace '${workspace}' registered. Admin key created — store it securely.`);
225
232
  printJSON(res.data.data);
226
233
  } catch (err) {
227
234
  handleError(err);
@@ -433,35 +440,47 @@ leadsCmd
433
440
 
434
441
  const usersCmd = program.command('users').description('Manage human user accounts (requires admin scope key)');
435
442
 
443
+ // Shared action for users create / users register
444
+ async function createUserAction(opts) {
445
+ const globalOpts = program.opts();
446
+ const client = getClient(globalOpts);
447
+
448
+ let password = opts.password;
449
+ if (!password) {
450
+ password = await promptSecret('Password for new user: ');
451
+ }
452
+
453
+ try {
454
+ const res = await client.post('/users', {
455
+ email: opts.email,
456
+ name: opts.name,
457
+ password,
458
+ role: opts.role
459
+ });
460
+ console.log('User created successfully.');
461
+ printJSON(res.data.data);
462
+ } catch (err) {
463
+ handleError(err);
464
+ }
465
+ }
466
+
436
467
  usersCmd
437
- .command('register')
468
+ .command('create')
438
469
  .description('Create a new human user account')
439
470
  .requiredOption('--email <email>', 'User email address')
440
471
  .requiredOption('--name <name>', 'User full name')
441
472
  .option('--password <password>', 'User password (will prompt if not provided)')
442
473
  .option('--role <role>', 'Role: admin or viewer', 'viewer')
443
- .action(async (opts) => {
444
- const globalOpts = program.opts();
445
- const client = getClient(globalOpts);
474
+ .action(createUserAction);
446
475
 
447
- let password = opts.password;
448
- if (!password) {
449
- password = await promptSecret('Password for new user: ');
450
- }
451
-
452
- try {
453
- const res = await client.post('/users', {
454
- email: opts.email,
455
- name: opts.name,
456
- password,
457
- role: opts.role
458
- });
459
- console.log('User created successfully.');
460
- printJSON(res.data.data);
461
- } catch (err) {
462
- handleError(err);
463
- }
464
- });
476
+ usersCmd
477
+ .command('register')
478
+ .description('Create a new human user account (alias for users create)')
479
+ .requiredOption('--email <email>', 'User email address')
480
+ .requiredOption('--name <name>', 'User full name')
481
+ .option('--password <password>', 'User password (will prompt if not provided)')
482
+ .option('--role <role>', 'Role: admin or viewer', 'viewer')
483
+ .action(createUserAction);
465
484
 
466
485
  usersCmd
467
486
  .command('list')
@@ -518,4 +537,45 @@ usersCmd
518
537
  }
519
538
  });
520
539
 
540
+ // ============================================================
541
+ // LOGIN — human admin/viewer login, saves JWT to config
542
+ // ============================================================
543
+
544
+ program
545
+ .command('login')
546
+ .description('Log in as a human admin/viewer (workspace + email + password → JWT saved to config)')
547
+ .requiredOption('--workspace <slug>', 'Workspace slug')
548
+ .requiredOption('--email <email>', 'Your email address')
549
+ .option('--password <password>', 'Your password (will prompt if not provided)')
550
+ .action(async (opts) => {
551
+ const globalOpts = program.opts();
552
+ const apiUrl = resolveApiUrl(globalOpts.url);
553
+ if (!apiUrl) {
554
+ console.error('Error: API URL not configured. Run: saac_crm config set --url <api-url>');
555
+ process.exit(1);
556
+ }
557
+
558
+ let password = opts.password;
559
+ if (!password) {
560
+ password = await promptSecret('Password: ');
561
+ }
562
+
563
+ try {
564
+ const res = await axios.post(
565
+ `${apiUrl.replace(/\/$/, '')}/api/v1/auth/login`,
566
+ { workspace: opts.workspace, email: opts.email, password },
567
+ { headers: { 'Content-Type': 'application/json' } }
568
+ );
569
+ const { token, user } = res.data.data;
570
+ // Save token to config for subsequent admin operations
571
+ const cfg = loadConfig();
572
+ cfg.token = token;
573
+ saveConfig(cfg);
574
+ console.log(`Logged in as ${user.email} (${user.role}). JWT saved to config.`);
575
+ printJSON({ email: user.email, name: user.name, role: user.role });
576
+ } catch (err) {
577
+ handleError(err);
578
+ }
579
+ });
580
+
521
581
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startanaicompany/crm",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "AI-first CRM CLI — manage leads and API keys from the terminal",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -9,8 +9,21 @@
9
9
  "scripts": {
10
10
  "test": "echo \"No tests yet\""
11
11
  },
12
- "keywords": ["crm", "ai", "leads", "api"],
12
+ "keywords": ["crm", "ai", "leads", "api", "saac", "agent"],
13
13
  "license": "MIT",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://git.startanaicompany.com/mikaelwestoo/url-friendly-slug-59b2ag.git",
17
+ "directory": "packages/crm-cli"
18
+ },
19
+ "files": [
20
+ "index.js",
21
+ "README.md",
22
+ "package.json"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
14
27
  "dependencies": {
15
28
  "axios": "^1.6.0",
16
29
  "commander": "^11.1.0"