Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions cli/agent_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,25 @@ grepai trace callees "ProcessOrder" --json
grepai trace graph "ValidateToken" --depth 3 --json
` + "```" + `

### Property/Data Usage Tracing

Use ` + "`grepai refs`" + ` to find non-call property/state usage (reads/writes):

` + "```bash" + `
# Find where a property is read
grepai refs readers "uid" --json

# Find where a property is written
grepai refs writers "uid" --json
` + "```" + `

### Workflow

1. Start with ` + "`grepai search`" + ` to find relevant code
2. Use ` + "`grepai trace`" + ` to understand function relationships
3. Use ` + "`Read`" + ` tool to examine files from results
4. Only use Grep for exact string searches if needed
3. Use ` + "`grepai refs`" + ` for property/state readers and writers
4. Use ` + "`Read`" + ` tool to examine files from results
5. Only use Grep for exact string searches if needed

`

Expand Down Expand Up @@ -123,6 +136,18 @@ grepai trace callees "ProcessOrder" --json
grepai trace graph "ValidateToken" --depth 3 --json
` + "```" + `

#### 3. Property/Data Usage Tracing: ` + "`grepai refs`" + `

Use this when the target is a property/state key rather than a function call:

` + "```bash" + `
# Find readers of a property
grepai refs readers "uid" --json

# Find writers of a property
grepai refs writers "uid" --json
` + "```" + `

Use ` + "`grepai trace`" + ` when you need to:
- Find all callers of a function
- Understand the call hierarchy
Expand All @@ -140,9 +165,10 @@ Only fall back to Grep/Glob when:

1. Start with ` + "`grepai search`" + ` to find relevant code semantically
2. Use ` + "`grepai trace`" + ` to understand function relationships and call graphs
3. Use ` + "`Read`" + ` to examine promising files in detail
4. Use Grep only for exact string searches if needed
5. Synthesize findings into a clear summary
3. Use ` + "`grepai refs`" + ` for property/state readers and writers
4. Use ` + "`Read`" + ` to examine promising files in detail
5. Use Grep only for exact string searches if needed
6. Synthesize findings into a clear summary
`

const subagentMarker = "name: deep-explore"
Expand Down
11 changes: 7 additions & 4 deletions cli/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,21 @@ func registerCompletions() {
_ = searchCmd.RegisterFlagCompletionFunc("workspace", workspaceCompleter)
_ = watchCmd.RegisterFlagCompletionFunc("workspace", workspaceCompleter)
_ = mcpServeCmd.RegisterFlagCompletionFunc("workspace", workspaceCompleter)
for _, cmd := range []*cobra.Command{traceCallersCmd, traceCalleesCmd, traceGraphCmd} {
for _, cmd := range []*cobra.Command{traceCallersCmd, traceCalleesCmd, traceGraphCmd, refsReadersCmd, refsWritersCmd, refsGraphCmd} {
_ = cmd.RegisterFlagCompletionFunc("workspace", workspaceCompleter)
}

// Dynamic project completion for searchCmd --project (depends on --workspace value)
_ = searchCmd.RegisterFlagCompletionFunc("project", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
projectCompleter := func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
wsName, _ := cmd.Flags().GetString("workspace")
if wsName == "" {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return completeProjectNames(wsName), cobra.ShellCompDirectiveNoFileComp
})
}
_ = searchCmd.RegisterFlagCompletionFunc("project", projectCompleter)
for _, cmd := range []*cobra.Command{refsReadersCmd, refsWritersCmd, refsGraphCmd} {
_ = cmd.RegisterFlagCompletionFunc("project", projectCompleter)
}

// Dynamic ValidArgsFunction for workspace subcommands
workspaceShowCmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
Expand Down
61 changes: 61 additions & 0 deletions cli/completion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,64 @@ func TestCompleteProjectNames_should_return_project_names(t *testing.T) {
t.Fatalf("expected frontend and backend, got: %v", names)
}
}

func TestRefsCompletion_should_suggest_subcommands(t *testing.T) {
var buf bytes.Buffer
rootCmd.SetOut(&buf)
rootCmd.SetErr(&buf)
rootCmd.SetArgs([]string{"__complete", "refs", ""})
defer rootCmd.SetOut(nil)
defer rootCmd.SetErr(nil)

if err := rootCmd.Execute(); err != nil {
t.Fatalf("__complete refs failed: %v", err)
}

output := buf.String()
for _, sub := range []string{"readers", "writers", "graph"} {
if !strings.Contains(output, sub) {
t.Fatalf("expected completion output to contain %q, got: %s", sub, output)
}
}
}

func TestRefsProjectCompletion_should_return_workspace_projects(t *testing.T) {
tmpDir := t.TempDir()
oldHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", oldHome)

wsCfg := &config.WorkspaceConfig{
Version: 1,
Workspaces: map[string]config.Workspace{
"test-ws": {
Name: "test-ws",
Projects: []config.ProjectEntry{
{Name: "frontend", Path: "/tmp/frontend"},
{Name: "backend", Path: "/tmp/backend"},
},
},
},
}
if err := config.SaveWorkspaceConfig(wsCfg); err != nil {
t.Fatalf("failed to save test workspace config: %v", err)
}

var buf bytes.Buffer
rootCmd.SetOut(&buf)
rootCmd.SetErr(&buf)
rootCmd.SetArgs([]string{"__complete", "refs", "readers", "--workspace", "test-ws", "--project", ""})
defer rootCmd.SetOut(nil)
defer rootCmd.SetErr(nil)

if err := rootCmd.Execute(); err != nil {
t.Fatalf("__complete refs readers --project failed: %v", err)
}

output := buf.String()
for _, project := range []string{"frontend", "backend"} {
if !strings.Contains(output, project) {
t.Fatalf("expected project completion output to contain %q, got: %s", project, output)
}
}
}
3 changes: 3 additions & 0 deletions cli/mcp_serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ The server communicates via stdio and exposes the following tools:
- grepai_trace_callers: Find all functions that call a symbol
- grepai_trace_callees: Find all functions called by a symbol
- grepai_trace_graph: Build a call graph around a symbol
- grepai_refs_readers: Find property/state readers for a symbol name
- grepai_refs_writers: Find property/state writers for a symbol name
- grepai_refs_graph: Build a property usage graph (readers + writers)
- grepai_index_status: Check index health and statistics (includes RPG stats when enabled)
- grepai_rpg_search: Search RPG graph nodes by feature semantics
- grepai_rpg_fetch: Fetch hierarchy and edge context for a specific RPG node
Expand Down
Loading