close-crm-cli 0.1.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/AGENTS.md ADDED
@@ -0,0 +1,566 @@
1
+ # AI Agent Guide — Close CRM CLI
2
+
3
+ > This file helps AI agents (Claude, GPT, Gemini, open-source models) install, authenticate, and use the Close CRM CLI to manage leads, contacts, opportunities, activities, pipelines, sequences, and the full Close CRM API.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install globally
9
+ npm install -g close-crm-cli
10
+
11
+ # Authenticate (non-interactive — best for agents)
12
+ export CLOSE_API_KEY="your-api-key-here"
13
+
14
+ # Verify it works
15
+ close users me
16
+ ```
17
+
18
+ **Requirements:** Node.js 18+
19
+
20
+ ## Authentication
21
+
22
+ Close CRM uses API key auth (HTTP Basic Auth under the hood). Provide your key via:
23
+
24
+ ```bash
25
+ # 1. Environment variable (recommended for agents)
26
+ export CLOSE_API_KEY="your-api-key-here"
27
+
28
+ # 2. Per-command flag
29
+ close leads list --api-key "your-api-key-here"
30
+
31
+ # 3. Interactive login (stores in ~/.close/config.json)
32
+ close login
33
+ ```
34
+
35
+ Get your API key: https://app.close.com/settings/api
36
+
37
+ ## Output Format
38
+
39
+ All commands output **JSON to stdout** by default:
40
+
41
+ ```bash
42
+ # Default: compact JSON
43
+ close leads list
44
+
45
+ # Pretty-printed JSON
46
+ close leads list --pretty
47
+
48
+ # Select specific fields
49
+ close leads list --fields id,display_name,status_label
50
+
51
+ # Suppress output (exit code only)
52
+ close leads list --quiet
53
+ ```
54
+
55
+ **Exit codes:** 0 = success, 1 = error. Errors go to stderr as JSON:
56
+ ```json
57
+ {"error":"No API key found.","code":"AUTH_ERROR"}
58
+ ```
59
+
60
+ ## Discovering Commands
61
+
62
+ ```bash
63
+ # List all command groups
64
+ close --help
65
+
66
+ # List subcommands in a group
67
+ close leads --help
68
+
69
+ # Get help for a specific subcommand
70
+ close leads create --help
71
+ ```
72
+
73
+ ## All Command Groups & Subcommands
74
+
75
+ ### leads
76
+ Manage CRM leads (companies/prospects).
77
+ ```
78
+ list List leads (with query support)
79
+ get Get a lead by ID
80
+ create Create a new lead (with optional contacts/opportunities)
81
+ update Update a lead
82
+ delete Delete a lead
83
+ merge Merge two leads (source → destination)
84
+ search Advanced search using Close query DSL
85
+ ```
86
+
87
+ ### contacts
88
+ Manage contacts (people) within leads.
89
+ ```
90
+ list List contacts (filter by --lead-id)
91
+ get Get a contact by ID
92
+ create Create a contact on a lead
93
+ update Update a contact
94
+ delete Delete a contact
95
+ ```
96
+
97
+ ### opportunities
98
+ Manage sales opportunities in pipelines.
99
+ ```
100
+ list List opportunities (filter by lead, pipeline, status, user)
101
+ get Get an opportunity by ID
102
+ create Create an opportunity on a lead
103
+ update Update an opportunity (move stages, update value, set close date)
104
+ delete Delete an opportunity
105
+ ```
106
+
107
+ ### tasks
108
+ Manage tasks and follow-ups.
109
+ ```
110
+ list List tasks (filter by lead, assignee, type, completion)
111
+ get Get a task by ID
112
+ create Create a task on a lead
113
+ update Update a task
114
+ delete Delete a task
115
+ bulk-update Bulk update tasks (e.g. mark multiple complete)
116
+ ```
117
+
118
+ ### activities
119
+ Unified activity stream.
120
+ ```
121
+ list List all activity types (Call, Email, Note, SMS, Meeting, etc.)
122
+ ```
123
+
124
+ ### calls
125
+ Log and manage call activities.
126
+ ```
127
+ list List call activities
128
+ get Get a call by ID
129
+ create Log a call
130
+ update Update a call
131
+ delete Delete a call
132
+ ```
133
+
134
+ ### notes
135
+ Manage note activities.
136
+ ```
137
+ list List notes
138
+ get Get a note by ID
139
+ create Create a note on a lead
140
+ update Update a note
141
+ delete Delete a note
142
+ ```
143
+
144
+ ### emails
145
+ Manage email activities (send/log emails).
146
+ ```
147
+ list List email activities
148
+ get Get an email by ID
149
+ create Send or log an email
150
+ update Update an email
151
+ delete Delete an email
152
+ ```
153
+
154
+ ### sms
155
+ Manage SMS activities.
156
+ ```
157
+ list List SMS activities
158
+ get Get an SMS by ID
159
+ create Send or log an SMS
160
+ delete Delete an SMS
161
+ ```
162
+
163
+ ### meetings
164
+ Manage meeting activities.
165
+ ```
166
+ list List meetings
167
+ get Get a meeting by ID
168
+ update Update a meeting
169
+ delete Delete a meeting
170
+ ```
171
+
172
+ ### users
173
+ Manage users.
174
+ ```
175
+ me Get current authenticated user
176
+ list List all users
177
+ get Get a user by ID
178
+ availability Get dialer availability status for all users
179
+ ```
180
+
181
+ ### pipelines
182
+ Manage sales pipelines.
183
+ ```
184
+ list List pipelines
185
+ get Get a pipeline by ID
186
+ create Create a pipeline
187
+ update Update a pipeline
188
+ delete Delete a pipeline
189
+ ```
190
+
191
+ ### lead-statuses
192
+ Manage lead status labels.
193
+ ```
194
+ list List lead statuses
195
+ get Get a lead status by ID
196
+ create Create a lead status
197
+ update Update a lead status
198
+ delete Delete a lead status
199
+ ```
200
+
201
+ ### opportunity-statuses
202
+ Manage opportunity status stages.
203
+ ```
204
+ list List opportunity statuses
205
+ get Get an opportunity status by ID
206
+ create Create an opportunity status (tied to a pipeline)
207
+ update Update an opportunity status
208
+ delete Delete an opportunity status
209
+ ```
210
+
211
+ ### custom-fields
212
+ Manage custom fields for all object types.
213
+ ```
214
+ list-lead List custom fields for leads
215
+ get-lead Get a lead custom field by ID
216
+ create-lead Create a lead custom field
217
+ update-lead Update a lead custom field
218
+ delete-lead Delete a lead custom field
219
+
220
+ list-contact (same pattern for contact)
221
+ get-contact
222
+ create-contact
223
+ update-contact
224
+ delete-contact
225
+
226
+ list-opportunity (same for opportunity)
227
+ get-opportunity
228
+ create-opportunity
229
+ update-opportunity
230
+ delete-opportunity
231
+
232
+ list-activity (same for activity)
233
+ get-activity
234
+ create-activity
235
+ update-activity
236
+ delete-activity
237
+
238
+ list-shared (same for shared fields)
239
+ get-shared
240
+ create-shared
241
+ update-shared
242
+ delete-shared
243
+ ```
244
+
245
+ ### webhooks
246
+ Subscribe to real-time events.
247
+ ```
248
+ list List webhook subscriptions
249
+ get Get a webhook by ID
250
+ create Create a webhook (specify events array)
251
+ update Update a webhook
252
+ delete Delete a webhook
253
+ ```
254
+
255
+ **Available webhook events:** `created.lead`, `updated.lead`, `deleted.lead`, `created.contact`, `updated.contact`, `deleted.contact`, `created.opportunity`, `updated.opportunity`, `deleted.opportunity`, `created.note`, `created.call`, `completed.call`, `created.email`, `created.sms`, `created.task`, `completed.task`
256
+
257
+ ### sequences
258
+ Manage automated outreach sequences.
259
+ ```
260
+ list List sequences
261
+ get Get a sequence by ID
262
+ create Create a sequence
263
+ update Update a sequence
264
+ delete Delete a sequence
265
+ subscribe Subscribe a contact to a sequence
266
+ list-subscriptions List sequence subscriptions
267
+ ```
268
+
269
+ ### email-templates
270
+ Manage reusable email templates.
271
+ ```
272
+ list List email templates
273
+ get Get a template by ID
274
+ create Create an email template
275
+ update Update a template
276
+ delete Delete a template
277
+ render Render a template with lead/contact variable substitution
278
+ ```
279
+
280
+ ### sms-templates
281
+ Manage SMS templates.
282
+ ```
283
+ list List SMS templates
284
+ get Get a template by ID
285
+ create Create an SMS template
286
+ update Update a template
287
+ delete Delete a template
288
+ ```
289
+
290
+ ### smart-views
291
+ Manage smart views (saved filtered views).
292
+ ```
293
+ list List smart views
294
+ get Get a smart view by ID
295
+ create Create a smart view
296
+ update Update a smart view
297
+ delete Delete a smart view
298
+ ```
299
+
300
+ ### reports
301
+ Sales analytics and reporting.
302
+ ```
303
+ activity-metrics Get activity metrics for a date range
304
+ activity-report Get detailed activity report (POST)
305
+ funnel Get pipeline funnel totals
306
+ ```
307
+
308
+ ### phone-numbers
309
+ Manage provisioned phone numbers.
310
+ ```
311
+ list List phone numbers
312
+ get Get a phone number by ID
313
+ update Update a phone number
314
+ delete Delete a phone number
315
+ ```
316
+
317
+ ### connected-accounts
318
+ Manage connected email accounts.
319
+ ```
320
+ list List connected accounts
321
+ get Get a connected account by ID
322
+ ```
323
+
324
+ ### organizations
325
+ Manage the organization (top-level account).
326
+ ```
327
+ get Get organization by ID
328
+ update Update organization settings
329
+ ```
330
+
331
+ ### groups
332
+ Manage user groups (teams).
333
+ ```
334
+ list List groups
335
+ get Get a group by ID
336
+ create Create a group
337
+ update Update a group
338
+ delete Delete a group
339
+ ```
340
+
341
+ ### roles
342
+ Manage user roles.
343
+ ```
344
+ list List roles
345
+ get Get a role by ID
346
+ ```
347
+
348
+ ### exports
349
+ Async data exports.
350
+ ```
351
+ list List exports
352
+ get Get export status and download URL
353
+ create-lead Start a lead export
354
+ create-opportunity Start an opportunity export
355
+ ```
356
+
357
+ ### unsubscribe
358
+ Manage email unsubscribe list.
359
+ ```
360
+ list List unsubscribed emails
361
+ add Add an email to the unsubscribe list
362
+ delete Remove an email from the unsubscribe list
363
+ ```
364
+
365
+ ---
366
+
367
+ ## Common Workflows for Agents
368
+
369
+ ### Create and qualify a lead
370
+ ```bash
371
+ # 1. Create the lead
372
+ close leads create --name "Acme Corp" --url "https://acme.com"
373
+ # → {"id":"lead_abc123","display_name":"Acme Corp",...}
374
+
375
+ # 2. Add a contact
376
+ close contacts create --lead-id lead_abc123 --name "Jane Doe" \
377
+ --emails '[{"email":"jane@acme.com","type":"office"}]' \
378
+ --phones '[{"phone":"+14155551234","type":"mobile"}]'
379
+
380
+ # 3. Create an opportunity
381
+ close opportunities create --lead-id lead_abc123 \
382
+ --note "Enterprise deal" --value 50000 --value-period one_time \
383
+ --confidence 40 --close-date "2025-06-30"
384
+
385
+ # 4. Add a note
386
+ close notes create --lead-id lead_abc123 --note "Intro call went well, demo scheduled"
387
+ ```
388
+
389
+ ### Log a call and create follow-up task
390
+ ```bash
391
+ # Log the call
392
+ close calls create --lead-id lead_abc123 --direction outbound \
393
+ --duration 1800 --note "Discussed pricing and timeline"
394
+
395
+ # Create follow-up task
396
+ close tasks create --lead-id lead_abc123 \
397
+ --text "Send proposal" --type email \
398
+ --due-date "2025-04-07T09:00:00"
399
+ ```
400
+
401
+ ### Move a deal through the pipeline
402
+ ```bash
403
+ # Check current pipeline stages
404
+ close opportunity-statuses list
405
+
406
+ # Move opportunity to next stage
407
+ close opportunities update oppo_abc123 --status-id "stat_demo_scheduled"
408
+
409
+ # Won it!
410
+ close opportunities update oppo_abc123 --status-id "stat_won" --confidence 100
411
+ ```
412
+
413
+ ### Set up a webhook for real-time events
414
+ ```bash
415
+ # Create webhook
416
+ close webhooks create \
417
+ --url "https://your-endpoint.com/close-hook" \
418
+ --events '["created.lead","updated.opportunity","created.call"]'
419
+
420
+ # List active webhooks
421
+ close webhooks list
422
+ ```
423
+
424
+ ### Enroll a contact in a sequence
425
+ ```bash
426
+ # List available sequences
427
+ close sequences list
428
+
429
+ # Subscribe the contact
430
+ close sequences subscribe \
431
+ --sequence-id seq_abc123 \
432
+ --contact-id cont_abc123
433
+ ```
434
+
435
+ ### Advanced lead search
436
+ ```bash
437
+ # Find all leads with status "Potential"
438
+ close leads list --query "status:Potential" --limit 100
439
+
440
+ # Advanced search with full query DSL
441
+ close leads search --query '{
442
+ "type": "and",
443
+ "queries": [
444
+ {
445
+ "type": "field",
446
+ "field": {"type": "regular", "field_name": "status_label"},
447
+ "negate": false,
448
+ "condition": {"type": "text", "mode": "equals", "value": "Potential"}
449
+ }
450
+ ]
451
+ }'
452
+ ```
453
+
454
+ ### Export leads to CSV
455
+ ```bash
456
+ # Start the export
457
+ close exports create-lead --format csv
458
+ # → {"id":"export_abc123","status":"pending",...}
459
+
460
+ # Poll until ready
461
+ close exports get export_abc123
462
+ # → {"id":"export_abc123","status":"completed","download_url":"https://..."}
463
+
464
+ # Download
465
+ curl -o leads.csv "https://..."
466
+ ```
467
+
468
+ ### Check pipeline health
469
+ ```bash
470
+ # Get funnel report
471
+ close reports funnel --pipeline-id pipe_abc123 --date-range this_month
472
+
473
+ # Get activity metrics for the team
474
+ close reports activity-metrics --date-range this_week
475
+ ```
476
+
477
+ ---
478
+
479
+ ## Pagination
480
+
481
+ List commands support offset-based pagination:
482
+
483
+ ```bash
484
+ # First page (25 items)
485
+ close leads list --limit 25
486
+
487
+ # Next page
488
+ close leads list --limit 25 --skip 25
489
+
490
+ # Third page
491
+ close leads list --limit 25 --skip 50
492
+ ```
493
+
494
+ ---
495
+
496
+ ## Custom Fields
497
+
498
+ Close CRM supports per-object custom fields. Set them using the `--custom` option with a JSON object where keys are custom field IDs:
499
+
500
+ ```bash
501
+ # Set custom fields on create
502
+ close leads create --name "Acme Corp" --custom '{"cf_budget":"500000","cf_industry":"SaaS"}'
503
+
504
+ # Update custom fields
505
+ close leads update lead_abc123 --custom '{"cf_budget":"750000"}'
506
+
507
+ # List available custom fields to find their IDs
508
+ close custom-fields list-lead
509
+ ```
510
+
511
+ ---
512
+
513
+ ## MCP Server (for Claude, Cursor, VS Code)
514
+
515
+ The CLI includes a built-in MCP server exposing all commands as tools:
516
+
517
+ ```bash
518
+ close mcp
519
+ ```
520
+
521
+ MCP config for Claude Desktop / Cursor:
522
+ ```json
523
+ {
524
+ "mcpServers": {
525
+ "close": {
526
+ "command": "npx",
527
+ "args": ["close-crm-cli", "mcp"],
528
+ "env": {
529
+ "CLOSE_API_KEY": "your-api-key"
530
+ }
531
+ }
532
+ }
533
+ }
534
+ ```
535
+
536
+ Or if installed globally:
537
+ ```json
538
+ {
539
+ "mcpServers": {
540
+ "close": {
541
+ "command": "close",
542
+ "args": ["mcp"],
543
+ "env": {
544
+ "CLOSE_API_KEY": "your-api-key"
545
+ }
546
+ }
547
+ }
548
+ }
549
+ ```
550
+
551
+ ---
552
+
553
+ ## Tips for AI Agents
554
+
555
+ 1. **Always use `--help`** on a group before guessing subcommand names
556
+ 2. **Parse JSON output** directly — it's machine-readable by default
557
+ 3. **Check exit codes** — 0 means success, 1 means error
558
+ 4. **Use `--fields`** to reduce output size (e.g. `--fields id,display_name`)
559
+ 5. **Use `--quiet`** when you only care about success/failure
560
+ 6. **Use `--pretty`** for human-readable JSON
561
+ 7. **Lead IDs** look like `lead_abc123`, contact IDs like `cont_abc123`, etc.
562
+ 8. **Custom field values** are set using `--custom '{"cf_fieldid":"value"}'`
563
+ 9. **Rate limits** are handled automatically with exponential backoff
564
+ 10. **All activity commands** share the same endpoint patterns: `/activity/call/`, `/activity/note/`, `/activity/email/`, `/activity/sms/`, `/activity/meeting/`
565
+ 11. **Sequence subscriptions** connect a contact to a sequence; check status with `sequences list-subscriptions --contact-id <id>`
566
+ 12. **Exports are async** — poll `exports get <id>` until `status === "completed"`, then download from `download_url`
package/CLAUDE.md ADDED
@@ -0,0 +1,148 @@
1
+ # CLAUDE.md — Developer Guide for close-crm-cli
2
+
3
+ ## Architecture Overview
4
+
5
+ This project follows the **CommandDefinition** pattern used across all bcharleson CLI tools:
6
+
7
+ - **One `CommandDefinition` object** = one CLI subcommand + one MCP tool
8
+ - All commands live in `src/commands/` grouped by resource
9
+ - `src/commands/index.ts` is the single registry — add commands here
10
+ - The MCP server (`src/mcp/server.ts`) auto-registers all commands from `allCommands[]`
11
+ - CLI registration (`registerAllCommands()`) also loops over `allCommands[]`
12
+
13
+ ## Adding a New Command
14
+
15
+ 1. Create `src/commands/{group}/{subcommand}.ts`
16
+ 2. Export a `CommandDefinition` object
17
+ 3. Import and add it to `allCommands[]` in `src/commands/index.ts`
18
+
19
+ That's it — the command automatically appears in both the CLI and the MCP server.
20
+
21
+ ### Command Template
22
+
23
+ ```typescript
24
+ import { z } from 'zod';
25
+ import type { CommandDefinition } from '../../core/types.js';
26
+ import { executeCommand } from '../../core/handler.js';
27
+
28
+ export const resourceActionCommand: CommandDefinition = {
29
+ name: 'resource_action', // snake_case, unique MCP tool name
30
+ group: 'resource', // CLI group name (kebab-case)
31
+ subcommand: 'action', // CLI subcommand name
32
+ description: 'What this does.', // Used in --help and MCP
33
+
34
+ inputSchema: z.object({
35
+ id: z.string().describe('Resource ID'),
36
+ name: z.string().optional().describe('Name'),
37
+ }),
38
+
39
+ cliMappings: {
40
+ args: [{ field: 'id', name: 'id', required: true }], // positional args
41
+ options: [
42
+ { field: 'name', flags: '--name <name>', description: 'Name' },
43
+ ],
44
+ },
45
+
46
+ endpoint: { method: 'PUT', path: '/resource/{id}/' },
47
+
48
+ fieldMappings: {
49
+ id: 'path', // goes in URL path
50
+ name: 'body', // goes in request body
51
+ // 'query' → goes in query string
52
+ },
53
+
54
+ handler: (input, client) => executeCommand(resourceActionCommand, input, client),
55
+ };
56
+ ```
57
+
58
+ For handlers with complex logic (like applying defaults), use an async function directly:
59
+
60
+ ```typescript
61
+ handler: async (input, client) => {
62
+ const body: Record<string, any> = { required_field: input.required_field };
63
+ if (input.optional) body.optional = input.optional;
64
+ return client.post('/resource/', body);
65
+ },
66
+ ```
67
+
68
+ ## Close CRM API Specifics
69
+
70
+ - **Base URL:** `https://api.close.com/api/v1`
71
+ - **Auth:** HTTP Basic Auth — `Authorization: Basic base64("apikey:")` (implemented in `CloseClient`)
72
+ - **HTTP methods:** GET, POST, PUT, DELETE (no PATCH)
73
+ - **Pagination:** `_limit` + `_skip` params, response has `data[]` + `has_more`
74
+ - **Rate limits:** 429 → read `rate_reset` header (Unix timestamp), sleep until reset
75
+ - **Custom fields:** Set as `custom.{FIELD_ID}` in request body
76
+
77
+ ## Project Structure
78
+
79
+ ```
80
+ src/
81
+ index.ts CLI entry point (Commander.js)
82
+ mcp.ts MCP server entry point
83
+ core/
84
+ types.ts CommandDefinition, CloseClient, GlobalOptions interfaces
85
+ client.ts HTTP client (Basic Auth, retry, rate limiting)
86
+ config.ts ~/.close/config.json management
87
+ auth.ts API key resolution (flag > env > config)
88
+ errors.ts Typed error classes
89
+ output.ts JSON output formatting
90
+ handler.ts executeCommand() — builds HTTP requests from CommandDefinitions
91
+ mcp/
92
+ server.ts MCP server (loops allCommands[], registers as MCP tools)
93
+ commands/
94
+ index.ts allCommands[] registry + registerAllCommands()
95
+ auth/ login, logout (special — no API client)
96
+ mcp/ mcp command registration
97
+ leads/ list, get, create, update, delete, merge, search
98
+ contacts/ list, get, create, update, delete
99
+ opportunities/ list, get, create, update, delete
100
+ tasks/ list, get, create, update, delete, bulk-update
101
+ activities/ list (unified stream)
102
+ calls/ list, get, create, update, delete
103
+ notes/ list, get, create, update, delete
104
+ emails/ list, get, create, update, delete
105
+ sms/ list, get, create, delete
106
+ meetings/ list, get, update, delete
107
+ users/ me, list, get, availability
108
+ pipelines/ list, get, create, update, delete
109
+ lead-statuses/ list, get, create, update, delete
110
+ opportunity-statuses/ list, get, create, update, delete
111
+ custom-fields/ index.ts (factory-generated, 25 commands)
112
+ webhooks/ list, get, create, update, delete
113
+ sequences/ list, get, create, update, delete, subscribe, list-subscriptions
114
+ email-templates/ list, get, create, update, delete, render
115
+ sms-templates/ list, get, create, update, delete
116
+ smart-views/ list, get, create, update, delete
117
+ reports/ activity-metrics, activity-report, funnel
118
+ phone-numbers/ list, get, update, delete
119
+ connected-accounts/ list, get
120
+ organizations/ get, update
121
+ groups/ list, get, create, update, delete
122
+ roles/ list, get
123
+ exports/ list, get, create-lead, create-opportunity
124
+ unsubscribe/ list, add, delete
125
+ ```
126
+
127
+ ## Build & Dev
128
+
129
+ ```bash
130
+ npm install
131
+ npm run dev -- leads list # Run CLI in dev mode
132
+ npm run dev:mcp # Run MCP server in dev mode
133
+ npm run build # Build to dist/
134
+ npm run typecheck # TypeScript type check
135
+ ```
136
+
137
+ ## Zod Version Note
138
+
139
+ This project uses Zod v3 (`"zod": "^3.24.0"`). The `inputSchema.shape` property is used in the MCP server to extract the Zod shape for tool registration. Do not upgrade to Zod v4 without testing the MCP server registration.
140
+
141
+ ## Conventions
142
+
143
+ - Use `z.preprocess()` for JSON array/object fields (handles both string-encoded and parsed values)
144
+ - Use `z.coerce.number()` for numeric CLI options (Commander.js passes everything as strings)
145
+ - Boolean CLI flags: use `z.preprocess()` with `v === 'true'` → `true` pattern
146
+ - All `handler` functions must return `Promise<unknown>`
147
+ - Use `encodeURIComponent()` for path parameters in custom handlers
148
+ - Keep command descriptions concise but complete — they appear in MCP tool descriptions seen by AI models