speclock 1.6.0 → 2.0.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 +47 -13
- package/package.json +2 -2
- package/src/cli/index.js +150 -13
- package/src/core/engine.js +243 -70
- package/src/core/git.js +6 -0
- package/src/core/hooks.js +87 -0
- package/src/core/llm-checker.js +239 -0
- package/src/core/semantics.js +1096 -0
- package/src/core/storage.js +18 -0
- package/src/core/templates.js +114 -0
- package/src/mcp/http-server.js +44 -4
- package/src/mcp/server.js +119 -2
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ No other tool does this. Not Claude's native memory. Not Mem0. Not CLAUDE.md fil
|
|
|
49
49
|
|---------|---------------------|------|--------------------------|--------------|
|
|
50
50
|
| Remembers context | Yes | Yes | Manual | **Yes** |
|
|
51
51
|
| **Stops the AI from breaking things** | No | No | No | **Yes — active enforcement** |
|
|
52
|
-
| **Semantic conflict detection** | No | No | No | **Yes —
|
|
52
|
+
| **Semantic conflict detection** | No | No | No | **Yes — semantic engine v2 (100% detection, 0% false positives)** |
|
|
53
53
|
| Works on Bolt.new | No | No | No | **Yes — npm file-based mode** |
|
|
54
54
|
| Works on Lovable | No | No | No | **Yes — MCP remote** |
|
|
55
55
|
| Structured decisions/locks | No | Tags only | Flat text | **Goals, locks, decisions, changes** |
|
|
@@ -155,18 +155,33 @@ AI: ⚠️ CONFLICT (HIGH — 100%): Violates lock "Never modify auth files"
|
|
|
155
155
|
Should I proceed or find another approach?
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
-
## Killer Feature: Semantic Conflict Detection
|
|
158
|
+
## Killer Feature: Semantic Conflict Detection v2
|
|
159
159
|
|
|
160
|
-
Not
|
|
160
|
+
Not keyword matching — **real semantic analysis**. Tested against 61 adversarial attack vectors across 7 categories. **100% detection rate, 0% false positives.**
|
|
161
|
+
|
|
162
|
+
SpecLock v2's semantic engine includes:
|
|
163
|
+
- **55 synonym groups** — "truncate" matches "delete", "flash" matches "overwrite", "sunset" matches "remove"
|
|
164
|
+
- **70+ euphemism map** — "clean up old data" detected as deletion, "streamline workflow" detected as removal
|
|
165
|
+
- **Domain concept maps** — "safety scanning" links to "CSAM detection", "PHI" links to "patient records"
|
|
166
|
+
- **Intent classifier** — "Enable audit logging" correctly allowed when lock says "Never disable audit logging"
|
|
167
|
+
- **Compound sentence splitter** — "Update UI and also delete patient records" — catches the hidden violation
|
|
168
|
+
- **Temporal evasion detection** — "temporarily disable" treated with same severity as "disable"
|
|
169
|
+
- **Optional LLM integration** — Enterprise-grade 99%+ accuracy with OpenAI/Anthropic API
|
|
161
170
|
|
|
162
171
|
```
|
|
163
|
-
Lock:
|
|
164
|
-
Action:
|
|
172
|
+
Lock: "Never delete patient records"
|
|
173
|
+
Action: "Clean up old patient data from cold storage"
|
|
165
174
|
|
|
166
|
-
Result:
|
|
167
|
-
-
|
|
175
|
+
Result: [HIGH] Conflict detected (confidence: 100%)
|
|
176
|
+
- euphemism detected: "clean up" (euphemism for delete)
|
|
177
|
+
- concept match: patient data → patient records
|
|
168
178
|
- lock prohibits this action (negation detected)
|
|
169
|
-
|
|
179
|
+
|
|
180
|
+
Lock: "Never disable audit logging"
|
|
181
|
+
Action: "Enable comprehensive audit logging"
|
|
182
|
+
|
|
183
|
+
Result: NO CONFLICT (confidence: 7%)
|
|
184
|
+
- intent alignment: "enable" is opposite of prohibited "disable" (compliant)
|
|
170
185
|
```
|
|
171
186
|
|
|
172
187
|
## Three Integration Modes
|
|
@@ -174,10 +189,10 @@ Result: [HIGH] Conflict detected (confidence: 85%)
|
|
|
174
189
|
| Mode | Platforms | How It Works |
|
|
175
190
|
|------|-----------|--------------|
|
|
176
191
|
| **MCP Remote** | Lovable, bolt.diy, Base44 | Connect via URL — no install needed |
|
|
177
|
-
| **MCP Local** | Claude Code, Cursor, Windsurf, Cline | `npx speclock serve` —
|
|
192
|
+
| **MCP Local** | Claude Code, Cursor, Windsurf, Cline | `npx speclock serve` — 22 tools via MCP |
|
|
178
193
|
| **npm File-Based** | Bolt.new, Aider, Rocket.new | `npx speclock setup` — AI reads SPECLOCK.md + uses CLI |
|
|
179
194
|
|
|
180
|
-
##
|
|
195
|
+
## 22 MCP Tools
|
|
181
196
|
|
|
182
197
|
### Memory Management
|
|
183
198
|
| Tool | Purpose |
|
|
@@ -218,6 +233,13 @@ Result: [HIGH] Conflict detected (confidence: 85%)
|
|
|
218
233
|
| `speclock_detect_drift` | Scan changes for constraint violations |
|
|
219
234
|
| `speclock_health` | Health score + multi-agent timeline |
|
|
220
235
|
|
|
236
|
+
### Templates, Reports & Enforcement
|
|
237
|
+
| Tool | Purpose |
|
|
238
|
+
|------|---------|
|
|
239
|
+
| `speclock_apply_template` | Apply pre-built constraint templates (nextjs, react, express, etc.) |
|
|
240
|
+
| `speclock_report` | Violation report — blocked change stats |
|
|
241
|
+
| `speclock_audit` | Audit staged files against active locks |
|
|
242
|
+
|
|
221
243
|
## Auto-Guard: Locks That Actually Work
|
|
222
244
|
|
|
223
245
|
When you add a lock, SpecLock **automatically finds and guards related files**:
|
|
@@ -251,7 +273,7 @@ Active locks are also embedded in `package.json` — so the AI sees your constra
|
|
|
251
273
|
|
|
252
274
|
```bash
|
|
253
275
|
# Setup
|
|
254
|
-
speclock setup --goal "Build my app"
|
|
276
|
+
speclock setup --goal "Build my app" --template nextjs # One-shot setup + template
|
|
255
277
|
|
|
256
278
|
# Memory
|
|
257
279
|
speclock goal <text> # Set project goal
|
|
@@ -265,6 +287,18 @@ speclock check <text> # Check for lock conflicts
|
|
|
265
287
|
speclock guard <file> --lock "text" # Manually guard a specific file
|
|
266
288
|
speclock unguard <file> # Remove guard from file
|
|
267
289
|
|
|
290
|
+
# Templates
|
|
291
|
+
speclock template list # List available templates
|
|
292
|
+
speclock template apply <name> # Apply: nextjs, react, express, supabase, stripe, security-hardened
|
|
293
|
+
|
|
294
|
+
# Violation Report
|
|
295
|
+
speclock report # Show violation stats + most tested locks
|
|
296
|
+
|
|
297
|
+
# Git Pre-commit Hook
|
|
298
|
+
speclock hook install # Install pre-commit hook
|
|
299
|
+
speclock hook remove # Remove pre-commit hook
|
|
300
|
+
speclock audit # Audit staged files against locks
|
|
301
|
+
|
|
268
302
|
# Tracking
|
|
269
303
|
speclock log-change <text> --files x # Log a change
|
|
270
304
|
speclock context # Regenerate context file
|
|
@@ -283,7 +317,7 @@ speclock watch # Start file watcher
|
|
|
283
317
|
└──────────────┬──────────────────┬────────────────────┘
|
|
284
318
|
│ │
|
|
285
319
|
MCP Protocol File-Based (npm)
|
|
286
|
-
(
|
|
320
|
+
(22 tool calls) (reads SPECLOCK.md +
|
|
287
321
|
.speclock/context/latest.md,
|
|
288
322
|
runs CLI commands)
|
|
289
323
|
│ │
|
|
@@ -318,4 +352,4 @@ MIT License - see [LICENSE](LICENSE) file.
|
|
|
318
352
|
|
|
319
353
|
---
|
|
320
354
|
|
|
321
|
-
*SpecLock
|
|
355
|
+
*SpecLock v2.0.0 — Real semantic conflict detection. 100% detection, 0% false positives. Because remembering isn't enough — AI needs to respect boundaries.*
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "speclock",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "AI constraint engine
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "AI constraint engine with real semantic conflict detection. 100% detection rate, 0% false positives. 22 MCP tools + CLI. Memory + enforcement for Bolt.new, Claude Code, Cursor, Lovable.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/mcp/server.js",
|
|
7
7
|
"bin": {
|
package/src/cli/index.js
CHANGED
|
@@ -16,9 +16,14 @@ import {
|
|
|
16
16
|
injectPackageJsonMarker,
|
|
17
17
|
syncLocksToPackageJson,
|
|
18
18
|
autoGuardRelatedFiles,
|
|
19
|
+
listTemplates,
|
|
20
|
+
applyTemplate,
|
|
21
|
+
generateReport,
|
|
22
|
+
auditStagedFiles,
|
|
19
23
|
} from "../core/engine.js";
|
|
20
24
|
import { generateContext } from "../core/context.js";
|
|
21
25
|
import { readBrain } from "../core/storage.js";
|
|
26
|
+
import { installHook, removeHook } from "../core/hooks.js";
|
|
22
27
|
|
|
23
28
|
// --- Argument parsing ---
|
|
24
29
|
|
|
@@ -74,23 +79,29 @@ function refreshContext(root) {
|
|
|
74
79
|
|
|
75
80
|
function printHelp() {
|
|
76
81
|
console.log(`
|
|
77
|
-
SpecLock
|
|
82
|
+
SpecLock v2.0.0 — AI Constraint Engine
|
|
78
83
|
Developed by Sandeep Roy (github.com/sgroy10)
|
|
79
84
|
|
|
80
85
|
Usage: speclock <command> [options]
|
|
81
86
|
|
|
82
87
|
Commands:
|
|
83
|
-
setup [--goal <text>]
|
|
88
|
+
setup [--goal <text>] [--template <name>] Full setup: init + SPECLOCK.md + context
|
|
84
89
|
init Initialize SpecLock in current directory
|
|
85
90
|
goal <text> Set or update the project goal
|
|
86
91
|
lock <text> [--tags a,b] Add a non-negotiable constraint
|
|
87
92
|
lock remove <id> Remove a lock by ID
|
|
88
|
-
guard <file> [--lock "text"] Inject lock warning into a file
|
|
89
|
-
unguard <file> Remove lock warning from a file
|
|
93
|
+
guard <file> [--lock "text"] Inject lock warning into a file
|
|
94
|
+
unguard <file> Remove lock warning from a file
|
|
90
95
|
decide <text> [--tags a,b] Record a decision
|
|
91
96
|
note <text> [--pinned] Add a pinned note
|
|
92
97
|
log-change <text> [--files x,y] Log a significant change
|
|
93
98
|
check <text> Check if action conflicts with locks
|
|
99
|
+
template list List available constraint templates
|
|
100
|
+
template apply <name> Apply a template (nextjs, react, etc.)
|
|
101
|
+
report Show violation report + stats
|
|
102
|
+
hook install Install git pre-commit hook
|
|
103
|
+
hook remove Remove git pre-commit hook
|
|
104
|
+
audit Audit staged files against locks
|
|
94
105
|
context Generate and print context pack
|
|
95
106
|
facts deploy [--provider X] Set deployment facts
|
|
96
107
|
watch Start file watcher (auto-track changes)
|
|
@@ -102,17 +113,20 @@ Options:
|
|
|
102
113
|
--source <user|agent> Who created this (default: user)
|
|
103
114
|
--files <a.ts,b.ts> Comma-separated file paths
|
|
104
115
|
--goal <text> Goal text (for setup command)
|
|
116
|
+
--template <name> Template to apply during setup
|
|
105
117
|
--lock <text> Lock text (for guard command)
|
|
106
118
|
--project <path> Project root (for serve)
|
|
107
119
|
|
|
120
|
+
Templates: nextjs, react, express, supabase, stripe, security-hardened
|
|
121
|
+
|
|
108
122
|
Examples:
|
|
109
|
-
npx speclock setup --goal "Build PawPalace pet shop"
|
|
123
|
+
npx speclock setup --goal "Build PawPalace pet shop" --template nextjs
|
|
110
124
|
npx speclock lock "Never modify auth files"
|
|
111
|
-
npx speclock
|
|
125
|
+
npx speclock template apply supabase
|
|
112
126
|
npx speclock check "Adding social login to auth page"
|
|
113
|
-
npx speclock
|
|
114
|
-
npx speclock
|
|
115
|
-
npx speclock
|
|
127
|
+
npx speclock report
|
|
128
|
+
npx speclock hook install
|
|
129
|
+
npx speclock audit
|
|
116
130
|
npx speclock status
|
|
117
131
|
`);
|
|
118
132
|
}
|
|
@@ -190,11 +204,21 @@ async function main() {
|
|
|
190
204
|
console.log("Injected SpecLock marker into package.json.");
|
|
191
205
|
}
|
|
192
206
|
|
|
193
|
-
// 5.
|
|
207
|
+
// 5. Apply template if specified
|
|
208
|
+
if (flags.template) {
|
|
209
|
+
const result = applyTemplate(root, flags.template);
|
|
210
|
+
if (result.applied) {
|
|
211
|
+
console.log(`Applied template "${result.displayName}": ${result.locksAdded} lock(s), ${result.decisionsAdded} decision(s).`);
|
|
212
|
+
} else {
|
|
213
|
+
console.error(`Template error: ${result.error}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 6. Generate context
|
|
194
218
|
generateContext(root);
|
|
195
219
|
console.log("Generated .speclock/context/latest.md");
|
|
196
220
|
|
|
197
|
-
//
|
|
221
|
+
// 7. Print summary
|
|
198
222
|
console.log(`
|
|
199
223
|
SpecLock is ready!
|
|
200
224
|
|
|
@@ -355,8 +379,8 @@ Tip: When starting a new chat, tell the AI:
|
|
|
355
379
|
console.log(`\nCONFLICT DETECTED`);
|
|
356
380
|
console.log("=".repeat(50));
|
|
357
381
|
for (const lock of result.conflictingLocks) {
|
|
358
|
-
console.log(` [${lock.
|
|
359
|
-
console.log(` Confidence: ${lock.
|
|
382
|
+
console.log(` [${lock.level}] "${lock.text}"`);
|
|
383
|
+
console.log(` Confidence: ${lock.confidence}%`);
|
|
360
384
|
if (lock.reasons && lock.reasons.length > 0) {
|
|
361
385
|
for (const reason of lock.reasons) {
|
|
362
386
|
console.log(` - ${reason}`);
|
|
@@ -460,6 +484,119 @@ Tip: When starting a new chat, tell the AI:
|
|
|
460
484
|
return;
|
|
461
485
|
}
|
|
462
486
|
|
|
487
|
+
// --- TEMPLATE ---
|
|
488
|
+
if (cmd === "template") {
|
|
489
|
+
const sub = args[0];
|
|
490
|
+
if (sub === "list" || !sub) {
|
|
491
|
+
const templates = listTemplates();
|
|
492
|
+
console.log("\nAvailable Templates:");
|
|
493
|
+
console.log("=".repeat(50));
|
|
494
|
+
for (const t of templates) {
|
|
495
|
+
console.log(` ${t.name.padEnd(20)} ${t.displayName} — ${t.description}`);
|
|
496
|
+
console.log(` ${"".padEnd(20)} ${t.lockCount} lock(s), ${t.decisionCount} decision(s)`);
|
|
497
|
+
console.log("");
|
|
498
|
+
}
|
|
499
|
+
console.log("Apply: npx speclock template apply <name>");
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (sub === "apply") {
|
|
503
|
+
const name = args[1];
|
|
504
|
+
if (!name) {
|
|
505
|
+
console.error("Error: Template name is required.");
|
|
506
|
+
console.error("Usage: speclock template apply <name>");
|
|
507
|
+
console.error("Run 'speclock template list' to see available templates.");
|
|
508
|
+
process.exit(1);
|
|
509
|
+
}
|
|
510
|
+
const result = applyTemplate(root, name);
|
|
511
|
+
if (result.applied) {
|
|
512
|
+
refreshContext(root);
|
|
513
|
+
console.log(`Template "${result.displayName}" applied successfully!`);
|
|
514
|
+
console.log(` Locks added: ${result.locksAdded}`);
|
|
515
|
+
console.log(` Decisions added: ${result.decisionsAdded}`);
|
|
516
|
+
} else {
|
|
517
|
+
console.error(result.error);
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
console.error(`Unknown template command: ${sub}`);
|
|
523
|
+
console.error("Usage: speclock template list | speclock template apply <name>");
|
|
524
|
+
process.exit(1);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// --- REPORT ---
|
|
528
|
+
if (cmd === "report") {
|
|
529
|
+
const report = generateReport(root);
|
|
530
|
+
console.log("\nSpecLock Violation Report");
|
|
531
|
+
console.log("=".repeat(50));
|
|
532
|
+
console.log(`Total violations blocked: ${report.totalViolations}`);
|
|
533
|
+
if (report.timeRange) {
|
|
534
|
+
console.log(`Period: ${report.timeRange.from.substring(0, 10)} to ${report.timeRange.to.substring(0, 10)}`);
|
|
535
|
+
}
|
|
536
|
+
if (report.mostTestedLocks.length > 0) {
|
|
537
|
+
console.log("\nMost tested locks:");
|
|
538
|
+
for (const lock of report.mostTestedLocks) {
|
|
539
|
+
console.log(` ${lock.count}x — "${lock.text}"`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (report.recentViolations.length > 0) {
|
|
543
|
+
console.log("\nRecent violations:");
|
|
544
|
+
for (const v of report.recentViolations) {
|
|
545
|
+
console.log(` [${v.at.substring(0, 19)}] ${v.topLevel} (${v.topConfidence}%) — "${v.action.substring(0, 60)}"`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
console.log(`\n${report.summary}`);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// --- HOOK ---
|
|
553
|
+
if (cmd === "hook") {
|
|
554
|
+
const sub = args[0];
|
|
555
|
+
if (sub === "install") {
|
|
556
|
+
const result = installHook(root);
|
|
557
|
+
if (result.success) {
|
|
558
|
+
console.log(result.message);
|
|
559
|
+
} else {
|
|
560
|
+
console.error(result.error);
|
|
561
|
+
process.exit(1);
|
|
562
|
+
}
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
if (sub === "remove") {
|
|
566
|
+
const result = removeHook(root);
|
|
567
|
+
if (result.success) {
|
|
568
|
+
console.log(result.message);
|
|
569
|
+
} else {
|
|
570
|
+
console.error(result.error);
|
|
571
|
+
process.exit(1);
|
|
572
|
+
}
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
console.error("Usage: speclock hook install | speclock hook remove");
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// --- AUDIT ---
|
|
580
|
+
if (cmd === "audit") {
|
|
581
|
+
const result = auditStagedFiles(root);
|
|
582
|
+
if (result.passed) {
|
|
583
|
+
console.log(result.message);
|
|
584
|
+
process.exit(0);
|
|
585
|
+
} else {
|
|
586
|
+
console.log("\nSPECLOCK AUDIT FAILED");
|
|
587
|
+
console.log("=".repeat(50));
|
|
588
|
+
for (const v of result.violations) {
|
|
589
|
+
console.log(` [${v.severity}] ${v.file}`);
|
|
590
|
+
console.log(` Lock: ${v.lockText}`);
|
|
591
|
+
console.log(` Reason: ${v.reason}`);
|
|
592
|
+
console.log("");
|
|
593
|
+
}
|
|
594
|
+
console.log(result.message);
|
|
595
|
+
console.log("Commit blocked. Unlock files or unstage them to proceed.");
|
|
596
|
+
process.exit(1);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
463
600
|
// --- STATUS ---
|
|
464
601
|
if (cmd === "status") {
|
|
465
602
|
showStatus(root);
|