deel-local-cli 1.5.0 → 1.5.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/package.json CHANGED
@@ -1,60 +1,60 @@
1
- {
2
- "name": "deel-local-cli",
3
- "version": "1.5.0",
4
- "description": "로컬 모델·사내 게이트웨이 전용 코딩 에이전트 CLI — 외부 의존성 0개 / Zero-dependency coding agent CLI for local LLMs and private gateways",
5
- "type": "module",
6
- "license": "MIT",
7
- "bin": {
8
- "deel": "bin/deel.js"
9
- },
10
- "engines": {
11
- "node": ">=20"
12
- },
13
- "files": [
14
- "bin",
15
- "src",
16
- "README.md",
17
- "README.en.md",
18
- "LICENSE"
19
- ],
20
- "keywords": [
21
- "cli",
22
- "coding-agent",
23
- "local-llm",
24
- "ollama",
25
- "lm-studio",
26
- "openai-compatible",
27
- "offline",
28
- "air-gapped",
29
- "zero-dependency",
30
- "agent",
31
- "acp",
32
- "agent-client-protocol",
33
- "zed",
34
- "korean"
35
- ],
36
- "repository": {
37
- "type": "git",
38
- "url": "git+https://github.com/jysvai/deel-local-cli.git"
39
- },
40
- "bugs": {
41
- "url": "https://github.com/jysvai/deel-local-cli/issues"
42
- },
43
- "homepage": "https://github.com/jysvai/deel-local-cli#readme",
44
- "scripts": {
45
- "start": "node bin/deel.js",
46
- "setup": "node bin/deel.js setup",
47
- "diagnose": "node bin/deel.js diagnose",
48
- "chat": "node bin/deel.js",
49
- "test": "node test/run.mjs",
50
- "docs": "node tools/check-docs.mjs",
51
- "verify": "node test/no-bundle.test.js && node test/network.test.js && node test/web.test.js",
52
- "bench": "node test/edit-bench.js",
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/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/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/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/edit-match.js && node --check src/tools/webfetch.js && node --check src/tools/todo.js && node --check src/tools/jobs.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/network.js && node --check src/setup.js && node --check src/report.js && node --check src/config.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/preview/serve.js && node --check src/ui/working.js && node --check src/ui/inputbox.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/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",
55
- "coverage": "node test/coverage.mjs",
56
- "prepublishOnly": "npm run check && npm test"
57
- },
58
- "dependencies": {},
59
- "devDependencies": {}
60
- }
1
+ {
2
+ "name": "deel-local-cli",
3
+ "version": "1.5.2",
4
+ "description": "로컬 모델·사내 게이트웨이 전용 코딩 에이전트 CLI — 외부 의존성 0개 / Zero-dependency coding agent CLI for local LLMs and private gateways",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "deel": "bin/deel.js"
9
+ },
10
+ "engines": {
11
+ "node": ">=20"
12
+ },
13
+ "files": [
14
+ "bin",
15
+ "src",
16
+ "README.md",
17
+ "README.en.md",
18
+ "LICENSE"
19
+ ],
20
+ "keywords": [
21
+ "cli",
22
+ "coding-agent",
23
+ "local-llm",
24
+ "ollama",
25
+ "lm-studio",
26
+ "openai-compatible",
27
+ "offline",
28
+ "air-gapped",
29
+ "zero-dependency",
30
+ "agent",
31
+ "acp",
32
+ "agent-client-protocol",
33
+ "zed",
34
+ "korean"
35
+ ],
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/jysvai/deel-local-cli.git"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/jysvai/deel-local-cli/issues"
42
+ },
43
+ "homepage": "https://github.com/jysvai/deel-local-cli#readme",
44
+ "scripts": {
45
+ "start": "node bin/deel.js",
46
+ "setup": "node bin/deel.js setup",
47
+ "diagnose": "node bin/deel.js diagnose",
48
+ "chat": "node bin/deel.js",
49
+ "test": "node test/run.mjs",
50
+ "docs": "node tools/check-docs.mjs",
51
+ "verify": "node test/no-bundle.test.js && node test/network.test.js && node test/web.test.js",
52
+ "bench": "node test/edit-bench.js",
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/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/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/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/edit-match.js && node --check src/tools/webfetch.js && node --check src/tools/todo.js && node --check src/tools/jobs.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/network.js && node --check src/setup.js && node --check src/report.js && node --check src/config.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/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/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/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",
55
+ "coverage": "node test/coverage.mjs",
56
+ "prepublishOnly": "npm run check && npm test"
57
+ },
58
+ "dependencies": {},
59
+ "devDependencies": {}
60
+ }
package/src/i18n/en.js CHANGED
@@ -129,7 +129,7 @@ export const en = {
129
129
  'head.shiftTab': 'Shift+Tab',
130
130
  'head.shiftTabHint': ' changes it · ',
131
131
  'head.tabHint': 'Tab completes the / command you are typing',
132
- 'head.newlineHint': 'New line: Alt+Enter (if your terminal sends it), or end a line with ` then Enter',
132
+ 'head.newlineHint': 'New line: Alt+Enter (if your terminal sends it), or end a line with space + ` then Enter',
133
133
  'head.thisPC': 'found',
134
134
  'head.skills': 'skills {n}',
135
135
  'head.commands': 'commands {n}',
package/src/i18n/ko.js CHANGED
@@ -116,7 +116,7 @@ export const ko = {
116
116
  'head.shiftTab': 'Shift+Tab',
117
117
  'head.shiftTabHint': '으로 바꿉니다 · ',
118
118
  'head.tabHint': 'Tab 은 치던 / 명령을 채웁니다',
119
- 'head.newlineHint': '줄바꿈: Alt+Enter(터미널이 지원하면) 또는 줄 끝에 ` 를 붙이고 Enter',
119
+ 'head.newlineHint': '줄바꿈: Alt+Enter(터미널이 지원하면) 또는 줄 끝에 빈칸+` 를 붙이고 Enter',
120
120
  'head.thisPC': '이 PC',
121
121
  'head.skills': '스킬 {n}',
122
122
  'head.commands': '명령 {n}',
package/src/repl.js CHANGED
@@ -121,6 +121,23 @@ const DIFF_LINES = { 쉬움: 14, 개발자: 40 };
121
121
  // 모델의 말 앞에 세우는 세로줄. 도구 줄과 눈으로 갈리게 하는 유일한 표시다.
122
122
  const 답표시 = c.hcyan('▌');
123
123
 
124
+ /**
125
+ * 줄 끝 백틱이 "이어쓰기" 표시인가.
126
+ *
127
+ * 예전에는 백틱 하나로 끝나기만 하면 표시로 봤다. 그런데 코딩 도구에서
128
+ * "read `config.json`" · "echo `date`" 처럼 **인라인 코드로 끝나는 줄**은
129
+ * 아주 흔하다. 그 줄들이 전부 안 보내지고, 닫는 백틱까지 뜯긴 채 이어쓰기
130
+ * 모드에 갇혔다 — 사람 눈에는 Enter 가 그냥 안 먹는 것으로 보인다.
131
+ *
132
+ * 그래서 조건을 둘로 좁혔다. 백틱 앞이 **빈칸**이고(또는 백틱만 있는 줄이고),
133
+ * 그 줄에 백틱이 **그것 하나뿐**일 때만 표시로 본다. 인라인 코드는 백틱이
134
+ * 둘이라 안 걸리고, ``` 울타리는 앞이 백틱이라 안 걸린다.
135
+ *
136
+ * 검사에서 표를 만들어 재려고 밖으로 뺐다.
137
+ */
138
+ export const 이어쓰기표시 = (l) =>
139
+ /(^|\s)`$/.test(l) && (String(l).match(/`/g) ?? []).length === 1;
140
+
124
141
  export async function chatLoop(opts = {}) {
125
142
  const cfg = load();
126
143
  const prof = activeProfile(cfg);
@@ -327,9 +344,12 @@ export async function chatLoop(opts = {}) {
327
344
  * 메시지로 묶어 보낼 때 쓴다. 확정된 줄은 여기 쌓아 두다가, ` 없이 끝나는
328
345
  * 줄이 오면 그때 \n 으로 이어붙여 한 메시지로 내보낸다.
329
346
  *
330
- * 실제 개행을 상자(rl.line) 안에 그대로 넣지는 않는다 접어쓰기() 가 \n 을
331
- * 다뤄서(글자 하나로 세고 폭만 잰다) 그리면 커서 자리와 테두리 수가
332
- * 어긋난다. 그래서 물리적으로는 줄씩만 치고, 이어붙이기는 밖에서 한다.
347
+ * 실제 개행을 상자(rl.line) 안에 넣어서는 **안 된다**. 화면은 멀쩡히
348
+ * 그려지지만, Enter 보낼 readline history 줄을 \n 에서
349
+ * 쪼개 거꾸로 쌓고 \r 다시 붙여 돌려준다. "안녕\n반가워" 를 보내면
350
+ * 'line' 이벤트에 오는 값은 "반가워\r안녕" 이다 — 사람이 쓴 순서가
351
+ * 뒤집혀서 모델에게 간다. historySize 를 0 으로 두면 안 그러니 history 가
352
+ * 하는 짓이 맞다. 그래서 개행은 rl.line 밖, 여기서만 다룬다.
333
353
  *
334
354
  * 백슬래시(\) 가 아니라 백틱을 고른 것은 일부러다 — 이 프로그램은 윈도우
335
355
  * 경로(`C:\Users\...`)를 늘 다루는데, 그 끝은 흔히 백슬래시로 끝난다.
@@ -338,6 +358,15 @@ export async function chatLoop(opts = {}) {
338
358
  */
339
359
  let 이어쓰기줄들 = null;
340
360
 
361
+ /** 줄을 쌓아 두고 "다음 줄" 이라고 알린다. 백틱 표시와 Alt+Enter 가 같이 쓴다. */
362
+ const 줄쌓기 = (줄) => {
363
+ const 첫줄 = 이어쓰기줄들 === null;
364
+ (이어쓰기줄들 ??= []).push(줄);
365
+ 화면.입력지움();
366
+ say(`${첫줄 ? ` ${c.hcyan('❯')} ` : ' '}${c.white(줄)}`);
367
+ say(` ${c.gray('… 다음 줄. 그냥 Enter 로 보냅니다 · Ctrl+C 로 취소')}`);
368
+ };
369
+
341
370
  rl.on('line', (l) => {
342
371
  if (echo) say(c.gray(l));
343
372
  let 보낼것 = l;
@@ -346,16 +375,9 @@ export async function chatLoop(opts = {}) {
346
375
  // 되묻는 자리: 답을 그 줄에 남긴 채 줄만 넘긴다.
347
376
  process.stdout.write(`\r\x1b[2K${묻는중}${c.white(l)}\n`);
348
377
  } else if (입력기다림) {
349
- // 백틱 **하나**로 끝날 때만 이어쓰기다. ``` 끝나는 줄은 마크다운
350
- // 코드 울타리라 그대로 둬야 한다 — 코딩 도구에 코드를 붙여넣는 것은
351
- // 드문 일이 아니고, 거기서 백틱 하나를 떼어먹으면 붙인 코드가 망가진다.
352
- if (/(^|[^`])`$/.test(l)) {
353
- const 줄 = l.slice(0, -1);
354
- const 첫줄 = 이어쓰기줄들 === null;
355
- (이어쓰기줄들 ??= []).push(줄);
356
- 화면.입력지움();
357
- say(`${첫줄 ? ` ${c.hcyan('❯')} ` : ' '}${c.white(줄)}`);
358
- say(` ${c.gray('… 다음 줄. 그냥 Enter 로 보냅니다')}`);
378
+ // 표시 자체와 빈칸은 사람이 글이 아니라 문법이다. 같이 뗀다.
379
+ if (이어쓰기표시(l)) {
380
+ 줄쌓기(l.slice(0, -1).replace(/\s+$/, ''));
359
381
  return;
360
382
  }
361
383
  // 상자를 걷어내고, 사람이 보낸 글을 대화에 남긴다. 안 남기면 스크롤을
@@ -480,13 +502,16 @@ export async function chatLoop(opts = {}) {
480
502
  * 뒤에 더 올 것을 기다리는 동안 우리 keypress 가 먼저 온다. 그래서
481
503
  * key.meta 로 여기서 골라낼 수 있다. rl.write('\n') 은 못 쓴다 —
482
504
  * 그것도 내부적으로 줄을 끝내는 처리를 그대로 타 버린다(직접 확인).
483
- * 그래서 rl.line·rl.cursor 를 손으로 이어붙인다.
505
+ *
506
+ * 커서 앞은 확정해서 쌓고, 뒤는 상자에 남긴다. rl.line 에 \n 을
507
+ * 넣어 이어붙이지 **않는다** — 그러면 화면은 맞는데 보낼 때
508
+ * history 가 줄 순서를 뒤집는다(이어쓰기줄들 선언부 참고).
484
509
  */
485
510
  if (key.meta && 입력기다림 && 묻는중 === null) {
486
- const 앞 = (rl.line ?? '').slice(0, rl.cursor ?? 0);
487
511
  const 뒤 = (rl.line ?? '').slice(rl.cursor ?? 0);
488
- rl.line = `${앞}\n${뒤}`;
489
- rl.cursor = 앞.length + 1;
512
+ 줄쌓기((rl.line ?? '').slice(0, rl.cursor ?? 0));
513
+ rl.line = 뒤;
514
+ rl.cursor = 0;
490
515
  } else {
491
516
  return; // 줄이 끝나는 것은 'line' 이 맡는다
492
517
  }
@@ -738,7 +763,7 @@ export async function chatLoop(opts = {}) {
738
763
  }
739
764
 
740
765
  // ── 머리말 ────────────────────────────────────────────────────────────
741
- 화면.머리말(headerLines(session, found));
766
+ 화면.머리말(headerLines(session, found, 상자쓰나));
742
767
  const warn = [];
743
768
  // 홈 폴더에서 켠 경우. 작업 범위가 집 전체가 된다.
744
769
  //
@@ -798,6 +823,17 @@ export async function chatLoop(opts = {}) {
798
823
  let interrupted = false;
799
824
  let turn = null; // 지금 도는 턴의 AbortController
800
825
  rl.on('SIGINT', () => {
826
+ /*
827
+ * 쌓아 둔 줄이 있으면 먼저 버린다. 이게 없으면 이어쓰기를 **취소할 길이
828
+ * 없다** — 표를 하나 붙여 놓고 마음이 바뀌어도, 다음에 치는 것이 무엇이든
829
+ * 앞줄에 붙어서 나간다. `/help` 같은 슬래시 명령까지 앞줄에 붙는 순간
830
+ * 더는 '/' 로 시작하지 않아 명령으로 안 읽히고 모델에게 넘어간다.
831
+ */
832
+ if (이어쓰기줄들 !== null) {
833
+ 이어쓰기줄들 = null;
834
+ say('');
835
+ say(` ${c.gray('이어쓰던 것을 버렸습니다.')}`);
836
+ }
801
837
  if (turn && !turn.signal.aborted) {
802
838
  turn.abort();
803
839
  return; // 화면 정리는 루프 쪽 'aborted' 이벤트가 한다