deel-local-cli 1.5.8 → 1.6.1

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.
Files changed (59) hide show
  1. package/README.en.md +30 -14
  2. package/README.md +28 -12
  3. package/bin/deel.js +10 -0
  4. package/package.json +2 -2
  5. package/src/acp/map.js +143 -0
  6. package/src/acp/serve.js +166 -13
  7. package/src/agent/commit.js +511 -0
  8. package/src/agent/compact.js +269 -226
  9. package/src/agent/loop.js +196 -12
  10. package/src/agent/mention.js +56 -10
  11. package/src/agent/review.js +192 -0
  12. package/src/agent/session.js +22 -2
  13. package/src/agent/threads.js +1 -1
  14. package/src/backend/adapter.js +342 -280
  15. package/src/backend/azure.js +151 -0
  16. package/src/backend/ctxsize.js +19 -0
  17. package/src/backend/detect.js +106 -0
  18. package/src/backend/http.js +350 -30
  19. package/src/backend/probe.js +48 -1
  20. package/src/backend/proxy.js +151 -0
  21. package/src/backend/quota.js +133 -0
  22. package/src/backend/retry.js +132 -0
  23. package/src/backend/vision.js +185 -0
  24. package/src/commands.js +341 -8
  25. package/src/completion.js +264 -0
  26. package/src/config.js +117 -1
  27. package/src/i18n/en.js +13 -1
  28. package/src/i18n/index.js +22 -3
  29. package/src/i18n/ja.js +266 -0
  30. package/src/i18n/ko.js +12 -0
  31. package/src/i18n/zh.js +266 -0
  32. package/src/oneshot.js +28 -3
  33. package/src/pack/sbom.js +25 -0
  34. package/src/pack/selfpack.js +9 -3
  35. package/src/plugins/manage.js +34 -7
  36. package/src/repl.js +92 -6
  37. package/src/report.js +26 -2
  38. package/src/safety/guard.js +74 -2
  39. package/src/safety/keystore.js +237 -0
  40. package/src/safety/network.js +76 -14
  41. package/src/safety/policy.js +209 -0
  42. package/src/safety/secrets.js +32 -0
  43. package/src/setup.js +40 -7
  44. package/src/tools/clipboard.js +178 -0
  45. package/src/tools/convert.js +287 -0
  46. package/src/tools/docs.js +72 -1
  47. package/src/tools/fastgrep.js +217 -0
  48. package/src/tools/fsutil.js +55 -12
  49. package/src/tools/ignore.js +192 -0
  50. package/src/tools/index.js +391 -41
  51. package/src/tools/jobs.js +4 -12
  52. package/src/tools/outline.js +3 -1
  53. package/src/tools/pdf.js +1368 -0
  54. package/src/tools/shell.js +123 -0
  55. package/src/tools/verify.js +20 -4
  56. package/src/tools/webfetch.js +18 -5
  57. package/src/ui/inputbox.js +2 -2
  58. package/src/ui/screen.js +4 -1
  59. package/src/ui/status.js +22 -0
package/README.en.md CHANGED
@@ -18,7 +18,7 @@ Zero dependencies · Node 20+ · Exactly one place your source can go
18
18
 
19
19
  [![Node.js CI](https://img.shields.io/github/actions/workflow/status/jysvai/deel-local-cli/test.yml?branch=main&logo=github&logoColor=white&label=Node.js%20CI)](https://github.com/jysvai/deel-local-cli/actions/workflows/test.yml)
20
20
  [![CodeQL](https://img.shields.io/github/actions/workflow/status/jysvai/deel-local-cli/codeql.yml?branch=main&logo=github&logoColor=white&label=CodeQL)](https://github.com/jysvai/deel-local-cli/actions/workflows/codeql.yml)
21
- [![tests](https://img.shields.io/badge/tests-3%2C869%20passing-1a7f37?logo=checkmarx&logoColor=white)](docs/en/develop.md)
21
+ [![tests](https://img.shields.io/badge/tests-4%2C932%20passing-1a7f37?logo=checkmarx&logoColor=white)](docs/en/develop.md)
22
22
 
23
23
  [![dependencies](https://img.shields.io/badge/dependencies-0-1a7f37)](https://www.npmjs.com/package/deel-local-cli?activeTab=dependencies)
24
24
  [![ESM](https://img.shields.io/badge/ESM-Node%2020%2B-5FA04E?logo=javascript&logoColor=white)](package.json)
@@ -95,12 +95,12 @@ This page is the **summary**. Each section links to the detail behind it.
95
95
  | [Models](docs/en/models.md) | Grade and window size · Korean-model presets · project detection |
96
96
  | [The screen](docs/en/interface.md) | The input box · work modes · simple vs developer · what it asks about |
97
97
  | [Tools in depth](docs/en/tools.md) | `Outline` · `Verify` · `Task` · `Jobs` · `Append` · `Def`/`Refs` · edit matching |
98
- | [Korean documents and Excel](docs/en/documents.md) | hwpx/docx/pptx · encoding · Excel → CSV |
98
+ | [Korean documents and Excel](docs/en/documents.md) | hwpx/docx/pptx/**PDF** · encoding · Excel → CSV |
99
99
  | [Extending](docs/en/extend.md) | Skills · plugins · MCP · ACP |
100
100
  | [Speed and spend](docs/en/tuning.md) | Per-stage effort · the prefix cache · context length |
101
101
  | [Safety and corporate review](docs/en/safety.md) | Undo · working scope · audit log · the review package |
102
102
  | [Configuration](docs/en/config.md) · [Development](docs/en/develop.md) | Env vars · run flags · running the tests · folder layout |
103
- | [Release notes](docs/en/releases.md) | [1.5.8](docs/en/releases.md#158) · [1.5.7](docs/en/releases.md#157) · [1.5.6](docs/en/releases.md#156) · [1.5.5](docs/en/releases.md#155) · [1.5.4](docs/en/releases.md#154) · [1.5.3](docs/en/releases.md#153) · [1.5.2](docs/en/releases.md#152) · [1.5.1](docs/en/releases.md#151) · [1.5.0](docs/en/releases.md#150) · [1.4.3](docs/en/releases.md#143) · [1.4.2](docs/en/releases.md#142) · [1.4.1](docs/en/releases.md#141) · [1.4.0](docs/en/releases.md#140) · [1.3.0](docs/en/releases.md#130) · [1.2.0](docs/en/releases.md#120) |
103
+ | [Release notes](docs/en/releases.md) | [1.6.1](docs/en/releases.md#161) · [1.6.0](docs/en/releases.md#160) · [1.5.8](docs/en/releases.md#158) · [1.5.7](docs/en/releases.md#157) · [1.5.6](docs/en/releases.md#156) · [1.5.5](docs/en/releases.md#155) · [1.5.4](docs/en/releases.md#154) · [1.5.3](docs/en/releases.md#153) · [1.5.2](docs/en/releases.md#152) · [1.5.1](docs/en/releases.md#151) · [1.5.0](docs/en/releases.md#150) · [1.4.3](docs/en/releases.md#143) · [1.4.2](docs/en/releases.md#142) · [1.4.1](docs/en/releases.md#141) · [1.4.0](docs/en/releases.md#140) · [1.3.0](docs/en/releases.md#130) · [1.2.0](docs/en/releases.md#120) |
104
104
 
105
105
  ---
106
106
 
@@ -207,19 +207,23 @@ reviewer catches one drifted claim, they stop trusting the rest of it.
207
207
 
208
208
  ## Quick start
209
209
 
210
- ### The screen speaks English too
210
+ ### The screen speaks your language
211
211
 
212
212
  deel is written in Korean — the code, the function names, the comments. That part stays.
213
- What you see on screen does not have to.
213
+ What you see on screen does not have to. Four screen languages ship: **한국어 · English ·
214
+ 日本語 · 中文**, all four complete.
214
215
 
215
216
  ```bash
216
- DEEL_LANG=en deel # this run only
217
+ DEEL_LANG=en deel # this run only (also ja, zh)
217
218
  /lang en # and remember it
219
+ /lang ja # 日本語
220
+ /lang zh # 中文
218
221
  /lang # how much is translated so far
219
222
  ```
220
223
 
221
- Untranslated lines come through in Korean rather than as blanks, and `/lang` tells you exactly
222
- how many are left.
224
+ Nothing ever comes through blank. A line that has not been translated falls back to English
225
+ first and Korean second — so a Japanese or Chinese screen degrades to English, not to Korean —
226
+ and `/lang` prints exactly how many strings are covered.
223
227
 
224
228
  What the model reads follows the same switch. Set it to English and the rules, the mode
225
229
  instructions, and the tool descriptions all go out in English — so the model answers you in
@@ -379,6 +383,7 @@ Names follow Claude Code / Codex conventions.
379
383
  | `/learned [clear]` | What deel has picked up on its own — commands that work here, this model's habits |
380
384
  | `/pin <text>` | Pin a line — folding and compaction **cannot reach it** |
381
385
  | `/evidence [file]` | Evidence — what changed, and what proves it. **What is unproven is listed too** |
386
+ | `/commit [all\|preview\|title]` | Commits only what this session changed; message from the diff and the evidence. **Never pushes** |
382
387
  | `/model` | Switch connection / model |
383
388
  | `/model 카드` | Model card — what this model has actually done here, and what deel changed because of it |
384
389
  | `/think <level>` | Reasoning level (`off·low·medium·high·max`) |
@@ -421,10 +426,11 @@ the conversation.
421
426
  | `Ctrl+O` | Work mode (`종합` → `코드` → `계획` → …) |
422
427
  | `↑` `↓` | Input history |
423
428
  | `Ctrl+C` | Stops the answer in progress; twice on an empty line quits |
429
+ | Typing while it works, then `Enter` | Steers without throwing anything away — takes effect from the next step |
424
430
 
425
431
  Korean IME composition, paste, `Ctrl+A/E` and backspace all keep working.
426
432
 
427
- > **More** — Attaching a file with @ · Interrupting
433
+ > **More** — Attaching a file with @ · Interrupting · Steering without stopping
428
434
  >
429
435
  > **[The screen read →](docs/en/interface.md#slash-commands)**
430
436
 
@@ -493,7 +499,7 @@ Names and arguments match Claude Code, so skills written for that convention wor
493
499
 
494
500
  | Tool | What it does |
495
501
  |---|---|
496
- | `Read` | Read a file (line numbers, `offset`/`limit`, **Excel as CSV, hwpx/docx/pptx as text**) |
502
+ | `Read` | Read a file (line numbers, `offset`/`limit`, **Excel as CSV, hwpx/docx/pptx and PDF as text**) |
497
503
  | `Write` | Write / overwrite a file (**several at once via the `files` array**) |
498
504
  | `Append` | Append to the end of a file — **how large files get written in pieces** |
499
505
  | `Edit` | Replace an exact string (`replace_all`; **several sites at once via the `edits` array**) |
@@ -530,7 +536,12 @@ their cost; here is why.
530
536
  **A file saved as CP949 is written back as CP949.** The encoding is never changed.
531
537
  Excel (`.xlsx`) is read as CSV — read-only.
532
538
 
533
- > **More** Encoding · Excel
539
+ Old formats (`.ppt`, `.doc`, `.xls`, `.rtf`) are read by **borrowing the LibreOffice already
540
+ on this machine** — the same terms on which deel borrows `rg`, and nothing is ever installed.
541
+ With no converter it **says so definitively and stops**: what is missing, what you can do about
542
+ it, and not to open the file again. Turn it off with `DEEL_CONVERT=off`.
543
+
544
+ > **More** — Encoding · Excel · borrowing a converter
534
545
  >
535
546
  > **[Korean documents and Excel read →](docs/en/documents.md#korean-text-and-excel)**
536
547
 
@@ -767,6 +778,7 @@ stdio. It is not a command you type yourself.
767
778
  | Approval dialog | deel's safety rails, rendered as the editor's own prompt (`allow once` · `always allow` · `reject`) |
768
779
  | Mode picker | deel's seven work modes (auto · code · plan · architect · debug · ask · orchestrator) |
769
780
  | Stop button | Reaches the turn mid-flight, even while waiting on the model |
781
+ | Past conversations | Still there after a restart. They live in the **same place** as the terminal's, so a session started in the editor can be picked up with `deel --resume` |
770
782
 
771
783
  **Still zero dependencies.** Same reason as MCP — newline-delimited JSON-RPC 2.0 is the whole
772
784
  transport, so no SDK is needed.
@@ -918,13 +930,15 @@ Stored in `~/.deel/config.json`. A `.deel/config.json` in the project folder tak
918
930
  | `address not found` | Typo, DNS, VPN / intranet connectivity |
919
931
  | `connection refused` | Server is down or the port differs |
920
932
  | certificate error | `set NODE_EXTRA_CA_CERTS=C:\path\corp-ca.pem` |
921
- | behind a proxy | `set HTTPS_PROXY=http://proxy:port` |
933
+ | behind a proxy | `set HTTPS_PROXY=http://proxy:port` (with auth: `http://user:pw@proxy:port`). If the first screen and `/status` show `proxy …`, it is in use. Exclude hosts with `NO_PROXY=.corp.com,10.1.2.3`; turn it off entirely with `"proxy": "none"` in the config |
934
+ | the proxy answers 407 | Put `user:pw@` into the proxy address. Proxies that only accept NTLM · Negotiate are not supported — ask the admin for Basic or an unauthenticated address |
922
935
  | 401 / 403 | Wrong key or auth header style (four are tried automatically) |
923
936
  | `address not permitted` | The lock did its job — pick a connection with `/model` |
924
937
  | Tool calls don't work | Run `deel diagnose`. Small models (1B–3B) often can't |
925
938
  | Empty replies | The server ignores streaming. deel retries once, then turns streaming off for the session |
926
939
  | Large files cut off mid-write | Check `/out` and raise it — the cap may be sitting at the 16,384 default because it could not be discovered |
927
940
  | Only `HTTP 400` shows | The server's own message is shown verbatim. If it is a length problem the number is read and applied automatically |
941
+ | `429` · `503` shows | The gateway pushed back for a moment. deel waits and calls again, up to three times (honouring `Retry-After`). If it keeps happening, check your quota |
928
942
  | `deel scan` finds nothing | Server is off or on another port — use `--ports` |
929
943
 
930
944
  ---
@@ -932,7 +946,7 @@ Stored in `~/.deel/config.json`. A `.deel/config.json` in the project folder tak
932
946
  ## Development
933
947
 
934
948
  ```bash
935
- npm test Full suite (3,869 checks)
949
+ npm test Full suite (4,932 checks)
936
950
  npm run coverage Which lines the tests actually execute
937
951
  npm run verify Import + network checks only
938
952
  npm run bench Edit success rate
@@ -957,7 +971,7 @@ so one run tells you everything.
957
971
  | `guard` | 24 | **What it refuses to do** — denied edits, unknown tools, repeated mutations, out-of-scope writes |
958
972
  | `network` | 30 | Nothing escapes the configured address |
959
973
  | `web` | 25 | Web reads stay read-only |
960
- | `abort` | 16 | Ctrl+C leaves the conversation valid |
974
+ | `abort` · `steer` | 16 · 15 | Ctrl+C leaves the conversation valid · a line typed mid-turn rides the next call |
961
975
  | `parallel` | 23 | Read-only tools run together; checklists |
962
976
  | `cli` | 75 | **Spawns the real `deel`** and drives it to completion |
963
977
  | `setup` | 42 | First-run wizard, driven through a fake TTY |
@@ -984,6 +998,8 @@ so one run tells you everything.
984
998
 
985
999
  | Version | What changed |
986
1000
  |---|---|
1001
+ | **[1.6.1](docs/en/releases.md#161)** | The places that made a turn spin in circles — the fence blocking `/dev/null` · old documents it could not read · images vanishing from files |
1002
+ | **[1.6.0](docs/en/releases.md#160)** | The things that did not work on a corporate network — proxy · 429 · Windows shell · 50k-file repos · PDF · clipboard paste · editor resume |
987
1003
  | **[1.5.8](docs/en/releases.md#158)** | A 5MB document showed 8 lines out of 919 · a regex read as a path blocked the command |
988
1004
  | **[1.5.7](docs/en/releases.md#157)** | Korean folders on macOS made your own files "out of scope" · paste · ESC |
989
1005
  | **[1.5.6](docs/en/releases.md#156)** | It asks when stuck — instead of writing a question and ending the turn |
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  [![Node.js CI](https://img.shields.io/github/actions/workflow/status/jysvai/deel-local-cli/test.yml?branch=main&logo=github&logoColor=white&label=Node.js%20CI)](https://github.com/jysvai/deel-local-cli/actions/workflows/test.yml)
20
20
  [![CodeQL](https://img.shields.io/github/actions/workflow/status/jysvai/deel-local-cli/codeql.yml?branch=main&logo=github&logoColor=white&label=CodeQL)](https://github.com/jysvai/deel-local-cli/actions/workflows/codeql.yml)
21
- [![tests](https://img.shields.io/badge/tests-3%2C869%20passing-1a7f37?logo=checkmarx&logoColor=white)](docs/ko/develop.md)
21
+ [![tests](https://img.shields.io/badge/tests-4%2C932%20passing-1a7f37?logo=checkmarx&logoColor=white)](docs/ko/develop.md)
22
22
 
23
23
  [![dependencies](https://img.shields.io/badge/dependencies-0-1a7f37)](https://www.npmjs.com/package/deel-local-cli?activeTab=dependencies)
24
24
  [![ESM](https://img.shields.io/badge/ESM-Node%2020%2B-5FA04E?logo=javascript&logoColor=white)](package.json)
@@ -96,12 +96,12 @@
96
96
  | [모델 다루기](docs/ko/models.md) | 급과 창 크기 · 국산 모델 이름표 · 켤 때 프로젝트 읽기 |
97
97
  | [화면과 조작](docs/ko/interface.md) | 입력칸 · 작업 모드 · 쉬움과 개발자 · 무엇을 묻고 무엇을 그냥 하나 |
98
98
  | [도구 자세히](docs/ko/tools.md) | `Outline` · `Verify` · `Task` · `Jobs` · `Append` · `Def`/`Refs` · 편집 매칭 |
99
- | [한글 문서와 엑셀](docs/ko/documents.md) | hwpx·docx·pptx · 인코딩 · 엑셀 → CSV |
99
+ | [한글 문서와 엑셀](docs/ko/documents.md) | hwpx·docx·pptx·**PDF** · 인코딩 · 엑셀 → CSV |
100
100
  | [늘려 쓰기](docs/ko/extend.md) | 스킬 · 플러그인 · MCP · ACP |
101
101
  | [속도와 씀씀이](docs/ko/tuning.md) | 단계별 추론 강도 · 프리픽스 캐시 · 컨텍스트 길이 |
102
102
  | [안전망과 사내 반입](docs/ko/safety.md) | 되돌리기 · 작업 범위 · 감사기록 · 심사 서류 |
103
103
  | [설정](docs/ko/config.md) · [개발](docs/ko/develop.md) | 환경변수 · 실행 옵션 · 검사 돌리기 · 폴더 구조 |
104
- | [릴리스 노트](docs/ko/releases.md) | [1.5.8](docs/ko/releases.md#158) · [1.5.7](docs/ko/releases.md#157) · [1.5.6](docs/ko/releases.md#156) · [1.5.5](docs/ko/releases.md#155) · [1.5.4](docs/ko/releases.md#154) · [1.5.3](docs/ko/releases.md#153) · [1.5.2](docs/ko/releases.md#152) · [1.5.1](docs/ko/releases.md#151) · [1.5.0](docs/ko/releases.md#150) · [1.4.3](docs/ko/releases.md#143) · [1.4.2](docs/ko/releases.md#142) · [1.4.1](docs/ko/releases.md#141) · [1.4.0](docs/ko/releases.md#140) · [1.3.0](docs/ko/releases.md#130) · [1.2.0](docs/ko/releases.md#120) |
104
+ | [릴리스 노트](docs/ko/releases.md) | [1.6.1](docs/ko/releases.md#161) · [1.6.0](docs/ko/releases.md#160) · [1.5.8](docs/ko/releases.md#158) · [1.5.7](docs/ko/releases.md#157) · [1.5.6](docs/ko/releases.md#156) · [1.5.5](docs/ko/releases.md#155) · [1.5.4](docs/ko/releases.md#154) · [1.5.3](docs/ko/releases.md#153) · [1.5.2](docs/ko/releases.md#152) · [1.5.1](docs/ko/releases.md#151) · [1.5.0](docs/ko/releases.md#150) · [1.4.3](docs/ko/releases.md#143) · [1.4.2](docs/ko/releases.md#142) · [1.4.1](docs/ko/releases.md#141) · [1.4.0](docs/ko/releases.md#140) · [1.3.0](docs/ko/releases.md#130) · [1.2.0](docs/ko/releases.md#120) |
105
105
 
106
106
  ---
107
107
 
@@ -342,7 +342,7 @@ LM Studio 는 `/api/v0/models`, llama.cpp 는 `/props`. 못 알아보면 `(추
342
342
  |---|---|
343
343
  | `/help` | 명령 목록 |
344
344
  | `/bell [on|off]` | 다 됐을 때·물어볼 때 종소리와 창 제목 |
345
- | `/lang [ko|en] [시킬말]` | 화면 말. **시킬 말을 따로 줄 수 있다** — `/lang ko en` 이면 모델에게는 영어로 시키고 답은 한국어로 받는다(8k 창에서 고정 몫 23% 감소). 코드는 그대로 |
345
+ | `/lang [ko|en|ja|zh] [시킬말]` | 화면 (한국어·English·日本語·中文 네 가지, 전부 다 채워져 있다). **시킬 말을 따로 줄 수 있다** — `/lang ko en` 이면 모델에게는 영어로 시키고 답은 한국어로 받는다(8k 창에서 고정 몫 23% 감소). 코드는 그대로 |
346
346
  | `/keys` | 이 터미널이 무슨 키를 보내는지 눌러서 확인 — 줄바꿈이 안 될 때 |
347
347
  | `/consult <프로필> <질문>` | 다른 모델에게 한 번 물어보기 — 지금 쓰는 것은 안 바꿈 |
348
348
  | `/export` | 이 대화를 **보고서 한 장**(HTML)으로 — 시킨 것·바뀐 것·확인한 것. 폐쇄망에서 여는 자기완결 파일 |
@@ -357,6 +357,7 @@ LM Studio 는 `/api/v0/models`, llama.cpp 는 `/props`. 못 알아보면 `(추
357
357
  | `/learned [지우기]` | 쓰면서 저절로 알게 된 것 — 되는 명령·이 모델의 버릇 |
358
358
  | `/pin <말>` | 못 박기 — 접거나 요약해도 **안 지워지는** 말 |
359
359
  | `/evidence [파일]` | 증거 — 무엇을 바꿨고 무엇이 그걸 증명하나. **안 된 것도** 적습니다 |
360
+ | `/commit [전부\|미리보기\|제목]` | 이번 대화가 바꾼 것만 담아 커밋. 메시지는 diff 와 증거에서. **push 는 안 합니다** |
360
361
  | `/model` | 연결·모델 바꾸기 |
361
362
  | `/model 카드` | 이 모델을 겪어 본 결과 — 그래서 deel 이 무엇을 바꿔 뒀는지 |
362
363
  | `/think <강도>` | 추론 강도 (`off·low·medium·high·max`) |
@@ -396,10 +397,11 @@ LM Studio 는 `/api/v0/models`, llama.cpp 는 `/props`. 못 알아보면 `(추
396
397
  | `Ctrl+O` | 작업 모드 (`종합` → `코드` → `계획` → …) |
397
398
  | `↑` `↓` | 지난 입력 이력 |
398
399
  | `Ctrl+C` | 답하는 중이면 그 답만 끊고, 빈 줄에서 두 번이면 끝냅니다 |
400
+ | 일하는 중에 그냥 치고 `Enter` | 하던 일을 안 버리고 방향만 틉니다 — 다음 걸음부터 반영 |
399
401
 
400
402
  한글 조합·붙여넣기·`Ctrl+A/E`·백스페이스는 전부 그대로 됩니다.
401
403
 
402
- > **자세히** — @파일 로 바로 붙이기 · 도중에 멈추기
404
+ > **자세히** — @파일 로 바로 붙이기 · 도중에 멈추기 · 멈추지 않고 방향만 틀기
403
405
  >
404
406
  > **[화면과 조작 읽기 →](docs/ko/interface.md#대화-중-명령)**
405
407
 
@@ -468,7 +470,7 @@ LM Studio 는 `/api/v0/models`, llama.cpp 는 `/props`. 못 알아보면 `(추
468
470
 
469
471
  | 도구 | 하는 일 |
470
472
  |---|---|
471
- | `Read` | 파일 읽기 (줄 번호 · `offset`/`limit` 지원 · **엑셀은 CSV 로, hwpx·docx·pptx 는 글로 바꿔서**) |
473
+ | `Read` | 파일 읽기 (줄 번호 · `offset`/`limit` 지원 · **엑셀은 CSV 로, hwpx·docx·pptx·PDF 는 글로 바꿔서**) |
472
474
  | `Write` | 파일 쓰기·덮어쓰기 (**여러 개는 `files` 배열로 한 번에**) |
473
475
  | `Append` | 파일 끝에 이어 붙이기 — **큰 파일을 나눠 쓰는 자리** |
474
476
  | `Edit` | 정확한 문자열 바꾸기 (`replace_all` · **여러 군데는 `edits` 배열로 한 번에**) |
@@ -504,10 +506,19 @@ Claude Code 에 없는 것은 아홉입니다 — `Append` · `Move` · `Ask` ·
504
506
  ## 한글 문서와 엑셀
505
507
 
506
508
  **CP949 로 저장된 파일은 CP949 로 되돌려 씁니다.** 인코딩을 바꾸지 않습니다.
507
- 엑셀(`.xlsx`)은 CSV 로, 한글·워드·파워포인트(`.hwpx`/`.docx`/`.pptx`)는 글로
508
- 바꿔서 읽습니다 — 전부 읽기 전용입니다.
509
+ 엑셀(`.xlsx`)은 CSV 로, 한글·워드·파워포인트(`.hwpx`/`.docx`/`.pptx`)
510
+ **PDF** 는 글로 바꿔서 읽습니다 — 전부 읽기 전용입니다.
509
511
 
510
- > **자세히** 인코딩 · 엑셀 · hwpx/docx/pptx
512
+ PDF **못 읽은 쪽을 읽었다고 말합니다.** 스캔본·암호·글꼴 표가 없는 쪽은
513
+ 빈 글로 넘기지 않고 그 자리에 까닭을 적습니다 — 빈 글은 「그런 내용이 없다」로
514
+ 읽히기 때문입니다.
515
+
516
+ 옛 형식(`.ppt`·`.doc`·`.xls`·`.rtf`)은 **이 PC 에 깔린 LibreOffice 를 빌려서**
517
+ 읽습니다 — `rg` 를 빌려 쓰는 것과 같은 원칙으로, 아무것도 설치하지 않습니다.
518
+ 없으면 **없다고 못 박고 끝냅니다**(무엇이 없어서 못 하는지, 무엇을 하면 되는지,
519
+ 그리고 「다시 열지 말라」까지). 끄려면 `DEEL_CONVERT=off`.
520
+
521
+ > **자세히** — 인코딩 · 엑셀 · hwpx/docx/pptx · PDF · 변환기 빌려 쓰기
511
522
  >
512
523
  > **[한글 문서와 엑셀 읽기 →](docs/ko/documents.md#한글-문서와-엑셀)**
513
524
 
@@ -742,6 +753,7 @@ deel acp
742
753
  | 승인 창 | deel 의 안전망이 그대로 에디터 창으로 뜹니다 (`이번만` · `앞으로 묻지 않기` · `안 함`) |
743
754
  | 모드 고르개 | deel 의 작업 모드 7개 (`종합` · `코드` · `계획` · `설계` · `디버그` · `묻기` · `총괄`) |
744
755
  | 멈춤 단추 | 도중에 닿습니다 — 답을 기다리는 중에도 |
756
+ | 지난 대화 | 껐다 켜도 그대로 열립니다. 터미널과 **같은 자리**에 남아서, 에디터에서 하던 것을 `deel --resume` 으로 이어받는 것도 됩니다 |
745
757
 
746
758
  **의존성은 그대로 0 입니다.** MCP 와 같은 이유입니다 — 줄 단위 JSON-RPC 2.0 이
747
759
  전부라 SDK 가 필요 없습니다.
@@ -896,13 +908,15 @@ deel sbom --only sbom # SBOM 한 장만
896
908
  | `주소를 찾을 수 없습니다` | 주소 오타, DNS, 사내망 접속 여부 |
897
909
  | `연결이 거부되었습니다` | 서버가 꺼져 있거나 포트가 다름 |
898
910
  | `인증서 문제` | `set NODE_EXTRA_CA_CERTS=C:\경로\사내CA.pem` |
899
- | 프록시를 거쳐야 함 | `set HTTPS_PROXY=http://프록시:포트` |
911
+ | 프록시를 거쳐야 함 | `set HTTPS_PROXY=http://프록시:포트` (인증은 `http://user:pw@프록시:포트`). 첫 화면과 `/status` 에 `프록시 …` 가 뜨면 거치는 것. 안 거칠 곳은 `NO_PROXY=.corp.com,10.1.2.3`, 아예 끄려면 설정에 `"proxy": "none"` |
912
+ | 프록시가 407 을 줌 | 프록시 주소에 `user:pw@` 를 넣으세요. NTLM · Negotiate 만 받는 프록시는 못 씁니다 — 담당자에게 Basic 이나 인증 없는 주소를 문의 |
900
913
  | 401 / 403 | 키가 틀렸거나 인증 헤더 형식이 다름 (4가지를 자동 시도합니다) |
901
914
  | `허용되지 않은 주소입니다` | 자물쇠가 막은 것. 정상입니다 — `/model` 로 연결을 고르세요 |
902
915
  | 도구 호출이 안 먹음 | `deel diagnose` 로 판정을 보세요. 작은 모델(1B~3B)은 자주 못 합니다 |
903
916
  | 대답이 비어 있음 | 스트리밍을 무시하는 서버입니다. 한 번은 저절로 다시 부르고, 그래도 비면 이 대화에서는 스트리밍을 끕니다 |
904
917
  | 큰 파일이 중간에 끊김 | `/out` 으로 지금 상한을 보고 올리세요. 상한을 몰라 16,384 로 서 있을 수 있습니다 |
905
918
  | `HTTP 400` 만 뜸 | 서버가 보낸 문장을 그대로 보여 줍니다. 길이 문제면 숫자를 읽어 저절로 맞춥니다 |
919
+ | `429` · `503` 이 뜸 | 게이트웨이가 잠깐 막은 것입니다. 세 번까지 저절로 기다렸다 다시 부릅니다(`Retry-After` 를 지킵니다). 그래도 계속 뜨면 할당량을 보세요 |
906
920
  | `deel scan` 이 0곳 | 로컬 서버가 꺼져 있거나 다른 포트 — `--ports` 로 지정 |
907
921
 
908
922
  ---
@@ -910,7 +924,7 @@ deel sbom --only sbom # SBOM 한 장만
910
924
  ## 개발
911
925
 
912
926
  ```bash
913
- npm test 전체 검증 (3,869항목)
927
+ npm test 전체 검증 (4,932항목)
914
928
  npm run coverage 검사가 소스의 어디를 밟았는지
915
929
  npm run verify 반입·통신 검증만
916
930
  npm run bench 편집 성공률 측정
@@ -948,7 +962,7 @@ zip 은 진짜 `unzip` 으로, tar 는 진짜 `tar` 가 만든 것을 읽혀 교
948
962
  | `guard` | 24 | **안 하는 자리** — 거부·모르는 도구·두 번 실행·범위 밖 |
949
963
  | `network` | 30 | 정해진 자리 밖으로 새지 않는가 |
950
964
  | `web` | 25 | 웹 읽기가 읽기만 하는가 |
951
- | `abort` | 16 | Ctrl+C 로 끊어도 대화가 성한가 |
965
+ | `abort` · `steer` | 16 · 15 | Ctrl+C 로 끊어도 대화가 성한가 · 도중에 낀 말이 다음 부름에 실리는가 |
952
966
  | `parallel` | 23 | 읽기만 동시에 도는가 · 할 일 목록 |
953
967
  | `cli` | 75 | **진짜 `deel` 을 띄워** 끝까지 돌려 본다 |
954
968
  | `setup` | 42 | 첫 실행 마법사 (가짜 TTY 로 사람처럼 입력) |
@@ -975,6 +989,8 @@ zip 은 진짜 `unzip` 으로, tar 는 진짜 `tar` 가 만든 것을 읽혀 교
975
989
 
976
990
  | 판 | 무엇이 바뀌었나 |
977
991
  |---|---|
992
+ | **[1.6.1](docs/ko/releases.md#161)** | 헛도는 턴을 만들던 자리들 — 울타리가 `/dev/null` 까지 막던 것 · 옷 문서를 못 읽던 것 · 파일에서 그림이 사라지던 것 |
993
+ | **[1.6.0](docs/ko/releases.md#160)** | 사내망에서 안 되던 것들 — 프록시 · 429 · 윈도우 셸 · 5만 개 저장소 · PDF · 캡처 붙여넣기 · 에디터 이어하기 |
978
994
  | **[1.5.8](docs/ko/releases.md#158)** | 5MB 문서를 919줄 중 8줄만 보던 것 · 정규식을 경로로 읽어 명령을 막던 것 |
979
995
  | **[1.5.7](docs/ko/releases.md#157)** | 맥 한글 폴더에서 제 파일이 「범위 밖」이던 것 · 붙여넣기 · ESC |
980
996
  | **[1.5.6](docs/ko/releases.md#156)** | 막히면 물어본다 — 글로 묻고 턴을 끝내는 대신에 |
package/bin/deel.js CHANGED
@@ -13,6 +13,7 @@ import { closeConnections } from '../src/backend/http.js';
13
13
  import { parseSize } from '../src/backend/ctxsize.js';
14
14
  import { runSessions } from '../src/agent/sessionui.js';
15
15
  import { acp } from '../src/acp/serve.js';
16
+ import { runCompletion } from '../src/completion.js';
16
17
 
17
18
  const MIN_NODE = 20;
18
19
 
@@ -137,6 +138,7 @@ function help() {
137
138
  say(` ${c.cyan('deel setup')} 연결 설정 (주소·키·모델)`);
138
139
  say(` ${c.cyan('deel status')} 연결 상태 보기`);
139
140
  say(` ${c.cyan('deel diagnose')} 저장된 연결로 진단 다시 돌리기`);
141
+ say(` ${c.cyan('deel completion <셸>')} 탭 완성 스크립트 ${c.gray('(bash · zsh · powershell)')}`);
140
142
  say(` ${c.cyan('deel --version')} 판 번호 ${c.gray('(-v 도 됩니다)')}`);
141
143
  say('');
142
144
  say(` ${c.bold('여러 로컬을 같이 쓸 때')}`);
@@ -298,6 +300,14 @@ async function main() {
298
300
  case 'sessions':
299
301
  case 'ls':
300
302
  return runSessions(flags);
303
+ /*
304
+ * 탭 완성 스크립트를 낸다 (src/completion.js).
305
+ *
306
+ * 표준출력으로만 낸다 — `deel completion bash > ~/.deel-completion.bash`
307
+ * 처럼 바로 파이프에 물릴 수 있어야 한다. 그래서 여기서는 say() 를 안 쓴다.
308
+ */
309
+ case 'completion':
310
+ return runCompletion(args);
301
311
  default:
302
312
  say('');
303
313
  say(` ${c.red('모르는 명령')} ${c.bold(cmd)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deel-local-cli",
3
- "version": "1.5.8",
3
+ "version": "1.6.1",
4
4
  "description": "로컬 모델·사내 게이트웨이 전용 코딩 에이전트 CLI — 외부 의존성 0개 / Zero-dependency coding agent CLI for local LLMs and private gateways",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -51,7 +51,7 @@
51
51
  "verify": "node test/no-bundle.test.js && node test/network.test.js && node test/web.test.js",
52
52
  "bench": "node test/edit-bench.js",
53
53
  "demo": "node test/demo.js",
54
- "check": "node --check bin/deel.js && node --check src/repl.js && node --check src/oneshot.js && node --check src/commands.js && node --check src/agent/loop.js && node --check src/agent/session.js && node --check src/agent/effort.js && node --check src/agent/modes.js && node --check src/agent/route.js && node --check src/agent/models.js && node --check src/agent/grade.js && node --check src/agent/mention.js && node --check src/agent/project.js && node --check src/tools/encoding.js && node --check src/tools/excel-com.js && node --check src/tools/excel.js && node --check src/tools/xlsx.js && node --check src/tools/docs.js && node --check src/agent/compact.js && node --check src/agent/store.js && node --check src/agent/sessionui.js && node --check src/backend/adapter.js && node --check src/backend/ctxsize.js && node --check src/backend/probe.js && node --check src/backend/detect.js && node --check src/backend/http.js && node --check src/backend/scan.js && node --check src/backend/scanui.js && node --check src/tools/index.js && node --check src/tools/desc.en.js && node --check src/tools/lsp.js && node --check src/lsp/rpc.js && node --check src/lsp/servers.js && node --check src/lsp/client.js && node --check src/lsp/diag.js && node --check src/tools/fsutil.js && node --check src/tools/edit-match.js && node --check src/tools/webfetch.js && node --check src/tools/todo.js && node --check src/tools/jobs.js && node --check src/skills/discover.js && node --check src/plugins/manage.js && node --check src/pack/zip.js && node --check src/pack/tar.js && node --check src/pack/selfpack.js && node --check src/safety/guard.js && node --check src/safety/undo.js && node --check src/safety/audit.js && node --check src/safety/network.js && node --check src/setup.js && node --check src/report.js && node --check src/config.js && node --check src/ui/diff.js && node --check src/ui/ansi.js && node --check src/ui/status.js && node --check src/ui/level.js && node --check src/ui/prompt.js && node --check src/ui/spinner.js && node --check src/ui/motion.js && node --check src/ui/office.js && node --check src/ui/notify.js && node --check src/ui/intro.js && node --check src/ui/banner.js && node --check src/ui/export.js && node --check src/i18n/index.js && node --check src/i18n/ko.js && node --check src/i18n/en.js && node --check src/preview/serve.js && node --check src/ui/working.js && node --check src/ui/inputbox.js && node --check src/ui/wrap.js && node --check src/ui/md.js && node --check src/agent/threads.js && node --check src/agent/evolve.js && node --check src/agent/pins.js && node --check src/agent/card.js && node --check src/agent/preset.js && node --check src/agent/evidence.js && node --check src/acp/jsonrpc.js && node --check src/acp/map.js && node --check src/acp/serve.js && node --check src/pack/sbom.js && node --check src/safety/secrets.js && echo OK",
54
+ "check": "node --check bin/deel.js && node --check src/repl.js && node --check src/oneshot.js && node --check src/commands.js && node --check src/agent/loop.js && node --check src/agent/session.js && node --check src/agent/effort.js && node --check src/agent/modes.js && node --check src/agent/route.js && node --check src/agent/models.js && node --check src/agent/grade.js && node --check src/agent/mention.js && node --check src/agent/project.js && node --check src/tools/encoding.js && node --check src/tools/excel-com.js && node --check src/tools/excel.js && node --check src/tools/xlsx.js && node --check src/tools/docs.js && node --check src/tools/convert.js && node --check src/tools/pdf.js && node --check src/tools/clipboard.js && node --check src/agent/compact.js && node --check src/agent/store.js && node --check src/agent/sessionui.js && node --check src/backend/adapter.js && node --check src/backend/ctxsize.js && node --check src/backend/probe.js && node --check src/backend/detect.js && node --check src/backend/http.js && node --check src/backend/retry.js && node --check src/backend/proxy.js && node --check src/backend/azure.js && node --check src/backend/vision.js && node --check src/backend/quota.js && node --check src/backend/scan.js && node --check src/backend/scanui.js && node --check src/tools/index.js && node --check src/tools/desc.en.js && node --check src/tools/lsp.js && node --check src/lsp/rpc.js && node --check src/lsp/servers.js && node --check src/lsp/client.js && node --check src/lsp/diag.js && node --check src/tools/fsutil.js && node --check src/tools/ignore.js && node --check src/tools/fastgrep.js && node --check src/tools/edit-match.js && node --check src/tools/webfetch.js && node --check src/tools/todo.js && node --check src/tools/jobs.js && node --check src/tools/shell.js && node --check src/skills/discover.js && node --check src/plugins/manage.js && node --check src/pack/zip.js && node --check src/pack/tar.js && node --check src/pack/selfpack.js && node --check src/safety/guard.js && node --check src/safety/undo.js && node --check src/safety/audit.js && node --check src/safety/keystore.js && node --check src/safety/policy.js && node --check src/safety/network.js && node --check src/setup.js && node --check src/report.js && node --check src/config.js && node --check src/completion.js && node --check src/ui/diff.js && node --check src/ui/ansi.js && node --check src/ui/status.js && node --check src/ui/level.js && node --check src/ui/prompt.js && node --check src/ui/spinner.js && node --check src/ui/motion.js && node --check src/ui/office.js && node --check src/ui/notify.js && node --check src/ui/intro.js && node --check src/ui/banner.js && node --check src/ui/export.js && node --check src/i18n/index.js && node --check src/i18n/ko.js && node --check src/i18n/en.js && node --check src/i18n/ja.js && node --check src/i18n/zh.js && node --check src/preview/serve.js && node --check src/ui/working.js && node --check src/ui/inputbox.js && node --check src/ui/wrap.js && node --check src/ui/md.js && node --check src/agent/threads.js && node --check src/agent/evolve.js && node --check src/agent/pins.js && node --check src/agent/card.js && node --check src/agent/preset.js && node --check src/agent/evidence.js && node --check src/agent/commit.js && node --check src/agent/review.js && node --check src/acp/jsonrpc.js && node --check src/acp/map.js && node --check src/acp/serve.js && node --check src/pack/sbom.js && node --check src/safety/secrets.js && echo OK",
55
55
  "coverage": "node test/coverage.mjs",
56
56
  "prepublishOnly": "npm run check && npm test"
57
57
  },
package/src/acp/map.js CHANGED
@@ -175,6 +175,149 @@ export function 멈춘까닭(까닭) {
175
175
  }
176
176
  }
177
177
 
178
+ /**
179
+ * 메시지 하나에서 사람이 읽을 글만 뽑는다.
180
+ *
181
+ * content 는 글 한 덩어리일 때도 있고, 그림이 섞인 배열일 때도 있다
182
+ * (backend/vision.js). 배열에서 글만 빼고 그림은 조용히 버리면, 되살린
183
+ * 화면에서 "이 말을 왜 했는지" 가 사라진다 — 몇 장이 붙어 있었는지는 적는다.
184
+ */
185
+ function 글만(m) {
186
+ const c = m?.content;
187
+ let 글 = '';
188
+ let 장수 = Array.isArray(m?.images) ? m.images.length : 0; // ollama 규격
189
+ if (typeof c === 'string') 글 = c;
190
+ else if (Array.isArray(c)) {
191
+ const 조각 = [];
192
+ for (const p of c) {
193
+ if (p?.type === 'text' && typeof p.text === 'string') 조각.push(p.text);
194
+ else if (p?.type === 'image_url') 장수++;
195
+ }
196
+ 글 = 조각.join('\n');
197
+ }
198
+ 글 = 글.trim();
199
+ if (장수) 글 = 글 ? `${글}\n\n_(그림 ${장수}장)_` : `_(그림 ${장수}장)_`;
200
+ return 글;
201
+ }
202
+
203
+ /** 저장된 도구 인자. 규격에 따라 글일 수도, 이미 풀린 것일 수도 있다. */
204
+ function 인자풀기(x) {
205
+ if (x && typeof x === 'object') return x;
206
+ if (typeof x !== 'string' || !x.trim()) return {};
207
+ try { return JSON.parse(x); } catch { return {}; }
208
+ }
209
+
210
+ /**
211
+ * 저장된 대화를 에디터에 다시 흘려 줄 알림 묶음으로.
212
+ *
213
+ * ── 왜 이 자리가 필요한가 ───────────────────────────────────────────────
214
+ *
215
+ * session/load 는 "지난 대화를 되살려라" 는 부름인데, 규격에는 되살린 것을
216
+ * **답으로 돌려주는 자리가 없다.** 오간 말을 전부 session/update 로 다시
217
+ * 흘려야 한다. 그러니까 에디터가 그리는 지난 대화는 여기서 만든 것이 전부다 —
218
+ * 여기서 빠뜨린 것은 화면에서 통째로 사라지고, 사람은 기록이 날아간 줄 안다.
219
+ *
220
+ * 도구 호출은 시작·끝 두 번으로 안 나눈다. 이미 끝난 일을 '도는 중' 으로 한 번
221
+ * 그렸다가 고칠 까닭이 없다. 끝난 모습 한 덩이만 준다.
222
+ *
223
+ * @param {object[]} messages store.js 가 읽어 온 대화
224
+ * @returns {object[]} session/update 의 update 자리에 그대로 넣을 것들
225
+ */
226
+ export function 되살린것(messages, { 최대내용 = 2000 } = {}) {
227
+ const 줄 = Array.isArray(messages) ? messages : [];
228
+
229
+ /*
230
+ * 도구 답을 먼저 줄 세운다.
231
+ *
232
+ * 답(role:'tool')은 부름보다 뒤에 온다. 앞에서부터 한 번에 그리려면 미리
233
+ * 찾아 둬야 한다. OpenAI 규격은 id 로 짝을 짓고, ollama 규격은 id 를 안 주므로
234
+ * 이름별 차례로 짝을 짓는다 (session.js 의 repairToolPairs 와 같은 눈).
235
+ */
236
+ const id로 = new Map();
237
+ const 이름으로 = new Map();
238
+ for (const m of 줄) {
239
+ if (m?.role !== 'tool') continue;
240
+ if (m.tool_call_id != null) id로.set(m.tool_call_id, m.content);
241
+ else if (m.tool_name) {
242
+ const q = 이름으로.get(m.tool_name) ?? [];
243
+ q.push(m.content);
244
+ 이름으로.set(m.tool_name, q);
245
+ }
246
+ }
247
+
248
+ const 나온것 = [];
249
+ let 말번호 = 0;
250
+ let 도구번호 = 0;
251
+
252
+ for (const m of 줄) {
253
+ if (!m || typeof m !== 'object') continue;
254
+ // 시스템 프롬프트는 사람이 한 말이 아니다. 되살리면 매번 대화 머리에
255
+ // 수천 자짜리 지시문이 붙어서, 정작 무슨 얘기를 했는지가 안 보인다.
256
+ if (m.role === 'system' || m.role === 'tool') continue;
257
+
258
+ if (m.role === 'user') {
259
+ const 글 = 글만(m);
260
+ if (글) 나온것.push({ sessionUpdate: 'user_message_chunk', content: { type: 'text', text: 글 } });
261
+ continue;
262
+ }
263
+ if (m.role !== 'assistant') continue;
264
+
265
+ 말번호++;
266
+ const 생각 = typeof m.thinking === 'string' ? m.thinking.trim() : '';
267
+ if (생각) {
268
+ 나온것.push({
269
+ sessionUpdate: 'agent_thought_chunk',
270
+ content: { type: 'text', text: 자르기(생각, 최대내용) },
271
+ messageId: `h${말번호}`,
272
+ });
273
+ }
274
+ const 글 = 글만(m);
275
+ if (글) {
276
+ 나온것.push({
277
+ sessionUpdate: 'agent_message_chunk',
278
+ content: { type: 'text', text: 글 },
279
+ messageId: `h${말번호}`,
280
+ });
281
+ }
282
+
283
+ for (const tc of Array.isArray(m.tool_calls) ? m.tool_calls : []) {
284
+ const fn = tc?.function ?? tc ?? {};
285
+ const 이름 = String(fn.name ?? tc?.name ?? '도구');
286
+ const 인자 = 인자풀기(fn.arguments ?? fn.args ?? tc?.args);
287
+
288
+ let 답;
289
+ if (tc?.id != null && id로.has(tc.id)) 답 = id로.get(tc.id);
290
+ else {
291
+ const q = 이름으로.get(이름);
292
+ if (q?.length) 답 = q.shift();
293
+ }
294
+
295
+ /*
296
+ * 답이 안 남은 부름 = 그때 프로그램이 도구 도는 중에 끊긴 것이다.
297
+ *
298
+ * 성공으로 그리면 안 된다. 그 도구가 끝까지 갔는지 아닌지가 다음에 무엇을
299
+ * 시킬지를 정한다 — 파일을 고치던 중이었을 수도 있다.
300
+ */
301
+ const 없음 = 답 === undefined || 답 === null;
302
+ 나온것.push({
303
+ sessionUpdate: 'tool_call',
304
+ toolCallId: `h${말번호}-${++도구번호}`,
305
+ title: 도구이름표(이름, 인자),
306
+ kind: 도구갈래(이름),
307
+ // 남은 글만 보고 성공·실패를 점치지 않는다. 도구마다 실패를 적는 말이
308
+ // 달라서, 맞히려 들면 멀쩡한 것을 빨갛게 칠하게 된다.
309
+ status: 없음 ? 'failed' : 'completed',
310
+ content: 없음
311
+ ? [{ type: 'content', content: { type: 'text', text: '결과가 안 남았습니다 — 이 도구가 도는 중에 끊겼습니다.' } }]
312
+ : [{ type: 'content', content: { type: 'text', text: 자르기(String(답), 최대내용) } }],
313
+ locations: 도구자리(이름, 인자, null),
314
+ });
315
+ }
316
+ }
317
+
318
+ return 나온것;
319
+ }
320
+
178
321
  /**
179
322
  * 프롬프트로 온 덩이들에서 글만 뽑는다.
180
323
  *