terminal-tool-for-agents 0.1.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ <div align="center">
2
+
3
+ <img src="./src/watch-ui/logo.png" alt="terminal-tool-for-agents, abbreviated as tta" width="520">
4
+
5
+
6
+ ### **tta: a terminal tool for agents — lets agents operate interactive terminals.**
7
+
8
+ [![npm](https://img.shields.io/npm/v/terminal-tool-for-agents.svg)](https://www.npmjs.com/package/terminal-tool-for-agents)
9
+
10
+ [中文 README](./README.zh.md)
11
+
12
+ </div>
13
+
14
+
15
+ ## What it is
16
+
17
+ `tta` is for agents. It drives interactive terminal programs: REPLs (e.g. `GDB`, `IPython`), TUIs (e.g. `lazygit`), setup wizards (e.g. `npm create vite`), long-running processes you observe over time (e.g. `npm run dev`), and **coding agent CLIs** (e.g. Claude Code — multi-agent orchestration see [**tta-agents**](./docs/tta-agents-docs.md)).
18
+
19
+ Idea: start background terminals as `sess`, send keys or text as `act`, then wait for a stable screen and read results as `obs`.
20
+
21
+ Use `bash` for non-interactive commands. Use `tta` for interactive ones.
22
+
23
+ Forked from [tui-use](https://github.com/onesuper/tui-use) and modified for `tta`. Thanks to [onesuper](https://github.com/onesuper) for the original work.
24
+
25
+
26
+ ## Quick Start
27
+
28
+ Copy this block into your agent:
29
+
30
+ ```text
31
+ Install tta CLI:
32
+ npm install -g terminal-tool-for-agents
33
+
34
+ Install the tta skill from:
35
+ https://github.com/yanggggjie/terminal-tool-for-agents/tree/main/skills/tta
36
+
37
+ (includes bundled tta-agents-skill; no separate install)
38
+
39
+ Confirm both are installed.
40
+ ```
41
+
42
+ Then ask your agent to run a task:
43
+
44
+ ```text
45
+ Use tta to run an interactive terminal program and finish the task.
46
+ ```
47
+
48
+ **Human session observation:**
49
+
50
+ ```bash
51
+ tta sess watch
52
+ ```
53
+
54
+ Then open http://127.0.0.1:7654/.
55
+
56
+ ## Update
57
+
58
+ Copy this block into your agent:
59
+
60
+ ```text
61
+ Update tta CLI:
62
+ npm update -g terminal-tool-for-agents
63
+
64
+ Update the tta skill from:
65
+ https://github.com/yanggggjie/terminal-tool-for-agents/tree/main/skills/tta
66
+
67
+ Kill all tta sessions so the background service restarts on next use:
68
+ tta sess killall
69
+
70
+ Confirm both are updated.
71
+ ```
72
+
73
+ ## When to use tta vs shell
74
+
75
+ | Situation | Tool | Kill session? |
76
+ |-----------|------|---------------|
77
+ | Plain / non-interactive command | shell | - |
78
+ | One-shot interactive CLI (`npm create vite@latest`) | tta | **Yes** when done |
79
+ | Interactive TUI (`lazygit`) | tta | **Yes** when done |
80
+ | Long-running + observe logs (`npm run dev`) | tta | **No** while observing |
81
+
82
+ Coding agent workers (keep chat context) → triggers bundled [tta-agents](./docs/tta-agents-docs.md) sub-skill.
83
+
84
+ **If you use tta-agents to orchestrate multiple coding agents: clearly tell the Orchestrator your permission scope (allowed/forbidden actions, directories, deploy, etc.). Workers run in auto mode by default and treat prompts as authorization.** See [tta-agents docs](./docs/tta-agents-docs.md).
85
+
86
+ ## API examples
87
+
88
+ Tip: Be lazy — don’t try it yourself; let the agent do it.
89
+
90
+ ```bash
91
+ # Dev server: keep session, observe with obs
92
+ tta sess start --sess=dev --cmd="npm run dev" --cwd="/path/to/project"
93
+ tta obs screen stable --sess=dev
94
+
95
+ # One-shot interactive CLI: kill when done
96
+ tta sess start --sess=vite-once --cmd="npm create vite@latest" --cwd="/path/to/project"
97
+ tta obs screen stable --sess=vite-once
98
+ tta act send key --sess=vite-once --key=enter
99
+ tta obs screen stable --sess=vite-once
100
+ tta sess kill --sess=vite-once
101
+ ```
102
+
103
+ ## API overview
104
+
105
+ All tta work happens inside a **session** (`--sess=`).
106
+
107
+ | API | Commands | Role |
108
+ |-----|----------|------|
109
+ | **sess** | `start`, `kill`, `killall`, `list`, `keys`, `watch` | Create, stop, list sessions; human watch UI |
110
+ | **act** | `send text`, `send key` | Send input to a **running** session |
111
+ | **obs** | `screen now`, `screen stable`, `screen scroll` | Read session screen |
112
+
113
+ ```text
114
+ tta sess start -> (tta act ... -> tta obs screen stable)* -> tta sess kill
115
+ ```
116
+
117
+ On failure: one line `error: <reason>`, exit code 1.
118
+
119
+ Operational details: [`skills/tta/SKILL.md`](./skills/tta/SKILL.md).
120
+
121
+ ## Requirements
122
+
123
+ - **Node.js** 22.x–26.x (`engines`: `>=22.0.0 <27.0.0`); repo includes `.nvmrc` (`24`) for local dev
124
+ - After `npm install` or `npm install -g`, if npm warns about allow-scripts for `node-pty`, run `npm approve-scripts node-pty` or `npm approve-scripts --allow-scripts-pending`, then reinstall so the PTY native module installs correctly.
125
+
126
+ ## Development
127
+
128
+ ```bash
129
+ just dev
130
+ just link # link for global testing
131
+ just unlink # remove link after testing
132
+ tta sess watch # open http://127.0.0.1:7654 to observe
133
+ ```
134
+
135
+ - **Backend** (`src/*.ts`): save → tsc recompiles → nodemon restarts server → refresh browser.
136
+ - **Watch UI** (`src/watch-ui/*`): save → refresh browser (served from `src/` in dev).
137
+
138
+ ## License
139
+
140
+ MIT
package/README.zh.md ADDED
@@ -0,0 +1,140 @@
1
+ <div align="center">
2
+
3
+ <img src="./src/watch-ui/logo.png" alt="terminal-tool-for-agents, abbreviated as tta" width="520">
4
+
5
+
6
+ ### **tta:供 Agent 使用的终端工具,让 Agent 操作交互式终端。**
7
+
8
+ [![npm](https://img.shields.io/npm/v/terminal-tool-for-agents.svg)](https://www.npmjs.com/package/terminal-tool-for-agents)
9
+
10
+ [English README](./README.md)
11
+
12
+ </div>
13
+
14
+
15
+ ## 是什么
16
+
17
+ `tta` 面向 Agent,驱动交互式终端程序:REPL(如 `GDB`、`IPython`)、TUI(如 `lazygit`)、安装向导(如 `npm create vite`)、持续观察日志的服务(如 `npm run dev`),以及 **Coding Agent CLI**(如`Claude Code` 多 Agent 编排见 [**tta-agents**](./docs/tta-agents-docs.zh.md))。
18
+
19
+ 核心思路:`sess` 启动后台终端 → `act` 发送按键或文本 → `obs` 等待稳定后读屏。
20
+
21
+ 非交互式命令用 `bash`,交互式命令用 `tta`。
22
+
23
+ Fork 自 [tui-use](https://github.com/onesuper/tui-use) 并改造为 `tta`。感谢 [onesuper](https://github.com/onesuper) 的原始工作。
24
+
25
+
26
+ ## 快速开始
27
+
28
+ 将下面这段复制给你的 Agent:
29
+
30
+ ```text
31
+ Install tta CLI:
32
+ npm install -g terminal-tool-for-agents
33
+
34
+ Install the tta skill from:
35
+ https://github.com/yanggggjie/terminal-tool-for-agents/tree/main/skills/tta
36
+
37
+ (includes bundled tta-agents-skill; no separate install)
38
+
39
+ Confirm both are installed.
40
+ ```
41
+
42
+ 然后让 Agent 执行任务:
43
+
44
+ ```text
45
+ Use tta to run an interactive terminal program and finish the task.
46
+ ```
47
+
48
+ **人类观察 session:**
49
+
50
+ ```bash
51
+ tta sess watch
52
+ ```
53
+
54
+ 然后打开 http://127.0.0.1:7654/。
55
+
56
+ ## 更新
57
+
58
+ 将下面这段复制给你的 Agent:
59
+
60
+ ```text
61
+ Update tta CLI:
62
+ npm update -g terminal-tool-for-agents
63
+
64
+ Update the tta skill from:
65
+ https://github.com/yanggggjie/terminal-tool-for-agents/tree/main/skills/tta
66
+
67
+ Kill all tta sessions so the background service restarts on next use:
68
+ tta sess killall
69
+
70
+ Confirm both are updated.
71
+ ```
72
+
73
+ ## 何时用 tta vs shell
74
+
75
+ | 场景 | 工具 | 是否 kill session? |
76
+ |------|------|---------------------|
77
+ | 普通 / 非交互式命令 | shell | - |
78
+ | 一次性交互 CLI(`npm create vite@latest`) | tta | 完成后 **要** |
79
+ | 交互式 TUI(`lazygit`) | tta | 完成后 **要** |
80
+ | 长驻进程 + 观察日志(`npm run dev`) | tta | 观察期间 **不要** |
81
+
82
+ Coding Agent(保留对话上下文)→ 触发内置 [tta-agents](./docs/tta-agents-docs.zh.md) 子 skill。
83
+
84
+ **若用 tta-agents 编排多个 Coding Agent:请清晰告知 Orchestrator 你的权限范围(允许/禁止的操作、目录、是否 deploy 等)。Worker 默认 auto 模式,会把 prompt 当授权执行。** 详见 [tta-agents 文档](./docs/tta-agents-docs.zh.md)。
85
+
86
+ ## API 示例
87
+
88
+ Tip:Be lazy,不要自己动手尝试,让 Agent 来做。
89
+
90
+ ```bash
91
+ # Dev server:保持 session,用 obs 观察
92
+ tta sess start --sess=dev --cmd="npm run dev" --cwd="/path/to/project"
93
+ tta obs screen stable --sess=dev
94
+
95
+ # 一次性交互 CLI:完成后 kill
96
+ tta sess start --sess=vite-once --cmd="npm create vite@latest" --cwd="/path/to/project"
97
+ tta obs screen stable --sess=vite-once
98
+ tta act send key --sess=vite-once --key=enter
99
+ tta obs screen stable --sess=vite-once
100
+ tta sess kill --sess=vite-once
101
+ ```
102
+
103
+ ## API 概览
104
+
105
+ tta 的一切操作都在 **session** 内进行(`--sess=`)。
106
+
107
+ | API | 命令 | 作用 |
108
+ |-----|------|------|
109
+ | **sess** | `start`, `kill`, `killall`, `list`, `keys`, `watch` | 创建、停止、列出 session;人类用 watch UI |
110
+ | **act** | `send text`, `send key` | 向 **运行中** 的 session 发送输入 |
111
+ | **obs** | `screen now`, `screen stable`, `screen scroll` | 读取 session 屏幕 |
112
+
113
+ ```text
114
+ tta sess start -> (tta act ... -> tta obs screen stable)* -> tta sess kill
115
+ ```
116
+
117
+ 失败时输出一行 `error: <reason>`,退出码为 1。
118
+
119
+ 操作细节见 [`skills/tta/SKILL.zh.md`](./skills/tta/SKILL.zh.md)。
120
+
121
+ ## 环境要求
122
+
123
+ - **Node.js** 22.x–26.x(`engines`:`>=22.0.0 <27.0.0`);仓库含 `.nvmrc`(`24`)供本地开发
124
+ - `npm install` 或 `npm install -g` 后,若 npm 对 `node-pty` 提示 allow-scripts,请运行 `npm approve-scripts node-pty` 或 `npm approve-scripts --allow-scripts-pending`,然后重新安装,以便 PTY 原生模块正确安装。
125
+
126
+ ## 开发
127
+
128
+ ```bash
129
+ just dev
130
+ just link # 链接以便全局测试
131
+ just unlink # 测试完成删除链接
132
+ tta sess watch # 打开 http://127.0.0.1:7654 观察
133
+ ```
134
+
135
+ - **后端**(`src/*.ts`):保存 → tsc 重编译 → nodemon 重启 server → 刷新浏览器。
136
+ - **Watch UI**(`src/watch-ui/*`):保存 → 刷新浏览器(开发模式下直接从 `src/` 提供)。
137
+
138
+ ## 许可证
139
+
140
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ /**
38
+ * tta CLI — sess (session lifecycle), act (input), obs (read screen).
39
+ * Options use --name=value syntax.
40
+ */
41
+ const path = __importStar(require("path"));
42
+ const fs = __importStar(require("fs"));
43
+ const commander_1 = require("commander");
44
+ const client_1 = require("./client");
45
+ const server_1 = require("./server");
46
+ const session_1 = require("./session");
47
+ const keys_1 = require("./keys");
48
+ const package_json_1 = require("../package.json");
49
+ const COMMAND_NAME = "tta";
50
+ const TOP_LEVEL_COMMANDS = new Set(["sess", "act", "obs", "help"]);
51
+ const DOCS_URL = "https://github.com/yanggggjie/terminal-tool-for-agents";
52
+ const SCROLL_DIRECTIONS = ["up", "down", "top", "bottom"];
53
+ const MAX_TEXT_INPUT_BYTES = 1024 * 1024;
54
+ const RED = "\x1b[31m";
55
+ const BOLD = "\x1b[1m";
56
+ const RESET = "\x1b[0m";
57
+ function bold(s) {
58
+ return `${BOLD}${s}${RESET}`;
59
+ }
60
+ const HELP_API = `
61
+ ${bold("API")} ${bold("Commands")} ${bold("Example")}
62
+ ${bold("sess")} start, kill, killall, list, keys tta sess start --sess=dev --cmd="npm run dev" --cwd="/path/to/project"
63
+ ${bold("act")} send text, send key tta act send text --sess=dev # stdin (heredoc)
64
+ ${bold("obs")} screen now, stable, scroll tta obs screen stable --sess=dev
65
+
66
+ ${bold("Workflow")}: sess start → (act → obs screen stable)* → sess kill
67
+ ${bold("Watch UI")}: tta sess watch (humans only — agents use obs)
68
+ ${bold("Docs")}: ${DOCS_URL}
69
+ `;
70
+ const program = new commander_1.Command();
71
+ const START_EXAMPLE = 'tta sess start --sess=dev --cmd="npm run dev" --cwd="/path/to/project"';
72
+ function firstPositionalArg(args) {
73
+ for (const a of args) {
74
+ if (!a.startsWith("-"))
75
+ return a;
76
+ }
77
+ return undefined;
78
+ }
79
+ function warnWrongTopLevel(got) {
80
+ process.stderr.write(`${RED}Unknown top-level command "${got}". Use tta sess, tta act, or tta obs.${RESET}\n\n`);
81
+ }
82
+ function printHelp() {
83
+ program.outputHelp();
84
+ }
85
+ program
86
+ .name(COMMAND_NAME)
87
+ .description("Tool for agents to operate interactive CLI, TUI, and agent REPLs via PTY")
88
+ .addHelpText("beforeAll", "tta is short for terminal-tool-for-agents.\n" +
89
+ "Use tta for interactive programs (prompts, TUI, agent CLIs) — not plain bash.\n")
90
+ .addHelpText("afterAll", HELP_API)
91
+ .version(package_json_1.version);
92
+ function formatSessionLine(session) {
93
+ if (session.status === "exited") {
94
+ return `${session.session_name} exited exit_code=${session.exit_code ?? 1}`;
95
+ }
96
+ return `${session.session_name} running`;
97
+ }
98
+ function requireCommandString(cmd) {
99
+ const command = cmd.trim();
100
+ if (!command) {
101
+ replyError(`--cmd= must not be empty. Example: ${START_EXAMPLE}`);
102
+ }
103
+ return command;
104
+ }
105
+ function replySuccess() {
106
+ console.log("success");
107
+ }
108
+ function replyError(message) {
109
+ console.log(`error: ${message}`);
110
+ process.exit(1);
111
+ }
112
+ function requireSession(sess) {
113
+ const err = (0, session_1.validateSessionName)(sess);
114
+ if (err)
115
+ replyError(err);
116
+ return sess;
117
+ }
118
+ function requireScrollDirection(dir) {
119
+ if (SCROLL_DIRECTIONS.includes(dir)) {
120
+ return dir;
121
+ }
122
+ replyError(`--dire= must be one of: ${SCROLL_DIRECTIONS.join(", ")}`);
123
+ }
124
+ function readStdinText() {
125
+ if (process.stdin.isTTY) {
126
+ replyError("Missing text input. Use a quoted heredoc, e.g. tta act send text --sess=dev <<'EOF'\\nhello\\nEOF");
127
+ }
128
+ const data = fs.readFileSync(0, "utf8");
129
+ if (Buffer.byteLength(data, "utf8") > MAX_TEXT_INPUT_BYTES) {
130
+ replyError(`Stdin exceeds ${MAX_TEXT_INPUT_BYTES} byte limit`);
131
+ }
132
+ return data;
133
+ }
134
+ function handleOp(res) {
135
+ if (res.type === "error")
136
+ replyError(res.message);
137
+ replySuccess();
138
+ }
139
+ function handleObs(res) {
140
+ if (res.type === "error")
141
+ replyError(res.message);
142
+ if (res.type !== "screen")
143
+ replyError("expected screen response");
144
+ const screen = res.screen;
145
+ if (screen)
146
+ console.log(screen);
147
+ }
148
+ // --- sess: session lifecycle ---
149
+ const sess = program
150
+ .command("sess")
151
+ .description("Session lifecycle — start, kill, list, watch (stdout: success | error: …, except list/keys/watch)");
152
+ sess
153
+ .command("start")
154
+ .description("Start a session — run an interactive program in a PTY")
155
+ .requiredOption("--sess <name>", "Session name (--sess=dev)")
156
+ .requiredOption("--cmd <command>", 'Command line (--cmd="npm run dev")')
157
+ .requiredOption("--cwd <path>", 'Working directory (--cwd="/path/to/project")')
158
+ .allowExcessArguments(false)
159
+ .action(async (options) => {
160
+ const res = await (0, client_1.sendRequest)({
161
+ type: "start",
162
+ session_name: requireSession(options.sess),
163
+ command: requireCommandString(options.cmd),
164
+ cwd: path.resolve(options.cwd),
165
+ });
166
+ handleOp(res);
167
+ });
168
+ sess
169
+ .command("kill")
170
+ .description("Kill a session")
171
+ .requiredOption("--sess <name>", "Session name (--sess=dev)")
172
+ .action(async (options) => {
173
+ const res = await (0, client_1.sendRequest)({
174
+ type: "kill",
175
+ session_name: requireSession(options.sess),
176
+ });
177
+ handleOp(res);
178
+ });
179
+ sess
180
+ .command("killall")
181
+ .description("Kill all sessions")
182
+ .action(async () => {
183
+ handleOp(await (0, client_1.sendRequest)({ type: "killall" }));
184
+ });
185
+ sess
186
+ .command("list")
187
+ .description("List sessions (running and exited; remove with sess kill)")
188
+ .action(async () => {
189
+ const res = await (0, client_1.sendRequest)({ type: "list" });
190
+ if (res.type === "error")
191
+ replyError(res.message);
192
+ if (res.type !== "list")
193
+ replyError("expected list response");
194
+ if (res.sessions.length === 0) {
195
+ console.log("No sessions");
196
+ return;
197
+ }
198
+ for (const s of res.sessions)
199
+ console.log(formatSessionLine(s));
200
+ });
201
+ sess
202
+ .command("keys")
203
+ .description("List key names for `tta act send key`")
204
+ .action(() => {
205
+ console.log(keys_1.SUPPORTED_KEYS.join(", "));
206
+ });
207
+ sess
208
+ .command("watch")
209
+ .description("Human-only: watch sessions in the browser (read-only)")
210
+ .action(async () => {
211
+ await runWatchServer();
212
+ });
213
+ // --- act: input to a running session ---
214
+ const act = program
215
+ .command("act")
216
+ .description("Send input to a running session (stdout: success | error: …)");
217
+ const send = act.command("send").description("Send text or key input to a session");
218
+ send
219
+ .command("text")
220
+ .description("Type text from stdin (quoted heredoc or pipe)")
221
+ .requiredOption("--sess <name>", "Session name (--sess=dev)")
222
+ .action(async (options) => {
223
+ handleOp(await (0, client_1.sendRequest)({
224
+ type: "send_text",
225
+ session_name: requireSession(options.sess),
226
+ text: readStdinText(),
227
+ }));
228
+ });
229
+ send
230
+ .command("key")
231
+ .description("Press a key (enter, escape, ctrl+c, arrow_up, …)")
232
+ .requiredOption("--sess <name>", "Session name (--sess=dev)")
233
+ .requiredOption("--key <key>", "Key name (--key=enter)")
234
+ .action(async (options) => {
235
+ handleOp(await (0, client_1.sendRequest)({
236
+ type: "send_key",
237
+ session_name: requireSession(options.sess),
238
+ key: options.key,
239
+ }));
240
+ });
241
+ // --- obs: read screen from a running session ---
242
+ const obs = program
243
+ .command("obs")
244
+ .description("Read screen from a session (stdout: screen text | error: …)");
245
+ const screen = obs.command("screen").description("Read terminal screen content");
246
+ screen
247
+ .command("now")
248
+ .description("Print the current screen immediately")
249
+ .requiredOption("--sess <name>", "Session name (--sess=dev)")
250
+ .action(async (options) => {
251
+ handleObs(await (0, client_1.sendRequest)({
252
+ type: "screen_now",
253
+ session_name: requireSession(options.sess),
254
+ }));
255
+ });
256
+ screen
257
+ .command("stable")
258
+ .description("Wait until the screen is stable, then print it")
259
+ .requiredOption("--sess <name>", "Session name (--sess=dev)")
260
+ .action(async (options) => {
261
+ handleObs(await (0, client_1.sendRequest)({
262
+ type: "screen_stable",
263
+ session_name: requireSession(options.sess),
264
+ }));
265
+ });
266
+ screen
267
+ .command("scroll")
268
+ .description("Scroll viewport, then print screen")
269
+ .requiredOption("--sess <name>", "Session name (--sess=dev)")
270
+ .requiredOption("--dire <direction>", "Scroll direction: up, down, top, bottom (--dire=up)")
271
+ .action(async (options) => {
272
+ handleObs(await (0, client_1.sendRequest)({
273
+ type: "screen_scroll",
274
+ session_name: requireSession(options.sess),
275
+ direction: requireScrollDirection(options.dire),
276
+ }));
277
+ });
278
+ async function runWatchServer() {
279
+ if (!process.stdout.isTTY) {
280
+ process.stderr.write("Error: tta sess watch is for human observation only. Agents must not run this command.\n");
281
+ process.exit(1);
282
+ }
283
+ await (0, client_1.ensureServerRunning)();
284
+ const res = await (0, client_1.sendRequest)({ type: "list" });
285
+ if (res.type === "error") {
286
+ process.stderr.write(`Error: ${res.message}\n`);
287
+ process.exit(1);
288
+ }
289
+ process.stderr.write("tta sess watch — read-only session observer (Ctrl+C to exit)\n");
290
+ console.log(server_1.SERVER_URL);
291
+ await new Promise((resolve) => {
292
+ const stop = () => resolve();
293
+ process.on("SIGINT", stop);
294
+ process.on("SIGTERM", stop);
295
+ });
296
+ }
297
+ const argv = process.argv.slice(2);
298
+ if (argv.length === 0) {
299
+ printHelp();
300
+ process.exit(0);
301
+ }
302
+ const top = firstPositionalArg(argv);
303
+ if (top && !TOP_LEVEL_COMMANDS.has(top)) {
304
+ warnWrongTopLevel(top);
305
+ printHelp();
306
+ process.exit(1);
307
+ }
308
+ program.exitOverride();
309
+ program.parseAsync(process.argv).catch((err) => {
310
+ if (err.code?.startsWith("commander.")) {
311
+ printHelp();
312
+ process.exit(1);
313
+ }
314
+ replyError(err.message ?? String(err));
315
+ });
316
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Request, Response } from "./protocol";
2
+ export declare function ensureServerRunning(): Promise<void>;
3
+ export declare function sendRequest(req: Request): Promise<Response>;
4
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAc/C,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAazD;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAWjE"}