@haystackeditor/cli 0.15.26 → 0.15.27
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 +39 -3
- package/dist/assets/hooks/package-lock.json +598 -0
- package/dist/assets/skills/map-cloud-verifier-universe/SKILL.md +2051 -0
- package/dist/assets/skills/map-cloud-verifier-universe/agents/openai.yaml +4 -0
- package/dist/assets/skills/map-cloud-verifier-universe/references/output-contract.md +3411 -0
- package/dist/assets/telemetry/browser-runtime.js +861 -0
- package/dist/assets/telemetry/runtime.cjs +1509 -0
- package/dist/commands/cloud-verifier-behaviors.d.ts +27 -0
- package/dist/commands/cloud-verifier-behaviors.js +218 -0
- package/dist/commands/cloud-verifier-data-store-census.d.ts +47 -0
- package/dist/commands/cloud-verifier-data-store-census.js +539 -0
- package/dist/commands/cloud-verifier-data-store-drift.d.ts +42 -0
- package/dist/commands/cloud-verifier-data-store-drift.js +158 -0
- package/dist/commands/cloud-verifier-identity-census.d.ts +88 -0
- package/dist/commands/cloud-verifier-identity-census.js +4057 -0
- package/dist/commands/cloud-verifier-materialization.d.ts +16 -0
- package/dist/commands/cloud-verifier-materialization.js +704 -0
- package/dist/commands/cloud-verifier-pascal-selector-census.d.ts +29 -0
- package/dist/commands/cloud-verifier-pascal-selector-census.js +1382 -0
- package/dist/commands/cloud-verifier-python-manifest-selector-census.d.ts +27 -0
- package/dist/commands/cloud-verifier-python-manifest-selector-census.js +2015 -0
- package/dist/commands/cloud-verifier-specialized-operational-census.d.ts +51 -0
- package/dist/commands/cloud-verifier-specialized-operational-census.js +11432 -0
- package/dist/commands/cloud-verifier-universe.d.ts +31 -0
- package/dist/commands/cloud-verifier-universe.js +10178 -0
- package/dist/commands/design-verify.d.ts +23 -0
- package/dist/commands/design-verify.js +142 -0
- package/dist/commands/hooks.js +2 -2
- package/dist/commands/prepare-universe-review.d.ts +115 -0
- package/dist/commands/prepare-universe-review.js +1092 -0
- package/dist/commands/production-source-deny-policy.d.ts +15 -0
- package/dist/commands/production-source-deny-policy.js +100 -0
- package/dist/commands/scaffold-provisional-universe.d.ts +468 -0
- package/dist/commands/scaffold-provisional-universe.js +808 -0
- package/dist/commands/schema-cmd.js +32 -0
- package/dist/commands/skills.d.ts +2 -2
- package/dist/commands/skills.js +415 -47
- package/dist/commands/telemetry.d.ts +53 -0
- package/dist/commands/telemetry.js +832 -0
- package/dist/index.js +134 -12
- package/dist/triage/runner.js +7 -6
- package/dist/utils/design-verifier-api.d.ts +129 -0
- package/dist/utils/design-verifier-api.js +175 -0
- package/dist/utils/design-verifier-result.d.ts +52 -0
- package/dist/utils/design-verifier-result.js +299 -0
- package/dist/utils/haystack-api.d.ts +2 -0
- package/dist/utils/haystack-api.js +10 -3
- package/dist/utils/hooks.js +2 -1
- package/package.json +7 -2
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
function findingExplanation(kind) {
|
|
3
|
+
if (kind === 'declared-change-not-observed') {
|
|
4
|
+
return 'The intended behavior change was not observed on the proposed revision.';
|
|
5
|
+
}
|
|
6
|
+
if (kind === 'unexpected-change') {
|
|
7
|
+
return 'The proposed revision changed behavior that was registered to remain stable.';
|
|
8
|
+
}
|
|
9
|
+
return 'Executed behavior contradicted the registered expectation.';
|
|
10
|
+
}
|
|
11
|
+
function sameRecordedValue(left, right) {
|
|
12
|
+
return isDeepStrictEqual(left, right);
|
|
13
|
+
}
|
|
14
|
+
function executionSummaries(value) {
|
|
15
|
+
if (!Array.isArray(value))
|
|
16
|
+
return [];
|
|
17
|
+
return value.filter((execution) => !!execution && typeof execution === 'object' &&
|
|
18
|
+
['base1', 'base2', 'head'].includes(execution.side) &&
|
|
19
|
+
['completed', 'failed', 'missing'].includes(execution.status) &&
|
|
20
|
+
Array.isArray(execution.diagnostics) && Array.isArray(execution.outputExcerpt));
|
|
21
|
+
}
|
|
22
|
+
export function buildDesignVerifierAgentReport(run) {
|
|
23
|
+
const repository = `${run.owner}/${run.repo}`;
|
|
24
|
+
if (run.status !== 'succeeded' || !run.result) {
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
status: 'failed',
|
|
28
|
+
verdict: 'inconclusive',
|
|
29
|
+
headline: 'VERIFICATION INCONCLUSIVE',
|
|
30
|
+
explanation: run.error || 'The verifier did not produce a terminal behavioral verdict.',
|
|
31
|
+
runId: run.runId,
|
|
32
|
+
repository,
|
|
33
|
+
pullRequest: run.pr,
|
|
34
|
+
revisions: { base: run.baseSha, head: run.headSha },
|
|
35
|
+
durationMs: run.durationMs,
|
|
36
|
+
timings: null,
|
|
37
|
+
changedFiles: [],
|
|
38
|
+
cases: [],
|
|
39
|
+
inspectCommand: `haystack design-verify ${repository}#${run.pr} --run ${run.runId}`,
|
|
40
|
+
replay: null,
|
|
41
|
+
error: run.error,
|
|
42
|
+
exitCode: 2,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const verdict = run.result.verdict || {};
|
|
46
|
+
const summary = verdict.summary || {};
|
|
47
|
+
const findings = Array.isArray(verdict.findings) ? verdict.findings : [];
|
|
48
|
+
const confirmations = Array.isArray(verdict.confirmations) ? verdict.confirmations : [];
|
|
49
|
+
const findingByCase = new Map(findings.map((finding) => [finding.caseId, finding]));
|
|
50
|
+
const confirmedIds = new Set(confirmations.map((confirmation) => confirmation.caseId));
|
|
51
|
+
const scenarioByCase = new Map(run.result.scenarios.map((scenario) => [scenario.caseId, scenario]));
|
|
52
|
+
const probeByCase = new Map(run.result.probes.map((probe) => [probe.caseId, probe]));
|
|
53
|
+
const cases = run.result.cases.map((testCase) => {
|
|
54
|
+
const id = String(testCase.id || '');
|
|
55
|
+
const finding = findingByCase.get(id);
|
|
56
|
+
const scenario = scenarioByCase.get(id);
|
|
57
|
+
const probe = probeByCase.get(id);
|
|
58
|
+
const observations = (Array.isArray(scenario?.divergences) ? scenario.divergences : []).map((item) => ({
|
|
59
|
+
path: String(item.display || (Array.isArray(item.path) ? item.path.join('.') : 'observation')),
|
|
60
|
+
base: item.base,
|
|
61
|
+
baseRepeat: item.base2,
|
|
62
|
+
head: item.head,
|
|
63
|
+
}));
|
|
64
|
+
return {
|
|
65
|
+
id,
|
|
66
|
+
title: String(testCase.title || scenario?.scenario || id),
|
|
67
|
+
story: String(testCase.story || ''),
|
|
68
|
+
expectedHead: String(testCase.expected_head_observation || ''),
|
|
69
|
+
verdict: finding
|
|
70
|
+
? 'finding'
|
|
71
|
+
: confirmedIds.has(id)
|
|
72
|
+
? 'confirmed'
|
|
73
|
+
: scenario?.status === 'clean'
|
|
74
|
+
? 'clean'
|
|
75
|
+
: 'inconclusive',
|
|
76
|
+
findingKind: finding?.kind || null,
|
|
77
|
+
baseStable: observations.length
|
|
78
|
+
? observations.every((item) => sameRecordedValue(item.base, item.baseRepeat))
|
|
79
|
+
: scenario?.status === 'clean' ? true : null,
|
|
80
|
+
observations,
|
|
81
|
+
generatedFiles: probe?.files || [],
|
|
82
|
+
executedCommand: probe?.run || null,
|
|
83
|
+
executions: executionSummaries(scenario?.executions),
|
|
84
|
+
infrastructure: scenario?.infrastructureReceipt &&
|
|
85
|
+
typeof scenario.infrastructureReceipt === 'object'
|
|
86
|
+
? {
|
|
87
|
+
verified: scenario.infrastructureReceipt.status === 'passed',
|
|
88
|
+
recipeId: typeof scenario.infrastructureReceipt.recipeId === 'string'
|
|
89
|
+
? scenario.infrastructureReceipt.recipeId
|
|
90
|
+
: null,
|
|
91
|
+
freshInstances: Array.isArray(scenario.infrastructureReceipt.environmentInstanceIds)
|
|
92
|
+
? scenario.infrastructureReceipt.environmentInstanceIds.length
|
|
93
|
+
: 0,
|
|
94
|
+
baseRepeat: typeof scenario.infrastructureReceipt.baseRepeat === 'string'
|
|
95
|
+
? scenario.infrastructureReceipt.baseRepeat
|
|
96
|
+
: null,
|
|
97
|
+
errors: Array.isArray(scenario.infrastructureReceipt.errors)
|
|
98
|
+
? scenario.infrastructureReceipt.errors.filter((item) => typeof item === 'string')
|
|
99
|
+
: [],
|
|
100
|
+
}
|
|
101
|
+
: null,
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
let agentVerdict;
|
|
105
|
+
let headline;
|
|
106
|
+
let explanation;
|
|
107
|
+
let exitCode;
|
|
108
|
+
if (findings.length > 0) {
|
|
109
|
+
agentVerdict = 'fix_needed';
|
|
110
|
+
headline = 'FIX NEEDED';
|
|
111
|
+
explanation = findingExplanation(String(findings[0]?.kind || ''));
|
|
112
|
+
exitCode = 1;
|
|
113
|
+
}
|
|
114
|
+
else if (summary.caseDesignOutcome === 'no-supported-cases' || Number(summary.scenarios || 0) === 0) {
|
|
115
|
+
agentVerdict = 'inconclusive';
|
|
116
|
+
headline = 'VERIFICATION INCONCLUSIVE';
|
|
117
|
+
explanation = 'The verifier could not design and execute a supported behavioral case.';
|
|
118
|
+
exitCode = 2;
|
|
119
|
+
}
|
|
120
|
+
else if (confirmations.length > 0) {
|
|
121
|
+
agentVerdict = 'fix_confirmed';
|
|
122
|
+
headline = 'FIX CONFIRMED';
|
|
123
|
+
explanation = 'The intended behavior change was observed on head and reproduced across two stable base runs.';
|
|
124
|
+
exitCode = 0;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
agentVerdict = 'no_unexpected_change';
|
|
128
|
+
headline = 'NO UNEXPECTED CHANGE';
|
|
129
|
+
explanation = 'Executed cases found no behavior change outside the registered expectations.';
|
|
130
|
+
exitCode = 0;
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
ok: exitCode === 0,
|
|
134
|
+
status: 'complete',
|
|
135
|
+
verdict: agentVerdict,
|
|
136
|
+
headline,
|
|
137
|
+
explanation,
|
|
138
|
+
runId: run.runId,
|
|
139
|
+
repository,
|
|
140
|
+
pullRequest: run.pr,
|
|
141
|
+
revisions: { base: run.baseSha, head: run.headSha },
|
|
142
|
+
durationMs: run.durationMs,
|
|
143
|
+
timings: run.result.timings || null,
|
|
144
|
+
changedFiles: run.result.changedFiles,
|
|
145
|
+
cases,
|
|
146
|
+
inspectCommand: `haystack design-verify ${repository}#${run.pr} --run ${run.runId}`,
|
|
147
|
+
replay: run.result.replay,
|
|
148
|
+
error: null,
|
|
149
|
+
exitCode,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function displayValue(value) {
|
|
153
|
+
const encoded = JSON.stringify(value);
|
|
154
|
+
return encoded === undefined ? String(value) : encoded;
|
|
155
|
+
}
|
|
156
|
+
function durationLabel(durationMs) {
|
|
157
|
+
if (durationMs === null)
|
|
158
|
+
return '';
|
|
159
|
+
const totalSeconds = Math.round(durationMs / 1000);
|
|
160
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
161
|
+
const seconds = totalSeconds % 60;
|
|
162
|
+
return minutes ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
163
|
+
}
|
|
164
|
+
function preciseDurationLabel(durationMs) {
|
|
165
|
+
if (durationMs === null)
|
|
166
|
+
return 'not recorded';
|
|
167
|
+
if (durationMs < 1000)
|
|
168
|
+
return `${Number(durationMs.toFixed(3))}ms`;
|
|
169
|
+
const minutes = Math.floor(durationMs / 60_000);
|
|
170
|
+
const seconds = Number(((durationMs % 60_000) / 1000).toFixed(3));
|
|
171
|
+
return minutes ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
172
|
+
}
|
|
173
|
+
function timingStageLabel(stage) {
|
|
174
|
+
if (stage === 'blast-radius')
|
|
175
|
+
return 'blast radius';
|
|
176
|
+
if (stage === 'case-design')
|
|
177
|
+
return 'case design';
|
|
178
|
+
return stage;
|
|
179
|
+
}
|
|
180
|
+
function commandLabel(command) {
|
|
181
|
+
if (!command)
|
|
182
|
+
return null;
|
|
183
|
+
return command.argv.map((arg) => (/^[A-Za-z0-9_./:=+-]+$/.test(arg) ? arg : JSON.stringify(arg))).join(' ');
|
|
184
|
+
}
|
|
185
|
+
function executionSideLabel(side) {
|
|
186
|
+
if (side === 'base1')
|
|
187
|
+
return 'base';
|
|
188
|
+
if (side === 'base2')
|
|
189
|
+
return 'base repeat';
|
|
190
|
+
return 'head';
|
|
191
|
+
}
|
|
192
|
+
function executionNeedsAttention(execution) {
|
|
193
|
+
return execution.status !== 'completed' || execution.diagnostics.length > 0;
|
|
194
|
+
}
|
|
195
|
+
export function formatDesignVerifierAgentReport(report) {
|
|
196
|
+
const timing = durationLabel(report.durationMs);
|
|
197
|
+
const lines = [
|
|
198
|
+
`${report.exitCode === 0 ? '✓' : report.exitCode === 1 ? '✗' : '?'} ${report.headline}${timing ? ` ${timing}` : ''}`,
|
|
199
|
+
'',
|
|
200
|
+
report.explanation,
|
|
201
|
+
];
|
|
202
|
+
if (report.revisions.base || report.revisions.head) {
|
|
203
|
+
lines.push('', `Revisions: base ${report.revisions.base || 'unknown'} (executed twice)`, ` head ${report.revisions.head || 'unknown'} (executed once)`);
|
|
204
|
+
}
|
|
205
|
+
if (report.timings) {
|
|
206
|
+
lines.push('', 'Timing breakdown:');
|
|
207
|
+
if (report.timings.admissionMs !== null) {
|
|
208
|
+
lines.push(` admission: ${preciseDurationLabel(report.timings.admissionMs)}`);
|
|
209
|
+
}
|
|
210
|
+
for (const stage of report.timings.stages) {
|
|
211
|
+
lines.push(` ${timingStageLabel(stage.stage)}: ${preciseDurationLabel(stage.durationMs)} (${stage.status})`);
|
|
212
|
+
}
|
|
213
|
+
lines.push(` pipeline total: ${preciseDurationLabel(report.timings.pipelineDurationMs)}`);
|
|
214
|
+
if (report.timings.unattributedMs !== null) {
|
|
215
|
+
lines.push(` orchestration/finalization not recorded in a phase: ${preciseDurationLabel(report.timings.unattributedMs)}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
for (const testCase of report.cases) {
|
|
219
|
+
lines.push('', `Test: ${testCase.title}`);
|
|
220
|
+
if (testCase.story)
|
|
221
|
+
lines.push(` Behavior: ${testCase.story}`);
|
|
222
|
+
if (testCase.expectedHead)
|
|
223
|
+
lines.push(` Expected on head: ${testCase.expectedHead}`);
|
|
224
|
+
if (testCase.observations.length) {
|
|
225
|
+
lines.push(' Observed:');
|
|
226
|
+
for (const observation of testCase.observations) {
|
|
227
|
+
lines.push(` ${observation.path}`);
|
|
228
|
+
lines.push(` base: ${displayValue(observation.base)} (repeat: ${displayValue(observation.baseRepeat)})`);
|
|
229
|
+
lines.push(` head: ${displayValue(observation.head)}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (testCase.baseStable !== null) {
|
|
233
|
+
lines.push(` Base stability: ${testCase.baseStable ? 'passed; both runs agreed' : 'failed; base runs disagreed'}`);
|
|
234
|
+
}
|
|
235
|
+
if (testCase.infrastructure) {
|
|
236
|
+
lines.push(testCase.infrastructure.verified
|
|
237
|
+
? ` Infrastructure: verified; same recipe, ${testCase.infrastructure.freshInstances} fresh instances`
|
|
238
|
+
: ` Infrastructure: unverified; ${testCase.infrastructure.errors.join('; ') || 'receipt missing'}`);
|
|
239
|
+
}
|
|
240
|
+
const executionsWithDiagnostics = testCase.executions.filter(executionNeedsAttention);
|
|
241
|
+
if (executionsWithDiagnostics.length) {
|
|
242
|
+
lines.push(' Execution diagnostics:');
|
|
243
|
+
for (const execution of executionsWithDiagnostics) {
|
|
244
|
+
const exit = execution.commandExitCode === null ? 'exit unknown' : `exit ${execution.commandExitCode}`;
|
|
245
|
+
const elapsed = execution.durationMs === null ? '' : `, ${durationLabel(execution.durationMs)}`;
|
|
246
|
+
lines.push(` ${executionSideLabel(execution.side)} (${exit}${elapsed}):`);
|
|
247
|
+
if (execution.scenarioError)
|
|
248
|
+
lines.push(` Scenario error: ${execution.scenarioError}`);
|
|
249
|
+
for (const diagnostic of execution.diagnostics) {
|
|
250
|
+
const identity = [diagnostic.type, diagnostic.code].filter(Boolean).join(', ');
|
|
251
|
+
lines.push(` ${diagnostic.kind}${identity ? ` (${identity})` : ''}: ${diagnostic.message}`);
|
|
252
|
+
}
|
|
253
|
+
if (execution.diagnosticsOmitted > 0) {
|
|
254
|
+
lines.push(` ... ${execution.diagnosticsOmitted} additional diagnostics omitted`);
|
|
255
|
+
}
|
|
256
|
+
if (execution.outputExcerpt.length) {
|
|
257
|
+
lines.push(' Relevant command output:');
|
|
258
|
+
for (const output of execution.outputExcerpt) {
|
|
259
|
+
lines.push(` ${output.stream}: ${output.text}`);
|
|
260
|
+
}
|
|
261
|
+
if (execution.outputLinesOmitted > 0) {
|
|
262
|
+
lines.push(` ... ${execution.outputLinesOmitted} output lines omitted`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
lines.push(` Full output artifact: ${execution.outputArtifact}`);
|
|
266
|
+
lines.push(` Structured trace artifact: ${execution.traceArtifact}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (testCase.generatedFiles.length)
|
|
270
|
+
lines.push(` Generated probe artifact: ${testCase.generatedFiles.join(', ')}`);
|
|
271
|
+
const command = commandLabel(testCase.executedCommand);
|
|
272
|
+
if (command)
|
|
273
|
+
lines.push(` Executed in the sandbox: ${command}`);
|
|
274
|
+
}
|
|
275
|
+
if (report.changedFiles.length) {
|
|
276
|
+
lines.push('', 'Changed files to inspect:', ...report.changedFiles.map((file) => ` ${file}`));
|
|
277
|
+
}
|
|
278
|
+
lines.push('', `Inspect this exact result again: ${report.inspectCommand}`, `Run: ${report.runId}`);
|
|
279
|
+
return lines.join('\n');
|
|
280
|
+
}
|
|
281
|
+
export function designVerifierStageLabel(stage) {
|
|
282
|
+
if (!stage)
|
|
283
|
+
return 'Waiting for the run to start';
|
|
284
|
+
if (stage === 'prepare' || stage === 'bake')
|
|
285
|
+
return 'Preparing the repository';
|
|
286
|
+
if (stage === 'blast-radius')
|
|
287
|
+
return 'Mapping affected behavior';
|
|
288
|
+
if (stage === 'prefetch')
|
|
289
|
+
return 'Retrieving relevant failure patterns';
|
|
290
|
+
if (stage === 'stage1')
|
|
291
|
+
return 'Designing behavioral test cases';
|
|
292
|
+
if (stage.startsWith('build:'))
|
|
293
|
+
return 'Building an executable probe';
|
|
294
|
+
if (stage.startsWith('execute:'))
|
|
295
|
+
return 'Running base/base/head comparisons';
|
|
296
|
+
if (stage === 'verdict')
|
|
297
|
+
return 'Comparing observations';
|
|
298
|
+
return stage;
|
|
299
|
+
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
export function haystackApiBase() {
|
|
2
|
+
return process.env.HAYSTACK_API_BASE ?? 'https://haystackeditor.com';
|
|
3
|
+
}
|
|
4
|
+
export function haystackApiUrl(path) {
|
|
5
|
+
if (!path.startsWith('/'))
|
|
6
|
+
throw new Error('Haystack API path must be absolute');
|
|
7
|
+
return `${haystackApiBase()}${path}`;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
10
|
* Typed error for non-OK Haystack API responses. Callers classify by
|
|
4
11
|
* `status` (never by message substring) and the message always carries a
|
|
@@ -70,7 +77,7 @@ export async function classifyHttpError(response, context) {
|
|
|
70
77
|
return new HaystackApiError(response.status, `${context}: unexpected response (HTTP ${response.status})${suffix}.`);
|
|
71
78
|
}
|
|
72
79
|
export async function haystackJson(path, token, init = {}, acceptedStatuses = []) {
|
|
73
|
-
const response = await fetch(
|
|
80
|
+
const response = await fetch(haystackApiUrl(path), {
|
|
74
81
|
...init,
|
|
75
82
|
headers: headers(token, init.headers),
|
|
76
83
|
});
|
|
@@ -91,7 +98,7 @@ export async function fetchGitHubJson(path, token, init = {}) {
|
|
|
91
98
|
}
|
|
92
99
|
export async function fetchAnalysisArtifact(owner, repo, prNumber, file, token) {
|
|
93
100
|
const ref = encodeURIComponent(`${owner}/${repo}#${prNumber}`);
|
|
94
|
-
const response = await fetch(
|
|
101
|
+
const response = await fetch(haystackApiUrl(`/api/analysis/${ref}/${file}`), {
|
|
95
102
|
headers: headers(token, { 'Cache-Control': 'no-cache' }),
|
|
96
103
|
});
|
|
97
104
|
if (response.status === 404)
|
package/dist/utils/hooks.js
CHANGED
|
@@ -169,10 +169,11 @@ export async function copyHookFiles(hooksDir) {
|
|
|
169
169
|
await copyDirRecursive(path.join(assetsDir, 'truncation-checker'), path.join(hooksDir, 'truncation-checker'));
|
|
170
170
|
// Copy hooks package.json
|
|
171
171
|
await fs.copyFile(path.join(assetsDir, 'package.json'), path.join(hooksDir, 'package.json'));
|
|
172
|
+
await fs.copyFile(path.join(assetsDir, 'package-lock.json'), path.join(hooksDir, 'package-lock.json'));
|
|
172
173
|
}
|
|
173
174
|
/** Install npm dependencies in the hooks directory */
|
|
174
175
|
export async function installHookDeps(hooksDir) {
|
|
175
|
-
execSync('npm
|
|
176
|
+
execSync('npm ci --ignore-scripts --no-fund --no-audit', {
|
|
176
177
|
cwd: hooksDir,
|
|
177
178
|
stdio: 'pipe',
|
|
178
179
|
timeout: 60_000,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haystackeditor/cli",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.27",
|
|
4
4
|
"description": "Set up Haystack for your project — automated PR review, triage, and merge queue",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,10 +10,13 @@
|
|
|
10
10
|
"build": "rm -rf dist && tsc && cp -r src/assets dist/assets",
|
|
11
11
|
"dev": "tsc --watch",
|
|
12
12
|
"start": "node dist/index.js",
|
|
13
|
+
"benchmark:telemetry": "pnpm build && node scripts/benchmark-telemetry-overhead.mjs",
|
|
14
|
+
"benchmark:telemetry:corpus": "pnpm build && node scripts/benchmark-open-source-telemetry.mjs",
|
|
13
15
|
"check:schemas": "node scripts/check-schemas.mjs",
|
|
14
16
|
"release": "node scripts/release.mjs",
|
|
15
17
|
"prepublishOnly": "node scripts/no-direct-publish.mjs",
|
|
16
|
-
"test": "pnpm build && vitest run && node --test tests/*.test.mjs"
|
|
18
|
+
"test": "pnpm build && vitest run && node --test tests/*.test.mjs",
|
|
19
|
+
"test:package": "node scripts/package-smoke.mjs"
|
|
17
20
|
},
|
|
18
21
|
"keywords": [
|
|
19
22
|
"haystack",
|
|
@@ -35,6 +38,7 @@
|
|
|
35
38
|
"url": "https://github.com/haystackeditor/haystack-review/issues"
|
|
36
39
|
},
|
|
37
40
|
"dependencies": {
|
|
41
|
+
"@babel/core": "7.29.0",
|
|
38
42
|
"@modelcontextprotocol/sdk": "1.26.0",
|
|
39
43
|
"chalk": "5.6.2",
|
|
40
44
|
"commander": "12.1.0",
|
|
@@ -56,6 +60,7 @@
|
|
|
56
60
|
"dist",
|
|
57
61
|
"schemas"
|
|
58
62
|
],
|
|
63
|
+
"bundledDependencies": [],
|
|
59
64
|
"engines": {
|
|
60
65
|
"node": ">=18"
|
|
61
66
|
}
|