@nrafinia/csmesh 0.2.6 → 0.2.8
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/README.md +556 -0
- package/bin/run.js +32 -0
- package/package.json +1 -1
- package/scripts/install.js +85 -0
package/README.md
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ⚡ csmesh
|
|
4
|
+
|
|
5
|
+
### Structural Code Intelligence Engine for C# & .NET
|
|
6
|
+
|
|
7
|
+
**Answers architectural, call-graph, and dependency questions under a hard token budget.**
|
|
8
|
+
Built for AI coding agents and developers who are tired of multi-turn "file-hopping" and noisy grep queries.
|
|
9
|
+
|
|
10
|
+
[](https://dotnet.microsoft.com/)
|
|
11
|
+
[](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/)
|
|
12
|
+
[](https://github.com/nRafinia/CsMesh)
|
|
13
|
+
[](https://github.com/nRafinia/CsMesh)
|
|
14
|
+
[](LICENSE)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
$ csmesh trace PaymentController.Post --budget 600
|
|
25
|
+
|
|
26
|
+
PaymentController.Post {http:POST /charge} Api/PaymentController.cs:14
|
|
27
|
+
-> CreatePaymentCommandHandler.Handle [mediatr via Send(CreatePaymentCommand)] App/CreatePaymentCommand.cs:18
|
|
28
|
+
-> IPaymentGateway.Authorize Infra/Repositories.cs:11
|
|
29
|
+
-> StripeGateway.Authorize [impl, di-bound] Infra/Repositories.cs:29
|
|
30
|
+
-> IPaymentRepository.Add Infra/Repositories.cs:7
|
|
31
|
+
-> PaymentRepository.Add [impl, di-bound] Infra/Repositories.cs:17
|
|
32
|
+
-> AppDbContext.SavePayment Infra/Repositories.cs:34
|
|
33
|
+
-> InMemoryPaymentRepository.Add [impl] Infra/Repositories.cs:23
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 📑 Table of Contents
|
|
40
|
+
|
|
41
|
+
- [The Problem: The Hidden Tax of AI Code Exploration](#-the-problem-the-hidden-tax-of-ai-code-exploration)
|
|
42
|
+
- [Dual Mode: CLI and MCP Server Support](#-dual-mode-cli-and-mcp-server-support)
|
|
43
|
+
- [Empirical Benchmarks](#-empirical-benchmarks)
|
|
44
|
+
- [Key Features](#-key-features)
|
|
45
|
+
- [Installation](#-installation)
|
|
46
|
+
- [Global .NET Tool](#1-as-a-global-net-tool)
|
|
47
|
+
- [Standalone Native AOT Binary](#2-as-a-standalone-native-aot-binary-zero-runtime-dependency)
|
|
48
|
+
- [Quick Start](#-quick-start)
|
|
49
|
+
- [Supported IDEs & AI Coding Agents](#-supported-ides--ai-coding-agents)
|
|
50
|
+
- [CLI Reference](#-cli-reference)
|
|
51
|
+
- [The Recommended Hybrid Workflow: csmesh vs. grep](#-the-recommended-hybrid-workflow-csmesh-vs-grep)
|
|
52
|
+
- [Deterministic Exit Codes](#-deterministic-exit-codes)
|
|
53
|
+
- [Telemetry & Audit Logging](#-telemetry--audit-logging)
|
|
54
|
+
- [Repository Structure](#-repository-structure)
|
|
55
|
+
- [License](#-license)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 🛑 The Problem: The Hidden Tax of AI Code Exploration
|
|
60
|
+
|
|
61
|
+
When an AI coding agent or engineer asks a structural question about a decoupled C# codebase—such as:
|
|
62
|
+
* *"If I modify this interface method, what breaks downstream?"*
|
|
63
|
+
* *"Which concrete class is actually resolved and injected by the DI container at runtime?"*
|
|
64
|
+
* *"Where does this Mediator `_mediator.Send()` or background queue message end up?"*
|
|
65
|
+
|
|
66
|
+
...standard tooling forces a repetitive, expensive **"file-hopping" loop**:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
[Agent] grep for interface -> finds 12 test fakes, mocks, & docstrings
|
|
70
|
+
↓ (Turn 1: ~600 tokens)
|
|
71
|
+
[Agent] opens File A -> finds interface dispatch, not the implementation
|
|
72
|
+
↓ (Turn 2: ~800 tokens)
|
|
73
|
+
[Agent] greps for DI registration -> sifts through Program.cs and test fixtures
|
|
74
|
+
↓ (Turn 3: ~1,200 tokens)
|
|
75
|
+
[Agent] opens File B -> discovers it sends a MediatR command
|
|
76
|
+
↓ (Turn 4: ~1,500 tokens)
|
|
77
|
+
Context Exhaustion & Slow Responses (~5,000 tokens burned, 4-5 turns wasted)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
In layered, enterprise .NET applications, **lexical text search (`grep`, `ripgrep`) hits a wall**. Text search cannot see:
|
|
81
|
+
1. **Dependency Injection Bindings** (`AddScoped<IService, Service>()`)
|
|
82
|
+
2. **CQRS / MediatR Handler Dispatches** (`_mediator.Send(cmd)`)
|
|
83
|
+
3. **Interface Implementation Ranking** (distinguishing production services from mock fakes)
|
|
84
|
+
4. **Attribute-based Endpoint Routing** (`[HttpGet]`, `[HttpPost]`, `[Route]`)
|
|
85
|
+
|
|
86
|
+
**`csmesh` solves this in a single shell command.** It parses your codebase's AST and semantic model via Roslyn into a pre-compiled, frozen symbol graph that returns exact answers in milliseconds.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 🔌 Dual Mode: CLI and MCP Server Support
|
|
91
|
+
|
|
92
|
+
`csmesh` supports both **command-line interface (CLI)** and **Model Context Protocol (MCP)** workflows with a first-class experience, giving developers and AI agents the flexibility to choose what works best:
|
|
93
|
+
|
|
94
|
+
* **⚡ Fast CLI-First Execution:**
|
|
95
|
+
- **Zero Idle Context Overhead:** Incurs zero token spend until explicitly invoked.
|
|
96
|
+
- **Hard Token Caps (`--budget`):** Guarantees answers fit within strict limits (e.g. `--budget 300` or `--budget 600`), exiting cleanly with code `2` on overflow instead of polluting conversation history.
|
|
97
|
+
- **Command Chaining:** Chain queries in a single turn (`csmesh impl IStore --budget 200 && csmesh blast-radius Order.Submit --budget 400`).
|
|
98
|
+
|
|
99
|
+
* **🤖 Native Model Context Protocol (MCP) Server:**
|
|
100
|
+
- **Interactive Agent Experience:** Run `csmesh serve` to expose query tools over standard JSON-RPC (stdio) to MCP-compatible clients like Claude Desktop, Cursor, Antigravity, VS Code, Windsurf, and Cline.
|
|
101
|
+
- **One-Command Setup:** Register csmesh into IDE configurations with `csmesh install --mcp` (locally) or `csmesh install --mcp --global` (machine-wide).
|
|
102
|
+
- **Token-Efficient Tool Responses:** Returns dense, structured plaintext designed for LLM comprehension without wasteful, unbounded JSON dumps.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 📊 Empirical Benchmarks
|
|
107
|
+
|
|
108
|
+
To quantify the real-world performance gains, `csmesh` was benchmarked against the standard AI agent workflow (**Ripgrep / `rg` + sequential file reads**) across a real-world enterprise .NET backend codebase (**29 projects, 1,942 symbols, 5,143 edges**).
|
|
109
|
+
|
|
110
|
+
The evaluation measured four critical dimensions:
|
|
111
|
+
1. **Query & Execution Latency**: Raw tool execution time and total agent turnaround time.
|
|
112
|
+
2. **Agent Round-Trips**: Number of iterative tool calls and model reasoning turns required to reach the answer.
|
|
113
|
+
3. **Context Spend & Token Consumption**: Prompt tokens spent on search noise vs. dense architectural facts.
|
|
114
|
+
4. **Semantic Accuracy**: Ability to distinguish runtime DI bindings, production code, and test doubles.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### Scenario-by-Scenario Benchmark Summary
|
|
119
|
+
|
|
120
|
+
| Workflow Scenario | With `csmesh` (Single Command) | Without `csmesh` (`rg` + File Reads) | Speed & Turn Efficiency | Token & Context Savings |
|
|
121
|
+
|:---|:---|:---|:---|:---|
|
|
122
|
+
| **1. DI Implementation & Binding**<br>`csmesh impl IOrderRepository` | **244 ms**<br>*(1 command / 1 turn)* | **~3 agent round-trips**<br>*(grep interface + grep DI registration + open config/file)* | **~15x faster** agent turnaround | **~90% reduction**<br>*(~100 tokens vs. ~1,500 tokens)* |
|
|
123
|
+
| **2. Deep Call Chain Trace**<br>`csmesh trace OrderEndpoints.CreateOrderAsync` | **156 ms**<br>*(1 command to specified depth)* | **5 to 7 iterative turns**<br>*(manually hopping across controllers, interfaces & handlers)* | **~30x faster** end-to-end task time | **~85% reduction**<br>*(~450 tokens vs. ~4,000 tokens)* |
|
|
124
|
+
| **3. Change Impact & Blast Radius**<br>`csmesh blast-radius OrderRepository.UpdateAsync` | **161 ms**<br>*(reverse graph separating test vs. prod callers)* | **4 to 6 manual turns**<br>*(grep for method name with dozens of false positives)* | Eliminates error-prone manual caller matching | **~80% reduction**<br>*(filters out comments, docs, & unrelated homonyms)* |
|
|
125
|
+
| **4. Multi-Hop Path Finding**<br>`csmesh path Endpoint -> Repository` | **157 ms**<br>*(deterministic 4-hop path across DI & services)* | **Impossible with grep**<br>*(requires multi-file inference, guessing, and trial-and-error)* | Solves in 1 deterministic step | **~95% reduction**<br>*(no intermediate exploratory reads)* |
|
|
126
|
+
| **5. Endpoint & Worker Discovery**<br>`csmesh entrypoints` | **143 ms**<br>*(both HTTP routes & background HostedServices)* | **Multiple grep commands + manual parsing**<br>*(high risk of missing background workers and consumers)* | 100% automated structural coverage | Structured, clean, noise-free output |
|
|
127
|
+
| **6. Type Structure & Signature**<br>`csmesh context OrderRecord` | **166 ms**<br>*(fields, nullability, signatures without reading disk)* | `rg` to locate file path + `view_file` to read entire source | 3x fewer steps | **~70% reduction**<br>*(symbol members only, no boilerplate)* |
|
|
128
|
+
| **7. Full Architecture Mapping**<br>`csmesh map` | **174 ms**<br>*(29 projects, dependency flow & entrypoint clusters)* | Read `.slnx` + inspect 29 `.csproj` project files manually | Hundreds of times faster | **~95% reduction** |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### Deep-Dive Real-World Scenarios
|
|
133
|
+
|
|
134
|
+
#### 1. Interface Implementation & Runtime DI Resolution
|
|
135
|
+
* **With `csmesh impl IOrderRepository --budget 300` (244 ms):**
|
|
136
|
+
Identifies all 3 concrete implementations in a single glance: tags `SqlOrderRepository` with `[di:scoped]` along with the exact file and line where it was bound in the IoC container, while clearly marking `SpyOrderRepository` and `InMemoryOrderRepository` as test doubles.
|
|
137
|
+
* **Without `csmesh`:**
|
|
138
|
+
- *Turn 1:* Run `rg ":\s*IOrderRepository\b"` to find inheriting classes (returns multiple classes, but cannot indicate which one is registered in production).
|
|
139
|
+
- *Turn 2:* Run `rg "AddScoped.*IOrderRepository"` to discover registration logic.
|
|
140
|
+
- *Turn 3:* Open the DI module or test fixture to verify which instance actually executes at runtime.
|
|
141
|
+
|
|
142
|
+
#### 2. Forward Call Chain Tracing Across Interface Boundaries
|
|
143
|
+
* **With `csmesh trace OrderEndpoints.CreateOrderAsync --depth 2` (156 ms):**
|
|
144
|
+
Follows execution seamlessly across decoupled interface abstractions. Traces `IAuthorizationService.AuthorizeAsync` directly to its concrete implementation `AuthorizationService.AuthorizeAsync`, continuing downstream to `AuditLogger.LogAsync` and `AppDbContext.SaveChangesAsync`.
|
|
145
|
+
* **Without `csmesh`:**
|
|
146
|
+
The agent must open the endpoint file (~100 lines), observe the interface call, search for the interface declaration, grep for implementations, open the implementation source, and repeat this cycle until reaching the persistence layer—burning 5 to 7 turns and 30+ seconds of reasoning time.
|
|
147
|
+
|
|
148
|
+
#### 3. Blast Radius & Change Impact Analysis
|
|
149
|
+
* **With `csmesh blast-radius OrderRepository.UpdateAsync --budget 800` (161 ms):**
|
|
150
|
+
Computes the reverse transitive dependency graph: reveals that modifying `UpdateAsync` impacts 18 internal members, 1 public HTTP route (`OrderEndpoints.CreateOrderAsync`), and 14 tests across 4 separate projects—clearly categorizing test callers vs. production entrypoints.
|
|
151
|
+
* **Without `csmesh`:**
|
|
152
|
+
Running `rg "\bUpdateAsync\b"` returns dozens of raw matching lines across interfaces, mocks, comments, and unrelated classes. Text search cannot determine which root endpoints ultimately depend on this method without exhaustive manual back-tracing.
|
|
153
|
+
|
|
154
|
+
#### 4. Multi-Hop Path Finding
|
|
155
|
+
* **With `csmesh path OrderEndpoints.CreateOrderAsync OrderRepository.UpdateAsync` (157 ms):**
|
|
156
|
+
```text
|
|
157
|
+
OrderEndpoints.CreateOrderAsync
|
|
158
|
+
-> OrderService.ProcessOrderAsync
|
|
159
|
+
-> IOrderRepository.UpdateAsync
|
|
160
|
+
-> SqlOrderRepository.UpdateAsync [impl, di-bound]
|
|
161
|
+
```
|
|
162
|
+
Resolves the exact 4-hop invocation path through services and DI container registrations in 157 ms—a task fundamentally beyond the capabilities of text search.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### Core Takeaways
|
|
167
|
+
|
|
168
|
+
1. **Semantic Intelligence vs. Lexical Speed:** While `ripgrep` searches text in 30–50 ms, its output is **lexical, not semantic**. `csmesh` answers in **140–250 ms**, but returns definitive, actionable architectural conclusions rather than raw strings.
|
|
169
|
+
2. **Eliminating the Agent Turn Latency Bottleneck:** In AI agent interactions, the dominant latency cost is LLM inference and reasoning per turn (often 5–15 seconds per round-trip). By collapsing 4 to 8 file-hunting turns into **1 single shell command**, `csmesh` cuts total agent task completion time by **over 80%**.
|
|
170
|
+
3. **Context Window Hygiene:** Replacing full source file dumps with compact graph edges saves **80% to 95% of token spend**, preserving the model's context window for actual implementation rather than navigation.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## ✨ Key Features
|
|
175
|
+
|
|
176
|
+
- **🚀 Native AOT & .NET 10 Ready:** Instantaneous sub-millisecond execution, zero JIT warm-up, and zero-allocation queries via `System.Collections.Frozen`.
|
|
177
|
+
- **🛡️ Token-Budget Enforcement (`--budget N`):** Hard limits on output tokens. Prevents agent context exhaustion by exiting with actionable tips when a query is too broad.
|
|
178
|
+
- **💉 DI & IoC Container Intelligence:** Reads service registrations in every form they take — two-argument, `typeof` pairs, keyed, factory lambdas, and alias registrations such as `sp => sp.GetRequiredService<Concrete>()` — and ranks the class the container actually returns ahead of the ones nobody registered.
|
|
179
|
+
- **📨 MediatR & CQRS Linking:** Resolves `_mediator.Send(...)` and `Publish(...)` calls to their concrete request handlers across decoupled project boundaries.
|
|
180
|
+
- **💥 Blast Radius & Impact Analysis:** Computes the reverse call graph to surface all direct/indirect callers, affected controllers, and background consumers before modifying a symbol.
|
|
181
|
+
- **🌐 Universal AI Agent Integration:** Installs native prompt rules and skills for **12+ AI tools** (Claude Code, Cursor, Antigravity, OpenCode, Windsurf, Cline, Copilot, MiMo Code, etc.) with both local and `--global` machine-wide support.
|
|
182
|
+
- **🔄 Incremental Re-indexing:** Node identity is a compiler symbol key, not an array position, so an edit re-binds only the files that moved and every edge into them survives. Rows from files the index has not caught up with are tagged `[STALE]`; `--heal` re-binds them before answering. Falls back to a full pass when an edit touches something that binds across files.
|
|
183
|
+
- **🧭 Entry by Description, Not by Name:** `csmesh where <term>` searches names, namespaces, file paths and route templates, then ranks by how many entrypoints reach each hit — so the handler outranks the DTO that shares its name.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 📦 Installation
|
|
188
|
+
|
|
189
|
+
### ⚡ Automatic One-Line Install (Recommended)
|
|
190
|
+
|
|
191
|
+
**Linux & macOS:**
|
|
192
|
+
```bash
|
|
193
|
+
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | sh
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Windows (PowerShell):**
|
|
197
|
+
```powershell
|
|
198
|
+
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iex
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### 1. As a Global .NET Tool
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Install from NuGet.org
|
|
207
|
+
dotnet tool install --global CsMesh
|
|
208
|
+
|
|
209
|
+
# Or build and install locally from source
|
|
210
|
+
dotnet pack -c Release
|
|
211
|
+
dotnet tool install --global --add-source ./src/CsMesh/bin/Release CsMesh
|
|
212
|
+
|
|
213
|
+
# Or update an existing installation
|
|
214
|
+
dotnet tool update --global CsMesh
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
<!-- ### 2. Via npm / npx
|
|
218
|
+
```bash
|
|
219
|
+
Bash
|
|
220
|
+
# Run directly without global installation
|
|
221
|
+
npx @nrafinia/csmesh --help
|
|
222
|
+
|
|
223
|
+
# Or install globally across Windows, macOS, and Linux
|
|
224
|
+
npm install -g @nrafinia/csmesh
|
|
225
|
+
```
|
|
226
|
+
-->
|
|
227
|
+
### 2. As a Standalone Native AOT Binary (Zero Runtime Dependency)
|
|
228
|
+
|
|
229
|
+
You can compile a single, standalone binary with zero dependencies on the .NET SDK:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Windows (win-x64)
|
|
233
|
+
dotnet publish src/CsMesh/CsMesh.csproj -c Release -r win-x64 -p:PublishAot=true
|
|
234
|
+
|
|
235
|
+
# Linux (linux-x64) - run via Linux or WSL
|
|
236
|
+
dotnet publish src/CsMesh/CsMesh.csproj -c Release -r linux-x64 -p:PublishAot=true
|
|
237
|
+
|
|
238
|
+
# macOS (osx-arm64)
|
|
239
|
+
dotnet publish src/CsMesh/CsMesh.csproj -c Release -r osx-arm64 -p:PublishAot=true
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The resulting binary in `bin/Release/net10.0/<rid>/publish/` has **sub-100ms startup** and runs on machines without .NET installed.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 🚀 Quick Start
|
|
247
|
+
|
|
248
|
+
Run these commands inside any C# / .NET repository (`.sln`, `.slnx`, `.csproj`):
|
|
249
|
+
|
|
250
|
+
### 1. Index the Repository
|
|
251
|
+
```bash
|
|
252
|
+
csmesh index
|
|
253
|
+
# indexed 28 files -> 161 nodes, 380 edges in 0.1s
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 2. Configure Your AI Coding Assistants
|
|
257
|
+
```bash
|
|
258
|
+
# Install skill and rule files in the current repository:
|
|
259
|
+
csmesh install
|
|
260
|
+
|
|
261
|
+
# Or install both skill files and MCP server integration:
|
|
262
|
+
csmesh install --all
|
|
263
|
+
|
|
264
|
+
# Or install machine-wide into your user profile (~/.claude, ~/.cursor, ~/.gemini, etc.):
|
|
265
|
+
csmesh install --global
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### 3. Ask Structural Questions
|
|
269
|
+
```bash
|
|
270
|
+
# I have words, not a symbol name.
|
|
271
|
+
csmesh where discount
|
|
272
|
+
|
|
273
|
+
# What does this method call down the line?
|
|
274
|
+
csmesh trace OrderService.SubmitOrder --budget 600
|
|
275
|
+
|
|
276
|
+
# Which concrete implementation runs for this interface in DI?
|
|
277
|
+
csmesh impl IPaymentGateway --budget 300
|
|
278
|
+
|
|
279
|
+
# What breaks if I change this method or property?
|
|
280
|
+
csmesh blast-radius Order.Status --budget 800
|
|
281
|
+
|
|
282
|
+
# Where are all the API routes and hosted workers?
|
|
283
|
+
csmesh entrypoints orders
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 🤖 Supported IDEs & AI Coding Agents
|
|
289
|
+
|
|
290
|
+
`csmesh install` sets up native prompt instructions and skills across all major coding tools:
|
|
291
|
+
|
|
292
|
+
| Agent / IDE | Local Target (`csmesh install`) | Global Target (`--global` / `-g`) | Format |
|
|
293
|
+
|:---|:---|:---|:---|
|
|
294
|
+
| **VS Code** | `.vscode/mcp.json` + `.github/copilot-instructions.md` | `~/.copilot/copilot-instructions.md` | MCP Server + Copilot Instructions |
|
|
295
|
+
| **JetBrains Rider** | `.mcp.json` + `AGENTS.md` | `~/.ai/mcp/mcp.json` + `~/.codex/AGENTS.md` | MCP Server + Agent Rules Block |
|
|
296
|
+
| **Claude Code** | `.claude/skills/csmesh/SKILL.md` | `~/.claude/skills/...` + `CLAUDE.md` | Skill (YAML frontmatter) |
|
|
297
|
+
| **Cursor** | `.cursor/rules/csmesh.mdc` + `.cursor/mcp.json` | `~/.cursor/rules/...` + `~/.cursor/mcp.json` | MDC Rule + MCP Server |
|
|
298
|
+
| **Google Antigravity** | `.agents/skills/csmesh/SKILL.md` + `.agents/mcp_config.json` | `~/.gemini/config/skills/...` + `mcp_config.json` | Workspace Skill + Rules + MCP |
|
|
299
|
+
| **Windsurf (Cascade)** | `.windsurfrules` | `~/.codeium/windsurf/` (rules & `mcp_config.json`) | Tagged Rules Block + MCP Server |
|
|
300
|
+
| **Cline & Roo Code** | `.clinerules` or `.cline/mcp.json` | `~/.cline/rules/` + `cline_mcp_settings.json` | Tagged Instruction Block + MCP Server |
|
|
301
|
+
| **GitHub Copilot** | `.github/copilot-instructions.md` | `~/.copilot/copilot-instructions.md` | User Instructions Block |
|
|
302
|
+
| **MiMo Code (Xiaomi)** | `.mimocode/skills/csmesh/SKILL.md` + `AGENTS.md` | `~/.mimocode/skills/...` + `.mimo/` | Skill + Agent Instructions |
|
|
303
|
+
| **Kilo Code** | `.kilocode/rules/csmesh.md` | `~/.kilocode/rules/csmesh.md` | Native Rule File |
|
|
304
|
+
| **Codex CLI & Kimi AI**| `AGENTS.md` | `~/.codex/AGENTS.md` | Open Agent Standard Block |
|
|
305
|
+
| **Gemini CLI** | `GEMINI.md` | `~/.gemini/GEMINI.md` | Open Agent Standard Block |
|
|
306
|
+
| **OpenCode** | `AGENTS.md` + `.opencode/rules/csmesh.md` | `~/.config/opencode/AGENTS.md` + `~/.opencode/rules/` | Open Agent Standard Block & Rules |
|
|
307
|
+
|
|
308
|
+
> [!TIP]
|
|
309
|
+
> Shared configuration files (`AGENTS.md`, `GEMINI.md`, `.windsurfrules`, `.clinerules`, `.github/copilot-instructions.md`) use safe tagged blocks (`<!-- csmesh-instructions -->`). Existing developer rules are **never overwritten**. When `--mcp` is passed (`csmesh install --mcp` or `csmesh install --all`), native MCP server configurations (`.mcp.json`, `.vscode/mcp.json`, `.cursor/mcp.json`, `~/.claude.json`, `cline_mcp_settings.json`, etc.) are also automatically merged.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 📖 CLI Reference
|
|
314
|
+
|
|
315
|
+
### Global Options
|
|
316
|
+
|
|
317
|
+
| Option | Description |
|
|
318
|
+
|:---|:---|
|
|
319
|
+
| `--repo <PATH>` | Target repository root (default: nearest `.sln`, `.slnx`, or `.git` above cwd) |
|
|
320
|
+
| `--under <PATH>` | Restrict the answer to a subtree, e.g. `--under src/Api`. Narrow before raising the budget. |
|
|
321
|
+
| `--budget <N>` | Hard token limit for stdout. Exits code `2` on overflow. Defaults per command below. |
|
|
322
|
+
| `--depth <N>` | Traversal depth limit (`trace` 6, `blast-radius` 3, `context` 3, `path` 12, `diff` 3) |
|
|
323
|
+
| `--heal` | Re-bind changed files before answering, instead of marking rows `[STALE]` |
|
|
324
|
+
| `--json` | Output results in structured JSON format |
|
|
325
|
+
| `--debug` | Print verbose diagnostics to stderr |
|
|
326
|
+
| `--no-telemetry` | Skip recording the invocation in local usage metrics |
|
|
327
|
+
| `-h, --help` | Display command help and usage examples |
|
|
328
|
+
|
|
329
|
+
Default budgets: `impl` 300, `path`/`where` 400, `trace`/`unresolved` 600, `map`/`silence` 700, everything else 800.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
### Commands
|
|
334
|
+
|
|
335
|
+
#### `csmesh map`
|
|
336
|
+
Where the weight is: which projects lean on which, where the entrypoints cluster, and the handful of members everything runs through. The first command to run in a repository you do not know — `ls` answers "where are the files", which is the wrong axis.
|
|
337
|
+
```bash
|
|
338
|
+
csmesh map
|
|
339
|
+
csmesh map --under src/Application --budget 400
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### `csmesh where <term>` (alias: `find`)
|
|
343
|
+
Finds the symbols a word belongs to, ranked by how many entrypoints reach them. Start here when the task is described in words rather than symbol names; the last line is the next command, already filled in.
|
|
344
|
+
```bash
|
|
345
|
+
csmesh where discount
|
|
346
|
+
csmesh where checkout refund --under src/Application
|
|
347
|
+
csmesh find "POST /orders"
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
#### `csmesh index`
|
|
351
|
+
Builds or refreshes the Roslyn symbol graph stored in `.csmesh/graph.json`. Incremental by default: only the files that changed since the last index are re-bound, and their symbols keep their existing identity so every edge into them survives the edit. Falls back to a full pass when an edit touches something that binds across files — an interface declaration, a handler, a container registration.
|
|
352
|
+
```bash
|
|
353
|
+
csmesh index
|
|
354
|
+
csmesh index --full # force a whole-solution rebuild
|
|
355
|
+
csmesh index --all # include projects no solution file builds
|
|
356
|
+
csmesh index --repo ./src
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
#### `csmesh trace <Type.Member>`
|
|
360
|
+
Follows execution pathways through method calls, interface dispatch, MediatR, and constructor invocations.
|
|
361
|
+
```bash
|
|
362
|
+
csmesh trace PaymentController.Post --budget 600
|
|
363
|
+
csmesh trace OrderService.Submit --depth 3
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
#### `csmesh impl <IInterface>`
|
|
367
|
+
Finds all implementations of an interface, ranking DI-bound registrations first.
|
|
368
|
+
```bash
|
|
369
|
+
csmesh impl IPaymentGateway --budget 300
|
|
370
|
+
csmesh impl IOrderRepository
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### `csmesh blast-radius <Type.Member>` (alias: `blast`)
|
|
374
|
+
Discovers direct callers, transitive callers, and reachable entrypoints affected by modifying a member.
|
|
375
|
+
```bash
|
|
376
|
+
csmesh blast-radius Order.Status --budget 800
|
|
377
|
+
csmesh blast PaymentService.Process --depth 2
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
#### `csmesh entrypoints [filter]`
|
|
381
|
+
Finds HTTP endpoints (`[HttpGet]`, `[HttpPost]`), message handlers, consumers, and background services.
|
|
382
|
+
```bash
|
|
383
|
+
csmesh entrypoints
|
|
384
|
+
csmesh entrypoints payments
|
|
385
|
+
csmesh entrypoints "POST /orders"
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### `csmesh context <Type.Member>`
|
|
389
|
+
Everything structural about one symbol in a single call: signature, members, callers, callees, implementations and the entrypoints above it. Replaces a `trace` plus an `impl` plus a `blast-radius`.
|
|
390
|
+
```bash
|
|
391
|
+
csmesh context OrderService --budget 800
|
|
392
|
+
csmesh context IPaymentGateway.Authorize --depth 2
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
#### `csmesh path <From> <To>` (alias: `why`)
|
|
396
|
+
The shortest route between two symbols, across DI bindings and MediatR dispatch. Answers "how does this controller ever reach that repository".
|
|
397
|
+
```bash
|
|
398
|
+
csmesh path PaymentController.Post SqlOrderStore.Save
|
|
399
|
+
csmesh why OrderController.Post CreateOrderHandler.Handle --budget 400
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
#### `csmesh cycles`
|
|
403
|
+
Circular dependencies between types, namespaces or projects. Reports one concrete loop per component rather than an unordered set.
|
|
404
|
+
```bash
|
|
405
|
+
csmesh cycles
|
|
406
|
+
csmesh cycles --project
|
|
407
|
+
csmesh cycles --namespace --under src/Domain
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
#### `csmesh diff [ref]`
|
|
411
|
+
The symbols a git change touched, and what they reach. Defaults to the working tree against `HEAD`.
|
|
412
|
+
```bash
|
|
413
|
+
csmesh diff
|
|
414
|
+
csmesh diff --staged
|
|
415
|
+
csmesh diff origin/main --budget 800
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### `csmesh changes`
|
|
419
|
+
Bindings, dispatches and implementations that appeared or vanished since the previous index — the structural change, not the textual one. Warns when a DI binding or a MediatR dispatch no longer resolves, which the compiler will not catch and mocked unit tests will not fail on.
|
|
420
|
+
```bash
|
|
421
|
+
csmesh changes
|
|
422
|
+
csmesh changes --calls --budget 1200
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
#### `csmesh silence <symbol> [<target>]` (alias: `why-not`)
|
|
426
|
+
Why a query came back empty. Exit `1` from any other command means the graph had nothing; it does not say whether the symbol was mistyped, lives in a package, was never bound because the solution was not built, or is reached only through a container scan. Those call for four different next actions.
|
|
427
|
+
```bash
|
|
428
|
+
csmesh silence IPaymentGateway
|
|
429
|
+
csmesh why-not OrderController.Post SqlOrderStore.Save
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
#### `csmesh unresolved`
|
|
433
|
+
Where the indexer failed, grouped by reason. Run this when an answer is thinner than expected.
|
|
434
|
+
```bash
|
|
435
|
+
csmesh unresolved
|
|
436
|
+
csmesh unresolved --kind di
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### `csmesh usage`
|
|
440
|
+
Displays local invocation analytics, token spend, caller attribution, and latency percentiles.
|
|
441
|
+
```bash
|
|
442
|
+
csmesh usage # Summary for last 7 days
|
|
443
|
+
csmesh usage --days 30 # Summary for last 30 days
|
|
444
|
+
csmesh usage --tail 10 # Last 10 raw invocations
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
#### `csmesh doctor`
|
|
448
|
+
Diagnoses index freshness, dirty files, caller attribution, and agent skill configurations.
|
|
449
|
+
```bash
|
|
450
|
+
csmesh doctor
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
#### `csmesh install [OPTIONS]`
|
|
454
|
+
Installs agent skill and rule files and optional MCP server integrations for AI assistants.
|
|
455
|
+
```bash
|
|
456
|
+
csmesh install # Install skill and rule files for current repo
|
|
457
|
+
csmesh install --mcp # Register csmesh as an MCP server
|
|
458
|
+
csmesh install --all # Install skills and MCP server
|
|
459
|
+
csmesh install --global # Install globally across all user agents
|
|
460
|
+
csmesh install -g --agent cursor # Install globally for Cursor only
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
#### `csmesh uninstall [OPTIONS]`
|
|
464
|
+
Safely removes agent skill/rule files, cleans up generated blocks, and unregisters MCP server integrations.
|
|
465
|
+
```bash
|
|
466
|
+
csmesh uninstall # Remove skill and rule files from current repo
|
|
467
|
+
csmesh uninstall --mcp # Unregister MCP server
|
|
468
|
+
csmesh uninstall --all # Remove skills and MCP server
|
|
469
|
+
csmesh uninstall --global # Remove globally across user config
|
|
470
|
+
csmesh uninstall -g --agent cursor # Remove globally for Cursor only
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
#### `csmesh serve`
|
|
474
|
+
Exposes csmesh query tools to AI agents as a Model Context Protocol (MCP) server over stdio.
|
|
475
|
+
```bash
|
|
476
|
+
csmesh serve
|
|
477
|
+
csmesh serve --repo ./src
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## ⚖️ The Recommended Hybrid Workflow: csmesh vs. grep
|
|
483
|
+
|
|
484
|
+
A symbol graph is not a replacement for text search or reading code; it is a replacement for **blindly hunting for code**. The most effective engineers and agents combine both tools:
|
|
485
|
+
|
|
486
|
+
```
|
|
487
|
+
┌─────────────────────────────────────┐
|
|
488
|
+
│ What are you asking? │
|
|
489
|
+
└──────────────────┬──────────────────┘
|
|
490
|
+
│
|
|
491
|
+
┌─────────────────────────┴─────────────────────────┐
|
|
492
|
+
▼ ▼
|
|
493
|
+
┌──────────────────────┐ ┌──────────────────────┐
|
|
494
|
+
│ Structural / Graph │ │ Lexical / Textual │
|
|
495
|
+
├──────────────────────┤ ├──────────────────────┤
|
|
496
|
+
│ • Call hierarchies │ │ • String literals │
|
|
497
|
+
│ • Who calls whom │ │ • Error messages │
|
|
498
|
+
│ • Interface dispatch │ │ • Config keys & YAML │
|
|
499
|
+
│ • Impact analysis │ │ • Docker / scripts │
|
|
500
|
+
│ • Entrypoint routing │ │ • Enum constants │
|
|
501
|
+
└──────────┬───────────┘ └──────────┬───────────┘
|
|
502
|
+
▼ ▼
|
|
503
|
+
csmesh grep / ripgrep
|
|
504
|
+
│ │
|
|
505
|
+
└─────────────────────────┬─────────────────────────┘
|
|
506
|
+
▼
|
|
507
|
+
┌─────────────────────────────────┐
|
|
508
|
+
│ Direct File Inspection │
|
|
509
|
+
│ (Evaluate if/else, error flow) │
|
|
510
|
+
└─────────────────────────────────┘
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
| Task | Primary Tool | Why? |
|
|
514
|
+
|:---|:---|:---|
|
|
515
|
+
| **Impact / Blast Radius** | `csmesh blast-radius` | Zero noise; eliminates candidate fakes and mocks across the solution. |
|
|
516
|
+
| **Interface Implementations** | `csmesh impl` | Resolves runtime DI bindings (`[di:bound]`) instantly. |
|
|
517
|
+
| **Execution Call Traces** | `csmesh trace` | Collapses multi-hop file reads into a single 5-line tree. |
|
|
518
|
+
| **Error Messages & Config Keys** | `grep` / `ripgrep` | Works identically across `.json`, `.yaml`, `.env`, and non-code assets. |
|
|
519
|
+
| **Enum Values & Data Constants** | `grep` / `ripgrep` | Simple primitives have no dispatch graph; text search locates exact tokens. |
|
|
520
|
+
| **Control Flow & Guard Clauses** | Direct File Read | Graphs reveal *who calls whom*; reading code reveals *under what conditions*. |
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## 🎯 Deterministic Exit Codes
|
|
525
|
+
|
|
526
|
+
`csmesh` uses strict, deterministic exit codes so automated agents can branch reliably without fuzzy text parsing:
|
|
527
|
+
|
|
528
|
+
| Code | Status | Meaning | Recommended Agent Action |
|
|
529
|
+
|:---:|:---|:---|:---|
|
|
530
|
+
| `0` | **Success** | Complete answer returned within budget. | Parse output directly. |
|
|
531
|
+
| `1` | **Not Found** | Symbol does not exist in repository. | Check spelling or verify namespace. |
|
|
532
|
+
| `2` | **Over Budget** | Answer exists but exceeds `--budget`. | Re-run with narrower `--depth` or query a specific callee. |
|
|
533
|
+
| `3` | **Ambiguous** | Multiple symbols match query. | Re-run with qualified `Type.Member` instead of bare member name. |
|
|
534
|
+
| `4` | **No Index** | Symbol graph has not been generated. | Execute `csmesh index` and retry. |
|
|
535
|
+
| `64`| **Usage Error** | Invalid flags, syntax, or arguments. | Run `csmesh <cmd> --help`. |
|
|
536
|
+
| `70`| **Internal Error** | Unhandled failure inside csmesh. | Re-run with `--debug` and open an issue. |
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
## 📊 Telemetry & Audit Logging
|
|
541
|
+
|
|
542
|
+
Every invocation records an audit log entry in `.csmesh/usage.jsonl` (local to the repository, never sent to external servers):
|
|
543
|
+
|
|
544
|
+
```json
|
|
545
|
+
{"ts":"2026-09-03T15:15:42Z","caller":"claude-code","caller_via":"env:CLAUDECODE","tty":false,"cmd":"trace","args":"PaymentController.Post --budget 600","exit":0,"ms":84,"budget":600,"out_tokens":125,"nodes":160,"edges":380}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Caller detection automatically attributes queries based on environment variables and process trees (`claude-code`, `cursor`, `windsurf`, `cline`, `antigravity`, `terminal-human`).
|
|
549
|
+
|
|
550
|
+
> To disable telemetry entirely, pass `--no-telemetry` or set `CSMESH_NO_TELEMETRY=1`.
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
## 📄 License
|
|
555
|
+
|
|
556
|
+
This project is licensed under the [MIT License](LICENSE).
|
package/bin/run.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { spawn } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const binName = process.platform === 'win32' ? 'csmesh.exe' : 'csmesh';
|
|
8
|
+
const binPath = path.join(__dirname, binName);
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(binPath)) {
|
|
11
|
+
console.error(`[csmesh] Native executable not found at: ${binPath}`);
|
|
12
|
+
console.error('Try reinstalling the package: npm install -g @nrafinia/csmesh');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const child = spawn(binPath, process.argv.slice(2), {
|
|
17
|
+
stdio: 'inherit',
|
|
18
|
+
windowsHide: true
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
child.on('error', (err) => {
|
|
22
|
+
console.error(`[csmesh] Failed to launch binary: ${err.message}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
child.on('exit', (code, signal) => {
|
|
27
|
+
if (signal) {
|
|
28
|
+
process.kill(process.pid, signal);
|
|
29
|
+
} else {
|
|
30
|
+
process.exit(code !== null ? code : 0);
|
|
31
|
+
}
|
|
32
|
+
});
|
package/package.json
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const https = require('https');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
|
|
6
|
+
const pkg = require('../package.json');
|
|
7
|
+
const platform = process.platform;
|
|
8
|
+
const arch = process.arch;
|
|
9
|
+
|
|
10
|
+
const targets = {
|
|
11
|
+
'win32-x64': { file: 'csmesh-win-x64.zip', bin: 'csmesh.exe' },
|
|
12
|
+
'linux-x64': { file: 'csmesh-linux-x64.tar.gz', bin: 'csmesh' },
|
|
13
|
+
'darwin-arm64': { file: 'csmesh-osx-arm64.tar.gz', bin: 'csmesh' }
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const key = `${platform}-${arch}`;
|
|
17
|
+
const target = targets[key];
|
|
18
|
+
|
|
19
|
+
if (!target) {
|
|
20
|
+
console.error(`[csmesh] Unsupported platform/architecture: ${key}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const binDir = path.join(__dirname, '..', 'bin');
|
|
25
|
+
if (!fs.existsSync(binDir)) {
|
|
26
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// برای رفع تفاوتهای ورژن npm با تگ گیتهاب (مانند 0.1.9-1 یا 0.1.10)
|
|
30
|
+
const cleanVersion = pkg.version.replace(/-.*/, '');
|
|
31
|
+
const releaseTag = cleanVersion;
|
|
32
|
+
|
|
33
|
+
const url = `https://github.com/nRafinia/CsMesh/releases/download/${releaseTag}/${target.file}`;
|
|
34
|
+
const tempArchive = path.join(binDir, target.file);
|
|
35
|
+
|
|
36
|
+
console.log(`[csmesh] Downloading binary from: ${url}`);
|
|
37
|
+
|
|
38
|
+
function download(fileUrl, destPath, callback) {
|
|
39
|
+
https.get(fileUrl, (res) => {
|
|
40
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
41
|
+
return download(res.headers.location, destPath, callback);
|
|
42
|
+
}
|
|
43
|
+
if (res.statusCode !== 200) {
|
|
44
|
+
return callback(new Error(`Server responded with status code ${res.statusCode} for ${fileUrl}`));
|
|
45
|
+
}
|
|
46
|
+
const fileStream = fs.createWriteStream(destPath);
|
|
47
|
+
res.pipe(fileStream);
|
|
48
|
+
fileStream.on('finish', () => {
|
|
49
|
+
fileStream.close(callback);
|
|
50
|
+
});
|
|
51
|
+
}).on('error', callback);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
download(url, tempArchive, (err) => {
|
|
55
|
+
if (err) {
|
|
56
|
+
console.error(`[csmesh] Download failed: ${err.message}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
if (target.file.endsWith('.zip')) {
|
|
62
|
+
if (platform === 'win32') {
|
|
63
|
+
execSync(`powershell -Command "Expand-Archive -Path '${tempArchive}' -DestinationPath '${binDir}' -Force"`);
|
|
64
|
+
} else {
|
|
65
|
+
execSync(`unzip -o "${tempArchive}" -d "${binDir}"`);
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
execSync(`tar -xzf "${tempArchive}" -C "${binDir}"`);
|
|
69
|
+
}
|
|
70
|
+
} catch (extractErr) {
|
|
71
|
+
console.error(`[csmesh] Extraction failed: ${extractErr.message}`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
} finally {
|
|
74
|
+
if (fs.existsSync(tempArchive)) {
|
|
75
|
+
fs.unlinkSync(tempArchive);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const binPath = path.join(binDir, target.bin);
|
|
80
|
+
if (platform !== 'win32' && fs.existsSync(binPath)) {
|
|
81
|
+
fs.chmodSync(binPath, 0o755);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log('[csmesh] Binary successfully installed and configured.');
|
|
85
|
+
});
|