feat(routes): #93 route-compiler substrate — discovery, route-graph IR, mode diagnostics, inspect focus (PR-1) - #116
Conversation
…able route-graph IR, mode diagnostics, inspect focus
Discover route modules under the conventional roots (src/mcp/<server>/
{tools,resources,prompts,apps}/, src/events/, src/providers/, src/cli/,
src/scripts/) through the existing sorted, ignore-aware, safe-path
discovery machinery, and compile them into a deep-frozen AgentRouteGraph
whose paths supply kind, owning server, and identity. New AB480x error
family: route-directory vs entry-file mode conflicts (AB4800 server file,
AB4801 declared server, AB4802 src/cli.ts), duplicate route ids (AB4803),
and unsafe route names (AB4804) — a server is in exactly one mode and the
compiler never silently chooses. Modules explicit configuration claims
(scripts, hooks, bin, lib, mcp entries) are never routes, keeping shipped
example layouts valid. inspect gains a --routes focus listing the graph.
The graph is consumer-invisible this wave: config stays empty until the
static extractor lands, and nothing generates entries from it.
Docs rider: supersession note on the 2026-08-26 filesystem-router
non-goal pointing at #93; status note on the 2026-08-25 capability-aware
Workbench spec pointing at #105.
Part of #93
🦋 Changeset detectedLatest commit: dc8af7e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dc8af7e243
ℹ️ 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".
| } | ||
| } | ||
| if (routes.some((route) => route.kind === 'cli')) { | ||
| const cliEntry = conventionalCliEntrySource(projectRoot); |
There was a problem hiding this comment.
Respect explicit bin configuration before reporting AB4802
When a project has routed commands, retains src/cli.ts, and explicitly points bin elsewhere, this unconditionally treats the shadowed file as the active conventional package entry and raises hard error AB4802. Existing packageConventionShadowNudges() explicitly defines that file as shadowed in this configuration and only emits AB4731, so otherwise valid validation/build commands are now blocked until an unused file is removed. Check whether the convention is active under config.bin before reporting this mode conflict.
Useful? React with 👍 / 👎.
| const matches = await fastGlob([...routeModulePatterns], { | ||
| absolute: true, | ||
| cwd: projectRoot, | ||
| followSymbolicLinks: false, | ||
| onlyFiles: true, |
There was a problem hiding this comment.
Include dotfiles in unsafe route-name validation
Because fast-glob defaults dot to false, inputs such as src/scripts/.release.ts or src/events/.internal/saved.ts never reach the isSafePathSegment check and are silently omitted instead of producing the documented hard AB4804 diagnostic. The only documented private convention here is _-prefixed segments, so hidden modules under a recognized route root should be scanned and then rejected as unsafe.
Useful? React with 👍 / 👎.
|
Duplicate of Wave 1 Lane B PR-1. Keeper is #119 (graph.ts + inspect.ts + route-graph tests). This branch used routes/discover.ts instead of the agreed compiler. |
…ared route graph to inspect Reconciliation of the two Lane B PR-1 implementations (#116 closed as duplicate, #119 the keeper): - Config always wins: modules referenced by explicit scripts/hooks/bin/ lib/mcp configuration are claimed by that declaration and never become routes. This keeps examples/hooks-and-scripts and examples/mcp-app — both with src/scripts/* files, all config-claimed — route-free and building unchanged (proved by pnpm examples:check). - Codex P2 fix: the inspect routes focus no longer reloads the config and recompiles the graph (a non-idempotent config factory could diverge from the validated model, and second-pass diagnostics were mishandled). PreparedProject now carries the graph compiled during discovery, and the focus serves it directly; route-free projects serve the shared frozen emptyCompiledRouteGraph. - Test coverage ported from #116: the claim rule (examples-shaped fixture), the declared entry/command/url server-conflict branch of AB4800, and the route-free inspect focus. Part of #93
* feat: compile route-graph IR and inspect focus (#93) Compile the conventional route tree (src/mcp/<server>/{tools,resources, prompts,apps}, src/events, src/providers, src/cli, src/scripts) into an immutable, digest-stable route-graph IR with hard collision errors (AB4800-AB4804) and explicit routes.servers/<id> + routes.cli mode overrides. discoverProject attaches the graph only when non-empty, validateSource surfaces its diagnostics, and inspect gains a routes focus (--routes) that dumps the graph bundler-style. Towards #93. Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com> * docs: mark filesystem-router non-goal superseded by #93 and add Workbench spec status note (#105, #107) Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com> * feat(routes): port the config-claim rule from #116 and serve the prepared route graph to inspect Reconciliation of the two Lane B PR-1 implementations (#116 closed as duplicate, #119 the keeper): - Config always wins: modules referenced by explicit scripts/hooks/bin/ lib/mcp configuration are claimed by that declaration and never become routes. This keeps examples/hooks-and-scripts and examples/mcp-app — both with src/scripts/* files, all config-claimed — route-free and building unchanged (proved by pnpm examples:check). - Codex P2 fix: the inspect routes focus no longer reloads the config and recompiles the graph (a non-idempotent config factory could diverge from the validated model, and second-pass diagnostics were mishandled). PreparedProject now carries the graph compiled during discovery, and the focus serves it directly; route-free projects serve the shared frozen emptyCompiledRouteGraph. - Test coverage ported from #116: the claim rule (examples-shaped fixture), the declared entry/command/url server-conflict branch of AB4800, and the route-free inspect focus. Part of #93 * fix(inspect): reuse prepared route graph for --routes focus Carry discovery's graph on the invalid-source prepare path and pin inspect --routes to a single config-factory evaluation. * refactor(routes): use the shared cycle-safe deepFreeze and fold the duplicate api re-export Deslop audit items 1 and 4: graph.ts drops its local deepFreeze copy for the shared core/freeze.ts implementation (cycle-free import; behavior equivalent for the fresh plain-object IR), and api.ts folds the two consecutive routes/graph re-export statements into one. Part of #93 * fix: contain hostile config throws in route discovery and resolve ignore types for consumers Route-graph compilation reads config sections (scripts, hooks, bin, lib, mcp) whose getters are untrusted until validation runs; a throwing getter must degrade to an absent graph so validation still reports AB7001 instead of the load-failure path reporting AB7000. The public-api consumer fixture also gains an ignore symlink because routes/graph.d.ts now pulls config/ignore.d.ts into the root declaration graph (ignore is a runtime dependency, matching the ajv precedent). * fix(routes): fail closed on hostile routes getters Keep discovery tolerant of hostile config-claim getters while forcing hostile routes access through source validation, so inspect reports AB7001 instead of silently returning ready. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Summary
First of two substrate PRs for the route compiler (Wave 1, Lane B of #107). Part of #93 — substrate only, the issue stays open.
src/mcp/<server>/{tools,resources,prompts,apps}/*,src/events/**,src/providers/*,src/cli/*,src/scripts/*) rides the existing deterministic machinery: sorted globbing, project ignore rules, safe path segments, provenance on every route. No parallel scanner.packages/agent-bundle/src/routes/): deep-frozenAgentRouteGraphofCompiledAgentRoute { kind, id, source, serverId?, config, provenance }. Paths supply kind/server/identity;configstays empty until PR-2's static extractor; the route-kind union is switched exhaustively with aneverdefault.AB480xdiagnostic family (documented indocs/diagnostics.md):AB4800route directory vssrc/mcp/<server>.tsentry,AB4801route-mode server also declared inmcp.servers,AB4802src/cli/routes vssrc/cli.ts,AB4803duplicate route ids,AB4804unsafe route names. All hard errors — a server (and the package CLI) is in exactly one mode; the compiler never silently chooses (issue rule 10).inspect --routesfocus through the existing focus/DTO pattern (additive toInspectOptions/ReadyInspectResult.selected).scripts/hooks/bin/lib/mcpconfiguration are claimed by that declaration and never become routes. This keepsexamples/hooks-and-scriptsandexamples/mcp-app(both havesrc/scripts/*files, all config-claimed) building unchanged — verified; no other example matches a conventional root.defineOperationand all existing conventions untouched,docs/framework-mode.mduntouched. Driven purely by internal fixtures (tests/routes.test.ts, 9 tests).agent-bundle.Test plan
tsc --noEmit,rslint, fulltest:unit(1790 passed)cli.test.ts,examples-contract.test.tsgreen against the built packagepnpm check:local-cigreen before merge