Repository navigation
refactor(server): move the plugin routes and types into their own slice - #1687
Conversation
A unit-lane test through a real createServer, with herdr's plugin calls stubbed the way server/http.test.ts stubs paneFind, so it runs without herdr or a plugin registry: the action list (this platform's actions only, no command lines), how a run stands by its log, the request validation before herdr is asked, and the run with no pane, with the named pane's whole context, or a pane not there.
The next feature slice out of server/index.ts and shared/protocol.ts (plan: .omo/plans/feature-slices-plan.md). GET /api/plugins/actions and GET/POST /api/plugin/action move, unchanged, into handlePluginRequest in server/plugin-routes.ts with the three constants only they used, called at the same place in the dispatch order; createServer still passes pluginActionWaitMs. The six plugin action types move verbatim into shared/plugins.ts (types only), and protocol.ts re-exports them, so every existing importer compiles unchanged.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Summary
Merge Risk: ⚪ Minimal · up to
|
|
Merge-pass review. CodeRabbit had no actionable comments; a code-review agent also reviewed it: APPROVE, nothing to fix.
Note for the next slice: the comment at |
…r own slice (#1688) The next feature slice out of `server/index.ts` and `shared/protocol.ts`, after integrations (#1686) and plugins (#1687): the background tasks 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. The agent catalog slice is on hold: the open PR #1597 changes the same `/api/agents` branch, and the refactor brief says the bug fix goes first, then the move. This PR moves responsibility, so it is **not move-only**. ## Three commits: the check first, then the move, then the branch the move made testable 1. **`test(server): pin GET /api/pane/omo-tasks before it moves`** adds `server/tasks-routes.test.ts`. The existing route coverage is live only: `api.contract.test.ts` checks the missing pane and an unknown pane, and `claude-session.contract.test.ts` checks a Claude Code pane's subagents. The parsers have unit tests (`omo-tasks.test.ts`, `claude-subagents.test.ts`). The new test runs the route itself in the unit lane without herdr: a real `createServer({ port: 0, hostname: "127.0.0.1", stateDir: mkdtempSync(…), … })` with `paneGet` stubbed through `spyOn(herdr, "paneGet")`. It pins: - a POST answers `400 method_not_allowed`, and a request without `pane_id` answers `400 missing_pane_id`; - a pane that runs neither OmO nor Claude Code answers 200 with no tasks, no runs and a valid `server_time`, after asking herdr for that pane; - when herdr does not answer that pane lookup, the route still answers 200 with what it knows, 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 background tasks route and types into their own slice`** - **Moved:** the branch, unchanged, into `handleTasksRequest(request, url, pathname, { omo, claudeAgents }): Promise<Response | null>` in the new `server/tasks-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`) and `claudeAgents` (`ClaudeSubagentStatus`). The route's type allows only the methods it calls (`sessionOf`, and `ensure` on the Claude tracker), and it constructs nothing, so there is one tracker each as before and startup order does not change. - **Moved:** `OmoTask`, `OmoRunNode`, `OmoRun` and `OmoActivity`, verbatim with their doc comments, into the new `shared/tasks.ts`. It holds types only. `OmoTaskResult` stays in `protocol.ts`, because it is conversation data. - **Stays in `index.ts`:** one call at the same place in the dispatch order, after the pane routes and before `/api/pane/plan`. The now-unused `processAlive`, `omoTasks`, `omoRuns` and `claudeSubagents` imports leave. `within` stays, because the plan route still uses it. - **Stays in `protocol.ts`:** a type re-export of the four names, so `server/omo-tasks.ts`, `server/claude-subagents.ts`, `server/claude-session.contract.test.ts`, `src/lib/api.ts`, `src/lib/omoTasks.ts` and its test, and `BackgroundTasks.tsx` compile unchanged. - **Also in this commit:** as the CI session asked after #1687, the comment on `createServer`'s `pluginActionWaitMs` option now says `PLUGIN_ACTION_WAIT_MS` lives in `server/plugin-routes.ts`. 3. **`test(server): cover the OmO branch of the tasks route`**, added after CodeRabbit's nitpick. `handleTasksRequest` now takes the trackers as an argument, so the unit lane can call it with a fake OmO tracker that names a session. The session's task record comes back as its task, the Claude tracker is not asked, and another path is not this route's. Rebased onto main after PR #1597 (86e0643) merged: the one conflict was the import block in `server/index.ts`, where PR #1597 renamed the `shell-agent.ts` import; both changes are kept. ## Checks - **After the move:** `HERDR_TEST_MODE=unit bun test server/tasks-routes.test.ts server/omo-tasks.test.ts server/claude-subagents.test.ts src/lib/omoTasks.test.ts server/plugin-routes.test.ts server/shell-agent.test.ts` gives **127 pass, 0 fail** (with the third commit). The pinning test's three cases are unchanged by the move. - **`--color-moved` on the move commit:** `git diff --color-moved=plain --color-moved-ws=allow-indentation-change HEAD~2 HEAD~1 -- server shared` shows 143 lines as moved: the branch (one indent level shallower in its new file), the `omo-tasks.ts` import that moved with it, and the four types. The 23 other lines are: - in `index.ts`: 4 import lines, the `pluginActionWaitMs` comment (before and after), and the 2-line call; - in the new route file: its 5-line header, 4 imports, the `TaskTrackers` type with its comment, the function's doc comment and signature, and `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/tasks.ts`. `shared/tasks.ts` has no import and no value export. - **Sizes:** `server/index.ts` goes from 785 to 763 lines and `shared/protocol.ts` from 1,452 to 1,410. The new modules are 41 and 43 lines. - **Risks checked:** - Import cycles: none new. The route imports `claude-subagents.ts`, `herdr/client.ts`, `http.ts`, `omo-status.ts` and `omo-tasks.ts`, none of which reaches `index.ts`. It imports nothing from `core/`, so the core ownership rule (`core/ownership.test.ts`) holds. - Initialization order: unchanged. The route only reads the trackers it is given. - `bun run check fast` (on the rebased branch): passes (unit 6151 pass, 0 fail, 12 skip in 437 files, 8 at a time, 57.6s). - CI's integration lane runs the `api.contract.test.ts` and `claude-session.contract.test.ts` cases against an isolated live herdr. ## Overlapping open PRs The open PRs that touch these files (#1598 and #1442 in `index.ts` and `protocol.ts`, #1652 and #1427 in `protocol.ts`) do not change the moved lines or these types. The open PR #1597, which edits `index.ts`, does not touch them either. No changelog fragment: users see no change.
…n slice (#1690) 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: - #1598 adds a path to the `bridgePath` list in `index.ts`. That list names `/api/agents`, but it stays in `index.ts` and this PR does not touch it. - #1427 changes an import line in `server/api.contract.test.ts` that names `AgentKind`. That import still resolves through the re-export in `protocol.ts`. No changelog fragment: users see no change.
…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.
…#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.
The next feature slice out of
server/index.tsandshared/protocol.ts, after the integrations pilot (#1686): the plugin action routes and their types move into their own files. Behaviour, paths, status codes and messages stay the same. The plan, with the order and the risks, is.omo/plans/feature-slices-plan.mdin the maintainer's workspace.The plan lists the agent catalog before plugins. It comes after this one because the open fix #1597 changes the same
/api/agentsbranch, and the refactor brief says to fix first, then move.This PR moves responsibility, so it is not move-only.
Two commits: the check first, then the move
test(server): pin the plugin routes before they moveaddsserver/plugin-routes.test.ts. The existing route coverage isserver/plugins.contract.test.ts, which needs a live isolated herdr and a disposable plugin registry, androute-envelope.contract.test.tsfor the gates.plugin-actions.test.tscovers the helpers but not the routes. So the new test runs the routes in the unit lane without herdr: a realcreateServer({ port: 0, hostname: "127.0.0.1", stateDir: mkdtempSync(…), … }), withpluginList,pluginActionList,pluginLogList,pluginActionInvokeand, in one case,sessionSnapshotstubbed throughspyOn(herdr, …), asserver/http.test.tsdoes forpaneFind. It pins:GET /api/plugins/actions:descriptionnull when missing,contexts[]when missing, and no command line in the answer;400 method_not_allowed.GET /api/plugin/action:plugin_idorlog_idis a 400;404 plugin_log_not_found;POST /api/plugin/action, validation before herdr is asked:invalid_json,missing_plugin_id,missing_action_idandinvalid_pane_idare 400s;400 method_not_allowed;POST /api/plugin/action, runs:pluginPaneContext(snapshot, pane);404 pane_not_foundand nothing is invoked.On unchanged code it gives 4 pass, 0 fail.
refactor(server): move the plugin routes and types into their own sliceserver/plugin-routes.ts:handlePluginRequest(request, url, pathname, options): Promise<Response | null>, the nullable route pattern ofworkspace-routes.ts,pane-routes.tsandintegrations-routes.ts;PLUGIN_PLATFORM,PLUGIN_ACTION_WAIT_MSandlivePaneIds.shared/plugins.ts: the six plugin action types (PluginActionContext,PluginAction,PluginActions,PluginActionsResponse,PluginActionRequest,PluginActionResult), verbatim with their doc comments. The file holds types only, with no imports and no values.index.ts: one call at the same place in the dispatch order, after the workspace routes and before the pane routes.createServerstill passes itspluginActionWaitMsoption throughoptions. The access, origin, watch and timeout gates, the/api/machines/localalias allowlist and the machine proxy path list are untouched. The now-unused importsHerdrError,readJsonObject, the four plugin RPCs,PluginInvocationContext,PluginActionsResponseand theplugin-actions.tshelpers leaveindex.ts.protocol.ts: a type re-export of the six names, so every importer compiles unchanged:server/plugin-actions.ts,server/plugins.contract.test.ts,src/lib/api.ts,machineContext.tsx,pluginRun.ts,paletteSearch.ts,CommandPalette.tsx,SettingsDialog.tsxandsite/demo/transport.ts. This PR does not touch them.Checks
HERDR_TEST_MODE=unit bun test server/plugin-routes.test.ts server/plugin-actions.test.ts server/integrations-routes.test.ts src/lib/pluginRun.test.ts src/lib/paletteSearch.test.tsgives 46 pass, 0 fail. The pinning test is unchanged between the two commits.--color-movedon the move commit:git diff --color-moved=plain --color-moved-ws=allow-indentation-change HEAD~1 HEAD -- server sharedshows 265 lines as moved: the three branches (one indent level shallower in their new file), the three constants, both import lines that moved with them, and the six types. The 21 other lines are:index.ts:http.tsimport withoutreadJsonObject;herdr/client.tsnames;plugin-routes.tsimport;herdr/client.tsimport;return null.protocol.ts: the re-export line.bun run typecheckpasses on both tsconfigs. No file insrc/orsite/importsshared/plugins.ts.shared/plugins.tshas no import and no value export.server/index.tsgoes from 854 to 778 lines andshared/protocol.tsfrom 1,503 to 1,452. The new modules are 87 and 52 lines.herdr/client.ts,http.tsandplugin-actions.ts, none of which reachesindex.ts.PLUGIN_PLATFORMreadsprocess.platformas before. The handler constructs nothing.bun run check fast: passes (unit 6135 pass, 0 fail, 12 skip in 436 files, 8 at a time, 57.7s).server/plugins.contract.test.tsandroute-envelope.contract.test.tsagainst an isolated live herdr.Overlapping open PRs
None of the open PRs that touch
server/index.tsorshared/protocol.ts(#1597, #1598, #1652, #1442, #1427) changes the moved lines or the plugin types, so any merge order works.No changelog fragment: users see no change.