Skip to content

Fix stalled run completion and marker handling#61

Draft
aidenybai wants to merge 5 commits intomainfrom
cursor/mock-argument-matching-0ece
Draft

Fix stalled run completion and marker handling#61
aidenybai wants to merge 5 commits intomainfrom
cursor/mock-argument-matching-0ece

Conversation

@aidenybai
Copy link
Copy Markdown
Member

@aidenybai aidenybai commented Mar 29, 2026

Summary

  • parse execution markers as soon as complete lines arrive, including leaked inline markers that get concatenated onto surrounding text, and strip them out of buffered agent text so STEP_* / RUN_COMPLETED surface without leaking into visible output
  • make executor streams emit their initial run state immediately and auto-finish after the terminal-step grace window even if the upstream ACP session never cleanly closes
  • keep CI heartbeat tied to actually printed progress and tighten execution prompts so Playwright snippets are written as plain JavaScript instead of TypeScript-only syntax

Testing

Passed

  • pnpm --filter @expect/shared format -- --check
  • pnpm --filter @expect/supervisor format -- --check
  • pnpm --filter @expect/shared test -- dynamic-steps.test.ts
  • pnpm --filter @expect/shared test -- prompts.test.ts
  • pnpm --filter expect-cli test -- ci-reporter.test.ts
  • pnpm --filter @expect/supervisor lint
  • pnpm build

Existing repo/environment blockers

  • pnpm typecheck fails in @expect/browser because generated runtime files are missing (packages/browser/src/generated/runtime-script, runtime-types)
  • pnpm test fails in @expect/cookies due to environment-dependent browser/cookie expectations in this container
  • pnpm --filter @expect/supervisor test -- executor.test.ts also hits the existing missing packages/browser/src/generated/runtime-script problem when unrelated watch tests load browser code
Open in Web Open in Cursor 

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
expect Ready Ready Preview, Comment Mar 29, 2026 11:28pm

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 29, 2026

Open in StackBlitz

npm i https://pkg.pr.new/expect-cli@61

commit: 0394efb

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

❌ Dogfood Test: failed

Workflow run #17

@github-actions
Copy link
Copy Markdown

❌ Expect tests failed

Workflow run #95

Test output

 �[1m�[36mexpect�[39m�[22m �[2mv0.0.18�[22m  �[2mCI�[22m · �[2mclaude�[22m�[2m · timeout 30m�[22m
::group::expect test execution
file:///home/runner/work/expect/expect/apps/cli/dist/index.js:29
`).pipe(g.catchTag(`PlatformError`,()=>g.void))),n}),_=g.gen(function*(){let e=yield*h(yield*em);return P.join(e,`last-tested`)}),v=g.fn(`Git.loadSavedFingerprint`)(function*(){let t=yield*_;return yield*e.readFileString(t).pipe(g.map(Ce.trim),g.catchTag(`PlatformError`,()=>g.succeed(void 0)))}),y=g.fn(`Git.saveTestedFingerprint`)(function*(){let t=yield*m();if(!t)return;let n=yield*_;yield*e.writeFileString(n,t)});return{withRepoRoot:r,getMainBranch:i,getCurrentBranch:a,isInsideWorkTree:o,getFileStats:c,getChangedFiles:u,getDiffPreview:d,getRecentCommits:f,getCommitSummary:p,getState:g.fn(`Git.getState`)(function*(){if(!(yield*o))return new rn({isGitRepo:!1,currentBranch:`HEAD`,mainBranch:void 0,isOnMain:!1,hasChangesFromMain:!1,hasUnstagedChanges:!1,hasBranchCommits:!1,branchCommitCount:0,fileStats:[],workingTreeFileStats:[],fingerprint:void 0,savedFingerprint:void 0});let[e,t,n,r]=yield*g.all([a,i,m(),v()],{concurrency:`unbounded`}),s=e===t,[l,u,d]=yield*g.all([c(sn.makeUnsafe({_tag:`Changes`,mainBranch:t})),c(sn.makeUnsafe({_tag:`WorkingTree`})),f(`${t}..HEAD`)],{concurrency:`unbounded`});return new rn({isGitRepo:!0,currentBranch:e,mainBranch:t,isOnMain:s,hasChangesFromMain:l.length>0,hasUnstagedChanges:u.length>0,hasBranchCommits:d.length>0,branchCommitCount:d.length,fileStats:l,workingTreeFileStats:u,fingerprint:n,savedFingerprint:r})}),computeFingerprint:m,saveTestedFingerprint:y}})}){static layer=x.effect(this)(this.make).pipe(x.provide(B.layer));static withRepoRoot=t=>{let n=x.effect(em)(g.tryPromise({try:()=>Kp(t).revparse([`--show-toplevel`]),catch:e=>new $p({cause:e})}).pipe(g.map(e=>e.trim())));return x.mergeAll(e.layer.pipe(x.provide(n)),n)}},nm=class extends A.ErrorClass(`@supervisor/ExecutionError`)({_tag:A.tag(`ExecutionError`),reason:A.Union([Pa,Ra,Ia,La])}){displayName=this.reason.displayName??`Browser testing failed`;message=this.reason.message};const rm=(e,t)=>{if(e.allStepsTerminal)return t??Date.now()};var im=class extends j.Service()(`@supervisor/Executor`,{make:g.gen(function*(){let e=yield*Ka,t=yield*tm,n=g.fn(`Executor.gatherContext`)(function*(e){let n=yield*t.getCurrentBranch,r=yield*t.getMainBranch,i=yield*t.getChangedFiles(e),a=yield*t.getDiffPreview(e),o=e._tag===`Branch`||e._tag===`Changes`?`${e.mainBranch}..HEAD`:e._tag===`Commit`?`-1 ${e.hash}`:`HEAD~5..HEAD`,s=yield*t.getRecentCommits(o);return{currentBranch:n,mainBranch:r,changedFiles:i.slice(0,12),recentCommits:s.slice(0,5),diffPreview:a}});return{execute:g.fn(`Executor.execute`)(function*(t){let r=yield*n(t.changesFor),a=no({userInstruction:t.instruction,scope:t.changesFor._tag,currentBranch:r.currentBranch,mainBranch:r.mainBranch,changedFiles:r.changedFiles,recentCommits:r.recentCommits,diffPreview:r.diffPreview,baseUrl:t.baseUrl,isHeadless:t.isHeadless,cookieBrowserKeys:t.cookieBrowserKeys,savedFlow:t.savedFlow,learnings:t.learnings,testCoverage:t.testCoverage}),s=on.makeUnsafe(crypto.randomUUID()),c=P.join(process.cwd(),Jp,`replays`,`${s}.ndjson`),l=new vn({id:s,changesFor:t.changesFor,currentBranch:r.currentBranch,diffPreview:r.diffPreview,fileStats:[],instruction:t.instruction,baseUrl:t.baseUrl?w.some(t.baseUrl):w.none(),isHeadless:t.isHeadless,cookieBrowserKeys:t.cookieBrowserKeys,testCoverage:t.testCoverage?w.some(t.testCoverage):w.none(),title:t.instruction,rationale:`Direct execution`,steps:[]}),u=new Kn({...l,events:[new yn({plan:l})]}),d=[{name:`EXPECT_REPLAY_OUTPUT_PATH`,value:c}];t.liveViewUrl&&d.push({name:o,value:t.liveViewUrl}),t.cookieBrowserKeys.length>0&&d.push({name:i,value:t.cookieBrowserKeys.join(`,`)});let f=new Qn({cwd:process.cwd(),sessionId:w.none(),prompt:a,systemPrompt:w.none(),mcpEnv:d});return yield*g.gen(function*(){let t=yield*D.unbounded(),n=yield*O.make(w.none()),r=e=>D.offer(t,e);yield*r(u);let i=g.gen(function*(){let e=yield*O.get(n);w.isNone(e)||(yield*v.interrupt(e.value),yield*O.set(n,w.none()))}),a=e=>g.gen(function*(){if(e.hasRunFinished||!e.allStepsTerminal){yield*i;return}let a=yield*O.get(n);if(w.isSome(a))return;let o=yield*g.gen(function*(){yield*g.sleep(`120000 millis`),yield*r(e.synthesizeRunFinished()),yield*D.end(t),yield*O.set(n,w.none())}).pipe(g.forkScoped);yield*O.set(n,w.some(o))});return yield*e.stream(f).pipe(M.runFoldEffect({plan:u,allTerminalSince:void 0},(e,n)=>g.gen(function*(){let i=e.plan.addEvent(n),o=rm(i,e.allTerminalSince),s=o!==void 0&&!i.hasRunFinished&&Date.now()-o>=12e4?i.synthesizeRunFinished():i;return yield*r(s),yield*a(s),s.hasRunFinished&&(yield*D.end(t)),{plan:s,allTerminalSince:o}})),g.flatMap(e=>g.gen(function*(){let n=e.plan.finalizeTextBlock(),i=rm(n,e.allTerminalSince)!==void 0&&!n.hasRunFinished?n.synthesizeRunFinished():n;i!==e.plan&&(yield*r(i)),yield*a(i),yield*D.end(t)})),g.catchTag(`AcpStreamError`,e=>D.fail(t,new nm({reason:e}))),g.catchTag(`AcpSessionCreateError`,e=>D.fail(t,new nm({reason:e}))),g.catchTag(`AcpProviderUnauthenticatedError`,e=>D.fail(t,new nm({reason:e}))),g.catchTag(`AcpProviderUsageLimitError`,e=>D.fail(t,new nm({reason:e}))),g.forkScoped),M.fromQueue(t)}).pipe(M.unwrap)},M.unwrap)}})}){static layer=x.effect(this)(this.make).pipe(x.provide(B.layer))},am=class extends j.Service()(`@supervisor/Reporter`,{make:g.gen(function*(){return{report:g.fn(`Reporter.report`)(function*(e){let t=e.events.filter(e=>e._tag===`StepFailed`),n=e.events.filter(e=>e._tag===`StepCompleted`),r=e.events.find(e=>e._tag===`RunFinished`),i=r?r.summary:t.length>0?`${t.length} step${t.length===1?``:`s`} failed, ${n.length} passed`:`${n.length} step${n.length===1?``:`s`} completed`,a=e.events.filter(e=>e._tag===`ToolResult`&&e.toolName.endsWith(`__screenshot`)&&!e.isError).map(e=>e._tag===`ToolResult`?e.result:``).filter(Boolean);return new qn({...e,summary:i,screenshotPaths:a,pullRequest:w.none(),testCoverageReport:e.testCoverage})})}})}){static layer=x.effect(this)(this.make)};const om=e=>{let t=[`format_version: ${e.formatVersion}`,`title: ${JSON.stringify(e.title)}`,`description: ${JSON.stringify(e.description)}`,`slug: ${JSON.stringify(e.slug)}`,`saved_target_scope: ${JSON.stringify(e.savedTargetScope)}`,`saved_target_display_name: ${JSON.stringify(e.savedTargetDisplayName)}`];return e.selectedCommit!==void 0&&t.push(`selected_commit: ${JSON.stringify(e.selectedCommit)}`),t.push(`flow: ${JSON.stringify(e.flow)}`),t.push(`environment: ${JSON.stringify(e.environment)}`),t.join(`
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

TypeError: yield* (intermediate value) is not iterable
    at Object.<anonymous> (file:///home/runner/work/expect/expect/apps/cli/dist/index.js:29:5046)
    at Generator.next (<anonymous>)
    at ~effect/Effect/successCont (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:868:26)
    at ~effect/Effect/evaluate (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/core.js:312:30)
    at FiberImpl.runLoop (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:444:107)
    at FiberImpl.evaluate (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:412:23)
    at file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:719:15
    at file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:695:72
    at process.processTicksAndRejections (node:internal/process/task_queues:104:5)

Node.js v24.14.0

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

✅ Expect tests passed

Workflow run #96

Test output

 �[1m�[36mexpect�[39m�[22m �[2mv0.0.18�[22m  �[2mCI�[22m · �[2mclaude�[22m�[2m · timeout 30m�[22m
::group::expect test execution

 �[1mTest the expect.dev marketing website at http://localhost:3000.   Verify the homepage loads, key sections are visible, and navigation works.   IMPORTANT: Run every test scenario to completion. If a step fails, record the failure   with evidence (screenshot or error) but continue testing remaining steps. Do not bail early.�[22m
[22:44:36.068] INFO (#102): ACP session created { sessionId: 'a1aa5a40-0aff-405b-9af3-31cff6c7fde5' }
[22:44:36.070] DEBUG (#102): ACP stream starting { sessionId: 'a1aa5a40-0aff-405b-9af3-31cff6c7fde5' }
 �[2m◯�[22m �[2mOpen homepage at localhost:3000�[22m
 �[32m✔�[39m Homepage loaded successfully — title "Expect", hero text visible, no console errors �[2m(21s)�[22m
 �[2m◯�[22m �[2mVerify key homepage sections and content�[22m
 �[32m✔�[39m All key homepage sections visible — hero, installation, add-skill, demo illustration �[2m(8s)�[22m
 �[2m◯�[22m �[2mTest theme toggle (light/dark mode)�[22m
 �[32m✔�[39m Theme toggle works — light/dark mode switches correctly with proper aria-pressed state �[2m(16s)�[22m
 �[2m◯�[22m �[2mTest copy buttons for installation commands�[22m
 �[32m✔�[39m Copy buttons work — both commands copy correct text to clipboard �[2m(13s)�[22m
 �[2m◯�[22m �[2mTest "View demo" navigation�[22m
 �[32m✔�[39m "View demo" navigates to /replay?demo=true — replay player loads with 6 steps, playback controls, speed selector, and step navigation �[2m(22s)�[22m
 �[2m◯�[22m �[2mVerify demo replay player functionality�[22m
 �[32m✔�[39m Replay player functional — speed/step controls work. Note: sandboxed iframe missing allow-scripts produces console errors (rrweb replay iframe security restriction) �[2m(23s)�[22m
 �[2m◯�[22m �[2mTest back navigation to homepage�[22m
 �[32m✔�[39m Back navigation works — returns to homepage with hero content visible �[2m(11s)�[22m
 �[2m◯�[22m �[2mTest external links (GitHub and X/Twitter)�[22m
 �[32m✔�[39m External links verified — GitHub and X have correct hrefs with target=_blank, View demo links to /replay?demo=true �[2m(15s)�[22m
 �[2m◯�[22m �[2mRun project healthcheck (pnpm check)�[22m
 �[32m✔�[39m Healthcheck failed — formatting issues in @expect/shared (src/models.ts and tests/dynamic-steps.test.ts) �[2m(12s)�[22m
[22:47:18.526] DEBUG (#103): ACP prompt completed
::endgroup::

 �[1mTests�[22m  �[32m9 passed�[39m �[2m(9)�[22m
 �[1mTime�[22m   2m 25s

📎 Download session recording

@github-actions
Copy link
Copy Markdown

✅ Expect tests passed

Workflow run #97

Test output

 �[1m�[36mexpect�[39m�[22m �[2mv0.0.18�[22m  �[2mCI�[22m · �[2mclaude�[22m�[2m · timeout 30m�[22m
::group::expect test execution

 �[1mTest the expect.dev marketing website at http://localhost:3000.   Verify the homepage loads, key sections are visible, and navigation works.   IMPORTANT: Run every test scenario to completion. If a step fails, record the failure   with evidence (screenshot or error) but continue testing remaining steps. Do not bail early.�[22m
[22:46:25.350] INFO (#102): ACP session created { sessionId: '0daab6f3-ae06-4b9e-995d-feaa625a9db6' }
[22:46:25.351] DEBUG (#102): ACP stream starting { sessionId: '0daab6f3-ae06-4b9e-995d-feaa625a9db6' }
 �[2m◯�[22m �[2mOpen homepage and verify it loads�[22m
 �[32m✔�[39m Homepage loaded successfully with title "Expect", hero section visible with value proposition headline �[2m(1m 42s)�[22m
 �[2m◯�[22m �[2mVerify key sections and navigation elements�[22m
 �[32m✔�[39m All key sections confirmed: hero with animated mockup, installation commands, footer with GitHub/X links and dark/light mode toggle �[2m(904ms)�[22m
 �[2m◯�[22m �[2mTest "View demo" navigation link�[22m
 �[32m✔�[39m "View demo" link navigates correctly to /replay?demo=true, rendering a session replay player with 6 steps in sidebar �[2m(849ms)�[22m
 �[2m◯�[22m �[2mCheck for console errors�[22m
 �[32m✔�[39m No homepage errors; only sandboxed iframe warnings on /replay?demo=true page (expected browser security restrictions, not bugs) �[2m(162ms)�[22m
 �[2m◯�[22m �[2mRun project health check�[22m
 �[32m✔�[39m Test suite run: 4 failed, 168 passed, 6 skipped. Failures are environment-specific (Firefox profiles.ini not present in CI runner, no default browser detected) — not related to the marketing website �[2m(12s)�[22m
[22:48:37.919] DEBUG (#103): ACP prompt completed
::endgroup::

 �[1mTests�[22m  �[32m5 passed�[39m �[2m(5)�[22m
 �[1mTime�[22m   1m 56s

📎 Download session recording

@github-actions
Copy link
Copy Markdown

❌ Expect tests failed

Workflow run #98

Test output

 �[1m�[36mexpect�[39m�[22m �[2mv0.0.18�[22m  �[2mCI�[22m · �[2mclaude�[22m�[2m · timeout 30m�[22m
::group::expect test execution

 �[1mTest the expect.dev marketing website at http://localhost:3000.   Verify the homepage loads, key sections are visible, and navigation works.   IMPORTANT: Run every test scenario to completion. If a step fails, record the failure   with evidence (screenshot or error) but continue testing remaining steps. Do not bail early.�[22m
[22:48:22.101] INFO (#102): ACP session created { sessionId: '96b54d20-a734-4fc2-8ee9-36448740fd98' }
[22:48:22.102] DEBUG (#102): ACP stream starting { sessionId: '96b54d20-a734-4fc2-8ee9-36448740fd98' }
 �[2m◯�[22m �[2mOpen homepage at http://localhost:3000�[22m
�[2m Still running… (2m elapsed)�[22m
�[2m Still running… (3m elapsed)�[22m
�[2m Still running… (4m elapsed)�[22m
�[2m Still running… (5m elapsed)�[22m
�[2m Still running… (6m elapsed)�[22m
[22:54:22.105] WARN (#104): ACP stream inactivity timeout { sessionId: '96b54d20-a734-4fc2-8ee9-36448740fd98' }
::endgroup::
file:///home/runner/work/expect/expect/apps/cli/dist/index.js:29
`).pipe(g.catchTag(`PlatformError`,()=>g.void))),n}),_=g.gen(function*(){let e=yield*h(yield*em);return P.join(e,`last-tested`)}),v=g.fn(`Git.loadSavedFingerprint`)(function*(){let t=yield*_;return yield*e.readFileString(t).pipe(g.map(Ce.trim),g.catchTag(`PlatformError`,()=>g.succeed(void 0)))}),y=g.fn(`Git.saveTestedFingerprint`)(function*(){let t=yield*m();if(!t)return;let n=yield*_;yield*e.writeFileString(n,t)});return{withRepoRoot:r,getMainBranch:i,getCurrentBranch:a,isInsideWorkTree:o,getFileStats:c,getChangedFiles:u,getDiffPreview:d,getRecentCommits:f,getCommitSummary:p,getState:g.fn(`Git.getState`)(function*(){if(!(yield*o))return new rn({isGitRepo:!1,currentBranch:`HEAD`,mainBranch:void 0,isOnMain:!1,hasChangesFromMain:!1,hasUnstagedChanges:!1,hasBranchCommits:!1,branchCommitCount:0,fileStats:[],workingTreeFileStats:[],fingerprint:void 0,savedFingerprint:void 0});let[e,t,n,r]=yield*g.all([a,i,m(),v()],{concurrency:`unbounded`}),s=e===t,[l,u,d]=yield*g.all([c(sn.makeUnsafe({_tag:`Changes`,mainBranch:t})),c(sn.makeUnsafe({_tag:`WorkingTree`})),f(`${t}..HEAD`)],{concurrency:`unbounded`});return new rn({isGitRepo:!0,currentBranch:e,mainBranch:t,isOnMain:s,hasChangesFromMain:l.length>0,hasUnstagedChanges:u.length>0,hasBranchCommits:d.length>0,branchCommitCount:d.length,fileStats:l,workingTreeFileStats:u,fingerprint:n,savedFingerprint:r})}),computeFingerprint:m,saveTestedFingerprint:y}})}){static layer=x.effect(this)(this.make).pipe(x.provide(B.layer));static withRepoRoot=t=>{let n=x.effect(em)(g.tryPromise({try:()=>Kp(t).revparse([`--show-toplevel`]),catch:e=>new $p({cause:e})}).pipe(g.map(e=>e.trim())));return x.mergeAll(e.layer.pipe(x.provide(n)),n)}},nm=class extends A.ErrorClass(`@supervisor/ExecutionError`)({_tag:A.tag(`ExecutionError`),reason:A.Union([Pa,Ra,Ia,La])}){displayName=this.reason.displayName??`Browser testing failed`;message=this.reason.message};const rm=(e,t)=>{if(e.allStepsTerminal)return t??Date.now()};var im=class extends j.Service()(`@supervisor/Executor`,{make:g.gen(function*(){let e=yield*Ka,t=yield*tm,n=g.fn(`Executor.gatherContext`)(function*(e){let n=yield*t.getCurrentBranch,r=yield*t.getMainBranch,i=yield*t.getChangedFiles(e),a=yield*t.getDiffPreview(e),o=e._tag===`Branch`||e._tag===`Changes`?`${e.mainBranch}..HEAD`:e._tag===`Commit`?`-1 ${e.hash}`:`HEAD~5..HEAD`,s=yield*t.getRecentCommits(o);return{currentBranch:n,mainBranch:r,changedFiles:i.slice(0,12),recentCommits:s.slice(0,5),diffPreview:a}});return{execute:g.fn(`Executor.execute`)(function*(t){let r=yield*n(t.changesFor),a=no({userInstruction:t.instruction,scope:t.changesFor._tag,currentBranch:r.currentBranch,mainBranch:r.mainBranch,changedFiles:r.changedFiles,recentCommits:r.recentCommits,diffPreview:r.diffPreview,baseUrl:t.baseUrl,isHeadless:t.isHeadless,cookieBrowserKeys:t.cookieBrowserKeys,savedFlow:t.savedFlow,learnings:t.learnings,testCoverage:t.testCoverage}),s=on.makeUnsafe(crypto.randomUUID()),c=P.join(process.cwd(),Jp,`replays`,`${s}.ndjson`),l=new vn({id:s,changesFor:t.changesFor,currentBranch:r.currentBranch,diffPreview:r.diffPreview,fileStats:[],instruction:t.instruction,baseUrl:t.baseUrl?w.some(t.baseUrl):w.none(),isHeadless:t.isHeadless,cookieBrowserKeys:t.cookieBrowserKeys,testCoverage:t.testCoverage?w.some(t.testCoverage):w.none(),title:t.instruction,rationale:`Direct execution`,steps:[]}),u=new Kn({...l,events:[new yn({plan:l})]}),d=[{name:`EXPECT_REPLAY_OUTPUT_PATH`,value:c}];t.liveViewUrl&&d.push({name:o,value:t.liveViewUrl}),t.cookieBrowserKeys.length>0&&d.push({name:i,value:t.cookieBrowserKeys.join(`,`)});let f=new Qn({cwd:process.cwd(),sessionId:w.none(),prompt:a,systemPrompt:w.none(),mcpEnv:d}),p=yield*D.unbounded(),m=yield*O.make(w.none()),h=e=>D.offer(p,e);yield*h(u);let _=g.gen(function*(){let e=yield*O.get(m);w.isNone(e)||(yield*v.interrupt(e.value),yield*O.set(m,w.none()))}),y=e=>g.gen(function*(){if(e.hasRunFinished||!e.allStepsTerminal){yield*_;return}let t=yield*O.get(m);if(w.isSome(t))return;let n=yield*g.gen(function*(){yield*g.sleep(`120000 millis`),yield*h(e.synthesizeRunFinished()),yield*D.end(p),yield*O.set(m,w.none())}).pipe(g.forkScoped);yield*O.set(m,w.some(n))});return yield*e.stream(f).pipe(M.runFoldEffect(()=>({plan:u,allTerminalSince:void 0}),(e,t)=>g.gen(function*(){let n=e.plan.addEvent(t),r=rm(n,e.allTerminalSince),i=r!==void 0&&!n.hasRunFinished&&Date.now()-r>=12e4?n.synthesizeRunFinished():n;return yield*h(i),yield*y(i),i.hasRunFinished&&(yield*D.end(p)),{plan:i,allTerminalSince:r}})),g.flatMap(e=>g.gen(function*(){let t=e.plan.finalizeTextBlock(),n=rm(t,e.allTerminalSince)!==void 0&&!t.hasRunFinished?t.synthesizeRunFinished():t;n!==e.plan&&(yield*h(n)),yield*y(n),yield*D.end(p)})),g.catchTags({AcpStreamError:e=>D.fail(p,new nm({reason:e})),AcpSessionCreateError:e=>D.fail(p,new nm({reason:e})),AcpProviderUnauthenticatedError:e=>D.fail(p,new nm({reason:e})),AcpProviderUsageLimitError:e=>D.fail(p,new nm({reason:e}))}),g.forkScoped),M.fromQueue(p)},M.unwrap)}})}){static layer=x.effect(this)(this.make).pipe(x.provide(B.layer))},am=class extends j.Service()(`@supervisor/Reporter`,{make:g.gen(function*(){return{report:g.fn(`Reporter.report`)(function*(e){let t=e.events.filter(e=>e._tag===`StepFailed`),n=e.events.filter(e=>e._tag===`StepCompleted`),r=e.events.find(e=>e._tag===`RunFinished`),i=r?r.summary:t.length>0?`${t.length} step${t.length===1?``:`s`} failed, ${n.length} passed`:`${n.length} step${n.length===1?``:`s`} completed`,a=e.events.filter(e=>e._tag===`ToolResult`&&e.toolName.endsWith(`__screenshot`)&&!e.isError).map(e=>e._tag===`ToolResult`?e.result:``).filter(Boolean);return new qn({...e,summary:i,screenshotPaths:a,pullRequest:w.none(),testCoverageReport:e.testCoverage})})}})}){static layer=x.effect(this)(this.make)};const om=e=>{let t=[`format_version: ${e.formatVersion}`,`title: ${JSON.stringify(e.title)}`,`description: ${JSON.stringify(e.description)}`,`slug: ${JSON.stringify(e.slug)}`,`saved_target_scope: ${JSON.stringify(e.savedTargetScope)}`,`saved_target_display_name: ${JSON.stringify(e.savedTargetDisplayName)}`];return e.selectedCommit!==void 0&&t.push(`selected_commit: ${JSON.stringify(e.selectedCommit)}`),t.push(`flow: ${JSON.stringify(e.flow)}`),t.push(`environment: ${JSON.stringify(e.environment)}`),t.join(`
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

nm [@supervisor/ExecutionError]: Streaming failed: Agent produced no output for 180s — the agent may be stalled
    at Object.AcpStreamError (file:///home/runner/work/expect/expect/apps/cli/dist/index.js:29:4746)
    at file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:1279:46
    at ~effect/Utils/internal (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/Utils.js:69:12)
    at file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:1279:11
    at file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:1266:29
    at ~effect/Utils/internal (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/Utils.js:69:12)
    at Object.~effect/Effect/failureCont (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:1266:10)
    at ~effect/Effect/evaluate (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/core.js:340:30)
    at FiberImpl.runLoop (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:444:107)
    at FiberImpl.evaluate (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:412:23) {
  reason: Pa [AcpStreamError]: Streaming failed: Agent produced no output for 180s — the agent may be stalled
      at Array.<anonymous> (file:///home/runner/work/expect/expect/apps/cli/dist/index.js:9:17373)
      at Generator.next (<anonymous>)
      at ~effect/Effect/successCont (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:868:26)
      at ~effect/Effect/evaluate (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/core.js:312:30)
      at FiberImpl.runLoop (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:444:107)
      at FiberImpl.evaluate (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:412:23)
      at file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:719:15
      at Timeout._onTimeout (file:///home/runner/work/expect/expect/node_modules/.pnpm/effect@4.0.0-beta.35/node_modules/effect/dist/internal/effect.js:2417:39)
      at listOnTimeout (node:internal/timers:605:17)
      at process.processTimers (node:internal/timers:541:7) {
    _tag: 'AcpStreamError',
    displayName: 'An unexpected error occurred while streaming',
    [cause]: 'Agent produced no output for 180s — the agent may be stalled'
  },
  _tag: 'ExecutionError',
  displayName: 'An unexpected error occurred while streaming'
}

Node.js v24.14.0

📎 Download session recording

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

✅ Expect tests passed

Workflow run #100

Test output

 �[1m�[36mexpect�[39m�[22m �[2mv0.0.18�[22m  �[2mCI�[22m · �[2mclaude�[22m�[2m · timeout 30m�[22m
::group::expect test execution

 �[1mTest the expect.dev marketing website at http://localhost:3000.   Verify the homepage loads, key sections are visible, and navigation works.   IMPORTANT: Run every test scenario to completion. If a step fails, record the failure   with evidence (screenshot or error) but continue testing remaining steps. Do not bail early.�[22m
[23:29:50.316] INFO (#102): ACP session created { sessionId: 'a32d8338-bdd0-466d-8df4-9c7c06082dec' }
[23:29:50.317] DEBUG (#102): ACP stream starting { sessionId: 'a32d8338-bdd0-466d-8df4-9c7c06082dec' }
 �[2m◯�[22m �[2mOpen homepage at http://localhost:3000�[22m
�[2m Still running… (2m elapsed)�[22m
 �[32m✔�[39m Homepage loads at http://localhost:3000 with title "Expect" and all content visible �[2m(2m 55s)�[22m
 �[32m✔�[39m Key sections verified: hero with animated mockup, headline, subtext, installation commands, CTA button, nav links, light/dark toggle
 �[32m✔�[39m Navigation works: "View demo" navigates to /replay?demo=true with full session replay viewer
 �[32m✔�[39m Interactive elements work: light/dark toggle, copy buttons, replay playback controls, step navigation
 �[32m✔�[39m Mobile layout verified at 375px width — all sections render correctly
[23:32:52.099] DEBUG (#103): ACP prompt completed
::endgroup::

 �[1mTests�[22m  �[32m1 passed�[39m �[2m(1)�[22m
 �[1mTime�[22m   2m 55s

📎 Download session recording

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants