speclock 5.2.6 → 5.3.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 +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 +553 -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/cli/index.js
CHANGED
|
@@ -62,6 +62,8 @@ import {
|
|
|
62
62
|
getSSOConfig,
|
|
63
63
|
saveSSOConfig,
|
|
64
64
|
} from "../core/sso.js";
|
|
65
|
+
import { syncRules, getSyncFormats } from "../core/rules-sync.js";
|
|
66
|
+
import { getReplay, listSessions, formatReplay } from "../core/replay.js";
|
|
65
67
|
|
|
66
68
|
// --- Argument parsing ---
|
|
67
69
|
|
|
@@ -117,7 +119,7 @@ function refreshContext(root) {
|
|
|
117
119
|
|
|
118
120
|
function printHelp() {
|
|
119
121
|
console.log(`
|
|
120
|
-
SpecLock v5.
|
|
122
|
+
SpecLock v5.3.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)
|
|
121
123
|
Developed by Sandeep Roy (github.com/sgroy10)
|
|
122
124
|
|
|
123
125
|
Usage: speclock <command> [options]
|
|
@@ -149,7 +151,13 @@ Commands:
|
|
|
149
151
|
license Show license tier and usage info
|
|
150
152
|
context Generate and print context pack
|
|
151
153
|
facts deploy [--provider X] Set deployment facts
|
|
152
|
-
|
|
154
|
+
sync [--format <name>] Sync constraints to AI tool rules files
|
|
155
|
+
sync --all Sync to ALL formats at once
|
|
156
|
+
sync --list List available sync formats
|
|
157
|
+
sync --preview <format> Preview without writing files
|
|
158
|
+
replay [--session <id>] Replay session activity — what AI tried & what was caught
|
|
159
|
+
replay --list List available sessions for replay
|
|
160
|
+
watch Start file watcher (live dashboard)
|
|
153
161
|
serve [--project <path>] Start MCP stdio server
|
|
154
162
|
status Show project brain summary
|
|
155
163
|
|
|
@@ -163,7 +171,10 @@ Options:
|
|
|
163
171
|
--format <soc2|hipaa|csv> Compliance export format
|
|
164
172
|
--project <path> Project root (for serve)
|
|
165
173
|
|
|
166
|
-
Templates: nextjs, react, express, supabase, stripe, security-hardened
|
|
174
|
+
Templates: nextjs, react, express, supabase, stripe, security-hardened,
|
|
175
|
+
safe-defaults, hipaa, api-stability, solo-founder
|
|
176
|
+
|
|
177
|
+
Sync Formats: cursor, claude, agents, windsurf, copilot, gemini, codex, aider
|
|
167
178
|
|
|
168
179
|
Policy-as-Code (v3.5):
|
|
169
180
|
policy list List all policy rules
|
|
@@ -310,11 +321,17 @@ Files created/updated:
|
|
|
310
321
|
Next steps:
|
|
311
322
|
To add constraints: npx speclock lock "Never touch auth files"
|
|
312
323
|
To check conflicts: npx speclock check "Modifying auth page"
|
|
313
|
-
To
|
|
324
|
+
To sync to AI tools: npx speclock sync --all
|
|
325
|
+
To replay sessions: npx speclock replay
|
|
314
326
|
To see status: npx speclock status
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
327
|
+
${!flags.template ? `
|
|
328
|
+
Quick start templates:
|
|
329
|
+
npx speclock template apply safe-defaults — Prevent the 5 most common AI disasters
|
|
330
|
+
npx speclock template apply solo-founder — Essential protection for indie builders
|
|
331
|
+
npx speclock template apply hipaa — HIPAA healthcare compliance (8 locks)
|
|
332
|
+
npx speclock template apply api-stability — Protect your public API contracts
|
|
333
|
+
` : ""}
|
|
334
|
+
Tip: Run "speclock sync --all" to push constraints to Cursor, Claude, Copilot, Windsurf, and more.
|
|
318
335
|
`);
|
|
319
336
|
return;
|
|
320
337
|
}
|
|
@@ -1096,6 +1113,119 @@ Tip: When starting a new chat, tell the AI:
|
|
|
1096
1113
|
process.exit(1);
|
|
1097
1114
|
}
|
|
1098
1115
|
|
|
1116
|
+
// --- REPLAY (new: incident replay) ---
|
|
1117
|
+
if (cmd === "replay") {
|
|
1118
|
+
const flags = parseFlags(args);
|
|
1119
|
+
|
|
1120
|
+
if (flags.list) {
|
|
1121
|
+
const result = listSessions(root, 10);
|
|
1122
|
+
console.log(`\nSession History (${result.total} total)`);
|
|
1123
|
+
console.log("=".repeat(60));
|
|
1124
|
+
if (result.sessions.length === 0) {
|
|
1125
|
+
console.log(" No sessions recorded yet.");
|
|
1126
|
+
} else {
|
|
1127
|
+
for (const s of result.sessions) {
|
|
1128
|
+
const current = s.isCurrent ? " [ACTIVE]" : "";
|
|
1129
|
+
console.log(` ${s.id} ${s.tool.padEnd(12)} ${s.startedAt.substring(0, 16)} ${s.events} events${current}`);
|
|
1130
|
+
if (s.summary && s.summary !== "(no summary)") {
|
|
1131
|
+
console.log(` ${"".padEnd(16)} ${s.summary.substring(0, 60)}`);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
console.log(`\nReplay a session: speclock replay --session <id>`);
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
const replay = getReplay(root, {
|
|
1140
|
+
sessionId: flags.session || null,
|
|
1141
|
+
limit: flags.limit ? parseInt(flags.limit, 10) : 50,
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1144
|
+
if (!replay.found) {
|
|
1145
|
+
console.error(replay.error);
|
|
1146
|
+
process.exit(1);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
console.log(`\nSpecLock Incident Replay`);
|
|
1150
|
+
console.log("=".repeat(60));
|
|
1151
|
+
console.log(formatReplay(replay));
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// --- SYNC (new: universal rules sync) ---
|
|
1156
|
+
if (cmd === "sync") {
|
|
1157
|
+
const flags = parseFlags(args);
|
|
1158
|
+
|
|
1159
|
+
// List available formats
|
|
1160
|
+
if (flags.list) {
|
|
1161
|
+
const formats = getSyncFormats();
|
|
1162
|
+
console.log("\nAvailable Sync Formats:");
|
|
1163
|
+
console.log("=".repeat(55));
|
|
1164
|
+
for (const f of formats) {
|
|
1165
|
+
console.log(` ${f.key.padEnd(12)} ${f.name.padEnd(18)} → ${f.file}`);
|
|
1166
|
+
console.log(` ${"".padEnd(12)} ${f.description}`);
|
|
1167
|
+
console.log("");
|
|
1168
|
+
}
|
|
1169
|
+
console.log("Usage:");
|
|
1170
|
+
console.log(" speclock sync --format cursor Sync to Cursor only");
|
|
1171
|
+
console.log(" speclock sync --all Sync to ALL formats");
|
|
1172
|
+
console.log(" speclock sync --preview claude Preview without writing");
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// Preview mode
|
|
1177
|
+
if (flags.preview) {
|
|
1178
|
+
const result = syncRules(root, { format: flags.preview, dryRun: true });
|
|
1179
|
+
if (result.errors.length > 0) {
|
|
1180
|
+
for (const err of result.errors) console.error(err);
|
|
1181
|
+
process.exit(1);
|
|
1182
|
+
}
|
|
1183
|
+
for (const s of result.synced) {
|
|
1184
|
+
console.log(`\n${"=".repeat(55)}`);
|
|
1185
|
+
console.log(`Preview: ${s.name} → ${s.file} (${s.size} bytes)`);
|
|
1186
|
+
console.log("=".repeat(55));
|
|
1187
|
+
console.log(s.content);
|
|
1188
|
+
}
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// Determine format
|
|
1193
|
+
const format = flags.format || (flags.all ? undefined : flags._[0]);
|
|
1194
|
+
if (!format && !flags.all) {
|
|
1195
|
+
console.error("Usage: speclock sync --format <cursor|claude|agents|windsurf|copilot|gemini|aider>");
|
|
1196
|
+
console.error(" speclock sync --all Sync to all formats");
|
|
1197
|
+
console.error(" speclock sync --list List formats");
|
|
1198
|
+
console.error(" speclock sync --preview <fmt> Preview output");
|
|
1199
|
+
process.exit(1);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
const options = {};
|
|
1203
|
+
if (format) options.format = format;
|
|
1204
|
+
if (flags.append) options.append = true;
|
|
1205
|
+
|
|
1206
|
+
const result = syncRules(root, options);
|
|
1207
|
+
|
|
1208
|
+
if (result.errors.length > 0) {
|
|
1209
|
+
for (const err of result.errors) console.error(`Error: ${err}`);
|
|
1210
|
+
if (result.synced.length === 0) process.exit(1);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
if (result.synced.length > 0) {
|
|
1214
|
+
console.log(`\nSpecLock Sync Complete`);
|
|
1215
|
+
console.log("=".repeat(55));
|
|
1216
|
+
console.log(`Constraints: ${result.lockCount} lock(s), ${result.decisionCount} decision(s)`);
|
|
1217
|
+
console.log("");
|
|
1218
|
+
for (const s of result.synced) {
|
|
1219
|
+
console.log(` ✓ ${s.name.padEnd(18)} → ${s.file} (${s.size} bytes)`);
|
|
1220
|
+
}
|
|
1221
|
+
console.log(`\n${result.synced.length} file(s) synced. Your AI tools will now see SpecLock constraints.`);
|
|
1222
|
+
if (!format) {
|
|
1223
|
+
console.log("\nTip: Add these files to git so your AI tools read them automatically.");
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1099
1229
|
// --- STATUS ---
|
|
1100
1230
|
if (cmd === "status") {
|
|
1101
1231
|
showStatus(root);
|