@zoulabo/line-hive 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 (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +457 -0
  3. package/bin/line-hive.js +44 -0
  4. package/dist/cli/config-writer.js +320 -0
  5. package/dist/cli/config-writer.js.map +1 -0
  6. package/dist/cli/doctor.js.map +1 -0
  7. package/dist/cli/init.js +85 -0
  8. package/dist/cli/init.js.map +1 -0
  9. package/dist/cli/prompts.js +35 -0
  10. package/dist/cli/prompts.js.map +1 -0
  11. package/dist/cli/test-connection.js +135 -0
  12. package/dist/cli/test-connection.js.map +1 -0
  13. package/dist/cli/webhook-capture.js +31 -0
  14. package/dist/cli/webhook-capture.js.map +1 -0
  15. package/dist/config.js +62 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/constants.js +15 -0
  18. package/dist/constants.js.map +1 -0
  19. package/dist/i18n.js +100 -0
  20. package/dist/i18n.js.map +1 -0
  21. package/dist/index.js +126 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/line/client.js +72 -0
  24. package/dist/line/client.js.map +1 -0
  25. package/dist/line/messages.js +217 -0
  26. package/dist/line/messages.js.map +1 -0
  27. package/dist/line/webhook.js +485 -0
  28. package/dist/line/webhook.js.map +1 -0
  29. package/dist/logger.js +5 -0
  30. package/dist/logger.js.map +1 -0
  31. package/dist/server.js +143 -0
  32. package/dist/server.js.map +1 -0
  33. package/dist/src/cli/config-writer.js +18 -0
  34. package/dist/src/cli/config-writer.js.map +1 -0
  35. package/dist/src/cli/init.js +11 -0
  36. package/dist/src/cli/init.js.map +1 -0
  37. package/dist/src/cli/prompts.js +38 -0
  38. package/dist/src/cli/prompts.js.map +1 -0
  39. package/dist/src/cli/webhook-capture.js +37 -0
  40. package/dist/src/cli/webhook-capture.js.map +1 -0
  41. package/dist/src/config.js +44 -0
  42. package/dist/src/config.js.map +1 -0
  43. package/dist/src/index.js +53 -0
  44. package/dist/src/index.js.map +1 -0
  45. package/dist/src/line/client.js +20 -0
  46. package/dist/src/line/client.js.map +1 -0
  47. package/dist/src/line/webhook.js +131 -0
  48. package/dist/src/line/webhook.js.map +1 -0
  49. package/dist/src/logger.js +11 -0
  50. package/dist/src/logger.js.map +1 -0
  51. package/dist/src/server.js +140 -0
  52. package/dist/src/server.js.map +1 -0
  53. package/dist/src/store/messageStore.js +222 -0
  54. package/dist/src/store/messageStore.js.map +1 -0
  55. package/dist/src/store/statusStore.js +87 -0
  56. package/dist/src/store/statusStore.js.map +1 -0
  57. package/dist/src/tools/cancelWait.js +26 -0
  58. package/dist/src/tools/cancelWait.js.map +1 -0
  59. package/dist/src/tools/checkMessages.js +16 -0
  60. package/dist/src/tools/checkMessages.js.map +1 -0
  61. package/dist/src/tools/getReply.js +15 -0
  62. package/dist/src/tools/getReply.js.map +1 -0
  63. package/dist/src/tools/sendMessage.js +58 -0
  64. package/dist/src/tools/sendMessage.js.map +1 -0
  65. package/dist/src/tools/setStatus.js +23 -0
  66. package/dist/src/tools/setStatus.js.map +1 -0
  67. package/dist/src/tools/waitForReply.js +85 -0
  68. package/dist/src/tools/waitForReply.js.map +1 -0
  69. package/dist/src/types/index.js +3 -0
  70. package/dist/src/types/index.js.map +1 -0
  71. package/dist/store/messageStore.js +513 -0
  72. package/dist/store/messageStore.js.map +1 -0
  73. package/dist/store/statusStore.js +320 -0
  74. package/dist/store/statusStore.js.map +1 -0
  75. package/dist/tools/ask.js +240 -0
  76. package/dist/tools/ask.js.map +1 -0
  77. package/dist/tools/cancelWait.js +30 -0
  78. package/dist/tools/cancelWait.js.map +1 -0
  79. package/dist/tools/checkMessages.js +23 -0
  80. package/dist/tools/checkMessages.js.map +1 -0
  81. package/dist/tools/getReply.js +12 -0
  82. package/dist/tools/getReply.js.map +1 -0
  83. package/dist/tools/listAgents.js +25 -0
  84. package/dist/tools/listAgents.js.map +1 -0
  85. package/dist/tools/sendMessage.js +99 -0
  86. package/dist/tools/sendMessage.js.map +1 -0
  87. package/dist/tools/setStatus.js +48 -0
  88. package/dist/tools/setStatus.js.map +1 -0
  89. package/dist/tools/waitForReply.js +36 -0
  90. package/dist/tools/waitForReply.js.map +1 -0
  91. package/dist/tools/waitForReplyInternal.js +66 -0
  92. package/dist/tools/waitForReplyInternal.js.map +1 -0
  93. package/dist/tunnel.js +124 -0
  94. package/dist/tunnel.js.map +1 -0
  95. package/dist/types/index.js +2 -0
  96. package/dist/types/index.js.map +1 -0
  97. package/dist/util/persistUserId.js.map +1 -0
  98. package/dist/util/sendWithTokenPool.js +51 -0
  99. package/dist/util/sendWithTokenPool.js.map +1 -0
  100. package/dist/util/sleep.js +5 -0
  101. package/dist/util/sleep.js.map +1 -0
  102. package/dist/util/toolHelpers.js +60 -0
  103. package/dist/util/toolHelpers.js.map +1 -0
  104. package/package.json +61 -0
  105. package/templates/line-notification.instructions.md +105 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Kizuna Contributors
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,457 @@
1
+ <p align="center">
2
+ <img src="assets/logo-line-hive.svg" alt="LINE Hive logo" width="120">
3
+ </p>
4
+
5
+ <h1 align="center">LINE Hive — Connect Your AI Agents</h1>
6
+
7
+ <p align="center">
8
+ <strong>Stay connected to your AI coding agents from your phone.</strong><br>
9
+ An MCP server that bridges AI agents (Copilot, Cursor, Claude) to LINE Messaging — check progress, answer questions, and get alerts without touching your computer.
10
+ </p>
11
+
12
+ <p align="center">
13
+ <em>Works with VS Code Copilot · Cursor · Claude Code · Claude Desktop · any MCP client</em>
14
+ </p>
15
+
16
+ ---
17
+
18
+ **Why?** AI agents run long tasks, hit decisions, and need your input. Instead of watching your editor, LINE Hive lets you check status or reply from LINE on your phone — when it's convenient for you.
19
+
20
+ <!-- screenshot placeholder: LINE conversation showing status query + agent reply -->
21
+
22
+ ## Contents
23
+
24
+ - [Quick Start](#quick-start)
25
+ - [How It Works](#how-it-works)
26
+ - [Setup](#setup) — [LINE Account](#1-create-a-line-official-account) · [Webhook Tunnel](#2-set-up-a-webhook-tunnel) · [Install](#3-install-line-hive-in-your-project)
27
+ - [MCP Tools](#mcp-tools)
28
+ - [LINE Commands](#line-commands)
29
+ - [Limitations](#limitations)
30
+ - [Development](#development)
31
+ - [Troubleshooting](#troubleshooting)
32
+ - [Architecture](#architecture)
33
+
34
+ ## Quick Start
35
+
36
+ ```bash
37
+ # 1. Run interactive setup in your project
38
+ npx @zoulabo/line-hive init
39
+
40
+ # 2. Restart your editor — the MCP server starts automatically
41
+ ```
42
+
43
+ The wizard prompts for your LINE credentials, configures your editor, and installs agent instructions. You'll need a [LINE Official Account](#1-create-a-line-official-account) and a [webhook tunnel](#2-set-up-a-webhook-tunnel) (ngrok recommended, but any tunnel works) first.
44
+
45
+ Optional: verify your LINE API connection:
46
+ ```bash
47
+ npx @zoulabo/line-hive test
48
+ ```
49
+
50
+ ## How It Works
51
+
52
+ Your AI agent sets its status; you query it from LINE whenever you want. Replies are free (uses LINE's replyToken — no push quota consumed).
53
+
54
+ ```mermaid
55
+ sequenceDiagram
56
+ participant You as You (LINE)
57
+ participant Server as LINE Hive
58
+ participant Agent as AI Agent
59
+
60
+ Agent->>Server: set_status("working on tests")
61
+ You->>Server: "?"
62
+ Server-->>You: Working: tests
63
+
64
+ Agent->>Server: set_status("needs_input")
65
+ You->>Server: "yes"
66
+ Server-->>You: Got it
67
+ Server->>Agent: pending_reply: "yes"
68
+ ```
69
+
70
+ **Key benefits:**
71
+ - **Free status queries** — uses LINE replyToken (no push quota consumed)
72
+ - **Multi-agent** — multiple editor windows share one LINE bot, numbered list shows all
73
+ - **No spam** — you check when convenient, not interrupted by push notifications
74
+ - **Works offline** — status is stored in SQLite; LINE responds even when the agent is busy
75
+
76
+ ## Prerequisites
77
+
78
+ 1. A LINE Official Account with Messaging API enabled ([setup guide below](#1-create-a-line-official-account))
79
+ 2. A webhook tunnel — ngrok (recommended, auto-managed), or any tunnel to localhost:19780 ([options below](#2-set-up-a-webhook-tunnel))
80
+ 3. Node.js 18+
81
+
82
+ ## Setup
83
+
84
+ ### 1. Create a LINE Official Account
85
+
86
+ > Takes ~5 minutes. You need a browser + LINE app on your phone.
87
+
88
+ 1. Go to [LINE Developers Console](https://developers.line.biz/console/) → log in with your LINE account
89
+ 2. Create a **Provider** (just an org label) → Create a **Messaging API** channel
90
+ 3. Copy your credentials from the channel settings:
91
+ - **Channel Secret** — *Basic settings* tab
92
+ - **Channel Access Token** — *Messaging API* tab → click *Issue*
93
+ 4. Add the bot as a friend: scan the QR code in *Messaging API* → *Bot information*
94
+ 5. Disable auto-reply: *Messaging API* → *Auto-reply messages* → *Edit* → turn off both responses
95
+
96
+ > **Webhook URL** — you'll set this after configuring your tunnel (next step). Format: `https://YOUR-TUNNEL-URL/webhook`
97
+
98
+ ### 2. Set Up a Webhook Tunnel
99
+
100
+ LINE needs a public HTTPS URL to send webhook events. Any tunnel that forwards to `localhost:19780` works:
101
+
102
+ | Tool | Stable URL? | Setup |
103
+ |------|-------------|-------|
104
+ | **ngrok** (recommended) | Yes (free tier) | Built-in auto-management via `NGROK_DOMAIN` env var |
105
+ | **VS Code Ports** | Yes (devtunnels) | Built-in — Ports panel → Forward Port 19780 |
106
+ | **cloudflared** (quick) | No (random URL) | `cloudflared tunnel --url http://localhost:19780` |
107
+ | **cloudflared** (named) | Yes (own domain) | Requires Cloudflare domain |
108
+ | **localtunnel** | No | `npx localtunnel --port 19780` |
109
+ | **localhost.run** | No | `ssh -R 80:localhost:19780 localhost.run` |
110
+
111
+ **Using ngrok (recommended):**
112
+
113
+ ngrok is recommended because the MCP server can auto-manage it — when `NGROK_DOMAIN` is set, the tunnel starts and auto-restarts alongside the webhook server. Other tunnels work fine but must be started manually.
114
+
115
+ 1. Sign up at [ngrok.com](https://ngrok.com/) (free tier works)
116
+ 2. Install the CLI:
117
+ ```bash
118
+ # macOS
119
+ brew install ngrok
120
+
121
+ # or download from https://ngrok.com/download
122
+ ```
123
+ 3. Authenticate:
124
+ ```bash
125
+ ngrok config add-authtoken YOUR_AUTH_TOKEN
126
+ ```
127
+ (Find your token at [dashboard.ngrok.com/get-started/your-authtoken](https://dashboard.ngrok.com/get-started/your-authtoken))
128
+ 4. **Claim a free stable domain**:
129
+ - Go to [dashboard.ngrok.com/domains](https://dashboard.ngrok.com/domains)
130
+ - Click *Create Domain* — you'll get something like `your-app-name.ngrok-free.dev`
131
+ - A stable domain means the URL doesn't change between restarts (no need to update LINE Console every time)
132
+
133
+ **Using a different tunnel:**
134
+
135
+ Start your tunnel manually before or after the MCP server. The webhook server listens on port 19780 regardless. Just skip setting `NGROK_DOMAIN` and the MCP server won't try to spawn ngrok.
136
+
137
+ **Set the webhook URL in LINE Console:**
138
+
139
+ 5. Go back to your channel in [LINE Developers Console](https://developers.line.biz/console/)
140
+ 6. *Messaging API* → *Webhook URL* → set to `https://YOUR-TUNNEL-URL/webhook`
141
+ 7. Toggle *Use webhook* → **On**
142
+ 8. Click *Verify* — it will fail until the MCP server is running (that's OK)
143
+
144
+ ### 3. Install LINE Hive in Your Project
145
+
146
+ ```bash
147
+ # Interactive setup (prompts for editor choice)
148
+ npx @zoulabo/line-hive init
149
+
150
+ # Or specify your editor directly:
151
+ npx @zoulabo/line-hive init --editor cursor
152
+ npx @zoulabo/line-hive init --editor claude-code
153
+ npx @zoulabo/line-hive init --editor claude-desktop
154
+ ```
155
+
156
+ The init wizard will:
157
+ 1. Ask which AI agent you're using (VS Code Copilot, Cursor, Claude Code, or Claude Desktop)
158
+ 2. Generate the appropriate config file
159
+ 3. Install the LINE instruction file (teaches AI agents how to use the LINE tools)
160
+ 4. Run a diagnostic check to verify your setup
161
+
162
+ This generates editor-specific config files:
163
+
164
+ | Editor | Config File | Credential Handling |
165
+ |--------|------------|-------------------|
166
+ | VS Code | `.vscode/mcp.json` | Prompted at startup (no secrets on disk) |
167
+ | Cursor | `.vscode/mcp.json` | Prompted at startup (no secrets on disk) |
168
+ | Claude Code | `.mcp.json` | Uses `${VAR}` env var expansion |
169
+ | Claude Desktop | `~/...Claude/claude_desktop_config.json` | Edit config file manually |
170
+
171
+ All editors also get a project-level instruction file that teaches AI agents how to use the LINE tools:
172
+ - **VS Code / Cursor / Claude Desktop**: `.github/instructions/line-notification.instructions.md`
173
+ - **Claude Code**: `.claude/rules/line-notification.md` (auto-loaded by Claude Code's rules system)
174
+
175
+ > **Note**: If you use Claude Code as a VS Code or Cursor extension, pass `--editor claude-code` (not `--editor vscode`). The `--editor` flag selects the AI agent's config format, not the editor application.
176
+
177
+ **VS Code / Cursor** — no secrets on disk. Credentials use `${input:}` placeholders. The editor prompts for them each session.
178
+
179
+ Restart your editor after init. You'll be prompted for:
180
+ - **LINE Channel Access Token** — from step 1
181
+ - **LINE Channel Secret** — from step 1
182
+ - **ngrok domain** — from step 2 (leave empty to skip tunnel)
183
+
184
+ The MCP server starts automatically, including the webhook server and ngrok tunnel.
185
+
186
+ ### Manual Configuration (without init wizard)
187
+
188
+ If you prefer manual setup or use a different MCP client:
189
+
190
+ <details>
191
+ <summary>Claude Code (.mcp.json)</summary>
192
+
193
+ Create `.mcp.json` in your project root:
194
+ ```json
195
+ {
196
+ "mcpServers": {
197
+ "line-hive": {
198
+ "command": "npx",
199
+ "args": ["line-hive"],
200
+ "env": {
201
+ "LINE_CHANNEL_ACCESS_TOKEN": "${LINE_CHANNEL_ACCESS_TOKEN}",
202
+ "LINE_CHANNEL_SECRET": "${LINE_CHANNEL_SECRET}",
203
+ "NGROK_DOMAIN": "${NGROK_DOMAIN:-}",
204
+ "WORKSPACE_PATH": "/path/to/your/project"
205
+ }
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ Set credentials in your shell profile, or use `claude mcp add` for secure storage:
212
+ ```bash
213
+ claude mcp add --transport stdio \
214
+ --env LINE_CHANNEL_ACCESS_TOKEN=your-token \
215
+ --env LINE_CHANNEL_SECRET=your-secret \
216
+ --env NGROK_DOMAIN=your-domain.ngrok-free.dev \
217
+ --env WORKSPACE_PATH=/path/to/your/project \
218
+ line-hive -- npx @zoulabo/line-hive
219
+ ```
220
+
221
+ Also install instructions: copy `templates/line-notification.instructions.md` to `.claude/rules/line-notification.md`.
222
+ </details>
223
+
224
+ <details>
225
+ <summary>Claude Desktop (claude_desktop_config.json)</summary>
226
+
227
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%/Claude/claude_desktop_config.json` (Windows):
228
+ ```json
229
+ {
230
+ "mcpServers": {
231
+ "line-hive": {
232
+ "command": "npx",
233
+ "args": ["line-hive"],
234
+ "env": {
235
+ "LINE_CHANNEL_ACCESS_TOKEN": "your-token",
236
+ "LINE_CHANNEL_SECRET": "your-secret",
237
+ "NGROK_DOMAIN": "your-domain.ngrok-free.dev",
238
+ "WORKSPACE_PATH": "/path/to/your/project"
239
+ }
240
+ }
241
+ }
242
+ }
243
+ ```
244
+ </details>
245
+
246
+ <details>
247
+ <summary>Any MCP Client (stdio)</summary>
248
+
249
+ The server uses stdio transport (stdin/stdout for MCP JSON-RPC). Configure your client to run:
250
+ ```bash
251
+ npx @zoulabo/line-hive
252
+ ```
253
+ With these environment variables:
254
+ - `LINE_CHANNEL_ACCESS_TOKEN` — required
255
+ - `LINE_CHANNEL_SECRET` — required
256
+ - `WORKSPACE_PATH` — recommended (for agent naming)
257
+ - `NGROK_DOMAIN` — optional (enables webhook tunnel)
258
+ </details>
259
+
260
+ ## MCP Tools
261
+
262
+ | Tool | Purpose | Blocking |
263
+ |------|---------|----------|
264
+ | `line_set_status` | Set agent description + name (status auto-derived) | No |
265
+ | `line_ask` | Send message + wait for reply (single tool call) | Yes |
266
+ | `line_send_message` | Push message to LINE (use sparingly — costs quota) | Yes (default) |
267
+ | `line_check_messages` | Fetch unclaimed inbound messages | No |
268
+ | `line_list_agents` | List all active agents across editor windows | No |
269
+
270
+ ### Recommended Pattern
271
+
272
+ ```
273
+ 1. line_set_status({ description: "Running tests...", agentName: "Nova" }) → auto-status: working
274
+ 2. line_ask({ text: "3 tests failed. Fix?", agentName: "Nova" }) → auto-status: needs_input
275
+ → user replies → auto-status: working
276
+ 3. line_set_status({ description: "Applying fixes..." }) → auto-status: working
277
+ 4. line_set_status({}) → auto-status: idle
278
+ ```
279
+
280
+ **Auto-status values**: `idle` | `working` | `needs_input` | `error` — the `status` parameter is not user-settable.
281
+
282
+ ## LINE Commands
283
+
284
+ Send these to your LINE bot:
285
+
286
+ | Command | Action |
287
+ |---------|--------|
288
+ | `status` / `s` / `?` | Show all agents with status |
289
+ | A number (e.g. `2`) | Select that agent (always — never forwarded to agents) |
290
+ | Any other text | Route to targeted/waiting agent |
291
+ | ▶️ Continue (button) | Send a reply token to keep the conversation going |
292
+ | 📊 Status (button) | Same as `?` |
293
+ | 📬 N more (button) | Pop all queued messages to the agent at once |
294
+
295
+ ## Limitations
296
+
297
+ ### LINE Messaging API
298
+
299
+ - **Push message quota** — free tier allows 200 push messages/month. Status queries via replyToken are free and unlimited. The server uses reply token pooling to minimize push usage. `line_ask` prefers reply tokens but falls back to push when none are available.
300
+ - **Reply token expiry** — tokens expire after ~15 minutes (empirically tested). The server pools and reuses them aggressively, but if no user interaction happens for a while, it falls back to push messages.
301
+ - **Single webhook URL** — LINE allows only one webhook URL per channel. All agent instances must share the same tunnel endpoint.
302
+ - **Text-only messages** — the server currently handles text messages only. Images, stickers, and rich media are ignored.
303
+ - **One user** — designed for single-developer use. The bot interacts with one LINE user (auto-registered on first message).
304
+
305
+ ### Multi-Workspace
306
+
307
+ - **Shared tunnel** — only the first editor window to start claims the webhook port and ngrok tunnel. Other windows connect to the same shared SQLite DB and piggyback on the existing webhook/tunnel.
308
+ - **Shared credentials** — all workspaces use the same LINE channel. There's no per-workspace channel isolation.
309
+ - **First-wins lifecycle** — if the first window is closed, the webhook server and tunnel stop. Other windows keep running (MCP tools still work via push messages) but webhook-based features (free replies, real-time routing) are unavailable until a window restarts and claims the port.
310
+
311
+ ### Webhook Tunnel
312
+
313
+ - **Any tunnel works** — the webhook server is a standard HTTP server on port 19780. Use ngrok, cloudflared, VS Code Ports, localtunnel, or any reverse tunnel.
314
+ - **ngrok auto-managed** — when `NGROK_DOMAIN` is set, the server spawns and auto-restarts ngrok as a child process. Other tunnels must be started manually.
315
+ - **ngrok free tier limits** — one stable domain, rate limits. Paid plan removes these.
316
+ - **Stable URL recommended** — without a stable domain/URL, you need to update the LINE Console webhook URL on every restart.
317
+
318
+ ### Claude Code
319
+
320
+ - **`MCP_TOOL_TIMEOUT`** — Claude Code enforces a timeout on individual MCP tool calls. `line_ask` can block for up to 2 hours waiting for user replies. If `MCP_TOOL_TIMEOUT` is set to a shorter value, `line_ask` calls may be terminated prematurely. Consider using the poll-centric flow (`line_set_status` + `line_check_messages`) if you hit timeout issues.
321
+ - **`--editor claude-code` required** — auto-detection of Claude Code is best-effort. Always pass `--editor claude-code` explicitly when running the init wizard. This applies whether you use Claude Code as a CLI tool, a VS Code extension, or a Cursor extension.
322
+ - **Instructions location** — Claude Code reads `.claude/rules/`, not `.github/instructions/`. The init wizard writes to the correct location based on the `--editor` flag.
323
+
324
+ ## Development
325
+
326
+ For contributing or running from source:
327
+
328
+ ```bash
329
+ git clone https://github.com/zoulabo/line-hive && cd line-hive
330
+ npm install && npm run build
331
+
332
+ npm run build # Compile TypeScript
333
+ npm run watch # Watch mode
334
+ npm test # Run tests (vitest)
335
+ npm start # Start standalone server
336
+ ```
337
+
338
+ ### CLI Commands
339
+
340
+ ```bash
341
+ npx @zoulabo/line-hive init [--editor ...] # Setup or update project config
342
+ npx @zoulabo/line-hive test # Test LINE API connection
343
+ ```
344
+
345
+ ### Updating
346
+
347
+ ```bash
348
+ npm update @zoulabo/line-hive # Update the package
349
+ npx @zoulabo/line-hive init # Refresh config files and instruction templates
350
+ ```
351
+
352
+ Re-running `init` is safe — it overwrites templates with the latest version while preserving your mcp.json credentials (prompted inputs).
353
+
354
+ ### Environment Variables
355
+
356
+ For standalone `npm start` (not needed when running via VS Code MCP):
357
+
358
+ ```bash
359
+ LINE_CHANNEL_ACCESS_TOKEN= # From LINE Developers Console
360
+ LINE_CHANNEL_SECRET= # For webhook signature verification
361
+ NGROK_DOMAIN= # Optional — enables auto-managed ngrok tunnel
362
+ # Omit if using a different tunnel (cloudflared, VS Code Ports, etc.)
363
+ WEBHOOK_PORT=19780
364
+ WEBHOOK_PATH=/webhook
365
+ SQLITE_PATH=~/.line-hive/line-hive.db
366
+ ```
367
+
368
+ ### Project Structure
369
+
370
+ ```
371
+ src/
372
+ ├── index.ts # Entry point
373
+ ├── server.ts # MCP server + tool handlers
374
+ ├── config.ts # Environment config
375
+ ├── logger.ts # Pino (stderr only — stdout is MCP)
376
+ ├── tunnel.ts # ngrok tunnel management
377
+ ├── cli/
378
+ │ ├── init.ts # Setup wizard
379
+ │ ├── test-connection.ts # LINE API connection test
380
+ │ ├── config-writer.ts # Generates mcp.json + instructions
381
+ │ └── webhook-capture.ts # Temp server to capture userId
382
+ ├── tools/ # MCP tool implementations
383
+ ├── line/
384
+ │ ├── client.ts # LINE API client
385
+ │ ├── messages.ts # Message builders, quick reply, postback
386
+ │ └── webhook.ts # Webhook handler + status responder
387
+ ├── store/
388
+ │ ├── messageStore.ts # Message persistence (SQLite)
389
+ │ └── statusStore.ts # Agent status management
390
+ ├── util/
391
+ │ └── sendWithTokenPool.ts # Reply token pool → push fallback
392
+ └── types/
393
+ └── index.ts
394
+ ```
395
+
396
+ ## Troubleshooting
397
+
398
+ <details>
399
+ <summary><b>MCP server fails to start</b></summary>
400
+
401
+ Run `npx @zoulabo/line-hive test` to diagnose. Common causes:
402
+ - **Missing credentials** — `LINE_CHANNEL_ACCESS_TOKEN` or `LINE_CHANNEL_SECRET` not set. VS Code/Cursor prompt at startup; Claude Code needs env vars.
403
+ - **Port 19780 in use** — Another process is using the webhook port. Kill it: `lsof -ti :19780 | xargs kill`
404
+ - **Node.js < 18** — Requires Node.js 18+.
405
+ </details>
406
+
407
+ <details>
408
+ <summary><b>LINE bot doesn't respond to messages</b></summary>
409
+
410
+ 1. Run `npx @zoulabo/line-hive test` to verify API connection
411
+ 2. Check that the webhook URL is set in [LINE Developers Console](https://developers.line.biz/console/) → *Messaging API* → *Webhook URL*
412
+ 3. Verify *Use webhook* is toggled **On**
413
+ 4. Make sure auto-reply is **disabled**: *Messaging API* → *Auto-reply messages* → *Edit* → turn off both responses
414
+ 5. Ensure the MCP server is running (check your editor's MCP status)
415
+ </details>
416
+
417
+ <details>
418
+ <summary><b>Claude Code: "which --editor should I use?"</b></summary>
419
+
420
+ Use `--editor claude-code` whether you're running Claude Code as:
421
+ - A standalone CLI tool
422
+ - A VS Code extension
423
+ - A Cursor extension
424
+
425
+ Don't use `--editor vscode` — that's for GitHub Copilot.
426
+ </details>
427
+
428
+ <details>
429
+ <summary><b>Reply tokens expire / push message quota exceeded</b></summary>
430
+
431
+ - Reply tokens expire after ~15 minutes. The server pools them aggressively but falls back to push messages when none are available.
432
+ - Free tier: 200 push messages/month. Status queries via `?` are free (use reply tokens).
433
+ - Tip: Send `?` in LINE periodically to replenish the token pool.
434
+ </details>
435
+
436
+ <details>
437
+ <summary><b>ngrok tunnel not starting</b></summary>
438
+
439
+ 1. Confirm ngrok is installed: `ngrok version`
440
+ 2. Check auth: `ngrok config check`
441
+ 3. Set `NGROK_DOMAIN` env var to your stable domain
442
+ 4. The tunnel auto-starts with the MCP server — only one instance can run the tunnel.
443
+ </details>
444
+
445
+ ## Architecture
446
+
447
+ - **SQLite** (WAL mode) shared across all agent instances at `~/.line-hive/line-hive.db`
448
+ - **Heartbeat** every 10s — dead agents auto-cleaned after 2 min
449
+ - **Reply token pooling** — webhook saves tokens for free replies (saves push quota)
450
+ - **Session correlation** — `line_ask` creates a session, webhook fulfills it on reply
451
+ - **Multi-agent routing** — user selects agent by number, or auto-routes to `needs_input` agent
452
+ - **Embedded tunnel** — ngrok auto-managed as child process (optional; any tunnel to localhost:19780 works)
453
+ - **Cross-platform** — works on macOS, Linux, and Windows
454
+
455
+ ## License
456
+
457
+ MIT
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from "node:path";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ async function run() {
10
+ const args = process.argv.slice(2);
11
+ const command = args[0];
12
+
13
+ if (command === "init") {
14
+ // Usage: line-hive init [projectDir] [--editor vscode|cursor|claude-code|claude-desktop]
15
+ const editorIdx = args.indexOf("--editor");
16
+ const editor = editorIdx !== -1 && args[editorIdx + 1] ? args[editorIdx + 1] : undefined;
17
+ // Project dir is first positional arg after "init" that isn't a flag or flag value
18
+ const positional = args.slice(1).filter((a, i) => {
19
+ if (a.startsWith("--")) return false;
20
+ const origIdx = i + 1; // offset for args (since we sliced from 1)
21
+ return origIdx !== editorIdx + 1; // skip the value after --editor
22
+ });
23
+ const projectDir = positional[0] || process.cwd();
24
+ const modulePath = path.join(__dirname, "..", "dist", "cli", "init.js");
25
+ const moduleUrl = pathToFileURL(modulePath).href;
26
+ const mod = await import(moduleUrl);
27
+ await mod.runCli(path.resolve(projectDir), editor);
28
+ return;
29
+ }
30
+
31
+ if (command === "test") {
32
+ const modulePath = path.join(__dirname, "..", "dist", "cli", "test-connection.js");
33
+ const moduleUrl = pathToFileURL(modulePath).href;
34
+ const mod = await import(moduleUrl);
35
+ await mod.runTestConnection();
36
+ return;
37
+ }
38
+
39
+ const modulePath = path.join(__dirname, "..", "dist", "index.js");
40
+ const moduleUrl = pathToFileURL(modulePath).href;
41
+ await import(moduleUrl);
42
+ }
43
+
44
+ run();