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 +12 -13
- package/bin/install.js +1 -1
- package/fmddr/SKILL.md +156 -0
- package/package.json +1 -2
- package/fmddr-release/SKILL.md +0 -316
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
|
|
53
|
-
cp -R skills/fmddr-setup
|
|
54
|
-
cp -R skills/fmddr-issue
|
|
55
|
-
cp -R skills/fmddr-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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-
|
|
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.
|
|
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": {
|
package/fmddr-release/SKILL.md
DELETED
|
@@ -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.
|