@dmsdc-ai/aigentry-telepty 0.4.3 → 0.4.4
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 +329 -0
- package/README.md +17 -0
- package/cli.js +225 -7
- package/daemon.js +199 -1
- package/package.json +4 -4
- package/src/bridge/j3-shim.js +264 -0
- package/src/bridge/supervisor-ipc.js +330 -0
- package/src/bridge/supervisor-launcher.js +193 -0
- package/src/config-file.js +86 -0
- package/src/lifecycle.js +237 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,335 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@dmsdc-ai/aigentry-telepty` are documented here.
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.4.4] - 2026-05-25
|
|
8
|
+
|
|
9
|
+
### Added — TELEPTY_SUBMIT_FORCE_DEFAULT env var (task #453)
|
|
10
|
+
|
|
11
|
+
- **Environment default for forced submit** —
|
|
12
|
+
`TELEPTY_SUBMIT_FORCE_DEFAULT=1` makes `telepty inject --submit` behave as
|
|
13
|
+
if `--submit-force` was passed, without changing behavior for users who leave
|
|
14
|
+
the env var unset. Accepted truthy values are `1`, `true`, `yes`, and `on`
|
|
15
|
+
after whitespace trimming and case normalization.
|
|
16
|
+
- **Per-call opt-out** — `telepty inject --submit --no-submit-force ...`
|
|
17
|
+
restores the normal gated submit behavior even when the environment default
|
|
18
|
+
is enabled. Explicit `--submit-force` remains valid and wins when supplied.
|
|
19
|
+
- **Automation caveat** — this is intended for orchestrators that already know
|
|
20
|
+
their targets are real, initialized REPLs. It bypasses the safety gate that
|
|
21
|
+
prevents submit during target boot, avoiding the transient 504
|
|
22
|
+
`bootstrap_not_ready` path where text lands in the input box but Enter is not
|
|
23
|
+
sent.
|
|
24
|
+
- **Observability** — env-driven calls emit
|
|
25
|
+
`[telepty inject] submit-force=env-default (TELEPTY_SUBMIT_FORCE_DEFAULT=1)`
|
|
26
|
+
to stderr before posting `/submit`.
|
|
27
|
+
|
|
28
|
+
### Notes — TELEPTY_SUBMIT_FORCE_DEFAULT env var
|
|
29
|
+
|
|
30
|
+
- **Test suite** — `npm test --silent` passes 403 / 403, including the new
|
|
31
|
+
`test/inject-submit-force-env.test.js` coverage for env-off, env-on,
|
|
32
|
+
`--no-submit-force`, explicit `--submit-force`, and value normalization.
|
|
33
|
+
- **Snyk SAST** — the requested `snyk_code_scan` MCP tool was not available in
|
|
34
|
+
this session, so the installed Snyk CLI was used. After replacing the new
|
|
35
|
+
localhost HTTP fixture with a loopback `net` test server and generating the
|
|
36
|
+
test auth token at runtime, `test/inject-submit-force-env.test.js` has 0
|
|
37
|
+
findings and the changed `cli.js` line ranges have 0 findings. The full repo
|
|
38
|
+
CLI scan still reports the pre-existing baseline findings in legacy `cli.js`,
|
|
39
|
+
`daemon.js`, existing HTTP test fixtures, and `scripts/bridge-phase1.js`. No
|
|
40
|
+
suppressions were added.
|
|
41
|
+
|
|
42
|
+
### Added — Idle session cleanup (issue #34)
|
|
43
|
+
|
|
44
|
+
- **Idle visibility in `telepty list`** — session rows now append
|
|
45
|
+
`💤 idle (Xh Ym)` when `lastActivityAt` is more than 60 seconds old.
|
|
46
|
+
`telepty list --json` preserves `lastActivityAt` and adds
|
|
47
|
+
`idle_seconds` for machine consumers.
|
|
48
|
+
- **Transport-agnostic lifecycle helpers** — `src/lifecycle.js` centralizes
|
|
49
|
+
duration parsing, idle-victim selection, older-than cleanup selection, and
|
|
50
|
+
PTY/process-level teardown. It uses native POSIX signals and the existing
|
|
51
|
+
Windows `taskkill` helper; it does not call cmux or any workspace-host API.
|
|
52
|
+
- **`telepty kill <id> [--force] [--timeout <sec>]`** — graceful teardown
|
|
53
|
+
sends SIGTERM, waits up to the configured timeout, then escalates to
|
|
54
|
+
SIGKILL. `--force` sends SIGKILL immediately. Successful teardown removes
|
|
55
|
+
the daemon registry entry and session socket artifacts.
|
|
56
|
+
- **Opt-in idle TTL** — daemon config loads `~/.telepty/config.json` or a
|
|
57
|
+
simple `config.yaml` / `config.yml` with `idle_ttl_default` (`off` by
|
|
58
|
+
default). `telepty allow --idle-ttl <duration|off>` stores a per-session
|
|
59
|
+
override. The daemon reaper emits a `tracing` event with
|
|
60
|
+
`action: "idle_ttl_auto_kill"` before auto-teardown.
|
|
61
|
+
- **`telepty clean --older-than <duration> [--idle] [--dry-run]`** — default
|
|
62
|
+
ghost-only cleanup remains unchanged. The new opt-in path removes sessions
|
|
63
|
+
older than the threshold by `createdAt`, or by `lastActivityAt` when
|
|
64
|
+
`--idle` is set; `--dry-run` reports targets without deleting them.
|
|
65
|
+
|
|
66
|
+
### Notes — Idle session cleanup
|
|
67
|
+
|
|
68
|
+
- **Test suite** — `npm test` passes 397 / 397, including transport-agnostic
|
|
69
|
+
lifecycle coverage for headless and cmux-backed fixtures.
|
|
70
|
+
- **Snyk SAST** — the requested `snyk_code_scan` MCP tool was not available in
|
|
71
|
+
this session, so the installed Snyk CLI was used. New standalone files
|
|
72
|
+
(`src/lifecycle.js`, `src/config-file.js`, and the new lifecycle tests)
|
|
73
|
+
scan with 0 findings. Scanning changed legacy entrypoints (`daemon.js` and
|
|
74
|
+
`cli.js`) still reports the repo's pre-existing baseline findings
|
|
75
|
+
previously noted for Phase 2: CLI path-traversal / command-injection flows
|
|
76
|
+
and daemon route-level prototype-pollution / throttling / command-execution
|
|
77
|
+
warnings. No suppressions were added.
|
|
78
|
+
|
|
79
|
+
### Added — Phase 5a-prime (task #430 P5a-prime)
|
|
80
|
+
|
|
81
|
+
- **`crates/telepty-cross-machine/`** — standalone Rust library plus
|
|
82
|
+
`telepty-cross-machine-bin` for manual HTTP peer operations only. Scope is
|
|
83
|
+
deliberately reduced from the two rejected Phase 5 drafts: no JS bridge, no
|
|
84
|
+
subprocess envelope contract, no outbox queue, no npm distribution, no SSH
|
|
85
|
+
transport, and no `cli.js` / `daemon.js` / `cross-machine.js` changes. This
|
|
86
|
+
follows the review basis in
|
|
87
|
+
`docs/reports/2026-05-24-phase5-spec-codex-review.md` and
|
|
88
|
+
`docs/reports/2026-05-24-phase5a-spec-codex-rereview.md`, which identified
|
|
89
|
+
bridge-consumed binary contracts as the unstable surface.
|
|
90
|
+
- **Manual HTTP subcommands** — `connect-http`, `list-peer-sessions`,
|
|
91
|
+
`inject-peer`, `list-peers`, and `remove-peer`. `connect-http` probes
|
|
92
|
+
`/api/health`, treats `/api/meta` as non-fatal, persists token-backed HTTP
|
|
93
|
+
peers to `~/.telepty/peers.json`, and prints human-friendly status. List
|
|
94
|
+
commands support free-form `--json` output without an envelope contract.
|
|
95
|
+
`inject-peer` fails fast on unreachable peers; there is no queueing.
|
|
96
|
+
- **Backward-compatible `peers.json` handling** — missing `transport` defaults
|
|
97
|
+
to SSH and round-trips without injecting a `transport` field, preserving the
|
|
98
|
+
JS-era legacy schema used by the SSH path. HTTP operations on SSH peers exit
|
|
99
|
+
4 with the explicit JS-path diagnostic required by Phase 5a-prime.
|
|
100
|
+
- **Addressing and atomic-write parity** — Rust host parsing mirrors
|
|
101
|
+
`host-spec.js` URL stripping, embedded-port, and IPv6 behavior. Peer updates
|
|
102
|
+
use the fsync-backed `tmp + fsync(tmp) + rename + fsync(parent_dir)` pattern
|
|
103
|
+
copied from `crates/telepty-supervisor-core/src/manifest.rs`.
|
|
104
|
+
- **Build metadata** — `build.rs` embeds git hash, dirty flag, and build
|
|
105
|
+
timestamp. `telepty-cross-machine-bin --version` prints
|
|
106
|
+
`telepty-cross-machine 0.0.1 (<git-hash>[, dirty])`.
|
|
107
|
+
|
|
108
|
+
### Added — Phase 2 Node↔Rust IPC bridge (task #430 P2)
|
|
109
|
+
|
|
110
|
+
- **`src/bridge/supervisor-ipc.js`** — Node `BridgeClient` speaking NDJSON
|
|
111
|
+
over the per-session UDS (`~/.telepty/sessions/<sid>/supervisor.sock`).
|
|
112
|
+
Surface: `connect(socketPath)` → client; `send(frame)` fire-and-forget;
|
|
113
|
+
`request(frame, {timeoutMs})` with trace_id correlation (resolves on
|
|
114
|
+
matching `pong`, rejects on matching `error` with the supervisor's
|
|
115
|
+
`ERR_*` code preserved, rejects `ERR_TIMEOUT` on drift); `subscribe({sid,
|
|
116
|
+
signal})` returning an `AsyncIterator<Frame>` that respects `AbortSignal`
|
|
117
|
+
and `iterator.return()` for clean unsubscribe; `close()` idempotent and
|
|
118
|
+
rejects any pending requests with `ERR_SUPERVISOR_GONE`. Per synthesis
|
|
119
|
+
ADR §6.2 (B3), `trace_id` is auto-filled for kinds the supervisor
|
|
120
|
+
mandates it on (`inject`/`output`/`signal`/`kill`/`delete`); pong
|
|
121
|
+
reflects ping `trace_id` so correlation works without server-side
|
|
122
|
+
per-client state. Malformed inbound lines surface as synthetic
|
|
123
|
+
`ERR_BAD_FRAME` to subscribers — the connection survives garbage so a
|
|
124
|
+
later-good frame still flows.
|
|
125
|
+
- **`src/bridge/j3-shim.js`** — 0.3.x→NDJSON translator covering the P2
|
|
126
|
+
subset (`inject` / `output` stream / `list`). `inject(sid, prompt, opts)`
|
|
127
|
+
opens a one-shot connection, sends an inject frame, watches 150 ms for a
|
|
128
|
+
trace_id-correlated `error` frame (catches B3 / `ERR_DUPLICATE_OP` /
|
|
129
|
+
`ERR_SHUTTING_DOWN`), and returns `{ success, trace_id, code?, error?
|
|
130
|
+
}`. `output(sid, {fromSeq, signal})` is an async generator yielding
|
|
131
|
+
`{ data, seq }` per `Frame::output` and a final `{ exit, ... }` on
|
|
132
|
+
`shutdown_drain`; consumer-driven cancellation via `AbortSignal` or
|
|
133
|
+
`break`. `list()` scans `~/.telepty/sessions/*/manifest.json` and
|
|
134
|
+
surfaces only `ready` / `draining` sessions (tombstones excluded — they
|
|
135
|
+
lack a usable socket; operators still see them via
|
|
136
|
+
`telepty-supervisor-bin --list`). Sessions root is resolved lazily so
|
|
137
|
+
`TELEPTY_SESSIONS_DIR` redirects work without re-requiring the module.
|
|
138
|
+
- **`src/bridge/supervisor-launcher.js`** — per-session Rust supervisor
|
|
139
|
+
process lifecycle. `resolveBinary({env})` chains
|
|
140
|
+
`TELEPTY_SUPERVISOR_BIN` (env override) → `./target/release/telepty-
|
|
141
|
+
supervisor-bin` (repo-relative) → `./target/debug/...` → `which
|
|
142
|
+
telepty-supervisor-bin` (PATH) and throws `ERR_BIN_NOT_FOUND` otherwise.
|
|
143
|
+
`spawn({sid, argv, cwd?, binary?, env?, stdio?})` shells out to the
|
|
144
|
+
binary with `stdio: ['ignore', 'ignore', 'pipe']` (default) so the
|
|
145
|
+
supervisor's M1/M2 stdout PTY-mirror doesn't bleed into the parent.
|
|
146
|
+
`waitReady(sid, {timeoutMs, pollMs})` gates on BOTH manifest status
|
|
147
|
+
(`ready`/`draining`) AND `fs.existsSync(socket)` — supervisor.rs writes
|
|
148
|
+
the manifest *before* `ipc::bind_socket`, so a manifest-only gate races
|
|
149
|
+
the bind; checking both closes the window without touching the
|
|
150
|
+
supervisor crate. `isAlive(sid)` cross-checks manifest pid via
|
|
151
|
+
`process.kill(pid, 0)`.
|
|
152
|
+
- **`cli.js` minimal-touch wiring** (Rule 29 surgical, +27 LOC, no
|
|
153
|
+
refactor of adjacent code):
|
|
154
|
+
- `cmd === 'list'` (L915): merges `bridgeShim.list()` into the daemon-
|
|
155
|
+
discovered session set, de-duplicated by `id`. Daemon entries remain
|
|
156
|
+
source-of-truth when both surfaces report the same session; bridge
|
|
157
|
+
entries fill the gap when daemon is down. Wrapped in a defensive
|
|
158
|
+
`try/catch` so any bridge failure leaves the daemon list intact.
|
|
159
|
+
- `cmd === 'inject'` LOCAL path (L1755): bridge-first attempt when
|
|
160
|
+
`!useSubmit && bridgeShim.findSupervisorManifest(target.id)` is
|
|
161
|
+
truthy. On bridge success, prints the existing
|
|
162
|
+
`✅ Context injected successfully into '...' (bridge).` line and
|
|
163
|
+
returns; on bridge failure, falls through to the unchanged daemon
|
|
164
|
+
HTTP path so caller-visible behavior never degrades. The gated
|
|
165
|
+
`--submit` semantics (render-gate / retry / `--submit-force`) stay
|
|
166
|
+
on `daemon.js` for the migration window — P2 wire does not carry
|
|
167
|
+
render-gate yet.
|
|
168
|
+
- **`cross-machine.js` UNTOUCHED** — P2 scope is local bridge only;
|
|
169
|
+
remote SSH / HTTP transport stays on the existing path. P3+ owns the
|
|
170
|
+
remote→bridge story.
|
|
171
|
+
|
|
172
|
+
### E2E acceptance — `telepty spawn → inject → output` works with daemon.js stopped
|
|
173
|
+
|
|
174
|
+
- `test/bridge-e2e.test.js` drives the supervisor binary directly through
|
|
175
|
+
`supervisor-launcher` + `j3-shim` in an isolated `HOME` so the live
|
|
176
|
+
daemon (if any) is never touched. The headline test launches a real
|
|
177
|
+
`cat -u` under the supervisor, subscribes to the output stream, injects
|
|
178
|
+
`ping-echo\n`, and asserts the echo arrives — proving the bridge alone
|
|
179
|
+
is sufficient for the primary three operations per dispatch §2.4. The
|
|
180
|
+
test self-skips with a clear hint when
|
|
181
|
+
`target/release/telepty-supervisor-bin` is absent (binary not built
|
|
182
|
+
yet), keeping CI without Rust toolchain green.
|
|
183
|
+
|
|
184
|
+
### Notes — Phase 2 bridge
|
|
185
|
+
|
|
186
|
+
- **No new npm dependencies** (Constitution §17 무의존). NDJSON parsing
|
|
187
|
+
via `readline.createInterface` from the Node stdlib; UDS connection via
|
|
188
|
+
`net.createConnection({ path })`; UUIDs via `crypto.randomUUID()`. Adds
|
|
189
|
+
zero packages to `package.json` `dependencies`.
|
|
190
|
+
- **Test suite** — `npm test` 375 / 375 pass in ~24 s (343 baseline
|
|
191
|
+
preserved per Rule 29 + 32 new bridge tests: 14 `BridgeClient` units,
|
|
192
|
+
14 `j3-shim` units, 4 E2E). Test file ratio is ~1:1 with prod LOC
|
|
193
|
+
(~787 prod / ~797 tests).
|
|
194
|
+
- **Snyk SAST** — `snyk_code_scan` on `src/bridge/` + new test files →
|
|
195
|
+
**0 findings**. Pre-existing `cli.js` findings (3× path-traversal on
|
|
196
|
+
CLI arg → `fs.readFileSync` / `fs.readdirSync` at L2345/L2347/L2656;
|
|
197
|
+
2× command-injection on CLI arg → `execSync` / `node-pty.spawn` at
|
|
198
|
+
L471/L1116) are unchanged by this work — they live in dataflows
|
|
199
|
+
unrelated to the L915/L1755 bridge insertions and are tracked
|
|
200
|
+
separately (consistent with the v0.4.3 baseline). No new Snyk findings
|
|
201
|
+
attributable to this phase.
|
|
202
|
+
- **Path budget** — bridge prod 787 LOC + bridge tests 797 LOC =
|
|
203
|
+
~1.6 kLOC, well within the dispatch envelope (bridge ~400-700 + shim
|
|
204
|
+
~200-400 + tests ~300-500). cli.js delta is +27 LOC pure additions
|
|
205
|
+
with no edits to existing lines, satisfying the minimal-touch
|
|
206
|
+
directive.
|
|
207
|
+
- **Cross-platform** — UDS path is POSIX-only in P2 (Windows native
|
|
208
|
+
pipe = P4 per dispatch §2). Bridge unit tests and E2E gracefully
|
|
209
|
+
skip on `process.platform === 'win32'`; the launcher still resolves
|
|
210
|
+
the binary path on Windows so the eventual P4 wiring has a stub to
|
|
211
|
+
extend.
|
|
212
|
+
|
|
213
|
+
### Carry-overs — Phase 2
|
|
214
|
+
|
|
215
|
+
1. **`telepty spawn` cli command bridge wiring** — out of P2 scope per
|
|
216
|
+
dispatch §Goal item 4 ("inject / output / list paths"). P3 owns the
|
|
217
|
+
refactor that lets `telepty spawn` route through
|
|
218
|
+
`supervisor-launcher.spawn` for supervisor-managed sessions.
|
|
219
|
+
2. **Render-gated `--submit` over bridge** — daemon.js stays as the
|
|
220
|
+
submit gate for the migration window. Bridge inject currently
|
|
221
|
+
appends a literal `\r` to the data (matching the legacy
|
|
222
|
+
`no_enter: false` default) without REPL readiness detection.
|
|
223
|
+
3. **Single-binary `telepty supervisor` mode** — P2 still spawns the
|
|
224
|
+
`telepty-supervisor-bin` standalone bin. The `telepty supervisor`
|
|
225
|
+
subcommand mode per orchestrator decision §6.6 A is post-P2.
|
|
226
|
+
|
|
227
|
+
### Added — Phase 1 supervisor-core-finish (task #430 P1)
|
|
228
|
+
|
|
229
|
+
- **A5 detach/reattach via UDS reconnection + log offset replay** —
|
|
230
|
+
`wire::Kind::Resume` frame with optional `from_seq: u64` lets a
|
|
231
|
+
reconnecting client request replay of `Output` frames whose `seq` is
|
|
232
|
+
greater than `from_seq` from `~/.telepty/sessions/<sid>/log.jsonl`
|
|
233
|
+
before subscribing to the live broadcast. Replay is per-connection
|
|
234
|
+
sequential (handler-local) — no broadcast race. Seq-less audit
|
|
235
|
+
frames (`shutdown_drain`) are forwarded unconditionally so a late
|
|
236
|
+
reattach observes terminal state.
|
|
237
|
+
- **A7 list discovery via filesystem manifest scan** —
|
|
238
|
+
`manifest::scan_sessions()` walks `~/.telepty/sessions/*/manifest.json`
|
|
239
|
+
with atomic per-file reads; missing / unparseable manifests are
|
|
240
|
+
skipped (never panics). New `telepty-supervisor-bin --list` flat
|
|
241
|
+
flag emits a JSON array of `Manifest` to stdout. Output shape is
|
|
242
|
+
the **supervisor-owned** view; the legacy `telepty list --json`
|
|
243
|
+
daemon view will be reconciled by the P3 cli refactor (per dispatch
|
|
244
|
+
§6.1). `--list` is mutually exclusive with run-mode argv.
|
|
245
|
+
- **A8 delete graceful drain integration test** —
|
|
246
|
+
`tests/delete_drain.rs` end-to-end (no goldens): graceful (SIGTERM)
|
|
247
|
+
and forced (SIGKILL) variants both assert manifest unlinked + socket
|
|
248
|
+
unlinked + `log.jsonl` contains `shutdown_drain` with correct
|
|
249
|
+
`exit_reason` + supervisor exits within 3 s. Production code already
|
|
250
|
+
existed in `supervisor::run` (kill_outcome → unlink_clean branch).
|
|
251
|
+
- **B3 trace_id enforcement extended to signal/kill/delete** —
|
|
252
|
+
`wire::validate_incoming` now rejects `Kind::Signal`, `Kind::Kill`,
|
|
253
|
+
`Kind::Delete` lacking `trace_id` with explicit error codes
|
|
254
|
+
(`signal_missing_trace_id`, `kill_missing_trace_id`,
|
|
255
|
+
`delete_missing_trace_id`) per C3 spec §1002 audit linkage
|
|
256
|
+
(`kind:"signal"` event matches originating injector trace_id;
|
|
257
|
+
`kind:"shutdown_drain"` carries parent_trace_id). Rejection reason
|
|
258
|
+
is ALSO appended to `log.jsonl` so the audit trail captures *why* a
|
|
259
|
+
frame was rejected even if the client disconnects before reading
|
|
260
|
+
the error response.
|
|
261
|
+
- **F3 atomic manifest write contract test** —
|
|
262
|
+
`tests/atomic_manifest.rs` (5 tests). Headline test
|
|
263
|
+
`concurrent_readers_never_observe_partial_json` runs 1 writer thread
|
|
264
|
+
+ 6 reader threads × 800 ms; readers always see a complete-old or
|
|
265
|
+
complete-new manifest, never partial JSON (the rename-atomicity
|
|
266
|
+
guarantee). Plus golden tests for `.json.tmp` cleanup, missing-
|
|
267
|
+
parent-dir creation, `unlink_clean` idempotency, and tombstone
|
|
268
|
+
audit-field roundtrip.
|
|
269
|
+
- **G3 audit trail expansion** — `dispatch_ingest` now logs each
|
|
270
|
+
validated ingest event (`Inject` / `Signal` / `Kill` / `Delete`) to
|
|
271
|
+
`log.jsonl` right after `validate_incoming` passes. Ping is
|
|
272
|
+
intentionally skipped (heartbeat noise). Validation rejections are
|
|
273
|
+
also logged (closes the silent-drop gap from earlier milestones).
|
|
274
|
+
`audit.rs` was extended (single module per Constitution §1
|
|
275
|
+
lightweight) rather than fragmenting into a new audit/ submodule.
|
|
276
|
+
R4 TelemetryEvent translation deferred to the P3 cli bridge per
|
|
277
|
+
orchestrator Phase 4 decision.
|
|
278
|
+
- **§8.A1 Normal termination contract test** —
|
|
279
|
+
`tests/normal_termination.rs` (2 tests). Covers child exits 0
|
|
280
|
+
(assert `exit_reason: normal`, `exit_code: 0`, escalated false,
|
|
281
|
+
manifest unlinked) and nonzero-but-natural exit (`sh -c 'exit 7'`
|
|
282
|
+
— assert exit_code propagated; `Normal` is the exit *mechanism*,
|
|
283
|
+
not the exit *code*).
|
|
284
|
+
|
|
285
|
+
### Performance — E1 local-inject latency bench
|
|
286
|
+
|
|
287
|
+
- New `crates/telepty-supervisor-core/benches/inject_e1.rs` custom
|
|
288
|
+
harness (no criterion — Constitution §17 no new Rust deps).
|
|
289
|
+
`[[bench]] harness = false`. Run with `cargo bench --bench inject_e1`.
|
|
290
|
+
100 warmup + 1000 measured roundtrips through real supervisor
|
|
291
|
+
wrapping `cat`.
|
|
292
|
+
- **E1-p50: 0.025 ms** (p90 0.057 ms, p99 0.091 ms) on
|
|
293
|
+
macos/aarch64 / Mac16,8 / Apple M4 Pro — **40× under the 1 ms
|
|
294
|
+
target**.
|
|
295
|
+
- Exit code 0 iff p50 < 1 ms (CI-gateable).
|
|
296
|
+
|
|
297
|
+
### Notes — Phase 1 supervisor-core-finish
|
|
298
|
+
|
|
299
|
+
- **No new Rust deps** (Constitution §17). `tokio` `fs` feature
|
|
300
|
+
enabled in workspace deps (feature flag only). `serde_json` added
|
|
301
|
+
to `telepty-supervisor-bin` (was already a workspace dep).
|
|
302
|
+
- **Rule 29 surgical** — changes scoped to
|
|
303
|
+
`crates/telepty-supervisor-core/` (src + tests + benches) and
|
|
304
|
+
`crates/telepty-supervisor-bin/`. No daemon.js / cli.js changes
|
|
305
|
+
(those land in P2/P3). No Windows code paths (P4 scope; cargo
|
|
306
|
+
features can gate but no implementation in this phase).
|
|
307
|
+
- **Tests** — 42 / 42 pass (23 baseline preserved + 19 new):
|
|
308
|
+
- Unit: +4 wire B3 (signal/kill/delete trace_id), +2 audit, +1
|
|
309
|
+
scan_sessions
|
|
310
|
+
- Integration: +3 reattach_replay (A5), +2 delete_drain (A8), +5
|
|
311
|
+
atomic_manifest (F3), +2 normal_termination (§8.A1)
|
|
312
|
+
- **Snyk SAST** — `snyk_code_scan` on `crates/` → 0 findings across
|
|
313
|
+
both crates. Run at each phase boundary (Phase 4+).
|
|
314
|
+
- **§8.A contract test parity** (per C3 spec
|
|
315
|
+
`docs/specs/2026-05-10-supervisor-c3-kill-gate-spec.md` §8.A): 7
|
|
316
|
+
of 13 Bucket-A scenarios covered + 2 extras (A5 reattach, F3
|
|
317
|
+
atomic) + 4 correctly deferred (Windows = P4 / Bucket B =
|
|
318
|
+
controlled-host out of Phase 1 spike scope). **2 follow-up
|
|
319
|
+
carry-overs documented**: §8.A3-tree (grandchild-cascade
|
|
320
|
+
killpg semantics — code already correct; explicit fixture
|
|
321
|
+
needed) and §8.A-reactor-stall (single-thread reactor
|
|
322
|
+
non-blocking invariant — code-review-only invariant; runtime
|
|
323
|
+
probe optional).
|
|
324
|
+
- **Sources of truth** — the synthesis ADR referenced in dispatch
|
|
325
|
+
(`docs/adr/2026-05-10-telepty-l2-architecture-q-prime-bis.md`)
|
|
326
|
+
and 6-phase plan (`docs/reports/2026-05-23-telepty-l2-supervisor-plan.md`)
|
|
327
|
+
live in the orchestrator repo, not visible from this repo.
|
|
328
|
+
Per Phase 1 CLDR + orchestrator hybrid (b)+(c) decision, this
|
|
329
|
+
work derives §19.2 contract requirements from the local
|
|
330
|
+
`docs/specs/2026-05-10-supervisor-c3-kill-gate-spec.md` (which
|
|
331
|
+
the code already cited as `SPEC-C3-r1`) plus the dispatch text
|
|
332
|
+
itself.
|
|
333
|
+
|
|
5
334
|
## [0.4.3] - 2026-05-23
|
|
6
335
|
|
|
7
336
|
### Fixed
|
package/README.md
CHANGED
|
@@ -68,6 +68,23 @@ telepty broadcast "status report"
|
|
|
68
68
|
| `telepty layout [grid\|tall\|stack]` | Arrange kitty windows |
|
|
69
69
|
| `telepty update` | Update to latest version |
|
|
70
70
|
|
|
71
|
+
## Environment variables
|
|
72
|
+
|
|
73
|
+
| Variable | Values | Default | Description |
|
|
74
|
+
|----------|--------|---------|-------------|
|
|
75
|
+
| `TELEPTY_SUBMIT_FORCE_DEFAULT` | `1`, `true`, `yes`, `on` to enable; unset, `0`, or `off` to disable | unset | Makes `telepty inject --submit <id> "text"` behave as if `--submit-force` was passed. |
|
|
76
|
+
|
|
77
|
+
`TELEPTY_SUBMIT_FORCE_DEFAULT=1` is for orchestrators and automation that
|
|
78
|
+
already know their targets are real, initialized REPLs. It avoids the transient
|
|
79
|
+
504 `bootstrap_not_ready` path where injected text lands in the target input box
|
|
80
|
+
but the render-gated submit refuses to press Enter while the target session is in
|
|
81
|
+
a temporary working state.
|
|
82
|
+
|
|
83
|
+
This bypasses the safety gate that protects sessions still booting. Set it only
|
|
84
|
+
when you understand that trade-off. Use `--no-submit-force` on a specific
|
|
85
|
+
`telepty inject --submit` call to restore the gated behavior even when the
|
|
86
|
+
environment default is enabled.
|
|
87
|
+
|
|
71
88
|
## Cross-Machine Sessions
|
|
72
89
|
|
|
73
90
|
telepty auto-discovers sessions across your Tailnet. All commands (`list`, `attach`, `inject`, `rename`, `multicast`, `broadcast`) work seamlessly across machines.
|