@pavp/storywright 1.13.2 → 1.13.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storywright",
3
- "version": "1.12.0",
3
+ "version": "1.13.4",
4
4
  "description": "PM skills for Claude Code — turn ambiguous inputs (prompts, screenshots, Figma links) into Jira-ready user stories.",
5
5
  "author": "pavp",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pavp/storywright",
3
- "version": "1.13.2",
3
+ "version": "1.13.4",
4
4
  "description": "PM Skills pack for Claude Code — turn ambiguous inputs (prompts, screenshots, Figma links) into Jira-ready user stories.",
5
5
  "keywords": [
6
6
  "claude",
@@ -53,6 +53,7 @@
53
53
  "@commitlint/cli": "^19.5.0",
54
54
  "@commitlint/config-conventional": "^19.5.0",
55
55
  "@semantic-release/changelog": "^6.0.3",
56
+ "@semantic-release/exec": "^7.1.0",
56
57
  "@semantic-release/git": "^10.0.1",
57
58
  "@semantic-release/github": "^11.0.0",
58
59
  "@semantic-release/npm": "^12.0.1",
@@ -2,7 +2,7 @@
2
2
  import { homedir } from "node:os";
3
3
  import { cp, mkdir, readdir, readFile, rm, unlink, writeFile } from "node:fs/promises";
4
4
  import { join } from "node:path";
5
- import { execSync } from "node:child_process";
5
+ import { execSync, execFileSync } from "node:child_process";
6
6
  import { REPO_ROOT, SKILLS_DIR, pathExists } from "./lib/skills.mjs";
7
7
 
8
8
  const skillsTarget = join(homedir(), ".claude", "skills", "storywright");
@@ -51,7 +51,9 @@ async function ensureGlobalGitignore() {
51
51
  globalIgnorePath = execSync("git config --global core.excludesFile", { encoding: "utf8" }).trim();
52
52
  } catch {
53
53
  globalIgnorePath = join(homedir(), ".gitignore_global");
54
- execSync(`git config --global core.excludesFile "${globalIgnorePath}"`);
54
+ // Array form (no shell) so a homedir with spaces or shell metacharacters
55
+ // can't break or inject into the command.
56
+ execFileSync("git", ["config", "--global", "core.excludesFile", globalIgnorePath]);
55
57
  }
56
58
  if (globalIgnorePath === "~") {
57
59
  globalIgnorePath = homedir();
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ // Write a version into the Claude marketplace manifest (.claude-plugin/plugin.json).
3
+ //
4
+ // semantic-release owns the version number in package.json (@semantic-release/npm
5
+ // bumps it in-place). plugin.json is a separate file no release plugin touches, so
6
+ // without this step the manifest drifts behind every release. Wired as the
7
+ // @semantic-release/exec prepareCmd, it runs after the version is computed and
8
+ // before @semantic-release/git commits the bump, keeping both files in lockstep.
9
+ //
10
+ // Usage: node scripts/sync-plugin-version.mjs <version>
11
+ // <version> defaults to package.json's version when omitted, so the script is
12
+ // also usable manually to repair drift outside a release.
13
+
14
+ import { readFile, writeFile } from "node:fs/promises";
15
+ import { fileURLToPath } from "node:url";
16
+ import { dirname, join } from "node:path";
17
+
18
+ const root = join(dirname(fileURLToPath(import.meta.url)), "..");
19
+ const manifestPath = join(root, ".claude-plugin", "plugin.json");
20
+
21
+ async function readJson(path) {
22
+ return JSON.parse(await readFile(path, "utf8"));
23
+ }
24
+
25
+ const version = process.argv[2] ?? (await readJson(join(root, "package.json"))).version;
26
+
27
+ if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version)) {
28
+ console.error(`✗ Refusing to write an invalid semver into plugin.json: "${version}"`);
29
+ process.exit(1);
30
+ }
31
+
32
+ const raw = await readFile(manifestPath, "utf8");
33
+
34
+ const versionLine = /("version"\s*:\s*")([^"]*)(")/;
35
+ const match = raw.match(versionLine);
36
+ if (!match) {
37
+ console.error(`✗ Could not find a "version" field in ${manifestPath}`);
38
+ process.exit(1);
39
+ }
40
+
41
+ const previous = match[2];
42
+ if (previous === version) {
43
+ console.log(`✓ plugin.json already at ${version} — no change`);
44
+ process.exit(0);
45
+ }
46
+
47
+ // Surgical replace of only the version value — preserves the file's existing
48
+ // formatting (indentation, array style) so releases don't churn unrelated lines.
49
+ const updated = raw.replace(versionLine, `$1${version}$3`);
50
+ await writeFile(manifestPath, updated);
51
+ console.log(`✓ plugin.json version ${previous} → ${version}`);