shipwright-cli 3.1.0 → 3.3.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/.claude/agents/code-reviewer.md +2 -0
- package/.claude/agents/devops-engineer.md +2 -0
- package/.claude/agents/doc-fleet-agent.md +2 -0
- package/.claude/agents/pipeline-agent.md +2 -0
- package/.claude/agents/shell-script-specialist.md +2 -0
- package/.claude/agents/test-specialist.md +2 -0
- package/.claude/hooks/agent-crash-capture.sh +32 -0
- package/.claude/hooks/post-tool-use.sh +3 -2
- package/.claude/hooks/pre-tool-use.sh +35 -3
- package/README.md +22 -8
- package/claude-code/hooks/config-change.sh +18 -0
- package/claude-code/hooks/instructions-reloaded.sh +7 -0
- package/claude-code/hooks/worktree-create.sh +25 -0
- package/claude-code/hooks/worktree-remove.sh +20 -0
- package/config/code-constitution.json +130 -0
- package/config/defaults.json +25 -2
- package/config/policy.json +1 -1
- package/dashboard/middleware/auth.ts +134 -0
- package/dashboard/middleware/constants.ts +21 -0
- package/dashboard/public/index.html +8 -6
- package/dashboard/public/styles.css +176 -97
- package/dashboard/routes/auth.ts +38 -0
- package/dashboard/server.ts +117 -25
- package/dashboard/services/config.ts +26 -0
- package/dashboard/services/db.ts +118 -0
- package/dashboard/src/canvas/pixel-agent.ts +298 -0
- package/dashboard/src/canvas/pixel-sprites.ts +440 -0
- package/dashboard/src/canvas/shipyard-effects.ts +367 -0
- package/dashboard/src/canvas/shipyard-scene.ts +616 -0
- package/dashboard/src/canvas/submarine-layout.ts +267 -0
- package/dashboard/src/components/header.ts +8 -7
- package/dashboard/src/core/api.ts +5 -0
- package/dashboard/src/core/router.ts +1 -0
- package/dashboard/src/design/submarine-theme.ts +253 -0
- package/dashboard/src/main.ts +2 -0
- package/dashboard/src/types/api.ts +12 -1
- package/dashboard/src/views/activity.ts +2 -1
- package/dashboard/src/views/metrics.ts +69 -1
- package/dashboard/src/views/shipyard.ts +39 -0
- package/dashboard/types/index.ts +166 -0
- package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
- package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
- package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
- package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
- package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
- package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
- package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
- package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
- package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
- package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
- package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
- package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
- package/docs/research/RESEARCH_INDEX.md +439 -0
- package/docs/research/RESEARCH_SOURCES.md +440 -0
- package/docs/research/RESEARCH_SUMMARY.txt +275 -0
- package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
- package/package.json +2 -2
- package/scripts/lib/adaptive-model.sh +427 -0
- package/scripts/lib/adaptive-timeout.sh +316 -0
- package/scripts/lib/audit-trail.sh +309 -0
- package/scripts/lib/auto-recovery.sh +471 -0
- package/scripts/lib/bandit-selector.sh +431 -0
- package/scripts/lib/bootstrap.sh +104 -2
- package/scripts/lib/causal-graph.sh +455 -0
- package/scripts/lib/compat.sh +126 -0
- package/scripts/lib/compound-audit.sh +337 -0
- package/scripts/lib/constitutional.sh +454 -0
- package/scripts/lib/context-budget.sh +359 -0
- package/scripts/lib/convergence.sh +594 -0
- package/scripts/lib/cost-optimizer.sh +634 -0
- package/scripts/lib/daemon-adaptive.sh +14 -2
- package/scripts/lib/daemon-dispatch.sh +106 -17
- package/scripts/lib/daemon-failure.sh +34 -4
- package/scripts/lib/daemon-patrol.sh +25 -4
- package/scripts/lib/daemon-poll-github.sh +361 -0
- package/scripts/lib/daemon-poll-health.sh +299 -0
- package/scripts/lib/daemon-poll.sh +27 -611
- package/scripts/lib/daemon-state.sh +119 -66
- package/scripts/lib/daemon-triage.sh +10 -0
- package/scripts/lib/dod-scorecard.sh +442 -0
- package/scripts/lib/error-actionability.sh +300 -0
- package/scripts/lib/formal-spec.sh +461 -0
- package/scripts/lib/helpers.sh +180 -5
- package/scripts/lib/intent-analysis.sh +409 -0
- package/scripts/lib/loop-convergence.sh +350 -0
- package/scripts/lib/loop-iteration.sh +682 -0
- package/scripts/lib/loop-progress.sh +48 -0
- package/scripts/lib/loop-restart.sh +185 -0
- package/scripts/lib/memory-effectiveness.sh +506 -0
- package/scripts/lib/mutation-executor.sh +352 -0
- package/scripts/lib/outcome-feedback.sh +521 -0
- package/scripts/lib/pipeline-cli.sh +336 -0
- package/scripts/lib/pipeline-commands.sh +1216 -0
- package/scripts/lib/pipeline-detection.sh +101 -3
- package/scripts/lib/pipeline-execution.sh +897 -0
- package/scripts/lib/pipeline-github.sh +28 -3
- package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
- package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
- package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
- package/scripts/lib/pipeline-intelligence.sh +104 -1138
- package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
- package/scripts/lib/pipeline-quality-checks.sh +17 -711
- package/scripts/lib/pipeline-quality-gates.sh +563 -0
- package/scripts/lib/pipeline-stages-build.sh +730 -0
- package/scripts/lib/pipeline-stages-delivery.sh +965 -0
- package/scripts/lib/pipeline-stages-intake.sh +1133 -0
- package/scripts/lib/pipeline-stages-monitor.sh +407 -0
- package/scripts/lib/pipeline-stages-review.sh +1022 -0
- package/scripts/lib/pipeline-stages.sh +161 -2901
- package/scripts/lib/pipeline-state.sh +36 -5
- package/scripts/lib/pipeline-util.sh +487 -0
- package/scripts/lib/policy-learner.sh +438 -0
- package/scripts/lib/process-reward.sh +493 -0
- package/scripts/lib/project-detect.sh +649 -0
- package/scripts/lib/quality-profile.sh +334 -0
- package/scripts/lib/recruit-commands.sh +885 -0
- package/scripts/lib/recruit-learning.sh +739 -0
- package/scripts/lib/recruit-roles.sh +648 -0
- package/scripts/lib/reward-aggregator.sh +458 -0
- package/scripts/lib/rl-optimizer.sh +362 -0
- package/scripts/lib/root-cause.sh +427 -0
- package/scripts/lib/scope-enforcement.sh +445 -0
- package/scripts/lib/session-restart.sh +493 -0
- package/scripts/lib/skill-memory.sh +300 -0
- package/scripts/lib/skill-registry.sh +775 -0
- package/scripts/lib/spec-driven.sh +476 -0
- package/scripts/lib/test-helpers.sh +18 -7
- package/scripts/lib/test-holdout.sh +429 -0
- package/scripts/lib/test-optimizer.sh +511 -0
- package/scripts/shipwright-file-suggest.sh +45 -0
- package/scripts/skills/adversarial-quality.md +61 -0
- package/scripts/skills/api-design.md +44 -0
- package/scripts/skills/architecture-design.md +50 -0
- package/scripts/skills/brainstorming.md +43 -0
- package/scripts/skills/data-pipeline.md +44 -0
- package/scripts/skills/deploy-safety.md +64 -0
- package/scripts/skills/documentation.md +38 -0
- package/scripts/skills/frontend-design.md +45 -0
- package/scripts/skills/generated/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
- package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
- package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
- package/scripts/skills/generated/cli-version-management.md +29 -0
- package/scripts/skills/generated/collection-system-validation.md +99 -0
- package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
- package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
- package/scripts/skills/generated/test-parallelization-detection.md +65 -0
- package/scripts/skills/observability.md +79 -0
- package/scripts/skills/performance.md +48 -0
- package/scripts/skills/pr-quality.md +49 -0
- package/scripts/skills/product-thinking.md +43 -0
- package/scripts/skills/security-audit.md +49 -0
- package/scripts/skills/systematic-debugging.md +40 -0
- package/scripts/skills/testing-strategy.md +47 -0
- package/scripts/skills/two-stage-review.md +52 -0
- package/scripts/skills/validation-thoroughness.md +55 -0
- package/scripts/sw +9 -3
- package/scripts/sw-activity.sh +9 -8
- package/scripts/sw-adaptive.sh +8 -7
- package/scripts/sw-adversarial.sh +2 -1
- package/scripts/sw-architecture-enforcer.sh +3 -1
- package/scripts/sw-auth.sh +12 -2
- package/scripts/sw-autonomous.sh +5 -1
- package/scripts/sw-changelog.sh +4 -1
- package/scripts/sw-checkpoint.sh +2 -1
- package/scripts/sw-ci.sh +15 -6
- package/scripts/sw-cleanup.sh +4 -26
- package/scripts/sw-code-review.sh +45 -20
- package/scripts/sw-connect.sh +2 -1
- package/scripts/sw-context.sh +2 -1
- package/scripts/sw-cost.sh +107 -5
- package/scripts/sw-daemon.sh +71 -11
- package/scripts/sw-dashboard.sh +3 -1
- package/scripts/sw-db.sh +71 -20
- package/scripts/sw-decide.sh +8 -2
- package/scripts/sw-decompose.sh +360 -17
- package/scripts/sw-deps.sh +4 -1
- package/scripts/sw-developer-simulation.sh +4 -1
- package/scripts/sw-discovery.sh +378 -5
- package/scripts/sw-doc-fleet.sh +4 -1
- package/scripts/sw-docs-agent.sh +3 -1
- package/scripts/sw-docs.sh +2 -1
- package/scripts/sw-doctor.sh +453 -2
- package/scripts/sw-dora.sh +4 -1
- package/scripts/sw-durable.sh +12 -7
- package/scripts/sw-e2e-orchestrator.sh +17 -16
- package/scripts/sw-eventbus.sh +13 -4
- package/scripts/sw-evidence.sh +364 -12
- package/scripts/sw-feedback.sh +550 -9
- package/scripts/sw-fix.sh +20 -1
- package/scripts/sw-fleet-discover.sh +6 -2
- package/scripts/sw-fleet-viz.sh +9 -4
- package/scripts/sw-fleet.sh +5 -1
- package/scripts/sw-github-app.sh +18 -4
- package/scripts/sw-github-checks.sh +3 -2
- package/scripts/sw-github-deploy.sh +3 -2
- package/scripts/sw-github-graphql.sh +18 -7
- package/scripts/sw-guild.sh +5 -1
- package/scripts/sw-heartbeat.sh +5 -30
- package/scripts/sw-hello.sh +67 -0
- package/scripts/sw-hygiene.sh +10 -3
- package/scripts/sw-incident.sh +273 -5
- package/scripts/sw-init.sh +18 -2
- package/scripts/sw-instrument.sh +10 -2
- package/scripts/sw-intelligence.sh +44 -7
- package/scripts/sw-jira.sh +5 -1
- package/scripts/sw-launchd.sh +2 -1
- package/scripts/sw-linear.sh +4 -1
- package/scripts/sw-logs.sh +4 -1
- package/scripts/sw-loop.sh +436 -1076
- package/scripts/sw-memory.sh +357 -3
- package/scripts/sw-mission-control.sh +6 -1
- package/scripts/sw-model-router.sh +483 -27
- package/scripts/sw-otel.sh +15 -4
- package/scripts/sw-oversight.sh +14 -5
- package/scripts/sw-patrol-meta.sh +334 -0
- package/scripts/sw-pipeline-composer.sh +7 -1
- package/scripts/sw-pipeline-vitals.sh +12 -6
- package/scripts/sw-pipeline.sh +54 -2653
- package/scripts/sw-pm.sh +16 -8
- package/scripts/sw-pr-lifecycle.sh +2 -1
- package/scripts/sw-predictive.sh +17 -5
- package/scripts/sw-prep.sh +185 -2
- package/scripts/sw-ps.sh +5 -25
- package/scripts/sw-public-dashboard.sh +17 -4
- package/scripts/sw-quality.sh +14 -6
- package/scripts/sw-reaper.sh +8 -25
- package/scripts/sw-recruit.sh +156 -2303
- package/scripts/sw-regression.sh +19 -12
- package/scripts/sw-release-manager.sh +3 -1
- package/scripts/sw-release.sh +4 -1
- package/scripts/sw-remote.sh +3 -1
- package/scripts/sw-replay.sh +7 -1
- package/scripts/sw-retro.sh +158 -1
- package/scripts/sw-review-rerun.sh +3 -1
- package/scripts/sw-scale.sh +14 -5
- package/scripts/sw-security-audit.sh +6 -1
- package/scripts/sw-self-optimize.sh +173 -6
- package/scripts/sw-session.sh +9 -3
- package/scripts/sw-setup.sh +3 -1
- package/scripts/sw-stall-detector.sh +406 -0
- package/scripts/sw-standup.sh +15 -7
- package/scripts/sw-status.sh +3 -1
- package/scripts/sw-strategic.sh +14 -6
- package/scripts/sw-stream.sh +13 -4
- package/scripts/sw-swarm.sh +20 -7
- package/scripts/sw-team-stages.sh +13 -6
- package/scripts/sw-templates.sh +7 -31
- package/scripts/sw-testgen.sh +17 -6
- package/scripts/sw-tmux-pipeline.sh +4 -1
- package/scripts/sw-tmux-role-color.sh +2 -0
- package/scripts/sw-tmux-status.sh +1 -1
- package/scripts/sw-tmux.sh +37 -1
- package/scripts/sw-trace.sh +3 -1
- package/scripts/sw-tracker-github.sh +3 -0
- package/scripts/sw-tracker-jira.sh +3 -0
- package/scripts/sw-tracker-linear.sh +3 -0
- package/scripts/sw-tracker.sh +3 -1
- package/scripts/sw-triage.sh +3 -2
- package/scripts/sw-upgrade.sh +3 -1
- package/scripts/sw-ux.sh +5 -2
- package/scripts/sw-webhook.sh +5 -2
- package/scripts/sw-widgets.sh +9 -4
- package/scripts/sw-worktree.sh +15 -3
- package/scripts/test-skill-injection.sh +1233 -0
- package/templates/pipelines/autonomous.json +27 -3
- package/templates/pipelines/cost-aware.json +34 -8
- package/templates/pipelines/deployed.json +12 -0
- package/templates/pipelines/enterprise.json +12 -0
- package/templates/pipelines/fast.json +6 -0
- package/templates/pipelines/full.json +27 -3
- package/templates/pipelines/hotfix.json +6 -0
- package/templates/pipelines/standard.json +12 -0
- package/templates/pipelines/tdd.json +12 -0
|
@@ -0,0 +1,1109 @@
|
|
|
1
|
+
# AI-Powered Skill Injection Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
+
|
|
5
|
+
**Goal:** Replace static rules-based skill selection with LLM-powered intelligent routing, dynamic skill generation, and outcome learning.
|
|
6
|
+
|
|
7
|
+
**Architecture:** One haiku LLM call at intake analyzes the issue and returns a complete skill plan (selection + rationale + generated skills). Downstream stages read from the plan artifact. A second haiku call at completion analyzes outcomes and refines the skill library. Static registry remains as three-layer fallback.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Bash, jq, Claude CLI (haiku model via `_intelligence_call_claude()`), JSON artifacts
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Task 1: Create Generated Skills Directory Structure
|
|
14
|
+
|
|
15
|
+
**Files:**
|
|
16
|
+
- Create: `scripts/skills/generated/.gitkeep`
|
|
17
|
+
- Create: `scripts/skills/generated/_refinements/.gitkeep`
|
|
18
|
+
|
|
19
|
+
**Step 1: Create directories**
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
mkdir -p scripts/skills/generated/_refinements
|
|
23
|
+
touch scripts/skills/generated/.gitkeep
|
|
24
|
+
touch scripts/skills/generated/_refinements/.gitkeep
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Step 2: Commit**
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git add scripts/skills/generated/
|
|
31
|
+
git commit -m "chore: add generated skills directory structure"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
### Task 2: Add `skill_build_catalog()` to skill-registry.sh
|
|
37
|
+
|
|
38
|
+
**Files:**
|
|
39
|
+
- Modify: `scripts/lib/skill-registry.sh` (append after line 319)
|
|
40
|
+
- Test: `scripts/test-skill-injection.sh`
|
|
41
|
+
|
|
42
|
+
**Step 1: Write the failing test**
|
|
43
|
+
|
|
44
|
+
Add Suite 11 to `scripts/test-skill-injection.sh`:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
echo ""
|
|
48
|
+
echo "═══ Suite 11: Skill Catalog Builder ═══"
|
|
49
|
+
echo ""
|
|
50
|
+
|
|
51
|
+
# Test: catalog includes curated skills
|
|
52
|
+
echo " ── Curated skills in catalog ──"
|
|
53
|
+
local catalog
|
|
54
|
+
catalog=$(skill_build_catalog 2>/dev/null || true)
|
|
55
|
+
assert_contains "$catalog" "brainstorming" "catalog includes brainstorming"
|
|
56
|
+
assert_contains "$catalog" "frontend-design" "catalog includes frontend-design"
|
|
57
|
+
assert_contains "$catalog" "security-audit" "catalog includes security-audit"
|
|
58
|
+
|
|
59
|
+
# Test: catalog includes one-line descriptions
|
|
60
|
+
assert_contains "$catalog" "Socratic" "brainstorming has description"
|
|
61
|
+
|
|
62
|
+
# Test: catalog includes generated skills when they exist
|
|
63
|
+
local _gen_dir="${SKILLS_DIR}/generated"
|
|
64
|
+
mkdir -p "$_gen_dir"
|
|
65
|
+
echo "## Test Generated Skill\nTest content for generated skill." > "$_gen_dir/test-gen-skill.md"
|
|
66
|
+
catalog=$(skill_build_catalog 2>/dev/null || true)
|
|
67
|
+
assert_contains "$catalog" "test-gen-skill" "catalog includes generated skill"
|
|
68
|
+
assert_contains "$catalog" "[generated]" "generated skill is tagged"
|
|
69
|
+
rm -f "$_gen_dir/test-gen-skill.md"
|
|
70
|
+
|
|
71
|
+
# Test: catalog includes memory context when available
|
|
72
|
+
skill_memory_clear 2>/dev/null || true
|
|
73
|
+
skill_memory_record "frontend" "plan" "brainstorming" "success" "1" >/dev/null 2>&1 || true
|
|
74
|
+
skill_memory_record "frontend" "plan" "brainstorming" "success" "1" >/dev/null 2>&1 || true
|
|
75
|
+
catalog=$(skill_build_catalog "frontend" "plan" 2>/dev/null || true)
|
|
76
|
+
assert_contains "$catalog" "success" "catalog includes memory context"
|
|
77
|
+
skill_memory_clear 2>/dev/null || true
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Step 2: Run test to verify it fails**
|
|
81
|
+
|
|
82
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | grep -A2 "Suite 11"`
|
|
83
|
+
Expected: FAIL — `skill_build_catalog: command not found`
|
|
84
|
+
|
|
85
|
+
**Step 3: Write the implementation**
|
|
86
|
+
|
|
87
|
+
Append to `scripts/lib/skill-registry.sh` after line 319:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
# AI-POWERED SKILL SELECTION (Tier 1)
|
|
92
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
GENERATED_SKILLS_DIR="${SKILLS_DIR}/generated"
|
|
95
|
+
REFINEMENTS_DIR="${GENERATED_SKILLS_DIR}/_refinements"
|
|
96
|
+
|
|
97
|
+
# skill_build_catalog — Build a compact skill index for the LLM router prompt.
|
|
98
|
+
# $1: issue_type (optional — for memory context)
|
|
99
|
+
# $2: stage (optional — for memory context)
|
|
100
|
+
# Returns: multi-line text, one skill per line with description and optional memory stats.
|
|
101
|
+
skill_build_catalog() {
|
|
102
|
+
local issue_type="${1:-}" stage="${2:-}"
|
|
103
|
+
local catalog=""
|
|
104
|
+
|
|
105
|
+
# Scan curated skills
|
|
106
|
+
local skill_file
|
|
107
|
+
for skill_file in "$SKILLS_DIR"/*.md; do
|
|
108
|
+
[[ ! -f "$skill_file" ]] && continue
|
|
109
|
+
local name
|
|
110
|
+
name=$(basename "$skill_file" .md)
|
|
111
|
+
# Extract first meaningful line as description (skip headers, blank lines)
|
|
112
|
+
local desc
|
|
113
|
+
desc=$(grep -v '^#\|^$\|^---\|^\*\*IMPORTANT' "$skill_file" 2>/dev/null | head -1 | cut -c1-120 || echo "")
|
|
114
|
+
[[ -z "$desc" ]] && desc=$(head -1 "$skill_file" | sed 's/^#* *//' | cut -c1-120)
|
|
115
|
+
|
|
116
|
+
local memory_hint=""
|
|
117
|
+
if [[ -n "$issue_type" && -n "$stage" ]] && type skill_memory_get_success_rate >/dev/null 2>&1; then
|
|
118
|
+
local rate
|
|
119
|
+
rate=$(skill_memory_get_success_rate "$issue_type" "$stage" "$name" 2>/dev/null || true)
|
|
120
|
+
[[ -n "$rate" ]] && memory_hint=" [${rate}% success for ${issue_type}/${stage}]"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
catalog="${catalog}
|
|
124
|
+
- ${name}: ${desc}${memory_hint}"
|
|
125
|
+
done
|
|
126
|
+
|
|
127
|
+
# Scan generated skills
|
|
128
|
+
if [[ -d "$GENERATED_SKILLS_DIR" ]]; then
|
|
129
|
+
for skill_file in "$GENERATED_SKILLS_DIR"/*.md; do
|
|
130
|
+
[[ ! -f "$skill_file" ]] && continue
|
|
131
|
+
local name
|
|
132
|
+
name=$(basename "$skill_file" .md)
|
|
133
|
+
local desc
|
|
134
|
+
desc=$(grep -v '^#\|^$\|^---\|^\*\*IMPORTANT' "$skill_file" 2>/dev/null | head -1 | cut -c1-120 || echo "")
|
|
135
|
+
[[ -z "$desc" ]] && desc=$(head -1 "$skill_file" | sed 's/^#* *//' | cut -c1-120)
|
|
136
|
+
|
|
137
|
+
local memory_hint=""
|
|
138
|
+
if [[ -n "$issue_type" && -n "$stage" ]] && type skill_memory_get_success_rate >/dev/null 2>&1; then
|
|
139
|
+
local rate
|
|
140
|
+
rate=$(skill_memory_get_success_rate "$issue_type" "$stage" "$name" 2>/dev/null || true)
|
|
141
|
+
[[ -n "$rate" ]] && memory_hint=" [${rate}% success for ${issue_type}/${stage}]"
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
catalog="${catalog}
|
|
145
|
+
- ${name} [generated]: ${desc}${memory_hint}"
|
|
146
|
+
done
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
echo "$catalog"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Step 4: Run test to verify it passes**
|
|
154
|
+
|
|
155
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | tail -5`
|
|
156
|
+
Expected: ALL TESTS PASSED
|
|
157
|
+
|
|
158
|
+
**Step 5: Commit**
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
git add scripts/lib/skill-registry.sh scripts/test-skill-injection.sh
|
|
162
|
+
git commit -m "feat(skills): add skill_build_catalog for LLM router prompt"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### Task 3: Add `skill_analyze_issue()` — the LLM Router
|
|
168
|
+
|
|
169
|
+
**Files:**
|
|
170
|
+
- Modify: `scripts/lib/skill-registry.sh` (append after `skill_build_catalog`)
|
|
171
|
+
- Test: `scripts/test-skill-injection.sh`
|
|
172
|
+
|
|
173
|
+
**Step 1: Write the failing test**
|
|
174
|
+
|
|
175
|
+
Add to Suite 11 in `scripts/test-skill-injection.sh`:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
echo ""
|
|
179
|
+
echo " ── LLM skill analysis (mock) ──"
|
|
180
|
+
|
|
181
|
+
# We can't test real LLM calls in unit tests, so test the JSON parsing/artifact writing
|
|
182
|
+
# Mock: simulate skill_analyze_issue writing skill-plan.json
|
|
183
|
+
local _test_artifacts
|
|
184
|
+
_test_artifacts=$(mktemp -d)
|
|
185
|
+
|
|
186
|
+
local _mock_plan='{"issue_type":"frontend","confidence":0.92,"secondary_domains":["accessibility"],"complexity_assessment":{"score":6,"reasoning":"moderate"},"skill_plan":{"plan":["brainstorming","frontend-design"],"build":["frontend-design"],"review":["two-stage-review"]},"skill_rationale":{"frontend-design":"ARIA progressbar needed","brainstorming":"Task decomposition required"},"generated_skills":[],"review_focus":["accessibility"],"risk_areas":["ETA accuracy"]}'
|
|
187
|
+
echo "$_mock_plan" > "$_test_artifacts/skill-plan.json"
|
|
188
|
+
|
|
189
|
+
# Verify skill-plan.json is valid JSON
|
|
190
|
+
assert_true "jq '.' '$_test_artifacts/skill-plan.json' >/dev/null 2>&1" "skill-plan.json is valid JSON"
|
|
191
|
+
|
|
192
|
+
# Verify we can extract skills for a stage
|
|
193
|
+
local _plan_skills
|
|
194
|
+
_plan_skills=$(jq -r '.skill_plan.plan[]' "$_test_artifacts/skill-plan.json" 2>/dev/null | tr '\n' ',' | sed 's/,$//')
|
|
195
|
+
assert_eq "$_plan_skills" "brainstorming,frontend-design" "plan stage skills extracted correctly"
|
|
196
|
+
|
|
197
|
+
# Verify rationale extraction
|
|
198
|
+
local _rationale
|
|
199
|
+
_rationale=$(jq -r '.skill_rationale["frontend-design"]' "$_test_artifacts/skill-plan.json" 2>/dev/null)
|
|
200
|
+
assert_contains "$_rationale" "ARIA" "rationale extracted correctly"
|
|
201
|
+
|
|
202
|
+
rm -rf "$_test_artifacts"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Step 2: Run test to verify it fails**
|
|
206
|
+
|
|
207
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | grep "LLM skill analysis"`
|
|
208
|
+
Expected: Tests should pass (testing JSON parsing, not LLM call)
|
|
209
|
+
|
|
210
|
+
**Step 3: Write the implementation**
|
|
211
|
+
|
|
212
|
+
Append to `scripts/lib/skill-registry.sh`:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# skill_analyze_issue — LLM-powered skill selection and gap detection.
|
|
216
|
+
# $1: issue_title
|
|
217
|
+
# $2: issue_body
|
|
218
|
+
# $3: issue_labels
|
|
219
|
+
# $4: artifacts_dir (where to write skill-plan.json)
|
|
220
|
+
# $5: intelligence_json (optional — reuse from intelligence_analyze_issue)
|
|
221
|
+
# Returns: 0 on success (skill-plan.json written), 1 on failure (caller should fallback)
|
|
222
|
+
# Requires: _intelligence_call_claude() from sw-intelligence.sh
|
|
223
|
+
skill_analyze_issue() {
|
|
224
|
+
local title="${1:-}" body="${2:-}" labels="${3:-}"
|
|
225
|
+
local artifacts_dir="${4:-${ARTIFACTS_DIR:-.claude/pipeline-artifacts}}"
|
|
226
|
+
local intelligence_json="${5:-}"
|
|
227
|
+
|
|
228
|
+
# Verify we have the LLM call function
|
|
229
|
+
if ! type _intelligence_call_claude >/dev/null 2>&1; then
|
|
230
|
+
return 1
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
# Build the skill catalog
|
|
234
|
+
local catalog
|
|
235
|
+
catalog=$(skill_build_catalog "" "" 2>/dev/null || true)
|
|
236
|
+
[[ -z "$catalog" ]] && return 1
|
|
237
|
+
|
|
238
|
+
# Build memory recommendations
|
|
239
|
+
local memory_context=""
|
|
240
|
+
if type skill_memory_get_recommendations >/dev/null 2>&1; then
|
|
241
|
+
local recs
|
|
242
|
+
recs=$(skill_memory_get_recommendations "backend" "plan" 2>/dev/null || true)
|
|
243
|
+
[[ -n "$recs" ]] && memory_context="Historical skill performance: $recs"
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
# Build the prompt
|
|
247
|
+
local prompt
|
|
248
|
+
prompt="You are a pipeline skill router. Analyze this GitHub issue and select the best skills for each pipeline stage.
|
|
249
|
+
|
|
250
|
+
## Issue
|
|
251
|
+
Title: ${title}
|
|
252
|
+
Labels: ${labels}
|
|
253
|
+
Body:
|
|
254
|
+
${body}
|
|
255
|
+
|
|
256
|
+
## Available Skills
|
|
257
|
+
${catalog}
|
|
258
|
+
|
|
259
|
+
${memory_context:+## Historical Context
|
|
260
|
+
$memory_context
|
|
261
|
+
}
|
|
262
|
+
${intelligence_json:+## Intelligence Analysis
|
|
263
|
+
$intelligence_json
|
|
264
|
+
}
|
|
265
|
+
## Pipeline Stages
|
|
266
|
+
Skills can be assigned to: plan, design, build, review, compound_quality, pr, deploy, validate, monitor
|
|
267
|
+
|
|
268
|
+
## Instructions
|
|
269
|
+
1. Classify the issue type (frontend|backend|api|database|infrastructure|documentation|security|performance|refactor|testing)
|
|
270
|
+
2. Select 1-4 skills per stage from the catalog. Only select skills relevant to that stage.
|
|
271
|
+
3. For each selected skill, write a one-sentence rationale explaining WHY this skill matters for THIS specific issue (not generic advice).
|
|
272
|
+
4. If the issue needs expertise not covered by any existing skill, generate a new skill with focused, actionable content (200-400 words).
|
|
273
|
+
5. Identify specific review focus areas and risk areas for this issue.
|
|
274
|
+
|
|
275
|
+
## Response Format (JSON only, no markdown)
|
|
276
|
+
{
|
|
277
|
+
\"issue_type\": \"frontend\",
|
|
278
|
+
\"confidence\": 0.92,
|
|
279
|
+
\"secondary_domains\": [\"accessibility\", \"real-time\"],
|
|
280
|
+
\"complexity_assessment\": {
|
|
281
|
+
\"score\": 6,
|
|
282
|
+
\"reasoning\": \"Brief explanation\"
|
|
283
|
+
},
|
|
284
|
+
\"skill_plan\": {
|
|
285
|
+
\"plan\": [\"skill-name-1\", \"skill-name-2\"],
|
|
286
|
+
\"design\": [\"skill-name\"],
|
|
287
|
+
\"build\": [\"skill-name\"],
|
|
288
|
+
\"review\": [\"skill-name\"],
|
|
289
|
+
\"compound_quality\": [\"skill-name\"],
|
|
290
|
+
\"pr\": [\"skill-name\"],
|
|
291
|
+
\"deploy\": [\"skill-name\"],
|
|
292
|
+
\"validate\": [],
|
|
293
|
+
\"monitor\": []
|
|
294
|
+
},
|
|
295
|
+
\"skill_rationale\": {
|
|
296
|
+
\"skill-name-1\": \"Why this skill matters for this specific issue\",
|
|
297
|
+
\"skill-name-2\": \"Why this skill matters\"
|
|
298
|
+
},
|
|
299
|
+
\"generated_skills\": [
|
|
300
|
+
{
|
|
301
|
+
\"name\": \"new-skill-name\",
|
|
302
|
+
\"reason\": \"Why no existing skill covers this\",
|
|
303
|
+
\"content\": \"## Skill Title\\n\\nActionable guidance...\"
|
|
304
|
+
}
|
|
305
|
+
],
|
|
306
|
+
\"review_focus\": [\"specific area 1\", \"specific area 2\"],
|
|
307
|
+
\"risk_areas\": [\"specific risk 1\"]
|
|
308
|
+
}"
|
|
309
|
+
|
|
310
|
+
# Call the LLM
|
|
311
|
+
local cache_key="skill_analysis_$(echo "${title}${body}" | md5sum 2>/dev/null | cut -c1-16 || echo "${RANDOM}")"
|
|
312
|
+
local result
|
|
313
|
+
if ! result=$(_intelligence_call_claude "$prompt" "$cache_key" 3600 "haiku"); then
|
|
314
|
+
return 1
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
# Validate the response has required fields
|
|
318
|
+
local valid
|
|
319
|
+
valid=$(echo "$result" | jq 'has("issue_type") and has("skill_plan") and has("skill_rationale")' 2>/dev/null || echo "false")
|
|
320
|
+
if [[ "$valid" != "true" ]]; then
|
|
321
|
+
warn "Skill analysis returned invalid JSON — falling back to static selection"
|
|
322
|
+
return 1
|
|
323
|
+
fi
|
|
324
|
+
|
|
325
|
+
# Write skill-plan.json
|
|
326
|
+
mkdir -p "$artifacts_dir"
|
|
327
|
+
echo "$result" | jq '.' > "$artifacts_dir/skill-plan.json"
|
|
328
|
+
|
|
329
|
+
# Save any generated skills to disk
|
|
330
|
+
local gen_count
|
|
331
|
+
gen_count=$(echo "$result" | jq '.generated_skills | length' 2>/dev/null || echo "0")
|
|
332
|
+
if [[ "$gen_count" -gt 0 ]]; then
|
|
333
|
+
mkdir -p "$GENERATED_SKILLS_DIR"
|
|
334
|
+
local i
|
|
335
|
+
for i in $(seq 0 $((gen_count - 1))); do
|
|
336
|
+
local gen_name gen_content
|
|
337
|
+
gen_name=$(echo "$result" | jq -r ".generated_skills[$i].name" 2>/dev/null)
|
|
338
|
+
gen_content=$(echo "$result" | jq -r ".generated_skills[$i].content" 2>/dev/null)
|
|
339
|
+
if [[ -n "$gen_name" && "$gen_name" != "null" && -n "$gen_content" && "$gen_content" != "null" ]]; then
|
|
340
|
+
# Only write if doesn't already exist (don't overwrite improved versions)
|
|
341
|
+
if [[ ! -f "$GENERATED_SKILLS_DIR/${gen_name}.md" ]]; then
|
|
342
|
+
printf '%b\n' "$gen_content" > "$GENERATED_SKILLS_DIR/${gen_name}.md"
|
|
343
|
+
info "Generated new skill: ${gen_name}"
|
|
344
|
+
fi
|
|
345
|
+
fi
|
|
346
|
+
done
|
|
347
|
+
fi
|
|
348
|
+
|
|
349
|
+
# Update INTELLIGENCE_ISSUE_TYPE from analysis
|
|
350
|
+
local analyzed_type
|
|
351
|
+
analyzed_type=$(echo "$result" | jq -r '.issue_type // empty' 2>/dev/null)
|
|
352
|
+
if [[ -n "$analyzed_type" ]]; then
|
|
353
|
+
export INTELLIGENCE_ISSUE_TYPE="$analyzed_type"
|
|
354
|
+
fi
|
|
355
|
+
|
|
356
|
+
# Update INTELLIGENCE_COMPLEXITY from analysis
|
|
357
|
+
local analyzed_complexity
|
|
358
|
+
analyzed_complexity=$(echo "$result" | jq -r '.complexity_assessment.score // empty' 2>/dev/null)
|
|
359
|
+
if [[ -n "$analyzed_complexity" ]]; then
|
|
360
|
+
export INTELLIGENCE_COMPLEXITY="$analyzed_complexity"
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
return 0
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Step 4: Run tests**
|
|
368
|
+
|
|
369
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | tail -5`
|
|
370
|
+
Expected: ALL TESTS PASSED
|
|
371
|
+
|
|
372
|
+
**Step 5: Commit**
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
git add scripts/lib/skill-registry.sh scripts/test-skill-injection.sh
|
|
376
|
+
git commit -m "feat(skills): add skill_analyze_issue LLM router"
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
### Task 4: Add `skill_load_from_plan()` — Plan-Based Stage Loader
|
|
382
|
+
|
|
383
|
+
**Files:**
|
|
384
|
+
- Modify: `scripts/lib/skill-registry.sh` (append after `skill_analyze_issue`)
|
|
385
|
+
- Test: `scripts/test-skill-injection.sh`
|
|
386
|
+
|
|
387
|
+
**Step 1: Write the failing test**
|
|
388
|
+
|
|
389
|
+
Add Suite 12 to `scripts/test-skill-injection.sh`:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
echo ""
|
|
393
|
+
echo "═══ Suite 12: Plan-Based Skill Loading ═══"
|
|
394
|
+
echo ""
|
|
395
|
+
|
|
396
|
+
local _test_artifacts
|
|
397
|
+
_test_artifacts=$(mktemp -d)
|
|
398
|
+
|
|
399
|
+
# Write a mock skill-plan.json
|
|
400
|
+
cat > "$_test_artifacts/skill-plan.json" << 'PLAN_EOF'
|
|
401
|
+
{
|
|
402
|
+
"issue_type": "frontend",
|
|
403
|
+
"skill_plan": {
|
|
404
|
+
"plan": ["brainstorming", "frontend-design"],
|
|
405
|
+
"build": ["frontend-design"],
|
|
406
|
+
"review": ["two-stage-review"],
|
|
407
|
+
"deploy": []
|
|
408
|
+
},
|
|
409
|
+
"skill_rationale": {
|
|
410
|
+
"brainstorming": "Task decomposition for progress bar feature",
|
|
411
|
+
"frontend-design": "ARIA progressbar role and responsive CSS needed",
|
|
412
|
+
"two-stage-review": "Spec compliance check against plan.md"
|
|
413
|
+
},
|
|
414
|
+
"generated_skills": []
|
|
415
|
+
}
|
|
416
|
+
PLAN_EOF
|
|
417
|
+
|
|
418
|
+
echo " ── Loading skills from plan ──"
|
|
419
|
+
|
|
420
|
+
# Test: load plan stage skills
|
|
421
|
+
local plan_content
|
|
422
|
+
ARTIFACTS_DIR="$_test_artifacts" plan_content=$(skill_load_from_plan "plan" 2>/dev/null || true)
|
|
423
|
+
assert_contains "$plan_content" "brainstorming" "plan stage loads brainstorming skill"
|
|
424
|
+
assert_contains "$plan_content" "frontend-design" "plan stage loads frontend-design skill content"
|
|
425
|
+
assert_contains "$plan_content" "ARIA progressbar" "plan stage includes rationale"
|
|
426
|
+
assert_contains "$plan_content" "Task decomposition" "plan stage includes brainstorming rationale"
|
|
427
|
+
|
|
428
|
+
# Test: load build stage skills
|
|
429
|
+
local build_content
|
|
430
|
+
ARTIFACTS_DIR="$_test_artifacts" build_content=$(skill_load_from_plan "build" 2>/dev/null || true)
|
|
431
|
+
assert_contains "$build_content" "frontend-design" "build stage loads frontend-design"
|
|
432
|
+
assert_not_contains "$build_content" "brainstorming" "build stage does NOT load brainstorming"
|
|
433
|
+
|
|
434
|
+
# Test: empty stage returns empty
|
|
435
|
+
local deploy_content
|
|
436
|
+
ARTIFACTS_DIR="$_test_artifacts" deploy_content=$(skill_load_from_plan "deploy" 2>/dev/null || true)
|
|
437
|
+
assert_eq "" "$(echo "$deploy_content" | tr -d '[:space:]')" "empty stage returns empty"
|
|
438
|
+
|
|
439
|
+
# Test: missing skill-plan.json falls back to skill_select_adaptive
|
|
440
|
+
local _no_plan_dir
|
|
441
|
+
_no_plan_dir=$(mktemp -d)
|
|
442
|
+
local fallback_content
|
|
443
|
+
ARTIFACTS_DIR="$_no_plan_dir" INTELLIGENCE_ISSUE_TYPE="frontend" fallback_content=$(skill_load_from_plan "plan" 2>/dev/null || true)
|
|
444
|
+
assert_contains "$fallback_content" "brainstorming\|frontend\|Socratic" "fallback to adaptive when no plan"
|
|
445
|
+
rm -rf "$_no_plan_dir"
|
|
446
|
+
|
|
447
|
+
# Test: refinements are appended
|
|
448
|
+
mkdir -p "$SKILLS_DIR/generated/_refinements"
|
|
449
|
+
echo "REFINEMENT: Always check stat-bar CSS pattern reuse." > "$SKILLS_DIR/generated/_refinements/frontend-design.patch.md"
|
|
450
|
+
ARTIFACTS_DIR="$_test_artifacts" plan_content=$(skill_load_from_plan "plan" 2>/dev/null || true)
|
|
451
|
+
assert_contains "$plan_content" "REFINEMENT" "refinement patch appended to skill"
|
|
452
|
+
rm -f "$SKILLS_DIR/generated/_refinements/frontend-design.patch.md"
|
|
453
|
+
|
|
454
|
+
rm -rf "$_test_artifacts"
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**Step 2: Run test to verify it fails**
|
|
458
|
+
|
|
459
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | grep -A2 "Suite 12"`
|
|
460
|
+
Expected: FAIL — `skill_load_from_plan: command not found`
|
|
461
|
+
|
|
462
|
+
**Step 3: Write the implementation**
|
|
463
|
+
|
|
464
|
+
Append to `scripts/lib/skill-registry.sh`:
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
# skill_load_from_plan — Load skill content for a stage from skill-plan.json artifact.
|
|
468
|
+
# $1: stage (plan|design|build|review|compound_quality|pr|deploy|validate|monitor)
|
|
469
|
+
# Reads: $ARTIFACTS_DIR/skill-plan.json
|
|
470
|
+
# Returns: combined prompt text with rationale + skill content + refinements.
|
|
471
|
+
# Falls back to skill_select_adaptive() if skill-plan.json is missing.
|
|
472
|
+
skill_load_from_plan() {
|
|
473
|
+
local stage="${1:-plan}"
|
|
474
|
+
local plan_file="${ARTIFACTS_DIR}/skill-plan.json"
|
|
475
|
+
|
|
476
|
+
# Fallback if no plan file
|
|
477
|
+
if [[ ! -f "$plan_file" ]]; then
|
|
478
|
+
if type skill_select_adaptive >/dev/null 2>&1; then
|
|
479
|
+
local _fallback_files _fallback_content
|
|
480
|
+
_fallback_files=$(skill_select_adaptive "${INTELLIGENCE_ISSUE_TYPE:-backend}" "$stage" "${ISSUE_BODY:-}" "${INTELLIGENCE_COMPLEXITY:-5}" 2>/dev/null || true)
|
|
481
|
+
if [[ -n "$_fallback_files" ]]; then
|
|
482
|
+
while IFS= read -r _path; do
|
|
483
|
+
[[ -z "$_path" || ! -f "$_path" ]] && continue
|
|
484
|
+
cat "$_path" 2>/dev/null
|
|
485
|
+
done <<< "$_fallback_files"
|
|
486
|
+
fi
|
|
487
|
+
fi
|
|
488
|
+
return 0
|
|
489
|
+
fi
|
|
490
|
+
|
|
491
|
+
# Extract skill names for this stage
|
|
492
|
+
local skill_names
|
|
493
|
+
skill_names=$(jq -r ".skill_plan.${stage}[]? // empty" "$plan_file" 2>/dev/null)
|
|
494
|
+
[[ -z "$skill_names" ]] && return 0
|
|
495
|
+
|
|
496
|
+
local issue_type
|
|
497
|
+
issue_type=$(jq -r '.issue_type // "unknown"' "$plan_file" 2>/dev/null)
|
|
498
|
+
|
|
499
|
+
# Build rationale header
|
|
500
|
+
local rationale_header=""
|
|
501
|
+
rationale_header="### Why these skills were selected (AI-analyzed):
|
|
502
|
+
"
|
|
503
|
+
while IFS= read -r skill_name; do
|
|
504
|
+
[[ -z "$skill_name" ]] && continue
|
|
505
|
+
local rat
|
|
506
|
+
rat=$(jq -r ".skill_rationale[\"${skill_name}\"] // empty" "$plan_file" 2>/dev/null)
|
|
507
|
+
[[ -n "$rat" ]] && rationale_header="${rationale_header}- **${skill_name}**: ${rat}
|
|
508
|
+
"
|
|
509
|
+
done <<< "$skill_names"
|
|
510
|
+
|
|
511
|
+
# Output rationale header
|
|
512
|
+
echo "$rationale_header"
|
|
513
|
+
|
|
514
|
+
# Load each skill's content
|
|
515
|
+
while IFS= read -r skill_name; do
|
|
516
|
+
[[ -z "$skill_name" ]] && continue
|
|
517
|
+
|
|
518
|
+
local skill_path=""
|
|
519
|
+
# Check curated directory first
|
|
520
|
+
if [[ -f "${SKILLS_DIR}/${skill_name}.md" ]]; then
|
|
521
|
+
skill_path="${SKILLS_DIR}/${skill_name}.md"
|
|
522
|
+
# Then check generated directory
|
|
523
|
+
elif [[ -f "${GENERATED_SKILLS_DIR}/${skill_name}.md" ]]; then
|
|
524
|
+
skill_path="${GENERATED_SKILLS_DIR}/${skill_name}.md"
|
|
525
|
+
fi
|
|
526
|
+
|
|
527
|
+
if [[ -n "$skill_path" ]]; then
|
|
528
|
+
cat "$skill_path" 2>/dev/null
|
|
529
|
+
echo ""
|
|
530
|
+
|
|
531
|
+
# Append refinement if exists
|
|
532
|
+
local refinement_path="${REFINEMENTS_DIR}/${skill_name}.patch.md"
|
|
533
|
+
if [[ -f "$refinement_path" ]]; then
|
|
534
|
+
echo ""
|
|
535
|
+
cat "$refinement_path" 2>/dev/null
|
|
536
|
+
echo ""
|
|
537
|
+
fi
|
|
538
|
+
fi
|
|
539
|
+
done <<< "$skill_names"
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
**Step 4: Run tests**
|
|
544
|
+
|
|
545
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | tail -5`
|
|
546
|
+
Expected: ALL TESTS PASSED
|
|
547
|
+
|
|
548
|
+
**Step 5: Commit**
|
|
549
|
+
|
|
550
|
+
```bash
|
|
551
|
+
git add scripts/lib/skill-registry.sh scripts/test-skill-injection.sh
|
|
552
|
+
git commit -m "feat(skills): add skill_load_from_plan for plan-based stage loading"
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
### Task 5: Add `skill_analyze_outcome()` — Outcome Learning Loop
|
|
558
|
+
|
|
559
|
+
**Files:**
|
|
560
|
+
- Modify: `scripts/lib/skill-registry.sh` (append after `skill_load_from_plan`)
|
|
561
|
+
- Test: `scripts/test-skill-injection.sh`
|
|
562
|
+
|
|
563
|
+
**Step 1: Write the failing test**
|
|
564
|
+
|
|
565
|
+
Add Suite 13 to `scripts/test-skill-injection.sh`:
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
echo ""
|
|
569
|
+
echo "═══ Suite 13: Outcome Learning Loop ═══"
|
|
570
|
+
echo ""
|
|
571
|
+
|
|
572
|
+
local _test_artifacts
|
|
573
|
+
_test_artifacts=$(mktemp -d)
|
|
574
|
+
|
|
575
|
+
# Write a mock skill-plan.json
|
|
576
|
+
cat > "$_test_artifacts/skill-plan.json" << 'PLAN_EOF'
|
|
577
|
+
{
|
|
578
|
+
"issue_type": "frontend",
|
|
579
|
+
"skill_plan": {
|
|
580
|
+
"plan": ["brainstorming", "frontend-design"],
|
|
581
|
+
"build": ["frontend-design"],
|
|
582
|
+
"review": ["two-stage-review"]
|
|
583
|
+
},
|
|
584
|
+
"skill_rationale": {
|
|
585
|
+
"frontend-design": "ARIA progressbar needed"
|
|
586
|
+
},
|
|
587
|
+
"generated_skills": []
|
|
588
|
+
}
|
|
589
|
+
PLAN_EOF
|
|
590
|
+
|
|
591
|
+
echo " ── Outcome JSON parsing ──"
|
|
592
|
+
|
|
593
|
+
# Test: parse a mock outcome response
|
|
594
|
+
local _mock_outcome='{"skill_effectiveness":{"frontend-design":{"verdict":"effective","evidence":"ARIA section in plan","learning":"stat-bar reuse hint followed"}},"refinements":[{"skill":"frontend-design","addition":"For dashboard features, mention existing CSS patterns"}],"generated_skill_verdict":{}}'
|
|
595
|
+
echo "$_mock_outcome" > "$_test_artifacts/skill-outcome.json"
|
|
596
|
+
|
|
597
|
+
# Verify outcome JSON is valid
|
|
598
|
+
assert_true "jq '.' '$_test_artifacts/skill-outcome.json' >/dev/null 2>&1" "outcome JSON is valid"
|
|
599
|
+
|
|
600
|
+
# Verify verdict extraction
|
|
601
|
+
local _verdict
|
|
602
|
+
_verdict=$(jq -r '.skill_effectiveness["frontend-design"].verdict' "$_test_artifacts/skill-outcome.json" 2>/dev/null)
|
|
603
|
+
assert_eq "effective" "$_verdict" "verdict extracted correctly"
|
|
604
|
+
|
|
605
|
+
# Verify refinement extraction
|
|
606
|
+
local _refinement_skill
|
|
607
|
+
_refinement_skill=$(jq -r '.refinements[0].skill' "$_test_artifacts/skill-outcome.json" 2>/dev/null)
|
|
608
|
+
assert_eq "frontend-design" "$_refinement_skill" "refinement skill extracted"
|
|
609
|
+
|
|
610
|
+
echo ""
|
|
611
|
+
echo " ── Refinement file writing ──"
|
|
612
|
+
|
|
613
|
+
# Test: skill_apply_refinements writes patch files
|
|
614
|
+
local _ref_dir="${SKILLS_DIR}/generated/_refinements"
|
|
615
|
+
mkdir -p "$_ref_dir"
|
|
616
|
+
skill_apply_refinements "$_test_artifacts/skill-outcome.json" 2>/dev/null || true
|
|
617
|
+
assert_true "[[ -f '$_ref_dir/frontend-design.patch.md' ]]" "refinement patch file created"
|
|
618
|
+
local _ref_content
|
|
619
|
+
_ref_content=$(cat "$_ref_dir/frontend-design.patch.md" 2>/dev/null || true)
|
|
620
|
+
assert_contains "$_ref_content" "dashboard" "refinement content written"
|
|
621
|
+
rm -f "$_ref_dir/frontend-design.patch.md"
|
|
622
|
+
|
|
623
|
+
echo ""
|
|
624
|
+
echo " ── Generated skill lifecycle ──"
|
|
625
|
+
|
|
626
|
+
# Test: prune verdict deletes generated skill
|
|
627
|
+
mkdir -p "${SKILLS_DIR}/generated"
|
|
628
|
+
echo "## Temp Skill" > "${SKILLS_DIR}/generated/temp-skill.md"
|
|
629
|
+
local _prune_outcome='{"skill_effectiveness":{},"refinements":[],"generated_skill_verdict":{"temp-skill":"prune"}}'
|
|
630
|
+
echo "$_prune_outcome" > "$_test_artifacts/skill-outcome.json"
|
|
631
|
+
skill_apply_lifecycle_verdicts "$_test_artifacts/skill-outcome.json" 2>/dev/null || true
|
|
632
|
+
assert_true "[[ ! -f '${SKILLS_DIR}/generated/temp-skill.md' ]]" "pruned skill deleted"
|
|
633
|
+
|
|
634
|
+
rm -rf "$_test_artifacts"
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
**Step 2: Run test to verify it fails**
|
|
638
|
+
|
|
639
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | grep -A2 "Suite 13"`
|
|
640
|
+
Expected: FAIL — functions not found
|
|
641
|
+
|
|
642
|
+
**Step 3: Write the implementation**
|
|
643
|
+
|
|
644
|
+
Append to `scripts/lib/skill-registry.sh`:
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
# skill_analyze_outcome — LLM-powered outcome analysis and learning.
|
|
648
|
+
# $1: pipeline_result ("success" or "failure")
|
|
649
|
+
# $2: artifacts_dir
|
|
650
|
+
# $3: failed_stage (optional — only for failures)
|
|
651
|
+
# $4: error_context (optional — last N lines of error output)
|
|
652
|
+
# Reads: $artifacts_dir/skill-plan.json, review artifacts
|
|
653
|
+
# Writes: $artifacts_dir/skill-outcome.json, refinement patches, lifecycle verdicts
|
|
654
|
+
# Returns: 0 on success, 1 on failure (falls back to boolean recording)
|
|
655
|
+
skill_analyze_outcome() {
|
|
656
|
+
local pipeline_result="${1:-success}"
|
|
657
|
+
local artifacts_dir="${2:-${ARTIFACTS_DIR:-.claude/pipeline-artifacts}}"
|
|
658
|
+
local failed_stage="${3:-}"
|
|
659
|
+
local error_context="${4:-}"
|
|
660
|
+
|
|
661
|
+
local plan_file="$artifacts_dir/skill-plan.json"
|
|
662
|
+
[[ ! -f "$plan_file" ]] && return 1
|
|
663
|
+
|
|
664
|
+
if ! type _intelligence_call_claude >/dev/null 2>&1; then
|
|
665
|
+
return 1
|
|
666
|
+
fi
|
|
667
|
+
|
|
668
|
+
# Gather context for analysis
|
|
669
|
+
local skill_plan
|
|
670
|
+
skill_plan=$(cat "$plan_file" 2>/dev/null)
|
|
671
|
+
|
|
672
|
+
local review_feedback=""
|
|
673
|
+
[[ -f "$artifacts_dir/review-results.log" ]] && review_feedback=$(tail -50 "$artifacts_dir/review-results.log" 2>/dev/null || true)
|
|
674
|
+
|
|
675
|
+
local prompt
|
|
676
|
+
prompt="You are a pipeline learning system. Analyze the outcome of this pipeline run and provide skill effectiveness feedback.
|
|
677
|
+
|
|
678
|
+
## Skill Plan Used
|
|
679
|
+
${skill_plan}
|
|
680
|
+
|
|
681
|
+
## Pipeline Result: ${pipeline_result}
|
|
682
|
+
${failed_stage:+Failed at stage: ${failed_stage}}
|
|
683
|
+
${error_context:+Error context:
|
|
684
|
+
${error_context}}
|
|
685
|
+
${review_feedback:+## Review Feedback
|
|
686
|
+
${review_feedback}}
|
|
687
|
+
|
|
688
|
+
## Instructions
|
|
689
|
+
1. For each skill in the plan, assess whether it was effective, partially effective, or ineffective.
|
|
690
|
+
2. Provide evidence for each verdict (what in the output shows the skill helped or didn't help).
|
|
691
|
+
3. Extract a one-sentence learning that would improve future use of this skill.
|
|
692
|
+
4. If any skill content could be improved, provide a specific refinement (one sentence to append).
|
|
693
|
+
5. For any generated skills, provide a lifecycle verdict: keep, keep_and_refine, or prune.
|
|
694
|
+
|
|
695
|
+
## Response Format (JSON only, no markdown)
|
|
696
|
+
{
|
|
697
|
+
\"skill_effectiveness\": {
|
|
698
|
+
\"skill-name\": {
|
|
699
|
+
\"verdict\": \"effective|partially_effective|ineffective\",
|
|
700
|
+
\"evidence\": \"What in the output shows this\",
|
|
701
|
+
\"learning\": \"One-sentence takeaway for future runs\"
|
|
702
|
+
}
|
|
703
|
+
},
|
|
704
|
+
\"refinements\": [
|
|
705
|
+
{
|
|
706
|
+
\"skill\": \"skill-name\",
|
|
707
|
+
\"addition\": \"One sentence to append to this skill for future use\"
|
|
708
|
+
}
|
|
709
|
+
],
|
|
710
|
+
\"generated_skill_verdict\": {
|
|
711
|
+
\"generated-skill-name\": \"keep|keep_and_refine|prune\"
|
|
712
|
+
}
|
|
713
|
+
}"
|
|
714
|
+
|
|
715
|
+
local cache_key="skill_outcome_$(echo "${skill_plan}${pipeline_result}" | md5sum 2>/dev/null | cut -c1-16 || echo "${RANDOM}")"
|
|
716
|
+
local result
|
|
717
|
+
if ! result=$(_intelligence_call_claude "$prompt" "$cache_key" 3600 "haiku"); then
|
|
718
|
+
return 1
|
|
719
|
+
fi
|
|
720
|
+
|
|
721
|
+
# Validate response
|
|
722
|
+
local valid
|
|
723
|
+
valid=$(echo "$result" | jq 'has("skill_effectiveness")' 2>/dev/null || echo "false")
|
|
724
|
+
if [[ "$valid" != "true" ]]; then
|
|
725
|
+
return 1
|
|
726
|
+
fi
|
|
727
|
+
|
|
728
|
+
# Write outcome artifact
|
|
729
|
+
echo "$result" | jq '.' > "$artifacts_dir/skill-outcome.json" 2>/dev/null || true
|
|
730
|
+
|
|
731
|
+
# Apply refinements
|
|
732
|
+
skill_apply_refinements "$artifacts_dir/skill-outcome.json" 2>/dev/null || true
|
|
733
|
+
|
|
734
|
+
# Apply lifecycle verdicts for generated skills
|
|
735
|
+
skill_apply_lifecycle_verdicts "$artifacts_dir/skill-outcome.json" 2>/dev/null || true
|
|
736
|
+
|
|
737
|
+
# Record enriched outcomes to skill memory
|
|
738
|
+
local issue_type
|
|
739
|
+
issue_type=$(jq -r '.issue_type // "backend"' "$plan_file" 2>/dev/null)
|
|
740
|
+
|
|
741
|
+
echo "$result" | jq -r '.skill_effectiveness | to_entries[] | "\(.key) \(.value.verdict)"' 2>/dev/null | while read -r skill_name verdict; do
|
|
742
|
+
[[ -z "$skill_name" ]] && continue
|
|
743
|
+
local outcome="success"
|
|
744
|
+
[[ "$verdict" == "ineffective" ]] && outcome="failure"
|
|
745
|
+
[[ "$verdict" == "partially_effective" ]] && outcome="retry"
|
|
746
|
+
|
|
747
|
+
# Record to all stages this skill was used in
|
|
748
|
+
jq -r ".skill_plan | to_entries[] | select(.value | index(\"$skill_name\")) | .key" "$plan_file" 2>/dev/null | while read -r stage; do
|
|
749
|
+
skill_memory_record "$issue_type" "$stage" "$skill_name" "$outcome" "1" 2>/dev/null || true
|
|
750
|
+
done
|
|
751
|
+
done
|
|
752
|
+
|
|
753
|
+
return 0
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
# skill_apply_refinements — Write refinement patches from outcome analysis.
|
|
757
|
+
# $1: path to skill-outcome.json
|
|
758
|
+
skill_apply_refinements() {
|
|
759
|
+
local outcome_file="${1:-}"
|
|
760
|
+
[[ ! -f "$outcome_file" ]] && return 1
|
|
761
|
+
|
|
762
|
+
mkdir -p "$REFINEMENTS_DIR"
|
|
763
|
+
|
|
764
|
+
local ref_count
|
|
765
|
+
ref_count=$(jq '.refinements | length' "$outcome_file" 2>/dev/null || echo "0")
|
|
766
|
+
[[ "$ref_count" -eq 0 ]] && return 0
|
|
767
|
+
|
|
768
|
+
local i
|
|
769
|
+
for i in $(seq 0 $((ref_count - 1))); do
|
|
770
|
+
local skill_name addition
|
|
771
|
+
skill_name=$(jq -r ".refinements[$i].skill" "$outcome_file" 2>/dev/null)
|
|
772
|
+
addition=$(jq -r ".refinements[$i].addition" "$outcome_file" 2>/dev/null)
|
|
773
|
+
if [[ -n "$skill_name" && "$skill_name" != "null" && -n "$addition" && "$addition" != "null" ]]; then
|
|
774
|
+
local patch_file="$REFINEMENTS_DIR/${skill_name}.patch.md"
|
|
775
|
+
# Append (don't overwrite) — accumulate learnings
|
|
776
|
+
echo "" >> "$patch_file"
|
|
777
|
+
echo "### Learned ($(date -u +%Y-%m-%d))" >> "$patch_file"
|
|
778
|
+
echo "$addition" >> "$patch_file"
|
|
779
|
+
fi
|
|
780
|
+
done
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
# skill_apply_lifecycle_verdicts — Apply keep/prune verdicts for generated skills.
|
|
784
|
+
# $1: path to skill-outcome.json
|
|
785
|
+
skill_apply_lifecycle_verdicts() {
|
|
786
|
+
local outcome_file="${1:-}"
|
|
787
|
+
[[ ! -f "$outcome_file" ]] && return 1
|
|
788
|
+
|
|
789
|
+
local verdicts
|
|
790
|
+
verdicts=$(jq -r '.generated_skill_verdict // {} | to_entries[] | "\(.key) \(.value)"' "$outcome_file" 2>/dev/null)
|
|
791
|
+
[[ -z "$verdicts" ]] && return 0
|
|
792
|
+
|
|
793
|
+
while read -r skill_name verdict; do
|
|
794
|
+
[[ -z "$skill_name" ]] && continue
|
|
795
|
+
local gen_path="$GENERATED_SKILLS_DIR/${skill_name}.md"
|
|
796
|
+
|
|
797
|
+
case "$verdict" in
|
|
798
|
+
prune)
|
|
799
|
+
if [[ -f "$gen_path" ]]; then
|
|
800
|
+
rm -f "$gen_path"
|
|
801
|
+
info "Pruned generated skill: ${skill_name}"
|
|
802
|
+
fi
|
|
803
|
+
;;
|
|
804
|
+
keep)
|
|
805
|
+
# No action needed — skill stays
|
|
806
|
+
;;
|
|
807
|
+
keep_and_refine)
|
|
808
|
+
# Refinement handled by skill_apply_refinements
|
|
809
|
+
;;
|
|
810
|
+
esac
|
|
811
|
+
done <<< "$verdicts"
|
|
812
|
+
}
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
**Step 4: Run tests**
|
|
816
|
+
|
|
817
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | tail -5`
|
|
818
|
+
Expected: ALL TESTS PASSED
|
|
819
|
+
|
|
820
|
+
**Step 5: Commit**
|
|
821
|
+
|
|
822
|
+
```bash
|
|
823
|
+
git add scripts/lib/skill-registry.sh scripts/test-skill-injection.sh
|
|
824
|
+
git commit -m "feat(skills): add outcome learning loop with refinements and lifecycle"
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
---
|
|
828
|
+
|
|
829
|
+
### Task 6: Integrate into `stage_intake()` in pipeline-stages.sh
|
|
830
|
+
|
|
831
|
+
**Files:**
|
|
832
|
+
- Modify: `scripts/lib/pipeline-stages.sh` (lines 264-296, add after line 288)
|
|
833
|
+
|
|
834
|
+
**Step 1: Write the integration code**
|
|
835
|
+
|
|
836
|
+
After the existing label grep block (line 288) and before the `log_stage` call (line 290), add:
|
|
837
|
+
|
|
838
|
+
```bash
|
|
839
|
+
# 8. AI-powered skill analysis (replaces static classification when available)
|
|
840
|
+
if type skill_analyze_issue >/dev/null 2>&1; then
|
|
841
|
+
local _intel_json=""
|
|
842
|
+
[[ -f "$ARTIFACTS_DIR/intelligence-analysis.json" ]] && _intel_json=$(cat "$ARTIFACTS_DIR/intelligence-analysis.json" 2>/dev/null || true)
|
|
843
|
+
|
|
844
|
+
if skill_analyze_issue "$GOAL" "${ISSUE_BODY:-}" "${ISSUE_LABELS:-}" "$ARTIFACTS_DIR" "$_intel_json" 2>/dev/null; then
|
|
845
|
+
info "Skill analysis: AI-powered skill plan written to skill-plan.json"
|
|
846
|
+
# INTELLIGENCE_ISSUE_TYPE and INTELLIGENCE_COMPLEXITY are updated by skill_analyze_issue
|
|
847
|
+
else
|
|
848
|
+
info "Skill analysis: LLM unavailable — using label-based classification"
|
|
849
|
+
fi
|
|
850
|
+
fi
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
**Step 2: Verify the intake flow**
|
|
854
|
+
|
|
855
|
+
The label grep (lines 264-288) still runs first as a fallback. If `skill_analyze_issue` succeeds, it overwrites `INTELLIGENCE_ISSUE_TYPE` with the LLM's classification. If it fails, the grep-based value stands.
|
|
856
|
+
|
|
857
|
+
**Step 3: Commit**
|
|
858
|
+
|
|
859
|
+
```bash
|
|
860
|
+
git add scripts/lib/pipeline-stages.sh
|
|
861
|
+
git commit -m "feat(intake): integrate AI-powered skill analysis into intake stage"
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
---
|
|
865
|
+
|
|
866
|
+
### Task 7: Replace `skill_select_adaptive()` calls with `skill_load_from_plan()` in all stages
|
|
867
|
+
|
|
868
|
+
**Files:**
|
|
869
|
+
- Modify: `scripts/lib/pipeline-stages.sh` (plan ~439-469, build ~1309-1326, review ~1762-1789, and similar blocks in design, compound_quality, pr, deploy, validate, monitor)
|
|
870
|
+
|
|
871
|
+
**Step 1: Replace plan stage injection (lines 439-469)**
|
|
872
|
+
|
|
873
|
+
Replace the entire `skill_select_adaptive` / `skill_load_prompts` block with:
|
|
874
|
+
|
|
875
|
+
```bash
|
|
876
|
+
# Inject skill prompts — prefer AI-powered plan, fallback to adaptive
|
|
877
|
+
local _skill_prompts=""
|
|
878
|
+
if type skill_load_from_plan >/dev/null 2>&1; then
|
|
879
|
+
_skill_prompts=$(skill_load_from_plan "plan" 2>/dev/null || true)
|
|
880
|
+
elif type skill_select_adaptive >/dev/null 2>&1; then
|
|
881
|
+
local _skill_files
|
|
882
|
+
_skill_files=$(skill_select_adaptive "${INTELLIGENCE_ISSUE_TYPE:-backend}" "plan" "${ISSUE_BODY:-}" "${INTELLIGENCE_COMPLEXITY:-5}" 2>/dev/null || true)
|
|
883
|
+
if [[ -n "$_skill_files" ]]; then
|
|
884
|
+
_skill_prompts=$(while IFS= read -r _path; do
|
|
885
|
+
[[ -z "$_path" || ! -f "$_path" ]] && continue
|
|
886
|
+
cat "$_path" 2>/dev/null
|
|
887
|
+
done <<< "$_skill_files")
|
|
888
|
+
fi
|
|
889
|
+
elif type skill_load_prompts >/dev/null 2>&1; then
|
|
890
|
+
_skill_prompts=$(skill_load_prompts "${INTELLIGENCE_ISSUE_TYPE:-backend}" "plan" 2>/dev/null || true)
|
|
891
|
+
fi
|
|
892
|
+
if [[ -n "$_skill_prompts" ]]; then
|
|
893
|
+
_skill_prompts=$(prune_context_section "skills" "$_skill_prompts" 8000)
|
|
894
|
+
plan_prompt="${plan_prompt}
|
|
895
|
+
## Skill Guidance (${INTELLIGENCE_ISSUE_TYPE:-backend} issue, AI-selected)
|
|
896
|
+
${_skill_prompts}
|
|
897
|
+
"
|
|
898
|
+
fi
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
**Step 2: Apply same pattern to build, design, review, and remaining stages**
|
|
902
|
+
|
|
903
|
+
Each stage's skill injection block gets the same three-level fallback:
|
|
904
|
+
1. `skill_load_from_plan "$stage"` (AI-powered)
|
|
905
|
+
2. `skill_select_adaptive` (adaptive rules)
|
|
906
|
+
3. `skill_load_prompts` (static registry)
|
|
907
|
+
|
|
908
|
+
The pattern is identical — only the stage name and variable names change.
|
|
909
|
+
|
|
910
|
+
**Step 3: Run existing tests**
|
|
911
|
+
|
|
912
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | tail -5`
|
|
913
|
+
Expected: ALL TESTS PASSED (existing tests use static functions which still work)
|
|
914
|
+
|
|
915
|
+
**Step 4: Commit**
|
|
916
|
+
|
|
917
|
+
```bash
|
|
918
|
+
git add scripts/lib/pipeline-stages.sh
|
|
919
|
+
git commit -m "feat(stages): replace static skill injection with plan-based loading"
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
---
|
|
923
|
+
|
|
924
|
+
### Task 8: Integrate `skill_analyze_outcome()` into pipeline completion
|
|
925
|
+
|
|
926
|
+
**Files:**
|
|
927
|
+
- Modify: `scripts/sw-pipeline.sh` (around lines 2494-2555, the completion handler)
|
|
928
|
+
|
|
929
|
+
**Step 1: Add outcome analysis after the success/failure emit_event blocks**
|
|
930
|
+
|
|
931
|
+
After line 2543 (end of success block) and before line 2545 (start of failure block), add a shared outcome analysis call. Best location: after the entire if/else block (around line 2560):
|
|
932
|
+
|
|
933
|
+
```bash
|
|
934
|
+
# AI-powered outcome learning
|
|
935
|
+
if type skill_analyze_outcome >/dev/null 2>&1; then
|
|
936
|
+
local _failed_stage=""
|
|
937
|
+
local _error_ctx=""
|
|
938
|
+
if [[ "$exit_code" -ne 0 ]]; then
|
|
939
|
+
_failed_stage="${CURRENT_STAGE_ID:-unknown}"
|
|
940
|
+
_error_ctx=$(tail -30 "$ARTIFACTS_DIR/errors-collected.json" 2>/dev/null || true)
|
|
941
|
+
fi
|
|
942
|
+
local _outcome_result="success"
|
|
943
|
+
[[ "$exit_code" -ne 0 ]] && _outcome_result="failure"
|
|
944
|
+
|
|
945
|
+
if skill_analyze_outcome "$_outcome_result" "$ARTIFACTS_DIR" "$_failed_stage" "$_error_ctx" 2>/dev/null; then
|
|
946
|
+
info "Skill outcome analysis complete — learnings recorded"
|
|
947
|
+
fi
|
|
948
|
+
fi
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
**Step 2: Commit**
|
|
952
|
+
|
|
953
|
+
```bash
|
|
954
|
+
git add scripts/sw-pipeline.sh
|
|
955
|
+
git commit -m "feat(pipeline): integrate outcome learning at pipeline completion"
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
---
|
|
959
|
+
|
|
960
|
+
### Task 9: Upgrade `skill_memory_record()` to store rich verdicts
|
|
961
|
+
|
|
962
|
+
**Files:**
|
|
963
|
+
- Modify: `scripts/lib/skill-memory.sh` (lines 30-91)
|
|
964
|
+
|
|
965
|
+
**Step 1: Extend the JSON record structure**
|
|
966
|
+
|
|
967
|
+
Update `skill_memory_record()` to accept optional verdict, evidence, and learning fields:
|
|
968
|
+
|
|
969
|
+
```bash
|
|
970
|
+
# Extended signature:
|
|
971
|
+
# $6: verdict (optional — "effective"|"partially_effective"|"ineffective")
|
|
972
|
+
# $7: evidence (optional — why this verdict)
|
|
973
|
+
# $8: learning (optional — one-sentence takeaway)
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
Update the record JSON construction (line 46-47) to include the new fields:
|
|
977
|
+
|
|
978
|
+
```bash
|
|
979
|
+
local verdict="${6:-}"
|
|
980
|
+
local evidence="${7:-}"
|
|
981
|
+
local learning="${8:-}"
|
|
982
|
+
|
|
983
|
+
local record
|
|
984
|
+
record=$(jq -n \
|
|
985
|
+
--arg it "$issue_type" --arg st "$stage" --arg sk "$skills_used" \
|
|
986
|
+
--arg oc "$outcome" --argjson at "$attempt" --arg ts "$timestamp" \
|
|
987
|
+
--arg vd "$verdict" --arg ev "$evidence" --arg lr "$learning" \
|
|
988
|
+
'{issue_type:$it, stage:$st, skills:$sk, outcome:$oc, attempt:$at, timestamp:$ts, verdict:$vd, evidence:$ev, learning:$lr}')
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
This is backward compatible — existing callers pass 5 args, new fields default to empty strings.
|
|
992
|
+
|
|
993
|
+
**Step 2: Run tests**
|
|
994
|
+
|
|
995
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | tail -5`
|
|
996
|
+
Expected: ALL TESTS PASSED (existing tests pass 5 args, new empty fields are fine)
|
|
997
|
+
|
|
998
|
+
**Step 3: Commit**
|
|
999
|
+
|
|
1000
|
+
```bash
|
|
1001
|
+
git add scripts/lib/skill-memory.sh
|
|
1002
|
+
git commit -m "feat(memory): extend skill_memory_record with verdict/evidence/learning"
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
---
|
|
1006
|
+
|
|
1007
|
+
### Task 10: Final Integration Test
|
|
1008
|
+
|
|
1009
|
+
**Files:**
|
|
1010
|
+
- Modify: `scripts/test-skill-injection.sh` (add Suite 14)
|
|
1011
|
+
|
|
1012
|
+
**Step 1: Write integration tests**
|
|
1013
|
+
|
|
1014
|
+
```bash
|
|
1015
|
+
echo ""
|
|
1016
|
+
echo "═══ Suite 14: Full AI Integration ═══"
|
|
1017
|
+
echo ""
|
|
1018
|
+
|
|
1019
|
+
echo " ── End-to-end skill flow ──"
|
|
1020
|
+
|
|
1021
|
+
# Test: catalog → plan → load → outcome cycle
|
|
1022
|
+
local _e2e_dir
|
|
1023
|
+
_e2e_dir=$(mktemp -d)
|
|
1024
|
+
|
|
1025
|
+
# 1. Build catalog (should include all 17 curated skills)
|
|
1026
|
+
local _catalog
|
|
1027
|
+
_catalog=$(skill_build_catalog 2>/dev/null || true)
|
|
1028
|
+
local _catalog_lines
|
|
1029
|
+
_catalog_lines=$(echo "$_catalog" | grep -c '^-' 2>/dev/null || echo "0")
|
|
1030
|
+
assert_true "[[ $_catalog_lines -ge 17 ]]" "catalog has at least 17 skills (got $_catalog_lines)"
|
|
1031
|
+
|
|
1032
|
+
# 2. Write a skill plan (simulating what skill_analyze_issue would produce)
|
|
1033
|
+
cat > "$_e2e_dir/skill-plan.json" << 'E2E_PLAN'
|
|
1034
|
+
{
|
|
1035
|
+
"issue_type": "api",
|
|
1036
|
+
"confidence": 0.88,
|
|
1037
|
+
"skill_plan": {
|
|
1038
|
+
"plan": ["brainstorming", "api-design"],
|
|
1039
|
+
"build": ["api-design"],
|
|
1040
|
+
"review": ["two-stage-review", "security-audit"]
|
|
1041
|
+
},
|
|
1042
|
+
"skill_rationale": {
|
|
1043
|
+
"api-design": "REST endpoint versioning needed",
|
|
1044
|
+
"brainstorming": "Multiple valid API approaches",
|
|
1045
|
+
"two-stage-review": "Spec compliance for API contract",
|
|
1046
|
+
"security-audit": "Auth endpoint requires security review"
|
|
1047
|
+
},
|
|
1048
|
+
"generated_skills": []
|
|
1049
|
+
}
|
|
1050
|
+
E2E_PLAN
|
|
1051
|
+
|
|
1052
|
+
# 3. Load from plan for each stage
|
|
1053
|
+
local _plan_out _build_out _review_out
|
|
1054
|
+
ARTIFACTS_DIR="$_e2e_dir" _plan_out=$(skill_load_from_plan "plan" 2>/dev/null || true)
|
|
1055
|
+
ARTIFACTS_DIR="$_e2e_dir" _build_out=$(skill_load_from_plan "build" 2>/dev/null || true)
|
|
1056
|
+
ARTIFACTS_DIR="$_e2e_dir" _review_out=$(skill_load_from_plan "review" 2>/dev/null || true)
|
|
1057
|
+
|
|
1058
|
+
assert_contains "$_plan_out" "api-design" "plan loads api-design skill"
|
|
1059
|
+
assert_contains "$_plan_out" "REST endpoint" "plan includes rationale"
|
|
1060
|
+
assert_contains "$_build_out" "api-design" "build loads api-design"
|
|
1061
|
+
assert_not_contains "$_build_out" "brainstorming" "build doesn't load plan-only skills"
|
|
1062
|
+
assert_contains "$_review_out" "two-stage-review" "review loads two-stage-review"
|
|
1063
|
+
assert_contains "$_review_out" "security-audit" "review loads security-audit"
|
|
1064
|
+
|
|
1065
|
+
# 4. Test fallback chain (no plan → adaptive → static)
|
|
1066
|
+
local _no_plan_dir
|
|
1067
|
+
_no_plan_dir=$(mktemp -d)
|
|
1068
|
+
ARTIFACTS_DIR="$_no_plan_dir" INTELLIGENCE_ISSUE_TYPE="api" _plan_out=$(skill_load_from_plan "plan" 2>/dev/null || true)
|
|
1069
|
+
assert_true "[[ -n '$_plan_out' ]]" "fallback produces output when no plan exists"
|
|
1070
|
+
|
|
1071
|
+
# 5. Verify generated skill directory structure
|
|
1072
|
+
assert_true "[[ -d '$SKILLS_DIR/generated' ]]" "generated skills directory exists"
|
|
1073
|
+
assert_true "[[ -d '$SKILLS_DIR/generated/_refinements' ]]" "refinements directory exists"
|
|
1074
|
+
|
|
1075
|
+
rm -rf "$_e2e_dir" "$_no_plan_dir"
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
**Step 2: Run the full suite**
|
|
1079
|
+
|
|
1080
|
+
Run: `bash scripts/test-skill-injection.sh 2>&1 | tail -10`
|
|
1081
|
+
Expected: ALL TESTS PASSED (count should be ~220+)
|
|
1082
|
+
|
|
1083
|
+
**Step 3: Commit**
|
|
1084
|
+
|
|
1085
|
+
```bash
|
|
1086
|
+
git add scripts/test-skill-injection.sh
|
|
1087
|
+
git commit -m "test(skills): add AI-powered skill injection integration tests"
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
---
|
|
1091
|
+
|
|
1092
|
+
## Execution Summary
|
|
1093
|
+
|
|
1094
|
+
| Task | What | Files | Depends On |
|
|
1095
|
+
|---|---|---|---|
|
|
1096
|
+
| 1 | Directory structure | `scripts/skills/generated/` | — |
|
|
1097
|
+
| 2 | `skill_build_catalog()` | `skill-registry.sh` | 1 |
|
|
1098
|
+
| 3 | `skill_analyze_issue()` | `skill-registry.sh` | 2 |
|
|
1099
|
+
| 4 | `skill_load_from_plan()` | `skill-registry.sh` | 2 |
|
|
1100
|
+
| 5 | `skill_analyze_outcome()` | `skill-registry.sh` | 2 |
|
|
1101
|
+
| 6 | Intake integration | `pipeline-stages.sh` | 3 |
|
|
1102
|
+
| 7 | Stage integration | `pipeline-stages.sh` | 4 |
|
|
1103
|
+
| 8 | Completion integration | `sw-pipeline.sh` | 5 |
|
|
1104
|
+
| 9 | Rich memory records | `skill-memory.sh` | 5 |
|
|
1105
|
+
| 10 | Integration tests | `test-skill-injection.sh` | all |
|
|
1106
|
+
|
|
1107
|
+
**Parallelizable:** Tasks 3, 4, 5 are independent (all append to skill-registry.sh but different functions). Tasks 6, 7, 8 are independent (different files). Task 9 is independent.
|
|
1108
|
+
|
|
1109
|
+
**Critical path:** 1 → 2 → (3 + 4 + 5) → (6 + 7 + 8 + 9) → 10
|