@haystackeditor/cli 0.8.1 → 0.10.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 +93 -87
- package/dist/assets/hooks/llm-rules-template.md +21 -0
- package/dist/assets/hooks/package.json +2 -2
- package/dist/assets/hooks/scripts/pre-push.sh +20 -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 +13 -21
- package/dist/commands/config.js +278 -92
- package/dist/commands/dismiss.d.ts +17 -0
- package/dist/commands/dismiss.js +201 -0
- package/dist/commands/init.js +25 -28
- 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/pr-status.d.ts +16 -0
- package/dist/commands/pr-status.js +188 -0
- package/dist/commands/setup.d.ts +13 -0
- package/dist/commands/setup.js +496 -0
- package/dist/commands/skills.d.ts +2 -2
- package/dist/commands/skills.js +51 -186
- package/dist/commands/submit.d.ts +23 -0
- package/dist/commands/submit.js +456 -0
- package/dist/commands/triage.d.ts +16 -0
- package/dist/commands/triage.js +354 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +344 -4
- 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 +296 -0
- package/dist/triage/runner.d.ts +21 -0
- package/dist/triage/runner.js +339 -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/pending-state.d.ts +40 -0
- package/dist/utils/pending-state.js +86 -0
- package/dist/utils/secrets.js +3 -3
- package/dist/utils/skill.js +257 -0
- package/package.json +11 -9
|
@@ -0,0 +1,164 @@
|
|
|
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
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# External Sandbox Setup
|
|
2
|
+
|
|
3
|
+
**Your job**: Help the user connect Haystack to their existing sandbox infrastructure instead of using Haystack's built-in sandboxes.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## When to Use This
|
|
8
|
+
|
|
9
|
+
External sandboxes are for users who:
|
|
10
|
+
- Have their own background agent (e.g., custom AI coding agent)
|
|
11
|
+
- Already spin up development environments (e.g., Codespaces, Gitpod, custom VMs)
|
|
12
|
+
- Want Haystack's review UI (browser, editor, terminal) to connect to THEIR sandbox
|
|
13
|
+
|
|
14
|
+
If the user doesn't have their own sandbox infrastructure, they should use Haystack's built-in sandboxes instead.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Step 1: Understand Their Setup
|
|
19
|
+
|
|
20
|
+
**Ask the user:**
|
|
21
|
+
|
|
22
|
+
> Do you have your own background agent or sandbox infrastructure?
|
|
23
|
+
>
|
|
24
|
+
> Haystack can connect to your existing sandbox instead of spinning up its own. This is useful if:
|
|
25
|
+
> - You have a custom AI agent that makes code changes
|
|
26
|
+
> - You use Codespaces, Gitpod, or similar cloud dev environments
|
|
27
|
+
> - You want to share a single sandbox between your agent and Haystack's review UI
|
|
28
|
+
>
|
|
29
|
+
> **How does your sandbox provide access?**
|
|
30
|
+
>
|
|
31
|
+
> 1. **HTTP API** - Your sandbox exposes an endpoint that returns URLs (recommended)
|
|
32
|
+
> 2. **Webhook push** - Your agent calls Haystack when the sandbox is ready
|
|
33
|
+
> 3. **Neither yet** - I need help designing the integration
|
|
34
|
+
|
|
35
|
+
**Wait for the user's response before continuing.**
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Step 2: Configure Based on Response
|
|
40
|
+
|
|
41
|
+
### Option 1: HTTP API (Pull)
|
|
42
|
+
|
|
43
|
+
The user's sandbox exposes an endpoint that Haystack queries.
|
|
44
|
+
|
|
45
|
+
**Their endpoint must return:**
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"devUrl": "https://sandbox.example.com:3000", // Browser preview
|
|
50
|
+
"opencodeUrl": "https://sandbox.example.com:8080", // Code editor (OpenCode)
|
|
51
|
+
"terminalUrl": "https://sandbox.example.com/term", // Web terminal
|
|
52
|
+
"status": "ready" // "starting" | "ready" | "stopped" | "error"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Query parameters Haystack sends:**
|
|
57
|
+
|
|
58
|
+
| Param | Description |
|
|
59
|
+
|-------|-------------|
|
|
60
|
+
| `session_id` | Haystack session ID |
|
|
61
|
+
| `repo` | Repository name (e.g., `owner/repo`) |
|
|
62
|
+
| `branch` | Branch name |
|
|
63
|
+
| `pr_number` | PR number (if applicable) |
|
|
64
|
+
|
|
65
|
+
**Add to `.haystack.json`:**
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"sandbox": {
|
|
70
|
+
"external": {
|
|
71
|
+
"pullEndpoint": "https://your-api.example.com/sandbox",
|
|
72
|
+
"authHeader": "X-API-Key"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
If they need authentication, tell them:
|
|
79
|
+
> Add your API key as a Haystack secret:
|
|
80
|
+
> ```bash
|
|
81
|
+
> npx @haystackeditor/cli secrets set SANDBOX_API_KEY "your-key"
|
|
82
|
+
> ```
|
|
83
|
+
> Then reference it in the config:
|
|
84
|
+
> ```json
|
|
85
|
+
> {
|
|
86
|
+
> "sandbox": {
|
|
87
|
+
> "external": {
|
|
88
|
+
> "pullEndpoint": "https://your-api.example.com/sandbox",
|
|
89
|
+
> "authHeader": "X-API-Key",
|
|
90
|
+
> "authValue": "$SANDBOX_API_KEY"
|
|
91
|
+
> }
|
|
92
|
+
> }
|
|
93
|
+
> }
|
|
94
|
+
> ```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### Option 2: Webhook Push
|
|
99
|
+
|
|
100
|
+
The user's agent calls Haystack when the sandbox is ready.
|
|
101
|
+
|
|
102
|
+
**Webhook endpoint:**
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
POST https://haystack-agent.akshaysg.workers.dev/sessions/{session_id}/external-sandbox
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Request body:**
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"devUrl": "https://sandbox.example.com:3000",
|
|
113
|
+
"opencodeUrl": "https://sandbox.example.com:8080",
|
|
114
|
+
"terminalUrl": "https://sandbox.example.com/term",
|
|
115
|
+
"status": "ready"
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Add to `.haystack.json`:**
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"sandbox": {
|
|
124
|
+
"external": {
|
|
125
|
+
"mode": "push"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Tell the user:**
|
|
132
|
+
> Your agent needs to POST to Haystack when the sandbox is ready.
|
|
133
|
+
>
|
|
134
|
+
> **Webhook URL pattern:**
|
|
135
|
+
> ```
|
|
136
|
+
> https://haystack-agent.akshaysg.workers.dev/sessions/{SESSION_ID}/external-sandbox
|
|
137
|
+
> ```
|
|
138
|
+
>
|
|
139
|
+
> The `SESSION_ID` is passed to your agent when Haystack requests a sandbox.
|
|
140
|
+
> Your agent should call this endpoint with the sandbox URLs when ready.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### Option 3: Neither (Help Design)
|
|
145
|
+
|
|
146
|
+
If they don't have an existing API, help them add one.
|
|
147
|
+
|
|
148
|
+
**Questions to ask:**
|
|
149
|
+
|
|
150
|
+
1. What language/framework is your agent built with?
|
|
151
|
+
2. Where does your agent store sandbox URLs? (DB, memory, file)
|
|
152
|
+
3. How does your sandbox expose services? (tunnels, direct ports, custom domain)
|
|
153
|
+
|
|
154
|
+
**Provide a minimal implementation example based on their stack:**
|
|
155
|
+
|
|
156
|
+
**Node.js/Express:**
|
|
157
|
+
```javascript
|
|
158
|
+
app.get('/sandbox', (req, res) => {
|
|
159
|
+
const { session_id, repo, branch, pr_number } = req.query;
|
|
160
|
+
|
|
161
|
+
// Look up or create sandbox for this session
|
|
162
|
+
const sandbox = getSandboxFor(session_id, repo, branch);
|
|
163
|
+
|
|
164
|
+
res.json({
|
|
165
|
+
devUrl: sandbox.devServerUrl,
|
|
166
|
+
opencodeUrl: sandbox.editorUrl,
|
|
167
|
+
terminalUrl: sandbox.terminalUrl,
|
|
168
|
+
status: sandbox.status // "starting" | "ready" | "stopped" | "error"
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Python/FastAPI:**
|
|
174
|
+
```python
|
|
175
|
+
@app.get("/sandbox")
|
|
176
|
+
async def get_sandbox(
|
|
177
|
+
session_id: str,
|
|
178
|
+
repo: str,
|
|
179
|
+
branch: str,
|
|
180
|
+
pr_number: Optional[int] = None
|
|
181
|
+
):
|
|
182
|
+
sandbox = await get_or_create_sandbox(session_id, repo, branch)
|
|
183
|
+
return {
|
|
184
|
+
"devUrl": sandbox.dev_server_url,
|
|
185
|
+
"opencodeUrl": sandbox.editor_url,
|
|
186
|
+
"terminalUrl": sandbox.terminal_url,
|
|
187
|
+
"status": sandbox.status
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Step 3: Verify the Configuration
|
|
194
|
+
|
|
195
|
+
After adding the config to `.haystack.json`, verify it works:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# If using pull mode, test the endpoint directly
|
|
199
|
+
curl "https://your-api.example.com/sandbox?session_id=test&repo=owner/repo&branch=main"
|
|
200
|
+
|
|
201
|
+
# Should return:
|
|
202
|
+
# {"devUrl": "...", "opencodeUrl": "...", "terminalUrl": "...", "status": "ready"}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Step 4: Commit
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
git add .haystack.json
|
|
211
|
+
git commit -m "Configure external sandbox integration"
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Done! Haystack will now use your sandbox infrastructure instead of its built-in sandboxes.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## URL Requirements
|
|
219
|
+
|
|
220
|
+
Your sandbox URLs must be:
|
|
221
|
+
|
|
222
|
+
| URL | Purpose | Requirements |
|
|
223
|
+
|-----|---------|--------------|
|
|
224
|
+
| `devUrl` | Browser preview | HTTPS, iframe-embeddable, serves your dev server |
|
|
225
|
+
| `opencodeUrl` | Code editor | HTTPS, serves OpenCode web UI on port 8080 |
|
|
226
|
+
| `terminalUrl` | Web terminal | HTTPS, WebSocket-capable, ttyd or xterm.js |
|
|
227
|
+
|
|
228
|
+
**Common Issues:**
|
|
229
|
+
|
|
230
|
+
- **CORS**: Your sandbox must allow requests from `https://haystackeditor.com`
|
|
231
|
+
- **X-Frame-Options**: Set to `ALLOWALL` or `ALLOW-FROM https://haystackeditor.com`
|
|
232
|
+
- **Mixed content**: All URLs must be HTTPS (no HTTP)
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Debugging
|
|
237
|
+
|
|
238
|
+
If the integration isn't working:
|
|
239
|
+
|
|
240
|
+
1. **Check the endpoint returns valid JSON** with all required fields
|
|
241
|
+
2. **Check status** - must be one of: `starting`, `ready`, `stopped`, `error`
|
|
242
|
+
3. **Check URLs are accessible** - Haystack can't access localhost or private IPs
|
|
243
|
+
4. **Check CORS headers** - your sandbox must allow cross-origin requests
|