@thebassclef/lite 1.0.4 → 1.1.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/dist/cli.cjs +65 -0
- package/dist/cli.js +65 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/agents/architect.md +70 -0
- package/dist/lite/.claude/agents/builder.md +114 -0
- package/dist/lite/.claude/agents/designer.md +156 -0
- package/dist/lite/.claude/agents/reviewer.md +88 -0
- package/dist/lite/.claude/hooks/bassclef-sync.sh +85 -27
- package/dist/lite/.claude/hooks/longrun-prep-compounding-axis-check.sh +492 -0
- package/dist/lite/.claude/hooks/longrun-prep-render-check.sh +236 -0
- package/dist/lite/.claude/hooks/persona-name-scrub-check.sh +105 -0
- package/dist/lite/.claude/hooks/skill-step-list-check.sh +171 -0
- package/dist/lite/.claude/luminaries/alan-cooper.md +170 -0
- package/dist/lite/.claude/luminaries/alistair-cockburn.md +140 -0
- package/dist/lite/.claude/luminaries/amazon-pr-faq.md +34 -0
- package/dist/lite/.claude/luminaries/andreas-zeller.md +74 -0
- package/dist/lite/.claude/luminaries/ash-maurya.md +121 -0
- package/dist/lite/.claude/luminaries/bill-buxton.md +210 -0
- package/dist/lite/.claude/luminaries/charles-sanders-peirce.md +150 -0
- package/dist/lite/.claude/luminaries/david-ogilvy.md +192 -0
- package/dist/lite/.claude/luminaries/don-norman.md +173 -0
- package/dist/lite/.claude/luminaries/edward-tufte.md +179 -0
- package/dist/lite/.claude/luminaries/eric-evans.md +160 -0
- package/dist/lite/.claude/luminaries/frederick-brooks.md +50 -0
- package/dist/lite/.claude/luminaries/gang-of-four.md +157 -0
- package/dist/lite/.claude/luminaries/glenford-myers.md +230 -0
- package/dist/lite/.claude/luminaries/hunt-thomas.md +115 -0
- package/dist/lite/.claude/luminaries/hyrum-wright.md +94 -0
- package/dist/lite/.claude/luminaries/jason-fried-dhh.md +46 -0
- package/dist/lite/.claude/luminaries/jesse-james-garrett.md +154 -0
- package/dist/lite/.claude/luminaries/john-ousterhout.md +94 -0
- package/dist/lite/.claude/luminaries/karl-popper.md +132 -0
- package/dist/lite/.claude/luminaries/kent-beck.md +168 -0
- package/dist/lite/.claude/luminaries/linus-torvalds.md +218 -0
- package/dist/lite/.claude/luminaries/martin-fowler.md +164 -0
- package/dist/lite/.claude/luminaries/michael-feathers.md +125 -0
- package/dist/lite/.claude/luminaries/michael-nygard.md +118 -0
- package/dist/lite/.claude/luminaries/robert-c-martin.md +164 -0
- package/dist/lite/.claude/luminaries/saltzer-schroeder.md +194 -0
- package/dist/lite/.claude/luminaries/sophia-prater.md +193 -0
- package/dist/lite/.claude/luminaries/stephen-toulmin.md +131 -0
- package/dist/lite/.claude/luminaries/tony-hoare.md +170 -0
- package/dist/lite/.claude/luminaries/vaughn-vernon.md +50 -0
- package/dist/lite/.claude/luminaries/w-edwards-deming.md +158 -0
- package/dist/lite/.claude/rules/accessor-library-discipline.md +110 -0
- package/dist/lite/.claude/rules/adr-discipline.md +96 -0
- package/dist/lite/.claude/rules/api-conventions.md +115 -0
- package/dist/lite/.claude/rules/artifact-ingestion.md +137 -0
- package/dist/lite/.claude/rules/assert-only-after-verify.md +111 -0
- package/dist/lite/.claude/rules/blocked-items.md +139 -0
- package/dist/lite/.claude/rules/bootstrap-pair-discipline.md +106 -0
- package/dist/lite/.claude/rules/branching.md +28 -0
- package/dist/lite/.claude/rules/cold-adopter-harness-discipline.md +93 -0
- package/dist/lite/.claude/rules/commit-conventions.md +22 -0
- package/dist/lite/.claude/rules/compounding-axis-fresh-analysis.md +173 -0
- package/dist/lite/.claude/rules/compounding-sequence-fresh-analysis.md +173 -0
- package/dist/lite/.claude/rules/context-engineering.md +155 -0
- package/dist/lite/.claude/rules/context-management.md +85 -0
- package/dist/lite/.claude/rules/defensive-bash.md +52 -0
- package/dist/lite/.claude/rules/deferred-actions.md +233 -0
- package/dist/lite/.claude/rules/destructive-operations.md +69 -0
- package/dist/lite/.claude/rules/diagnosis.md +38 -0
- package/dist/lite/.claude/rules/github-issue-flash-tweet.md +114 -0
- package/dist/lite/.claude/rules/guardrails.md +73 -0
- package/dist/lite/.claude/rules/hook-wire-on-author.md +77 -0
- package/dist/lite/.claude/rules/identifier-leak-prevention.md +73 -0
- package/dist/lite/.claude/rules/iteration-bet-brief-completeness.md +43 -0
- package/dist/lite/.claude/rules/lite-manifest-schema-change-discipline.md +79 -0
- package/dist/lite/.claude/rules/longrun-prep-plan-doc-compression.md +77 -0
- package/dist/lite/.claude/rules/loop-discipline.md +71 -0
- package/dist/lite/.claude/rules/manual-prod-approval.md +100 -0
- package/dist/lite/.claude/rules/marker-enrichment-discipline.md +72 -0
- package/dist/lite/.claude/rules/mobile-ephemeral-session.md +109 -0
- package/dist/lite/.claude/rules/new-dependency-check.md +44 -0
- package/dist/lite/.claude/rules/oo-ad-entry-point.md +95 -0
- package/dist/lite/.claude/rules/operator-facing-prose.md +177 -0
- package/dist/lite/.claude/rules/option-label-discipline.md +82 -0
- package/dist/lite/.claude/rules/pattern-annotation.md +83 -0
- package/dist/lite/.claude/rules/persona-name-leak-scrub.md +90 -0
- package/dist/lite/.claude/rules/plain-english-discipline.md +132 -0
- package/dist/lite/.claude/rules/plan-enumeration-needs-value-props.md +177 -0
- package/dist/lite/.claude/rules/pr-body-shape.md +195 -0
- package/dist/lite/.claude/rules/pr-strategy.md +142 -0
- package/dist/lite/.claude/rules/pr-title-shape.md +90 -0
- package/dist/lite/.claude/rules/prototype-workflow.md +53 -0
- package/dist/lite/.claude/rules/reserved-skill-names.md +103 -0
- package/dist/lite/.claude/rules/schema-management.md +42 -0
- package/dist/lite/.claude/rules/sdlc-gates.md +149 -0
- package/dist/lite/.claude/rules/security.md +37 -0
- package/dist/lite/.claude/rules/session-artifacts.md +236 -0
- package/dist/lite/.claude/rules/skill-composition-declarations.md +105 -0
- package/dist/lite/.claude/rules/skill-description-clarity.md +196 -0
- package/dist/lite/.claude/rules/skill-procedure-step-list.md +119 -0
- package/dist/lite/.claude/rules/sprint-prep-preset-picker.md +76 -0
- package/dist/lite/.claude/rules/state-schema-validation.md +156 -0
- package/dist/lite/.claude/rules/stuck-signal-diagnostic.md +111 -0
- package/dist/lite/.claude/rules/substrate-config-schema.md +85 -0
- package/dist/lite/.claude/rules/test-list-discipline.md +129 -0
- package/dist/lite/.claude/rules/test-sufficiency.md +186 -0
- package/dist/lite/.claude/rules/testing-tier-config.md +125 -0
- package/dist/lite/.claude/rules/testing.md +38 -0
- package/dist/lite/.claude/rules/turn-estimate-grounding.md +82 -0
- package/dist/lite/.claude/rules/visual-hierarchy.md +427 -0
- package/dist/lite/.claude/rules/we-dont-break-adopters.md +103 -0
- package/dist/lite/.claude/rules/whereami-load-bearing.md +184 -0
- package/dist/lite/.claude/rules/writing-craft-discipline.md +72 -0
- package/dist/lite/.claude/rules/wu-sequencing-compounds.md +119 -0
- package/dist/lite/.claude/skills/build/SKILL.md +640 -0
- package/dist/lite/.claude/skills/chronicle/SKILL.md +55 -0
- package/dist/lite/.claude/skills/clean-artifacts/SKILL.md +249 -0
- package/dist/lite/.claude/skills/decompose/SKILL.md +280 -0
- package/dist/lite/.claude/skills/diagnose/SKILL.md +297 -0
- package/dist/lite/.claude/skills/feynman/SKILL.md +90 -0
- package/dist/lite/.claude/skills/howdoi/SKILL.md +105 -0
- package/dist/lite/.claude/skills/ia-model/SKILL.md +108 -0
- package/dist/lite/.claude/skills/interaction-design/SKILL.md +112 -0
- package/dist/lite/.claude/skills/interpret-input/SKILL.md +180 -0
- package/dist/lite/.claude/skills/journal/SKILL.md +209 -0
- package/dist/lite/.claude/skills/kiss/SKILL.md +449 -0
- package/dist/lite/.claude/skills/launch/SKILL.md +915 -0
- package/dist/lite/.claude/skills/lean-canvas/SKILL.md +332 -0
- package/dist/lite/.claude/skills/longrun/SKILL.md +512 -0
- package/dist/lite/.claude/skills/luminary/SKILL.md +481 -0
- package/dist/lite/.claude/skills/ogilvy-writing-audit/SKILL.md +177 -0
- package/dist/lite/.claude/skills/onboard-repo/SKILL.md +1640 -0
- package/dist/lite/.claude/skills/pattern-review/SKILL.md +99 -0
- package/dist/lite/.claude/skills/personas/SKILL.md +207 -0
- package/dist/lite/.claude/skills/promote/SKILL.md +283 -0
- package/dist/lite/.claude/skills/requirement/SKILL.md +98 -0
- package/dist/lite/.claude/skills/retro/SKILL.md +117 -0
- package/dist/lite/.claude/skills/riff/SKILL.md +114 -0
- package/dist/lite/.claude/skills/roadmap-reconcile/SKILL.md +163 -0
- package/dist/lite/.claude/skills/session-end/SKILL.md +309 -0
- package/dist/lite/.claude/skills/session-log/SKILL.md +299 -0
- package/dist/lite/.claude/skills/skills/SKILL.md +228 -0
- package/dist/lite/.claude/skills/spec/SKILL.md +105 -0
- package/dist/lite/.claude/skills/sprint/SKILL.md +418 -0
- package/dist/lite/.claude/skills/stage/SKILL.md +384 -0
- package/dist/lite/.claude/skills/state-a-problem/SKILL.md +185 -0
- package/dist/lite/.claude/skills/temperance/SKILL.md +108 -0
- package/dist/lite/.claude/skills/use-case/SKILL.md +417 -0
- package/dist/lite/.claude/skills/user-stories/SKILL.md +268 -0
- package/dist/lite/.claude/skills/value-prop/SKILL.md +251 -0
- package/dist/lite/.claude/skills/verify/SKILL.md +160 -0
- package/dist/lite/.claude/skills/visual-review/SKILL.md +503 -0
- package/dist/lite/.claude/skills/whats-the-plan/SKILL.md +202 -0
- package/dist/lite/.claude/skills/whereami/SKILL.md +307 -0
- package/dist/lite/AGENTS.md +79 -0
- package/dist/lite/CLAUDE-lite.md +85 -0
- package/dist/lite/CODE_OF_CONDUCT.md +28 -0
- package/dist/lite/CONTRIBUTING.md +177 -0
- package/dist/lite/README.md +173 -0
- package/dist/lite/SECURITY.md +19 -0
- package/dist/lite/architecture/decisions/ADR-029-release-pipeline.md +79 -0
- package/dist/lite/architecture/decisions/ADR-031-non-breaking-changes-adopter-discipline.md +139 -0
- package/dist/lite/architecture/decisions/ADR-032-adopter-sync-dispatcher-architecture.md +192 -0
- package/dist/lite/architecture/decisions/ADR-039-release-tagging-scheme.md +145 -0
- package/dist/lite/architecture/decisions/ADR-040-planning-skill-vocabulary-and-lite-profile.md +155 -0
- package/dist/lite/architecture/decisions/ADR-044-unified-skill-body-template.md +162 -0
- package/dist/lite/lib/clean-artifacts-sweep.sh +112 -0
- package/dist/lite/lib/code-comment-discipline.sh +144 -0
- package/dist/lite/lib/composer-preflight.sh +459 -0
- package/dist/lite/lib/deferred-actions.sh +146 -0
- package/dist/lite/lib/hook-header-parser.sh +61 -0
- package/dist/lite/lib/hook-heartbeat.sh +152 -0
- package/dist/lite/lib/hook-inject.sh +255 -0
- package/dist/lite/lib/hook-installer.sh +195 -0
- package/dist/lite/lib/luminary-pick.sh +96 -0
- package/dist/lite/lib/output-discipline.sh +143 -0
- package/dist/lite/lib/prose-scan-boundary.sh +171 -0
- package/dist/lite/lib/rewrite-check.sh +214 -0
- package/dist/lite/lib/session-rescue.sh +151 -0
- package/dist/lite/lib/source-graph-walker.sh +277 -0
- package/dist/lite/lib/state.sh +1372 -0
- package/dist/lite/lib/telemetry.sh +205 -0
- package/dist/lite/lib/tier-check.sh +187 -0
- package/dist/lite/lib/tier-dependency-audit.sh +1088 -0
- package/dist/lite/presence/install/bassclef-hook-connect.sh +178 -0
- package/dist/lite/presence/install/bassclef-sync.dispatcher.template.sh +841 -0
- package/dist/lite/presence/install/bassclef-sync.template.sh +2278 -0
- package/dist/lite/presence/install/schedule-auto-save.cron.sh +88 -0
- package/dist/lite/presence/install/schedule-auto-save.taskscheduler.md +122 -0
- package/dist/lite/scripts/aggregate-telemetry.sh +217 -0
- package/dist/lite/scripts/analyze-tier-dependencies.sh +239 -0
- package/dist/lite/scripts/generate-lite-manifest.sh +505 -0
- package/dist/lite/scripts/generate-tier-manifest.sh +28 -0
- package/dist/lite/scripts/intent-drift-check.sh +456 -0
- package/dist/lite/scripts/lite-manifest-drift-check.sh +146 -0
- package/dist/lite/scripts/render-lite-manifest-doc.sh +150 -0
- package/dist/lite/standards/adr-template.md +86 -0
- package/dist/lite/standards/api-conventions/nextjs.md +84 -0
- package/dist/lite/standards/artifact-composition.md +209 -0
- package/dist/lite/standards/bash-hook-safety.md +246 -0
- package/dist/lite/standards/bassclef-configs-schema.md +232 -0
- package/dist/lite/standards/bassclef-evolution.md +143 -0
- package/dist/lite/standards/bassclef-internal-jargon.md +244 -0
- package/dist/lite/standards/bassclef-managed-sentinel.md +96 -0
- package/dist/lite/standards/bassclef-source-config.md +228 -0
- package/dist/lite/standards/branch-stacking.md +408 -0
- package/dist/lite/standards/code-safety-principles.md +176 -0
- package/dist/lite/standards/composer-prerequisites.md +155 -0
- package/dist/lite/standards/deferred-actions-schema.md +204 -0
- package/dist/lite/standards/dependency-discipline/cargo.md +39 -0
- package/dist/lite/standards/dependency-discipline/gem.md +43 -0
- package/dist/lite/standards/dependency-discipline/go-mod.md +41 -0
- package/dist/lite/standards/dependency-discipline/npm.md +42 -0
- package/dist/lite/standards/dependency-discipline/pip.md +42 -0
- package/dist/lite/standards/deployment-topology/ec2-tailscale.md +225 -0
- package/dist/lite/standards/deployment-topology.md +69 -0
- package/dist/lite/standards/docs-sync-allowlist.md +76 -0
- package/dist/lite/standards/domain-and-dns.md +145 -0
- package/dist/lite/standards/frontend-stack.md +67 -0
- package/dist/lite/standards/frontmatter-schema.md +154 -0
- package/dist/lite/standards/graceful-exit.md +227 -0
- package/dist/lite/standards/hook-idempotency.md +102 -0
- package/dist/lite/standards/hook-injection-discipline.md +202 -0
- package/dist/lite/standards/hook-install-class.md +215 -0
- package/dist/lite/standards/input-handler-interface.md +152 -0
- package/dist/lite/standards/lite-manifest-schema-changes.md +180 -0
- package/dist/lite/standards/lite-manifest.json +2797 -0
- package/dist/lite/standards/luminary-matching.md +105 -0
- package/dist/lite/standards/luminary-problem-patterns.md +481 -0
- package/dist/lite/standards/migration-discipline/active-record.md +50 -0
- package/dist/lite/standards/migration-discipline/alembic.md +43 -0
- package/dist/lite/standards/migration-discipline/gorm.md +50 -0
- package/dist/lite/standards/migration-discipline/prisma.md +53 -0
- package/dist/lite/standards/migration-discipline/sqlalchemy.md +51 -0
- package/dist/lite/standards/mobile-ephemeral-session.md +167 -0
- package/dist/lite/standards/model-routing-discipline.md +160 -0
- package/dist/lite/standards/ogilvy-writing-rules.md +225 -0
- package/dist/lite/standards/opener-discipline.md +96 -0
- package/dist/lite/standards/operator-facing-prose-discipline.md +201 -0
- package/dist/lite/standards/persona-schema.md +229 -0
- package/dist/lite/standards/pluggable-luminaries.md +323 -0
- package/dist/lite/standards/pr-body-discipline.md +115 -0
- package/dist/lite/standards/preview-state-schema.md +189 -0
- package/dist/lite/standards/project-directory-layout.md +276 -0
- package/dist/lite/standards/release-tagging.md +137 -0
- package/dist/lite/standards/reserved-skill-names.md +120 -0
- package/dist/lite/standards/scannable-multi-option-output.md +265 -0
- package/dist/lite/standards/sdlc-compliance.md +286 -0
- package/dist/lite/standards/sdlc-gates/typescript.md +57 -0
- package/dist/lite/standards/secrets-lifecycle.md +210 -0
- package/dist/lite/standards/security-scanner-adapter.md +145 -0
- package/dist/lite/standards/session-board.md +256 -0
- package/dist/lite/standards/skill-output-discipline.md +121 -0
- package/dist/lite/standards/state-spine-contract.md +255 -0
- package/dist/lite/standards/state-spine.md +511 -0
- package/dist/lite/standards/steering-hints/kiss-words.md +11 -0
- package/dist/lite/standards/substrate-config-schema.md +267 -0
- package/dist/lite/standards/tech-stack-config.md +109 -0
- package/dist/lite/standards/tier-dependency-analysis.md +167 -0
- package/dist/lite/standards/tier-runtime-deps/lite.md +57 -0
- package/dist/lite/standards/tier-tag-schema.md +155 -0
- package/dist/lite/standards/two-layer-config.md +99 -0
- package/dist/lite/standards/use-case-format.md +292 -0
- package/dist/lite/standards/user-story-invest.md +268 -0
- package/dist/lite/standards/velocity-and-appetite.md +229 -0
- package/dist/lite/standards/voice-input-pattern.md +119 -0
- package/dist/lite/standards/whereami-schema.md +301 -0
- package/dist/lite/standards/worktree-management.md +211 -0
- package/dist/lite/standards/writing-guide.md +213 -0
- package/dist/lite/templates/chronicle-template.md +75 -0
- package/dist/lite/templates/deferred-action-template.md +45 -0
- package/dist/lite/templates/memory-proposal-template.md +77 -0
- package/dist/lite/templates/persona-template.md +200 -0
- package/dist/lite/templates/pr-faq.md +45 -0
- package/dist/lite/templates/secret-rotation-template.md +162 -0
- package/dist/lite/templates/spec-template.md +131 -0
- package/dist/lite/templates/use-case-template.md +194 -0
- package/dist/lite/templates/user-story-template.md +107 -0
- package/dist/lite/templates/whereami-template.md +101 -0
- package/package.json +1 -1
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# lib/composer-preflight.sh — shared pre-flight check for composer skills.
|
|
4
|
+
#
|
|
5
|
+
# Composer skills (/launch, /build, /shape full) source this helper
|
|
6
|
+
# in Phase -1 (before Phase 0). Surfaces 6 prerequisites at once:
|
|
7
|
+
# 1. feature-branch — repo on a feature branch (refuses on main)
|
|
8
|
+
# 2. state-spine — lib/state.sh present (AUTO-PREP from bassclef)
|
|
9
|
+
# 3. personas — at least 1 persona scaffolded (signal-and-offer)
|
|
10
|
+
# 4. budget — iteration_ceiling sufficient for estimate
|
|
11
|
+
# 5. skill-registry — dispatching skill resolves (covers bassclef#271)
|
|
12
|
+
# 6. deploy-host — hosting_platform set + adapter shipped (bassclef#449/#450)
|
|
13
|
+
#
|
|
14
|
+
# Usage (from a composer SKILL.md procedure):
|
|
15
|
+
# source $BASSCLEF_DIR/lib/composer-preflight.sh
|
|
16
|
+
# composer_preflight_check <skill_name> <estimated_turns> [--no-launch]
|
|
17
|
+
# case $? in
|
|
18
|
+
# 0) ;; # all pass — proceed to Phase 0
|
|
19
|
+
# 1) ;; # warnings — composer prompts operator proceed/abort
|
|
20
|
+
# 2) exit 1 ;; # failures — composer refuses dispatch
|
|
21
|
+
# esac
|
|
22
|
+
#
|
|
23
|
+
# --no-launch: variants-only run; Check 6 short-circuits to pass.
|
|
24
|
+
# Use when /launch is invoked for variant generation only,
|
|
25
|
+
# no deploy-host chain. /stage (light) is the typical caller.
|
|
26
|
+
#
|
|
27
|
+
# Override: SKIP_COMPOSER_PREFLIGHT=1 (logged via trace-helper).
|
|
28
|
+
#
|
|
29
|
+
# Standard: standards/composer-prerequisites.md
|
|
30
|
+
# Refs bassclef#408 (preflight scaffold) + bassclef#449/#450 (deploy-host check).
|
|
31
|
+
|
|
32
|
+
# Don't use `set -e` — preflight checks must complete even when one fails.
|
|
33
|
+
|
|
34
|
+
# Output format (key=value lines on stdout):
|
|
35
|
+
# check_<n>_name=<check name>
|
|
36
|
+
# check_<n>_status=<pass|warn|fail>
|
|
37
|
+
# check_<n>_message=<single-line message>
|
|
38
|
+
# check_<n>_recommendation=<single-line recommendation>
|
|
39
|
+
# summary_status=<pass|warn|fail>
|
|
40
|
+
# summary_count_pass=<n>
|
|
41
|
+
# summary_count_warn=<n>
|
|
42
|
+
# summary_count_fail=<n>
|
|
43
|
+
|
|
44
|
+
composer_preflight_check() {
|
|
45
|
+
local skill_name="${1:-}"
|
|
46
|
+
local estimated_turns="${2:-50}"
|
|
47
|
+
local mode_flag="${3:-}" # optional: --no-launch for variants-only runs
|
|
48
|
+
|
|
49
|
+
# Override hatch
|
|
50
|
+
if [ "${SKIP_COMPOSER_PREFLIGHT:-0}" = "1" ]; then
|
|
51
|
+
if command -v trace_log >/dev/null 2>&1; then
|
|
52
|
+
trace_log "composer-preflight" "OVERRIDE skill=$skill_name" 2>/dev/null || true
|
|
53
|
+
fi
|
|
54
|
+
echo "summary_status=skip"
|
|
55
|
+
return 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if [ -z "$skill_name" ]; then
|
|
59
|
+
echo "summary_status=fail" >&2
|
|
60
|
+
echo "ERROR: composer_preflight_check requires skill_name" >&2
|
|
61
|
+
return 2
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
local pass=0 warn=0 fail=0
|
|
65
|
+
|
|
66
|
+
# === Check 1: feature-branch ===
|
|
67
|
+
local current_branch
|
|
68
|
+
current_branch=$(git branch --show-current 2>/dev/null || echo "")
|
|
69
|
+
echo "check_1_name=feature-branch"
|
|
70
|
+
if [ -z "$current_branch" ]; then
|
|
71
|
+
echo "check_1_status=fail"
|
|
72
|
+
echo "check_1_message=Not in a git repository OR branch detection failed"
|
|
73
|
+
echo "check_1_recommendation=Run from inside a git repository"
|
|
74
|
+
fail=$((fail + 1))
|
|
75
|
+
elif [ "$current_branch" = "main" ] || [ "$current_branch" = "master" ]; then
|
|
76
|
+
echo "check_1_status=fail"
|
|
77
|
+
echo "check_1_message=On $current_branch — composer skills refuse to run from default branch"
|
|
78
|
+
echo "check_1_recommendation=git checkout -b feature/<slug>"
|
|
79
|
+
fail=$((fail + 1))
|
|
80
|
+
else
|
|
81
|
+
echo "check_1_status=pass"
|
|
82
|
+
echo "check_1_message=On feature branch: $current_branch"
|
|
83
|
+
echo "check_1_recommendation="
|
|
84
|
+
pass=$((pass + 1))
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# === Check 2: state-spine ===
|
|
88
|
+
local repo_root
|
|
89
|
+
repo_root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
90
|
+
echo "check_2_name=state-spine"
|
|
91
|
+
if [ -f "$repo_root/lib/state.sh" ]; then
|
|
92
|
+
echo "check_2_status=pass"
|
|
93
|
+
echo "check_2_message=lib/state.sh present"
|
|
94
|
+
echo "check_2_recommendation="
|
|
95
|
+
pass=$((pass + 1))
|
|
96
|
+
else
|
|
97
|
+
# Auto-prep available: bootstrap from BASSCLEF_DIR if reachable
|
|
98
|
+
local bassclef_state="${BASSCLEF_DIR:-}/lib/state.sh"
|
|
99
|
+
if [ -n "${BASSCLEF_DIR:-}" ] && [ -f "$bassclef_state" ]; then
|
|
100
|
+
echo "check_2_status=warn"
|
|
101
|
+
echo "check_2_message=lib/state.sh missing; AUTO-PREP available from $bassclef_state"
|
|
102
|
+
echo "check_2_recommendation=cp $bassclef_state $repo_root/lib/state.sh # safe to auto-execute"
|
|
103
|
+
warn=$((warn + 1))
|
|
104
|
+
else
|
|
105
|
+
echo "check_2_status=fail"
|
|
106
|
+
echo "check_2_message=lib/state.sh missing AND BASSCLEF_DIR not reachable"
|
|
107
|
+
echo "check_2_recommendation=Run /onboard-repo to bootstrap bassclef substrate"
|
|
108
|
+
fail=$((fail + 1))
|
|
109
|
+
fi
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# === Check 3: personas ===
|
|
113
|
+
echo "check_3_name=personas"
|
|
114
|
+
local persona_count=0
|
|
115
|
+
if [ -d "$repo_root/docs/personas" ]; then
|
|
116
|
+
persona_count=$(find "$repo_root/docs/personas" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
117
|
+
fi
|
|
118
|
+
if [ "$persona_count" -ge 1 ]; then
|
|
119
|
+
echo "check_3_status=pass"
|
|
120
|
+
echo "check_3_message=$persona_count persona(s) scaffolded"
|
|
121
|
+
echo "check_3_recommendation="
|
|
122
|
+
pass=$((pass + 1))
|
|
123
|
+
else
|
|
124
|
+
echo "check_3_status=warn"
|
|
125
|
+
echo "check_3_message=No personas scaffolded; composers default to operator-as-persona"
|
|
126
|
+
echo "check_3_recommendation=Run /personas to seed primary persona OR proceed with operator-only"
|
|
127
|
+
warn=$((warn + 1))
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# === Check 4: budget ===
|
|
131
|
+
echo "check_4_name=budget"
|
|
132
|
+
local budget_estimate=$(( estimated_turns * 10 / 100 )) # rough $0.10/turn proxy
|
|
133
|
+
local ceiling=""
|
|
134
|
+
if [ -f "$repo_root/substrate.config.md" ]; then
|
|
135
|
+
# Use [[:space:]] (POSIX) instead of \s (GNU extension) for BSD sed compat
|
|
136
|
+
ceiling=$(grep -E '^[[:space:]]*iteration_ceiling:' "$repo_root/substrate.config.md" 2>/dev/null \
|
|
137
|
+
| head -1 | sed 's/.*:[[:space:]]*//;s/[[:space:]].*//;s/^\$//' || echo "")
|
|
138
|
+
fi
|
|
139
|
+
if [ -z "$ceiling" ] || [ "$ceiling" = "0" ]; then
|
|
140
|
+
# Sequential mode (no burst cost) — pass
|
|
141
|
+
echo "check_4_status=pass"
|
|
142
|
+
echo "check_4_message=Sequential mode (\$0 burst); estimated $estimated_turns turns"
|
|
143
|
+
echo "check_4_recommendation="
|
|
144
|
+
pass=$((pass + 1))
|
|
145
|
+
elif ! [[ "$ceiling" =~ ^[0-9]+$ ]]; then
|
|
146
|
+
# Non-numeric ceiling (e.g., free-form description) — pass with note
|
|
147
|
+
echo "check_4_status=pass"
|
|
148
|
+
echo "check_4_message=iteration_ceiling: $ceiling (free-form); estimated $estimated_turns turns"
|
|
149
|
+
echo "check_4_recommendation="
|
|
150
|
+
pass=$((pass + 1))
|
|
151
|
+
elif [ "$ceiling" -lt "$budget_estimate" ]; then
|
|
152
|
+
echo "check_4_status=warn"
|
|
153
|
+
echo "check_4_message=iteration_ceiling \$$ceiling < estimated \$$budget_estimate ($estimated_turns turns)"
|
|
154
|
+
echo "check_4_recommendation=Bump iteration_ceiling in substrate.config.md OR reduce composer tier"
|
|
155
|
+
warn=$((warn + 1))
|
|
156
|
+
else
|
|
157
|
+
echo "check_4_status=pass"
|
|
158
|
+
echo "check_4_message=iteration_ceiling \$$ceiling >= estimated \$$budget_estimate"
|
|
159
|
+
echo "check_4_recommendation="
|
|
160
|
+
pass=$((pass + 1))
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# === Check 5: skill-registry ===
|
|
164
|
+
# Detects bassclef#271 race — skill not picked up by harness registry.
|
|
165
|
+
# Read-and-check approach: the skill MUST exist as SKILL.md at a discoverable
|
|
166
|
+
# path. Three discovery paths:
|
|
167
|
+
# a) ~/.claude/skills/<skill>/SKILL.md (user-level symlink — harness primary)
|
|
168
|
+
# b) <repo>/.claude/skills/<skill>/SKILL.md (repo-level — fallback)
|
|
169
|
+
# c) <BASSCLEF_DIR>/.claude/skills/<skill>/SKILL.md (bassclef authoritative)
|
|
170
|
+
echo "check_5_name=skill-registry"
|
|
171
|
+
local user_skill="$HOME/.claude/skills/$skill_name/SKILL.md"
|
|
172
|
+
local repo_skill="$repo_root/.claude/skills/$skill_name/SKILL.md"
|
|
173
|
+
local bassclef_skill="${BASSCLEF_DIR:-}/.claude/skills/$skill_name/SKILL.md"
|
|
174
|
+
|
|
175
|
+
if [ -f "$user_skill" ] || [ -L "$user_skill" ]; then
|
|
176
|
+
echo "check_5_status=pass"
|
|
177
|
+
echo "check_5_message=Skill resolves at user-level: $user_skill"
|
|
178
|
+
echo "check_5_recommendation="
|
|
179
|
+
pass=$((pass + 1))
|
|
180
|
+
elif [ -f "$repo_skill" ] || [ -L "$repo_skill" ]; then
|
|
181
|
+
echo "check_5_status=warn"
|
|
182
|
+
echo "check_5_message=Skill at repo-level only ($repo_skill); user-level symlink missing — harness may not pick up (bassclef#271)"
|
|
183
|
+
echo "check_5_recommendation=Run bassclef-sync.sh to create user-level symlink OR restart Claude session"
|
|
184
|
+
warn=$((warn + 1))
|
|
185
|
+
elif [ -n "${BASSCLEF_DIR:-}" ] && [ -f "$bassclef_skill" ]; then
|
|
186
|
+
echo "check_5_status=warn"
|
|
187
|
+
echo "check_5_message=Skill at bassclef only; consumer-side links missing — substrate sync incomplete"
|
|
188
|
+
echo "check_5_recommendation=Run bassclef-sync.sh in this repo OR /onboard-repo"
|
|
189
|
+
warn=$((warn + 1))
|
|
190
|
+
else
|
|
191
|
+
echo "check_5_status=fail"
|
|
192
|
+
echo "check_5_message=Skill /$skill_name not found at any discovery path"
|
|
193
|
+
echo "check_5_recommendation=Verify skill name OR check bassclef substrate sync"
|
|
194
|
+
fail=$((fail + 1))
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
# === Check 6: deploy-host (bassclef#449/#450 + bassclef#523) ===
|
|
198
|
+
#
|
|
199
|
+
# Reads hosting_platform from substrate.config.md and verifies (a) a deploy
|
|
200
|
+
# adapter is shipped AND (b) provisioning has actually happened (the
|
|
201
|
+
# per-platform provisioning-indicator field is populated with a real value,
|
|
202
|
+
# not the schema's bracketed placeholder). Catches the preview→production
|
|
203
|
+
# gap before /launch burns 200t AND the silent-defer-bind class
|
|
204
|
+
# where Phase 12 silently no-ops because the consumer never ran
|
|
205
|
+
# /provision-deploy-host (bassclef#523 — today's POA mobile session).
|
|
206
|
+
#
|
|
207
|
+
# Logic:
|
|
208
|
+
# missing hosting_platform → fail (set hosting_platform: amplify)
|
|
209
|
+
# hosting_platform=none + --no-launch → pass (variants-only run)
|
|
210
|
+
# hosting_platform=none + no --no-launch → fail (refuse dispatch)
|
|
211
|
+
# adapter shipped + indicator populated → pass
|
|
212
|
+
# adapter shipped + indicator MISSING → fail with three-path remediation:
|
|
213
|
+
# run /provision-deploy-host inline / re-dispatch with --no-launch /
|
|
214
|
+
# explicit defer
|
|
215
|
+
# adapter not shipped (vercel | netlify | cf-pages) → warn
|
|
216
|
+
# any other value → fail (not in enum)
|
|
217
|
+
#
|
|
218
|
+
# Per-platform provisioning indicators (set by /provision-deploy-host on success):
|
|
219
|
+
# amplify → amplify_app_id (e.g., d154l5usyc80nk)
|
|
220
|
+
# ec2-tailscale → deploy_host (e.g., poa-prod.tailnet.ts.net)
|
|
221
|
+
# mock → no indicator required (test scaffold)
|
|
222
|
+
#
|
|
223
|
+
# The override --no-launch lets /launch run in variants-only mode
|
|
224
|
+
# (e.g., /stage light callers) without requiring deploy-host provisioning.
|
|
225
|
+
echo "check_6_name=deploy-host"
|
|
226
|
+
local hosting=""
|
|
227
|
+
if [ -f "$repo_root/substrate.config.md" ]; then
|
|
228
|
+
hosting=$(grep -E '^[[:space:]]*hosting_platform:' "$repo_root/substrate.config.md" 2>/dev/null \
|
|
229
|
+
| head -1 | sed 's/.*:[[:space:]]*//;s/[[:space:]].*//;s/^["'\'']//;s/["'\'']$//')
|
|
230
|
+
fi
|
|
231
|
+
local bassclef_adapter_dir="${BASSCLEF_DIR:-}/scripts/adapters/deploy"
|
|
232
|
+
local adapter_check=""
|
|
233
|
+
if [ -n "$hosting" ] && [ -n "${BASSCLEF_DIR:-}" ]; then
|
|
234
|
+
adapter_check="${bassclef_adapter_dir}/${hosting}.sh"
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
# Helper: read the per-platform provisioning-indicator field from
|
|
238
|
+
# substrate.config.md. Returns the field value if populated and not the
|
|
239
|
+
# bracketed placeholder shape (e.g., `[e.g., d154l...]`); empty otherwise.
|
|
240
|
+
_check6_provisioning_indicator_value() {
|
|
241
|
+
local field="$1"
|
|
242
|
+
[ -f "$repo_root/substrate.config.md" ] || return 0
|
|
243
|
+
local val
|
|
244
|
+
val=$(grep -E "^[[:space:]]*${field}:" "$repo_root/substrate.config.md" 2>/dev/null \
|
|
245
|
+
| head -1 | sed 's/.*:[[:space:]]*//;s/[[:space:]]*#.*$//;s/^["'\'']//;s/["'\'']$//')
|
|
246
|
+
# Reject placeholders (bracketed values are schema templates, not real values)
|
|
247
|
+
case "$val" in
|
|
248
|
+
"" | \[*\] | "[]" )
|
|
249
|
+
echo ""
|
|
250
|
+
;;
|
|
251
|
+
*)
|
|
252
|
+
echo "$val"
|
|
253
|
+
;;
|
|
254
|
+
esac
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if [ -z "$hosting" ]; then
|
|
258
|
+
echo "check_6_status=fail"
|
|
259
|
+
echo "check_6_message=hosting_platform missing from substrate.config.md"
|
|
260
|
+
echo "check_6_recommendation=Add 'hosting_platform: amplify' (bassclef default per ADR-008) OR 'hosting_platform: none' if no UI ships"
|
|
261
|
+
fail=$((fail + 1))
|
|
262
|
+
elif [ "$hosting" = "none" ]; then
|
|
263
|
+
if [ "$mode_flag" = "--no-launch" ]; then
|
|
264
|
+
echo "check_6_status=pass"
|
|
265
|
+
echo "check_6_message=hosting_platform=none + --no-launch (variants-only run)"
|
|
266
|
+
echo "check_6_recommendation="
|
|
267
|
+
pass=$((pass + 1))
|
|
268
|
+
else
|
|
269
|
+
echo "check_6_status=fail"
|
|
270
|
+
echo "check_6_message=hosting_platform=none — composer would generate variants that can't launch"
|
|
271
|
+
echo "check_6_recommendation=Set hosting_platform to a deploy provider (amplify) OR re-run with --no-launch for variants-only"
|
|
272
|
+
fail=$((fail + 1))
|
|
273
|
+
fi
|
|
274
|
+
elif [ -n "$adapter_check" ] && [ -f "$adapter_check" ]; then
|
|
275
|
+
# Adapter shipped — now verify provisioning indicator is populated.
|
|
276
|
+
# --no-launch override skips this gate (variants-only run).
|
|
277
|
+
if [ "$mode_flag" = "--no-launch" ]; then
|
|
278
|
+
echo "check_6_status=pass"
|
|
279
|
+
echo "check_6_message=hosting_platform=$hosting + --no-launch (variants-only; provisioning indicator gate bypassed)"
|
|
280
|
+
echo "check_6_recommendation="
|
|
281
|
+
pass=$((pass + 1))
|
|
282
|
+
else
|
|
283
|
+
local indicator_field=""
|
|
284
|
+
case "$hosting" in
|
|
285
|
+
amplify) indicator_field="amplify_app_id" ;;
|
|
286
|
+
ec2-tailscale) indicator_field="deploy_host" ;;
|
|
287
|
+
mock) indicator_field="" ;; # test scaffold, no indicator required
|
|
288
|
+
esac
|
|
289
|
+
local indicator_value=""
|
|
290
|
+
if [ -n "$indicator_field" ]; then
|
|
291
|
+
indicator_value=$(_check6_provisioning_indicator_value "$indicator_field")
|
|
292
|
+
fi
|
|
293
|
+
if [ -z "$indicator_field" ] || [ -n "$indicator_value" ]; then
|
|
294
|
+
echo "check_6_status=pass"
|
|
295
|
+
if [ -n "$indicator_field" ]; then
|
|
296
|
+
echo "check_6_message=hosting_platform=$hosting; adapter shipped; ${indicator_field}=${indicator_value}"
|
|
297
|
+
else
|
|
298
|
+
echo "check_6_message=hosting_platform=$hosting; adapter shipped (no indicator required for $hosting)"
|
|
299
|
+
fi
|
|
300
|
+
echo "check_6_recommendation="
|
|
301
|
+
pass=$((pass + 1))
|
|
302
|
+
else
|
|
303
|
+
echo "check_6_status=fail"
|
|
304
|
+
echo "check_6_message=hosting_platform=$hosting; adapter shipped but ${indicator_field} not populated in substrate.config.md — /provision-deploy-host has not run for this consumer"
|
|
305
|
+
echo "check_6_recommendation=Three paths: (a) run /provision-deploy-host (creates ${hosting} app + populates ${indicator_field}; ~1-2h, mostly waiting); (b) re-dispatch with --no-launch for variants-only (no deploy host needed); (c) explicit defer — tell the agent 'skip launch deploy-host check this session' (per blocked-items.md deferral syntax)"
|
|
306
|
+
fail=$((fail + 1))
|
|
307
|
+
fi
|
|
308
|
+
fi
|
|
309
|
+
elif [ "$hosting" = "vercel" ] || [ "$hosting" = "netlify" ] || [ "$hosting" = "cloudflare-pages" ]; then
|
|
310
|
+
echo "check_6_status=warn"
|
|
311
|
+
echo "check_6_message=hosting_platform=$hosting in schema enum but adapter not yet shipped"
|
|
312
|
+
echo "check_6_recommendation=Switch to amplify (bassclef default) OR contribute the adapter at scripts/adapters/deploy/${hosting}.sh"
|
|
313
|
+
warn=$((warn + 1))
|
|
314
|
+
elif [ "$hosting" = "amplify" ] || [ "$hosting" = "ec2-tailscale" ] || [ "$hosting" = "mock" ]; then
|
|
315
|
+
# Known-good enum value but adapter not found at expected path — could be
|
|
316
|
+
# BASSCLEF_DIR pointing at the wrong place, or substrate sync incomplete
|
|
317
|
+
if [ -z "${BASSCLEF_DIR:-}" ]; then
|
|
318
|
+
echo "check_6_status=warn"
|
|
319
|
+
echo "check_6_message=hosting_platform=$hosting (BASSCLEF_DIR not reachable; can't verify adapter)"
|
|
320
|
+
echo "check_6_recommendation=Set BASSCLEF_DIR OR run /onboard-repo to sync bassclef substrate"
|
|
321
|
+
warn=$((warn + 1))
|
|
322
|
+
else
|
|
323
|
+
echo "check_6_status=warn"
|
|
324
|
+
echo "check_6_message=hosting_platform=$hosting in enum but adapter missing at $adapter_check"
|
|
325
|
+
echo "check_6_recommendation=Run bassclef-sync.sh to refresh adapter symlinks OR check BASSCLEF_DIR points at bassclef repo root"
|
|
326
|
+
warn=$((warn + 1))
|
|
327
|
+
fi
|
|
328
|
+
else
|
|
329
|
+
echo "check_6_status=fail"
|
|
330
|
+
echo "check_6_message=hosting_platform=$hosting not in schema enum"
|
|
331
|
+
echo "check_6_recommendation=Use one of: amplify | ec2-tailscale | vercel | netlify | cloudflare-pages | none"
|
|
332
|
+
fail=$((fail + 1))
|
|
333
|
+
fi
|
|
334
|
+
|
|
335
|
+
# === Check 7: spec-and-use-case (bet 24a Step 2c per Cockburn ceremony matrix) ===
|
|
336
|
+
# Fires when staged diff includes code paths that merit spec + use-case coverage.
|
|
337
|
+
# Warns if no artifact at docs/use-cases/UC-*.md OR docs/specs/*.md OR
|
|
338
|
+
# docs/decompositions/*.md when substrate + adopter code staged.
|
|
339
|
+
# Per .claude/rules/oo-ad-entry-point.md (extended to include hook/lib/script paths).
|
|
340
|
+
# Cockburn tiering — new hook + lib merit brief use case; app code merits fully-dressed.
|
|
341
|
+
echo "check_7_name=spec-and-use-case"
|
|
342
|
+
local staged_code
|
|
343
|
+
staged_code=$(git diff --cached --name-only --diff-filter=AM 2>/dev/null | grep -E \
|
|
344
|
+
-e '^src/.*\.(ts|tsx|js|py)$' \
|
|
345
|
+
-e '^\.claude/hooks/[^/]+\.sh$' \
|
|
346
|
+
-e '^lib/[^/]+\.sh$' \
|
|
347
|
+
-e '^scripts/[^/]+\.sh$' \
|
|
348
|
+
|| true)
|
|
349
|
+
if [ -z "$staged_code" ]; then
|
|
350
|
+
echo "check_7_status=pass"
|
|
351
|
+
echo "check_7_message=No code paths staged (docs-only or non-code commit)"
|
|
352
|
+
echo "check_7_recommendation="
|
|
353
|
+
pass=$((pass + 1))
|
|
354
|
+
else
|
|
355
|
+
local uc_count spec_count decomp_count total_artifacts
|
|
356
|
+
uc_count=$(ls "$repo_root/docs/use-cases/"UC-*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
357
|
+
spec_count=$(ls "$repo_root/docs/specs/"*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
358
|
+
decomp_count=$(ls "$repo_root/docs/decompositions/"*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
359
|
+
total_artifacts=$((uc_count + spec_count + decomp_count))
|
|
360
|
+
if [ "$total_artifacts" -gt 0 ]; then
|
|
361
|
+
echo "check_7_status=pass"
|
|
362
|
+
echo "check_7_message=Code staged + $total_artifacts design artifact(s) present (uc=$uc_count spec=$spec_count decomp=$decomp_count)"
|
|
363
|
+
echo "check_7_recommendation="
|
|
364
|
+
pass=$((pass + 1))
|
|
365
|
+
else
|
|
366
|
+
echo "check_7_status=warn"
|
|
367
|
+
echo "check_7_message=Code paths staged but no use-case / spec / decomposition present"
|
|
368
|
+
echo "check_7_recommendation=Per Cockburn ceremony matrix — new hook + lib merit brief use case at docs/use-cases/UC-<slug>.md; app code merits fully-dressed. Skip only for typo/trivial extensions."
|
|
369
|
+
warn=$((warn + 1))
|
|
370
|
+
fi
|
|
371
|
+
fi
|
|
372
|
+
|
|
373
|
+
# === Summary ===
|
|
374
|
+
echo "summary_count_pass=$pass"
|
|
375
|
+
echo "summary_count_warn=$warn"
|
|
376
|
+
echo "summary_count_fail=$fail"
|
|
377
|
+
if [ "$fail" -gt 0 ]; then
|
|
378
|
+
echo "summary_status=fail"
|
|
379
|
+
return 2
|
|
380
|
+
elif [ "$warn" -gt 0 ]; then
|
|
381
|
+
echo "summary_status=warn"
|
|
382
|
+
return 1
|
|
383
|
+
else
|
|
384
|
+
echo "summary_status=pass"
|
|
385
|
+
return 0
|
|
386
|
+
fi
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
# Helper: render the structured output as a human-readable block.
|
|
390
|
+
# Composers can pipe `composer_preflight_check ... | composer_preflight_render`
|
|
391
|
+
# for a polished operator-facing surface.
|
|
392
|
+
composer_preflight_render() {
|
|
393
|
+
local skill_name="${1:-the skill}"
|
|
394
|
+
local input
|
|
395
|
+
input=$(cat)
|
|
396
|
+
|
|
397
|
+
echo ""
|
|
398
|
+
echo "============================================"
|
|
399
|
+
echo "PRE-FLIGHT CHECK — /$skill_name"
|
|
400
|
+
echo "============================================"
|
|
401
|
+
|
|
402
|
+
local i status name message rec
|
|
403
|
+
for i in 1 2 3 4 5 6 7; do
|
|
404
|
+
status=$(echo "$input" | grep -E "^check_${i}_status=" | head -1 | sed 's/^check_[0-9]_status=//')
|
|
405
|
+
name=$(echo "$input" | grep -E "^check_${i}_name=" | head -1 | sed 's/^check_[0-9]_name=//')
|
|
406
|
+
message=$(echo "$input" | grep -E "^check_${i}_message=" | head -1 | sed 's/^check_[0-9]_message=//')
|
|
407
|
+
rec=$(echo "$input" | grep -E "^check_${i}_recommendation=" | head -1 | sed 's/^check_[0-9]_recommendation=//')
|
|
408
|
+
|
|
409
|
+
# Skip render slot if check didn't fire (e.g., pre-Check-6 fixtures)
|
|
410
|
+
[ -z "$name" ] && continue
|
|
411
|
+
|
|
412
|
+
local glyph
|
|
413
|
+
case "$status" in
|
|
414
|
+
pass) glyph="✓" ;;
|
|
415
|
+
warn) glyph="⚠️ " ;;
|
|
416
|
+
fail) glyph="✗" ;;
|
|
417
|
+
*) glyph="?" ;;
|
|
418
|
+
esac
|
|
419
|
+
|
|
420
|
+
printf " %s %-15s %s\n" "$glyph" "$name" "$message"
|
|
421
|
+
if [ -n "$rec" ]; then
|
|
422
|
+
printf " └─ recommendation: %s\n" "$rec"
|
|
423
|
+
fi
|
|
424
|
+
done
|
|
425
|
+
|
|
426
|
+
local summary_status pass warn fail
|
|
427
|
+
summary_status=$(echo "$input" | grep "^summary_status=" | head -1 | sed 's/^summary_status=//')
|
|
428
|
+
pass=$(echo "$input" | grep "^summary_count_pass=" | head -1 | sed 's/^summary_count_pass=//')
|
|
429
|
+
warn=$(echo "$input" | grep "^summary_count_warn=" | head -1 | sed 's/^summary_count_warn=//')
|
|
430
|
+
fail=$(echo "$input" | grep "^summary_count_fail=" | head -1 | sed 's/^summary_count_fail=//')
|
|
431
|
+
|
|
432
|
+
echo ""
|
|
433
|
+
case "$summary_status" in
|
|
434
|
+
pass)
|
|
435
|
+
echo "DISPATCH READY: all $pass checks pass."
|
|
436
|
+
;;
|
|
437
|
+
warn)
|
|
438
|
+
echo "DISPATCH WITH WARNINGS: $pass pass, $warn warn, $fail fail."
|
|
439
|
+
echo "Composer should ask operator to proceed/abort."
|
|
440
|
+
;;
|
|
441
|
+
fail)
|
|
442
|
+
echo "DISPATCH REFUSED: $pass pass, $warn warn, $fail fail."
|
|
443
|
+
echo "Resolve fail-tier checks before proceeding."
|
|
444
|
+
;;
|
|
445
|
+
skip)
|
|
446
|
+
echo "PRE-FLIGHT SKIPPED (SKIP_COMPOSER_PREFLIGHT=1)."
|
|
447
|
+
;;
|
|
448
|
+
esac
|
|
449
|
+
echo "============================================"
|
|
450
|
+
echo ""
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
# If sourced, the functions are available. If executed directly, run a
|
|
454
|
+
# self-test against the current repo + report.
|
|
455
|
+
if [ "${BASH_SOURCE[0]:-$0}" = "${0}" ]; then
|
|
456
|
+
echo "Self-test mode: running composer_preflight_check for /launch with 60-turn estimate"
|
|
457
|
+
echo ""
|
|
458
|
+
composer_preflight_check "launch" 60 | composer_preflight_render "launch"
|
|
459
|
+
fi
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# lib/deferred-actions.sh — typed accessor for docs/deferred-actions/
|
|
4
|
+
#
|
|
5
|
+
# Single reader/writer for deferred-action entries. Replaces ad-hoc ls +
|
|
6
|
+
# grep patterns in 60-deferred-actions.sh and similar consumers.
|
|
7
|
+
#
|
|
8
|
+
# Public API:
|
|
9
|
+
# da_dir → echo path to docs/deferred-actions/
|
|
10
|
+
# da_completed_dir → echo path to docs/deferred-actions/completed/
|
|
11
|
+
# da_list_open → list open *.md (one path per line)
|
|
12
|
+
# da_list_completed → list completed/*.md
|
|
13
|
+
# da_get_field <id> <field> → frontmatter field reader
|
|
14
|
+
# da_resolve <id> → git mv id.md → completed/id.md
|
|
15
|
+
# da_filter_by_capability <cap> → list open whose required-capability matches
|
|
16
|
+
# da_filter_by_priority <high|medium|low> → list open by priority field
|
|
17
|
+
#
|
|
18
|
+
# `<id>` may be a bare filename (`2026-04-26T01-00-00Z-foo.md`) or full path.
|
|
19
|
+
# `<cap>` matches against `requires_capability:` frontmatter field.
|
|
20
|
+
|
|
21
|
+
set -uo pipefail
|
|
22
|
+
|
|
23
|
+
da_dir() {
|
|
24
|
+
if [[ -n "${DEFERRED_ACTIONS_DIR:-}" ]]; then
|
|
25
|
+
echo "$DEFERRED_ACTIONS_DIR"
|
|
26
|
+
elif [[ -n "${BASSCLEF_REPO_ROOT:-}" ]]; then
|
|
27
|
+
echo "$BASSCLEF_REPO_ROOT/docs/deferred-actions"
|
|
28
|
+
else
|
|
29
|
+
echo "docs/deferred-actions"
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
da_completed_dir() {
|
|
34
|
+
echo "$(da_dir)/completed"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
da_list_open() {
|
|
38
|
+
local dir
|
|
39
|
+
dir="$(da_dir)"
|
|
40
|
+
[[ -d "$dir" ]] || return 0
|
|
41
|
+
# Open entries = .md files at top-level (not in completed/), excluding README/template
|
|
42
|
+
find "$dir" -maxdepth 1 -type f -name '*.md' \
|
|
43
|
+
! -name 'README.md' \
|
|
44
|
+
! -name 'template.md' \
|
|
45
|
+
2>/dev/null | sort
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
da_list_completed() {
|
|
49
|
+
local dir
|
|
50
|
+
dir="$(da_completed_dir)"
|
|
51
|
+
[[ -d "$dir" ]] || return 0
|
|
52
|
+
find "$dir" -maxdepth 1 -type f -name '*.md' 2>/dev/null | sort
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Resolve <id> → full path. Accepts bare filename or full path.
|
|
56
|
+
# Full path forms: absolute (/foo), explicit relative (./foo), or any other
|
|
57
|
+
# string that already resolves to a file. Bare filename: prepended with da_dir.
|
|
58
|
+
# Non-existent bare-relative: also prepended with da_dir (backward compat).
|
|
59
|
+
_da_resolve_path() {
|
|
60
|
+
local id="$1"
|
|
61
|
+
if [[ "$id" == /* || "$id" == ./* ]]; then
|
|
62
|
+
echo "$id"
|
|
63
|
+
elif [[ -f "$id" ]]; then
|
|
64
|
+
# Bare-relative path that already resolves — pass through.
|
|
65
|
+
# Closes bassclef-upstream#1016 (da_list_open output was being doubled).
|
|
66
|
+
echo "$id"
|
|
67
|
+
else
|
|
68
|
+
echo "$(da_dir)/$id"
|
|
69
|
+
fi
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
da_get_field() {
|
|
73
|
+
local id="$1"
|
|
74
|
+
local field="$2"
|
|
75
|
+
local path
|
|
76
|
+
path="$(_da_resolve_path "$id")"
|
|
77
|
+
[[ -f "$path" ]] || { echo "not-found: $path" >&2; return 1; }
|
|
78
|
+
# Read frontmatter only (between two `---` lines)
|
|
79
|
+
awk -v f="$field" '
|
|
80
|
+
BEGIN { in_fm = 0; seen_open = 0 }
|
|
81
|
+
/^---[[:space:]]*$/ {
|
|
82
|
+
if (!seen_open) { seen_open = 1; in_fm = 1; next }
|
|
83
|
+
else { in_fm = 0; exit }
|
|
84
|
+
}
|
|
85
|
+
in_fm && $0 ~ "^" f ":" {
|
|
86
|
+
sub("^" f ":[[:space:]]*", "")
|
|
87
|
+
# Strip surrounding quotes if any
|
|
88
|
+
gsub(/^"|"$/, "")
|
|
89
|
+
print
|
|
90
|
+
exit
|
|
91
|
+
}
|
|
92
|
+
' "$path"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
da_resolve() {
|
|
96
|
+
local id="$1"
|
|
97
|
+
local src dst dst_dir
|
|
98
|
+
src="$(_da_resolve_path "$id")"
|
|
99
|
+
[[ -f "$src" ]] || { echo "da_resolve: not-found: $src" >&2; return 1; }
|
|
100
|
+
dst_dir="$(da_completed_dir)"
|
|
101
|
+
mkdir -p "$dst_dir"
|
|
102
|
+
dst="$dst_dir/$(basename "$src")"
|
|
103
|
+
git mv "$src" "$dst" 2>/dev/null || mv "$src" "$dst"
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
da_filter_by_capability() {
|
|
107
|
+
local cap="$1"
|
|
108
|
+
local entry value
|
|
109
|
+
while IFS= read -r entry; do
|
|
110
|
+
[[ -z "$entry" ]] && continue
|
|
111
|
+
value="$(da_get_field "$entry" requires_capability 2>/dev/null || true)"
|
|
112
|
+
# Match if exact OR comma-separated list contains cap
|
|
113
|
+
if [[ "$value" == "$cap" || ",$value," == *",$cap,"* ]]; then
|
|
114
|
+
echo "$entry"
|
|
115
|
+
fi
|
|
116
|
+
done < <(da_list_open)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
da_filter_by_priority() {
|
|
120
|
+
local prio="$1"
|
|
121
|
+
local entry value
|
|
122
|
+
while IFS= read -r entry; do
|
|
123
|
+
[[ -z "$entry" ]] && continue
|
|
124
|
+
value="$(da_get_field "$entry" priority 2>/dev/null || true)"
|
|
125
|
+
[[ "$value" == "$prio" ]] && echo "$entry"
|
|
126
|
+
done < <(da_list_open)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
130
|
+
cmd="${1:-}"
|
|
131
|
+
shift || true
|
|
132
|
+
case "$cmd" in
|
|
133
|
+
dir) da_dir ;;
|
|
134
|
+
completed_dir) da_completed_dir ;;
|
|
135
|
+
list_open) da_list_open ;;
|
|
136
|
+
list_completed) da_list_completed ;;
|
|
137
|
+
get_field) da_get_field "$@" ;;
|
|
138
|
+
resolve) da_resolve "$@" ;;
|
|
139
|
+
filter_by_capability) da_filter_by_capability "$@" ;;
|
|
140
|
+
filter_by_priority) da_filter_by_priority "$@" ;;
|
|
141
|
+
*)
|
|
142
|
+
echo "usage: $0 {dir|completed_dir|list_open|list_completed|get_field|resolve|filter_by_capability|filter_by_priority} [args]" >&2
|
|
143
|
+
exit 2
|
|
144
|
+
;;
|
|
145
|
+
esac
|
|
146
|
+
fi
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# install-class: dual
|
|
4
|
+
#
|
|
5
|
+
# lib/hook-header-parser.sh — reads the # install-class: header from a hook file
|
|
6
|
+
#
|
|
7
|
+
# @pattern patterns/code/gof/adapter.md
|
|
8
|
+
# Adapts raw header text to typed enum values.
|
|
9
|
+
#
|
|
10
|
+
# Contract (Hoare):
|
|
11
|
+
# - Precondition: hook_path exists and is readable
|
|
12
|
+
# - Postcondition (success): stdout is one of operator|project|dual + exit 0
|
|
13
|
+
# - Postcondition (failure): stdout empty + exit non-zero
|
|
14
|
+
#
|
|
15
|
+
# Per docs/decompositions/2026-09-15-install-class-dispatch.md
|
|
16
|
+
# Per docs/use-cases/UC-lib-hook-installer.md
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
# Valid install-class values per standards/hook-install-class.md
|
|
21
|
+
_HOOK_INSTALL_CLASS_VALID_VALUES=(operator project dual)
|
|
22
|
+
|
|
23
|
+
# parse_install_class(hook_path) → prints "operator" | "project" | "dual" | ""
|
|
24
|
+
# Returns 0 on success, non-zero on failure.
|
|
25
|
+
parse_install_class() {
|
|
26
|
+
local hook_path="$1"
|
|
27
|
+
|
|
28
|
+
# Precondition: file exists and is readable (not a directory)
|
|
29
|
+
if [ ! -f "$hook_path" ] || [ ! -r "$hook_path" ]; then
|
|
30
|
+
return 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Read first 10 lines only — strict header window
|
|
34
|
+
# Match: optional leading whitespace + "# install-class: <value>"
|
|
35
|
+
# Case-sensitive on value
|
|
36
|
+
local raw_class
|
|
37
|
+
raw_class=$(head -n 10 "$hook_path" | grep -E '^[[:space:]]*# install-class:[[:space:]]*' | head -n 1 || true)
|
|
38
|
+
|
|
39
|
+
if [ -z "$raw_class" ]; then
|
|
40
|
+
return 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Extract value — strip leading whitespace, hash, "install-class:", surrounding whitespace
|
|
44
|
+
local value
|
|
45
|
+
value=$(echo "$raw_class" | sed -E 's/^[[:space:]]*#[[:space:]]*install-class:[[:space:]]*//; s/[[:space:]]*$//')
|
|
46
|
+
|
|
47
|
+
# Validate against enum
|
|
48
|
+
local v
|
|
49
|
+
for v in "${_HOOK_INSTALL_CLASS_VALID_VALUES[@]}"; do
|
|
50
|
+
if [ "$value" = "$v" ]; then
|
|
51
|
+
echo "$value"
|
|
52
|
+
return 0
|
|
53
|
+
fi
|
|
54
|
+
done
|
|
55
|
+
|
|
56
|
+
# Unknown or malformed value
|
|
57
|
+
return 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Export for callers that source this file
|
|
61
|
+
export -f parse_install_class 2>/dev/null || true
|