cli-jaw 1.0.0 → 1.0.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/README.ko.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  *Claude, Codex, Gemini... 이제 번갈아 쓰지 마세요.*
8
8
 
9
- [![Tests](https://img.shields.io/badge/tests-383%20pass-brightgreen)](#-테스트)
9
+ [![Tests](https://img.shields.io/badge/tests-445%20pass-brightgreen)](#-테스트)
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue)](https://typescriptlang.org)
11
11
  [![Node](https://img.shields.io/badge/node-%3E%3D22-blue)](https://nodejs.org)
12
12
  [![License](https://img.shields.io/badge/license-ISC-yellow)](LICENSE)
@@ -14,7 +14,7 @@
14
14
 
15
15
  [English](README.md) / **한국어** / [中文](README.zh-CN.md)
16
16
 
17
- ![CLI-JAW Web UI](docs/screenshots/web-ui.png)
17
+ <video src="https://github.com/user-attachments/assets/a7cf17c9-bfb3-44f0-b7fd-d001a39643fd" autoplay loop muted playsinline width="100%"></video>
18
18
 
19
19
  </div>
20
20
 
@@ -79,9 +79,10 @@ gemini # Google Gemini — 첫 실행 시 인증
79
79
  ## CLI-JAW란 무엇인가요?
80
80
 
81
81
  CLI-JAW는 내 컴퓨터에 상주하며 이미 익숙한 인터페이스인 **웹, 터미널, 텔레그램**에서 작동하는 **개인용 AI 비서**입니다. 궁금한 것을 묻고, 작업을 위임하고, 워크플로우를 자동화하세요.
82
+ ![CLI-JAW Web UI](image/README/1772128366759.png)
82
83
 
83
- > 💬 *"오늘 일정 정리해줘"* → 텔레그램으로 바로 정리해서 보내줘요
84
- > 💬 *"이 모듈 리팩토링하고 테스트도 짜줘"* → 서브에이전트가 알아서, 커피 한 잔 하고 오면 돼요
84
+ > 💬 *"오늘 일정 정리해줘"* → 텔레그램으로 바로 정리해서 보내줘요
85
+ > 💬 *"이 모듈 리팩토링하고 테스트도 짜줘"* → 서브에이전트가 알아서, 커피 한 잔 하고 오면 돼요
85
86
  > 💬 *"저 PDF 다운받아서 핵심만 노션에 정리해"* → 브라우저 + 노션 스킬 조합으로 뚝딱
86
87
 
87
88
  단일 모델만을 사용하는 기존 비서들과 달리, CLI-JAW는 5개의 AI 엔진(Claude, Codex, Gemini, OpenCode, Copilot)을 공식 CLI를 통해 오케스트레이션하여 모든 제공업체의 장점을 통합된 경험으로 제공합니다. 하나의 엔진 사용량이 초과되면 자동으로 다음 엔진으로 전환됩니다. 107개의 내장 스킬이 브라우저 자동화부터 문서 생성까지 모든 것을 처리합니다.
@@ -93,7 +94,7 @@ CLI-JAW는 내 컴퓨터에 상주하며 이미 익숙한 인터페이스인 **
93
94
  | ⚡ **멀티 에이전트 자동 전환(Fallback)** | 엔진 하나가 멈춰도 걱정 없습니다. 다음 엔진이 즉시 이어받아 중단 없는 작업이 가능합니다. |
94
95
  | 🎭 **오케스트레이션 기반 성능 극대화** | 복잡한 작업은 전문화된 서브 에이전트에게 분산시켜 처리량을 극대화합니다. |
95
96
  | 📦 **107개의 내장 스킬** | 브라우저 자동화, 문서 생성, 텔레그램 연동, 영구 메모리 등 설치 즉시 사용 가능한 기능들을 제공합니다. |
96
- | 🖥️ **크로스 플랫폼** | macOS, Linux, Windows (WSL) 브라우저 실행, CLI 감지, 설치 모두 네이티브 지원. |
97
+ | 🖥️ **크로스 플랫폼** | macOS, Linux, Windows — ENOENT-safe CLI 스폰, 자동 감지, `.cmd` shim 지원, 네이티브 설치 전부 크로스플랫폼 동작. |
97
98
 
98
99
  ![CLI-JAW 터미널](docs/screenshots/terminal-cli.png)
99
100
 
@@ -343,6 +344,19 @@ jaw --home ~/my-project launchd --port 3458 # 프로젝트 → 포트 3458
343
344
 
344
345
  ---
345
346
 
347
+ ## 🐳 Docker — 컨테이너 격리
348
+
349
+ 보안 격리를 위해 Docker 컨테이너에서 실행 — AI 에이전트가 호스트 파일에 접근 불가.
350
+
351
+ ```bash
352
+ docker compose up -d # → http://localhost:3457
353
+ ```
354
+
355
+ > 자세한 내용은 [English README](README.md#-docker--container-isolation) 참고.
356
+ > `Dockerfile` (npm 배포판) / `Dockerfile.dev` (로컬 소스) 두 가지 제공.
357
+
358
+ ---
359
+
346
360
  ## 🛠️ 개발
347
361
 
348
362
  <details>
@@ -386,7 +400,7 @@ src/
386
400
  ## 🧪 테스트
387
401
 
388
402
  <details>
389
- <summary>383 pass · 1 skipped · 외부 의존성 0</summary>
403
+ <summary>445 pass · 1 skipped · 외부 의존성 0</summary>
390
404
 
391
405
  ```bash
392
406
  npm test
@@ -415,6 +429,7 @@ npm test
415
429
  | `doctor`에서 CLI 누락 표시 | 해당 CLI 미설치 | `npm i -g @anthropic-ai/claude-code` 등 설치 |
416
430
  | 포트 3457 사용 중 | 다른 프로세스가 점유 | `PORT=4000 jaw serve` 또는 기존 프로세스 종료 |
417
431
  | 텔레그램 봇 무반응 | 토큰 미설정 또는 Chat ID 누락 | `jaw init --telegram-token ...` 재실행 |
432
+ | 텔레그램 ✓✓ 지연 표시 | Telegram 서버 측 전달 확인 타이밍 | 정상 동작 — 서버 부하에 따라 수 분 걸릴 수 있음. 버그 아님 |
418
433
  | `npm install -g` 권한 오류 | 글로벌 디렉토리 권한 문제 | `sudo npm i -g cli-jaw` 또는 [nvm](https://github.com/nvm-sh/nvm) 사용 권장 |
419
434
  | 빌드 실패 (`tsc` 에러) | Node 22 미만 버전 | `node -v` 확인 → 22 이상으로 업그레이드 |
420
435
  | 메모리가 세션 간 유지 안 됨 | `~/.cli-jaw/memory/` 디렉토리 없음 | `jaw init` 재실행하면 자동 생성 |
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  *One assistant. Five brains. Always on.*
8
8
 
9
- [![Tests](https://img.shields.io/badge/tests-383%20pass-brightgreen)](#-tests)
9
+ [![Tests](https://img.shields.io/badge/tests-445%20pass-brightgreen)](#-tests)
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue)](https://typescriptlang.org)
11
11
  [![Node](https://img.shields.io/badge/node-%3E%3D22-blue)](https://nodejs.org)
12
12
  [![License](https://img.shields.io/badge/license-ISC-yellow)](LICENSE)
@@ -14,7 +14,7 @@
14
14
 
15
15
  **English** / [한국어](README.ko.md) / [中文](README.zh-CN.md)
16
16
 
17
- ![CLI-JAW Web UI](docs/screenshots/web-ui.png)
17
+ <video src="https://github.com/user-attachments/assets/a7cf17c9-bfb3-44f0-b7fd-d001a39643fd" autoplay loop muted playsinline width="100%"></video>
18
18
 
19
19
  </div>
20
20
 
@@ -76,25 +76,25 @@ Check what's ready: `jaw doctor`
76
76
 
77
77
  ---
78
78
 
79
-
80
79
  ## What is CLI-JAW?
81
80
 
82
81
  CLI-JAW is a **personal AI assistant** that lives on your machine and works from the interfaces you already use — **Web, Terminal, and Telegram**. Ask it anything, delegate tasks, automate your workflows.
82
+ ![1772128366759](image/README/1772128366759.png)
83
83
 
84
- > 💬 *"Summarize today's schedule"* → answer on Telegram
85
- > 💬 *"Refactor this module and write tests"* → sub-agents handle it while you grab coffee
84
+ > 💬 *"Summarize today's schedule"* → answer on Telegram
85
+ > 💬 *"Refactor this module and write tests"* → sub-agents handle it while you grab coffee
86
86
  > 💬 *"Download that PDF and put the key points in Notion"* → browser + Notion skill, done
87
87
 
88
88
  Unlike single-model assistants, CLI-JAW orchestrates **5 AI engines** (Claude, Codex, Gemini, OpenCode, Copilot) through their official CLIs — giving you the best of every provider in one unified experience. If one engine is busy, it automatically falls back to the next. 107 built-in skills handle everything from browser automation to document generation.
89
89
 
90
- | | Why CLI-JAW? |
91
- | ------------------------------ | ------------------------------------------------------------------------------------------- |
92
- | 🛡️ **TOS-Safe** | Uses official CLIs only — no API key scraping, no reverse engineering, no ban risk. |
93
- | 🤖 **Verified Agent Tools** | 5 battle-tested coding agents (Claude, Codex, Gemini, OpenCode, Copilot) under one roof. |
94
- | ⚡ **Multi-Agent Fallback** | One engine down? The next picks up automatically. Zero downtime. |
95
- | 🎭 **Orchestrated Performance** | Complex tasks split across specialized sub-agents for maximum throughput. |
96
- | 📦 **107 Built-in Skills** | Browser automation, document generation, Telegram, memory — ready out of the box. |
97
- | 🖥️ **Cross-Platform** | macOS, Linux, Windows (WSL) browser launch, CLI detection, and install all work natively. |
90
+ | | Why CLI-JAW? |
91
+ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
92
+ | 🛡️**TOS-Safe** | Uses official CLIs only — no API key scraping, no reverse engineering, no ban risk. |
93
+ | 🤖**Verified Agent Tools** | 5 battle-tested coding agents (Claude, Codex, Gemini, OpenCode, Copilot) under one roof. |
94
+ | ⚡**Multi-Agent Fallback** | One engine down? The next picks up automatically. Zero downtime. |
95
+ | 🎭**Orchestrated Performance** | Complex tasks split across specialized sub-agents for maximum throughput. |
96
+ | 📦**107 Built-in Skills** | Browser automation, document generation, Telegram, memory — ready out of the box. |
97
+ | 🖥️**Cross-Platform** | macOS, Linux, Windows — ENOENT-safe CLI spawn, auto-detection,`.cmd` shim support, and native install all work across platforms. |
98
98
 
99
99
  ![CLI-JAW Terminal](docs/screenshots/terminal-cli.png)
100
100
 
@@ -113,7 +113,7 @@ graph LR
113
113
  JAW -->|inject| SK["📦 Skills"]
114
114
  JAW -->|control| BR["🌐 Chrome"]
115
115
  JAW -->|send| TG["📱 Telegram"]
116
-
116
+
117
117
  style JAW fill:#f5e6d3,stroke:#d4a574,stroke-width:2px,color:#5c4033
118
118
  ```
119
119
 
@@ -128,7 +128,6 @@ graph LR
128
128
  - 🔍 **Web search** — Real-time information via MCP tools.
129
129
  - ⏰ **Heartbeat jobs** — Schedule recurring tasks that run automatically.
130
130
 
131
-
132
131
  ---
133
132
 
134
133
  ## 📦 Skill System
@@ -138,26 +137,26 @@ graph LR
138
137
  <details>
139
138
  <summary>View all skills</summary>
140
139
 
141
- | Tier | Count | How it works |
142
- | -------------------- | :---: | --------------------------------------------------------- |
143
- | **Active Skills** | 17 | Auto-injected into every AI prompt. Always available. |
144
- | **Reference Skills** | 90 | AI reads them on-demand when you ask for a relevant task. |
140
+ | Tier | Count | How it works |
141
+ | -------------------------- | :---: | --------------------------------------------------------- |
142
+ | **Active Skills** | 17 | Auto-injected into every AI prompt. Always available. |
143
+ | **Reference Skills** | 90 | AI reads them on-demand when you ask for a relevant task. |
145
144
 
146
145
  #### Active Skills (always on)
147
146
 
148
- | Skill | What it does |
149
- | ------------------------------------------------------------------- | --------------------------------------------------------- |
150
- | `browser` | Chrome automation — snapshot, click, navigate, screenshot |
151
- | `github` | Issues, PRs, CI, code review via `gh` CLI |
152
- | `notion` | Create/manage Notion pages and databases |
153
- | `memory` | Persistent long-term memory across sessions |
154
- | `telegram-send` | Send photos, documents, voice messages to Telegram |
155
- | `vision-click` | Screenshot → AI finds coordinates → clicks (one command) |
156
- | `imagegen` | Generate/edit images via OpenAI Image API |
157
- | `pdf` / `docx` / `xlsx` | Read, create, edit office documents |
158
- | `screen-capture` | macOS screenshot and camera capture |
159
- | `openai-docs` | Up-to-date OpenAI API documentation |
160
- | `dev` / `dev-frontend` / `dev-backend` / `dev-data` / `dev-testing` | Development guidelines for sub-agents |
147
+ | Skill | What it does |
148
+ | ----------------------------------------------------------------------------- | ---------------------------------------------------------- |
149
+ | `browser` | Chrome automation — snapshot, click, navigate, screenshot |
150
+ | `github` | Issues, PRs, CI, code review via `gh` CLI |
151
+ | `notion` | Create/manage Notion pages and databases |
152
+ | `memory` | Persistent long-term memory across sessions |
153
+ | `telegram-send` | Send photos, documents, voice messages to Telegram |
154
+ | `vision-click` | Screenshot → AI finds coordinates → clicks (one command) |
155
+ | `imagegen` | Generate/edit images via OpenAI Image API |
156
+ | `pdf` / `docx` / `xlsx` | Read, create, edit office documents |
157
+ | `screen-capture` | macOS screenshot and camera capture |
158
+ | `openai-docs` | Up-to-date OpenAI API documentation |
159
+ | `dev` / `dev-frontend` / `dev-backend` / `dev-data` / `dev-testing` | Development guidelines for sub-agents |
161
160
 
162
161
  #### Reference Skills (on-demand)
163
162
 
@@ -189,6 +188,7 @@ Your assistant isn't tied to your desk. Chat from anywhere via Telegram:
189
188
  </details>
190
189
 
191
190
  **What you can do from Telegram:**
191
+
192
192
  - 💬 Chat with your assistant (any of 5 AI engines)
193
193
  - 🎤 Send voice messages (auto-transcribed)
194
194
  - 📎 Send files and photos for processing
@@ -196,6 +196,7 @@ Your assistant isn't tied to your desk. Chat from anywhere via Telegram:
196
196
  - 🔄 Switch AI engines on the fly
197
197
 
198
198
  **What your assistant sends back:**
199
+
199
200
  - AI responses with markdown formatting
200
201
  - Generated images, PDFs, documents
201
202
  - Scheduled task results (heartbeat jobs)
@@ -216,18 +217,18 @@ For complex tasks, your assistant delegates work to specialized sub-agents:
216
217
  ```mermaid
217
218
  graph TD
218
219
  USER["👤 Your Request"] --> TRIAGE["🔍 Triage — Simple or Complex?"]
219
-
220
+
220
221
  TRIAGE -->|Simple| DIRECT["⚡ Direct Response"]
221
222
  TRIAGE -->|Complex| PLAN["📝 Planning"]
222
-
223
+
223
224
  PLAN --> FE["🎨 Frontend"]
224
225
  PLAN --> BE["⚙️ Backend"]
225
226
  PLAN --> DATA["📊 Data"]
226
-
227
+
227
228
  FE --> GATE["🚪 Gate Review"]
228
229
  BE --> GATE
229
230
  DATA --> GATE
230
-
231
+
231
232
  GATE -->|Pass| NEXT["✅ Done"]
232
233
  GATE -->|Fail| RETRY["🔄 Debug & Retry"]
233
234
 
@@ -256,7 +257,7 @@ graph LR
256
257
  MJ -->|auto-sync| OC["OpenCode"]
257
258
  MJ -->|auto-sync| CP["Copilot"]
258
259
  MJ -->|auto-sync| AG["Antigravity"]
259
-
260
+
260
261
  style MJ fill:#f5e6d3,stroke:#d4a574,stroke-width:2px,color:#5c4033
261
262
  ```
262
263
 
@@ -304,13 +305,13 @@ jaw --home ~/my-project launchd --port 3458 # project → port 3458
304
305
 
305
306
  Each instance is fully independent — different working directory, different memory, different MCP config. Perfect for separating work/personal contexts or per-project AI setups.
306
307
 
307
- | Flag / Env | What it does |
308
- | --------------------- | ----------------------------------------- |
308
+ | Flag / Env | What it does |
309
+ | ----------------------- | ----------------------------------------- |
309
310
  | `--home <path>` | Use a custom home directory for this run |
310
- | `--home=<path>` | Same, with `=` syntax |
311
+ | `--home=<path>` | Same, with `=` syntax |
311
312
  | `CLI_JAW_HOME=<path>` | Set via environment variable |
312
313
  | `jaw clone <target>` | Clone current instance to a new directory |
313
- | `--port <port>` | Custom port for `serve` / `launchd` |
314
+ | `--port <port>` | Custom port for `serve` / `launchd` |
314
315
 
315
316
  ---
316
317
 
@@ -321,13 +322,13 @@ Each CLI comes with preconfigured presets, but you can type **any model ID** dir
321
322
  <details>
322
323
  <summary>View all presets</summary>
323
324
 
324
- | CLI | Default | Notable Models |
325
- | ------------ | -------------------------- | ----------------------------------------------- |
325
+ | CLI | Default | Notable Models |
326
+ | ------------------ | ---------------------------- | ----------------------------------------------- |
326
327
  | **Claude** | `claude-sonnet-4-6` | opus-4-6, haiku-4-5, extended thinking variants |
327
328
  | **Codex** | `gpt-5.3-codex` | spark, 5.2, 5.1-max, 5.1-mini |
328
329
  | **Gemini** | `gemini-2.5-pro` | 3.0-pro-preview, 3-flash-preview, 2.5-flash |
329
- | **OpenCode** | `claude-opus-4-6-thinking` | 🆓 big-pickle, GLM-5, MiniMax, Kimi, GPT-5-Nano |
330
- | **Copilot** | `gpt-4.1` 🆓 | 🆓 gpt-5-mini, claude-sonnet-4.6, opus-4.6 |
330
+ | **OpenCode** | `claude-opus-4-6-thinking` | 🆓 big-pickle, GLM-5, MiniMax, Kimi, GPT-5-Nano |
331
+ | **Copilot** | `gpt-4.1` 🆓 | 🆓 gpt-5-mini, claude-sonnet-4.6, opus-4.6 |
331
332
 
332
333
  </details>
333
334
 
@@ -335,6 +336,56 @@ Each CLI comes with preconfigured presets, but you can type **any model ID** dir
335
336
 
336
337
  ---
337
338
 
339
+ ## 🐳 Docker — Container Isolation
340
+
341
+ Run CLI-JAW in a Docker container for **security isolation** — AI agents cannot access host files.
342
+
343
+ ```bash
344
+ # Quick start (after npm publish)
345
+ docker compose up -d
346
+ # → http://localhost:3457
347
+
348
+ # Or build manually
349
+ docker build -t cli-jaw .
350
+ docker run -d -p 3457:3457 --env-file .env --name jaw cli-jaw
351
+ ```
352
+
353
+ <details>
354
+ <summary>📋 Docker details</summary>
355
+
356
+ **Two Dockerfiles:**
357
+
358
+ | File | Purpose | Use Case |
359
+ | ------------------ | -------------------------- | ----------------------- |
360
+ | `Dockerfile` | Installs from npm registry | Production / deployment |
361
+ | `Dockerfile.dev` | Builds from local source | Development / testing |
362
+
363
+ ```bash
364
+ # Dev build (local source)
365
+ docker build -f Dockerfile.dev -t cli-jaw:dev .
366
+ docker run -d -p 3457:3457 --env-file .env cli-jaw:dev
367
+
368
+ # Pin version for CI
369
+ docker build --build-arg CLI_JAW_VERSION=1.0.1 -t cli-jaw:1.0.1 .
370
+
371
+ # If Chromium sandbox fails in your environment
372
+ docker run -e CHROME_NO_SANDBOX=1 -p 3457:3457 cli-jaw
373
+ ```
374
+
375
+ **Security:**
376
+
377
+ - Non-root `jaw` user — Chromium sandbox enabled by default
378
+ - No `ipc: host` or `seccomp=unconfined` — full container isolation
379
+ - `--no-sandbox` only via explicit `CHROME_NO_SANDBOX=1` opt-in
380
+ - Build-time feature guard prevents outdated image deployment
381
+
382
+ **Volumes:** Data persists in `jaw-data` named volume (`/home/jaw/.cli-jaw`).
383
+ To use existing host config: `-v ~/.cli-jaw:/home/jaw/.cli-jaw`
384
+
385
+ </details>
386
+
387
+ ---
388
+
338
389
  ## 🛠️ Development
339
390
 
340
391
  <details>
@@ -378,7 +429,7 @@ src/
378
429
  ## 🧪 Tests
379
430
 
380
431
  <details>
381
- <summary>383 pass · 1 skipped · zero external dependencies</summary>
432
+ <summary>445 pass · 1 skipped · zero external dependencies</summary>
382
433
 
383
434
  ```bash
384
435
  npm test
@@ -392,8 +443,8 @@ All tests run via `tsx --test` (native Node.js test runner + TypeScript).
392
443
 
393
444
  ## 📖 Documentation
394
445
 
395
- | Document | What's inside |
396
- | --------------------------------------- | ----------------------------------------------------- |
446
+ | Document | What's inside |
447
+ | ------------------------------------ | ----------------------------------------------------- |
397
448
  | [ARCHITECTURE.md](docs/ARCHITECTURE.md) | System design, module graph, REST API (40+ endpoints) |
398
449
  | [TESTS.md](TESTS.md) | Test coverage and test plan |
399
450
 
@@ -404,15 +455,16 @@ All tests run via `tsx --test` (native Node.js test runner + TypeScript).
404
455
  <details>
405
456
  <summary>Common issues</summary>
406
457
 
407
- | Problem | Solution |
408
- | ---------------------------- | ------------------------------------------------------------------------------------------- |
409
- | `cli-jaw: command not found` | Run `npm install -g cli-jaw` again. Check `npm bin -g` is in your `$PATH`. |
410
- | `Error: node version` | Upgrade to Node.js ≥ 22: `nvm install 22` or download from [nodejs.org](https://nodejs.org) |
411
- | Agent timeout / no response | Run `jaw doctor` to check CLI auth. Re-authenticate with `claude auth` / `codex login`. |
458
+ | Problem | Solution |
459
+ | ------------------------------ | --------------------------------------------------------------------------------------------- |
460
+ | `cli-jaw: command not found` | Run `npm install -g cli-jaw` again. Check `npm bin -g` is in your `$PATH`. |
461
+ | `Error: node version` | Upgrade to Node.js ≥ 22:`nvm install 22` or download from [nodejs.org](https://nodejs.org) |
462
+ | Agent timeout / no response | Run `jaw doctor` to check CLI auth. Re-authenticate with `claude auth` / `codex login`. |
412
463
  | `EADDRINUSE: port 3457` | Another instance is running. Stop it or use `jaw serve --port 3458`. |
413
- | Telegram bot not responding | Check token with `jaw doctor`. Ensure `jaw serve` is running. |
414
- | Skills not loading | Run `jaw skill reset` then `jaw mcp sync`. |
415
- | Browser commands fail | Install Chrome/Chromium. Run `jaw browser start` first. |
464
+ | Telegram bot not responding | Check token with `jaw doctor`. Ensure `jaw serve` is running. |
465
+ | Telegram ✓✓ delayed | Normal Telegram server-side delivery ack can take a few minutes under load. Not a bug. |
466
+ | Skills not loading | Run `jaw skill reset` then `jaw mcp sync`. |
467
+ | Browser commands fail | Install Chrome/Chromium. Run `jaw browser start` first. |
416
468
 
417
469
  </details>
418
470
 
package/README.zh-CN.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  *Claude、Codex、Gemini... 从此告别来回切换。*
8
8
 
9
- [![Tests](https://img.shields.io/badge/tests-383%20pass-brightgreen)](#-测试)
9
+ [![Tests](https://img.shields.io/badge/tests-445%20pass-brightgreen)](#-测试)
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue)](https://typescriptlang.org)
11
11
  [![Node](https://img.shields.io/badge/node-%3E%3D22-blue)](https://nodejs.org)
12
12
  [![License](https://img.shields.io/badge/license-ISC-yellow)](LICENSE)
@@ -14,7 +14,7 @@
14
14
 
15
15
  [English](README.md) / [한국어](README.ko.md) / **中文**
16
16
 
17
- ![CLI-JAW Web UI](docs/screenshots/web-ui.png)
17
+ <video src="https://github.com/user-attachments/assets/a7cf17c9-bfb3-44f0-b7fd-d001a39643fd" autoplay loop muted playsinline width="100%"></video>
18
18
 
19
19
  </div>
20
20
 
@@ -79,9 +79,10 @@ gemini # Google Gemini — 首次运行触发认证
79
79
  ## CLI-JAW 是什么?
80
80
 
81
81
  CLI-JAW 是驻留在您本地机器上的**专属 AI 助手**,并在您熟悉的界面中运行 — **网页、终端和 Telegram**。您可以向它提出任何问题、委派任务或是自动化您的工作流。
82
+ ![CLI-JAW Web UI](image/README/1772128366759.png)
82
83
 
83
- > 💬 *"帮我整理一下今天的日程"* → 直接在 Telegram 上收到整理好的结果
84
- > 💬 *"重构这个模块,顺便写好测试"* → 子 Agent 搞定,你喝杯咖啡回来就行
84
+ > 💬 *"帮我整理一下今天的日程"* → 直接在 Telegram 上收到整理好的结果
85
+ > 💬 *"重构这个模块,顺便写好测试"* → 子 Agent 搞定,你喝杯咖啡回来就行
85
86
  > 💬 *"把那个 PDF 下载下来,关键信息放到 Notion 里"* → 浏览器 + Notion 技能组合,搞定
86
87
 
87
88
  与单一模型的助手不同,CLI-JAW 通过官方 CLI 命令行工具对 **5 大 AI 引擎**(Claude、Codex、Gemini、OpenCode、Copilot)进行编排 — 为您提供各大供应商最优势的能力及统一的体验。当一个引擎处于繁忙状态时,它会自动无缝切换至下一个。107 个内置技能可处理从浏览器自动化到文档生成的所有事务。
@@ -93,7 +94,7 @@ CLI-JAW 是驻留在您本地机器上的**专属 AI 助手**,并在您熟悉
93
94
  | ⚡ **多模型自动回退 (Fallback)** | 单一引擎发生故障?下一个立即接管。确保零停机。 |
94
95
  | 🎭 **基于编排的性能优化** | 复杂的任务会被拆分给专业的子智能体,以实现效率最大化。 |
95
96
  | 📦 **107 个内置技能** | 浏览器自动化、文档生成、Telegram 通知、持久化记忆 — 开箱即用。 |
96
- | 🖥️ **跨平台支持** | macOS、Linux、Windows (WSL) 浏览器启动、CLI 检测、安装均原生支持。 |
97
+ | 🖥️ **跨平台支持** | macOS、Linux、Windows — ENOENT-safe CLI 启动、自动检测、`.cmd` 支持,跨平台原生运行。 |
97
98
 
98
99
  ![CLI-JAW 终端](docs/screenshots/terminal-cli.png)
99
100
 
@@ -343,6 +344,19 @@ jaw --home ~/my-project launchd --port 3458 # 项目 → 端口 3458
343
344
 
344
345
  ---
345
346
 
347
+ ## 🐳 Docker — 容器隔离
348
+
349
+ 在 Docker 容器中运行以实现安全隔离 — AI 代理无法访问主机文件。
350
+
351
+ ```bash
352
+ docker compose up -d # → http://localhost:3457
353
+ ```
354
+
355
+ > 详细信息请参阅 [English README](README.md#-docker--container-isolation)。
356
+ > 提供 `Dockerfile`(npm 发布版)和 `Dockerfile.dev`(本地源码构建)两种方式。
357
+
358
+ ---
359
+
346
360
  ## 🛠️ 开发
347
361
 
348
362
  <details>
@@ -386,7 +400,7 @@ src/
386
400
  ## 🧪 测试
387
401
 
388
402
  <details>
389
- <summary>383 pass · 1 skipped · 零外部依赖</summary>
403
+ <summary>445 pass · 1 skipped · 零外部依赖</summary>
390
404
 
391
405
  ```bash
392
406
  npm test
@@ -415,6 +429,7 @@ npm test
415
429
  | `doctor` 显示 CLI 缺失 | 对应 CLI 未安装 | 按提示安装,如 `npm i -g @anthropic-ai/claude-code` |
416
430
  | 端口 3457 被占用 | 其他进程占用了端口 | 改用 `PORT=4000 jaw serve` 或终止占用进程 |
417
431
  | Telegram 机器人无响应 | Token 未配置或缺少 Chat ID | 重新运行 `jaw init --telegram-token ...` |
432
+ | Telegram ✓✓ 延迟显示 | Telegram 服务器端交付确认时序 | 正常行为 — 服务器负载较高时可能延迟数分钟,非 Bug |
418
433
  | `npm install -g` 权限错误 | 全局目录权限不足 | 使用 `sudo npm i -g cli-jaw` 或推荐 [nvm](https://github.com/nvm-sh/nvm) |
419
434
  | 构建失败(`tsc` 报错) | Node 版本低于 22 | `node -v` 检查 → 升级至 22+ |
420
435
  | 会话间记忆未保留 | `~/.cli-jaw/memory/` 目录缺失 | 重新运行 `jaw init` 自动创建 |
@@ -11,6 +11,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
11
11
  const projectRoot = join(__dirname, '..', '..');
12
12
  const { values } = parseArgs({
13
13
  args: process.argv.slice(3),
14
+ allowNegative: true,
14
15
  options: {
15
16
  port: { type: 'string', default: process.env.PORT || '3457' },
16
17
  host: { type: 'string', default: '0.0.0.0' },
@@ -1 +1 @@
1
- {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../../bin/commands/serve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../../bin/commands/serve.ts"],"names":[],"mappings":"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"}
@@ -6,14 +6,30 @@ let _cachedToken = null;
6
6
  function getCopilotToken() {
7
7
  if (_cachedToken)
8
8
  return _cachedToken;
9
- try {
10
- _cachedToken = execSync('security find-generic-password -s "copilot-cli" -w', { encoding: 'utf8', timeout: 5000 }).trim();
9
+ // ─── DIFF-D: env-first fallback (cross-platform) ───
10
+ const envToken = process.env.COPILOT_GITHUB_TOKEN ||
11
+ process.env.GH_TOKEN ||
12
+ process.env.GITHUB_TOKEN;
13
+ if (envToken) {
14
+ _cachedToken = envToken;
15
+ return _cachedToken;
11
16
  }
12
- catch (e) {
13
- console.warn('[quota-copilot] keychain read failed:', e.message?.split('\n')[0]);
14
- return null;
17
+ // macOS only: Keychain lookup
18
+ if (process.platform === 'darwin') {
19
+ try {
20
+ _cachedToken = execSync('security find-generic-password -s "copilot-cli" -w', { encoding: 'utf8', timeout: 5000 }).trim();
21
+ }
22
+ catch (e) {
23
+ console.warn('[quota-copilot] keychain read failed:', e.message?.split('\n')[0]);
24
+ return null;
25
+ }
26
+ return _cachedToken || null;
27
+ }
28
+ // win32/linux: no keychain CLI — rely on env tokens above
29
+ if (process.env.DEBUG) {
30
+ console.info(`[quota-copilot] token lookup skipped on ${process.platform} (set COPILOT_GITHUB_TOKEN or GH_TOKEN)`);
15
31
  }
16
- return _cachedToken || null;
32
+ return null;
17
33
  }
18
34
  export async function fetchCopilotQuota() {
19
35
  const token = getCopilotToken();
@@ -1 +1 @@
1
- {"version":3,"file":"quota-copilot.js","sourceRoot":"","sources":["../../lib/quota-copilot.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,qDAAqD;AACrD,sDAAsD;AAEtD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,IAAI,YAAY,GAAkB,IAAI,CAAC;AAEvC,SAAS,eAAe;IACpB,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IACtC,IAAI,CAAC;QACD,YAAY,GAAG,QAAQ,CACnB,oDAAoD,EACpD,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CACtC,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,uCAAuC,EAAG,CAAW,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5F,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,YAAY,IAAI,IAAI,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACnC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,8CAA8C,EAAE;YACpE,OAAO,EAAE;gBACL,eAAe,EAAE,SAAS,KAAK,EAAE;gBACjC,gBAAgB,EAAE,eAAe;aACpC;YACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SACpC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAyB,CAAC;QAErD,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC;QACxC,MAAM,EAAE,GAAG,IAAI,CAAC,oBAAoB,IAAI,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,EAAE,CAAC;QAEnB,IAAI,CAAC,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC;gBACT,KAAK,EAAE,SAAS;gBAChB,IAAI,EAAE,EAAE,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,WAAW,CAAC;gBACvD,KAAK,EAAE,EAAE,CAAC,WAAW;gBACrB,OAAO,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,iBAAiB,IAAI,GAAG,CAAC;aAC/C,CAAC,CAAC;QACP,CAAC;QAED,OAAO;YACH,OAAO,EAAE;gBACL,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;gBACzB,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI;aAC9E;YACD,OAAO;YACP,SAAS,EAAE,IAAI,CAAC,gBAAgB,IAAI,IAAI;SAC3C,CAAC;IACN,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAG,CAAW,CAAC,OAAO,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,sBAAsB;IAClC,YAAY,GAAG,IAAI,CAAC;AACxB,CAAC"}
1
+ {"version":3,"file":"quota-copilot.js","sourceRoot":"","sources":["../../lib/quota-copilot.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -22,7 +22,7 @@ import { mergeSettingsPatch } from './src/core/settings-merge.js';
22
22
  import { setWss, broadcast } from './src/core/bus.js';
23
23
  import * as memory from './src/memory/memory.js';
24
24
  import { loadLocales, t, normalizeLocale } from './src/core/i18n.js';
25
- import { JAW_HOME, PROMPTS_DIR, DB_PATH, SKILLS_DIR, SKILLS_REF_DIR, settings, loadSettings, saveSettings, replaceSettings, ensureDirs, runMigration, loadHeartbeatFile, saveHeartbeatFile, detectAllCli, } from './src/core/config.js';
25
+ import { JAW_HOME, PROMPTS_DIR, DB_PATH, SKILLS_DIR, SKILLS_REF_DIR, settings, loadSettings, saveSettings, replaceSettings, ensureDirs, runMigration, loadHeartbeatFile, saveHeartbeatFile, detectAllCli, APP_VERSION, } from './src/core/config.js';
26
26
  import { db, getSession, updateSession, getMessages, getMessagesWithTrace, clearMessages, getMemory, upsertMemory, deleteMemory, getEmployees, insertEmployee, deleteEmployee, } from './src/core/db.js';
27
27
  import { initPromptFiles, getMemoryDir, regenerateB, A2_PATH, HEARTBEAT_PATH, getMergedSkills, } from './src/prompt/builder.js';
28
28
  import { activeProcess, killAllAgents, messageQueue, saveUpload, memoryFlushCounter, resetFallbackState, } from './src/agent/spawn.js';
@@ -237,7 +237,7 @@ function applySettingsPatch(rawPatch = {}, { restartTelegram = false } = {}) {
237
237
  }
238
238
  }
239
239
  if (restartTelegram && hasTelegramUpdate)
240
- initTelegram();
240
+ void initTelegram();
241
241
  return settings;
242
242
  }
243
243
  function seedDefaultEmployees({ reset = false, notify = false } = {}) {
@@ -265,6 +265,7 @@ function makeWebCommandCtx(req, localeOverride = null) {
265
265
  resetEmployees: () => seedDefaultEmployees({ reset: true, notify: true }),
266
266
  });
267
267
  }
268
+ app.get('/api/health', (_req, res) => res.json({ ok: true, version: APP_VERSION, uptime: process.uptime() }));
268
269
  app.get('/api/session', (_, res) => ok(res, getSession(), getSession()));
269
270
  app.get('/api/messages', (req, res) => {
270
271
  const includeTrace = ['1', 'true', 'yes'].includes(String(req.query.includeTrace || '').toLowerCase());
@@ -748,10 +749,16 @@ app.get('/api/i18n/:lang', (req, res) => {
748
749
  // ─── Start ───────────────────────────────────────────
749
750
  watchHeartbeatFile();
750
751
  // ─── Graceful Shutdown ──────────────────────────────
751
- ['SIGTERM', 'SIGINT'].forEach(sig => process.on(sig, () => {
752
+ ['SIGTERM', 'SIGINT'].forEach(sig => process.on(sig, async () => {
752
753
  console.log(`\n[server] ${sig} received, shutting down...`);
753
754
  stopHeartbeat();
754
755
  killAllAgents('shutdown');
756
+ if (telegramBot) {
757
+ try {
758
+ await telegramBot.stop();
759
+ }
760
+ catch { }
761
+ }
755
762
  wss.close();
756
763
  server.close(() => {
757
764
  console.log('[server] closed');
@@ -804,7 +811,7 @@ server.listen(PORT, () => {
804
811
  catch (e) {
805
812
  console.error('[mcp-init]', e.message);
806
813
  }
807
- initTelegram();
814
+ void initTelegram();
808
815
  startHeartbeat();
809
816
  // ─── Seed default employees if none exist ────────
810
817
  const seeded = seedDefaultEmployees();