@graftsync/skill 0.1.2 → 0.2.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/SKILL.md +50 -49
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: graft-sync
|
|
3
|
-
description: Keep local modifications ("grafts") to upstream npm packages working when upstream releases a new version. Use when a repo has a `.grafts/` directory and an upstream dependency was bumped, `graft sync` reported `needs-agent`, a graft's anchors miss or its
|
|
3
|
+
description: Keep local modifications ("grafts") to upstream npm packages working when upstream releases a new version. Use when a repo has a `.grafts/` directory and an upstream dependency was bumped, `graft sync` reported `needs-agent`, a graft's anchors miss or its tests fail after an upgrade, or you are asked to sync, repair, add, or retire a graft.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Graft sync
|
|
@@ -17,19 +17,19 @@ https://github.com/brandonroberts/graft/blob/main/docs/spec.md
|
|
|
17
17
|
|
|
18
18
|
`graft.md` frontmatter:
|
|
19
19
|
|
|
20
|
-
- `rootstock.package` / `rootstock.verified` — upstream package and the last version the
|
|
21
|
-
|
|
20
|
+
- `rootstock.package` / `rootstock.verified` — upstream package and the last version the graft
|
|
21
|
+
was verified against.
|
|
22
22
|
- `mechanism` — how it is applied (e.g. `patch`: a pnpm `patchedDependencies` patch file).
|
|
23
23
|
- `variants` — one implementation per upstream version range (`range` + `module` path).
|
|
24
24
|
Ranges are disjoint; exactly one variant applies to any version.
|
|
25
|
-
- `oracle` — the command that proves the invariants hold, run once per `mode`
|
|
26
|
-
(with `GRAFT_MODE` and `GRAFT_UPSTREAM_VERSION` set).
|
|
27
25
|
- `status` — `applied` | `conflicted` | `upstreamed` | `obsolete`.
|
|
28
26
|
|
|
29
27
|
Body sections, all required — read them before touching anything:
|
|
30
28
|
|
|
31
29
|
- **Why** — what the modification enables and why upstream doesn't do it.
|
|
32
|
-
- **Invariants** — observable behaviors that must hold
|
|
30
|
+
- **Invariants** — observable behaviors that must hold, and which of the project's tests cover
|
|
31
|
+
them. **This is the contract, and verifying it is your job:** Graft only checks that a graft
|
|
32
|
+
still *fits* (anchors, apply, install). It runs no tests.
|
|
33
33
|
- **Where to look** — the upstream area, described by behavior so you can re-find it after
|
|
34
34
|
a refactor. Trust this over file paths.
|
|
35
35
|
- **Anchors** — what each variant matches on and why it was chosen.
|
|
@@ -51,7 +51,7 @@ the project root. Exit codes: `0` ok, `1` something needs attention, `2` tooling
|
|
|
51
51
|
| Apply a variant to pristine upstream, for inspection | `graft preview <id> [--version X] [--out dir]` |
|
|
52
52
|
| Register a new variant | `graft variant add <id> --range R --module ./variants/… --verify-version X --note "…"` |
|
|
53
53
|
| Wire the package manager to the selected variants + reinstall | `graft apply` |
|
|
54
|
-
| Prove
|
|
54
|
+
| Prove the Invariants | the project's own tests (see *Invariants*) |
|
|
55
55
|
| Status, verified version, History | `graft mark <id> [--status S] [--verified X] [--history "…"]` |
|
|
56
56
|
| Where a variant fits across published versions | `graft replay <id> [--range R]` |
|
|
57
57
|
|
|
@@ -65,7 +65,7 @@ Reports from `sync` land in `.grafts/.report/` (`sync.md`, `sync.json`, and per
|
|
|
65
65
|
`verified` and wrote History. Only grafts marked `needs-agent` are yours.
|
|
66
66
|
2. **Gather context for each `needs-agent` graft**, in this order:
|
|
67
67
|
`graft show <id>` → the reasons in the sync report → `graft check <id> --version <target>` →
|
|
68
|
-
`graft diff <id>` (from `verified` to the target)
|
|
68
|
+
`graft diff <id>` (from `verified` to the target).
|
|
69
69
|
3. **Locate the new equivalent code by behavior.** Use *Where to look* and *Anchors*, then
|
|
70
70
|
the scoped diff. If a target file was removed or renamed, search the new version's
|
|
71
71
|
published files for the behavior (the pristine copy is under `.grafts/.cache/upstream/`). Upstream
|
|
@@ -81,19 +81,21 @@ Reports from `sync` land in `.grafts/.report/` (`sync.md`, `sync.json`, and per
|
|
|
81
81
|
refuses (and rolls back) if the anchors don't match at the target. Older open-ended ranges
|
|
82
82
|
are narrowed automatically; existing variant files are never touched. Then
|
|
83
83
|
`graft check <id> --version <target>` should be clean.
|
|
84
|
-
7. **
|
|
85
|
-
it wires the package manager to the new variant, installs the target, and
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
7. **Check it fits:** re-run `graft sync --version <target> --install`. With anchors now
|
|
85
|
+
matching, it wires the package manager to the new variant, installs the target, and on green
|
|
86
|
+
sets `verified` and status `applied`.
|
|
87
|
+
8. **Prove the Invariants** at the target with the project's tests: run the ones *Invariants*
|
|
88
|
+
names (and the suite), and add a test for any Invariant nothing covers. Show it fails
|
|
89
|
+
without the graft. If a test fails, the graft isn't done, whatever sync said: fix the
|
|
90
|
+
variant, or stop (see *When to stop*).
|
|
91
|
+
9. **Finish:** open a PR (see below), saying how you verified each Invariant.
|
|
89
92
|
|
|
90
93
|
## Adding a new graft
|
|
91
94
|
|
|
92
95
|
When asked to capture a modification as a graft (new, or migrating an existing patch):
|
|
93
96
|
|
|
94
97
|
1. **Scaffold:** `graft init --agent` (once; it also installs this skill), then `graft add <id> --package <pkg> --target <file>`.
|
|
95
|
-
This creates `graft.md
|
|
96
|
-
oracle stub that exits 1.
|
|
98
|
+
This creates `graft.md` and an empty variant stub (which fails loudly until written).
|
|
97
99
|
2. **Write the intent first,** with the person who owns the modification if you can: *Why*,
|
|
98
100
|
the *Invariants* (observable behaviors, one per bullet), *Where to look* (by behavior), and
|
|
99
101
|
*Anchors* (what the variant matches on and why).
|
|
@@ -106,23 +108,18 @@ When asked to capture a modification as a graft (new, or migrating an existing p
|
|
|
106
108
|
(`pnpm patch-commit` may also write a `package.json` entry; the next step replaces it).
|
|
107
109
|
4. **Apply it:** `graft apply`. This points the package manager at the
|
|
108
110
|
variant, reinstalls, and re-checks anchors.
|
|
109
|
-
5. **
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
- **
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
For a dependency's browser behavior, load it through the dev server (e.g. a one-line
|
|
122
|
-
module importing it) instead of rendering pages through a framework's dev SSR.
|
|
123
|
-
- **Cover the modes the bug lives in.** A dev-only bug needs a `dev` mode; a production
|
|
124
|
-
build may behave differently (e.g. Vite replaces `process.env` only there).
|
|
125
|
-
6. **Prove it:** `graft verify <id>`, then `graft sync` (green).
|
|
111
|
+
5. **Cover the Invariants with the project's tests.** Find the tests that exercise each
|
|
112
|
+
Invariant, or add them to the project's suite, and name them under *Invariants*. Show each
|
|
113
|
+
fails without the modification and passes with it: a test that can't fail proves nothing.
|
|
114
|
+
Also keep one pre-existing behavior the graft must not break covered.
|
|
115
|
+
- **Test what the graft changes, not the whole stack.** For a patch that stops a dependency
|
|
116
|
+
loading Node polyfills, assert it doesn't load them (e.g. via `require.cache`); you don't
|
|
117
|
+
need a browser or a build.
|
|
118
|
+
- **Browser tests** (Playwright etc.), when you need one, fail on uncaught page errors,
|
|
119
|
+
**`console.error`** messages and failed (5xx) requests: Angular's `ErrorHandler`, React
|
|
120
|
+
error boundaries and Vue's `errorHandler` catch errors and only log them. Assert something
|
|
121
|
+
visible that depends on the graft, and stop any server you start on every exit.
|
|
122
|
+
6. **Check it:** `graft sync` (green), and the project's tests pass.
|
|
126
123
|
7. **Find the variant's real range:** `graft replay <id>` checks every published version.
|
|
127
124
|
Record what you learn in *History*.
|
|
128
125
|
|
|
@@ -130,12 +127,13 @@ When asked to capture a modification as a graft (new, or migrating an existing p
|
|
|
130
127
|
|
|
131
128
|
- **Never edit an existing variant.** Older version ranges keep their variants and tests.
|
|
132
129
|
Write a new file for the new range. `graft variant add` refuses to re-register a file.
|
|
133
|
-
- **The Invariants are the contract and
|
|
134
|
-
|
|
135
|
-
- **Never weaken
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
- **Never set `verified`**
|
|
130
|
+
- **The Invariants are the contract, and you verify them.** A green sync means the change still
|
|
131
|
+
fits and installs, not that it still works. Prove the Invariants with the project's tests.
|
|
132
|
+
- **Never weaken a test** to get green: don't skip, loosen, or delete checks, and don't change
|
|
133
|
+
Invariants to match what you built. If an invariant is genuinely obsolete, say so and ask a
|
|
134
|
+
human.
|
|
135
|
+
- **Never set `verified`** (or register a variant) for a version you haven't verified the
|
|
136
|
+
Invariants at.
|
|
139
137
|
- **Fail loudly.** A graft that silently applies nothing is the worst outcome. Anchors must
|
|
140
138
|
match exactly once; don't add fuzz, catch-alls, or "skip if not found" logic.
|
|
141
139
|
- **Anchor by behavior.** Prefer stable exported names, public API lists, and user-facing
|
|
@@ -179,8 +177,8 @@ When asked to capture a modification as a graft (new, or migrating an existing p
|
|
|
179
177
|
- If the graft's variants are generated, give it a `generator: { command }` in its
|
|
180
178
|
frontmatter (`{version}` and `{out}` are substituted; e.g.
|
|
181
179
|
`node tools/cjs-to-esm/make-variant.mjs semver {version} {out}`). `graft sync` then
|
|
182
|
-
regenerates and registers a variant itself when the old one misses, and keeps it only if
|
|
183
|
-
|
|
180
|
+
regenerates and registers a variant itself when the old one misses, and keeps it only if it
|
|
181
|
+
fits and installs. If sync still hands the graft to you, its reasons say what the generator
|
|
184
182
|
did; the rejected output is under `.grafts/.report/<id>/regenerated/`. Fix the generator
|
|
185
183
|
or review that output rather than hand-patching the old variant.
|
|
186
184
|
|
|
@@ -204,13 +202,14 @@ When asked to capture a modification as a graft (new, or migrating an existing p
|
|
|
204
202
|
`{ "ref": "graft/<id>-<target>", "base": "<target>" }`. Register it with
|
|
205
203
|
`graft variant add <id> --range '>=<target>' --module ./variants/v<target>.json
|
|
206
204
|
--verify-version <target>`.
|
|
207
|
-
4.
|
|
205
|
+
4. Check it with `graft sync --version <target> --install`, then prove the Invariants with the
|
|
206
|
+
project's tests.
|
|
208
207
|
- **Repo mode** (`fork.install: none`): the fork is the product (e.g. a translated docs site),
|
|
209
|
-
nothing is installed, and
|
|
208
|
+
nothing is installed, and a green sync materializes the rebased checkout. The diff in
|
|
210
209
|
`.grafts/.report/<id>/diff.patch` is what upstream changed since the fork's base in the files
|
|
211
210
|
the fork touches. A clean rebase is not enough: upstream text that lands next to the change
|
|
212
|
-
(e.g. a new English paragraph in a translated page)
|
|
213
|
-
|
|
211
|
+
(e.g. a new English paragraph in a translated page) merges without a conflict, so run the
|
|
212
|
+
project's checks (the graft's *Invariants* say which) on the result. Same fix steps as above, with `graft sync --version <target>` (no `--install`). A
|
|
214
213
|
green sync leaves the result as branch `graft/<id>/<target>` in `.grafts/.cache/fork/<id>`;
|
|
215
214
|
fetch it from there. Never push it unless the user asks.
|
|
216
215
|
- A target can be an upstream commit between releases: `--version 22.3.0-next.3+<sha>` (the
|
|
@@ -221,7 +220,7 @@ When asked to capture a modification as a graft (new, or migrating an existing p
|
|
|
221
220
|
variant. A green sync puts the new `verified` only in the result branch; adopt it with
|
|
222
221
|
`git fetch <repo> <ref> && git read-tree -u --reset FETCH_HEAD`. On the `-agent` branch,
|
|
223
222
|
graft.md already says the target version (`status: conflicted`): resolve, then
|
|
224
|
-
`graft sync --version <target>`
|
|
223
|
+
`graft sync --version <target>` checks the working tree as it is; then run the project's checks.
|
|
225
224
|
- **Start from the prepared branch.** On `needs-agent`, the report's "Start from" line names
|
|
226
225
|
`graft/<id>/<target>-agent` in the cache clone: git's merge of the fork's change onto the
|
|
227
226
|
target, with conflict markers left only in the files it lists. Fetch it into the fork, resolve
|
|
@@ -235,7 +234,7 @@ Stop and mark the graft `conflicted` (`graft mark <id> --status conflicted --his
|
|
|
235
234
|
|
|
236
235
|
- the behavior the graft modifies no longer exists upstream, or upstream changed it in a way
|
|
237
236
|
that makes an invariant impossible or contradictory;
|
|
238
|
-
- you cannot make the
|
|
237
|
+
- you cannot make the project's tests pass for an Invariant without weakening them;
|
|
239
238
|
- upstream now does what the graft did — say so; a human decides whether to mark it
|
|
240
239
|
`upstreamed`. Graft detects the common case for you: when the variant no longer applies
|
|
241
240
|
but upstream already contains its change (for patches, the reverse patch applies cleanly),
|
|
@@ -256,7 +255,9 @@ at everything else: `GRAFT_SKILL_PATH` (this file), `GRAFT_COMMAND` (how to run
|
|
|
256
255
|
`GRAFT_TARGET_VERSION`, and `GRAFT_BRANCH` (already checked out).
|
|
257
256
|
|
|
258
257
|
- Do **not** commit, push, or open a pull request. The action re-runs `graft sync` on your
|
|
259
|
-
work and opens the PR itself: a normal PR
|
|
258
|
+
work and opens the PR itself: a normal PR when every graft fits, otherwise a draft. It can't
|
|
259
|
+
check behavior: prove the Invariants with the project's tests before you finish, and say how
|
|
260
|
+
in the PR description.
|
|
260
261
|
- Write the PR description (format below) to `GRAFT_PR_BODY_FILE`.
|
|
261
262
|
|
|
262
263
|
## PR description
|
|
@@ -272,8 +273,8 @@ at everything else: `GRAFT_SKILL_PATH` (this file), `GRAFT_COMMAND` (how to run
|
|
|
272
273
|
**What changed upstream:** <the behavior-level change, citing the scoped diff>
|
|
273
274
|
**Anchors that moved:** <anchor names, and where they went>
|
|
274
275
|
**New variant:** `variants/<file>` for `<range>` — <how it differs from the previous variant>
|
|
275
|
-
**
|
|
276
|
+
**Verified:** <which tests, covering which Invariants, passed against <package>@<target>>
|
|
276
277
|
```
|
|
277
278
|
|
|
278
|
-
For a conflicted graft, replace *New variant* and *
|
|
279
|
+
For a conflicted graft, replace *New variant* and *Verified* with **Failing invariant**,
|
|
279
280
|
**What was tried**, and **What a human needs to decide**.
|