@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.
- package/README.md +54 -11
- package/index.js +89 -29
- 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
|
-
##
|
|
11
|
+
## First-Time Setup
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
#
|
|
15
|
-
saac_crm config set --url https://
|
|
14
|
+
# 1. Point at your CRM deployment
|
|
15
|
+
saac_crm config set --url https://your-crm.example.com
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
|
|
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
|
|
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
|
-
#
|
|
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.
|
|
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 —
|
|
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('
|
|
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('--
|
|
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:
|
|
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 '${
|
|
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('
|
|
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(
|
|
444
|
-
const globalOpts = program.opts();
|
|
445
|
-
const client = getClient(globalOpts);
|
|
474
|
+
.action(createUserAction);
|
|
446
475
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
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.
|
|
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"
|