@tonbo/yield 0.1.0 → 0.1.1

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/README.md +32 -6
  2. package/dist/bin/yield.js +1678 -205
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,7 +2,15 @@
2
2
 
3
3
  `yield` captures the sessions of your coding agents (Claude Code and Codex) on every machine you use and lists them from any of them. It signs in, runs a capture service on each machine, snapshots the git work trees the agents work in, lists sessions and recalls the turns that changed a file; handoff comes later.
4
4
 
5
- Install the public package with Node.js 22 or newer:
5
+ Install it on macOS (arm64, x64) or Linux with glibc (x64, arm64) with one line, without sudo and without Node.js:
6
+
7
+ ```console
8
+ curl -fsSL https://tonbo.dev/install.sh | sh
9
+ ```
10
+
11
+ The installer, [`install.sh`](install.sh), uses the system `node` when it is 22 or newer and has npm beside it; otherwise it downloads the latest official Node.js 22 build from nodejs.org into `~/.tonbo/runtime/node-<version>`, checked against the release's `SHASUMS256.txt`. It installs `@tonbo/yield` into the private prefix `~/.tonbo/yield`, never a global npm, and writes the launcher `~/.local/bin/yield`, which runs it with that Node.js; when `~/.local/bin` is not on `PATH` it prints the line to add for your shell. Running it again upgrades in place, and when the capture service is installed it reinstalls the service on the new version (which restarts it) and removes Node.js runtimes it no longer uses. `YIELD_VERSION` pins a version or dist-tag: `curl -fsSL https://tonbo.dev/install.sh | YIELD_VERSION=0.2.0 sh`. musl distributions (Alpine), 32-bit systems and Windows are refused with a message; on Windows, install the npm package instead. User Center serves the file at `/install.sh` as `text/plain` from an embedded copy (`apps/user-center/src/app/install.sh`); after changing `install.sh`, run `pnpm --dir apps/user-center generate:install-script`, or the route's test fails.
12
+
13
+ Or install the public package with Node.js 22 or newer:
6
14
 
7
15
  ```console
8
16
  npm install --global @tonbo/yield
@@ -13,12 +21,26 @@ Merging a change to the `version` in `package.json` to `main` releases it: [`ton
13
21
  ## Sign in
14
22
 
15
23
  ```console
16
- yield login [--account <name>]
24
+ yield login [--account <name>] [--name <name>]
17
25
  yield whoami [--json]
18
26
  yield logout
19
27
  ```
20
28
 
21
- `yield` and the [`tonbo`](../tonbo) CLI share one login through the internal package [`@tonbo/cli-core`](../../packages/tonbo-cli-core): the same browser handoff, the same personal key named `CLI on <hostname>` and the same credentials file, `${XDG_CONFIG_HOME:-$HOME/.config}/tonbo/credentials.json`. Logging in with either CLI signs both in, and a login replaces the host's earlier key, so the two never hold different keys. `whoami` prints the account, your role and this machine's device id, which is the key id of that login; revoking the key revokes the device.
29
+ `yield` and the [`tonbo`](../tonbo) CLI share one login through the internal package [`@tonbo/cli-core`](../../packages/tonbo-cli-core): the same browser handoff, the same personal key named `CLI on <hostname>` and the same credentials file, `${XDG_CONFIG_HOME:-$HOME/.config}/tonbo/credentials.json`. Logging in with either CLI signs both in, and a login replaces the host's earlier key, so the two never hold different keys. `whoami` prints the account, your role and this machine's device id.
30
+
31
+ ## The device id
32
+
33
+ The device id names this computer for its whole life ([ADR-0015](../../apps/user-center/docs/decisions/adr-0015-byoc-machines.md) Q1). The first command that needs it makes a random UUID and keeps it in `${XDG_STATE_HOME:-$HOME/.local/state}/tonbo-yield/device.json` beside a SHA-256 of the operating system's machine id (macOS `IOPlatformUUID`, Linux `/etc/machine-id`). A login, a re-login or a revoked key leaves it unchanged. When the saved hash differs from the computer's, the state directory came from another computer (a cloned disk) and a new UUID replaces it; when the machine id cannot be read, the saved UUID stays. A lost state directory makes a new device, as a new computer would. Captured records (`device`), the Streams producer (`yield/<device id>`) and the snapshot refs (`refs/tonbo/u/<sub>/<device id>`) name it.
34
+
35
+ `yield login` and each start of the daemon register this computer as a device of your personal account (`PUT /v1/machines/self`, a Machine of kind `byoc`, ADR-0015) with the saved login: its device id, hostname, operating system, architecture, Yield's version and the harnesses it has. Only the key a CLI login issued registers, and only in your personal account; `--name` chooses the device's name the first time (`<os>-<n>` otherwise). The running daemon registers again every 300 seconds, give or take 30 (machine-v2 `kinds.byoc.heartbeat`, an interim until the state work of Yield M4), which keeps `last_seen` fresh; an unchanged report writes only `last_seen`, and a throttled one (429 `device_report_throttled`) counts as done. Registration never holds back capture: a refusal or a failure is printed or logged (once, until it changes) and tried again at the next login or heartbeat. A refusal no retry changes, such as a login to an organization (`self_requires_personal_account`), a key that a CLI login did not issue, the device limit or a taken name, stops the heartbeat until the saved login changes.
36
+
37
+ ```console
38
+ yield devices [--json]
39
+ ```
40
+
41
+ `devices` lists your computers, only the `byoc` Machines of your personal account (`GET /v1/machines`, every page, with the saved login; never `TONBO_API_KEY`), and under an organization's login says to log in to your personal account instead: the name, online when the last report is within machine-v2's `online_window_seconds` (900), when it was last seen, the OS and architecture, the agents it captures, Yield's version, and which one is this computer. A region whose devices could not be read is named below the table.
42
+
43
+ Yield 0.1.0 named the device by the key id of its login. Its state upgrades in place: each file keeps its offset, so nothing captured is sent again, and moves to the producer `yield/<device id>` from epoch 0, seq 0, saved before it is used. A batch saved under the old producer is first finished under it, so a resend after a crash is still answered as a duplicate, and the inbox moves once no such batch is left. Snapshots start a new chain on the new device's ref; the old refs stay.
22
44
 
23
45
  ## Capture
24
46
 
@@ -36,9 +58,10 @@ The capture follows [`contracts/sessions/capture-v1.json`](../../contracts/sessi
36
58
  - It discovers the account's store once an hour through `GET /v1/sessions/store` and again whenever the store refuses a request. An account without a store (409 `sessions_store_unavailable`: no active git workspace Agent) is reported by `daemon status` and `sessions` as needing an account owner to enable git, and the daemon asks again every 10 minutes.
37
59
  - Streams does not accept the personal key itself: the client exchanges it at `POST <console origin>/api/iam/token` for a ten-minute Streams access token (`@tonbo/cli-core` `AccessTokens`), keeps it in memory, replaces it a minute before it expires, and exchanges again once after a Streams 401. A refused exchange asks for `yield login`; a 429 or 5xx is retried with backoff while the offsets stay.
38
60
  - It watches `~/.claude/projects` and `~/.codex/sessions` and rescans them every two seconds; a missing root is fine. Each file is read from its saved byte offset, and only complete lines count.
39
- - Each line, except the contract's excluded types, is redacted with the contract's patterns and becomes one record of the stream `session.<session id>`. Consecutive lines go in one append request (at most the contract's `max_batch_lines` and `max_batch_bytes`), which ends early at a line that causes an inbox record. Each request carries `Producer-Id: yield/<device id>`, `Producer-Epoch` and `Producer-Seq`, the request's ordinal within the epoch; the batch's seq and byte range are saved before it is sent, so a resend after a crash is the identical batch and is answered as a duplicate. A line that is not JSON is uploaded as it is. If the redaction fails, nothing more of that session is uploaded and the session is marked blocked.
61
+ - Each line, except the contract's excluded types, becomes one record of the stream `session.<session id>`. Consecutive lines go in one append request (at most the contract's `max_batch_lines` and `max_batch_bytes`), which ends early at a line that causes an inbox record. Each request carries `Producer-Id: yield/<device id>`, `Producer-Epoch` and `Producer-Seq`, the request's ordinal within the epoch; the batch's seq and byte range are saved before it is sent, so a resend after a crash is the identical batch and is answered as a duplicate. The record carries the line as written, without redaction; a line that is not JSON is uploaded as it is too.
40
62
  - When a session is first seen it appends `session_start` to `proc.inbox`, and at each turn end `turn_end` with the cwd, git root, branch, the paths written since the previous turn end (at most 50, relative to the git root inside it) and `stream_offset`, the session stream's `Stream-Next-Offset` after the turn's last record (the append's answer, or the stream's tail when a resent batch is answered as a duplicate).
41
- - The state, `${XDG_STATE_HOME:-$HOME/.local/state}/tonbo-yield/state.json`, keeps each file's offset with its producer sequence and epoch, and is replaced atomically. The source files are the offline queue: while the store is unreachable the offset stays and the upload is retried with backoff, honoring `Retry-After`. A new epoch starts from seq 0, saved before it is used, when Streams has forgotten the producer (idle for 7 days) or is ahead of a lost local state.
63
+ - On every pass it decides each live session's state, `running`, `waiting`, `idle` or `ended` (capture-v1 `sources.<source>.state`; [Yield session state](../../docs/design/yield-session-state.md)), and appends `session_state` to `proc.inbox` when the state or the turn changes, and while a turn runs, when it has written new paths, at most every 10 seconds. Claude Code's live-process registry (`~/.claude/sessions/<pid>.json`) gives a Claude session's liveness and status; a running `codex` process whose working directory is the session's cwd keeps a Codex session live; otherwise a session's turn decides `running` or `idle`, and a session whose liveness cannot be told ends after 30 quiet minutes. A session first seen already ended is not reported.
64
+ - The state, `${XDG_STATE_HOME:-$HOME/.local/state}/tonbo-yield/state.json`, keeps each file's offset with its producer, sequence and epoch, and is replaced atomically. The source files are the offline queue: while the store is unreachable the offset stays and the upload is retried with backoff, honoring `Retry-After`. A new epoch starts from seq 0, saved before it is used, when Streams has forgotten the producer (idle for 7 days) or is ahead of a lost local state.
42
65
  - The first run also captures the session files changed in the last 14 days (`--since` sets the bound); older files are recorded as skipped until they change again.
43
66
 
44
67
  ### Snapshots
@@ -55,10 +78,13 @@ The daemon uses the saved login only; `TONBO_API_KEY` does not name a device. On
55
78
  ## Sessions
56
79
 
57
80
  ```console
81
+ yield ps [--all] [--limit <sessions>] [--json]
58
82
  yield sessions [--limit <records>] [--json]
59
83
  ```
60
84
 
61
- `sessions` reads `proc.inbox` and prints one row per session among its newest records (200 by default): the last activity, the device (`this machine` for this one), the source, the git root or cwd, the branch and the turn ends seen.
85
+ `ps` reads the catalog, recall's `GET /sessions` without `repo`, which the git-ingester keeps in the workspace's index from `proc.inbox`. It prints your sessions on every device, most recent activity first: the state and since when, the device (`this computer` for this one), the agent, the git root or cwd, the session and the files it recently wrote (the turn in progress's first). Ended sessions are left out unless `--all`; a session no client reported a state for shows `ended` once it is 30 minutes quiet, and `unknown` before.
86
+
87
+ `sessions` reads `proc.inbox` itself and prints one row per session among its newest records (200 by default): the last activity, the device (`this machine` for this one), the source, the git root or cwd, the branch and the turn ends seen. `ps` supersedes it; it stays until the first-run end-to-end check (`e2e/src/yield-first-run-e2e.mjs`) reads `ps`, once the index serves personal workspaces (ADR-0016 PR 4).
62
88
 
63
89
  ## Recall
64
90