@haystackeditor/cli 0.6.0 → 0.7.1
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/utils/detect.js +65 -4
- package/dist/utils/skill.js +72 -4
- package/package.json +1 -1
package/dist/utils/detect.js
CHANGED
|
@@ -27,7 +27,12 @@ export async function detectProject(rootDir = process.cwd()) {
|
|
|
27
27
|
}
|
|
28
28
|
// Detect framework
|
|
29
29
|
result.framework = await detectFramework(rootDir);
|
|
30
|
-
//
|
|
30
|
+
// Extract custom port from config if framework supports it
|
|
31
|
+
const customPort = await extractPortFromConfig(rootDir, result.framework);
|
|
32
|
+
if (customPort) {
|
|
33
|
+
result.suggestedPort = customPort;
|
|
34
|
+
}
|
|
35
|
+
// Set suggestions based on framework (won't override customPort if set)
|
|
31
36
|
setSuggestions(result);
|
|
32
37
|
// Detect auth bypass from .env.example
|
|
33
38
|
result.suggestedAuthBypass = await detectAuthBypass(rootDir);
|
|
@@ -188,12 +193,14 @@ async function detectService(rootDir, servicePath) {
|
|
|
188
193
|
else if (await hasFile(fullPath, 'vite.config.ts') || await hasFile(fullPath, 'vite.config.js')) {
|
|
189
194
|
framework = 'vite';
|
|
190
195
|
suggestedCommand = 'pnpm dev';
|
|
191
|
-
|
|
196
|
+
// Try to extract custom port from vite config, fallback to default
|
|
197
|
+
suggestedPort = await extractPortFromConfig(fullPath, 'vite') ?? 5173;
|
|
192
198
|
}
|
|
193
199
|
else if (await hasFile(fullPath, 'next.config.js') || await hasFile(fullPath, 'next.config.ts')) {
|
|
194
200
|
framework = 'nextjs';
|
|
195
201
|
suggestedCommand = 'pnpm dev';
|
|
196
|
-
|
|
202
|
+
// Try to extract custom port from next config, fallback to default
|
|
203
|
+
suggestedPort = await extractPortFromConfig(fullPath, 'nextjs') ?? 3000;
|
|
197
204
|
}
|
|
198
205
|
else if (scripts.dev) {
|
|
199
206
|
suggestedCommand = 'pnpm dev';
|
|
@@ -280,6 +287,7 @@ async function detectAuthBypass(rootDir) {
|
|
|
280
287
|
}
|
|
281
288
|
/**
|
|
282
289
|
* Set suggestions based on detected framework
|
|
290
|
+
* Note: This is sync, so custom port extraction happens in detectProject
|
|
283
291
|
*/
|
|
284
292
|
function setSuggestions(result) {
|
|
285
293
|
const frameworkDefaults = {
|
|
@@ -294,7 +302,8 @@ function setSuggestions(result) {
|
|
|
294
302
|
};
|
|
295
303
|
const defaults = result.framework ? frameworkDefaults[result.framework] : null;
|
|
296
304
|
result.suggestedDevCommand = defaults?.command || `${result.packageManager} dev`;
|
|
297
|
-
|
|
305
|
+
// suggestedPort may already be set from custom config extraction
|
|
306
|
+
result.suggestedPort = result.suggestedPort || defaults?.port || 3000;
|
|
298
307
|
result.suggestedReadyPattern = defaults?.ready || 'ready|started|listening|Local:';
|
|
299
308
|
}
|
|
300
309
|
/**
|
|
@@ -309,6 +318,58 @@ async function hasFile(dir, file) {
|
|
|
309
318
|
return false;
|
|
310
319
|
}
|
|
311
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* Extract custom port from framework config files
|
|
323
|
+
*
|
|
324
|
+
* Parses vite.config.ts, next.config.js, etc. to find custom port settings
|
|
325
|
+
* Returns undefined if no custom port is configured (use framework default)
|
|
326
|
+
*/
|
|
327
|
+
async function extractPortFromConfig(rootDir, framework) {
|
|
328
|
+
if (!framework)
|
|
329
|
+
return undefined;
|
|
330
|
+
// Config files to check based on framework
|
|
331
|
+
const configFiles = {
|
|
332
|
+
vite: ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'],
|
|
333
|
+
nextjs: ['next.config.js', 'next.config.ts', 'next.config.mjs'],
|
|
334
|
+
nuxt: ['nuxt.config.ts', 'nuxt.config.js'],
|
|
335
|
+
sveltekit: ['svelte.config.js', 'svelte.config.ts'],
|
|
336
|
+
astro: ['astro.config.mjs', 'astro.config.ts'],
|
|
337
|
+
};
|
|
338
|
+
const files = configFiles[framework];
|
|
339
|
+
if (!files)
|
|
340
|
+
return undefined;
|
|
341
|
+
let configContent = null;
|
|
342
|
+
for (const file of files) {
|
|
343
|
+
try {
|
|
344
|
+
configContent = await fs.readFile(path.join(rootDir, file), 'utf-8');
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// File not found, try next
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (!configContent)
|
|
352
|
+
return undefined;
|
|
353
|
+
// Patterns to match port configuration
|
|
354
|
+
// Vite: server: { port: 3000 } or server.port = 3000
|
|
355
|
+
// Next: env: { PORT: 3000 } or experimental.serverPort
|
|
356
|
+
const patterns = [
|
|
357
|
+
/server\s*:\s*\{[^}]*port\s*:\s*(\d+)/s, // server: { port: 3000 }
|
|
358
|
+
/server\s*\.\s*port\s*[=:]\s*(\d+)/, // server.port = 3000
|
|
359
|
+
/port\s*:\s*(\d+)/, // port: 3000 (generic)
|
|
360
|
+
/PORT\s*[=:]\s*['"]?(\d+)['"]?/, // PORT = 3000
|
|
361
|
+
];
|
|
362
|
+
for (const pattern of patterns) {
|
|
363
|
+
const match = configContent.match(pattern);
|
|
364
|
+
if (match) {
|
|
365
|
+
const port = parseInt(match[1], 10);
|
|
366
|
+
if (port > 0 && port < 65536) {
|
|
367
|
+
return port;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return undefined;
|
|
372
|
+
}
|
|
312
373
|
/**
|
|
313
374
|
* Detect proxy dependencies from vite.config.ts/js
|
|
314
375
|
*
|
package/dist/utils/skill.js
CHANGED
|
@@ -50,7 +50,75 @@ Your flows should describe THIS journey, not just "pages load".
|
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
53
|
-
## Step 3:
|
|
53
|
+
## Step 3: Verify ALL Services Have Flows (CRITICAL)
|
|
54
|
+
|
|
55
|
+
**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.
|
|
56
|
+
|
|
57
|
+
### Check for Uncovered Services
|
|
58
|
+
|
|
59
|
+
\`\`\`bash
|
|
60
|
+
# List all services
|
|
61
|
+
grep -A1 '"services"' .haystack.json | grep -E '^\\s+"[^"]+":' | sed 's/.*"\\([^"]*\\)".*/\\1/'
|
|
62
|
+
|
|
63
|
+
# List all flows
|
|
64
|
+
grep '"name":' .haystack.json
|
|
65
|
+
|
|
66
|
+
# MANUAL CHECK: Does every service have a flow?
|
|
67
|
+
\`\`\`
|
|
68
|
+
|
|
69
|
+
### Types of Services
|
|
70
|
+
|
|
71
|
+
| Service Type | How to Verify |
|
|
72
|
+
|--------------|---------------|
|
|
73
|
+
| **Web frontend** | UI flows (navigate, wait_for, screenshot) |
|
|
74
|
+
| **API/Worker** | UI flows that hit API endpoints |
|
|
75
|
+
| **CLI/Batch** | Backend flows with golden inputs |
|
|
76
|
+
| **Analysis pipeline** | Backend flows with known PR input |
|
|
77
|
+
|
|
78
|
+
### Backend Verification (CLI tools, analysis pipelines, batch jobs)
|
|
79
|
+
|
|
80
|
+
**Not everything is a web page.** For CLI tools and batch processes, you need:
|
|
81
|
+
|
|
82
|
+
1. **Golden input** - A known-good input that produces predictable output
|
|
83
|
+
2. **Run command** - How to execute the service
|
|
84
|
+
3. **Output assertion** - What to check in the output
|
|
85
|
+
|
|
86
|
+
\`\`\`json
|
|
87
|
+
{
|
|
88
|
+
"name": "Analysis pipeline - golden PR",
|
|
89
|
+
"description": "Run analysis on known PR to verify pipeline works",
|
|
90
|
+
"trigger": "on_change",
|
|
91
|
+
"watch_patterns": ["analysis/src/**", "analysis/package.json"],
|
|
92
|
+
"service": "haystack-analysis",
|
|
93
|
+
"type": "backend",
|
|
94
|
+
"steps": [
|
|
95
|
+
{
|
|
96
|
+
"action": "run",
|
|
97
|
+
"command": "pnpm start",
|
|
98
|
+
"env": { "PR_IDENTIFIER": "owner/repo#123" },
|
|
99
|
+
"timeout": 120
|
|
100
|
+
},
|
|
101
|
+
{ "action": "assert_exit_code", "code": 0 },
|
|
102
|
+
{ "action": "assert_output_contains", "pattern": "Analysis complete" }
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
\`\`\`
|
|
106
|
+
|
|
107
|
+
### Finding Golden Inputs
|
|
108
|
+
|
|
109
|
+
For analysis/processing pipelines:
|
|
110
|
+
- Pick a **small, stable PR** that won't change
|
|
111
|
+
- Document what the expected output should be
|
|
112
|
+
- Add it as a comment in the flow description
|
|
113
|
+
|
|
114
|
+
\`\`\`bash
|
|
115
|
+
# Find a good golden PR (small, merged, stable)
|
|
116
|
+
gh pr list --state merged --limit 10 --json number,title,changedFiles | jq '.[] | select(.changedFiles < 5)'
|
|
117
|
+
\`\`\`
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Step 4: Assess Data Needs
|
|
54
122
|
|
|
55
123
|
\`\`\`bash
|
|
56
124
|
# Find API calls
|
|
@@ -85,7 +153,7 @@ grep -r "https://" src/ --include="*.ts" --include="*.tsx" | grep -v node_module
|
|
|
85
153
|
|
|
86
154
|
---
|
|
87
155
|
|
|
88
|
-
## Step
|
|
156
|
+
## Step 5: Write Flows
|
|
89
157
|
|
|
90
158
|
Flows tell the Planner about your app's routes, UI elements, and user journeys.
|
|
91
159
|
|
|
@@ -157,7 +225,7 @@ For flows that only matter when certain files change:
|
|
|
157
225
|
|
|
158
226
|
---
|
|
159
227
|
|
|
160
|
-
## Step
|
|
228
|
+
## Step 6: Configure Fixtures (if needed)
|
|
161
229
|
|
|
162
230
|
Based on user's answer in Step 3:
|
|
163
231
|
|
|
@@ -189,7 +257,7 @@ fixtures:
|
|
|
189
257
|
|
|
190
258
|
---
|
|
191
259
|
|
|
192
|
-
## Step
|
|
260
|
+
## Step 7: Commit
|
|
193
261
|
|
|
194
262
|
\`\`\`bash
|
|
195
263
|
git add .haystack.json fixtures/
|