@haystackeditor/cli 0.8.0 → 0.9.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/README.md +105 -12
- package/dist/assets/hooks/agent-context/detect.ts +136 -0
- package/dist/assets/hooks/agent-context/format.ts +99 -0
- package/dist/assets/hooks/agent-context/index.ts +39 -0
- package/dist/assets/hooks/agent-context/parsers/claude.ts +253 -0
- package/dist/assets/hooks/agent-context/parsers/gemini.ts +155 -0
- package/dist/assets/hooks/agent-context/parsers/opencode.ts +174 -0
- package/dist/assets/hooks/agent-context/tsconfig.json +13 -0
- package/dist/assets/hooks/agent-context/types.ts +58 -0
- package/dist/assets/hooks/llm-rules-template.md +56 -0
- package/dist/assets/hooks/package.json +11 -0
- package/dist/assets/hooks/scripts/commit-msg.sh +4 -0
- package/dist/assets/hooks/scripts/post-commit.sh +4 -0
- package/dist/assets/hooks/scripts/pre-commit.sh +92 -0
- package/dist/assets/hooks/scripts/pre-push.sh +25 -0
- package/dist/assets/hooks/scripts/prepare-commit-msg.sh +3 -0
- package/dist/assets/hooks/truncation-checker/ast-analyzer.ts +528 -0
- package/dist/assets/hooks/truncation-checker/index.ts +595 -0
- package/dist/assets/hooks/truncation-checker/tsconfig.json +13 -0
- package/dist/assets/skills/prepare-haystack.md +323 -0
- package/dist/assets/skills/secrets.md +164 -0
- package/dist/assets/skills/setup-external-sandbox.md +243 -0
- package/dist/assets/skills/setup-haystack.md +639 -0
- package/dist/assets/skills/submit.md +154 -0
- package/dist/assets/templates/CLAUDE.md.snippet +42 -0
- package/dist/assets/templates/haystack.yml +193 -0
- package/dist/commands/check-pending.d.ts +19 -0
- package/dist/commands/check-pending.js +217 -0
- package/dist/commands/config.d.ts +18 -12
- package/dist/commands/config.js +327 -52
- package/dist/commands/hooks.d.ts +17 -0
- package/dist/commands/hooks.js +269 -0
- package/dist/commands/install-session-hooks.d.ts +16 -0
- package/dist/commands/install-session-hooks.js +302 -0
- package/dist/commands/login.js +1 -1
- package/dist/commands/policy.d.ts +31 -0
- package/dist/commands/policy.js +365 -0
- package/dist/commands/skills.d.ts +8 -0
- package/dist/commands/skills.js +80 -0
- package/dist/commands/submit.d.ts +22 -0
- package/dist/commands/submit.js +428 -0
- package/dist/commands/triage.d.ts +16 -0
- package/dist/commands/triage.js +354 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +317 -2
- package/dist/tools/detect.d.ts +50 -0
- package/dist/tools/detect.js +853 -0
- package/dist/tools/fixtures.d.ts +38 -0
- package/dist/tools/fixtures.js +199 -0
- package/dist/tools/setup.d.ts +43 -0
- package/dist/tools/setup.js +597 -0
- package/dist/triage/prompts.d.ts +31 -0
- package/dist/triage/prompts.js +266 -0
- package/dist/triage/runner.d.ts +21 -0
- package/dist/triage/runner.js +325 -0
- package/dist/triage/traces.d.ts +20 -0
- package/dist/triage/traces.js +305 -0
- package/dist/triage/types.d.ts +47 -0
- package/dist/triage/types.js +7 -0
- package/dist/types.d.ts +1387 -191
- package/dist/types.js +254 -2
- package/dist/utils/analysis-api.d.ts +108 -0
- package/dist/utils/analysis-api.js +194 -0
- package/dist/utils/config.js +1 -1
- package/dist/utils/git.d.ts +80 -0
- package/dist/utils/git.js +302 -0
- package/dist/utils/github-api.d.ts +83 -0
- package/dist/utils/github-api.js +266 -0
- package/dist/utils/hooks.d.ts +26 -0
- package/dist/utils/hooks.js +226 -0
- package/dist/utils/pending-state.d.ts +38 -0
- package/dist/utils/pending-state.js +86 -0
- package/dist/utils/secrets.js +3 -3
- package/dist/utils/skill.d.ts +1 -1
- package/dist/utils/skill.js +658 -1
- package/package.json +5 -3
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
# Haystack Verification Setup
|
|
2
|
+
|
|
3
|
+
> **PRO Feature**: Verification Flow requires a Haystack PRO subscription to run cloud sandboxes. Free users can still set up the `.haystack.json` configuration — it will be ready when they upgrade. See https://haystackeditor.com/pricing for details.
|
|
4
|
+
|
|
5
|
+
**Your job**: Help the verification system understand this app so it can visually verify PRs work correctly.
|
|
6
|
+
|
|
7
|
+
The verification system has two parts:
|
|
8
|
+
1. **Planner** - An AI that explores the codebase to figure out what to test
|
|
9
|
+
2. **Executor** - Takes screenshots based on the plan
|
|
10
|
+
|
|
11
|
+
Your `.haystack.json` flows feed into the **corpus** - they're hints for the Planner about what routes exist, what selectors to use, and what the core user journey looks like.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Step 0: Configure Dev Server for Cloud Sandboxes
|
|
16
|
+
|
|
17
|
+
Cloud sandboxes access your dev server via tunnel URLs (`*.modal.host`). Most modern dev servers block non-localhost hosts by default. **You must configure your dev server to allow external hosts.**
|
|
18
|
+
|
|
19
|
+
### Vite / SvelteKit / Astro / Nuxt 3
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// vite.config.ts (or framework equivalent)
|
|
23
|
+
export default defineConfig({
|
|
24
|
+
server: {
|
|
25
|
+
allowedHosts: true, // Required for Haystack cloud sandboxes
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Next.js
|
|
31
|
+
|
|
32
|
+
Next.js allows all hosts by default in development. No configuration needed.
|
|
33
|
+
|
|
34
|
+
If you've restricted hosts, add to `next.config.js`:
|
|
35
|
+
```javascript
|
|
36
|
+
module.exports = {
|
|
37
|
+
allowedDevHosts: ['localhost', '.modal.host'],
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Webpack Dev Server (CRA, Vue CLI, custom)
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// webpack.config.js or vue.config.js
|
|
45
|
+
module.exports = {
|
|
46
|
+
devServer: {
|
|
47
|
+
allowedHosts: 'all', // or ['.modal.host']
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For Create React App, set environment variable:
|
|
53
|
+
```bash
|
|
54
|
+
DANGEROUSLY_DISABLE_HOST_CHECK=true npm start
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Angular
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
// angular.json → serve → options
|
|
61
|
+
{
|
|
62
|
+
"disableHostCheck": true
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or run with: `ng serve --disable-host-check`
|
|
67
|
+
|
|
68
|
+
### Remix
|
|
69
|
+
|
|
70
|
+
Remix dev server allows all hosts by default. No configuration needed.
|
|
71
|
+
|
|
72
|
+
### Other Frameworks
|
|
73
|
+
|
|
74
|
+
Look for `allowedHosts`, `disableHostCheck`, or `host` options in your dev server config. The goal is to allow requests from `*.modal.host` domains.
|
|
75
|
+
|
|
76
|
+
**Skip this step if**: Your dev server already allows external hosts or doesn't have host checking.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Step 1: Generate Base Config
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx @haystackeditor/cli init --yes
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This detects your dev server command, port, and service dependencies.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Step 2: Understand the App's Core Feature
|
|
91
|
+
|
|
92
|
+
Before writing any flows, answer this:
|
|
93
|
+
|
|
94
|
+
**What is the ONE main thing users do in this app?**
|
|
95
|
+
|
|
96
|
+
Read the codebase to understand the core user journey:
|
|
97
|
+
- E-commerce: browse products → add to cart → checkout
|
|
98
|
+
- Dashboard: view metrics → filter data → export
|
|
99
|
+
- Editor: create document → edit → save
|
|
100
|
+
- Social: view feed → create post → interact
|
|
101
|
+
- SaaS: sign up → configure → use feature
|
|
102
|
+
|
|
103
|
+
Your flows should describe THIS journey, not just "pages load".
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Step 3: Verify ALL Services Have Flows (CRITICAL)
|
|
108
|
+
|
|
109
|
+
**Every service in `.haystack.json` must have at least one verification flow.** This is the most common mistake - adding services but forgetting to add flows that exercise them.
|
|
110
|
+
|
|
111
|
+
### Check for Uncovered Services
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# List all services
|
|
115
|
+
grep -A1 '"services"' .haystack.json | grep -E '^\s+"[^"]+":' | sed 's/.*"\([^"]*\)".*/\1/'
|
|
116
|
+
|
|
117
|
+
# List all flows
|
|
118
|
+
grep '"name":' .haystack.json
|
|
119
|
+
|
|
120
|
+
# MANUAL CHECK: Does every service have a flow?
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Types of Services
|
|
124
|
+
|
|
125
|
+
| Service Type | How to Verify |
|
|
126
|
+
|--------------|---------------|
|
|
127
|
+
| **Web frontend** | UI flows (navigate, wait_for, screenshot) |
|
|
128
|
+
| **API/Worker** | UI flows that hit API endpoints |
|
|
129
|
+
| **CLI/Batch** | Backend flows with golden inputs |
|
|
130
|
+
| **Analysis pipeline** | Backend flows with known PR input |
|
|
131
|
+
|
|
132
|
+
### Backend Verification (CLI tools, analysis pipelines, batch jobs)
|
|
133
|
+
|
|
134
|
+
**Not everything is a web page.** For CLI tools and batch processes, you need:
|
|
135
|
+
|
|
136
|
+
1. **Golden input** - A known-good input that produces predictable output
|
|
137
|
+
2. **Run command** - How to execute the service
|
|
138
|
+
3. **Output assertion** - What to check in the output
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"name": "Backend pipeline - golden input",
|
|
143
|
+
"description": "Run pipeline on known input to verify it works",
|
|
144
|
+
"trigger": "on_change",
|
|
145
|
+
"watch_patterns": ["packages/my-pipeline/src/**"],
|
|
146
|
+
"service": "my-pipeline",
|
|
147
|
+
"type": "backend",
|
|
148
|
+
"steps": [
|
|
149
|
+
{
|
|
150
|
+
"action": "run",
|
|
151
|
+
"command": "pnpm start",
|
|
152
|
+
"env": { "INPUT_ID": "known-good-input-123" },
|
|
153
|
+
"timeout": 120
|
|
154
|
+
},
|
|
155
|
+
{ "action": "assert_exit_code", "code": 0 },
|
|
156
|
+
{ "action": "assert_output_contains", "pattern": "Processing complete" }
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## STOP - Confirm Golden URLs and Golden Data
|
|
164
|
+
|
|
165
|
+
**If you identified backend services that need verification, you MUST ask the user with a proposed example:**
|
|
166
|
+
|
|
167
|
+
First, explore the codebase to find:
|
|
168
|
+
- Example inputs used in tests, scripts, or documentation
|
|
169
|
+
- Default/demo values in config files or environment variables
|
|
170
|
+
- IDs or URLs referenced in comments or READMEs
|
|
171
|
+
|
|
172
|
+
Then propose a specific example:
|
|
173
|
+
|
|
174
|
+
> I found these backend services that need verification:
|
|
175
|
+
> - **[service name]**: [what it does]
|
|
176
|
+
>
|
|
177
|
+
> For backend verification, I need **golden test data** - stable inputs that produce predictable output.
|
|
178
|
+
>
|
|
179
|
+
> **Based on what I found in the codebase, here's my suggestion:**
|
|
180
|
+
> - **Golden URL/Input**: `[specific example you found, e.g., a test ID, demo endpoint, or sample file]`
|
|
181
|
+
> - **Command**: `[the command to run with this input]`
|
|
182
|
+
> - **Expected Output**: `[what success looks like based on the code]`
|
|
183
|
+
>
|
|
184
|
+
> Does this look right? Or should I use different test data?
|
|
185
|
+
|
|
186
|
+
**Wait for the user to confirm or provide alternatives before adding backend flows.**
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Step 4: Assess Data Needs
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Find API calls
|
|
194
|
+
grep -r "fetch(\|useQuery\|useSWR\|axios" src/ --include="*.tsx" --include="*.ts" | wc -l
|
|
195
|
+
|
|
196
|
+
# Find dynamic routes
|
|
197
|
+
grep -r "useParams\|router.query\|\[.*\]" src/ --include="*.tsx" | head -10
|
|
198
|
+
|
|
199
|
+
# Find external domains
|
|
200
|
+
grep -r "https://" src/ --include="*.ts" --include="*.tsx" | grep -v node_modules | head -10
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## STOP - Ask About Auth Requirements
|
|
206
|
+
|
|
207
|
+
**You MUST ask the user before proceeding with fixtures or flows:**
|
|
208
|
+
|
|
209
|
+
> Does this app require signed-in users to access the main features?
|
|
210
|
+
>
|
|
211
|
+
> Looking at the codebase, I see [authentication code, protected routes, user state, etc.].
|
|
212
|
+
>
|
|
213
|
+
> **How should verification handle authentication?**
|
|
214
|
+
>
|
|
215
|
+
> | Strategy | Best For | Complexity |
|
|
216
|
+
> |----------|----------|------------|
|
|
217
|
+
> | **Bypass** | Dev mode skips auth entirely | ⭐ Simplest |
|
|
218
|
+
> | **Fixture** | Mock auth endpoints return fake user | ⭐⭐ Easy |
|
|
219
|
+
> | **Token** | Inject real session token (you provide) | ⭐⭐⭐ Medium |
|
|
220
|
+
> | **Test Account** | Full login flow with test credentials | ⭐⭐⭐⭐ Complex |
|
|
221
|
+
>
|
|
222
|
+
> 1. **Bypass** - Set env var like `SKIP_AUTH=true` (does your app support this?)
|
|
223
|
+
> 2. **Fixture** - I'll create a mock `/auth/status` that returns a fake user
|
|
224
|
+
> 3. **Token** - You provide a session cookie/token value to inject
|
|
225
|
+
> 4. **Test Account** - Automated login with username/password (most realistic)
|
|
226
|
+
|
|
227
|
+
**Wait for the user's response, then configure auth accordingly.**
|
|
228
|
+
|
|
229
|
+
### Configuring Auth Based on User Response
|
|
230
|
+
|
|
231
|
+
**Bypass (simplest):**
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"auth": {
|
|
235
|
+
"strategy": "bypass",
|
|
236
|
+
"env": { "VITE_SKIP_AUTH": "true" }
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Fixture (mock auth endpoint):**
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"auth": {
|
|
245
|
+
"strategy": "fixture",
|
|
246
|
+
"env": { "VITE_SKIP_AUTH": "true" },
|
|
247
|
+
"fixture": {
|
|
248
|
+
"pattern": "/auth/status",
|
|
249
|
+
"source": "file://fixtures/auth-status.json"
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Create `fixtures/auth-status.json`:
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"authenticated": true,
|
|
259
|
+
"user": {
|
|
260
|
+
"id": "test-user-123",
|
|
261
|
+
"email": "test@example.com",
|
|
262
|
+
"name": "Test User"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Token (inject session):**
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"auth": {
|
|
271
|
+
"strategy": "token",
|
|
272
|
+
"token": {
|
|
273
|
+
"type": "cookie",
|
|
274
|
+
"name": "session",
|
|
275
|
+
"value": "$SESSION_TOKEN"
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The `$SESSION_TOKEN` is resolved from Haystack secrets. Tell the user:
|
|
282
|
+
> To use token auth, you'll need to add your session value as a secret:
|
|
283
|
+
> ```bash
|
|
284
|
+
> npx @haystackeditor/cli secrets set SESSION_TOKEN "your-session-value"
|
|
285
|
+
> ```
|
|
286
|
+
|
|
287
|
+
**Test Account (full login flow):**
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"auth": {
|
|
291
|
+
"strategy": "test_account",
|
|
292
|
+
"test_account": {
|
|
293
|
+
"username": "$TEST_USERNAME",
|
|
294
|
+
"password": "$TEST_PASSWORD",
|
|
295
|
+
"login_url": "/login",
|
|
296
|
+
"steps": [
|
|
297
|
+
{ "action": "type", "selector": "input[name=email]", "value": "$TEST_USERNAME" },
|
|
298
|
+
{ "action": "type", "selector": "input[name=password]", "value": "$TEST_PASSWORD" },
|
|
299
|
+
{ "action": "click", "selector": "button[type=submit]" }
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## STOP - Ask About Database Requirements
|
|
309
|
+
|
|
310
|
+
**You MUST ask the user if the app needs database access:**
|
|
311
|
+
|
|
312
|
+
> Does this app need a real database for verification?
|
|
313
|
+
>
|
|
314
|
+
> Looking at the codebase, I see [Prisma/Drizzle/Knex/raw SQL queries/etc.].
|
|
315
|
+
>
|
|
316
|
+
> **How should verification handle database access?**
|
|
317
|
+
>
|
|
318
|
+
> | Strategy | Best For | Complexity |
|
|
319
|
+
> |----------|----------|------------|
|
|
320
|
+
> | **Fixture** | Mock API responses (no real DB needed) | ⭐ Simplest |
|
|
321
|
+
> | **Memory** | In-memory SQLite for read-heavy apps | ⭐⭐ Easy |
|
|
322
|
+
> | **Seed** | File-based DB with seed data | ⭐⭐⭐ Medium |
|
|
323
|
+
> | **Docker** | Spin up Postgres/MySQL/Redis containers | ⭐⭐⭐⭐ Complex |
|
|
324
|
+
> | **Remote** | Connect to read-only staging database | ⭐⭐⭐⭐⭐ Advanced |
|
|
325
|
+
>
|
|
326
|
+
> For most apps, **fixtures are sufficient** — they mock the API layer so no real DB is needed.
|
|
327
|
+
|
|
328
|
+
**Wait for the user's response, then configure database accordingly.**
|
|
329
|
+
|
|
330
|
+
### Configuring Database Based on User Response
|
|
331
|
+
|
|
332
|
+
**Fixture (simplest - mock API responses):**
|
|
333
|
+
```json
|
|
334
|
+
{
|
|
335
|
+
"fixtures": [
|
|
336
|
+
{ "pattern": "/api/users", "source": "file://fixtures/users.json" },
|
|
337
|
+
{ "pattern": "/api/posts/*", "source": "file://fixtures/posts.json" }
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**Memory (in-memory SQLite):**
|
|
343
|
+
```json
|
|
344
|
+
{
|
|
345
|
+
"database": {
|
|
346
|
+
"strategy": "memory",
|
|
347
|
+
"env": { "DATABASE_URL": "sqlite::memory:" }
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Seed (file-based with seed data):**
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"database": {
|
|
356
|
+
"strategy": "seed",
|
|
357
|
+
"env": { "DATABASE_URL": "file:./test.db" },
|
|
358
|
+
"seed_command": "pnpm db:seed"
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Docker (real database containers):**
|
|
364
|
+
```json
|
|
365
|
+
{
|
|
366
|
+
"database": {
|
|
367
|
+
"strategy": "docker",
|
|
368
|
+
"services": [
|
|
369
|
+
{
|
|
370
|
+
"image": "postgres:15-alpine",
|
|
371
|
+
"port": 5432,
|
|
372
|
+
"env": {
|
|
373
|
+
"POSTGRES_USER": "test",
|
|
374
|
+
"POSTGRES_PASSWORD": "test",
|
|
375
|
+
"POSTGRES_DB": "testdb"
|
|
376
|
+
},
|
|
377
|
+
"health_check": "pg_isready -U test",
|
|
378
|
+
"health_timeout": 30
|
|
379
|
+
}
|
|
380
|
+
],
|
|
381
|
+
"env": { "DATABASE_URL": "postgresql://test:test@localhost:5432/testdb" },
|
|
382
|
+
"migrate_command": "pnpm prisma migrate deploy",
|
|
383
|
+
"seed_command": "pnpm db:seed"
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Remote (read-only staging database):**
|
|
389
|
+
```json
|
|
390
|
+
{
|
|
391
|
+
"database": {
|
|
392
|
+
"strategy": "remote",
|
|
393
|
+
"env": { "DATABASE_URL": "$STAGING_DATABASE_URL" },
|
|
394
|
+
"read_only": true
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
The `$STAGING_DATABASE_URL` is resolved from Haystack secrets. Tell the user:
|
|
400
|
+
> To use a remote database, add the connection string as a secret:
|
|
401
|
+
> ```bash
|
|
402
|
+
> npx @haystackeditor/cli secrets set STAGING_DATABASE_URL "postgresql://..."
|
|
403
|
+
> ```
|
|
404
|
+
|
|
405
|
+
**Fallback strategies** (try multiple approaches):
|
|
406
|
+
```json
|
|
407
|
+
{
|
|
408
|
+
"database": {
|
|
409
|
+
"strategy": "memory",
|
|
410
|
+
"env": { "DATABASE_URL": "sqlite::memory:" },
|
|
411
|
+
"fallback": {
|
|
412
|
+
"strategy": "seed",
|
|
413
|
+
"env": { "DATABASE_URL": "file:./test.db" },
|
|
414
|
+
"seed_command": "pnpm db:seed"
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## STOP - Ask About Test Data Strategy
|
|
423
|
+
|
|
424
|
+
**You MUST ask the user before proceeding:**
|
|
425
|
+
|
|
426
|
+
> I analyzed the codebase and found:
|
|
427
|
+
> - X API fetch calls
|
|
428
|
+
> - Y dynamic routes with parameters
|
|
429
|
+
> - These external domains: [list them]
|
|
430
|
+
>
|
|
431
|
+
> **How should I handle test data for verification?**
|
|
432
|
+
>
|
|
433
|
+
> 1. **Passthrough** - Let API calls through to real servers (add domains to `network.allow`)
|
|
434
|
+
> 2. **Staging URL** - Point flows at your staging/demo environment
|
|
435
|
+
> 3. **Local fixtures** - JSON files in `fixtures/` directory
|
|
436
|
+
> 4. **Skip data pages** - Only test static pages that don't need API data
|
|
437
|
+
|
|
438
|
+
**Wait for the user's response before continuing.**
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## STOP - Confirm Frontend Golden URLs
|
|
443
|
+
|
|
444
|
+
**Goldens are URLs with real staging data** - they let verification test pages that need actual content to render properly. You need MULTIPLE goldens to cover different scenarios.
|
|
445
|
+
|
|
446
|
+
**Before writing flows for dynamic routes, explore the codebase to find example data:**
|
|
447
|
+
|
|
448
|
+
1. Check test files (`*.test.ts`, `cypress/`, `playwright/`) for example IDs/URLs
|
|
449
|
+
2. Check README/docs for demo links or example usage
|
|
450
|
+
3. Check seed data, fixtures, or mock files
|
|
451
|
+
4. Check `.env.example` or config for staging URLs
|
|
452
|
+
5. Check existing routes to understand the URL format
|
|
453
|
+
|
|
454
|
+
**Then propose MULTIPLE golden URLs (aim for 3-5) covering different scenarios:**
|
|
455
|
+
|
|
456
|
+
> I found these dynamic routes that need staging data to render:
|
|
457
|
+
>
|
|
458
|
+
> **[Route Name]** (`/path/:param1/:param2`)
|
|
459
|
+
>
|
|
460
|
+
> | Golden | URL | Why |
|
|
461
|
+
> |--------|-----|-----|
|
|
462
|
+
> | Large dataset | `/path/example/large-123` | Tests performance with many items |
|
|
463
|
+
> | Typical case | `/path/example/medium-456` | Common user scenario |
|
|
464
|
+
> | Edge case | `/path/example/empty-789` | Tests empty/minimal state |
|
|
465
|
+
> | Error state | `/path/example/error-000` | Tests error handling UI |
|
|
466
|
+
>
|
|
467
|
+
> **Evidence:**
|
|
468
|
+
> - Found `large-123` in `cypress/fixtures/test-data.json`
|
|
469
|
+
> - Found `medium-456` in README as demo example
|
|
470
|
+
> - Found `empty-789` in `src/tests/edge-cases.test.ts`
|
|
471
|
+
>
|
|
472
|
+
> Does this look right?
|
|
473
|
+
> 1. ✅ Yes, use these goldens
|
|
474
|
+
> 2. 🔄 Use different URLs (I'll provide them)
|
|
475
|
+
|
|
476
|
+
**Add goldens to `verification.goldens` in `.haystack.json` using this EXACT format:**
|
|
477
|
+
|
|
478
|
+
```json
|
|
479
|
+
{
|
|
480
|
+
"verification": {
|
|
481
|
+
"goldens": {
|
|
482
|
+
"frontend": [
|
|
483
|
+
{
|
|
484
|
+
"id": "large-dataset",
|
|
485
|
+
"description": "100+ items - tests rendering performance",
|
|
486
|
+
"route": "/the/actual/url/with/data"
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
"id": "typical-case",
|
|
490
|
+
"description": "Standard 10-20 items",
|
|
491
|
+
"route": "/another/url/with/typical/data"
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"id": "empty-state",
|
|
495
|
+
"description": "No items - tests empty state UI",
|
|
496
|
+
"route": "/url/that/shows/empty/state"
|
|
497
|
+
}
|
|
498
|
+
],
|
|
499
|
+
"backend": [
|
|
500
|
+
{
|
|
501
|
+
"id": "golden-input-1",
|
|
502
|
+
"description": "Known-good input for pipeline testing",
|
|
503
|
+
"input": { "type": "github_pr", "value": "owner/repo#123" }
|
|
504
|
+
}
|
|
505
|
+
]
|
|
506
|
+
},
|
|
507
|
+
"commands": [...]
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**DO NOT:**
|
|
513
|
+
- Ask the user what format to use - USE THIS FORMAT
|
|
514
|
+
- Put goldens at the top level - they go inside `verification.goldens`
|
|
515
|
+
- Use a flat object like `{ "goldens": { "name": "url" } }` - use the array format above
|
|
516
|
+
- Embed golden URLs only in flow steps - also add them to the goldens section for discoverability
|
|
517
|
+
|
|
518
|
+
**CRITICAL**:
|
|
519
|
+
- Propose MULTIPLE goldens (3-5), not just one
|
|
520
|
+
- Cover different scenarios: large, typical, empty, error states
|
|
521
|
+
- Always propose SPECIFIC URLs, never ask the user to freestyle
|
|
522
|
+
- Show WHERE you found the example data (file path, line if possible)
|
|
523
|
+
- Make sure URLs match the app's actual route format (check `<Route path=`)
|
|
524
|
+
- Wait for confirmation before writing flows with these URLs
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
## Step 5: Write Flows
|
|
529
|
+
|
|
530
|
+
Flows tell the Planner about your app's routes, UI elements, and user journeys.
|
|
531
|
+
|
|
532
|
+
### Structure
|
|
533
|
+
|
|
534
|
+
```yaml
|
|
535
|
+
flows:
|
|
536
|
+
- name: "Descriptive name of what this tests"
|
|
537
|
+
trigger: always # or on_change with watch_patterns
|
|
538
|
+
steps:
|
|
539
|
+
- action: navigate
|
|
540
|
+
url: "/"
|
|
541
|
+
- action: wait_for
|
|
542
|
+
selector: "[data-testid='specific-element']"
|
|
543
|
+
- action: click
|
|
544
|
+
selector: "[data-testid='button']"
|
|
545
|
+
- action: screenshot
|
|
546
|
+
name: "result"
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### What to Include
|
|
550
|
+
|
|
551
|
+
**Core journey flow** (trigger: always):
|
|
552
|
+
- The main thing users do in your app
|
|
553
|
+
- Multiple steps with interactions (click, type)
|
|
554
|
+
- Waits for meaningful state changes
|
|
555
|
+
|
|
556
|
+
**Route coverage flows**:
|
|
557
|
+
- One flow per major route
|
|
558
|
+
- Uses specific selectors the Planner can learn from
|
|
559
|
+
- `watch_patterns` to only run when relevant files change
|
|
560
|
+
|
|
561
|
+
### Finding Good Selectors
|
|
562
|
+
|
|
563
|
+
```bash
|
|
564
|
+
# Find data-testid attributes
|
|
565
|
+
grep -r "data-testid" src/ --include="*.tsx" | head -20
|
|
566
|
+
|
|
567
|
+
# Find aria-labels
|
|
568
|
+
grep -r "aria-label" src/ --include="*.tsx" | head -20
|
|
569
|
+
|
|
570
|
+
# Find component class names
|
|
571
|
+
grep -r "className=" src/components/ --include="*.tsx" | head -20
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Use specific selectors like:
|
|
575
|
+
- `[data-testid='dashboard-chart']`
|
|
576
|
+
- `[aria-label='Submit form']`
|
|
577
|
+
- `.pricing-table`
|
|
578
|
+
- `button[type='submit']`
|
|
579
|
+
|
|
580
|
+
If good selectors don't exist, add `data-testid` to key components.
|
|
581
|
+
|
|
582
|
+
### watch_patterns
|
|
583
|
+
|
|
584
|
+
For flows that only matter when certain files change:
|
|
585
|
+
|
|
586
|
+
```yaml
|
|
587
|
+
- name: "Settings page works"
|
|
588
|
+
trigger: on_change
|
|
589
|
+
watch_patterns:
|
|
590
|
+
- "src/pages/settings/**"
|
|
591
|
+
- "src/components/settings/**"
|
|
592
|
+
steps:
|
|
593
|
+
- action: navigate
|
|
594
|
+
url: "/settings"
|
|
595
|
+
# ...
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
## Step 6: Configure Fixtures (if needed)
|
|
601
|
+
|
|
602
|
+
Based on user's answer in Step 3:
|
|
603
|
+
|
|
604
|
+
**Passthrough**:
|
|
605
|
+
```yaml
|
|
606
|
+
network:
|
|
607
|
+
allow:
|
|
608
|
+
- "api.example.com"
|
|
609
|
+
- "cdn.example.com"
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
**Staging URL**:
|
|
613
|
+
```yaml
|
|
614
|
+
flows:
|
|
615
|
+
- name: "Dashboard with real data"
|
|
616
|
+
steps:
|
|
617
|
+
- action: navigate
|
|
618
|
+
url: "https://staging.example.com/dashboard"
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**Local fixtures**:
|
|
622
|
+
```yaml
|
|
623
|
+
fixtures:
|
|
624
|
+
- pattern: "/api/user"
|
|
625
|
+
source: "file://fixtures/user.json"
|
|
626
|
+
- pattern: "/api/data/*"
|
|
627
|
+
source: "file://fixtures/data.json"
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
## Step 7: Commit
|
|
633
|
+
|
|
634
|
+
```bash
|
|
635
|
+
git add .haystack.json fixtures/
|
|
636
|
+
git commit -m "Add Haystack verification"
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
Done! The Planner will use your flows to understand the app and create verification plans for PRs.
|