@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.
- package/LICENSE +21 -0
- package/README.md +457 -0
- package/bin/line-hive.js +44 -0
- package/dist/cli/config-writer.js +320 -0
- package/dist/cli/config-writer.js.map +1 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/init.js +85 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/prompts.js +35 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/cli/test-connection.js +135 -0
- package/dist/cli/test-connection.js.map +1 -0
- package/dist/cli/webhook-capture.js +31 -0
- package/dist/cli/webhook-capture.js.map +1 -0
- package/dist/config.js +62 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.js +15 -0
- package/dist/constants.js.map +1 -0
- package/dist/i18n.js +100 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/line/client.js +72 -0
- package/dist/line/client.js.map +1 -0
- package/dist/line/messages.js +217 -0
- package/dist/line/messages.js.map +1 -0
- package/dist/line/webhook.js +485 -0
- package/dist/line/webhook.js.map +1 -0
- package/dist/logger.js +5 -0
- package/dist/logger.js.map +1 -0
- package/dist/server.js +143 -0
- package/dist/server.js.map +1 -0
- package/dist/src/cli/config-writer.js +18 -0
- package/dist/src/cli/config-writer.js.map +1 -0
- package/dist/src/cli/init.js +11 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/prompts.js +38 -0
- package/dist/src/cli/prompts.js.map +1 -0
- package/dist/src/cli/webhook-capture.js +37 -0
- package/dist/src/cli/webhook-capture.js.map +1 -0
- package/dist/src/config.js +44 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/index.js +53 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/line/client.js +20 -0
- package/dist/src/line/client.js.map +1 -0
- package/dist/src/line/webhook.js +131 -0
- package/dist/src/line/webhook.js.map +1 -0
- package/dist/src/logger.js +11 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/server.js +140 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/store/messageStore.js +222 -0
- package/dist/src/store/messageStore.js.map +1 -0
- package/dist/src/store/statusStore.js +87 -0
- package/dist/src/store/statusStore.js.map +1 -0
- package/dist/src/tools/cancelWait.js +26 -0
- package/dist/src/tools/cancelWait.js.map +1 -0
- package/dist/src/tools/checkMessages.js +16 -0
- package/dist/src/tools/checkMessages.js.map +1 -0
- package/dist/src/tools/getReply.js +15 -0
- package/dist/src/tools/getReply.js.map +1 -0
- package/dist/src/tools/sendMessage.js +58 -0
- package/dist/src/tools/sendMessage.js.map +1 -0
- package/dist/src/tools/setStatus.js +23 -0
- package/dist/src/tools/setStatus.js.map +1 -0
- package/dist/src/tools/waitForReply.js +85 -0
- package/dist/src/tools/waitForReply.js.map +1 -0
- package/dist/src/types/index.js +3 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/store/messageStore.js +513 -0
- package/dist/store/messageStore.js.map +1 -0
- package/dist/store/statusStore.js +320 -0
- package/dist/store/statusStore.js.map +1 -0
- package/dist/tools/ask.js +240 -0
- package/dist/tools/ask.js.map +1 -0
- package/dist/tools/cancelWait.js +30 -0
- package/dist/tools/cancelWait.js.map +1 -0
- package/dist/tools/checkMessages.js +23 -0
- package/dist/tools/checkMessages.js.map +1 -0
- package/dist/tools/getReply.js +12 -0
- package/dist/tools/getReply.js.map +1 -0
- package/dist/tools/listAgents.js +25 -0
- package/dist/tools/listAgents.js.map +1 -0
- package/dist/tools/sendMessage.js +99 -0
- package/dist/tools/sendMessage.js.map +1 -0
- package/dist/tools/setStatus.js +48 -0
- package/dist/tools/setStatus.js.map +1 -0
- package/dist/tools/waitForReply.js +36 -0
- package/dist/tools/waitForReply.js.map +1 -0
- package/dist/tools/waitForReplyInternal.js +66 -0
- package/dist/tools/waitForReplyInternal.js.map +1 -0
- package/dist/tunnel.js +124 -0
- package/dist/tunnel.js.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/util/persistUserId.js.map +1 -0
- package/dist/util/sendWithTokenPool.js +51 -0
- package/dist/util/sendWithTokenPool.js.map +1 -0
- package/dist/util/sleep.js +5 -0
- package/dist/util/sleep.js.map +1 -0
- package/dist/util/toolHelpers.js +60 -0
- package/dist/util/toolHelpers.js.map +1 -0
- package/package.json +61 -0
- 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
|
package/bin/line-hive.js
ADDED
|
@@ -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();
|