agent-bober 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/.claude-plugin/plugin.json +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +495 -0
  4. package/agents/bober-evaluator.md +323 -0
  5. package/agents/bober-generator.md +245 -0
  6. package/agents/bober-planner.md +248 -0
  7. package/dist/cli/commands/eval.d.ts +6 -0
  8. package/dist/cli/commands/eval.d.ts.map +1 -0
  9. package/dist/cli/commands/eval.js +129 -0
  10. package/dist/cli/commands/eval.js.map +1 -0
  11. package/dist/cli/commands/init.d.ts +5 -0
  12. package/dist/cli/commands/init.d.ts.map +1 -0
  13. package/dist/cli/commands/init.js +547 -0
  14. package/dist/cli/commands/init.js.map +1 -0
  15. package/dist/cli/commands/plan.d.ts +5 -0
  16. package/dist/cli/commands/plan.d.ts.map +1 -0
  17. package/dist/cli/commands/plan.js +87 -0
  18. package/dist/cli/commands/plan.js.map +1 -0
  19. package/dist/cli/commands/run.d.ts +5 -0
  20. package/dist/cli/commands/run.d.ts.map +1 -0
  21. package/dist/cli/commands/run.js +120 -0
  22. package/dist/cli/commands/run.js.map +1 -0
  23. package/dist/cli/commands/sprint.d.ts +6 -0
  24. package/dist/cli/commands/sprint.d.ts.map +1 -0
  25. package/dist/cli/commands/sprint.js +206 -0
  26. package/dist/cli/commands/sprint.js.map +1 -0
  27. package/dist/cli/index.d.ts +3 -0
  28. package/dist/cli/index.d.ts.map +1 -0
  29. package/dist/cli/index.js +124 -0
  30. package/dist/cli/index.js.map +1 -0
  31. package/dist/config/defaults.d.ts +15 -0
  32. package/dist/config/defaults.d.ts.map +1 -0
  33. package/dist/config/defaults.js +226 -0
  34. package/dist/config/defaults.js.map +1 -0
  35. package/dist/config/index.d.ts +4 -0
  36. package/dist/config/index.d.ts.map +1 -0
  37. package/dist/config/index.js +8 -0
  38. package/dist/config/index.js.map +1 -0
  39. package/dist/config/loader.d.ts +18 -0
  40. package/dist/config/loader.d.ts.map +1 -0
  41. package/dist/config/loader.js +189 -0
  42. package/dist/config/loader.js.map +1 -0
  43. package/dist/config/schema.d.ts +904 -0
  44. package/dist/config/schema.d.ts.map +1 -0
  45. package/dist/config/schema.js +181 -0
  46. package/dist/config/schema.js.map +1 -0
  47. package/dist/contracts/eval-result.d.ts +205 -0
  48. package/dist/contracts/eval-result.d.ts.map +1 -0
  49. package/dist/contracts/eval-result.js +87 -0
  50. package/dist/contracts/eval-result.js.map +1 -0
  51. package/dist/contracts/index.d.ts +4 -0
  52. package/dist/contracts/index.d.ts.map +1 -0
  53. package/dist/contracts/index.js +16 -0
  54. package/dist/contracts/index.js.map +1 -0
  55. package/dist/contracts/spec.d.ts +101 -0
  56. package/dist/contracts/spec.d.ts.map +1 -0
  57. package/dist/contracts/spec.js +51 -0
  58. package/dist/contracts/spec.js.map +1 -0
  59. package/dist/contracts/sprint-contract.d.ts +141 -0
  60. package/dist/contracts/sprint-contract.d.ts.map +1 -0
  61. package/dist/contracts/sprint-contract.js +80 -0
  62. package/dist/contracts/sprint-contract.js.map +1 -0
  63. package/dist/evaluators/builtin/api-check.d.ts +13 -0
  64. package/dist/evaluators/builtin/api-check.d.ts.map +1 -0
  65. package/dist/evaluators/builtin/api-check.js +152 -0
  66. package/dist/evaluators/builtin/api-check.js.map +1 -0
  67. package/dist/evaluators/builtin/build-check.d.ts +17 -0
  68. package/dist/evaluators/builtin/build-check.d.ts.map +1 -0
  69. package/dist/evaluators/builtin/build-check.js +155 -0
  70. package/dist/evaluators/builtin/build-check.js.map +1 -0
  71. package/dist/evaluators/builtin/command-runner.d.ts +26 -0
  72. package/dist/evaluators/builtin/command-runner.d.ts.map +1 -0
  73. package/dist/evaluators/builtin/command-runner.js +114 -0
  74. package/dist/evaluators/builtin/command-runner.js.map +1 -0
  75. package/dist/evaluators/builtin/lint.d.ts +17 -0
  76. package/dist/evaluators/builtin/lint.d.ts.map +1 -0
  77. package/dist/evaluators/builtin/lint.js +264 -0
  78. package/dist/evaluators/builtin/lint.js.map +1 -0
  79. package/dist/evaluators/builtin/playwright.d.ts +16 -0
  80. package/dist/evaluators/builtin/playwright.d.ts.map +1 -0
  81. package/dist/evaluators/builtin/playwright.js +238 -0
  82. package/dist/evaluators/builtin/playwright.js.map +1 -0
  83. package/dist/evaluators/builtin/typescript-check.d.ts +12 -0
  84. package/dist/evaluators/builtin/typescript-check.d.ts.map +1 -0
  85. package/dist/evaluators/builtin/typescript-check.js +155 -0
  86. package/dist/evaluators/builtin/typescript-check.js.map +1 -0
  87. package/dist/evaluators/builtin/unit-test.d.ts +18 -0
  88. package/dist/evaluators/builtin/unit-test.d.ts.map +1 -0
  89. package/dist/evaluators/builtin/unit-test.js +279 -0
  90. package/dist/evaluators/builtin/unit-test.js.map +1 -0
  91. package/dist/evaluators/index.d.ts +11 -0
  92. package/dist/evaluators/index.d.ts.map +1 -0
  93. package/dist/evaluators/index.js +13 -0
  94. package/dist/evaluators/index.js.map +1 -0
  95. package/dist/evaluators/plugin-interface.d.ts +50 -0
  96. package/dist/evaluators/plugin-interface.d.ts.map +1 -0
  97. package/dist/evaluators/plugin-interface.js +2 -0
  98. package/dist/evaluators/plugin-interface.js.map +1 -0
  99. package/dist/evaluators/plugin-loader.d.ts +18 -0
  100. package/dist/evaluators/plugin-loader.d.ts.map +1 -0
  101. package/dist/evaluators/plugin-loader.js +107 -0
  102. package/dist/evaluators/plugin-loader.js.map +1 -0
  103. package/dist/evaluators/registry.d.ts +78 -0
  104. package/dist/evaluators/registry.d.ts.map +1 -0
  105. package/dist/evaluators/registry.js +238 -0
  106. package/dist/evaluators/registry.js.map +1 -0
  107. package/dist/index.d.ts +17 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +22 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/orchestrator/context-handoff.d.ts +543 -0
  112. package/dist/orchestrator/context-handoff.d.ts.map +1 -0
  113. package/dist/orchestrator/context-handoff.js +133 -0
  114. package/dist/orchestrator/context-handoff.js.map +1 -0
  115. package/dist/orchestrator/evaluator-agent.d.ts +15 -0
  116. package/dist/orchestrator/evaluator-agent.d.ts.map +1 -0
  117. package/dist/orchestrator/evaluator-agent.js +233 -0
  118. package/dist/orchestrator/evaluator-agent.js.map +1 -0
  119. package/dist/orchestrator/generator-agent.d.ts +16 -0
  120. package/dist/orchestrator/generator-agent.d.ts.map +1 -0
  121. package/dist/orchestrator/generator-agent.js +147 -0
  122. package/dist/orchestrator/generator-agent.js.map +1 -0
  123. package/dist/orchestrator/pipeline.d.ts +24 -0
  124. package/dist/orchestrator/pipeline.d.ts.map +1 -0
  125. package/dist/orchestrator/pipeline.js +290 -0
  126. package/dist/orchestrator/pipeline.js.map +1 -0
  127. package/dist/orchestrator/planner-agent.d.ts +10 -0
  128. package/dist/orchestrator/planner-agent.d.ts.map +1 -0
  129. package/dist/orchestrator/planner-agent.js +187 -0
  130. package/dist/orchestrator/planner-agent.js.map +1 -0
  131. package/dist/state/helpers.d.ts +5 -0
  132. package/dist/state/helpers.d.ts.map +1 -0
  133. package/dist/state/helpers.js +8 -0
  134. package/dist/state/helpers.js.map +1 -0
  135. package/dist/state/history.d.ts +39 -0
  136. package/dist/state/history.d.ts.map +1 -0
  137. package/dist/state/history.js +162 -0
  138. package/dist/state/history.js.map +1 -0
  139. package/dist/state/index.d.ts +8 -0
  140. package/dist/state/index.d.ts.map +1 -0
  141. package/dist/state/index.js +22 -0
  142. package/dist/state/index.js.map +1 -0
  143. package/dist/state/plan-state.d.ts +21 -0
  144. package/dist/state/plan-state.d.ts.map +1 -0
  145. package/dist/state/plan-state.js +108 -0
  146. package/dist/state/plan-state.js.map +1 -0
  147. package/dist/state/sprint-state.d.ts +20 -0
  148. package/dist/state/sprint-state.d.ts.map +1 -0
  149. package/dist/state/sprint-state.js +98 -0
  150. package/dist/state/sprint-state.js.map +1 -0
  151. package/dist/utils/fs.d.ts +31 -0
  152. package/dist/utils/fs.d.ts.map +1 -0
  153. package/dist/utils/fs.js +67 -0
  154. package/dist/utils/fs.js.map +1 -0
  155. package/dist/utils/git.d.ts +35 -0
  156. package/dist/utils/git.d.ts.map +1 -0
  157. package/dist/utils/git.js +84 -0
  158. package/dist/utils/git.js.map +1 -0
  159. package/dist/utils/index.d.ts +4 -0
  160. package/dist/utils/index.d.ts.map +1 -0
  161. package/dist/utils/index.js +4 -0
  162. package/dist/utils/index.js.map +1 -0
  163. package/dist/utils/logger.d.ts +45 -0
  164. package/dist/utils/logger.d.ts.map +1 -0
  165. package/dist/utils/logger.js +73 -0
  166. package/dist/utils/logger.js.map +1 -0
  167. package/hooks/hooks.json +10 -0
  168. package/package.json +67 -0
  169. package/scripts/detect-stack.sh +287 -0
  170. package/scripts/init-project.sh +206 -0
  171. package/scripts/run-eval.sh +175 -0
  172. package/skills/bober.anchor/SKILL.md +365 -0
  173. package/skills/bober.anchor/references/anchor-guide.md +567 -0
  174. package/skills/bober.brownfield/SKILL.md +422 -0
  175. package/skills/bober.brownfield/references/codebase-analysis.md +304 -0
  176. package/skills/bober.eval/SKILL.md +235 -0
  177. package/skills/bober.eval/references/eval-strategies.md +407 -0
  178. package/skills/bober.eval/references/feedback-format.md +182 -0
  179. package/skills/bober.plan/SKILL.md +244 -0
  180. package/skills/bober.plan/references/clarification-guide.md +124 -0
  181. package/skills/bober.plan/references/spec-schema.md +253 -0
  182. package/skills/bober.react/SKILL.md +330 -0
  183. package/skills/bober.react/references/react-scaffold.md +344 -0
  184. package/skills/bober.run/SKILL.md +303 -0
  185. package/skills/bober.solidity/SKILL.md +416 -0
  186. package/skills/bober.solidity/references/solidity-guide.md +487 -0
  187. package/skills/bober.sprint/SKILL.md +280 -0
  188. package/skills/bober.sprint/references/contract-schema.md +251 -0
  189. package/templates/base/CLAUDE.md +20 -0
  190. package/templates/base/bober.config.json +35 -0
  191. package/templates/brownfield/CLAUDE.md +34 -0
  192. package/templates/brownfield/bober.config.json +37 -0
  193. package/templates/presets/anchor/CLAUDE.md +163 -0
  194. package/templates/presets/anchor/bober.config.json +9 -0
  195. package/templates/presets/api-node/CLAUDE.md +153 -0
  196. package/templates/presets/api-node/bober.config.json +10 -0
  197. package/templates/presets/nextjs/CLAUDE.md +82 -0
  198. package/templates/presets/nextjs/bober.config.json +14 -0
  199. package/templates/presets/python-api/CLAUDE.md +202 -0
  200. package/templates/presets/python-api/bober.config.json +9 -0
  201. package/templates/presets/react-vite/CLAUDE.md +71 -0
  202. package/templates/presets/react-vite/bober.config.json +53 -0
  203. package/templates/presets/react-vite/scaffold/package.json +45 -0
  204. package/templates/presets/react-vite/scaffold/server/index.ts +38 -0
  205. package/templates/presets/react-vite/scaffold/server/tsconfig.json +24 -0
  206. package/templates/presets/react-vite/scaffold/src/App.tsx +37 -0
  207. package/templates/presets/react-vite/scaffold/src/index.html +12 -0
  208. package/templates/presets/react-vite/scaffold/src/main.tsx +12 -0
  209. package/templates/presets/react-vite/scaffold/tsconfig.json +27 -0
  210. package/templates/presets/react-vite/scaffold/vite.config.ts +34 -0
  211. package/templates/presets/solidity/CLAUDE.md +106 -0
  212. package/templates/presets/solidity/bober.config.json +9 -0
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env bash
2
+ # ──────────────────────────────────────────────────────────────────────
3
+ # init-project.sh — Initialize a new bober-managed project.
4
+ #
5
+ # Usage:
6
+ # bash scripts/init-project.sh <template>
7
+ #
8
+ # Templates: base, brownfield
9
+ # Presets: nextjs, react-vite, solidity, anchor, api-node, python-api
10
+ # ──────────────────────────────────────────────────────────────────────
11
+
12
+ set -euo pipefail
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ PACKAGE_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
16
+ TEMPLATES_DIR="$PACKAGE_ROOT/templates"
17
+ PROJECT_DIR="$(pwd)"
18
+
19
+ # ── Argument validation ─────────────────────────────────────────────
20
+
21
+ TEMPLATE="${1:-}"
22
+
23
+ if [[ -z "$TEMPLATE" ]]; then
24
+ echo "Usage: bash scripts/init-project.sh <template>"
25
+ echo ""
26
+ echo "Available templates:"
27
+ echo " base Minimal greenfield configuration (customize yourself)"
28
+ echo " brownfield Existing codebase (conservative settings)"
29
+ echo ""
30
+ echo "Available presets:"
31
+ echo " nextjs Next.js full-stack app"
32
+ echo " react-vite React + Vite + any backend"
33
+ echo " solidity EVM smart contracts (Hardhat/Foundry)"
34
+ echo " anchor Solana programs (Anchor/Rust)"
35
+ echo " api-node Node.js API (Express/NestJS/Fastify)"
36
+ echo " python-api Python API (FastAPI/Django)"
37
+ exit 1
38
+ fi
39
+
40
+ # Resolve template directory — presets live under templates/presets/
41
+ if [[ "$TEMPLATE" == "base" || "$TEMPLATE" == "brownfield" ]]; then
42
+ TEMPLATE_DIR="$TEMPLATES_DIR/$TEMPLATE"
43
+ else
44
+ TEMPLATE_DIR="$TEMPLATES_DIR/presets/$TEMPLATE"
45
+ fi
46
+
47
+ if [[ ! -d "$TEMPLATE_DIR" ]]; then
48
+ echo "Error: Unknown template '$TEMPLATE'."
49
+ echo "Available templates: base, brownfield"
50
+ echo "Available presets: nextjs, react-vite, solidity, anchor, api-node, python-api"
51
+ exit 1
52
+ fi
53
+
54
+ echo "Initializing bober project with template: $TEMPLATE"
55
+ echo "Project directory: $PROJECT_DIR"
56
+ echo ""
57
+
58
+ # ── Create .bober directory structure ───────────────────────────────
59
+
60
+ echo "Creating .bober/ directory structure..."
61
+
62
+ mkdir -p "$PROJECT_DIR/.bober/specs"
63
+ mkdir -p "$PROJECT_DIR/.bober/contracts"
64
+ mkdir -p "$PROJECT_DIR/.bober/evaluations"
65
+ mkdir -p "$PROJECT_DIR/.bober/snapshots"
66
+
67
+ # Initialize progress tracker
68
+ if [[ ! -f "$PROJECT_DIR/.bober/progress.md" ]]; then
69
+ cat > "$PROJECT_DIR/.bober/progress.md" << 'PROGRESS'
70
+ # Bober Progress
71
+
72
+ Tracking all plans, sprints, and evaluations.
73
+
74
+ ---
75
+
76
+ PROGRESS
77
+ echo " Created .bober/progress.md"
78
+ fi
79
+
80
+ # Initialize history log
81
+ if [[ ! -f "$PROJECT_DIR/.bober/history.jsonl" ]]; then
82
+ echo "{\"event\":\"project-initialized\",\"template\":\"$TEMPLATE\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" \
83
+ > "$PROJECT_DIR/.bober/history.jsonl"
84
+ echo " Created .bober/history.jsonl"
85
+ fi
86
+
87
+ # ── Copy bober.config.json ──────────────────────────────────────────
88
+
89
+ if [[ -f "$PROJECT_DIR/bober.config.json" ]]; then
90
+ echo " bober.config.json already exists — skipping (will not overwrite)"
91
+ else
92
+ # Determine the project name from the directory name
93
+ PROJECT_NAME="$(basename "$PROJECT_DIR")"
94
+ # Copy and substitute the project name
95
+ sed "s/\"name\": \"\"/\"name\": \"$PROJECT_NAME\"/" \
96
+ "$TEMPLATE_DIR/bober.config.json" > "$PROJECT_DIR/bober.config.json"
97
+ echo " Created bober.config.json"
98
+ fi
99
+
100
+ # ── Copy CLAUDE.md ──────────────────────────────────────────────────
101
+
102
+ if [[ -f "$PROJECT_DIR/CLAUDE.md" ]]; then
103
+ echo " CLAUDE.md already exists — skipping (will not overwrite)"
104
+ else
105
+ cp "$TEMPLATE_DIR/CLAUDE.md" "$PROJECT_DIR/CLAUDE.md"
106
+ echo " Created CLAUDE.md"
107
+ fi
108
+
109
+ # ── Copy scaffold files (preset templates with scaffold dirs) ───────
110
+
111
+ if [[ -d "$TEMPLATE_DIR/scaffold" ]]; then
112
+ echo ""
113
+ echo "Copying scaffold files..."
114
+
115
+ # Only copy scaffold files that do not already exist
116
+ while IFS= read -r -d '' file; do
117
+ relative="${file#$TEMPLATE_DIR/scaffold/}"
118
+ target="$PROJECT_DIR/$relative"
119
+ target_dir="$(dirname "$target")"
120
+
121
+ if [[ -f "$target" ]]; then
122
+ echo " Skipping $relative (already exists)"
123
+ else
124
+ mkdir -p "$target_dir"
125
+ cp "$file" "$target"
126
+ echo " Created $relative"
127
+ fi
128
+ done < <(find "$TEMPLATE_DIR/scaffold" -type f -print0)
129
+ fi
130
+
131
+ # ── Update .gitignore ───────────────────────────────────────────────
132
+
133
+ echo ""
134
+ echo "Updating .gitignore..."
135
+
136
+ GITIGNORE="$PROJECT_DIR/.gitignore"
137
+
138
+ # Entries to ensure are present
139
+ ENTRIES=(
140
+ ".bober/"
141
+ ".bober/snapshots/"
142
+ )
143
+
144
+ touch "$GITIGNORE"
145
+
146
+ for entry in "${ENTRIES[@]}"; do
147
+ if ! grep -qxF "$entry" "$GITIGNORE" 2>/dev/null; then
148
+ echo "$entry" >> "$GITIGNORE"
149
+ echo " Added '$entry' to .gitignore"
150
+ fi
151
+ done
152
+
153
+ # ── Summary ─────────────────────────────────────────────────────────
154
+
155
+ echo ""
156
+ echo "──────────────────────────────────────────────────────"
157
+ echo " bober project initialized successfully!"
158
+ echo "──────────────────────────────────────────────────────"
159
+ echo ""
160
+ echo "Next steps:"
161
+ echo ""
162
+
163
+ if [[ "$TEMPLATE" == "react-vite" ]]; then
164
+ echo " 1. npm install"
165
+ echo " 2. npm run dev # start frontend + backend"
166
+ echo " 3. /bober:plan # create your first plan"
167
+ echo " 4. /bober:sprint # run the first sprint"
168
+ elif [[ "$TEMPLATE" == "nextjs" ]]; then
169
+ echo " 1. npm install"
170
+ echo " 2. npm run dev # start Next.js dev server"
171
+ echo " 3. /bober:plan # create your first plan"
172
+ echo " 4. /bober:sprint # run the first sprint"
173
+ elif [[ "$TEMPLATE" == "solidity" ]]; then
174
+ echo " 1. npm install"
175
+ echo " 2. npx hardhat compile # compile contracts"
176
+ echo " 3. /bober:plan # create your first plan"
177
+ echo " 4. /bober:sprint # run the first sprint"
178
+ elif [[ "$TEMPLATE" == "anchor" ]]; then
179
+ echo " 1. anchor build # build the program"
180
+ echo " 2. anchor test # run tests"
181
+ echo " 3. /bober:plan # create your first plan"
182
+ echo " 4. /bober:sprint # run the first sprint"
183
+ elif [[ "$TEMPLATE" == "api-node" ]]; then
184
+ echo " 1. npm install"
185
+ echo " 2. npm run dev # start the API server"
186
+ echo " 3. /bober:plan # create your first plan"
187
+ echo " 4. /bober:sprint # run the first sprint"
188
+ elif [[ "$TEMPLATE" == "python-api" ]]; then
189
+ echo " 1. pip install -r requirements.txt # or: poetry install"
190
+ echo " 2. uvicorn app.main:app --reload # start the API server"
191
+ echo " 3. /bober:plan # create your first plan"
192
+ echo " 4. /bober:sprint # run the first sprint"
193
+ elif [[ "$TEMPLATE" == "brownfield" ]]; then
194
+ echo " 1. Review bober.config.json and update the 'commands' section"
195
+ echo " with your project's build, test, lint, and dev commands."
196
+ echo " 2. /bober:plan # create your first plan"
197
+ echo " 3. /bober:sprint # run the first sprint"
198
+ elif [[ "$TEMPLATE" == "base" ]]; then
199
+ echo " 1. Edit bober.config.json to match your project setup."
200
+ echo " 2. Edit CLAUDE.md with your project's conventions."
201
+ echo " 3. /bober:plan # create your first plan"
202
+ echo " 4. /bober:sprint # run the first sprint"
203
+ fi
204
+
205
+ echo ""
206
+ echo "Run /bober:plan to start planning your first feature."
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env bash
2
+ # ──────────────────────────────────────────────────────────────────────
3
+ # run-eval.sh — Run evaluation strategies from bober.config.json.
4
+ #
5
+ # Usage:
6
+ # bash scripts/run-eval.sh [project-dir]
7
+ #
8
+ # Reads bober.config.json to determine which strategies to run,
9
+ # executes each in order, and outputs a combined JSON result.
10
+ # ──────────────────────────────────────────────────────────────────────
11
+
12
+ set -euo pipefail
13
+
14
+ PROJECT_DIR="${1:-.}"
15
+ PROJECT_DIR="$(cd "$PROJECT_DIR" && pwd)"
16
+ CONFIG_FILE="$PROJECT_DIR/bober.config.json"
17
+
18
+ # ── Validate config ─────────────────────────────────────────────────
19
+
20
+ if [[ ! -f "$CONFIG_FILE" ]]; then
21
+ echo "Error: bober.config.json not found in $PROJECT_DIR" >&2
22
+ echo "Run 'bober init' or 'bash scripts/init-project.sh <template>' first." >&2
23
+ exit 1
24
+ fi
25
+
26
+ # ── Parse config ────────────────────────────────────────────────────
27
+ # We use lightweight parsing to avoid requiring jq as a dependency.
28
+ # For production use, the TypeScript evaluator handles full parsing.
29
+
30
+ # Extract commands from config
31
+ get_command() {
32
+ local key="$1"
33
+ local cmd
34
+ cmd=$(grep -o "\"$key\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" "$CONFIG_FILE" 2>/dev/null | head -1 | sed 's/.*:[[:space:]]*"\(.*\)"/\1/')
35
+ echo "$cmd"
36
+ }
37
+
38
+ CMD_BUILD="$(get_command "build")"
39
+ CMD_TEST="$(get_command "test")"
40
+ CMD_LINT="$(get_command "lint")"
41
+ CMD_TYPECHECK="$(get_command "typecheck")"
42
+
43
+ # ── Strategy Execution ──────────────────────────────────────────────
44
+
45
+ RESULTS=()
46
+ OVERALL_PASS=true
47
+ STRATEGY_COUNT=0
48
+ PASS_COUNT=0
49
+ FAIL_COUNT=0
50
+ SKIP_COUNT=0
51
+
52
+ run_strategy() {
53
+ local strategy_type="$1"
54
+ local required="$2"
55
+ local command="$3"
56
+ local status="skip"
57
+ local output=""
58
+ local exit_code=0
59
+
60
+ STRATEGY_COUNT=$((STRATEGY_COUNT + 1))
61
+
62
+ if [[ -z "$command" ]]; then
63
+ echo " [$strategy_type] SKIP — no command configured"
64
+ SKIP_COUNT=$((SKIP_COUNT + 1))
65
+ status="skip"
66
+ output="No command configured for $strategy_type"
67
+ else
68
+ echo " [$strategy_type] Running: $command"
69
+
70
+ set +e
71
+ output=$(cd "$PROJECT_DIR" && eval "$command" 2>&1)
72
+ exit_code=$?
73
+ set -e
74
+
75
+ if [[ $exit_code -eq 0 ]]; then
76
+ echo " [$strategy_type] PASS"
77
+ status="pass"
78
+ PASS_COUNT=$((PASS_COUNT + 1))
79
+ else
80
+ echo " [$strategy_type] FAIL (exit code $exit_code)"
81
+ status="fail"
82
+ FAIL_COUNT=$((FAIL_COUNT + 1))
83
+
84
+ if [[ "$required" == "true" ]]; then
85
+ OVERALL_PASS=false
86
+ fi
87
+ fi
88
+ fi
89
+
90
+ # Escape output for JSON (basic escaping)
91
+ output=$(echo "$output" | head -50 | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g' | tr '\n' ' ' | head -c 2000)
92
+
93
+ RESULTS+=("{\"strategy\":\"$strategy_type\",\"status\":\"$status\",\"required\":$required,\"exitCode\":$exit_code,\"output\":\"$output\"}")
94
+ }
95
+
96
+ echo ""
97
+ echo "Running evaluations in $PROJECT_DIR"
98
+ echo "──────────────────────────────────────────────────────"
99
+ echo ""
100
+
101
+ # ── Extract and run strategies ──────────────────────────────────────
102
+ # Parse the strategies array from config. We look for type/required pairs.
103
+
104
+ # Run strategies in canonical order: typecheck -> lint -> build -> unit-test -> playwright
105
+
106
+ if grep -q '"typecheck"' "$CONFIG_FILE" 2>/dev/null; then
107
+ required="true"
108
+ grep -q '"type"[[:space:]]*:[[:space:]]*"typecheck"' "$CONFIG_FILE" && \
109
+ grep -A1 '"typecheck"' "$CONFIG_FILE" | grep -q '"required"[[:space:]]*:[[:space:]]*false' && required="false"
110
+ run_strategy "typecheck" "$required" "$CMD_TYPECHECK"
111
+ fi
112
+
113
+ if grep -q '"type"[[:space:]]*:[[:space:]]*"lint"' "$CONFIG_FILE" 2>/dev/null; then
114
+ required="true"
115
+ grep -A1 '"lint"' "$CONFIG_FILE" | grep -q '"required"[[:space:]]*:[[:space:]]*false' && required="false"
116
+ run_strategy "lint" "$required" "$CMD_LINT"
117
+ fi
118
+
119
+ if grep -q '"type"[[:space:]]*:[[:space:]]*"build"' "$CONFIG_FILE" 2>/dev/null; then
120
+ required="true"
121
+ grep -A1 '"build"' "$CONFIG_FILE" | grep -q '"required"[[:space:]]*:[[:space:]]*false' && required="false"
122
+ run_strategy "build" "$required" "$CMD_BUILD"
123
+ fi
124
+
125
+ if grep -q '"type"[[:space:]]*:[[:space:]]*"unit-test"' "$CONFIG_FILE" 2>/dev/null; then
126
+ required="true"
127
+ grep -A1 '"unit-test"' "$CONFIG_FILE" | grep -q '"required"[[:space:]]*:[[:space:]]*false' && required="false"
128
+ run_strategy "unit-test" "$required" "$CMD_TEST"
129
+ fi
130
+
131
+ if grep -q '"type"[[:space:]]*:[[:space:]]*"playwright"' "$CONFIG_FILE" 2>/dev/null; then
132
+ required="false"
133
+ grep -A1 '"playwright"' "$CONFIG_FILE" | grep -q '"required"[[:space:]]*:[[:space:]]*true' && required="true"
134
+
135
+ PLAYWRIGHT_CMD=""
136
+ if [[ -f "$PROJECT_DIR/package.json" ]] && grep -q "playwright" "$PROJECT_DIR/package.json" 2>/dev/null; then
137
+ PLAYWRIGHT_CMD="npx playwright test"
138
+ fi
139
+ run_strategy "playwright" "$required" "$PLAYWRIGHT_CMD"
140
+ fi
141
+
142
+ # ── Output combined result ──────────────────────────────────────────
143
+
144
+ echo ""
145
+ echo "──────────────────────────────────────────────────────"
146
+
147
+ if [[ "$OVERALL_PASS" == "true" ]]; then
148
+ echo " RESULT: PASS ($PASS_COUNT passed, $FAIL_COUNT failed, $SKIP_COUNT skipped)"
149
+ else
150
+ echo " RESULT: FAIL ($PASS_COUNT passed, $FAIL_COUNT failed, $SKIP_COUNT skipped)"
151
+ fi
152
+
153
+ echo ""
154
+
155
+ # Build the JSON results array
156
+ RESULTS_JSON="["
157
+ for i in "${!RESULTS[@]}"; do
158
+ [[ $i -gt 0 ]] && RESULTS_JSON+=","
159
+ RESULTS_JSON+="${RESULTS[$i]}"
160
+ done
161
+ RESULTS_JSON+="]"
162
+
163
+ # Output combined result as JSON
164
+ cat <<EOF
165
+ {
166
+ "overall": "$( [[ "$OVERALL_PASS" == "true" ]] && echo "pass" || echo "fail" )",
167
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
168
+ "projectDir": "$PROJECT_DIR",
169
+ "strategiesRun": $STRATEGY_COUNT,
170
+ "passed": $PASS_COUNT,
171
+ "failed": $FAIL_COUNT,
172
+ "skipped": $SKIP_COUNT,
173
+ "results": $RESULTS_JSON
174
+ }
175
+ EOF