@robota-sdk/agent-cli 3.0.0-beta.6 → 3.0.0-beta.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,11 @@
1
1
  # @robota-sdk/agent-cli
2
2
 
3
- AI coding assistant CLI built on Robota SDK. Loads AGENTS.md/CLAUDE.md for project context and provides tool-calling REPL with Claude Code-compatible permission modes.
3
+ AI coding assistant CLI built on Robota SDK. Loads AGENTS.md/CLAUDE.md for project context and provides a tool-calling REPL with Claude Code-compatible permission modes.
4
4
 
5
5
  ## Installation
6
6
 
7
+ Requires Node.js 22+.
8
+
7
9
  ```bash
8
10
  # Global install
9
11
  npm install -g @robota-sdk/agent-cli
@@ -12,6 +14,8 @@ npm install -g @robota-sdk/agent-cli
12
14
  npx @robota-sdk/agent-cli
13
15
  ```
14
16
 
17
+ > **macOS users**: Korean/CJK IME input may crash macOS Terminal.app. Use **[iTerm2](https://iterm2.com/)** instead. This is a known Ink + Terminal.app issue shared with Claude Code.
18
+
15
19
  After installing globally, the `robota` command is available system-wide:
16
20
 
17
21
  ```bash
@@ -22,9 +26,11 @@ robota -p "List all files" # Print mode (one-shot, exit after response)
22
26
 
23
27
  ### Environment Variables
24
28
 
25
- | Variable | Description | Required |
26
- | ------------------- | ----------------- | -------- |
27
- | `ANTHROPIC_API_KEY` | Anthropic API key | Yes |
29
+ | Variable | Description | Required |
30
+ | ------------------- | ---------------------------------------------- | -------------- |
31
+ | `ANTHROPIC_API_KEY` | Anthropic API key for the `anthropic` provider | Anthropic only |
32
+ | `DEEPSEEK_API_KEY` | DeepSeek API key for the `deepseek` provider | DeepSeek only |
33
+ | `DASHSCOPE_API_KEY` | Alibaba Cloud Model Studio key for `qwen` | Qwen only |
28
34
 
29
35
  Set your key before running:
30
36
 
@@ -35,11 +41,7 @@ export ANTHROPIC_API_KEY=sk-ant-...
35
41
  ## Development Setup (Monorepo)
36
42
 
37
43
  ```bash
38
- # 1. Copy .env.example and add your Anthropic API key
39
- cp packages/agent-cli/.env.example packages/agent-cli/.env
40
- # Edit .env and set ANTHROPIC_API_KEY=sk-ant-...
41
-
42
- # 2. Build dependencies and CLI
44
+ # Build dependencies and CLI
43
45
  pnpm build:deps
44
46
  pnpm --filter @robota-sdk/agent-cli build
45
47
  ```
@@ -50,7 +52,7 @@ pnpm --filter @robota-sdk/agent-cli build
50
52
  # From monorepo root
51
53
  cd packages/agent-cli
52
54
 
53
- # Development mode (no build needed, auto-loads .env)
55
+ # Development mode (no build needed)
54
56
  pnpm dev
55
57
 
56
58
  # Production mode (requires build)
@@ -71,73 +73,126 @@ robota -p "prompt" # Print mode (one-shot, exit after response)
71
73
  robota -c # Continue last session
72
74
  robota -r <session-id> # Resume session by ID
73
75
  robota --model <model> # Model override (e.g., claude-sonnet-4-6)
76
+ robota --language <lang> # Response language (ko, en, ja, zh)
74
77
  robota --permission-mode <mode> # plan | default | acceptEdits | bypassPermissions
75
78
  robota --max-turns <n> # Limit agentic turns per interaction
79
+ robota --output-format <fmt> # text | json | stream-json (print mode)
80
+ robota --system-prompt <text> # Replace system prompt (print mode)
81
+ robota --append-system-prompt <text> # Append to system prompt (print mode)
82
+ robota --reset # Delete user settings and exit
83
+ robota --check-update # Check npm for a newer CLI version and exit
84
+ robota --disable-update-check # Skip interactive startup update check for this run
76
85
  robota --version # Show version
77
86
  ```
78
87
 
79
- ## Built-in Tools
88
+ ### CLI Updates
80
89
 
81
- The CLI provides 6 tools that the AI agent can invoke:
90
+ Robota can check npm for a newer `@robota-sdk/agent-cli` version:
82
91
 
83
- | Tool | Description | Primary Argument |
84
- | ------- | ------------------------------------ | ---------------- |
85
- | `Bash` | Execute shell commands | `command` |
86
- | `Read` | Read file contents with line numbers | `filePath` |
87
- | `Write` | Write content to a file | `filePath` |
88
- | `Edit` | Replace a string in a file | `filePath` |
89
- | `Glob` | Find files matching a pattern | `pattern` |
90
- | `Grep` | Search file contents with regex | `pattern` |
92
+ ```bash
93
+ robota --check-update
94
+ ```
91
95
 
92
- ## Permission System
96
+ When an update is available, Robota prints the npm global install command:
93
97
 
94
- Every tool call passes through a three-step permission gate before execution:
98
+ ```bash
99
+ npm install -g '@robota-sdk/agent-cli@latest'
100
+ ```
95
101
 
96
- 1. **Deny list** if any deny pattern matches, the action is blocked immediately
97
- 2. **Allow list** — if any allow pattern matches, the action is auto-approved
98
- 3. **Mode policy** — the active permission mode determines the decision
102
+ Robota does not implement its own updater and does not modify `~/.robota/settings.json` for update checks. Interactive startup checks use a user-level operational cache at `~/.robota/update-check.json` and can be skipped for one run with `--disable-update-check`. Print/headless mode (`robota -p`) does not perform automatic startup update checks so scripted stdout and stderr remain deterministic.
99
103
 
100
- When a tool requires approval, the user sees an interactive prompt:
104
+ ### Print Mode Output Formats
101
105
 
102
- ```
103
- [Permission Required] Tool: Bash
104
- Arguments: command: rm -rf dist
105
- Allow? [y/N]
106
+ Print mode (`-p`) supports three output formats via `--output-format`:
107
+
108
+ | Format | Description |
109
+ | ------------- | ------------------------------------------------------------------ |
110
+ | `text` | Plain text response to stdout (default) |
111
+ | `json` | Single JSON object: `{ type, result, session_id, subtype }` |
112
+ | `stream-json` | Newline-delimited JSON with `content_block_delta` streaming events |
113
+
114
+ ### Stdin Pipe
115
+
116
+ When `-p` is used without a positional argument and stdin is piped, the CLI reads from stdin:
117
+
118
+ ```bash
119
+ echo "Explain this error" | robota -p
120
+ cat file.ts | robota -p "Review this code" --output-format json
121
+ git diff | robota -p "Summarize changes" --output-format stream-json
106
122
  ```
107
123
 
108
- - Type `y` or `yes` to approve
109
- - Press Enter or type anything else to deny
124
+ ## First-Run Setup
110
125
 
111
- If denied, the AI agent receives a "Permission denied" error and can adjust its approach.
126
+ When no usable settings file exists, the CLI prompts for:
112
127
 
113
- ### Permission Modes
128
+ 1. **Provider selection** from the providers assembled into the CLI binary
129
+ 2. **Provider-specific setup fields** such as model, base URL, and masked API key
130
+ 3. **Response language** (ko/en/ja/zh, default: en)
114
131
 
115
- | Mode | Alias | Read/Glob/Grep | Write/Edit | Bash |
116
- | ------------------- | -------- | :------------: | :--------: | :-----: |
117
- | `plan` | safe | auto | deny | deny |
118
- | `default` | moderate | auto | approve | approve |
119
- | `acceptEdits` | full | auto | auto | approve |
120
- | `bypassPermissions` | — | auto | auto | auto |
132
+ Creates `~/.robota/settings.json`. Use `robota --reset` to return to first-run state.
121
133
 
122
- - **auto** tool executes without prompting
123
- - **approve** user is prompted to allow or deny
124
- - **deny** — tool is blocked silently (no prompt shown)
134
+ Provider setup is generated from provider definitions. The default CLI build includes Anthropic,
135
+ OpenAI-compatible, DeepSeek, Gemma, and Qwen providers; other embeddings can inject their own
136
+ provider definitions.
137
+ Interactive setup creates a readable profile key from the selected model id, such as
138
+ `claude-sonnet-4-6` or `gpt-4o`, and appends `-2`, `-3`, etc. when that key already exists. Generated
139
+ profile keys never include API keys or credential hints.
125
140
 
126
- Unknown tools default to `approve` in most modes, `deny` in `plan` mode.
141
+ Inside the TUI, `/provider` and `/provider list` show configured profiles as an interactive picker. Selecting a profile opens command-owned actions for switch, edit, test, duplicate, delete, and cancel. Headless mode prints the same profile list text without opening prompts.
127
142
 
128
- ### Changing Mode at Runtime
143
+ Non-interactive/headless mode never prompts. Configure a provider ahead of time with `robota --configure` in an interactive terminal, or use `robota --configure-provider <profile> --type <type> ... --set-current`.
144
+
145
+ ## Built-in Tools
129
146
 
130
- Use the `/mode` slash command in the REPL:
147
+ The AI agent can invoke 8 local tools:
148
+
149
+ | Tool | Description | Primary Argument |
150
+ | ----------- | ------------------------------------ | ---------------- |
151
+ | `Bash` | Execute shell commands | `command` |
152
+ | `Read` | Read file contents with line numbers | `filePath` |
153
+ | `Write` | Write content to a file | `filePath` |
154
+ | `Edit` | Replace a string in a file | `filePath` |
155
+ | `Glob` | Find files matching a pattern | `pattern` |
156
+ | `Grep` | Search file contents with regex | `pattern` |
157
+ | `WebFetch` | Fetch URL content as text | `url` |
158
+ | `WebSearch` | Search the internet | `query` |
159
+
160
+ ## Recent TUI Capabilities
161
+
162
+ - Provider setup and profile management are generated from provider definitions, so the default CLI
163
+ build can configure, switch, edit, test, duplicate, and delete Anthropic, OpenAI-compatible,
164
+ DeepSeek, Gemma, and Qwen profiles without provider-specific UI branches.
165
+ - Interactive startup can check npm for newer CLI versions; print/headless mode skips startup update checks to keep scripted output deterministic.
166
+ - Long-running sessions show provider usage summaries, status activity, background job tree rows, and collapsed command-output transcripts.
167
+ - Edit results render as context hunks with markdown-friendly diff blocks.
168
+ - Background subagents are real runtime jobs with transcripts and resumable task snapshots.
169
+ - Explicit multi-agent requests use the `/agent` command module batch path through the SDK runtime.
131
170
 
132
- ```
133
- > /mode # Show current mode
134
- Current permission mode: default
171
+ ## Permission System
172
+
173
+ Every tool call passes through a three-step permission gate:
174
+
175
+ 1. **Deny list** — if any deny pattern matches, the action is blocked
176
+ 2. **Allow list** — if any allow pattern matches, the action is auto-approved
177
+ 3. **Mode policy** — the active permission mode determines the decision
178
+
179
+ ### Permission Modes
180
+
181
+ | Mode | Read/Glob/Grep | Write/Edit | Bash |
182
+ | ------------------- | :------------: | :--------: | :-----: |
183
+ | `plan` | auto | deny | deny |
184
+ | `default` | auto | approve | approve |
185
+ | `acceptEdits` | auto | auto | approve |
186
+ | `bypassPermissions` | auto | auto | auto |
135
187
 
136
- > /mode plan # Switch to plan (read-only)
137
- Permission mode set to: plan
188
+ ### Changing Mode at Runtime
189
+
190
+ Use the `/permissions` slash command:
138
191
 
139
- > /mode bypassPermissions # Skip all prompts
140
- Permission mode set to: bypassPermissions
192
+ ```
193
+ > /permissions # Show current mode and session-approved tools
194
+ > /permissions plan # Switch to plan (read-only)
195
+ > /permissions bypassPermissions # Skip all prompts
141
196
  ```
142
197
 
143
198
  Or set it at startup:
@@ -146,7 +201,7 @@ Or set it at startup:
146
201
  robota --permission-mode plan
147
202
  ```
148
203
 
149
- ### Permission Patterns (allow/deny lists)
204
+ ### Permission Patterns
150
205
 
151
206
  Configure in `.robota/settings.json` or `.robota/settings.local.json`:
152
207
 
@@ -159,42 +214,140 @@ Configure in `.robota/settings.json` or `.robota/settings.local.json`:
159
214
  }
160
215
  ```
161
216
 
162
- **Pattern syntax:**
217
+ Pattern syntax: `ToolName` matches any invocation; `ToolName(pattern)` matches on the primary argument with shell-style globs (`*`, `**`).
218
+
219
+ ## Keyboard Controls
220
+
221
+ | Key | Action |
222
+ | ---------- | ----------------------------------------------------------- |
223
+ | Enter | Submit input |
224
+ | ESC | Abort current execution (graceful — saves partial response) |
225
+ | Ctrl+C | Exit process immediately |
226
+ | Up/Down | Navigate visual lines in wrapped multi-line input |
227
+ | Arrow keys | Navigate slash command autocomplete, permission prompt |
163
228
 
164
- - `ToolName` — match any invocation of that tool (e.g., `Bash`)
165
- - `ToolName(pattern)` — match when the primary argument matches the glob (e.g., `Bash(pnpm *)`)
166
- - `*` — zero or more characters (shell-style)
167
- - `**` — one or more characters (recursive path matching)
229
+ ## Paste Handling
168
230
 
169
- **Evaluation order:** deny patterns are checked first, then allow patterns, then the mode policy. Deny always wins.
231
+ Bracketed paste mode (DECSET 2004) is enabled on startup. When pasting multiline text, the input area collapses it into a label: `[Pasted text #1 +42 lines]`. Multiple pastes are numbered sequentially. The full content is expanded on submit.
232
+
233
+ Single-line paste is inserted directly as typed text. Terminals without bracketed paste fall back to heuristic detection.
234
+
235
+ ## Edit Diff Display
236
+
237
+ After the Edit tool runs, a `DiffBlock` component renders the change inline:
238
+
239
+ ```
240
+ ✓ Edit(src/provider.ts)
241
+ │ src/provider.ts
242
+ │ - const DEFAULT_MAX_TOKENS = 4096;
243
+ │ + const maxTokens = getModelMaxOutput(modelId);
244
+ ```
245
+
246
+ Removed lines appear in red with `-`, added lines in green with `+`. Diffs longer than 10 lines show the first 8 + a `... and N more lines` summary.
247
+
248
+ ## Session Management
249
+
250
+ The CLI supports continuing, resuming, forking, and naming sessions.
251
+
252
+ ### CLI Flags
253
+
254
+ | Flag | Description |
255
+ | --------------------- | ------------------------------------------------ |
256
+ | `-c`, `--continue` | Continue the most recent session |
257
+ | `-r`, `--resume <id>` | Resume a specific session by ID |
258
+ | `--fork-session <id>` | Fork a session (new session with copied history) |
259
+ | `--name <name>` | Assign a name to the session at startup |
260
+
261
+ ### TUI Commands
262
+
263
+ | Command | Description |
264
+ | ---------------- | ----------------------------------- |
265
+ | `/resume` | List recent sessions and resume one |
266
+ | `/rename <name>` | Rename the current session |
267
+
268
+ ### Session Name Display
269
+
270
+ When a session has a name, it appears in three places:
271
+
272
+ - **Input border** — session name shown in the input area border
273
+ - **Terminal title** — updated via ANSI escape sequences
274
+ - **StatusBar** — displayed alongside activity, model, and context usage
170
275
 
171
276
  ## Slash Commands
172
277
 
173
- | Command | Description |
174
- | -------------- | ------------------------------- |
175
- | `/help` | Show help |
176
- | `/clear` | Clear conversation history |
177
- | `/mode [mode]` | Show or change permission mode |
178
- | `/resume` | List and resume a saved session |
179
- | `/cost` | Show token usage |
180
- | `/model` | Show current model |
181
- | `/exit` | Exit CLI |
278
+ | Command | Description |
279
+ | ------------------------- | ---------------------------------------------------------------------- |
280
+ | `/help` | Show available commands |
281
+ | `/clear` | Clear conversation history |
282
+ | `/model [model]` | Select AI model (confirmation prompt, CLI restarts) |
283
+ | `/language [lang]` | Set response language (ko, en, ja, zh), saves and restarts |
284
+ | `/compact [instructions]` | Compress context window |
285
+ | `/cost` | Show session info |
286
+ | `/context` | Context window details, reference inventory, and auto-compact controls |
287
+ | `/agent` | Run and manage background subagent jobs |
288
+ | `/permissions [mode]` | Show permission rules or change permission mode |
289
+ | `/plugin [subcommand]` | Plugin management |
290
+ | `/resume` | List recent sessions and resume one |
291
+ | `/rename <name>` | Rename the current session |
292
+ | `/exit` | Exit CLI |
293
+
294
+ Typing `/` triggers an autocomplete popup with arrow-key navigation and Esc to dismiss. Tab inserts the highlighted command into the input field without executing — continue typing args or press Enter to execute. Enter selects and executes immediately. Commands with subcommands (e.g., `/permissions`, `/model`) show a nested submenu. Skill commands discovered from `.agents/skills/` and `.claude/commands/` appear alongside built-in commands.
295
+
296
+ ## Plugin Management
297
+
298
+ The `/plugin` command opens an interactive TUI or runs plugin operations through the injected plugin command module:
299
+
300
+ | Subcommand | Description |
301
+ | ---------------------------------------- | ------------------------------------- |
302
+ | `/plugin` or `/plugin manage` | Open the plugin manager TUI |
303
+ | `/plugin install <name>@<marketplace>` | Install a plugin from a marketplace |
304
+ | `/plugin uninstall <name>@<marketplace>` | Remove an installed plugin |
305
+ | `/plugin enable <name>@<marketplace>` | Enable a disabled plugin |
306
+ | `/plugin disable <name>@<marketplace>` | Disable a plugin without uninstalling |
307
+ | `/plugin marketplace add <source>` | Add a marketplace source |
308
+ | `/plugin marketplace remove <name>` | Remove a marketplace source |
309
+ | `/plugin marketplace update <name>` | Update a marketplace source |
310
+ | `/plugin marketplace list` | List configured marketplace sources |
182
311
 
183
312
  ## Configuration
184
313
 
185
- Settings are loaded from (highest priority first):
314
+ Settings are merged in this order, from lowest to highest priority:
186
315
 
187
- 1. `.robota/settings.local.json` (local, gitignored)
188
- 2. `.robota/settings.json` (project, shared)
189
- 3. `~/.robota/settings.json` (user global)
316
+ 1. `~/.robota/settings.json` (user global)
317
+ 2. `~/.claude/settings.json` (user global, Claude Code compatible)
318
+ 3. `.robota/settings.json` (project, shared)
319
+ 4. `.robota/settings.local.json` (local, gitignored)
320
+ 5. `.claude/settings.json` (project, Claude Code compatible)
321
+ 6. `.claude/settings.local.json` (local, gitignored, Claude Code compatible)
190
322
 
191
323
  ```json
192
324
  {
193
325
  "defaultMode": "default",
194
- "provider": {
195
- "name": "anthropic",
196
- "model": "claude-sonnet-4-6",
197
- "apiKey": "$ENV:ANTHROPIC_API_KEY"
326
+ "language": "en",
327
+ "currentProvider": "qwen-plus",
328
+ "providers": {
329
+ "qwen-plus": {
330
+ "type": "qwen",
331
+ "model": "qwen-plus",
332
+ "apiKey": "$ENV:DASHSCOPE_API_KEY",
333
+ "baseURL": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
334
+ },
335
+ "supergemma4-26b-uncensored-v2": {
336
+ "type": "gemma",
337
+ "model": "supergemma4-26b-uncensored-v2",
338
+ "apiKey": "lm-studio",
339
+ "baseURL": "http://localhost:1234/v1"
340
+ },
341
+ "gpt-4o": {
342
+ "type": "openai",
343
+ "model": "gpt-4o",
344
+ "apiKey": "$ENV:OPENAI_API_KEY"
345
+ },
346
+ "claude-sonnet-4-6": {
347
+ "type": "anthropic",
348
+ "model": "claude-sonnet-4-6",
349
+ "apiKey": "$ENV:ANTHROPIC_API_KEY"
350
+ }
198
351
  },
199
352
  "permissions": {
200
353
  "allow": ["Bash(pnpm *)"],
@@ -203,13 +356,27 @@ Settings are loaded from (highest priority first):
203
356
  }
204
357
  ```
205
358
 
206
- ### Environment Variables
207
-
208
- | Variable | Description | Required |
209
- | ------------------- | ----------------- | -------- |
210
- | `ANTHROPIC_API_KEY` | Anthropic API key | Yes |
359
+ `currentProvider` selects a profile key from `providers`. The key is the stable profile identity, not
360
+ the provider type; multiple profile keys may use the same provider type and model when they represent
361
+ different credentials, endpoints, accounts, or operational defaults. Qwen Model Studio profiles use
362
+ `type: "qwen"` with a DashScope-compatible `baseURL`; the API key is usually stored as
363
+ `$ENV:DASHSCOPE_API_KEY`. DeepSeek profiles use `type: "deepseek"` with
364
+ `https://api.deepseek.com` and `$ENV:DEEPSEEK_API_KEY`. Gemma-family LM Studio models use
365
+ `type: "gemma"` so Robota can apply Gemma-specific channel-marker projection while still talking to
366
+ the OpenAI-compatible `/v1/chat/completions` API through `baseURL`. Generic OpenAI-compatible profiles use
367
+ `type: "openai"` and do not apply provider-specific projection. Use `--provider <profile>` for a
368
+ one-shot invocation override; add `--set-current` only when the selected profile should become the
369
+ persisted default. The legacy single-provider shape remains supported:
211
370
 
212
- Copy `.env.example` to `.env` and set your key. The CLI reads `.env` automatically in dev mode.
371
+ ```json
372
+ {
373
+ "provider": {
374
+ "name": "anthropic",
375
+ "model": "claude-sonnet-4-6",
376
+ "apiKey": "$ENV:ANTHROPIC_API_KEY"
377
+ }
378
+ }
379
+ ```
213
380
 
214
381
  ## Context Discovery
215
382
 
@@ -219,36 +386,73 @@ The CLI automatically discovers and loads:
219
386
  - **CLAUDE.md** — same walk-up discovery
220
387
  - **Project metadata** — from `package.json`, `tsconfig.json`
221
388
 
222
- All context is assembled into the system prompt for the AI assistant.
389
+ All context is assembled into the system prompt.
390
+
391
+ Ordinary prompts may also reference workspace-local files with path-like `@file` tokens, for
392
+ example `@AGENTS.md` or `@docs/SPEC.md`. The CLI passes those prompts through unchanged; the SDK
393
+ resolves bounded file content under the active `cwd`, sends the enriched prompt to the model, and
394
+ records a structured file-reference event in the session history.
395
+
396
+ ## Memory Management
397
+
398
+ - **Message windowing** — React state keeps the most recent 100 messages. Older messages are dropped from the render tree; full history remains in the session store.
399
+ - **Tool state cleanup** — Completed tool execution states are trimmed to the most recent 50 entries.
400
+ - **React.memo** — `MessageItem` uses `React.memo` to skip redundant re-renders.
401
+
402
+ ## Session Logging
403
+
404
+ Session logs are written to `.robota/logs/{sessionId}.jsonl` in JSONL format by default, capturing structured events for diagnostics and replay. Background task lifecycle/progress events are logged there as they happen. Child-process subagents also write append-only transcripts to `.robota/logs/{sessionId}/subagents/{agentId}.jsonl`, including streaming text deltas while the local provider request is still running.
405
+
406
+ Resumable session JSON is written to `.robota/sessions/{sessionId}.json` for the current project and includes messages, UI history, the exact system prompt, registered tool schemas, and background task snapshots. High-frequency streaming chunks stay in JSONL transcript files; the session JSON stores task state and transcript paths.
223
407
 
224
408
  ## Architecture
225
409
 
410
+ The CLI is a pure TUI layer. All business logic lives in `@robota-sdk/agent-sdk`'s `InteractiveSession`. `useInteractiveSession` is the sole React↔SDK bridge, converting SDK events to React state.
411
+
226
412
  ```
227
- bin.ts → cli.ts (parseArgs, load config/context, create Session)
228
- ├── config/config-loader.ts — settings file discovery + Zod validation
229
- ├── context/context-loader.ts AGENTS.md/CLAUDE.md walk-up discovery
230
- ├── context/project-detector.ts — package.json/tsconfig detection
231
- ├── context/system-prompt-builder.ts system message assembly
232
- ├── session.ts — Robota agent wrapper + permission enforcement
233
- └── permissions/
234
- ├── permission-gate.ts — 3-step evaluation (deny allow → mode)
235
- ├── permission-mode.ts mode × tool policy matrix
236
- └── permission-prompt.ts — interactive [y/N] prompt
237
- ├── tools/ — 6 built-in tools (Bash, Read, Write, Edit, Glob, Grep)
238
- ├── session-store.ts — JSON file-based session persistence
239
- └── ui/ — Ink TUI components (App, MessageList, InputArea, etc.)
413
+ bin.ts → cli.ts (arg parsing)
414
+ └── ui/render.tsx App.tsx (thin JSX shell)
415
+ ├── useInteractiveSession (ONLY React↔SDK bridge)
416
+ ├── InteractiveSession (SDK)
417
+ ├── CommandRegistry (SDK, re-exported by CLI)
418
+ │ │ ├── BuiltinCommandSource (SDK, empty by default)
419
+ │ ├── agent-command-skills (/skills command + virtual skill aliases)
420
+ ├── PluginCommandSource (SDK, plugin skills)
421
+ │ └── ICommandModule sources (/help, /compact, ...)
422
+ └── SystemCommandExecutor (SDK)
423
+ ├── plugin-hooks-merger.ts (merges plugin hooks into SDK config)
424
+ ├── MessageList.tsx
425
+ ├── InputArea.tsx (CjkTextInput, bracketed paste, slash detection)
426
+ ├── StatusBar.tsx (activity, conditional mode, model, context %)
427
+ ├── PermissionPrompt.tsx (arrow-key Allow/Deny)
428
+ ├── SlashAutocomplete.tsx (command popup with scroll)
429
+ ├── DiffBlock.tsx (Edit tool diff display)
430
+ ├── MenuSelect.tsx (arrow-key menu, Plugin TUI)
431
+ ├── PluginTUI.tsx (plugin management screen stack)
432
+ ├── TextPrompt.tsx (text input for Plugin TUI)
433
+ └── ConfirmPrompt.tsx (reusable yes/no prompt)
240
434
  ```
241
435
 
242
- Tool calls flow through the permission system:
436
+ ## Dependencies
243
437
 
244
- ```
245
- AI agent requests tool call
246
- Session.wrapToolWithPermission() intercepts execute()
247
- evaluatePermission(toolName, args, mode, allow/deny lists)
248
- deny list match? blocked
249
- allow list match? auto-approved
250
- mode policy lookup auto | approve | deny
251
- if 'approve': promptForApproval() → user types y/N
252
- if allowed: original tool.execute() runs
253
- if denied: returns error result to AI agent
254
- ```
438
+ | Package | Purpose |
439
+ | -------------------------------------- | ------------------------------------------ |
440
+ | `@robota-sdk/agent-sdk` | Session factory, query, config, context |
441
+ | `@robota-sdk/agent-core` | Types (TPermissionMode, TToolArgs) |
442
+ | `@robota-sdk/agent-transport-headless` | Headless runner for print mode (`-p`) |
443
+ | `ink` 7, `react` 19.2+ | TUI rendering |
444
+ | `ink-select-input` | Arrow-key selection (permission prompt) |
445
+ | `ink-spinner` | Loading spinner |
446
+ | `chalk` | Terminal colors |
447
+ | `ink-text-input` | Base text input (extended by CjkTextInput) |
448
+ | `marked`, `marked-terminal` | Markdown parsing and terminal rendering |
449
+ | `cli-highlight` | Syntax highlighting for code blocks |
450
+ | `string-width` | Unicode-aware string width (CJK support) |
451
+
452
+ ## Documentation
453
+
454
+ See [docs/SPEC.md](./docs/SPEC.md) for the full specification, architecture details, and design decisions.
455
+
456
+ ## License
457
+
458
+ MIT
package/dist/node/bin.js CHANGED
@@ -1,9 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startCli
4
- } from "./chunk-4DYVT4WI.js";
4
+ } from "./chunk-J654S773.js";
5
+ import "./chunk-BENOH47A.js";
5
6
 
6
7
  // src/bin.ts
8
+ process.on("uncaughtException", (err) => {
9
+ const msg = err.message ?? "";
10
+ const isLikelyIME = msg.includes("string-width") || msg.includes("setCursorPosition") || msg.includes("getStringWidth") || msg.includes("slice") || msg.includes("charCodeAt");
11
+ if (isLikelyIME) {
12
+ process.stderr.write(`[robota] IME error suppressed: ${msg}
13
+ `);
14
+ return;
15
+ }
16
+ throw err;
17
+ });
7
18
  startCli().catch((err) => {
8
19
  const message = err instanceof Error ? err.message : String(err);
9
20
  process.stderr.write(message + "\n");