deel-local-cli 1.6.3 → 1.8.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 +1182 -0
- package/README.md +850 -636
- package/bin/deel.js +44 -3
- package/package.json +3 -3
- package/src/acp/map.js +1 -1
- package/src/acp/serve.js +25 -2
- package/src/agent/loop.js +41 -9
- package/src/agent/session.js +15 -9
- package/src/backend/adapter.js +277 -4
- package/src/backend/ctxsize.js +16 -2
- package/src/backend/detect.js +104 -6
- package/src/backend/price.js +197 -0
- package/src/backend/retry.js +3 -0
- package/src/backend/scanui.js +2 -1
- package/src/backend/vision.js +26 -4
- package/src/commands.js +141 -38
- package/src/completion.js +21 -2
- package/src/i18n/en.js +160 -1
- package/src/i18n/index.js +22 -0
- package/src/i18n/ja.js +152 -1
- package/src/i18n/ko.js +173 -1
- package/src/i18n/zh.js +152 -1
- package/src/oneshot.js +39 -6
- package/src/pack/selfpack.js +1 -1
- package/src/providers/anthropic.js +48 -0
- package/src/providers/bedrock.js +102 -0
- package/src/providers/custom.js +65 -0
- package/src/providers/gemini.js +64 -0
- package/src/providers/index.js +121 -0
- package/src/providers/openai.js +68 -0
- package/src/repl.js +198 -33
- package/src/report.js +3 -2
- package/src/reset.js +397 -0
- package/src/safety/audit.js +5 -2
- package/src/safety/authcmd.js +305 -0
- package/src/safety/keystore.js +53 -0
- package/src/safety/runmode.js +123 -0
- package/src/safety/secrets.js +61 -0
- package/src/safety/undo.js +3 -2
- package/src/setup.js +215 -12
- package/src/tools/desc.en.js +19 -14
- package/src/tools/index.js +141 -43
- package/src/tools/jobs.js +17 -13
- package/src/tools/lsp.js +5 -4
- package/src/tools/outline.js +7 -3
- package/src/tools/task.js +10 -6
- package/src/tools/todo.js +9 -2
- package/src/tools/verify.js +9 -3
- package/src/tools/webfetch.js +2 -1
- package/src/ui/export.js +1 -1
- package/src/ui/histline.js +67 -0
- package/src/ui/status.js +88 -3
- package/README.en.md +0 -1025
package/bin/deel.js
CHANGED
|
@@ -14,6 +14,7 @@ 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';
|
|
17
18
|
|
|
18
19
|
const MIN_NODE = 20;
|
|
19
20
|
|
|
@@ -106,7 +107,7 @@ function runSbom(flags) {
|
|
|
106
107
|
// 실제로 이랬다 — deel run --json "검사 돌려줘" 를 쳤더니 --json 이 뒤의 말을
|
|
107
108
|
// 통째로 삼켰다. 시킬 말이 사라졌으니 "무엇을 시킬지 적어 주세요" 가 떴는데,
|
|
108
109
|
// 화면만 보면 왜 그런지 알 길이 없다. 깃발을 앞에 두는 것은 아주 흔한 습관이다.
|
|
109
|
-
const BOOL = new Set(['help', 'version', 'offline', 'continue', 'json', 'quiet', 'yes', 'no-tui', 'tui']);
|
|
110
|
+
const BOOL = new Set(['help', 'version', 'offline', 'online', 'continue', 'json', 'quiet', 'yes', 'no-tui', 'tui']);
|
|
110
111
|
|
|
111
112
|
function parse(argv) {
|
|
112
113
|
const flags = {};
|
|
@@ -138,6 +139,7 @@ function help() {
|
|
|
138
139
|
say(` ${c.cyan('deel setup')} 연결 설정 (주소·키·모델)`);
|
|
139
140
|
say(` ${c.cyan('deel status')} 연결 상태 보기`);
|
|
140
141
|
say(` ${c.cyan('deel diagnose')} 저장된 연결로 진단 다시 돌리기`);
|
|
142
|
+
say(` ${c.cyan('deel reset')} 설정·기억·기록 지우기 ${c.gray('(그냥 치면 보여만 줍니다)')}`);
|
|
141
143
|
say(` ${c.cyan('deel completion <셸>')} 탭 완성 스크립트 ${c.gray('(bash · zsh · powershell)')}`);
|
|
142
144
|
say(` ${c.cyan('deel --version')} 판 번호 ${c.gray('(-v 도 됩니다)')}`);
|
|
143
145
|
say('');
|
|
@@ -155,6 +157,19 @@ function help() {
|
|
|
155
157
|
say(` ${c.gray('에디터 설정에 이 명령을 적어 두면 그 안에서 deel 이 돕니다.')}`);
|
|
156
158
|
say(` ${c.gray('승인 창·모드 고르개·고친 파일 링크가 에디터 것으로 그려집니다.')}`);
|
|
157
159
|
say('');
|
|
160
|
+
say(` ${c.bold('되돌아가기')} ${c.gray('— 지우려고 다시 깔지 않아도 됩니다')}`);
|
|
161
|
+
say('');
|
|
162
|
+
say(` ${c.cyan('deel reset')} 무엇이 얼마나 있는지 보여 주고 묻습니다 ${c.gray('(아무것도 안 지웁니다)')}`);
|
|
163
|
+
say(` ${c.gray('deel reset model')} 연결·프로필·잠긴 열쇠`);
|
|
164
|
+
say(` ${c.gray('deel reset memory')} 기억 (.deel/memory.md)`);
|
|
165
|
+
say(` ${c.gray('deel reset sessions')} 대화 기록`);
|
|
166
|
+
say(` ${c.gray('deel reset learned')} 배운 것 (이 PC + 이 폴더)`);
|
|
167
|
+
say(` ${c.gray('deel reset plugins')} 설치한 플러그인`);
|
|
168
|
+
say(` ${c.gray('deel reset all')} 위 전부 ${c.gray('— 플러그인·되돌리기·감사기록은 빼고')}`);
|
|
169
|
+
say(` ${c.gray('--hard')} ${c.yellow('되돌리기 스냅샷·감사기록까지')}. all 에서만 씁니다`);
|
|
170
|
+
say(` ${c.gray('--yes')} 안 묻고 지웁니다 (스크립트용)`);
|
|
171
|
+
say(` ${c.gray('.deel/mcp.json · .deelignore · DEEL.md 는 사람이 적은 것이라 어떤 길로도 안 건드립니다.')}`);
|
|
172
|
+
say('');
|
|
158
173
|
say(` ${c.bold('사내 반입')}`);
|
|
159
174
|
say('');
|
|
160
175
|
say(` ${c.cyan('deel audit')} 의존성·네트워크 호출 자리 심사서 ${c.gray('(사람이 읽는 글)')}`);
|
|
@@ -175,7 +190,11 @@ function help() {
|
|
|
175
190
|
say(` ${c.gray('--think <수준>')} off / low / medium(기본) / high / max`);
|
|
176
191
|
say(` ${c.gray('--effort <배분>')} even(균일) / save(절약, 기본) / deep(깊게)`);
|
|
177
192
|
say(` ${c.gray('--no-tui')} 입력 상자 없이 줄 화면으로 (파이프·기록·좁은 터미널)`);
|
|
178
|
-
|
|
193
|
+
// 실행 모드 셋. 기본이 잠겨 있다는 것을 여기서 분명히 말한다 —
|
|
194
|
+
// 「--online 이 있다」 보다 「기본은 안 나간다」 가 사람이 알아야 할 쪽이다.
|
|
195
|
+
say(` ${c.gray('(기본)')} ⌂ 이 안 — 바깥 주소면 한 번 물어보고 기억합니다`);
|
|
196
|
+
say(` ${c.gray('--online')} ↗ 바깥 — 묻지 않고 나갑니다 ${c.gray('(스크립트·CI 처럼 물어볼 사람이 없을 때)')}`);
|
|
197
|
+
say(` ${c.gray('--offline')} ⛊ 봉인 — 기억해 둔 허가까지 무시하고 막습니다 ${c.gray('(사내망은 그대로 갑니다)')}`);
|
|
179
198
|
say(` ${c.gray('--continue')} 이 폴더에서 가장 최근 대화 이어하기`);
|
|
180
199
|
say(` ${c.gray('--resume <id>')} 골라서 이어하기 (deel sessions 로 id 확인)`);
|
|
181
200
|
say('');
|
|
@@ -210,7 +229,18 @@ async function main() {
|
|
|
210
229
|
process.exit(1);
|
|
211
230
|
}
|
|
212
231
|
|
|
213
|
-
const { cmd
|
|
232
|
+
const { cmd: 친명령, args, flags } = parse(process.argv.slice(2));
|
|
233
|
+
|
|
234
|
+
/*
|
|
235
|
+
* `deel online` · `deel offline` 은 깃발의 별칭이다.
|
|
236
|
+
*
|
|
237
|
+
* 사람은 이것을 「모드로 켠다」 고 생각한다 — `deel --online` 보다
|
|
238
|
+
* `deel online` 이 먼저 손에서 나온다. 둘 다 받는다. 안 받으면 "모르는
|
|
239
|
+
* 명령입니다" 가 뜨는데, 그 화면에서는 무엇을 잘못 쳤는지 알 길이 없다.
|
|
240
|
+
*/
|
|
241
|
+
const cmd = (친명령 === 'online' || 친명령 === 'offline')
|
|
242
|
+
? (flags[친명령] = true, '')
|
|
243
|
+
: 친명령;
|
|
214
244
|
|
|
215
245
|
/*
|
|
216
246
|
* 판 번호.
|
|
@@ -241,6 +271,7 @@ async function main() {
|
|
|
241
271
|
think: flags.think ? String(flags.think) : undefined,
|
|
242
272
|
effort: flags.effort ? String(flags.effort) : undefined,
|
|
243
273
|
offline: flags.offline === true || flags.offline === 'true',
|
|
274
|
+
online: flags.online === true || flags.online === 'true',
|
|
244
275
|
yes: flags.yes === true || flags.yes === 'true',
|
|
245
276
|
json: flags.json === true || flags.json === 'true',
|
|
246
277
|
quiet: flags.quiet === true || flags.quiet === 'true',
|
|
@@ -261,6 +292,7 @@ async function main() {
|
|
|
261
292
|
// --tui 터미널이면 무조건 입력 상자를 켠다
|
|
262
293
|
tui: flags['no-tui'] === true ? false : (flags.tui === true ? true : null),
|
|
263
294
|
offline: flags.offline === true || flags.offline === 'true',
|
|
295
|
+
online: flags.online === true || flags.online === 'true',
|
|
264
296
|
continue: flags.continue === true || flags.c === true,
|
|
265
297
|
sessionId: typeof flags.resume === 'string' ? flags.resume : (flags.resume === true ? null : undefined),
|
|
266
298
|
});
|
|
@@ -281,6 +313,7 @@ async function main() {
|
|
|
281
313
|
think: flags.think ? String(flags.think) : undefined,
|
|
282
314
|
effort: flags.effort ? String(flags.effort) : undefined,
|
|
283
315
|
offline: flags.offline === true || flags.offline === 'true',
|
|
316
|
+
online: flags.online === true || flags.online === 'true',
|
|
284
317
|
});
|
|
285
318
|
case 'status':
|
|
286
319
|
return showStatus();
|
|
@@ -300,6 +333,14 @@ async function main() {
|
|
|
300
333
|
case 'sessions':
|
|
301
334
|
case 'ls':
|
|
302
335
|
return runSessions(flags);
|
|
336
|
+
/*
|
|
337
|
+
* 초기화.
|
|
338
|
+
*
|
|
339
|
+
* setup 과 달리 **설정을 안 읽는다.** 초기화를 찾는 까닭이 대개 설정이
|
|
340
|
+
* 깨져서인데, 읽고 시작하면 그 자리에서 못 넘어간다.
|
|
341
|
+
*/
|
|
342
|
+
case 'reset':
|
|
343
|
+
return runReset(args, flags);
|
|
303
344
|
/*
|
|
304
345
|
* 탭 완성 스크립트를 낸다 (src/completion.js).
|
|
305
346
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deel-local-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "로컬 모델·사내 게이트웨이 전용 코딩 에이전트 CLI — 외부 의존성 0개 / Zero-dependency coding agent CLI for local LLMs and private gateways",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"bin",
|
|
15
15
|
"src",
|
|
16
16
|
"README.md",
|
|
17
|
-
"README.
|
|
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/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/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/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/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",
|
|
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
|
@@ -42,6 +42,7 @@ import { 말 as 옮긴말 } from '../i18n/index.js';
|
|
|
42
42
|
import { 알림채움 } from '../backend/retry.js';
|
|
43
43
|
import { discover } from '../skills/discover.js';
|
|
44
44
|
import { allowEndpoint, setOffline } from '../safety/network.js';
|
|
45
|
+
import { 지금모드, 바깥인가, 나갈수있나 } from '../safety/runmode.js';
|
|
45
46
|
import { 주소가리기 } from '../safety/secrets.js';
|
|
46
47
|
import { probeCtx, 기본값 as CTX_DEFAULT } from '../backend/ctxsize.js';
|
|
47
48
|
import { 다붙이기 } from '../backend/mcp.js';
|
|
@@ -138,9 +139,28 @@ export async function acp(opts = {}) {
|
|
|
138
139
|
streaming: prof.streaming ?? false,
|
|
139
140
|
tools: prof.tools ?? false, json: prof.json ?? false, think: prof.think ?? false,
|
|
140
141
|
};
|
|
142
|
+
/*
|
|
143
|
+
* 바깥으로 나가는 연결은 허가가 있어야 연다 (safety/runmode.js).
|
|
144
|
+
*
|
|
145
|
+
* 에디터에는 승인 창이 있지만 그건 **도구 실행**을 묻는 창이고, 「이 대화가
|
|
146
|
+
* 통째로 바깥으로 나갑니다」 를 물을 자리는 규격에 없다. 그래서 여기서는
|
|
147
|
+
* 묻지 않고 또렷하게 거절한다 — 에디터 화면에 이 글이 그대로 뜬다.
|
|
148
|
+
*/
|
|
149
|
+
const 바깥연결 = 바깥인가(conn.base);
|
|
150
|
+
const 실행모드 = 지금모드({
|
|
151
|
+
online: opts.online === true,
|
|
152
|
+
// 관리 정책이 offline 을 못박아 뒀으면 옵션과 상관없이 켠다 (safety/policy.js).
|
|
153
|
+
offline: !!(opts.offline ?? prof.offline ?? cfg?.offline),
|
|
154
|
+
});
|
|
155
|
+
const 나감 = 나갈수있나(실행모드, { 바깥: 바깥연결, 허가: prof.online === true });
|
|
156
|
+
if (나감.물어볼까) {
|
|
157
|
+
const 어디 = (() => { try { return new URL(conn.base).host; } catch { return conn.base; } })();
|
|
158
|
+
throw 잘못된인자오류(
|
|
159
|
+
`이 연결은 이 컴퓨터 밖으로 나갑니다 (${주소가리기(어디)}).`
|
|
160
|
+
+ ' 터미널에서 deel 을 한 번 켜서 허락하거나, deel acp --online 으로 띄우세요.');
|
|
161
|
+
}
|
|
141
162
|
allowEndpoint(conn.base);
|
|
142
|
-
|
|
143
|
-
if (opts.offline ?? prof.offline ?? cfg?.offline) setOffline(true);
|
|
163
|
+
if (실행모드.허가무시) setOffline(true);
|
|
144
164
|
|
|
145
165
|
const session = new Session(conn, {
|
|
146
166
|
root,
|
|
@@ -151,6 +171,9 @@ export async function acp(opts = {}) {
|
|
|
151
171
|
think: opts.think ?? 'medium',
|
|
152
172
|
effort: opts.effort ?? 'save',
|
|
153
173
|
});
|
|
174
|
+
// 지금 어느 실행 모드인가. 화면이 첫 줄에 이걸 그린다(ui/status.js).
|
|
175
|
+
// session 에 실어 두는 까닭은, 대화 도중 /model 로 옮겨도 같은 자리를 보게 하려는 것이다.
|
|
176
|
+
session.실행모드 = 실행모드;
|
|
154
177
|
|
|
155
178
|
const found = discover(root);
|
|
156
179
|
session.skills = found.skills;
|
package/src/agent/loop.js
CHANGED
|
@@ -14,7 +14,8 @@ import { Session } from './session.js';
|
|
|
14
14
|
import { 최대깊이, 하위모드, 하위요약 } from '../tools/task.js';
|
|
15
15
|
import { 프로필찾기, 쓸수있나, 연결만들기, 알릴말, 목록보기 } from './models.js';
|
|
16
16
|
import { allowTemporarily, isOffline } from '../safety/network.js';
|
|
17
|
-
import { 가리기, 훑기, 가렸다는말, 봤다는말,
|
|
17
|
+
import { 가리기, 훑기, 가렸다는말, 봤다는말, 가릴까 } from '../safety/secrets.js';
|
|
18
|
+
import { 바깥인가 } from '../safety/runmode.js';
|
|
18
19
|
import { get as workMode } from './modes.js';
|
|
19
20
|
import { 지시말 } from '../i18n/index.js';
|
|
20
21
|
import { 빠진것, 빠졌다는말 } from './asks.js';
|
|
@@ -171,6 +172,23 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
171
172
|
|
|
172
173
|
const conn = session.conn;
|
|
173
174
|
|
|
175
|
+
/*
|
|
176
|
+
* ── 바깥 모델에게는 파일 속 비밀도 가린다 ───────────────────────────
|
|
177
|
+
*
|
|
178
|
+
* safety/secrets.js 는 「파일 내용은 안 가린다」 로 정해 두었다. 가리면
|
|
179
|
+
* 모델이 가려진 글을 보고 그대로 되돌려 써서 **사람의 열쇠가 지워지기**
|
|
180
|
+
* 때문이다. 로컬 모델만 쓰던 동안에는 그 손해가 이득보다 컸다 — 어차피
|
|
181
|
+
* 이 컴퓨터 밖으로 안 나가니까.
|
|
182
|
+
*
|
|
183
|
+
* 바깥으로 나가는 순간 저울이 뒤집힌다. Read 한 번이면 `.env` 가 통째로
|
|
184
|
+
* 남의 서버 로그에 남는다. 그건 되돌릴 수가 없다.
|
|
185
|
+
*
|
|
186
|
+
* 되돌려 쓰는 사고는 이제 다른 자리에서 막는다 — Write·Append·Edit 이
|
|
187
|
+
* 가린 표를 파일에 못 쓴다(tools/index.js 의 가린표되돌리나). 그 자물쇠가
|
|
188
|
+
* 생겼기 때문에 여기서 가릴 수 있게 된 것이다. 순서가 중요하다.
|
|
189
|
+
*/
|
|
190
|
+
const 바깥으로나감 = 바깥인가(conn.base);
|
|
191
|
+
|
|
174
192
|
/**
|
|
175
193
|
* 같은 실패가 되풀이되는지 센다.
|
|
176
194
|
*
|
|
@@ -197,7 +215,8 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
197
215
|
// 파일 하나가 아니라 **그 파일** 을 센다. 이름만 세면 서로 다른 파일 세 개를
|
|
198
216
|
// 고치다 실패한 것이 한 덩어리로 뭉쳐 턴이 죽는다. 다섯 군데 중 두 군데만
|
|
199
217
|
// 고쳐 놓고 '헛돌고 있어 멈췄습니다' 가 되는 것이 그 모습이다.
|
|
200
|
-
const 어디 = call.args?.file_path ?? call.args?.path ?? call.args?.pattern ?? call.args?.command
|
|
218
|
+
const 어디 = call.args?.file_path ?? call.args?.path ?? call.args?.pattern ?? call.args?.command
|
|
219
|
+
?? call.args?.purpose ?? call.args?.목적 ?? '';
|
|
201
220
|
const 서명 = `${call.name}|${이유}|${String(어디).slice(0, 200)}`;
|
|
202
221
|
const n = (막힘.get(서명) ?? 0) + 1;
|
|
203
222
|
막힘.set(서명, n);
|
|
@@ -513,6 +532,16 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
513
532
|
think: thinkFor(conn, think),
|
|
514
533
|
maxTokens,
|
|
515
534
|
signal,
|
|
535
|
+
/*
|
|
536
|
+
* 열쇠받기(safety/authcmd.js)가 걸린 연결에서 쓴다.
|
|
537
|
+
*
|
|
538
|
+
* 두 갈래를 위층으로 올린다 — 「부를까요」 를 사람에게 묻는 길과,
|
|
539
|
+
* 「지금 사내 로그인을 기다리는 중」 을 화면에 적는 길. 여기서 화면을
|
|
540
|
+
* 직접 만지지 않는 것은, 이 루프가 대화 화면 말고 oneshot·ACP 에서도
|
|
541
|
+
* 돌기 때문이다. 그쪽에는 물어볼 사람이 없다.
|
|
542
|
+
*/
|
|
543
|
+
열쇠물어보기: session.열쇠물어보기 ?? null,
|
|
544
|
+
onAuth: (것) => { session.onAuth?.(것); },
|
|
516
545
|
});
|
|
517
546
|
|
|
518
547
|
let msg;
|
|
@@ -927,8 +956,8 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
927
956
|
*/
|
|
928
957
|
if (실행할것.length === 1 && 실행할것[0].name === 'Task') {
|
|
929
958
|
const call = 실행할것[0];
|
|
930
|
-
const 목적 = String(call.args
|
|
931
|
-
const 할일 = String(call.args
|
|
959
|
+
const 목적 = String(call.args?.purpose ?? call.args?.목적 ?? '').trim() || '이름 없는 작업';
|
|
960
|
+
const 할일 = String(call.args?.task ?? call.args?.할일 ?? '').trim();
|
|
932
961
|
|
|
933
962
|
// 할 일이 비면 하위는 아무것도 모른 채로 시작한다. 하위는 이 대화를
|
|
934
963
|
// 못 보므로, 여기서 통과시키면 걸음만 태우고 빈손으로 돌아온다.
|
|
@@ -941,7 +970,7 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
941
970
|
continue;
|
|
942
971
|
}
|
|
943
972
|
|
|
944
|
-
const 자식모드 = 하위모드(call.args
|
|
973
|
+
const 자식모드 = 하위모드(call.args?.mode ?? call.args?.모드, 모드.id);
|
|
945
974
|
|
|
946
975
|
/*
|
|
947
976
|
* ── 다른 모델에게 떼어 주기 ─────────────────────────────────────
|
|
@@ -957,7 +986,7 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
957
986
|
let 자식conn = conn;
|
|
958
987
|
let 자리닫기 = null;
|
|
959
988
|
let 모델알림 = null;
|
|
960
|
-
const 부른모델 = String(call.args
|
|
989
|
+
const 부른모델 = String(call.args?.model ?? call.args?.모델 ?? '').trim();
|
|
961
990
|
if (부른모델) {
|
|
962
991
|
const 찾음 = 프로필찾기(부른모델);
|
|
963
992
|
if (!찾음.ok) {
|
|
@@ -1218,7 +1247,9 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
1218
1247
|
*/
|
|
1219
1248
|
const 아는열쇠들 = [conn.key, process.env.DEEL_API_KEY].filter(Boolean);
|
|
1220
1249
|
let 비밀 = [];
|
|
1221
|
-
|
|
1250
|
+
// 바깥으로 나가면 파일에서 읽어 온 글까지 가린다 (safety/secrets.js 의 가릴까).
|
|
1251
|
+
const 이번엔가릴까 = 가릴까(call.name, { 바깥: 바깥으로나감 });
|
|
1252
|
+
if (이번엔가릴까) {
|
|
1222
1253
|
const 가린 = 가리기(실을것, { 열쇠들: 아는열쇠들 });
|
|
1223
1254
|
if (가린.가린것.length) {
|
|
1224
1255
|
비밀 = 가린.가린것;
|
|
@@ -1231,7 +1262,8 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
1231
1262
|
if (비밀.length) {
|
|
1232
1263
|
ctx.audit?.write?.('secret', {
|
|
1233
1264
|
tool: call.name,
|
|
1234
|
-
가렸나:
|
|
1265
|
+
가렸나: 이번엔가릴까,
|
|
1266
|
+
바깥: 바깥으로나감,
|
|
1235
1267
|
무엇: 비밀.map((x) => `${x.종류}×${x.몇번}`).join(' '),
|
|
1236
1268
|
});
|
|
1237
1269
|
}
|
|
@@ -1249,7 +1281,7 @@ export async function* run(session, ctx, userText, { signal = null, 깊이 = 0,
|
|
|
1249
1281
|
result,
|
|
1250
1282
|
ms,
|
|
1251
1283
|
parallel: 함께,
|
|
1252
|
-
...(비밀.length ? { 비밀: { 가렸나:
|
|
1284
|
+
...(비밀.length ? { 비밀: { 가렸나: 이번엔가릴까, 말: 봤다는말(비밀) } } : {}),
|
|
1253
1285
|
};
|
|
1254
1286
|
}
|
|
1255
1287
|
}
|
package/src/agent/session.js
CHANGED
|
@@ -9,7 +9,7 @@ import { 매김, 급말, 값 as 급값, 지켜본것 } from './grade.js';
|
|
|
9
9
|
import { 지문 } from './project.js';
|
|
10
10
|
import { 프롬프트토막 as 기억토막 } from './memory.js';
|
|
11
11
|
import { 못박기 } from './pins.js';
|
|
12
|
-
import { 언어,
|
|
12
|
+
import { 언어, 지시말, 말 as 옮긴말 } from '../i18n/index.js';
|
|
13
13
|
import { 셸안내 } from '../tools/shell.js';
|
|
14
14
|
|
|
15
15
|
// 토큰 추정 — 정확한 토크나이저 없이 대략만 센다.
|
|
@@ -630,15 +630,21 @@ export class Session {
|
|
|
630
630
|
const 기억 = this.memory ? estimateTokens(this.memory) : 0;
|
|
631
631
|
const 기억줄 = this.memory ? this.memory.split('\n').filter((l) => l.startsWith('- ')).length : 0;
|
|
632
632
|
|
|
633
|
+
/*
|
|
634
|
+
* 이름은 화면에 그대로 나간다(`/context`). 그래서 여기서 말 표를 거친다.
|
|
635
|
+
* 여기만 한국어로 두면 영어로 켠 사람의 컨텍스트 표가 통째로 한국어가
|
|
636
|
+
* 되는데, `/lang` 은 그 사이에도 100% 라고 답한다 — 표에 없는 글은
|
|
637
|
+
* 세지지 못하기 때문이다. test/langleak.test.js 가 이 자리를 지킨다.
|
|
638
|
+
*/
|
|
633
639
|
const rows = [
|
|
634
|
-
{ label: '
|
|
635
|
-
{ label: this.rules ?
|
|
636
|
-
{ label:
|
|
637
|
-
{ label: '
|
|
638
|
-
{ label:
|
|
639
|
-
{ label: '
|
|
640
|
-
{ label: '
|
|
641
|
-
{ label:
|
|
640
|
+
{ label: 옮긴말('ctx.system'), n: sys },
|
|
641
|
+
{ label: this.rules ? 옮긴말('ctx.rules', { 이름: this.rules.name }) : 옮긴말('ctx.rulesNone'), n: rules },
|
|
642
|
+
{ label: 옮긴말('ctx.memory', { n: 기억줄 }), n: 기억 },
|
|
643
|
+
{ label: 옮긴말('ctx.learned'), n: this.배움요약 ? estimateTokens(this.배움요약) : 0 },
|
|
644
|
+
{ label: 옮긴말('ctx.skills', { 실림: listed.length, 전체: this.skills.length }), n: skills },
|
|
645
|
+
{ label: 옮긴말('ctx.tools'), n: 도구 },
|
|
646
|
+
{ label: 옮긴말('ctx.history'), n: history },
|
|
647
|
+
{ label: 옮긴말('ctx.toolResults', { n: this.filesRead.size }), n: files },
|
|
642
648
|
];
|
|
643
649
|
const used = rows.reduce((a, r) => a + r.n, 0);
|
|
644
650
|
const total = this.conn.ctx ?? 32768;
|