@baleen37/ars 1.1.0 → 1.2.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 CHANGED
@@ -1,9 +1,14 @@
1
1
  # ars
2
2
 
3
- `ars` lists Claude Code and Codex sessions from configured SSH hosts, combines
4
- them in one searchable picker, and resumes the selected native session. It is a
5
- single local Go binary: remote hosts do not need an `ars` install, daemon,
6
- cache, or background process.
3
+ `ars` is a full-screen Claude Code and Codex session navigator for the current
4
+ computer and explicitly configured SSH peers. Selecting a row creates or
5
+ attaches to a provider process in an ARS-owned tmux server. `Ctrl+Q` detaches
6
+ the terminal client, keeps that provider process alive on its original host,
7
+ and returns to the same refreshed TUI.
8
+
9
+ ARS is one local Go binary. Peers need no `ars` install, daemon, database,
10
+ cache, index, or background helper. Collection uses a private, one-shot,
11
+ version-matched ARS/2 helper over the user's existing OpenSSH configuration.
7
12
 
8
13
  ## Install
9
14
 
@@ -22,11 +27,13 @@ Prerequisites:
22
27
 
23
28
  - Go as declared by `go.mod`, for building from source
24
29
  - OpenSSH `ssh` locally and an OpenSSH-compatible server on each remote host
25
- - `fzf` locally for interactive selection; `ars list --json` does not use it
30
+ - `tmux` on every managed computer, including the current one
26
31
  - a POSIX `/bin/sh` plus `uname`, `mkdir`, `cat`, `chmod`, `rm`, and `rmdir` on
27
32
  each remote host
28
- - `claude` and/or `codex` on the remote `PATH`, with their native session
29
- metadata under the remote user's home directory
33
+ - `claude` and/or `codex` on each node's `PATH`, with native session metadata
34
+ under that user's home directory
35
+
36
+ `fzf` is not used or required.
30
37
 
31
38
  Build the three collector assets and the local executable:
32
39
 
@@ -40,7 +47,7 @@ local `ars` build: `darwin/arm64`, `linux/amd64`, and `linux/arm64`. Generated
40
47
  collector blobs and the root `ars` build artifact are local build outputs and
41
48
  must not be committed.
42
49
 
43
- ## Inventory
50
+ ## Common roster and local identity
44
51
 
45
52
  The default inventory is `${XDG_CONFIG_HOME}/ars/hosts` when
46
53
  `XDG_CONFIG_HOME` is set, otherwise `~/.config/ars/hosts`. Put one OpenSSH
@@ -53,10 +60,22 @@ deploy@example.internal
53
60
  agent-mac
54
61
  ```
55
62
 
56
- Blank lines and comments are ignored. Targets may use names and aliases from
57
- the user's SSH config. Duplicates, whitespace, control characters, a leading
58
- dash, and targets over 255 bytes make the entire inventory invalid. `ars` does
59
- not infer `localhost` or discover hosts.
63
+ Every managed computer uses the same `hosts` roster. On each computer, select
64
+ that computer's exact roster entry once:
65
+
66
+ ```sh
67
+ ars local set devbox
68
+ ```
69
+
70
+ This writes `${XDG_CONFIG_HOME}/ars/local-host`, or
71
+ `~/.config/ars/local-host` when `XDG_CONFIG_HOME` is unset. ARS never infers
72
+ local identity from OS hostnames, DNS, SSH aliases, VPNs, users, or interfaces.
73
+ The current computer is rendered as `local`, but its configured target remains
74
+ the canonical identity used by JSON and routing.
75
+
76
+ Blank lines and comments in `hosts` are ignored. Targets may use names and
77
+ aliases from the user's SSH config. Duplicates, whitespace, control characters,
78
+ a leading dash, and targets over 255 bytes make the entire inventory invalid.
60
79
 
61
80
  `ars remote add <host>` creates the inventory and its parent directory when
62
81
  missing, preserves existing comments, entries, and order, and rejects invalid
@@ -72,16 +91,40 @@ ars # search sessions from every configured host
72
91
  ars devbox # search one configured host
73
92
  ars list --json # return all hosts, sessions, and errors as JSON
74
93
  ars remote add devbox # add an SSH target to the ARS inventory
94
+ ars local set devbox # mark this computer's exact roster entry
75
95
  ars --help # show all command forms
76
96
  ars remote --help # show remote command help
77
97
  ```
78
98
 
79
- Interactive rows contain a private numeric index followed by display-only
80
- metadata. `fzf` returns only that opaque index; titles, paths, and host names
81
- are never parsed back into identity. Enter resumes the selected session.
82
- Canceling `fzf` exits zero without starting the resume SSH connection. A
83
- healthy result with no sessions prints `No sessions found.` and does not open
84
- `fzf`.
99
+ `ars` and `ars <host>` require a TTY. Use `ars list --json` for a headless,
100
+ one-shot result.
101
+
102
+ ## TUI
103
+
104
+ The screen has one line per session:
105
+
106
+ ```text
107
+ state | title | provider | local/host | project | runtime | activity age
108
+ ```
109
+
110
+ `Active` contains ARS-owned runtimes: `attached(n)` has one or more terminal
111
+ clients and `running` has none. `Recent` contains saved provider histories with
112
+ no ARS runtime. The footer shows the selected row's full CWD, native ID, and
113
+ exact update time. Search is a Unicode-aware, case-insensitive substring match;
114
+ there is no fuzzy ranker.
115
+
116
+ Keys:
117
+
118
+ - `Up`, `Down`, `j`, `k`: move
119
+ - `/`: search
120
+ - `Enter`: start or attach
121
+ - `r`: refresh
122
+ - `q`, `Ctrl+C`: quit ARS
123
+ - `Ctrl+Q`: detach only while inside an attached ARS tmux client
124
+
125
+ The screen collects at startup, on `r`, and after attach returns. It does not
126
+ poll, watch, or cache in the background. Canonical host/provider/native-ID data,
127
+ never rendered row text, determines the attach command.
85
128
 
86
129
  ## Session inclusion
87
130
 
@@ -102,6 +145,26 @@ metadata file modification time as `updated_at`, validate canonical UUIDs, and
102
145
  deduplicate by host, provider, and native ID. A missing executable or metadata
103
146
  tree is a healthy absent-provider result, not a host failure.
104
147
 
148
+ ## Persistent provider runtime
149
+
150
+ ARS uses a dedicated versioned, per-user tmux server (`ars-v1`) with
151
+ `-f /dev/null`. It does not use, configure, rename, attach, or bind keys in the
152
+ user's default tmux server. It creates exactly one hashed runtime for the
153
+ selected `(provider, native ID)` and rechecks after a concurrent create instead
154
+ of starting a duplicate provider process.
155
+
156
+ On first selection, ARS starts the adapter's fixed native resume command in the
157
+ saved CWD. Later selections attach that same runtime. `Ctrl+Q` is a prefix-free
158
+ binding in the ARS server and runs `detach-client`; it is not delivered to
159
+ Claude or Codex. When another computer attaches with `ssh -tt`, tmux detaches
160
+ the previous client back to its TUI and hands the same provider process to the
161
+ new client.
162
+
163
+ If the provider exits, its tmux session ends and the native history remains in
164
+ `Recent`. A host reboot or loss of the ARS tmux server ends the live process but
165
+ does not remove native history. ARS does not discover or adopt providers that
166
+ were started outside its own tmux server.
167
+
105
168
  ## JSON schema version 1
106
169
 
107
170
  Public JSON uses dedicated DTOs and always ends with a newline:
@@ -135,9 +198,9 @@ an empty `sessions` array distinguishes a healthy empty host from an
135
198
  unreachable host. Stable error codes are `ssh_timeout`, `ssh_failed`,
136
199
  `unsupported_target`, `protocol_error`, and `resource_limit`.
137
200
 
138
- ## SSH and failure behavior
201
+ ## SSH and partial-failure behavior
139
202
 
140
- Collection and resume deliberately use separate SSH modes:
203
+ Collection and attach deliberately use separate SSH modes:
141
204
 
142
205
  - Collection is non-interactive (`BatchMode=yes`, no agent/X11/port
143
206
  forwarding), uses separate probe and upload invocations that each make one
@@ -145,23 +208,25 @@ Collection and resume deliberately use separate SSH modes:
145
208
  `StrictHostKeyChecking=yes`, uses a 5-second connect timeout, and gives the
146
209
  full probe/upload/protocol flow 60 seconds per host. Unknown hosts fail; ars
147
210
  never accepts or rewrites `known_hosts` entries.
148
- - Resume runs `ssh -tt` with the user's normal SSH configuration,
149
- authentication, and forwarding behavior. It executes only
150
- `cd <saved-cwd> && exec claude --resume <uuid>` or
151
- `cd <saved-cwd> && exec codex resume <uuid>`. Resume preserves the SSH exit
152
- code when available.
211
+ - Attach runs `ssh -tt` with the user's normal OpenSSH configuration,
212
+ authentication, and host-key verification. The bounded fixed remote script
213
+ checks or creates the exact ARS tmux runtime, reapplies `Ctrl+Q`, and attaches
214
+ with previous-client detachment. ARS does not weaken host-key checking or
215
+ write SSH configuration.
153
216
 
154
217
  Hosts are collected with at most four workers. One failed host produces a
155
- structured error while healthy peer sessions remain usable. If every selected
156
- host fails, `ars` exits non-zero and never opens `fzf`. A healthy empty host is
157
- success. Provider-level corrupt records can yield a partial provider result
158
- without discarding its valid sessions.
218
+ bounded visible error while healthy local and peer sessions remain searchable
219
+ and attachable. A provider or runtime warning is shown beside otherwise healthy
220
+ sessions. If every selected host fails, the TUI still permits refresh and quit;
221
+ JSON mode writes the structured result and exits non-zero. A healthy empty host
222
+ is success. Provider-level corrupt records can yield a warning without
223
+ discarding valid sessions.
159
224
 
160
225
  ## Bounds and cleanup
161
226
 
162
227
  Collection is bounded and fail-closed:
163
228
 
164
- - 64 KiB startup noise and 64 KiB per ARS/1 protocol line
229
+ - 64 KiB startup noise and 64 KiB per ARS/2 protocol line
165
230
  - 16 MiB total collector stdout and 64 KiB diagnostic stderr
166
231
  - 10,000 sessions total; provider traversal also caps discovered sessions at
167
232
  10,000
@@ -178,13 +243,16 @@ that exact leftover.
178
243
 
179
244
  ## Privacy
180
245
 
181
- The collector returns validated metadata only: provider, native UUID,
182
- modification time, saved CWD, and native title. Prompts, responses, tool input
183
- or output, credentials, raw transcript lines, provider source paths, and
184
- filenames never cross the ARS/1 boundary. Host diagnostics are bounded and
185
- sanitized before public output. The saved CWD and native title are still
186
- potentially sensitive metadata, so treat JSON output and terminal history
187
- accordingly.
246
+ The private ARS/2 collector returns validated metadata only: provider, native
247
+ UUID, modification time, saved CWD, native title, runtime state, attached-client
248
+ count, and runtime start time. Prompts, responses, tool input or output,
249
+ credentials, raw transcript lines, provider source paths, filenames, pane
250
+ content, and attached terminal output never cross the collection boundary.
251
+ Host diagnostics are bounded and sanitized before display.
252
+
253
+ Public JSON schema v1 deliberately omits all runtime fields and remains the
254
+ provider-history view. Saved CWD and native title are still potentially
255
+ sensitive metadata, so protect JSON output and terminal history accordingly.
188
256
 
189
257
  ## Verification
190
258
 
@@ -196,20 +264,40 @@ go test ./...
196
264
  go test -race ./...
197
265
  go vet ./...
198
266
  go run ./cmd/ars-build
267
+ go test ./internal/runtime -run TestDisposableTmux -count=1 -v
268
+ go test ./internal/tui -run TestPTYAttachDetachRestoresTUI -count=1 -v
269
+ npm test
270
+ git diff --check
199
271
  ```
200
272
 
201
273
  The ephemeral loopback sshd integration is disposable and opt-in:
202
274
 
203
275
  ```sh
204
- ARS_RUN_SSHD_INTEGRATION=1 go test ./internal/ssh -run TestEphemeralSSHDCollectsAndResumes -v
276
+ ARS_RUN_SSHD_INTEGRATION=1 go test ./internal/ssh -run TestEphemeralSSHDCollectsAndAttaches -count=1 -v
205
277
  ```
206
278
 
207
279
  It generates temporary host/client keys, `authorized_keys`, `known_hosts`, and
208
- configs, and does not modify a system sshd or persistent SSH configuration.
209
- Before release, also use two explicitly configured real hosts to verify one
210
- Claude and one Codex resume, an unreachable peer beside a healthy host, a
211
- healthy empty host, fzf cancellation, and nonce-specific cleanup after an
212
- interrupt.
280
+ configs, logs, provider fixture, and isolated tmux socket. It verifies strict
281
+ host-key checking, remote create/detach with the same provider PID, and
282
+ second-client handoff without modifying system sshd, persistent SSH state, or
283
+ the default tmux server.
284
+
285
+ Automated evidence is separate from real-host acceptance. Before release, use
286
+ two genuinely ready hosts with the same ARS build and roster and verify:
287
+
288
+ 1. Each host renders its own configured target as `local`, while canonical JSON
289
+ session sets match.
290
+ 2. Host A starts Claude, `Ctrl+Q` returns to its TUI, and the provider PID stays
291
+ alive; host B then attaches the same PID and A returns to its TUI.
292
+ 3. Repeat the same flow for Codex.
293
+ 4. Network loss returns to the TUI without killing the provider, and an
294
+ unreachable peer remains visible beside healthy sessions.
295
+ 5. The user's default tmux server, configuration, keys, and sessions are
296
+ unchanged.
297
+
298
+ If inventory, SSH, DNS, tmux, or provider readiness is missing, record this
299
+ manual gate as incomplete. Disposable or simulated results are never a real
300
+ two-host pass.
213
301
 
214
302
  ## Release
215
303
 
package/package.json CHANGED
@@ -23,5 +23,5 @@
23
23
  "type": "git",
24
24
  "url": "git+https://github.com/baleen37/agent-remote-sessions.git"
25
25
  },
26
- "version": "1.1.0"
26
+ "version": "1.2.0"
27
27
  }
Binary file
Binary file
Binary file