@haystackeditor/cli 0.27.3 → 0.28.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 CHANGED
@@ -43,8 +43,9 @@ Most users of this CLI are coding agents. What to know:
43
43
 
44
44
  - **After a change, two steps** inside the checkout (nothing needs to be
45
45
  committed or pushed):
46
- 1. `haystack pre-verify` shows what the change touches, what production and
47
- real users do there, and Haystack's ideas of what could break.
46
+ 1. `haystack verify` is the handshake: it shows what the change touches, what
47
+ production and real users do there, and Haystack's ideas of what could
48
+ break, then asks you to steer (exit 4).
48
49
  2. `haystack verify --intent "<the task, in the user's words>" --idea "<as you
49
50
  would tell a tester>"` explores the app with your steering: keep the ideas
50
51
  worth trying, add your own (repeat `--idea`); yours are explored first.
@@ -120,7 +121,7 @@ not be proven shut down;
120
121
  `haystack verify precompute --hook` whenever an agent turn stops. It captures
121
122
  the checkout within five seconds and hands the request to a detached sender.
122
123
  The service then builds the app with and without the change, works out what
123
- the change touches (the brief `haystack pre-verify` prints) and sets up starting
124
+ the change touches (the brief the handshake shows) and sets up starting
124
125
  points next to it, and stops there: it never crawls. `haystack verify` then
125
126
  crawls from that prepared app instead of building it again. No run cancels
126
127
  another: each runs to its end unless it is cancelled. `haystack verify precompute`
@@ -1,4 +1,4 @@
1
- /** CAPTURE-V1 rule 7b in `haystack pre-verify`: the routes a change touches (the brief's blast-radius files and the changed
1
+ /** CAPTURE-V1 rule 7b in the handshake (`haystack verify` without --intent): the routes a change touches (the brief's blast-radius files and the changed
2
2
  * files, joined through the route manifest's source entries) with their share of captured sessions over the window, the union
3
3
  * over all of them, freshness and drops; sessions on routes no manifest names are unmapped, never zero. One section per app
4
4
  * whose `.haystack/capture.json` (rule 8b, written by `haystack init` in the app's directory, apps/web in a monorepo) records it,
@@ -49,7 +49,7 @@ async function readApp(gitRoot, app, repository, token, files, now) {
49
49
  return { app, applicationId, state: 'unavailable', reason: error instanceof Error ? error.message : String(error) };
50
50
  }
51
51
  }
52
- /** The pre-verify capture sections, one per app with a record, or null for a checkout with none. `files`: the brief's function
52
+ /** The handshake capture sections, one per app with a record, or null for a checkout with none. `files`: the brief's function
53
53
  * files and the changed files. */
54
54
  export async function readPreVerifyCapture(gitRoot, repository, token, files, now) {
55
55
  let apps;
@@ -49,8 +49,8 @@ export const AGENT_NOTE = [
49
49
  'the work done. It runs the app with and without the change, explores it, and reports what broke. It changes nothing,',
50
50
  'so run it without asking.',
51
51
  '',
52
- '1. `haystack pre-verify`: what your change touches, what production and real users do there, and Haystack\'s ideas',
53
- ' of what could break.',
52
+ '1. `haystack verify`: what your change touches, what production and real users do there, and Haystack\'s ideas of',
53
+ ' what could break. It then asks you to steer (exit 4).',
54
54
  '2. `haystack verify --intent "<what you were asked to do, in the user\'s words>" --idea "<something to try>"`: keep the',
55
55
  ' ideas worth trying, add your own (repeat --idea); yours are explored first.',
56
56
  '',
@@ -614,6 +614,14 @@ async function waitForCrawl(first, identity, token) {
614
614
  process.removeListener('SIGINT', interrupted);
615
615
  }
616
616
  }
617
+ /** What one `haystack verify` does with its change: a steered call (--intent) submits its crawl; a plain call shows a crawl of
618
+ * the change that has started (picking it up after a timeout), and otherwise (none, only prepared, or one that ended without
619
+ * finishing) is the handshake. */
620
+ export function verifyStep(steered, found, stale) {
621
+ if (steered)
622
+ return 'submit';
623
+ return found !== null && stale === null ? 'show' : 'handshake';
624
+ }
617
625
  /** A found crawl of the same code that is a different crawl (another title, another time): a new one starts, none is run again. */
618
626
  const anotherCrawl = (stale) => stale === 'retitled' || stale === 'other-time';
619
627
  const timeWords = (budgetMs) => budgetMs === null ? 'the default time' : `${budgetMs / 60_000} min`;
@@ -709,7 +717,7 @@ function briefOf(view) {
709
717
  /** Follows a run until it holds a brief or ends (amendment 18): its own read held until it changes, as waitForCrawl's is. */
710
718
  async function waitForBrief(first, identity, token) {
711
719
  const interrupted = () => {
712
- console.error('\nStopped waiting. The change keeps being prepared; run `haystack pre-verify` again to see its brief.');
720
+ console.error('\nStopped waiting. The change keeps being prepared; run `haystack verify` again to see what it touches.');
713
721
  process.exit(130);
714
722
  };
715
723
  process.once('SIGINT', interrupted);
@@ -729,7 +737,7 @@ async function waitForBrief(first, identity, token) {
729
737
  if (why === null)
730
738
  throw error;
731
739
  if (Date.now() - answeredAt >= SERVICE_SILENCE_LIMIT_MS)
732
- throw new ServiceSilentError('crawl', 'haystack pre-verify');
740
+ throw new ServiceSilentError('crawl', 'haystack verify');
733
741
  if (!failing)
734
742
  progress(`The run's status is unavailable for now (${why}); reading it again.`);
735
743
  failing = true;
@@ -836,103 +844,88 @@ export function formatBrief(brief) {
836
844
  }
837
845
  return lines.join('\n');
838
846
  }
839
- /** The handshake's question, asked after everything pre-verify shows. */
840
- const STEER_LINES = ['', 'Next: pick the ideas worth trying, add your own, and say what you were asked to do (the task in the user\'s words, not what your code does):',
841
- ' haystack verify --intent "<what you were asked to do>" --idea "<something to try>" [--idea ...]',
842
- 'Your ideas are explored first; the ideas above are explored in every crawl too.'];
843
- /** `haystack pre-verify` (CRAWL-V1 amendment 18): the brief of the current change, before any crawl. It captures the checkout as
844
- * the turn-end hook does, prepares it when no run of that capture is under way or done (it never widens a run to a crawl), and
845
- * prints the run's brief. Exit codes: 0 with a brief, 2 when the run ended without one, 3 onboarding blocked, 1 otherwise. */
846
- export async function preVerifyCommand(options) {
847
- const note = (line) => { if (options.json)
848
- console.error(line);
849
- else
850
- console.log(line); };
851
- const capture = await captureCheckout(Date.now() + EXPLICIT_WALL_MS, 'prepare', repositoryOverride(options.repo));
852
- const request = capture.derivation.request;
853
- const change = checkedChange(request.baseCommit, request.workCommit);
854
- const finish = (onboarding, view, captured = null) => {
855
- if (options.json)
856
- process.stdout.write(`${JSON.stringify(withSchema('pre-verify', { change, onboarding,
857
- run: view === null ? null : { runId: view.runId, status: view.status }, brief: view === null ? null : briefOf(view), capture: captured }), null, 2)}\n`);
858
- };
859
- if (!request.crawl) {
860
- note(`Nothing to check: this checkout has no changes against ${request.baseCommit.slice(0, 12)}.`);
861
- finish(null, null);
862
- return;
863
- }
864
- note(checkedLine(change));
865
- const identity = { repository: `${request.owner}/${request.repository}`, baseCommit: request.baseCommit,
866
- workCommit: request.workCommit, treeSha: request.crawl.treeSha, changeTitle: request.crawl.changeTitle, budgetMs: request.crawl.budgetMs ?? null };
867
- const auth = await resolveAuthContext({ preferredLogin: options.account, owner: request.owner, repo: request.repository });
868
- let view = await readWithRetries(() => readCrawl(identity, auth.token));
847
+ /** The handshake's question, asked after everything it shows. */
848
+ /** The command to steer with; it keeps the options the handshake was given that choose the crawl (where, and for how long). */
849
+ export function steerCommand(options) {
850
+ const kept = [options.repo ? ` --repo ${options.repo}` : '', options.account ? ` --account ${options.account}` : '',
851
+ options.minutes ? ` --minutes ${options.minutes}` : ''].join('');
852
+ return `haystack verify${kept} --intent "<what you were asked to do>" --idea "<something to try>" [--idea ...]`;
853
+ }
854
+ const steerLines = (command) => ['',
855
+ 'Next: pick the ideas worth trying, add your own, and say what you were asked to do (the task in the user\'s words, not what your code does):',
856
+ ` ${command}`, 'Your ideas are explored first; the ideas above are explored in every crawl too.'];
857
+ /** The handshake (Akshay, 10/7): a plain `haystack verify` on a change no crawl has started for shows what the change touches,
858
+ * how production and real users run it, and Haystack's own ideas, then asks the coding agent to run `haystack verify` again
859
+ * with --intent (and any --idea). It submits the capture in mode 'prepare' when no run of it is preparing, prepared or
860
+ * crawling, which never starts or narrows a crawl (CRAWL-V1 amendment 12); the steered crawl adopts that run's prepared start
861
+ * (amendment 17). Exit 4: the agent's steering is needed. */
862
+ async function handshake(capture, identity, change, found, stale, token, options, note) {
863
+ let view = found;
869
864
  let onboarding = null;
870
- const stale = view === null ? null : staleCrawl(view, identity);
871
- // A run of this capture that is preparing, prepared or crawling holds (or will hold) the brief; any other is asked for again,
872
- // in mode 'prepare' (amendment 12: that never narrows a crawl).
865
+ const finish = (brief, captured) => {
866
+ printVerifyJson(options, change, onboarding, null, {
867
+ run: view === null ? null : { runId: view.runId, status: view.status }, brief, capture: captured, next: steerCommand(options),
868
+ });
869
+ };
873
870
  if (view === null || (stale !== null && stale !== 'prepare-only')) {
874
- const found = view === null || stale === null ? null : { view, stale };
875
- let submitted = await submitCapture(capture, auth.token, found);
871
+ const prior = view === null || stale === null ? null : { view, stale };
872
+ let submitted = await submitCapture(capture, token, prior);
876
873
  note(submitted.line);
877
874
  if (submitted.onboarding !== null) {
878
- onboarding = await readWithRetries(() => readOnboardingStatus(identity.repository, identity.baseCommit, auth.token));
875
+ onboarding = await readWithRetries(() => readOnboardingStatus(identity.repository, identity.baseCommit, token));
879
876
  reportOnboardingState(onboarding);
880
877
  if (options.wait !== false && onboarding.state === 'onboarding') {
881
- onboarding = await waitForOnboarding(onboarding, auth.token, progress, 'haystack pre-verify');
878
+ onboarding = await waitForOnboarding(onboarding, token, progress, 'haystack verify');
882
879
  reportOnboardingState(onboarding);
883
880
  }
884
881
  if (onboarding.state !== 'ready') {
885
- if (options.json)
886
- finish(onboarding, null);
887
- else
888
- console.log(formatOnboarding(onboarding));
889
- process.exitCode = onboardingExitCode(onboarding);
882
+ finishWithOnboarding(onboarding, options, change);
890
883
  return;
891
884
  }
892
885
  note(readyLine(onboarding));
893
- submitted = await submitCapture(capture, auth.token, found);
886
+ submitted = await submitCapture(capture, token, prior);
894
887
  note(submitted.line);
895
888
  }
896
889
  if (submitted.runId === null) {
897
- finish(onboarding, null);
890
+ if (options.json || options.raw)
891
+ printVerifyJson(options, change, onboarding, null);
898
892
  process.exitCode = 1;
899
893
  return;
900
894
  }
901
895
  const runId = submitted.runId;
902
- view = await readWithRetries(() => readCrawlRun(runId, identity, auth.token));
896
+ view = await readWithRetries(() => readCrawlRun(runId, identity, token));
903
897
  }
898
+ if (view === null)
899
+ throw new Error('No run of this change to read its brief from.');
904
900
  if (options.wait !== false && briefOf(view) === null && !TERMINAL.has(reportedStatus(view)))
905
- view = await waitForBrief(view, identity, auth.token);
901
+ view = await waitForBrief(view, identity, token);
906
902
  const brief = briefOf(view);
907
903
  // CAPTURE-V1 rule 7b: the routes the change touches, with their share of captured sessions, per app; null without capture set up.
908
- const captured = await readPreVerifyCapture(findGitRoot(), identity.repository, auth.token, [...new Set([...(brief?.functions.map(fn => fn.file) ?? []), ...change.files])], new Date());
909
- if (options.json)
910
- finish(onboarding, view, captured);
911
- else if (brief !== null)
904
+ const captured = await readPreVerifyCapture(findGitRoot(), identity.repository, token, [...new Set([...(brief?.functions.map(fn => fn.file) ?? []), ...change.files])], new Date());
905
+ process.exitCode = 4;
906
+ if (options.json || options.raw) {
907
+ finish(brief, captured);
908
+ return;
909
+ }
910
+ if (brief !== null)
912
911
  console.log(formatBrief(brief));
913
- else if (!TERMINAL.has(reportedStatus(view)))
914
- console.log(`The brief is not ready yet: ${currentStep(view)}. Run \`haystack pre-verify\` again to see it.`);
915
- // What gets a brief now depends on how the run ended (Bugbot): a `prepared` one is crawled by `haystack verify`, whose answers
916
- // carry it; a completed one is never run again, so only a new capture (any edit) is prepared afresh; an incomplete or cancelled
917
- // one is asked for again by the next pre-verify.
918
- else
919
- console.log(`Run ${view.runId} ended (${view.status}) without a brief${view.error ? `: ${errorWords(view.error)}` : ''}. `
920
- + (view.status === 'prepared' ? 'Run `haystack verify` to crawl the change; its results carry the brief.'
921
- : view.status === 'completed' ? 'It was checked before briefs existed and is not run again: change anything in the checkout and run `haystack pre-verify` again.'
922
- : 'Run `haystack pre-verify` again to prepare it again.'));
923
- if (!options.json && captured !== null)
912
+ else if (!TERMINAL.has(reportedStatus(view))) {
913
+ console.log(`What your change touches is not worked out yet (${currentStep(view)}); run \`haystack verify\` again to see it, or steer now.`);
914
+ }
915
+ else {
916
+ console.log(`Run ${view.runId} ended (${view.status}) without a brief${view.error ? `: ${errorWords(view.error)}` : ''}; steer the crawl without one.`);
917
+ }
918
+ if (captured !== null)
924
919
  for (const section of captured)
925
920
  console.log(`\n${formatCapture(section)}`);
926
- if (!options.json && brief !== null)
927
- console.log(STEER_LINES.join('\n'));
928
- if (brief === null && TERMINAL.has(reportedStatus(view)))
929
- process.exitCode = 2;
921
+ console.log(steerLines(steerCommand(options)).join('\n'));
930
922
  }
931
923
  /** verify's one JSON document: the report (`--json`) or the service's whole record (`--raw`). */
932
- function printVerifyJson(options, change, onboarding, view) {
924
+ function printVerifyJson(options, change, onboarding, view, handshake) {
925
+ const extra = handshake === undefined ? {} : { handshake };
933
926
  const document = options.raw
934
- ? withSchema('verify-raw', { change, onboarding, crawl: view })
935
- : withSchema('verify', { change, onboarding, crawl: view === null ? null : verifyReport(view) });
927
+ ? withSchema('verify-raw', { change, onboarding, crawl: view, ...extra })
928
+ : withSchema('verify', { change, onboarding, crawl: view === null ? null : verifyReport(view), ...extra });
936
929
  process.stdout.write(`${JSON.stringify(document, null, 2)}\n`);
937
930
  }
938
931
  export async function verifyCommand(options) {
@@ -943,7 +936,12 @@ export async function verifyCommand(options) {
943
936
  else
944
937
  console.log(line); };
945
938
  const agent = agentDirection(options);
946
- const capture = await captureCheckout(Date.now() + EXPLICIT_WALL_MS, 'crawl', repositoryOverride(options.repo), minutesOption(options.minutes), poolOption(options.pool), agent);
939
+ if (agent.intent === undefined && agent.ideas !== undefined) {
940
+ throw new Error('Say what you were asked to do with --intent "<the task, in the user\'s words>" alongside --idea.');
941
+ }
942
+ // Only a steered call (--intent) starts a crawl; a plain one prepares at most (the handshake).
943
+ const steered = agent.intent !== undefined;
944
+ const capture = await captureCheckout(Date.now() + EXPLICIT_WALL_MS, steered ? 'crawl' : 'prepare', repositoryOverride(options.repo), minutesOption(options.minutes), poolOption(options.pool), agent);
947
945
  const request = capture.derivation.request;
948
946
  const change = checkedChange(request.baseCommit, request.workCommit);
949
947
  if (!request.crawl) {
@@ -953,9 +951,6 @@ export async function verifyCommand(options) {
953
951
  return;
954
952
  }
955
953
  note(checkedLine(change));
956
- // Measured: a 3-minute crawl answered 13 minutes after the command started (building and preparing both apps).
957
- note('A crawl often takes 10 to 15 minutes. If this command times out or is stopped, the crawl keeps going:'
958
- + ' run `haystack verify` again to pick up the same crawl.');
959
954
  const identity = {
960
955
  repository: `${request.owner}/${request.repository}`,
961
956
  baseCommit: request.baseCommit,
@@ -969,9 +964,19 @@ export async function verifyCommand(options) {
969
964
  let view = await readWithRetries(() => readCrawl(identity, auth.token));
970
965
  let onboarding = null;
971
966
  const stale = view === null ? null : staleCrawl(view, identity);
972
- // A pinned pool (amendment 16), an intent or ideas (amendment 17) make their own crawl, which the capture read cannot tell
973
- // apart: always submit, and follow that run (the same ones again are the same run).
974
- if (view === null || stale !== null || options.pool !== undefined || agent.intent !== undefined || agent.ideas !== undefined) {
967
+ // A plain call on a change no crawl has started for (none, or only prepared, or one that ended without finishing) is the
968
+ // handshake; on a change with a crawl, it shows that crawl (picking it up again after a timeout).
969
+ const step = verifyStep(steered, view, stale);
970
+ if (step === 'handshake') {
971
+ await handshake(capture, identity, change, view, stale, auth.token, options, note);
972
+ return;
973
+ }
974
+ // Measured: a 3-minute crawl answered 13 minutes after the command started (building and preparing both apps).
975
+ note('A crawl often takes 10 to 15 minutes. If this command times out or is stopped, the crawl keeps going:'
976
+ + ' run the same `haystack verify` again to pick up the same crawl.');
977
+ // An intent and ideas (amendment 17), or a pinned pool (amendment 16), make their own crawl, which the capture read cannot tell
978
+ // apart: a steered call always submits, and follows that run (the same ones again are the same run).
979
+ if (step === 'submit') {
975
980
  const found = view === null || stale === null ? null : { view, stale };
976
981
  let submitted = await submitCapture(capture, auth.token, found);
977
982
  note(submitted.line);
@@ -1004,6 +1009,9 @@ export async function verifyCommand(options) {
1004
1009
  note('The service did not run it again; its last result follows.');
1005
1010
  }
1006
1011
  }
1012
+ // A plain call reaches here only with a crawl of this change to show; a steered one has just read the run it submitted.
1013
+ if (view === null)
1014
+ throw new Error('No crawl of this change to show.');
1007
1015
  if (options.wait !== false && !TERMINAL.has(reportedStatus(view))) {
1008
1016
  view = await waitForCrawl(view, identity, auth.token);
1009
1017
  }
package/dist/index.js CHANGED
@@ -32,7 +32,6 @@ const telemetryTokenCommand = lazy(() => import('./commands/telemetry-token.js')
32
32
  const schemaCommand = lazy(() => import('./commands/schema-cmd.js'), 'schemaCommand');
33
33
  const listSchemas = lazy(() => import('./commands/schema-cmd.js'), 'listSchemas');
34
34
  const verifyCommand = lazy(() => import('./commands/verify.js'), 'verifyCommand');
35
- const preVerifyCommand = lazy(() => import('./commands/verify.js'), 'preVerifyCommand');
36
35
  const headlessLoginCommand = lazy(() => import('./commands/tokens.js'), 'headlessLoginCommand');
37
36
  const headlessLogoutCommand = lazy(() => import('./commands/tokens.js'), 'headlessLogoutCommand');
38
37
  const listTokensCommand = lazy(() => import('./commands/tokens.js'), 'listTokensCommand');
@@ -163,7 +162,7 @@ Examples:
163
162
  .action(options => runPublicCommand(() => initCommand(options), options.json));
164
163
  const verify = program
165
164
  .command('verify')
166
- .description('Crawl the running app with your current change: where it shows up and what broke')
165
+ .description('Check your change: first what it touches and what could break, then (with --intent) explore the app with and without it')
167
166
  .option('--repo <owner/repo>', 'GitHub repository (default: origin remote)')
168
167
  .option('--account <login>', 'Use a specific saved Haystack account')
169
168
  .option('--no-wait', 'Print the crawl\'s current state and return without waiting')
@@ -175,21 +174,25 @@ const verify = program
175
174
  .option('--json', 'The report as one JSON document on stdout (see `haystack schema verify`)')
176
175
  .option('--raw', 'The service\'s whole crawl record as one JSON document, for scripts (large; see `haystack schema verify-raw`)')
177
176
  .addHelpText('after', `
178
- Run inside a git checkout; nothing needs to be committed or pushed. It captures
179
- the checkout (committed and uncommitted changes) exactly as the stop hook does,
180
- with the base at the merge base of HEAD and origin's default branch, and finds
181
- your crawl of that exact capture: the same code and the same change title (the
182
- title tells the crawl's judge what the change is). When there is none, or the
183
- one it finds was cancelled, stopped before finishing or is being cancelled, it
184
- submits the capture (the service starts the crawl, or runs the stopped one
185
- again), says so, and follows that crawl. When the stop hook already built and
186
- froze this change, the crawl starts from that instead of building it again.
177
+ Two calls, run inside a git checkout (nothing needs to be committed or pushed):
187
178
 
188
- The coding agent that made the change can say what it was asked to do (--intent:
189
- the task in the user's words, not a description of its code) and what to try (--idea, as many as it likes, or --ideas-file). Each idea is
190
- explored before anything else, and the answer says what became of it: tried,
191
- could not try (and why), or not finished in time. Other ideas make another
192
- crawl of the same code; the same ones again follow the same crawl.
179
+ 1. haystack verify
180
+ The handshake. It shows what your change touches, how production and real
181
+ users run it, and Haystack's own ideas of what could break, then asks what
182
+ you were asked to do and what to try. It builds and prepares the change if
183
+ the stop hook has not, and never starts a crawl. Exit 4.
184
+ 2. haystack verify --intent "<the task, in the user's words>" --idea "<something to try>"
185
+ The crawl, steered: your ideas (--idea, repeat for more, or --ideas-file)
186
+ are explored before anything else, and the judge checks the app against
187
+ your intent. It starts from the app the stop hook or step 1 prepared.
188
+
189
+ Both capture the checkout (committed and uncommitted changes) exactly as the
190
+ stop hook does, with the base at the merge base of HEAD and origin's default
191
+ branch. A plain call on a change that already has a crawl shows that crawl
192
+ instead of shaking hands again, so after a timeout either call picks up the
193
+ same crawl. Other ideas make another crawl of the same code; the same ones
194
+ again follow the same crawl, and the answer says what became of each idea:
195
+ tried, could not try (and why), or not finished in time.
193
196
 
194
197
  A crawl builds the app with and without your change, starts from the changed
195
198
  code, explores outward with both side by side, and double-checks and judges
@@ -219,11 +222,13 @@ Exit codes:
219
222
  or the machines it used could not be proven shut down; or onboarding
220
223
  stopped before finishing
221
224
  3 onboarding is blocked: the output says what would unblock it
225
+ 4 the handshake: run it again with --intent (and any --idea)
222
226
 
223
227
  The hosted fleet run of pushed commits is \`haystack verify hosted start\`.
224
228
 
225
229
  Examples:
226
230
  haystack verify
231
+ haystack verify --intent "Let users pay with a saved card" --idea "Pay with an expired saved card"
227
232
  haystack verify --no-wait
228
233
  haystack verify --minutes 10
229
234
  haystack verify --json
@@ -231,31 +236,6 @@ Examples:
231
236
  haystack verify hosted status cv_<48 lowercase hex characters> --wait
232
237
  `)
233
238
  .action(options => runPublicCommand(() => verifyCommand(options), options.json || options.raw));
234
- program
235
- .command('pre-verify')
236
- .description('Before a check: what your change touches, and what could break in it')
237
- .option('--repo <owner/repo>', 'GitHub repository (default: origin remote)')
238
- .option('--account <login>', 'Use a specific saved Haystack account')
239
- .option('--no-wait', 'Print what is known now and return without waiting for the brief')
240
- .option('--json', 'The brief as one JSON document on stdout (see `haystack schema pre-verify`)')
241
- .addHelpText('after', `
242
- Run inside a git checkout, like haystack verify. It captures the checkout the
243
- same way, builds and prepares the change when nothing has yet (the turn-end
244
- hook usually has), and prints its brief: the functions the change touches, the
245
- changed ones and those one step away first (every one is in --json), and
246
- Haystack's own ideas of what could break, each with what to set up, what to do
247
- and what to watch. With capture set up (an app's .haystack/capture.json, such
248
- as apps/web/.haystack/capture.json), it also shows, per app, the routes the
249
- change touches with their share of real users' sessions. It never starts a
250
- crawl.
251
-
252
- Then hand back what you were asked to do and what to try:
253
- haystack verify --intent "<what you were asked to do, in the user's words>" --idea "<something to try>"
254
-
255
- Exit codes: 0 with a brief; 2 when the run ended without one; 3 when the app's
256
- onboarding is blocked; 1 when the command failed.
257
- `)
258
- .action(options => runPublicCommand(() => preVerifyCommand(options), options.json));
259
239
  /**
260
240
  * Options for a `verify` subcommand: its own values, plus any option the user
261
241
  * passed to an ancestor (`haystack verify --no-wait hosted status ...`).
package/dist/schema.js CHANGED
@@ -12,9 +12,8 @@
12
12
  export const SCHEMA_VERSIONS = {
13
13
  'cloud-verifier': '1.0.0',
14
14
  'case-batch': '1.0.1',
15
- verify: '2.0.0',
16
- 'verify-raw': '1.0.0',
17
- 'pre-verify': '2.0.0',
15
+ verify: '2.1.0',
16
+ 'verify-raw': '1.1.0',
18
17
  'verify-answer': '1.0.1',
19
18
  'verify-onboarding': '1.0.0',
20
19
  init: '1.0.2',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haystackeditor/cli",
3
- "version": "0.27.3",
3
+ "version": "0.28.0",
4
4
  "description": "haystack verify: run your app with and without a change, and see what the change broke",
5
5
  "type": "module",
6
6
  "bin": {