Skip to content

feat(flows): fix large asset downloads and add per-file progress - #1459

Merged
Chase J (chajac) merged 8 commits into
mainfrom
asset-download-progress
Aug 12, 2026
Merged

feat(flows): fix large asset downloads and add per-file progress#1459
Chase J (chajac) merged 8 commits into
mainfrom
asset-download-progress

Conversation

@chajac

@chajac Chase J (chajac) commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Note

PR body AI drafted & edited as needed

Overview of Changes

flows pull failed on environments that have large team-storage assets. Each download had a fixed 30-second deadline. A 1.4 GB asset could not finish in that time, so the pull always stopped with a timeout error. The user also could not see how many files remained during a pull.

  • src/shell/platform/fetchSignedUrl.ts: the download now uses a stall timeout in place of a whole-download deadline. The 30-second timer restarts each time data arrives. A slow download that makes progress can finish at any size. A download that receives no data for 30 seconds still fails. Error classification does not change.
  • fetchSignedUrl.ts with a new Fs.openWriteHandle primitive: the download writes each chunk to a .part file. The CLI renames the file to its final name when the download completes. Before, the CLI held the full body in memory and briefly needed about two times the file size. A failed download removes the partial file. The stall timer stops while a chunk writes to disk. Because of this, a slow disk cannot cause a false stall. A measured 1.5 GB pull now uses a maximum of about 290 MB of memory. Before, it used 3.35 GB.
  • describeErrors.ts / messages/auth.ts: the timeout messages now say that the download stalled and show the stall time. A download can now run longer than 30 seconds before it fails, so the old "timed out after 30s" text was not correct.
  • shell/ui withProgress: each task now receives an update(message) callback. Human mode replaces the spinner label with each new message. If a task fails, the error line keeps the last message. Verbose mode logs each message as a step line. Agent mode writes one line to stderr for each message. The json output does not change. Tasks that ignore the callback do not change.
  • writeAssetSnapshot.ts / createPlatformClient.ts / pull handler: the download loop sends progress events to the progress step. The step shows "Downloading team-storage assets (2/45)". The total counts only the files that download. Reused and skipped files are not included.
image

Testing

bun run test
bun run typecheck
bun run lint
bun run format:check
bun run knip
  • Each layer has new tests, and each test was written before its code. The tests cover stall detection, slow downloads that finish, disk-write failures, partial-file removal, the write-handle contract, progress counts that exclude reused files, message updates in the three UI modes, and the pull handler wiring.
  • An end-to-end pull against a real environment retrieved 138 flows and 45 assets (1.5 GB in total). This included a 1.4 GB asset that always failed before. The counter moved from (1/45) to (45/45). Peak memory stayed below 300 MB.

This is the /usr/bin/time -l output for the streamed 1.5 GB pull:

47.34 real         6.95 user         2.82 sys
           298893312  maximum resident set size
                   0  average shared memory size
                   0  average unshared data size
                   0  average unshared stack size
               18579  page reclaims
                  91  page faults
                   0  swaps
                   0  block input operations
                   0  block output operations
                 101  messages sent
               42418  messages received
                   0  signals received
                 653  voluntary context switches
              200519  involuntary context switches
         43581930183  instructions retired
         23251474162  cycles elapsed
           254045944  peak memory footprint

Checklist

  • Changes follow the code style of this project
  • Self-review completed
  • Tests added/updated
  • No breaking changes

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The change adds per-file progress callbacks for team-storage asset downloads and passes progress messages through the pull handler to human and agent renderers. JSON output remains unchanged. Signed-URL downloads now use a 30-second no-data stall timeout, stream response chunks into temporary files, and clean up failed downloads. Filesystem write handles and in-memory filesystem coverage support the streaming implementation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullHandler
  participant PlatformClient
  participant writeAssetSnapshot
  participant fetchSignedUrl
  participant Renderer
  PullHandler->>PlatformClient: syncTeamStorageAssets(onProgress)
  PlatformClient->>writeAssetSnapshot: download assets
  writeAssetSnapshot->>fetchSignedUrl: fetch signed URL
  fetchSignedUrl-->>writeAssetSnapshot: persist downloaded asset
  writeAssetSnapshot-->>PlatformClient: current and total counts
  PlatformClient-->>PullHandler: progress callback
  PullHandler->>Renderer: update progress message
Loading

Suggested reviewers: smonn, gorangajic

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits, uses an allowed type and scope, uses imperative wording, and clearly describes the download and progress changes.
Description check ✅ Passed The description includes the required overview, testing commands and results, checklist, implementation details, and validation evidence.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch asset-download-progress

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/shell/platform/fetchSignedUrl.ts`:
- Around line 72-97: Update the download flow around the response body reader to
write each received chunk directly to a temporary destination file instead of
accumulating chunks and constructing a second full-size Uint8Array. After all
reads and the write complete, rename the temporary file to args.dest; ensure
timeout, network, and write failures clean up the temporary file and preserve
their existing error results.

In `@src/shell/platform/teamStorageAssets.test.ts`:
- Line 59: Remove the duplicate declarations causing compilation failures: in
src/shell/platform/teamStorageAssets.test.ts lines 59-59 and
src/shell/platform/teamStorageAssets.reuse.test.ts lines 74-74, retain only one
const progress declaration in each test; in
src/domains/flows/pull/handler.test.ts lines 151-151, retain only one onProgress
property in the options type.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5ad91122-5294-482d-ad61-ead37154ce28

📥 Commits

Reviewing files that changed from the base of the PR and between d6f68cf and 8680389.

📒 Files selected for processing (23)
  • .changeset/asset-download-progress-counter.md
  • .changeset/stall-timeout-signed-url-downloads.md
  • src/core/messages/auth.ts
  • src/core/messages/flows.ts
  • src/domains/flows/pull/handler.test.ts
  • src/domains/flows/pull/handler.ts
  • src/shell/platform/createPlatformClient.ts
  • src/shell/platform/describeErrors.test.ts
  • src/shell/platform/describeErrors.ts
  • src/shell/platform/fetchSignedUrl.test.ts
  • src/shell/platform/fetchSignedUrl.ts
  • src/shell/platform/slowFetch.testUtils.ts
  • src/shell/platform/teamStorageAssets.reuse.test.ts
  • src/shell/platform/teamStorageAssets.test.ts
  • src/shell/platform/teamStorageAssets.ts
  • src/shell/platform/writeAssetSnapshot.ts
  • src/shell/ui/renderers/modes/agent.test.ts
  • src/shell/ui/renderers/modes/agent.ts
  • src/shell/ui/renderers/modes/human.ts
  • src/shell/ui/renderers/modes/human.withProgress.update.test.ts
  • src/shell/ui/renderers/modes/json.test.ts
  • src/shell/ui/renderers/modes/json.ts
  • src/shell/ui/renderers/modes/progress.ts

Comment thread src/shell/platform/fetchSignedUrl.ts Outdated
Comment thread src/shell/platform/teamStorageAssets.test.ts
@chajac
Chase J (chajac) marked this pull request as ready for review August 11, 2026 12:25
@chajac Chase J (chajac) changed the title feat(flows): stall timeout and per-file progress for downloads feat(flows): fix large asset downloads and add per-file progress Aug 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/shell/fs.ts`:
- Around line 99-101: Update the async write method to loop until the entire
chunk has been written, advancing by FileHandle.write()’s bytesWritten result
and retrying the unwritten suffix. If any write reports zero bytes, fail instead
of accepting the next chunk, while preserving sequential chunk processing.

In `@src/shell/platform/fetchSignedUrl.ts`:
- Around line 75-79: Abort the active fetch before returning from both local
filesystem failure handlers in fetchSignedUrl.ts:
src/shell/platform/fetchSignedUrl.ts lines 75-79 and 103-108. In each catch
block, call the existing controller.abort with the caught error, then preserve
the current failure result.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cf3e979d-4995-459d-a6a1-648903944a95

📥 Commits

Reviewing files that changed from the base of the PR and between 8680389 and 668966e.

📒 Files selected for processing (9)
  • .changeset/stream-signed-url-downloads.md
  • src/shell/fs.testUtils.dirTree.test.ts
  • src/shell/fs.testUtils.syncAndStreams.test.ts
  • src/shell/fs.testUtils.test.ts
  • src/shell/fs.testUtils.ts
  • src/shell/fs.ts
  • src/shell/memoryFsTree.testUtils.ts
  • src/shell/platform/fetchSignedUrl.test.ts
  • src/shell/platform/fetchSignedUrl.ts
💤 Files with no reviewable changes (1)
  • src/shell/fs.testUtils.test.ts

Comment thread src/shell/fs.ts Outdated
Comment thread src/shell/platform/fetchSignedUrl.ts
@chajac
Chase J (chajac) requested a review from a team August 11, 2026 14:15

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see anything worth raising here, but I'm not an domain expert here so might as well request for another pair of eyes on this one

Comment thread src/shell/platform/fetchSignedUrl.ts
# Conflicts:
#	src/shell/platform/describeErrors.test.ts
@chajac
Chase J (chajac) merged commit 47c7ea0 into main Aug 12, 2026
6 of 7 checks passed
@chajac
Chase J (chajac) deleted the asset-download-progress branch August 12, 2026 10:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/shell/platform/describeErrors.ts (1)

12-30: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Preserve errorBody in pull failures

At src/domains/flows/pull/fetchPhase.ts:27,36 and src/domains/flows/pull/handler.ts:108, new Error(result.error) discards result.errorBody. The command context renders errorBody only for returned failures, so server-provided reasons are lost. Propagate both fields to the command boundary or include both values in the thrown error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shell/platform/describeErrors.ts` around lines 12 - 30, Preserve
server-provided error details in pull failures by updating the fetch phase and
pull handler paths that currently throw new Error(result.error). Propagate
result.errorBody alongside result.error to the command boundary, or include both
values in the thrown error so returned failures retain the original reason.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/shell/platform/describeErrors.ts`:
- Around line 12-30: Preserve server-provided error details in pull failures by
updating the fetch phase and pull handler paths that currently throw new
Error(result.error). Propagate result.errorBody alongside result.error to the
command boundary, or include both values in the thrown error so returned
failures retain the original reason.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 93aa56a6-ce0e-4696-bbb3-82944b59d873

📥 Commits

Reviewing files that changed from the base of the PR and between 16d36f0 and 18ccd88.

📒 Files selected for processing (2)
  • src/shell/platform/describeErrors.test.ts
  • src/shell/platform/describeErrors.ts

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants