wispy-cli 1.1.0 → 1.1.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 +488 -190
  2. package/core/cron.mjs +2 -0
  3. package/package.json +25 -6
package/README.md CHANGED
@@ -1,273 +1,571 @@
1
1
  # 🌿 Wispy CLI
2
2
 
3
- AI workspace assistant with multi-agent orchestration. Like Claude Code or Codex, but with workstream isolation, budget management, and a team of specialized sub-agents.
3
+ > Your personal AI assistant chat, automate, and orchestrate from the terminal.
4
4
 
5
- ## Quick Start
5
+ [![npm version](https://img.shields.io/npm/v/wispy-cli.svg)](https://www.npmjs.com/package/wispy-cli)
6
+ [![Node.js >= 18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
+
9
+ Wispy is a powerful terminal AI assistant that talks to your files, runs commands, orchestrates sub-agents, sends messages to Telegram/Discord/Slack, and remembers things across sessions — all from a single `wispy` command.
10
+
11
+ ## ✨ Features
12
+
13
+ - 💬 **Interactive REPL + TUI** — chat mode, slash commands, streaming responses
14
+ - 🤖 **7 AI providers** — Gemini, Claude, OpenAI, Groq, DeepSeek, Ollama, OpenRouter
15
+ - 🔧 **18+ built-in tools** — files, shell commands, git, web search, and more
16
+ - 🔌 **MCP server integration** — connect any Model Context Protocol server
17
+ - 📱 **Multi-channel bot** — Telegram, Discord, Slack with session isolation
18
+ - 🧠 **Long-term memory** — persistent facts, daily logs, project notes
19
+ - ⏰ **Cron scheduler** — scheduled tasks with channel delivery
20
+ - 🤝 **Sub-agent orchestration** — spawn parallel agents, steer them, collect results
21
+ - 📂 **Workstream isolation** — separate contexts per project
22
+
23
+ ---
24
+
25
+ ## 🚀 Quick Start
6
26
 
7
27
  ```bash
28
+ # Install globally
8
29
  npm install -g wispy-cli
9
- export GOOGLE_AI_KEY=your-key # or ANTHROPIC_API_KEY or OPENAI_API_KEY
30
+
31
+ # Set your API key (any of these)
32
+ export GOOGLE_AI_KEY=your_key # Gemini (recommended, has free tier)
33
+ export ANTHROPIC_API_KEY=your_key # Claude
34
+ export OPENAI_API_KEY=your_key # OpenAI / GPT
35
+
36
+ # Start chatting
10
37
  wispy
11
38
  ```
12
39
 
13
- That's it. No server setup needed it starts automatically.
40
+ Wispy auto-detects your API key and starts the REPL immediately.
14
41
 
15
- ## Features
42
+ ---
16
43
 
17
- ### Chat & Tools
44
+ ## 📦 Installation
45
+
46
+ ### Requirements
47
+ - **Node.js >= 18** (ESM modules required)
48
+
49
+ ### Global install
18
50
  ```bash
19
- wispy # Interactive REPL
20
- wispy "read my package.json" # One-shot with tool use
21
- wispy --continue "and fix it"# Continue previous session
22
- wispy --new "fresh start" # New session
51
+ npm install -g wispy-cli
23
52
  ```
24
53
 
25
- Wispy can **read/write files, run commands, search the web** — not just chat.
54
+ ### Local install
55
+ ```bash
56
+ npm install wispy-cli
57
+ npx wispy
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 🗣️ Chat Modes
26
63
 
27
- ### Workstream Isolation
64
+ ### REPL (default)
28
65
  ```bash
29
- wispy -w backend "fix the API" # Backend workstream
30
- wispy -w frontend "add dark mode" # Frontend workstream
31
- wispy overview # See all workstreams at a glance
32
- wispy search "auth" # Search across all workstreams
66
+ wispy # start interactive chat
67
+ wispy -w myproject # start in a specific workstream
68
+ wispy --session my-ses # resume a named session
33
69
  ```
34
70
 
35
- Each workstream has its own conversation history, context, and budget.
71
+ **REPL slash commands:**
72
+ ```
73
+ /help — show all slash commands
74
+ /clear — reset conversation history
75
+ /sessions — list recent sessions
76
+ /memory — show memory files
77
+ /tools — list available tools
78
+ /model — show current AI model
79
+ /workstream — show active workstream
80
+ /exit — exit Wispy
81
+ ```
36
82
 
37
- ### Multi-Agent Orchestration
83
+ ### TUI (Ink-based)
38
84
  ```bash
39
- # AI automatically delegates to specialized sub-agents:
40
- # 🔍 explorer codebase search
41
- # 📋 planner — strategy design
42
- # 🔨 worker — implementation
43
- # 🔎 reviewer — code review & QA
44
- ```
45
-
46
- #### Execution Modes
47
- - **Pipeline** — Sequential chaining: `explore → plan → implement → review`
48
- - **Ralph mode** — Persistence: retry until reviewer confirms done (max 5 rounds)
49
- - **Async agents** — Fire-and-forget background tasks
50
-
51
- ### 7 Providers (Auto-detected)
52
-
53
- | Provider | Env Variable | Free Tier |
54
- |----------|-------------|-----------|
55
- | Google AI (Gemini) | `GOOGLE_AI_KEY` | ✅ |
56
- | Anthropic (Claude) | `ANTHROPIC_API_KEY` | ❌ |
57
- | OpenAI (GPT-4o) | `OPENAI_API_KEY` | ❌ |
58
- | OpenRouter | `OPENROUTER_API_KEY` | Some |
59
- | Groq | `GROQ_API_KEY` | ✅ |
60
- | DeepSeek | `DEEPSEEK_API_KEY` | ✅ |
61
- | Ollama (local) | `OLLAMA_HOST` | ✅ |
62
-
63
- Also auto-detects macOS Keychain credentials.
64
-
65
- ### Cost Optimization
66
- - **Smart model routing** — simple tasks → cheap model, complex → mid, critical → expensive
67
- - **Per-workstream budgets** — `/budget set 5.00` to cap spending
68
- - **Context window optimization** — auto-trims old messages to save tokens
69
- - **Token tracking** — see cost after every response
70
-
71
- ### Security
72
- - Sandboxed command execution (macOS Seatbelt)
73
- - Process hardening (core dump disable, ptrace block)
74
- - Audit logging (JSON Lines)
75
- - Rate limiting + CORS restriction
76
- - API key isolation per workstream
77
-
78
- ## In-Session Commands
79
-
80
- | Command | Description |
81
- |---------|-------------|
82
- | `/help` | Show all commands |
83
- | `/compact` | Compress conversation history |
84
- | `/memory <type> <text>` | Save to persistent memory |
85
- | `/budget` | Show spending per workstream |
86
- | `/budget set <usd>` | Set budget limit |
87
- | `/overview` | Director view — all workstreams |
88
- | `/search <keyword>` | Search across workstreams |
89
- | `/cost` | Show session token usage |
90
- | `/workstreams` | List all workstreams |
91
- | `/provider` | Show current provider |
92
- | `/model [name]` | Show/change model |
93
- | `/clear` | Reset conversation |
94
- | `/quit` | Exit |
95
-
96
- ## Project Context (WISPY.md)
97
-
98
- Create a `WISPY.md` in your project root or `~/.wispy/WISPY.md`. It gets loaded into every conversation turn (up to 40K chars), just like Claude Code's `CLAUDE.md`.
99
-
100
- ```markdown
101
- # WISPY.md
102
- ## About this project
103
- - Next.js 15 app with TypeScript
104
- - Use Tailwind CSS
105
- - Korean comments preferred
106
- ```
107
-
108
- ## Workstream Context (work.md)
109
-
110
- Each workstream can have its own `work.md` — loaded every turn, like WISPY.md but scoped to that workstream.
85
+ wispy-tui # full terminal UI with scrollable history
86
+ wispy-tui -w myproject # workstream-specific TUI
87
+ ```
111
88
 
89
+ ### One-shot (non-interactive)
112
90
  ```bash
113
- /work init # Create work.md for current workstream
114
- /work set "deadline: Friday" # Append context
115
- /work # View current work.md
91
+ wispy ask "What files are in the current directory?"
92
+ wispy exec "summarize README.md"
116
93
  ```
117
94
 
118
- File locations (searched in order):
119
- 1. `~/.wispy/conversations/<workstream>.work.md`
120
- 2. `.wispy/<workstream>.work.md`
121
- 3. `work.md` (project root fallback)
95
+ ### Overview
96
+ ```bash
97
+ wispy overview # show all workstreams and recent activity
98
+ ```
122
99
 
123
- ```markdown
124
- # backend
125
- ## Goals
126
- - Migrate to PostgreSQL
127
- - Add rate limiting
100
+ ---
128
101
 
129
- ## Context
130
- - Using Express.js + TypeORM
131
- - Staging server: staging.example.com
132
- ```
102
+ ## 🤖 AI Providers
133
103
 
134
- ## Persistent Memory
104
+ Wispy detects your configured provider automatically. Priority order:
135
105
 
136
- Wispy remembers across sessions via `~/.wispy/memory/`:
106
+ | Provider | Env Var | Default Model |
107
+ |----------|---------|---------------|
108
+ | **Google AI** (Gemini) | `GOOGLE_AI_KEY` or `GEMINI_API_KEY` | `gemini-2.5-flash` |
109
+ | **Anthropic** (Claude) | `ANTHROPIC_API_KEY` | `claude-sonnet-4-20250514` |
110
+ | **OpenAI** | `OPENAI_API_KEY` | `gpt-4o` |
111
+ | **OpenRouter** | `OPENROUTER_API_KEY` | `anthropic/claude-sonnet-4` |
112
+ | **Groq** | `GROQ_API_KEY` | `llama-3.3-70b-versatile` |
113
+ | **DeepSeek** | `DEEPSEEK_API_KEY` | `deepseek-chat` |
114
+ | **Ollama** (local) | `OLLAMA_HOST` | `llama3.2` |
137
115
 
116
+ ### Override provider
138
117
  ```bash
139
- /memory user "prefers dark mode"
140
- /memory project "deadline is Friday"
141
- /memory feedback "don't use var, use const"
142
- /memory references "API docs: https://..."
118
+ WISPY_PROVIDER=anthropic wispy
119
+ WISPY_MODEL=claude-3-5-haiku wispy
143
120
  ```
144
121
 
145
- ## Multi-Channel Bot Support (v0.6.0)
122
+ ### Config file
123
+ ```json
124
+ // ~/.wispy/config.json
125
+ {
126
+ "provider": "google",
127
+ "model": "gemini-2.5-flash",
128
+ "apiKey": "optional-if-not-in-env"
129
+ }
130
+ ```
131
+
132
+ ---
133
+
134
+ ## 🔧 Built-in Tools
135
+
136
+ Wispy gives the AI access to these tools automatically:
146
137
 
147
- Run Wispy as a bot on Telegram, Discord, and Slack — all at once or individually.
138
+ | Tool | Description |
139
+ |------|-------------|
140
+ | `read_file` | Read any file's contents |
141
+ | `write_file` | Write or create files |
142
+ | `file_edit` | Edit files with find-and-replace |
143
+ | `file_search` | Search files with regex (like grep) |
144
+ | `list_directory` | List directory contents |
145
+ | `run_command` | Execute shell commands |
146
+ | `git_status` / `git_diff` / `git_log` | Git operations |
147
+ | `web_search` | Search the web |
148
+ | `memory_save` | Save facts to persistent memory |
149
+ | `memory_get` | Retrieve a memory by key |
150
+ | `memory_search` | Full-text search across all memories |
151
+ | `memory_list` | List all memory files |
152
+ | `memory_append` | Append to a memory file |
153
+ | `memory_delete` | Delete a memory file |
154
+ | `spawn_subagent` | Launch a parallel sub-agent |
155
+ | `list_subagents` | List running sub-agents |
156
+ | `get_subagent_result` | Get a sub-agent's result |
157
+ | `kill_subagent` | Cancel a sub-agent |
148
158
 
149
- ### Quick Start
159
+ ---
150
160
 
161
+ ## 📱 Channel Setup
162
+
163
+ Run Wispy as a multi-platform bot that responds to messages in Telegram, Discord, or Slack.
164
+
165
+ ### Start the bot server
151
166
  ```bash
152
- # Set up a channel (interactive)
153
- wispy channel setup telegram
154
- wispy channel setup discord
155
- wispy channel setup slack
167
+ wispy channels start # start all configured channels
168
+ wispy channels start --telegram # start only Telegram
169
+ ```
170
+
171
+ ### Telegram
172
+ 1. Create a bot via [@BotFather](https://t.me/BotFather)
173
+ 2. Copy the bot token
174
+ 3. Configure:
175
+ ```bash
176
+ # Option 1: env var
177
+ export WISPY_TELEGRAM_TOKEN=your_bot_token
178
+
179
+ # Option 2: config file
180
+ # ~/.wispy/channels.json
181
+ {
182
+ "telegram": {
183
+ "enabled": true,
184
+ "token": "your_bot_token"
185
+ }
186
+ }
187
+ ```
188
+
189
+ ### Discord
190
+ 1. Create a bot at [discord.com/developers](https://discord.com/developers/applications)
191
+ 2. Install peer dependency: `npm install -g discord.js`
192
+ 3. Configure:
193
+ ```json
194
+ {
195
+ "discord": {
196
+ "enabled": true,
197
+ "token": "your_discord_token",
198
+ "clientId": "your_client_id",
199
+ "guildId": "optional_guild_id"
200
+ }
201
+ }
202
+ ```
203
+
204
+ ### Slack
205
+ 1. Create a Slack app at [api.slack.com](https://api.slack.com/apps)
206
+ 2. Install peer dependency: `npm install -g @slack/bolt`
207
+ 3. Configure:
208
+ ```json
209
+ {
210
+ "slack": {
211
+ "enabled": true,
212
+ "botToken": "xoxb-your-token",
213
+ "appToken": "xapp-your-token",
214
+ "signingSecret": "your-signing-secret"
215
+ }
216
+ }
217
+ ```
218
+
219
+ Each chat/user gets an isolated session — Wispy remembers context per conversation.
156
220
 
157
- # Start all configured channels
158
- wispy --serve
221
+ ---
159
222
 
160
- # Or start a single channel
161
- wispy --telegram
162
- wispy --discord
163
- wispy --slack
223
+ ## 🧠 Memory System
164
224
 
165
- # List configured channels
166
- wispy channel list
225
+ Wispy has a file-based long-term memory stored in `~/.wispy/memory/`.
167
226
 
168
- # Test a channel connection
169
- wispy channel test telegram
227
+ ### Using memory in chat
228
+ Just ask Wispy to remember things:
229
+ ```
230
+ You: Remember that my project uses TypeScript and Next.js 15
231
+ Wispy: Got it! I'll remember that. 🌿
170
232
  ```
171
233
 
172
- ### Telegram Setup
234
+ Or use memory tools explicitly:
235
+ ```
236
+ You: Save this to memory: the deployment command is `vercel --prod`
237
+ ```
173
238
 
174
- 1. Talk to [@BotFather](https://t.me/BotFather) on Telegram
175
- 2. Send `/newbot`, follow prompts, copy the token
176
- 3. Run `wispy channel setup telegram`
239
+ ### Memory structure
240
+ ```
241
+ ~/.wispy/memory/
242
+ ├── MEMORY.md — main persistent memory (auto-included in every chat)
243
+ ├── user.md — user preferences
244
+ ├── daily/
245
+ │ └── 2026-04-03.md — daily logs
246
+ └── projects/
247
+ └── myapp.md — project-specific notes
248
+ ```
177
249
 
178
- **Or** set the env var:
250
+ ### Memory CLI
179
251
  ```bash
180
- export WISPY_TELEGRAM_TOKEN=your-token
181
- wispy --telegram
252
+ wispy memory list # list all memory files
253
+ wispy memory get MEMORY # show main memory
254
+ wispy memory save user "I prefer TypeScript"
255
+ wispy memory search "deployment" # full-text search
256
+ wispy memory delete daily/old-date
182
257
  ```
183
258
 
184
- Bot commands: `/start`, `/clear`, `/model`, `/help`
259
+ ---
260
+
261
+ ## ⏰ Cron Scheduler
185
262
 
186
- ### Discord Setup
263
+ Schedule tasks to run automatically and optionally deliver results to a channel.
187
264
 
188
- 1. Go to [Discord Developer Portal](https://discord.com/developers/applications)
189
- 2. Create an app → Bot → copy the token
190
- 3. Enable **Message Content Intent** in Bot settings
191
- 4. Invite bot to your server with `bot` + `applications.commands` scopes
192
- 5. Run `wispy channel setup discord`
265
+ ### Add a scheduled job
266
+ ```bash
267
+ # Every morning briefing
268
+ wispy cron add \
269
+ --name "Morning Briefing" \
270
+ --schedule "0 9 * * *" \
271
+ --task "Summarize my pending tasks and give me a morning overview" \
272
+ --channel "telegram:YOUR_CHAT_ID"
273
+
274
+ # Every 30 minutes
275
+ wispy cron add \
276
+ --name "Price Check" \
277
+ --schedule every:1800000 \
278
+ --task "Check the current price of BTC and ETH"
279
+
280
+ # One-shot at specific time
281
+ wispy cron add \
282
+ --name "Reminder" \
283
+ --schedule "at:2026-12-31T09:00:00Z" \
284
+ --task "Remind me it's New Year's Eve!"
285
+ ```
193
286
 
194
- **Or** set the env var:
287
+ ### Schedule formats
288
+ | Format | Example | Description |
289
+ |--------|---------|-------------|
290
+ | Cron expression | `0 9 * * *` | Standard 5-field cron (daily at 9am) |
291
+ | Interval | `every:1800000` | Every N milliseconds (30 min) |
292
+ | One-shot | `at:2026-12-31T09:00:00Z` | Specific ISO timestamp |
293
+
294
+ ### Manage jobs
195
295
  ```bash
196
- export WISPY_DISCORD_TOKEN=your-token
197
- wispy --discord
296
+ wispy cron list # list all jobs
297
+ wispy cron run <id> # run a job immediately
298
+ wispy cron remove <id> # delete a job
299
+ wispy cron history <id> # view execution history
300
+ ```
301
+
302
+ ### Start the scheduler
303
+ ```bash
304
+ wispy cron start # start the cron scheduler daemon
305
+ ```
306
+
307
+ ---
308
+
309
+ ## 🤝 Sub-agents
310
+
311
+ Delegate complex tasks to parallel sub-agents and collect results.
312
+
313
+ ### From chat
314
+ ```
315
+ You: Spawn a sub-agent to analyze all TypeScript files in src/ and report issues
316
+ Wispy: Spawning sub-agent 'code-review'... 🌿
198
317
  ```
199
318
 
200
- Triggers: mention @Wispy, `!clear`, `!model`, `!help`, or DM the bot.
319
+ ### Sub-agent tools (available to Wispy in chat)
320
+ - `spawn_subagent` — start a sub-agent with a task
321
+ - `list_subagents` — see all active/recent sub-agents
322
+ - `get_subagent_result` — wait for and retrieve results
323
+ - `kill_subagent` — cancel a running sub-agent
324
+ - `steer_subagent` — send mid-task guidance
201
325
 
202
- ### Slack Setup
326
+ ### Sub-agent lifecycle
327
+ ```
328
+ pending → running → completed
329
+ ↘ failed
330
+ ↘ killed
331
+ ↘ timeout
332
+ ```
203
333
 
204
- 1. Go to [Slack API](https://api.slack.com/apps) Create New App → From scratch
205
- 2. Enable **Socket Mode** → copy App-Level Token (`xapp-...`)
206
- 3. OAuth & Permissions → copy Bot User OAuth Token (`xoxb-...`)
207
- 4. Subscribe to `app_mention` + `message.im` events
208
- 5. Add `/wispy` slash command
209
- 6. Run `wispy channel setup slack`
334
+ Sub-agent results persist to `~/.wispy/subagents/` for later retrieval.
210
335
 
211
- **Or** set env vars:
336
+ ---
337
+
338
+ ## 🔌 MCP Integration
339
+
340
+ Connect any [Model Context Protocol](https://modelcontextprotocol.io) server and Wispy will automatically use its tools.
341
+
342
+ ### Configuration
343
+ ```json
344
+ // ~/.wispy/mcp.json
345
+ {
346
+ "servers": {
347
+ "filesystem": {
348
+ "command": "npx",
349
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
350
+ },
351
+ "github": {
352
+ "command": "npx",
353
+ "args": ["-y", "@modelcontextprotocol/server-github"],
354
+ "env": { "GITHUB_TOKEN": "your_token" }
355
+ }
356
+ }
357
+ }
358
+ ```
359
+
360
+ ### MCP CLI
212
361
  ```bash
213
- export WISPY_SLACK_BOT_TOKEN=xoxb-...
214
- export WISPY_SLACK_APP_TOKEN=xapp-...
215
- wispy --slack
362
+ wispy mcp list # list configured servers
363
+ wispy mcp status # show connected servers and their tools
364
+ wispy mcp add # interactive server setup
216
365
  ```
217
366
 
218
- Triggers: `@mention`, DMs, `/wispy <message>` slash command.
367
+ ---
368
+
369
+ ## ⚙️ Configuration
370
+
371
+ All configuration lives in `~/.wispy/`:
219
372
 
220
- ### channels.json Config
373
+ ```
374
+ ~/.wispy/
375
+ ├── config.json — main config (provider, model, apiKey)
376
+ ├── channels.json — channel bot configuration
377
+ ├── mcp.json — MCP server configuration
378
+ ├── sessions/ — conversation history
379
+ ├── memory/ — long-term memory files
380
+ ├── cron/ — scheduler jobs and history
381
+ ├── subagents/ — sub-agent results
382
+ └── audit/ — audit log (JSONL per day)
383
+ ```
221
384
 
222
- Stored at `~/.wispy/channels.json`:
385
+ ### config.json reference
223
386
  ```json
224
387
  {
225
- "telegram": { "enabled": true, "token": "..." },
226
- "discord": { "enabled": true, "token": "..." },
227
- "slack": { "enabled": true, "botToken": "...", "appToken": "..." }
388
+ "provider": "google", // auto-detected if omitted
389
+ "model": "gemini-2.5-flash", // defaults to provider's default
390
+ "apiKey": "...", // env var takes precedence
391
+ "workstream": "default" // default workstream
228
392
  }
229
393
  ```
230
394
 
231
- ### Optional Dependencies
395
+ ### Environment variables
396
+ ```bash
397
+ WISPY_PROVIDER=google # force provider
398
+ WISPY_MODEL=gemini-2.5-flash # force model
399
+ WISPY_WORKSTREAM=myproject # set active workstream
400
+ WISPY_DEBUG=1 # enable debug output
401
+ ```
402
+
403
+ ---
232
404
 
233
- Channel adapters use peer dependencies — install only what you need:
405
+ ## 📂 Workstream Isolation
406
+
407
+ Workstreams let you maintain separate AI contexts for different projects.
234
408
 
235
409
  ```bash
236
- npm install grammy # Telegram
237
- npm install discord.js # Discord
238
- npm install @slack/bolt # Slack
410
+ wispy -w frontend # chat in "frontend" workstream
411
+ wispy -w backend # completely separate context
412
+ wispy overview # see all workstreams
239
413
  ```
240
414
 
241
- Each adapter gracefully fails with a helpful install message if the package isn't present.
415
+ Each workstream has its own:
416
+ - Conversation sessions
417
+ - Context/memory scope
418
+ - Sub-agent history
419
+
420
+ ---
421
+
422
+ ## 🏗️ Architecture
423
+
424
+ ```
425
+ ┌─────────────────────────────┐
426
+ │ WispyEngine │
427
+ │ core/engine.mjs │
428
+ │ processMessage() ─────────┐│
429
+ └─────────────────────────────┘│
430
+ │ │
431
+ ┌──────────────────────────┼──────────┐ │
432
+ │ │ │ │ │
433
+ REPL TUI channels server.mjs │
434
+ (bin/wispy) (bin/wispy-tui) (lib/channels/) │
435
+
436
+ ┌─────────────────────────┘
437
+
438
+ ┌───────────────────┼──────────────────────────┐
439
+ │ │ │
440
+ ProviderRegistry ToolRegistry SessionManager
441
+ core/providers.mjs core/tools.mjs core/session.mjs
442
+ (Gemini/Claude/ (18+ built-in + (file-based,
443
+ OpenAI/Groq/ MCP tools) per-channel)
444
+ DeepSeek/Ollama/
445
+ OpenRouter)
446
+
447
+ └── MemoryManager CronManager SubAgentManager
448
+ core/memory.mjs core/cron.mjs core/subagents.mjs
449
+ (~/.wispy/ (~/.wispy/ (~/.wispy/
450
+ memory/) cron/) subagents/)
451
+ ```
452
+
453
+ All surfaces (REPL, TUI, channels) call `WispyEngine.processMessage()` — one core, many interfaces.
454
+
455
+ ---
456
+
457
+ ## 🛠️ Development
458
+
459
+ ```bash
460
+ # Clone
461
+ git clone https://github.com/mindsurf0176-ui/poropo-workspace
462
+ cd wispy-cli
242
463
 
243
- ### Per-Chat Session Isolation
464
+ # Install
465
+ npm install
244
466
 
245
- Each chat/channel/DM gets its own conversation history stored in:
246
- `~/.wispy/channel-sessions/<channel>/<chatId>.json`
467
+ # Run tests (91 integration tests)
468
+ npm test
247
469
 
248
- No cross-contamination between users or channels.
470
+ # Development REPL
471
+ node bin/wispy.mjs
472
+ ```
249
473
 
250
- ## Architecture
474
+ ### Running tests
475
+ ```bash
476
+ npm test # run all integration tests
477
+ npm run test:verbose # run with spec reporter
478
+ npm run test:basic # run basic smoke tests only
479
+ ```
251
480
 
481
+ ### Project structure
482
+ ```
483
+ wispy-cli/
484
+ ├── bin/
485
+ │ ├── wispy.mjs — main CLI entry point
486
+ │ └── wispy-tui.mjs — TUI entry point (Ink)
487
+ ├── core/
488
+ │ ├── engine.mjs — WispyEngine (main chat loop)
489
+ │ ├── session.mjs — SessionManager
490
+ │ ├── providers.mjs — ProviderRegistry (7 AI providers)
491
+ │ ├── tools.mjs — ToolRegistry (18+ built-in tools)
492
+ │ ├── memory.mjs — MemoryManager
493
+ │ ├── cron.mjs — CronManager (scheduler)
494
+ │ ├── subagents.mjs — SubAgentManager
495
+ │ ├── mcp.mjs — MCP client/manager
496
+ │ ├── config.mjs — config loader + provider detection
497
+ │ └── index.mjs — public API exports
498
+ ├── lib/
499
+ │ ├── wispy-repl.mjs — REPL implementation
500
+ │ ├── wispy-tui.mjs — TUI implementation (Ink/React)
501
+ │ └── channels/
502
+ │ ├── index.mjs — ChannelManager
503
+ │ ├── telegram.mjs — Telegram adapter (grammY)
504
+ │ ├── discord.mjs — Discord adapter (discord.js)
505
+ │ ├── slack.mjs — Slack adapter (@slack/bolt)
506
+ │ └── base.mjs — ChannelAdapter base class
507
+ └── tests/
508
+ ├── core-engine.test.mjs
509
+ ├── core-session.test.mjs
510
+ ├── core-memory.test.mjs
511
+ ├── core-cron.test.mjs
512
+ ├── core-subagents.test.mjs
513
+ ├── core-tools.test.mjs
514
+ └── channels.test.mjs
252
515
  ```
253
- wispy (CLI REPL / TUI)
254
- ↕ Gemini/Claude/OpenAI API (tool calling)
255
- ↕ AWOS Server (auto-started, sandboxed tools)
256
- ↕ Local Node (macOS file/browser/app actions)
257
516
 
258
- wispy --serve (Channel Bot Mode)
259
- ↕ Telegram (grammY long polling)
260
- Discord (discord.js gateway)
261
- ↕ Slack (bolt socket mode)
262
- ↕ Gemini/Claude/OpenAI API (per-chat sessions)
517
+ ---
518
+
519
+ ## 📋 CLI Reference
520
+
521
+ ```
522
+ Usage: wispy [options] [command]
523
+
524
+ Commands:
525
+ wispy — start interactive REPL
526
+ wispy ask <message> — one-shot chat
527
+ wispy exec <message> — one-shot execution
528
+ wispy overview — show workstream overview
529
+ wispy sessions — list recent sessions
530
+ wispy memory <cmd> — manage long-term memory
531
+ wispy cron <cmd> — manage scheduled jobs
532
+ wispy channels <cmd> — manage channel bots
533
+ wispy mcp <cmd> — manage MCP servers
534
+ wispy server <cmd> — start/stop HTTP/WS server
535
+ wispy audit <cmd> — view audit log
536
+
537
+ Options:
538
+ -w, --workstream <name> — set active workstream
539
+ --session <id> — resume a specific session
540
+ --model <name> — override AI model
541
+ --provider <name> — override AI provider
542
+ --help — show help
543
+ --version — show version
263
544
  ```
264
545
 
265
- ## Requirements
546
+ ---
547
+
548
+ ## 🔑 API Keys
549
+
550
+ Get free/paid API keys from:
551
+ - **Google AI (Gemini)** — [aistudio.google.com/apikey](https://aistudio.google.com/apikey) *(free tier available)*
552
+ - **Anthropic (Claude)** — [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys)
553
+ - **OpenAI** — [platform.openai.com/api-keys](https://platform.openai.com/api-keys)
554
+ - **OpenRouter** — [openrouter.ai/keys](https://openrouter.ai/keys) *(free credits)*
555
+ - **Groq** — [console.groq.com/keys](https://console.groq.com/keys) *(free tier)*
556
+ - **DeepSeek** — [platform.deepseek.com/api_keys](https://platform.deepseek.com/api_keys)
557
+ - **Ollama** — [ollama.ai](https://ollama.ai) *(fully local, no key needed)*
558
+
559
+ ---
560
+
561
+ ## 📝 License
562
+
563
+ MIT — see [LICENSE](LICENSE)
564
+
565
+ ---
266
566
 
267
- - Node.js 20+
268
- - One API key (Google AI recommended for free tier)
269
- - macOS or Linux
567
+ ## 🙌 Credits
270
568
 
271
- ## License
569
+ Built by Minseo & Poropo 🫧
272
570
 
273
- Apache-2.0Minseo & Poropo 🌿
571
+ *Wispy is a small ghost that lives in terminals floating between code, files, and servers.*
package/core/cron.mjs CHANGED
@@ -119,6 +119,8 @@ export class CronManager {
119
119
  this._running = true;
120
120
  this._tick();
121
121
  this._timer = setInterval(() => this._tick(), TICK_INTERVAL_MS);
122
+ // unref() so the timer doesn't prevent the process from exiting
123
+ if (this._timer?.unref) this._timer.unref();
122
124
  console.error(`[wispy-cron] Scheduler started (checking every ${TICK_INTERVAL_MS / 1000}s)`);
123
125
  }
124
126
 
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "wispy-cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "🌿 Wispy — AI workspace assistant with multi-agent orchestration and multi-channel bot support",
5
- "license": "Apache-2.0",
5
+ "license": "MIT",
6
6
  "author": "Minseo & Poropo",
7
+ "homepage": "https://github.com/mindsurf0176-ui/poropo-workspace/tree/master/agent-workstream-os/wispy-cli#readme",
7
8
  "repository": {
8
9
  "type": "git",
9
- "url": "https://github.com/mindsurf0176-ui/poropo-workspace"
10
+ "url": "git+https://github.com/mindsurf0176-ui/poropo-workspace.git",
11
+ "directory": "agent-workstream-os/wispy-cli"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/mindsurf0176-ui/poropo-workspace/issues"
10
15
  },
11
16
  "keywords": [
12
17
  "ai",
@@ -19,13 +24,25 @@
19
24
  "gemini",
20
25
  "claude",
21
26
  "openai",
27
+ "groq",
28
+ "deepseek",
29
+ "ollama",
30
+ "openrouter",
22
31
  "tui",
23
32
  "ink",
24
33
  "telegram",
25
34
  "discord",
26
35
  "slack",
27
36
  "bot",
28
- "chatbot"
37
+ "chatbot",
38
+ "mcp",
39
+ "model-context-protocol",
40
+ "memory",
41
+ "cron",
42
+ "scheduler",
43
+ "subagent",
44
+ "terminal",
45
+ "repl"
29
46
  ],
30
47
  "type": "module",
31
48
  "bin": {
@@ -41,7 +58,9 @@
41
58
  ],
42
59
  "scripts": {
43
60
  "postinstall": "node scripts/postinstall.mjs",
44
- "test": "node --test test/basic.test.mjs"
61
+ "test": "node --test --test-force-exit --test-timeout=15000 tests/*.test.mjs",
62
+ "test:basic": "node --test --test-force-exit test/basic.test.mjs",
63
+ "test:verbose": "node --test --test-force-exit --test-timeout=15000 --test-reporter=spec tests/*.test.mjs"
45
64
  },
46
65
  "dependencies": {
47
66
  "cron-parser": "^5.5.0",
@@ -68,6 +87,6 @@
68
87
  }
69
88
  },
70
89
  "engines": {
71
- "node": ">=20.0.0"
90
+ "node": ">=18.0.0"
72
91
  }
73
92
  }