squidclaw 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.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -0
  3. package/bin/squidclaw.js +512 -0
  4. package/lib/ai/gateway.js +283 -0
  5. package/lib/ai/prompt-builder.js +149 -0
  6. package/lib/api/server.js +235 -0
  7. package/lib/behavior/engine.js +187 -0
  8. package/lib/channels/hub-media.js +128 -0
  9. package/lib/channels/hub.js +89 -0
  10. package/lib/channels/whatsapp/manager.js +319 -0
  11. package/lib/channels/whatsapp/media.js +228 -0
  12. package/lib/cli/agent-cmd.js +182 -0
  13. package/lib/cli/brain-cmd.js +49 -0
  14. package/lib/cli/broadcast-cmd.js +28 -0
  15. package/lib/cli/channels-cmd.js +157 -0
  16. package/lib/cli/config-cmd.js +26 -0
  17. package/lib/cli/conversations-cmd.js +27 -0
  18. package/lib/cli/engine-cmd.js +115 -0
  19. package/lib/cli/handoff-cmd.js +26 -0
  20. package/lib/cli/hours-cmd.js +38 -0
  21. package/lib/cli/key-cmd.js +62 -0
  22. package/lib/cli/knowledge-cmd.js +59 -0
  23. package/lib/cli/memory-cmd.js +50 -0
  24. package/lib/cli/platform-cmd.js +51 -0
  25. package/lib/cli/setup.js +226 -0
  26. package/lib/cli/stats-cmd.js +66 -0
  27. package/lib/cli/tui.js +308 -0
  28. package/lib/cli/update-cmd.js +25 -0
  29. package/lib/cli/webhook-cmd.js +40 -0
  30. package/lib/core/agent-manager.js +83 -0
  31. package/lib/core/agent.js +162 -0
  32. package/lib/core/config.js +172 -0
  33. package/lib/core/logger.js +43 -0
  34. package/lib/engine.js +117 -0
  35. package/lib/features/heartbeat.js +71 -0
  36. package/lib/storage/interface.js +56 -0
  37. package/lib/storage/sqlite.js +409 -0
  38. package/package.json +48 -0
  39. package/templates/BEHAVIOR.md +42 -0
  40. package/templates/IDENTITY.md +7 -0
  41. package/templates/RULES.md +9 -0
  42. package/templates/SOUL.md +19 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Squidclaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # 🦑 Squidclaw
2
+
3
+ **AI agent platform — human-like agents for WhatsApp & more.**
4
+
5
+ Squidclaw lets you create AI agents that feel like real people. They text naturally, remember conversations, learn over time, and work on WhatsApp out of the box.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npm i -g squidclaw
11
+ squidclaw setup
12
+ squidclaw start
13
+ ```
14
+
15
+ That's it. Your AI agent is live.
16
+
17
+ ## Features
18
+
19
+ - 🧠 **10+ AI Providers** — Claude, GPT-4o, Gemini, Llama, Mistral, local models
20
+ - 📱 **WhatsApp** — Multi-session, pairing code + QR, auto-reconnect
21
+ - 💬 **Human-like behavior** — Message splitting, reactions, emotion detection
22
+ - 🧬 **Soul & Personality** — Each agent has its own identity, tone, and rules
23
+ - 🧠 **Memory** — Short-term conversations + long-term learned facts
24
+ - 📚 **Knowledge Base** — Upload docs, RAG-powered answers
25
+ - 🔄 **Auto-fallback** — Claude down? Auto-switch to GPT-4o or free models
26
+ - 🤝 **Handoff** — Escalate to humans when needed
27
+ - 📊 **Usage tracking** — Tokens, costs, per-agent analytics
28
+ - 💓 **Heartbeat** — Proactive check-ins and scheduled messages
29
+ - 🔗 **Webhooks** — Integrate with any system
30
+ - 📢 **Broadcast** — Bulk messages with rate limiting
31
+ - 🌍 **Bilingual** — Arabic + English with auto-detection
32
+ - 🏢 **Platform mode** — Multi-tenant for SaaS builders
33
+
34
+ ## Supported AI Models
35
+
36
+ ### Paid
37
+ | Provider | Models |
38
+ |----------|--------|
39
+ | Anthropic | Claude Opus 4, Sonnet 4, Haiku 3.5 |
40
+ | OpenAI | GPT-4o, GPT-4o Mini, o3, o4-mini |
41
+ | Google | Gemini 2.5 Pro, 2.5 Flash, 2.0 Flash |
42
+ | Mistral | Large, Medium, Small |
43
+
44
+ ### Free
45
+ | Provider | Models | Notes |
46
+ |----------|--------|-------|
47
+ | Groq | Llama 4 Scout, Maverick | Free tier, very fast |
48
+ | Together | Llama 4 Scout, Maverick | Free $5 credit |
49
+ | Cerebras | Llama 3.3 70B | Free, fastest inference |
50
+ | Ollama | Any local model | Runs on your machine |
51
+ | LM Studio | Any local model | Runs on your machine |
52
+
53
+ ## Commands
54
+
55
+ ```bash
56
+ # Engine
57
+ squidclaw start # Start the engine
58
+ squidclaw stop # Stop the engine
59
+ squidclaw status # Show status
60
+
61
+ # Agents
62
+ squidclaw agent create # Create a new agent
63
+ squidclaw agent list # List all agents
64
+ squidclaw agent chat <id> # Chat in terminal
65
+ squidclaw agent edit <id> # Edit agent files
66
+ squidclaw agent delete <id> # Delete an agent
67
+
68
+ # Brain / Models
69
+ squidclaw brain list # Show available models
70
+ squidclaw brain set <model> # Set default model
71
+ squidclaw brain show # Show current model
72
+
73
+ # API Keys
74
+ squidclaw key set <provider> <key> # Set API key
75
+ squidclaw key test # Test connection
76
+ squidclaw key show # Show keys (masked)
77
+ squidclaw key remove <provider> # Remove a key
78
+
79
+ # Channels
80
+ squidclaw channels login whatsapp # Connect WhatsApp
81
+ squidclaw channels status # Show connections
82
+ squidclaw channels logout whatsapp # Disconnect
83
+
84
+ # Usage
85
+ squidclaw usage # Token usage & costs
86
+ squidclaw stats # Detailed analytics
87
+ squidclaw logs # View logs
88
+ ```
89
+
90
+ ## How It Works
91
+
92
+ Each agent gets its own soul (personality), memory, and rules:
93
+
94
+ ```
95
+ ~/.squidclaw/agents/luna/
96
+ ├── SOUL.md ← who the agent IS
97
+ ├── IDENTITY.md ← name, language, emoji
98
+ ├── MEMORY.md ← long-term learned facts
99
+ ├── RULES.md ← hard boundaries
100
+ └── BEHAVIOR.md ← behavior config
101
+ ```
102
+
103
+ When a WhatsApp message comes in:
104
+
105
+ 1. **Route** → identify which agent owns this number
106
+ 2. **Understand** → detect language, emotion, intent
107
+ 3. **Think** → load soul + memory + knowledge → call AI
108
+ 4. **Behave** → split into short messages, add reactions
109
+ 5. **Reply** → send human-like responses with natural timing
110
+
111
+ ## Platform Mode (for SaaS builders)
112
+
113
+ Squidclaw can run in multi-tenant mode — one process, many agents, many customers:
114
+
115
+ ```bash
116
+ squidclaw platform init --supabase-url <url> --supabase-key <key>
117
+ ```
118
+
119
+ Perfect for building your own AI agent SaaS on top of Squidclaw.
120
+
121
+ ## REST API
122
+
123
+ When running, Squidclaw exposes a REST API on port 9500:
124
+
125
+ | Endpoint | Description |
126
+ |----------|-------------|
127
+ | `GET /health` | Engine health |
128
+ | `GET /api/agents` | List agents |
129
+ | `POST /api/agents` | Create agent |
130
+ | `POST /api/agents/:id/chat` | Chat with agent |
131
+ | `POST /api/agents/:id/whatsapp/pair` | WhatsApp pairing |
132
+ | `GET /api/usage` | Usage stats |
133
+ | `GET /api/handoffs` | Active handoffs |
134
+ | `POST /api/webhooks` | Add webhook |
135
+
136
+ Full API docs at [squidclaw.dev/docs/api](https://squidclaw.dev/docs/api)
137
+
138
+ ## Requirements
139
+
140
+ - Node.js 20+
141
+ - Any AI provider API key (or use free models)
142
+
143
+ ## License
144
+
145
+ MIT
146
+
147
+ ---
148
+
149
+ Built with 🦑 by [Squidclaw](https://squidclaw.dev)
@@ -0,0 +1,512 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 🦑 Squidclaw CLI
5
+ * AI agent platform — human-like agents for WhatsApp & more
6
+ * https://squidclaw.dev
7
+ */
8
+
9
+ import { Command } from 'commander';
10
+ import chalk from 'chalk';
11
+ import { readFileSync } from 'fs';
12
+ import { fileURLToPath } from 'url';
13
+ import { dirname, join } from 'path';
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
17
+
18
+ const program = new Command();
19
+
20
+ program
21
+ .name('squidclaw')
22
+ .description('🦑 AI agent platform — human-like agents for WhatsApp & more')
23
+ .version(pkg.version);
24
+
25
+ // ── Setup ──────────────────────────────────────────────
26
+ program
27
+ .command('setup')
28
+ .description('Interactive first-time setup wizard')
29
+ .action(async () => {
30
+ const { setup } = await import('../lib/cli/setup.js');
31
+ await setup();
32
+ });
33
+
34
+ // ── Start / Stop / Restart / Status ────────────────────
35
+ program
36
+ .command('start')
37
+ .description('Start the Squidclaw engine')
38
+ .option('-p, --port <port>', 'API port', '9500')
39
+ .option('-d, --daemon', 'Run as background daemon')
40
+ .action(async (opts) => {
41
+ const { start } = await import('../lib/cli/engine-cmd.js');
42
+ await start(opts);
43
+ });
44
+
45
+ program
46
+ .command('stop')
47
+ .description('Stop the Squidclaw engine')
48
+ .action(async () => {
49
+ const { stop } = await import('../lib/cli/engine-cmd.js');
50
+ await stop();
51
+ });
52
+
53
+ program
54
+ .command('restart')
55
+ .description('Restart the Squidclaw engine')
56
+ .action(async () => {
57
+ const { restart } = await import('../lib/cli/engine-cmd.js');
58
+ await restart();
59
+ });
60
+
61
+ program
62
+ .command('status')
63
+ .description('Show engine status, agents, and connections')
64
+ .action(async () => {
65
+ const { status } = await import('../lib/cli/engine-cmd.js');
66
+ await status();
67
+ });
68
+
69
+ // ── Agent Management ───────────────────────────────────
70
+ const agent = program.command('agent').description('Manage agents');
71
+
72
+ agent
73
+ .command('create')
74
+ .description('Create a new agent')
75
+ .option('-n, --name <name>', 'Agent name')
76
+ .option('--soul <text>', 'Soul/personality description')
77
+ .option('-l, --language <lang>', 'Language (en/ar/bilingual)', 'en')
78
+ .action(async (opts) => {
79
+ const { createAgent } = await import('../lib/cli/agent-cmd.js');
80
+ await createAgent(opts);
81
+ });
82
+
83
+ agent
84
+ .command('list')
85
+ .description('List all agents')
86
+ .action(async () => {
87
+ const { listAgents } = await import('../lib/cli/agent-cmd.js');
88
+ await listAgents();
89
+ });
90
+
91
+ agent
92
+ .command('edit <id>')
93
+ .description('Edit an agent')
94
+ .action(async (id) => {
95
+ const { editAgent } = await import('../lib/cli/agent-cmd.js');
96
+ await editAgent(id);
97
+ });
98
+
99
+ agent
100
+ .command('delete <id>')
101
+ .description('Delete an agent')
102
+ .action(async (id) => {
103
+ const { deleteAgent } = await import('../lib/cli/agent-cmd.js');
104
+ await deleteAgent(id);
105
+ });
106
+
107
+ agent
108
+ .command('chat <id>')
109
+ .description('Chat with an agent in terminal')
110
+ .action(async (id) => {
111
+ const { chatAgent } = await import('../lib/cli/agent-cmd.js');
112
+ await chatAgent(id);
113
+ });
114
+
115
+ // ── Brain / Model Management ───────────────────────────
116
+ const brain = program.command('brain').description('Manage AI models');
117
+
118
+ brain
119
+ .command('list')
120
+ .description('List available models')
121
+ .action(async () => {
122
+ const { listBrains } = await import('../lib/cli/brain-cmd.js');
123
+ await listBrains();
124
+ });
125
+
126
+ brain
127
+ .command('set <model>')
128
+ .description('Set default model')
129
+ .option('-a, --agent <id>', 'Set for specific agent')
130
+ .option('-f, --fallback <model>', 'Add fallback model', [])
131
+ .action(async (model, opts) => {
132
+ const { setBrain } = await import('../lib/cli/brain-cmd.js');
133
+ await setBrain(model, opts);
134
+ });
135
+
136
+ brain
137
+ .command('show')
138
+ .description('Show current model config')
139
+ .action(async () => {
140
+ const { showBrain } = await import('../lib/cli/brain-cmd.js');
141
+ await showBrain();
142
+ });
143
+
144
+ // ── API Key Management ─────────────────────────────────
145
+ const key = program.command('key').description('Manage API keys');
146
+
147
+ key
148
+ .command('set <provider> <apiKey>')
149
+ .description('Set API key for a provider')
150
+ .action(async (provider, apiKey) => {
151
+ const { setKey } = await import('../lib/cli/key-cmd.js');
152
+ await setKey(provider, apiKey);
153
+ });
154
+
155
+ key
156
+ .command('test')
157
+ .description('Test current API key')
158
+ .option('-p, --provider <provider>', 'Test specific provider')
159
+ .action(async (opts) => {
160
+ const { testKey } = await import('../lib/cli/key-cmd.js');
161
+ await testKey(opts);
162
+ });
163
+
164
+ key
165
+ .command('show')
166
+ .description('Show configured keys (masked)')
167
+ .action(async () => {
168
+ const { showKeys } = await import('../lib/cli/key-cmd.js');
169
+ await showKeys();
170
+ });
171
+
172
+ key
173
+ .command('remove <provider>')
174
+ .description('Remove an API key')
175
+ .action(async (provider) => {
176
+ const { removeKey } = await import('../lib/cli/key-cmd.js');
177
+ await removeKey(provider);
178
+ });
179
+
180
+ // ── Channel Management ─────────────────────────────────
181
+ const channels = program.command('channels').description('Manage messaging channels');
182
+
183
+ channels
184
+ .command('login <channel>')
185
+ .description('Connect a channel (whatsapp, telegram)')
186
+ .option('-a, --agent <id>', 'Agent to connect')
187
+ .option('-m, --method <method>', 'Login method (pairing/qr)', 'pairing')
188
+ .action(async (channel, opts) => {
189
+ const { loginChannel } = await import('../lib/cli/channels-cmd.js');
190
+ await loginChannel(channel, opts);
191
+ });
192
+
193
+ channels
194
+ .command('status')
195
+ .description('Show channel connection status')
196
+ .action(async () => {
197
+ const { channelStatus } = await import('../lib/cli/channels-cmd.js');
198
+ await channelStatus();
199
+ });
200
+
201
+ channels
202
+ .command('logout <channel>')
203
+ .description('Disconnect a channel')
204
+ .option('-a, --agent <id>', 'Agent to disconnect')
205
+ .action(async (channel, opts) => {
206
+ const { logoutChannel } = await import('../lib/cli/channels-cmd.js');
207
+ await logoutChannel(channel, opts);
208
+ });
209
+
210
+ // ── Memory Management ──────────────────────────────────
211
+ const memory = program.command('memory').description('Manage agent memory');
212
+
213
+ memory
214
+ .command('show <agentId>')
215
+ .description('Show agent memory')
216
+ .action(async (agentId) => {
217
+ const { showMemory } = await import('../lib/cli/memory-cmd.js');
218
+ await showMemory(agentId);
219
+ });
220
+
221
+ memory
222
+ .command('clear <agentId>')
223
+ .description('Clear agent memory')
224
+ .option('--confirm', 'Skip confirmation')
225
+ .action(async (agentId, opts) => {
226
+ const { clearMemory } = await import('../lib/cli/memory-cmd.js');
227
+ await clearMemory(agentId, opts);
228
+ });
229
+
230
+ memory
231
+ .command('export <agentId>')
232
+ .description('Export agent memory to file')
233
+ .option('-o, --output <path>', 'Output file path')
234
+ .action(async (agentId, opts) => {
235
+ const { exportMemory } = await import('../lib/cli/memory-cmd.js');
236
+ await exportMemory(agentId, opts);
237
+ });
238
+
239
+ // ── Knowledge Base ─────────────────────────────────────
240
+ const knowledge = program.command('knowledge').description('Manage knowledge base');
241
+
242
+ knowledge
243
+ .command('upload <file>')
244
+ .description('Upload a document to knowledge base')
245
+ .option('-a, --agent <id>', 'Target agent')
246
+ .action(async (file, opts) => {
247
+ const { uploadKnowledge } = await import('../lib/cli/knowledge-cmd.js');
248
+ await uploadKnowledge(file, opts);
249
+ });
250
+
251
+ knowledge
252
+ .command('list')
253
+ .description('List knowledge base documents')
254
+ .option('-a, --agent <id>', 'Filter by agent')
255
+ .action(async (opts) => {
256
+ const { listKnowledge } = await import('../lib/cli/knowledge-cmd.js');
257
+ await listKnowledge(opts);
258
+ });
259
+
260
+ knowledge
261
+ .command('delete <docId>')
262
+ .description('Delete a document')
263
+ .action(async (docId) => {
264
+ const { deleteKnowledge } = await import('../lib/cli/knowledge-cmd.js');
265
+ await deleteKnowledge(docId);
266
+ });
267
+
268
+ // ── Usage & Stats ──────────────────────────────────────
269
+ program
270
+ .command('usage')
271
+ .description('Show token usage and costs')
272
+ .option('-a, --agent <id>', 'Filter by agent')
273
+ .option('-p, --period <period>', 'Time period (7d/30d/all)', '30d')
274
+ .action(async (opts) => {
275
+ const { showUsage } = await import('../lib/cli/stats-cmd.js');
276
+ await showUsage(opts);
277
+ });
278
+
279
+ program
280
+ .command('stats')
281
+ .description('Show detailed analytics')
282
+ .option('-a, --agent <id>', 'Filter by agent')
283
+ .option('-p, --period <period>', 'Time period (7d/30d/all)', '7d')
284
+ .action(async (opts) => {
285
+ const { showStats } = await import('../lib/cli/stats-cmd.js');
286
+ await showStats(opts);
287
+ });
288
+
289
+ program
290
+ .command('logs')
291
+ .description('Show engine logs')
292
+ .option('-a, --agent <id>', 'Filter by agent')
293
+ .option('-n, --lines <n>', 'Number of lines', '50')
294
+ .option('-f, --follow', 'Follow log output')
295
+ .action(async (opts) => {
296
+ const { showLogs } = await import('../lib/cli/stats-cmd.js');
297
+ await showLogs(opts);
298
+ });
299
+
300
+ // ── Broadcast ──────────────────────────────────────────
301
+ const broadcast = program.command('broadcast').description('Send broadcast messages');
302
+
303
+ broadcast
304
+ .command('send')
305
+ .description('Send a broadcast message')
306
+ .requiredOption('-a, --agent <id>', 'Agent to send from')
307
+ .requiredOption('-m, --message <text>', 'Message to send')
308
+ .option('-g, --group <group>', 'Target group')
309
+ .action(async (opts) => {
310
+ const { sendBroadcast } = await import('../lib/cli/broadcast-cmd.js');
311
+ await sendBroadcast(opts);
312
+ });
313
+
314
+ // ── Handoff ────────────────────────────────────────────
315
+ const handoff = program.command('handoff').description('Manage human handoffs');
316
+
317
+ handoff
318
+ .command('list')
319
+ .description('List pending handoffs')
320
+ .action(async () => {
321
+ const { listHandoffs } = await import('../lib/cli/handoff-cmd.js');
322
+ await listHandoffs();
323
+ });
324
+
325
+ handoff
326
+ .command('resolve <id>')
327
+ .description('Resolve a handoff (hand back to agent)')
328
+ .action(async (id) => {
329
+ const { resolveHandoff } = await import('../lib/cli/handoff-cmd.js');
330
+ await resolveHandoff(id);
331
+ });
332
+
333
+ // ── Business Hours ─────────────────────────────────────
334
+ const hours = program.command('hours').description('Manage business hours');
335
+
336
+ hours
337
+ .command('set <schedule>')
338
+ .description('Set business hours (e.g. "sun-thu 9:00-18:00")')
339
+ .option('-a, --agent <id>', 'Agent')
340
+ .option('-t, --timezone <tz>', 'Timezone', 'UTC')
341
+ .action(async (schedule, opts) => {
342
+ const { setHours } = await import('../lib/cli/hours-cmd.js');
343
+ await setHours(schedule, opts);
344
+ });
345
+
346
+ hours
347
+ .command('show')
348
+ .description('Show business hours')
349
+ .option('-a, --agent <id>', 'Agent')
350
+ .action(async (opts) => {
351
+ const { showHours } = await import('../lib/cli/hours-cmd.js');
352
+ await showHours(opts);
353
+ });
354
+
355
+ hours
356
+ .command('off')
357
+ .description('Set 24/7 mode (no business hours)')
358
+ .option('-a, --agent <id>', 'Agent')
359
+ .action(async (opts) => {
360
+ const { setAlwaysOn } = await import('../lib/cli/hours-cmd.js');
361
+ await setAlwaysOn(opts);
362
+ });
363
+
364
+ // ── Webhook ────────────────────────────────────────────
365
+ const webhook = program.command('webhook').description('Manage webhooks');
366
+
367
+ webhook
368
+ .command('add <url>')
369
+ .description('Add a webhook endpoint')
370
+ .action(async (url) => {
371
+ const { addWebhook } = await import('../lib/cli/webhook-cmd.js');
372
+ await addWebhook(url);
373
+ });
374
+
375
+ webhook
376
+ .command('list')
377
+ .description('List webhooks')
378
+ .action(async () => {
379
+ const { listWebhooks } = await import('../lib/cli/webhook-cmd.js');
380
+ await listWebhooks();
381
+ });
382
+
383
+ webhook
384
+ .command('remove <id>')
385
+ .description('Remove a webhook')
386
+ .action(async (id) => {
387
+ const { removeWebhook } = await import('../lib/cli/webhook-cmd.js');
388
+ await removeWebhook(id);
389
+ });
390
+
391
+ // ── Config ─────────────────────────────────────────────
392
+ const config = program.command('config').description('Manage configuration');
393
+
394
+ config
395
+ .command('get [key]')
396
+ .description('Get config value')
397
+ .action(async (key) => {
398
+ const { getConfig } = await import('../lib/cli/config-cmd.js');
399
+ await getConfig(key);
400
+ });
401
+
402
+ config
403
+ .command('set <key> <value>')
404
+ .description('Set config value')
405
+ .action(async (key, value) => {
406
+ const { setConfig } = await import('../lib/cli/config-cmd.js');
407
+ await setConfig(key, value);
408
+ });
409
+
410
+ config
411
+ .command('edit')
412
+ .description('Open config in editor')
413
+ .action(async () => {
414
+ const { editConfig } = await import('../lib/cli/config-cmd.js');
415
+ await editConfig();
416
+ });
417
+
418
+ // ── Conversations ──────────────────────────────────────
419
+ const conversations = program.command('conversations').description('Manage conversations');
420
+
421
+ conversations
422
+ .command('list')
423
+ .description('List recent conversations')
424
+ .option('-a, --agent <id>', 'Filter by agent')
425
+ .option('-n, --limit <n>', 'Limit results', '20')
426
+ .action(async (opts) => {
427
+ const { listConversations } = await import('../lib/cli/conversations-cmd.js');
428
+ await listConversations(opts);
429
+ });
430
+
431
+ conversations
432
+ .command('search <query>')
433
+ .description('Search conversations')
434
+ .option('-a, --agent <id>', 'Filter by agent')
435
+ .action(async (query, opts) => {
436
+ const { searchConversations } = await import('../lib/cli/conversations-cmd.js');
437
+ await searchConversations(query, opts);
438
+ });
439
+
440
+ conversations
441
+ .command('export')
442
+ .description('Export conversations')
443
+ .option('-a, --agent <id>', 'Filter by agent')
444
+ .option('-f, --format <format>', 'Export format (csv/json)', 'json')
445
+ .option('-o, --output <path>', 'Output file')
446
+ .action(async (opts) => {
447
+ const { exportConversations } = await import('../lib/cli/conversations-cmd.js');
448
+ await exportConversations(opts);
449
+ });
450
+
451
+ // ── Platform Mode ──────────────────────────────────────
452
+ const platform = program.command('platform').description('Platform integration (multi-tenant)');
453
+
454
+ platform
455
+ .command('init')
456
+ .description('Initialize platform mode')
457
+ .option('--supabase-url <url>', 'Supabase project URL')
458
+ .option('--supabase-key <key>', 'Supabase service role key')
459
+ .action(async (opts) => {
460
+ const { initPlatform } = await import('../lib/cli/platform-cmd.js');
461
+ await initPlatform(opts);
462
+ });
463
+
464
+ platform
465
+ .command('agents')
466
+ .description('List all platform agents')
467
+ .action(async () => {
468
+ const { platformAgents } = await import('../lib/cli/platform-cmd.js');
469
+ await platformAgents();
470
+ });
471
+
472
+ platform
473
+ .command('usage')
474
+ .description('Platform-wide usage stats')
475
+ .action(async () => {
476
+ const { platformUsage } = await import('../lib/cli/platform-cmd.js');
477
+ await platformUsage();
478
+ });
479
+
480
+ // ── Update ─────────────────────────────────────────────
481
+ program
482
+ .command('update')
483
+ .description('Update Squidclaw to latest version')
484
+ .action(async () => {
485
+ const { update } = await import('../lib/cli/update-cmd.js');
486
+ await update();
487
+ });
488
+
489
+ // ── Splash ─────────────────────────────────────────────
490
+ if (process.argv.length <= 2) {
491
+ console.log(chalk.cyan(`
492
+ 🦑 Squidclaw v${pkg.version}
493
+ AI agent platform — human-like agents for WhatsApp & more
494
+
495
+ ${chalk.gray('Get started:')} squidclaw setup
496
+ ${chalk.gray('Help:')} squidclaw --help
497
+ ${chalk.gray('Docs:')} https://squidclaw.dev
498
+ `));
499
+ process.exit(0);
500
+ }
501
+
502
+ program.parse();
503
+
504
+ // ── TUI ────────────────────────────────────────────────
505
+ program
506
+ .command('tui')
507
+ .description('Open terminal chat UI')
508
+ .option('-a, --agent <id>', 'Start with specific agent')
509
+ .action(async (opts) => {
510
+ const { tui } = await import('../lib/cli/tui.js');
511
+ await tui(opts);
512
+ });