copilot-proxy-web 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # CHANGELOG
2
+
3
+ ## Unreleased
4
+ - Architecture: refactor `bin/run-web.js` into service-oriented modules with TDD guardrails (`daemon-service`, `daemon-state`, `cloudflare-service`, `cloudflare-state`, `cloudflare-setup-service`, `cloudflare-setup-deps`, `cloudflare-utils`)
5
+ - Tests: add focused unit tests for refactored modules (`cloudflare-utils`, `cloudflare-state`, `cloudflare-service`, `cloudflare-setup-service`, `cloudflare-setup-deps`, `daemon-service`)
6
+ - CLI behavior: keep `run/start/stop/status/check/cloudflare/wc` user-facing behavior stable while moving logic behind injectable services
7
+ - Cloudflare setup: preflight sections, domain inference, clearer hints, and overwrite guidance for DNS route conflicts
8
+ - Cloudflare status/diagnose: configurable local health check URL/path and improved output details
9
+ - Web UI: display app version in header (via API)
10
+ - API: expose app version in `/api/status` and `X-App-Version` header
11
+ - Web UI/API: interactive shell toggle for sessions (uses login+interactive shell)
12
+ - Conversation API + UI view (JSON snapshot, polling, idle hook)
13
+ - Conversation view: reduce duplicate output when terminal emits repetitive ANSI frames (planned)
14
+ - Conversation view: headless terminal buffer with dirty-row deltas and optional context lines
15
+ - Conversation view: profile selection now explicit (`none` or `copilot`), with `none` as default
16
+ - Conversation view: removed `auto` profile mode to avoid false positives; profile behavior is now deterministic
17
+ - Conversation view: Copilot prompt-block trimming remains profile-scoped (`copilot` only)
18
+ - Conversation view: suppress duplicate spinner-only frames via canonical terminal text de-dup
19
+ - Conversation view: show dirty row range in event meta header (e.g. `rows: 20-23`) for diagnostics
20
+ - Web UI: Send now triggers submit sequence (focus + enter)
21
+ - Web UI: textarea send uses API /keys + double submit to reliably trigger Copilot CLI thinking (WS-only input was flaky)
22
+ - Web UI: support `#conversation` URL hash deep-link and mode sync on toggle/hash change
23
+ - Web UI: new session default name increments as `tab01`, `tab02`, ... with local counter persistence
24
+ - Xterm view: fixed PTY-mode intermittent clipping on refresh by avoiding FitAddon in PTY mode and capping local display rows to visible viewport capacity
25
+ - Xterm view: improved replay/render settling with staged scroll-to-bottom callbacks after large writes
26
+ - Debug tooling: added `enableDebugMode()` / `disableDebugMode()` browser helpers and `cp_debug_xterm` localStorage toggle
27
+ - Debug tooling: added `Copy xterm debug` / `Reset xterm debug` buttons, in-memory log buffer, and clipboard reset support
28
+ - Known issue: xterm view may show duplicate/garbled output after refresh or view toggles (tracking)
29
+ - Packaging/metadata: tighten npm publish files, add description/keywords/engines, and update README install guidance
30
+ - Security: trust `X-Forwarded-For` only when explicitly enabled via `--use-x-forwarded-for` (or `USE_X_FORWARDED_FOR=1`)
31
+ - Security: simplified proxy trust config to a single switch (`--use-x-forwarded-for` / `USE_X_FORWARDED_FOR=1`)
32
+ - Test tooling: added `clean:appledouble` and run it before `test:ui` to avoid Playwright parsing macOS `._*` files
33
+
34
+ ## 1.0.0
35
+ - PTY-backed proxy for Copilot CLI
36
+ - Web UI (xterm.js) with multi-session tabs
37
+ - HTTP API + WebSocket streaming
38
+ - Idle hooks with Markdown pipeline
39
+ - Telegram sink support
40
+ - Auth token for API/WS
41
+ - Cloudflare Tunnel helpers (setup/start/stop/status/check)
42
+ - WSS client via `npx copilot-proxy-web wc`
43
+ - Unit tests for core helpers and CLI
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Copilot Proxy 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.arch.md ADDED
@@ -0,0 +1,87 @@
1
+ # Architecture
2
+
3
+ ## Overview
4
+
5
+ Copilot Proxy runs local PTY sessions and exposes them through Web UI, WebSocket streaming, and an HTTP API.
6
+
7
+ The codebase is now split into three layers:
8
+
9
+ - Launcher layer: `bin/run-web.js` (CLI parsing + command dispatch)
10
+ - Runtime layer: `copilot-proxy.js` (session manager + API/WS server + hooks pipeline)
11
+ - Service/helper layer: `lib/*` (daemon/cloudflare services, state stores, adapters, and pure helpers)
12
+
13
+ ## Diagram
14
+
15
+ ```
16
+ User/UI/Client
17
+ ├─ Web UI (xterm.js)
18
+ ├─ WebSocket client
19
+ └─ HTTP API client
20
+
21
+
22
+ copilot-proxy.js
23
+ ├─ Session Manager
24
+ │ ├─ Session (default)
25
+ │ │ └─ PTY (copilot shell)
26
+ │ └─ Session (s-*)
27
+ │ └─ PTY (copilot shell)
28
+ ├─ Hook Registry
29
+ │ ├─ Markdown pipeline
30
+ │ └─ Telegram sink
31
+ └─ Log files (run.log / idle.log)
32
+
33
+ CLI (bin/run-web.js)
34
+ ├─ daemon-service + daemon-state
35
+ │ └─ run/start/stop/status/check
36
+ ├─ cloudflare-service + cloudflare-state + cloudflare-utils
37
+ │ └─ cloudflare start/stop/status/check/diagnose/token
38
+ └─ cloudflare setup (still in run-web, uses shared helpers)
39
+ ```
40
+
41
+ ## Components
42
+
43
+ - `copilot-proxy.js`: runtime server, session manager, PTY spawn, API/WS wiring, hook pipeline.
44
+ - `bin/run-web.js`: launcher entry; parses CLI flags and routes subcommands.
45
+ - `public/`: Web UI (xterm.js) with session tabs.
46
+ - `lib/daemon-service.js`: background process lifecycle for run/start/stop/status/check.
47
+ - `lib/daemon-state.js`: pid/state file persistence for daemon lifecycle.
48
+ - `lib/cloudflare-service.js`: cloudflare lifecycle checks and status flow.
49
+ - `lib/cloudflare-state.js`: cloudflare pid/state/token persistence.
50
+ - `lib/cloudflare-utils.js`: pure hostname/path/check formatting helpers.
51
+ - `lib/`: other shared helpers (PTY utils, hooks, markdown, telegram, auth, log rotation).
52
+
53
+ ## Dependency direction
54
+
55
+ - `bin/run-web.js` depends on `lib/*` services/stores/utils.
56
+ - `copilot-proxy.js` depends on API/WS/helper modules under `lib/*`.
57
+ - `lib/*` modules do not depend on `bin/*`.
58
+ - State stores (`daemon-state`, `cloudflare-state`) are filesystem adapters used by services.
59
+
60
+ ## Data flow
61
+
62
+ 1) Web UI / WS client selects a session.
63
+ 2) Each session owns a PTY and its own history buffer.
64
+ 3) PTY output fan-outs to:
65
+ - Terminal stdout
66
+ - `run.log`
67
+ - WebSocket broadcast (per session)
68
+ - Idle buffer (per session)
69
+ - Hook registry (`raw_output`, `thinking_start`, `thinking_end`)
70
+ 4) Hooks can forward to:
71
+ - Markdown pipeline (idle log / markdown output)
72
+ - Telegram sink (MarkdownV2)
73
+
74
+ ## Auth
75
+
76
+ - HTTP: `Authorization: Bearer <token>`
77
+ - WebSocket: `Sec-WebSocket-Protocol: auth.<base64url(token)>`
78
+
79
+ ## Session scope
80
+
81
+ - WebSocket: `ws(s)://host/ws?sessionId=...`
82
+ - HTTP: `/api/sessions/:id/*` or `x-session-id` header or `?sessionId=...`
83
+ - Default session id: `default`
84
+
85
+ ## Cloudflare Tunnel
86
+
87
+ `cloudflare setup` writes an ingress rule that maps a public hostname (optional path) to a local service target (default: `http://127.0.0.1:<port>`).
package/README.md ADDED
@@ -0,0 +1,295 @@
1
+ # Copilot Proxy
2
+
3
+ NPM package: `copilot-proxy-web`.
4
+
5
+ Proxy GitHub Copilot CLI through a PTY with a Web UI, WebSocket streaming, and an HTTP API, plus an idle-based output hook pipeline.
6
+
7
+ ## Screenshots
8
+
9
+ ![Web UI - Index 01](https://raw.githubusercontent.com/changyy/copilot-proxy-web/main/resource/screenshots/index-01.png)
10
+ ![Web UI - Index 02](https://raw.githubusercontent.com/changyy/copilot-proxy-web/main/resource/screenshots/index-02.png)
11
+
12
+ ## Quickstart
13
+
14
+ Install:
15
+
16
+ ```bash
17
+ npm i -g copilot-proxy-web
18
+ ```
19
+
20
+ Run Web UI + API:
21
+
22
+ ```bash
23
+ npx copilot-proxy-web run
24
+ ```
25
+
26
+ Recommended run modes:
27
+
28
+ ```bash
29
+ # Local/default (do not trust proxy headers)
30
+ npx copilot-proxy-web run --web --auth-token YOUR_TOKEN
31
+
32
+ # Behind a trusted reverse proxy (Cloudflare, etc.)
33
+ npx copilot-proxy-web run --web --auth-token YOUR_TOKEN --use-x-forwarded-for
34
+ ```
35
+
36
+ For local development:
37
+
38
+ ```bash
39
+ npm install
40
+ ```
41
+
42
+ Background mode:
43
+
44
+ ```bash
45
+ npx copilot-proxy-web start
46
+ npx copilot-proxy-web status
47
+ npx copilot-proxy-web check
48
+ npx copilot-proxy-web stop
49
+ ```
50
+
51
+ Trusted reverse proxy mode:
52
+
53
+ ```bash
54
+ npx copilot-proxy-web start --auth-token YOUR_TOKEN --use-x-forwarded-for
55
+ ```
56
+
57
+ Open Web UI:
58
+
59
+ ```
60
+ http://localhost:3000
61
+ ```
62
+
63
+ Create a session in the Web UI and set the command to run, for example:
64
+
65
+ ```
66
+ copilot --model gpt-5-mini
67
+ ```
68
+
69
+ The session modal includes an "Interactive shell" toggle (default on). When enabled, commands run via a login+interactive shell (`-lic`).
70
+
71
+ ## CLI
72
+
73
+ Primary commands:
74
+
75
+ ```bash
76
+ npx copilot-proxy-web run
77
+ npx copilot-proxy-web start
78
+ npx copilot-proxy-web stop
79
+ npx copilot-proxy-web status
80
+ npx copilot-proxy-web check
81
+ npx copilot-proxy-web wc --url ws://127.0.0.1:3000/ws --sessionId default
82
+ npx copilot-proxy-web cloudflare setup --hostname proxy.example.com
83
+ ```
84
+
85
+ ## WebSocket client (wc)
86
+
87
+ Basic:
88
+
89
+ ```bash
90
+ npx copilot-proxy-web wc --url ws://127.0.0.1:3000/ws --sessionId default
91
+ ```
92
+
93
+ With AUTH_TOKEN:
94
+
95
+ ```bash
96
+ AUTH_TOKEN=YOUR_TOKEN npx copilot-proxy-web wc --url wss://proxy.example.com/ws --sessionId default
97
+ ```
98
+
99
+ With Cloudflare Access (Service Token):
100
+
101
+ ```bash
102
+ npx copilot-proxy-web wc \
103
+ --url wss://proxy.example.com/ws \
104
+ --sessionId default \
105
+ --token YOUR_TOKEN \
106
+ --cf-access-id YOUR_ACCESS_ID \
107
+ --cf-access-secret YOUR_ACCESS_SECRET
108
+ ```
109
+
110
+ Custom headers / Origin:
111
+
112
+ ```bash
113
+ npx copilot-proxy-web wc --url wss://ws.ptt.cc:443/bbs \
114
+ --origin https://term.ptt.cc \
115
+ --header "User-Agent: my-client/1.0"
116
+ ```
117
+
118
+ ## Cloudflare Zero Trust (Tunnel)
119
+
120
+ Setup (DNS route is created by `cloudflared`):
121
+
122
+ ```bash
123
+ npx copilot-proxy-web cloudflare setup --hostname proxy.example.com
124
+ ```
125
+
126
+ During setup, the CLI prints a preflight report (DNS route, tunnel, credentials/token).
127
+
128
+ Optional overrides:
129
+
130
+ ```bash
131
+ npx copilot-proxy-web cloudflare setup \
132
+ --hostname proxy.example.com \
133
+ --domain example.com \
134
+ --tunnel-name copilot-proxy-web \
135
+ --port 3000 \
136
+ --service http
137
+ ```
138
+
139
+ `--domain` is optional but recommended. It prevents mismatched zones and allows short hostnames. If omitted, it is auto-inferred from the last two labels of `--hostname` (e.g. `a.b.c.d` -> `c.d`):
140
+
141
+ ```bash
142
+ npx copilot-proxy-web cloudflare setup --hostname office --domain ainfo.me
143
+ ```
144
+
145
+ You can also pin a longer zone explicitly:
146
+
147
+ ```bash
148
+ npx copilot-proxy-web cloudflare setup --hostname a.b.c.d --domain b.c.d
149
+ ```
150
+
151
+ Or set a full service target (including path):
152
+
153
+ ```bash
154
+ npx copilot-proxy-web cloudflare setup \
155
+ --hostname proxy.example.com \
156
+ --service-url https://127.0.0.1:3000/
157
+ ```
158
+
159
+ Match a path on the public hostname:
160
+
161
+ ```bash
162
+ npx copilot-proxy-web cloudflare setup \
163
+ --hostname proxy.example.com \
164
+ --path /path01 \
165
+ --service-url http://127.0.0.1:3000/path02
166
+ ```
167
+
168
+ This maps `https://proxy.example.com/path01` to `http://127.0.0.1:3000/path02`.
169
+
170
+ Start/stop/status/check:
171
+
172
+ ```bash
173
+ npx copilot-proxy-web cloudflare start
174
+ npx copilot-proxy-web cloudflare status
175
+ npx copilot-proxy-web cloudflare check
176
+ npx copilot-proxy-web cloudflare diagnose
177
+ npx copilot-proxy-web cloudflare stop
178
+ ```
179
+
180
+ Token mode (optional):
181
+
182
+ ```bash
183
+ npx copilot-proxy-web cloudflare token set --token <TOKEN>
184
+ npx copilot-proxy-web cloudflare token get
185
+ npx copilot-proxy-web cloudflare token clear
186
+ ```
187
+
188
+ ## API
189
+
190
+ Status:
191
+
192
+ ```bash
193
+ curl http://localhost:3000/api/status
194
+ ```
195
+
196
+ Send text:
197
+
198
+ ```bash
199
+ curl -X POST http://localhost:3000/api/send \
200
+ -H 'Content-Type: application/json' \
201
+ -d '{"text":"hello", "submit": true}'
202
+ ```
203
+
204
+ Sessions:
205
+
206
+ ```bash
207
+ curl -X POST http://localhost:3000/api/sessions \
208
+ -H 'Content-Type: application/json' \
209
+ -d '{"id":"s1", "autoStart": false}'
210
+
211
+ curl -X POST http://localhost:3000/api/sessions/s1/start \
212
+ -H 'Content-Type: application/json' \
213
+ -d '{"command":"copilot --model gpt-5-mini"}'
214
+
215
+ curl http://localhost:3000/api/sessions
216
+ ```
217
+
218
+ Conversation (JSON):
219
+
220
+ ```bash
221
+ curl http://localhost:3000/api/sessions/s1/conversation
222
+ ```
223
+
224
+ Conversation rendering (server-side):
225
+
226
+ - `CONVERSATION_CONTEXT` (default: 1) adds surrounding lines when emitting terminal deltas.
227
+ - `CONVERSATION_PROFILE` (default: none) enables optional profile-specific filtering.
228
+ - `--conversation-profile copilot|none` overrides profile per session start.
229
+
230
+ Web UI deep link:
231
+
232
+ - `http://localhost:3000/?sessionId=tab1#conversation` opens directly in Conversation view.
233
+
234
+ ## Auth (Token)
235
+
236
+ Enable auth by providing a token (CLI or env). API requests must include:
237
+
238
+ ```
239
+ Authorization: Bearer YOUR_TOKEN
240
+ ```
241
+
242
+ CLI:
243
+
244
+ ```bash
245
+ node copilot-proxy.js --auth-token YOUR_TOKEN --web --port 3000 --shell -- copilot
246
+ ```
247
+
248
+ WebSocket auth uses `Sec-WebSocket-Protocol`:
249
+
250
+ ```
251
+ auth.<base64url(token)>
252
+ ```
253
+
254
+ ## Security notes
255
+
256
+ - Always set `AUTH_TOKEN` when binding to a non-loopback host.
257
+ - `X-Forwarded-For` is ignored by default. Enable `--use-x-forwarded-for` (or `USE_X_FORWARDED_FOR=1`) only when running behind a trusted reverse proxy.
258
+ - Web UI stores the token in `sessionStorage`; avoid logging in on shared or untrusted devices.
259
+ - PTY input/output logs and idle hooks may contain sensitive content; protect or disable logging if needed.
260
+ - Cloudflare tunnel credentials and tokens are stored under `~/.cloudflared` and `~/.copilot-proxy-web/cloudflare`. Treat them as secrets.
261
+
262
+ ## TODO
263
+
264
+ - Conversation: reduce duplicate terminal output in conversation view.
265
+
266
+ ## Logs
267
+
268
+ - Runtime output log follows `--log` (default: `run.log`).
269
+ - Access ledger is written to `access.log` under the same log directory.
270
+ - Access entries are JSON lines and include `type`, `ip`, `path`, `status`, `auth`, and timestamp.
271
+ - `ACCESS_LOG_MODE` controls verbosity:
272
+ - `auth` (default): only auth failures/blocks on `/api/*` (plus HTTP 5xx).
273
+ - `all`: log all API/WS access events.
274
+ - `off`: disable `access.log`.
275
+
276
+ ## Web UI notes
277
+
278
+ - When `--no-default-session` is used, Web UI starts with no tabs and prompts to create a session.
279
+ - Session tabs show running/stopped and allow start for stopped sessions.
280
+
281
+ ## Tests
282
+
283
+ ```bash
284
+ npm test
285
+ npm run test:ui
286
+ npx playwright install
287
+ ```
288
+
289
+ ## Code layout
290
+
291
+ - `copilot-proxy.js` main runtime
292
+ - `bin/run-web.js` CLI entry
293
+ - `public/` Web UI
294
+ - `lib/` shared helpers
295
+ - `test/` unit tests