blockpatch 1.0.0 → 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 (53) hide show
  1. package/CONTRIBUTING.md +9 -1
  2. package/README.md +100 -468
  3. package/conformance/README.md +29 -0
  4. package/conformance/cases/ambiguous-source/case.json +8 -0
  5. package/conformance/cases/ambiguous-target/case.json +8 -0
  6. package/conformance/cases/create-file/case.json +8 -0
  7. package/conformance/cases/crlf/case.json +10 -0
  8. package/conformance/cases/cross-file-relocation/case.json +12 -0
  9. package/conformance/cases/delete-existing-file/case.json +10 -0
  10. package/conformance/cases/insert-existing-file/case.json +10 -0
  11. package/conformance/cases/no-trailing-newline/case.json +10 -0
  12. package/conformance/cases/remove-file/case.json +9 -0
  13. package/conformance/cases/same-file-relocation/case.json +10 -0
  14. package/conformance/runner.mjs +221 -0
  15. package/dist/cli.js +1038 -526
  16. package/docs/behavior.md +207 -0
  17. package/docs/commands.md +88 -0
  18. package/docs/spec.md +366 -0
  19. package/examples/README.md +15 -0
  20. package/examples/create-file/README.md +9 -0
  21. package/examples/create-file/expected/file.txt +1 -0
  22. package/examples/create-file/patch.blockpatch +8 -0
  23. package/examples/create-file/work/.gitkeep +1 -0
  24. package/examples/cross-file-relocation/README.md +10 -0
  25. package/examples/cross-file-relocation/expected/source.txt +2 -0
  26. package/examples/cross-file-relocation/expected/target.txt +6 -0
  27. package/examples/cross-file-relocation/patch.blockpatch +26 -0
  28. package/examples/cross-file-relocation/work/source.txt +5 -0
  29. package/examples/cross-file-relocation/work/target.txt +3 -0
  30. package/examples/delete-existing-file/README.md +9 -0
  31. package/examples/delete-existing-file/expected/file.txt +2 -0
  32. package/examples/delete-existing-file/patch.blockpatch +10 -0
  33. package/examples/delete-existing-file/work/file.txt +3 -0
  34. package/examples/failure-ambiguous-target/README.md +9 -0
  35. package/examples/failure-ambiguous-target/patch.blockpatch +14 -0
  36. package/examples/failure-ambiguous-target/work/file.txt +5 -0
  37. package/examples/insert-existing-file/README.md +9 -0
  38. package/examples/insert-existing-file/expected/file.txt +3 -0
  39. package/examples/insert-existing-file/patch.blockpatch +10 -0
  40. package/examples/insert-existing-file/work/file.txt +2 -0
  41. package/examples/remove-file/README.md +9 -0
  42. package/examples/remove-file/expected/.gitkeep +1 -0
  43. package/examples/remove-file/patch.blockpatch +8 -0
  44. package/examples/remove-file/work/file.txt +1 -0
  45. package/examples/reverse/README.md +9 -0
  46. package/examples/reverse/expected/file.txt +4 -0
  47. package/examples/reverse/patch.blockpatch +14 -0
  48. package/examples/reverse/work/file.txt +4 -0
  49. package/examples/same-file-relocation/README.md +9 -0
  50. package/examples/same-file-relocation/expected/file.txt +4 -0
  51. package/examples/same-file-relocation/patch.blockpatch +14 -0
  52. package/examples/same-file-relocation/work/file.txt +4 -0
  53. package/package.json +13 -5
@@ -0,0 +1,9 @@
1
+ # Create File
2
+
3
+ Creates `file.txt` from a whole-file `/dev/null -> file` patch.
4
+
5
+ ```sh
6
+ blockpatch check patch.blockpatch -d work
7
+ blockpatch apply patch.blockpatch -d work
8
+ diff -u expected/file.txt work/file.txt
9
+ ```
@@ -0,0 +1 @@
1
+ created file
@@ -0,0 +1,8 @@
1
+ diff --blockpatch /dev/null b/file.txt
2
+ blockpatch version 1
3
+ blockpatch move id=move-1 payload-sha256=072a398e62ad50e40613b98e57f3e3236a471dcbd7c2b9f190440c22adc16a0f
4
+ --- /dev/null
5
+ +++ b/file.txt
6
+
7
+ @@ -0,0 +1,1 @@ blockpatch-target id=move-1
8
+ +created file
@@ -0,0 +1 @@
1
+ This directory is intentionally empty before applying the patch.
@@ -0,0 +1,10 @@
1
+ # Cross-File Relocation
2
+
3
+ Moves `movedThing` from `source.txt` to `target.txt`. Cross-file relocations use two sections tied by the same move id and payload hash.
4
+
5
+ ```sh
6
+ blockpatch check patch.blockpatch -d work
7
+ blockpatch apply patch.blockpatch -d work
8
+ diff -u expected/source.txt work/source.txt
9
+ diff -u expected/target.txt work/target.txt
10
+ ```
@@ -0,0 +1,2 @@
1
+ alpha()
2
+ omega()
@@ -0,0 +1,6 @@
1
+ class Target {
2
+ method() {}
3
+ function movedThing() {
4
+ return 42;
5
+ }
6
+ }
@@ -0,0 +1,26 @@
1
+ diff --blockpatch a/source.txt b/source.txt
2
+ blockpatch version 1
3
+ blockpatch move id=move-1 role=source payload-sha256=a990c0da5571138b0e2363af883a399fe214a137ad809c67f6530c618967a4e6
4
+ --- a/source.txt
5
+ +++ b/source.txt
6
+
7
+ @@ -1,5 +1,2 @@ blockpatch-source id=move-1
8
+ alpha()
9
+ -function movedThing() {
10
+ - return 42;
11
+ -}
12
+ omega()
13
+
14
+ diff --blockpatch a/target.txt b/target.txt
15
+ blockpatch version 1
16
+ blockpatch move id=move-1 role=target payload-sha256=a990c0da5571138b0e2363af883a399fe214a137ad809c67f6530c618967a4e6
17
+ --- a/target.txt
18
+ +++ b/target.txt
19
+
20
+ @@ -1,3 +1,6 @@ blockpatch-target id=move-1
21
+ class Target {
22
+ method() {}
23
+ +function movedThing() {
24
+ + return 42;
25
+ +}
26
+ }
@@ -0,0 +1,5 @@
1
+ alpha()
2
+ function movedThing() {
3
+ return 42;
4
+ }
5
+ omega()
@@ -0,0 +1,3 @@
1
+ class Target {
2
+ method() {}
3
+ }
@@ -0,0 +1,9 @@
1
+ # Delete Existing File
2
+
3
+ Deletes a patch-carried payload from an existing file with a source-only hunk.
4
+
5
+ ```sh
6
+ blockpatch check patch.blockpatch -d work
7
+ blockpatch apply patch.blockpatch -d work
8
+ diff -u expected/file.txt work/file.txt
9
+ ```
@@ -0,0 +1,2 @@
1
+ alpha
2
+ omega
@@ -0,0 +1,10 @@
1
+ diff --blockpatch a/file.txt b/file.txt
2
+ blockpatch version 1
3
+ blockpatch move id=move-1 payload-sha256=5dbe6af8d3a2a31f6696ebdae9e590977a19b827ec8e0a22ea1e3decf1a79b77
4
+ --- a/file.txt
5
+ +++ b/file.txt
6
+
7
+ @@ -1,3 +1,2 @@ blockpatch-source id=move-1
8
+ alpha
9
+ -remove me
10
+ omega
@@ -0,0 +1,3 @@
1
+ alpha
2
+ remove me
3
+ omega
@@ -0,0 +1,9 @@
1
+ # Failure: Ambiguous Target
2
+
3
+ Demonstrates strict target matching. The target anchor appears twice, so `blockpatch` refuses to guess.
4
+
5
+ ```sh
6
+ blockpatch check patch.blockpatch -d work
7
+ ```
8
+
9
+ Expected error: `Target anchor is ambiguous`.
@@ -0,0 +1,14 @@
1
+ diff --blockpatch a/file.txt b/file.txt
2
+ blockpatch version 1
3
+ blockpatch move id=move-1 payload-sha256=f721166071c491fd38ac82a8432ecc349f39f537a969054ab2c8d3175c731e7e
4
+ --- a/file.txt
5
+ +++ b/file.txt
6
+
7
+ @@ -1,3 +1,2 @@ blockpatch-source id=move-1
8
+ alpha
9
+ -move me
10
+ omega
11
+
12
+ @@ -4,1 +4,2 @@ blockpatch-target id=move-1
13
+ target
14
+ +move me
@@ -0,0 +1,5 @@
1
+ alpha
2
+ move me
3
+ omega
4
+ target
5
+ target
@@ -0,0 +1,9 @@
1
+ # Insert Existing File
2
+
3
+ Inserts a patch-carried payload into an existing file with a target-only hunk.
4
+
5
+ ```sh
6
+ blockpatch check patch.blockpatch -d work
7
+ blockpatch apply patch.blockpatch -d work
8
+ diff -u expected/file.txt work/file.txt
9
+ ```
@@ -0,0 +1,3 @@
1
+ alpha
2
+ inserted line
3
+ omega
@@ -0,0 +1,10 @@
1
+ diff --blockpatch a/file.txt b/file.txt
2
+ blockpatch version 1
3
+ blockpatch move id=move-1 payload-sha256=cbfeef0cd60ab2c01e036d23082a1f19ea3f5153d9cffde8790ad0152a3830f5
4
+ --- a/file.txt
5
+ +++ b/file.txt
6
+
7
+ @@ -1,2 +1,3 @@ blockpatch-target id=move-1
8
+ alpha
9
+ +inserted line
10
+ omega
@@ -0,0 +1,2 @@
1
+ alpha
2
+ omega
@@ -0,0 +1,9 @@
1
+ # Remove File
2
+
3
+ Removes `file.txt` with a whole-file `file -> /dev/null` patch.
4
+
5
+ ```sh
6
+ blockpatch check patch.blockpatch -d work
7
+ blockpatch apply patch.blockpatch -d work
8
+ test ! -e work/file.txt
9
+ ```
@@ -0,0 +1 @@
1
+ After applying the patch, file.txt should not exist.
@@ -0,0 +1,8 @@
1
+ diff --blockpatch a/file.txt /dev/null
2
+ blockpatch version 1
3
+ blockpatch move id=move-1 payload-sha256=4da5a83256114db88b111676cf3b2f4a04f202d3d7fc99417cac1ba5145713e2
4
+ --- a/file.txt
5
+ +++ /dev/null
6
+
7
+ @@ -1,1 +0,0 @@ blockpatch-source id=move-1
8
+ -obsolete file
@@ -0,0 +1 @@
1
+ obsolete file
@@ -0,0 +1,9 @@
1
+ # Reverse
2
+
3
+ Applies the same relocation patch in reverse. The `work/` tree starts in the already-applied state and `-R` restores the original ordering.
4
+
5
+ ```sh
6
+ blockpatch check -R patch.blockpatch -d work
7
+ blockpatch apply -R patch.blockpatch -d work
8
+ diff -u expected/file.txt work/file.txt
9
+ ```
@@ -0,0 +1,4 @@
1
+ alpha
2
+ move me
3
+ omega
4
+ target
@@ -0,0 +1,14 @@
1
+ diff --blockpatch a/file.txt b/file.txt
2
+ blockpatch version 1
3
+ blockpatch move id=move-1 payload-sha256=f721166071c491fd38ac82a8432ecc349f39f537a969054ab2c8d3175c731e7e
4
+ --- a/file.txt
5
+ +++ b/file.txt
6
+
7
+ @@ -1,3 +1,2 @@ blockpatch-source id=move-1
8
+ alpha
9
+ -move me
10
+ omega
11
+
12
+ @@ -4,1 +4,2 @@ blockpatch-target id=move-1
13
+ target
14
+ +move me
@@ -0,0 +1,4 @@
1
+ alpha
2
+ omega
3
+ target
4
+ move me
@@ -0,0 +1,9 @@
1
+ # Same-File Relocation
2
+
3
+ Moves `move me` from between `alpha` and `omega` to after `target` in the same file.
4
+
5
+ ```sh
6
+ blockpatch check patch.blockpatch -d work
7
+ blockpatch apply patch.blockpatch -d work
8
+ diff -u expected/file.txt work/file.txt
9
+ ```
@@ -0,0 +1,4 @@
1
+ alpha
2
+ omega
3
+ target
4
+ move me
@@ -0,0 +1,14 @@
1
+ diff --blockpatch a/file.txt b/file.txt
2
+ blockpatch version 1
3
+ blockpatch move id=move-1 payload-sha256=f721166071c491fd38ac82a8432ecc349f39f537a969054ab2c8d3175c731e7e
4
+ --- a/file.txt
5
+ +++ b/file.txt
6
+
7
+ @@ -1,3 +1,2 @@ blockpatch-source id=move-1
8
+ alpha
9
+ -move me
10
+ omega
11
+
12
+ @@ -4,1 +4,2 @@ blockpatch-target id=move-1
13
+ target
14
+ +move me
@@ -0,0 +1,4 @@
1
+ alpha
2
+ move me
3
+ omega
4
+ target
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "blockpatch",
3
- "version": "1.0.0",
4
- "description": "Anchored text block relocation patches",
3
+ "version": "1.1.1",
4
+ "description": "Hash-verified, reviewable block-move patches for coding agents",
5
+ "packageManager": "bun@1.3.14",
5
6
  "type": "module",
6
7
  "license": "MIT",
7
8
  "repository": {
@@ -21,10 +22,14 @@
21
22
  "agent"
22
23
  ],
23
24
  "bin": {
24
- "blockpatch": "dist/cli.js"
25
+ "blockpatch": "dist/cli.js",
26
+ "blockpatch-conformance": "conformance/runner.mjs"
25
27
  },
26
28
  "files": [
27
29
  "dist",
30
+ "docs",
31
+ "examples",
32
+ "conformance",
28
33
  "README.md",
29
34
  "CONTRIBUTING.md",
30
35
  "LICENSE"
@@ -34,12 +39,15 @@
34
39
  "typecheck": "tsc -p tsconfig.json --noEmit",
35
40
  "build": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\" && bun build ./src/cli.ts --target=node --outdir=dist",
36
41
  "smoke:dist": "node test/built-cli-smoke.mjs",
37
- "prepublishOnly": "bun run typecheck && bun test && bun run build",
42
+ "smoke:pack": "node test/packed-cli-smoke.mjs",
43
+ "conformance": "node conformance/runner.mjs node dist/cli.js",
44
+ "prepublishOnly": "bun run typecheck && bun test && bun run build && npm run smoke:dist && npm run smoke:pack",
45
+ "pack:dry": "npm pack --dry-run",
38
46
  "publish:dry": "npm publish --dry-run"
39
47
  },
40
48
  "devDependencies": {
41
49
  "@types/bun": "^1.3.14",
42
- "@types/node": "^26.1.0",
50
+ "@types/node": "^20",
43
51
  "typescript": "^5.8.3"
44
52
  },
45
53
  "engines": {