bigpowers 2.93.0 → 2.93.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.93.0",
3
+ "version": "2.93.2",
4
4
  "description": "80 skills — 73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "keywords": [
6
6
  "gemini-extension"
package/.pi/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.93.0",
3
+ "version": "2.93.2",
4
4
  "description": "80 skills — 73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "keywords": [
6
6
  "pi-package"
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [2.93.2](https://github.com/danielvm-git/bigpowers/compare/v2.93.1...v2.93.2) (2026-11-03)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **deps:** clear the production dependency advisories ([#200](https://github.com/danielvm-git/bigpowers/issues/200)) ([1ff6dea](https://github.com/danielvm-git/bigpowers/commit/1ff6dea73d7fdc06ebb3172839758f7a1be995c4))
7
+
8
+ ## [2.93.1](https://github.com/danielvm-git/bigpowers/compare/v2.93.0...v2.93.1) (2026-11-03)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **cli:** report the installed version after a self-update ([#198](https://github.com/danielvm-git/bigpowers/issues/198)) ([4a2d8d0](https://github.com/danielvm-git/bigpowers/commit/4a2d8d0131d593c83c86151f6c716d2bfae96498))
14
+
1
15
  # [2.93.0](https://github.com/danielvm-git/bigpowers/compare/v2.92.0...v2.93.0) (2026-11-03)
2
16
 
3
17
 
package/README.md CHANGED
@@ -67,6 +67,8 @@ Use **arrow keys** to navigate, **space** to select, and **Enter** to confirm.
67
67
 
68
68
  ![Interactive Installer](docs/images/interactive-installer.png)
69
69
 
70
+ *Screenshot from an earlier release; the current installer may differ.*
71
+
70
72
  ### From source (contributors)
71
73
 
72
74
  ```bash
package/bin/bigpowers.js CHANGED
@@ -10,7 +10,9 @@ const path = require('path');
10
10
 
11
11
  const ROOT = path.dirname(path.dirname(__filename));
12
12
  const SKILLS_MARKER = path.join(os.homedir(), '.claude', 'skills', 'survey-context');
13
- const pkg = require(path.join(ROOT, 'package.json'));
13
+ // Version strings come from disk, not from a require cache captured at startup:
14
+ // `update` reinstalls this package mid-process (BUG-2026-11-03-cli-update-stale-version).
15
+ const { readPackageVersion } = require(path.join(ROOT, 'scripts', 'lib', 'cli-version'));
14
16
 
15
17
  function isInstalled() {
16
18
  try {
@@ -95,10 +97,11 @@ if (cmd === 'status') {
95
97
  const count = fs.readdirSync(path.join(os.homedir(), '.claude', 'skills'))
96
98
  .filter(d => fs.lstatSync(path.join(os.homedir(), '.claude', 'skills', d)).isSymbolicLink())
97
99
  .length;
98
- console.log(`bigpowers v${pkg.version} — ${count} skills installed`);
100
+ const version = readPackageVersion(ROOT);
101
+ console.log(`bigpowers v${version} — ${count} skills installed`);
99
102
  const latest = latestPublishedVersion();
100
- if (latest && latest !== pkg.version) {
101
- console.log(`\n⬆️ A newer release is available: v${latest} (you have v${pkg.version}).`);
103
+ if (latest && latest !== version) {
104
+ console.log(`\n⬆️ A newer release is available: v${latest} (you have v${version}).`);
102
105
  console.log(' Upgrade: npm install -g bigpowers@latest && bigpowers update');
103
106
  }
104
107
  } else {
@@ -123,10 +126,10 @@ Commands:
123
126
 
124
127
  // Default: check state and guide
125
128
  if (isInstalled()) {
126
- console.log(`bigpowers v${pkg.version} — already installed.`);
129
+ console.log(`bigpowers v${readPackageVersion(ROOT)} — already installed.`);
127
130
  console.log('Commands: bigpowers {setup|update|status|help}');
128
131
  } else {
129
- console.log(`🚀 bigpowers v${pkg.version} — skills not yet installed.`);
132
+ console.log(`🚀 bigpowers v${readPackageVersion(ROOT)} — skills not yet installed.`);
130
133
  console.log(' Run: bigpowers setup');
131
134
  process.exit(1);
132
135
  }
package/bin/setup.js CHANGED
@@ -16,9 +16,9 @@ const { execSync, spawn } = require('child_process');
16
16
  const fs = require('fs');
17
17
  const path = require('path');
18
18
  const { installGlobal, installLocal, uninstallTool, detectExistingInstall } = require('../scripts/lib/install-helpers');
19
+ const { readPackageVersion } = require('../scripts/lib/cli-version');
19
20
 
20
21
  const ROOT = path.resolve(path.dirname(__filename), '..');
21
- const pkg = require(path.join(ROOT, 'package.json'));
22
22
 
23
23
  // ── ANSI helpers ─────────────────────────────────────────────────────────────
24
24
  const c = {
@@ -30,7 +30,11 @@ const c = {
30
30
  };
31
31
 
32
32
  // ── ASCII banner ─────────────────────────────────────────────────────────────
33
- const BANNER = `
33
+ // The version is a parameter, read fresh from disk at render time: `update`
34
+ // reinstalls this package mid-process, so a value captured at startup is the one
35
+ // that was just replaced (BUG-2026-11-03-cli-update-stale-version).
36
+ function banner(version) {
37
+ return `
34
38
  ${c.cyan('╔════════════════════════════════════════════════════════════════════════════╗')}
35
39
  ${c.cyan('║')} ${c.cyan('║')}
36
40
  ${c.cyan('║')} ${c.bold(c.cyan('██████╗ ██╗ ██████╗ ██████╗ ██████╗ █ █ ███████╗██████╗ ███████╗'))} ${c.cyan('║')}
@@ -41,9 +45,10 @@ ${c.cyan('║')} ${c.bold(c.cyan('██████╔╝██║╚██
41
45
  ${c.cyan('║')} ${c.bold(c.cyan('╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝'))} ${c.cyan('║')}
42
46
  ${c.cyan('║')} ${c.cyan('║')}
43
47
  ${c.cyan('║')} ${c.dim('Spec-Driven & Test-First Skills for Solo Developers')} ${c.cyan('║')}
44
- ${c.cyan('║')} ${c.dim(`v${pkg.version}`)} ${c.cyan('║')}
48
+ ${c.cyan('║')} ${c.dim(`v${version}`)} ${c.cyan('║')}
45
49
  ${c.cyan('╚════════════════════════════════════════════════════════════════════════════╝')}
46
50
  `;
51
+ }
47
52
 
48
53
  // ── Tool definitions ─────────────────────────────────────────────────────────
49
54
  const TOOLS = [
@@ -164,8 +169,9 @@ async function handleUninstall() {
164
169
  async function main() {
165
170
  const { intro, outro, select, multiselect, spinner, confirm, isCancel } = await clack();
166
171
 
167
- console.log(BANNER);
168
- intro(c.bold(`bigpowers v${pkg.version}`));
172
+ const version = readPackageVersion(ROOT); // after a self-update this is the NEW version
173
+ console.log(banner(version));
174
+ intro(c.bold(`bigpowers v${version}`));
169
175
 
170
176
  // ── Step 0: Detect existing install ────────────────────────────────────
171
177
  const hasExisting = detectExistingInstall();
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.93.0",
3
+ "version": "2.93.2",
4
4
  "description": "73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "setup": "node bin/setup.js",
8
8
  "compliance": "bash scripts/audit-compliance.sh specs/verifications/features && bash scripts/validate-doctrine.sh && python3 scripts/check-skill-links.py",
9
+ "audit:prod": "npm audit --omit=dev",
9
10
  "doctrine": "bash scripts/validate-doctrine.sh",
10
11
  "sync": "bash scripts/sync-skills.sh",
11
12
  "validate-specs": "bash scripts/validate-specs-yaml.sh",
@@ -65,7 +66,7 @@
65
66
  "remark-frontmatter": "^5.0.0",
66
67
  "remark-parse": "^11.0.0",
67
68
  "unified": "^11.0.5",
68
- "zod": "^3.24.2"
69
+ "zod": "^4.6.7"
69
70
  },
70
71
  "devDependencies": {
71
72
  "@ctxo/lang-typescript": "^0.11.0",
@@ -0,0 +1,29 @@
1
+ // story: BUG-2026-11-03-cli-update-stale-version
2
+ // cli-version.js — read the installed version from disk, never from a require cache.
3
+ //
4
+ // `bigpowers update` runs `npm install -g bigpowers@latest` inside a *running*
5
+ // process. bin/bigpowers.js has already require()d package.json by then, so when
6
+ // bin/setup.js (required after the reinstall) reads the same resolved path, Node
7
+ // hands back the cached object: the banner printed v2.88.5 while v2.92.0 was what
8
+ // had just been installed, and `bigpowers install` — a fresh process — correctly
9
+ // reported 2.92.0.
10
+ //
11
+ // readFileSync always sees the new file, so every user-facing version string goes
12
+ // through here.
13
+
14
+ 'use strict';
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+
19
+ /** Version of the package rooted at `root`, read fresh from disk. */
20
+ function readPackageVersion(root) {
21
+ try {
22
+ const text = fs.readFileSync(path.join(root, 'package.json'), 'utf8');
23
+ return JSON.parse(text).version || 'unknown';
24
+ } catch {
25
+ return 'unknown';
26
+ }
27
+ }
28
+
29
+ module.exports = { readPackageVersion };
@@ -53,6 +53,13 @@ GOLDEN_GATES=(
53
53
  "target-contracts:bash scripts/test-target-contracts.sh:false"
54
54
  # Registry-driven replacements for the 25 hand-written per-target scripts.
55
55
  "install-hub:bash scripts/test-install-hub.sh:false"
56
+ # Whether the package *builds* was gated; whether its tree is *safe* was not.
57
+ # `npm audit --omit=dev` was 10 advisories (1 critical) with nothing watching.
58
+ "prod-dependency-audit:bash scripts/test-prod-dependency-audit.sh:false"
59
+ # `bigpowers update` runs `npm install -g @latest` inside a live process; a
60
+ # version captured by require() at startup then reports the release that was
61
+ # just replaced (BUG-2026-11-03-cli-update-stale-version).
62
+ "bigpowers-cli-version:bash scripts/test-bigpowers-cli-version.sh:false"
56
63
  "adapter-render:bash scripts/test-adapter-render.sh:false"
57
64
  "adapters:bash scripts/test-adapters.sh:false"
58
65
  # Previously orphaned: present in scripts/ but reachable from no gate.
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env bash
2
+ # story: BUG-2026-11-03-cli-update-stale-version
3
+ # test-bigpowers-cli-version.sh — `update` must report the version it just installed.
4
+ #
5
+ # Reproduces the reported symptom without touching npm or the real HOME:
6
+ # bigpowers update → banner v2.88.5 (wrong: a require() cache captured at startup,
7
+ # before `npm install -g bigpowers@latest`)
8
+ # bigpowers install → banner v2.92.0 (right: a fresh process reads package.json)
9
+ #
10
+ # Three assertions:
11
+ # 1. readPackageVersion() sees the on-disk version even after package.json was
12
+ # already require()d and then rewritten (the exact mechanism).
13
+ # 2. the installer's banner renders that fresh value — end to end, from a copy
14
+ # of bin/ whose version changes between process start and banner render.
15
+ # 3. neither CLI entry point still interpolates a cached `pkg.version` into a
16
+ # user-facing line (static guard: the cache is invisible at runtime until
17
+ # the day a self-update happens).
18
+ #
19
+ # Usage: bash scripts/test-bigpowers-cli-version.sh
20
+ set -euo pipefail
21
+ source "$(dirname "${BASH_SOURCE[0]}")/lib/skill-common.sh"
22
+ resolve_repo_root
23
+ cd "$REPO_ROOT"
24
+
25
+ source scripts/lib/test-assertions.sh
26
+ TA_PASS=0
27
+ TA_FAIL=0
28
+ TA_TMPDIR="$(mktemp -d)"
29
+ trap ta_cleanup EXIT
30
+
31
+ echo "=== test-bigpowers-cli-version.sh ==="
32
+
33
+ # ── 1. readPackageVersion ignores the require cache ─────────────────────────
34
+ mkdir -p "$TA_TMPDIR/pkgver"
35
+ if [ ! -f scripts/lib/cli-version.js ]; then
36
+ ta_fail "(1) scripts/lib/cli-version.js is missing — nothing reads the version from disk"
37
+ CACHE_OUT=""
38
+ else
39
+ CACHE_OUT="$(node -e '
40
+ const fs = require("fs"), path = require("path");
41
+ const dir = process.argv[1];
42
+ fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify({ version: "2.88.5" }));
43
+ const cached = require(path.join(dir, "package.json")); // what bin/bigpowers.js does at startup
44
+ fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify({ version: "2.92.0" })); // npm install -g @latest
45
+ const { readPackageVersion } = require(process.argv[2]);
46
+ process.stdout.write(`${cached.version}|${readPackageVersion(dir)}`);
47
+ ' "$TA_TMPDIR/pkgver" "$REPO_ROOT/scripts/lib/cli-version.js")"
48
+ fi
49
+ if [ "$CACHE_OUT" = "2.88.5|2.92.0" ]; then
50
+ ta_pass "(1) readPackageVersion sees the on-disk version after package.json is rewritten"
51
+ else
52
+ ta_fail "(1) version read followed the require cache: got '$CACHE_OUT' (want '2.88.5|2.92.0')"
53
+ fi
54
+
55
+ # ── 2. the banner an `update` run prints carries the new version ────────────
56
+ # Drive the exact sequence bin/bigpowers.js uses: read package.json at startup,
57
+ # let `npm install -g bigpowers@latest` replace it, then require bin/setup.js —
58
+ # which renders the banner. stdin at EOF makes setup draw the banner and exit, so
59
+ # nothing is installed and no prompt is answered.
60
+ FAKE_PKG="$TA_TMPDIR/fakepkg"
61
+ mkdir -p "$FAKE_PKG"
62
+ cp -R "$REPO_ROOT/bin" "$FAKE_PKG/bin"
63
+ cp -R "$REPO_ROOT/scripts" "$FAKE_PKG/scripts"
64
+ ln -sfn "$REPO_ROOT/node_modules" "$FAKE_PKG/node_modules"
65
+ printf '{"name":"bigpowers-fake","version":"2.88.5"}\n' > "$FAKE_PKG/package.json"
66
+ cat > "$FAKE_PKG/driver.js" <<'DRIVER'
67
+ // Mimics `bigpowers update`: snapshot at startup, reinstall over it, then render.
68
+ const { execFileSync } = require('child_process');
69
+ const fs = require('fs');
70
+ const path = require('path');
71
+
72
+ const root = __dirname;
73
+ const pkg = require(path.join(root, 'package.json')); // 2.88.5 — the version the process booted with
74
+ fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify({ name: 'bigpowers-fake', version: '2.92.0' }));
75
+ process.stdout.write(`startup=${pkg.version}\n`);
76
+ require(path.join(root, 'bin', 'setup.js')); // prints the banner
77
+ DRIVER
78
+ BANNER_OUT="$(
79
+ cd "$FAKE_PKG"
80
+ HOME="$TA_TMPDIR/home" perl -e 'alarm 25; exec @ARGV' node driver.js < /dev/null 2>&1 || true
81
+ )"
82
+ if printf '%s' "$BANNER_OUT" | grep -q "startup=2.88.5" && printf '%s' "$BANNER_OUT" | grep -q "v2.92.0"; then
83
+ ta_pass "(2) the banner after a self-update reports the installed version (2.92.0), not the startup one (2.88.5)"
84
+ elif printf '%s' "$BANNER_OUT" | grep -q "v2.88.5"; then
85
+ ta_fail "(2) the banner reported the startup version (v2.88.5) after 2.92.0 was installed"
86
+ else
87
+ ta_fail "(2) no banner version found in the update flow"
88
+ fi
89
+
90
+ # ── 3. no user-facing line interpolates the startup snapshot ────────────────
91
+ # `pkg.version` is the value captured when the process started. Anywhere it
92
+ # reaches the user after a self-update, it is the version that was replaced.
93
+ STALE=0
94
+ for f in bin/setup.js bin/bigpowers.js; do
95
+ grep -nE 'pkg\.version' "$f" | grep -vE '^\s*[0-9]+:\s*//' >/dev/null 2>&1 && STALE=1
96
+ done
97
+ if [ "$STALE" -eq 0 ]; then
98
+ ta_pass "(3) neither bin/setup.js nor bin/bigpowers.js prints a cached pkg.version"
99
+ else
100
+ ta_fail "(3) a CLI entry point still interpolates pkg.version (stale after self-update)"
101
+ fi
102
+
103
+ echo "$TA_PASS passed, $TA_FAIL failed"
104
+ [[ "$TA_FAIL" -eq 0 ]]
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env bash
2
+ # story: BUG-2026-11-03-prod-dependency-advisories
3
+ # test-prod-dependency-audit.sh — the shipped dependency graph must stay advisory-free.
4
+ #
5
+ # `npm audit --omit=dev` covers what users actually install. It was 10 advisories
6
+ # (1 critical) on 2.93.1 with nothing watching it: the only dependency gates were
7
+ # about whether the package *builds*, not whether its tree is safe.
8
+ #
9
+ # Two failure modes, both loud:
10
+ # 1. any advisory in the production tree → FAIL, listing package + severity
11
+ # 2. the audit could not run (no registry) → FAIL, naming the escape hatch
12
+ #
13
+ # Nothing here passes silently. To skip it deliberately (offline work), the golden
14
+ # runner's own mechanism is the documented path:
15
+ # GOLDEN_SKIP_GATES=prod-dependency-audit bash scripts/run-verification-gates.sh
16
+ # ...which records the gate as SKIPPED in the report rather than green.
17
+ #
18
+ # Dev-tree advisories are out of scope: they are concentrated in the npm bundle
19
+ # inside @semantic-release/npm and need major release-tool upgrades
20
+ # (BUG-2026-11-03-dev-dependency-advisories).
21
+ #
22
+ # Usage: bash scripts/test-prod-dependency-audit.sh
23
+ set -euo pipefail
24
+ source "$(dirname "${BASH_SOURCE[0]}")/lib/skill-common.sh"
25
+ resolve_repo_root
26
+ cd "$REPO_ROOT"
27
+
28
+ source scripts/lib/test-assertions.sh
29
+ TA_PASS=0
30
+ TA_FAIL=0
31
+ TA_TMPDIR="$(mktemp -d)"
32
+ trap ta_cleanup EXIT
33
+
34
+ echo "=== test-prod-dependency-audit.sh ==="
35
+
36
+ if ! command -v npm >/dev/null 2>&1; then
37
+ ta_fail "npm is unavailable — cannot audit the production dependency graph"
38
+ echo "$TA_PASS passed, $TA_FAIL failed"
39
+ exit 1
40
+ fi
41
+
42
+ AUDIT_JSON="$TA_TMPDIR/audit-prod.json"
43
+ # npm audit exits 1 when it finds advisories — capture, do not abort.
44
+ npm audit --omit=dev --json >"$AUDIT_JSON" 2>"$TA_TMPDIR/audit-prod.err" || true
45
+
46
+ REPORT="$(
47
+ python3 - "$AUDIT_JSON" <<'PY'
48
+ import json, sys
49
+
50
+ path = sys.argv[1]
51
+ try:
52
+ data = json.load(open(path, encoding="utf-8"))
53
+ except Exception:
54
+ print("UNPARSEABLE")
55
+ sys.exit(0)
56
+
57
+ meta = data.get("metadata") or {}
58
+ counts = meta.get("vulnerabilities")
59
+ if counts is None:
60
+ print("UNPARSEABLE")
61
+ sys.exit(0)
62
+
63
+ total = counts.get("total", 0)
64
+ rows = []
65
+ for name, info in sorted((data.get("vulnerabilities") or {}).items()):
66
+ severity = info.get("severity", "?")
67
+ via = info.get("via") or []
68
+ title = ""
69
+ for entry in via:
70
+ if isinstance(entry, dict) and entry.get("title"):
71
+ title = entry["title"]
72
+ break
73
+ rows.append(f"{severity:<9} {name} {title[:70]}")
74
+ print(f"TOTAL={total}")
75
+ for row in rows:
76
+ print(f" {row}")
77
+ PY
78
+ )"
79
+
80
+ if [[ "$REPORT" == UNPARSEABLE* ]]; then
81
+ ta_fail "npm audit produced no parseable report — the registry was probably unreachable:"
82
+ sed -n '1,5p' "$TA_TMPDIR/audit-prod.err" | sed 's/^/ /' >&2
83
+ ta_fail "run with network, or skip deliberately: GOLDEN_SKIP_GATES=prod-dependency-audit"
84
+ else
85
+ TOTAL="$(grep -oE 'TOTAL=[0-9]+' <<< "$REPORT" | cut -d= -f2)"
86
+ if [[ "${TOTAL:-0}" -eq 0 ]]; then
87
+ ta_pass "no advisories in the production dependency tree (npm audit --omit=dev)"
88
+ else
89
+ ta_fail "$TOTAL advisor$([[ "$TOTAL" -eq 1 ]] && echo 'y' || echo 'ies') in the production dependency tree:"
90
+ sed -n '2,$p' <<< "$REPORT" | sed 's/^/ /' >&2
91
+ fi
92
+ fi
93
+
94
+ echo "$TA_PASS passed, $TA_FAIL failed"
95
+ [[ "$TA_FAIL" -eq 0 ]]