@benjaminthomas/spec-driven-dev 1.16.0 → 1.16.2
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
|
@@ -787,7 +787,7 @@ skips that step rather than failing.
|
|
|
787
787
|
|
|
788
788
|
| Skill | Stage | SKILL.md lines | Words | Supporting files |
|
|
789
789
|
|---|---|---:|---:|---:|
|
|
790
|
-
| `spec-setup` | 0 · configure |
|
|
790
|
+
| `spec-setup` | 0 · configure | 299 | 3,163 | 4 |
|
|
791
791
|
| `spec-investigate` | 1 · understand | 387 | 3,391 | 1 |
|
|
792
792
|
| `spec-create` | 2 · plan | 198 | 1,806 | 6 |
|
|
793
793
|
| `spec-implement` | 3 · build | 327 | 2,777 | 3 |
|
|
@@ -796,7 +796,7 @@ skips that step rather than failing.
|
|
|
796
796
|
| `spec-checkpoint` | 6 · commit | 140 | 1,168 | 0 |
|
|
797
797
|
| `spec-ship` | 7 · PR | 230 | 1,412 | 0 |
|
|
798
798
|
| `generative-seo` | standalone | 255 | 2,209 | 7 |
|
|
799
|
-
| **Total** | | **2,
|
|
799
|
+
| **Total** | | **2,136** | **18,825** | **23** |
|
|
800
800
|
|
|
801
801
|
- **8** skills: **1** setup + **6** workflow stages + **1** standalone
|
|
802
802
|
- **4** tools supported natively (Claude Code, Codex CLI, Cursor, Antigravity), plus an MCP fallback
|
|
@@ -849,7 +849,7 @@ plugin/evals/ `claude plugin eval` cases
|
|
|
849
849
|
1. Increase `version` in both `package.json` and `plugin/.claude-plugin/plugin.json` (the check fails if
|
|
850
850
|
they differ).
|
|
851
851
|
2. Add a `CHANGELOG.md` entry, then commit and push.
|
|
852
|
-
3. Tag the release and push the tag: `git tag v1.16.
|
|
852
|
+
3. Tag the release and push the tag: `git tag v1.16.1 && git push origin v1.16.1`.
|
|
853
853
|
4. Watch the **publish** run in the repo's Actions tab. When it's green, the new version is on
|
|
854
854
|
npm. Claude Code plugin users get it from the marketplace once the commit is on `main`.
|
|
855
855
|
|
package/bin/cli.mjs
CHANGED
|
@@ -592,6 +592,14 @@ function configApplies(f, dir) {
|
|
|
592
592
|
return here === real(base) || c.repos.some((r) => { const p = real(path.resolve(base, expandHome(String(r.path || "")))); return here === p || here.startsWith(p + path.sep); });
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
+
// Back up a file without ever overwriting an older backup (that would lose the user's original).
|
|
596
|
+
function backup(file) {
|
|
597
|
+
let b = `${file}.bak`;
|
|
598
|
+
if (fs.existsSync(b)) b = `${file}.bak-${new Date().toISOString().replace(/[-:]/g, "").replace("T", "-").slice(0, 15)}`;
|
|
599
|
+
fs.copyFileSync(file, b);
|
|
600
|
+
return b;
|
|
601
|
+
}
|
|
602
|
+
|
|
595
603
|
// The effective config: the team's rules (team.yml in the specs repo) with the personal file on top.
|
|
596
604
|
function readConfig(file) {
|
|
597
605
|
const personal = parseYaml(fs.readFileSync(file, "utf8"));
|
|
@@ -979,11 +987,12 @@ function teamInit() {
|
|
|
979
987
|
const { team, personal: mine } = splitConfig(personal);
|
|
980
988
|
fs.mkdirSync(path.dirname(tf), { recursive: true });
|
|
981
989
|
fs.writeFileSync(tf, TEAM_HEADER + dumpYaml(team));
|
|
982
|
-
|
|
990
|
+
// --fresh: spec-setup wrote this file moments ago in the same run, so a backup would only be clutter.
|
|
991
|
+
const saved = flag("fresh") ? null : backup(file);
|
|
983
992
|
fs.writeFileSync(file, PERSONAL_HEADER(path.relative(path.dirname(file), tf)) + dumpYaml(mine));
|
|
984
993
|
step(1, "Team rules shared", ink.cyan);
|
|
985
994
|
console.log(`✓ Wrote ${tf} (tracker, git conventions, commands, models, GitRisk, sharing)
|
|
986
|
-
✓ ${file} now keeps only your local settings (the old file is ${path.basename(
|
|
995
|
+
✓ ${file} now keeps only your local settings${saved ? ` (the old file is saved as ${path.basename(saved)})` : ""}
|
|
987
996
|
Next: commit team.yml in the specs repo. Colleagues who clone it run: spec-driven-dev setup --join=<path to the specs repo>
|
|
988
997
|
or say "run spec-setup" in their AI tool, which finds it and offers to join.`);
|
|
989
998
|
}
|
|
@@ -1007,7 +1016,7 @@ function join() {
|
|
|
1007
1016
|
if (!have.length) throw new Error(`None of the team's repos (${known.map((r) => r.name).join(", ")}) are cloned in ${workspace}. Clone the ones you work on, then join again (or pass --workspace=<folder>).`);
|
|
1008
1017
|
const file = path.join(workspace, ".spec-driven.yml");
|
|
1009
1018
|
if (fs.existsSync(file) && !flag("force")) throw new Error(`${file} already exists. Add --force to replace it with the team's setup (it's backed up first).`);
|
|
1010
|
-
if (fs.existsSync(file))
|
|
1019
|
+
if (fs.existsSync(file)) console.log(` Backed up your old settings to ${path.basename(backup(file))}`);
|
|
1011
1020
|
const mine = { version: 1, layout: have.length > 1 ? "multi-repo" : "single", repos: have.map((n) => ({ path: n })), specs_dir: path.relative(workspace, specsDir) || ".", pipeline: { after_approval: opt("after-approval") || "stop" } };
|
|
1012
1021
|
if (mine.layout === "single") { delete mine.repos; }
|
|
1013
1022
|
fs.writeFileSync(file, PERSONAL_HEADER(path.relative(workspace, path.join(specsDir, "team.yml"))) + dumpYaml(mine));
|
package/bin/team.mjs
CHANGED
|
@@ -49,7 +49,7 @@ export function dumpYaml(obj, indent = "") {
|
|
|
49
49
|
const scalar = (v) => (typeof v === "string" ? (/^[\w./@~-]+$/.test(v) && !/^(on|off|yes|no|true|false|null|\d.*)$/i.test(v) ? v : JSON.stringify(v)) : String(v));
|
|
50
50
|
let out = "";
|
|
51
51
|
for (const [k, v] of Object.entries(obj)) {
|
|
52
|
-
if (v === undefined || v === null || (isObj(v) && !Object.keys(v).length)) continue;
|
|
52
|
+
if (v === undefined || v === null || v === "" || (isObj(v) && !Object.keys(v).length)) continue; // "" means unset
|
|
53
53
|
if (Array.isArray(v)) {
|
|
54
54
|
out += `${indent}${k}:\n`;
|
|
55
55
|
for (const item of v) {
|
|
@@ -57,7 +57,7 @@ export function dumpYaml(obj, indent = "") {
|
|
|
57
57
|
const body = dumpYaml(item, `${indent} `).replace(/^\s+/, "");
|
|
58
58
|
out += `${indent} - ${body}`;
|
|
59
59
|
}
|
|
60
|
-
} else if (isObj(v)) out += `${indent}${k}:\n${
|
|
60
|
+
} else if (isObj(v)) { const body = dumpYaml(v, `${indent} `); if (body) out += `${indent}${k}:\n${body}`; }
|
|
61
61
|
else out += `${indent}${k}: ${scalar(v)}\n`;
|
|
62
62
|
}
|
|
63
63
|
return out;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benjaminthomas/spec-driven-dev",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.2",
|
|
4
4
|
"description": "Spec-driven AI development workflow (investigate → spec → implement → verify → review → ship) as Agent Skills for Claude Code, Cursor, Codex CLI and Antigravity.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ticket-to-pr",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.2",
|
|
4
4
|
"description": "Parallel-batch spec-driven feature workflow (spec-setup, spec-investigate, spec-create, spec-implement, spec-verify, spec-review, spec-checkpoint, spec-ship) plus a portable SEO/GEO operations skill (generative-seo) for any codebase.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Benjamin Thomas",
|
|
@@ -223,8 +223,9 @@ for the rest.
|
|
|
223
223
|
under `repos:` where they differ from the top level.
|
|
224
224
|
2. If it's inside a repo, tell the user it's meant to be committed (so teammates get the same
|
|
225
225
|
rules) — don't commit it yourself.
|
|
226
|
-
**Multi-repo with specs in a repo:** run `spec-driven-dev team init` right after writing
|
|
227
|
-
file
|
|
226
|
+
**Multi-repo with specs in a repo:** run `spec-driven-dev team init --fresh` right after writing
|
|
227
|
+
the file (`--fresh` skips the backup, since you wrote the file this run; leave it off when
|
|
228
|
+
splitting a config that existed before). It moves the team's rules (tracker, git conventions, commands, models, GitRisk, sharing)
|
|
228
229
|
into `{specs_dir}/team.yml`, which is committed with the specs, and leaves only local paths in
|
|
229
230
|
`.spec-driven.yml`. Tell the user to commit `team.yml`, and that colleagues then just say
|
|
230
231
|
"run spec-setup" and choose *Join*.
|
|
@@ -40,7 +40,10 @@ never ask again.
|
|
|
40
40
|
|
|
41
41
|
## 3. Discovery questions (one round)
|
|
42
42
|
|
|
43
|
-
Show the draft map first
|
|
43
|
+
Show the draft map first. Give it a **Source** column and fill it on every line: **detected**
|
|
44
|
+
with the file or command it came from (`AGENTS.md:12`, `git log`), or **guess**. One note for the
|
|
45
|
+
whole table isn't enough. Count anything you report (spec folders, repos, files) with a command,
|
|
46
|
+
never by eye. Then
|
|
44
47
|
ask only what the code can't answer, as **plain text in one message**, after the setup choices have
|
|
45
48
|
been answered. These are open questions, so
|
|
46
49
|
never put them in a menu or multiple-choice tool (a menu needs two or more real options, and these
|