patch-cc 0.2.4__tar.gz → 0.3.0__tar.gz
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.
- {patch_cc-0.2.4 → patch_cc-0.3.0}/AGENTS.md +7 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/PKG-INFO +12 -6
- {patch_cc-0.2.4 → patch_cc-0.3.0}/README.md +9 -5
- {patch_cc-0.2.4 → patch_cc-0.3.0}/docs/CONDUCT.md +31 -13
- {patch_cc-0.2.4 → patch_cc-0.3.0}/docs/INTERNALS.md +56 -23
- patch_cc-0.3.0/docs/PLAYBOOK.md +1227 -0
- patch_cc-0.3.0/docs/corpus.md +81 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/pyproject.toml +17 -1
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/__init__.py +1 -1
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/bun/blob.py +70 -26
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/bun/container.py +56 -12
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/bun/elf.py +17 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/bun/macho.py +9 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/cache.py +34 -47
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/cli.py +79 -25
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/codex/__init__.py +11 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/codex/gateway.py +33 -10
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/codex/models.py +8 -6
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/codex/oauth.py +44 -4
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/codex/translate.py +76 -21
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/doctor.py +71 -14
- patch_cc-0.3.0/src/patch_cc/js.py +1007 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/locate.py +12 -1
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/menu.py +32 -27
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/patcher.py +79 -50
- patch_cc-0.3.0/src/patch_cc/patches/agents.py +577 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/patches/base.py +150 -102
- patch_cc-0.3.0/src/patch_cc/patches/chrome.py +450 -0
- patch_cc-0.3.0/src/patch_cc/patches/codex.py +879 -0
- patch_cc-0.3.0/src/patch_cc/patches/output.py +258 -0
- patch_cc-0.3.0/src/patch_cc/patches/streaming.py +1024 -0
- patch_cc-0.3.0/src/patch_cc/patches/thinking.py +527 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/ui.py +44 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/uv.lock +60 -1
- patch_cc-0.2.4/docs/PLAYBOOK.md +0 -638
- patch_cc-0.2.4/src/patch_cc/patches/agents.py +0 -393
- patch_cc-0.2.4/src/patch_cc/patches/chrome.py +0 -262
- patch_cc-0.2.4/src/patch_cc/patches/codex.py +0 -519
- patch_cc-0.2.4/src/patch_cc/patches/output.py +0 -173
- patch_cc-0.2.4/src/patch_cc/patches/streaming.py +0 -837
- patch_cc-0.2.4/src/patch_cc/patches/thinking.py +0 -287
- {patch_cc-0.2.4 → patch_cc-0.3.0}/.github/workflows/ci.yml +0 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/.github/workflows/release.yml +0 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/.gitignore +0 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/CLAUDE.md +0 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/LICENSE +0 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/docs/demo.gif +0 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/bun/__init__.py +0 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/bun/errors.py +0 -0
- {patch_cc-0.2.4 → patch_cc-0.3.0}/src/patch_cc/patches/__init__.py +0 -0
|
@@ -16,3 +16,10 @@ Verify with `uv run patch-cc doctor` (every patch against a clean bundle;
|
|
|
16
16
|
point it at the pristine copies in `~/.local/share/patch-cc/backups/` to sweep
|
|
17
17
|
older builds). There is no test suite by design — doctor against real bundles
|
|
18
18
|
is the check.
|
|
19
|
+
|
|
20
|
+
Be exact about what that covers: doctor runs the **matchers** and parses the
|
|
21
|
+
bundle they produce. It never runs the gateway, the translator, the OAuth flow
|
|
22
|
+
or the menu, so a change under `src/patch_cc/codex/` (the bridge — all of it
|
|
23
|
+
runtime, none of it a patch; the Codex *patch* is `patches/codex.py`, which the
|
|
24
|
+
sweep does cover) or in `menu.py` is checked by exercising it — a real `codex
|
|
25
|
+
serve` against a real turn — and a green sweep says nothing about it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: patch-cc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Interactive patcher for the Claude Code native binary
|
|
5
5
|
Project-URL: Homepage, https://github.com/anfreire/patch-cc
|
|
6
6
|
Project-URL: Repository, https://github.com/anfreire/patch-cc
|
|
@@ -25,6 +25,8 @@ Requires-Python: >=3.11
|
|
|
25
25
|
Requires-Dist: blessed>=1.47.0
|
|
26
26
|
Requires-Dist: lief>=0.15; sys_platform == 'darwin'
|
|
27
27
|
Requires-Dist: rich>=13.7
|
|
28
|
+
Requires-Dist: tree-sitter-javascript>=0.23
|
|
29
|
+
Requires-Dist: tree-sitter>=0.25
|
|
28
30
|
Description-Content-Type: text/markdown
|
|
29
31
|
|
|
30
32
|
# patch-cc
|
|
@@ -37,7 +39,7 @@ you want — inline and live thinking, detailed tool calls, subagent model
|
|
|
37
39
|
overrides, your own startup name, your **ChatGPT/Codex-plan GPT models as
|
|
38
40
|
native models** — and apply them to your installed `claude` in one keystroke.
|
|
39
41
|
Fully reversible: a pristine backup is kept, `patch-cc restore` puts it back.
|
|
40
|
-
|
|
42
|
+
No Node, no Bun.
|
|
41
43
|
|
|
42
44
|
```bash
|
|
43
45
|
uvx patch-cc # fullscreen menu, no install needed
|
|
@@ -92,7 +94,7 @@ patch-cc # then just run it
|
|
|
92
94
|
| Chrome & branding | Disable spinner tips | No rotating tips on the spinner |
|
|
93
95
|
| | Mark `--version` | Appends `(patched)` — or any marker you choose |
|
|
94
96
|
| | Custom startup name | Defaults to `<your username>'s Code` |
|
|
95
|
-
| | Startup org/email label | Replace the org/email on the welcome screen — or hide it |
|
|
97
|
+
| | Startup org/email label | Replace the org/email on the welcome screen — or hide it (demo mode keeps the stock line) |
|
|
96
98
|
|
|
97
99
|
## Usage
|
|
98
100
|
|
|
@@ -197,9 +199,13 @@ startup name / `--version` marker are visible tells too.
|
|
|
197
199
|
|
|
198
200
|
Claude Code now ships only as a Bun single-file executable; the npm package is a
|
|
199
201
|
wrapper that downloads it. patch-cc edits the JavaScript bundle embedded in the
|
|
200
|
-
binary's `.bun` section in place. It also drops the module's
|
|
201
|
-
precompiled bytecode — editing the source invalidates it anyway
|
|
202
|
-
|
|
202
|
+
binary's `.bun` section in place. It also drops the entry module's stale
|
|
203
|
+
precompiled bytecode — editing the source invalidates it anyway, and it is more
|
|
204
|
+
than half the download — so on Linux, where the ELF section is rewritten in
|
|
205
|
+
place, a patched binary is *smaller* than the original, not larger. (On macOS
|
|
206
|
+
the freed bytes are not yet reclaimed, so the file keeps its size; it still runs
|
|
207
|
+
correctly.) [docs/INTERNALS.md](docs/INTERNALS.md#the-bytecode-and-why-we-drop-it)
|
|
208
|
+
has the measurements; `patch-cc status` has yours.
|
|
203
209
|
|
|
204
210
|
See [docs/INTERNALS.md](docs/INTERNALS.md) for the container format and
|
|
205
211
|
[docs/PLAYBOOK.md](docs/PLAYBOOK.md) for repairing a patch after an update.
|
|
@@ -8,7 +8,7 @@ you want — inline and live thinking, detailed tool calls, subagent model
|
|
|
8
8
|
overrides, your own startup name, your **ChatGPT/Codex-plan GPT models as
|
|
9
9
|
native models** — and apply them to your installed `claude` in one keystroke.
|
|
10
10
|
Fully reversible: a pristine backup is kept, `patch-cc restore` puts it back.
|
|
11
|
-
|
|
11
|
+
No Node, no Bun.
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
uvx patch-cc # fullscreen menu, no install needed
|
|
@@ -63,7 +63,7 @@ patch-cc # then just run it
|
|
|
63
63
|
| Chrome & branding | Disable spinner tips | No rotating tips on the spinner |
|
|
64
64
|
| | Mark `--version` | Appends `(patched)` — or any marker you choose |
|
|
65
65
|
| | Custom startup name | Defaults to `<your username>'s Code` |
|
|
66
|
-
| | Startup org/email label | Replace the org/email on the welcome screen — or hide it |
|
|
66
|
+
| | Startup org/email label | Replace the org/email on the welcome screen — or hide it (demo mode keeps the stock line) |
|
|
67
67
|
|
|
68
68
|
## Usage
|
|
69
69
|
|
|
@@ -168,9 +168,13 @@ startup name / `--version` marker are visible tells too.
|
|
|
168
168
|
|
|
169
169
|
Claude Code now ships only as a Bun single-file executable; the npm package is a
|
|
170
170
|
wrapper that downloads it. patch-cc edits the JavaScript bundle embedded in the
|
|
171
|
-
binary's `.bun` section in place. It also drops the module's
|
|
172
|
-
precompiled bytecode — editing the source invalidates it anyway
|
|
173
|
-
|
|
171
|
+
binary's `.bun` section in place. It also drops the entry module's stale
|
|
172
|
+
precompiled bytecode — editing the source invalidates it anyway, and it is more
|
|
173
|
+
than half the download — so on Linux, where the ELF section is rewritten in
|
|
174
|
+
place, a patched binary is *smaller* than the original, not larger. (On macOS
|
|
175
|
+
the freed bytes are not yet reclaimed, so the file keeps its size; it still runs
|
|
176
|
+
correctly.) [docs/INTERNALS.md](docs/INTERNALS.md#the-bytecode-and-why-we-drop-it)
|
|
177
|
+
has the measurements; `patch-cc status` has yours.
|
|
174
178
|
|
|
175
179
|
See [docs/INTERNALS.md](docs/INTERNALS.md) for the container format and
|
|
176
180
|
[docs/PLAYBOOK.md](docs/PLAYBOOK.md) for repairing a patch after an update.
|
|
@@ -30,26 +30,44 @@ shape that already absorbs every case, found rather than bolted on.
|
|
|
30
30
|
|
|
31
31
|
- **Explicit invocations are hermetic.** A non-interactive command's arguments
|
|
32
32
|
are its whole input; no saved state may *silently* change what it does.
|
|
33
|
-
Persisted choices pre-fill the interactive UI and never act on their own
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
Persisted choices pre-fill the interactive UI and never act on their own. Two
|
|
34
|
+
flags do read state, and each *names* the state it reads: `apply --from-cache`
|
|
35
|
+
takes the remembered selection, and `apply --codex` takes your plan's
|
|
36
|
+
catalogue — asking for a Codex model is asking for the plan that describes it,
|
|
37
|
+
so the display name and context window are read from there rather than
|
|
38
|
+
invented. Neither is hidden behind a default, and absent both, the same command
|
|
39
|
+
always yields the same result. Asking for a Codex model is also the one thing
|
|
40
|
+
whose *output* can differ between two identical invocations — under either flag
|
|
41
|
+
that does it, `--codex` naming ids directly or `--from-cache` replaying a
|
|
42
|
+
remembered set that holds them (both re-read the plan at bake time): a plan
|
|
43
|
+
that cannot be reached is not an error, so the id still bakes, on its
|
|
44
|
+
fallbacks. That is the price of not guessing a context window, and it is paid
|
|
45
|
+
under flags that say so.
|
|
37
46
|
|
|
38
|
-
- **
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
- **Find by the name upstream wrote; edit the grammar node.** The authored
|
|
48
|
+
names — string literals, `case` labels, property names — and the shape of the
|
|
49
|
+
tree are what a build keeps. Never describe the syntax between them, and never
|
|
50
|
+
anchor on a minified local: that is the half a minifier regenerates. A new
|
|
51
|
+
upstream *shape* earns a narrow new branch; a new *spelling* of one shape
|
|
52
|
+
should already cost nothing. Full rules and the repair loop:
|
|
53
|
+
[PLAYBOOK.md](PLAYBOOK.md).
|
|
42
54
|
|
|
43
55
|
- **Report absent apart from broken.** A matcher that finds nothing may be a
|
|
44
56
|
shape this build simply lacks — most patches carry several — not a regression.
|
|
45
57
|
Keep "gone", "already applied", and "not on this build" as distinct signals;
|
|
46
58
|
never collapse them into one number. Which one a sub-step's silence means is
|
|
47
|
-
not guesswork: declare it (`expect=True
|
|
48
|
-
|
|
59
|
+
not guesswork: declare it (`expect=True`) so a green tick cannot cover a dead
|
|
60
|
+
feature. A step nobody declared is a step that cannot report its own death:
|
|
61
|
+
`branding` carried none, so a name badge that stopped being a bold render was
|
|
62
|
+
a green run, an unchanged banner, and a manifest asserting the new name. See
|
|
63
|
+
[PLAYBOOK.md](PLAYBOOK.md).
|
|
49
64
|
|
|
50
|
-
- **Port faithfully.** When you change a patch, verify its output against
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
- **Port faithfully.** When you change a patch, verify its output against a real
|
|
66
|
+
bundle — byte-identical where behaviour must not change. `doctor` over the
|
|
67
|
+
archived corpus is that check, and the *diff* between two sweeps is the half
|
|
68
|
+
that matters: a red build is loud on its own, but a widened locator shows up
|
|
69
|
+
only as an old build's counts quietly moving. Be able to say what every moved
|
|
70
|
+
number means. The sweep is in [PLAYBOOK.md](PLAYBOOK.md).
|
|
53
71
|
|
|
54
72
|
- **The user controls commits and releases.** Don't commit, push, or publish
|
|
55
73
|
unless asked.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Internals
|
|
2
2
|
|
|
3
|
-
How patch-cc gets from a
|
|
3
|
+
How patch-cc gets from a Claude binary to a patched, smaller one.
|
|
4
4
|
|
|
5
5
|
## The shape of a native Claude binary
|
|
6
6
|
|
|
@@ -35,32 +35,52 @@ A module record (new 52-byte format) is six such pairs — `name`, `contents`,
|
|
|
35
35
|
`sourcemap`, `bytecode`, `moduleInfo`, `bytecodeOriginPath` — followed by four
|
|
36
36
|
`u8` flags (`encoding`, `loader`, `moduleFormat`, `side`).
|
|
37
37
|
|
|
38
|
-
The module we patch is the entrypoint,
|
|
39
|
-
(
|
|
38
|
+
The module we patch is the entrypoint, which the offsets struct names by index
|
|
39
|
+
(`entry_point_id`) — the same index Bun itself resolves it by. Its `contents` is
|
|
40
|
+
the JS we edit. Its *name* is upstream's to change and we never read it:
|
|
41
|
+
2.1.229 renamed it `/$bunfs/root/src/entrypoints/cli.js` → `/$bunfs/root/cli`.
|
|
40
42
|
|
|
41
43
|
Code: `src/patch_cc/bun/blob.py`.
|
|
42
44
|
|
|
43
|
-
## The
|
|
45
|
+
## The bytecode, and why we drop it
|
|
44
46
|
|
|
45
|
-
The entry module also carries
|
|
46
|
-
|
|
47
|
+
The entry module also carries precompiled Bun **bytecode** — more than half the
|
|
48
|
+
binary. Every other module has none.
|
|
47
49
|
|
|
48
50
|
Any edit to `contents` invalidates that bytecode; Bun detects the mismatch and
|
|
49
51
|
recompiles from source at launch. So keeping it buys nothing:
|
|
50
52
|
|
|
51
53
|
| binary | size | startup |
|
|
52
54
|
|---|---|---|
|
|
53
|
-
| original (valid bytecode) |
|
|
54
|
-
| patched, bytecode kept |
|
|
55
|
-
| patched, bytecode dropped | **
|
|
55
|
+
| original (valid bytecode) | 323 MB | ~100 ms |
|
|
56
|
+
| patched, bytecode kept | 323 MB | ~650 ms |
|
|
57
|
+
| patched, bytecode dropped | **125 MB** | ~650 ms |
|
|
56
58
|
|
|
57
59
|
Patching pays the recompile cost either way, so patch-cc drops the entry
|
|
58
60
|
module's bytecode (`rebuild(..., drop_bytecode=True)`). The result runs source,
|
|
59
|
-
guaranteeing our edits are authoritative, and
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
guaranteeing our edits are authoritative, and — on Linux — is smaller by
|
|
62
|
+
exactly the bytecode.
|
|
63
|
+
|
|
64
|
+
The size figures are the **ELF** path: the `.bun` section is rewritten in place,
|
|
65
|
+
so the dropped bytecode is genuinely reclaimed (`container.verify` refuses a
|
|
66
|
+
Linux write that did not shrink). On **macOS** the file keeps its original size:
|
|
67
|
+
`macho.py` grows a segment but never shrinks one, so the freed bytes stay as
|
|
68
|
+
dead space. The binary still runs correctly (the bytecode is gone), it is just
|
|
69
|
+
not smaller — reclaiming it means shrinking the Mach-O segment and re-laying
|
|
70
|
+
`__LINKEDIT`, which is not done yet.
|
|
71
|
+
|
|
72
|
+
Those are **2.1.232's** Linux numbers, and they are a measurement rather than a
|
|
73
|
+
promise: the same table read 267 / 113 MB against 2.1.216, because the bytecode
|
|
74
|
+
grew from 154 MB to 198 MB in the fifteen builds between them (2.1.230 was
|
|
75
|
+
never published). Read the current pair off any
|
|
76
|
+
binary with `patch-cc status` rather than off this table.
|
|
77
|
+
|
|
78
|
+
Every write asserts the binary it produced carries `bytecode == 0`
|
|
79
|
+
(`container.verify`, beside the round-trip check), and `patch-cc status` reports
|
|
80
|
+
the field for an installed one. `doctor` cannot: a dry run is handed a *clean*
|
|
81
|
+
bundle, which still has its bytecode by definition. If a future Bun build makes
|
|
82
|
+
bytecode authoritative over source, that assert is the tripwire — every patch
|
|
83
|
+
would silently no-op otherwise.
|
|
64
84
|
|
|
65
85
|
## Writing it back without ballooning
|
|
66
86
|
|
|
@@ -92,20 +112,23 @@ Every patched bundle ends with a single comment line — the one description of
|
|
|
92
112
|
its shape; [PLAYBOOK.md](PLAYBOOK.md) covers what it means for matcher health:
|
|
93
113
|
|
|
94
114
|
```
|
|
95
|
-
//patch-cc {"v":1,"tool":"<version>","patches":[...],"brand":...,"
|
|
96
|
-
"org":...,"codex":{"port":8817,"models":["gpt-5.6-sol"
|
|
115
|
+
//patch-cc {"v":1,"tool":"<version>","patches":[...],"brand":...,"suffix":...,
|
|
116
|
+
"models":{...},"org":...,"codex":{"port":8817,"models":["gpt-5.6-sol"]}}
|
|
97
117
|
```
|
|
98
118
|
|
|
119
|
+
Every key after `patches` is a configurable patch's own, declared in one place
|
|
120
|
+
(`Patch.setting`) so the manifest here, the cache, and the menu cannot spell it
|
|
121
|
+
three ways. Each is written only when *that* patch landed **and** has a value
|
|
122
|
+
worth recording, so `status` can never assert a name, marker, or model the
|
|
123
|
+
bundle does not contain — and so this is the *widest* the line gets, not its
|
|
124
|
+
fixed shape.
|
|
125
|
+
|
|
99
126
|
That line is why `patch-cc status` can name exactly what is applied: several
|
|
100
127
|
patches are value flips (`verbose:!0`) that leave no other trace. A comment
|
|
101
128
|
can't collide with code and travels with the bundle through extract/repack.
|
|
102
129
|
The menu also reads it to pre-select the current patch set — the binary is the
|
|
103
130
|
state.
|
|
104
131
|
|
|
105
|
-
Every key after `patches` belongs to a patch and is written only when *that*
|
|
106
|
-
patch landed, so `status` can never assert a name, marker, or model the bundle
|
|
107
|
-
does not contain.
|
|
108
|
-
|
|
109
132
|
Each key records what was *asked for*, never what was derived from it. `codex`
|
|
110
133
|
carries model ids and a port and nothing else: a Codex model's display name and
|
|
111
134
|
context window are already baked into the bundle, and repeating them here would
|
|
@@ -120,9 +143,19 @@ rather than from a store of their own.
|
|
|
120
143
|
`~/.local/share/patch-cc/backups/`. `restore` copies it back — never an
|
|
121
144
|
inverse patch (insertions cascade, so a reverse diff is meaningless).
|
|
122
145
|
- Patching always starts from that pristine copy, so re-applying never stacks
|
|
123
|
-
edits on edits, and an apply where **
|
|
124
|
-
|
|
125
|
-
startup).
|
|
146
|
+
edits on edits, and an apply where **nothing lands** — every selected patch
|
|
147
|
+
broken, so the manifest would claim nothing — leaves the binary untouched
|
|
148
|
+
entirely (stripping bytecode for nothing would only slow startup). A patch
|
|
149
|
+
that *lands* still writes even where it changed no bytes, because landing
|
|
150
|
+
includes an override the build already satisfies: the manifest records what
|
|
151
|
+
was asked and verified present, so `status` can report it.
|
|
152
|
+
- The bundle is parsed, and any syntax error aborts before the binary or the
|
|
153
|
+
backup is touched — the two checks below answer "did we write what we meant
|
|
154
|
+
to", which a corrupt splice satisfies perfectly. The parse is the same one
|
|
155
|
+
the patches locate with, so it costs nothing extra and sits at *every* batch
|
|
156
|
+
of edits as well as on the final bytes: a patch that produces rubble is named
|
|
157
|
+
and dropped rather than aborting the run. See
|
|
158
|
+
[PLAYBOOK.md](PLAYBOOK.md#the-syntax-gate).
|
|
126
159
|
- Every write is verified: patch-cc re-extracts the JS from the binary it just
|
|
127
160
|
wrote and asserts it equals what it meant to write.
|
|
128
161
|
- Patching a binary that is already marked, when no pristine backup exists, is
|