multi-project-gateway 0.2.0 → 0.4.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/README.md +285 -20
- package/dist/cli.js +889 -69
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,17 +5,23 @@ A Discord bot that routes channel messages to per-project [Claude Code](https://
|
|
|
5
5
|
## How it works
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
Discord channel --> Router --> Session Manager --> claude --print
|
|
9
|
-
(per project)
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
Discord channel --> Router --> Agent Dispatch --> Session Manager --> claude --print
|
|
9
|
+
(per project) (channel -> (@mention -> (queue, resume, (in project dir)
|
|
10
|
+
project) agent) persist) |
|
|
11
|
+
^ |
|
|
12
|
+
|--- auto-handoff if response has @mention <-'
|
|
13
|
+
|
|
|
14
|
+
Discord reply <-- Chunker <-------------------------- JSON response <--------'
|
|
12
15
|
```
|
|
13
16
|
|
|
14
17
|
1. User posts a message in a mapped Discord channel
|
|
15
18
|
2. Router resolves the channel to a project config
|
|
16
|
-
3.
|
|
17
|
-
4.
|
|
18
|
-
5.
|
|
19
|
+
3. If the message is in a main channel, the bot creates a thread for the response; if already in a thread, replies there directly
|
|
20
|
+
4. If agents are configured, agent dispatch routes via `@mention` or last active agent
|
|
21
|
+
5. Session manager spawns `claude --print` in the project directory (or resumes an existing session)
|
|
22
|
+
6. If the response contains an `@mention` of another agent, auto-handoff loops until done or turn limit reached
|
|
23
|
+
7. Response is chunked to fit Discord's 2000-char limit and sent back in the thread
|
|
24
|
+
8. Sessions persist to disk and resume across gateway restarts
|
|
19
25
|
|
|
20
26
|
## Security model
|
|
21
27
|
|
|
@@ -28,9 +34,57 @@ By default, each Claude session is restricted to its project directory using `--
|
|
|
28
34
|
**Important considerations:**
|
|
29
35
|
- Anyone who can post in a mapped Discord channel can instruct Claude to read and modify files in that project's directory
|
|
30
36
|
- Only map channels that trusted users have access to
|
|
31
|
-
-
|
|
37
|
+
- Tool restrictions are enforced via `--allowed-tools` / `--disallowed-tools` (see [Tool security](#tool-security))
|
|
32
38
|
- For maximum access (e.g., in a sandboxed environment), you can set `claudeArgs` to use `--dangerously-skip-permissions`, but this gives Claude full OS-level access
|
|
33
39
|
|
|
40
|
+
### Tool security
|
|
41
|
+
|
|
42
|
+
The gateway restricts which tools Claude can use via `--allowed-tools` and `--disallowed-tools` CLI flags. By default, only safe file-system and read-only tools are allowed.
|
|
43
|
+
|
|
44
|
+
**Default allowlist:**
|
|
45
|
+
|
|
46
|
+
| Tool | Description | Security implications |
|
|
47
|
+
|------|-------------|----------------------|
|
|
48
|
+
| `Read` | Read file contents | Read-only. Can read any file in the project directory. |
|
|
49
|
+
| `Edit` | Edit existing files (patch-based) | Can modify existing files. Cannot create new files. |
|
|
50
|
+
| `Write` | Create or overwrite files | Can create new files or overwrite existing ones. |
|
|
51
|
+
| `Glob` | Find files by pattern | Read-only directory listing. Low risk. |
|
|
52
|
+
| `Grep` | Search file contents | Read-only content search. Low risk. |
|
|
53
|
+
| `Bash(git:*)` | Run git commands only | Restricted to `git` subcommands. Can commit, push, branch. Cannot run arbitrary shell commands. |
|
|
54
|
+
| `TodoWrite` | Write to Claude's internal todo list | No file-system side effects. |
|
|
55
|
+
|
|
56
|
+
**Tools NOT in the default allowlist (higher risk):**
|
|
57
|
+
|
|
58
|
+
| Tool | Risk | Why it is excluded |
|
|
59
|
+
|------|------|--------------------|
|
|
60
|
+
| `Bash` (unrestricted) | **High** | Full shell access: can run any command, install packages, access network, modify system files. |
|
|
61
|
+
| `WebSearch` / `WebFetch` | **Medium** | Network access: can exfiltrate data or fetch untrusted content. |
|
|
62
|
+
| `NotebookEdit` | **Low** | Jupyter notebook editing. Excluded for simplicity; add if needed. |
|
|
63
|
+
|
|
64
|
+
**Configuration examples:**
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"defaults": {
|
|
69
|
+
"allowedTools": ["Read", "Edit", "Write", "Glob", "Grep", "Bash(git:*)", "TodoWrite"]
|
|
70
|
+
},
|
|
71
|
+
"projects": {
|
|
72
|
+
"TRUSTED_PROJECT_CHANNEL": {
|
|
73
|
+
"directory": "/path/to/trusted-project",
|
|
74
|
+
"allowedTools": ["Read", "Edit", "Write", "Glob", "Grep", "Bash", "TodoWrite"]
|
|
75
|
+
},
|
|
76
|
+
"READ_ONLY_CHANNEL": {
|
|
77
|
+
"directory": "/path/to/sensitive-project",
|
|
78
|
+
"allowedTools": ["Read", "Glob", "Grep"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Override precedence:** per-project `allowedTools`/`disallowedTools` override gateway defaults. If both `allowedTools` and `disallowedTools` are set at the same level, `allowedTools` takes precedence (a warning is logged). If `claudeArgs` (at either the gateway or project level) already contains `--allowed-tools` or `--disallowed-tools`, the config-based tool restrictions are skipped to avoid conflicts.
|
|
85
|
+
|
|
86
|
+
> **Disallow-only mode:** When a project sets only `disallowedTools` without setting `allowedTools`, the gateway-level `allowedTools` default still applies (via fallback). This means the project inherits the default allowlist _and_ adds its disallow rules on top — but since `allowedTools` takes precedence over `disallowedTools`, the disallow list is effectively ignored. To use disallow-only mode (block specific tools while allowing everything else), explicitly set `"allowedTools": []` at the project level to clear the inherited allowlist.
|
|
87
|
+
|
|
34
88
|
## Prerequisites
|
|
35
89
|
|
|
36
90
|
- **Node.js** 20+
|
|
@@ -46,9 +100,10 @@ By default, each Claude session is restricted to its project directory using `--
|
|
|
46
100
|
3. Go to **Bot** in the sidebar
|
|
47
101
|
4. Click **Reset Token** and copy the token (you'll need it in step 3)
|
|
48
102
|
5. Enable **Message Content Intent** under Privileged Gateway Intents
|
|
49
|
-
6.
|
|
50
|
-
7.
|
|
51
|
-
8.
|
|
103
|
+
6. If you plan to use **role-based access control** (`allowedRoles` in config), also enable the **Server Members Intent** (GuildMembers) under Privileged Gateway Intents. This is required for the bot to read member roles.
|
|
104
|
+
7. Go to **OAuth2 > URL Generator**, select the `bot` scope
|
|
105
|
+
8. Under Bot Permissions, select: **Send Messages**, **Read Message History**, **Add Reactions**
|
|
106
|
+
9. Copy the generated URL and open it in your browser to invite the bot to your server
|
|
52
107
|
|
|
53
108
|
### 2. Create Discord channels for your projects
|
|
54
109
|
|
|
@@ -61,11 +116,17 @@ npm install -g multi-project-gateway
|
|
|
61
116
|
mpg init
|
|
62
117
|
```
|
|
63
118
|
|
|
119
|
+
This creates `.env` and `config.json` in the current directory. To store config centrally in `~/.mpg/` instead (recommended for worktrees and multi-config setups):
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
mpg init --profile default
|
|
123
|
+
```
|
|
124
|
+
|
|
64
125
|
The init wizard will:
|
|
65
126
|
- Check that `claude` CLI is available
|
|
66
127
|
- Ask for your Discord bot token
|
|
67
128
|
- Walk you through adding projects (name, directory path, channel ID)
|
|
68
|
-
- Generate `config.json` and `.env`
|
|
129
|
+
- Generate `config.json` and `.env` (in CWD or `~/.mpg/profiles/<name>/` when using `--profile`)
|
|
69
130
|
|
|
70
131
|
Or set up manually by cloning:
|
|
71
132
|
|
|
@@ -105,9 +166,11 @@ Create `config.json`:
|
|
|
105
166
|
### 4. Start the gateway
|
|
106
167
|
|
|
107
168
|
```bash
|
|
108
|
-
mpg start
|
|
169
|
+
mpg start # if installed globally (uses default profile or CWD)
|
|
170
|
+
mpg start --profile dev # use a named profile from ~/.mpg/
|
|
171
|
+
mpg start --config /path/to/config.json # use an explicit config file
|
|
109
172
|
# or
|
|
110
|
-
npm run dev
|
|
173
|
+
npm run dev # development (no build step)
|
|
111
174
|
# or
|
|
112
175
|
npm run build && npm start # production
|
|
113
176
|
```
|
|
@@ -132,9 +195,79 @@ Commands:
|
|
|
132
195
|
start Start the gateway (default)
|
|
133
196
|
init Interactive setup wizard
|
|
134
197
|
status Show session status from disk
|
|
198
|
+
logs Show structured gateway logs
|
|
135
199
|
help Show help
|
|
200
|
+
|
|
201
|
+
Options:
|
|
202
|
+
--profile <name> Use a named profile (default: "default")
|
|
203
|
+
--config <path> Use a specific config.json path
|
|
204
|
+
--migrate Copy CWD config files into ~/.mpg/profiles/default/
|
|
205
|
+
--level <level> (logs) Filter by minimum log level (debug|info|warn|error)
|
|
136
206
|
```
|
|
137
207
|
|
|
208
|
+
## Config home (`~/.mpg/`)
|
|
209
|
+
|
|
210
|
+
By default, mpg resolves configuration from the current working directory. For multi-worktree setups or dev/prod separation, you can use a centralized config home at `~/.mpg/` (overridable via the `MPG_HOME` environment variable).
|
|
211
|
+
|
|
212
|
+
### Directory layout
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
~/.mpg/
|
|
216
|
+
├── .env # shared secrets (bot token)
|
|
217
|
+
├── profiles/
|
|
218
|
+
│ ├── default/
|
|
219
|
+
│ │ ├── config.json # project/channel config
|
|
220
|
+
│ │ └── sessions.json # runtime session state
|
|
221
|
+
│ └── dev/
|
|
222
|
+
│ ├── config.json
|
|
223
|
+
│ └── sessions.json
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Resolution order
|
|
227
|
+
|
|
228
|
+
**`.env` / secrets:**
|
|
229
|
+
1. Environment variables (already set) — highest priority
|
|
230
|
+
2. `$MPG_HOME/.env`
|
|
231
|
+
3. `$CWD/.env` — lowest priority, backward compat
|
|
232
|
+
|
|
233
|
+
**`config.json`:**
|
|
234
|
+
1. `--config <path>` CLI flag
|
|
235
|
+
2. `--profile <name>` resolves to `$MPG_HOME/profiles/<name>/config.json`
|
|
236
|
+
3. `$MPG_HOME/profiles/default/config.json`
|
|
237
|
+
4. `$CWD/config.json` — backward compat fallback
|
|
238
|
+
|
|
239
|
+
**`sessions.json`:** Always co-located with the resolved `config.json` (same directory).
|
|
240
|
+
|
|
241
|
+
### Setting up profiles
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# Create a profile using the init wizard
|
|
245
|
+
mpg init --profile default
|
|
246
|
+
|
|
247
|
+
# Create a dev profile
|
|
248
|
+
mpg init --profile dev
|
|
249
|
+
|
|
250
|
+
# Start with a specific profile
|
|
251
|
+
mpg start --profile dev
|
|
252
|
+
|
|
253
|
+
# Or point to an explicit config file
|
|
254
|
+
mpg start --config /path/to/config.json
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Migrating from CWD-based setup
|
|
258
|
+
|
|
259
|
+
If you already have `.env`, `config.json`, and `.sessions.json` in your current directory:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
mpg init --migrate
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
This copies your CWD files into `~/.mpg/profiles/default/` and prints what it did. The original files are left in place, so nothing breaks. No automatic migration is performed.
|
|
266
|
+
|
|
267
|
+
### Backward compatibility
|
|
268
|
+
|
|
269
|
+
If `~/.mpg/` does not exist and CWD files do, everything works exactly as before — zero breaking change.
|
|
270
|
+
|
|
138
271
|
## Configuration
|
|
139
272
|
|
|
140
273
|
### `config.json`
|
|
@@ -144,16 +277,102 @@ Commands:
|
|
|
144
277
|
| `defaults.idleTimeoutMs` | number | `1800000` (30 min) | Session idle timeout before cleanup |
|
|
145
278
|
| `defaults.maxConcurrentSessions` | number | `4` | Max concurrent Claude processes |
|
|
146
279
|
| `defaults.claudeArgs` | string[] | `["--permission-mode", "acceptEdits", "--output-format", "json"]` | Args passed to every `claude` invocation |
|
|
280
|
+
| `defaults.allowedTools` | string[] | `["Read", "Edit", "Write", "Glob", "Grep", "Bash(git:*)", "TodoWrite"]` | Tools Claude is allowed to use (see [Tool security](#tool-security)) |
|
|
281
|
+
| `defaults.disallowedTools` | string[] | `[]` | Tools Claude is forbidden from using (conflicts with `allowedTools`) |
|
|
282
|
+
| `defaults.maxTurnsPerAgent` | number | `5` | Max automatic handoffs in a single agent chain |
|
|
283
|
+
| `defaults.agentTimeoutMs` | number | `180000` (3 min) | Timeout per agent turn during auto-handoff |
|
|
284
|
+
| `defaults.sessionTtlMs` | number | `604800000` (7 days) | Max age for persisted sessions before pruning |
|
|
285
|
+
| `defaults.maxPersistedSessions` | number | `50` | Max number of persisted sessions kept on disk |
|
|
286
|
+
| `defaults.httpPort` | number \| false | `3100` | Port for the web dashboard and API (`false` to disable) |
|
|
287
|
+
| `defaults.logLevel` | string | `"info"` | Minimum log level (`debug`, `info`, `warn`, `error`) |
|
|
147
288
|
| `projects.<channelId>.name` | string | channel ID | Display name for the project |
|
|
148
289
|
| `projects.<channelId>.directory` | string | **required** | Absolute path to the project directory |
|
|
149
290
|
| `projects.<channelId>.idleTimeoutMs` | number | inherits default | Per-project idle timeout override |
|
|
150
291
|
| `projects.<channelId>.claudeArgs` | string[] | inherits default | Per-project Claude args override |
|
|
292
|
+
| `projects.<channelId>.allowedTools` | string[] | inherits default | Per-project allowed tools override |
|
|
293
|
+
| `projects.<channelId>.disallowedTools` | string[] | inherits default | Per-project disallowed tools override |
|
|
294
|
+
| `projects.<channelId>.agents` | object | — | Named agents for this project (see [Multi-agent setup](#multi-agent-setup)) |
|
|
295
|
+
| `projects.<channelId>.allowedRoles` | string[] | — | Discord role names required to use this project (empty = no restriction) |
|
|
296
|
+
| `projects.<channelId>.rateLimitPerUser` | number | — | Max messages per user per minute for this project |
|
|
297
|
+
|
|
298
|
+
## Multi-agent setup
|
|
299
|
+
|
|
300
|
+
You can define multiple agents per project that collaborate via `@mentions`. Each agent gets its own Claude session with a dedicated system prompt, and agents can hand off work to each other automatically.
|
|
301
|
+
|
|
302
|
+
### Defining agents
|
|
303
|
+
|
|
304
|
+
Add an `agents` map to any project in `config.json`. Each key is the agent name (used as `@name` in Discord), with `role` and `prompt` fields:
|
|
305
|
+
|
|
306
|
+
```json
|
|
307
|
+
{
|
|
308
|
+
"projects": {
|
|
309
|
+
"CHANNEL_ID": {
|
|
310
|
+
"name": "my-app",
|
|
311
|
+
"directory": "/path/to/my-app",
|
|
312
|
+
"agents": {
|
|
313
|
+
"pm": {
|
|
314
|
+
"role": "Product Manager",
|
|
315
|
+
"prompt": "You are the PM for my-app. Analyze requirements, create issues, and review work. When you need code implemented, mention @engineer in your response. Never write code directly."
|
|
316
|
+
},
|
|
317
|
+
"engineer": {
|
|
318
|
+
"role": "Software Engineer",
|
|
319
|
+
"prompt": "You are a senior engineer for my-app. Implement features, write tests, fix bugs, and create PRs. When work is done or you need PM review, mention @pm in your response."
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### How agent routing works
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
User sends message
|
|
331
|
+
|
|
|
332
|
+
v
|
|
333
|
+
Contains @agentName? ── YES ──> Route to that agent
|
|
334
|
+
| (session key: threadId:agentName)
|
|
335
|
+
NO
|
|
336
|
+
|
|
|
337
|
+
v
|
|
338
|
+
In a thread with prior agent activity? ── YES ──> Route to last active agent
|
|
339
|
+
|
|
|
340
|
+
NO
|
|
341
|
+
|
|
|
342
|
+
v
|
|
343
|
+
Route to default session (no agent)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
- **`@mention` routing:** Write `@pm fix the login bug` to target a specific agent. The mention is stripped from the prompt.
|
|
347
|
+
- **Plain reply routing:** Follow-up messages in a thread (without an `@mention`) automatically route to whichever agent last responded in that thread.
|
|
348
|
+
- **Isolated sessions:** Each agent gets its own Claude session per thread (`threadId:agentName`), so `@pm` and `@engineer` maintain separate conversation histories.
|
|
349
|
+
|
|
350
|
+
### Automatic agent handoffs
|
|
351
|
+
|
|
352
|
+
When an agent's response contains an `@mention` of another agent in the same project, the gateway automatically forwards that response as the next agent's input. This creates a collaborative loop:
|
|
353
|
+
|
|
354
|
+
1. User writes `@pm add a search feature to the dashboard`
|
|
355
|
+
2. PM agent analyzes the request, responds with requirements mentioning `@engineer`
|
|
356
|
+
3. Gateway automatically sends PM's response to the engineer agent
|
|
357
|
+
4. Engineer implements and responds mentioning `@pm` for review
|
|
358
|
+
5. Loop continues until no `@mention` is found or the turn limit is reached
|
|
359
|
+
|
|
360
|
+
The turn counter resets whenever a human posts a new message. The `maxTurnsPerAgent` default (5) prevents runaway loops.
|
|
361
|
+
|
|
362
|
+
### Listing agents
|
|
363
|
+
|
|
364
|
+
Use `!agents` in any mapped Discord channel to see the available agents for that project.
|
|
365
|
+
|
|
366
|
+
### Thread history
|
|
367
|
+
|
|
368
|
+
When an agent is invoked in a thread, the gateway prepends the last 20 messages as context so the agent understands the conversation so far. This is especially useful when a different agent picks up a thread mid-conversation.
|
|
151
369
|
|
|
152
370
|
### Environment variables
|
|
153
371
|
|
|
154
372
|
| Variable | Required | Description |
|
|
155
373
|
|----------|----------|-------------|
|
|
156
374
|
| `DISCORD_BOT_TOKEN` | Yes | Discord bot token |
|
|
375
|
+
| `MPG_HOME` | No | Override config home directory (default: `~/.mpg`) |
|
|
157
376
|
|
|
158
377
|
### Resuming sessions from terminal
|
|
159
378
|
|
|
@@ -166,6 +385,19 @@ claude --resume <session-id>
|
|
|
166
385
|
|
|
167
386
|
**Important:** You must run `claude --resume` from the same directory the session was started in (i.e., the project's `directory` in `config.json`). Claude will not find the session if you run it from a different working directory.
|
|
168
387
|
|
|
388
|
+
## Threading and per-thread sessions
|
|
389
|
+
|
|
390
|
+
When a user posts a message in a mapped channel, the bot automatically creates a Discord thread and replies there instead of cluttering the main channel. Follow-up messages within the thread continue the same conversation.
|
|
391
|
+
|
|
392
|
+
Each thread gets its **own Claude session**, isolated from the main channel and other threads. This means:
|
|
393
|
+
|
|
394
|
+
- Multiple users can work in the same project channel without their conversations interleaving
|
|
395
|
+
- Each thread maintains its own context and history
|
|
396
|
+
- The thread inherits the project config (directory, Claude args) from the parent channel
|
|
397
|
+
- Threads auto-archive after 60 minutes of inactivity
|
|
398
|
+
|
|
399
|
+
If thread creation fails (e.g., due to permissions), the bot falls back to replying in the main channel.
|
|
400
|
+
|
|
169
401
|
## Discord commands
|
|
170
402
|
|
|
171
403
|
The gateway responds to commands in any mapped Discord channel:
|
|
@@ -174,21 +406,54 @@ The gateway responds to commands in any mapped Discord channel:
|
|
|
174
406
|
|---------|-------------|
|
|
175
407
|
| `!sessions` | List all active sessions with idle time and queue depth |
|
|
176
408
|
| `!session <name>` | Inspect a specific project's session (ID, idle time, queue) |
|
|
409
|
+
| `!restart <name>` | Reset a session (fresh context, keeps worktree) |
|
|
177
410
|
| `!kill <name>` | Force-close a project's session |
|
|
411
|
+
| `!ask <agent> <message>` | Dispatch a message to a specific agent (shorthand: `!<agent> <message>`) |
|
|
412
|
+
| `!agents` | List available agents for the current project |
|
|
178
413
|
| `!help` | Show available commands |
|
|
179
414
|
|
|
415
|
+
## Web dashboard
|
|
416
|
+
|
|
417
|
+
The gateway includes a built-in web dashboard for monitoring sessions and projects. It starts automatically on the port configured by `defaults.httpPort` (default: `3100`). Set `httpPort` to `false` to disable it.
|
|
418
|
+
|
|
419
|
+
Open `http://localhost:3100/` to view the dashboard, which shows:
|
|
420
|
+
|
|
421
|
+
- Gateway health and Discord connection status
|
|
422
|
+
- Active sessions with last activity time and queue depth
|
|
423
|
+
- Configured projects and their agents
|
|
424
|
+
|
|
425
|
+
### API endpoints
|
|
426
|
+
|
|
427
|
+
| Endpoint | Description |
|
|
428
|
+
|----------|-------------|
|
|
429
|
+
| `GET /` | Web dashboard (auto-refreshes every 5 seconds) |
|
|
430
|
+
| `GET /health` | Health check — returns status, uptime, session/queue counts, and Discord connection state |
|
|
431
|
+
| `GET /api/sessions` | List all active sessions with details |
|
|
432
|
+
| `GET /api/projects` | List configured projects and their agents |
|
|
433
|
+
| `GET /api/status` | Combined status: version, health, sessions, and projects |
|
|
434
|
+
|
|
180
435
|
## Architecture
|
|
181
436
|
|
|
182
437
|
| Module | Responsibility |
|
|
183
438
|
|--------|---------------|
|
|
184
439
|
| `src/cli.ts` | CLI entry point — `mpg start`, `mpg init`, `mpg status` |
|
|
185
|
-
| `src/
|
|
440
|
+
| `src/resolve-home.ts` | Resolves `~/.mpg/` config home, profiles, and file resolution order |
|
|
441
|
+
| `src/init.ts` | Interactive setup wizard (supports `--profile`) |
|
|
186
442
|
| `src/config.ts` | Validates and merges `config.json` with defaults |
|
|
187
|
-
| `src/router.ts` | Maps channel IDs to project configs
|
|
188
|
-
| `src/session-manager.ts` | One session per
|
|
443
|
+
| `src/router.ts` | Maps channel IDs to project configs; threads resolve to their own session using the parent channel's project config |
|
|
444
|
+
| `src/session-manager.ts` | One session per channel/thread, queues concurrent messages, manages idle timeouts |
|
|
189
445
|
| `src/session-store.ts` | Persists session IDs to `.sessions.json` for resume across restarts |
|
|
190
446
|
| `src/claude-cli.ts` | Spawns `claude --print` subprocess, parses JSON output |
|
|
191
|
-
| `src/
|
|
447
|
+
| `src/agent-dispatch.ts` | Parses `@mentions`, resolves agent targets |
|
|
448
|
+
| `src/turn-counter.ts` | Tracks handoff turns per thread, enforces `maxTurnsPerAgent` |
|
|
449
|
+
| `src/worktree.ts` | Manages git worktrees for session isolation; reconciles orphans on startup |
|
|
450
|
+
| `src/embed-format.ts` | Builds Discord embeds for agent responses and handoff announcements |
|
|
451
|
+
| `src/persona-presets.ts` | Built-in persona library (PM, engineer, etc.) for agent shorthand config |
|
|
452
|
+
| `src/role-check.ts` | Checks Discord member roles against `allowedRoles` |
|
|
453
|
+
| `src/rate-limiter.ts` | Per-user rate limiting (sliding window) |
|
|
454
|
+
| `src/health-server.ts` | Web dashboard and REST API (`/health`, `/api/sessions`, `/api/projects`, `/api/status`) |
|
|
455
|
+
| `src/logger.ts` | Structured logger with level filtering and JSON output |
|
|
456
|
+
| `src/discord.ts` | Discord.js client, message routing, agent handoff loop, response chunking |
|
|
192
457
|
|
|
193
458
|
## Scripts
|
|
194
459
|
|
|
@@ -204,9 +469,9 @@ The gateway responds to commands in any mapped Discord channel:
|
|
|
204
469
|
|
|
205
470
|
- **Text only** — attachments and embeds are not forwarded to Claude
|
|
206
471
|
- **One message at a time per project** — concurrent messages to the same project are queued
|
|
207
|
-
- **
|
|
472
|
+
- **Per-thread sessions** — each thread gets its own Claude session scoped to the parent channel's project; threads auto-archive after 60 minutes of inactivity
|
|
208
473
|
- **Local only** — the gateway runs on the same machine as the project directories
|
|
209
|
-
- **
|
|
474
|
+
- **Optional Discord access control** — per-project `allowedRoles` restricts usage to specific Discord roles; `rateLimitPerUser` throttles per-user message rate. Without these, any user in a mapped channel can send prompts
|
|
210
475
|
|
|
211
476
|
## License
|
|
212
477
|
|