speclock 5.2.6 → 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.
- package/README.md +144 -24
- package/package.json +242 -67
- package/src/cli/index.js +137 -7
- package/src/core/auth.js +341 -341
- package/src/core/compliance.js +1 -1
- package/src/core/engine.js +63 -1
- package/src/core/lock-author.js +487 -487
- package/src/core/replay.js +236 -0
- package/src/core/rules-sync.js +548 -0
- package/src/core/templates.js +69 -0
- package/src/dashboard/index.html +2 -2
- package/src/mcp/http-server.js +3 -3
- package/src/mcp/server.js +130 -1
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.
|
|
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;
|