fmddr-skills 0.4.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/README.md +83 -0
- package/bin/install.js +76 -0
- package/fmddr/SKILL.md +174 -0
- package/fmddr-issue/SKILL.md +121 -0
- package/fmddr-issue/templates/bug-report.md +56 -0
- package/fmddr-issue/templates/feature-request.md +50 -0
- package/fmddr-release/SKILL.md +265 -0
- package/fmddr-setup/SKILL.md +106 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# fmddr — Claude Code skills
|
|
2
|
+
|
|
3
|
+
Four agent skills for working with [`fmddr`](https://github.com/proofsh/fmddr)
|
|
4
|
+
from Claude Code:
|
|
5
|
+
|
|
6
|
+
| Skill | Triggers on | Purpose |
|
|
7
|
+
| --------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
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
|
+
| `fmddr` | FileMaker / DDR / fmp12 / Profile.xml / "where is X used" / refactor talk | Recognize when to reach for `fmddr` and use it correctly |
|
|
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
|
+
|
|
13
|
+
**Typical first-time flow:**
|
|
14
|
+
1. `npx fmddr-skills` — installs all four skills
|
|
15
|
+
2. In a Claude Code session: "set up fmddr for my DDR" → `fmddr-setup` activates
|
|
16
|
+
3. Now any FileMaker question → `fmddr` activates automatically
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
### npx (no git required)
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npx fmddr-skills # install all four skills (personal)
|
|
24
|
+
npx fmddr-skills fmddr fmddr-setup # install specific skills only
|
|
25
|
+
npx fmddr-skills --project # project-scoped (.claude/skills/)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Manual — personal (one user, all projects)
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
mkdir -p ~/.claude/skills
|
|
32
|
+
cp -R skills/fmddr ~/.claude/skills/
|
|
33
|
+
cp -R skills/fmddr-setup ~/.claude/skills/
|
|
34
|
+
cp -R skills/fmddr-issue ~/.claude/skills/
|
|
35
|
+
cp -R skills/fmddr-release ~/.claude/skills/
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Manual — project-scoped (this repo only)
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
mkdir -p .claude/skills
|
|
42
|
+
cp -R skills/fmddr .claude/skills/
|
|
43
|
+
cp -R skills/fmddr-setup .claude/skills/
|
|
44
|
+
cp -R skills/fmddr-issue .claude/skills/
|
|
45
|
+
cp -R skills/fmddr-release .claude/skills/
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Project skills override personal skills with the same name.
|
|
49
|
+
|
|
50
|
+
## Verify
|
|
51
|
+
|
|
52
|
+
In a Claude Code session, type `/` and look for the skills, or ask
|
|
53
|
+
"is the fmddr skill loaded?" — Claude will list available skills.
|
|
54
|
+
|
|
55
|
+
## Layout
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
skills/
|
|
59
|
+
├── package.json ← npm package (fmddr-skills)
|
|
60
|
+
├── bin/
|
|
61
|
+
│ └── install.js ← npx entry point
|
|
62
|
+
├── fmddr-setup/
|
|
63
|
+
│ └── SKILL.md
|
|
64
|
+
├── fmddr/
|
|
65
|
+
│ └── SKILL.md
|
|
66
|
+
├── fmddr-issue/
|
|
67
|
+
│ ├── SKILL.md
|
|
68
|
+
│ └── templates/
|
|
69
|
+
│ ├── bug-report.md
|
|
70
|
+
│ └── feature-request.md
|
|
71
|
+
└── fmddr-release/
|
|
72
|
+
└── SKILL.md
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Updating
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npx fmddr-skills@latest # via npm (when a new version is published)
|
|
79
|
+
|
|
80
|
+
# or from a local clone:
|
|
81
|
+
cd /path/to/fmddr && git pull
|
|
82
|
+
npx --prefix skills . fmddr-skills
|
|
83
|
+
```
|
package/bin/install.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
|
|
8
|
+
const ALL_SKILLS = ["fmddr", "fmddr-issue", "fmddr-release", "fmddr-setup"];
|
|
9
|
+
|
|
10
|
+
// Parse args: `npx fmddr-skills [skill1 skill2 ...]`
|
|
11
|
+
const requested = process.argv.slice(2).filter(a => !a.startsWith("-"));
|
|
12
|
+
const showHelp = process.argv.includes("--help") || process.argv.includes("-h");
|
|
13
|
+
const scopeFlag = process.argv.includes("--project") || process.argv.includes("-p")
|
|
14
|
+
? "project"
|
|
15
|
+
: "personal";
|
|
16
|
+
|
|
17
|
+
if (showHelp) {
|
|
18
|
+
console.log(`
|
|
19
|
+
fmddr-skills — install Claude Code skills for fmddr
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
npx fmddr-skills install all skills (personal)
|
|
23
|
+
npx fmddr-skills fmddr install one skill
|
|
24
|
+
npx fmddr-skills fmddr fmddr-issue install two skills
|
|
25
|
+
npx fmddr-skills --project install into .claude/skills/ (project-scoped)
|
|
26
|
+
|
|
27
|
+
Available skills: ${ALL_SKILLS.join(", ")}
|
|
28
|
+
`);
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const toInstall = requested.length > 0 ? requested : ALL_SKILLS;
|
|
33
|
+
|
|
34
|
+
// Validate
|
|
35
|
+
for (const name of toInstall) {
|
|
36
|
+
if (!ALL_SKILLS.includes(name)) {
|
|
37
|
+
console.error(`Unknown skill: "${name}". Available: ${ALL_SKILLS.join(", ")}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Resolve destination
|
|
43
|
+
const dest =
|
|
44
|
+
scopeFlag === "project"
|
|
45
|
+
? path.join(process.cwd(), ".claude", "skills")
|
|
46
|
+
: path.join(os.homedir(), ".claude", "skills");
|
|
47
|
+
|
|
48
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
49
|
+
|
|
50
|
+
// Copy a directory tree recursively
|
|
51
|
+
function copyDir(src, dst) {
|
|
52
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
53
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
54
|
+
const srcPath = path.join(src, entry.name);
|
|
55
|
+
const dstPath = path.join(dst, entry.name);
|
|
56
|
+
if (entry.isDirectory()) {
|
|
57
|
+
copyDir(srcPath, dstPath);
|
|
58
|
+
} else {
|
|
59
|
+
fs.copyFileSync(srcPath, dstPath);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const skillsRoot = path.join(__dirname, "..");
|
|
65
|
+
let installed = 0;
|
|
66
|
+
|
|
67
|
+
for (const name of toInstall) {
|
|
68
|
+
const src = path.join(skillsRoot, name);
|
|
69
|
+
const dst = path.join(dest, name);
|
|
70
|
+
copyDir(src, dst);
|
|
71
|
+
console.log(` ✓ ${name} → ${dst}`);
|
|
72
|
+
installed++;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log(`\nInstalled ${installed} skill${installed === 1 ? "" : "s"} into ${dest}`);
|
|
76
|
+
console.log("Open a Claude Code session and type / to confirm they appear.");
|
package/fmddr/SKILL.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fmddr
|
|
3
|
+
description: Reach for this skill whenever the user is working with a FileMaker solution — analyzing, auditing, refactoring, documenting, or cleaning up an `.fmp12` file or its DDR (Database Design Report). Triggers on FileMaker Pro, FMP, fmp12, Claris FileMaker, DDR, Profile.xml, Summary.xml, fmxmlsnippet, custom functions, table occurrences, layouts, scripts, ExecuteSQL audits, "where is field X used", "what scripts call this", "find unused fields/scripts/layouts", "what breaks if I delete this", impact analysis, dead-code hunts, FileMaker refactors, and anything that smells like a FileMaker DDR XML (look for `<FMPReport type="Report">`, `<FMPReport type="Summary">`, files ending `.xml` near `.fmp12`, or directories like `<solution>_Files/`). The `fmddr` CLI parses a DDR once into a queryable SQLite index, then answers structural and cross-reference questions in milliseconds with stable JSON output. Also covers filing bug reports and feature requests against proofsh/fmddr on GitHub.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# fmddr — FileMaker DDR analyzer
|
|
7
|
+
|
|
8
|
+
`fmddr` turns a FileMaker DDR XML into a SQLite index, then answers
|
|
9
|
+
structural questions about the solution: where is this field used, what
|
|
10
|
+
scripts call this script, what breaks if I remove this, what's dead code,
|
|
11
|
+
where do `ExecuteSQL` and `Evaluate` show up. Output is JSON-first and
|
|
12
|
+
stable, so it composes with shell pipelines and agent loops.
|
|
13
|
+
|
|
14
|
+
This skill exists for two reasons:
|
|
15
|
+
|
|
16
|
+
1. **Recognize when to reach for it.** A grep over a multi-thousand-script
|
|
17
|
+
FileMaker solution is the wrong tool. `fmddr` is the right one.
|
|
18
|
+
2. **Use it well.** Index once, query many times, dispatch on the JSON
|
|
19
|
+
`kind` field rather than parsing prose.
|
|
20
|
+
|
|
21
|
+
## When to reach for fmddr
|
|
22
|
+
|
|
23
|
+
Trigger on **any** of these signals — don't wait for the user to name
|
|
24
|
+
the tool:
|
|
25
|
+
|
|
26
|
+
### Surface signals (filenames / contents)
|
|
27
|
+
- `Profile.xml`, `Summary.xml`, anything matching `<FMPReport type="Report">`
|
|
28
|
+
or `<FMPReport type="Summary">` at the top of an XML file.
|
|
29
|
+
- A `*.fmp12` file in the working tree (FileMaker solution).
|
|
30
|
+
- An `<solution>_Files/` directory next to a `Summary.xml` (multi-file
|
|
31
|
+
DDR export).
|
|
32
|
+
- Mentions of "DDR", "Database Design Report", "fmxmlsnippet",
|
|
33
|
+
"BaseTable", "TableOccurrence", "ScriptStep", "CustomFunction",
|
|
34
|
+
"ValueList", "ScriptTrigger" — these are FileMaker schema terms.
|
|
35
|
+
- An existing `*.fmddr.db` SQLite file.
|
|
36
|
+
|
|
37
|
+
### Question shapes
|
|
38
|
+
| If the user asks… | Use… |
|
|
39
|
+
| ---------------------------------------------------------- | --------------------------------------------------- |
|
|
40
|
+
| "Where is `Customer::Email` used?" | `fmddr field references` / `script-refs` / `on-layouts` |
|
|
41
|
+
| "What scripts call *Save Case Request*?" | `fmddr script called-by` |
|
|
42
|
+
| "What does this script call?" | `fmddr script calls` / `chain --format mermaid` |
|
|
43
|
+
| "If I delete this field, what breaks?" | `fmddr impact field` |
|
|
44
|
+
| "What's dead in this file?" | `fmddr unused --kind {field,script,layout,custom_function,value_list,table_occurrence}` |
|
|
45
|
+
| "Where do we use `ExecuteSQL` / `Evaluate`?" | `fmddr risky-steps --has execute_sql` |
|
|
46
|
+
| "What custom functions does X use?" | `fmddr cf called-by` / `fmddr cf calls` |
|
|
47
|
+
| "What relationships connect these two TOs?" | `fmddr graph path <from-TO> <to-TO>` |
|
|
48
|
+
| "Find scripts named like *_OLD or BACKUP_*" | `fmddr cleanup-candidates` |
|
|
49
|
+
| "Are there orphan refs?" | `fmddr orphans` |
|
|
50
|
+
| "Search for anything called `…`" | `fmddr search "<fts5-query>"` |
|
|
51
|
+
|
|
52
|
+
### Anti-signals (do **not** invoke)
|
|
53
|
+
- The user is working in a FileMaker GUI and just wants to chat about
|
|
54
|
+
design. `fmddr` is for analysis of an exported DDR — it doesn't talk
|
|
55
|
+
to FileMaker Server.
|
|
56
|
+
- The XML is from a non-FileMaker tool (no `<FMPReport>` root).
|
|
57
|
+
|
|
58
|
+
## Install fmddr (if missing)
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
fmddr --version || pipx install fmddr
|
|
62
|
+
# or, in a project venv:
|
|
63
|
+
fmddr --version || pip install fmddr
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Python 3.11+ required. Optional `[lxml]` extra speeds up parsing on huge
|
|
67
|
+
DDRs.
|
|
68
|
+
|
|
69
|
+
## The two-step contract
|
|
70
|
+
|
|
71
|
+
Every analysis follows the same shape:
|
|
72
|
+
|
|
73
|
+
### 1. Index (once per DDR)
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
fmddr index path/to/Profile.xml --out ./profile.fmddr.db
|
|
77
|
+
# multi-file solution:
|
|
78
|
+
fmddr index path/to/Summary.xml --out ./solution.fmddr.db
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`index` is idempotent and streaming — safe to re-run. ~7s per 500MB DDR.
|
|
82
|
+
|
|
83
|
+
If a `*.fmddr.db` already exists in CWD and is newer than the source XML,
|
|
84
|
+
skip re-indexing.
|
|
85
|
+
|
|
86
|
+
### 2. Query (millisecond-cheap)
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
fmddr stats --db ./profile.fmddr.db
|
|
90
|
+
fmddr field script-refs "Customer::Email"
|
|
91
|
+
fmddr impact field "Customer::__UID"
|
|
92
|
+
fmddr unused --kind script
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
DB resolution order: `--db` flag → `$FMDDR_DB` → unique `*.fmddr.db` in
|
|
96
|
+
CWD → error. Set `FMDDR_DB` once at the start of an agent loop and drop
|
|
97
|
+
the flag.
|
|
98
|
+
|
|
99
|
+
## Output contract
|
|
100
|
+
|
|
101
|
+
Every command emits a stable envelope. Dispatch on `kind`, not prose.
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"kind": "field.script-refs",
|
|
106
|
+
"version": 1,
|
|
107
|
+
"ddr": {"path": "...", "sha256": "...", "indexed_at": "..."},
|
|
108
|
+
"query": {"field": {"id": 8712, "name": "...", "table": "..."}},
|
|
109
|
+
"result": [...],
|
|
110
|
+
"result_count": 1,
|
|
111
|
+
"truncated": false
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Format flags: `-o {json,jsonl,table,markdown,csv,tsv}`. JSON is the
|
|
116
|
+
default when stdout is not a TTY.
|
|
117
|
+
|
|
118
|
+
Exit codes worth handling:
|
|
119
|
+
|
|
120
|
+
- `0` ok
|
|
121
|
+
- `1` not found (no field/script matched the token)
|
|
122
|
+
- `2` ambiguous (qualify with `Table::Field` or use `--by-id`)
|
|
123
|
+
- `64` bad usage
|
|
124
|
+
- `70` internal error
|
|
125
|
+
|
|
126
|
+
## Common multi-step recipes
|
|
127
|
+
|
|
128
|
+
**"Find every place this field is used, including inside calc text on
|
|
129
|
+
other fields and CFs":**
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
fmddr field references "Customer::Email" # all refs, denormalized
|
|
133
|
+
fmddr field script-refs "Customer::Email" # scripts + step index
|
|
134
|
+
fmddr field on-layouts "Customer::Email" # layouts
|
|
135
|
+
fmddr field field-refs "Customer::Email" # other fields whose calcs name it
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**"Audit risky scripts":**
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
fmddr risky-steps --has execute_sql
|
|
142
|
+
fmddr risky-steps --has evaluate
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**"Map a script's call chain":**
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
fmddr script chain "Save Case Request" --depth 3 --format mermaid
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**"What can I safely delete?":**
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
for kind in field script layout custom_function value_list table_occurrence; do
|
|
155
|
+
fmddr unused --kind "$kind" -o json
|
|
156
|
+
done
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Filing bugs & feature requests against fmddr
|
|
160
|
+
|
|
161
|
+
If `fmddr` itself misbehaves, ask the user whether to file an issue at
|
|
162
|
+
**https://github.com/proofsh/fmddr**. Use the companion skill
|
|
163
|
+
`fmddr-issue` (same install bundle). It includes:
|
|
164
|
+
|
|
165
|
+
- Bug-report and feature-request templates with the exact diagnostics
|
|
166
|
+
to capture.
|
|
167
|
+
- A four-level severity scale (`critical` / `high` / `medium` / `low`)
|
|
168
|
+
mapped to GitHub labels.
|
|
169
|
+
- A privacy checklist — DDRs leak business logic, so the skill scrubs
|
|
170
|
+
table/field names, paths, and calc text before posting.
|
|
171
|
+
|
|
172
|
+
The skill posts via the GitHub MCP `mcp__github__issue_write` (scoped to
|
|
173
|
+
`proofsh/fmddr`), with `gh issue create` as a fallback. Always confirm
|
|
174
|
+
title and body with the user before posting.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fmddr-issue
|
|
3
|
+
description: Companion to the `fmddr` skill. Use when the user wants to report a bug, file an issue, or request a feature for the `fmddr` CLI/library (FileMaker DDR analyzer). Gathers diagnostics, classifies severity for bugs on a four-level scale, then opens an issue at proofsh/fmddr on GitHub. Triggers on phrases like "fmddr bug", "report fmddr issue", "fmddr feature request", "file an issue for fmddr", or when an fmddr command crashed and the user wants it filed upstream.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# fmddr — file a bug report or feature request
|
|
7
|
+
|
|
8
|
+
Help the user open a high-quality issue at https://github.com/proofsh/fmddr.
|
|
9
|
+
Two paths: **bug report** and **feature request**. Always confirm the title
|
|
10
|
+
and body with the user before posting.
|
|
11
|
+
|
|
12
|
+
## When to invoke
|
|
13
|
+
|
|
14
|
+
- User says "report this as a bug to fmddr", "file an issue", "open an
|
|
15
|
+
fmddr ticket", "this should be fixed upstream", etc.
|
|
16
|
+
- An `fmddr` command just crashed or returned a wrong result and the user
|
|
17
|
+
wants it tracked.
|
|
18
|
+
- User asks for a new query/command/output format and wants it on the
|
|
19
|
+
roadmap.
|
|
20
|
+
|
|
21
|
+
If unsure whether the user wants a bug or a feature, ask once — the two
|
|
22
|
+
templates differ.
|
|
23
|
+
|
|
24
|
+
## Workflow
|
|
25
|
+
|
|
26
|
+
### 1. Classify
|
|
27
|
+
|
|
28
|
+
Ask the user (or infer from context) which one this is:
|
|
29
|
+
|
|
30
|
+
- **Bug** — something behaves incorrectly, crashes, returns wrong data,
|
|
31
|
+
or violates the documented contract.
|
|
32
|
+
- **Feature request** — new command, new flag, new output format, new
|
|
33
|
+
schema, performance ask, docs gap.
|
|
34
|
+
|
|
35
|
+
### 2. Gather diagnostics (bugs only)
|
|
36
|
+
|
|
37
|
+
Run these in the user's working directory and capture the output. Skip
|
|
38
|
+
gracefully if a command isn't available.
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
fmddr --version
|
|
42
|
+
python --version
|
|
43
|
+
uname -srm # or `sw_vers` on macOS
|
|
44
|
+
fmddr stats --db <their db> -o json # if they have an indexed DB
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For a crash, also collect:
|
|
48
|
+
|
|
49
|
+
- The exact command they ran (with paths redacted if sensitive).
|
|
50
|
+
- The full traceback or error output.
|
|
51
|
+
- DDR shape if relevant: file size, FileMaker version that produced it,
|
|
52
|
+
whether it's a single `Profile.xml` or a multi-file `Summary.xml`.
|
|
53
|
+
- Whether `--db`, `$FMDDR_DB`, or auto-discovery was in use.
|
|
54
|
+
|
|
55
|
+
**Never** include DDR contents, table/field/script names, or proprietary
|
|
56
|
+
schema in the issue body unless the user explicitly approves. DDRs leak
|
|
57
|
+
business logic. Offer to redact identifiers to `Table_A`, `Field_1`, etc.
|
|
58
|
+
|
|
59
|
+
### 3. Severity scale (bugs only)
|
|
60
|
+
|
|
61
|
+
Pick one with the user. Map it to a GitHub label.
|
|
62
|
+
|
|
63
|
+
| Severity | Label | When to use |
|
|
64
|
+
| ------------ | ------------------ | ------------------------------------------------------------------------------------------------- |
|
|
65
|
+
| **Critical** | `severity:critical`| Data corruption, wrong query results, index build silently drops rows, security issue. No workaround. |
|
|
66
|
+
| **High** | `severity:high` | Common command crashes or returns no results when it should. Workaround exists but is painful. |
|
|
67
|
+
| **Medium** | `severity:medium` | Edge-case crash, output format glitch, misleading error message, perf regression on large DDRs. |
|
|
68
|
+
| **Low** | `severity:low` | Cosmetic, typo, doc inaccuracy, minor UX nit. |
|
|
69
|
+
|
|
70
|
+
If the repo doesn't have these labels yet, fall back to the closest
|
|
71
|
+
existing one (`bug`, `enhancement`) and mention the severity in the body.
|
|
72
|
+
|
|
73
|
+
### 4. Draft the issue
|
|
74
|
+
|
|
75
|
+
Use the matching template under `templates/`:
|
|
76
|
+
|
|
77
|
+
- `templates/bug-report.md`
|
|
78
|
+
- `templates/feature-request.md`
|
|
79
|
+
|
|
80
|
+
Fill in every section. Strip empty headings. Keep titles under 70 chars
|
|
81
|
+
and front-load the affected command:
|
|
82
|
+
|
|
83
|
+
- Bug: `script chain: crashes on cyclic call graph` ✓
|
|
84
|
+
- Bug: `there is a problem when I run a script chain command` ✗
|
|
85
|
+
- Feature: `field references: add --since flag for time-windowed audits` ✓
|
|
86
|
+
|
|
87
|
+
### 5. Confirm with the user
|
|
88
|
+
|
|
89
|
+
Show the rendered title, labels, and body. Ask: "Post this to
|
|
90
|
+
proofsh/fmddr?" Wait for an explicit yes before calling any GitHub tool.
|
|
91
|
+
|
|
92
|
+
### 6. Post the issue
|
|
93
|
+
|
|
94
|
+
Use the GitHub MCP tool, scoped to this repo:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
mcp__github__issue_write
|
|
98
|
+
owner: "proofsh"
|
|
99
|
+
repo: "fmddr"
|
|
100
|
+
action: "create"
|
|
101
|
+
title: "<title>"
|
|
102
|
+
body: "<rendered template>"
|
|
103
|
+
labels: ["bug", "severity:high"] # or ["enhancement"] for features
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If `mcp__github__issue_write` is unavailable in the session, fall back to
|
|
107
|
+
`gh issue create --repo proofsh/fmddr --title ... --body-file ... --label ...`.
|
|
108
|
+
Do **not** attempt to push an issue file into the repo as a commit.
|
|
109
|
+
|
|
110
|
+
After posting, return the issue URL to the user.
|
|
111
|
+
|
|
112
|
+
## Privacy checklist (run before posting)
|
|
113
|
+
|
|
114
|
+
- [ ] No DDR file contents pasted (XML snippets, calc text, script bodies).
|
|
115
|
+
- [ ] No real table/field/script/layout names unless the user okayed it.
|
|
116
|
+
- [ ] No file paths containing usernames or client names (`/Users/jane/AcmeCorp/...`).
|
|
117
|
+
- [ ] No customer data in error messages.
|
|
118
|
+
- [ ] Tracebacks scrubbed of absolute paths if they leak identity.
|
|
119
|
+
|
|
120
|
+
If anything's unclear, ask the user before posting — once an issue is up
|
|
121
|
+
it's effectively public.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<one sentence: what command, what went wrong>
|
|
4
|
+
|
|
5
|
+
## Severity
|
|
6
|
+
|
|
7
|
+
**<critical | high | medium | low>** — <one-line justification>
|
|
8
|
+
|
|
9
|
+
## Reproduction
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
# exact command(s); redact paths and identifiers as needed
|
|
13
|
+
fmddr <subcommand> ...
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Input:** <single Profile.xml | Summary.xml multi-file | indexed DB only>
|
|
17
|
+
**DDR size (if relevant):** <MB>
|
|
18
|
+
**FileMaker version that produced the DDR:** <e.g. FMP 2024 19.6.1>
|
|
19
|
+
|
|
20
|
+
## Expected behavior
|
|
21
|
+
|
|
22
|
+
<what should have happened — quote docs/README/--help if applicable>
|
|
23
|
+
|
|
24
|
+
## Actual behavior
|
|
25
|
+
|
|
26
|
+
<what happened instead>
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
<error output / traceback / wrong JSON, fenced>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Environment
|
|
33
|
+
|
|
34
|
+
- `fmddr --version`: <x.y.z>
|
|
35
|
+
- Python: <3.11.x>
|
|
36
|
+
- OS: <macOS 14.5 / Ubuntu 22.04 / Windows 11 + WSL2 / ...>
|
|
37
|
+
- Install method: <pip | pipx | from source>
|
|
38
|
+
- Optional extras: <none | [lxml]>
|
|
39
|
+
- DB resolution: <--db flag | $FMDDR_DB | auto-discovery>
|
|
40
|
+
|
|
41
|
+
## Index metadata (if applicable)
|
|
42
|
+
|
|
43
|
+
Output of `fmddr stats -o json` (or note "no DB built yet"):
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
<paste here>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Workaround
|
|
50
|
+
|
|
51
|
+
<known workaround, or "none">
|
|
52
|
+
|
|
53
|
+
## Additional context
|
|
54
|
+
|
|
55
|
+
<links to related issues, prior discussion, screenshots of Rich-table
|
|
56
|
+
output if a rendering bug, etc.>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<one sentence: what new capability, on which subcommand>
|
|
4
|
+
|
|
5
|
+
## Problem / use case
|
|
6
|
+
|
|
7
|
+
<the concrete analysis you're trying to do that fmddr can't currently
|
|
8
|
+
support, or supports awkwardly. Real-world scenarios beat abstract
|
|
9
|
+
"it would be nice if…" framing.>
|
|
10
|
+
|
|
11
|
+
## Proposed shape
|
|
12
|
+
|
|
13
|
+
<sketch the CLI surface — subcommand, flags, a sample invocation — and
|
|
14
|
+
what the JSON envelope `result` array would contain. Don't over-design;
|
|
15
|
+
a rough shape is fine.>
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
fmddr <subcommand> ... --new-flag ...
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"kind": "<proposed kind>",
|
|
24
|
+
"result": [
|
|
25
|
+
{ "...": "..." }
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Alternatives considered
|
|
31
|
+
|
|
32
|
+
<existing fmddr commands you tried, shell pipelines that almost work,
|
|
33
|
+
why they fall short>
|
|
34
|
+
|
|
35
|
+
## Scope hints (optional)
|
|
36
|
+
|
|
37
|
+
- Which query module would own this? (`tables`, `fields`, `scripts`,
|
|
38
|
+
`layouts`, `cf`, `graph`, `impact`, `search`)
|
|
39
|
+
- Does it need new index columns or only new SQL over existing tables?
|
|
40
|
+
- Does it need a new ref kind?
|
|
41
|
+
|
|
42
|
+
## Environment
|
|
43
|
+
|
|
44
|
+
- `fmddr --version`: <x.y.z>
|
|
45
|
+
- DDR shape this would run against: <single Profile.xml | Summary.xml>
|
|
46
|
+
|
|
47
|
+
## Additional context
|
|
48
|
+
|
|
49
|
+
<links, prior art from other DDR tools (FMPerception, BaseElements,
|
|
50
|
+
InspectorPro), references to FileMaker docs>
|
|
@@ -0,0 +1,265 @@
|
|
|
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, 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
|
+
Pre-1.0 versioning per `CHANGELOG.md`: `0.MINOR.PATCH` — `MINOR` bumps for
|
|
22
|
+
new public surface, `PATCH` for bugfixes. Pick the right one before
|
|
23
|
+
starting; don't ask mid-flow.
|
|
24
|
+
|
|
25
|
+
## Docs — what self-syncs vs. what doesn't
|
|
26
|
+
|
|
27
|
+
The Fumadocs site under `docs/` auto-syncs two things from the repo root
|
|
28
|
+
at build time, so the release process never edits them by hand:
|
|
29
|
+
|
|
30
|
+
- `docs/lib/version.ts` reads `version` from `pyproject.toml` → drives
|
|
31
|
+
the home-page version banner.
|
|
32
|
+
- `docs/scripts/sync-changelog.mjs` mirrors `CHANGELOG.md` →
|
|
33
|
+
`docs/content/docs/changelog.md` (gitignored). Runs before `dev` /
|
|
34
|
+
`build`.
|
|
35
|
+
|
|
36
|
+
So a pure bugfix patch release needs **no** docs commits — once the docs
|
|
37
|
+
deploy fires, both surfaces pick up the new version and changelog
|
|
38
|
+
automatically.
|
|
39
|
+
|
|
40
|
+
Everything else is hand-written and **must** be updated before cutting
|
|
41
|
+
the release. The doc edits belong in the feature/fix PR, not the
|
|
42
|
+
`Release X.Y.Z` commit. Check each that applies to the release:
|
|
43
|
+
|
|
44
|
+
- New command, subcommand, or flag → `docs/content/docs/reference/commands.md`
|
|
45
|
+
- Output envelope / JSON shape change → `docs/content/docs/reference/envelope.md`
|
|
46
|
+
- Architectural change (index schema, build sequence) →
|
|
47
|
+
`docs/content/docs/reference/architecture.md`
|
|
48
|
+
- New workflow worth a guide → `docs/content/docs/guides/*.md`
|
|
49
|
+
- Quickstart-affecting change → `docs/content/docs/quickstart.md`
|
|
50
|
+
- Landing-page copy change → `docs/app/(home)/page.tsx`
|
|
51
|
+
|
|
52
|
+
If the release contains user-visible changes and the PR didn't touch
|
|
53
|
+
docs, **stop the release** and ask the user whether docs should be
|
|
54
|
+
updated first. Don't ship undocumented public surface.
|
|
55
|
+
|
|
56
|
+
## Pre-flight
|
|
57
|
+
|
|
58
|
+
Run these and stop if any fail:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
git branch --show-current # must be `main`
|
|
62
|
+
git status # must be clean
|
|
63
|
+
git pull --ff-only # latest main
|
|
64
|
+
python -m pytest -q # green
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If the release is for a bugfix that's still on a feature branch, finish
|
|
68
|
+
the PR → merge → checkout main → pull first. **Don't release from a
|
|
69
|
+
feature branch.**
|
|
70
|
+
|
|
71
|
+
Decide the new version (`X.Y.Z`) and today's date (`YYYY-MM-DD`) up front.
|
|
72
|
+
|
|
73
|
+
## Release steps
|
|
74
|
+
|
|
75
|
+
### 1. Bump versions and update CHANGELOG
|
|
76
|
+
|
|
77
|
+
Edit all three files in one commit:
|
|
78
|
+
|
|
79
|
+
- `pyproject.toml` → `version = "X.Y.Z"`
|
|
80
|
+
- `src/fmddr/__init__.py` → `__version__ = "X.Y.Z"`
|
|
81
|
+
- `CHANGELOG.md`:
|
|
82
|
+
- Insert a new section `## [X.Y.Z] — YYYY-MM-DD` directly after
|
|
83
|
+
`## [Unreleased]`.
|
|
84
|
+
- Move any unreleased entries into it (or write the section fresh if
|
|
85
|
+
`[Unreleased]` was empty).
|
|
86
|
+
- Use the same `### Added` / `### Fixed` / `### Changed` headings as
|
|
87
|
+
prior releases.
|
|
88
|
+
- Link to the closing PR(s)/issue(s) inline:
|
|
89
|
+
`([#6](https://github.com/proofsh/fmddr/pull/6))` or
|
|
90
|
+
`([#5](https://github.com/proofsh/fmddr/issues/5))`.
|
|
91
|
+
|
|
92
|
+
Sanity-check after editing:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
grep -E '"0\.[0-9]+\.[0-9]+"|__version__' pyproject.toml src/fmddr/__init__.py
|
|
96
|
+
grep -E '^## \[' CHANGELOG.md | head -3
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
All three should show the new version; the CHANGELOG's first dated entry
|
|
100
|
+
should be `[X.Y.Z]`.
|
|
101
|
+
|
|
102
|
+
### 2. Commit
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
git add pyproject.toml src/fmddr/__init__.py CHANGELOG.md
|
|
106
|
+
git commit -m "Release X.Y.Z"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The message is literally `Release X.Y.Z` — match prior commits
|
|
110
|
+
(`Release 0.2.2`, `Release 0.2.3`). The user will push when they're
|
|
111
|
+
ready; do **not** push without explicit instruction.
|
|
112
|
+
|
|
113
|
+
### 3. Build artifacts
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
rm -f dist/fmddr-X.Y.Z* # clean any stale local builds
|
|
117
|
+
python -m build
|
|
118
|
+
ls -lh dist/fmddr-X.Y.Z*
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Expected output: `fmddr-X.Y.Z.tar.gz` and `fmddr-X.Y.Z-py3-none-any.whl`.
|
|
122
|
+
If `python -m build` isn't available, install it: `pip install build`.
|
|
123
|
+
|
|
124
|
+
Verify the wheel actually contains the bumped version:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
python -c "import zipfile, sys; z=zipfile.ZipFile('dist/fmddr-X.Y.Z-py3-none-any.whl'); print(z.read('fmddr/__init__.py').decode())"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Must print `__version__ = "X.Y.Z"`. If it prints the old version, step 1
|
|
131
|
+
missed `__init__.py`.
|
|
132
|
+
|
|
133
|
+
### 4. Push the release commit
|
|
134
|
+
|
|
135
|
+
Only after the user authorizes the push:
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
git push origin main
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Per the user's global git-push policy, every push needs explicit
|
|
142
|
+
authorization in the current message. A previous "yes, release it"
|
|
143
|
+
doesn't carry forward.
|
|
144
|
+
|
|
145
|
+
### 5. Tag and push the tag
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
git tag -a vX.Y.Z -m "fmddr X.Y.Z"
|
|
149
|
+
git push origin vX.Y.Z
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Annotated tag (`-a`), `v`-prefixed name. Match prior tags (`v0.2.2`,
|
|
153
|
+
`v0.2.3`).
|
|
154
|
+
|
|
155
|
+
### 6. Upload to PyPI
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
twine upload dist/fmddr-X.Y.Z*
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Uses the user's `~/.pypirc` or env vars for credentials. If twine isn't
|
|
162
|
+
installed: `pip install twine`. **Never** print or commit credentials.
|
|
163
|
+
|
|
164
|
+
If the user wants to dry-run first:
|
|
165
|
+
`twine upload --repository testpypi dist/fmddr-X.Y.Z*`.
|
|
166
|
+
|
|
167
|
+
### 7. Create the GitHub release
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
gh release create vX.Y.Z \
|
|
171
|
+
--repo proofsh/fmddr \
|
|
172
|
+
--title "vX.Y.Z" \
|
|
173
|
+
--generate-notes \
|
|
174
|
+
dist/fmddr-X.Y.Z.tar.gz \
|
|
175
|
+
dist/fmddr-X.Y.Z-py3-none-any.whl
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`--generate-notes` produces the "What's Changed" + compare-link body that
|
|
179
|
+
matches prior releases. If the user wants custom notes, replace
|
|
180
|
+
`--generate-notes` with `--notes-file <file>` or `--notes "..."` and
|
|
181
|
+
paste the relevant `CHANGELOG.md` section.
|
|
182
|
+
|
|
183
|
+
Both built artifacts must be attached — that's how prior releases look
|
|
184
|
+
(`gh release view v0.2.3` shows `.whl` + `.tar.gz` assets).
|
|
185
|
+
|
|
186
|
+
### 8. Verify
|
|
187
|
+
|
|
188
|
+
```sh
|
|
189
|
+
gh release view vX.Y.Z --repo proofsh/fmddr
|
|
190
|
+
pip index versions fmddr 2>/dev/null || pip install --dry-run fmddr==X.Y.Z
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Confirm:
|
|
194
|
+
- The release page lists both artifacts.
|
|
195
|
+
- PyPI serves the new version (may take ~30s after `twine upload`).
|
|
196
|
+
- The git tag points at the `Release X.Y.Z` commit (`git show vX.Y.Z`).
|
|
197
|
+
|
|
198
|
+
Report the release URL and PyPI URL back to the user.
|
|
199
|
+
|
|
200
|
+
### 9. Upgrade the user's local install
|
|
201
|
+
|
|
202
|
+
The user has `fmddr` installed as a `uv` tool at `~/.local/bin/fmddr`
|
|
203
|
+
(symlink into `~/.local/share/uv/tools/fmddr/`). It is **separate** from
|
|
204
|
+
this repo's `.venv` and won't pick up the new release on its own.
|
|
205
|
+
|
|
206
|
+
After PyPI confirms the new version is live:
|
|
207
|
+
|
|
208
|
+
```sh
|
|
209
|
+
uv tool upgrade fmddr
|
|
210
|
+
~/.local/bin/fmddr --version # must print X.Y.Z
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
If `uv` isn't available or the install method has changed, fall back
|
|
214
|
+
based on what `which fmddr` resolves to:
|
|
215
|
+
|
|
216
|
+
- `~/.local/share/uv/tools/...` → `uv tool upgrade fmddr`
|
|
217
|
+
- `pipx`-managed (`pipx list` shows it) → `pipx upgrade fmddr`
|
|
218
|
+
- Plain `pip install --user` → `pip install --user --upgrade fmddr`
|
|
219
|
+
|
|
220
|
+
Run `fmddr --version` (no path) at the end to confirm the user's `$PATH`
|
|
221
|
+
resolves to the upgraded binary, not the dev `.venv` shim.
|
|
222
|
+
|
|
223
|
+
## When the bugfix is still on a feature branch
|
|
224
|
+
|
|
225
|
+
The full flow when starting from an open issue:
|
|
226
|
+
|
|
227
|
+
1. Create branch `fix/<slug>` (or `feat/<slug>` for minor bumps).
|
|
228
|
+
2. Implement + tests + CHANGELOG entry under `[Unreleased]` only —
|
|
229
|
+
**don't** bump version numbers in the bugfix commit.
|
|
230
|
+
3. PR with `Closes #<issue>`; wait for merge.
|
|
231
|
+
4. `git checkout main && git pull --ff-only`.
|
|
232
|
+
5. Run this skill from step 1, moving the `[Unreleased]` block into the
|
|
233
|
+
new versioned section.
|
|
234
|
+
|
|
235
|
+
This keeps the bugfix PR reviewable on its own merits and the release
|
|
236
|
+
commit small and mechanical.
|
|
237
|
+
|
|
238
|
+
## Common failure modes
|
|
239
|
+
|
|
240
|
+
- **Version drift between `pyproject.toml` and `__init__.py`.** Has
|
|
241
|
+
happened on this repo before. The wheel-version check in step 3 is the
|
|
242
|
+
guardrail — run it.
|
|
243
|
+
- **Tagged the wrong commit.** If the tag is on a commit that doesn't
|
|
244
|
+
bump versions (e.g. you tagged the merge commit before bumping
|
|
245
|
+
`__init__.py`), delete the local tag (`git tag -d vX.Y.Z`), retag, and
|
|
246
|
+
force-push the tag. Only acceptable if no one has pulled it yet —
|
|
247
|
+
otherwise cut a `X.Y.(Z+1)` instead.
|
|
248
|
+
- **Forgot to build before tagging.** The tag should point at the commit
|
|
249
|
+
whose source matches what you upload to PyPI. Build from the tagged
|
|
250
|
+
commit, not from a dirty tree.
|
|
251
|
+
- **Twine 401 / 403.** Token wrong or scope mismatch. Don't paste the
|
|
252
|
+
token into chat. Tell the user to refresh `~/.pypirc` or
|
|
253
|
+
`TWINE_PASSWORD` and re-run step 6.
|
|
254
|
+
- **`gh release create` fails on tag not found.** Push the tag (step 5)
|
|
255
|
+
before step 7.
|
|
256
|
+
|
|
257
|
+
## Privacy / safety
|
|
258
|
+
|
|
259
|
+
- Don't run `twine upload` or `gh release create` without explicit user
|
|
260
|
+
go-ahead — both are public, irreversible publishes.
|
|
261
|
+
- Don't print PyPI tokens, GitHub tokens, or any credential. If a
|
|
262
|
+
command fails with an auth error, ask the user to fix their env; never
|
|
263
|
+
ask them to paste the secret.
|
|
264
|
+
- Don't force-push `main` to "fix" a botched release. Cut a new patch
|
|
265
|
+
version instead.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fmddr-setup
|
|
3
|
+
description: Install and initialize fmddr for a FileMaker solution. Use when the user asks to "set up fmddr", "install fmddr", "get fmddr ready", "index my DDR", "index my SaveAsXML", or when fmddr commands fail because the CLI isn't installed or no index exists yet. Also triggers when the user drops a .xml DDR/SaveAsXML into the working directory and wants to start analyzing it, or when `fmddr` is not found in PATH.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# fmddr-setup — install fmddr and index a FileMaker solution
|
|
7
|
+
|
|
8
|
+
This skill gets fmddr installed and an index built in one pass, so the
|
|
9
|
+
user is ready to run any fmddr query immediately after.
|
|
10
|
+
|
|
11
|
+
## Step 1 — Check whether fmddr is installed
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
fmddr --version
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- If it prints a version → already installed, skip to Step 2.
|
|
18
|
+
- If it fails (`command not found`) → install it (Step 1a).
|
|
19
|
+
|
|
20
|
+
### Step 1a — Install fmddr
|
|
21
|
+
|
|
22
|
+
Try installers in this order, stopping at the first that works:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
uv tool install fmddr # preferred (fast, isolated)
|
|
26
|
+
pipx install fmddr # good alternative
|
|
27
|
+
pip install --user fmddr # fallback
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
After installing, confirm:
|
|
31
|
+
```sh
|
|
32
|
+
fmddr --version
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If `fmddr` still isn't on `$PATH` after `uv tool install`, the `uv`
|
|
36
|
+
tools bin dir may not be in `$PATH`. Tell the user:
|
|
37
|
+
```
|
|
38
|
+
Add ~/.local/bin to your PATH, or run: export PATH="$HOME/.local/bin:$PATH"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Step 2 — Find the DDR or SaveAsXML
|
|
42
|
+
|
|
43
|
+
Look in the current directory and one level down for:
|
|
44
|
+
|
|
45
|
+
1. `*.xml` files whose first 200 bytes match `<FMPReport` — these are
|
|
46
|
+
DDR or SaveAsXML exports.
|
|
47
|
+
2. A `Summary.xml` next to a `*_Files/` directory — multi-file DDR.
|
|
48
|
+
3. Any file the user has already named (trust user-provided paths).
|
|
49
|
+
|
|
50
|
+
Use `find . -maxdepth 2 -name "*.xml"` if nothing is immediately visible,
|
|
51
|
+
then peek the first line of candidates with `head -c 200`.
|
|
52
|
+
|
|
53
|
+
**DDR vs. SaveAsXML — how to tell:**
|
|
54
|
+
- `<FMPReport type="Report">` → standard DDR → use `fmddr index`
|
|
55
|
+
- `<FMPReport type="Summary">` → multi-file DDR Summary → use `fmddr index` (auto-detected)
|
|
56
|
+
- File is UTF-16 LE (BOM `FF FE`) AND contains `<FMSaveAsXML` or the
|
|
57
|
+
`<FMPReport` tag is absent → SaveAsXML → use `fmddr index-savexml`
|
|
58
|
+
- If `fmddr index` fails with a ParseError on a UTF-16 file, retry with
|
|
59
|
+
`fmddr index-savexml`
|
|
60
|
+
|
|
61
|
+
## Step 3 — Build the index
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
# Standard DDR (Report or Summary):
|
|
65
|
+
fmddr index path/to/Profile.xml
|
|
66
|
+
|
|
67
|
+
# SaveAsXML (whole-file clone export):
|
|
68
|
+
fmddr index-savexml path/to/MyFile.xml
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
This writes `<basename>.fmddr.db` next to the source file (or in the
|
|
72
|
+
current directory if the source is read-only).
|
|
73
|
+
|
|
74
|
+
Large files (300–700 MB) take 5–20 seconds. Tell the user what's
|
|
75
|
+
happening:
|
|
76
|
+
```
|
|
77
|
+
Indexing… (this takes ~10s for a 300 MB DDR)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Step 4 — Confirm and orient the user
|
|
81
|
+
|
|
82
|
+
Run `fmddr stats` to show what was indexed:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
fmddr stats
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Then report a one-line summary, e.g.:
|
|
89
|
+
```
|
|
90
|
+
Index ready: 247 tables, 2304 scripts, 870 layouts — run any fmddr command to start.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Suggest two starter commands based on what's in the file:
|
|
94
|
+
- If the solution has many scripts: `fmddr unused --kind script`
|
|
95
|
+
- If it has a big field count: `fmddr unused --kind field`
|
|
96
|
+
- Always: `fmddr risky-steps --has execute_sql`
|
|
97
|
+
|
|
98
|
+
## Common problems
|
|
99
|
+
|
|
100
|
+
| Symptom | Fix |
|
|
101
|
+
|---------|-----|
|
|
102
|
+
| `command not found: fmddr` after `uv tool install` | `export PATH="$HOME/.local/bin:$PATH"` |
|
|
103
|
+
| `ParseError: not well-formed` on index | File is SaveAsXML → use `fmddr index-savexml` |
|
|
104
|
+
| `No .fmddr.db found` on query commands | Index not built yet — run Step 3 |
|
|
105
|
+
| `Ambiguous: multiple scripts match` on a query | Add the script ID: `fmddr script show 900` |
|
|
106
|
+
| Very slow index on a 600 MB file | Normal — large SaveAsXML files take up to 30s |
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fmddr-skills",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Claude Code skills for fmddr — FileMaker DDR analyzer",
|
|
5
|
+
"keywords": ["claude-code", "claude", "skills", "filemaker", "fmddr", "ddr"],
|
|
6
|
+
"homepage": "https://fmddr.dev",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/proofsh/fmddr.git",
|
|
10
|
+
"directory": "skills"
|
|
11
|
+
},
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"bin": {
|
|
14
|
+
"fmddr-skills": "./bin/install.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"bin/",
|
|
18
|
+
"fmddr/",
|
|
19
|
+
"fmddr-issue/",
|
|
20
|
+
"fmddr-release/",
|
|
21
|
+
"fmddr-setup/"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
}
|
|
26
|
+
}
|