rustcodegraph 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ /node_modules
2
+
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [1.1.0] - 2026-06-27
6
+
7
+ ### Fixes
8
+
9
+ - Published a maintenance release with the latest packaging and release workflow updates.
package/README.md CHANGED
@@ -4,19 +4,19 @@
4
4
 
5
5
  English · [简体中文](README.zh-CN.md)
6
6
 
7
+ RustCodeGraph in this repository is based on CodeGraph and adapted for our current Rust-first CLI and MCP workflow. It keeps the original local-first code intelligence direction, while the documentation, packaging, and product description here reflect the current `rustcodegraph` project rather than the older CodeGraph branding.
8
+
7
9
  ## 🎉 1.0 Released!
8
10
 
9
11
  Already installed? Run `rustcodegraph upgrade` to update in place.
10
12
 
11
- Follow [@getcodegraph](https://x.com/getcodegraph) on X for updates.
12
-
13
13
  ### Supercharge Claude Code, Cursor, Codex, OpenCode, Hermes Agent, Gemini, Antigravity, and Kiro with Semantic Code Intelligence
14
14
 
15
15
  **~16% cheaper · ~58% fewer tool calls · 100% local**
16
16
 
17
17
  ### [Documentation →](docs/user/README.md)
18
18
 
19
- [![npm version](https://img.shields.io/npm/v/@hunzhiwange/rustcodegraph.svg)](https://www.npmjs.com/package/@hunzhiwange/rustcodegraph)
19
+ [![npm version](https://img.shields.io/npm/v/rustcodegraph.svg)](https://www.npmjs.com/package/rustcodegraph)
20
20
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
21
21
  [![Self-contained](https://img.shields.io/badge/Rust-native%20%C2%B7%20no%20Node%20runtime-brightgreen.svg)](https://github.com/hunzhiwange/rustcodegraph/releases)
22
22
 
@@ -35,8 +35,6 @@ Follow [@getcodegraph](https://x.com/getcodegraph) on X for updates.
35
35
 
36
36
  <br>
37
37
 
38
- **The RustCodeGraph platform is coming** — for every PR, know exactly what to test, what could break, which flows are affected, and whether business logic is compromised.
39
-
40
38
  </div>
41
39
 
42
40
  ## Get Started
@@ -60,7 +58,7 @@ irm https://raw.githubusercontent.com/hunzhiwange/rustcodegraph/main/install.ps1
60
58
  <summary><b>Already have Node? Use npm instead</b></summary>
61
59
 
62
60
  ```bash
63
- npm i -g @hunzhiwange/rustcodegraph
61
+ npm i -g rustcodegraph
64
62
  ```
65
63
 
66
64
  <sub>The npm package downloads the matching Rust binary from GitHub Releases — nothing to compile, no TypeScript runtime to build. The installer puts `rustcodegraph` on your PATH but **doesn't change your current shell** — open a new terminal before the next step so the command resolves.</sub>
@@ -106,7 +104,7 @@ Changed your mind? One command removes RustCodeGraph from every agent it configu
106
104
  rustcodegraph uninstall
107
105
  ```
108
106
 
109
- <sub>Reverses the installer — strips RustCodeGraph's MCP server config, instructions, and permissions from each configured agent. Your project indexes (`.rustcodegraph/`) are left untouched; remove those per-project with `rustcodegraph uninit`. If you installed through npm and also want to remove the package, run this before uninstalling `@hunzhiwange/rustcodegraph`; npm package removal does not edit agent configs. Use `--target` to remove from specific agents, or `--yes` to run non-interactively.</sub>
107
+ <sub>Reverses the installer — strips RustCodeGraph's MCP server config, instructions, and permissions from each configured agent. Your project indexes (`.rustcodegraph/`) are left untouched; remove those per-project with `rustcodegraph uninit`. If you installed through npm and also want to remove the package, run this before uninstalling `rustcodegraph`; npm package removal does not edit agent configs. Use `--target` to remove from specific agents, or `--yes` to run non-interactively.</sub>
110
108
 
111
109
  ---
112
110
 
@@ -388,7 +386,7 @@ curl -fsSL https://raw.githubusercontent.com/hunzhiwange/rustcodegraph/main/inst
388
386
  brew install hunzhiwange/tap/rustcodegraph
389
387
 
390
388
  # Or use npm.
391
- npm install -g @hunzhiwange/rustcodegraph
389
+ npm install -g rustcodegraph
392
390
  ```
393
391
 
394
392
  **Add to `~/.claude.json`:**
@@ -705,7 +703,7 @@ Framework routing is validated the same way, on a canonical app per framework: E
705
703
 
706
704
  **MCP hits `database is locked`** — current builds shouldn't: the Rust runtime uses SQLite in WAL mode, where concurrent reads normally do not block on a writer. If you still see it:
707
705
 
708
- - **You're still running the old CodeGraph package or binary.** RustCodeGraph is a separate project and does not upgrade CodeGraph in place. Install RustCodeGraph separately — `curl -fsSL https://raw.githubusercontent.com/hunzhiwange/rustcodegraph/main/install.sh | sh` (macOS/Linux), `irm https://raw.githubusercontent.com/hunzhiwange/rustcodegraph/main/install.ps1 | iex` (Windows), or `npm i -g @hunzhiwange/rustcodegraph` — then make sure your MCP config points at `rustcodegraph`.
706
+ - **You're still running the old CodeGraph package or binary.** RustCodeGraph is a separate project and does not upgrade CodeGraph in place. Install RustCodeGraph separately — `curl -fsSL https://raw.githubusercontent.com/hunzhiwange/rustcodegraph/main/install.sh | sh` (macOS/Linux), `irm https://raw.githubusercontent.com/hunzhiwange/rustcodegraph/main/install.ps1 | iex` (Windows), or `npm i -g rustcodegraph` — then make sure your MCP config points at `rustcodegraph`.
709
707
  - **`rustcodegraph status` shows `Journal:` other than `wal`** — WAL couldn't be enabled on this filesystem (common on network shares and WSL2 `/mnt`), so reads can block on writes. Move the project (with its `.rustcodegraph/` folder) onto a local disk.
710
708
 
711
709
  **MCP server not connecting** — Your agent starts the server itself, so you don't launch it by hand. Make sure the project is initialized and indexed (`rustcodegraph status`) and that the path in your MCP config is correct. If it still won't connect, re-run `rustcodegraph install` to rewrite the config.
@@ -0,0 +1,212 @@
1
+ const { createWriteStream, existsSync, mkdirSync, mkdtemp } = require("fs");
2
+ const { join, sep } = require("path");
3
+ const { spawnSync } = require("child_process");
4
+ const { tmpdir } = require("os");
5
+
6
+ const axios = require("axios");
7
+ const rimraf = require("rimraf");
8
+ const tmpDir = tmpdir();
9
+
10
+ const error = (msg) => {
11
+ console.error(msg);
12
+ process.exit(1);
13
+ };
14
+
15
+ class Package {
16
+ constructor(platform, name, url, filename, zipExt, binaries) {
17
+ let errors = [];
18
+ if (typeof url !== "string") {
19
+ errors.push("url must be a string");
20
+ } else {
21
+ try {
22
+ new URL(url);
23
+ } catch (e) {
24
+ errors.push(e);
25
+ }
26
+ }
27
+ if (name && typeof name !== "string") {
28
+ errors.push("package name must be a string");
29
+ }
30
+ if (!name) {
31
+ errors.push("You must specify the name of your package");
32
+ }
33
+ if (binaries && typeof binaries !== "object") {
34
+ errors.push("binaries must be a string => string map");
35
+ }
36
+ if (!binaries) {
37
+ errors.push("You must specify the binaries in the package");
38
+ }
39
+
40
+ if (errors.length > 0) {
41
+ let errorMsg =
42
+ "One or more of the parameters you passed to the Binary constructor are invalid:\n";
43
+ errors.forEach((error) => {
44
+ errorMsg += error;
45
+ });
46
+ errorMsg +=
47
+ '\n\nCorrect usage: new Package("my-binary", "https://example.com/binary/download.tar.gz", {"my-binary": "my-binary"})';
48
+ error(errorMsg);
49
+ }
50
+
51
+ this.platform = platform;
52
+ this.url = url;
53
+ this.name = name;
54
+ this.filename = filename;
55
+ this.zipExt = zipExt;
56
+ this.installDirectory = join(__dirname, "node_modules", ".bin_real");
57
+ this.binaries = binaries;
58
+
59
+ if (!existsSync(this.installDirectory)) {
60
+ mkdirSync(this.installDirectory, { recursive: true });
61
+ }
62
+ }
63
+
64
+ exists() {
65
+ for (const binaryName in this.binaries) {
66
+ const binRelPath = this.binaries[binaryName];
67
+ const binPath = join(this.installDirectory, binRelPath);
68
+ if (!existsSync(binPath)) {
69
+ return false;
70
+ }
71
+ }
72
+ return true;
73
+ }
74
+
75
+ install(fetchOptions, suppressLogs = false) {
76
+ if (this.exists()) {
77
+ if (!suppressLogs) {
78
+ console.error(
79
+ `${this.name} is already installed, skipping installation.`,
80
+ );
81
+ }
82
+ return Promise.resolve();
83
+ }
84
+
85
+ if (existsSync(this.installDirectory)) {
86
+ rimraf.sync(this.installDirectory);
87
+ }
88
+
89
+ mkdirSync(this.installDirectory, { recursive: true });
90
+
91
+ if (!suppressLogs) {
92
+ console.error(`Downloading release from ${this.url}`);
93
+ }
94
+
95
+ return axios({ ...fetchOptions, url: this.url, responseType: "stream" })
96
+ .then((res) => {
97
+ return new Promise((resolve, reject) => {
98
+ mkdtemp(`${tmpDir}${sep}`, (err, directory) => {
99
+ let tempFile = join(directory, this.filename);
100
+ const sink = res.data.pipe(createWriteStream(tempFile));
101
+ sink.on("error", (err) => reject(err));
102
+ sink.on("close", () => {
103
+ if (/\.tar\.*/.test(this.zipExt)) {
104
+ const result = spawnSync("tar", [
105
+ "xf",
106
+ tempFile,
107
+ // The tarballs are stored with a leading directory
108
+ // component; we strip one component in the
109
+ // shell installers too.
110
+ "--strip-components",
111
+ "1",
112
+ "-C",
113
+ this.installDirectory,
114
+ ]);
115
+ if (result.status == 0) {
116
+ resolve();
117
+ } else if (result.error) {
118
+ reject(result.error);
119
+ } else {
120
+ reject(
121
+ new Error(
122
+ `An error occurred untarring the artifact: stdout: ${result.stdout}; stderr: ${result.stderr}`,
123
+ ),
124
+ );
125
+ }
126
+ } else if (this.zipExt == ".zip") {
127
+ let result;
128
+ if (this.platform.artifactName.includes("windows")) {
129
+ // Windows does not have "unzip" by default on many installations, instead
130
+ // we use Expand-Archive from powershell
131
+ result = spawnSync("powershell.exe", [
132
+ "-NoProfile",
133
+ "-NonInteractive",
134
+ "-Command",
135
+ `& {
136
+ param([string]$LiteralPath, [string]$DestinationPath)
137
+ Expand-Archive -LiteralPath $LiteralPath -DestinationPath $DestinationPath -Force
138
+ }`,
139
+ tempFile,
140
+ this.installDirectory,
141
+ ]);
142
+ } else {
143
+ result = spawnSync("unzip", [
144
+ "-q",
145
+ tempFile,
146
+ "-d",
147
+ this.installDirectory,
148
+ ]);
149
+ }
150
+
151
+ if (result.status == 0) {
152
+ resolve();
153
+ } else if (result.error) {
154
+ reject(result.error);
155
+ } else {
156
+ reject(
157
+ new Error(
158
+ `An error occurred unzipping the artifact: stdout: ${result.stdout}; stderr: ${result.stderr}`,
159
+ ),
160
+ );
161
+ }
162
+ } else {
163
+ reject(
164
+ new Error(`Unrecognized file extension: ${this.zipExt}`),
165
+ );
166
+ }
167
+ });
168
+ });
169
+ });
170
+ })
171
+ .then(() => {
172
+ if (!suppressLogs) {
173
+ console.error(`${this.name} has been installed!`);
174
+ }
175
+ })
176
+ .catch((e) => {
177
+ error(`Error fetching release: ${e.message}`);
178
+ });
179
+ }
180
+
181
+ run(binaryName, fetchOptions) {
182
+ const promise = !this.exists()
183
+ ? this.install(fetchOptions, true)
184
+ : Promise.resolve();
185
+
186
+ promise
187
+ .then(() => {
188
+ const [, , ...args] = process.argv;
189
+
190
+ const options = { cwd: process.cwd(), stdio: "inherit" };
191
+
192
+ const binRelPath = this.binaries[binaryName];
193
+ if (!binRelPath) {
194
+ error(`${binaryName} is not a known binary in ${this.name}`);
195
+ }
196
+ const binPath = join(this.installDirectory, binRelPath);
197
+ const result = spawnSync(binPath, args, options);
198
+
199
+ if (result.error) {
200
+ error(result.error);
201
+ }
202
+
203
+ process.exit(result.status);
204
+ })
205
+ .catch((e) => {
206
+ error(e.message);
207
+ process.exit(1);
208
+ });
209
+ }
210
+ }
211
+
212
+ module.exports.Package = Package;
package/binary.js ADDED
@@ -0,0 +1,126 @@
1
+ const { Package } = require("./binary-install");
2
+ const os = require("os");
3
+ const cTable = require("console.table");
4
+ const libc = require("detect-libc");
5
+ const { configureProxy } = require("axios-proxy-builder");
6
+
7
+ const error = (msg) => {
8
+ console.error(msg);
9
+ process.exit(1);
10
+ };
11
+
12
+ const {
13
+ name,
14
+ artifactDownloadUrl,
15
+ supportedPlatforms,
16
+ glibcMinimum,
17
+ } = require("./package.json");
18
+
19
+ const builderGlibcMajorVersion = glibcMinimum.major;
20
+ const builderGlibcMInorVersion = glibcMinimum.series;
21
+
22
+ const getPlatform = () => {
23
+ const rawOsType = os.type();
24
+ const rawArchitecture = os.arch();
25
+
26
+ // We want to use rust-style target triples as the canonical key
27
+ // for a platform, so translate the "os" library's concepts into rust ones
28
+ let osType = "";
29
+ switch (rawOsType) {
30
+ case "Windows_NT":
31
+ osType = "pc-windows-msvc";
32
+ break;
33
+ case "Darwin":
34
+ osType = "apple-darwin";
35
+ break;
36
+ case "Linux":
37
+ osType = "unknown-linux-gnu";
38
+ break;
39
+ }
40
+
41
+ let arch = "";
42
+ switch (rawArchitecture) {
43
+ case "x64":
44
+ arch = "x86_64";
45
+ break;
46
+ case "arm64":
47
+ arch = "aarch64";
48
+ break;
49
+ }
50
+
51
+ if (rawOsType === "Linux") {
52
+ if (libc.familySync() == "musl") {
53
+ osType = "unknown-linux-musl-dynamic";
54
+ } else if (libc.isNonGlibcLinuxSync()) {
55
+ console.warn(
56
+ "Your libc is neither glibc nor musl; trying static musl binary instead",
57
+ );
58
+ osType = "unknown-linux-musl-static";
59
+ } else {
60
+ let libcVersion = libc.versionSync();
61
+ let splitLibcVersion = libcVersion.split(".");
62
+ let libcMajorVersion = splitLibcVersion[0];
63
+ let libcMinorVersion = splitLibcVersion[1];
64
+ if (
65
+ libcMajorVersion != builderGlibcMajorVersion ||
66
+ libcMinorVersion < builderGlibcMInorVersion
67
+ ) {
68
+ // We can't run the glibc binaries, but we can run the static musl ones
69
+ // if they exist
70
+ console.warn(
71
+ "Your glibc isn't compatible; trying static musl binary instead",
72
+ );
73
+ osType = "unknown-linux-musl-static";
74
+ }
75
+ }
76
+ }
77
+
78
+ // Assume the above succeeded and build a target triple to look things up with.
79
+ // If any of it failed, this lookup will fail and we'll handle it like normal.
80
+ let targetTriple = `${arch}-${osType}`;
81
+ let platform = supportedPlatforms[targetTriple];
82
+
83
+ if (!platform) {
84
+ error(
85
+ `Platform with type "${rawOsType}" and architecture "${rawArchitecture}" is not supported by ${name}.\nYour system must be one of the following:\n\n${Object.keys(
86
+ supportedPlatforms,
87
+ ).join(",")}`,
88
+ );
89
+ }
90
+
91
+ return platform;
92
+ };
93
+
94
+ const getPackage = () => {
95
+ const platform = getPlatform();
96
+ const url = `${artifactDownloadUrl}/${platform.artifactName}`;
97
+ let filename = platform.artifactName;
98
+ let ext = platform.zipExt;
99
+ let binary = new Package(platform, name, url, filename, ext, platform.bins);
100
+
101
+ return binary;
102
+ };
103
+
104
+ const install = (suppressLogs) => {
105
+ if (!artifactDownloadUrl || artifactDownloadUrl.length === 0) {
106
+ console.warn("in demo mode, not installing binaries");
107
+ return;
108
+ }
109
+ const package = getPackage();
110
+ const proxy = configureProxy(package.url);
111
+
112
+ return package.install(proxy, suppressLogs);
113
+ };
114
+
115
+ const run = (binaryName) => {
116
+ const package = getPackage();
117
+ const proxy = configureProxy(package.url);
118
+
119
+ package.run(binaryName, proxy);
120
+ };
121
+
122
+ module.exports = {
123
+ install,
124
+ run,
125
+ getPackage,
126
+ };
package/install.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { install } = require("./binary");
4
+ install(false);