feat(ui): Steps for servers — route roots, server effects, request/decorator triggers, guards for Python/Java/Kotlin/C#/Go/C

- api/route-roots.ts: the symbol a route runs (references-edge handler, exported page component, or the route itself for an inline handler), shared by steps and screens; the bare Steps tab lists an API's endpoints by router file
- api/effects.ts: database / response / queue / email / payments / cache / auth / process / network / storage / device / telemetry, matched on the call as written per language family, with model + read/write and the literal status on a response site
- graph/branch-guards.ts: callSitesForFile (the whole member chain), memberTypesInTree, decoratorsForFile, request/decorator triggers with the middleware/guard chain; guard + argument rules for Python, Java, Kotlin, C#, Go and C
- steps.ts: classify on the chain before trusting a name match, retarget this.x.y() by declared type, skip test doubles after the effect pre-check, project kind on the wire
- viewer: kindWord/kindWords per project kind, endpoint chooser, response boxes labelled by status codes
- python.ts: FastAPI detected from a monorepo sub-directory; is-test-file: samples/examples package paths are not tests
- tests: ui-steps-api-servers, ui-effects, branch-guards-languages; spec §3.13 Servers paragraph, CHANGELOG, plan doc

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REFyW9hmNrxhwN5wxRoAkC
This commit is contained in:
Colby McHenry
2026-08-28 13:45:38 -05:00
co-authored by Claude Fable 5
parent 5e06204deb
commit 950686def4
22 changed files with 3869 additions and 190 deletions
+16
View File
@@ -242,6 +242,22 @@ export const fastapiResolver: FrameworkResolver = {
const content = context.readFile(file);
if (content && content.includes('FastAPI(')) return true;
}
// A service that is one directory of a monorepo (`backend/pyproject.toml`,
// `backend/app/main.py`): its manifest or its app object sits below the root.
let looked = 0;
for (const file of context.getAllFiles()) {
const norm = file.replace(/\\/g, '/');
const base = norm.slice(norm.lastIndexOf('/') + 1);
if (base === 'requirements.txt' || base === 'pyproject.toml' || base === 'requirements-dev.txt') {
const content = context.readFile(file);
if (content && /\bfastapi\b/i.test(content)) return true;
if (++looked >= 40) break;
} else if ((base === 'main.py' || base === 'app.py' || base === 'api.py') && norm.split('/').length <= 4) {
const content = context.readFile(file);
if (content && content.includes('FastAPI(')) return true;
if (++looked >= 40) break;
}
}
return false;
},