deel-local-cli 1.8.0 → 1.10.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.
Files changed (49) hide show
  1. package/README.ko.md +1166 -1182
  2. package/README.md +1223 -1232
  3. package/bin/deel.js +55 -12
  4. package/package.json +3 -3
  5. package/src/acp/serve.js +40 -3
  6. package/src/agent/compact.js +314 -296
  7. package/src/agent/effort.js +27 -7
  8. package/src/agent/evidence.js +2 -0
  9. package/src/agent/filemem.js +141 -0
  10. package/src/agent/grade.js +51 -1
  11. package/src/agent/loop.js +202 -35
  12. package/src/agent/session.js +121 -5
  13. package/src/agent/store.js +186 -9
  14. package/src/agent/threads.js +26 -1
  15. package/src/backend/adapter.js +201 -18
  16. package/src/backend/learn.js +24 -0
  17. package/src/backend/mcp.js +96 -5
  18. package/src/backend/probe.js +131 -61
  19. package/src/backend/quota.js +29 -5
  20. package/src/backend/toolfit.js +325 -0
  21. package/src/commands.js +107 -27
  22. package/src/config.js +47 -2
  23. package/src/i18n/en.js +56 -2
  24. package/src/i18n/index.js +18 -0
  25. package/src/i18n/ja.js +58 -2
  26. package/src/i18n/ko.js +103 -2
  27. package/src/i18n/zh.js +58 -2
  28. package/src/lsp/client.js +49 -5
  29. package/src/oneshot.js +81 -3
  30. package/src/pack/sbom.js +30 -4
  31. package/src/pack/selfpack.js +25 -9
  32. package/src/pack/sheet.en.js +288 -0
  33. package/src/pack/tar.js +65 -2
  34. package/src/plugins/manage.js +46 -9
  35. package/src/repl.js +264 -35
  36. package/src/safety/audit.js +92 -8
  37. package/src/safety/authcmd.js +14 -3
  38. package/src/safety/guard.js +143 -0
  39. package/src/safety/keystore.js +62 -39
  40. package/src/safety/undo.js +24 -6
  41. package/src/tools/index.js +239 -34
  42. package/src/tools/jobs.js +158 -29
  43. package/src/tools/verify.js +33 -4
  44. package/src/tools/webfetch.js +92 -9
  45. package/src/ui/md.js +201 -5
  46. package/src/ui/motion.js +0 -1
  47. package/src/ui/pastechip.js +50 -3
  48. package/src/ui/pick.js +115 -0
  49. package/src/ui/screen.js +23 -3
package/bin/deel.js CHANGED
@@ -15,6 +15,8 @@ import { runSessions } from '../src/agent/sessionui.js';
15
15
  import { acp } from '../src/acp/serve.js';
16
16
  import { runCompletion } from '../src/completion.js';
17
17
  import { runReset } from '../src/reset.js';
18
+ import { 언어잡기, 언어 } from '../src/i18n/index.js';
19
+ import { load as 설정읽기 } from '../src/config.js';
18
20
 
19
21
  const MIN_NODE = 20;
20
22
 
@@ -35,25 +37,63 @@ function 판번호() {
35
37
  }
36
38
  }
37
39
 
40
+ /*
41
+ * 켤 때 말을 한 번 정한다.
42
+ *
43
+ * 여태 이 자리가 비어 있었다. 말을 정하는 곳이 repl.js 하나뿐이라서,
44
+ * `deel audit`·`deel pack`·`deel sbom` 은 **언제나 한국어**로 나왔다 —
45
+ * /lang en 으로 쓰던 사람이 심사에 낼 서류를 뽑으면 한글 문서가 나왔다는 뜻이다.
46
+ *
47
+ * 설정을 못 읽어도 죽지 않는다. 말 하나 때문에 `deel --version` 이 안 되면 안 된다.
48
+ */
49
+ function 말정하기() {
50
+ let cfg = null;
51
+ try { cfg = 설정읽기(); } catch { /* 설정이 없어도 기본 말로 돈다 */ }
52
+ return 언어잡기({ cfg });
53
+ }
54
+
38
55
  // 사내 반입용 묶음 만들기.
39
56
  function runPack(flags) {
40
- const out = flags.out ? String(flags.out) : join(process.cwd(), 'deel-반입.zip');
57
+ const 한국어 = 언어() === 'ko';
58
+ const out = flags.out ? String(flags.out) : join(process.cwd(), 한국어 ? 'deel-반입.zip' : 'deel-import.zip');
41
59
  const r = packSelf(out);
42
60
  const a = r.audit;
43
61
  say('');
44
- rule('반입 묶음', 70);
62
+ rule(한국어 ? '반입 묶음' : 'Review package', 70);
45
63
  say(` ${mark.ok} ${c.bold(r.out)}`);
46
- say(` ${c.gray(`${r.files}개 파일 · ${(r.bytes / 1024).toFixed(1)}KB`)}`);
64
+ say(` ${c.gray(한국어 ? `${r.files}개 파일 · ${(r.bytes / 1024).toFixed(1)}KB` : `${r.files} files · ${(r.bytes / 1024).toFixed(1)}KB`)}`);
47
65
  say('');
48
- say(` ${c.gray('의존성')} ${a.deps.length === 0 ? c.green('0개') : c.red(a.deps.length + '')}`);
49
- say(` ${c.gray('설치 스크립트')} ${a.lifecycle.length === 0 ? c.green('없음') : c.red(a.lifecycle.join(', '))}`);
50
- say(` ${c.gray('외부 import')} ${a.외부모듈.length === 0 ? c.green('0건') : c.red(a.외부모듈.length + '건')}`);
51
- say(` ${c.gray('네트워크 호출')} ${a.calls.net.length}곳 ${c.gray('(설정한 주소로만)')}`);
52
- say(` ${c.gray('포트 열기')} ${a.calls.listen.length === 0 ? c.green('없음') : c.red(a.calls.listen.length + '곳')}`);
66
+ const 없음 = 한국어 ? '없음' : 'none';
67
+ const 개 = (n, 단위) => (한국어 ? `${n}${단위}` : String(n));
68
+ /*
69
+ * 이름 칸을 손으로 띄우지 않는다.
70
+ *
71
+ * 한글은 한 글자가 두 칸이라 「의존성」 과 「Dependencies」 를 같은 수의
72
+ * 빈칸으로 맞출 수 없다. 손으로 맞춰 두면 말을 바꾸는 순간 줄이 어긋난다 —
73
+ * 실제로 영어판이 처음에 그렇게 어긋났다.
74
+ */
75
+ const 칸 = (ko, en) => (한국어 ? ko : en.padEnd(18));
76
+ say(` ${c.gray(칸('의존성 ', 'Dependencies'))}${a.deps.length === 0 ? c.green(개(0, '개')) : c.red(개(a.deps.length, '개'))}`);
77
+ say(` ${c.gray(칸('설치 스크립트 ', 'Install scripts'))}${a.lifecycle.length === 0 ? c.green(없음) : c.red(a.lifecycle.join(', '))}`);
78
+ say(` ${c.gray(칸('외부 import ', 'External imports'))}${a.외부모듈.length === 0 ? c.green(개(0, '건')) : c.red(개(a.외부모듈.length, '건'))}`);
79
+ say(` ${c.gray(칸('네트워크 호출 ', 'Network calls'))}${개(a.calls.net.length, '곳')} ${c.gray(한국어 ? '(설정한 주소로만)' : '(only to the configured address)')}`);
80
+ say(` ${c.gray(칸('포트 열기 ', 'Listening ports'))}${a.calls.listen.length === 0 ? c.green(없음) : c.red(개(a.calls.listen.length, '곳'))}`);
53
81
  say('');
54
- say(` ${c.gray('안에 반입심사서.txt · sbom.cdx.json · 심사명세.json 이 같이 들어 있습니다.')}`);
55
- say(` ${c.gray('사람이 읽을 장, 스캐너에 넣을 장입니다 — 그대로 제출하시면 됩니다.')}`);
56
- say(` ${c.gray('내용만 먼저 보시려면')} ${c.cyan('deel audit')}`);
82
+ /*
83
+ * 여기 적는 이름은 zip 안에 진짜로 이름이어야 한다.
84
+ *
85
+ * 안내 글과 실제 파일 이름이 어긋나면, 받은 사람은 없는 파일을 찾다가
86
+ * 묶음이 잘못 만들어진 줄 안다 — 서류를 못 믿게 되는 자리다.
87
+ */
88
+ if (한국어) {
89
+ say(` ${c.gray('안에 반입심사서.txt · sbom.cdx.json · 심사명세.json 이 같이 들어 있습니다.')}`);
90
+ say(` ${c.gray('사람이 읽을 것 한 장, 스캐너에 넣을 것 두 장입니다 — 그대로 제출하시면 됩니다.')}`);
91
+ say(` ${c.gray('내용만 먼저 보시려면')} ${c.cyan('deel audit')}`);
92
+ } else {
93
+ say(` ${c.gray('It contains import-review.txt · sbom.cdx.json · audit-spec.json.')}`);
94
+ say(` ${c.gray('One document to read, two to feed a scanner — submit them as they are.')}`);
95
+ say(` ${c.gray('To see the contents first:')} ${c.cyan('deel audit')}`);
96
+ }
57
97
  say('');
58
98
  return 0;
59
99
  }
@@ -208,7 +248,7 @@ function help() {
208
248
  say(` ${c.gray('--quiet')} 도구가 무엇을 했는지 안 적음 (오류는 그래도 적음)`);
209
249
  say(` ${c.gray('--yes')} 승인이 필요한 것도 그냥 실행. ${c.yellow('기본은 거부입니다')}`);
210
250
  say(` ${c.gray('답은 표준출력, 도구 기록은 표준오류로 나갑니다 — 파이프로 넘겨도 답만 넘어갑니다.')}`);
211
- say(` ${c.gray('끝난 까닭이 종료코드에 담깁니다:')} ${c.gray('0 끝냄 · 1 오류 · 2 걸음수상한 · 3 헛돎 · 4 중단')}`);
251
+ say(` ${c.gray('끝난 까닭이 종료코드에 담깁니다:')} ${c.gray('0 끝냄 · 1 오류 · 2 걸음수상한 · 3 헛돎 · 4 중단 · 5 말없이끊김')}`);
212
252
  say('');
213
253
  say(` ${c.bold('진단 직접 지정')} ${c.gray('— 설정을 남기지 않고 확인만 할 때')}`);
214
254
  say('');
@@ -231,6 +271,9 @@ async function main() {
231
271
 
232
272
  const { cmd: 친명령, args, flags } = parse(process.argv.slice(2));
233
273
 
274
+ // 서류를 뽑는 명령(audit·sbom·pack)이 어느 말로 나갈지를 여기서 정한다.
275
+ 말정하기();
276
+
234
277
  /*
235
278
  * `deel online` · `deel offline` 은 깃발의 별칭이다.
236
279
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "deel-local-cli",
3
- "version": "1.8.0",
4
- "description": "로컬 모델·사내 게이트웨이 전용 코딩 에이전트 CLI 외부 의존성 0개 / Zero-dependency coding agent CLI for local LLMs and private gateways",
3
+ "version": "1.10.0",
4
+ "description": "A coding-agent CLI that runs on local models and private gateways. Zero dependencies, Node 20+.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -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/askcheck.js && node --check src/agent/asks.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/price.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/spawn.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/authcmd.js && node --check src/safety/policy.js && node --check src/safety/network.js && node --check src/safety/runmode.js && node --check src/providers/index.js && node --check src/providers/openai.js && node --check src/providers/anthropic.js && node --check src/providers/gemini.js && node --check src/providers/bedrock.js && node --check src/providers/custom.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/pastechip.js && node --check src/ui/histline.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 && node --check src/version.js && node --check src/agent/budget.js && node --check src/agent/memory.js && node --check src/agent/recall.js && node --check src/agent/salvage.js && node --check src/backend/learn.js && node --check src/backend/mcp.js && node --check src/tools/task.js && node --check src/tools/outline.js && node --check src/tools/verify.js && node --check src/ui/approve.js && node --check src/ui/complete.js && node --check src/ui/screen.js && node --check src/reset.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/askcheck.js && node --check src/agent/asks.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/toolfit.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/price.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/spawn.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/authcmd.js && node --check src/safety/policy.js && node --check src/safety/network.js && node --check src/safety/runmode.js && node --check src/providers/index.js && node --check src/providers/openai.js && node --check src/providers/anthropic.js && node --check src/providers/gemini.js && node --check src/providers/bedrock.js && node --check src/providers/custom.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/pastechip.js && node --check src/ui/pick.js && node --check src/ui/histline.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/pack/sheet.en.js && node --check src/safety/secrets.js && node --check src/version.js && node --check src/agent/budget.js && node --check src/agent/filemem.js && node --check src/agent/memory.js && node --check src/agent/recall.js && node --check src/agent/salvage.js && node --check src/backend/learn.js && node --check src/backend/mcp.js && node --check src/tools/task.js && node --check src/tools/outline.js && node --check src/tools/verify.js && node --check src/ui/approve.js && node --check src/ui/complete.js && node --check src/ui/screen.js && node --check src/reset.js && echo OK",
55
55
  "coverage": "node test/coverage.mjs",
56
56
  "prepublishOnly": "npm run check && npm test"
57
57
  },
package/src/acp/serve.js CHANGED
@@ -36,7 +36,7 @@ import { Session, repairToolPairs } from '../agent/session.js';
36
36
  import { Store, sessionsDir, prune } from '../agent/store.js';
37
37
  import { makeScope } from '../safety/guard.js';
38
38
  import { History } from '../safety/undo.js';
39
- import { Audit } from '../safety/audit.js';
39
+ import { Audit, 열쇠묻기 } from '../safety/audit.js';
40
40
  import { activeProfile, load, resolveKey, homeDir, save as saveCfg } from '../config.js';
41
41
  import { 말 as 옮긴말 } from '../i18n/index.js';
42
42
  import { 알림채움 } from '../backend/retry.js';
@@ -242,7 +242,7 @@ export async function acp(opts = {}) {
242
242
  // 적어 둔 허락·금지 규칙 (safety/policy.js). 승인 모드보다 먼저 본다.
243
243
  규칙들: 규칙모으기(cfg),
244
244
  history: new History(root),
245
- audit: new Audit(root),
245
+ audit: new Audit(root, { 열쇠들: 열쇠묻기(conn) }),
246
246
  seen: new Set(),
247
247
  mcp: mcp붙임.서버들,
248
248
  skills: found.skills,
@@ -427,8 +427,34 @@ export async function acp(opts = {}) {
427
427
 
428
428
  // 답이 천장에서 잘렸고 더 못 올린다. 조용히 끝내면 에디터에는 중간에서
429
429
  // 끊긴 답만 남아서, 사람은 모델이 대충 답한 줄 안다.
430
+ //
431
+ // 한국어를 박아 두고 있었다 — `/lang en` 으로 켠 사람이 이 자리에서만
432
+ // 한글을 본다. 말 표를 거친다.
430
433
  case 'capped':
431
- 말하기(`\n\n_(답이 ${ev.cap.toLocaleString()} 토큰에서 잘렸습니다 — 터미널에서 \`/out 32k\` 로 상한을 올리거나, 파일은 나눠 쓰게 하세요)_\n\n`);
434
+ 말하기(`\n\n_(${옮긴말('ev.capped', { 한계: ev.cap.toLocaleString() })})_\n\n`);
435
+ break;
436
+
437
+ /*
438
+ * ── 여기 셋은 에디터에 아무 말도 안 가고 있었다 ──────────────
439
+ *
440
+ * 특히 cutoff 가 나쁘다. 서버가 끝났다는 말도 없이 멈춘 반쪽 답이
441
+ * 에디터에는 **온전한 답**으로 뜬다. 사람은 그걸 읽고 다음 일로
442
+ * 넘어가는데, 정작 답의 뒷부분은 오지도 않았다.
443
+ */
444
+ case 'cutoff':
445
+ 말하기(`\n\n_(${옮긴말('ev.cutoff')})_\n\n`);
446
+ break;
447
+
448
+ case 'nudge':
449
+ 말하기(`\n\n_(${ev.why === '요청누락'
450
+ ? 옮긴말('ev.nudgeMissed', { n: ev.빠진?.length ?? 0 })
451
+ : 옮긴말('ev.nudgeRead')})_\n\n`);
452
+ break;
453
+
454
+ case 'learned':
455
+ 말하기(`\n\n_(${ev.what === 'ctx'
456
+ ? 옮긴말('ev.learnedCtx', { 한계: ev.limit.toLocaleString() })
457
+ : 옮긴말('ev.learnedOut', { 한계: ev.limit.toLocaleString() })})_\n\n`);
432
458
  break;
433
459
 
434
460
  // 서버가 잠깐 막아 기다리는 중. 아직 흘러간 글이 없으니 답을 새로 시작하지는 않는다.
@@ -457,6 +483,17 @@ export async function acp(opts = {}) {
457
483
  * 덧붙이기로는 못 맞춘다 — 앞의 것 여러 개가 요약 하나로 바뀌었으니,
458
484
  * 이어 붙이면 파일에는 접히기 전과 접힌 뒤가 겹쳐 남는다. 새로 적는다.
459
485
  */
486
+ /*
487
+ * 자리가 다 차서 비웠다. 에디터에는 오류가 아니라 알림으로 간다 —
488
+ * 붉게 보내면 편집기가 턴이 끝난 줄 알고 되물음을 닫아 버린다.
489
+ */
490
+ case 'reset':
491
+ 말하기(`\n\n_(${(ev.kept?.할일 ?? 0)
492
+ ? 옮긴말('ev.reset', { 버린수: ev.dropped, 할일: ev.kept.할일 })
493
+ : 옮긴말('ev.resetBare', { 버린수: ev.dropped })})_\n\n`);
494
+ 방.store.replace(방.session.messages, `자리부족 — 앞선 대화 ${ev.dropped}개를 비움`);
495
+ 적은데까지 = 방.session.messages.length;
496
+ break;
460
497
  case 'compacted':
461
498
  방.store.replace(방.session.messages, `압축 — ${ev.folded}개를 요약으로`);
462
499
  적은데까지 = 방.session.messages.length;