deel-local-cli 1.1.1 → 1.4.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.en.md +826 -19
- package/README.md +689 -14
- package/bin/deel.js +73 -4
- package/package.json +7 -3
- package/src/acp/jsonrpc.js +230 -0
- package/src/acp/map.js +219 -0
- package/src/acp/serve.js +556 -0
- package/src/agent/budget.js +0 -14
- package/src/agent/card.js +110 -0
- package/src/agent/compact.js +95 -0
- package/src/agent/evidence.js +186 -0
- package/src/agent/evolve.js +213 -0
- package/src/agent/grade.js +20 -0
- package/src/agent/loop.js +172 -14
- package/src/agent/models.js +169 -0
- package/src/agent/modes.js +49 -1
- package/src/agent/pins.js +140 -0
- package/src/agent/project.js +10 -4
- package/src/agent/session.js +359 -11
- package/src/agent/store.js +31 -0
- package/src/agent/threads.js +154 -0
- package/src/commands.js +751 -55
- package/src/config.js +10 -1
- package/src/i18n/en.js +244 -0
- package/src/i18n/index.js +126 -0
- package/src/i18n/ko.js +231 -0
- package/src/lsp/client.js +459 -0
- package/src/lsp/diag.js +112 -0
- package/src/lsp/rpc.js +84 -0
- package/src/lsp/servers.js +218 -0
- package/src/oneshot.js +23 -0
- package/src/pack/sbom.js +218 -0
- package/src/pack/selfpack.js +19 -3
- package/src/repl.js +273 -22
- package/src/safety/guard.js +37 -2
- package/src/safety/secrets.js +205 -0
- package/src/safety/undo.js +11 -4
- package/src/setup.js +2 -2
- package/src/skills/discover.js +1 -1
- package/src/tools/desc.en.js +219 -0
- package/src/tools/edit-match.js +16 -5
- package/src/tools/excel-com.js +1 -1
- package/src/tools/excel.js +1 -1
- package/src/tools/fsutil.js +0 -8
- package/src/tools/index.js +149 -6
- package/src/tools/lsp.js +327 -0
- package/src/tools/task.js +30 -2
- package/src/tools/todo.js +19 -3
- package/src/ui/ansi.js +42 -2
- package/src/ui/approve.js +25 -21
- package/src/ui/inputbox.js +69 -13
- package/src/ui/intro.js +174 -0
- package/src/ui/level.js +11 -5
- package/src/ui/md.js +227 -0
- package/src/ui/notify.js +101 -0
- package/src/ui/prompt.js +1 -1
- package/src/ui/screen.js +1 -1
- package/src/ui/status.js +190 -34
- package/src/ui/working.js +0 -3
- package/src/ui/wrap.js +1 -8
package/README.en.md
CHANGED
|
@@ -53,16 +53,22 @@ Zero dependencies · Node 20+ · Exactly one place your source can go
|
|
|
53
53
|
- [Simple vs developer](#simple-vs-developer)
|
|
54
54
|
- [Tools](#tools)
|
|
55
55
|
- [Korean text and Excel](#korean-text-and-excel)
|
|
56
|
+
- [Serving what you built](#serving-what-you-built)
|
|
56
57
|
- [Skills and plugins](#skills-and-plugins)
|
|
57
58
|
- [Reasoning effort](#reasoning-effort)
|
|
58
59
|
- [Auto-compaction](#auto-compaction)
|
|
59
60
|
- [Resuming a conversation](#resuming-a-conversation)
|
|
60
61
|
- [Attaching tools from outside (MCP)](#attaching-tools-from-outside-mcp)
|
|
62
|
+
- [Inside your editor (ACP)](#inside-your-editor-acp)
|
|
63
|
+
- [Keeping secrets out of the conversation](#keeping-secrets-out-of-the-conversation)
|
|
61
64
|
- [Safety](#safety)
|
|
62
65
|
- [Corporate review package](#corporate-review-package)
|
|
63
66
|
- [Configuration](#configuration)
|
|
64
67
|
- [Troubleshooting](#troubleshooting)
|
|
65
68
|
- [Development](#development)
|
|
69
|
+
- [Release notes](#release-notes)
|
|
70
|
+
|
|
71
|
+
Each section is open at the summary. Click **▸ More** to unfold the detail behind it.
|
|
66
72
|
|
|
67
73
|
---
|
|
68
74
|
|
|
@@ -93,6 +99,29 @@ deel audit # full review sheet
|
|
|
93
99
|
|
|
94
100
|
## Quick start
|
|
95
101
|
|
|
102
|
+
### The screen speaks English too
|
|
103
|
+
|
|
104
|
+
deel is written in Korean — the code, the function names, the comments. That part stays.
|
|
105
|
+
What you see on screen does not have to.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
DEEL_LANG=en deel # this run only
|
|
109
|
+
/lang en # and remember it
|
|
110
|
+
/lang # how much is translated so far
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Untranslated lines come through in Korean rather than as blanks, and `/lang` tells you exactly
|
|
114
|
+
how many are left.
|
|
115
|
+
|
|
116
|
+
What the model reads follows the same switch. Set it to English and the rules, the mode
|
|
117
|
+
instructions, and the tool descriptions all go out in English — so the model answers you in
|
|
118
|
+
English instead of Korean. That side is cheaper, too: the part of the window that ships on every
|
|
119
|
+
single request drops from about 4,900 tokens to about 3,450 — on a 32k model, from 15% of the
|
|
120
|
+
window to 10.5%.
|
|
121
|
+
|
|
122
|
+
Tool names and argument names stay Korean (`목적`, `할일`, `번호`). Those are identifiers, not
|
|
123
|
+
prose — rename them and the tool stops being called at all.
|
|
124
|
+
|
|
96
125
|
### Install
|
|
97
126
|
|
|
98
127
|
```bash
|
|
@@ -203,6 +232,9 @@ $ deel scan
|
|
|
203
232
|
|
|
204
233
|
Switch with `/model` mid-conversation — **the conversation carries over.**
|
|
205
234
|
|
|
235
|
+
<details>
|
|
236
|
+
<summary><b>More</b> — It adapts to whatever model is attached · Small windows get a smaller fixed share · On startup it reads what kind of project this folder is</summary>
|
|
237
|
+
|
|
206
238
|
### It adapts to whatever model is attached
|
|
207
239
|
|
|
208
240
|
If you move between models, any number tuned for one of them is wrong for all the others.
|
|
@@ -333,6 +365,8 @@ can be recovered with one `Glob`; "tests run with `npm test`" requires opening
|
|
|
333
365
|
|
|
334
366
|
7ms on a folder with 600 files (`test/project.test.js`).
|
|
335
367
|
|
|
368
|
+
</details>
|
|
369
|
+
|
|
336
370
|
---
|
|
337
371
|
|
|
338
372
|
## Slash commands
|
|
@@ -342,13 +376,22 @@ Names follow Claude Code / Codex conventions.
|
|
|
342
376
|
| Command | What it does |
|
|
343
377
|
|---|---|
|
|
344
378
|
| `/help` | Command list |
|
|
379
|
+
| `/lang [ko\|en]` | Screen language. Falls back to Korean for anything not translated yet |
|
|
380
|
+
| `/bell [on\|off]` | Ring and set the window title when a turn ends, or when deel needs an answer |
|
|
381
|
+
| `/consult <profile> <question>` | Ask a second model one question. Your current model stays put |
|
|
382
|
+
| `/lsp [on\|off]` | Language servers — what is installed, and whether `Def`/`Refs` are available. `off` turns post-edit diagnostics off only |
|
|
345
383
|
| `/context` | What is consuming the context window |
|
|
346
384
|
| `/ctx [auto\|number]` | Context **length** — re-read it off the model, or set it yourself |
|
|
347
385
|
| `/grade [small\|medium\|large\|auto]` | Model **grade** — how much it does on its own. A different axis from `/ctx` |
|
|
348
386
|
| `/out [number\|auto]` | Cap on a **single reply** — raise it when large files get cut |
|
|
349
387
|
| `/compact` | Summarise and fold older turns |
|
|
350
388
|
| `/clear` | Clear the conversation (keeps link and rules) |
|
|
389
|
+
| `/thread [new\|fork\|close\|n]` | Conversation threads — side work in its own context. Link and undo stay shared |
|
|
390
|
+
| `/learned [clear]` | What deel has picked up on its own — commands that work here, this model's habits |
|
|
391
|
+
| `/pin <text>` | Pin a line — folding and compaction **cannot reach it** |
|
|
392
|
+
| `/evidence [file]` | Evidence — what changed, and what proves it. **What is unproven is listed too** |
|
|
351
393
|
| `/model` | Switch connection / model |
|
|
394
|
+
| `/model 카드` | Model card — what this model has actually done here, and what deel changed because of it |
|
|
352
395
|
| `/think <level>` | Reasoning level (`off·low·medium·high·max`) |
|
|
353
396
|
| `/think 배분 <profile>` | Per-stage profile (`even·save·deep`) |
|
|
354
397
|
| `/think 자세히` | Stage table — which stage runs at which level and cap |
|
|
@@ -359,6 +402,7 @@ Names follow Claude Code / Codex conventions.
|
|
|
359
402
|
| `/level [level]` | How much to show (`쉬움` simple · `개발자` developer) |
|
|
360
403
|
| `/undo [turns]` | Revert file changes |
|
|
361
404
|
| `/diff [file]` | Files changed this session, and the changed lines |
|
|
405
|
+
| `/preview [folder\|file\|off]` | Serve what you built, right here — a browser opens with it |
|
|
362
406
|
| `/tools` | Available tools |
|
|
363
407
|
| `/skills [query\|all\|off]` | Browse, search, load skills |
|
|
364
408
|
| `/plugin [install\|remove\|pack]` | Manage plugins |
|
|
@@ -390,6 +434,9 @@ the conversation.
|
|
|
390
434
|
|
|
391
435
|
Korean IME composition, paste, `Ctrl+A/E` and backspace all keep working.
|
|
392
436
|
|
|
437
|
+
<details>
|
|
438
|
+
<summary><b>More</b> — Attaching a file with @ · Interrupting</summary>
|
|
439
|
+
|
|
393
440
|
### Attaching a file with `@`
|
|
394
441
|
|
|
395
442
|
Write `@` followed by a path and that file is sent along with your message.
|
|
@@ -448,6 +495,8 @@ session. Tools already running finish; **tools not yet started never run.**
|
|
|
448
495
|
|
|
449
496
|
Pressing Ctrl+C again on an empty line quits.
|
|
450
497
|
|
|
498
|
+
</details>
|
|
499
|
+
|
|
451
500
|
---
|
|
452
501
|
|
|
453
502
|
## Work modes
|
|
@@ -476,6 +525,9 @@ Don't confuse this with `/mode`. They are separate axes:
|
|
|
476
525
|
If you have explicitly set `/think` or `/mode`, your choice wins. A work mode never
|
|
477
526
|
overrides something a person chose.
|
|
478
527
|
|
|
528
|
+
<details>
|
|
529
|
+
<summary><b>More</b> — Switching by itself (Auto mode)</summary>
|
|
530
|
+
|
|
479
531
|
### Switching by itself (Auto mode)
|
|
480
532
|
|
|
481
533
|
You start in **Auto**. Nothing has been decided about what kind of work is coming.
|
|
@@ -518,6 +570,8 @@ A `~` in the status line means it switched by itself; no `~` means you chose it.
|
|
|
518
570
|
|
|
519
571
|
Choosing a mode yourself **pins** it. `/auto` (or `/work auto`) hands the wheel back.
|
|
520
572
|
|
|
573
|
+
</details>
|
|
574
|
+
|
|
521
575
|
---
|
|
522
576
|
|
|
523
577
|
## Simple vs developer
|
|
@@ -539,6 +593,9 @@ Two things matter here:
|
|
|
539
593
|
- **Beginners do not get fewer safeguards.** Undo, workspace scope and dangerous-command
|
|
540
594
|
blocking are identical. A beginner needs the undo more, not less.
|
|
541
595
|
|
|
596
|
+
<details>
|
|
597
|
+
<summary><b>More</b> — The input box · You don't have to type the whole command · The box stays while it works · The picture on the left moves too and 1 more</summary>
|
|
598
|
+
|
|
542
599
|
### The input box
|
|
543
600
|
|
|
544
601
|
Launched in a terminal, **the conversation scrolls normally and an input box is pinned at
|
|
@@ -652,21 +709,46 @@ more than a blank screen. One turn reads like this:
|
|
|
652
709
|
(turning it over) (looking at files) (writing code) (writing the answer)
|
|
653
710
|
```
|
|
654
711
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
|
658
|
-
|
|
659
|
-
|
|
|
660
|
-
| `
|
|
661
|
-
| `
|
|
662
|
-
|
|
|
663
|
-
|
|
|
712
|
+
The phrases are Korean, because the interface is. Here is what each set means:
|
|
713
|
+
|
|
714
|
+
| Activity | On screen | Roughly |
|
|
715
|
+
|---|---|---|
|
|
716
|
+
| Thinking | 머리 굴리는 중 · 어떻게 할지 궁리하는 중 · 수 읽는 중 · 따져 보는 중 | turning it over · working out how · reading ahead · weighing it up |
|
|
717
|
+
| `Read` `Grep` `Glob` | 파일 들여다보는 중 · 코드 훑는 중 · 어디 있나 뒤지는 중 · 단서 찾는 중 | looking at files · skimming code · hunting for where it is · looking for a clue |
|
|
718
|
+
| `Write` `Edit` `Append` | 코드 짜는 중 · 고쳐 넣는 중 · 손보는 중 · 한 줄씩 옮기는 중 | writing code · patching it in · touching it up · moving it a line at a time |
|
|
719
|
+
| `Bash` | 명령 돌리는 중 · 터미널 두드리는 중 · 결과 기다리는 중 | running a command · at the terminal · waiting on output |
|
|
720
|
+
| `WebFetch` | 문서 찾아보는 중 · 읽어 오는 중 | looking up docs · fetching |
|
|
721
|
+
| Answering | 답 쓰는 중 · 정리해서 말하는 중 | writing the answer · putting it together |
|
|
722
|
+
| **Past 45 seconds** | 아직 하는 중 · 조금만 더 · 생각보다 오래 걸리는 중 | still going · nearly there · taking longer than expected |
|
|
664
723
|
|
|
665
724
|
Within a category the phrase advances every 4 seconds — text frozen for 30 seconds reads as
|
|
666
725
|
hung too. On the right: **elapsed time**, and while the model is reasoning, **how many
|
|
667
726
|
characters of thinking have arrived**. One number that genuinely increases is what turns
|
|
668
727
|
"still alive" from a claim into a fact.
|
|
669
728
|
|
|
729
|
+
### The picture on the left moves too
|
|
730
|
+
|
|
731
|
+
What spins next to the phrase is not a spinner — it is **a small drawing of the work being
|
|
732
|
+
done right now**.
|
|
733
|
+
|
|
734
|
+
| Doing | One cycle | The picture |
|
|
735
|
+
|---|---|---|
|
|
736
|
+
| Thinking | `⠀⠶⠀` `⠰⣿⠆` `⢾⣿⡷` `⠰⣿⠆` | swells and shrinks |
|
|
737
|
+
| Reading | `⠉⠉⠉` `⠒⠒⠒` `⠤⠤⠤` `⣀⣀⣀` | a scanning line travels down |
|
|
738
|
+
| Writing | `⡼⠭⠧` `⠼⡯⠧` `⠼⠿⡧` `⠼⡭⠧` | **a laptop typing** |
|
|
739
|
+
| Commands | `⠉⠀⠀` `⠉⠈⠀` `⠛⠊⠀` `⠿⠮⠄` | output piles up a line at a time |
|
|
740
|
+
| Answering | `⠉⠀⠀` `⠛⠉⠀` `⠿⠛⠉` `⣿⠿⠛` | text fills up |
|
|
741
|
+
| Web | `⣀⣀⣀` `⣤⣀⣀` `⣶⣤⣀` `⣿⣶⣤` | signal bars grow |
|
|
742
|
+
| Compacting | `⣿⣿⣿` `⣶⣶⣶` `⣤⣤⣤` `⣀⣀⣀` | pressed down into one line |
|
|
743
|
+
| Past 45 seconds | `⠶⠀⠀` `⠰⠆⠀` `⠀⠶⠀` `⠀⠰⠆` | back and forth — "waiting" |
|
|
744
|
+
|
|
745
|
+
Braille only. One braille cell is **2 wide by 4 dots tall**, so three cells make a 6×4 grid
|
|
746
|
+
that is exactly three columns in any terminal. Emoji and `●` `▪` include glyphs that East
|
|
747
|
+
Asian locales measure as two columns, which knocks the border out of line every 90ms.
|
|
748
|
+
|
|
749
|
+
If the drawing does not render, or you use a screen reader, `DEEL_NO_MOTION=1` turns it off
|
|
750
|
+
and you get the old single-cell spinner.
|
|
751
|
+
|
|
670
752
|
### What gets asked, and what just happens
|
|
671
753
|
|
|
672
754
|
Whether your files change **with or without being asked** is the one thing that has to be
|
|
@@ -706,6 +788,8 @@ press only makes it ask more; it never drops you into "changes files unasked" in
|
|
|
706
788
|
> approval indicator off the line entirely. Now **the model name shortens first** — you
|
|
707
789
|
> already know what you are running; whether your files change unasked is what you need now.
|
|
708
790
|
|
|
791
|
+
</details>
|
|
792
|
+
|
|
709
793
|
---
|
|
710
794
|
|
|
711
795
|
## Tools
|
|
@@ -730,12 +814,17 @@ Names and arguments match Claude Code, so skills written for that convention wor
|
|
|
730
814
|
| `Verify` | Check that what was built **actually works** |
|
|
731
815
|
| `Task` | Run one chunk of a big job in a **separate context** |
|
|
732
816
|
| `Jobs` | Inspect, read and stop **background commands** — the other half of `Bash`'s `background` |
|
|
817
|
+
| `Def` | **Where a name is defined** — only shown when a language server is installed |
|
|
818
|
+
| `Refs` | **Every place a name is used** — only shown when a language server is installed |
|
|
733
819
|
|
|
734
820
|
Seven tools here are not in Claude Code — `Append`, `Recall`, `Remember`, `Outline`,
|
|
735
821
|
`Verify`, `Task`, `Jobs`. Each tool costs 150-400 tokens of schema on **every request**,
|
|
736
822
|
so a test stops you every time the list grows (`test/loop.test.js`). The last four earned
|
|
737
823
|
their cost; here is why.
|
|
738
824
|
|
|
825
|
+
<details>
|
|
826
|
+
<summary><b>More</b> — Outline · Verify · Task · Def · Refs · Commands that never finish and 9 more</summary>
|
|
827
|
+
|
|
739
828
|
### Seeing a project's shape cheaply — `Outline`
|
|
740
829
|
|
|
741
830
|
There used to be only two ways to understand someone else's code. `Glob` gives you paths;
|
|
@@ -1126,10 +1215,125 @@ last edit did. That original state comes from the earliest undo snapshot.
|
|
|
1126
1215
|
`/diff` is **in the simple level's command list.** As long as `auto` edits without asking,
|
|
1127
1216
|
a beginner needs a way to see what changed more than anyone.
|
|
1128
1217
|
|
|
1218
|
+
### With a language server, it sees meaning — `Def` and `Refs`
|
|
1219
|
+
|
|
1220
|
+
`Grep` finds **text**; a language server knows **meaning**. Grep for `run` and you get the
|
|
1221
|
+
`run` in a comment, the `run` in a third-party library, the `run` inside a string. Which of
|
|
1222
|
+
those actually call that function is something a person has to open one by one. The model
|
|
1223
|
+
cannot afford that, so it edits based on the first few hits, and **the ones it missed only
|
|
1224
|
+
surface once you run the thing.**
|
|
1225
|
+
|
|
1226
|
+
```
|
|
1227
|
+
⏺ Refs(add_up)
|
|
1228
|
+
add_up — used in 3 places · 2 files
|
|
1229
|
+
|
|
1230
|
+
src/use.py (2)
|
|
1231
|
+
4: return add_up(1, 2)
|
|
1232
|
+
9: return add_up(x, x)
|
|
1233
|
+
src/other.py (1)
|
|
1234
|
+
2: value = add_up(9, 9)
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
`Grep` stays. When you rename something outright you actually need it — a language server
|
|
1238
|
+
does not look at comments, config or docs. These two **add to** what was here; they do not
|
|
1239
|
+
replace it.
|
|
1240
|
+
|
|
1241
|
+
They take a **name**, not a position. LSP asks "this file, this line, this column", but the
|
|
1242
|
+
model does not know the column. Finding out means reading the file first, and that throws
|
|
1243
|
+
away the whole point of the tool. So it resolves the name through `workspace/symbol` first
|
|
1244
|
+
and asks again at that position. When a name exists in several places you get **the list** —
|
|
1245
|
+
it does not pick one and pretend.
|
|
1246
|
+
|
|
1247
|
+
### It checks the file you just edited
|
|
1248
|
+
|
|
1249
|
+
`Verify` stays too. They do different jobs.
|
|
1250
|
+
|
|
1251
|
+
| | When | What |
|
|
1252
|
+
|---|---|---|
|
|
1253
|
+
| `Verify` | Once, before you finish | **Syntax** (`node --check`, `py_compile`) |
|
|
1254
|
+
| Post-edit diagnostics | Right after an edit, that file only | **Meaning** (undefined names, wrong types, missing arguments) |
|
|
1255
|
+
|
|
1256
|
+
Some things are syntactically fine and still wrong. `node --check` passes all of them.
|
|
1257
|
+
|
|
1258
|
+
```
|
|
1259
|
+
⏺ Write(pkg/bad.py)
|
|
1260
|
+
3 lines
|
|
1261
|
+
language server — pkg/bad.py: 2 errors
|
|
1262
|
+
line 1 error: Type "Literal['x']" is not assignable to declared type "int"
|
|
1263
|
+
line 2 error: "missing_name" is not defined
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
Until now that only showed up **once something was run**, and running goes through user
|
|
1267
|
+
approval, so it was several steps later. In between, the model treats that file as finished
|
|
1268
|
+
and moves to the next one. When the error finally surfaces you have to trace back, and
|
|
1269
|
+
tracing back costs more than the fix.
|
|
1270
|
+
|
|
1271
|
+
When everything is fine it **says nothing.** A line of "0 errors" after every edit fills the
|
|
1272
|
+
window. And not receiving diagnostics is not the same as having none — when nothing came
|
|
1273
|
+
back, it says nothing rather than inventing an answer.
|
|
1274
|
+
|
|
1275
|
+
### It installs nothing
|
|
1276
|
+
|
|
1277
|
+
**deel does not install language servers.** It scans PATH; if one is there it uses it, and
|
|
1278
|
+
if not it falls back to `Grep` and `Outline`. This program exists for places where you cannot
|
|
1279
|
+
bring in unapproved software, so a tool running `npm i -g` on its own is out of the question.
|
|
1280
|
+
|
|
1281
|
+
With no server, `Def` and `Refs` **do not appear in the model's tool list at all** — the same
|
|
1282
|
+
way web tools are hidden offline. Leave an unusable tool standing and the model calls it,
|
|
1283
|
+
gets "not available", and calls it again. That round trip costs more than the schema does.
|
|
1284
|
+
|
|
1285
|
+
`/lsp` shows you what is there.
|
|
1286
|
+
|
|
1287
|
+
```
|
|
1288
|
+
$ /lsp
|
|
1289
|
+
|
|
1290
|
+
◈ 2 language server(s) on this machine
|
|
1291
|
+
✓ ts typescript-language-server
|
|
1292
|
+
✓ py pyright-langserver
|
|
1293
|
+
|
|
1294
|
+
Language of this folder: py · 12 files
|
|
1295
|
+
Tools: Def · Refs
|
|
1296
|
+
Diagnostics after an edit: on
|
|
1297
|
+
Turn post-edit diagnostics on or off: /lsp on · /lsp off
|
|
1298
|
+
```
|
|
1299
|
+
|
|
1300
|
+
It looks for `ts`, `py`, `go`, `rs`, `java`, `cs`, `cpp`, `rb`, `php` and `lua`. When one is
|
|
1301
|
+
missing it prints the install command **as text only.** Whether to run it is your call.
|
|
1302
|
+
|
|
1303
|
+
<details>
|
|
1304
|
+
<summary>Four things a real server (pyright) taught us</summary>
|
|
1305
|
+
|
|
1306
|
+
A stub server alone would have shown green for all of these.
|
|
1307
|
+
|
|
1308
|
+
- **Servers spell URIs differently than we do.** We send `file:///C:/…`; pyright answers with
|
|
1309
|
+
`file:///c%3A/…` — lowercase drive letter, percent-encoded colon. Compared as strings they
|
|
1310
|
+
never match. Diagnostics arrive correctly, are not found in our table, and become "nothing
|
|
1311
|
+
came back" — and **saying nothing means the file is sound**, so a broken file gets reported
|
|
1312
|
+
as fine. We compare paths, not URIs.
|
|
1313
|
+
- **A server that just started answers empty.** Not because the name is missing but because
|
|
1314
|
+
it has not finished indexing. Asked 0.2s after startup it said no; 0.5s later it said yes.
|
|
1315
|
+
Turning that into "no such name" makes the model create something that already exists. So
|
|
1316
|
+
it asks again a few times, but only while the server is young.
|
|
1317
|
+
- **npm installs two names on Windows.** An extension-less sh script and a `.cmd`. Find the
|
|
1318
|
+
first one and the file plainly exists, so it reports "installed" — but Windows cannot run
|
|
1319
|
+
it. Claiming it is there and then failing is the hardest failure to spot.
|
|
1320
|
+
- **`cmd /s /c` strips the outer pair of quotes.** Wrap the command once and it breaks
|
|
1321
|
+
entirely, and all you see from the outside is "no language server".
|
|
1322
|
+
|
|
1323
|
+
</details>
|
|
1324
|
+
|
|
1325
|
+
</details>
|
|
1326
|
+
|
|
1129
1327
|
---
|
|
1130
1328
|
|
|
1131
1329
|
## Korean text and Excel
|
|
1132
1330
|
|
|
1331
|
+
**A file saved as CP949 is written back as CP949.** The encoding is never changed.
|
|
1332
|
+
Excel (`.xlsx`) is read as CSV — read-only.
|
|
1333
|
+
|
|
1334
|
+
<details>
|
|
1335
|
+
<summary><b>More</b> — Encoding · Excel</summary>
|
|
1336
|
+
|
|
1133
1337
|
### Encoding — written back the way it was read
|
|
1134
1338
|
|
|
1135
1339
|
Corporate documents are often not UTF-8. Files saved by old Windows Notepad in a legacy
|
|
@@ -1200,6 +1404,55 @@ Extracted intermediate files are deleted after use.
|
|
|
1200
1404
|
> to do instead. Round-tripping a file with formatting, formulas and charts through CSV
|
|
1201
1405
|
> always loses something. Better not to write than to write knowing you'll lose data.
|
|
1202
1406
|
|
|
1407
|
+
</details>
|
|
1408
|
+
|
|
1409
|
+
---
|
|
1410
|
+
|
|
1411
|
+
## Serving what you built
|
|
1412
|
+
|
|
1413
|
+
```
|
|
1414
|
+
❯ /preview
|
|
1415
|
+
|
|
1416
|
+
▶ Serving http://127.0.0.1:56801/
|
|
1417
|
+
showing .
|
|
1418
|
+
Edit a file and the page reloads by itself.
|
|
1419
|
+
Only this machine can open it (127.0.0.1). No other PC can see it.
|
|
1420
|
+
Stop with /preview off · it shuts down when deel exits.
|
|
1421
|
+
```
|
|
1422
|
+
|
|
1423
|
+
A browser opens with it. `/preview <folder>` picks what to serve, `/preview off` stops it.
|
|
1424
|
+
|
|
1425
|
+
**This is not the same as double-clicking the file (`file://`).** Under `file://` everything
|
|
1426
|
+
below is blocked — and the error only shows up in the console while the page stays blank, so
|
|
1427
|
+
you end up suspecting your own code. This is a real HTTP server, so it all works:
|
|
1428
|
+
|
|
1429
|
+
| | `file://` | `/preview` |
|
|
1430
|
+
|---|---|---|
|
|
1431
|
+
| `<script type="module">` · `import` | blocked (CORS) | **works** |
|
|
1432
|
+
| `fetch('./data.json')` | blocked | **works** |
|
|
1433
|
+
| `new Worker(...)` | blocked | **works** |
|
|
1434
|
+
| `WebAssembly.compileStreaming` | blocked (MIME) | **works** |
|
|
1435
|
+
| textures · `getImageData` | tainted canvas | **works** |
|
|
1436
|
+
| `.glb` / `.gltf` (Three.js) | no MIME type → silently not drawn | **works** |
|
|
1437
|
+
|
|
1438
|
+
All seven were run in a real Chrome and confirmed **7/7**.
|
|
1439
|
+
|
|
1440
|
+
Apps with a router (React Router and friends) get the first page back when you reload on a
|
|
1441
|
+
deep link. Never for requests with an extension (`app.js`) though — returning HTML for a
|
|
1442
|
+
missing script dies with `Unexpected token '<'`, which hides the real cause (a typo in a filename).
|
|
1443
|
+
|
|
1444
|
+
### It opens exactly as much as it says
|
|
1445
|
+
|
|
1446
|
+
Starting a server means opening your disk to somebody else.
|
|
1447
|
+
|
|
1448
|
+
- Bound to **`127.0.0.1` only**. `0.0.0.0` is not available at all — on an office network
|
|
1449
|
+
that would let anyone read your source.
|
|
1450
|
+
- Port **0** (the kernel hands out a free one). A fixed port steals someone else's.
|
|
1451
|
+
- Paths cannot leave the working scope. `../` · `%2e%2e` · double encoding · absolute paths ·
|
|
1452
|
+
null bytes · symlinks — eight of these are held shut by tests.
|
|
1453
|
+
- **It only serves.** `POST` · `PUT` · `DELETE` are refused with 405.
|
|
1454
|
+
- It shuts down when `deel` exits.
|
|
1455
|
+
|
|
1203
1456
|
---
|
|
1204
1457
|
|
|
1205
1458
|
## Skills and plugins
|
|
@@ -1215,6 +1468,9 @@ plugins ~/.claude/plugins/** ~/.deel/plugins/**
|
|
|
1215
1468
|
|
|
1216
1469
|
Reads the Claude Code format: `SKILL.md` with YAML front matter, `commands/*.md`, `$ARGUMENTS`.
|
|
1217
1470
|
|
|
1471
|
+
<details>
|
|
1472
|
+
<summary><b>More</b> — Loaded in three stages · Fetching plugins · Deliberately not included</summary>
|
|
1473
|
+
|
|
1218
1474
|
### Loaded in three stages
|
|
1219
1475
|
|
|
1220
1476
|
Loading everything would blow the context window.
|
|
@@ -1247,6 +1503,8 @@ with a licence table — ready to hand to a security reviewer.
|
|
|
1247
1503
|
| sub-agents | Doubles model calls against a gateway quota |
|
|
1248
1504
|
| MCP | A separate protocol; a project of its own |
|
|
1249
1505
|
|
|
1506
|
+
</details>
|
|
1507
|
+
|
|
1250
1508
|
---
|
|
1251
1509
|
|
|
1252
1510
|
## Reasoning effort
|
|
@@ -1295,6 +1553,9 @@ That second-to-last line exists for a reason: **when all three caps are equal, i
|
|
|
1295
1553
|
only thing that says whether that is correct.** A low known cap makes them equal, and that
|
|
1296
1554
|
is fine. For a while all three read `16,384` always — which meant the table said nothing.
|
|
1297
1555
|
|
|
1556
|
+
<details>
|
|
1557
|
+
<summary><b>More</b> — Context length is read off the model · /out · Truncated tool calls</summary>
|
|
1558
|
+
|
|
1298
1559
|
### Context length is read off the model
|
|
1299
1560
|
|
|
1300
1561
|
This one number sizes the whole program: how many files fit in one read, when the
|
|
@@ -1428,6 +1689,8 @@ One silently swallowed value produced all of that. What happens now:
|
|
|
1428
1689
|
spinning one. What is counted here is not steps but **how many times the same tool failed for
|
|
1429
1690
|
the same reason.**
|
|
1430
1691
|
|
|
1692
|
+
</details>
|
|
1693
|
+
|
|
1431
1694
|
---
|
|
1432
1695
|
|
|
1433
1696
|
## Auto-compaction
|
|
@@ -1495,6 +1758,9 @@ The model sees it as `mcp__wiki__search`. `/mcp` shows what is attached.
|
|
|
1495
1758
|
**Dependencies stay at zero.** The stdio transport is nothing but newline-delimited JSON-RPC
|
|
1496
1759
|
2.0 over a child process's stdin/stdout, so `child_process` and `JSON` cover it. No SDK.
|
|
1497
1760
|
|
|
1761
|
+
<details>
|
|
1762
|
+
<summary><b>More</b> — But this is somebody else's program</summary>
|
|
1763
|
+
|
|
1498
1764
|
### But this is somebody else's program
|
|
1499
1765
|
|
|
1500
1766
|
This project exists because unapproved software is blocked. Turning on MCP carelessly would
|
|
@@ -1514,6 +1780,110 @@ One server crashing, hanging, or talking nonsense does not affect the others. Fa
|
|
|
1514
1780
|
swallowed — the reason appears in the header, because a silent drop leaves "why is that tool
|
|
1515
1781
|
missing?" unanswerable.
|
|
1516
1782
|
|
|
1783
|
+
</details>
|
|
1784
|
+
|
|
1785
|
+
---
|
|
1786
|
+
|
|
1787
|
+
## Inside your editor (ACP)
|
|
1788
|
+
|
|
1789
|
+
A tool that makes you open one more terminal window stops being used after about two weeks.
|
|
1790
|
+
Developers live inside the IDE. So deel speaks **ACP** (Agent Client Protocol) — Zed,
|
|
1791
|
+
JetBrains, Neovim and Emacs attach to it **without changing a line on their side**.
|
|
1792
|
+
|
|
1793
|
+
One command in your editor's settings:
|
|
1794
|
+
|
|
1795
|
+
```
|
|
1796
|
+
deel acp
|
|
1797
|
+
```
|
|
1798
|
+
|
|
1799
|
+
The editor spawns that as a child process and exchanges newline-delimited JSON-RPC 2.0 over
|
|
1800
|
+
stdio. It is not a command you type yourself.
|
|
1801
|
+
|
|
1802
|
+
**What you get once it is attached:**
|
|
1803
|
+
|
|
1804
|
+
| In the editor | From deel |
|
|
1805
|
+
|---|---|
|
|
1806
|
+
| Streaming reply pane | The model's text and its reasoning |
|
|
1807
|
+
| Tool list with icons and status | `Read` is a read, `Edit` is an edit, `Bash` is an execution — **the kind is sent**, not just a name |
|
|
1808
|
+
| Clickable file links | The **absolute path** of every file touched |
|
|
1809
|
+
| Approval dialog | deel's safety rails, rendered as the editor's own prompt (`allow once` · `always allow` · `reject`) |
|
|
1810
|
+
| Mode picker | deel's seven work modes (auto · code · plan · architect · debug · ask · orchestrator) |
|
|
1811
|
+
| Stop button | Reaches the turn mid-flight, even while waiting on the model |
|
|
1812
|
+
|
|
1813
|
+
**Still zero dependencies.** Same reason as MCP — newline-delimited JSON-RPC 2.0 is the whole
|
|
1814
|
+
transport, so no SDK is needed.
|
|
1815
|
+
|
|
1816
|
+
<details>
|
|
1817
|
+
<summary><b>Details</b> — the places this breaks silently</summary>
|
|
1818
|
+
|
|
1819
|
+
This protocol fails quietly. The editor shows "the agent is not responding" and nothing
|
|
1820
|
+
anywhere explains why. So these are nailed down by tests (`test/acp.test.js` spawns a real
|
|
1821
|
+
process and talks over a real pipe).
|
|
1822
|
+
|
|
1823
|
+
| The place | Why it matters |
|
|
1824
|
+
|---|---|
|
|
1825
|
+
| **Nothing but ACP on stdout** | The spec says `MUST NOT`. deel has dozens of places that print to the screen; one of them firing in this mode breaks the pipe. Rather than guarding each call site, **the pipe itself is swapped out** — so code written later is safe without knowing about this. What gets printed is not dropped, it goes to stderr |
|
|
1826
|
+
| **Korean split across chunk boundaries** | Pipes break on bytes, not characters. Decoding each chunk separately turns `안녕` into `안<?>하` — and **the JSON still parses**, so no error is raised. The characters are quietly mangled |
|
|
1827
|
+
| **A request with `id: 0`** | ACP clients count from zero. Reading `if (msg.id)` treats the very first `initialize` as a notification and never answers — it hangs the moment it connects |
|
|
1828
|
+
| **Cancellation reaching a running turn** | Cancellation always arrives while something is running; that is what cancellation is. Awaiting each incoming line in order means it **never arrives** |
|
|
1829
|
+
| **When permission cannot be asked** | It is tempting to just run the tool — otherwise nothing works against a client that has not built the approval dialog yet. But that means "if I can't ask, I do as I please". **It does not** |
|
|
1830
|
+
|
|
1831
|
+
**What it does not do yet, stated plainly:**
|
|
1832
|
+
|
|
1833
|
+
| | |
|
|
1834
|
+
|---|---|
|
|
1835
|
+
| `session/load` | Restoring a past conversation means replaying every message as an update. Half-built, the editor opens an empty conversation and the user assumes the history is gone. It reports **`loadSession: false`** |
|
|
1836
|
+
| Image / audio attachments | Most local models cannot read them. Rather than dropping them silently, deel tells the model what it could not read |
|
|
1837
|
+
| MCP servers passed in by the editor | Not launched. That would mean **deel spawning processes named in the editor's config**. "What does this tool launch?" is the first question in a corporate review, and "whatever the editor says" is not an acceptable answer. Only `.deel/mcp.json`, written by a person, is launched |
|
|
1838
|
+
|
|
1839
|
+
</details>
|
|
1840
|
+
|
|
1841
|
+
---
|
|
1842
|
+
|
|
1843
|
+
## Keeping secrets out of the conversation
|
|
1844
|
+
|
|
1845
|
+
People rarely paste a key. The leak is almost always **command output**.
|
|
1846
|
+
|
|
1847
|
+
```
|
|
1848
|
+
env OPENAI_API_KEY=sk-proj-…
|
|
1849
|
+
git remote -v https://user:token@github.com/…
|
|
1850
|
+
curl -v > Authorization: Bearer eyJ…
|
|
1851
|
+
a failing test log the whole connection string
|
|
1852
|
+
```
|
|
1853
|
+
|
|
1854
|
+
That text goes to the model **and** gets written to `.deel/sessions/*.jsonl` on disk. That
|
|
1855
|
+
file is later re-read by `/recall` and can end up inside a `deel pack` bundle. Leak once and
|
|
1856
|
+
you have several copies.
|
|
1857
|
+
|
|
1858
|
+
So it is masked at the single point where tool output enters the conversation.
|
|
1859
|
+
|
|
1860
|
+
```
|
|
1861
|
+
⏺ Bash(env | grep API) done
|
|
1862
|
+
⊘ 2 secret-looking values entered the conversation (openai · env var) — masked before the model
|
|
1863
|
+
```
|
|
1864
|
+
|
|
1865
|
+
What it looks for: private-key blocks · OpenAI/Anthropic keys · GitHub tokens · Slack tokens ·
|
|
1866
|
+
AWS keys · Google keys · JWTs · credentials embedded in URLs · `Authorization`-family headers ·
|
|
1867
|
+
env vars named `…KEY` / `…TOKEN` / `…SECRET` / `…PASSWORD`. Plus **the configured gateway key
|
|
1868
|
+
regardless of its shape** — that one is not a guess, it is a known value.
|
|
1869
|
+
|
|
1870
|
+
### File contents are deliberately not masked
|
|
1871
|
+
|
|
1872
|
+
`.env` is exactly where masking feels most tempting, and exactly where it backfires: the model
|
|
1873
|
+
sees the masked text, edits it, writes it back — and `«가림»` lands where the real key was.
|
|
1874
|
+
**Protecting the secret would destroy it.**
|
|
1875
|
+
|
|
1876
|
+
So on the file side it reports instead of rewriting.
|
|
1877
|
+
|
|
1878
|
+
```
|
|
1879
|
+
⏺ Read(.env) 12 lines
|
|
1880
|
+
! 3 secret-looking values entered the conversation (env var)
|
|
1881
|
+
— file contents are not masked (masking them would erase the key on write-back)
|
|
1882
|
+
```
|
|
1883
|
+
|
|
1884
|
+
Saying plainly what cannot be stopped beats claiming it was stopped while corrupting the file.
|
|
1885
|
+
Either way it lands in the audit log.
|
|
1886
|
+
|
|
1517
1887
|
---
|
|
1518
1888
|
|
|
1519
1889
|
## Safety
|
|
@@ -1543,6 +1913,9 @@ Undo history stores whole file contents, so repeated edits to large files add up
|
|
|
1543
1913
|
it keeps the **most recent 50 turns** and drops the rest. What you just did is always
|
|
1544
1914
|
undoable; `/status` shows how large the history currently is.
|
|
1545
1915
|
|
|
1916
|
+
<details>
|
|
1917
|
+
<summary><b>More</b> — Files removed through Bash come back too · What it will not read</summary>
|
|
1918
|
+
|
|
1546
1919
|
### Files removed through `Bash` come back too
|
|
1547
1920
|
|
|
1548
1921
|
The safety net covered `Write` and `Edit` only. But a model moving a file reaches for
|
|
@@ -1611,6 +1984,8 @@ the read guard look at the same set. They used to be two copies, and two copies
|
|
|
1611
1984
|
comes when only one of them learns a new name — a folder that is skipped while walking but
|
|
1612
1985
|
readable if you name it directly, which is very hard to explain.
|
|
1613
1986
|
|
|
1987
|
+
</details>
|
|
1988
|
+
|
|
1614
1989
|
---
|
|
1615
1990
|
|
|
1616
1991
|
## Corporate review package
|
|
@@ -1621,25 +1996,39 @@ deel pack --out deel-import.zip
|
|
|
1621
1996
|
|
|
1622
1997
|
```
|
|
1623
1998
|
✓ deel-import.zip
|
|
1624
|
-
|
|
1999
|
+
94 files · 509.6KB
|
|
1625
2000
|
|
|
1626
2001
|
Dependencies 0
|
|
1627
2002
|
Install scripts none
|
|
1628
2003
|
External imports 0
|
|
1629
2004
|
Network calls 3 sites (configured address only)
|
|
1630
|
-
Ports opened
|
|
2005
|
+
Ports opened 1 site (/preview only)
|
|
1631
2006
|
```
|
|
1632
2007
|
|
|
1633
|
-
The
|
|
2008
|
+
The zip carries **one document for people and two for machines.** A corporate review is
|
|
2009
|
+
not a human-only process — security feeds an SBOM to a scanner, and operations reads the
|
|
2010
|
+
audit-log spec to write SIEM ingestion rules.
|
|
2011
|
+
|
|
2012
|
+
| File | What |
|
|
2013
|
+
|---|---|
|
|
2014
|
+
| `반입심사서.txt` | Dependencies · install scripts · **every network and process-spawn call site found by scanning the source** (file:line) · the three outbound lanes · SHA-256 per file |
|
|
2015
|
+
| `sbom.cdx.json` | **SBOM (CycloneDX 1.5).** Feed it straight to a scanner. One component per file with SHA-256; dependencies stated as an **explicit empty array** — "not declared" and "none" are different claims |
|
|
2016
|
+
| `심사명세.json` | Egress list (per lane: when, where, what, how it's stopped, and the source location) · **audit-log spec** (field names and meanings, plus what is never recorded) · file hashes |
|
|
2017
|
+
|
|
2018
|
+
```bash
|
|
2019
|
+
deel audit # the human-readable sheet only
|
|
2020
|
+
deel sbom # the two machine-readable ones, on stdout (deel sbom | jq)
|
|
2021
|
+
deel sbom --out review.json # to a file
|
|
2022
|
+
deel sbom --only sbom # just the SBOM
|
|
2023
|
+
```
|
|
1634
2024
|
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
- SHA-256 per file (verify with `certutil -hashfile`)
|
|
2025
|
+
All three are generated by scanning the source, never written by hand — hand-written sheets
|
|
2026
|
+
drift, and **a review document that drifts is worse than none.** Find one wrong line and the
|
|
2027
|
+
reviewer stops trusting the rest. The audit-log spec is the one hand-written part, so a test
|
|
2028
|
+
checks it against real log records on every run.
|
|
1640
2029
|
|
|
1641
|
-
|
|
1642
|
-
|
|
2030
|
+
<details>
|
|
2031
|
+
<summary><b>More</b> — Diagnosing a corporate gateway</summary>
|
|
1643
2032
|
|
|
1644
2033
|
### Diagnosing a corporate gateway
|
|
1645
2034
|
|
|
@@ -1662,12 +2051,17 @@ Hand over `report.txt` alone — plain text, no colour codes.
|
|
|
1662
2051
|
|
|
1663
2052
|
Verdict is one of **ready · limited · blocked · unreachable**.
|
|
1664
2053
|
|
|
2054
|
+
</details>
|
|
2055
|
+
|
|
1665
2056
|
---
|
|
1666
2057
|
|
|
1667
2058
|
## Configuration
|
|
1668
2059
|
|
|
1669
2060
|
Stored in `~/.deel/config.json`. A `.deel/config.json` in the project folder takes precedence.
|
|
1670
2061
|
|
|
2062
|
+
<details>
|
|
2063
|
+
<summary><b>More</b> — Supported servers · Environment variables · Flags · Project rules</summary>
|
|
2064
|
+
|
|
1671
2065
|
### Supported servers
|
|
1672
2066
|
|
|
1673
2067
|
| | Example address |
|
|
@@ -1712,6 +2106,8 @@ deel --no-tui Turn the input box off; plain scrolling view (see below
|
|
|
1712
2106
|
If the working folder has `DEEL.md`, `CLAUDE.md` or `AGENTS.md`, it is loaded as project rules.
|
|
1713
2107
|
`/init` scaffolds one.
|
|
1714
2108
|
|
|
2109
|
+
</details>
|
|
2110
|
+
|
|
1715
2111
|
---
|
|
1716
2112
|
|
|
1717
2113
|
## Troubleshooting
|
|
@@ -1777,6 +2173,9 @@ so one run tells you everything.
|
|
|
1777
2173
|
| `no-bundle` | 12 | Nothing foreign in the published package; test-file hygiene |
|
|
1778
2174
|
| `edit-bench` | 20 cases | Edit success rate |
|
|
1779
2175
|
|
|
2176
|
+
<details>
|
|
2177
|
+
<summary><b>More</b> — Coverage · Layout</summary>
|
|
2178
|
+
|
|
1780
2179
|
### Coverage
|
|
1781
2180
|
|
|
1782
2181
|
```bash
|
|
@@ -1797,6 +2196,414 @@ Currently **92% overall** (7,056 of 7,646 lines). Three files are deliberately l
|
|
|
1797
2196
|
| `repl.js` | 77% | The keypress paths — Shift+Tab, Ctrl+C, password entry, paste. Reaching them needs a pty, and a pty is a dependency. What the screen *prints* is measured instead, as a value (`ui` and `tui` suites) |
|
|
1798
2197
|
| `plugins/manage.js` | 79% | The GitHub download path. **Tests not reaching the network** matters more. Folder installs are covered |
|
|
1799
2198
|
|
|
2199
|
+
### Layout
|
|
2200
|
+
|
|
2201
|
+
```
|
|
2202
|
+
bin/deel.js entry point
|
|
2203
|
+
src/
|
|
2204
|
+
repl.js the conversation screen — what a person faces
|
|
2205
|
+
oneshot.js run once and exit (-p)
|
|
2206
|
+
commands.js 35 slash commands
|
|
2207
|
+
setup.js first-run connection setup
|
|
2208
|
+
config.js reading and writing config
|
|
2209
|
+
|
|
2210
|
+
ui/ansi.js colour · East Asian width
|
|
2211
|
+
ui/screen.js picking a screen (line mode / box mode)
|
|
2212
|
+
ui/inputbox.js the box at the bottom — overwrite-in-place, cursor position
|
|
2213
|
+
ui/status.js status line — model, context, mode, approvals
|
|
2214
|
+
ui/working.js working phrases — they follow what is happening
|
|
2215
|
+
ui/motion.js the braille drawing next to the phrase
|
|
2216
|
+
ui/approve.js approval mode display (auto / risky only / everything)
|
|
2217
|
+
ui/diff.js showing what changed, where it changed
|
|
2218
|
+
ui/wrap.js wrapping to width without breaking colour
|
|
2219
|
+
ui/level.js simple vs developer
|
|
2220
|
+
|
|
2221
|
+
agent/loop.js the agent loop
|
|
2222
|
+
agent/session.js conversation state + context accounting
|
|
2223
|
+
agent/modes.js work modes (auto · code · plan · architect · debug · ask · orchestrator)
|
|
2224
|
+
agent/route.js picking the mode from what was said
|
|
2225
|
+
agent/effort.js per-stage reasoning effort
|
|
2226
|
+
agent/budget.js shares that follow the window — lines read, description length, steps
|
|
2227
|
+
agent/project.js working out what kind of project this folder is
|
|
2228
|
+
agent/compact.js summarising compaction
|
|
2229
|
+
agent/store.js saving and resuming conversations
|
|
2230
|
+
agent/recall.js searching past conversations (no index, within budget)
|
|
2231
|
+
agent/memory.js what outlives the conversation
|
|
2232
|
+
agent/mention.js attaching files with `@`
|
|
2233
|
+
|
|
2234
|
+
backend/http.js the single HTTP layer (the only door out)
|
|
2235
|
+
backend/detect.js protocol and auth detection
|
|
2236
|
+
backend/adapter.js absorbing OpenAI/Ollama differences + streaming parser
|
|
2237
|
+
backend/ctxsize.js reading context length off the model
|
|
2238
|
+
backend/probe.js 8 diagnostic checks
|
|
2239
|
+
backend/scan.js scanning for local servers
|
|
2240
|
+
backend/mcp.js attaching outside tools (MCP, stdio)
|
|
2241
|
+
|
|
2242
|
+
tools/index.js 17 tools
|
|
2243
|
+
tools/edit-match.js staged-relaxation edit matching
|
|
2244
|
+
tools/outline.js a file's shape, cheaply
|
|
2245
|
+
tools/verify.js checking what was built
|
|
2246
|
+
tools/task.js splitting big work off
|
|
2247
|
+
tools/jobs.js commands that run in the background
|
|
2248
|
+
tools/todo.js checklists
|
|
2249
|
+
tools/webfetch.js reading the web (read-only)
|
|
2250
|
+
tools/encoding.js writing back in the encoding it was read in
|
|
2251
|
+
tools/xlsx.js Excel → CSV (written here)
|
|
2252
|
+
tools/lsp.js Def · Refs — asking the language server
|
|
2253
|
+
|
|
2254
|
+
lsp/rpc.js LSP framing (Content-Length + JSON-RPC, written here)
|
|
2255
|
+
lsp/servers.js finding installed language servers (installs nothing)
|
|
2256
|
+
lsp/client.js one server: spawn, talk, time out, clean up
|
|
2257
|
+
lsp/diag.js is the file you just edited sound?
|
|
2258
|
+
|
|
2259
|
+
preview/serve.js serving what you built (127.0.0.1 only)
|
|
2260
|
+
skills/discover.js finding skills, commands and plugins on the machine
|
|
2261
|
+
plugins/manage.js installing, removing and packing plugins
|
|
2262
|
+
pack/zip.js ZIP writing (written here, keeps non-ASCII names)
|
|
2263
|
+
pack/tar.js TAR reading (written here)
|
|
2264
|
+
pack/selfpack.js review dossier + source bundle
|
|
2265
|
+
|
|
2266
|
+
safety/network.js the lock on the way out
|
|
2267
|
+
safety/guard.js working scope + dangerous-command blocking
|
|
2268
|
+
safety/undo.js snapshots and undo
|
|
2269
|
+
safety/audit.js recording what happened, and when
|
|
2270
|
+
test/ tests (excluded from the published package)
|
|
2271
|
+
```
|
|
2272
|
+
|
|
2273
|
+
</details>
|
|
2274
|
+
|
|
2275
|
+
---
|
|
2276
|
+
|
|
2277
|
+
## Release notes
|
|
2278
|
+
|
|
2279
|
+
<details>
|
|
2280
|
+
<summary><b>▸ 1.4.0 — deel gets a face, speaks English, and sees meaning</b> · what changed in seven places</summary>
|
|
2281
|
+
|
|
2282
|
+
<br>
|
|
2283
|
+
|
|
2284
|
+
| | Before | After |
|
|
2285
|
+
|---|---|---|
|
|
2286
|
+
| `/undo` | rolled back files only — the conversation still believed it happened | rewinds **the conversation too** |
|
|
2287
|
+
| Turns that take minutes | you sat watching the screen | a bell and the window title — you can be in another window |
|
|
2288
|
+
| Startup · status bar | looked like any other CLI | letters that grow on start, a status bar that names the boundary |
|
|
2289
|
+
| English speakers | the screen was all unreadable | `/lang en` — the screen **and what the model reads** |
|
|
2290
|
+
| Models per session | one | a different model per chunk — routine work to a small one |
|
|
2291
|
+
| Finding a name | `Grep` only — comments and strings mixed in | `Def` / `Refs` — by **meaning**, when a server is installed |
|
|
2292
|
+
| A file you just edited | you found out by running it | checked **right after** the edit, that file only |
|
|
2293
|
+
|
|
2294
|
+
<br>
|
|
2295
|
+
|
|
2296
|
+
#### 1. `/undo` rewinds the conversation
|
|
2297
|
+
|
|
2298
|
+
Roll back only the files and the conversation still holds the edit. The model believes it
|
|
2299
|
+
just changed that file and builds the next step on top — and nothing on screen says
|
|
2300
|
+
otherwise. Now the messages fold back with the files. Folding can orphan a tool call, which
|
|
2301
|
+
the server answers with a 400, so the same `repairToolPairs` runs over the result.
|
|
2302
|
+
|
|
2303
|
+
#### 2. It tells you when it is done — `/bell`
|
|
2304
|
+
|
|
2305
|
+
A local model can take minutes per turn. A bell and the window title say when it finishes.
|
|
2306
|
+
The bell is ``, but **not one byte reaches a pipe** — with no TTY it writes nowhere. The
|
|
2307
|
+
title ends with ST, not BEL; ending with BEL rings the bell on every title update.
|
|
2308
|
+
|
|
2309
|
+
#### 3. A screen that is deel's own
|
|
2310
|
+
|
|
2311
|
+
On start, `deel` grows into `deel-local`. The status bar names the boundary you are inside
|
|
2312
|
+
with one glyph (`⌂` this folder · `↗` outside · `?` unknown). The animation uses braille and
|
|
2313
|
+
box-drawing only — emoji and geometric shapes are East Asian Ambiguous, so their width
|
|
2314
|
+
varies per terminal and the line drifts by a column.
|
|
2315
|
+
|
|
2316
|
+
#### 4·5. English on screen, and in what the model reads
|
|
2317
|
+
|
|
2318
|
+
`/lang en` switches the screen. Untranslated strings come through in Korean rather than as
|
|
2319
|
+
blanks, and `/lang` counts honestly how many are left.
|
|
2320
|
+
|
|
2321
|
+
But switching only the screen leaves the model answering in Korean — its rules say to. So
|
|
2322
|
+
what the model reads switches too (base rules, mode instructions, all sixteen tool
|
|
2323
|
+
descriptions). There is a bonus: Korean costs about one token per character and English
|
|
2324
|
+
about one per 3.6, so the fixed share of a 32k window dropped from **4,910 to 3,446 tokens.**
|
|
2325
|
+
|
|
2326
|
+
Tool names and argument names are **not** translated. Those are identifiers.
|
|
2327
|
+
|
|
2328
|
+
#### 6. Several models in one session — `Task`'s `모델`
|
|
2329
|
+
|
|
2330
|
+
A large model and a small one, together, on 8GB of RAM. Routine work (formatting, repetitive
|
|
2331
|
+
edits, short summaries) goes to the small one; you keep what needs judgement. The subtask's
|
|
2332
|
+
endpoint opens through `allowTemporarily` and **always closes in `finally`** — afterwards
|
|
2333
|
+
exactly one endpoint is open again.
|
|
2334
|
+
|
|
2335
|
+
#### 7. Language servers — `Def`, `Refs`, post-edit diagnostics
|
|
2336
|
+
|
|
2337
|
+
See "With a language server, it sees meaning" above. **It installs nothing.**
|
|
2338
|
+
|
|
2339
|
+
</details>
|
|
2340
|
+
|
|
2341
|
+
<details>
|
|
2342
|
+
<summary><b>▸ 1.3.0 — evidence instead of claims, the editor instead of a terminal</b> · what changed in six places</summary>
|
|
2343
|
+
|
|
2344
|
+
<br>
|
|
2345
|
+
|
|
2346
|
+
| | Before | After |
|
|
2347
|
+
|---|---|---|
|
|
2348
|
+
| Rules that must hold | **vanished** when folded or summarised | live outside the message list, where folding cannot reach |
|
|
2349
|
+
| This model's habits | the prompt **asked** it to behave | the harness changes instead — no cooperation needed |
|
|
2350
|
+
| Finishing | "all done" | what changed, and what proves it. **Including what doesn't** |
|
|
2351
|
+
| Where you use it | one more terminal window | inside your editor (Zed · JetBrains · Neovim · Emacs) |
|
|
2352
|
+
| Review paperwork | one document, for humans | SBOM · egress list · audit spec — **straight into a scanner** |
|
|
2353
|
+
| Keys | one `env` and they were in the conversation and on disk | masked where output enters. Files are **deliberately** left alone |
|
|
2354
|
+
|
|
2355
|
+
<br>
|
|
2356
|
+
|
|
2357
|
+
#### 1. Rules that must hold were vanishing into the fold — `/pin`
|
|
2358
|
+
|
|
2359
|
+
Long conversations fold and summarise earlier turns to make room. A 2026 measurement found
|
|
2360
|
+
**summarisation preserves only about 50% of safety constraints.** If "never touch this
|
|
2361
|
+
folder" lands in the missing half, the model is in a state where it was never told. Nothing
|
|
2362
|
+
appears on screen.
|
|
2363
|
+
|
|
2364
|
+
Pinned lines are **not kept with the messages.** They are appended to the end of the system
|
|
2365
|
+
prompt — and since folding and compaction only touch messages, they are structurally out of
|
|
2366
|
+
reach. Not carefully preserved: **impossible to remove.**
|
|
2367
|
+
|
|
2368
|
+
```
|
|
2369
|
+
/pin never touch src/legacy
|
|
2370
|
+
|
|
2371
|
+
✓ Pinned — 2 now (78 tokens)
|
|
2372
|
+
```
|
|
2373
|
+
|
|
2374
|
+
Up to 12 lines / 240 tokens. Past that it says so and carries the most recent — dropping
|
|
2375
|
+
them quietly would defeat the point of pinning.
|
|
2376
|
+
|
|
2377
|
+
#### 2. Observed habits stayed as words — `/model 카드`
|
|
2378
|
+
|
|
2379
|
+
deel already watched what the model did. But watching was all it did — it **wrote advice
|
|
2380
|
+
into the prompt**: "you keep truncating arguments, use Append." Small models don't follow
|
|
2381
|
+
that advice. That is what makes them small models.
|
|
2382
|
+
|
|
2383
|
+
Now what it observes becomes **harness settings**. Instead of asking the model, deel changes
|
|
2384
|
+
its own behaviour.
|
|
2385
|
+
|
|
2386
|
+
| Observed | What changes |
|
|
2387
|
+
|---|---|
|
|
2388
|
+
| Arguments truncate often (over 15%) | The cap is raised up front — no wasted first call |
|
|
2389
|
+
| It repeats itself | Three identical calls tolerated becomes two |
|
|
2390
|
+
| Edits miss often | More surrounding lines are shown on a near-miss |
|
|
2391
|
+
|
|
2392
|
+
**Nothing changes before 12 steps.** Pinning down a healthy model because of one unlucky
|
|
2393
|
+
truncation is worse than not learning at all.
|
|
2394
|
+
|
|
2395
|
+
#### 3. Evidence instead of "all done" — `/evidence`
|
|
2396
|
+
|
|
2397
|
+
A 2026 survey found **96% of developers don't fully trust AI-written code, while 48% verify
|
|
2398
|
+
it every time.** 38% said it is harder to review than human code.
|
|
2399
|
+
|
|
2400
|
+
Why harder? Ask a person why they wrote it that way and you get an answer. Agent-written
|
|
2401
|
+
code arrives with **one line: "done."** That line cannot be reviewed.
|
|
2402
|
+
|
|
2403
|
+
```
|
|
2404
|
+
/evidence
|
|
2405
|
+
|
|
2406
|
+
Changed 3 files · +142 −38
|
|
2407
|
+
Ran 5 commands (1 failed)
|
|
2408
|
+
Unproven 1
|
|
2409
|
+
|
|
2410
|
+
✗ src/worker.js — the last `npm test` failed — an earlier pass
|
|
2411
|
+
does not prove the current state.
|
|
2412
|
+
```
|
|
2413
|
+
|
|
2414
|
+
Listing what changed is something `/diff` already does. What only this does is **say that
|
|
2415
|
+
the unproven is unproven.** Three things get caught —
|
|
2416
|
+
|
|
2417
|
+
- Changed something and ran nothing? Nothing was proven
|
|
2418
|
+
- Counting a red test as green means **offering a failing test as evidence**
|
|
2419
|
+
- A check run *before* the edit proves nothing about it — "I ran it earlier" is the most
|
|
2420
|
+
common form of self-deception
|
|
2421
|
+
|
|
2422
|
+
If the build passed and the tests broke *after* it, the earlier green is not evidence. The
|
|
2423
|
+
last thing you ran is red; it cannot have been verified.
|
|
2424
|
+
|
|
2425
|
+
`/evidence filename` writes it as markdown under `.deel/증거/`. The screen scrolls away, and
|
|
2426
|
+
the review happens later, by someone else.
|
|
2427
|
+
|
|
2428
|
+
#### 4. It made you open one more terminal — `deel acp`
|
|
2429
|
+
|
|
2430
|
+
Developers live inside the IDE. A tool that makes you switch windows stops being used after
|
|
2431
|
+
about two weeks. A build that cleared corporate review and then nobody uses is the saddest
|
|
2432
|
+
possible outcome.
|
|
2433
|
+
|
|
2434
|
+
deel now speaks **ACP** (Agent Client Protocol). One line — `deel acp` — in your editor's
|
|
2435
|
+
settings and Zed, JetBrains, Neovim and Emacs attach **without changing a line on their side**.
|
|
2436
|
+
|
|
2437
|
+
The work isn't connecting the pipe; it is **making the editor able to show something**.
|
|
2438
|
+
Kind, location and status are all optional in the spec, so a quick implementation omits all
|
|
2439
|
+
three — and then every tool is the same grey dot and no changed file is clickable.
|
|
2440
|
+
|
|
2441
|
+
Approval flows through too. deel's safety rails render as the editor's own dialog, and
|
|
2442
|
+
"always allow" is remembered for that session. Against a client that cannot ask, it
|
|
2443
|
+
**does not run** — "if I can't ask, I do as I please" is not an option.
|
|
2444
|
+
|
|
2445
|
+
**Still zero dependencies.** Newline-delimited JSON-RPC 2.0 is the whole transport, so no SDK.
|
|
2446
|
+
|
|
2447
|
+
#### 5. Review paperwork only a human could read — `deel sbom`
|
|
2448
|
+
|
|
2449
|
+
A Korean financial-sector rule change on 2026-04-20 opened an exemption to the network-
|
|
2450
|
+
separation mandate. The paperwork demanded at that door is not prose — security feeds an
|
|
2451
|
+
**SBOM to a scanner** for a vulnerability list, and operations reads the audit-log spec to
|
|
2452
|
+
write SIEM ingestion rules.
|
|
2453
|
+
|
|
2454
|
+
`deel pack` now emits three documents.
|
|
2455
|
+
|
|
2456
|
+
| | |
|
|
2457
|
+
|---|---|
|
|
2458
|
+
| `반입심사서.txt` | The human-readable sheet, as before |
|
|
2459
|
+
| `sbom.cdx.json` | CycloneDX 1.5. One component per file with SHA-256. Dependencies as an **explicit empty array** — "not declared" and "none" are different claims |
|
|
2460
|
+
| `심사명세.json` | Egress list (per lane: when, where, what, how it's stopped, source location) · audit-log spec · file hashes |
|
|
2461
|
+
|
|
2462
|
+
All three are generated by scanning the source. The audit-log spec is the one hand-written
|
|
2463
|
+
part, so **a test compares it against real log records on every run** — a review document
|
|
2464
|
+
that drifts is worse than none, and one wrong line costs you the reviewer's trust in the rest.
|
|
2465
|
+
|
|
2466
|
+
#### 6. One `env` put your keys in the conversation and on disk
|
|
2467
|
+
|
|
2468
|
+
People rarely paste a key. The leak is almost always command output — `env`, `git remote -v`,
|
|
2469
|
+
`curl -v`, a failing test log. That text goes to the model **and** is written to
|
|
2470
|
+
`.deel/sessions/*.jsonl`. Leak once, and you have several copies.
|
|
2471
|
+
|
|
2472
|
+
Masking now happens at the single point where tool output enters the conversation:
|
|
2473
|
+
private-key blocks, OpenAI, Anthropic, GitHub, Slack, AWS, Google, JWTs, credentials in URLs,
|
|
2474
|
+
`Authorization`-family headers, and env vars named `…KEY` / `…TOKEN` / `…SECRET` /
|
|
2475
|
+
`…PASSWORD`. The configured gateway key is removed regardless of shape — that one is a known
|
|
2476
|
+
value, not a guess.
|
|
2477
|
+
|
|
2478
|
+
**File contents are deliberately not masked.** Mask `.env` and the model edits the masked text
|
|
2479
|
+
and writes it back, landing a placeholder where the real key was — protecting the secret would
|
|
2480
|
+
destroy it. So on the file side it reports instead of rewriting.
|
|
2481
|
+
|
|
2482
|
+
<br>
|
|
2483
|
+
|
|
2484
|
+
Tests 2,578 → **2,860** · 54/54 files. Earlier releases are on the [tags](https://github.com/jysvai/deel-local-cli/tags) page.
|
|
2485
|
+
|
|
2486
|
+
</details>
|
|
2487
|
+
|
|
2488
|
+
<details>
|
|
2489
|
+
<summary><b>▸ 1.2.0 — so the conversation doesn't break</b> · what changed in six places</summary>
|
|
2490
|
+
|
|
2491
|
+
<br>
|
|
2492
|
+
|
|
2493
|
+
| | Before | After |
|
|
2494
|
+
|---|---|---|
|
|
2495
|
+
| Resuming | a conversation cut mid-tool-call **would not reopen** | unmatched calls are cleared, then it opens |
|
|
2496
|
+
| Counting tokens | it guessed, and stayed wrong | it corrects itself against the server |
|
|
2497
|
+
| Making room | summarising arrived at turn 49 | it holds out to turn **102** |
|
|
2498
|
+
| Side questions | piled up in the main context | live in their own thread |
|
|
2499
|
+
| Yesterday's lesson | vanished when you quit | carries over to the next session |
|
|
2500
|
+
| The answer on screen | `**bold**` showed up as characters | it is drawn |
|
|
2501
|
+
|
|
2502
|
+
<br>
|
|
2503
|
+
|
|
2504
|
+
#### 1. A conversation cut mid-tool-call would not reopen
|
|
2505
|
+
|
|
2506
|
+
Close the window or hit <kbd>Ctrl</kbd>+<kbd>C</kbd> while a tool is running and the saved conversation keeps **a call with no result under it**. Reopen it with `--resume` and the server rejects the mismatch with a 400 — the conversation was written down perfectly well, and you still could not carry on.
|
|
2507
|
+
|
|
2508
|
+
Now the pairs are checked before it opens. Calls with no result go, results with no parent go, and **whatever the model said stays.**
|
|
2509
|
+
|
|
2510
|
+
```
|
|
2511
|
+
$ deel --resume 20260826-140217
|
|
2512
|
+
|
|
2513
|
+
✓ 20260826-140217 — 메시지 48개를 이어 받았습니다.
|
|
2514
|
+
중단된 도구 호출 2개를 걷어냈습니다 — 그때 하던 일은 다시 시켜 주세요.
|
|
2515
|
+
```
|
|
2516
|
+
|
|
2517
|
+
#### 2. It misjudged the room left
|
|
2518
|
+
|
|
2519
|
+
Token counts are estimated from character counts. Mix Korean, code and JSON and that estimate drifts from the truth — so deel folded early with room to spare, or did not fold when there was none and the server refused.
|
|
2520
|
+
|
|
2521
|
+
It now **corrects the multiplier against what the server actually reports** with every answer. One line at the foot of `/context`:
|
|
2522
|
+
|
|
2523
|
+
```
|
|
2524
|
+
서버가 알려 준 실제값에 맞춰 +12% 보정했습니다 (7번 재봄).
|
|
2525
|
+
```
|
|
2526
|
+
|
|
2527
|
+
The multiplier is kept per model, so **the next session starts from it** instead of measuring again from scratch.
|
|
2528
|
+
|
|
2529
|
+
#### 3. Summarising arrived too early
|
|
2530
|
+
|
|
2531
|
+
At 80% of the window, earlier turns get folded into a summary. That **cannot be undone**, and the file contents the reasoning rested on are gone with it.
|
|
2532
|
+
|
|
2533
|
+
There is now a step before it. At 55%, **only older tool results** are folded — the four most recent are left alone, and nothing the model or you said is touched at all.
|
|
2534
|
+
|
|
2535
|
+
```
|
|
2536
|
+
◲ 오래된 도구 결과 6개를 접었습니다 (2,148 토큰을 비움)
|
|
2537
|
+
```
|
|
2538
|
+
|
|
2539
|
+
What was there is left in its place:
|
|
2540
|
+
|
|
2541
|
+
```
|
|
2542
|
+
(접힘) Read(src/runner.js) — 61줄. 자리를 비우려고 내용을 접었습니다. 필요하면 다시 읽으세요.
|
|
2543
|
+
```
|
|
2544
|
+
|
|
2545
|
+
Measured by streaming the same conversation through: summarising is pushed from **turn 49 to turn 102 — 2.1×**.
|
|
2546
|
+
|
|
2547
|
+
#### 4. Side questions polluted the main line
|
|
2548
|
+
|
|
2549
|
+
"Just check this one thing" piles into the main context and stays there long after the checking is done.
|
|
2550
|
+
|
|
2551
|
+
```
|
|
2552
|
+
/thread new 로그확인
|
|
2553
|
+
⑂ 로그확인 갈래로 왔습니다. 빈 대화입니다
|
|
2554
|
+
본줄기로 돌아가려면 /thread 1
|
|
2555
|
+
```
|
|
2556
|
+
|
|
2557
|
+
`fork` carries the conversation so far with you. What threads **keep apart is the messages, the token count and the checklist**; what they **share is the connection, undo and the audit log** — a file changed inside a thread still comes back with `/undo`. The `⑂` marker appears in the status line only once there is more than one thread.
|
|
2558
|
+
|
|
2559
|
+
#### 5. Yesterday's lesson vanished when you quit
|
|
2560
|
+
|
|
2561
|
+
deel could work out that `pnpm` is not on this machine, and lose it the moment you quit. Tomorrow it calls it again, fails again, works around it again.
|
|
2562
|
+
|
|
2563
|
+
```
|
|
2564
|
+
/learned
|
|
2565
|
+
── 겪어 본 것 ──────────────────────────────────────
|
|
2566
|
+
|
|
2567
|
+
이 폴더에서 돌려 본 명령
|
|
2568
|
+
✓ npm test 됨 12 · 안 됨 0
|
|
2569
|
+
✗ pnpm 됨 0 · 안 됨 3
|
|
2570
|
+
|
|
2571
|
+
이 모델에 대해 qwen2.5-coder:7b
|
|
2572
|
+
같이 걸어 본 걸음 86
|
|
2573
|
+
인자가 잘림 14 (16%)
|
|
2574
|
+
토큰 추정 보정 ×1.12
|
|
2575
|
+
|
|
2576
|
+
이 중 프롬프트에 실리는 것
|
|
2577
|
+
- 여기서 되는 명령: `npm test`
|
|
2578
|
+
- 이 PC 에서 안 되는 명령(다시 부르지 마라): `pnpm`
|
|
2579
|
+
```
|
|
2580
|
+
|
|
2581
|
+
**This is not training.** It does not touch the model and it does not hoard conversations — that would only eat context. It counts, and it carries over **only what it has seen twice**, all of it **within 220 tokens**. Something seen once may be a coincidence, and writing a coincidence down as fact sends the model around a road that actually works.
|
|
2582
|
+
|
|
2583
|
+
Commands that work live with the folder (`.deel/배운것.json`); the model's habits live in the config folder. So **move the folder and what it learned about the model comes along.** `/learned 지우기` empties it whenever you want.
|
|
2584
|
+
|
|
2585
|
+
#### 6. The answer showed up as raw characters
|
|
2586
|
+
|
|
2587
|
+
The model speaks Markdown and the screen did not know it, so asterisks, backticks and hashes came through mixed into the prose. You had to re-read it in your head to see what was a heading and what was code.
|
|
2588
|
+
|
|
2589
|
+
```
|
|
2590
|
+
before after
|
|
2591
|
+
▌ ## 고친 것 ▌ ▍ 고친 것
|
|
2592
|
+
▌ **src/runner.js** 의 `console.log` ▌ src/runner.js 의 console.log
|
|
2593
|
+
▌ - [ ] 남은 것: `src/worker.js` ▌ ☐ 남은 것: src/worker.js
|
|
2594
|
+
▌ ```js ▌ ┌──────────────── js
|
|
2595
|
+
▌ log.info('시작', { id }) ▌ │ log.info('시작', { id })
|
|
2596
|
+
▌ |---|---| ▌ ┼────────┼─────────┼
|
|
2597
|
+
```
|
|
2598
|
+
|
|
2599
|
+
Answers arrive in fragments, so a line can only be drawn **once it ends**. But a whole paragraph on one line would leave the screen still for seconds — so once a line grows past the screen width, everything up to there is **streamed raw**. Looking alive comes before looking neat.
|
|
2600
|
+
|
|
2601
|
+
<br>
|
|
2602
|
+
|
|
2603
|
+
Tests 2,532 → **2,578** · 48/48 files. Earlier releases are in the [tags](https://github.com/jysvai/deel-local-cli/tags).
|
|
2604
|
+
|
|
2605
|
+
</details>
|
|
2606
|
+
|
|
1800
2607
|
---
|
|
1801
2608
|
|
|
1802
2609
|
## Licence
|