deel-local-cli 2.0.1 → 2.1.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.ko.md +34 -7
- package/README.md +35 -7
- package/bin/deel.js +34 -1
- package/package.json +1 -1
- package/src/acp/serve.js +83 -17
- package/src/agent/commit.js +2 -2
- package/src/agent/compact.js +4 -4
- package/src/agent/donecheck.js +97 -0
- package/src/agent/grade.js +1 -1
- package/src/agent/loop.js +176 -13
- package/src/agent/memory.js +1 -1
- package/src/agent/models.js +1 -1
- package/src/agent/modes.js +3 -0
- package/src/agent/outschema.js +1 -1
- package/src/agent/pins.js +7 -2
- package/src/agent/project.js +1 -1
- package/src/agent/recall.js +1 -1
- package/src/agent/session.js +15 -0
- package/src/agent/store.js +13 -26
- package/src/backend/ctxsize.js +2 -2
- package/src/backend/http.js +1 -1
- package/src/backend/learn.js +27 -1
- package/src/backend/mcp.js +97 -16
- package/src/backend/proxy.js +1 -1
- package/src/backend/quota.js +2 -2
- package/src/commands.js +24 -2
- package/src/completion.js +16 -3
- package/src/config.js +33 -11
- package/src/configexplain.js +1 -1
- package/src/doctor.js +11 -1
- package/src/eval/run.js +432 -0
- package/src/eval/starter.js +95 -0
- package/src/i18n/en.js +20 -0
- package/src/i18n/ja.js +20 -0
- package/src/i18n/ko.js +20 -0
- package/src/i18n/zh.js +20 -0
- package/src/jsonl.js +42 -0
- package/src/lsp/client.js +6 -46
- package/src/oneshot.js +85 -3
- package/src/pack/selfpack.js +2 -2
- package/src/pack/zip.js +18 -1
- package/src/plugins/manage.js +81 -14
- package/src/reap.js +70 -0
- package/src/repl.js +85 -11
- package/src/report.js +1 -1
- package/src/safety/audit.js +4 -19
- package/src/safety/authcmd.js +1 -1
- package/src/safety/guard.js +56 -6
- package/src/safety/hooks.js +1 -1
- package/src/safety/keystore.js +18 -3
- package/src/safety/policy.js +38 -0
- package/src/safety/shellenv.js +1 -1
- package/src/safety/undo.js +44 -20
- package/src/skills/discover.js +1 -1
- package/src/tools/docs.js +3 -3
- package/src/tools/edit-match.js +1 -1
- package/src/tools/encoding.js +1 -1
- package/src/tools/excel-com.js +56 -30
- package/src/tools/fastgrep.js +1 -1
- package/src/tools/fsutil.js +8 -4
- package/src/tools/ignore.js +21 -1
- package/src/tools/index.js +122 -11
- package/src/tools/jobs.js +23 -4
- package/src/tools/shell.js +27 -0
- package/src/tools/todo.js +1 -1
- package/src/tools/webfetch.js +1 -1
- package/src/tools/xlsx.js +4 -4
- package/src/ui/approve.js +57 -3
- package/src/ui/banner.js +1 -1
- package/src/ui/inputbox.js +1 -1
- package/src/ui/md.js +1 -1
- package/src/ui/motion.js +1 -1
package/README.ko.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
[](https://github.com/jysvai/deel-local-cli/actions/workflows/test.yml)
|
|
22
22
|
[](https://github.com/jysvai/deel-local-cli/actions/workflows/codeql.yml)
|
|
23
|
-
[](docs/ko/develop.md)
|
|
24
24
|
|
|
25
25
|
[](https://www.npmjs.com/package/deel-local-cli?activeTab=dependencies)
|
|
26
26
|
[](package.json)
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
| [늘려 쓰기](docs/ko/extend.md) | 스킬 · 플러그인 · MCP · 에이전트 · 훅 · ACP |
|
|
128
128
|
| [속도와 씀씀이](docs/ko/tuning.md) | 단계별 추론 강도 · 프리픽스 캐시 · 컨텍스트 길이 |
|
|
129
129
|
| [안전망과 사내 반입](docs/ko/safety.md) | 되돌리기 · 작업 범위 · 감사기록 · 심사 서류 |
|
|
130
|
+
| [사내 배포 안내](docs/ko/company.md) | 처음 쓰는 사람 · 관리 정책 한 장 · 어디로 나가나 · 막는 것의 한계 |
|
|
130
131
|
| [설정](docs/ko/config.md) · [개발](docs/ko/develop.md) | 환경변수 · 실행 옵션 · 검사 돌리기 · 폴더 구조 |
|
|
131
132
|
| [릴리스 노트](docs/ko/releases.md) | [1.16.x](docs/ko/releases/1.x.md#116x) · [1.15.x](docs/ko/releases/1.x.md#115x) · [1.14.x](docs/ko/releases/1.x.md#114x) · [1.13.x](docs/ko/releases/1.x.md#113x) · [1.12.x](docs/ko/releases/1.x.md#112x) · [1.10.x](docs/ko/releases/1.x.md#110x) · [1.9.x](docs/ko/releases/1.x.md#19x) · [그 앞](docs/ko/releases.md) |
|
|
132
133
|
|
|
@@ -243,6 +244,12 @@ Model Context Protocol 과 Agent Client Protocol 은 둘 다 표준입출력으
|
|
|
243
244
|
npm install -g deel-local-cli
|
|
244
245
|
```
|
|
245
246
|
|
|
247
|
+
이 명령은 옛 판이 깔려 있어도 늘 npm 의 최신 판을 받습니다. `npx` 로 쓸 때는 `@latest` 를 붙이세요 —
|
|
248
|
+
전에 깔아 둔 deel 이 있으면 `npx deel-local-cli` 는 새로 받지 않고 **그걸** 실행합니다.
|
|
249
|
+
`npx deel-local-cli@latest` 는 늘 최신을 받습니다. 지금 도는 판은 `deel --version` 으로 봅니다.
|
|
250
|
+
`npm i -g` 로도 옛 판이 오면 `npm view deel-local-cli version` 을 보세요 — 사내 npm 미러는
|
|
251
|
+
npmjs.org 보다 늦을 수 있습니다.
|
|
252
|
+
|
|
246
253
|
설치가 싫으면 소스를 받아 그대로 쓰셔도 됩니다. `npm install` 이 필요 없습니다.
|
|
247
254
|
|
|
248
255
|
```bash
|
|
@@ -316,7 +323,7 @@ deel --offline
|
|
|
316
323
|
무엇이 어디로 갈 수 있는지는 켤 때 화면 맨 위에 늘 적혀 있습니다.
|
|
317
324
|
|
|
318
325
|
```
|
|
319
|
-
deel 2.0
|
|
326
|
+
deel 2.1.0 ⌂ 이 안
|
|
320
327
|
보냄 이 컴퓨터 안 127.0.0.1:11434 ← 여기 말고는 어디로도 안 갑니다
|
|
321
328
|
```
|
|
322
329
|
|
|
@@ -1134,9 +1141,26 @@ AWS 키 · Google 키 · JWT · 주소에 박힌 열쇠 · `Authorization` 계
|
|
|
1134
1141
|
|
|
1135
1142
|
| 모드 | 언제 물어보나 |
|
|
1136
1143
|
|---|---|
|
|
1137
|
-
| `auto` (기본) | 안
|
|
1144
|
+
| `auto` (기본) | 안 물어봄 — **맡기는 모드**. 되돌리기가 안전망. 모델이 되묻거나 계획부터 내도 60초 안에 답이 없으면 알아서 진행(`askWait`) |
|
|
1138
1145
|
| `confirm` | 되돌릴 수 없는 명령만 |
|
|
1139
|
-
| `strict` | 파일 변경·명령
|
|
1146
|
+
| `strict` | 파일 변경·명령 전부. **바뀔 내용(diff)을 먼저 보여 주고** 묻습니다 |
|
|
1147
|
+
|
|
1148
|
+
회사에서 「바꾸기 전에 늘 사람이 본다」 를 정해야 하면 관리 정책에 `"approval": "strict"` 한 줄을
|
|
1149
|
+
적습니다. 그러면 `/mode` · Shift+Tab · `--yes` · 「앞으로 묻지 않기」 어느 것으로도 그 아래로 못
|
|
1150
|
+
내립니다 — [사내 배포 안내](docs/ko/company.md).
|
|
1151
|
+
|
|
1152
|
+
**「다 됐다」 는 검사가 정합니다.** 설정에 `"check": "npm test"` 를 적거나 `deel run --check` 로 주면,
|
|
1153
|
+
모델이 무엇을 바꾸고 끝내려 할 때 deel 이 그 검사를 **직접** 돌립니다. 실패하면 출력을 돌려주고 이어서
|
|
1154
|
+
고치게 하고(기본 3판), 끝내 실패면 실패로 끝냅니다 — `deel run` 은 종료코드 8. 검사 명령도 모델의
|
|
1155
|
+
명령과 같은 관문(규칙·훅·승인·위험 명령 차단)을 지납니다 — [완료 검사](docs/ko/company.md#완료-검사).
|
|
1156
|
+
|
|
1157
|
+
**얼마나 해내나는 골든셋으로 잽니다.** `deel eval --init` 이 예제 과제 다섯을 만들고, `deel eval` 이
|
|
1158
|
+
과제마다 임시 폴더에서 deel 을 돌린 뒤 **모델이 못 본** 정답 검사로 채점합니다. 결과를 남겨 두고
|
|
1159
|
+
지난번보다 나빠진 과제를 짚습니다 — [골든셋](docs/ko/company.md#골든셋).
|
|
1160
|
+
|
|
1161
|
+
위험 명령 차단은 **금지 목록 방식**입니다. 목록에 없는 꼴은 새어 나갈 수 있고, 실제로 그렇게
|
|
1162
|
+
찾아 막아 온 기록이 릴리스 노트에 있습니다. 그래서 하나에 기대지 않고 겹쳐 씁니다 — 작업 범위,
|
|
1163
|
+
정책 금지 규칙, 승인, 되돌리기, 감사 로그.
|
|
1140
1164
|
|
|
1141
1165
|
되돌리기 이력은 파일 내용을 통째로 담기 때문에 큰 파일을 여러 번 고치면 금방 커집니다.
|
|
1142
1166
|
32MB 를 넘으면 **최근 50턴만 남기고** 오래된 것을 버립니다. 방금 한 일은 언제나
|
|
@@ -1240,7 +1264,7 @@ deel stats # 이 폴더에서 실제로 무엇을 했나 (.de
|
|
|
1240
1264
|
## 개발
|
|
1241
1265
|
|
|
1242
1266
|
```bash
|
|
1243
|
-
npm test 전체 검증 (
|
|
1267
|
+
npm test 전체 검증 (14,322항목 — 몇몇은 터미널에 따라 갈립니다)
|
|
1244
1268
|
npm run coverage 검사가 소스의 어디를 밟았는지
|
|
1245
1269
|
npm run verify 반입·통신 검증만
|
|
1246
1270
|
npm run bench 편집 성공률 측정
|
|
@@ -1297,7 +1321,7 @@ zip 은 진짜 `unzip` 으로, tar 는 진짜 `tar` 가 만든 것을 읽혀 교
|
|
|
1297
1321
|
| `exitcode` · `doorparity` | 7 · 19 | 화면에 적은 종료코드 표가 진짜인가 · 문 **네 개**가 같은 것을 주는가 |
|
|
1298
1322
|
| `no-bundle` | 28 | 배포 묶음에 남의 것이 안 섞였는가 · 검사 파일 위생 |
|
|
1299
1323
|
| `edit-bench` | 15건 | 편집 성공률 |
|
|
1300
|
-
| `mutate` | 어긋 1,
|
|
1324
|
+
| `mutate` | 어긋 1,785개 | **검사가 정말 지키는가** — 지켜야 할 줄을 일부러 어긋내고 빨개지는지 본다 |
|
|
1301
1325
|
|
|
1302
1326
|
> **자세히** — 어디를 밟았는지 · 폴더 구조
|
|
1303
1327
|
>
|
|
@@ -1309,7 +1333,10 @@ zip 은 진짜 `unzip` 으로, tar 는 진짜 `tar` 가 만든 것을 읽혀 교
|
|
|
1309
1333
|
|
|
1310
1334
|
| 판 | 무엇이 바뀌었나 |
|
|
1311
1335
|
|---|---|
|
|
1312
|
-
| **[2.0
|
|
1336
|
+
| **[2.1.0](docs/ko/releases/2.1.md#210)** | 맡기면 멈추지 않고, 묻게 하면 diff 를 보여 줍니다 — 「다 됐다」 는 검사가 정합니다(`check`) · 얼마나 해내나는 골든셋으로 잽니다(`deel eval`) · 관리 정책 `"approval"` 로 회사가 승인 바닥을 겁니다 |
|
|
1337
|
+
| [2.0.3](docs/ko/releases/2.0.md#203) | 2.0.2 는 npm 에 못 나갔습니다 — 이제 GitHub 릴리스는 npm 에 올라간 뒤에만 생깁니다 |
|
|
1338
|
+
| [2.0.2](docs/ko/releases/2.0.md#202) | 2.0.1 까지 넘겨 둔 것을 다 잡았습니다 — `deel run` 에만 없던 MCP 도구, 끝난 명령의 번호로 가던 `taskkill`, 한 번 넘어지면 세션 내내 못 쓰던 MCP 서버 |
|
|
1339
|
+
| [2.0.1](docs/ko/releases/2.0.md#201) | 울타리 하나가 안 걸렸습니다 — `sudo -u root bash` 가 `curl … \| bash` 막이를 지나갔습니다 — 그리고 관문 넷이 빨개질 수 없었습니다 |
|
|
1313
1340
|
| [2.0.0](docs/ko/releases/2.0.md#200) | 있다고 적힌 울타리마다 실제로 걸리는지 다시 봤습니다 — 바뀐 것 전부·어디를 어떻게 고쳤나·어떻게 찾았나(CHA) |
|
|
1314
1341
|
|
|
1315
1342
|
<p align="center">
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Vendor APIs connect too — **only when you say so**
|
|
|
20
20
|
|
|
21
21
|
[](https://github.com/jysvai/deel-local-cli/actions/workflows/test.yml)
|
|
22
22
|
[](https://github.com/jysvai/deel-local-cli/actions/workflows/codeql.yml)
|
|
23
|
-
[](docs/en/develop.md)
|
|
24
24
|
|
|
25
25
|
[](https://www.npmjs.com/package/deel-local-cli?activeTab=dependencies)
|
|
26
26
|
[](package.json)
|
|
@@ -162,6 +162,7 @@ This page is the **summary**. Each section links to the detail behind it.
|
|
|
162
162
|
| [Extending](docs/en/extend.md) | Skills · plugins · MCP · subagents · hooks · ACP |
|
|
163
163
|
| [Speed and spend](docs/en/tuning.md) | Per-stage effort · the prefix cache · context length |
|
|
164
164
|
| [Safety and corporate review](docs/en/safety.md) | Undo · working scope · audit log · the review package |
|
|
165
|
+
| [Rolling it out at work](docs/en/company.md) | First-time users · one policy file · where requests go · what the guards cannot do |
|
|
165
166
|
| [Configuration](docs/en/config.md) · [Development](docs/en/develop.md) | Env vars · run flags · running the tests · folder layout |
|
|
166
167
|
| [Release notes](docs/en/releases.md) | [1.16.x](docs/en/releases/1.x.md#116x) · [1.15.x](docs/en/releases/1.x.md#115x) · [1.14.x](docs/en/releases/1.x.md#114x) · [1.13.x](docs/en/releases/1.x.md#113x) · [1.12.x](docs/en/releases/1.x.md#112x) · [1.10.x](docs/en/releases/1.x.md#110x) · [1.9.x](docs/en/releases/1.x.md#19x) · [older](docs/en/releases.md) |
|
|
167
168
|
|
|
@@ -314,6 +315,12 @@ that sends `목적` instead of `purpose` still gets through.
|
|
|
314
315
|
npm install -g deel-local-cli
|
|
315
316
|
```
|
|
316
317
|
|
|
318
|
+
This always installs the newest version on npm, including over an older one. With `npx`, add `@latest`:
|
|
319
|
+
if an older deel is already installed, `npx deel-local-cli` runs that one instead of fetching a new one —
|
|
320
|
+
`npx deel-local-cli@latest` always gets the newest. `deel --version` shows what you are running.
|
|
321
|
+
If `npm i -g` still brings an old version, check `npm view deel-local-cli version` — a company npm
|
|
322
|
+
mirror can lag behind npmjs.org.
|
|
323
|
+
|
|
317
324
|
Or skip installing entirely — there is no `npm install` step:
|
|
318
325
|
|
|
319
326
|
```bash
|
|
@@ -389,7 +396,7 @@ deel --offline
|
|
|
389
396
|
The destination is printed at the top of every session:
|
|
390
397
|
|
|
391
398
|
```
|
|
392
|
-
deel 2.0
|
|
399
|
+
deel 2.1.0 ⌂ inside
|
|
393
400
|
Sends to this machine 127.0.0.1:11434 ← nowhere else
|
|
394
401
|
```
|
|
395
402
|
|
|
@@ -1236,9 +1243,27 @@ does not ask.
|
|
|
1236
1243
|
|
|
1237
1244
|
| Mode | Asks when |
|
|
1238
1245
|
|---|---|
|
|
1239
|
-
| `auto` (default) | Never — undo is the safety net |
|
|
1246
|
+
| `auto` (default) | Never — **the hand-off mode**; undo is the safety net. If the model asks a question or offers a plan first, it carries on by itself after 60 seconds with no answer (`askWait`) |
|
|
1240
1247
|
| `confirm` | Irreversible commands only |
|
|
1241
|
-
| `strict` | All file changes and commands |
|
|
1248
|
+
| `strict` | All file changes and commands. **Shows the change (a diff) first**, then asks |
|
|
1249
|
+
|
|
1250
|
+
If your organisation needs "a person sees every change before it lands", put `"approval": "strict"`
|
|
1251
|
+
in the managed policy. Then `/mode`, Shift+Tab, `--yes` and "don't ask again" all stop at that
|
|
1252
|
+
floor — see [Rolling it out at work](docs/en/company.md).
|
|
1253
|
+
|
|
1254
|
+
**A check, not the model, says when it is done.** Put `"check": "npm test"` in the config or pass
|
|
1255
|
+
`deel run --check`, and when the model has changed something and tries to finish, deel runs that check
|
|
1256
|
+
**itself**. A failure goes back to the model to keep fixing (3 rounds by default); still failing ends as
|
|
1257
|
+
failed — `deel run` exits with 8. The check goes through the same gates as the model's own commands
|
|
1258
|
+
(rules, hooks, approval, the dangerous-command guard) — see [Completion check](docs/en/company.md#completion-check).
|
|
1259
|
+
|
|
1260
|
+
**How much it gets done is measured with a golden set.** `deel eval --init` creates five example tasks,
|
|
1261
|
+
and `deel eval` runs deel on each one in a temp folder, then grades it with checks **the model never saw**.
|
|
1262
|
+
Results are kept, and tasks that got worse since last time are pointed out — see [Golden set](docs/en/company.md#golden-set).
|
|
1263
|
+
|
|
1264
|
+
Blocked commands are a **deny list**. Shapes the list does not know can get through, and the
|
|
1265
|
+
release notes record the ones found and closed so far. So no single layer is relied on: working
|
|
1266
|
+
scope, policy deny rules, approval, undo and the audit log are stacked.
|
|
1242
1267
|
|
|
1243
1268
|
Undo history stores whole file contents, so repeated edits to large files add up. Past 32MB
|
|
1244
1269
|
it keeps the **most recent 50 turns** and drops the rest. What you just did is always
|
|
@@ -1334,7 +1359,7 @@ Stored in `~/.deel/config.json`. A `.deel/config.json` in the project folder tak
|
|
|
1334
1359
|
## Development
|
|
1335
1360
|
|
|
1336
1361
|
```bash
|
|
1337
|
-
npm test Full suite (
|
|
1362
|
+
npm test Full suite (14,322 checks; a few are TTY-dependent)
|
|
1338
1363
|
npm run coverage Which lines the tests actually execute
|
|
1339
1364
|
npm run verify Import + network checks only
|
|
1340
1365
|
npm run bench Edit success rate
|
|
@@ -1378,7 +1403,7 @@ so one run tells you everything.
|
|
|
1378
1403
|
| `exitcode` · `doorparity` | 7 · 19 | The printed exit-code table is real · all **four** doors hand out the same thing |
|
|
1379
1404
|
| `no-bundle` | 28 | Nothing foreign in the published package; test-file hygiene |
|
|
1380
1405
|
| `edit-bench` | 15 cases | Edit success rate |
|
|
1381
|
-
| `mutate` | 1,
|
|
1406
|
+
| `mutate` | 1,785 mutants | **Whether the tests actually guard** — break the line on purpose, check it turns red |
|
|
1382
1407
|
|
|
1383
1408
|
> **More** — Coverage · Layout
|
|
1384
1409
|
>
|
|
@@ -1390,7 +1415,10 @@ so one run tells you everything.
|
|
|
1390
1415
|
|
|
1391
1416
|
| Version | What changed |
|
|
1392
1417
|
|---|---|
|
|
1393
|
-
| **[2.0
|
|
1418
|
+
| **[2.1.0](docs/en/releases/2.1.md#210)** | Hand it off and it keeps going; make it ask and it shows the diff — a check decides when it is done (`check`), a golden set measures how much gets done (`deel eval`), and `"approval"` in the managed policy lets a company set an approval floor |
|
|
1419
|
+
| [2.0.3](docs/en/releases/2.0.md#203) | 2.0.2 never reached npm — GitHub releases now appear only after npm has the version |
|
|
1420
|
+
| [2.0.2](docs/en/releases/2.0.md#202) | Everything 2.0.1 left open, closed — MCP tools missing only from `deel run`, `taskkill` sent to an exited command's pid, MCP servers that stayed down for the session after one crash |
|
|
1421
|
+
| [2.0.1](docs/en/releases/2.0.md#201) | One fence in 2.0.0 did not hold — `sudo -u root bash` walked through the `curl … \| bash` guard — and four gates could not go red |
|
|
1394
1422
|
| [2.0.0](docs/en/releases/2.0.md#200) | Every fence we said was there, checked for whether it actually holds — everything that changed, where and how it was fixed, and how it was found (CHA) |
|
|
1395
1423
|
|
|
1396
1424
|
<p align="center">
|
package/bin/deel.js
CHANGED
|
@@ -23,6 +23,7 @@ import { 규칙모으기, 어떻게할까, 확인목록, 확인인자, 확인돌
|
|
|
23
23
|
import { 기록자리, 세기, 도구차례, 막힘차례, 셈JSON } from '../src/stats.js';
|
|
24
24
|
import { 진찰 } from '../src/doctor.js';
|
|
25
25
|
import { 설명, 설명줄들 } from '../src/configexplain.js';
|
|
26
|
+
import { runEval } from '../src/eval/run.js';
|
|
26
27
|
|
|
27
28
|
const MIN_NODE = 20;
|
|
28
29
|
|
|
@@ -625,6 +626,8 @@ const BOOL = new Set([
|
|
|
625
626
|
'hard',
|
|
626
627
|
// trust --off · --list, scan --save · --pick. 여태 목록에 없어 뒤의 낱말을 삼킬 수 있었다.
|
|
627
628
|
'off', 'list', 'save', 'pick',
|
|
629
|
+
// eval --init · --keep (src/eval/run.js).
|
|
630
|
+
'init', 'keep',
|
|
628
631
|
]);
|
|
629
632
|
|
|
630
633
|
/*
|
|
@@ -646,6 +649,8 @@ const BOOL = new Set([
|
|
|
646
649
|
const 값깃발 = new Set([
|
|
647
650
|
'root', 'mode', 'work', 'level', 'ctx', 'max-tokens', 'think', 'effort', 'output-schema',
|
|
648
651
|
'out', 'only', 'days', 'tool', 'url', 'key', 'model', 'host', 'ports', 'timeout', 'rm', 'delete',
|
|
652
|
+
// run --check <명령> (agent/donecheck.js) · eval --repeat <수> (src/eval/run.js).
|
|
653
|
+
'check', 'repeat',
|
|
649
654
|
]);
|
|
650
655
|
// 값을 줘도 되고 안 줘도 되는 깃발. `--resume` 만 치면 이어 할 대화를 고른다.
|
|
651
656
|
const 값골라깃발 = new Set(['resume']);
|
|
@@ -902,6 +907,8 @@ function help() {
|
|
|
902
907
|
say(` ${c.gray('--json')} 결과를 JSON 한 덩이로 (답·도구 횟수·토큰·끝난 까닭)`);
|
|
903
908
|
say(` ${c.gray('--quiet')} 도구가 무엇을 했는지 안 적음 (오류는 그래도 적음)`);
|
|
904
909
|
say(` ${c.gray('--yes')} 승인이 필요한 것도 그냥 실행. ${c.yellow('기본은 거부입니다')}`);
|
|
910
|
+
// 새로 넣는 도움말 줄은 말() 로 적는다 — 영어로 켠 사람에게 한국어 줄을 더 새게 하지 않는다(test/langleak.test.js 의 래칫).
|
|
911
|
+
say(` ${c.gray('--check <cmd>')} ${말('cli.checkFlag')}`);
|
|
905
912
|
/*
|
|
906
913
|
* 답의 모양을 못 박는 자리 (src/agent/outschema.js).
|
|
907
914
|
*
|
|
@@ -914,7 +921,13 @@ function help() {
|
|
|
914
921
|
// 이 줄은 src/oneshot.js 의 EXIT 와 짝이다. test/exitcode.test.js 가 둘이
|
|
915
922
|
// 어긋나면 빨개진다 — 한 판 동안 refusal(6) 이 여기서 빠져 있었고, 그
|
|
916
923
|
// 사실을 말해 주는 자리가 아무 데도 없었다.
|
|
917
|
-
say(` ${c.gray('끝난 까닭이 종료코드에 담깁니다:')} ${c.gray('0 끝냄 · 1 오류 · 2 걸음수상한 · 3 헛돎 · 4 중단 · 5 말없이끊김 · 6 거절 · 7 모양안맞음 · 64 사용법틀림')}`);
|
|
924
|
+
say(` ${c.gray('끝난 까닭이 종료코드에 담깁니다:')} ${c.gray('0 끝냄 · 1 오류 · 2 걸음수상한 · 3 헛돎 · 4 중단 · 5 말없이끊김 · 6 거절 · 7 모양안맞음 · 8 검사실패 · 64 사용법틀림')}`);
|
|
925
|
+
say('');
|
|
926
|
+
say(` ${c.bold(말('cli.evalTitle'))} ${c.gray(말('cli.evalWhy'))}`);
|
|
927
|
+
say('');
|
|
928
|
+
say(` ${c.cyan('deel eval --init')} ${말('cli.evalInit')}`);
|
|
929
|
+
say(` ${c.cyan('deel eval [dir]')} ${말('cli.evalRun')}`);
|
|
930
|
+
say(` ${c.gray('--repeat <n> · --only <name> · --keep · --json')}`);
|
|
918
931
|
say('');
|
|
919
932
|
say(` ${c.bold('진단 직접 지정')} ${c.gray('— 설정을 남기지 않고 확인만 할 때')}`);
|
|
920
933
|
say('');
|
|
@@ -1113,6 +1126,8 @@ async function main() {
|
|
|
1113
1126
|
quiet: flags.quiet === true || flags.quiet === 'true',
|
|
1114
1127
|
// 답의 모양을 못 박는다. 이게 있으면 표준출력은 그 JSON 하나다.
|
|
1115
1128
|
outputSchema: flags['output-schema'] ? String(flags['output-schema']) : undefined,
|
|
1129
|
+
// 끝내려는 자리에서 돌릴 검사 (agent/donecheck.js). 설정의 check 를 이긴다.
|
|
1130
|
+
check: flags.check !== undefined ? String(flags.check) : undefined,
|
|
1116
1131
|
});
|
|
1117
1132
|
case '':
|
|
1118
1133
|
case 'chat':
|
|
@@ -1186,6 +1201,24 @@ async function main() {
|
|
|
1186
1201
|
return runRules(args, flags);
|
|
1187
1202
|
case 'doc2md':
|
|
1188
1203
|
return runDoc2md(args, flags);
|
|
1204
|
+
// 과제 모음(골든셋)을 실제 모델로 돌려 성공률을 잰다 (src/eval/run.js).
|
|
1205
|
+
case 'eval':
|
|
1206
|
+
return runEval({
|
|
1207
|
+
폴더: args[0] ?? null,
|
|
1208
|
+
init: flags.init === true || flags.init === 'true',
|
|
1209
|
+
repeat: flags.repeat ?? 1,
|
|
1210
|
+
keep: flags.keep === true || flags.keep === 'true',
|
|
1211
|
+
json: flags.json === true || flags.json === 'true',
|
|
1212
|
+
only: flags.only !== undefined ? String(flags.only) : null,
|
|
1213
|
+
시간초: flags.timeout !== undefined ? Number(flags.timeout) : null,
|
|
1214
|
+
// 과제마다 띄우는 `deel run` 에 그대로 넘길 것 — 바깥 게이트웨이면 --online 이 있어야 돈다.
|
|
1215
|
+
깃발들: [
|
|
1216
|
+
...(flags.online === true || flags.online === 'true' ? ['--online'] : []),
|
|
1217
|
+
...(flags.offline === true || flags.offline === 'true' ? ['--offline'] : []),
|
|
1218
|
+
...(flags.think ? ['--think', String(flags.think)] : []),
|
|
1219
|
+
...(flags.effort ? ['--effort', String(flags.effort)] : []),
|
|
1220
|
+
],
|
|
1221
|
+
});
|
|
1189
1222
|
case 'sbom':
|
|
1190
1223
|
return runSbom(flags);
|
|
1191
1224
|
case 'scan':
|
package/package.json
CHANGED
package/src/acp/serve.js
CHANGED
|
@@ -27,10 +27,11 @@
|
|
|
27
27
|
// 그래서 여기서 process.stdout.write 를 통째로 바꿔 끼운다. 부르는 자리를
|
|
28
28
|
// 하나하나 찾아 막는 방법도 있지만, 그건 앞으로 새로 쓰는 코드까지 계속
|
|
29
29
|
// 조심해야 한다는 뜻이다 — 언젠가 반드시 한 군데를 빠뜨린다.
|
|
30
|
-
import { existsSync, statSync } from 'node:fs';
|
|
30
|
+
import { existsSync, statSync, realpathSync } from 'node:fs';
|
|
31
31
|
import { isAbsolute, join, resolve } from 'node:path';
|
|
32
32
|
import { VERSION } from '../version.js';
|
|
33
|
-
import { 규칙모으기, 늘허락,
|
|
33
|
+
import { 규칙모으기, 늘허락, 정책읽기, 승인바닥 } from '../safety/policy.js';
|
|
34
|
+
import { 검사설정 } from '../agent/donecheck.js';
|
|
34
35
|
import { 훅읽기 } from '../safety/hooks.js';
|
|
35
36
|
import { 에이전트읽기 } from '../agent/agents.js';
|
|
36
37
|
import { 남길것읽기 } from '../safety/shellenv.js';
|
|
@@ -63,7 +64,7 @@ import { 연결, 줄나누기, 모르는방법오류, 잘못된인자오류, 인
|
|
|
63
64
|
import { 도구시작, 도구끝남, 도구이름표, 도구갈래, 도구자리, 멈춘까닭, 프롬프트글, 되살린것 } from './map.js';
|
|
64
65
|
|
|
65
66
|
/** 우리가 말하는 규격 판. 정수 하나이고, 깨지는 변경에서만 올라간다. */
|
|
66
|
-
|
|
67
|
+
const 규격판 = 1;
|
|
67
68
|
|
|
68
69
|
/**
|
|
69
70
|
* 이 모드에서 표준출력을 잠근다.
|
|
@@ -74,6 +75,22 @@ export const 규격판 = 1;
|
|
|
74
75
|
*
|
|
75
76
|
* @returns {(줄: string) => void} 진짜 표준출력으로 쓰는 함수. ACP 만 이걸 쓴다
|
|
76
77
|
*/
|
|
78
|
+
/**
|
|
79
|
+
* 두 폴더 글이 **같은 자리**인가를 가르는 열쇠 (2.0.2 · 508).
|
|
80
|
+
*
|
|
81
|
+
* 글자로 견줬다(윈도에서만 소문자로). 그래서 한 폴더가 두 벌로 셌다 —
|
|
82
|
+
* 맥(대소문자를 안 가리는 APFS)의 `/Users/me/Proj` 와 `/users/me/proj`, 정션·심링크로 들어온 길,
|
|
83
|
+
* 8.3 짧은 이름. 같은 폴더인데 MCP 서버를 한 벌 더 띄우고, 같은 대화를 「다른 폴더로 열려
|
|
84
|
+
* 있다」 며 거절했다. 실제 자리(realpath)로 편 뒤에 견준다 — 맥·윈도의 realpath 는 디스크에
|
|
85
|
+
* 적힌 대소문자로 돌려준다. 윈도는 드라이브 글자(`C:` · `c:`)까지 맞추려고 소문자로 한 번 더 편다.
|
|
86
|
+
* 없는 자리면 글자 그대로 편다(견줄 것은 견준다).
|
|
87
|
+
*/
|
|
88
|
+
export function 자리열쇠(p) {
|
|
89
|
+
let r = resolve(String(p ?? ''));
|
|
90
|
+
try { r = realpathSync.native(r); } catch { /* 없거나 못 읽는 자리 — 글자로 견준다 */ }
|
|
91
|
+
return process.platform === 'win32' ? r.toLowerCase() : r;
|
|
92
|
+
}
|
|
93
|
+
|
|
77
94
|
export function 표준출력잠그기() {
|
|
78
95
|
const 진짜 = process.stdout.write.bind(process.stdout);
|
|
79
96
|
process.stdout.write = function (덩이, enc, cb) {
|
|
@@ -156,10 +173,7 @@ export async function acp(opts = {}) {
|
|
|
156
173
|
* 겹쳐 온 session/new 둘을 가르려면 이름을 짓는 그 자리에서 바로 적어 둬야 한다.
|
|
157
174
|
*/
|
|
158
175
|
const 열린자리 = new Map();
|
|
159
|
-
const 같은자리 = (가, 나) =>
|
|
160
|
-
const 편 = (p) => { const r = resolve(String(p)); return process.platform === 'win32' ? r.toLowerCase() : r; };
|
|
161
|
-
return 편(가) === 편(나);
|
|
162
|
-
};
|
|
176
|
+
const 같은자리 = (가, 나) => 자리열쇠(가) === 자리열쇠(나);
|
|
163
177
|
|
|
164
178
|
/*
|
|
165
179
|
* 폴더 → MCP 붙임. **폴더 하나에 한 벌**이다.
|
|
@@ -194,7 +208,24 @@ export async function acp(opts = {}) {
|
|
|
194
208
|
* @param {object} o
|
|
195
209
|
* @param {string|null} o.아이디 이어할 대화 이름. 주면 그 파일에 이어 쓴다
|
|
196
210
|
*/
|
|
197
|
-
|
|
211
|
+
/*
|
|
212
|
+
* 방을 짓다 넘어지면 **잡아 둔 이름을 푼다** (2.0.2 · 508).
|
|
213
|
+
*
|
|
214
|
+
* 이름은 짓자마자 열린자리 에 적는다(겹쳐 온 session/new 가 피하게). 그런데 그 뒤에서
|
|
215
|
+
* 넘어지면(훅·에이전트·감사기록을 여는 자리) 방은 없는데 이름만 남아, 이 창이 끝날 때까지
|
|
216
|
+
* 그 이름을 「다른 폴더로 열려 있다」 며 되살리기를 거절하고 정리(prune)에서도 뺐다.
|
|
217
|
+
*/
|
|
218
|
+
async function 방만들기(요청, 옵션 = {}) {
|
|
219
|
+
const 잡은이름 = [];
|
|
220
|
+
try {
|
|
221
|
+
return await 방짓기(요청, 옵션, 잡은이름);
|
|
222
|
+
} catch (err) {
|
|
223
|
+
for (const id of 잡은이름) if (!방들.has(id)) 열린자리.delete(id);
|
|
224
|
+
throw err;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async function 방짓기(요청, { 아이디 = null } = {}, 잡은이름 = []) {
|
|
198
229
|
/*
|
|
199
230
|
* 작업 폴더를 **설정보다 먼저** 정한다.
|
|
200
231
|
*
|
|
@@ -212,9 +243,13 @@ export async function acp(opts = {}) {
|
|
|
212
243
|
* 그 경로를 통째로 새로 만들었다. 둘 다 에디터가 잘못 준 것이니 잘못된 인자로 답한다.
|
|
213
244
|
* 안 주면 예전처럼 --root(없으면 띄운 자리)를 쓴다 — 그건 사람이 띄울 때 정한 것이다.
|
|
214
245
|
*/
|
|
215
|
-
|
|
246
|
+
/*
|
|
247
|
+
* **빈 글도 준 것이다** (2.0.2 · 508). 빈 글을 안 준 것으로 쳐서 --root 로 갔다 — 규격 위반 입력을
|
|
248
|
+
* 사람이 띄울 때 정한 자리로 조용히 바꿔 여는 것이다. 에디터가 cwd 를 못 채웠다는 뜻이니 거절한다.
|
|
249
|
+
*/
|
|
250
|
+
const 준자리 = typeof 요청?.cwd === 'string' ? 요청.cwd : null;
|
|
216
251
|
if (준자리 != null) {
|
|
217
|
-
if (!isAbsolute(준자리)) throw 잘못된인자오류(`cwd 는 절대 경로여야 합니다: ${준자리}`);
|
|
252
|
+
if (!isAbsolute(준자리)) throw 잘못된인자오류(`cwd 는 절대 경로여야 합니다: ${준자리 || '(빈 글)'}`);
|
|
218
253
|
let 폴더인가 = false;
|
|
219
254
|
try { 폴더인가 = statSync(준자리).isDirectory(); } catch { /* 없다 */ }
|
|
220
255
|
if (!폴더인가) throw 잘못된인자오류(`cwd 가 있는 폴더가 아닙니다: ${준자리}`);
|
|
@@ -428,6 +463,7 @@ export async function acp(opts = {}) {
|
|
|
428
463
|
// begin() 이 이름을 옮겼을 수 있으니 그 뒤에 적는다. Store 를 지은 자리부터 여기까지
|
|
429
464
|
// 기다림이 없어서, 겹쳐 온 session/new 도 이 적힌 것을 보고 이름을 피한다.
|
|
430
465
|
열린자리.set(store.id, root);
|
|
466
|
+
잡은이름.push(store.id);
|
|
431
467
|
/*
|
|
432
468
|
* 남은 할 일과 시킨 말 원문도 이 파일과 묶는다 (agent/store.js 의 살림따라가기).
|
|
433
469
|
*
|
|
@@ -459,7 +495,8 @@ export async function acp(opts = {}) {
|
|
|
459
495
|
* 그래서 deel 은 늘 제 폴더의 .deel/mcp.json 만 본다. 사람이 직접 적은 것만
|
|
460
496
|
* 띄운다는 규칙이 대화 화면과 여기서 똑같이 유지된다.
|
|
461
497
|
*/
|
|
462
|
-
|
|
498
|
+
// 같은 폴더면 한 벌 — 글자가 달라도 (자리열쇠 머리말 · 2.0.2 · 508). `C:` · `c:` 로 두 벌 띄웠었다.
|
|
499
|
+
const 캐시열쇠 = 자리열쇠(root);
|
|
463
500
|
if (!mcp캐시.has(캐시열쇠)) {
|
|
464
501
|
mcp캐시.set(캐시열쇠, 다붙이기(root, {
|
|
465
502
|
// 봉인은 MCP 를 붙이는 자리에도 그대로 걸린다 (safety/runmode.js 의 봉인됐나).
|
|
@@ -510,6 +547,8 @@ export async function acp(opts = {}) {
|
|
|
510
547
|
get 눈있나() { return !!conn.vision; },
|
|
511
548
|
// 적어 둔 허락·금지 규칙 (safety/policy.js). 승인 모드보다 먼저 본다.
|
|
512
549
|
규칙들: 규칙모으기(cfg),
|
|
550
|
+
// 끝내려는 자리에서 돌릴 검사 (agent/donecheck.js). 터미널과 같은 설정을 읽는다.
|
|
551
|
+
완료검사: 검사설정(cfg),
|
|
513
552
|
// 사람이 적어 둔 훅 (safety/hooks.js). 에디터 안에서도 같은 것이 돌아야 한다 —
|
|
514
553
|
// 여기만 빠지면 「터미널에서는 막히고 에디터에서는 안 막힌다」 가 된다.
|
|
515
554
|
훅들: 훅정보.훅들,
|
|
@@ -533,7 +572,7 @@ export async function acp(opts = {}) {
|
|
|
533
572
|
*/
|
|
534
573
|
ask: async (_라벨, o = {}) => o?.def ?? '',
|
|
535
574
|
askPassword: async () => null,
|
|
536
|
-
confirm: (이름,
|
|
575
|
+
confirm: (이름, 인자, 곁것 = {}) => 승인묻기(방, 이름, 인자, 곁것?.미리보기),
|
|
537
576
|
};
|
|
538
577
|
|
|
539
578
|
방.ctx.배움 = new 배움(root, homeDir());
|
|
@@ -580,7 +619,7 @@ export async function acp(opts = {}) {
|
|
|
580
619
|
// deel 의 안전장치를 에디터의 승인 창으로 그대로 내보낸다. 이게 붙는 것과
|
|
581
620
|
// 안 붙는 것의 차이가 크다 — 안 붙으면 위험한 명령을 물어볼 데가 없어서
|
|
582
621
|
// 무조건 거부하게 되고, 그러면 에디터 안에서는 아무 일도 못 하는 도구가 된다.
|
|
583
|
-
async function 승인묻기(방, 이름,
|
|
622
|
+
async function 승인묻기(방, 이름, 인자, 미리보기 = []) {
|
|
584
623
|
/*
|
|
585
624
|
* ── 끊긴 턴의 승인은 없다 (사냥5 H5-3) ─────────────────────────────────
|
|
586
625
|
*
|
|
@@ -595,7 +634,13 @@ export async function acp(opts = {}) {
|
|
|
595
634
|
*/
|
|
596
635
|
const 신호 = 방.도는신호 ?? null;
|
|
597
636
|
if (신호?.aborted) return false;
|
|
598
|
-
|
|
637
|
+
/*
|
|
638
|
+
* 관리 정책이 승인 바닥을 걸었으면 「앞으로 묻지 않기」 는 없다 (safety/policy.js 의 승인바닥).
|
|
639
|
+
* 바닥은 바꾸기 전에 사람이 본다는 약속이라, 버튼 한 번으로 그 사람을 빼는 길을 주면
|
|
640
|
+
* 안 된다. 전에 눌러 둔 늘 허락도 이 판에서는 안 먹는다.
|
|
641
|
+
*/
|
|
642
|
+
const 바닥걸림 = 승인바닥().바닥 !== 'auto';
|
|
643
|
+
if (방.늘허락.has(이름) && !바닥걸림) return true;
|
|
599
644
|
|
|
600
645
|
const 아이디 = `t${++방.도구번호}`;
|
|
601
646
|
try {
|
|
@@ -608,10 +653,18 @@ export async function acp(opts = {}) {
|
|
|
608
653
|
status: 'pending',
|
|
609
654
|
locations: 도구자리(이름, 인자, null, { 뿌리: 방.root }),
|
|
610
655
|
rawInput: 인자 ?? {},
|
|
656
|
+
/*
|
|
657
|
+
* 무엇이 바뀌는지를 같이 보낸다 (tools/index.js 의 바뀔내용). 편집기는 이걸 승인 창에
|
|
658
|
+
* diff 로 그린다. 여태는 제목 한 줄과 날것 인자만 보내서, 사람은 old_string·new_string
|
|
659
|
+
* JSON 을 읽고 허락해야 했다. 새 파일이면 oldText 가 null 이다 (ACP 의 Diff 꼴).
|
|
660
|
+
*/
|
|
661
|
+
...(Array.isArray(미리보기) && 미리보기.length
|
|
662
|
+
? { content: 미리보기.map((것) => ({ type: 'diff', path: 것.경로, oldText: 것.전, newText: 것.후 })) }
|
|
663
|
+
: {}),
|
|
611
664
|
},
|
|
612
665
|
options: [
|
|
613
666
|
{ optionId: 'allow_once', name: '이번만 실행', kind: 'allow_once' },
|
|
614
|
-
{ optionId: 'allow_always', name: `${이름} 은 앞으로 묻지 않기`, kind: 'allow_always' },
|
|
667
|
+
...(바닥걸림 ? [] : [{ optionId: 'allow_always', name: `${이름} 은 앞으로 묻지 않기`, kind: 'allow_always' }]),
|
|
615
668
|
{ optionId: 'reject_once', name: '하지 않기', kind: 'reject_once' },
|
|
616
669
|
],
|
|
617
670
|
}, { signal: 신호 });
|
|
@@ -620,6 +673,7 @@ export async function acp(opts = {}) {
|
|
|
620
673
|
if (신호?.aborted) return false;
|
|
621
674
|
const 결과 = 답?.outcome ?? {};
|
|
622
675
|
if (결과.outcome !== 'selected') return false; // cancelled 도 여기로 온다
|
|
676
|
+
if (결과.optionId === 'allow_always' && 바닥걸림) return true;
|
|
623
677
|
if (결과.optionId === 'allow_always') {
|
|
624
678
|
방.늘허락.add(이름);
|
|
625
679
|
/*
|
|
@@ -846,6 +900,17 @@ export async function acp(opts = {}) {
|
|
|
846
900
|
말하기(`\n\n_(${옮긴말('ev.hookBlock')})_\n\n`);
|
|
847
901
|
break;
|
|
848
902
|
|
|
903
|
+
// 완료 검사 (agent/donecheck.js). 에디터에도 무엇을 돌렸고 어떻게 됐는지 적는다.
|
|
904
|
+
case 'check_start':
|
|
905
|
+
말하기(`\n\n_(${옮긴말('check.start', { 판: ev.판, 최대: ev.최대, 명령: ev.명령 })})_\n\n`);
|
|
906
|
+
break;
|
|
907
|
+
|
|
908
|
+
case 'check':
|
|
909
|
+
말하기(`\n\n_(${ev.ok === true ? 옮긴말('check.pass', { 명령: ev.명령 })
|
|
910
|
+
: ev.ok === false ? `${옮긴말('check.fail', { 판: ev.판, 최대: ev.최대, 요약: ev.요약 })} — ${ev.판 < ev.최대 ? 옮긴말('check.retry') : 옮긴말('check.gaveUp', { 판: ev.판 })}`
|
|
911
|
+
: 옮긴말('check.skipped', { 까닭: ev.까닭 })})_\n\n`);
|
|
912
|
+
break;
|
|
913
|
+
|
|
849
914
|
case 'nudge':
|
|
850
915
|
말하기(`\n\n_(${ev.why === '요청누락'
|
|
851
916
|
? 옮긴말('ev.nudgeMissed', { n: ev.빠진?.length ?? 0 })
|
|
@@ -1134,8 +1199,9 @@ export async function acp(opts = {}) {
|
|
|
1134
1199
|
// 이름 대화를 되살리라는데 A 폴더 방이 나가서, 그 뒤 한 말이 A 에 적히고 A 를
|
|
1135
1200
|
// 고친다. 폴더가 다르면 방만들기 로 보내고, 거기서 또렷하게 거절한다.
|
|
1136
1201
|
const 있던방 = 방들.get(아이디);
|
|
1137
|
-
|
|
1138
|
-
const
|
|
1202
|
+
// 빈 cwd 는 방만들기 가 거절한다 — 여기서 --root 로 바꿔 있던 방을 내주지 않는다 (2.0.2 · 508).
|
|
1203
|
+
const 바란자리 = typeof 인자?.cwd === 'string' ? 인자.cwd : (opts.root ?? process.cwd());
|
|
1204
|
+
const 방 = 있던방 && 바란자리 && 같은자리(있던방.root, 바란자리) ? 있던방 : await 방만들기(인자, { 아이디 });
|
|
1139
1205
|
|
|
1140
1206
|
/*
|
|
1141
1207
|
* 화면에 그릴 것과 모델에게 줄 것이 다르다.
|
package/src/agent/commit.js
CHANGED
|
@@ -299,7 +299,7 @@ export function 담기(뿌리, 경로들, { 전부 = false, 안쪽 = '' } = {})
|
|
|
299
299
|
*
|
|
300
300
|
* @returns {{샌것: string[], 못뺀것: string[]}}
|
|
301
301
|
*/
|
|
302
|
-
|
|
302
|
+
function 살림도로빼기(뿌리, 파일들) {
|
|
303
303
|
const 샌것 = 파일들.filter((f) => 살림에닿나(join(뿌리, f)));
|
|
304
304
|
if (!샌것.length) return { 샌것, 못뺀것: [] };
|
|
305
305
|
// 첫 커밋 전이면 HEAD 가 없어 restore 가 안 된다. 그때는 index 에서 지운다.
|
|
@@ -458,7 +458,7 @@ export function 답가르기(글) {
|
|
|
458
458
|
* 글자를 감춘다), 그렇게 적힌 것은 이력에 영영 남아 남의 터미널에서 다시 돈다.
|
|
459
459
|
* 줄바꿈과 탭만 남긴다.
|
|
460
460
|
*/
|
|
461
|
-
|
|
461
|
+
function 제어글자빼기(글) {
|
|
462
462
|
let 남길것 = '';
|
|
463
463
|
for (const 글자 of String(글 ?? '')) {
|
|
464
464
|
const 값 = 글자.codePointAt(0);
|
package/src/agent/compact.js
CHANGED
|
@@ -14,8 +14,8 @@ import { 그림장수, 글만 } from '../backend/vision.js';
|
|
|
14
14
|
|
|
15
15
|
// 몇 %에서 접기 시작할지. 접고 나서 다시 금방 차면 아무 소용이 없으니 넉넉히 비운다.
|
|
16
16
|
export const COMPACT_AT = 0.8;
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
const KEEP_TAIL_RATIO = 0.3; // 최근 대화 중 남길 비율
|
|
18
|
+
const KEEP_HEAD = 2; // 맨 처음 요청은 언제나 남긴다 (목표가 거기 있다)
|
|
19
19
|
|
|
20
20
|
/*
|
|
21
21
|
* ── 그 전에, 도구 결과부터 접는다 ──────────────────────────────────────
|
|
@@ -37,7 +37,7 @@ export const KEEP_HEAD = 2; // 맨 처음 요청은 언제나 남긴
|
|
|
37
37
|
*/
|
|
38
38
|
export const FOLD_AT = 0.55; // 이 아래로는 접을 이유가 없다
|
|
39
39
|
export const KEEP_RECENT = 4; // 최근 도구 결과 이만큼은 원문 그대로 둔다
|
|
40
|
-
|
|
40
|
+
const FOLD_MIN = 300; // 이보다 작으면 접어도 자리가 안 준다 (글자 수)
|
|
41
41
|
export const 접힘표 = '(접힘)';
|
|
42
42
|
|
|
43
43
|
/*
|
|
@@ -109,7 +109,7 @@ export const 캐시일때비울몫 = 0.10;
|
|
|
109
109
|
* (여기가 「두 번 넘게」 라고 적혀 있었다. 아래 셈은 두 번째에 이미 단정한다 —
|
|
110
110
|
* 한 번의 차이지만, 적힌 것과 하는 것이 다르면 다음 사람이 그 값을 못 믿는다.)
|
|
111
111
|
*/
|
|
112
|
-
|
|
112
|
+
const 재볼기회 = 2;
|
|
113
113
|
|
|
114
114
|
export function 캐시가도나(session) {
|
|
115
115
|
const u = session?.usage ?? {};
|