@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.
Files changed (63) hide show
  1. package/README.md +93 -87
  2. package/dist/assets/hooks/llm-rules-template.md +21 -0
  3. package/dist/assets/hooks/package.json +2 -2
  4. package/dist/assets/hooks/scripts/pre-push.sh +20 -0
  5. package/dist/assets/skills/prepare-haystack.md +323 -0
  6. package/dist/assets/skills/secrets.md +164 -0
  7. package/dist/assets/skills/setup-external-sandbox.md +243 -0
  8. package/dist/assets/skills/setup-haystack.md +639 -0
  9. package/dist/assets/skills/submit.md +154 -0
  10. package/dist/assets/templates/CLAUDE.md.snippet +42 -0
  11. package/dist/assets/templates/haystack.yml +193 -0
  12. package/dist/commands/check-pending.d.ts +19 -0
  13. package/dist/commands/check-pending.js +217 -0
  14. package/dist/commands/config.d.ts +13 -21
  15. package/dist/commands/config.js +278 -92
  16. package/dist/commands/dismiss.d.ts +17 -0
  17. package/dist/commands/dismiss.js +201 -0
  18. package/dist/commands/init.js +25 -28
  19. package/dist/commands/install-session-hooks.d.ts +16 -0
  20. package/dist/commands/install-session-hooks.js +302 -0
  21. package/dist/commands/login.js +1 -1
  22. package/dist/commands/policy.d.ts +31 -0
  23. package/dist/commands/policy.js +365 -0
  24. package/dist/commands/pr-status.d.ts +16 -0
  25. package/dist/commands/pr-status.js +188 -0
  26. package/dist/commands/setup.d.ts +13 -0
  27. package/dist/commands/setup.js +496 -0
  28. package/dist/commands/skills.d.ts +2 -2
  29. package/dist/commands/skills.js +51 -186
  30. package/dist/commands/submit.d.ts +23 -0
  31. package/dist/commands/submit.js +456 -0
  32. package/dist/commands/triage.d.ts +16 -0
  33. package/dist/commands/triage.js +354 -0
  34. package/dist/index.d.ts +7 -0
  35. package/dist/index.js +344 -4
  36. package/dist/tools/detect.d.ts +50 -0
  37. package/dist/tools/detect.js +853 -0
  38. package/dist/tools/fixtures.d.ts +38 -0
  39. package/dist/tools/fixtures.js +199 -0
  40. package/dist/tools/setup.d.ts +43 -0
  41. package/dist/tools/setup.js +597 -0
  42. package/dist/triage/prompts.d.ts +31 -0
  43. package/dist/triage/prompts.js +296 -0
  44. package/dist/triage/runner.d.ts +21 -0
  45. package/dist/triage/runner.js +339 -0
  46. package/dist/triage/traces.d.ts +20 -0
  47. package/dist/triage/traces.js +305 -0
  48. package/dist/triage/types.d.ts +47 -0
  49. package/dist/triage/types.js +7 -0
  50. package/dist/types.d.ts +1387 -191
  51. package/dist/types.js +254 -2
  52. package/dist/utils/analysis-api.d.ts +108 -0
  53. package/dist/utils/analysis-api.js +194 -0
  54. package/dist/utils/config.js +1 -1
  55. package/dist/utils/git.d.ts +80 -0
  56. package/dist/utils/git.js +302 -0
  57. package/dist/utils/github-api.d.ts +83 -0
  58. package/dist/utils/github-api.js +266 -0
  59. package/dist/utils/pending-state.d.ts +40 -0
  60. package/dist/utils/pending-state.js +86 -0
  61. package/dist/utils/secrets.js +3 -3
  62. package/dist/utils/skill.js +257 -0
  63. 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