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 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.** 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.
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.3.1 — Because remembering isn't enough. AI needs to respect boundaries.*
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.4.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.4.0 — AI Constraint Engine
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. Generate context
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
- // 5. Print summary
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
 
@@ -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
- ## STOP Read this before doing ANYTHING.
705
+ ## CRITICAL: LOCKED FILES CANNOT BE MODIFIED
706
706
 
707
- **If a file contains "SPECLOCK-GUARD" at the top DO NOT EDIT IT. Period.**
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
- ## Your Job (Do This Automatically The User Will NOT Ask)
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
- ### On EVERY message:
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
- ### Before changing ANY code:
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
- ### Detect constraints from natural language:
719
- Users will NOT say "lock this." They speak naturally. YOU must detect it.
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
- Examples of what users say what you do:
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 src/components/Auth.tsx --lock "Never modify auth files"\` |
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 the payment files |
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 the API files |
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
- ### When user wants to change something locked:
736
- User might say "actually, let me change auth" or "ok modify the database."
737
- 1. Warn: "This is currently locked: [constraint]. Want me to unlock?"
738
- 2. If they confirm → \`npx speclock lock remove <lockId>\` + \`npx speclock unguard <file>\`
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 if they want to re-lock: "Want me to lock this again?"
763
+ 4. Ask: "Want me to re-lock this?"
741
764
 
742
- ### After building something:
743
- \`npx speclock log-change "what you built" --files file1.tsx,file2.ts\`
765
+ ## After Building Something
744
766
 
745
- ### When a tech decision is made:
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 a constraint
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 Rule
783
+ ## Key Rules
763
784
 
764
- **The user will NEVER tell you to run these commands. You run them automatically.**
765
- **The user will NEVER say "lock this." You detect the intent and lock it yourself.**
766
- **The user will NEVER say "check constraints." You check before EVERY code change.**
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 BY SPECLOCK: ${lockText}${style.end || ""}`,
815
- `${style.start}Run "npx speclock check" before ANY changes to this file.${style.end || ""}`,
816
- `${style.start}If you modify this file, you are VIOLATING a project constraint.${style.end || ""}`,
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)) {