@haystackeditor/cli 0.15.31 → 0.16.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 +111 -60
- package/dist/assets/hooks/scripts/commit-msg.sh +3 -0
- package/dist/assets/hooks/scripts/post-commit.sh +3 -0
- package/dist/assets/hooks/scripts/pre-commit.sh +11 -6
- package/dist/assets/hooks/scripts/pre-push.sh +3 -0
- package/dist/assets/hooks/scripts/prepare-commit-msg.sh +3 -0
- package/dist/commands/case-batch-contract.js +608 -0
- package/dist/commands/case-batch.js +713 -0
- package/dist/commands/cloud-verifier-identity-census.js +5 -2
- package/dist/commands/combination-search-hook.js +139 -0
- package/dist/commands/dismiss.js +2 -1
- package/dist/commands/hooks.js +66 -7
- package/dist/commands/install-session-hooks.js +131 -44
- package/dist/commands/policy.js +32 -45
- package/dist/commands/precompute-delivery.js +6 -1
- package/dist/commands/scaffold-provisional-universe.js +8 -10
- package/dist/commands/setup.js +32 -10
- package/dist/commands/submit.js +7 -2
- package/dist/commands/telemetry.js +17 -2
- package/dist/commands/triage.js +2 -1
- package/dist/commands/verify-explore.js +1 -0
- package/dist/commands/verify-hosted-mcp.js +3 -12
- package/dist/commands/verify-hosted-reproducibility.js +49 -547
- package/dist/commands/verify-hosted.js +66 -168
- package/dist/commands/verify-precompute.js +57 -10
- package/dist/commands/verify.js +51 -139
- package/dist/index.js +238 -350
- package/dist/lazy.js +8 -0
- package/dist/schema.js +1 -0
- package/dist/tools/detect.js +3 -24
- package/dist/triage/prompts.js +46 -45
- package/dist/triage/runner.js +119 -33
- package/dist/types.js +3 -3
- package/dist/utils/auth.js +14 -2
- package/dist/utils/git.js +60 -29
- package/dist/utils/github-api.js +14 -1
- package/dist/utils/haystack-api.js +26 -7
- package/dist/utils/hooks.js +43 -6
- package/dist/utils/prompter.js +25 -10
- package/dist/utils/safe-write.js +31 -0
- package/dist/utils/secret-paths.js +115 -0
- package/dist/utils/secrets.js +0 -1
- package/dist/utils/telemetry.js +34 -14
- package/dist/utils/update-check.js +151 -0
- package/package.json +18 -14
- package/schemas/case-batch.v1.json +184 -0
- package/schemas/cloud-verifier.v1.json +55 -100
- package/dist/commands/ask.d.ts +0 -14
- package/dist/commands/cloud-verifier-behaviors.d.ts +0 -27
- package/dist/commands/cloud-verifier-data-store-census.d.ts +0 -47
- package/dist/commands/cloud-verifier-data-store-drift.d.ts +0 -42
- package/dist/commands/cloud-verifier-identity-census.d.ts +0 -88
- package/dist/commands/cloud-verifier-materialization.d.ts +0 -16
- package/dist/commands/cloud-verifier-pascal-selector-census.d.ts +0 -29
- package/dist/commands/cloud-verifier-python-manifest-selector-census.d.ts +0 -27
- package/dist/commands/cloud-verifier-specialized-operational-census.d.ts +0 -51
- package/dist/commands/cloud-verifier-universe.d.ts +0 -31
- package/dist/commands/config.d.ts +0 -46
- package/dist/commands/design-verify.d.ts +0 -33
- package/dist/commands/dismiss.d.ts +0 -29
- package/dist/commands/hooks.d.ts +0 -13
- package/dist/commands/inbox.d.ts +0 -65
- package/dist/commands/init.d.ts +0 -10
- package/dist/commands/install-session-hooks.d.ts +0 -17
- package/dist/commands/login.d.ts +0 -8
- package/dist/commands/mcp.d.ts +0 -1
- package/dist/commands/policy.d.ts +0 -31
- package/dist/commands/pr-status.d.ts +0 -144
- package/dist/commands/pr.d.ts +0 -40
- package/dist/commands/precompute-delivery-contract.d.ts +0 -68
- package/dist/commands/precompute-delivery.d.ts +0 -20
- package/dist/commands/prepare-universe-review.d.ts +0 -115
- package/dist/commands/production-source-deny-policy.d.ts +0 -15
- package/dist/commands/request-review.d.ts +0 -26
- package/dist/commands/review.d.ts +0 -25
- package/dist/commands/rules.d.ts +0 -4
- package/dist/commands/scaffold-provisional-universe.d.ts +0 -468
- package/dist/commands/schema-cmd.d.ts +0 -2
- package/dist/commands/setup.d.ts +0 -28
- package/dist/commands/skills.d.ts +0 -8
- package/dist/commands/status.d.ts +0 -4
- package/dist/commands/submit.d.ts +0 -30
- package/dist/commands/system-map.d.ts +0 -42
- package/dist/commands/telemetry.d.ts +0 -53
- package/dist/commands/tokens.d.ts +0 -14
- package/dist/commands/triage.d.ts +0 -35
- package/dist/commands/verify-core.d.ts +0 -449
- package/dist/commands/verify-core.js +0 -789
- package/dist/commands/verify-explore.d.ts +0 -14
- package/dist/commands/verify-history.d.ts +0 -14
- package/dist/commands/verify-hosted-mcp.d.ts +0 -12
- package/dist/commands/verify-hosted-reproducibility.d.ts +0 -90
- package/dist/commands/verify-hosted.d.ts +0 -92
- package/dist/commands/verify-mcp.d.ts +0 -8
- package/dist/commands/verify-mcp.js +0 -517
- package/dist/commands/verify-ops.d.ts +0 -158
- package/dist/commands/verify-ops.js +0 -1148
- package/dist/commands/verify-precompute.d.ts +0 -30
- package/dist/commands/verify-reproducibility.d.ts +0 -85
- package/dist/commands/verify-reproducibility.js +0 -494
- package/dist/commands/verify-reseal.d.ts +0 -9
- package/dist/commands/verify-reseal.js +0 -148
- package/dist/commands/verify-sandboxes.d.ts +0 -95
- package/dist/commands/verify-sandboxes.js +0 -352
- package/dist/commands/verify.d.ts +0 -28
- package/dist/commands/webhooks.d.ts +0 -30
- package/dist/index.d.ts +0 -22
- package/dist/schema.d.ts +0 -28
- package/dist/states.d.ts +0 -29
- package/dist/tools/detect.d.ts +0 -50
- package/dist/triage/prompts.d.ts +0 -24
- package/dist/triage/runner.d.ts +0 -34
- package/dist/triage/types.d.ts +0 -42
- package/dist/types/verify-history.d.ts +0 -38
- package/dist/types.d.ts +0 -1684
- package/dist/utils/action-output.d.ts +0 -24
- package/dist/utils/analysis-api.d.ts +0 -187
- package/dist/utils/auth.d.ts +0 -79
- package/dist/utils/config.d.ts +0 -24
- package/dist/utils/design-verifier-api.d.ts +0 -208
- package/dist/utils/design-verifier-history.d.ts +0 -46
- package/dist/utils/design-verifier-result.d.ts +0 -74
- package/dist/utils/detect.d.ts +0 -43
- package/dist/utils/git.d.ts +0 -135
- package/dist/utils/github-api.d.ts +0 -104
- package/dist/utils/haystack-api.d.ts +0 -37
- package/dist/utils/hooks.d.ts +0 -12
- package/dist/utils/pending-state.d.ts +0 -40
- package/dist/utils/pr-ref.d.ts +0 -27
- package/dist/utils/prompter.d.ts +0 -85
- package/dist/utils/secrets.d.ts +0 -47
- package/dist/utils/telemetry.d.ts +0 -19
- /package/dist/commands/{precompute-delivery-worker.d.ts → combination-search-hook-contract.js} +0 -0
|
@@ -1,517 +0,0 @@
|
|
|
1
|
-
// MCP server for the cloud verifier: `haystack verify mcp`.
|
|
2
|
-
//
|
|
3
|
-
// Design intent (mirrors the CLI):
|
|
4
|
-
// - Tools return FINDINGS, not run.json. The raw file holds evidence arrays per
|
|
5
|
-
// universe per cell; an agent asking "what broke" gets the sentence, the
|
|
6
|
-
// readings that changed, and the SDK log lines. Raw blobs sit behind `raw`.
|
|
7
|
-
// - `verify_wait` is the primitive: start → wait → read. Its terminal predicate
|
|
8
|
-
// is the RUN status only — a cell can sit in `provisioning` for minutes while
|
|
9
|
-
// sandbox creation retries, and that must not end a wait.
|
|
10
|
-
// - A test passes or it fails. `infra_error` means the verifier could not run
|
|
11
|
-
// it; it is surfaced under `problems`/`could_not_run`, never as a verdict.
|
|
12
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
13
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
|
-
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
15
|
-
import * as fs from 'node:fs';
|
|
16
|
-
import * as os from 'node:os';
|
|
17
|
-
import * as path from 'node:path';
|
|
18
|
-
import { cellDetail, discoverVerifyRoot, findCell, findCellByStableSelector, listRunRows, loadRunAuto, resolveServer, runDir, setVerifyToken, summarizeRun, verifyAuthHeaders, waitForTerminal, } from './verify-core.js';
|
|
19
|
-
import { resolveInventory } from './verify-sandboxes.js';
|
|
20
|
-
const runInput = {
|
|
21
|
-
type: 'string',
|
|
22
|
-
description: 'Run selector: a run id (run-…), a chapter id (e.g. posthog-js-3191) for its newest run, or "latest". Default "latest".',
|
|
23
|
-
};
|
|
24
|
-
export const VERIFY_TOOLS = [
|
|
25
|
-
{
|
|
26
|
-
name: 'verify_start',
|
|
27
|
-
description: 'Start a cloud verifier run for a specimen. Returns run_id immediately; call verify_wait next — do not poll yourself.',
|
|
28
|
-
inputSchema: {
|
|
29
|
-
type: 'object',
|
|
30
|
-
properties: {
|
|
31
|
-
specimen: { type: 'string', description: 'Specimen/chapter id (e.g. posthog-js-3191, posthog-js-478, analytics-js-255, bootstrap-text-muted, or "all").' },
|
|
32
|
-
intent_transcript: { type: 'string', description: 'Optional coding-agent transcript used as intent evidence when judging differences.' },
|
|
33
|
-
},
|
|
34
|
-
required: ['specimen'],
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
name: 'verify_status',
|
|
39
|
-
description: 'Current state of a run: per-test verdicts, counts, a findings digest (what failed and which readings moved), live environment URLs with expiry, and anything that could not run (reported as verifier defects, never as findings).',
|
|
40
|
-
inputSchema: {
|
|
41
|
-
type: 'object',
|
|
42
|
-
properties: {
|
|
43
|
-
run: runInput,
|
|
44
|
-
raw: { type: 'boolean', description: 'Return the full run.json instead of the summary. It is very large; only use when the summary is insufficient.' },
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: 'verify_wait',
|
|
50
|
-
description: 'Block until the run reaches a terminal state (complete/failed), then return the same summary as verify_status plus outcome. Use this instead of polling: cells legitimately sit in "provisioning" for minutes while sandbox creation retries.',
|
|
51
|
-
inputSchema: {
|
|
52
|
-
type: 'object',
|
|
53
|
-
properties: {
|
|
54
|
-
run: runInput,
|
|
55
|
-
timeout_seconds: { type: 'integer', minimum: 10, description: 'Give up waiting after this long (default 1800). A timeout returns the current summary with timed_out=true; the run keeps going.' },
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: 'verify_findings',
|
|
61
|
-
description: 'Just the problems a run found: each failing test with its verdict, the readings that moved (base → head), the judge\'s explanation, and live environment links. Lighter than verify_status when "what broke" is the only question.',
|
|
62
|
-
inputSchema: {
|
|
63
|
-
type: 'object',
|
|
64
|
-
properties: { run: runInput },
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'verify_diff',
|
|
69
|
-
description: 'Build the base-vs-head screenshot differ for one test (the same viewer as the results page: 1 what changed / 2 before / 3 after). Returns the page path plus per-step byte-identical verdicts — use those verdicts to answer "did the pixels change"; give the page path to a human.',
|
|
70
|
-
inputSchema: {
|
|
71
|
-
type: 'object',
|
|
72
|
-
properties: {
|
|
73
|
-
run: runInput,
|
|
74
|
-
cell: { type: 'string', description: 'Test selector: ordinal (1-based), riskCellId, planner cellKey, or a title substring.' },
|
|
75
|
-
step: { type: 'integer', minimum: 1, description: 'Compare only the screenshot captured after this replay step.' },
|
|
76
|
-
out_dir: { type: 'string', description: 'Where to build the page (default: a temp directory).' },
|
|
77
|
-
},
|
|
78
|
-
required: ['cell'],
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
name: 'verify_list',
|
|
83
|
-
description: 'List verifier runs on disk, newest first: run id, chapters, status, verdict counts, age.',
|
|
84
|
-
inputSchema: {
|
|
85
|
-
type: 'object',
|
|
86
|
-
properties: { limit: { type: 'integer', minimum: 1, maximum: 200, description: 'Max runs to return (default 20).' } },
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: 'verify_cell',
|
|
91
|
-
description: 'One test in full: the finding, oracle readings that changed (base → head), request timelines, SDK log lines, artifacts, and the live environment if one is still up.',
|
|
92
|
-
inputSchema: {
|
|
93
|
-
type: 'object',
|
|
94
|
-
properties: {
|
|
95
|
-
run: runInput,
|
|
96
|
-
cell: { type: 'string', description: 'Test selector: ordinal (1-based), riskCellId (cell-…), planner cellKey, or a title substring.' },
|
|
97
|
-
raw: { type: 'boolean', description: 'Return the raw RiskCell JSON (all evidence) instead of the summary.' },
|
|
98
|
-
},
|
|
99
|
-
required: ['cell'],
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: 'verify_universe',
|
|
104
|
-
description: 'Get or open a live universe for one test: returns the running environment when one is still live, otherwise reopens the retained state onto fresh compute (reusing an existing attachment when present).',
|
|
105
|
-
inputSchema: {
|
|
106
|
-
type: 'object',
|
|
107
|
-
properties: {
|
|
108
|
-
run: runInput,
|
|
109
|
-
cell: { type: 'string', description: 'Stable test selector: ordinal (1-based), riskCellId, or exact planner cellKey.' },
|
|
110
|
-
side: { type: 'string', enum: ['base', 'head'], description: 'Matched universe side (default head).' },
|
|
111
|
-
},
|
|
112
|
-
required: ['cell'],
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
name: 'verify_cleanup',
|
|
117
|
-
description: 'Read retained-state cleanup for one test universe by its exact fork ID: shared references, provider deletion attempts, and the durable cleanup-SLO verdict.',
|
|
118
|
-
inputSchema: {
|
|
119
|
-
type: 'object',
|
|
120
|
-
properties: {
|
|
121
|
-
run: runInput,
|
|
122
|
-
cell: { type: 'string', description: 'Stable test selector: ordinal (1-based), riskCellId, or exact planner cellKey.' },
|
|
123
|
-
side: { type: 'string', enum: ['base', 'head'], description: 'Matched universe side (default head).' },
|
|
124
|
-
},
|
|
125
|
-
required: ['cell'],
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: 'verify_reopen',
|
|
130
|
-
description: 'Attach fresh compute to retained Archil state selected by an exact fork ID or a stable run/test/side coordinate. Returns the exact sandbox ID for inspection or mutation.',
|
|
131
|
-
inputSchema: {
|
|
132
|
-
type: 'object',
|
|
133
|
-
properties: {
|
|
134
|
-
fork_id: { type: 'string', description: 'Exact structured Archil fork ID. Use this instead of run/cell to reopen a reforked child.' },
|
|
135
|
-
run: runInput,
|
|
136
|
-
cell: { type: 'string', description: 'Stable test selector: ordinal (1-based), riskCellId, or exact planner cellKey.' },
|
|
137
|
-
side: { type: 'string', enum: ['base', 'head'], description: 'Matched universe side (default head; run/cell only).' },
|
|
138
|
-
},
|
|
139
|
-
anyOf: [{ required: ['fork_id'] }, { required: ['cell'] }],
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
name: 'verify_refork',
|
|
144
|
-
description: 'Quiesce a reopened Archil universe and checkpoint it into a durable child. Select the parent by exact fork ID or stable run/test/side coordinate; child_key is a caller-supplied stable identifier.',
|
|
145
|
-
inputSchema: {
|
|
146
|
-
type: 'object',
|
|
147
|
-
properties: {
|
|
148
|
-
fork_id: { type: 'string', description: 'Exact structured Archil parent fork ID. Use this for nested reforks.' },
|
|
149
|
-
run: runInput,
|
|
150
|
-
cell: { type: 'string', description: 'Stable test selector: ordinal (1-based), riskCellId, or exact planner cellKey.' },
|
|
151
|
-
side: { type: 'string', enum: ['base', 'head'], description: 'Matched universe side (default head; run/cell only).' },
|
|
152
|
-
child_key: { type: 'string', description: 'Stable child identifier, 1-128 characters (letters, numbers, dot, underscore, colon, hyphen).' },
|
|
153
|
-
},
|
|
154
|
-
required: ['child_key'],
|
|
155
|
-
anyOf: [{ required: ['fork_id'] }, { required: ['cell'] }],
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
name: 'verify_artifact',
|
|
160
|
-
description: 'Fetch one run artifact (screenshot .png, DOM snapshot .html, video .webm, stage .json) to a local file. Small text artifacts are also returned inline.',
|
|
161
|
-
inputSchema: {
|
|
162
|
-
type: 'object',
|
|
163
|
-
properties: {
|
|
164
|
-
run: runInput,
|
|
165
|
-
path: { type: 'string', description: 'Artifact path as shown by verify_cell — "<chapter>/artifacts/<file>" or a bare file name.' },
|
|
166
|
-
out_path: { type: 'string', description: 'Where to write the file (default: a temp directory).' },
|
|
167
|
-
},
|
|
168
|
-
required: ['path'],
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
name: 'sandbox_list',
|
|
173
|
-
description: 'Inventory of running E2B sandboxes with verifier attribution (which run/test each belongs to) and staleness. The account is shared with other workstreams — "other" sandboxes are not ours.',
|
|
174
|
-
inputSchema: { type: 'object', properties: {} },
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
name: 'sandbox_kill',
|
|
178
|
-
description: 'Kill one E2B sandbox by id. Refuses sandboxes that cannot be attributed to the verifier (the account is shared) unless force=true.',
|
|
179
|
-
inputSchema: {
|
|
180
|
-
type: 'object',
|
|
181
|
-
properties: {
|
|
182
|
-
sandbox_id: { type: 'string' },
|
|
183
|
-
force: { type: 'boolean', description: 'Kill even without verifier attribution. Only when the operator has confirmed the sandbox is theirs.' },
|
|
184
|
-
},
|
|
185
|
-
required: ['sandbox_id'],
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
];
|
|
189
|
-
export async function runVerifyMcpServer(options) {
|
|
190
|
-
setVerifyToken(options.token);
|
|
191
|
-
const server = resolveServer(options.server);
|
|
192
|
-
const repoRoot = discoverVerifyRoot(options.repoRoot);
|
|
193
|
-
const mcp = new Server({ name: 'haystack-verify', version: '1.0.0' }, { capabilities: { tools: {} } });
|
|
194
|
-
mcp.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: VERIFY_TOOLS }));
|
|
195
|
-
mcp.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
196
|
-
const { name, arguments: args } = request.params;
|
|
197
|
-
const input = (args ?? {});
|
|
198
|
-
const ok = (data) => ({ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] });
|
|
199
|
-
const fail = (message) => ({ isError: true, content: [{ type: 'text', text: message }] });
|
|
200
|
-
const selector = typeof input.run === 'string' && input.run ? input.run : 'latest';
|
|
201
|
-
try {
|
|
202
|
-
if (name === 'verify_start') {
|
|
203
|
-
if (typeof input.specimen !== 'string')
|
|
204
|
-
return fail('specimen required');
|
|
205
|
-
let response;
|
|
206
|
-
try {
|
|
207
|
-
response = await fetch(`${server}/api/cloud-verifier/runs`, {
|
|
208
|
-
method: 'POST',
|
|
209
|
-
headers: { 'content-type': 'application/json', ...verifyAuthHeaders() },
|
|
210
|
-
body: JSON.stringify({
|
|
211
|
-
specimen: input.specimen,
|
|
212
|
-
intentTranscript: typeof input.intent_transcript === 'string' ? input.intent_transcript : undefined,
|
|
213
|
-
}),
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
return fail(`Control plane at ${server} is unreachable (${error instanceof Error ? error.message : error}). Start it with \`pnpm dev\` in the repository.`);
|
|
218
|
-
}
|
|
219
|
-
const body = await response.text();
|
|
220
|
-
if (!response.ok) {
|
|
221
|
-
let reason = body;
|
|
222
|
-
try {
|
|
223
|
-
reason = JSON.parse(body).error || body;
|
|
224
|
-
}
|
|
225
|
-
catch { /* non-JSON error body */ }
|
|
226
|
-
return fail(`Run rejected (${response.status}): ${reason}`);
|
|
227
|
-
}
|
|
228
|
-
const started = JSON.parse(body);
|
|
229
|
-
return ok({
|
|
230
|
-
run_id: started.runId,
|
|
231
|
-
status: started.status,
|
|
232
|
-
results_url: started.resultsUrl,
|
|
233
|
-
next: `Call verify_wait with run="${started.runId}".`,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
if (name === 'verify_status') {
|
|
237
|
-
const loaded = await loadRunAuto({ server, repoRoot, selector });
|
|
238
|
-
if (input.raw === true)
|
|
239
|
-
return ok(loaded.run);
|
|
240
|
-
return ok(summarizeRun(loaded, server));
|
|
241
|
-
}
|
|
242
|
-
if (name === 'verify_wait') {
|
|
243
|
-
const timeoutSeconds = typeof input.timeout_seconds === 'number' ? input.timeout_seconds : 1800;
|
|
244
|
-
const result = await waitForTerminal({
|
|
245
|
-
server,
|
|
246
|
-
repoRoot,
|
|
247
|
-
selector,
|
|
248
|
-
timeoutMs: timeoutSeconds * 1000,
|
|
249
|
-
intervalMs: 3000,
|
|
250
|
-
});
|
|
251
|
-
const summary = summarizeRun(result.loaded, server);
|
|
252
|
-
const outcome = result.timedOut ? 'timed_out'
|
|
253
|
-
: summary.stale ? 'stale'
|
|
254
|
-
: summary.counts.could_not_run > 0 ? 'completed_with_unrunnable_tests'
|
|
255
|
-
: summary.status === 'failed' && summary.counts.total === 0 ? 'run_failed'
|
|
256
|
-
: summary.counts.failed > 0 ? 'tests_failed'
|
|
257
|
-
: 'all_passed';
|
|
258
|
-
return ok({ outcome, timed_out: result.timedOut, ...summary });
|
|
259
|
-
}
|
|
260
|
-
if (name === 'verify_findings') {
|
|
261
|
-
const loaded = await loadRunAuto({ server, repoRoot, selector });
|
|
262
|
-
const summary = summarizeRun(loaded, server);
|
|
263
|
-
return ok({
|
|
264
|
-
run_id: summary.run_id,
|
|
265
|
-
status: summary.status,
|
|
266
|
-
counts: summary.counts,
|
|
267
|
-
findings: summary.findings,
|
|
268
|
-
problems: summary.problems,
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
if (name === 'verify_diff') {
|
|
272
|
-
if (typeof input.cell !== 'string')
|
|
273
|
-
return fail('cell required');
|
|
274
|
-
const { buildScreenshotDiff } = await import('./verify-ops.js');
|
|
275
|
-
const result = await buildScreenshotDiff({
|
|
276
|
-
server,
|
|
277
|
-
repoRoot,
|
|
278
|
-
runSelector: selector,
|
|
279
|
-
cellSelector: input.cell,
|
|
280
|
-
step: typeof input.step === 'number' ? input.step : undefined,
|
|
281
|
-
outDir: typeof input.out_dir === 'string' ? input.out_dir : undefined,
|
|
282
|
-
});
|
|
283
|
-
return ok({
|
|
284
|
-
run_id: result.detail.run_id,
|
|
285
|
-
ordinal: result.detail.ordinal,
|
|
286
|
-
title: result.detail.title,
|
|
287
|
-
html: result.html,
|
|
288
|
-
steps: result.steps,
|
|
289
|
-
differing: result.differing,
|
|
290
|
-
identical: result.identical,
|
|
291
|
-
note: 'Open the html in a browser for the visual compare (keys: 1 what changed, 2 before, 3 after, arrows step).',
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
if (name === 'verify_list') {
|
|
295
|
-
const limit = typeof input.limit === 'number' ? input.limit : 20;
|
|
296
|
-
const { rows, source, total } = await listRunRows({ server, repoRoot, limit });
|
|
297
|
-
return ok({ source, total, returned: rows.length, runs: rows });
|
|
298
|
-
}
|
|
299
|
-
if (name === 'verify_cell') {
|
|
300
|
-
if (typeof input.cell !== 'string')
|
|
301
|
-
return fail('cell required');
|
|
302
|
-
const loaded = await loadRunAuto({ server, repoRoot, selector });
|
|
303
|
-
const match = findCell(loaded.run, input.cell);
|
|
304
|
-
if (input.raw === true)
|
|
305
|
-
return ok(match.cell);
|
|
306
|
-
return ok(cellDetail(loaded.run, match));
|
|
307
|
-
}
|
|
308
|
-
if (name === 'verify_universe') {
|
|
309
|
-
if (typeof input.cell !== 'string')
|
|
310
|
-
return fail('cell required');
|
|
311
|
-
if (input.side !== undefined
|
|
312
|
-
&& input.side !== 'base'
|
|
313
|
-
&& input.side !== 'head') {
|
|
314
|
-
return fail('side must be base or head');
|
|
315
|
-
}
|
|
316
|
-
const loaded = await loadRunAuto({ server, repoRoot, selector });
|
|
317
|
-
const match = findCellByStableSelector(loaded.run, input.cell);
|
|
318
|
-
const side = input.side === 'base' ? 'base' : 'head';
|
|
319
|
-
const universe = side === 'base' ? match.cell.base : match.cell.head;
|
|
320
|
-
const expired = universe.expiresAt
|
|
321
|
-
? Date.parse(universe.expiresAt) < Date.now()
|
|
322
|
-
: false;
|
|
323
|
-
if (universe.browserUrl && universe.status === 'running' && !expired) {
|
|
324
|
-
return ok({
|
|
325
|
-
schema_version: '1.0.0',
|
|
326
|
-
run_id: loaded.run.runId,
|
|
327
|
-
ordinal: match.cell.ordinal,
|
|
328
|
-
side,
|
|
329
|
-
source: 'running',
|
|
330
|
-
url: universe.browserUrl,
|
|
331
|
-
expires_at: universe.expiresAt ?? null,
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
if (!universe.forkId) {
|
|
335
|
-
return fail(`Test ${match.cell.ordinal}'s ${side} universe is not running and `
|
|
336
|
-
+ 'has no durable fork ID to reopen.');
|
|
337
|
-
}
|
|
338
|
-
const { requestUniverseReopen } = await import('./verify-ops.js');
|
|
339
|
-
const reopened = await requestUniverseReopen(server, universe.forkId);
|
|
340
|
-
return ok({
|
|
341
|
-
schema_version: '1.0.0',
|
|
342
|
-
run_id: loaded.run.runId,
|
|
343
|
-
ordinal: match.cell.ordinal,
|
|
344
|
-
side,
|
|
345
|
-
source: 'reopened',
|
|
346
|
-
url: reopened.browserUrl,
|
|
347
|
-
expires_at: reopened.expiresAt,
|
|
348
|
-
fork_id: reopened.forkId,
|
|
349
|
-
sandbox_id: reopened.sandboxId,
|
|
350
|
-
state_expires_at: reopened.stateExpiresAt,
|
|
351
|
-
reused: reopened.reused,
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
if (name === 'verify_cleanup') {
|
|
355
|
-
if (typeof input.cell !== 'string')
|
|
356
|
-
return fail('cell required');
|
|
357
|
-
if (input.side !== undefined
|
|
358
|
-
&& input.side !== 'base'
|
|
359
|
-
&& input.side !== 'head') {
|
|
360
|
-
return fail('side must be base or head');
|
|
361
|
-
}
|
|
362
|
-
const loaded = await loadRunAuto({ server, repoRoot, selector });
|
|
363
|
-
const match = findCellByStableSelector(loaded.run, input.cell);
|
|
364
|
-
const side = input.side === 'base' ? 'base' : 'head';
|
|
365
|
-
const universe = side === 'base' ? match.cell.base : match.cell.head;
|
|
366
|
-
if (!universe.forkId) {
|
|
367
|
-
return fail(`Test ${match.cell.ordinal}'s ${side} universe has no durable fork ID.`);
|
|
368
|
-
}
|
|
369
|
-
const { requestUniverseCleanupStatus } = await import('./verify-ops.js');
|
|
370
|
-
return ok({
|
|
371
|
-
run_id: loaded.run.runId,
|
|
372
|
-
ordinal: match.cell.ordinal,
|
|
373
|
-
side,
|
|
374
|
-
...await requestUniverseCleanupStatus(server, universe.forkId),
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
if (name === 'verify_reopen' || name === 'verify_refork') {
|
|
378
|
-
if (input.side !== undefined
|
|
379
|
-
&& input.side !== 'base'
|
|
380
|
-
&& input.side !== 'head') {
|
|
381
|
-
return fail('side must be base or head');
|
|
382
|
-
}
|
|
383
|
-
const forkId = typeof input.fork_id === 'string'
|
|
384
|
-
? input.fork_id
|
|
385
|
-
: undefined;
|
|
386
|
-
const cell = typeof input.cell === 'string' ? input.cell : undefined;
|
|
387
|
-
if (forkId && cell) {
|
|
388
|
-
return fail('provide fork_id or run/cell, not both');
|
|
389
|
-
}
|
|
390
|
-
if (!forkId && !cell)
|
|
391
|
-
return fail('fork_id or cell required');
|
|
392
|
-
if (name === 'verify_refork') {
|
|
393
|
-
if (typeof input.child_key !== 'string') {
|
|
394
|
-
return fail('child_key required');
|
|
395
|
-
}
|
|
396
|
-
if (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(input.child_key)) {
|
|
397
|
-
return fail('child_key must start with a letter or number and contain at '
|
|
398
|
-
+ 'most 128 letters, numbers, dots, underscores, colons, or hyphens');
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
const { reforkRetainedUniverse, requestUniverseReopen, resolveRetainedUniverseTarget, } = await import('./verify-ops.js');
|
|
402
|
-
const target = await resolveRetainedUniverseTarget({
|
|
403
|
-
server,
|
|
404
|
-
repoRoot,
|
|
405
|
-
source: forkId ?? selector,
|
|
406
|
-
cellSelector: cell,
|
|
407
|
-
side: typeof input.side === 'string' ? input.side : undefined,
|
|
408
|
-
});
|
|
409
|
-
if (name === 'verify_reopen') {
|
|
410
|
-
const reopened = await requestUniverseReopen(server, target.forkId);
|
|
411
|
-
return ok({
|
|
412
|
-
schema_version: '1.0.0',
|
|
413
|
-
run_id: target.runId,
|
|
414
|
-
ordinal: target.ordinal,
|
|
415
|
-
side: target.side,
|
|
416
|
-
...reopened,
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
const operation = await reforkRetainedUniverse(server, target, input.child_key);
|
|
420
|
-
return ok({
|
|
421
|
-
schema_version: '1.0.0',
|
|
422
|
-
run_id: target.runId,
|
|
423
|
-
ordinal: target.ordinal,
|
|
424
|
-
side: target.side,
|
|
425
|
-
child_key: input.child_key,
|
|
426
|
-
attachment_sandbox_id: operation.reopened.sandboxId,
|
|
427
|
-
reused_attachment: operation.reopened.reused,
|
|
428
|
-
...operation.reforked,
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
if (name === 'verify_artifact') {
|
|
432
|
-
if (typeof input.path !== 'string')
|
|
433
|
-
return fail('path required');
|
|
434
|
-
const loaded = await loadRunAuto({ server, repoRoot, selector });
|
|
435
|
-
const run = loaded.run;
|
|
436
|
-
const requested = input.path.replace(/^\/+/, '');
|
|
437
|
-
const fileName = path.posix.basename(requested);
|
|
438
|
-
// Resolve to "<chapter>/artifacts/<file>" — accept that form or a bare
|
|
439
|
-
// file name (searched across chapters on disk / in evidence URLs).
|
|
440
|
-
let rel = requested.includes('/') ? requested : null;
|
|
441
|
-
let bytes = null;
|
|
442
|
-
const localRunDir = repoRoot ? runDir(repoRoot, run.runId) : null;
|
|
443
|
-
if (localRunDir && fs.existsSync(path.join(localRunDir, 'chapters'))) {
|
|
444
|
-
const candidates = rel
|
|
445
|
-
? [path.join(localRunDir, 'chapters', rel)]
|
|
446
|
-
: run.chapters.map(chapter => path.join(localRunDir, 'chapters', chapter.chapterId, 'artifacts', fileName));
|
|
447
|
-
for (const candidate of candidates) {
|
|
448
|
-
const resolved = path.resolve(candidate);
|
|
449
|
-
if (!resolved.startsWith(path.resolve(localRunDir, 'chapters') + path.sep))
|
|
450
|
-
continue;
|
|
451
|
-
if (fs.existsSync(resolved) && fs.statSync(resolved).isFile()) {
|
|
452
|
-
bytes = fs.readFileSync(resolved);
|
|
453
|
-
rel = path.relative(path.join(localRunDir, 'chapters'), resolved);
|
|
454
|
-
break;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
if (!bytes) {
|
|
459
|
-
// A bare file name carries no chapter, and artifacts live under
|
|
460
|
-
// <chapter>/artifacts/<file> — try each chapter of the run.
|
|
461
|
-
const candidates = rel ? [rel] : run.chapters.map(chapter => `${chapter.chapterId}/artifacts/${fileName}`);
|
|
462
|
-
for (const candidate of candidates) {
|
|
463
|
-
const url = `${server}/api/cloud-verifier/runs/${run.runId}/artifacts/${candidate.split('/').map(encodeURIComponent).join('/')}`;
|
|
464
|
-
const response = await fetch(url, { headers: verifyAuthHeaders() });
|
|
465
|
-
if (!response.ok)
|
|
466
|
-
continue;
|
|
467
|
-
bytes = Buffer.from(await response.arrayBuffer());
|
|
468
|
-
rel = candidate;
|
|
469
|
-
break;
|
|
470
|
-
}
|
|
471
|
-
if (!bytes)
|
|
472
|
-
return fail(`Artifact "${input.path}" not found for ${run.runId} on disk or the control plane. Use verify_cell to list artifact paths.`);
|
|
473
|
-
}
|
|
474
|
-
const outPath = typeof input.out_path === 'string' && input.out_path
|
|
475
|
-
? path.resolve(input.out_path)
|
|
476
|
-
: path.join(os.tmpdir(), 'haystack-verify-artifacts', run.runId, rel ?? fileName);
|
|
477
|
-
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
478
|
-
fs.writeFileSync(outPath, bytes);
|
|
479
|
-
const textual = ['.json', '.txt', '.log', '.ndjson'].includes(path.extname(outPath));
|
|
480
|
-
return ok({
|
|
481
|
-
run_id: run.runId,
|
|
482
|
-
artifact: rel ?? fileName,
|
|
483
|
-
saved_to: outPath,
|
|
484
|
-
bytes: bytes.length,
|
|
485
|
-
...(textual && bytes.length <= 65536 ? { content: bytes.toString('utf8') } : {}),
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
if (name === 'sandbox_list') {
|
|
489
|
-
const { inventory, via } = await resolveInventory({ server, repoRoot });
|
|
490
|
-
return ok({ ...inventory, via });
|
|
491
|
-
}
|
|
492
|
-
if (name === 'sandbox_kill') {
|
|
493
|
-
if (typeof input.sandbox_id !== 'string')
|
|
494
|
-
return fail('sandbox_id required');
|
|
495
|
-
const { inventory, kill } = await resolveInventory({ server, repoRoot });
|
|
496
|
-
const target = inventory.sandboxes.find(row => row.sandbox_id === input.sandbox_id);
|
|
497
|
-
if (!target)
|
|
498
|
-
return fail(`Sandbox ${input.sandbox_id} is not in the running list (already gone?).`);
|
|
499
|
-
const result = await kill(target.sandbox_id, input.force === true);
|
|
500
|
-
if (!result.ok) {
|
|
501
|
-
return fail(`Refusing/failed to kill ${target.sandbox_id}: ${result.error}`);
|
|
502
|
-
}
|
|
503
|
-
return ok({
|
|
504
|
-
killed: target.sandbox_id,
|
|
505
|
-
was: target.run_id
|
|
506
|
-
? { run_id: target.run_id, role: target.role, cell: target.cell }
|
|
507
|
-
: { template: target.template, forced: !target.verifier },
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
return fail(`unknown tool: ${name}`);
|
|
511
|
-
}
|
|
512
|
-
catch (error) {
|
|
513
|
-
return fail(error instanceof Error ? error.message : String(error));
|
|
514
|
-
}
|
|
515
|
-
});
|
|
516
|
-
await mcp.connect(new StdioServerTransport());
|
|
517
|
-
}
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { type CellDetail } from './verify-core.js';
|
|
2
|
-
export interface VerifyOpsOptions {
|
|
3
|
-
server?: string;
|
|
4
|
-
repoRoot?: string;
|
|
5
|
-
token?: string;
|
|
6
|
-
json?: boolean;
|
|
7
|
-
}
|
|
8
|
-
export declare function verifyStatusCommand(runSelector: string | undefined, options: VerifyOpsOptions): Promise<void>;
|
|
9
|
-
export interface VerifyWatchOptions extends VerifyOpsOptions {
|
|
10
|
-
interval?: string;
|
|
11
|
-
timeout?: string;
|
|
12
|
-
}
|
|
13
|
-
export declare function verifyWatchCommand(runSelector: string | undefined, options: VerifyWatchOptions): Promise<void>;
|
|
14
|
-
export declare function verifyListCommand(options: VerifyOpsOptions & {
|
|
15
|
-
limit?: string;
|
|
16
|
-
}): Promise<void>;
|
|
17
|
-
export declare function verifyShowCommand(runSelector: string, cellSelector: string, options: VerifyOpsOptions & {
|
|
18
|
-
timeline?: boolean;
|
|
19
|
-
}): Promise<void>;
|
|
20
|
-
export interface VerifyArtifactsOptions extends VerifyOpsOptions {
|
|
21
|
-
out?: string;
|
|
22
|
-
cell?: string;
|
|
23
|
-
}
|
|
24
|
-
export declare function verifyArtifactsCommand(runSelector: string, options: VerifyArtifactsOptions): Promise<void>;
|
|
25
|
-
export declare function verifyFindingsCommand(runSelector: string | undefined, options: VerifyOpsOptions & {
|
|
26
|
-
full?: boolean;
|
|
27
|
-
}): Promise<void>;
|
|
28
|
-
export interface VerifyOpenOptions extends VerifyOpsOptions {
|
|
29
|
-
side?: string;
|
|
30
|
-
step?: string;
|
|
31
|
-
kind?: string;
|
|
32
|
-
live?: boolean;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Open one piece of a run: a live environment (`--live`), a specific artifact
|
|
36
|
-
* by file name, or a cell's video/screenshot/DOM snapshot picked by
|
|
37
|
-
* --side/--step/--kind.
|
|
38
|
-
*/
|
|
39
|
-
export declare function verifyOpenCommand(runSelector: string, target: string, options: VerifyOpenOptions): Promise<void>;
|
|
40
|
-
export interface DiffResult {
|
|
41
|
-
html: string;
|
|
42
|
-
steps: Array<{
|
|
43
|
-
ordinal: number;
|
|
44
|
-
name: string;
|
|
45
|
-
identical: boolean | null;
|
|
46
|
-
}>;
|
|
47
|
-
differing: number;
|
|
48
|
-
identical: number;
|
|
49
|
-
detail: CellDetail;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Build the screenshot-diff page for one test and report which steps differ
|
|
53
|
-
* byte-for-byte. Shared by `haystack verify diff` and the MCP verify_diff tool.
|
|
54
|
-
*/
|
|
55
|
-
export declare function buildScreenshotDiff(options: {
|
|
56
|
-
server: string;
|
|
57
|
-
repoRoot: string | null;
|
|
58
|
-
runSelector: string;
|
|
59
|
-
cellSelector: string;
|
|
60
|
-
step?: number;
|
|
61
|
-
outDir?: string;
|
|
62
|
-
}): Promise<DiffResult>;
|
|
63
|
-
export interface VerifyDiffOptions extends VerifyOpsOptions {
|
|
64
|
-
step?: string;
|
|
65
|
-
out?: string;
|
|
66
|
-
open?: boolean;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Build and open the base-vs-head screenshot differ for one test — the same
|
|
70
|
-
* viewer as the results page: 1 what changed / 2 before / 3 after, swapped in
|
|
71
|
-
* place, with arrow keys stepping.
|
|
72
|
-
*/
|
|
73
|
-
export declare function verifyDiffCommand(runSelector: string, cellSelector: string, options: VerifyDiffOptions): Promise<void>;
|
|
74
|
-
export interface VerifyShellOptions extends VerifyOpsOptions {
|
|
75
|
-
side?: string;
|
|
76
|
-
}
|
|
77
|
-
export interface ReopenResponse {
|
|
78
|
-
forkId: string;
|
|
79
|
-
sandboxId: string;
|
|
80
|
-
browserUrl: string | null;
|
|
81
|
-
expiresAt: string;
|
|
82
|
-
stateExpiresAt: string;
|
|
83
|
-
reused: boolean;
|
|
84
|
-
}
|
|
85
|
-
export interface ReforkResponse {
|
|
86
|
-
forkId: string;
|
|
87
|
-
parentForkId: string;
|
|
88
|
-
checkpointName: string;
|
|
89
|
-
stateExpiresAt: string;
|
|
90
|
-
}
|
|
91
|
-
export interface RetainedUniverseTarget {
|
|
92
|
-
forkId: string;
|
|
93
|
-
runId: string | null;
|
|
94
|
-
ordinal: number | null;
|
|
95
|
-
side: 'base' | 'head' | null;
|
|
96
|
-
}
|
|
97
|
-
export interface UniverseCleanupStatus {
|
|
98
|
-
forkId: string;
|
|
99
|
-
catalogStatus: 'available' | 'expired' | 'deleted';
|
|
100
|
-
status: 'not_started' | 'pending' | 'complete' | 'missed';
|
|
101
|
-
checkedAt: string;
|
|
102
|
-
resources: Array<{
|
|
103
|
-
resourceIdentity: string;
|
|
104
|
-
resource: {
|
|
105
|
-
kind: 'archil-disk';
|
|
106
|
-
id: string;
|
|
107
|
-
region: string;
|
|
108
|
-
} | {
|
|
109
|
-
kind: 'e2b-snapshot';
|
|
110
|
-
id: string;
|
|
111
|
-
};
|
|
112
|
-
status: 'unregistered' | 'active' | 'deleting' | 'deleted';
|
|
113
|
-
referenceCount: number;
|
|
114
|
-
deleteAttempts: number;
|
|
115
|
-
updatedAt?: string;
|
|
116
|
-
deletion?: {
|
|
117
|
-
status: 'pending' | 'met' | 'missed';
|
|
118
|
-
requestedAt: string;
|
|
119
|
-
deadlineAt: string;
|
|
120
|
-
sloSeconds: number;
|
|
121
|
-
deletedAt?: string;
|
|
122
|
-
durationMs?: number;
|
|
123
|
-
};
|
|
124
|
-
}>;
|
|
125
|
-
}
|
|
126
|
-
export declare function requestUniverseCleanupStatus(server: string, forkId: string): Promise<UniverseCleanupStatus>;
|
|
127
|
-
export interface VerifyCleanupOptions extends VerifyOpsOptions {
|
|
128
|
-
side?: string;
|
|
129
|
-
}
|
|
130
|
-
export declare function verifyCleanupCommand(runSelector: string, cellSelector: string, options: VerifyCleanupOptions): Promise<void>;
|
|
131
|
-
export declare function requestUniverseReopen(server: string, forkId: string): Promise<ReopenResponse>;
|
|
132
|
-
export declare function requestUniverseRefork(server: string, forkId: string, sandboxId: string, childKey: string): Promise<ReforkResponse>;
|
|
133
|
-
export declare function resolveRetainedUniverseTarget(options: {
|
|
134
|
-
server: string;
|
|
135
|
-
repoRoot: string | null;
|
|
136
|
-
source: string;
|
|
137
|
-
cellSelector?: string;
|
|
138
|
-
side?: string;
|
|
139
|
-
}): Promise<RetainedUniverseTarget>;
|
|
140
|
-
export declare function reforkRetainedUniverse(server: string, target: RetainedUniverseTarget, childKey: string): Promise<{
|
|
141
|
-
reopened: ReopenResponse;
|
|
142
|
-
reforked: ReforkResponse;
|
|
143
|
-
}>;
|
|
144
|
-
export interface VerifyReopenOptions extends VerifyOpsOptions {
|
|
145
|
-
side?: string;
|
|
146
|
-
openBrowser?: boolean;
|
|
147
|
-
}
|
|
148
|
-
export declare function verifyReopenCommand(source: string, cellSelector: string | undefined, options: VerifyReopenOptions): Promise<void>;
|
|
149
|
-
export interface VerifyReforkOptions extends VerifyOpsOptions {
|
|
150
|
-
side?: string;
|
|
151
|
-
}
|
|
152
|
-
export declare function verifyReforkCommand(source: string, cellOrChildKey: string, requestedChildKey: string | undefined, options: VerifyReforkOptions): Promise<void>;
|
|
153
|
-
/**
|
|
154
|
-
* Drop a terminal into a test's live universe via the E2B CLI. Only failing
|
|
155
|
-
* tests keep a universe alive. An expired Archil-backed compute attachment is
|
|
156
|
-
* transparently replaced while its durable state is still retained.
|
|
157
|
-
*/
|
|
158
|
-
export declare function verifyShellCommand(runSelector: string, cellSelector: string, options: VerifyShellOptions): Promise<void>;
|