Compare commits

..

1 Commits

Author SHA1 Message Date
29c7d051b6 v1.16.0-codesight-merge: 4 new codecontext tools — blast radius, hot files, routes, middleware
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) <noreply@anthropic.com>
2026-05-24 05:19:52 +00:00
7 changed files with 211 additions and 2 deletions

View File

@@ -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. 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 ## 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_<name>` to `<serverName>_<toolName>` 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. 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_<name>` to `<serverName>_<toolName>` 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.

View File

@@ -21,6 +21,10 @@ import {
watchChanges, watchChanges,
getSemanticNeighborhoods, getSemanticNeighborhoods,
getFrameworkAnalysis, getFrameworkAnalysis,
getBlastRadius,
getHotFiles,
getRoutes,
getMiddleware,
} from './tools/codecontext/index.js'; } from './tools/codecontext/index.js';
// v1.13.17-cross-repo-reads: cross-repo read grant request tool. Paired // 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 // with the pause-on-pending-grant branch in inference/tool-phase.ts and the
@@ -680,6 +684,11 @@ export let ALL_TOOLS: ToolDef<unknown>[] = [
watchChanges as ToolDef<unknown>, watchChanges as ToolDef<unknown>,
getSemanticNeighborhoods as ToolDef<unknown>, getSemanticNeighborhoods as ToolDef<unknown>,
getFrameworkAnalysis as ToolDef<unknown>, getFrameworkAnalysis as ToolDef<unknown>,
// v1.16: codesight-merge tools. Backed by the same codecontext sidecar.
getBlastRadius as ToolDef<unknown>,
getHotFiles as ToolDef<unknown>,
getRoutes as ToolDef<unknown>,
getMiddleware as ToolDef<unknown>,
// v1.13.17-cross-repo-reads: paired with the pause-on-pending-grant // 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 // branch in tool-phase.ts. Read-only — only ever READS files; the only
// state change is appending to sessions.allowed_read_paths via the // state change is appending to sessions.allowed_read_paths via the

View File

@@ -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<typeof GetBlastRadiusInput>;
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<CodecontextResponse> {
return callCodecontext(
{ toolName: 'get_blast_radius', args: { file_path: input.file_path }, projectPath },
fetcher,
);
}
export const getBlastRadius: ToolDef<GetBlastRadiusInputT> = {
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);
},
};

View File

@@ -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<typeof GetHotFilesInput>;
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<CodecontextResponse> {
return callCodecontext(
{ toolName: 'get_hot_files', args: input.limit != null ? { limit: input.limit } : {}, projectPath },
fetcher,
);
}
export const getHotFiles: ToolDef<GetHotFilesInputT> = {
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);
},
};

View File

@@ -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<typeof GetMiddlewareInput>;
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<CodecontextResponse> {
return callCodecontext({ toolName: 'get_middleware', args: {}, projectPath }, fetcher);
}
export const getMiddleware: ToolDef<GetMiddlewareInputT> = {
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);
},
};

View File

@@ -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<typeof GetRoutesInput>;
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<CodecontextResponse> {
const args: Record<string, unknown> = {};
if (input.framework) args.framework = input.framework;
return callCodecontext({ toolName: 'get_routes', args, projectPath }, fetcher);
}
export const getRoutes: ToolDef<GetRoutesInputT> = {
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);
},
};

View File

@@ -1,5 +1,5 @@
// v1.12 Track B.2: codecontext tool registry. Re-exports the 8 ToolDefs so // codecontext tool registry. Re-exports ToolDefs so tools.ts can pull them
// tools.ts can pull them in one line. // in one line. v1.12: 8 original tools. v1.16: +4 codesight-merge tools.
export { getCodebaseOverview } from './get_codebase_overview.js'; export { getCodebaseOverview } from './get_codebase_overview.js';
export { getFileAnalysis } from './get_file_analysis.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 { watchChanges } from './watch_changes.js';
export { getSemanticNeighborhoods } from './get_semantic_neighborhoods.js'; export { getSemanticNeighborhoods } from './get_semantic_neighborhoods.js';
export { getFrameworkAnalysis } from './get_framework_analysis.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';