@startanaicompany/crm 1.0.1 → 1.0.2
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 +59 -25
- package/index.js +16 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,44 +8,61 @@ 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
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🤖 AI Agent Quick Start (zero-auth, no human needed)
|
|
14
|
+
|
|
15
|
+
Agents bootstrap themselves with a single command — **no credentials required**:
|
|
12
16
|
|
|
13
17
|
```bash
|
|
14
|
-
# 1
|
|
18
|
+
# Step 1: create your own API key (no auth needed)
|
|
15
19
|
saac_crm config set --url https://your-crm.example.com
|
|
20
|
+
saac_crm keys create --name my-agent
|
|
21
|
+
# → returns crm_xxxxxxxxxxxx — store this as your API key
|
|
16
22
|
|
|
17
|
-
# 2
|
|
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
|
|
23
|
+
# Step 2: set the key and start managing leads
|
|
24
24
|
export SAAC_CRM_API_KEY=crm_xxxxxxxxxxxx
|
|
25
|
+
saac_crm leads create --name "Jane Smith" --email "jane@example.com"
|
|
26
|
+
saac_crm leads list
|
|
25
27
|
```
|
|
26
28
|
|
|
27
29
|
> **Auth priority**: `--api-key` flag > `SAAC_CRM_API_KEY` env var > config file (`~/.saac_crm/config.json`)
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
> ⚠️ **Agents: never call `saac_crm register`** — that command is for one-time operator setup only (requires deployment password). Your entry point is always `keys create --name`.
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 👤 Operator Setup (one-time, human)
|
|
36
|
+
|
|
37
|
+
This is done once per deployment — **not by agents**:
|
|
32
38
|
|
|
33
39
|
```bash
|
|
34
|
-
#
|
|
35
|
-
saac_crm
|
|
40
|
+
# 1. Point at your deployment
|
|
41
|
+
saac_crm config set --url https://your-crm.example.com
|
|
36
42
|
|
|
37
|
-
#
|
|
38
|
-
|
|
43
|
+
# 2. Register workspace + create admin key (prompts for workspace slug and password)
|
|
44
|
+
saac_crm register --name "main-admin-key"
|
|
45
|
+
# → prompts: Workspace slug (e.g. mycompany):
|
|
46
|
+
# → prompts: Deployment admin password:
|
|
47
|
+
# → returns crm_xxx admin key — store securely
|
|
48
|
+
|
|
49
|
+
# 3. Save admin key and create first human user account
|
|
50
|
+
saac_crm config set --api-key crm_xxx_admin_key
|
|
51
|
+
saac_crm users create --email admin@example.com --name "Admin" --role admin
|
|
39
52
|
```
|
|
40
53
|
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Commands
|
|
57
|
+
|
|
41
58
|
### API Keys
|
|
42
59
|
|
|
43
60
|
```bash
|
|
44
|
-
# Create
|
|
61
|
+
# Create agent key — ZERO AUTH, no prior setup needed
|
|
45
62
|
saac_crm keys create --name "my-agent"
|
|
46
63
|
|
|
47
|
-
# Create
|
|
48
|
-
saac_crm keys create --name "admin-
|
|
64
|
+
# Create admin scope key (operator only — requires deployment password + workspace slug)
|
|
65
|
+
saac_crm keys create --name "admin-key" --scope admin \
|
|
49
66
|
--workspace mycompany --admin-password <deployment-password>
|
|
50
67
|
|
|
51
68
|
# List all keys (metadata only — full key never shown again)
|
|
@@ -83,7 +100,8 @@ saac_crm leads history <id>
|
|
|
83
100
|
### Users (requires admin scope key)
|
|
84
101
|
|
|
85
102
|
```bash
|
|
86
|
-
# Create a human user account
|
|
103
|
+
# Create a human user account (both commands are equivalent)
|
|
104
|
+
saac_crm users create --email admin@example.com --name "Admin User" --role admin
|
|
87
105
|
saac_crm users register --email admin@example.com --name "Admin User" --role admin
|
|
88
106
|
|
|
89
107
|
# List users
|
|
@@ -96,6 +114,23 @@ saac_crm users update <id> --role viewer
|
|
|
96
114
|
saac_crm users deactivate <id>
|
|
97
115
|
```
|
|
98
116
|
|
|
117
|
+
### Human Login
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Log in as admin/viewer — saves JWT to config for dashboard access
|
|
121
|
+
saac_crm login --workspace mycompany --email admin@example.com
|
|
122
|
+
# → prompts for password, saves JWT to ~/.saac_crm/config.json
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Workspace Registration (operator only)
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# First-time setup — registers workspace slug + creates admin key
|
|
129
|
+
# Prompts for --workspace and --admin-password if not provided
|
|
130
|
+
saac_crm register --name "main-admin-key"
|
|
131
|
+
saac_crm register --name "main-admin-key" --workspace mycompany --admin-password <pw>
|
|
132
|
+
```
|
|
133
|
+
|
|
99
134
|
### Configuration
|
|
100
135
|
|
|
101
136
|
```bash
|
|
@@ -111,11 +146,10 @@ saac_crm config get
|
|
|
111
146
|
--url <url> Override API base URL for this command
|
|
112
147
|
```
|
|
113
148
|
|
|
114
|
-
##
|
|
149
|
+
## Architecture
|
|
115
150
|
|
|
116
|
-
|
|
117
|
-
1. **Workspace slug** (e.g. `mycompany`)
|
|
118
|
-
2. **Email**
|
|
119
|
-
3. **Password**
|
|
151
|
+
This is a **single-tenant** system: one workspace slug per deployment, registered once by an operator.
|
|
120
152
|
|
|
121
|
-
|
|
153
|
+
- **Agents** → self-service `keys create` → manage leads
|
|
154
|
+
- **Operators** → `register` once → `users create` → human accounts
|
|
155
|
+
- **Humans** → `login` → web dashboard at your deployment URL
|
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.2')
|
|
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
|
|
|
@@ -115,9 +115,14 @@ configCmd
|
|
|
115
115
|
.option('--url <url>', 'CRM API base URL (e.g. https://yourapp.example.com)')
|
|
116
116
|
.option('--api-key <key>', 'Default API key to use')
|
|
117
117
|
.action((opts) => {
|
|
118
|
+
// NOTE: commander.js may consume --url and --api-key at the parent program level
|
|
119
|
+
// if they share the same option names. Always fall back to program.opts().
|
|
120
|
+
const globalOpts = program.opts();
|
|
118
121
|
const cfg = loadConfig();
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
const urlValue = opts.url || globalOpts.url;
|
|
123
|
+
const apiKeyValue = opts.apiKey || globalOpts.apiKey;
|
|
124
|
+
if (urlValue) cfg.apiUrl = urlValue;
|
|
125
|
+
if (apiKeyValue) cfg.apiKey = apiKeyValue;
|
|
121
126
|
saveConfig(cfg);
|
|
122
127
|
console.log('Configuration saved to', CONFIG_FILE);
|
|
123
128
|
printJSON(cfg);
|
|
@@ -317,7 +322,7 @@ leadsCmd
|
|
|
317
322
|
};
|
|
318
323
|
try {
|
|
319
324
|
const res = await client.post('/leads', body, { headers });
|
|
320
|
-
printJSON(res.data
|
|
325
|
+
printJSON(res.data);
|
|
321
326
|
} catch (err) {
|
|
322
327
|
handleError(err);
|
|
323
328
|
}
|
|
@@ -330,15 +335,20 @@ leadsCmd
|
|
|
330
335
|
.option('--email <email>', 'Filter by email (partial match)')
|
|
331
336
|
.option('--company <company>', 'Filter by company (partial match)')
|
|
332
337
|
.option('--tag <tag>', 'Filter by tag — repeatable, AND logic', (v, prev) => prev.concat([v]), [])
|
|
338
|
+
.option('--api-key-id <id>', 'Filter by the API key ID that created the lead')
|
|
339
|
+
.option('--self', 'Filter leads created by the current API key (shorthand for --api-key-id self)')
|
|
333
340
|
.option('--page <n>', 'Page number', '1')
|
|
334
341
|
.option('--per-page <n>', 'Results per page', '20')
|
|
335
342
|
.action(async (opts) => {
|
|
336
343
|
const globalOpts = program.opts();
|
|
337
344
|
const client = getClient(globalOpts);
|
|
345
|
+
// --self is a shorthand for --api-key-id self
|
|
346
|
+
const apiKeyIdFilter = opts.self ? 'self' : opts.apiKeyId;
|
|
338
347
|
const params = {
|
|
339
348
|
...(opts.status && { status: opts.status }),
|
|
340
349
|
...(opts.email && { email: opts.email }),
|
|
341
350
|
...(opts.company && { company: opts.company }),
|
|
351
|
+
...(apiKeyIdFilter && { api_key_id: apiKeyIdFilter }),
|
|
342
352
|
page: opts.page,
|
|
343
353
|
per_page: opts.perPage
|
|
344
354
|
};
|
|
@@ -361,7 +371,7 @@ leadsCmd
|
|
|
361
371
|
const client = getClient(globalOpts);
|
|
362
372
|
try {
|
|
363
373
|
const res = await client.get(`/leads/${id}`);
|
|
364
|
-
printJSON(res.data
|
|
374
|
+
printJSON(res.data);
|
|
365
375
|
} catch (err) {
|
|
366
376
|
handleError(err);
|
|
367
377
|
}
|
|
@@ -399,7 +409,7 @@ leadsCmd
|
|
|
399
409
|
};
|
|
400
410
|
try {
|
|
401
411
|
const res = await client.put(`/leads/${id}`, body);
|
|
402
|
-
printJSON(res.data
|
|
412
|
+
printJSON(res.data);
|
|
403
413
|
} catch (err) {
|
|
404
414
|
handleError(err);
|
|
405
415
|
}
|