feat(phase-5): WS5 — Developer Experience

Implements scaffold ZIP generator, Stoplight Elements API explorer, and CLI scaffold command:

Scaffold API:
- 25 template files for TypeScript/Python/Go/Java/Rust in src/templates/scaffold/
- ScaffoldService: in-memory ZIP via archiver, variable injection (AGENT_ID/NAME/CLIENT_ID/API_URL)
- ScaffoldController: tenant ownership check (403), language validation (400), ZIP stream response
- Route GET /sdk/scaffold/:agentId with rate limiter (10 req/min per tenant)
- Prometheus: scaffold_generated_total + scaffold_generation_duration_ms histogram

Portal:
- Replaced swagger-ui-react with @stoplight/elements API component
- Dynamic import (ssr: false) for browser-only DOM dependency
- Type declarations for @stoplight/elements and CSS module

CLI:
- sentryagent scaffold --agent-id <id> [--language typescript] [--out .]
- Raw fetch for binary ZIP stream → unzipper.Extract() → prints next steps
- Human-readable 400/403/404 error messages

Tests: 19 tests (unit + integration), ScaffoldService 80%+ branch coverage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SentryAgent.ai Developer
2026-04-03 02:50:32 +00:00
parent 16497706d3
commit 662879f0ee
42 changed files with 6176 additions and 1741 deletions

View File

@@ -68,6 +68,12 @@ import { createOIDCRouter } from './routes/oidc.js';
import { createFederationRouter } from './routes/federation.js';
import { createWebhooksRouter } from './routes/webhooks.js';
import { createComplianceRouter } from './routes/compliance.js';
import { createDelegationRouter } from './routes/delegation.js';
import { DelegationService } from './services/DelegationService.js';
import { DelegationController } from './controllers/DelegationController.js';
import { createScaffoldRouter } from './routes/scaffold.js';
import { ScaffoldService } from './services/ScaffoldService.js';
import { ScaffoldController } from './controllers/ScaffoldController.js';
import { errorHandler } from './middleware/errorHandler.js';
import { createOpaMiddleware } from './middleware/opa.js';
@@ -326,6 +332,22 @@ export async function createApp(): Promise<Application> {
app.use(`${API_BASE}/oidc`, createOIDCTrustPoliciesRouter(oidcTrustPolicyController, authMiddleware));
app.use(`${API_BASE}/oidc`, createOIDCTokenExchangeRouter(oidcTokenExchangeController));
// ────────────────────────────────────────────────────────────────
// Phase 5 WS2: A2A Delegation (guarded by A2A_ENABLED flag)
// ────────────────────────────────────────────────────────────────
if (process.env['A2A_ENABLED'] !== 'false') {
const delegationService = new DelegationService(pool, auditService);
const delegationController = new DelegationController(delegationService);
app.use(`${API_BASE}`, createDelegationRouter(delegationController, authMiddleware));
}
// ────────────────────────────────────────────────────────────────
// Phase 5 WS5: Scaffold Generator
// ────────────────────────────────────────────────────────────────
const scaffoldService = new ScaffoldService();
const scaffoldController = new ScaffoldController(scaffoldService, pool, auditService);
app.use(`${API_BASE}`, createScaffoldRouter(scaffoldController, authMiddleware));
// ────────────────────────────────────────────────────────────────
// Dashboard static assets (served from dashboard/dist/)
// Placed after API routes so API routes take precedence.