@robota-sdk/agent-cli 3.0.0-beta.5 → 3.0.0-beta.51

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,6 +1,8 @@
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
+
5
+ **Version**: 3.0.0-beta.40
4
6
 
5
7
  ## Installation
6
8
 
@@ -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
@@ -71,14 +75,48 @@ robota -p "prompt" # Print mode (one-shot, exit after response)
71
75
  robota -c # Continue last session
72
76
  robota -r <session-id> # Resume session by ID
73
77
  robota --model <model> # Model override (e.g., claude-sonnet-4-6)
78
+ robota --language <lang> # Response language (ko, en, ja, zh)
74
79
  robota --permission-mode <mode> # plan | default | acceptEdits | bypassPermissions
75
80
  robota --max-turns <n> # Limit agentic turns per interaction
81
+ robota --output-format <fmt> # text | json | stream-json (print mode)
82
+ robota --system-prompt <text> # Replace system prompt (print mode)
83
+ robota --append-system-prompt <text> # Append to system prompt (print mode)
84
+ robota --reset # Delete user settings and exit
76
85
  robota --version # Show version
77
86
  ```
78
87
 
88
+ ### Print Mode Output Formats
89
+
90
+ Print mode (`-p`) supports three output formats via `--output-format`:
91
+
92
+ | Format | Description |
93
+ | ------------- | ------------------------------------------------------------------ |
94
+ | `text` | Plain text response to stdout (default) |
95
+ | `json` | Single JSON object: `{ type, result, session_id, subtype }` |
96
+ | `stream-json` | Newline-delimited JSON with `content_block_delta` streaming events |
97
+
98
+ ### Stdin Pipe
99
+
100
+ When `-p` is used without a positional argument and stdin is piped, the CLI reads from stdin:
101
+
102
+ ```bash
103
+ echo "Explain this error" | robota -p
104
+ cat file.ts | robota -p "Review this code" --output-format json
105
+ git diff | robota -p "Summarize changes" --output-format stream-json
106
+ ```
107
+
108
+ ## First-Run Setup
109
+
110
+ When no settings file exists, the CLI prompts for:
111
+
112
+ 1. **Anthropic API key** (input masked with asterisks)
113
+ 2. **Response language** (ko/en/ja/zh, default: en)
114
+
115
+ Creates `~/.robota/settings.json`. Use `robota --reset` to return to first-run state.
116
+
79
117
  ## Built-in Tools
80
118
 
81
- The CLI provides 6 tools that the AI agent can invoke:
119
+ The AI agent can invoke 6 tools:
82
120
 
83
121
  | Tool | Description | Primary Argument |
84
122
  | ------- | ------------------------------------ | ---------------- |
@@ -91,53 +129,29 @@ The CLI provides 6 tools that the AI agent can invoke:
91
129
 
92
130
  ## Permission System
93
131
 
94
- Every tool call passes through a three-step permission gate before execution:
132
+ Every tool call passes through a three-step permission gate:
95
133
 
96
- 1. **Deny list** — if any deny pattern matches, the action is blocked immediately
134
+ 1. **Deny list** — if any deny pattern matches, the action is blocked
97
135
  2. **Allow list** — if any allow pattern matches, the action is auto-approved
98
136
  3. **Mode policy** — the active permission mode determines the decision
99
137
 
100
- When a tool requires approval, the user sees an interactive prompt:
101
-
102
- ```
103
- [Permission Required] Tool: Bash
104
- Arguments: command: rm -rf dist
105
- Allow? [y/N]
106
- ```
107
-
108
- - Type `y` or `yes` to approve
109
- - Press Enter or type anything else to deny
110
-
111
- If denied, the AI agent receives a "Permission denied" error and can adjust its approach.
112
-
113
138
  ### Permission Modes
114
139
 
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 |
121
-
122
- - **auto** — tool executes without prompting
123
- - **approve** — user is prompted to allow or deny
124
- - **deny** — tool is blocked silently (no prompt shown)
125
-
126
- Unknown tools default to `approve` in most modes, `deny` in `plan` mode.
140
+ | Mode | Read/Glob/Grep | Write/Edit | Bash |
141
+ | ------------------- | :------------: | :--------: | :-----: |
142
+ | `plan` | auto | deny | deny |
143
+ | `default` | auto | approve | approve |
144
+ | `acceptEdits` | auto | auto | approve |
145
+ | `bypassPermissions` | auto | auto | auto |
127
146
 
128
147
  ### Changing Mode at Runtime
129
148
 
130
- Use the `/mode` slash command in the REPL:
149
+ Use the `/mode` slash command:
131
150
 
132
151
  ```
133
152
  > /mode # Show current mode
134
- Current permission mode: default
135
-
136
153
  > /mode plan # Switch to plan (read-only)
137
- Permission mode set to: plan
138
-
139
154
  > /mode bypassPermissions # Skip all prompts
140
- Permission mode set to: bypassPermissions
141
155
  ```
142
156
 
143
157
  Or set it at startup:
@@ -146,7 +160,7 @@ Or set it at startup:
146
160
  robota --permission-mode plan
147
161
  ```
148
162
 
149
- ### Permission Patterns (allow/deny lists)
163
+ ### Permission Patterns
150
164
 
151
165
  Configure in `.robota/settings.json` or `.robota/settings.local.json`:
152
166
 
@@ -159,26 +173,97 @@ Configure in `.robota/settings.json` or `.robota/settings.local.json`:
159
173
  }
160
174
  ```
161
175
 
162
- **Pattern syntax:**
176
+ Pattern syntax: `ToolName` matches any invocation; `ToolName(pattern)` matches on the primary argument with shell-style globs (`*`, `**`).
177
+
178
+ ## Keyboard Controls
179
+
180
+ | Key | Action |
181
+ | ---------- | ----------------------------------------------------------- |
182
+ | Enter | Submit input |
183
+ | ESC | Abort current execution (graceful — saves partial response) |
184
+ | Ctrl+C | Exit process immediately |
185
+ | Up/Down | Navigate visual lines in wrapped multi-line input |
186
+ | Arrow keys | Navigate slash command autocomplete, permission prompt |
187
+
188
+ ## Paste Handling
189
+
190
+ 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.
191
+
192
+ Single-line paste is inserted directly as typed text. Terminals without bracketed paste fall back to heuristic detection.
193
+
194
+ ## Edit Diff Display
195
+
196
+ After the Edit tool runs, a `DiffBlock` component renders the change inline:
197
+
198
+ ```
199
+ ✓ Edit(src/provider.ts)
200
+ │ src/provider.ts
201
+ │ - const DEFAULT_MAX_TOKENS = 4096;
202
+ │ + const maxTokens = getModelMaxOutput(modelId);
203
+ ```
204
+
205
+ 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.
206
+
207
+ ## Session Management
208
+
209
+ The CLI supports continuing, resuming, forking, and naming sessions.
210
+
211
+ ### CLI Flags
163
212
 
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)
213
+ | Flag | Description |
214
+ | --------------------- | ------------------------------------------------ |
215
+ | `-c`, `--continue` | Continue the most recent session |
216
+ | `-r`, `--resume <id>` | Resume a specific session by ID |
217
+ | `--fork-session <id>` | Fork a session (new session with copied history) |
218
+ | `--name <name>` | Assign a name to the session at startup |
168
219
 
169
- **Evaluation order:** deny patterns are checked first, then allow patterns, then the mode policy. Deny always wins.
220
+ ### TUI Commands
221
+
222
+ | Command | Description |
223
+ | ---------------- | ----------------------------------- |
224
+ | `/resume` | List recent sessions and resume one |
225
+ | `/rename <name>` | Rename the current session |
226
+
227
+ ### Session Name Display
228
+
229
+ When a session has a name, it appears in three places:
230
+
231
+ - **Input border** — session name shown in the input area border
232
+ - **Terminal title** — updated via ANSI escape sequences
233
+ - **StatusBar** — displayed alongside mode, model, and context usage
170
234
 
171
235
  ## Slash Commands
172
236
 
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 |
237
+ | Command | Description |
238
+ | ------------------------- | ---------------------------------------------------------- |
239
+ | `/help` | Show available commands |
240
+ | `/clear` | Clear conversation history |
241
+ | `/mode [mode]` | Show or change permission mode |
242
+ | `/model [model]` | Select AI model (confirmation prompt, CLI restarts) |
243
+ | `/language [lang]` | Set response language (ko, en, ja, zh), saves and restarts |
244
+ | `/compact [instructions]` | Compress context window |
245
+ | `/cost` | Show session info |
246
+ | `/context` | Context window details |
247
+ | `/permissions` | Show permission rules |
248
+ | `/plugin [subcommand]` | Plugin management TUI |
249
+ | `/resume` | List recent sessions and resume one |
250
+ | `/rename <name>` | Rename the current session |
251
+ | `/exit` | Exit CLI |
252
+
253
+ 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., `/mode`, `/model`) show a nested submenu. Skill commands discovered from `.agents/skills/` and `.claude/commands/` appear alongside built-in commands.
254
+
255
+ ## Plugin Management
256
+
257
+ The `/plugin` command opens an interactive TUI for managing bundle plugins:
258
+
259
+ | Subcommand | Description |
260
+ | -------------------------- | ------------------------------------------------ |
261
+ | `/plugin install <name>` | Install a plugin from marketplace or local path |
262
+ | `/plugin uninstall <name>` | Remove an installed plugin |
263
+ | `/plugin enable <name>` | Enable a disabled plugin |
264
+ | `/plugin disable <name>` | Disable a plugin without uninstalling |
265
+ | `/plugin list` | List installed plugins with status |
266
+ | `/plugin marketplace` | Browse available plugins from configured sources |
182
267
 
183
268
  ## Configuration
184
269
 
@@ -186,11 +271,14 @@ Settings are loaded from (highest priority first):
186
271
 
187
272
  1. `.robota/settings.local.json` (local, gitignored)
188
273
  2. `.robota/settings.json` (project, shared)
189
- 3. `~/.robota/settings.json` (user global)
274
+ 3. `.claude/settings.json` (project, Claude Code compatible)
275
+ 4. `~/.robota/settings.json` (user global)
276
+ 5. `~/.claude/settings.json` (user global, Claude Code compatible)
190
277
 
191
278
  ```json
192
279
  {
193
280
  "defaultMode": "default",
281
+ "language": "en",
194
282
  "provider": {
195
283
  "name": "anthropic",
196
284
  "model": "claude-sonnet-4-6",
@@ -203,14 +291,6 @@ Settings are loaded from (highest priority first):
203
291
  }
204
292
  ```
205
293
 
206
- ### Environment Variables
207
-
208
- | Variable | Description | Required |
209
- | ------------------- | ----------------- | -------- |
210
- | `ANTHROPIC_API_KEY` | Anthropic API key | Yes |
211
-
212
- Copy `.env.example` to `.env` and set your key. The CLI reads `.env` automatically in dev mode.
213
-
214
294
  ## Context Discovery
215
295
 
216
296
  The CLI automatically discovers and loads:
@@ -219,36 +299,65 @@ The CLI automatically discovers and loads:
219
299
  - **CLAUDE.md** — same walk-up discovery
220
300
  - **Project metadata** — from `package.json`, `tsconfig.json`
221
301
 
222
- All context is assembled into the system prompt for the AI assistant.
302
+ All context is assembled into the system prompt.
303
+
304
+ ## Memory Management
305
+
306
+ - **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.
307
+ - **Tool state cleanup** — Completed tool execution states are trimmed to the most recent 50 entries.
308
+ - **React.memo** — `MessageItem` uses `React.memo` to skip redundant re-renders.
309
+
310
+ ## Session Logging
311
+
312
+ Session logs are written to `.robota/logs/{sessionId}.jsonl` in JSONL format by default, capturing structured events for diagnostics and replay.
223
313
 
224
314
  ## Architecture
225
315
 
316
+ 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.
317
+
226
318
  ```
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.)
319
+ bin.ts → cli.ts (arg parsing)
320
+ └── ui/render.tsx App.tsx (thin JSX shell)
321
+ ├── useInteractiveSession (ONLY React↔SDK bridge)
322
+ ├── InteractiveSession (SDK)
323
+ ├── CommandRegistry (SDK, re-exported by CLI)
324
+ │ │ ├── BuiltinCommandSource (SDK)
325
+ │ ├── SkillCommandSource (SDK, discovers from 4 paths)
326
+ │ └── PluginCommandSource (CLI-local)
327
+ └── SystemCommandExecutor (SDK)
328
+ ├── plugin-hooks-merger.ts (merges plugin hooks into SDK config)
329
+ ├── MessageList.tsx
330
+ ├── InputArea.tsx (CjkTextInput, bracketed paste, slash detection)
331
+ ├── StatusBar.tsx (mode, model, context %, message count)
332
+ ├── PermissionPrompt.tsx (arrow-key Allow/Deny)
333
+ ├── SlashAutocomplete.tsx (command popup with scroll)
334
+ ├── DiffBlock.tsx (Edit tool diff display)
335
+ ├── MenuSelect.tsx (arrow-key menu, Plugin TUI)
336
+ ├── PluginTUI.tsx (plugin management screen stack)
337
+ ├── TextPrompt.tsx (text input for Plugin TUI)
338
+ └── ConfirmPrompt.tsx (reusable yes/no prompt)
240
339
  ```
241
340
 
242
- Tool calls flow through the permission system:
341
+ ## Dependencies
243
342
 
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
- ```
343
+ | Package | Purpose |
344
+ | -------------------------------------- | ------------------------------------------ |
345
+ | `@robota-sdk/agent-sdk` | Session factory, query, config, context |
346
+ | `@robota-sdk/agent-core` | Types (TPermissionMode, TToolArgs) |
347
+ | `@robota-sdk/agent-transport-headless` | Headless runner for print mode (`-p`) |
348
+ | `ink`, `react` | TUI rendering |
349
+ | `ink-select-input` | Arrow-key selection (permission prompt) |
350
+ | `ink-spinner` | Loading spinner |
351
+ | `chalk` | Terminal colors |
352
+ | `ink-text-input` | Base text input (extended by CjkTextInput) |
353
+ | `marked`, `marked-terminal` | Markdown parsing and terminal rendering |
354
+ | `cli-highlight` | Syntax highlighting for code blocks |
355
+ | `string-width` | Unicode-aware string width (CJK support) |
356
+
357
+ ## Documentation
358
+
359
+ See [docs/SPEC.md](./docs/SPEC.md) for the full specification, architecture details, and design decisions.
360
+
361
+ ## License
362
+
363
+ MIT
package/dist/node/bin.js CHANGED
@@ -1,9 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startCli
4
- } from "./chunk-4DYVT4WI.js";
4
+ } from "./chunk-7EBJI2DW.js";
5
5
 
6
6
  // src/bin.ts
7
+ process.on("uncaughtException", (err) => {
8
+ const msg = err.message ?? "";
9
+ const isLikelyIME = msg.includes("string-width") || msg.includes("setCursorPosition") || msg.includes("getStringWidth") || msg.includes("slice") || msg.includes("charCodeAt");
10
+ if (isLikelyIME) {
11
+ process.stderr.write(`[robota] IME error suppressed: ${msg}
12
+ `);
13
+ return;
14
+ }
15
+ throw err;
16
+ });
7
17
  startCli().catch((err) => {
8
18
  const message = err instanceof Error ? err.message : String(err);
9
19
  process.stderr.write(message + "\n");