gru-ai 0.1.0 → 0.2.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/hooks/detect-stale-docs.sh +132 -0
- package/.claude/hooks/tests/gate/01-valid-lightweight-skip/approve.skip +1 -0
- package/.claude/hooks/tests/gate/01-valid-lightweight-skip/audit.skip +1 -0
- package/.claude/hooks/tests/gate/01-valid-lightweight-skip/brainstorm.skip +1 -0
- package/.claude/hooks/tests/gate/01-valid-lightweight-skip/directive.json +12 -0
- package/.claude/hooks/tests/gate/01-valid-lightweight-skip/project-brainstorm.skip +1 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/audit.md +2 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/brainstorm.md +2 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/digest.md +2 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/directive.json +12 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/plan.json +14 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/projects/test-project/build-task-1.md +2 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/projects/test-project/build-task-2.md +2 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/projects/test-project/project.json +9 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/projects/test-project/review-task-1.md +2 -0
- package/.claude/hooks/tests/gate/02-valid-heavyweight/projects/test-project/review-task-2.md +2 -0
- package/.claude/hooks/tests/gate/03-fail-missing-brainstorm/directive.json +11 -0
- package/.claude/hooks/tests/gate/04-fail-missing-review/directive.json +12 -0
- package/.claude/hooks/tests/gate/04-fail-missing-review/projects/test-project/build-task-a.md +2 -0
- package/.claude/hooks/tests/gate/04-fail-missing-review/projects/test-project/build-task-b.md +2 -0
- package/.claude/hooks/tests/gate/04-fail-missing-review/projects/test-project/project.json +9 -0
- package/.claude/hooks/tests/gate/04-fail-missing-review/projects/test-project/review-task-a.md +2 -0
- package/.claude/hooks/tests/gate/05-valid-completion/digest.md +2 -0
- package/.claude/hooks/tests/gate/05-valid-completion/directive.json +17 -0
- package/.claude/hooks/tests/gate/06-fail-missing-build/directive.json +10 -0
- package/.claude/hooks/tests/gate/06-fail-missing-build/projects/test-project/project.json +8 -0
- package/.claude/hooks/tests/gate/07-valid-medium-full/audit.md +2 -0
- package/.claude/hooks/tests/gate/07-valid-medium-full/brainstorm.md +2 -0
- package/.claude/hooks/tests/gate/07-valid-medium-full/directive.json +12 -0
- package/.claude/hooks/tests/gate/07-valid-medium-full/plan.json +10 -0
- package/.claude/hooks/tests/gate/07-valid-medium-full/projects/test-project/project.json +8 -0
- package/.claude/hooks/tests/gate/08-fail-invalid-json/brainstorm.md +2 -0
- package/.claude/hooks/tests/gate/08-fail-invalid-json/directive.json +10 -0
- package/.claude/hooks/tests/gate/08-fail-invalid-json/plan.json +1 -0
- package/.claude/hooks/tests/gate/09-malformed-directive-json/directive.json +1 -0
- package/.claude/hooks/tests/gate/run-tests.sh +283 -0
- package/.claude/hooks/validate-cast.sh +168 -0
- package/.claude/hooks/validate-gate.sh +478 -0
- package/.claude/hooks/validate-project-json.sh +109 -0
- package/.claude/hooks/validate-reviews.sh +89 -0
- package/.claude/skills/directive/docs/pipeline/00-delegation-and-triage.md +2 -0
- package/.claude/skills/directive/docs/pipeline/02-read-directive.md +0 -6
- package/.claude/skills/directive/docs/pipeline/03-read-context.md +1 -3
- package/.claude/skills/directive/docs/pipeline/05-planning.md +1 -1
- package/.claude/skills/directive/docs/pipeline/06-technical-audit.md +0 -23
- package/.claude/skills/directive/docs/pipeline/07-plan-approval.md +0 -1
- package/.claude/skills/directive/docs/pipeline/09-execute-projects.md +12 -7
- package/.claude/skills/directive/docs/pipeline/10-wrapup.md +0 -4
- package/.claude/skills/directive/docs/reference/rules/casting-rules.md +2 -2
- package/.claude/skills/directive/docs/reference/rules/phase-definitions.md +3 -0
- package/.claude/skills/directive/docs/reference/rules/scope-and-dod.md +1 -1
- package/.claude/skills/directive/docs/reference/schemas/directive-json.md +0 -7
- package/.claude/skills/directive/docs/reference/schemas/plan-schema.md +0 -1
- package/.claude/skills/directive/docs/reference/templates/investigator-prompt.md +0 -3
- package/.claude/skills/directive/docs/reference/templates/planner-prompt.md +0 -1
- package/.claude/skills/gruai-agents/SKILL.md +114 -68
- package/.claude/skills/gruai-config/SKILL.md +33 -6
- package/.claude/skills/scout/SKILL.md +1 -1
- package/cli/resolve-pkg-root.sh +49 -0
- package/cli/templates/CLAUDE.md.template +1 -1
- package/cli/templates/directive.json.template +0 -1
- package/cli/templates/welcome-directive/directive.json +0 -1
- package/dist/00_Modern_Office_Singles.tsx +4 -0
- package/dist/Game.tiled-project +14 -0
- package/dist/Game.tiled-session +90 -0
- package/dist/Interiors.tsx +4 -0
- package/dist/Interiors_32x32.tsx +4 -0
- package/dist/Office_Design_1.tsx +4 -0
- package/dist/Office_Design_2.tsx +4 -0
- package/dist/assets/GamePage-B2OsBjXm.js +49 -0
- package/dist/assets/index-Bh01am7W.js +12 -0
- package/dist/assets/index-DCNBE1pw.css +1 -0
- package/dist/assets/office/Interiors.png +0 -0
- package/dist/assets/office/classroom.png +0 -0
- package/dist/assets/office/conference.png +0 -0
- package/dist/assets/office/generic.png +0 -0
- package/dist/assets/office/kitchen.png +0 -0
- package/dist/assets/office/livingroom.png +0 -0
- package/dist/assets/office/music-sport.png +0 -0
- package/dist/classroom.tsx +4 -0
- package/dist/conference.tsx +4 -0
- package/dist/furniture.tsx +4 -0
- package/dist/generic.tsx +4 -0
- package/dist/index.html +2 -2
- package/dist/kitchen.tsx +4 -0
- package/dist/livingroom.tsx +4 -0
- package/dist/music-sport.tsx +4 -0
- package/dist/office.tmx +398 -0
- package/dist/room-builder.tsx +4 -0
- package/dist-cli/commands/init.d.ts +9 -0
- package/dist-cli/commands/init.js +239 -0
- package/dist-cli/commands/scaffold.d.ts +15 -0
- package/dist-cli/commands/scaffold.js +338 -0
- package/dist-cli/commands/start.d.ts +7 -0
- package/dist-cli/commands/start.js +84 -0
- package/dist-cli/commands/update.d.ts +9 -0
- package/dist-cli/commands/update.js +189 -0
- package/dist-cli/index.d.ts +2 -0
- package/dist-cli/index.js +75 -0
- package/dist-cli/lib/color.d.ts +15 -0
- package/dist-cli/lib/color.js +21 -0
- package/dist-cli/lib/paths.d.ts +13 -0
- package/dist-cli/lib/paths.js +41 -0
- package/dist-cli/lib/roles.d.ts +22 -0
- package/dist-cli/lib/roles.js +201 -0
- package/dist-cli/lib/types.d.ts +42 -0
- package/dist-cli/lib/types.js +4 -0
- package/dist-server/scripts/personality-compiler.d.ts +13 -0
- package/dist-server/scripts/personality-compiler.js +172 -0
- package/dist-server/scripts/spawn-agent.d.ts +15 -0
- package/dist-server/scripts/spawn-agent.js +144 -0
- package/dist-server/server/actions/send-input.js +1 -3
- package/dist-server/server/config.d.ts +0 -1
- package/dist-server/server/config.js +0 -4
- package/dist-server/server/db.d.ts +0 -1
- package/dist-server/server/db.js +0 -15
- package/dist-server/server/index.js +17 -27
- package/dist-server/server/notifications/notifier.js +3 -2
- package/dist-server/server/parsers/session-scanner.js +15 -8
- package/dist-server/server/parsers/task-parser.d.ts +2 -5
- package/dist-server/server/parsers/task-parser.js +10 -25
- package/dist-server/server/paths.d.ts +34 -0
- package/dist-server/server/paths.js +110 -0
- package/dist-server/server/platform/__tests__/claude-code.test.js +0 -2
- package/dist-server/server/platform/__tests__/codex-cli-spawn.test.d.ts +1 -0
- package/dist-server/server/platform/__tests__/codex-cli-spawn.test.js +124 -0
- package/dist-server/server/platform/aider-spawn.d.ts +77 -0
- package/dist-server/server/platform/aider-spawn.js +189 -0
- package/dist-server/server/platform/claude-code-spawn.d.ts +59 -0
- package/dist-server/server/platform/claude-code-spawn.js +174 -0
- package/dist-server/server/platform/claude-code.d.ts +1 -1
- package/dist-server/server/platform/claude-code.js +2 -3
- package/dist-server/server/platform/codex-cli-spawn.d.ts +81 -0
- package/dist-server/server/platform/codex-cli-spawn.js +204 -0
- package/dist-server/server/platform/gemini-cli-spawn.d.ts +75 -0
- package/dist-server/server/platform/gemini-cli-spawn.js +188 -0
- package/dist-server/server/platform/index.d.ts +26 -1
- package/dist-server/server/platform/index.js +37 -0
- package/dist-server/server/platform/spawn-adapter.d.ts +115 -0
- package/dist-server/server/platform/spawn-adapter.js +12 -0
- package/dist-server/server/platform/types.d.ts +0 -4
- package/dist-server/server/state/aggregator.d.ts +0 -2
- package/dist-server/server/state/aggregator.js +9 -107
- package/dist-server/server/state/work-item-types.d.ts +953 -291
- package/dist-server/server/state/work-item-types.js +2 -6
- package/dist-server/server/types.d.ts +3 -79
- package/dist-server/server/watchers/directive-watcher.js +7 -3
- package/dist-server/server/watchers/state-watcher.js +0 -3
- package/package.json +10 -3
- package/dist/assets/GamePage-C5XQQOQH.js +0 -49
- package/dist/assets/index-CnTPDqpP.js +0 -12
- package/dist/assets/index-gR5q7ikB.css +0 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# detect-stale-docs.sh — Post-directive hook to detect potentially stale documentation
|
|
3
|
+
#
|
|
4
|
+
# After a directive completes, scans .context/ and .claude/ docs for references
|
|
5
|
+
# to files that were modified in the directive. If the doc itself was NOT modified,
|
|
6
|
+
# it is flagged as potentially stale.
|
|
7
|
+
#
|
|
8
|
+
# Staleness heuristic:
|
|
9
|
+
# "References a file" = doc contains a literal file path substring (grep -F)
|
|
10
|
+
# "Stale" = doc references a file modified in the directive, but the doc
|
|
11
|
+
# itself was NOT modified in the same directive
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# ./detect-stale-docs.sh file1.ts file2.tsx ...
|
|
15
|
+
# ./detect-stale-docs.sh --from-diff <base-branch>
|
|
16
|
+
# echo "file1.ts\nfile2.ts" | ./detect-stale-docs.sh --stdin
|
|
17
|
+
#
|
|
18
|
+
# Output: list of potentially stale docs with the files they reference
|
|
19
|
+
# Exit 0 always (output is informational, not blocking)
|
|
20
|
+
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
# Anchor to repo root
|
|
24
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || {
|
|
25
|
+
echo "Error: not in a git repo" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
}
|
|
28
|
+
cd "$REPO_ROOT"
|
|
29
|
+
|
|
30
|
+
# --- Collect modified files ---
|
|
31
|
+
MODIFIED_FILES=()
|
|
32
|
+
|
|
33
|
+
if [[ "${1:-}" == "--from-diff" ]]; then
|
|
34
|
+
# Get modified files from git diff against a base branch
|
|
35
|
+
BASE_BRANCH="${2:-main}"
|
|
36
|
+
while IFS= read -r f; do
|
|
37
|
+
[[ -n "$f" ]] && MODIFIED_FILES+=("$f")
|
|
38
|
+
done < <(git diff --name-only "$BASE_BRANCH" 2>/dev/null)
|
|
39
|
+
elif [[ "${1:-}" == "--stdin" ]]; then
|
|
40
|
+
# Read file list from stdin
|
|
41
|
+
while IFS= read -r f; do
|
|
42
|
+
[[ -n "$f" ]] && MODIFIED_FILES+=("$f")
|
|
43
|
+
done
|
|
44
|
+
else
|
|
45
|
+
# Read file list from arguments
|
|
46
|
+
for f in "$@"; do
|
|
47
|
+
[[ -n "$f" ]] && MODIFIED_FILES+=("$f")
|
|
48
|
+
done
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if [[ ${#MODIFIED_FILES[@]} -eq 0 ]]; then
|
|
52
|
+
exit 0 # No modified files — nothing to check
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# --- Build newline-separated list of modified docs (for exclusion) ---
|
|
56
|
+
# Compatible with bash 3.x (no associative arrays)
|
|
57
|
+
MODIFIED_DOCS=""
|
|
58
|
+
for f in "${MODIFIED_FILES[@]}"; do
|
|
59
|
+
case "$f" in
|
|
60
|
+
.context/*.md|.claude/*.md)
|
|
61
|
+
MODIFIED_DOCS="${MODIFIED_DOCS}${f}"$'\n'
|
|
62
|
+
;;
|
|
63
|
+
esac
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
# --- Create temp file with patterns (one per line) for grep -f ---
|
|
67
|
+
PATTERNS_FILE=$(mktemp)
|
|
68
|
+
trap 'rm -f "$PATTERNS_FILE"' EXIT
|
|
69
|
+
printf '%s\n' "${MODIFIED_FILES[@]}" > "$PATTERNS_FILE"
|
|
70
|
+
|
|
71
|
+
# --- Phase 1: Find all candidate docs in a single grep pass ---
|
|
72
|
+
# Use grep -Fl -f to find all .md files that contain ANY modified file path.
|
|
73
|
+
# This is much faster than iterating: one grep invocation covers all docs + patterns.
|
|
74
|
+
CANDIDATE_DOCS=()
|
|
75
|
+
while IFS= read -r doc; do
|
|
76
|
+
[[ -n "$doc" ]] && CANDIDATE_DOCS+=("$doc")
|
|
77
|
+
done < <(
|
|
78
|
+
find .context/ .claude/ -name '*.md' -type f 2>/dev/null \
|
|
79
|
+
| grep -v '/worktrees/' \
|
|
80
|
+
| grep -v 'node_modules' \
|
|
81
|
+
| xargs grep -Fl -f "$PATTERNS_FILE" 2>/dev/null || true
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if [[ ${#CANDIDATE_DOCS[@]} -eq 0 ]]; then
|
|
85
|
+
echo "No potentially stale docs detected."
|
|
86
|
+
exit 0
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# --- Phase 2: For each candidate, determine which files it references ---
|
|
90
|
+
# Only runs on the (small) set of docs that matched in Phase 1.
|
|
91
|
+
# Also filters out docs that were themselves modified (zero false positives).
|
|
92
|
+
|
|
93
|
+
STALE_RESULTS=()
|
|
94
|
+
|
|
95
|
+
for doc in "${CANDIDATE_DOCS[@]}"; do
|
|
96
|
+
# Skip docs that were also modified in this directive
|
|
97
|
+
if echo "$MODIFIED_DOCS" | grep -qxF "$doc" 2>/dev/null; then
|
|
98
|
+
continue
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Determine which specific modified files this doc references
|
|
102
|
+
REFERENCED=()
|
|
103
|
+
for modified in "${MODIFIED_FILES[@]}"; do
|
|
104
|
+
if grep -qF "$modified" "$doc" 2>/dev/null; then
|
|
105
|
+
REFERENCED+=("$modified")
|
|
106
|
+
fi
|
|
107
|
+
done
|
|
108
|
+
|
|
109
|
+
if [[ ${#REFERENCED[@]} -gt 0 ]]; then
|
|
110
|
+
REFS_STR=$(printf '%s, ' "${REFERENCED[@]}")
|
|
111
|
+
REFS_STR="${REFS_STR%, }" # trim trailing comma+space
|
|
112
|
+
STALE_RESULTS+=("$doc -> references modified: $REFS_STR")
|
|
113
|
+
fi
|
|
114
|
+
done
|
|
115
|
+
|
|
116
|
+
# --- Output ---
|
|
117
|
+
if [[ ${#STALE_RESULTS[@]} -eq 0 ]]; then
|
|
118
|
+
echo "No potentially stale docs detected."
|
|
119
|
+
exit 0
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
echo "## Potentially Stale Docs"
|
|
123
|
+
echo ""
|
|
124
|
+
echo "The following docs reference files that were modified but were not themselves updated:"
|
|
125
|
+
echo ""
|
|
126
|
+
for result in "${STALE_RESULTS[@]}"; do
|
|
127
|
+
echo "- $result"
|
|
128
|
+
done
|
|
129
|
+
echo ""
|
|
130
|
+
echo "Consider reviewing these docs for accuracy."
|
|
131
|
+
|
|
132
|
+
exit 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Skipped: lightweight directive does not require approval
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Skipped: lightweight directive does not require audit
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Skipped: lightweight directive does not require brainstorm
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "test-lightweight",
|
|
3
|
+
"title": "Test lightweight directive",
|
|
4
|
+
"status": "in_progress",
|
|
5
|
+
"weight": "lightweight",
|
|
6
|
+
"pipeline": {
|
|
7
|
+
"triage": { "status": "completed" },
|
|
8
|
+
"read": { "status": "completed" },
|
|
9
|
+
"context": { "status": "completed" },
|
|
10
|
+
"approve": { "status": "completed" }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Skipped: lightweight directive does not require project brainstorm
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "test-heavyweight",
|
|
3
|
+
"title": "Test heavyweight directive",
|
|
4
|
+
"status": "in_progress",
|
|
5
|
+
"weight": "heavyweight",
|
|
6
|
+
"pipeline": {
|
|
7
|
+
"triage": { "status": "completed" },
|
|
8
|
+
"read": { "status": "completed" },
|
|
9
|
+
"context": { "status": "completed" },
|
|
10
|
+
"approve": { "status": "completed" }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"goal": "Test heavyweight",
|
|
3
|
+
"projects": [
|
|
4
|
+
{
|
|
5
|
+
"id": "test-project",
|
|
6
|
+
"title": "Test project",
|
|
7
|
+
"cast": { "builder": "riley", "auditor": "sarah", "reviewers": ["sarah"] },
|
|
8
|
+
"tasks": [
|
|
9
|
+
{ "id": "task-1", "title": "First task" },
|
|
10
|
+
{ "id": "task-2", "title": "Second task" }
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "test-no-brainstorm",
|
|
3
|
+
"title": "Test missing brainstorm for heavyweight",
|
|
4
|
+
"status": "in_progress",
|
|
5
|
+
"weight": "heavyweight",
|
|
6
|
+
"pipeline": {
|
|
7
|
+
"triage": { "status": "completed" },
|
|
8
|
+
"read": { "status": "completed" },
|
|
9
|
+
"context": { "status": "completed" }
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "test-no-review",
|
|
3
|
+
"title": "Test missing review artifacts",
|
|
4
|
+
"status": "in_progress",
|
|
5
|
+
"weight": "medium",
|
|
6
|
+
"pipeline": {
|
|
7
|
+
"triage": { "status": "completed" },
|
|
8
|
+
"read": { "status": "completed" },
|
|
9
|
+
"context": { "status": "completed" },
|
|
10
|
+
"approve": { "status": "completed" }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "test-completion",
|
|
3
|
+
"title": "Test completion gate",
|
|
4
|
+
"status": "awaiting_completion",
|
|
5
|
+
"weight": "strategic",
|
|
6
|
+
"pipeline": {
|
|
7
|
+
"triage": { "status": "completed" },
|
|
8
|
+
"read": { "status": "completed" },
|
|
9
|
+
"context": { "status": "completed" },
|
|
10
|
+
"brainstorm": { "status": "completed" },
|
|
11
|
+
"plan": { "status": "completed" },
|
|
12
|
+
"audit": { "status": "completed" },
|
|
13
|
+
"approve": { "status": "completed" },
|
|
14
|
+
"execute": { "status": "completed" },
|
|
15
|
+
"wrapup": { "status": "completed" }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "test-medium-full",
|
|
3
|
+
"title": "Test medium with all artifacts",
|
|
4
|
+
"status": "in_progress",
|
|
5
|
+
"weight": "medium",
|
|
6
|
+
"pipeline": {
|
|
7
|
+
"triage": { "status": "completed" },
|
|
8
|
+
"read": { "status": "completed" },
|
|
9
|
+
"context": { "status": "completed" },
|
|
10
|
+
"approve": { "status": "completed" }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ this is not valid json !!!
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"broken
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# run-tests.sh — Test runner for validate-gate.sh
|
|
3
|
+
#
|
|
4
|
+
# Exercises all fixture directories and reports pass/fail.
|
|
5
|
+
# Exit 0 when all tests pass, exit 1 with details on failure.
|
|
6
|
+
#
|
|
7
|
+
# Usage: ./run-tests.sh
|
|
8
|
+
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
12
|
+
GATE_SCRIPT="$(cd "$SCRIPT_DIR/../.." && pwd)/validate-gate.sh"
|
|
13
|
+
PASS_COUNT=0
|
|
14
|
+
FAIL_COUNT=0
|
|
15
|
+
FAILURES=()
|
|
16
|
+
|
|
17
|
+
# Colors (if terminal supports them)
|
|
18
|
+
RED='\033[0;31m'
|
|
19
|
+
GREEN='\033[0;32m'
|
|
20
|
+
YELLOW='\033[0;33m'
|
|
21
|
+
NC='\033[0m' # No Color
|
|
22
|
+
|
|
23
|
+
run_test() {
|
|
24
|
+
local name="$1"
|
|
25
|
+
local fixture_dir="$2"
|
|
26
|
+
local target_step="$3"
|
|
27
|
+
local expect_valid="$4" # "true" or "false"
|
|
28
|
+
local extra_args="${5:-}"
|
|
29
|
+
local expect_violation_substr="${6:-}"
|
|
30
|
+
|
|
31
|
+
# Make a working copy so directive.json writes don't pollute fixtures
|
|
32
|
+
local tmpdir
|
|
33
|
+
tmpdir=$(mktemp -d)
|
|
34
|
+
cp -R "$fixture_dir/" "$tmpdir/"
|
|
35
|
+
|
|
36
|
+
local output
|
|
37
|
+
if [[ -n "$extra_args" ]]; then
|
|
38
|
+
output=$("$GATE_SCRIPT" "$tmpdir" "$target_step" "$extra_args" 2>&1) || true
|
|
39
|
+
else
|
|
40
|
+
output=$("$GATE_SCRIPT" "$tmpdir" "$target_step" 2>&1) || true
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
local actual_valid
|
|
44
|
+
actual_valid=$(echo "$output" | jq -r '.valid' 2>/dev/null || echo "parse_error")
|
|
45
|
+
|
|
46
|
+
local test_passed=true
|
|
47
|
+
|
|
48
|
+
if [[ "$actual_valid" != "$expect_valid" ]]; then
|
|
49
|
+
test_passed=false
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# If we expect a specific violation substring, check for it
|
|
53
|
+
if [[ -n "$expect_violation_substr" && "$expect_valid" == "false" ]]; then
|
|
54
|
+
if ! echo "$output" | jq -r '.violations[].message' 2>/dev/null | grep -q "$expect_violation_substr"; then
|
|
55
|
+
test_passed=false
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# If gate passed (valid=true), verify it wrote to directive.json
|
|
60
|
+
if [[ "$expect_valid" == "true" && "$actual_valid" == "true" ]]; then
|
|
61
|
+
local gates_entry
|
|
62
|
+
gates_entry=$(jq -r ".gates.\"$target_step\".passed_at // empty" "$tmpdir/directive.json" 2>/dev/null)
|
|
63
|
+
if [[ -z "$gates_entry" ]]; then
|
|
64
|
+
test_passed=false
|
|
65
|
+
echo -e " ${RED}FAIL${NC} $name — gate passed but did not write gates.$target_step to directive.json"
|
|
66
|
+
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
67
|
+
FAILURES+=("$name (gates write missing)")
|
|
68
|
+
rm -rf "$tmpdir"
|
|
69
|
+
return
|
|
70
|
+
fi
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
if [[ "$test_passed" == "true" ]]; then
|
|
74
|
+
echo -e " ${GREEN}PASS${NC} $name"
|
|
75
|
+
PASS_COUNT=$((PASS_COUNT + 1))
|
|
76
|
+
else
|
|
77
|
+
echo -e " ${RED}FAIL${NC} $name"
|
|
78
|
+
echo " Expected valid=$expect_valid, got valid=$actual_valid"
|
|
79
|
+
echo " Output: $(echo "$output" | head -5)"
|
|
80
|
+
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
81
|
+
FAILURES+=("$name")
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
rm -rf "$tmpdir"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
echo ""
|
|
88
|
+
echo "validate-gate.sh Test Suite"
|
|
89
|
+
echo "==========================="
|
|
90
|
+
echo ""
|
|
91
|
+
|
|
92
|
+
# ---------------------------------------------------------------------------
|
|
93
|
+
# Test 01: Valid lightweight with .skip markers
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
echo "01: Lightweight directive with .skip markers"
|
|
96
|
+
|
|
97
|
+
run_test \
|
|
98
|
+
"plan gate passes with brainstorm.skip (lightweight)" \
|
|
99
|
+
"$SCRIPT_DIR/01-valid-lightweight-skip" \
|
|
100
|
+
"plan" \
|
|
101
|
+
"true"
|
|
102
|
+
|
|
103
|
+
run_test \
|
|
104
|
+
"execute gate passes with approve.skip (lightweight)" \
|
|
105
|
+
"$SCRIPT_DIR/01-valid-lightweight-skip" \
|
|
106
|
+
"execute" \
|
|
107
|
+
"true"
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# Test 02: Valid heavyweight — full artifact chain
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
echo ""
|
|
113
|
+
echo "02: Heavyweight directive with all artifacts"
|
|
114
|
+
|
|
115
|
+
run_test \
|
|
116
|
+
"plan gate passes (brainstorm.md exists)" \
|
|
117
|
+
"$SCRIPT_DIR/02-valid-heavyweight" \
|
|
118
|
+
"plan" \
|
|
119
|
+
"true"
|
|
120
|
+
|
|
121
|
+
run_test \
|
|
122
|
+
"audit gate passes (plan.json exists with .projects)" \
|
|
123
|
+
"$SCRIPT_DIR/02-valid-heavyweight" \
|
|
124
|
+
"audit" \
|
|
125
|
+
"true"
|
|
126
|
+
|
|
127
|
+
run_test \
|
|
128
|
+
"execute gate passes (approval in directive.json)" \
|
|
129
|
+
"$SCRIPT_DIR/02-valid-heavyweight" \
|
|
130
|
+
"execute" \
|
|
131
|
+
"true"
|
|
132
|
+
|
|
133
|
+
run_test \
|
|
134
|
+
"review-gate passes for task-1 (build-task-1.md exists)" \
|
|
135
|
+
"$SCRIPT_DIR/02-valid-heavyweight" \
|
|
136
|
+
"review-gate" \
|
|
137
|
+
"true" \
|
|
138
|
+
"task-1"
|
|
139
|
+
|
|
140
|
+
run_test \
|
|
141
|
+
"wrapup gate passes (all reviews exist)" \
|
|
142
|
+
"$SCRIPT_DIR/02-valid-heavyweight" \
|
|
143
|
+
"wrapup" \
|
|
144
|
+
"true"
|
|
145
|
+
|
|
146
|
+
run_test \
|
|
147
|
+
"completion gate passes (digest.md exists)" \
|
|
148
|
+
"$SCRIPT_DIR/02-valid-heavyweight" \
|
|
149
|
+
"completion" \
|
|
150
|
+
"true"
|
|
151
|
+
|
|
152
|
+
# ---------------------------------------------------------------------------
|
|
153
|
+
# Test 03: Fail — missing brainstorm for heavyweight
|
|
154
|
+
# ---------------------------------------------------------------------------
|
|
155
|
+
echo ""
|
|
156
|
+
echo "03: Missing brainstorm for heavyweight"
|
|
157
|
+
|
|
158
|
+
run_test \
|
|
159
|
+
"plan gate fails (no brainstorm.md, heavyweight)" \
|
|
160
|
+
"$SCRIPT_DIR/03-fail-missing-brainstorm" \
|
|
161
|
+
"plan" \
|
|
162
|
+
"false" \
|
|
163
|
+
"" \
|
|
164
|
+
"Missing brainstorm artifact"
|
|
165
|
+
|
|
166
|
+
# ---------------------------------------------------------------------------
|
|
167
|
+
# Test 04: Fail — missing review artifact
|
|
168
|
+
# ---------------------------------------------------------------------------
|
|
169
|
+
echo ""
|
|
170
|
+
echo "04: Missing review artifact blocks wrapup"
|
|
171
|
+
|
|
172
|
+
run_test \
|
|
173
|
+
"wrapup gate fails (review-task-b.md missing)" \
|
|
174
|
+
"$SCRIPT_DIR/04-fail-missing-review" \
|
|
175
|
+
"wrapup" \
|
|
176
|
+
"false" \
|
|
177
|
+
"" \
|
|
178
|
+
"Missing review artifact"
|
|
179
|
+
|
|
180
|
+
# ---------------------------------------------------------------------------
|
|
181
|
+
# Test 05: Valid completion gate
|
|
182
|
+
# ---------------------------------------------------------------------------
|
|
183
|
+
echo ""
|
|
184
|
+
echo "05: Valid completion gate"
|
|
185
|
+
|
|
186
|
+
run_test \
|
|
187
|
+
"completion gate passes (digest.md exists, strategic)" \
|
|
188
|
+
"$SCRIPT_DIR/05-valid-completion" \
|
|
189
|
+
"completion" \
|
|
190
|
+
"true"
|
|
191
|
+
|
|
192
|
+
# ---------------------------------------------------------------------------
|
|
193
|
+
# Test 06: Fail — missing build artifact blocks review
|
|
194
|
+
# ---------------------------------------------------------------------------
|
|
195
|
+
echo ""
|
|
196
|
+
echo "06: Missing build artifact blocks review"
|
|
197
|
+
|
|
198
|
+
run_test \
|
|
199
|
+
"review-gate fails for task 'widget' (no build-widget.md)" \
|
|
200
|
+
"$SCRIPT_DIR/06-fail-missing-build" \
|
|
201
|
+
"review-gate" \
|
|
202
|
+
"false" \
|
|
203
|
+
"widget" \
|
|
204
|
+
"Missing build artifact"
|
|
205
|
+
|
|
206
|
+
# ---------------------------------------------------------------------------
|
|
207
|
+
# Test 07: Valid medium — full chain through execute
|
|
208
|
+
# ---------------------------------------------------------------------------
|
|
209
|
+
echo ""
|
|
210
|
+
echo "07: Medium directive with full chain"
|
|
211
|
+
|
|
212
|
+
run_test \
|
|
213
|
+
"plan gate passes (brainstorm.md exists, medium)" \
|
|
214
|
+
"$SCRIPT_DIR/07-valid-medium-full" \
|
|
215
|
+
"plan" \
|
|
216
|
+
"true"
|
|
217
|
+
|
|
218
|
+
run_test \
|
|
219
|
+
"audit gate passes (plan.json valid)" \
|
|
220
|
+
"$SCRIPT_DIR/07-valid-medium-full" \
|
|
221
|
+
"audit" \
|
|
222
|
+
"true"
|
|
223
|
+
|
|
224
|
+
run_test \
|
|
225
|
+
"approve gate passes (project.json with tasks)" \
|
|
226
|
+
"$SCRIPT_DIR/07-valid-medium-full" \
|
|
227
|
+
"approve" \
|
|
228
|
+
"true"
|
|
229
|
+
|
|
230
|
+
run_test \
|
|
231
|
+
"execute gate passes (approval completed)" \
|
|
232
|
+
"$SCRIPT_DIR/07-valid-medium-full" \
|
|
233
|
+
"execute" \
|
|
234
|
+
"true"
|
|
235
|
+
|
|
236
|
+
# ---------------------------------------------------------------------------
|
|
237
|
+
# Test 08: Fail — invalid JSON in plan.json
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
echo ""
|
|
240
|
+
echo "08: Invalid JSON in artifact"
|
|
241
|
+
|
|
242
|
+
run_test \
|
|
243
|
+
"audit gate fails (plan.json is invalid JSON)" \
|
|
244
|
+
"$SCRIPT_DIR/08-fail-invalid-json" \
|
|
245
|
+
"audit" \
|
|
246
|
+
"false" \
|
|
247
|
+
"" \
|
|
248
|
+
"not valid JSON"
|
|
249
|
+
|
|
250
|
+
# ---------------------------------------------------------------------------
|
|
251
|
+
# Test 09: Fail — malformed directive.json
|
|
252
|
+
# ---------------------------------------------------------------------------
|
|
253
|
+
echo ""
|
|
254
|
+
echo "09: Malformed directive.json"
|
|
255
|
+
|
|
256
|
+
run_test \
|
|
257
|
+
"plan gate fails (directive.json is not valid JSON)" \
|
|
258
|
+
"$SCRIPT_DIR/09-malformed-directive-json" \
|
|
259
|
+
"plan" \
|
|
260
|
+
"false" \
|
|
261
|
+
"" \
|
|
262
|
+
"not valid JSON"
|
|
263
|
+
|
|
264
|
+
# ---------------------------------------------------------------------------
|
|
265
|
+
# Summary
|
|
266
|
+
# ---------------------------------------------------------------------------
|
|
267
|
+
echo ""
|
|
268
|
+
echo "==========================="
|
|
269
|
+
TOTAL=$((PASS_COUNT + FAIL_COUNT))
|
|
270
|
+
echo -e "Results: ${GREEN}${PASS_COUNT}${NC} passed, ${RED}${FAIL_COUNT}${NC} failed, ${TOTAL} total"
|
|
271
|
+
|
|
272
|
+
if [[ $FAIL_COUNT -gt 0 ]]; then
|
|
273
|
+
echo ""
|
|
274
|
+
echo "Failures:"
|
|
275
|
+
for f in "${FAILURES[@]}"; do
|
|
276
|
+
echo -e " ${RED}-${NC} $f"
|
|
277
|
+
done
|
|
278
|
+
exit 1
|
|
279
|
+
fi
|
|
280
|
+
|
|
281
|
+
echo ""
|
|
282
|
+
echo -e "${GREEN}All tests passed.${NC}"
|
|
283
|
+
exit 0
|