patch-cc 0.2.3__tar.gz → 0.2.4__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.3 → patch_cc-0.2.4}/PKG-INFO +2 -2
- {patch_cc-0.2.3 → patch_cc-0.2.4}/docs/PLAYBOOK.md +12 -4
- {patch_cc-0.2.3 → patch_cc-0.2.4}/pyproject.toml +1 -1
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/__init__.py +1 -1
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/cli.py +0 -5
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/doctor.py +9 -8
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patcher.py +11 -9
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patches/__init__.py +0 -2
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patches/base.py +0 -5
- {patch_cc-0.2.3 → patch_cc-0.2.4}/uv.lock +1 -1
- {patch_cc-0.2.3 → patch_cc-0.2.4}/.github/workflows/ci.yml +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/.github/workflows/release.yml +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/.gitignore +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/AGENTS.md +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/CLAUDE.md +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/LICENSE +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/README.md +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/docs/CONDUCT.md +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/docs/INTERNALS.md +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/docs/demo.gif +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/bun/__init__.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/bun/blob.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/bun/container.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/bun/elf.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/bun/errors.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/bun/macho.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/cache.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/codex/__init__.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/codex/gateway.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/codex/models.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/codex/oauth.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/codex/translate.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/locate.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/menu.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patches/agents.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patches/chrome.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patches/codex.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patches/output.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patches/streaming.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/patches/thinking.py +0 -0
- {patch_cc-0.2.3 → patch_cc-0.2.4}/src/patch_cc/ui.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: patch-cc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
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
|
|
@@ -116,10 +116,18 @@ can finish.
|
|
|
116
116
|
Every patched bundle ends with one comment line recording what was applied; its
|
|
117
117
|
shape lives in [INTERNALS.md](INTERNALS.md#the-manifest). What matters here is
|
|
118
118
|
that it makes `status` a parse instead of a guess — several patches are value
|
|
119
|
-
flips (`verbose:!0`) that leave no other fingerprint — and that
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
flips (`verbose:!0`) that leave no other fingerprint — and that it is the
|
|
120
|
+
**only** evidence `is_patched` accepts. Authorship is declared, never inferred:
|
|
121
|
+
`is_patched` once also took side effects of our edits as proof — the `__cc_`
|
|
122
|
+
identifier prefix, the old `--version` marker — until 2.1.227 shipped
|
|
123
|
+
`__cc_name`/`__cc_line`/`__cc_set` shell variables of its own and every
|
|
124
|
+
pristine install read as patched, hard-blocking `apply`. A prefix tracks
|
|
125
|
+
upstream's naming fashion, never authorship (the same lesson as the `.enum(`
|
|
126
|
+
callee above), and once upstream ships it, it fires on every later build, so no
|
|
127
|
+
narrowing rescues an inferred fingerprint — `__cc_line` was already both our
|
|
128
|
+
arrow-param and their shell variable. Binaries patched by pre-manifest versions
|
|
129
|
+
therefore read as clean, which costs nothing now that Claude's daily
|
|
130
|
+
auto-update has long since replaced that population.
|
|
123
131
|
|
|
124
132
|
## How resilience is detected
|
|
125
133
|
|
|
@@ -525,11 +525,6 @@ def cmd_status(args) -> int:
|
|
|
525
525
|
if isinstance(codex.get("port"), int):
|
|
526
526
|
style, note = gateway_note(codex["port"])
|
|
527
527
|
console.print(f" gateway: [{style}]{note}[/{style}]")
|
|
528
|
-
elif st.patched:
|
|
529
|
-
console.print(
|
|
530
|
-
" [dim]patched by an older patch-cc (no manifest); "
|
|
531
|
-
"re-apply to record one[/dim]"
|
|
532
|
-
)
|
|
533
528
|
console.print(
|
|
534
529
|
f" bytecode: "
|
|
535
530
|
f"{'stripped' if st.bytecode_stripped else f'{st.bytecode_size / 1e6:.0f} MB present'}"
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Two different questions, deliberately kept apart:
|
|
4
4
|
|
|
5
5
|
* **status** -- is the *installed* binary patched right now? Answered by the
|
|
6
|
-
manifest comment every patched bundle ends with
|
|
7
|
-
|
|
6
|
+
manifest comment every patched bundle ends with, and the bytecode-stripped
|
|
7
|
+
invariant.
|
|
8
8
|
* **dryrun** -- would our patches still apply to *this* bundle? Answered by
|
|
9
9
|
running every patch and reporting per-step hits, so a silently drifted
|
|
10
10
|
matcher shows up as a concrete "reducer.message_stop missed" instead of a
|
|
@@ -21,20 +21,23 @@ from dataclasses import dataclass, field
|
|
|
21
21
|
|
|
22
22
|
from .bun import Bundle
|
|
23
23
|
from .codex.models import CodexModel
|
|
24
|
-
from .patcher import
|
|
24
|
+
from .patcher import read_manifest
|
|
25
25
|
from .patches import ALL_PATCHES, Options, Outcome, Patch
|
|
26
26
|
from .patches.agents import INHERIT, BuiltinAgent, discover_agents, discover_models
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@dataclass(slots=True)
|
|
30
30
|
class Status:
|
|
31
|
-
patched: bool
|
|
32
31
|
bytecode_stripped: bool
|
|
33
32
|
bytecode_size: int
|
|
34
33
|
#: Parsed manifest for binaries patched by this tool; ``None`` when the
|
|
35
|
-
#: binary is pristine
|
|
34
|
+
#: binary is pristine.
|
|
36
35
|
manifest: dict | None
|
|
37
36
|
|
|
37
|
+
@property
|
|
38
|
+
def patched(self) -> bool:
|
|
39
|
+
return self.manifest is not None
|
|
40
|
+
|
|
38
41
|
@property
|
|
39
42
|
def patch_ids(self) -> list[str]:
|
|
40
43
|
if not self.manifest:
|
|
@@ -48,12 +51,10 @@ class Status:
|
|
|
48
51
|
|
|
49
52
|
|
|
50
53
|
def status(bundle: Bundle) -> Status:
|
|
51
|
-
source = bundle.source
|
|
52
54
|
return Status(
|
|
53
|
-
patched=is_patched(source),
|
|
54
55
|
bytecode_stripped=bundle.bytecode_size == 0,
|
|
55
56
|
bytecode_size=bundle.bytecode_size,
|
|
56
|
-
manifest=read_manifest(source),
|
|
57
|
+
manifest=read_manifest(bundle.source),
|
|
57
58
|
)
|
|
58
59
|
|
|
59
60
|
|
|
@@ -11,7 +11,7 @@ from pathlib import Path
|
|
|
11
11
|
|
|
12
12
|
from . import __version__, locate
|
|
13
13
|
from .bun import Bundle, container
|
|
14
|
-
from .patches import ALL_PATCHES, DEFAULT_SUFFIX,
|
|
14
|
+
from .patches import ALL_PATCHES, DEFAULT_SUFFIX, Options, Outcome, Patch
|
|
15
15
|
|
|
16
16
|
#: Every patched bundle ends with one comment line recording exactly what was
|
|
17
17
|
#: applied. Comments cannot collide with code, survive re-extraction, and make
|
|
@@ -19,9 +19,6 @@ from .patches import ALL_PATCHES, DEFAULT_SUFFIX, SENTINEL, Options, Outcome, Pa
|
|
|
19
19
|
#: fingerprint.
|
|
20
20
|
MANIFEST_PREFIX = "//patch-cc "
|
|
21
21
|
|
|
22
|
-
#: Fingerprints of binaries patched by versions before the manifest existed.
|
|
23
|
-
_LEGACY_MARKER = "(Claude Code)\\n" + DEFAULT_SUFFIX
|
|
24
|
-
|
|
25
22
|
|
|
26
23
|
class AlreadyPatchedError(RuntimeError):
|
|
27
24
|
"""The only source available is already patched; patching it would stack.
|
|
@@ -132,11 +129,16 @@ def read_manifest(source: str) -> dict | None:
|
|
|
132
129
|
|
|
133
130
|
|
|
134
131
|
def is_patched(source: str) -> bool:
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
)
|
|
132
|
+
"""Whether the bundle carries our manifest -- the one mark of our work.
|
|
133
|
+
|
|
134
|
+
Authorship is declared, never inferred. This used to also sniff side
|
|
135
|
+
effects of our edits (the ``__cc_`` identifier prefix, the old
|
|
136
|
+
``--version`` marker), until 2.1.227 shipped ``__cc_``-prefixed shell
|
|
137
|
+
variables of its own and every pristine install read as patched. An
|
|
138
|
+
inferred fingerprint is a bet that upstream's vocabulary never overlaps
|
|
139
|
+
ours, and once upstream ships it, it fires on every build after, forever.
|
|
140
|
+
"""
|
|
141
|
+
return read_manifest(source) is not None
|
|
140
142
|
|
|
141
143
|
|
|
142
144
|
def selected_patches(ids: list[str]) -> list[Patch]:
|
|
@@ -22,7 +22,6 @@ from .base import (
|
|
|
22
22
|
GROUP_CHROME,
|
|
23
23
|
GROUP_MODELS,
|
|
24
24
|
GROUP_OUTPUT,
|
|
25
|
-
SENTINEL,
|
|
26
25
|
Options,
|
|
27
26
|
Outcome,
|
|
28
27
|
Patch,
|
|
@@ -61,7 +60,6 @@ __all__ = [
|
|
|
61
60
|
"DEFAULT_BRAND",
|
|
62
61
|
"DEFAULT_SUFFIX",
|
|
63
62
|
"GROUP_ORDER",
|
|
64
|
-
"SENTINEL",
|
|
65
63
|
"Options",
|
|
66
64
|
"Outcome",
|
|
67
65
|
"Patch",
|
|
@@ -32,11 +32,6 @@ from ..codex import DEFAULT_PORT
|
|
|
32
32
|
if TYPE_CHECKING:
|
|
33
33
|
from ..codex.models import CodexModel
|
|
34
34
|
|
|
35
|
-
#: Prefix for every identifier we inject. These are the only reliable
|
|
36
|
-
#: fingerprints of our work -- value flips like ``verbose:!0`` are
|
|
37
|
-
#: indistinguishable from the 11 that upstream already ships.
|
|
38
|
-
SENTINEL = "__cc_"
|
|
39
|
-
|
|
40
35
|
# Groups, in display order: what renders, what runs (and how hard), how it is
|
|
41
36
|
# dressed. Generic on purpose -- a group named after a feature (Thinking,
|
|
42
37
|
# Subagents, Codex) fits exactly that feature, and the next patch that is
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|