speclock 4.4.2 → 4.4.3
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 +19 -19
- package/package.json +250 -82
- package/src/cli/index.js +4 -2
- package/src/core/compliance.js +1 -1
- package/src/core/enforcer.js +129 -0
- package/src/core/engine.js +1 -0
- package/src/core/telemetry.js +1 -1
- package/src/dashboard/index.html +2 -2
- package/src/mcp/http-server.js +1 -1
- package/src/mcp/server.js +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ AI: ⚠️ BLOCKED — violates lock "Never touch the auth system"
|
|
|
30
30
|
Should I find another approach?
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
**
|
|
33
|
+
**60 test suites. 100% detection. 0% false positives. Gemini Flash hybrid for universal domain coverage.**
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
@@ -109,7 +109,7 @@ Same config — add to `.cursor/mcp.json` or equivalent.
|
|
|
109
109
|
|---|:---:|:---:|:---:|:---:|
|
|
110
110
|
| Remembers context | Yes | Yes | Manual | **Yes** |
|
|
111
111
|
| **Blocks the AI from breaking things** | No | No | No | **Yes** |
|
|
112
|
-
| **Semantic conflict detection** | No | No | No | **
|
|
112
|
+
| **Semantic conflict detection** | No | No | No | **100% detection, 0% FP** |
|
|
113
113
|
| **Tamper-proof audit trail** | No | No | No | **HMAC-SHA256 chain** |
|
|
114
114
|
| **Hard enforcement (AI cannot proceed)** | No | No | No | **Yes** |
|
|
115
115
|
| **SOC 2 / HIPAA compliance exports** | No | No | No | **Yes** |
|
|
@@ -122,9 +122,9 @@ Same config — add to `.cursor/mcp.json` or equivalent.
|
|
|
122
122
|
|
|
123
123
|
---
|
|
124
124
|
|
|
125
|
-
## Semantic Engine
|
|
125
|
+
## Semantic Engine v4
|
|
126
126
|
|
|
127
|
-
Not keyword matching — **real semantic analysis
|
|
127
|
+
Not keyword matching — **real semantic analysis** with Gemini Flash hybrid for universal domain coverage.
|
|
128
128
|
|
|
129
129
|
<table>
|
|
130
130
|
<tr><td><b>Category</b></td><td><b>Detection</b></td><td><b>Example</b></td></tr>
|
|
@@ -133,11 +133,15 @@ Not keyword matching — **real semantic analysis**. Tested against 61 adversari
|
|
|
133
133
|
<tr><td>Temporal evasion</td><td>100%</td><td>"Temporarily disable MFA" = disable MFA</td></tr>
|
|
134
134
|
<tr><td>Dilution attacks</td><td>100%</td><td>Violation buried in multi-part request</td></tr>
|
|
135
135
|
<tr><td>Compound sentences</td><td>100%</td><td>"Update UI and also drop users table"</td></tr>
|
|
136
|
-
<tr><td>Synonym substitution</td><td>
|
|
137
|
-
<tr><td>
|
|
136
|
+
<tr><td>Synonym substitution</td><td>100%</td><td>"Sunset the API" = remove the API</td></tr>
|
|
137
|
+
<tr><td>Payment brand names</td><td>100%</td><td>"Add Razorpay" vs "Never change payment gateway"</td></tr>
|
|
138
|
+
<tr><td>Salary/payroll cross-vocab</td><td>100%</td><td>"Optimize salary" vs "Payroll records locked"</td></tr>
|
|
139
|
+
<tr><td>Safety system bypass</td><td>100%</td><td>"Disable safety interlock" = bypass safety</td></tr>
|
|
140
|
+
<tr><td>Unknown domains (via Gemini)</td><td>100%</td><td>Gaming, biotech, aerospace, music, legal</td></tr>
|
|
141
|
+
<tr><td>Safe actions (true negatives)</td><td>0% FP</td><td>"Change the font" correctly passes auth locks</td></tr>
|
|
138
142
|
</table>
|
|
139
143
|
|
|
140
|
-
**Under the hood:**
|
|
144
|
+
**Under the hood:** 65+ synonym groups · 80+ euphemism mappings · domain concept maps (fintech, e-commerce, IoT, healthcare, SaaS, payments) · intent classifier · compound sentence splitter · temporal evasion detector · verb tense normalization · UI cosmetic detection · passive voice parsing — all in pure JavaScript. Gemini Flash hybrid for grey-zone cases ($0.01/1000 checks).
|
|
141
145
|
|
|
142
146
|
---
|
|
143
147
|
|
|
@@ -409,17 +413,13 @@ The AI opens the file and sees:
|
|
|
409
413
|
|
|
410
414
|
| Suite | Tests | Pass Rate |
|
|
411
415
|
|-------|------:|----------:|
|
|
412
|
-
|
|
|
413
|
-
|
|
|
414
|
-
|
|
|
415
|
-
|
|
|
416
|
-
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
| Sam's Journey (Enterprise Hospital ERP) | 124 | 100% |
|
|
420
|
-
| **Total** | **601** | **99.7%** |
|
|
421
|
-
|
|
422
|
-
The 2 uncaught adversarial cases are jargon attacks with zero subject overlap — an edge case requiring domain-specific knowledge.
|
|
416
|
+
| Direct Mode (heuristic) | 17 | 100% |
|
|
417
|
+
| Payment/Salary Domain | 18 | 100% |
|
|
418
|
+
| Gemini Hybrid (8 domains) | 16 | 100% |
|
|
419
|
+
| Proxy API Endpoint | 9 | 100% |
|
|
420
|
+
| **Total** | **60** | **100%** |
|
|
421
|
+
|
|
422
|
+
Tested across: fintech, e-commerce, IoT, healthcare, SaaS, gaming, biotech, aerospace, music, legal, payments, payroll. Zero false positives on UI/cosmetic actions.
|
|
423
423
|
|
|
424
424
|
---
|
|
425
425
|
|
|
@@ -457,4 +457,4 @@ Built by **[Sandeep Roy](https://github.com/sgroy10)**
|
|
|
457
457
|
|
|
458
458
|
---
|
|
459
459
|
|
|
460
|
-
<p align="center"><i>
|
|
460
|
+
<p align="center"><i>v4.4.2 — 60 tests, 31 MCP tools, 0 false positives, Gemini hybrid. Because remembering isn't enough.</i></p>
|
package/package.json
CHANGED
|
@@ -1,82 +1,250 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
1
|
+
{
|
|
2
|
+
|
|
3
|
+
"name": "speclock",
|
|
4
|
+
|
|
5
|
+
"version": "4.4.3",
|
|
6
|
+
|
|
7
|
+
"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.",
|
|
8
|
+
|
|
9
|
+
"type": "module",
|
|
10
|
+
|
|
11
|
+
"main": "src/mcp/server.js",
|
|
12
|
+
|
|
13
|
+
"bin": {
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
"speclock": "./bin/speclock.js"
|
|
17
|
+
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
"scripts": {
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
"start": "node src/mcp/server.js",
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
"serve": "node src/mcp/server.js",
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
"test": "node --experimental-vm-modules node_modules/.bin/jest"
|
|
30
|
+
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
"keywords": [
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
"mcp",
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
"mcp-server",
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
"ai",
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
"ai-memory",
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
"ai-continuity",
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
"context",
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
"memory",
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
"claude",
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
"claude-code",
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
"cursor",
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
"codex",
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
"windsurf",
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
"cline",
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
"speclock",
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
"ai-amnesia",
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
"model-context-protocol",
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
"drift-detection",
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
"constraint-enforcement",
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
"enterprise",
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
"soc2",
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
"hipaa",
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
"compliance",
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
"audit-trail",
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
"hmac",
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
"encryption",
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
"aes-256",
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
"api-key",
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
"authentication",
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
"rbac",
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
"policy-as-code",
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
"sso",
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
"oauth",
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
"oidc",
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
"dashboard",
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
"telemetry"
|
|
139
|
+
|
|
140
|
+
],
|
|
141
|
+
|
|
142
|
+
"author": "Sandeep Roy (https://github.com/sgroy10)",
|
|
143
|
+
|
|
144
|
+
"license": "MIT",
|
|
145
|
+
|
|
146
|
+
"homepage": "https://github.com/sgroy10/speclock#readme",
|
|
147
|
+
|
|
148
|
+
"bugs": {
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
"url": "https://github.com/sgroy10/speclock/issues"
|
|
152
|
+
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
"repository": {
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
"type": "git",
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
"url": "git+https://github.com/sgroy10/speclock.git"
|
|
162
|
+
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
"engines": {
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
"node": ">=18"
|
|
169
|
+
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
"dependencies": {
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
"chokidar": "^3.6.0",
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
"zod": "^3.25.0"
|
|
182
|
+
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
"files": [
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
"bin/",
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
"src/",
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
"src/dashboard/",
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
"README.md",
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
"SPECLOCK-INSTRUCTIONS.md",
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
"LICENSE"
|
|
204
|
+
|
|
205
|
+
],
|
|
206
|
+
|
|
207
|
+
"devDependencies": {
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
"esbuild": "^0.27.3",
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
"jest": "^30.2.0"
|
|
214
|
+
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
"speclock": {
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
"active": true,
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
"message": "STOP — This project has SpecLock constraints. Read SPECLOCK.md and .speclock/context/latest.md BEFORE making ANY changes. Run 'npx speclock check' before ALL code changes. If a lock below is violated, STOP and ask user to unlock.",
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
"locks": [
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
"Game balance configuration must not be changed",
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
"Patient records must never be deleted",
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
"No breaking changes to public API"
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
],
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
"context": ".speclock/context/latest.md",
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
"rules": "SPECLOCK.md"
|
|
248
|
+
|
|
249
|
+
}
|
|
250
|
+
}
|
package/src/cli/index.js
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
exportCompliance,
|
|
25
25
|
getLicenseInfo,
|
|
26
26
|
enforceConflictCheck,
|
|
27
|
+
enforceConflictCheckAsync,
|
|
27
28
|
setEnforcementMode,
|
|
28
29
|
overrideLock,
|
|
29
30
|
getOverrideHistory,
|
|
@@ -116,7 +117,7 @@ function refreshContext(root) {
|
|
|
116
117
|
|
|
117
118
|
function printHelp() {
|
|
118
119
|
console.log(`
|
|
119
|
-
SpecLock v4.4.
|
|
120
|
+
SpecLock v4.4.3 — AI Constraint Engine (Gemini LLM + Policy-as-Code + SSO + Dashboard + Telemetry + Auth + RBAC + Encryption)
|
|
120
121
|
Developed by Sandeep Roy (github.com/sgroy10)
|
|
121
122
|
|
|
122
123
|
Usage: speclock <command> [options]
|
|
@@ -452,7 +453,8 @@ Tip: When starting a new chat, tell the AI:
|
|
|
452
453
|
console.error('Usage: speclock check "what you plan to do"');
|
|
453
454
|
process.exit(1);
|
|
454
455
|
}
|
|
455
|
-
|
|
456
|
+
// Use async version for Gemini proxy coverage on grey-zone cases
|
|
457
|
+
const result = await enforceConflictCheckAsync(root, text);
|
|
456
458
|
if (result.hasConflict) {
|
|
457
459
|
console.log(`\n${result.blocked ? "BLOCKED" : "CONFLICT DETECTED"}`);
|
|
458
460
|
console.log("=".repeat(50));
|
package/src/core/compliance.js
CHANGED
package/src/core/enforcer.js
CHANGED
|
@@ -190,6 +190,135 @@ export function enforceConflictCheck(root, proposedAction) {
|
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Async version of enforceConflictCheck — uses Gemini proxy for grey-zone cases.
|
|
195
|
+
* Falls back to heuristic-only if proxy is unavailable.
|
|
196
|
+
*/
|
|
197
|
+
export async function enforceConflictCheckAsync(root, proposedAction) {
|
|
198
|
+
const brain = readBrain(root);
|
|
199
|
+
if (!brain) {
|
|
200
|
+
return {
|
|
201
|
+
hasConflict: false,
|
|
202
|
+
blocked: false,
|
|
203
|
+
mode: "advisory",
|
|
204
|
+
conflictingLocks: [],
|
|
205
|
+
analysis: "SpecLock not initialized. No enforcement.",
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const config = getEnforcementConfig(brain);
|
|
210
|
+
const activeLocks = (brain.specLock?.items || []).filter((l) => l.active !== false);
|
|
211
|
+
|
|
212
|
+
if (activeLocks.length === 0) {
|
|
213
|
+
return {
|
|
214
|
+
hasConflict: false,
|
|
215
|
+
blocked: false,
|
|
216
|
+
mode: config.mode,
|
|
217
|
+
conflictingLocks: [],
|
|
218
|
+
analysis: "No active locks. No constraints to check against.",
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Run heuristic against all active locks
|
|
223
|
+
const conflicting = [];
|
|
224
|
+
for (const lock of activeLocks) {
|
|
225
|
+
const result = analyzeConflict(proposedAction, lock.text);
|
|
226
|
+
if (result.isConflict) {
|
|
227
|
+
conflicting.push({
|
|
228
|
+
id: lock.id,
|
|
229
|
+
text: lock.text,
|
|
230
|
+
confidence: result.confidence,
|
|
231
|
+
level: result.level,
|
|
232
|
+
reasons: result.reasons,
|
|
233
|
+
source: "heuristic",
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// If all heuristic conflicts are HIGH, trust them — skip proxy
|
|
239
|
+
const allHigh = conflicting.length > 0 && conflicting.every((c) => c.confidence > 70);
|
|
240
|
+
|
|
241
|
+
// Grey zone: call proxy for Gemini coverage
|
|
242
|
+
if (!allHigh) {
|
|
243
|
+
try {
|
|
244
|
+
const { checkConflictAsync } = await import("./conflict.js");
|
|
245
|
+
const asyncResult = await checkConflictAsync(root, proposedAction);
|
|
246
|
+
|
|
247
|
+
if (asyncResult.hasConflict) {
|
|
248
|
+
// Merge: use async result's locks (which already merged heuristic + proxy)
|
|
249
|
+
const merged = new Map();
|
|
250
|
+
for (const c of conflicting) merged.set(c.text, c);
|
|
251
|
+
for (const c of asyncResult.conflictingLocks) {
|
|
252
|
+
const existing = merged.get(c.text);
|
|
253
|
+
if (!existing || c.confidence > existing.confidence) {
|
|
254
|
+
merged.set(c.text, {
|
|
255
|
+
id: c.id || c.lockId,
|
|
256
|
+
text: c.text,
|
|
257
|
+
confidence: c.confidence,
|
|
258
|
+
level: c.level,
|
|
259
|
+
reasons: c.reasons || [],
|
|
260
|
+
source: c.source || "proxy",
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
conflicting.length = 0;
|
|
265
|
+
conflicting.push(...merged.values());
|
|
266
|
+
}
|
|
267
|
+
} catch (_) {
|
|
268
|
+
// Proxy unavailable — continue with heuristic results
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (conflicting.length === 0) {
|
|
273
|
+
return {
|
|
274
|
+
hasConflict: false,
|
|
275
|
+
blocked: false,
|
|
276
|
+
mode: config.mode,
|
|
277
|
+
conflictingLocks: [],
|
|
278
|
+
analysis: `Checked against ${activeLocks.length} active lock(s). No conflicts detected. Proceed with caution.`,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Sort by confidence descending
|
|
283
|
+
conflicting.sort((a, b) => b.confidence - a.confidence);
|
|
284
|
+
|
|
285
|
+
const topConfidence = conflicting[0].confidence;
|
|
286
|
+
const meetsThreshold = topConfidence >= config.blockThreshold;
|
|
287
|
+
const blocked = config.mode === "hard" && meetsThreshold;
|
|
288
|
+
|
|
289
|
+
const details = conflicting
|
|
290
|
+
.map(
|
|
291
|
+
(c) =>
|
|
292
|
+
`- [${c.level}] "${c.text}" (confidence: ${c.confidence}%)\n Reasons: ${c.reasons.join("; ")}`
|
|
293
|
+
)
|
|
294
|
+
.join("\n");
|
|
295
|
+
|
|
296
|
+
addViolation(brain, {
|
|
297
|
+
at: nowIso(),
|
|
298
|
+
action: proposedAction,
|
|
299
|
+
locks: conflicting.map((c) => ({ id: c.id, text: c.text, confidence: c.confidence, level: c.level })),
|
|
300
|
+
topLevel: conflicting[0].level,
|
|
301
|
+
topConfidence,
|
|
302
|
+
enforced: blocked,
|
|
303
|
+
mode: config.mode,
|
|
304
|
+
});
|
|
305
|
+
writeBrain(root, brain);
|
|
306
|
+
|
|
307
|
+
const modeLabel = blocked
|
|
308
|
+
? "BLOCKED — Hard enforcement active. This action cannot proceed."
|
|
309
|
+
: "WARNING — Advisory mode. Review before proceeding.";
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
hasConflict: true,
|
|
313
|
+
blocked,
|
|
314
|
+
mode: config.mode,
|
|
315
|
+
threshold: config.blockThreshold,
|
|
316
|
+
topConfidence,
|
|
317
|
+
conflictingLocks: conflicting,
|
|
318
|
+
analysis: `${modeLabel}\n\nConflict with ${conflicting.length} lock(s):\n${details}`,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
193
322
|
/**
|
|
194
323
|
* Override a lock for a specific action, with a reason.
|
|
195
324
|
* Logged to audit trail. Triggers escalation if overridden too many times.
|
package/src/core/engine.js
CHANGED
package/src/core/telemetry.js
CHANGED
|
@@ -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.4.
|
|
260
|
+
version: "4.4.3",
|
|
261
261
|
totalCalls: summary.totalCalls,
|
|
262
262
|
avgResponseMs: summary.avgResponseMs,
|
|
263
263
|
conflicts: summary.conflicts,
|
package/src/dashboard/index.html
CHANGED
|
@@ -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.4.
|
|
92
|
+
<div class="meta">v4.4.3 — 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.4.
|
|
185
|
+
SpecLock v4.4.3 — Developed by Sandeep Roy — <a href="https://github.com/sgroy10/speclock" style="color:var(--accent)">GitHub</a>
|
|
186
186
|
</div>
|
|
187
187
|
|
|
188
188
|
<script>
|
package/src/mcp/http-server.js
CHANGED
|
@@ -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.4.
|
|
94
|
+
const VERSION = "4.4.3";
|
|
95
95
|
const AUTHOR = "Sandeep Roy";
|
|
96
96
|
const START_TIME = Date.now();
|
|
97
97
|
|
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.4.
|
|
103
|
+
const VERSION = "4.4.3";
|
|
104
104
|
const AUTHOR = "Sandeep Roy";
|
|
105
105
|
|
|
106
106
|
const server = new McpServer(
|