deel-local-cli 0.5.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -1,246 +1,637 @@
1
- # deel-local-cli
1
+ <div align="center">
2
2
 
3
- A coding agent CLI that runs entirely on **local models or your own private gateway**.
4
- **Zero dependencies** — nothing but Node's own standard library.
3
+ # deel
5
4
 
6
- > The interface and source comments are in Korean. This file is the English guide.
5
+ **A coding-agent CLI that runs on local models and private gateways only**
7
6
 
8
- ---
7
+ Zero dependencies · Node 20+ · Exactly one place your source can go
8
+
9
+ [한국어](README.md) · [Corporate review](#corporate-review-package) · [Troubleshooting](#troubleshooting)
9
10
 
10
- ## Why zero dependencies
11
+ </div>
11
12
 
12
- This was built for an offline corporate network where installing third-party
13
- software requires review. `dependencies` is empty and stays empty — that fact is
14
- the argument you hand to a security team.
13
+ ---
15
14
 
16
15
  ```
17
- npm ls → no dependencies
18
- cat package.json "dependencies": {}
16
+ ╭──────────────────────────────────────────────────────────────╮
17
+ deel OpenAI-compatible │
18
+ │ │
19
+ │ Model qwen2.5-coder:7b (40k tokens) │
20
+ │ Sends to this machine 127.0.0.1:11434 ← nowhere else │
21
+ │ Link streaming · tools · reasoning control │
22
+ │ Folder C:\work\myproject │
23
+ │ This PC 337 skills · 127 commands · 42 plugins │
24
+ ╰──────────────────────────────────────────────────────────────╯
25
+
26
+ ▏myproject ▏qwen2.5-coder:7b ▏▰▰▱▱▱▱▱▱▱▱ 22% 28k/128k ▏◇ medium·save ▏auto
27
+ ❯ unify the logging style
28
+
29
+ ❊ Grep(console.log)
30
+ └ 1 file · 1 hit
31
+ ◧ Read(src/runner.js)
32
+ └ 5 lines
33
+ ◈ Edit(src/runner.js)
34
+ └ 1 spot
35
+
36
+ Unified log calls to the logger format. One change in runner.js.
37
+
38
+ ── 4.2s · 3 tools · ↑3,900 ↓180
19
39
  ```
20
40
 
21
- All you need is **Node 20+**. There is no `npm install` step.
41
+ ---
42
+
43
+ ## Contents
44
+
45
+ - [Why this exists](#why-this-exists)
46
+ - [Quick start](#quick-start)
47
+ - [Where your data can go](#where-your-data-can-go)
48
+ - [Multiple local runtimes](#multiple-local-runtimes)
49
+ - [Slash commands](#slash-commands)
50
+ - [Tools](#tools)
51
+ - [Skills and plugins](#skills-and-plugins)
52
+ - [Reasoning effort](#reasoning-effort)
53
+ - [Auto-compaction](#auto-compaction)
54
+ - [Resuming a conversation](#resuming-a-conversation)
55
+ - [Safety](#safety)
56
+ - [Corporate review package](#corporate-review-package)
57
+ - [Configuration](#configuration)
58
+ - [Troubleshooting](#troubleshooting)
59
+ - [Development](#development)
22
60
 
23
61
  ---
24
62
 
25
- ## Install
63
+ ## Why this exists
64
+
65
+ When a corporate security policy blocks **unapproved software**, most coding-agent tools are
66
+ unusable: hundreds of transitive dependencies, scripts that run at install time, and no
67
+ one-line answer to "where does it send my code?"
68
+
69
+ deel is built to pass that review.
70
+
71
+ | | deel |
72
+ |---|---|
73
+ | External dependencies | **0** — Node built-ins only |
74
+ | Install scripts | **none** — unzip and run |
75
+ | Where source can go | **one address** — the one you configured |
76
+ | Requirement | Node 20+ |
77
+
78
+ Verify it yourself:
26
79
 
27
80
  ```bash
28
- npm install -g deel-local-cli
29
- # or run without installing
30
- npx deel-local-cli setup
81
+ npm view deel-local-cli dependencies # {}
82
+ npm view deel-local-cli scripts # no install/postinstall
83
+ deel audit # full review sheet
31
84
  ```
32
85
 
33
- For an air-gapped machine, copy the folder across and run `node bin/deel.js`
34
- directly. Nothing is installed on the target machine.
35
-
36
86
  ---
37
87
 
38
- ## Connect
88
+ ## Quick start
89
+
90
+ ### Install
39
91
 
40
92
  ```bash
41
- deel setup
93
+ npm install -g deel-local-cli
42
94
  ```
43
95
 
44
- It asks for a name, base URL and API key, probes the endpoint, lists the models
45
- it found, and saves the profile to `~/.deel/config.json`.
96
+ Or skip installing entirely there is no `npm install` step:
46
97
 
47
- Point it at anything OpenAI-compatible:
98
+ ```bash
99
+ git clone https://github.com/jysvai/deel-local-cli
100
+ node deel-local-cli/bin/deel.js
101
+ ```
48
102
 
49
- | | Example URL |
50
- |---|---|
51
- | Private AI gateway | `https://ai-gw.example.corp/v1` |
52
- | Ollama | `http://localhost:11434` |
53
- | LM Studio | `http://localhost:1234/v1` |
54
- | vLLM / LiteLLM | `http://host:port/v1` |
103
+ > **Note** do not run `npm install` in your home directory. A `node_modules` there makes every
104
+ > later npm command scan it and report warnings about unrelated packages. Use `-g` or `npx`.
105
+
106
+ ### Point it at a model
107
+
108
+ Scan this machine and pick one:
55
109
 
56
- The auth style is detected automatically — `Authorization: Bearer`, `x-api-key`,
57
- `api-key` (Azure-style), or none.
110
+ ```bash
111
+ deel scan --pick
112
+ ```
58
113
 
59
- ### Keeping the key out of the config file
114
+ Or enter an address directly (use this for a corporate gateway):
60
115
 
61
116
  ```bash
62
- export DEEL_API_KEY=sk-xxxx # takes precedence over the file
63
- deel diagnose --url https://ai-gw.example.corp/v1 --model sec-llm-01
117
+ deel setup
64
118
  ```
65
119
 
66
- Other environment variables: `NODE_EXTRA_CA_CERTS` (corporate CA),
67
- `HTTPS_PROXY`, `DEEL_DEBUG=1` (full stack traces).
120
+ ### Start
121
+
122
+ Run `deel` in the folder you want to work in. **That folder becomes the scope — files outside it
123
+ cannot be read or written.**
124
+
125
+ ```bash
126
+ cd C:\work\myproject
127
+ deel
128
+ ```
68
129
 
69
130
  ---
70
131
 
71
- ## Diagnose a gateway
132
+ ## Where your data can go
133
+
134
+ A coding agent ships your whole source to a model. **The address is everything.**
135
+ Rather than promising in prose, the code enforces it: `src/safety/network.js` checks every request
136
+ and never builds one for an address that is not on the allow-list.
137
+
138
+ ```
139
+ [A] Model gateway ────── the only path your source travels
140
+ One address, set in `setup`. Switching models closes the previous one.
72
141
 
73
- Before trusting an endpoint, find out what it actually supports:
142
+ [B] Web read (WebFetch) receive-only
143
+ GET only, zero-byte body. Private/loopback addresses refused. Every visit logged.
144
+
145
+ [C] Plugin fetch ─────── open only while /plugin install runs
146
+ ```
147
+
148
+ Pass `--offline` and **both B and C are closed** — traffic stays on this machine.
74
149
 
75
150
  ```bash
76
- deel diagnose --url <base-url> --key <key> --model <model> --out report.txt
151
+ deel --offline
77
152
  ```
78
153
 
79
- | Check | Why it matters |
80
- |---|---|
81
- | Basic chat | URL, key and model name are right |
82
- | System message | Whether rules and skills take effect |
83
- | Streaming | Whether output can arrive token by token |
84
- | **Tool calling** | **Whether files can be read and edited — the critical one** |
85
- | **Tool result round-trip** | **Whether multi-turn works — the agent loop depends on it** |
86
- | Structured output | Whether edit formats can be schema-enforced |
87
- | Reasoning effort | Whether `/think` reaches the model |
88
- | Context length | How many files fit at once |
154
+ The destination is printed at the top of every session:
89
155
 
90
- It ends with a verdict: **ready / limited / blocked / unreachable**, plus a
91
- plain-text report you can hand to whoever runs the gateway.
156
+ ```
157
+ Sends to this machine 127.0.0.1:11434 ← nowhere else
158
+ ```
92
159
 
93
- Reasoning models are handled correctly: if all output lands in `thinking` and
94
- the body gets truncated, it retries with thinking disabled instead of reporting
95
- a false failure.
160
+ Nothing is collected or transmitted. No telemetry, no usage stats, no crash reporting.
161
+ Conversation history, undo snapshots and config live only in `.deel/` inside your working folder.
162
+
163
+ > Verified by 55 checks in `npm test` (network + web), including bringing up a real server and
164
+ > confirming that **not a single request reaches it** when it is not allow-listed.
96
165
 
97
166
  ---
98
167
 
99
- ## Chat
168
+ ## Multiple local runtimes
100
169
 
101
- Run it inside the folder you want to work in. That folder becomes the **scope** —
102
- nothing outside it can be read or written, even if the model asks.
170
+ People rarely run just one. `deel scan` knocks on 13 known ports concurrently and identifies
171
+ each runtime from its **response**, not its port number Ollama by `/api/version`,
172
+ LM Studio by `/api/v0/models`, llama.cpp by `/props`. Unrecognised ones are marked as a guess.
103
173
 
104
174
  ```
105
- deel sec-llm-01 · /home/you/project
106
- skills: 337 · commands: 127 (42 plugins)
175
+ $ deel scan
107
176
 
108
- unify the log format
177
+ found 3
109
178
 
110
- Grep(console.log)
111
- 1 file · 1 match
179
+ Ollama 127.0.0.1:11434 Ollama API 36ms
180
+ · qwen2.5-coder:7b 7B · 4.4GB
181
+ · llama3.2:1b 1B · 1.2GB
182
+ ◆ LM Studio 127.0.0.1:1234 OpenAI-compat 7ms
183
+ · devstral-small-2507
184
+ ◆ llama.cpp 127.0.0.1:8080 OpenAI-compat 7ms
185
+ · gemma-3-4b-it
112
186
 
113
- Read(src/runner.js)
114
- └ 5 lines
187
+ Recommended Ollama · qwen2.5-coder:7b
188
+ ```
115
189
 
116
- Edit(src/runner.js)
117
- └ 1 occurrence
190
+ | Command | What it does |
191
+ |---|---|
192
+ | `deel scan` | Show what is running |
193
+ | `deel scan --pick` | Choose one from the list |
194
+ | `deel scan --save` | Register everything found |
195
+ | `deel scan --ports 9000,9100` | Extra ports to probe |
196
+ | `deel scan --host <addr>` | Defaults to `127.0.0.1` |
118
197
 
119
- Unified the log calls to the logger format. One change in runner.js.
198
+ Switch with `/model` mid-conversation **the conversation carries over.**
120
199
 
121
- ─ 4.2s · 3 tools · 180 tokens
122
- ```
200
+ ---
123
201
 
124
- ### Slash commands
202
+ ## Slash commands
125
203
 
126
- Names follow the Claude Code / Codex convention.
204
+ Names follow Claude Code / Codex conventions.
127
205
 
128
- | Command | |
206
+ | Command | What it does |
129
207
  |---|---|
130
- | `/help` | list commands |
131
- | `/context` | context usage what is taking up room |
132
- | `/compact` · `/clear` | shrink · wipe the conversation |
133
- | `/model` | switch connection or model (conversation continues) |
134
- | `/think off\|low\|medium\|high\|max` | reasoning effort |
135
- | `/mode auto\|confirm\|strict` | execution mode |
136
- | `/undo [n]` | roll back the last n turns |
137
- | `/tools` · `/skills` | what is available |
138
- | `/cost` · `/status` | usage · connection |
139
- | `/init` | create a `DEEL.md` rules file |
208
+ | `/help` | Command list |
209
+ | `/context` | What is consuming the context window |
210
+ | `/compact` | Summarise and fold older turns |
211
+ | `/clear` | Clear the conversation (keeps link and rules) |
212
+ | `/model` | Switch connection / model |
213
+ | `/think <level\|profile>` | `off·low·medium·high·max` or `even·save·deep` |
214
+ | `/mode <mode>` | `auto` · `confirm` · `strict` |
215
+ | `/undo [turns]` | Revert file changes |
216
+ | `/tools` | Available tools |
217
+ | `/skills [query\|all\|off]` | Browse, search, load skills |
218
+ | `/plugin [install\|remove\|pack]` | Manage plugins |
219
+ | `/cost` | Session usage |
220
+ | `/status` | Connection status |
221
+ | `/scan [save]` | Sweep this machine for local model servers (`save` registers them) |
222
+ | `/sessions` | Past conversations in this folder |
223
+ | `/init` | Create a `DEEL.md` rules file |
224
+ | `/exit` | Quit |
225
+
226
+ Discovered plugin commands are invoked as `/<plugin>:<name>`, with `$ARGUMENTS` substituted.
227
+
228
+ `/scan` and `/sessions` work without leaving the session. If you just started another local
229
+ server or loaded a different model, `/scan save` then `/model` switches over without losing
230
+ the conversation.
231
+
232
+ ### Interrupting
233
+
234
+ Press **Ctrl+C** to stop the model mid-answer when it is heading the wrong way.
235
+
236
+ ```
237
+ ❯ rewrite the whole test suite
238
+ ◧ Read test/smoke.js
239
+ ◧ Read test/loop.test.js
240
+ ^C
241
+ ⚠ Stopped (after step 2)
140
242
 
141
- ### Tools
243
+
244
+ ```
142
245
 
143
- Names and arguments match Claude Code, so skills and commands written for that
144
- convention work unchanged.
246
+ The conversation stays valid. If the model had announced tool calls, each unanswered one is
247
+ filled with a `stopped by user` result so the call/result pairing holds — a conversation with
248
+ broken pairing is rejected with HTTP 400 on the next request, which would waste the whole
249
+ session. Tools already running finish; **tools not yet started never run.**
145
250
 
146
- `Read` · `Write` · `Edit` · `Glob` · `Grep` · `Bash` · `Skill`
251
+ Pressing Ctrl+C again on an empty line quits.
147
252
 
148
253
  ---
149
254
 
150
- ## Edits survive sloppy models
255
+ ## Tools
256
+
257
+ Names and arguments match Claude Code, so skills written for that convention work unchanged.
258
+
259
+ | Tool | What it does |
260
+ |---|---|
261
+ | `Read` | Read a file (line numbers, `offset`/`limit`) |
262
+ | `Write` | Write / overwrite a file |
263
+ | `Edit` | Replace an exact string (`replace_all` supported) |
264
+ | `Glob` | Find files by name pattern |
265
+ | `Grep` | Regex search file contents |
266
+ | `Bash` | Run a command |
267
+ | `Skill` | Expand a skill body (shown to the model only when skills exist) |
268
+ | `WebFetch` | Read a web page (read-only; hidden under `--offline`) |
269
+ | `TodoWrite` | Checklist — breaks long work into steps and shows progress |
270
+
271
+ ### Checklists
151
272
 
152
- Models routinely get whitespace, indentation and line endings slightly wrong.
153
- `Edit` relaxes matching in stages — but **refuses outright when ambiguous**,
154
- because silently editing the wrong place is far worse than not finding it.
273
+ Keeps the model from losing its place on multi-step work. The list is redrawn whenever the
274
+ model updates it.
155
275
 
156
276
  ```
157
- exact trailing space & CRLF → indentation → all whitespace
277
+ ☰ Todo 1/3 done ← just finished 1
278
+
279
+ ✓ unify log format
280
+ ▶ fix the tests
281
+ ☐ update the docs
158
282
  ```
159
283
 
160
- Measured by `npm run bench`:
284
+ Only one item may be **in progress** at a time; setting two is refused. Holding several at
285
+ once is how nothing gets finished.
286
+
287
+ ### Read-only tools run together
288
+
289
+ When the model asks for three `Read` calls at once, all three run **concurrently** — sweeping
290
+ five files costs about what reading one costs.
161
291
 
162
292
  ```
163
- should-fix cases exact-only 2/10 (20%) → staged 10/10 (100%)
164
- should-refuse 5/5 (100%) · wrong-place edits: 0
293
+ Read src/a.js ◧ Read src/b.js ◧ Read src/c.js together
165
294
  ```
166
295
 
167
- When it fails, it points at the closest real line so the model can correct itself:
296
+ Only `Read`, `Glob`, `Grep`, `Skill` and `WebFetch` are eligible. `Write`, `Edit` and `Bash`
297
+ always run one at a time — two concurrent writes to one file scramble the undo snapshot
298
+ order, and `Bash` can do anything. Results come back **in the order the model asked for
299
+ them**, even when they finish out of order; shuffled results confuse the model about which
300
+ result belongs to which call.
301
+
302
+ ### Edits survive small mistakes
303
+
304
+ Models routinely get whitespace, indentation and line endings wrong. deel relaxes matching in
305
+ stages but **refuses outright when the match is ambiguous** — silently editing the wrong place is
306
+ far worse than not finding it.
168
307
 
169
308
  ```
170
- Not found.
171
- Line 2 of the file is closest:
172
- console.log("start: " + id);
173
- Copy that line verbatim and try again.
309
+ exact → ignore trailing space / CRLF → ignore indentation → ignore all whitespace
174
310
  ```
175
311
 
312
+ Measured with `npm run bench`:
313
+
314
+ | | Success | Wrong place edited |
315
+ |---|---|---|
316
+ | Exact match only | 20% | 0 |
317
+ | Staged relaxation | **100%** | **0** |
318
+
319
+ On failure it points at the closest line in the file.
320
+
176
321
  ---
177
322
 
178
- ## Skills and commands come from the host machine
323
+ ## Skills and plugins
179
324
 
180
- Nothing is bundled. On startup it scans:
325
+ **deel does not carry skills with it.** On startup it scans the machine it is running on and uses
326
+ whatever is there. On a clean PC: zero. On a PC with skills installed: those skills.
181
327
 
182
328
  ```
183
329
  project ./.deel/skills ./.claude/skills ./.deel/commands ./.claude/commands
184
330
  user ~/.deel/skills ~/.claude/skills ~/.claude/commands
185
- plugins ~/.claude/plugins/** (any folder with .claude-plugin/plugin.json)
331
+ plugins ~/.claude/plugins/** ~/.deel/plugins/**
186
332
  ```
187
333
 
188
- It reads the Claude Code format: `SKILL.md` with YAML frontmatter,
189
- `commands/*.md` with `$ARGUMENTS` substitution.
334
+ Reads the Claude Code format: `SKILL.md` with YAML front matter, `commands/*.md`, `$ARGUMENTS`.
190
335
 
191
336
  ### Loaded in three stages
192
337
 
193
- Listing everything would blow the context window. So:
338
+ Loading everything would blow the context window.
194
339
 
195
340
  | Stage | What | Cost |
196
341
  |---|---|---|
197
- | 1 | name + one-line description in the system prompt | ~1,800 tokens for 40 |
198
- | 2 | the model calls `Skill` for the one body it wants | one at a time |
199
- | 3 | files that body references, via `Read` | only if needed |
342
+ | 1 | Name + one-line description in the prompt | ~1,800 tokens for 40 skills |
343
+ | 2 | Body of the one the model picks via `Skill` | one at a time |
344
+ | 3 | Files that body references, via `Read` | on demand |
345
+
346
+ ### Fetching plugins
347
+
348
+ ```bash
349
+ # on a connected machine
350
+ /plugin install affaan-m/ECC # git clone, or tarball when git is absent
351
+ /plugin pack import.zip # bundle, excluding executable scripts
352
+
353
+ # on the air-gapped machine — just unzip
354
+ unzip import.zip -d ~/.deel/plugins/
355
+ ```
356
+
357
+ `/plugin pack` omits `.js` `.sh` `.ps1` `.py` and friends, and includes a plain-text manifest
358
+ with a licence table — ready to hand to a security reviewer.
359
+
360
+ ### Deliberately not included
361
+
362
+ | | Why |
363
+ |---|---|
364
+ | hooks | Executable scripts — fails import review, widens the blast radius of autonomy |
365
+ | sub-agents | Doubles model calls against a gateway quota |
366
+ | MCP | A separate protocol; a project of its own |
367
+
368
+ ---
369
+
370
+ ## Reasoning effort
371
+
372
+ One answer means several model calls, and **each needs a different amount of thinking.**
373
+ All-high is slow; all-low wanders off.
374
+
375
+ ```
376
+ $ /think
377
+
378
+ Base medium Profile save Hard on the first decision, light while continuing
379
+
380
+ Stage Effort Cap When
381
+ first call · medium 4,096 deciding what to do
382
+ continuing ↓ low 2,048 reading a tool result, picking the next step
383
+ stuck ↑ high 4,096 the previous tool errored
384
+ ```
385
+
386
+ | Profile | Character |
387
+ |---|---|
388
+ | `even` | Same effort everywhere — predictable, slower |
389
+ | `save` (default) | Hard on the first decision only |
390
+ | `deep` | Everything one notch up — for hard work |
391
+
392
+ **Caps are not fixed numbers.** They are computed from the model's context window and how
393
+ much of it is currently used — the profile decides what share of the remaining room a stage gets.
394
+
395
+ | Model | First call | Continuing | Stuck |
396
+ |---|---|---|---|
397
+ | 2k local | 554 | 512 | 554 |
398
+ | 8k local | 2,007 | 1,003 | 2,007 |
399
+ | 40k (qwen3) | 11,688 | 5,844 | 11,688 |
400
+ | 128k gateway | 16,384 | 16,384 | 16,384 |
401
+ | 128k, 80% full | 7,680 | 3,840 | 7,680 |
402
+
403
+ Caps shrink as the context fills. Handing a 4k model a 4,096-token cap would leave no room for input.
404
+ Raise the ceiling with `maxTokens` in the profile if you need more.
405
+
406
+ If a saved cap truncates a reply, **that step alone is retried with the cap lifted.**
407
+ A truncated reply means a half-written tool call, which fails silently.
408
+
409
+ ---
410
+
411
+ ## Auto-compaction
412
+
413
+ At 80% context, older turns are **summarised and folded** so work continues.
414
+ Plain truncation makes the model forget: it re-reads files and re-fixes what it already fixed.
415
+
416
+ ```
417
+ ◱ Folded 44 turns into a summary — 10,399 → 3,170 tokens (70% smaller)
418
+ ```
419
+
420
+ The summary keeps goal / done / learned / decided / remaining. The cut point is chosen so a
421
+ **tool call is never separated from its result** — splitting them makes the server return 400.
422
+ If the summary request fails, it falls back to plain trimming rather than stopping.
423
+
424
+ `/compact` folds on demand.
425
+
426
+ ---
427
+
428
+ ## Resuming a conversation
429
+
430
+ Close the terminal by accident, or reboot, and the conversation is still there.
431
+ Messages are written to `.deel/sessions/` **as each one completes**, so a crash
432
+ loses at most the message in flight.
433
+
434
+ ```
435
+ $ deel sessions
436
+
437
+ ── conversations in this folder ────────────────────────────────
438
+ ● 20260824-090200 just now 1 turn devstral-small-2507
439
+ fix the failing test
440
+ · 20260824-084500 2h ago 2 turns qwen2.5-coder:7b
441
+ switch src/a.js logging to the logger
442
+ ```
443
+
444
+ | Command | What it does |
445
+ |---|---|
446
+ | `deel --continue` | Resume the most recent conversation in this folder |
447
+ | `deel --resume <id>` | Resume a specific one |
448
+ | `deel sessions` | List what is stored |
449
+ | `deel sessions --rm <id>` | Delete one |
450
+
451
+ The format is `jsonl` — one message per line — so a power cut costs only the last line.
452
+ Resumed history keeps tool calls paired with their results, so work continues immediately.
453
+ Conversations older than 30 days and outside the most recent 30 are pruned automatically.
454
+
455
+ Everything lives in `.deel/sessions/` inside the working folder, and `.gitignore`
456
+ covers `.deel/` so it never reaches a repository.
457
+
458
+ ---
459
+
460
+ ## Safety
461
+
462
+ Instead of approval prompts, the design makes things **reversible**. The default `auto` mode
463
+ does not ask.
464
+
465
+ | Mechanism | Detail |
466
+ |---|---|
467
+ | **Undo** | Snapshot before every write. `/undo` restores per turn |
468
+ | **Scope** | Outside the starting folder is refused, even if the model insists |
469
+ | **Blocked commands** | Only irreversible ones (disk format, recursive delete, `--force` push) |
470
+ | **No re-run** | A mutating command is never retried after failure |
471
+ | **Interrupt** | Ctrl+C stops mid-answer and leaves the conversation valid |
472
+ | **Audit log** | Everything recorded in `.deel/audit.jsonl` |
473
+
474
+ | Mode | Asks when |
475
+ |---|---|
476
+ | `auto` (default) | Never — undo is the safety net |
477
+ | `confirm` | Irreversible commands only |
478
+ | `strict` | All file changes and commands |
479
+
480
+ Undo history stores whole file contents, so repeated edits to large files add up. Past 32MB
481
+ it keeps the **most recent 50 turns** and drops the rest. What you just did is always
482
+ undoable; `/status` shows how large the history currently is.
200
483
 
201
- On a machine with 337 skills, listing 40 costs about 1,800 tokens instead of
202
- well over 100,000.
484
+ ---
485
+
486
+ ## Corporate review package
487
+
488
+ ```bash
489
+ deel pack --out deel-import.zip
490
+ ```
491
+
492
+ ```
493
+ ✓ deel-import.zip
494
+ 39 files · 100.2KB
495
+
496
+ Dependencies 0
497
+ Install scripts none
498
+ External imports 0
499
+ Network calls 3 sites (configured address only)
500
+ Ports opened none
501
+ ```
502
+
503
+ The bundled review sheet contains:
504
+
505
+ - Dependency list and every external `import` in the source
506
+ - Presence of `preinstall` / `install` / `postinstall` / `prepare`
507
+ - **Every network and process-spawn call site found by scanning the source** (file:line)
508
+ - The three outbound lanes, explained
509
+ - SHA-256 per file (verify with `certutil -hashfile`)
203
510
 
204
- Not supported on purpose: **hooks** (executable scriptsa review problem and an
205
- extra failure path for autonomous execution), **subagents** (doubles model calls
206
- against a gateway quota), and **MCP** (a separate protocol, a project of its own).
511
+ It is generated by scanning the source, not written by hand hand-written sheets drift from reality.
512
+ Use `deel audit` to read it without building a zip.
513
+
514
+ ### Diagnosing a corporate gateway
515
+
516
+ ```bash
517
+ node bin/deel.js diagnose --url <gateway> --key <key> --model <model> --out report.txt
518
+ ```
519
+
520
+ Hand over `report.txt` alone — plain text, no colour codes.
521
+
522
+ | Check | Why it matters |
523
+ |---|---|
524
+ | Basic chat | Address, key and model name are right |
525
+ | System message | Rules (`DEEL.md`) and skills take effect |
526
+ | Streaming | Output can flow token by token |
527
+ | **Tool calls** | **Whether it can read and edit files — the critical one** |
528
+ | **Tool results** | **Whether multi-turn works — the premise of the agent loop** |
529
+ | Structured output | Edit format can be enforced by schema |
530
+ | Reasoning control | Whether `/think` works at the model layer |
531
+ | Context length | How many files can be read at once |
532
+
533
+ Verdict is one of **ready · limited · blocked · unreachable**.
207
534
 
208
535
  ---
209
536
 
210
- ## Safety without approval prompts
537
+ ## Configuration
538
+
539
+ Stored in `~/.deel/config.json`. A `.deel/config.json` in the project folder takes precedence.
211
540
 
212
- The default mode is `auto`: it edits files and runs commands without asking.
213
- The safety net is that everything is **reversible**, not that everything is gated.
541
+ ### Supported servers
214
542
 
215
- | | |
543
+ | | Example address |
216
544
  |---|---|
217
- | **Undo** | every file is snapshotted before it changes; `/undo` restores by turn |
218
- | **Scope** | the starting folder is a hard boundary |
219
- | **Blocked commands** | only irreversible ones — disk format, recursive delete, force-push, piping downloads into a shell. Ordinary commands pass |
220
- | **No re-run** | a mutating command is never retried after failure — running it twice is the accident |
221
- | **Audit log** | everything lands in `.deel/audit.jsonl` |
545
+ | Corporate AI gateway (OpenAI-compatible) | `https://ai-gw.example.corp/v1` |
546
+ | Ollama | `http://localhost:11434` |
547
+ | LM Studio | `http://localhost:1234/v1` |
548
+ | llama.cpp · vLLM · LiteLLM | `http://host:port/v1` |
549
+
550
+ Auth style is detected automatically: `Authorization: Bearer` → `x-api-key` → `api-key` (Azure) → none.
551
+
552
+ ### Environment variables
553
+
554
+ | Variable | Use |
555
+ |---|---|
556
+ | `DEEL_API_KEY` | Keep the key out of the config file (takes precedence) |
557
+ | `DEEL_KEY_<PROFILE_ID>` | Per-profile key |
558
+ | `NODE_EXTRA_CA_CERTS` | Corporate TLS certificate |
559
+ | `HTTPS_PROXY` | Behind a proxy |
560
+ | `DEEL_DEBUG=1` | Verbose errors |
561
+ | `NO_COLOR` | Disable colour |
562
+
563
+ ### Flags
564
+
565
+ ```bash
566
+ deel --root <folder> Working scope. Defaults to the current folder
567
+ deel --mode <mode> auto (default) / confirm / strict
568
+ deel --think <level> off / low / medium (default) / high / max
569
+ deel --effort <profile> even / save (default) / deep
570
+ deel --offline Nothing leaves this machine
571
+ deel --continue Resume the most recent conversation
572
+ deel --resume <id> Resume a specific one
573
+ ```
222
574
 
223
- `/mode confirm` asks before irreversible commands; `/mode strict` asks before
224
- every file change and command.
575
+ ### Project rules
576
+
577
+ If the working folder has `DEEL.md`, `CLAUDE.md` or `AGENTS.md`, it is loaded as project rules.
578
+ `/init` scaffolds one.
579
+
580
+ ---
581
+
582
+ ## Troubleshooting
583
+
584
+ | Symptom | Check |
585
+ |---|---|
586
+ | `address not found` | Typo, DNS, VPN / intranet connectivity |
587
+ | `connection refused` | Server is down or the port differs |
588
+ | certificate error | `set NODE_EXTRA_CA_CERTS=C:\path\corp-ca.pem` |
589
+ | behind a proxy | `set HTTPS_PROXY=http://proxy:port` |
590
+ | 401 / 403 | Wrong key or auth header style (four are tried automatically) |
591
+ | `address not permitted` | The lock did its job — pick a connection with `/model` |
592
+ | Tool calls don't work | Run `deel diagnose`. Small models (1B–3B) often can't |
593
+ | Empty replies | A heavy-reasoning model — try `/think low` |
594
+ | `deel scan` finds nothing | Server is off or on another port — use `--ports` |
225
595
 
226
596
  ---
227
597
 
228
598
  ## Development
229
599
 
230
600
  ```bash
231
- npm run check # syntax across every module
232
- npm test # 20 tool checks + 16 engine checks + the edit benchmark
233
- npm run demo # see the chat screen, driven by a fake gateway
234
- npm run bench # edit reliability numbers
601
+ npm test Full suite (254 checks)
602
+ npm run verify Import + network checks only
603
+ npm run bench Edit success rate
604
+ npm run demo See what the UI actually looks like
605
+ npm run check Syntax check every file
235
606
  ```
236
607
 
237
- The engine tests spin up a **fake OpenAI-compatible gateway** over HTTP. No real
238
- model is involved, so the loop, streaming parser, tool execution and undo are all
239
- verified deterministically including the case where a gateway splits tool-call
240
- arguments across streaming chunks.
608
+ Tests run against a **fake gateway**, so the loop, streaming, tool execution, undo and compaction
609
+ are verified deterministically without any model. ZIP output is cross-checked with the real
610
+ `unzip`; the TAR reader is fed archives produced by the real `tar`.
611
+
612
+ `npm test` runs each file separately and reports **per-file exit codes**, because the exit code
613
+ — not the pass marks on screen — is what CI reads, and the two can disagree: a file can pass
614
+ every check and still die on the way out, leaving the screen green and the exit code 1. That
615
+ happened once on Windows and cost a lot of time. The runner does not stop at the first failure,
616
+ so one run tells you everything.
617
+
618
+ | Suite | Checks | Covers |
619
+ |---|---|---|
620
+ | `smoke` | 20 | Tools, scope, undo, audit log |
621
+ | `loop` | 16 | Agent loop, streaming, tool calls |
622
+ | `network` | 30 | Nothing escapes the configured address |
623
+ | `web` | 25 | Web reads stay read-only |
624
+ | `abort` | 16 | Ctrl+C leaves the conversation valid |
625
+ | `parallel` | 23 | Read-only tools run together; checklists |
626
+ | `compact` | 21 | Summary folding, pairing intact, graceful fallback |
627
+ | `store` | 34 | Session persistence, resume, crash recovery |
628
+ | `scan` | 19 | Distinguishing multiple runtimes |
629
+ | `plugins` | 38 | Plugin fetch/pack, ZIP/TAR |
630
+ | `no-bundle` | 12 | Nothing foreign in the published package; test-file hygiene |
631
+ | `edit-bench` | 20 cases | Edit success rate |
241
632
 
242
633
  ---
243
634
 
244
- ## License
635
+ ## Licence
245
636
 
246
- MIT
637
+ [MIT](LICENSE)