Skip to content

refactor(server): move the agent catalog route and type into their own slice - #1690

Merged
devswha merged 2 commits into
mainfrom
refactor/slice-agents
Oct 23, 2026
Merged

devswha merged 2 commits into
mainfrom
refactor/slice-agents

Conversation

@devswha

@devswha devswha commented Oct 22, 2026

Copy link
Copy Markdown
Owner

The next feature slice out of server/index.ts and shared/protocol.ts, after integrations (#1686), plugins (#1687) and background tasks (#1688): the agent catalog route and its type move into their own files. Behaviour, path, status codes and messages stay the same. The plan is .omo/plans/feature-slices-plan.md in the maintainer's workspace.

This slice waited for PR #1597 (merged as 86e0643), which changed this same /api/agents branch. The refactor brief puts a bug fix first and the move after it. The branch moves here exactly as PR #1597 left it, including its on-demand login PATH lookup through the server's shell-agent locator.

This PR moves responsibility, so it is not move-only.

Two commits: the check first, then the move

  1. test(server): pin GET /api/agents before it moves adds server/agents-routes.test.ts.

    • Why it is needed: the existing route coverage is api.contract.test.ts (fallbacks, PATH, sort), which needs a live isolated herdr. server/shell-agent.test.ts covers the locator but not the route.
    • How it runs without herdr, in the unit lane:
      • a real createServer({ port: 0, hostname: "127.0.0.1", stateDir: mkdtempSync(…), …, shellAgents }), given a stand-in locator through createServer's own shellAgents option;
      • herdr's agentManifests stubbed with spyOn(herdr, "agentManifests");
      • PATH pointed at a temp folder that holds only a codex executable, and restored after each test.
    • What it pins:
      • herdr's agents (codex, pi, someagent) are offered, plus Oh My Pi and Claude Code always;
      • the shell agent the locator finds (gjc) is offered and the one it does not find (omo) is not, and the locator is asked about both;
      • each agent has its label (an unknown kind keeps its kind as its label) and its installed flag: true for codex on PATH and for gjc, which the locator found, false for the rest;
      • the order is by label, then kind;
      • herdr's own error passes through (502);
      • a POST answers 400 method_not_allowed.

    On unchanged code it gives 2 pass, 0 fail.

  2. refactor(server): move the agent catalog route and type into their own slice

    • Moved: the branch, unchanged, into handleAgentsRequest(request, pathname, shellAgents): Promise<Response | null> in the new server/agents-routes.ts, the nullable route pattern of the earlier slices.
    • Moved with it: AGENT_LABELS, which only this branch used.
    • The locator stays the server's: index.ts passes its own shellAgents, the one launches use too. The route's type allows only executable, so nothing is constructed, the locator's stop() stays with the server, and startup order does not change.
    • Moved: AgentKind, into the new shared/agents.ts (types only), together with its doc comment ("GET /api/agents: one agent kind herdr can start …"). That comment sat a few declarations away in protocol.ts, above the directory listing type. This is the one line that changes place for a reason other than the move, so the comment now documents the type it describes.
    • Stays in index.ts: one call at the same place in the dispatch order, after the auth, device, update and diagnostics routes and before /api/fs/*. The now-unused agentManifests, SHELL_AGENTS and AgentKind imports leave.
    • Stays in protocol.ts: a type re-export of AgentKind, so server/api.contract.test.ts, src/lib/api.ts, AgentPicker.tsx, NewSessionDialog.tsx, SessionHistory.tsx and WorktreeDialog.tsx compile unchanged.

Checks

  • After the move: HERDR_TEST_MODE=unit bun test server/agents-routes.test.ts server/shell-agent.test.ts src/lib/agentRoster.test.ts server/tasks-routes.test.ts server/startup-order.test.ts gives 26 pass, 0 fail. The pinning test is unchanged between the two commits.
  • --color-moved on the move commit: git diff --color-moved=plain --color-moved-ws=allow-indentation-change HEAD~1 HEAD -- server shared shows 106 lines as moved: the branch (one indent level shallower in its new file), the label table, AgentKind and its comment. The 21 other lines are:
    • in index.ts:
      • the shortened protocol import;
      • the shell-agent.ts import without SHELL_AGENTS;
      • the new agents-routes.ts import;
      • the dropped agentManifests import line;
      • the 2-line call.
    • in the new route file:
      • its 5-line header;
      • 4 imports;
      • the function's doc comment and signature;
      • return null.
    • in protocol.ts: the re-export line.
  • Client imports: bun run typecheck passes on both tsconfigs. No file in src/ or site/ imports shared/agents.ts. shared/agents.ts has no import and no value export.
  • Sizes: server/index.ts goes from 763 to 724 lines and shared/protocol.ts from 1,410 to 1,404. The new modules are 55 and 7 lines.
  • Risks checked:
    • Import cycles: none new. The route imports herdr/client.ts, http.ts and shell-agent.ts, none of which reaches index.ts.
    • Initialization order: unchanged. AGENT_LABELS is a constant, and the locator is created by createServer as before.
  • bun run check fast: passes (unit 6153 pass, 0 fail, 12 skip in 438 files, 8 at a time, 57.5s).
  • CI's integration lane runs the api.contract.test.ts agent cases against an isolated live herdr.

Overlapping open PRs

Open PRs that touch these files: #1598 and #1442 (index.ts and protocol.ts), and #1652 and #1427 (protocol.ts). Each diff was checked for the moved lines and for AgentKind, and none of them changes either one:

No changelog fragment: users see no change.

A unit-lane test through a real createServer, given a stand-in shell-agent
locator (createServer's shellAgents option) and herdr's agent manifests stubbed,
with PATH pointed at a temp folder, so it runs without herdr or the PC's own
agents: herdr's agents plus Oh My Pi and Claude Code, the shell agents the
locator finds, each one's label and installed flag, sorted by label; herdr's
own error passes through, and a non-GET is refused.
…n slice

The next feature slice out of server/index.ts and shared/protocol.ts (plan:
.omo/plans/feature-slices-plan.md). GET /api/agents moves, unchanged and with
the on-demand login PATH lookup PR #1597 gave it, into handleAgentsRequest in
server/agents-routes.ts with AGENT_LABELS, the label table only it used. It is
called at the same place in the dispatch order and given the server's own
shell-agent locator, which launches use too. AgentKind moves into
shared/agents.ts together with its doc comment, which sat on another declaration
in protocol.ts; protocol.ts re-exports the type, so every importer compiles
unchanged.
@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 40d0681 and 3004b87.

📒 Files selected for processing: 5
  • server/agents-routes.test.ts
  • server/agents-routes.ts
  • server/index.ts
  • shared/agents.ts
  • shared/protocol.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review.

📝 Summary

Summary by CodeRabbit

  • New Features
    • The agents list now includes available agent types with clear labels and indicates which ones are installed and ready to use.
    • Agent options are presented in a consistent, alphabetical order.
    • Requests for the agent list now return clearer responses when the request method is unsupported or the service encounters an error.

The change adds a dedicated handler for GET /api/agents, exports the shared AgentKind type, and adds tests for catalog results, Herdr errors, and unsupported methods.

Changes: Agent catalog endpoint

Layer / File(s) Summary
Shared agent-kind contract
shared/agents.ts, shared/protocol.ts
AgentKind is exported from shared/agents.ts and re-exported from shared/protocol.ts. The /api/agents documentation comment is removed.
Catalog handler and server integration
server/agents-routes.ts, server/index.ts, server/agents-routes.test.ts
The handler combines manifest kinds with always-offered and available shell agents, sets installation status, sorts results, and handles errors and non-GET requests. server/index.ts delegates agent requests to the handler. Tests cover the returned catalog, Herdr errors, and method rejection.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Refactor

Suggested reviewers: haeminway1

Merge Risk: ⚪ Minimal · up to 3004b

The agent catalog move appears ready to merge after normal checks; the new test does not use the user’s herdr session by default.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title "refactor(server): move the agent catalog route and type into their own slice" matches the main change: the /api/agents route moves from server/index.ts into server/agents-routes.ts and Agen…
Description check Passed The description follows the template's shape. It has a Change section that explains the move, the behavior kept the same, and the reason for the test-first commit. It has a Validation section that lis…
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.
Full details: Title check

Explanation

The title "refactor(server): move the agent catalog route and type into their own slice" matches the main change: the /api/agents route moves from server/index.ts into server/agents-routes.ts and AgentKind moves into shared/agents.ts. It is specific and conventional-commit formatted. It is slightly long at 76 characters, but it is clear.

Full details: Description check

Explanation

The description follows the template's shape. It has a Change section that explains the move, the behavior kept the same, and the reason for the test-first commit. It has a Validation section that lists the unit test command, the typecheck, the check fast run, and the CI integration lane. It does not link an issue, but the template only requires one for features, and this is a refactor. It does not mention contract-test coverage explicitly for the HTTP change, though it does say api.contract.test.ts runs in CI. The changelog note is present.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@devswha

devswha commented Oct 23, 2026

Copy link
Copy Markdown
Owner Author

Merge-pass review (maintainer-approved merge). CodeRabbit had no actionable comments; a code-review agent also reviewed 3004b87: APPROVE, no blockers.

Behaviour is identical.

  • handleAgentsRequest (server/agents-routes.ts:33-53) matches the old /api/agents branch on main (after fix(agents): share bounded login PATH discovery with shell launch #1597, 86e0643) apart from indentation. AGENT_LABELS matches byte for byte and has no other user.
  • In --color-moved, only 21 lines are not moved: the new file's header, imports, signature and return null, the import edits, the 2-line call and the re-export.
  • The call keeps its place (index.ts:495), after every access, origin, watch and timeout gate. The bridge path list and the /api/machines/local list are untouched.

One locator.

  • index.ts passes the server's own shellAgents (created at :230), the same one launches use (:542), and only the server stops it (:643).
  • The handler can only call executable, so it cannot create a second locator.
  • There is no import cycle, and startup-order.test.ts passes.

Type move. AgentKind moved to shared/agents.ts (types only), re-exported with export type. bun run typecheck passes.

Tests.

  • The four unit test files give 57 pass. The /api/agents cases of api.contract.test.ts, including fix(agents): share bounded login PATH discovery with shell launch #1597's login-shell case, give 4 pass on an isolated herdr session.
  • 15 of 16 handler mutations fail a test.
  • The survivor is sort-by-kind instead of by label: the stubbed agents come out in the same order either way. The sort line moved unchanged and api.contract.test.ts:1296 still checks label order, so it does not block. A test-only follow-up will add agents whose label order differs from their kind order, plus the plain-error 500 case.

No closing keyword before another PR number in the title, body or commits.

@devswha
devswha merged commit 952b9fc into main Oct 23, 2026
17 checks passed
@devswha
devswha deleted the refactor/slice-agents branch October 23, 2026 02:24
devswha added a commit that referenced this pull request Oct 23, 2026
…1694)

The next feature slice out of `server/index.ts` and
`shared/protocol.ts`, after integrations (#1686), plugins (#1687),
background tasks (#1688) and the agent catalog (#1690): the plan route
and its types move into their own files. Behaviour, path, status codes
and messages stay the same. The plan is
`.omo/plans/feature-slices-plan.md` in the maintainer's workspace.

This PR moves responsibility, so it is **not move-only**.

## Two commits: the check first, then the move

1. **`test(server): pin GET /api/pane/plan before it moves`** adds
`server/plan-routes.test.ts`.
- **Why it is needed:** the existing route coverage is live only:
`api.contract.test.ts` (missing pane, wrong method) and
`claude-session.contract.test.ts` (a Claude Code pane's plan). The plan
readers have unit tests (`session-plan.test.ts`,
`session-plan-readers.test.ts`).
- **How it runs without herdr, in the unit lane:** a real
`createServer({ port: 0, hostname: "127.0.0.1", stateDir:
mkdtempSync(…), … })`, with `sessionSnapshot` stubbed through
`spyOn(herdr, "sessionSnapshot")`.
   - **What it pins:**
- a POST answers `400 method_not_allowed`, and a request without
`pane_id` answers `400 missing_pane_id`;
- a pane herdr does not have, and a pane that keeps no plan, both answer
200 `{ plan: null }` with a valid `server_time`;
- when herdr does not answer the snapshot, the route still answers 200
`{ plan: null }` once its 1-second bound (`within(1000, …)`) runs out.
That makes this test take about a second.

   On unchanged code it gives **3 pass, 0 fail**.
2. **`refactor(server): move the plan route and types into their own
slice`**
- **Moved:** the branch, unchanged, into `handlePlanRequest(request,
url, pathname, { omo, claudeAgents, plans }): Promise<Response | null>`
in the new `server/plan-routes.ts`. This is the nullable route pattern
of the earlier slices.
- **The trackers stay the core's:** `index.ts` passes the core's own
`omo` (`OmoStatus`), `claudeAgents` (`ClaudeSubagentStatus`) and `plans`
(`SessionPlans`). The route's type allows only the methods it calls:
`apply`; `ensure`; and `known`, `ensure`, `planOf`. It constructs
nothing, so there is one tracker each as before and startup order does
not change.
- **Moved:** `PlanStep` and `PanePlan`, verbatim with their doc
comments, into the new `shared/plans.ts` (types only).
- **Stays in `protocol.ts`:** `PlanSummary`, because the session
snapshot's pane enrichment and the `pane-status` WebSocket message both
carry it; a re-export would add nothing there. Also a type re-export of
`PlanStep` and `PanePlan`, so `server/session-plan.ts`,
`server/session-plan-reader.ts`,
`server/claude-session.contract.test.ts`, `src/lib/api.ts`,
`src/lib/plan.ts` and its test, `BackgroundTasks.tsx` and
`site/demo/transport.ts` compile unchanged.
- **Stays in `index.ts`:** one call at the same place in the dispatch
order, after the background tasks route and before session history. The
now-unused `within`, `sessionSnapshot`, `HerdrPane` and `PanePlan`
imports leave.

## Checks

- **After the move:** `HERDR_TEST_MODE=unit bun test
server/plan-routes.test.ts server/tasks-routes.test.ts
server/session-plan.test.ts server/session-plan-readers.test.ts
src/lib/plan.test.ts server/startup-order.test.ts` gives **41 pass, 0
fail**. The pinning test is unchanged between the two commits.
- **`--color-moved` on the move commit:** `git diff --color-moved=plain
--color-moved-ws=allow-indentation-change HEAD~1 HEAD -- server shared`
shows 102 lines as moved: the branch (one indent level shallower in its
new file) and both types. The 23 other lines are:
  - in `index.ts`:
    - the shortened protocol import;
    - the dropped `within` and `sessionSnapshot` imports;
    - the new `plan-routes.ts` import;
    - the 2-line call.
  - in the new route file:
    - its 3-line header;
    - 7 imports;
    - the `PlanTrackers` type with its comment;
    - the function's doc comment and signature;
    - `return null`.
  - in `protocol.ts`: the re-export line.
- **Client imports:** `bun run typecheck` passes on both tsconfigs. No
file in `src/` or `site/` imports `shared/plans.ts`. `shared/plans.ts`
has no import and no value export.
- **Sizes:** `server/index.ts` goes from 724 to 704 lines and
`shared/protocol.ts` from 1,404 to 1,381. The new modules are 41 and 24
lines.
- **Risks checked:**
- Import cycles: none new. The route imports `claude-subagents.ts`,
`herdr/client.ts` and `http.ts`, plus types only from `omo-status.ts`
and `session-plan.ts`. None of them reaches `index.ts`, and nothing
comes from `core/`.
  - Initialization order: unchanged.
- `bun run check fast`: passes (unit 6156 pass, 0 fail, 12 skip in 439
files, 8 at a time, 57.9s).
- CI's integration lane runs the `api.contract.test.ts` and
`claude-session.contract.test.ts` plan cases against an isolated live
herdr.

## Overlapping open PRs

Open PRs that touch these files: #1652, #1598, #1442 and #1427. I
checked each diff for the moved lines and for `PlanStep` and `PanePlan`:
- #1652, #1598 and #1442 change neither.
- #1427 changes an import line that names `PanePlan` and `PlanStep`. It
imports them from `protocol.ts`, so the line still resolves through the
re-export.

No changelog fragment: users see no change.
devswha added a commit that referenced this pull request Oct 23, 2026
…#1696)

The last inline feature slice out of `server/index.ts` and
`shared/protocol.ts`, after integrations (#1686), plugins (#1687),
background tasks (#1688), the agent catalog (#1690) and plans (#1694):
the file routes and their types move into their own files. Behaviour,
paths, status codes, headers and messages stay the same. The plan is
`.omo/plans/feature-slices-plan.md` in the maintainer's workspace.

This PR moves responsibility, so it is **not move-only**.

## Two commits: the check first, then the move

1. **`test(server): pin the file routes before they move`** adds
`server/file-routes.test.ts`.
- **Why it is needed:** the existing route coverage is mostly live:
`page-media.contract.test.ts`, `route-envelope.contract.test.ts` and
`device-access.contract.test.ts`. The helpers have unit tests
(`file-view.test.ts`, `project-favicon.test.ts`, `files.test.ts`). In
the unit lane, only `open-access.test.ts` reaches a file route, and only
for the watching-device refusal.
- **How it runs without herdr, in the unit lane:** a real
`createServer({ port: 0, hostname: "127.0.0.1", stateDir:
mkdtempSync(…), … })` reading a temp project folder, with `paneGet`
stubbed through `spyOn(herdr, "paneGet")` where a pane is involved.
   - **What it pins:**
     - **Methods and other sites:**
       - a POST answers `400 method_not_allowed`, and HEAD is allowed;
- another site's `no-cors` read answers `403 cross_site`, while a
top-level navigation is served.
     - **A file by its absolute path:**
       - `/api/fs/stat` answers its name, kind and size;
- `/api/fs/file` answers its bytes, `inline` by default and `attachment`
with `download=1`;
       - a missing file answers `404 not_found`.
- **A relative path in a pane's folder:** with `pane_id`, a relative
path is found in the folder herdr reports for that pane. When herdr
cannot say that folder, the relative path is `404 not_found`, but an
absolute path is still served.
- **The project icon:** `/api/fs/favicon` without `root` answers `400
missing_root`. A folder with `public/favicon.ico` answers that icon, and
a folder without one answers `{ icon: null }`.
- **Page media:** an address never given out answers `404 not_found`,
and a POST answers `400 method_not_allowed`.

   On unchanged code it gives **5 pass, 0 fail**.
2. **`refactor(server): move the file routes and types into their own
slice`**
- **Moved:** both branches, unchanged, into `handleFileRequest(request,
url, pathname, requester): Promise<Response | null>` in the new
`server/file-routes.ts`:
     - `/api/fs/stat`, `/api/fs/file` and `/api/fs/favicon`;
     - `/api/fs/page-media/:media_id`.
- **Moved with them:** `claudeTempFolder`, which only the file read
used.
- **Who asks:** the access gate in `index.ts` already worked out who
asks: `bridgeAuthorized`, `requestHost`, `forwarded`, `client` and
`access`. The route gets those values as they are (`FileRequester`),
because a page's media plays only for the client and device that
rendered it. Nothing is computed again.
- **Shared state stays where it is:** the page-media registry stays in
`file-view.ts`. Sign-out and device revocation still call
`forgetPageMedia` from `index.ts`.
- **Moved:** `FileKind`, `FileInfo` and `ProjectFavicon`, verbatim with
their doc comments, into the new `shared/files.ts` (types only).
- **Stays in `index.ts`:** one call at the same place in the dispatch
order, after the agent catalog and before the workspace routes. Every
gate before it is untouched, including the watching-device refusal of
file reads. The imports only these routes used leave `index.ts`:
`paneContext`, `resolveAgent`, `claudePaneSession`,
`claudeSessionTempDir`, `findProjectFavicon`, `paneGet`,
`isSecureRequest`, the file-view helpers except `forgetPageMedia`, and
`ProjectFavicon`.
- **Stays in `protocol.ts`:** a type re-export of the three names, so
every importer compiles unchanged.

## Checks

- **After the move:** `HERDR_TEST_MODE=unit bun test
server/file-routes.test.ts server/file-view.test.ts
server/project-favicon.test.ts server/files.test.ts
server/open-access.test.ts server/startup-order.test.ts` gives ****71
pass, 0 fail****. The pinning test is unchanged between the two commits.
- **`--color-moved` on the move commit:** `git diff --color-moved=plain
--color-moved-ws=allow-indentation-change HEAD~1 HEAD -- server shared`
shows 168 lines as moved: both branches (one indent level shallower in
their new file), `claudeTempFolder` and the three types. The 26 other
lines are:
  - in `index.ts`:
- the shortened protocol, `auth.ts` and `file-view.ts` imports (each
before and after);
    - the new `file-routes.ts` import;
    - the dropped `paneGet` import line;
    - the 2-line call.
  - in the new route file:
    - its 4-line header;
    - the 6 imports that did not move with the code;
    - the `FileRequester` type with its comment;
    - the function's doc comment and signature;
    - `return null`.
  - in `protocol.ts`: the re-export line.

The imports only the moved code used (`paneContext`/`resolveAgent`,
`claudePaneSession`, `claudeSessionTempDir`, `findProjectFavicon`) show
as moved from `index.ts` into the route file.
- **Client imports:** `bun run typecheck` passes on both tsconfigs. No
file in `src/` or `site/` imports `shared/files.ts`. `shared/files.ts`
has no import and no value export.
- **Sizes:** `server/index.ts` goes from 704 to 657 lines and
`shared/protocol.ts` from 1,381 to 1,353. The new modules are 69 and 29
lines.
- **Risks checked:**
- Import cycles: none new. The route imports `access.ts` (type only),
`auth.ts`, `claude-store.ts`, `conversation.ts`, `file-view.ts`,
`herdr/client.ts`, `http.ts`, `pane-context.ts` and
`project-favicon.ts`. These were all already imported by `index.ts`, and
none of them imports `index.ts`.
  - Initialization order: unchanged. No module state moves.
- `bun run check fast`: passes (unit 6161 pass, 0 fail, 12 skip in 440
files, 8 at a time, 57.4s).
- CI's integration lane runs `page-media.contract.test.ts`,
`route-envelope.contract.test.ts` and `device-access.contract.test.ts`
against an isolated live herdr.

## Overlapping open PRs

Open PRs that touch these files: #1652, #1598, #1442 and #1427. I
checked each diff for the moved lines, the page-media names and the
three file types:
- #1652, #1442 and #1427 change none of them.
- #1598 changes the `bridgePath` list in `index.ts`, which names
`/api/fs/`. That list stays in `index.ts`, and this PR does not touch
it.

No changelog fragment: users see no change.
devswha added a commit that referenced this pull request Oct 23, 2026
…1698)

A test-only follow-up to the background tasks slice (#1688) and the
agent catalog slice (#1690). In their code reviews, the reviewer broke
the moved routes on purpose, one change at a time, to see whether the
route tests would notice. Three of those breakages left every test
passing. This PR adds what those three cases need. No production file
changes.

## `server/tasks-routes.test.ts` (#1688 review, point 3)

The test that calls the route directly with an OmO session now also:
- writes a `dag_1.json` workflow record for that session under the
project's `.omo/senpi-task/dag/runs`, and asserts `runs` is `[["dag_1",
"Bug-fix round", "running"]]` (id, name, status). Before, the fixture
had no workflow, so `runs` was `[]` either way, and returning `runs: []`
from the OmO branch went unnoticed;
- asserts `server_time` on the OmO answer parses as a date. Before, it
was checked only on the non-OmO answer, so dropping it from the OmO
branch went unnoticed.

## `server/agents-routes.test.ts` (#1690 review, L1 and the surviving
sort mutation)

- **Sort order:** the stubbed herdr manifests now also offer `cmd`
(label "Command Code") and `copilot` (label "GitHub Copilot"). Sorted by
label, they land after `codex` and after `gjc`; sorted by kind, `cmd`
comes before `codex` and `copilot` before `gjc`. Sorting by kind instead
of label now fails the test.
- **Error mapping:** a plain error from herdr's agent manifests now pins
`500 internal_error` without the error's own text, next to the existing
`HerdrError` → 502 case.

## Checks

- `HERDR_TEST_MODE=unit bun test server/tasks-routes.test.ts
server/agents-routes.test.ts`: **6 pass, 0 fail**.
- The three breakages from the reviews each fail a test now. I made each
change, ran the two test files, then restored the code:

  | Breakage | Before this PR | Now |
  | --- | --- | --- |
  | OmO branch answers `runs: []` | all tests pass | 1 fail |
  | OmO branch answers without `server_time` | all tests pass | 1 fail |
  | `/api/agents` sorted by kind only | all tests pass | 1 fail |

- `bun run typecheck`: passes.
- `bun run check fast`: passes (unit 6161 pass, 0 fail, 12 skip in 440
files, 8 at a time, 57.5s).

Test-only: no change in `server/` outside the two test files, nor in
`src/` or `shared/`. No changelog fragment: users see no change.
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