@excitedjs/dreamux 0.2.0 → 0.3.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 +155 -160
- package/bin/tm +30 -0
- package/dist/admin/client.js +98 -0
- package/dist/admin/client.js.map +1 -0
- package/dist/admin/methods.js +83 -38
- package/dist/admin/methods.js.map +1 -1
- package/dist/admin/socket.js +2 -2
- package/dist/admin/socket.js.map +1 -1
- package/dist/channel/feishu-gate.js +187 -18
- package/dist/channel/feishu-gate.js.map +1 -1
- package/dist/channel/feishu-message.js +92 -0
- package/dist/channel/feishu-message.js.map +1 -0
- package/dist/cli/doctor.js +53 -58
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/dreamux.js +33 -51
- package/dist/cli/dreamux.js.map +1 -1
- package/dist/cli/server-ctl.js +6 -8
- package/dist/cli/server-ctl.js.map +1 -1
- package/dist/cli/server.js +22 -32
- package/dist/cli/server.js.map +1 -1
- package/dist/codex/events.js +3 -2
- package/dist/codex/events.js.map +1 -1
- package/dist/codex/mcp-config.js +24 -0
- package/dist/codex/mcp-config.js.map +1 -0
- package/dist/codex/supervisor.js +16 -0
- package/dist/codex/supervisor.js.map +1 -1
- package/dist/dispatcher/approval.js +2 -3
- package/dist/dispatcher/approval.js.map +1 -1
- package/dist/dispatcher/runtime.js +193 -141
- package/dist/dispatcher/runtime.js.map +1 -1
- package/dist/dispatcher/turn-manager.js +78 -97
- package/dist/dispatcher/turn-manager.js.map +1 -1
- package/dist/feishu/bot.js +71 -9
- package/dist/feishu/bot.js.map +1 -1
- package/dist/mcp/feishu-mcp.js +269 -0
- package/dist/mcp/feishu-mcp.js.map +1 -0
- package/dist/onboard/config-files.js +52 -22
- package/dist/onboard/config-files.js.map +1 -1
- package/dist/onboard/dispatcher-skill.js +18 -0
- package/dist/onboard/dispatcher-skill.js.map +1 -0
- package/dist/onboard/run.js +17 -50
- package/dist/onboard/run.js.map +1 -1
- package/dist/onboard/service.js +4 -8
- package/dist/onboard/service.js.map +1 -1
- package/dist/onboard/uninstall.js +47 -13
- package/dist/onboard/uninstall.js.map +1 -1
- package/dist/onboard/wizard.js +3 -27
- package/dist/onboard/wizard.js.map +1 -1
- package/dist/runtime/config.js +158 -64
- package/dist/runtime/config.js.map +1 -1
- package/dist/runtime/dispatcher-codex-home.js +14 -51
- package/dist/runtime/dispatcher-codex-home.js.map +1 -1
- package/dist/runtime/dispatcher-id.js +9 -0
- package/dist/runtime/dispatcher-id.js.map +1 -0
- package/dist/runtime/dispatcher-store.js +202 -0
- package/dist/runtime/dispatcher-store.js.map +1 -0
- package/dist/runtime/package-bin.js +41 -0
- package/dist/runtime/package-bin.js.map +1 -0
- package/dist/runtime/paths.js +82 -48
- package/dist/runtime/paths.js.map +1 -1
- package/dist/runtime/secrets.js +4 -3
- package/dist/runtime/secrets.js.map +1 -1
- package/dist/server.js +110 -36
- package/dist/server.js.map +1 -1
- package/package.json +6 -6
- package/skills/dispatcher/SKILL.md +107 -0
- package/db/migrations/0001_init.sql +0 -49
- package/dist/channel/outbound.js +0 -12
- package/dist/channel/outbound.js.map +0 -1
- package/dist/db/repository.js +0 -223
- package/dist/db/repository.js.map +0 -1
- package/dist/db/schema.js +0 -29
- package/dist/db/schema.js.map +0 -1
- package/dist/db/types.js +0 -2
- package/dist/db/types.js.map +0 -1
- package/dist/onboard/plugins.js +0 -202
- package/dist/onboard/plugins.js.map +0 -1
package/README.md
CHANGED
|
@@ -3,56 +3,61 @@
|
|
|
3
3
|
The Codex-host server package. One long-running Node process hosts N
|
|
4
4
|
**Dispatchers**; each Dispatcher binds **1 Feishu bot + 1 Codex thread**.
|
|
5
5
|
|
|
6
|
-
This file is the **package-level** quick start. For the monorepo layout
|
|
7
|
-
|
|
8
|
-
[`README.md`](../../README.md) and
|
|
6
|
+
This file is the **package-level** quick start. For the monorepo layout and
|
|
7
|
+
knowledge base, see the top-level [`README.md`](../../README.md) and
|
|
9
8
|
[`.agents/root.md`](../../.agents/root.md).
|
|
10
9
|
|
|
11
10
|
Design background:
|
|
12
11
|
[#1 Proposal](https://github.com/excitedjs/dreamux/issues/1) ·
|
|
13
12
|
[#2 Engineering plan](https://github.com/excitedjs/dreamux/issues/2) ·
|
|
14
13
|
[#4 Monorepo + harness](https://github.com/excitedjs/dreamux/issues/4) ·
|
|
15
|
-
[#18 Global bin onboarding](https://github.com/excitedjs/dreamux/issues/18)
|
|
14
|
+
[#18 Global bin onboarding](https://github.com/excitedjs/dreamux/issues/18) ·
|
|
15
|
+
[#36 MVP tracking](https://github.com/excitedjs/dreamux/issues/36).
|
|
16
16
|
|
|
17
17
|
## What this package ships
|
|
18
18
|
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- A
|
|
23
|
-
|
|
19
|
+
- Public CLI bins: `dreamux` and `tm`. `dreamux` owns onboarding, serving,
|
|
20
|
+
status, doctor, dispatcher commands, and config commands. `tm` is a wrapper
|
|
21
|
+
around the package-local `@excitedjs/tm` dependency for dispatcher skills.
|
|
22
|
+
- A bundled dispatcher Codex skill, copied by `dreamux onboard` into
|
|
23
|
+
`<dispatcher cwd>/.codex/skills/dispatcher/SKILL.md`.
|
|
24
|
+
- Config-backed dispatcher declarations, server-owned state/log paths, a
|
|
25
|
+
Feishu long-connection inbound channel, Codex app-server lifecycle
|
|
26
|
+
management, and a dispatcher-scoped Feishu MCP shim for model replies.
|
|
24
27
|
|
|
25
|
-
##
|
|
28
|
+
## MVP contract
|
|
26
29
|
|
|
27
30
|
- **One Node process, many Dispatchers.** Each Dispatcher = 1 Feishu Bot
|
|
28
|
-
(
|
|
29
|
-
|
|
30
|
-
- **
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- **Dispatcher cwd is explicit, Codex state stays
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
(`app_id`/`app_secret`) + 1 long-lived Codex `app-server` child + 1 Codex
|
|
32
|
+
thread.
|
|
33
|
+
- **One dispatcher is one trust domain.** A bot may receive multiple chats, but
|
|
34
|
+
all accepted messages share one Codex thread. Do not bind unrelated private
|
|
35
|
+
chats to the same dispatcher.
|
|
36
|
+
- **Dispatcher cwd is explicit, Codex state stays global.** Dispatcher
|
|
37
|
+
app-server processes use Codex's global default home (`~/.codex`) for auth,
|
|
38
|
+
memory, and config. The dispatcher skill is workspace-local under the
|
|
39
|
+
dispatcher cwd.
|
|
40
|
+
- **Inbound state is in memory.** The server keeps only process-local turn
|
|
41
|
+
queues, message dedupe, coalescing state, and received-reaction ownership.
|
|
42
|
+
Restarting the server drops unprocessed inbound messages and may leave
|
|
43
|
+
received reactions behind.
|
|
44
|
+
- **Outbound is MCP reply-only.** Assistant text emitted by Codex is never
|
|
45
|
+
forwarded to Feishu automatically. The model must call the dispatcher-scoped
|
|
46
|
+
Feishu MCP tools such as `reply` or `react`.
|
|
47
|
+
- **No webhook surface in MVP.** Feishu inbound uses the SDK long-connection
|
|
48
|
+
WebSocket path. Webhook-only verification/encryption fields are not part of
|
|
49
|
+
the config schema.
|
|
50
|
+
|
|
51
|
+
Explicitly **not** in MVP: per-chat threads, durable inbound buffers,
|
|
52
|
+
automatic assistant-text outbound, HTTP MCP listeners by default, reaction
|
|
53
|
+
ledgers, streaming outbound, tm registry isolation, cross-machine
|
|
54
|
+
coordination, and a web UI.
|
|
48
55
|
|
|
49
56
|
## Install / build / test
|
|
50
57
|
|
|
51
|
-
Use the monorepo (rush) path from the repo root
|
|
52
|
-
install path
|
|
53
|
-
pnpm `workspace:*` protocol
|
|
54
|
-
`cd packages/dreamux && npm install` no longer works (see
|
|
55
|
-
[the install-model decision](../../.agents/decisions/install-model.md)):
|
|
58
|
+
Use the monorepo (rush) path from the repo root. It is the only supported
|
|
59
|
+
install path because this package depends on workspace packages through the
|
|
60
|
+
pnpm `workspace:*` protocol:
|
|
56
61
|
|
|
57
62
|
```bash
|
|
58
63
|
node common/scripts/install-run-rush.js update
|
|
@@ -60,10 +65,8 @@ node common/scripts/install-run-rush.js build
|
|
|
60
65
|
node common/scripts/install-run-rush.js test
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
The bin launchers shell out to plain `node` against the compiled `dist/`
|
|
66
|
-
output; **no `tsx` is needed at runtime** (PR #6).
|
|
68
|
+
The bin launchers shell out to plain `node` against compiled `dist/` output;
|
|
69
|
+
no `tsx` is needed at runtime.
|
|
67
70
|
|
|
68
71
|
## Run the server
|
|
69
72
|
|
|
@@ -71,75 +74,37 @@ output; **no `tsx` is needed at runtime** (PR #6).
|
|
|
71
74
|
./bin/dreamux serve
|
|
72
75
|
```
|
|
73
76
|
|
|
74
|
-
The launcher works from any cwd and via symlinks
|
|
77
|
+
The launcher works from any cwd and via symlinks.
|
|
75
78
|
|
|
76
|
-
The server keeps operator-edited config separate from
|
|
77
|
-
|
|
79
|
+
The server keeps operator-edited config separate from server-owned state and
|
|
80
|
+
logs:
|
|
78
81
|
|
|
79
82
|
| Path | Purpose | Source of truth |
|
|
80
83
|
|---|---|---|
|
|
81
|
-
| `~/.dreamux/config.json`
|
|
82
|
-
| `~/.
|
|
83
|
-
| `~/.
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
| `~/.
|
|
87
|
-
| `~/.codex-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
the `~/.codex-host` half anywhere you like.
|
|
92
|
-
|
|
93
|
-
## Configure a dispatcher
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
./bin/dreamux dispatcher add \
|
|
97
|
-
--id flow \
|
|
98
|
-
--bot-app-id <APP_ID> \
|
|
99
|
-
--bot-secret-ref config:flow \
|
|
100
|
-
--codex-cwd /path/to/dispatcher/workspace
|
|
101
|
-
|
|
102
|
-
# Inspect / restart
|
|
103
|
-
./bin/dreamux dispatcher list
|
|
104
|
-
./bin/dreamux dispatcher status --id flow
|
|
105
|
-
./bin/dreamux dispatcher start --id flow # if not auto-started
|
|
106
|
-
```
|
|
84
|
+
| `~/.dreamux/config.json` | User-editable config and Feishu bot secrets, created by `dreamux onboard`; edit and restart to apply | the operator |
|
|
85
|
+
| `~/.dreamux/state/server.json` | Server status snapshot | the server |
|
|
86
|
+
| `~/.dreamux/state/admin.sock` | Admin Unix socket | the server |
|
|
87
|
+
| `~/.dreamux/state/<id>/status.json` | Dispatcher runtime status and Codex thread id | the server |
|
|
88
|
+
| `~/.dreamux/state/<id>/access.json` | Dispatcher-local access-gate state | the server |
|
|
89
|
+
| `~/.dreamux/state/<id>/codex.sock` | Codex app-server Unix socket | the server |
|
|
90
|
+
| `~/.dreamux/logs/codex-app-server/<id>.log` | Codex app-server stdout/stderr | the server |
|
|
91
|
+
| `~/.dreamux/logs/feishu-channel/<id>.log` | Feishu channel logs | the server |
|
|
92
|
+
| `~/.codex/` | Codex global default home: auth, memory, and config | the operator / Codex |
|
|
93
|
+
| `<dispatcher cwd>/.codex/skills/dispatcher/SKILL.md` | Dispatcher skill copied by `dreamux onboard`; reported but not deleted by `dreamux uninstall` | dreamux installer |
|
|
107
94
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
registers the dispatcher with `bot_secret_ref=config:<dispatcher-id>`.
|
|
111
|
-
`dreamux config show` redacts these secrets by default; use
|
|
112
|
-
`dreamux config show --raw` only when you intentionally need the unredacted
|
|
113
|
-
local file.
|
|
95
|
+
`rm -rf ~/.dreamux/state ~/.dreamux/logs` is a state/log recovery path; dreamux
|
|
96
|
+
config and global Codex auth survive.
|
|
114
97
|
|
|
115
|
-
##
|
|
116
|
-
|
|
117
|
-
1. `dreamux onboard --dispatcher-id flow --dispatcher-cwd <WORKSPACE> --bot-app-id <APP_ID> --bot-app-secret <APP_SECRET>`
|
|
118
|
-
2. `dreamux serve` — dispatcher `flow` goes to `ready`
|
|
119
|
-
3. Invite the bot to a Feishu group A, send `hi`
|
|
120
|
-
4. Server delivers it into the Codex thread; reply goes back to group A
|
|
121
|
-
5. Invite the same bot to a DM, ask "do you remember the 'hi' from earlier?"
|
|
122
|
-
6. Same thread, so the reply confirms — and goes back to the DM
|
|
123
|
-
7. Ask the bot to "run the test suite via tm and summarize"
|
|
124
|
-
8. Codex shells out to `tm`, reads stdout/stderr, replies into the source chat
|
|
125
|
-
9. Repeat with a **different** worktree to prove dispatcher↔worktree decoupling
|
|
126
|
-
10. `pkill node` to crash the server, then restart it
|
|
127
|
-
11. Continue chatting — Codex `thread/resume` restores context
|
|
98
|
+
## Configure dispatchers
|
|
128
99
|
|
|
129
|
-
|
|
100
|
+
For normal installs, run `dreamux onboard`. It writes `~/.dreamux/config.json`
|
|
101
|
+
with mode `0600`, creates state/log directories, installs the workspace skill,
|
|
102
|
+
and registers a user-level service when supported.
|
|
130
103
|
|
|
131
|
-
|
|
132
|
-
per-dispatcher field → `~/.dreamux/config.json` → built-in default.
|
|
133
|
-
See [the global-config decision](../../.agents/decisions/global-config-dir.md).
|
|
134
|
-
|
|
135
|
-
### Global: `~/.dreamux/config.json`
|
|
136
|
-
|
|
137
|
-
Auto-created on first boot with this default shape:
|
|
104
|
+
Dispatcher declarations live in `config.json`:
|
|
138
105
|
|
|
139
106
|
```json
|
|
140
107
|
{
|
|
141
|
-
"runtime_dir": "~/.codex-host",
|
|
142
|
-
"admin_socket": null,
|
|
143
108
|
"codex": {
|
|
144
109
|
"bin": "codex",
|
|
145
110
|
"approval_policy": "never",
|
|
@@ -147,87 +112,117 @@ Auto-created on first boot with this default shape:
|
|
|
147
112
|
"extra_args": [],
|
|
148
113
|
"initialize_timeout_ms": 10000
|
|
149
114
|
},
|
|
150
|
-
"
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
"flow": {
|
|
115
|
+
"dispatchers": [
|
|
116
|
+
{
|
|
117
|
+
"id": "flow",
|
|
118
|
+
"cwd": "<WORKSPACE>",
|
|
119
|
+
"enabled": true,
|
|
120
|
+
"feishu": {
|
|
157
121
|
"app_id": "<APP_ID>",
|
|
158
122
|
"app_secret": "<APP_SECRET>"
|
|
123
|
+
},
|
|
124
|
+
"codex": {
|
|
125
|
+
"approval_policy": null,
|
|
126
|
+
"sandbox_mode": null,
|
|
127
|
+
"extra_args": [],
|
|
128
|
+
"extra_env": {
|
|
129
|
+
"EXAMPLE_FLAG": "1"
|
|
130
|
+
}
|
|
159
131
|
}
|
|
160
132
|
}
|
|
161
|
-
|
|
133
|
+
]
|
|
162
134
|
}
|
|
163
135
|
```
|
|
164
136
|
|
|
165
|
-
Edit and restart `dreamux serve
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
move the legacy TOML file aside.
|
|
170
|
-
|
|
171
|
-
### `codex_args_json` (per-dispatcher, overrides global)
|
|
137
|
+
Edit and restart `dreamux serve` to apply dispatcher declaration changes.
|
|
138
|
+
`app_id` values must be unique across all declared dispatchers, including
|
|
139
|
+
disabled ones. Dispatcher ids use a path-safe character set so they map
|
|
140
|
+
one-to-one to state directories.
|
|
172
141
|
|
|
173
|
-
|
|
142
|
+
Access-gate allowlists are not part of `config.json`. Configure them in
|
|
143
|
+
`~/.dreamux/state/<id>/access.json`:
|
|
174
144
|
|
|
175
145
|
```json
|
|
176
|
-
{
|
|
146
|
+
{
|
|
147
|
+
"version": 1,
|
|
148
|
+
"dm": {
|
|
149
|
+
"allow_users": ["<USER_ID>"]
|
|
150
|
+
},
|
|
151
|
+
"group": {
|
|
152
|
+
"allow_chats": ["<CHAT_ID>"],
|
|
153
|
+
"follow_users": ["<USER_ID>"],
|
|
154
|
+
"require_mention": true
|
|
155
|
+
},
|
|
156
|
+
"observed_chats": [],
|
|
157
|
+
"warnings": [],
|
|
158
|
+
"last_gate": null
|
|
159
|
+
}
|
|
177
160
|
```
|
|
178
161
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
-
|
|
208
|
-
|
|
162
|
+
The server reads `access.json` directly at runtime and preserves runtime
|
|
163
|
+
observations and warnings in the same file.
|
|
164
|
+
|
|
165
|
+
`dreamux config show`, `dreamux status`, `dreamux doctor`, and logs redact
|
|
166
|
+
`app_secret`. There is no CLI raw mode for printing the unredacted local file.
|
|
167
|
+
|
|
168
|
+
## Codex configuration precedence
|
|
169
|
+
|
|
170
|
+
Precedence for Codex-related values, highest first:
|
|
171
|
+
|
|
172
|
+
1. Environment variables, such as `CODEX_HOST_CODEX_BIN`.
|
|
173
|
+
2. Per-dispatcher `dispatchers[].codex` fields.
|
|
174
|
+
3. Global `codex` fields in `~/.dreamux/config.json`.
|
|
175
|
+
4. Built-in defaults compiled into `src/runtime/config.ts`.
|
|
176
|
+
|
|
177
|
+
Per-dispatcher `extra_args` are appended after global `codex.extra_args`, which
|
|
178
|
+
matches Codex's last-write-wins behavior for repeated `-c key=value` options.
|
|
179
|
+
Per-dispatcher `extra_env` is merged over the server process environment before
|
|
180
|
+
spawning that dispatcher app-server; dreamux still removes `CODEX_HOME` so
|
|
181
|
+
Codex keeps using its global default home.
|
|
182
|
+
|
|
183
|
+
## MCP reply flow
|
|
184
|
+
|
|
185
|
+
Each dispatcher injects a Feishu MCP stdio server into its Codex app-server.
|
|
186
|
+
The stdio shim does not read Feishu secrets. It forwards outbound tool calls to
|
|
187
|
+
the serve process over the admin socket, and the serve process owns the Feishu
|
|
188
|
+
client plus process-local received-reaction cleanup state.
|
|
189
|
+
|
|
190
|
+
The model-facing tools include:
|
|
191
|
+
|
|
192
|
+
- `reply`: send a Feishu reply to a target message or chat.
|
|
193
|
+
- `react`: add a model-owned reaction to a Feishu message.
|
|
194
|
+
|
|
195
|
+
If the model only emits assistant text, nothing is sent to Feishu.
|
|
196
|
+
|
|
197
|
+
## MVP verification path
|
|
198
|
+
|
|
199
|
+
1. `dreamux onboard --dispatcher-id flow --dispatcher-cwd <WORKSPACE> --bot-app-id <APP_ID> --bot-app-secret <APP_SECRET>`
|
|
200
|
+
2. `dreamux serve` starts dispatcher `flow`.
|
|
201
|
+
3. Invite the bot to a Feishu group, send a mention that passes the access gate.
|
|
202
|
+
4. Server injects a `<feishu_message>` block into the Codex thread.
|
|
203
|
+
5. Codex calls the Feishu MCP `reply` tool; the reply is delivered to Feishu.
|
|
204
|
+
6. Send another accepted message from a different chat in the same trust
|
|
205
|
+
domain; it enters the same Codex thread.
|
|
206
|
+
7. Ask the bot to run teammate work through the bundled `tm` wrapper.
|
|
207
|
+
8. Restart the server and continue chatting; Codex `thread/resume` restores the
|
|
208
|
+
thread when possible, but in-flight inbound messages are not durable.
|
|
209
209
|
|
|
210
210
|
## Testing
|
|
211
211
|
|
|
212
212
|
```bash
|
|
213
|
-
|
|
214
|
-
node common/scripts/install-run-rush.js test # smoke + bin-launcher + codex-live
|
|
213
|
+
node common/scripts/install-run-rush.js test
|
|
215
214
|
```
|
|
216
215
|
|
|
217
|
-
- `tests/smoke.test.ts` — fake-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
- `tests/bin-launcher.test.ts` —
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
`@openai/codex@latest` before running tests so this compatibility check is
|
|
228
|
-
not skipped by default and tracks the current Codex CLI. Local developers can
|
|
229
|
-
still opt out explicitly with `DREAMUX_SKIP_LIVE_CODEX=1` when no Codex
|
|
230
|
-
binary is available.
|
|
216
|
+
- `tests/smoke.test.ts` — fake-Codex dispatcher behavior: access gate,
|
|
217
|
+
in-memory turn serialization/coalescing/dedupe, MCP reply-only outbound,
|
|
218
|
+
thread resume, app-server restart behavior, and approval fail-fast.
|
|
219
|
+
- `tests/bin-launcher.test.ts` — real launcher and repo-root shim behavior from
|
|
220
|
+
arbitrary cwd and through symlinks.
|
|
221
|
+
- `tests/doctor.test.ts` — standalone doctor checks for config, Codex home,
|
|
222
|
+
services, and dispatcher workspace skill state.
|
|
223
|
+
- `tests/codex-0135-live.test.ts` and `tests/codex-0136-mcp-live.test.ts` —
|
|
224
|
+
real Codex app-server compatibility checks. Set `DREAMUX_SKIP_LIVE_CODEX=1`
|
|
225
|
+
only when no Codex binary is available locally.
|
|
231
226
|
|
|
232
227
|
## License
|
|
233
228
|
|
package/bin/tm
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Launcher for the tm CLI bundled as a direct @excitedjs/dreamux dependency.
|
|
3
|
+
# Resolves its own location through symlinks so it works from npm global bins,
|
|
4
|
+
# npm-link, and source-checkout shortcuts.
|
|
5
|
+
set -eu
|
|
6
|
+
|
|
7
|
+
SOURCE="${BASH_SOURCE[0]}"
|
|
8
|
+
hop=0
|
|
9
|
+
while [ -L "$SOURCE" ]; do
|
|
10
|
+
hop=$((hop + 1))
|
|
11
|
+
if [ "$hop" -gt 40 ]; then
|
|
12
|
+
echo "tm: too many symlink hops resolving $SOURCE" >&2
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
TARGET="$(readlink "$SOURCE")"
|
|
16
|
+
if [ "${TARGET:0:1}" = "/" ]; then
|
|
17
|
+
SOURCE="$TARGET"
|
|
18
|
+
else
|
|
19
|
+
SOURCE="$(dirname -- "$SOURCE")/$TARGET"
|
|
20
|
+
fi
|
|
21
|
+
done
|
|
22
|
+
|
|
23
|
+
DIR="$(cd -- "$(dirname -- "$SOURCE")/.." &> /dev/null && pwd)"
|
|
24
|
+
TARGET="$DIR/node_modules/.bin/tm"
|
|
25
|
+
if [ ! -x "$TARGET" ]; then
|
|
26
|
+
echo "tm: $TARGET is missing." >&2
|
|
27
|
+
echo "Install dependencies first from the repo root: node common/scripts/install-run-rush.js update." >&2
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
exec "$TARGET" "$@"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { connect } from 'node:net';
|
|
2
|
+
import { adminSocketPath as defaultAdminSocketPath } from '../runtime/paths.js';
|
|
3
|
+
export class AdminClientError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
constructor(code, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.name = 'AdminClientError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
12
|
+
let nextRequestId = 1;
|
|
13
|
+
export function sendAdminRequest(method, params, options = {}) {
|
|
14
|
+
const socketPath = options.socketPath ?? defaultAdminSocketPath();
|
|
15
|
+
const request = {
|
|
16
|
+
id: options.requestId ?? adminRequestId(),
|
|
17
|
+
method,
|
|
18
|
+
params,
|
|
19
|
+
};
|
|
20
|
+
return sendOne(socketPath, request, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
21
|
+
}
|
|
22
|
+
export function sendOneAdminRequest(socketPath, request, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
23
|
+
return sendOne(socketPath, request, timeoutMs);
|
|
24
|
+
}
|
|
25
|
+
function sendOne(socketPath, request, timeoutMs) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
let buf = '';
|
|
28
|
+
let settled = false;
|
|
29
|
+
let sock = null;
|
|
30
|
+
const timer = setTimeout(() => {
|
|
31
|
+
settle(new Error(`admin socket request timed out after ${timeoutMs}ms`));
|
|
32
|
+
try {
|
|
33
|
+
sock?.destroy();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
/* already gone */
|
|
37
|
+
}
|
|
38
|
+
}, timeoutMs);
|
|
39
|
+
timer.unref();
|
|
40
|
+
function settle(value, isError = true) {
|
|
41
|
+
if (settled)
|
|
42
|
+
return;
|
|
43
|
+
settled = true;
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
if (isError)
|
|
46
|
+
reject(value);
|
|
47
|
+
else
|
|
48
|
+
resolve(value);
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
sock = connect(socketPath);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
settle(err);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
sock.setEncoding('utf8');
|
|
58
|
+
sock.on('connect', () => {
|
|
59
|
+
sock.write(`${JSON.stringify(request)}\n`);
|
|
60
|
+
});
|
|
61
|
+
sock.on('data', (chunk) => {
|
|
62
|
+
buf += chunk;
|
|
63
|
+
const nl = buf.indexOf('\n');
|
|
64
|
+
if (nl === -1 || settled)
|
|
65
|
+
return;
|
|
66
|
+
const line = buf.slice(0, nl).trim();
|
|
67
|
+
try {
|
|
68
|
+
const response = JSON.parse(line);
|
|
69
|
+
if (response.ok)
|
|
70
|
+
settle(response.result, false);
|
|
71
|
+
else
|
|
72
|
+
settle(new AdminClientError(response.error.code, response.error.message));
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
settle(err);
|
|
76
|
+
}
|
|
77
|
+
sock.end();
|
|
78
|
+
});
|
|
79
|
+
sock.on('error', (err) => {
|
|
80
|
+
if (settled)
|
|
81
|
+
return;
|
|
82
|
+
const code = err.code;
|
|
83
|
+
if (code === 'ENOENT' || code === 'ECONNREFUSED') {
|
|
84
|
+
settle(new Error(`cannot reach admin socket at ${socketPath} - is the server running?`));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
settle(err);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
sock.on('close', () => {
|
|
91
|
+
settle(new Error('admin socket closed without a response'));
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function adminRequestId() {
|
|
96
|
+
return `mcp-${process.pid}-${Date.now()}-${nextRequestId++}`;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/admin/client.ts"],"names":[],"mappings":"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"}
|