speclock 1.3.1 → 1.4.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 +128 -205
- package/package.json +2 -2
- package/src/cli/index.js +46 -1
- package/src/core/engine.js +109 -16
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# SpecLock
|
|
2
2
|
|
|
3
|
-
**AI
|
|
3
|
+
**AI Constraint Engine** — Memory + enforcement for AI coding tools. The only solution that makes your AI **respect boundaries**, not just remember things.
|
|
4
4
|
|
|
5
5
|
> Developed by **Sandeep Roy** ([github.com/sgroy10](https://github.com/sgroy10))
|
|
6
6
|
|
|
7
|
+
**Website**: [sgroy10.github.io/speclock](https://sgroy10.github.io/speclock/) | **npm**: [npmjs.com/package/speclock](https://www.npmjs.com/package/speclock) | **Smithery**: [smithery.ai/servers/sgroy10/speclock](https://smithery.ai/servers/sgroy10/speclock)
|
|
8
|
+
|
|
7
9
|
[](https://www.npmjs.com/package/speclock)
|
|
8
10
|
[](https://opensource.org/licenses/MIT)
|
|
9
11
|
[](https://modelcontextprotocol.io)
|
|
@@ -13,73 +15,78 @@
|
|
|
13
15
|
|
|
14
16
|
## The Problem
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
AI tools now have memory. Claude Code has auto-memory. Cursor has Memory Bank. Mem0 exists.
|
|
19
|
+
|
|
20
|
+
**But memory without enforcement is dangerous.**
|
|
17
21
|
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
+
- Your AI remembers you use PostgreSQL — then switches to MongoDB because it "seemed better"
|
|
23
|
+
- Your AI remembers your auth setup — then rewrites it while "fixing" a bug
|
|
24
|
+
- Your AI remembers your constraints — then ignores them when they're inconvenient
|
|
25
|
+
- You said "never touch auth files" 3 sessions ago — the AI doesn't care
|
|
22
26
|
|
|
23
|
-
**
|
|
27
|
+
**Remembering is not the same as respecting.** AI tools need guardrails, not just memory.
|
|
24
28
|
|
|
25
29
|
## The Solution
|
|
26
30
|
|
|
27
|
-
SpecLock
|
|
31
|
+
SpecLock adds **active constraint enforcement** on top of persistent memory. When your AI tries to break something you locked, SpecLock **stops it before the damage is done**.
|
|
28
32
|
|
|
29
33
|
```
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
├── events.log # Append-only event ledger (JSONL)
|
|
33
|
-
├── patches/ # Git diffs captured per event
|
|
34
|
-
└── context/
|
|
35
|
-
└── latest.md # Always-fresh context pack for any AI agent
|
|
36
|
-
```
|
|
34
|
+
You: "Don't ever touch the auth files"
|
|
35
|
+
AI: 🔒 Locked: "Never modify auth files"
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
... 5 sessions later ...
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
You: "Add social login to the login page"
|
|
40
|
+
AI: ⚠️ CONFLICT: This violates your lock "Never modify auth files"
|
|
41
|
+
Should I proceed or find another approach?
|
|
42
|
+
```
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
No other tool does this. Not Claude's native memory. Not Mem0. Not CLAUDE.md files.
|
|
43
45
|
|
|
44
|
-
##
|
|
46
|
+
## How SpecLock Is Different
|
|
45
47
|
|
|
46
|
-
| Feature |
|
|
47
|
-
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
48
|
+
| Feature | Claude Native Memory | Mem0 | CLAUDE.md / .cursorrules | **SpecLock** |
|
|
49
|
+
|---------|---------------------|------|--------------------------|--------------|
|
|
50
|
+
| Remembers context | Yes | Yes | Manual | **Yes** |
|
|
51
|
+
| **Stops the AI from breaking things** | No | No | No | **Yes — active enforcement** |
|
|
52
|
+
| **Semantic conflict detection** | No | No | No | **Yes — synonym + negation analysis** |
|
|
53
|
+
| Works on Bolt.new | No | No | No | **Yes — npm file-based mode** |
|
|
54
|
+
| Works on Lovable | No | No | No | **Yes — MCP remote** |
|
|
55
|
+
| Structured decisions/locks | No | Tags only | Flat text | **Goals, locks, decisions, changes** |
|
|
56
|
+
| Git-aware (checkpoints, rollback) | No | No | No | **Yes** |
|
|
57
|
+
| Drift detection | No | No | No | **Yes — scans changes against locks** |
|
|
58
|
+
| Multi-agent timeline | No | No | No | **Yes** |
|
|
59
|
+
| Cross-platform | Claude only | MCP only | Tool-specific | **Universal (MCP + npm)** |
|
|
56
60
|
|
|
57
61
|
**Other tools remember. SpecLock enforces.**
|
|
58
62
|
|
|
59
63
|
## Quick Start
|
|
60
64
|
|
|
61
|
-
###
|
|
65
|
+
### Bolt.new / Aider / Any npm Platform (No MCP Needed)
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
Just tell the AI:
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
```
|
|
70
|
+
"Install speclock and set up project memory"
|
|
71
|
+
```
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
Or run it yourself:
|
|
70
74
|
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
"mcpServers": {
|
|
74
|
-
"speclock": {
|
|
75
|
-
"command": "npx",
|
|
76
|
-
"args": ["-y", "speclock", "serve", "--project", "."]
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
75
|
+
```bash
|
|
76
|
+
npx speclock setup --goal "Build my app"
|
|
80
77
|
```
|
|
81
78
|
|
|
82
|
-
**
|
|
79
|
+
**That's it.** The AI reads `SPECLOCK.md`, follows the rules, and uses CLI commands. Tested on Bolt.new — the AI ran 17 commands automatically on first install, setting up goals, locks, and decisions without any configuration.
|
|
80
|
+
|
|
81
|
+
### Lovable (MCP Remote — No Install)
|
|
82
|
+
|
|
83
|
+
1. Go to **Settings → Connectors → Personal connectors → New MCP server**
|
|
84
|
+
2. Enter URL: `https://speclock-mcp-production.up.railway.app/mcp` — No auth
|
|
85
|
+
3. Paste [Project Instructions](#project-instructions) into Knowledge
|
|
86
|
+
|
|
87
|
+
### Claude Code (MCP Local)
|
|
88
|
+
|
|
89
|
+
Add to `.claude/settings.json` or `.mcp.json`:
|
|
83
90
|
|
|
84
91
|
```json
|
|
85
92
|
{
|
|
@@ -92,104 +99,85 @@ The MCP server gives the AI tools for memory and constraint checking. The projec
|
|
|
92
99
|
}
|
|
93
100
|
```
|
|
94
101
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
**Bolt.new / Aider / Any platform with npm** (NEW in v1.3.0):
|
|
98
|
-
|
|
99
|
-
No MCP needed. Just tell the AI:
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
"Install speclock and set up project memory"
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Or run it yourself:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
npx speclock setup --goal "Build my app"
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
This creates:
|
|
112
|
-
- `SPECLOCK.md` — AI rules file (the AI reads this automatically)
|
|
113
|
-
- `.speclock/brain.json` — Project memory
|
|
114
|
-
- `.speclock/context/latest.md` — Context file for the AI
|
|
115
|
-
|
|
116
|
-
**That's it.** The AI reads `SPECLOCK.md`, follows the rules, and uses CLI commands (`npx speclock lock "..."`, `npx speclock check "..."`, etc.) instead of MCP tools. Tested and working on Bolt.new — the AI ran 17 commands automatically on first install.
|
|
117
|
-
|
|
118
|
-
### 2. Add Project Instructions (Required for MCP platforms)
|
|
119
|
-
|
|
120
|
-
> **This is the critical step.** Without project instructions, the AI has the tools but won't use them automatically. With them, SpecLock becomes an active guardrail.
|
|
102
|
+
### Cursor / Windsurf / Cline
|
|
121
103
|
|
|
122
|
-
|
|
104
|
+
Same MCP config as Claude Code. Add to `.cursor/mcp.json` or equivalent.
|
|
123
105
|
|
|
124
|
-
|
|
125
|
-
|----------|----------------|
|
|
126
|
-
| **Lovable** | Project Settings → Knowledge |
|
|
127
|
-
| **Cursor** | `.cursorrules` file in project root |
|
|
128
|
-
| **Claude Code** | `CLAUDE.md` file in project root |
|
|
129
|
-
| **Windsurf** | `.windsurfrules` file in project root |
|
|
106
|
+
### Project Instructions
|
|
130
107
|
|
|
131
|
-
|
|
108
|
+
For MCP platforms, paste these rules into your platform's instruction settings (Lovable Knowledge, .cursorrules, CLAUDE.md, etc.):
|
|
132
109
|
|
|
133
110
|
```
|
|
134
111
|
## SpecLock Rules (MANDATORY — follow on every message)
|
|
135
112
|
|
|
136
|
-
1. START
|
|
137
|
-
|
|
138
|
-
|
|
113
|
+
1. START: Call speclock_session_briefing FIRST. Show: "🔒 Memory loaded — X locks, Y decisions."
|
|
114
|
+
2. BEFORE CHANGES: Call speclock_check_conflict. If HIGH conflict, STOP and warn.
|
|
115
|
+
3. LOCK: When user says "never/always/don't touch" → call speclock_add_lock immediately.
|
|
116
|
+
4. AFTER FEATURES: Call speclock_log_change with summary + files affected.
|
|
117
|
+
5. UNLOCK: When user wants to change something locked → warn first, only proceed on confirm.
|
|
118
|
+
6. END: Call speclock_session_summary with what was accomplished.
|
|
119
|
+
```
|
|
139
120
|
|
|
140
|
-
|
|
121
|
+
See [SPECLOCK-INSTRUCTIONS.md](SPECLOCK-INSTRUCTIONS.md) for platform-specific versions.
|
|
141
122
|
|
|
142
|
-
|
|
123
|
+
## What It Looks Like In Practice
|
|
143
124
|
|
|
144
|
-
|
|
125
|
+
### Bolt.new — Session 1 (Setup)
|
|
126
|
+
```
|
|
127
|
+
User: "Install speclock and set up memory for my SaaS"
|
|
145
128
|
|
|
146
|
-
|
|
129
|
+
Bolt: ✓ Ran npx speclock setup
|
|
130
|
+
✓ Set goal: "Build B2B SaaS API"
|
|
131
|
+
✓ Added 6 locks (auth, security, rate limiting...)
|
|
132
|
+
✓ Recorded 7 decisions (Supabase, Stripe, Gemini...)
|
|
133
|
+
✓ Context file generated — project memory active
|
|
147
134
|
```
|
|
148
135
|
|
|
149
|
-
|
|
136
|
+
### Bolt.new — Session 2 (Full Memory)
|
|
137
|
+
```
|
|
138
|
+
User: "Create a plan for the API endpoints"
|
|
150
139
|
|
|
151
|
-
|
|
140
|
+
Bolt: ✓ Read project context (6 locks, 7 decisions)
|
|
141
|
+
✓ Created 10-phase plan respecting ALL constraints
|
|
142
|
+
✓ All plans use Supabase (locked), Bearer auth (locked)
|
|
143
|
+
✓ Logged planning phase back to SpecLock
|
|
144
|
+
```
|
|
152
145
|
|
|
153
|
-
|
|
146
|
+
### Any Platform — Constraint Enforcement
|
|
147
|
+
```
|
|
148
|
+
You: "Add social login to the login page"
|
|
149
|
+
AI: ⚠️ CONFLICT (HIGH — 100%): Violates lock "Never modify auth files"
|
|
150
|
+
Reasons:
|
|
151
|
+
- Direct keyword match: auth
|
|
152
|
+
- Synonym match: security, authentication
|
|
153
|
+
- Lock prohibits this action (negation detected)
|
|
154
|
+
|
|
155
|
+
Should I proceed or find another approach?
|
|
156
|
+
```
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
2. **During work**: AI auto-captures decisions, logs changes, checks constraints before modifying code
|
|
157
|
-
3. **Constraint protection**: If the AI tries to break something you locked, it stops and warns you
|
|
158
|
-
4. **Every session ends**: AI records what was accomplished
|
|
159
|
-
5. **Next session**: Full continuity — the AI remembers everything from all previous sessions
|
|
158
|
+
## Killer Feature: Semantic Conflict Detection
|
|
160
159
|
|
|
161
|
-
|
|
160
|
+
Not just keyword matching. SpecLock uses **synonym expansion** (15 groups), **negation detection**, and **destructive action flagging**:
|
|
162
161
|
|
|
163
|
-
### You lock something important:
|
|
164
|
-
```
|
|
165
|
-
You: "Don't ever touch the auth files"
|
|
166
|
-
AI: 🔒 Locked: "Never modify auth files"
|
|
167
162
|
```
|
|
163
|
+
Lock: "No breaking changes to public API"
|
|
164
|
+
Action: "Remove the external endpoints"
|
|
168
165
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
Should I proceed anyway, or find another approach?
|
|
166
|
+
Result: [HIGH] Conflict detected (confidence: 85%)
|
|
167
|
+
- synonym match: remove/delete, external/public, endpoints/api
|
|
168
|
+
- lock prohibits this action (negation detected)
|
|
169
|
+
- destructive action against locked constraint
|
|
174
170
|
```
|
|
175
171
|
|
|
176
|
-
|
|
177
|
-
```
|
|
178
|
-
You: "Let's keep working on the dashboard"
|
|
179
|
-
AI: 🔒 Memory loaded — 5 locks, 3 decisions, 2 sessions tracked.
|
|
180
|
-
Last session you added the payment page and locked the auth files.
|
|
181
|
-
Ready to work on the dashboard.
|
|
182
|
-
```
|
|
172
|
+
## Three Integration Modes
|
|
183
173
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
AI: 🔓 Unlocked. Proceeding with auth file changes.
|
|
190
|
-
```
|
|
174
|
+
| Mode | Platforms | How It Works |
|
|
175
|
+
|------|-----------|--------------|
|
|
176
|
+
| **MCP Remote** | Lovable, bolt.diy, Base44 | Connect via URL — no install needed |
|
|
177
|
+
| **MCP Local** | Claude Code, Cursor, Windsurf, Cline | `npx speclock serve` — 19 tools via MCP |
|
|
178
|
+
| **npm File-Based** | Bolt.new, Aider, Rocket.new | `npx speclock setup` — AI reads SPECLOCK.md + uses CLI |
|
|
191
179
|
|
|
192
|
-
## MCP Tools
|
|
180
|
+
## 19 MCP Tools
|
|
193
181
|
|
|
194
182
|
### Memory Management
|
|
195
183
|
| Tool | Purpose |
|
|
@@ -206,11 +194,11 @@ AI: 🔓 Unlocked. Proceeding with auth file changes.
|
|
|
206
194
|
### Change Tracking
|
|
207
195
|
| Tool | Purpose |
|
|
208
196
|
|------|---------|
|
|
209
|
-
| `speclock_log_change` |
|
|
197
|
+
| `speclock_log_change` | Log a significant change |
|
|
210
198
|
| `speclock_get_changes` | Get recent tracked changes |
|
|
211
|
-
| `speclock_get_events` | Get event log (filterable
|
|
199
|
+
| `speclock_get_events` | Get event log (filterable) |
|
|
212
200
|
|
|
213
|
-
###
|
|
201
|
+
### Enforcement & Protection
|
|
214
202
|
| Tool | Purpose |
|
|
215
203
|
|------|---------|
|
|
216
204
|
| `speclock_check_conflict` | Check action against locks (semantic matching) |
|
|
@@ -230,97 +218,32 @@ AI: 🔓 Unlocked. Proceeding with auth file changes.
|
|
|
230
218
|
| `speclock_detect_drift` | Scan changes for constraint violations |
|
|
231
219
|
| `speclock_health` | Health score + multi-agent timeline |
|
|
232
220
|
|
|
233
|
-
## Killer Features
|
|
234
|
-
|
|
235
|
-
### Semantic Conflict Detection
|
|
236
|
-
|
|
237
|
-
Not just keyword matching — SpecLock understands synonyms, negation, and destructive intent:
|
|
238
|
-
|
|
239
|
-
```
|
|
240
|
-
Lock: "No breaking changes to public API"
|
|
241
|
-
|
|
242
|
-
Action: "remove the external endpoints"
|
|
243
|
-
Result: [HIGH] Conflict detected (confidence: 85%)
|
|
244
|
-
- synonym match: remove/delete, external/public, endpoints/api
|
|
245
|
-
- lock prohibits this action (negation detected)
|
|
246
|
-
- destructive action against locked constraint
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### Auto-Lock Suggestions
|
|
250
|
-
|
|
251
|
-
SpecLock analyzes your decisions and notes for commitment language and suggests constraints:
|
|
252
|
-
|
|
253
|
-
```
|
|
254
|
-
Decision: "Always use REST for public endpoints"
|
|
255
|
-
→ Suggestion: Promote to lock (contains "always" — strong commitment language)
|
|
256
|
-
|
|
257
|
-
Project mentions "security" but has no security lock
|
|
258
|
-
→ Suggestion: "No secrets or credentials in source code"
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
### Drift Detection
|
|
262
|
-
|
|
263
|
-
Proactively scans recent changes against your locks:
|
|
264
|
-
|
|
265
|
-
```
|
|
266
|
-
Lock: "No database schema changes without migration"
|
|
267
|
-
Change: "Modified users table schema directly"
|
|
268
|
-
→ [HIGH] Drift detected — review immediately
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Multi-Agent Timeline
|
|
272
|
-
|
|
273
|
-
Track which AI tools touched your project and what they did:
|
|
274
|
-
|
|
275
|
-
```
|
|
276
|
-
Health Check — Score: 85/100 (Grade: A)
|
|
277
|
-
|
|
278
|
-
Multi-Agent Timeline:
|
|
279
|
-
- claude-code: 12 sessions, last active 2026-02-24
|
|
280
|
-
- cursor: 5 sessions, last active 2026-02-23
|
|
281
|
-
- codex: 2 sessions, last active 2026-02-20
|
|
282
|
-
```
|
|
283
|
-
|
|
284
221
|
## CLI Commands
|
|
285
222
|
|
|
286
223
|
```bash
|
|
287
|
-
# Setup
|
|
288
|
-
speclock setup --goal "Build my app"
|
|
224
|
+
# Setup
|
|
225
|
+
speclock setup --goal "Build my app" # One-shot: init + rules + context
|
|
289
226
|
|
|
290
|
-
# Memory
|
|
291
|
-
speclock
|
|
292
|
-
speclock
|
|
293
|
-
speclock lock <
|
|
294
|
-
speclock
|
|
295
|
-
speclock
|
|
296
|
-
speclock note <text> Add a note
|
|
227
|
+
# Memory
|
|
228
|
+
speclock goal <text> # Set project goal
|
|
229
|
+
speclock lock <text> [--tags a,b] # Add a constraint
|
|
230
|
+
speclock lock remove <id> # Remove a lock
|
|
231
|
+
speclock decide <text> # Record a decision
|
|
232
|
+
speclock note <text> # Add a note
|
|
297
233
|
|
|
298
|
-
#
|
|
299
|
-
speclock log-change <text> --files x Log a
|
|
300
|
-
speclock context
|
|
234
|
+
# Tracking
|
|
235
|
+
speclock log-change <text> --files x # Log a change
|
|
236
|
+
speclock context # Regenerate context file
|
|
301
237
|
|
|
302
|
-
#
|
|
303
|
-
speclock check <text> Check for lock conflicts
|
|
238
|
+
# Enforcement
|
|
239
|
+
speclock check <text> # Check for lock conflicts
|
|
304
240
|
|
|
305
241
|
# Other
|
|
306
|
-
speclock
|
|
307
|
-
speclock
|
|
308
|
-
speclock
|
|
309
|
-
speclock status Show brain summary
|
|
242
|
+
speclock status # Show brain summary
|
|
243
|
+
speclock serve [--project <path>] # Start MCP server
|
|
244
|
+
speclock watch # Start file watcher
|
|
310
245
|
```
|
|
311
246
|
|
|
312
|
-
## Three Integration Modes
|
|
313
|
-
|
|
314
|
-
SpecLock works everywhere because it adapts to your platform:
|
|
315
|
-
|
|
316
|
-
| Mode | Platforms | How It Works |
|
|
317
|
-
|------|-----------|--------------|
|
|
318
|
-
| **MCP Remote** | Lovable, bolt.diy, Base44 | Connect via URL — no install needed |
|
|
319
|
-
| **MCP Local** | Claude Code, Cursor, Windsurf, Cline | `npx speclock serve` — 19 tools via MCP |
|
|
320
|
-
| **npm File-Based** | Bolt.new, Aider, Rocket.new | `npx speclock setup` — AI reads SPECLOCK.md + uses CLI |
|
|
321
|
-
|
|
322
|
-
SpecLock is infrastructure, not a competitor. It makes **every** AI coding tool better.
|
|
323
|
-
|
|
324
247
|
## Architecture
|
|
325
248
|
|
|
326
249
|
```
|
|
@@ -335,7 +258,7 @@ SpecLock is infrastructure, not a competitor. It makes **every** AI coding tool
|
|
|
335
258
|
│ │
|
|
336
259
|
┌──────────────▼──────────────────▼────────────────────┐
|
|
337
260
|
│ SpecLock Core Engine │
|
|
338
|
-
│ Memory | Tracking |
|
|
261
|
+
│ Memory | Tracking | Enforcement | Git | Intelligence│
|
|
339
262
|
└──────────────────────┬───────────────────────────────┘
|
|
340
263
|
│
|
|
341
264
|
.speclock/
|
|
@@ -364,4 +287,4 @@ MIT License - see [LICENSE](LICENSE) file.
|
|
|
364
287
|
|
|
365
288
|
---
|
|
366
289
|
|
|
367
|
-
*SpecLock v1.3.
|
|
290
|
+
*SpecLock v1.3.1 — 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": "1.
|
|
4
|
-
"description": "AI
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "AI constraint engine — MCP server + CLI with active enforcement. Memory + guardrails for AI coding tools. Works with 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
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
checkConflict,
|
|
12
12
|
watchRepo,
|
|
13
13
|
createSpecLockMd,
|
|
14
|
+
guardFile,
|
|
15
|
+
unguardFile,
|
|
14
16
|
} from "../core/engine.js";
|
|
15
17
|
import { generateContext } from "../core/context.js";
|
|
16
18
|
import { readBrain } from "../core/storage.js";
|
|
@@ -69,7 +71,7 @@ function refreshContext(root) {
|
|
|
69
71
|
|
|
70
72
|
function printHelp() {
|
|
71
73
|
console.log(`
|
|
72
|
-
SpecLock v1.
|
|
74
|
+
SpecLock v1.4.0 — AI Constraint Engine
|
|
73
75
|
Developed by Sandeep Roy (github.com/sgroy10)
|
|
74
76
|
|
|
75
77
|
Usage: speclock <command> [options]
|
|
@@ -80,6 +82,8 @@ Commands:
|
|
|
80
82
|
goal <text> Set or update the project goal
|
|
81
83
|
lock <text> [--tags a,b] Add a non-negotiable constraint
|
|
82
84
|
lock remove <id> Remove a lock by ID
|
|
85
|
+
guard <file> [--lock "text"] Inject lock warning into a file (NEW)
|
|
86
|
+
unguard <file> Remove lock warning from a file (NEW)
|
|
83
87
|
decide <text> [--tags a,b] Record a decision
|
|
84
88
|
note <text> [--pinned] Add a pinned note
|
|
85
89
|
log-change <text> [--files x,y] Log a significant change
|
|
@@ -95,11 +99,13 @@ Options:
|
|
|
95
99
|
--source <user|agent> Who created this (default: user)
|
|
96
100
|
--files <a.ts,b.ts> Comma-separated file paths
|
|
97
101
|
--goal <text> Goal text (for setup command)
|
|
102
|
+
--lock <text> Lock text (for guard command)
|
|
98
103
|
--project <path> Project root (for serve)
|
|
99
104
|
|
|
100
105
|
Examples:
|
|
101
106
|
npx speclock setup --goal "Build PawPalace pet shop"
|
|
102
107
|
npx speclock lock "Never modify auth files"
|
|
108
|
+
npx speclock guard src/Auth.tsx --lock "Never modify auth files"
|
|
103
109
|
npx speclock check "Adding social login to auth page"
|
|
104
110
|
npx speclock log-change "Built payment system" --files src/pay.tsx
|
|
105
111
|
npx speclock decide "Use Supabase for auth"
|
|
@@ -336,6 +342,45 @@ Next steps:
|
|
|
336
342
|
return;
|
|
337
343
|
}
|
|
338
344
|
|
|
345
|
+
// --- GUARD (new: file-level lock) ---
|
|
346
|
+
if (cmd === "guard") {
|
|
347
|
+
const flags = parseFlags(args);
|
|
348
|
+
const filePath = flags._[0];
|
|
349
|
+
if (!filePath) {
|
|
350
|
+
console.error("Error: File path is required.");
|
|
351
|
+
console.error('Usage: speclock guard <file> --lock "constraint text"');
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
354
|
+
const lockText = flags.lock || "This file is locked by SpecLock. Do not modify.";
|
|
355
|
+
const result = guardFile(root, filePath, lockText);
|
|
356
|
+
if (result.success) {
|
|
357
|
+
console.log(`Guarded: ${filePath}`);
|
|
358
|
+
console.log(`Lock warning injected: "${lockText}"`);
|
|
359
|
+
} else {
|
|
360
|
+
console.error(result.error);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// --- UNGUARD ---
|
|
367
|
+
if (cmd === "unguard") {
|
|
368
|
+
const filePath = args[0];
|
|
369
|
+
if (!filePath) {
|
|
370
|
+
console.error("Error: File path is required.");
|
|
371
|
+
console.error("Usage: speclock unguard <file>");
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
const result = unguardFile(root, filePath);
|
|
375
|
+
if (result.success) {
|
|
376
|
+
console.log(`Unguarded: ${filePath}`);
|
|
377
|
+
} else {
|
|
378
|
+
console.error(result.error);
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
|
|
339
384
|
// --- FACTS ---
|
|
340
385
|
if (cmd === "facts") {
|
|
341
386
|
const sub = args.shift();
|
package/src/core/engine.js
CHANGED
|
@@ -700,37 +700,45 @@ export async function watchRepo(root) {
|
|
|
700
700
|
// --- SPECLOCK.md generator (for npm dependency / file-based mode) ---
|
|
701
701
|
|
|
702
702
|
export function createSpecLockMd(root) {
|
|
703
|
-
const mdContent = `# SpecLock —
|
|
703
|
+
const mdContent = `# SpecLock — AI Constraint Engine Active
|
|
704
704
|
|
|
705
|
-
|
|
706
|
-
Read \`.speclock/context/latest.md\` for full project context before making changes.
|
|
705
|
+
## MANDATORY: Read this BEFORE doing anything.
|
|
707
706
|
|
|
708
|
-
|
|
707
|
+
This project uses **SpecLock** for AI constraint enforcement.
|
|
709
708
|
|
|
710
|
-
|
|
709
|
+
**STOP. Before writing or modifying ANY code, you MUST:**
|
|
710
|
+
1. Read \`.speclock/context/latest.md\` for project memory
|
|
711
|
+
2. Run \`npx speclock check "what you plan to change"\`
|
|
712
|
+
3. If conflict found → STOP and warn the user
|
|
711
713
|
|
|
712
|
-
|
|
714
|
+
**If a file starts with "SPECLOCK-GUARD — DO NOT MODIFY" → DO NOT EDIT IT.**
|
|
713
715
|
|
|
714
|
-
|
|
716
|
+
## Rules (MANDATORY — every message, no exceptions)
|
|
715
717
|
|
|
716
|
-
|
|
718
|
+
1. **FIRST ACTION OF EVERY MESSAGE**: Read \`.speclock/context/latest.md\`. This contains all project constraints (locks), decisions, and goals. Show: "Memory loaded — X locks, Y decisions." If the file doesn't exist, run \`npx speclock context\`.
|
|
719
|
+
|
|
720
|
+
2. **BEFORE MODIFYING ANY CODE — EVERY TIME**: Run \`npx speclock check "description of what you plan to change"\`. If a conflict is found (HIGH confidence), STOP IMMEDIATELY. Tell the user which constraint would be violated. Do NOT proceed unless the user explicitly overrides. THIS IS THE MOST IMPORTANT RULE.
|
|
721
|
+
|
|
722
|
+
3. **WHEN USER SAYS "lock this", "never touch", "don't change", "always", "critical"**: Run \`npx speclock lock "the exact constraint"\`. Then run \`npx speclock guard <file> --lock "constraint"\` on the specific files to inject a lock warning directly into the file. Confirm: "Locked: [constraint]"
|
|
723
|
+
|
|
724
|
+
4. **AFTER COMPLETING A FEATURE OR CHANGE**: Run \`npx speclock log-change "what was built" --files file1.tsx,file2.ts\`.
|
|
717
725
|
|
|
718
726
|
5. **WHEN AN ARCHITECTURAL DECISION IS MADE**: Run \`npx speclock decide "the decision"\`
|
|
719
727
|
|
|
720
|
-
6. **WHEN USER WANTS TO CHANGE SOMETHING LOCKED**: Warn first
|
|
728
|
+
6. **WHEN USER WANTS TO CHANGE SOMETHING LOCKED**: Warn first. If confirmed, run \`npx speclock lock remove <lockId>\` and \`npx speclock unguard <file>\` to remove the file guard.
|
|
721
729
|
|
|
722
730
|
## Quick Reference
|
|
723
731
|
|
|
724
732
|
\`\`\`bash
|
|
725
|
-
npx speclock
|
|
726
|
-
npx speclock context # Regenerate context file
|
|
733
|
+
npx speclock check "what you plan to do" # CHECK BEFORE CHANGES
|
|
727
734
|
npx speclock lock "constraint text" # Add a constraint
|
|
735
|
+
npx speclock guard src/Auth.tsx --lock "text" # Inject lock into file
|
|
736
|
+
npx speclock unguard src/Auth.tsx # Remove file lock
|
|
728
737
|
npx speclock lock remove <lockId> # Remove a constraint
|
|
729
|
-
npx speclock decide "decision text" # Record a decision
|
|
730
738
|
npx speclock log-change "what changed" # Log a change
|
|
731
|
-
npx speclock
|
|
732
|
-
npx speclock
|
|
733
|
-
npx speclock
|
|
739
|
+
npx speclock decide "decision text" # Record a decision
|
|
740
|
+
npx speclock context # Regenerate context file
|
|
741
|
+
npx speclock status # See brain summary
|
|
734
742
|
\`\`\`
|
|
735
743
|
|
|
736
744
|
## How It Works
|
|
@@ -740,9 +748,94 @@ SpecLock maintains a \`.speclock/\` directory with structured project memory:
|
|
|
740
748
|
- \`events.log\` — immutable audit trail
|
|
741
749
|
- \`context/latest.md\` — human-readable context (read this!)
|
|
742
750
|
|
|
743
|
-
|
|
751
|
+
**Guarded files** have a lock warning header injected directly into the source code.
|
|
752
|
+
When you see "SPECLOCK-GUARD" at the top of a file, that file is LOCKED.
|
|
744
753
|
`;
|
|
745
754
|
const filePath = path.join(root, "SPECLOCK.md");
|
|
746
755
|
fs.writeFileSync(filePath, mdContent);
|
|
747
756
|
return filePath;
|
|
748
757
|
}
|
|
758
|
+
|
|
759
|
+
// --- File-level lock guard ---
|
|
760
|
+
|
|
761
|
+
const GUARD_MARKERS = {
|
|
762
|
+
js: { start: "// ", block: false },
|
|
763
|
+
ts: { start: "// ", block: false },
|
|
764
|
+
jsx: { start: "// ", block: false },
|
|
765
|
+
tsx: { start: "// ", block: false },
|
|
766
|
+
py: { start: "# ", block: false },
|
|
767
|
+
rb: { start: "# ", block: false },
|
|
768
|
+
sh: { start: "# ", block: false },
|
|
769
|
+
css: { start: "/* ", end: " */", block: true },
|
|
770
|
+
html: { start: "<!-- ", end: " -->", block: true },
|
|
771
|
+
vue: { start: "<!-- ", end: " -->", block: true },
|
|
772
|
+
svelte: { start: "<!-- ", end: " -->", block: true },
|
|
773
|
+
sql: { start: "-- ", block: false },
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
const GUARD_TAG = "SPECLOCK-GUARD";
|
|
777
|
+
|
|
778
|
+
function getCommentStyle(filePath) {
|
|
779
|
+
const ext = path.extname(filePath).slice(1).toLowerCase();
|
|
780
|
+
return GUARD_MARKERS[ext] || { start: "// ", block: false };
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
export function guardFile(root, relativeFilePath, lockText) {
|
|
784
|
+
const fullPath = path.join(root, relativeFilePath);
|
|
785
|
+
if (!fs.existsSync(fullPath)) {
|
|
786
|
+
return { success: false, error: `File not found: ${relativeFilePath}` };
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
790
|
+
const style = getCommentStyle(fullPath);
|
|
791
|
+
|
|
792
|
+
// Check if already guarded
|
|
793
|
+
if (content.includes(GUARD_TAG)) {
|
|
794
|
+
return { success: false, error: `File already guarded: ${relativeFilePath}` };
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
const warningLines = [
|
|
798
|
+
`${style.start}${"=".repeat(60)}${style.end || ""}`,
|
|
799
|
+
`${style.start}${GUARD_TAG} — DO NOT MODIFY THIS FILE${style.end || ""}`,
|
|
800
|
+
`${style.start}LOCKED BY SPECLOCK: ${lockText}${style.end || ""}`,
|
|
801
|
+
`${style.start}Run "npx speclock check" before ANY changes to this file.${style.end || ""}`,
|
|
802
|
+
`${style.start}If you modify this file, you are VIOLATING a project constraint.${style.end || ""}`,
|
|
803
|
+
`${style.start}${"=".repeat(60)}${style.end || ""}`,
|
|
804
|
+
"",
|
|
805
|
+
];
|
|
806
|
+
|
|
807
|
+
const guarded = warningLines.join("\n") + content;
|
|
808
|
+
fs.writeFileSync(fullPath, guarded);
|
|
809
|
+
|
|
810
|
+
return { success: true };
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
export function unguardFile(root, relativeFilePath) {
|
|
814
|
+
const fullPath = path.join(root, relativeFilePath);
|
|
815
|
+
if (!fs.existsSync(fullPath)) {
|
|
816
|
+
return { success: false, error: `File not found: ${relativeFilePath}` };
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
820
|
+
if (!content.includes(GUARD_TAG)) {
|
|
821
|
+
return { success: false, error: `File is not guarded: ${relativeFilePath}` };
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Remove everything from first marker line to the blank line after last marker
|
|
825
|
+
const lines = content.split("\n");
|
|
826
|
+
let guardEnd = 0;
|
|
827
|
+
let inGuard = false;
|
|
828
|
+
for (let i = 0; i < lines.length; i++) {
|
|
829
|
+
if (lines[i].includes(GUARD_TAG)) inGuard = true;
|
|
830
|
+
if (inGuard && lines[i].includes("=".repeat(60)) && i > 0) {
|
|
831
|
+
guardEnd = i + 1; // Skip the blank line after
|
|
832
|
+
if (lines[guardEnd] === "") guardEnd++;
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const unguarded = lines.slice(guardEnd).join("\n");
|
|
838
|
+
fs.writeFileSync(fullPath, unguarded);
|
|
839
|
+
|
|
840
|
+
return { success: true };
|
|
841
|
+
}
|