@traz-dev/traz 0.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,44 @@
1
+ # Changelog
2
+
3
+ All notable changes to `traz` will be documented in this file.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
+
6
+ ---
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+ - `traz recap` command: Summarize recent events from a given timeframe for morning standups and AI context syncing.
12
+ - Interactive guided onboarding: First-time users get a friendly setup wizard with `dialoguer` menus.
13
+ - Antigravity (agy) MCP integration: `traz setup agy` and documented in `MCP_INTEGRATION.md`.
14
+
15
+ ### Changed
16
+ - `traz init` now automatically creates a `.traz/` local directory and adds it to `.gitignore` without needing the `--local` flag.
17
+ - Interactive REPL mode: Returning users see a clean prompt instead of a large ASCII banner.
18
+ - MCP server command simplified from `traz mcp serve` to `traz mcp` across all docs.
19
+
20
+ ### Fixed
21
+ - CI: Fixed `cargo fmt` formatting failures.
22
+ - CI: Fixed flaky semantic search snapshot tests in CI environments where embedding generation fails.
23
+ - Documentation: Corrected `traz mcp serve` → `traz mcp` references across `README.md` and `MCP_INTEGRATION.md`.
24
+
25
+ ---
26
+
27
+ ## [0.1.0] — 2026-06-06
28
+
29
+ ### Added
30
+ - Local-first engineering memory layer backed by SQLite.
31
+ - `traz recent`, `traz search`, `traz timeline`, `traz context` — core read commands.
32
+ - `traz add`, `traz log`, `traz capture` — event ingestion commands.
33
+ - `traz mcp` — MCP stdio server for Claude Code, Cursor, Gemini CLI, Aider, Warp, and Antigravity.
34
+ - `traz init` — project setup with optional git hook integration.
35
+ - `traz tui` — ratatui-based terminal UI dashboard.
36
+ - `traz doctor` — installation diagnostic tool.
37
+ - `traz status` — system health overview.
38
+ - `traz setup <tool>` — step-by-step integration guides for popular AI tools.
39
+ - Semantic search with local ONNX embeddings (all-MiniLM-L6-v2 via fastembed-rs).
40
+ - Dense AI-optimized output format (`--dense` flag) reducing MCP token payloads by 60–75%.
41
+ - Session checkpointing via `traz checkpoint` for safe context-window resets.
42
+ - Git hook integration for automatic event capture on commit/push/checkout.
43
+ - Shell failure tracking hooks for zsh and bash.
44
+ - Cross-platform release binaries: Linux (x86_64, aarch64), macOS (x86_64, aarch64), Windows (x86_64).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mithilgirish
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,354 @@
1
+ <p align="center">
2
+ <img width="800" alt="traz" src="https://github.com/user-attachments/assets/f4b969a0-b23e-400b-a012-38f05e20973b" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <strong>Trace. Context. Continuity.</strong><br/>
7
+ <sub>A local-first engineering memory layer and MCP server that provides AI coding tools with a shared, persistent context architecture.</sub>
8
+ </p>
9
+
10
+ <p align="center">
11
+ <a href="https://github.com/mithilgirish/traz/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License" /></a>
12
+
13
+ <img src="https://img.shields.io/badge/MCP-compatible-green" alt="MCP compatible" />
14
+ <img src="https://img.shields.io/badge/SQLite-Local_First-purple" alt="SQLite" />
15
+ <a href="https://traz.mithilgirish.dev"><img src="https://img.shields.io/badge/docs-traz.mithilgirish.dev-6366f1" alt="Documentation" /></a>
16
+ </p>
17
+
18
+ ---
19
+
20
+ ## Table of Contents
21
+ - [Overview](#overview)
22
+ - [The Context Fragmentation Problem](#the-context-fragmentation-problem)
23
+ - [Core Architecture & Design](#core-architecture--design)
24
+ - [Installation Guide](#installation-guide)
25
+ - [Initialization & Configuration](#initialization--configuration)
26
+ - [Command Line Interface Reference](#command-line-interface-reference)
27
+ - [Ingestion Commands](#ingestion-commands)
28
+ - [Exploration Commands](#exploration-commands)
29
+ - [Maintenance Commands](#maintenance-commands)
30
+ - [Terminal User Interface (TUI)](#terminal-user-interface-tui)
31
+ - [Agent Integration (MCP)](#agent-integration-mcp)
32
+ - [Supported AI Environments](#supported-ai-environments)
33
+ - [Manual MCP Configuration](#manual-mcp-configuration)
34
+ - [Advanced Subsystems](#advanced-subsystems)
35
+ - [Semantic Vector Search](#semantic-vector-search)
36
+ - [Context Window Compression (Dense Format)](#context-window-compression-dense-format)
37
+ - [Security & Privacy](#security--privacy)
38
+ - [Troubleshooting & FAQ](#troubleshooting--faq)
39
+ - [Roadmap](#roadmap)
40
+ - [Contributing](#contributing)
41
+ - [License](#license)
42
+
43
+ ---
44
+
45
+ ## Overview
46
+
47
+ `traz` is a local-first engineering memory layer designed specifically for AI-augmented development.
48
+
49
+ By capturing debugging history, architectural decisions, file modifications, and workflow traces as you code, `traz` establishes a highly searchable, persistent context timeline. This timeline is securely stored in a local SQLite vector database and automatically exposed via the **Model Context Protocol (MCP)**. This enables any compatible AI agent (Claude Code, Cursor, Aider, Gemini CLI, OpenAI Codex) to instantly synchronize context without manual developer intervention or copy-pasting.
50
+
51
+ ## The Context Fragmentation Problem
52
+
53
+ Modern software development increasingly relies on multiple, specialized AI agents. A standard workflow might involve:
54
+ 1. Triaging a stack trace in Claude Code.
55
+ 2. Refactoring a dense component within Cursor IDE.
56
+ 3. Generating unit tests via a terminal agent like Aider or Antigravity.
57
+
58
+ At every tool boundary, context is lost. The AI in the IDE does not inherently know what the AI in the terminal just fixed. Every new session starts as an isolated environment, forcing developers to manually rebuild the context window.
59
+
60
+ `traz` resolves this by acting as a persistent context plane. It ensures that subsequent AI sessions—regardless of the tool—inherit the context of previous decisions, mitigating context loss, reducing LLM token duplication, and preventing regression of thought.
61
+
62
+ ## Core Architecture & Design
63
+
64
+ The `traz` architecture is built upon three primary pillars:
65
+
66
+ 1. **Local Timeline Engine (SQLite):** A zero-dependency, local-first storage mechanism. It tracks event schemas across sessions, ensuring that proprietary source code and architectural context never leave the local machine. There are no cloud accounts, no sync delays, and no vendor lock-in.
67
+ 2. **Hybrid Vector Search:** Leverages the `fastembed-rs` library to execute ONNX-accelerated embedding generation locally. It implements Reciprocal Rank Fusion (RRF) to intelligently merge exact keyword matches (FTS5) with semantic vector similarity, ensuring high-fidelity context retrieval even when vocabulary drifts.
68
+ 3. **MCP Server Integration:** Implements the open Model Context Protocol to serve context transparently to supported AI agents. By utilizing an engineered "Dense Output Format," it compresses context payload sizes by up to 75%, preserving valuable context window capacity for the LLM's actual reasoning process.
69
+
70
+ ```mermaid
71
+ graph TD
72
+ A[Claude Code] -->|stdio / MCP| C(traz MCP Server)
73
+ B[Cursor IDE] -->|stdio / MCP| C
74
+ D[CLI / Shell Hooks] -->|Commands| C
75
+ C --> E[(SQLite Vector DB)]
76
+ C --> F[fastembed-rs ONNX]
77
+ E --> G[Timeline Engine]
78
+ ```
79
+
80
+ For an in-depth review of the underlying schema, migration logic, and RRF mathematics, please refer to the [Architecture Documentation](./docs/ARCHITECTURE.md).
81
+
82
+ ## Installation Guide
83
+
84
+ Select your preferred installation method:
85
+
86
+ ### 1. Via NPM (Cross-Platform)
87
+ ```bash
88
+ npm install -g @traz-dev/traz
89
+ ```
90
+
91
+ ### 2. Via Homebrew (macOS & Linux)
92
+ ```bash
93
+ brew tap mithilgirish/traz
94
+ brew install traz
95
+ ```
96
+
97
+ ### 3. Standalone Installers (No dependencies required)
98
+ * **macOS & Linux (Shell):**
99
+ ```bash
100
+ curl --proto '=https' --tlsv1.2 -LsSf https://github.com/mithilgirish/traz/releases/latest/download/traz-installer.sh | sh
101
+ ```
102
+ * **Windows (PowerShell):**
103
+ ```powershell
104
+ irm https://github.com/mithilgirish/traz/releases/latest/download/traz-installer.ps1 | iex
105
+ ```
106
+
107
+ ### 4. Via Cargo (Build from source)
108
+ Requires the Rust toolchain (v1.75.0 or higher):
109
+ ```bash
110
+ cargo install --git https://github.com/mithilgirish/traz.git traz
111
+ ```
112
+
113
+ ### Build from Source manually
114
+ For contributors or users requiring specific branch deployments:
115
+ ```bash
116
+ git clone https://github.com/mithilgirish/traz.git
117
+ cd traz
118
+ cargo build --release
119
+
120
+ # Optional: Add to PATH systematically
121
+ sudo cp target/release/traz /usr/local/bin/
122
+ ```
123
+
124
+ ### Verification
125
+ Ensure the binary is correctly linked and the embedding model engine is accessible.
126
+ ```bash
127
+ traz doctor
128
+ ```
129
+
130
+ ## Initialization & Configuration
131
+
132
+ Initialize `traz` within your repository to establish the local timeline directory (`.traz/`). This directory acts as the nexus for your project's history.
133
+
134
+ ```bash
135
+ cd your-project
136
+ traz init
137
+ ```
138
+
139
+ Running `traz init` performs the following automated steps:
140
+ 1. Creates the `.traz/` local directory.
141
+ 2. Initializes the SQLite schema (`traz.db`) and vector index.
142
+ 3. Automatically appends `.traz/` to your `.gitignore` to prevent committing the database to remote version control.
143
+
144
+ ## Command Line Interface Reference
145
+
146
+ The CLI is designed to be highly composable, scriptable for CI/CD integration, and readable for daily workflow monitoring.
147
+
148
+ ### Ingestion Commands
149
+
150
+ **Log Manual Context:**
151
+ Append a manual note, architectural decision, or debugging trace directly to the timeline.
152
+ ```bash
153
+ traz log "traced root cause of memory leak to unbounded queue growth in the worker pool"
154
+ ```
155
+
156
+ **Add Structured Events:**
157
+ Useful for shell aliases or git hooks.
158
+ ```bash
159
+ traz add --tool cursor --event-type bug_fix --title "Fixed auth race condition"
160
+ ```
161
+
162
+ ### Exploration Commands
163
+
164
+ **View Recent Activity:**
165
+ Fetch a chronological list of the most recent events across all tools.
166
+ ```bash
167
+ $ traz recent --limit 5
168
+
169
+ [claude-code · 2h ago] fixed websocket reconnect issue
170
+ [cursor · 5h ago] updated auth middleware
171
+ [warp · 1d ago] traced memory leak in queue worker
172
+ [aider · 2d ago] reverted broken cache optimization
173
+ ```
174
+
175
+ **Search Engineering History:**
176
+ Perform keyword searches against the timeline.
177
+ ```bash
178
+ $ traz search auth
179
+
180
+ [2d ago] claude-code
181
+ Fixed JWT refresh race condition
182
+
183
+ [5h ago] cursor
184
+ Updated auth middleware retry logic
185
+ ```
186
+
187
+ **View Workflow Timeline:**
188
+ Render a bulleted workflow trace of operations, useful for generating PR descriptions or commit summaries.
189
+ ```bash
190
+ $ traz timeline
191
+
192
+ • created websocket handler
193
+ • debugged reconnect issue
194
+ • added retry backoff
195
+ • verified with local tests
196
+ ```
197
+
198
+ **Time-Bounded AI Recap:**
199
+ Generate a time-bounded summary, commonly used for daily standups or morning synchronization.
200
+ ```bash
201
+ $ traz recap --hours 24
202
+ ```
203
+
204
+ ### Maintenance Commands
205
+
206
+ **Context Checkpointing:**
207
+ Save a named snapshot of the current state. Useful when switching branches or finalizing a massive refactor.
208
+ ```bash
209
+ traz checkpoint --message "completed auth migration"
210
+ ```
211
+
212
+ **Backfill Embeddings:**
213
+ Generate missing vector embeddings for older events ingested prior to vector support or during offline periods.
214
+ ```bash
215
+ traz backfill-embeddings
216
+ ```
217
+
218
+ ## Terminal User Interface (TUI)
219
+
220
+ For an interactive, visually structured view of the repository's history and AI traces, `traz` ships with a native TUI.
221
+
222
+ ```bash
223
+ traz tui
224
+ ```
225
+
226
+ The TUI provides:
227
+ - Split-pane navigation of historical checkpoints.
228
+ - Interactive filtering by AI tool, event type, or timestamp.
229
+ - Detailed inspection of specific debug logs or diffs associated with an event.
230
+
231
+ ## Agent Integration (MCP)
232
+
233
+ `traz` acts as an MCP stdio server. It features auto-detecting setup workflows to register itself across major AI tools effortlessly.
234
+
235
+ ### Supported AI Environments
236
+
237
+ Run the setup command corresponding to your primary tool. The wizard will automatically locate the tool's configuration file and inject the necessary MCP routing logic.
238
+
239
+ ```bash
240
+ traz setup claude # Configures Claude Code
241
+ traz setup cursor # Modifies ~/.cursor/mcp.json
242
+ traz setup opencode # Configures OpenCode
243
+ traz setup codex # Configures OpenAI Codex CLI
244
+ traz setup gemini # Configures Gemini CLI
245
+ traz setup agy # Configures Antigravity CLI
246
+ ```
247
+
248
+ ### Manual MCP Configuration
249
+
250
+ For tools not supported by the interactive wizard (such as Aider or custom agents), configure your agent to execute `traz` with the `mcp` subcommand.
251
+
252
+ **Example `mcp.json` structure:**
253
+ ```json
254
+ {
255
+ "mcpServers": {
256
+ "traz": {
257
+ "command": "traz",
258
+ "args": ["mcp"]
259
+ }
260
+ }
261
+ }
262
+ ```
263
+
264
+ Once configured, the AI tool will automatically query the `traz` server on initialization, retrieve the latest checkpoints, and restore context natively. For further details, refer to the [Agent Integration Guide](./docs/AGENT_INTEGRATION.md).
265
+
266
+ ## Advanced Subsystems
267
+
268
+ ### Semantic Vector Search
269
+
270
+ By default, `traz` generates local embeddings for all ingested events using an ONNX-accelerated MiniLM model (`fastembed-rs`). This enables semantic retrieval, allowing you to find contextually relevant history even when exact keywords are omitted.
271
+
272
+ ```bash
273
+ $ traz search "database connection pooling"
274
+
275
+ [semantic search] Search: "database connection pooling" (2 results)
276
+ ─────────────────────────────────────────────
277
+ 1. Added pg_bouncer for connections (72%)
278
+ Tool: cursor Type: commit Age: 3d ago Tags: #db
279
+
280
+ 2. Re-architected connection lifecycle (64%)
281
+ Tool: gemini Type: refactor Age: 1w ago Tags: #db #performance
282
+ ```
283
+
284
+ ### Context Window Compression (Dense Format)
285
+
286
+ Long-running projects accumulate extensive, verbose timelines. Standard JSON serialization of this data rapidly depletes an LLM's context window.
287
+
288
+ `traz` implements a `--dense` formatting protocol over MCP. Instead of passing nested JSON arrays to the agent, the server parses the historical data into an ultra-compact plaintext format, stripping redundant schema keys and whitespace. This methodology consistently compresses context payload sizes by **60% to 75%**.
289
+
290
+ ## Security & Privacy
291
+
292
+ Security is foundational to `traz`.
293
+ - **Zero Telemetry:** The CLI binary contains no telemetry, analytics, or remote tracking systems.
294
+ - **Local Isolation:** The SQLite database is stored locally in your project folder (`.traz/traz.db`) and is strictly `.gitignore`d. No data is transmitted to an external server.
295
+ - **Embedding Generation:** Semantic vector generation runs completely on-device using ONNX execution providers. Your proprietary commit messages and architecture plans are never sent to external embedding APIs.
296
+
297
+ ## Troubleshooting & FAQ
298
+
299
+ **Q: `traz setup cursor` fails to detect my configuration.**
300
+ A: Ensure you have initialized Cursor at least once so the `~/.cursor` configuration directory exists. You can manually append the JSON block defined in the Manual MCP Configuration section.
301
+
302
+ **Q: Semantic search is returning errors or panicking in CI environments.**
303
+ A: In headless CI environments missing certain runtime libraries, `fastembed-rs` may fail to generate embeddings. Set the `TRAZ_DISABLE_EMBEDDINGS=1` environment variable during automated testing to bypass vector generation.
304
+
305
+ **Q: How do I clear my context timeline?**
306
+ A: You can purge the local memory by simply deleting the database file: `rm -rf .traz/`. Re-run `traz init` to start fresh.
307
+
308
+ ## Roadmap
309
+
310
+ **v0.1 (Current)**
311
+ - [x] Local timeline storage (SQLite)
312
+ - [x] CLI commands (recent, search, timeline, log, recap)
313
+ - [x] Context and history retrieval system
314
+ - [x] Native MCP server implementation
315
+ - [x] Automatic git hook integrations
316
+ - [x] Interactive Tool Setup Adapters
317
+ - [x] Semantic search via local ONNX embeddings
318
+ - [x] Terminal UI (TUI) Dashboard
319
+ - [x] Token-optimized Dense output formats
320
+ - [x] Workflow Checkpoints
321
+
322
+ **Future Proposals**
323
+ - [ ] VSCode and JetBrains native extensions
324
+ - [ ] Network-level team synchronization (Opt-in)
325
+ - [ ] Advanced Graph visualizations
326
+
327
+ ## Contributing
328
+
329
+ We welcome contributions from the community. If you plan to introduce significant architectural changes or core database migrations, please open an issue first to discuss the proposed design.
330
+
331
+ ### Development Workflow
332
+ ```bash
333
+ # Clone the repository
334
+ git clone https://github.com/mithilgirish/traz.git
335
+ cd traz
336
+
337
+ # Run test suite
338
+ cargo test
339
+
340
+ # Ensure formatting and linting pass
341
+ cargo fmt --all -- --check
342
+ cargo clippy -- -D warnings
343
+ ```
344
+
345
+ Please review the [CONTRIBUTING.md](./CONTRIBUTING.md) for strict code style guidelines and testing protocols prior to submitting Pull Requests.
346
+
347
+ ## License
348
+
349
+ This project is licensed under the [MIT License](./LICENSE). All contributions are subject to these licensing terms.
350
+
351
+ ---
352
+ <p align="center">
353
+ <sub>Built for developers who switch tools, not context.</sub>
354
+ </p>
@@ -0,0 +1,348 @@
1
+ const {
2
+ createWriteStream,
3
+ existsSync,
4
+ mkdirSync,
5
+ mkdtemp,
6
+ rmSync,
7
+ } = require("fs");
8
+ const { join, sep } = require("path");
9
+ const { spawnSync } = require("child_process");
10
+ const { tmpdir } = require("os");
11
+
12
+ const https = require("node:https");
13
+ const http = require("node:http");
14
+
15
+ const tmpDir = tmpdir();
16
+
17
+ const error = (msg) => {
18
+ console.error(msg);
19
+ process.exit(1);
20
+ };
21
+
22
+ function getProxyForUrl(urlString) {
23
+ const url = new URL(urlString);
24
+ const isHttps = url.protocol === "https:";
25
+
26
+ const noProxy = process.env.NO_PROXY || process.env.no_proxy || "";
27
+ if (noProxy === "*") return null;
28
+ if (noProxy) {
29
+ const hostname = url.hostname.toLowerCase();
30
+ const noProxyList = noProxy.split(",").map((s) => s.trim().toLowerCase());
31
+ for (const entry of noProxyList) {
32
+ if (hostname === entry || hostname.endsWith("." + entry)) {
33
+ return null;
34
+ }
35
+ }
36
+ }
37
+
38
+ const proxyEnv = isHttps
39
+ ? process.env.HTTPS_PROXY || process.env.https_proxy
40
+ : process.env.HTTP_PROXY || process.env.http_proxy;
41
+
42
+ if (!proxyEnv) return null;
43
+
44
+ const proxyUrl = new URL(proxyEnv);
45
+
46
+ let auth = null;
47
+ if (proxyUrl.username || proxyUrl.password) {
48
+ auth = `${proxyUrl.username}:${proxyUrl.password}`;
49
+ }
50
+
51
+ return {
52
+ hostname: proxyUrl.hostname,
53
+ port: proxyUrl.port || (proxyUrl.protocol === "https:" ? 443 : 80),
54
+ auth: auth,
55
+ };
56
+ }
57
+
58
+ function connectThroughProxy(proxy, target) {
59
+ return new Promise((resolve, reject) => {
60
+ const headers = {};
61
+ if (proxy.auth) {
62
+ headers["Proxy-Authorization"] =
63
+ "Basic " + Buffer.from(proxy.auth).toString("base64");
64
+ }
65
+
66
+ const connectReq = http.request({
67
+ hostname: proxy.hostname,
68
+ port: proxy.port,
69
+ method: "CONNECT",
70
+ path: `${target.hostname}:${target.port || 443}`,
71
+ headers,
72
+ });
73
+ connectReq.on("connect", (res, socket) => {
74
+ if (res.statusCode === 200) {
75
+ resolve(socket);
76
+ } else {
77
+ reject(new Error(`Proxy CONNECT failed with status ${res.statusCode}`));
78
+ }
79
+ });
80
+ connectReq.on("error", reject);
81
+ connectReq.end();
82
+ });
83
+ }
84
+
85
+ function download(urlString, maxRedirects) {
86
+ if (maxRedirects === undefined) maxRedirects = 5;
87
+ return new Promise((resolve, reject) => {
88
+ if (maxRedirects < 0) {
89
+ return reject(new Error("Too many redirects"));
90
+ }
91
+
92
+ const parsed = new URL(urlString);
93
+ const isHttps = parsed.protocol === "https:";
94
+ const mod = isHttps ? https : http;
95
+ const proxy = getProxyForUrl(urlString);
96
+
97
+ const doRequest = (extraOptions) => {
98
+ const options = Object.assign(
99
+ {
100
+ hostname: parsed.hostname,
101
+ port: parsed.port || (isHttps ? 443 : 80),
102
+ path: parsed.pathname + parsed.search,
103
+ method: "GET",
104
+ headers: { "User-Agent": "cargo-dist-npm-installer" },
105
+ },
106
+ extraOptions || {},
107
+ );
108
+
109
+ if (proxy && !isHttps) {
110
+ // HTTP through HTTP proxy: request the full URL via the proxy
111
+ options.hostname = proxy.hostname;
112
+ options.port = proxy.port;
113
+ options.path = urlString;
114
+ if (proxy.auth) {
115
+ options.headers["Proxy-Authorization"] =
116
+ "Basic " + Buffer.from(proxy.auth).toString("base64");
117
+ }
118
+ }
119
+
120
+ const req = mod.request(options, (res) => {
121
+ if (
122
+ res.statusCode >= 300 &&
123
+ res.statusCode < 400 &&
124
+ res.headers.location
125
+ ) {
126
+ res.resume();
127
+ const nextUrl = new URL(res.headers.location, urlString).toString();
128
+ return download(nextUrl, maxRedirects - 1).then(resolve, reject);
129
+ }
130
+ if (res.statusCode < 200 || res.statusCode >= 300) {
131
+ res.resume();
132
+ return reject(new Error(`HTTP ${res.statusCode} from ${urlString}`));
133
+ }
134
+ resolve(res);
135
+ });
136
+ req.on("error", reject);
137
+ req.end();
138
+ };
139
+
140
+ if (proxy && isHttps) {
141
+ connectThroughProxy(proxy, parsed).then(
142
+ (socket) => doRequest({ socket, agent: false }),
143
+ reject,
144
+ );
145
+ } else {
146
+ doRequest();
147
+ }
148
+ });
149
+ }
150
+
151
+ class Package {
152
+ constructor(platform, name, url, filename, zipExt, binaries) {
153
+ let errors = [];
154
+ if (typeof url !== "string") {
155
+ errors.push("url must be a string");
156
+ } else {
157
+ try {
158
+ new URL(url);
159
+ } catch (e) {
160
+ errors.push(e);
161
+ }
162
+ }
163
+ if (name && typeof name !== "string") {
164
+ errors.push("package name must be a string");
165
+ }
166
+ if (!name) {
167
+ errors.push("You must specify the name of your package");
168
+ }
169
+ if (binaries && typeof binaries !== "object") {
170
+ errors.push("binaries must be a string => string map");
171
+ }
172
+ if (!binaries) {
173
+ errors.push("You must specify the binaries in the package");
174
+ }
175
+
176
+ if (errors.length > 0) {
177
+ let errorMsg =
178
+ "One or more of the parameters you passed to the Binary constructor are invalid:\n";
179
+ errors.forEach((error) => {
180
+ errorMsg += error;
181
+ });
182
+ errorMsg +=
183
+ '\n\nCorrect usage: new Package("my-binary", "https://example.com/binary/download.tar.gz", {"my-binary": "my-binary"})';
184
+ error(errorMsg);
185
+ }
186
+
187
+ this.platform = platform;
188
+ this.url = url;
189
+ this.name = name;
190
+ this.filename = filename;
191
+ this.zipExt = zipExt;
192
+ this.installDirectory = join(__dirname, "node_modules", ".bin_real");
193
+ this.binaries = binaries;
194
+
195
+ if (!existsSync(this.installDirectory)) {
196
+ mkdirSync(this.installDirectory, { recursive: true });
197
+ }
198
+ }
199
+
200
+ exists() {
201
+ for (const binaryName in this.binaries) {
202
+ const binRelPath = this.binaries[binaryName];
203
+ const binPath = join(this.installDirectory, binRelPath);
204
+ if (!existsSync(binPath)) {
205
+ return false;
206
+ }
207
+ }
208
+ return true;
209
+ }
210
+
211
+ install(suppressLogs = false) {
212
+ if (this.exists()) {
213
+ if (!suppressLogs) {
214
+ console.error(
215
+ `${this.name} is already installed, skipping installation.`,
216
+ );
217
+ }
218
+ return Promise.resolve();
219
+ }
220
+
221
+ try {
222
+ rmSync(this.installDirectory, { recursive: true, force: true });
223
+ } catch {
224
+ // ignore - directory may not exist
225
+ }
226
+
227
+ mkdirSync(this.installDirectory, { recursive: true });
228
+
229
+ if (!suppressLogs) {
230
+ console.error(`Downloading release from ${this.url}`);
231
+ }
232
+
233
+ return download(this.url)
234
+ .then((res) => {
235
+ return new Promise((resolve, reject) => {
236
+ mkdtemp(`${tmpDir}${sep}`, (err, directory) => {
237
+ if (err) return reject(err);
238
+ let tempFile = join(directory, this.filename);
239
+ const sink = res.pipe(createWriteStream(tempFile));
240
+ sink.on("error", (err) => reject(err));
241
+ sink.on("close", () => {
242
+ if (/\.tar\.*/.test(this.zipExt)) {
243
+ const result = spawnSync("tar", [
244
+ "xf",
245
+ tempFile,
246
+ // The tarballs are stored with a leading directory
247
+ // component; we strip one component in the
248
+ // shell installers too.
249
+ "--strip-components",
250
+ "1",
251
+ "-C",
252
+ this.installDirectory,
253
+ ]);
254
+ if (result.status == 0) {
255
+ resolve();
256
+ } else if (result.error) {
257
+ reject(result.error);
258
+ } else {
259
+ reject(
260
+ new Error(
261
+ `An error occurred untarring the artifact: stdout: ${result.stdout}; stderr: ${result.stderr}`,
262
+ ),
263
+ );
264
+ }
265
+ } else if (this.zipExt == ".zip") {
266
+ let result;
267
+ if (this.platform.artifactName.includes("windows")) {
268
+ // Windows does not have "unzip" by default on many installations, instead
269
+ // we use Expand-Archive from powershell
270
+ result = spawnSync("powershell.exe", [
271
+ "-NoProfile",
272
+ "-NonInteractive",
273
+ "-Command",
274
+ `& {
275
+ param([string]$LiteralPath, [string]$DestinationPath)
276
+ Expand-Archive -LiteralPath $LiteralPath -DestinationPath $DestinationPath -Force
277
+ }`,
278
+ tempFile,
279
+ this.installDirectory,
280
+ ]);
281
+ } else {
282
+ result = spawnSync("unzip", [
283
+ "-q",
284
+ tempFile,
285
+ "-d",
286
+ this.installDirectory,
287
+ ]);
288
+ }
289
+
290
+ if (result.status == 0) {
291
+ resolve();
292
+ } else if (result.error) {
293
+ reject(result.error);
294
+ } else {
295
+ reject(
296
+ new Error(
297
+ `An error occurred unzipping the artifact: stdout: ${result.stdout}; stderr: ${result.stderr}`,
298
+ ),
299
+ );
300
+ }
301
+ } else {
302
+ reject(
303
+ new Error(`Unrecognized file extension: ${this.zipExt}`),
304
+ );
305
+ }
306
+ });
307
+ });
308
+ });
309
+ })
310
+ .then(() => {
311
+ if (!suppressLogs) {
312
+ console.error(`${this.name} has been installed!`);
313
+ }
314
+ })
315
+ .catch((e) => {
316
+ error(`Error fetching release: ${e.message}`);
317
+ });
318
+ }
319
+
320
+ run(binaryName) {
321
+ const promise = !this.exists() ? this.install(true) : Promise.resolve();
322
+
323
+ promise
324
+ .then(() => {
325
+ const [, , ...args] = process.argv;
326
+
327
+ const options = { cwd: process.cwd(), stdio: "inherit" };
328
+
329
+ const binRelPath = this.binaries[binaryName];
330
+ if (!binRelPath) {
331
+ error(`${binaryName} is not a known binary in ${this.name}`);
332
+ }
333
+ const binPath = join(this.installDirectory, binRelPath);
334
+ const result = spawnSync(binPath, args, options);
335
+
336
+ if (result.error) {
337
+ error(result.error);
338
+ }
339
+
340
+ process.exit(result.status);
341
+ })
342
+ .catch((e) => {
343
+ error(e.message);
344
+ });
345
+ }
346
+ }
347
+
348
+ module.exports.Package = Package;
package/binary.js ADDED
@@ -0,0 +1,124 @@
1
+ const { Package } = require("./binary-install");
2
+ const os = require("os");
3
+ const libc = require("detect-libc");
4
+
5
+ const error = (msg) => {
6
+ console.error(msg);
7
+ process.exit(1);
8
+ };
9
+
10
+ const {
11
+ name,
12
+ artifactDownloadUrls,
13
+ supportedPlatforms,
14
+ glibcMinimum,
15
+ } = require("./package.json");
16
+
17
+ // FIXME: implement NPM installer handling of fallback download URLs
18
+ const artifactDownloadUrl = artifactDownloadUrls[0];
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 pkg = getPackage();
110
+
111
+ return pkg.install(suppressLogs);
112
+ };
113
+
114
+ const run = (binaryName) => {
115
+ const pkg = getPackage();
116
+
117
+ pkg.run(binaryName);
118
+ };
119
+
120
+ module.exports = {
121
+ install,
122
+ run,
123
+ getPackage,
124
+ };
package/install.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { install } = require("./binary");
4
+ install(false);
@@ -0,0 +1,52 @@
1
+ {
2
+ "lockfileVersion": 3,
3
+ "name": "@traz-dev/traz",
4
+ "packages": {
5
+ "": {
6
+ "bin": {
7
+ "traz": "run-traz.js"
8
+ },
9
+ "dependencies": {
10
+ "detect-libc": "^2.1.2"
11
+ },
12
+ "devDependencies": {
13
+ "prettier": "^3.8.3"
14
+ },
15
+ "engines": {
16
+ "node": ">=14.14",
17
+ "npm": ">=6"
18
+ },
19
+ "hasInstallScript": true,
20
+ "license": "MIT",
21
+ "name": "@traz-dev/traz",
22
+ "version": "0.1.0"
23
+ },
24
+ "node_modules/detect-libc": {
25
+ "engines": {
26
+ "node": ">=8"
27
+ },
28
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
29
+ "license": "Apache-2.0",
30
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
31
+ "version": "2.1.2"
32
+ },
33
+ "node_modules/prettier": {
34
+ "bin": {
35
+ "prettier": "bin/prettier.cjs"
36
+ },
37
+ "dev": true,
38
+ "engines": {
39
+ "node": ">=14"
40
+ },
41
+ "funding": {
42
+ "url": "https://github.com/prettier/prettier?sponsor=1"
43
+ },
44
+ "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
45
+ "license": "MIT",
46
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
47
+ "version": "3.8.3"
48
+ }
49
+ },
50
+ "requires": true,
51
+ "version": "0.1.0"
52
+ }
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "artifactDownloadUrls": [
3
+ "https://github.com/mithilgirish/traz/releases/download/v0.1.0"
4
+ ],
5
+ "author": "Mithil Girish",
6
+ "bin": {
7
+ "traz": "run-traz.js"
8
+ },
9
+ "dependencies": {
10
+ "detect-libc": "^2.1.2"
11
+ },
12
+ "description": "A local-first engineering memory layer and MCP server for AI coding tools",
13
+ "devDependencies": {
14
+ "prettier": "^3.8.3"
15
+ },
16
+ "engines": {
17
+ "node": ">=14.14",
18
+ "npm": ">=6"
19
+ },
20
+ "glibcMinimum": {
21
+ "major": 2,
22
+ "series": 39
23
+ },
24
+ "homepage": "https://traz.mithilgirish.dev",
25
+ "keywords": [
26
+ "development-tools",
27
+ "command-line-utilities",
28
+ "mcp",
29
+ "ai",
30
+ "claude",
31
+ "llm",
32
+ "context"
33
+ ],
34
+ "license": "MIT",
35
+ "name": "@traz-dev/traz",
36
+ "preferUnplugged": true,
37
+ "repository": "https://github.com/mithilgirish/traz",
38
+ "scripts": {
39
+ "fmt": "prettier --write **/*.js",
40
+ "fmt:check": "prettier --check **/*.js",
41
+ "postinstall": "node ./install.js"
42
+ },
43
+ "supportedPlatforms": {
44
+ "aarch64-apple-darwin": {
45
+ "artifactName": "traz-aarch64-apple-darwin.tar.xz",
46
+ "bins": {
47
+ "traz": "traz"
48
+ },
49
+ "zipExt": ".tar.xz"
50
+ },
51
+ "aarch64-pc-windows-msvc": {
52
+ "artifactName": "traz-x86_64-pc-windows-msvc.zip",
53
+ "bins": {
54
+ "traz": "traz.exe"
55
+ },
56
+ "zipExt": ".zip"
57
+ },
58
+ "aarch64-unknown-linux-gnu": {
59
+ "artifactName": "traz-aarch64-unknown-linux-gnu.tar.xz",
60
+ "bins": {
61
+ "traz": "traz"
62
+ },
63
+ "zipExt": ".tar.xz"
64
+ },
65
+ "x86_64-pc-windows-gnu": {
66
+ "artifactName": "traz-x86_64-pc-windows-msvc.zip",
67
+ "bins": {
68
+ "traz": "traz.exe"
69
+ },
70
+ "zipExt": ".zip"
71
+ },
72
+ "x86_64-pc-windows-msvc": {
73
+ "artifactName": "traz-x86_64-pc-windows-msvc.zip",
74
+ "bins": {
75
+ "traz": "traz.exe"
76
+ },
77
+ "zipExt": ".zip"
78
+ },
79
+ "x86_64-unknown-linux-gnu": {
80
+ "artifactName": "traz-x86_64-unknown-linux-gnu.tar.xz",
81
+ "bins": {
82
+ "traz": "traz"
83
+ },
84
+ "zipExt": ".tar.xz"
85
+ }
86
+ },
87
+ "version": "0.1.0",
88
+ "volta": {
89
+ "node": "18.14.1",
90
+ "npm": "9.5.0"
91
+ }
92
+ }
package/run-traz.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { run } = require("./binary");
4
+ run("traz");