From 29c7d051b6df32d7bb06dd3ad65c33a0e950f082 Mon Sep 17 00:00:00 2001 From: indifferentketchup Date: Sun, 24 May 2026 05:19:52 +0000 Subject: [PATCH] =?UTF-8?q?v1.16.0-codesight-merge:=204=20new=20codecontex?= =?UTF-8?q?t=20tools=20=E2=80=94=20blast=20radius,=20hot=20files,=20routes?= =?UTF-8?q?,=20middleware?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BooCode wrapper tools for the 4 new MCP tools added to the codecontext sidecar (Go side committed separately at /opt/forks/codecontext). - get_blast_radius: reverse-edge BFS — "what breaks if I change this?" - get_hot_files: most-imported files by incoming edge count - get_routes: Fastify/Express route extraction via tree-sitter AST - get_middleware: middleware detection via import + registration patterns Wrappers follow the existing codecontext pattern: Zod input → callCodecontext → ToolDef export. Registered in ALL_TOOLS (alpha-sorted). All 4 are read-only. codecontext sidecar rebuilt from commit b19e646 with the 4 new Go handlers (2130 lines, 29 tests). Reviewer fixes applied: defer RUnlock on Tier 2 handlers, extractObjectProperty delegates to extractStringValue for template-literal route paths. 363/363 server tests passing. No schema changes, no frontend changes. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 4 ++ apps/server/src/services/tools.ts | 9 ++++ .../tools/codecontext/get_blast_radius.ts | 51 +++++++++++++++++++ .../tools/codecontext/get_hot_files.ts | 50 ++++++++++++++++++ .../tools/codecontext/get_middleware.ts | 41 +++++++++++++++ .../services/tools/codecontext/get_routes.ts | 50 ++++++++++++++++++ .../src/services/tools/codecontext/index.ts | 8 ++- 7 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 apps/server/src/services/tools/codecontext/get_blast_radius.ts create mode 100644 apps/server/src/services/tools/codecontext/get_hot_files.ts create mode 100644 apps/server/src/services/tools/codecontext/get_middleware.ts create mode 100644 apps/server/src/services/tools/codecontext/get_routes.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index df798d5..3d8c846 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes per release tag. Most recent on top, ordered by tag creation date (which matches the git history). Tag names follow `vMAJOR.MINOR.PATCH-slug` — the slug describes what shipped, so the tag name alone is enough to recall the batch. +## v1.16.0-codesight-merge — 2026-05-24 + +Ports codesight's highest-value analysis capabilities into the codecontext sidecar as 4 new MCP tools. Tier 1 (graph queries on existing edges, no re-parsing): `get_blast_radius` (BFS reverse-edge traversal — "what breaks if I change this file?", with depth tracking) and `get_hot_files` (most-imported files ranked by incoming edge count — change-risk indicators). Tier 2 (tree-sitter AST re-parsing on demand): `get_routes` (Fastify/Express HTTP route extraction with method, path, file, line, inferred tags for db/auth/cache) and `get_middleware` (middleware registration detection via import-name heuristics and app.register/addHook/setErrorHandler patterns, classifying as auth/cors/rate-limit/security/error-handler/logging/validation). All 4 tools use `defer s.graphMu.RUnlock()` for consistent mutex discipline (reviewer caught that the initial implementation released the lock early on the Tier 2 tools). Route object-property extraction delegates to `extractStringValue` for template-literal handling (reviewer catch). codecontext sidecar rebuilt from `/opt/forks/codecontext` commit `b19e646`, tagged `v1.16.0-codesight-merge`. BooCode wrapper tools follow the existing codecontext pattern — 4 new files in `apps/server/src/services/tools/codecontext/`, registered in ALL_TOOLS. 29 new Go tests + 363/363 BooCode server tests passing. No schema changes, no frontend changes. + ## v1.15.0-mcp-multi — 2026-05-24 Multi-server MCP client with stdio + Streamable HTTP transports, JSON config file, and per-agent tool glob patterns. Generalizes the v1.14.1 single-server Context7 PoC into a registry of named MCP servers with per-server graceful degradation. JSON config at `/data/mcp.json` (bind-mounted alongside `AGENTS.md`) matches opencode's `mcpServers` schema shape so server entries are copy-pasteable. Config file missing = no MCP (opt-in by file presence). Stdio transport spawns a persistent subprocess via the SDK's `StdioClientTransport` with NDJSON framing; Streamable HTTP reuses the v1.14.1 pattern via `StreamableHTTPClientTransport`. Tool prefix generalized from `context7_` to `_` with a reverse `toolToServer` map for dispatch routing. Per-agent AGENTS.md `tools:` field now supports glob patterns (`context7_*`, `!web_*`) via `matchToolGlob` (last-match-wins, `!` prefix denies); replaces the exact-match `.includes()` in `stream-phase.ts`. Glob patterns bypass `ALL_TOOL_NAMES` validation in the parser since MCP tool names aren't known at parse time. `refreshToolNames()` in `agents.ts` rebuilds the `DEFAULT_TOOLS` snapshot after `appendMcpTools` so agents without explicit `tools:` lists see MCP tools — reviewer caught that the module-load-time snapshot would permanently exclude late-registered tools. Read-only invariant preserved: all MCP tools with `readOnlyHint: false` rejected at discovery. Result size capped at 5MB. Shutdown hook closes all transports. v1.14.1 env vars (`MCP_CONTEXT7_URL`, `MCP_CONTEXT7_API_KEY`) removed — superseded by the config file. Default `data/mcp.json` ships with Context7 disabled; flip `"enabled": true` to activate. 363/363 server tests passing (27 new: multi-server wrapping, glob matching, routing, degradation). No schema changes, no frontend changes. diff --git a/apps/server/src/services/tools.ts b/apps/server/src/services/tools.ts index fc0aecb..4ee5d69 100644 --- a/apps/server/src/services/tools.ts +++ b/apps/server/src/services/tools.ts @@ -21,6 +21,10 @@ import { watchChanges, getSemanticNeighborhoods, getFrameworkAnalysis, + getBlastRadius, + getHotFiles, + getRoutes, + getMiddleware, } from './tools/codecontext/index.js'; // v1.13.17-cross-repo-reads: cross-repo read grant request tool. Paired // with the pause-on-pending-grant branch in inference/tool-phase.ts and the @@ -680,6 +684,11 @@ export let ALL_TOOLS: ToolDef[] = [ watchChanges as ToolDef, getSemanticNeighborhoods as ToolDef, getFrameworkAnalysis as ToolDef, + // v1.16: codesight-merge tools. Backed by the same codecontext sidecar. + getBlastRadius as ToolDef, + getHotFiles as ToolDef, + getRoutes as ToolDef, + getMiddleware as ToolDef, // v1.13.17-cross-repo-reads: paired with the pause-on-pending-grant // branch in tool-phase.ts. Read-only — only ever READS files; the only // state change is appending to sessions.allowed_read_paths via the diff --git a/apps/server/src/services/tools/codecontext/get_blast_radius.ts b/apps/server/src/services/tools/codecontext/get_blast_radius.ts new file mode 100644 index 0000000..cdfbbe6 --- /dev/null +++ b/apps/server/src/services/tools/codecontext/get_blast_radius.ts @@ -0,0 +1,51 @@ +import { z } from 'zod'; +import type { ToolDef } from '../../tools.js'; +import { callCodecontext, type CodecontextResponse } from '../../codecontext_client.js'; + +export const GetBlastRadiusInput = z.object({ + file_path: z.string().trim().min(1), +}); +export type GetBlastRadiusInputT = z.infer; + +const DESCRIPTION = + 'Returns all files that depend (transitively) on the given file, with depth tracking. ' + + 'Use to assess the impact of changing a file — "what breaks if I modify this?" ' + + 'Traverses the import graph in reverse via BFS. Results sorted by distance (closest dependents first).'; + +export async function executeGetBlastRadius( + input: GetBlastRadiusInputT, + projectPath: string, + fetcher: typeof fetch = fetch, +): Promise { + return callCodecontext( + { toolName: 'get_blast_radius', args: { file_path: input.file_path }, projectPath }, + fetcher, + ); +} + +export const getBlastRadius: ToolDef = { + name: 'get_blast_radius', + description: DESCRIPTION, + inputSchema: GetBlastRadiusInput, + jsonSchema: { + type: 'function', + function: { + name: 'get_blast_radius', + description: DESCRIPTION, + parameters: { + type: 'object', + properties: { + file_path: { + type: 'string', + description: 'Absolute or project-relative path to the file to analyze.', + }, + }, + required: ['file_path'], + additionalProperties: false, + }, + }, + }, + async execute(input, projectRoot) { + return await executeGetBlastRadius(input, projectRoot); + }, +}; diff --git a/apps/server/src/services/tools/codecontext/get_hot_files.ts b/apps/server/src/services/tools/codecontext/get_hot_files.ts new file mode 100644 index 0000000..337a4d0 --- /dev/null +++ b/apps/server/src/services/tools/codecontext/get_hot_files.ts @@ -0,0 +1,50 @@ +import { z } from 'zod'; +import type { ToolDef } from '../../tools.js'; +import { callCodecontext, type CodecontextResponse } from '../../codecontext_client.js'; + +export const GetHotFilesInput = z.object({ + limit: z.number().int().min(1).max(100).optional(), +}); +export type GetHotFilesInputT = z.infer; + +const DESCRIPTION = + 'Returns the most-imported files in the project, ranked by incoming import count. ' + + 'Hot files are high-risk change targets — many other files depend on them. ' + + 'Use to identify core modules and assess refactoring risk.'; + +export async function executeGetHotFiles( + input: GetHotFilesInputT, + projectPath: string, + fetcher: typeof fetch = fetch, +): Promise { + return callCodecontext( + { toolName: 'get_hot_files', args: input.limit != null ? { limit: input.limit } : {}, projectPath }, + fetcher, + ); +} + +export const getHotFiles: ToolDef = { + name: 'get_hot_files', + description: DESCRIPTION, + inputSchema: GetHotFilesInput, + jsonSchema: { + type: 'function', + function: { + name: 'get_hot_files', + description: DESCRIPTION, + parameters: { + type: 'object', + properties: { + limit: { + type: 'number', + description: 'Maximum number of files to return (default 20, max 100).', + }, + }, + additionalProperties: false, + }, + }, + }, + async execute(input, projectRoot) { + return await executeGetHotFiles(input, projectRoot); + }, +}; diff --git a/apps/server/src/services/tools/codecontext/get_middleware.ts b/apps/server/src/services/tools/codecontext/get_middleware.ts new file mode 100644 index 0000000..3ced203 --- /dev/null +++ b/apps/server/src/services/tools/codecontext/get_middleware.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import type { ToolDef } from '../../tools.js'; +import { callCodecontext, type CodecontextResponse } from '../../codecontext_client.js'; + +export const GetMiddlewareInput = z.object({}); +export type GetMiddlewareInputT = z.infer; + +const DESCRIPTION = + 'Detects middleware registrations in the project. Identifies auth, CORS, rate-limit, ' + + 'security-headers, error-handler, logging, and validation middleware by analyzing ' + + 'import names (@fastify/cors, helmet, etc.) and registration patterns ' + + '(app.register, app.addHook, app.setErrorHandler).'; + +export async function executeGetMiddleware( + _input: GetMiddlewareInputT, + projectPath: string, + fetcher: typeof fetch = fetch, +): Promise { + return callCodecontext({ toolName: 'get_middleware', args: {}, projectPath }, fetcher); +} + +export const getMiddleware: ToolDef = { + name: 'get_middleware', + description: DESCRIPTION, + inputSchema: GetMiddlewareInput, + jsonSchema: { + type: 'function', + function: { + name: 'get_middleware', + description: DESCRIPTION, + parameters: { + type: 'object', + properties: {}, + additionalProperties: false, + }, + }, + }, + async execute(input, projectRoot) { + return await executeGetMiddleware(input, projectRoot); + }, +}; diff --git a/apps/server/src/services/tools/codecontext/get_routes.ts b/apps/server/src/services/tools/codecontext/get_routes.ts new file mode 100644 index 0000000..ebaaff1 --- /dev/null +++ b/apps/server/src/services/tools/codecontext/get_routes.ts @@ -0,0 +1,50 @@ +import { z } from 'zod'; +import type { ToolDef } from '../../tools.js'; +import { callCodecontext, type CodecontextResponse } from '../../codecontext_client.js'; + +export const GetRoutesInput = z.object({ + framework: z.string().trim().optional(), +}); +export type GetRoutesInputT = z.infer; + +const DESCRIPTION = + 'Extracts HTTP routes from the project via tree-sitter AST analysis. ' + + 'Detects Fastify and Express route registrations (app.get, app.post, app.route, router.use, etc.) ' + + 'with method, path, file, line number, and inferred tags (db, auth, cache). ' + + 'Optional framework filter narrows to "fastify" or "express".'; + +export async function executeGetRoutes( + input: GetRoutesInputT, + projectPath: string, + fetcher: typeof fetch = fetch, +): Promise { + const args: Record = {}; + if (input.framework) args.framework = input.framework; + return callCodecontext({ toolName: 'get_routes', args, projectPath }, fetcher); +} + +export const getRoutes: ToolDef = { + name: 'get_routes', + description: DESCRIPTION, + inputSchema: GetRoutesInput, + jsonSchema: { + type: 'function', + function: { + name: 'get_routes', + description: DESCRIPTION, + parameters: { + type: 'object', + properties: { + framework: { + type: 'string', + description: 'Filter to a specific framework: "fastify" or "express". Omit for all.', + }, + }, + additionalProperties: false, + }, + }, + }, + async execute(input, projectRoot) { + return await executeGetRoutes(input, projectRoot); + }, +}; diff --git a/apps/server/src/services/tools/codecontext/index.ts b/apps/server/src/services/tools/codecontext/index.ts index 7abbcd7..219507b 100644 --- a/apps/server/src/services/tools/codecontext/index.ts +++ b/apps/server/src/services/tools/codecontext/index.ts @@ -1,5 +1,5 @@ -// v1.12 Track B.2: codecontext tool registry. Re-exports the 8 ToolDefs so -// tools.ts can pull them in one line. +// codecontext tool registry. Re-exports ToolDefs so tools.ts can pull them +// in one line. v1.12: 8 original tools. v1.16: +4 codesight-merge tools. export { getCodebaseOverview } from './get_codebase_overview.js'; export { getFileAnalysis } from './get_file_analysis.js'; @@ -9,3 +9,7 @@ export { getDependencies } from './get_dependencies.js'; export { watchChanges } from './watch_changes.js'; export { getSemanticNeighborhoods } from './get_semantic_neighborhoods.js'; export { getFrameworkAnalysis } from './get_framework_analysis.js'; +export { getBlastRadius } from './get_blast_radius.js'; +export { getHotFiles } from './get_hot_files.js'; +export { getRoutes } from './get_routes.js'; +export { getMiddleware } from './get_middleware.js';