bigpowers 2.75.1 → 2.76.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 +1 -1
- package/CHANGELOG.md +20 -0
- package/bin/bigspec +35 -1
- package/kernel/src/publish-to-wiki.sh +131 -6
- package/package.json +1 -1
- package/scripts/audit-compliance.sh +2 -3
- package/scripts/build-receipts.sh +2 -2
- package/scripts/build-skill-graph.sh +1 -1
- package/scripts/check-spec-drift.sh +2 -2
- package/scripts/check-spec-version-gap.sh +13 -13
- package/scripts/compile-rule-matrix.sh +2 -2
- package/scripts/decompose-conventions.sh +2 -2
- package/scripts/generate-adr-wiki.sh +3 -2
- package/scripts/generate-agent-guide.sh +2 -2
- package/scripts/generate-epics-wiki.sh +3 -2
- package/scripts/hooks/token-mgmt-pre-tool-use.sh +5 -5
- package/scripts/land-branch.sh +11 -11
- package/scripts/lib/audit-compliance-report.sh +1 -0
- package/scripts/lib/emit-okf-metrics.sh +1 -0
- package/scripts/lib/golden-suite-report.sh +1 -0
- package/scripts/lib/golden-suite-run.sh +5 -1
- package/scripts/lib/migrate-version-transforms.sh +3 -4
- package/scripts/lib/record-cycle-time-lib.sh +31 -0
- package/scripts/lib/sync-post.sh +6 -1
- package/scripts/lib/test-assertions.sh +11 -0
- package/scripts/lib/validate-okf-kinds.sh +7 -4
- package/scripts/record-cycle-time.sh +4 -28
- package/scripts/sync-bugs-registry.sh +1 -0
- package/scripts/sync-skills.sh +3 -3
- package/scripts/test-adapters.sh +13 -13
- package/scripts/test-trace-matrix-size.sh +4 -4
- package/scripts/test-trace-strict.sh +8 -8
- package/scripts/validate-doctrine.sh +18 -18
- package/scripts/validate-skill-catalog.sh +10 -10
- package/scripts/verify-install.sh +39 -37
- package/tests/test-epic-status-drift.sh +53 -0
- package/tests/test-okf-generators.sh +57 -0
package/.pi/package.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
# [2.76.0](https://github.com/danielvm-git/bigpowers/compare/v2.75.2...v2.76.0) (2026-07-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **ci:** add OKF type fields and gate wiki publish on WIKI_PAT ([9628122](https://github.com/danielvm-git/bigpowers/commit/96281227e91ebed19300daed8dd05d51d6021c9e))
|
|
7
|
+
* **ci:** skip estimated commit_range check and wiki publish without PAT ([bf079ad](https://github.com/danielvm-git/bigpowers/commit/bf079ad384c4363980fe30383406d37629718b89))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **e37:** Reach — Close release: AGENTS.md spine, targets.yaml registry, OSS waves A-E; fix 6 compliance bugs ([5a7f407](https://github.com/danielvm-git/bigpowers/commit/5a7f407008818cec518969a2b46e5ae28ee130bb))
|
|
13
|
+
|
|
14
|
+
## [2.75.2](https://github.com/danielvm-git/bigpowers/compare/v2.75.1...v2.75.2) (2026-07-07)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* **ci:** enforce blocking OKF validation and close bug audit gaps ([e502c62](https://github.com/danielvm-git/bigpowers/commit/e502c62583024df36bed086d8e44a871907632cd))
|
|
20
|
+
|
|
1
21
|
## [2.75.1](https://github.com/danielvm-git/bigpowers/compare/v2.75.0...v2.75.1) (2026-07-07)
|
|
2
22
|
|
|
3
23
|
|
package/bin/bigspec
CHANGED
|
@@ -1,2 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
|
|
2
|
+
# story: e48s10
|
|
3
|
+
# bigspec — minimal project bootstrap helper
|
|
4
|
+
|
|
5
|
+
print_wiki_setup() {
|
|
6
|
+
cat <<'EOF'
|
|
7
|
+
Wiki publishing enabled.
|
|
8
|
+
|
|
9
|
+
1. Create a GitHub Wiki for this repository (or use the .wiki.git remote).
|
|
10
|
+
2. Configure CI secrets: WIKI_PAT (repo scope for wiki push).
|
|
11
|
+
3. Set WIKI_REPO_URL to the wiki clone URL (e.g. https://github.com/org/repo.wiki.git).
|
|
12
|
+
4. Dry-run locally: bash kernel/src/publish-to-wiki.sh --dry-run
|
|
13
|
+
5. Publish on merge: .github/workflows/publish-wiki.yml (gates on validate-okf first).
|
|
14
|
+
|
|
15
|
+
See docs/references/okf.md for OKF bundle layout and CI integration.
|
|
16
|
+
EOF
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
case "${1:-}" in
|
|
20
|
+
init)
|
|
21
|
+
if [[ "${2:-}" == "--with-wiki" ]]; then
|
|
22
|
+
print_wiki_setup
|
|
23
|
+
exit 0
|
|
24
|
+
fi
|
|
25
|
+
echo "Usage: bigspec init [--with-wiki]"
|
|
26
|
+
exit 1
|
|
27
|
+
;;
|
|
28
|
+
--with-wiki)
|
|
29
|
+
print_wiki_setup
|
|
30
|
+
exit 0
|
|
31
|
+
;;
|
|
32
|
+
*)
|
|
33
|
+
echo "Usage: bigspec init [--with-wiki]"
|
|
34
|
+
exit 1
|
|
35
|
+
;;
|
|
36
|
+
esac
|
|
@@ -3,23 +3,148 @@
|
|
|
3
3
|
# publish-to-wiki.sh — publish OKF bundles to a .wiki.git repository
|
|
4
4
|
set -euo pipefail
|
|
5
5
|
|
|
6
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
7
|
+
HEADER="$ROOT/kernel/templates/wiki/header.md"
|
|
8
|
+
EPICS_SRC="$ROOT/specs/epics-wiki"
|
|
9
|
+
ADR_SRC="$ROOT/specs/adr-wiki"
|
|
10
|
+
|
|
6
11
|
usage() {
|
|
7
12
|
echo "Usage: $0 [--dry-run]"
|
|
8
|
-
echo "Publishes OKF concept bundles from specs/epics-wiki and specs/adr-wiki
|
|
13
|
+
echo "Publishes OKF concept bundles from specs/epics-wiki and specs/adr-wiki"
|
|
14
|
+
echo "to the configured wiki git repository, rewriting links to wiki slug format."
|
|
9
15
|
exit 0
|
|
10
16
|
}
|
|
11
17
|
|
|
12
|
-
|
|
18
|
+
wiki_slug_from_file() {
|
|
19
|
+
local base
|
|
20
|
+
base="$(basename "$1")"
|
|
21
|
+
base="${base%.okf.md}"
|
|
22
|
+
base="${base%.md}"
|
|
23
|
+
echo "$base"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
rewrite_links() {
|
|
27
|
+
sed -E \
|
|
28
|
+
-e 's/\]\(([^)]*)\.okf\.md\)/](\1)/g' \
|
|
29
|
+
-e 's/\]\(([^)]*)\.md\)/](\1)/g' \
|
|
30
|
+
-e 's/\]\(specs\/[^)]+\/([^/)]+)\)/](\1)/g'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
stage_bundle() {
|
|
34
|
+
local src="$1" section="$2" dest_root="$3"
|
|
35
|
+
local slug dest_dir dest_file
|
|
36
|
+
slug="$(wiki_slug_from_file "$src")"
|
|
37
|
+
dest_dir="$dest_root/$section"
|
|
38
|
+
dest_file="$dest_dir/${slug}.md"
|
|
39
|
+
mkdir -p "$dest_dir"
|
|
40
|
+
{
|
|
41
|
+
if [[ -f "$HEADER" ]]; then cat "$HEADER"; echo ""; fi
|
|
42
|
+
rewrite_links < "$src"
|
|
43
|
+
} > "$dest_file"
|
|
44
|
+
echo "$section/$slug.md"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
collect_sources() {
|
|
48
|
+
local dir="$1"
|
|
49
|
+
if [[ -d "$dir" ]]; then
|
|
50
|
+
find "$dir" -maxdepth 1 -name '*.okf.md' -type f | sort
|
|
51
|
+
fi
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
publish_bundles() {
|
|
55
|
+
local dest_root="$1"
|
|
56
|
+
local -a pages=()
|
|
57
|
+
local src
|
|
58
|
+
|
|
59
|
+
rm -rf "$dest_root"
|
|
60
|
+
mkdir -p "$dest_root"
|
|
61
|
+
|
|
62
|
+
while IFS= read -r src; do
|
|
63
|
+
[[ -n "$src" ]] || continue
|
|
64
|
+
pages+=("$(stage_bundle "$src" "Epics" "$dest_root")")
|
|
65
|
+
done < <(collect_sources "$EPICS_SRC")
|
|
66
|
+
|
|
67
|
+
while IFS= read -r src; do
|
|
68
|
+
[[ -n "$src" ]] || continue
|
|
69
|
+
pages+=("$(stage_bundle "$src" "ADRs" "$dest_root")")
|
|
70
|
+
done < <(collect_sources "$ADR_SRC")
|
|
71
|
+
|
|
72
|
+
if [[ -f "$ROOT/kernel/templates/wiki/_Sidebar.md" ]]; then
|
|
73
|
+
cp "$ROOT/kernel/templates/wiki/_Sidebar.md" "$dest_root/_Sidebar.md"
|
|
74
|
+
pages+=("_Sidebar.md")
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
printf '%s\n' "${pages[@]}"
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
push_to_wiki() {
|
|
81
|
+
local staged_root="$1"
|
|
82
|
+
local wiki_repo="${WIKI_REPO_URL:-}"
|
|
83
|
+
local work_dir="${WIKI_WORK_DIR:-}"
|
|
84
|
+
|
|
85
|
+
if [[ -z "$wiki_repo" ]]; then
|
|
86
|
+
echo "publish-to-wiki: WIKI_REPO_URL is not set — skipping push" >&2
|
|
87
|
+
return 0
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
local clone_url="$wiki_repo"
|
|
91
|
+
if [[ -n "${WIKI_PAT:-}" && "$wiki_repo" == https://* ]]; then
|
|
92
|
+
clone_url="${wiki_repo/https:\/\//https://x-access-token:${WIKI_PAT}@}"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
if [[ -z "$work_dir" ]]; then
|
|
96
|
+
work_dir="$(mktemp -d)"
|
|
97
|
+
trap 'rm -rf "$work_dir"' EXIT
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if [[ -d "$work_dir/.git" ]]; then
|
|
101
|
+
git -C "$work_dir" pull --rebase origin master 2>/dev/null || git -C "$work_dir" pull --rebase origin main
|
|
102
|
+
else
|
|
103
|
+
git clone "$clone_url" "$work_dir"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
rsync -a --delete "$staged_root/" "$work_dir/"
|
|
107
|
+
git -C "$work_dir" add -A
|
|
108
|
+
if git -C "$work_dir" diff --cached --quiet; then
|
|
109
|
+
echo "publish-to-wiki: no wiki changes to push"
|
|
110
|
+
return 0
|
|
111
|
+
fi
|
|
112
|
+
git -C "$work_dir" -c user.name="bigpowers-bot" -c user.email="bot@bigpowers.local" \
|
|
113
|
+
commit -m "chore(wiki): sync OKF bundles from main"
|
|
114
|
+
git -C "$work_dir" push origin HEAD
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
|
13
118
|
usage
|
|
14
119
|
fi
|
|
15
120
|
|
|
16
121
|
DRY_RUN=0
|
|
17
122
|
if [[ "${1:-}" == "--dry-run" ]]; then
|
|
18
123
|
DRY_RUN=1
|
|
19
|
-
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
STAGING="$(mktemp -d)"
|
|
127
|
+
trap 'rm -rf "$STAGING"' EXIT
|
|
128
|
+
|
|
129
|
+
mapfile -t PAGES < <(publish_bundles "$STAGING")
|
|
130
|
+
PAGE_COUNT="${#PAGES[@]}"
|
|
131
|
+
|
|
132
|
+
if [[ "$PAGE_COUNT" -eq 0 ]]; then
|
|
133
|
+
echo "publish-to-wiki: no OKF bundles found under specs/epics-wiki or specs/adr-wiki" >&2
|
|
134
|
+
exit 1
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
echo "publish-to-wiki: pages: $PAGE_COUNT"
|
|
138
|
+
printf ' - %s\n' "${PAGES[@]}"
|
|
139
|
+
|
|
140
|
+
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
141
|
+
echo "publish-to-wiki: dry-run complete (staged under $STAGING)"
|
|
142
|
+
exit 0
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
if [[ -z "${WIKI_PAT:-}" ]]; then
|
|
146
|
+
echo "publish-to-wiki: WIKI_PAT not set — skipping wiki push"
|
|
20
147
|
exit 0
|
|
21
148
|
fi
|
|
22
149
|
|
|
23
|
-
|
|
24
|
-
echo "publish-to-wiki: Rewriting links and publishing to wiki..."
|
|
25
|
-
exit 0
|
|
150
|
+
push_to_wiki "$STAGING"
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# audit-compliance.sh — Agentic Gherkin Compliance Harness (LLM-Judge Upgrade)
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
source "$
|
|
6
|
-
source "$_LIB/audit-compliance-report.sh"
|
|
4
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/audit-compliance-runner.sh"
|
|
5
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/audit-compliance-report.sh"
|
|
7
6
|
|
|
8
7
|
audit_show_help() {
|
|
9
8
|
cat <<EOF
|
|
@@ -6,7 +6,7 @@ source "$(dirname "${BASH_SOURCE[0]}")/lib/python-env.sh"
|
|
|
6
6
|
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || { echo "build-receipts: not inside a git repo" >&2; exit 1; }
|
|
7
7
|
OUTFILE="$ROOT/specs/receipts.json"
|
|
8
8
|
TIMESTAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
9
|
-
|
|
9
|
+
receipts_emit_json() {
|
|
10
10
|
$PYTHON -c "
|
|
11
11
|
import json, sys, os, subprocess, glob as gb
|
|
12
12
|
sections = {}
|
|
@@ -103,6 +103,6 @@ for key, sec in sections.items(): print(f' {key}: source={sec.get(\"source\",\"
|
|
|
103
103
|
"
|
|
104
104
|
}
|
|
105
105
|
echo "build-receipts: aggregating quality evidence..."
|
|
106
|
-
|
|
106
|
+
receipts_emit_json
|
|
107
107
|
echo "build-receipts: done — $(date -u +%H:%M:%SZ)"
|
|
108
108
|
exit 0
|
|
@@ -12,7 +12,7 @@ GRAPH_JSONL="$REPO_ROOT/bigpowers-mcp/graph.jsonl"
|
|
|
12
12
|
SKILL_GRAPH_JSON="$REPO_ROOT/specs/skill-graph.json"
|
|
13
13
|
SKILLS_WIKI="$REPO_ROOT/specs/skills-wiki/skills"
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
skill_graph_show_help() {
|
|
16
16
|
cat <<EOF
|
|
17
17
|
Usage: $(basename "$0") [OPTION]
|
|
18
18
|
|
|
@@ -10,7 +10,7 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
10
10
|
TRACE_MATRIX="$REPO_ROOT/specs/traceability-matrix.json"
|
|
11
11
|
DRIFT_REPORT="$REPO_ROOT/specs/drift-report.json"
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
drift_show_help() {
|
|
14
14
|
cat <<EOF
|
|
15
15
|
Usage: $(basename "$0") [OPTION]
|
|
16
16
|
|
|
@@ -23,7 +23,7 @@ EOF
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
if [ "$#" -eq 1 ] && [ "$1" = "--help" ]; then
|
|
26
|
-
|
|
26
|
+
drift_show_help
|
|
27
27
|
exit 0
|
|
28
28
|
fi
|
|
29
29
|
|
|
@@ -5,7 +5,7 @@ source "$(dirname "${BASH_SOURCE[0]}")/lib/python-env.sh"
|
|
|
5
5
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
6
|
BP_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
gap_usage() {
|
|
9
9
|
cat <<'EOF'
|
|
10
10
|
Usage: check-spec-version-gap.sh [--help] [--project <dir>] [--json]
|
|
11
11
|
Exit codes: 0=no gap, 1=gap, 2=no specs, 3=blocked, 4=error
|
|
@@ -18,7 +18,7 @@ JSON_STDOUT=false
|
|
|
18
18
|
SKIP_BLOCK=false
|
|
19
19
|
while [[ $# -gt 0 ]]; do
|
|
20
20
|
case "$1" in
|
|
21
|
-
--help|-h)
|
|
21
|
+
--help|-h) gap_usage ;;
|
|
22
22
|
--project) PROJECT_DIR="${2:?}"; shift 2 ;;
|
|
23
23
|
--json) JSON_STDOUT=true; shift ;;
|
|
24
24
|
--skip-block) SKIP_BLOCK=true; shift ;;
|
|
@@ -29,7 +29,7 @@ done
|
|
|
29
29
|
PROJECT_DIR="$(cd "$PROJECT_DIR" 2>/dev/null && pwd)" || { echo "bad dir: $PROJECT_DIR" >&2; exit 4; }
|
|
30
30
|
SPECS="$PROJECT_DIR/specs"
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
gap_emit_json() {
|
|
33
33
|
if $JSON_STDOUT; then echo "$1"; else echo "$1" >&2; fi
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -37,7 +37,7 @@ get_installed_version() {
|
|
|
37
37
|
$PYTHON -c "import json; d=json.load(open('$BP_ROOT/package.json')); print(d.get('version','unknown'))" 2>/dev/null || echo "unknown"
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
gap_yaml_get() {
|
|
41
41
|
[[ ! -f "$1" ]] && { echo ""; return; }
|
|
42
42
|
$PYTHON -c "
|
|
43
43
|
import sys, yaml
|
|
@@ -116,29 +116,29 @@ check_active_work() {
|
|
|
116
116
|
branch=$(git -C "$PROJECT_DIR" branch --show-current 2>/dev/null || echo "")
|
|
117
117
|
if on_feature_branch "$branch"; then echo "true"; return; fi
|
|
118
118
|
if has_dirty_specs; then echo "true"; return; fi
|
|
119
|
-
af=$(
|
|
119
|
+
af=$(gap_yaml_get "$SPECS/state.yaml" "active_flow")
|
|
120
120
|
if is_blocking_active_flow "$af"; then echo "true"; return; fi
|
|
121
121
|
echo "false"
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
# Main
|
|
125
|
-
[[ ! -d "$SPECS" ]] && {
|
|
125
|
+
[[ ! -d "$SPECS" ]] && { gap_emit_json '{"gap":false,"reason":"NO_SPECS"}'; exit 2; }
|
|
126
126
|
IV=$(get_installed_version)
|
|
127
127
|
if [ "$SKIP_BLOCK" != "true" ] && [[ "$(check_active_work)" == "true" ]]; then
|
|
128
|
-
|
|
128
|
+
gap_emit_json '{"gap":true,"blocked":true,"reason":"ACTIVE_WORK","installed_version":"'"$IV"'"}'
|
|
129
129
|
exit 3
|
|
130
130
|
fi
|
|
131
131
|
|
|
132
|
-
SV=$(
|
|
132
|
+
SV=$(gap_yaml_get "$SPECS/state.yaml" "bigpowers_version")
|
|
133
133
|
|
|
134
134
|
if yaml_value_set "$SV"; then
|
|
135
135
|
if [[ "$SV" == "$IV" ]]; then
|
|
136
|
-
|
|
136
|
+
gap_emit_json '{"gap":false,"stamp":true,"detected_version":"'"$SV"'","installed_version":"'"$IV"'","detection_method":"stamp","confidence":"high"}'
|
|
137
137
|
exit 0
|
|
138
138
|
fi
|
|
139
139
|
APP=$(find_migrations "$SV")
|
|
140
140
|
CNT=$(echo "$APP" | $PYTHON -c "import json,sys; print(len(json.load(sys.stdin)))" 2>/dev/null || echo 0)
|
|
141
|
-
|
|
141
|
+
gap_emit_json "$($PYTHON -c "import json; a=json.loads('''$APP'''); print(json.dumps({'gap':True,'stamp':True,'detected_version':'$SV','detection_method':'stamp','installed_version':'$IV','applicable_migrations':len(a),'migration_ids':[m['id'] for m in a],'confidence':'high','active_work_blocked':False}))")"
|
|
142
142
|
exit 1
|
|
143
143
|
fi
|
|
144
144
|
|
|
@@ -150,7 +150,7 @@ for f in release-plan.yaml execution-status.yaml product/SCOPE_LATEST.yaml metri
|
|
|
150
150
|
[[ -f "$SPECS/$f" ]] && { MARKERS+=("$f"); [[ -z "$DV" ]] && DV="2.0.0"; }
|
|
151
151
|
done
|
|
152
152
|
if [[ -f "$SPECS/state.yaml" ]]; then
|
|
153
|
-
ec=$(
|
|
153
|
+
ec=$(gap_yaml_get "$SPECS/state.yaml" "epic_cycle.current_step")
|
|
154
154
|
if yaml_value_set "$ec"; then
|
|
155
155
|
MARKERS+=("epic_cycle"); [[ "$DV" == "2.0.0" ]] && DV="2.20.0"
|
|
156
156
|
fi
|
|
@@ -161,12 +161,12 @@ fi
|
|
|
161
161
|
[[ -z "$DV" ]] && { DV="unknown"; CONF="low"; }
|
|
162
162
|
|
|
163
163
|
if [[ "$DV" != "unknown" ]] && ! version_lt "$DV" "$IV"; then
|
|
164
|
-
[[ "$DV" == "$IV" ]] && {
|
|
164
|
+
[[ "$DV" == "$IV" ]] && { gap_emit_json '{"gap":false,"stamp":false,"detected_version":"'"$DV"'","installed_version":"'"$IV"'","detection_method":"fingerprint","confidence":"'"$CONF"'"}'; exit 0; }
|
|
165
165
|
fi
|
|
166
166
|
|
|
167
167
|
APP=$(find_migrations "$DV")
|
|
168
168
|
CNT=$(echo "$APP" | $PYTHON -c "import json,sys; print(len(json.load(sys.stdin)))" 2>/dev/null || echo 0)
|
|
169
169
|
MJ=$(printf '%s\n' "${MARKERS[@]}" | $PYTHON -c "import json,sys; print(json.dumps([l.strip() for l in sys.stdin if l.strip()]))" 2>/dev/null || echo "[]")
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
gap_emit_json "$($PYTHON -c "import json; a=json.loads('''$APP'''); m=json.loads('''$MJ'''); print(json.dumps({'gap':True,'stamp':False,'detected_version':'$DV','detection_method':'fingerprint','installed_version':'$IV','applicable_migrations':len(a),'migration_ids':[x['id'] for x in a],'confidence':'$CONF','active_work_blocked':False,'matched_markers':m}))")"
|
|
172
172
|
exit 1
|
|
@@ -10,7 +10,7 @@ CONVENTIONS="$REPO_ROOT/CONVENTIONS.md"
|
|
|
10
10
|
OUTPUT="$REPO_ROOT/specs/rule-matrix.json"
|
|
11
11
|
MATRIX_VERSION="1.0.0"
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
matrix_show_help() {
|
|
14
14
|
cat <<EOF
|
|
15
15
|
Usage: $(basename "$0") [OPTION]
|
|
16
16
|
|
|
@@ -26,7 +26,7 @@ EOF
|
|
|
26
26
|
STDOUT_ONLY=0
|
|
27
27
|
if [ "$#" -eq 1 ]; then
|
|
28
28
|
case "$1" in
|
|
29
|
-
--help)
|
|
29
|
+
--help) matrix_show_help; exit 0 ;;
|
|
30
30
|
--stdout) STDOUT_ONLY=1 ;;
|
|
31
31
|
*) echo "[ERROR] Unknown option: $1" >&2; exit 1 ;;
|
|
32
32
|
esac
|
|
@@ -11,7 +11,7 @@ CONVENTIONS_WIKI="$REPO_ROOT/specs/conventions-wiki"
|
|
|
11
11
|
CONVENTIONS_INDEX="$CONVENTIONS_WIKI/index.md"
|
|
12
12
|
SKILL_GRAPH="$REPO_ROOT/specs/skill-graph.json"
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
decompose_show_help() {
|
|
15
15
|
cat <<EOF
|
|
16
16
|
Usage: $(basename "$0") [OPTION]
|
|
17
17
|
|
|
@@ -24,7 +24,7 @@ EOF
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
if [ "$#" -eq 1 ] && [ "$1" = "--help" ]; then
|
|
27
|
-
|
|
27
|
+
decompose_show_help
|
|
28
28
|
exit 0
|
|
29
29
|
fi
|
|
30
30
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# story: e48s01
|
|
2
3
|
# story: e45s01 e45s06
|
|
3
4
|
# generate-adr-wiki.sh — emit OKF concept bundles from specs/adr/*.md
|
|
4
5
|
set -euo pipefail
|
|
@@ -16,7 +17,7 @@ fi
|
|
|
16
17
|
|
|
17
18
|
count=0
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
adr_wiki_assign_tier() {
|
|
20
21
|
local adr_id="$1"
|
|
21
22
|
case "$adr_id" in
|
|
22
23
|
ADR-0001|ADR-0002|ADR-0003|0001-*|0002-*|0003-*) echo "core" ;;
|
|
@@ -54,7 +55,7 @@ if len(parts) >= 3:
|
|
|
54
55
|
fi
|
|
55
56
|
[ -z "$title" ] && title="$adr_name"
|
|
56
57
|
|
|
57
|
-
tier=$(
|
|
58
|
+
tier=$(adr_wiki_assign_tier "$adr_name")
|
|
58
59
|
|
|
59
60
|
bundle="$WIKI/${adr_name}.okf.md"
|
|
60
61
|
|
|
@@ -9,7 +9,7 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
9
9
|
CLAUDE_MD="$REPO_ROOT/CLAUDE.md"
|
|
10
10
|
AGENT_GUIDE="$REPO_ROOT/specs/agent-guide"
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
agent_guide_show_help() {
|
|
13
13
|
cat <<EOF
|
|
14
14
|
Usage: $(basename "$0") [OPTION]
|
|
15
15
|
|
|
@@ -22,7 +22,7 @@ EOF
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
if [ "$#" -eq 1 ] && [ "$1" = "--help" ]; then
|
|
25
|
-
|
|
25
|
+
agent_guide_show_help
|
|
26
26
|
exit 0
|
|
27
27
|
fi
|
|
28
28
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# story: e48s01
|
|
2
3
|
# story: e45s01 e45s06
|
|
3
4
|
# generate-epics-wiki.sh — emit OKF concept bundles from specs/epics/*/epic.yaml
|
|
4
5
|
set -euo pipefail
|
|
@@ -15,7 +16,7 @@ extract() {
|
|
|
15
16
|
|
|
16
17
|
count=0
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
epics_wiki_assign_tier() {
|
|
19
20
|
local epic_id="$1"
|
|
20
21
|
case "$epic_id" in
|
|
21
22
|
e28|e38|e40|e41|e44|e45|e46) echo "core" ;;
|
|
@@ -42,7 +43,7 @@ for epic_yaml in "$ROOT"/specs/epics/*/epic.yaml "$ROOT"/specs/epics/archive/*/e
|
|
|
42
43
|
|
|
43
44
|
[[ -z "$epic_id" ]] && continue
|
|
44
45
|
|
|
45
|
-
tier=$(
|
|
46
|
+
tier=$(epics_wiki_assign_tier "$epic_id")
|
|
46
47
|
|
|
47
48
|
# Build references array from story list
|
|
48
49
|
story_count=$(grep -c '^\s*- id:' "$epic_yaml" 2>/dev/null || true)
|
|
@@ -7,7 +7,7 @@ READ_MAX_BYTES=102400 # 100KB
|
|
|
7
7
|
GREP_MAX_MATCHES=200
|
|
8
8
|
BASH_WARN_PATTERNS='^(npm test|pnpm test|yarn test|cargo test|go test|jest|vitest|pytest|rake test|rspec|git log|git diff|docker logs|kubectl logs|find |rg |grep )'
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
token_mgmt_deny() {
|
|
11
11
|
echo "TOKEN-MGMT BLOCK: $1" >&2
|
|
12
12
|
echo "Use sqz_read_file / sqz_grep / rtk / bts compress per CLAUDE.md § Token Management." >&2
|
|
13
13
|
exit 2
|
|
@@ -23,16 +23,16 @@ case "$TOOL" in
|
|
|
23
23
|
[[ -n "$PATH_ARG" && -f "$PATH_ARG" ]] || exit 0
|
|
24
24
|
SIZE="$(wc -c < "$PATH_ARG" | tr -d ' ')"
|
|
25
25
|
if (( SIZE > READ_MAX_BYTES )); then
|
|
26
|
-
|
|
26
|
+
token_mgmt_deny "Read $PATH_ARG is ${SIZE} bytes (max ${READ_MAX_BYTES}). Use sqz_read_file or bts compress."
|
|
27
27
|
fi
|
|
28
28
|
;;
|
|
29
29
|
Grep|grep)
|
|
30
30
|
LIMIT="$(echo "$TOOL_INPUT" | jq -r '.head_limit // .max_matches // empty')"
|
|
31
31
|
if [[ -z "$LIMIT" || "$LIMIT" == "null" ]]; then
|
|
32
|
-
|
|
32
|
+
token_mgmt_deny "Grep without head_limit (max ${GREP_MAX_MATCHES}). Set head_limit<=${GREP_MAX_MATCHES} or use sqz_grep."
|
|
33
33
|
fi
|
|
34
34
|
if [[ "$LIMIT" =~ ^[0-9]+$ ]] && (( LIMIT > GREP_MAX_MATCHES )); then
|
|
35
|
-
|
|
35
|
+
token_mgmt_deny "Grep head_limit=${LIMIT} exceeds ${GREP_MAX_MATCHES}. Lower limit or use sqz_grep."
|
|
36
36
|
fi
|
|
37
37
|
;;
|
|
38
38
|
Bash|bash|Shell|shell)
|
|
@@ -42,7 +42,7 @@ case "$TOOL" in
|
|
|
42
42
|
exit 0
|
|
43
43
|
fi
|
|
44
44
|
if echo "$CMD" | grep -qE "$BASH_WARN_PATTERNS"; then
|
|
45
|
-
|
|
45
|
+
token_mgmt_deny "Bash may exceed 500 lines of output. Prefix with rtk or pipe through sqz compress."
|
|
46
46
|
fi
|
|
47
47
|
;;
|
|
48
48
|
*)
|
package/scripts/land-branch.sh
CHANGED
|
@@ -13,7 +13,7 @@ usage_land() {
|
|
|
13
13
|
exit 1
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
land_branch_deny() {
|
|
17
17
|
echo "ERROR: $1" >&2
|
|
18
18
|
exit 1
|
|
19
19
|
}
|
|
@@ -34,16 +34,16 @@ COMMIT_MSG="${ARGS[1]:-}"
|
|
|
34
34
|
[ -n "$FEATURE_BRANCH" ] && [ -n "$COMMIT_MSG" ] || usage_land
|
|
35
35
|
|
|
36
36
|
if [[ ! "$COMMIT_MSG" =~ $CONVENTIONAL_REGEX ]]; then
|
|
37
|
-
|
|
37
|
+
land_branch_deny "Commit message must follow Conventional Commits: <type>(<scope>): <subject>"
|
|
38
38
|
fi
|
|
39
39
|
|
|
40
40
|
if [ ${#COMMIT_MSG} -gt 72 ]; then
|
|
41
|
-
|
|
41
|
+
land_branch_deny "Commit subject line must be 72 characters or less"
|
|
42
42
|
fi
|
|
43
43
|
|
|
44
44
|
# Primary worktree only (.git is a directory, not a gitdir pointer file)
|
|
45
45
|
if [ -f .git ]; then
|
|
46
|
-
|
|
46
|
+
land_branch_deny "Run from the primary repository root, not a linked worktree (cd to main repo first)"
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
49
|
detect_default_branch() {
|
|
@@ -58,7 +58,7 @@ detect_default_branch() {
|
|
|
58
58
|
elif git show-ref --verify --quiet refs/heads/master; then
|
|
59
59
|
echo "master"
|
|
60
60
|
else
|
|
61
|
-
|
|
61
|
+
land_branch_deny "Could not detect default branch (main/master)"
|
|
62
62
|
fi
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -69,12 +69,12 @@ echo "==> Land branch: $FEATURE_BRANCH -> $DEFAULT_BRANCH"
|
|
|
69
69
|
echo " Repo root: $REPO_ROOT"
|
|
70
70
|
|
|
71
71
|
if ! git show-ref --verify --quiet "refs/heads/$FEATURE_BRANCH"; then
|
|
72
|
-
|
|
72
|
+
land_branch_deny "Feature branch '$FEATURE_BRANCH' does not exist"
|
|
73
73
|
fi
|
|
74
74
|
|
|
75
75
|
for protected in main master; do
|
|
76
76
|
if [ "$FEATURE_BRANCH" = "$protected" ]; then
|
|
77
|
-
|
|
77
|
+
land_branch_deny "Cannot land protected branch '$FEATURE_BRANCH'"
|
|
78
78
|
fi
|
|
79
79
|
done
|
|
80
80
|
|
|
@@ -115,15 +115,15 @@ fi
|
|
|
115
115
|
echo "==> Updating $DEFAULT_BRANCH"
|
|
116
116
|
git checkout "$DEFAULT_BRANCH"
|
|
117
117
|
if ! git diff-index --quiet HEAD -- 2>/dev/null; then
|
|
118
|
-
|
|
118
|
+
land_branch_deny "Working tree on $DEFAULT_BRANCH is not clean. Stash or commit first."
|
|
119
119
|
fi
|
|
120
120
|
|
|
121
121
|
if git remote get-url origin >/dev/null 2>&1; then
|
|
122
|
-
git pull --ff-only origin "$DEFAULT_BRANCH" ||
|
|
122
|
+
git pull --ff-only origin "$DEFAULT_BRANCH" || land_branch_deny "git pull --ff-only failed; resolve before landing"
|
|
123
123
|
fi
|
|
124
124
|
|
|
125
125
|
if ! git merge-base --is-ancestor "$DEFAULT_BRANCH" "$FEATURE_BRANCH" 2>/dev/null; then
|
|
126
|
-
|
|
126
|
+
land_branch_deny "Feature branch '$FEATURE_BRANCH' is not based on current $DEFAULT_BRANCH (rebase or recreate branch)"
|
|
127
127
|
fi
|
|
128
128
|
|
|
129
129
|
export GIT_BIGPOWERS_LAND=1
|
|
@@ -131,7 +131,7 @@ export GIT_BIGPOWERS_LAND=1
|
|
|
131
131
|
echo "==> Squash merge $FEATURE_BRANCH"
|
|
132
132
|
git merge --squash "$FEATURE_BRANCH"
|
|
133
133
|
if git diff-index --quiet HEAD -- 2>/dev/null; then
|
|
134
|
-
|
|
134
|
+
land_branch_deny "Squash merge produced no changes (already merged?)"
|
|
135
135
|
fi
|
|
136
136
|
|
|
137
137
|
git commit -m "$COMMIT_MSG"
|
|
@@ -31,6 +31,7 @@ emit_okf_metrics() {
|
|
|
31
31
|
printf -- '---\n'
|
|
32
32
|
printf -- 'okf_kind: story-metrics\n'
|
|
33
33
|
printf -- 'okf_version: "0.1"\n'
|
|
34
|
+
printf -- 'type: StoryMetrics\n'
|
|
34
35
|
printf -- 'id: %s\n' "$story"
|
|
35
36
|
printf -- 'epic: %s\n' "${story%%s*}"
|
|
36
37
|
printf -- 'bcps: %s\n' "$bcps"
|
|
@@ -32,7 +32,11 @@ golden_suite_main() {
|
|
|
32
32
|
esac
|
|
33
33
|
done
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
golden_agent_cli_available() {
|
|
36
|
+
$AGENT_MODE && ! command -v gh-aw &>/dev/null && ! command -v gh &>/dev/null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if golden_agent_cli_available; then
|
|
36
40
|
echo -e "${GOLDEN_YELLOW}WARNING: gh-aw not installed — agent gate skipped${GOLDEN_NC}" >&2
|
|
37
41
|
AGENT_MODE=false
|
|
38
42
|
fi
|