deel-local-cli 1.0.2 → 1.1.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 +381 -7
- package/README.md +407 -7
- package/bin/deel.js +266 -234
- package/package.json +4 -3
- package/src/agent/budget.js +167 -0
- package/src/agent/grade.js +207 -0
- package/src/agent/loop.js +778 -574
- package/src/agent/modes.js +109 -28
- package/src/agent/project.js +171 -0
- package/src/agent/session.js +131 -12
- package/src/backend/learn.js +46 -4
- package/src/commands.js +73 -0
- package/src/oneshot.js +390 -327
- package/src/repl.js +1074 -887
- package/src/safety/audit.js +3 -1
- package/src/tools/index.js +500 -107
- package/src/tools/jobs.js +670 -0
- package/src/tools/outline.js +331 -0
- package/src/tools/task.js +153 -0
- package/src/tools/verify.js +306 -0
- package/src/tools/webfetch.js +152 -16
- package/src/ui/inputbox.js +97 -5
- package/src/ui/screen.js +51 -3
- package/src/ui/status.js +69 -4
- 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`
|
|
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
|
-
|
|
600
|
-
|
|
601
|
-
|
|
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
|