@runchr/gstack-antigravity 0.1.1 → 0.1.3

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.

Potentially problematic release.


This version of @runchr/gstack-antigravity might be problematic. Click here for more details.

Files changed (229) hide show
  1. package/.agents/skills/gstack/.agents/skills/gstack/SKILL.md +651 -0
  2. package/.agents/skills/gstack/.agents/skills/gstack-autoplan/SKILL.md +678 -0
  3. package/.agents/skills/gstack/.agents/skills/gstack-benchmark/SKILL.md +482 -0
  4. package/.agents/skills/gstack/.agents/skills/gstack-browse/SKILL.md +511 -0
  5. package/.agents/skills/gstack/.agents/skills/gstack-canary/SKILL.md +486 -0
  6. package/.agents/skills/gstack/.agents/skills/gstack-careful/SKILL.md +50 -0
  7. package/.agents/skills/gstack/.agents/skills/gstack-cso/SKILL.md +607 -0
  8. package/.agents/skills/gstack/.agents/skills/gstack-design-consultation/SKILL.md +615 -0
  9. package/.agents/skills/gstack/.agents/skills/gstack-design-review/SKILL.md +988 -0
  10. package/.agents/skills/gstack/.agents/skills/gstack-document-release/SKILL.md +604 -0
  11. package/.agents/skills/gstack/.agents/skills/gstack-freeze/SKILL.md +67 -0
  12. package/.agents/skills/gstack/.agents/skills/gstack-guard/SKILL.md +62 -0
  13. package/.agents/skills/gstack/.agents/skills/gstack-investigate/SKILL.md +415 -0
  14. package/.agents/skills/gstack/.agents/skills/gstack-land-and-deploy/SKILL.md +873 -0
  15. package/.agents/skills/gstack/.agents/skills/gstack-office-hours/SKILL.md +986 -0
  16. package/.agents/skills/gstack/.agents/skills/gstack-plan-ceo-review/SKILL.md +1268 -0
  17. package/.agents/skills/gstack/.agents/skills/gstack-plan-design-review/SKILL.md +668 -0
  18. package/.agents/skills/gstack/.agents/skills/gstack-plan-eng-review/SKILL.md +826 -0
  19. package/.agents/skills/gstack/.agents/skills/gstack-qa/SKILL.md +1006 -0
  20. package/.agents/skills/gstack/.agents/skills/gstack-qa-only/SKILL.md +626 -0
  21. package/.agents/skills/gstack/.agents/skills/gstack-retro/SKILL.md +1065 -0
  22. package/.agents/skills/gstack/.agents/skills/gstack-review/SKILL.md +704 -0
  23. package/.agents/skills/gstack/.agents/skills/gstack-setup-browser-cookies/SKILL.md +325 -0
  24. package/.agents/skills/gstack/.agents/skills/gstack-setup-deploy/SKILL.md +450 -0
  25. package/.agents/skills/gstack/.agents/skills/gstack-ship/SKILL.md +1312 -0
  26. package/.agents/skills/gstack/.agents/skills/gstack-unfreeze/SKILL.md +36 -0
  27. package/.agents/skills/gstack/.agents/skills/gstack-upgrade/SKILL.md +220 -0
  28. package/.agents/skills/gstack/.env.example +5 -0
  29. package/.agents/skills/gstack/.github/workflows/skill-docs.yml +17 -0
  30. package/.agents/skills/gstack/AGENTS.md +49 -0
  31. package/.agents/skills/gstack/ARCHITECTURE.md +359 -0
  32. package/.agents/skills/gstack/BROWSER.md +271 -0
  33. package/.agents/skills/gstack/CHANGELOG.md +800 -0
  34. package/.agents/skills/gstack/CLAUDE.md +284 -0
  35. package/.agents/skills/gstack/CONTRIBUTING.md +370 -0
  36. package/.agents/skills/gstack/ETHOS.md +129 -0
  37. package/.agents/skills/gstack/LICENSE +21 -0
  38. package/.agents/skills/gstack/README.md +228 -0
  39. package/.agents/skills/gstack/SKILL.md +657 -0
  40. package/.agents/skills/gstack/SKILL.md.tmpl +281 -0
  41. package/.agents/skills/gstack/TODOS.md +564 -0
  42. package/.agents/skills/gstack/VERSION +1 -0
  43. package/.agents/skills/gstack/autoplan/SKILL.md +689 -0
  44. package/.agents/skills/gstack/autoplan/SKILL.md.tmpl +416 -0
  45. package/.agents/skills/gstack/benchmark/SKILL.md +489 -0
  46. package/.agents/skills/gstack/benchmark/SKILL.md.tmpl +233 -0
  47. package/.agents/skills/gstack/bin/dev-setup +68 -0
  48. package/.agents/skills/gstack/bin/dev-teardown +56 -0
  49. package/.agents/skills/gstack/bin/gstack-analytics +191 -0
  50. package/.agents/skills/gstack/bin/gstack-community-dashboard +113 -0
  51. package/.agents/skills/gstack/bin/gstack-config +38 -0
  52. package/.agents/skills/gstack/bin/gstack-diff-scope +71 -0
  53. package/.agents/skills/gstack/bin/gstack-global-discover.ts +591 -0
  54. package/.agents/skills/gstack/bin/gstack-repo-mode +93 -0
  55. package/.agents/skills/gstack/bin/gstack-review-log +9 -0
  56. package/.agents/skills/gstack/bin/gstack-review-read +12 -0
  57. package/.agents/skills/gstack/bin/gstack-slug +15 -0
  58. package/.agents/skills/gstack/bin/gstack-telemetry-log +158 -0
  59. package/.agents/skills/gstack/bin/gstack-telemetry-sync +127 -0
  60. package/.agents/skills/gstack/bin/gstack-update-check +196 -0
  61. package/.agents/skills/gstack/browse/SKILL.md +517 -0
  62. package/.agents/skills/gstack/browse/SKILL.md.tmpl +141 -0
  63. package/.agents/skills/gstack/browse/bin/find-browse +21 -0
  64. package/.agents/skills/gstack/browse/bin/remote-slug +14 -0
  65. package/.agents/skills/gstack/browse/scripts/build-node-server.sh +48 -0
  66. package/.agents/skills/gstack/browse/src/browser-manager.ts +634 -0
  67. package/.agents/skills/gstack/browse/src/buffers.ts +137 -0
  68. package/.agents/skills/gstack/browse/src/bun-polyfill.cjs +109 -0
  69. package/.agents/skills/gstack/browse/src/cli.ts +420 -0
  70. package/.agents/skills/gstack/browse/src/commands.ts +111 -0
  71. package/.agents/skills/gstack/browse/src/config.ts +150 -0
  72. package/.agents/skills/gstack/browse/src/cookie-import-browser.ts +417 -0
  73. package/.agents/skills/gstack/browse/src/cookie-picker-routes.ts +207 -0
  74. package/.agents/skills/gstack/browse/src/cookie-picker-ui.ts +541 -0
  75. package/.agents/skills/gstack/browse/src/find-browse.ts +61 -0
  76. package/.agents/skills/gstack/browse/src/meta-commands.ts +269 -0
  77. package/.agents/skills/gstack/browse/src/platform.ts +17 -0
  78. package/.agents/skills/gstack/browse/src/read-commands.ts +335 -0
  79. package/.agents/skills/gstack/browse/src/server.ts +369 -0
  80. package/.agents/skills/gstack/browse/src/snapshot.ts +398 -0
  81. package/.agents/skills/gstack/browse/src/url-validation.ts +91 -0
  82. package/.agents/skills/gstack/browse/src/write-commands.ts +352 -0
  83. package/.agents/skills/gstack/browse/test/bun-polyfill.test.ts +72 -0
  84. package/.agents/skills/gstack/browse/test/commands.test.ts +1836 -0
  85. package/.agents/skills/gstack/browse/test/config.test.ts +250 -0
  86. package/.agents/skills/gstack/browse/test/cookie-import-browser.test.ts +397 -0
  87. package/.agents/skills/gstack/browse/test/cookie-picker-routes.test.ts +205 -0
  88. package/.agents/skills/gstack/browse/test/find-browse.test.ts +50 -0
  89. package/.agents/skills/gstack/browse/test/fixtures/basic.html +33 -0
  90. package/.agents/skills/gstack/browse/test/fixtures/cursor-interactive.html +22 -0
  91. package/.agents/skills/gstack/browse/test/fixtures/dialog.html +15 -0
  92. package/.agents/skills/gstack/browse/test/fixtures/empty.html +2 -0
  93. package/.agents/skills/gstack/browse/test/fixtures/forms.html +55 -0
  94. package/.agents/skills/gstack/browse/test/fixtures/qa-eval-checkout.html +108 -0
  95. package/.agents/skills/gstack/browse/test/fixtures/qa-eval-spa.html +98 -0
  96. package/.agents/skills/gstack/browse/test/fixtures/qa-eval.html +51 -0
  97. package/.agents/skills/gstack/browse/test/fixtures/responsive.html +49 -0
  98. package/.agents/skills/gstack/browse/test/fixtures/snapshot.html +55 -0
  99. package/.agents/skills/gstack/browse/test/fixtures/spa.html +24 -0
  100. package/.agents/skills/gstack/browse/test/fixtures/states.html +17 -0
  101. package/.agents/skills/gstack/browse/test/fixtures/upload.html +25 -0
  102. package/.agents/skills/gstack/browse/test/gstack-config.test.ts +125 -0
  103. package/.agents/skills/gstack/browse/test/gstack-update-check.test.ts +467 -0
  104. package/.agents/skills/gstack/browse/test/handoff.test.ts +235 -0
  105. package/.agents/skills/gstack/browse/test/path-validation.test.ts +63 -0
  106. package/.agents/skills/gstack/browse/test/platform.test.ts +37 -0
  107. package/.agents/skills/gstack/browse/test/snapshot.test.ts +467 -0
  108. package/.agents/skills/gstack/browse/test/test-server.ts +57 -0
  109. package/.agents/skills/gstack/browse/test/url-validation.test.ts +72 -0
  110. package/.agents/skills/gstack/canary/SKILL.md +493 -0
  111. package/.agents/skills/gstack/canary/SKILL.md.tmpl +220 -0
  112. package/.agents/skills/gstack/careful/SKILL.md +59 -0
  113. package/.agents/skills/gstack/careful/SKILL.md.tmpl +57 -0
  114. package/.agents/skills/gstack/careful/bin/check-careful.sh +112 -0
  115. package/.agents/skills/gstack/codex/SKILL.md +677 -0
  116. package/.agents/skills/gstack/codex/SKILL.md.tmpl +356 -0
  117. package/.agents/skills/gstack/conductor.json +6 -0
  118. package/.agents/skills/gstack/cso/SKILL.md +615 -0
  119. package/.agents/skills/gstack/cso/SKILL.md.tmpl +376 -0
  120. package/.agents/skills/gstack/design-consultation/SKILL.md +625 -0
  121. package/.agents/skills/gstack/design-consultation/SKILL.md.tmpl +369 -0
  122. package/.agents/skills/gstack/design-review/SKILL.md +998 -0
  123. package/.agents/skills/gstack/design-review/SKILL.md.tmpl +262 -0
  124. package/.agents/skills/gstack/docs/images/github-2013.png +0 -0
  125. package/.agents/skills/gstack/docs/images/github-2026.png +0 -0
  126. package/.agents/skills/gstack/docs/skills.md +877 -0
  127. package/.agents/skills/gstack/document-release/SKILL.md +613 -0
  128. package/.agents/skills/gstack/document-release/SKILL.md.tmpl +357 -0
  129. package/.agents/skills/gstack/freeze/SKILL.md +82 -0
  130. package/.agents/skills/gstack/freeze/SKILL.md.tmpl +80 -0
  131. package/.agents/skills/gstack/freeze/bin/check-freeze.sh +68 -0
  132. package/.agents/skills/gstack/gstack-upgrade/SKILL.md +226 -0
  133. package/.agents/skills/gstack/gstack-upgrade/SKILL.md.tmpl +224 -0
  134. package/.agents/skills/gstack/guard/SKILL.md +82 -0
  135. package/.agents/skills/gstack/guard/SKILL.md.tmpl +80 -0
  136. package/.agents/skills/gstack/investigate/SKILL.md +435 -0
  137. package/.agents/skills/gstack/investigate/SKILL.md.tmpl +196 -0
  138. package/.agents/skills/gstack/land-and-deploy/SKILL.md +880 -0
  139. package/.agents/skills/gstack/land-and-deploy/SKILL.md.tmpl +575 -0
  140. package/.agents/skills/gstack/office-hours/SKILL.md +996 -0
  141. package/.agents/skills/gstack/office-hours/SKILL.md.tmpl +624 -0
  142. package/.agents/skills/gstack/package.json +55 -0
  143. package/.agents/skills/gstack/plan-ceo-review/SKILL.md +1277 -0
  144. package/.agents/skills/gstack/plan-ceo-review/SKILL.md.tmpl +838 -0
  145. package/.agents/skills/gstack/plan-design-review/SKILL.md +676 -0
  146. package/.agents/skills/gstack/plan-design-review/SKILL.md.tmpl +314 -0
  147. package/.agents/skills/gstack/plan-eng-review/SKILL.md +836 -0
  148. package/.agents/skills/gstack/plan-eng-review/SKILL.md.tmpl +279 -0
  149. package/.agents/skills/gstack/qa/SKILL.md +1016 -0
  150. package/.agents/skills/gstack/qa/SKILL.md.tmpl +316 -0
  151. package/.agents/skills/gstack/qa/references/issue-taxonomy.md +85 -0
  152. package/.agents/skills/gstack/qa/templates/qa-report-template.md +126 -0
  153. package/.agents/skills/gstack/qa-only/SKILL.md +633 -0
  154. package/.agents/skills/gstack/qa-only/SKILL.md.tmpl +101 -0
  155. package/.agents/skills/gstack/retro/SKILL.md +1072 -0
  156. package/.agents/skills/gstack/retro/SKILL.md.tmpl +833 -0
  157. package/.agents/skills/gstack/review/SKILL.md +849 -0
  158. package/.agents/skills/gstack/review/SKILL.md.tmpl +259 -0
  159. package/.agents/skills/gstack/review/TODOS-format.md +62 -0
  160. package/.agents/skills/gstack/review/checklist.md +190 -0
  161. package/.agents/skills/gstack/review/design-checklist.md +132 -0
  162. package/.agents/skills/gstack/review/greptile-triage.md +220 -0
  163. package/.agents/skills/gstack/scripts/analytics.ts +190 -0
  164. package/.agents/skills/gstack/scripts/dev-skill.ts +82 -0
  165. package/.agents/skills/gstack/scripts/eval-compare.ts +96 -0
  166. package/.agents/skills/gstack/scripts/eval-list.ts +116 -0
  167. package/.agents/skills/gstack/scripts/eval-select.ts +86 -0
  168. package/.agents/skills/gstack/scripts/eval-summary.ts +187 -0
  169. package/.agents/skills/gstack/scripts/eval-watch.ts +172 -0
  170. package/.agents/skills/gstack/scripts/gen-skill-docs.ts +2414 -0
  171. package/.agents/skills/gstack/scripts/skill-check.ts +167 -0
  172. package/.agents/skills/gstack/setup +269 -0
  173. package/.agents/skills/gstack/setup-browser-cookies/SKILL.md +330 -0
  174. package/.agents/skills/gstack/setup-browser-cookies/SKILL.md.tmpl +74 -0
  175. package/.agents/skills/gstack/setup-deploy/SKILL.md +459 -0
  176. package/.agents/skills/gstack/setup-deploy/SKILL.md.tmpl +220 -0
  177. package/.agents/skills/gstack/ship/SKILL.md +1457 -0
  178. package/.agents/skills/gstack/ship/SKILL.md.tmpl +528 -0
  179. package/.agents/skills/gstack/supabase/config.sh +10 -0
  180. package/.agents/skills/gstack/supabase/functions/community-pulse/index.ts +59 -0
  181. package/.agents/skills/gstack/supabase/functions/telemetry-ingest/index.ts +135 -0
  182. package/.agents/skills/gstack/supabase/functions/update-check/index.ts +37 -0
  183. package/.agents/skills/gstack/supabase/migrations/001_telemetry.sql +89 -0
  184. package/.agents/skills/gstack/test/analytics.test.ts +277 -0
  185. package/.agents/skills/gstack/test/codex-e2e.test.ts +197 -0
  186. package/.agents/skills/gstack/test/fixtures/coverage-audit-fixture.ts +76 -0
  187. package/.agents/skills/gstack/test/fixtures/eval-baselines.json +7 -0
  188. package/.agents/skills/gstack/test/fixtures/qa-eval-checkout-ground-truth.json +43 -0
  189. package/.agents/skills/gstack/test/fixtures/qa-eval-ground-truth.json +43 -0
  190. package/.agents/skills/gstack/test/fixtures/qa-eval-spa-ground-truth.json +43 -0
  191. package/.agents/skills/gstack/test/fixtures/review-eval-design-slop.css +86 -0
  192. package/.agents/skills/gstack/test/fixtures/review-eval-design-slop.html +41 -0
  193. package/.agents/skills/gstack/test/fixtures/review-eval-enum-diff.rb +30 -0
  194. package/.agents/skills/gstack/test/fixtures/review-eval-enum.rb +27 -0
  195. package/.agents/skills/gstack/test/fixtures/review-eval-vuln.rb +14 -0
  196. package/.agents/skills/gstack/test/gemini-e2e.test.ts +173 -0
  197. package/.agents/skills/gstack/test/gen-skill-docs.test.ts +1049 -0
  198. package/.agents/skills/gstack/test/global-discover.test.ts +187 -0
  199. package/.agents/skills/gstack/test/helpers/codex-session-runner.ts +282 -0
  200. package/.agents/skills/gstack/test/helpers/e2e-helpers.ts +239 -0
  201. package/.agents/skills/gstack/test/helpers/eval-store.test.ts +548 -0
  202. package/.agents/skills/gstack/test/helpers/eval-store.ts +689 -0
  203. package/.agents/skills/gstack/test/helpers/gemini-session-runner.test.ts +104 -0
  204. package/.agents/skills/gstack/test/helpers/gemini-session-runner.ts +201 -0
  205. package/.agents/skills/gstack/test/helpers/llm-judge.ts +130 -0
  206. package/.agents/skills/gstack/test/helpers/observability.test.ts +283 -0
  207. package/.agents/skills/gstack/test/helpers/session-runner.test.ts +96 -0
  208. package/.agents/skills/gstack/test/helpers/session-runner.ts +357 -0
  209. package/.agents/skills/gstack/test/helpers/skill-parser.ts +206 -0
  210. package/.agents/skills/gstack/test/helpers/touchfiles.ts +260 -0
  211. package/.agents/skills/gstack/test/hook-scripts.test.ts +373 -0
  212. package/.agents/skills/gstack/test/skill-e2e-browse.test.ts +293 -0
  213. package/.agents/skills/gstack/test/skill-e2e-deploy.test.ts +279 -0
  214. package/.agents/skills/gstack/test/skill-e2e-design.test.ts +614 -0
  215. package/.agents/skills/gstack/test/skill-e2e-plan.test.ts +538 -0
  216. package/.agents/skills/gstack/test/skill-e2e-qa-bugs.test.ts +194 -0
  217. package/.agents/skills/gstack/test/skill-e2e-qa-workflow.test.ts +412 -0
  218. package/.agents/skills/gstack/test/skill-e2e-review.test.ts +535 -0
  219. package/.agents/skills/gstack/test/skill-e2e-workflow.test.ts +586 -0
  220. package/.agents/skills/gstack/test/skill-e2e.test.ts +3325 -0
  221. package/.agents/skills/gstack/test/skill-llm-eval.test.ts +787 -0
  222. package/.agents/skills/gstack/test/skill-parser.test.ts +179 -0
  223. package/.agents/skills/gstack/test/skill-routing-e2e.test.ts +605 -0
  224. package/.agents/skills/gstack/test/skill-validation.test.ts +1520 -0
  225. package/.agents/skills/gstack/test/telemetry.test.ts +278 -0
  226. package/.agents/skills/gstack/test/touchfiles.test.ts +262 -0
  227. package/.agents/skills/gstack/unfreeze/SKILL.md +40 -0
  228. package/.agents/skills/gstack/unfreeze/SKILL.md.tmpl +38 -0
  229. package/package.json +2 -1
@@ -0,0 +1,535 @@
1
+ import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
2
+ import { runSkillTest } from './helpers/session-runner';
3
+ import {
4
+ ROOT, browseBin, runId, evalsEnabled, selectedTests,
5
+ describeIfSelected, testConcurrentIfSelected,
6
+ copyDirSync, setupBrowseShims, logCost, recordE2E,
7
+ createEvalCollector, finalizeEvalCollector,
8
+ } from './helpers/e2e-helpers';
9
+ import { spawnSync } from 'child_process';
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ import * as os from 'os';
13
+
14
+ const evalCollector = createEvalCollector('e2e-review');
15
+
16
+ // --- B5: Review skill E2E ---
17
+
18
+ describeIfSelected('Review skill E2E', ['review-sql-injection'], () => {
19
+ let reviewDir: string;
20
+
21
+ beforeAll(() => {
22
+ reviewDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-e2e-review-'));
23
+
24
+ // Pre-build a git repo with a vulnerable file on a feature branch (decision 5A)
25
+ const run = (cmd: string, args: string[]) =>
26
+ spawnSync(cmd, args, { cwd: reviewDir, stdio: 'pipe', timeout: 5000 });
27
+
28
+ run('git', ['init', '-b', 'main']);
29
+ run('git', ['config', 'user.email', 'test@test.com']);
30
+ run('git', ['config', 'user.name', 'Test']);
31
+
32
+ // Commit a clean base on main
33
+ fs.writeFileSync(path.join(reviewDir, 'app.rb'), '# clean base\nclass App\nend\n');
34
+ run('git', ['add', 'app.rb']);
35
+ run('git', ['commit', '-m', 'initial commit']);
36
+
37
+ // Create feature branch with vulnerable code
38
+ run('git', ['checkout', '-b', 'feature/add-user-controller']);
39
+ const vulnContent = fs.readFileSync(path.join(ROOT, 'test', 'fixtures', 'review-eval-vuln.rb'), 'utf-8');
40
+ fs.writeFileSync(path.join(reviewDir, 'user_controller.rb'), vulnContent);
41
+ run('git', ['add', 'user_controller.rb']);
42
+ run('git', ['commit', '-m', 'add user controller']);
43
+
44
+ // Copy review skill files
45
+ fs.copyFileSync(path.join(ROOT, 'review', 'SKILL.md'), path.join(reviewDir, 'review-SKILL.md'));
46
+ fs.copyFileSync(path.join(ROOT, 'review', 'checklist.md'), path.join(reviewDir, 'review-checklist.md'));
47
+ fs.copyFileSync(path.join(ROOT, 'review', 'greptile-triage.md'), path.join(reviewDir, 'review-greptile-triage.md'));
48
+ });
49
+
50
+ afterAll(() => {
51
+ try { fs.rmSync(reviewDir, { recursive: true, force: true }); } catch {}
52
+ });
53
+
54
+ test('/review produces findings on SQL injection branch', async () => {
55
+ const result = await runSkillTest({
56
+ prompt: `You are in a git repo on a feature branch with changes against main.
57
+ Read review-SKILL.md for the review workflow instructions.
58
+ Also read review-checklist.md and apply it.
59
+ Skip the preamble bash block, lake intro, telemetry, and contributor mode sections — go straight to the review.
60
+ Run /review on the current diff (git diff main...HEAD).
61
+ Write your review findings to ${reviewDir}/review-output.md`,
62
+ workingDirectory: reviewDir,
63
+ maxTurns: 20,
64
+ timeout: 180_000,
65
+ testName: 'review-sql-injection',
66
+ runId,
67
+ });
68
+
69
+ logCost('/review', result);
70
+ recordE2E(evalCollector, '/review SQL injection', 'Review skill E2E', result);
71
+ expect(result.exitReason).toBe('success');
72
+
73
+ // Verify the review output mentions SQL injection-related findings
74
+ const reviewOutputPath = path.join(reviewDir, 'review-output.md');
75
+ if (fs.existsSync(reviewOutputPath)) {
76
+ const reviewContent = fs.readFileSync(reviewOutputPath, 'utf-8').toLowerCase();
77
+ const hasSqlContent =
78
+ reviewContent.includes('sql') ||
79
+ reviewContent.includes('injection') ||
80
+ reviewContent.includes('sanitiz') ||
81
+ reviewContent.includes('parameteriz') ||
82
+ reviewContent.includes('interpolat') ||
83
+ reviewContent.includes('user_input') ||
84
+ reviewContent.includes('unsanitized');
85
+ expect(hasSqlContent).toBe(true);
86
+ }
87
+ }, 210_000);
88
+ });
89
+
90
+ // --- Review: Enum completeness E2E ---
91
+
92
+ describeIfSelected('Review enum completeness E2E', ['review-enum-completeness'], () => {
93
+ let enumDir: string;
94
+
95
+ beforeAll(() => {
96
+ enumDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-e2e-enum-'));
97
+
98
+ const run = (cmd: string, args: string[]) =>
99
+ spawnSync(cmd, args, { cwd: enumDir, stdio: 'pipe', timeout: 5000 });
100
+
101
+ run('git', ['init', '-b', 'main']);
102
+ run('git', ['config', 'user.email', 'test@test.com']);
103
+ run('git', ['config', 'user.name', 'Test']);
104
+
105
+ // Commit baseline on main — order model with 4 statuses
106
+ const baseContent = fs.readFileSync(path.join(ROOT, 'test', 'fixtures', 'review-eval-enum.rb'), 'utf-8');
107
+ fs.writeFileSync(path.join(enumDir, 'order.rb'), baseContent);
108
+ run('git', ['add', 'order.rb']);
109
+ run('git', ['commit', '-m', 'initial order model']);
110
+
111
+ // Feature branch adds "returned" status but misses handlers
112
+ run('git', ['checkout', '-b', 'feature/add-returned-status']);
113
+ const diffContent = fs.readFileSync(path.join(ROOT, 'test', 'fixtures', 'review-eval-enum-diff.rb'), 'utf-8');
114
+ fs.writeFileSync(path.join(enumDir, 'order.rb'), diffContent);
115
+ run('git', ['add', 'order.rb']);
116
+ run('git', ['commit', '-m', 'add returned status']);
117
+
118
+ // Copy review skill files
119
+ fs.copyFileSync(path.join(ROOT, 'review', 'SKILL.md'), path.join(enumDir, 'review-SKILL.md'));
120
+ fs.copyFileSync(path.join(ROOT, 'review', 'checklist.md'), path.join(enumDir, 'review-checklist.md'));
121
+ fs.copyFileSync(path.join(ROOT, 'review', 'greptile-triage.md'), path.join(enumDir, 'review-greptile-triage.md'));
122
+ });
123
+
124
+ afterAll(() => {
125
+ try { fs.rmSync(enumDir, { recursive: true, force: true }); } catch {}
126
+ });
127
+
128
+ test('/review catches missing enum handlers for new status value', async () => {
129
+ const result = await runSkillTest({
130
+ prompt: `You are in a git repo on branch feature/add-returned-status with changes against main.
131
+ Read review-SKILL.md for the review workflow instructions.
132
+ Also read review-checklist.md and apply it — pay special attention to the Enum & Value Completeness section.
133
+ Run /review on the current diff (git diff main...HEAD).
134
+ Write your review findings to ${enumDir}/review-output.md
135
+
136
+ The diff adds a new "returned" status to the Order model. Your job is to check if all consumers handle it.`,
137
+ workingDirectory: enumDir,
138
+ maxTurns: 15,
139
+ timeout: 90_000,
140
+ testName: 'review-enum-completeness',
141
+ runId,
142
+ });
143
+
144
+ logCost('/review enum', result);
145
+ recordE2E(evalCollector, '/review enum completeness', 'Review enum completeness E2E', result);
146
+ expect(result.exitReason).toBe('success');
147
+
148
+ // Verify the review caught the missing enum handlers
149
+ const reviewPath = path.join(enumDir, 'review-output.md');
150
+ if (fs.existsSync(reviewPath)) {
151
+ const review = fs.readFileSync(reviewPath, 'utf-8');
152
+ // Should mention the missing "returned" handling in at least one of the methods
153
+ const mentionsReturned = review.toLowerCase().includes('returned');
154
+ const mentionsEnum = review.toLowerCase().includes('enum') || review.toLowerCase().includes('status');
155
+ const mentionsCritical = review.toLowerCase().includes('critical');
156
+ expect(mentionsReturned).toBe(true);
157
+ expect(mentionsEnum || mentionsCritical).toBe(true);
158
+ }
159
+ }, 120_000);
160
+ });
161
+
162
+ // --- Review: Design review lite E2E ---
163
+
164
+ describeIfSelected('Review design lite E2E', ['review-design-lite'], () => {
165
+ let designDir: string;
166
+
167
+ beforeAll(() => {
168
+ designDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-e2e-design-lite-'));
169
+
170
+ const run = (cmd: string, args: string[]) =>
171
+ spawnSync(cmd, args, { cwd: designDir, stdio: 'pipe', timeout: 5000 });
172
+
173
+ run('git', ['init', '-b', 'main']);
174
+ run('git', ['config', 'user.email', 'test@test.com']);
175
+ run('git', ['config', 'user.name', 'Test']);
176
+
177
+ // Commit clean base on main
178
+ fs.writeFileSync(path.join(designDir, 'index.html'), '<h1>Clean</h1>\n');
179
+ fs.writeFileSync(path.join(designDir, 'styles.css'), 'body { font-size: 16px; }\n');
180
+ run('git', ['add', '.']);
181
+ run('git', ['commit', '-m', 'initial']);
182
+
183
+ // Feature branch adds AI slop CSS + HTML
184
+ run('git', ['checkout', '-b', 'feature/add-landing-page']);
185
+ const slopCss = fs.readFileSync(path.join(ROOT, 'test', 'fixtures', 'review-eval-design-slop.css'), 'utf-8');
186
+ const slopHtml = fs.readFileSync(path.join(ROOT, 'test', 'fixtures', 'review-eval-design-slop.html'), 'utf-8');
187
+ fs.writeFileSync(path.join(designDir, 'styles.css'), slopCss);
188
+ fs.writeFileSync(path.join(designDir, 'landing.html'), slopHtml);
189
+ run('git', ['add', '.']);
190
+ run('git', ['commit', '-m', 'add landing page']);
191
+
192
+ // Copy review skill files
193
+ fs.copyFileSync(path.join(ROOT, 'review', 'SKILL.md'), path.join(designDir, 'review-SKILL.md'));
194
+ fs.copyFileSync(path.join(ROOT, 'review', 'checklist.md'), path.join(designDir, 'review-checklist.md'));
195
+ fs.copyFileSync(path.join(ROOT, 'review', 'design-checklist.md'), path.join(designDir, 'review-design-checklist.md'));
196
+ fs.copyFileSync(path.join(ROOT, 'review', 'greptile-triage.md'), path.join(designDir, 'review-greptile-triage.md'));
197
+ });
198
+
199
+ afterAll(() => {
200
+ try { fs.rmSync(designDir, { recursive: true, force: true }); } catch {}
201
+ });
202
+
203
+ test('/review catches design anti-patterns in CSS/HTML diff', async () => {
204
+ const result = await runSkillTest({
205
+ prompt: `You are in a git repo on branch feature/add-landing-page with changes against main.
206
+ Read review-SKILL.md for the review workflow instructions.
207
+ Read review-checklist.md for the code review checklist.
208
+ Read review-design-checklist.md for the design review checklist.
209
+ Run /review on the current diff (git diff main...HEAD).
210
+
211
+ Skip the preamble bash block, lake intro, telemetry, and contributor mode sections — go straight to the review.
212
+
213
+ The diff adds a landing page with CSS and HTML. Check for both code issues AND design anti-patterns.
214
+ Write your review findings to ${designDir}/review-output.md
215
+
216
+ Important: The design checklist should catch issues like blacklisted fonts, small font sizes, outline:none, !important, AI slop patterns (purple gradients, generic hero copy, 3-column feature grid), etc.`,
217
+ workingDirectory: designDir,
218
+ maxTurns: 35,
219
+ timeout: 240_000,
220
+ testName: 'review-design-lite',
221
+ runId,
222
+ });
223
+
224
+ logCost('/review design lite', result);
225
+ recordE2E(evalCollector, '/review design lite', 'Review design lite E2E', result);
226
+ expect(result.exitReason).toBe('success');
227
+
228
+ // Verify the review caught at least 4 of 7 planted design issues
229
+ const reviewPath = path.join(designDir, 'review-output.md');
230
+ if (fs.existsSync(reviewPath)) {
231
+ const review = fs.readFileSync(reviewPath, 'utf-8').toLowerCase();
232
+ let detected = 0;
233
+
234
+ // Issue 1: Blacklisted font (Papyrus) — HIGH
235
+ if (review.includes('papyrus') || review.includes('blacklisted font') || review.includes('font family')) detected++;
236
+ // Issue 2: Body text < 16px — HIGH
237
+ if (review.includes('14px') || review.includes('font-size') || review.includes('font size') || review.includes('body text')) detected++;
238
+ // Issue 3: outline: none — HIGH
239
+ if (review.includes('outline') || review.includes('focus')) detected++;
240
+ // Issue 4: !important — HIGH
241
+ if (review.includes('!important') || review.includes('important')) detected++;
242
+ // Issue 5: Purple gradient — MEDIUM
243
+ if (review.includes('gradient') || review.includes('purple') || review.includes('violet') || review.includes('#6366f1') || review.includes('#8b5cf6')) detected++;
244
+ // Issue 6: Generic hero copy — MEDIUM
245
+ if (review.includes('welcome to') || review.includes('all-in-one') || review.includes('generic') || review.includes('hero copy') || review.includes('ai slop')) detected++;
246
+ // Issue 7: 3-column feature grid — LOW
247
+ if (review.includes('3-column') || review.includes('three-column') || review.includes('feature grid') || review.includes('icon') || review.includes('circle')) detected++;
248
+
249
+ console.log(`Design review detected ${detected}/7 planted issues`);
250
+ expect(detected).toBeGreaterThanOrEqual(4);
251
+ }
252
+ }, 300_000);
253
+ });
254
+
255
+ // --- Base branch detection smoke tests ---
256
+
257
+ describeIfSelected('Base branch detection', ['review-base-branch', 'ship-base-branch', 'retro-base-branch'], () => {
258
+ let baseBranchDir: string;
259
+ const run = (cmd: string, args: string[], cwd: string) =>
260
+ spawnSync(cmd, args, { cwd, stdio: 'pipe', timeout: 5000 });
261
+
262
+ beforeAll(() => {
263
+ baseBranchDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-e2e-basebranch-'));
264
+ });
265
+
266
+ afterAll(() => {
267
+ try { fs.rmSync(baseBranchDir, { recursive: true, force: true }); } catch {}
268
+ });
269
+
270
+ testConcurrentIfSelected('review-base-branch', async () => {
271
+ const dir = path.join(baseBranchDir, 'review-base');
272
+ fs.mkdirSync(dir, { recursive: true });
273
+
274
+ // Create git repo with a feature branch off main
275
+ run('git', ['init'], dir);
276
+ run('git', ['config', 'user.email', 'test@test.com'], dir);
277
+ run('git', ['config', 'user.name', 'Test'], dir);
278
+
279
+ fs.writeFileSync(path.join(dir, 'app.rb'), '# clean base\nclass App\nend\n');
280
+ run('git', ['add', 'app.rb'], dir);
281
+ run('git', ['commit', '-m', 'initial commit'], dir);
282
+
283
+ // Create feature branch with a change
284
+ run('git', ['checkout', '-b', 'feature/test-review'], dir);
285
+ fs.writeFileSync(path.join(dir, 'app.rb'), '# clean base\nclass App\n def hello; "world"; end\nend\n');
286
+ run('git', ['add', 'app.rb'], dir);
287
+ run('git', ['commit', '-m', 'feat: add hello method'], dir);
288
+
289
+ // Copy review skill files
290
+ fs.copyFileSync(path.join(ROOT, 'review', 'SKILL.md'), path.join(dir, 'review-SKILL.md'));
291
+ fs.copyFileSync(path.join(ROOT, 'review', 'checklist.md'), path.join(dir, 'review-checklist.md'));
292
+ fs.copyFileSync(path.join(ROOT, 'review', 'greptile-triage.md'), path.join(dir, 'review-greptile-triage.md'));
293
+
294
+ const result = await runSkillTest({
295
+ prompt: `You are in a git repo on a feature branch with changes.
296
+ Read review-SKILL.md for the review workflow instructions.
297
+ Also read review-checklist.md and apply it.
298
+
299
+ IMPORTANT: Follow Step 0 to detect the base branch. Since there is no remote, gh commands will fail — fall back to main.
300
+ Then run the review against the detected base branch.
301
+ Write your findings to ${dir}/review-output.md`,
302
+ workingDirectory: dir,
303
+ maxTurns: 15,
304
+ timeout: 90_000,
305
+ testName: 'review-base-branch',
306
+ runId,
307
+ });
308
+
309
+ logCost('/review base-branch', result);
310
+ recordE2E(evalCollector, '/review base branch detection', 'Base branch detection', result);
311
+ expect(result.exitReason).toBe('success');
312
+
313
+ // Verify the review used "base branch" language (from Step 0)
314
+ const toolOutputs = result.toolCalls.map(tc => tc.output || '').join('\n');
315
+ const allOutput = (result.output || '') + toolOutputs;
316
+ // The agent should have run git diff against main (the fallback)
317
+ const usedGitDiff = result.toolCalls.some(tc => {
318
+ if (tc.tool !== 'Bash') return false;
319
+ const cmd = typeof tc.input === 'string' ? tc.input : tc.input?.command || JSON.stringify(tc.input);
320
+ return cmd.includes('git diff');
321
+ });
322
+ expect(usedGitDiff).toBe(true);
323
+ }, 120_000);
324
+
325
+ testConcurrentIfSelected('ship-base-branch', async () => {
326
+ const dir = path.join(baseBranchDir, 'ship-base');
327
+ fs.mkdirSync(dir, { recursive: true });
328
+
329
+ // Create git repo with feature branch
330
+ run('git', ['init'], dir);
331
+ run('git', ['config', 'user.email', 'test@test.com'], dir);
332
+ run('git', ['config', 'user.name', 'Test'], dir);
333
+
334
+ fs.writeFileSync(path.join(dir, 'app.ts'), 'console.log("v1");\n');
335
+ run('git', ['add', 'app.ts'], dir);
336
+ run('git', ['commit', '-m', 'initial'], dir);
337
+
338
+ run('git', ['checkout', '-b', 'feature/ship-test'], dir);
339
+ fs.writeFileSync(path.join(dir, 'app.ts'), 'console.log("v2");\n');
340
+ run('git', ['add', 'app.ts'], dir);
341
+ run('git', ['commit', '-m', 'feat: update to v2'], dir);
342
+
343
+ // Copy ship skill
344
+ fs.copyFileSync(path.join(ROOT, 'ship', 'SKILL.md'), path.join(dir, 'ship-SKILL.md'));
345
+
346
+ const result = await runSkillTest({
347
+ prompt: `Read ship-SKILL.md for the ship workflow.
348
+
349
+ Skip the preamble bash block, lake intro, telemetry, and contributor mode sections — go straight to Step 0.
350
+
351
+ Run ONLY Step 0 (Detect base branch) and Step 1 (Pre-flight) from the ship workflow.
352
+ Since there is no remote, gh commands will fail — fall back to main.
353
+
354
+ After completing Step 0 and Step 1, STOP. Do NOT proceed to Step 2 or beyond.
355
+ Do NOT push, create PRs, or modify VERSION/CHANGELOG.
356
+
357
+ Write a summary of what you detected to ${dir}/ship-preflight.md including:
358
+ - The detected base branch name
359
+ - The current branch name
360
+ - The diff stat against the base branch`,
361
+ workingDirectory: dir,
362
+ maxTurns: 18,
363
+ timeout: 150_000,
364
+ testName: 'ship-base-branch',
365
+ runId,
366
+ });
367
+
368
+ logCost('/ship base-branch', result);
369
+ recordE2E(evalCollector, '/ship base branch detection', 'Base branch detection', result);
370
+ expect(result.exitReason).toBe('success');
371
+
372
+ // Verify preflight output was written
373
+ const preflightPath = path.join(dir, 'ship-preflight.md');
374
+ if (fs.existsSync(preflightPath)) {
375
+ const content = fs.readFileSync(preflightPath, 'utf-8');
376
+ expect(content.length).toBeGreaterThan(20);
377
+ // Should mention the branch name
378
+ expect(content.toLowerCase()).toMatch(/main|base/);
379
+ }
380
+
381
+ // Verify no destructive actions — no push, no PR creation
382
+ const destructiveTools = result.toolCalls.filter(tc =>
383
+ tc.tool === 'Bash' && typeof tc.input === 'string' &&
384
+ (tc.input.includes('git push') || tc.input.includes('gh pr create'))
385
+ );
386
+ expect(destructiveTools).toHaveLength(0);
387
+ }, 180_000);
388
+
389
+ testConcurrentIfSelected('retro-base-branch', async () => {
390
+ const dir = path.join(baseBranchDir, 'retro-base');
391
+ fs.mkdirSync(dir, { recursive: true });
392
+
393
+ // Create git repo with commit history
394
+ run('git', ['init'], dir);
395
+ run('git', ['config', 'user.email', 'dev@example.com'], dir);
396
+ run('git', ['config', 'user.name', 'Dev'], dir);
397
+
398
+ fs.writeFileSync(path.join(dir, 'app.ts'), 'console.log("hello");\n');
399
+ run('git', ['add', 'app.ts'], dir);
400
+ run('git', ['commit', '-m', 'feat: initial app', '--date', '2026-03-14T09:00:00'], dir);
401
+
402
+ fs.writeFileSync(path.join(dir, 'auth.ts'), 'export function login() {}\n');
403
+ run('git', ['add', 'auth.ts'], dir);
404
+ run('git', ['commit', '-m', 'feat: add auth', '--date', '2026-03-15T10:00:00'], dir);
405
+
406
+ fs.writeFileSync(path.join(dir, 'test.ts'), 'test("it works", () => {});\n');
407
+ run('git', ['add', 'test.ts'], dir);
408
+ run('git', ['commit', '-m', 'test: add tests', '--date', '2026-03-16T11:00:00'], dir);
409
+
410
+ // Copy retro skill
411
+ fs.mkdirSync(path.join(dir, 'retro'), { recursive: true });
412
+ fs.copyFileSync(path.join(ROOT, 'retro', 'SKILL.md'), path.join(dir, 'retro', 'SKILL.md'));
413
+
414
+ const result = await runSkillTest({
415
+ prompt: `Read retro/SKILL.md for instructions on how to run a retrospective.
416
+
417
+ IMPORTANT: Follow the "Detect default branch" step first. Since there is no remote, gh will fail — fall back to main.
418
+ Then use the detected branch name for all git queries.
419
+
420
+ Run /retro for the last 7 days of this git repo. Skip any AskUserQuestion calls — this is non-interactive.
421
+ This is a local-only repo so use the local branch (main) instead of origin/main for all git log commands.
422
+
423
+ Write your retrospective to ${dir}/retro-output.md`,
424
+ workingDirectory: dir,
425
+ maxTurns: 25,
426
+ timeout: 240_000,
427
+ testName: 'retro-base-branch',
428
+ runId,
429
+ });
430
+
431
+ logCost('/retro base-branch', result);
432
+ recordE2E(evalCollector, '/retro default branch detection', 'Base branch detection', result, {
433
+ passed: ['success', 'error_max_turns'].includes(result.exitReason),
434
+ });
435
+ expect(['success', 'error_max_turns']).toContain(result.exitReason);
436
+
437
+ // Verify retro output was produced
438
+ const retroPath = path.join(dir, 'retro-output.md');
439
+ if (fs.existsSync(retroPath)) {
440
+ const content = fs.readFileSync(retroPath, 'utf-8');
441
+ expect(content.length).toBeGreaterThan(100);
442
+ }
443
+ }, 300_000);
444
+ });
445
+
446
+ // --- Retro E2E ---
447
+
448
+ describeIfSelected('Retro E2E', ['retro'], () => {
449
+ let retroDir: string;
450
+
451
+ beforeAll(() => {
452
+ retroDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-e2e-retro-'));
453
+ const run = (cmd: string, args: string[]) =>
454
+ spawnSync(cmd, args, { cwd: retroDir, stdio: 'pipe', timeout: 5000 });
455
+
456
+ // Create a git repo with varied commit history
457
+ run('git', ['init', '-b', 'main']);
458
+ run('git', ['config', 'user.email', 'dev@example.com']);
459
+ run('git', ['config', 'user.name', 'Dev']);
460
+
461
+ // Day 1 commits
462
+ fs.writeFileSync(path.join(retroDir, 'app.ts'), 'console.log("hello");\n');
463
+ run('git', ['add', 'app.ts']);
464
+ run('git', ['commit', '-m', 'feat: initial app setup', '--date', '2026-03-10T09:00:00']);
465
+
466
+ fs.writeFileSync(path.join(retroDir, 'auth.ts'), 'export function login() {}\n');
467
+ run('git', ['add', 'auth.ts']);
468
+ run('git', ['commit', '-m', 'feat: add auth module', '--date', '2026-03-10T11:00:00']);
469
+
470
+ // Day 2 commits
471
+ fs.writeFileSync(path.join(retroDir, 'app.ts'), 'import { login } from "./auth";\nconsole.log("hello");\nlogin();\n');
472
+ run('git', ['add', 'app.ts']);
473
+ run('git', ['commit', '-m', 'fix: wire up auth to app', '--date', '2026-03-11T10:00:00']);
474
+
475
+ fs.writeFileSync(path.join(retroDir, 'test.ts'), 'import { test } from "bun:test";\ntest("login", () => {});\n');
476
+ run('git', ['add', 'test.ts']);
477
+ run('git', ['commit', '-m', 'test: add login test', '--date', '2026-03-11T14:00:00']);
478
+
479
+ // Day 3 commits
480
+ fs.writeFileSync(path.join(retroDir, 'api.ts'), 'export function getUsers() { return []; }\n');
481
+ run('git', ['add', 'api.ts']);
482
+ run('git', ['commit', '-m', 'feat: add users API endpoint', '--date', '2026-03-12T09:30:00']);
483
+
484
+ fs.writeFileSync(path.join(retroDir, 'README.md'), '# My App\nA test application.\n');
485
+ run('git', ['add', 'README.md']);
486
+ run('git', ['commit', '-m', 'docs: add README', '--date', '2026-03-12T16:00:00']);
487
+
488
+ // Copy retro skill
489
+ fs.mkdirSync(path.join(retroDir, 'retro'), { recursive: true });
490
+ fs.copyFileSync(
491
+ path.join(ROOT, 'retro', 'SKILL.md'),
492
+ path.join(retroDir, 'retro', 'SKILL.md'),
493
+ );
494
+ });
495
+
496
+ afterAll(() => {
497
+ try { fs.rmSync(retroDir, { recursive: true, force: true }); } catch {}
498
+ });
499
+
500
+ test('/retro produces analysis from git history', async () => {
501
+ const result = await runSkillTest({
502
+ prompt: `Read retro/SKILL.md for instructions on how to run a retrospective.
503
+
504
+ Run /retro for the last 7 days of this git repo. Skip any AskUserQuestion calls — this is non-interactive.
505
+ Write your retrospective report to ${retroDir}/retro-output.md
506
+
507
+ Analyze the git history and produce the narrative report as described in the SKILL.md.`,
508
+ workingDirectory: retroDir,
509
+ maxTurns: 30,
510
+ timeout: 300_000,
511
+ testName: 'retro',
512
+ runId,
513
+ model: 'claude-opus-4-6',
514
+ });
515
+
516
+ logCost('/retro', result);
517
+ recordE2E(evalCollector, '/retro', 'Retro E2E', result, {
518
+ passed: ['success', 'error_max_turns'].includes(result.exitReason),
519
+ });
520
+ // Accept error_max_turns — retro does many git commands to analyze history
521
+ expect(['success', 'error_max_turns']).toContain(result.exitReason);
522
+
523
+ // Verify the retro was written
524
+ const retroPath = path.join(retroDir, 'retro-output.md');
525
+ if (fs.existsSync(retroPath)) {
526
+ const retro = fs.readFileSync(retroPath, 'utf-8');
527
+ expect(retro.length).toBeGreaterThan(100);
528
+ }
529
+ }, 420_000);
530
+ });
531
+
532
+ // Module-level afterAll — finalize eval collector after all tests complete
533
+ afterAll(async () => {
534
+ await finalizeEvalCollector(evalCollector);
535
+ });