aw-ecc 1.4.23 → 1.4.31
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-plugin/plugin.json +1 -1
- package/.cursor/INSTALL.md +9 -0
- package/.cursor/hooks/adapter.js +34 -3
- package/.cursor/hooks/aw-phase-definitions.js +11 -0
- package/.cursor/hooks/before-submit-prompt.sh +17 -0
- package/.cursor/hooks/session-start.sh +36 -0
- package/.cursor/hooks/shared/aw-phase-definitions.js +1 -19
- package/.cursor/hooks/shared/aw-phase-runner.js +38 -2
- package/.cursor/hooks/shared/user-prompt-submit.sh +40 -60
- package/.cursor/hooks.json +15 -15
- package/.cursor/rules/common-aw-routing.md +43 -0
- package/.cursor/skills/api-and-interface-design/SKILL.md +75 -0
- package/.cursor/skills/aw-brainstorm/SKILL.md +115 -0
- package/.cursor/skills/aw-build/SKILL.md +152 -0
- package/.cursor/skills/aw-build/evals/build-stage-cases.json +28 -0
- package/.cursor/skills/aw-debug/SKILL.md +49 -0
- package/.cursor/skills/aw-deploy/SKILL.md +101 -0
- package/.cursor/skills/aw-deploy/evals/deploy-stage-cases.json +32 -0
- package/.cursor/skills/aw-execute/SKILL.md +47 -0
- package/.cursor/skills/aw-execute/references/mode-code.md +47 -0
- package/.cursor/skills/aw-execute/references/mode-docs.md +28 -0
- package/.cursor/skills/aw-execute/references/mode-infra.md +44 -0
- package/.cursor/skills/aw-execute/references/mode-migration.md +58 -0
- package/.cursor/skills/aw-execute/references/worker-implementer.md +26 -0
- package/.cursor/skills/aw-execute/references/worker-parallel-worker.md +23 -0
- package/.cursor/skills/aw-execute/references/worker-quality-reviewer.md +23 -0
- package/.cursor/skills/aw-execute/references/worker-spec-reviewer.md +23 -0
- package/.cursor/skills/aw-execute/scripts/build-worker-bundle.js +229 -0
- package/.cursor/skills/aw-finish/SKILL.md +111 -0
- package/.cursor/skills/aw-investigate/SKILL.md +109 -0
- package/.cursor/skills/aw-plan/SKILL.md +368 -0
- package/.cursor/skills/aw-prepare/SKILL.md +118 -0
- package/.cursor/skills/aw-review/SKILL.md +118 -0
- package/.cursor/skills/aw-ship/SKILL.md +115 -0
- package/.cursor/skills/aw-spec/SKILL.md +104 -0
- package/.cursor/skills/aw-tasks/SKILL.md +138 -0
- package/.cursor/skills/aw-test/SKILL.md +118 -0
- package/.cursor/skills/aw-verify/SKILL.md +51 -0
- package/.cursor/skills/aw-yolo/SKILL.md +111 -0
- package/.cursor/skills/browser-testing-with-devtools/SKILL.md +81 -0
- package/.cursor/skills/ci-cd-and-automation/SKILL.md +71 -0
- package/.cursor/skills/code-simplification/SKILL.md +74 -0
- package/.cursor/skills/context-engineering/SKILL.md +74 -0
- package/.cursor/skills/deprecation-and-migration/SKILL.md +75 -0
- package/.cursor/skills/documentation-and-adrs/SKILL.md +75 -0
- package/.cursor/skills/frontend-ui-engineering/SKILL.md +68 -0
- package/.cursor/skills/git-workflow-and-versioning/SKILL.md +75 -0
- package/.cursor/skills/idea-refine/SKILL.md +84 -0
- package/.cursor/skills/incremental-implementation/SKILL.md +75 -0
- package/.cursor/skills/performance-optimization/SKILL.md +77 -0
- package/.cursor/skills/security-and-hardening/SKILL.md +70 -0
- package/.cursor/skills/using-aw-skills/SKILL.md +290 -0
- package/.cursor/skills/using-aw-skills/evals/skill-trigger-cases.tsv +25 -0
- package/.cursor/skills/using-aw-skills/evals/test-skill-triggers.sh +171 -0
- package/.cursor/skills/using-aw-skills/hooks/hooks.json +9 -0
- package/.cursor/skills/using-aw-skills/hooks/session-start.sh +67 -0
- package/.cursor/skills/using-platform-skills/SKILL.md +163 -0
- package/.cursor/skills/using-platform-skills/evals/platform-selection-cases.json +52 -0
- package/.opencode/package.json +1 -1
- package/package.json +5 -1
- package/scripts/cursor-aw-home/hooks.json +15 -15
- package/scripts/cursor-aw-hooks/adapter.js +34 -3
- package/scripts/cursor-aw-hooks/aw-phase-definitions.js +11 -0
- package/scripts/cursor-aw-hooks/before-submit-prompt.sh +17 -0
- package/scripts/cursor-aw-hooks/session-start.sh +36 -0
- package/scripts/hooks/session-start-rules-context.sh +8 -1
- package/scripts/hooks/shared/aw-phase-definitions.js +1 -19
- package/scripts/hooks/shared/aw-phase-runner.js +38 -2
- package/scripts/hooks/shared/user-prompt-submit.sh +40 -60
- package/scripts/lib/cursor-aw-hook-files.js +2 -0
- package/scripts/lib/cursor-hook-config.js +47 -15
- package/scripts/lib/install-executor.js +7 -0
- package/scripts/lib/install-targets/cursor-project.js +7 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test harness for verifying SDLC skill auto-triggering across AI CLIs.
|
|
3
|
+
# Public AW surface under test: /aw:plan, /aw:build, /aw:investigate,
|
|
4
|
+
# /aw:test, /aw:review, /aw:deploy, and /aw:ship.
|
|
5
|
+
|
|
6
|
+
set -uo pipefail
|
|
7
|
+
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
RESULTS_DIR="$SCRIPT_DIR/results"
|
|
10
|
+
CASES_FILE="$SCRIPT_DIR/skill-trigger-cases.tsv"
|
|
11
|
+
DEFAULT_WORKSPACE_DIR="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
12
|
+
WORKSPACE_DIR="${WORKSPACE_DIR:-$DEFAULT_WORKSPACE_DIR}"
|
|
13
|
+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
14
|
+
MAX_TURNS=3
|
|
15
|
+
QUICK_MODE=false
|
|
16
|
+
|
|
17
|
+
mkdir -p "$RESULTS_DIR"
|
|
18
|
+
|
|
19
|
+
RED='\033[0;31m'
|
|
20
|
+
GREEN='\033[0;32m'
|
|
21
|
+
YELLOW='\033[0;33m'
|
|
22
|
+
BLUE='\033[0;34m'
|
|
23
|
+
NC='\033[0m'
|
|
24
|
+
|
|
25
|
+
run_with_timeout() {
|
|
26
|
+
local secs="$1"
|
|
27
|
+
shift
|
|
28
|
+
if command -v gtimeout &>/dev/null; then
|
|
29
|
+
gtimeout "$secs" "$@"
|
|
30
|
+
else
|
|
31
|
+
perl -e "
|
|
32
|
+
alarm $secs;
|
|
33
|
+
\$SIG{ALRM} = sub { kill 9, \$pid; exit 124 };
|
|
34
|
+
\$pid = fork;
|
|
35
|
+
if (\$pid == 0) { exec @ARGV; }
|
|
36
|
+
waitpid \$pid, 0;
|
|
37
|
+
exit \$? >> 8;
|
|
38
|
+
" "$@"
|
|
39
|
+
fi
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
load_test_cases() {
|
|
43
|
+
local mode_filter="$1"
|
|
44
|
+
local -n out_cases="$2"
|
|
45
|
+
|
|
46
|
+
if [ ! -f "$CASES_FILE" ]; then
|
|
47
|
+
echo "Missing cases file: $CASES_FILE" >&2
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
while IFS=$'\t' read -r mode prompt expected_pattern description expected_route primary_skill supporting_skills; do
|
|
52
|
+
if [ -z "${mode:-}" ] || [[ "$mode" == \#* ]]; then
|
|
53
|
+
continue
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if [ "$mode_filter" = "quick" ] && [ "$mode" != "quick" ]; then
|
|
57
|
+
continue
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
out_cases+=("$prompt|$expected_pattern|$description|$expected_route|$primary_skill|$supporting_skills")
|
|
61
|
+
done < "$CASES_FILE"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
run_prompt() {
|
|
65
|
+
local cli="$1"
|
|
66
|
+
local prompt="$2"
|
|
67
|
+
local output_file="$3"
|
|
68
|
+
|
|
69
|
+
cd "$WORKSPACE_DIR"
|
|
70
|
+
|
|
71
|
+
case "$cli" in
|
|
72
|
+
claude)
|
|
73
|
+
run_with_timeout 120 claude -p "$prompt" \
|
|
74
|
+
--output-format text \
|
|
75
|
+
--max-turns "$MAX_TURNS" \
|
|
76
|
+
> "$output_file" 2>&1 || true
|
|
77
|
+
;;
|
|
78
|
+
codex)
|
|
79
|
+
run_with_timeout 120 codex exec --skip-git-repo-check --sandbox read-only "$prompt" \
|
|
80
|
+
> "$output_file" 2>&1 || true
|
|
81
|
+
;;
|
|
82
|
+
cursor)
|
|
83
|
+
run_with_timeout 120 cursor -p "$prompt" > "$output_file" 2>&1 || true
|
|
84
|
+
;;
|
|
85
|
+
opencode)
|
|
86
|
+
run_with_timeout 120 opencode -p "$prompt" > "$output_file" 2>&1 || true
|
|
87
|
+
;;
|
|
88
|
+
*)
|
|
89
|
+
echo "Unknown CLI: $cli" > "$output_file"
|
|
90
|
+
return 1
|
|
91
|
+
;;
|
|
92
|
+
esac
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
check_skill_triggered() {
|
|
96
|
+
local output_file="$1"
|
|
97
|
+
local expected_pattern="$2"
|
|
98
|
+
|
|
99
|
+
if [ ! -f "$output_file" ] || [ ! -s "$output_file" ]; then
|
|
100
|
+
echo "no_output"
|
|
101
|
+
return
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
local content
|
|
105
|
+
content=$(cat "$output_file")
|
|
106
|
+
|
|
107
|
+
local grep_pattern="${expected_pattern//;/|}"
|
|
108
|
+
if echo "$content" | grep -qiE "$grep_pattern"; then
|
|
109
|
+
echo "triggered"
|
|
110
|
+
return
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
if echo "$content" | grep -qiE "using.*skill|invoking.*skill|Skill\(skill:|I'm using the"; then
|
|
114
|
+
echo "skill_invoked_different"
|
|
115
|
+
return
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
if echo "$content" | grep -qi "max turns"; then
|
|
119
|
+
echo "max_turns_hit"
|
|
120
|
+
return
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
if [ ${#content} -gt 50 ]; then
|
|
124
|
+
echo "responded_no_skill"
|
|
125
|
+
return
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
echo "no_response"
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
run_test() {
|
|
132
|
+
local cli="$1"
|
|
133
|
+
local prompt="$2"
|
|
134
|
+
local expected_pattern="$3"
|
|
135
|
+
local description="$4"
|
|
136
|
+
local test_id="$5"
|
|
137
|
+
|
|
138
|
+
local output_file="$RESULTS_DIR/${cli}_${test_id}_${TIMESTAMP}.txt"
|
|
139
|
+
|
|
140
|
+
printf " [%d] %-45s " "$test_id" "$description"
|
|
141
|
+
|
|
142
|
+
run_prompt "$cli" "$prompt" "$output_file"
|
|
143
|
+
|
|
144
|
+
local result
|
|
145
|
+
result=$(check_skill_triggered "$output_file" "$expected_pattern")
|
|
146
|
+
|
|
147
|
+
case "$result" in
|
|
148
|
+
triggered)
|
|
149
|
+
printf "${GREEN}PASS${NC}\n"
|
|
150
|
+
return 0
|
|
151
|
+
;;
|
|
152
|
+
skill_invoked_different)
|
|
153
|
+
printf "${YELLOW}PARTIAL${NC} — different skill invoked\n"
|
|
154
|
+
return 0
|
|
155
|
+
;;
|
|
156
|
+
max_turns_hit)
|
|
157
|
+
printf "${YELLOW}PARTIAL${NC} — hit max turns (tried to use tools)\n"
|
|
158
|
+
return 0
|
|
159
|
+
;;
|
|
160
|
+
responded_no_skill)
|
|
161
|
+
printf "${RED}FAIL${NC} — responded without skill\n"
|
|
162
|
+
head -c 100 "$output_file" 2>/dev/null | tr '\n' ' '
|
|
163
|
+
echo ""
|
|
164
|
+
return 1
|
|
165
|
+
;;
|
|
166
|
+
no_response|no_output)
|
|
167
|
+
printf "${RED}FAIL${NC} — no output\n"
|
|
168
|
+
return 1
|
|
169
|
+
;;
|
|
170
|
+
esac
|
|
171
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
LOCAL_ROOT=""
|
|
6
|
+
SEARCH_ROOT="$SCRIPT_DIR"
|
|
7
|
+
while [[ "$SEARCH_ROOT" != "/" ]]; do
|
|
8
|
+
if [[ -f "$SEARCH_ROOT/skills/using-aw-skills/SKILL.md" ]]; then
|
|
9
|
+
LOCAL_ROOT="$SEARCH_ROOT"
|
|
10
|
+
break
|
|
11
|
+
fi
|
|
12
|
+
SEARCH_ROOT="$(dirname "$SEARCH_ROOT")"
|
|
13
|
+
done
|
|
14
|
+
|
|
15
|
+
AW_REGISTRY_ROOT=""
|
|
16
|
+
SEARCH_ROOT="$SCRIPT_DIR"
|
|
17
|
+
while [[ "$SEARCH_ROOT" != "/" ]]; do
|
|
18
|
+
if [[ -d "$SEARCH_ROOT/.aw_registry" ]]; then
|
|
19
|
+
AW_REGISTRY_ROOT="$SEARCH_ROOT/.aw_registry"
|
|
20
|
+
break
|
|
21
|
+
fi
|
|
22
|
+
if [[ "$(basename "$SEARCH_ROOT")" == ".aw_registry" ]]; then
|
|
23
|
+
AW_REGISTRY_ROOT="$SEARCH_ROOT"
|
|
24
|
+
break
|
|
25
|
+
fi
|
|
26
|
+
SEARCH_ROOT="$(dirname "$SEARCH_ROOT")"
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
if [[ -z "$LOCAL_ROOT" && -z "$AW_REGISTRY_ROOT" ]]; then
|
|
30
|
+
echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "additionalContext": "WARNING: .aw_registry not found. AW skills unavailable."}}'
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
CONTEXT="# AW Session Context
|
|
35
|
+
|
|
36
|
+
## First Response Rule
|
|
37
|
+
Before any substantive response, select the smallest correct AW skill stack from the repo-local router.
|
|
38
|
+
Honor an explicit AW command and its mapped stage skill first.
|
|
39
|
+
Otherwise choose the needed process skill, primary stage skill, and matching route by intent, then load deeper domain skills.
|
|
40
|
+
Do not start with generic implementation, review, or deploy advice before skill selection.
|
|
41
|
+
|
|
42
|
+
## Primary Routes
|
|
43
|
+
- /aw:plan -> ideas, specs, task breakdown, architecture direction
|
|
44
|
+
- /aw:build -> approved implementation work
|
|
45
|
+
- /aw:investigate -> bugs, alerts, or unclear runtime failures
|
|
46
|
+
- /aw:test -> QA proof and regression evidence
|
|
47
|
+
- /aw:review -> findings, risk review, and readiness
|
|
48
|
+
- /aw:deploy -> rollout or release execution
|
|
49
|
+
- /aw:ship -> release closeout and final handoff
|
|
50
|
+
|
|
51
|
+
## Compatibility Routes
|
|
52
|
+
- /aw:execute -> compatibility route; resolve to /aw:build
|
|
53
|
+
- /aw:verify -> compatibility route; resolve to /aw:test or /aw:review
|
|
54
|
+
|
|
55
|
+
## Router Source
|
|
56
|
+
Use skills/using-aw-skills/SKILL.md as the repo-local router.
|
|
57
|
+
Load domain, platform, and craft skills only after the smallest correct AW route is selected."
|
|
58
|
+
|
|
59
|
+
# --- Output in Claude Code hookSpecificOutput format ---
|
|
60
|
+
# Escape for JSON: newlines, quotes, backslashes
|
|
61
|
+
JSON_CONTEXT=$(printf '%s' "$CONTEXT" | python3 -c '
|
|
62
|
+
import sys, json
|
|
63
|
+
content = sys.stdin.read()
|
|
64
|
+
print(json.dumps(content))
|
|
65
|
+
' 2>/dev/null || printf '%s' "$CONTEXT" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g' | awk '{printf "%s\\n", $0}')
|
|
66
|
+
|
|
67
|
+
echo "{\"hookSpecificOutput\": {\"hookEventName\": \"SessionStart\", \"additionalContext\": ${JSON_CONTEXT}}}"
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: using-platform-skills
|
|
3
|
+
description: Select the smallest correct GHL platform skill stack after the AW stage is known. Use when the task touches backend services, frontend MFAs, data systems, infra, review, test, or product-specific platform context.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Using Platform Skills
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
This is the second-hop router for GHL-specific work.
|
|
11
|
+
Use it after `using-aw-skills` has already selected the primary AW stage.
|
|
12
|
+
|
|
13
|
+
Its job is to:
|
|
14
|
+
|
|
15
|
+
- identify the touched GHL domain
|
|
16
|
+
- pick the smallest correct platform family
|
|
17
|
+
- choose the first supporting platform skills for the selected stage
|
|
18
|
+
- avoid loading every platform playbook by default
|
|
19
|
+
|
|
20
|
+
## When to Use
|
|
21
|
+
|
|
22
|
+
- the primary AW stage is already known
|
|
23
|
+
- the task touches a real GHL backend, worker, frontend, data, infra, test, review, or product surface
|
|
24
|
+
- platform-specific conventions materially change how the stage should be done
|
|
25
|
+
|
|
26
|
+
Do not use:
|
|
27
|
+
|
|
28
|
+
- before the primary AW stage is selected
|
|
29
|
+
- for generic non-GHL work
|
|
30
|
+
- when no platform family materially changes the implementation, test, review, or deploy path
|
|
31
|
+
|
|
32
|
+
## Skill Discovery
|
|
33
|
+
|
|
34
|
+
After the AW stage is selected, choose the platform family:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
Primary AW stage selected
|
|
38
|
+
│
|
|
39
|
+
├── Backend service or worker? ───────────────→ platform-services:*
|
|
40
|
+
├── Frontend MFA or design-system work? ─────→ platform-frontend:* + platform-design:*
|
|
41
|
+
├── Data store, analytics, search, cache,
|
|
42
|
+
│ or data migration work? ──────────────────────→ platform-data:*
|
|
43
|
+
├── Infra or deploy path work? ──────────────→ platform-infra:*
|
|
44
|
+
├── Test system or QA governance work? ──────→ platform-sdet:*
|
|
45
|
+
├── Formal review or readiness work? ────────→ platform-review:*
|
|
46
|
+
└── Product-context ambiguity? ──────────────→ platform-product:*
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then choose the smallest supporting skills for the current stage.
|
|
50
|
+
|
|
51
|
+
## Workflow
|
|
52
|
+
|
|
53
|
+
1. Confirm the AW stage first.
|
|
54
|
+
Do not pick platform skills until the primary route is clear.
|
|
55
|
+
2. Identify the touched surface.
|
|
56
|
+
Backend, frontend, data, infra, review, test, or product context.
|
|
57
|
+
3. Choose the first platform family.
|
|
58
|
+
Start from the family that most directly changes the current stage behavior.
|
|
59
|
+
4. Add only the first supporting platform skills.
|
|
60
|
+
Prefer the smallest stack that changes implementation quality, test evidence, review depth, or release safety.
|
|
61
|
+
Do not duplicate planning-process skills already owned by `aw-plan`, `aw-spec`, `aw-tasks`, or Addy-style planning helpers.
|
|
62
|
+
5. Add craft skills only if they sharpen the same stage.
|
|
63
|
+
Do not let craft skills replace platform families or vice versa.
|
|
64
|
+
|
|
65
|
+
## Stage-to-Platform Matrix
|
|
66
|
+
|
|
67
|
+
### Backend services and workers
|
|
68
|
+
|
|
69
|
+
| AW stage | First platform skills to load |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `aw-plan` | `platform-services:development` |
|
|
72
|
+
| `aw-build` | `platform-services:development` |
|
|
73
|
+
| `aw-investigate` | `platform-infra:grafana` |
|
|
74
|
+
| `aw-test` | `platform-sdet:quality-gates` |
|
|
75
|
+
| `aw-review` | `platform-review:code-review-pr`, `platform-sdet:quality-gates` |
|
|
76
|
+
| `aw-deploy` | `platform-infra:staging-deploy`, `platform-infra:deployment-strategies`, `platform-infra:production-readiness` |
|
|
77
|
+
| `aw-ship` | `platform-review:code-review-pr`, `platform-infra:staging-deploy`, `platform-infra:production-readiness` |
|
|
78
|
+
|
|
79
|
+
### Frontend MFAs and design-system work
|
|
80
|
+
|
|
81
|
+
| AW stage | First platform skills to load |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `aw-plan` | `platform-design:system`, `platform-frontend:vue-development` |
|
|
84
|
+
| `aw-build` | `platform-frontend:vue-development`, `highrise-ui-governance`, `quality-gate-coder` |
|
|
85
|
+
| `aw-investigate` | `platform-infra:grafana` when runtime signals matter; otherwise use the smallest relevant frontend family |
|
|
86
|
+
| `aw-test` | `platform-frontend:a11y-review`, `platform-sdet:quality-gates` |
|
|
87
|
+
| `aw-review` | `platform-review:code-review-pr`, `platform-design:review`, `platform-frontend:a11y-review`, `platform-sdet:quality-gates` |
|
|
88
|
+
| `aw-deploy` | `deploy-versioned-mfa`, `platform-infra:staging-deploy`, `platform-infra:production-readiness` |
|
|
89
|
+
| `aw-ship` | `deploy-versioned-mfa`, `platform-infra:staging-deploy`, `platform-infra:production-readiness` |
|
|
90
|
+
|
|
91
|
+
### Data, migration, and storage work
|
|
92
|
+
|
|
93
|
+
`platform-data:*` is the family for the data team surface.
|
|
94
|
+
Use it for:
|
|
95
|
+
|
|
96
|
+
- transactional databases
|
|
97
|
+
- document stores
|
|
98
|
+
- analytical databases and warehouses
|
|
99
|
+
- search indexes
|
|
100
|
+
- realtime data stores
|
|
101
|
+
- cache and key-value systems
|
|
102
|
+
- migration and cross-database movement
|
|
103
|
+
|
|
104
|
+
Current concrete data families include:
|
|
105
|
+
|
|
106
|
+
- `platform-data:cloudsql-clickhouse` for CloudSQL and ClickHouse
|
|
107
|
+
- `platform-data:mongodb-patterns`
|
|
108
|
+
- `platform-data:firestore-patterns`
|
|
109
|
+
- `platform-data:redis-patterns`
|
|
110
|
+
- `platform-data:elasticsearch-patterns`
|
|
111
|
+
- `platform-data:migration-patterns`
|
|
112
|
+
|
|
113
|
+
Keep infra ownership separate:
|
|
114
|
+
|
|
115
|
+
- provisioning clusters, secrets, Helm, Terraform, Jenkins, or deploy topology -> `platform-infra:*`
|
|
116
|
+
- modeling schemas, indexes, migrations, sync workers, queries, or search mappings -> `platform-data:*`
|
|
117
|
+
|
|
118
|
+
| AW stage | First platform skills to load |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `aw-plan` | `platform-data:migration-patterns` or the narrow storage family |
|
|
121
|
+
| `aw-build` | `platform-data:migration-patterns`, `platform-data:mongodb-patterns`, `platform-data:redis-patterns`, `platform-data:elasticsearch-patterns`, `platform-data:cloudsql-clickhouse`, or another narrow data family |
|
|
122
|
+
| `aw-test` | `platform-sdet:quality-gates` |
|
|
123
|
+
| `aw-review` | `platform-review:code-review-pr` plus the narrow data family when contracts or safety need checking |
|
|
124
|
+
| `aw-deploy` / `aw-ship` | `platform-infra:deployment-strategies`, plus the narrow data family when rollout safety depends on it |
|
|
125
|
+
|
|
126
|
+
### Infra, release, and operational work
|
|
127
|
+
|
|
128
|
+
| AW stage | First platform skills to load |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `aw-plan` | `platform-infra:deployment-strategies` |
|
|
131
|
+
| `aw-build` | `platform-infra:jenkins-pipelines`, `platform-infra:kubernetes-workloads`, `platform-infra:terraform-iac`, or another narrow infra family |
|
|
132
|
+
| `aw-investigate` | `platform-infra:grafana`, `platform-infra:log-analysis` |
|
|
133
|
+
| `aw-test` | `platform-sdet:quality-gates` |
|
|
134
|
+
| `aw-review` | `platform-review:code-review-pr`, `platform-infra:production-readiness` |
|
|
135
|
+
| `aw-deploy` | `platform-infra:staging-deploy`, `platform-infra:deployment-strategies`, `platform-infra:production-readiness` |
|
|
136
|
+
| `aw-ship` | `platform-infra:deployment-strategies`, `platform-infra:production-readiness` |
|
|
137
|
+
|
|
138
|
+
## Common Rationalizations
|
|
139
|
+
|
|
140
|
+
| Rationalization | Reality |
|
|
141
|
+
|---|---|
|
|
142
|
+
| "The AW stage is enough; platform rules can be implied." | Platform families encode real org behavior and should be selected explicitly when they matter. |
|
|
143
|
+
| "I'll just load everything platform-related to be safe." | Flooding the session makes routing less clear and increases noise. |
|
|
144
|
+
| "Frontend only needs frontend skills." | Real frontend work often also needs design, accessibility, quality-gate, or deploy support. |
|
|
145
|
+
| "Review and test don't need platform families." | Review depth and test evidence are some of the most platform-specific parts of the workflow. |
|
|
146
|
+
|
|
147
|
+
## Red Flags
|
|
148
|
+
|
|
149
|
+
- platform skills are chosen before the AW stage is known
|
|
150
|
+
- every task loads multiple platform families with no clear reason
|
|
151
|
+
- frontend tasks skip `platform-design:*` or accessibility support when UI quality matters
|
|
152
|
+
- backend tasks skip platform service conventions and jump straight to generic coding
|
|
153
|
+
- deploy and ship work proceed without platform infra or readiness support
|
|
154
|
+
|
|
155
|
+
## Verification
|
|
156
|
+
|
|
157
|
+
Before leaving platform selection, confirm:
|
|
158
|
+
|
|
159
|
+
- [ ] the AW stage was chosen first
|
|
160
|
+
- [ ] exactly one primary platform family was selected first
|
|
161
|
+
- [ ] the first supporting platform skills match the current AW stage
|
|
162
|
+
- [ ] only the smallest useful platform stack was loaded
|
|
163
|
+
- [ ] craft skills complement the platform stack instead of replacing it
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cases": [
|
|
3
|
+
{
|
|
4
|
+
"id": "backend-plan",
|
|
5
|
+
"prompt": "Create the implementation spec for the approved Communities moderation API contract.",
|
|
6
|
+
"awStage": "aw-plan",
|
|
7
|
+
"surface": "backend-service",
|
|
8
|
+
"expectedPlatformFamilies": ["platform-services:*"],
|
|
9
|
+
"expectedSupportingSkills": ["platform-services:development"]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "frontend-plan",
|
|
13
|
+
"prompt": "Create the implementation spec for the approved Communities feed MFA change.",
|
|
14
|
+
"awStage": "aw-plan",
|
|
15
|
+
"surface": "frontend-mfa",
|
|
16
|
+
"expectedPlatformFamilies": ["platform-frontend:*", "platform-design:*"],
|
|
17
|
+
"expectedSupportingSkills": ["platform-design:system", "platform-frontend:vue-development"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "backend-investigate",
|
|
21
|
+
"prompt": "Investigate this Communities moderation worker retry failure before patching.",
|
|
22
|
+
"awStage": "aw-investigate",
|
|
23
|
+
"surface": "backend-worker",
|
|
24
|
+
"expectedPlatformFamilies": ["platform-infra:*"],
|
|
25
|
+
"expectedSupportingSkills": ["platform-infra:grafana"]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "frontend-test",
|
|
29
|
+
"prompt": "Test the approved Communities feed MFA UI change for responsive and accessibility regressions.",
|
|
30
|
+
"awStage": "aw-test",
|
|
31
|
+
"surface": "frontend-mfa",
|
|
32
|
+
"expectedPlatformFamilies": ["platform-frontend:*", "platform-sdet:*"],
|
|
33
|
+
"expectedSupportingSkills": ["platform-frontend:a11y-review", "platform-sdet:quality-gates"]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "service-deploy",
|
|
37
|
+
"prompt": "Deploy this verified Communities moderation API service to staging.",
|
|
38
|
+
"awStage": "aw-deploy",
|
|
39
|
+
"surface": "backend-service",
|
|
40
|
+
"expectedPlatformFamilies": ["platform-infra:*"],
|
|
41
|
+
"expectedSupportingSkills": ["platform-infra:staging-deploy", "platform-infra:deployment-strategies", "platform-infra:production-readiness"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "data-build",
|
|
45
|
+
"prompt": "Add the new analytics projection and search mapping for this reporting workflow.",
|
|
46
|
+
"awStage": "aw-build",
|
|
47
|
+
"surface": "data-analytics-search",
|
|
48
|
+
"expectedPlatformFamilies": ["platform-data:*"],
|
|
49
|
+
"expectedSupportingSkills": ["platform-data:cloudsql-clickhouse", "platform-data:elasticsearch-patterns"]
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
package/.opencode/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aw-ecc",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.31",
|
|
4
4
|
"description": "GoHighLevel Agentic Workspace Engine — forked from Everything Claude Code (ecc-universal)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -110,6 +110,10 @@
|
|
|
110
110
|
"orchestrate:status": "node scripts/orchestration-status.js",
|
|
111
111
|
"orchestrate:worker": "bash scripts/orchestrate-codex-worker.sh",
|
|
112
112
|
"orchestrate:tmux": "node scripts/orchestrate-worktrees.js",
|
|
113
|
+
"test:hook-contracts": "node tests/hooks/harness-hook-output-contracts.test.js",
|
|
114
|
+
"eval:aw:fresh-env-cli-smoke": "bash tests/evals/run-aw-fresh-env-cli-smoke.sh",
|
|
115
|
+
"eval:aw:published-package-e2e": "bash tests/evals/run-aw-published-package-e2e.sh",
|
|
116
|
+
"eval:aw:release-gate": "bash tests/evals/run-aw-release-gate.sh",
|
|
113
117
|
"test": "node scripts/ci/validate-agents.js && node scripts/ci/validate-commands.js && node scripts/ci/validate-rules.js && node scripts/ci/validate-skills.js && node scripts/ci/validate-hooks.js && node scripts/ci/validate-install-manifests.js && node scripts/ci/validate-no-personal-paths.js && node scripts/ci/catalog.js --text && node tests/run-all.js",
|
|
114
118
|
"coverage": "c8 --all --include=\"scripts/**/*.js\" --check-coverage --lines 80 --functions 80 --branches 80 --statements 80 --reporter=text --reporter=lcov node tests/run-all.js"
|
|
115
119
|
},
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
"hooks": {
|
|
4
4
|
"sessionStart": [
|
|
5
5
|
{
|
|
6
|
-
"command": "
|
|
6
|
+
"command": "bash -lc \"for candidate in \\\"$PWD/.cursor/hooks/session-start.sh\\\" \\\"$HOME/.cursor/hooks/session-start.sh\\\"; do if [ -f \\\"$candidate\\\" ]; then exec bash \\\"$candidate\\\"; fi; done; exit 0\"",
|
|
7
7
|
"event": "sessionStart",
|
|
8
8
|
"description": "Load previous context and detect environment"
|
|
9
9
|
}
|
|
10
10
|
],
|
|
11
11
|
"sessionEnd": [
|
|
12
12
|
{
|
|
13
|
-
"command": "node
|
|
13
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"session-end.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
14
14
|
"event": "sessionEnd",
|
|
15
15
|
"description": "Persist session state and evaluate patterns"
|
|
16
16
|
}
|
|
@@ -22,91 +22,91 @@
|
|
|
22
22
|
"description": "Block git hook-bypass flag to protect pre-commit, commit-msg, and pre-push hooks from being skipped"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
"command": "node
|
|
25
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"before-shell-execution.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
26
26
|
"event": "beforeShellExecution",
|
|
27
27
|
"description": "Tmux dev server blocker, tmux reminder, git push review"
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
30
|
"afterShellExecution": [
|
|
31
31
|
{
|
|
32
|
-
"command": "node
|
|
32
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"after-shell-execution.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
33
33
|
"event": "afterShellExecution",
|
|
34
34
|
"description": "PR URL logging, build analysis"
|
|
35
35
|
}
|
|
36
36
|
],
|
|
37
37
|
"afterFileEdit": [
|
|
38
38
|
{
|
|
39
|
-
"command": "node
|
|
39
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"after-file-edit.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
40
40
|
"event": "afterFileEdit",
|
|
41
41
|
"description": "Auto-format, TypeScript check, console.log warning"
|
|
42
42
|
}
|
|
43
43
|
],
|
|
44
44
|
"beforeMCPExecution": [
|
|
45
45
|
{
|
|
46
|
-
"command": "node
|
|
46
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"before-mcp-execution.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
47
47
|
"event": "beforeMCPExecution",
|
|
48
48
|
"description": "MCP audit logging and untrusted server warning"
|
|
49
49
|
}
|
|
50
50
|
],
|
|
51
51
|
"afterMCPExecution": [
|
|
52
52
|
{
|
|
53
|
-
"command": "node
|
|
53
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"after-mcp-execution.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
54
54
|
"event": "afterMCPExecution",
|
|
55
55
|
"description": "MCP result logging"
|
|
56
56
|
}
|
|
57
57
|
],
|
|
58
58
|
"beforeReadFile": [
|
|
59
59
|
{
|
|
60
|
-
"command": "node
|
|
60
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"before-read-file.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
61
61
|
"event": "beforeReadFile",
|
|
62
62
|
"description": "Warn when reading sensitive files (.env, .key, .pem)"
|
|
63
63
|
}
|
|
64
64
|
],
|
|
65
65
|
"beforeSubmitPrompt": [
|
|
66
66
|
{
|
|
67
|
-
"command": "
|
|
67
|
+
"command": "bash -lc \"for candidate in \\\"$PWD/.cursor/hooks/before-submit-prompt.sh\\\" \\\"$HOME/.cursor/hooks/before-submit-prompt.sh\\\"; do if [ -f \\\"$candidate\\\" ]; then exec bash \\\"$candidate\\\"; fi; done; exit 0\"",
|
|
68
68
|
"event": "beforeSubmitPrompt",
|
|
69
69
|
"description": "Detect secrets in prompts (sk-, ghp_, AKIA patterns)"
|
|
70
70
|
}
|
|
71
71
|
],
|
|
72
72
|
"subagentStart": [
|
|
73
73
|
{
|
|
74
|
-
"command": "node
|
|
74
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"subagent-start.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
75
75
|
"event": "subagentStart",
|
|
76
76
|
"description": "Log agent spawning for observability"
|
|
77
77
|
}
|
|
78
78
|
],
|
|
79
79
|
"subagentStop": [
|
|
80
80
|
{
|
|
81
|
-
"command": "node
|
|
81
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"subagent-stop.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
82
82
|
"event": "subagentStop",
|
|
83
83
|
"description": "Log agent completion"
|
|
84
84
|
}
|
|
85
85
|
],
|
|
86
86
|
"beforeTabFileRead": [
|
|
87
87
|
{
|
|
88
|
-
"command": "node
|
|
88
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"before-tab-file-read.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
89
89
|
"event": "beforeTabFileRead",
|
|
90
90
|
"description": "Block Tab from reading secrets (.env, .key, .pem, credentials)"
|
|
91
91
|
}
|
|
92
92
|
],
|
|
93
93
|
"afterTabFileEdit": [
|
|
94
94
|
{
|
|
95
|
-
"command": "node
|
|
95
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"after-tab-file-edit.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
96
96
|
"event": "afterTabFileEdit",
|
|
97
97
|
"description": "Auto-format Tab edits"
|
|
98
98
|
}
|
|
99
99
|
],
|
|
100
100
|
"preCompact": [
|
|
101
101
|
{
|
|
102
|
-
"command": "node
|
|
102
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"pre-compact.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
103
103
|
"event": "preCompact",
|
|
104
104
|
"description": "Save state before context compaction"
|
|
105
105
|
}
|
|
106
106
|
],
|
|
107
107
|
"stop": [
|
|
108
108
|
{
|
|
109
|
-
"command": "node .cursor
|
|
109
|
+
"command": "node -e \"const fs=require('fs');const path=require('path');const os=require('os');const scriptName=\\\"stop.js\\\";const candidates=[path.join(process.cwd(), '.cursor', 'hooks', scriptName),path.join(os.homedir(), '.cursor', 'hooks', scriptName)];const target=candidates.find(candidate => fs.existsSync(candidate));if(!target) process.exit(0);require(target)\"",
|
|
110
110
|
"event": "stop",
|
|
111
111
|
"description": "Console.log audit on all modified files"
|
|
112
112
|
}
|