Skip to content
Merged
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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to srcwalk are documented here.

## Unreleased

## [1.1.0] - 2026-07-13

### Added
- Added bounded local structural links to context call neighborhoods and bounded unique direct-call evidence with positional argument-to-parameter mappings to context and `trace callees --detailed`. Evidence uses exact source anchors and abstains when targets or local predecessors are ambiguous.

### Changed
- Aligned CLI error and overflow wording with command behavior, including unresolved callee labels and discover mode errors.
- Raised the default response budget from 5,000 to 6,000 tokens; explicit `--budget`, `--no-budget`, raw-read, overview, and evidence-row caps are unchanged.

## [1.0.1] - 2026-05-26

### Changed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "srcwalk"
version = "1.0.1"
version = "1.1.0"
edition = "2021"
description = "Tree-sitter indexed lookups — smart code reading for AI agents"
license = "MIT"
Expand Down
194 changes: 90 additions & 104 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ one binary, zero config.
- **Show** — read files, line ranges, symbols, headings, and capped raw pages.
- **Discover** — find definitions, usages, files, text, comments, and
field/member access evidence.
- **Trace** — inspect callers and callees with bounded depth, hub guards, and
unresolved-call labels.
- **Context** — build one-target packets with Flow Maps, local evidence, call
neighborhoods, and exact next commands.
- **Trace** — inspect callers and callees with bounded depth, hub guards,
unresolved-call labels, and bounded direct-call evidence.
- **Context** — build one-target packets with Flow Maps, local structural links,
call neighborhoods, and exact next commands.
- **Review & diff** — turn Git changes into bounded evidence packets for changed
files, symbols, and untracked files.
- **Compare & assess** — compare two known targets structurally, or scan blast
Expand Down Expand Up @@ -81,62 +81,25 @@ See [`CHANGELOG.md`](./CHANGELOG.md) for curated release notes. Maintainers shou

## Quick examples

Agent routing order lives in `srcwalk guide`; examples below are command reference, not a workflow.
These representative commands show the main shapes. Use `srcwalk --help` for the
full command and flag reference; agent routing lives in `srcwalk guide`.

```sh
# Read a file (structural view by default; raw pages are explicit)
# Read and drill into source
srcwalk src/auth.ts
srcwalk src/auth.ts:72 # drill into exact hit line
srcwalk src/auth.ts --section handleAuth # drill into symbol
srcwalk src/auth.ts --section 72 # focused line context
srcwalk src/auth.ts --section 44-89 # line range

# Discover definitions/usages/text/name globs/files
srcwalk discover handleAuth --scope src/ # definitions + usages
srcwalk discover handleAuth --scope src/auth.ts # exact-file scope
srcwalk discover handleAuth --scope 'src/**/*.ts' # glob scope
srcwalk discover handleAuth --scope src/auth.ts:40-90 # exact-file range scope
srcwalk discover "foo, bar" --scope src/ --scope tests/ # multi-symbol + multi-scope
srcwalk discover is_args --as access --scope src/ # file-grouped field/member access
srcwalk discover '*Controller' --as symbol --scope src/ --filter kind:class
srcwalk discover handleAuth --scope src/ --expand # inline source context
srcwalk discover '*.ts' --scope src/ # file globs are inferred
srcwalk discover handleAuth --scope src/ --exclude '*test*' # exclude file patterns
srcwalk discover 'alloc,copy' --match any --as text --scope src/ # literal text OR
srcwalk discover 'alloc,copy' --match all --as text --scope src/ # same-file co-occurrence
# Raw regex grep remains an rg job; srcwalk text discovery is literal navigation evidence.

# Trace callers (reverse call graph)
srcwalk trace callers handleAuth --scope src/
srcwalk trace callers decompileFunction --filter 'args:3' --scope src/
srcwalk trace callers handleAuth --count-by caller --scope src/ # grouped compact output

# Trace callees (forward call graph)
srcwalk trace callees handleAuth --scope src/
srcwalk trace callees handleAuth --detailed --filter 'callee:validateToken' --scope src/
srcwalk trace callees handleAuth --depth 2 --scope src/ # transitive

# Context and Review Packets with Flow Maps
srcwalk context src/auth.ts:handleAuth # one-target Flow Map + neighborhood + Next footer
srcwalk review --staged # staged change Review Packet
srcwalk review HEAD~1..HEAD --scope src # changed evidence + changed-symbol Flow Maps

# Compare two known targets structurally
srcwalk compare src/auth.ts:validateToken src/auth.ts:validateSession
srcwalk src/auth.ts:72
srcwalk src/auth.ts --section handleAuth

# Context (compact slice: ordered calls + local resolves + callers)
srcwalk context handleAuth --filter 'callee:validateToken' --scope src/

# Assess (heuristic blast-radius triage)
srcwalk assess validateToken --scope src/
# Find and follow code
srcwalk discover handleAuth --scope src/
srcwalk context src/auth.ts:handleAuth
srcwalk trace callers handleAuth --scope src/
srcwalk trace callees handleAuth --detailed --scope src/

# Deps (file coupling)
# Review changes and orient in a project
srcwalk review --staged
srcwalk deps src/auth.ts
srcwalk deps docs/guide.md # Markdown/HTML links and assets

# Overview / semantic directory orientation
srcwalk overview --scope src/
srcwalk overview --scope src/ --symbols # inline symbol kind/range anchors when budget allows
```

Discovery commands respect ignore files; explicit file reads can still inspect ignored paths.
Expand All @@ -150,7 +113,7 @@ Examples below use this repository. Timings may vary between machines; snippets

```
$ srcwalk src/evidence/next_action.rs
# src/evidence/next_action.rs (198 lines, ~1.2k tokens) [outline]
# src/evidence/next_action.rs (200 lines, ~1.2k tokens) [outline]

[1-] imports: std::collections::BTreeMap, std::fmt::Write as _, crate::evidence
[7-13] struct NextAction
Expand Down Expand Up @@ -179,13 +142,20 @@ $ srcwalk src/evidence/next_action.rs
[109-118] mod impl NextActionConfidence
[110-117] fn sort_rank
const fn sort_rank(self) -> u8
[120-127] mod impl NextActionConfidence
[121-126] fn from
[120-129] mod impl NextActionConfidence
[121-128] fn from
fn from(source: EvidenceSource) -> Self
[129-139] fn render_next_actions
[131-141] fn render_next_actions
pub(crate) fn render_next_actions(actions: &[NextAction]) -> String
[141-157] fn ordered_unique
[143-159] fn ordered_unique
fn ordered_unique(actions: &[NextAction]) -> Vec<NextAction>
[162-199] mod tests
[163] import use std::path::Path;
[165] import use super::*;
[168-185] fn render_orders_by_rank_then_dedupes_by_command
fn render_orders_by_rank_then_dedupes_by_command()
[188-198] fn duplicate_commands_keep_best_rank
fn duplicate_commands_keep_best_rank()

> Next: drill into a symbol with --section <name> or a line range
> Next: need raw file text? retry with --full, or use --section <range> for a smaller slice.
Expand All @@ -208,20 +178,20 @@ $ srcwalk src/evidence/next_action.rs --section "NextAction,render_next_actions,

---

## section: render_next_actions [129-139] (compact)
## section: render_next_actions [131-141] (compact)

129 │ pub(crate) fn render_next_actions(actions: &[NextAction]) -> String {
130 │ let actions = ordered_unique(actions);
131 │ let mut out = String::new();
131 │ pub(crate) fn render_next_actions(actions: &[NextAction]) -> String {
132 │ let actions = ordered_unique(actions);
133 │ let mut out = String::new();
... 8 lines omitted; narrow --section or raise --budget.

---

## section: ordered_unique [141-157] (compact)
## section: ordered_unique [143-159] (compact)

141 │ fn ordered_unique(actions: &[NextAction]) -> Vec<NextAction> {
142 │ let mut by_command = BTreeMap::<String, NextAction>::new();
143 │ for action in actions {
143 │ fn ordered_unique(actions: &[NextAction]) -> Vec<NextAction> {
144 │ let mut by_command = BTreeMap::<String, NextAction>::new();
145 │ for action in actions {
... 14 lines omitted; narrow --section or raise --budget.

> Caveat: compacted ~272/260 tokens; shown 3 symbols.
Expand All @@ -239,40 +209,44 @@ confidence: structural syntax
caveat: source-evidence navigation only; no runtime proof

## Target
- src/evidence/next_action.rs:141-157 ordered_unique
- src/evidence/next_action.rs:143-159 ordered_unique

## Flow Map
shape: 1 entry, 0 decisions, 1 loop, 1 exit, 4 actions
N1 entry :141-157 entry
next -> N2 action :142 BTreeMap::<String, NextAction>::new()
N2 action :142 BTreeMap::<String, NextAction>::new()
calls: BTreeMap::<String, NextAction>::new :142
next -> N3 loop :143-152 actions
N3 loop :143-152 actions
body -> N4 action :144-151 by_command .entry(action.command.clone()) .and_modify(|existing| { if action.sort_key() < exist…
next -> N5 action :154 by_command.into_values().collect()
N4 action :144-151 by_command .entry(action.command.clone()) .and_modify(|existing| { if action.sort_key() < exist…
calls: by_command .entry :144
reads: action.clone call_arg :151
loop_back -> N3 loop :143-152 actions
N5 action :154 by_command.into_values().collect()
calls: by_command.into_values :154
next -> N6 action :155 actions.sort_by(|left, right| left.sort_key().cmp(&right.sort_key()))
N6 action :155 actions.sort_by(|left, right| left.sort_key().cmp(&right.sort_key()))
calls: actions.sort_by :155
reads: left.sort_key().cmp call_arg :155; right.sort_key call_arg :155
next -> N7 return :157 end
N7 return :157 end
N1 entry :143-159 entry
definitions: actions parameter :143
next -> N2 action :144 BTreeMap::<String, NextAction>::new()
N2 action :144 BTreeMap::<String, NextAction>::new()
calls: BTreeMap::<String, NextAction>::new :144
writes: by_command assignment_lhs :144
next -> N3 loop :145-154 actions
N3 loop :145-154 actions
reads: actions condition :145
body -> N4 action :146-153 by_command .entry(action.command.clone()) .and_modify(|existing| { if action.sort_key() < exist…
next -> N5 action :156 by_command.into_values().collect()
N4 action :146-153 by_command .entry(action.command.clone()) .and_modify(|existing| { if action.sort_key() < exist…
calls: by_command .entry :146
reads: action.clone call_arg :153
loop_back -> N3 loop :145-154 actions
N5 action :156 by_command.into_values().collect()
calls: by_command.into_values :156
writes: actions assignment_lhs :156
next -> N6 action :157 actions.sort_by(|left, right| left.sort_key().cmp(&right.sort_key()))
N6 action :157 actions.sort_by(|left, right| left.sort_key().cmp(&right.sort_key()))
calls: actions.sort_by :157
reads: left call_arg :157; right call_arg :157; left.sort_key().cmp call_arg :157; +1 more
next -> N7 return :159 end
N7 return :159 end

## Exits
- :157 end
- :159 end

## Call Neighborhood
### Callees (ordered)
- L142 by_command = BTreeMap::<String, NextAction>::new()
- L151 by_command.entry(action.command.clone()).and_modify(|existing| { if action.sort_key() < existing.sort_key() { *existing = action.clone(); } }).or_insert_with(arg1=|| action.clone())
- L154 actions = by_command.into_values().collect()
- L155 actions.sort_by(arg1=|left, right| left.sort_key().cmp(&right.sort_key()))
- L144 by_command = BTreeMap::<String, NextAction>::new()
- L153 by_command.entry(action.command.clone()).and_modify(|existing| { if action.sort_key() < existing.sort_key() { *existing = action.clone(); } }).or_insert_with(arg1=|| action.clone())
- L156 actions = by_command.into_values().collect()
- L157 actions.sort_by(arg1=|left, right| left.sort_key().cmp(&right.sort_key()))

### Resolved local callees
[fn] NextAction src/evidence/next_action.rs:7-13
Expand All @@ -281,11 +255,11 @@ N7 return :157 end


### Callers
- [fn] render_next_actions src/evidence/next_action.rs:130
- [fn] render_next_actions src/evidence/next_action.rs:132

> Caveat: static context packet is capped; verify exact edges with trace commands.

> Next: srcwalk show src/evidence/next_action.rs:141-157 -C 20
> Next: srcwalk show src/evidence/next_action.rs:143-159 -C 20
> Next: srcwalk trace callers ordered_unique
> Next: srcwalk trace callees ordered_unique --detailed
```
Expand Down Expand Up @@ -336,18 +310,20 @@ hunks:
$ srcwalk discover "render_next_actions, Anchor" --scope src/evidence --scope src/commands --limit 2
# Search: "render_next_actions" in 2 scopes — 2 matches (1 definitions, 1 usages)
Scopes on this page: src/evidence (2), src/commands (0)
[fn] render_next_actions src/evidence/next_action.rs:129-139
[fn] render_next_actions src/evidence/next_action.rs:131-141
source: ast · kind: definition · confidence: structural syntax

## src/evidence/mod.rs:9 [usage]
→ [9] pub(crate) use next_action::{render_next_actions, NextAction};
## src/evidence/mod.rs:14 [usage]
source: text · kind: usage · confidence: text evidence
→ [14] pub(crate) use next_action::{render_next_actions, NextAction};

## Confirmed next context targets
> Next: srcwalk context src/evidence/next_action.rs:129-139
> Next: srcwalk context src/evidence/next_action.rs:131-141

(~101 tokens)
(~133 tokens)

> Next: 25 more matches available. Continue with --offset 2 --limit 2.
> Next: choose a confirmed context target above, or read raw hit evidence with `srcwalk show <path>:<line> -C 10`.
> Next: choose a confirmed context target above, or read exact hit evidence with `srcwalk show <path>:<line> -C 10`.

---
# Search: "Anchor" in 2 scopes — 2 matches (1 definitions, 1 usages)
Expand All @@ -372,20 +348,30 @@ Scopes on this page: src/evidence (2), src/commands (0)
pub(crate) fn display_relative_to(&self, scope: &Path) -> String
[58-64] fn display_with_path
fn display_with_path(&self, path: &str) -> String
[68-106] mod tests
[69] import use super::*;
[72-80] fn line_anchor_uses_existing_display_path
fn line_anchor_uses_existing_display_path()
[83-93] fn range_anchor_uses_existing_relative_display_path
fn range_anchor_uses_existing_relative_display_path()
[96-105] fn file_anchor_uses_existing_relative_display_path
fn file_anchor_uses_existing_relative_display_path()
[struct] Anchor src/evidence/anchor.rs:6-9
source: ast · kind: definition · confidence: structural syntax

## src/evidence/anchor.rs:18 [usage]
source: text · kind: usage · confidence: text evidence
→ [18] impl Anchor {
[6-9] struct Anchor
[12-16] enum AnchorRange
→ [18-65] mod impl Anchor
[19-24] fn file
pub(crate) fn file(path: &Path) -> Self

(~418 tokens)
(~449 tokens)

> Next: 38 more matches available. Continue with --offset 2 --limit 2.
> Next: choose a confirmed context target above, or read raw hit evidence with `srcwalk show <path>:<line> -C 10`.
> Next: 64 more matches available. Continue with --offset 2 --limit 2.
> Next: read exact hit evidence with `srcwalk show <path>:<line> -C 10`.
```
</details>

Expand Down Expand Up @@ -462,7 +448,7 @@ Bloom-filter pruning + length-sorted memchr + tree-sitter parse cache.
`trace callees`, `assess`, `deps`, `overview`.
- **Target-first reading** — `srcwalk <path>`, `<path>:<line>`, and `--section <symbol|range>`.
- **Multi-hop caller BFS** — up to 5 hops, hub guard, collision detection.
- **Forward callees** — resolved/unresolved calls, detailed ordered call sites, and depth support.
- **Forward callees** — resolved/unresolved calls, detailed ordered call sites, bounded unique-target argument mappings, and depth support.
- **Search ergonomics** — cross-naming-convention Did-you-mean, bare-filename auto-pick, typo tolerance.
- **Performance** — mmap walkers, Aho-Corasick, rayon-parallel search, mimalloc.

Expand Down
2 changes: 1 addition & 1 deletion npm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "srcwalk",
"version": "1.0.1",
"version": "1.1.0",
"description": "Code-intelligence CLI for AI agents — tree-sitter outlines, symbol search, caller/callee graphs, deps, overview",
"bin": {
"srcwalk": "run.js"
Expand Down
8 changes: 5 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ use clap::{ArgAction, Args, Parser, ValueEnum};
use clap_complete::Shell;
use srcwalk::ArtifactMode;

pub(crate) const DEFAULT_OUTPUT_BUDGET: u64 = 6_000;

/// srcwalk — Tree-sitter indexed lookups, smart code reading for AI agents.
/// Run `srcwalk guide` for the embedded, version-matched agent guide.
#[derive(Parser)]
#[command(name = "srcwalk", about, after_help = ROOT_HELP)]
#[command(name = "srcwalk", about, version, after_help = ROOT_HELP)]
pub(crate) struct Cli {
#[command(subcommand)]
pub(crate) command: Option<Command>,
Expand All @@ -24,7 +26,7 @@ pub(crate) struct Cli {
pub(crate) section: Option<String>,

/// Max tokens in response. Reduces detail to fit.
/// Default: 5000 unless --no-budget is set.
/// Default: 6000 unless --no-budget is set.
#[arg(long)]
pub(crate) budget: Option<u64>,

Expand Down Expand Up @@ -330,7 +332,7 @@ pub(crate) struct CommonArgs {
/// Scope root for search and relative path resolution.
#[arg(long, default_value = ".", action = ArgAction::Append)]
pub(crate) scope: Vec<PathBuf>,
/// Max tokens in response. Reduces detail to fit.
/// Max tokens in response. Reduces detail to fit. Default: 6000.
#[arg(long)]
pub(crate) budget: Option<u64>,
/// Disable default budget cap.
Expand Down
Loading
Loading