Repository navigation
[agent-cli] every caller that quotes a failed eas run reads it with readEasFailure - #127
Conversation
3500b6f to
0f996dc
Compare
|
|
||
| function firstLine(text: string): string { | ||
| return text.trim().split('\n')[0] ?? ''; | ||
| return `${what}: ${easFailureReason(result, result.command)}`; |
There was a problem hiding this comment.
[bug] refusalReason now sends every failure that is not a controller error through easFailureReason. When stderr is only runner lines, that helper says the eas CLI never started and the fix is npm install --save-dev eas-cli. This command is simulator:exec npx agent-device@latest. stdin is not a TTY, so npm logs npm warn exec The following package was not found and will be installed: agent-device@latest and then installs. If the process stops there (the verb deadline sends SIGKILL, and spawnCapture keeps that as exitCode: null), those lines are all stderr has. Before, the reason quoted that line after exited on a signal. Now it says the eas CLI was not delivered. eas had already started. The package still being fetched is agent-device, and pinning eas-cli does not install it.
Suggestion: Keep readEasFailure for a recognised cause and for a real CLI line. On runner-only, if the quoted line names a package other than eas-cli, say that package was still installing. Keep the "eas CLI was not delivered" sentence for a line that is the outer eas-cli install. A unit test with only the agent-device npm warn exec line should not tell the reader to pin eas-cli.
| `Why: "${[easCliLabel(easCli), ...args].join(' ')}" ${describeExit(result.exitCode, result.spawnError)}${ | ||
| quoted ? `: ${quoted}` : '' | ||
| }`, | ||
| `How: check the id with "${easCommandPrefix()} build:list --limit 5 --json --non-interactive", and that this machine is signed in to the account that owns it.`, |
There was a problem hiding this comment.
[suggestion] A recognised failure now puts cause.summary on the Why line. The How line under it is still the old advice: check the build id, and check that this machine is signed in. Before, an unlinked project never reached that summary. The tail of stderr was quoted, and this How was the only next step. Now the Why says the project is not linked and names eas init, and the How still says to check sign-in. That is the wrong next step the summary exists to replace. build:list on an unlinked project fails the same way, so the How sends the reader back into the same error. A signed-out machine is fine, because the summary and this How agree.
Suggestion: When said.kind === 'cause', use said.cause.how as the How line. cloudSessionUnknownError already does that. Leave the build-id How for an unrecognised line.
| `Why: "${[easCliLabel(easCli), ...args].join(' ')}" ${describeExit(result.exitCode, result.spawnError)}.`, | ||
| runnerCrashDetail({ tool: 'eas', exitCode: result.exitCode }, easCliLabel(easCli)), | ||
| `Why: ${runnerNoiseReason({ tool: 'eas', exitCode: result.exitCode }, easCliLabel(easCli), said.runnerLine)}.`, | ||
| `How: run this command again — the install completes once and the next run is warm. "npm install --save-dev eas-cli" pins the CLI into the project, which removes the download from every run.`, |
There was a problem hiding this comment.
we should not recommend to install eas-cli locally. could you help to fix the problem as well?
0f996dc to
8a6e80d
Compare
…eadEasFailure (llp/0021 rules 11 and 14) The build lookup and the fingerprint compare used looksLikeRunnerNoise, which read only the first stderr line. On a cold scratch directory bunx prints first and the EAS CLI writes its error after it, so the guard said the runner did all of it and dropped the EAS line. The session listing and the cloud reload quoted the first stderr line, which is the runner's progress in the same case. The compare quoted the stderr tail. All four now use readEasFailure. looksLikeRunnerNoise and runnerNoiseLine are deleted, and their cases move to the readEasFailure tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8a6e80d to
beebc25
Compare
davidmokos
left a comment
There was a problem hiding this comment.
left one comment inline. this can make status --explain show a dependency warning instead of the error, so let's fix it before merging.
| if (line) { | ||
| return line; | ||
| } | ||
| const said = readEasFailure(result); |
There was a problem hiding this comment.
this can hide the actual error when eas-cli is installed in the project. EAS prints Found eas-cli in your project dependencies. to stderr, and we now pick that over the real error on stdout.
can we filter out these notices first? otherwise status --explain just shows the dependency warning instead of why the lookup failed.
There was a problem hiding this comment.
Fixed in 0e25ce7.
readEasFailure now skips the eas-cli dependency notice: Found eas-cli in your project/monorepo dependencies., the cli.version line, and the Learn more link. The lookup's real error is quoted instead. The notice is quoted only when EAS printed nothing else, as evidence that EAS started. It also strips ANSI codes first, because FORCE_COLOR in our environment reaches eas-cli and colors the notice.
Tests: buildCache-test.ts has your case (the notice on stderr, the error on stdout), and easFailure-test.ts has the colored notice captured from eas-cli 24.12.1 with FORCE_COLOR=1. Both fail without the fix.
On the eas-cli side, expo/eas-cli#4591 stops printing the notice when stderr is not a terminal. We still need this filter for projects that pin an older eas-cli.
…1 rule 11) eas-cli writes "Found eas-cli in your project dependencies." and two more lines to stderr before a command that reads the project, when the project depends on eas-cli. readEasFailure read that notice as the failure, so status --explain showed it instead of the lookup's error on stdout. The notice now yields to every other line. It is quoted only when EAS printed nothing else, as evidence that EAS started. readEasFailure also strips ANSI codes first: FORCE_COLOR in the caller's environment reaches eas-cli, and the colored notice did not match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ssion start and stop (#126) ## What was wrong An EAS Simulator session start through `bunx eas-cli@latest` exited 1, and the report quoted `Resolving dependencies` as what EAS said [observed live, 2026-10-05]. On a cold scratch directory, bunx writes its install progress to stderr before the EAS CLI writes there. So the first line of stderr is the runner's line. This breaks llp/0021 rule 11 ("The runner is not the service"). Each caller that quotes a failed `eas` run reads its output in a different way. Some read the first stderr line, one reads stdout first, and one quotes the tail. The first-line `looksLikeRunnerNoise` guard has the same problem: when EAS writes after the runner, the guard says that the runner printed everything. ## What changes `readEasFailure` in `src/utils/easFailure.ts` reads a failed `eas` run in one way: 1. A recognised EAS sentence (`classifyEasFailure`), with its fix. 2. Else the first stderr line that is not the runner's and is not the CLI's closing `Error: <command> command failed.` line. 3. Else the first stdout line. 4. Else, if only the runner printed, "the runner did not deliver the CLI" (`runnerNoiseReason`). `easFailureReason` writes that as one reason line. In this PR, the session start and the session stop use it. #127, stacked on this PR, moves the other callers and deletes `looksLikeRunnerNoise`. The order uses the two observations. The session start error was on stderr. The `build:list` explanation for an unlinked project was on stdout, with only the generic closing line on stderr. The second commit covers `npx`. On an empty npm cache, `npx --yes eas-cli@latest` writes `npm warn deprecated …` lines before the EAS CLI runs and `npm notice …` lines after it [observed — npm 10.9.4, 2026-10-07]. The runner list matched only `npm warn exec`, so a deprecation warning was quoted as what EAS said. The list now matches every `npm warn` and `npm notice` line. `npm error` stays out, because that is the runner failing. This PR replaces the error-output part of #112. #112 quoted the last 20 lines of stderr, and llp/0021 rule 14 ("A message is not a tail") prohibits that. ## Tests - `src/utils/__tests__/easFailure-test.ts`: each order rule, a recognised sentence after the runner, and the reason text. - `src/dev/__tests__/openAppEas-test.ts`: runner then error, runner only, and runner then a created session. The first and third cases fail on the earlier head of this PR. - Local: typecheck, lint, `bun run format:check`, `bun run test`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Stacked on #126.
What was wrong
looksLikeRunnerNoiseread only the first stderr line. On a cold scratch directory, bunx prints its progress first and the EAS CLI writes its error after it. The guard then said that the runner printed everything, and the EAS line was lost. Two independent reviews of #126 found this.The other callers had their own versions of the same reading:
status --explain(src/impact/buildCache.ts) used the guard.src/impact/compare.ts) used the guard, and otherwise quoted the tail of stderr (rule 14).src/device/cloudSimulator.ts) quoted the first stderr line.src/runtime/reload/cloudReload.ts) quoted the first stderr line.What changes
All four use
readEasFailurefrom #126.looksLikeRunnerNoiseandrunnerNoiseLineare deleted. Their test cases move to thereadEasFailuretests.runnerNoiseReasonnow says "exited on a signal" when there is no exit code.The reload and the listing also get the recognised-sentence answers (
classifyEasFailure), the same as the build lookup.Tests
src/impact/__tests__/buildCache-test.ts"quotes the CLI's line after the runner's progress". It fails on [agent-cli] one reading of a failed eas run, starting with the EAS session start and stop #126 alone.bun run test, and the e2e filescloud-simulator-test dev-eas-test eas-preflight-test eas-runner-test eas-shim-test runtime-reload-test status-installed-test status-test(209 passed).🤖 Generated with Claude Code