@baleen37/ars 1.0.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,27 +60,71 @@ 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.
79
+
80
+ `ars remote add <host>` creates the inventory and its parent directory when
81
+ missing, preserves existing comments, entries, and order, and rejects invalid
82
+ or duplicate targets. A target beginning with `#` is rejected because inventory
83
+ loading would interpret it as a comment. The command does not edit `~/.ssh/config`.
60
84
 
61
85
  ## Commands
62
86
 
63
- There are exactly three command forms:
87
+ The supported command forms are:
64
88
 
65
89
  ```sh
66
- ars # search sessions from every configured host
67
- ars devbox # search one configured host
68
- ars list --json # return all hosts, sessions, and errors as JSON
90
+ ars # search sessions from every configured host
91
+ ars devbox # search one configured host
92
+ ars list --json # return all hosts, sessions, and errors as JSON
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
95
+ ars --help # show all command forms
96
+ ars remote --help # show remote command help
97
+ ```
98
+
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
69
108
  ```
70
109
 
71
- Interactive rows contain a private numeric index followed by display-only
72
- metadata. `fzf` returns only that opaque index; titles, paths, and host names
73
- are never parsed back into identity. Enter resumes the selected session.
74
- Canceling `fzf` exits zero without starting the resume SSH connection. A
75
- healthy result with no sessions prints `No sessions found.` and does not open
76
- `fzf`.
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.
77
128
 
78
129
  ## Session inclusion
79
130
 
@@ -94,6 +145,26 @@ metadata file modification time as `updated_at`, validate canonical UUIDs, and
94
145
  deduplicate by host, provider, and native ID. A missing executable or metadata
95
146
  tree is a healthy absent-provider result, not a host failure.
96
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
+
97
168
  ## JSON schema version 1
98
169
 
99
170
  Public JSON uses dedicated DTOs and always ends with a newline:
@@ -127,9 +198,9 @@ an empty `sessions` array distinguishes a healthy empty host from an
127
198
  unreachable host. Stable error codes are `ssh_timeout`, `ssh_failed`,
128
199
  `unsupported_target`, `protocol_error`, and `resource_limit`.
129
200
 
130
- ## SSH and failure behavior
201
+ ## SSH and partial-failure behavior
131
202
 
132
- Collection and resume deliberately use separate SSH modes:
203
+ Collection and attach deliberately use separate SSH modes:
133
204
 
134
205
  - Collection is non-interactive (`BatchMode=yes`, no agent/X11/port
135
206
  forwarding), uses separate probe and upload invocations that each make one
@@ -137,23 +208,25 @@ Collection and resume deliberately use separate SSH modes:
137
208
  `StrictHostKeyChecking=yes`, uses a 5-second connect timeout, and gives the
138
209
  full probe/upload/protocol flow 60 seconds per host. Unknown hosts fail; ars
139
210
  never accepts or rewrites `known_hosts` entries.
140
- - Resume runs `ssh -tt` with the user's normal SSH configuration,
141
- authentication, and forwarding behavior. It executes only
142
- `cd <saved-cwd> && exec claude --resume <uuid>` or
143
- `cd <saved-cwd> && exec codex resume <uuid>`. Resume preserves the SSH exit
144
- 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.
145
216
 
146
217
  Hosts are collected with at most four workers. One failed host produces a
147
- structured error while healthy peer sessions remain usable. If every selected
148
- host fails, `ars` exits non-zero and never opens `fzf`. A healthy empty host is
149
- success. Provider-level corrupt records can yield a partial provider result
150
- 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.
151
224
 
152
225
  ## Bounds and cleanup
153
226
 
154
227
  Collection is bounded and fail-closed:
155
228
 
156
- - 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
157
230
  - 16 MiB total collector stdout and 64 KiB diagnostic stderr
158
231
  - 10,000 sessions total; provider traversal also caps discovered sessions at
159
232
  10,000
@@ -170,13 +243,16 @@ that exact leftover.
170
243
 
171
244
  ## Privacy
172
245
 
173
- The collector returns validated metadata only: provider, native UUID,
174
- modification time, saved CWD, and native title. Prompts, responses, tool input
175
- or output, credentials, raw transcript lines, provider source paths, and
176
- filenames never cross the ARS/1 boundary. Host diagnostics are bounded and
177
- sanitized before public output. The saved CWD and native title are still
178
- potentially sensitive metadata, so treat JSON output and terminal history
179
- 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.
180
256
 
181
257
  ## Verification
182
258
 
@@ -188,20 +264,40 @@ go test ./...
188
264
  go test -race ./...
189
265
  go vet ./...
190
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
191
271
  ```
192
272
 
193
273
  The ephemeral loopback sshd integration is disposable and opt-in:
194
274
 
195
275
  ```sh
196
- 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
197
277
  ```
198
278
 
199
279
  It generates temporary host/client keys, `authorized_keys`, `known_hosts`, and
200
- configs, and does not modify a system sshd or persistent SSH configuration.
201
- Before release, also use two explicitly configured real hosts to verify one
202
- Claude and one Codex resume, an unreachable peer beside a healthy host, a
203
- healthy empty host, fzf cancellation, and nonce-specific cleanup after an
204
- 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.
205
301
 
206
302
  ## Release
207
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.0.0"
26
+ "version": "1.2.0"
27
27
  }
Binary file
Binary file
Binary file