Skip to content

Code Analysis

Sia edited this page May 31, 2026 · 3 revisions

Code Analysis

Three independent in-process tools that read the workspace tree:

Tool URL Purpose
Gradle wrapper /projects/{id}/wrapper Show current wrapper version + 1-click upgrade
Code statistics /projects/{id}/stats File / LoC / size per language
Workspace grep /code-search Cross-project source-tree search

None of these depend on external binaries (no cloc, no ripgrep). The walks are sequential JVM I/O — fine for typical Android projects (a few thousand files), noticeable but acceptable on multi-GB monorepos.

Gradle wrapper management

What's shown

/projects/{id}/wrapper parses gradle/wrapper/gradle-wrapper.properties:

  • Current version — from distributionUrl (https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip9.5.1).
  • Distribution typebin (binary only, ~150 MB download) or all (binary + source + docs, ~400 MB).
  • Raw URL — copy/inspect.
  • Properties file path — for direct shell editing if you need it.

Upgrading

Type a new version (regex ^[0-9]+(\.[0-9]+)*(-rc-[0-9]+)?$), pick bin or all, submit. Server:

  1. Reads the existing file.
  2. Replaces only the distributionUrl= line. Other properties (zipStoreBase, validateDistributionUrl, etc.) are preserved.
  3. Writes to .tmp and atomically moves into place.

Next ./gradlew invocation will download the new distribution automatically. The audit log records wrapper.update with the version in the detail JSON.

Safety

  • Version regex blocks shell / path injection.
  • Distribution type whitelist (bin / all) only.
  • Atomic write — a crashed save can't leave a half-written .properties.

What this doesn't do

  • It does not edit gradle.properties (use Env Files Quick Edit for that).
  • It does not validate that the upgraded version is compatible with your project's plugins. A --refresh-dependencies rebuild is the fastest way to catch issues.

Code statistics

Method

/projects/{id}/stats walks the project root and:

  1. Filters out .git, build, .gradle, node_modules, .idea, .vibecoder/.
  2. Skips binary extensions (30+ — .apk / .aab / .jar / .png / .mp4 / .ttf / …).
  3. Skips files larger than 5 MB.
  4. Classifies remaining files by extension into one of 35+ languages (Kotlin / Java / Swift / Go / Rust / TS / JS / Vue / Svelte / Python / Ruby / SQL / GraphQL / Terraform / …).
  5. Counts lines (Files.lines(p).count()).

This is not cloc-grade accuracy — blank lines and comments are counted. But for "is this app mostly Kotlin or mostly XML?" the result is right.

Output

Column Notes
Language Friendly name (e.g. Kotlin, not kt)
Files Count
Lines Total
Bar Visual share of total lines (relative to the biggest language)

Top-line summary cards: total files / total lines / total bytes / walk duration ms.

Workspace grep (/code-search)

The companion to /history (conversation search) and /logs (build-log search) — this one walks source files.

Filters

  • Query — required (≥ 1 char). Empty query returns an empty result, preventing accidental "dump everything" requests.
  • Project filter — optional substring match against the project id.
  • Case sensitive — checkbox.

Behavior

  • Walks every project directory at the top of workspace.root (skipping .vibecoder and other dotfiles).
  • Per file: skips if >5 MB, skips if a known binary extension.
  • Reads line-by-line; stops the file scan as soon as 200 total matches accumulate.
  • Match preview shows the full line (clipped to 400 chars) with the matched substring wrapped in <mark style="background:#facc15">.
  • File link goes to /projects/{id}/view?path=<file> — the existing file viewer renders the file with syntax highlighting (highlight.js) and navigates to the line.

Performance characteristics

Workspace size Typical scan time
1 small Android project (~500 files, 50 K LoC) < 1 s
5 mid-size projects (~5 K files, 500 K LoC) 1-3 s
10+ large projects (10 K+ files, 1M+ LoC) 5-15 s

Future improvement: detect rg in $PATH and use it for big workspaces.

Why no regex?

The current input field treats the query as a literal substring (with Regex.escape applied for the <mark> highlight). Regex would be more powerful but also a footgun (catastrophic backtracking on user input). A future version may add an explicit "regex mode" checkbox with a timeout-bounded Matcher.

Symbol definition lookup

Best-effort "jump to definition" for Kotlin and Java without spawning a real Language Server. The lookup walks the project tree and matches six declaration patterns:

Pattern Kind
fun <name>( (incl. generics + receiver) fun
(open|abstract|sealed|inner|data|enum|annotation|value)* (class|interface|object) <name> class
(val|var) <name> [:=] (top-level + property) val
Java (public|protected|private|static|final|abstract|synchronized|native) ... <name>( fun
Java (class|interface|enum) <name> class
typealias <name> = typealias

UI

/projects/{id}/symbols is an admin SSR page with a single text-input form. The query must be a valid Kotlin / Java identifier ([A-Za-z_][A-Za-z0-9_]{0,79}); arbitrary regex is rejected so users can't slow the scan or smuggle injection.

Each hit links to /projects/{id}/view?path=<rel>&line=<n> — the file viewer reads the line query parameter, smooth-scrolls the highlighted code to the target row, and flashes a yellow outline for 1.5 s.

┌────────────────────────────────────────────────────────────────┐
│  심볼 정의 찾기 — my-app (my-app)                              │
│                                                                │
│  심볼 이름  [ onCreate ___________________ ]  [검색]  [grep으로→] │
│                                                                │
│  Kind   Location                          Source line          │
│  fun    app/src/.../MainActivity.kt:24    override fun onCreate│
│  fun    app/src/.../SettingsActivity.kt:18  override fun onCreate│
└────────────────────────────────────────────────────────────────┘

The console page sidebar gets a ⇢ 정의 검색 chip next to git so the search is reachable from any project workflow.

JSON API

curl -H "Authorization: Bearer $TOKEN" \
  'http://localhost:17880/api/projects/my-app/symbols?name=onCreate'
{
  "hits": [
    { "relPath": "app/src/.../MainActivity.kt",
      "lineNumber": 24, "kind": "fun",
      "line": "override fun onCreate(savedInstanceState: Bundle?) {" }
  ]
}

Trade-off (vs. Kotlin LSP)

A real kotlin-language-server (or bash-language-server, etc.) would give precise resolution (overloads, nested types, references, rename refactoring) but adds a separate JVM (~300 MB image, ~200 MB RAM at idle, 10–30 s cold start) for the Kotlin path alone. For the single-user dev profile defined in CLAUDE.md §1 the simpler regex scan covers ~90% of "jump to definition" cases in single-digit milliseconds with zero new dependencies.

LSP integration remains the right move when:

  • You need references-to (Find Usages).
  • You routinely jump into nested types with shadowed names.
  • You want IDE-grade hover / signature popups.

Track interest in the roadmap section below.

Limitations

  • Java method patterns recognize the most common modifiers (public/protected/private/static/final/abstract/synchronized/ native). Methods with a very long generic return type, or with a leading comment block on the same line, may not match.
  • Hits are line-level; the actual declaration token is highlighted in the file viewer (whole line outlined, not the symbol itself).
  • 100-hit hard cap, 5 MB per-file size cap, plus the standard exclusion list (build/ / .gradle/ / node_modules/ / .idea/).
  • .kt, .kts, .java, .groovy only. XML / properties / Markdown declarations don't appear here — use workspace grep.

Roadmap

  • CVE matching on dependencies — see Dependency Audit for the related Gradle dependency tree feature; CVE lookup is the obvious add.
  • ripgrep fallback for code-search — auto-detect rg in $PATH and delegate.
  • Per-language tokei-style stats — separate code / comment / blank line columns. Probably a small library import.
  • Full LSP integration (references, rename, hover) beyond the current regex-based symbol lookup — requires a separate JVM / image bump and is tracked separately.

Related

  • Build Cache Management — clean Gradle / Android / npm caches when stats show your project ballooning.
  • Dependency Audit — Gradle dependency tree with coordinate extraction (sibling feature).
  • Backup & Restore/backup excludes the same caches that bloat your stats.

Clone this wiki locally