@haystackeditor/cli 0.10.2 → 0.11.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 +6 -4
- package/dist/commands/config.js +81 -66
- package/dist/commands/dismiss.js +2 -1
- package/dist/commands/request-review.d.ts +15 -0
- package/dist/commands/request-review.js +95 -0
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +274 -2
- package/dist/commands/submit.js +1 -1
- package/dist/commands/triage.js +115 -23
- package/dist/index.d.ts +1 -0
- package/dist/index.js +43 -18
- package/dist/triage/prompts.js +13 -5
- package/dist/triage/runner.js +1 -1
- package/dist/triage/types.d.ts +1 -1
- package/dist/types.d.ts +132 -26
- package/dist/types.js +42 -5
- package/dist/utils/analysis-api.d.ts +16 -0
- package/dist/utils/analysis-api.js +23 -5
- package/dist/utils/telemetry.d.ts +17 -0
- package/dist/utils/telemetry.js +109 -0
- package/package.json +1 -1
- package/dist/commands/secrets.d.ts +0 -33
- package/dist/commands/secrets.js +0 -216
- package/dist/tools/fixtures.d.ts +0 -38
- package/dist/tools/fixtures.js +0 -199
- package/dist/tools/setup.d.ts +0 -43
- package/dist/tools/setup.js +0 -597
- package/dist/utils/skill.d.ts +0 -10
- package/dist/utils/skill.js +0 -1671
package/dist/triage/prompts.js
CHANGED
|
@@ -45,7 +45,7 @@ const INTENT_DRIFT_SCHEMA = `{
|
|
|
45
45
|
"line": 42,
|
|
46
46
|
"severity": "error | warning | info",
|
|
47
47
|
"message": "Description of the drift or incomplete fulfillment",
|
|
48
|
-
"pattern": "intent_drift | incomplete_fulfillment"
|
|
48
|
+
"pattern": "intent_drift | incomplete_fulfillment | scope_creep"
|
|
49
49
|
}
|
|
50
50
|
],
|
|
51
51
|
"summary": "Brief 1-sentence summary",
|
|
@@ -261,12 +261,20 @@ The agent didn't finish everything that was asked:
|
|
|
261
261
|
- Agent said "I'll skip X for now" for something the user explicitly requested
|
|
262
262
|
- Tests not written when user asked for tests
|
|
263
263
|
|
|
264
|
+
### Scope Creep
|
|
265
|
+
The agent added functionality the user never asked for:
|
|
266
|
+
- User asks to fix a bug → agent also adds a cooldown, retry logic, or caching layer
|
|
267
|
+
- User asks to investigate → agent proactively "fixes" things beyond what was discussed
|
|
268
|
+
- User asks for one feature → agent bundles in extra features "while we're at it"
|
|
269
|
+
- Any new mechanism not traceable to a user instruction
|
|
270
|
+
|
|
264
271
|
## Red flags to search for in the diff
|
|
265
272
|
|
|
266
273
|
- Fixed/hardcoded values where dynamic behavior was requested
|
|
267
274
|
- TODO, FIXME, placeholder, stub comments in new code
|
|
268
275
|
- Empty function bodies or early returns
|
|
269
276
|
- Interface fields that are declared but never assigned anywhere
|
|
277
|
+
- New mechanisms (cooldowns, retries, caches, rate limits) not requested by the user
|
|
270
278
|
|
|
271
279
|
## Output
|
|
272
280
|
|
|
@@ -277,15 +285,15 @@ ${INTENT_DRIFT_SCHEMA}
|
|
|
277
285
|
\`\`\`
|
|
278
286
|
|
|
279
287
|
- Set \`sessionsChecked\` to the number of trace files you read
|
|
280
|
-
- Set \`passed\` to \`true\` if no drift
|
|
288
|
+
- Set \`passed\` to \`true\` if no drift, incomplete fulfillment, or scope creep found
|
|
281
289
|
- Set \`passed\` to \`false\` if any issues with severity "error" were found
|
|
282
|
-
- For each issue, set \`pattern\` to
|
|
290
|
+
- For each issue, set \`pattern\` to "intent_drift", "incomplete_fulfillment", or "scope_creep"
|
|
283
291
|
- You MUST write the result file even if no issues are found
|
|
284
292
|
|
|
285
293
|
## Severity guidelines
|
|
286
294
|
|
|
287
|
-
- **error**: Core user intent violated — the main thing they asked for is wrong or missing
|
|
288
|
-
- **warning**: Secondary requirement missed or approximated
|
|
295
|
+
- **error**: Core user intent violated — the main thing they asked for is wrong or missing, or large unrequested feature added
|
|
296
|
+
- **warning**: Secondary requirement missed or approximated, or small unrequested mechanism added
|
|
289
297
|
- **info**: Minor simplification that mostly still works as intended${precomputedDiff ? `
|
|
290
298
|
|
|
291
299
|
## Diff (precomputed)
|
package/dist/triage/runner.js
CHANGED
|
@@ -17,7 +17,7 @@ const TRIAGE_DIR = '.haystack/triage';
|
|
|
17
17
|
const TIMEOUT_MS = 300_000; // 5 minutes per checker
|
|
18
18
|
/** Max agentic turns per checker — kept tight since these are read-only tasks */
|
|
19
19
|
const MAX_TURNS = {
|
|
20
|
-
'code-review':
|
|
20
|
+
'code-review': 5,
|
|
21
21
|
'rules-validator': 10,
|
|
22
22
|
'intent-drift': 10,
|
|
23
23
|
};
|
package/dist/triage/types.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface TriageIssue {
|
|
|
13
13
|
/** For rules validator: rule ID (e.g., PR001) */
|
|
14
14
|
rule?: string;
|
|
15
15
|
/** For intent drift: drift pattern */
|
|
16
|
-
pattern?: 'intent_drift' | 'incomplete_fulfillment';
|
|
16
|
+
pattern?: 'intent_drift' | 'incomplete_fulfillment' | 'scope_creep';
|
|
17
17
|
}
|
|
18
18
|
export interface CodeReviewResult {
|
|
19
19
|
checker: 'code-review';
|
package/dist/types.d.ts
CHANGED
|
@@ -56,7 +56,9 @@ declare const DevServerSchema: z.ZodObject<{
|
|
|
56
56
|
/** Valid AI reviewer source identifiers that the merge queue can wait for */
|
|
57
57
|
export declare const AI_REVIEWER_SOURCES: readonly ["cursor", "coderabbit", "copilot", "greptile", "sourcery", "qodo", "codeant", "ellipsis", "korbit", "panto", "bito", "graphite", "deepsource", "snyk", "codacy", "sonarcloud", "sweep", "codeguru", "codereviewer", "codium"];
|
|
58
58
|
export declare const AI_REVIEWER_DISPLAY_NAMES: Record<typeof AI_REVIEWER_SOURCES[number], string>;
|
|
59
|
-
|
|
59
|
+
/** Maps friendly source names to exact GitHub bot login usernames. */
|
|
60
|
+
export declare const AI_REVIEWER_BOT_USERNAMES: Record<typeof AI_REVIEWER_SOURCES[number], string>;
|
|
61
|
+
declare const MergeQueueConfigSchema: z.ZodObject<{
|
|
60
62
|
/** Enable the Haystack auto-merge queue */
|
|
61
63
|
merge_queue: z.ZodOptional<z.ZodBoolean>;
|
|
62
64
|
/** Automatically rebase PRs that develop merge conflicts after pushes to the base branch */
|
|
@@ -74,8 +76,36 @@ declare const BabysitterConfigSchema: z.ZodObject<{
|
|
|
74
76
|
default_minutes?: number | undefined;
|
|
75
77
|
authors?: Record<string, number> | undefined;
|
|
76
78
|
}>>;
|
|
77
|
-
/**
|
|
78
|
-
|
|
79
|
+
/** Batch multiple PRs into one CI run */
|
|
80
|
+
batch_merge: z.ZodOptional<z.ZodObject<{
|
|
81
|
+
/** Enable batch merging */
|
|
82
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
83
|
+
/** Minimum PRs to form a batch */
|
|
84
|
+
min_batch_size: z.ZodOptional<z.ZodNumber>;
|
|
85
|
+
/** Maximum PRs per batch (cap: 20) */
|
|
86
|
+
max_batch_size: z.ZodOptional<z.ZodNumber>;
|
|
87
|
+
}, "strip", z.ZodTypeAny, {
|
|
88
|
+
enabled?: boolean | undefined;
|
|
89
|
+
min_batch_size?: number | undefined;
|
|
90
|
+
max_batch_size?: number | undefined;
|
|
91
|
+
}, {
|
|
92
|
+
enabled?: boolean | undefined;
|
|
93
|
+
min_batch_size?: number | undefined;
|
|
94
|
+
max_batch_size?: number | undefined;
|
|
95
|
+
}>>;
|
|
96
|
+
/** Wait for external AI code reviewers before merging — all bots must post */
|
|
97
|
+
wait_for_reviewer: z.ZodOptional<z.ZodObject<{
|
|
98
|
+
/** GitHub bot usernames to wait for (e.g. "cursor-bugbot[bot]") */
|
|
99
|
+
bots: z.ZodArray<z.ZodString, "many">;
|
|
100
|
+
/** Give up waiting after this many minutes (default: 30) */
|
|
101
|
+
timeout_minutes: z.ZodOptional<z.ZodNumber>;
|
|
102
|
+
}, "strip", z.ZodTypeAny, {
|
|
103
|
+
bots: string[];
|
|
104
|
+
timeout_minutes?: number | undefined;
|
|
105
|
+
}, {
|
|
106
|
+
bots: string[];
|
|
107
|
+
timeout_minutes?: number | undefined;
|
|
108
|
+
}>>;
|
|
79
109
|
}, "strip", z.ZodTypeAny, {
|
|
80
110
|
merge_queue?: boolean | undefined;
|
|
81
111
|
auto_resolve_conflicts?: boolean | undefined;
|
|
@@ -83,7 +113,15 @@ declare const BabysitterConfigSchema: z.ZodObject<{
|
|
|
83
113
|
default_minutes?: number | undefined;
|
|
84
114
|
authors?: Record<string, number> | undefined;
|
|
85
115
|
} | undefined;
|
|
86
|
-
|
|
116
|
+
batch_merge?: {
|
|
117
|
+
enabled?: boolean | undefined;
|
|
118
|
+
min_batch_size?: number | undefined;
|
|
119
|
+
max_batch_size?: number | undefined;
|
|
120
|
+
} | undefined;
|
|
121
|
+
wait_for_reviewer?: {
|
|
122
|
+
bots: string[];
|
|
123
|
+
timeout_minutes?: number | undefined;
|
|
124
|
+
} | undefined;
|
|
87
125
|
}, {
|
|
88
126
|
merge_queue?: boolean | undefined;
|
|
89
127
|
auto_resolve_conflicts?: boolean | undefined;
|
|
@@ -91,7 +129,15 @@ declare const BabysitterConfigSchema: z.ZodObject<{
|
|
|
91
129
|
default_minutes?: number | undefined;
|
|
92
130
|
authors?: Record<string, number> | undefined;
|
|
93
131
|
} | undefined;
|
|
94
|
-
|
|
132
|
+
batch_merge?: {
|
|
133
|
+
enabled?: boolean | undefined;
|
|
134
|
+
min_batch_size?: number | undefined;
|
|
135
|
+
max_batch_size?: number | undefined;
|
|
136
|
+
} | undefined;
|
|
137
|
+
wait_for_reviewer?: {
|
|
138
|
+
bots: string[];
|
|
139
|
+
timeout_minutes?: number | undefined;
|
|
140
|
+
} | undefined;
|
|
95
141
|
}>;
|
|
96
142
|
declare const ServiceSchema: z.ZodObject<{
|
|
97
143
|
/** Root directory relative to repo root */
|
|
@@ -1109,8 +1155,8 @@ export declare const HaystackConfigSchema: z.ZodObject<{
|
|
|
1109
1155
|
services?: string[] | undefined;
|
|
1110
1156
|
description?: string | undefined;
|
|
1111
1157
|
}>>>;
|
|
1112
|
-
/**
|
|
1113
|
-
|
|
1158
|
+
/** Merge queue configuration for autonomous PR maintenance */
|
|
1159
|
+
merge_queue: z.ZodOptional<z.ZodObject<{
|
|
1114
1160
|
/** Enable the Haystack auto-merge queue */
|
|
1115
1161
|
merge_queue: z.ZodOptional<z.ZodBoolean>;
|
|
1116
1162
|
/** Automatically rebase PRs that develop merge conflicts after pushes to the base branch */
|
|
@@ -1128,8 +1174,36 @@ export declare const HaystackConfigSchema: z.ZodObject<{
|
|
|
1128
1174
|
default_minutes?: number | undefined;
|
|
1129
1175
|
authors?: Record<string, number> | undefined;
|
|
1130
1176
|
}>>;
|
|
1131
|
-
/**
|
|
1132
|
-
|
|
1177
|
+
/** Batch multiple PRs into one CI run */
|
|
1178
|
+
batch_merge: z.ZodOptional<z.ZodObject<{
|
|
1179
|
+
/** Enable batch merging */
|
|
1180
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
1181
|
+
/** Minimum PRs to form a batch */
|
|
1182
|
+
min_batch_size: z.ZodOptional<z.ZodNumber>;
|
|
1183
|
+
/** Maximum PRs per batch (cap: 20) */
|
|
1184
|
+
max_batch_size: z.ZodOptional<z.ZodNumber>;
|
|
1185
|
+
}, "strip", z.ZodTypeAny, {
|
|
1186
|
+
enabled?: boolean | undefined;
|
|
1187
|
+
min_batch_size?: number | undefined;
|
|
1188
|
+
max_batch_size?: number | undefined;
|
|
1189
|
+
}, {
|
|
1190
|
+
enabled?: boolean | undefined;
|
|
1191
|
+
min_batch_size?: number | undefined;
|
|
1192
|
+
max_batch_size?: number | undefined;
|
|
1193
|
+
}>>;
|
|
1194
|
+
/** Wait for external AI code reviewers before merging — all bots must post */
|
|
1195
|
+
wait_for_reviewer: z.ZodOptional<z.ZodObject<{
|
|
1196
|
+
/** GitHub bot usernames to wait for (e.g. "cursor-bugbot[bot]") */
|
|
1197
|
+
bots: z.ZodArray<z.ZodString, "many">;
|
|
1198
|
+
/** Give up waiting after this many minutes (default: 30) */
|
|
1199
|
+
timeout_minutes: z.ZodOptional<z.ZodNumber>;
|
|
1200
|
+
}, "strip", z.ZodTypeAny, {
|
|
1201
|
+
bots: string[];
|
|
1202
|
+
timeout_minutes?: number | undefined;
|
|
1203
|
+
}, {
|
|
1204
|
+
bots: string[];
|
|
1205
|
+
timeout_minutes?: number | undefined;
|
|
1206
|
+
}>>;
|
|
1133
1207
|
}, "strip", z.ZodTypeAny, {
|
|
1134
1208
|
merge_queue?: boolean | undefined;
|
|
1135
1209
|
auto_resolve_conflicts?: boolean | undefined;
|
|
@@ -1137,7 +1211,15 @@ export declare const HaystackConfigSchema: z.ZodObject<{
|
|
|
1137
1211
|
default_minutes?: number | undefined;
|
|
1138
1212
|
authors?: Record<string, number> | undefined;
|
|
1139
1213
|
} | undefined;
|
|
1140
|
-
|
|
1214
|
+
batch_merge?: {
|
|
1215
|
+
enabled?: boolean | undefined;
|
|
1216
|
+
min_batch_size?: number | undefined;
|
|
1217
|
+
max_batch_size?: number | undefined;
|
|
1218
|
+
} | undefined;
|
|
1219
|
+
wait_for_reviewer?: {
|
|
1220
|
+
bots: string[];
|
|
1221
|
+
timeout_minutes?: number | undefined;
|
|
1222
|
+
} | undefined;
|
|
1141
1223
|
}, {
|
|
1142
1224
|
merge_queue?: boolean | undefined;
|
|
1143
1225
|
auto_resolve_conflicts?: boolean | undefined;
|
|
@@ -1145,11 +1227,36 @@ export declare const HaystackConfigSchema: z.ZodObject<{
|
|
|
1145
1227
|
default_minutes?: number | undefined;
|
|
1146
1228
|
authors?: Record<string, number> | undefined;
|
|
1147
1229
|
} | undefined;
|
|
1148
|
-
|
|
1230
|
+
batch_merge?: {
|
|
1231
|
+
enabled?: boolean | undefined;
|
|
1232
|
+
min_batch_size?: number | undefined;
|
|
1233
|
+
max_batch_size?: number | undefined;
|
|
1234
|
+
} | undefined;
|
|
1235
|
+
wait_for_reviewer?: {
|
|
1236
|
+
bots: string[];
|
|
1237
|
+
timeout_minutes?: number | undefined;
|
|
1238
|
+
} | undefined;
|
|
1149
1239
|
}>>;
|
|
1150
1240
|
}, "strip", z.ZodTypeAny, {
|
|
1151
1241
|
version: "1";
|
|
1152
1242
|
name?: string | undefined;
|
|
1243
|
+
merge_queue?: {
|
|
1244
|
+
merge_queue?: boolean | undefined;
|
|
1245
|
+
auto_resolve_conflicts?: boolean | undefined;
|
|
1246
|
+
merge_debounce?: {
|
|
1247
|
+
default_minutes?: number | undefined;
|
|
1248
|
+
authors?: Record<string, number> | undefined;
|
|
1249
|
+
} | undefined;
|
|
1250
|
+
batch_merge?: {
|
|
1251
|
+
enabled?: boolean | undefined;
|
|
1252
|
+
min_batch_size?: number | undefined;
|
|
1253
|
+
max_batch_size?: number | undefined;
|
|
1254
|
+
} | undefined;
|
|
1255
|
+
wait_for_reviewer?: {
|
|
1256
|
+
bots: string[];
|
|
1257
|
+
timeout_minutes?: number | undefined;
|
|
1258
|
+
} | undefined;
|
|
1259
|
+
} | undefined;
|
|
1153
1260
|
services?: Record<string, {
|
|
1154
1261
|
command: string;
|
|
1155
1262
|
type?: "server" | "batch" | undefined;
|
|
@@ -1251,18 +1358,26 @@ export declare const HaystackConfigSchema: z.ZodObject<{
|
|
|
1251
1358
|
services?: string[] | undefined;
|
|
1252
1359
|
description?: string | undefined;
|
|
1253
1360
|
}> | undefined;
|
|
1254
|
-
|
|
1361
|
+
}, {
|
|
1362
|
+
version: "1";
|
|
1363
|
+
name?: string | undefined;
|
|
1364
|
+
merge_queue?: {
|
|
1255
1365
|
merge_queue?: boolean | undefined;
|
|
1256
1366
|
auto_resolve_conflicts?: boolean | undefined;
|
|
1257
1367
|
merge_debounce?: {
|
|
1258
1368
|
default_minutes?: number | undefined;
|
|
1259
1369
|
authors?: Record<string, number> | undefined;
|
|
1260
1370
|
} | undefined;
|
|
1261
|
-
|
|
1371
|
+
batch_merge?: {
|
|
1372
|
+
enabled?: boolean | undefined;
|
|
1373
|
+
min_batch_size?: number | undefined;
|
|
1374
|
+
max_batch_size?: number | undefined;
|
|
1375
|
+
} | undefined;
|
|
1376
|
+
wait_for_reviewer?: {
|
|
1377
|
+
bots: string[];
|
|
1378
|
+
timeout_minutes?: number | undefined;
|
|
1379
|
+
} | undefined;
|
|
1262
1380
|
} | undefined;
|
|
1263
|
-
}, {
|
|
1264
|
-
version: "1";
|
|
1265
|
-
name?: string | undefined;
|
|
1266
1381
|
services?: Record<string, {
|
|
1267
1382
|
command: string;
|
|
1268
1383
|
type?: "server" | "batch" | undefined;
|
|
@@ -1364,15 +1479,6 @@ export declare const HaystackConfigSchema: z.ZodObject<{
|
|
|
1364
1479
|
services?: string[] | undefined;
|
|
1365
1480
|
description?: string | undefined;
|
|
1366
1481
|
}> | undefined;
|
|
1367
|
-
babysitter?: {
|
|
1368
|
-
merge_queue?: boolean | undefined;
|
|
1369
|
-
auto_resolve_conflicts?: boolean | undefined;
|
|
1370
|
-
merge_debounce?: {
|
|
1371
|
-
default_minutes?: number | undefined;
|
|
1372
|
-
authors?: Record<string, number> | undefined;
|
|
1373
|
-
} | undefined;
|
|
1374
|
-
expected_ai_reviewers?: ("cursor" | "coderabbit" | "copilot" | "greptile" | "sourcery" | "qodo" | "codeant" | "ellipsis" | "korbit" | "panto" | "bito" | "graphite" | "deepsource" | "snyk" | "codacy" | "sonarcloud" | "sweep" | "codeguru" | "codereviewer" | "codium")[] | undefined;
|
|
1375
|
-
} | undefined;
|
|
1376
1482
|
}>;
|
|
1377
1483
|
export type HaystackConfig = z.infer<typeof HaystackConfigSchema>;
|
|
1378
1484
|
export type VerificationCommand = z.infer<typeof VerificationCommandSchema>;
|
|
@@ -1392,7 +1498,7 @@ export type DockerService = z.infer<typeof DockerServiceSchema>;
|
|
|
1392
1498
|
export type DatabaseConfig = z.infer<typeof DatabaseConfigSchema>;
|
|
1393
1499
|
export type NetworkConfig = z.infer<typeof NetworkConfigSchema>;
|
|
1394
1500
|
export type SecretDeclaration = z.infer<typeof SecretDeclarationSchema>;
|
|
1395
|
-
export type
|
|
1501
|
+
export type MergeQueueConfig = z.infer<typeof MergeQueueConfigSchema>;
|
|
1396
1502
|
/**
|
|
1397
1503
|
* Project detection results
|
|
1398
1504
|
*/
|
package/dist/types.js
CHANGED
|
@@ -94,8 +94,31 @@ export const AI_REVIEWER_DISPLAY_NAMES = {
|
|
|
94
94
|
codereviewer: 'CodeReviewBot',
|
|
95
95
|
codium: 'Codium',
|
|
96
96
|
};
|
|
97
|
+
/** Maps friendly source names to exact GitHub bot login usernames. */
|
|
98
|
+
export const AI_REVIEWER_BOT_USERNAMES = {
|
|
99
|
+
cursor: 'cursor-bugbot[bot]',
|
|
100
|
+
coderabbit: 'coderabbitai[bot]',
|
|
101
|
+
copilot: 'copilot[bot]',
|
|
102
|
+
greptile: 'greptile[bot]',
|
|
103
|
+
sourcery: 'sourcery-ai[bot]',
|
|
104
|
+
qodo: 'qodo-merge-pro[bot]',
|
|
105
|
+
codeant: 'codeant-ai[bot]',
|
|
106
|
+
ellipsis: 'ellipsis-dev[bot]',
|
|
107
|
+
korbit: 'korbit-ai[bot]',
|
|
108
|
+
panto: 'pantoaibot[bot]',
|
|
109
|
+
bito: 'bito[bot]',
|
|
110
|
+
graphite: 'graphite-app[bot]',
|
|
111
|
+
deepsource: 'deepsource-io[bot]',
|
|
112
|
+
snyk: 'snyk[bot]',
|
|
113
|
+
codacy: 'codacy-production[bot]',
|
|
114
|
+
sonarcloud: 'sonarcloud[bot]',
|
|
115
|
+
sweep: 'sweep-ai[bot]',
|
|
116
|
+
codeguru: 'aws-codeguru-reviewer[bot]',
|
|
117
|
+
codereviewer: 'codereviewbot[bot]',
|
|
118
|
+
codium: 'codiumai[bot]',
|
|
119
|
+
};
|
|
97
120
|
const AIReviewerSourceSchema = z.enum(AI_REVIEWER_SOURCES);
|
|
98
|
-
const
|
|
121
|
+
const MergeQueueConfigSchema = z.object({
|
|
99
122
|
/** Enable the Haystack auto-merge queue */
|
|
100
123
|
merge_queue: z.boolean().optional(),
|
|
101
124
|
/** Automatically rebase PRs that develop merge conflicts after pushes to the base branch */
|
|
@@ -107,8 +130,22 @@ const BabysitterConfigSchema = z.object({
|
|
|
107
130
|
/** Per-author wait time overrides (author login → minutes) */
|
|
108
131
|
authors: z.record(z.string(), z.number()).optional(),
|
|
109
132
|
}).optional(),
|
|
110
|
-
/**
|
|
111
|
-
|
|
133
|
+
/** Batch multiple PRs into one CI run */
|
|
134
|
+
batch_merge: z.object({
|
|
135
|
+
/** Enable batch merging */
|
|
136
|
+
enabled: z.boolean().optional(),
|
|
137
|
+
/** Minimum PRs to form a batch */
|
|
138
|
+
min_batch_size: z.number().optional(),
|
|
139
|
+
/** Maximum PRs per batch (cap: 20) */
|
|
140
|
+
max_batch_size: z.number().optional(),
|
|
141
|
+
}).optional(),
|
|
142
|
+
/** Wait for external AI code reviewers before merging — all bots must post */
|
|
143
|
+
wait_for_reviewer: z.object({
|
|
144
|
+
/** GitHub bot usernames to wait for (e.g. "cursor-bugbot[bot]") */
|
|
145
|
+
bots: z.array(z.string()),
|
|
146
|
+
/** Give up waiting after this many minutes (default: 30) */
|
|
147
|
+
timeout_minutes: z.number().optional(),
|
|
148
|
+
}).optional(),
|
|
112
149
|
});
|
|
113
150
|
// =============================================================================
|
|
114
151
|
// SERVICE (for monorepos)
|
|
@@ -253,6 +290,6 @@ export const HaystackConfigSchema = z.object({
|
|
|
253
290
|
network: NetworkConfigSchema.optional(),
|
|
254
291
|
/** Secrets required by this project */
|
|
255
292
|
secrets: z.record(z.string(), SecretDeclarationSchema).optional(),
|
|
256
|
-
/**
|
|
257
|
-
|
|
293
|
+
/** Merge queue configuration for autonomous PR maintenance */
|
|
294
|
+
merge_queue: MergeQueueConfigSchema.optional(),
|
|
258
295
|
});
|
|
@@ -105,4 +105,20 @@ export declare function fetchAnalysisResults(owner: string, repo: string, prNumb
|
|
|
105
105
|
* This is the rich analysis data shown on the Haystack feed — includes
|
|
106
106
|
* verdict, rating, structured findings, verified bugs, and agent fix prompts.
|
|
107
107
|
*/
|
|
108
|
+
export interface AutoFixManifest {
|
|
109
|
+
jobId: string;
|
|
110
|
+
repo: string;
|
|
111
|
+
prNumber: number;
|
|
112
|
+
fixedItems: Array<{
|
|
113
|
+
category: string;
|
|
114
|
+
summary: string;
|
|
115
|
+
}>;
|
|
116
|
+
leftForReview: Array<{
|
|
117
|
+
category: string;
|
|
118
|
+
summary: string;
|
|
119
|
+
reason: string;
|
|
120
|
+
}>;
|
|
121
|
+
timestamp: string;
|
|
122
|
+
}
|
|
123
|
+
export declare function fetchAutoFixManifest(owner: string, repo: string, prNumber: number, token?: string): Promise<AutoFixManifest | null>;
|
|
108
124
|
export declare function fetchRatingSynthesis(owner: string, repo: string, prNumber: number, token?: string): Promise<RatingSynthesis | null>;
|
|
@@ -160,11 +160,29 @@ export async function fetchAnalysisResults(owner, repo, prNumber, token) {
|
|
|
160
160
|
autoMerged,
|
|
161
161
|
};
|
|
162
162
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
export async function fetchAutoFixManifest(owner, repo, prNumber, token) {
|
|
164
|
+
const url = `${PROD_API_BASE}/v3/result/${owner}/${repo}/${prNumber}/auto-fix-manifest.json`;
|
|
165
|
+
try {
|
|
166
|
+
const response = await fetch(url, {
|
|
167
|
+
headers: apiHeaders(token),
|
|
168
|
+
});
|
|
169
|
+
if (!response.ok)
|
|
170
|
+
return null;
|
|
171
|
+
const data = await response.json();
|
|
172
|
+
if (data.download_url) {
|
|
173
|
+
const s3Resp = await fetch(data.download_url, {
|
|
174
|
+
headers: { 'User-Agent': 'Haystack-CLI' },
|
|
175
|
+
});
|
|
176
|
+
if (!s3Resp.ok)
|
|
177
|
+
return null;
|
|
178
|
+
return await s3Resp.json();
|
|
179
|
+
}
|
|
180
|
+
return data;
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
168
186
|
export async function fetchRatingSynthesis(owner, repo, prNumber, token) {
|
|
169
187
|
// Use v3/result endpoint (same as the Lambda serves generic files)
|
|
170
188
|
const url = `${PROD_API_BASE}/v3/result/${owner}/${repo}/${prNumber}/rating_synthesis.json`;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight CLI telemetry — fire-and-forget error tracking via PostHog HTTP API.
|
|
3
|
+
*
|
|
4
|
+
* Events go to the same PostHog project as the web app, enabling unified
|
|
5
|
+
* alerting across frontend, CLI, and backend.
|
|
6
|
+
*
|
|
7
|
+
* All calls are non-blocking and never throw — telemetry failures must not
|
|
8
|
+
* break CLI commands.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Track an error event. Fire-and-forget — never throws.
|
|
12
|
+
*/
|
|
13
|
+
export declare function trackError(errorType: string, metadata?: Record<string, unknown>): void;
|
|
14
|
+
/**
|
|
15
|
+
* Track a setup event (non-error). Fire-and-forget.
|
|
16
|
+
*/
|
|
17
|
+
export declare function trackSetupEvent(step: string, metadata?: Record<string, unknown>): void;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight CLI telemetry — fire-and-forget error tracking via PostHog HTTP API.
|
|
3
|
+
*
|
|
4
|
+
* Events go to the same PostHog project as the web app, enabling unified
|
|
5
|
+
* alerting across frontend, CLI, and backend.
|
|
6
|
+
*
|
|
7
|
+
* All calls are non-blocking and never throw — telemetry failures must not
|
|
8
|
+
* break CLI commands.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { dirname, resolve } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import * as os from 'os';
|
|
14
|
+
const POSTHOG_HOST = 'https://us.i.posthog.com';
|
|
15
|
+
const POSTHOG_API_KEY = process.env.HAYSTACK_POSTHOG_KEY || 'phc_7wHrCoMlcwuftLe6N38hPb9wKHb4OK0wNw9ayeRySad';
|
|
16
|
+
const CURRENT_FILE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const PACKAGE_JSON_PATH = resolve(CURRENT_FILE_DIR, '../../package.json');
|
|
18
|
+
/**
|
|
19
|
+
* Stable machine identifier for PostHog distinct_id.
|
|
20
|
+
* Uses hostname + username so events are attributable per-machine.
|
|
21
|
+
* Never throws — falls back to hostname-only or 'anonymous'.
|
|
22
|
+
*/
|
|
23
|
+
function getDistinctId() {
|
|
24
|
+
try {
|
|
25
|
+
const hostname = os.hostname();
|
|
26
|
+
try {
|
|
27
|
+
return `cli:${os.userInfo().username}@${hostname}`;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return `cli:${hostname}`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return 'cli:anonymous';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Track an error event. Fire-and-forget — never throws.
|
|
39
|
+
*/
|
|
40
|
+
export function trackError(errorType, metadata) {
|
|
41
|
+
try {
|
|
42
|
+
if (typeof globalThis.fetch !== 'function')
|
|
43
|
+
return;
|
|
44
|
+
const event = {
|
|
45
|
+
api_key: POSTHOG_API_KEY,
|
|
46
|
+
distinct_id: getDistinctId(),
|
|
47
|
+
event: 'cli_error',
|
|
48
|
+
properties: {
|
|
49
|
+
error_type: errorType,
|
|
50
|
+
cli_version: getCLIVersion(),
|
|
51
|
+
os: process.platform,
|
|
52
|
+
arch: process.arch,
|
|
53
|
+
node_version: process.version,
|
|
54
|
+
timestamp: new Date().toISOString(),
|
|
55
|
+
...metadata,
|
|
56
|
+
},
|
|
57
|
+
timestamp: new Date().toISOString(),
|
|
58
|
+
};
|
|
59
|
+
// Fire-and-forget — never block the CLI
|
|
60
|
+
globalThis.fetch(`${POSTHOG_HOST}/capture/`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: { 'Content-Type': 'application/json' },
|
|
63
|
+
body: JSON.stringify(event),
|
|
64
|
+
}).catch(() => { });
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Telemetry must never crash the CLI
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Track a setup event (non-error). Fire-and-forget.
|
|
72
|
+
*/
|
|
73
|
+
export function trackSetupEvent(step, metadata) {
|
|
74
|
+
try {
|
|
75
|
+
if (typeof globalThis.fetch !== 'function')
|
|
76
|
+
return;
|
|
77
|
+
const event = {
|
|
78
|
+
api_key: POSTHOG_API_KEY,
|
|
79
|
+
distinct_id: getDistinctId(),
|
|
80
|
+
event: 'cli_setup',
|
|
81
|
+
properties: {
|
|
82
|
+
step,
|
|
83
|
+
cli_version: getCLIVersion(),
|
|
84
|
+
os: process.platform,
|
|
85
|
+
arch: process.arch,
|
|
86
|
+
timestamp: new Date().toISOString(),
|
|
87
|
+
...metadata,
|
|
88
|
+
},
|
|
89
|
+
timestamp: new Date().toISOString(),
|
|
90
|
+
};
|
|
91
|
+
globalThis.fetch(`${POSTHOG_HOST}/capture/`, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: { 'Content-Type': 'application/json' },
|
|
94
|
+
body: JSON.stringify(event),
|
|
95
|
+
}).catch(() => { });
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Telemetry must never crash the CLI
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function getCLIVersion() {
|
|
102
|
+
try {
|
|
103
|
+
const packageJson = JSON.parse(readFileSync(PACKAGE_JSON_PATH, 'utf8'));
|
|
104
|
+
return typeof packageJson.version === 'string' ? packageJson.version : 'unknown';
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return 'unknown';
|
|
108
|
+
}
|
|
109
|
+
}
|
package/package.json
CHANGED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Secrets commands - manage secrets stored on Haystack Platform
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* List all secrets (keys only, not values)
|
|
6
|
-
*/
|
|
7
|
-
export declare function listSecrets(): Promise<void>;
|
|
8
|
-
/**
|
|
9
|
-
* Set a secret
|
|
10
|
-
*/
|
|
11
|
-
export declare function setSecret(key: string, value: string, options: {
|
|
12
|
-
scope?: string;
|
|
13
|
-
scopeId?: string;
|
|
14
|
-
}): Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* Get a secret value (for programmatic use)
|
|
17
|
-
* Returns the value to stdout for piping to other commands.
|
|
18
|
-
* Use --quiet to suppress all output except the value.
|
|
19
|
-
*/
|
|
20
|
-
export declare function getSecret(key: string, options: {
|
|
21
|
-
quiet?: boolean;
|
|
22
|
-
}): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* Get multiple secrets needed by a repo's .haystack.json
|
|
25
|
-
* Returns JSON object with key-value pairs.
|
|
26
|
-
*/
|
|
27
|
-
export declare function getSecretsForRepo(keys: string[], options: {
|
|
28
|
-
json?: boolean;
|
|
29
|
-
}): Promise<void>;
|
|
30
|
-
/**
|
|
31
|
-
* Delete a secret
|
|
32
|
-
*/
|
|
33
|
-
export declare function deleteSecret(key: string): Promise<void>;
|