speclock 5.2.5 → 5.3.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.
@@ -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.5";
116
+ const VERSION = "5.3.0";
117
117
  const AUTHOR = "Sandeep Roy";
118
118
  const START_TIME = Date.now();
119
119
 
@@ -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 — 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
- tools: 42,
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. 46 MCP tools. 929 tests, 100% accuracy.",
905
+ tools: 46,
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
@@ -65,6 +65,8 @@ import {
65
65
  parseUnifiedDiff,
66
66
  } from "../core/engine.js";
67
67
  import { generateContext, generateContextPack } from "../core/context.js";
68
+ import { syncRules, getSyncFormats } from "../core/rules-sync.js";
69
+ import { getReplay, listSessions, formatReplay } from "../core/replay.js";
68
70
  import {
69
71
  readBrain,
70
72
  readEvents,
@@ -120,7 +122,7 @@ const PROJECT_ROOT =
120
122
  args.project || process.env.SPECLOCK_PROJECT_ROOT || process.cwd();
121
123
 
122
124
  // --- MCP Server ---
123
- const VERSION = "5.2.5";
125
+ const VERSION = "5.3.0";
124
126
  const AUTHOR = "Sandeep Roy";
125
127
 
126
128
  const server = new McpServer(
@@ -1895,6 +1897,133 @@ server.tool(
1895
1897
  }
1896
1898
  );
1897
1899
 
1900
+ // --- Universal Rules Sync (v5.3) ---
1901
+
1902
+ // Tool 36: speclock_sync_rules
1903
+ server.tool(
1904
+ "speclock_sync_rules",
1905
+ "Sync SpecLock constraints to AI tool rules files. Generates .cursorrules, CLAUDE.md, AGENTS.md, .windsurfrules, copilot-instructions.md, GEMINI.md, and .aider.conf.yml from your SpecLock constraints. One source of truth for all AI tools. Use --format for a specific tool, or sync all at once.",
1906
+ {
1907
+ format: z.enum(["cursor", "claude", "agents", "windsurf", "copilot", "gemini", "codex", "aider", "all"]).optional().default("all").describe("Target format. 'all' syncs to every supported AI tool."),
1908
+ dryRun: z.boolean().optional().default(false).describe("Preview output without writing files"),
1909
+ append: z.boolean().optional().default(false).describe("Append to existing CLAUDE.md instead of overwriting (only for claude format)"),
1910
+ },
1911
+ async ({ format, dryRun, append }) => {
1912
+ const options = { dryRun };
1913
+ if (format && format !== "all") options.format = format;
1914
+ if (append) options.append = true;
1915
+
1916
+ const result = syncRules(PROJECT_ROOT, options);
1917
+
1918
+ if (result.errors.length > 0 && result.synced.length === 0) {
1919
+ return { content: [{ type: "text", text: `Sync failed: ${result.errors.join(", ")}` }], isError: true };
1920
+ }
1921
+
1922
+ const lines = [
1923
+ `## Rules Sync ${dryRun ? "(Preview)" : "Complete"}`,
1924
+ ``,
1925
+ `Constraints synced: ${result.lockCount} lock(s), ${result.decisionCount || 0} decision(s)`,
1926
+ ``,
1927
+ ];
1928
+
1929
+ for (const s of result.synced) {
1930
+ if (dryRun && s.content) {
1931
+ lines.push(`### ${s.name} → ${s.file}`);
1932
+ lines.push("```");
1933
+ lines.push(s.content);
1934
+ lines.push("```");
1935
+ lines.push("");
1936
+ } else {
1937
+ lines.push(`- **${s.name}** → \`${s.file}\` (${s.size} bytes)`);
1938
+ }
1939
+ }
1940
+
1941
+ if (!dryRun && result.synced.length > 0) {
1942
+ lines.push(``, `${result.synced.length} file(s) written. Your AI tools will now see SpecLock constraints.`);
1943
+ lines.push(``, `Tip: Commit these files to git so they're always in sync.`);
1944
+ }
1945
+
1946
+ if (result.errors.length > 0) {
1947
+ lines.push(``, `Warnings: ${result.errors.join(", ")}`);
1948
+ }
1949
+
1950
+ return { content: [{ type: "text", text: lines.join("\n") }] };
1951
+ }
1952
+ );
1953
+
1954
+ // Tool 37: speclock_replay
1955
+ server.tool(
1956
+ "speclock_replay",
1957
+ "Replay a session's activity log — shows exactly what AI agents tried and what SpecLock caught. Returns chronological event list with ALLOW/WARN/BLOCK verdicts, changes logged, locks added/removed, and session stats. Like a flight recorder for your AI coding sessions.",
1958
+ {
1959
+ sessionId: z.string().optional().describe("Specific session ID to replay. Omit to replay most recent session."),
1960
+ limit: z.number().optional().default(50).describe("Max events to return"),
1961
+ },
1962
+ async ({ sessionId, limit }) => {
1963
+ const replay = getReplay(PROJECT_ROOT, { sessionId, limit });
1964
+
1965
+ if (!replay.found) {
1966
+ return { content: [{ type: "text", text: replay.error }], isError: true };
1967
+ }
1968
+
1969
+ const formatted = formatReplay(replay);
1970
+ return { content: [{ type: "text", text: `## Incident Replay\n\n\`\`\`\n${formatted}\n\`\`\`` }] };
1971
+ }
1972
+ );
1973
+
1974
+ // Tool 38: speclock_list_sessions
1975
+ server.tool(
1976
+ "speclock_list_sessions",
1977
+ "List available sessions for replay. Shows session IDs, tools used, timestamps, and event counts.",
1978
+ {
1979
+ limit: z.number().optional().default(10).describe("Max sessions to list"),
1980
+ },
1981
+ async ({ limit }) => {
1982
+ const result = listSessions(PROJECT_ROOT, limit);
1983
+
1984
+ if (result.sessions.length === 0) {
1985
+ return { content: [{ type: "text", text: "No sessions recorded yet." }] };
1986
+ }
1987
+
1988
+ const lines = [`## Sessions (${result.total} total)`, ""];
1989
+ for (const s of result.sessions) {
1990
+ const current = s.isCurrent ? " **[ACTIVE]**" : "";
1991
+ lines.push(`- **${s.id}** — ${s.tool} — ${s.startedAt.substring(0, 16)} — ${s.events} events${current}`);
1992
+ if (s.summary && s.summary !== "(no summary)") {
1993
+ lines.push(` _${s.summary.substring(0, 80)}_`);
1994
+ }
1995
+ }
1996
+ lines.push("", "Use `speclock_replay` with a session ID to see full activity log.");
1997
+
1998
+ return { content: [{ type: "text", text: lines.join("\n") }] };
1999
+ }
2000
+ );
2001
+
2002
+ // Tool 39: speclock_list_sync_formats
2003
+ server.tool(
2004
+ "speclock_list_sync_formats",
2005
+ "List all available AI tool formats that SpecLock can sync constraints to. Shows format key, tool name, output file path, and description.",
2006
+ {},
2007
+ async () => {
2008
+ const formats = getSyncFormats();
2009
+ const lines = [
2010
+ `## Available Sync Formats`,
2011
+ ``,
2012
+ `| Format | Tool | Output File | Description |`,
2013
+ `|--------|------|-------------|-------------|`,
2014
+ ];
2015
+
2016
+ for (const f of formats) {
2017
+ lines.push(`| ${f.key} | ${f.name} | \`${f.file}\` | ${f.description} |`);
2018
+ }
2019
+
2020
+ lines.push(``);
2021
+ lines.push(`Use \`speclock_sync_rules\` with a specific format or "all" to sync.`);
2022
+
2023
+ return { content: [{ type: "text", text: lines.join("\n") }] };
2024
+ }
2025
+ );
2026
+
1898
2027
  // --- Smithery sandbox export ---
1899
2028
  export default function createSandboxServer() {
1900
2029
  return server;