deel-local-cli 1.0.0 → 1.0.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.en.md CHANGED
@@ -20,10 +20,12 @@ Zero dependencies · Node 20+ · Exactly one place your source can go
20
20
  │ Sends to this machine 127.0.0.1:11434 ← nowhere else │
21
21
  │ Link streaming · tools · reasoning control │
22
22
  │ Folder C:\work\myproject │
23
+ │ Approval ⏵⏵ 자동 승인 — nothing is asked; /undo is the net │
24
+ │ Shift+Tab to change · Tab completes a / command │
23
25
  │ This PC 337 skills · 127 commands · 42 plugins │
24
26
  ╰──────────────────────────────────────────────────────────────╯
25
27
 
26
- ▏myproject · qwen2.5-coder:7b ▏ ▰▰▱▱▱▱▱▱▱▱ 22% 28k/128k ▏ ◎ 종합 · ◇ medium·절약 · auto
28
+ ▏myproject · qwen2.5-coder:7b ▏ ▰▰▱▱▱▱▱▱▱▱ 22% 28k/128k ▏ ◎ 종합 · ◇ medium·절약 · ⏵⏵ 자동
27
29
  ❯ unify the logging style
28
30
 
29
31
  ❊ Grep(console.log)
@@ -245,6 +247,18 @@ Discovered plugin commands are invoked as `/<plugin>:<name>`, with `$ARGUMENTS`
245
247
  server or loaded a different model, `/scan save` then `/model` switches over without losing
246
248
  the conversation.
247
249
 
250
+ **Without typing**
251
+
252
+ | Key | What it does |
253
+ |---|---|
254
+ | `Tab` | Completes the `/` command you are typing. Candidates appear under the box as you type |
255
+ | `Shift+Tab` | Approval policy (`⏵⏵ auto` → `⏵ risky only` → `⏸ everything`) |
256
+ | `Ctrl+O` | Work mode (`종합` → `코드` → `계획` → …) |
257
+ | `↑` `↓` | Input history |
258
+ | `Ctrl+C` | Stops the answer in progress; twice on an empty line quits |
259
+
260
+ Korean IME composition, paste, `Ctrl+A/E` and backspace all keep working.
261
+
248
262
  ### Attaching a file with `@`
249
263
 
250
264
  Write `@` followed by a path and that file is sent along with your message.
@@ -394,51 +408,172 @@ Two things matter here:
394
408
  - **Beginners do not get fewer safeguards.** Undo, workspace scope and dangerous-command
395
409
  blocking are identical. A beginner needs the undo more, not less.
396
410
 
397
- ### Two screens
398
-
399
- Launched in a terminal, deel runs **full-screen**: conversation on the left, files changed
400
- this session at the top right, todos below them, with a status line and an input box pinned
401
- at the bottom.
402
-
403
- ```
404
- 대화 ─────────────────────────────────────────────┬ 바뀐 파일 ───────────────┐
405
- │ ❊ Grep(console.log) │ src/runner.js +3-1 │
406
- 3 files · 11 hits │ src/index.js +1-1
407
- │ │ src/ui/log.js +12-0 │
408
- │ ◈ Edit(src/runner.js) ├ ───────────────────│
409
- │ └ 1 spot +3-1 │ ☑ find log calls │
410
- │ - 12 console.log('시작', 이름) │ unify runner.js
411
- │ + 12 logger.info({ 단계: '시작', 이름 }) │ ▶ unify index.js │
412
- │ │ update docs │
413
- │ ▌ Unified log calls to the logger format. │ │
414
- │ │ │
415
- │ ── 4.2s · 3 tools · ↑3,900 ↓180 │ │
416
- └───────────────────────────────────────────────────┴──────────────────────────┘
417
- ▏myproject · qwen2.5-coder:7b ▏ ▰▰▱▱▱▱▱▱ 22% ▏ ◎ 종합 · ◇ medium · auto ▏ ↑3.8k ↓180
411
+ ### The input box
412
+
413
+ Launched in a terminal, **the conversation scrolls normally and an input box is pinned at
414
+ the bottom.** Only the box is erased and redrawn nothing above it is touched.
415
+
416
+ ```
417
+ ❊ Grep(console.log)
418
+ 3 files · 11 hits
419
+ Edit(src/runner.js)
420
+ 1 spot +3-1
421
+ - 12 console.log('시작', 이름)
422
+ + 12 logger.info({ 단계: '시작', 이름 })
423
+
424
+ Unified log calls to the logger format. One change in runner.js.
425
+
426
+ ── 4.2s · 3 tools · ↑3,900 ↓180
427
+
428
+ ▏myproject · qwen2.5-coder:7b ▏ ▰▰▱▱▱▱▱▱ 22% ▏ ◎ 종합 · ◇ medium · ⏵⏵ 자동
418
429
  ╭─────────────────────────────────────────────────────────────────────────────╮
419
- │ ❯
430
+ │ ❯ also shrink the aggregate helpers
420
431
  ╰─────────────────────────────────────────────────────────────────────────────╯
421
432
  ```
422
433
 
434
+ Terminal scrollback, selection and `Ctrl+F` all keep working, because the conversation is
435
+ never trapped inside a pane of ours. Long input grows the box to as many lines as it needs.
436
+
423
437
  **It switches itself off where it would do harm.** Piped or redirected output, `CI` set,
424
- `TERM=dumb`, or a window under 60×16 all fall back to the **scrolling view** without asking
425
- `deel … | tee log.txt` must not become a pile of escape codes. Passing `--tui` does not
426
- override a pipe.
438
+ `TERM=dumb`, or a window under 40 columns: no box, no asking. `deel | tee log.txt` must
439
+ not become a pile of escape codes. Passing `--tui` does not override a pipe, and `--no-tui`
440
+ turns it off at any time.
441
+
442
+ Line editing stays entirely with Node's readline — Korean IME composition, paste, history,
443
+ Ctrl+A/E, backspace. We only *draw* the string readline is holding. Hand-rolling a line
444
+ editor is how you break IME input first.
445
+
446
+ > **A path taken and abandoned** — the first version borrowed the whole terminal (an
447
+ > alternate screen, like vim) and split it into conversation, changed-files and todo panes.
448
+ > It looked the part, and **every slash command went dead.** Six modules including
449
+ > `commands.js` write straight to the terminal rather than through the screen object, and a
450
+ > full repaint erased their output the instant it appeared. Not "the command didn't run" —
451
+ > "you can't see that it ran", which is worse. Fixing it would mean threading every one of
452
+ > those six through the screen object, plus every one added later, with a silent return of
453
+ > the same symptom if one is missed. So the design went the other way: let the conversation
454
+ > flow, manage only the box. ([`test/box.test.js`](test/box.test.js) spawns a child that
455
+ > pretends to be a terminal, so this one cannot ship again.)
456
+
457
+ ---
458
+
459
+ ### You don't have to type the whole command
460
+
461
+ There are over thirty commands. The only person who has them memorised is the one who
462
+ wrote them, and even he gets as far as `/mem…` and stops to wonder whether it was `memory`
463
+ or `memo`. If the only recourse at that point is typing `/help` and scanning thirty lines,
464
+ that isn't a command, it's a quiz.
465
+
466
+ So they show up **while you type.**
467
+
468
+ ```
469
+ ╭─────────────────────────────────────────────────────────────────────────────╮
470
+ │ ❯ /mo │
471
+ ╰─────────────────────────────────────────────────────────────────────────────╯
472
+ › /model [이름|list|models] 연결·모델 바꾸기 (이름 일부 · list · models)
473
+ /mode <모드> 승인 정책 — 얼마나 물어보나
474
+ /memory [지우기 <번호>|…] 대화가 끝나도 남는 기억 — 보기·지우기
475
+ ```
476
+
477
+ `Tab` fills it in: all the way if only one matches, otherwise **only as far as they all
478
+ agree** (`/mo` + Tab → `/mode`). It doesn't pick one for you, because deleting the wrong
479
+ guess costs more than typing the rest. Commands that take an argument get a trailing space
480
+ so you can keep going.
481
+
482
+ Prefix matches come first and **substring matches follow** — typos cluster in the first
483
+ character, so `/emo` still surfaces `/memory`. The moment you type a space (`/mode auto`)
484
+ the list folds away: the command is already decided.
427
485
 
428
- | | Full-screen | Scrolling (`--no-tui`) |
486
+ The list sits **below** the box. Putting it inside would push what you are typing upward,
487
+ so you could no longer see it.
488
+
489
+ > No up/down selection. That would have to take over **input history** (up arrow), which
490
+ > is used far more often. What is needed here isn't picking, it's recognising — and once
491
+ > you recognise it, one `Tab` is enough.
492
+ >
493
+ > Commands hidden at the `쉬움` level still surface when you type their prefix. Hidden is
494
+ > not the same as unavailable — someone who knows `/recall` should not be told it doesn't
495
+ > exist because of a display setting.
496
+
497
+ ---
498
+
499
+ ### The box stays while it works
500
+
501
+ Local models are slow. A single step can take tens of seconds, and if the bottom of the
502
+ screen goes blank for that long, **people assume it hung and hit Ctrl+C** — losing work that
503
+ was nearly done. So the border stays and only the contents change.
504
+
505
+ ```
506
+ ◧ Read(집계.py)
507
+ └ 6 lines
508
+
509
+ ▏myproject · qwen2.5-coder:7b ▏ ▰▱▱▱▱▱▱▱▱▱ 2% ▏ ◎ 종합 · ◇ medium · ⏵⏵ 자동 ▏ ↑3.8k ↓180
510
+ ╭─────────────────────────────────────────────────────────────────────────────╮
511
+ │ ⠹ 파일 들여다보는 중… 12초 · 생각 1,240자 · Ctrl+C 중단 │
512
+ ╰─────────────────────────────────────────────────────────────────────────────╯
513
+ ```
514
+
515
+ The phrase tracks **what is actually happening**. This is not decoration: a message that
516
+ cycles at random stops being read after the second time, and from then on it is worth no
517
+ more than a blank screen. One turn reads like this:
518
+
519
+ ```
520
+ 머리 굴리는 중 → 파일 들여다보는 중 → 코드 짜는 중 → 답 쓰는 중
521
+ (turning it over) (looking at files) (writing code) (writing the answer)
522
+ ```
523
+
524
+ | Activity | Phrases |
525
+ |---|---|
526
+ | Thinking | 머리 굴리는 중 · 어떻게 할지 궁리하는 중 · 수 읽는 중 · 따져 보는 중 |
527
+ | `Read` `Grep` `Glob` | 파일 들여다보는 중 · 코드 훑는 중 · 어디 있나 뒤지는 중 · 단서 찾는 중 |
528
+ | `Write` `Edit` `Append` | 코드 짜는 중 · 고쳐 넣는 중 · 손보는 중 · 한 줄씩 옮기는 중 |
529
+ | `Bash` | 명령 돌리는 중 · 터미널 두드리는 중 · 결과 기다리는 중 |
530
+ | `WebFetch` | 문서 찾아보는 중 · 읽어 오는 중 |
531
+ | Answering | 답 쓰는 중 · 정리해서 말하는 중 |
532
+ | **Past 45 seconds** | 아직 하는 중 · 조금만 더 · 생각보다 오래 걸리는 중 |
533
+
534
+ Within a category the phrase advances every 4 seconds — text frozen for 30 seconds reads as
535
+ hung too. On the right: **elapsed time**, and while the model is reasoning, **how many
536
+ characters of thinking have arrived**. One number that genuinely increases is what turns
537
+ "still alive" from a claim into a fact.
538
+
539
+ ### What gets asked, and what just happens
540
+
541
+ Whether your files change **with or without being asked** is the one thing that has to be
542
+ readable at a glance. It sits on the right of the status line at all times.
543
+
544
+ | Indicator | Command | What it asks about |
429
545
  |---|---|---|
430
- | When | Launched in a terminal | Pipes, CI, small windows, `--no-tui` |
431
- | Files changed / todos | Always visible on the right (≥96 cols) | Printed inline as they happen |
432
- | Earlier output | Wrapped and paged inside the frame | Your terminal's own scrollback |
433
- | On exit | **Replays the conversation into scrollback** | Already there |
434
- | For keeping a log | Not this one | This one |
546
+ | `⏵⏵ 자동 승인` (auto) | `/mode auto` | Nothing is asked. `/undo` is the safety net |
547
+ | `⏵ 위험만 확인` (risky only) | `/mode confirm` | Only irreversible commands. Files change unasked |
548
+ | `⏸ 모두 확인` (everything) | `/mode strict` | Every file change and every command is confirmed first |
549
+
550
+ `/mode` on its own lists all three and marks the current one with ●. The startup header
551
+ spells it out in a sentence, so the glyph is enough from then on.
552
+
553
+ **`Shift+Tab` cycles it without typing.** Each press moves one step and leaves a line
554
+ saying where it went. Whatever you were typing stays put.
555
+
556
+ ```
557
+ ⏵ 위험만 확인 되돌릴 수 없는 명령만 물어봅니다. 파일은 안 묻고 고칩니다
558
+ 자동 승인 → 위험만 확인 · Shift+Tab 으로 계속 바꿉니다
559
+ ```
560
+
561
+ The cycle runs **loose → strict** (auto → risky only → everything → auto). A mistaken
562
+ press only makes it ask more; it never drops you into "changes files unasked" in one hit.
435
563
 
436
- Full-screen uses the alternate screen buffer, like vim. Exiting would otherwise erase the whole
437
- conversation, so the recent lines are reprinted into the real screen on the way out. Whether it
438
- exits on Ctrl+C or dies on an uncaught error, **the terminal is always restored.**
564
+ > That key used to cycle the work mode (`종합`, `코드`, …). The swap is about **who
565
+ > reaches for it more often.** Work mode follows your request on its own, while approval
566
+ > policy is what you want to change mid-task when a particular job deserves a look.
567
+ > Work mode moved to `Ctrl+O`; `/work` still does the same thing.
439
568
 
440
- If the full-screen view cannot be set up an unusual terminal, anything at all it falls back
441
- to the scrolling view and says why in one line. **No program should fail to start over a screen.**
569
+ > It used to be the bare word `auto`. Next to `종합` and `medium·절약` it looked like just
570
+ > another mode, and nothing on screen said that one of them meant **files change without
571
+ > asking.**
572
+ >
573
+ > That also changed what gets truncated when space runs out. A corporate gateway model name
574
+ > like `databricks-gpt-5-6-luna` eats twenty-three columns, and that alone was pushing the
575
+ > approval indicator off the line entirely. Now **the model name shortens first** — you
576
+ > already know what you are running; whether your files change unasked is what you need now.
442
577
 
443
578
  ---
444
579
 
@@ -1195,7 +1330,7 @@ deel --effort <profile> even / save (default) / deep
1195
1330
  deel --offline Nothing leaves this machine
1196
1331
  deel --continue Resume the most recent conversation
1197
1332
  deel --resume <id> Resume a specific one
1198
- deel --no-tui Turn the full-screen view off; use the scrolling view (see below)
1333
+ deel --no-tui Turn the input box off; plain scrolling view (see below)
1199
1334
  ```
1200
1335
 
1201
1336
  ### Project rules
@@ -1226,7 +1361,7 @@ If the working folder has `DEEL.md`, `CLAUDE.md` or `AGENTS.md`, it is loaded as
1226
1361
  ## Development
1227
1362
 
1228
1363
  ```bash
1229
- npm test Full suite (1,745 checks)
1364
+ npm test Full suite (1,832 checks)
1230
1365
  npm run coverage Which lines the tests actually execute
1231
1366
  npm run verify Import + network checks only
1232
1367
  npm run bench Edit success rate
@@ -1280,7 +1415,7 @@ Zero dependencies rules out c8 and nyc, so this reads Node's own
1280
1415
  `NODE_V8_COVERAGE` instead — nothing new to get through an import review. It picks up
1281
1416
  child processes too, so the `cli` suite that spawns `deel` counts like everything else.
1282
1417
 
1283
- Currently **92% overall** (6,960 of 7,570 lines). Three files are deliberately left short.
1418
+ Currently **92% overall** (7,056 of 7,646 lines). Three files are deliberately left short.
1284
1419
 
1285
1420
  | File | Now | Why it stops there |
1286
1421
  |---|---|---|
package/README.md CHANGED
@@ -20,11 +20,13 @@
20
20
  │ 보냄 이 컴퓨터 안 127.0.0.1:11434 ← 여기 말고는 어디로도 안 갑니다 │
21
21
  │ 연결 스트리밍 · 도구 · 추론 조절 │
22
22
  │ 폴더 C:\work\myproject │
23
+ │ 승인 ⏵⏵ 자동 승인 — 안 묻고 고칩니다. 되돌리기(/undo)가 안전망입니다 │
24
+ │ Shift+Tab 으로 바꿉니다 · Tab 은 치던 / 명령을 채웁니다 │
23
25
  │ 이 PC 스킬 337 · 명령 127 · 플러그인 42 │
24
26
  ╰──────────────────────────────────────────────────────────────╯
25
27
  /help 명령 목록 /think 추론 강도 Ctrl+C 중단·끝내기
26
28
 
27
- ▏myproject · qwen2.5-coder:7b ▏ ▰▰▱▱▱▱▱▱▱▱ 22% 28k/128k ▏ ◎ 종합 · ◇ medium·절약 · auto
29
+ ▏myproject · qwen2.5-coder:7b ▏ ▰▰▱▱▱▱▱▱▱▱ 22% 28k/128k ▏ ◎ 종합 · ◇ medium·절약 · ⏵⏵ 자동
28
30
  ❯ 로그 형식 통일해줘
29
31
 
30
32
  ❊ Grep(console.log)
@@ -251,6 +253,18 @@ LM Studio 는 `/api/v0/models`, llama.cpp 는 `/props`. 못 알아보면 `(추
251
253
  `/scan` 과 `/sessions` 는 나가지 않고도 씁니다. 로컬 서버를 새로 켰거나 모델을
252
254
  바꿔 올렸을 때 `/scan save` → `/model` 두 번이면 대화를 이어둔 채로 갈아탑니다.
253
255
 
256
+ **치지 않고 쓰는 것**
257
+
258
+ | 키 | 무엇을 |
259
+ |---|---|
260
+ | `Tab` | 치던 `/` 명령을 채웁니다. 치는 도중에 후보가 상자 아래에 뜹니다 |
261
+ | `Shift+Tab` | 승인 방식 (`⏵⏵ 자동` → `⏵ 위험만` → `⏸ 모두`) |
262
+ | `Ctrl+O` | 작업 모드 (`종합` → `코드` → `계획` → …) |
263
+ | `↑` `↓` | 지난 입력 이력 |
264
+ | `Ctrl+C` | 답하는 중이면 그 답만 끊고, 빈 줄에서 두 번이면 끝냅니다 |
265
+
266
+ 한글 조합·붙여넣기·`Ctrl+A/E`·백스페이스는 전부 그대로 됩니다.
267
+
254
268
  ### `@파일` 로 바로 붙이기
255
269
 
256
270
  말 속에 `@` 뒤로 경로를 쓰면 그 파일을 말과 함께 바로 보냅니다.
@@ -401,50 +415,172 @@ LM Studio 는 `/api/v0/models`, llama.cpp 는 `/props`. 못 알아보면 `(추
401
415
  - **초보라고 승인을 덜 받지 않습니다.** 되돌리기·작업 범위·위험 명령 차단은 두 수준이 같습니다.
402
416
  초보일수록 되돌릴 수 있어야 합니다.
403
417
 
404
- ### 화면 두 가지
405
-
406
- 터미널에서 그냥 켜면 **전체화면**입니다. 왼쪽은 대화, 오른쪽 위는 이번에 바뀐 파일,
407
- 오른쪽 아래는 일입니다. 아래에 상태줄과 입력칸이 고정으로 붙습니다.
408
-
409
- ```
410
- 대화 ─────────────────────────────────────────────┬ 바뀐 파일 ───────────────┐
411
- │ ❊ Grep(console.log) │ src/runner.js +3-1 │
412
- │ └ 3개 파일 · 11건 │ src/index.js +1-1 │
413
- │ │ src/ui/log.js +12-0 │
414
- │ ◈ Edit(src/runner.js) ├ 할 일 ───────────────────│
415
- │ └ 1군데 +3-1 │ 로그 호출 찾기 │
416
- │ - 12 console.log('시작', 이름) │ ☑ runner.js 통일 │
417
- │ + 12 logger.info({ 단계: '시작', 이름 }) │ ▶ index.js 통일 │
418
- │ │ ☐ 문서 갱신 │
419
- │ ▌ 로그 호출을 logger 형식으로 통일했습니다. │ │
420
- │ │ │
421
- │ ── 4.2초 · 도구 3회 · ↑3,900 ↓180 │ │
422
- └───────────────────────────────────────────────────┴──────────────────────────┘
423
- ▏myproject · qwen2.5-coder:7b ▏ ▰▰▱▱▱▱▱▱ 22% ▏ ◎ 종합 · ◇ medium · auto ▏ ↑3.8k ↓180
418
+ ### 입력칸
419
+
420
+ 터미널에서 그냥 켜면 **대화는 위로 흘러가고, 아래에 입력 상자가 붙습니다.**
421
+ 상자만 우리가 지우고 다시 그립니다 위쪽 대화는 손대지 않습니다.
422
+
423
+ ```
424
+ Grep(console.log)
425
+ 3개 파일 · 11건
426
+ Edit(src/runner.js)
427
+ 1군데 +3-1
428
+ - 12 console.log('시작', 이름)
429
+ + 12 logger.info({ 단계: '시작', 이름 })
430
+
431
+ 로그 호출을 logger 형식으로 통일했습니다. runner.js 한 군데입니다.
432
+
433
+ ── 4.2초 · 도구 3회 · ↑3,900 ↓180
434
+
435
+ ▏myproject · qwen2.5-coder:7b ▏ ▰▰▱▱▱▱▱▱ 22% ▏ ◎ 종합 · medium · ⏵⏵ 자동
424
436
  ╭─────────────────────────────────────────────────────────────────────────────╮
425
- │ ❯
437
+ │ ❯ 집계 함수도 줄여줘
426
438
  ╰─────────────────────────────────────────────────────────────────────────────╯
427
439
  ```
428
440
 
441
+ 터미널 스크롤·복사·`Ctrl+F` 찾기가 **그대로 됩니다.** 대화를 우리 칸에 가둬 두지
442
+ 않기 때문입니다. 긴 글을 치면 상자가 알아서 여러 줄로 늘어납니다.
443
+
429
444
  **저절로 꺼지는 자리가 있습니다.** 파이프·리다이렉트로 넘길 때, `CI` 가 켜져 있을 때,
430
- `TERM=dumb` 일 때, 창이 60칸·16줄보다 작을 때는 묻지 않고 **줄 화면**으로 갑니다.
445
+ `TERM=dumb` 일 때, 창이 40칸보다 좁을 때는 묻지 않고 상자를 그립니다.
431
446
  `deel … | tee 기록.txt` 가 제어문자 덩어리가 되면 안 되기 때문입니다.
432
- `--tui` 를 줘도 파이프면 안 켭니다.
447
+ `--tui` 를 줘도 파이프면 안 켭니다. `--no-tui` 로 언제든 끌 수 있습니다.
448
+
449
+ 줄 편집은 전부 Node 의 readline 이 그대로 맡습니다 — 한글 조합, 붙여넣기,
450
+ 위아래 이력, Ctrl+A/E, 백스페이스. 우리는 readline 이 들고 있는 글을 상자 안에
451
+ **그리기만** 합니다. 직접 키를 받아 줄 편집을 짜기 시작하면 한글 입력기부터 깨집니다.
452
+
453
+ > **한 번 틀렸던 길** — 처음에는 터미널을 통째로 빌려(vim 처럼 딴 화면) 대화 칸·
454
+ > 파일 칸·할 일 칸을 나눠 그렸습니다. 보기에는 그럴듯했는데 **슬래시 명령이 전부
455
+ > 먹통**이 됐습니다. `commands.js` 를 비롯한 여섯 모듈이 화면 객체를 안 거치고
456
+ > 터미널에 바로 쓰는데, 매번 화면을 통째로 다시 그리니 그 글이 찍히자마자 덮여
457
+ > 사라졌던 것입니다. 명령이 안 도는 게 아니라 **결과가 안 보이는** 것이라 더
458
+ > 나빴습니다. 고치려면 터미널에 쓰는 자리를 전부 화면 객체로 꿰야 하는데, 지금
459
+ > 여섯 곳이고 앞으로 늘 것이며, 하나라도 빠뜨리면 같은 증상이 조용히 돌아옵니다.
460
+ > 그래서 반대로 갔습니다 — 대화는 그냥 흘려보내고 상자만 관리합니다.
461
+ > ([`test/box.test.js`](test/box.test.js) 가 터미널인 척하는 자식을 띄워
462
+ > 이 결함이 다시 안 나가는지 봅니다.)
463
+
464
+ ---
465
+
466
+ ### 명령은 다 안 쳐도 됩니다
467
+
468
+ 명령이 서른 개가 넘습니다. 다 외우고 있는 사람은 만든 사람뿐이고, 그마저도
469
+ `/mem…` 까지 치고 "이게 memory 였나 memo 였나" 하고 멈춥니다. 그때 할 수 있는
470
+ 것이 `/help` 를 쳐서 서른 줄을 받아 눈으로 훑는 것뿐이면, 그건 명령이 아니라
471
+ 시험입니다.
472
+
473
+ 그래서 **치는 도중에 보여 줍니다.**
474
+
475
+ ```
476
+ ╭─────────────────────────────────────────────────────────────────────────────╮
477
+ │ ❯ /mo │
478
+ ╰─────────────────────────────────────────────────────────────────────────────╯
479
+ › /model [이름|list|models] 연결·모델 바꾸기 (이름 일부 · list · models)
480
+ /mode <모드> 승인 정책 — 얼마나 물어보나
481
+ /memory [지우기 <번호>|…] 대화가 끝나도 남는 기억 — 보기·지우기
482
+ ```
483
+
484
+ `Tab` 을 누르면 채워집니다. 하나만 맞으면 끝까지, 여럿이면 **다 같이 가진
485
+ 앞부분까지만** 채웁니다(`/mo` + Tab → `/mode`). 하나를 골라 박아 넣지 않는
486
+ 것은, 사람이 원한 것이 아닐 때 지우는 수고가 더 들기 때문입니다. 인자를 받는
487
+ 명령이면 빈칸까지 붙여 바로 이어 칠 수 있게 합니다.
488
+
489
+ 앞에서 맞는 것을 먼저 보여 주고, **가운데 맞는 것도 뒤에 붙입니다** — 오타는
490
+ 앞글자에서 제일 많이 나므로, `/emo` 라고 잘못 쳐도 `/memory` 가 나옵니다.
491
+ 빈칸을 치는 순간(`/mode auto`) 목록은 접힙니다. 명령이 이미 정해졌기 때문입니다.
492
+
493
+ 목록은 **상자 아래**에 붙습니다. 안에 넣으면 치던 글이 밀려 올라가서 무엇을
494
+ 치고 있었는지가 안 보입니다.
433
495
 
434
- | | 전체화면 | 화면 (`--no-tui`) |
496
+ > 위아래 화살표로 고르게 하지 않습니다. 그러면 **지난 입력 이력**(위 화살표)
497
+ > 뺏어야 하는데, 그건 훨씬 자주 쓰는 기능입니다. 여기서 필요한 것은 고르는
498
+ > 것이 아니라 **알아보는 것**이고, 알아보고 나면 Tab 한 번이면 됩니다.
499
+ >
500
+ > `쉬움` 수준에서 감춰 둔 명령도 앞글자를 치면 나옵니다. 감춘 것은 '못 쓰는
501
+ > 것' 이 아닙니다 — `/recall` 을 아는 사람이 수준 설정 때문에 "그런 명령
502
+ > 없다" 는 화면을 보면 안 됩니다.
503
+
504
+ ---
505
+
506
+ ### 일하는 중에는 상자가 그대로 있습니다
507
+
508
+ 로컬 모델은 느립니다. 한 걸음에 수십 초가 걸리는데 그 동안 화면 아래가 텅 비면
509
+ **멈춘 줄 알고 Ctrl+C 를 누르게 됩니다** — 다 되어 가던 일이 그렇게 날아갑니다.
510
+ 그래서 테두리는 그대로 두고 안엣것만 바꿉니다.
511
+
512
+ ```
513
+ ◧ Read(집계.py)
514
+ └ 6줄
515
+
516
+ ▏myproject · qwen2.5-coder:7b ▏ ▰▱▱▱▱▱▱▱▱▱ 2% ▏ ◎ 종합 · ◇ medium · ⏵⏵ 자동 ▏ ↑3.8k ↓180
517
+ ╭─────────────────────────────────────────────────────────────────────────────╮
518
+ │ ⠹ 파일 들여다보는 중… 12초 · 생각 1,240자 · Ctrl+C 중단 │
519
+ ╰─────────────────────────────────────────────────────────────────────────────╯
520
+ ```
521
+
522
+ 문구는 **지금 진짜로 하는 일**을 따라갑니다. 재미로 넣은 것이 아닙니다 —
523
+ 아무 말이나 돌려 대면 두 번째부터 아무도 안 읽고, 그때부터는 화면이 조용한 것과
524
+ 같아집니다. 한 턴을 돌리면 이렇게 지나갑니다:
525
+
526
+ ```
527
+ 머리 굴리는 중 → 파일 들여다보는 중 → 코드 짜는 중 → 답 쓰는 중
528
+ ```
529
+
530
+ | 하는 일 | 문구 |
531
+ |---|---|
532
+ | 생각 | 머리 굴리는 중 · 어떻게 할지 궁리하는 중 · 수 읽는 중 · 따져 보는 중 |
533
+ | `Read` `Grep` `Glob` | 파일 들여다보는 중 · 코드 훑는 중 · 어디 있나 뒤지는 중 · 단서 찾는 중 |
534
+ | `Write` `Edit` `Append` | 코드 짜는 중 · 고쳐 넣는 중 · 손보는 중 · 한 줄씩 옮기는 중 |
535
+ | `Bash` | 명령 돌리는 중 · 터미널 두드리는 중 · 결과 기다리는 중 |
536
+ | `WebFetch` | 문서 찾아보는 중 · 읽어 오는 중 |
537
+ | 답하는 중 | 답 쓰는 중 · 정리해서 말하는 중 |
538
+ | **45초가 넘으면** | 아직 하는 중 · 조금만 더 · 생각보다 오래 걸리는 중 |
539
+
540
+ 같은 갈래 안에서도 4초마다 다른 문구로 넘어갑니다. 같은 글자가 30초 동안 그대로
541
+ 있으면 그것도 멈춘 것처럼 보이기 때문입니다. 오른쪽에는 **걸린 시간**과, 모델이
542
+ 추론 중이면 **지금까지 생각한 글자 수**가 같이 뜹니다 — 진짜로 늘어나는 숫자가
543
+ 하나 있어야 '살아 있다' 가 표시가 아니라 사실이 됩니다.
544
+
545
+ ### 무엇을 물어보고 무엇을 그냥 할지
546
+
547
+ 내 파일이 **물어보고 바뀌는지, 안 물어보고 바뀌는지**는 흘깃 봐서 바로 알아야
548
+ 하는 한 가지입니다. 상태줄 오른쪽에 늘 떠 있습니다.
549
+
550
+ | 표시 | 명령 | 무엇을 물어보나 |
435
551
  |---|---|---|
436
- | 언제 | 터미널에서 그냥 | 파이프·CI·좁은 창·`--no-tui` |
437
- | 바뀐 파일·할 | 오른쪽 칸에 보임 (96칸 이상) | 나올 줄로 흘려보냄 |
438
- | 지난 화면 | 스크롤 대신 안에서 접어 보여 | 터미널 스크롤 그대로 |
439
- | 나갈 때 | **나눈 대화를 스크롤백에 되살림** | 이미 거기 있음 |
440
- | 기록으로 남길 | 맞음 | 이쪽 |
552
+ | `⏵⏵ 자동 승인` | `/mode auto` | 묻고 고칩니다. 되돌리기(`/undo`)가 안전망입니다 |
553
+ | `⏵ 위험만 확인` | `/mode confirm` | 되돌릴 없는 명령만 물어봅니다. 파일은 묻고 고칩니다 |
554
+ | `⏸ 모두 확인` | `/mode strict` | 파일을 고치거나 명령을 돌리기 전에 매번 물어봅니다 |
555
+
556
+ `/mode` 치면 셋을 나란히 보여 주고 지금 것에 ● 를 찍습니다.
557
+ 켤 때 머리말에도 사람 말로 한 줄 나옵니다 — 한 번 읽고 나면 그 다음부터는
558
+ 글자만 봐도 압니다.
559
+
560
+ **`Shift+Tab` 으로 치지 않고 바꿉니다.** 누를 때마다 차례로 돌고, 무엇에서
561
+ 무엇으로 갔는지 한 줄이 남습니다. 치던 글은 그대로 있습니다.
562
+
563
+ ```
564
+ ⏵ 위험만 확인 되돌릴 수 없는 명령만 물어봅니다. 파일은 안 묻고 고칩니다
565
+ 자동 승인 → 위험만 확인 · Shift+Tab 으로 계속 바꿉니다
566
+ ```
567
+
568
+ 차례는 **느슨한 쪽 → 조이는 쪽**입니다(자동 → 위험만 → 모두 → 자동). 잘못
569
+ 눌러도 더 물어보게 될 뿐, 한 번에 '안 묻고 고침' 으로 떨어지지 않습니다.
441
570
 
442
- 전체화면은 vim 처럼 화면(대체 화면 버퍼) 씁니다. 그냥 나가면 방금 나눈 대화가
443
- 통째로 사라지므로, 나갈 최근 줄들을 원래 화면에 다시 찍어 놓습니다.
444
- Ctrl+C 죽든 오류로 터지든 **터미널은 반드시 되돌려 놓습니다.**
571
+ > 자리는 원래 작업 모드(`종합`·`코드`…) 쓰고 있었습니다. 바꾼 이유는
572
+ > **누가 자주 손대느냐**입니다. 작업 모드는 요청을 보고 저절로 옮겨 가지만,
573
+ > 승인 방식은 "이번 건은 봐야겠다" 싶을 때 일하는 도중에 바꾸고 싶어집니다.
574
+ > 작업 모드는 `Ctrl+O` 로 옮겼고 `/work` 도 그대로 됩니다.
445
575
 
446
- 전체화면을 세우면 유별난 터미널이거나 무엇이 됐든 조용히 줄 화면으로 가고
447
- 그랬는지 말합니다. **화면 하나 때문에 프로그램이 뜨는 일은 없습니다.**
576
+ > 전에는 `auto` 라는 영문 낱말이었습니다. 옆에 `종합`·`medium·절약` 나란히
577
+ > 있으니 그냥 '모드' 보였고, 그중 하나가 **묻지 않고 파일을 고친다**는
578
+ > 뜻이라는 것은 화면 어디에도 없었습니다.
579
+ >
580
+ > 자리가 모자랄 때 무엇을 접는지도 그래서 바꿨습니다. 사내 게이트웨이 모델 이름은
581
+ > `databricks-gpt-5-6-luna` 처럼 스물세 칸을 그냥 먹는데, 그것 하나 때문에 승인
582
+ > 방식이 화면에서 통째로 사라지고 있었습니다. 지금은 **모델 이름을 먼저 줄입니다** —
583
+ > 무엇으로 도는지는 이미 알지만, 내 파일이 안 물어보고 바뀌는지는 지금 봐야 압니다.
448
584
 
449
585
  ---
450
586
 
@@ -1216,7 +1352,7 @@ deel --effort <배분> even / save(기본) / deep
1216
1352
  deel --offline 이 컴퓨터 밖으로 아무것도 안 보냄
1217
1353
  deel --continue 가장 최근 대화 이어하기
1218
1354
  deel --resume <id> 골라서 이어하기
1219
- deel --no-tui 전체화면을 끄고 줄 화면으로 (아래 참고)
1355
+ deel --no-tui 입력 상자를 끄고 줄 화면으로 (아래 참고)
1220
1356
  ```
1221
1357
 
1222
1358
  ### 프로젝트 규칙
@@ -1247,7 +1383,7 @@ deel --no-tui 전체화면을 끄고 줄 화면으로 (아래 참고)
1247
1383
  ## 개발
1248
1384
 
1249
1385
  ```bash
1250
- npm test 전체 검증 (1,745항목)
1386
+ npm test 전체 검증 (1,832항목)
1251
1387
  npm run coverage 검사가 소스의 어디를 밟았는지
1252
1388
  npm run verify 반입·통신 검증만
1253
1389
  npm run bench 편집 성공률 측정
@@ -1314,7 +1450,7 @@ node test/coverage.mjs --json 기계가 읽을 형태로
1314
1450
  `NODE_V8_COVERAGE` 를 읽습니다 — 새로 반입 심사할 것이 하나도 안 늡니다.
1315
1451
  자식 프로세스까지 잡히므로 `deel` 을 띄워 보는 `cli` 검사도 그대로 집계됩니다.
1316
1452
 
1317
- 지금 **전체 92%** (7,570줄 중 6,960줄). 일부러 못 채운 곳이 셋 있습니다.
1453
+ 지금 **전체 92%** (7,646줄 중 7,056줄). 일부러 못 채운 곳이 셋 있습니다.
1318
1454
 
1319
1455
  | 파일 | 지금 | 왜 못 채우나 |
1320
1456
  |---|---|---|
@@ -1328,8 +1464,11 @@ node test/coverage.mjs --json 기계가 읽을 형태로
1328
1464
  bin/deel.js 진입점
1329
1465
  src/
1330
1466
  ui/ 색·한글 폭·상자·상태줄·입력
1331
- ui/screen.js 화면 고르기 (줄 화면 / 전체화면)
1332
- ui/tui.js 전체화면 접어쓰기·오른쪽 칸·나갈 되살리기
1467
+ ui/screen.js 화면 고르기 (줄 화면 / 상자 화면)
1468
+ ui/inputbox.js 아래 입력 상자 그리기·지우기·커서 자리
1469
+ ui/working.js 일하는 중 문구 — 지금 하는 일을 따라간다
1470
+ ui/approve.js 승인 방식 표시 (자동/위험만/모두)
1471
+ ui/wrap.js 색을 지키며 폭에 맞춰 접기
1333
1472
  agent/loop.js 에이전트 루프
1334
1473
  agent/session.js 대화 상태 + 컨텍스트 셈
1335
1474
  agent/effort.js 단계별 추론 강도 배분
package/bin/deel.js CHANGED
@@ -102,7 +102,7 @@ function help() {
102
102
  say(` ${c.gray('--max-tokens <길이>')} 한 번에 받을 답 길이 상한 (32k). 큰 파일이 잘리면 올린다 — /out 과 같은 값`);
103
103
  say(` ${c.gray('--think <수준>')} off / low / medium(기본) / high / max`);
104
104
  say(` ${c.gray('--effort <배분>')} even(균일) / save(절약, 기본) / deep(깊게)`);
105
- say(` ${c.gray('--no-tui')} 전체화면 대신 줄 화면으로 (파이프·기록·좁은 터미널)`);
105
+ say(` ${c.gray('--no-tui')} 입력 상자 없이 줄 화면으로 (파이프·기록·좁은 터미널)`);
106
106
  say(` ${c.gray('--offline')} 이 컴퓨터 밖으로는 아무것도 안 보냄 (자물쇠)`);
107
107
  say(` ${c.gray('--continue')} 이 폴더에서 가장 최근 대화 이어하기`);
108
108
  say(` ${c.gray('--resume <id>')} 골라서 이어하기 (deel sessions 로 id 확인)`);
@@ -173,9 +173,9 @@ async function main() {
173
173
  maxTokens: flags['max-tokens'] ? parseSize(String(flags['max-tokens'])) : undefined,
174
174
  think: flags.think ? String(flags.think) : undefined,
175
175
  effort: flags.effort ? String(flags.effort) : undefined,
176
- // 전체화면을 쓸지. 안 주면 null — 그러면 화면 쪽이 상황을 보고 정한다.
177
- // --no-tui 줄 화면으로 (파이프·기록·좁은 터미널·문제가 생겼을 때)
178
- // --tui 터미널이면 무조건 전체화면으로
176
+ // 입력 상자를 쓸지. 안 주면 null — 그러면 화면 쪽이 상황을 보고 정한다.
177
+ // --no-tui 입력 상자 없이 줄 화면으로 (파이프·기록·좁은 터미널)
178
+ // --tui 터미널이면 무조건 입력 상자를 켠다
179
179
  tui: flags['no-tui'] === true ? false : (flags.tui === true ? true : null),
180
180
  offline: flags.offline === true || flags.offline === 'true',
181
181
  continue: flags.continue === true || flags.c === true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deel-local-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "로컬 모델·사내 게이트웨이 전용 코딩 에이전트 CLI — 외부 의존성 0개 / Zero-dependency coding agent CLI for local LLMs and private gateways",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -236,7 +236,7 @@ export function get(id) {
236
236
  return MODES[normalize(id) ?? DEFAULT];
237
237
  }
238
238
 
239
- /** Shift+Tab 으로 돌릴 때 다음 모드. */
239
+ /** Ctrl+O 돌릴 때 다음 모드. (Shift+Tab 은 승인 방식이 가져갔다) */
240
240
  export function next(id) {
241
241
  const i = ORDER.indexOf(normalize(id) ?? DEFAULT);
242
242
  return ORDER[(i + 1) % ORDER.length];