Skip to content

api: catch the CLI up to the current routes, and stop failing silently - #107

Merged
hbrooks merged 1 commit into
mainfrom
api/catch-up-to-current-routes
Aug 11, 2026
Merged

api: catch the CLI up to the current routes, and stop failing silently#107
hbrooks merged 1 commit into
mainfrom
api/catch-up-to-current-routes

Conversation

@hbrooks

@hbrooks hbrooks commented Aug 11, 2026

Copy link
Copy Markdown
Member

Summary

Most CLI commands were 404ing against prod. The backend renamed routes under /integrations, /agents, /secrets, and /files, and every path in the CLI was a hand-maintained copy that drifted. agent github repos, agent config list, agent variable list, agent asset list, and agent login were all broken.

Two failures made this worse than it had to be:

  • Errors said nothing. The server moved to {"error": {"code", "message"}}, and we only read {"detail"}, so every failure printed a bare 404 Not Found with the server's actual explanation discarded.
  • The sessions UI failed silently. The composer's repository, config, and model pickers each ended in .catch(() => []), so a broken route rendered an empty list with no indication anything had failed. That is how this was found.

What changed

Routes. Every drifted path repointed, and @ellipsis-dev/sdk bumped to 0.6.0.

before after
/github/*, /slack/*, /linear/teams, /sentry/organizations /integrations/…
/configs, /defaults, /templates /agents/…
/variables /secrets
/assets /files
/cli-auth/* /auth/cli/*

Errors. parseErrorResponse reads the {error: {message}} envelope, and still reads {detail} because FastAPI's own validation and auth rejections answer in that shape.

The footer. Background API failures now show as a red line in the nav hint row. The hints are recoverable from muscle memory; a swallowed error is not.

asset to file. Follows the server, including the response keys ({asset:…} to {file:…}, {assets:[…]} to {files:[…]}). agent asset still works as a hidden alias.

Removed review surface the server deleted (#6108, #6109): pull_request_number is required now, so reviewing your working tree cannot work at all, and the /reviews/defaults ladder was replaced by resolving a pipeline from its committed location. Gone: the local-tree path and its sidecar-branch push, --branch/--config/--model/--budget, and the agent review default group.

Fixed agent review init, which defaulted to agents/code_review.yaml and wrote a file the sync rejects outright. Only code_review.yaml and .ellipsis/code_review.yaml run. It now refuses an illegal path rather than writing a file that looks fine and never executes, and the scaffold drops pull_requests.repositories (a sync error outside the .ellipsis repo) and include_default_reviewers (deleted from a schema that forbids unknown keys).

Test plan

  • bun run typecheck clean, bun run test 436 passing
  • Verified against prod: github repos, file list, integration, slack channels, linear teams, sentry orgs, variable list, session list, me, model list
  • Error text confirmed live: GET /sessions/… failed: 404 Agent session … not found. with a request id, where it previously read 404 Not Found
  • Footer rendered offline in both states: key hints when healthy, red x repositories: … when a picker fails
  • review init verified in a scratch repo: writes both legal paths, refuses agents/code_review.yaml
  • Scaffold validated against the backend's own CodeReviewConfig.assert_valid_for_location at both legal locations, and confirmed the old default is rejected
  • Not run: any command that POSTs. POST /reviews and agent session start are untested here, since exercising them creates real state in prod.

Note

agent config list, agent template list, and agent config default list still return 422 on prod. The public /agents/* routes are shadowed by the legacy dashboard AgentsRouter, which mounts at the same prefix with header auth and is registered first. Not fixable from the CLI; @hbrooks is fixing it backend-side. The paths in this PR are correct and those three commands start working once the shadowing is resolved.

Two pre-existing bugs found while working, left for a follow-up: agent review's stream call passes the crun_… review id to a session endpoint (stage session ids live in stages[]), and prod now serves /files while the published SDK 0.6.0 spec still says /assets, so the SDK needs a republish to match.

Important

Realigns CLI routes with backend refactoring, fixes silent error handling, and removes deprecated review functionality.

Routes updated: Most CLI commands were 404ing because the backend reorganized route namespaces; routes repointed to /integrations/… (GitHub, Slack, Linear, Sentry), /agents/… (configs, defaults, templates), /secrets (variables), /files (assets), and /auth/cli/… (login). @ellipsis-dev/sdk bumped to 0.6.0.

Error reporting improved: parseErrorResponse now reads the new {error: {code, message}} envelope from the server while still supporting {detail} for FastAPI's own validation and auth rejections. Error details are no longer discarded — the server's actual message now appears instead of a bare 404 Not Found.

API failures now visible: The sessions UI's background calls (configs, repos, models pickers) replace the nav hint row with a red error line (e.g., ✗ repositories: 404 Agent session … not found) instead of silently .catch(() => []) into empty lists, making broken routes and expired tokens discoverable.

Asset → File: Response keys renamed (assetfile, assetsfiles, /assets/files). The old agent asset command still works as an alias.

Review functionality removed: The backend deleted support for reviewing uncommitted working trees (which required a sidecar branch push). Removed --branch, --config, --model, --budget options from agent review start; pull-request is now required (no longer optional). Removed the agent review default subcommand.

agent review init hardened: Now refuses paths outside of code_review.yaml and .ellipsis/code_review.yaml (the only two paths the server reads), preventing configs that look correct but never execute. Scaffold updated to remove sync-error fields (pull_requests.repositories, include_default_reviewers).

This description was created by Ellipsis for d5f1b78. It will automatically update as commits are pushed.

Most commands were 404ing against prod: the backend renamed routes under
/integrations, /agents, /secrets, and /files, and every CLI path was a
hand-maintained copy that drifted. Worse, the failures were invisible in the
sessions UI, because the composer's pickers swallowed their errors and rendered
an empty list.

Repoints every drifted path and bumps @ellipsis-dev/sdk to 0.6.0. Error output
now reads the server's {error: {code, message}} envelope, so a failure shows
what went wrong instead of a bare status line; FastAPI's own {detail}
rejections are still read, since validation and auth answer in that shape.

Renames the asset command tree to file, following the server. The old spelling
stays as a hidden alias.

Drops the review surface the server deleted: pull_request_number is required
now, so reviewing your working tree cannot work, and the /reviews/defaults
ladder was replaced by resolving a pipeline from its committed location. That
also fixes review init, which defaulted to agents/code_review.yaml and so wrote
a file the sync rejects outright; the only paths that run are code_review.yaml
and .ellipsis/code_review.yaml.
@hbrooks
hbrooks merged commit 8115cc3 into main Aug 11, 2026
1 check passed

@ellipsis-dev ellipsis-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Changes requested ❌ — 2 issues

Reviewed d5f1b78 in 10 minutes, 29 seconds.
  • Reviewed 1 commit with 1163 lines of code in 25 files
  • Ran 1 review agent producing 2 comments where 2 were posted
  • This pipeline runs no gatekeeper, so findings are posted as written.
  • View full details on ellipsis.dev

This review was created by Ellipsis. You can tag @ellipsis in this pull request.

Comment thread src/ui/SessionsApp.tsx
setPolledOnce(true)
} catch {
// Transient poll failure — keep the previous list; the next tick retries.
setApiError(null)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The sessions poll wipes every reported API error on success, so a composer picker failure is erased within one 5s tick and never comes back — clear only the poll's own error.

poll() runs on mount and every SIDEBAR_POLL_MS (5000) while the nav is shown, and each success calls setApiError(null). The pickers fetch once (pickersLoading.current is never reset), so the failure cannot be re-reported. Verified against prod from this checkout: GET /agents/configs returns 422 while GET /sessions succeeds, so agent shows x agent configs: 422 … for under five seconds and then silently renders an empty config picker — the exact failure this change was written to stop.

Suggested change
setApiError(null)
// Only the poll's own failure is known to be over; a picker's is not.
setApiError((prev) => (prev?.startsWith('sessions: ') ? null : prev))

Comment thread src/commands/review.ts
// Block-and-stream, then re-read: the findings are collected from the
// sandbox at teardown, so they only exist once the review finalizes.
// Same two-step `agent asset get` uses.
// Same two-step `agent file get` uses.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The default agent review <n> path is dead as written: line 96 streams started.id (a crun_…) against /sessions/{id}, which 404s, so the command errors out after creating a real billable review and never prints findings.

Confirmed live against prod: GET /sessions/crun_5Dzhd…404 Agent session crun_5Dzhd… not found. watchSessionStreaming either throws StreamAuthError or degrades to watchSession(), which polls the same 404 and throws — either way api.getReview(started.id) on line 97 is never reached. The PR body defers this as pre-existing, but the effect is that the flagship command exits nonzero on every invocation without --no-wait; the fix is to stream a stage session id from Review.stages[].session_id.

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.

1 participant