Skip to content

Releases

v0.11.7

Choose a tag to compare

@github-actions github-actions released this 08 Nov 16:33
b8f531f

Rebuild note: the graph format changed, so the first start after the upgrade builds each tree once.

Calls are linked only where the build allows them

  • A Rust name reaches only its crate and the crates it depends on. A call matched by name alone linked to the one definition of that name anywhere in the tree, even in a crate the caller cannot reach. It now links only when that definition is in the caller's crate or a crate its Cargo.toml names by path (directly or through [workspace.dependencies]).
  • A standard method on a value of unknown type links nowhere. x.len(), x.is_empty(), x.iter() … no longer point at a tree method of that name; find_callers lists such calls from the definition's own crate under undecided_callers.
  • A call to a definition the file has just renamed or removed is no longer taken as a local call, so detect_changes lists the dangling callers in the same file too.
  • r#name is the name name.

Tools

  • find_unused lists the definitions of Rust files no mod declaration reaches under not_compiled, and overview names those files. Crate roots, #[path], inline modules and include! are followed.
  • overview lists the crates of a Rust workspace and names a subsystem crate/stem, so the lib.rs of two crates no longer read as one subsystem.
  • affected_tests pages its tests with limit (default 50) and offset, and for Rust names the cargo test runs that cover them.
  • change_history returns the first body_lines (default 6) of each commit body and says how many it left out.
  • query_graph ranks an implementation before the tests that repeat its words, unless the question asks about tests.
  • explain_node: structurally_similar lists only the nearest definitions by embedding; callers, callees and the file's other definitions follow under nearby.

Security

  • Access-token hashes (SHA-256) and the random bytes of new tokens come from ring, the library rustls already uses for TLS. Stored token hashes stay valid.
  • SECURITY.md states the versioning policy and that release notes name every vulnerability a release fixes.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir

v0.11.6

Choose a tag to compare

@github-actions github-actions released this 07 Nov 23:56
9035886

Rebuild note: the graph format changed, so the first start after the upgrade builds each tree once.

Calls are linked only where the code says so

  • A method on a value of unknown type is a guess. x.is_empty() linked to the one tree method of that name, in whatever crate or package it lived; cycles and check_architecture then reported cycles and violations the build system rules out. Such a call is now ambiguous, so the inferred floor of cycles and of deny rules no longer sees it. impact, find_callers and affected_tests still include it.
  • A known type outside the tree holds its own methods. labels.get() with labels: HashMap no longer links to a tree get. A type in the tree is followed strictly, and a Rust method is found in every impl of its type, wherever the crate puts it.
  • Rust: use crate::…, super::… and self::… (lists and aliases included) scope a call to the file they name, so an imported function is inferred rather than ambiguous. A path keeps all its segments, so std::fs::read_dir never names the tree, and a path is never read as a value of the same name. f(x).g() names no receiver; Variant(x) and TupleStruct(x) are no calls. A name bound to a field (let bank = &mut self.data;) or a loop over fields of one type takes that type.
  • A placeholder reached from several languages links only into one of them.

Tools

  • detect_changes lists definitions the change removed or renamed (removed_symbols) and every definition still calling one (risk.dangling_callers), which raises the risk to high; affected_tests takes those callers as seeds. All definitions of a new, untracked file count as changed.
  • affected_tests lists a production helper named test_* only where a runner collects tests by name (Python, Ruby); elsewhere the path or a test attribute decides.
  • find_unused no longer counts a local of the same name (let x = …) as a use, and leaves out methods of a Rust impl Trait for Type.
  • explain_node names the same callers as find_callers, once each; its similar definitions come without placeholders and most alike first.
  • The cycles description states its real default.

Servers

  • A backend reached at the moment it ends no longer drops the client that just connected.
  • --linger and --sleep-after are checked before a backend starts; an edited language rule file, and a rebuilt binary of the same version, get a backend of their own.

Releases

  • Each release is now published to the MCP registry by the release workflow.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir

v0.11.5

Choose a tag to compare

@github-actions github-actions released this 07 Nov 17:43
b738fc0

Servers

  • serve works where the shared backend cannot. In 0.11.4 a client whose state directory was not writable, as in the container image, got an error instead of a server. serve now reaches for the shared backend first and, when that fails, serves the client itself.

Security

  • SECURITY.md states the threat model: what the index defends the machine against, that tool answers carry repository text to the model unfiltered, and how to check the binary without trusting its author.
  • The OpenSSF Scorecard is published for the repository.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir

v0.11.4

Choose a tag to compare

@github-actions github-actions released this 07 Nov 16:44
6722813

Servers

  • One server per tree, however many assistants use it. Over stdio, serve now relays to a backend for the tree on a Unix socket in the per-user state directory (directory 0700, socket 0600) and starts it when none runs. The backend holds the graph, the watcher and the sleep, and answers every client. Several assistants on one tree build and watch it once; a connection a client forgets to close costs a few megabytes and no polling.
  • The backend accepts connections before it reads the tree, so a client connects at once. A lock lets one client start it while the others wait, a socket left by a backend that died is replaced, and a client whose backend went away starts a new one and sends the request again.
  • The backend ends a minute after its last client leaves (--linger <seconds>). Backends are keyed by version, tree and options, so an upgrade never talks to an older one. --own-process keeps a server per client; Windows always does.

Releases

  • The Homebrew tap and the Scoop bucket move only once the release is published. A release that failed after its build left them naming archives that did not exist.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir

v0.11.3

Choose a tag to compare

@github-actions github-actions released this 07 Nov 15:04
aeec2a3

Servers

  • Idle servers cost almost nothing. A watching server polled its whole tree four times a second while nothing happened. It now waits longer while files stay still, up to two seconds, and never less than ten walks of the tree.
  • Servers sleep. After ten minutes without a request a server lets its graph go and stops watching; the next request loads it again first. The connection stays open, since a stdio client does not start a stopped server again. --sleep-after <minutes> sets the wait, 0 keeps the graph.
  • Replaced servers can be found. A client that starts a new server without closing the old connection leaves the old one running. glasir servers lists every running server with its tree, client and last request; --stop-replaced ends those a newer server for the same tree and client took over without a request since.

Servers from earlier versions record no status and are not listed.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir

v0.11.2

Choose a tag to compare

@github-actions github-actions released this 07 Nov 13:20
6c51259

Fixes

  • The server no longer stops on a snippet. Tools other than the scanners lexed files without their language's syntax: a JavaScript regexp holding a quote read as a string to the end of the file, a snippet range ran past its definition and the server panicked. Every reader of tokens now uses the scanner's configuration, and a range that does not fit the file is refused.
  • Names stay within their language. A name used in one language no longer counts as a use of a definition in an unrelated one, so a JavaScript variable no longer reaches Rust tests.
  • A documentation heading is no class. A struct sharing its name with a heading resolves its methods again.
  • Rust aliases and unit structs end at their semicolon instead of taking the next item into their range and snippet.

Tools

  • get_code_snippet names the lines of other definitions of the same name in the file (also_defined_at) and takes max_lines, with the line it would go on at.

The snapshot format and the scanner identity changed; the first analyse after upgrading rebuilds the graph.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir

v0.11.1

Choose a tag to compare

@github-actions github-actions released this 06 Nov 21:09
7f2a151

0.11.0 was tagged but never published: a timing test stopped its build. This is that release.

Highlights

  • Inherited methods resolve in every class-based language. Java, Kotlin, C#, Swift, C++, Scala, Rust, Python, JavaScript, TypeScript, Go, PHP, Ruby and Dart state their bases, and a call follows them up the chain to the method that answers it, including across traits, mixins, extensions and Go embedding. Only classes the tree defines count, and an import or the file's package decides which of two same-named classes is meant.
  • find_callers says what it cannot decide. Calls by a name several definitions could answer are listed as undecided_callers instead of reading as if nothing called the symbol.
  • Rust calls through a typed value resolve. A field, parameter or let binding states the type, so self.path.grant() reaches that type's method even when the name alone is ambiguous.
  • Very large trees finish. A language check walked the whole symbol table per definition, which on the largest trees never ended. Crafted files no longer cost the square of their length either: nesting and lookahead are bounded, and files stay within 1 MiB.
  • A served tree is not trusted to run anything. Every git call Glasir makes checks the repository's own configuration first and refuses, by name, a repository whose .git/config sets something git would run on a diff, a log or the index: core.fsmonitor other than git's own daemon, diff.external, a diff driver's command or textconv, filter.*. Before, serving a checkout with a nested repository carrying such a setting ran it on the next detect_changes, affected_tests, impact-of or review. Every git child now has a deadline and a bound on the output read, and leaves the optional index locks alone.
  • Release archives carry build provenance. Every .tar.gz and .zip is attested by the release workflow and verifiable with gh attestation verify <archive> --repo Attackwave/glasir; the .sha256 beside it stays. The review action verifies that before it runs a downloaded release, and refuses releases before 0.11.0, which carry none.

Hardening

  • glasir view serves its map with the connection cap, the deadlines and the thread per connection the MCP endpoint already had; one idle client or one wide viewport query no longer holds the map for everyone, and a viewport query costs at most the nodes it returns.
  • The map page escapes the names it embeds: a file whose name ends a script element could run in the map's origin before.
  • A stored .glasir-graph is checked against itself after reading (offsets, edge arrays, targets, names, communities, hubs) and rebuilt when it does not agree, as for a stale version; a crafted file could stop the server before.
  • The release workflow holds write access only in the jobs that publish; the tools it installs are pinned by version, the container's base images by digest, and the image build leaves out the files Glasir writes beside a tree.

Assistants

  • glasir install adds a session hook that points a coding assistant at the graph in an indexed tree, and the repository ships a plugin with a marketplace entry.

Scanners

  • Block balance on real code: blocks, strings and comments no longer derail a file in Ruby, TypeScript, JSX, Kotlin, Dart, Elixir, PHP, C and C++ macros and conditional branches, Java and C# constants, or shell. Heredocs, #{...} and ${...} with nested quotes, raw strings, regexps and JSX text are read as what they are.
  • Classes and methods defined in one file resolve per class; super.run() in run no longer links to itself.
  • overview states the server version and when the index was loaded, and warns about directories that repeat each other.
  • impact of a class or module reaches through its members.

Review

  • A pull request from a fork, whose token cannot comment, no longer fails the action's comment step: the report is in the job summary and the gate applies.
  • Release notes come from the tree (.github/releases/<tag>.md) and travel through the release's pull request.

Operations

  • The flood regression test compares cost against a quarter of the input instead of a fixed time, so a slower runner fails nothing.
  • Partition floor 58 -> 62.

The snapshot format and the scanner identity changed; the first analyse after upgrading rebuilds the graph.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 02 Nov 23:21
0a9a9c2

Highlights

  • Several repositories as one tree. glasir serve on a directory holding more than one git repository (up to two levels down) serves them as one graph: HTTP routes already joined across repositories, and now detect_changes, co_changes, change_history, impact-of and the git hooks work per repository, with each path prefixed by its repository.
  • Workflows and local actions are in the graph. .github/workflows/*.yml and every action.yml are read for what they express: jobs are symbols, needs connects them, and uses: ./… and the scripts a step runs connect the job to those files. impact on a script shows the workflow that runs it; glasir review on a workflow change has symbols to report. .github/workflows, .github/actions and .github/scripts enter the indexed scope; issue templates, dependabot and the rest of .github stay out.
  • Rust calls through a module resolve. commits::changes() reaches changes in commits.rs — beside the caller, under the crate's src/, or as a mod.rs — where before the bare name was refused whenever two files defined it.

Review

  • A symbol a test reads through a reference (a constant, a table a check iterates) now counts as reached by that test; review reported such code as untested before.
  • A file the history says usually changes with a changed one is a medium reason now, not high: a reminder, not a blocked merge on its own. high is a changed symbol with callers and no test reaching it.

Fixes

  • Directories named parsers, bench/deep or bench/langs were left out of every tree. Those rules belonged to this repository and are in its own .glasirignore now; the indexer's fixed rules keep only tmp and vendor at the root and target, node_modules and dot-directories anywhere.
  • Shell scripts: only the command is a call. set -e no longer yields a call to e, echo hi none to hi, local owner=… none to owner; flags, variables, operands and continuation lines are arguments. A shell script has a top-level node even when it calls nothing, so a step running it has something to point at.
  • A Rust value named like a file (community.get(i) beside community.rs) was read as a call into that file.
  • A root action.yml read as plain YAML produced dozens of nodes named after its keys.

The snapshot format and the scanner identity changed; the first analyse after upgrading rebuilds the graph.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir
  • Archives for Linux (static, x86_64 and arm64), macOS (arm64 and x86_64) and Windows are attached, each with a SHA-256 checksum, the licences and an SBOM.

v0.9.1

Choose a tag to compare

@github-actions github-actions released this 25 Oct 03:05
d988140

Fixes

  • glasir review --fail-on <level> gated nothing. The command-line parser took --fail-on high as a flag followed by a revision named high, so the merge gate in 0.9.0 never fired unless written --fail-on=high; the GitHub Action passes the spaced form, so its fail-on input had no effect. The same applied to impact-of --depth <n> and guard --rules <file>. All three read their value now, and a check makes sure every option the code reads is parsed with one.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir
  • Archives for Linux (static, x86_64 and arm64), macOS (arm64 and x86_64) and Windows are attached, each with a SHA-256 checksum, the licences and an SBOM.

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 01:22
6610a70

Highlights

  • A review on every pull request. glasir review [rev] prints what detect_changes and affected_tests know about a change, as Markdown: the risk level and its reasons, the changed symbols, their dependents by distance, the tests that reach the change, and the files the graph does not cover. --fail-on medium turns it into a merge gate. A GitHub Action in this repository (Attackwave/glasir@v0.9.0) runs it on each push to a pull request and keeps one comment current; the graph is built on the runner and no source leaves it.
  • Five more coding assistants. glasir install registers with Copilot CLI, Roo Code, Kiro, Amp and Continue, each in its own project file. That makes 14 clients, from one command in the project directory.
  • glasir export writes the graph as node-link JSON, the form glasir import reads: every symbol by name, every edge with the tier it was resolved at. For moving a graph into another tool, or comparing two builds.

Agents

  • At the handshake, the server now tells a client when to reach for which tool: overview in an unfamiliar tree, query_graph for a question or a file's path, get_code_snippet instead of opening the file, impact or find_callers before a change, detect_changes and affected_tests before a commit. Clients speaking the newer protocol revision received no instructions before.

Install

  • Homebrew: brew install attackwave/glasir/glasir
  • Scoop: add the bucket Attackwave/scoop-glasir, then run scoop install glasir
  • Archives for Linux (static, x86_64 and arm64), macOS (arm64 and x86_64) and Windows are attached, each with a SHA-256 checksum, the licences and an SBOM.