Skip to content

fix(bash): handle real-world scripts safely#1

Draft
Adam0120 wants to merge 2 commits into
Omar-Elwazeery:feat/bash-script-supportfrom
Adam0120:fix/pr-1217-bash-realworld
Draft

fix(bash): handle real-world scripts safely#1
Adam0120 wants to merge 2 commits into
Omar-Elwazeery:feat/bash-script-supportfrom
Adam0120:fix/pr-1217-bash-realworld

Conversation

@Adam0120

Copy link
Copy Markdown

Summary

This is a focused follow-up for colbymchenry#1217. It keeps that PR's Bash extractor and adds the fixes needed for real deployment-script repositories:

  • vendor the official ABI-15 tree-sitter-bash 0.25.1 WASM and ship its MIT notice;
  • resolve canonical root-level script-directory variables such as S6_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) without guessing arbitrary dynamic paths;
  • preserve exact shell path semantics instead of trying .sh, .bash, or .bats suffixes;
  • add extraction, resolution, and full-graph regressions.

Reproduction and root cause

On a 101-script deployment repository, the grammar currently obtained from tree-sitter-wasms indexed only 1 script successfully and reported 100 parse errors. A minimal case "$1" in ... esac reproduces resolved is not a function under web-tree-sitter 0.25. The bundled grammar is from tree-sitter-bash 0.20.5 (ABI 13); the official 0.25.1 npm artifact is ABI 15 and parses the same corpus cleanly.

The original resolver also tried Bash filename suffixes before the requested path. Shells do not perform that extension search, so source ./helpers could be connected to helpers.bats even when the exact extensionless file existed—or when no runtime-resolvable file existed at all.

Real scripts commonly source files through a canonical variable holding the current script directory. This patch folds only an exact, root-level deterministic idiom, processes assignments in AST order, and invalidates the value on every later write. Function-body, here-doc, branch, arbitrary-variable, and reassignment cases stay unresolved by design.

Validation

  • npm run build
  • Bash-focused Vitest: 9/9 passed across extraction, resolution, and sync
  • Main-based integration branch: full extraction + sync suites, 615/615 passed
  • Real repository: 112 files indexed; 101/101 .sh files recognized as Bash; 3,840 nodes; 6,836 edges; 234 cross-file import edges
  • Verified cross-file chains including s6_wire_local.sh -> atomic-write.sh and _ensure_connect_wrapper -> dirextalk_atomic_write
  • WASM SHA-256: 8292919c88a0f7d3fb31d0cd0253ca5a9531bc1ede82b0537f2c63dd8abe6a7a (byte-identical to the official npm artifact)

Behavior boundary

This does not attempt general shell evaluation, environment expansion, command substitution, or fuzzy path inference. Dynamic cases remain unresolved so the graph prefers missing edges over incorrect ones.

@Omar-Elwazeery Omar-Elwazeery force-pushed the feat/bash-script-support branch from 1745053 to c8a48a2 Compare July 11, 2026 18:29
Omar-Elwazeery pushed a commit that referenced this pull request Jul 11, 2026
…tier when they collide with real callables (colbymchenry#1252)

handleExplore's named-symbol seeding treats every identifier-shaped query
token as "a symbol the agent named" and grants its definition the
named-FIRST sort tier. Natural-language questions broke this assumption:
ordinary words exact-matched unrelated callables ("check" ->
WalCheckpointValve.check, "serve" -> query-worker serve, "initialize" ->
DatabaseConnection.initialize), and those collisions outranked — and within
the per-repo file budget fully displaced — the corroborated answer files,
forcing the agent back to Read/Grep. The >3-def single-pick fallback had
the same hole: on grpc, the colbymchenry#1064 flagship query "add a parameter to
NewClient" itself tiered balancerStateAggregator.add's file to slot #1.

Guard: a shape-precise token (camelCase, PascalCase, snake_case,
qualified) seeds unconditionally — it is an unambiguous symbol reference.
A bare lowercase word seeds only defs whose file another query token
co-names (that token is itself an exact symbol name defined in the same
file — the "check drain fire" sibling-bag shape), which an incidental
English-word collision never is. Applied by filtering cands ahead of both
branches so the overloaded-name fallback is covered too.

Validated per the retrieval playbook: deterministic probes on this repo
(collision queries fixed; sibling-bag and single-camelCase retained), and
baseline-vs-fixed probes on the colbymchenry#1064 repos — Alamofire and excalidraw
byte-identical, grpc improved (the add-collision file drops out and
clientconn.go + dialoptions.go lead). Full suite green.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants