@toolbaux/guardian 0.1.15 → 0.1.17
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 +9 -6
- package/dist/cli.js +2 -0
- package/dist/commands/init.js +32 -30
- package/dist/commands/mcp-serve.js +9 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@toolbaux/guardian)
|
|
4
4
|
[](./LICENSE)
|
|
5
5
|
|
|
6
|
+
> **Beta Release** — Guardian is under active development. Core features (extract, context, drift, MCP server) are stable and used daily across multiple projects, but you may encounter minor issues with edge cases in framework detection or config handling. Bug reports and feedback welcome via [GitHub Issues](https://github.com/idocoding/guardian/issues).
|
|
7
|
+
|
|
6
8
|
Architectural intelligence for codebases. One command turns your repo into compact, machine-readable context that AI coding tools can reason about without hallucinating.
|
|
7
9
|
|
|
8
10
|
```bash
|
|
@@ -53,7 +55,7 @@ After `guardian init`, your project gets:
|
|
|
53
55
|
- `.specs/` directory with architecture snapshots
|
|
54
56
|
- `CLAUDE.md` with auto-injected context (refreshed on every save and commit)
|
|
55
57
|
- Pre-commit hook that keeps context fresh automatically
|
|
56
|
-
- `guardian.config.json`
|
|
58
|
+
- `guardian.config.json` for project settings (roots auto-detected at runtime)
|
|
57
59
|
|
|
58
60
|
## Claude Code / Cursor Integration
|
|
59
61
|
|
|
@@ -96,9 +98,8 @@ Guardian includes an MCP server that Claude Code and Cursor connect to automatic
|
|
|
96
98
|
|
|
97
99
|
All responses are compact JSON — no pretty-printing, no verbose keys. Repeated calls are cached (30s TTL). Usage metrics tracked per session.
|
|
98
100
|
|
|
99
|
-
**
|
|
101
|
+
**Setup:** `guardian init` and the VSCode extension auto-create `.mcp.json` at your project root. If you need to create it manually:
|
|
100
102
|
|
|
101
|
-
Create `.mcp.json` at your project root:
|
|
102
103
|
```json
|
|
103
104
|
{
|
|
104
105
|
"mcpServers": {
|
|
@@ -110,6 +111,8 @@ Create `.mcp.json` at your project root:
|
|
|
110
111
|
}
|
|
111
112
|
```
|
|
112
113
|
|
|
114
|
+
> **Note:** After `.mcp.json` is created or modified, you must **restart your Claude Code / Cursor session** (or reload the VSCode window) for the MCP server to connect. MCP config is only read at session start.
|
|
115
|
+
|
|
113
116
|
## VSCode Extension
|
|
114
117
|
|
|
115
118
|
Install from [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=toolbaux.toolbaux-guardian):
|
|
@@ -276,14 +279,14 @@ guardian feature-context --spec feature-specs/billing.yaml
|
|
|
276
279
|
<details>
|
|
277
280
|
<summary><strong>Configuration</strong></summary>
|
|
278
281
|
|
|
279
|
-
`guardian.config.json` at project root (auto-created by `guardian init`):
|
|
282
|
+
`guardian.config.json` at project root (auto-created by `guardian init`). Backend and frontend roots are auto-detected at runtime — only set them if auto-detection picks the wrong directory:
|
|
280
283
|
|
|
281
284
|
```json
|
|
282
285
|
{
|
|
283
286
|
"project": {
|
|
287
|
+
"description": "Short product description for generated docs",
|
|
284
288
|
"backendRoot": "./backend",
|
|
285
|
-
"frontendRoot": "./frontend"
|
|
286
|
-
"description": "Short product description for generated docs"
|
|
289
|
+
"frontendRoot": "./frontend"
|
|
287
290
|
},
|
|
288
291
|
"frontend": {
|
|
289
292
|
"routeDirs": ["app"],
|
package/dist/cli.js
CHANGED
|
@@ -343,9 +343,11 @@ program
|
|
|
343
343
|
.command("mcp-serve")
|
|
344
344
|
.description("Start Guardian MCP server for Claude Code / Cursor integration")
|
|
345
345
|
.option("--specs <dir>", "Specs directory", ".specs")
|
|
346
|
+
.option("--quiet", "Suppress stderr output (for clients that merge streams)", false)
|
|
346
347
|
.action(async (options) => {
|
|
347
348
|
await runMcpServe({
|
|
348
349
|
specs: options.specs,
|
|
350
|
+
quiet: options.quiet,
|
|
349
351
|
});
|
|
350
352
|
});
|
|
351
353
|
program.parseAsync().catch((error) => {
|
package/dist/commands/init.js
CHANGED
|
@@ -15,10 +15,6 @@ import fs from "node:fs/promises";
|
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import { DEFAULT_SPECS_DIR } from "../config.js";
|
|
17
17
|
const DEFAULT_CONFIG = {
|
|
18
|
-
project: {
|
|
19
|
-
backendRoot: "./backend",
|
|
20
|
-
frontendRoot: "./frontend",
|
|
21
|
-
},
|
|
22
18
|
docs: {
|
|
23
19
|
mode: "full",
|
|
24
20
|
},
|
|
@@ -78,32 +74,8 @@ export async function runInit(options) {
|
|
|
78
74
|
// 2. Create guardian.config.json if missing
|
|
79
75
|
const configPath = path.join(root, "guardian.config.json");
|
|
80
76
|
if (!(await fileExists(configPath))) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (options.backendRoot) {
|
|
84
|
-
config.project.backendRoot = options.backendRoot;
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
for (const candidate of ["./backend", "./server", "./api", "./src"]) {
|
|
88
|
-
if (await dirExists(path.join(root, candidate))) {
|
|
89
|
-
config.project.backendRoot = candidate;
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
if (options.frontendRoot) {
|
|
95
|
-
config.project.frontendRoot = options.frontendRoot;
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
for (const candidate of ["./frontend", "./client", "./web", "./app"]) {
|
|
99
|
-
if (await dirExists(path.join(root, candidate))) {
|
|
100
|
-
config.project.frontendRoot = candidate;
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
106
|
-
console.log(` ✓ Created guardian.config.json (backend: ${config.project.backendRoot}, frontend: ${config.project.frontendRoot})`);
|
|
77
|
+
await fs.writeFile(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n", "utf8");
|
|
78
|
+
console.log(" ✓ Created guardian.config.json");
|
|
107
79
|
}
|
|
108
80
|
else {
|
|
109
81
|
console.log(" · guardian.config.json already exists");
|
|
@@ -232,6 +204,36 @@ async function dirExists(p) {
|
|
|
232
204
|
}
|
|
233
205
|
}
|
|
234
206
|
async function setupClaudeCodeHooks(root, specsDir) {
|
|
207
|
+
// Create .mcp.json at project root (MCP standard — works with Claude Code, Cursor, etc.)
|
|
208
|
+
const mcpJsonPath = path.join(root, ".mcp.json");
|
|
209
|
+
try {
|
|
210
|
+
let mcpConfig = {};
|
|
211
|
+
if (await fileExists(mcpJsonPath)) {
|
|
212
|
+
try {
|
|
213
|
+
mcpConfig = JSON.parse(await fs.readFile(mcpJsonPath, "utf8"));
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Corrupted — overwrite
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!mcpConfig.mcpServers)
|
|
220
|
+
mcpConfig.mcpServers = {};
|
|
221
|
+
const servers = mcpConfig.mcpServers;
|
|
222
|
+
if (!servers.guardian) {
|
|
223
|
+
servers.guardian = {
|
|
224
|
+
command: "guardian",
|
|
225
|
+
args: ["mcp-serve", "--specs", specsDir],
|
|
226
|
+
};
|
|
227
|
+
await fs.writeFile(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + "\n", "utf8");
|
|
228
|
+
console.log(" ✓ Created .mcp.json (MCP server config)");
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
console.log(" · .mcp.json already has guardian MCP config");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
console.warn(` ⚠ Could not create .mcp.json: ${err.message}`);
|
|
236
|
+
}
|
|
235
237
|
const claudeDir = path.join(root, ".claude");
|
|
236
238
|
const hooksDir = path.join(claudeDir, "hooks");
|
|
237
239
|
const settingsPath = path.join(claudeDir, "settings.json");
|
|
@@ -456,12 +456,15 @@ async function handleRequest(req) {
|
|
|
456
456
|
// ── Entry point ──
|
|
457
457
|
export async function runMcpServe(options) {
|
|
458
458
|
const specsDir = path.resolve(options.specs);
|
|
459
|
+
const quiet = options.quiet ?? false;
|
|
459
460
|
intelPath = path.join(specsDir, "machine", "codebase-intelligence.json");
|
|
460
461
|
// Pre-load intelligence
|
|
461
462
|
await loadIntel();
|
|
462
463
|
// Log to stderr (stdout is for MCP protocol)
|
|
463
|
-
|
|
464
|
-
|
|
464
|
+
if (!quiet) {
|
|
465
|
+
process.stderr.write(`Guardian MCP server started. Intelligence: ${intelPath}\n`);
|
|
466
|
+
process.stderr.write(`Tools: ${TOOLS.map((t) => t.name).join(", ")}\n`);
|
|
467
|
+
}
|
|
465
468
|
// Read JSON-RPC messages from stdin, line by line
|
|
466
469
|
const rl = readline.createInterface({ input: process.stdin });
|
|
467
470
|
rl.on("line", async (line) => {
|
|
@@ -484,10 +487,12 @@ export async function runMcpServe(options) {
|
|
|
484
487
|
session_end: new Date().toISOString(),
|
|
485
488
|
});
|
|
486
489
|
await fs.appendFile(metricsPath, entry + "\n", "utf8");
|
|
487
|
-
|
|
490
|
+
if (!quiet)
|
|
491
|
+
process.stderr.write(`Guardian metrics saved to ${metricsPath}\n`);
|
|
488
492
|
}
|
|
489
493
|
catch { }
|
|
490
|
-
|
|
494
|
+
if (!quiet)
|
|
495
|
+
process.stderr.write("Guardian MCP server stopped.\n");
|
|
491
496
|
process.exit(0);
|
|
492
497
|
});
|
|
493
498
|
}
|
package/package.json
CHANGED