speclock 4.3.3 → 4.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.
@@ -144,3 +144,59 @@ AI: 🔓 Unlocked. Proceeding with auth file changes.
144
144
  1. Add to `~/.claude.json` or `.mcp.json`: `{"mcpServers":{"speclock":{"command":"npx","args":["-y","speclock","serve","--project","."]}}}`
145
145
  2. Add the instruction above to `CLAUDE.md`
146
146
  3. Done.
147
+
148
+ ---
149
+
150
+ ## For Bolt.new, Kimi, Replit, and other platforms WITHOUT MCP
151
+
152
+ These platforms don't have MCP connectors. SpecLock works via `npm install` + direct JavaScript API. The conflict checking uses a cloud proxy to get Gemini LLM coverage automatically — no API key needed.
153
+
154
+ ### Setup:
155
+ 1. Install: `npm install speclock`
156
+ 2. Paste the instructions below into the platform's Knowledge / System Prompt / Project Instructions.
157
+
158
+ ### Instructions to paste:
159
+
160
+ ```
161
+ ## SpecLock Rules (MANDATORY — follow on every message)
162
+
163
+ This project uses SpecLock for constraint protection. SpecLock is installed via npm.
164
+
165
+ ### How to check conflicts:
166
+ Before making ANY significant code change, run this check:
167
+
168
+ const { checkConflictAsync } = await import("speclock/src/core/engine.js");
169
+ const result = await checkConflictAsync("description of what you are about to do", ["lock text 1", "lock text 2"]);
170
+ if (result.hasConflict) {
171
+ // STOP — warn the user about the conflict
172
+ // result.analysis contains the details
173
+ }
174
+
175
+ ### How to check conflicts (alternative — pass lock text directly):
176
+ const { checkConflictAsync } = await import("speclock/src/core/engine.js");
177
+ const result = await checkConflictAsync("Add Razorpay payment gateway", "Never change from Stripe payment integration");
178
+ // result.hasConflict will be true
179
+
180
+ ### Rules:
181
+ 1. MAINTAIN A LIST of user constraints (locks) in memory. When the user says "never", "always", "don't touch", "lock this" — add it to your lock list.
182
+ 2. BEFORE MODIFYING CODE: Call checkConflictAsync with what you're about to do and ALL active locks. If hasConflict is true, STOP and warn the user.
183
+ 3. The function is ASYNC — always use await. It calls a cloud API for accurate detection across all domains.
184
+ 4. If the function is unavailable, at minimum do a manual check: does your proposed action violate any of the user's stated constraints?
185
+ ```
186
+
187
+ ### Example usage in code:
188
+ ```javascript
189
+ import { checkConflictAsync } from "speclock/src/core/engine.js";
190
+
191
+ // Check a single lock
192
+ const r = await checkConflictAsync("Switch to MongoDB", "Never change the database technology");
193
+ console.log(r.hasConflict); // true
194
+ console.log(r.analysis); // "1 conflict(s) confirmed..."
195
+
196
+ // Check multiple locks
197
+ const r2 = await checkConflictAsync("Add Razorpay payments", [
198
+ "Never change from Stripe",
199
+ "Never modify the payment system"
200
+ ]);
201
+ console.log(r2.hasConflict); // true
202
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speclock",
3
- "version": "4.3.3",
3
+ "version": "4.4.0",
4
4
  "description": "AI constraint engine with Gemini LLM universal detection, Policy-as-Code DSL, OAuth/OIDC SSO, admin dashboard, telemetry, API key auth, RBAC, AES-256-GCM encryption, hard enforcement, semantic pre-commit, HMAC audit chain, SOC 2/HIPAA compliance. Cross-platform: MCP + direct API. 31 MCP tools + CLI. Enterprise platform.",
5
5
  "type": "module",
6
6
  "main": "src/mcp/server.js",
package/src/cli/index.js CHANGED
@@ -116,7 +116,7 @@ function refreshContext(root) {
116
116
 
117
117
  function printHelp() {
118
118
  console.log(`
119
- SpecLock v4.3.3 — AI Constraint Engine (Gemini LLM + Policy-as-Code + SSO + Dashboard + Telemetry + Auth + RBAC + Encryption)
119
+ SpecLock v4.4.0 — AI Constraint Engine (Gemini LLM + Policy-as-Code + SSO + Dashboard + Telemetry + Auth + RBAC + Encryption)
120
120
  Developed by Sandeep Roy (github.com/sgroy10)
121
121
 
122
122
  Usage: speclock <command> [options]
@@ -9,7 +9,7 @@
9
9
  import { readBrain, readEvents } from "./storage.js";
10
10
  import { verifyAuditChain } from "./audit.js";
11
11
 
12
- const VERSION = "4.3.3";
12
+ const VERSION = "4.4.0";
13
13
 
14
14
  // PHI-related keywords for HIPAA filtering
15
15
  const PHI_KEYWORDS = [
@@ -59,13 +59,18 @@ const GUARD_TAG = "SPECLOCK-GUARD";
59
59
  /**
60
60
  * Detect if the first argument is a file-system path (brain mode)
61
61
  * or natural text (direct mode for cross-platform usage).
62
+ * Must be strict: "spay/neuter" is NOT a path, "/app" IS a path.
62
63
  */
63
64
  function isDirectoryPath(str) {
64
65
  if (!str || typeof str !== "string") return false;
65
66
  // Absolute paths: /foo, C:\foo, \\server
66
- if (str.startsWith("/") || str.startsWith("\\") || /^[A-Z]:/i.test(str)) return true;
67
- // Relative path with separator or current dir
68
- if (str === "." || str === ".." || str.includes("/") || str.includes("\\")) return true;
67
+ if (/^[A-Z]:/i.test(str)) return true; // C:\Users\...
68
+ if (str.startsWith("\\\\")) return true; // \\server\share
69
+ if (str.startsWith("/") && !str.includes(" ")) return true; // /app, /usr/local (no spaces = likely path)
70
+ // Relative path starting with . or ..
71
+ if (/^\.\.?[/\\]/.test(str)) return true; // ./foo, ../bar
72
+ if (str === "." || str === "..") return true;
73
+ // Natural language with / in the middle (spay/neuter, TCP/IP, etc.) is NOT a path
69
74
  return false;
70
75
  }
71
76
 
@@ -257,7 +257,7 @@ export async function flushToRemote(root) {
257
257
  // Build anonymized payload
258
258
  const payload = {
259
259
  instanceId: summary.instanceId,
260
- version: "4.3.3",
260
+ version: "4.4.0",
261
261
  totalCalls: summary.totalCalls,
262
262
  avgResponseMs: summary.avgResponseMs,
263
263
  conflicts: summary.conflicts,
@@ -89,7 +89,7 @@
89
89
  <div class="header">
90
90
  <div>
91
91
  <h1><span>SpecLock</span> Dashboard</h1>
92
- <div class="meta">v4.3.3 &mdash; AI Constraint Engine</div>
92
+ <div class="meta">v4.4.0 &mdash; AI Constraint Engine</div>
93
93
  </div>
94
94
  <div style="display:flex;align-items:center;gap:12px;">
95
95
  <span id="health-badge" class="status-badge healthy">Loading...</span>
@@ -182,7 +182,7 @@
182
182
  </div>
183
183
 
184
184
  <div style="text-align:center;padding:24px;color:var(--muted);font-size:12px;">
185
- SpecLock v4.3.3 &mdash; Developed by Sandeep Roy &mdash; <a href="https://github.com/sgroy10/speclock" style="color:var(--accent)">GitHub</a>
185
+ SpecLock v4.4.0 &mdash; Developed by Sandeep Roy &mdash; <a href="https://github.com/sgroy10/speclock" style="color:var(--accent)">GitHub</a>
186
186
  </div>
187
187
 
188
188
  <script>
@@ -91,7 +91,7 @@ import { fileURLToPath } from "url";
91
91
  import _path from "path";
92
92
 
93
93
  const PROJECT_ROOT = process.env.SPECLOCK_PROJECT_ROOT || process.cwd();
94
- const VERSION = "4.3.3";
94
+ const VERSION = "4.4.0";
95
95
  const AUTHOR = "Sandeep Roy";
96
96
  const START_TIME = Date.now();
97
97
 
@@ -221,13 +221,8 @@ function createSpecLockServer() {
221
221
  // Tool 7: speclock_add_note
222
222
  server.tool("speclock_add_note", "Add a pinned note for reference.", { text: z.string().min(1).describe("The note text"), pinned: z.boolean().default(true).describe("Whether to pin this note") }, async ({ text, pinned }) => {
223
223
  ensureInit(PROJECT_ROOT);
224
- const brain = readBrain(PROJECT_ROOT);
225
- const note = { id: newId(), text, pinned, createdAt: nowIso() };
226
- brain.state.notes.push(note);
227
- writeBrain(PROJECT_ROOT, brain);
228
- appendEvent(PROJECT_ROOT, { type: "note_added", noteId: note.id, text });
229
- bumpEvents(PROJECT_ROOT);
230
- return { content: [{ type: "text", text: `Note added [${note.id}]: ${text}` }] };
224
+ const result = addNote(PROJECT_ROOT, text, pinned);
225
+ return { content: [{ type: "text", text: `Note added [${result.noteId}]: ${text}` }] };
231
226
  });
232
227
 
233
228
  // Tool 8: speclock_set_deploy_facts
package/src/mcp/server.js CHANGED
@@ -100,7 +100,7 @@ const PROJECT_ROOT =
100
100
  args.project || process.env.SPECLOCK_PROJECT_ROOT || process.cwd();
101
101
 
102
102
  // --- MCP Server ---
103
- const VERSION = "4.3.3";
103
+ const VERSION = "4.4.0";
104
104
  const AUTHOR = "Sandeep Roy";
105
105
 
106
106
  const server = new McpServer(