bigpowers 2.83.0 → 2.83.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/.pi/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.83.0",
3
+ "version": "2.83.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.83.2](https://github.com/danielvm-git/bigpowers/compare/v2.83.1...v2.83.2) (2026-07-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **install:** stop setup from running dev-maintenance regen ([2d89ee2](https://github.com/danielvm-git/bigpowers/commit/2d89ee26a71b9004cf69ad25ce55a9f5b0699018))
7
+
8
+ ## [2.83.1](https://github.com/danielvm-git/bigpowers/compare/v2.83.0...v2.83.1) (2026-07-24)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **install:** resolve EEXIST errors during update by cleaning old symlinks first ([8a9a81f](https://github.com/danielvm-git/bigpowers/commit/8a9a81fa949489c594c2078d847d0e4d8e3e8b12))
14
+
1
15
  # [2.83.0](https://github.com/danielvm-git/bigpowers/compare/v2.82.4...v2.83.0) (2026-07-24)
2
16
 
3
17
 
package/bin/setup.js CHANGED
@@ -232,14 +232,27 @@ async function main() {
232
232
  process.exit(0);
233
233
  }
234
234
 
235
- // ── Step 4: Install ───────────────────────────────────────────────────
235
+ // ── Step 4: Clean old symlinks ─────────────────────────────────────────
236
236
  const s = await spinner();
237
237
  s.start('Preparing installation...');
238
238
  await sleep(200);
239
239
 
240
+ // Uninstall existing symlinks for selected tools before reinstalling
241
+ if (hasExisting) {
242
+ s.message('Cleaning old symlinks...');
243
+ for (const toolId of selectedTools) {
244
+ try {
245
+ uninstallTool(toolId, ROOT);
246
+ } catch {
247
+ // Ignore errors during cleanup — tool might not be installed yet
248
+ }
249
+ }
250
+ await sleep(100);
251
+ }
252
+
240
253
  s.message('Syncing skills...');
241
254
  try {
242
- runInherited('bash scripts/sync-skills.sh');
255
+ runInherited('bash scripts/sync-skills.sh --distribute-only');
243
256
  } catch {
244
257
  s.error('Sync failed.');
245
258
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.83.0",
3
+ "version": "2.83.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": {
@@ -18,9 +18,9 @@ function linkSkills(skillsDir, targetDir) {
18
18
  const src = path.join(skillsDir, entry.name);
19
19
  const dst = path.join(targetDir, entry.name);
20
20
 
21
+ // Remove existing symlink or directory
21
22
  try {
22
- const stat = fs.lstatSync(dst);
23
- if (stat.isSymbolicLink()) fs.unlinkSync(dst);
23
+ fs.rmSync(dst, { force: true, recursive: true });
24
24
  } catch {}
25
25
 
26
26
  fs.symlinkSync(src, dst);
@@ -33,17 +33,17 @@ function linkDir(src, dst) {
33
33
  `Link source missing: ${src} (run bash scripts/sync-skills.sh first)`
34
34
  );
35
35
  }
36
+ // Remove existing symlink or directory
36
37
  try {
37
- const stat = fs.lstatSync(dst);
38
- if (stat.isSymbolicLink()) fs.unlinkSync(dst);
38
+ fs.rmSync(dst, { force: true, recursive: true });
39
39
  } catch {}
40
40
  fs.symlinkSync(src, dst);
41
41
  }
42
42
 
43
43
  function linkFile(src, dst) {
44
+ // Remove existing symlink or file
44
45
  try {
45
- const stat = fs.lstatSync(dst);
46
- if (stat.isSymbolicLink()) fs.unlinkSync(dst);
46
+ fs.rmSync(dst, { force: true });
47
47
  } catch {}
48
48
  fs.symlinkSync(src, dst);
49
49
  }
@@ -73,9 +73,9 @@ function linkHook(src, dst) {
73
73
  `Hook source missing: ${src} (expected under repo skills/ or scripts/hooks/; fix path or restore file)`
74
74
  );
75
75
  }
76
+ // Remove existing symlink or file
76
77
  try {
77
- const stat = fs.lstatSync(dst);
78
- if (stat.isSymbolicLink()) fs.unlinkSync(dst);
78
+ fs.rmSync(dst, { force: true });
79
79
  } catch {}
80
80
  fs.symlinkSync(src, dst);
81
81
  try { fs.chmodSync(src, 0o755); } catch {}
@@ -17,25 +17,33 @@
17
17
  # Run this after adding or updating any skill. Symlinks carry changes through automatically.
18
18
  #
19
19
  # Flags:
20
- # --okf Generate specs/skills-wiki/ OKF concept bundle from SKILL.md frontmatter
21
- # --opencode <p> Sync to bigpowers-opencode repo
20
+ # --okf Generate specs/skills-wiki/ OKF concept bundle from SKILL.md frontmatter
21
+ # --opencode <p> Sync to bigpowers-opencode repo
22
+ # --distribute-only Render skills to target tool directories only — skip
23
+ # lockfile/index/README/reference-table/OKF-wiki regen.
24
+ # Used by bin/setup.js: end-user installs never carry
25
+ # specs/ or docs/ (see .npmignore), so that dev-only
26
+ # maintenance step has nothing to operate on.
22
27
  set -euo pipefail
23
28
  source "$(dirname "${BASH_SOURCE[0]}")/lib/python-env.sh"
24
29
 
25
30
  OKF_MODE=0
26
31
  OPN_TARGET=""
32
+ DISTRIBUTE_ONLY=0
27
33
 
28
34
  for arg in "$@"; do
29
35
  case "$arg" in
30
36
  --okf) OKF_MODE=1 ;;
31
37
  --opencode=*) OPN_TARGET="${arg#*=}" ;;
32
38
  --opencode) shift; OPN_TARGET="$1" ;;
39
+ --distribute-only) DISTRIBUTE_ONLY=1 ;;
33
40
  --help|-h)
34
- echo "Usage: sync-skills.sh [--okf] [--opencode <path>]"
41
+ echo "Usage: sync-skills.sh [--okf] [--opencode <path>] [--distribute-only]"
35
42
  echo ""
36
- echo " --okf Generate specs/skills-wiki/ OKF concept bundle"
37
- echo " --opencode Sync skills to bigpowers-opencode repo"
38
- echo " --help Show this message"
43
+ echo " --okf Generate specs/skills-wiki/ OKF concept bundle"
44
+ echo " --opencode Sync skills to bigpowers-opencode repo"
45
+ echo " --distribute-only Render skills only — skip dev-maintenance regen"
46
+ echo " --help Show this message"
39
47
  exit 0
40
48
  ;;
41
49
  *) echo "sync-skills: unknown flag: $arg" >&2; exit 2 ;;
@@ -96,5 +104,10 @@ if [[ "$OKF_MODE" -eq 1 ]]; then
96
104
  bash "$REPO_ROOT/scripts/okf-post-sync.sh"
97
105
  fi
98
106
 
107
+ if [[ "$DISTRIBUTE_ONLY" -eq 1 ]]; then
108
+ echo "sync-skills: $skill_count skills synced (--distribute-only: dev-maintenance regen skipped)"
109
+ exit 0
110
+ fi
111
+
99
112
  sync_post_run "$skill_count" "$opencode_count"
100
113
  exit 0
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env bash
2
+ # story: BUG-2026-07-24-installer-runs-dev-maintenance-pipeline
3
+ # Regression test: bigpowers setup must not run bigpowers' own dev-maintenance
4
+ # regen (lockfile, SKILL-INDEX, OKF wikis) against an end-user install.
5
+ set -euo pipefail
6
+
7
+ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
8
+ PASS=0
9
+ FAIL=0
10
+
11
+ pass() { echo "PASS: $1"; PASS=$((PASS + 1)); }
12
+ fail() { echo "FAIL: $1" >&2; FAIL=$((FAIL + 1)); }
13
+
14
+ echo "=== test-install-distribute-only.sh ==="
15
+
16
+ SYNC_SH="$REPO_ROOT/scripts/sync-skills.sh"
17
+ SETUP_JS="$REPO_ROOT/bin/setup.js"
18
+
19
+ grep -q -- '--distribute-only' "$SYNC_SH" && pass 'sync-skills.sh: --distribute-only flag defined' \
20
+ || fail 'sync-skills.sh: missing --distribute-only flag'
21
+ grep -q "sync-skills.sh --distribute-only" "$SETUP_JS" && pass 'setup.js: invokes sync-skills.sh with --distribute-only' \
22
+ || fail 'setup.js: does not pass --distribute-only'
23
+
24
+ hash_of() { [[ -f "$1" ]] && shasum -a 256 "$1" | awk '{print $1}' || echo "absent"; }
25
+ listing_of() { [[ -d "$1" ]] && (find "$1" -maxdepth 1 -type f | sort) || echo "absent"; }
26
+
27
+ LOCK_BEFORE=$(hash_of "$REPO_ROOT/skills-lock.json")
28
+ INDEX_BEFORE=$(hash_of "$REPO_ROOT/SKILL-INDEX.md")
29
+ SEARCH_INDEX_BEFORE=$(hash_of "$REPO_ROOT/specs/SKILL-SEARCH-INDEX_LATEST.md")
30
+ EPICS_WIKI_BEFORE=$(listing_of "$REPO_ROOT/specs/epics-wiki")
31
+
32
+ OUT="$(cd "$REPO_ROOT" && bash scripts/sync-skills.sh --distribute-only 2>&1)"
33
+ echo "$OUT" | grep -q -- '--distribute-only: dev-maintenance regen skipped' \
34
+ && pass 'sync-skills.sh --distribute-only: confirmation message printed' \
35
+ || fail 'sync-skills.sh --distribute-only: missing confirmation message'
36
+ echo "$OUT" | grep -q 'Generating OKF wikis' \
37
+ && fail 'sync-skills.sh --distribute-only: still generated OKF wikis' \
38
+ || pass 'sync-skills.sh --distribute-only: no OKF wiki generation'
39
+ echo "$OUT" | grep -q 'regenerate-lockfile' \
40
+ && fail 'sync-skills.sh --distribute-only: still regenerated lockfile' \
41
+ || pass 'sync-skills.sh --distribute-only: no lockfile regen'
42
+
43
+ [[ "$(hash_of "$REPO_ROOT/skills-lock.json")" == "$LOCK_BEFORE" ]] \
44
+ && pass 'skills-lock.json untouched' || fail 'skills-lock.json was modified'
45
+ [[ "$(hash_of "$REPO_ROOT/SKILL-INDEX.md")" == "$INDEX_BEFORE" ]] \
46
+ && pass 'SKILL-INDEX.md untouched' || fail 'SKILL-INDEX.md was modified'
47
+ [[ "$(hash_of "$REPO_ROOT/specs/SKILL-SEARCH-INDEX_LATEST.md")" == "$SEARCH_INDEX_BEFORE" ]] \
48
+ && pass 'SKILL-SEARCH-INDEX_LATEST.md untouched' || fail 'SKILL-SEARCH-INDEX_LATEST.md was modified'
49
+ [[ "$(listing_of "$REPO_ROOT/specs/epics-wiki")" == "$EPICS_WIKI_BEFORE" ]] \
50
+ && pass 'specs/epics-wiki/ untouched' || fail 'specs/epics-wiki/ was modified'
51
+
52
+ [[ -f "$REPO_ROOT/.cursor/rules/fix-bug.mdc" ]] && pass 'skills still distributed (.cursor/rules populated)' \
53
+ || fail 'skill distribution did not run'
54
+
55
+ bash -n "$SYNC_SH" && pass 'bash -n sync-skills.sh' || fail 'bash -n sync-skills.sh'
56
+ node --check "$SETUP_JS" && pass 'node --check setup.js' || fail 'node --check setup.js'
57
+
58
+ echo "test-install-distribute-only: $PASS passed, $FAIL failed"
59
+ [[ "$FAIL" -eq 0 ]] || exit 1