tabminal 2.0.15 → 2.0.16

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.
Files changed (3) hide show
  1. package/AGENTS.md +360 -209
  2. package/README.md +2 -2
  3. package/package.json +1 -1
package/AGENTS.md CHANGED
@@ -1,320 +1,471 @@
1
1
  # Tabminal Agent Notes
2
2
 
3
- Last updated: 2026-03-23
3
+ Last updated: 2026-03-27
4
4
 
5
- This file is for future AI/code agents working in this repo.
6
- Goal: keep context accurate, avoid reintroducing old bugs, and preserve current UX
7
- contracts after the multi-host refactor.
5
+ This file is for future coding agents working in this repo.
6
+ Keep it current, specific, and operational. The main goal is to preserve the
7
+ current product contracts so later work does not regress multi-host behavior,
8
+ ACP agent UX, or mobile ergonomics.
8
9
 
9
10
  ## 1) Project Snapshot
10
11
 
11
- - Runtime: Node.js >= 22, ESM project.
12
- - Backend entry: `src/server.mjs`.
13
- - Frontend entry: `public/app.js` (plus modules in `public/modules/`).
14
- - PWA shell: `public/index.html` + `public/sw.js`.
15
- - Native app workspace: `apps/`
16
- - Apple client: `apps/Apple`
17
- - Ghostty vendor tooling: `apps/ghostty-vendor`
18
- - Multi-host registry persistence: `~/.tabminal/cluster.json` via backend API.
12
+ - Runtime: Node.js `>= 22`, ESM project.
13
+ - Backend entry: `/Users/leask/Documents/Tabminal/src/server.mjs`
14
+ - Frontend entry: `/Users/leask/Documents/Tabminal/public/app.js`
15
+ - PWA shell:
16
+ - `/Users/leask/Documents/Tabminal/public/index.html`
17
+ - `/Users/leask/Documents/Tabminal/public/sw.js`
18
+ - Native app workspace:
19
+ - `/Users/leask/Documents/Tabminal/apps/Apple`
20
+ - `/Users/leask/Documents/Tabminal/apps/ghostty-vendor`
19
21
 
20
- Core idea now:
21
- - One web app can connect to multiple Tabminal backends.
22
- - Main host controls page-level auth modal/state.
23
- - Sub-hosts are independent connection/auth units and can reconnect separately.
22
+ Current product shape:
24
23
 
25
- ## 2) Non-Negotiable Behavior Contracts
24
+ - Persistent terminal sessions remain the core product.
25
+ - There are now two AI surfaces:
26
+ - terminal-native assistant in `src/terminal-session.mjs`
27
+ - ACP agent workspace in `src/acp-manager.mjs` + `public/app.js`
28
+ - One web UI can connect to multiple Tabminal hosts.
29
+ - The workspace bar now mixes file tabs, agent tabs, and pinned terminal tabs.
30
+
31
+ Important persistence files under `~/.tabminal`:
32
+
33
+ - `config.json`
34
+ - `cluster.json`
35
+ - `agent-tabs.json`
36
+ - `agent-config.json`
37
+
38
+ ## 2) Non-Negotiable Contracts
26
39
 
27
40
  ### 2.1 Host model and state isolation
28
41
 
29
- - UI term is `Host` (not `Server`) for user-facing labels.
42
+ - UI term is `Host`, not `Server`, for user-facing labels.
30
43
  - Every session belongs to exactly one host.
31
- - Session/editor/file-tree/expanded-path state is host-isolated.
44
+ - Session state, editor state, file tree state, ACP agent tabs, and workspace
45
+ tabs are host-isolated.
32
46
  - Do not merge runtime state across hosts.
33
47
 
34
48
  Relevant code:
35
- - `public/app.js` (`state.servers`, `state.sessions`, `makeSessionKey` usage)
36
- - `public/modules/session-meta.js`
49
+ - `/Users/leask/Documents/Tabminal/public/app.js`
50
+ - `/Users/leask/Documents/Tabminal/public/modules/session-meta.js`
37
51
 
38
52
  ### 2.2 Auth model
39
53
 
40
- - Main host (`id = 'main'`) auth controls the app login modal.
41
- - Only main host 401/403 should trigger global login modal.
42
- - Sub-host 401/403 should mark that host as reconnect/login required, not global logout.
43
- - Sub-host may require Cloudflare Access login without password change.
54
+ - Main host (`id = 'main'`) controls the global login modal.
55
+ - Only main-host `401/403` should trigger app-wide login UI.
56
+ - Sub-host auth failures must stay local to that host.
57
+ - Sub-hosts may require Cloudflare Access login without password change.
44
58
 
45
59
  Relevant code:
46
- - `public/app.js` `ServerClient.handleUnauthorized`
47
- - `public/app.js` `ServerClient.handleAccessRedirect`
60
+ - `/Users/leask/Documents/Tabminal/public/app.js`
61
+ - `ServerClient.handleUnauthorized`
62
+ - `ServerClient.handleAccessRedirect`
48
63
 
49
- ### 2.3 Token storage contract
64
+ ### 2.3 Token storage
50
65
 
51
66
  - Main host token:
52
- - persisted in browser `localStorage` key `tabminal_auth_token:main`.
67
+ - browser `localStorage`
68
+ - key: `tabminal_auth_token:main`
53
69
  - Sub-host tokens:
54
- - persisted in backend registry `~/.tabminal/cluster.json`.
55
- - should not persist in browser localStorage.
56
- - Removing a host should remove any stale local token key for that host id.
70
+ - persisted in backend `cluster.json`
71
+ - do not persist in browser `localStorage`
72
+ - Removing a host should also remove any stale local token keyed to that host.
57
73
 
58
74
  Relevant code:
59
- - `public/app.js` `ServerClient.constructor`, `ServerClient.setToken`
60
- - `src/persistence.mjs` `loadCluster` / `saveCluster`
75
+ - `/Users/leask/Documents/Tabminal/public/app.js`
76
+ - `/Users/leask/Documents/Tabminal/src/persistence.mjs`
61
77
 
62
- ### 2.4 Host registry persistence contract
78
+ ### 2.4 Host registry persistence
63
79
 
64
- - Frontend does not own host list persistence anymore.
65
- - Source of truth: backend `GET/PUT /api/cluster`.
66
- - File format in `~/.tabminal/cluster.json`:
80
+ - Frontend is not the source of truth for host list persistence.
81
+ - Source of truth is backend `GET/PUT /api/cluster`.
82
+ - File format:
67
83
  - `{ "servers": [{ id, baseUrl, host, token }, ...] }`
68
- - On page load, host list is restored from backend after main host auth succeeds.
84
+ - On page load, host list restores only after main-host auth succeeds.
69
85
 
70
86
  Relevant code:
71
- - `public/app.js` `loadServerRegistryFromBackend`, `saveServerRegistryToBackend`
72
- - `src/server.mjs` `/api/cluster`
73
- - `src/persistence.mjs` cluster helpers
87
+ - `/Users/leask/Documents/Tabminal/public/app.js`
88
+ - `/Users/leask/Documents/Tabminal/src/server.mjs`
89
+ - `/Users/leask/Documents/Tabminal/src/persistence.mjs`
74
90
 
75
91
  ### 2.5 Deduplication and self-host skip
76
92
 
77
93
  - Host uniqueness key is normalized `hostname[:port]` in lowercase.
78
- - Path is not part of dedupe key.
79
- - Registry hydration skips entries that resolve to current main node
80
- (same endpoint key or same hostname) to prevent self-loop duplicates.
81
- - This is intentional to support sharing one cluster config across nodes.
94
+ - Path is intentionally not part of the dedupe key.
95
+ - Hydration skips entries that resolve to the current main node to avoid
96
+ self-loop duplicates.
97
+ - Path-based multi-host routing such as `/a/*` and `/b/*` is not supported by
98
+ the current client assumptions.
82
99
 
83
100
  Relevant code:
84
- - `public/modules/url-auth.js` `getServerEndpointKeyFromUrl`
85
- - `public/app.js` `findServerByEndpointKey`, `hydrateServerRegistry`
86
-
87
- Important implication:
88
- - Path-based multi-host on one domain (like `/a/*`, `/b/*`) is not supported by current
89
- client routing assumptions.
101
+ - `/Users/leask/Documents/Tabminal/public/modules/url-auth.js`
102
+ - `/Users/leask/Documents/Tabminal/public/app.js`
90
103
 
91
104
  ### 2.6 Session creation ownership
92
105
 
93
- - Backend no longer auto-creates a default session/tab.
94
- - Frontend ensures usability:
95
- - if no sessions after init, create one on main host.
96
- - if user closes last session, create one on main host.
106
+ - Backend does not auto-create a default session anymore.
107
+ - Frontend is responsible for usability:
108
+ - create one main-host session if init returns none
109
+ - recreate one main-host session if user closes the last session
97
110
 
98
111
  Relevant code:
99
- - `public/app.js` `initApp`, `closeSession`
100
- - `src/server.mjs` (no auto-create fallback)
112
+ - `/Users/leask/Documents/Tabminal/public/app.js`
113
+ - `/Users/leask/Documents/Tabminal/src/server.mjs`
101
114
 
102
- ### 2.7 Polling / heartbeat behavior
115
+ ### 2.7 Polling and heartbeat
103
116
 
104
- - Online heartbeat sync interval: `1000ms` (frontend).
105
- - Reconnect retry cadence when host is down: `5000ms` throttle per host.
106
- - Do not remove strong polling; it is a UX requirement.
117
+ - Frontend heartbeat cadence: `1000ms`
118
+ - Reconnect retry throttle per host: `5000ms`
119
+ - Do not weaken these without measuring UX fallout.
107
120
 
108
121
  Relevant code:
109
- - `public/app.js`
110
- - `HEARTBEAT_INTERVAL_MS = 1000`
111
- - `RECONNECT_RETRY_MS = 5000`
112
- - `syncServer`, `ServerClient.startHeartbeat`
122
+ - `/Users/leask/Documents/Tabminal/public/app.js`
113
123
 
114
124
  ### 2.8 Cloudflare Access handling
115
125
 
116
- Current behavior for sub-hosts:
117
- - requests use `credentials: 'include'` so Access cookies can be sent.
118
- - requests default to `redirect: 'manual'` on non-main hosts.
119
- - Access redirect is treated as reconnect reason, not generic password failure.
120
- - reconnect UI can trigger opening host root in a new tab for Access login.
126
+ - Non-main host requests use `credentials: 'include'`.
127
+ - Non-main host fetches default to `redirect: 'manual'`.
128
+ - Access redirects should show reconnect/login state, not generic password
129
+ failure.
130
+ - Reconnect UI may open the host root in a new tab for Access login.
121
131
 
122
132
  Relevant code:
123
- - `public/app.js`
124
- - `ServerClient.fetch`
125
- - `probeAccessLoginUrl`
126
- - `openAccessLoginPage`
127
- - `public/modules/url-auth.js`
128
- - `isAccessRedirectResponse`
129
- - `buildAccessLoginUrl` (root origin)
133
+ - `/Users/leask/Documents/Tabminal/public/app.js`
134
+ - `/Users/leask/Documents/Tabminal/public/modules/url-auth.js`
130
135
 
131
- ### 2.9 CORS policy in backend
136
+ ### 2.9 Runtime version and PWA coherence
132
137
 
133
- - Backend currently allows cross-origin by reflecting request origin when present.
134
- - For requests without origin, backend returns `Access-Control-Allow-Origin: *`.
135
- - OPTIONS is handled with 204 directly.
136
- - No per-origin `cors-origin` config is used now.
138
+ - Backend heartbeat returns runtime boot id.
139
+ - Frontend appends `?rt=<bootId>` and reloads on runtime change.
140
+ - `index.html` versions `styles.css` and `app.js` with runtime key.
141
+ - Service worker is versioned the same way.
137
142
 
138
143
  Relevant code:
139
- - `src/server.mjs` top-level CORS middleware
144
+ - `/Users/leask/Documents/Tabminal/src/server.mjs`
145
+ - `/Users/leask/Documents/Tabminal/public/app.js`
146
+ - `/Users/leask/Documents/Tabminal/public/index.html`
147
+ - `/Users/leask/Documents/Tabminal/public/sw.js`
140
148
 
141
- ### 2.10 Runtime version and PWA cache coherence
149
+ ## 3) ACP Design Contracts
142
150
 
143
- - Backend heartbeat returns runtime boot id.
144
- - Frontend appends `?rt=<bootId>` to URL and reloads on server restart/version change.
145
- - `index.html` loads `styles.css` and `app.js` using runtime key.
146
- - SW is registered with `?rt=<bootId>`, cache key includes that runtime id.
147
- - App shell (`/`, `/index.html`, `/app.js`, `/styles.css`, `/modules/*`) uses
148
- network-first.
151
+ ### 3.1 ACP architecture shape
149
152
 
150
- Relevant code:
151
- - `src/server.mjs` `/api/heartbeat` -> `runtime.bootId`
152
- - `public/app.js` `handlePrimaryRuntimeVersion`
153
- - `public/index.html` runtime loader script
154
- - `public/sw.js`
153
+ - Tabminal embeds an ACP supervisor in the backend.
154
+ - ACP agents are not implemented in-repo; Tabminal launches or attaches to
155
+ external ACP runtimes.
156
+ - Built-in definitions currently include:
157
+ - Gemini CLI
158
+ - Codex CLI
159
+ - Claude Agent
160
+ - GitHub Copilot
161
+ - ACP Test Agent when `TABMINAL_ENABLE_TEST_AGENT=1`
155
162
 
156
- ## 3) UX Contracts to Keep
163
+ Relevant code:
164
+ - `/Users/leask/Documents/Tabminal/src/acp-manager.mjs`
165
+ - `/Users/leask/Documents/Tabminal/src/acp-test-agent.mjs`
157
166
 
158
- ### 3.1 Sidebar host controls
167
+ ### 3.2 ACP workspace model
159
168
 
160
- - Per-host row: primary action button + (non-main only) remove button.
161
- - Remove button is overlay style (top-left), hidden by default, fades in on hover/focus.
162
- - Main host has no remove button.
163
- - Main button text:
164
- - normal: `New Tab @ <Host>`
165
- - reconnect: `Reconnect <Host>`
166
- - access flow: `Cloudflare Login <Host>`
167
- - Second line includes latency text + heartbeat dot + mini heartbeat canvas.
169
+ - Agent tabs share the same workspace strip as file tabs and pinned terminal
170
+ tabs.
171
+ - Showing the agent workspace must not force-open the file tree.
172
+ - Showing the file tree must not be required for agent tabs to exist.
173
+ - Workspace bar should stay visible whenever there is any open file tab, agent
174
+ tab, or pinned terminal tab.
168
175
 
169
176
  Relevant code:
170
- - `public/app.js` `renderServerControls`
171
- - `public/styles.css` `.server-row`, `.server-main-button`, `.server-delete-button`
177
+ - `/Users/leask/Documents/Tabminal/public/app.js`
178
+ - `/Users/leask/Documents/Tabminal/public/styles.css`
172
179
 
173
- ### 3.2 Host naming display
180
+ ### 3.3 Agent dropdown and toggle behavior
174
181
 
175
- Display priority for host name:
176
- 1. configured `host` alias
177
- 2. runtime hostname from host heartbeat
178
- 3. URL hostname
179
- 4. `'unknown'`
182
+ - Left sidebar robot button is a toggle.
183
+ - First click opens the host-scoped agent dropdown.
184
+ - Clicking the same button again closes it.
185
+ - If either file tree or agent toggle is active, the opposite control remains
186
+ visible; do not let one disappear while the other is lit.
180
187
 
181
- Session metadata line should stay:
182
- - `HOST: user@<host>`
183
- - host text uses `.host-emphasis` style.
188
+ ### 3.4 Jump in semantics
189
+
190
+ - `Jump in` is not a read-only preview.
191
+ - While the managed terminal is still alive, it should switch into a real
192
+ controllable terminal session.
193
+ - If the terminal has already exited, the restored session is effectively
194
+ history-only.
195
+ - Agent sync must never steal focus back from a session the user jumped into.
184
196
 
185
197
  Relevant code:
186
- - `public/modules/session-meta.js`
198
+ - `/Users/leask/Documents/Tabminal/public/app.js`
187
199
 
188
- ### 3.3 Path display
200
+ ### 3.5 Hidden terminal resize contract
189
201
 
190
- - PWD display in tab meta uses fish-style compact path shortening.
191
- - Keep this style unless a full UX redesign is explicitly requested.
202
+ - If a main terminal is hidden because it is pinned into a workspace tab and is
203
+ not the active visible tab, do not report resized dimensions from that hidden
204
+ state back to the backend.
205
+ - Keep the previous valid size instead.
206
+ - This prevents broken sidebar previews caused by tiny hidden-layout sizes.
192
207
 
193
208
  Relevant code:
194
- - `public/modules/session-meta.js` `shortenPathFishStyle`
209
+ - `/Users/leask/Documents/Tabminal/public/app.js`
195
210
 
196
- ### 3.4 Small-screen rule (< 600px height)
211
+ ### 3.6 Shell ready noise filtering
197
212
 
198
- - `new-tab-item` region is capped to two-button area height and scrollable.
199
- - This is intentional for small-height mobile/embedded layouts.
213
+ - `TABMINAL_SHELL_READY=1` and related shell bootstrap commands are internal.
214
+ - They must not produce user notifications or visible execution-completed noise.
200
215
 
201
216
  Relevant code:
202
- - `public/styles.css` `@media (max-height: 600px)` on `.new-tab-item`
217
+ - `/Users/leask/Documents/Tabminal/shell/tabminal-bashrc`
218
+ - `/Users/leask/Documents/Tabminal/src/terminal-session.mjs`
219
+ - `/Users/leask/Documents/Tabminal/public/app.js`
203
220
 
204
- ## 4) Known Pitfalls and Their Root Causes
221
+ ### 3.7 Agent plan behavior
205
222
 
206
- ### 4.1 `SecurityError: insecure WebSocket from HTTPS page`
223
+ - In-progress plan lives in the fixed area between activity strip and composer.
224
+ - Once fully completed, it should archive into transcript history and stop
225
+ occupying the fixed panel slot.
226
+ - Completed plans are historical transcript content, not permanent composer UI.
207
227
 
208
- Cause:
209
- - trying `ws://` from HTTPS page.
210
- Current mitigation:
211
- - WS URL builder chooses `wss://` if page is HTTPS or host URL is HTTPS.
228
+ ### 3.8 Transcript auto-scroll contract
212
229
 
213
- Check:
214
- - `public/app.js` `ServerClient.resolveWsUrl`
215
- - ensure host URL is HTTPS when used from secure origin.
230
+ - If the user was already at the bottom, keep them pinned to bottom when:
231
+ - new transcript messages arrive
232
+ - tool-call terminal blocks grow
233
+ - plan/activity/queue panels change height
234
+ - transcript container height changes
235
+ - If the user was not at the bottom, preserve position and do not yank them
236
+ back down.
216
237
 
217
- ### 4.2 `TypeError: Failed to fetch` during heartbeat
238
+ Relevant code:
239
+ - `/Users/leask/Documents/Tabminal/public/app.js`
218
240
 
219
- Usually means:
220
- - host down, DNS issue, TLS failure, CORS block, or network unreachable.
221
- Expected behavior:
222
- - warning-level reconnect messaging, not noisy crash behavior.
241
+ ### 3.9 Slash command menu contract
223
242
 
224
- Check:
225
- - browser network tab
226
- - host availability
227
- - Access auth state for that host
243
+ - Slash-command menu opens upward, as a floating overlay above the composer.
244
+ - It must not push the composer or nearby controls.
245
+ - Keyboard navigation must keep the active item scrolled into view with some
246
+ padding from the edges.
247
+ - Current shortcut to open agent menu is `Ctrl+Shift+A`.
228
248
 
229
- ### 4.3 Cloudflare Access 302/login loops
249
+ Relevant code:
250
+ - `/Users/leask/Documents/Tabminal/public/app.js`
251
+ - `/Users/leask/Documents/Tabminal/public/styles.css`
252
+ - `/Users/leask/Documents/Tabminal/public/index.html`
230
253
 
231
- Important:
232
- - CORS headers alone do not fix Access redirect login requirements.
233
- - Main issue is Access auth challenge during API request.
234
- - Current design handles this by detecting redirect and opening host root login page.
254
+ ### 3.10 Usage HUD contract
235
255
 
236
- ### 4.4 Host list not restoring after refresh
256
+ - Expanded usage HUD is now a CSS-driven fixed layout.
257
+ - Do not reintroduce JS-measured width growth or time-based width drift.
258
+ - Context line uses right-side usage text.
259
+ - Limit rows use `% left` plus reset text.
260
+ - The HUD should expand predictably and not resize every second as reset text
261
+ updates.
237
262
 
238
- Check in order:
239
- 1. main host authenticated?
240
- 2. `/api/cluster` returns expected `servers` array?
241
- 3. entries include valid `id` and `baseUrl`?
242
- 4. entry skipped as self-host by dedupe/hostname rule?
263
+ Relevant code:
264
+ - `/Users/leask/Documents/Tabminal/public/styles.css`
265
+ - `/Users/leask/Documents/Tabminal/public/app.js`
243
266
 
244
- ### 4.5 Same domain with different path does not behave as separate hosts
267
+ ## 4) ACP Status and Remaining Gaps
245
268
 
246
- Current architecture dedupes by `hostname[:port]` and uses absolute `/api/*`/`/ws/*`.
247
- Do not assume path-prefix multiplexing works without deeper routing redesign.
269
+ `/Users/leask/Documents/Tabminal/ACP_PLANING.md` is partly stale.
248
270
 
249
- ## 5) File Map for Fast Onboarding
271
+ Implemented from that plan:
250
272
 
251
- Backend:
252
- - `src/server.mjs`: API routes, WS upgrade, CORS, runtime boot id, startup/shutdown.
253
- - `src/config.mjs`: merged config parser (defaults/home/local/CLI/env), validation.
254
- - `src/auth.mjs`: hash auth, lockout logic, API and WS auth checks.
255
- - `src/persistence.mjs`: sessions, memory, cluster registry disk persistence.
256
- - `src/terminal-manager.mjs`: PTY session lifecycle + persistence glue.
257
- - `src/terminal-session.mjs`: terminal stream parsing, history, metadata, AI context.
273
+ - ACP supervisor and backend APIs
274
+ - ACP websocket fan-out
275
+ - agent tab restore and `loadSession` restore where supported
276
+ - slash commands
277
+ - prompt attachments
278
+ - structured tool cards
279
+ - diff and code/resource rendering
280
+ - managed terminal transcript UI
281
+ - permission handling
282
+ - usage HUD
283
+ - browser smoke and ACP test agent support
258
284
 
259
- Frontend:
260
- - `public/app.js`: host/session state, sync loop, UI orchestration.
261
- - `public/modules/url-auth.js`: URL normalization, dedupe key, auth helpers.
262
- - `public/modules/session-meta.js`: host display and path shortening.
263
- - `public/styles.css`: sidebar/tab/host control styling and responsive rules.
264
- - `public/index.html`: shell DOM, runtime versioned loader, SW register.
265
- - `public/sw.js`: runtime-versioned caching strategy.
285
+ Still not clearly done end-to-end:
266
286
 
267
- Native apps:
268
- - `apps/README.md`: native app architecture and rollout plan.
269
- - `apps/Apple`: Apple-platform app, Swift package, CLI launch scripts.
270
- - `apps/ghostty-vendor`: Ghostty xcframework build and verification helpers.
287
+ - registry-driven install UX
288
+ - explicit TCP ACP runtime support in the UI
289
+ - dedicated conversation history browser independent of terminal sessions
271
290
 
272
- ## 6) Logs and Debug Guidance
291
+ Implication:
273
292
 
274
- Expected, low-noise warnings:
275
- - host unreachable / reconnect transitions.
276
- - invalid cluster entries skipped.
293
+ - Do not delete `ACP_PLANING.md` just because most of the MVP shipped.
294
+ - If it is removed later, first copy the still-open deferred items into a new
295
+ canonical roadmap document.
277
296
 
278
- Avoid:
279
- - spamming full stack traces for normal offline scenarios.
280
- - debug-only console noise left enabled by default.
297
+ ## 5) File Map for Fast Onboarding
281
298
 
282
- Note:
283
- - old `cluster-debug` helper has been intentionally removed; do not reintroduce
284
- unless there is a concrete observability requirement.
299
+ Backend:
300
+ - `/Users/leask/Documents/Tabminal/src/server.mjs`
301
+ - API routes, WS upgrade, auth, runtime boot id
302
+ - `/Users/leask/Documents/Tabminal/src/config.mjs`
303
+ - merged config parser and validation
304
+ - `/Users/leask/Documents/Tabminal/src/auth.mjs`
305
+ - password hashing and auth checks
306
+ - `/Users/leask/Documents/Tabminal/src/persistence.mjs`
307
+ - sessions, cluster registry, ACP tab/config persistence
308
+ - `/Users/leask/Documents/Tabminal/src/terminal-manager.mjs`
309
+ - PTY lifecycle and persistence
310
+ - `/Users/leask/Documents/Tabminal/src/terminal-session.mjs`
311
+ - terminal stream parsing, shell AI path, execution model
312
+ - `/Users/leask/Documents/Tabminal/src/acp-manager.mjs`
313
+ - ACP definitions, runtime supervision, ACP tab lifecycle
314
+ - `/Users/leask/Documents/Tabminal/src/acp-test-agent.mjs`
315
+ - local ACP smoke agent with slash-command fixtures
285
316
 
286
- ## 7) Security and Risk Notes
317
+ Frontend:
318
+ - `/Users/leask/Documents/Tabminal/public/app.js`
319
+ - nearly all UI orchestration lives here
320
+ - `/Users/leask/Documents/Tabminal/public/modules/url-auth.js`
321
+ - URL normalization and auth helpers
322
+ - `/Users/leask/Documents/Tabminal/public/modules/session-meta.js`
323
+ - host display and compact path formatting
324
+ - `/Users/leask/Documents/Tabminal/public/styles.css`
325
+ - all current UI contracts and responsive rules
326
+ - `/Users/leask/Documents/Tabminal/public/index.html`
327
+ - shell DOM, layout bootstrapping, shortcuts modal
287
328
 
288
- - Product is high-privilege by design (terminal + file write).
289
- - AI features may send terminal context to model providers.
290
- - Current policy is explicit risk acknowledgment (`--accept-terms` / config flag).
291
- - Choose trusted model providers and least-privilege credentials.
329
+ Tests and smoke:
330
+ - `/Users/leask/Documents/Tabminal/test/acp-manager.mjs`
331
+ - richest ACP coverage
332
+ - `/Users/leask/Documents/Tabminal/scripts/acp-browser-smoke.mjs`
333
+ - browser ACP smoke against a real running app and real Chrome remote debug
292
334
 
293
- ## 8) Deployment and Ops Notes
335
+ ## 6) Debug and Testing Guidance
294
336
 
295
- - Local helper script: `reploy.sh` (intentionally ignored by git and npm package).
296
- - It restarts one macOS launchctl node + several Linux pm2 nodes via SSH.
297
- - Script contains aggressive cleanup on Linux nodes (reset/clean fallback);
298
- use carefully in shared environments.
337
+ ### 6.1 Basic quality gates
299
338
 
300
- ## 9) Quality Gates Before Release
339
+ Run these before release or after meaningful ACP/UI changes:
301
340
 
302
- Recommended checks:
303
341
  1. `npm run lint`
304
342
  2. `npm test`
305
343
  3. `npm run build`
306
- 4. quick manual smoke:
307
- - main host login
308
- - add host (with and without password, inheritance path)
309
- - reconnect flow (normal + Access login path)
310
- - delete host
311
- - restart backend and confirm runtime cache refresh (`rt` flow)
312
344
 
313
- ## 10) Change Safety Rules for Future Refactors
345
+ ### 6.2 ACP test agent
346
+
347
+ Enable it with:
348
+
349
+ ```bash
350
+ TABMINAL_ENABLE_TEST_AGENT=1 npm start -- --accept-terms
351
+ ```
352
+
353
+ Useful slash commands in ACP Test Agent:
354
+
355
+ - `/demo`: richest happy-path demo
356
+ - `/plan`: plan and usage only
357
+ - `/diff`: terminal, diff, code/resource payloads
358
+ - `/permission`: permission flow
359
+ - `/cancel`: long-running cancel flow
360
+ - `/stale`: stale tool settlement path
361
+ - `/order`: message ordering around tools
362
+ - `/fail`: prompt error path
363
+
364
+ Use these instead of inventing ad-hoc prompts when validating ACP UI.
365
+
366
+ ### 6.3 Browser smoke
367
+
368
+ Preferred browser smoke:
369
+
370
+ - `/Users/leask/Documents/Tabminal/scripts/acp-browser-smoke.mjs`
371
+
372
+ It supports:
373
+
374
+ - Chrome remote debugging target
375
+ - ACP Test Agent slash-command flows
376
+ - attachment coverage
377
+ - tool/diff/code/terminal assertions
378
+ - restore-tail validation
379
+
380
+ Typical setup:
381
+
382
+ 1. Start a local Tabminal instance with `TABMINAL_ENABLE_TEST_AGENT=1`
383
+ 2. Run Chrome with remote debugging
384
+ 3. Point smoke at that Chrome target and Tabminal URL
385
+
386
+ ### 6.4 Availability/debug tips
387
+
388
+ If an ACP agent appears inconsistently available:
389
+
390
+ - Compare the backend runtime `PATH` with your interactive shell `PATH`.
391
+ - Do not assume your login shell and the running `npm start` environment match.
392
+ - Copilot and other CLIs may live in `~/.local/bin`; ACP discovery now augments
393
+ common user-local bin paths.
394
+ - Restore failures should not temporarily mark built-in definitions unavailable.
395
+
396
+ Relevant code:
397
+ - `/Users/leask/Documents/Tabminal/src/acp-manager.mjs`
398
+
399
+ ### 6.5 Focus and session-debug tips
400
+
401
+ If `Jump in` appears to bounce back to the original agent workspace:
402
+
403
+ - inspect agent-sync code first
404
+ - the previous bug was backend updates restoring preferred workspace on the
405
+ wrong session and stealing focus
406
+
407
+ If terminal preview proportions become huge:
408
+
409
+ - check whether a hidden terminal is still reporting resized dimensions
410
+
411
+ If you get noisy shell-ready notifications:
412
+
413
+ - check for internal execution events being surfaced to the frontend
414
+
415
+ ## 7) Known Pitfalls
416
+
417
+ ### 7.1 `SecurityError: insecure WebSocket from HTTPS page`
418
+
419
+ Cause:
420
+ - trying `ws://` from an HTTPS page
421
+
422
+ Mitigation:
423
+ - websocket URL must switch to `wss://` when page or host URL is HTTPS
424
+
425
+ ### 7.2 `TypeError: Failed to fetch` during heartbeat
426
+
427
+ Typical causes:
428
+ - host down
429
+ - DNS/TLS failure
430
+ - CORS block
431
+ - network unreachable
432
+ - Cloudflare Access auth needed
433
+
434
+ Expected behavior:
435
+ - reconnect warning state, not noisy crash behavior
436
+
437
+ ### 7.3 Cloudflare Access loops
438
+
439
+ - CORS headers alone do not solve auth redirects.
440
+ - The problem is usually Access challenge during API fetch.
441
+ - Current model is to detect redirect and open host root login page.
442
+
443
+ ### 7.4 Same domain with different path as multiple hosts
444
+
445
+ - Not supported by current assumptions.
446
+ - Do not patch around this casually; it needs a deeper routing redesign.
447
+
448
+ ## 8) Security and Risk Notes
449
+
450
+ - Product is high-privilege by design.
451
+ - AI features may send terminal or agent context to external providers.
452
+ - `--accept-terms` is the explicit risk-ack mechanism.
453
+ - Prefer least-privilege credentials and trusted providers.
454
+
455
+ ## 9) Deployment and Ops Notes
456
+
457
+ - Local helper script:
458
+ - `/Users/leask/Documents/Tabminal/reploy.sh`
459
+ - It restarts one macOS launchctl node plus several Linux `pm2` nodes via SSH.
460
+ - It includes aggressive cleanup behavior on Linux nodes; use carefully.
461
+
462
+ ## 10) Change Safety Rules
314
463
 
315
- - Do not move host list back to localStorage.
464
+ - Do not move host registry persistence back into browser-owned local state.
316
465
  - Do not make sub-host auth failures trigger global logout.
317
466
  - Do not remove `credentials: 'include'` from host fetch wrapper.
318
- - Do not remove reconnect backoff (`5s`) or online heartbeat cadence (`1s`).
467
+ - Do not remove the `1s` heartbeat or `5s` reconnect throttle without evidence.
319
468
  - Do not reintroduce backend auto-create-session fallback.
320
- - Do not add path-based host assumptions without redesigning URL/WS routing model.
469
+ - Do not bring back JS-driven usage HUD width measurement.
470
+ - Do not let agent sync steal focus from a user-selected terminal session.
471
+ - Do not let hidden terminal tabs report bogus tiny sizes to the backend.
package/README.md CHANGED
@@ -267,8 +267,8 @@ reliable.
267
267
 
268
268
  ## Architecture Snapshot
269
269
 
270
- - Backend: Node.js, Koa, `node-pty`, WebSocket, ACP SDK
271
- - Frontend: vanilla JS, `xterm.js`, Monaco Editor
270
+ - Backend: `Node.js`, [`utilitas`](https://github.com/leask/utilitas), `Koa`, `node-pty`, `WebSocket`, `ACP SDK`
271
+ - Frontend: [`Vanilla JS 😝`](http://vanilla-js.com/), `xterm.js`, `Monaco Editor`
272
272
  - Persistence: host-local files under `~/.tabminal`
273
273
  - Native clients and packaging work live under:
274
274
  - `apps/Apple`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tabminal",
3
- "version": "2.0.15",
3
+ "version": "2.0.16",
4
4
  "description": "A modern, persistent web terminal with multi-tab support and real-time system monitoring.",
5
5
  "type": "module",
6
6
  "bin": {