@golproductions/check 3.0.7 → 3.1.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.
- package/README.md +14 -105
- package/package.json +5 -21
- package/src/index.js +352 -6
- package/src/mcp.js +1 -1
package/README.md
CHANGED
|
@@ -1,125 +1,34 @@
|
|
|
1
|
-
# Check
|
|
1
|
+
# Check -- The Universal Anti-Hallucination Engine
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
AI agents hallucinate. Check catches it before it reaches your project.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
No AI inside. Deterministic. Same input, same output. Every time.
|
|
5
|
+
No AI inside. Deterministic. Sub-100ms.
|
|
8
6
|
|
|
9
7
|
## Install
|
|
10
8
|
|
|
11
|
-
One command. Every IDE.
|
|
12
|
-
|
|
13
9
|
```
|
|
14
10
|
npx @golproductions/check --install YOUR_KEY
|
|
15
11
|
```
|
|
16
12
|
|
|
17
|
-
Auto-detects
|
|
18
|
-
|
|
19
|
-
Get your free API key (120 free checks) at [golproductions.com/check](https://www.golproductions.com/check.html)
|
|
20
|
-
|
|
21
|
-
## What it catches
|
|
13
|
+
One command. Auto-detects your environment and configures everything.
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
|------|-------------|
|
|
25
|
-
| **Phantom commands** | AI runs `git stash apply 3` — stash doesn't exist. **Blocked.** |
|
|
26
|
-
| **Hallucinated imports** | AI writes `import cache from "express-session"` — not installed. **Blocked.** |
|
|
27
|
-
| **Invented functions** | AI calls `db.findUserByEmail()` — doesn't exist in your project. **Blocked.** |
|
|
28
|
-
| **Broken syntax** | AI writes a file with mismatched brackets. **Flagged.** |
|
|
29
|
-
| **Post-write integrity** | After the AI writes a file, imports and function calls are re-verified. **Two checkpoints.** |
|
|
15
|
+
120 free checks on signup at [golproductions.com/check](https://www.golproductions.com/check.html)
|
|
30
16
|
|
|
31
17
|
## Supported environments
|
|
32
18
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
| Environment | Integration |
|
|
36
|
-
|-------------|-------------|
|
|
37
|
-
| Claude Code | PreToolUse hook |
|
|
38
|
-
| Cursor | beforeShellExecution hook |
|
|
39
|
-
| Gemini CLI / Antigravity | BeforeTool hook |
|
|
40
|
-
|
|
41
|
-
**MCP Server (agent-driven)**
|
|
42
|
-
|
|
43
|
-
| Environment | Integration |
|
|
44
|
-
|-------------|-------------|
|
|
45
|
-
| Claude Code | MCP server |
|
|
46
|
-
| Cursor | MCP server |
|
|
47
|
-
| Windsurf / Devin Desktop | MCP server |
|
|
48
|
-
| Continue | MCP server |
|
|
49
|
-
| Amazon Q | MCP server |
|
|
50
|
-
| Roo Code | MCP server |
|
|
51
|
-
| Claude Desktop | MCP server |
|
|
52
|
-
| Any MCP client | MCP server |
|
|
53
|
-
|
|
54
|
-
**Editor plugins**
|
|
55
|
-
|
|
56
|
-
| Editor | Install |
|
|
57
|
-
|--------|---------|
|
|
58
|
-
| VS Code / Cursor / Devin Desktop | [Open VSX](https://open-vsx.org/extension/golproductions/gol-check) |
|
|
59
|
-
| JetBrains (IntelliJ, WebStorm, PyCharm, GoLand, Rider, PHPStorm, RubyMine) | [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/com.golproductions.check) |
|
|
60
|
-
| Neovim | [check.nvim](https://github.com/golproductions/check.nvim) |
|
|
61
|
-
| Emacs | [check.el](https://github.com/golproductions/check.el) |
|
|
62
|
-
| Sublime Text | [GOLCheck](https://github.com/golproductions/check-sublime) |
|
|
63
|
-
| Zed | [check-zed](https://github.com/golproductions/check-zed) |
|
|
64
|
-
|
|
65
|
-
**Direct API**
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
POST https://triage.golproductions.com/preflight
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## MCP Server
|
|
72
|
-
|
|
73
|
-
Run Check as an MCP server for direct agent integration:
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
npx @golproductions/check check-mcp
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Exposes two tools:
|
|
80
|
-
- **Check** — validates a command, returns `RUNNABLE` or `INVALID`
|
|
81
|
-
- **CheckAndExecute** — validates then executes, blocking invalid commands before they reach the shell
|
|
82
|
-
|
|
83
|
-
## How it works
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
AI generates code
|
|
87
|
-
↓
|
|
88
|
-
Check intercepts (pre-execution)
|
|
89
|
-
↓
|
|
90
|
-
Verifies against your actual project
|
|
91
|
-
↓
|
|
92
|
-
Real → allowed | Not real → blocked
|
|
93
|
-
↓
|
|
94
|
-
After file write → second verification pass
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Sub-100ms. Your AI never knows it's there.
|
|
98
|
-
|
|
99
|
-
## Why not just use another guardrail?
|
|
100
|
-
|
|
101
|
-
| | Check | Security firewalls | LLM guardrails | Eval platforms |
|
|
102
|
-
|---|---|---|---|---|
|
|
103
|
-
| **Checks code correctness** | Yes | No — checks safety | No — checks format | No — scores after |
|
|
104
|
-
| **Knows your project** | Yes | No | No | No |
|
|
105
|
-
| **Pre-execution** | Yes | Yes | Varies | No |
|
|
106
|
-
| **Post-write verification** | Yes | No | No | No |
|
|
107
|
-
| **No AI inside** | Yes | Varies | Uses LLMs | Uses LLMs |
|
|
108
|
-
| **Per-check pricing** | $0.0068 AUD | Free (self-hosted) | Enterprise | SaaS |
|
|
109
|
-
|
|
110
|
-
Every other tool checks the AI. **Check checks the code.**
|
|
19
|
+
Claude Code, Cursor, Gemini CLI, Windsurf, Devin Desktop, Continue, Amazon Q, Roo Code, Claude Desktop, JetBrains, VS Code, Neovim, Emacs, Sublime Text, Zed, and any MCP client.
|
|
111
20
|
|
|
112
21
|
## Pricing
|
|
113
22
|
|
|
114
|
-
|
|
23
|
+
$0.0068 AUD per check. No subscription. Credits never expire.
|
|
115
24
|
|
|
116
|
-
| Tier | Checks |
|
|
117
|
-
|
|
118
|
-
| Free | 120 |
|
|
119
|
-
| $5 | ~735 |
|
|
120
|
-
| $10 | ~1,470 |
|
|
121
|
-
| $25 | ~3,676 |
|
|
122
|
-
| $50 | ~7,352 |
|
|
25
|
+
| Tier | Checks |
|
|
26
|
+
|------|--------|
|
|
27
|
+
| Free | 120 |
|
|
28
|
+
| $5 | ~735 |
|
|
29
|
+
| $10 | ~1,470 |
|
|
30
|
+
| $25 | ~3,676 |
|
|
31
|
+
| $50 | ~7,352 |
|
|
123
32
|
|
|
124
33
|
## Links
|
|
125
34
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@golproductions/check",
|
|
3
|
-
"version": "3.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
|
+
"description": "The universal anti-hallucination engine for AI coding agents. Catches what is not real before it reaches your project.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"check": "src/index.js",
|
|
7
7
|
"check-mcp": "src/mcp.js"
|
|
@@ -18,35 +18,19 @@
|
|
|
18
18
|
"keywords": [
|
|
19
19
|
"anti-hallucination",
|
|
20
20
|
"ai-hallucination",
|
|
21
|
-
"hallucination-detection",
|
|
22
|
-
"ai-firewall",
|
|
23
21
|
"ai-agents",
|
|
24
|
-
"ai-
|
|
25
|
-
"command-validation",
|
|
26
|
-
"import-validation",
|
|
27
|
-
"function-verification",
|
|
28
|
-
"code-integrity",
|
|
29
|
-
"pre-execution",
|
|
30
|
-
"deterministic-verification",
|
|
22
|
+
"ai-coding-agent",
|
|
31
23
|
"claude-code",
|
|
32
24
|
"cursor",
|
|
33
|
-
"antigravity",
|
|
34
25
|
"windsurf",
|
|
35
|
-
"devin-desktop",
|
|
36
26
|
"gemini-cli",
|
|
37
27
|
"amazon-q",
|
|
38
28
|
"continue-dev",
|
|
39
29
|
"roo-code",
|
|
40
|
-
"cline",
|
|
41
|
-
"ai-guardrails",
|
|
42
|
-
"llm-validation",
|
|
43
30
|
"mcp",
|
|
44
31
|
"model-context-protocol",
|
|
45
|
-
"ai-coding-agent",
|
|
46
|
-
"code-verification",
|
|
47
32
|
"ai-safety",
|
|
48
|
-
"developer-tools"
|
|
49
|
-
"devtools"
|
|
33
|
+
"developer-tools"
|
|
50
34
|
],
|
|
51
35
|
"dependencies": {
|
|
52
36
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
@@ -57,5 +41,5 @@
|
|
|
57
41
|
"type": "git",
|
|
58
42
|
"url": "git+https://github.com/golproductions/check.git"
|
|
59
43
|
},
|
|
60
|
-
"homepage": "https://
|
|
44
|
+
"homepage": "https://golproductions.com/check"
|
|
61
45
|
}
|
package/src/index.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync, createWriteStream, chmodSync } from "node:fs";
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, createWriteStream, chmodSync, unlinkSync, rmSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { homedir, platform, arch } from "node:os";
|
|
5
5
|
import { pipeline } from "node:stream/promises";
|
|
6
6
|
import { Readable } from "node:stream";
|
|
7
7
|
|
|
8
|
-
const VERSION = "3.0
|
|
8
|
+
const VERSION = "3.1.0";
|
|
9
9
|
const BINARY_VERSION = "3.0.0";
|
|
10
10
|
const API = "https://triage.golproductions.com/preflight";
|
|
11
11
|
const CDN = "https://pub-e55366a7f5994be9be04f0e205179f4a.r2.dev/releases";
|
|
12
12
|
const CLIENT_ID = process.env.GOL_CLIENT_ID || "";
|
|
13
13
|
|
|
14
|
+
function getClientId() {
|
|
15
|
+
if (CLIENT_ID) return CLIENT_ID;
|
|
16
|
+
try {
|
|
17
|
+
const cfg = JSON.parse(readFileSync(join(homedir(), ".claude", "settings.json"), "utf8"));
|
|
18
|
+
return cfg.env?.GOL_CLIENT_ID || "";
|
|
19
|
+
} catch { return ""; }
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
async function validateKey(key) {
|
|
15
23
|
try {
|
|
16
24
|
const res = await fetch(API, {
|
|
@@ -239,9 +247,347 @@ async function install() {
|
|
|
239
247
|
process.exit(0);
|
|
240
248
|
}
|
|
241
249
|
|
|
242
|
-
|
|
243
|
-
|
|
250
|
+
function isCheckRef(str) {
|
|
251
|
+
return str && (str.includes(".check") || str.includes("truth-gate"));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function isCheckHook(hook) {
|
|
255
|
+
if (isCheckRef(hook.command)) return true;
|
|
256
|
+
if (hook.args?.some(a => isCheckRef(a))) return true;
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function uninstall() {
|
|
261
|
+
const home = homedir();
|
|
262
|
+
let removed = 0;
|
|
263
|
+
|
|
264
|
+
console.log("\n Removing Check...\n");
|
|
265
|
+
|
|
266
|
+
const hookTargets = [
|
|
267
|
+
{
|
|
268
|
+
name: "Claude Code",
|
|
269
|
+
path: join(home, ".claude", "settings.json"),
|
|
270
|
+
clean: (cfg) => {
|
|
271
|
+
if (cfg.hooks?.PreToolUse) {
|
|
272
|
+
cfg.hooks.PreToolUse = cfg.hooks.PreToolUse.filter(h => !h.hooks?.some(isCheckHook));
|
|
273
|
+
if (cfg.hooks.PreToolUse.length === 0) delete cfg.hooks.PreToolUse;
|
|
274
|
+
}
|
|
275
|
+
if (cfg.hooks?.PostToolUse) {
|
|
276
|
+
cfg.hooks.PostToolUse = cfg.hooks.PostToolUse.filter(h => !h.hooks?.some(isCheckHook));
|
|
277
|
+
if (cfg.hooks.PostToolUse.length === 0) delete cfg.hooks.PostToolUse;
|
|
278
|
+
}
|
|
279
|
+
if (cfg.hooks && Object.keys(cfg.hooks).length === 0) delete cfg.hooks;
|
|
280
|
+
if (cfg.env) {
|
|
281
|
+
delete cfg.env.GOL_CLIENT_ID;
|
|
282
|
+
if (Object.keys(cfg.env).length === 0) delete cfg.env;
|
|
283
|
+
}
|
|
284
|
+
return cfg;
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: "Gemini CLI",
|
|
289
|
+
path: join(home, ".gemini", "settings.json"),
|
|
290
|
+
clean: (cfg) => {
|
|
291
|
+
if (cfg.hooks?.BeforeTool) {
|
|
292
|
+
cfg.hooks.BeforeTool = cfg.hooks.BeforeTool.filter(h => !h.hooks?.some(hh => hh.name === "check-gate"));
|
|
293
|
+
if (cfg.hooks.BeforeTool.length === 0) delete cfg.hooks.BeforeTool;
|
|
294
|
+
if (Object.keys(cfg.hooks).length === 0) delete cfg.hooks;
|
|
295
|
+
}
|
|
296
|
+
return cfg;
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "Cursor",
|
|
301
|
+
path: join(home, ".cursor", "hooks.json"),
|
|
302
|
+
clean: (cfg) => {
|
|
303
|
+
if (cfg.hooks?.beforeShellExecution) {
|
|
304
|
+
cfg.hooks.beforeShellExecution = cfg.hooks.beforeShellExecution.filter(h => !isCheckRef(h.command));
|
|
305
|
+
if (cfg.hooks.beforeShellExecution.length === 0) delete cfg.hooks.beforeShellExecution;
|
|
306
|
+
if (Object.keys(cfg.hooks).length === 0) delete cfg.hooks;
|
|
307
|
+
}
|
|
308
|
+
return cfg;
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: "Homebase",
|
|
313
|
+
path: join(home, ".homebase", "hooks.json"),
|
|
314
|
+
clean: (cfg) => {
|
|
315
|
+
if (cfg.hooks?.PreToolUse) {
|
|
316
|
+
cfg.hooks.PreToolUse = cfg.hooks.PreToolUse.filter(h => !h.hooks?.some(isCheckHook));
|
|
317
|
+
if (cfg.hooks.PreToolUse.length === 0) delete cfg.hooks.PreToolUse;
|
|
318
|
+
}
|
|
319
|
+
if (cfg.hooks?.PostToolUse) {
|
|
320
|
+
cfg.hooks.PostToolUse = cfg.hooks.PostToolUse.filter(h => !h.hooks?.some(isCheckHook));
|
|
321
|
+
if (cfg.hooks.PostToolUse.length === 0) delete cfg.hooks.PostToolUse;
|
|
322
|
+
}
|
|
323
|
+
if (cfg.hooks && Object.keys(cfg.hooks).length === 0) delete cfg.hooks;
|
|
324
|
+
if (cfg.env) {
|
|
325
|
+
delete cfg.env.GOL_CLIENT_ID;
|
|
326
|
+
if (Object.keys(cfg.env).length === 0) delete cfg.env;
|
|
327
|
+
}
|
|
328
|
+
return cfg;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
];
|
|
332
|
+
|
|
333
|
+
const mcpUserTargets = [
|
|
334
|
+
{ name: "Windsurf", path: join(home, ".codeium", "windsurf", "mcp_config.json") },
|
|
335
|
+
{ name: "Amazon Q", path: join(home, ".aws", "amazonq", "mcp.json") },
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
const mcpProjectTargets = [
|
|
339
|
+
{ name: "Continue", path: join(process.cwd(), ".continue", "mcpServers", "check.json"), deleteFile: true },
|
|
340
|
+
{ name: "Roo Code", path: join(process.cwd(), ".roo", "mcp.json") },
|
|
341
|
+
{ name: "Project MCP", path: join(process.cwd(), ".mcp.json") },
|
|
342
|
+
];
|
|
343
|
+
|
|
344
|
+
for (const t of hookTargets) {
|
|
345
|
+
if (!existsSync(t.path)) continue;
|
|
346
|
+
try {
|
|
347
|
+
const cfg = JSON.parse(readFileSync(t.path, "utf8"));
|
|
348
|
+
const cleaned = t.clean(cfg);
|
|
349
|
+
writeFileSync(t.path, JSON.stringify(cleaned, null, 2) + "\n", "utf8");
|
|
350
|
+
console.log(" removed " + t.name);
|
|
351
|
+
removed++;
|
|
352
|
+
} catch {}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
for (const t of [...mcpUserTargets, ...mcpProjectTargets]) {
|
|
356
|
+
if (!existsSync(t.path)) continue;
|
|
357
|
+
try {
|
|
358
|
+
if (t.deleteFile) {
|
|
359
|
+
unlinkSync(t.path);
|
|
360
|
+
console.log(" removed " + t.name);
|
|
361
|
+
removed++;
|
|
362
|
+
} else {
|
|
363
|
+
const cfg = JSON.parse(readFileSync(t.path, "utf8"));
|
|
364
|
+
if (cfg.mcpServers?.Check) {
|
|
365
|
+
delete cfg.mcpServers.Check;
|
|
366
|
+
if (Object.keys(cfg.mcpServers).length === 0) delete cfg.mcpServers;
|
|
367
|
+
writeFileSync(t.path, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
368
|
+
console.log(" removed " + t.name);
|
|
369
|
+
removed++;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
} catch {}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const checkDir = join(home, ".check");
|
|
376
|
+
if (existsSync(checkDir)) {
|
|
377
|
+
try {
|
|
378
|
+
rmSync(checkDir, { recursive: true, force: true });
|
|
379
|
+
console.log(" removed ~/.check/");
|
|
380
|
+
} catch {}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (removed === 0) {
|
|
384
|
+
console.log(" No Check installations found.\n");
|
|
385
|
+
} else {
|
|
386
|
+
console.log(`\n Removed from ${removed} tool${removed !== 1 ? "s" : ""}.`);
|
|
387
|
+
console.log(" CLAUDE.md / AGENTS.md rules were left in place.\n");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
process.exit(0);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async function status() {
|
|
394
|
+
const home = homedir();
|
|
395
|
+
const checkDir = join(home, ".check");
|
|
396
|
+
const ext = platform() === "win32" ? ".exe" : "";
|
|
397
|
+
const id = getClientId();
|
|
398
|
+
|
|
399
|
+
console.log(`\n Check v${VERSION}\n`);
|
|
400
|
+
|
|
401
|
+
if (id) {
|
|
402
|
+
const masked = id.length > 12 ? id.slice(0, 8) + "..." + id.slice(-4) : id;
|
|
403
|
+
console.log(" Client ID: " + masked);
|
|
404
|
+
} else {
|
|
405
|
+
console.log(" Client ID: not set");
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const binaryPath = join(checkDir, "truth-gate" + ext);
|
|
409
|
+
console.log(" Binary: " + (existsSync(binaryPath) ? "installed" : "not found"));
|
|
410
|
+
const scriptPath = join(checkDir, "check.mjs");
|
|
411
|
+
console.log(" Script: " + (existsSync(scriptPath) ? "installed" : "not found"));
|
|
412
|
+
|
|
413
|
+
console.log("\n Integrations:\n");
|
|
414
|
+
|
|
415
|
+
const checks = [
|
|
416
|
+
{
|
|
417
|
+
name: "Claude Code",
|
|
418
|
+
path: join(home, ".claude", "settings.json"),
|
|
419
|
+
test: (cfg) => cfg.hooks?.PreToolUse?.some(h => h.hooks?.some(isCheckHook)) || cfg.hooks?.PostToolUse?.some(h => h.hooks?.some(isCheckHook)),
|
|
420
|
+
detail: (cfg) => {
|
|
421
|
+
const parts = [];
|
|
422
|
+
if (cfg.hooks?.PreToolUse?.some(h => h.hooks?.some(isCheckHook))) parts.push("PreToolUse");
|
|
423
|
+
if (cfg.hooks?.PostToolUse?.some(h => h.hooks?.some(isCheckHook))) parts.push("PostToolUse");
|
|
424
|
+
return parts.join(", ");
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
name: "Gemini CLI",
|
|
429
|
+
path: join(home, ".gemini", "settings.json"),
|
|
430
|
+
test: (cfg) => cfg.hooks?.BeforeTool?.some(h => h.hooks?.some(hh => hh.name === "check-gate")),
|
|
431
|
+
detail: () => "BeforeTool"
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
name: "Cursor",
|
|
435
|
+
path: join(home, ".cursor", "hooks.json"),
|
|
436
|
+
test: (cfg) => cfg.hooks?.beforeShellExecution?.some(h => isCheckRef(h.command)),
|
|
437
|
+
detail: () => "beforeShellExecution"
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
name: "Homebase",
|
|
441
|
+
path: join(home, ".homebase", "hooks.json"),
|
|
442
|
+
test: (cfg) => cfg.hooks?.PreToolUse?.some(h => h.hooks?.some(isCheckHook)) || cfg.hooks?.PostToolUse?.some(h => h.hooks?.some(isCheckHook)),
|
|
443
|
+
detail: (cfg) => {
|
|
444
|
+
const parts = [];
|
|
445
|
+
if (cfg.hooks?.PreToolUse?.some(h => h.hooks?.some(isCheckHook))) parts.push("PreToolUse");
|
|
446
|
+
if (cfg.hooks?.PostToolUse?.some(h => h.hooks?.some(isCheckHook))) parts.push("PostToolUse");
|
|
447
|
+
return parts.join(", ");
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
{ name: "Windsurf", path: join(home, ".codeium", "windsurf", "mcp_config.json"), test: (cfg) => !!cfg.mcpServers?.Check, detail: () => "MCP" },
|
|
451
|
+
{ name: "Continue", path: join(process.cwd(), ".continue", "mcpServers", "check.json"), test: (cfg) => !!cfg.mcpServers?.Check, detail: () => "MCP (project)" },
|
|
452
|
+
{ name: "Amazon Q", path: join(home, ".aws", "amazonq", "mcp.json"), test: (cfg) => !!cfg.mcpServers?.Check, detail: () => "MCP" },
|
|
453
|
+
{ name: "Roo Code", path: join(process.cwd(), ".roo", "mcp.json"), test: (cfg) => !!cfg.mcpServers?.Check, detail: () => "MCP (project)" },
|
|
454
|
+
{ name: "Project MCP", path: join(process.cwd(), ".mcp.json"), test: (cfg) => !!cfg.mcpServers?.Check, detail: () => "MCP (project)" },
|
|
455
|
+
];
|
|
456
|
+
|
|
457
|
+
for (const c of checks) {
|
|
458
|
+
if (!existsSync(c.path)) {
|
|
459
|
+
console.log(" - " + c.name.padEnd(14) + " not detected");
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
try {
|
|
463
|
+
const cfg = JSON.parse(readFileSync(c.path, "utf8"));
|
|
464
|
+
if (c.test(cfg)) {
|
|
465
|
+
console.log(" + " + c.name.padEnd(14) + " active (" + c.detail(cfg) + ")");
|
|
466
|
+
} else {
|
|
467
|
+
console.log(" - " + c.name.padEnd(14) + " tool installed, Check not configured");
|
|
468
|
+
}
|
|
469
|
+
} catch {
|
|
470
|
+
console.log(" ? " + c.name.padEnd(14) + " config unreadable");
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
console.log("");
|
|
475
|
+
process.exit(0);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async function credits() {
|
|
479
|
+
const id = getClientId();
|
|
480
|
+
if (!id) {
|
|
481
|
+
console.log("\n No Client ID found. Set GOL_CLIENT_ID or run --install first.\n");
|
|
482
|
+
process.exit(1);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
const res = await fetch(API.replace("/preflight", "/credits"), {
|
|
487
|
+
method: "GET",
|
|
488
|
+
headers: { "X-GOL-CLIENT-ID": id, "User-Agent": "c/" + VERSION },
|
|
489
|
+
signal: AbortSignal.timeout(10000),
|
|
490
|
+
});
|
|
491
|
+
if (!res.ok) {
|
|
492
|
+
console.log("\n Could not fetch credits (HTTP " + res.status + ").\n");
|
|
493
|
+
process.exit(1);
|
|
494
|
+
}
|
|
495
|
+
const d = await res.json();
|
|
496
|
+
console.log(`\n Check v${VERSION} — Credits\n`);
|
|
497
|
+
if (d.free_remaining !== undefined) console.log(" Free today: " + d.free_remaining + " / " + (d.free_daily || 120));
|
|
498
|
+
if (d.calls_today !== undefined) console.log(" Calls today: " + d.calls_today);
|
|
499
|
+
if (d.balance !== undefined) console.log(" Balance: $" + d.balance + " AUD");
|
|
500
|
+
if (d.total_calls !== undefined) console.log(" Total calls: " + d.total_calls);
|
|
501
|
+
if (d.plan) console.log(" Plan: " + d.plan);
|
|
502
|
+
if (Object.keys(d).length === 0) console.log(" " + JSON.stringify(d));
|
|
503
|
+
console.log("");
|
|
504
|
+
} catch (err) {
|
|
505
|
+
console.log("\n Could not reach API: " + err.message + "\n");
|
|
506
|
+
}
|
|
507
|
+
process.exit(0);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
async function docs() {
|
|
511
|
+
console.log(`
|
|
512
|
+
Check v${VERSION} — Documentation
|
|
513
|
+
|
|
514
|
+
Install: npx @golproductions/check --install <key>
|
|
515
|
+
Uninstall: npx @golproductions/check --uninstall
|
|
516
|
+
Status: npx @golproductions/check --status
|
|
517
|
+
Credits: npx @golproductions/check --credits
|
|
518
|
+
|
|
519
|
+
How it works:
|
|
520
|
+
|
|
521
|
+
Check installs hooks into your AI coding tools. Every time
|
|
522
|
+
the AI runs a command or edits a file, Check verifies it
|
|
523
|
+
before or after execution.
|
|
524
|
+
|
|
525
|
+
PreToolUse Validates commands before they run.
|
|
526
|
+
PostToolUse Verifies results after execution.
|
|
527
|
+
MCP Server Provides Check and CheckAndExecute tools.
|
|
528
|
+
CLAUDE.md Adds anti-fabrication instructions.
|
|
529
|
+
|
|
530
|
+
Supported tools:
|
|
531
|
+
|
|
532
|
+
Claude Code, Gemini CLI, Cursor, Windsurf, Continue,
|
|
533
|
+
Amazon Q Developer, Roo Code, Homebase
|
|
534
|
+
|
|
535
|
+
Pricing:
|
|
536
|
+
|
|
537
|
+
120 free checks per day. Then $0.0068 AUD per check.
|
|
538
|
+
Credits never expire. Pay as you go.
|
|
539
|
+
|
|
540
|
+
Links:
|
|
541
|
+
|
|
542
|
+
Website: https://golproductions.com/check
|
|
543
|
+
Docs: https://github.com/golproductions/check
|
|
544
|
+
Support: support@golproductions.com
|
|
545
|
+
`);
|
|
546
|
+
|
|
547
|
+
try {
|
|
548
|
+
const { execSync } = await import("node:child_process");
|
|
549
|
+
const url = "https://github.com/golproductions/check";
|
|
550
|
+
if (platform() === "win32") execSync(`start "" "${url}"`, { stdio: "ignore", shell: true });
|
|
551
|
+
else if (platform() === "darwin") execSync(`open "${url}"`, { stdio: "ignore" });
|
|
552
|
+
else execSync(`xdg-open "${url}"`, { stdio: "ignore" });
|
|
553
|
+
} catch {}
|
|
554
|
+
|
|
555
|
+
process.exit(0);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function help() {
|
|
559
|
+
console.log(`
|
|
560
|
+
Check v${VERSION} — Anti-hallucination layer for AI coding agents
|
|
561
|
+
|
|
562
|
+
Usage:
|
|
563
|
+
|
|
564
|
+
npx @golproductions/check --install <key> Install Check with your Client ID
|
|
565
|
+
npx @golproductions/check --uninstall Remove Check from all tools
|
|
566
|
+
npx @golproductions/check --status Show what is installed and active
|
|
567
|
+
npx @golproductions/check --credits Check your usage and balance
|
|
568
|
+
npx @golproductions/check --docs View documentation
|
|
569
|
+
npx @golproductions/check --help Show this help
|
|
570
|
+
|
|
571
|
+
Get your key: https://golproductions.com/check
|
|
572
|
+
Pricing: 120 free/day, then $0.0068 AUD per check
|
|
573
|
+
`);
|
|
574
|
+
process.exit(0);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// CLI routing
|
|
578
|
+
const args = process.argv.slice(2);
|
|
579
|
+
if (args.includes("--install")) { await install(); }
|
|
580
|
+
if (args.includes("--uninstall")) { await uninstall(); }
|
|
581
|
+
if (args.includes("--status")) { await status(); }
|
|
582
|
+
if (args.includes("--credits")) { await credits(); }
|
|
583
|
+
if (args.includes("--docs")) { await docs(); }
|
|
584
|
+
if (args.includes("--help") || args.includes("-h")) { help(); }
|
|
585
|
+
if (args.includes("--mcp")) { await import("./mcp.js"); process.exit(0); }
|
|
586
|
+
|
|
587
|
+
// No flags + interactive terminal = show help
|
|
588
|
+
if (!args.some(a => a.startsWith("-")) && process.stdin.isTTY) { help(); }
|
|
244
589
|
|
|
590
|
+
// Hook handler (invoked by tools via stdin)
|
|
245
591
|
function detect(p) {
|
|
246
592
|
if (typeof p.command === "string" && !p.tool_input) return "cursor";
|
|
247
593
|
if (p.hook_event_name === "BeforeTool" || p.toolCall?.argumentsJson) return "gemini";
|
|
@@ -290,7 +636,7 @@ async function main() {
|
|
|
290
636
|
f = detect(p);
|
|
291
637
|
const c = cmd(p, f);
|
|
292
638
|
if (!c) { out(f, true); return; }
|
|
293
|
-
if (!CLIENT_ID) {
|
|
639
|
+
if (!CLIENT_ID) { out(f, false, "check: GOL_CLIENT_ID not set. Get your key at https://golproductions.com/check"); return; }
|
|
294
640
|
const controller = new AbortController();
|
|
295
641
|
const timer = setTimeout(() => controller.abort(), 5000);
|
|
296
642
|
const res = await fetch(API, {
|
|
@@ -303,7 +649,7 @@ async function main() {
|
|
|
303
649
|
const d = await res.json();
|
|
304
650
|
if (d.verdict === "runnable") { out(f, true); }
|
|
305
651
|
else { out(f, false, d.reason || "denied — address the issue before continuing"); }
|
|
306
|
-
} catch { out(f,
|
|
652
|
+
} catch { out(f, false, "check: verification failed, command blocked"); }
|
|
307
653
|
}
|
|
308
654
|
|
|
309
655
|
main();
|
package/src/mcp.js
CHANGED
|
@@ -6,7 +6,7 @@ import { execFile } from "node:child_process";
|
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
|
|
8
8
|
const execFileAsync = promisify(execFile);
|
|
9
|
-
const VERSION = "
|
|
9
|
+
const VERSION = "3.0.8";
|
|
10
10
|
const API = "https://triage.golproductions.com/preflight";
|
|
11
11
|
const CLIENT_ID = process.env.GOL_CLIENT_ID;
|
|
12
12
|
const IS_WIN = process.platform === "win32";
|