@sunaiva/gate 1.0.0 → 1.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/BUSINESS_LICENSE.md +70 -0
- package/CHANGELOG.md +148 -0
- package/LICENSE +0 -0
- package/README.md +411 -27
- package/dist/config/defaults.d.ts +22 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +56 -8
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/loader.d.ts +0 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +24 -6
- package/dist/config/loader.js.map +1 -1
- package/dist/engine/backend-client.d.ts +58 -0
- package/dist/engine/backend-client.d.ts.map +1 -0
- package/dist/engine/backend-client.js +287 -0
- package/dist/engine/backend-client.js.map +1 -0
- package/dist/engine/hmac-verifier.d.ts +33 -0
- package/dist/engine/hmac-verifier.d.ts.map +1 -0
- package/dist/engine/hmac-verifier.js +161 -0
- package/dist/engine/hmac-verifier.js.map +1 -0
- package/dist/engine/immutability.d.ts +59 -0
- package/dist/engine/immutability.d.ts.map +1 -0
- package/dist/engine/immutability.js +129 -0
- package/dist/engine/immutability.js.map +1 -0
- package/dist/engine/pattern-matcher.d.ts +13 -0
- package/dist/engine/pattern-matcher.d.ts.map +1 -1
- package/dist/engine/pattern-matcher.js +85 -17
- package/dist/engine/pattern-matcher.js.map +1 -1
- package/dist/engine/rule-engine.d.ts +62 -1
- package/dist/engine/rule-engine.d.ts.map +1 -1
- package/dist/engine/rule-engine.js +222 -12
- package/dist/engine/rule-engine.js.map +1 -1
- package/dist/engine/session-state.d.ts +0 -0
- package/dist/engine/session-state.d.ts.map +1 -1
- package/dist/engine/session-state.js +8 -2
- package/dist/engine/session-state.js.map +1 -1
- package/dist/engine/ship-confidence-gate.d.ts +184 -0
- package/dist/engine/ship-confidence-gate.d.ts.map +1 -0
- package/dist/engine/ship-confidence-gate.js +768 -0
- package/dist/engine/ship-confidence-gate.js.map +1 -0
- package/dist/index.d.ts +0 -0
- package/dist/index.d.ts.map +0 -0
- package/dist/index.js +289 -2
- package/dist/index.js.map +1 -1
- package/dist/rules/categories.json +0 -0
- package/dist/rules/presets.json +0 -0
- package/dist/rules/rules.json +200 -100
- package/dist/tools/audit.d.ts +6 -0
- package/dist/tools/audit.d.ts.map +1 -1
- package/dist/tools/audit.js +43 -6
- package/dist/tools/audit.js.map +1 -1
- package/dist/tools/bypass.d.ts +0 -0
- package/dist/tools/bypass.d.ts.map +1 -1
- package/dist/tools/bypass.js +50 -6
- package/dist/tools/bypass.js.map +1 -1
- package/dist/tools/rules.d.ts +0 -0
- package/dist/tools/rules.d.ts.map +0 -0
- package/dist/tools/rules.js +0 -0
- package/dist/tools/rules.js.map +0 -0
- package/dist/tools/ship-confidence.d.ts +11 -0
- package/dist/tools/ship-confidence.d.ts.map +1 -0
- package/dist/tools/ship-confidence.js +42 -0
- package/dist/tools/ship-confidence.js.map +1 -0
- package/dist/tools/update.d.ts +0 -0
- package/dist/tools/update.d.ts.map +1 -1
- package/dist/tools/update.js +45 -9
- package/dist/tools/update.js.map +1 -1
- package/dist/tools/validate.d.ts +0 -0
- package/dist/tools/validate.d.ts.map +1 -1
- package/dist/tools/validate.js +56 -4
- package/dist/tools/validate.js.map +1 -1
- package/dist/types/backend.d.ts +69 -0
- package/dist/types/backend.d.ts.map +1 -0
- package/dist/types/backend.js +18 -0
- package/dist/types/backend.js.map +1 -0
- package/package.json +11 -3
package/dist/tools/audit.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async-style audit write. The file I/O is deferred to setImmediate so the hot
|
|
3
|
+
* path (the validate_action response) returns before the syscall. Errors are
|
|
4
|
+
* swallowed because the audit log is informational and must never break
|
|
5
|
+
* enforcement.
|
|
6
|
+
*/
|
|
1
7
|
export declare function appendAudit(entry: Record<string, unknown>): void;
|
|
2
8
|
export declare function handleGetAuditLog(args: {
|
|
3
9
|
limit?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AA+BA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAYhE;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GAejF"}
|
package/dist/tools/audit.js
CHANGED
|
@@ -1,16 +1,53 @@
|
|
|
1
|
-
import { readFileSync, appendFileSync, existsSync, mkdirSync } from "node:fs";
|
|
1
|
+
import { readFileSync, appendFileSync, existsSync, mkdirSync, statSync, renameSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { getConfig } from "../config/loader.js";
|
|
4
|
+
// Rotate audit log when it crosses this size (bytes).
|
|
5
|
+
const AUDIT_ROTATE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
6
|
+
// Throttle rotation checks: only stat the file at most every 60s.
|
|
7
|
+
const ROTATE_CHECK_MS = 60_000;
|
|
8
|
+
let _lastRotateCheck = 0;
|
|
4
9
|
function getLogPath() {
|
|
5
10
|
return getConfig().audit_log_path;
|
|
6
11
|
}
|
|
7
|
-
|
|
12
|
+
function maybeRotate(logPath) {
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
if (now - _lastRotateCheck < ROTATE_CHECK_MS)
|
|
15
|
+
return;
|
|
16
|
+
_lastRotateCheck = now;
|
|
8
17
|
try {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
if (!existsSync(logPath))
|
|
19
|
+
return;
|
|
20
|
+
const size = statSync(logPath).size;
|
|
21
|
+
if (size < AUDIT_ROTATE_BYTES)
|
|
22
|
+
return;
|
|
23
|
+
// Rotate: audit.jsonl -> audit.jsonl.1 (best-effort). Single-slot rotation
|
|
24
|
+
// is acceptable for an informational audit ledger.
|
|
25
|
+
const rotated = `${logPath}.1`;
|
|
26
|
+
renameSync(logPath, rotated);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Fail-OPEN: never let rotation block writes.
|
|
12
30
|
}
|
|
13
|
-
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Async-style audit write. The file I/O is deferred to setImmediate so the hot
|
|
34
|
+
* path (the validate_action response) returns before the syscall. Errors are
|
|
35
|
+
* swallowed because the audit log is informational and must never break
|
|
36
|
+
* enforcement.
|
|
37
|
+
*/
|
|
38
|
+
export function appendAudit(entry) {
|
|
39
|
+
const stamped = { ...entry };
|
|
40
|
+
setImmediate(() => {
|
|
41
|
+
try {
|
|
42
|
+
const logPath = getLogPath();
|
|
43
|
+
mkdirSync(dirname(logPath), { recursive: true });
|
|
44
|
+
maybeRotate(logPath);
|
|
45
|
+
appendFileSync(logPath, JSON.stringify(stamped) + "\n");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Fail-OPEN
|
|
49
|
+
}
|
|
50
|
+
});
|
|
14
51
|
}
|
|
15
52
|
export async function handleGetAuditLog(args) {
|
|
16
53
|
const logPath = getLogPath();
|
package/dist/tools/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/bypass.d.ts
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bypass.d.ts","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bypass.d.ts","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAgBA,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;;;GAiD9E"}
|
package/dist/tools/bypass.js
CHANGED
|
@@ -1,16 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* log_bypass MCP tool — record an intentional, justified rule bypass.
|
|
3
|
+
*
|
|
4
|
+
* Constitutional rules CANNOT be bypassed (Builder B4 — Finding C3).
|
|
5
|
+
* Backed by `src/engine/immutability.ts`. A rejected bypass writes
|
|
6
|
+
* NOTHING to the audit log (per B4 brief test #8) — the entire call
|
|
7
|
+
* fails before audit is touched. This is intentional: a constitutional
|
|
8
|
+
* bypass attempt is a misuse signal, not a logged business event.
|
|
9
|
+
*/
|
|
1
10
|
import { loadAllRules } from "../engine/rule-engine.js";
|
|
11
|
+
import { assertCanBypass, ConstitutionalImmutableError, } from "../engine/immutability.js";
|
|
2
12
|
import { appendAudit } from "./audit.js";
|
|
3
13
|
export async function handleLogBypass(args) {
|
|
4
14
|
const rules = loadAllRules();
|
|
5
|
-
const rule = rules.find(r => r.id === args.rule_id);
|
|
15
|
+
const rule = rules.find((r) => r.id === args.rule_id);
|
|
6
16
|
if (!rule) {
|
|
7
|
-
return {
|
|
17
|
+
return {
|
|
18
|
+
content: [{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: JSON.stringify({ error: `Rule not found: ${args.rule_id}` }),
|
|
21
|
+
}],
|
|
22
|
+
};
|
|
8
23
|
}
|
|
9
|
-
|
|
10
|
-
|
|
24
|
+
try {
|
|
25
|
+
assertCanBypass(args.rule_id);
|
|
11
26
|
}
|
|
12
|
-
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err instanceof ConstitutionalImmutableError) {
|
|
29
|
+
return {
|
|
30
|
+
content: [{
|
|
31
|
+
type: "text",
|
|
32
|
+
text: JSON.stringify({
|
|
33
|
+
error: "CONSTITUTIONAL_RULE_CANNOT_BE_BYPASSED",
|
|
34
|
+
rule_id: err.rule_id,
|
|
35
|
+
message: "Constitutional rules cannot be bypassed via log_bypass",
|
|
36
|
+
}),
|
|
37
|
+
}],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
const entry = {
|
|
43
|
+
timestamp: new Date().toISOString(),
|
|
44
|
+
type: "bypass",
|
|
45
|
+
rule_id: args.rule_id,
|
|
46
|
+
reason: args.reason,
|
|
47
|
+
};
|
|
13
48
|
appendAudit(entry);
|
|
14
|
-
return {
|
|
49
|
+
return {
|
|
50
|
+
content: [{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: JSON.stringify({
|
|
53
|
+
logged: true,
|
|
54
|
+
bypass_id: `byp_${Date.now()}`,
|
|
55
|
+
rule_id: args.rule_id,
|
|
56
|
+
}),
|
|
57
|
+
}],
|
|
58
|
+
};
|
|
15
59
|
}
|
|
16
60
|
//# sourceMappingURL=bypass.js.map
|
package/dist/tools/bypass.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bypass.js","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAyC;IAC7E,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"bypass.js","sourceRoot":"","sources":["../../src/tools/bypass.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EACL,eAAe,EACf,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAyC;IAC7E,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;iBACnE,CAAC;SACH,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,4BAA4B,EAAE,CAAC;YAChD,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,wCAAwC;4BAC/C,OAAO,EAAE,GAAG,CAAC,OAAO;4BACpB,OAAO,EAAE,wDAAwD;yBAClE,CAAC;qBACH,CAAC;aACH,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;IACF,WAAW,CAAC,KAAK,CAAC,CAAC;IAEnB,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,MAAM,EAAE,IAAI;oBACZ,SAAS,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE;oBAC9B,OAAO,EAAE,IAAI,CAAC,OAAO;iBACtB,CAAC;aACH,CAAC;KACH,CAAC;AACJ,CAAC"}
|
package/dist/tools/rules.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/tools/rules.js
CHANGED
|
File without changes
|
package/dist/tools/rules.js.map
CHANGED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ship-confidence.d.ts","sourceRoot":"","sources":["../../src/tools/ship-confidence.ts"],"names":[],"mappings":"AAQA,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;;;;;GAmCA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: ship_confidence_check
|
|
3
|
+
*
|
|
4
|
+
* Invokes the ShipConfidenceGate for a given artifact_id and returns a
|
|
5
|
+
* structured result. The audit ledger is written by the gate itself.
|
|
6
|
+
*/
|
|
7
|
+
import { ShipConfidenceGate } from "../engine/ship-confidence-gate.js";
|
|
8
|
+
export async function handleShipConfidenceCheck(args) {
|
|
9
|
+
// Lazy single-instance — picks up env at call time (test-friendly).
|
|
10
|
+
const gate = new ShipConfidenceGate();
|
|
11
|
+
const result = await gate.check(args.artifact_id, {
|
|
12
|
+
commandPreview: args.command_preview,
|
|
13
|
+
label: args.label,
|
|
14
|
+
});
|
|
15
|
+
const responseBody = {
|
|
16
|
+
allowed: result.decision === "allow",
|
|
17
|
+
decision: result.decision,
|
|
18
|
+
tier: result.tier,
|
|
19
|
+
reason: result.reason,
|
|
20
|
+
evidence: result.evidence,
|
|
21
|
+
verdict_id: result.verdict_id,
|
|
22
|
+
level: result.level,
|
|
23
|
+
signed_at: result.signed_at,
|
|
24
|
+
age_minutes: result.age_minutes,
|
|
25
|
+
would_have_been: result.would_have_been,
|
|
26
|
+
bypassed: result.bypassed ?? false,
|
|
27
|
+
stamp: result.stamp,
|
|
28
|
+
hook_name: result.stamp.hook_name,
|
|
29
|
+
hook_version: result.stamp.hook_version,
|
|
30
|
+
rule_name: result.stamp.rule_name,
|
|
31
|
+
rule_version: result.stamp.rule_version,
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: "text",
|
|
37
|
+
text: JSON.stringify(responseBody, null, 2),
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=ship-confidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ship-confidence.js","sourceRoot":"","sources":["../../src/tools/ship-confidence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,IAI/C;IACC,oEAAoE;IACpE,MAAM,IAAI,GAAG,IAAI,kBAAkB,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;QAChD,cAAc,EAAE,IAAI,CAAC,eAAe;QACpC,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG;QACnB,OAAO,EAAE,MAAM,CAAC,QAAQ,KAAK,OAAO;QACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,KAAK;QAClC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;QACjC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;QACvC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;QACjC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;KACxC,CAAC;IAEF,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;aAC5C;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/dist/tools/update.d.ts
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAmBA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;;;;;GA0CtF"}
|
package/dist/tools/update.js
CHANGED
|
@@ -1,24 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update_rules MCP tool — enable/disable rules.
|
|
3
|
+
*
|
|
4
|
+
* Constitutional rules CANNOT be disabled (Builder B4 — Finding C2).
|
|
5
|
+
* Backed by `src/engine/immutability.ts` whose source of truth is the
|
|
6
|
+
* frozen CONSTITUTIONAL_RULE_IDS array in defaults.ts plus any rule
|
|
7
|
+
* with `enforcement === "constitutional"` in rules.json.
|
|
8
|
+
*
|
|
9
|
+
* Atomicity: if ANY disable target is constitutional, the WHOLE call
|
|
10
|
+
* rejects — no partial commits (per B4 brief test #5). This prevents
|
|
11
|
+
* a caller from sneaking a real disable past the guard by mixing
|
|
12
|
+
* constitutional and non-constitutional IDs.
|
|
13
|
+
*/
|
|
1
14
|
import { getConfig, saveConfig } from "../config/loader.js";
|
|
2
|
-
import {
|
|
15
|
+
import { assertCanDisable, ConstitutionalImmutableError, } from "../engine/immutability.js";
|
|
3
16
|
export async function handleUpdateRules(args) {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
17
|
+
const blocked = [];
|
|
18
|
+
if (args.disable) {
|
|
19
|
+
for (const id of args.disable) {
|
|
20
|
+
try {
|
|
21
|
+
assertCanDisable(id);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
if (err instanceof ConstitutionalImmutableError) {
|
|
25
|
+
blocked.push(err.rule_id);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (blocked.length > 0) {
|
|
8
34
|
return {
|
|
9
35
|
content: [{
|
|
10
36
|
type: "text",
|
|
11
|
-
text: JSON.stringify({
|
|
37
|
+
text: JSON.stringify({
|
|
38
|
+
error: "CONSTITUTIONAL_RULE_IMMUTABLE",
|
|
39
|
+
rule_ids: blocked,
|
|
40
|
+
message: "Constitutional rules cannot be disabled via update_rules",
|
|
41
|
+
}),
|
|
12
42
|
}],
|
|
13
43
|
};
|
|
14
44
|
}
|
|
45
|
+
const cfg = getConfig();
|
|
15
46
|
const active = new Set(cfg.active_rules);
|
|
16
47
|
if (args.enable)
|
|
17
|
-
args.enable.forEach(id => active.add(id));
|
|
48
|
+
args.enable.forEach((id) => active.add(id));
|
|
18
49
|
if (args.disable)
|
|
19
|
-
args.disable.forEach(id => active.delete(id));
|
|
50
|
+
args.disable.forEach((id) => active.delete(id));
|
|
20
51
|
cfg.active_rules = [...active];
|
|
21
52
|
saveConfig(cfg);
|
|
22
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
content: [{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: JSON.stringify({ updated: true, active_count: cfg.active_rules.length }),
|
|
57
|
+
}],
|
|
58
|
+
};
|
|
23
59
|
}
|
|
24
60
|
//# sourceMappingURL=update.js.map
|
package/dist/tools/update.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/tools/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,gBAAgB,EAChB,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AAEnC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAA+C;IACrF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,gBAAgB,CAAC,EAAE,CAAC,CAAC;YACvB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,4BAA4B,EAAE,CAAC;oBAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,KAAK,EAAE,+BAA+B;wBACtC,QAAQ,EAAE,OAAO;wBACjB,OAAO,EAAE,0DAA0D;qBACpE,CAAC;iBACH,CAAC;SACH,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,IAAI,CAAC,MAAM;QAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,IAAI,IAAI,CAAC,OAAO;QAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,GAAG,CAAC,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAC/B,UAAU,CAAC,GAAG,CAAC,CAAC;IAEhB,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;aAC/E,CAAC;KACH,CAAC;AACJ,CAAC"}
|
package/dist/tools/validate.d.ts
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"AAQA,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GA4EpF"}
|
package/dist/tools/validate.js
CHANGED
|
@@ -1,26 +1,78 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { evaluateActionAsync } from "../engine/rule-engine.js";
|
|
2
2
|
import { getConfig } from "../config/loader.js";
|
|
3
3
|
import { getWarningCounts, recordWarning } from "../engine/session-state.js";
|
|
4
4
|
import { appendAudit } from "./audit.js";
|
|
5
|
+
const PKG_VERSION = "1.1.0";
|
|
6
|
+
const HOOK_NAME = "sunaiva-gate";
|
|
5
7
|
export async function handleValidateAction(args) {
|
|
8
|
+
// Kill-switch: short-circuit everything if disabled.
|
|
9
|
+
if (process.env.DISABLE_SUNAIVA_GATE === "1") {
|
|
10
|
+
return {
|
|
11
|
+
content: [{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: JSON.stringify({
|
|
14
|
+
allowed: true,
|
|
15
|
+
gate_version: PKG_VERSION,
|
|
16
|
+
hook_name: HOOK_NAME,
|
|
17
|
+
disabled: true,
|
|
18
|
+
message: `[${HOOK_NAME} v${PKG_VERSION}] DISABLED via DISABLE_SUNAIVA_GATE=1 — all actions allowed.`,
|
|
19
|
+
}, null, 2),
|
|
20
|
+
}],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const dryRun = process.env.SUNAIVA_GATE_DRY_RUN === "1";
|
|
6
24
|
const cfg = getConfig();
|
|
7
25
|
const counts = getWarningCounts();
|
|
8
|
-
|
|
26
|
+
// Async path — when SUNAIVA_GATE_API_TOKEN is set, premium rules are
|
|
27
|
+
// delegated to the BackendClient. Unset → premium rules return
|
|
28
|
+
// `skipped_no_token` and the once-per-process stderr notice fires.
|
|
29
|
+
const result = await evaluateActionAsync(args.action, cfg, counts, args.context);
|
|
9
30
|
for (const w of result.warnings)
|
|
10
31
|
recordWarning(w.id);
|
|
32
|
+
const decision = result.allowed ? "pass" : "block";
|
|
11
33
|
const entry = {
|
|
12
34
|
timestamp: new Date().toISOString(),
|
|
13
|
-
|
|
35
|
+
gate_version: PKG_VERSION,
|
|
36
|
+
type: dryRun ? `dry_run_${decision}` : decision,
|
|
14
37
|
action: args.action.slice(0, 200),
|
|
38
|
+
severity_tier: result.severity_tier,
|
|
15
39
|
violations: result.violations.map(r => r.id),
|
|
16
40
|
warnings: result.warnings.map(r => r.id),
|
|
41
|
+
skipped_premium: result.skipped_premium,
|
|
42
|
+
would_have_blocked: result.would_have_blocked,
|
|
17
43
|
};
|
|
18
44
|
appendAudit(entry);
|
|
45
|
+
// In dry-run, force allowed=true but expose what would have happened.
|
|
46
|
+
const finalAllowed = dryRun ? true : result.allowed;
|
|
47
|
+
// Self-stamping: every block/warn message identifies the gate + escape hatch.
|
|
48
|
+
let stamp = `[${HOOK_NAME} v${PKG_VERSION}]`;
|
|
49
|
+
if (!finalAllowed) {
|
|
50
|
+
const violationNames = result.violations.map(r => `${r.id} (${r.name})`).join(", ");
|
|
51
|
+
stamp += ` BLOCKED by ${violationNames}. Escape: export DISABLE_SUNAIVA_GATE=1`;
|
|
52
|
+
}
|
|
53
|
+
else if (dryRun && result.would_have_blocked.length > 0) {
|
|
54
|
+
stamp += ` DRY-RUN — would have blocked: ${result.would_have_blocked.join(", ")}`;
|
|
55
|
+
}
|
|
56
|
+
else if (result.warnings.length > 0) {
|
|
57
|
+
const warnNames = result.warnings.map(r => `${r.id} (${r.name})`).join(", ");
|
|
58
|
+
stamp += ` WARN ${warnNames}. Next match will block. Escape: export DISABLE_SUNAIVA_GATE=1`;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
stamp += " allow";
|
|
62
|
+
}
|
|
19
63
|
return {
|
|
20
64
|
content: [{
|
|
21
65
|
type: "text",
|
|
22
66
|
text: JSON.stringify({
|
|
23
|
-
allowed:
|
|
67
|
+
allowed: finalAllowed,
|
|
68
|
+
gate_version: PKG_VERSION,
|
|
69
|
+
hook_name: HOOK_NAME,
|
|
70
|
+
escape_hatch: "DISABLE_SUNAIVA_GATE=1",
|
|
71
|
+
severity_tier: result.severity_tier,
|
|
72
|
+
dry_run: dryRun,
|
|
73
|
+
would_have_blocked: result.would_have_blocked,
|
|
74
|
+
skipped_premium: result.skipped_premium,
|
|
75
|
+
message: stamp,
|
|
24
76
|
rule_violations: result.violations.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
25
77
|
warnings: result.warnings.map(r => ({ id: r.id, name: r.name })),
|
|
26
78
|
}, null, 2),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the Sunaiva Gate premium backend integration.
|
|
3
|
+
*
|
|
4
|
+
* Exposed from `src/types/backend.ts` so other internal modules (e.g.,
|
|
5
|
+
* B2's ship-confidence flow) can import the same shapes without depending
|
|
6
|
+
* on the full backend-client implementation.
|
|
7
|
+
*
|
|
8
|
+
* API contract source: sunaiva-gate-backend/README.md §"API contract"
|
|
9
|
+
* POST /api/v1/match
|
|
10
|
+
* Request : { rule_id, input_text, context? }
|
|
11
|
+
* Response: { matched, severity, decision, reason? }
|
|
12
|
+
*/
|
|
13
|
+
/** Severity tier returned by the backend for a matched rule. */
|
|
14
|
+
export type BackendSeverity = "block" | "warn" | "log";
|
|
15
|
+
/** Decision instruction the backend wants the client to enforce. */
|
|
16
|
+
export type BackendDecision = "deny" | "allow" | "ask";
|
|
17
|
+
/**
|
|
18
|
+
* Status of a per-rule backend evaluation. The client never blocks the
|
|
19
|
+
* customer on backend-side failures — those are treated as a skip so a
|
|
20
|
+
* Sunaiva outage cannot trigger a customer-side service outage.
|
|
21
|
+
*/
|
|
22
|
+
export type BackendEvalStatus = "matched" | "no_match" | "skipped_no_token" | "skipped_auth" | "skipped_tier" | "skipped_quota" | "skipped_unknown" | "skipped_error" | "skipped_disabled";
|
|
23
|
+
/** Per-rule evaluation outcome. */
|
|
24
|
+
export interface BackendRuleResult {
|
|
25
|
+
rule_id: string;
|
|
26
|
+
status: BackendEvalStatus;
|
|
27
|
+
matched: boolean;
|
|
28
|
+
severity?: BackendSeverity;
|
|
29
|
+
decision?: BackendDecision;
|
|
30
|
+
reason?: string;
|
|
31
|
+
/** Set when status is `skipped_error` / `skipped_*` for operator visibility. */
|
|
32
|
+
error?: string;
|
|
33
|
+
/** HTTP status code returned by the backend, if any. */
|
|
34
|
+
http_status?: number;
|
|
35
|
+
/** Wall-clock latency for this rule's backend call (ms). */
|
|
36
|
+
latency_ms: number;
|
|
37
|
+
}
|
|
38
|
+
/** Aggregate of all rule evaluations in a single backend pass. */
|
|
39
|
+
export interface BackendEvalResult {
|
|
40
|
+
/** Rule IDs that were attempted. */
|
|
41
|
+
evaluated_rules: string[];
|
|
42
|
+
/** Per-rule results in input order. */
|
|
43
|
+
results: BackendRuleResult[];
|
|
44
|
+
/** Subset of evaluated_rules that matched (matched=true). */
|
|
45
|
+
matched_rule_ids: string[];
|
|
46
|
+
/** Subset of evaluated_rules that were skipped for any reason. */
|
|
47
|
+
skipped_rule_ids: string[];
|
|
48
|
+
/** Total wall-clock latency (ms) for all calls combined. */
|
|
49
|
+
latency_ms: number;
|
|
50
|
+
/** True iff no API token was configured (drives once-per-session stderr notice). */
|
|
51
|
+
premium_skipped_due_to_no_token: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** Options for constructing a BackendClient. */
|
|
54
|
+
export interface BackendClientOptions {
|
|
55
|
+
/** Backend URL. Defaults to env SUNAIVA_GATE_BACKEND_URL or the production URL. */
|
|
56
|
+
url?: string;
|
|
57
|
+
/** Customer JWT. Defaults to env SUNAIVA_GATE_API_TOKEN. */
|
|
58
|
+
apiToken?: string;
|
|
59
|
+
/** Request timeout (ms). Defaults to env SUNAIVA_GATE_BACKEND_TIMEOUT_MS or 3000. */
|
|
60
|
+
timeoutMs?: number;
|
|
61
|
+
/** Injected fetch (for tests). Defaults to global fetch. */
|
|
62
|
+
fetchImpl?: typeof fetch;
|
|
63
|
+
}
|
|
64
|
+
/** Production backend URL. */
|
|
65
|
+
export declare const DEFAULT_BACKEND_URL = "https://gate.sunaiva.dev/api/v1/match";
|
|
66
|
+
export declare const DEFAULT_TIMEOUT_MS = 3000;
|
|
67
|
+
export declare const RETRY_BACKOFF_MS = 500;
|
|
68
|
+
export declare const MAX_RETRIES = 1;
|
|
69
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/types/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEvD,oEAAoE;AACpE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAEvD;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,UAAU,GACV,kBAAkB,GAClB,cAAc,GACd,cAAc,GACd,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,kBAAkB,CACnB;AAEH,mCAAmC;AACnC,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,uCAAuC;IACvC,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,6DAA6D;IAC7D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,kEAAkE;IAClE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,+BAA+B,EAAE,OAAO,CAAC;CAC1C;AAED,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,8BAA8B;AAC9B,eAAO,MAAM,mBAAmB,0CAA0C,CAAC;AAC3E,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,WAAW,IAAI,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the Sunaiva Gate premium backend integration.
|
|
3
|
+
*
|
|
4
|
+
* Exposed from `src/types/backend.ts` so other internal modules (e.g.,
|
|
5
|
+
* B2's ship-confidence flow) can import the same shapes without depending
|
|
6
|
+
* on the full backend-client implementation.
|
|
7
|
+
*
|
|
8
|
+
* API contract source: sunaiva-gate-backend/README.md §"API contract"
|
|
9
|
+
* POST /api/v1/match
|
|
10
|
+
* Request : { rule_id, input_text, context? }
|
|
11
|
+
* Response: { matched, severity, decision, reason? }
|
|
12
|
+
*/
|
|
13
|
+
/** Production backend URL. */
|
|
14
|
+
export const DEFAULT_BACKEND_URL = "https://gate.sunaiva.dev/api/v1/match";
|
|
15
|
+
export const DEFAULT_TIMEOUT_MS = 3000;
|
|
16
|
+
export const RETRY_BACKOFF_MS = 500;
|
|
17
|
+
export const MAX_RETRIES = 1;
|
|
18
|
+
//# sourceMappingURL=backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/types/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAqEH,8BAA8B;AAC9B,MAAM,CAAC,MAAM,mBAAmB,GAAG,uCAAuC,CAAC;AAC3E,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sunaiva/gate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Sunaiva Gate MCP — enforcement layer for AI agent rules. Stop documenting rules your agents ignore. Start enforcing them.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -9,15 +9,23 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/",
|
|
12
|
+
"dist/rules/",
|
|
13
|
+
"dist/rules/rules.json",
|
|
14
|
+
"dist/rules/presets.json",
|
|
15
|
+
"dist/rules/categories.json",
|
|
12
16
|
"README.md",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"BUSINESS_LICENSE.md",
|
|
19
|
+
"LICENSE",
|
|
13
20
|
"package.json"
|
|
14
21
|
],
|
|
15
22
|
"scripts": {
|
|
16
23
|
"build": "tsc && node scripts/strip-patterns.js",
|
|
17
24
|
"start": "node dist/index.js",
|
|
18
25
|
"dev": "tsx src/index.ts",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
26
|
+
"verify-bundle": "node scripts/verify-bundle.js",
|
|
27
|
+
"prepack": "node scripts/verify-bundle.js",
|
|
28
|
+
"prepublishOnly": "npm run build && node scripts/verify-bundle.js",
|
|
21
29
|
"test": "node --experimental-vm-modules node_modules/.bin/jest --passWithNoTests"
|
|
22
30
|
},
|
|
23
31
|
"keywords": [
|