deel-local-cli 1.0.2 → 1.1.1

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.
Files changed (37) hide show
  1. package/README.en.md +381 -7
  2. package/README.md +493 -9
  3. package/bin/deel.js +266 -234
  4. package/package.json +4 -3
  5. package/src/agent/budget.js +167 -0
  6. package/src/agent/grade.js +207 -0
  7. package/src/agent/loop.js +778 -574
  8. package/src/agent/modes.js +109 -28
  9. package/src/agent/project.js +171 -0
  10. package/src/agent/route.js +55 -3
  11. package/src/agent/session.js +131 -12
  12. package/src/backend/http.js +41 -4
  13. package/src/backend/learn.js +46 -4
  14. package/src/commands.js +178 -3
  15. package/src/oneshot.js +390 -327
  16. package/src/preview/serve.js +326 -0
  17. package/src/repl.js +1184 -887
  18. package/src/safety/audit.js +3 -1
  19. package/src/skills/builtin//352/262/200/354/202/254-/353/250/274/354/240/200/SKILL.md +64 -0
  20. package/src/skills/builtin//352/271/212/354/235/264/354/236/210/352/262/214-/353/247/214/353/223/244/352/270/260/SKILL.md +78 -0
  21. package/src/skills/builtin//353/201/235/352/271/214/354/247/200-/355/225/230/352/270/260/SKILL.md +65 -0
  22. package/src/skills/builtin//354/212/244/354/212/244/353/241/234-/352/262/200/355/206/240/SKILL.md +74 -0
  23. package/src/skills/builtin//354/260/224/353/237/254/353/263/264/352/270/260/SKILL.md +59 -0
  24. package/src/skills/builtin//354/260/250/352/267/274/354/260/250/352/267/274-/353/224/224/353/262/204/352/271/205/SKILL.md +73 -0
  25. package/src/skills/builtin//354/275/224/353/223/234-/354/244/204/354/235/264/352/270/260/SKILL.md +66 -0
  26. package/src/skills/discover.js +17 -2
  27. package/src/tools/index.js +500 -107
  28. package/src/tools/jobs.js +670 -0
  29. package/src/tools/outline.js +331 -0
  30. package/src/tools/task.js +153 -0
  31. package/src/tools/verify.js +306 -0
  32. package/src/tools/webfetch.js +152 -16
  33. package/src/ui/inputbox.js +102 -7
  34. package/src/ui/motion.js +212 -0
  35. package/src/ui/screen.js +51 -3
  36. package/src/ui/status.js +69 -4
  37. package/src/ui/working.js +8 -1
package/README.en.md CHANGED
@@ -203,6 +203,136 @@ $ deel scan
203
203
 
204
204
  Switch with `/model` mid-conversation — **the conversation carries over.**
205
205
 
206
+ ### It adapts to whatever model is attached
207
+
208
+ If you move between models, any number tuned for one of them is wrong for all the others.
209
+ So **no number is hardcoded.**
210
+
211
+ There are two axes. They are easy to confuse, so they have separate commands.
212
+
213
+ | | What it measures | Command |
214
+ |---|---|---|
215
+ | **Window size** | how much it can hold | `/ctx` |
216
+ | **Model grade** | how much it can do on its own | `/grade` |
217
+
218
+ They do not move together. A 3B model with a 128k window exists; so does a very good model
219
+ with 32k. Treat them as one axis and you hold one back while overrunning the other.
220
+
221
+ **Derived from window size** (`src/agent/budget.js`):
222
+
223
+ | | 8k | 32k | 131k | 655k |
224
+ |---|---|---|---|---|
225
+ | Steps per turn (code) | 16 | 48 | 192 | 200 |
226
+ | `Read` lines | 200 | 384 | 1,536 | 4,000 |
227
+ | `Glob` results | 50 | 192 | 768 | 1,000 |
228
+ | `Outline` lines | 120 | 480 | 1,920 | 2,500 |
229
+ | `WebFetch` chars | 4,000 | 12,800 | 51,200 | 120,000 |
230
+ | Subtask summary | 400 | 1,600 | 4,000 | 4,000 |
231
+
232
+ **Derived from model grade** (`src/agent/grade.js`):
233
+
234
+ | | small | medium | large |
235
+ |---|---|---|---|
236
+ | Files per `Write` | 3 | 6 | 12 |
237
+ | Split-writing threshold | 200 lines | 400 lines | 800 lines |
238
+ | Spell out the procedure | yes | yes | **no — give the goal** |
239
+ | Require verification | yes | yes | **yes** (grade-independent) |
240
+
241
+ The grade is decided like this:
242
+
243
+ 1. **First guess from the name.** `qwen2.5-coder-7b` -> small, `llama-3.3-70b` -> large.
244
+ Version numbers (`2.5`) and quantisation tags (`q4_k_m`) are not read as sizes.
245
+ A name that says nothing means **medium**, not small — a corporate gateway is exactly
246
+ that case, and the models behind one are usually big. Guessing small holds them back.
247
+ 2. **Corrected by what actually happened.** Truncated tool arguments, empty answers,
248
+ failed edits and repeats are counted. A model labelled 70B that truncates every step is
249
+ dropped to **small**; a 7B that runs ten clean steps is raised one level. The name is a
250
+ guess; what happened is a fact.
251
+ 3. **You win if you say so.** `/grade large`, and `/grade auto` hands it back.
252
+
253
+ The status line shows `◈ small?`. The question mark means **still a guess** — a guess is
254
+ not presented with the same face as something measured.
255
+
256
+ The grade only changes **how much hand-holding you get**. Working scope, approval mode,
257
+ undo and the audit log are identical at every grade. There is no "it is a good model, so
258
+ skip verification" — that is exactly how a good model's mistake goes unnoticed.
259
+
260
+ ### Small windows get a smaller fixed share
261
+
262
+ The system prompt and the tool definitions go out **in full on every request**. Compaction
263
+ (`/compact`) cannot shrink them. Once that share passes half the window there is no room
264
+ left however well you fold, and it looks like "the model suddenly got stupid".
265
+
266
+ Adding three tools (`Outline`, `Verify`, `Task`) pushed it to **49%** at 8k. Dropping a
267
+ tool would have fixed it — and would have made small models capable of different things,
268
+ which is the thing to avoid. The descriptions were trimmed to the window instead.
269
+
270
+ | | 8k | 16k | 32k+ |
271
+ |---|---|---|---|
272
+ | Base rules | short form | short form | full |
273
+ | Mode description | short form | short form | full |
274
+ | Tool descriptions | 90 chars | 140 chars | 220 / full |
275
+ | Obvious param descriptions | dropped | kept | kept |
276
+ | Descriptions inside array items | dropped | dropped | kept |
277
+ | **Fixed share** | **2,712 tokens (33%)** | 3,290 (21%) | 4,745 (4% at 131k) |
278
+
279
+ The **folder brief** adds roughly 80 more tokens at 8k (below). That value varies by
280
+ folder, so it is not in the table.
281
+
282
+ **Tool names and arguments are untouched.** What is possible is identical in every window;
283
+ what disappears is only the argument for *why* to use a tool. Large windows keep it,
284
+ because that argument earns its keep — those two sentences are what make a model call
285
+ `Outline` before `Read`.
286
+
287
+ A test pins these numbers (`test/compact.test.js`).
288
+
289
+ ### On startup it reads what kind of project this folder is
290
+
291
+ Started in a folder of someone else's code, the model began knowing nothing. So it
292
+ retraced the same three steps every time — scan the top level, read `package.json`, find
293
+ out how tests are run. **On a local model each step is 20-40 seconds, so two minutes go
294
+ by before the work even starts.**
295
+
296
+ The worse case is the model *skipping* those three steps. Then it creates files by its
297
+ own conventions without knowing what the project already uses — a `requirements.txt`
298
+ dropped into an npm project.
299
+
300
+ The answers are all knowable at startup, so they are read once and put in the prompt.
301
+
302
+ The brief itself is written in Korean, like everything else deel puts on screen — this is
303
+ deel's own folder, wrapped here for width:
304
+
305
+ ```
306
+ --- 이 폴더 --- (this folder)
307
+ node 프로젝트 (deel-local-cli) · git main
308
+ 돌릴 수 있는 것: npm start · npm test · npm run bench · npm run chat · npm run check ·
309
+ npm run coverage · npm run demo · npm run diagnose (runnable)
310
+ 위쪽: bin/ src/ test/ LICENSE README.en.md README.md package.json report.txt (top level)
311
+ 위쪽 한 겹만 본 것이다. 안을 알아야 하면 Outline 을 불러라.
312
+ (top level only — call Outline to see inside)
313
+ ```
314
+
315
+ **Nothing is invented.** Runnable commands are copied verbatim from `scripts` in
316
+ `package.json`. Advertising a command that does not exist means the model calls it,
317
+ fails, and spends the steps you just saved looking for the real one.
318
+
319
+ **The last line matters.** What is listed is the top level and `package.json`, nothing
320
+ inside subfolders. Without saying so, the model treats this as a map of the whole project
321
+ and stops calling `Outline` — at which point the brief costs more than it saves.
322
+
323
+ | Not done | Why |
324
+ |---|---|
325
+ | No `git` subprocess | `.git/HEAD` is read directly. Spawning one freezes startup for seconds on a large repo |
326
+ | No directory walk | Top level **only**. Descending is slow on large repos, and only one line goes in the prompt anyway |
327
+ | Not re-read each turn | Once, at startup. A prompt that changes mid-conversation makes it impossible to tell why an answer changed |
328
+
329
+ It scales with the window — 10 entries and 4 commands at 8k, 24 and 8 on a large one.
330
+ If only one thing survives a narrow window it is the **commands**. The top-level listing
331
+ can be recovered with one `Glob`; "tests run with `npm test`" requires opening
332
+ `package.json`.
333
+
334
+ 7ms on a folder with 600 files (`test/project.test.js`).
335
+
206
336
  ---
207
337
 
208
338
  ## Slash commands
@@ -214,6 +344,7 @@ Names follow Claude Code / Codex conventions.
214
344
  | `/help` | Command list |
215
345
  | `/context` | What is consuming the context window |
216
346
  | `/ctx [auto\|number]` | Context **length** — re-read it off the model, or set it yourself |
347
+ | `/grade [small\|medium\|large\|auto]` | Model **grade** — how much it does on its own. A different axis from `/ctx` |
217
348
  | `/out [number\|auto]` | Cap on a **single reply** — raise it when large files get cut |
218
349
  | `/compact` | Summarise and fold older turns |
219
350
  | `/clear` | Clear the conversation (keeps link and rules) |
@@ -584,21 +715,233 @@ Names and arguments match Claude Code, so skills written for that convention wor
584
715
  | Tool | What it does |
585
716
  |---|---|
586
717
  | `Read` | Read a file (line numbers, `offset`/`limit`, **Excel as CSV**) |
587
- | `Write` | Write / overwrite a file |
718
+ | `Write` | Write / overwrite a file (**several at once via the `files` array**) |
588
719
  | `Append` | Append to the end of a file — **how large files get written in pieces** |
589
- | `Edit` | Replace an exact string (`replace_all` supported) |
720
+ | `Edit` | Replace an exact string (`replace_all`; **several sites at once via the `edits` array**) |
590
721
  | `Glob` | Find files by name pattern |
591
722
  | `Grep` | Regex search file contents |
592
- | `Bash` | Run a command |
723
+ | `Bash` | Run a command (**`background: true` for anything that does not finish**) |
593
724
  | `Skill` | Expand a skill body (shown to the model only when skills exist) |
594
725
  | `WebFetch` | Read a web page (read-only; hidden under `--offline`) |
595
726
  | `Recall` | Search **past conversations** — the model digs up "that thing last time" itself |
596
727
  | `Remember` | One line that outlives the session — known from the start next time |
597
728
  | `TodoWrite` | Checklist — breaks long work into steps and shows progress |
729
+ | `Outline` | See a folder's **skeleton only** — tens of times cheaper than reading it whole |
730
+ | `Verify` | Check that what was built **actually works** |
731
+ | `Task` | Run one chunk of a big job in a **separate context** |
732
+ | `Jobs` | Inspect, read and stop **background commands** — the other half of `Bash`'s `background` |
733
+
734
+ Seven tools here are not in Claude Code — `Append`, `Recall`, `Remember`, `Outline`,
735
+ `Verify`, `Task`, `Jobs`. Each tool costs 150-400 tokens of schema on **every request**,
736
+ so a test stops you every time the list grows (`test/loop.test.js`). The last four earned
737
+ their cost; here is why.
738
+
739
+ ### Seeing a project's shape cheaply — `Outline`
740
+
741
+ There used to be only two ways to understand someone else's code. `Glob` gives you paths;
742
+ `Read` pulls a whole file into the window. **The middle was missing.**
743
+
744
+ So the model started editing without knowing what lived where, and re-created functions
745
+ that already existed somewhere else. It had not seen them — which is different from not
746
+ knowing.
747
+
748
+ ```
749
+ ❉ Outline(src/ui) 12 files · 122 places
750
+
751
+ src/ui/screen.js (304 lines)
752
+ 46 fn 상자쓸까
753
+ 65 class LineScreen
754
+ 92 method 줄
755
+ 198 class BoxScreen
756
+ ```
757
+
758
+ Reading that folder whole costs **25,612 tokens**; `Outline` costs **857** — 30x cheaper.
759
+ An 8k model can see the shape of a whole project.
760
+
761
+ It reads js/ts, py, java/kotlin, go, rust, c#, md, html, css, sh and json. Regex, not a
762
+ parser (zero dependencies). So it **says what it could not read** — dropping those
763
+ silently makes the model believe the file does not exist, and rebuild config that is
764
+ already there.
765
+
766
+ ### Checking what was built — `Verify`
767
+
768
+ The end of a turn used to say:
769
+
770
+ ```
771
+ ✓ index.html · 410 lines · 18.2KB
772
+ ```
773
+
774
+ That proves the file **exists**, not that it **works**. An unclosed `<div>`, a
775
+ `src="app.js"` pointing at nothing, a JS file one bracket short — all green.
776
+
777
+ What can be run gets run (`node --check`, `py_compile`); what cannot gets read (HTML tag
778
+ pairing, missing references, CSS braces, JSON).
779
+
780
+ ```
781
+ ⏺ Verify 1 broken · 3 checked
782
+ ```
783
+
784
+ And the part that matters most — **what could not be checked is reported as such.**
598
785
 
599
- Only **three** tools here are not in Claude Code `Append`, `Recall`, `Remember`. Each
600
- tool costs roughly 150 tokens of schema on **every request**, so a test stops you every
601
- time the list grows (`test/loop.test.js`).
786
+ Arbitrary commands are **not** run here. That path has to be `Bash` alone: the approval
787
+ gate and the safety checks live only there, so running commands from here would break the
788
+ strict-mode promise in exactly this one spot. It tells you `npm test` exists instead.
789
+
790
+ ### Splitting big work off — `Task`
791
+
792
+ Building eight files in one window means all eight files pile up in that window. On a 32k
793
+ model it fills around the third or fourth, and once it fills, earlier turns get folded
794
+ away. From then on the model has forgotten what it was building — **no error appears, the
795
+ result just gets worse.** That was the root of "build me a dashboard" ending as a plan.
796
+
797
+ `Task` runs that chunk in a **fresh conversation** and returns only a summary.
798
+
799
+ ```
800
+ ⌥ subtask build the page skeleton separate conversation · max 8 steps
801
+ │ ◆ Write(index.html +1) 2 files · 24 lines
802
+ ✓ subtask build the page skeleton done · 2 files · 2 steps
803
+ ```
804
+
805
+ Peak conversation size while building the same four files (system prompt excluded):
806
+
807
+ | | Peak |
808
+ |---|---|
809
+ | All in one window | 4,181 chars |
810
+ | Split with `Task` | **2,113 chars** |
811
+
812
+ The left column keeps growing with each file; the right one does not.
813
+
814
+ **Every guard still applies.** A subtask runs inside the same working folder, follows the
815
+ same approval mode, is undone **together with** its parent by one `/undo`, and lands in
816
+ the audit log. There is no path for a subtask to edit files under a read-only mode
817
+ (architect, plan, ask) — that is blocked both at the mode level and in the tool list.
818
+ Nesting stops at two levels.
819
+
820
+ ### Commands that never finish — `Bash`'s `background` and `Jobs`
821
+
822
+ `Bash` only returns once the command **ends**. So anything that does not end could not be
823
+ run — `npm run dev`, `python -m http.server`, `vite`, `npm run watch`. Asking for one used
824
+ to mean waiting 120 seconds and then a kill, leaving one line on screen.
825
+
826
+ ```
827
+ ▶ Bash(npm run dev)
828
+ └ 시간 초과로 중단됨 (120000ms) 2분 0.0초
829
+ (timed out)
830
+ ```
831
+
832
+ The model concludes the server would not start and gives up, or worse, raises `timeout`
833
+ and calls again — which stalls the whole turn. **There was no way at all to start what
834
+ you built and check it.** `Verify` gets you as far as "the syntax is valid"; whether it
835
+ actually comes up requires bringing it up.
836
+
837
+ ```
838
+ ▶ Bash(npm run dev)
839
+ └ 1번으로 띄움 (started as job 1)
840
+
841
+ ◈ Edit(src/App.jsx)
842
+ └ 1군데 (1 site)
843
+
844
+ ◐ Jobs(1번)
845
+ └ 도는중 · 24초 (running · 24s)
846
+
847
+ ◐ Jobs(1번 · 끝내기)
848
+ └ 끝냄 · 41초 (stopped · 41s)
849
+ ```
850
+
851
+ It starts and **returns immediately**. Output accumulates and `Jobs` reads it.
852
+
853
+ **Something that did not start is never reported as started.** The job is watched briefly
854
+ after launch, and if it dies in that window it comes back as a failure. The most common
855
+ failure is a port already in use; reporting that as "started" sends the model on to the
856
+ next step while you refresh a server that was never there.
857
+
858
+ ```
859
+ ▶ Bash(npm run dev)
860
+ └ 띄우자마자 끝났습니다 (종료코드 1).
861
+ (exited immediately, exit code 1)
862
+ ```
863
+
864
+ | Guarantee | Detail |
865
+ |---|---|
866
+ | Safety checks | **Identical** to `Bash`. This must not become a back door |
867
+ | Cleanup | Everything is killed when deel exits — **down to grandchildren**, and it says how many |
868
+ | Retained | 256KB. Past that the front is dropped and **the drop is stated** |
869
+ | Handed to the model | 4,000 chars. This **must** be a different number from the one above |
870
+ | On stop | Waits for the dying output, and returns only once the process is **actually dead** |
871
+ | Argument names | Korean and English both accepted (`번호`/`job`, `끝내기`/`stop`). Unrecognized ones **are reported** |
872
+ | Count | Eight running. Finished jobs keep the most recent eight, and evictions **are stated** |
873
+
874
+ Why two different caps: make them equal and every overflow of a `watch` job means
875
+ one `Jobs` read dumps 256KB into the window. On an 8k model that single read ends
876
+ the window.
877
+
878
+ **Stopping a job does not close its pipes immediately.** At the moment the kill is
879
+ issued there is still unread data in the pipe, and the last few lines before a
880
+ death are the ones that matter — the stack trace a server leaves on the way down.
881
+ Printing `last output:` and then withholding the last output is worse than not
882
+ printing it. It also waits until the process is **confirmed dead** before dropping
883
+ it from the list: dropping a live one means it can never be named again, which is
884
+ the exact state this feature exists to prevent.
885
+
886
+ Finished jobs are not dropped right away — they are kept so their final output can
887
+ be read. Only the most recent eight survive; otherwise thirty short commands leave
888
+ thirty entries, each holding up to 256KB.
889
+
890
+ **Argument names are accepted in both Korean and English.** Models frequently
891
+ translate Korean parameter names into English — not a guess, something this repo
892
+ already hit (`Task` accepts both `목적` and `purpose`). `Jobs` did not, which meant:
893
+
894
+ ```
895
+ Jobs({job: 1, stop: true}) -> a listing comes back. The server keeps running.
896
+ ```
897
+
898
+ The model asked for a stop and **got what looks like a success** while the port
899
+ stays held. So both spellings are accepted, and when nothing is recognized it says
900
+ so rather than falling back to a listing. The name mapping lives in exactly **one**
901
+ place — the on-screen label reads it too. Two copies means the tool works while the
902
+ label shows empty parentheses.
903
+
904
+ **Killing grandchildren is where this quietly goes wrong.** `npm run dev` descends
905
+ npm → node → vite, and the thing holding the port is at the bottom. Windows has
906
+ `taskkill /t` to walk the tree; Unix has nothing equivalent, so the job is
907
+ **started in its own process group** — after the fact there is no way to name a
908
+ grandchild at all. Skip that and deel says "killed 3" while the server keeps running.
909
+
910
+ Cleanup is where this quietly goes wrong. Skip it and a process nobody started keeps
911
+ running. Next time you start a dev server you get "port already in use" with **no way to
912
+ find what is holding it**. So `test/jobs.test.js` verifies the process actually died, via
913
+ a file the child keeps appending to.
914
+
915
+ `deel run` (one-shot mode) does the same. A batch job is hurt worst by missing this — the
916
+ job reports done, the server keeps running, and the next job fails to bind the same port
917
+ with nothing in the log to explain it.
918
+
919
+ ### Several at once — `Write`'s `files`, `Edit`'s `edits`
920
+
921
+ One round trip is 20-40 seconds on a local model. Creating five files with five `Write`
922
+ calls is two to three minutes of nothing but round trips. So they go in one array.
923
+
924
+ ```
925
+ ◈ Edit(src/app.js 외 2군데)
926
+ └ 2개 파일 · 3군데 (2 files · 3 sites)
927
+ ✓ src/app.js · 2군데
928
+ ✓ src/style.css · 1군데
929
+ ```
930
+
931
+ **Editing is worth more than writing here.** Creating files happens once; editing happens
932
+ continuously. Six edit sites at six round trips is minutes gone.
933
+
934
+ | | Guaranteed |
935
+ |---|---|
936
+ | Applied in order | Editing one file twice is common. Each edit re-reads from disk, so later ones see earlier results |
937
+ | One failure | The rest still run. Stopping at the first failure re-adds the round trips this was meant to remove |
938
+ | On failure | "Resend only what failed — **and `Read` the file again first**" |
939
+ | Undo | Still **one turn**. Six sites in one file is one `/undo` |
940
+ | Single-site form | The result shape is byte-for-byte unchanged |
941
+
942
+ It reports `2 files · 3 sites` rather than a single number. Editing one file at six sites
943
+ is normal, so "3 files" would be false — and once the screen stops matching what you can
944
+ count yourself, you stop trusting the screen.
602
945
 
603
946
  ### Finding past conversations, and remembering decisions
604
947
 
@@ -1180,7 +1523,7 @@ does not ask.
1180
1523
 
1181
1524
  | Mechanism | Detail |
1182
1525
  |---|---|
1183
- | **Undo** | Snapshot before every write. `/undo` restores per turn |
1526
+ | **Undo** | Snapshot before every write. `/undo` restores per turn. **Includes moves and deletes done through `Bash`** |
1184
1527
  | **Change display** | The changed lines are shown on every edit; `/diff` for the whole session |
1185
1528
  | **Scope** | Outside the starting folder is refused, even if the model insists |
1186
1529
  | **Blocked commands** | Only irreversible ones (disk format, recursive delete, `--force` push) |
@@ -1200,6 +1543,37 @@ Undo history stores whole file contents, so repeated edits to large files add up
1200
1543
  it keeps the **most recent 50 turns** and drops the rest. What you just did is always
1201
1544
  undoable; `/status` shows how large the history currently is.
1202
1545
 
1546
+ ### Files removed through `Bash` come back too
1547
+
1548
+ The safety net covered `Write` and `Edit` only. But a model moving a file reaches for
1549
+ `Bash` — `mv old.js new.js`, `rm temp.txt`. The file was gone and `/undo` could do
1550
+ nothing about it. It was half a safety net.
1551
+
1552
+ Now a mutating command snapshots the files it names beforehand, and **says what it saved,
1553
+ right there**.
1554
+
1555
+ ```
1556
+ ▶ Bash(mv src/old.js src/new.js)
1557
+ └ 성공
1558
+ ↩ src/old.js 는 떠 뒀습니다 — /undo 로 되돌아갑니다
1559
+ (saved src/old.js — /undo restores it)
1560
+ ```
1561
+
1562
+ `mv` and `rm` leave one "success" line on screen. From that line alone there is no way to
1563
+ tell whether it is reversible, so people either assume it is and move on, or assume it is
1564
+ not and get scared. So the fact is stated.
1565
+
1566
+ **What cannot be saved is not hidden.** Shell-expanded wildcards (`rm *.tmp`), deletions
1567
+ inside a script, and whole directories are invisible here. In those cases the `↩` line
1568
+ simply does not appear — **it never claims "everything is reversible"**. False reassurance
1569
+ means people stop checking.
1570
+
1571
+ Snapshotting casts a **wider** net than blocking does. The scope guard (`checkPaths`) only
1572
+ treats words containing a slash as paths — anything else would block legitimate commands —
1573
+ but `del target.txt`, with no slash, is the most common form there is. This is a reading
1574
+ site rather than a blocking one, so it scans broadly and saves a file only when one is
1575
+ actually there. A wrong guess costs nothing. Up to 24 per command.
1576
+
1203
1577
  ### What it will not read
1204
1578
 
1205
1579
  Walking a folder turns up things that are not project files: the private stores other coding