bigpowers 2.79.1 → 2.80.0

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.79.1",
3
+ "version": "2.80.0",
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,10 @@
1
+ # [2.80.0](https://github.com/danielvm-git/bigpowers/compare/v2.79.1...v2.80.0) (2026-07-23)
2
+
3
+
4
+ ### Features
5
+
6
+ * **e54s01:** freeze skill catalog baseline snapshot ([0df0fff](https://github.com/danielvm-git/bigpowers/commit/0df0fff86fc48794a2343ae4b2c421835bc5c58c))
7
+
1
8
  ## [2.79.1](https://github.com/danielvm-git/bigpowers/compare/v2.79.0...v2.79.1) (2026-07-23)
2
9
 
3
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.79.1",
3
+ "version": "2.80.0",
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": {
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env bash
2
+ # story: e54s01
3
+ # snapshot-catalog-baseline.sh — freeze the live skill catalog into a dated,
4
+ # immutable YAML baseline for e56's reclassification diff.
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ source "$SCRIPT_DIR/lib/skill-common.sh"
9
+ source "$SCRIPT_DIR/lib/python-env.sh"
10
+
11
+ resolve_repo_root
12
+ cd "$REPO_ROOT"
13
+
14
+ DRY_RUN=false
15
+ while [[ $# -gt 0 ]]; do
16
+ case "$1" in
17
+ --dry-run) DRY_RUN=true; shift ;;
18
+ -h|--help) echo "Usage: bash scripts/snapshot-catalog-baseline.sh [--dry-run]"; exit 0 ;;
19
+ *) echo "Unknown flag: $1" >&2; exit 2 ;;
20
+ esac
21
+ done
22
+
23
+ DATE_STR="$(date +%Y-%m-%d)"
24
+ COMMIT_HASH="$(git rev-parse HEAD 2>/dev/null || echo unknown)"
25
+ OUT_FILE="$REPO_ROOT/specs/tech-architecture/CATALOG-BASELINE-${DATE_STR}.yaml"
26
+
27
+ # unquote_source_desc — strip a source frontmatter's own surrounding quotes
28
+ # and unescape its inner \" , or re-quoting double-escapes the description.
29
+ unquote_source_desc() {
30
+ local desc="$1"
31
+ if [[ "$desc" == \"*\" ]]; then
32
+ desc="${desc#\"}"
33
+ desc="${desc%\"}"
34
+ desc="${desc//\\\"/\"}"
35
+ fi
36
+ echo "$desc"
37
+ }
38
+
39
+ # emit_skill_row — print one skill's YAML row to stdout; appends any missing-
40
+ # field warning line for that skill to $WARN_FILE (a plain file, since this
41
+ # function runs inside a command-substitution subshell and can't mutate the
42
+ # caller's shell variables).
43
+ emit_skill_row() {
44
+ local skill_md="$1" name phase model effort desc desc_escaped
45
+ name="$(basename "$(dirname "$skill_md")")"
46
+ parse_frontmatter_okf "$skill_md" || true
47
+
48
+ phase="$(awk '/^---/{f++} f==1 && /^phase:/{print; exit}' "$skill_md" | sed 's/^phase:[[:space:]]*//')"
49
+ model="${_PF_MODEL:-}"
50
+ effort="${_PF_EFFORT:-}"
51
+ desc="${_PF_DESCRIPTION:-}"
52
+
53
+ [[ -z "$phase" ]] && phase="null"
54
+ [[ -z "$model" ]] && { model="null"; echo " - \"${name}: missing model field\"" >> "$WARN_FILE"; }
55
+ [[ -z "$effort" ]] && { effort="null"; echo " - \"${name}: missing effort field\"" >> "$WARN_FILE"; }
56
+ [[ -z "$desc" ]] && desc="null"
57
+
58
+ desc="$(unquote_source_desc "$desc")"
59
+ desc_escaped="${desc//\"/\\\"}"
60
+
61
+ echo " - name: \"${name}\"\n path: \"skills/${name}/SKILL.md\"\n phase: ${phase}\n effort: ${effort}\n model: ${model}\n description: \"${desc_escaped}\"\n"
62
+ }
63
+
64
+ WARN_FILE="$(mktemp)"
65
+ trap 'rm -f "$WARN_FILE"' EXIT
66
+
67
+ ROWS=""
68
+ COUNT=0
69
+
70
+ for skill_md in "$SKILLS_ROOT"/*/SKILL.md; do
71
+ [[ -f "$skill_md" ]] || continue
72
+ ROWS="${ROWS}$(emit_skill_row "$skill_md")"
73
+ COUNT=$((COUNT + 1))
74
+ done
75
+
76
+ WARNINGS="$(cat "$WARN_FILE")"
77
+ WARN_COUNT="$(grep -c '^ -' "$WARN_FILE" || true)"
78
+
79
+ if $DRY_RUN; then
80
+ echo "${COUNT} skills scanned"
81
+ echo "${WARN_COUNT} warnings"
82
+ [[ -n "$WARNINGS" ]] && echo -e "warnings:\n${WARNINGS}"
83
+ exit 0
84
+ fi
85
+
86
+ mkdir -p "$REPO_ROOT/specs/tech-architecture"
87
+
88
+ {
89
+ echo "# CATALOG-BASELINE-${DATE_STR}.yaml"
90
+ echo "# frozen for e54-e59 migration; do not hand-edit"
91
+ echo "snapshot_date: \"${DATE_STR}\""
92
+ echo "commit_hash: \"${COMMIT_HASH}\""
93
+ echo "total_skill_count: ${COUNT}"
94
+ echo "warnings:"
95
+ if [[ -n "$WARNINGS" ]]; then
96
+ echo -e "$WARNINGS"
97
+ else
98
+ echo " []"
99
+ fi
100
+ echo "skills:"
101
+ echo -e "$ROWS"
102
+ } > "$OUT_FILE"
103
+
104
+ echo "Wrote ${OUT_FILE} (${COUNT} skills, ${WARN_COUNT} warnings)"
@@ -102,6 +102,48 @@ else
102
102
  tt_fail "expired tombstone was not flagged"
103
103
  fi
104
104
 
105
+ # --- Scenario: rejects path-traversal / invalid skill names (threat model CWE-22) ---
106
+ # tombstone-skill.sh exits non-zero on rejection, and this script runs under
107
+ # `set -o pipefail` — capture output via `|| true` first so the pipe's exit
108
+ # status doesn't mask the grep check below.
109
+ output=$(bash scripts/tombstone-skill.sh "../../etc/passwd" "target" 2>&1 || true)
110
+ if echo "$output" | grep -qi "not a valid skill name"; then
111
+ tt_pass "tombstone-skill.sh rejects a path-traversal old-name"
112
+ else
113
+ tt_fail "tombstone-skill.sh did not reject a path-traversal old-name"
114
+ fi
115
+
116
+ output=$(bash scripts/tombstone-skill.sh "$FIXTURE_OLD" "../../etc/passwd" 2>&1 || true)
117
+ if echo "$output" | grep -qi "not a valid skill name"; then
118
+ tt_pass "tombstone-skill.sh rejects a path-traversal new-name"
119
+ else
120
+ tt_fail "tombstone-skill.sh did not reject a path-traversal new-name"
121
+ fi
122
+
123
+ # --- Scenario: validate-tombstones.sh rejects an invalid name read back from the ledger ---
124
+ python3 -c "
125
+ import yaml
126
+ d = yaml.safe_load(open('$TOMBSTONES_FILE')) or {'tombstones': []}
127
+ d.setdefault('tombstones', []).append({
128
+ 'old_name': '../../etc/passwd',
129
+ 'new_name_or_merge_target': 'target',
130
+ 'created_at_version': '0.0.0',
131
+ })
132
+ yaml.dump(d, open('$TOMBSTONES_FILE', 'w'), default_flow_style=False)
133
+ "
134
+ output=$(bash scripts/validate-tombstones.sh 2>&1 | strip_ansi || true)
135
+ if echo "$output" | grep -qi "FAIL.*not a valid skill name"; then
136
+ tt_pass "validate-tombstones.sh rejects a path-traversal name read from the ledger"
137
+ else
138
+ tt_fail "validate-tombstones.sh did not reject a path-traversal name read from the ledger"
139
+ fi
140
+ python3 -c "
141
+ import yaml
142
+ d = yaml.safe_load(open('$TOMBSTONES_FILE')) or {'tombstones': []}
143
+ d['tombstones'] = [t for t in d.get('tombstones', []) if t.get('old_name') != '../../etc/passwd']
144
+ yaml.dump(d, open('$TOMBSTONES_FILE', 'w'), default_flow_style=False)
145
+ "
146
+
105
147
  echo "---"
106
148
  if [[ "$FAILURES" -eq 0 ]]; then
107
149
  echo -e "${GREEN}test-tombstone-mechanism: ALL PASS${NC}"