speclock 1.2.1 → 1.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 +66 -28
- package/SPECLOCK-INSTRUCTIONS.md +146 -0
- package/package.json +2 -1
- package/src/cli/index.js +155 -37
- package/src/core/engine.js +50 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SpecLock
|
|
2
2
|
|
|
3
|
-
**AI Continuity Engine** —
|
|
3
|
+
**AI Continuity Engine** — MCP server + npm package that kills AI amnesia. Works with Lovable, Claude Code, Cursor, Bolt.new, and more.
|
|
4
4
|
|
|
5
5
|
> Developed by **Sandeep Roy** ([github.com/sgroy10](https://github.com/sgroy10))
|
|
6
6
|
|
|
@@ -94,7 +94,28 @@ The MCP server gives the AI tools for memory and constraint checking. The projec
|
|
|
94
94
|
|
|
95
95
|
**Windsurf / Cline / Any MCP tool** — Same pattern as above.
|
|
96
96
|
|
|
97
|
-
|
|
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)
|
|
98
119
|
|
|
99
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.
|
|
100
121
|
|
|
@@ -202,7 +223,7 @@ AI: 🔓 Unlocked. Proceeding with auth file changes.
|
|
|
202
223
|
| `speclock_checkpoint` | Create named git tag for rollback |
|
|
203
224
|
| `speclock_repo_status` | Branch, commit, changed files, diff |
|
|
204
225
|
|
|
205
|
-
### Intelligence
|
|
226
|
+
### Intelligence
|
|
206
227
|
| Tool | Purpose |
|
|
207
228
|
|------|---------|
|
|
208
229
|
| `speclock_suggest_locks` | AI-powered lock suggestions from patterns |
|
|
@@ -262,50 +283,67 @@ Multi-Agent Timeline:
|
|
|
262
283
|
|
|
263
284
|
## CLI Commands
|
|
264
285
|
|
|
265
|
-
```
|
|
286
|
+
```bash
|
|
287
|
+
# Setup (NEW in v1.3.0)
|
|
288
|
+
speclock setup --goal "Build my app" Full one-shot setup (init + SPECLOCK.md + context)
|
|
289
|
+
|
|
290
|
+
# Memory Management
|
|
266
291
|
speclock init Initialize SpecLock
|
|
267
292
|
speclock goal <text> Set project goal
|
|
268
293
|
speclock lock <text> [--tags a,b] Add a SpecLock constraint
|
|
269
294
|
speclock lock remove <id> Remove a lock
|
|
270
295
|
speclock decide <text> Record a decision
|
|
271
296
|
speclock note <text> Add a note
|
|
272
|
-
|
|
297
|
+
|
|
298
|
+
# Change Tracking
|
|
299
|
+
speclock log-change <text> --files x Log a significant change (NEW in v1.3.0)
|
|
273
300
|
speclock context Generate and print context pack
|
|
301
|
+
|
|
302
|
+
# Protection
|
|
303
|
+
speclock check <text> Check for lock conflicts (NEW in v1.3.0)
|
|
304
|
+
|
|
305
|
+
# Other
|
|
306
|
+
speclock facts deploy --provider X Set deploy facts
|
|
274
307
|
speclock watch Start file watcher
|
|
275
308
|
speclock serve [--project <path>] Start MCP server
|
|
276
309
|
speclock status Show brain summary
|
|
277
310
|
```
|
|
278
311
|
|
|
279
|
-
##
|
|
312
|
+
## Three Integration Modes
|
|
280
313
|
|
|
281
|
-
|
|
314
|
+
SpecLock works everywhere because it adapts to your platform:
|
|
282
315
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
-
|
|
288
|
-
- Any MCP-compatible tool
|
|
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 |
|
|
289
321
|
|
|
290
322
|
SpecLock is infrastructure, not a competitor. It makes **every** AI coding tool better.
|
|
291
323
|
|
|
292
324
|
## Architecture
|
|
293
325
|
|
|
294
326
|
```
|
|
295
|
-
|
|
296
|
-
│
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
327
|
+
┌─────────────────────────────────────────────────────┐
|
|
328
|
+
│ AI Tool (Bolt.new, Lovable, Claude Code) │
|
|
329
|
+
└──────────────┬──────────────────┬────────────────────┘
|
|
330
|
+
│ │
|
|
331
|
+
MCP Protocol File-Based (npm)
|
|
332
|
+
(19 tool calls) (reads SPECLOCK.md +
|
|
333
|
+
.speclock/context/latest.md,
|
|
334
|
+
runs CLI commands)
|
|
335
|
+
│ │
|
|
336
|
+
┌──────────────▼──────────────────▼────────────────────┐
|
|
337
|
+
│ SpecLock Core Engine │
|
|
338
|
+
│ Memory | Tracking | Protection | Git | Intelligence │
|
|
339
|
+
└──────────────────────┬───────────────────────────────┘
|
|
340
|
+
│
|
|
341
|
+
.speclock/
|
|
342
|
+
├── brain.json (structured memory)
|
|
343
|
+
├── events.log (immutable audit trail)
|
|
344
|
+
├── patches/ (git diffs per event)
|
|
345
|
+
└── context/
|
|
346
|
+
└── latest.md (human-readable context)
|
|
309
347
|
```
|
|
310
348
|
|
|
311
349
|
## Contributing
|
|
@@ -326,4 +364,4 @@ MIT License - see [LICENSE](LICENSE) file.
|
|
|
326
364
|
|
|
327
365
|
---
|
|
328
366
|
|
|
329
|
-
*SpecLock — Because no AI session should ever forget.*
|
|
367
|
+
*SpecLock v1.3.0 — Because no AI session should ever forget.*
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# SpecLock Project Instructions — Copy-Paste Templates
|
|
2
|
+
|
|
3
|
+
These are **project-level instructions** that you paste into your AI coding platform's settings. They force the AI to use SpecLock on every action — turning it from a passive notepad into an active guardrail.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## For Lovable
|
|
8
|
+
|
|
9
|
+
Go to **Project Settings → Knowledge** and paste this:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
## SpecLock Rules (MANDATORY — follow on every message)
|
|
13
|
+
|
|
14
|
+
1. START OF EVERY CONVERSATION: Call speclock_session_briefing FIRST. Read all locks, decisions, and goals before doing anything else. Show a brief summary: "🔒 Memory loaded — X locks, Y decisions."
|
|
15
|
+
|
|
16
|
+
2. BEFORE WRITING OR MODIFYING ANY CODE: Call speclock_check_conflict with a description of what you're about to change (e.g., "Adding payment page, creating new route and components" or "Modifying the auth login flow"). If a conflict is found with HIGH confidence, STOP and tell me which lock would be violated. Do NOT proceed unless I explicitly say to override it.
|
|
17
|
+
|
|
18
|
+
3. WHEN I SAY "lock this", "never touch this", "don't ever change this", "this is critical", or similar: Immediately call speclock_add_lock with my exact constraint. Confirm with: "🔒 Locked: [constraint]"
|
|
19
|
+
|
|
20
|
+
4. AFTER COMPLETING ANY FEATURE OR SIGNIFICANT CHANGE: Call speclock_log_change with a summary of what was built/changed and which files were affected. Also call speclock_add_decision if an architectural choice was made.
|
|
21
|
+
|
|
22
|
+
5. WHEN I ASK TO REMOVE OR CHANGE SOMETHING THAT WAS LOCKED: Warn me first: "⚠️ You locked this: [constraint]. Want me to unlock it and proceed?" Only proceed if I confirm.
|
|
23
|
+
|
|
24
|
+
6. END OF CONVERSATION: Call speclock_session_summary with what was accomplished.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## For Cursor
|
|
30
|
+
|
|
31
|
+
Create or add to `.cursorrules` in your project root:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
## SpecLock Rules (MANDATORY — follow on every message)
|
|
35
|
+
|
|
36
|
+
1. START OF EVERY CONVERSATION: Call speclock_session_briefing FIRST. Read all locks, decisions, and goals before doing anything else. Show a brief summary: "🔒 Memory loaded — X locks, Y decisions."
|
|
37
|
+
|
|
38
|
+
2. BEFORE WRITING OR MODIFYING ANY CODE: Call speclock_check_conflict with a description of what you're about to change. If a conflict is found with HIGH confidence, STOP and tell me which lock would be violated. Do NOT proceed unless I explicitly say to override.
|
|
39
|
+
|
|
40
|
+
3. WHEN I SAY "lock this", "never touch this", "don't change this": Call speclock_add_lock immediately. Confirm: "🔒 Locked: [constraint]"
|
|
41
|
+
|
|
42
|
+
4. AFTER COMPLETING ANY FEATURE: Call speclock_log_change with a summary and files affected. Call speclock_add_decision if an architectural choice was made.
|
|
43
|
+
|
|
44
|
+
5. WHEN I ASK TO CHANGE SOMETHING LOCKED: Warn me: "⚠️ This is locked: [constraint]. Unlock and proceed?" Only continue if I confirm.
|
|
45
|
+
|
|
46
|
+
6. END OF SESSION: Call speclock_session_summary.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## For Claude Code
|
|
52
|
+
|
|
53
|
+
Add to `CLAUDE.md` in your project root:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
## SpecLock Rules (MANDATORY — follow on every message)
|
|
57
|
+
|
|
58
|
+
1. START OF EVERY CONVERSATION: Call speclock_session_briefing FIRST. Read all locks, decisions, and goals before doing anything else. Show: "🔒 Memory loaded — X locks, Y decisions."
|
|
59
|
+
|
|
60
|
+
2. BEFORE WRITING OR MODIFYING ANY CODE: Call speclock_check_conflict with what you're about to change. If conflict found (HIGH), STOP and warn me. Do NOT proceed unless I override.
|
|
61
|
+
|
|
62
|
+
3. WHEN I SAY "lock this", "never touch", "don't change": Call speclock_add_lock. Confirm: "🔒 Locked: [constraint]"
|
|
63
|
+
|
|
64
|
+
4. AFTER COMPLETING FEATURES: Call speclock_log_change + speclock_add_decision for architectural choices.
|
|
65
|
+
|
|
66
|
+
5. LOCKED ITEMS: Warn before changing. Only proceed if I confirm unlock.
|
|
67
|
+
|
|
68
|
+
6. END OF SESSION: Call speclock_session_summary.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## For Windsurf
|
|
74
|
+
|
|
75
|
+
Add to `.windsurfrules` in your project root:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
## SpecLock Rules (MANDATORY — follow on every message)
|
|
79
|
+
|
|
80
|
+
1. START OF EVERY CONVERSATION: Call speclock_session_briefing FIRST. Show: "🔒 Memory loaded — X locks, Y decisions."
|
|
81
|
+
|
|
82
|
+
2. BEFORE MODIFYING CODE: Call speclock_check_conflict. If HIGH conflict, STOP and warn me.
|
|
83
|
+
|
|
84
|
+
3. WHEN I SAY "lock this" / "never touch" / "don't change": Call speclock_add_lock. Confirm: "🔒 Locked: [constraint]"
|
|
85
|
+
|
|
86
|
+
4. AFTER FEATURES: Call speclock_log_change + speclock_add_decision.
|
|
87
|
+
|
|
88
|
+
5. LOCKED ITEMS: Warn before changing. Only unlock if I confirm.
|
|
89
|
+
|
|
90
|
+
6. END: Call speclock_session_summary.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## How It Works In Practice
|
|
96
|
+
|
|
97
|
+
### Example 1: User locks something
|
|
98
|
+
```
|
|
99
|
+
User: "Don't ever touch the auth files"
|
|
100
|
+
AI: 🔒 Locked: "Never modify auth files"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Example 2: AI checks before changing
|
|
104
|
+
```
|
|
105
|
+
User: "Add social login to the login page"
|
|
106
|
+
AI: *calls speclock_check_conflict("Modifying auth login page to add social login")*
|
|
107
|
+
⚠️ This conflicts with your lock: "Never modify auth files"
|
|
108
|
+
Should I proceed anyway, or find another approach?
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Example 3: New session, full memory
|
|
112
|
+
```
|
|
113
|
+
User: "Let's keep working on the dashboard"
|
|
114
|
+
AI: *calls speclock_session_briefing*
|
|
115
|
+
🔒 Memory loaded — 5 locks, 3 decisions, 2 sessions tracked.
|
|
116
|
+
Last session you added the payment page and locked the auth files.
|
|
117
|
+
Ready to work on the dashboard.
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Example 4: User changes their mind
|
|
121
|
+
```
|
|
122
|
+
User: "Actually, unlock the auth files, I need to change them"
|
|
123
|
+
AI: You locked: "Never modify auth files". Want me to unlock this?
|
|
124
|
+
User: "Yes"
|
|
125
|
+
AI: 🔓 Unlocked. Proceeding with auth file changes.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## The Complete Setup (2 minutes)
|
|
131
|
+
|
|
132
|
+
### Lovable:
|
|
133
|
+
1. Connect SpecLock: Settings → Connectors → Custom → URL: `https://speclock-mcp-production.up.railway.app/mcp` → No auth
|
|
134
|
+
2. Paste the instruction above into: Project Settings → Knowledge
|
|
135
|
+
3. Say "initialize speclock" in your first chat
|
|
136
|
+
4. Done. Every session after: AI auto-checks memory and constraints.
|
|
137
|
+
|
|
138
|
+
### Cursor:
|
|
139
|
+
1. Add to `.cursor/mcp.json`: `{"mcpServers":{"speclock":{"command":"npx","args":["-y","speclock","serve","--project","."]}}}`
|
|
140
|
+
2. Create `.cursorrules` with the instruction above
|
|
141
|
+
3. Done.
|
|
142
|
+
|
|
143
|
+
### Claude Code:
|
|
144
|
+
1. Add to `~/.claude.json` or `.mcp.json`: `{"mcpServers":{"speclock":{"command":"npx","args":["-y","speclock","serve","--project","."]}}}`
|
|
145
|
+
2. Add the instruction above to `CLAUDE.md`
|
|
146
|
+
3. Done.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "speclock",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "AI continuity engine — MCP server + CLI that kills AI amnesia. Maintains project memory, enforces constraints, and detects drift across AI coding sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/mcp/server.js",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"bin/",
|
|
55
55
|
"src/",
|
|
56
56
|
"README.md",
|
|
57
|
+
"SPECLOCK-INSTRUCTIONS.md",
|
|
57
58
|
"LICENSE"
|
|
58
59
|
],
|
|
59
60
|
"devDependencies": {
|
package/src/cli/index.js
CHANGED
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
addDecision,
|
|
8
8
|
addNote,
|
|
9
9
|
updateDeployFacts,
|
|
10
|
+
logChange,
|
|
11
|
+
checkConflict,
|
|
10
12
|
watchRepo,
|
|
13
|
+
createSpecLockMd,
|
|
11
14
|
} from "../core/engine.js";
|
|
12
15
|
import { generateContext } from "../core/context.js";
|
|
13
16
|
import { readBrain } from "../core/storage.js";
|
|
@@ -52,50 +55,56 @@ function rootDir() {
|
|
|
52
55
|
return process.cwd();
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
// --- Auto-regenerate context after write operations ---
|
|
59
|
+
|
|
60
|
+
function refreshContext(root) {
|
|
61
|
+
try {
|
|
62
|
+
generateContext(root);
|
|
63
|
+
} catch (_) {
|
|
64
|
+
// Silently skip if context generation fails
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
// --- Help text ---
|
|
56
69
|
|
|
57
70
|
function printHelp() {
|
|
58
71
|
console.log(`
|
|
59
|
-
SpecLock v1.
|
|
72
|
+
SpecLock v1.3.0 — AI Continuity Engine
|
|
60
73
|
Developed by Sandeep Roy (github.com/sgroy10)
|
|
61
74
|
|
|
62
75
|
Usage: speclock <command> [options]
|
|
63
76
|
|
|
64
77
|
Commands:
|
|
65
|
-
init
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
lock
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
setup [--goal <text>] Full setup: init + SPECLOCK.md + context
|
|
79
|
+
init Initialize SpecLock in current directory
|
|
80
|
+
goal <text> Set or update the project goal
|
|
81
|
+
lock <text> [--tags a,b] Add a non-negotiable constraint
|
|
82
|
+
lock remove <id> Remove a lock by ID
|
|
83
|
+
decide <text> [--tags a,b] Record a decision
|
|
84
|
+
note <text> [--pinned] Add a pinned note
|
|
85
|
+
log-change <text> [--files x,y] Log a significant change
|
|
86
|
+
check <text> Check if action conflicts with locks
|
|
87
|
+
context Generate and print context pack
|
|
88
|
+
facts deploy [--provider X] Set deployment facts
|
|
89
|
+
watch Start file watcher (auto-track changes)
|
|
90
|
+
serve [--project <path>] Start MCP stdio server
|
|
91
|
+
status Show project brain summary
|
|
76
92
|
|
|
77
93
|
Options:
|
|
78
|
-
--tags <a,b,c>
|
|
79
|
-
--source <user|agent>
|
|
80
|
-
--
|
|
81
|
-
--
|
|
82
|
-
--
|
|
83
|
-
--url <url> Deployment URL
|
|
84
|
-
--notes <text> Additional notes
|
|
85
|
-
--project <path> Project root (for serve)
|
|
94
|
+
--tags <a,b,c> Comma-separated tags
|
|
95
|
+
--source <user|agent> Who created this (default: user)
|
|
96
|
+
--files <a.ts,b.ts> Comma-separated file paths
|
|
97
|
+
--goal <text> Goal text (for setup command)
|
|
98
|
+
--project <path> Project root (for serve)
|
|
86
99
|
|
|
87
100
|
Examples:
|
|
88
|
-
speclock
|
|
89
|
-
speclock
|
|
90
|
-
speclock
|
|
91
|
-
speclock
|
|
92
|
-
speclock
|
|
93
|
-
speclock
|
|
94
|
-
|
|
95
|
-
MCP Tools (19): init, get_context, set_goal, add_lock, remove_lock,
|
|
96
|
-
add_decision, add_note, set_deploy_facts, log_change, get_changes,
|
|
97
|
-
get_events, check_conflict, session_briefing, session_summary,
|
|
98
|
-
checkpoint, repo_status, suggest_locks, detect_drift, health
|
|
101
|
+
npx speclock setup --goal "Build PawPalace pet shop"
|
|
102
|
+
npx speclock lock "Never modify auth files"
|
|
103
|
+
npx speclock check "Adding social login to auth page"
|
|
104
|
+
npx speclock log-change "Built payment system" --files src/pay.tsx
|
|
105
|
+
npx speclock decide "Use Supabase for auth"
|
|
106
|
+
npx speclock context
|
|
107
|
+
npx speclock status
|
|
99
108
|
`);
|
|
100
109
|
}
|
|
101
110
|
|
|
@@ -104,7 +113,7 @@ MCP Tools (19): init, get_context, set_goal, add_lock, remove_lock,
|
|
|
104
113
|
function showStatus(root) {
|
|
105
114
|
const brain = readBrain(root);
|
|
106
115
|
if (!brain) {
|
|
107
|
-
console.log("SpecLock not initialized. Run: speclock
|
|
116
|
+
console.log("SpecLock not initialized. Run: npx speclock setup");
|
|
108
117
|
return;
|
|
109
118
|
}
|
|
110
119
|
|
|
@@ -113,11 +122,11 @@ function showStatus(root) {
|
|
|
113
122
|
console.log(`\nSpecLock Status — ${brain.project.name}`);
|
|
114
123
|
console.log("=".repeat(50));
|
|
115
124
|
console.log(`Goal: ${brain.goal.text || "(not set)"}`);
|
|
116
|
-
console.log(`
|
|
125
|
+
console.log(`Locks: ${activeLocks.length} active`);
|
|
117
126
|
console.log(`Decisions: ${brain.decisions.length}`);
|
|
118
127
|
console.log(`Notes: ${brain.notes.length}`);
|
|
119
128
|
console.log(`Events: ${brain.events.count}`);
|
|
120
|
-
console.log(`Deploy: ${brain.facts.deploy.provider}`);
|
|
129
|
+
console.log(`Deploy: ${brain.facts.deploy.provider || "(not set)"}`);
|
|
121
130
|
|
|
122
131
|
if (brain.sessions.current) {
|
|
123
132
|
console.log(`Session: active (${brain.sessions.current.toolUsed})`);
|
|
@@ -133,7 +142,6 @@ function showStatus(root) {
|
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
console.log(`Recent changes: ${brain.state.recentChanges.length}`);
|
|
136
|
-
console.log(`Reverts: ${brain.state.reverts.length}`);
|
|
137
145
|
console.log("");
|
|
138
146
|
}
|
|
139
147
|
|
|
@@ -148,12 +156,60 @@ async function main() {
|
|
|
148
156
|
process.exit(0);
|
|
149
157
|
}
|
|
150
158
|
|
|
159
|
+
// --- SETUP (new: one-shot full setup) ---
|
|
160
|
+
if (cmd === "setup") {
|
|
161
|
+
const flags = parseFlags(args);
|
|
162
|
+
const goalText = flags.goal || flags._.join(" ").trim();
|
|
163
|
+
|
|
164
|
+
// 1. Initialize
|
|
165
|
+
ensureInit(root);
|
|
166
|
+
console.log("Initialized .speclock/ directory.");
|
|
167
|
+
|
|
168
|
+
// 2. Set goal if provided
|
|
169
|
+
if (goalText) {
|
|
170
|
+
setGoal(root, goalText);
|
|
171
|
+
console.log(`Goal set: "${goalText}"`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 3. Create SPECLOCK.md in project root
|
|
175
|
+
const mdPath = createSpecLockMd(root);
|
|
176
|
+
console.log(`Created SPECLOCK.md (AI instructions file).`);
|
|
177
|
+
|
|
178
|
+
// 4. Generate context
|
|
179
|
+
generateContext(root);
|
|
180
|
+
console.log("Generated .speclock/context/latest.md");
|
|
181
|
+
|
|
182
|
+
// 5. Print summary
|
|
183
|
+
console.log(`
|
|
184
|
+
SpecLock is ready!
|
|
185
|
+
|
|
186
|
+
Files created:
|
|
187
|
+
.speclock/brain.json — Project memory
|
|
188
|
+
.speclock/context/latest.md — Context for AI (read this)
|
|
189
|
+
SPECLOCK.md — AI rules (read this)
|
|
190
|
+
|
|
191
|
+
Next steps:
|
|
192
|
+
The AI should read SPECLOCK.md for rules and
|
|
193
|
+
.speclock/context/latest.md for project context.
|
|
194
|
+
|
|
195
|
+
To add constraints: npx speclock lock "Never touch auth files"
|
|
196
|
+
To check conflicts: npx speclock check "Modifying auth page"
|
|
197
|
+
To log changes: npx speclock log-change "Built landing page"
|
|
198
|
+
To see status: npx speclock status
|
|
199
|
+
`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// --- INIT ---
|
|
151
204
|
if (cmd === "init") {
|
|
152
205
|
ensureInit(root);
|
|
153
|
-
|
|
206
|
+
createSpecLockMd(root);
|
|
207
|
+
generateContext(root);
|
|
208
|
+
console.log("SpecLock initialized. Created SPECLOCK.md and context file.");
|
|
154
209
|
return;
|
|
155
210
|
}
|
|
156
211
|
|
|
212
|
+
// --- GOAL ---
|
|
157
213
|
if (cmd === "goal") {
|
|
158
214
|
const text = args.join(" ").trim();
|
|
159
215
|
if (!text) {
|
|
@@ -162,10 +218,12 @@ async function main() {
|
|
|
162
218
|
process.exit(1);
|
|
163
219
|
}
|
|
164
220
|
setGoal(root, text);
|
|
221
|
+
refreshContext(root);
|
|
165
222
|
console.log(`Goal set: "${text}"`);
|
|
166
223
|
return;
|
|
167
224
|
}
|
|
168
225
|
|
|
226
|
+
// --- LOCK ---
|
|
169
227
|
if (cmd === "lock") {
|
|
170
228
|
// Check for "lock remove <id>"
|
|
171
229
|
if (args[0] === "remove") {
|
|
@@ -177,6 +235,7 @@ async function main() {
|
|
|
177
235
|
}
|
|
178
236
|
const result = removeLock(root, lockId);
|
|
179
237
|
if (result.removed) {
|
|
238
|
+
refreshContext(root);
|
|
180
239
|
console.log(`Lock removed: "${result.lockText}"`);
|
|
181
240
|
} else {
|
|
182
241
|
console.error(result.error);
|
|
@@ -193,10 +252,12 @@ async function main() {
|
|
|
193
252
|
process.exit(1);
|
|
194
253
|
}
|
|
195
254
|
const { lockId } = addLock(root, text, parseTags(flags.tags), flags.source || "user");
|
|
196
|
-
|
|
255
|
+
refreshContext(root);
|
|
256
|
+
console.log(`Locked (${lockId}): "${text}"`);
|
|
197
257
|
return;
|
|
198
258
|
}
|
|
199
259
|
|
|
260
|
+
// --- DECIDE ---
|
|
200
261
|
if (cmd === "decide") {
|
|
201
262
|
const flags = parseFlags(args);
|
|
202
263
|
const text = flags._.join(" ").trim();
|
|
@@ -206,10 +267,12 @@ async function main() {
|
|
|
206
267
|
process.exit(1);
|
|
207
268
|
}
|
|
208
269
|
const { decId } = addDecision(root, text, parseTags(flags.tags), flags.source || "user");
|
|
270
|
+
refreshContext(root);
|
|
209
271
|
console.log(`Decision recorded (${decId}): "${text}"`);
|
|
210
272
|
return;
|
|
211
273
|
}
|
|
212
274
|
|
|
275
|
+
// --- NOTE ---
|
|
213
276
|
if (cmd === "note") {
|
|
214
277
|
const flags = parseFlags(args);
|
|
215
278
|
const text = flags._.join(" ").trim();
|
|
@@ -220,10 +283,60 @@ async function main() {
|
|
|
220
283
|
}
|
|
221
284
|
const pinned = flags.pinned !== false;
|
|
222
285
|
const { noteId } = addNote(root, text, pinned);
|
|
286
|
+
refreshContext(root);
|
|
223
287
|
console.log(`Note added (${noteId}): "${text}"`);
|
|
224
288
|
return;
|
|
225
289
|
}
|
|
226
290
|
|
|
291
|
+
// --- LOG-CHANGE (new) ---
|
|
292
|
+
if (cmd === "log-change") {
|
|
293
|
+
const flags = parseFlags(args);
|
|
294
|
+
const text = flags._.join(" ").trim();
|
|
295
|
+
if (!text) {
|
|
296
|
+
console.error("Error: Change summary is required.");
|
|
297
|
+
console.error('Usage: speclock log-change "what changed" --files a.ts,b.ts');
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
const files = flags.files ? flags.files.split(",").map((f) => f.trim()).filter(Boolean) : [];
|
|
301
|
+
logChange(root, text, files);
|
|
302
|
+
refreshContext(root);
|
|
303
|
+
console.log(`Change logged: "${text}"`);
|
|
304
|
+
if (files.length > 0) {
|
|
305
|
+
console.log(`Files: ${files.join(", ")}`);
|
|
306
|
+
}
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// --- CHECK (new: conflict check) ---
|
|
311
|
+
if (cmd === "check") {
|
|
312
|
+
const text = args.join(" ").trim();
|
|
313
|
+
if (!text) {
|
|
314
|
+
console.error("Error: Action description is required.");
|
|
315
|
+
console.error('Usage: speclock check "what you plan to do"');
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
const result = checkConflict(root, text);
|
|
319
|
+
if (result.hasConflict) {
|
|
320
|
+
console.log(`\nCONFLICT DETECTED`);
|
|
321
|
+
console.log("=".repeat(50));
|
|
322
|
+
for (const lock of result.conflictingLocks) {
|
|
323
|
+
console.log(` [${lock.confidence}] "${lock.text}"`);
|
|
324
|
+
console.log(` Confidence: ${lock.score}%`);
|
|
325
|
+
if (lock.reasons && lock.reasons.length > 0) {
|
|
326
|
+
for (const reason of lock.reasons) {
|
|
327
|
+
console.log(` - ${reason}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
console.log("");
|
|
331
|
+
}
|
|
332
|
+
console.log(result.analysis);
|
|
333
|
+
} else {
|
|
334
|
+
console.log(`No conflicts found. Safe to proceed with: "${text}"`);
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// --- FACTS ---
|
|
227
340
|
if (cmd === "facts") {
|
|
228
341
|
const sub = args.shift();
|
|
229
342
|
if (sub !== "deploy") {
|
|
@@ -245,21 +358,25 @@ async function main() {
|
|
|
245
358
|
String(flags.autoDeploy).toLowerCase() === "true";
|
|
246
359
|
}
|
|
247
360
|
updateDeployFacts(root, payload);
|
|
361
|
+
refreshContext(root);
|
|
248
362
|
console.log("Deploy facts updated.");
|
|
249
363
|
return;
|
|
250
364
|
}
|
|
251
365
|
|
|
366
|
+
// --- CONTEXT ---
|
|
252
367
|
if (cmd === "context") {
|
|
253
368
|
const md = generateContext(root);
|
|
254
369
|
console.log(md);
|
|
255
370
|
return;
|
|
256
371
|
}
|
|
257
372
|
|
|
373
|
+
// --- WATCH ---
|
|
258
374
|
if (cmd === "watch") {
|
|
259
375
|
await watchRepo(root);
|
|
260
376
|
return;
|
|
261
377
|
}
|
|
262
378
|
|
|
379
|
+
// --- SERVE ---
|
|
263
380
|
if (cmd === "serve") {
|
|
264
381
|
// Start MCP server — pass through --project if provided
|
|
265
382
|
const flags = parseFlags(args);
|
|
@@ -269,6 +386,7 @@ async function main() {
|
|
|
269
386
|
return;
|
|
270
387
|
}
|
|
271
388
|
|
|
389
|
+
// --- STATUS ---
|
|
272
390
|
if (cmd === "status") {
|
|
273
391
|
showStatus(root);
|
|
274
392
|
return;
|
package/src/core/engine.js
CHANGED
|
@@ -696,3 +696,53 @@ export async function watchRepo(root) {
|
|
|
696
696
|
console.log("SpecLock watching for changes...");
|
|
697
697
|
return watcher;
|
|
698
698
|
}
|
|
699
|
+
|
|
700
|
+
// --- SPECLOCK.md generator (for npm dependency / file-based mode) ---
|
|
701
|
+
|
|
702
|
+
export function createSpecLockMd(root) {
|
|
703
|
+
const mdContent = `# SpecLock — Project Memory Active
|
|
704
|
+
|
|
705
|
+
This project uses **SpecLock** for AI continuity across sessions.
|
|
706
|
+
Read \`.speclock/context/latest.md\` for full project context before making changes.
|
|
707
|
+
|
|
708
|
+
## Rules (follow on every message)
|
|
709
|
+
|
|
710
|
+
1. **START OF EVERY MESSAGE**: Read \`.speclock/context/latest.md\` for project memory — goals, constraints (locks), decisions, and recent changes. If the file doesn't exist, run \`npx speclock context\` to generate it.
|
|
711
|
+
|
|
712
|
+
2. **BEFORE MODIFYING CODE**: Run \`npx speclock check "description of what you plan to change"\`. If a conflict is found (HIGH confidence), STOP and warn the user which constraint would be violated. Do NOT proceed unless the user explicitly says to override.
|
|
713
|
+
|
|
714
|
+
3. **WHEN USER SAYS "lock this", "never touch", "don't change", "always", "critical"**: Run \`npx speclock lock "the exact constraint"\`. Confirm: "Locked: [constraint]"
|
|
715
|
+
|
|
716
|
+
4. **AFTER COMPLETING A FEATURE OR SIGNIFICANT CHANGE**: Run \`npx speclock log-change "what was built/changed" --files file1.tsx,file2.ts\`. Then run \`npx speclock context\` to refresh the context file.
|
|
717
|
+
|
|
718
|
+
5. **WHEN AN ARCHITECTURAL DECISION IS MADE**: Run \`npx speclock decide "the decision"\`
|
|
719
|
+
|
|
720
|
+
6. **WHEN USER WANTS TO CHANGE SOMETHING LOCKED**: Warn first: "This is locked: [constraint]. Want me to unlock and proceed?" If confirmed, run \`npx speclock lock remove <lockId>\`
|
|
721
|
+
|
|
722
|
+
## Quick Reference
|
|
723
|
+
|
|
724
|
+
\`\`\`bash
|
|
725
|
+
npx speclock status # See brain summary
|
|
726
|
+
npx speclock context # Regenerate context file
|
|
727
|
+
npx speclock lock "constraint text" # Add a constraint
|
|
728
|
+
npx speclock lock remove <lockId> # Remove a constraint
|
|
729
|
+
npx speclock decide "decision text" # Record a decision
|
|
730
|
+
npx speclock log-change "what changed" # Log a change
|
|
731
|
+
npx speclock check "what you plan to do" # Check for conflicts
|
|
732
|
+
npx speclock goal "project goal" # Set/update goal
|
|
733
|
+
npx speclock note "important note" # Add a note
|
|
734
|
+
\`\`\`
|
|
735
|
+
|
|
736
|
+
## How It Works
|
|
737
|
+
|
|
738
|
+
SpecLock maintains a \`.speclock/\` directory with structured project memory:
|
|
739
|
+
- \`brain.json\` — goals, locks, decisions, session history
|
|
740
|
+
- \`events.log\` — immutable audit trail
|
|
741
|
+
- \`context/latest.md\` — human-readable context (read this!)
|
|
742
|
+
|
|
743
|
+
Every command automatically refreshes the context file so it's always up to date.
|
|
744
|
+
`;
|
|
745
|
+
const filePath = path.join(root, "SPECLOCK.md");
|
|
746
|
+
fs.writeFileSync(filePath, mdContent);
|
|
747
|
+
return filePath;
|
|
748
|
+
}
|