speclock 1.4.1 → 1.5.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 +2 -2
- package/package.json +1 -1
- package/src/cli/index.js +14 -5
- package/src/core/engine.js +86 -33
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ Or run it yourself:
|
|
|
76
76
|
npx speclock setup --goal "Build my app"
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
**That's it.**
|
|
79
|
+
**That's it.** SpecLock creates `SPECLOCK.md`, injects a marker into `package.json`, and generates `.speclock/context/latest.md`. The AI reads these automatically and follows the rules. When the AI returns in a new session, it sees the SpecLock marker in `package.json` and knows to check the rules before making changes.
|
|
80
80
|
|
|
81
81
|
### Lovable (MCP Remote — No Install)
|
|
82
82
|
|
|
@@ -287,4 +287,4 @@ MIT License - see [LICENSE](LICENSE) file.
|
|
|
287
287
|
|
|
288
288
|
---
|
|
289
289
|
|
|
290
|
-
*SpecLock v1.
|
|
290
|
+
*SpecLock v1.5.0 — Because remembering isn't enough. AI needs to respect boundaries.*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "speclock",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
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",
|
package/src/cli/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
createSpecLockMd,
|
|
14
14
|
guardFile,
|
|
15
15
|
unguardFile,
|
|
16
|
+
injectPackageJsonMarker,
|
|
16
17
|
} from "../core/engine.js";
|
|
17
18
|
import { generateContext } from "../core/context.js";
|
|
18
19
|
import { readBrain } from "../core/storage.js";
|
|
@@ -71,7 +72,7 @@ function refreshContext(root) {
|
|
|
71
72
|
|
|
72
73
|
function printHelp() {
|
|
73
74
|
console.log(`
|
|
74
|
-
SpecLock v1.
|
|
75
|
+
SpecLock v1.5.0 — AI Constraint Engine
|
|
75
76
|
Developed by Sandeep Roy (github.com/sgroy10)
|
|
76
77
|
|
|
77
78
|
Usage: speclock <command> [options]
|
|
@@ -181,18 +182,25 @@ async function main() {
|
|
|
181
182
|
const mdPath = createSpecLockMd(root);
|
|
182
183
|
console.log(`Created SPECLOCK.md (AI instructions file).`);
|
|
183
184
|
|
|
184
|
-
// 4.
|
|
185
|
+
// 4. Inject marker into package.json (so AI tools auto-discover SpecLock)
|
|
186
|
+
const pkgResult = injectPackageJsonMarker(root);
|
|
187
|
+
if (pkgResult.success) {
|
|
188
|
+
console.log("Injected SpecLock marker into package.json.");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 5. Generate context
|
|
185
192
|
generateContext(root);
|
|
186
193
|
console.log("Generated .speclock/context/latest.md");
|
|
187
194
|
|
|
188
|
-
//
|
|
195
|
+
// 6. Print summary
|
|
189
196
|
console.log(`
|
|
190
197
|
SpecLock is ready!
|
|
191
198
|
|
|
192
|
-
Files created:
|
|
199
|
+
Files created/updated:
|
|
193
200
|
.speclock/brain.json — Project memory
|
|
194
201
|
.speclock/context/latest.md — Context for AI (read this)
|
|
195
202
|
SPECLOCK.md — AI rules (read this)
|
|
203
|
+
package.json — SpecLock marker added (AI auto-discovery)
|
|
196
204
|
|
|
197
205
|
Next steps:
|
|
198
206
|
The AI should read SPECLOCK.md for rules and
|
|
@@ -210,8 +218,9 @@ Next steps:
|
|
|
210
218
|
if (cmd === "init") {
|
|
211
219
|
ensureInit(root);
|
|
212
220
|
createSpecLockMd(root);
|
|
221
|
+
injectPackageJsonMarker(root);
|
|
213
222
|
generateContext(root);
|
|
214
|
-
console.log("SpecLock initialized. Created SPECLOCK.md and context file.");
|
|
223
|
+
console.log("SpecLock initialized. Created SPECLOCK.md, updated package.json, and generated context file.");
|
|
215
224
|
return;
|
|
216
225
|
}
|
|
217
226
|
|
package/src/core/engine.js
CHANGED
|
@@ -702,68 +702,91 @@ export async function watchRepo(root) {
|
|
|
702
702
|
export function createSpecLockMd(root) {
|
|
703
703
|
const mdContent = `# SpecLock — AI Constraint Engine Active
|
|
704
704
|
|
|
705
|
-
##
|
|
705
|
+
## CRITICAL: LOCKED FILES CANNOT BE MODIFIED
|
|
706
706
|
|
|
707
|
-
|
|
707
|
+
If a lock says "never modify auth files" then you CANNOT modify those files.
|
|
708
|
+
Not now. Not later. Not if the user asks a question. Not for any reason.
|
|
708
709
|
|
|
709
|
-
|
|
710
|
+
**The ONLY way to modify a locked file:** The user must explicitly say "unlock" or "remove the lock."
|
|
711
|
+
Asking a question is NOT permission. Talking about a feature is NOT permission.
|
|
712
|
+
ONLY the words "unlock", "remove the lock", or "I changed my mind about the lock" count.
|
|
710
713
|
|
|
711
|
-
|
|
712
|
-
Read \`.speclock/context/latest.md\` first. Always. No exceptions.
|
|
714
|
+
**If a file contains "SPECLOCK-GUARD" at the top → DO NOT EDIT IT. No exceptions.**
|
|
713
715
|
|
|
714
|
-
|
|
715
|
-
Run \`npx speclock check "what you plan to do"\` BEFORE writing code.
|
|
716
|
-
If conflict → STOP. Tell the user. Do NOT proceed.
|
|
716
|
+
## On EVERY message — do this FIRST:
|
|
717
717
|
|
|
718
|
-
|
|
719
|
-
|
|
718
|
+
1. Read \`.speclock/context/latest.md\` for project memory
|
|
719
|
+
2. Run \`npx speclock check "what you plan to do"\` BEFORE any code changes
|
|
720
|
+
3. If conflict found → STOP. Tell user. Do NOT proceed. Do NOT ask "should I proceed?"
|
|
721
|
+
4. Wait for user to explicitly say "unlock" or "remove the lock" before touching locked files
|
|
720
722
|
|
|
721
|
-
|
|
723
|
+
## Returning to This Project? (New Chat Session)
|
|
724
|
+
|
|
725
|
+
SpecLock is ALREADY installed. Do NOT reinstall it. Do NOT say "it's not installed."
|
|
726
|
+
1. Run \`npx speclock status\` to see current locks and decisions
|
|
727
|
+
2. Read \`.speclock/context/latest.md\` for full project context
|
|
728
|
+
3. Respect ALL existing locks — they carry over between sessions
|
|
729
|
+
|
|
730
|
+
## What Counts as Permission to Bypass a Lock?
|
|
731
|
+
|
|
732
|
+
| User says | Is this permission? | What you do |
|
|
733
|
+
|-----------|-------------------|-------------|
|
|
734
|
+
| "add google auth" | NO — lock still active | Say "Auth files are locked. Want me to unlock them first?" |
|
|
735
|
+
| "is speclock initialized?" | NO — just a question | Answer the question. Do NOT change any code. |
|
|
736
|
+
| "yeah go ahead" (after you warned about lock) | NO — too vague | Say "To modify locked files, please confirm: unlock the auth files" |
|
|
737
|
+
| "ok unlock the auth files" | YES — explicit unlock | Run \`npx speclock lock remove <lockId>\`, then make changes |
|
|
738
|
+
| "remove the lock on auth" | YES — explicit unlock | Run \`npx speclock lock remove <lockId>\`, then make changes |
|
|
739
|
+
| "I changed my mind, you can edit auth" | YES — explicit unlock | Run \`npx speclock lock remove <lockId>\`, then make changes |
|
|
740
|
+
|
|
741
|
+
**When in doubt: DO NOT modify locked files. Ask for clarification instead.**
|
|
742
|
+
|
|
743
|
+
## Detect Constraints from Natural Language
|
|
744
|
+
|
|
745
|
+
Users will NOT say "lock this." They speak naturally. YOU must detect intent and lock automatically.
|
|
722
746
|
|
|
723
747
|
| User says | You do |
|
|
724
748
|
|-----------|--------|
|
|
725
|
-
| "don't touch the auth" | \`npx speclock lock "Never modify auth files"\` + \`npx speclock guard
|
|
749
|
+
| "don't touch the auth" | \`npx speclock lock "Never modify auth files"\` + \`npx speclock guard\` the auth files |
|
|
726
750
|
| "database is firebase, don't change it" | \`npx speclock lock "Database must always be Firebase"\` |
|
|
727
|
-
| "leave the payment system alone" | \`npx speclock lock "Never modify payment system"\` + guard
|
|
751
|
+
| "leave the payment system alone" | \`npx speclock lock "Never modify payment system"\` + guard payment files |
|
|
728
752
|
| "always use Supabase" | \`npx speclock lock "Always use Supabase"\` |
|
|
729
|
-
| "the API is done, don't mess with it" | \`npx speclock lock "Never modify API endpoints"\` + guard
|
|
753
|
+
| "the API is done, don't mess with it" | \`npx speclock lock "Never modify API endpoints"\` + guard API files |
|
|
730
754
|
|
|
731
755
|
When you lock something, ALSO guard the specific files:
|
|
732
756
|
\`npx speclock guard <filepath> --lock "the constraint"\`
|
|
733
|
-
This injects a warning directly into the file so it cannot be missed.
|
|
734
757
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
1.
|
|
738
|
-
2.
|
|
758
|
+
## Unlocking (When User Gives Explicit Permission)
|
|
759
|
+
|
|
760
|
+
1. User says "unlock auth" or "remove the auth lock" or "I changed my mind about auth"
|
|
761
|
+
2. Run \`npx speclock lock remove <lockId>\` + \`npx speclock unguard <file>\`
|
|
739
762
|
3. Make the changes
|
|
740
|
-
4. Ask
|
|
763
|
+
4. Ask: "Want me to re-lock this?"
|
|
741
764
|
|
|
742
|
-
|
|
743
|
-
\`npx speclock log-change "what you built" --files file1.tsx,file2.ts\`
|
|
765
|
+
## After Building Something
|
|
744
766
|
|
|
745
|
-
|
|
746
|
-
\`npx speclock decide "the decision"\`
|
|
767
|
+
\`npx speclock log-change "what you built" --files file1.tsx,file2.ts\`
|
|
747
768
|
|
|
748
769
|
## Commands
|
|
749
770
|
|
|
750
771
|
\`\`\`bash
|
|
772
|
+
npx speclock status # Check current state
|
|
751
773
|
npx speclock check "what you plan to do" # ALWAYS RUN BEFORE CHANGES
|
|
752
774
|
npx speclock lock "constraint" # Lock a constraint
|
|
753
775
|
npx speclock guard <file> --lock "constraint" # Protect a specific file
|
|
754
776
|
npx speclock unguard <file> # Remove file protection
|
|
755
|
-
npx speclock lock remove <lockId> # Unlock
|
|
777
|
+
npx speclock lock remove <lockId> # Unlock (only after explicit permission)
|
|
756
778
|
npx speclock log-change "what changed" # Log changes
|
|
757
779
|
npx speclock decide "decision" # Record a decision
|
|
758
780
|
npx speclock context # Refresh context file
|
|
759
|
-
npx speclock status # See project summary
|
|
760
781
|
\`\`\`
|
|
761
782
|
|
|
762
|
-
## Key
|
|
783
|
+
## Key Rules
|
|
763
784
|
|
|
764
|
-
**
|
|
765
|
-
**
|
|
766
|
-
**
|
|
785
|
+
1. **A question is NOT permission to bypass a lock.**
|
|
786
|
+
2. **Run speclock check before EVERY code change, EVERY time, EVERY message.**
|
|
787
|
+
3. **If you already warned about a conflict, the lock is STILL active until explicitly removed.**
|
|
788
|
+
4. **The user will NEVER tell you to run these commands. You run them automatically.**
|
|
789
|
+
5. **If this file exists, SpecLock is installed. Do NOT reinstall.**
|
|
767
790
|
`;
|
|
768
791
|
const filePath = path.join(root, "SPECLOCK.md");
|
|
769
792
|
fs.writeFileSync(filePath, mdContent);
|
|
@@ -811,9 +834,11 @@ export function guardFile(root, relativeFilePath, lockText) {
|
|
|
811
834
|
const warningLines = [
|
|
812
835
|
`${style.start}${"=".repeat(60)}${style.end || ""}`,
|
|
813
836
|
`${style.start}${GUARD_TAG} — DO NOT MODIFY THIS FILE${style.end || ""}`,
|
|
814
|
-
`${style.start}LOCKED
|
|
815
|
-
`${style.start}
|
|
816
|
-
`${style.start}
|
|
837
|
+
`${style.start}LOCKED: ${lockText}${style.end || ""}`,
|
|
838
|
+
`${style.start}THIS FILE IS LOCKED. DO NOT EDIT, CHANGE, OR REWRITE ANY PART OF IT.${style.end || ""}`,
|
|
839
|
+
`${style.start}The user must say "unlock" before this file can be changed.${style.end || ""}`,
|
|
840
|
+
`${style.start}A question is NOT permission. Asking about features is NOT permission.${style.end || ""}`,
|
|
841
|
+
`${style.start}ONLY "unlock" or "remove the lock" is permission to edit this file.${style.end || ""}`,
|
|
817
842
|
`${style.start}${"=".repeat(60)}${style.end || ""}`,
|
|
818
843
|
"",
|
|
819
844
|
];
|
|
@@ -824,6 +849,34 @@ export function guardFile(root, relativeFilePath, lockText) {
|
|
|
824
849
|
return { success: true };
|
|
825
850
|
}
|
|
826
851
|
|
|
852
|
+
// --- Package.json marker injection (makes Bolt.new auto-discover SpecLock) ---
|
|
853
|
+
|
|
854
|
+
export function injectPackageJsonMarker(root) {
|
|
855
|
+
const pkgPath = path.join(root, "package.json");
|
|
856
|
+
if (!fs.existsSync(pkgPath)) {
|
|
857
|
+
return { success: false, error: "No package.json found in project root." };
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
try {
|
|
861
|
+
const raw = fs.readFileSync(pkgPath, "utf-8");
|
|
862
|
+
const pkg = JSON.parse(raw);
|
|
863
|
+
|
|
864
|
+
// Add speclock marker
|
|
865
|
+
pkg.speclock = {
|
|
866
|
+
active: true,
|
|
867
|
+
rules: "IMPORTANT: Read SPECLOCK.md before making ANY changes to this project. Read .speclock/context/latest.md for project memory, goals, locks, and decisions. Run 'npx speclock check' before modifying locked files.",
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
// Write back with same formatting
|
|
871
|
+
const indent = raw.match(/^(\s+)/m)?.[1] || " ";
|
|
872
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, indent) + "\n");
|
|
873
|
+
|
|
874
|
+
return { success: true };
|
|
875
|
+
} catch (err) {
|
|
876
|
+
return { success: false, error: `Failed to modify package.json: ${err.message}` };
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
827
880
|
export function unguardFile(root, relativeFilePath) {
|
|
828
881
|
const fullPath = path.join(root, relativeFilePath);
|
|
829
882
|
if (!fs.existsSync(fullPath)) {
|