deel-local-cli 1.1.1 → 1.2.0

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
@@ -54,6 +54,7 @@
54
54
  - [쉬움 · 개발자](#쉬움--개발자)
55
55
  - [도구](#도구)
56
56
  - [한글 문서와 엑셀](#한글-문서와-엑셀)
57
+ - [만든 웹을 그 자리에서 띄웁니다](#만든-웹을-그-자리에서-띄웁니다)
57
58
  - [스킬·플러그인](#스킬플러그인)
58
59
  - [추론 강도](#추론-강도)
59
60
  - [자동 압축](#자동-압축)
@@ -64,6 +65,9 @@
64
65
  - [설정](#설정)
65
66
  - [문제 해결](#문제-해결)
66
67
  - [개발](#개발)
68
+ - [릴리스 노트](#릴리스-노트)
69
+
70
+ 각 절은 요약만 펴 두었습니다. **▸ 자세히** 를 누르면 그 안의 이야기가 펼쳐집니다.
67
71
 
68
72
  ---
69
73
 
@@ -212,6 +216,9 @@ LM Studio 는 `/api/v0/models`, llama.cpp 는 `/props`. 못 알아보면 `(추
212
216
 
213
217
  등록한 뒤에는 대화 중 `/model` 로 갈아탑니다. **대화 내용은 그대로 이어집니다.**
214
218
 
219
+ <details>
220
+ <summary><b>자세히</b> — 걸린 모델에 맞춰 스스로 바뀝니다 · 작은 창에서는 고정 몫을 줄입니다 · 켤 때 이 폴더가 무슨 프로젝트인지 읽습니다</summary>
221
+
215
222
  ### 걸린 모델에 맞춰 스스로 바뀝니다
216
223
 
217
224
  여러 모델을 왔다 갔다 쓰면, 어느 한 모델에 맞춰 박아 둔 숫자는 나머지 전부에서
@@ -354,6 +361,8 @@ node 프로젝트 (deel-local-cli) · git main
354
361
 
355
362
  파일 600개짜리 폴더에서 7ms 입니다(`test/project.test.js`).
356
363
 
364
+ </details>
365
+
357
366
  ---
358
367
 
359
368
  ## 대화 중 명령
@@ -369,6 +378,8 @@ node 프로젝트 (deel-local-cli) · git main
369
378
  | `/grade [작음\|보통\|큼\|auto]` | 모델 **급** — 얼마나 알아서 하나. `/ctx` 와 다른 축입니다 |
370
379
  | `/compact` | 앞선 대화를 요약해서 접기 |
371
380
  | `/clear` | 대화 비우기 (연결·규칙은 유지) |
381
+ | `/thread [new\|fork\|close\|번호]` | 대화 갈래 — 곁가지를 딴 자리에서. 연결·되돌리기는 같이 씁니다 |
382
+ | `/learned [지우기]` | 쓰면서 저절로 알게 된 것 — 되는 명령·이 모델의 버릇 |
372
383
  | `/model` | 연결·모델 바꾸기 |
373
384
  | `/think <강도>` | 추론 강도 (`off·low·medium·high·max`) |
374
385
  | `/think 배분 <배분>` | 단계별 배분 (`균일·절약·깊게`) |
@@ -380,6 +391,7 @@ node 프로젝트 (deel-local-cli) · git main
380
391
  | `/level [수준]` | 화면에 무엇을 내놓을지 (`쉬움` · `개발자`) |
381
392
  | `/undo [턴수]` | 파일 변경 되돌리기 |
382
393
  | `/diff [파일]` | 이번 대화에서 바뀐 파일 · 바뀐 자리 보기 |
394
+ | `/preview [폴더\|파일\|off]` | 만든 웹을 이 자리에서 띄워 보기 — 브라우저가 같이 열립니다 |
383
395
  | `/tools` | 쓸 수 있는 도구 |
384
396
  | `/skills [검색어\|all\|off]` | 스킬 보기·검색·골라 올리기 |
385
397
  | `/plugin [install\|remove\|pack]` | 플러그인 관리 |
@@ -408,6 +420,9 @@ node 프로젝트 (deel-local-cli) · git main
408
420
 
409
421
  한글 조합·붙여넣기·`Ctrl+A/E`·백스페이스는 전부 그대로 됩니다.
410
422
 
423
+ <details>
424
+ <summary><b>자세히</b> — @파일 로 바로 붙이기 · 도중에 멈추기</summary>
425
+
411
426
  ### `@파일` 로 바로 붙이기
412
427
 
413
428
  말 속에 `@` 뒤로 경로를 쓰면 그 파일을 말과 함께 바로 보냅니다.
@@ -467,6 +482,8 @@ node 프로젝트 (deel-local-cli) · git main
467
482
 
468
483
  발견된 스킬의 명령은 `/<플러그인>:<이름>` 으로 부르고 `$ARGUMENTS` 가 치환됩니다.
469
484
 
485
+ </details>
486
+
470
487
  ---
471
488
 
472
489
  ## 작업 모드
@@ -495,6 +512,9 @@ node 프로젝트 (deel-local-cli) · git main
495
512
  `/think` 나 `/mode` 를 직접 고른 적이 있으면 그 선택이 우선합니다.
496
513
  모드가 사람이 고른 값을 덮어쓰지 않습니다.
497
514
 
515
+ <details>
516
+ <summary><b>자세히</b> — 저절로 옮겨 가기 (종합 모드)</summary>
517
+
498
518
  ### 저절로 옮겨 가기 (종합 모드)
499
519
 
500
520
  처음에는 **종합** 으로 시작합니다. 무슨 일이 올지 모르는 상태입니다.
@@ -537,6 +557,8 @@ node 프로젝트 (deel-local-cli) · git main
537
557
 
538
558
  직접 고르면 그때부터 **고정** 됩니다. 다시 맡기려면 `/auto` 또는 `/work 종합`.
539
559
 
560
+ </details>
561
+
540
562
  ---
541
563
 
542
564
  ## 쉬움 · 개발자
@@ -558,6 +580,9 @@ node 프로젝트 (deel-local-cli) · git main
558
580
  - **초보라고 승인을 덜 받지 않습니다.** 되돌리기·작업 범위·위험 명령 차단은 두 수준이 같습니다.
559
581
  초보일수록 되돌릴 수 있어야 합니다.
560
582
 
583
+ <details>
584
+ <summary><b>자세히</b> — 입력칸 · 명령은 다 안 쳐도 됩니다 · 일하는 중에는 상자가 그대로 있습니다 · 왼쪽 그림도 같이 움직입니다 외 1개</summary>
585
+
561
586
  ### 입력칸
562
587
 
563
588
  터미널에서 그냥 켜면 **대화는 위로 흘러가고, 맨 아래에 입력 상자가 붙습니다.**
@@ -747,6 +772,8 @@ node 프로젝트 (deel-local-cli) · git main
747
772
  > 방식이 화면에서 통째로 사라지고 있었습니다. 지금은 **모델 이름을 먼저 줄입니다** —
748
773
  > 무엇으로 도는지는 이미 알지만, 내 파일이 안 물어보고 바뀌는지는 지금 봐야 압니다.
749
774
 
775
+ </details>
776
+
750
777
  ---
751
778
 
752
779
  ## 도구
@@ -778,6 +805,9 @@ Claude Code 에 없는 것은 일곱입니다 — `Append` · `Recall` · `Remem
778
805
  (`test/loop.test.js`). 뒤의 넷은 그 값을 치르고도 넣을 만해서 넣은 것들이라,
779
806
  아래에 왜인지를 적어 뒀습니다.
780
807
 
808
+ <details>
809
+ <summary><b>자세히</b> — Outline · Verify · Task · 끝나지 않는 명령은 뒤에서 외 9개</summary>
810
+
781
811
  ### 프로젝트 모양을 싸게 봅니다 — `Outline`
782
812
 
783
813
  전에는 남의 코드를 이해하는 길이 둘뿐이었습니다. `Glob` 은 경로만 주고,
@@ -1190,10 +1220,18 @@ $ /diff
1190
1220
  `/diff` 는 **쉬움 수준의 명령 목록에도 들어 있습니다.** `auto` 가 안 물어보고
1191
1221
  고치는 이상, 초보일수록 '무엇이 바뀌었나' 를 볼 통로가 필요합니다.
1192
1222
 
1223
+ </details>
1224
+
1193
1225
  ---
1194
1226
 
1195
1227
  ## 한글 문서와 엑셀
1196
1228
 
1229
+ **CP949 로 저장된 파일은 CP949 로 되돌려 씁니다.** 인코딩을 바꾸지 않습니다.
1230
+ 엑셀(`.xlsx`)은 CSV 로 바꿔서 읽습니다 — 읽기 전용입니다.
1231
+
1232
+ <details>
1233
+ <summary><b>자세히</b> — 인코딩 · 엑셀</summary>
1234
+
1197
1235
  ### 인코딩 — 읽은 그대로 되돌려 씁니다
1198
1236
 
1199
1237
  사내 문서는 UTF-8 이 아닌 경우가 흔합니다. 윈도우 메모장이 오래 쓰던 완성형
@@ -1264,6 +1302,8 @@ utf8 로 받으면 한글이 깨집니다. 바이트로 받아서 풉니다.
1264
1302
  > 서식·수식·차트가 든 파일을 CSV 로 왕복시키면 반드시 뭔가 잃기 때문입니다.
1265
1303
  > 잃는 걸 알면서 쓰느니 안 쓰는 편이 낫습니다.
1266
1304
 
1305
+ </details>
1306
+
1267
1307
  ---
1268
1308
 
1269
1309
  ## 만든 웹을 그 자리에서 띄웁니다
@@ -1341,6 +1381,9 @@ utf8 로 받으면 한글이 깨집니다. 바이트로 받아서 풉니다.
1341
1381
 
1342
1382
  Claude Code 와 같은 형식(`SKILL.md` + YAML 앞머리, `commands/*.md`, `$ARGUMENTS`)을 읽습니다.
1343
1383
 
1384
+ <details>
1385
+ <summary><b>자세히</b> — 3단계로 나눠 올립니다 · 플러그인 받아 오기 · 안 넣은 것</summary>
1386
+
1344
1387
  ### 3단계로 나눠 올립니다
1345
1388
 
1346
1389
  전부 올리면 컨텍스트가 죽습니다.
@@ -1374,6 +1417,8 @@ unzip 반입.zip -d ~/.deel/plugins/
1374
1417
  | 서브에이전트 | 모델 호출이 배로 늘어 게이트웨이 할당량을 먹습니다 |
1375
1418
  | MCP | 별도 프로토콜이라 그 자체로 하나의 프로젝트입니다 |
1376
1419
 
1420
+ </details>
1421
+
1377
1422
  ---
1378
1423
 
1379
1424
  ## 추론 강도
@@ -1421,6 +1466,9 @@ $ /think 자세히
1421
1466
  이 한 줄로 갈립니다. 아는 상한이 낮으면 셋이 같아지는 것이 맞습니다.
1422
1467
  한동안 이 표는 세 줄이 늘 `16,384` 였고, 그건 표가 뜻이 없다는 뜻이었습니다.
1423
1468
 
1469
+ <details>
1470
+ <summary><b>자세히</b> — 컨텍스트 길이는 모델에서 긁어옵니다 · /out · 잘린 도구 호출</summary>
1471
+
1424
1472
  ### 컨텍스트 길이는 모델에서 긁어옵니다
1425
1473
 
1426
1474
  이 숫자 하나가 프로그램 전체 크기를 정합니다. 한 번에 읽힐 수 있는 파일 수,
@@ -1555,6 +1603,8 @@ This model's maximum context length is 8192 tokens, however you requested 41003
1555
1603
  '헛도는 작업' 을 구분하지 못합니다. 여기서 세는 것은 걸음 수가 아니라
1556
1604
  **같은 도구가 같은 이유로 실패한 횟수**입니다.
1557
1605
 
1606
+ </details>
1607
+
1558
1608
  ---
1559
1609
 
1560
1610
  ## 자동 압축
@@ -1623,6 +1673,9 @@ deel 은 그걸 **코드를 안 고치고** 도구로 씁니다.
1623
1673
  JSON-RPC 2.0 을 주고받는 것이 전부라, `child_process` 와 `JSON` 이면 됩니다. SDK 가
1624
1674
  필요 없습니다.
1625
1675
 
1676
+ <details>
1677
+ <summary><b>자세히</b> — 다만 이건 남의 프로그램입니다</summary>
1678
+
1626
1679
  ### 다만 이건 남의 프로그램입니다
1627
1680
 
1628
1681
  이 프로젝트가 존재하는 이유가 '미승인 SW 반입 금지' 인데, MCP 를 아무렇게나 켜면
@@ -1642,6 +1695,8 @@ JSON-RPC 2.0 을 주고받는 것이 전부라, `child_process` 와 `JSON` 이
1642
1695
  조용히 빠지지 않고 머리말에 이유가 뜹니다 — 조용히 빠지면 "왜 그 도구가 없지" 를
1643
1696
  영영 알 수 없습니다.
1644
1697
 
1698
+ </details>
1699
+
1645
1700
  ---
1646
1701
 
1647
1702
  ## 안전망
@@ -1670,6 +1725,9 @@ JSON-RPC 2.0 을 주고받는 것이 전부라, `child_process` 와 `JSON` 이
1670
1725
  32MB 를 넘으면 **최근 50턴만 남기고** 오래된 것을 버립니다. 방금 한 일은 언제나
1671
1726
  되돌릴 수 있고, 지금 이력이 얼마나 되는지는 `/status` 에서 봅니다.
1672
1727
 
1728
+ <details>
1729
+ <summary><b>자세히</b> — Bash 로 사라진 것도 되돌아갑니다 · 안 읽는 자리</summary>
1730
+
1673
1731
  ### `Bash` 로 사라진 것도 되돌아갑니다
1674
1732
 
1675
1733
  안전망이 `Write` · `Edit` 만 지키고 있었습니다. 그런데 모델은 파일을 옮길 때
@@ -1736,6 +1794,8 @@ JSON-RPC 2.0 을 주고받는 것이 전부라, `child_process` 와 `JSON` 이
1736
1794
  반드시 옵니다 — 훑을 때는 안 걸리는데 이름을 대면 읽히는, 설명하기 어려운
1737
1795
  상태가 됩니다.
1738
1796
 
1797
+ </details>
1798
+
1739
1799
  ---
1740
1800
 
1741
1801
  ## 사내 반입
@@ -1769,6 +1829,9 @@ zip 안에 들어가는 `반입심사서.txt` 에는 이런 것이 적힙니다.
1769
1829
  손으로 적지 않고 코드가 소스를 훑어서 만듭니다 — 손으로 적으면 언젠가 사실과 어긋납니다.
1770
1830
  묶지 않고 내용만 보려면 `deel audit`.
1771
1831
 
1832
+ <details>
1833
+ <summary><b>자세히</b> — 사내 게이트웨이 진단</summary>
1834
+
1772
1835
  ### 사내 게이트웨이 진단
1773
1836
 
1774
1837
  압축을 푼 폴더에서:
@@ -1792,12 +1855,17 @@ node bin/deel.js diagnose --url <게이트웨이주소> --key <키> --model <모
1792
1855
 
1793
1856
  판정은 **준비됨 · 제한적 · 막힘 · 연결실패** 넷 중 하나로 나옵니다.
1794
1857
 
1858
+ </details>
1859
+
1795
1860
  ---
1796
1861
 
1797
1862
  ## 설정
1798
1863
 
1799
1864
  `~/.deel/config.json` 에 저장됩니다. 프로젝트 폴더에 `.deel/config.json` 이 있으면 그쪽이 우선입니다.
1800
1865
 
1866
+ <details>
1867
+ <summary><b>자세히</b> — 붙는 서버 · 환경변수 · 실행 옵션 · 프로젝트 규칙</summary>
1868
+
1801
1869
  ### 붙는 서버
1802
1870
 
1803
1871
  주소만 넣으면 규격을 알아서 찾습니다.
@@ -1844,6 +1912,8 @@ deel --no-tui 입력 상자를 끄고 줄 화면으로 (아래 참고
1844
1912
  작업 폴더에 `DEEL.md` · `CLAUDE.md` · `AGENTS.md` 중 하나가 있으면 읽어서 규칙으로 씁니다.
1845
1913
  `/init` 으로 틀을 만들 수 있습니다.
1846
1914
 
1915
+ </details>
1916
+
1847
1917
  ---
1848
1918
 
1849
1919
  ## 문제 해결
@@ -1922,6 +1992,9 @@ zip 은 진짜 `unzip` 으로, tar 는 진짜 `tar` 가 만든 것을 읽혀 교
1922
1992
  | `no-bundle` | 12 | 배포 묶음에 남의 것이 안 섞였는가 · 검사 파일 위생 |
1923
1993
  | `edit-bench` | 20건 | 편집 성공률 |
1924
1994
 
1995
+ <details>
1996
+ <summary><b>자세히</b> — 어디를 밟았는지 · 폴더 구조</summary>
1997
+
1925
1998
  ### 어디를 밟았는지
1926
1999
 
1927
2000
  ```bash
@@ -1947,40 +2020,194 @@ node test/coverage.mjs --json 기계가 읽을 형태로
1947
2020
  ```
1948
2021
  bin/deel.js 진입점
1949
2022
  src/
1950
- ui/ 색·한글 폭·상자·상태줄·입력
2023
+ repl.js 대화 화면 — 사람이 마주하는 자리
2024
+ oneshot.js 한 번 돌리고 끝내기 (-p)
2025
+ commands.js / 명령 35종
2026
+ setup.js 처음 켤 때 연결 잡기
2027
+ config.js 설정 읽고 쓰기
2028
+
2029
+ ui/ansi.js 색 · 한글 폭 계산
1951
2030
  ui/screen.js 화면 고르기 (줄 화면 / 상자 화면)
1952
- ui/inputbox.js 맨 아래 입력 상자 — 그리기·지우기·커서 자리
2031
+ ui/inputbox.js 맨 아래 입력 상자 — 덮어 그리기·커서 자리
2032
+ ui/status.js 상태줄 — 모델·컨텍스트·모드·승인
1953
2033
  ui/working.js 일하는 중 문구 — 지금 하는 일을 따라간다
2034
+ ui/motion.js 문구 옆에서 도는 점자 그림
1954
2035
  ui/approve.js 승인 방식 표시 (자동/위험만/모두)
2036
+ ui/diff.js 고친 자리를 그 자리에서 보여 주기
1955
2037
  ui/wrap.js 색을 지키며 폭에 맞춰 접기
2038
+ ui/level.js 쉬움 · 개발자
2039
+
1956
2040
  agent/loop.js 에이전트 루프
1957
2041
  agent/session.js 대화 상태 + 컨텍스트 셈
2042
+ agent/modes.js 작업 모드 (종합·코드·계획·설계·디버그·묻기·총괄)
2043
+ agent/route.js 말을 보고 알맞은 모드 고르기
1958
2044
  agent/effort.js 단계별 추론 강도 배분
2045
+ agent/budget.js 창 크기에 맞춘 몫 — 읽을 줄·설명 길이·걸음 수
2046
+ agent/project.js 이 폴더가 무슨 프로젝트인지 읽기
1959
2047
  agent/compact.js 요약 압축
1960
2048
  agent/store.js 대화 저장·이어하기
1961
2049
  agent/recall.js 지난 대화 찾기 (색인 없이, 예산 안에서)
1962
2050
  agent/memory.js 대화가 끝나도 남는 것
2051
+ agent/mention.js `@파일` 붙이기
2052
+
1963
2053
  backend/http.js HTTP 한 겹 (바깥으로 나가는 유일한 문)
1964
2054
  backend/detect.js 규격·인증 자동 판별
1965
2055
  backend/adapter.js OpenAI/Ollama 차이 흡수 + 스트리밍 파서
2056
+ backend/ctxsize.js 컨텍스트 길이를 모델에서 긁어오기
1966
2057
  backend/probe.js 진단 검사 8종
1967
2058
  backend/scan.js 로컬 서버 훑기
1968
2059
  backend/mcp.js 밖에서 도구 붙이기 (MCP, stdio)
1969
- tools/index.js 도구 11종
2060
+
2061
+ tools/index.js 도구 15종
1970
2062
  tools/edit-match.js 단계별 완화 편집 매칭
1971
- tools/webfetch.js 읽기 (읽기 전용)
2063
+ tools/outline.js 파일 모양만 싸게 보기
2064
+ tools/verify.js 만든 것 확인
2065
+ tools/task.js 큰 일을 떼어 따로 돌리기
2066
+ tools/jobs.js 뒤에서 도는 명령
1972
2067
  tools/todo.js 할 일 목록
2068
+ tools/webfetch.js 웹 읽기 (읽기 전용)
2069
+ tools/encoding.js 읽은 인코딩 그대로 되돌려 쓰기
2070
+ tools/xlsx.js 엑셀 → CSV (직접 구현)
2071
+
2072
+ preview/serve.js 만든 웹 띄우기 (127.0.0.1 에만)
1973
2073
  skills/discover.js 그 PC 의 스킬·명령·플러그인 찾기
1974
2074
  plugins/manage.js 플러그인 설치·삭제·묶기
1975
2075
  pack/zip.js ZIP 쓰기 (직접 구현, 한글 이름 보존)
1976
2076
  pack/tar.js TAR 읽기 (직접 구현)
1977
2077
  pack/selfpack.js 반입 심사서 + 소스 묶기
2078
+
1978
2079
  safety/network.js 나가는 자리 자물쇠
1979
2080
  safety/guard.js 작업 범위 + 위험 명령 차단
1980
2081
  safety/undo.js 스냅샷·되돌리기
2082
+ safety/audit.js 무엇을 언제 했는지 남기기
1981
2083
  test/ 검증 (배포 묶음에서 뺀다)
1982
2084
  ```
1983
2085
 
2086
+ </details>
2087
+
2088
+ ---
2089
+
2090
+ ## 릴리스 노트
2091
+
2092
+ <details>
2093
+ <summary><b>▸ 1.2.0 — 대화가 끊기지 않게</b> · 여섯 자리가 어떻게 바뀌었나</summary>
2094
+
2095
+ <br>
2096
+
2097
+ | | 전 | 후 |
2098
+ |---|---|---|
2099
+ | 이어받기 | 도구를 부르다 끊긴 대화는 **다시 안 열렸다** | 짝 안 맞는 호출을 걷어내고 연다 |
2100
+ | 토큰 셈 | 어림잡은 채로 끝까지 갔다 | 서버 실제값에 맞춰 간다 |
2101
+ | 자리 비우기 | 49턴이면 요약이 왔다 | **102턴**까지 간다 |
2102
+ | 곁가지 | 본줄기 컨텍스트에 그대로 쌓였다 | 딴 갈래에서 |
2103
+ | 어제 알아낸 것 | 끄면 사라졌다 | 다음에 켤 때 넘어온다 |
2104
+ | 답 화면 | `**굵게**` 가 글자로 보였다 | 그려진다 |
2105
+
2106
+ <br>
2107
+
2108
+ #### 1. 도구를 부르다 끊긴 대화가 다시 안 열리던 것
2109
+
2110
+ 도구를 부르던 중에 창을 닫거나 <kbd>Ctrl</kbd>+<kbd>C</kbd> 로 끊으면, 적어 둔 대화에 **부름은 있고 결과가 없는 자리**가 남습니다. 다음에 `--resume` 으로 열면 서버가 그 짝을 문제 삼아 400 을 돌려줍니다 — 대화는 멀쩡히 적혀 있는데 이어서 갈 수가 없었습니다.
2111
+
2112
+ 이제 열기 전에 짝을 맞춰 봅니다. 결과 없는 부름은 버리고, 부모 없는 결과도 버리고, **모델이 한 말은 남깁니다.**
2113
+
2114
+ ```
2115
+ $ deel --resume 20260826-140217
2116
+
2117
+ ✓ 20260826-140217 — 메시지 48개를 이어 받았습니다.
2118
+ 중단된 도구 호출 2개를 걷어냈습니다 — 그때 하던 일은 다시 시켜 주세요.
2119
+ ```
2120
+
2121
+ #### 2. 남은 자리를 잘못 알던 것
2122
+
2123
+ 토큰 수는 글자 수로 어림잡습니다. 그런데 한국어·코드·JSON 이 섞이면 그 어림이 실제와 어긋나서, 자리가 남았는데 일찍 접거나 없는데 안 접어 서버가 거절했습니다.
2124
+
2125
+ 이제 서버가 답마다 알려 주는 **실제값과 견줘 배수를 고쳐 갑니다.** `/context` 맨 아래에 한 줄로 뜹니다.
2126
+
2127
+ ```
2128
+ 서버가 알려 준 실제값에 맞춰 +12% 보정했습니다 (7번 재봄).
2129
+ ```
2130
+
2131
+ 이 배수는 모델별로 남아서 **다음에 켤 때 그 값으로 시작합니다.** 처음부터 다시 재지 않습니다.
2132
+
2133
+ #### 3. 요약이 너무 일찍 오던 것
2134
+
2135
+ 창의 80% 가 차면 앞 대화를 요약으로 접습니다. 요약은 **되돌릴 수 없고**, 판단의 근거였던 파일 내용이 통째로 사라집니다.
2136
+
2137
+ 그 전에 한 단계를 넣었습니다. 55% 에서 **오래된 도구 결과만** 먼저 접습니다 — 최근 4개는 안 건드립니다. 모델이 한 말과 사람이 한 말도 하나도 안 건드립니다.
2138
+
2139
+ ```
2140
+ ◲ 오래된 도구 결과 6개를 접었습니다 (2,148 토큰을 비움)
2141
+ ```
2142
+
2143
+ 접힌 자리에는 무엇이었는지가 남습니다.
2144
+
2145
+ ```
2146
+ (접힘) Read(src/runner.js) — 61줄. 자리를 비우려고 내용을 접었습니다. 필요하면 다시 읽으세요.
2147
+ ```
2148
+
2149
+ 같은 대화를 흘려보내며 재 봤습니다 — 요약이 오는 시점이 **49턴 → 102턴, 2.1배** 늦춰집니다.
2150
+
2151
+ #### 4. 곁가지가 본줄기를 더럽히던 것
2152
+
2153
+ "이것만 잠깐 봐 줘" 한 마디가 본줄기 컨텍스트에 그대로 쌓입니다. 확인이 끝나도 그 말은 안 없어집니다.
2154
+
2155
+ ```
2156
+ /thread new 로그확인
2157
+ ⑂ 로그확인 갈래로 왔습니다. 빈 대화입니다
2158
+ 본줄기로 돌아가려면 /thread 1
2159
+ ```
2160
+
2161
+ `fork` 로 갈라 나오면 여기까지 오간 말을 물려받습니다. 갈래끼리 **나뉘는 것은 오간 말·토큰·할 일**이고, **같이 쓰는 것은 연결·되돌리기·감사기록**입니다 — 갈래에서 고친 파일도 `/undo` 로 그대로 되돌아갑니다. 갈래가 둘 이상일 때만 상태줄에 `⑂` 가 뜹니다.
2162
+
2163
+ #### 5. 어제 알아낸 것이 오늘 또 사라지던 것
2164
+
2165
+ `pnpm` 이 이 PC 에 없다는 걸 알아내도 끄면 사라졌습니다. 내일 또 부르고, 또 실패하고, 또 우회합니다.
2166
+
2167
+ ```
2168
+ /learned
2169
+ ── 겪어 본 것 ──────────────────────────────────────
2170
+
2171
+ 이 폴더에서 돌려 본 명령
2172
+ ✓ npm test 됨 12 · 안 됨 0
2173
+ ✗ pnpm 됨 0 · 안 됨 3
2174
+
2175
+ 이 모델에 대해 qwen2.5-coder:7b
2176
+ 같이 걸어 본 걸음 86
2177
+ 인자가 잘림 14 (16%)
2178
+ 토큰 추정 보정 ×1.12
2179
+
2180
+ 이 중 프롬프트에 실리는 것
2181
+ - 여기서 되는 명령: `npm test`
2182
+ - 이 PC 에서 안 되는 명령(다시 부르지 마라): `pnpm`
2183
+ ```
2184
+
2185
+ **학습이 아닙니다.** 모델을 고치지도, 대화를 쌓아 두지도 않습니다 — 그러면 컨텍스트만 먹습니다. 세어 두기만 하고, **두 번 이상 겪은 것만**, 다 합쳐 **220토큰 안에서** 넘깁니다. 한 번 겪은 것은 우연일 수 있고, 우연을 사실처럼 적으면 모델이 되는 길을 두고 우회합니다.
2186
+
2187
+ 되는 명령은 폴더(`.deel/배운것.json`)에, 모델 버릇은 설정 폴더에 따로 둡니다. 그래서 **폴더를 옮겨도 모델에 대해 알아낸 것은 따라옵니다.** `/learned 지우기` 로 언제든 비웁니다.
2188
+
2189
+ #### 6. 답이 글자 그대로 보이던 것
2190
+
2191
+ 모델은 마크다운으로 말하는데 화면은 그걸 몰라서, 별표와 백틱과 우물정자가 글에 섞여 나왔습니다. 무엇이 제목이고 무엇이 코드인지 사람이 머릿속에서 다시 읽어야 했습니다.
2192
+
2193
+ ```
2194
+ 전 후
2195
+ ▌ ## 고친 것 ▌ ▍ 고친 것
2196
+ ▌ **src/runner.js** 의 `console.log` ▌ src/runner.js 의 console.log
2197
+ ▌ - [ ] 남은 것: `src/worker.js` ▌ ☐ 남은 것: src/worker.js
2198
+ ▌ ```js ▌ ┌──────────────── js
2199
+ ▌ log.info('시작', { id }) ▌ │ log.info('시작', { id })
2200
+ ▌ |---|---| ▌ ┼────────┼─────────┼
2201
+ ```
2202
+
2203
+ 답은 토막토막 흘러오므로 **줄이 끝나야** 그릴 수 있습니다. 그런데 문단 하나가 통째로 한 줄이면 몇 초 동안 화면이 멈춘 것처럼 보입니다 — 그래서 한 줄이 화면 폭을 넘게 길어지면 거기까지를 **날것 그대로 흘려보냅니다.** 모양보다 '살아 있다' 가 먼저입니다.
2204
+
2205
+ <br>
2206
+
2207
+ 검사 2,532 → **2,578개** · 48/48 파일. 지난 판들은 [태그](https://github.com/jysvai/deel-local-cli/tags)에서 봅니다.
2208
+
2209
+ </details>
2210
+
1984
2211
  ---
1985
2212
 
1986
2213
  ## 라이선스
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deel-local-cli",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "로컬 모델·사내 게이트웨이 전용 코딩 에이전트 CLI — 외부 의존성 0개 / Zero-dependency coding agent CLI for local LLMs and private gateways",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -46,7 +46,7 @@
46
46
  "verify": "node test/no-bundle.test.js && node test/network.test.js && node test/web.test.js",
47
47
  "bench": "node test/edit-bench.js",
48
48
  "demo": "node test/demo.js",
49
- "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/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/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/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/preview/serve.js && node --check src/ui/working.js && node --check src/ui/inputbox.js && echo OK",
49
+ "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/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/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/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/preview/serve.js && node --check src/ui/working.js && node --check src/ui/inputbox.js && node --check src/ui/md.js && node --check src/agent/threads.js && node --check src/agent/evolve.js && echo OK",
50
50
  "coverage": "node test/coverage.mjs",
51
51
  "prepublishOnly": "npm run check && npm test"
52
52
  },
@@ -151,17 +151,3 @@ export function 설명길이(ctx) {
151
151
  return 90; // 8k 언저리. 첫 문장 하나만 남는다
152
152
  }
153
153
 
154
- /** `/ctx` 에서 지금 값이 얼마인지 보여 주려고 한데 모아 준다. */
155
- export function 지금값(ctx, 모드id = 'auto') {
156
- return {
157
- 걸음: 걸음수(모드id, ctx),
158
- 하위걸음: 하위걸음수(모드id, ctx),
159
- 읽기: 읽을줄수(ctx),
160
- 찾기: 찾을개수(ctx),
161
- 훑기: 찾을줄수(ctx),
162
- 뼈대: 뼈대줄수(ctx),
163
- 웹: 웹글자수(ctx),
164
- 도구설명: 설명길이(ctx),
165
- 요약: 요약길이(ctx),
166
- };
167
- }
@@ -15,6 +15,93 @@ export const COMPACT_AT = 0.8;
15
15
  export const KEEP_TAIL_RATIO = 0.3; // 최근 대화 중 남길 비율
16
16
  export const KEEP_HEAD = 2; // 맨 처음 요청은 언제나 남긴다 (목표가 거기 있다)
17
17
 
18
+ /*
19
+ * ── 그 전에, 도구 결과부터 접는다 ──────────────────────────────────────
20
+ *
21
+ * 요약 압축은 잃는 것이 크다. 사람이 한 말도, 모델이 왜 그렇게 정했는지도
22
+ * 세 줄로 줄어든다. 그런데 자리를 실제로 먹고 있는 것은 대개 그쪽이 아니다.
23
+ *
24
+ * Read 로 600줄짜리 파일을 한 번 열면 32k 창의 15% 가 그 자리에서 사라지고,
25
+ * 그 사본은 대화가 끝날 때까지 이력에 그대로 눌러앉는다. 이미 다 읽고 고친
26
+ * 파일인데도 그렇다. 세 번 읽으면 창의 절반이 옛날 파일 내용이다.
27
+ *
28
+ * 그래서 80% 에서 통째로 요약하기 전에, 먼저 **오래된 도구 결과만** 한 줄로
29
+ * 접는다. 사람 말과 모델의 판단은 한 글자도 안 건드린다. 무엇을 읽었는지는
30
+ * 남기므로 모델은 필요하면 그 파일을 다시 읽으면 된다 — 읽는 값은 싸고,
31
+ * 하던 일을 잊는 값은 비싸다.
32
+ *
33
+ * 최근 것은 안 접는다. 방금 읽은 것을 접으면 그 자리에서 다시 읽게 되고,
34
+ * 그러면 접은 보람이 없다.
35
+ */
36
+ export const FOLD_AT = 0.55; // 이 아래로는 접을 이유가 없다
37
+ export const KEEP_RECENT = 4; // 최근 도구 결과 이만큼은 원문 그대로 둔다
38
+ export const FOLD_MIN = 300; // 이보다 작으면 접어도 자리가 안 준다 (글자 수)
39
+ export const 접힘표 = '(접힘)';
40
+
41
+ /** 인자에서 사람이 알아볼 한 조각만 뽑는다. 경로가 제일 쓸모 있다. */
42
+ function 어디(args) {
43
+ if (!args || typeof args !== 'object') return '';
44
+ for (const k of ['file_path', 'path', 'pattern', 'command', 'query', 'url', '목적']) {
45
+ const v = args[k];
46
+ if (typeof v === 'string' && v.trim()) return v.trim().replace(/\s+/g, ' ').slice(0, 60);
47
+ }
48
+ return '';
49
+ }
50
+
51
+ export function shouldFold(session, at = FOLD_AT) {
52
+ const b = session.breakdown();
53
+ return b.total > 0 && b.used / b.total >= at;
54
+ }
55
+
56
+ /**
57
+ * 오래된 도구 결과를 한 줄로 접는다.
58
+ *
59
+ * 짝은 안 건드린다 — 메시지를 지우는 게 아니라 **내용만** 바꾸므로 호출과
60
+ * 결과의 짝이 그대로다. 규격이 깨질 자리가 아예 없다.
61
+ *
62
+ * @returns {{접은것: number, 아낀토큰: number}}
63
+ */
64
+ export function foldToolResults(session, { keep = KEEP_RECENT, min = FOLD_MIN } = {}) {
65
+ const ms = session.messages ?? [];
66
+
67
+ // 호출 쪽에서 이름과 인자를 가져온다. 결과 메시지에는 그게 안 실려 있다.
68
+ const 이름표 = new Map();
69
+ for (const m of ms) {
70
+ for (const c of m?.tool_calls ?? []) {
71
+ let args = {};
72
+ try { args = JSON.parse(c?.function?.arguments ?? '{}'); } catch { /* 못 읽으면 그만 */ }
73
+ if (c?.id) 이름표.set(c.id, { name: c?.function?.name ?? '도구', args });
74
+ }
75
+ }
76
+
77
+ const 자리 = [];
78
+ ms.forEach((m, i) => {
79
+ if (m?.role !== 'tool') return;
80
+ const 글 = typeof m.content === 'string' ? m.content : '';
81
+ if (글.startsWith(접힘표)) return; // 이미 접은 것
82
+ 자리.push({ i, 글 });
83
+ });
84
+
85
+ const 접을것 = 자리.slice(0, Math.max(0, 자리.length - keep)).filter((x) => x.글.length >= min);
86
+ let 아낀토큰 = 0;
87
+
88
+ for (const { i, 글 } of 접을것) {
89
+ const m = ms[i];
90
+ const 아는것 = 이름표.get(m.tool_call_id) ?? { name: m.tool_name ?? '도구', args: {} };
91
+ const 곳 = 어디(아는것.args);
92
+ const 줄수 = 글.split('\n').length;
93
+ const 전 = estimateTokens(글);
94
+ ms[i] = {
95
+ ...m,
96
+ content: `${접힘표} ${아는것.name}${곳 ? `(${곳})` : ''} — ${줄수}줄. `
97
+ + '자리를 비우려고 내용을 접었습니다. 필요하면 다시 읽으세요.',
98
+ };
99
+ 아낀토큰 += 전 - estimateTokens(ms[i].content);
100
+ }
101
+
102
+ return { 접은것: 접을것.length, 아낀토큰: Math.max(0, 아낀토큰) };
103
+ }
104
+
18
105
  const 요약지시 = `지금까지의 대화를 다음 형식으로 요약하세요. 이어서 일할 사람이 이것만 보고도 계속할 수 있어야 합니다.
19
106
  추측하지 말고 실제로 오간 내용만 쓰세요. 한국어로, 각 항목 3줄 이내로 쓰세요.
20
107