deel-local-cli 1.7.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 (61) hide show
  1. package/README.ko.md +1166 -0
  2. package/README.md +1223 -1107
  3. package/bin/deel.js +78 -12
  4. package/package.json +4 -4
  5. package/src/acp/map.js +1 -1
  6. package/src/acp/serve.js +40 -3
  7. package/src/agent/compact.js +314 -296
  8. package/src/agent/effort.js +27 -7
  9. package/src/agent/evidence.js +2 -0
  10. package/src/agent/filemem.js +141 -0
  11. package/src/agent/grade.js +51 -1
  12. package/src/agent/loop.js +218 -40
  13. package/src/agent/session.js +136 -14
  14. package/src/agent/store.js +186 -9
  15. package/src/agent/threads.js +26 -1
  16. package/src/backend/adapter.js +272 -23
  17. package/src/backend/learn.js +24 -0
  18. package/src/backend/mcp.js +96 -5
  19. package/src/backend/probe.js +131 -61
  20. package/src/backend/quota.js +29 -5
  21. package/src/backend/retry.js +3 -0
  22. package/src/backend/scanui.js +1 -1
  23. package/src/backend/toolfit.js +325 -0
  24. package/src/commands.js +170 -61
  25. package/src/completion.js +20 -2
  26. package/src/config.js +47 -2
  27. package/src/i18n/en.js +210 -3
  28. package/src/i18n/index.js +40 -0
  29. package/src/i18n/ja.js +204 -3
  30. package/src/i18n/ko.js +270 -3
  31. package/src/i18n/zh.js +204 -3
  32. package/src/lsp/client.js +49 -5
  33. package/src/oneshot.js +92 -5
  34. package/src/pack/sbom.js +30 -4
  35. package/src/pack/selfpack.js +26 -10
  36. package/src/pack/sheet.en.js +288 -0
  37. package/src/pack/tar.js +65 -2
  38. package/src/plugins/manage.js +46 -9
  39. package/src/repl.js +344 -61
  40. package/src/reset.js +397 -0
  41. package/src/safety/audit.js +95 -8
  42. package/src/safety/authcmd.js +316 -0
  43. package/src/safety/guard.js +143 -0
  44. package/src/safety/keystore.js +114 -38
  45. package/src/safety/undo.js +25 -6
  46. package/src/tools/desc.en.js +19 -14
  47. package/src/tools/index.js +349 -75
  48. package/src/tools/jobs.js +175 -42
  49. package/src/tools/lsp.js +5 -4
  50. package/src/tools/outline.js +7 -3
  51. package/src/tools/task.js +10 -6
  52. package/src/tools/todo.js +9 -2
  53. package/src/tools/verify.js +42 -7
  54. package/src/tools/webfetch.js +94 -10
  55. package/src/ui/export.js +1 -1
  56. package/src/ui/md.js +201 -5
  57. package/src/ui/motion.js +0 -1
  58. package/src/ui/pastechip.js +50 -3
  59. package/src/ui/pick.js +115 -0
  60. package/src/ui/screen.js +23 -3
  61. package/README.en.md +0 -1117
package/bin/deel.js CHANGED
@@ -14,6 +14,9 @@ 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
16
  import { runCompletion } from '../src/completion.js';
17
+ import { runReset } from '../src/reset.js';
18
+ import { 언어잡기, 언어 } from '../src/i18n/index.js';
19
+ import { load as 설정읽기 } from '../src/config.js';
17
20
 
18
21
  const MIN_NODE = 20;
19
22
 
@@ -34,25 +37,63 @@ function 판번호() {
34
37
  }
35
38
  }
36
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
+
37
55
  // 사내 반입용 묶음 만들기.
38
56
  function runPack(flags) {
39
- 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');
40
59
  const r = packSelf(out);
41
60
  const a = r.audit;
42
61
  say('');
43
- rule('반입 묶음', 70);
62
+ rule(한국어 ? '반입 묶음' : 'Review package', 70);
44
63
  say(` ${mark.ok} ${c.bold(r.out)}`);
45
- 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`)}`);
46
65
  say('');
47
- say(` ${c.gray('의존성')} ${a.deps.length === 0 ? c.green('0개') : c.red(a.deps.length + '')}`);
48
- say(` ${c.gray('설치 스크립트')} ${a.lifecycle.length === 0 ? c.green('없음') : c.red(a.lifecycle.join(', '))}`);
49
- say(` ${c.gray('외부 import')} ${a.외부모듈.length === 0 ? c.green('0건') : c.red(a.외부모듈.length + '건')}`);
50
- say(` ${c.gray('네트워크 호출')} ${a.calls.net.length}곳 ${c.gray('(설정한 주소로만)')}`);
51
- 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, '곳'))}`);
52
81
  say('');
53
- say(` ${c.gray('안에 반입심사서.txt · sbom.cdx.json · 심사명세.json 이 같이 들어 있습니다.')}`);
54
- say(` ${c.gray('사람이 읽을 장, 스캐너에 넣을 장입니다 — 그대로 제출하시면 됩니다.')}`);
55
- 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
+ }
56
97
  say('');
57
98
  return 0;
58
99
  }
@@ -138,6 +179,7 @@ function help() {
138
179
  say(` ${c.cyan('deel setup')} 연결 설정 (주소·키·모델)`);
139
180
  say(` ${c.cyan('deel status')} 연결 상태 보기`);
140
181
  say(` ${c.cyan('deel diagnose')} 저장된 연결로 진단 다시 돌리기`);
182
+ say(` ${c.cyan('deel reset')} 설정·기억·기록 지우기 ${c.gray('(그냥 치면 보여만 줍니다)')}`);
141
183
  say(` ${c.cyan('deel completion <셸>')} 탭 완성 스크립트 ${c.gray('(bash · zsh · powershell)')}`);
142
184
  say(` ${c.cyan('deel --version')} 판 번호 ${c.gray('(-v 도 됩니다)')}`);
143
185
  say('');
@@ -155,6 +197,19 @@ function help() {
155
197
  say(` ${c.gray('에디터 설정에 이 명령을 적어 두면 그 안에서 deel 이 돕니다.')}`);
156
198
  say(` ${c.gray('승인 창·모드 고르개·고친 파일 링크가 에디터 것으로 그려집니다.')}`);
157
199
  say('');
200
+ say(` ${c.bold('되돌아가기')} ${c.gray('— 지우려고 다시 깔지 않아도 됩니다')}`);
201
+ say('');
202
+ say(` ${c.cyan('deel reset')} 무엇이 얼마나 있는지 보여 주고 묻습니다 ${c.gray('(아무것도 안 지웁니다)')}`);
203
+ say(` ${c.gray('deel reset model')} 연결·프로필·잠긴 열쇠`);
204
+ say(` ${c.gray('deel reset memory')} 기억 (.deel/memory.md)`);
205
+ say(` ${c.gray('deel reset sessions')} 대화 기록`);
206
+ say(` ${c.gray('deel reset learned')} 배운 것 (이 PC + 이 폴더)`);
207
+ say(` ${c.gray('deel reset plugins')} 설치한 플러그인`);
208
+ say(` ${c.gray('deel reset all')} 위 전부 ${c.gray('— 플러그인·되돌리기·감사기록은 빼고')}`);
209
+ say(` ${c.gray('--hard')} ${c.yellow('되돌리기 스냅샷·감사기록까지')}. all 에서만 씁니다`);
210
+ say(` ${c.gray('--yes')} 안 묻고 지웁니다 (스크립트용)`);
211
+ say(` ${c.gray('.deel/mcp.json · .deelignore · DEEL.md 는 사람이 적은 것이라 어떤 길로도 안 건드립니다.')}`);
212
+ say('');
158
213
  say(` ${c.bold('사내 반입')}`);
159
214
  say('');
160
215
  say(` ${c.cyan('deel audit')} 의존성·네트워크 호출 자리 심사서 ${c.gray('(사람이 읽는 글)')}`);
@@ -193,7 +248,7 @@ function help() {
193
248
  say(` ${c.gray('--quiet')} 도구가 무엇을 했는지 안 적음 (오류는 그래도 적음)`);
194
249
  say(` ${c.gray('--yes')} 승인이 필요한 것도 그냥 실행. ${c.yellow('기본은 거부입니다')}`);
195
250
  say(` ${c.gray('답은 표준출력, 도구 기록은 표준오류로 나갑니다 — 파이프로 넘겨도 답만 넘어갑니다.')}`);
196
- say(` ${c.gray('끝난 까닭이 종료코드에 담깁니다:')} ${c.gray('0 끝냄 · 1 오류 · 2 걸음수상한 · 3 헛돎 · 4 중단')}`);
251
+ say(` ${c.gray('끝난 까닭이 종료코드에 담깁니다:')} ${c.gray('0 끝냄 · 1 오류 · 2 걸음수상한 · 3 헛돎 · 4 중단 · 5 말없이끊김')}`);
197
252
  say('');
198
253
  say(` ${c.bold('진단 직접 지정')} ${c.gray('— 설정을 남기지 않고 확인만 할 때')}`);
199
254
  say('');
@@ -216,6 +271,9 @@ async function main() {
216
271
 
217
272
  const { cmd: 친명령, args, flags } = parse(process.argv.slice(2));
218
273
 
274
+ // 서류를 뽑는 명령(audit·sbom·pack)이 어느 말로 나갈지를 여기서 정한다.
275
+ 말정하기();
276
+
219
277
  /*
220
278
  * `deel online` · `deel offline` 은 깃발의 별칭이다.
221
279
  *
@@ -318,6 +376,14 @@ async function main() {
318
376
  case 'sessions':
319
377
  case 'ls':
320
378
  return runSessions(flags);
379
+ /*
380
+ * 초기화.
381
+ *
382
+ * setup 과 달리 **설정을 안 읽는다.** 초기화를 찾는 까닭이 대개 설정이
383
+ * 깨져서인데, 읽고 시작하면 그 자리에서 못 넘어간다.
384
+ */
385
+ case 'reset':
386
+ return runReset(args, flags);
321
387
  /*
322
388
  * 탭 완성 스크립트를 낸다 (src/completion.js).
323
389
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "deel-local-cli",
3
- "version": "1.7.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": {
@@ -14,7 +14,7 @@
14
14
  "bin",
15
15
  "src",
16
16
  "README.md",
17
- "README.en.md",
17
+ "README.ko.md",
18
18
  "LICENSE"
19
19
  ],
20
20
  "keywords": [
@@ -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/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 && 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/map.js CHANGED
@@ -55,7 +55,7 @@ export function 도구갈래(이름) {
55
55
  */
56
56
  export function 도구이름표(이름, 인자) {
57
57
  const a = 인자 ?? {};
58
- const 첫 = a.file_path ?? a.pattern ?? a.path ?? a.url ?? a.name ?? a.목적
58
+ const 첫 = a.file_path ?? a.pattern ?? a.path ?? a.url ?? a.name ?? a.purpose ?? a.목적
59
59
  ?? (a.command ? String(a.command).replace(/\s+/g, ' ') : null)
60
60
  ?? (Array.isArray(a.files) && a.files.length
61
61
  ? `${a.files[0]?.file_path ?? '?'}${a.files.length > 1 ? ` 외 ${a.files.length - 1}개` : ''}`
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;