@robota-sdk/agent-cli 3.0.0-beta.62 → 3.0.0-beta.64

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.
@@ -1,123 +1,2 @@
1
- import {
2
- createProviderFromProfile,
3
- isSubagentWorkerParentMessage
4
- } from "../chunk-BENOH47A.js";
5
-
6
- // src/subagents/child-process-subagent-worker.ts
7
- import {
8
- createDefaultTools,
9
- createSubagentLogger,
10
- createSubagentSession
11
- } from "@robota-sdk/agent-sdk";
12
- var CANCEL_EXIT_CODE = 130;
13
- var NOOP_TERMINAL = {
14
- write: () => {
15
- },
16
- writeLine: () => {
17
- },
18
- writeMarkdown: () => {
19
- },
20
- writeError: () => {
21
- },
22
- prompt: () => Promise.resolve(""),
23
- select: () => Promise.resolve(0),
24
- spinner: () => ({ stop: () => {
25
- }, update: () => {
26
- } })
27
- };
28
- var session = null;
29
- var cancelled = false;
30
- var running = Promise.resolve();
31
- function sendChildMessage(message) {
32
- if (process.send) {
33
- process.send(message);
34
- }
35
- }
36
- async function runInitialPrompt(payload) {
37
- try {
38
- const provider = createProviderFromProfile(payload.providerProfile, payload.request.model);
39
- const sessionLogger = payload.logsDir ? createSubagentLogger(payload.request.parentSessionId, payload.jobId, payload.logsDir) : void 0;
40
- session = createSubagentSession({
41
- agentDefinition: payload.agentDefinition,
42
- parentConfig: payload.parentConfig,
43
- parentContext: payload.parentContext,
44
- parentTools: createDefaultTools(),
45
- provider,
46
- terminal: NOOP_TERMINAL,
47
- sessionId: payload.jobId,
48
- ...sessionLogger ? { sessionLogger } : {},
49
- permissionMode: payload.permissionMode,
50
- hooks: payload.parentConfig.hooks,
51
- onTextDelta: (delta) => sendChildMessage({ type: "text_delta", delta }),
52
- onToolExecution: forwardToolExecution
53
- });
54
- const output = await session.run(payload.request.prompt);
55
- if (cancelled) {
56
- sendChildMessage({ type: "cancelled", reason: "Subagent worker cancelled" });
57
- return;
58
- }
59
- sendChildMessage({ type: "result", output });
60
- } catch (error) {
61
- if (cancelled) {
62
- sendChildMessage({ type: "cancelled", reason: "Subagent worker cancelled" });
63
- return;
64
- }
65
- const message = error instanceof Error ? error.message : String(error);
66
- sendChildMessage({ type: "error", message });
67
- } finally {
68
- setImmediate(() => process.exit(cancelled ? CANCEL_EXIT_CODE : 0));
69
- }
70
- }
71
- function forwardToolExecution(event) {
72
- if (event.type === "start") {
73
- sendChildMessage({ type: "tool_start", toolName: event.toolName, toolArgs: event.toolArgs });
74
- return;
75
- }
76
- sendChildMessage({ type: "tool_end", toolName: event.toolName, success: event.success ?? true });
77
- }
78
- function runFollowUp(prompt) {
79
- if (session === null) {
80
- sendChildMessage({ type: "error", message: "Subagent worker has not started" });
81
- return;
82
- }
83
- running = running.then(async () => {
84
- try {
85
- await session?.run(prompt);
86
- } catch (error) {
87
- const message = error instanceof Error ? error.message : String(error);
88
- sendChildMessage({ type: "error", message });
89
- }
90
- });
91
- }
92
- async function cancelWorker(reason) {
93
- cancelled = true;
94
- session?.abort();
95
- sendChildMessage({ type: "cancelled", reason });
96
- await session?.shutdown({ reason: "other" }).catch(() => void 0);
97
- setTimeout(() => process.exit(CANCEL_EXIT_CODE), 0);
98
- }
99
- process.on("message", (message) => {
100
- if (!isSubagentWorkerParentMessage(message)) {
101
- sendChildMessage({ type: "error", message: "Malformed subagent worker parent message" });
102
- return;
103
- }
104
- switch (message.type) {
105
- case "start":
106
- running = running.then(() => runInitialPrompt(message.payload));
107
- break;
108
- case "send":
109
- runFollowUp(message.prompt);
110
- break;
111
- case "cancel":
112
- void cancelWorker(message.reason);
113
- break;
114
- default:
115
- sendChildMessage({ type: "error", message: "Unhandled subagent worker parent message" });
116
- }
117
- });
118
- process.on("disconnect", () => {
119
- cancelled = true;
120
- session?.abort();
121
- void session?.shutdown({ reason: "other" }).catch(() => void 0);
122
- });
123
- sendChildMessage({ type: "ready" });
1
+ import{n as e,r as t}from"../child-process-subagent-ipc-DVpVp43R.js";import{createDefaultTools as n,createSubagentLogger as r,createSubagentSession as i}from"@robota-sdk/agent-framework";import{createProviderFromProfile as a}from"@robota-sdk/agent-executor";const o={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let s=null,c=!1,l=Promise.resolve();function u(e){process.send&&process.send(e)}async function d(e){try{let l=a(e.providerProfile,e.request.model,t),d=e.logsDir?r(e.request.parentSessionId,e.jobId,e.logsDir):void 0;s=i({agentDefinition:e.agentDefinition,parentConfig:e.parentConfig,parentContext:e.parentContext,parentTools:n(),provider:l,terminal:o,sessionId:e.jobId,...d?{sessionLogger:d}:{},permissionMode:e.permissionMode,hooks:e.parentConfig.hooks,onTextDelta:e=>u({type:`text_delta`,delta:e}),onToolExecution:f});let p=await s.run(e.request.prompt);if(c){u({type:`cancelled`,reason:`Subagent worker cancelled`});return}u({type:`result`,output:p})}catch(e){if(c){u({type:`cancelled`,reason:`Subagent worker cancelled`});return}u({type:`error`,message:e instanceof Error?e.message:String(e)})}finally{setImmediate(()=>process.exit(c?130:0))}}function f(e){if(e.type===`start`){u({type:`tool_start`,toolName:e.toolName,toolArgs:e.toolArgs});return}u({type:`tool_end`,toolName:e.toolName,success:e.success??!0})}function p(e){if(s===null){u({type:`error`,message:`Subagent worker has not started`});return}l=l.then(async()=>{try{await s?.run(e)}catch(e){u({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function m(e){c=!0,s?.abort(),u({type:`cancelled`,reason:e}),await s?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}process.on(`message`,t=>{if(!e(t)){u({type:`error`,message:`Malformed subagent worker parent message`});return}switch(t.type){case`start`:l=l.then(()=>d(t.payload));break;case`send`:p(t.prompt);break;case`cancel`:m(t.reason);break;default:u({type:`error`,message:`Unhandled subagent worker parent message`})}}),process.on(`disconnect`,()=>{c=!0,s?.abort(),s?.shutdown({reason:`other`}).catch(()=>void 0)}),u({type:`ready`});export{};
2
+ //# sourceMappingURL=child-process-subagent-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-process-subagent-worker.js","names":[],"sources":["../../../src/subagents/child-process-subagent-worker.ts"],"sourcesContent":["import {\n createDefaultTools,\n createSubagentLogger,\n createSubagentSession,\n} from '@robota-sdk/agent-framework';\nimport { createProviderFromProfile } from '@robota-sdk/agent-executor';\nimport {\n isSubagentWorkerParentMessage,\n type ISubagentWorkerStartPayload,\n type TSubagentWorkerChildMessage,\n type TSubagentWorkerWireValue,\n} from './child-process-subagent-ipc.js';\nimport type { ITerminalOutput } from '../types.js';\nimport { DEFAULT_PROVIDER_DEFINITIONS } from '../utils/provider-default-definitions.js';\n\nconst CANCEL_EXIT_CODE = 130;\n\nconst NOOP_TERMINAL: ITerminalOutput = {\n write: (): void => {},\n writeLine: (): void => {},\n writeMarkdown: (): void => {},\n writeError: (): void => {},\n prompt: (): Promise<string> => Promise.resolve(''),\n select: (): Promise<number> => Promise.resolve(0),\n spinner: () => ({ stop: (): void => {}, update: (): void => {} }),\n};\n\ntype TSubagentSessionToolEvent = Parameters<\n NonNullable<Parameters<typeof createSubagentSession>[0]['onToolExecution']>\n>[0];\n\nlet session: ReturnType<typeof createSubagentSession> | null = null;\nlet cancelled = false;\nlet running: Promise<void> = Promise.resolve();\n\nfunction sendChildMessage(message: TSubagentWorkerChildMessage): void {\n if (process.send) {\n process.send(message);\n }\n}\n\nasync function runInitialPrompt(payload: ISubagentWorkerStartPayload): Promise<void> {\n try {\n const provider = createProviderFromProfile(\n payload.providerProfile,\n payload.request.model,\n DEFAULT_PROVIDER_DEFINITIONS,\n );\n const sessionLogger = payload.logsDir\n ? createSubagentLogger(payload.request.parentSessionId, payload.jobId, payload.logsDir)\n : undefined;\n session = createSubagentSession({\n agentDefinition: payload.agentDefinition,\n parentConfig: payload.parentConfig,\n parentContext: payload.parentContext,\n parentTools: createDefaultTools(),\n provider,\n terminal: NOOP_TERMINAL,\n sessionId: payload.jobId,\n ...(sessionLogger ? { sessionLogger } : {}),\n permissionMode: payload.permissionMode,\n hooks: payload.parentConfig.hooks,\n onTextDelta: (delta) => sendChildMessage({ type: 'text_delta', delta }),\n onToolExecution: forwardToolExecution,\n });\n const output = await session.run(payload.request.prompt);\n if (cancelled) {\n sendChildMessage({ type: 'cancelled', reason: 'Subagent worker cancelled' });\n return;\n }\n sendChildMessage({ type: 'result', output });\n } catch (error) {\n if (cancelled) {\n sendChildMessage({ type: 'cancelled', reason: 'Subagent worker cancelled' });\n return;\n }\n const message = error instanceof Error ? error.message : String(error);\n sendChildMessage({ type: 'error', message });\n } finally {\n setImmediate(() => process.exit(cancelled ? CANCEL_EXIT_CODE : 0));\n }\n}\n\nfunction forwardToolExecution(event: TSubagentSessionToolEvent): void {\n if (event.type === 'start') {\n sendChildMessage({ type: 'tool_start', toolName: event.toolName, toolArgs: event.toolArgs });\n return;\n }\n sendChildMessage({ type: 'tool_end', toolName: event.toolName, success: event.success ?? true });\n}\n\nfunction runFollowUp(prompt: string): void {\n if (session === null) {\n sendChildMessage({ type: 'error', message: 'Subagent worker has not started' });\n return;\n }\n running = running.then(async () => {\n try {\n await session?.run(prompt);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n sendChildMessage({ type: 'error', message });\n }\n });\n}\n\nasync function cancelWorker(reason?: string): Promise<void> {\n cancelled = true;\n session?.abort();\n sendChildMessage({ type: 'cancelled', reason });\n await session?.shutdown({ reason: 'other' }).catch(() => undefined);\n setTimeout(() => process.exit(CANCEL_EXIT_CODE), 0);\n}\n\nprocess.on('message', (message: TSubagentWorkerWireValue) => {\n if (!isSubagentWorkerParentMessage(message)) {\n sendChildMessage({ type: 'error', message: 'Malformed subagent worker parent message' });\n return;\n }\n\n switch (message.type) {\n case 'start':\n running = running.then(() => runInitialPrompt(message.payload));\n break;\n case 'send':\n runFollowUp(message.prompt);\n break;\n case 'cancel':\n void cancelWorker(message.reason);\n break;\n default:\n sendChildMessage({ type: 'error', message: 'Unhandled subagent worker parent message' });\n }\n});\n\nprocess.on('disconnect', () => {\n cancelled = true;\n session?.abort();\n void session?.shutdown({ reason: 'other' }).catch(() => undefined);\n});\n\nsendChildMessage({ type: 'ready' });\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robota-sdk/agent-cli",
3
- "version": "3.0.0-beta.62",
3
+ "version": "3.0.0-beta.64",
4
4
  "description": "AI coding assistant CLI built on Robota SDK",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,55 +38,27 @@
38
38
  "bin"
39
39
  ],
40
40
  "dependencies": {
41
+ "@robota-sdk/agent-executor": "3.0.0-beta.64",
41
42
  "chalk": "^5.3.0",
42
43
  "cli-highlight": "^2.1.0",
43
- "ink": "^7.0.1",
44
- "ink-select-input": "^6.2.0",
45
- "ink-spinner": "^5.0.0",
46
- "ink-text-input": "^6.0.0",
47
44
  "marked": "^9.1.5",
48
45
  "marked-terminal": "^7.3.0",
49
46
  "open": "^11.0.0",
50
- "react": "19.2.4",
51
47
  "string-width": "^8.2.0",
52
48
  "ws": "^8.18.3",
53
- "@robota-sdk/agent-command-agent": "3.0.0-beta.62",
54
- "@robota-sdk/agent-command-background": "3.0.0-beta.62",
55
- "@robota-sdk/agent-command-help": "3.0.0-beta.62",
56
- "@robota-sdk/agent-command-exit": "3.0.0-beta.62",
57
- "@robota-sdk/agent-command-language": "3.0.0-beta.62",
58
- "@robota-sdk/agent-command-model": "3.0.0-beta.62",
59
- "@robota-sdk/agent-command-memory": "3.0.0-beta.62",
60
- "@robota-sdk/agent-command-context": "3.0.0-beta.62",
61
- "@robota-sdk/agent-command-compact": "3.0.0-beta.62",
62
- "@robota-sdk/agent-command-permissions": "3.0.0-beta.62",
63
- "@robota-sdk/agent-command-provider": "3.0.0-beta.62",
64
- "@robota-sdk/agent-command-plugin": "3.0.0-beta.62",
65
- "@robota-sdk/agent-command-rewind": "3.0.0-beta.62",
66
- "@robota-sdk/agent-command-reset": "3.0.0-beta.62",
67
- "@robota-sdk/agent-command-session": "3.0.0-beta.62",
68
- "@robota-sdk/agent-command-skills": "3.0.0-beta.62",
69
- "@robota-sdk/agent-core": "3.0.0-beta.62",
70
- "@robota-sdk/agent-command-statusline": "3.0.0-beta.62",
71
- "@robota-sdk/agent-command-user-local": "3.0.0-beta.62",
72
- "@robota-sdk/agent-provider-anthropic": "3.0.0-beta.62",
73
- "@robota-sdk/agent-provider-deepseek": "3.0.0-beta.62",
74
- "@robota-sdk/agent-provider-openai": "3.0.0-beta.62",
75
- "@robota-sdk/agent-provider-gemini": "3.0.0-beta.62",
76
- "@robota-sdk/agent-provider-qwen": "3.0.0-beta.62",
77
- "@robota-sdk/agent-provider-gemma": "3.0.0-beta.62",
78
- "@robota-sdk/agent-transport-headless": "3.0.0-beta.62",
79
- "@robota-sdk/agent-sdk": "3.0.0-beta.62",
80
- "@robota-sdk/agent-transport-ws": "3.0.0-beta.62"
49
+ "@robota-sdk/agent-command": "3.0.0-beta.64",
50
+ "@robota-sdk/agent-core": "3.0.0-beta.64",
51
+ "@robota-sdk/agent-interface-transport": "3.0.0-beta.64",
52
+ "@robota-sdk/agent-provider": "3.0.0-beta.64",
53
+ "@robota-sdk/agent-framework": "3.0.0-beta.64",
54
+ "@robota-sdk/agent-transport": "3.0.0-beta.64"
81
55
  },
82
56
  "devDependencies": {
83
57
  "@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
84
58
  "@types/marked": "^6.0.0",
85
- "@types/react": "^19.2.14",
86
59
  "@types/ws": "^8.5.10",
87
- "ink-testing-library": "^4.0.0",
88
60
  "rimraf": "^5.0.5",
89
- "tsup": "^8.0.1",
61
+ "tsdown": "^0.22.0",
90
62
  "tsx": "^4.7.0",
91
63
  "typescript": "^5.3.3",
92
64
  "vitest": "^1.6.1"
@@ -96,9 +68,9 @@
96
68
  "access": "public"
97
69
  },
98
70
  "scripts": {
99
- "build": "tsup",
100
- "build:js": "tsup --no-dts",
101
- "build:types": "tsup --dts-only",
71
+ "build": "pnpm --filter @robota-sdk/agent-web build:spa && node scripts/copy-web-assets.mjs && tsdown",
72
+ "build:js": "tsdown --no-dts",
73
+ "build:types": "tsdown --dts",
102
74
  "dev": "tsx src/bin.ts",
103
75
  "start": "node dist/node/bin.js",
104
76
  "test": "vitest run --passWithNoTests",
package/README.ko.md DELETED
@@ -1,297 +0,0 @@
1
- **Language:** [English](README.md) | [한국어](README.ko.md)
2
-
3
- # @robota-sdk/agent-cli
4
-
5
- Robota SDK 기반의 AI 코딩 어시스턴트 CLI. AGENTS.md/CLAUDE.md를 로드하여 프로젝트 컨텍스트를 파악하고, Claude Code 호환 권한 모드를 갖춘 도구 호출 REPL을 제공합니다.
6
-
7
- ## 시스템 요구사항
8
-
9
- **Node.js 22 이상** 필요합니다.
10
-
11
- ```bash
12
- node --version # v22.x.x 이상이어야 합니다
13
- ```
14
-
15
- Node.js 버전이 22 미만이라면 [nvm](https://github.com/nvm-sh/nvm)으로 업그레이드:
16
-
17
- ```bash
18
- nvm install 22
19
- nvm use 22
20
- ```
21
-
22
- ## 설치
23
-
24
- ```bash
25
- # 전역 설치
26
- npm install -g @robota-sdk/agent-cli
27
-
28
- # 또는 npx로 직접 실행
29
- npx @robota-sdk/agent-cli
30
- ```
31
-
32
- > **macOS Terminal.app 사용자**: 한국어/중국어/일본어 입력 시 크래시가 발생할 수 있습니다. **[iTerm2](https://iterm2.com/)** 사용을 권장합니다. 이는 Ink + Terminal.app의 알려진 문제로 Claude Code와 동일합니다.
33
-
34
- 전역 설치 후 시스템 전체에서 `robota` 명령어를 사용할 수 있습니다:
35
-
36
- ```bash
37
- robota # 인터랙티브 REPL
38
- robota "프롬프트" # 초기 프롬프트와 함께 REPL 시작
39
- robota -p "파일 목록 출력" # 출력 모드 (단발성, 응답 후 종료)
40
- ```
41
-
42
- ### 환경 변수
43
-
44
- | 변수 | 설명 | 필수 여부 |
45
- | ------------------- | ---------------------------------------- | -------------- |
46
- | `ANTHROPIC_API_KEY` | Anthropic 프로바이더용 API 키 | Anthropic 전용 |
47
- | `DEEPSEEK_API_KEY` | DeepSeek 프로바이더용 API 키 | DeepSeek 전용 |
48
- | `DASHSCOPE_API_KEY` | Qwen(알리바바 클라우드) 모델 스튜디오 키 | Qwen 전용 |
49
-
50
- 실행 전 키를 설정하세요:
51
-
52
- ```bash
53
- export ANTHROPIC_API_KEY=sk-ant-...
54
- ```
55
-
56
- ## 개발 환경 설정 (모노레포)
57
-
58
- ```bash
59
- # 의존성 및 CLI 빌드
60
- pnpm build:deps
61
- pnpm --filter @robota-sdk/agent-cli build
62
- ```
63
-
64
- ## 실행 (모노레포)
65
-
66
- ```bash
67
- # 모노레포 루트에서
68
- cd packages/agent-cli
69
-
70
- # 개발 모드 (빌드 불필요)
71
- pnpm dev
72
-
73
- # 프로덕션 모드 (빌드 필요)
74
- pnpm start
75
-
76
- # 인자 포함 실행
77
- pnpm dev -- --version
78
- pnpm dev -- --permission-mode plan
79
- pnpm dev -- -p "src/ 내 모든 TypeScript 파일 목록"
80
- ```
81
-
82
- ## CLI 플래그
83
-
84
- ```
85
- robota # 인터랙티브 REPL (기본 모드)
86
- robota "프롬프트" # 초기 프롬프트와 함께 REPL 시작
87
- robota -p "프롬프트" # 출력 모드 (단발성, 응답 후 종료)
88
- robota -c # 마지막 세션 이어서 시작
89
- robota -r <session-id> # 세션 ID로 세션 재개
90
- robota --model <모델> # 모델 지정 (예: claude-sonnet-4-6)
91
- robota --language <언어> # 응답 언어 (ko, en, ja, zh)
92
- robota --permission-mode <모드> # plan | default | acceptEdits | bypassPermissions
93
- robota --max-turns <n> # 인터랙션당 에이전틱 턴 제한
94
- robota --output-format <형식> # text | json | stream-json (출력 모드)
95
- robota --system-prompt <텍스트> # 시스템 프롬프트 교체 (출력 모드)
96
- robota --append-system-prompt <텍스트> # 시스템 프롬프트에 추가 (출력 모드)
97
- robota --reset # 사용자 설정 삭제 후 종료
98
- robota --check-update # npm에서 최신 CLI 버전 확인 후 종료
99
- robota --disable-update-check # 이번 실행에서 시작 시 업데이트 확인 건너뜀
100
- robota --version # 버전 표시
101
- ```
102
-
103
- ### CLI 업데이트 확인
104
-
105
- ```bash
106
- robota --check-update
107
- ```
108
-
109
- 업데이트가 있으면 npm 전역 설치 명령어를 출력합니다:
110
-
111
- ```bash
112
- npm install -g '@robota-sdk/agent-cli@latest'
113
- ```
114
-
115
- ### 출력 모드 형식
116
-
117
- 출력 모드(`-p`)는 `--output-format`으로 세 가지 형식을 지원합니다:
118
-
119
- | 형식 | 설명 |
120
- | ------------- | ---------------------------------------------------------------- |
121
- | `text` | 표준 출력에 일반 텍스트 응답 (기본값) |
122
- | `json` | 단일 JSON 객체: `{ type, result, session_id, subtype }` |
123
- | `stream-json` | `content_block_delta` 스트리밍 이벤트를 줄바꿈으로 구분한 NDJSON |
124
-
125
- ### 표준 입력(Stdin) 파이프
126
-
127
- `-p`와 위치 인자 없이 stdin이 파이프되면 CLI가 stdin에서 읽습니다:
128
-
129
- ```bash
130
- echo "이 오류를 설명해줘" | robota -p
131
- cat file.ts | robota -p "이 코드를 검토해줘" --output-format json
132
- git diff | robota -p "변경 사항 요약" --output-format stream-json
133
- ```
134
-
135
- ## 최초 실행 설정
136
-
137
- 사용 가능한 설정 파일이 없으면 CLI가 다음을 안내합니다:
138
-
139
- 1. **프로바이더 선택** — CLI 바이너리에 포함된 프로바이더 중 선택
140
- 2. **프로바이더별 설정** — 모델, base URL, 마스킹된 API 키 등
141
- 3. **응답 언어** (ko/en/ja/zh, 기본값: en)
142
-
143
- `~/.robota/settings.json`에 설정이 저장됩니다. `robota --reset`으로 최초 실행 상태로 되돌릴 수 있습니다.
144
-
145
- ## 내장 도구
146
-
147
- AI 에이전트는 8개의 로컬 도구를 호출할 수 있습니다:
148
-
149
- | 도구 | 설명 | 주요 인자 |
150
- | ----------- | ----------------------------- | ---------- |
151
- | `Bash` | 셸 명령 실행 | `command` |
152
- | `Read` | 줄 번호와 함께 파일 내용 읽기 | `filePath` |
153
- | `Write` | 파일에 내용 쓰기 | `filePath` |
154
- | `Edit` | 파일의 문자열 교체 | `filePath` |
155
- | `Glob` | 패턴으로 파일 검색 | `pattern` |
156
- | `Grep` | 정규식으로 파일 내용 검색 | `pattern` |
157
- | `WebFetch` | URL 내용을 텍스트로 가져오기 | `url` |
158
- | `WebSearch` | 인터넷 검색 | `query` |
159
-
160
- ## 권한 시스템
161
-
162
- 모든 도구 호출은 세 단계 권한 게이트를 통과합니다:
163
-
164
- 1. **거부 목록** — 거부 패턴이 일치하면 차단
165
- 2. **허용 목록** — 허용 패턴이 일치하면 자동 승인
166
- 3. **모드 정책** — 활성 권한 모드에 따라 결정
167
-
168
- ### 권한 모드
169
-
170
- | 모드 | Read/Glob/Grep | Write/Edit | Bash |
171
- | ------------------- | :------------: | :--------: | :--: |
172
- | `plan` | 자동 | 거부 | 거부 |
173
- | `default` | 자동 | 승인 | 승인 |
174
- | `acceptEdits` | 자동 | 자동 | 승인 |
175
- | `bypassPermissions` | 자동 | 자동 | 자동 |
176
-
177
- ### 런타임 모드 변경
178
-
179
- `/permissions` 슬래시 커맨드 사용:
180
-
181
- ```
182
- > /permissions # 현재 모드 및 세션 승인 도구 표시
183
- > /permissions plan # 읽기 전용 모드로 전환
184
- > /permissions bypassPermissions # 모든 프롬프트 건너뜀
185
- ```
186
-
187
- 또는 시작 시 설정:
188
-
189
- ```bash
190
- robota --permission-mode plan
191
- ```
192
-
193
- ### 권한 패턴
194
-
195
- `.robota/settings.json` 또는 `.robota/settings.local.json`에 설정:
196
-
197
- ```json
198
- {
199
- "permissions": {
200
- "allow": ["Bash(pnpm *)", "Bash(git status)", "Read(/src/**)"],
201
- "deny": ["Bash(rm -rf *)", "Write(.env)"]
202
- }
203
- }
204
- ```
205
-
206
- 패턴 문법: `ToolName`은 모든 호출에 매칭; `ToolName(pattern)`은 셸 스타일 글로브(`*`, `**`)로 주요 인자에 매칭.
207
-
208
- ## 키보드 단축키
209
-
210
- | 키 | 동작 |
211
- | --------- | ------------------------------------------ |
212
- | Enter | 입력 제출 |
213
- | ESC | 현재 실행 중단 (부분 응답 저장) |
214
- | Ctrl+C | 즉시 프로세스 종료 |
215
- | Up/Down | 여러 줄 입력에서 줄 탐색 |
216
- | 화살표 키 | 슬래시 커맨드 자동완성, 권한 프롬프트 탐색 |
217
-
218
- ## 주요 슬래시 커맨드
219
-
220
- | 커맨드 | 설명 |
221
- | --------------------- | ----------------------------------------------- |
222
- | `/help` | 사용 가능한 커맨드 표시 |
223
- | `/clear` | 대화 기록 초기화 |
224
- | `/model [모델명]` | AI 모델 변경 (확인 프롬프트, CLI 재시작) |
225
- | `/language [언어]` | 응답 언어 설정 (ko, en, ja, zh), 저장 후 재시작 |
226
- | `/compact [지시사항]` | 컨텍스트 창 압축 |
227
- | `/cost` | 세션 정보 표시 |
228
- | `/context` | 컨텍스트 창 상세, 참조 목록, 자동 압축 설정 |
229
- | `/agent` | 백그라운드 서브에이전트 작업 실행 및 관리 |
230
- | `/permissions [모드]` | 권한 규칙 표시 또는 권한 모드 변경 |
231
- | `/plugin [하위명령]` | 플러그인 관리 |
232
- | `/resume` | 최근 세션 목록 표시 및 재개 |
233
- | `/rename <이름>` | 현재 세션 이름 변경 |
234
- | `/exit` | CLI 종료 |
235
-
236
- ## 세션 관리
237
-
238
- ### CLI 플래그
239
-
240
- | 플래그 | 설명 |
241
- | --------------------- | ---------------------------------------- |
242
- | `-c`, `--continue` | 가장 최근 세션 이어서 시작 |
243
- | `-r`, `--resume <id>` | 특정 세션 ID로 재개 |
244
- | `--fork-session <id>` | 세션 포크 (복사된 기록으로 새 세션 시작) |
245
- | `--name <이름>` | 시작 시 세션에 이름 지정 |
246
-
247
- ## 설정
248
-
249
- 설정은 다음 순서로 병합됩니다 (낮은 우선순위 → 높은 우선순위):
250
-
251
- 1. `~/.robota/settings.json` (사용자 전역)
252
- 2. `~/.claude/settings.json` (사용자 전역, Claude Code 호환)
253
- 3. `.robota/settings.json` (프로젝트, 공유)
254
- 4. `.robota/settings.local.json` (로컬, gitignore 대상)
255
- 5. `.claude/settings.json` (프로젝트, Claude Code 호환)
256
- 6. `.claude/settings.local.json` (로컬, gitignore 대상, Claude Code 호환)
257
-
258
- ```json
259
- {
260
- "defaultMode": "default",
261
- "language": "ko",
262
- "currentProvider": "claude-sonnet-4-6",
263
- "providers": {
264
- "claude-sonnet-4-6": {
265
- "type": "anthropic",
266
- "model": "claude-sonnet-4-6",
267
- "apiKey": "$ENV:ANTHROPIC_API_KEY"
268
- }
269
- },
270
- "permissions": {
271
- "allow": ["Bash(pnpm *)"],
272
- "deny": ["Bash(rm -rf *)"]
273
- }
274
- }
275
- ```
276
-
277
- ## 컨텍스트 자동 탐색
278
-
279
- CLI는 다음을 자동으로 탐색하고 로드합니다:
280
-
281
- - **AGENTS.md** — cwd에서 파일시스템 루트까지 상위 디렉토리 탐색
282
- - **CLAUDE.md** — 동일한 상위 탐색
283
- - **프로젝트 메타데이터** — `package.json`, `tsconfig.json`
284
-
285
- 모든 컨텍스트가 시스템 프롬프트로 조합됩니다.
286
-
287
- ## 세션 로깅
288
-
289
- 세션 로그는 JSONL 형식으로 `.robota/logs/{sessionId}.jsonl`에 기록됩니다. 재개 가능한 세션 JSON은 `.robota/sessions/{sessionId}.json`에 저장됩니다.
290
-
291
- ## 아키텍처
292
-
293
- CLI는 순수 TUI 레이어입니다. 모든 비즈니스 로직은 `@robota-sdk/agent-sdk`의 `InteractiveSession`에 있습니다. `useInteractiveSession`이 유일한 React↔SDK 브릿지입니다.
294
-
295
- ## 라이선스
296
-
297
- MIT