deel-local-cli 2.1.1 → 2.1.2
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 +5 -4
- package/README.md +5 -4
- package/bin/deel.js +56 -43
- package/package.json +1 -1
- package/src/acp/serve.js +85 -3
- package/src/agent/donecheck.js +19 -4
- package/src/agent/loop.js +6 -2
- package/src/agent/session.js +22 -5
- package/src/backend/http.js +2 -23
- package/src/backend/mcp.js +15 -0
- package/src/completion.js +2 -0
- package/src/eval/run.js +73 -14
- package/src/exit.js +116 -0
- package/src/i18n/en.js +3 -1
- package/src/i18n/ja.js +3 -1
- package/src/i18n/ko.js +3 -1
- package/src/i18n/zh.js +3 -1
- package/src/oneshot.js +20 -88
- package/src/repl.js +1 -1
- package/src/safety/undo.js +77 -7
- package/src/setup.js +3 -5
- package/src/ui/banner.js +8 -1
package/src/backend/mcp.js
CHANGED
|
@@ -952,6 +952,21 @@ export function 이름풀기(전체) {
|
|
|
952
952
|
return m ? { 서버: m[1], 도구: m[2] } : null;
|
|
953
953
|
}
|
|
954
954
|
|
|
955
|
+
/**
|
|
956
|
+
* 서버가 이 도구를 **읽기만 한다** 고 적었나 (MCP `annotations.readOnlyHint`).
|
|
957
|
+
*
|
|
958
|
+
* confirm 이 MCP 도구를 안 물을지 정하는 데만 쓴다 (loop.js 의 관문). 적힌 말은 남의 서버가 한
|
|
959
|
+
* 말이라 좁게 믿는다 — 참(`true`)일 때만, 그리고 「지운다」(destructiveHint) 를 같이 적었으면
|
|
960
|
+
* 앞뒤가 안 맞으니 안 믿는다. strict 는 이 말을 아예 안 본다.
|
|
961
|
+
*/
|
|
962
|
+
export function 읽기만하나(서버들, 전체) {
|
|
963
|
+
const 갈린것 = 이름풀기(전체);
|
|
964
|
+
if (!갈린것) return false;
|
|
965
|
+
const 서버 = (서버들 ?? []).find((s) => s?.이름 === 갈린것.서버);
|
|
966
|
+
const 적힌것 = (서버?.도구 ?? []).find((t) => t?.name === 갈린것.도구)?.annotations;
|
|
967
|
+
return 적힌것?.readOnlyHint === true && 적힌것?.destructiveHint !== true;
|
|
968
|
+
}
|
|
969
|
+
|
|
955
970
|
/**
|
|
956
971
|
* 설정에 적힌 서버를 전부 띄운다.
|
|
957
972
|
*
|
package/src/completion.js
CHANGED
|
@@ -91,6 +91,8 @@ export const 깃발들 = [
|
|
|
91
91
|
{ 이름: '--hard', 뜻: 'reset all 에서 되돌리기·감사기록까지', en: 'with reset all: undo snapshots and the audit log too', 값: false },
|
|
92
92
|
{ 이름: '--json', 뜻: '결과를 JSON 으로', en: 'output JSON', 값: false },
|
|
93
93
|
{ 이름: '--check', 뜻: 'run: 끝내기 전에 돌릴 검사 명령', en: 'run: check command to pass before finishing', 값: null },
|
|
94
|
+
{ 이름: '--check-rounds', 뜻: 'run: 검사를 몇 번까지 돌리나 (1~10)', en: 'run: how many times the check runs (1-10)', 값: null },
|
|
95
|
+
{ 이름: '--check-timeout', 뜻: 'run: 검사 한 번의 제한 시간(초)', en: 'run: time limit per check run (seconds)', 값: null },
|
|
94
96
|
{ 이름: '--repeat', 뜻: 'eval: 과제마다 몇 번 돌릴까', en: 'eval: runs per task', 값: null },
|
|
95
97
|
{ 이름: '--init', 뜻: 'eval: 예제 과제를 만든다', en: 'eval: write the example tasks', 값: false },
|
|
96
98
|
{ 이름: '--only', 뜻: 'eval: 고른 과제만 (쉼표) · sbom: 한 가지만', en: 'eval: only these tasks (comma); sbom: only one part', 값: null },
|
package/src/eval/run.js
CHANGED
|
@@ -97,20 +97,48 @@ export function 과제읽기(폴더) {
|
|
|
97
97
|
return 과제들;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
// 수 칸은 수나 수를 적은 글만 읽는다. Number(true) = 1 · Number(null) = 0 이라 참/거짓이 수로 통과했다 (2.1.2 2차 눈).
|
|
101
|
+
const 수로 = (v) => (typeof v === 'number' || (typeof v === 'string' && v.trim() !== '') ? Number(v) : NaN);
|
|
102
|
+
|
|
100
103
|
/** task.json 이 쓸 수 있는 모양인가. 쓸 수 있으면 null, 아니면 까닭. */
|
|
101
104
|
export function 설정탈(v) {
|
|
102
105
|
if (!v || typeof v !== 'object' || Array.isArray(v)) return 'task.json 이 객체가 아닙니다';
|
|
103
106
|
if (typeof v.prompt !== 'string' || !v.prompt.trim()) return 'prompt(시킬 말)가 없습니다';
|
|
104
107
|
if (typeof v.check !== 'string' || !v.check.trim()) return 'check(정답 검사 명령)가 없습니다';
|
|
105
108
|
for (const 칸 of ['timeout', 'checkTimeout']) {
|
|
106
|
-
if (v[칸] !== undefined && !(Number.isFinite(
|
|
109
|
+
if (v[칸] !== undefined && !(Number.isFinite(수로(v[칸])) && 수로(v[칸]) > 0)) return `${칸} 은 0 보다 큰 초여야 합니다`;
|
|
107
110
|
}
|
|
108
111
|
for (const 칸 of ['doneCheck', 'work']) {
|
|
109
112
|
if (v[칸] !== undefined && typeof v[칸] !== 'string') return `${칸} 은 글이어야 합니다`;
|
|
110
113
|
}
|
|
114
|
+
// 과제마다 완료 검사를 몇 번·얼마나 돌리나 (2.1.2) — deel run 의 --check-rounds · --check-timeout 으로 넘긴다.
|
|
115
|
+
if (v.doneCheckRounds !== undefined && !(Number.isInteger(수로(v.doneCheckRounds)) && 수로(v.doneCheckRounds) >= 1)) {
|
|
116
|
+
return 'doneCheckRounds 는 1 이상의 정수여야 합니다';
|
|
117
|
+
}
|
|
118
|
+
if (v.doneCheckTimeout !== undefined && !(Number.isFinite(수로(v.doneCheckTimeout)) && 수로(v.doneCheckTimeout) > 0)) {
|
|
119
|
+
return 'doneCheckTimeout 은 0 보다 큰 초여야 합니다';
|
|
120
|
+
}
|
|
121
|
+
if ((v.doneCheckRounds !== undefined || v.doneCheckTimeout !== undefined) && !v.doneCheck) {
|
|
122
|
+
return 'doneCheckRounds · doneCheckTimeout 은 doneCheck(완료 검사 명령)와 같이 적어야 합니다';
|
|
123
|
+
}
|
|
111
124
|
return null;
|
|
112
125
|
}
|
|
113
126
|
|
|
127
|
+
/**
|
|
128
|
+
* 과제 하나에 띄울 `deel run` 의 인자. 시킬 말은 `--` 뒤 맨 끝이다 — 대시로 시작해도 깃발로 안 읽힌다.
|
|
129
|
+
*/
|
|
130
|
+
export function 실행인자(설정, 작업, 깃발들 = []) {
|
|
131
|
+
return [
|
|
132
|
+
진입점, 'run', '--json', '--yes', '--root', 작업,
|
|
133
|
+
...(설정.work ? ['--work', 설정.work] : []),
|
|
134
|
+
...(설정.doneCheck ? ['--check', 설정.doneCheck] : []),
|
|
135
|
+
...(설정.doneCheck && 설정.doneCheckRounds !== undefined ? ['--check-rounds', String(설정.doneCheckRounds)] : []),
|
|
136
|
+
...(설정.doneCheck && 설정.doneCheckTimeout !== undefined ? ['--check-timeout', String(설정.doneCheckTimeout)] : []),
|
|
137
|
+
...깃발들,
|
|
138
|
+
'--', 설정.prompt,
|
|
139
|
+
];
|
|
140
|
+
}
|
|
141
|
+
|
|
114
142
|
/**
|
|
115
143
|
* 폴더를 통째로 복사한다. 원본이 없으면 아무것도 안 한다(start/ 가 없는 과제는 빈 폴더에서 시작).
|
|
116
144
|
*
|
|
@@ -189,15 +217,8 @@ export async function 한번돌리기(과제, { 판 = 1, 깃발들 = [], 남김
|
|
|
189
217
|
const 작업 = mkdtempSync(join(tmpdir(), 'deel-eval-'));
|
|
190
218
|
try {
|
|
191
219
|
폴더복사(join(과제.자리, 'start'), 작업);
|
|
192
|
-
const 제한초 =
|
|
193
|
-
const 인자 =
|
|
194
|
-
진입점, 'run', '--json', '--yes', '--root', 작업,
|
|
195
|
-
...(설정.work ? ['--work', 설정.work] : []),
|
|
196
|
-
...(설정.doneCheck ? ['--check', 설정.doneCheck] : []),
|
|
197
|
-
...깃발들,
|
|
198
|
-
// `--` 뒤는 낱말이다 — 시킬 말이 대시로 시작해도 깃발로 안 읽힌다.
|
|
199
|
-
'--', 설정.prompt,
|
|
200
|
-
];
|
|
220
|
+
const 제한초 = 제한초고르기(설정, 시간초);
|
|
221
|
+
const 인자 = 실행인자(설정, 작업, 깃발들);
|
|
201
222
|
const 돌림 = await 돌려보기(process.execPath, 인자, {
|
|
202
223
|
timeout: 제한초 * 1000, maxBuffer: 64 * 1024 * 1024,
|
|
203
224
|
덤: { cwd: 작업, env: { ...process.env, NO_COLOR: '1' } },
|
|
@@ -251,8 +272,12 @@ export function 과제별(결과들) {
|
|
|
251
272
|
/**
|
|
252
273
|
* 지난 결과와 견준다. 다 통과하던 과제가 하나라도 떨어졌으면 나빠짐, 못 하던 과제를 다 해내면 나아짐.
|
|
253
274
|
* 되풀이 수가 다르면 비율로 본다.
|
|
275
|
+
*
|
|
276
|
+
* 지난번에 있던 과제가 이번에 없으면 **사라짐**, 처음 재는 과제는 **새것** 으로 적는다 (2.1.2). 여태
|
|
277
|
+
* 사라진 과제는 말없이 빠져, 떨어지던 과제 폴더를 지우고 돌려도 남은 과제끼리 「지난번과 같습니다」 가
|
|
278
|
+
* 나왔다. `일부만`(--only)이면 안 고른 과제가 다 사라짐이 되므로 사라짐은 안 센다.
|
|
254
279
|
*/
|
|
255
|
-
export function 견주기(지난것,
|
|
280
|
+
export function 견주기(지난것, 지금것, { 일부만 = false } = {}) {
|
|
256
281
|
const 비율 = (x) => (x.판 ? x.통과 / x.판 : 0);
|
|
257
282
|
const 지난표 = new Map((지난것 ?? []).map((x) => [x.과제, x]));
|
|
258
283
|
const 나빠짐 = [];
|
|
@@ -266,9 +291,28 @@ export function 견주기(지난것, 지금것) {
|
|
|
266
291
|
if (비율(x) < 비율(전)) 나빠짐.push(x.과제);
|
|
267
292
|
else if (비율(x) > 비율(전)) 나아짐.push(x.과제);
|
|
268
293
|
}
|
|
269
|
-
|
|
294
|
+
const 지금이름 = new Set(지금것.map((x) => x.과제));
|
|
295
|
+
const 사라짐 = 일부만 ? [] : [...지난표.keys()].filter((이름) => !지금이름.has(이름));
|
|
296
|
+
const 새것 = 지금것.filter((x) => !지난표.has(x.과제)).map((x) => x.과제);
|
|
297
|
+
return { 나빠짐, 나아짐, 견준, 사라짐, 새것 };
|
|
270
298
|
}
|
|
271
299
|
|
|
300
|
+
/**
|
|
301
|
+
* 「지난번과 같습니다」 를 어디까지 말할 수 있나. 달라진 과제가 있거나 견준 것이 없으면 null.
|
|
302
|
+
* 견주지 않은 과제(사라짐 · 새것 · --only 로 안 고른 것)가 있으면 '견준만큼' — 처음 재는 과제가 떨어져도
|
|
303
|
+
* 견준 과제끼리 같으면 「같습니다」 가 나와 그 실패가 묻혔다 (2.1.2 2차 눈).
|
|
304
|
+
*/
|
|
305
|
+
export function 같음범위(견줌, { 일부만 = false } = {}) {
|
|
306
|
+
if (!견줌?.견준 || 견줌.나빠짐.length || 견줌.나아짐.length) return null;
|
|
307
|
+
return 일부만 || 견줌.사라짐.length || 견줌.새것.length ? '견준만큼' : '전부';
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* 과제 하나의 제한 시간(초). task.json 에 적힌 것이 `--timeout` 을 이긴다 — pytest-timeout 의 표시나
|
|
312
|
+
* jest 의 과제별 시간과 같은 차례다. `--timeout` 은 제 시간을 안 적은 과제의 기본값이다.
|
|
313
|
+
*/
|
|
314
|
+
export const 제한초고르기 = (설정, 시간초) => Number(설정?.timeout ?? 시간초 ?? 기본시간초);
|
|
315
|
+
|
|
272
316
|
/**
|
|
273
317
|
* 제일 새 결과 파일. 깨졌거나 과제별이 없는 것(손으로 적은 `{}` 따위)은 건너뛴다 — 견줄 것이 없다.
|
|
274
318
|
*
|
|
@@ -377,6 +421,10 @@ export async function runEval({ 폴더 = null, init = false, repeat = 1, keep =
|
|
|
377
421
|
if (!Number.isInteger(되풀이) || 되풀이 < 1 || 되풀이 > 최대되풀이) {
|
|
378
422
|
return 못돌림(64, 글(`--repeat 는 1 ~ ${최대되풀이} 사이의 정수여야 합니다: ${repeat}`, `--repeat must be a whole number from 1 to ${최대되풀이}: ${repeat}`));
|
|
379
423
|
}
|
|
424
|
+
// 0 · 글 · 음수가 그대로 넘어가면 setTimeout(0) · NaN 이 되어 과제마다 deel 을 곧바로 죽인다 — 전부 「시간 초과」 실패.
|
|
425
|
+
if (시간초 !== null && !(Number.isFinite(Number(시간초)) && Number(시간초) > 0)) {
|
|
426
|
+
return 못돌림(64, 글(`--timeout 은 0 보다 큰 초여야 합니다: ${시간초}`, `--timeout must be a number of seconds above 0: ${시간초}`));
|
|
427
|
+
}
|
|
380
428
|
if (!existsSync(고른폴더)) {
|
|
381
429
|
return 못돌림(1, 글(`과제 모음이 없습니다 — ${보일}`, `No task folder — ${보일}`),
|
|
382
430
|
`${c.gray(글('예제부터 만들려면:', 'To start from examples:'))} ${c.cyan('deel eval --init')}`);
|
|
@@ -390,6 +438,9 @@ export async function runEval({ 폴더 = null, init = false, repeat = 1, keep =
|
|
|
390
438
|
|
|
391
439
|
말하기('');
|
|
392
440
|
말하기(` ${c.bold(글('골든셋', 'Golden set'))} ${c.gray(`— ${보일} · ${글(`과제 ${과제들.length}개 · 과제마다 ${되풀이}번`, `${과제들.length} tasks · ${되풀이} run(s) each`)}`)}`);
|
|
441
|
+
// --timeout 을 줬는데 제 시간을 적은 과제가 있으면 그 과제는 적힌 값을 쓴다고 미리 말한다 (제한초고르기).
|
|
442
|
+
const 제시간 = 시간초 !== null ? 과제들.filter((x) => x.설정?.timeout !== undefined).length : 0;
|
|
443
|
+
if (제시간) 말하기(` ${c.gray(글(`task.json 에 timeout 을 적은 과제 ${제시간}개는 --timeout 대신 그 값을 씁니다`, `${제시간} task(s) set their own timeout in task.json and use it instead of --timeout`))}`);
|
|
393
444
|
말하기('');
|
|
394
445
|
|
|
395
446
|
/*
|
|
@@ -436,7 +487,7 @@ export async function runEval({ 폴더 = null, init = false, repeat = 1, keep =
|
|
|
436
487
|
const 통과수 = 결과들.filter((r) => r.통과).length;
|
|
437
488
|
const 모델 = 결과들.find((r) => r.deel?.model)?.deel.model ?? null;
|
|
438
489
|
const 지난 = 지난결과(고른폴더, { 전체만: !only, 이름들: only ? 과제들.map((x) => x.이름) : null });
|
|
439
|
-
const 견줌 = 견주기(지난?.값?.과제별,
|
|
490
|
+
const 견줌 = 견주기(지난?.값?.과제별, 묶음, { 일부만: !!only });
|
|
440
491
|
const 초 = Math.round((Date.now() - t0) / 1000);
|
|
441
492
|
const 토큰 = 결과들.reduce((a, r) => ({ in: a.in + (r.deel?.usage?.in ?? 0), out: a.out + (r.deel?.usage?.out ?? 0) }), { in: 0, out: 0 });
|
|
442
493
|
|
|
@@ -475,7 +526,15 @@ export async function runEval({ 폴더 = null, init = false, repeat = 1, keep =
|
|
|
475
526
|
if (지난) {
|
|
476
527
|
if (견줌.나빠짐.length) 말하기(` ${c.red('▼')} ${글('지난번보다 나빠짐:', 'Worse than last time:')} ${견줌.나빠짐.join(' · ')}`);
|
|
477
528
|
if (견줌.나아짐.length) 말하기(` ${c.green('▲')} ${글('지난번보다 나아짐:', 'Better than last time:')} ${견줌.나아짐.join(' · ')}`);
|
|
478
|
-
if (
|
|
529
|
+
if (견줌.사라짐.length) 말하기(` ${c.yellow('⚠')} ${글('지난번에 있던 과제가 이번엔 없습니다:', 'Tasks from last time are missing now:')} ${견줌.사라짐.join(' · ')}`);
|
|
530
|
+
if (견줌.새것.length) 말하기(` ${c.gray(글(`처음 재는 과제: ${견줌.새것.join(' · ')}`, `Measured for the first time: ${견줌.새것.join(' · ')}`))}`);
|
|
531
|
+
// 견주지 않은 과제가 있으면 「같다」 는 견준 과제끼리의 말이다 — 그렇게 적는다.
|
|
532
|
+
const 같음 = 같음범위(견줌, { 일부만: !!only });
|
|
533
|
+
if (같음) {
|
|
534
|
+
말하기(` ${c.gray(같음 === '견준만큼'
|
|
535
|
+
? 글(`견준 과제 ${견줌.견준}개는 지난번(${지난.파일})과 같습니다`, `The ${견줌.견준} task(s) compared are the same as last time (${지난.파일})`)
|
|
536
|
+
: 글(`지난번(${지난.파일})과 같습니다`, `Same as last time (${지난.파일})`))}`);
|
|
537
|
+
}
|
|
479
538
|
}
|
|
480
539
|
if (남긴곳) 말하기(` ${c.gray(글(`결과: ${relative(뿌리, 남긴곳)}`, `Results: ${relative(뿌리, 남긴곳)}`))}`);
|
|
481
540
|
else if (못남긴까닭) {
|
package/src/exit.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// 종료코드와 시작도 못 한 실패 한 덩이 — `deel run` 과 진입점(bin/deel.js)이 같이 쓴다.
|
|
2
|
+
//
|
|
3
|
+
// oneshot.js 에서 떼어 냈다 (2.1.2). 진입점이 이 표 하나 때문에 oneshot.js 를 불러오면 대화 화면·도구·
|
|
4
|
+
// 게이트웨이까지 딸려 와서, `deel --version` 한 줄이 파일 164개를 읽었다. oneshot.js 는 그대로 내보낸다.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 종료코드.
|
|
8
|
+
*
|
|
9
|
+
* 스크립트는 화면 글이 아니라 이 숫자만 본다. 그래서 '끝났다' 와 '끝난 척했다'
|
|
10
|
+
* 를 반드시 갈라 놔야 한다 — 걸음 수 상한에 걸려 멈춘 것을 0 으로 돌려주면
|
|
11
|
+
* 야간 배치가 아무 일도 안 하고 초록불을 켠다. 그게 제일 나쁜 결말이다.
|
|
12
|
+
*/
|
|
13
|
+
export const EXIT = {
|
|
14
|
+
done: 0, // 끝까지 답했다
|
|
15
|
+
error: 1, // 오류로 끝났다 (연결 없음 · 시킬 말 없음 · 모델 오류)
|
|
16
|
+
limit: 2, // 도구 호출 걸음 수 상한에 닿았다
|
|
17
|
+
stuck: 3, // 같은 자리에서 헛돌아 스스로 멈췄다
|
|
18
|
+
aborted: 4, // 도중에 끊겼다 (Ctrl+C)
|
|
19
|
+
/*
|
|
20
|
+
* 서버가 끝났다는 말을 한 번도 안 주고 답을 멈췄다.
|
|
21
|
+
*
|
|
22
|
+
* 여기에 자기 코드가 있어야 한다. 전에는 이걸 아예 안 보고 `done`(0) 으로
|
|
23
|
+
* 끝냈다. `deel -p` 는 잡·CI 에서 돌고 그 뒤에 스크립트가 붙는데, 반쪽짜리
|
|
24
|
+
* 답이 0 으로 넘어가면 그 스크립트는 온전한 답으로 알고 그대로 쓴다.
|
|
25
|
+
* 사람이 나중에 결과를 보고 왜 반쪽인지 되짚을 방법이 없다.
|
|
26
|
+
*/
|
|
27
|
+
cutoff: 5,
|
|
28
|
+
/*
|
|
29
|
+
* 모델이 안 하겠다고 했다 (안전 판정).
|
|
30
|
+
*
|
|
31
|
+
* 이것도 자기 코드가 있어야 한다. 거절한 답은 **아무 일도 안 한 답**인데,
|
|
32
|
+
* 도구 호출이 없다는 것 말고는 짧은 답과 겉모습이 같다. 0 으로 끝내면
|
|
33
|
+
* 뒤에 붙은 스크립트는 일이 된 줄 알고 그 다음 단계로 넘어간다.
|
|
34
|
+
*
|
|
35
|
+
* 오류(1)와도 갈라 둔다. 고칠 자리가 다르기 때문이다 — 오류는 연결이나
|
|
36
|
+
* 열쇠를 보는 일이고, 거절은 **시킨 말을 바꾸는 일**이다.
|
|
37
|
+
*/
|
|
38
|
+
refusal: 6,
|
|
39
|
+
/*
|
|
40
|
+
* 답이 --output-schema 에 안 맞았다.
|
|
41
|
+
*
|
|
42
|
+
* 여기에도 자기 코드가 있어야 한다. 「모양을 못 박아 달라」 고 한 사람에게
|
|
43
|
+
* 모양이 안 맞는 것을 0 으로 넘기면, 파이프 뒤 스크립트가 그걸 온전한
|
|
44
|
+
* 것으로 받아 쓴다 — 그게 이 기능이 없애려던 바로 그 상황이다.
|
|
45
|
+
*
|
|
46
|
+
* 오류(1)와도 가른다. 고칠 자리가 다르다 — 오류는 연결을 보는 일이고,
|
|
47
|
+
* 이건 스키마나 시킨 말을 바꾸는 일이다.
|
|
48
|
+
*/
|
|
49
|
+
schema: 7,
|
|
50
|
+
/*
|
|
51
|
+
* 완료 검사가 통과하지 않은 채 끝났다 (agent/donecheck.js · 2.1.0).
|
|
52
|
+
*
|
|
53
|
+
* 모델은 「다 됐습니다」 라고 했는데 사람이 정해 둔 검사(`--check` · 설정의 `check`)가
|
|
54
|
+
* 정해 둔 판수를 다 돌고도 빨갛거나, 관문에 막혀 아예 못 돌았다. 0 으로 끝내면 야간
|
|
55
|
+
* 배치가 빨간 검사 위에 초록불을 켠다 — 이 기능이 없애려던 바로 그 결말이다.
|
|
56
|
+
*
|
|
57
|
+
* 오류(1)와 가른다. 고칠 자리가 다르다 — 연결이 아니라 코드나 검사 쪽이다.
|
|
58
|
+
*/
|
|
59
|
+
check: 8,
|
|
60
|
+
/*
|
|
61
|
+
* 인자를 잘못 줬다 — 모르는 깃발 · 값 없는 깃발 · 모르는 모드 이름 · 못 읽는 --ctx.
|
|
62
|
+
*
|
|
63
|
+
* 여기에 **따로** 둔다. 처음에는 `--work` 오타를 2 로 끝냈는데, 2 는 이 표에서 이미
|
|
64
|
+
* 「걸음 수 상한」 이다. `deel run --jsn …` 을 CI 에 건 사람은 오타 하나로 「일이 커서
|
|
65
|
+
* 멈췄다」 를 받고 작업을 쪼개러 간다. 고칠 자리가 스크립트 한 줄인데.
|
|
66
|
+
*
|
|
67
|
+
* 64 는 sysexits.h 의 EX_USAGE 다. 1~8 과 안 겹치고, 셸·CI 도구들이 「부른 모양이
|
|
68
|
+
* 틀렸다」 로 이미 알아듣는 수라 새로 지어내지 않았다. 이 경우는 모델을 한 번도 안 부른다.
|
|
69
|
+
*/
|
|
70
|
+
usage: 64,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 모델을 부르기 전에 선 실패 한 덩이 (사냥5 B5-10).
|
|
75
|
+
*
|
|
76
|
+
* 성공한 `--json` 에는 model 과 usage.prompt·cacheRead·cacheWrite·못잰것 이 있는데, 모델을
|
|
77
|
+
* 부르기 전에 선 실패(64 · 7 · 시킬 말 없음 · 없는 뿌리 · 연결 없음 · 대화 화면 전용)에는
|
|
78
|
+
* 그 칸들이 없었다. `jq .usage.prompt` 는 null 을, 모양을 못 박은 파서는 오류를 낸다 —
|
|
79
|
+
* 실패를 제일 잘 다뤄야 할 자리에서 파서가 먼저 죽는다. 칸은 늘 같게 두고 값만 비운다.
|
|
80
|
+
*
|
|
81
|
+
* bin/deel.js 의 인자탈·마지막 catch 도 이걸로 짓는다. 세 벌이면 언젠가 한 벌만 고친다.
|
|
82
|
+
*/
|
|
83
|
+
export function 실패덩이({ reason, code, why = '', model = null }) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false, reason, code, text: '',
|
|
86
|
+
tools: 0, steps: 0,
|
|
87
|
+
usage: { in: 0, out: 0, prompt: 0, cacheRead: 0, cacheWrite: 0, calls: 0, ms: 0, 못잰것: 0, retries: 0 },
|
|
88
|
+
model,
|
|
89
|
+
ms: 0,
|
|
90
|
+
...(why ? { why } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 열어 둔 연결을 닫는다. 프로그램을 끝내기 직전에 부른다.
|
|
96
|
+
*
|
|
97
|
+
* fetch 는 연결을 재사용하려고 소켓을 살려 둔다(keep-alive). 그래서 할 일이
|
|
98
|
+
* 끝나도 프로세스가 저절로 안 끝난다. 예전에는 그걸 process.exit() 으로
|
|
99
|
+
* 잘라 냈는데, 윈도우에서 닫는 중인 핸들을 두고 끊으면 libuv 가 abort 한다.
|
|
100
|
+
*
|
|
101
|
+
* Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), src\win\async.c
|
|
102
|
+
*
|
|
103
|
+
* 실제로 `deel scan` 이 결과를 다 찍고 나서 이렇게 죽었다. 화면에는 정상으로
|
|
104
|
+
* 보이는데 종료코드는 3221226505(0xC0000409) 였다.
|
|
105
|
+
*
|
|
106
|
+
* 그래서 잘라 내는 대신 닫는다. 이 자리는 Node 내부 이름이라 없을 수도 있으므로,
|
|
107
|
+
* 없으면 조용히 넘어간다 — 그때는 부르는 쪽의 시간제한이 받아 준다.
|
|
108
|
+
* 프록시 길은 요청마다 소켓을 새로 열고 끝나면 닫으므로(Connection: close) 여기 안 온다.
|
|
109
|
+
*/
|
|
110
|
+
export function closeConnections() {
|
|
111
|
+
try {
|
|
112
|
+
const d = globalThis[Symbol.for('undici.globalDispatcher.1')];
|
|
113
|
+
if (d && typeof d.close === 'function') return d.close().catch(() => {});
|
|
114
|
+
} catch { /* 없으면 그만 */ }
|
|
115
|
+
return Promise.resolve();
|
|
116
|
+
}
|
package/src/i18n/en.js
CHANGED
|
@@ -319,7 +319,7 @@ export const en = {
|
|
|
319
319
|
'approve.auto.line': 'edits without asking. /undo is the safety net',
|
|
320
320
|
'approve.confirm.name': 'risky only',
|
|
321
321
|
'approve.confirm.short': 'risky',
|
|
322
|
-
'approve.confirm.line': 'asks before commands it cannot take back. Files are edited without asking',
|
|
322
|
+
'approve.confirm.line': 'asks before commands it cannot take back and MCP tools. Files are edited without asking',
|
|
323
323
|
'approve.strict.name': 'ask always',
|
|
324
324
|
'approve.strict.short': 'always',
|
|
325
325
|
'approve.strict.line': 'asks before every file edit and every command',
|
|
@@ -520,12 +520,14 @@ export const en = {
|
|
|
520
520
|
'ev.nudgeRead': 'It was about to finish having only read things — pushed back once',
|
|
521
521
|
'check.start': 'Completion check ({판}/{최대}) — {명령}',
|
|
522
522
|
'check.clamped': '{칸} {준값} is over the limit — using {쓴값}',
|
|
523
|
+
'check.invalid': '{칸} {준값} is not a usable value — using the default {쓴값}',
|
|
523
524
|
'check.pass': 'Completion check passed — {명령}',
|
|
524
525
|
'check.fail': 'Completion check failed ({판}/{최대}) — {요약}',
|
|
525
526
|
'check.retry': 'Sending the failure back to fix',
|
|
526
527
|
'check.gaveUp': 'Still failing after {판} runs — ending as failed',
|
|
527
528
|
'check.skipped': 'Could not run the completion check — {까닭}',
|
|
528
529
|
'cli.checkFlag': 'run this check before finishing; failures go back to be fixed, and still failing ends with 8',
|
|
530
|
+
'cli.checkRoundsFlag': 'for this run only: how many times the check runs (1-10; fixes = runs - 1) and the time limit per run (s)',
|
|
529
531
|
'cli.evalTitle': 'Golden set',
|
|
530
532
|
'cli.evalWhy': '— run a set of tasks on the real model and measure how many it gets done',
|
|
531
533
|
'cli.evalInit': 'create five example tasks in golden/',
|
package/src/i18n/ja.js
CHANGED
|
@@ -286,7 +286,7 @@ export const ja = {
|
|
|
286
286
|
'approve.auto.line': '訊かずに直します。/undo が受け皿です',
|
|
287
287
|
'approve.confirm.name': '危ないものだけ',
|
|
288
288
|
'approve.confirm.short': '危険時',
|
|
289
|
-
'approve.confirm.line': '
|
|
289
|
+
'approve.confirm.line': '取り消せないコマンドと MCP ツールの前に訊きます。ファイルは訊かずに直します',
|
|
290
290
|
'approve.strict.name': '毎回訊く',
|
|
291
291
|
'approve.strict.short': '毎回',
|
|
292
292
|
'approve.strict.line': 'ファイルを直すたび、コマンドを打つたびに訊きます',
|
|
@@ -478,12 +478,14 @@ export const ja = {
|
|
|
478
478
|
'ev.nudgeRead': '読むだけで終えようとしたので、一度押し戻しました',
|
|
479
479
|
'check.start': '完了チェック ({판}/{최대}) — {명령}',
|
|
480
480
|
'check.clamped': '{칸} {준값} は上限を超えるため {쓴값} にしました',
|
|
481
|
+
'check.invalid': '{칸} {준값} は使えない値のため既定の {쓴값} を使います',
|
|
481
482
|
'check.pass': '完了チェック合格 — {명령}',
|
|
482
483
|
'check.fail': '完了チェック失敗 ({판}/{최대}) — {요약}',
|
|
483
484
|
'check.retry': '失敗内容を返して直させます',
|
|
484
485
|
'check.gaveUp': '{판}回回しても失敗しました — 失敗として終えます',
|
|
485
486
|
'check.skipped': '完了チェックを回せませんでした — {까닭}',
|
|
486
487
|
'cli.checkFlag': '終える前にこのチェックを回し、通れば終了(失敗なら直させ、最後まで失敗なら 8)',
|
|
488
|
+
'cli.checkRoundsFlag': 'この実行だけ:チェックを回す回数(1〜10、直す機会は回数−1)と1回の制限時間(秒)',
|
|
487
489
|
'cli.evalTitle': 'ゴールデンセット',
|
|
488
490
|
'cli.evalWhy': '— 課題集を実際のモデルで回し、いくつこなせるかを測ります',
|
|
489
491
|
'cli.evalInit': 'golden/ に例題を五つ作ります',
|
package/src/i18n/ko.js
CHANGED
|
@@ -308,7 +308,7 @@ export const ko = {
|
|
|
308
308
|
'approve.auto.line': '안 묻고 고칩니다. 되돌리기(/undo)가 안전망입니다',
|
|
309
309
|
'approve.confirm.name': '위험만 확인',
|
|
310
310
|
'approve.confirm.short': '위험만',
|
|
311
|
-
'approve.confirm.line': '되돌릴 수 없는
|
|
311
|
+
'approve.confirm.line': '되돌릴 수 없는 명령·MCP 도구만 물어봅니다. 파일은 안 묻고 고칩니다',
|
|
312
312
|
'approve.strict.name': '모두 확인',
|
|
313
313
|
'approve.strict.short': '모두',
|
|
314
314
|
'approve.strict.line': '파일을 고치거나 명령을 돌리기 전에 매번 물어봅니다',
|
|
@@ -552,12 +552,14 @@ export const ko = {
|
|
|
552
552
|
'ev.nudgeRead': '읽기만 하고 끝내려고 해서 한 번 되밀었습니다',
|
|
553
553
|
'check.start': '완료 검사 ({판}/{최대}) — {명령}',
|
|
554
554
|
'check.clamped': '{칸} {준값} 은 상한을 넘어 {쓴값} 으로 줄였습니다',
|
|
555
|
+
'check.invalid': '{칸} {준값} 은 쓸 수 없는 값이라 기본값 {쓴값} 을 씁니다',
|
|
555
556
|
'check.pass': '완료 검사 통과 — {명령}',
|
|
556
557
|
'check.fail': '완료 검사 실패 ({판}/{최대}) — {요약}',
|
|
557
558
|
'check.retry': '실패 내용을 돌려주고 다시 고치게 합니다',
|
|
558
559
|
'check.gaveUp': '{판}번 돌렸는데도 실패했습니다 — 실패로 끝냅니다',
|
|
559
560
|
'check.skipped': '완료 검사를 못 돌렸습니다 — {까닭}',
|
|
560
561
|
'cli.checkFlag': '끝내려 할 때 이 검사를 돌려 통과해야 끝남 (실패하면 고치게 하고, 끝내 실패면 8)',
|
|
562
|
+
'cli.checkRoundsFlag': '이번 실행에서만 검사 판수(1~10, 고칠 기회는 판수−1)·한 번의 제한 시간(초)을 덮음',
|
|
561
563
|
'cli.evalTitle': '골든셋',
|
|
562
564
|
'cli.evalWhy': '— 과제 모음을 실제 모델로 돌려 몇 개를 해내나 잽니다',
|
|
563
565
|
'cli.evalInit': '예제 과제 다섯을 golden/ 에 만듭니다',
|
package/src/i18n/zh.js
CHANGED
|
@@ -286,7 +286,7 @@ export const zh = {
|
|
|
286
286
|
'approve.auto.line': '不问就改。/undo 是兜底',
|
|
287
287
|
'approve.confirm.name': '只问危险的',
|
|
288
288
|
'approve.confirm.short': '危险时',
|
|
289
|
-
'approve.confirm.line': '
|
|
289
|
+
'approve.confirm.line': '收不回的命令和 MCP 工具之前会问。改文件不问',
|
|
290
290
|
'approve.strict.name': '每次都问',
|
|
291
291
|
'approve.strict.short': '每次',
|
|
292
292
|
'approve.strict.line': '每改一个文件、每跑一条命令都问',
|
|
@@ -478,12 +478,14 @@ export const zh = {
|
|
|
478
478
|
'ev.nudgeRead': '只看不动就要收尾,已经推回去一次',
|
|
479
479
|
'check.start': '完成检查 ({판}/{최대}) — {명령}',
|
|
480
480
|
'check.clamped': '{칸} {준값} 超过上限,改用 {쓴값}',
|
|
481
|
+
'check.invalid': '{칸} {준값} 不是可用的值,改用默认值 {쓴값}',
|
|
481
482
|
'check.pass': '完成检查通过 — {명령}',
|
|
482
483
|
'check.fail': '完成检查失败 ({판}/{최대}) — {요약}',
|
|
483
484
|
'check.retry': '把失败内容交回去重新修',
|
|
484
485
|
'check.gaveUp': '跑了 {판} 次仍然失败 — 按失败结束',
|
|
485
486
|
'check.skipped': '没能跑完成检查 — {까닭}',
|
|
486
487
|
'cli.checkFlag': '结束前跑这个检查,通过才结束(失败就让它修,最后仍失败则返回 8)',
|
|
488
|
+
'cli.checkRoundsFlag': '仅本次运行:检查跑几次(1~10,修复机会 = 次数 − 1)和每次的时限(秒)',
|
|
487
489
|
'cli.evalTitle': '黄金集',
|
|
488
490
|
'cli.evalWhy': '— 用真实模型跑一组任务,测它能完成多少',
|
|
489
491
|
'cli.evalInit': '在 golden/ 里建五个示例任务',
|
package/src/oneshot.js
CHANGED
|
@@ -49,93 +49,10 @@ import { 모두끝내기 as 일감모두끝내기, 일감인자 } from './tools/
|
|
|
49
49
|
import { 첫이름 } from './tools/label.js';
|
|
50
50
|
import { 검사설정 } from './agent/donecheck.js';
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
* 스크립트는 화면 글이 아니라 이 숫자만 본다. 그래서 '끝났다' 와 '끝난 척했다'
|
|
56
|
-
* 를 반드시 갈라 놔야 한다 — 걸음 수 상한에 걸려 멈춘 것을 0 으로 돌려주면
|
|
57
|
-
* 야간 배치가 아무 일도 안 하고 초록불을 켠다. 그게 제일 나쁜 결말이다.
|
|
58
|
-
*/
|
|
59
|
-
export const EXIT = {
|
|
60
|
-
done: 0, // 끝까지 답했다
|
|
61
|
-
error: 1, // 오류로 끝났다 (연결 없음 · 시킬 말 없음 · 모델 오류)
|
|
62
|
-
limit: 2, // 도구 호출 걸음 수 상한에 닿았다
|
|
63
|
-
stuck: 3, // 같은 자리에서 헛돌아 스스로 멈췄다
|
|
64
|
-
aborted: 4, // 도중에 끊겼다 (Ctrl+C)
|
|
65
|
-
/*
|
|
66
|
-
* 서버가 끝났다는 말을 한 번도 안 주고 답을 멈췄다.
|
|
67
|
-
*
|
|
68
|
-
* 여기에 자기 코드가 있어야 한다. 전에는 이걸 아예 안 보고 `done`(0) 으로
|
|
69
|
-
* 끝냈다. `deel -p` 는 잡·CI 에서 돌고 그 뒤에 스크립트가 붙는데, 반쪽짜리
|
|
70
|
-
* 답이 0 으로 넘어가면 그 스크립트는 온전한 답으로 알고 그대로 쓴다.
|
|
71
|
-
* 사람이 나중에 결과를 보고 왜 반쪽인지 되짚을 방법이 없다.
|
|
72
|
-
*/
|
|
73
|
-
cutoff: 5,
|
|
74
|
-
/*
|
|
75
|
-
* 모델이 안 하겠다고 했다 (안전 판정).
|
|
76
|
-
*
|
|
77
|
-
* 이것도 자기 코드가 있어야 한다. 거절한 답은 **아무 일도 안 한 답**인데,
|
|
78
|
-
* 도구 호출이 없다는 것 말고는 짧은 답과 겉모습이 같다. 0 으로 끝내면
|
|
79
|
-
* 뒤에 붙은 스크립트는 일이 된 줄 알고 그 다음 단계로 넘어간다.
|
|
80
|
-
*
|
|
81
|
-
* 오류(1)와도 갈라 둔다. 고칠 자리가 다르기 때문이다 — 오류는 연결이나
|
|
82
|
-
* 열쇠를 보는 일이고, 거절은 **시킨 말을 바꾸는 일**이다.
|
|
83
|
-
*/
|
|
84
|
-
refusal: 6,
|
|
85
|
-
/*
|
|
86
|
-
* 답이 --output-schema 에 안 맞았다.
|
|
87
|
-
*
|
|
88
|
-
* 여기에도 자기 코드가 있어야 한다. 「모양을 못 박아 달라」 고 한 사람에게
|
|
89
|
-
* 모양이 안 맞는 것을 0 으로 넘기면, 파이프 뒤 스크립트가 그걸 온전한
|
|
90
|
-
* 것으로 받아 쓴다 — 그게 이 기능이 없애려던 바로 그 상황이다.
|
|
91
|
-
*
|
|
92
|
-
* 오류(1)와도 가른다. 고칠 자리가 다르다 — 오류는 연결을 보는 일이고,
|
|
93
|
-
* 이건 스키마나 시킨 말을 바꾸는 일이다.
|
|
94
|
-
*/
|
|
95
|
-
schema: 7,
|
|
96
|
-
/*
|
|
97
|
-
* 완료 검사가 통과하지 않은 채 끝났다 (agent/donecheck.js · 2.1.0).
|
|
98
|
-
*
|
|
99
|
-
* 모델은 「다 됐습니다」 라고 했는데 사람이 정해 둔 검사(`--check` · 설정의 `check`)가
|
|
100
|
-
* 정해 둔 판수를 다 돌고도 빨갛거나, 관문에 막혀 아예 못 돌았다. 0 으로 끝내면 야간
|
|
101
|
-
* 배치가 빨간 검사 위에 초록불을 켠다 — 이 기능이 없애려던 바로 그 결말이다.
|
|
102
|
-
*
|
|
103
|
-
* 오류(1)와 가른다. 고칠 자리가 다르다 — 연결이 아니라 코드나 검사 쪽이다.
|
|
104
|
-
*/
|
|
105
|
-
check: 8,
|
|
106
|
-
/*
|
|
107
|
-
* 인자를 잘못 줬다 — 모르는 깃발 · 값 없는 깃발 · 모르는 모드 이름 · 못 읽는 --ctx.
|
|
108
|
-
*
|
|
109
|
-
* 여기에 **따로** 둔다. 처음에는 `--work` 오타를 2 로 끝냈는데, 2 는 이 표에서 이미
|
|
110
|
-
* 「걸음 수 상한」 이다. `deel run --jsn …` 을 CI 에 건 사람은 오타 하나로 「일이 커서
|
|
111
|
-
* 멈췄다」 를 받고 작업을 쪼개러 간다. 고칠 자리가 스크립트 한 줄인데.
|
|
112
|
-
*
|
|
113
|
-
* 64 는 sysexits.h 의 EX_USAGE 다. 1~8 과 안 겹치고, 셸·CI 도구들이 「부른 모양이
|
|
114
|
-
* 틀렸다」 로 이미 알아듣는 수라 새로 지어내지 않았다. 이 경우는 모델을 한 번도 안 부른다.
|
|
115
|
-
*/
|
|
116
|
-
usage: 64,
|
|
117
|
-
};
|
|
52
|
+
// 종료코드 표와 실패덩이는 src/exit.js 에 있다 — 진입점이 이 파일 없이 쓰게 (2.1.2).
|
|
53
|
+
export { EXIT, 실패덩이 } from './exit.js';
|
|
54
|
+
import { EXIT, 실패덩이 } from './exit.js';
|
|
118
55
|
|
|
119
|
-
/**
|
|
120
|
-
* 모델을 부르기 전에 선 실패 한 덩이 (사냥5 B5-10).
|
|
121
|
-
*
|
|
122
|
-
* 성공한 `--json` 에는 model 과 usage.prompt·cacheRead·cacheWrite·못잰것 이 있는데, 모델을
|
|
123
|
-
* 부르기 전에 선 실패(64 · 7 · 시킬 말 없음 · 없는 뿌리 · 연결 없음 · 대화 화면 전용)에는
|
|
124
|
-
* 그 칸들이 없었다. `jq .usage.prompt` 는 null 을, 모양을 못 박은 파서는 오류를 낸다 —
|
|
125
|
-
* 실패를 제일 잘 다뤄야 할 자리에서 파서가 먼저 죽는다. 칸은 늘 같게 두고 값만 비운다.
|
|
126
|
-
*
|
|
127
|
-
* bin/deel.js 의 인자탈·마지막 catch 도 이걸로 짓는다. 세 벌이면 언젠가 한 벌만 고친다.
|
|
128
|
-
*/
|
|
129
|
-
export function 실패덩이({ reason, code, why = '', model = null }) {
|
|
130
|
-
return {
|
|
131
|
-
ok: false, reason, code, text: '',
|
|
132
|
-
tools: 0, steps: 0,
|
|
133
|
-
usage: { in: 0, out: 0, prompt: 0, cacheRead: 0, cacheWrite: 0, calls: 0, ms: 0, 못잰것: 0, retries: 0 },
|
|
134
|
-
model,
|
|
135
|
-
ms: 0,
|
|
136
|
-
...(why ? { why } : {}),
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
56
|
|
|
140
57
|
/**
|
|
141
58
|
* 표준입력에 실려 온 말을 통째로 읽는다.
|
|
@@ -307,6 +224,17 @@ export async function runOnce(opts = {}) {
|
|
|
307
224
|
}
|
|
308
225
|
}
|
|
309
226
|
|
|
227
|
+
/*
|
|
228
|
+
* --check-rounds · --check-timeout (2.1.2). 치는 자리에서 바로 고칠 수 있으니 틀린 값은 사용법 틀림(64)이다 —
|
|
229
|
+
* 설정 파일에 적힌 틀린 값은 기본값을 쓰고 화면에 말하는 것(donecheck.js 의 줄임)과 다르다.
|
|
230
|
+
*/
|
|
231
|
+
if (opts.checkRounds !== undefined && !(Number.isInteger(Number(opts.checkRounds)) && Number(opts.checkRounds) >= 1)) {
|
|
232
|
+
return 못함('usage', `--check-rounds 는 1 이상의 정수여야 합니다: ${opts.checkRounds}`);
|
|
233
|
+
}
|
|
234
|
+
if (opts.checkTimeout !== undefined && !(Number.isFinite(Number(opts.checkTimeout)) && Number(opts.checkTimeout) > 0)) {
|
|
235
|
+
return 못함('usage', `--check-timeout 은 0 보다 큰 초여야 합니다: ${opts.checkTimeout}`);
|
|
236
|
+
}
|
|
237
|
+
|
|
310
238
|
// ── 시킬 말 ───────────────────────────────────────────────────────────
|
|
311
239
|
// 인자로 준 것이 먼저다. 없을 때만 표준입력을 읽는다 —
|
|
312
240
|
// 둘 다 있을 때 무엇이 이기는지가 헷갈리면 스크립트가 조용히 엉뚱한 일을 한다.
|
|
@@ -629,7 +557,11 @@ export async function runOnce(opts = {}) {
|
|
|
629
557
|
// 안 거두면 배치가 끝나고도 언어 서버가 폴더를 물고 남는다.
|
|
630
558
|
lsp: { 켬: true },
|
|
631
559
|
// 끝내려는 자리에서 돌릴 검사 (agent/donecheck.js). `--check` 가 설정의 check 를 이긴다.
|
|
632
|
-
완료검사: 검사설정(
|
|
560
|
+
완료검사: 검사설정({
|
|
561
|
+
...cfg,
|
|
562
|
+
...(opts.checkRounds !== undefined ? { checkRounds: Number(opts.checkRounds) } : {}),
|
|
563
|
+
...(opts.checkTimeout !== undefined ? { checkTimeout: Number(opts.checkTimeout) } : {}),
|
|
564
|
+
}, opts.check),
|
|
633
565
|
// 되물을 사람이 없으니 기본값을 그대로 돌려준다.
|
|
634
566
|
ask: async (_label, o = {}) => o?.def ?? '',
|
|
635
567
|
// 엑셀 암호를 여기서 기다리면 그대로 선다. 없다고 바로 답한다 —
|
|
@@ -929,7 +861,7 @@ export async function runOnce(opts = {}) {
|
|
|
929
861
|
|
|
930
862
|
case 'check_start':
|
|
931
863
|
곁(` ${c.cyan('⧗')} ${c.gray(옮긴말('check.start', { 판: ev.판, 최대: ev.최대, 명령: ev.명령 }))}`);
|
|
932
|
-
for (const 줄 of ev.줄임 ?? []) 곁(` ${c.yellow('⚠')} ${c.gray(옮긴말('check.clamped', 줄))}`);
|
|
864
|
+
for (const 줄 of ev.줄임 ?? []) 곁(` ${c.yellow('⚠')} ${c.gray(옮긴말(줄.틀림 ? 'check.invalid' : 'check.clamped', 줄))}`);
|
|
933
865
|
break;
|
|
934
866
|
|
|
935
867
|
case 'check':
|
package/src/repl.js
CHANGED
|
@@ -3057,7 +3057,7 @@ export async function chatLoop(opts = {}) {
|
|
|
3057
3057
|
if (streamed) { 답비우기(); say(''); streamed = false; }
|
|
3058
3058
|
say('');
|
|
3059
3059
|
say(` ${c.cyan('⧗')} ${c.gray(옮긴말('check.start', { 판: ev.판, 최대: ev.최대, 명령: ev.명령 }))}`);
|
|
3060
|
-
for (const 줄 of ev.줄임 ?? []) say(` ${c.yellow('⚠')} ${c.gray(옮긴말('check.clamped', 줄))}`);
|
|
3060
|
+
for (const 줄 of ev.줄임 ?? []) say(` ${c.yellow('⚠')} ${c.gray(옮긴말(줄.틀림 ? 'check.invalid' : 'check.clamped', 줄))}`);
|
|
3061
3061
|
break;
|
|
3062
3062
|
|
|
3063
3063
|
case 'check':
|