fmddr-skills 0.6.2 → 0.6.4

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.md CHANGED
@@ -8,7 +8,6 @@ Claude Code, Cursor, and any agent that reads `AGENTS.md`.
8
8
  | `fmddr-setup` | "set up fmddr", "install fmddr", "index my DDR", fmddr not found in PATH | Install fmddr and build the index for a solution |
9
9
  | `fmddr` | FileMaker / DDR / fmp12 / Profile.xml / "where is X used" / refactor talk | Recognize when to reach for `fmddr` and use it correctly |
10
10
  | `fmddr-issue` | "report a bug", "file an issue", "feature request" — for fmddr | Open a high-quality issue at proofsh/fmddr (with severity) |
11
- | `fmddr-release` | "release fmddr", "cut a patch", "publish to PyPI" | End-to-end release flow: bump, changelog, build, tag, publish |
12
11
 
13
12
  ## Install
14
13
 
@@ -49,10 +48,10 @@ Compatible with any agent that picks up `AGENTS.md` from the project root
49
48
 
50
49
  ```sh
51
50
  mkdir -p ~/.claude/skills
52
- cp -R skills/fmddr ~/.claude/skills/
53
- cp -R skills/fmddr-setup ~/.claude/skills/
54
- cp -R skills/fmddr-issue ~/.claude/skills/
55
- cp -R skills/fmddr-release ~/.claude/skills/
51
+ cp -R skills/fmddr ~/.claude/skills/
52
+ cp -R skills/fmddr-setup ~/.claude/skills/
53
+ cp -R skills/fmddr-issue ~/.claude/skills/
54
+ cp -R skills/fmddr-generate-docs ~/.claude/skills/
56
55
  ```
57
56
 
58
57
  ## Layout
@@ -62,17 +61,17 @@ skills/
62
61
  ├── package.json ← npm package (fmddr-skills)
63
62
  ├── bin/
64
63
  │ └── install.js ← npx entry point
64
+ ├── fmddr/
65
+ │ └── SKILL.md
65
66
  ├── fmddr-setup/
66
67
  │ └── SKILL.md
67
- ├── fmddr/
68
+ ├── fmddr-generate-docs/
68
69
  │ └── SKILL.md
69
- ├── fmddr-issue/
70
- ├── SKILL.md
71
- └── templates/
72
- ├── bug-report.md
73
- └── feature-request.md
74
- └── fmddr-release/
75
- └── SKILL.md
70
+ └── fmddr-issue/
71
+ ├── SKILL.md
72
+ └── templates/
73
+ ├── bug-report.md
74
+ └── feature-request.md
76
75
  ```
77
76
 
78
77
  ## Updating
package/bin/install.js CHANGED
@@ -5,7 +5,7 @@ const fs = require("fs");
5
5
  const path = require("path");
6
6
  const os = require("os");
7
7
 
8
- const ALL_SKILLS = ["fmddr", "fmddr-generate-docs", "fmddr-issue", "fmddr-release", "fmddr-setup"];
8
+ const ALL_SKILLS = ["fmddr", "fmddr-generate-docs", "fmddr-issue", "fmddr-setup"];
9
9
 
10
10
  const args = process.argv.slice(2);
11
11
  const showHelp = args.includes("--help") || args.includes("-h");
package/fmddr/SKILL.md CHANGED
@@ -58,6 +58,33 @@ the tool:
58
58
  | "Search for anything called `…`" | `fmddr search "<fts5-query>"` |
59
59
  | "Explode / split the DDR into files" | `fmddr split` or `fmddr split-savexml` |
60
60
  | "What's slow on the server?" / TopCallStats.log analysis | `fmddr tcs index <log>` then `fmddr tcs slowest` / `hotspots` |
61
+ | "Show me this visually" / "open in canvas" / "visualize" | `fmddr canvas launch` or `fmddr canvas view --field/--script/--layout/--table/--relationship` |
62
+
63
+ ### Proactively suggest canvas
64
+
65
+ After any query that surfaces a specific script, field, or table, offer
66
+ canvas as a natural next step — especially if the result has multiple
67
+ references or a complex call chain. Good moments:
68
+
69
+ - After `fmddr field references` / `script-refs` / `on-layouts` → suggest
70
+ `fmddr canvas view --field "Table::Field"` to see the full reference graph visually.
71
+ - After `fmddr script show` / `script chain` / `script calls` → suggest
72
+ `fmddr canvas view --script "Script Name"` to open focused on that script's
73
+ call graph (called scripts, navigated layouts, touched TOs).
74
+ - After `fmddr layout show` / `on-layouts` results → suggest
75
+ `fmddr canvas view --layout "Layout Name"` to see the layout's bound TO and
76
+ which scripts navigate to it.
77
+ - After finding a table or TO (e.g., `fmddr table fields`) → suggest
78
+ `fmddr canvas view --table "TableName"` to explore relationships, layouts, and scripts.
79
+ - After `fmddr graph path` or a relationship query → suggest
80
+ `fmddr canvas view --relationship "LeftTO:RightTO"` to visualise the join.
81
+ - If the user says "open in canvas", "show me this visually", or "visualize"
82
+ → run the appropriate `canvas view` or `canvas launch` command immediately without asking.
83
+
84
+ `canvas launch` opens a browser tab with the full canvas. `canvas view` supports
85
+ every entity type — `--field`, `--script`, `--layout`, `--table`, `--relationship`
86
+ — and pre-populates the canvas with that entity's reference graph. Pass `--no-open`
87
+ to print the shareable `?v=` URL without opening the browser.
61
88
 
62
89
  ### Anti-signals (do **not** invoke)
63
90
  - The user is working in a FileMaker GUI and just wants to chat about
@@ -232,6 +259,28 @@ fmddr tcs hotspots --by table --limit 20 # busiest tables
232
259
  Re-imports of the same log are blocked by SHA; pass `--force` to replace
233
260
  or `--reset` to wipe all prior runs first. TCS data survives `fmddr index --force`.
234
261
 
262
+ **"Open the visual canvas browser":**
263
+ ```sh
264
+ fmddr canvas launch # blank canvas, browse freely
265
+ fmddr canvas launch --script "Batch Process Orders" # open focused on a script
266
+ fmddr canvas launch --field "Customer::Email" # open focused on a field
267
+ fmddr canvas launch --table "Customer" # open focused on a table
268
+
269
+ # Pre-populate with the full reference graph for any entity type:
270
+ fmddr canvas view --field "Customer::Email" # field ref graph
271
+ fmddr canvas view --script "Save Case Request" # script call/nav graph
272
+ fmddr canvas view --layout "Customer Detail" # layout context graph
273
+ fmddr canvas view --table "Customer" # TO neighbourhood graph
274
+ fmddr canvas view --relationship "Customer:Orders" # relationship join graph
275
+ fmddr canvas view --relationship 42 # by numeric id
276
+
277
+ # Add --no-open to any canvas view command to print the ?v= URL instead:
278
+ fmddr canvas view --field "Customer::Email" --no-open
279
+ ```
280
+ Canvas persists node positions across reloads (localStorage). "Reset view"
281
+ clears the saved state. Multiple `--exclude-folder` globs can strip Trash /
282
+ Backup script folders from the `canvas view` graph.
283
+
235
284
  **"Refresh the split tree after a SaveAsXML export, preserving folders":**
236
285
  ```sh
237
286
  fmddr split-savexml "Profile FLX May 5 2026.xml" \
@@ -240,6 +289,113 @@ fmddr split-savexml "Profile FLX May 5 2026.xml" \
240
289
  fmddr index-savexml "Profile FLX May 5 2026.xml" --out ./profile.fmddr.db
241
290
  ```
242
291
 
292
+ ## Canvas — visual DDR explorer
293
+
294
+ Canvas is a local browser-based node graph that lets users visually explore
295
+ the structure of their FileMaker solution. It runs against the same `.fmddr.db`
296
+ index as the CLI queries — no extra indexing needed.
297
+
298
+ ### What canvas shows
299
+
300
+ Each entity in the solution is a draggable **node**:
301
+
302
+ | Node type | Shows |
303
+ | ----------------- | ------------------------------------------------------------ |
304
+ | Base table | All fields with type/badge icons (calc, global, key, etc.) |
305
+ | Table occurrence | Fields inherited from the base table |
306
+ | Script | Name, folder, step count; double-click to view steps |
307
+ | Layout | Wireframe thumbnail, object count, bound table occurrence |
308
+ | Relationship | Left TO ⇄ Right TO with cardinality and join predicates |
309
+
310
+ Edges connect nodes to show references: which scripts use a field, which
311
+ layouts are on a table, which scripts call which other scripts, etc.
312
+
313
+ ### When canvas beats text output
314
+
315
+ Prefer canvas when:
316
+ - The result has **many cross-references** (e.g. a field used in 20 scripts
317
+ and 8 layouts — the graph shows the shape at a glance).
318
+ - The user wants to **explore** rather than answer a specific question.
319
+ - You want a **shareable snapshot** of a specific view to hand off.
320
+ - The question involves **relationships between multiple entities**
321
+ (script chains, layout-to-TO linkages, field dependency webs).
322
+
323
+ Stick to text (`field references`, `script chain`, etc.) when the user
324
+ needs the raw data for scripting, piping, or a quick yes/no answer.
325
+
326
+ ### Command surface
327
+
328
+ ```sh
329
+ # Open a blank canvas (browse freely)
330
+ fmddr canvas launch --db <path>
331
+
332
+ # Open focused on one entity (canvas starts with that node selected)
333
+ fmddr canvas launch --field "Table::Field"
334
+ fmddr canvas launch --script "Script Name"
335
+ fmddr canvas launch --table "TableName"
336
+
337
+ # Pre-populate with the full reference graph for any entity type
338
+ # Each command opens the canvas with a ?v= URL pre-loaded with the graph.
339
+ # Add --no-open to print the URL instead of opening the browser.
340
+
341
+ # Field — root = canonical TO, children = every referencing script/layout/relationship
342
+ fmddr canvas view --field "Table::Field"
343
+ fmddr canvas view --field "Table::Field" --no-open # print ?v= URL only
344
+
345
+ # Script — root = script, children = called scripts, navigated layouts, touched TOs
346
+ fmddr canvas view --script "Script Name"
347
+ fmddr canvas view --script "Script Name" --no-open
348
+
349
+ # Layout — root = layout, children = bound TO, scripts that navigate here
350
+ fmddr canvas view --layout "Layout Name"
351
+ fmddr canvas view --layout "Layout Name" --no-open
352
+
353
+ # Table occurrence — root = TO, children = relationships, related TOs, layouts, scripts
354
+ # Accepts: TO name, base table name, or numeric id
355
+ fmddr canvas view --table "CustomerTO"
356
+ fmddr canvas view --table "Customer" # base table name → first TO
357
+ fmddr canvas view --table 42 # numeric TO id
358
+
359
+ # Relationship — root = relationship, children = left TO and right TO
360
+ # Accepts: numeric id or "LeftTO:RightTO"
361
+ fmddr canvas view --relationship 42
362
+ fmddr canvas view --relationship "Customer:Orders"
363
+
364
+ # Filter which reference kinds appear in the graph (--field only)
365
+ fmddr canvas view --field "Table::Field" --kinds scripts,layouts
366
+
367
+ # Strip Trash/Backup/archive script folders from the graph
368
+ fmddr canvas view --field "Table::Field" --exclude-folder "Trash" --exclude-folder "*Backup*"
369
+ fmddr canvas view --script "Script Name" --exclude-folder "*Backup*"
370
+ ```
371
+
372
+ ### URL structure
373
+
374
+ Canvas uses two URL parameters:
375
+
376
+ **`?v=<token>`** — pre-loaded view. The CLI posts the node/edge payload to the
377
+ local server and gets back a short token. The URL opens with the full graph
378
+ already rendered. Tokens expire after 24 hours; re-run `canvas view` to
379
+ regenerate. Use `--no-open` to print the URL for sharing or bookmarking.
380
+
381
+ **`?focus=<ref>`** — single-entity focus. Encodes which node to highlight on
382
+ load. Format:
383
+ - `field:<toId>.<fieldId>` — a specific field on a specific table occurrence
384
+ - `to:<toId>` — a table occurrence
385
+ - `script:<scriptId>` — a script
386
+ - `layout:<layoutId>` — a layout
387
+
388
+ The IDs are numeric synth IDs from the index, not names. `canvas launch
389
+ --field/--script/--table` handles the resolution automatically — agents
390
+ don't need to construct these manually.
391
+
392
+ ### Canvas persists state
393
+
394
+ Node positions and viewport are saved to `localStorage` (keyed per DB).
395
+ Reloading the browser restores the canvas exactly as the user left it.
396
+ "Reset view" clears the saved state. `?v=` and `?focus=` URLs always take
397
+ precedence over saved state.
398
+
243
399
  ## Filing bugs & feature requests against fmddr
244
400
 
245
401
  If `fmddr` itself misbehaves, ask the user whether to file an issue at
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fmddr-skills",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Claude Code skills for fmddr — FileMaker DDR analyzer",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -25,7 +25,6 @@
25
25
  "fmddr/",
26
26
  "fmddr-generate-docs/",
27
27
  "fmddr-issue/",
28
- "fmddr-release/",
29
28
  "fmddr-setup/"
30
29
  ],
31
30
  "engines": {
@@ -1,316 +0,0 @@
1
- ---
2
- name: fmddr-release
3
- description: Cut a new fmddr release end-to-end — bump version, update CHANGELOG, refresh docs if user-visible surface changed, sync and publish the fmddr-skills npm package, tag, build sdist+wheel, publish to PyPI, and create the GitHub release with artifacts attached. Use when the user says "release fmddr", "cut a patch release", "release X.Y.Z", "ship 0.2.x", "publish to PyPI", "tag a release", or after a bugfix/feature has landed on `main` and they want it shipped. Handles both bugfix → PR → merge → release flows and direct-on-main releases. Knows which docs auto-sync from the repo root (version banner, CHANGELOG page) and which are hand-written and must be updated for new commands/flags/output shapes before shipping.
4
- ---
5
-
6
- # fmddr — cut a release
7
-
8
- The release process touches **four** version surfaces that must all agree.
9
- Forgetting one (commonly `src/fmddr/__init__.py`) ships a release where
10
- `fmddr --version` lies. Walk every step in order; do not skip ahead.
11
-
12
- ## Version surfaces — keep these in sync
13
-
14
- | File | Format |
15
- | -------------------------- | ---------------------------- |
16
- | `pyproject.toml` | `version = "X.Y.Z"` |
17
- | `src/fmddr/__init__.py` | `__version__ = "X.Y.Z"` |
18
- | `CHANGELOG.md` | `## [X.Y.Z] — YYYY-MM-DD` |
19
- | Git tag | `vX.Y.Z` (note the `v`) |
20
-
21
- The npm package (`skills/package.json`) has its own version and is bumped
22
- separately in step 2b. It does not need to match the Python version.
23
-
24
- Pre-1.0 versioning per `CHANGELOG.md`: `0.MINOR.PATCH` — `MINOR` bumps for
25
- new public surface, `PATCH` for bugfixes. Pick the right one before
26
- starting; don't ask mid-flow.
27
-
28
- ## Docs — what self-syncs vs. what doesn't
29
-
30
- The Fumadocs site under `docs/` auto-syncs two things from the repo root
31
- at build time, so the release process never edits them by hand:
32
-
33
- - `docs/lib/version.ts` reads `version` from `pyproject.toml` → drives
34
- the home-page version banner.
35
- - `docs/scripts/sync-changelog.mjs` mirrors `CHANGELOG.md` →
36
- `docs/content/docs/changelog.md` (gitignored). Runs before `dev` /
37
- `build`.
38
-
39
- So a pure bugfix patch release needs **no** docs commits — once the docs
40
- deploy fires, both surfaces pick up the new version and changelog
41
- automatically.
42
-
43
- Everything else is hand-written and **must** be updated before cutting
44
- the release. The doc edits belong in the feature/fix PR, not the
45
- `Release X.Y.Z` commit. Check each that applies to the release:
46
-
47
- - New command, subcommand, or flag → `docs/content/docs/reference/commands/ingest.md`
48
- (or the relevant commands file)
49
- - Output envelope / JSON shape change → `docs/content/docs/reference/envelope.md`
50
- - Architectural change (index schema, build sequence) →
51
- `docs/content/docs/reference/architecture.md`
52
- - New workflow worth a guide → `docs/content/docs/guides/*.md`
53
- - Quickstart-affecting change → `docs/content/docs/quickstart.md`
54
- - Landing-page copy change → `docs/app/(home)/page.tsx`
55
-
56
- If the release contains user-visible changes and the PR didn't touch
57
- docs, **stop the release** and ask the user whether docs should be
58
- updated first. Don't ship undocumented public surface.
59
-
60
- ## Skills — keep in sync with new features
61
-
62
- The `skills/` directory in the repo is the source of truth for the
63
- `fmddr-skills` npm package. The user's installed copies live at
64
- `~/.claude/skills/fmddr*/SKILL.md` and may have been edited in-session.
65
-
66
- **Before every release**, check whether the installed skills differ from
67
- the repo and sync them:
68
-
69
- ```sh
70
- diff ~/.claude/skills/fmddr/SKILL.md skills/fmddr/SKILL.md
71
- diff ~/.claude/skills/fmddr-setup/SKILL.md skills/fmddr-setup/SKILL.md
72
- diff ~/.claude/skills/fmddr-release/SKILL.md skills/fmddr-release/SKILL.md
73
- diff ~/.claude/skills/fmddr-issue/SKILL.md skills/fmddr-issue/SKILL.md
74
- ```
75
-
76
- If any differ, copy the installed version (which is more current) into the
77
- repo:
78
-
79
- ```sh
80
- cp ~/.claude/skills/fmddr/SKILL.md skills/fmddr/SKILL.md
81
- cp ~/.claude/skills/fmddr-setup/SKILL.md skills/fmddr-setup/SKILL.md
82
- cp ~/.claude/skills/fmddr-release/SKILL.md skills/fmddr-release/SKILL.md
83
- cp ~/.claude/skills/fmddr-issue/SKILL.md skills/fmddr-issue/SKILL.md
84
- ```
85
-
86
- For any release that adds a new command, flag, or workflow:
87
- - The relevant skill files **must** be updated to document it before
88
- shipping (so `npx fmddr-skills` gives agents current knowledge).
89
- - Key skills to update when ingest commands change: `fmddr/SKILL.md`
90
- and `fmddr-setup/SKILL.md`.
91
- - The release commit should include the updated skill files.
92
-
93
- ## Pre-flight
94
-
95
- Run these and stop if any fail:
96
-
97
- ```sh
98
- git branch --show-current # must be `main`
99
- git status # must be clean
100
- git pull --ff-only # latest main
101
- python -m pytest -q # green
102
- ```
103
-
104
- If the release is for a bugfix that's still on a feature branch, finish
105
- the PR → merge → checkout main → pull first. **Don't release from a
106
- feature branch.**
107
-
108
- Decide the new version (`X.Y.Z`) and today's date (`YYYY-MM-DD`) up front.
109
-
110
- ## Release steps
111
-
112
- ### 1. Bump Python versions and update CHANGELOG
113
-
114
- Edit all three files:
115
-
116
- - `pyproject.toml` → `version = "X.Y.Z"`
117
- - `src/fmddr/__init__.py` → `__version__ = "X.Y.Z"`
118
- - `CHANGELOG.md`:
119
- - Insert a new section `## [X.Y.Z] — YYYY-MM-DD` directly after
120
- `## [Unreleased]`.
121
- - Move any unreleased entries into it (or write the section fresh if
122
- `[Unreleased]` was empty).
123
- - Use the same `### Added` / `### Fixed` / `### Changed` headings as
124
- prior releases.
125
- - Link to the closing PR(s)/issue(s) inline:
126
- `([#6](https://github.com/proofsh/fmddr/pull/6))`.
127
-
128
- Sanity-check after editing:
129
-
130
- ```sh
131
- grep -E '"0\.[0-9]+\.[0-9]+"|__version__' pyproject.toml src/fmddr/__init__.py
132
- grep -E '^## \[' CHANGELOG.md | head -3
133
- ```
134
-
135
- All three should show the new version; the CHANGELOG's first dated entry
136
- should be `[X.Y.Z]`.
137
-
138
- ### 2. Sync and bump the npm skills package
139
-
140
- #### 2a. Sync skill files from installed → repo
141
-
142
- ```sh
143
- diff ~/.claude/skills/fmddr/SKILL.md skills/fmddr/SKILL.md
144
- # (repeat for fmddr-setup, fmddr-release, fmddr-issue)
145
- ```
146
-
147
- Copy any that differ:
148
-
149
- ```sh
150
- cp ~/.claude/skills/fmddr/SKILL.md skills/fmddr/SKILL.md
151
- cp ~/.claude/skills/fmddr-setup/SKILL.md skills/fmddr-setup/SKILL.md
152
- cp ~/.claude/skills/fmddr-release/SKILL.md skills/fmddr-release/SKILL.md
153
- cp ~/.claude/skills/fmddr-issue/SKILL.md skills/fmddr-issue/SKILL.md
154
- ```
155
-
156
- #### 2b. Bump the npm package version
157
-
158
- Open `skills/package.json` and bump `"version"`. Use the same
159
- `MINOR.PATCH` convention as the Python package, but they don't need
160
- to be identical:
161
- - If any skill content changed → bump the patch.
162
- - If a new skill was added or removed → bump the minor.
163
-
164
- ```sh
165
- # verify the bump
166
- grep '"version"' skills/package.json
167
- ```
168
-
169
- ### 3. Commit
170
-
171
- Stage all changed files — Python version files, CHANGELOG, and any
172
- updated skill files and `package.json`:
173
-
174
- ```sh
175
- git add pyproject.toml src/fmddr/__init__.py CHANGELOG.md
176
- git add skills/fmddr/SKILL.md skills/fmddr-setup/SKILL.md \
177
- skills/fmddr-release/SKILL.md skills/fmddr-issue/SKILL.md \
178
- skills/package.json
179
- # also add any other modified files (docs, split_savexml.py, cli.py, etc.)
180
- git commit -m "Release X.Y.Z"
181
- ```
182
-
183
- The message is literally `Release X.Y.Z`. The user will push when ready;
184
- do **not** push without explicit instruction.
185
-
186
- ### 4. Build Python artifacts
187
-
188
- ```sh
189
- python -m build
190
- ls -lh dist/fmddr-X.Y.Z*
191
- ```
192
-
193
- Expected: `fmddr-X.Y.Z.tar.gz` and `fmddr-X.Y.Z-py3-none-any.whl`.
194
-
195
- Verify the wheel:
196
-
197
- ```sh
198
- python -c "import zipfile; z=zipfile.ZipFile('dist/fmddr-X.Y.Z-py3-none-any.whl'); print(z.read('fmddr/__init__.py').decode())"
199
- ```
200
-
201
- Must print `__version__ = "X.Y.Z"`.
202
-
203
- ### 5. Push the release commit
204
-
205
- Only after the user authorizes:
206
-
207
- ```sh
208
- git push origin main
209
- ```
210
-
211
- Per the user's global git-push policy, every push needs explicit
212
- authorization in the current message.
213
-
214
- ### 6. Tag and push the tag
215
-
216
- ```sh
217
- git tag -a vX.Y.Z -m "fmddr X.Y.Z"
218
- git push origin vX.Y.Z
219
- ```
220
-
221
- Annotated tag, `v`-prefixed name.
222
-
223
- ### 7. Upload to PyPI
224
-
225
- ```sh
226
- twine upload dist/fmddr-X.Y.Z*
227
- ```
228
-
229
- Uses `~/.pypirc` or env vars. **Never** print credentials.
230
-
231
- ### 8. Publish the npm skills package
232
-
233
- ```sh
234
- cd skills
235
- npm publish
236
- cd ..
237
- ```
238
-
239
- Uses `~/.npmrc` or `NPM_TOKEN` env var for auth. Publishes as
240
- `fmddr-skills` to the npm registry. If the user wants to dry-run:
241
- `npm publish --dry-run`.
242
-
243
- After publishing, verify:
244
- ```sh
245
- npm info fmddr-skills version
246
- ```
247
-
248
- ### 9. Create the GitHub release
249
-
250
- ```sh
251
- gh release create vX.Y.Z \
252
- --repo proofsh/fmddr \
253
- --title "vX.Y.Z" \
254
- --generate-notes \
255
- dist/fmddr-X.Y.Z.tar.gz \
256
- dist/fmddr-X.Y.Z-py3-none-any.whl
257
- ```
258
-
259
- Both built artifacts must be attached.
260
-
261
- ### 10. Verify
262
-
263
- ```sh
264
- gh release view vX.Y.Z --repo proofsh/fmddr
265
- npm info fmddr-skills version
266
- ```
267
-
268
- Confirm:
269
- - GitHub release page lists both `.whl` and `.tar.gz` artifacts.
270
- - PyPI serves the new version (may take ~30s).
271
- - npm serves the new `fmddr-skills` version.
272
- - Git tag points at the `Release X.Y.Z` commit.
273
-
274
- Report the release URL, PyPI URL, and npm URL back to the user.
275
-
276
- ### 11. Upgrade the user's local install
277
-
278
- ```sh
279
- uv tool upgrade fmddr
280
- fmddr --version # must print X.Y.Z
281
- ```
282
-
283
- Optionally reinstall the npm skills to pick up the updated SKILL.md files:
284
- ```sh
285
- npx fmddr-skills@latest
286
- ```
287
-
288
- ## When the bugfix is still on a feature branch
289
-
290
- 1. Create branch `fix/<slug>` (or `feat/<slug>` for minor bumps).
291
- 2. Implement + tests + CHANGELOG entry under `[Unreleased]` only.
292
- 3. PR with `Closes #<issue>`; wait for merge.
293
- 4. `git checkout main && git pull --ff-only`.
294
- 5. Run this skill from step 1.
295
-
296
- ## Common failure modes
297
-
298
- - **Version drift between `pyproject.toml` and `__init__.py`.** The
299
- wheel-version check in step 4 is the guardrail — run it.
300
- - **Skill files out of sync.** Always diff before committing. Shipping
301
- stale skills means agents won't know about new commands.
302
- - **Tagged the wrong commit.** Delete local tag (`git tag -d vX.Y.Z`),
303
- retag, force-push the tag — only OK if no one has pulled it yet.
304
- Otherwise cut `X.Y.(Z+1)`.
305
- - **`gh release create` fails on tag not found.** Push the tag (step 6)
306
- before step 9.
307
- - **npm 401 / 403.** Token wrong — tell the user to refresh `~/.npmrc`
308
- or `NPM_TOKEN`. Never ask them to paste the token.
309
- - **Twine 401 / 403.** Same pattern for PyPI.
310
-
311
- ## Privacy / safety
312
-
313
- - Don't run `twine upload`, `npm publish`, or `gh release create`
314
- without explicit user go-ahead — all are public, irreversible.
315
- - Don't print PyPI tokens, npm tokens, or GitHub tokens.
316
- - Don't force-push `main`. Cut a new patch version instead.