speclock 5.2.0 → 5.2.1

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
@@ -305,25 +305,118 @@ pip install speclock-sdk
305
305
  ```
306
306
 
307
307
  ```python
308
- from speclock import ConstraintChecker
309
- checker = ConstraintChecker(constraints)
310
- result = checker.check({"metric": "speed_mps", "value": 3.5})
308
+ from speclock import SpecLock
309
+
310
+ sl = SpecLock(project_root=".")
311
+
312
+ # Check text constraints (semantic conflict detection)
313
+ result = sl.check_text("Switch database to MongoDB")
314
+ # → { has_conflict: True, conflicting_locks: [...] }
315
+
316
+ # Check typed constraints (numerical/range/state/temporal)
317
+ result = sl.check_typed(metric="speed_mps", value=3.5)
311
318
  # → violation: speed exceeds 2.0 m/s limit
319
+
320
+ # Combined check (text + typed in one call)
321
+ result = sl.check(action="Increase speed", speed_mps=3.5)
322
+ ```
323
+
324
+ Uses the same `.speclock/brain.json` as the Node.js MCP server — constraints stay in sync across all environments.
325
+
326
+ **ROS2 Guardian Node:** Real-time constraint enforcement for robots and autonomous systems.
327
+
328
+ ```yaml
329
+ # config/constraints.yaml
330
+ constraints:
331
+ - type: range
332
+ metric: joint_position_rad
333
+ min: -3.14
334
+ max: 3.14
335
+ - type: numerical
336
+ metric: velocity_mps
337
+ operator: "<="
338
+ value: 2.0
339
+ - type: state
340
+ metric: system_mode
341
+ forbidden:
342
+ - from: emergency_stop
343
+ to: autonomous
344
+ ```
345
+
346
+ - Subscribes to `/joint_states`, `/cmd_vel`, `/speclock/state_transition`
347
+ - Publishes violations to `/speclock/violations`
348
+ - Triggers emergency stop via `/speclock/emergency_stop`
349
+ - Checks constraints on every incoming ROS2 message at configurable rate
350
+
351
+ ---
352
+
353
+ ## Patch Gateway (v5.1)
354
+
355
+ One API call gates every change. Takes a description + file list, returns ALLOW/WARN/BLOCK:
356
+
357
+ ```
358
+ speclock_review_patch({
359
+ description: "Add social login to auth page",
360
+ files: ["src/auth/login.js"]
361
+ })
362
+
363
+ → { verdict: "BLOCK", riskScore: 85,
364
+ reasons: [{ type: "semantic_conflict", lock: "Never modify auth" }],
365
+ blastRadius: { impactPercent: 28.3 },
366
+ summary: "BLOCKED. 1 constraint conflict. 12 files affected." }
367
+ ```
368
+
369
+ Combines semantic conflict detection + lock-to-file mapping + blast radius + typed constraint awareness into a single risk score (0-100).
370
+
371
+ ---
372
+
373
+ ## AI Patch Firewall (v5.2)
374
+
375
+ Reviews actual diffs, not just descriptions. Catches things intent review misses:
376
+
377
+ ```
378
+ POST /api/v2/gateway/review-diff
379
+ {
380
+ "description": "Remove password column",
381
+ "diff": "diff --git a/migrations/001.sql ..."
382
+ }
383
+
384
+ → { verdict: "BLOCK",
385
+ reviewMode: "unified",
386
+ intentVerdict: "ALLOW", ← description alone looks safe
387
+ diffVerdict: "BLOCK", ← diff reveals destructive schema change
388
+ signals: {
389
+ schemaChange: { score: 12, isDestructive: true },
390
+ interfaceBreak: { score: 10 },
391
+ protectedSymbolEdit: { score: 8 },
392
+ dependencyDrift: { score: 5 },
393
+ publicApiImpact: { score: 0 }
394
+ },
395
+ recommendation: { action: "require_approval" } }
312
396
  ```
313
397
 
314
- **ROS2 Guardian Node:** Real-time constraint enforcement for robots. Subscribes to sensor topics, checks constraints at configurable rate, publishes violations, triggers emergency stop.
398
+ **Signal detection:** Interface breaks (removed/changed exports), protected symbol edits in locked zones, dependency drift (critical package add/remove), schema/migration destructive changes, public API route changes.
399
+
400
+ **Hard escalation rules:** Auto-BLOCK on destructive schema changes, removed API routes, protected symbol edits, or multiple critical findings — regardless of score.
401
+
402
+ **Unified review:** Merges intent (35%) + diff (65%), takes the stronger verdict. Falls back to intent-only when no diff is available.
315
403
 
316
404
  ---
317
405
 
318
- ## REST API v2 (v5.0)
406
+ ## REST API v2
319
407
 
320
- Real-time constraint checking for autonomous systems:
408
+ Real-time constraint checking, patch review, and autonomous systems:
321
409
 
322
410
  ```bash
323
- # Single check
324
- POST /api/v2/check-typed { metric, value, entity }
411
+ # Patch Gateway (v5.1)
412
+ POST /api/v2/gateway/review { description, files, useLLM }
413
+
414
+ # AI Patch Firewall (v5.2)
415
+ POST /api/v2/gateway/review-diff { description, files, diff, options }
416
+ POST /api/v2/gateway/parse-diff { diff }
325
417
 
326
- # Batch check (up to 100)
418
+ # Typed constraint checking
419
+ POST /api/v2/check-typed { metric, value, entity }
327
420
  POST /api/v2/check-batch { checks: [...] }
328
421
 
329
422
  # SSE streaming (real-time violations)
@@ -335,6 +428,7 @@ POST /api/v2/compiler/compile { text, autoApply }
335
428
  # Code Graph
336
429
  GET /api/v2/graph/blast-radius?file=src/core/memory.js
337
430
  GET /api/v2/graph/lock-map
431
+ POST /api/v2/graph/build
338
432
  ```
339
433
 
340
434
  ---
@@ -436,6 +530,17 @@ GET /api/v2/graph/lock-map
436
530
 
437
531
  </details>
438
532
 
533
+ <details>
534
+ <summary><b>Patch Gateway & AI Patch Firewall</b> — change review, diff analysis (v5.1/v5.2)</summary>
535
+
536
+ | Tool | What it does |
537
+ |------|-------------|
538
+ | `speclock_review_patch` | ALLOW/WARN/BLOCK verdict for proposed changes |
539
+ | `speclock_review_patch_diff` | Diff-native review with signal scoring + unified verdict |
540
+ | `speclock_parse_diff` | Parse unified diff into structured changes (debug/inspect) |
541
+
542
+ </details>
543
+
439
544
  ---
440
545
 
441
546
  ## CLI
@@ -611,4 +716,4 @@ Built by **[Sandeep Roy](https://github.com/sgroy10)**
611
716
 
612
717
  ---
613
718
 
614
- <p align="center"><i>v5.0.0 — 1073 tests, 99.4% pass rate, 42 MCP tools, Spec Compiler, Code Graph, Typed Constraints, Python SDK, ROS2, REST API v2. Because remembering isn't enough.</i></p>
719
+ <p align="center"><i>v5.2.0 — 1073 tests, 99.4% pass rate, 42 MCP tools, Patch Gateway, AI Patch Firewall, Spec Compiler, Code Graph, Typed Constraints, Python SDK, ROS2, REST API v2. Because remembering isn't enough.</i></p>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  "name": "speclock",
4
4
 
5
- "version": "5.2.0",
5
+ "version": "5.2.1",
6
6
 
7
7
  "description": "AI Constraint Engine — AI Patch Firewall. Diff-native review (interface breaks, protected symbols, dependency drift, schema changes, API impact), Patch Gateway (ALLOW/WARN/BLOCK verdicts), Spec Compiler (NL→constraints), Code Graph (blast radius, lock-to-file mapping), Typed constraints, REST API v2, Python SDK, ROS2 integration. 42 MCP tools, Gemini LLM hybrid, HMAC audit chain, RBAC, encryption, SOC 2/HIPAA compliance.",
8
8
 
package/src/cli/index.js CHANGED
@@ -117,7 +117,7 @@ function refreshContext(root) {
117
117
 
118
118
  function printHelp() {
119
119
  console.log(`
120
- SpecLock v5.2.0 — AI Constraint Engine (Spec Compiler + Code Graph + Typed Constraints + Python SDK + ROS2 + REST API v2 + Gemini LLM + Policy-as-Code + Auth + RBAC + Encryption)
120
+ SpecLock v5.2.1 — AI Constraint Engine (Spec Compiler + Code Graph + Typed Constraints + Python SDK + ROS2 + REST API v2 + Gemini LLM + Policy-as-Code + Auth + RBAC + Encryption)
121
121
  Developed by Sandeep Roy (github.com/sgroy10)
122
122
 
123
123
  Usage: speclock <command> [options]
@@ -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.2.0";
12
+ const VERSION = "5.2.1";
13
13
 
14
14
  // PHI-related keywords for HIPAA filtering
15
15
  const PHI_KEYWORDS = [
@@ -14,7 +14,7 @@ import { analyzeConflict } from "./semantics.js";
14
14
  // --- Signal score caps (from ChatGPT spec) ---
15
15
 
16
16
  const CAPS = {
17
- semanticConflict: 20,
17
+ semanticConflict: 45,
18
18
  lockFileOverlap: 20,
19
19
  blastRadius: 15,
20
20
  typedConstraintRelevance: 10,
@@ -514,6 +514,17 @@ export function calculateVerdict(signals, reasons) {
514
514
  hardBlockReason = "Multiple critical issues with high confidence.";
515
515
  }
516
516
 
517
+ // Semantic conflict at HIGH confidence (>=0.7) should hard-block
518
+ // even if other signals are absent — the engine is certain this
519
+ // action violates a lock.
520
+ const highConfSemantic = reasons.filter(r =>
521
+ r.type === "semantic_conflict" && (r.confidence || 0) >= 0.7
522
+ );
523
+ if (highConfSemantic.length > 0) {
524
+ hardBlock = true;
525
+ hardBlockReason = `High-confidence semantic conflict: ${highConfSemantic[0].message || "action violates active lock"}.`;
526
+ }
527
+
517
528
  // --- Determine verdict ---
518
529
  let verdict;
519
530
  if (hardBlock || riskScore >= 50) {
@@ -272,6 +272,10 @@ export const EUPHEMISM_MAP = {
272
272
  "reconcile": ["modify", "adjust", "change", "alter"],
273
273
  "reverse": ["undo", "revert", "modify", "change"],
274
274
  "recalculate": ["modify", "change", "update", "alter"],
275
+ "recompute": ["modify", "change", "recalculate", "alter"],
276
+ "reprocess": ["override", "modify", "recalculate", "delete", "redo"],
277
+ "round up": ["modify", "tamper", "falsify", "alter", "inflate"],
278
+ "round down": ["modify", "tamper", "falsify", "alter", "deflate"],
275
279
  "backdate": ["modify", "tamper", "falsify", "change"],
276
280
  "rebalance": ["modify", "adjust", "change", "redistribute"],
277
281
  "reclassify": ["modify", "change", "recategorize"],
@@ -319,7 +323,7 @@ export const EUPHEMISM_MAP = {
319
323
  "bridge": ["connect", "link", "merge", "join"],
320
324
  "segment": ["split", "separate", "isolate", "divide"],
321
325
  "flatten": ["merge", "simplify", "restructure"],
322
- "consolidate": ["merge", "combine", "reduce"],
326
+ "consolidate": ["merge", "combine", "reduce", "delete", "expose"],
323
327
  "spin up": ["create", "deploy", "start"],
324
328
  "spin down": ["delete", "remove", "stop"],
325
329
  "tear down": ["delete", "remove", "destroy"],
@@ -349,6 +353,23 @@ export const EUPHEMISM_MAP = {
349
353
  "scrape": ["extract", "collect", "harvest"],
350
354
  "harvest": ["collect", "extract", "scrape"],
351
355
 
356
+ // Verification/compliance bypass euphemisms
357
+ "skip check": ["bypass", "disable", "remove"],
358
+ "skip verification": ["bypass", "disable", "remove"],
359
+ "streamline verification": ["bypass", "weaken", "remove", "skip"],
360
+ "streamline application": ["bypass", "skip", "remove"],
361
+ "streamline detection": ["weaken", "disable", "bypass"],
362
+ "for research purposes": ["excuse", "bypass", "unauthorized"],
363
+ "in dev": ["excuse", "bypass"],
364
+ "mock change": ["bypass", "modify", "test excuse"],
365
+
366
+ // Record manipulation/destruction euphemisms
367
+ "clean up records": ["delete", "remove", "destroy"],
368
+ "clean up old": ["delete", "remove", "purge"],
369
+ "archive and delete": ["delete", "remove", "destroy"],
370
+ "refresh timestamps": ["falsify", "tamper", "modify"],
371
+ "refresh inspection": ["falsify", "tamper", "modify"],
372
+
352
373
  // Encryption euphemisms
353
374
  "unencrypted": ["without encryption", "disable encryption", "no encryption", "plaintext"],
354
375
  "plaintext": ["without encryption", "unencrypted", "no encryption"],
@@ -689,6 +710,45 @@ export const CONCEPT_MAP = {
689
710
  "k8s": ["kubernetes", "cluster", "infrastructure",
690
711
  "container orchestration"],
691
712
  "cluster": ["kubernetes", "k8s", "infrastructure", "nodes"],
713
+
714
+ // Education / student records
715
+ "gpa": ["grades", "grade point", "academic record", "transcript"],
716
+ "grades": ["gpa", "academic record", "transcript", "marks", "scores"],
717
+ "transcript": ["grades", "gpa", "academic record", "student record"],
718
+ "financial aid": ["student loans", "scholarships", "grants", "student data", "student records"],
719
+ "student records": ["grades", "transcript", "enrollment", "academic data"],
720
+ "weighted averages": ["grades", "gpa", "academic calculation"],
721
+
722
+ // Government / benefits
723
+ "voter rolls": ["voter registration", "election records", "voter data"],
724
+ "citizen database": ["pii", "personal data", "government records", "citizen data"],
725
+ "benefit applications": ["claims", "welfare", "government benefits"],
726
+ "denied applications": ["rejected claims", "denied benefits", "denied requests"],
727
+
728
+ // Insurance / claims
729
+ "claims": ["insurance claims", "benefit claims", "applications"],
730
+ "denied claims": ["rejected claims", "denied applications"],
731
+ "cancelled applications": ["denied claims", "rejected applications", "voided applications"],
732
+
733
+ // Aerospace / aviation safety
734
+ "inspection records": ["safety records", "maintenance records", "compliance records"],
735
+ "discrepancy reports": ["safety reports", "incident reports", "audit findings"],
736
+ "black box": ["flight recorder", "flight data", "telemetry data", "safety data"],
737
+ "inspection timestamps": ["safety records", "maintenance dates", "compliance dates"],
738
+
739
+ // Gaming / virtual economy
740
+ "virtual currency": ["in-game currency", "game tokens", "game economy"],
741
+ "player data": ["user data", "gamer data", "player records", "pii"],
742
+ "player ips": ["ip addresses", "pii", "player data", "network data"],
743
+ "cheat detection": ["anti-cheat", "cheat prevention", "security", "game integrity"],
744
+
745
+ // Real estate / tenant screening
746
+ "background check": ["tenant screening", "verification", "due diligence"],
747
+ "tenant screening": ["background check", "credit check", "verification"],
748
+
749
+ // Telecom / billing
750
+ "call records": ["cdr", "call data", "telecom records", "billing records"],
751
+ "subscriber data": ["customer data", "user data", "telecom records"],
692
752
  };
693
753
 
694
754
  // ===================================================================
@@ -780,7 +840,9 @@ const NEGATIVE_INTENT_MARKERS = [
780
840
  "clean up", "sunset", "retire", "phase out",
781
841
  "decommission", "wind down", "take down",
782
842
  "take offline", "pull the plug",
783
- "streamline",
843
+ "streamline", "consolidate",
844
+ "round up", "round down", "reprocess", "recompute",
845
+ "falsify", "tamper",
784
846
  ].sort((a, b) => b.length - a.length);
785
847
 
786
848
  // ===================================================================
@@ -1892,15 +1954,50 @@ export function scoreConflict({ actionText, lockText }) {
1892
1954
  rawWordOverlap &&
1893
1955
  euphemismMatches.some(m => m.includes(`euphemism for ${_prohibVerb}`));
1894
1956
 
1895
- if (!euphemismMatchesProhibitedVerb) {
1957
+ // NEW: Check if euphemism maps to lock's prohibited verb even without
1958
+ // word overlap. Cross-domain attacks like "truncate audit_log" vs
1959
+ // "Never delete student records" have no shared nouns but the euphemism
1960
+ // still proves destructive intent matching the lock's prohibition.
1961
+ const _DESTRUCTIVE_VERBS = new Set([
1962
+ "delete", "remove", "destroy", "wipe", "purge", "erase",
1963
+ "disable", "bypass", "expose", "tamper", "falsify",
1964
+ "override", "leak", "steal", "skip", "weaken",
1965
+ ]);
1966
+ const euphemismMatchesDestructiveProhibition = !euphemismMatchesProhibitedVerb &&
1967
+ _prohibVerb && _DESTRUCTIVE_VERBS.has(_prohibVerb) &&
1968
+ euphemismMatches.some(m => m.includes(`euphemism for ${_prohibVerb}`));
1969
+
1970
+ if (euphemismMatchesProhibitedVerb) {
1971
+ // Full bypass — euphemism matches prohibited verb AND has content overlap
1972
+ // No reduction applied (existing behavior)
1973
+ } else if (euphemismMatchesDestructiveProhibition) {
1974
+ // Euphemism maps to destructive prohibited verb but no subject overlap
1975
+ // Apply moderate reduction (not 0.15) — still suspicious enough to flag
1976
+ score = Math.floor(score * 0.50);
1977
+ reasons.push("scope gate softened: euphemism matches destructive prohibition without subject overlap");
1978
+ } else {
1896
1979
  // NO subject match at all — verb-only match → heavy reduction
1897
1980
  score = Math.floor(score * 0.15);
1898
1981
  reasons.push("subject gate: no subject overlap — verb-only match, likely false positive");
1899
1982
  }
1900
1983
  } else if (hasVocabSubjectMatch && !hasScopeMatch && subjectComparison.lockSubjects.length > 0 && subjectComparison.actionSubjects.length > 0) {
1901
1984
  // Vocabulary overlap exists but subjects point to DIFFERENT scopes
1902
- score = Math.floor(score * 0.35);
1903
- reasons.push(`scope gate: shared vocabulary but different scope — lock targets "${subjectComparison.lockSubjects[0]}", action targets "${subjectComparison.actionSubjects[0]}"`);
1985
+ // If euphemism maps to a destructive verb, soften the gate
1986
+ const _prohibVerb2 = extractProhibitedVerb(lockText);
1987
+ const _DESTRUCTIVE_VERBS2 = new Set([
1988
+ "delete", "remove", "destroy", "wipe", "purge", "erase",
1989
+ "disable", "bypass", "expose", "tamper", "falsify",
1990
+ "override", "leak", "steal", "skip", "weaken",
1991
+ ]);
1992
+ const hasDestructiveEuphemism = _prohibVerb2 && _DESTRUCTIVE_VERBS2.has(_prohibVerb2) &&
1993
+ euphemismMatches.some(m => m.includes(`euphemism for ${_prohibVerb2}`));
1994
+ if (hasDestructiveEuphemism) {
1995
+ score = Math.floor(score * 0.55);
1996
+ reasons.push(`scope gate softened: destructive euphemism with different scope — lock targets "${subjectComparison.lockSubjects[0]}", action targets "${subjectComparison.actionSubjects[0]}"`);
1997
+ } else {
1998
+ score = Math.floor(score * 0.35);
1999
+ reasons.push(`scope gate: shared vocabulary but different scope — lock targets "${subjectComparison.lockSubjects[0]}", action targets "${subjectComparison.actionSubjects[0]}"`);
2000
+ }
1904
2001
  }
1905
2002
 
1906
2003
  const prohibitedVerb = extractProhibitedVerb(lockText);
@@ -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.2.0 &mdash; AI Constraint Engine</div>
92
+ <div class="meta">v5.2.1 &mdash; AI Constraint Engine</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.2.0 &mdash; Developed by Sandeep Roy &mdash; <a href="https://github.com/sgroy10/speclock" style="color:var(--accent)">GitHub</a>
185
+ SpecLock v5.2.1 &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.2.0";
116
+ const VERSION = "5.2.1";
117
117
  const AUTHOR = "Sandeep Roy";
118
118
  const START_TIME = Date.now();
119
119
 
@@ -901,7 +901,7 @@ app.get("/", (req, res) => {
901
901
  name: "speclock",
902
902
  version: VERSION,
903
903
  author: AUTHOR,
904
- description: "AI Constraint Engine for autonomous systems governance. Spec Compiler (NL→constraints), Code Graph (blast radius, lock-to-file mapping), Typed constraints (numerical, range, state, temporal), REST API v2 with batch checking & SSE streaming. Python SDK + ROS2 integration. Policy-as-Code, RBAC, AES-256-GCM encryption, hard enforcement, HMAC audit chain, SOC 2/HIPAA compliance. 42 MCP tools. 940 tests, 99.4% accuracy.",
904
+ description: "AI Constraint Engine AI Patch Firewall. 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. 42 MCP tools. 1073 tests, 99.4% accuracy.",
905
905
  tools: 42,
906
906
  mcp_endpoint: "/mcp",
907
907
  health_endpoint: "/health",
@@ -913,45 +913,60 @@ app.get("/", (req, res) => {
913
913
  // Smithery server card for listing metadata
914
914
  app.get("/.well-known/mcp/server-card.json", (req, res) => {
915
915
  setCorsHeaders(res);
916
+ // Smithery-compatible server card format (SEP-1649)
916
917
  res.json({
917
- name: "SpecLock",
918
- version: VERSION,
919
- description: "AI Constraint Engine for autonomous systems governance. Spec Compiler (NL→constraints via Gemini Flash), Code Graph (dependency parsing, blast radius, lock-to-file mapping), Typed constraints (numerical, range, state, temporal), REST API v2, Python SDK + ROS2 Guardian Node. Hybrid heuristic + Gemini LLM. Policy-as-Code, RBAC, AES-256-GCM encryption, hard enforcement, HMAC audit chain, SOC 2/HIPAA compliance. 42 MCP tools. 940 tests, 99.4% accuracy. Works with Claude Code, Cursor, Windsurf, Cline, Bolt.new, Lovable.",
920
- author: {
921
- name: "Sandeep Roy",
922
- url: "https://github.com/sgroy10",
923
- },
924
- repository: "https://github.com/sgroy10/speclock",
925
- homepage: "https://sgroy10.github.io/speclock/",
926
- license: "MIT",
927
- capabilities: {
928
- tools: 42,
929
- categories: [
930
- "Memory Management",
931
- "Change Tracking",
932
- "Constraint Enforcement",
933
- "Git Integration",
934
- "AI Intelligence",
935
- "Templates & Reports",
936
- "Compliance & Audit",
937
- "Hard Enforcement",
938
- "Policy-as-Code",
939
- "Telemetry",
940
- "Typed Constraints",
941
- "REST API v2",
942
- "Real-Time Streaming",
943
- "Robotics / ROS2",
944
- "Python SDK",
945
- ],
918
+ serverInfo: {
919
+ name: "speclock",
920
+ version: VERSION,
946
921
  },
947
- keywords: [
948
- "ai-memory", "constraint-enforcement", "mcp", "policy-as-code",
949
- "sso", "oauth", "rbac", "encryption", "audit", "compliance",
950
- "soc2", "hipaa", "dashboard", "telemetry", "claude-code",
951
- "cursor", "bolt-new", "lovable", "enterprise",
952
- "robotics", "ros2", "autonomous-systems", "iot", "typed-constraints",
953
- "real-time", "sse", "batch-api", "python-sdk", "safety",
922
+ tools: [
923
+ { name: "speclock_init", description: "Initialize SpecLock in the current project directory.", inputSchema: { type: "object", properties: {} } },
924
+ { name: "speclock_get_context", description: "THE KEY TOOL. Returns the full structured context pack.", inputSchema: { type: "object", properties: { format: { enum: ["markdown","json"], type: "string", default: "markdown" } } } },
925
+ { name: "speclock_set_goal", description: "Set or update the project goal.", inputSchema: { type: "object", properties: { text: { type: "string", minLength: 1 } } } },
926
+ { name: "speclock_add_lock", description: "Add a non-negotiable constraint (SpecLock).", inputSchema: { type: "object", properties: { text: { type: "string", minLength: 1 }, tags: { type: "array", items: { type: "string" }, default: [] }, source: { enum: ["user","agent"], type: "string", default: "agent" } } } },
927
+ { name: "speclock_remove_lock", description: "Remove (deactivate) a SpecLock by its ID.", inputSchema: { type: "object", properties: { lockId: { type: "string", minLength: 1 } } } },
928
+ { name: "speclock_add_decision", description: "Record an architectural or design decision.", inputSchema: { type: "object", properties: { text: { type: "string", minLength: 1 }, tags: { type: "array", items: { type: "string" }, default: [] }, source: { enum: ["user","agent"], type: "string", default: "agent" } } } },
929
+ { name: "speclock_add_note", description: "Add a pinned note for reference.", inputSchema: { type: "object", properties: { text: { type: "string", minLength: 1 }, pinned: { type: "boolean", default: true } } } },
930
+ { name: "speclock_set_deploy_facts", description: "Record deployment configuration facts.", inputSchema: { type: "object", properties: { provider: { type: "string" }, branch: { type: "string" }, url: { type: "string" }, autoDeploy: { type: "boolean" }, notes: { type: "string" } } } },
931
+ { name: "speclock_log_change", description: "Manually log a significant change.", inputSchema: { type: "object", properties: { summary: { type: "string", minLength: 1 }, files: { type: "array", items: { type: "string" }, default: [] } } } },
932
+ { name: "speclock_get_changes", description: "Get recent file changes tracked by SpecLock.", inputSchema: { type: "object", properties: { limit: { type: "integer", default: 20, minimum: 1, maximum: 100 } } } },
933
+ { name: "speclock_get_events", description: "Get the event log, optionally filtered by type.", inputSchema: { type: "object", properties: { type: { type: "string" }, limit: { type: "integer", default: 50, minimum: 1, maximum: 200 }, since: { type: "string" } } } },
934
+ { name: "speclock_check_conflict", description: "Check if a proposed action conflicts with any active SpecLock. In hard mode, blocks above threshold.", inputSchema: { type: "object", properties: { proposedAction: { type: "string", minLength: 1 } } } },
935
+ { name: "speclock_session_briefing", description: "Start a new session and get a full briefing.", inputSchema: { type: "object", properties: { toolName: { enum: ["claude-code","cursor","codex","windsurf","cline","unknown"], type: "string", default: "unknown" } } } },
936
+ { name: "speclock_session_summary", description: "End the current session and record what was accomplished.", inputSchema: { type: "object", properties: { summary: { type: "string", minLength: 1 } } } },
937
+ { name: "speclock_checkpoint", description: "Create a named git tag checkpoint for easy rollback.", inputSchema: { type: "object", properties: { name: { type: "string", minLength: 1 } } } },
938
+ { name: "speclock_repo_status", description: "Get current git repository status.", inputSchema: { type: "object", properties: {} } },
939
+ { name: "speclock_suggest_locks", description: "AI-powered lock suggestions based on project patterns.", inputSchema: { type: "object", properties: {} } },
940
+ { name: "speclock_detect_drift", description: "Scan recent changes for constraint violations.", inputSchema: { type: "object", properties: {} } },
941
+ { name: "speclock_health", description: "Health check with completeness score and multi-agent timeline.", inputSchema: { type: "object", properties: {} } },
942
+ { name: "speclock_apply_template", description: "Apply a pre-built constraint template (nextjs, react, express, supabase, stripe, security-hardened).", inputSchema: { type: "object", properties: { name: { type: "string" } } } },
943
+ { name: "speclock_report", description: "Violation report — how many times SpecLock blocked changes.", inputSchema: { type: "object", properties: {} } },
944
+ { name: "speclock_audit", description: "Audit staged files against active locks.", inputSchema: { type: "object", properties: {} } },
945
+ { name: "speclock_verify_audit", description: "Verify the integrity of the HMAC audit chain.", inputSchema: { type: "object", properties: {} } },
946
+ { name: "speclock_export_compliance", description: "Generate compliance reports (SOC 2, HIPAA, CSV).", inputSchema: { type: "object", properties: { format: { enum: ["soc2","hipaa","csv"], type: "string" } } } },
947
+ { name: "speclock_set_enforcement", description: "Set enforcement mode: advisory (warn) or hard (block).", inputSchema: { type: "object", properties: { mode: { enum: ["advisory","hard"], type: "string" }, blockThreshold: { type: "integer", default: 70, minimum: 0, maximum: 100 } } } },
948
+ { name: "speclock_override_lock", description: "Override a lock with justification. Logged to audit trail.", inputSchema: { type: "object", properties: { lockId: { type: "string", minLength: 1 }, action: { type: "string", minLength: 1 }, reason: { type: "string", minLength: 1 } } } },
949
+ { name: "speclock_semantic_audit", description: "Semantic pre-commit: analyzes code changes vs locks.", inputSchema: { type: "object", properties: {} } },
950
+ { name: "speclock_override_history", description: "Show lock override history.", inputSchema: { type: "object", properties: { lockId: { type: "string" } } } },
951
+ { name: "speclock_policy_evaluate", description: "Evaluate policy-as-code rules against proposed actions.", inputSchema: { type: "object", properties: { files: { type: "array", items: { type: "string" } }, actionType: { type: "string" } } } },
952
+ { name: "speclock_policy_manage", description: "Policy CRUD: list, add, remove policy rules.", inputSchema: { type: "object", properties: { action: { enum: ["list","add","remove"], type: "string" } } } },
953
+ { name: "speclock_telemetry", description: "Opt-in usage analytics summary.", inputSchema: { type: "object", properties: { action: { enum: ["status","enable","disable","report"], type: "string" } } } },
954
+ { name: "speclock_guard_file", description: "Add SPECLOCK-GUARD header to lock specific files.", inputSchema: { type: "object", properties: { file: { type: "string" }, lockId: { type: "string" } } } },
955
+ { name: "speclock_auto_guard", description: "Auto-guard files related to lock keywords.", inputSchema: { type: "object", properties: {} } },
956
+ { name: "speclock_add_typed_lock", description: "Add typed constraint (numerical/range/state/temporal).", inputSchema: { type: "object", properties: { constraintType: { enum: ["numerical","range","state","temporal"], type: "string" }, metric: { type: "string" }, operator: { type: "string" }, value: {}, unit: { type: "string" }, description: { type: "string" } } } },
957
+ { name: "speclock_check_typed", description: "Check proposed values against typed constraints.", inputSchema: { type: "object", properties: { metric: { type: "string" }, value: {} } } },
958
+ { name: "speclock_list_typed_locks", description: "List all typed constraints with current thresholds.", inputSchema: { type: "object", properties: {} } },
959
+ { name: "speclock_update_threshold", description: "Update typed lock thresholds dynamically.", inputSchema: { type: "object", properties: { lockId: { type: "string" }, value: {}, operator: { type: "string" } } } },
960
+ { name: "speclock_compile_spec", description: "Compile natural language (PRDs, READMEs) into structured constraints via Gemini Flash.", inputSchema: { type: "object", properties: { text: { type: "string" }, autoApply: { type: "boolean", default: false } } } },
961
+ { name: "speclock_build_graph", description: "Build/refresh code dependency graph from imports (JS/TS/Python).", inputSchema: { type: "object", properties: {} } },
962
+ { name: "speclock_blast_radius", description: "Calculate blast radius — transitive dependents, impact %, depth.", inputSchema: { type: "object", properties: { file: { type: "string" } } } },
963
+ { name: "speclock_map_locks", description: "Map active locks to actual code files via the dependency graph.", inputSchema: { type: "object", properties: {} } },
964
+ { name: "speclock_review_patch", description: "ALLOW/WARN/BLOCK verdict — combines semantic conflict + lock-file mapping + blast radius.", inputSchema: { type: "object", properties: { description: { type: "string" }, files: { type: "array", items: { type: "string" } } } } },
965
+ { name: "speclock_review_patch_diff", description: "Diff-native review — parses actual diffs for interface breaks, protected symbols, dependency drift, schema changes.", inputSchema: { type: "object", properties: { description: { type: "string" }, diff: { type: "string" } } } },
966
+ { name: "speclock_parse_diff", description: "Parse unified diff into structured changes — imports, exports, symbols, routes, schema detection.", inputSchema: { type: "object", properties: { diff: { type: "string" } } } },
954
967
  ],
968
+ resources: [],
969
+ prompts: [],
955
970
  });
956
971
  });
957
972
 
package/src/mcp/server.js CHANGED
@@ -120,7 +120,7 @@ const PROJECT_ROOT =
120
120
  args.project || process.env.SPECLOCK_PROJECT_ROOT || process.cwd();
121
121
 
122
122
  // --- MCP Server ---
123
- const VERSION = "5.2.0";
123
+ const VERSION = "5.2.1";
124
124
  const AUTHOR = "Sandeep Roy";
125
125
 
126
126
  const server = new McpServer(