Summary
code_index extracts symbols from direct declarations (function Foo(), class Foo) but silently skips const exports wrapped in HOFs like React's memo(), forwardRef(), and lazy(). This is a very common React idiom — in a typical TypeScript+React codebase, the majority of UI components fall into this pattern and become invisible to code_search, code_context, and code_impact.
This is a particularly bad failure mode because the empty result is silent — calling code_impact("MyComponent") returns "No symbols found", which an AI agent may interpret as "no callers, safe to delete" rather than "indexer didn't see this symbol."
Environment
- CogniLayer v4.3.0
- Project: TypeScript + React + Vite + Tailwind
- Tree-sitter language pack: installed (other symbols index correctly)
Reproduction
In a .tsx file:
import { memo, forwardRef } from "react";
// Indexed correctly
export function useAuth() { /* ... */ }
// Not indexed
export const DiagnosticsTab = memo(function DiagnosticsTab({ analysis }) {
return <div>...</div>;
});
// Same issue
export const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
return <button ref={ref} {...props} />;
});
After code_index({ full: true }):
code_search("useAuth") -> Found, with full reference graph
code_search("DiagnosticsTab") -> "No symbols found"
code_search("Button") -> "No symbols found"
code_search("memo") -> "No symbols found" (despite being imported in 100+ files)
The tree-sitter AST appears to parse correctly. The gap is in symbol extraction — it doesn't recognize export const X = <Identifier>(<arg-with-name>) as defining a symbol X.
Suggested fix
When the extractor sees export const Foo = call(arg):
- Always register
Foo as an exported symbol of kind const/variable.
- If the call argument is a named function expression (
memo(function Bar() {})), register both Foo and Bar.
- If the wrapper is a known HOF (
memo, forwardRef, lazy, observer, withRouter...), tag kind as react_component.
Even step (1) alone would close the gap for the common case.
Why this matters for AI agent workflows
CogniLayer is positioned as the code-intelligence layer for AI agents, with code_impact as a mandatory check before risky changes. With this gap, agents:
- Run
code_impact("ComponentName") -> empty
- Conclude "no impact, safe to refactor"
- Break dozens of callers
A README note about the limitation ("use grep as fallback for React components") would also help in the meantime.
Happy to PR a fix if you can point at the symbol-extraction module.
Summary
code_indexextracts symbols from direct declarations (function Foo(),class Foo) but silently skipsconstexports wrapped in HOFs like React'smemo(),forwardRef(), andlazy(). This is a very common React idiom — in a typical TypeScript+React codebase, the majority of UI components fall into this pattern and become invisible tocode_search,code_context, andcode_impact.This is a particularly bad failure mode because the empty result is silent — calling
code_impact("MyComponent")returns "No symbols found", which an AI agent may interpret as "no callers, safe to delete" rather than "indexer didn't see this symbol."Environment
Reproduction
In a
.tsxfile:After
code_index({ full: true }):The tree-sitter AST appears to parse correctly. The gap is in symbol extraction — it doesn't recognize
export const X = <Identifier>(<arg-with-name>)as defining a symbolX.Suggested fix
When the extractor sees
export const Foo = call(arg):Fooas an exported symbol of kindconst/variable.memo(function Bar() {})), register bothFooandBar.memo,forwardRef,lazy,observer,withRouter...), tag kind asreact_component.Even step (1) alone would close the gap for the common case.
Why this matters for AI agent workflows
CogniLayer is positioned as the code-intelligence layer for AI agents, with
code_impactas a mandatory check before risky changes. With this gap, agents:code_impact("ComponentName")-> emptyA README note about the limitation ("use grep as fallback for React components") would also help in the meantime.
Happy to PR a fix if you can point at the symbol-extraction module.