deel-local-cli 1.2.0 → 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 +481 -12
- package/README.md +460 -12
- 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/card.js +110 -0
- package/src/agent/compact.js +10 -2
- package/src/agent/evidence.js +186 -0
- package/src/agent/grade.js +20 -0
- package/src/agent/loop.js +134 -13
- package/src/agent/models.js +169 -0
- package/src/agent/modes.js +47 -1
- package/src/agent/pins.js +140 -0
- package/src/agent/project.js +10 -4
- package/src/agent/session.js +214 -10
- package/src/agent/store.js +31 -0
- package/src/commands.js +586 -52
- 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 +19 -0
- package/src/pack/sbom.js +218 -0
- package/src/pack/selfpack.js +19 -3
- package/src/repl.js +193 -8
- package/src/safety/secrets.js +205 -0
- package/src/safety/undo.js +10 -3
- package/src/tools/desc.en.js +219 -0
- package/src/tools/index.js +148 -5
- package/src/tools/lsp.js +327 -0
- package/src/tools/task.js +30 -2
- package/src/ui/ansi.js +36 -0
- package/src/ui/approve.js +25 -21
- package/src/ui/inputbox.js +37 -7
- package/src/ui/intro.js +174 -0
- package/src/ui/level.js +11 -5
- package/src/ui/notify.js +101 -0
- package/src/ui/status.js +177 -34
package/README.en.md
CHANGED
|
@@ -59,6 +59,8 @@ Zero dependencies · Node 20+ · Exactly one place your source can go
|
|
|
59
59
|
- [Auto-compaction](#auto-compaction)
|
|
60
60
|
- [Resuming a conversation](#resuming-a-conversation)
|
|
61
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)
|
|
62
64
|
- [Safety](#safety)
|
|
63
65
|
- [Corporate review package](#corporate-review-package)
|
|
64
66
|
- [Configuration](#configuration)
|
|
@@ -97,6 +99,29 @@ deel audit # full review sheet
|
|
|
97
99
|
|
|
98
100
|
## Quick start
|
|
99
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
|
+
|
|
100
125
|
### Install
|
|
101
126
|
|
|
102
127
|
```bash
|
|
@@ -351,6 +376,10 @@ Names follow Claude Code / Codex conventions.
|
|
|
351
376
|
| Command | What it does |
|
|
352
377
|
|---|---|
|
|
353
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 |
|
|
354
383
|
| `/context` | What is consuming the context window |
|
|
355
384
|
| `/ctx [auto\|number]` | Context **length** — re-read it off the model, or set it yourself |
|
|
356
385
|
| `/grade [small\|medium\|large\|auto]` | Model **grade** — how much it does on its own. A different axis from `/ctx` |
|
|
@@ -359,7 +388,10 @@ Names follow Claude Code / Codex conventions.
|
|
|
359
388
|
| `/clear` | Clear the conversation (keeps link and rules) |
|
|
360
389
|
| `/thread [new\|fork\|close\|n]` | Conversation threads — side work in its own context. Link and undo stay shared |
|
|
361
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** |
|
|
362
393
|
| `/model` | Switch connection / model |
|
|
394
|
+
| `/model 카드` | Model card — what this model has actually done here, and what deel changed because of it |
|
|
363
395
|
| `/think <level>` | Reasoning level (`off·low·medium·high·max`) |
|
|
364
396
|
| `/think 배분 <profile>` | Per-stage profile (`even·save·deep`) |
|
|
365
397
|
| `/think 자세히` | Stage table — which stage runs at which level and cap |
|
|
@@ -782,6 +814,8 @@ Names and arguments match Claude Code, so skills written for that convention wor
|
|
|
782
814
|
| `Verify` | Check that what was built **actually works** |
|
|
783
815
|
| `Task` | Run one chunk of a big job in a **separate context** |
|
|
784
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 |
|
|
785
819
|
|
|
786
820
|
Seven tools here are not in Claude Code — `Append`, `Recall`, `Remember`, `Outline`,
|
|
787
821
|
`Verify`, `Task`, `Jobs`. Each tool costs 150-400 tokens of schema on **every request**,
|
|
@@ -789,7 +823,7 @@ so a test stops you every time the list grows (`test/loop.test.js`). The last fo
|
|
|
789
823
|
their cost; here is why.
|
|
790
824
|
|
|
791
825
|
<details>
|
|
792
|
-
<summary><b>More</b> — Outline · Verify · Task · Commands that never finish and 9 more</summary>
|
|
826
|
+
<summary><b>More</b> — Outline · Verify · Task · Def · Refs · Commands that never finish and 9 more</summary>
|
|
793
827
|
|
|
794
828
|
### Seeing a project's shape cheaply — `Outline`
|
|
795
829
|
|
|
@@ -1181,6 +1215,113 @@ last edit did. That original state comes from the earliest undo snapshot.
|
|
|
1181
1215
|
`/diff` is **in the simple level's command list.** As long as `auto` edits without asking,
|
|
1182
1216
|
a beginner needs a way to see what changed more than anyone.
|
|
1183
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
|
+
|
|
1184
1325
|
</details>
|
|
1185
1326
|
|
|
1186
1327
|
---
|
|
@@ -1643,6 +1784,108 @@ missing?" unanswerable.
|
|
|
1643
1784
|
|
|
1644
1785
|
---
|
|
1645
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
|
+
|
|
1887
|
+
---
|
|
1888
|
+
|
|
1646
1889
|
## Safety
|
|
1647
1890
|
|
|
1648
1891
|
Instead of approval prompts, the design makes things **reversible**. The default `auto` mode
|
|
@@ -1753,25 +1996,36 @@ deel pack --out deel-import.zip
|
|
|
1753
1996
|
|
|
1754
1997
|
```
|
|
1755
1998
|
✓ deel-import.zip
|
|
1756
|
-
|
|
1999
|
+
94 files · 509.6KB
|
|
1757
2000
|
|
|
1758
2001
|
Dependencies 0
|
|
1759
2002
|
Install scripts none
|
|
1760
2003
|
External imports 0
|
|
1761
2004
|
Network calls 3 sites (configured address only)
|
|
1762
|
-
Ports opened
|
|
2005
|
+
Ports opened 1 site (/preview only)
|
|
1763
2006
|
```
|
|
1764
2007
|
|
|
1765
|
-
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.
|
|
1766
2011
|
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
-
|
|
1771
|
-
|
|
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 |
|
|
1772
2017
|
|
|
1773
|
-
|
|
1774
|
-
|
|
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
|
+
```
|
|
2024
|
+
|
|
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.
|
|
1775
2029
|
|
|
1776
2030
|
<details>
|
|
1777
2031
|
<summary><b>More</b> — Diagnosing a corporate gateway</summary>
|
|
@@ -1985,7 +2239,7 @@ src/
|
|
|
1985
2239
|
backend/scan.js scanning for local servers
|
|
1986
2240
|
backend/mcp.js attaching outside tools (MCP, stdio)
|
|
1987
2241
|
|
|
1988
|
-
tools/index.js
|
|
2242
|
+
tools/index.js 17 tools
|
|
1989
2243
|
tools/edit-match.js staged-relaxation edit matching
|
|
1990
2244
|
tools/outline.js a file's shape, cheaply
|
|
1991
2245
|
tools/verify.js checking what was built
|
|
@@ -1995,6 +2249,12 @@ src/
|
|
|
1995
2249
|
tools/webfetch.js reading the web (read-only)
|
|
1996
2250
|
tools/encoding.js writing back in the encoding it was read in
|
|
1997
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?
|
|
1998
2258
|
|
|
1999
2259
|
preview/serve.js serving what you built (127.0.0.1 only)
|
|
2000
2260
|
skills/discover.js finding skills, commands and plugins on the machine
|
|
@@ -2016,6 +2276,215 @@ test/ tests (excluded from the published package)
|
|
|
2016
2276
|
|
|
2017
2277
|
## Release notes
|
|
2018
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
|
+
|
|
2019
2488
|
<details>
|
|
2020
2489
|
<summary><b>▸ 1.2.0 — so the conversation doesn't break</b> · what changed in six places</summary>
|
|
2021
2490
|
|