- Implemented `tools-codegraph.ts` to provide various queries on the codebase dependency graph, including impact analysis, dead code detection, module boundaries, and more. - Created a schema for validating query inputs using Zod. - Developed helper functions for resolving file paths, formatting output, and handling different query types. - Added tests for the codegraph queries in `codegraph-queries.test.ts` to ensure functionality and correctness. - Introduced tests for the codegraph scanning and loading functionalities in `codegraph.test.ts`, verifying the detection of source files, imports, exports, circular dependencies, and entry points.
5.8 KiB
Codebase Graph — Spec
TL;DR
Static-analysis graph that scans a TypeScript project and injects a compact architecture overview into the system prompt, so the agent knows the codebase structure before making a single tool call.
Problem
When a session starts in a large TS codebase, the agent has no idea what files exist, how they connect, or what the architecture is. It wastes 2-5 turns exploring (glob, grep, read_file) just to build a mental model. This is the "shiro-neko" problem: the agent should be a senior engineer who has read the codebase, not a newcomer who needs to explore first.
Goal
- Compute a dependency graph of all .ts/.tsx files in the workspace via TypeScript compiler API
- Persist the graph to
.shiro/codegraph.json(mtime-based freshness) - Inject a compact "Codebase Architecture" section (~200-500 tokens) into the system prompt
- Provide a
codegraphtool for detailed queries (file deps, type refs, circular deps, etc.) - Add a
/graphcommand to force regeneration
Architecture
Data model (src/codegraph.ts)
type FileNode = {
path: string; // relative to root
kind: 'source' | 'test' | 'config' | 'other';
imports: string[]; // file-relative paths
exports: string[]; // exported names
types: string[]; // exported type/interface names
classes: string[]; // exported class names
functions: string[]; // exported function names
size: number; // estimated LOC
};
type CodeGraph = {
version: 1;
generated: string; // ISO timestamp
root: string; // project root
entryPoints: string[]; // files with main() or re-export patterns
files: Record<string, FileNode>;
moduleMap: Record<string, string[]>; // dir → files
circularDeps: string[][]; // cycles
summary: string; // compact text for system prompt
};
Static analysis approach
Use TypeScript createProgram to:
- Read
tsconfig.json(if exists) for compiler options + include patterns - Create a program with all source files
- For each source file:
- Walk
ImportDeclarationnodes → extract resolved file paths - Walk
ExportDeclarationnodes → extract exported names - Walk
InterfaceDeclaration,TypeAliasDeclaration→ exported types - Walk
ClassDeclaration→ exported classes - Walk
FunctionDeclaration→ exported functions
- Walk
- Build the dependency graph
- Detect circular dependencies via DFS
- Classify files: source (src/), test (test/, *.test.ts), config (tsconfig, package.json), other
- Detect entry points: files in
src/that import fewest others (leaf-ward), or containmain()/export default - Generate compact summary text
Summary text format
Codebase Architecture (shiro-neko)
Entry: src/cli.tsx (CLI entry, loads everything)
Modules (6):
src/ → 13 files: session, tools, prompt, config, cli, subagent, memory, commands, agents, notebook, prune, pricing, store
src/ui/ → 4 files: App, ChatMessage, Thinking, BusyIndicator
src/tools-* → 4 files: git, net, mcp, memory (tool implementations)
test/ → 22 files
Key abstractions: Session (core), Notebook (task state), Permission (access), Undo (rollback)
Circular deps: none
System prompt integration (prompt.ts)
New PromptParts field: codegraph?: string
Section placement: after "Environment", before "Tools available":
Codebase Architecture
${codegraph}
Only shown when graph is available (non-empty). Omitted when workspace has no .ts files.
Session lifecycle (session.ts)
On systemFor() call:
- Check
.shiro/codegraph.jsonexistence + freshness - Freshness: recompute if any .ts file in workspace has mtime > graph.generated
- Cache in Session (don't recompute per-step)
- Pass
PromptParts.codegraphonly when variant is non-empty (not in headless one-shot)
Tool: codegraph
{
name: 'codegraph',
description: 'Query the pre-computed codebase dependency graph.',
input: {
query: 'list' | 'file <path>' | 'deps <path>' | 'types' | 'circular',
},
}
list: all files with kind + sizefile <path>: full info for one filedeps <path>: what it imports and what imports it (reverse deps)types: all exported types/interfaces across codebasecircular: all detected circular dependency chains
Command: /graph
Forces regeneration of the codegraph. Shows the summary output in chat.
Files touched
- NEW:
src/codegraph.ts— core static analysis - NEW:
src/tools-codegraph.ts— tool definition - NEW:
test/codegraph.test.ts— tests - EDIT:
src/prompt.ts— addcodegraph?: stringto PromptParts, inject section - EDIT:
src/session.ts— compute/load graph in systemFor(), pass to PromptParts - EDIT:
src/cli.tsx— register codegraph tool, compute on startup - EDIT:
src/commands.ts— add/graphcommand - EDIT:
src/ui/App.tsx— handle/graphcommand - NEW:
docs/codegraph.md— user-facing documentation
Verification
bun run typecheck— cleanbun test— all existing + new codegraph tests passbun test test/codegraph.test.ts— standalone codegraph verificationbun run build— binary compiles- Manual: start session in shiro-neko repo → system prompt includes architecture section
/graphregenerates and shows summarycodegraph typestool lists all exported types- Circular deps detected if they exist (none expected in shiro-neko itself)
Edge cases
- Empty workspace: graph is empty, summary section omitted from prompt
- Huge codebase (>500 files): summary truncated to top modules, tool provides full detail
- No tsconfig.json: fall back to default compiler options + all .ts files in CWD
- Circular deps: detected, listed in summary, queryable via tool
- Freshness: file mtime check on each session start; too slow? add a
--no-graphflag