diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d0fa7c..7dd7755 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,6 +94,7 @@ JevGate now works in a coding agent's loop. `jevgate hook` checks each edit and - It merges into the files already there and keeps their key order, layout and the text of every number and string it does not change (`1e3`, a 30-digit integer, `"\/"`), so running it again changes nothing; `--remove` takes out what it wrote and nothing else, and `--dry-run` shows what would change. Every file is read before the first is written, so a settings file that is not plain JSON stops it with nothing written. On a scratch home and repository holding other tools' settings for all five agents, a run took 0.04 s at the median, a second run changed nothing, and `--remove` gave 11 of the 13 files back byte for byte; the other two, written on one line, came back laid out over several. - Claude Code and Codex run `jevgate hook || echo '{"systemMessage": …}'` and Gemini CLI `jevgate hook; exit 0`, so a `jevgate` missing from the agent's `PATH`, or one before 0.27, is shown and blocks nothing: with a plain `jevgate hook` and JevGate 0.25.0 on the `PATH`, Claude Code 2.1.283 dropped the prompt and Codex 0.153.4 ended the turn, and Gemini CLI denies on any exit but 0 and 1. These commands stay the same across versions, as Codex and Gemini CLI trust a hook by its command. After writing, it runs the `jevgate` on your `PATH` on an event it ignores, passing over npx's temporary copy, and warns when that one cannot answer the hooks. - A Claude Code plugin in this repository bundles the same hooks, the MCP server (`jevgate mcp`) and a skill on acting on findings (`/jevgate:findings`): `/plugin marketplace add Tech-Byte-Frontier/jevgate`, then `/plugin install jevgate@jevgate`. It runs `jevgate` 0.27 or later from the `PATH`, installed separately. The coding-agents page sets up Claude Code by hand with the same hooks, and a test holds the plugin and the page to what `init --agent claude` writes. +- An npm package, `@tech-byte-frontier/jevgate`, runs the release binary where Homebrew and cargo are not at hand: `npm install -g @tech-byte-frontier/jevgate` puts `jevgate` on the `PATH` agents' hooks use. Its first run downloads the release archive of its version from GitHub, checks it against the release's SHA-256 checksums and caches the binary (3.9 s for 0.25.0); later runs add about 30 ms to the binary's start. It has no dependencies and no install scripts. The unscoped `jevgate` on npm is a different project. - **Gaming guards.** A check with `--base`, and each check of the agent hook, report what the change does to the checks around the code: new suppressions of other tools (`# noqa`, `eslint-disable`, `@ts-ignore`, `#[allow(…)]`, `//nolint`, `@SuppressWarnings` and about 50 more) and new `jevgate: allow` comments, skipped, focused or removed tests, edits to `jevgate.toml` or the baseline, including one that leaves it unreadable, a file of code JevGate stops judging because it now reads as generated code, grew past `max_file_bytes`, is no longer UTF-8 or no longer parses (a Python file given a Latin-1 coding line and one Latin-1 byte had passed with no guard), and a rewritten test Jev reads as checking less than before. - They follow the findings in the agent text, are `guards` in the JSON report and the MCP tools' results, and are GitHub notices. They never fail the gate: most are legitimate, and JevGate cannot see the other tools' findings. A moved line or a test moved to another file of the change adds nothing, but a comment, attribute or decorator moved or copied above other code is added, since it applies to code it did not before: moving a `jevgate: allow` comment from an accepted function to the long one a turn wrote had accepted it with no guard. On the last five commits of 142 corpus projects the scan reported 129 guards, each checked against Git, and it adds 29 ms at the median to a check of a last commit. - The rewritten-test question is asked with the test before and after and the functions of its file the new version newly calls. On 15 corpus tests in 9 languages weakened by hand for the test it answered 0.92 to 0.96, and on 15 rewrites of them that check as much, 0.27 or less; of the 52 tests the corpus projects' last commits rewrote it raised one, a Go test that stopped checking an error's text and made one up when none came. Its recall on weakenings made in real changes is not measured yet. diff --git a/README.md b/README.md index 1b26f8f..23e6b49 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,12 @@ It reads Rust, Python, JavaScript, TypeScript, Go, C#, Ruby, PHP, Java and Bend ```sh brew install tech-byte-frontier/tap/jevgate # macOS and Linux, with Homebrew curl -fsSL https://raw.githubusercontent.com/Tech-Byte-Frontier/jevgate/main/install.sh | sh # Linux and macOS +npm install -g @tech-byte-frontier/jevgate # any platform with Node 20 or later cargo binstall jevgate # any platform, with cargo-binstall cargo install jevgate --locked # build from source; needs Rust 1.90 or later ``` -Releases have binaries for Linux, macOS and Windows with checksums and build provenance. Reviewing needs an API key from [TypeSafe](https://console.typesafe.ai/settings/keys) or [OpenRouter](https://openrouter.ai/settings/keys), which serve the same model at the same price; a [Vercel AI Gateway](https://vercel.com/docs/ai-gateway/authentication-and-byok/api-keys) key is accepted too, but has not been tried with a real key yet. [Install](https://tech-byte-frontier.github.io/jevgate/install.html) covers verifying a download, shell completions and man pages. +Releases have binaries for Linux, macOS and Windows with checksums and build provenance. Reviewing needs an API key from [TypeSafe](https://console.typesafe.ai/settings/keys) or [OpenRouter](https://openrouter.ai/settings/keys), which serve the same model at the same price; a [Vercel AI Gateway](https://vercel.com/docs/ai-gateway/authentication-and-byok/api-keys) key is accepted too, but has not been tried with a real key yet. [Install](https://tech-byte-frontier.github.io/jevgate/install.html) covers verifying a download, the npm package, shell completions and man pages. ## Quick start diff --git a/npm/lib/launcher.js b/npm/lib/launcher.js index 5bb0755..34d75b5 100644 --- a/npm/lib/launcher.js +++ b/npm/lib/launcher.js @@ -14,7 +14,7 @@ const { spawnSync } = require("node:child_process"); const RELEASES = "https://github.com/Tech-Byte-Frontier/jevgate/releases/download"; const INSTALL_PAGE = "https://tech-byte-frontier.github.io/jevgate/install.html"; -/** A release archive is about 7 MB; a download slower than this has stalled. */ +/** A release archive is about 10 MB (0.30.0); a download slower than this has stalled. */ const DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1000; /** Release builds by Node's platform and architecture. Windows on Arm runs the x64 build. */ @@ -173,6 +173,7 @@ async function main(args, host = {}) { home = os.homedir(), streams = process, fetchBytes = download, + sums = shippedSums(), } = host; const version = require("../package.json").version; const build = target(platform, arch); @@ -184,7 +185,7 @@ async function main(args, host = {}) { build, cache: cacheDirectory(env, platform, home), fetchBytes, - sums: shippedSums(), + sums, log: (message) => streams.stderr.write(`jevgate: ${message}\n`), }); } catch (error) { diff --git a/npm/test/launcher.test.js b/npm/test/launcher.test.js index b1f084b..5cd5ea9 100644 --- a/npm/test/launcher.test.js +++ b/npm/test/launcher.test.js @@ -151,7 +151,8 @@ test("the launcher runs the binary with the same arguments and exit code", { ski const home = path.join(directory, "home"); const env = { XDG_CACHE_HOME: path.join(directory, "xdg") }; const captured = streams(); - const run = () => launcher.main(["check", "--base", "HEAD"], { env, home, streams: captured, fetchBytes: served.fetchBytes }); + // `sums: null`: no shipped copy, even when one was downloaded into the package to publish it. + const run = () => launcher.main(["check", "--base", "HEAD"], { env, home, streams: captured, fetchBytes: served.fetchBytes, sums: null }); assert.equal(await run(), 3); assert.equal(fs.readFileSync(record, "utf8").trim(), "check --base HEAD"); assert.match(captured.out.stderr, /downloading JevGate/); diff --git a/site/src/install.md b/site/src/install.md index 230fbb5..3c29306 100644 --- a/site/src/install.md +++ b/site/src/install.md @@ -3,12 +3,15 @@ ```sh brew install tech-byte-frontier/tap/jevgate # macOS and Linux, with Homebrew curl -fsSL https://raw.githubusercontent.com/Tech-Byte-Frontier/jevgate/main/install.sh | sh # Linux and macOS +npm install -g @tech-byte-frontier/jevgate # any platform with Node 20 or later cargo binstall jevgate # any platform, with cargo-binstall cargo install jevgate --locked # build from source; needs Rust 1.90 or later ``` Each [release](https://github.com/Tech-Byte-Frontier/jevgate/releases) has binaries for Linux (x86_64 and arm64, static), macOS (Apple silicon and Intel) and Windows (x86_64), with SHA-256 checksums and build provenance: `gh attestation verify --repo Tech-Byte-Frontier/jevgate`. The install script checks the checksum and installs to `~/.local/bin`; set `JEVGATE_VERSION` or `JEVGATE_INSTALL_DIR` to change the version or place. +The npm package `@tech-byte-frontier/jevgate` runs the same binaries. On its first run it downloads the release archive of its own version from GitHub, checks it against the release's SHA-256 checksums, and keeps the binary in your cache directory (`~/Library/Caches/jevgate`, `$XDG_CACHE_HOME/jevgate` or `~/.cache/jevgate`, `%LOCALAPPDATA%\jevgate\cache`); later runs start it directly, with the same arguments and exit code. It has no dependencies and runs nothing when installed. `npx @tech-byte-frontier/jevgate check` runs it once without installing, but agents' hooks need `jevgate` on the `PATH`, which `npm install -g` provides. The unscoped npm package `jevgate` is a different project. + `jevgate completions bash|zsh|fish|powershell` prints a shell completion script and `jevgate man` a man page; Homebrew installs both. Reviewing needs an API key. Jev, the model JevGate asks, is served by TypeSafe and by two gateways, at the same price: diff --git a/site/src/privacy-and-cost.md b/site/src/privacy-and-cost.md index 0d60b38..b2ac144 100644 --- a/site/src/privacy-and-cost.md +++ b/site/src/privacy-and-cost.md @@ -10,6 +10,7 @@ - **Where requests go:** to TypeSafe, or through OpenRouter or Vercel AI Gateway, which pass TypeSafe's API through. Each keeps what it receives under its own terms: see [retention and training](#retention-and-training). - **Cost:** every run prints its input tokens and an estimated cost, priced by the model that answered: Jev 1.13 costs $0.042 per million input tokens, under any of its names (`jev-1.13.0`, OpenRouter's `typesafe/jev-1.13` and its dated `typesafe/jev-1.13-20260917`), and output is free. When a response reports no token usage, or names a model without a version, such as Vercel AI Gateway's `typesafe-ai/jev`, whose price follows whatever version it points to, the cost is shown as unknown, never as $0. Cached answers cost nothing, and a request sends only the questions the cache does not answer. - **The agent hook:** `jevgate hook` uploads what `jevgate check` would for the files an agent edits, under the same patterns, and nothing else. Installed in `~/.claude/settings.json` or another user-level file, as `jevgate init --agent` does unless you pass `--project`, it checks every Git repository the agent works in, including ones without a `jevgate.toml` to bound the uploads; install it in each repository's settings to choose. +- **The npm package** downloads its version's release archive, and the checksums when the package holds none, from GitHub on that version's first run, and nothing after that. - **Guards:** a check with `--base` and the agent hook compare `jevgate.toml`, the baseline and the changed files with their previous versions locally. Two questions send more, within the upload patterns: a test whose assertions the change rewrote, before and after, with the functions of its file the new version newly calls; and a comment or string that addresses a reviewer, with the three lines around it. - **Secrets:** out of scope on purpose, because judging secrets would mean uploading them. Use a local secret scanner.