Skip to content

feat(cli): migrate sequence + routes to thin IPC wrappers#30241

Merged
noanflaherty merged 1 commit into
mainfrom
cli-ipc-migration/pr-7-sequence-routes
May 11, 2026
Merged

feat(cli): migrate sequence + routes to thin IPC wrappers#30241
noanflaherty merged 1 commit into
mainfrom
cli-ipc-migration/pr-7-sequence-routes

Conversation

@noanflaherty
Copy link
Copy Markdown
Contributor

@noanflaherty noanflaherty commented May 11, 2026

Summary

  • Migrate sequence and routes CLI commands to thin IPC wrappers
  • Create sequence-routes.ts and user-routes-cli.ts route files
  • Update COMMAND_INVENTORY.md

Part of plan: cli-ipc-migration.md (PR 7 of 11)


Open in Devin Review

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd85eacf2a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +152 to +156
const basePath = join(routesDir, routePath);

for (const ext of HANDLER_EXTENSIONS) {
const candidate = `${basePath}${ext}`;
if (existsSync(candidate)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Block path traversal in user_routes_inspect resolver

resolveHandlerFile() joins routePath directly onto routesDir without a containment check, so a caller can pass values like ../../runtime/routes/index and make user_routes_inspect read/import files outside /workspace/routes. In this migration the handler now runs inside the daemon and is exposed through shared routes, so this becomes a server-side path traversal/import primitive rather than a local CLI-only behavior; mirror the dispatcher’s resolve(...).startsWith(resolve(routesDir)) guard before probing candidates.

Useful? React with 👍 / 👎.

Comment on lines +206 to +209
operationId: "sequence_list",
method: "POST",
endpoint: "sequences/list",
handler: handleSequenceList,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Register route policy for new sequence endpoints

These new shared sequences/* routes are added without policyKey overrides and there are no corresponding registerPolicy(...) entries for derived keys like sequences/list in runtime/auth/route-policy.ts, so HttpRouter treats them as unprotected (enforcePolicy no-ops on missing policy). This also violates the route-policy coverage guard (runtime/auth/__tests__/guard-tests.test.ts) that requires each dispatched endpoint to have a policy mapping.

Useful? React with 👍 / 👎.

Comment on lines +223 to +226
operationId: "user_routes_list",
method: "GET",
endpoint: "user-routes/list",
handler: handleUserRoutesList,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add policy mapping for user-routes CLI HTTP endpoints

The new user-routes/list and user-routes/inspect route definitions also lack policy mapping, so any authenticated principal can hit these endpoints regardless of intended scope/profile, and the route-policy coverage guard will report missing policies for these derived keys. Add explicit policyKey values and matching entries in runtime/auth/route-policy.ts (or register the derived keys directly) before exposing them through the shared route table.

Useful? React with 👍 / 👎.

@noanflaherty noanflaherty merged commit ede6758 into main May 11, 2026
9 of 13 checks passed
@noanflaherty noanflaherty deleted the cli-ipc-migration/pr-7-sequence-routes branch May 11, 2026 02:14
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 3 potential issues.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +109 to +112
const r = await cliIpcCall<{ sequences: SequenceSummary[] }>(
"sequence_list",
params,
);
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.

🔴 CLI passes IPC params at top level but route handlers read from body, breaking all parameterized commands

All parameterized IPC calls in sequence.ts and routes.ts pass flat params (e.g., cliIpcCall("sequence_pause", { id })) but the shared route handlers destructure { body = {} } from RouteHandlerArgs and parse body with Zod. The IPC server (assistant-server.ts:346-350) spreads req.params as top-level RouteHandlerArgs fields via injectLocalActorHeader (assistant-server.ts:584-587), never wrapping them in a body property. So body is always undefined → defaults to {} → Zod parse fails for required fields (id, path, key/value, enrollmentId) and silently ignores optional fields (status filter in sequence_list).

Affected commands and their failure modes
  • sequence list --status active → status filter silently ignored (returns all sequences)
  • sequence get <id> → Zod error: id required
  • sequence pause <id> → Zod error: id required
  • sequence resume <id> → Zod error: id required
  • sequence cancel-enrollment <id> → Zod error: enrollmentId required
  • sequence guardrails set <key> <value> → Zod error: key/value required
  • routes inspect <path> → Zod error: path required
Prompt for agents
The CLI passes IPC params as flat objects (e.g. { id: "xxx" }) but the shared route handlers read from the body field of RouteHandlerArgs. The IPC adapter in assistant-server.ts (injectLocalActorHeader) casts params directly to RouteHandlerArgs without wrapping them in body.

Either:
1. Wrap the params in body on the CLI side for all calls: cliIpcCall("sequence_pause", { body: { id } }) — check what convention existing working THIN commands use (e.g. task commands, avatar commands).
2. OR modify injectLocalActorHeader in assistant-server.ts to automatically place non-RouteHandlerArgs keys into body.

This affects all parameterized calls in assistant/src/cli/commands/sequence.ts (sequence_list, sequence_get, sequence_pause, sequence_resume, sequence_cancel_enrollment, sequence_guardrails_set) and assistant/src/cli/commands/routes.ts (user_routes_inspect).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +5 to +6
* discovery and inspection endpoints for CLI consumption. The filesystem
* scanning logic that was previously in the CLI command is now here.
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.

🔴 Comment references removed code, violating mandatory AGENTS.md rule

The module comment at user-routes-cli.ts:6 says "The filesystem scanning logic that was previously in the CLI command is now here." This uses the phrase "was previously in" to narrate history, which violates the mandatory rule in assistant/AGENTS.md: "do not reference code that has been removed … Avoid phrases like 'no longer does X', 'previously used Y', or 'was removed in PR Z'." Comments should describe the current state only.

Suggested change
* discovery and inspection endpoints for CLI consumption. The filesystem
* scanning logic that was previously in the CLI command is now here.
* discovery and inspection endpoints for CLI consumption. Contains the
* filesystem scanning and module-loading logic for route discovery.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +221 to +231
export const ROUTES: RouteDefinition[] = [
{
operationId: "user_routes_list",
method: "GET",
endpoint: "user-routes/list",
handler: handleUserRoutesList,
summary: "List user-defined route handlers",
description:
"Scan workspace routes directory for handler files and return discovered routes with methods and public URLs.",
tags: ["user-routes"],
},
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.

🚩 GET handler user_routes_list executes dynamic imports which have potential side effects

The handleUserRoutesList handler is registered as a GET route (method: "GET") but internally calls discoverRoutes()inspectModule()await import(filePath), which executes arbitrary user-authored code. The assistant/src/runtime/AGENTS.md states "GET handlers must be safe and side-effect-free." Dynamic imports of user code can theoretically produce side effects (file writes, network calls). However, the import is purely for inspection (detecting exported HTTP methods and descriptions), and this exact logic existed in the old CLI code. The risk is low since user route handlers are already trusted code in the workspace. A POST method might be more semantically appropriate given the import side effects, but this is a judgment call rather than a clear bug.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

noanflaherty pushed a commit that referenced this pull request May 11, 2026
)

The CLI IPC refactor PRs (#30238#30247) added new shared routes without
matching policy entries in route-policy.ts. The route-policy coverage
guard test fails on main with 29 missing endpoints:

  - audit, auth/info
  - conversations/cli/{list,create,export,clear}
  - inference/send
  - internal/mcp/{list,add,remove}
  - oauth/apps.upsert, oauth/apps/lookup
  - oauth/providers.{register,update,delete}
  - platform/{status,connect,disconnect,callback-routes/register,callback-routes}
  - sequences/{list,get,pause,resume,cancel-enrollment,stats,guardrails}
  - user-routes/{list,inspect}

http-router.ts treats unregistered endpoints as unprotected (enforcePolicy
no-ops on missing keys), so any authenticated principal could hit these
over HTTP without the intended scope/principal-type gates. The IPC dispatch
path bypasses enforcePolicy entirely, so the existing CLI flows are
unaffected by these additions.

Scope/principal assignments mirror sibling routes:
  - oauth/apps mutations use ACTOR_ENDPOINTS settings.write (matches
    oauth/apps.create/.delete already present)
  - oauth/providers mutations use ACTOR_ENDPOINTS settings.write
  - oauth/apps/lookup uses ACTOR_ENDPOINTS settings.read
  - auth/info uses ACTOR_ENDPOINTS settings.read
  - internal/mcp/{list,add,remove} join INTERNAL_ENDPOINTS (gateway-only,
    internal.write) alongside the existing internal/mcp/reload entry
  - CLI-driven routes (audit, conversations/cli/*, inference/send,
    platform/*, sequences/*, user-routes/*) are local-only with
    settings.read or settings.write, mirroring tasks/*, cache/*, defer/*,
    domain/*, email/* — destructive 'conversations/cli/clear' elevates
    to settings.write to match conversations/clear-all
  - inference/send uses chat.write (LLM dispatch on behalf of caller),
    aligned with tts/synthesize-cli + stt/transcribe-file

Closes route-policy coverage findings on PRs #30241 (sequences,
user-routes), #30242 (conversations/cli/clear), #30244 (inference/send),
#30245 (internal/mcp), #30246 (oauth/providers, oauth/apps), #30247
(platform/*).

Co-authored-by: credence-the-bot[bot] <credence-the-bot[bot]@users.noreply.github.com>
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