@haystackeditor/cli 0.27.1 → 0.27.3
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 +22 -16
- package/dist/commands/init.js +20 -6
- package/dist/commands/verify-onboarding.js +29 -9
- package/dist/commands/verify-precompute.js +1 -1
- package/dist/commands/verify.js +13 -8
- package/dist/index.js +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,10 +41,13 @@ or `HAYSTACK_TELEMETRY_DISABLED=1` to turn this telemetry off.
|
|
|
41
41
|
|
|
42
42
|
Most users of this CLI are coding agents. What to know:
|
|
43
43
|
|
|
44
|
-
- **After a change,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
- **After a change, two steps** inside the checkout (nothing needs to be
|
|
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.
|
|
48
|
+
2. `haystack verify --intent "<the task, in the user's words>" --idea "<as you
|
|
49
|
+
would tell a tester>"` explores the app with your steering: keep the ideas
|
|
50
|
+
worth trying, add your own (repeat `--idea`); yours are explored first.
|
|
48
51
|
- **First time in a repository**, `haystack init --yes` sets it up and starts
|
|
49
52
|
onboarding the app. `haystack verify onboarding` shows where onboarding is.
|
|
50
53
|
When onboarding asks a question, answer it with
|
|
@@ -74,10 +77,11 @@ It then finds your crawl of that exact capture: the same code and the same
|
|
|
74
77
|
change title (HEAD's subject, which tells the crawl's judge what the change is;
|
|
75
78
|
committing or rewording keeps the code but changes the title). When there is
|
|
76
79
|
none, or the one it finds was cancelled, stopped before finishing or is being
|
|
77
|
-
cancelled,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
cancelled, or the stop hook only built it, it asks the service for the crawl
|
|
81
|
+
(the service starts it, runs the stopped one again once it has shut down, or
|
|
82
|
+
turns the hook's prepared run into a crawl that starts from the app the hook
|
|
83
|
+
already built), says so in one line, and follows that crawl; it never shows a
|
|
84
|
+
crawl of another revision or another title.
|
|
81
85
|
|
|
82
86
|
A crawl builds the app with and without your change, starts from the changed
|
|
83
87
|
code, reaches it in the running app, explores outward with both builds side by
|
|
@@ -108,18 +112,20 @@ up, what became of each idea, and what never ran (`haystack schema verify`).
|
|
|
108
112
|
it is large (`haystack schema verify-raw`). Exit codes: 0 when the crawl
|
|
109
113
|
answered or finished (the bugs
|
|
110
114
|
it found are in the output) or is still running under `--no-wait`; 2 when it ended
|
|
111
|
-
without finishing (stopped early, or cancelled
|
|
112
|
-
|
|
115
|
+
without finishing (stopped early, or cancelled) or the machines it used could
|
|
116
|
+
not be proven shut down;
|
|
113
117
|
1 when the command failed or no crawl could be started.
|
|
114
118
|
|
|
115
119
|
**The stop hook.** `haystack init` installs a Claude Code Stop hook that runs
|
|
116
120
|
`haystack verify precompute --hook` whenever an agent turn stops. It captures
|
|
117
|
-
the checkout within five seconds and hands the request to a detached sender
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
the checkout within five seconds and hands the request to a detached sender.
|
|
122
|
+
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
|
+
points next to it, and stops there: it never crawls. `haystack verify` then
|
|
125
|
+
crawls from that prepared app instead of building it again. No run cancels
|
|
126
|
+
another: each runs to its end unless it is cancelled. `haystack verify precompute`
|
|
127
|
+
(without `--hook`) submits the same capture in the foreground and prints one
|
|
128
|
+
line for the run it started.
|
|
123
129
|
|
|
124
130
|
Retained fleet cases remain available through their exact case IDs:
|
|
125
131
|
|
package/dist/commands/init.js
CHANGED
|
@@ -45,16 +45,21 @@ export const AGENT_NOTE = [
|
|
|
45
45
|
NOTE_BEGIN,
|
|
46
46
|
'## Haystack',
|
|
47
47
|
'',
|
|
48
|
-
'After you change this app\'s code, or when the user asks you to check a change,
|
|
49
|
-
'
|
|
50
|
-
'
|
|
48
|
+
'After you change this app\'s code, or when the user asks you to check a change, check it with Haystack before you call',
|
|
49
|
+
'the work done. It runs the app with and without the change, explores it, and reports what broke. It changes nothing,',
|
|
50
|
+
'so run it without asking.',
|
|
51
51
|
'',
|
|
52
|
-
'
|
|
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.',
|
|
54
|
+
'2. `haystack verify --intent "<what you were asked to do, in the user\'s words>" --idea "<something to try>"`: keep the',
|
|
55
|
+
' ideas worth trying, add your own (repeat --idea); yours are explored first.',
|
|
56
|
+
'',
|
|
57
|
+
'- `verify` often takes 10 to 15 minutes: give it your longest timeout or run it in the background, and do not pipe it',
|
|
53
58
|
' through `tail` or `head`, which hide its progress. If your command times out, run it again: it picks up the same crawl.',
|
|
54
59
|
'- Fix each bug it reports that your change caused, then run `haystack verify` again.',
|
|
55
60
|
'- If it says onboarding needs an answer, ask the user that question and file their choice with',
|
|
56
61
|
' `haystack verify answer <question-id> <choice>`.',
|
|
57
|
-
'- Read
|
|
62
|
+
'- Read verify\'s short report. `--json` prints the same report as data; `--raw` prints the crawl\'s whole record (large), for scripts;',
|
|
58
63
|
' `haystack verify --help` explains the output and exit codes.',
|
|
59
64
|
'- If `haystack` is not installed, run each command as `npx -y -p @haystackeditor/cli@latest haystack <command>`.',
|
|
60
65
|
'- If Haystack fails, confuses you or gets in your way, say so in a sentence with',
|
|
@@ -511,7 +516,8 @@ export async function initCommand(options) {
|
|
|
511
516
|
}
|
|
512
517
|
let onboarding;
|
|
513
518
|
try {
|
|
514
|
-
// The notes first: onboarding plans from the facts it starts with,
|
|
519
|
+
// The notes first: onboarding plans from the facts it starts with (rule 2, amendment 34: new notes onboard again only while
|
|
520
|
+
// the repository has no setup, after a run that ended without one).
|
|
515
521
|
if (notes) {
|
|
516
522
|
notesWritten = await writeOnboardingNotes(repository, notes, token);
|
|
517
523
|
say(notesWritten === 'written' ? chalk.green('✓ Wrote the onboarding notes') : chalk.dim('The onboarding notes are already these.'));
|
|
@@ -529,6 +535,14 @@ export async function initCommand(options) {
|
|
|
529
535
|
const done = plan.changes.length > 0 ? 'The changes above were made, but onboarding' : 'Onboarding';
|
|
530
536
|
throw new Error(`${done} could not start: ${error instanceof Error ? error.message : String(error)} Run \`haystack init\` again to start it.`);
|
|
531
537
|
}
|
|
538
|
+
// New notes for an app that is already set up change nothing about its setup (rule 2, amendment 34: each app is set up once).
|
|
539
|
+
// Said in words, and in --json's notices for the coding agent, which otherwise reads "notes: written" as a new onboarding
|
|
540
|
+
// (Codex on langgenius/dify, 2026-10-07).
|
|
541
|
+
if (notesWritten === 'written' && onboarding.state === 'ready') {
|
|
542
|
+
const notice = 'The app is already set up, so these notes do not change its setup: Haystack sets each app up once and keeps the notes.';
|
|
543
|
+
plan.notices.push(notice);
|
|
544
|
+
say(chalk.dim(notice));
|
|
545
|
+
}
|
|
532
546
|
reportOnboardingState(onboarding);
|
|
533
547
|
say(formatOnboarding(onboarding));
|
|
534
548
|
say('');
|
|
@@ -106,6 +106,13 @@ export function parseOnboardingStatus(value, expected) {
|
|
|
106
106
|
invalid('its review');
|
|
107
107
|
if (value.state !== 'ready' && review !== null)
|
|
108
108
|
invalid('its review');
|
|
109
|
+
// Rule 2 (amendment 34): a ready status names the base its record was made at and when it was published.
|
|
110
|
+
const ready = value.state === 'ready';
|
|
111
|
+
if (ready ? !(typeof value.recordBaseCommit === 'string' && COMMIT.test(value.recordBaseCommit)) : value.recordBaseCommit !== null)
|
|
112
|
+
invalid('its record base');
|
|
113
|
+
if (ready ? !(typeof value.recordPublishedAt === 'string' && !Number.isNaN(Date.parse(value.recordPublishedAt)))
|
|
114
|
+
: value.recordPublishedAt !== null)
|
|
115
|
+
invalid('its record time');
|
|
109
116
|
if (value.block !== null)
|
|
110
117
|
parseOnboardingBlock(value.block);
|
|
111
118
|
const checkpoint = value.checkpoint;
|
|
@@ -147,8 +154,8 @@ async function body(response, what) {
|
|
|
147
154
|
throw new OnboardingResponseError(`The onboarding service returned ${what} that is not JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
148
155
|
}
|
|
149
156
|
}
|
|
150
|
-
/** The onboarding of `repository
|
|
151
|
-
*
|
|
157
|
+
/** The onboarding of `repository`, asked at `baseCommit` (rule 2, amendment 34: one setup per repository, the same at every
|
|
158
|
+
* base); with `onboardRunId`, that run's, or the repository's record once it has one: what a waiting command follows. */
|
|
152
159
|
export async function readOnboardingStatus(repository, baseCommit, token, onboardRunId = null) {
|
|
153
160
|
if (!COMMIT.test(baseCommit))
|
|
154
161
|
throw new Error(`Invalid base commit ${baseCommit}.`);
|
|
@@ -159,7 +166,7 @@ export async function readOnboardingStatus(repository, baseCommit, token, onboar
|
|
|
159
166
|
throw await classifyHttpError(response, `Haystack API ${path}`);
|
|
160
167
|
return parseOnboardingStatus(await body(response, 'a status'), { repository, baseCommit });
|
|
161
168
|
}
|
|
162
|
-
/** Rule 12's start POST: onboard
|
|
169
|
+
/** Rule 12's start POST: onboard the repository now, at this base, before any change exists. Idempotent: a
|
|
163
170
|
* ready, blocked or running onboarding is answered as it is. */
|
|
164
171
|
export async function startOnboarding(repository, baseCommit, token) {
|
|
165
172
|
if (!COMMIT.test(baseCommit))
|
|
@@ -198,8 +205,7 @@ export async function waitForOnboarding(first, token, progress, resume) {
|
|
|
198
205
|
await delay(ONBOARDING_READ_EVERY_MS);
|
|
199
206
|
let next;
|
|
200
207
|
try {
|
|
201
|
-
// The run this wait follows,
|
|
202
|
-
// not-started while the run goes on to admit this command's crawl (galaxy's n8n replays, 2026-10-03).
|
|
208
|
+
// The run this wait follows, until the repository has a record.
|
|
203
209
|
next = await readOnboardingStatus(status.repository, status.baseCommit, token, status.onboardRunId);
|
|
204
210
|
}
|
|
205
211
|
catch (error) {
|
|
@@ -282,16 +288,16 @@ export function blockLines(block) {
|
|
|
282
288
|
return lines;
|
|
283
289
|
}
|
|
284
290
|
export function formatOnboarding(status) {
|
|
285
|
-
const lines = [chalk.dim(` Onboarding ${status.onboardRunId ?? '(none)'} of ${safe(status.repository)} at base ${status.baseCommit.slice(0, 12)}`)];
|
|
291
|
+
const lines = [chalk.dim(` Onboarding ${status.onboardRunId ?? '(none)'} of ${safe(status.repository)}, asked at base ${status.baseCommit.slice(0, 12)}`)];
|
|
286
292
|
switch (status.state) {
|
|
287
293
|
case 'ready':
|
|
288
|
-
lines.push(
|
|
294
|
+
lines.push(readyLine(status));
|
|
289
295
|
break;
|
|
290
296
|
case 'onboarding':
|
|
291
297
|
lines.push(onboardingStep(status));
|
|
292
298
|
break;
|
|
293
299
|
case 'not-started':
|
|
294
|
-
lines.push('Onboarding has not started for this
|
|
300
|
+
lines.push('Onboarding has not started for this repository. `haystack init` starts it.');
|
|
295
301
|
break;
|
|
296
302
|
case 'incomplete':
|
|
297
303
|
lines.push(`Onboarding stopped before finishing${status.checkpoint?.error ? `: ${safe(status.checkpoint.error.message)}` : ''}.`
|
|
@@ -319,6 +325,20 @@ export function formatOnboarding(status) {
|
|
|
319
325
|
lines.push('', ...unreviewed.map(note => chalk.yellow(`Note: ${safe(note)}`)));
|
|
320
326
|
return lines.join('\n');
|
|
321
327
|
}
|
|
328
|
+
/** Rule 2 (amendment 34): the repository's one setup, which base it was made at and how long ago, in one sentence. */
|
|
329
|
+
export function readyLine(status, now = Date.now()) {
|
|
330
|
+
if (status.recordBaseCommit === null || status.recordPublishedAt === null)
|
|
331
|
+
return 'The app is onboarded.';
|
|
332
|
+
return `The app is onboarded: its setup was made at base ${status.recordBaseCommit.slice(0, 12)} `
|
|
333
|
+
+ `${age(now - Date.parse(status.recordPublishedAt))} and serves every base.`;
|
|
334
|
+
}
|
|
335
|
+
/** "just now", "5 minutes ago", "3 hours ago", "2 days ago". */
|
|
336
|
+
function age(ms) {
|
|
337
|
+
const minutes = Math.floor(Math.max(0, ms) / 60_000);
|
|
338
|
+
const [count, unit] = minutes < 1 ? [0, ''] : minutes < 60 ? [minutes, 'minute'] : minutes < 2_880 ? [Math.floor(minutes / 60), 'hour']
|
|
339
|
+
: [Math.floor(minutes / 1_440), 'day'];
|
|
340
|
+
return count === 0 ? 'just now' : `${count} ${unit}${count === 1 ? '' : 's'} ago`;
|
|
341
|
+
}
|
|
322
342
|
/** Rule 17 (amendment 32): an onboarding the independent review skipped, as the sentence every result shows; none otherwise. */
|
|
323
343
|
export function reviewNotes(review) {
|
|
324
344
|
if (review?.verdict !== 'skipped')
|
|
@@ -397,7 +417,7 @@ export async function verifyAnswerCommand(questionId, choice, options) {
|
|
|
397
417
|
}
|
|
398
418
|
}
|
|
399
419
|
/** Makes the coding agent's notes the repository's onboarding notes (rule 7, amendment 18), unless they are exactly these
|
|
400
|
-
* already: 'unchanged' then, so running init again with the same notes
|
|
420
|
+
* already: 'unchanged' then, so running init again with the same notes changes no facts. */
|
|
401
421
|
export async function writeOnboardingNotes(repository, notes, token) {
|
|
402
422
|
for (let attempt = 1;; attempt += 1) {
|
|
403
423
|
const facts = await readFacts(repository, token);
|
|
@@ -486,7 +486,7 @@ function printResult(result) {
|
|
|
486
486
|
else if (crawl?.status === 'unavailable')
|
|
487
487
|
console.log(`Crawl unavailable: ${crawlUnavailableText(crawl.reason)}.`);
|
|
488
488
|
else if (crawl?.status === 'onboarding') {
|
|
489
|
-
console.log(`The app is being onboarded
|
|
489
|
+
console.log(`The app is being onboarded (${crawl.onboardRunId}); this change is built and frozen when it is ready.`
|
|
490
490
|
+ ' Run `haystack verify` to check it.');
|
|
491
491
|
}
|
|
492
492
|
else if (crawl?.status === 'onboarding-blocked')
|
package/dist/commands/verify.js
CHANGED
|
@@ -32,7 +32,7 @@ import { GATEWAY_TIMEOUT_MS, gatewayFetch } from './case-batch.js';
|
|
|
32
32
|
import { CRAWL_BRIEF_MAX_FUNCTIONS, CRAWL_BRIEF_MAX_GROUPS, CRAWL_BRIEF_MAX_PRODUCTION_ROWS, CRAWL_BUDGET_MAX_MS, CRAWL_BUDGET_MIN_MS, CRAWL_MAX_FINDINGS, CRAWL_MAX_FINDING_STEPS, CRAWL_MAX_IDEAS, CRAWL_MAX_STAND_IN_LINES, CRAWL_MAX_STAND_IN_ROWS, CRAWL_MAX_TEXT_CHARS, CRAWL_WAIT_MAX_MS, CRAWL_POOLS, } from './crawl-contract.js';
|
|
33
33
|
import { captureCheckout, crawlUnavailableText, EXPLICIT_WALL_MS, normalModeFailure, postPrecomputeCapture, } from './verify-precompute.js';
|
|
34
34
|
import { SPOT_WORDS, TERMINAL, VERDICT_WORDS, VERDICTS, currentStep, errorWords, headline, plural, reportedStatus, results, verifyReport, } from './crawl-report.js';
|
|
35
|
-
import { formatOnboarding, onboardingExitCode, readOnboardingStatus, reportOnboardingState, reviewNotes, standInGapNotes, waitForOnboarding, } from './verify-onboarding.js';
|
|
35
|
+
import { formatOnboarding, onboardingExitCode, readOnboardingStatus, readyLine, reportOnboardingState, reviewNotes, standInGapNotes, waitForOnboarding, } from './verify-onboarding.js';
|
|
36
36
|
import { formatCapture, readPreVerifyCapture } from './capture-brief.js';
|
|
37
37
|
/** A held read (waitAfter): the service's hold, then the time any read gets. */
|
|
38
38
|
const HELD_READ_TIMEOUT_MS = CRAWL_WAIT_MAX_MS + GATEWAY_TIMEOUT_MS;
|
|
@@ -660,11 +660,11 @@ async function submitCapture(capture, token, found) {
|
|
|
660
660
|
line: `${before}, and ${found === null ? 'one' : 'another'} could not be started: ${crawlUnavailableText(crawl.reason)}.` };
|
|
661
661
|
}
|
|
662
662
|
if (crawl.status === 'onboarding') {
|
|
663
|
-
return { runId: null, onboarding: 'onboarding', line: `${before}. The app is not onboarded
|
|
663
|
+
return { runId: null, onboarding: 'onboarding', line: `${before}. The app is not onboarded yet: `
|
|
664
664
|
+ `the service is preparing it (${crawl.onboardRunId}) and runs the crawl when it is ready.` };
|
|
665
665
|
}
|
|
666
666
|
if (crawl.status === 'onboarding-blocked') {
|
|
667
|
-
return { runId: null, onboarding: 'onboarding-blocked', line: `${before}, and the app's onboarding
|
|
667
|
+
return { runId: null, onboarding: 'onboarding-blocked', line: `${before}, and the app's onboarding is blocked.` };
|
|
668
668
|
}
|
|
669
669
|
if (found === null) {
|
|
670
670
|
return { runId: crawl.runId, onboarding: null, line: crawl.status === 'queued'
|
|
@@ -834,9 +834,12 @@ export function formatBrief(brief) {
|
|
|
834
834
|
lines.push(` ${safe(change.changeKey)}: ${safe(change.reason)}`);
|
|
835
835
|
}
|
|
836
836
|
}
|
|
837
|
-
lines.push('', '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):', ' haystack verify --intent "<what you were asked to do>" --idea "<something to try>" [--idea ...]', 'Your ideas are explored first; the ideas above are explored in every crawl too.');
|
|
838
837
|
return lines.join('\n');
|
|
839
838
|
}
|
|
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.'];
|
|
840
843
|
/** `haystack pre-verify` (CRAWL-V1 amendment 18): the brief of the current change, before any crawl. It captures the checkout as
|
|
841
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
|
|
842
845
|
* prints the run's brief. Exit codes: 0 with a brief, 2 when the run ended without one, 3 onboarding blocked, 1 otherwise. */
|
|
@@ -886,7 +889,7 @@ export async function preVerifyCommand(options) {
|
|
|
886
889
|
process.exitCode = onboardingExitCode(onboarding);
|
|
887
890
|
return;
|
|
888
891
|
}
|
|
889
|
-
note(
|
|
892
|
+
note(readyLine(onboarding));
|
|
890
893
|
submitted = await submitCapture(capture, auth.token, found);
|
|
891
894
|
note(submitted.line);
|
|
892
895
|
}
|
|
@@ -920,6 +923,8 @@ export async function preVerifyCommand(options) {
|
|
|
920
923
|
if (!options.json && captured !== null)
|
|
921
924
|
for (const section of captured)
|
|
922
925
|
console.log(`\n${formatCapture(section)}`);
|
|
926
|
+
if (!options.json && brief !== null)
|
|
927
|
+
console.log(STEER_LINES.join('\n'));
|
|
923
928
|
if (brief === null && TERMINAL.has(reportedStatus(view)))
|
|
924
929
|
process.exitCode = 2;
|
|
925
930
|
}
|
|
@@ -981,9 +986,9 @@ export async function verifyCommand(options) {
|
|
|
981
986
|
finishWithOnboarding(onboarding, options, change);
|
|
982
987
|
return;
|
|
983
988
|
}
|
|
984
|
-
// Ready: the service admitted the waiting crawl when the record published
|
|
985
|
-
// submission of the same capture finds it
|
|
986
|
-
note(
|
|
989
|
+
// Ready: the service admitted the waiting crawl when the record published (amendment 12:
|
|
990
|
+
// every waiting request is admitted); this submission of the same capture finds it.
|
|
991
|
+
note(readyLine(onboarding));
|
|
987
992
|
submitted = await submitCapture(capture, auth.token, found);
|
|
988
993
|
note(submitted.line);
|
|
989
994
|
}
|
package/dist/index.js
CHANGED
|
@@ -119,7 +119,9 @@ an hour). The file is JSON with any of three notes, each plain text:
|
|
|
119
119
|
signIn how a person gets an account and signs in, and the kinds of users
|
|
120
120
|
workflow what a signed-in user mainly does, step by step
|
|
121
121
|
Leave out what you do not know. Onboarding still proves everything it takes
|
|
122
|
-
from the notes.
|
|
122
|
+
from the notes. The app is onboarded once: notes written before that feed its
|
|
123
|
+
onboarding (an onboarding that stopped on a question starts again with them);
|
|
124
|
+
after it, new notes start no onboarding.
|
|
123
125
|
|
|
124
126
|
Every run also plans telemetry for the app: --app names it when the repository
|
|
125
127
|
has several (init never picks one), --origin its production origins and
|
|
@@ -180,7 +182,8 @@ your crawl of that exact capture: the same code and the same change title (the
|
|
|
180
182
|
title tells the crawl's judge what the change is). When there is none, or the
|
|
181
183
|
one it finds was cancelled, stopped before finishing or is being cancelled, it
|
|
182
184
|
submits the capture (the service starts the crawl, or runs the stopped one
|
|
183
|
-
again), says so, and follows that crawl.
|
|
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.
|
|
184
187
|
|
|
185
188
|
The coding agent that made the change can say what it was asked to do (--intent:
|
|
186
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
|