@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,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pending submit state persistence.
|
|
3
|
+
*
|
|
4
|
+
* Manages `.haystack/pending-submit.json` in the git root directory.
|
|
5
|
+
* This file persists across CLI sessions so that analysis results
|
|
6
|
+
* can be retrieved after disconnection.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { findGitRoot } from './git.js';
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Constants
|
|
13
|
+
// ============================================================================
|
|
14
|
+
const PENDING_FILE = 'pending-submit.json';
|
|
15
|
+
const HAYSTACK_DIR = '.haystack';
|
|
16
|
+
const STALE_THRESHOLD_MS = 2 * 60 * 60 * 1000; // 2 hours
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Functions
|
|
19
|
+
// ============================================================================
|
|
20
|
+
function getPendingPath(gitRoot) {
|
|
21
|
+
const root = gitRoot || findGitRoot();
|
|
22
|
+
if (!root)
|
|
23
|
+
return null;
|
|
24
|
+
return join(root, HAYSTACK_DIR, PENDING_FILE);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Save pending submit state to disk.
|
|
28
|
+
*/
|
|
29
|
+
export function savePendingSubmit(state, gitRoot) {
|
|
30
|
+
const root = gitRoot || findGitRoot();
|
|
31
|
+
if (!root)
|
|
32
|
+
throw new Error('Not a git repository');
|
|
33
|
+
const dir = join(root, HAYSTACK_DIR);
|
|
34
|
+
if (!existsSync(dir)) {
|
|
35
|
+
mkdirSync(dir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
const filePath = join(dir, PENDING_FILE);
|
|
38
|
+
writeFileSync(filePath, JSON.stringify(state, null, 2));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Load pending submit state from disk.
|
|
42
|
+
* Returns null if no pending state exists or if it's stale.
|
|
43
|
+
*/
|
|
44
|
+
export function loadPendingSubmit(gitRoot) {
|
|
45
|
+
const filePath = getPendingPath(gitRoot);
|
|
46
|
+
if (!filePath || !existsSync(filePath))
|
|
47
|
+
return null;
|
|
48
|
+
try {
|
|
49
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
50
|
+
const state = JSON.parse(content);
|
|
51
|
+
// Check version
|
|
52
|
+
if (state.version !== 1)
|
|
53
|
+
return null;
|
|
54
|
+
// Auto-mark stale entries
|
|
55
|
+
if (state.status === 'polling') {
|
|
56
|
+
const age = Date.now() - new Date(state.submittedAt).getTime();
|
|
57
|
+
if (age > STALE_THRESHOLD_MS) {
|
|
58
|
+
state.status = 'stale';
|
|
59
|
+
savePendingSubmit(state, gitRoot);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return state;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Clear pending submit state (delete the file).
|
|
70
|
+
*/
|
|
71
|
+
export function clearPendingSubmit(gitRoot) {
|
|
72
|
+
const filePath = getPendingPath(gitRoot);
|
|
73
|
+
if (filePath && existsSync(filePath)) {
|
|
74
|
+
unlinkSync(filePath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Update the status and optionally the analysis result of a pending submit.
|
|
79
|
+
*/
|
|
80
|
+
export function updatePendingSubmit(updates, gitRoot) {
|
|
81
|
+
const state = loadPendingSubmit(gitRoot);
|
|
82
|
+
if (!state)
|
|
83
|
+
return;
|
|
84
|
+
Object.assign(state, updates);
|
|
85
|
+
savePendingSubmit(state, gitRoot);
|
|
86
|
+
}
|
package/dist/utils/secrets.js
CHANGED
|
@@ -18,7 +18,7 @@ const SECRET_PATTERNS = [
|
|
|
18
18
|
// API Keys
|
|
19
19
|
{
|
|
20
20
|
name: 'generic-api-key',
|
|
21
|
-
pattern: /(?:api[_-]?key|apikey)\s*[:=]\s*['"]?([a-zA-Z0-9_
|
|
21
|
+
pattern: /(?:api[_-]?key|apikey)\s*[:=]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
22
22
|
description: 'Potential API key detected',
|
|
23
23
|
severity: 'high',
|
|
24
24
|
},
|
|
@@ -43,7 +43,7 @@ const SECRET_PATTERNS = [
|
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
name: 'cloudflare-api-token',
|
|
46
|
-
pattern: /(?:cloudflare|cf)[_-]?(?:api)?[_-]?token\s*[:=]\s*['"]?([a-zA-Z0-9_
|
|
46
|
+
pattern: /(?:cloudflare|cf)[_-]?(?:api)?[_-]?token\s*[:=]\s*['"]?([a-zA-Z0-9_-]{40,})['"]?/gi,
|
|
47
47
|
description: 'Cloudflare API Token detected',
|
|
48
48
|
severity: 'high',
|
|
49
49
|
},
|
|
@@ -122,7 +122,7 @@ const SECRET_PATTERNS = [
|
|
|
122
122
|
// Generic high-entropy strings in config values
|
|
123
123
|
{
|
|
124
124
|
name: 'high-entropy-string',
|
|
125
|
-
pattern: /(?:token|key|secret|password|credential|auth)\s*[:=]\s*['"]([a-zA-Z0-9+/=_
|
|
125
|
+
pattern: /(?:token|key|secret|password|credential|auth)\s*[:=]\s*['"]([a-zA-Z0-9+/=_-]{32,})['"]?/gi,
|
|
126
126
|
description: 'High-entropy string in sensitive field',
|
|
127
127
|
severity: 'medium',
|
|
128
128
|
},
|
package/dist/utils/skill.js
CHANGED
|
@@ -1380,12 +1380,266 @@ npx @haystackeditor/cli secrets get SECRET_NAME --show-metadata
|
|
|
1380
1380
|
- For CI, use GitHub Secrets or organization-level Haystack secrets
|
|
1381
1381
|
- Check \`npx @haystackeditor/cli secrets list --scope=org\`
|
|
1382
1382
|
`;
|
|
1383
|
+
const SETUP_RULES_CONTENT = `# Set Up Review Policies & Rules
|
|
1384
|
+
|
|
1385
|
+
**Your job**: Help the user configure two systems that control how Haystack evaluates their PRs:
|
|
1386
|
+
|
|
1387
|
+
1. **Review Policies** — deterministic, path-based triggers that **always** require human review
|
|
1388
|
+
2. **PR Rules** — LLM-evaluated code invariants that **flag violations** in the diff
|
|
1389
|
+
|
|
1390
|
+
These are distinct systems. Make sure the user understands the difference before proceeding.
|
|
1391
|
+
|
|
1392
|
+
---
|
|
1393
|
+
|
|
1394
|
+
## The Two Systems
|
|
1395
|
+
|
|
1396
|
+
### Review Policies (\`.haystack/review-policy.md\`)
|
|
1397
|
+
|
|
1398
|
+
**"If a PR touches X → human review needed, period."**
|
|
1399
|
+
|
|
1400
|
+
Policies are simple glob patterns. When a PR changes files matching a policy's paths, Haystack will always recommend human review for that PR, regardless of what the code changes look like.
|
|
1401
|
+
|
|
1402
|
+
**Good candidates for policies:**
|
|
1403
|
+
- Infrastructure (Terraform, Kubernetes, CI/CD pipelines)
|
|
1404
|
+
- Authentication and authorization code
|
|
1405
|
+
- Database migrations and schemas
|
|
1406
|
+
- API contracts (OpenAPI specs, GraphQL schemas, protobuf)
|
|
1407
|
+
- Security-sensitive code (crypto, secrets handling)
|
|
1408
|
+
- Billing/payment logic
|
|
1409
|
+
- Code that bypasses feature flags or launches directly to production
|
|
1410
|
+
|
|
1411
|
+
**Format:**
|
|
1412
|
+
\`\`\`markdown
|
|
1413
|
+
## Policy name
|
|
1414
|
+
- **Paths**: \\\`glob/pattern/**\\\`, \\\`other/pattern/*.ts\\\`
|
|
1415
|
+
- **Severity**: critical | high | medium | low
|
|
1416
|
+
- **Reason**: Why this always needs human eyes
|
|
1417
|
+
\`\`\`
|
|
1418
|
+
|
|
1419
|
+
### PR Rules (\`.haystack/pr-rules.yml\`)
|
|
1420
|
+
|
|
1421
|
+
**"If this invariant is violated in the diff → flag it."**
|
|
1422
|
+
|
|
1423
|
+
Rules are checked by an LLM that reads the PR diff and looks for violations. They catch patterns that shouldn't appear in new code, regardless of which files are touched.
|
|
1424
|
+
|
|
1425
|
+
**Good candidates for rules:**
|
|
1426
|
+
- Error handling conventions (no silent catches, no swallowed errors)
|
|
1427
|
+
- Logging requirements (all API calls must be logged)
|
|
1428
|
+
- Security patterns (no hardcoded secrets, no SQL string concatenation)
|
|
1429
|
+
- Code style invariants (no TODOs without issue refs, no console.log in production)
|
|
1430
|
+
- Architecture boundaries (service A must not import from service B)
|
|
1431
|
+
- Naming conventions specific to your team
|
|
1432
|
+
|
|
1433
|
+
**Format:**
|
|
1434
|
+
\`\`\`yaml
|
|
1435
|
+
- id: PR001
|
|
1436
|
+
name: Short rule name
|
|
1437
|
+
type: llm
|
|
1438
|
+
severity: warning | error
|
|
1439
|
+
message: Human-readable description of the violation
|
|
1440
|
+
llm:
|
|
1441
|
+
prompt: >
|
|
1442
|
+
Detailed instructions for the LLM about what to look for
|
|
1443
|
+
in the PR diff. Be specific about what counts as a violation
|
|
1444
|
+
and what doesn't.
|
|
1445
|
+
files: "optional/glob/pattern/**/*.ts" # optional file scope
|
|
1446
|
+
\`\`\`
|
|
1447
|
+
|
|
1448
|
+
---
|
|
1449
|
+
|
|
1450
|
+
## Step 1: Explore the Codebase
|
|
1451
|
+
|
|
1452
|
+
Before suggesting anything, understand the repo structure:
|
|
1453
|
+
|
|
1454
|
+
\`\`\`bash
|
|
1455
|
+
# Understand repo layout
|
|
1456
|
+
ls -la
|
|
1457
|
+
find . -maxdepth 2 -type d -not -path '*/node_modules/*' -not -path '*/.git/*' | head -40
|
|
1458
|
+
|
|
1459
|
+
# Find infrastructure files
|
|
1460
|
+
find . -name "*.tf" -o -name "Dockerfile*" -o -name "docker-compose*" -o -name "*.yml" -path "*/.github/*" | head -20
|
|
1461
|
+
|
|
1462
|
+
# Find auth-related code
|
|
1463
|
+
grep -rl "auth\\|login\\|session\\|token\\|credential" --include="*.ts" --include="*.py" --include="*.go" --include="*.js" -l | grep -v node_modules | head -20
|
|
1464
|
+
|
|
1465
|
+
# Find database/migration files
|
|
1466
|
+
find . -path "*/migration*" -o -path "*/schema*" -o -name "*.sql" | grep -v node_modules | head -20
|
|
1467
|
+
|
|
1468
|
+
# Find API contract files
|
|
1469
|
+
find . -name "*.proto" -o -name "openapi*" -o -name "swagger*" -o -name "*.graphql" | head -20
|
|
1470
|
+
|
|
1471
|
+
# Find feature flag patterns
|
|
1472
|
+
grep -rl "feature.?flag\\|feature.?toggle\\|isEnabled\\|FEATURE_" --include="*.ts" --include="*.py" --include="*.go" --include="*.js" -l | grep -v node_modules | head -20
|
|
1473
|
+
|
|
1474
|
+
# Check for existing config
|
|
1475
|
+
cat .haystack/review-policy.md 2>/dev/null || echo "No review-policy.md yet"
|
|
1476
|
+
cat .haystack/pr-rules.yml 2>/dev/null || echo "No pr-rules.yml yet"
|
|
1477
|
+
\`\`\`
|
|
1478
|
+
|
|
1479
|
+
Also look for:
|
|
1480
|
+
- CI/CD pipeline files
|
|
1481
|
+
- Payment or billing directories
|
|
1482
|
+
- Secrets or credential management code
|
|
1483
|
+
- Environment configuration patterns
|
|
1484
|
+
- Key shared libraries or core utilities that many things depend on
|
|
1485
|
+
|
|
1486
|
+
---
|
|
1487
|
+
|
|
1488
|
+
## STOP — Propose Review Policies
|
|
1489
|
+
|
|
1490
|
+
Present your findings to the user. Be specific about what you found and why each area warrants a policy.
|
|
1491
|
+
|
|
1492
|
+
**Format your proposal like this:**
|
|
1493
|
+
|
|
1494
|
+
> Based on the codebase, here are the areas I'd recommend always requiring human review:
|
|
1495
|
+
>
|
|
1496
|
+
> | # | Policy | Paths | Severity | Why |
|
|
1497
|
+
> |---|--------|-------|----------|-----|
|
|
1498
|
+
> | 1 | Infrastructure | \\\`terraform/**\\\`, \\\`*.tf\\\` | high | Cost and security implications |
|
|
1499
|
+
> | 2 | Auth & secrets | \\\`src/auth/**\\\`, \\\`**/*.secret*\\\` | critical | Security-sensitive |
|
|
1500
|
+
> | 3 | ... | ... | ... | ... |
|
|
1501
|
+
>
|
|
1502
|
+
> **Notes:**
|
|
1503
|
+
> - I didn't find any database migrations in this repo, so I'm not including that
|
|
1504
|
+
> - The \`src/core/\` directory is imported by everything — should changes there always need review?
|
|
1505
|
+
>
|
|
1506
|
+
> Which of these should I include? Any to add, remove, or modify?
|
|
1507
|
+
|
|
1508
|
+
**Wait for the user to confirm before writing anything.**
|
|
1509
|
+
|
|
1510
|
+
---
|
|
1511
|
+
|
|
1512
|
+
## Step 2: Write review-policy.md
|
|
1513
|
+
|
|
1514
|
+
Once the user confirms, write the policies to \`.haystack/review-policy.md\`:
|
|
1515
|
+
|
|
1516
|
+
\`\`\`markdown
|
|
1517
|
+
# Review Policies
|
|
1518
|
+
|
|
1519
|
+
Review policies define file patterns that always require human attention. When a PR touches files matching these patterns, Haystack will flag it for human review.
|
|
1520
|
+
|
|
1521
|
+
## [Policy name]
|
|
1522
|
+
- **Paths**: \\\`pattern/**\\\`
|
|
1523
|
+
- **Severity**: [level]
|
|
1524
|
+
- **Reason**: [why]
|
|
1525
|
+
\`\`\`
|
|
1526
|
+
|
|
1527
|
+
Create the \`.haystack/\` directory if it doesn't exist.
|
|
1528
|
+
|
|
1529
|
+
---
|
|
1530
|
+
|
|
1531
|
+
## Step 3: Understand Team Conventions
|
|
1532
|
+
|
|
1533
|
+
Now shift to rules. Ask the user about their code quality invariants:
|
|
1534
|
+
|
|
1535
|
+
> Now let's set up **PR rules** — these are code invariants that Haystack checks in every diff.
|
|
1536
|
+
>
|
|
1537
|
+
> Unlike policies (which trigger on file paths), rules look at *what the code does*. For example:
|
|
1538
|
+
> - "Don't add empty catch blocks"
|
|
1539
|
+
> - "Don't add TODOs without issue references"
|
|
1540
|
+
> - "Don't hardcode API URLs"
|
|
1541
|
+
>
|
|
1542
|
+
> **What conventions does your team care about?** Some common categories:
|
|
1543
|
+
>
|
|
1544
|
+
> 1. **Error handling** — e.g., no swallowed errors, no silent fallbacks
|
|
1545
|
+
> 2. **Security** — e.g., no hardcoded secrets, no raw SQL strings
|
|
1546
|
+
> 3. **Logging** — e.g., all API calls must have logging
|
|
1547
|
+
> 4. **Code hygiene** — e.g., no TODOs without issues, no console.log in production
|
|
1548
|
+
> 5. **Architecture** — e.g., no cross-service imports, no direct DB access from UI layer
|
|
1549
|
+
> 6. **Testing** — e.g., no skipped tests without reason, no snapshot-only tests
|
|
1550
|
+
>
|
|
1551
|
+
> Tell me which categories matter to your team, or describe your own conventions.
|
|
1552
|
+
|
|
1553
|
+
Also explore the codebase for clues:
|
|
1554
|
+
|
|
1555
|
+
\`\`\`bash
|
|
1556
|
+
# Check for linter configs (reveals team conventions)
|
|
1557
|
+
cat .eslintrc* .eslintrc.json .eslintrc.js eslint.config.* 2>/dev/null | head -50
|
|
1558
|
+
|
|
1559
|
+
# Check for existing code review guidelines
|
|
1560
|
+
find . -name "CONTRIBUTING*" -o -name "REVIEW*" -o -name "STYLE*" | head -5
|
|
1561
|
+
|
|
1562
|
+
# Look for common anti-patterns
|
|
1563
|
+
grep -rn "catch.*{\\s*}" --include="*.ts" --include="*.js" | head -5
|
|
1564
|
+
grep -rn "console\\.log" --include="*.ts" --include="*.tsx" | grep -v test | head -5
|
|
1565
|
+
grep -rn "TODO\\|FIXME\\|HACK\\|XXX" --include="*.ts" --include="*.tsx" | head -10
|
|
1566
|
+
\`\`\`
|
|
1567
|
+
|
|
1568
|
+
---
|
|
1569
|
+
|
|
1570
|
+
## STOP — Propose PR Rules
|
|
1571
|
+
|
|
1572
|
+
Based on the user's input and your codebase exploration, propose 2-5 custom rules.
|
|
1573
|
+
|
|
1574
|
+
**Format your proposal like this:**
|
|
1575
|
+
|
|
1576
|
+
> Here are the PR rules I'd suggest:
|
|
1577
|
+
>
|
|
1578
|
+
> **1. PR001 — No silent error handling** (warning)
|
|
1579
|
+
> > Flag: Adding catch blocks that swallow errors without logging or re-throwing
|
|
1580
|
+
>
|
|
1581
|
+
> **2. PR002 — No TODOs without tracking issues** (warning)
|
|
1582
|
+
> > Flag: Adding TODO/FIXME comments without referencing an issue number
|
|
1583
|
+
>
|
|
1584
|
+
> **3. PR003 — No hardcoded API endpoints** (warning)
|
|
1585
|
+
> > Flag: Adding hardcoded URLs or API endpoints instead of using config/env vars
|
|
1586
|
+
>
|
|
1587
|
+
> Should I add, remove, or modify any of these?
|
|
1588
|
+
|
|
1589
|
+
**Wait for the user to confirm before writing.**
|
|
1590
|
+
|
|
1591
|
+
---
|
|
1592
|
+
|
|
1593
|
+
## Step 4: Write pr-rules.yml
|
|
1594
|
+
|
|
1595
|
+
Once confirmed, write to \`.haystack/pr-rules.yml\`:
|
|
1596
|
+
|
|
1597
|
+
\`\`\`yaml
|
|
1598
|
+
version: 1
|
|
1599
|
+
|
|
1600
|
+
rules:
|
|
1601
|
+
- id: PR001
|
|
1602
|
+
name: [Short name]
|
|
1603
|
+
type: llm
|
|
1604
|
+
severity: warning
|
|
1605
|
+
message: [Human-readable description]
|
|
1606
|
+
llm:
|
|
1607
|
+
prompt: >
|
|
1608
|
+
[Detailed LLM instructions — be specific about what counts as
|
|
1609
|
+
a violation and what doesn't. Include examples of violations
|
|
1610
|
+
and non-violations when helpful.]
|
|
1611
|
+
\`\`\`
|
|
1612
|
+
|
|
1613
|
+
**Tips for writing good rule prompts:**
|
|
1614
|
+
- Be specific about what counts as a violation
|
|
1615
|
+
- Mention common false positives to ignore (e.g., "test files are exempt")
|
|
1616
|
+
- Use the \`files\` field to scope rules to relevant file types
|
|
1617
|
+
- \`severity: error\` caps the Haystack rating at 3 (needs review); \`warning\` is advisory
|
|
1618
|
+
|
|
1619
|
+
---
|
|
1620
|
+
|
|
1621
|
+
## Step 5: Commit
|
|
1622
|
+
|
|
1623
|
+
\`\`\`bash
|
|
1624
|
+
git add .haystack/review-policy.md .haystack/pr-rules.yml
|
|
1625
|
+
git commit -m "Add Haystack review policies and PR rules"
|
|
1626
|
+
\`\`\`
|
|
1627
|
+
|
|
1628
|
+
Done! Haystack will now:
|
|
1629
|
+
- Flag PRs touching policy-matched files for human review
|
|
1630
|
+
- Check every PR diff against your custom rules and report violations
|
|
1631
|
+
`;
|
|
1632
|
+
const SETUP_RULES_COMMAND = `# Set Up Rules
|
|
1633
|
+
|
|
1634
|
+
Follow .agents/skills/setup-haystack-rules.md to configure review policies (what always needs human review) and PR rules (what code invariants to enforce).
|
|
1635
|
+
`;
|
|
1383
1636
|
export async function createSkillFile() {
|
|
1384
1637
|
const skillDir = path.join(process.cwd(), '.agents', 'skills');
|
|
1385
1638
|
const setupPath = path.join(skillDir, 'setup-haystack.md');
|
|
1386
1639
|
const refPath = path.join(skillDir, 'haystack-reference.md');
|
|
1387
1640
|
const prepPath = path.join(skillDir, 'prepare-haystack.md');
|
|
1388
1641
|
const secretsPath = path.join(skillDir, 'setup-haystack-secrets.md');
|
|
1642
|
+
const rulesPath = path.join(skillDir, 'setup-haystack-rules.md');
|
|
1389
1643
|
// Create directory if needed
|
|
1390
1644
|
await fs.mkdir(skillDir, { recursive: true });
|
|
1391
1645
|
// Write all skill files
|
|
@@ -1393,6 +1647,7 @@ export async function createSkillFile() {
|
|
|
1393
1647
|
await fs.writeFile(refPath, REFERENCE_CONTENT, 'utf-8');
|
|
1394
1648
|
await fs.writeFile(prepPath, PREPARE_VERIFICATION_CONTENT, 'utf-8');
|
|
1395
1649
|
await fs.writeFile(secretsPath, SECRETS_SKILL_CONTENT, 'utf-8');
|
|
1650
|
+
await fs.writeFile(rulesPath, SETUP_RULES_CONTENT, 'utf-8');
|
|
1396
1651
|
return setupPath;
|
|
1397
1652
|
}
|
|
1398
1653
|
/**
|
|
@@ -1404,11 +1659,13 @@ export async function createClaudeCommand() {
|
|
|
1404
1659
|
const setupPath = path.join(commandDir, 'setup-haystack.md');
|
|
1405
1660
|
const prepPath = path.join(commandDir, 'prepare-haystack.md');
|
|
1406
1661
|
const secretsPath = path.join(commandDir, 'setup-haystack-secrets.md');
|
|
1662
|
+
const rulesPath = path.join(commandDir, 'setup-haystack-rules.md');
|
|
1407
1663
|
// Create directory if needed
|
|
1408
1664
|
await fs.mkdir(commandDir, { recursive: true });
|
|
1409
1665
|
// Write command files
|
|
1410
1666
|
await fs.writeFile(setupPath, CLAUDE_COMMAND_CONTENT, 'utf-8');
|
|
1411
1667
|
await fs.writeFile(prepPath, PREPARE_HAYSTACK_COMMAND, 'utf-8');
|
|
1412
1668
|
await fs.writeFile(secretsPath, SECRETS_COMMAND_CONTENT, 'utf-8');
|
|
1669
|
+
await fs.writeFile(rulesPath, SETUP_RULES_COMMAND, 'utf-8');
|
|
1413
1670
|
return setupPath;
|
|
1414
1671
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haystackeditor/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Set up Haystack verification for your project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,16 +32,18 @@
|
|
|
32
32
|
"url": "https://github.com/haystackeditor/haystack-review/issues"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"chalk": "
|
|
36
|
-
"commander": "
|
|
37
|
-
"fast-glob": "
|
|
38
|
-
"
|
|
39
|
-
"
|
|
35
|
+
"chalk": "5.6.2",
|
|
36
|
+
"commander": "12.1.0",
|
|
37
|
+
"fast-glob": "3.3.3",
|
|
38
|
+
"glob": "10.5.0",
|
|
39
|
+
"inquirer": "9.3.8",
|
|
40
|
+
"yaml": "2.8.2",
|
|
41
|
+
"zod": "3.25.76"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
|
-
"@types/inquirer": "
|
|
43
|
-
"@types/node": "
|
|
44
|
-
"typescript": "
|
|
44
|
+
"@types/inquirer": "9.0.9",
|
|
45
|
+
"@types/node": "20.19.30",
|
|
46
|
+
"typescript": "5.9.3"
|
|
45
47
|
},
|
|
46
48
|
"files": [
|
|
47
49
|
"dist"
|