@benjaminthomas/spec-driven-dev 1.5.0 → 1.5.1
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 +9 -1
- package/bin/cli.mjs +30 -6
- package/bin/spec-driven-dev.cjs +10 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -375,6 +375,13 @@ run one after another, stopping at the first failure. Two steps always wait for
|
|
|
375
375
|
spec, and pushing or opening the PR. You don't need slash commands either. Saying "investigate
|
|
376
376
|
STP-123" or "ship it" picks the right skill.
|
|
377
377
|
|
|
378
|
+
**Setup didn't ask me anything.**
|
|
379
|
+
Update to 1.5.1 or later (`npx @benjaminthomas/spec-driven-dev@latest --version`). Earlier versions
|
|
380
|
+
crashed on Node 14 or 16, which nvm often switches to inside older projects, and wrote a config
|
|
381
|
+
silently when there was no terminal. Now it runs on Node 14+. With no terminal to answer in (a `!`
|
|
382
|
+
command in Claude Code, an editor task, piped input), it stops, changes nothing, and tells you to run
|
|
383
|
+
it in a terminal window or pass flags such as `--layout=multi-repo --repos=…`.
|
|
384
|
+
|
|
378
385
|
**Setup didn't ask me about repos.**
|
|
379
386
|
It only asks about repos for a multi-repo or monorepo layout. If it detected `single`, type
|
|
380
387
|
`multi-repo` at the layout question, then add your other repos by path. If it asked nothing at all,
|
|
@@ -455,7 +462,8 @@ can otherwise reuse an older copy it cached. What changed in each version is in
|
|
|
455
462
|
`npx github:benjaminthomas/spec-driven-dev` installs straight from GitHub instead, for example to
|
|
456
463
|
try an unreleased commit on `main`.
|
|
457
464
|
|
|
458
|
-
**Requirements:** Node.js
|
|
465
|
+
**Requirements:** Node.js 14 or newer and git. The installer has no dependencies, and CI tests it on
|
|
466
|
+
Node 14, 16, 18, 20, 22, and 24.
|
|
459
467
|
|
|
460
468
|
### Claude Code (plugin, with automatic updates)
|
|
461
469
|
|
package/bin/cli.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import fs from "node:fs";
|
|
|
13
13
|
import os from "node:os";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { execFileSync } from "node:child_process";
|
|
16
|
-
import { createInterface } from "node:readline/promises
|
|
16
|
+
import { createInterface } from "node:readline"; // callback API: readline/promises needs Node 17+
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
18
|
|
|
19
19
|
const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
@@ -40,8 +40,21 @@ if (flag("version") || flag("v")) {
|
|
|
40
40
|
console.log(JSON.parse(fs.readFileSync(path.join(ROOT, "package.json"), "utf8")).version);
|
|
41
41
|
process.exit(0);
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// No terminal to answer in (e.g. `!` in Claude Code, an IDE task, a pipe) and nothing passed explicitly:
|
|
44
|
+
// stop rather than write a config from guesses.
|
|
45
|
+
const ANSWER_FLAGS = ["yes", "y", "layout", "repos", "packages", "tools", "workspace", "after-approval", "skills", "global", "no-setup"];
|
|
46
|
+
if (["install", "setup"].includes(command) && !process.stdin.isTTY && !args.some((a) => ANSWER_FLAGS.some((f) => a === `--${f}` || a.startsWith(`--${f}=`)))) {
|
|
47
|
+
console.log(`✗ No interactive terminal, so setup can't ask its questions. Nothing was changed.
|
|
48
|
+
|
|
49
|
+
This happens when it runs through another program: a "!" command in Claude Code, an editor task,
|
|
50
|
+
or piped input. Either:
|
|
51
|
+
• run it yourself in a terminal window (Terminal, iTerm, or your editor's terminal panel):
|
|
52
|
+
npx @benjaminthomas/spec-driven-dev@latest ${command === "setup" ? "setup" : ""}
|
|
53
|
+
• or give the answers as flags, for example:
|
|
54
|
+
npx @benjaminthomas/spec-driven-dev@latest setup --layout=multi-repo --repos=~/Projects/frontend,~/Projects/backend
|
|
55
|
+
(add --yes to accept everything it detects)`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
45
58
|
|
|
46
59
|
if (flag("help") || flag("h")) {
|
|
47
60
|
console.log(fs.readFileSync(fileURLToPath(import.meta.url), "utf8").split("\n").slice(1, 11).join("\n").replace(/^\/\/ ?/gm, ""));
|
|
@@ -51,7 +64,7 @@ if (flag("help") || flag("h")) {
|
|
|
51
64
|
const rl = YES ? null : createInterface({ input: process.stdin, output: process.stdout });
|
|
52
65
|
async function ask(q, def = "") {
|
|
53
66
|
if (YES) return def;
|
|
54
|
-
const a = (await rl.question(`${q}${def ? ` [${def}]` : ""}:
|
|
67
|
+
const a = (await new Promise((resolve) => rl.question(`${q}${def ? ` [${def}]` : ""}: `, resolve))).trim();
|
|
55
68
|
return a || def;
|
|
56
69
|
}
|
|
57
70
|
async function pick(q, items, defaults) {
|
|
@@ -68,6 +81,17 @@ const run = (cmd, argv, cwd) => {
|
|
|
68
81
|
};
|
|
69
82
|
const onPath = (bin) => !!run(process.platform === "win32" ? "where" : "which", [bin]);
|
|
70
83
|
|
|
84
|
+
// fs.cpSync needs Node 16.7+; this keeps Node 14 working. Follows symlinks, skips .DS_Store.
|
|
85
|
+
function copyDir(from, to) {
|
|
86
|
+
fs.mkdirSync(to, { recursive: true });
|
|
87
|
+
for (const e of fs.readdirSync(from)) {
|
|
88
|
+
if (e === ".DS_Store") continue;
|
|
89
|
+
const src = path.join(from, e), dst = path.join(to, e);
|
|
90
|
+
if (fs.statSync(src).isDirectory()) copyDir(src, dst);
|
|
91
|
+
else fs.copyFileSync(src, dst);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
71
95
|
// ---------- install ----------
|
|
72
96
|
async function install() {
|
|
73
97
|
const detected = Object.keys(TOOLS).filter((t) => fs.existsSync(path.join(HOME, TOOLS[t].home)) || onPath(TOOLS[t].bin));
|
|
@@ -96,7 +120,7 @@ async function install() {
|
|
|
96
120
|
for (const s of skills) {
|
|
97
121
|
const to = path.join(dest, s);
|
|
98
122
|
fs.rmSync(to, { recursive: true, force: true });
|
|
99
|
-
|
|
123
|
+
copyDir(path.join(SKILLS_DIR, s), to);
|
|
100
124
|
}
|
|
101
125
|
console.log(`✓ ${skills.length} skills → ${dest}`);
|
|
102
126
|
}
|
|
@@ -247,7 +271,7 @@ async function chooseRepos(d) {
|
|
|
247
271
|
const found = findRepos(scanRoot);
|
|
248
272
|
if (found.length) {
|
|
249
273
|
const owners = {};
|
|
250
|
-
for (const r of found)
|
|
274
|
+
for (const r of found) { const o = gitFacts(path.join(scanRoot, r))?.owner || "?"; (owners[o] = owners[o] || []).push(r); }
|
|
251
275
|
const biggest = Object.values(owners).sort((a, b) => b.length - a.length)[0] || [];
|
|
252
276
|
const here = insideRepo ? [path.relative(scanRoot, d.root)] : [];
|
|
253
277
|
console.log(`Found ${found.length} git repos under ${scanRoot}. Which ones belong to this workspace?`);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Launcher: plain CommonJS so it runs on any Node and can explain a too-old version,
|
|
3
|
+
// instead of the ESM entry failing with a syntax error.
|
|
4
|
+
const major = Number(process.versions.node.split(".")[0]);
|
|
5
|
+
if (major < 14) {
|
|
6
|
+
console.error(`✗ spec-driven-dev needs Node.js 14 or newer; this is ${process.version}.`);
|
|
7
|
+
console.error(" If you use nvm, run it from a folder without an old .nvmrc, or: nvm exec 20 npx @benjaminthomas/spec-driven-dev@latest");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
import("./cli.mjs").catch((e) => { console.error(e); process.exit(1); });
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benjaminthomas/spec-driven-dev",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Spec-driven AI development workflow (investigate → spec → implement → verify → ship) as Agent Skills for Claude Code, Cursor, Codex CLI and Antigravity.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"bin": { "spec-driven-dev": "bin/
|
|
6
|
+
"bin": { "spec-driven-dev": "bin/spec-driven-dev.cjs" },
|
|
7
7
|
"files": ["bin", "skills"],
|
|
8
8
|
"scripts": { "test": "python3 scripts/check.py && node scripts/test-cli.mjs" },
|
|
9
|
-
"engines": { "node": ">=
|
|
9
|
+
"engines": { "node": ">=14" },
|
|
10
10
|
"keywords": ["agent-skills", "claude-code", "cursor", "codex", "antigravity", "spec-driven-development", "ai-agents"],
|
|
11
11
|
"repository": { "type": "git", "url": "git+https://github.com/benjaminthomas/spec-driven-dev.git" },
|
|
12
12
|
"license": "MIT",
|