@ictechgy/lterm 1.0.24 → 1.0.25

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.ko.md +83 -29
  2. package/README.md +80 -26
  3. package/package.json +5 -5
package/README.ko.md CHANGED
@@ -7,7 +7,7 @@
7
7
  - **무엇** — tmux처럼 터미널 세션을 백그라운드에서 오래 유지하는 데몬이지만, 기능 범위를 더 작게 좁힌 도구입니다. AI 에이전트 도구를 위한 tmux 호환 명령 계층을 제공하며, 세션을 이름이나 pane id로 detach·reattach할 수 있습니다.
8
8
  - **대상** — Claude Code, Codex CLI, OpenCode, GitHub Copilot CLI, Cursor Agent, Antigravity/`agy`, Kiro, Jules, Aider, Goose, Amp, Crush, Kimi, Qwen, Gemini CLI, `oh-my-codex` / `oh-my-claude` 같은 terminal-first coding agent를 쓰는 사용자와, 이를 `cmux` 안에서 실행하는 사용자.
9
9
  - **사용법** — `lterm start`로 만들고 `lterm resume`으로 (재)접속합니다. shim이 적용된 agent 실행에는 `lterm agent <profile>` / `lterm claude` / `lterm codex` / `lterm opencode` / `lterm agy` / `lterm kiro` / `lterm gemini` 같은 내장 단축 명령을 사용할 수 있습니다. tmux가 켜진 세션 안에서는 `tmux` 명령이 `lterm tmux-compat`으로 해석됩니다.
10
- - **상태** — 1.0 명령/출력 호환성 경계를 문서화한 alpha MVP입니다. 같은 OS 사용자 안에서 쓰는 편의용 데몬이며, **샌드박스도, escape-sequence sanitizer도, 완전한 tmux 대체품도 아닙니다.**
10
+ - **상태** — 문서화된 1.0 명령/출력 호환성 경계를 따르는 1.x CLI입니다. 같은 OS 사용자 안에서 쓰는 편의용 데몬이며, **샌드박스도, escape-sequence sanitizer도, 완전한 tmux 대체품도 아닙니다.**
11
11
 
12
12
  ---
13
13
 
@@ -78,7 +78,7 @@ GitHub에서 Cargo로 설치할 때는 release tag를 고정하세요. 아래
78
78
  README 릴리스 기준이며, 더 최신 tag가 있는지는 Releases 페이지에서 확인하세요:
79
79
 
80
80
  ```bash
81
- cargo install --locked --git https://github.com/ictechgy/light_terminal --tag v1.0.24
81
+ cargo install --locked --git https://github.com/ictechgy/light_terminal --tag v1.0.25
82
82
  ```
83
83
 
84
84
  저장소를 클론한 뒤 직접 빌드하려면 Rust 1.85 이상이 필요합니다.
@@ -138,6 +138,7 @@ lterm -a api
138
138
  | tmux 호환을 켠 상태로 명령 실행 | `lterm run -- codex exec "요약해줘"` | 없음 (`--no-tmux`로 opt out) |
139
139
  | 세션 열기 또는 생성 | `lterm open main` | `attach-or-new` |
140
140
  | 기존 세션 재개 | `lterm resume api` | `attach`, `a`, `-a` |
141
+ | 마지막으로 선택한 세션에 재접속 | `lterm reconnect --mobile` | 없음 |
141
142
  | 모바일에서 agent 출력 확인 | `LTERM_MOBILE=1 lterm resume codex-lterm` | transcript 강제는 `--mobile`, 기존 raw attach 강제는 `--raw` |
142
143
  | 세션 목록 보기 | `lterm sessions` | `list`, `ls` |
143
144
  | 프로세스 트리 확인 | `lterm processes api --json --orphans` | `ps` |
@@ -154,6 +155,7 @@ lterm -a api
154
155
  | 세션 종료 | `lterm close api` | `kill` |
155
156
  | 데몬과 shim 상태 진단 | `lterm doctor --json` | `status` |
156
157
  | redacted 로컬 진단 bundle 수집 | `lterm diagnose --bundle` | 없음 |
158
+ | redacted 로컬 진단 inspect | `lterm inspect --json` | 없음 |
157
159
  | 로컬 설정 단계 미리 보기 | `lterm init --shell zsh` | 없음 |
158
160
  | 지원되는 AI CLI statusline badge 설치 | `lterm install-ai-statusline` | 없음 |
159
161
  | shell completion 설치 | `lterm install-completions --shell zsh` | 없음 |
@@ -211,13 +213,17 @@ row status 표시 여부는 attach mode와는 별개입니다. `--attach-mode=au
211
213
 
212
214
  `lterm status-theme <target> <theme>`(alias: `lterm theme`)은 PTY를 재시작하지 않고 세션별 status bar theme을 저장합니다. pane id를 지정하면 해당 pane이 속한 세션에 적용됩니다. `default`, `clear`, `none`을 쓰면 세션 override를 지우고 attach하는 client의 기본값으로 돌아갑니다. 이미 attach된 client는 detach 후 다시 attach할 때 새 색을 반영합니다. 새 세션은 `lterm start --status-theme green -n api -- npm run dev`(또는 alias `--status-color`)처럼 생성 시점에 같은 metadata를 저장할 수 있습니다.
213
215
 
214
- `lterm doctor`(호환 이름: `lterm status`)는 client/daemon version, protocol 호환성, runtime/data/socket/shim path, shim directory가 `PATH`에 있는지 등을 보고합니다. 이 명령은 daemon을 시작하지 않습니다. 현재 socket에서 호환 daemon이 응답하지 않으면 `daemon_reachable=no` / `false`로 표시됩니다. 일반 client 동작 중 접근 가능한 daemon이 다른 lterm 또는 protocol version을 보고하면 stderr에 경고를 출력하며, 보통 binary upgrade 뒤 예전 daemon이 살아 있는 상황을 뜻합니다.
216
+ `lterm doctor`(호환 이름: `lterm status`)는 client/daemon version, protocol 호환성, runtime/data/socket/shim path, shim directory가 `PATH`에 있는지, count와 boolean/null `tmux_compat` summary 등을 보고합니다. 현재 build는 `tmux_compat`를 출력하지만, stable schema는 binary upgrade 중 예전 doctor output도 validate되도록 additive/optional로 유지합니다. 이 명령은 daemon을 시작하지 않습니다. 현재 socket에서 호환 daemon이 응답하지 않으면 `daemon_reachable=no` / `false`로 표시됩니다. 일반 client 동작 중 접근 가능한 daemon이 다른 lterm 또는 protocol version을 보고하면 stderr에 경고를 출력하며, 보통 binary upgrade 뒤 예전 daemon이 살아 있는 상황을 뜻합니다.
215
217
 
216
218
  `lterm diagnose --bundle`은 issue 보고와 agent handoff를 위한 local-only JSON
217
219
  진단 bundle을 출력합니다. `doctor` 데이터와 redact된 환경 변수 presence flag를
218
220
  포함하고, 기존 daemon에 접근 가능한 경우에 한해 세션 metadata와 process row를
219
221
  함께 담습니다. 이 명령은 daemon을 시작하지 않으며, 기본적으로 raw PTY bytes나
220
- scrollback은 포함하지 않습니다.
222
+ scrollback은 포함하지 않습니다. inspect-style JSON entrypoint가 필요한 도구는
223
+ 같은 redacted bundle을 출력하는 `lterm inspect --json`을 사용할 수 있으며,
224
+ `--json`이 필수입니다.
225
+
226
+ Opt-in local footprint 측정은 `python3 scripts/footprint_benchmark.py --quick --json target/footprint-baseline.json --markdown target/footprint-baseline.md`로 실행합니다. 격리된 lterm-vs-tmux 측정 방법과 해석 caveat는 [`docs/footprint-benchmark.md`](docs/footprint-benchmark.md)를 참고하세요.
221
227
 
222
228
  `lterm logs <target>`은 `--start` / `-S`와 `--end` / `-E` line offset을 받습니다. 0 이상의 값은 absolute scrollback line index이고, 음수 값은 현재 scrollback line count에서 뒤로 셉니다. `--end`는 inclusive라 `lterm logs api -S0 -E0`은 첫 번째 줄만 capture합니다. Capture 출력은 계속 정제된 text입니다. 즉 terminal control은 제거하고 한국어, CJK, emoji 같은 UTF-8 text는 보존합니다. attach된 PTY stream은 raw 그대로 유지됩니다.
223
229
 
@@ -287,38 +293,81 @@ lterm sessions --all
287
293
  lterm processes api --orphans
288
294
  lterm logs api --start=-80 --end=-1
289
295
  lterm urls api --last
296
+ lterm search api 'build failed'
290
297
  lterm compose api
291
298
  LTERM_MOBILE=1 lterm resume codex-lterm
299
+ lterm reconnect --mobile
292
300
  lterm resume --raw codex-lterm
293
301
  lterm wait api --contains READY --timeout 30s --json
294
302
  lterm watch api --exit --notify
295
303
  lterm input api 'echo hello' --enter
296
304
  ```
297
305
 
298
- 위의 일반 alias는 tmux 용어를 몰라도 agent terminal을 일상적으로 다룰 수 있게 해 주는 명령 집합입니다. `sessions`는 영속 작업을 나열하고, `processes`는 child process tree를 확인하고, `logs`는 정제된 scrollback을 읽고, `compose`는 정제된 scrollback과 하단 고정 prompt로 텍스트를 commit할 수 있게 하며, 모바일 transcript attach는 긴 agent 출력을 휴대폰의 기본 scrollback으로 읽을 수 있게 해 줍니다. `wait` / `watch`는 marker 또는 종료 조건을 script와 agent가 관측할 수 있게 하고, `input`은 대상 PTY에 텍스트를 씁니다. `lterm mobile`은 `lterm compose`의 visible alias이고, 별개의 attach flag인 `--mobile`은 normal-screen transcript attach 경로를 선택합니다. 호환 이름 `list` / `ls`, `ps`, `capture`, `send`는 스크립트와 기존 사용 습관에서도 계속 사용할 수 있습니다.
299
-
300
- `lterm urls <target>`은 raw attach PTY stream을 건드리지 않고, 마지막 120개
301
- 정제된 scrollback line에서 `http://` / `https://` link를 추출합니다. 기본
302
- 출력은 link마다 `N<TAB>URL` 줄이고, `--last`는 휴대폰에서 복사하기 쉽도록
303
- 가장 최근의 유효한 URL 하나만 출력합니다. `--json`은 JSON array를 출력하고,
304
- `--tail N`으로 scan 범위를 바꿀 수 있습니다. text mode에서 URL이 없으면 성공
305
- 종료하면서 출력하지 않고, JSON mode는 `[]`를 출력합니다. 추출은 unique ASCII
306
- URL token 256개로 제한되며, 4096 byte를 넘는 raw URL candidate는 잘라 내지
307
- 않고 건너뜁니다. 모바일 transcript mode에서는 `/links` 또는 `/urls`를 입력하면
308
- numbered list를 로컬로 보여 주며, 해당 입력은 PTY로 전달되지 않습니다.
309
- Claude/OAuth 로그인 URL을 Termius 같은 모바일 SSH client에서 복사해야 할 때
310
- 유용합니다. Claude 전용 모바일 제어가 목적이라면 Claude Code Remote Control
311
- 흐름도 URL 복사 왕복을 줄이는 우회책이 있습니다.
312
-
313
- 추출된 link는 신뢰할 수 없는 terminal output으로 취급하세요. 악성 프로그램은
314
- 피싱 URL을 출력할 있고, OAuth, magic-login, device-code link에는 짧게 살아
315
- 있는 secret이 포함될 있습니다. 예상한 link 열고, 공유 로그나 채팅에
316
- 그대로 붙여넣지 말고, `--last`는 최신 link가 의도한 대상임을 알고 있을 때만
317
- 사용하는 것이 안전합니다.
318
-
319
- 자동화와 테스트에는 `lterm compose api --once --message 'hello'`를 사용하면 번의 정제된 capture/send 사이클을 실행합니다. `logs`와 같은 session-or-pane target 모델에서 마지막 `--tail` 정제 라인(기본값: 80)을 capture한 뒤, 기본으로 Enter(`\r`)를 붙여 `lterm input --enter`와 맞추며, `--no-enter`를 추가하면 message byte만 정확히 보냅니다. `compose` / `mobile`은 attach client가 아니며 attached-client 수나 PTY geometry를 바꾸지 않습니다.
320
- Interactive compose 화면은 `--refresh`(기본값: 500ms), 로컬 입력, 터미널 resize 이벤트마다 갱신됩니다. Enter누르면 현재 입력 buffer를 commit하고(빈 buffer도 commit됨), 위 one-shot 규칙처럼 기본으로 `\r`을 덧붙입니다. Ctrl-C, Ctrl-D, EscPTY로 전달하지 않고 로컬 composer를 종료합니다.
321
- `lterm compose api --transcript`를 사용하면 모바일 auto attach가 쓰는 것과 같은 normal-screen transcript UI를 직접 열 수 있습니다. alternate-screen composer 없이 정제된 scrollback과 간단한 line input만 쓰고 싶을 때 적합합니다. 출력만 보고 싶으면 `--read-only`를 추가하세요. Transcript-local command에는 `/refresh`, `/raw`, `/links` / `/urls`, `/exit` / `/quit`가 있고, `/links`와 `/urls`는 로컬에서만 처리되어 PTY로 전달되지 않습니다. link가 없으면 `No URLs found in current transcript.`를 출력하며, 이외의 줄은 PTY로 전달됩니다.
306
+ 위의 일반 alias는 tmux 용어를 몰라도 agent terminal을 일상적으로 다룰 수 있게 해 주는 명령 집합입니다. `sessions`는 영속 작업을 나열하고, `processes`는 child process tree를 확인하고, `logs`는 정제된 scrollback을 읽고, `compose`는 정제된 scrollback과 하단 고정 prompt로 텍스트를 commit할 수 있게 하며, 모바일 transcript attach는 긴 agent 출력을 휴대폰의 기본 scrollback으로 읽을 수 있게 해 줍니다. `reconnect`는 SSH 재접속 뒤 마지막으로 선택했던 로컬 lterm 세션을 다시 엽니다. `wait` / `watch`는 marker 또는 종료 조건을 script와 agent가 관측할 수 있게 하고, `input`은 대상 PTY에 텍스트를 씁니다. `lterm mobile`은 `lterm compose`의 visible alias이고, 별개의 attach flag인 `--mobile`은 normal-screen transcript attach 경로를 선택합니다. 호환 이름 `list` / `ls`, `ps`, `capture`, `send`는 스크립트와 기존 사용 습관에서도 계속 사용할 수 있습니다.
307
+
308
+ `lterm reconnect [fallback]`는 마지막으로 선택한 세션을 가리키는 비공개
309
+ 최소 pointer(`session_id`, pane id, 사용자가 붙인 session name, timestamp)만
310
+ 저장하고, 다음 실행 pointer를 사용합니다. pointer가 없거나 손상됐거나
311
+ 오래되어 이상 맞지 않으면 `fallback`(기본값: `main`)으로 돌아가며,
312
+ 동작은 `lterm open`과 같은 attach-or-create 방식입니다.
313
+
314
+ 세션 이름에는 secret을 넣지 마세요. `reconnect`도 raw attach가 가능하므로,
315
+ 휴대폰 SSH client에서 정제된 normal-screen transcript를 원하면 `--mobile`을
316
+ 함께 사용하세요. 모바일 SSH 로그인용 optional snippet은
317
+ `lterm init --mobile-reconnect --shell zsh`(`bash`, `fish`, `posix`도 가능)로
318
+ 미리 있고, `--shell`을 생략하면 `$SHELL`에서 감지합니다. snippet은
319
+ 자동 설치되지 않습니다. 검토한 직접 복사하고, 되돌릴 때는 복사한 block을
320
+ 삭제하거나 `LTERM_RECONNECT_DISABLE=1`로 건너뛰세요.
321
+
322
+ `lterm urls <target>`는 raw attach PTY stream을 건드리지 않고, 마지막
323
+ 120줄의 정제된 scrollback에서 `http://`와 `https://` link 추출합니다.
324
+ 기본 출력은 link마다 줄씩 `N<TAB>URL`입니다. 최신 유효 URL만 보려면
325
+ `--last`, JSON 배열이 필요하면 `--json`, 검색 범위를 바꾸려면 `--tail N`을
326
+ 사용하세요. text mode에서 link가 없으면 성공 종료하며 아무것도 출력하지 않고,
327
+ JSON mode에서는 `[]`를 출력합니다. URL 추출은 unique ASCII URL token 256개로
328
+ 제한되며, 4096 byte넘는 raw candidate자르지 않고 건너뜁니다.
329
+
330
+ mobile transcript mode에서는 `/links` 또는 `/urls`를 입력하면 같은 번호 목록을
331
+ PTY로 보내지 않고 로컬에서 보여 줍니다. Termius 계열 모바일 SSH client에서
332
+ Claude/OAuth login URL을 복사할 때 유용하며, Claude 전용 모바일
333
+ 제어에는 Claude Code Remote Control flow가 URL 복사 왕복을 줄여 줄 수도
334
+ 있습니다. 추출된 link는 신뢰할 수 없는 terminal output으로 취급하세요. 악성
335
+ 프로그램이 피싱 URL을 출력할 수 있고, OAuth/magic-login/device-code link는
336
+ 짧게 살아 있는 secret을 포함할 수 있습니다. 예상한 link만 열고, 공유 로그나
337
+ 채팅에 붙여 넣지 말며, `--last`는 최신 link가 원하는 link임을 알 때만
338
+ 사용하세요.
339
+
340
+ `lterm search <target> QUERY`는 raw attach PTY stream을 건드리지 않고,
341
+ 마지막 120줄의 정제된 scrollback에서 대소문자를 구분하는 literal match를
342
+ 찾습니다. 기본 출력은 1부터 시작하는 번호를 붙인 `N<TAB>LINE`입니다. `--json`은
343
+ 같은 정제된 match를 JSON 배열로 출력하고, `--tail N`은 검색 범위를
344
+ 바꿉니다. text mode에서 match가 없으면 성공 종료하며 아무것도 출력하지 않고,
345
+ 빈 `QUERY`는 거부합니다. mobile transcript mode에서는 `/grep QUERY`를 입력해
346
+ active transcript tail window의 match를 PTY로 보내지 않고 로컬에서 볼 수
347
+ 있습니다. query 없는 `/grep`은 `Usage: /grep QUERY`를 출력하고, match가 없으면
348
+ `No matches found in current transcript.`를 출력합니다.
349
+
350
+ 자동화와 테스트에서 `lterm compose api --once --message 'hello'`는 정제된
351
+ capture/send cycle을 한 번 수행합니다. `logs`와 같은 session-or-pane target
352
+ 모델로 마지막 `--tail`줄(기본값: 80)의 정제된 output을 캡처한 뒤, 기본적으로
353
+ Enter(`\r`)를 덧붙여 `lterm input --enter`와 같은 방식으로 보냅니다. 정확한
354
+ message byte만 보내려면 `--no-enter`를 추가하세요. `compose` / `mobile`은 attach
355
+ client가 아니며 attached-client 수나 PTY geometry를 바꾸지 않습니다.
356
+
357
+ interactive compose에서는 `--refresh`(기본값: 500ms), local input, resize event에
358
+ 맞춰 view를 갱신합니다. Enter는 현재 input buffer를 commit하며, 빈 buffer도
359
+ commit 대상입니다. 기본적으로 `\r`을 덧붙입니다. Ctrl-C, Ctrl-D, Esc는 PTY로
360
+ 전달하지 않고 local composer를 종료합니다.
361
+
362
+ `lterm compose api --transcript`는 mobile auto attach와 같은 normal-screen
363
+ transcript UI를 엽니다. alternate-screen composer 없이 정제된 scrollback과
364
+ 간단한 line input만 쓰고 싶을 때 사용하고, 출력만 보려면 `--read-only`를
365
+ 추가하세요. transcript-local command는 `/refresh`, `/raw`, `/links` / `/urls`,
366
+ `/grep QUERY`, `/exit` / `/quit`입니다. `/links`, `/urls`, `/grep`은 로컬에서만
367
+ 처리되고 PTY로 전달되지 않습니다. link가 없으면 `No URLs found in current
368
+ transcript.`를 출력하고, query 없는 `/grep`은 `Usage: /grep QUERY`, match가
369
+ 없으면 `No matches found in current transcript.`를 출력합니다. 알 수 없는 줄은
370
+ PTY로 전송됩니다.
322
371
 
323
372
  **세션 종료:**
324
373
 
@@ -524,6 +573,11 @@ lterm ssh user@host main
524
573
  lterm ssh devbox main -- -p 2222 -i ~/.ssh/id_ed25519
525
574
  ```
526
575
 
576
+ 일반 모바일 SSH로 호스트에 로그인한 뒤에는 `lterm reconnect --mobile`을 실행해
577
+ 그 호스트에서 마지막으로 선택했던 lterm 세션을 다시 열 수 있습니다. `lterm ssh`
578
+ 자체는 구버전 원격 설치와의 호환성을 위해 기존 `attach-or-new` wire command를
579
+ 그대로 유지합니다.
580
+
527
581
  ## 구조
528
582
 
529
583
  - **데몬** — 사용자별 Unix socket 하나를 `$XDG_RUNTIME_DIR` 아래에 만들고, 없으면 `/tmp` 아래 소유자 전용 fallback 경로를 사용합니다.
@@ -540,7 +594,7 @@ lterm ssh devbox main -- -p 2222 -i ~/.ssh/id_ed25519
540
594
 
541
595
  **터미널 출력은 그대로 전달됩니다.** `lterm resume`(호환 이름: `lterm attach`)은 full-screen 터미널 프로그램과 cmux/OSC 알림이 정상 동작하도록 PTY byte를 그대로 통과시킵니다. 로컬 상태 바는 클라이언트 쪽 표시 요소일 뿐이며, 완전한 raw 모드 터미널이 필요하면 `--no-status`를 사용하세요. nested agent row suspension은 host-side geometry/status 관리일 뿐 attach된 PTY byte를 정제하거나 다시 쓰지 않습니다. 신뢰할 수 없는 child 프로그램은 tmux/screen에서와 마찬가지로 attach된 터미널에 escape sequence를 출력할 수 있습니다. **`lterm`을 escape-sequence sanitizer나 sandbox로 사용하지 마세요.**
542
596
 
543
- **Capture 출력은 표시/로깅 전에 terminal control sequence를 제거합니다.** `lterm logs`(호환 이름: `lterm capture`), `lterm compose`(alias: `lterm mobile`), `tmux capture-pane`은 captured scrollback 출력할 raw 또는 UTF-8 encoded C1 control을 포함한 터미널 제어 시퀀스를 제거합니다. 정상 UTF-8 text인 한국어, CJK, emoji는 보존합니다. 그래도 scrollback text는 신뢰할 수 없는 프로그램 출력일 수 있으므로 사람이나 agent에게 넘기기 전에 확인하세요. `compose`는 attach가 아닌 view에서 기존 input/send 경로로 텍스트를 commit하며, raw attached PTY stream을 변환하지 않습니다.
597
+ **Capture report 출력은 표시/로깅 전에 terminal control sequence를 제거합니다.** `lterm logs`(호환 이름: `lterm capture`), `lterm compose`(alias: `lterm mobile`), `lterm search`, `lterm urls`, 진단 출력, `tmux capture-pane`은 scrollback에서 나온 text를 출력하기 전에 raw 또는 UTF-8 encoded C1 control을 포함한 터미널 제어 시퀀스를 제거합니다. 정상 UTF-8 text인 한국어, CJK, emoji는 보존합니다. 그래도 scrollback text는 신뢰할 수 없는 프로그램 출력일 수 있으므로 사람이나 agent에게 넘기기 전에 확인하세요. `compose`는 attach가 아닌 view에서 기존 input/send 경로로 텍스트를 commit하며, raw attach PTY stream을 변환하지 않습니다.
544
598
 
545
599
  **프로세스 가시성.** `lterm processes [session]`(호환 이름: `lterm ps [session]`)은 process-group id와 함께 각 세션 child 아래의 process tree를 보여 줍니다. `--orphans`를 추가하면 기록된 session root의 descendant가 아니지만 같은 process group에 남아 있는 row도 함께 보여 주므로, Codex/OMX/MCP subprocess가 누적되어 메모리 누수처럼 커지기 전에 확인할 수 있습니다. 시스템 `ps`는 절대 경로로 호출하며, 형식이 잘못된 process row는 추측하지 않고 건너뜁니다.
546
600
 
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  - **What** — A persistent terminal session daemon (like tmux, but smaller) with a tmux-compatible command layer for AI-agent tooling. Detach and reattach by name or pane id.
8
8
  - **Who it's for** — Terminal-first coding agents such as Claude Code, Codex CLI, OpenCode, GitHub Copilot CLI, Cursor Agent, Antigravity/`agy`, Kiro, Jules, Aider, Goose, Amp, Crush, Kimi, Qwen, Gemini CLI, `oh-my-codex` / `oh-my-claude`, and users running them inside `cmux`.
9
9
  - **How** — Use `lterm start` to create a session, `lterm resume` to reconnect, and `lterm agent <profile>` / `lterm claude` / `lterm codex` / `lterm opencode` / `lterm agy` / `lterm kiro` / `lterm gemini` for built-in shimmed agent launchers. Inside a tmux-enabled session, the `tmux` command resolves to `lterm tmux-compat`.
10
- - **Status** — Alpha MVP with a documented 1.0 command/output compatibility boundary. It is a same-user convenience daemon — **not** a sandbox, an escape-sequence sanitizer, or a full tmux replacement.
10
+ - **Status** — 1.x CLI with a documented 1.0 command/output compatibility boundary. It is a same-user convenience daemon — **not** a sandbox, an escape-sequence sanitizer, or a full tmux replacement.
11
11
 
12
12
  ---
13
13
 
@@ -81,7 +81,7 @@ With Cargo from GitHub, pin a release tag. The example below uses the current
81
81
  README release; check the Releases page for newer tags:
82
82
 
83
83
  ```bash
84
- cargo install --locked --git https://github.com/ictechgy/light_terminal --tag v1.0.24
84
+ cargo install --locked --git https://github.com/ictechgy/light_terminal --tag v1.0.25
85
85
  ```
86
86
 
87
87
  Building from this checkout requires Rust 1.85 or newer:
@@ -141,6 +141,7 @@ lterm -a api
141
141
  | Run a command with tmux compatibility enabled | `lterm run -- codex exec "summarize"` | None (`--no-tmux` opts out) |
142
142
  | Open or create a session | `lterm open main` | `attach-or-new` |
143
143
  | Resume an existing session | `lterm resume api` | `attach`, `a`, `-a` |
144
+ | Reconnect to the last selected session | `lterm reconnect --mobile` | None |
144
145
  | Review an agent session in mobile scrollback | `LTERM_MOBILE=1 lterm resume codex-lterm` | Force with `--mobile`; force raw with `--raw` |
145
146
  | List sessions | `lterm sessions` | `list`, `ls` |
146
147
  | Inspect process trees | `lterm processes api --json --orphans` | `ps` |
@@ -157,6 +158,7 @@ lterm -a api
157
158
  | Stop a session | `lterm close api` | `kill` |
158
159
  | Diagnose daemon and shim state | `lterm doctor --json` | `status` |
159
160
  | Collect a redacted local diagnostic bundle | `lterm diagnose --bundle` | None |
161
+ | Inspect redacted local diagnostics | `lterm inspect --json` | None |
160
162
  | Preview local setup steps | `lterm init --shell zsh` | None |
161
163
  | Install supported AI CLI statusline badges | `lterm install-ai-statusline` | None |
162
164
  | Install shell completions | `lterm install-completions --shell zsh` | None |
@@ -211,13 +213,16 @@ Every lterm session also exports `LTERM_SESSION` and `LTERM_PANE` inside the chi
211
213
 
212
214
  `lterm status-theme <target> <theme>` (alias: `lterm theme`) stores a per-session status bar theme without restarting the PTY; pane ids resolve to their session. Use `default`, `clear`, or `none` to remove the session override and return to the attaching client's default. Already-attached clients keep their current status color until they detach and reattach. New sessions can set the same metadata at creation time with `lterm start --status-theme green -n api -- npm run dev` (or alias `--status-color`).
213
215
 
214
- `lterm doctor` (compatibility name: `lterm status`) reports client/daemon versions, protocol compatibility, runtime/data/socket/shim paths, and whether the shim directory is on `PATH`. It does not start the daemon; `daemon_reachable=no` / `false` means no compatible daemon answered on the current socket. Normal client operations warn on stderr when a reachable daemon reports a different lterm or protocol version, which usually means an old daemon survived a binary upgrade.
216
+ `lterm doctor` (compatibility name: `lterm status`) reports client/daemon versions, protocol compatibility, runtime/data/socket/shim paths, whether the shim directory is on `PATH`, and a count plus boolean/null `tmux_compat` summary. Current builds emit `tmux_compat`, but the stable schema keeps it additive/optional so older doctor outputs still validate during mixed-version upgrades. It does not start the daemon; `daemon_reachable=no` / `false` means no compatible daemon answered on the current socket. Normal client operations warn on stderr when a reachable daemon reports a different lterm or protocol version, which usually means an old daemon survived a binary upgrade.
215
217
 
216
218
  `lterm diagnose --bundle` prints a local-only JSON diagnostic bundle for issues
217
219
  and agent handoffs. It includes `doctor` data, redacted environment presence
218
220
  flags, and — only when an existing daemon is reachable — session metadata plus
219
221
  process rows. It does not start the daemon and does not include raw PTY bytes or
220
- scrollback by default.
222
+ scrollback by default. `lterm inspect --json` prints the same redacted bundle for
223
+ tools that expect an inspect-style JSON entrypoint; it requires `--json`.
224
+
225
+ For opt-in local footprint measurements, run `python3 scripts/footprint_benchmark.py --quick --json target/footprint-baseline.json --markdown target/footprint-baseline.md`. See [`docs/footprint-benchmark.md`](docs/footprint-benchmark.md) for the isolated lterm-vs-tmux methodology and interpretation caveats.
221
226
 
222
227
  `lterm logs <target>` accepts `--start` / `-S` and `--end` / `-E` line offsets. Non-negative values are absolute scrollback line indexes; negative values count back from the current scrollback line count. `--end` is inclusive, so `lterm logs api -S0 -E0` captures only the first line. Capture output remains sanitized text: terminal controls are removed, while UTF-8 text such as Korean, CJK, and emoji is preserved. Attached PTY streams remain raw.
223
228
 
@@ -288,38 +293,82 @@ lterm sessions --all
288
293
  lterm processes api --orphans
289
294
  lterm logs api --start=-80 --end=-1
290
295
  lterm urls api --last
296
+ lterm search api 'build failed'
291
297
  lterm compose api
292
298
  LTERM_MOBILE=1 lterm resume codex-lterm
299
+ lterm reconnect --mobile
293
300
  lterm resume --raw codex-lterm
294
301
  lterm wait api --contains READY --timeout 30s --json
295
302
  lterm watch api --exit --notify
296
303
  lterm input api 'echo hello' --enter
297
304
  ```
298
305
 
299
- The generic aliases above are meant for day-to-day agent-terminal use: `sessions` lists persistent work, `processes` inspects child process trees, `logs` reads sanitized scrollback, `compose` shows sanitized scrollback with a fixed bottom prompt for committing text, mobile transcript attach gives phone clients native scrollback for long agent output, `wait` / `watch` make marker-or-exit conditions observable for scripts and agents, and `input` writes text to the target PTY. `lterm mobile` is a visible alias for `lterm compose`; separately, the `--mobile` attach flag selects the normal-screen transcript attach path. The compatibility names `list` / `ls`, `ps`, `capture`, and `send` remain available for scripts and muscle memory.
306
+ The generic aliases above are meant for day-to-day agent-terminal use: `sessions` lists persistent work, `processes` inspects child process trees, `logs` reads sanitized scrollback, `compose` shows sanitized scrollback with a fixed bottom prompt for committing text, mobile transcript attach gives phone clients native scrollback for long agent output, `reconnect` resumes the last selected local lterm session after an SSH reconnect, `wait` / `watch` make marker-or-exit conditions observable for scripts and agents, and `input` writes text to the target PTY. `lterm mobile` is a visible alias for `lterm compose`; separately, the `--mobile` attach flag selects the normal-screen transcript attach path. The compatibility names `list` / `ls`, `ps`, `capture`, and `send` remain available for scripts and muscle memory.
307
+
308
+ `lterm reconnect [fallback]` stores a private, minimal pointer to the last
309
+ selected session (`session_id`, pane id, user-chosen session name, and
310
+ timestamp), then uses that pointer on the next run. Missing, corrupt, or stale
311
+ pointers fall back to `fallback` (default: `main`) with the same
312
+ attach-or-create behavior as `lterm open`.
313
+
314
+ Do not put secrets in session names. `reconnect` can still raw-attach, so use
315
+ `--mobile` on phone SSH clients when you want the sanitized normal-screen
316
+ transcript instead of the raw PTY stream. Preview the optional SSH-login snippet
317
+ with `lterm init --mobile-reconnect --shell zsh` (or `bash`, `fish`, `posix`);
318
+ omit `--shell` to detect from `$SHELL`. The snippet is not installed
319
+ automatically: copy it only after review, remove the copied block to undo it, or
320
+ set `LTERM_RECONNECT_DISABLE=1` to skip it.
300
321
 
301
322
  `lterm urls <target>` extracts `http://` and `https://` links from the last
302
323
  120 sanitized scrollback lines without touching the raw attached PTY stream.
303
- Default output is `N<TAB>URL`, one link per line; `--last` prints only the
304
- newest valid URL occurrence for phone-friendly copy/paste, `--json` emits a
305
- JSON array, and `--tail N` changes the scan range. Empty text modes exit
306
- successfully with no output, while JSON mode prints `[]`. Extraction is bounded
307
- to 256 unique ASCII URL tokens and skips raw URL candidates longer than 4096
308
- bytes instead of truncating them. In mobile transcript mode, type `/links` or
309
- `/urls` to show the same numbered list locally instead of sending that text to
310
- the PTY. This is useful for Claude/OAuth login URLs on Termius-style mobile SSH
311
- clients; for Claude-specific mobile control, Claude Code's Remote Control flow
312
- can also reduce URL-copy round trips.
313
-
314
- Treat extracted links as untrusted terminal output. A malicious program can
315
- print phishing URLs, and OAuth, magic-login, or device-code links may carry
316
- short-lived secrets. Open only links you expect, avoid pasting them into shared
317
- logs or chat, and prefer `--last` only when you know the newest link is the one
318
- you intend to use.
319
-
320
- For automation and tests, `lterm compose api --once --message 'hello'` performs one sanitized capture/send cycle. It captures the last `--tail` sanitized lines (default: 80) from the same session-or-pane target model as `logs`, then appends Enter (`\r`) by default, matching `lterm input --enter`; add `--no-enter` to send the exact message bytes. `compose` / `mobile` is not an attach client and does not change attached-client counts or PTY geometry.
321
- In interactive compose, the view refreshes on `--refresh` (default: 500ms) and after local input or resize events. Pressing Enter commits the current input buffer (empty buffers are committed too) and appends `\r` by default, matching the one-shot rule above. Ctrl-C, Ctrl-D, and Esc exit the local composer instead of forwarding to the PTY.
322
- `lterm compose api --transcript` opens the same normal-screen transcript UI used by mobile auto attach. It is useful when you want sanitized scrollback and simple line input without the alternate-screen composer; add `--read-only` when you only want to watch output. Transcript-local commands include `/refresh`, `/raw`, `/links` / `/urls`, and `/exit` / `/quit`; `/links` and `/urls` are handled locally and are never forwarded to the PTY. When no links are present they print `No URLs found in current transcript.`; unrecognized lines are sent to the PTY.
324
+ Default output is `N<TAB>URL`, one link per line. Use `--last` for the newest
325
+ valid URL, `--json` for a JSON array, and `--tail N` to change the scan range.
326
+ Empty text modes exit successfully with no output; JSON mode prints `[]`. URL
327
+ extraction is bounded to 256 unique ASCII URL tokens and skips raw candidates
328
+ longer than 4096 bytes instead of truncating them.
329
+
330
+ In mobile transcript mode, type `/links` or `/urls` to show the same numbered
331
+ list locally instead of sending that text to the PTY. This is useful for
332
+ Claude/OAuth login URLs on Termius-style mobile SSH clients; for
333
+ Claude-specific mobile control, Claude Code's Remote Control flow can also
334
+ reduce URL-copy round trips. Treat extracted links as untrusted terminal
335
+ output: a malicious program can print phishing URLs, and OAuth, magic-login, or
336
+ device-code links may carry short-lived secrets. Open only links you expect,
337
+ avoid pasting them into shared logs or chat, and use `--last` only when you
338
+ know the newest link is the one you intend to open.
339
+
340
+ `lterm search <target> QUERY` searches the last 120 sanitized scrollback lines
341
+ for case-sensitive literal matches without touching the raw attached PTY stream.
342
+ Default output is `N<TAB>LINE` with 1-based numbering; `--json` emits the same
343
+ sanitized matching lines as a JSON array, and `--tail N` changes the scan range.
344
+ No-match text mode exits successfully with no output, while an empty `QUERY` is
345
+ rejected. In mobile transcript mode, type `/grep QUERY` to show matching lines
346
+ from the active transcript tail window locally instead of sending that text to
347
+ the PTY. `/grep` without a query prints `Usage: /grep QUERY`; no matches print
348
+ `No matches found in current transcript.`
349
+
350
+ For automation and tests, `lterm compose api --once --message 'hello'` performs
351
+ one sanitized capture/send cycle. It captures the last `--tail` sanitized lines
352
+ (default: 80) from the same session-or-pane target model as `logs`, then appends
353
+ Enter (`\r`) by default, matching `lterm input --enter`; add `--no-enter` to
354
+ send the exact message bytes. `compose` / `mobile` is not an attach client and
355
+ does not change attached-client counts or PTY geometry.
356
+
357
+ In interactive compose, the view refreshes on `--refresh` (default: 500ms) and
358
+ after local input or resize events. Pressing Enter commits the current input
359
+ buffer, including an empty buffer, and appends `\r` by default. Ctrl-C, Ctrl-D,
360
+ and Esc exit the local composer instead of forwarding to the PTY.
361
+
362
+ `lterm compose api --transcript` opens the same normal-screen transcript UI used
363
+ by mobile auto attach. Use it when you want sanitized scrollback and simple line
364
+ input without the alternate-screen composer; add `--read-only` when you only
365
+ want to watch output. Transcript-local commands include `/refresh`, `/raw`,
366
+ `/links` / `/urls`, `/grep QUERY`, and `/exit` / `/quit`. `/links`, `/urls`,
367
+ and `/grep` are handled locally and are never forwarded to the PTY. When no
368
+ links are present they print `No URLs found in current transcript.`; `/grep`
369
+ without a query prints `Usage: /grep QUERY`; no matches print
370
+ `No matches found in current transcript.` Unrecognized lines are sent to the
371
+ PTY.
323
372
 
324
373
  **Stop a session:**
325
374
 
@@ -516,6 +565,11 @@ This uses the same attach-or-create behavior as `lterm open main` on the remote
516
565
  lterm ssh devbox main -- -p 2222 -i ~/.ssh/id_ed25519
517
566
  ```
518
567
 
568
+ After a plain mobile SSH login to a host, run `lterm reconnect --mobile` to
569
+ resume the last lterm session selected on that host. `lterm ssh` itself keeps
570
+ the legacy `attach-or-new` remote command for compatibility with older remote
571
+ installs.
572
+
519
573
  ## Architecture
520
574
 
521
575
  - **Daemon** — one Unix socket per user under `$XDG_RUNTIME_DIR`, with an owner-only fallback under `/tmp`.
@@ -532,7 +586,7 @@ the old code until they are stopped.
532
586
 
533
587
  **Terminal output is forwarded as-is.** `lterm resume` (compatibility name: `lterm attach`) passes PTY bytes through so full-screen terminal programs and cmux/OSC notifications keep working. The local status bar is purely a client-side decoration; use `--no-status` for a fully raw terminal surface. Any nested-agent row suspension is host-side geometry/status management only and does not sanitize or rewrite attached PTY bytes. Untrusted child programs can still emit terminal escape sequences to an attached terminal — exactly as under tmux/screen. **Do not use `lterm` as an escape-sequence sanitizer or sandbox.**
534
588
 
535
- **Capture output is terminal-control-sanitized before display/logging.** `lterm logs` (compatibility name: `lterm capture`), `lterm compose` (alias: `lterm mobile`), and `tmux capture-pane` strip terminal control sequences, including raw or UTF-8-encoded C1 controls, before printing scrollback. Valid UTF-8 text such as Korean, CJK, and emoji is preserved. Scrollback text can still be untrusted program output, so review it before feeding it to humans or agents. `compose` is a non-attached view that commits text through the existing input/send path; it does not transform raw attached PTY streams.
589
+ **Capture and report output is terminal-control-sanitized before display/logging.** `lterm logs` (compatibility name: `lterm capture`), `lterm compose` (alias: `lterm mobile`), `lterm search`, `lterm urls`, diagnostics, and `tmux capture-pane` strip terminal control sequences, including raw or UTF-8-encoded C1 controls, before printing scrollback-derived text. Valid UTF-8 text such as Korean, CJK, and emoji is preserved. Scrollback text can still be untrusted program output, so review it before feeding it to humans or agents. `compose` is a non-attached view that commits text through the existing input/send path; it does not transform raw attached PTY streams.
536
590
 
537
591
  **Process visibility.** `lterm processes [session]` (or compatibility name `lterm ps [session]`) shows the process tree rooted at each session child, including process-group ids. Add `--orphans` to also include same-process-group rows that are no longer descendants of the recorded session root, so long-running Codex/OMX/MCP subprocess buildup stays visible before it becomes a memory-leak surprise. The system `ps` is invoked by absolute path, and malformed process rows are skipped rather than guessed at.
538
592
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ictechgy/lterm",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
4
4
  "description": "Lightweight tmux-compatible terminal session daemon with cmux-friendly notifications.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "homepage": "https://github.com/ictechgy/light_terminal#readme",
@@ -36,10 +36,10 @@
36
36
  "scripts/validate_npm_packages.mjs"
37
37
  ],
38
38
  "optionalDependencies": {
39
- "lterm-darwin-arm64": "1.0.24",
40
- "lterm-darwin-x64": "1.0.24",
41
- "lterm-linux-arm64": "1.0.24",
42
- "lterm-linux-x64": "1.0.24"
39
+ "lterm-darwin-arm64": "1.0.25",
40
+ "lterm-darwin-x64": "1.0.25",
41
+ "lterm-linux-arm64": "1.0.25",
42
+ "lterm-linux-x64": "1.0.25"
43
43
  },
44
44
  "engines": {
45
45
  "node": ">=16"