@haystackeditor/cli 0.10.1 → 0.10.2
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/dist/commands/config.d.ts +1 -5
- package/dist/commands/config.js +2 -56
- package/dist/commands/init.js +0 -30
- package/dist/commands/skills.js +3 -8
- package/dist/commands/status.js +0 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -58
- package/dist/types.d.ts +4 -4
- package/dist/types.js +4 -4
- package/dist/utils/secrets.js +1 -2
- package/package.json +1 -1
- package/dist/assets/skills/prepare-haystack.md +0 -323
- package/dist/assets/skills/secrets.md +0 -164
- package/dist/assets/skills/setup-external-sandbox.md +0 -243
- package/dist/assets/skills/setup-haystack.md +0 -639
- package/dist/assets/templates/CLAUDE.md.snippet +0 -42
- package/dist/assets/templates/haystack.yml +0 -193
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
# Prepare Codebase for Verification
|
|
2
|
-
|
|
3
|
-
> **PRO Feature**: Verification Flow requires a Haystack PRO subscription to run cloud sandboxes. Free users can still prepare their codebase — it will be ready when they upgrade. See https://haystackeditor.com/pricing for details.
|
|
4
|
-
|
|
5
|
-
**Your job**: Make this codebase easy to verify by adding semantic identifiers that the verification system can target.
|
|
6
|
-
|
|
7
|
-
The verification Planner needs to find UI elements by selectors. Generic selectors like `div` or `.flex` are useless. Your job is to add meaningful identifiers throughout the codebase.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## What to Add
|
|
12
|
-
|
|
13
|
-
### 1. `aria-label` on Interactive Elements
|
|
14
|
-
|
|
15
|
-
Every clickable/interactive element should have an aria-label describing what it does:
|
|
16
|
-
|
|
17
|
-
```tsx
|
|
18
|
-
// Before
|
|
19
|
-
<button onClick={onSave}>💾</button>
|
|
20
|
-
<button onClick={() => setOpen(true)}>
|
|
21
|
-
<MenuIcon />
|
|
22
|
-
</button>
|
|
23
|
-
|
|
24
|
-
// After
|
|
25
|
-
<button onClick={onSave} aria-label="Save document">💾</button>
|
|
26
|
-
<button onClick={() => setOpen(true)} aria-label="Open menu">
|
|
27
|
-
<MenuIcon />
|
|
28
|
-
</button>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
**Target elements:**
|
|
32
|
-
- Buttons (especially icon-only buttons)
|
|
33
|
-
- Links without descriptive text
|
|
34
|
-
- Toggle switches
|
|
35
|
-
- Dropdown triggers
|
|
36
|
-
- Modal open/close buttons
|
|
37
|
-
- Form submit buttons
|
|
38
|
-
|
|
39
|
-
### 2. `data-testid` on Key Sections
|
|
40
|
-
|
|
41
|
-
Major UI sections should have data-testid for easy targeting:
|
|
42
|
-
|
|
43
|
-
```tsx
|
|
44
|
-
// Before
|
|
45
|
-
<div className="flex flex-col p-4">
|
|
46
|
-
<h1>Dashboard</h1>
|
|
47
|
-
{/* content */}
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
// After
|
|
51
|
-
<div className="flex flex-col p-4" data-testid="dashboard-container">
|
|
52
|
-
<h1>Dashboard</h1>
|
|
53
|
-
{/* content */}
|
|
54
|
-
</div>
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**Target sections:**
|
|
58
|
-
- Page containers (dashboard, settings, profile)
|
|
59
|
-
- Navigation bars/sidebars
|
|
60
|
-
- Modal/dialog content
|
|
61
|
-
- Form containers
|
|
62
|
-
- Data tables/lists
|
|
63
|
-
- Card components
|
|
64
|
-
- Loading states
|
|
65
|
-
- Error states
|
|
66
|
-
- Empty states
|
|
67
|
-
|
|
68
|
-
### 3. `role` Attributes for Semantic Structure
|
|
69
|
-
|
|
70
|
-
Add ARIA roles where HTML semantics aren't clear:
|
|
71
|
-
|
|
72
|
-
```tsx
|
|
73
|
-
// Before
|
|
74
|
-
<div className="modal-overlay">
|
|
75
|
-
<div className="modal-content">
|
|
76
|
-
|
|
77
|
-
// After
|
|
78
|
-
<div className="modal-overlay" role="presentation">
|
|
79
|
-
<div className="modal-content" role="dialog" aria-modal="true">
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
**Common roles:**
|
|
83
|
-
- `role="dialog"` - Modals/dialogs
|
|
84
|
-
- `role="navigation"` - Nav sections
|
|
85
|
-
- `role="main"` - Main content area
|
|
86
|
-
- `role="alert"` - Error/success messages
|
|
87
|
-
- `role="status"` - Loading indicators
|
|
88
|
-
- `role="tablist"`, `role="tab"`, `role="tabpanel"` - Tab interfaces
|
|
89
|
-
|
|
90
|
-
### 4. State Indicators
|
|
91
|
-
|
|
92
|
-
Add attributes that indicate UI state:
|
|
93
|
-
|
|
94
|
-
```tsx
|
|
95
|
-
// Before
|
|
96
|
-
<button onClick={toggle}>
|
|
97
|
-
{isOpen ? 'Close' : 'Open'}
|
|
98
|
-
</button>
|
|
99
|
-
|
|
100
|
-
// After
|
|
101
|
-
<button
|
|
102
|
-
onClick={toggle}
|
|
103
|
-
aria-expanded={isOpen}
|
|
104
|
-
aria-label={isOpen ? 'Close panel' : 'Open panel'}
|
|
105
|
-
>
|
|
106
|
-
{isOpen ? 'Close' : 'Open'}
|
|
107
|
-
</button>
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
**State attributes:**
|
|
111
|
-
- `aria-expanded` - Collapsible sections
|
|
112
|
-
- `aria-selected` - Selected items in lists
|
|
113
|
-
- `aria-checked` - Checkboxes/toggles
|
|
114
|
-
- `aria-disabled` - Disabled elements
|
|
115
|
-
- `aria-busy` - Loading states
|
|
116
|
-
- `data-state="loading|error|success"` - Custom states
|
|
117
|
-
|
|
118
|
-
### 5. Form Accessibility
|
|
119
|
-
|
|
120
|
-
Forms should have proper labels and descriptions:
|
|
121
|
-
|
|
122
|
-
```tsx
|
|
123
|
-
// Before
|
|
124
|
-
<input type="email" placeholder="Email" />
|
|
125
|
-
<span className="text-red-500">{error}</span>
|
|
126
|
-
|
|
127
|
-
// After
|
|
128
|
-
<input
|
|
129
|
-
type="email"
|
|
130
|
-
placeholder="Email"
|
|
131
|
-
aria-label="Email address"
|
|
132
|
-
aria-describedby={error ? "email-error" : undefined}
|
|
133
|
-
aria-invalid={!!error}
|
|
134
|
-
/>
|
|
135
|
-
{error && <span id="email-error" role="alert" className="text-red-500">{error}</span>}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
## Step 1: Scan for Missing Identifiers
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
# Find buttons without aria-label
|
|
144
|
-
grep -rn "<button" src/ --include="*.tsx" | grep -v "aria-label" | head -20
|
|
145
|
-
|
|
146
|
-
# Find icon-only buttons (likely missing labels)
|
|
147
|
-
grep -rn "<button.*Icon\|<button.*>.*</.*Icon>" src/ --include="*.tsx" | head -20
|
|
148
|
-
|
|
149
|
-
# Find modals/dialogs without role
|
|
150
|
-
grep -rn "modal\|dialog\|Modal\|Dialog" src/ --include="*.tsx" | grep -v "role=" | head -20
|
|
151
|
-
|
|
152
|
-
# Find forms without proper labeling
|
|
153
|
-
grep -rn "<input\|<select\|<textarea" src/ --include="*.tsx" | grep -v "aria-label\|id=" | head -20
|
|
154
|
-
|
|
155
|
-
# Find major components (likely need data-testid)
|
|
156
|
-
ls src/components/ src/pages/ 2>/dev/null
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## Step 2: Prioritize by Impact
|
|
162
|
-
|
|
163
|
-
Focus on elements the verification system is most likely to need:
|
|
164
|
-
|
|
165
|
-
**High Priority (do first):**
|
|
166
|
-
1. Navigation elements (header, sidebar, menu buttons)
|
|
167
|
-
2. Primary actions (submit buttons, save buttons, CTAs)
|
|
168
|
-
3. Modal triggers and dialogs
|
|
169
|
-
4. Form inputs and submit buttons
|
|
170
|
-
5. Page-level containers
|
|
171
|
-
|
|
172
|
-
**Medium Priority:**
|
|
173
|
-
1. Toggle switches and checkboxes
|
|
174
|
-
2. Dropdown menus
|
|
175
|
-
3. Tab interfaces
|
|
176
|
-
4. Cards and list items
|
|
177
|
-
5. Loading/error states
|
|
178
|
-
|
|
179
|
-
**Lower Priority:**
|
|
180
|
-
1. Decorative elements
|
|
181
|
-
2. Static content sections
|
|
182
|
-
3. Footer links
|
|
183
|
-
|
|
184
|
-
---
|
|
185
|
-
|
|
186
|
-
## Step 3: Add Identifiers Systematically
|
|
187
|
-
|
|
188
|
-
Go component by component. For each component:
|
|
189
|
-
|
|
190
|
-
1. **Check the component's purpose** - What does it DO?
|
|
191
|
-
2. **Add aria-label** to interactive elements describing the ACTION
|
|
192
|
-
3. **Add data-testid** to the container if it's a major section
|
|
193
|
-
4. **Add role** if the semantic HTML isn't clear
|
|
194
|
-
5. **Add state attributes** if the component has dynamic states
|
|
195
|
-
|
|
196
|
-
### Naming Conventions
|
|
197
|
-
|
|
198
|
-
**aria-label**: Describe the action, not the element
|
|
199
|
-
- ✅ `aria-label="Close modal"`
|
|
200
|
-
- ✅ `aria-label="Submit contact form"`
|
|
201
|
-
- ❌ `aria-label="Button"`
|
|
202
|
-
- ❌ `aria-label="Click here"`
|
|
203
|
-
|
|
204
|
-
**data-testid**: Use kebab-case, describe the section
|
|
205
|
-
- ✅ `data-testid="user-profile-card"`
|
|
206
|
-
- ✅ `data-testid="search-results-list"`
|
|
207
|
-
- ❌ `data-testid="div1"`
|
|
208
|
-
- ❌ `data-testid="container"`
|
|
209
|
-
|
|
210
|
-
---
|
|
211
|
-
|
|
212
|
-
## Step 4: Verify Coverage
|
|
213
|
-
|
|
214
|
-
After adding identifiers, check coverage:
|
|
215
|
-
|
|
216
|
-
```bash
|
|
217
|
-
# Count aria-labels added
|
|
218
|
-
grep -r "aria-label" src/ --include="*.tsx" | wc -l
|
|
219
|
-
|
|
220
|
-
# Count data-testid added
|
|
221
|
-
grep -r "data-testid" src/ --include="*.tsx" | wc -l
|
|
222
|
-
|
|
223
|
-
# Count role attributes
|
|
224
|
-
grep -r "role=" src/ --include="*.tsx" | wc -l
|
|
225
|
-
|
|
226
|
-
# List all data-testid values (check for meaningful names)
|
|
227
|
-
grep -oh 'data-testid="[^"]*"' src/ -r --include="*.tsx" | sort -u
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
---
|
|
231
|
-
|
|
232
|
-
## Step 5: Commit
|
|
233
|
-
|
|
234
|
-
```bash
|
|
235
|
-
git add src/
|
|
236
|
-
git commit -m "Add accessibility attributes for verification
|
|
237
|
-
|
|
238
|
-
- Added aria-labels to interactive elements
|
|
239
|
-
- Added data-testid to major sections
|
|
240
|
-
- Added ARIA roles for semantic structure
|
|
241
|
-
- Added state indicators (aria-expanded, etc.)"
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
## Quick Reference: Common Patterns
|
|
247
|
-
|
|
248
|
-
### Icon Button
|
|
249
|
-
```tsx
|
|
250
|
-
<button onClick={onAction} aria-label="Descriptive action name">
|
|
251
|
-
<Icon />
|
|
252
|
-
</button>
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Modal
|
|
256
|
-
```tsx
|
|
257
|
-
<div role="dialog" aria-modal="true" aria-labelledby="modal-title" data-testid="settings-modal">
|
|
258
|
-
<h2 id="modal-title">Settings</h2>
|
|
259
|
-
<button onClick={onClose} aria-label="Close settings">×</button>
|
|
260
|
-
</div>
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Navigation
|
|
264
|
-
```tsx
|
|
265
|
-
<nav aria-label="Main navigation" data-testid="main-nav">
|
|
266
|
-
<a href="/dashboard" aria-current={isActive ? "page" : undefined}>Dashboard</a>
|
|
267
|
-
</nav>
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
### Toggle
|
|
271
|
-
```tsx
|
|
272
|
-
<button
|
|
273
|
-
onClick={toggle}
|
|
274
|
-
aria-pressed={isOn}
|
|
275
|
-
aria-label={`${isOn ? 'Disable' : 'Enable'} notifications`}
|
|
276
|
-
>
|
|
277
|
-
{isOn ? 'On' : 'Off'}
|
|
278
|
-
</button>
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
### Loading State
|
|
282
|
-
```tsx
|
|
283
|
-
<div data-testid="content-area" aria-busy={isLoading}>
|
|
284
|
-
{isLoading ? (
|
|
285
|
-
<div role="status" aria-label="Loading content">
|
|
286
|
-
<Spinner />
|
|
287
|
-
</div>
|
|
288
|
-
) : (
|
|
289
|
-
content
|
|
290
|
-
)}
|
|
291
|
-
</div>
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
### Form Field
|
|
295
|
-
```tsx
|
|
296
|
-
<div data-testid="email-field">
|
|
297
|
-
<label htmlFor="email">Email</label>
|
|
298
|
-
<input
|
|
299
|
-
id="email"
|
|
300
|
-
type="email"
|
|
301
|
-
aria-describedby={error ? "email-error" : "email-hint"}
|
|
302
|
-
aria-invalid={!!error}
|
|
303
|
-
/>
|
|
304
|
-
<span id="email-hint">We'll never share your email</span>
|
|
305
|
-
{error && <span id="email-error" role="alert">{error}</span>}
|
|
306
|
-
</div>
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
### Expandable Section
|
|
310
|
-
```tsx
|
|
311
|
-
<div data-testid="faq-section">
|
|
312
|
-
<button
|
|
313
|
-
onClick={() => setExpanded(!expanded)}
|
|
314
|
-
aria-expanded={expanded}
|
|
315
|
-
aria-controls="faq-content"
|
|
316
|
-
>
|
|
317
|
-
FAQ
|
|
318
|
-
</button>
|
|
319
|
-
<div id="faq-content" hidden={!expanded}>
|
|
320
|
-
{content}
|
|
321
|
-
</div>
|
|
322
|
-
</div>
|
|
323
|
-
```
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
# /secrets
|
|
2
|
-
|
|
3
|
-
Manage secrets for Haystack sandbox access to external services.
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
Store sensitive values (API keys, database URLs, tokens) that your sandbox needs to access external services. Secrets are:
|
|
8
|
-
- **Zero-knowledge encrypted** - Encrypted locally before leaving your machine
|
|
9
|
-
- **Injected at runtime** - Available as environment variables in the sandbox
|
|
10
|
-
- **Scoped** - User, org, or repo level with cascading resolution
|
|
11
|
-
|
|
12
|
-
## When to Use This
|
|
13
|
-
|
|
14
|
-
Use secrets when your project needs:
|
|
15
|
-
- Database connections (`DATABASE_URL`)
|
|
16
|
-
- API keys for external services (`STRIPE_SECRET_KEY`, `OPENAI_API_KEY`)
|
|
17
|
-
- Authentication tokens (`GITHUB_TOKEN`, `AWS_ACCESS_KEY_ID`)
|
|
18
|
-
- Any sensitive values referenced in `.haystack.json`
|
|
19
|
-
|
|
20
|
-
## Workflow
|
|
21
|
-
|
|
22
|
-
### 1. Check for Existing Secrets
|
|
23
|
-
|
|
24
|
-
First, see what secrets are already configured:
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
Call haystack_secrets_list
|
|
28
|
-
|
|
29
|
-
If user wants org/repo scope:
|
|
30
|
-
haystack_secrets_list with scope="org" and scope_id="<org-name>"
|
|
31
|
-
haystack_secrets_list with scope="repo" and scope_id="<owner/repo>"
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### 2. Set a Secret
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
Call haystack_secrets_set with:
|
|
38
|
-
key: "DATABASE_URL" # Must be UPPERCASE_WITH_UNDERSCORES
|
|
39
|
-
value: "postgres://..." # The secret value (encrypted before sending)
|
|
40
|
-
scope: "user" # Optional: user (default), org, or repo
|
|
41
|
-
scope_id: "acme/myapp" # Required for org/repo scope
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### 3. Reference in Config
|
|
45
|
-
|
|
46
|
-
Update `.haystack.json` to use the secret:
|
|
47
|
-
|
|
48
|
-
```yaml
|
|
49
|
-
dev_server:
|
|
50
|
-
command: pnpm dev
|
|
51
|
-
env:
|
|
52
|
-
DATABASE_URL: $DATABASE_URL # Injected from secrets
|
|
53
|
-
STRIPE_KEY: $STRIPE_SECRET_KEY # Another secret
|
|
54
|
-
|
|
55
|
-
fixtures:
|
|
56
|
-
"/api/external":
|
|
57
|
-
source: "https://api.example.com/data"
|
|
58
|
-
headers:
|
|
59
|
-
Authorization: "Bearer $API_TOKEN" # Secret in headers
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 4. Delete a Secret
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
Call haystack_secrets_delete with:
|
|
66
|
-
key: "OLD_API_KEY"
|
|
67
|
-
scope: "user" # Match the scope where it was set
|
|
68
|
-
scope_id: "..." # Required for org/repo
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Scopes Explained
|
|
72
|
-
|
|
73
|
-
| Scope | Who Can Access | Use Case |
|
|
74
|
-
|-------|----------------|----------|
|
|
75
|
-
| `user` | Only you | Personal API keys, dev credentials |
|
|
76
|
-
| `org` | All org members | Shared staging credentials |
|
|
77
|
-
| `repo` | Repo collaborators | Project-specific secrets |
|
|
78
|
-
|
|
79
|
-
**Resolution order** (first match wins):
|
|
80
|
-
1. `repo` secrets (most specific)
|
|
81
|
-
2. `org` secrets
|
|
82
|
-
3. `user` secrets (fallback)
|
|
83
|
-
|
|
84
|
-
This allows repo-specific overrides of org defaults.
|
|
85
|
-
|
|
86
|
-
## Examples
|
|
87
|
-
|
|
88
|
-
### Add a Database URL
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
User: "I need to connect to my Postgres database in the sandbox"
|
|
92
|
-
|
|
93
|
-
1. Call haystack_secrets_set:
|
|
94
|
-
key: "DATABASE_URL"
|
|
95
|
-
value: "postgres://user:pass@host:5432/db"
|
|
96
|
-
|
|
97
|
-
2. Update .haystack.json:
|
|
98
|
-
dev_server:
|
|
99
|
-
env:
|
|
100
|
-
DATABASE_URL: $DATABASE_URL
|
|
101
|
-
|
|
102
|
-
3. Confirm: "Added DATABASE_URL. Your sandbox will now have access to your database."
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Add Stripe Keys for a Repo
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
User: "Set up Stripe keys for this project"
|
|
109
|
-
|
|
110
|
-
1. Call haystack_secrets_set:
|
|
111
|
-
key: "STRIPE_SECRET_KEY"
|
|
112
|
-
value: "sk_test_..."
|
|
113
|
-
scope: "repo"
|
|
114
|
-
scope_id: "acme/checkout-service"
|
|
115
|
-
|
|
116
|
-
2. Call haystack_secrets_set:
|
|
117
|
-
key: "STRIPE_WEBHOOK_SECRET"
|
|
118
|
-
value: "whsec_..."
|
|
119
|
-
scope: "repo"
|
|
120
|
-
scope_id: "acme/checkout-service"
|
|
121
|
-
|
|
122
|
-
3. Update .haystack.json with $STRIPE_SECRET_KEY and $STRIPE_WEBHOOK_SECRET
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Check What Secrets Are Configured
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
User: "What secrets do I have?"
|
|
129
|
-
|
|
130
|
-
1. Call haystack_secrets_list (user scope)
|
|
131
|
-
2. Call haystack_secrets_list with scope="org", scope_id="acme" (if applicable)
|
|
132
|
-
3. Call haystack_secrets_list with scope="repo", scope_id="acme/myapp" (if applicable)
|
|
133
|
-
|
|
134
|
-
Report: "You have 3 user secrets, 2 org secrets, and 1 repo secret configured."
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Tips
|
|
138
|
-
|
|
139
|
-
- **Key naming**: Use `UPPERCASE_WITH_UNDERSCORES` (e.g., `DATABASE_URL`, `API_SECRET_KEY`)
|
|
140
|
-
- **Never log secrets**: The MCP tools never return secret values, only keys
|
|
141
|
-
- **Rotation**: To rotate, just call `haystack_secrets_set` again with the new value
|
|
142
|
-
- **Cleanup**: Use `haystack_secrets_delete` to remove unused secrets
|
|
143
|
-
|
|
144
|
-
## Troubleshooting
|
|
145
|
-
|
|
146
|
-
### "Not authenticated"
|
|
147
|
-
Run `haystack login` first to authenticate with Haystack.
|
|
148
|
-
|
|
149
|
-
### "scope_id required"
|
|
150
|
-
For `org` or `repo` scope, you must provide `scope_id`:
|
|
151
|
-
- Org: `scope_id: "my-org-name"`
|
|
152
|
-
- Repo: `scope_id: "owner/repo-name"`
|
|
153
|
-
|
|
154
|
-
### "Invalid key format"
|
|
155
|
-
Secret keys must be:
|
|
156
|
-
- Start with a letter
|
|
157
|
-
- Uppercase letters only
|
|
158
|
-
- Underscores allowed
|
|
159
|
-
- Examples: `DATABASE_URL`, `AWS_ACCESS_KEY_ID`, `STRIPE_SECRET_KEY`
|
|
160
|
-
|
|
161
|
-
### Secret not available in sandbox
|
|
162
|
-
1. Check the secret exists: `haystack_secrets_list`
|
|
163
|
-
2. Verify `.haystack.json` references it with `$KEY_NAME`
|
|
164
|
-
3. Check resolution order - repo secrets override org/user secrets
|