speclock 5.4.1 → 5.5.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/README.md CHANGED
@@ -8,7 +8,13 @@
8
8
  <a href="https://www.npmjs.com/package/speclock"><img src="https://img.shields.io/npm/v/speclock.svg?style=flat-square&color=4F46E5" alt="npm version" /></a>
9
9
  <a href="https://www.npmjs.com/package/speclock"><img src="https://img.shields.io/npm/dm/speclock.svg?style=flat-square&color=22C55E" alt="npm downloads" /></a>
10
10
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT License" /></a>
11
- <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-42_tools-green.svg?style=flat-square" alt="MCP 49 tools" /></a>
11
+ <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-51_tools-green.svg?style=flat-square" alt="MCP 51 tools" /></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <img src="https://img.shields.io/badge/drift_score-12%2F100-brightgreen.svg?style=flat-square" alt="Drift Score" />
16
+ <img src="https://img.shields.io/badge/lock_coverage-83%25-brightgreen.svg?style=flat-square" alt="Lock Coverage" />
17
+ <img src="https://img.shields.io/badge/lock_strength-85%2F100-brightgreen.svg?style=flat-square" alt="Lock Strength" />
12
18
  </p>
13
19
 
14
20
  <p align="center">
@@ -19,6 +25,10 @@
19
25
 
20
26
  ---
21
27
 
28
+ > **New in v5.4:** `speclock drift` — the only tool that measures how much your AI has drifted from your architecture. `speclock coverage` — find what's unprotected. `speclock strengthen` — grade your locks. Three numbers that tell your project's whole story.
29
+
30
+ ---
31
+
22
32
  ```
23
33
  You: "Never touch the auth system"
24
34
  AI: 🔒 Locked.
@@ -32,8 +42,8 @@ AI: ⚠️ BLOCKED — violates lock "Never touch the auth system"
32
42
  Should I find another approach?
33
43
  ```
34
44
 
35
- **100/100 on Claude's independent test suite. 929 tests across 18 suites. 0 false positives. 15.7ms per check.**
36
- **Gemini Flash hybrid, Spec Compiler, Code Graph, Typed Constraints, Python SDK, ROS2 integration.**
45
+ **100/100 on Claude's independent test suite. 976 tests across 19 suites. 0 false positives. 15.7ms per check.**
46
+ **Zero-config Guardian Mode, Universal Rules Sync, AI Patch Firewall, Drift Score, Spec Compiler, Code Graph.**
37
47
 
38
48
  ---
39
49
 
@@ -45,6 +55,14 @@ npx speclock setup --goal "Build my app"
45
55
 
46
56
  That's it. One command. Works everywhere — Bolt.new, Claude Code, Cursor, Lovable, Windsurf, Cline, Aider.
47
57
 
58
+ ### Already have `.cursorrules`, `CLAUDE.md`, or `AGENTS.md`?
59
+
60
+ ```bash
61
+ npx speclock protect
62
+ ```
63
+
64
+ Zero flags. Reads your existing rule files, extracts enforceable constraints, installs a pre-commit hook, and syncs rules to every AI tool. **Your rules are now enforced, not just suggested.**
65
+
48
66
  ## The Problem
49
67
 
50
68
  AI coding tools have memory now. Claude Code has `CLAUDE.md`. Cursor has `.cursorrules`. Mem0 exists.
@@ -581,7 +599,7 @@ POST /api/v2/graph/build
581
599
 
582
600
  ---
583
601
 
584
- ## 49 MCP Tools
602
+ ## 51 MCP Tools
585
603
 
586
604
  <details>
587
605
  <summary><b>Memory</b> — goal, locks, decisions, notes, deploy facts</summary>
@@ -797,7 +815,7 @@ The AI opens the file and sees:
797
815
  │ AI Tool (Claude Code, Cursor, Bolt.new...) │
798
816
  └────────────┬──────────────────┬──────────────────┘
799
817
  │ │
800
- MCP Protocol (49 tools) npm File-Based
818
+ MCP Protocol (51 tools) npm File-Based
801
819
  │ (SPECLOCK.md + CLI)
802
820
  │ │
803
821
  ┌────────────▼──────────────────▼──────────────────┐
@@ -865,9 +883,10 @@ The AI opens the file and sees:
865
883
  | Question Framing | 9 | 100% | "What if we..." and "How hard would it be..." |
866
884
  | REST API v2 | 9 | 100% | Typed constraint endpoints, SSE |
867
885
  | PII/Export Detection | 8 | 100% | SSN, email export, data access violations |
868
- | **Total** | **929** | **100%** | **18 suites, 15+ domains** |
886
+ | Guardian (Protect) | 47 | 100% | Zero-config rule file extraction |
887
+ | **Total** | **976** | **100%** | **19 suites, 15+ domains** |
869
888
 
870
- **External validation:** Claude's independent 7-suite adversarial test battery — **100/100 (100%)** on v5.4.0. Zero false positives. Zero missed violations. 15.7ms per check.
889
+ **External validation:** Claude's independent 7-suite adversarial test battery — **100/100 (100%)** on v5.5.0. Zero false positives. Zero missed violations. 15.7ms per check.
871
890
 
872
891
  Tested across: fintech, e-commerce, IoT, healthcare, SaaS, gaming, biotech, aerospace, payments, payroll, robotics, autonomous systems, telecom, insurance, government. All 11 Indian payment gateways detected. Zero false positives on UI/cosmetic actions.
873
892
 
@@ -905,11 +924,11 @@ Issues and PRs welcome on [GitHub](https://github.com/sgroy10/speclock).
905
924
 
906
925
  **SpecLock** is created and maintained by **[Sandeep Roy](https://github.com/sgroy10)**.
907
926
 
908
- Sandeep Roy is the sole developer of SpecLock — the AI Constraint Engine that enforces project rules across AI coding sessions. All 49 MCP tools, the semantic conflict detection engine, enterprise security features (SOC 2, HIPAA, RBAC, encryption), and the pre-publish test gate were designed and built by Sandeep Roy.
927
+ Sandeep Roy is the sole developer of SpecLock — the AI Constraint Engine that enforces project rules across AI coding sessions. All 51 MCP tools, the semantic conflict detection engine, enterprise security features (SOC 2, HIPAA, RBAC, encryption), and the pre-publish test gate were designed and built by Sandeep Roy.
909
928
 
910
929
  - GitHub: [@sgroy10](https://github.com/sgroy10)
911
930
  - npm: [speclock](https://www.npmjs.com/package/speclock)
912
931
 
913
932
  ---
914
933
 
915
- <p align="center"><i>SpecLock v5.4.0 — Developed by Sandeep Roy 929 tests, 100% pass rate, 49 MCP tools, Universal Rules Sync, Incident Replay, AI Patch Firewall, Spec Compiler, Code Graph, Typed Constraints, Python SDK, ROS2, REST API v2. Because remembering isn't enough.</i></p>
934
+ <p align="center"><i>SpecLock v5.5.0 — Your AI has rules. SpecLock makes them unbreakable. 976 tests, 100% pass rate, 51 MCP tools, Zero-config Guardian Mode, Universal Rules Sync, AI Patch Firewall, Drift Score. Developed by Sandeep Roy.</i></p>
package/bin/speclock.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  // SpecLock CLI — AI Constraint Engine
3
3
  // Developed by Sandeep Roy (https://github.com/sgroy10)
4
4
  import "../src/cli/index.js";
package/package.json CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  "name": "speclock",
4
4
 
5
- "version": "5.4.1",
5
+ "version": "5.5.0",
6
6
 
7
- "description": "AI Constraint Engine by Sandeep Roy Universal Rules Sync (one command syncs constraints to Cursor, Claude Code, Copilot, Windsurf, Gemini, Aider, AGENTS.md). AI Patch Firewall, diff-native review, Patch Gateway (ALLOW/WARN/BLOCK), Spec Compiler (NL→constraints), Code Graph (blast radius), Typed constraints, REST API v2, Python SDK, ROS2 integration. 49 MCP tools, Gemini LLM hybrid, HMAC audit chain, RBAC, encryption, SOC 2/HIPAA compliance. Developed by Sandeep Roy.",
7
+ "description": "Stop AI from breaking code you told it not to touch. Enforces .cursorrules, CLAUDE.md, and AGENTS.md not just suggests. Zero-config: npx speclock protect reads your existing AI rule files, extracts constraints, installs pre-commit hooks, and makes your rules unbreakable. 51 MCP tools, Universal Rules Sync, AI Patch Firewall, Spec Compiler, Code Graph, Typed Constraints, Drift Score, HMAC audit chain, SOC 2/HIPAA compliance. Developed by Sandeep Roy.",
8
8
 
9
9
  "type": "module",
10
10
 
package/src/cli/index.js CHANGED
@@ -67,6 +67,7 @@ import { getReplay, listSessions, formatReplay } from "../core/replay.js";
67
67
  import { computeDriftScore, formatDriftScore } from "../core/drift-score.js";
68
68
  import { computeCoverage, formatCoverage } from "../core/coverage.js";
69
69
  import { analyzeLockStrength, formatStrength } from "../core/strengthen.js";
70
+ import { protect, formatProtectReport } from "../core/guardian.js";
70
71
 
71
72
  // --- Argument parsing ---
72
73
 
@@ -122,7 +123,7 @@ function refreshContext(root) {
122
123
 
123
124
  function printHelp() {
124
125
  console.log(`
125
- SpecLock v5.4.1 — AI Constraint Engine (Universal Rules Sync + Spec Compiler + Code Graph + Typed Constraints + Python SDK + ROS2 + REST API v2 + Gemini LLM + Policy-as-Code + Auth + RBAC + Encryption)
126
+ SpecLock v5.5.0Your AI has rules. SpecLock makes them unbreakable.
126
127
  Developed by Sandeep Roy (github.com/sgroy10)
127
128
 
128
129
  Usage: speclock <command> [options]
@@ -133,6 +134,7 @@ Commands:
133
134
  goal <text> Set or update the project goal
134
135
  lock <text> [--tags a,b] Add a non-negotiable constraint
135
136
  lock remove <id> Remove a lock by ID
137
+ protect Zero-config: read rule files, extract locks, enforce
136
138
  guard <file> [--lock "text"] Inject lock warning into a file
137
139
  unguard <file> Remove lock warning from a file
138
140
  decide <text> [--tags a,b] Record a decision
@@ -545,6 +547,21 @@ Tip: Run "speclock sync --all" to push constraints to Cursor, Claude, Copilot, W
545
547
  return;
546
548
  }
547
549
 
550
+ // --- PROTECT (zero-config guardian mode) ---
551
+ if (cmd === "protect") {
552
+ const flags = parseFlags(args);
553
+ const opts = {
554
+ skipHook: flags["no-hook"] === true,
555
+ skipSync: flags["no-sync"] === true,
556
+ };
557
+ const report = protect(root, opts);
558
+ console.log(formatProtectReport(report));
559
+ if (report.errors.length > 0 && report.discovered.length === 0) {
560
+ process.exit(1);
561
+ }
562
+ return;
563
+ }
564
+
548
565
  // --- FACTS ---
549
566
  if (cmd === "facts") {
550
567
  const sub = args.shift();
@@ -9,7 +9,7 @@
9
9
  import { readBrain, readEvents } from "./storage.js";
10
10
  import { verifyAuditChain } from "./audit.js";
11
11
 
12
- const VERSION = "5.4.1";
12
+ const VERSION = "5.5.0";
13
13
 
14
14
  // PHI-related keywords for HIPAA filtering
15
15
  const PHI_KEYWORDS = [
@@ -73,6 +73,14 @@ export {
73
73
  semanticAudit,
74
74
  } from "./pre-commit-semantic.js";
75
75
 
76
+ // --- Guardian (v5.5) ---
77
+ export {
78
+ discoverRuleFiles,
79
+ extractConstraints,
80
+ protect,
81
+ formatProtectReport,
82
+ } from "./guardian.js";
83
+
76
84
  // --- File Watcher ---
77
85
  // watchRepo stays here because it uses multiple modules
78
86
 
@@ -0,0 +1,348 @@
1
+ // ===================================================================
2
+ // SpecLock Guardian — Zero-Config Protection from AI Rule Files
3
+ // Reads existing .cursorrules, CLAUDE.md, AGENTS.md, copilot-instructions.md
4
+ // and auto-extracts enforceable constraints. One command. No flags.
5
+ //
6
+ // "Your AI has rules. SpecLock makes them unbreakable."
7
+ //
8
+ // Developed by Sandeep Roy (https://github.com/sgroy10)
9
+ // ===================================================================
10
+
11
+ import fs from "fs";
12
+ import path from "path";
13
+ import { ensureInit, addLock, addDecision } from "./memory.js";
14
+ import { readBrain } from "./storage.js";
15
+ import { installHook, isHookInstalled } from "./hooks.js";
16
+ import { syncRules } from "./rules-sync.js";
17
+ import { generateContext } from "./context.js";
18
+
19
+ // --- Rule file discovery ---
20
+
21
+ const RULE_FILES = [
22
+ { file: ".cursorrules", tool: "Cursor" },
23
+ { file: ".cursor/rules/rules.mdc", tool: "Cursor (MDC)" },
24
+ { file: "CLAUDE.md", tool: "Claude Code" },
25
+ { file: "AGENTS.md", tool: "AGENTS.md" },
26
+ { file: ".github/copilot-instructions.md", tool: "GitHub Copilot" },
27
+ { file: ".windsurfrules", tool: "Windsurf" },
28
+ { file: ".windsurf/rules/rules.md", tool: "Windsurf (dir)" },
29
+ { file: "GEMINI.md", tool: "Gemini" },
30
+ { file: ".aider.conf.yml", tool: "Aider" },
31
+ { file: "COPILOT.md", tool: "Copilot (alt)" },
32
+ { file: ".github/instructions.md", tool: "GitHub (alt)" },
33
+ ];
34
+
35
+ /**
36
+ * Discover all AI rule files in the project.
37
+ */
38
+ export function discoverRuleFiles(root) {
39
+ const found = [];
40
+ for (const entry of RULE_FILES) {
41
+ const fullPath = path.join(root, entry.file);
42
+ if (fs.existsSync(fullPath)) {
43
+ const content = fs.readFileSync(fullPath, "utf-8").trim();
44
+ if (content.length > 0) {
45
+ found.push({
46
+ file: entry.file,
47
+ tool: entry.tool,
48
+ path: fullPath,
49
+ content,
50
+ size: content.length,
51
+ lines: content.split("\n").length,
52
+ });
53
+ }
54
+ }
55
+ }
56
+ return found;
57
+ }
58
+
59
+ // --- Heuristic constraint extraction (no API key needed) ---
60
+
61
+ // Patterns that signal a constraint/rule
62
+ const CONSTRAINT_PATTERNS = [
63
+ // Strong imperative (NEVER, ALWAYS, MUST, DO NOT)
64
+ /^[-*•]\s*(NEVER|ALWAYS|MUST|DO NOT|DON'T|DONT|SHALL NOT|REQUIRED|MANDATORY|CRITICAL|IMPORTANT)\b/i,
65
+ /^(NEVER|ALWAYS|MUST|DO NOT|DON'T|DONT|SHALL NOT)\b/i,
66
+ // "Do not..." / "Don't..." at line start
67
+ /^[-*•]\s*(Do not|Don't|Dont|Never|Always|Must)\b/,
68
+ /^(Do not|Don't|Dont)\b/,
69
+ // Emphasis markers suggesting importance
70
+ /^\*\*(NEVER|ALWAYS|MUST|DO NOT|DON'T|IMPORTANT|CRITICAL|REQUIRED)\*\*/i,
71
+ // "X is required" / "X is mandatory" / "X is non-negotiable"
72
+ /\b(is required|is mandatory|is non-negotiable|is critical|is forbidden|is prohibited)\b/i,
73
+ // "Keep X" / "Preserve X" / "Protect X"
74
+ /^[-*•]\s*(Keep|Preserve|Protect|Maintain|Ensure|Enforce)\b/,
75
+ // Negative imperatives
76
+ /^[-*•]\s*(Avoid|Prevent|Prohibit|Forbid|Restrict|Disallow)\b/i,
77
+ // "should never" / "must never" / "must always"
78
+ /\b(should never|must never|must always|should always|must not|should not|cannot|can not)\b/i,
79
+ ];
80
+
81
+ // Patterns that signal a decision/choice
82
+ const DECISION_PATTERNS = [
83
+ /^[-*•]\s*(Use|Using|Tech stack|Stack|Framework|We use|Built with|Powered by)\b/i,
84
+ /\b(tech stack|architecture|we chose|we decided|we use|built with)\b/i,
85
+ ];
86
+
87
+ // Lines to skip (headers, empty, comments, boilerplate)
88
+ const SKIP_PATTERNS = [
89
+ /^#+\s/, // Markdown headers
90
+ /^---+$/, // Horizontal rules
91
+ /^\s*$/, // Empty lines
92
+ /^```/, // Code fences
93
+ /^<!--/, // HTML comments
94
+ /^>\s/, // Blockquotes (context, not rules)
95
+ /^Auto-synced by SpecLock/, // Our own output
96
+ /^Powered by \[SpecLock\]/, // Our own footer
97
+ /^#\s*SpecLock/, // SpecLock headers
98
+ ];
99
+
100
+ /**
101
+ * Extract constraints from raw text using heuristic pattern matching.
102
+ * No API key required — works offline, instantly.
103
+ */
104
+ export function extractConstraints(content, sourceFile) {
105
+ const lines = content.split("\n");
106
+ const locks = [];
107
+ const decisions = [];
108
+ const seen = new Set();
109
+
110
+ for (let i = 0; i < lines.length; i++) {
111
+ const raw = lines[i];
112
+ const trimmed = raw.trim();
113
+
114
+ // Skip non-content lines
115
+ if (SKIP_PATTERNS.some((p) => p.test(trimmed))) continue;
116
+
117
+ // Clean up: remove leading bullet/dash, markdown bold
118
+ const cleaned = trimmed
119
+ .replace(/^[-*•]\s*/, "")
120
+ .replace(/\*\*/g, "")
121
+ .trim();
122
+
123
+ if (cleaned.length < 10 || cleaned.length > 300) continue;
124
+
125
+ // Deduplicate
126
+ const key = cleaned.toLowerCase().replace(/\s+/g, " ");
127
+ if (seen.has(key)) continue;
128
+
129
+ // Check for constraint patterns
130
+ if (CONSTRAINT_PATTERNS.some((p) => p.test(trimmed) || p.test(cleaned))) {
131
+ seen.add(key);
132
+ locks.push({
133
+ text: cleaned,
134
+ tags: [sourceFile.replace(/[/.]/g, "_").replace(/^_+|_+$/g, "")],
135
+ source: "guardian",
136
+ line: i + 1,
137
+ });
138
+ continue;
139
+ }
140
+
141
+ // Check for decision patterns
142
+ if (DECISION_PATTERNS.some((p) => p.test(trimmed) || p.test(cleaned))) {
143
+ seen.add(key);
144
+ decisions.push({
145
+ text: cleaned,
146
+ tags: [sourceFile.replace(/[/.]/g, "_").replace(/^_+|_+$/g, "")],
147
+ line: i + 1,
148
+ });
149
+ }
150
+ }
151
+
152
+ return { locks, decisions };
153
+ }
154
+
155
+ /**
156
+ * Run the full Guardian protect flow:
157
+ * 1. Init SpecLock if needed
158
+ * 2. Discover rule files
159
+ * 3. Extract constraints from each
160
+ * 4. Add as locks (skip duplicates with existing)
161
+ * 5. Install pre-commit hook
162
+ * 6. Sync rules back to all formats
163
+ * 7. Generate context
164
+ *
165
+ * Returns a report object.
166
+ */
167
+ export function protect(root, options = {}) {
168
+ const report = {
169
+ discovered: [],
170
+ extracted: { locks: 0, decisions: 0 },
171
+ added: { locks: 0, decisions: 0, skipped: 0 },
172
+ hookInstalled: false,
173
+ hookStatus: "",
174
+ synced: [],
175
+ errors: [],
176
+ };
177
+
178
+ // 1. Init
179
+ const brain = ensureInit(root);
180
+
181
+ // 2. Discover
182
+ const ruleFiles = discoverRuleFiles(root);
183
+ report.discovered = ruleFiles.map((f) => ({
184
+ file: f.file,
185
+ tool: f.tool,
186
+ lines: f.lines,
187
+ size: f.size,
188
+ }));
189
+
190
+ if (ruleFiles.length === 0) {
191
+ report.errors.push(
192
+ "No AI rule files found (.cursorrules, CLAUDE.md, AGENTS.md, etc). " +
193
+ "Create one first, or use 'speclock setup' to start from scratch."
194
+ );
195
+ return report;
196
+ }
197
+
198
+ // 3. Extract constraints from each file
199
+ const allLocks = [];
200
+ const allDecisions = [];
201
+
202
+ for (const rf of ruleFiles) {
203
+ const result = extractConstraints(rf.content, rf.file);
204
+ allLocks.push(...result.locks);
205
+ allDecisions.push(...result.decisions);
206
+ }
207
+
208
+ report.extracted.locks = allLocks.length;
209
+ report.extracted.decisions = allDecisions.length;
210
+
211
+ // 4. Add locks (skip duplicates against existing brain locks)
212
+ const existingTexts = new Set(
213
+ (brain.specLock?.items || [])
214
+ .filter((l) => l.active !== false)
215
+ .map((l) => l.text.toLowerCase().replace(/\s+/g, " "))
216
+ );
217
+
218
+ for (const lock of allLocks) {
219
+ const normalized = lock.text.toLowerCase().replace(/\s+/g, " ");
220
+ if (existingTexts.has(normalized)) {
221
+ report.added.skipped++;
222
+ continue;
223
+ }
224
+ existingTexts.add(normalized);
225
+ addLock(root, lock.text, lock.tags, lock.source || "guardian");
226
+ report.added.locks++;
227
+ }
228
+
229
+ for (const dec of allDecisions) {
230
+ const normalized = dec.text.toLowerCase().replace(/\s+/g, " ");
231
+ if (existingTexts.has(normalized)) {
232
+ report.added.skipped++;
233
+ continue;
234
+ }
235
+ existingTexts.add(normalized);
236
+ addDecision(root, dec.text, dec.tags, "guardian");
237
+ report.added.decisions++;
238
+ }
239
+
240
+ // 5. Install pre-commit hook
241
+ if (!options.skipHook) {
242
+ if (isHookInstalled(root)) {
243
+ report.hookInstalled = true;
244
+ report.hookStatus = "already installed";
245
+ } else {
246
+ const hookResult = installHook(root);
247
+ report.hookInstalled = hookResult.success;
248
+ report.hookStatus = hookResult.success
249
+ ? "installed"
250
+ : hookResult.error || "failed";
251
+ }
252
+ } else {
253
+ report.hookStatus = "skipped (--no-hook)";
254
+ }
255
+
256
+ // 6. Sync rules to formats that WEREN'T source files (don't overwrite user's originals)
257
+ if (!options.skipSync) {
258
+ const sourceFiles = new Set(ruleFiles.map((f) => f.file));
259
+ try {
260
+ const syncResult = syncRules(root, { format: "all", excludeFiles: sourceFiles });
261
+ report.synced = (syncResult.synced || []).map((s) => s.file || s);
262
+ } catch (e) {
263
+ report.errors.push(`Sync failed: ${e.message}`);
264
+ }
265
+ }
266
+
267
+ // 7. Generate context
268
+ try {
269
+ generateContext(root);
270
+ } catch (_) {
271
+ // Non-critical
272
+ }
273
+
274
+ return report;
275
+ }
276
+
277
+ /**
278
+ * Format protect report for CLI output.
279
+ */
280
+ export function formatProtectReport(report) {
281
+ const lines = [];
282
+
283
+ lines.push("");
284
+ lines.push(" SpecLock Protect — Guardian Mode");
285
+ lines.push(" " + "=".repeat(50));
286
+ lines.push("");
287
+
288
+ // Discovered files
289
+ if (report.discovered.length > 0) {
290
+ lines.push(" Rule files found:");
291
+ for (const f of report.discovered) {
292
+ lines.push(` [+] ${f.file} (${f.tool}, ${f.lines} lines)`);
293
+ }
294
+ } else {
295
+ lines.push(" [!] No rule files found.");
296
+ }
297
+ lines.push("");
298
+
299
+ // Extracted
300
+ lines.push(` Extracted: ${report.extracted.locks} constraints, ${report.extracted.decisions} decisions`);
301
+
302
+ // Added
303
+ if (report.added.locks > 0 || report.added.decisions > 0) {
304
+ lines.push(` Added: ${report.added.locks} new locks, ${report.added.decisions} new decisions`);
305
+ }
306
+ if (report.added.skipped > 0) {
307
+ lines.push(` Skipped: ${report.added.skipped} (already existed)`);
308
+ }
309
+ lines.push("");
310
+
311
+ // Hook
312
+ if (report.hookStatus === "installed") {
313
+ lines.push(" Pre-commit hook: INSTALLED");
314
+ lines.push(" Every commit will now be checked against your constraints.");
315
+ } else if (report.hookStatus === "already installed") {
316
+ lines.push(" Pre-commit hook: already active");
317
+ } else {
318
+ lines.push(` Pre-commit hook: ${report.hookStatus}`);
319
+ }
320
+ lines.push("");
321
+
322
+ // Sync
323
+ if (report.synced.length > 0) {
324
+ lines.push(" Rules synced to:");
325
+ for (const s of report.synced) {
326
+ lines.push(` [+] ${s}`);
327
+ }
328
+ lines.push("");
329
+ }
330
+
331
+ // Errors
332
+ if (report.errors.length > 0) {
333
+ for (const e of report.errors) {
334
+ lines.push(` [!] ${e}`);
335
+ }
336
+ lines.push("");
337
+ }
338
+
339
+ // Final message
340
+ const total = report.added.locks + report.added.skipped;
341
+ if (total > 0) {
342
+ lines.push(" Your rules are now ENFORCED, not just suggested.");
343
+ lines.push(" AI agents that violate constraints will be blocked.");
344
+ }
345
+ lines.push("");
346
+
347
+ return lines.join("\n");
348
+ }
@@ -451,7 +451,11 @@ export function syncRules(root, options = {}) {
451
451
  const synced = [];
452
452
  const errors = [];
453
453
 
454
+ // Skip formats whose output files are in the exclude list (used by guardian to avoid overwriting source files)
455
+ const excludeFiles = options.excludeFiles instanceof Set ? options.excludeFiles : new Set();
456
+
454
457
  for (const [key, fmt] of Object.entries(formats)) {
458
+ if (excludeFiles.has(fmt.file)) continue;
455
459
  try {
456
460
  const content = fmt.generate(brain);
457
461
  const filePath = path.join(root, fmt.file);
@@ -257,7 +257,7 @@ export async function flushToRemote(root) {
257
257
  // Build anonymized payload
258
258
  const payload = {
259
259
  instanceId: summary.instanceId,
260
- version: "4.5.7",
260
+ version: "5.5.0",
261
261
  totalCalls: summary.totalCalls,
262
262
  avgResponseMs: summary.avgResponseMs,
263
263
  conflicts: summary.conflicts,
@@ -89,7 +89,7 @@
89
89
  <div class="header">
90
90
  <div>
91
91
  <h1><span>SpecLock</span> Dashboard</h1>
92
- <div class="meta">v5.4.1 &mdash; AI Constraint Engine</div>
92
+ <div class="meta">v5.5.0 &mdash; Your AI has rules. SpecLock makes them unbreakable.</div>
93
93
  </div>
94
94
  <div style="display:flex;align-items:center;gap:12px;">
95
95
  <span id="health-badge" class="status-badge healthy">Loading...</span>
@@ -182,7 +182,7 @@
182
182
  </div>
183
183
 
184
184
  <div style="text-align:center;padding:24px;color:var(--muted);font-size:12px;">
185
- SpecLock v5.4.1 &mdash; Developed by Sandeep Roy &mdash; <a href="https://github.com/sgroy10/speclock" style="color:var(--accent)">GitHub</a>
185
+ SpecLock v5.5.0 &mdash; Developed by Sandeep Roy &mdash; <a href="https://github.com/sgroy10/speclock" style="color:var(--accent)">GitHub</a>
186
186
  </div>
187
187
 
188
188
  <script>
@@ -113,7 +113,7 @@ import { fileURLToPath } from "url";
113
113
  import _path from "path";
114
114
 
115
115
  const PROJECT_ROOT = process.env.SPECLOCK_PROJECT_ROOT || process.cwd();
116
- const VERSION = "5.4.1";
116
+ const VERSION = "5.5.0";
117
117
  const AUTHOR = "Sandeep Roy";
118
118
  const START_TIME = Date.now();
119
119
 
@@ -887,7 +887,7 @@ app.get("/health", (req, res) => {
887
887
  status: "healthy",
888
888
  version: VERSION,
889
889
  uptime: Math.floor((Date.now() - START_TIME) / 1000),
890
- tools: 42,
890
+ tools: 51,
891
891
  auditChain: auditStatus,
892
892
  authEnabled: isAuthEnabled(PROJECT_ROOT),
893
893
  rateLimit: { limit: RATE_LIMIT, windowMs: RATE_WINDOW_MS },
@@ -901,8 +901,8 @@ app.get("/", (req, res) => {
901
901
  name: "speclock",
902
902
  version: VERSION,
903
903
  author: AUTHOR,
904
- description: "AI Constraint Engine Universal Rules Sync + AI Patch Firewall. Syncs constraints to Cursor, Claude Code, Copilot, Windsurf, Gemini, Aider, AGENTS.md. Patch Gateway (ALLOW/WARN/BLOCK verdicts), diff-native review (interface breaks, protected symbols, dependency drift, schema changes, API impact). Spec Compiler (NL→constraints), Code Graph (blast radius, lock-to-file mapping), Typed constraints, REST API v2, Python SDK + ROS2 integration. Policy-as-Code, RBAC, AES-256-GCM encryption, HMAC audit chain, SOC 2/HIPAA compliance. 49 MCP tools. 929 tests, 100% accuracy.",
905
- tools: 49,
904
+ description: "Stop AI from breaking code you told it not to touch. Enforces .cursorrules, CLAUDE.md, and AGENTS.md not just suggests. Zero-config Guardian Mode, Universal Rules Sync, AI Patch Firewall, Spec Compiler, Code Graph, Drift Score, HMAC audit chain, SOC 2/HIPAA compliance. 51 MCP tools. 976 tests.",
905
+ tools: 51,
906
906
  mcp_endpoint: "/mcp",
907
907
  health_endpoint: "/health",
908
908
  npm: "https://www.npmjs.com/package/speclock",
package/src/mcp/server.js CHANGED
@@ -70,6 +70,7 @@ import { getReplay, listSessions, formatReplay } from "../core/replay.js";
70
70
  import { computeDriftScore, formatDriftScore } from "../core/drift-score.js";
71
71
  import { computeCoverage, formatCoverage } from "../core/coverage.js";
72
72
  import { analyzeLockStrength, formatStrength } from "../core/strengthen.js";
73
+ import { discoverRuleFiles, protect, formatProtectReport } from "../core/guardian.js";
73
74
  import {
74
75
  readBrain,
75
76
  readEvents,
@@ -125,7 +126,7 @@ const PROJECT_ROOT =
125
126
  args.project || process.env.SPECLOCK_PROJECT_ROOT || process.cwd();
126
127
 
127
128
  // --- MCP Server ---
128
- const VERSION = "5.4.1";
129
+ const VERSION = "5.5.0";
129
130
  const AUTHOR = "Sandeep Roy";
130
131
 
131
132
  const server = new McpServer(
@@ -2065,6 +2066,46 @@ server.tool(
2065
2066
  }
2066
2067
  );
2067
2068
 
2069
+ // Tool 43: speclock_protect
2070
+ server.tool(
2071
+ "speclock_protect",
2072
+ "Zero-config Guardian Mode — Reads existing AI rule files (.cursorrules, CLAUDE.md, AGENTS.md, copilot-instructions.md, etc.), auto-extracts enforceable constraints, installs pre-commit hook, and syncs rules to all AI tools. One command, no flags. Makes your AI rules unbreakable.",
2073
+ {
2074
+ skipHook: { type: "boolean", description: "Skip pre-commit hook installation", default: false },
2075
+ skipSync: { type: "boolean", description: "Skip syncing rules to all formats", default: false },
2076
+ },
2077
+ async ({ skipHook, skipSync }) => {
2078
+ const report = protect(PROJECT_ROOT, { skipHook, skipSync });
2079
+ const formatted = formatProtectReport(report);
2080
+ return { content: [{ type: "text", text: formatted }] };
2081
+ }
2082
+ );
2083
+
2084
+ // Tool 44: speclock_discover_rules
2085
+ server.tool(
2086
+ "speclock_discover_rules",
2087
+ "Discover all AI rule files in the project (.cursorrules, CLAUDE.md, AGENTS.md, copilot-instructions.md, .windsurfrules, GEMINI.md, .aider.conf.yml). Shows which tools have rules configured and their sizes. Use this to see what rules exist before running speclock_protect.",
2088
+ {},
2089
+ async () => {
2090
+ const files = discoverRuleFiles(PROJECT_ROOT);
2091
+ if (files.length === 0) {
2092
+ return { content: [{ type: "text", text: "No AI rule files found in this project. Create a .cursorrules, CLAUDE.md, or AGENTS.md file first." }] };
2093
+ }
2094
+ const lines = [
2095
+ `## AI Rule Files Found`,
2096
+ ``,
2097
+ `| File | Tool | Lines | Size |`,
2098
+ `|------|------|-------|------|`,
2099
+ ];
2100
+ for (const f of files) {
2101
+ lines.push(`| \`${f.file}\` | ${f.tool} | ${f.lines} | ${f.size} bytes |`);
2102
+ }
2103
+ lines.push(``);
2104
+ lines.push(`Run \`speclock_protect\` to extract constraints and make them enforceable.`);
2105
+ return { content: [{ type: "text", text: lines.join("\n") }] };
2106
+ }
2107
+ );
2108
+
2068
2109
  // --- Smithery sandbox export ---
2069
2110
  export default function createSandboxServer() {
2070
2111
  return server;