wtt-connect 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/README.md +295 -0
- package/bin/wtt-connect.js +7 -0
- package/package.json +32 -0
- package/scripts/install-agent.sh +4 -0
- package/scripts/install-launchd.sh +51 -0
- package/scripts/install-systemd-user.sh +189 -0
- package/scripts/uninstall-launchd.sh +18 -0
- package/scripts/uninstall-systemd-user.sh +42 -0
- package/src/adapter-registry.js +58 -0
- package/src/adapters/acp.js +196 -0
- package/src/adapters/claude-code.js +161 -0
- package/src/adapters/codex.js +88 -0
- package/src/adapters/generic-cli.js +258 -0
- package/src/adapters/index.js +28 -0
- package/src/adapters/openclaw.js +32 -0
- package/src/artifacts.js +68 -0
- package/src/attachments.js +181 -0
- package/src/config.js +118 -0
- package/src/env.js +42 -0
- package/src/events.js +23 -0
- package/src/logger.js +18 -0
- package/src/main.js +143 -0
- package/src/mime.js +12 -0
- package/src/permissions.js +28 -0
- package/src/runner.js +562 -0
- package/src/runtime-info.js +71 -0
- package/src/service-manager.js +510 -0
- package/src/session-manager.js +31 -0
- package/src/setup.js +71 -0
- package/src/shell-runner.js +184 -0
- package/src/smoke.js +99 -0
- package/src/store.js +58 -0
- package/src/stt.js +146 -0
- package/src/terminal-session.js +152 -0
- package/src/tts.js +40 -0
- package/src/wtt-api.js +79 -0
- package/src/wtt-client.js +144 -0
package/README.md
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# wtt-connect
|
|
2
|
+
|
|
3
|
+
`wtt-connect` is the WTT-native connector daemon. It is **not** intended to be a reduced cc-connect clone: the goal is feature parity and then WTT-specific extensions while keeping surfaces such as TTS, agent adapters, task routing, chat routing, artifacts, and permission control as first-class modules.
|
|
4
|
+
|
|
5
|
+
Implemented production-oriented surfaces:
|
|
6
|
+
|
|
7
|
+
- Long-lived WTT WebSocket client
|
|
8
|
+
- WTT chat and task event intake
|
|
9
|
+
- Per-session mailbox/actor queue (`topic_id` / `task_id`) so busy acks are never treated as final replies
|
|
10
|
+
- Durable local state store for session/thread ids, dedupe, and artifact ledger
|
|
11
|
+
- Multi-adapter registry and routing, aligned with cc-connect's agent backend matrix without depending on a cc-connect process:
|
|
12
|
+
- `codex` via `codex exec --json`
|
|
13
|
+
- `claude-code` via `claude -p --output-format stream-json`
|
|
14
|
+
- `cursor` via Cursor Agent CLI (`agent --print --output-format stream-json`)
|
|
15
|
+
- `gemini` via Gemini CLI (`gemini --output-format stream-json`)
|
|
16
|
+
- `qoder` via `qodercli -f stream-json`
|
|
17
|
+
- `opencode` / `crush` via OpenCode-style `run --format json`
|
|
18
|
+
- `iflow` via iFlow CLI
|
|
19
|
+
- `kimi` via Kimi CLI (`kimi --print --output-format stream-json`)
|
|
20
|
+
- `pi` via Cursor Background Agent (`pi --mode json`)
|
|
21
|
+
- `acp` for any Agent Client Protocol compatible agent
|
|
22
|
+
- `devin` through ACP (`devin acp`)
|
|
23
|
+
- Normalized tool/progress event publishing
|
|
24
|
+
- TTS extension point:
|
|
25
|
+
- `none`
|
|
26
|
+
- `macos-say` using the macOS `say` command, emitted as WAV when upload is enabled
|
|
27
|
+
- HTTP task status update path
|
|
28
|
+
- Permission broker for Codex modes, including explicit opt-in for dangerous `yolo`
|
|
29
|
+
- Optional WTT media artifact upload path (`/media/sign` → direct upload → `/media/commit`)
|
|
30
|
+
- Attachment staging for WTT message media/files; image attachments are passed to Codex with `--image` (including Claude Code image fallback when the Claude provider cannot view images directly)
|
|
31
|
+
- STT extension point (`command` and OpenAI/Whisper providers) for audio attachments
|
|
32
|
+
- Setup/claim-code command, smoke-task/smoke-chat commands, start script, and macOS launchd installer
|
|
33
|
+
- npm-installable Node.js implementation (Node >= 22) with runtime dependencies installed by npm
|
|
34
|
+
|
|
35
|
+
## Why this exists
|
|
36
|
+
|
|
37
|
+
cc-connect is a broad IM-to-agent bridge. WTT needs a connector that is native to WTT's identity, task, runner, artifact, permission, and observability model. `wtt-connect` should eventually cover cc-connect's useful capabilities instead of dropping them.
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
Install once, then bind each WTT agent identity with one command:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g wtt-connect
|
|
45
|
+
wtt-connect up codex agent-001 'wtt-tok-001'
|
|
46
|
+
wtt-connect up claude-code agent-002 'wtt-tok-002'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`up` writes a profile, installs a background service, enables it for the current user, starts it immediately, and prints status. On Linux it installs a `systemd --user` service; on macOS it installs a LaunchAgent. The npm install step installs package dependencies such as `node-pty`; users should not need to run `npm install` inside a cloned source tree.
|
|
50
|
+
|
|
51
|
+
Common management commands:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
wtt-connect list
|
|
55
|
+
wtt-connect status all
|
|
56
|
+
wtt-connect restart all
|
|
57
|
+
wtt-connect logs agent-001-codex --lines 100
|
|
58
|
+
wtt-connect down agent-001-codex
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For source-tree development:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
cd tools/wtt-connect
|
|
65
|
+
node ./bin/wtt-connect.js setup --claim-code
|
|
66
|
+
npm run doctor
|
|
67
|
+
npm start
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or run directly:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
node ./bin/wtt-connect.js doctor
|
|
74
|
+
node ./bin/wtt-connect.js start
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
Environment variables are loaded from `tools/wtt-connect/.env` and current working directory `.env`.
|
|
80
|
+
For multiple WTT agent identities, pass an explicit dotenv file with `--env-file` or `WTT_CONNECT_ENV_FILE`; that file is loaded before the default `.env` files, so it wins for that process.
|
|
81
|
+
|
|
82
|
+
Important settings:
|
|
83
|
+
|
|
84
|
+
- `WTT_BASE_URL`
|
|
85
|
+
- `WTT_AGENT_ID`
|
|
86
|
+
- `WTT_TOKEN`
|
|
87
|
+
- `WTT_CONNECT_ADAPTER=codex|claude-code|cursor|gemini|qoder|opencode|crush|iflow|kimi|pi|acp|devin`
|
|
88
|
+
- `WTT_CONNECT_ADAPTERS=codex,claude-code,cursor,gemini,qoder,opencode,iflow,kimi,pi,acp,devin`
|
|
89
|
+
- `WTT_CONNECT_WORKDIR`
|
|
90
|
+
- `WTT_CONNECT_MODE=full-auto|auto-edit|yolo|suggest`
|
|
91
|
+
- `WTT_CONNECT_AGENT_ALIASES=alias1,alias2` for extra @mention names in discussion/collaborative topics; `WTT_AGENT_ID` always works
|
|
92
|
+
- `WTT_CONNECT_ALLOW_YOLO=1` only when intentionally using `yolo`
|
|
93
|
+
- `WTT_CONNECT_STATE_DIR` / `WTT_CONNECT_STORE_FILE` for durable sessions
|
|
94
|
+
- `WTT_CONNECT_UPLOAD_ARTIFACTS=1` to upload generated summaries/TTS through WTT media
|
|
95
|
+
- `WTT_CONNECT_TTS_PROVIDER=none|macos-say`
|
|
96
|
+
- `WTT_CONNECT_STT_PROVIDER=none|command|openai|whisper` and `WTT_CONNECT_STT_COMMAND='...'`
|
|
97
|
+
- `WTT_CONNECT_STT_OPENAI_API_KEY`, `WTT_CONNECT_STT_OPENAI_BASE_URL`, `WTT_CONNECT_STT_OPENAI_MODEL`, `WTT_CONNECT_STT_OPENAI_TRANSPORT=auto|fetch|curl`, `WTT_CONNECT_STT_LANGUAGE` for OpenAI-compatible speech-to-text
|
|
98
|
+
- `WTT_CONNECT_ENABLE_SHELL=1` exposes an interactive agent-side Terminal from wtt-web for claimed online agents
|
|
99
|
+
- `WTT_CONNECT_SHELL_MODE=unsafe|readonly|off`; default `unsafe` runs one-shot shell commands without command filtering. The interactive Terminal always opens a real PTY shell on the agent host.
|
|
100
|
+
- `WTT_CONNECT_SHELL_TIMEOUT_SECONDS` and `WTT_CONNECT_SHELL_MAX_OUTPUT_CHARS` only bound legacy one-shot command execution and returned output
|
|
101
|
+
|
|
102
|
+
A JSON config may also be supplied:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
node ./bin/wtt-connect.js start --config ./config.json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### One-command service binding
|
|
109
|
+
|
|
110
|
+
The recommended install path for users is npm + `up`:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm install -g wtt-connect
|
|
114
|
+
wtt-connect up <agenttype> <agent_id> <token>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Examples:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
wtt-connect up codex agent-alice 'wtt-tok-alice'
|
|
121
|
+
wtt-connect up codex agent-bob 'wtt-tok-bob'
|
|
122
|
+
wtt-connect up claude-code agent-claude 'wtt-tok-claude'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Each call creates an independent profile and service:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
~/.config/wtt-connect/profiles/agent-alice-codex.env
|
|
129
|
+
~/.local/state/wtt-connect/agent-alice-codex/state.json
|
|
130
|
+
~/.config/systemd/user/wtt-connect@agent-alice-codex.service
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
On macOS the same profile and state paths are used, while the service file is:
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
~/Library/LaunchAgents/com.wtt.connect.agent-alice-codex.plist
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
A profile contains exactly one WTT identity: `WTT_AGENT_ID`, `WTT_TOKEN`, adapter, workdir, permission mode, and state directory. Multiple profiles may point at the same local `codex` or `claude` CLI binary; they must not share `WTT_AGENT_ID`, `WTT_TOKEN`, or `WTT_CONNECT_STATE_DIR`.
|
|
140
|
+
|
|
141
|
+
Useful flags:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
wtt-connect up codex agent-alice 'wtt-tok-alice' \
|
|
145
|
+
--mode yolo \
|
|
146
|
+
--allow-yolo \
|
|
147
|
+
--workdir /data/workspaces/alice \
|
|
148
|
+
--base-url https://www.waxbyte.com \
|
|
149
|
+
--enable-linger
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`--enable-linger` asks systemd to start the Linux user service at boot before an interactive login. Without it, the service starts when the user session starts. On macOS LaunchAgents start at user login; `--enable-linger` is ignored with a warning.
|
|
153
|
+
|
|
154
|
+
Start an already-created profile in the foreground:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
wtt-connect start --profile agent-alice-codex
|
|
158
|
+
wtt-connect doctor --profile agent-alice-codex
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Service names are platform-specific:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
Linux: wtt-connect@agent-alice-codex.service
|
|
165
|
+
macOS: com.wtt.connect.agent-alice-codex
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Logs are read with the same command on both platforms:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
wtt-connect logs agent-alice-codex --lines 100
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
On Linux this reads `journalctl --user`; on macOS it tails files under the profile state directory.
|
|
175
|
+
|
|
176
|
+
### Multiple WTT agent identities
|
|
177
|
+
|
|
178
|
+
Use one `wtt-connect` process per WTT agent identity. `wtt-connect up` is the preferred way to create those processes. Each process should have its own `WTT_AGENT_ID`, `WTT_TOKEN`, adapter default, and state directory:
|
|
179
|
+
|
|
180
|
+
```dotenv
|
|
181
|
+
# .env.codex
|
|
182
|
+
WTT_AGENT_ID=agent-codex
|
|
183
|
+
WTT_TOKEN=***
|
|
184
|
+
WTT_CONNECT_ADAPTER=codex
|
|
185
|
+
WTT_CONNECT_ADAPTERS=codex
|
|
186
|
+
WTT_CONNECT_STATE_DIR=.wtt-connect-codex
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```dotenv
|
|
190
|
+
# .env.claude
|
|
191
|
+
WTT_AGENT_ID=agent-claude
|
|
192
|
+
WTT_TOKEN=***
|
|
193
|
+
WTT_CONNECT_ADAPTER=claude-code
|
|
194
|
+
WTT_CONNECT_ADAPTERS=claude-code
|
|
195
|
+
WTT_CONNECT_STATE_DIR=.wtt-connect-claude
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Start them separately:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
./start.sh --env-file .env.codex
|
|
202
|
+
./start.sh --env-file .env.claude
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Install them as separate macOS LaunchAgents:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
./scripts/install-launchd.sh --name codex --env-file .env.codex
|
|
209
|
+
./scripts/install-launchd.sh --name claude --env-file .env.claude
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Install them as separate Linux `systemd --user` services from a source checkout if you are not using npm:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
./scripts/install-agent.sh codex agent-codex '***'
|
|
216
|
+
./scripts/install-agent.sh claude-code agent-claude '***'
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The npm equivalent is preferred for end users:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
wtt-connect up codex agent-codex '***'
|
|
223
|
+
wtt-connect up claude-code agent-claude '***'
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Use named options when you need a custom service name, permission mode, or boot-before-login behavior:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
./scripts/install-systemd-user.sh \
|
|
230
|
+
--name alice-codex \
|
|
231
|
+
--agent-id agent-codex \
|
|
232
|
+
--token '***' \
|
|
233
|
+
--adapter codex \
|
|
234
|
+
--mode yolo \
|
|
235
|
+
--allow-yolo \
|
|
236
|
+
--publish-progress \
|
|
237
|
+
--enable-linger
|
|
238
|
+
|
|
239
|
+
./scripts/install-systemd-user.sh \
|
|
240
|
+
--name alice-claude \
|
|
241
|
+
--agent-id agent-claude \
|
|
242
|
+
--token '***' \
|
|
243
|
+
--adapter claude-code \
|
|
244
|
+
--mode yolo \
|
|
245
|
+
--allow-yolo \
|
|
246
|
+
--publish-progress \
|
|
247
|
+
--enable-linger
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Each invocation writes a separate `.env.<name>`, `.wtt-connect-<name>` state directory, and `wtt-connect-<name>.service`. Multiple WTT agent identities may share the same local `codex` or `claude` CLI binary; only the WTT identity and state directory need to be unique.
|
|
251
|
+
|
|
252
|
+
Uninstall one identity with:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
./scripts/uninstall-launchd.sh --name codex
|
|
256
|
+
./scripts/uninstall-systemd-user.sh --name alice-codex
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Discussion/collaborative topics are mention-gated: `wtt-connect` only replies when the message targets its `WTT_AGENT_ID`, one of `WTT_CONNECT_AGENT_ALIASES`, backend-resolved `runner_agent_id`, or a multi-mention `mention_target_agent_ids` entry. P2P and task topics still run normally.
|
|
260
|
+
|
|
261
|
+
Adapter routing can be explicit through task fields such as `exec_mode=gemini`, or through message mentions such as `@codex`, `@claude`, `@cursor`, `@gemini`, `@qoder`, `@opencode`, `@iflow`, `@kimi`, `@pi`, `@acp`, or `@devin` when those adapters are enabled.
|
|
262
|
+
|
|
263
|
+
OpenClaw is deliberately not part of the default `wtt-connect` adapter set because WTT already has the first-class `wtt-plugin` for OpenClaw.
|
|
264
|
+
|
|
265
|
+
## Direction
|
|
266
|
+
|
|
267
|
+
Near-term parity targets with cc-connect:
|
|
268
|
+
|
|
269
|
+
1. Rich attachment rendering in WTT Web and task artifact schema persistence
|
|
270
|
+
2. Fine-grained permission broker with per-task policy, not just env-level modes
|
|
271
|
+
3. TTS/STT providers beyond macOS `say`
|
|
272
|
+
4. Multiple concurrent local adapters under one claimed WTT agent
|
|
273
|
+
5. Durable session store expanded across all native adapters
|
|
274
|
+
6. Tool/progress event normalization for WTT Web observability
|
|
275
|
+
7. Installer/claim flow integrated with wtt-web
|
|
276
|
+
8. Artifact schema in task rows, not only topic messages
|
|
277
|
+
|
|
278
|
+
## Production helpers
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
./start.sh
|
|
282
|
+
./scripts/install-launchd.sh
|
|
283
|
+
./scripts/uninstall-launchd.sh
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Smoke tests
|
|
287
|
+
|
|
288
|
+
Run the connector in one terminal, then:
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
node ./bin/wtt-connect.js smoke-task --expected WTT_CONNECT_TASK_READY
|
|
292
|
+
node ./bin/wtt-connect.js smoke-chat --expected WTT_CONNECT_CHAT_READY
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
`smoke-chat` requires a second sender agent via `WTT_SMOKE_SENDER_AGENT_ID` and `WTT_SMOKE_SENDER_TOKEN`.
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wtt-connect",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "WTT-native connector daemon for Codex, Claude Code, Cursor, Gemini, ACP, and other coding agent surfaces.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"wtt-connect": "bin/wtt-connect.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"check": "node --check bin/wtt-connect.js && node --check src/*.js && node --check src/adapters/*.js",
|
|
12
|
+
"doctor": "node ./bin/wtt-connect.js doctor",
|
|
13
|
+
"setup": "node ./bin/wtt-connect.js setup",
|
|
14
|
+
"smoke:task": "node ./bin/wtt-connect.js smoke-task",
|
|
15
|
+
"smoke:chat": "node ./bin/wtt-connect.js smoke-chat",
|
|
16
|
+
"start": "node ./bin/wtt-connect.js start"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"node-pty": "^1.1.0"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"bin",
|
|
26
|
+
"src",
|
|
27
|
+
"scripts",
|
|
28
|
+
"systemd",
|
|
29
|
+
"README.md",
|
|
30
|
+
"package.json"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
4
|
+
NAME=""
|
|
5
|
+
ENV_FILE=""
|
|
6
|
+
while [[ $# -gt 0 ]]; do
|
|
7
|
+
case "$1" in
|
|
8
|
+
--name)
|
|
9
|
+
NAME="$2"; shift 2 ;;
|
|
10
|
+
--env-file)
|
|
11
|
+
ENV_FILE="$2"; shift 2 ;;
|
|
12
|
+
*)
|
|
13
|
+
echo "unknown argument: $1" >&2
|
|
14
|
+
echo "usage: $0 [--name codex] [--env-file .env.codex]" >&2
|
|
15
|
+
exit 2 ;;
|
|
16
|
+
esac
|
|
17
|
+
done
|
|
18
|
+
if [[ -z "$NAME" && -n "$ENV_FILE" ]]; then
|
|
19
|
+
base="$(basename "$ENV_FILE")"
|
|
20
|
+
NAME="${base#.env.}"
|
|
21
|
+
NAME="${NAME#.env}"
|
|
22
|
+
fi
|
|
23
|
+
LABEL="com.wtt.connect${NAME:+.$NAME}"
|
|
24
|
+
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
|
25
|
+
mkdir -p "$HOME/Library/LaunchAgents" "$ROOT/logs"
|
|
26
|
+
PROGRAM_ARGS="<string>$ROOT/start.sh</string>"
|
|
27
|
+
if [[ -n "$ENV_FILE" ]]; then
|
|
28
|
+
PROGRAM_ARGS="$PROGRAM_ARGS<string>--env-file</string><string>$ENV_FILE</string>"
|
|
29
|
+
fi
|
|
30
|
+
NODE_BIN="$(command -v node || true)"
|
|
31
|
+
NODE_DIR="$(dirname "${NODE_BIN:-/usr/bin/node}")"
|
|
32
|
+
LAUNCH_PATH="$NODE_DIR:$PATH"
|
|
33
|
+
cat > "$PLIST" <<PLIST
|
|
34
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
35
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
36
|
+
<plist version="1.0"><dict>
|
|
37
|
+
<key>Label</key><string>$LABEL</string>
|
|
38
|
+
<key>ProgramArguments</key><array>$PROGRAM_ARGS</array>
|
|
39
|
+
<key>WorkingDirectory</key><string>$ROOT</string>
|
|
40
|
+
<key>EnvironmentVariables</key><dict>
|
|
41
|
+
<key>PATH</key><string>$LAUNCH_PATH</string>
|
|
42
|
+
</dict>
|
|
43
|
+
<key>RunAtLoad</key><true/>
|
|
44
|
+
<key>KeepAlive</key><true/>
|
|
45
|
+
<key>StandardOutPath</key><string>$ROOT/logs/${LABEL}.out.log</string>
|
|
46
|
+
<key>StandardErrorPath</key><string>$ROOT/logs/${LABEL}.err.log</string>
|
|
47
|
+
</dict></plist>
|
|
48
|
+
PLIST
|
|
49
|
+
launchctl unload "$PLIST" >/dev/null 2>&1 || true
|
|
50
|
+
launchctl load "$PLIST"
|
|
51
|
+
echo "installed $PLIST"
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
|
|
6
|
+
usage() {
|
|
7
|
+
local code="${1:-2}"
|
|
8
|
+
cat >&2 <<'USAGE'
|
|
9
|
+
Usage:
|
|
10
|
+
install-systemd-user.sh <agenttype> <agent_id> <token> [options]
|
|
11
|
+
install-systemd-user.sh --name <name> --agent-id <agent_id> --token <token> --adapter <adapter> [options]
|
|
12
|
+
|
|
13
|
+
Minimal:
|
|
14
|
+
<agenttype> codex or claude-code
|
|
15
|
+
<agent_id> WTT agent id
|
|
16
|
+
<token> WTT agent token
|
|
17
|
+
|
|
18
|
+
Named options:
|
|
19
|
+
--name <name> Local service/env suffix, e.g. alice-codex.
|
|
20
|
+
Defaults to <agent_id>-<adapter>.
|
|
21
|
+
--agent-id <agent_id> WTT agent id
|
|
22
|
+
--token <token> WTT agent token
|
|
23
|
+
--adapter <adapter> codex, claude-code, cursor, gemini, qoder, opencode, iflow, kimi, pi, acp, devin.
|
|
24
|
+
Defaults to codex.
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--base-url <url> WTT base URL (default: https://www.waxbyte.com)
|
|
28
|
+
--workdir <dir> Agent working directory (default: wtt-connect root)
|
|
29
|
+
--env-file <file> Env file to write (default: .env.<name>)
|
|
30
|
+
--state-dir <dir> State directory (default: .wtt-connect-<name>)
|
|
31
|
+
--mode <mode> full-auto, auto-edit, suggest, yolo (default: full-auto)
|
|
32
|
+
--allow-yolo Required when --mode yolo is used
|
|
33
|
+
--publish-progress Publish agent progress/status messages
|
|
34
|
+
--timeout <seconds> Per-run timeout (default: 3600)
|
|
35
|
+
--node-bin <path> node binary (default: command -v node)
|
|
36
|
+
--codex-bin <path> codex binary shared by any number of services
|
|
37
|
+
--claude-bin <path> claude binary shared by any number of services
|
|
38
|
+
--enable-linger Enable systemd user linger so services start at boot before login
|
|
39
|
+
--no-start Enable service but do not start it now
|
|
40
|
+
USAGE
|
|
41
|
+
exit "$code"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
NAME=""
|
|
45
|
+
AGENT_ID=""
|
|
46
|
+
TOKEN=""
|
|
47
|
+
ADAPTER=""
|
|
48
|
+
BASE_URL="https://www.waxbyte.com"
|
|
49
|
+
WORKDIR="$ROOT"
|
|
50
|
+
ENV_FILE=""
|
|
51
|
+
STATE_DIR=""
|
|
52
|
+
MODE="${WTT_CONNECT_MODE:-full-auto}"
|
|
53
|
+
ALLOW_YOLO=0
|
|
54
|
+
PUBLISH_PROGRESS=0
|
|
55
|
+
TIMEOUT_SECONDS=3600
|
|
56
|
+
NODE_BIN="${WTT_NODE_BIN:-$(command -v node || true)}"
|
|
57
|
+
CODEX_BIN="${WTT_CODEX_BIN:-$(command -v codex || true)}"
|
|
58
|
+
CLAUDE_BIN="${WTT_CLAUDE_BIN:-$(command -v claude || true)}"
|
|
59
|
+
ENABLE_LINGER=0
|
|
60
|
+
START_NOW=1
|
|
61
|
+
POSITIONAL=()
|
|
62
|
+
|
|
63
|
+
while [[ $# -gt 0 ]]; do
|
|
64
|
+
case "$1" in
|
|
65
|
+
--name) NAME="$2"; shift 2 ;;
|
|
66
|
+
--agent-id) AGENT_ID="$2"; shift 2 ;;
|
|
67
|
+
--token) TOKEN="$2"; shift 2 ;;
|
|
68
|
+
--adapter) ADAPTER="$2"; shift 2 ;;
|
|
69
|
+
--base-url) BASE_URL="$2"; shift 2 ;;
|
|
70
|
+
--workdir) WORKDIR="$2"; shift 2 ;;
|
|
71
|
+
--env-file) ENV_FILE="$2"; shift 2 ;;
|
|
72
|
+
--state-dir) STATE_DIR="$2"; shift 2 ;;
|
|
73
|
+
--mode) MODE="$2"; shift 2 ;;
|
|
74
|
+
--allow-yolo) ALLOW_YOLO=1; shift ;;
|
|
75
|
+
--publish-progress) PUBLISH_PROGRESS=1; shift ;;
|
|
76
|
+
--timeout) TIMEOUT_SECONDS="$2"; shift 2 ;;
|
|
77
|
+
--node-bin) NODE_BIN="$2"; shift 2 ;;
|
|
78
|
+
--codex-bin) CODEX_BIN="$2"; shift 2 ;;
|
|
79
|
+
--claude-bin) CLAUDE_BIN="$2"; shift 2 ;;
|
|
80
|
+
--enable-linger) ENABLE_LINGER=1; shift ;;
|
|
81
|
+
--no-start) START_NOW=0; shift ;;
|
|
82
|
+
-h|--help) usage 0 ;;
|
|
83
|
+
--*) echo "unknown argument: $1" >&2; usage ;;
|
|
84
|
+
*)
|
|
85
|
+
POSITIONAL+=("$1")
|
|
86
|
+
shift
|
|
87
|
+
;;
|
|
88
|
+
esac
|
|
89
|
+
done
|
|
90
|
+
|
|
91
|
+
if [[ "${#POSITIONAL[@]}" -gt 0 ]]; then
|
|
92
|
+
[[ -z "$AGENT_ID" && -z "$TOKEN" ]] || { echo "do not mix positional agent/token with --agent-id/--token" >&2; exit 2; }
|
|
93
|
+
[[ -z "$ADAPTER" ]] || { echo "do not mix positional agenttype with --adapter" >&2; exit 2; }
|
|
94
|
+
[[ "${#POSITIONAL[@]}" -eq 3 ]] || { echo "positional usage: $0 <agenttype> <agent_id> <token>" >&2; usage; }
|
|
95
|
+
ADAPTER="${POSITIONAL[0]}"
|
|
96
|
+
AGENT_ID="${POSITIONAL[1]}"
|
|
97
|
+
TOKEN="${POSITIONAL[2]}"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
ADAPTER="${ADAPTER:-codex}"
|
|
101
|
+
if [[ -z "$NAME" && -n "$AGENT_ID" ]]; then
|
|
102
|
+
NAME="$AGENT_ID-$ADAPTER"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
[[ -n "$NAME" && -n "$AGENT_ID" && -n "$TOKEN" && -n "$ADAPTER" ]] || usage
|
|
106
|
+
[[ -n "$NODE_BIN" && -x "$NODE_BIN" ]] || { echo "node binary not found; pass --node-bin" >&2; exit 1; }
|
|
107
|
+
|
|
108
|
+
SAFE_NAME="$(printf '%s' "$NAME" | tr -cs 'A-Za-z0-9_.@-' '-' | sed 's/^-//; s/-$//')"
|
|
109
|
+
[[ -n "$SAFE_NAME" ]] || { echo "invalid --name" >&2; exit 1; }
|
|
110
|
+
|
|
111
|
+
case "$MODE" in
|
|
112
|
+
suggest|auto-edit|full-auto|yolo) ;;
|
|
113
|
+
*) echo "invalid --mode: $MODE" >&2; exit 1 ;;
|
|
114
|
+
esac
|
|
115
|
+
if [[ "$MODE" == "yolo" && "$ALLOW_YOLO" != "1" ]]; then
|
|
116
|
+
echo "--mode yolo requires --allow-yolo" >&2
|
|
117
|
+
exit 1
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
ENV_FILE="${ENV_FILE:-$ROOT/.env.$SAFE_NAME}"
|
|
121
|
+
STATE_DIR="${STATE_DIR:-$ROOT/.wtt-connect-$SAFE_NAME}"
|
|
122
|
+
SERVICE_NAME="wtt-connect-$SAFE_NAME.service"
|
|
123
|
+
SYSTEMD_USER_DIR="$HOME/.config/systemd/user"
|
|
124
|
+
SERVICE_PATH="$SYSTEMD_USER_DIR/$SERVICE_NAME"
|
|
125
|
+
|
|
126
|
+
NODE_MAJOR="$("$NODE_BIN" -p 'Number(process.versions.node.split(".")[0])')"
|
|
127
|
+
NODE_WS_FLAG=()
|
|
128
|
+
if [[ "$NODE_MAJOR" -lt 22 ]]; then
|
|
129
|
+
NODE_WS_FLAG=(--experimental-websocket)
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
mkdir -p "$(dirname "$ENV_FILE")" "$STATE_DIR" "$SYSTEMD_USER_DIR"
|
|
133
|
+
|
|
134
|
+
{
|
|
135
|
+
echo "# wtt-connect config for $NAME"
|
|
136
|
+
echo "# Keep local; contains agent secrets."
|
|
137
|
+
echo "WTT_BASE_URL=$BASE_URL"
|
|
138
|
+
echo "WTT_AGENT_ID=$AGENT_ID"
|
|
139
|
+
echo "WTT_TOKEN=$TOKEN"
|
|
140
|
+
echo "WTT_CONNECT_ADAPTERS=$ADAPTER"
|
|
141
|
+
echo "WTT_CONNECT_ADAPTER=$ADAPTER"
|
|
142
|
+
echo "WTT_CONNECT_WORKDIR=$WORKDIR"
|
|
143
|
+
echo "WTT_CONNECT_MODE=$MODE"
|
|
144
|
+
if [[ "$ALLOW_YOLO" == "1" ]]; then echo "WTT_CONNECT_ALLOW_YOLO=1"; fi
|
|
145
|
+
echo "WTT_CONNECT_ENABLE_CHAT=1"
|
|
146
|
+
echo "WTT_CONNECT_PUBLISH_PROGRESS=$PUBLISH_PROGRESS"
|
|
147
|
+
echo "WTT_CONNECT_TASK_TIMEOUT_SECONDS=$TIMEOUT_SECONDS"
|
|
148
|
+
echo "WTT_CONNECT_STATE_DIR=$STATE_DIR"
|
|
149
|
+
echo "WTT_REQUIRE_COMMIT_PUSH=1"
|
|
150
|
+
if [[ -n "$CODEX_BIN" ]]; then echo "WTT_CODEX_BIN=$CODEX_BIN"; fi
|
|
151
|
+
if [[ -n "$CLAUDE_BIN" ]]; then echo "WTT_CLAUDE_BIN=$CLAUDE_BIN"; fi
|
|
152
|
+
} > "$ENV_FILE"
|
|
153
|
+
chmod 600 "$ENV_FILE"
|
|
154
|
+
|
|
155
|
+
cat > "$SERVICE_PATH" <<SERVICE
|
|
156
|
+
[Unit]
|
|
157
|
+
Description=WTT Connect Agent ($NAME)
|
|
158
|
+
After=network-online.target
|
|
159
|
+
Wants=network-online.target
|
|
160
|
+
|
|
161
|
+
[Service]
|
|
162
|
+
Type=simple
|
|
163
|
+
WorkingDirectory=$ROOT
|
|
164
|
+
Environment=PATH=/home/cecwxf/.local/npm-global/bin:/usr/local/bin:/usr/bin:/bin
|
|
165
|
+
ExecStart=$NODE_BIN ${NODE_WS_FLAG[*]} $ROOT/bin/wtt-connect.js start --env-file $ENV_FILE
|
|
166
|
+
Restart=always
|
|
167
|
+
RestartSec=5
|
|
168
|
+
|
|
169
|
+
[Install]
|
|
170
|
+
WantedBy=default.target
|
|
171
|
+
SERVICE
|
|
172
|
+
|
|
173
|
+
systemctl --user daemon-reload
|
|
174
|
+
if [[ "$START_NOW" == "1" ]]; then
|
|
175
|
+
systemctl --user enable --now "$SERVICE_NAME"
|
|
176
|
+
else
|
|
177
|
+
systemctl --user enable "$SERVICE_NAME"
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
if [[ "$ENABLE_LINGER" == "1" ]]; then
|
|
181
|
+
loginctl enable-linger "${USER}" || {
|
|
182
|
+
echo "warning: failed to enable linger; service will start when the user session starts" >&2
|
|
183
|
+
}
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
echo "installed service: $SERVICE_NAME"
|
|
187
|
+
echo "env file: $ENV_FILE"
|
|
188
|
+
echo "state dir: $STATE_DIR"
|
|
189
|
+
systemctl --user --no-pager --full status "$SERVICE_NAME" || true
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
NAME=""
|
|
4
|
+
while [[ $# -gt 0 ]]; do
|
|
5
|
+
case "$1" in
|
|
6
|
+
--name)
|
|
7
|
+
NAME="$2"; shift 2 ;;
|
|
8
|
+
*)
|
|
9
|
+
echo "unknown argument: $1" >&2
|
|
10
|
+
echo "usage: $0 [--name codex]" >&2
|
|
11
|
+
exit 2 ;;
|
|
12
|
+
esac
|
|
13
|
+
done
|
|
14
|
+
LABEL="com.wtt.connect${NAME:+.$NAME}"
|
|
15
|
+
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
|
16
|
+
launchctl unload "$PLIST" >/dev/null 2>&1 || true
|
|
17
|
+
rm -f "$PLIST"
|
|
18
|
+
echo "uninstalled $PLIST"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
|
|
6
|
+
usage() {
|
|
7
|
+
local code="${1:-2}"
|
|
8
|
+
cat >&2 <<'USAGE'
|
|
9
|
+
Usage:
|
|
10
|
+
uninstall-systemd-user.sh --name <name> [--delete-env]
|
|
11
|
+
USAGE
|
|
12
|
+
exit "$code"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
NAME=""
|
|
16
|
+
DELETE_ENV=0
|
|
17
|
+
while [[ $# -gt 0 ]]; do
|
|
18
|
+
case "$1" in
|
|
19
|
+
--name) NAME="$2"; shift 2 ;;
|
|
20
|
+
--delete-env) DELETE_ENV=1; shift ;;
|
|
21
|
+
-h|--help) usage 0 ;;
|
|
22
|
+
*) echo "unknown argument: $1" >&2; usage ;;
|
|
23
|
+
esac
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
[[ -n "$NAME" ]] || usage
|
|
27
|
+
SAFE_NAME="$(printf '%s' "$NAME" | tr -cs 'A-Za-z0-9_.@-' '-' | sed 's/^-//; s/-$//')"
|
|
28
|
+
[[ -n "$SAFE_NAME" ]] || { echo "invalid --name" >&2; exit 1; }
|
|
29
|
+
|
|
30
|
+
SERVICE_NAME="wtt-connect-$SAFE_NAME.service"
|
|
31
|
+
SERVICE_PATH="$HOME/.config/systemd/user/$SERVICE_NAME"
|
|
32
|
+
ENV_FILE="$ROOT/.env.$SAFE_NAME"
|
|
33
|
+
|
|
34
|
+
systemctl --user disable --now "$SERVICE_NAME" >/dev/null 2>&1 || true
|
|
35
|
+
rm -f "$SERVICE_PATH"
|
|
36
|
+
systemctl --user daemon-reload
|
|
37
|
+
|
|
38
|
+
if [[ "$DELETE_ENV" == "1" ]]; then
|
|
39
|
+
rm -f "$ENV_FILE"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
echo "uninstalled service: $SERVICE_NAME"
|